diff --git a/.claude/skills/tanstack-router/SKILL.md b/.claude/skills/tanstack-router/SKILL.md index 14cf808..6cfd6d0 100644 --- a/.claude/skills/tanstack-router/SKILL.md +++ b/.claude/skills/tanstack-router/SKILL.md @@ -49,7 +49,7 @@ conditionally mounted for dev use `env.isDev` from `@/shared/config/env`. ## Router config `apps/web/src/routes/router.tsx` creates the router. It mounts under the proxy sub-path via -`BASE_PREFIX` (from `@/shared/lib/basePath`) so client routing resolves behind the oasis pod-proxy: +`BASE_PREFIX` (from `@/shared/lib/basePath`) so client routing resolves behind the tangle pod-proxy: ```typescript export const router = createRouter({ diff --git a/.env.example b/.env.example index e638718..c35dc51 100644 --- a/.env.example +++ b/.env.example @@ -1,17 +1,17 @@ -# Minerva (Shopify SSO) auth config for scripts/minervaAuth.ts. -# Copy to .env (gitignored) and fill in the internal values. +# Oktasso SSO auth config for scripts/oktassoAuth.ts. +# Copy to .env (gitignored) and fill in the provider values. -# Shopify-internal endpoints + SSO client (ask your team / see tangle_deploy). -MINERVA_OAUTH_ENDPOINT_BASE= -MINERVA_TOKEN_EXCHANGE_URL= -MINERVA_CLIENT_ID= +# Provider endpoints + SSO client for your deployment. +OKTASSO_OAUTH_ENDPOINT_BASE= +OKTASSO_TOKEN_EXCHANGE_URL= +OKTASSO_CLIENT_ID= # Generic OAuth/PKCE settings — the defaults below are fine for local dev. -MINERVA_SCOPES="profile email openid" -MINERVA_REDIRECT_URI=http://localhost:3001/auth -MINERVA_CALLBACK_PORT=3001 +OKTASSO_SCOPES="profile email openid" +OKTASSO_REDIRECT_URI=http://localhost:3001/auth +OKTASSO_CALLBACK_PORT=3001 # Token cache lifetime in ms (55 minutes). -MINERVA_REFRESH_AFTER_MS=3300000 +OKTASSO_REFRESH_AFTER_MS=3300000 # Default bundle used by the Sessions page New session button. VITE_DEFAULT_SESSION_BUNDLE_ID=tangle diff --git a/README.md b/README.md index e00d90a..ee64c0c 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ the full list and defaults): | `PI_BIN` | Path to the `pi` agent executable | | `PI_PROVIDER` / `PI_MODEL` / `PI_THINKING` | Default LLM provider, model, and thinking level | | `PI_PROXY_URL` / `PI_PROXY_API_KEY` | LLM proxy endpoint and credential | -| `TANGLE_API_URL` / `OASIS_TOKEN` | Tangle pipeline API for bundles that integrate with it | +| `TANGLE_API_URL` / `TANGLE_TOKEN` | Tangle pipeline API for bundles that integrate with it | ### Common commands diff --git a/apps/server/package.json b/apps/server/package.json index d2c6557..f14fd73 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -5,7 +5,7 @@ "type": "module", "prettier": "@tangent/build/prettier", "scripts": { - "dev": "AUTH_JWT_TOKEN_COOKIE_NAME=MINERVA_TOKEN tsx watch --tsconfig ./tsconfig.json src/index.ts", + "dev": "AUTH_JWT_TOKEN_COOKIE_NAME=OKTASSO_TOKEN tsx watch --tsconfig ./tsconfig.json src/index.ts", "seed": "tsx --tsconfig ./tsconfig.json src/seed.ts", "build": "node build.mjs", "lint": "eslint .", diff --git a/apps/server/src/auth/identity.ts b/apps/server/src/auth/identity.ts index c29c78f..fde6051 100644 --- a/apps/server/src/auth/identity.ts +++ b/apps/server/src/auth/identity.ts @@ -54,7 +54,7 @@ function pickString( /** * Resolves the current {@link UserIdentity} from a raw `Cookie` header. Reads - * the Minerva JWT from {@link AUTH_JWT_TOKEN_COOKIE_NAME}, decodes its payload + * the Oktasso JWT from {@link AUTH_JWT_TOKEN_COOKIE_NAME}, decodes its payload * (no signature check), and maps the email + name claims onto the identity. * * Returns `null` when the cookie name is unconfigured, the cookie is missing, diff --git a/apps/server/src/bundleUi/egressAllowlist.ts b/apps/server/src/bundleUi/egressAllowlist.ts index 2499cf7..dbf274a 100644 --- a/apps/server/src/bundleUi/egressAllowlist.ts +++ b/apps/server/src/bundleUi/egressAllowlist.ts @@ -3,7 +3,7 @@ * * A sandboxed component can only reach destinations registered here; anything * else is denied before a network call is made. Unlike the earlier alias-based - * stub, components now name a **real, full URL** (e.g. the Oasis executions API) + * stub, components now name a **real, full URL** (e.g. the Tangle executions API) * and the proxy validates it against the allowlist of host/path patterns, then * performs the actual `fetch` server-side, injecting any credentials and * stripping host internals out of the response. @@ -42,14 +42,14 @@ interface EgressRule { } /** - * Optional credential for the Oasis API, injected server-side as a `Cookie` + * Optional credential for the Tangle API, injected server-side as a `Cookie` * header. Unset by default (the public executions-state endpoint is - * unauthenticated); set `OASIS_TOKEN` to a cookie string such as - * `MINERVA_TOKEN=` to authenticate. Generate one with - * `pnpm oasis:token` (or `pnpm dev:auth`). + * unauthenticated); set `TANGLE_TOKEN` to a cookie string such as + * `OKTASSO_TOKEN=` to authenticate. Generate one with + * `pnpm tangle:token` (or `pnpm dev:auth`). */ -function oasisAuthHeaders(): Record { - const token = process.env.OASIS_TOKEN; +function tangleAuthHeaders(): Record { + const token = process.env.TANGLE_TOKEN; return token ? { cookie: token } : {}; } @@ -91,7 +91,7 @@ const TANGLE_RULES: EgressRule[] = TANGLE_PATH_RULES.map((rule) => ({ method: rule.method, matches: (url) => url.origin === TANGLE_API_ORIGIN && rule.test.test(url.pathname), - headers: oasisAuthHeaders, + headers: tangleAuthHeaders, })); /** Registered destinations the bridge may reach. */ @@ -103,7 +103,7 @@ const EGRESS_RULES: EgressRule[] = [ matches: (url) => url.origin === "https://oasis.shopify.io" && /^\/api\/executions\/[^/]+\/state$/.test(url.pathname), - headers: oasisAuthHeaders, + headers: tangleAuthHeaders, }, ...TANGLE_RULES, ]; diff --git a/apps/server/src/config.ts b/apps/server/src/config.ts index 7b102c1..9ab0032 100644 --- a/apps/server/src/config.ts +++ b/apps/server/src/config.ts @@ -128,7 +128,7 @@ export const INTERNAL_TOKEN = process.env.TANGENT_INTERNAL_TOKEN ?? randomUUID(); /** - * Name of the cookie holding the Minerva JWT that `GET /api/me` reads to resolve + * Name of the cookie holding the Oktasso JWT that `GET /api/me` reads to resolve * the current user. Empty by default so the route is effectively disabled until * an environment supplies the cookie name (the local `dev` script sets it). */ diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index 826c213..193c3da 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -99,7 +99,7 @@ app.use( ); app.use("/api/agent-bundles", createAgentBundlesRouter(agentBundleStore)); app.use("/api/global-memory", createGlobalMemoryRouter(memory)); -// Returns the current user, derived from the Minerva JWT cookie. +// Returns the current user, derived from the Oktasso JWT cookie. app.use("/api/me", createMeRouter()); // Internal API for the orchestrator extension running inside each Pi process. app.use("/internal/agents", createInternalAgentsRouter(store, pi)); diff --git a/apps/server/src/pi/types.ts b/apps/server/src/pi/types.ts index eb16bc3..0d29b32 100644 --- a/apps/server/src/pi/types.ts +++ b/apps/server/src/pi/types.ts @@ -155,7 +155,7 @@ export interface SessionAgents { */ config?: ResolvedSessionConfig; /** - * The human who owns the session, resolved from their Minerva JWT. Captured + * The human who owns the session, resolved from their Oktasso JWT. Captured * so every agent's system prompt can be told who it's helping. Absent for * unauthenticated sessions. */ diff --git a/apps/server/src/routes/me.ts b/apps/server/src/routes/me.ts index 9cebb7b..eb5623a 100644 --- a/apps/server/src/routes/me.ts +++ b/apps/server/src/routes/me.ts @@ -4,14 +4,14 @@ import { resolveUserIdentity } from "../auth/identity.ts"; import { AUTH_JWT_TOKEN_COOKIE_NAME } from "../config.ts"; /** - * Handles `GET /api/me`. Resolves the current user from the Minerva JWT in the + * Handles `GET /api/me`. Resolves the current user from the Oktasso JWT in the * configured cookie ({@link AUTH_JWT_TOKEN_COOKIE_NAME}) and returns the full * identity. `user_id` is kept (set to the email) for backward compatibility * alongside the structured `email` / `first_name` / `last_name` fields. */ function handleGetMe(req: Request, res: Response): void { if (!AUTH_JWT_TOKEN_COOKIE_NAME) { - res.status(501).json({ error: "Minerva cookie name not configured" }); + res.status(501).json({ error: "Oktasso cookie name not configured" }); return; } @@ -25,8 +25,8 @@ function handleGetMe(req: Request, res: Response): void { } /** - * Public REST router exposing the current user, derived from the Minerva JWT in - * the `MINERVA_TOKEN` cookie. The signature is not verified at this time. + * Public REST router exposing the current user, derived from the Oktasso JWT in + * the `OKTASSO_TOKEN` cookie. The signature is not verified at this time. */ export function createMeRouter(): Router { const router = Router(); diff --git a/apps/server/src/routes/sessions/handlers.ts b/apps/server/src/routes/sessions/handlers.ts index f2bcb46..6f957bd 100644 --- a/apps/server/src/routes/sessions/handlers.ts +++ b/apps/server/src/routes/sessions/handlers.ts @@ -210,7 +210,7 @@ export async function handleCreateSession( return; } - // Resolve the creator's identity from their Minerva JWT cookie so every agent + // Resolve the creator's identity from their Oktasso JWT cookie so every agent // spawned for the session knows who it's helping. const user = resolveUserIdentity(req.headers.cookie) ?? undefined; const session = await store.createSession({ name: body.name, user }); diff --git a/apps/server/src/store/sessionStore.ts b/apps/server/src/store/sessionStore.ts index 2e8e2ae..79a4ee4 100644 --- a/apps/server/src/store/sessionStore.ts +++ b/apps/server/src/store/sessionStore.ts @@ -15,6 +15,11 @@ import type { */ export type SessionAgentStatus = "active" | "killed" | "error"; +/** + * Input accepted by {@link SessionStore.createSession}: the public wire request + * plus the server-resolved {@link UserIdentity} (from the creator's Oktasso JWT), + * which is never part of the client-supplied body. + */ export interface CreateSessionParams { name?: string; user?: UserIdentity; diff --git a/apps/web/index.html b/apps/web/index.html index ecb8325..81284fc 100644 --- a/apps/web/index.html +++ b/apps/web/index.html @@ -3,7 +3,7 @@ `; diff --git a/scripts/print-oasis-token.ts b/scripts/print-oasis-token.ts deleted file mode 100644 index ba4844b..0000000 --- a/scripts/print-oasis-token.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Prints an Oasis cookie token to stdout for use as `OASIS_TOKEN`. - * - * Runs the Minerva PKCE flow (or reuses the shared on-disk cache) and writes - * the `MINERVA_TOKEN=` cookie string — and nothing else — to stdout, - * so it can be captured directly: - * - * OASIS_TOKEN="$(pnpm -s oasis:token)" pnpm dev - * - * All diagnostics (browser prompt, errors) go to stderr. - */ - -import { getMinervaHeaders } from "./minervaAuth.ts"; - -const baseUrl = - process.argv[2] ?? process.env.OASIS_BASE_URL ?? "https://oasis.shopify.io"; -const forceRefresh = process.env.OASIS_TOKEN_FORCE_REFRESH === "1"; - -try { - const headers = await getMinervaHeaders({ baseUrl, forceRefresh }); - process.stdout.write(headers.cookie); -} catch (err) { - console.error(err instanceof Error ? err.message : String(err)); - process.exit(1); -} diff --git a/scripts/print-tangle-token.ts b/scripts/print-tangle-token.ts new file mode 100644 index 0000000..d15bcba --- /dev/null +++ b/scripts/print-tangle-token.ts @@ -0,0 +1,27 @@ +/** + * Prints a Tangle cookie token to stdout for use as `TANGLE_TOKEN`. + * + * Runs the Oktasso PKCE flow (or reuses the shared on-disk cache) and writes + * the `OKTASSO_TOKEN=` cookie string — and nothing else — to stdout, + * so it can be captured directly: + * + * TANGLE_TOKEN="$(pnpm -s tangle:token)" pnpm dev + * + * All diagnostics (browser prompt, errors) go to stderr. + */ + +import { getOktassoHeaders } from "./oktassoAuth.ts"; + +const baseUrl = + process.argv[2] ?? + process.env.TANGLE_BASE_URL ?? + "https://tangle.example.com"; +const forceRefresh = process.env.TANGLE_TOKEN_FORCE_REFRESH === "1"; + +try { + const headers = await getOktassoHeaders({ baseUrl, forceRefresh }); + process.stdout.write(headers.cookie); +} catch (err) { + console.error(err instanceof Error ? err.message : String(err)); + process.exit(1); +} diff --git a/turbo.json b/turbo.json index 9d880fc..a83a142 100644 --- a/turbo.json +++ b/turbo.json @@ -17,7 +17,7 @@ "TANGENT_INTERNAL_URL", "TANGENT_INTERNAL_TOKEN", "TANGLE_API_URL", - "OASIS_TOKEN" + "TANGLE_TOKEN" ], "tasks": { "build": {