@use-aistack/cli 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/api.ts","../src/commands/collect.ts","../src/classifier.ts","../src/stableKey.ts","../src/config.ts","../src/git.ts","../src/github-repo.ts","../src/hooks.ts","../src/mcp.ts","../src/plugins.ts","../src/scanner.ts","../src/theme.ts","../src/commands/connect.ts","../src/commands/create.ts","../src/commands/login.ts","../src/commands/sync.ts","../src/sync/stage.ts","../src/transcripts/pricing.ts","../src/transcripts/analyzer.ts","../src/transcripts/bundled-allowlist.ts","../src/transcripts/allowlist.ts","../src/transcripts/scan.ts","../src/transcripts/payload.ts","../src/transcripts/index.ts","../src/sync/summary.ts","../src/sync/server.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { BASE_URL } from \"./api.js\";\nimport { collectCommand } from \"./commands/collect.js\";\nimport { connectCommand } from \"./commands/connect.js\";\nimport { createCommand } from \"./commands/create.js\";\nimport { loginCommand } from \"./commands/login.js\";\nimport { syncCommand } from \"./commands/sync.js\";\nimport { runStdioSyncServer } from \"./sync/server.js\";\n\nconst program = new Command();\n\nprogram\n\t.name(\"aistack\")\n\t.description(\"Measure and share your AI stack from your terminal\")\n\t.version(\"0.4.0\");\n\nprogram\n\t.command(\"login\")\n\t.description(\"Authenticate with AI Stack\")\n\t.action(loginCommand);\n\nprogram\n\t.command(\"collect\")\n\t.description(\"Scan and upload AI config files from your project\")\n\t.option(\"--no-global\", \"Exclude global config files (~/.claude, etc.)\")\n\t.action((options) => collectCommand({ global: options.global ?? true }));\n\nprogram\n\t.command(\"create\")\n\t.description(\"Download and write your stack's AI config files\")\n\t.action(createCommand);\n\nprogram\n\t.command(\"mcp\")\n\t.description(\n\t\t\"Run the aistack MCP server on stdio (sync preview + gated publish)\",\n\t)\n\t.action(() => {\n\t\t// stdout belongs to the protocol. Diagnostics go to stderr only.\n\t\trunStdioSyncServer({\n\t\t\tbaseUrl: BASE_URL,\n\t\t\tlog: (line) => process.stderr.write(`[aistack-mcp] ${line}\\n`),\n\t\t});\n\t});\n\n// The documented default sync surface (#56): terminal-first, TTY gate.\nprogram\n\t.command(\"sync\")\n\t.description(\"Scan, preview, and publish measured usage (rolling 30 days)\")\n\t.action(syncCommand);\n\nprogram\n\t.command(\"connect\")\n\t.description(\"Install the in-session sync surface (MCP server + Skill)\")\n\t.argument(\"<harness>\", 'the harness to connect (\"claude\")')\n\t.action(connectCommand);\n\nprogram.parse();\n","export const BASE_URL = process.env.AISTACK_URL || \"https://aistack.to\";\n\nasync function request(\n\tpath: string,\n\toptions: RequestInit = {},\n): Promise<Response> {\n\treturn fetch(`${BASE_URL}${path}`, {\n\t\t...options,\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t...options.headers,\n\t\t},\n\t});\n}\n\nfunction authHeaders(token: string): HeadersInit {\n\treturn { Authorization: `Bearer ${token}` };\n}\n\n/**\n * Turn the two statuses #52 introduced into sentences.\n *\n * A bare `429` tells the user nothing they can act on, and a bare `403` reads\n * like a bug rather than a machine that is no longer allowed to do this. Every\n * other status keeps its number, because the number is all we know about it.\n */\nfunction failure(what: string, res: Response): Error {\n\tif (res.status === 429) {\n\t\tconst retry = res.headers.get(\"Retry-After\");\n\t\treturn new Error(\n\t\t\tretry\n\t\t\t\t? `${what}: too many requests. Try again in ${retry} seconds.`\n\t\t\t\t: `${what}: too many requests. Try again in a minute.`,\n\t\t);\n\t}\n\tif (res.status === 403) {\n\t\treturn new Error(\n\t\t\t`${what}: this machine is not allowed to do that. Run \\`aistack login\\` again to re-link it.`,\n\t\t);\n\t}\n\treturn new Error(`${what}: ${res.status}`);\n}\n\n/**\n * Open a device-code session.\n *\n * `machineName` is a PROPOSAL, not a fact: the approval page renders it in an\n * editable field, so the user sees the string before it is stored and can\n * overwrite or clear it. That is why the hostname may be sent automatically —\n * the consent happens in the browser, a moment later, with the string on screen.\n */\nexport async function authStart(machineName?: string): Promise<{\n\tsecretId: string;\n\tuserCode: string;\n\tauthUrl: string;\n}> {\n\tconst res = await request(\"/api/cli/auth/start\", {\n\t\tmethod: \"POST\",\n\t\tbody: JSON.stringify(machineName ? { machineName } : {}),\n\t});\n\tif (!res.ok) throw failure(\"Auth start failed\", res);\n\treturn res.json();\n}\n\nexport async function authPoll(\n\tsecretId: string,\n): Promise<{ status: string; token?: string; userId?: string }> {\n\tconst res = await request(\n\t\t`/api/cli/auth/poll?secretId=${encodeURIComponent(secretId)}`,\n\t);\n\tif (!res.ok) throw failure(\"Auth poll failed\", res);\n\treturn res.json();\n}\n\nexport async function stackCollect(\n\ttoken: string,\n\tdata: { resources: Resource[] },\n): Promise<{ slug: string; shortId: string; url: string }> {\n\tconst res = await request(\"/api/cli/stacks/collect\", {\n\t\tmethod: \"POST\",\n\t\theaders: authHeaders(token),\n\t\tbody: JSON.stringify(data),\n\t});\n\tif (res.status === 401)\n\t\tthrow new Error(\n\t\t\t\"Authentication expired. Run `npx @use-aistack/cli login` again.\",\n\t\t);\n\tif (!res.ok) {\n\t\tthrow new Error(await formatHttpError(res, \"Collect failed\"));\n\t}\n\treturn res.json();\n}\n\nasync function formatHttpError(res: Response, label: string): Promise<string> {\n\tconst prefix = `${label}: ${res.status} ${res.statusText || \"\"}`.trim();\n\tconst text = await res.text().catch(() => \"\");\n\tif (!text) return prefix;\n\ttry {\n\t\tconst body = JSON.parse(text) as { error?: string; message?: string };\n\t\tconst detail = body.error || body.message;\n\t\tif (detail) return `${prefix} — ${detail}`;\n\t} catch {}\n\tconst snippet = text.trim().slice(0, 500);\n\treturn snippet ? `${prefix} — ${snippet}` : prefix;\n}\n\nexport type SyncPublishResult = {\n\treceivedAt: number;\n\tstackSlug: string;\n\turl: string;\n\tkeptPrivate: { stored: number; refused: boolean };\n};\n\n/**\n * Publish one approved snapshot.\n *\n * Takes the staged body as an ALREADY-SERIALIZED string: the bytes the user\n * approved at the gate are the bytes on the wire, with no re-serialization\n * step between them (#35's binding constraint, #41).\n */\nexport async function syncPublish(\n\ttoken: string,\n\tbodyJson: string,\n): Promise<SyncPublishResult> {\n\tconst res = await request(\"/api/cli/sync\", {\n\t\tmethod: \"POST\",\n\t\theaders: authHeaders(token),\n\t\tbody: bodyJson,\n\t});\n\tif (res.status === 401)\n\t\tthrow new Error(\n\t\t\t\"Authentication expired. Run `npx @use-aistack/cli login` again.\",\n\t\t);\n\tif (res.status === 403 || res.status === 429)\n\t\tthrow failure(\"Sync failed\", res);\n\tif (!res.ok) {\n\t\tthrow new Error(await formatHttpError(res, \"Sync failed\"));\n\t}\n\treturn res.json();\n}\n\nexport async function stackGet(token: string): Promise<StackData | null> {\n\tconst res = await request(\"/api/cli/stacks\", {\n\t\theaders: authHeaders(token),\n\t});\n\tif (res.status === 401)\n\t\tthrow new Error(\n\t\t\t\"Authentication expired. Run `npx @use-aistack/cli login` again.\",\n\t\t);\n\tif (res.status === 404) return null;\n\tif (!res.ok) throw failure(\"Stack fetch failed\", res);\n\treturn res.json();\n}\n\n// Types used across the CLI\nexport interface ResourceFile {\n\tname: string;\n\tcontent: string;\n\tpath?: string;\n\ttags?: string[];\n}\n\nexport interface Resource {\n\ttype: string;\n\tname: string;\n\tdescription?: string;\n\tgroup: string;\n\tstableKey: string;\n\tfiles?: ResourceFile[];\n\tupstream?: {\n\t\trepoUrl: string;\n\t\tpath?: string;\n\t\tlicense?: string;\n\t\tstars?: number;\n\t\tlastCommitSha?: string;\n\t\tlastSyncAt?: number;\n\t};\n\tpkg?: {\n\t\tregistry: \"npm\" | \"pypi\" | \"oci\" | \"url\";\n\t\tid: string;\n\t\tversion?: string;\n\t\ttransport?: \"stdio\" | \"http\" | \"sse\";\n\t};\n}\n\nexport interface StackData {\n\tname: string;\n\tslug: string;\n\tshortId: string;\n\tresources: Resource[];\n}\n","import * as p from \"@clack/prompts\";\nimport { type Resource, stackCollect, stackGet } from \"../api.js\";\nimport { classify } from \"../classifier.js\";\nimport { getExcludedPaths, getToken, saveExcludedPaths } from \"../config.js\";\nimport { buildRepoLinkResource, detectRepoUrl } from \"../git.js\";\nimport { repoNameFromCanonical } from \"../github-repo.js\";\nimport { detectHooks } from \"../hooks.js\";\nimport { detectMcpServers } from \"../mcp.js\";\nimport { detectInstalledPlugins } from \"../plugins.js\";\nimport { type ScannedFile, scanGlobal, scanLocal } from \"../scanner.js\";\nimport {\n\tbold,\n\tdim,\n\tdivider,\n\tintro,\n\tlime,\n\tlimeBold,\n\tlines,\n\toutro,\n\toutroCancel,\n\toutroError,\n\toutroSkipped,\n\tred,\n\tsection,\n\tyellow,\n} from \"../theme.js\";\n\n// Sentinel selection key for the detected repo link. NUL-prefixed so it can\n// never collide with a real ScannedFile.relativePath, letting links ride the\n// existing excluded[] selection/persistence model with no config.ts changes.\nconst REPO_LINK_KEY = \"\\0repo-link\";\n\n/**\n * A non-file resource surfaced during collect — the repo link, an installed\n * plugin, etc. Toggleable and persisted exactly like a scanned file, keyed by\n * its sentinel. Everything attaches to the single stack (global) server-side.\n */\ninterface DetectedLink {\n\tkey: string;\n\tresource: Resource;\n\tlabel: string;\n}\n\nexport async function collectCommand(options: { global: boolean }) {\n\tintro(\"collect\");\n\n\tconst token = getToken();\n\tif (!token) {\n\t\tp.log.error(\n\t\t\t`Not authenticated. Run ${limeBold(\"npx @use-aistack/cli login\")} first.`,\n\t\t);\n\t\toutroError(\"not authenticated\");\n\t\tprocess.exit(1);\n\t}\n\n\tconst cwd = process.cwd();\n\tconst savedExcluded = getExcludedPaths(cwd);\n\n\tconst s = p.spinner();\n\ts.start(\"Scanning...\");\n\n\tconst localFiles = scanLocal(cwd);\n\tconst globalFiles = options.global ? scanGlobal() : [];\n\ts.stop(\"Scan complete\");\n\n\tif (localFiles.length === 0 && globalFiles.length === 0) {\n\t\tp.log.warn(\"No AI configuration files found.\");\n\t\toutroSkipped(\"nothing to collect\");\n\t\treturn;\n\t}\n\n\t// Apply saved exclusions\n\tconst allFiles = [...localFiles, ...globalFiles];\n\tlet selectedFiles = allFiles.filter(\n\t\t(f) => !savedExcluded.includes(f.relativePath),\n\t);\n\tlet excluded = allFiles.filter((f) => savedExcluded.includes(f.relativePath));\n\n\t// Show file counts\n\tp.log.info(\n\t\t`${lime(String(selectedFiles.length))} included${excluded.length > 0 ? ` · ${dim(String(excluded.length) + \" excluded\")}` : \"\"}`,\n\t);\n\n\t// Detect non-file links: the repo this lives in, installed Claude Code\n\t// plugins, MCP servers, hooks. Each is toggleable and included by default\n\t// unless previously deselected. All graceful no-ops.\n\tconst detectedLinks: DetectedLink[] = [];\n\tconst repoUrl = detectRepoUrl(cwd);\n\tif (repoUrl) {\n\t\tdetectedLinks.push({\n\t\t\tkey: REPO_LINK_KEY,\n\t\t\tresource: buildRepoLinkResource(repoUrl),\n\t\t\tlabel: `repo · ${repoNameFromCanonical(repoUrl)}`,\n\t\t});\n\t}\n\tfor (const resource of detectInstalledPlugins()) {\n\t\tdetectedLinks.push({\n\t\t\tkey: `\\0plugin:${resource.stableKey}`,\n\t\t\tresource,\n\t\t\tlabel: `plugin · ${resource.name}`,\n\t\t});\n\t}\n\tfor (const resource of detectMcpServers(cwd)) {\n\t\tdetectedLinks.push({\n\t\t\tkey: `\\0mcp:${resource.stableKey}`,\n\t\t\tresource,\n\t\t\tlabel: `mcp · ${resource.name}`,\n\t\t});\n\t}\n\tfor (const resource of detectHooks(cwd)) {\n\t\tdetectedLinks.push({\n\t\t\tkey: `\\0hook:${resource.stableKey}`,\n\t\t\tresource,\n\t\t\tlabel: `hook · ${resource.name}`,\n\t\t});\n\t}\n\n\tconst includedLinks = new Set(\n\t\tdetectedLinks\n\t\t\t.filter((l) => !savedExcluded.includes(l.key))\n\t\t\t.map((l) => l.key),\n\t);\n\tconst withLinks = (base: Resource[]): Resource[] => [\n\t\t...base,\n\t\t...detectedLinks\n\t\t\t.filter((l) => includedLinks.has(l.key))\n\t\t\t.map((l) => l.resource),\n\t];\n\n\t// Classify selected files\n\tlet allResources = withLinks(classify(selectedFiles));\n\n\t// Fetch the existing stack and diff against its resources.\n\tlet existingStack: Awaited<ReturnType<typeof stackGet>> = null;\n\ttry {\n\t\texistingStack = await stackGet(token);\n\t} catch (err) {\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\toutroError(\"error\");\n\t\tprocess.exit(1);\n\t}\n\n\t// Show file list or diff\n\tif (existingStack) {\n\t\tconst diff = diffResources(allResources, existingStack.resources);\n\t\tconst changeCount = diff.added + diff.changed + diff.removed;\n\n\t\tif (changeCount === 0) {\n\t\t\tp.log.info(\"No changes since last collect.\");\n\t\t\toutroSkipped(\"nothing to upload\");\n\t\t\treturn;\n\t\t}\n\n\t\tdivider();\n\t\tsection(\"changes\");\n\t\tlines(\n\t\t\tdiff.details.map((f) => {\n\t\t\t\tif (f.status === \"added\") return lime(`+ ${f.name}`);\n\t\t\t\tif (f.status === \"changed\") return yellow(`~ ${f.name}`);\n\t\t\t\treturn red(`- ${f.name}`);\n\t\t\t}),\n\t\t);\n\t\tif (diff.unchanged > 0) {\n\t\t\tlines([dim(`${diff.unchanged} unchanged`)]);\n\t\t}\n\t\tdivider();\n\t} else {\n\t\tconst local = selectedFiles.filter((f) => f.source === \"local\");\n\t\tconst global = selectedFiles.filter((f) => f.source === \"global\");\n\n\t\tif (local.length > 0) {\n\t\t\tp.log.step(`${bold(\"LOCAL\")} ${dim(String(local.length))}`);\n\t\t\tdivider();\n\t\t\tfor (const [type, files] of groupByType(local)) {\n\t\t\t\tlines([`${lime(type.toUpperCase())} ${dim(`${files.length}`)}`]);\n\t\t\t\tlines(files.map((f) => dim(` ${f.relativePath}`)));\n\t\t\t}\n\t\t\tdivider();\n\t\t}\n\t\tif (global.length > 0) {\n\t\t\tp.log.step(`${bold(\"GLOBAL\")} ${dim(String(global.length))}`);\n\t\t\tdivider();\n\t\t\tfor (const [type, files] of groupByType(global)) {\n\t\t\t\tlines([`${lime(type.toUpperCase())} ${dim(`${files.length}`)}`]);\n\t\t\t\tlines(files.map((f) => dim(` ${f.relativePath}`)));\n\t\t\t}\n\t\t\tdivider();\n\t\t}\n\t\tconst shownLinks = detectedLinks.filter((l) => includedLinks.has(l.key));\n\t\tif (shownLinks.length > 0) {\n\t\t\tp.log.step(`${bold(\"LINKS\")} ${dim(String(shownLinks.length))}`);\n\t\t\tdivider();\n\t\t\tlines(shownLinks.map((l) => dim(` ${l.label}`)));\n\t\t\tdivider();\n\t\t}\n\t}\n\n\t// Action: upload, customize, or cancel\n\tconst action = await p.select({\n\t\tmessage: existingStack\n\t\t\t? \"Upload changes?\"\n\t\t\t: `Upload ${bold(String(selectedFiles.length))} files to your stack?`,\n\t\toptions: [\n\t\t\t{ value: \"upload\", label: \"Upload\" },\n\t\t\t{ value: \"customize\", label: \"Select files\" },\n\t\t\t{ value: \"cancel\", label: \"Cancel\" },\n\t\t],\n\t});\n\n\tif (p.isCancel(action) || action === \"cancel\") {\n\t\toutroCancel();\n\t\tprocess.exit(0);\n\t}\n\n\tif (action === \"customize\") {\n\t\tconst linkOptions = detectedLinks.map((l) => ({\n\t\t\tvalue: l.key,\n\t\t\tlabel: l.label,\n\t\t\thint: \"link\",\n\t\t}));\n\t\tconst selected = await p.multiselect({\n\t\t\tmessage: \"Select files to include:\",\n\t\t\toptions: [\n\t\t\t\t...linkOptions,\n\t\t\t\t...allFiles.map((f) => ({\n\t\t\t\t\tvalue: f.relativePath,\n\t\t\t\t\tlabel: f.relativePath,\n\t\t\t\t\thint: `${f.type}${f.source === \"global\" ? \" · global\" : \"\"}`,\n\t\t\t\t})),\n\t\t\t],\n\t\t\tinitialValues: [\n\t\t\t\t...detectedLinks\n\t\t\t\t\t.filter((l) => includedLinks.has(l.key))\n\t\t\t\t\t.map((l) => l.key),\n\t\t\t\t...selectedFiles.map((f) => f.relativePath),\n\t\t\t],\n\t\t});\n\n\t\tif (p.isCancel(selected)) {\n\t\t\toutroCancel();\n\t\t\tprocess.exit(0);\n\t\t}\n\n\t\tconst selectedSet = new Set(selected as string[]);\n\t\tselectedFiles = allFiles.filter((f) => selectedSet.has(f.relativePath));\n\t\texcluded = allFiles.filter((f) => !selectedSet.has(f.relativePath));\n\t\tincludedLinks.clear();\n\t\tfor (const l of detectedLinks) {\n\t\t\tif (selectedSet.has(l.key)) includedLinks.add(l.key);\n\t\t}\n\t\tallResources = withLinks(classify(selectedFiles));\n\n\t\tif (selectedFiles.length === 0 && includedLinks.size === 0) {\n\t\t\tp.log.warn(\"No files selected.\");\n\t\t\toutroSkipped(\"nothing to collect\");\n\t\t\tprocess.exit(0);\n\t\t}\n\t}\n\n\ts.start(\"Uploading...\");\n\ttry {\n\t\tconst result = await stackCollect(token, { resources: allResources });\n\t\ts.stop(lime(\"Uploaded\"));\n\t\tconst excludedKeys = excluded.map((f) => f.relativePath);\n\t\tfor (const l of detectedLinks) {\n\t\t\tif (!includedLinks.has(l.key)) excludedKeys.push(l.key);\n\t\t}\n\t\tsaveExcludedPaths(cwd, excludedKeys);\n\t\tp.log.success(dim(result.url));\n\t\toutro(lime(\"done\"));\n\t} catch (err) {\n\t\ts.stop(\"Upload failed\");\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\toutroError(\"upload failed\");\n\t\tprocess.exit(1);\n\t}\n}\n\nconst TYPE_ORDER = [\n\t\"config\",\n\t\"prompt\",\n\t\"rule\",\n\t\"command\",\n\t\"skill\",\n\t\"subagent\",\n\t\"mcp\",\n\t\"hook\",\n\t\"custom\",\n];\n\nfunction groupByType(files: ScannedFile[]): Map<string, ScannedFile[]> {\n\tconst map = new Map<string, ScannedFile[]>();\n\tfor (const f of files) {\n\t\tconst existing = map.get(f.type) ?? [];\n\t\texisting.push(f);\n\t\tmap.set(f.type, existing);\n\t}\n\tconst sorted = new Map<string, ScannedFile[]>();\n\tfor (const type of TYPE_ORDER) {\n\t\tconst group = map.get(type);\n\t\tif (group) sorted.set(type, group);\n\t}\n\tfor (const [type, group] of map) {\n\t\tif (!sorted.has(type)) sorted.set(type, group);\n\t}\n\treturn sorted;\n}\n\ninterface DiffResult {\n\tadded: number;\n\tchanged: number;\n\tremoved: number;\n\tunchanged: number;\n\tdetails: Array<{ name: string; status: \"added\" | \"changed\" | \"removed\" }>;\n}\n\nexport function diffResources(\n\tcurrent: Resource[],\n\texisting: Resource[],\n): DiffResult {\n\tconst existingMap = new Map<string, string>();\n\tfor (const item of existing) {\n\t\tfor (const file of item.files ?? []) {\n\t\t\texistingMap.set(file.path ?? file.name, file.content);\n\t\t}\n\t}\n\n\tconst currentMap = new Map<string, string>();\n\tfor (const item of current) {\n\t\tfor (const file of item.files ?? []) {\n\t\t\tcurrentMap.set(file.path ?? file.name, file.content);\n\t\t}\n\t}\n\n\tconst details: DiffResult[\"details\"] = [];\n\tlet added = 0;\n\tlet changed = 0;\n\tlet unchanged = 0;\n\n\tfor (const [key, content] of currentMap) {\n\t\tconst prev = existingMap.get(key);\n\t\tif (prev === undefined) {\n\t\t\tadded++;\n\t\t\tdetails.push({ name: key, status: \"added\" });\n\t\t} else if (prev !== content) {\n\t\t\tchanged++;\n\t\t\tdetails.push({ name: key, status: \"changed\" });\n\t\t} else {\n\t\t\tunchanged++;\n\t\t}\n\t}\n\n\tlet removed = 0;\n\tfor (const key of existingMap.keys()) {\n\t\tif (!currentMap.has(key)) {\n\t\t\tremoved++;\n\t\t\tdetails.push({ name: key, status: \"removed\" });\n\t\t}\n\t}\n\n\t// Linked resources (GitHub repos AND package refs like MCP servers) carry no\n\t// files, so the file maps above can't see them. Diff them by stableKey —\n\t// unique for both `linked:<repo>:<path>` and `linked:pkg:<registry>:<id>` —\n\t// otherwise a link-only change is invisible and collect wrongly reports\n\t// \"nothing to upload\".\n\tconst linkLabel = (item: Resource): string => {\n\t\tif (item.upstream)\n\t\t\treturn `link: ${repoNameFromCanonical(item.upstream.repoUrl)}`;\n\t\tif (item.pkg) return `link: ${item.pkg.id}`;\n\t\treturn `link: ${item.name}`;\n\t};\n\tconst linkMap = (items: Resource[]): Map<string, Resource> => {\n\t\tconst map = new Map<string, Resource>();\n\t\tfor (const item of items) {\n\t\t\tif ((item.upstream || item.pkg) && !item.files?.length) {\n\t\t\t\tmap.set(item.stableKey, item);\n\t\t\t}\n\t\t}\n\t\treturn map;\n\t};\n\tconst existingLinks = linkMap(existing);\n\tconst currentLinks = linkMap(current);\n\tfor (const [key, item] of currentLinks) {\n\t\tif (!existingLinks.has(key)) {\n\t\t\tadded++;\n\t\t\tdetails.push({ name: linkLabel(item), status: \"added\" });\n\t\t}\n\t}\n\tfor (const [key, item] of existingLinks) {\n\t\tif (!currentLinks.has(key)) {\n\t\t\tremoved++;\n\t\t\tdetails.push({ name: linkLabel(item), status: \"removed\" });\n\t\t}\n\t}\n\n\treturn { added, changed, removed, unchanged, details };\n}\n","import type { ScannedFile } from \"./scanner.js\";\nimport type { Resource } from \"./api.js\";\nimport { basename, dirname } from \"node:path\";\nimport { computeStableKey } from \"./stableKey.js\";\n\nexport function classify(files: ScannedFile[]): Resource[] {\n\t// Group by {group, source, type, containing directory}\n\tconst groups = new Map<string, ScannedFile[]>();\n\tconst singletons: ScannedFile[] = [];\n\n\tconst singletonRoots = new Set([\n\t\t\".\",\n\t\t\"~\",\n\t\t\"~/.claude\",\n\t\t\"~/.cursor\",\n\t\t\"~/.continue\",\n\t\t\".claude\",\n\t\t\".cursor\",\n\t\t\".github\",\n\t]);\n\n\tfor (const file of files) {\n\t\tconst dir = dirname(file.relativePath);\n\t\tconst isSingleton = singletonRoots.has(dir);\n\n\t\tif (isSingleton) {\n\t\t\tsingletons.push(file);\n\t\t} else {\n\t\t\tconst key = `${file.group}:${file.source}:${file.type}:${dir}`;\n\t\t\tconst existing = groups.get(key) ?? [];\n\t\t\texisting.push(file);\n\t\t\tgroups.set(key, existing);\n\t\t}\n\t}\n\n\tconst items: Resource[] = [];\n\n\t// Singletons: one Resource per file\n\tfor (const file of singletons) {\n\t\tconst relPath = file.relativePath\n\t\t\t.replace(/^~\\/\\.[^/]+\\//, \"\")\n\t\t\t.replace(/^\\.[^/]+\\//, \"\");\n\t\titems.push({\n\t\t\ttype: file.type,\n\t\t\tname: file.relativePath,\n\t\t\tgroup: file.group,\n\t\t\tstableKey: computeStableKey(file.group, file.type, relPath),\n\t\t\tfiles: [\n\t\t\t\t{\n\t\t\t\t\tname: basename(file.relativePath),\n\t\t\t\t\tcontent: file.content,\n\t\t\t\t\tpath: file.relativePath,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\t}\n\n\t// Groups: one Resource per directory group\n\tfor (const [, groupFiles] of groups) {\n\t\tconst first = groupFiles[0];\n\t\tconst dir = dirname(first.relativePath);\n\t\tconst relPath = dir\n\t\t\t.replace(/^~\\/\\.claude\\//, \"\")\n\t\t\t.replace(/^\\.claude\\//, \"\")\n\t\t\t.replace(/^~\\/\\.cursor\\//, \"\")\n\t\t\t.replace(/^\\.cursor\\//, \"\");\n\t\tconst typeLabel =\n\t\t\tfirst.type === \"subagent\" ? \"subagents\" : `${first.type}s`;\n\n\t\titems.push({\n\t\t\ttype: first.type,\n\t\t\tname: dir,\n\t\t\tdescription: `${groupFiles.length} ${typeLabel}`,\n\t\t\tgroup: first.group,\n\t\t\tstableKey: computeStableKey(first.group, first.type, relPath),\n\t\t\tfiles: groupFiles.map((f) => ({\n\t\t\t\tname: basename(f.relativePath),\n\t\t\t\tcontent: f.content,\n\t\t\t\tpath: f.relativePath,\n\t\t\t})),\n\t\t});\n\t}\n\n\treturn items;\n}\n","export function computeStableKey(\n\tgroup: string,\n\ttype: string,\n\trelPath: string,\n): string {\n\treturn `${group}:${type}:${relPath}`;\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst CONFIG_DIR = join(homedir(), \".config\", \"aistack\");\nconst CREDENTIALS_FILE = join(CONFIG_DIR, \"credentials.json\");\n\ninterface Credentials {\n\ttoken: string;\n\tuserId?: string;\n}\n\nexport function getToken(): string | null {\n\tif (!existsSync(CREDENTIALS_FILE)) return null;\n\ttry {\n\t\tconst data = JSON.parse(\n\t\t\treadFileSync(CREDENTIALS_FILE, \"utf-8\"),\n\t\t) as Credentials;\n\t\treturn data.token ?? null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport function saveToken(token: string, userId?: string): void {\n\tmkdirSync(CONFIG_DIR, { recursive: true });\n\twriteFileSync(CREDENTIALS_FILE, JSON.stringify({ token, userId }, null, 2));\n}\n\nexport function clearToken(): void {\n\tif (existsSync(CREDENTIALS_FILE)) {\n\t\twriteFileSync(CREDENTIALS_FILE, \"{}\");\n\t}\n}\n\nconst SETTINGS_FILE = join(CONFIG_DIR, \"settings.json\");\n\n/**\n * Machine-local switches (#56). A separate file from credentials.json so a\n * login overwrite never resets an answered upsell, and clearing settings never\n * touches the token.\n */\nexport interface Settings {\n\t/** The post-sync connect-claude upsell was answered (either way). */\n\tconnectClaudeAnswered?: boolean;\n}\n\nexport function getSettings(): Settings {\n\tif (!existsSync(SETTINGS_FILE)) return {};\n\ttry {\n\t\tconst raw = JSON.parse(readFileSync(SETTINGS_FILE, \"utf-8\"));\n\t\treturn raw && typeof raw === \"object\" ? (raw as Settings) : {};\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nexport function saveSettings(patch: Partial<Settings>): void {\n\tmkdirSync(CONFIG_DIR, { recursive: true });\n\twriteFileSync(\n\t\tSETTINGS_FILE,\n\t\tJSON.stringify({ ...getSettings(), ...patch }, null, 2),\n\t);\n}\n\nconst PROJECTS_FILE = join(CONFIG_DIR, \"projects.json\");\n\ninterface ProjectEntry {\n\texcluded?: string[];\n}\n\ninterface ProjectsData {\n\t[directory: string]: ProjectEntry;\n}\n\nfunction readProjects(): ProjectsData {\n\tif (!existsSync(PROJECTS_FILE)) return {};\n\ttry {\n\t\tconst raw = JSON.parse(readFileSync(PROJECTS_FILE, \"utf-8\"));\n\t\t// Tolerate legacy entries: string values (oldest) and objects that still\n\t\t// carry a `name` field. Only `excluded` is read going forward.\n\t\tconst data: ProjectsData = {};\n\t\tfor (const [key, value] of Object.entries(raw)) {\n\t\t\tif (typeof value === \"string\") {\n\t\t\t\tdata[key] = {};\n\t\t\t} else if (value && typeof value === \"object\") {\n\t\t\t\tconst excluded = (value as { excluded?: string[] }).excluded;\n\t\t\t\tdata[key] = Array.isArray(excluded) ? { excluded } : {};\n\t\t\t}\n\t\t}\n\t\treturn data;\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction writeProjects(data: ProjectsData): void {\n\tmkdirSync(CONFIG_DIR, { recursive: true });\n\twriteFileSync(PROJECTS_FILE, JSON.stringify(data, null, 2));\n}\n\nexport function getExcludedPaths(directory: string): string[] {\n\treturn readProjects()[directory]?.excluded ?? [];\n}\n\nexport function saveExcludedPaths(directory: string, excluded: string[]): void {\n\tconst data = readProjects();\n\tdata[directory] = {\n\t\texcluded: excluded.length > 0 ? excluded : undefined,\n\t};\n\twriteProjects(data);\n}\n","import { execFileSync } from \"node:child_process\";\nimport type { Resource } from \"./api.js\";\nimport {\n\tcanonicalizeRepoUrl,\n\tnormalizeUpstreamPath,\n\trepoNameFromCanonical,\n} from \"./github-repo.js\";\n\n/**\n * Returns the raw `origin` remote URL for a working directory, or null when it\n * can't be determined. Injectable so `detectRepoUrl` stays unit-testable\n * without spawning git.\n */\nexport type GitRemoteRunner = (cwd: string) => string | null;\n\nexport const defaultGitRemoteRunner: GitRemoteRunner = (cwd) => {\n\ttry {\n\t\t// argv form (no shell) — git walks up to the repo root itself, and\n\t\t// stderr is swallowed so \"not a git repository\" never leaks into the\n\t\t// CLI's output. git missing / no repo / no origin all throw → null.\n\t\treturn execFileSync(\"git\", [\"-C\", cwd, \"remote\", \"get-url\", \"origin\"], {\n\t\t\tencoding: \"utf-8\",\n\t\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t\t}).trim();\n\t} catch {\n\t\treturn null;\n\t}\n};\n\n/**\n * Detect the canonical GitHub repo URL for `cwd`, or null. Non-GitHub origins\n * (GitLab, Bitbucket, …) canonicalize to null, so this is a graceful no-op\n * outside of GitHub repos.\n */\nexport function detectRepoUrl(\n\tcwd: string,\n\trun: GitRemoteRunner = defaultGitRemoteRunner,\n): string | null {\n\tconst raw = run(cwd);\n\tif (!raw) return null;\n\treturn canonicalizeRepoUrl(raw);\n}\n\nexport interface LinkSpec {\n\t/** Canonical GitHub URL (https://github.com/owner/repo). */\n\tcanonical: string;\n\t/** Optional subpath within the repo. */\n\tpath?: string;\n\tname: string;\n\ttype: string;\n\tgroup: string;\n\t/** Optional pinned commit, stored as upstream.lastCommitSha. */\n\tsha?: string;\n}\n\n/**\n * Build a linked-resource payload. Mirrors the web `linkResource` mutation: no\n * files (upstream presence is the storage discriminator) and the exact\n * `linked:${canonical}:${normPath}` stableKey so the web unlink UI — which\n * matches by stableKey — recognizes it. `path`/`lastCommitSha` are omitted when\n * empty so the by_upstream dedup index matches at both write and query.\n */\nexport function buildLinkResource(spec: LinkSpec): Resource {\n\tconst normPath = normalizeUpstreamPath(spec.path);\n\treturn {\n\t\ttype: spec.type,\n\t\tname: spec.name,\n\t\tgroup: spec.group,\n\t\tstableKey: `linked:${spec.canonical}:${normPath}`,\n\t\tupstream: {\n\t\t\trepoUrl: spec.canonical,\n\t\t\t...(normPath ? { path: normPath } : {}),\n\t\t\t...(spec.sha ? { lastCommitSha: spec.sha } : {}),\n\t\t},\n\t};\n}\n\n/** The repo this project lives in: a GitHub link (stack-owned server-side). */\nexport function buildRepoLinkResource(canonical: string): Resource {\n\treturn buildLinkResource({\n\t\tcanonical,\n\t\tname: repoNameFromCanonical(canonical),\n\t\ttype: \"custom\",\n\t\tgroup: \"generic\",\n\t});\n}\n","/**\n * Trimmed copy of `src/lib/github-repo.ts` — the CANONICAL parser, whose\n * `github-repo.test.ts` is the canonical test table. Copied (not imported)\n * because the CLI ships as an independent npm package and its tsconfig\n * (`rootDir: \"src\"` + `declaration: true`) forbids cross-rootDir imports.\n * Keep these functions in sync with the canonical source.\n *\n * Only the pieces the CLI needs are included: `parseRepo`,\n * `canonicalizeRepoUrl`, `repoNameFromCanonical`, and `normalizeUpstreamPath`\n * (a null from `canonicalizeRepoUrl` is the CLI's graceful-skip signal, so\n * `isGithubRepoUrl` is intentionally omitted).\n */\n\nfunction isGithubHost(host: string): boolean {\n\tconst h = host.toLowerCase();\n\treturn h === \"github.com\" || h === \"www.github.com\";\n}\n\nexport function parseRepo(\n\tinput: string,\n): { owner: string; repo: string } | null {\n\tconst trimmed = input.trim();\n\tif (!trimmed) return null;\n\n\t// SCP-like form `git@host:owner/repo`: take the host and the path after the\n\t// colon. Otherwise strip the scheme, then split the leading host off the path.\n\tconst scpMatch = trimmed.match(/^[^@]+@([^:]+):(.+)$/);\n\tlet host: string;\n\tlet withoutHost: string;\n\tif (scpMatch) {\n\t\thost = scpMatch[1];\n\t\twithoutHost = scpMatch[2];\n\t} else {\n\t\tconst withoutScheme = trimmed.replace(/^[a-z]+:\\/\\//i, \"\");\n\t\tconst slash = withoutScheme.indexOf(\"/\");\n\t\tif (slash === -1) return null;\n\t\thost = withoutScheme.slice(0, slash);\n\t\twithoutHost = withoutScheme.slice(slash + 1);\n\t}\n\tif (!isGithubHost(host)) return null;\n\n\t// Drop any query string or anchor, then split into path segments.\n\tconst pathPart = withoutHost.replace(/[?#].*$/, \"\");\n\tconst segments = pathPart.split(\"/\").filter(Boolean);\n\n\tconst owner = segments[0];\n\tconst repo = segments[1]?.replace(/\\.git$/, \"\");\n\tif (!owner || !repo) return null;\n\n\treturn { owner: owner.toLowerCase(), repo: repo.toLowerCase() };\n}\n\nexport function canonicalizeRepoUrl(input: string): string | null {\n\tconst parsed = parseRepo(input);\n\tif (!parsed) return null;\n\treturn `https://github.com/${parsed.owner}/${parsed.repo}`;\n}\n\nexport function repoNameFromCanonical(canonical: string): string {\n\treturn parseRepo(canonical)?.repo ?? \"\";\n}\n\nexport function normalizeUpstreamPath(path: string | undefined): string {\n\tif (!path) return \"\";\n\treturn path.split(\"/\").filter(Boolean).join(\"/\");\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Resource } from \"./api.js\";\n\n/**\n * Extract hooks defined inline in Claude Code settings as discrete `hook`\n * resources — one per event (PreToolUse, PostToolUse, …). Without this they\n * only ride inside the collected settings.json config blob and never surface as\n * first-class hooks.\n *\n * These are HOSTED resources (the event's config block is the content), so they\n * participate in the normal file-based diff. They intentionally duplicate data\n * also present in the settings.json resource; the distinct `hooks:` stableKeys\n * mean no collision, and first-class visibility was the deliberate tradeoff.\n */\n\ninterface SettingsFile {\n\thooks?: Record<string, unknown>;\n}\n\nfunction readJson<T>(path: string): T | null {\n\ttry {\n\t\tif (!existsSync(path)) return null;\n\t\treturn JSON.parse(readFileSync(path, \"utf-8\")) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction hooksFrom(\n\tpath: string,\n\tsource: \"local\" | \"global\",\n\tout: Resource[],\n\tseen: Set<string>,\n) {\n\tconst hooks = readJson<SettingsFile>(path)?.hooks;\n\tif (!hooks || typeof hooks !== \"object\") return;\n\tfor (const [event, config] of Object.entries(hooks)) {\n\t\tconst stableKey = `hooks:${source}:${event}`;\n\t\tif (seen.has(stableKey)) continue;\n\t\tseen.add(stableKey);\n\t\tout.push({\n\t\t\ttype: \"hook\",\n\t\t\tname: event,\n\t\t\tgroup: \"claude-code\",\n\t\t\tstableKey,\n\t\t\tfiles: [\n\t\t\t\t{\n\t\t\t\t\tname: `${event}.json`,\n\t\t\t\t\tcontent: JSON.stringify(config, null, 2),\n\t\t\t\t\tpath: `hooks/${event}.json`,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\t}\n}\n\n/**\n * Detect inline hooks from project settings (`.claude/settings.json` +\n * `.claude/settings.local.json`) and global settings (`~/.claude/settings.json`).\n * Project settings win over the `.local` override on the same event.\n */\nexport function detectHooks(cwd: string, home: string = homedir()): Resource[] {\n\tconst out: Resource[] = [];\n\tconst seen = new Set<string>();\n\thooksFrom(join(cwd, \".claude\", \"settings.json\"), \"local\", out, seen);\n\thooksFrom(join(cwd, \".claude\", \"settings.local.json\"), \"local\", out, seen);\n\thooksFrom(join(home, \".claude\", \"settings.json\"), \"global\", out, seen);\n\treturn out;\n}\n","import { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\nimport { parse as parseToml } from \"smol-toml\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { Resource } from \"./api.js\";\n\n/**\n * Detect configured MCP servers and resolve each to a `pkg` reference (its\n * package identity), parsed from the launch `command`/`args` — npm/PyPI/OCI for\n * stdio servers, or a URL for remote (http/sse) servers. `env` is intentionally\n * dropped (it carries secrets), so this is a safer representation than uploading\n * the raw config file.\n */\n\nexport interface McpServerConfig {\n\tcommand?: string;\n\targs?: string[];\n\ttype?: string;\n\ttransport?: string;\n\turl?: string;\n}\n\nexport interface PkgRef {\n\tregistry: \"npm\" | \"pypi\" | \"oci\" | \"url\";\n\tid: string;\n\tversion?: string;\n\ttransport?: \"stdio\" | \"http\" | \"sse\";\n}\n\nfunction commandName(cmd: string): string {\n\treturn cmd.replace(/\\\\/g, \"/\").split(\"/\").pop() ?? cmd;\n}\n\n/** Split an npm/PyPI spec into id + version, handling scoped npm (@scope/n@v). */\nfunction splitVersion(spec: string): { id: string; version?: string } {\n\tconst at = spec.indexOf(\"@\", spec.startsWith(\"@\") ? 1 : 0);\n\tif (at <= 0) return { id: spec };\n\treturn { id: spec.slice(0, at), version: spec.slice(at + 1) || undefined };\n}\n\n/** First arg that isn't a flag (and isn't in `skip`). */\nfunction firstPositional(args: string[], skip = 0): string | undefined {\n\tfor (const a of args.slice(skip)) {\n\t\tif (!a.startsWith(\"-\")) return a;\n\t}\n\treturn undefined;\n}\n\n// docker/podman flags that consume the following token (so it isn't the image).\nconst CONTAINER_VALUE_FLAGS = new Set([\n\t\"-e\",\n\t\"--env\",\n\t\"-v\",\n\t\"--volume\",\n\t\"-p\",\n\t\"--publish\",\n\t\"-w\",\n\t\"--workdir\",\n\t\"--name\",\n\t\"--mount\",\n\t\"--network\",\n\t\"-u\",\n\t\"--user\",\n\t\"-l\",\n\t\"--label\",\n]);\n\nfunction containerImage(args: string[]): string | undefined {\n\tconst runIdx = args.indexOf(\"run\");\n\tconst rest = runIdx >= 0 ? args.slice(runIdx + 1) : args;\n\tfor (let i = 0; i < rest.length; i++) {\n\t\tconst a = rest[i];\n\t\tif (a.startsWith(\"-\")) {\n\t\t\tif (CONTAINER_VALUE_FLAGS.has(a) && !a.includes(\"=\")) i++;\n\t\t\tcontinue;\n\t\t}\n\t\treturn a; // first positional after `run` is the image\n\t}\n\treturn undefined;\n}\n\n/** Split a container image ref into id + tag (ignoring a registry host:port). */\nfunction splitImageTag(image: string): { id: string; version?: string } {\n\tconst colon = image.lastIndexOf(\":\");\n\tif (colon > 0 && !image.slice(colon + 1).includes(\"/\")) {\n\t\treturn { id: image.slice(0, colon), version: image.slice(colon + 1) };\n\t}\n\treturn { id: image };\n}\n\n/** Parse a single MCP server config into a package reference, or null. */\nexport function parseMcpPackage(server: McpServerConfig): PkgRef | null {\n\t// Remote server: a URL endpoint (http/sse).\n\tif (server.url) {\n\t\tconst t = (server.type ?? server.transport ?? \"\").toLowerCase();\n\t\treturn {\n\t\t\tregistry: \"url\",\n\t\t\tid: server.url,\n\t\t\ttransport: t === \"sse\" ? \"sse\" : \"http\",\n\t\t};\n\t}\n\n\tconst command = server.command ? commandName(server.command) : \"\";\n\tif (!command) return null;\n\tconst args = server.args ?? [];\n\n\t// npm-family runners.\n\tif (command === \"npx\" || command === \"bunx\" || command === \"pnpx\") {\n\t\tconst spec = firstPositional(args);\n\t\treturn spec\n\t\t\t? { registry: \"npm\", ...splitVersion(spec), transport: \"stdio\" }\n\t\t\t: null;\n\t}\n\tif ((command === \"pnpm\" || command === \"yarn\") && args[0] === \"dlx\") {\n\t\tconst spec = firstPositional(args, 1);\n\t\treturn spec\n\t\t\t? { registry: \"npm\", ...splitVersion(spec), transport: \"stdio\" }\n\t\t\t: null;\n\t}\n\n\t// Python-family runners.\n\tif (command === \"uvx\") {\n\t\tconst spec = firstPositional(args);\n\t\treturn spec\n\t\t\t? { registry: \"pypi\", ...splitVersion(spec), transport: \"stdio\" }\n\t\t\t: null;\n\t}\n\tif (command === \"pipx\" && args[0] === \"run\") {\n\t\tconst spec = firstPositional(args, 1);\n\t\treturn spec\n\t\t\t? { registry: \"pypi\", ...splitVersion(spec), transport: \"stdio\" }\n\t\t\t: null;\n\t}\n\tif (command === \"uv\" && args[0] === \"tool\" && args[1] === \"run\") {\n\t\tconst spec = firstPositional(args, 2);\n\t\treturn spec\n\t\t\t? { registry: \"pypi\", ...splitVersion(spec), transport: \"stdio\" }\n\t\t\t: null;\n\t}\n\tif (/^python[0-9.]*$/.test(command)) {\n\t\tconst i = args.indexOf(\"-m\");\n\t\tconst mod = i >= 0 ? args[i + 1] : undefined;\n\t\treturn mod ? { registry: \"pypi\", id: mod, transport: \"stdio\" } : null;\n\t}\n\n\t// Container runners.\n\tif (command === \"docker\" || command === \"podman\") {\n\t\tconst image = containerImage(args);\n\t\tif (!image) return null;\n\t\treturn { registry: \"oci\", ...splitImageTag(image), transport: \"stdio\" };\n\t}\n\n\t// node/deno/bun running a local script, or an unknown command → skip.\n\treturn null;\n}\n\n/** Build a `type:\"mcp\"` linked resource from a parsed package reference. */\nexport function buildMcpResource(\n\tname: string,\n\tgroup: string,\n\tpkg: PkgRef,\n): Resource {\n\treturn {\n\t\ttype: \"mcp\",\n\t\tname,\n\t\tgroup,\n\t\tstableKey: `linked:pkg:${pkg.registry}:${pkg.id}`,\n\t\tpkg,\n\t};\n}\n\nfunction readText(path: string): string | null {\n\ttry {\n\t\tif (!existsSync(path)) return null;\n\t\treturn readFileSync(path, \"utf-8\");\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction readParsed<T>(\n\tpath: string,\n\tparse: (raw: string) => unknown,\n): T | null {\n\tconst raw = readText(path);\n\tif (raw === null) return null;\n\ttry {\n\t\treturn parse(raw) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction readJson<T>(path: string): T | null {\n\treturn readParsed<T>(path, JSON.parse);\n}\nfunction readYaml<T>(path: string): T | null {\n\treturn readParsed<T>(path, parseYaml);\n}\nfunction readToml<T>(path: string): T | null {\n\treturn readParsed<T>(path, parseToml);\n}\n\ntype ServerMap = Record<string, McpServerConfig> | undefined;\ninterface McpFile {\n\tmcpServers?: ServerMap;\n\tservers?: ServerMap; // VS Code uses `servers`\n}\ninterface ClaudeJson {\n\tmcpServers?: ServerMap;\n\tprojects?: Record<string, { mcpServers?: ServerMap }>;\n}\n// Continue uses a LIST under mcpServers; Codex (TOML) uses `mcp_servers`.\ninterface ContinueYaml {\n\tmcpServers?: Array<{ name?: string } & McpServerConfig>;\n}\ninterface CodexToml {\n\tmcp_servers?: Record<string, McpServerConfig>;\n}\n\n/** Normalize Continue's list form to the common name→config map. */\nfunction continueListToMap(file: ContinueYaml | null): ServerMap {\n\tif (!file?.mcpServers?.length) return undefined;\n\tconst map: Record<string, McpServerConfig> = {};\n\tfile.mcpServers.forEach((s, i) => {\n\t\tmap[s.name ?? `server-${i}`] = s;\n\t});\n\treturn map;\n}\n\n/** Per-OS VS Code globalStorage bases (+ Code-OSS/VSCodium variants). */\nfunction vscodeGlobalStorageBases(home: string): string[] {\n\tconst apps = [\"Code\", \"Code - OSS\", \"VSCodium\"];\n\tlet root: string;\n\tif (platform() === \"darwin\") {\n\t\troot = join(home, \"Library\", \"Application Support\");\n\t} else if (platform() === \"win32\") {\n\t\troot = process.env.APPDATA ?? join(home, \"AppData\", \"Roaming\");\n\t} else {\n\t\troot = process.env.XDG_CONFIG_HOME ?? join(home, \".config\");\n\t}\n\treturn apps.map((app) => join(root, app, \"User\", \"globalStorage\"));\n}\n\n/**\n * Read MCP server configs across the known tool locations and return one\n * `type:\"mcp\"` pkg-link resource per server, deduped by package identity.\n * Project-level configs win over global ones on the same identity.\n */\nexport function detectMcpServers(\n\tcwd: string,\n\thome: string = homedir(),\n): Resource[] {\n\tconst out: Resource[] = [];\n\tconst seen = new Set<string>();\n\tconst add = (servers: ServerMap, group: string) => {\n\t\tfor (const [name, cfg] of Object.entries(servers ?? {})) {\n\t\t\tconst pkg = parseMcpPackage(cfg);\n\t\t\tif (!pkg) continue;\n\t\t\tconst resource = buildMcpResource(name, group, pkg);\n\t\t\tif (seen.has(resource.stableKey)) continue;\n\t\t\tseen.add(resource.stableKey);\n\t\t\tout.push(resource);\n\t\t}\n\t};\n\n\t// Project configs first (so they win dedup over global).\n\tadd(readJson<McpFile>(join(cwd, \".mcp.json\"))?.mcpServers, \"claude-code\");\n\tadd(readJson<McpFile>(join(cwd, \"mcp.json\"))?.mcpServers, \"generic\");\n\tadd(\n\t\treadJson<McpFile>(join(cwd, \".cursor\", \"mcp.json\"))?.mcpServers,\n\t\t\"cursor\",\n\t);\n\tadd(readJson<McpFile>(join(cwd, \".vscode\", \"mcp.json\"))?.servers, \"generic\");\n\tadd(\n\t\treadJson<McpFile>(join(cwd, \"claude_desktop_config.json\"))?.mcpServers,\n\t\t\"claude-desktop\",\n\t);\n\n\t// Continue (project): a list per YAML file under .continue/mcpServers/.\n\tfor (const file of listYamlFiles(join(cwd, \".continue\", \"mcpServers\"))) {\n\t\tadd(continueListToMap(readYaml<ContinueYaml>(file)), \"continue\");\n\t}\n\t// Roo (project).\n\tadd(readJson<McpFile>(join(cwd, \".roo\", \"mcp.json\"))?.mcpServers, \"roo\");\n\n\t// --- Global / stack-scoped: user-level tool configs ---\n\tconst claudeJson = readJson<ClaudeJson>(join(home, \".claude.json\"));\n\tadd(claudeJson?.projects?.[cwd]?.mcpServers, \"claude-code\");\n\tadd(claudeJson?.mcpServers, \"claude-code\");\n\tadd(\n\t\treadJson<McpFile>(join(home, \".cursor\", \"mcp.json\"))?.mcpServers,\n\t\t\"cursor\",\n\t);\n\t// Windsurf (global only).\n\tadd(\n\t\treadJson<McpFile>(join(home, \".codeium\", \"windsurf\", \"mcp_config.json\"))\n\t\t\t?.mcpServers,\n\t\t\"windsurf\",\n\t);\n\t// Cline + Roo: VS Code extension globalStorage (OS-specific base).\n\tfor (const base of vscodeGlobalStorageBases(home)) {\n\t\tadd(\n\t\t\treadJson<McpFile>(\n\t\t\t\tjoin(\n\t\t\t\t\tbase,\n\t\t\t\t\t\"saoudrizwan.claude-dev\",\n\t\t\t\t\t\"settings\",\n\t\t\t\t\t\"cline_mcp_settings.json\",\n\t\t\t\t),\n\t\t\t)?.mcpServers,\n\t\t\t\"cline\",\n\t\t);\n\t\tadd(\n\t\t\treadJson<McpFile>(\n\t\t\t\tjoin(\n\t\t\t\t\tbase,\n\t\t\t\t\t\"rooveterinaryinc.roo-cline\",\n\t\t\t\t\t\"settings\",\n\t\t\t\t\t\"mcp_settings.json\",\n\t\t\t\t),\n\t\t\t)?.mcpServers,\n\t\t\t\"roo\",\n\t\t);\n\t}\n\t// Continue (global).\n\tfor (const file of listYamlFiles(join(home, \".continue\", \"mcpServers\"))) {\n\t\tadd(continueListToMap(readYaml<ContinueYaml>(file)), \"continue\");\n\t}\n\t// Gemini CLI (global).\n\tadd(\n\t\treadJson<McpFile>(join(home, \".gemini\", \"settings.json\"))?.mcpServers,\n\t\t\"gemini\",\n\t);\n\t// Codex CLI (global, TOML).\n\tadd(\n\t\treadToml<CodexToml>(join(home, \".codex\", \"config.toml\"))?.mcp_servers,\n\t\t\"codex\",\n\t);\n\n\treturn out;\n}\n\n/** List `*.yaml`/`*.yml` files in a directory (empty if absent). */\nfunction listYamlFiles(dir: string): string[] {\n\ttry {\n\t\treturn readdirSync(dir)\n\t\t\t.filter((f) => f.endsWith(\".yaml\") || f.endsWith(\".yml\"))\n\t\t\t.map((f) => join(dir, f));\n\t} catch {\n\t\treturn [];\n\t}\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Resource } from \"./api.js\";\nimport { buildLinkResource } from \"./git.js\";\nimport { canonicalizeRepoUrl } from \"./github-repo.js\";\n\n/**\n * Detect installed Claude Code plugins from the on-disk registry and resolve\n * each to a GitHub link pointing at its TRUE upstream source (not the\n * aggregator marketplace), attached at stack scope (the user's toolchain).\n *\n * Registry shape (~/.claude/plugins/):\n * installed_plugins.json → { plugins: { \"<name>@<marketplace>\": [{ gitCommitSha, version, ... }] } }\n * known_marketplaces.json → { \"<marketplace>\": { source: { repo }, installLocation } }\n * <installLocation>/.claude-plugin/marketplace.json → { plugins: [{ name, source, ... }] }\n */\n\ninterface InstalledEntry {\n\tscope?: string;\n\tversion?: string;\n\tgitCommitSha?: string;\n}\n\nexport interface InstalledPlugins {\n\tplugins?: Record<string, InstalledEntry[]>;\n}\n\nexport interface KnownMarketplace {\n\tsource?: { source?: string; repo?: string; url?: string };\n\tinstallLocation?: string;\n}\n\nexport type KnownMarketplaces = Record<string, KnownMarketplace>;\n\n/** A plugin's source in marketplace.json — polymorphic. */\ntype PluginSource =\n\t| string\n\t| {\n\t\t\tsource?: string;\n\t\t\turl?: string;\n\t\t\tpath?: string;\n\t\t\tref?: string;\n\t\t\tsha?: string;\n\t };\n\ninterface ManifestPlugin {\n\tname: string;\n\tsource?: PluginSource;\n\trepository?: string;\n\thomepage?: string;\n}\n\nexport interface Manifest {\n\tplugins?: ManifestPlugin[];\n}\n\nfunction marketplaceRepoUrl(mp: KnownMarketplace | undefined): string | null {\n\tconst src = mp?.source;\n\tif (!src) return null;\n\tif (src.repo) return `https://github.com/${src.repo}`;\n\treturn src.url ?? null;\n}\n\n/** Resolve a plugin entry's source to a repo URL (+ optional subpath / sha). */\nfunction resolveSource(\n\tentry: ManifestPlugin,\n\tmpRepoUrl: string | null,\n): { url: string; path?: string; sha?: string } | null {\n\tconst src = entry.source;\n\tif (typeof src === \"string\") {\n\t\tif (!mpRepoUrl) return null;\n\t\tconst path = src.replace(/^\\.\\//, \"\").replace(/\\/+$/, \"\");\n\t\treturn { url: mpRepoUrl, path: path || undefined };\n\t}\n\tif (src && typeof src === \"object\" && src.url) {\n\t\treturn { url: src.url, path: src.path, sha: src.sha };\n\t}\n\tconst fallback = entry.repository ?? entry.homepage ?? mpRepoUrl;\n\treturn fallback ? { url: fallback } : null;\n}\n\n/** Pure: map the parsed registry + manifests to plugin link resources. */\nexport function resolvePluginLinks(\n\tinstalled: InstalledPlugins,\n\tmarketplaces: KnownMarketplaces,\n\tmanifests: Record<string, Manifest>,\n): Resource[] {\n\tconst out: Resource[] = [];\n\tfor (const [key, entries] of Object.entries(installed.plugins ?? {})) {\n\t\tconst at = key.lastIndexOf(\"@\");\n\t\tif (at <= 0) continue;\n\t\tconst pluginName = key.slice(0, at);\n\t\tconst marketplace = key.slice(at + 1);\n\n\t\tconst mpRepoUrl = marketplaceRepoUrl(marketplaces[marketplace]);\n\t\tconst entry = manifests[marketplace]?.plugins?.find(\n\t\t\t(p) => p.name === pluginName,\n\t\t);\n\t\tif (!entry) continue;\n\n\t\tconst resolved = resolveSource(entry, mpRepoUrl);\n\t\tif (!resolved) continue;\n\n\t\tconst canonical = canonicalizeRepoUrl(resolved.url);\n\t\tif (!canonical) continue; // non-GitHub source → skip (graceful)\n\n\t\tout.push(\n\t\t\tbuildLinkResource({\n\t\t\t\tcanonical,\n\t\t\t\tpath: resolved.path,\n\t\t\t\tname: pluginName,\n\t\t\t\ttype: \"plugin\",\n\t\t\t\tgroup: \"claude-code\",\n\t\t\t\tsha: resolved.sha ?? entries[0]?.gitCommitSha,\n\t\t\t}),\n\t\t);\n\t}\n\treturn out;\n}\n\nfunction readJson<T>(path: string): T | null {\n\ttry {\n\t\tif (!existsSync(path)) return null;\n\t\treturn JSON.parse(readFileSync(path, \"utf-8\")) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** IO wrapper: read the registry + manifests, return plugin link resources. */\nexport function detectInstalledPlugins(\n\tpluginsDir: string = join(homedir(), \".claude\", \"plugins\"),\n): Resource[] {\n\tconst installed = readJson<InstalledPlugins>(\n\t\tjoin(pluginsDir, \"installed_plugins.json\"),\n\t);\n\tif (!installed?.plugins) return [];\n\n\tconst marketplaces =\n\t\treadJson<KnownMarketplaces>(join(pluginsDir, \"known_marketplaces.json\")) ??\n\t\t{};\n\n\tconst manifests: Record<string, Manifest> = {};\n\tfor (const key of Object.keys(installed.plugins)) {\n\t\tconst mp = key.slice(key.lastIndexOf(\"@\") + 1);\n\t\tif (!mp || manifests[mp]) continue;\n\t\tconst installLocation =\n\t\t\tmarketplaces[mp]?.installLocation ?? join(pluginsDir, \"marketplaces\", mp);\n\t\tconst manifest = readJson<Manifest>(\n\t\t\tjoin(installLocation, \".claude-plugin\", \"marketplace.json\"),\n\t\t);\n\t\tif (manifest) manifests[mp] = manifest;\n\t}\n\n\treturn resolvePluginLinks(installed, marketplaces, manifests);\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, relative } from \"node:path\";\nimport ignore from \"ignore\";\n\nexport type FileType =\n\t| \"rule\"\n\t| \"mcp\"\n\t| \"skill\"\n\t| \"command\"\n\t| \"prompt\"\n\t| \"hook\"\n\t| \"subagent\"\n\t| \"config\"\n\t| \"custom\";\n\nexport interface ScannedFile {\n\tpath: string;\n\trelativePath: string;\n\tcontent: string;\n\ttype: FileType;\n\tsource: \"local\" | \"global\";\n\tgroup: string;\n}\n\nconst MAX_FILE_SIZE = 100 * 1024; // 100KB\n\ninterface FilePattern {\n\tpath: string;\n\ttype: FileType;\n\tgroup: string;\n}\n\nconst LOCAL_PATTERNS: FilePattern[] = [\n\t// Rules\n\t{ path: \"CLAUDE.md\", type: \"rule\", group: \"claude-code\" },\n\t{ path: \"AGENTS.md\", type: \"rule\", group: \"claude-code\" },\n\t{ path: \"GEMINI.md\", type: \"rule\", group: \"gemini\" },\n\t{ path: \".cursorrules\", type: \"rule\", group: \"cursor\" },\n\t{ path: \".windsurfrules\", type: \"rule\", group: \"windsurf\" },\n\t{ path: \".clinerules\", type: \"rule\", group: \"cline\" },\n\t{ path: \".roorules\", type: \"rule\", group: \"roo\" },\n\t{ path: \".github/copilot-instructions.md\", type: \"rule\", group: \"copilot\" },\n\t// MCP servers are detected separately as pkg-reference links (see mcp.ts) —\n\t// their config files are intentionally NOT collected as content here (which\n\t// would also upload `env` secrets).\n\t// Config\n\t{ path: \".aider.conf.yml\", type: \"config\", group: \"aider\" },\n\t{ path: \".continue/config.json\", type: \"config\", group: \"continue\" },\n\t{ path: \".continue/config.yaml\", type: \"config\", group: \"continue\" },\n\t{ path: \".claude/settings.json\", type: \"config\", group: \"claude-code\" },\n\t{\n\t\tpath: \".claude/settings.local.json\",\n\t\ttype: \"config\",\n\t\tgroup: \"claude-code\",\n\t},\n\t// Prompts\n\t{ path: \"system-prompt.md\", type: \"prompt\", group: \"generic\" },\n];\n\nconst LOCAL_DIR_PATTERNS: { dir: string; type: FileType; group: string }[] = [\n\t{ dir: \".cursor/rules\", type: \"rule\", group: \"cursor\" },\n\t{ dir: \".clinerules\", type: \"rule\", group: \"cline\" },\n\t{ dir: \".windsurf/rules\", type: \"rule\", group: \"windsurf\" },\n\t{ dir: \".roo/rules\", type: \"rule\", group: \"roo\" },\n\t{ dir: \".github/instructions\", type: \"rule\", group: \"copilot\" },\n\t{ dir: \".github/prompts\", type: \"prompt\", group: \"copilot\" },\n\t{ dir: \".claude/commands\", type: \"command\", group: \"claude-code\" },\n\t{ dir: \".claude/agents\", type: \"subagent\", group: \"claude-code\" },\n\t{ dir: \".claude/hooks\", type: \"hook\", group: \"claude-code\" },\n\t{ dir: \"prompts\", type: \"prompt\", group: \"generic\" },\n\t{ dir: \".ai\", type: \"custom\", group: \"generic\" },\n];\n\nfunction loadGitignore(cwd: string): ReturnType<typeof ignore> {\n\tconst ig = ignore();\n\tconst gitignorePath = join(cwd, \".gitignore\");\n\tif (existsSync(gitignorePath)) {\n\t\tig.add(readFileSync(gitignorePath, \"utf-8\"));\n\t}\n\tig.add([\"node_modules\", \".git\", \"dist\", \"build\", \".next\", \".output\"]);\n\treturn ig;\n}\n\nfunction readFileSafe(filePath: string): string | null {\n\ttry {\n\t\tconst stat = statSync(filePath);\n\t\tif (stat.size > MAX_FILE_SIZE) return null;\n\t\treturn readFileSync(filePath, \"utf-8\");\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction walkDir(dir: string, maxDepth = 3, currentDepth = 0): string[] {\n\tif (currentDepth >= maxDepth || !existsSync(dir)) return [];\n\tconst results: string[] = [];\n\ttry {\n\t\tfor (const entry of readdirSync(dir, { withFileTypes: true })) {\n\t\t\tconst fullPath = join(dir, entry.name);\n\t\t\tif (entry.isFile()) {\n\t\t\t\tresults.push(fullPath);\n\t\t\t} else if (entry.isDirectory()) {\n\t\t\t\tresults.push(...walkDir(fullPath, maxDepth, currentDepth + 1));\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t/* permission errors, etc */\n\t}\n\treturn results;\n}\n\nexport function scanLocal(cwd: string): ScannedFile[] {\n\tconst ig = loadGitignore(cwd);\n\tconst results: ScannedFile[] = [];\n\n\tfor (const pattern of LOCAL_PATTERNS) {\n\t\tconst filePath = join(cwd, pattern.path);\n\t\tconst content = readFileSafe(filePath);\n\t\tif (content !== null) {\n\t\t\tconst rel = relative(cwd, filePath);\n\t\t\tif (!ig.ignores(rel)) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: rel,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype: pattern.type,\n\t\t\t\t\tsource: \"local\",\n\t\t\t\t\tgroup: pattern.group,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const { dir, type, group } of LOCAL_DIR_PATTERNS) {\n\t\tconst dirPath = join(cwd, dir);\n\t\tconst files = walkDir(dirPath);\n\t\tfor (const filePath of files) {\n\t\t\tconst rel = relative(cwd, filePath);\n\t\t\tif (ig.ignores(rel)) continue;\n\t\t\tconst content = readFileSafe(filePath);\n\t\t\tif (content !== null) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: rel,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype,\n\t\t\t\t\tsource: \"local\",\n\t\t\t\t\tgroup,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// Scan for skill directories (dirs with SKILL.md, 3 levels deep)\n\ttry {\n\t\tfor (const entry of readdirSync(cwd, { withFileTypes: true }).filter((e) =>\n\t\t\te.isDirectory(),\n\t\t)) {\n\t\t\tif (ig.ignores(entry.name + \"/\")) continue;\n\t\t\tscanSkillDirs(join(cwd, entry.name), cwd, ig, results, 1);\n\t\t}\n\t} catch {\n\t\t/* permission errors */\n\t}\n\n\treturn results;\n}\n\nfunction scanSkillDirs(\n\tdir: string,\n\tcwd: string,\n\tig: ReturnType<typeof ignore>,\n\tresults: ScannedFile[],\n\tdepth: number,\n) {\n\tif (depth > 3) return;\n\tconst skillMd = join(dir, \"SKILL.md\");\n\tif (existsSync(skillMd)) {\n\t\tconst files = walkDir(dir, 1);\n\t\tfor (const filePath of files) {\n\t\t\tconst rel = relative(cwd, filePath);\n\t\t\tif (ig.ignores(rel)) continue;\n\t\t\tconst content = readFileSafe(filePath);\n\t\t\tif (content !== null) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: rel,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype: \"skill\",\n\t\t\t\t\tsource: \"local\",\n\t\t\t\t\tgroup: \"generic\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\ttry {\n\t\tfor (const entry of readdirSync(dir, { withFileTypes: true })) {\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tconst rel = relative(cwd, join(dir, entry.name));\n\t\t\t\tif (!ig.ignores(rel + \"/\")) {\n\t\t\t\t\tscanSkillDirs(join(dir, entry.name), cwd, ig, results, depth + 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t/* permission errors */\n\t}\n}\n\nexport function scanGlobal(): ScannedFile[] {\n\tconst home = homedir();\n\tconst results: ScannedFile[] = [];\n\n\tconst globalPatterns: FilePattern[] = [\n\t\t{ path: \".claude/CLAUDE.md\", type: \"rule\", group: \"claude-code\" },\n\t\t{ path: \".claude/settings.json\", type: \"config\", group: \"claude-code\" },\n\t\t{ path: \".continue/config.json\", type: \"config\", group: \"continue\" },\n\t\t{ path: \".continue/config.yaml\", type: \"config\", group: \"continue\" },\n\t\t{ path: \".aider.conf.yml\", type: \"config\", group: \"aider\" },\n\t\t{ path: \".gemini/GEMINI.md\", type: \"rule\", group: \"gemini\" },\n\t\t{ path: \".gemini/settings.json\", type: \"config\", group: \"gemini\" },\n\t\t{ path: \".codex/config.toml\", type: \"config\", group: \"codex\" },\n\t\t{\n\t\t\tpath: \".codeium/windsurf/memories/global_rules.md\",\n\t\t\ttype: \"rule\",\n\t\t\tgroup: \"windsurf\",\n\t\t},\n\t];\n\n\tfor (const pattern of globalPatterns) {\n\t\tconst filePath = join(home, pattern.path);\n\t\tconst content = readFileSafe(filePath);\n\t\tif (content !== null) {\n\t\t\tresults.push({\n\t\t\t\tpath: filePath,\n\t\t\t\trelativePath: `~/${pattern.path}`,\n\t\t\t\tcontent,\n\t\t\t\ttype: pattern.type,\n\t\t\t\tsource: \"global\",\n\t\t\t\tgroup: pattern.group,\n\t\t\t});\n\t\t}\n\t}\n\n\tconst globalDirs: { dir: string; type: FileType; group: string }[] = [\n\t\t{ dir: \".claude/commands\", type: \"command\", group: \"claude-code\" },\n\t\t{ dir: \".claude/agents\", type: \"subagent\", group: \"claude-code\" },\n\t\t{ dir: \".claude/hooks\", type: \"hook\", group: \"claude-code\" },\n\t\t{ dir: \".cursor/rules\", type: \"rule\", group: \"cursor\" },\n\t];\n\n\tfor (const { dir, type, group } of globalDirs) {\n\t\tconst dirPath = join(home, dir);\n\t\tconst files = walkDir(dirPath, 2);\n\t\tfor (const filePath of files) {\n\t\t\tconst content = readFileSafe(filePath);\n\t\t\tif (content !== null) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: `~/${relative(home, filePath)}`,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype,\n\t\t\t\t\tsource: \"global\",\n\t\t\t\t\tgroup,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// Global skills: ~/.claude/skills/<name>/SKILL.md (+ supporting files). Not\n\t// covered by globalDirs since each skill is its own dir keyed by SKILL.md.\n\tconst skillsRoot = join(home, \".claude\", \"skills\");\n\ttry {\n\t\tfor (const entry of readdirSync(skillsRoot, { withFileTypes: true })) {\n\t\t\tif (!entry.isDirectory()) continue;\n\t\t\tconst skillDir = join(skillsRoot, entry.name);\n\t\t\tif (!existsSync(join(skillDir, \"SKILL.md\"))) continue;\n\t\t\tfor (const filePath of walkDir(skillDir, 2)) {\n\t\t\t\tconst content = readFileSafe(filePath);\n\t\t\t\tif (content !== null) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\tpath: filePath,\n\t\t\t\t\t\trelativePath: `~/${relative(home, filePath)}`,\n\t\t\t\t\t\tcontent,\n\t\t\t\t\t\ttype: \"skill\",\n\t\t\t\t\t\tsource: \"global\",\n\t\t\t\t\t\tgroup: \"claude-code\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t/* skills dir absent / permission errors */\n\t}\n\n\treturn results;\n}\n","import * as p from \"@clack/prompts\";\n\nconst esc = (code: string) => `\\x1b[${code}m`;\nconst reset = esc(\"0\");\n\nconst LIME = \"163;230;53\";\nconst BLACK = \"0;0;0\";\nconst YELLOW = \"250;204;21\";\nconst RED = \"248;113;113\";\nconst MUTED = \"120;120;120\";\n\nexport const lime = (s: string) => `${esc(`38;2;${LIME}`)}${s}${reset}`;\nexport const limeBold = (s: string) =>\n\t`${esc(\"1\")}${esc(`38;2;${LIME}`)}${s}${reset}`;\nexport const bgLime = (s: string) =>\n\t`${esc(`48;2;${LIME}`)}${esc(`38;2;${BLACK}`)}${s}${reset}`;\nexport const yellow = (s: string) => `${esc(`38;2;${YELLOW}`)}${s}${reset}`;\nexport const red = (s: string) => `${esc(`38;2;${RED}`)}${s}${reset}`;\nexport const dim = (s: string) => `${esc(`38;2;${MUTED}`)}${s}${reset}`;\nexport const bold = (s: string) => `${esc(\"1\")}${s}${reset}`;\n\n// ■ logo square in lime + AISTACK in bold on lime bg\nexport const banner = (cmd: string) =>\n\t`${lime(\"■\")} ${bgLime(` AISTACK `)} ${bold(cmd.toUpperCase())}`;\n\n// Compact line with clack-style bar\nconst BAR = `${esc(`38;2;${MUTED}`)}│${reset}`;\n\nexport function lines(items: string[]) {\n\tfor (const item of items) {\n\t\tconsole.log(`${BAR} ${item}`);\n\t}\n}\n\nexport function section(label: string, count?: number) {\n\tconsole.log(`${BAR}`);\n\tconst countStr = count !== undefined ? ` ${dim(String(count))}` : \"\";\n\tconsole.log(`${BAR} ${bold(label.toUpperCase())}${countStr}`);\n}\n\nexport function divider() {\n\tconsole.log(`${BAR} ${dim(\"─\".repeat(40))}`);\n}\n\nexport function intro(cmd: string) {\n\tconsole.log();\n\tp.intro(banner(cmd));\n}\n\nexport function outro(msg: string) {\n\tp.outro(msg);\n\tconsole.log();\n}\n\nexport function outroError(msg: string) {\n\tp.outro(red(msg));\n\tconsole.log();\n}\n\nexport function outroCancel(msg = \"cancelled\") {\n\tp.cancel(dim(msg));\n\tconsole.log();\n}\n\nexport function outroSkipped(msg: string) {\n\tp.outro(dim(msg));\n\tconsole.log();\n}\n","// `aistack connect claude` — the opt-in in-session sync surface (#56, #57).\n//\n// Installs BOTH halves or NEITHER: the user-scoped MCP server registration and\n// the Skill copy travel together, because the Skill drives `sync_preview` /\n// `sync_publish` and has nothing to do without the server (#56 decision 3).\n// The harness argument leaves room for `connect codex` later without a rename.\n\nimport { spawnSync } from \"node:child_process\";\nimport { cpSync, existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as p from \"@clack/prompts\";\nimport { getSettings, saveSettings } from \"../config.js\";\nimport {\n\tdim,\n\tintro,\n\tlimeBold,\n\toutro,\n\toutroError,\n\toutroSkipped,\n} from \"../theme.js\";\n\n/** The documented manual install line, printed when we cannot run it. */\nexport const MANUAL_MCP_ADD =\n\t\"claude mcp add --scope user aistack -- npx -y @use-aistack/cli mcp\";\n\nconst MCP_ADD_ARGS = [\n\t\"mcp\",\n\t\"add\",\n\t\"--scope\",\n\t\"user\",\n\t\"aistack\",\n\t\"--\",\n\t\"npx\",\n\t\"-y\",\n\t\"@use-aistack/cli\",\n\t\"mcp\",\n];\n\nconst MCP_REMOVE_ARGS = [\"mcp\", \"remove\", \"--scope\", \"user\", \"aistack\"];\n\nexport const SKILL_DEST = join(homedir(), \".claude\", \"skills\", \"aistack-sync\");\n\nexport interface RunResult {\n\t/** The binary was not found on PATH. */\n\tnotFound: boolean;\n\tstatus: number | null;\n\toutput: string;\n}\n\nexport type Runner = (args: string[]) => RunResult;\n\nfunction runClaude(args: string[]): RunResult {\n\tconst r = spawnSync(\"claude\", args, { encoding: \"utf-8\" });\n\tconst notFound =\n\t\tr.error !== undefined &&\n\t\t(r.error as NodeJS.ErrnoException).code === \"ENOENT\";\n\treturn {\n\t\tnotFound,\n\t\tstatus: r.status,\n\t\toutput: `${r.stdout ?? \"\"}${r.stderr ?? \"\"}`,\n\t};\n}\n\n/** Is the `claude` binary reachable? Cheap check used to skip the upsell. */\nexport function claudeOnPath(run: Runner = runClaude): boolean {\n\treturn !run([\"--version\"]).notFound;\n}\n\n/**\n * The bundled Skill directory, resolved relative to this module. In the\n * published package that is `<pkg>/skills/aistack-sync` next to `dist/`; in\n * dev it is two levels up from `src/commands/`. Walking up covers both.\n */\nexport function findSkillSource(\n\tfromDir: string = dirname(fileURLToPath(import.meta.url)),\n): string | null {\n\tlet dir = fromDir;\n\tfor (let i = 0; i < 4; i++) {\n\t\tconst candidate = join(dir, \"skills\", \"aistack-sync\");\n\t\tif (existsSync(join(candidate, \"SKILL.md\"))) return candidate;\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) break;\n\t\tdir = parent;\n\t}\n\treturn null;\n}\n\nexport interface ConnectOutcome {\n\tok: boolean;\n\tmessage: string;\n}\n\n/**\n * Install the server registration, then the Skill. If the Skill copy fails\n * after a fresh registration, the registration is rolled back — both halves\n * or neither.\n */\nexport function installClaudeConnect(\n\trun: Runner = runClaude,\n\tcopySkill: (src: string, dest: string) => void = (src, dest) =>\n\t\tcpSync(src, dest, { recursive: true }),\n): ConnectOutcome {\n\tconst source = findSkillSource();\n\tif (source === null) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tmessage:\n\t\t\t\t\"this install is missing its bundled Skill (skills/aistack-sync) — nothing was installed\",\n\t\t};\n\t}\n\n\tconst add = run(MCP_ADD_ARGS);\n\tif (add.notFound) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tmessage: `claude was not found on PATH — nothing was installed. Manual install:\\n${MANUAL_MCP_ADD}`,\n\t\t};\n\t}\n\tconst alreadyRegistered =\n\t\tadd.status !== 0 && add.output.includes(\"already exists\");\n\tif (add.status !== 0 && !alreadyRegistered) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tmessage: `claude mcp add failed — nothing was installed.\\n${add.output.trim()}`,\n\t\t};\n\t}\n\n\ttry {\n\t\tcopySkill(source, SKILL_DEST);\n\t} catch (e) {\n\t\t// Both halves or neither: a fresh registration without its Skill is\n\t\t// rolled back. A pre-existing registration is left as it was.\n\t\tif (!alreadyRegistered) run(MCP_REMOVE_ARGS);\n\t\treturn {\n\t\t\tok: false,\n\t\t\tmessage: `copying the Skill to ${SKILL_DEST} failed — the MCP registration was ${\n\t\t\t\talreadyRegistered ? \"left as it was\" : \"rolled back\"\n\t\t\t}.\\n${e instanceof Error ? e.message : String(e)}`,\n\t\t};\n\t}\n\n\treturn {\n\t\tok: true,\n\t\tmessage: `Installed. Say ${limeBold('\"sync my stack\"')} in any Claude Code session.`,\n\t};\n}\n\nexport async function connectCommand(harness: string): Promise<void> {\n\tintro(\"connect\");\n\n\tif (harness !== \"claude\") {\n\t\toutroError(`unknown harness \"${harness}\" — supported: claude`);\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\tif (!claudeOnPath()) {\n\t\tp.log.warn(\n\t\t\t`claude was not found on PATH. Manual install:\\n${dim(MANUAL_MCP_ADD)}\\nplus copy skills/aistack-sync from this package to ${dim(SKILL_DEST)}`,\n\t\t);\n\t\toutroSkipped(\"nothing was installed\");\n\t\treturn;\n\t}\n\n\tconst result = installClaudeConnect();\n\tif (!result.ok) {\n\t\toutroError(result.message);\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\tp.log.success(result.message);\n\toutro(\"done\");\n}\n\n/**\n * The post-sync upsell (#56 decision 2), asked once per machine. Any explicit\n * answer persists to ~/.config/aistack/settings.json; ctrl-C is not an answer\n * and the question returns on the next sync. Skipped silently when claude is\n * not on PATH — the offer would be noise on a machine that cannot take it.\n */\nexport async function offerConnectUpsell(): Promise<void> {\n\tif (getSettings().connectClaudeAnswered === true) return;\n\tif (!claudeOnPath()) return;\n\n\tconst answer = await p.select({\n\t\tmessage: \"Sync from inside Claude Code too?\",\n\t\toptions: [\n\t\t\t{\n\t\t\t\tvalue: \"later\",\n\t\t\t\tlabel: \"Not now\",\n\t\t\t\thint: \"this question will not come back\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tvalue: \"install\",\n\t\t\t\tlabel: \"Install\",\n\t\t\t\thint: \"adds the aistack MCP server + Skill to Claude Code\",\n\t\t\t},\n\t\t],\n\t\tinitialValue: \"later\",\n\t});\n\n\tif (p.isCancel(answer)) return;\n\tsaveSettings({ connectClaudeAnswered: true });\n\n\tif (answer === \"install\") {\n\t\tconst result = installClaudeConnect();\n\t\tif (result.ok) {\n\t\t\tp.log.success(result.message);\n\t\t} else {\n\t\t\tp.log.error(result.message);\n\t\t}\n\t\treturn;\n\t}\n\n\tp.log.message(\n\t\t`If you change your mind: ${limeBold(\"npx @use-aistack/cli connect claude\")}`,\n\t);\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport { stackGet } from \"../api.js\";\nimport { getToken } from \"../config.js\";\nimport {\n\tbold,\n\tdim,\n\tdivider,\n\tintro,\n\tlime,\n\tlimeBold,\n\tlines,\n\toutro,\n\toutroCancel,\n\toutroError,\n\toutroSkipped,\n\tsection,\n\tyellow,\n} from \"../theme.js\";\n\nexport async function createCommand() {\n\tintro(\"create\");\n\n\tconst token = getToken();\n\tif (!token) {\n\t\tp.log.error(\n\t\t\t`Not authenticated. Run ${limeBold(\"npx @use-aistack/cli login\")} first.`,\n\t\t);\n\t\toutroError(\"not authenticated\");\n\t\tprocess.exit(1);\n\t}\n\n\tconst s = p.spinner();\n\ts.start(\"Fetching stack...\");\n\n\tlet stack: Awaited<ReturnType<typeof stackGet>>;\n\ttry {\n\t\tstack = await stackGet(token);\n\t\tif (!stack) {\n\t\t\ts.stop(\"Not found\");\n\t\t\tp.log.error(\"No stack found. Create a stack on aistack.to first.\");\n\t\t\toutroError(\"not found\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\ts.stop(bold(stack.name));\n\t} catch (err) {\n\t\ts.stop(\"Failed to fetch stack\");\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\toutroError(\"error\");\n\t\tprocess.exit(1);\n\t}\n\n\tconst localFiles: FileToWrite[] = [];\n\n\tfor (const item of stack.resources) {\n\t\tfor (const file of item.files ?? []) {\n\t\t\tlocalFiles.push({ path: file.path ?? file.name, content: file.content });\n\t\t}\n\t}\n\n\t// Linked resources have no files to write — surface them so they aren't\n\t// silently dropped on download (GitHub repos + package refs like MCP servers).\n\tconst linked = stack.resources.filter(\n\t\t(item) => (item.upstream || item.pkg) && !item.files?.length,\n\t);\n\tif (linked.length > 0) {\n\t\tsection(\"linked\", linked.length);\n\t\tlines([dim(\"view only\")]);\n\t\tlines(\n\t\t\tlinked.map((item) =>\n\t\t\t\tdim(\n\t\t\t\t\titem.upstream?.repoUrl ??\n\t\t\t\t\t\t(item.pkg ? `${item.pkg.registry}:${item.pkg.id}` : \"\"),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t}\n\n\tif (localFiles.length === 0) {\n\t\tp.log.warn(\"No local files to write.\");\n\t\toutroSkipped(\"nothing to create\");\n\t\treturn;\n\t}\n\n\tconst cwd = process.cwd();\n\tconst toWrite: FileToWrite[] = [];\n\tconst skipped: { path: string; differs: boolean }[] = [];\n\n\tfor (const f of localFiles) {\n\t\tconst fullPath = join(cwd, f.path);\n\t\tif (existsSync(fullPath)) {\n\t\t\tconst existing = readFileSync(fullPath, \"utf-8\");\n\t\t\tskipped.push({ path: f.path, differs: existing !== f.content });\n\t\t} else {\n\t\t\ttoWrite.push(f);\n\t\t}\n\t}\n\n\tsection(\"local files\", localFiles.length);\n\tlines(toWrite.map((f) => lime(`+ ${f.path}`)));\n\tlines(\n\t\tskipped.map((f) =>\n\t\t\tf.differs\n\t\t\t\t? `${yellow(`= ${f.path}`)} ${dim(\"(differs)\")}`\n\t\t\t\t: dim(`= ${f.path} (identical)`),\n\t\t),\n\t);\n\n\tif (toWrite.length === 0) {\n\t\tdivider();\n\t\tp.log.info(\"All local files already exist.\");\n\t\toutroSkipped(\"nothing to write\");\n\t\treturn;\n\t}\n\n\tdivider();\n\n\tconst confirm = await p.confirm({\n\t\tmessage: `Write ${lime(String(toWrite.length))} new files? ${dim(`(${skipped.length} skipped)`)}`,\n\t});\n\n\tif (p.isCancel(confirm) || !confirm) {\n\t\toutroCancel();\n\t\tprocess.exit(0);\n\t}\n\n\tfor (const f of toWrite) {\n\t\tconst fullPath = join(cwd, f.path);\n\t\tconst dir = dirname(fullPath);\n\t\tmkdirSync(dir, { recursive: true });\n\t\twriteFileSync(fullPath, f.content);\n\t}\n\n\tp.log.success(\n\t\t`${lime(String(toWrite.length))} written, ${dim(String(skipped.length) + \" skipped\")}`,\n\t);\n\toutro(lime(\"done\"));\n}\n\ninterface FileToWrite {\n\tpath: string;\n\tcontent: string;\n}\n","import { hostname } from \"node:os\";\nimport * as p from \"@clack/prompts\";\nimport open from \"open\";\nimport { authPoll, authStart } from \"../api.js\";\nimport { saveToken } from \"../config.js\";\nimport { dim, intro, lime, limeBold, outro, outroError } from \"../theme.js\";\n\n/**\n * What to call this machine on the account's linked-machines list (#49).\n *\n * The hostname is only a proposal — the approval page shows it in an editable\n * field before anything is stored. Trimmed to the server's 64-character bound so\n * a long hostname is dropped by us rather than silently by the server, and\n * `.local` is stripped because mDNS suffixes carry no information for a reader.\n */\nexport function proposedMachineName(\n\tread: () => string = hostname,\n): string | undefined {\n\ttry {\n\t\tconst name = read()\n\t\t\t.trim()\n\t\t\t.replace(/\\.local$/i, \"\");\n\t\tif (!name || name.length > 64) return undefined;\n\t\treturn name;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport async function loginCommand() {\n\tintro(\"login\");\n\n\tconst s = p.spinner();\n\ts.start(\"Starting authentication...\");\n\n\tlet session: Awaited<ReturnType<typeof authStart>>;\n\ttry {\n\t\tsession = await authStart(proposedMachineName());\n\t\ts.stop(\"Session created\");\n\t} catch (err) {\n\t\ts.stop(\"Failed to start authentication\");\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\toutroError(\"error\");\n\t\tprocess.exit(1);\n\t}\n\n\tp.log.info(`${dim(\"CODE\")} ${limeBold(session.userCode)}`);\n\tp.log.info(`${dim(\"OPEN\")} ${dim(session.authUrl)}`);\n\n\ttry {\n\t\tawait open(session.authUrl);\n\t} catch {\n\t\tp.log.warn(\n\t\t\t\"Could not open browser automatically. Please visit the URL above.\",\n\t\t);\n\t}\n\n\ts.start(\"Waiting for approval...\");\n\n\tconst maxAttempts = 36;\n\tfor (let i = 0; i < maxAttempts; i++) {\n\t\tawait new Promise((resolve) => setTimeout(resolve, 5000));\n\n\t\ttry {\n\t\t\tconst result = await authPoll(session.secretId);\n\n\t\t\tif (result.status === \"approved\" && result.token) {\n\t\t\t\ts.stop(lime(\"Authenticated\"));\n\t\t\t\tsaveToken(result.token, result.userId);\n\t\t\t\tp.log.success(\n\t\t\t\t\t`Token saved. Run ${limeBold(\"npx @use-aistack/cli collect\")} to get started.`,\n\t\t\t\t);\n\t\t\t\toutro(lime(\"done\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (result.status === \"expired\") {\n\t\t\t\ts.stop(\"Session expired\");\n\t\t\t\tp.log.error(\"Authentication session expired. Please try again.\");\n\t\t\t\toutroError(\"expired\");\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\ts.stop(\"Error polling\");\n\t\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\t\toutroError(\"error\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\ts.stop(\"Timed out\");\n\tp.log.error(\"Authentication timed out after 3 minutes. Please try again.\");\n\toutroError(\"timed out\");\n\tprocess.exit(1);\n}\n","// The documented default sync surface (#56, built by #55/#57).\n//\n// The MCP-free channel: a human types `aistack sync` in their own terminal,\n// so a real TTY exists and the gate can be a @clack/prompts select. Same\n// staged-bytes property as the MCP server (#41): the summary and the confirm\n// derive from the exact serialized `bodyJson`, and that string goes on the\n// wire byte-identical. One gate policy, two renderings.\n//\n// Fail-closed: ctrl-C, ESC, EOF, and a missing TTY all resolve to \"nothing\n// was sent\" before any network call.\n\nimport * as p from \"@clack/prompts\";\nimport { BASE_URL, syncPublish } from \"../api.js\";\nimport { stageSync } from \"../sync/stage.js\";\nimport { dim, intro, lime, outro, outroCancel, outroError } from \"../theme.js\";\nimport { offerConnectUpsell } from \"./connect.js\";\n\nexport async function syncCommand(): Promise<void> {\n\tintro(\"sync\");\n\n\t// The whole premise of this channel is a human at a terminal. A pipe or a\n\t// model-launched Bash call has no TTY, and a gate that cannot ask must not\n\t// send (#31) — refuse before scanning anything.\n\tif (!process.stdin.isTTY || !process.stdout.isTTY) {\n\t\toutroError(\"sync needs an interactive terminal — nothing was sent\");\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\tconst s = p.spinner();\n\ts.start(\"Scanning local Claude Code transcripts\");\n\tlet staged: Awaited<ReturnType<typeof stageSync>>;\n\ttry {\n\t\tstaged = await stageSync({ baseUrl: BASE_URL });\n\t} catch (e) {\n\t\ts.stop(\"Scan failed\");\n\t\toutroError(e instanceof Error ? e.message : String(e));\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\ts.stop(\"Scan complete\");\n\n\t// Beat one — the same full summary the MCP preview returns, verbatim,\n\t// printed behind the clack bar so it reads as one flow.\n\tp.log.message(staged.summary.split(\"\\n\").join(\"\\n\"));\n\n\tif (staged.blockedReason !== null) {\n\t\toutroError(staged.blockedReason);\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\t// Beat two — the same short dialog text, as a select. The enum mirrors the\n\t// elicitation's {publish, cancel}; cancel is the initial value, so Enter\n\t// alone publishes nothing.\n\tconst decision = await p.select({\n\t\tmessage: staged.dialog.split(\"\\n\").join(dim(\" · \")),\n\t\toptions: [\n\t\t\t{ value: \"cancel\", label: \"Cancel\", hint: \"nothing leaves this machine\" },\n\t\t\t{ value: \"publish\", label: \"Publish\" },\n\t\t],\n\t\tinitialValue: \"cancel\",\n\t});\n\n\tif (p.isCancel(decision) || decision !== \"publish\") {\n\t\toutroCancel(\"nothing was sent\");\n\t\treturn;\n\t}\n\n\ts.start(\"Publishing\");\n\ttry {\n\t\tconst res = await syncPublish(staged.token as string, staged.bodyJson);\n\t\ts.stop(\"Published\");\n\t\tconst lines = [\n\t\t\t`Snapshot received at ${new Date(res.receivedAt).toISOString()}`,\n\t\t\tlime(res.url),\n\t\t];\n\t\tif (res.keptPrivate.refused && staged.body.keptPrivate !== undefined) {\n\t\t\tlines.push(\n\t\t\t\t\"Note: the kept-private names were refused by the server — the review switch is off there now. They stayed on this machine.\",\n\t\t\t);\n\t\t} else if (res.keptPrivate.stored > 0) {\n\t\t\tlines.push(\n\t\t\t\t`${res.keptPrivate.stored} kept-private names went up for your review at ${res.url}/changes`,\n\t\t\t);\n\t\t}\n\t\tp.log.message(lines.join(\"\\n\"));\n\t\tawait offerConnectUpsell();\n\t\toutro(\"done\");\n\t} catch (e) {\n\t\ts.stop(\"Publish failed\");\n\t\toutroError(e instanceof Error ? e.message : String(e));\n\t\tprocess.exitCode = 1;\n\t}\n}\n","// Stage one send: scan → build → derive the gate's text from the exact bytes.\n//\n// Wayfinder ticket #41 (map #29). The staged `bodyJson` string IS what a\n// publish transmits — the summary and the dialog are derived from it and from\n// nothing else, so the user can never approve a sentence about different bytes\n// (#35's binding constraint). The publish tool takes only the stage id; it can\n// name WHICH staged send to release, never what is in it.\n\nimport { createHash } from \"node:crypto\";\nimport { getToken } from \"../config.js\";\nimport {\n\ttype KeptPrivateAtom,\n\ttype LoadedSyncConfig,\n\tloadSyncConfig,\n\ttype NameCategory,\n\ttype SyncConfig,\n} from \"../transcripts/allowlist.js\";\nimport { createAggregate } from \"../transcripts/analyzer.js\";\nimport { DEFAULT_WINDOW_DAYS } from \"../transcripts/index.js\";\nimport {\n\tbuildPayload,\n\tbuildSyncBody,\n\ttype SyncBody,\n} from \"../transcripts/payload.js\";\nimport { type ScanStats, scan, windowStartMs } from \"../transcripts/scan.js\";\nimport { buildGateDialog, buildGateSummary } from \"./summary.js\";\n\nexport type StagedSend = {\n\t/** Content-derived: the sha256 prefix of `bodyJson`. Same bytes, same id. */\n\tid: string;\n\t/** The exact request body a publish sends, already serialized. */\n\tbodyJson: string;\n\tbody: SyncBody;\n\tkeptPrivate: Record<NameCategory, KeptPrivateAtom[]>;\n\tsummary: string;\n\tdialog: string;\n\tconfig: SyncConfig;\n\ttoken: string | null;\n\tstagedAt: number;\n\t/**\n\t * `null` when this stage may not publish, with `blockedReason` saying why.\n\t * A gate that cannot name its destination must not send (#33 decision 7),\n\t * so no token and no resolved stack both block here, before any dialog.\n\t */\n\tblockedReason: string | null;\n};\n\nexport type StageDeps = {\n\tbaseUrl: string;\n\tnow?: () => number;\n\tgetTokenImpl?: () => string | null;\n\tloadConfigImpl?: (opts: {\n\t\tbaseUrl: string;\n\t\ttoken?: string;\n\t}) => Promise<LoadedSyncConfig>;\n\tscanImpl?: typeof scan;\n\twindowDays?: number;\n};\n\nexport function stageId(bodyJson: string): string {\n\treturn createHash(\"sha256\").update(bodyJson).digest(\"hex\").slice(0, 12);\n}\n\nexport async function stageSync(deps: StageDeps): Promise<StagedSend> {\n\tconst now = (deps.now ?? Date.now)();\n\tconst token = (deps.getTokenImpl ?? getToken)();\n\tconst loadConfig = deps.loadConfigImpl ?? loadSyncConfig;\n\tconst doScan = deps.scanImpl ?? scan;\n\tconst windowDays = deps.windowDays ?? DEFAULT_WINDOW_DAYS;\n\n\tconst { config, source } = await loadConfig({\n\t\tbaseUrl: deps.baseUrl,\n\t\t...(token ? { token } : {}),\n\t});\n\n\tconst aggregate = createAggregate();\n\tconst stats: ScanStats = await doScan(aggregate, {\n\t\tsinceMs: windowStartMs(now, windowDays),\n\t});\n\n\tconst built = buildPayload({\n\t\taggregate,\n\t\tstats,\n\t\tsyncConfig: config,\n\t\tnow,\n\t\twindowDays,\n\t});\n\tconst body = buildSyncBody(built, config);\n\tconst bodyJson = JSON.stringify(body);\n\n\tconst ctx = {\n\t\tbody,\n\t\tkeptPrivate: built.keptPrivate,\n\t\tconfig,\n\t\tsource,\n\t\tbaseUrl: deps.baseUrl,\n\t};\n\n\tlet blockedReason: string | null = null;\n\tif (token === null) {\n\t\tblockedReason =\n\t\t\t\"This machine is not linked. Run `npx @use-aistack/cli login` first.\";\n\t} else if (config.stack === null) {\n\t\tblockedReason =\n\t\t\tsource === \"bundled\"\n\t\t\t\t? \"Could not fetch your settings from aistack, so the destination stack is unknown. Publish needs it. Check the network and preview again.\"\n\t\t\t\t: \"The token resolves no destination stack. Run `npx @use-aistack/cli login` again to re-link this machine.\";\n\t}\n\n\treturn {\n\t\tid: stageId(bodyJson),\n\t\tbodyJson,\n\t\tbody,\n\t\tkeptPrivate: built.keptPrivate,\n\t\tsummary: buildGateSummary(ctx),\n\t\tdialog: buildGateDialog(ctx),\n\t\tconfig,\n\t\ttoken,\n\t\tstagedAt: now,\n\t\tblockedReason,\n\t};\n}\n","// Time-aware pinned price table for API-equivalent cost.\n//\n// Wayfinder ticket #37 (map #29), decision 8 of the wire-format grilling #33.\n//\n// WHY THIS IS A LIST OF PERIODS AND NOT A FLAT MAP\n// A published \"API-equivalent cost\" covers a rolling 30-day window, and a\n// window can straddle a repricing. On 2026-09-05 the window covers Aug 6 →\n// Sep 5, but `claude-sonnet-5`'s introductory rate ends Aug 31 — so 25 days\n// price at $2/$10 and 5 days at $3/$15. A flat table misprices one side or the\n// other for a month after every repricing, which breaks the honesty tenet the\n// measured layer is built on.\n//\n// So each model's price is a list of effective-from ranges, and every response\n// is priced at the rate in effect at ITS OWN timestamp. Cost therefore has to\n// accumulate at ingest (see analyzer.ts) — summing tokens per model and pricing\n// once at the end cannot express a mid-window rate change.\n//\n// Source: Anthropic public list prices as of 2026-07-25. Cache multipliers from\n// https://platform.claude.com/docs/en/build-with-claude/prompt-caching:\n// 5m cache write = 1.25x input, 1h cache write = 2x input, read = 0.1x input.\n\nexport const PRICING_TABLE_VERSION = \"anthropic-list-2026-07-25\";\n\nexport const CACHE_WRITE_5M_MULTIPLIER = 1.25;\nexport const CACHE_WRITE_1H_MULTIPLIER = 2.0;\nexport const CACHE_READ_MULTIPLIER = 0.1;\n\n/**\n * End of the `claude-sonnet-5` introductory rate. Anthropic documents it as \"in\n * effect through 2026-08-31\", so the post-intro period opens at the following\n * UTC midnight.\n *\n * The boundary is approximated in UTC because the announcement names a date,\n * not a timezone. A response written within a few hours of the boundary can\n * therefore be priced on the wrong side of it — worth a handful of cents on a\n * single day, and the alternative (guessing US/Pacific) is no more defensible.\n */\nexport const SONNET_5_INTRO_ENDS_MS = Date.UTC(2026, 8, 1); // 2026-09-01T00:00:00Z\n\n/** USD per million tokens, valid over `[from, to)`. */\nexport type PricePeriod = {\n\t/** Inclusive lower bound, epoch ms. `null` = since the model existed. */\n\tfrom: number | null;\n\t/** Exclusive upper bound, epoch ms. `null` = still in effect. */\n\tto: number | null;\n\tinput: number;\n\toutput: number;\n};\n\n/**\n * Only rates we can actually cite are encoded. Inventing historical periods to\n * make the table look complete would fabricate cost for old records, so every\n * model with one known rate gets one open-ended period.\n */\nconst PRICES: Record<string, PricePeriod[]> = {\n\t\"claude-fable-5\": [{ from: null, to: null, input: 10, output: 50 }],\n\t\"claude-mythos-5\": [{ from: null, to: null, input: 10, output: 50 }],\n\t\"claude-opus-5\": [{ from: null, to: null, input: 5, output: 25 }],\n\t\"claude-opus-4-8\": [{ from: null, to: null, input: 5, output: 25 }],\n\t\"claude-opus-4-7\": [{ from: null, to: null, input: 5, output: 25 }],\n\t\"claude-opus-4-6\": [{ from: null, to: null, input: 5, output: 25 }],\n\t\"claude-sonnet-5\": [\n\t\t{ from: null, to: SONNET_5_INTRO_ENDS_MS, input: 2, output: 10 },\n\t\t{ from: SONNET_5_INTRO_ENDS_MS, to: null, input: 3, output: 15 },\n\t],\n\t\"claude-sonnet-4-6\": [{ from: null, to: null, input: 3, output: 15 }],\n\t\"claude-haiku-4-5\": [{ from: null, to: null, input: 1, output: 5 }],\n\t// Fast mode (research preview) — Claude API only, Opus 5 / Opus 4.8 only.\n\t// Opus 4.7 fast mode was removed, so there is deliberately no 4-7 entry.\n\t\"claude-opus-5#fast\": [{ from: null, to: null, input: 10, output: 50 }],\n\t\"claude-opus-4-8#fast\": [{ from: null, to: null, input: 10, output: 50 }],\n};\n\nexport type TokenCounts = {\n\tinput: number;\n\toutput: number;\n\tcacheWrite5m: number;\n\tcacheWrite1h: number;\n\t/** `cache_creation_input_tokens` not covered by the TTL breakdown; priced at the 5m rate. */\n\tcacheWriteUnsplit: number;\n\tcacheRead: number;\n};\n\n/**\n * Normalize an observed `message.model` into a pricing key. Handles the\n * dated-suffix variants (`claude-haiku-4-5-20251001`). The `#fast` suffix is\n * appended by the caller from `usage.speed`.\n */\nexport function normalizeModel(model: string): string {\n\tconst [base, suffix] = model.split(\"#\");\n\tconst stripped = base.replace(/-\\d{8}$/, \"\");\n\treturn suffix ? `${stripped}#${suffix}` : stripped;\n}\n\n/** Drop the analyzer's synthetic `#fast` suffix, leaving the vendor-assigned id. */\nexport function baseModelId(modelKey: string): string {\n\treturn modelKey.split(\"#\")[0];\n}\n\n/**\n * The rate in effect for `modelKey` at `atMs`, or `null` when the model is\n * unknown or the timestamp predates every period we can cite.\n *\n * A `null` timestamp also yields `null`: a record with no parseable timestamp\n * cannot be priced time-awarely, and inventing a price for it (say, today's)\n * would silently attribute the wrong rate. Its tokens surface as unpriced.\n */\nexport function priceAt(\n\tmodelKey: string,\n\tatMs: number | null,\n): PricePeriod | null {\n\tif (atMs === null) return null;\n\tconst periods = PRICES[modelKey];\n\tif (!periods) return null;\n\tfor (const p of periods) {\n\t\tif ((p.from === null || atMs >= p.from) && (p.to === null || atMs < p.to)) {\n\t\t\treturn p;\n\t\t}\n\t}\n\treturn null;\n}\n\n/** True when we hold at least one citable rate for this model, at any time. */\nexport function isPricedModel(modelKey: string): boolean {\n\treturn PRICES[modelKey] !== undefined;\n}\n\n/**\n * Cost of one response's tokens at the rate in effect at its own timestamp.\n * Returns `null` when no rate applies — the caller must surface that as\n * unpriced tokens rather than zeroing it.\n */\nexport function apiEquivalentCost(\n\tmodelKey: string,\n\tt: TokenCounts,\n\tatMs: number | null,\n): number | null {\n\tconst p = priceAt(modelKey, atMs);\n\tif (!p) return null;\n\tconst M = 1_000_000;\n\treturn (\n\t\t(t.input * p.input +\n\t\t\tt.output * p.output +\n\t\t\t(t.cacheWrite5m + t.cacheWriteUnsplit) *\n\t\t\t\tp.input *\n\t\t\t\tCACHE_WRITE_5M_MULTIPLIER +\n\t\t\tt.cacheWrite1h * p.input * CACHE_WRITE_1H_MULTIPLIER +\n\t\t\tt.cacheRead * p.input * CACHE_READ_MULTIPLIER) /\n\t\tM\n\t);\n}\n","// Pure fold over parsed Claude Code transcript records. No I/O, no console.\n//\n// Wayfinder ticket #37 (map #29), productizing the #32 prototype. Field\n// semantics come from docs/research/claude-code-transcripts-2026-07.md (#30),\n// as corrected by #32 and #33. Every field is treated as untrusted and\n// optional: records arrive as `unknown` and are narrowed here.\n//\n// THE LOAD-BEARING SUBTLETY — read before touching `ingestAssistant`.\n// Claude Code writes ONE API response as SEVERAL JSONL records: each carries a\n// distinct content block (thinking, then tool_use, then tool_use...) and a\n// *cumulative* `usage` snapshot that grows with each record. Measured on a real\n// corpus: 20,073 of 44,280 response groups have differing usage across their\n// records, 20,071 of them monotonically increasing.\n//\n// So there are three wrong ways to count and one right way:\n// - sum every record -> ~2x over\n// - keep the first record -> ~2.1x under\n// - keep the last record -> right, but relies on file order\n// - keep the largest total -> right, order-independent <- this\n// Keeping the largest total is also ccusage's documented rule\n// (`should_replace_deduped_entry`).\n//\n// THE SECOND SUBTLETY — cost accumulates HERE, not in `finalize`.\n// Decision 8 of #33 made pricing time-aware, so a response is priced at the\n// rate in effect at its own timestamp. Summing tokens per model and pricing\n// once at the end cannot express a rate change inside the window, so each\n// response's cost is computed as it is ingested and un-applied on replace.\n\nimport {\n\tapiEquivalentCost,\n\tisPricedModel,\n\tnormalizeModel,\n\ttype TokenCounts,\n} from \"./pricing.js\";\n\n// ---------------------------------------------------------------------------\n// Narrowing helpers — records are untrusted external JSON\n// ---------------------------------------------------------------------------\n\ntype Obj = Record<string, unknown>;\n\nconst asObj = (v: unknown): Obj | null =>\n\ttypeof v === \"object\" && v !== null && !Array.isArray(v) ? (v as Obj) : null;\nconst asStr = (v: unknown): string | null =>\n\ttypeof v === \"string\" && v.length > 0 ? v : null;\nconst asNum = (v: unknown): number =>\n\ttypeof v === \"number\" && Number.isFinite(v) ? v : 0;\nconst asArr = (v: unknown): unknown[] => (Array.isArray(v) ? v : []);\n\n/**\n * Every name that becomes a Map key or leaves this module goes through here.\n *\n * These are user-chosen strings (skill names, MCP servers, subagent types,\n * slash commands, model ids) and a hostile one is a real vector: control\n * characters move a terminal cursor, and an unterminated bidi override (U+202E)\n * reorders the rest of the rendered line — including the count and percentage\n * printed beside the name. Both survive `JSON.stringify`, which escapes C0 but\n * not bidi. See CVE-2021-42574 (\"Trojan Source\").\n *\n * Sanitizing at ingest rather than at print means the guarantee travels with\n * the module: `finalize()`'s output is safe for any consumer, not just the\n * renderer that happens to sit in front of it today.\n */\nconst NAME_UNSAFE_RE =\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: stripping them is the point\n\t/[\\u0000-\\u001f\\u007f-\\u009f\\u00ad\\u061c\\u200b-\\u200f\\u2028-\\u202e\\u2060-\\u2064\\u2066-\\u2069\\ufeff]/g;\nconst NAME_MAX = 64;\n\nexport function cleanName(s: string): string {\n\tconst stripped = s.replace(NAME_UNSAFE_RE, \"�\").trim();\n\tif (stripped.length === 0) return \"(unnamed)\";\n\treturn stripped.length > NAME_MAX\n\t\t? `${stripped.slice(0, NAME_MAX - 1)}…`\n\t\t: stripped;\n}\n\n/**\n * The same bar as `cleanName`, asked as a question.\n *\n * Used on names arriving from the NETWORK — the per-stack opt-ins the sync\n * config carries (#44). Those are the user's own strings, so the curated list's\n * conventional charset is the wrong bar: parentheses, accents and CJK are all\n * legitimate names someone runs. What is refused is what cannot be rendered\n * safely, which is exactly what `cleanName` strips on the way in.\n */\nexport function isDisplaySafeName(s: string): boolean {\n\tif (s.length === 0 || s.trim().length === 0) return false;\n\tif (s.length > NAME_MAX) return false;\n\t// A `g`-flagged regex carries `lastIndex` across `.test` calls, so this uses\n\t// a fresh non-global copy rather than the shared literal.\n\treturn !new RegExp(NAME_UNSAFE_RE.source).test(s);\n}\n\n/** `asStr` for anything that will be used as a name. */\nconst asName = (v: unknown): string | null => {\n\tconst s = asStr(v);\n\treturn s === null ? null : cleanName(s);\n};\n\n// ---------------------------------------------------------------------------\n// Aggregate\n// ---------------------------------------------------------------------------\n\nexport type ModelUsage = TokenCounts & {\n\tmessages: number;\n\t/**\n\t * API-equivalent cost accumulated per response at that response's own rate\n\t * (#33 decision 8). Not derivable from the token totals above once a window\n\t * straddles a repricing.\n\t */\n\tcostUSD: number;\n\t/** Tokens whose own timestamp had no citable rate. Surfaced, never zeroed. */\n\tunpricedTokens: number;\n};\n\ntype Entry = {\n\tmodelKey: string;\n\tcounts: TokenCounts;\n\t/** `null` = no rate applied at this response's timestamp. */\n\tcostUSD: number | null;\n};\n\n/** One API response's full contribution, kept so it can be un-applied on replace. */\ntype Contribution = {\n\tentries: Entry[];\n\ttotal: number;\n\tsidechain: boolean;\n\twebSearch: number;\n\twebFetch: number;\n\t/** Iteration types that mirrored top-level usage, for the diagnostics line. */\n\tmirroredIterationTypes: Array<[string, number]>;\n\t/** Iterations naming a different model, attributed to that model (#33 dec. 9). */\n\tfallbackAttempts: number;\n\t/** Mirror-suspected iterations with no `model` field — skipped, not billed. */\n\tuntypedMirrors: number;\n};\n\ntype SeenEntry = { requestId: string | null; contribution: Contribution };\n\nexport type Aggregate = {\n\t// provenance / scan health\n\tfiles: number;\n\tlines: number;\n\tparseErrors: number;\n\trecords: number;\n\tassistantRecords: number;\n\t/** Distinct API responses actually counted. */\n\tdistinctResponses: number;\n\t/** Extra records of a response already counted (same message.id AND requestId). */\n\tcontinuationsFolded: number;\n\t/** Same message.id under a NEW requestId — a genuine replay (e.g. /btw sidechain). */\n\trealReplaysFolded: number;\n\t/** Times a later record superseded an earlier one because it carried a larger total. */\n\tsupersededByLarger: number;\n\t/** Assistant records with no message.id — counted without dedup protection. */\n\tunkeyedResponses: number;\n\tsyntheticRecords: number;\n\tsyntheticTokens: number;\n\ttoolBlocksWithoutId: number;\n\t/** Responses whose first attempt ran on a different model (#33 decision 9). */\n\tfallbackAttempts: number;\n\tuntypedMirrors: number;\n\t/** Records with no parseable timestamp — cannot be priced time-awarely. */\n\tuntimestampedResponses: number;\n\tprojectDirs: Set<string>; // held only to count — names never leave this module\n\tccVersions: Set<string>;\n\tmirroredIterationTypes: Map<string, number>;\n\n\t// tokens\n\tbyModel: Map<string, ModelUsage>;\n\tsidechainTokens: number;\n\tmainTokens: number;\n\n\t// activity\n\tsessions: Set<string>;\n\tactiveDays: Set<string>; // UTC YYYY-MM-DD\n\tfirstTs: number | null;\n\tlastTs: number | null;\n\n\t// tools / skills / mcp / agents\n\ttoolCalls: Map<string, number>;\n\tskillCalls: Map<string, number>;\n\tmcpServerCalls: Map<string, number>;\n\tmcpToolCalls: Map<string, number>;\n\tsubagentCalls: Map<string, number>;\n\tslashCommands: Map<string, number>;\n\ttoolCallDedup: Set<string>;\n\n\t// content-block shape\n\tthinkingBlocks: number;\n\ttextBlocks: number;\n\twebSearchRequests: number;\n\twebFetchRequests: number;\n\n\t// dedup bookkeeping — keyed by message.id alone, so it covers BOTH the\n\t// continuation case (same requestId) and the replay case (new requestId).\n\tseen: Map<string, SeenEntry>;\n};\n\nexport function createAggregate(): Aggregate {\n\treturn {\n\t\tfiles: 0,\n\t\tlines: 0,\n\t\tparseErrors: 0,\n\t\trecords: 0,\n\t\tassistantRecords: 0,\n\t\tdistinctResponses: 0,\n\t\tcontinuationsFolded: 0,\n\t\trealReplaysFolded: 0,\n\t\tsupersededByLarger: 0,\n\t\tunkeyedResponses: 0,\n\t\tsyntheticRecords: 0,\n\t\tsyntheticTokens: 0,\n\t\ttoolBlocksWithoutId: 0,\n\t\tfallbackAttempts: 0,\n\t\tuntypedMirrors: 0,\n\t\tuntimestampedResponses: 0,\n\t\tprojectDirs: new Set(),\n\t\tccVersions: new Set(),\n\t\tmirroredIterationTypes: new Map(),\n\t\tbyModel: new Map(),\n\t\tsidechainTokens: 0,\n\t\tmainTokens: 0,\n\t\tsessions: new Set(),\n\t\tactiveDays: new Set(),\n\t\tfirstTs: null,\n\t\tlastTs: null,\n\t\ttoolCalls: new Map(),\n\t\tskillCalls: new Map(),\n\t\tmcpServerCalls: new Map(),\n\t\tmcpToolCalls: new Map(),\n\t\tsubagentCalls: new Map(),\n\t\tslashCommands: new Map(),\n\t\ttoolCallDedup: new Set(),\n\t\tthinkingBlocks: 0,\n\t\ttextBlocks: 0,\n\t\twebSearchRequests: 0,\n\t\twebFetchRequests: 0,\n\t\tseen: new Map(),\n\t};\n}\n\nconst bump = (m: Map<string, number>, k: string, n = 1) =>\n\tm.set(k, (m.get(k) ?? 0) + n);\n\nfunction emptyUsage(): ModelUsage {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheWrite5m: 0,\n\t\tcacheWrite1h: 0,\n\t\tcacheWriteUnsplit: 0,\n\t\tcacheRead: 0,\n\t\tmessages: 0,\n\t\tcostUSD: 0,\n\t\tunpricedTokens: 0,\n\t};\n}\n\nconst countsTotal = (t: TokenCounts): number =>\n\tt.input +\n\tt.output +\n\tt.cacheWrite5m +\n\tt.cacheWrite1h +\n\tt.cacheWriteUnsplit +\n\tt.cacheRead;\n\n// ---------------------------------------------------------------------------\n// Ingest\n// ---------------------------------------------------------------------------\n\nexport type IngestContext = { projectDir: string };\n\n/** Fold one parsed JSONL record into the aggregate. */\nexport function ingestRecord(\n\tagg: Aggregate,\n\traw: unknown,\n\tctx: IngestContext,\n): void {\n\tconst rec = asObj(raw);\n\tif (!rec) return;\n\n\tagg.records++;\n\tagg.projectDirs.add(ctx.projectDir);\n\n\tconst version = asStr(rec.version);\n\tif (version) agg.ccVersions.add(cleanName(version));\n\tconst sessionId = asStr(rec.sessionId);\n\tif (sessionId) agg.sessions.add(sessionId);\n\n\tlet tsMs: number | null = null;\n\tconst timestamp = asStr(rec.timestamp);\n\tif (timestamp) {\n\t\tconst ts = Date.parse(timestamp);\n\t\tif (!Number.isNaN(ts)) {\n\t\t\ttsMs = ts;\n\t\t\tagg.activeDays.add(timestamp.slice(0, 10));\n\t\t\tagg.firstTs = agg.firstTs === null ? ts : Math.min(agg.firstTs, ts);\n\t\t\tagg.lastTs = agg.lastTs === null ? ts : Math.max(agg.lastTs, ts);\n\t\t}\n\t}\n\n\tconst type = asStr(rec.type);\n\tif (type === \"assistant\") ingestAssistant(agg, rec, tsMs);\n\telse if (type === \"user\") ingestUser(agg, rec);\n}\n\nfunction ingestAssistant(agg: Aggregate, rec: Obj, tsMs: number | null): void {\n\tagg.assistantRecords++;\n\tconst msg = asObj(rec.message);\n\tif (!msg) return;\n\n\tconst messageId = asStr(msg.id);\n\tconst requestId = asStr(rec.requestId);\n\tconst existing = messageId === null ? undefined : agg.seen.get(messageId);\n\t// A genuine replay is the same message.id under a NEW requestId. Its records\n\t// repeat content already counted; a continuation's records do not.\n\tconst isReplay = existing !== undefined && existing.requestId !== requestId;\n\n\t// Content blocks are counted per RECORD, deliberately outside the token\n\t// fold: the records of ONE response carry disjoint blocks (verified across\n\t// 44,478 groups — zero overlap), so folding them would drop real blocks.\n\t// Replays are the exception and must be skipped, because `tool_use` has\n\t// `block.id` to dedup on but thinking/text blocks have no identity at all.\n\tif (!isReplay) ingestContentBlocks(agg, msg.content);\n\n\tconst usage = asObj(msg.usage);\n\tif (!usage) return;\n\n\tconst model = asName(msg.model) ?? \"(unknown)\";\n\t// `<synthetic>` is the harness's own pseudo-model for records it generates\n\t// itself. Not a tool the user chose — excluded from inventory and pricing,\n\t// but its tokens are surfaced rather than silently dropped.\n\tif (model.startsWith(\"<\")) {\n\t\tagg.syntheticRecords++;\n\t\tagg.syntheticTokens += countsTotal(readCounts(usage));\n\t\treturn;\n\t}\n\n\tif (tsMs === null) agg.untimestampedResponses++;\n\n\tconst sidechain = rec.isSidechain === true;\n\tconst contribution = buildContribution(usage, model, sidechain, tsMs);\n\n\tif (messageId === null) {\n\t\t// No dedup key available — count it and record that we were unprotected.\n\t\tagg.unkeyedResponses++;\n\t\tacceptContribution(agg, contribution);\n\t\treturn;\n\t}\n\n\tif (existing === undefined) {\n\t\tagg.distinctResponses++;\n\t\tacceptContribution(agg, contribution);\n\t\tagg.seen.set(messageId, { requestId, contribution });\n\t\treturn;\n\t}\n\n\tif (isReplay) agg.realReplaysFolded++;\n\telse agg.continuationsFolded++;\n\n\tif (!supersedes(contribution, existing.contribution)) return;\n\n\tagg.supersededByLarger++;\n\tretractContribution(agg, existing.contribution);\n\tacceptContribution(agg, contribution);\n\t// Keep the FIRST-seen requestId, not this record's. If a genuine replay wins\n\t// on tokens, overwriting it would make the replay's own later records compare\n\t// equal to the stored id, read as continuations, and get their thinking/text\n\t// blocks counted a second time — reopening exactly what the `isReplay` gate\n\t// above exists to close. (tool_use survives either way via `block.id`.)\n\tagg.seen.set(messageId, { requestId: existing.requestId, contribution });\n}\n\n/**\n * Apply a contribution and tally its diagnostics. Paired with\n * `retractContribution` so every per-response census stays per-RESPONSE rather\n * than per-record — these used to be bumped while merely *building* a\n * contribution, which counted every folded continuation too.\n */\nfunction acceptContribution(agg: Aggregate, c: Contribution): void {\n\tapplyContribution(agg, c, +1);\n}\n\nfunction retractContribution(agg: Aggregate, c: Contribution): void {\n\tapplyContribution(agg, c, -1);\n}\n\n/**\n * ccusage's collision rule: a non-sidechain copy beats a sidechain one;\n * otherwise the larger token total wins. Order-independent by construction,\n * so the result does not depend on filesystem traversal order.\n */\nfunction supersedes(next: Contribution, prev: Contribution): boolean {\n\tif (prev.sidechain !== next.sidechain)\n\t\treturn prev.sidechain && !next.sidechain;\n\treturn next.total > prev.total;\n}\n\nfunction readCounts(usage: Obj): TokenCounts {\n\tconst t: TokenCounts = {\n\t\tinput: asNum(usage.input_tokens),\n\t\toutput: asNum(usage.output_tokens),\n\t\tcacheWrite5m: 0,\n\t\tcacheWrite1h: 0,\n\t\tcacheWriteUnsplit: 0,\n\t\tcacheRead: asNum(usage.cache_read_input_tokens),\n\t};\n\tconst cacheWriteTotal = asNum(usage.cache_creation_input_tokens);\n\tconst cc = asObj(usage.cache_creation);\n\tif (cc) {\n\t\tt.cacheWrite5m = asNum(cc.ephemeral_5m_input_tokens);\n\t\tt.cacheWrite1h = asNum(cc.ephemeral_1h_input_tokens);\n\t\tconst residual = cacheWriteTotal - (t.cacheWrite5m + t.cacheWrite1h);\n\t\tif (residual > 0) t.cacheWriteUnsplit = residual;\n\t} else {\n\t\tt.cacheWriteUnsplit = cacheWriteTotal;\n\t}\n\treturn t;\n}\n\n/** `usage.speed === \"fast\"` prices under a separate, higher rate. */\nfunction modelKeyFor(model: string, speed: string | null): string {\n\treturn normalizeModel(speed === \"fast\" ? `${model}#fast` : model);\n}\n\nfunction makeEntry(\n\tmodelKey: string,\n\tcounts: TokenCounts,\n\ttsMs: number | null,\n): Entry {\n\treturn {\n\t\tmodelKey,\n\t\tcounts,\n\t\tcostUSD: apiEquivalentCost(modelKey, counts, tsMs),\n\t};\n}\n\nfunction buildContribution(\n\tusage: Obj,\n\tmodel: string,\n\tsidechain: boolean,\n\ttsMs: number | null,\n): Contribution {\n\tconst modelKey = modelKeyFor(model, asStr(usage.speed));\n\tconst entries: Entry[] = [makeEntry(modelKey, readCounts(usage), tsMs)];\n\tconst mirrored = new Map<string, number>();\n\tlet fallbackAttempts = 0;\n\tlet untypedMirrors = 0;\n\n\tfor (const rawIt of asArr(usage.iterations)) {\n\t\tconst it = asObj(rawIt);\n\t\tif (!it) continue;\n\t\tconst itType = asName(it.type) ?? \"(untyped)\";\n\t\tconst itModel = asName(it.model);\n\t\tconst itKey =\n\t\t\titModel === null ? null : modelKeyFor(itModel, asStr(it.speed));\n\n\t\t// Advisor iterations are a genuinely separate billed call under their own\n\t\t// model, never a mirror of top-level usage (ccusage prices them apart).\n\t\tif (itType === \"advisor_message\") {\n\t\t\tentries.push(makeEntry(itKey ?? modelKey, readCounts(it), tsMs));\n\t\t\tcontinue;\n\t\t}\n\n\t\t// #33 decision 9, SHARPENED — read the whole comment before touching this.\n\t\t//\n\t\t// The prototype skipped EVERY `type: \"message\"` iteration as a mirror of\n\t\t// top-level usage, which was correct by luck rather than construction: a\n\t\t// real `fallback_message` record showed top-level usage equal to the\n\t\t// fallback iteration EXACTLY, while a sibling `type: message` iteration\n\t\t// named a DIFFERENT model and carried tokens recorded nowhere else. So\n\t\t// `message.model` is already the serving model, and the mirror test is the\n\t\t// MODEL, not the type.\n\t\t//\n\t\t// #33 phrased the fix as \"skip it only when `iter.model === message.model`\".\n\t\t// Taken literally that is a ~2x overcount, because the corpus says the\n\t\t// `model` field is almost never there: of 63,638 non-advisor iterations,\n\t\t// 63,634 carry NO `model` at all — and all 63,634 are byte-exact mirrors of\n\t\t// their record's top-level usage (measured: zero differ). They carry 7.24\n\t\t// BILLION tokens, nearly double the corpus total, so attributing them as\n\t\t// separate entries would roughly double both tokens and cost. Only 8\n\t\t// iterations name a model: 4 matching (the `fallback_message` entries) and\n\t\t// 4 differing (the real first attempts).\n\t\t//\n\t\t// So the operative rule is: SKIP UNLESS THE ITERATION NAMES A DIFFERENT\n\t\t// MODEL. Absent is treated as matching — mis-attributing is a double-bill,\n\t\t// skipping is at worst an undercount, and the measurement above says it is\n\t\t// not even that.\n\t\tif (itKey === null) {\n\t\t\tuntypedMirrors++;\n\t\t\tbump(mirrored, itType);\n\t\t\tcontinue;\n\t\t}\n\t\tif (itKey === modelKey) {\n\t\t\tbump(mirrored, itType);\n\t\t\tcontinue;\n\t\t}\n\t\tentries.push(makeEntry(itKey, readCounts(it), tsMs));\n\t\tfallbackAttempts++;\n\t}\n\n\tconst serverTools = asObj(usage.server_tool_use);\n\treturn {\n\t\tentries,\n\t\ttotal: entries.reduce((a, e) => a + countsTotal(e.counts), 0),\n\t\tsidechain,\n\t\twebSearch: serverTools ? asNum(serverTools.web_search_requests) : 0,\n\t\twebFetch: serverTools ? asNum(serverTools.web_fetch_requests) : 0,\n\t\tmirroredIterationTypes: [...mirrored],\n\t\tfallbackAttempts,\n\t\tuntypedMirrors,\n\t};\n}\n\n/** Add (sign +1) or remove (sign -1) a response's contribution from the totals. */\nfunction applyContribution(\n\tagg: Aggregate,\n\tc: Contribution,\n\tsign: 1 | -1,\n): void {\n\tc.entries.forEach(({ modelKey, counts, costUSD }, i) => {\n\t\tlet m = agg.byModel.get(modelKey);\n\t\tif (!m) {\n\t\t\tm = emptyUsage();\n\t\t\tagg.byModel.set(modelKey, m);\n\t\t}\n\t\t// One response is one message, even when a fallback attempt or an advisor\n\t\t// iteration attributes tokens to a second model — counting per entry would\n\t\t// inflate the response total past distinctResponses.\n\t\tif (i === 0) m.messages += sign;\n\t\tm.input += sign * counts.input;\n\t\tm.output += sign * counts.output;\n\t\tm.cacheWrite5m += sign * counts.cacheWrite5m;\n\t\tm.cacheWrite1h += sign * counts.cacheWrite1h;\n\t\tm.cacheWriteUnsplit += sign * counts.cacheWriteUnsplit;\n\t\tm.cacheRead += sign * counts.cacheRead;\n\t\tif (costUSD === null) m.unpricedTokens += sign * countsTotal(counts);\n\t\telse m.costUSD += sign * costUSD;\n\t});\n\tif (c.sidechain) agg.sidechainTokens += sign * c.total;\n\telse agg.mainTokens += sign * c.total;\n\tagg.webSearchRequests += sign * c.webSearch;\n\tagg.webFetchRequests += sign * c.webFetch;\n\tagg.fallbackAttempts += sign * c.fallbackAttempts;\n\tagg.untypedMirrors += sign * c.untypedMirrors;\n\tfor (const [type, count] of c.mirroredIterationTypes) {\n\t\tbump(agg.mirroredIterationTypes, type, sign * count);\n\t}\n}\n\nfunction ingestContentBlocks(agg: Aggregate, content: unknown): void {\n\tfor (const rawBlock of asArr(content)) {\n\t\tconst block = asObj(rawBlock);\n\t\tif (!block) continue;\n\t\tconst type = asStr(block.type);\n\t\tif (type === \"thinking\") agg.thinkingBlocks++;\n\t\telse if (type === \"text\") agg.textBlocks++;\n\t\telse if (type === \"tool_use\") ingestToolUse(agg, block);\n\t}\n}\n\nfunction ingestToolUse(agg: Aggregate, block: Obj): void {\n\tconst name = asName(block.name);\n\tif (!name) return;\n\n\t// `toolu_...` block ids are globally unique, which makes this key both\n\t// collision-proof and replay-proof without a record-level prefix. A block\n\t// with no id is skipped rather than folded under a name-only key, which\n\t// would silently collapse every call to that tool into one.\n\tconst blockId = asStr(block.id);\n\tif (!blockId) {\n\t\tagg.toolBlocksWithoutId++;\n\t\treturn;\n\t}\n\tif (agg.toolCallDedup.has(blockId)) return;\n\tagg.toolCallDedup.add(blockId);\n\n\tconst input = asObj(block.input) ?? {};\n\n\tif (name.startsWith(\"mcp__\")) {\n\t\tconst parts = name.slice(\"mcp__\".length).split(\"__\");\n\t\tbump(agg.mcpServerCalls, parts[0] || \"(unknown)\");\n\t\tbump(agg.mcpToolCalls, name);\n\t\treturn;\n\t}\n\tif (name === \"Skill\") {\n\t\tbump(agg.skillCalls, asName(input.skill) ?? \"(unnamed)\");\n\t\tbump(agg.toolCalls, \"Skill\");\n\t\treturn;\n\t}\n\t// `Task` is the pre-rename spelling of `Agent`.\n\tif (name === \"Agent\" || name === \"Task\") {\n\t\tbump(agg.subagentCalls, asName(input.subagent_type) ?? \"(default)\");\n\t\tbump(agg.toolCalls, \"Agent\");\n\t\treturn;\n\t}\n\tbump(agg.toolCalls, name);\n}\n\nconst SLASH_RE = /<command-name>\\/?([^<\\n\\r]{1,64})<\\/command-name>/g;\n\nfunction ingestUser(agg: Aggregate, rec: Obj): void {\n\tconst msg = asObj(rec.message);\n\tif (!msg) return;\n\tconst content = msg.content;\n\n\tlet text = \"\";\n\tif (typeof content === \"string\") text = content;\n\telse {\n\t\tfor (const rawBlock of asArr(content)) {\n\t\t\tconst block = asObj(rawBlock);\n\t\t\tif (!block) continue;\n\t\t\tif (asStr(block.type) === \"text\") text += asStr(block.text) ?? \"\";\n\t\t}\n\t}\n\tif (!text.includes(\"<command-name>\")) return;\n\n\t// `matchAll` over `exec` in a loop: the regex is module-level and `g`-flagged,\n\t// so an `exec` loop carries a shared `lastIndex` that a forgotten reset turns\n\t// into records being skipped at random.\n\tfor (const match of text.matchAll(SLASH_RE)) {\n\t\tbump(agg.slashCommands, cleanName(match[1]));\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Finalize — the shape the wire payload is derived from\n// ---------------------------------------------------------------------------\n\nexport type ModelRow = {\n\t/** Pricing key: normalized vendor id, plus `#fast` when speed was fast. */\n\tmodelKey: string;\n\ttokens: TokenCounts;\n\ttotalTokens: number;\n\tmessages: number;\n\tshare: number;\n\t/** Accumulated at each response's own rate. `null` when nothing was priced. */\n\tcostUSD: number | null;\n\t/** Tokens inside this row that no rate covered. */\n\tunpricedTokens: number;\n};\n\nexport type Finalized = {\n\tmodels: ModelRow[];\n\ttotalTokens: number;\n\ttotalCostUSD: number;\n\tunpricedModels: string[];\n\tunpricedTokens: number;\n\tcacheHitShare: number;\n\tsidechainShare: number;\n\tactiveDays: number;\n\tfirstTs: number | null;\n\tlastTs: number | null;\n\tsessions: number;\n\tprojects: number;\n\ttools: Array<[string, number]>;\n\tskills: Array<[string, number]>;\n\tmcpServers: Array<[string, number]>;\n\tsubagents: Array<[string, number]>;\n\tslashCommands: Array<[string, number]>;\n\ttotalToolCalls: number;\n\t/** Newest Claude Code version observed, or null when none was recorded. */\n\tharnessVersion: string | null;\n};\n\nfunction buildModelRows(agg: Aggregate): {\n\trows: ModelRow[];\n\ttotalTokens: number;\n\ttotalCostUSD: number;\n\tunpricedModels: string[];\n\tunpricedTokens: number;\n} {\n\tconst rows: ModelRow[] = [];\n\tlet totalTokens = 0;\n\tlet totalCostUSD = 0;\n\tconst unpricedModels: string[] = [];\n\tlet unpricedTokens = 0;\n\n\tfor (const [modelKey, u] of agg.byModel) {\n\t\tconst tokens: TokenCounts = {\n\t\t\tinput: u.input,\n\t\t\toutput: u.output,\n\t\t\tcacheWrite5m: u.cacheWrite5m,\n\t\t\tcacheWrite1h: u.cacheWrite1h,\n\t\t\tcacheWriteUnsplit: u.cacheWriteUnsplit,\n\t\t\tcacheRead: u.cacheRead,\n\t\t};\n\t\tconst sum = countsTotal(tokens);\n\t\ttotalTokens += sum;\n\t\tif (u.unpricedTokens > 0) {\n\t\t\tunpricedModels.push(modelKey);\n\t\t\tunpricedTokens += u.unpricedTokens;\n\t\t}\n\t\ttotalCostUSD += u.costUSD;\n\t\trows.push({\n\t\t\tmodelKey,\n\t\t\ttokens,\n\t\t\ttotalTokens: sum,\n\t\t\tmessages: u.messages,\n\t\t\tshare: 0,\n\t\t\t// A model we hold no rate for at all reports null rather than $0.00,\n\t\t\t// so \"we can't price this\" never reads as \"this was free\".\n\t\t\tcostUSD: isPricedModel(modelKey) ? u.costUSD : null,\n\t\t\tunpricedTokens: u.unpricedTokens,\n\t\t});\n\t}\n\tfor (const r of rows) r.share = totalTokens ? r.totalTokens / totalTokens : 0;\n\trows.sort(\n\t\t(a, b) =>\n\t\t\tb.totalTokens - a.totalTokens || a.modelKey.localeCompare(b.modelKey),\n\t);\n\treturn { rows, totalTokens, totalCostUSD, unpricedModels, unpricedTokens };\n}\n\nfunction computeCacheHitShare(rows: ModelRow[]): number {\n\tlet cacheRead = 0;\n\tlet inputClass = 0;\n\tfor (const r of rows) {\n\t\tcacheRead += r.tokens.cacheRead;\n\t\tinputClass +=\n\t\t\tr.tokens.input +\n\t\t\tr.tokens.cacheRead +\n\t\t\tr.tokens.cacheWrite5m +\n\t\t\tr.tokens.cacheWrite1h +\n\t\t\tr.tokens.cacheWriteUnsplit;\n\t}\n\treturn inputClass ? cacheRead / inputClass : 0;\n}\n\n/**\n * Newest observed Claude Code version, compared numerically per dotted segment\n * so `2.1.9` doesn't sort above `2.1.220`.\n */\nexport function newestVersion(versions: Iterable<string>): string | null {\n\tlet best: string | null = null;\n\tlet bestParts: number[] = [];\n\tfor (const v of versions) {\n\t\tconst parts = v.split(\".\").map((p) => Number.parseInt(p, 10));\n\t\tif (parts.some((n) => !Number.isFinite(n))) continue;\n\t\tif (best === null || compareParts(parts, bestParts) > 0) {\n\t\t\tbest = v;\n\t\t\tbestParts = parts;\n\t\t}\n\t}\n\treturn best;\n}\n\nfunction compareParts(a: number[], b: number[]): number {\n\tconst len = Math.max(a.length, b.length);\n\tfor (let i = 0; i < len; i++) {\n\t\tconst d = (a[i] ?? 0) - (b[i] ?? 0);\n\t\tif (d !== 0) return d;\n\t}\n\treturn 0;\n}\n\nexport function finalize(agg: Aggregate): Finalized {\n\tconst { rows, totalTokens, totalCostUSD, unpricedModels, unpricedTokens } =\n\t\tbuildModelRows(agg);\n\n\tconst byCount = (m: Map<string, number>): Array<[string, number]> =>\n\t\t[...m.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));\n\n\tlet totalToolCalls = 0;\n\tfor (const v of agg.toolCalls.values()) totalToolCalls += v;\n\tfor (const v of agg.mcpToolCalls.values()) totalToolCalls += v;\n\n\tconst sideTotal = agg.sidechainTokens + agg.mainTokens;\n\n\treturn {\n\t\tmodels: rows,\n\t\ttotalTokens,\n\t\ttotalCostUSD,\n\t\tunpricedModels,\n\t\tunpricedTokens,\n\t\tcacheHitShare: computeCacheHitShare(rows),\n\t\tsidechainShare: sideTotal ? agg.sidechainTokens / sideTotal : 0,\n\t\tactiveDays: agg.activeDays.size,\n\t\tfirstTs: agg.firstTs,\n\t\tlastTs: agg.lastTs,\n\t\tsessions: agg.sessions.size,\n\t\tprojects: agg.projectDirs.size,\n\t\ttools: byCount(agg.toolCalls),\n\t\tskills: byCount(agg.skillCalls),\n\t\tmcpServers: byCount(agg.mcpServerCalls),\n\t\tsubagents: byCount(agg.subagentCalls),\n\t\tslashCommands: byCount(agg.slashCommands),\n\t\ttotalToolCalls,\n\t\tharnessVersion: newestVersion(agg.ccVersions),\n\t};\n}\n","// The bundled curated allowlist — the fallback copy for `/api/sync-config`.\n//\n// Wayfinder ticket #37 (map #29), decision 4 of the wire-format grilling #33.\n//\n// WHAT BELONGS HERE, AND WHY IT IS SHORT\n// These four classes of name are user-chosen. A Skill called `acme-q3-pricing`,\n// an MCP server called `internal-billing`, a subagent called `client-migration`\n// — each is a real leak, and none of them is distinguishable from a public name\n// by shape.\n//\n// THE BAR (grilling #42): a name qualifies if the STRING carries no private\n// information no matter who typed it. That is a property of the string, not of\n// the user and not of the artifact.\n//\n// The bar is deliberately NOT \"the name identifies a public artifact, so\n// publishing it reveals nothing the user hasn't already published\". That was the\n// original wording and it is wrong: `stripe` is on this list, and publishing it\n// plainly does reveal something the user never published — that they use Stripe.\n// It cannot be the harm, because revealing what you use is the entire product.\n// The harm is narrower: strings drawn from the user's private vocabulary, which\n// leak a relationship (an employer, a client, a codename) rather than a\n// preference. `stripe` and `filesystem` are safe even for someone who named\n// their own server that by coincidence.\n//\n// Three sources meet that bar:\n// 1. Claude Code's own built-in subagent types and slash commands (vendor-\n// assigned, same class as a built-in tool name).\n// 2. Skills that ship with Claude Code itself.\n// 3. MCP servers with a public, documented, first-party endpoint.\n//\n// WHY THIS LIST DOES NOT NEED TO BE LONG (#42 decision 1)\n// It is no longer the only road to publishing a name. The approve gate offers\n// every kept-private name as an explicit, default-off tick, and the tick set\n// comes back down with the rest of the sync config. This list only exists to\n// spare a user from ticking boxes nobody would think twice about — so it can\n// stay strict, and every user-chosen name goes through the person who knows\n// whether it is a secret.\n//\n// The author's own `alp-river:*` plugin is deliberately NOT seeded, even though\n// it is genuinely published. This list is GLOBAL: seeding it would publish those\n// names for every user who installs the plugin without any of them ticking\n// anything, and an author adding their own names to the default everyone else\n// inherits is what would make the list untrustworthy for every other entry.\n//\n// `/api/sync-config` (ticket #38) serves the AUTHORITATIVE list. This copy only\n// covers the case where that endpoint can't be reached, which for an installed\n// user is permanent if the plugin never auto-updates. Growing the curated list\n// is server-side work; adding entries here only helps the offline case.\n\nimport type { CuratedAllowlist } from \"./allowlist.js\";\n\n/** Claude Code's own subagent types. Vendor-assigned, not user-chosen. */\nconst BUILTIN_SUBAGENTS = [\n\t\"(default)\",\n\t\"claude\",\n\t\"claude-code-guide\",\n\t\"Explore\",\n\t\"fork\",\n\t\"general-purpose\",\n\t\"Plan\",\n\t\"statusline-setup\",\n] as const;\n\n/** Skills bundled with Claude Code. */\nconst BUILTIN_SKILLS = [\n\t\"artifact-capabilities\",\n\t\"artifact-design\",\n\t\"claude-api\",\n\t\"code-review\",\n\t\"codebase-design\",\n\t\"dataviz\",\n\t\"diagnosing-bugs\",\n\t\"domain-modeling\",\n\t\"fewer-permission-prompts\",\n\t\"grilling\",\n\t\"init\",\n\t\"keybindings-help\",\n\t\"loop\",\n\t\"prototype\",\n\t\"research\",\n\t\"review\",\n\t\"run\",\n\t\"schedule\",\n\t\"security-review\",\n\t\"simplify\",\n\t\"tdd\",\n\t\"update-config\",\n] as const;\n\n/** Claude Code's own slash commands. */\nconst BUILTIN_SLASH_COMMANDS = [\n\t\"add-dir\",\n\t\"agents\",\n\t\"bug\",\n\t\"clear\",\n\t\"compact\",\n\t\"config\",\n\t\"context\",\n\t\"cost\",\n\t\"doctor\",\n\t\"effort\",\n\t\"exit\",\n\t\"export\",\n\t\"fast\",\n\t\"help\",\n\t\"hooks\",\n\t\"ide\",\n\t\"init\",\n\t\"login\",\n\t\"logout\",\n\t\"mcp\",\n\t\"memory\",\n\t\"model\",\n\t\"output-style\",\n\t\"permissions\",\n\t\"plugin\",\n\t\"privacy-settings\",\n\t\"release-notes\",\n\t\"resume\",\n\t\"review\",\n\t\"rewind\",\n\t\"security-review\",\n\t\"status\",\n\t\"statusline\",\n\t\"terminal-setup\",\n\t\"todos\",\n\t\"upgrade\",\n\t\"usage\",\n\t\"vim\",\n\t\"workflows\",\n] as const;\n\n/**\n * MCP servers with a public first-party endpoint.\n *\n * Matched against the server segment the analyzer parses out of an\n * `mcp__<server>__<tool>` name, which is the LOCAL alias the user configured —\n * so this only fires when the user kept the conventional name. A renamed server\n * is kept private, which is the correct direction to fail.\n *\n * ONE normalization applies first (#42 decision 5): a server provided by a\n * plugin is observed as `plugin_<plugin>_<server>`, a string Claude Code\n * generates rather than one the user typed. Strip that wrapper before matching,\n * and publish the NORMALIZED name. The safety property is that normalization can\n * only ever emit a string already on this list — a non-matching inner segment\n * emits nothing and the raw name falls through to the gate's review list — so a\n * bug here is bounded by an already-vetted set. If the upstream convention\n * changes, matching reverts to keeping names private: a fail-safe regression.\n */\nconst PUBLIC_MCP_SERVERS = [\n\t\"chrome-devtools\",\n\t\"context7\",\n\t\"deepwiki\",\n\t\"figma\",\n\t\"filesystem\",\n\t\"git\",\n\t\"github\",\n\t\"huggingface\",\n\t\"ide\",\n\t\"linear\",\n\t\"notion\",\n\t\"playwright\",\n\t\"puppeteer\",\n\t\"sentry\",\n\t\"slack\",\n\t\"stripe\",\n] as const;\n\nexport const BUNDLED_CURATED_ALLOWLIST: CuratedAllowlist = {\n\tmcpServers: PUBLIC_MCP_SERVERS,\n\tskills: BUILTIN_SKILLS,\n\tsubagents: BUILTIN_SUBAGENTS,\n\tslashCommands: BUILTIN_SLASH_COMMANDS,\n};\n","// Fail-closed name filtering for the measured layer.\n//\n// Wayfinder ticket #37 (map #29), decisions 2-4 of the wire-format grilling #33.\n//\n// THE INVERSION THIS FILE EXISTS TO PERFORM\n// The prototype's `toolCalls` map was a catch-all: anything that wasn't an\n// `mcp__*` tool, a Skill, or an Agent fell THROUGH into it, and from there into\n// the payload. That is denylist-shaped — a tool name nobody anticipated\n// publishes by default. Here a name publishes only if it matches a known list,\n// and everything else is withheld and published as a per-category count.\n//\n// Two classes of name, two mechanisms:\n// - Built-in Claude Code tool names are VENDOR-assigned and enumerable, so\n// they match a hardcoded literal set (BUILTIN_TOOLS below).\n// - MCP servers / Skills / subagents / slash commands are USER-chosen and can\n// carry a client name, a project codename, or an internal system's name.\n// They match a curated list fetched from aistack, with the bundled copy\n// below as the fallback.\n//\n// Model ids are exempt from all of this — see decision 3 and payload.ts.\n//\n// WHY FETCHED AND NOT ONLY BUNDLED (decision 4)\n// Third-party marketplace plugin auto-update defaults to OFF, and a\n// `plugin.json` whose `version` isn't bumped ships nothing. A bundled-only list\n// is, for an installed user, frozen forever — a Skill that becomes public next\n// month would never publish. The filtering itself still runs client-side:\n// fail-closed only means something if it happens before the send.\n\nimport { isDisplaySafeName } from \"./analyzer.js\";\nimport { BUNDLED_CURATED_ALLOWLIST } from \"./bundled-allowlist.js\";\n\n/**\n * Every built-in tool Claude Code can emit as a `tool_use` block name.\n *\n * Deliberately a literal set and not a pattern: a pattern is a denylist wearing\n * a hat. Grounded in the observed corpus (22 distinct names across 235,961\n * records) plus the documented tool surface, including tools that are deferred\n * or unavailable in most sessions — an unknown-but-real built-in withheld as a\n * count is a small loss; an unknown-and-user-named tool published verbatim is\n * the leak this whole file prevents.\n *\n * `Task` is the pre-rename spelling of `Agent`; the analyzer folds it into\n * `Agent` at ingest, so it is here only to make the set self-documenting.\n */\nexport const BUILTIN_TOOLS: ReadonlySet<string> = new Set([\n\t\"Agent\",\n\t\"Artifact\",\n\t\"AskUserQuestion\",\n\t\"Bash\",\n\t\"BashOutput\",\n\t\"CronCreate\",\n\t\"CronDelete\",\n\t\"CronList\",\n\t\"DesignSync\",\n\t\"Edit\",\n\t\"EndConversation\",\n\t\"EnterPlanMode\",\n\t\"EnterWorktree\",\n\t\"ExitPlanMode\",\n\t\"ExitWorktree\",\n\t\"Glob\",\n\t\"Grep\",\n\t\"KillBash\",\n\t\"KillShell\",\n\t\"ListMcpResourcesTool\",\n\t\"LS\",\n\t\"Monitor\",\n\t\"MultiEdit\",\n\t\"NotebookEdit\",\n\t\"NotebookRead\",\n\t\"PushNotification\",\n\t\"Read\",\n\t\"ReadMcpResourceDirTool\",\n\t\"ReadMcpResourceTool\",\n\t\"RemoteTrigger\",\n\t\"ReportFindings\",\n\t\"ScheduleWakeup\",\n\t\"SendMessage\",\n\t\"SendUserFile\",\n\t\"Skill\",\n\t\"SlashCommand\",\n\t\"Task\",\n\t\"TaskCreate\",\n\t\"TaskGet\",\n\t\"TaskList\",\n\t\"TaskOutput\",\n\t\"TaskStop\",\n\t\"TaskUpdate\",\n\t\"TodoWrite\",\n\t\"ToolSearch\",\n\t\"WebFetch\",\n\t\"WebSearch\",\n\t\"Workflow\",\n\t\"Write\",\n]);\n\n/** The four user-chosen atom classes that need the curated list. */\nexport type CuratedAllowlist = {\n\tmcpServers: readonly string[];\n\tskills: readonly string[];\n\tsubagents: readonly string[];\n\tslashCommands: readonly string[];\n};\n\n/** The five inventory classes the payload carries. */\nexport const NAME_CATEGORIES = [\n\t\"builtinTools\",\n\t\"mcpServers\",\n\t\"skills\",\n\t\"subagents\",\n\t\"slashCommands\",\n] as const;\n\nexport type NameCategory = (typeof NAME_CATEGORIES)[number];\n\n/**\n * Names this stack's owner has explicitly ticked for publication (#42\n * decision 1), served per-stack by the authenticated half of `/api/sync-config`.\n *\n * The curated list is a convenience default, not the coverage mechanism: every\n * user-chosen name class is unbounded and unenumerable, so a hand-curated list\n * can only ever be a rounding error against the real population. Coverage comes\n * from here — from the person who knows which of their names are secret.\n *\n * `builtinTools` is included for symmetry even though that class is\n * vendor-assigned: a built-in this version of the client has never heard of is\n * kept private like anything else, and the owner can tick it.\n */\nexport type OptInNames = Record<NameCategory, readonly string[]>;\n\nexport const EMPTY_OPT_INS: OptInNames = {\n\tbuiltinTools: [],\n\tmcpServers: [],\n\tskills: [],\n\tsubagents: [],\n\tslashCommands: [],\n};\n\nexport type SyncConfig = {\n\tallowlist: CuratedAllowlist;\n\t/**\n\t * Stack-level cost preference (decision 11). When false the payload omits\n\t * cost entirely rather than zeroing it — see payload.ts.\n\t */\n\tpublishCost: boolean;\n\t/** Per-stack ticked names, unioned into the allowlist before filtering. */\n\toptIns: OptInNames;\n\t/**\n\t * Whether this stack stages its kept-private names on the web so the owner\n\t * can tick them there (#48). Off means the machine sends the payload alone\n\t * and the names never leave it.\n\t */\n\treviewKeptPrivate: boolean;\n\t/**\n\t * The stack the bearer token is bound to — where a publish would land.\n\t *\n\t * The approve gate must name its destination BEFORE the send (#33\n\t * decision 7, #41), and beat one points at `/stacks/{slug}/changes` (#48),\n\t * so both ride on the authenticated half of the config fetch. `null` when\n\t * the fetch was anonymous, failed, or the token resolved no stack — and a\n\t * gate that cannot name its destination must not publish.\n\t */\n\tstack: { name: string; slug: string } | null;\n};\n\n/**\n * Used when `/api/sync-config` can't be reached.\n *\n * `publishCost: false` is deliberate. The toggle is a stack-level preference we\n * do not hold locally, and the fail-closed default for a preference we can't\n * read is the one that transmits less. A user whose fetch failed sees cost\n * missing from the gate and can retry; the reverse — publishing cost the stack\n * had opted out of — is not recoverable, because the snapshot is immutable.\n */\nexport const BUNDLED_SYNC_CONFIG: SyncConfig = {\n\tallowlist: BUNDLED_CURATED_ALLOWLIST,\n\tpublishCost: false,\n\t// Empty for the same reason, and it is the load-bearing half of #42\n\t// decision 2: a failed config fetch reverts every ticked name to\n\t// kept-private. Losing the network publishes LESS, never more.\n\toptIns: EMPTY_OPT_INS,\n\t// Same direction again (#48): a machine that cannot read the switch does not\n\t// upload the names it is holding back. The default is ON server-side, so this\n\t// costs the owner one retry and never costs them a name.\n\treviewKeptPrivate: false,\n\t// No fetch, no destination — and the gate refuses to publish without one.\n\tstack: null,\n};\n\n// ---------------------------------------------------------------------------\n// Fetch\n// ---------------------------------------------------------------------------\n\nconst SYNC_CONFIG_PATH = \"/api/sync-config\";\nconst FETCH_TIMEOUT_MS = 5_000;\n\nexport type SyncConfigSource = \"fetched\" | \"bundled\";\n\nexport type LoadedSyncConfig = {\n\tconfig: SyncConfig;\n\tsource: SyncConfigSource;\n\t/** Present when the fetch failed and the bundled copy was used. */\n\terror?: string;\n};\n\n/**\n * A name arriving from the network is no more trusted than one from a\n * transcript. Names are matched by exact equality, so a hostile list can widen\n * what publishes but can never smuggle a wildcard — and the approve gate\n * renders every name that will publish, which is what defuses that residual\n * trust (decision 4). Charset and length are still bounded so a pathological\n * entry can't reach a terminal or a database column.\n */\nconst CURATED_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9 ._:@/-]{0,63}$/;\n\nfunction readNameList(v: unknown): string[] {\n\tif (!Array.isArray(v)) return [];\n\tconst out: string[] = [];\n\tfor (const item of v) {\n\t\tif (typeof item === \"string\" && CURATED_NAME_RE.test(item)) out.push(item);\n\t}\n\treturn out;\n}\n\n/**\n * Opt-ins are read against a LOOSER bar than the curated list.\n *\n * A curated entry is ours and conventional, so the tight charset costs nothing.\n * An opt-in is the user's own name — `(default)`, an accented word, a CJK skill\n * — and dropping it here would silently un-tick a decision they made at the\n * gate. The bar that survives is the one that matters for a string we print and\n * store: no control characters, no bidi overrides, bounded length.\n */\nfunction readOptInList(v: unknown): string[] {\n\tif (!Array.isArray(v)) return [];\n\tconst out: string[] = [];\n\tfor (const item of v) {\n\t\tif (typeof item === \"string\" && isDisplaySafeName(item)) out.push(item);\n\t}\n\treturn out;\n}\n\nfunction readOptIns(v: unknown): OptInNames {\n\tif (typeof v !== \"object\" || v === null || Array.isArray(v))\n\t\treturn EMPTY_OPT_INS;\n\tconst obj = v as Record<string, unknown>;\n\treturn {\n\t\tbuiltinTools: readOptInList(obj.builtinTools),\n\t\tmcpServers: readOptInList(obj.mcpServers),\n\t\tskills: readOptInList(obj.skills),\n\t\tsubagents: readOptInList(obj.subagents),\n\t\tslashCommands: readOptInList(obj.slashCommands),\n\t};\n}\n\n/**\n * A slug becomes a URL path segment the gate prints, so it gets the tightest\n * bar of any string here. The name is display text and gets `isDisplaySafeName`.\n */\nconst STACK_SLUG_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;\n\nfunction readStack(v: unknown): SyncConfig[\"stack\"] {\n\tif (typeof v !== \"object\" || v === null || Array.isArray(v)) return null;\n\tconst obj = v as Record<string, unknown>;\n\tif (typeof obj.name !== \"string\" || !isDisplaySafeName(obj.name)) return null;\n\tif (typeof obj.slug !== \"string\" || !STACK_SLUG_RE.test(obj.slug))\n\t\treturn null;\n\treturn { name: obj.name, slug: obj.slug };\n}\n\nfunction readSyncConfig(raw: unknown): SyncConfig | null {\n\tif (typeof raw !== \"object\" || raw === null || Array.isArray(raw))\n\t\treturn null;\n\tconst obj = raw as Record<string, unknown>;\n\tconst listRaw = obj.allowlist;\n\tif (typeof listRaw !== \"object\" || listRaw === null) return null;\n\tconst list = listRaw as Record<string, unknown>;\n\treturn {\n\t\tallowlist: {\n\t\t\tmcpServers: readNameList(list.mcpServers),\n\t\t\tskills: readNameList(list.skills),\n\t\t\tsubagents: readNameList(list.subagents),\n\t\t\tslashCommands: readNameList(list.slashCommands),\n\t\t},\n\t\t// Anything other than an explicit `true` fails closed.\n\t\tpublishCost: obj.publishCost === true,\n\t\t// Absent means \"no stack resolved\" — an anonymous fetch, or a token bound\n\t\t// to nothing. Both fail closed to publishing no user-chosen names.\n\t\toptIns: readOptIns(obj.optIns),\n\t\t// Anything other than an explicit `true` keeps the names on the machine.\n\t\treviewKeptPrivate: obj.reviewKeptPrivate === true,\n\t\tstack: readStack(obj.stack),\n\t};\n}\n\n/**\n * Fetch the curated allowlist and the cost preference, falling back to the\n * bundled copy on any failure. Never throws — an unreachable aistack must not\n * prevent a local analysis from running, it must only narrow what could publish.\n */\nexport async function loadSyncConfig(opts: {\n\tbaseUrl: string;\n\t/**\n\t * Bearer for the authenticated half: `publishCost`, `optIns`,\n\t * `reviewKeptPrivate` and the destination stack. Absent, the server answers\n\t * with the anonymous fail-closed body — same allowlist, everything else off.\n\t */\n\ttoken?: string;\n\tfetchImpl?: typeof fetch;\n\ttimeoutMs?: number;\n}): Promise<LoadedSyncConfig> {\n\tconst doFetch = opts.fetchImpl ?? fetch;\n\ttry {\n\t\tconst res = await doFetch(`${opts.baseUrl}${SYNC_CONFIG_PATH}`, {\n\t\t\tsignal: AbortSignal.timeout(opts.timeoutMs ?? FETCH_TIMEOUT_MS),\n\t\t\theaders: {\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t...(opts.token ? { Authorization: `Bearer ${opts.token}` } : {}),\n\t\t\t},\n\t\t});\n\t\tif (!res.ok) {\n\t\t\treturn {\n\t\t\t\tconfig: BUNDLED_SYNC_CONFIG,\n\t\t\t\tsource: \"bundled\",\n\t\t\t\terror: `sync-config returned ${res.status}`,\n\t\t\t};\n\t\t}\n\t\tconst parsed = readSyncConfig(await res.json());\n\t\tif (!parsed) {\n\t\t\treturn {\n\t\t\t\tconfig: BUNDLED_SYNC_CONFIG,\n\t\t\t\tsource: \"bundled\",\n\t\t\t\terror: \"sync-config response was not the expected shape\",\n\t\t\t};\n\t\t}\n\t\treturn { config: parsed, source: \"fetched\" };\n\t} catch (err) {\n\t\treturn {\n\t\t\tconfig: BUNDLED_SYNC_CONFIG,\n\t\t\tsource: \"bundled\",\n\t\t\terror: err instanceof Error ? err.message : \"sync-config fetch failed\",\n\t\t};\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Filtering\n// ---------------------------------------------------------------------------\n\nexport type Atom = { name: string; count: number };\n\n/**\n * One observed name that will NOT publish, as the approve gate needs to render\n * it: the raw string, how often it ran, and the plugin it came from.\n *\n * Local only — this never enters the payload. It exists because the gate offers\n * every kept-private name as an explicit, default-off tick (#42 decision 1), and\n * it cannot offer what the analyzer does not hand back.\n */\nexport type KeptPrivateAtom = {\n\tname: string;\n\tcount: number;\n\t/** Plugin prefix, for the gate's grouped bulk tick. `null` when standalone. */\n\tgroup: string | null;\n};\n\nexport type FilteredAtoms = {\n\t/** Publishable names, ordered by count descending. */\n\tallowed: Atom[];\n\t/** The rest, with everything the gate needs to offer them as ticks. */\n\tkeptPrivate: KeptPrivateAtom[];\n\t/** How many DISTINCT names were kept private. */\n\twithheld: number;\n};\n\n/**\n * A server an MCP plugin provides is observed as `plugin_<plugin>_<server>`.\n *\n * That whole string is GENERATED by Claude Code — the user typed none of it —\n * which is a different class from a hand-edited `.mcp.json` alias. Strip the\n * wrapper before matching (#42 decision 5).\n *\n * The split takes the FIRST underscore-free segment as the plugin name. A plugin\n * whose own name carries an underscore therefore splits wrong, the inner segment\n * matches nothing, and the raw name stays kept private — the same direction\n * every other miss fails in.\n */\nconst PLUGIN_MCP_RE = /^plugin_([^_]+)_(.+)$/;\n\n/** `plugin:artifact` is the convention for a plugin's skills and subagents. */\nconst PLUGIN_PREFIX_RE = /^([^:\\s]+):(.+)$/;\n\n/**\n * The plugin a name came from, for the gate's grouped bulk tick.\n *\n * Grouping is a UI affordance only. What the gate STORES is every name in the\n * group, expanded (#42 decision 3): a stored `alp-river:*` would be a standing\n * grant to names that do not exist yet, and nobody can consent to a name they\n * have not thought of.\n */\nexport function pluginGroup(name: string): string | null {\n\treturn (\n\t\tPLUGIN_MCP_RE.exec(name)?.[1] ?? PLUGIN_PREFIX_RE.exec(name)?.[1] ?? null\n\t);\n}\n\nexport type FilterSets = {\n\t/** Curated list UNION this stack's opt-ins. A match here publishes verbatim. */\n\tpublishable: ReadonlySet<string>;\n\t/**\n\t * The curated list alone — the only target normalization may match.\n\t *\n\t * This is what makes the normalization safe to state in one line:\n\t * normalization can only ever emit a string that is already curated. The\n\t * blast radius of a bug in it is an already-vetted set, by construction.\n\t */\n\tcurated: ReadonlySet<string>;\n};\n\n/**\n * Resolve the name an atom would publish under, or `null` to keep it private.\n *\n * Raw match first, so a name the owner ticked publishes exactly as they saw it\n * at the gate. Only an unmatched name is normalized, and only against the\n * curated list.\n */\nfunction publishedName(name: string, sets: FilterSets): string | null {\n\tif (sets.publishable.has(name)) return name;\n\tconst inner = PLUGIN_MCP_RE.exec(name)?.[2];\n\tif (inner && sets.curated.has(inner)) return inner;\n\treturn null;\n}\n\n/**\n * Split observed atoms into what publishes and what stays on the machine.\n *\n * The withheld figure counts distinct names, not calls: it answers \"how much of\n * my inventory is not shown\", which is the honesty question, without leaking\n * how heavily any single kept-private thing is used.\n *\n * Counts are merged by PUBLISHED name, because normalization can map two\n * observed names onto one — a plugin-provided `chrome-devtools` and a directly\n * configured one both publish as `chrome-devtools`, and two rows with the same\n * name would double-count that server in the rendered inventory.\n */\nexport function filterAtoms(\n\tatoms: readonly Atom[],\n\tsets: FilterSets,\n): FilteredAtoms {\n\tconst merged = new Map<string, number>();\n\tconst keptPrivate: KeptPrivateAtom[] = [];\n\tfor (const atom of atoms) {\n\t\tconst published = publishedName(atom.name, sets);\n\t\tif (published === null) {\n\t\t\tkeptPrivate.push({\n\t\t\t\tname: atom.name,\n\t\t\t\tcount: atom.count,\n\t\t\t\tgroup: pluginGroup(atom.name),\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tmerged.set(published, (merged.get(published) ?? 0) + atom.count);\n\t}\n\tconst allowed = [...merged].map(([name, count]) => ({ name, count }));\n\tallowed.sort((a, b) => b.count - a.count || a.name.localeCompare(b.name));\n\tkeptPrivate.sort((a, b) => b.count - a.count || a.name.localeCompare(b.name));\n\treturn { allowed, keptPrivate, withheld: keptPrivate.length };\n}\n","// I/O shell around the pure analyzer: find transcript roots, stream JSONL, hand\n// each parsed record to ingestRecord. Nothing leaves this machine.\n//\n// Wayfinder ticket #37 (map #29).\n//\n// STANDING NON-GOAL (locked in #13): raw transcripts, prompts, absolute paths,\n// and repo names never leave the machine. Two consequences visible here:\n// project directories are counted but their names never escape this module, and\n// read errors are swallowed rather than thrown, because the error object carries\n// the absolute path and the munged project directory.\n\nimport { createReadStream, type Dirent } from \"node:fs\";\nimport { readdir, realpath, stat } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport readline from \"node:readline\";\n\nimport { type Aggregate, ingestRecord } from \"./analyzer.js\";\n\n/** Discovery order mirrors ccusage's adapter: CLAUDE_CONFIG_DIR, then the defaults. */\nexport function transcriptRoots(): string[] {\n\tconst env = process.env.CLAUDE_CONFIG_DIR;\n\tif (env) {\n\t\treturn env\n\t\t\t.split(\",\")\n\t\t\t.map((s) => s.trim())\n\t\t\t.filter(Boolean)\n\t\t\t.map((s) => path.join(s, \"projects\"));\n\t}\n\tconst roots = [path.join(homedir(), \".claude\", \"projects\")];\n\tconst xdg = process.env.XDG_CONFIG_HOME ?? path.join(homedir(), \".config\");\n\troots.push(path.join(xdg, \"claude\", \"projects\"));\n\treturn roots;\n}\n\n/**\n * UTC midnight opening a rolling window of `days` calendar days ending on the\n * day containing `now` (inclusive). `days = 30` therefore spans today plus the\n * 29 preceding days.\n *\n * Defined once and shared by the scan filter and the payload's `window.from`, so\n * the reported window and the records actually counted cannot drift apart.\n */\nexport function windowStartMs(now: number, days: number): number {\n\tconst startOfToday = Date.UTC(\n\t\tnew Date(now).getUTCFullYear(),\n\t\tnew Date(now).getUTCMonth(),\n\t\tnew Date(now).getUTCDate(),\n\t);\n\treturn startOfToday - (days - 1) * 86_400_000;\n}\n\n/** Recursive *.jsonl walk — the nested `<sessionId>/subagents/` layout is real. */\nasync function* walkJsonl(dir: string): AsyncGenerator<string> {\n\tlet entries: Dirent[];\n\ttry {\n\t\tentries = await readdir(dir, { withFileTypes: true });\n\t} catch {\n\t\treturn;\n\t}\n\tfor (const e of entries) {\n\t\tconst full = path.join(dir, e.name);\n\t\tif (e.isDirectory()) yield* walkJsonl(full);\n\t\telse if (e.isFile() && e.name.endsWith(\".jsonl\")) yield full;\n\t}\n}\n\nexport type ScanOptions = {\n\t/** Only ingest records with a timestamp at or after this epoch ms. */\n\tsinceMs?: number;\n\tonProgress?: (files: number) => void;\n\t/** Override the discovered roots. Tests only. */\n\troots?: string[];\n};\n\nexport type ScanStats = {\n\t/** Files found on disk before any window filter. */\n\tfilesFound: number;\n\t/** Files actually opened and read. */\n\tfilesRead: number;\n\t/** Files skipped because their mtime predates the window. */\n\tfilesSkippedByMtime: number;\n\t/** Files skipped because a resolved path was already scanned (overlapping roots). */\n\tfilesSkippedAsDuplicate: number;\n\t/**\n\t * Files that could not be read (permissions, or pruned mid-scan). Counted\n\t * rather than thrown: an unhandled read error would surface the absolute path\n\t * AND the munged project directory in the crash output, which is exactly what\n\t * this tool promises never to emit.\n\t */\n\tfilesUnreadable: number;\n};\n\n/**\n * KNOWN PERFORMANCE FLOOR — measured, decided, deliberately not fixed.\n *\n * Enumeration walks every project directory and `realpath`+`stat`s every file\n * BEFORE the mtime filter can skip anything, so a narrow window still pays a\n * floor proportional to TOTAL history (~60 ms over 3,206 files today, growing\n * linearly). The obvious fix — prune whole project directories by directory\n * mtime — is UNSOUND, and this was verified rather than assumed: appending to a\n * file does not update its parent directory's mtime (only adding, removing, or\n * renaming an entry does). A session resumed with `--resume` appends to a\n * transcript created before the window opened, inside a directory whose mtime\n * never moves, so dir-mtime pruning would silently drop live in-window records\n * — a wrong number, which is worse than a slow one for a tool whose whole claim\n * is measured-not-claimed.\n *\n * The sound version is a persisted enumeration cache, which cuts against #33\n * decision 1 (a sync is a stateless snapshot-replace, no durable client scan\n * state). So: DEFERRED. 60 ms is two orders of magnitude under the ~3 s full\n * scan and invisible next to the send round-trip; it becomes worth revisiting\n * only when total history reaches a scale where the floor dominates.\n */\nexport async function scan(\n\tagg: Aggregate,\n\topts: ScanOptions = {},\n): Promise<ScanStats> {\n\tconst stats: ScanStats = {\n\t\tfilesFound: 0,\n\t\tfilesRead: 0,\n\t\tfilesSkippedByMtime: 0,\n\t\tfilesSkippedAsDuplicate: 0,\n\t\tfilesUnreadable: 0,\n\t};\n\t// Roots can overlap (CLAUDE_CONFIG_DIR may repeat a dir; ~/.claude and\n\t// ~/.config/claude may be symlinked together). Without this guard the same\n\t// file is ingested twice and the record/line/block counters silently double.\n\tconst visited = new Set<string>();\n\n\tfor (const root of opts.roots ?? transcriptRoots()) {\n\t\tif (!(await exists(root))) continue;\n\t\tfor await (const file of walkJsonl(root)) {\n\t\t\tstats.filesFound++;\n\n\t\t\tlet resolved: string;\n\t\t\ttry {\n\t\t\t\tresolved = await realpath(file);\n\t\t\t} catch {\n\t\t\t\tresolved = file;\n\t\t\t}\n\t\t\tif (visited.has(resolved)) {\n\t\t\t\tstats.filesSkippedAsDuplicate++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvisited.add(resolved);\n\n\t\t\t// Transcripts are append-only and chronological, so a file untouched\n\t\t\t// since the window opened cannot hold an in-window record. This is what\n\t\t\t// makes a narrow window actually cheaper rather than merely narrower.\n\t\t\tif (opts.sinceMs !== undefined) {\n\t\t\t\ttry {\n\t\t\t\t\tconst st = await stat(file);\n\t\t\t\t\tif (st.mtimeMs < opts.sinceMs) {\n\t\t\t\t\t\tstats.filesSkippedByMtime++;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t/* unreadable stat — fall through and try to read it */\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Project dir = first path segment under projects/ (privacy-sensitive:\n\t\t\t// it is a munged absolute path, so it is only ever counted, never shown).\n\t\t\tconst rel = path.relative(root, file);\n\t\t\tconst projectDir = rel.split(path.sep)[0] ?? \"(root)\";\n\t\t\tagg.files++;\n\t\t\tstats.filesRead++;\n\t\t\tif (opts.onProgress && agg.files % 200 === 0) opts.onProgress(agg.files);\n\t\t\ttry {\n\t\t\t\tawait ingestFile(agg, file, projectDir, opts.sinceMs);\n\t\t\t} catch {\n\t\t\t\t// Swallow deliberately: the error object carries the absolute path.\n\t\t\t\tstats.filesUnreadable++;\n\t\t\t\tstats.filesRead--;\n\t\t\t}\n\t\t}\n\t}\n\treturn stats;\n}\n\nasync function exists(p: string): Promise<boolean> {\n\ttry {\n\t\tawait stat(p);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function ingestFile(\n\tagg: Aggregate,\n\tfile: string,\n\tprojectDir: string,\n\tsinceMs?: number,\n): Promise<void> {\n\tconst rl = readline.createInterface({\n\t\tinput: createReadStream(file, { encoding: \"utf8\" }),\n\t\tcrlfDelay: Number.POSITIVE_INFINITY,\n\t});\n\tfor await (const line of rl) {\n\t\tif (!line) continue;\n\t\tagg.lines++;\n\t\tlet rec: unknown;\n\t\ttry {\n\t\t\trec = JSON.parse(line);\n\t\t} catch {\n\t\t\tagg.parseErrors++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (sinceMs !== undefined) {\n\t\t\tconst ts =\n\t\t\t\trec &&\n\t\t\t\ttypeof rec === \"object\" &&\n\t\t\t\t\"timestamp\" in rec &&\n\t\t\t\ttypeof (rec as { timestamp?: unknown }).timestamp === \"string\"\n\t\t\t\t\t? Date.parse((rec as { timestamp: string }).timestamp)\n\t\t\t\t\t: Number.NaN;\n\t\t\tif (Number.isNaN(ts) || ts < sinceMs) continue;\n\t\t}\n\t\tingestRecord(agg, rec, { projectDir });\n\t}\n}\n","// The wire payload builder — the only thing in this module that decides what\n// leaves the machine.\n//\n// Wayfinder ticket #37 (map #29). Shape fixed by the wire-format grilling #33;\n// nothing here is open design.\n//\n// Two invariants this file is responsible for:\n// 1. FAIL-CLOSED NAMES. Every freeform name is matched against an allowlist\n// before it can reach the payload; unmatched names publish only as\n// per-category counts (#33 decisions 2-4). Model ids are the sole exempt\n// class (decision 3) and are charset/length sanitized instead.\n// 2. COST IS ABSENT, NOT ZEROED. With `publishCost` off, the cost fields are\n// not in the payload at all (#33 decision 11) — there is nothing to\n// \"reveal\" server-side, because nothing was transmitted.\n\nimport {\n\ttype Atom,\n\tBUILTIN_TOOLS,\n\tfilterAtoms,\n\ttype KeptPrivateAtom,\n\ttype NameCategory,\n\ttype SyncConfig,\n} from \"./allowlist.js\";\nimport {\n\ttype Aggregate,\n\tcleanName,\n\ttype Finalized,\n\tfinalize,\n\ttype ModelRow,\n} from \"./analyzer.js\";\nimport { baseModelId, PRICING_TABLE_VERSION } from \"./pricing.js\";\nimport { type ScanStats, windowStartMs } from \"./scan.js\";\n\nexport const SCHEMA_VERSION = 1;\nexport const HARNESS_NAME = \"claude-code\";\n\nexport type PayloadModel = {\n\t/** Vendor-assigned id, sanitized. `catalogSlug` is resolved SERVER-side at read time. */\n\tid: string;\n\ttokenShare: number;\n\ttokens: {\n\t\tinput: number;\n\t\toutput: number;\n\t\tcacheWrite: number;\n\t\tcacheRead: number;\n\t};\n\tapiEquivalentUSD?: number;\n};\n\nexport type PayloadAtom = { name: string; callShare: number };\n\nexport type PayloadInventory = {\n\tbuiltinTools: PayloadAtom[];\n\tmcpServers: PayloadAtom[];\n\tskills: PayloadAtom[];\n\tsubagents: PayloadAtom[];\n\tslashCommands: PayloadAtom[];\n\t/** DISTINCT names withheld per category, so the gap in the shares is explained. */\n\twithheld: {\n\t\tbuiltinTools: number;\n\t\tmcpServers: number;\n\t\tskills: number;\n\t\tsubagents: number;\n\t\tslashCommands: number;\n\t};\n};\n\nexport type MeasuredPayload = {\n\tschemaVersion: number;\n\t/** Client clock. The server stamps its own `receivedAt` (#33 decision 6). */\n\tcapturedAt: number;\n\twindow: { days: number; from: string; to: string };\n\tharness: { name: string; version: string | null };\n\t/** `null` when `publishCost` is off — no cost was computed into the payload. */\n\tpricingTable: string | null;\n\tactivity: {\n\t\tsessions: number;\n\t\tactiveDays: number;\n\t\t/** COUNT only. Project directory names are munged absolute paths and never travel. */\n\t\tprojects: number;\n\t\ttotalTokens: number;\n\t\tcacheHitShare: number;\n\t\tsubagentShare: number;\n\t};\n\tmodels: PayloadModel[];\n\tinventory: PayloadInventory;\n\tcoverage: {\n\t\tfilesScanned: number;\n\t\tfilesUnreadable: number;\n\t\tlinesParsed: number;\n\t\tlinesFailed: number;\n\t};\n\texcludedTokens: { unpriced: number; synthetic: number };\n};\n\n// ---------------------------------------------------------------------------\n// Sanitization\n// ---------------------------------------------------------------------------\n\n/**\n * Model ids are exempt from the allowlist (#33 decision 3) precisely because\n * they are vendor-assigned: on the day a new Claude model ships, fail-closing it\n * would make its tokens silently vanish from every sync and understate cost with\n * no visible cause. Exempt is not unchecked, though — the id still becomes a\n * database key and a rendered string, so charset and length are bounded here.\n */\nconst MODEL_ID_UNSAFE_RE = /[^A-Za-z0-9._:-]+/g;\nconst MODEL_ID_MAX = 64;\n\nexport function sanitizeModelId(id: string): string {\n\tconst collapsed = cleanName(id)\n\t\t.replace(MODEL_ID_UNSAFE_RE, \"-\")\n\t\t.replace(/^-+|-+$/g, \"\");\n\tif (collapsed.length === 0) return \"unknown\";\n\treturn collapsed.length > MODEL_ID_MAX\n\t\t? collapsed.slice(0, MODEL_ID_MAX)\n\t\t: collapsed;\n}\n\nconst round4 = (n: number): number => Math.round(n * 10_000) / 10_000;\nconst round2 = (n: number): number => Math.round(n * 100) / 100;\nconst utcDate = (ms: number): string => new Date(ms).toISOString().slice(0, 10);\n\n// ---------------------------------------------------------------------------\n// Inventory\n// ---------------------------------------------------------------------------\n\nconst toAtoms = (pairs: ReadonlyArray<readonly [string, number]>): Atom[] =>\n\tpairs.map(([name, count]) => ({ name, count }));\n\n/**\n * Shares are computed over ALL observed calls, including withheld ones.\n *\n * Renormalizing over only the allowlisted atoms would make the published shares\n * sum to 1.0 and read as a complete inventory — a withheld MCP server carrying\n * 90% of the calls would leave no trace. Keeping the true denominator means the\n * shares sum to less than 1 exactly when something was withheld, and the\n * `withheld` counts say how many things.\n */\nfunction buildCategory(\n\tobserved: ReadonlyArray<readonly [string, number]>,\n\tcurated: ReadonlySet<string>,\n\toptIns: readonly string[],\n\tdenominator: number,\n): { atoms: PayloadAtom[]; withheld: number; keptPrivate: KeptPrivateAtom[] } {\n\t// The union is where #42 decision 1 lands: a name publishes if it is curated\n\t// OR the owner ticked it. Filtering itself is unchanged — still client-side,\n\t// still fail-closed, still before the send. What moves is who judged the name.\n\tconst publishable = new Set([...curated, ...optIns]);\n\tconst {\n\t\tallowed: kept,\n\t\tkeptPrivate,\n\t\twithheld,\n\t} = filterAtoms(toAtoms(observed), { publishable, curated });\n\treturn {\n\t\tatoms: kept.map((a) => ({\n\t\t\tname: a.name,\n\t\t\tcallShare: denominator ? round4(a.count / denominator) : 0,\n\t\t})),\n\t\twithheld,\n\t\tkeptPrivate,\n\t};\n}\n\nconst sumCounts = (pairs: ReadonlyArray<readonly [string, number]>): number => {\n\tlet n = 0;\n\tfor (const [, c] of pairs) n += c;\n\treturn n;\n};\n\n// ---------------------------------------------------------------------------\n// Models\n// ---------------------------------------------------------------------------\n\ntype ModelGroup = {\n\tid: string;\n\ttotalTokens: number;\n\tinput: number;\n\toutput: number;\n\tcacheWrite: number;\n\tcacheRead: number;\n\tcostUSD: number;\n\tunpricedTokens: number;\n\tanyUnpriceable: boolean;\n};\n\n/**\n * Collapse the analyzer's pricing keys into vendor-assigned ids.\n *\n * The analyzer prices fast mode under a synthetic `claude-opus-5#fast` key\n * because it bills at a different rate ($10/$50 vs $5/$25). That suffix is OURS,\n * not the vendor's, so publishing it would hand the server an id that cannot\n * resolve against the models catalog — the exact silent-disappearance failure\n * decision 3 exists to prevent. The rows are therefore merged back onto the base\n * id here. Cost stays exact because it was already accumulated per response at\n * the fast rate; what is lost is the fast-mode share itself, which the payload\n * has no field for and which is a candidate for a later schema bump.\n */\nfunction groupModels(rows: readonly ModelRow[]): ModelGroup[] {\n\tconst groups = new Map<string, ModelGroup>();\n\tfor (const r of rows) {\n\t\tconst id = sanitizeModelId(baseModelId(r.modelKey));\n\t\tlet g = groups.get(id);\n\t\tif (!g) {\n\t\t\tg = {\n\t\t\t\tid,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcostUSD: 0,\n\t\t\t\tunpricedTokens: 0,\n\t\t\t\tanyUnpriceable: false,\n\t\t\t};\n\t\t\tgroups.set(id, g);\n\t\t}\n\t\tg.totalTokens += r.totalTokens;\n\t\tg.input += r.tokens.input;\n\t\tg.output += r.tokens.output;\n\t\tg.cacheWrite +=\n\t\t\tr.tokens.cacheWrite5m +\n\t\t\tr.tokens.cacheWrite1h +\n\t\t\tr.tokens.cacheWriteUnsplit;\n\t\tg.cacheRead += r.tokens.cacheRead;\n\t\tg.costUSD += r.costUSD ?? 0;\n\t\tg.unpricedTokens += r.unpricedTokens;\n\t\tif (r.costUSD === null) g.anyUnpriceable = true;\n\t}\n\treturn [...groups.values()].sort(\n\t\t(a, b) => b.totalTokens - a.totalTokens || a.id.localeCompare(b.id),\n\t);\n}\n\nfunction buildModels(\n\trows: readonly ModelRow[],\n\ttotalTokens: number,\n\tpublishCost: boolean,\n): PayloadModel[] {\n\treturn groupModels(rows).map((g) => {\n\t\tconst model: PayloadModel = {\n\t\t\tid: g.id,\n\t\t\ttokenShare: totalTokens ? round4(g.totalTokens / totalTokens) : 0,\n\t\t\ttokens: {\n\t\t\t\tinput: g.input,\n\t\t\t\toutput: g.output,\n\t\t\t\tcacheWrite: g.cacheWrite,\n\t\t\t\tcacheRead: g.cacheRead,\n\t\t\t},\n\t\t};\n\t\t// Absent, not zero: a partially-priced model reporting a dollar figure\n\t\t// would understate without saying so. `excludedTokens.unpriced` carries\n\t\t// the tokens that were left out.\n\t\tif (publishCost && !g.anyUnpriceable && g.unpricedTokens === 0) {\n\t\t\tmodel.apiEquivalentUSD = round2(g.costUSD);\n\t\t}\n\t\treturn model;\n\t});\n}\n\n// ---------------------------------------------------------------------------\n// Build\n// ---------------------------------------------------------------------------\n\nexport type BuildPayloadInput = {\n\taggregate: Aggregate;\n\tstats: ScanStats;\n\tsyncConfig: SyncConfig;\n\t/** Client clock, epoch ms. The same value used to derive the scan window. */\n\tnow: number;\n\twindowDays: number;\n};\n\nexport type BuiltPayload = {\n\tpayload: MeasuredPayload;\n\t/** The same numbers unfiltered, for the local report and the approve gate. */\n\tfinalized: Finalized;\n\t/**\n\t * Every observed name that will NOT publish, by category — the gate's review\n\t * list (#42 decision 1, wired in #44).\n\t *\n\t * This is the one thing here that is deliberately NOT in the payload. It is\n\t * the list of names the user has not agreed to publish, so it stays on the\n\t * machine; the payload carries only the per-category COUNT.\n\t */\n\tkeptPrivate: Record<NameCategory, KeptPrivateAtom[]>;\n};\n\nexport function buildPayload(input: BuildPayloadInput): BuiltPayload {\n\tconst { aggregate: agg, stats, syncConfig, now, windowDays } = input;\n\tconst finalized = finalize(agg);\n\tconst { publishCost, allowlist, optIns } = syncConfig;\n\n\tconst fromMs = windowStartMs(now, windowDays);\n\tconst from = utcDate(fromMs);\n\tconst to = utcDate(now);\n\n\t// Counted against the reported window rather than taken from the aggregate's\n\t// size: a clock-skewed, imported, or restored transcript dated in the future\n\t// would otherwise push activeDays past `windowDays`, printing an impossible\n\t// value under a payload that claims to be deterministic.\n\tlet activeDays = 0;\n\tfor (const d of agg.activeDays) if (d >= from && d <= to) activeDays++;\n\n\tconst totalToolCalls = finalized.totalToolCalls;\n\tconst builtins = buildCategory(\n\t\tfinalized.tools,\n\t\tBUILTIN_TOOLS,\n\t\toptIns.builtinTools,\n\t\ttotalToolCalls,\n\t);\n\tconst mcp = buildCategory(\n\t\tfinalized.mcpServers,\n\t\tnew Set(allowlist.mcpServers),\n\t\toptIns.mcpServers,\n\t\tsumCounts(finalized.mcpServers),\n\t);\n\tconst skills = buildCategory(\n\t\tfinalized.skills,\n\t\tnew Set(allowlist.skills),\n\t\toptIns.skills,\n\t\tsumCounts(finalized.skills),\n\t);\n\tconst subagents = buildCategory(\n\t\tfinalized.subagents,\n\t\tnew Set(allowlist.subagents),\n\t\toptIns.subagents,\n\t\tsumCounts(finalized.subagents),\n\t);\n\tconst slash = buildCategory(\n\t\tfinalized.slashCommands,\n\t\tnew Set(allowlist.slashCommands),\n\t\toptIns.slashCommands,\n\t\tsumCounts(finalized.slashCommands),\n\t);\n\n\tconst payload: MeasuredPayload = {\n\t\tschemaVersion: SCHEMA_VERSION,\n\t\tcapturedAt: now,\n\t\twindow: { days: windowDays, from, to },\n\t\tharness: {\n\t\t\tname: HARNESS_NAME,\n\t\t\tversion:\n\t\t\t\tfinalized.harnessVersion === null\n\t\t\t\t\t? null\n\t\t\t\t\t: sanitizeModelId(finalized.harnessVersion),\n\t\t},\n\t\tpricingTable: publishCost ? PRICING_TABLE_VERSION : null,\n\t\tactivity: {\n\t\t\tsessions: finalized.sessions,\n\t\t\tactiveDays,\n\t\t\tprojects: finalized.projects,\n\t\t\ttotalTokens: finalized.totalTokens,\n\t\t\tcacheHitShare: round4(finalized.cacheHitShare),\n\t\t\tsubagentShare: round4(finalized.sidechainShare),\n\t\t},\n\t\tmodels: buildModels(finalized.models, finalized.totalTokens, publishCost),\n\t\tinventory: {\n\t\t\tbuiltinTools: builtins.atoms,\n\t\t\tmcpServers: mcp.atoms,\n\t\t\tskills: skills.atoms,\n\t\t\tsubagents: subagents.atoms,\n\t\t\tslashCommands: slash.atoms,\n\t\t\twithheld: {\n\t\t\t\tbuiltinTools: builtins.withheld,\n\t\t\t\tmcpServers: mcp.withheld,\n\t\t\t\tskills: skills.withheld,\n\t\t\t\tsubagents: subagents.withheld,\n\t\t\t\tslashCommands: slash.withheld,\n\t\t\t},\n\t\t},\n\t\tcoverage: {\n\t\t\tfilesScanned: stats.filesRead,\n\t\t\tfilesUnreadable: stats.filesUnreadable,\n\t\t\tlinesParsed: agg.lines - agg.parseErrors,\n\t\t\tlinesFailed: agg.parseErrors,\n\t\t},\n\t\texcludedTokens: {\n\t\t\tunpriced: finalized.unpricedTokens,\n\t\t\tsynthetic: agg.syntheticTokens,\n\t\t},\n\t};\n\n\treturn {\n\t\tpayload,\n\t\tfinalized,\n\t\tkeptPrivate: {\n\t\t\tbuiltinTools: builtins.keptPrivate,\n\t\t\tmcpServers: mcp.keptPrivate,\n\t\t\tskills: skills.keptPrivate,\n\t\t\tsubagents: subagents.keptPrivate,\n\t\t\tslashCommands: slash.keptPrivate,\n\t\t},\n\t};\n}\n\n/** What `POST /api/cli/sync` takes: one sealed payload, one unsealed half. */\nexport type SyncBody = {\n\tpayload: MeasuredPayload;\n\tkeptPrivate?: Record<NameCategory, KeptPrivateAtom[]>;\n};\n\n/**\n * Assemble the request body from a built payload.\n *\n * The two halves ride in ONE request (#48): a second call would let them drift\n * against a newer snapshot. They stay SEPARATE objects because the payload's\n * validator is closed and rejects any extra key — that closedness is the privacy\n * claim, so a kept-private name may sit beside the payload and never inside it.\n *\n * The switch is read from the sync config the server just served. Off — or a\n * config the machine could not fetch, which reads as off — sends the payload\n * alone and the names stay on the machine.\n */\nexport function buildSyncBody(\n\tbuilt: BuiltPayload,\n\tsyncConfig: SyncConfig,\n): SyncBody {\n\tif (!syncConfig.reviewKeptPrivate) return { payload: built.payload };\n\treturn { payload: built.payload, keptPrivate: built.keptPrivate };\n}\n","// Local transcript analysis -> the measured-layer wire payload.\n//\n// Wayfinder ticket #37 (map #29). Everything here runs on the user's machine;\n// only the object returned by `buildPayload` is ever a candidate to leave it, and\n// only after the approve gate the send channel owns (ticket #41).\n//\n// Typical use:\n//\n// const now = Date.now();\n// const agg = createAggregate();\n// const stats = await scan(agg, { sinceMs: windowStartMs(now, DEFAULT_WINDOW_DAYS) });\n// const { config } = await loadSyncConfig({ baseUrl });\n// const { payload } = buildPayload({\n// aggregate: agg, stats, syncConfig: config, now, windowDays: DEFAULT_WINDOW_DAYS,\n// });\n\nexport {\n\ttype Atom,\n\tBUILTIN_TOOLS,\n\tBUNDLED_SYNC_CONFIG,\n\ttype CuratedAllowlist,\n\tEMPTY_OPT_INS,\n\ttype FilteredAtoms,\n\ttype FilterSets,\n\tfilterAtoms,\n\ttype KeptPrivateAtom,\n\ttype LoadedSyncConfig,\n\tloadSyncConfig,\n\tNAME_CATEGORIES,\n\ttype NameCategory,\n\ttype OptInNames,\n\tpluginGroup,\n\ttype SyncConfig,\n\ttype SyncConfigSource,\n} from \"./allowlist.js\";\nexport {\n\ttype Aggregate,\n\tcleanName,\n\tcreateAggregate,\n\ttype Finalized,\n\tfinalize,\n\ttype IngestContext,\n\tingestRecord,\n\tisDisplaySafeName,\n\ttype ModelRow,\n\ttype ModelUsage,\n\tnewestVersion,\n} from \"./analyzer.js\";\nexport { BUNDLED_CURATED_ALLOWLIST } from \"./bundled-allowlist.js\";\nexport {\n\tbuildPayload,\n\tbuildSyncBody,\n\tHARNESS_NAME,\n\ttype MeasuredPayload,\n\ttype PayloadAtom,\n\ttype PayloadInventory,\n\ttype PayloadModel,\n\tSCHEMA_VERSION,\n\ttype SyncBody,\n\tsanitizeModelId,\n} from \"./payload.js\";\nexport {\n\tapiEquivalentCost,\n\tbaseModelId,\n\tCACHE_READ_MULTIPLIER,\n\tCACHE_WRITE_1H_MULTIPLIER,\n\tCACHE_WRITE_5M_MULTIPLIER,\n\tisPricedModel,\n\tnormalizeModel,\n\tPRICING_TABLE_VERSION,\n\ttype PricePeriod,\n\tpriceAt,\n\tSONNET_5_INTRO_ENDS_MS,\n\ttype TokenCounts,\n} from \"./pricing.js\";\nexport {\n\ttype ScanOptions,\n\ttype ScanStats,\n\tscan,\n\ttranscriptRoots,\n\twindowStartMs,\n} from \"./scan.js\";\n\n/** Rolling window locked by the owner in the #32 prototype resolution. */\nexport const DEFAULT_WINDOW_DAYS = 30;\n","// The approve gate's two beats, as text.\n//\n// Wayfinder ticket #41 (map #29), shape fixed by the spike #35 and the copy\n// locked in #48. Beat one is the FULL summary, printed as ordinary scrollable\n// transcript output. Beat two is the SHORT elicitation message — it must stay\n// short, or `Accept` falls below the fold and the gate times out (#35, 1H).\n//\n// Everything here derives from the exact bytes that will be sent (`body`),\n// plus the local-only kept-private list that deliberately never enters them.\n// Nothing in this file is accepted as a caller-supplied argument beside the\n// payload — the spike promoted that from a caution to a demonstrated property.\n\nimport type {\n\tKeptPrivateAtom,\n\tNameCategory,\n\tSyncConfig,\n\tSyncConfigSource,\n} from \"../transcripts/allowlist.js\";\nimport { NAME_CATEGORIES } from \"../transcripts/allowlist.js\";\nimport type { MeasuredPayload, SyncBody } from \"../transcripts/payload.js\";\n\nexport type GateContext = {\n\t/** The exact request body a publish would send. */\n\tbody: SyncBody;\n\t/** The local-only review list — never inside `body.payload` (#44). */\n\tkeptPrivate: Record<NameCategory, KeptPrivateAtom[]>;\n\tconfig: SyncConfig;\n\tsource: SyncConfigSource;\n\t/** Web origin for the URLs the gate prints, e.g. https://aistack.to */\n\tbaseUrl: string;\n};\n\n// ---------------------------------------------------------------------------\n// Formatting\n// ---------------------------------------------------------------------------\n\n/** `4.27B`, `40.7M`, `216k`, `950` — three significant digits, like #40. */\nexport function fmtTokens(n: number): string {\n\tconst sig = (v: number): string => {\n\t\tconst s = v.toPrecision(3);\n\t\treturn s.includes(\".\") ? s.replace(/\\.?0+$/, \"\") : s;\n\t};\n\tif (n >= 1e9) return `${sig(n / 1e9)}B`;\n\tif (n >= 1e6) return `${sig(n / 1e6)}M`;\n\tif (n >= 1e3) return `${sig(n / 1e3)}k`;\n\treturn String(n);\n}\n\n/** `≈$5,840` — whole dollars; the ≈ and \"at API prices\" wording are #37's. */\nexport function fmtUSD(n: number): string {\n\treturn `≈$${Math.round(n).toLocaleString(\"en-US\")}`;\n}\n\nconst fmtPct = (share: number): string => `${(share * 100).toFixed(1)}%`;\n\n/**\n * The dollar figure the gate names, or `null` when none may render.\n *\n * Mirrors the public display's rule (#46): a dollar figure never renders\n * without its pricing table. Summing only the models that carry the field\n * matches what actually goes up — an unpriceable model publishes tokens, not\n * dollars.\n */\nexport function totalUSD(payload: MeasuredPayload): number | null {\n\tif (payload.pricingTable === null) return null;\n\tlet sum = 0;\n\tlet any = false;\n\tfor (const m of payload.models) {\n\t\tif (m.apiEquivalentUSD !== undefined) {\n\t\t\tsum += m.apiEquivalentUSD;\n\t\t\tany = true;\n\t\t}\n\t}\n\treturn any ? sum : null;\n}\n\n/** DISTINCT kept-private names, from the send bytes (`inventory.withheld`). */\nexport function withheldCount(payload: MeasuredPayload): number {\n\tconst w = payload.inventory.withheld;\n\treturn (\n\t\tw.builtinTools + w.mcpServers + w.skills + w.subagents + w.slashCommands\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Beat two — the elicitation message. Copy locked in #48; keep it SHORT.\n// ---------------------------------------------------------------------------\n\nexport function buildGateDialog(ctx: GateContext): string {\n\tconst { payload, keptPrivate } = ctx.body;\n\tconst usd = totalUSD(payload);\n\tconst facts = [\n\t\t`${fmtTokens(payload.activity.totalTokens)} tokens`,\n\t\t`${payload.window.days} days`,\n\t\t...(usd === null ? [] : [fmtUSD(usd)]),\n\t].join(\" · \");\n\n\tconst n = withheldCount(payload);\n\tconst lines = [`Publish to aistack? ${facts}`];\n\tif (n > 0) {\n\t\tlines.push(\n\t\t\tkeptPrivate === undefined\n\t\t\t\t? `${n} name${n === 1 ? \"\" : \"s\"} stay${n === 1 ? \"s\" : \"\"} on this machine`\n\t\t\t\t: `${n} name${n === 1 ? \"\" : \"s\"} go${n === 1 ? \"es\" : \"\"} up for you to review`,\n\t\t);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Beat one — the full summary, transcript output.\n// ---------------------------------------------------------------------------\n\nconst CATEGORY_LABEL: Record<NameCategory, string> = {\n\tbuiltinTools: \"tools\",\n\tmcpServers: \"mcp\",\n\tskills: \"skills\",\n\tsubagents: \"agents\",\n\tslashCommands: \"commands\",\n};\n\n/** Kept-private rows for the gate: one row per group, then singles (#48). */\nexport function keptPrivateRows(\n\tkeptPrivate: Record<NameCategory, KeptPrivateAtom[]>,\n): Array<{ label: string; names: number }> {\n\tconst groups = new Map<string, number>();\n\tconst singles: string[] = [];\n\tfor (const category of NAME_CATEGORIES) {\n\t\tfor (const atom of keptPrivate[category]) {\n\t\t\tif (atom.group === null) singles.push(atom.name);\n\t\t\telse groups.set(atom.group, (groups.get(atom.group) ?? 0) + 1);\n\t\t}\n\t}\n\tconst rows = [...groups].map(([label, names]) => ({ label, names }));\n\tfor (const name of singles) rows.push({ label: name, names: 1 });\n\trows.sort((a, b) => b.names - a.names || a.label.localeCompare(b.label));\n\treturn rows;\n}\n\nconst KEPT_PRIVATE_ROWS_SHOWN = 6;\n\nexport function buildGateSummary(ctx: GateContext): string {\n\tconst { body, keptPrivate, config, source, baseUrl } = ctx;\n\tconst { payload } = body;\n\tconst host = baseUrl.replace(/^https?:\\/\\//, \"\");\n\tconst out: string[] = [];\n\n\tout.push(\"from your machine — sync preview\");\n\tout.push(\"\");\n\n\tif (config.stack === null) {\n\t\tout.push(\"to (no linked stack — publish is unavailable)\");\n\t} else {\n\t\tout.push(\n\t\t\t`to ${config.stack.name} · ${host}/stacks/${config.stack.slug}`,\n\t\t);\n\t}\n\tout.push(\n\t\t`window ${payload.window.days} days · ${payload.window.from} → ${payload.window.to}`,\n\t);\n\tout.push(\n\t\t`activity ${payload.activity.sessions} sessions · ${payload.activity.activeDays} active days · ${fmtTokens(payload.activity.totalTokens)} tokens`,\n\t);\n\tconst usd = totalUSD(payload);\n\tout.push(\n\t\tusd === null\n\t\t\t? \"cost not published\"\n\t\t\t: `cost ${fmtUSD(usd)} at API prices`,\n\t);\n\n\t// Coverage is silent when clean; a degraded scan is named as a floor (#40).\n\tconst cov = payload.coverage;\n\tif (cov.filesUnreadable > 0 || cov.linesFailed > 0) {\n\t\tout.push(\n\t\t\t`coverage ${cov.filesUnreadable} files unreadable · ${cov.linesFailed} lines failed — this reading is a floor`,\n\t\t);\n\t}\n\n\tout.push(\"\");\n\tout.push(\"models\");\n\tfor (const m of payload.models) {\n\t\tconst dollars =\n\t\t\tusd !== null && m.apiEquivalentUSD !== undefined\n\t\t\t\t? ` ${fmtUSD(m.apiEquivalentUSD)}`\n\t\t\t\t: \"\";\n\t\tout.push(` ${m.id.padEnd(28)} ${fmtPct(m.tokenShare)}${dollars}`);\n\t}\n\n\tout.push(\"\");\n\tout.push(\"what publishes\");\n\tfor (const category of NAME_CATEGORIES) {\n\t\tconst atoms = payload.inventory[category];\n\t\tif (atoms.length === 0) continue;\n\t\tconst names = atoms.map((a) => a.name).join(\", \");\n\t\tout.push(` ${CATEGORY_LABEL[category].padEnd(9)} ${names}`);\n\t}\n\n\tconst n = withheldCount(payload);\n\tif (n > 0) {\n\t\tout.push(\"\");\n\t\tout.push(`kept private: ${n} name${n === 1 ? \"\" : \"s\"}`);\n\t\tconst rows = keptPrivateRows(keptPrivate);\n\t\tconst shown = rows.slice(0, KEPT_PRIVATE_ROWS_SHOWN);\n\t\tconst width = Math.max(...shown.map((r) => r.label.length));\n\t\tfor (const row of shown) {\n\t\t\tout.push(` ${row.label.padEnd(width)} ${row.names}`);\n\t\t}\n\t\tif (rows.length > shown.length) {\n\t\t\tout.push(` ...${rows.length - shown.length} more`);\n\t\t}\n\t\t// #48: beat one names the switch before the first upload, and points at\n\t\t// the changes page. Both lines are the locked copy, verbatim or near it.\n\t\tif (body.keptPrivate !== undefined && config.stack !== null) {\n\t\t\tout.push(` publish them at ${host}/stacks/${config.stack.slug}/changes`);\n\t\t\tout.push(\n\t\t\t\t\" (they go up for you to review — turn off: Review kept-private names, on your stack)\",\n\t\t\t);\n\t\t} else {\n\t\t\tout.push(\" they stay on this machine\");\n\t\t}\n\t}\n\n\tif (source === \"bundled\") {\n\t\tout.push(\"\");\n\t\tout.push(\n\t\t\t\"! could not fetch your settings from aistack — using the bundled list.\",\n\t\t);\n\t\tout.push(\n\t\t\t\" This publishes less: no cost, no ticked names, nothing staged for review.\",\n\t\t);\n\t}\n\n\treturn out.join(\"\\n\");\n}\n","// The local stdio MCP server — the send channel picked by the spike #35.\n//\n// Wayfinder ticket #41 (map #29). Two tools, two beats:\n//\n// sync_preview — scans locally, stages the exact send bytes, returns the\n// full summary as ordinary transcript output (beat one).\n// sync_publish — takes the stage id, raises a SHORT `elicitation/create`\n// with an ENUM field (beat two), and sends only on\n// `decision: \"publish\"`.\n//\n// Why elicitation and not `requiresUserInteraction`: the spike showed the\n// permission dialog can be silenced forever with one click and writes a grant\n// broader than the sentence shown, while an elicitation is raised INSIDE the\n// call — there is no string a model can spell to route around it, and no\n// \"don't ask again\" exists for it. The enum widget is the working one; the\n// boolean widget is dead in 2.1.220 and must never ship.\n//\n// Fail-closed, by construction: ESC, a timeout, a headless auto-cancel, an\n// error reply, or a client that never declared the elicitation capability all\n// resolve to \"nothing was sent\". The model's arguments count for nothing —\n// the only path to a send runs through the user's own keystrokes.\n//\n// Hand-rolled JSON-RPC over stdio, zero dependencies, structured so tests can\n// drive `handle()` directly and capture every outbound frame.\n\nimport { type SyncPublishResult, syncPublish } from \"../api.js\";\nimport { type StageDeps, type StagedSend, stageSync } from \"./stage.js\";\n\nconst SERVER_NAME = \"aistack\";\nconst SERVER_VERSION = \"0.3.0\";\n\n/** How long a staged preview stays publishable. Stale bytes must re-preview. */\nexport const STAGE_TTL_MS = 10 * 60 * 1000;\n\n/**\n * How long the gate waits for the human. Deliberately WELL past the harness's\n * own 120 s tool timeout (#35, 1H measured 92 s for a one-line answer): the\n * server must never be the first to give up. On expiry it resolves as cancel.\n */\nexport const ELICIT_TIMEOUT_MS = 10 * 60 * 1000;\n\nconst PREVIEW_TOOL = {\n\tname: \"sync_preview\",\n\tdescription:\n\t\t\"Scan local Claude Code transcripts and stage a measured-usage snapshot for aistack. \" +\n\t\t\"Returns the full preview of exactly what would publish. \" +\n\t\t\"Show the returned text to the user VERBATIM — it is the review surface. Nothing is sent.\",\n\tinputSchema: { type: \"object\", properties: {} },\n\tannotations: {\n\t\ttitle: \"aistack — preview sync (sends nothing)\",\n\t\treadOnlyHint: true,\n\t\topenWorldHint: true,\n\t},\n};\n\nconst PUBLISH_TOOL = {\n\tname: \"sync_publish\",\n\tdescription:\n\t\t\"Publish the staged aistack snapshot named by preview_id. \" +\n\t\t\"Asks the user for confirmation during the call; only their explicit choice sends anything. \" +\n\t\t\"Call sync_preview first and show its output.\",\n\tinputSchema: {\n\t\ttype: \"object\",\n\t\tproperties: {\n\t\t\tpreview_id: {\n\t\t\t\ttype: \"string\",\n\t\t\t\tdescription: \"The `preview id` line from sync_preview's output.\",\n\t\t\t},\n\t\t},\n\t\trequired: [\"preview_id\"],\n\t},\n\tannotations: {\n\t\ttitle: \"aistack — publish measured usage (asks the user first)\",\n\t\tdestructiveHint: false,\n\t\topenWorldHint: true,\n\t},\n};\n\ntype JsonRpcMessage = {\n\tjsonrpc?: string;\n\tid?: string | number;\n\tmethod?: string;\n\tparams?: Record<string, unknown> | undefined;\n\tresult?: unknown;\n\terror?: unknown;\n};\n\nexport type SyncServerDeps = {\n\tbaseUrl: string;\n\tstageImpl?: (deps: StageDeps) => Promise<StagedSend>;\n\tpublishImpl?: (token: string, bodyJson: string) => Promise<SyncPublishResult>;\n\tnow?: () => number;\n\telicitTimeoutMs?: number;\n\t/** Diagnostics only. NEVER stdout — that would corrupt the protocol. */\n\tlog?: (line: string) => void;\n};\n\nexport type SyncServer = {\n\thandle: (msg: JsonRpcMessage) => void;\n\t/** Test seam: the staged send, if any. */\n\tstaged: () => StagedSend | null;\n};\n\nconst textResult = (text: string, isError = false) => ({\n\tcontent: [{ type: \"text\", text }],\n\t...(isError ? { isError: true } : {}),\n});\n\nexport function createSyncServer(\n\tdeps: SyncServerDeps,\n\tsend: (msg: JsonRpcMessage) => void,\n): SyncServer {\n\tconst now = deps.now ?? Date.now;\n\tconst stage = deps.stageImpl ?? stageSync;\n\tconst publish = deps.publishImpl ?? syncPublish;\n\tconst log = deps.log ?? (() => {});\n\tconst elicitTimeoutMs = deps.elicitTimeoutMs ?? ELICIT_TIMEOUT_MS;\n\n\tlet clientSupportsElicitation = false;\n\tlet staged: StagedSend | null = null;\n\tlet nextRequestId = 1;\n\tconst pending = new Map<string, (reply: JsonRpcMessage | null) => void>();\n\n\tconst ok = (id: string | number | undefined, result: unknown) =>\n\t\tsend({ jsonrpc: \"2.0\", id, result });\n\tconst err = (\n\t\tid: string | number | undefined,\n\t\tcode: number,\n\t\tmessage: string,\n\t) => send({ jsonrpc: \"2.0\", id, error: { code, message } });\n\n\t/** Ask the client something; `null` reply means the gate timed out. */\n\tconst request = (\n\t\tmethod: string,\n\t\tparams: Record<string, unknown>,\n\t\tonReply: (reply: JsonRpcMessage | null) => void,\n\t) => {\n\t\tconst id = `aistack-${nextRequestId++}`;\n\t\tpending.set(id, onReply);\n\t\tsend({ jsonrpc: \"2.0\", id, method, params });\n\t\tconst timer = setTimeout(() => {\n\t\t\tif (pending.delete(id)) onReply(null);\n\t\t}, elicitTimeoutMs);\n\t\t(timer as { unref?: () => void }).unref?.();\n\t};\n\n\tconst runPreview = async (id: string | number | undefined) => {\n\t\ttry {\n\t\t\tstaged = await stage({ baseUrl: deps.baseUrl, now });\n\t\t} catch (e) {\n\t\t\tstaged = null;\n\t\t\tconst message = e instanceof Error ? e.message : String(e);\n\t\t\treturn ok(id, textResult(`Preview failed: ${message}`, true));\n\t\t}\n\t\tconst lines = [staged.summary, \"\"];\n\t\tif (staged.blockedReason === null) {\n\t\t\tlines.push(`preview id: ${staged.id}`);\n\t\t\tlines.push(\n\t\t\t\t\"To publish, call sync_publish with this preview id. The user confirms in a dialog during that call.\",\n\t\t\t);\n\t\t} else {\n\t\t\tlines.push(`publish unavailable: ${staged.blockedReason}`);\n\t\t}\n\t\treturn ok(id, textResult(lines.join(\"\\n\")));\n\t};\n\n\tconst runPublish = (\n\t\tid: string | number | undefined,\n\t\targs: Record<string, unknown> | undefined,\n\t) => {\n\t\t// Every refusal below is fail-closed: no dialog was shown, nothing sent.\n\t\tif (!clientSupportsElicitation) {\n\t\t\treturn ok(\n\t\t\t\tid,\n\t\t\t\ttextResult(\n\t\t\t\t\t\"Not published: this Claude Code version did not declare the elicitation capability, \" +\n\t\t\t\t\t\t\"so the approve dialog cannot be shown. The gate never degrades silently — \" +\n\t\t\t\t\t\t\"update Claude Code and try again.\",\n\t\t\t\t\ttrue,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tconst previewId = args?.preview_id;\n\t\tif (staged === null) {\n\t\t\treturn ok(\n\t\t\t\tid,\n\t\t\t\ttextResult(\n\t\t\t\t\t\"Not published: nothing is staged. Run sync_preview first and show its output to the user.\",\n\t\t\t\t\ttrue,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tif (typeof previewId !== \"string\" || previewId !== staged.id) {\n\t\t\treturn ok(\n\t\t\t\tid,\n\t\t\t\ttextResult(\n\t\t\t\t\t\"Not published: preview_id does not match the staged preview. Run sync_preview again.\",\n\t\t\t\t\ttrue,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tif (staged.blockedReason !== null) {\n\t\t\treturn ok(id, textResult(`Not published: ${staged.blockedReason}`, true));\n\t\t}\n\t\tif (now() - staged.stagedAt > STAGE_TTL_MS) {\n\t\t\tstaged = null;\n\t\t\treturn ok(\n\t\t\t\tid,\n\t\t\t\ttextResult(\n\t\t\t\t\t\"Not published: the staged preview is older than 10 minutes. Run sync_preview again so the user reviews current bytes.\",\n\t\t\t\t\ttrue,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tconst approvedStage = staged;\n\t\tlog(`elicitation raised for stage ${approvedStage.id}`);\n\t\trequest(\n\t\t\t\"elicitation/create\",\n\t\t\t{\n\t\t\t\tmessage: approvedStage.dialog,\n\t\t\t\trequestedSchema: {\n\t\t\t\t\ttype: \"object\",\n\t\t\t\t\tproperties: {\n\t\t\t\t\t\tdecision: {\n\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t// The enum widget is the one that works (#35, 1G). Never a boolean.\n\t\t\t\t\t\t\tenum: [\"publish\", \"cancel\"],\n\t\t\t\t\t\t\tdescription: \"Publish the snapshot described above?\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\trequired: [\"decision\"],\n\t\t\t\t},\n\t\t\t},\n\t\t\t(reply) => {\n\t\t\t\tconst result = reply?.result as\n\t\t\t\t\t| { action?: string; content?: { decision?: string } }\n\t\t\t\t\t| undefined;\n\t\t\t\tconst approved =\n\t\t\t\t\tresult?.action === \"accept\" &&\n\t\t\t\t\tresult?.content?.decision === \"publish\";\n\t\t\t\tif (!approved) {\n\t\t\t\t\tconst outcome =\n\t\t\t\t\t\treply === null ? \"timed out\" : (result?.action ?? \"error\");\n\t\t\t\t\tlog(`elicitation resolved without consent: ${outcome}`);\n\t\t\t\t\treturn ok(\n\t\t\t\t\t\tid,\n\t\t\t\t\t\ttextResult(\n\t\t\t\t\t\t\t`Not published: the confirmation was not accepted (${outcome}). Nothing left this machine.`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tlog(`consent received, sending stage ${approvedStage.id}`);\n\t\t\t\tpublish(approvedStage.token as string, approvedStage.bodyJson).then(\n\t\t\t\t\t(res) => {\n\t\t\t\t\t\tif (staged?.id === approvedStage.id) staged = null;\n\t\t\t\t\t\tconst lines = [\n\t\t\t\t\t\t\t`Published. Snapshot received at ${new Date(res.receivedAt).toISOString()}.`,\n\t\t\t\t\t\t\tres.url,\n\t\t\t\t\t\t];\n\t\t\t\t\t\tconst kp = approvedStage.body.keptPrivate;\n\t\t\t\t\t\tif (res.keptPrivate.refused && kp !== undefined) {\n\t\t\t\t\t\t\tlines.push(\n\t\t\t\t\t\t\t\t\"Note: the kept-private names were refused by the server — the review switch is off there now. They stayed on this machine.\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else if (res.keptPrivate.stored > 0) {\n\t\t\t\t\t\t\tlines.push(\n\t\t\t\t\t\t\t\t`${res.keptPrivate.stored} kept-private names went up for your review at ${res.url}/changes`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tok(id, textResult(lines.join(\"\\n\")));\n\t\t\t\t\t},\n\t\t\t\t\t(e) => {\n\t\t\t\t\t\tconst message = e instanceof Error ? e.message : String(e);\n\t\t\t\t\t\tok(\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\ttextResult(`Publish failed after consent: ${message}`, true),\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\t};\n\n\tconst handle = (msg: JsonRpcMessage) => {\n\t\tconst { id, method, params } = msg;\n\n\t\t// A reply to something we asked, not a new request.\n\t\tif (method === undefined && id !== undefined && pending.has(String(id))) {\n\t\t\tconst onReply = pending.get(String(id));\n\t\t\tpending.delete(String(id));\n\t\t\tonReply?.(msg);\n\t\t\treturn;\n\t\t}\n\n\t\tswitch (method) {\n\t\t\tcase \"initialize\": {\n\t\t\t\tconst capabilities =\n\t\t\t\t\t(params?.capabilities as Record<string, unknown> | undefined) ?? {};\n\t\t\t\tclientSupportsElicitation = \"elicitation\" in capabilities;\n\t\t\t\tlog(\n\t\t\t\t\t`initialize: elicitation ${clientSupportsElicitation ? \"declared\" : \"ABSENT\"}`,\n\t\t\t\t);\n\t\t\t\treturn ok(id, {\n\t\t\t\t\tprotocolVersion:\n\t\t\t\t\t\t(params?.protocolVersion as string | undefined) ?? \"2025-06-18\",\n\t\t\t\t\tcapabilities: { tools: { listChanged: false } },\n\t\t\t\t\tserverInfo: { name: SERVER_NAME, version: SERVER_VERSION },\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"ping\":\n\t\t\t\treturn ok(id, {});\n\n\t\t\tcase \"tools/list\":\n\t\t\t\treturn ok(id, { tools: [PREVIEW_TOOL, PUBLISH_TOOL] });\n\n\t\t\tcase \"tools/call\": {\n\t\t\t\tconst name = params?.name;\n\t\t\t\tconst args = params?.arguments as Record<string, unknown> | undefined;\n\t\t\t\tif (name === \"sync_preview\") return void runPreview(id);\n\t\t\t\tif (name === \"sync_publish\") return runPublish(id, args);\n\t\t\t\treturn err(id, -32602, `Unknown tool: ${String(name)}`);\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tif (method?.startsWith(\"notifications/\")) return;\n\t\t\t\tif (method !== undefined)\n\t\t\t\t\treturn err(id, -32601, `Method not found: ${method}`);\n\t\t}\n\t};\n\n\treturn { handle, staged: () => staged };\n}\n\n/** Wire the server to real stdio. Never returns; the harness owns the process. */\nexport function runStdioSyncServer(deps: SyncServerDeps): void {\n\tconst server = createSyncServer(deps, (msg) => {\n\t\tprocess.stdout.write(`${JSON.stringify(msg)}\\n`);\n\t});\n\tlet buffer = \"\";\n\tprocess.stdin.setEncoding(\"utf8\");\n\tprocess.stdin.on(\"data\", (chunk: string) => {\n\t\tbuffer += chunk;\n\t\tlet nl = buffer.indexOf(\"\\n\");\n\t\twhile (nl !== -1) {\n\t\t\tconst line = buffer.slice(0, nl).trim();\n\t\t\tbuffer = buffer.slice(nl + 1);\n\t\t\tif (line) {\n\t\t\t\ttry {\n\t\t\t\t\tserver.handle(JSON.parse(line));\n\t\t\t\t} catch (e) {\n\t\t\t\t\tdeps.log?.(`parse error: ${String(e)}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tnl = buffer.indexOf(\"\\n\");\n\t\t}\n\t});\n}\n"],"mappings":"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","names":["path","p","path","existsSync","readFileSync","homedir","join","path","existsSync","readFileSync","homedir","join","path","readJson","existsSync","readFileSync","homedir","join","path","p","readJson","existsSync","readFileSync","join","homedir","existsSync","readdirSync","readFileSync","homedir","join","stat","intro","outro","intro","outro","existsSync","homedir","dirname","join","p","join","homedir","dirname","existsSync","intro","outro","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","p","intro","join","existsSync","readFileSync","confirm","dirname","mkdirSync","writeFileSync","outro","p","intro","outro","p","p","p","homedir","homedir","p","lines","intro","lines","outro","log","request","lines"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/api.ts","../src/commands/collect.ts","../src/classifier.ts","../src/stableKey.ts","../src/config.ts","../src/git.ts","../src/github-repo.ts","../src/hooks.ts","../src/mcp.ts","../src/plugins.ts","../src/scanner.ts","../src/theme.ts","../src/commands/connect.ts","../src/commands/create.ts","../src/commands/login.ts","../src/commands/sync.ts","../src/autosync/codexHook.ts","../src/autosync/optin.ts","../src/autosync/hook.ts","../src/autosync/run.ts","../src/sync/stage.ts","../src/harness/claude/adapter.ts","../src/harness/shared/pricing.ts","../src/harness/shared/aggregate.ts","../src/harness/shared/bundled-allowlist.ts","../src/harness/shared/allowlist.ts","../src/harness/claude/analyzer.ts","../src/harness/claude/scan.ts","../src/harness/shared/window.ts","../src/harness/codex/adapter.ts","../src/harness/codex/analyzer.ts","../src/harness/codex/scan.ts","../src/harness/shared/payload.ts","../src/harness/index.ts","../src/sync/summary.ts","../src/sync/server.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { BASE_URL } from \"./api.js\";\nimport { collectCommand } from \"./commands/collect.js\";\nimport { connectCommand } from \"./commands/connect.js\";\nimport { createCommand } from \"./commands/create.js\";\nimport { loginCommand } from \"./commands/login.js\";\nimport { syncCommand } from \"./commands/sync.js\";\nimport { runStdioSyncServer } from \"./sync/server.js\";\n\nconst program = new Command();\n\nprogram\n\t.name(\"aistack\")\n\t.description(\"Measure and share your AI stack from your terminal\")\n\t.version(\"0.5.0\");\n\nprogram\n\t.command(\"login\")\n\t.description(\"Authenticate with AI Stack\")\n\t.action(loginCommand);\n\nprogram\n\t.command(\"collect\")\n\t.description(\"Scan and upload AI config files from your project\")\n\t.option(\"--no-global\", \"Exclude global config files (~/.claude, etc.)\")\n\t.action((options) => collectCommand({ global: options.global ?? true }));\n\nprogram\n\t.command(\"create\")\n\t.description(\"Download and write your stack's AI config files\")\n\t.action(createCommand);\n\nprogram\n\t.command(\"mcp\")\n\t.description(\n\t\t\"Run the aistack MCP server on stdio (sync preview + gated publish)\",\n\t)\n\t.action(() => {\n\t\t// stdout belongs to the protocol. Diagnostics go to stderr only.\n\t\trunStdioSyncServer({\n\t\t\tbaseUrl: BASE_URL,\n\t\t\tlog: (line) => process.stderr.write(`[aistack-mcp] ${line}\\n`),\n\t\t});\n\t});\n\n// The documented default sync surface (#56): terminal-first, TTY gate.\nprogram\n\t.command(\"sync\")\n\t.description(\"Scan, preview, and publish measured usage (rolling 30 days)\")\n\t.option(\n\t\t\"--auto [state]\",\n\t\t\"silent background sync; 'on' enables the SessionStart hook, 'off' revokes it\",\n\t)\n\t.option(\n\t\t\"--every <hours>\",\n\t\t\"with --auto on: hours between auto-syncs (default 24)\",\n\t)\n\t.action((options) => syncCommand(options));\n\nprogram\n\t.command(\"connect\")\n\t.description(\"Install the in-session sync surface (MCP server + Skill)\")\n\t.argument(\"<harness>\", 'the harness to connect (\"claude\")')\n\t.action(connectCommand);\n\nprogram.parse();\n","export const BASE_URL = process.env.AISTACK_URL || \"https://aistack.to\";\n\nasync function request(\n\tpath: string,\n\toptions: RequestInit = {},\n): Promise<Response> {\n\treturn fetch(`${BASE_URL}${path}`, {\n\t\t...options,\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t...options.headers,\n\t\t},\n\t});\n}\n\nfunction authHeaders(token: string): HeadersInit {\n\treturn { Authorization: `Bearer ${token}` };\n}\n\n/**\n * Turn the two statuses #52 introduced into sentences.\n *\n * A bare `429` tells the user nothing they can act on, and a bare `403` reads\n * like a bug rather than a machine that is no longer allowed to do this. Every\n * other status keeps its number, because the number is all we know about it.\n */\nfunction failure(what: string, res: Response): Error {\n\tif (res.status === 429) {\n\t\tconst retry = res.headers.get(\"Retry-After\");\n\t\treturn new Error(\n\t\t\tretry\n\t\t\t\t? `${what}: too many requests. Try again in ${retry} seconds.`\n\t\t\t\t: `${what}: too many requests. Try again in a minute.`,\n\t\t);\n\t}\n\tif (res.status === 403) {\n\t\treturn new Error(\n\t\t\t`${what}: this machine is not allowed to do that. Run \\`aistack login\\` again to re-link it.`,\n\t\t);\n\t}\n\treturn new Error(`${what}: ${res.status}`);\n}\n\n/**\n * Open a device-code session.\n *\n * `machineName` is a PROPOSAL, not a fact: the approval page renders it in an\n * editable field, so the user sees the string before it is stored and can\n * overwrite or clear it. That is why the hostname may be sent automatically —\n * the consent happens in the browser, a moment later, with the string on screen.\n */\nexport async function authStart(machineName?: string): Promise<{\n\tsecretId: string;\n\tuserCode: string;\n\tauthUrl: string;\n}> {\n\tconst res = await request(\"/api/cli/auth/start\", {\n\t\tmethod: \"POST\",\n\t\tbody: JSON.stringify(machineName ? { machineName } : {}),\n\t});\n\tif (!res.ok) throw failure(\"Auth start failed\", res);\n\treturn res.json();\n}\n\nexport async function authPoll(\n\tsecretId: string,\n): Promise<{ status: string; token?: string; userId?: string }> {\n\tconst res = await request(\n\t\t`/api/cli/auth/poll?secretId=${encodeURIComponent(secretId)}`,\n\t);\n\tif (!res.ok) throw failure(\"Auth poll failed\", res);\n\treturn res.json();\n}\n\nexport async function stackCollect(\n\ttoken: string,\n\tdata: { resources: Resource[] },\n): Promise<{ slug: string; shortId: string; url: string }> {\n\tconst res = await request(\"/api/cli/stacks/collect\", {\n\t\tmethod: \"POST\",\n\t\theaders: authHeaders(token),\n\t\tbody: JSON.stringify(data),\n\t});\n\tif (res.status === 401)\n\t\tthrow new Error(\n\t\t\t\"Authentication expired. Run `npx @use-aistack/cli login` again.\",\n\t\t);\n\tif (!res.ok) {\n\t\tthrow new Error(await formatHttpError(res, \"Collect failed\"));\n\t}\n\treturn res.json();\n}\n\nasync function formatHttpError(res: Response, label: string): Promise<string> {\n\tconst prefix = `${label}: ${res.status} ${res.statusText || \"\"}`.trim();\n\tconst text = await res.text().catch(() => \"\");\n\tif (!text) return prefix;\n\ttry {\n\t\tconst body = JSON.parse(text) as { error?: string; message?: string };\n\t\tconst detail = body.error || body.message;\n\t\tif (detail) return `${prefix} — ${detail}`;\n\t} catch {}\n\tconst snippet = text.trim().slice(0, 500);\n\treturn snippet ? `${prefix} — ${snippet}` : prefix;\n}\n\nexport type SyncPublishResult = {\n\treceivedAt: number;\n\tstackSlug: string;\n\turl: string;\n\tkeptPrivate: { stored: number; refused: boolean };\n};\n\n/**\n * Publish one approved snapshot.\n *\n * Takes the staged body as an ALREADY-SERIALIZED string: the bytes the user\n * approved at the gate are the bytes on the wire, with no re-serialization\n * step between them (#35's binding constraint, #41).\n */\nexport async function syncPublish(\n\ttoken: string,\n\tbodyJson: string,\n): Promise<SyncPublishResult> {\n\tconst res = await request(\"/api/cli/sync\", {\n\t\tmethod: \"POST\",\n\t\theaders: authHeaders(token),\n\t\tbody: bodyJson,\n\t});\n\tif (res.status === 401)\n\t\tthrow new Error(\n\t\t\t\"Authentication expired. Run `npx @use-aistack/cli login` again.\",\n\t\t);\n\tif (res.status === 403 || res.status === 429)\n\t\tthrow failure(\"Sync failed\", res);\n\tif (!res.ok) {\n\t\tthrow new Error(await formatHttpError(res, \"Sync failed\"));\n\t}\n\treturn res.json();\n}\n\nexport async function stackGet(token: string): Promise<StackData | null> {\n\tconst res = await request(\"/api/cli/stacks\", {\n\t\theaders: authHeaders(token),\n\t});\n\tif (res.status === 401)\n\t\tthrow new Error(\n\t\t\t\"Authentication expired. Run `npx @use-aistack/cli login` again.\",\n\t\t);\n\tif (res.status === 404) return null;\n\tif (!res.ok) throw failure(\"Stack fetch failed\", res);\n\treturn res.json();\n}\n\n// Types used across the CLI\nexport interface ResourceFile {\n\tname: string;\n\tcontent: string;\n\tpath?: string;\n\ttags?: string[];\n}\n\nexport interface Resource {\n\ttype: string;\n\tname: string;\n\tdescription?: string;\n\tgroup: string;\n\tstableKey: string;\n\tfiles?: ResourceFile[];\n\tupstream?: {\n\t\trepoUrl: string;\n\t\tpath?: string;\n\t\tlicense?: string;\n\t\tstars?: number;\n\t\tlastCommitSha?: string;\n\t\tlastSyncAt?: number;\n\t};\n\tpkg?: {\n\t\tregistry: \"npm\" | \"pypi\" | \"oci\" | \"url\";\n\t\tid: string;\n\t\tversion?: string;\n\t\ttransport?: \"stdio\" | \"http\" | \"sse\";\n\t};\n}\n\nexport interface StackData {\n\tname: string;\n\tslug: string;\n\tshortId: string;\n\tresources: Resource[];\n}\n","import * as p from \"@clack/prompts\";\nimport { type Resource, stackCollect, stackGet } from \"../api.js\";\nimport { classify } from \"../classifier.js\";\nimport { getExcludedPaths, getToken, saveExcludedPaths } from \"../config.js\";\nimport { buildRepoLinkResource, detectRepoUrl } from \"../git.js\";\nimport { repoNameFromCanonical } from \"../github-repo.js\";\nimport { detectHooks } from \"../hooks.js\";\nimport { detectMcpServers } from \"../mcp.js\";\nimport { detectInstalledPlugins } from \"../plugins.js\";\nimport { type ScannedFile, scanGlobal, scanLocal } from \"../scanner.js\";\nimport {\n\tbold,\n\tdim,\n\tdivider,\n\tintro,\n\tlime,\n\tlimeBold,\n\tlines,\n\toutro,\n\toutroCancel,\n\toutroError,\n\toutroSkipped,\n\tred,\n\tsection,\n\tyellow,\n} from \"../theme.js\";\n\n// Sentinel selection key for the detected repo link. NUL-prefixed so it can\n// never collide with a real ScannedFile.relativePath, letting links ride the\n// existing excluded[] selection/persistence model with no config.ts changes.\nconst REPO_LINK_KEY = \"\\0repo-link\";\n\n/**\n * A non-file resource surfaced during collect — the repo link, an installed\n * plugin, etc. Toggleable and persisted exactly like a scanned file, keyed by\n * its sentinel. Everything attaches to the single stack (global) server-side.\n */\ninterface DetectedLink {\n\tkey: string;\n\tresource: Resource;\n\tlabel: string;\n}\n\nexport async function collectCommand(options: { global: boolean }) {\n\tintro(\"collect\");\n\n\tconst token = getToken();\n\tif (!token) {\n\t\tp.log.error(\n\t\t\t`Not authenticated. Run ${limeBold(\"npx @use-aistack/cli login\")} first.`,\n\t\t);\n\t\toutroError(\"not authenticated\");\n\t\tprocess.exit(1);\n\t}\n\n\tconst cwd = process.cwd();\n\tconst savedExcluded = getExcludedPaths(cwd);\n\n\tconst s = p.spinner();\n\ts.start(\"Scanning...\");\n\n\tconst localFiles = scanLocal(cwd);\n\tconst globalFiles = options.global ? scanGlobal() : [];\n\ts.stop(\"Scan complete\");\n\n\tif (localFiles.length === 0 && globalFiles.length === 0) {\n\t\tp.log.warn(\"No AI configuration files found.\");\n\t\toutroSkipped(\"nothing to collect\");\n\t\treturn;\n\t}\n\n\t// Apply saved exclusions\n\tconst allFiles = [...localFiles, ...globalFiles];\n\tlet selectedFiles = allFiles.filter(\n\t\t(f) => !savedExcluded.includes(f.relativePath),\n\t);\n\tlet excluded = allFiles.filter((f) => savedExcluded.includes(f.relativePath));\n\n\t// Show file counts\n\tp.log.info(\n\t\t`${lime(String(selectedFiles.length))} included${excluded.length > 0 ? ` · ${dim(String(excluded.length) + \" excluded\")}` : \"\"}`,\n\t);\n\n\t// Detect non-file links: the repo this lives in, installed Claude Code\n\t// plugins, MCP servers, hooks. Each is toggleable and included by default\n\t// unless previously deselected. All graceful no-ops.\n\tconst detectedLinks: DetectedLink[] = [];\n\tconst repoUrl = detectRepoUrl(cwd);\n\tif (repoUrl) {\n\t\tdetectedLinks.push({\n\t\t\tkey: REPO_LINK_KEY,\n\t\t\tresource: buildRepoLinkResource(repoUrl),\n\t\t\tlabel: `repo · ${repoNameFromCanonical(repoUrl)}`,\n\t\t});\n\t}\n\tfor (const resource of detectInstalledPlugins()) {\n\t\tdetectedLinks.push({\n\t\t\tkey: `\\0plugin:${resource.stableKey}`,\n\t\t\tresource,\n\t\t\tlabel: `plugin · ${resource.name}`,\n\t\t});\n\t}\n\tfor (const resource of detectMcpServers(cwd)) {\n\t\tdetectedLinks.push({\n\t\t\tkey: `\\0mcp:${resource.stableKey}`,\n\t\t\tresource,\n\t\t\tlabel: `mcp · ${resource.name}`,\n\t\t});\n\t}\n\tfor (const resource of detectHooks(cwd)) {\n\t\tdetectedLinks.push({\n\t\t\tkey: `\\0hook:${resource.stableKey}`,\n\t\t\tresource,\n\t\t\tlabel: `hook · ${resource.name}`,\n\t\t});\n\t}\n\n\tconst includedLinks = new Set(\n\t\tdetectedLinks\n\t\t\t.filter((l) => !savedExcluded.includes(l.key))\n\t\t\t.map((l) => l.key),\n\t);\n\tconst withLinks = (base: Resource[]): Resource[] => [\n\t\t...base,\n\t\t...detectedLinks\n\t\t\t.filter((l) => includedLinks.has(l.key))\n\t\t\t.map((l) => l.resource),\n\t];\n\n\t// Classify selected files\n\tlet allResources = withLinks(classify(selectedFiles));\n\n\t// Fetch the existing stack and diff against its resources.\n\tlet existingStack: Awaited<ReturnType<typeof stackGet>> = null;\n\ttry {\n\t\texistingStack = await stackGet(token);\n\t} catch (err) {\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\toutroError(\"error\");\n\t\tprocess.exit(1);\n\t}\n\n\t// Show file list or diff\n\tif (existingStack) {\n\t\tconst diff = diffResources(allResources, existingStack.resources);\n\t\tconst changeCount = diff.added + diff.changed + diff.removed;\n\n\t\tif (changeCount === 0) {\n\t\t\tp.log.info(\"No changes since last collect.\");\n\t\t\toutroSkipped(\"nothing to upload\");\n\t\t\treturn;\n\t\t}\n\n\t\tdivider();\n\t\tsection(\"changes\");\n\t\tlines(\n\t\t\tdiff.details.map((f) => {\n\t\t\t\tif (f.status === \"added\") return lime(`+ ${f.name}`);\n\t\t\t\tif (f.status === \"changed\") return yellow(`~ ${f.name}`);\n\t\t\t\treturn red(`- ${f.name}`);\n\t\t\t}),\n\t\t);\n\t\tif (diff.unchanged > 0) {\n\t\t\tlines([dim(`${diff.unchanged} unchanged`)]);\n\t\t}\n\t\tdivider();\n\t} else {\n\t\tconst local = selectedFiles.filter((f) => f.source === \"local\");\n\t\tconst global = selectedFiles.filter((f) => f.source === \"global\");\n\n\t\tif (local.length > 0) {\n\t\t\tp.log.step(`${bold(\"LOCAL\")} ${dim(String(local.length))}`);\n\t\t\tdivider();\n\t\t\tfor (const [type, files] of groupByType(local)) {\n\t\t\t\tlines([`${lime(type.toUpperCase())} ${dim(`${files.length}`)}`]);\n\t\t\t\tlines(files.map((f) => dim(` ${f.relativePath}`)));\n\t\t\t}\n\t\t\tdivider();\n\t\t}\n\t\tif (global.length > 0) {\n\t\t\tp.log.step(`${bold(\"GLOBAL\")} ${dim(String(global.length))}`);\n\t\t\tdivider();\n\t\t\tfor (const [type, files] of groupByType(global)) {\n\t\t\t\tlines([`${lime(type.toUpperCase())} ${dim(`${files.length}`)}`]);\n\t\t\t\tlines(files.map((f) => dim(` ${f.relativePath}`)));\n\t\t\t}\n\t\t\tdivider();\n\t\t}\n\t\tconst shownLinks = detectedLinks.filter((l) => includedLinks.has(l.key));\n\t\tif (shownLinks.length > 0) {\n\t\t\tp.log.step(`${bold(\"LINKS\")} ${dim(String(shownLinks.length))}`);\n\t\t\tdivider();\n\t\t\tlines(shownLinks.map((l) => dim(` ${l.label}`)));\n\t\t\tdivider();\n\t\t}\n\t}\n\n\t// Action: upload, customize, or cancel\n\tconst action = await p.select({\n\t\tmessage: existingStack\n\t\t\t? \"Upload changes?\"\n\t\t\t: `Upload ${bold(String(selectedFiles.length))} files to your stack?`,\n\t\toptions: [\n\t\t\t{ value: \"upload\", label: \"Upload\" },\n\t\t\t{ value: \"customize\", label: \"Select files\" },\n\t\t\t{ value: \"cancel\", label: \"Cancel\" },\n\t\t],\n\t});\n\n\tif (p.isCancel(action) || action === \"cancel\") {\n\t\toutroCancel();\n\t\tprocess.exit(0);\n\t}\n\n\tif (action === \"customize\") {\n\t\tconst linkOptions = detectedLinks.map((l) => ({\n\t\t\tvalue: l.key,\n\t\t\tlabel: l.label,\n\t\t\thint: \"link\",\n\t\t}));\n\t\tconst selected = await p.multiselect({\n\t\t\tmessage: \"Select files to include:\",\n\t\t\toptions: [\n\t\t\t\t...linkOptions,\n\t\t\t\t...allFiles.map((f) => ({\n\t\t\t\t\tvalue: f.relativePath,\n\t\t\t\t\tlabel: f.relativePath,\n\t\t\t\t\thint: `${f.type}${f.source === \"global\" ? \" · global\" : \"\"}`,\n\t\t\t\t})),\n\t\t\t],\n\t\t\tinitialValues: [\n\t\t\t\t...detectedLinks\n\t\t\t\t\t.filter((l) => includedLinks.has(l.key))\n\t\t\t\t\t.map((l) => l.key),\n\t\t\t\t...selectedFiles.map((f) => f.relativePath),\n\t\t\t],\n\t\t});\n\n\t\tif (p.isCancel(selected)) {\n\t\t\toutroCancel();\n\t\t\tprocess.exit(0);\n\t\t}\n\n\t\tconst selectedSet = new Set(selected as string[]);\n\t\tselectedFiles = allFiles.filter((f) => selectedSet.has(f.relativePath));\n\t\texcluded = allFiles.filter((f) => !selectedSet.has(f.relativePath));\n\t\tincludedLinks.clear();\n\t\tfor (const l of detectedLinks) {\n\t\t\tif (selectedSet.has(l.key)) includedLinks.add(l.key);\n\t\t}\n\t\tallResources = withLinks(classify(selectedFiles));\n\n\t\tif (selectedFiles.length === 0 && includedLinks.size === 0) {\n\t\t\tp.log.warn(\"No files selected.\");\n\t\t\toutroSkipped(\"nothing to collect\");\n\t\t\tprocess.exit(0);\n\t\t}\n\t}\n\n\ts.start(\"Uploading...\");\n\ttry {\n\t\tconst result = await stackCollect(token, { resources: allResources });\n\t\ts.stop(lime(\"Uploaded\"));\n\t\tconst excludedKeys = excluded.map((f) => f.relativePath);\n\t\tfor (const l of detectedLinks) {\n\t\t\tif (!includedLinks.has(l.key)) excludedKeys.push(l.key);\n\t\t}\n\t\tsaveExcludedPaths(cwd, excludedKeys);\n\t\tp.log.success(dim(result.url));\n\t\toutro(lime(\"done\"));\n\t} catch (err) {\n\t\ts.stop(\"Upload failed\");\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\toutroError(\"upload failed\");\n\t\tprocess.exit(1);\n\t}\n}\n\nconst TYPE_ORDER = [\n\t\"config\",\n\t\"prompt\",\n\t\"rule\",\n\t\"command\",\n\t\"skill\",\n\t\"subagent\",\n\t\"mcp\",\n\t\"hook\",\n\t\"custom\",\n];\n\nfunction groupByType(files: ScannedFile[]): Map<string, ScannedFile[]> {\n\tconst map = new Map<string, ScannedFile[]>();\n\tfor (const f of files) {\n\t\tconst existing = map.get(f.type) ?? [];\n\t\texisting.push(f);\n\t\tmap.set(f.type, existing);\n\t}\n\tconst sorted = new Map<string, ScannedFile[]>();\n\tfor (const type of TYPE_ORDER) {\n\t\tconst group = map.get(type);\n\t\tif (group) sorted.set(type, group);\n\t}\n\tfor (const [type, group] of map) {\n\t\tif (!sorted.has(type)) sorted.set(type, group);\n\t}\n\treturn sorted;\n}\n\ninterface DiffResult {\n\tadded: number;\n\tchanged: number;\n\tremoved: number;\n\tunchanged: number;\n\tdetails: Array<{ name: string; status: \"added\" | \"changed\" | \"removed\" }>;\n}\n\nexport function diffResources(\n\tcurrent: Resource[],\n\texisting: Resource[],\n): DiffResult {\n\tconst existingMap = new Map<string, string>();\n\tfor (const item of existing) {\n\t\tfor (const file of item.files ?? []) {\n\t\t\texistingMap.set(file.path ?? file.name, file.content);\n\t\t}\n\t}\n\n\tconst currentMap = new Map<string, string>();\n\tfor (const item of current) {\n\t\tfor (const file of item.files ?? []) {\n\t\t\tcurrentMap.set(file.path ?? file.name, file.content);\n\t\t}\n\t}\n\n\tconst details: DiffResult[\"details\"] = [];\n\tlet added = 0;\n\tlet changed = 0;\n\tlet unchanged = 0;\n\n\tfor (const [key, content] of currentMap) {\n\t\tconst prev = existingMap.get(key);\n\t\tif (prev === undefined) {\n\t\t\tadded++;\n\t\t\tdetails.push({ name: key, status: \"added\" });\n\t\t} else if (prev !== content) {\n\t\t\tchanged++;\n\t\t\tdetails.push({ name: key, status: \"changed\" });\n\t\t} else {\n\t\t\tunchanged++;\n\t\t}\n\t}\n\n\tlet removed = 0;\n\tfor (const key of existingMap.keys()) {\n\t\tif (!currentMap.has(key)) {\n\t\t\tremoved++;\n\t\t\tdetails.push({ name: key, status: \"removed\" });\n\t\t}\n\t}\n\n\t// Linked resources (GitHub repos AND package refs like MCP servers) carry no\n\t// files, so the file maps above can't see them. Diff them by stableKey —\n\t// unique for both `linked:<repo>:<path>` and `linked:pkg:<registry>:<id>` —\n\t// otherwise a link-only change is invisible and collect wrongly reports\n\t// \"nothing to upload\".\n\tconst linkLabel = (item: Resource): string => {\n\t\tif (item.upstream)\n\t\t\treturn `link: ${repoNameFromCanonical(item.upstream.repoUrl)}`;\n\t\tif (item.pkg) return `link: ${item.pkg.id}`;\n\t\treturn `link: ${item.name}`;\n\t};\n\tconst linkMap = (items: Resource[]): Map<string, Resource> => {\n\t\tconst map = new Map<string, Resource>();\n\t\tfor (const item of items) {\n\t\t\tif ((item.upstream || item.pkg) && !item.files?.length) {\n\t\t\t\tmap.set(item.stableKey, item);\n\t\t\t}\n\t\t}\n\t\treturn map;\n\t};\n\tconst existingLinks = linkMap(existing);\n\tconst currentLinks = linkMap(current);\n\tfor (const [key, item] of currentLinks) {\n\t\tif (!existingLinks.has(key)) {\n\t\t\tadded++;\n\t\t\tdetails.push({ name: linkLabel(item), status: \"added\" });\n\t\t}\n\t}\n\tfor (const [key, item] of existingLinks) {\n\t\tif (!currentLinks.has(key)) {\n\t\t\tremoved++;\n\t\t\tdetails.push({ name: linkLabel(item), status: \"removed\" });\n\t\t}\n\t}\n\n\treturn { added, changed, removed, unchanged, details };\n}\n","import { basename, dirname } from \"node:path\";\nimport type { Resource } from \"./api.js\";\nimport type { ScannedFile } from \"./scanner.js\";\nimport { computeStableKey } from \"./stableKey.js\";\n\nexport function classify(files: ScannedFile[]): Resource[] {\n\t// Group by {group, source, type, containing directory}\n\tconst groups = new Map<string, ScannedFile[]>();\n\tconst singletons: ScannedFile[] = [];\n\n\tconst singletonRoots = new Set([\n\t\t\".\",\n\t\t\"~\",\n\t\t\"~/.claude\",\n\t\t\"~/.cursor\",\n\t\t\"~/.continue\",\n\t\t\".claude\",\n\t\t\".cursor\",\n\t\t\".github\",\n\t]);\n\n\tfor (const file of files) {\n\t\tconst dir = dirname(file.relativePath);\n\t\tconst isSingleton = singletonRoots.has(dir);\n\n\t\tif (isSingleton) {\n\t\t\tsingletons.push(file);\n\t\t} else {\n\t\t\tconst key = `${file.group}:${file.source}:${file.type}:${dir}`;\n\t\t\tconst existing = groups.get(key) ?? [];\n\t\t\texisting.push(file);\n\t\t\tgroups.set(key, existing);\n\t\t}\n\t}\n\n\tconst items: Resource[] = [];\n\n\t// Singletons: one Resource per file\n\tfor (const file of singletons) {\n\t\tconst relPath = file.relativePath\n\t\t\t.replace(/^~\\/\\.[^/]+\\//, \"\")\n\t\t\t.replace(/^\\.[^/]+\\//, \"\");\n\t\titems.push({\n\t\t\ttype: file.type,\n\t\t\tname: file.relativePath,\n\t\t\tgroup: file.group,\n\t\t\tstableKey: computeStableKey(file.group, file.type, relPath),\n\t\t\tfiles: [\n\t\t\t\t{\n\t\t\t\t\tname: basename(file.relativePath),\n\t\t\t\t\tcontent: file.content,\n\t\t\t\t\tpath: file.relativePath,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\t}\n\n\t// Groups: one Resource per directory group\n\tfor (const [, groupFiles] of groups) {\n\t\tconst first = groupFiles[0];\n\t\tconst dir = dirname(first.relativePath);\n\t\tconst relPath = dir\n\t\t\t.replace(/^~\\/\\.claude\\//, \"\")\n\t\t\t.replace(/^\\.claude\\//, \"\")\n\t\t\t.replace(/^~\\/\\.cursor\\//, \"\")\n\t\t\t.replace(/^\\.cursor\\//, \"\");\n\t\tconst typeLabel =\n\t\t\tfirst.type === \"subagent\" ? \"subagents\" : `${first.type}s`;\n\n\t\titems.push({\n\t\t\ttype: first.type,\n\t\t\tname: dir,\n\t\t\tdescription: `${groupFiles.length} ${typeLabel}`,\n\t\t\tgroup: first.group,\n\t\t\tstableKey: computeStableKey(first.group, first.type, relPath),\n\t\t\tfiles: groupFiles.map((f) => ({\n\t\t\t\tname: basename(f.relativePath),\n\t\t\t\tcontent: f.content,\n\t\t\t\tpath: f.relativePath,\n\t\t\t})),\n\t\t});\n\t}\n\n\treturn items;\n}\n","export function computeStableKey(\n\tgroup: string,\n\ttype: string,\n\trelPath: string,\n): string {\n\treturn `${group}:${type}:${relPath}`;\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { BASE_URL } from \"./api.js\";\n\nconst CONFIG_DIR = join(homedir(), \".config\", \"aistack\");\nconst CREDENTIALS_FILE = join(CONFIG_DIR, \"credentials.json\");\n\ninterface ServerCredentials {\n\ttoken: string;\n\tuserId?: string;\n}\n\n/**\n * Credentials keyed by server URL (#61). Since hash-at-rest (#52) the server\n * stores only a hash, so this file holds the only plaintext copy of each\n * token. The old flat `{token, userId}` form let a localhost login overwrite\n * the prod token, which was unrecoverable. The map keeps one entry per server.\n */\ninterface CredentialsFile {\n\tservers: Record<string, ServerCredentials>;\n}\n\n/** Where a legacy flat token is assumed to come from. */\nconst DEFAULT_SERVER_URL = \"https://aistack.to\";\n\n/**\n * Read the credentials file and lift the legacy flat form into the map.\n *\n * A legacy token carries no record of which server issued it. It is assigned\n * to the default prod URL, not the caller's current server: every real flat\n * token came from prod, and keying it under a localhost caller would put it\n * exactly where the next localhost login overwrites it.\n */\nfunction readCredentials(file: string): {\n\tdata: CredentialsFile;\n\tlegacy: boolean;\n} {\n\tconst empty = { data: { servers: {} }, legacy: false };\n\tif (!existsSync(file)) return empty;\n\ttry {\n\t\tconst raw = JSON.parse(readFileSync(file, \"utf-8\"));\n\t\tif (!raw || typeof raw !== \"object\") return empty;\n\t\tif (raw.servers && typeof raw.servers === \"object\") {\n\t\t\treturn {\n\t\t\t\tdata: { servers: raw.servers as Record<string, ServerCredentials> },\n\t\t\t\tlegacy: false,\n\t\t\t};\n\t\t}\n\t\tif (typeof raw.token === \"string\" && raw.token) {\n\t\t\treturn {\n\t\t\t\tdata: {\n\t\t\t\t\tservers: {\n\t\t\t\t\t\t[DEFAULT_SERVER_URL]: { token: raw.token, userId: raw.userId },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tlegacy: true,\n\t\t\t};\n\t\t}\n\t\t// A cleared legacy file is `{}` — empty, but safe to rewrite.\n\t\treturn { data: { servers: {} }, legacy: true };\n\t} catch {\n\t\t// Do not rewrite an unreadable file. It may still hold a token that a\n\t\t// human can recover, and this file holds the only plaintext copy.\n\t\treturn empty;\n\t}\n}\n\nfunction writeCredentials(file: string, data: CredentialsFile): void {\n\tmkdirSync(dirname(file), { recursive: true });\n\twriteFileSync(file, JSON.stringify(data, null, 2));\n}\n\nexport function getToken(\n\tserverUrl: string = BASE_URL,\n\tfile: string = CREDENTIALS_FILE,\n): string | null {\n\tconst { data, legacy } = readCredentials(file);\n\tif (legacy) writeCredentials(file, data);\n\treturn data.servers[serverUrl]?.token ?? null;\n}\n\nexport function saveToken(\n\ttoken: string,\n\tuserId?: string,\n\tserverUrl: string = BASE_URL,\n\tfile: string = CREDENTIALS_FILE,\n): void {\n\tconst { data } = readCredentials(file);\n\tdata.servers[serverUrl] = { token, userId };\n\twriteCredentials(file, data);\n}\n\n/** Remove only the current server's entry. Other servers keep their tokens. */\nexport function clearToken(\n\tserverUrl: string = BASE_URL,\n\tfile: string = CREDENTIALS_FILE,\n): void {\n\tif (!existsSync(file)) return;\n\tconst { data } = readCredentials(file);\n\tdelete data.servers[serverUrl];\n\twriteCredentials(file, data);\n}\n\nconst SETTINGS_FILE = join(CONFIG_DIR, \"settings.json\");\n\n/**\n * Machine-local switches (#56). A separate file from credentials.json so a\n * login overwrite never resets an answered upsell, and clearing settings never\n * touches the token.\n */\nexport interface AutoSyncConfig {\n\t/** The standing opt-in. `sync --auto` publishes nothing when false. */\n\tenabled: boolean;\n\t/** Minimum hours between auto-sync attempts. Default 24. */\n\tfrequencyHours: number;\n}\n\n/** Bookkeeping the `sync --auto` runs write. Separate from the opt-in. */\nexport interface AutoSyncState {\n\t/** Epoch ms of the last attempt (success or failure). The freshness gate. */\n\tlastRunAt?: number;\n\tlastSuccessAt?: number;\n\t/** One line about the last run, shown on the next interactive sync. */\n\tlastResult?: string;\n\tconsecutiveFailures?: number;\n\t/** The 3-failure systemMessage went out. Reset on success. */\n\tfailureWarned?: boolean;\n}\n\nexport const DEFAULT_FREQUENCY_HOURS = 24;\n\nexport interface Settings {\n\t/** The post-sync connect-claude upsell was answered (either way). */\n\tconnectClaudeAnswered?: boolean;\n\t/** The post-sync auto-sync ask was answered (either way). */\n\tautoSyncAnswered?: boolean;\n\tautoSync?: AutoSyncConfig;\n\tautoSyncState?: AutoSyncState;\n}\n\nexport function getSettings(file: string = SETTINGS_FILE): Settings {\n\tif (!existsSync(file)) return {};\n\ttry {\n\t\tconst raw = JSON.parse(readFileSync(file, \"utf-8\"));\n\t\treturn raw && typeof raw === \"object\" ? (raw as Settings) : {};\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nexport function saveSettings(\n\tpatch: Partial<Settings>,\n\tfile: string = SETTINGS_FILE,\n): void {\n\tmkdirSync(dirname(file), { recursive: true });\n\twriteFileSync(\n\t\tfile,\n\t\tJSON.stringify({ ...getSettings(file), ...patch }, null, 2),\n\t);\n}\n\nconst PROJECTS_FILE = join(CONFIG_DIR, \"projects.json\");\n\ninterface ProjectEntry {\n\texcluded?: string[];\n}\n\ninterface ProjectsData {\n\t[directory: string]: ProjectEntry;\n}\n\nfunction readProjects(): ProjectsData {\n\tif (!existsSync(PROJECTS_FILE)) return {};\n\ttry {\n\t\tconst raw = JSON.parse(readFileSync(PROJECTS_FILE, \"utf-8\"));\n\t\t// Tolerate legacy entries: string values (oldest) and objects that still\n\t\t// carry a `name` field. Only `excluded` is read going forward.\n\t\tconst data: ProjectsData = {};\n\t\tfor (const [key, value] of Object.entries(raw)) {\n\t\t\tif (typeof value === \"string\") {\n\t\t\t\tdata[key] = {};\n\t\t\t} else if (value && typeof value === \"object\") {\n\t\t\t\tconst excluded = (value as { excluded?: string[] }).excluded;\n\t\t\t\tdata[key] = Array.isArray(excluded) ? { excluded } : {};\n\t\t\t}\n\t\t}\n\t\treturn data;\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction writeProjects(data: ProjectsData): void {\n\tmkdirSync(CONFIG_DIR, { recursive: true });\n\twriteFileSync(PROJECTS_FILE, JSON.stringify(data, null, 2));\n}\n\nexport function getExcludedPaths(directory: string): string[] {\n\treturn readProjects()[directory]?.excluded ?? [];\n}\n\nexport function saveExcludedPaths(directory: string, excluded: string[]): void {\n\tconst data = readProjects();\n\tdata[directory] = {\n\t\texcluded: excluded.length > 0 ? excluded : undefined,\n\t};\n\twriteProjects(data);\n}\n","import { execFileSync } from \"node:child_process\";\nimport type { Resource } from \"./api.js\";\nimport {\n\tcanonicalizeRepoUrl,\n\tnormalizeUpstreamPath,\n\trepoNameFromCanonical,\n} from \"./github-repo.js\";\n\n/**\n * Returns the raw `origin` remote URL for a working directory, or null when it\n * can't be determined. Injectable so `detectRepoUrl` stays unit-testable\n * without spawning git.\n */\nexport type GitRemoteRunner = (cwd: string) => string | null;\n\nexport const defaultGitRemoteRunner: GitRemoteRunner = (cwd) => {\n\ttry {\n\t\t// argv form (no shell) — git walks up to the repo root itself, and\n\t\t// stderr is swallowed so \"not a git repository\" never leaks into the\n\t\t// CLI's output. git missing / no repo / no origin all throw → null.\n\t\treturn execFileSync(\"git\", [\"-C\", cwd, \"remote\", \"get-url\", \"origin\"], {\n\t\t\tencoding: \"utf-8\",\n\t\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t\t}).trim();\n\t} catch {\n\t\treturn null;\n\t}\n};\n\n/**\n * Detect the canonical GitHub repo URL for `cwd`, or null. Non-GitHub origins\n * (GitLab, Bitbucket, …) canonicalize to null, so this is a graceful no-op\n * outside of GitHub repos.\n */\nexport function detectRepoUrl(\n\tcwd: string,\n\trun: GitRemoteRunner = defaultGitRemoteRunner,\n): string | null {\n\tconst raw = run(cwd);\n\tif (!raw) return null;\n\treturn canonicalizeRepoUrl(raw);\n}\n\nexport interface LinkSpec {\n\t/** Canonical GitHub URL (https://github.com/owner/repo). */\n\tcanonical: string;\n\t/** Optional subpath within the repo. */\n\tpath?: string;\n\tname: string;\n\ttype: string;\n\tgroup: string;\n\t/** Optional pinned commit, stored as upstream.lastCommitSha. */\n\tsha?: string;\n}\n\n/**\n * Build a linked-resource payload. Mirrors the web `linkResource` mutation: no\n * files (upstream presence is the storage discriminator) and the exact\n * `linked:${canonical}:${normPath}` stableKey so the web unlink UI — which\n * matches by stableKey — recognizes it. `path`/`lastCommitSha` are omitted when\n * empty so the by_upstream dedup index matches at both write and query.\n */\nexport function buildLinkResource(spec: LinkSpec): Resource {\n\tconst normPath = normalizeUpstreamPath(spec.path);\n\treturn {\n\t\ttype: spec.type,\n\t\tname: spec.name,\n\t\tgroup: spec.group,\n\t\tstableKey: `linked:${spec.canonical}:${normPath}`,\n\t\tupstream: {\n\t\t\trepoUrl: spec.canonical,\n\t\t\t...(normPath ? { path: normPath } : {}),\n\t\t\t...(spec.sha ? { lastCommitSha: spec.sha } : {}),\n\t\t},\n\t};\n}\n\n/** The repo this project lives in: a GitHub link (stack-owned server-side). */\nexport function buildRepoLinkResource(canonical: string): Resource {\n\treturn buildLinkResource({\n\t\tcanonical,\n\t\tname: repoNameFromCanonical(canonical),\n\t\ttype: \"custom\",\n\t\tgroup: \"generic\",\n\t});\n}\n","/**\n * Trimmed copy of `src/lib/github-repo.ts` — the CANONICAL parser, whose\n * `github-repo.test.ts` is the canonical test table. Copied (not imported)\n * because the CLI ships as an independent npm package and its tsconfig\n * (`rootDir: \"src\"` + `declaration: true`) forbids cross-rootDir imports.\n * Keep these functions in sync with the canonical source.\n *\n * Only the pieces the CLI needs are included: `parseRepo`,\n * `canonicalizeRepoUrl`, `repoNameFromCanonical`, and `normalizeUpstreamPath`\n * (a null from `canonicalizeRepoUrl` is the CLI's graceful-skip signal, so\n * `isGithubRepoUrl` is intentionally omitted).\n */\n\nfunction isGithubHost(host: string): boolean {\n\tconst h = host.toLowerCase();\n\treturn h === \"github.com\" || h === \"www.github.com\";\n}\n\nexport function parseRepo(\n\tinput: string,\n): { owner: string; repo: string } | null {\n\tconst trimmed = input.trim();\n\tif (!trimmed) return null;\n\n\t// SCP-like form `git@host:owner/repo`: take the host and the path after the\n\t// colon. Otherwise strip the scheme, then split the leading host off the path.\n\tconst scpMatch = trimmed.match(/^[^@]+@([^:]+):(.+)$/);\n\tlet host: string;\n\tlet withoutHost: string;\n\tif (scpMatch) {\n\t\thost = scpMatch[1];\n\t\twithoutHost = scpMatch[2];\n\t} else {\n\t\tconst withoutScheme = trimmed.replace(/^[a-z]+:\\/\\//i, \"\");\n\t\tconst slash = withoutScheme.indexOf(\"/\");\n\t\tif (slash === -1) return null;\n\t\thost = withoutScheme.slice(0, slash);\n\t\twithoutHost = withoutScheme.slice(slash + 1);\n\t}\n\tif (!isGithubHost(host)) return null;\n\n\t// Drop any query string or anchor, then split into path segments.\n\tconst pathPart = withoutHost.replace(/[?#].*$/, \"\");\n\tconst segments = pathPart.split(\"/\").filter(Boolean);\n\n\tconst owner = segments[0];\n\tconst repo = segments[1]?.replace(/\\.git$/, \"\");\n\tif (!owner || !repo) return null;\n\n\treturn { owner: owner.toLowerCase(), repo: repo.toLowerCase() };\n}\n\nexport function canonicalizeRepoUrl(input: string): string | null {\n\tconst parsed = parseRepo(input);\n\tif (!parsed) return null;\n\treturn `https://github.com/${parsed.owner}/${parsed.repo}`;\n}\n\nexport function repoNameFromCanonical(canonical: string): string {\n\treturn parseRepo(canonical)?.repo ?? \"\";\n}\n\nexport function normalizeUpstreamPath(path: string | undefined): string {\n\tif (!path) return \"\";\n\treturn path.split(\"/\").filter(Boolean).join(\"/\");\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Resource } from \"./api.js\";\n\n/**\n * Extract hooks defined inline in Claude Code settings as discrete `hook`\n * resources — one per event (PreToolUse, PostToolUse, …). Without this they\n * only ride inside the collected settings.json config blob and never surface as\n * first-class hooks.\n *\n * These are HOSTED resources (the event's config block is the content), so they\n * participate in the normal file-based diff. They intentionally duplicate data\n * also present in the settings.json resource; the distinct `hooks:` stableKeys\n * mean no collision, and first-class visibility was the deliberate tradeoff.\n */\n\ninterface SettingsFile {\n\thooks?: Record<string, unknown>;\n}\n\nfunction readJson<T>(path: string): T | null {\n\ttry {\n\t\tif (!existsSync(path)) return null;\n\t\treturn JSON.parse(readFileSync(path, \"utf-8\")) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction hooksFrom(\n\tpath: string,\n\tsource: \"local\" | \"global\",\n\tout: Resource[],\n\tseen: Set<string>,\n) {\n\tconst hooks = readJson<SettingsFile>(path)?.hooks;\n\tif (!hooks || typeof hooks !== \"object\") return;\n\tfor (const [event, config] of Object.entries(hooks)) {\n\t\tconst stableKey = `hooks:${source}:${event}`;\n\t\tif (seen.has(stableKey)) continue;\n\t\tseen.add(stableKey);\n\t\tout.push({\n\t\t\ttype: \"hook\",\n\t\t\tname: event,\n\t\t\tgroup: \"claude-code\",\n\t\t\tstableKey,\n\t\t\tfiles: [\n\t\t\t\t{\n\t\t\t\t\tname: `${event}.json`,\n\t\t\t\t\tcontent: JSON.stringify(config, null, 2),\n\t\t\t\t\tpath: `hooks/${event}.json`,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\t}\n}\n\n/**\n * Detect inline hooks from project settings (`.claude/settings.json` +\n * `.claude/settings.local.json`) and global settings (`~/.claude/settings.json`).\n * Project settings win over the `.local` override on the same event.\n */\nexport function detectHooks(cwd: string, home: string = homedir()): Resource[] {\n\tconst out: Resource[] = [];\n\tconst seen = new Set<string>();\n\thooksFrom(join(cwd, \".claude\", \"settings.json\"), \"local\", out, seen);\n\thooksFrom(join(cwd, \".claude\", \"settings.local.json\"), \"local\", out, seen);\n\thooksFrom(join(home, \".claude\", \"settings.json\"), \"global\", out, seen);\n\treturn out;\n}\n","import { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\nimport { parse as parseToml } from \"smol-toml\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { Resource } from \"./api.js\";\n\n/**\n * Detect configured MCP servers and resolve each to a `pkg` reference (its\n * package identity), parsed from the launch `command`/`args` — npm/PyPI/OCI for\n * stdio servers, or a URL for remote (http/sse) servers. `env` is intentionally\n * dropped (it carries secrets), so this is a safer representation than uploading\n * the raw config file.\n */\n\nexport interface McpServerConfig {\n\tcommand?: string;\n\targs?: string[];\n\ttype?: string;\n\ttransport?: string;\n\turl?: string;\n}\n\nexport interface PkgRef {\n\tregistry: \"npm\" | \"pypi\" | \"oci\" | \"url\";\n\tid: string;\n\tversion?: string;\n\ttransport?: \"stdio\" | \"http\" | \"sse\";\n}\n\nfunction commandName(cmd: string): string {\n\treturn cmd.replace(/\\\\/g, \"/\").split(\"/\").pop() ?? cmd;\n}\n\n/** Split an npm/PyPI spec into id + version, handling scoped npm (@scope/n@v). */\nfunction splitVersion(spec: string): { id: string; version?: string } {\n\tconst at = spec.indexOf(\"@\", spec.startsWith(\"@\") ? 1 : 0);\n\tif (at <= 0) return { id: spec };\n\treturn { id: spec.slice(0, at), version: spec.slice(at + 1) || undefined };\n}\n\n/** First arg that isn't a flag (and isn't in `skip`). */\nfunction firstPositional(args: string[], skip = 0): string | undefined {\n\tfor (const a of args.slice(skip)) {\n\t\tif (!a.startsWith(\"-\")) return a;\n\t}\n\treturn undefined;\n}\n\n// docker/podman flags that consume the following token (so it isn't the image).\nconst CONTAINER_VALUE_FLAGS = new Set([\n\t\"-e\",\n\t\"--env\",\n\t\"-v\",\n\t\"--volume\",\n\t\"-p\",\n\t\"--publish\",\n\t\"-w\",\n\t\"--workdir\",\n\t\"--name\",\n\t\"--mount\",\n\t\"--network\",\n\t\"-u\",\n\t\"--user\",\n\t\"-l\",\n\t\"--label\",\n]);\n\nfunction containerImage(args: string[]): string | undefined {\n\tconst runIdx = args.indexOf(\"run\");\n\tconst rest = runIdx >= 0 ? args.slice(runIdx + 1) : args;\n\tfor (let i = 0; i < rest.length; i++) {\n\t\tconst a = rest[i];\n\t\tif (a.startsWith(\"-\")) {\n\t\t\tif (CONTAINER_VALUE_FLAGS.has(a) && !a.includes(\"=\")) i++;\n\t\t\tcontinue;\n\t\t}\n\t\treturn a; // first positional after `run` is the image\n\t}\n\treturn undefined;\n}\n\n/** Split a container image ref into id + tag (ignoring a registry host:port). */\nfunction splitImageTag(image: string): { id: string; version?: string } {\n\tconst colon = image.lastIndexOf(\":\");\n\tif (colon > 0 && !image.slice(colon + 1).includes(\"/\")) {\n\t\treturn { id: image.slice(0, colon), version: image.slice(colon + 1) };\n\t}\n\treturn { id: image };\n}\n\n/** Parse a single MCP server config into a package reference, or null. */\nexport function parseMcpPackage(server: McpServerConfig): PkgRef | null {\n\t// Remote server: a URL endpoint (http/sse).\n\tif (server.url) {\n\t\tconst t = (server.type ?? server.transport ?? \"\").toLowerCase();\n\t\treturn {\n\t\t\tregistry: \"url\",\n\t\t\tid: server.url,\n\t\t\ttransport: t === \"sse\" ? \"sse\" : \"http\",\n\t\t};\n\t}\n\n\tconst command = server.command ? commandName(server.command) : \"\";\n\tif (!command) return null;\n\tconst args = server.args ?? [];\n\n\t// npm-family runners.\n\tif (command === \"npx\" || command === \"bunx\" || command === \"pnpx\") {\n\t\tconst spec = firstPositional(args);\n\t\treturn spec\n\t\t\t? { registry: \"npm\", ...splitVersion(spec), transport: \"stdio\" }\n\t\t\t: null;\n\t}\n\tif ((command === \"pnpm\" || command === \"yarn\") && args[0] === \"dlx\") {\n\t\tconst spec = firstPositional(args, 1);\n\t\treturn spec\n\t\t\t? { registry: \"npm\", ...splitVersion(spec), transport: \"stdio\" }\n\t\t\t: null;\n\t}\n\n\t// Python-family runners.\n\tif (command === \"uvx\") {\n\t\tconst spec = firstPositional(args);\n\t\treturn spec\n\t\t\t? { registry: \"pypi\", ...splitVersion(spec), transport: \"stdio\" }\n\t\t\t: null;\n\t}\n\tif (command === \"pipx\" && args[0] === \"run\") {\n\t\tconst spec = firstPositional(args, 1);\n\t\treturn spec\n\t\t\t? { registry: \"pypi\", ...splitVersion(spec), transport: \"stdio\" }\n\t\t\t: null;\n\t}\n\tif (command === \"uv\" && args[0] === \"tool\" && args[1] === \"run\") {\n\t\tconst spec = firstPositional(args, 2);\n\t\treturn spec\n\t\t\t? { registry: \"pypi\", ...splitVersion(spec), transport: \"stdio\" }\n\t\t\t: null;\n\t}\n\tif (/^python[0-9.]*$/.test(command)) {\n\t\tconst i = args.indexOf(\"-m\");\n\t\tconst mod = i >= 0 ? args[i + 1] : undefined;\n\t\treturn mod ? { registry: \"pypi\", id: mod, transport: \"stdio\" } : null;\n\t}\n\n\t// Container runners.\n\tif (command === \"docker\" || command === \"podman\") {\n\t\tconst image = containerImage(args);\n\t\tif (!image) return null;\n\t\treturn { registry: \"oci\", ...splitImageTag(image), transport: \"stdio\" };\n\t}\n\n\t// node/deno/bun running a local script, or an unknown command → skip.\n\treturn null;\n}\n\n/** Build a `type:\"mcp\"` linked resource from a parsed package reference. */\nexport function buildMcpResource(\n\tname: string,\n\tgroup: string,\n\tpkg: PkgRef,\n): Resource {\n\treturn {\n\t\ttype: \"mcp\",\n\t\tname,\n\t\tgroup,\n\t\tstableKey: `linked:pkg:${pkg.registry}:${pkg.id}`,\n\t\tpkg,\n\t};\n}\n\nfunction readText(path: string): string | null {\n\ttry {\n\t\tif (!existsSync(path)) return null;\n\t\treturn readFileSync(path, \"utf-8\");\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction readParsed<T>(\n\tpath: string,\n\tparse: (raw: string) => unknown,\n): T | null {\n\tconst raw = readText(path);\n\tif (raw === null) return null;\n\ttry {\n\t\treturn parse(raw) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction readJson<T>(path: string): T | null {\n\treturn readParsed<T>(path, JSON.parse);\n}\nfunction readYaml<T>(path: string): T | null {\n\treturn readParsed<T>(path, parseYaml);\n}\nfunction readToml<T>(path: string): T | null {\n\treturn readParsed<T>(path, parseToml);\n}\n\ntype ServerMap = Record<string, McpServerConfig> | undefined;\ninterface McpFile {\n\tmcpServers?: ServerMap;\n\tservers?: ServerMap; // VS Code uses `servers`\n}\ninterface ClaudeJson {\n\tmcpServers?: ServerMap;\n\tprojects?: Record<string, { mcpServers?: ServerMap }>;\n}\n// Continue uses a LIST under mcpServers; Codex (TOML) uses `mcp_servers`.\ninterface ContinueYaml {\n\tmcpServers?: Array<{ name?: string } & McpServerConfig>;\n}\ninterface CodexToml {\n\tmcp_servers?: Record<string, McpServerConfig>;\n}\n\n/** Normalize Continue's list form to the common name→config map. */\nfunction continueListToMap(file: ContinueYaml | null): ServerMap {\n\tif (!file?.mcpServers?.length) return undefined;\n\tconst map: Record<string, McpServerConfig> = {};\n\tfile.mcpServers.forEach((s, i) => {\n\t\tmap[s.name ?? `server-${i}`] = s;\n\t});\n\treturn map;\n}\n\n/** Per-OS VS Code globalStorage bases (+ Code-OSS/VSCodium variants). */\nfunction vscodeGlobalStorageBases(home: string): string[] {\n\tconst apps = [\"Code\", \"Code - OSS\", \"VSCodium\"];\n\tlet root: string;\n\tif (platform() === \"darwin\") {\n\t\troot = join(home, \"Library\", \"Application Support\");\n\t} else if (platform() === \"win32\") {\n\t\troot = process.env.APPDATA ?? join(home, \"AppData\", \"Roaming\");\n\t} else {\n\t\troot = process.env.XDG_CONFIG_HOME ?? join(home, \".config\");\n\t}\n\treturn apps.map((app) => join(root, app, \"User\", \"globalStorage\"));\n}\n\n/**\n * Read MCP server configs across the known tool locations and return one\n * `type:\"mcp\"` pkg-link resource per server, deduped by package identity.\n * Project-level configs win over global ones on the same identity.\n */\nexport function detectMcpServers(\n\tcwd: string,\n\thome: string = homedir(),\n): Resource[] {\n\tconst out: Resource[] = [];\n\tconst seen = new Set<string>();\n\tconst add = (servers: ServerMap, group: string) => {\n\t\tfor (const [name, cfg] of Object.entries(servers ?? {})) {\n\t\t\tconst pkg = parseMcpPackage(cfg);\n\t\t\tif (!pkg) continue;\n\t\t\tconst resource = buildMcpResource(name, group, pkg);\n\t\t\tif (seen.has(resource.stableKey)) continue;\n\t\t\tseen.add(resource.stableKey);\n\t\t\tout.push(resource);\n\t\t}\n\t};\n\n\t// Project configs first (so they win dedup over global).\n\tadd(readJson<McpFile>(join(cwd, \".mcp.json\"))?.mcpServers, \"claude-code\");\n\tadd(readJson<McpFile>(join(cwd, \"mcp.json\"))?.mcpServers, \"generic\");\n\tadd(\n\t\treadJson<McpFile>(join(cwd, \".cursor\", \"mcp.json\"))?.mcpServers,\n\t\t\"cursor\",\n\t);\n\tadd(readJson<McpFile>(join(cwd, \".vscode\", \"mcp.json\"))?.servers, \"generic\");\n\tadd(\n\t\treadJson<McpFile>(join(cwd, \"claude_desktop_config.json\"))?.mcpServers,\n\t\t\"claude-desktop\",\n\t);\n\n\t// Continue (project): a list per YAML file under .continue/mcpServers/.\n\tfor (const file of listYamlFiles(join(cwd, \".continue\", \"mcpServers\"))) {\n\t\tadd(continueListToMap(readYaml<ContinueYaml>(file)), \"continue\");\n\t}\n\t// Roo (project).\n\tadd(readJson<McpFile>(join(cwd, \".roo\", \"mcp.json\"))?.mcpServers, \"roo\");\n\n\t// --- Global / stack-scoped: user-level tool configs ---\n\tconst claudeJson = readJson<ClaudeJson>(join(home, \".claude.json\"));\n\tadd(claudeJson?.projects?.[cwd]?.mcpServers, \"claude-code\");\n\tadd(claudeJson?.mcpServers, \"claude-code\");\n\tadd(\n\t\treadJson<McpFile>(join(home, \".cursor\", \"mcp.json\"))?.mcpServers,\n\t\t\"cursor\",\n\t);\n\t// Windsurf (global only).\n\tadd(\n\t\treadJson<McpFile>(join(home, \".codeium\", \"windsurf\", \"mcp_config.json\"))\n\t\t\t?.mcpServers,\n\t\t\"windsurf\",\n\t);\n\t// Cline + Roo: VS Code extension globalStorage (OS-specific base).\n\tfor (const base of vscodeGlobalStorageBases(home)) {\n\t\tadd(\n\t\t\treadJson<McpFile>(\n\t\t\t\tjoin(\n\t\t\t\t\tbase,\n\t\t\t\t\t\"saoudrizwan.claude-dev\",\n\t\t\t\t\t\"settings\",\n\t\t\t\t\t\"cline_mcp_settings.json\",\n\t\t\t\t),\n\t\t\t)?.mcpServers,\n\t\t\t\"cline\",\n\t\t);\n\t\tadd(\n\t\t\treadJson<McpFile>(\n\t\t\t\tjoin(\n\t\t\t\t\tbase,\n\t\t\t\t\t\"rooveterinaryinc.roo-cline\",\n\t\t\t\t\t\"settings\",\n\t\t\t\t\t\"mcp_settings.json\",\n\t\t\t\t),\n\t\t\t)?.mcpServers,\n\t\t\t\"roo\",\n\t\t);\n\t}\n\t// Continue (global).\n\tfor (const file of listYamlFiles(join(home, \".continue\", \"mcpServers\"))) {\n\t\tadd(continueListToMap(readYaml<ContinueYaml>(file)), \"continue\");\n\t}\n\t// Gemini CLI (global).\n\tadd(\n\t\treadJson<McpFile>(join(home, \".gemini\", \"settings.json\"))?.mcpServers,\n\t\t\"gemini\",\n\t);\n\t// Codex CLI (global, TOML).\n\tadd(\n\t\treadToml<CodexToml>(join(home, \".codex\", \"config.toml\"))?.mcp_servers,\n\t\t\"codex\",\n\t);\n\n\treturn out;\n}\n\n/** List `*.yaml`/`*.yml` files in a directory (empty if absent). */\nfunction listYamlFiles(dir: string): string[] {\n\ttry {\n\t\treturn readdirSync(dir)\n\t\t\t.filter((f) => f.endsWith(\".yaml\") || f.endsWith(\".yml\"))\n\t\t\t.map((f) => join(dir, f));\n\t} catch {\n\t\treturn [];\n\t}\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Resource } from \"./api.js\";\nimport { buildLinkResource } from \"./git.js\";\nimport { canonicalizeRepoUrl } from \"./github-repo.js\";\n\n/**\n * Detect installed Claude Code plugins from the on-disk registry and resolve\n * each to a GitHub link pointing at its TRUE upstream source (not the\n * aggregator marketplace), attached at stack scope (the user's toolchain).\n *\n * Registry shape (~/.claude/plugins/):\n * installed_plugins.json → { plugins: { \"<name>@<marketplace>\": [{ gitCommitSha, version, ... }] } }\n * known_marketplaces.json → { \"<marketplace>\": { source: { repo }, installLocation } }\n * <installLocation>/.claude-plugin/marketplace.json → { plugins: [{ name, source, ... }] }\n */\n\ninterface InstalledEntry {\n\tscope?: string;\n\tversion?: string;\n\tgitCommitSha?: string;\n}\n\nexport interface InstalledPlugins {\n\tplugins?: Record<string, InstalledEntry[]>;\n}\n\nexport interface KnownMarketplace {\n\tsource?: { source?: string; repo?: string; url?: string };\n\tinstallLocation?: string;\n}\n\nexport type KnownMarketplaces = Record<string, KnownMarketplace>;\n\n/** A plugin's source in marketplace.json — polymorphic. */\ntype PluginSource =\n\t| string\n\t| {\n\t\t\tsource?: string;\n\t\t\turl?: string;\n\t\t\tpath?: string;\n\t\t\tref?: string;\n\t\t\tsha?: string;\n\t };\n\ninterface ManifestPlugin {\n\tname: string;\n\tsource?: PluginSource;\n\trepository?: string;\n\thomepage?: string;\n}\n\nexport interface Manifest {\n\tplugins?: ManifestPlugin[];\n}\n\nfunction marketplaceRepoUrl(mp: KnownMarketplace | undefined): string | null {\n\tconst src = mp?.source;\n\tif (!src) return null;\n\tif (src.repo) return `https://github.com/${src.repo}`;\n\treturn src.url ?? null;\n}\n\n/** Resolve a plugin entry's source to a repo URL (+ optional subpath / sha). */\nfunction resolveSource(\n\tentry: ManifestPlugin,\n\tmpRepoUrl: string | null,\n): { url: string; path?: string; sha?: string } | null {\n\tconst src = entry.source;\n\tif (typeof src === \"string\") {\n\t\tif (!mpRepoUrl) return null;\n\t\tconst path = src.replace(/^\\.\\//, \"\").replace(/\\/+$/, \"\");\n\t\treturn { url: mpRepoUrl, path: path || undefined };\n\t}\n\tif (src && typeof src === \"object\" && src.url) {\n\t\treturn { url: src.url, path: src.path, sha: src.sha };\n\t}\n\tconst fallback = entry.repository ?? entry.homepage ?? mpRepoUrl;\n\treturn fallback ? { url: fallback } : null;\n}\n\n/** Pure: map the parsed registry + manifests to plugin link resources. */\nexport function resolvePluginLinks(\n\tinstalled: InstalledPlugins,\n\tmarketplaces: KnownMarketplaces,\n\tmanifests: Record<string, Manifest>,\n): Resource[] {\n\tconst out: Resource[] = [];\n\tfor (const [key, entries] of Object.entries(installed.plugins ?? {})) {\n\t\tconst at = key.lastIndexOf(\"@\");\n\t\tif (at <= 0) continue;\n\t\tconst pluginName = key.slice(0, at);\n\t\tconst marketplace = key.slice(at + 1);\n\n\t\tconst mpRepoUrl = marketplaceRepoUrl(marketplaces[marketplace]);\n\t\tconst entry = manifests[marketplace]?.plugins?.find(\n\t\t\t(p) => p.name === pluginName,\n\t\t);\n\t\tif (!entry) continue;\n\n\t\tconst resolved = resolveSource(entry, mpRepoUrl);\n\t\tif (!resolved) continue;\n\n\t\tconst canonical = canonicalizeRepoUrl(resolved.url);\n\t\tif (!canonical) continue; // non-GitHub source → skip (graceful)\n\n\t\tout.push(\n\t\t\tbuildLinkResource({\n\t\t\t\tcanonical,\n\t\t\t\tpath: resolved.path,\n\t\t\t\tname: pluginName,\n\t\t\t\ttype: \"plugin\",\n\t\t\t\tgroup: \"claude-code\",\n\t\t\t\tsha: resolved.sha ?? entries[0]?.gitCommitSha,\n\t\t\t}),\n\t\t);\n\t}\n\treturn out;\n}\n\nfunction readJson<T>(path: string): T | null {\n\ttry {\n\t\tif (!existsSync(path)) return null;\n\t\treturn JSON.parse(readFileSync(path, \"utf-8\")) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** IO wrapper: read the registry + manifests, return plugin link resources. */\nexport function detectInstalledPlugins(\n\tpluginsDir: string = join(homedir(), \".claude\", \"plugins\"),\n): Resource[] {\n\tconst installed = readJson<InstalledPlugins>(\n\t\tjoin(pluginsDir, \"installed_plugins.json\"),\n\t);\n\tif (!installed?.plugins) return [];\n\n\tconst marketplaces =\n\t\treadJson<KnownMarketplaces>(join(pluginsDir, \"known_marketplaces.json\")) ??\n\t\t{};\n\n\tconst manifests: Record<string, Manifest> = {};\n\tfor (const key of Object.keys(installed.plugins)) {\n\t\tconst mp = key.slice(key.lastIndexOf(\"@\") + 1);\n\t\tif (!mp || manifests[mp]) continue;\n\t\tconst installLocation =\n\t\t\tmarketplaces[mp]?.installLocation ?? join(pluginsDir, \"marketplaces\", mp);\n\t\tconst manifest = readJson<Manifest>(\n\t\t\tjoin(installLocation, \".claude-plugin\", \"marketplace.json\"),\n\t\t);\n\t\tif (manifest) manifests[mp] = manifest;\n\t}\n\n\treturn resolvePluginLinks(installed, marketplaces, manifests);\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, relative } from \"node:path\";\nimport ignore from \"ignore\";\n\nexport type FileType =\n\t| \"rule\"\n\t| \"mcp\"\n\t| \"skill\"\n\t| \"command\"\n\t| \"prompt\"\n\t| \"hook\"\n\t| \"subagent\"\n\t| \"config\"\n\t| \"custom\";\n\nexport interface ScannedFile {\n\tpath: string;\n\trelativePath: string;\n\tcontent: string;\n\ttype: FileType;\n\tsource: \"local\" | \"global\";\n\tgroup: string;\n}\n\nconst MAX_FILE_SIZE = 100 * 1024; // 100KB\n\ninterface FilePattern {\n\tpath: string;\n\ttype: FileType;\n\tgroup: string;\n}\n\nconst LOCAL_PATTERNS: FilePattern[] = [\n\t// Rules\n\t{ path: \"CLAUDE.md\", type: \"rule\", group: \"claude-code\" },\n\t{ path: \"AGENTS.md\", type: \"rule\", group: \"claude-code\" },\n\t{ path: \"GEMINI.md\", type: \"rule\", group: \"gemini\" },\n\t{ path: \".cursorrules\", type: \"rule\", group: \"cursor\" },\n\t{ path: \".windsurfrules\", type: \"rule\", group: \"windsurf\" },\n\t{ path: \".clinerules\", type: \"rule\", group: \"cline\" },\n\t{ path: \".roorules\", type: \"rule\", group: \"roo\" },\n\t{ path: \".github/copilot-instructions.md\", type: \"rule\", group: \"copilot\" },\n\t// MCP servers are detected separately as pkg-reference links (see mcp.ts) —\n\t// their config files are intentionally NOT collected as content here (which\n\t// would also upload `env` secrets).\n\t// Config\n\t{ path: \".aider.conf.yml\", type: \"config\", group: \"aider\" },\n\t{ path: \".continue/config.json\", type: \"config\", group: \"continue\" },\n\t{ path: \".continue/config.yaml\", type: \"config\", group: \"continue\" },\n\t{ path: \".claude/settings.json\", type: \"config\", group: \"claude-code\" },\n\t{\n\t\tpath: \".claude/settings.local.json\",\n\t\ttype: \"config\",\n\t\tgroup: \"claude-code\",\n\t},\n\t// Prompts\n\t{ path: \"system-prompt.md\", type: \"prompt\", group: \"generic\" },\n];\n\nconst LOCAL_DIR_PATTERNS: { dir: string; type: FileType; group: string }[] = [\n\t{ dir: \".cursor/rules\", type: \"rule\", group: \"cursor\" },\n\t{ dir: \".clinerules\", type: \"rule\", group: \"cline\" },\n\t{ dir: \".windsurf/rules\", type: \"rule\", group: \"windsurf\" },\n\t{ dir: \".roo/rules\", type: \"rule\", group: \"roo\" },\n\t{ dir: \".github/instructions\", type: \"rule\", group: \"copilot\" },\n\t{ dir: \".github/prompts\", type: \"prompt\", group: \"copilot\" },\n\t{ dir: \".claude/commands\", type: \"command\", group: \"claude-code\" },\n\t{ dir: \".claude/agents\", type: \"subagent\", group: \"claude-code\" },\n\t{ dir: \".claude/hooks\", type: \"hook\", group: \"claude-code\" },\n\t{ dir: \"prompts\", type: \"prompt\", group: \"generic\" },\n\t{ dir: \".ai\", type: \"custom\", group: \"generic\" },\n];\n\nfunction loadGitignore(cwd: string): ReturnType<typeof ignore> {\n\tconst ig = ignore();\n\tconst gitignorePath = join(cwd, \".gitignore\");\n\tif (existsSync(gitignorePath)) {\n\t\tig.add(readFileSync(gitignorePath, \"utf-8\"));\n\t}\n\tig.add([\"node_modules\", \".git\", \"dist\", \"build\", \".next\", \".output\"]);\n\treturn ig;\n}\n\nfunction readFileSafe(filePath: string): string | null {\n\ttry {\n\t\tconst stat = statSync(filePath);\n\t\tif (stat.size > MAX_FILE_SIZE) return null;\n\t\treturn readFileSync(filePath, \"utf-8\");\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction walkDir(dir: string, maxDepth = 3, currentDepth = 0): string[] {\n\tif (currentDepth >= maxDepth || !existsSync(dir)) return [];\n\tconst results: string[] = [];\n\ttry {\n\t\tfor (const entry of readdirSync(dir, { withFileTypes: true })) {\n\t\t\tconst fullPath = join(dir, entry.name);\n\t\t\tif (entry.isFile()) {\n\t\t\t\tresults.push(fullPath);\n\t\t\t} else if (entry.isDirectory()) {\n\t\t\t\tresults.push(...walkDir(fullPath, maxDepth, currentDepth + 1));\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t/* permission errors, etc */\n\t}\n\treturn results;\n}\n\nexport function scanLocal(cwd: string): ScannedFile[] {\n\tconst ig = loadGitignore(cwd);\n\tconst results: ScannedFile[] = [];\n\n\tfor (const pattern of LOCAL_PATTERNS) {\n\t\tconst filePath = join(cwd, pattern.path);\n\t\tconst content = readFileSafe(filePath);\n\t\tif (content !== null) {\n\t\t\tconst rel = relative(cwd, filePath);\n\t\t\tif (!ig.ignores(rel)) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: rel,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype: pattern.type,\n\t\t\t\t\tsource: \"local\",\n\t\t\t\t\tgroup: pattern.group,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const { dir, type, group } of LOCAL_DIR_PATTERNS) {\n\t\tconst dirPath = join(cwd, dir);\n\t\tconst files = walkDir(dirPath);\n\t\tfor (const filePath of files) {\n\t\t\tconst rel = relative(cwd, filePath);\n\t\t\tif (ig.ignores(rel)) continue;\n\t\t\tconst content = readFileSafe(filePath);\n\t\t\tif (content !== null) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: rel,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype,\n\t\t\t\t\tsource: \"local\",\n\t\t\t\t\tgroup,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// Scan for skill directories (dirs with SKILL.md, 3 levels deep)\n\ttry {\n\t\tfor (const entry of readdirSync(cwd, { withFileTypes: true }).filter((e) =>\n\t\t\te.isDirectory(),\n\t\t)) {\n\t\t\tif (ig.ignores(entry.name + \"/\")) continue;\n\t\t\tscanSkillDirs(join(cwd, entry.name), cwd, ig, results, 1);\n\t\t}\n\t} catch {\n\t\t/* permission errors */\n\t}\n\n\treturn results;\n}\n\nfunction scanSkillDirs(\n\tdir: string,\n\tcwd: string,\n\tig: ReturnType<typeof ignore>,\n\tresults: ScannedFile[],\n\tdepth: number,\n) {\n\tif (depth > 3) return;\n\tconst skillMd = join(dir, \"SKILL.md\");\n\tif (existsSync(skillMd)) {\n\t\tconst files = walkDir(dir, 1);\n\t\tfor (const filePath of files) {\n\t\t\tconst rel = relative(cwd, filePath);\n\t\t\tif (ig.ignores(rel)) continue;\n\t\t\tconst content = readFileSafe(filePath);\n\t\t\tif (content !== null) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: rel,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype: \"skill\",\n\t\t\t\t\tsource: \"local\",\n\t\t\t\t\tgroup: \"generic\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\ttry {\n\t\tfor (const entry of readdirSync(dir, { withFileTypes: true })) {\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tconst rel = relative(cwd, join(dir, entry.name));\n\t\t\t\tif (!ig.ignores(rel + \"/\")) {\n\t\t\t\t\tscanSkillDirs(join(dir, entry.name), cwd, ig, results, depth + 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t/* permission errors */\n\t}\n}\n\nexport function scanGlobal(): ScannedFile[] {\n\tconst home = homedir();\n\tconst results: ScannedFile[] = [];\n\n\tconst globalPatterns: FilePattern[] = [\n\t\t{ path: \".claude/CLAUDE.md\", type: \"rule\", group: \"claude-code\" },\n\t\t{ path: \".claude/settings.json\", type: \"config\", group: \"claude-code\" },\n\t\t{ path: \".continue/config.json\", type: \"config\", group: \"continue\" },\n\t\t{ path: \".continue/config.yaml\", type: \"config\", group: \"continue\" },\n\t\t{ path: \".aider.conf.yml\", type: \"config\", group: \"aider\" },\n\t\t{ path: \".gemini/GEMINI.md\", type: \"rule\", group: \"gemini\" },\n\t\t{ path: \".gemini/settings.json\", type: \"config\", group: \"gemini\" },\n\t\t{ path: \".codex/config.toml\", type: \"config\", group: \"codex\" },\n\t\t{\n\t\t\tpath: \".codeium/windsurf/memories/global_rules.md\",\n\t\t\ttype: \"rule\",\n\t\t\tgroup: \"windsurf\",\n\t\t},\n\t];\n\n\tfor (const pattern of globalPatterns) {\n\t\tconst filePath = join(home, pattern.path);\n\t\tconst content = readFileSafe(filePath);\n\t\tif (content !== null) {\n\t\t\tresults.push({\n\t\t\t\tpath: filePath,\n\t\t\t\trelativePath: `~/${pattern.path}`,\n\t\t\t\tcontent,\n\t\t\t\ttype: pattern.type,\n\t\t\t\tsource: \"global\",\n\t\t\t\tgroup: pattern.group,\n\t\t\t});\n\t\t}\n\t}\n\n\tconst globalDirs: { dir: string; type: FileType; group: string }[] = [\n\t\t{ dir: \".claude/commands\", type: \"command\", group: \"claude-code\" },\n\t\t{ dir: \".claude/agents\", type: \"subagent\", group: \"claude-code\" },\n\t\t{ dir: \".claude/hooks\", type: \"hook\", group: \"claude-code\" },\n\t\t{ dir: \".cursor/rules\", type: \"rule\", group: \"cursor\" },\n\t];\n\n\tfor (const { dir, type, group } of globalDirs) {\n\t\tconst dirPath = join(home, dir);\n\t\tconst files = walkDir(dirPath, 2);\n\t\tfor (const filePath of files) {\n\t\t\tconst content = readFileSafe(filePath);\n\t\t\tif (content !== null) {\n\t\t\t\tresults.push({\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\trelativePath: `~/${relative(home, filePath)}`,\n\t\t\t\t\tcontent,\n\t\t\t\t\ttype,\n\t\t\t\t\tsource: \"global\",\n\t\t\t\t\tgroup,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// Global skills: ~/.claude/skills/<name>/SKILL.md (+ supporting files). Not\n\t// covered by globalDirs since each skill is its own dir keyed by SKILL.md.\n\tconst skillsRoot = join(home, \".claude\", \"skills\");\n\ttry {\n\t\tfor (const entry of readdirSync(skillsRoot, { withFileTypes: true })) {\n\t\t\tif (!entry.isDirectory()) continue;\n\t\t\tconst skillDir = join(skillsRoot, entry.name);\n\t\t\tif (!existsSync(join(skillDir, \"SKILL.md\"))) continue;\n\t\t\tfor (const filePath of walkDir(skillDir, 2)) {\n\t\t\t\tconst content = readFileSafe(filePath);\n\t\t\t\tif (content !== null) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\tpath: filePath,\n\t\t\t\t\t\trelativePath: `~/${relative(home, filePath)}`,\n\t\t\t\t\t\tcontent,\n\t\t\t\t\t\ttype: \"skill\",\n\t\t\t\t\t\tsource: \"global\",\n\t\t\t\t\t\tgroup: \"claude-code\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t/* skills dir absent / permission errors */\n\t}\n\n\treturn results;\n}\n","import * as p from \"@clack/prompts\";\n\nconst esc = (code: string) => `\\x1b[${code}m`;\nconst reset = esc(\"0\");\n\nconst LIME = \"163;230;53\";\nconst BLACK = \"0;0;0\";\nconst YELLOW = \"250;204;21\";\nconst RED = \"248;113;113\";\nconst MUTED = \"120;120;120\";\n\nexport const lime = (s: string) => `${esc(`38;2;${LIME}`)}${s}${reset}`;\nexport const limeBold = (s: string) =>\n\t`${esc(\"1\")}${esc(`38;2;${LIME}`)}${s}${reset}`;\nexport const bgLime = (s: string) =>\n\t`${esc(`48;2;${LIME}`)}${esc(`38;2;${BLACK}`)}${s}${reset}`;\nexport const yellow = (s: string) => `${esc(`38;2;${YELLOW}`)}${s}${reset}`;\nexport const red = (s: string) => `${esc(`38;2;${RED}`)}${s}${reset}`;\nexport const dim = (s: string) => `${esc(`38;2;${MUTED}`)}${s}${reset}`;\nexport const bold = (s: string) => `${esc(\"1\")}${s}${reset}`;\n\n// ■ logo square in lime + AISTACK in bold on lime bg\nexport const banner = (cmd: string) =>\n\t`${lime(\"■\")} ${bgLime(` AISTACK `)} ${bold(cmd.toUpperCase())}`;\n\n// Compact line with clack-style bar\nconst BAR = `${esc(`38;2;${MUTED}`)}│${reset}`;\n\nexport function lines(items: string[]) {\n\tfor (const item of items) {\n\t\tconsole.log(`${BAR} ${item}`);\n\t}\n}\n\nexport function section(label: string, count?: number) {\n\tconsole.log(`${BAR}`);\n\tconst countStr = count !== undefined ? ` ${dim(String(count))}` : \"\";\n\tconsole.log(`${BAR} ${bold(label.toUpperCase())}${countStr}`);\n}\n\nexport function divider() {\n\tconsole.log(`${BAR} ${dim(\"─\".repeat(40))}`);\n}\n\nexport function intro(cmd: string) {\n\tconsole.log();\n\tp.intro(banner(cmd));\n}\n\nexport function outro(msg: string) {\n\tp.outro(msg);\n\tconsole.log();\n}\n\nexport function outroError(msg: string) {\n\tp.outro(red(msg));\n\tconsole.log();\n}\n\nexport function outroCancel(msg = \"cancelled\") {\n\tp.cancel(dim(msg));\n\tconsole.log();\n}\n\nexport function outroSkipped(msg: string) {\n\tp.outro(dim(msg));\n\tconsole.log();\n}\n","// `aistack connect claude` — the opt-in in-session sync surface (#56, #57).\n//\n// Installs BOTH halves or NEITHER: the user-scoped MCP server registration and\n// the Skill copy travel together, because the Skill drives `sync_preview` /\n// `sync_publish` and has nothing to do without the server (#56 decision 3).\n// The harness argument leaves room for `connect codex` later without a rename.\n\nimport { spawnSync } from \"node:child_process\";\nimport { cpSync, existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as p from \"@clack/prompts\";\nimport { getSettings, saveSettings } from \"../config.js\";\nimport {\n\tdim,\n\tintro,\n\tlimeBold,\n\toutro,\n\toutroError,\n\toutroSkipped,\n} from \"../theme.js\";\n\n/** The documented manual install line, printed when we cannot run it. */\nexport const MANUAL_MCP_ADD =\n\t\"claude mcp add --scope user aistack -- npx -y @use-aistack/cli mcp\";\n\nconst MCP_ADD_ARGS = [\n\t\"mcp\",\n\t\"add\",\n\t\"--scope\",\n\t\"user\",\n\t\"aistack\",\n\t\"--\",\n\t\"npx\",\n\t\"-y\",\n\t\"@use-aistack/cli\",\n\t\"mcp\",\n];\n\nconst MCP_REMOVE_ARGS = [\"mcp\", \"remove\", \"--scope\", \"user\", \"aistack\"];\n\nexport const SKILL_DEST = join(homedir(), \".claude\", \"skills\", \"aistack-sync\");\n\nexport interface RunResult {\n\t/** The binary was not found on PATH. */\n\tnotFound: boolean;\n\tstatus: number | null;\n\toutput: string;\n}\n\nexport type Runner = (args: string[]) => RunResult;\n\nfunction runClaude(args: string[]): RunResult {\n\tconst r = spawnSync(\"claude\", args, { encoding: \"utf-8\" });\n\tconst notFound =\n\t\tr.error !== undefined &&\n\t\t(r.error as NodeJS.ErrnoException).code === \"ENOENT\";\n\treturn {\n\t\tnotFound,\n\t\tstatus: r.status,\n\t\toutput: `${r.stdout ?? \"\"}${r.stderr ?? \"\"}`,\n\t};\n}\n\n/** Is the `claude` binary reachable? Cheap check used to skip the upsell. */\nexport function claudeOnPath(run: Runner = runClaude): boolean {\n\treturn !run([\"--version\"]).notFound;\n}\n\n/**\n * The bundled Skill directory, resolved relative to this module. In the\n * published package that is `<pkg>/skills/aistack-sync` next to `dist/`; in\n * dev it is two levels up from `src/commands/`. Walking up covers both.\n */\nexport function findSkillSource(\n\tfromDir: string = dirname(fileURLToPath(import.meta.url)),\n): string | null {\n\tlet dir = fromDir;\n\tfor (let i = 0; i < 4; i++) {\n\t\tconst candidate = join(dir, \"skills\", \"aistack-sync\");\n\t\tif (existsSync(join(candidate, \"SKILL.md\"))) return candidate;\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) break;\n\t\tdir = parent;\n\t}\n\treturn null;\n}\n\nexport interface ConnectOutcome {\n\tok: boolean;\n\tmessage: string;\n}\n\n/**\n * Install the server registration, then the Skill. If the Skill copy fails\n * after a fresh registration, the registration is rolled back — both halves\n * or neither.\n */\nexport function installClaudeConnect(\n\trun: Runner = runClaude,\n\tcopySkill: (src: string, dest: string) => void = (src, dest) =>\n\t\tcpSync(src, dest, { recursive: true }),\n): ConnectOutcome {\n\tconst source = findSkillSource();\n\tif (source === null) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tmessage:\n\t\t\t\t\"this install is missing its bundled Skill (skills/aistack-sync) — nothing was installed\",\n\t\t};\n\t}\n\n\tconst add = run(MCP_ADD_ARGS);\n\tif (add.notFound) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tmessage: `claude was not found on PATH — nothing was installed. Manual install:\\n${MANUAL_MCP_ADD}`,\n\t\t};\n\t}\n\tconst alreadyRegistered =\n\t\tadd.status !== 0 && add.output.includes(\"already exists\");\n\tif (add.status !== 0 && !alreadyRegistered) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tmessage: `claude mcp add failed — nothing was installed.\\n${add.output.trim()}`,\n\t\t};\n\t}\n\n\ttry {\n\t\tcopySkill(source, SKILL_DEST);\n\t} catch (e) {\n\t\t// Both halves or neither: a fresh registration without its Skill is\n\t\t// rolled back. A pre-existing registration is left as it was.\n\t\tif (!alreadyRegistered) run(MCP_REMOVE_ARGS);\n\t\treturn {\n\t\t\tok: false,\n\t\t\tmessage: `copying the Skill to ${SKILL_DEST} failed — the MCP registration was ${\n\t\t\t\talreadyRegistered ? \"left as it was\" : \"rolled back\"\n\t\t\t}.\\n${e instanceof Error ? e.message : String(e)}`,\n\t\t};\n\t}\n\n\treturn {\n\t\tok: true,\n\t\tmessage: `Installed. Say ${limeBold('\"sync my stack\"')} in any Claude Code session.`,\n\t};\n}\n\nexport async function connectCommand(harness: string): Promise<void> {\n\tintro(\"connect\");\n\n\tif (harness !== \"claude\") {\n\t\toutroError(`unknown harness \"${harness}\" — supported: claude`);\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\tif (!claudeOnPath()) {\n\t\tp.log.warn(\n\t\t\t`claude was not found on PATH. Manual install:\\n${dim(MANUAL_MCP_ADD)}\\nplus copy skills/aistack-sync from this package to ${dim(SKILL_DEST)}`,\n\t\t);\n\t\toutroSkipped(\"nothing was installed\");\n\t\treturn;\n\t}\n\n\tconst result = installClaudeConnect();\n\tif (!result.ok) {\n\t\toutroError(result.message);\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\tp.log.success(result.message);\n\toutro(\"done\");\n}\n\n/**\n * The post-sync upsell (#56 decision 2), asked once per machine. Any explicit\n * answer persists to ~/.config/aistack/settings.json; ctrl-C is not an answer\n * and the question returns on the next sync. Skipped silently when claude is\n * not on PATH — the offer would be noise on a machine that cannot take it.\n */\nexport async function offerConnectUpsell(): Promise<void> {\n\tif (getSettings().connectClaudeAnswered === true) return;\n\tif (!claudeOnPath()) return;\n\n\tconst answer = await p.select({\n\t\tmessage: \"Sync from inside Claude Code too?\",\n\t\toptions: [\n\t\t\t{\n\t\t\t\tvalue: \"later\",\n\t\t\t\tlabel: \"Not now\",\n\t\t\t\thint: \"this question will not come back\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tvalue: \"install\",\n\t\t\t\tlabel: \"Install\",\n\t\t\t\thint: \"adds the aistack MCP server + Skill to Claude Code\",\n\t\t\t},\n\t\t],\n\t\tinitialValue: \"later\",\n\t});\n\n\tif (p.isCancel(answer)) return;\n\tsaveSettings({ connectClaudeAnswered: true });\n\n\tif (answer === \"install\") {\n\t\tconst result = installClaudeConnect();\n\t\tif (result.ok) {\n\t\t\tp.log.success(result.message);\n\t\t} else {\n\t\t\tp.log.error(result.message);\n\t\t}\n\t\treturn;\n\t}\n\n\tp.log.message(\n\t\t`If you change your mind: ${limeBold(\"npx @use-aistack/cli connect claude\")}`,\n\t);\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport * as p from \"@clack/prompts\";\nimport { stackGet } from \"../api.js\";\nimport { getToken } from \"../config.js\";\nimport {\n\tbold,\n\tdim,\n\tdivider,\n\tintro,\n\tlime,\n\tlimeBold,\n\tlines,\n\toutro,\n\toutroCancel,\n\toutroError,\n\toutroSkipped,\n\tsection,\n\tyellow,\n} from \"../theme.js\";\n\nexport async function createCommand() {\n\tintro(\"create\");\n\n\tconst token = getToken();\n\tif (!token) {\n\t\tp.log.error(\n\t\t\t`Not authenticated. Run ${limeBold(\"npx @use-aistack/cli login\")} first.`,\n\t\t);\n\t\toutroError(\"not authenticated\");\n\t\tprocess.exit(1);\n\t}\n\n\tconst s = p.spinner();\n\ts.start(\"Fetching stack...\");\n\n\tlet stack: Awaited<ReturnType<typeof stackGet>>;\n\ttry {\n\t\tstack = await stackGet(token);\n\t\tif (!stack) {\n\t\t\ts.stop(\"Not found\");\n\t\t\tp.log.error(\"No stack found. Create a stack on aistack.to first.\");\n\t\t\toutroError(\"not found\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\ts.stop(bold(stack.name));\n\t} catch (err) {\n\t\ts.stop(\"Failed to fetch stack\");\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\toutroError(\"error\");\n\t\tprocess.exit(1);\n\t}\n\n\tconst localFiles: FileToWrite[] = [];\n\n\tfor (const item of stack.resources) {\n\t\tfor (const file of item.files ?? []) {\n\t\t\tlocalFiles.push({ path: file.path ?? file.name, content: file.content });\n\t\t}\n\t}\n\n\t// Linked resources have no files to write — surface them so they aren't\n\t// silently dropped on download (GitHub repos + package refs like MCP servers).\n\tconst linked = stack.resources.filter(\n\t\t(item) => (item.upstream || item.pkg) && !item.files?.length,\n\t);\n\tif (linked.length > 0) {\n\t\tsection(\"linked\", linked.length);\n\t\tlines([dim(\"view only\")]);\n\t\tlines(\n\t\t\tlinked.map((item) =>\n\t\t\t\tdim(\n\t\t\t\t\titem.upstream?.repoUrl ??\n\t\t\t\t\t\t(item.pkg ? `${item.pkg.registry}:${item.pkg.id}` : \"\"),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t}\n\n\tif (localFiles.length === 0) {\n\t\tp.log.warn(\"No local files to write.\");\n\t\toutroSkipped(\"nothing to create\");\n\t\treturn;\n\t}\n\n\tconst cwd = process.cwd();\n\tconst toWrite: FileToWrite[] = [];\n\tconst skipped: { path: string; differs: boolean }[] = [];\n\n\tfor (const f of localFiles) {\n\t\tconst fullPath = join(cwd, f.path);\n\t\tif (existsSync(fullPath)) {\n\t\t\tconst existing = readFileSync(fullPath, \"utf-8\");\n\t\t\tskipped.push({ path: f.path, differs: existing !== f.content });\n\t\t} else {\n\t\t\ttoWrite.push(f);\n\t\t}\n\t}\n\n\tsection(\"local files\", localFiles.length);\n\tlines(toWrite.map((f) => lime(`+ ${f.path}`)));\n\tlines(\n\t\tskipped.map((f) =>\n\t\t\tf.differs\n\t\t\t\t? `${yellow(`= ${f.path}`)} ${dim(\"(differs)\")}`\n\t\t\t\t: dim(`= ${f.path} (identical)`),\n\t\t),\n\t);\n\n\tif (toWrite.length === 0) {\n\t\tdivider();\n\t\tp.log.info(\"All local files already exist.\");\n\t\toutroSkipped(\"nothing to write\");\n\t\treturn;\n\t}\n\n\tdivider();\n\n\tconst confirm = await p.confirm({\n\t\tmessage: `Write ${lime(String(toWrite.length))} new files? ${dim(`(${skipped.length} skipped)`)}`,\n\t});\n\n\tif (p.isCancel(confirm) || !confirm) {\n\t\toutroCancel();\n\t\tprocess.exit(0);\n\t}\n\n\tfor (const f of toWrite) {\n\t\tconst fullPath = join(cwd, f.path);\n\t\tconst dir = dirname(fullPath);\n\t\tmkdirSync(dir, { recursive: true });\n\t\twriteFileSync(fullPath, f.content);\n\t}\n\n\tp.log.success(\n\t\t`${lime(String(toWrite.length))} written, ${dim(String(skipped.length) + \" skipped\")}`,\n\t);\n\toutro(lime(\"done\"));\n}\n\ninterface FileToWrite {\n\tpath: string;\n\tcontent: string;\n}\n","import { hostname } from \"node:os\";\nimport * as p from \"@clack/prompts\";\nimport open from \"open\";\nimport { authPoll, authStart } from \"../api.js\";\nimport { saveToken } from \"../config.js\";\nimport { dim, intro, lime, limeBold, outro, outroError } from \"../theme.js\";\n\n/**\n * What to call this machine on the account's linked-machines list (#49).\n *\n * The hostname is only a proposal — the approval page shows it in an editable\n * field before anything is stored. Trimmed to the server's 64-character bound so\n * a long hostname is dropped by us rather than silently by the server, and\n * `.local` is stripped because mDNS suffixes carry no information for a reader.\n */\nexport function proposedMachineName(\n\tread: () => string = hostname,\n): string | undefined {\n\ttry {\n\t\tconst name = read()\n\t\t\t.trim()\n\t\t\t.replace(/\\.local$/i, \"\");\n\t\tif (!name || name.length > 64) return undefined;\n\t\treturn name;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport async function loginCommand() {\n\tintro(\"login\");\n\n\tconst s = p.spinner();\n\ts.start(\"Starting authentication...\");\n\n\tlet session: Awaited<ReturnType<typeof authStart>>;\n\ttry {\n\t\tsession = await authStart(proposedMachineName());\n\t\ts.stop(\"Session created\");\n\t} catch (err) {\n\t\ts.stop(\"Failed to start authentication\");\n\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\toutroError(\"error\");\n\t\tprocess.exit(1);\n\t}\n\n\tp.log.info(`${dim(\"CODE\")} ${limeBold(session.userCode)}`);\n\tp.log.info(`${dim(\"OPEN\")} ${dim(session.authUrl)}`);\n\n\ttry {\n\t\tawait open(session.authUrl);\n\t} catch {\n\t\tp.log.warn(\n\t\t\t\"Could not open browser automatically. Please visit the URL above.\",\n\t\t);\n\t}\n\n\ts.start(\"Waiting for approval...\");\n\n\tconst maxAttempts = 36;\n\tfor (let i = 0; i < maxAttempts; i++) {\n\t\tawait new Promise((resolve) => setTimeout(resolve, 5000));\n\n\t\ttry {\n\t\t\tconst result = await authPoll(session.secretId);\n\n\t\t\tif (result.status === \"approved\" && result.token) {\n\t\t\t\ts.stop(lime(\"Authenticated\"));\n\t\t\t\tsaveToken(result.token, result.userId);\n\t\t\t\tp.log.success(\n\t\t\t\t\t`Token saved. Run ${limeBold(\"npx @use-aistack/cli collect\")} to get started.`,\n\t\t\t\t);\n\t\t\t\toutro(lime(\"done\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (result.status === \"expired\") {\n\t\t\t\ts.stop(\"Session expired\");\n\t\t\t\tp.log.error(\"Authentication session expired. Please try again.\");\n\t\t\t\toutroError(\"expired\");\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\ts.stop(\"Error polling\");\n\t\t\tp.log.error(err instanceof Error ? err.message : String(err));\n\t\t\toutroError(\"error\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\ts.stop(\"Timed out\");\n\tp.log.error(\"Authentication timed out after 3 minutes. Please try again.\");\n\toutroError(\"timed out\");\n\tprocess.exit(1);\n}\n","// The documented default sync surface (#56, built by #55/#57).\n//\n// The MCP-free channel: a human types `aistack sync` in their own terminal,\n// so a real TTY exists and the gate can be a @clack/prompts select. Same\n// staged-bytes property as the MCP server (#41): the summary and the confirm\n// derive from the exact serialized `bodyJson`, and that string goes on the\n// wire byte-identical. One gate policy, two renderings.\n//\n// Fail-closed: ctrl-C, ESC, EOF, and a missing TTY all resolve to \"nothing\n// was sent\" before any network call.\n\nimport * as p from \"@clack/prompts\";\nimport { BASE_URL, syncPublish } from \"../api.js\";\nimport {\n\tCODEX_TRUST_INSTRUCTION,\n\tcodexAutoSyncHookInstalled,\n\tcodexHookTrusted,\n} from \"../autosync/codexHook.js\";\nimport {\n\tdisableAutoSync,\n\tenableAutoSync,\n\tofferAutoSyncOptIn,\n} from \"../autosync/optin.js\";\nimport { runAutoSync } from \"../autosync/run.js\";\nimport { DEFAULT_FREQUENCY_HOURS, getSettings } from \"../config.js\";\nimport { stageSync } from \"../sync/stage.js\";\nimport { dim, intro, lime, outro, outroCancel, outroError } from \"../theme.js\";\nimport { offerConnectUpsell } from \"./connect.js\";\n\nexport interface SyncOptions {\n\t/** `--auto` → true, `--auto on` → \"on\", `--auto off` → \"off\". */\n\tauto?: boolean | string;\n\t/** `--every <hours>`, applied with `--auto on`. */\n\tevery?: string;\n}\n\nexport async function syncCommand(options: SyncOptions = {}): Promise<void> {\n\t// The silent path (#62): no TTY, no prompts, no upsells. Publishes only\n\t// under the standing opt-in and always exits 0 — the hook command's `||`\n\t// offline fallback must never fire on a mere sync failure.\n\tif (options.auto === true) {\n\t\tawait runAutoSync({ baseUrl: BASE_URL });\n\t\treturn;\n\t}\n\n\tif (options.auto === \"on\" || options.auto === \"off\") {\n\t\tintro(\"sync\");\n\t\tconst result =\n\t\t\toptions.auto === \"on\"\n\t\t\t\t? enableAutoSync(\n\t\t\t\t\t\toptions.every\n\t\t\t\t\t\t\t? Number.parseInt(options.every, 10) || DEFAULT_FREQUENCY_HOURS\n\t\t\t\t\t\t\t: DEFAULT_FREQUENCY_HOURS,\n\t\t\t\t\t)\n\t\t\t\t: disableAutoSync();\n\t\tif (result.ok) {\n\t\t\tp.log.success(result.message);\n\t\t\toutro(\"done\");\n\t\t} else {\n\t\t\toutroError(result.message);\n\t\t\tprocess.exitCode = 1;\n\t\t}\n\t\treturn;\n\t}\n\tif (options.auto !== undefined) {\n\t\tintro(\"sync\");\n\t\toutroError(`unknown --auto value \"${options.auto}\" — use on or off`);\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\tintro(\"sync\");\n\n\t// The interactive surface is where a silent failure becomes visible (#62):\n\t// report the last auto-sync outcome, whatever it was.\n\tconst lastAuto = getSettings().autoSyncState?.lastResult;\n\tif (lastAuto !== undefined) {\n\t\tp.log.message(dim(`auto-sync: ${lastAuto}`));\n\t}\n\n\t// The Codex hook does not run until the user trusts it via /hooks (#65 §6).\n\t// Repeat the one-time instruction while the hook is installed but the trust\n\t// hash is verifiably absent; an unreadable config stays silent.\n\tif (codexAutoSyncHookInstalled() && codexHookTrusted() === false) {\n\t\tp.log.warn(CODEX_TRUST_INSTRUCTION);\n\t}\n\n\t// The whole premise of this channel is a human at a terminal. A pipe or a\n\t// model-launched Bash call has no TTY, and a gate that cannot ask must not\n\t// send (#31) — refuse before scanning anything.\n\tif (!process.stdin.isTTY || !process.stdout.isTTY) {\n\t\toutroError(\"sync needs an interactive terminal — nothing was sent\");\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\tconst s = p.spinner();\n\ts.start(\"Scanning local agent transcripts\");\n\tlet staged: Awaited<ReturnType<typeof stageSync>>;\n\ttry {\n\t\tstaged = await stageSync({ baseUrl: BASE_URL });\n\t} catch (e) {\n\t\ts.stop(\"Scan failed\");\n\t\toutroError(e instanceof Error ? e.message : String(e));\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\ts.stop(\"Scan complete\");\n\n\t// Beat one — the same full summary the MCP preview returns, verbatim,\n\t// printed behind the clack bar so it reads as one flow.\n\tp.log.message(staged.summary.split(\"\\n\").join(\"\\n\"));\n\n\tif (staged.blockedReason !== null) {\n\t\toutroError(staged.blockedReason);\n\t\tprocess.exitCode = 1;\n\t\treturn;\n\t}\n\n\t// Beat two — the same short dialog text, as a select. The enum mirrors the\n\t// elicitation's {publish, cancel}; cancel is the initial value, so Enter\n\t// alone publishes nothing.\n\tconst decision = await p.select({\n\t\tmessage: staged.dialog.split(\"\\n\").join(dim(\" · \")),\n\t\toptions: [\n\t\t\t{ value: \"cancel\", label: \"Cancel\", hint: \"nothing leaves this machine\" },\n\t\t\t{ value: \"publish\", label: \"Publish\" },\n\t\t],\n\t\tinitialValue: \"cancel\",\n\t});\n\n\tif (p.isCancel(decision) || decision !== \"publish\") {\n\t\toutroCancel(\"nothing was sent\");\n\t\treturn;\n\t}\n\n\ts.start(\"Publishing\");\n\ttry {\n\t\tconst res = await syncPublish(staged.token as string, staged.bodyJson);\n\t\ts.stop(\"Published\");\n\t\tconst lines = [\n\t\t\t`Snapshot received at ${new Date(res.receivedAt).toISOString()}`,\n\t\t\tlime(res.url),\n\t\t];\n\t\tif (res.keptPrivate.refused && staged.body.keptPrivate !== undefined) {\n\t\t\tlines.push(\n\t\t\t\t\"Note: the kept-private names were refused by the server — the review switch is off there now. They stayed on this machine.\",\n\t\t\t);\n\t\t} else if (res.keptPrivate.stored > 0) {\n\t\t\tlines.push(\n\t\t\t\t`${res.keptPrivate.stored} kept-private names went up for your review at ${res.url}/changes`,\n\t\t\t);\n\t\t}\n\t\tp.log.message(lines.join(\"\\n\"));\n\t\t// At most one ask per sync (#62): the auto-sync opt-in is the primary\n\t\t// ask; the connect upsell yields and waits for a later sync.\n\t\tconst asked = await offerAutoSyncOptIn();\n\t\tif (!asked) await offerConnectUpsell();\n\t\toutro(\"done\");\n\t} catch (e) {\n\t\ts.stop(\"Publish failed\");\n\t\toutroError(e instanceof Error ? e.message : String(e));\n\t\tprocess.exitCode = 1;\n\t}\n}\n","// The Codex half of the background trigger (#66 decision 4, built in #67):\n// a `SessionStart` hook in ~/.codex/hooks.json, matcher `startup` only.\n//\n// Two ways this differs from the Claude hook (hook.ts):\n//\n// 1. THE COMMAND SELF-DETACHES. Codex parses `async` but does not honor it —\n// the runner awaits the hook with a timeout and kill_on_drop (#65 §6).\n// So the command backgrounds the real work under `setsid nohup … &` and\n// exits 0 immediately; kill_on_drop kills only the already-exited shell.\n// 2. THE TRUST GATE. Codex pins each hook command's sha256 as a\n// `trusted_hash` in config.toml. An untrusted or CHANGED command silently\n// does not run, and only the user can trust it, via /hooks inside Codex.\n// That is why the command text uses `@latest` — the text (and therefore\n// the hash) stays stable across CLI updates — and why install prints the\n// one-time trust instruction.\n\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport type { HookResult } from \"./hook.js\";\n\nfunction codexHome(): string {\n\treturn process.env.CODEX_HOME || join(homedir(), \".codex\");\n}\n\nexport function codexHooksFile(): string {\n\treturn join(codexHome(), \"hooks.json\");\n}\n\n/**\n * Is Codex on this machine at all? Keyed on $CODEX_HOME existing, not on\n * session logs: a hook belongs wherever Codex will RUN, including a fresh\n * install that has no sessions yet.\n */\nexport function codexPresent(): boolean {\n\treturn existsSync(codexHome());\n}\n\nexport function codexConfigFile(): string {\n\treturn join(codexHome(), \"config.toml\");\n}\n\n/**\n * EXACT quoting, settled here (#66 left it to this ticket): the outer layer is\n * a JSON string in hooks.json; Codex runs it through a shell, and the single\n * `sh -c '…'` wrapper makes the detach group unambiguous regardless of how\n * that outer shell tokenizes. No `||` fallback like the Claude command — the\n * fallback semantics live INSIDE the detached shell so the hook process itself\n * still exits instantly.\n *\n * DO NOT REFORMAT THIS STRING. Its sha256 is the trust hash; any byte change\n * un-trusts the hook on every machine until each user re-runs /hooks.\n */\nexport const CODEX_HOOK_COMMAND =\n\t\"sh -c 'setsid nohup sh -c \\\"npx -y @use-aistack/cli@latest sync --auto || npx -y --prefer-offline @use-aistack/cli sync --auto\\\" >/dev/null 2>&1 &'\";\n\ninterface HookEntry {\n\ttype: string;\n\tcommand?: string;\n\ttimeout?: number;\n}\n\ninterface HookMatcher {\n\tmatcher?: string;\n\thooks?: HookEntry[];\n}\n\ninterface CodexHooksJson {\n\thooks?: Record<string, HookMatcher[]>;\n\t[key: string]: unknown;\n}\n\n/** Recognize our hook across versions: package name plus the auto flag. */\nfunction isOurs(entry: HookEntry): boolean {\n\treturn (\n\t\ttypeof entry.command === \"string\" &&\n\t\tentry.command.includes(\"@use-aistack/cli\") &&\n\t\tentry.command.includes(\"sync --auto\")\n\t);\n}\n\nfunction readHooksJson(\n\tfile: string,\n): { settings: CodexHooksJson } | { error: string } {\n\tif (!existsSync(file)) return { settings: {} };\n\ttry {\n\t\tconst raw = JSON.parse(readFileSync(file, \"utf-8\"));\n\t\tif (raw && typeof raw === \"object\" && !Array.isArray(raw)) {\n\t\t\treturn { settings: raw as CodexHooksJson };\n\t\t}\n\t\treturn { error: `${file} does not hold a JSON object` };\n\t} catch {\n\t\t// Never rewrite a file we cannot parse — it is the user's Codex\n\t\t// configuration, and a rewrite would destroy whatever is in it.\n\t\treturn { error: `${file} is not valid JSON — fix it, then retry` };\n\t}\n}\n\n/** The instruction install prints; the interactive sync repeats it while untrusted. */\nexport const CODEX_TRUST_INSTRUCTION =\n\t\"Codex hook written — open Codex and run /hooks once to trust it, or it will not run.\";\n\n/**\n * Add the SessionStart auto-sync hook, matcher `startup` only (resume/clear/\n * compact would multiply runs; the freshness gate would drop them anyway).\n * Idempotent: an existing aistack entry is replaced, not duplicated.\n */\nexport function installCodexAutoSyncHook(\n\tfile: string = codexHooksFile(),\n): HookResult {\n\tconst read = readHooksJson(file);\n\tif (\"error\" in read) return { ok: false, message: read.error };\n\tconst settings = read.settings;\n\n\tconst hooks = settings.hooks ?? {};\n\tconst sessionStart = Array.isArray(hooks.SessionStart)\n\t\t? hooks.SessionStart\n\t\t: [];\n\n\tconst kept = sessionStart\n\t\t.map((m) => ({\n\t\t\t...m,\n\t\t\thooks: (m.hooks ?? []).filter((h) => !isOurs(h)),\n\t\t}))\n\t\t.filter((m) => (m.hooks?.length ?? 0) > 0);\n\n\tkept.push({\n\t\tmatcher: \"startup\",\n\t\thooks: [{ type: \"command\", command: CODEX_HOOK_COMMAND, timeout: 30 }],\n\t});\n\n\tsettings.hooks = { ...hooks, SessionStart: kept };\n\tmkdirSync(dirname(file), { recursive: true });\n\twriteFileSync(file, `${JSON.stringify(settings, null, 2)}\\n`);\n\treturn { ok: true, message: CODEX_TRUST_INSTRUCTION };\n}\n\n/**\n * Remove only our hook. Other hooks and events stay. A missing file or an\n * absent hook is success — the goal state already holds.\n */\nexport function removeCodexAutoSyncHook(\n\tfile: string = codexHooksFile(),\n): HookResult {\n\tif (!existsSync(file))\n\t\treturn { ok: true, message: \"no Codex hook to remove\" };\n\tconst read = readHooksJson(file);\n\tif (\"error\" in read) return { ok: false, message: read.error };\n\tconst settings = read.settings;\n\n\tconst sessionStart = settings.hooks?.SessionStart;\n\tif (!Array.isArray(sessionStart)) {\n\t\treturn { ok: true, message: \"no Codex hook to remove\" };\n\t}\n\n\tconst kept = sessionStart\n\t\t.map((m) => ({\n\t\t\t...m,\n\t\t\thooks: (m.hooks ?? []).filter((h) => !isOurs(h)),\n\t\t}))\n\t\t.filter((m) => (m.hooks?.length ?? 0) > 0);\n\n\tconst hooks = { ...settings.hooks };\n\tif (kept.length > 0) {\n\t\thooks.SessionStart = kept;\n\t} else {\n\t\tdelete hooks.SessionStart;\n\t}\n\tif (Object.keys(hooks).length > 0) {\n\t\tsettings.hooks = hooks;\n\t} else {\n\t\tdelete settings.hooks;\n\t}\n\n\twriteFileSync(file, `${JSON.stringify(settings, null, 2)}\\n`);\n\treturn { ok: true, message: `hook removed from ${file}` };\n}\n\n/** Is the Codex auto-sync hook present? */\nexport function codexAutoSyncHookInstalled(\n\tfile: string = codexHooksFile(),\n): boolean {\n\tconst read = readHooksJson(file);\n\tif (\"error\" in read) return false;\n\tconst sessionStart = read.settings.hooks?.SessionStart;\n\tif (!Array.isArray(sessionStart)) return false;\n\treturn sessionStart.some((m) => (m.hooks ?? []).some((h) => isOurs(h)));\n}\n\n/**\n * Best-effort trust check: Codex pins each trusted hook's sha256 under\n * `[hooks.state]` in config.toml, so the command's hash appearing anywhere in\n * that file reads as trusted. `null` when the file cannot be read — unknown,\n * not untrusted, so the caller does not nag on a parse quirk.\n */\nexport function codexHookTrusted(\n\tconfigFile: string = codexConfigFile(),\n): boolean | null {\n\tlet text: string;\n\ttry {\n\t\ttext = readFileSync(configFile, \"utf-8\");\n\t} catch {\n\t\treturn null;\n\t}\n\tconst hash = createHash(\"sha256\").update(CODEX_HOOK_COMMAND).digest(\"hex\");\n\treturn text.includes(hash);\n}\n","// The auto-sync opt-in (#62, map #60).\n//\n// This ask is the PRIMARY post-sync ask: it runs first, and the connect-claude\n// upsell yields to a later sync (at most one ask per sync, each asked once,\n// each persisted). Any explicit answer persists to\n// ~/.config/aistack/settings.json; ctrl-C is not an answer and the question\n// returns on the next sync.\n\nimport * as p from \"@clack/prompts\";\nimport {\n\tDEFAULT_FREQUENCY_HOURS,\n\tgetSettings,\n\tsaveSettings,\n} from \"../config.js\";\nimport { dim, limeBold } from \"../theme.js\";\nimport {\n\tcodexPresent,\n\tinstallCodexAutoSyncHook,\n\tremoveCodexAutoSyncHook,\n} from \"./codexHook.js\";\nimport {\n\ttype HookResult,\n\tinstallAutoSyncHook,\n\tremoveAutoSyncHook,\n} from \"./hook.js\";\n\nexport interface EnableDeps {\n\tsettingsFile?: string;\n\tinstallHook?: () => HookResult;\n\tremoveHook?: () => HookResult;\n\tinstallCodexHook?: () => HookResult;\n\tremoveCodexHook?: () => HookResult;\n\tcodexPresentImpl?: () => boolean;\n}\n\n/**\n * Turn the standing opt-in on: persist the flag, write the SessionStart hooks\n * — Claude Code always, Codex when it is on this machine (#66 decision 4; one\n * `sync --auto` covers all detected harnesses, so both hooks run the same\n * command). When a hook write fails, the flag is NOT persisted — a\n * half-enabled state (flag on, no hook) would claim a freshness the machine\n * cannot deliver.\n */\nexport function enableAutoSync(\n\tfrequencyHours: number = DEFAULT_FREQUENCY_HOURS,\n\tdeps: EnableDeps = {},\n): HookResult {\n\tconst install = deps.installHook ?? installAutoSyncHook;\n\tconst result = install();\n\tif (!result.ok) return result;\n\n\tconst hasCodex = (deps.codexPresentImpl ?? codexPresent)();\n\tlet trustLine: string | null = null;\n\tif (hasCodex) {\n\t\tconst codexResult = (deps.installCodexHook ?? installCodexAutoSyncHook)();\n\t\tif (!codexResult.ok) return codexResult;\n\t\t// The one-time /hooks trust step (#65 §6) — repeated by the next\n\t\t// interactive sync while the hook stays untrusted.\n\t\ttrustLine = codexResult.message;\n\t}\n\n\tsaveSettings(\n\t\t{\n\t\t\tautoSyncAnswered: true,\n\t\t\tautoSync: { enabled: true, frequencyHours },\n\t\t},\n\t\tdeps.settingsFile,\n\t);\n\tconst sessionWord = hasCodex ? \"Claude Code or Codex\" : \"Claude Code\";\n\treturn {\n\t\tok: true,\n\t\tmessage: [\n\t\t\t`Auto-sync is on — about every ${frequencyHours}h when a ${sessionWord} session starts. Turn it off any time: npx @use-aistack/cli sync --auto off`,\n\t\t\t...(trustLine ? [trustLine] : []),\n\t\t].join(\"\\n\"),\n\t};\n}\n\n/**\n * Revoke: remove the hook AND flip the flag. The flag flips even when the\n * hook file cannot be edited, because `sync --auto` gates on the flag — a\n * stale hook without the flag publishes nothing.\n */\nexport function disableAutoSync(deps: EnableDeps = {}): HookResult {\n\tconst remove = deps.removeHook ?? removeAutoSyncHook;\n\tconst settings = getSettings(deps.settingsFile);\n\tsaveSettings(\n\t\t{\n\t\t\tautoSyncAnswered: true,\n\t\t\tautoSync: {\n\t\t\t\tenabled: false,\n\t\t\t\tfrequencyHours:\n\t\t\t\t\tsettings.autoSync?.frequencyHours ?? DEFAULT_FREQUENCY_HOURS,\n\t\t\t},\n\t\t},\n\t\tdeps.settingsFile,\n\t);\n\tconst result = remove();\n\tconst codexResult = (deps.codexPresentImpl ?? codexPresent)()\n\t\t? (deps.removeCodexHook ?? removeCodexAutoSyncHook)()\n\t\t: { ok: true, message: \"\" };\n\tconst failures = [result, codexResult]\n\t\t.filter((r) => !r.ok)\n\t\t.map((r) => r.message);\n\tif (failures.length > 0) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tmessage: `Auto-sync is off (nothing will publish), but a hook could not be removed: ${failures.join(\"; \")}`,\n\t\t};\n\t}\n\treturn { ok: true, message: \"Auto-sync is off. The hooks were removed.\" };\n}\n\n/**\n * The post-sync ask. Returns true when it asked (so the caller skips the\n * connect upsell this sync), false when it had nothing to ask.\n */\nexport async function offerAutoSyncOptIn(): Promise<boolean> {\n\tif (getSettings().autoSyncAnswered === true) return false;\n\n\tconst answer = await p.select({\n\t\tmessage: \"Keep this stack fresh automatically?\",\n\t\toptions: [\n\t\t\t{\n\t\t\t\tvalue: \"later\",\n\t\t\t\tlabel: \"Not now\",\n\t\t\t\thint: \"this question will not come back\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tvalue: \"enable\",\n\t\t\t\tlabel: \"Enable\",\n\t\t\t\thint: \"a silent daily sync when a Claude Code session starts\",\n\t\t\t},\n\t\t],\n\t\tinitialValue: \"later\",\n\t});\n\n\tif (p.isCancel(answer)) return true;\n\n\tif (answer === \"enable\") {\n\t\tconst result = enableAutoSync();\n\t\tif (result.ok) {\n\t\t\tp.log.success(result.message);\n\t\t} else {\n\t\t\tp.log.error(result.message);\n\t\t}\n\t\treturn true;\n\t}\n\n\tsaveSettings({ autoSyncAnswered: true });\n\tp.log.message(\n\t\t`If you change your mind: ${limeBold(\"npx @use-aistack/cli sync --auto on\")} ${dim(\n\t\t\t\"(and --auto off to revoke)\",\n\t\t)}`,\n\t);\n\treturn true;\n}\n","// The background trigger (#62, map #60): a `SessionStart` hook in\n// ~/.claude/settings.json, `async: true`.\n//\n// SessionStart, not SessionEnd — teardown is not guaranteed (crash, SIGKILL,\n// closed terminal), and at start-of-session the previous sessions are fully on\n// disk. The command runs `@latest` through npx, so unattended machines update\n// by construction. The `||` fallback covers the offline case: when the network\n// resolve of `@latest` fails, the second npx runs the cached copy.\n// `sync --auto` always exits 0, so the fallback never fires on a sync failure.\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nexport const CLAUDE_SETTINGS_FILE = join(homedir(), \".claude\", \"settings.json\");\n\nexport const AUTO_SYNC_HOOK_COMMAND =\n\t\"npx -y @use-aistack/cli@latest sync --auto || npx -y --prefer-offline @use-aistack/cli sync --auto\";\n\ninterface HookEntry {\n\ttype: string;\n\tcommand?: string;\n\tasync?: boolean;\n}\n\ninterface HookMatcher {\n\tmatcher?: string;\n\thooks?: HookEntry[];\n}\n\ninterface ClaudeSettings {\n\thooks?: Record<string, HookMatcher[]>;\n\t[key: string]: unknown;\n}\n\n/** Recognize our hook across versions: package name plus the auto flag. */\nfunction isOurs(entry: HookEntry): boolean {\n\treturn (\n\t\ttypeof entry.command === \"string\" &&\n\t\tentry.command.includes(\"@use-aistack/cli\") &&\n\t\tentry.command.includes(\"sync --auto\")\n\t);\n}\n\nexport interface HookResult {\n\tok: boolean;\n\tmessage: string;\n}\n\nfunction readClaudeSettings(\n\tfile: string,\n): { settings: ClaudeSettings } | { error: string } {\n\tif (!existsSync(file)) return { settings: {} };\n\ttry {\n\t\tconst raw = JSON.parse(readFileSync(file, \"utf-8\"));\n\t\tif (raw && typeof raw === \"object\" && !Array.isArray(raw)) {\n\t\t\treturn { settings: raw as ClaudeSettings };\n\t\t}\n\t\treturn { error: `${file} does not hold a JSON object` };\n\t} catch {\n\t\t// Never rewrite a file we cannot parse — it is the user's Claude Code\n\t\t// configuration, and a rewrite would destroy whatever is in it.\n\t\treturn { error: `${file} is not valid JSON — fix it, then retry` };\n\t}\n}\n\n/**\n * Add the SessionStart auto-sync hook. Idempotent: an existing aistack\n * auto-sync entry (any version of the command) is replaced, not duplicated.\n * All other hooks are preserved byte-for-byte in structure.\n */\nexport function installAutoSyncHook(\n\tfile: string = CLAUDE_SETTINGS_FILE,\n): HookResult {\n\tconst read = readClaudeSettings(file);\n\tif (\"error\" in read) return { ok: false, message: read.error };\n\tconst settings = read.settings;\n\n\tconst hooks = settings.hooks ?? {};\n\tconst sessionStart = Array.isArray(hooks.SessionStart)\n\t\t? hooks.SessionStart\n\t\t: [];\n\n\tconst kept = sessionStart\n\t\t.map((m) => ({\n\t\t\t...m,\n\t\t\thooks: (m.hooks ?? []).filter((h) => !isOurs(h)),\n\t\t}))\n\t\t.filter((m) => (m.hooks?.length ?? 0) > 0);\n\n\tkept.push({\n\t\thooks: [{ type: \"command\", command: AUTO_SYNC_HOOK_COMMAND, async: true }],\n\t});\n\n\tsettings.hooks = { ...hooks, SessionStart: kept };\n\tmkdirSync(dirname(file), { recursive: true });\n\twriteFileSync(file, `${JSON.stringify(settings, null, 2)}\\n`);\n\treturn { ok: true, message: `SessionStart hook written to ${file}` };\n}\n\n/**\n * Remove only our hook. Other SessionStart hooks and other events stay. A\n * missing file or an absent hook is success — the goal state already holds.\n */\nexport function removeAutoSyncHook(\n\tfile: string = CLAUDE_SETTINGS_FILE,\n): HookResult {\n\tif (!existsSync(file)) return { ok: true, message: \"no hook to remove\" };\n\tconst read = readClaudeSettings(file);\n\tif (\"error\" in read) return { ok: false, message: read.error };\n\tconst settings = read.settings;\n\n\tconst sessionStart = settings.hooks?.SessionStart;\n\tif (!Array.isArray(sessionStart)) {\n\t\treturn { ok: true, message: \"no hook to remove\" };\n\t}\n\n\tconst kept = sessionStart\n\t\t.map((m) => ({\n\t\t\t...m,\n\t\t\thooks: (m.hooks ?? []).filter((h) => !isOurs(h)),\n\t\t}))\n\t\t.filter((m) => (m.hooks?.length ?? 0) > 0);\n\n\tconst hooks = { ...settings.hooks };\n\tif (kept.length > 0) {\n\t\thooks.SessionStart = kept;\n\t} else {\n\t\tdelete hooks.SessionStart;\n\t}\n\tif (Object.keys(hooks).length > 0) {\n\t\tsettings.hooks = hooks;\n\t} else {\n\t\tdelete settings.hooks;\n\t}\n\n\twriteFileSync(file, `${JSON.stringify(settings, null, 2)}\\n`);\n\treturn { ok: true, message: `hook removed from ${file}` };\n}\n\n/** Is the auto-sync hook present? Used by status reporting. */\nexport function autoSyncHookInstalled(\n\tfile: string = CLAUDE_SETTINGS_FILE,\n): boolean {\n\tconst read = readClaudeSettings(file);\n\tif (\"error\" in read) return false;\n\tconst sessionStart = read.settings.hooks?.SessionStart;\n\tif (!Array.isArray(sessionStart)) return false;\n\treturn sessionStart.some((m) => (m.hooks ?? []).some((h) => isOurs(h)));\n}\n","// `sync --auto` — the silent background run (#62, map #60).\n//\n// The tenets from map #29 hold: passive analysis, never passive publish. The\n// standing opt-in (`autoSync.enabled` in ~/.config/aistack/settings.json) is\n// the ONLY thing that lets this path publish, and the user can revoke it with\n// one command. No prompts, no upsells, no email, no dialogs. The escalation\n// ladder is: one log line per run → the next interactive sync reports the last\n// result → after 3 consecutive failures, one visible systemMessage line.\n//\n// This function never sets a nonzero exit code. The hook command falls back to\n// the npx cache on `||`, and a nonzero exit from a mere sync failure would\n// fire that fallback and run the whole sync twice.\n\nimport {\n\tappendFileSync,\n\tmkdirSync,\n\treadFileSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { syncPublish } from \"../api.js\";\nimport {\n\ttype AutoSyncState,\n\tDEFAULT_FREQUENCY_HOURS,\n\tgetSettings,\n\tsaveSettings,\n} from \"../config.js\";\nimport { stageSync } from \"../sync/stage.js\";\n\nexport const SYNC_LOG_FILE = join(homedir(), \".config\", \"aistack\", \"sync.log\");\n\n/** The log stays small: newest 200 lines, older lines fall off. */\nexport const SYNC_LOG_MAX_LINES = 200;\n\n/** The one-line fix, named in the escalation message and nowhere vaguer. */\nconst FIX_COMMAND = \"npx @use-aistack/cli sync\";\n\nexport type AutoSyncDeps = {\n\tbaseUrl: string;\n\tnow?: () => number;\n\tsettingsFile?: string;\n\tlogFile?: string;\n\tstageImpl?: typeof stageSync;\n\tpublishImpl?: typeof syncPublish;\n\t/** Where the systemMessage JSON goes. Defaults to stdout. */\n\temit?: (line: string) => void;\n};\n\nexport function appendLogLine(file: string, line: string): void {\n\tmkdirSync(dirname(file), { recursive: true });\n\tappendFileSync(file, `${line}\\n`);\n\tconst lines = readFileSync(file, \"utf-8\").split(\"\\n\").filter(Boolean);\n\tif (lines.length > SYNC_LOG_MAX_LINES) {\n\t\twriteFileSync(file, `${lines.slice(-SYNC_LOG_MAX_LINES).join(\"\\n\")}\\n`);\n\t}\n}\n\nexport async function runAutoSync(deps: AutoSyncDeps): Promise<void> {\n\tconst now = (deps.now ?? Date.now)();\n\tconst settingsFile = deps.settingsFile;\n\tconst logFile = deps.logFile ?? SYNC_LOG_FILE;\n\tconst emit =\n\t\tdeps.emit ?? ((line: string) => process.stdout.write(`${line}\\n`));\n\tconst stamp = new Date(now).toISOString();\n\n\tconst settings = getSettings(settingsFile);\n\tconst config = settings.autoSync;\n\n\t// The hard gate. A hook left behind after a revoke publishes nothing.\n\tif (config?.enabled !== true) {\n\t\tappendLogLine(logFile, `${stamp} skipped — auto-sync is not enabled`);\n\t\treturn;\n\t}\n\n\t// The freshness gate keys on the last ATTEMPT, not the last success. A\n\t// broken setup then retries once per frequency window, not once per\n\t// session start, and still reaches the 3-failure escalation.\n\tconst frequencyHours = config.frequencyHours || DEFAULT_FREQUENCY_HOURS;\n\tconst state: AutoSyncState = settings.autoSyncState ?? {};\n\tconst lastRunAt = state.lastRunAt ?? 0;\n\tif (now - lastRunAt < frequencyHours * 3_600_000) return;\n\n\tconst stage = deps.stageImpl ?? stageSync;\n\tconst publish = deps.publishImpl ?? syncPublish;\n\n\tlet failure: string | null = null;\n\tlet url: string | undefined;\n\ttry {\n\t\tconst staged = await stage({ baseUrl: deps.baseUrl, now: () => now });\n\t\tif (staged.blockedReason !== null) {\n\t\t\tfailure = staged.blockedReason;\n\t\t} else {\n\t\t\tconst res = await publish(staged.token as string, staged.bodyJson);\n\t\t\turl = res.url;\n\t\t}\n\t} catch (e) {\n\t\tfailure = e instanceof Error ? e.message : String(e);\n\t}\n\n\tif (failure === null) {\n\t\tsaveSettings(\n\t\t\t{\n\t\t\t\tautoSyncState: {\n\t\t\t\t\tlastRunAt: now,\n\t\t\t\t\tlastSuccessAt: now,\n\t\t\t\t\tlastResult: `ok — published at ${stamp}`,\n\t\t\t\t\tconsecutiveFailures: 0,\n\t\t\t\t\tfailureWarned: false,\n\t\t\t\t},\n\t\t\t},\n\t\t\tsettingsFile,\n\t\t);\n\t\tappendLogLine(logFile, `${stamp} ok — published${url ? ` ${url}` : \"\"}`);\n\t\treturn;\n\t}\n\n\tconst consecutiveFailures = (state.consecutiveFailures ?? 0) + 1;\n\tconst shouldWarn = consecutiveFailures >= 3 && state.failureWarned !== true;\n\tsaveSettings(\n\t\t{\n\t\t\tautoSyncState: {\n\t\t\t\t...state,\n\t\t\t\tlastRunAt: now,\n\t\t\t\tlastResult: `failed at ${stamp} — ${failure}`,\n\t\t\t\tconsecutiveFailures,\n\t\t\t\tfailureWarned: state.failureWarned === true || shouldWarn,\n\t\t\t},\n\t\t},\n\t\tsettingsFile,\n\t);\n\tappendLogLine(\n\t\tlogFile,\n\t\t`${stamp} fail (${consecutiveFailures} in a row) — ${failure}`,\n\t);\n\n\t// One visible line, once per failure streak. SessionStart hook JSON:\n\t// Claude Code shows `systemMessage` to the user when the async hook lands.\n\tif (shouldWarn) {\n\t\temit(\n\t\t\tJSON.stringify({\n\t\t\t\tsystemMessage: `aistack auto-sync failed ${consecutiveFailures} times in a row (${failure}). Run \\`${FIX_COMMAND}\\` in a terminal to fix it, or \\`${FIX_COMMAND} --auto off\\` to stop these runs.`,\n\t\t\t}),\n\t\t);\n\t}\n}\n","// Stage one send: scan every detected harness → build → derive the gate's\n// text from the exact bytes.\n//\n// Wayfinder ticket #41 (map #29), widened to the adapter seam by #67 (map\n// #60). The staged `bodyJson` string IS what a publish transmits — the summary\n// and the dialog are derived from it and from nothing else, so the user can\n// never approve a sentence about different bytes (#35's binding constraint).\n// The publish tool takes only the stage id; it can name WHICH staged send to\n// release, never what is in it.\n//\n// One stage covers ALL detected harnesses (#66 decision 4): the payloads ride\n// in one request so the server can land them atomically, and the kept-private\n// union is one list because consent is per name, not per harness.\n\nimport { createHash } from \"node:crypto\";\nimport { getToken } from \"../config.js\";\nimport { detectedAdapters } from \"../harness/index.js\";\nimport {\n\ttype KeptPrivateAtom,\n\ttype LoadedSyncConfig,\n\tloadSyncConfig,\n\ttype NameCategory,\n\ttype SyncConfig,\n} from \"../harness/shared/allowlist.js\";\nimport {\n\ttype BuiltPayload,\n\tbuildPayload,\n\tbuildSyncBody,\n\tmergeKeptPrivate,\n\ttype SyncBody,\n} from \"../harness/shared/payload.js\";\nimport {\n\tDEFAULT_WINDOW_DAYS,\n\twindowStartMs,\n} from \"../harness/shared/window.js\";\nimport type { HarnessAdapter } from \"../harness/types.js\";\nimport { buildGateDialog, buildGateSummary } from \"./summary.js\";\n\nexport type StagedSend = {\n\t/** Content-derived: the sha256 prefix of `bodyJson`. Same bytes, same id. */\n\tid: string;\n\t/** The exact request body a publish sends, already serialized. */\n\tbodyJson: string;\n\tbody: SyncBody;\n\tkeptPrivate: Record<NameCategory, KeptPrivateAtom[]>;\n\tsummary: string;\n\tdialog: string;\n\tconfig: SyncConfig;\n\ttoken: string | null;\n\tstagedAt: number;\n\t/**\n\t * `null` when this stage may not publish, with `blockedReason` saying why.\n\t * A gate that cannot name its destination must not send (#33 decision 7),\n\t * so no token and no resolved stack both block here, before any dialog.\n\t */\n\tblockedReason: string | null;\n};\n\nexport type StageDeps = {\n\tbaseUrl: string;\n\tnow?: () => number;\n\tgetTokenImpl?: () => string | null;\n\tloadConfigImpl?: (opts: {\n\t\tbaseUrl: string;\n\t\ttoken?: string;\n\t}) => Promise<LoadedSyncConfig>;\n\t/** Override the adapter set. Tests only. */\n\tadaptersImpl?: () => Promise<HarnessAdapter[]>;\n\twindowDays?: number;\n};\n\nexport function stageId(bodyJson: string): string {\n\treturn createHash(\"sha256\").update(bodyJson).digest(\"hex\").slice(0, 12);\n}\n\nexport async function stageSync(deps: StageDeps): Promise<StagedSend> {\n\tconst now = (deps.now ?? Date.now)();\n\tconst token = (deps.getTokenImpl ?? getToken)();\n\tconst loadConfig = deps.loadConfigImpl ?? loadSyncConfig;\n\tconst adapters = deps.adaptersImpl ?? detectedAdapters;\n\tconst windowDays = deps.windowDays ?? DEFAULT_WINDOW_DAYS;\n\n\tconst { config, source } = await loadConfig({\n\t\tbaseUrl: deps.baseUrl,\n\t\t...(token ? { token } : {}),\n\t});\n\n\tconst built: BuiltPayload[] = [];\n\tconst sinceMs = windowStartMs(now, windowDays);\n\tfor (const adapter of await adapters()) {\n\t\tconst { aggregate, stats } = await adapter.scan({ sinceMs });\n\t\tbuilt.push(\n\t\t\tbuildPayload({\n\t\t\t\taggregate,\n\t\t\t\tstats,\n\t\t\t\tsyncConfig: config,\n\t\t\t\tnow,\n\t\t\t\twindowDays,\n\t\t\t\tharnessName: adapter.name,\n\t\t\t\tbuiltinTools: adapter.builtinTools,\n\t\t\t\tpricingTableVersion: adapter.pricingTableVersion,\n\t\t\t}),\n\t\t);\n\t}\n\n\tconst body = buildSyncBody(built, config);\n\tconst bodyJson = JSON.stringify(body);\n\tconst keptPrivate = mergeKeptPrivate(built.map((b) => b.keptPrivate));\n\n\tconst ctx = {\n\t\tbody,\n\t\tkeptPrivate,\n\t\tconfig,\n\t\tsource,\n\t\tbaseUrl: deps.baseUrl,\n\t};\n\n\tlet blockedReason: string | null = null;\n\tif (built.length === 0) {\n\t\tblockedReason =\n\t\t\t\"No supported harness was found on this machine — no Claude Code and no Codex logs to read.\";\n\t} else if (token === null) {\n\t\tblockedReason =\n\t\t\t\"This machine is not linked. Run `npx @use-aistack/cli login` first.\";\n\t} else if (config.stack === null) {\n\t\tblockedReason =\n\t\t\tsource === \"bundled\"\n\t\t\t\t? \"Could not fetch your settings from aistack, so the destination stack is unknown. Publish needs it. Check the network and preview again.\"\n\t\t\t\t: \"The token resolves no destination stack. Run `npx @use-aistack/cli login` again to re-link this machine.\";\n\t}\n\n\treturn {\n\t\tid: stageId(bodyJson),\n\t\tbodyJson,\n\t\tbody,\n\t\tkeptPrivate,\n\t\tsummary: buildGateSummary(ctx),\n\t\tdialog: buildGateDialog(ctx),\n\t\tconfig,\n\t\ttoken,\n\t\tstagedAt: now,\n\t\tblockedReason,\n\t};\n}\n","// The Claude Code harness behind the seam (#67). The parsing lives in\n// analyzer.ts/scan.ts, unchanged from the single-harness era; this file only\n// gives it the adapter shape.\n\nimport { stat } from \"node:fs/promises\";\nimport { BUILTIN_TOOLS } from \"../shared/allowlist.js\";\nimport { PRICING_TABLE_VERSION } from \"../shared/pricing.js\";\nimport type {\n\tHarnessAdapter,\n\tHarnessScan,\n\tHarnessScanOptions,\n} from \"../types.js\";\nimport { createAggregate } from \"./analyzer.js\";\nimport { scan, transcriptRoots } from \"./scan.js\";\n\nexport const CLAUDE_HARNESS_NAME = \"claude-code\";\n\nasync function exists(p: string): Promise<boolean> {\n\ttry {\n\t\tawait stat(p);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport const claudeAdapter: HarnessAdapter = {\n\tname: CLAUDE_HARNESS_NAME,\n\tbuiltinTools: BUILTIN_TOOLS,\n\tpricingTableVersion: PRICING_TABLE_VERSION,\n\n\tasync detect(): Promise<boolean> {\n\t\tfor (const root of transcriptRoots()) {\n\t\t\tif (await exists(root)) return true;\n\t\t}\n\t\treturn false;\n\t},\n\n\tasync scan(opts: HarnessScanOptions): Promise<HarnessScan> {\n\t\tconst aggregate = createAggregate();\n\t\tconst stats = await scan(aggregate, {\n\t\t\tsinceMs: opts.sinceMs,\n\t\t\t...(opts.onProgress ? { onProgress: opts.onProgress } : {}),\n\t\t});\n\t\treturn { aggregate, stats };\n\t},\n};\n","// Time-aware pinned price table for API-equivalent cost.\n//\n// Wayfinder ticket #37 (map #29), decision 8 of the wire-format grilling #33.\n//\n// WHY THIS IS A LIST OF PERIODS AND NOT A FLAT MAP\n// A published \"API-equivalent cost\" covers a rolling 30-day window, and a\n// window can straddle a repricing. On 2026-09-05 the window covers Aug 6 →\n// Sep 5, but `claude-sonnet-5`'s introductory rate ends Aug 31 — so 25 days\n// price at $2/$10 and 5 days at $3/$15. A flat table misprices one side or the\n// other for a month after every repricing, which breaks the honesty tenet the\n// measured layer is built on.\n//\n// So each model's price is a list of effective-from ranges, and every response\n// is priced at the rate in effect at ITS OWN timestamp. Cost therefore has to\n// accumulate at ingest (see analyzer.ts) — summing tokens per model and pricing\n// once at the end cannot express a mid-window rate change.\n//\n// Sources: Anthropic public list prices as of 2026-07-25 (cache multipliers\n// from https://platform.claude.com/docs/en/build-with-claude/prompt-caching:\n// 5m cache write = 1.25x input, 1h cache write = 2x input, read = 0.1x input)\n// and OpenAI public list prices as of 2026-08-01\n// (https://developers.openai.com/api/docs/pricing — cached input is 10% of\n// input, the same multiplier `cacheRead` already uses; Codex reports no cache\n// writes, so the write multipliers never fire for OpenAI rows).\n//\n// Each harness's payload is stamped with ITS vendor's table id — the id is a\n// citation for the dollars in that payload, and one payload never mixes\n// vendors.\n\nexport const PRICING_TABLE_VERSION = \"anthropic-list-2026-07-25\";\nexport const OPENAI_PRICING_TABLE_VERSION = \"openai-list-2026-08-01\";\n\nexport const CACHE_WRITE_5M_MULTIPLIER = 1.25;\nexport const CACHE_WRITE_1H_MULTIPLIER = 2.0;\nexport const CACHE_READ_MULTIPLIER = 0.1;\n\n/**\n * End of the `claude-sonnet-5` introductory rate. Anthropic documents it as \"in\n * effect through 2026-08-31\", so the post-intro period opens at the following\n * UTC midnight.\n *\n * The boundary is approximated in UTC because the announcement names a date,\n * not a timezone. A response written within a few hours of the boundary can\n * therefore be priced on the wrong side of it — worth a handful of cents on a\n * single day, and the alternative (guessing US/Pacific) is no more defensible.\n */\nexport const SONNET_5_INTRO_ENDS_MS = Date.UTC(2026, 8, 1); // 2026-09-01T00:00:00Z\n\n/** USD per million tokens, valid over `[from, to)`. */\nexport type PricePeriod = {\n\t/** Inclusive lower bound, epoch ms. `null` = since the model existed. */\n\tfrom: number | null;\n\t/** Exclusive upper bound, epoch ms. `null` = still in effect. */\n\tto: number | null;\n\tinput: number;\n\toutput: number;\n};\n\n/**\n * Only rates we can actually cite are encoded. Inventing historical periods to\n * make the table look complete would fabricate cost for old records, so every\n * model with one known rate gets one open-ended period.\n */\nconst PRICES: Record<string, PricePeriod[]> = {\n\t\"claude-fable-5\": [{ from: null, to: null, input: 10, output: 50 }],\n\t\"claude-mythos-5\": [{ from: null, to: null, input: 10, output: 50 }],\n\t\"claude-opus-5\": [{ from: null, to: null, input: 5, output: 25 }],\n\t\"claude-opus-4-8\": [{ from: null, to: null, input: 5, output: 25 }],\n\t\"claude-opus-4-7\": [{ from: null, to: null, input: 5, output: 25 }],\n\t\"claude-opus-4-6\": [{ from: null, to: null, input: 5, output: 25 }],\n\t\"claude-sonnet-5\": [\n\t\t{ from: null, to: SONNET_5_INTRO_ENDS_MS, input: 2, output: 10 },\n\t\t{ from: SONNET_5_INTRO_ENDS_MS, to: null, input: 3, output: 15 },\n\t],\n\t\"claude-sonnet-4-6\": [{ from: null, to: null, input: 3, output: 15 }],\n\t\"claude-haiku-4-5\": [{ from: null, to: null, input: 1, output: 5 }],\n\t// Fast mode (research preview) — Claude API only, Opus 5 / Opus 4.8 only.\n\t// Opus 4.7 fast mode was removed, so there is deliberately no 4-7 entry.\n\t\"claude-opus-5#fast\": [{ from: null, to: null, input: 10, output: 50 }],\n\t\"claude-opus-4-8#fast\": [{ from: null, to: null, input: 10, output: 50 }],\n\t// OpenAI (Codex) — standard-context tier (<272K; observed context window is\n\t// 258,400). gpt-5.3-codex and the 5.6 line have NO published price yet, so\n\t// they are deliberately absent and surface as unpriced (#66 decision 6).\n\t\"gpt-5.5\": [{ from: null, to: null, input: 5, output: 30 }],\n\t\"gpt-5.4\": [{ from: null, to: null, input: 2.5, output: 15 }],\n\t\"gpt-5.4-mini\": [{ from: null, to: null, input: 0.75, output: 4.5 }],\n};\n\nexport type TokenCounts = {\n\tinput: number;\n\toutput: number;\n\tcacheWrite5m: number;\n\tcacheWrite1h: number;\n\t/** `cache_creation_input_tokens` not covered by the TTL breakdown; priced at the 5m rate. */\n\tcacheWriteUnsplit: number;\n\tcacheRead: number;\n};\n\n/**\n * Normalize an observed `message.model` into a pricing key. Handles the\n * dated-suffix variants (`claude-haiku-4-5-20251001`). The `#fast` suffix is\n * appended by the caller from `usage.speed`.\n */\nexport function normalizeModel(model: string): string {\n\tconst [base, suffix] = model.split(\"#\");\n\tconst stripped = base.replace(/-\\d{8}$/, \"\");\n\treturn suffix ? `${stripped}#${suffix}` : stripped;\n}\n\n/** Drop the analyzer's synthetic `#fast` suffix, leaving the vendor-assigned id. */\nexport function baseModelId(modelKey: string): string {\n\treturn modelKey.split(\"#\")[0];\n}\n\n/**\n * The rate in effect for `modelKey` at `atMs`, or `null` when the model is\n * unknown or the timestamp predates every period we can cite.\n *\n * A `null` timestamp also yields `null`: a record with no parseable timestamp\n * cannot be priced time-awarely, and inventing a price for it (say, today's)\n * would silently attribute the wrong rate. Its tokens surface as unpriced.\n */\nexport function priceAt(\n\tmodelKey: string,\n\tatMs: number | null,\n): PricePeriod | null {\n\tif (atMs === null) return null;\n\tconst periods = PRICES[modelKey];\n\tif (!periods) return null;\n\tfor (const p of periods) {\n\t\tif ((p.from === null || atMs >= p.from) && (p.to === null || atMs < p.to)) {\n\t\t\treturn p;\n\t\t}\n\t}\n\treturn null;\n}\n\n/** True when we hold at least one citable rate for this model, at any time. */\nexport function isPricedModel(modelKey: string): boolean {\n\treturn PRICES[modelKey] !== undefined;\n}\n\n/**\n * Cost of one response's tokens at the rate in effect at its own timestamp.\n * Returns `null` when no rate applies — the caller must surface that as\n * unpriced tokens rather than zeroing it.\n */\nexport function apiEquivalentCost(\n\tmodelKey: string,\n\tt: TokenCounts,\n\tatMs: number | null,\n): number | null {\n\tconst p = priceAt(modelKey, atMs);\n\tif (!p) return null;\n\tconst M = 1_000_000;\n\treturn (\n\t\t(t.input * p.input +\n\t\t\tt.output * p.output +\n\t\t\t(t.cacheWrite5m + t.cacheWriteUnsplit) *\n\t\t\t\tp.input *\n\t\t\t\tCACHE_WRITE_5M_MULTIPLIER +\n\t\t\tt.cacheWrite1h * p.input * CACHE_WRITE_1H_MULTIPLIER +\n\t\t\tt.cacheRead * p.input * CACHE_READ_MULTIPLIER) /\n\t\tM\n\t);\n}\n","// Harness-agnostic aggregate machinery: the fold target every adapter fills,\n// and the finalize step that turns it into display-ready rows.\n//\n// Extracted from the Claude analyzer by ticket #67 (map #60) so the Codex\n// adapter can reuse the same totals, name hygiene, and model rows without\n// inheriting Claude's record-dedup logic. Everything here is pure — no I/O,\n// no console.\n\nimport { isPricedModel, type TokenCounts } from \"./pricing.js\";\n\n// ---------------------------------------------------------------------------\n// Narrowing helpers — records are untrusted external JSON\n// ---------------------------------------------------------------------------\n\nexport type Obj = Record<string, unknown>;\n\nexport const asObj = (v: unknown): Obj | null =>\n\ttypeof v === \"object\" && v !== null && !Array.isArray(v) ? (v as Obj) : null;\nexport const asStr = (v: unknown): string | null =>\n\ttypeof v === \"string\" && v.length > 0 ? v : null;\nexport const asNum = (v: unknown): number =>\n\ttypeof v === \"number\" && Number.isFinite(v) ? v : 0;\nexport const asArr = (v: unknown): unknown[] => (Array.isArray(v) ? v : []);\n\n/**\n * Every name that becomes a Map key or leaves this module goes through here.\n *\n * These are user-chosen strings (skill names, MCP servers, subagent types,\n * slash commands, model ids) and a hostile one is a real vector: control\n * characters move a terminal cursor, and an unterminated bidi override (U+202E)\n * reorders the rest of the rendered line — including the count and percentage\n * printed beside the name. Both survive `JSON.stringify`, which escapes C0 but\n * not bidi. See CVE-2021-42574 (\"Trojan Source\").\n *\n * Sanitizing at ingest rather than at print means the guarantee travels with\n * the module: `finalize()`'s output is safe for any consumer, not just the\n * renderer that happens to sit in front of it today.\n */\nconst NAME_UNSAFE_RE =\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: stripping them is the point\n\t/[\\u0000-\\u001f\\u007f-\\u009f\\u00ad\\u061c\\u200b-\\u200f\\u2028-\\u202e\\u2060-\\u2064\\u2066-\\u2069\\ufeff]/g;\nconst NAME_MAX = 64;\n\nexport function cleanName(s: string): string {\n\tconst stripped = s.replace(NAME_UNSAFE_RE, \"�\").trim();\n\tif (stripped.length === 0) return \"(unnamed)\";\n\treturn stripped.length > NAME_MAX\n\t\t? `${stripped.slice(0, NAME_MAX - 1)}…`\n\t\t: stripped;\n}\n\n/**\n * The same bar as `cleanName`, asked as a question.\n *\n * Used on names arriving from the NETWORK — the per-stack opt-ins the sync\n * config carries (#44). Those are the user's own strings, so the curated list's\n * conventional charset is the wrong bar: parentheses, accents and CJK are all\n * legitimate names someone runs. What is refused is what cannot be rendered\n * safely, which is exactly what `cleanName` strips on the way in.\n */\nexport function isDisplaySafeName(s: string): boolean {\n\tif (s.length === 0 || s.trim().length === 0) return false;\n\tif (s.length > NAME_MAX) return false;\n\t// A `g`-flagged regex carries `lastIndex` across `.test` calls, so this uses\n\t// a fresh non-global copy rather than the shared literal.\n\treturn !new RegExp(NAME_UNSAFE_RE.source).test(s);\n}\n\n/** `asStr` for anything that will be used as a name. */\nexport const asName = (v: unknown): string | null => {\n\tconst s = asStr(v);\n\treturn s === null ? null : cleanName(s);\n};\n\n// ---------------------------------------------------------------------------\n// Aggregate\n// ---------------------------------------------------------------------------\n\nexport type ModelUsage = TokenCounts & {\n\tmessages: number;\n\t/**\n\t * API-equivalent cost accumulated per response at that response's own rate\n\t * (#33 decision 8). Not derivable from the token totals above once a window\n\t * straddles a repricing.\n\t */\n\tcostUSD: number;\n\t/** Tokens whose own timestamp had no citable rate. Surfaced, never zeroed. */\n\tunpricedTokens: number;\n};\n\n/**\n * The fold target. `Seen` is the adapter's own dedup bookkeeping type —\n * Claude keys responses by `message.id`, Codex needs none — kept generic so\n * the shared shape does not import any one harness's record semantics.\n */\nexport type Aggregate<Seen = unknown> = {\n\t// provenance / scan health\n\tfiles: number;\n\tlines: number;\n\tparseErrors: number;\n\trecords: number;\n\tassistantRecords: number;\n\t/** Distinct API responses actually counted. */\n\tdistinctResponses: number;\n\t/** Extra records of a response already counted (same message.id AND requestId). */\n\tcontinuationsFolded: number;\n\t/** Same message.id under a NEW requestId — a genuine replay (e.g. /btw sidechain). */\n\trealReplaysFolded: number;\n\t/** Times a later record superseded an earlier one because it carried a larger total. */\n\tsupersededByLarger: number;\n\t/** Assistant records with no message.id — counted without dedup protection. */\n\tunkeyedResponses: number;\n\tsyntheticRecords: number;\n\tsyntheticTokens: number;\n\ttoolBlocksWithoutId: number;\n\t/** Responses whose first attempt ran on a different model (#33 decision 9). */\n\tfallbackAttempts: number;\n\tuntypedMirrors: number;\n\t/** Records with no parseable timestamp — cannot be priced time-awarely. */\n\tuntimestampedResponses: number;\n\tprojectDirs: Set<string>; // held only to count — names never leave this module\n\tccVersions: Set<string>;\n\tmirroredIterationTypes: Map<string, number>;\n\n\t// tokens\n\tbyModel: Map<string, ModelUsage>;\n\tsidechainTokens: number;\n\tmainTokens: number;\n\n\t// activity\n\tsessions: Set<string>;\n\tactiveDays: Set<string>; // UTC YYYY-MM-DD\n\tfirstTs: number | null;\n\tlastTs: number | null;\n\n\t// tools / skills / mcp / agents\n\ttoolCalls: Map<string, number>;\n\tskillCalls: Map<string, number>;\n\tmcpServerCalls: Map<string, number>;\n\tmcpToolCalls: Map<string, number>;\n\tsubagentCalls: Map<string, number>;\n\tslashCommands: Map<string, number>;\n\ttoolCallDedup: Set<string>;\n\n\t// content-block shape\n\tthinkingBlocks: number;\n\ttextBlocks: number;\n\twebSearchRequests: number;\n\twebFetchRequests: number;\n\n\t// adapter-owned dedup bookkeeping\n\tseen: Map<string, Seen>;\n};\n\nexport function createAggregate<Seen = unknown>(): Aggregate<Seen> {\n\treturn {\n\t\tfiles: 0,\n\t\tlines: 0,\n\t\tparseErrors: 0,\n\t\trecords: 0,\n\t\tassistantRecords: 0,\n\t\tdistinctResponses: 0,\n\t\tcontinuationsFolded: 0,\n\t\trealReplaysFolded: 0,\n\t\tsupersededByLarger: 0,\n\t\tunkeyedResponses: 0,\n\t\tsyntheticRecords: 0,\n\t\tsyntheticTokens: 0,\n\t\ttoolBlocksWithoutId: 0,\n\t\tfallbackAttempts: 0,\n\t\tuntypedMirrors: 0,\n\t\tuntimestampedResponses: 0,\n\t\tprojectDirs: new Set(),\n\t\tccVersions: new Set(),\n\t\tmirroredIterationTypes: new Map(),\n\t\tbyModel: new Map(),\n\t\tsidechainTokens: 0,\n\t\tmainTokens: 0,\n\t\tsessions: new Set(),\n\t\tactiveDays: new Set(),\n\t\tfirstTs: null,\n\t\tlastTs: null,\n\t\ttoolCalls: new Map(),\n\t\tskillCalls: new Map(),\n\t\tmcpServerCalls: new Map(),\n\t\tmcpToolCalls: new Map(),\n\t\tsubagentCalls: new Map(),\n\t\tslashCommands: new Map(),\n\t\ttoolCallDedup: new Set(),\n\t\tthinkingBlocks: 0,\n\t\ttextBlocks: 0,\n\t\twebSearchRequests: 0,\n\t\twebFetchRequests: 0,\n\t\tseen: new Map(),\n\t};\n}\n\nexport const bump = (m: Map<string, number>, k: string, n = 1) =>\n\tm.set(k, (m.get(k) ?? 0) + n);\n\nexport function emptyUsage(): ModelUsage {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheWrite5m: 0,\n\t\tcacheWrite1h: 0,\n\t\tcacheWriteUnsplit: 0,\n\t\tcacheRead: 0,\n\t\tmessages: 0,\n\t\tcostUSD: 0,\n\t\tunpricedTokens: 0,\n\t};\n}\n\nexport const countsTotal = (t: TokenCounts): number =>\n\tt.input +\n\tt.output +\n\tt.cacheWrite5m +\n\tt.cacheWrite1h +\n\tt.cacheWriteUnsplit +\n\tt.cacheRead;\n\n/**\n * Fold one priced usage delta into the per-model totals. The Claude adapter\n * has its own apply/retract pair (dedup can un-count a response); an adapter\n * whose records are already deltas — Codex — adds through here.\n */\nexport function addModelUsage(\n\tagg: Aggregate<never> | Aggregate<unknown>,\n\tmodelKey: string,\n\tcounts: TokenCounts,\n\tcostUSD: number | null,\n\tmessages = 1,\n): void {\n\tlet m = agg.byModel.get(modelKey);\n\tif (!m) {\n\t\tm = emptyUsage();\n\t\tagg.byModel.set(modelKey, m);\n\t}\n\tm.messages += messages;\n\tm.input += counts.input;\n\tm.output += counts.output;\n\tm.cacheWrite5m += counts.cacheWrite5m;\n\tm.cacheWrite1h += counts.cacheWrite1h;\n\tm.cacheWriteUnsplit += counts.cacheWriteUnsplit;\n\tm.cacheRead += counts.cacheRead;\n\tif (costUSD === null) m.unpricedTokens += countsTotal(counts);\n\telse m.costUSD += costUSD;\n}\n\n// ---------------------------------------------------------------------------\n// Finalize — the shape the wire payload is derived from\n// ---------------------------------------------------------------------------\n\nexport type ModelRow = {\n\t/** Pricing key: normalized vendor id, plus `#fast` when speed was fast. */\n\tmodelKey: string;\n\ttokens: TokenCounts;\n\ttotalTokens: number;\n\tmessages: number;\n\tshare: number;\n\t/** Accumulated at each response's own rate. `null` when nothing was priced. */\n\tcostUSD: number | null;\n\t/** Tokens inside this row that no rate covered. */\n\tunpricedTokens: number;\n};\n\nexport type Finalized = {\n\tmodels: ModelRow[];\n\ttotalTokens: number;\n\ttotalCostUSD: number;\n\tunpricedModels: string[];\n\tunpricedTokens: number;\n\tcacheHitShare: number;\n\tsidechainShare: number;\n\tactiveDays: number;\n\tfirstTs: number | null;\n\tlastTs: number | null;\n\tsessions: number;\n\tprojects: number;\n\ttools: Array<[string, number]>;\n\tskills: Array<[string, number]>;\n\tmcpServers: Array<[string, number]>;\n\tsubagents: Array<[string, number]>;\n\tslashCommands: Array<[string, number]>;\n\ttotalToolCalls: number;\n\t/** Newest harness version observed, or null when none was recorded. */\n\tharnessVersion: string | null;\n};\n\nfunction buildModelRows(agg: Aggregate): {\n\trows: ModelRow[];\n\ttotalTokens: number;\n\ttotalCostUSD: number;\n\tunpricedModels: string[];\n\tunpricedTokens: number;\n} {\n\tconst rows: ModelRow[] = [];\n\tlet totalTokens = 0;\n\tlet totalCostUSD = 0;\n\tconst unpricedModels: string[] = [];\n\tlet unpricedTokens = 0;\n\n\tfor (const [modelKey, u] of agg.byModel) {\n\t\tconst tokens: TokenCounts = {\n\t\t\tinput: u.input,\n\t\t\toutput: u.output,\n\t\t\tcacheWrite5m: u.cacheWrite5m,\n\t\t\tcacheWrite1h: u.cacheWrite1h,\n\t\t\tcacheWriteUnsplit: u.cacheWriteUnsplit,\n\t\t\tcacheRead: u.cacheRead,\n\t\t};\n\t\tconst sum = countsTotal(tokens);\n\t\ttotalTokens += sum;\n\t\tif (u.unpricedTokens > 0) {\n\t\t\tunpricedModels.push(modelKey);\n\t\t\tunpricedTokens += u.unpricedTokens;\n\t\t}\n\t\ttotalCostUSD += u.costUSD;\n\t\trows.push({\n\t\t\tmodelKey,\n\t\t\ttokens,\n\t\t\ttotalTokens: sum,\n\t\t\tmessages: u.messages,\n\t\t\tshare: 0,\n\t\t\t// A model we hold no rate for at all reports null rather than $0.00,\n\t\t\t// so \"we can't price this\" never reads as \"this was free\".\n\t\t\tcostUSD: isPricedModel(modelKey) ? u.costUSD : null,\n\t\t\tunpricedTokens: u.unpricedTokens,\n\t\t});\n\t}\n\tfor (const r of rows) r.share = totalTokens ? r.totalTokens / totalTokens : 0;\n\trows.sort(\n\t\t(a, b) =>\n\t\t\tb.totalTokens - a.totalTokens || a.modelKey.localeCompare(b.modelKey),\n\t);\n\treturn { rows, totalTokens, totalCostUSD, unpricedModels, unpricedTokens };\n}\n\nfunction computeCacheHitShare(rows: ModelRow[]): number {\n\tlet cacheRead = 0;\n\tlet inputClass = 0;\n\tfor (const r of rows) {\n\t\tcacheRead += r.tokens.cacheRead;\n\t\tinputClass +=\n\t\t\tr.tokens.input +\n\t\t\tr.tokens.cacheRead +\n\t\t\tr.tokens.cacheWrite5m +\n\t\t\tr.tokens.cacheWrite1h +\n\t\t\tr.tokens.cacheWriteUnsplit;\n\t}\n\treturn inputClass ? cacheRead / inputClass : 0;\n}\n\n/**\n * Newest observed harness version, compared numerically per dotted segment\n * so `2.1.9` doesn't sort above `2.1.220`.\n */\nexport function newestVersion(versions: Iterable<string>): string | null {\n\tlet best: string | null = null;\n\tlet bestParts: number[] = [];\n\tfor (const v of versions) {\n\t\tconst parts = v.split(\".\").map((p) => Number.parseInt(p, 10));\n\t\tif (parts.some((n) => !Number.isFinite(n))) continue;\n\t\tif (best === null || compareParts(parts, bestParts) > 0) {\n\t\t\tbest = v;\n\t\t\tbestParts = parts;\n\t\t}\n\t}\n\treturn best;\n}\n\nfunction compareParts(a: number[], b: number[]): number {\n\tconst len = Math.max(a.length, b.length);\n\tfor (let i = 0; i < len; i++) {\n\t\tconst d = (a[i] ?? 0) - (b[i] ?? 0);\n\t\tif (d !== 0) return d;\n\t}\n\treturn 0;\n}\n\nexport function finalize(agg: Aggregate): Finalized {\n\tconst { rows, totalTokens, totalCostUSD, unpricedModels, unpricedTokens } =\n\t\tbuildModelRows(agg);\n\n\tconst byCount = (m: Map<string, number>): Array<[string, number]> =>\n\t\t[...m.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));\n\n\tlet totalToolCalls = 0;\n\tfor (const v of agg.toolCalls.values()) totalToolCalls += v;\n\tfor (const v of agg.mcpToolCalls.values()) totalToolCalls += v;\n\n\tconst sideTotal = agg.sidechainTokens + agg.mainTokens;\n\n\treturn {\n\t\tmodels: rows,\n\t\ttotalTokens,\n\t\ttotalCostUSD,\n\t\tunpricedModels,\n\t\tunpricedTokens,\n\t\tcacheHitShare: computeCacheHitShare(rows),\n\t\tsidechainShare: sideTotal ? agg.sidechainTokens / sideTotal : 0,\n\t\tactiveDays: agg.activeDays.size,\n\t\tfirstTs: agg.firstTs,\n\t\tlastTs: agg.lastTs,\n\t\tsessions: agg.sessions.size,\n\t\tprojects: agg.projectDirs.size,\n\t\ttools: byCount(agg.toolCalls),\n\t\tskills: byCount(agg.skillCalls),\n\t\tmcpServers: byCount(agg.mcpServerCalls),\n\t\tsubagents: byCount(agg.subagentCalls),\n\t\tslashCommands: byCount(agg.slashCommands),\n\t\ttotalToolCalls,\n\t\tharnessVersion: newestVersion(agg.ccVersions),\n\t};\n}\n","// The bundled curated allowlist — the fallback copy for `/api/sync-config`.\n//\n// Wayfinder ticket #37 (map #29), decision 4 of the wire-format grilling #33.\n//\n// WHAT BELONGS HERE, AND WHY IT IS SHORT\n// These four classes of name are user-chosen. A Skill called `acme-q3-pricing`,\n// an MCP server called `internal-billing`, a subagent called `client-migration`\n// — each is a real leak, and none of them is distinguishable from a public name\n// by shape.\n//\n// THE BAR (grilling #42): a name qualifies if the STRING carries no private\n// information no matter who typed it. That is a property of the string, not of\n// the user and not of the artifact.\n//\n// The bar is deliberately NOT \"the name identifies a public artifact, so\n// publishing it reveals nothing the user hasn't already published\". That was the\n// original wording and it is wrong: `stripe` is on this list, and publishing it\n// plainly does reveal something the user never published — that they use Stripe.\n// It cannot be the harm, because revealing what you use is the entire product.\n// The harm is narrower: strings drawn from the user's private vocabulary, which\n// leak a relationship (an employer, a client, a codename) rather than a\n// preference. `stripe` and `filesystem` are safe even for someone who named\n// their own server that by coincidence.\n//\n// Three sources meet that bar:\n// 1. Claude Code's own built-in subagent types and slash commands (vendor-\n// assigned, same class as a built-in tool name).\n// 2. Skills that ship with Claude Code itself.\n// 3. MCP servers with a public, documented, first-party endpoint.\n//\n// WHY THIS LIST DOES NOT NEED TO BE LONG (#42 decision 1)\n// It is no longer the only road to publishing a name. The approve gate offers\n// every kept-private name as an explicit, default-off tick, and the tick set\n// comes back down with the rest of the sync config. This list only exists to\n// spare a user from ticking boxes nobody would think twice about — so it can\n// stay strict, and every user-chosen name goes through the person who knows\n// whether it is a secret.\n//\n// The author's own `alp-river:*` plugin is deliberately NOT seeded, even though\n// it is genuinely published. This list is GLOBAL: seeding it would publish those\n// names for every user who installs the plugin without any of them ticking\n// anything, and an author adding their own names to the default everyone else\n// inherits is what would make the list untrustworthy for every other entry.\n//\n// `/api/sync-config` (ticket #38) serves the AUTHORITATIVE list. This copy only\n// covers the case where that endpoint can't be reached, which for an installed\n// user is permanent if the plugin never auto-updates. Growing the curated list\n// is server-side work; adding entries here only helps the offline case.\n\nimport type { CuratedAllowlist } from \"./allowlist.js\";\n\n/** Claude Code's own subagent types. Vendor-assigned, not user-chosen. */\nconst BUILTIN_SUBAGENTS = [\n\t\"(default)\",\n\t\"claude\",\n\t\"claude-code-guide\",\n\t\"Explore\",\n\t\"fork\",\n\t\"general-purpose\",\n\t\"Plan\",\n\t\"statusline-setup\",\n] as const;\n\n/** Skills bundled with Claude Code. */\nconst BUILTIN_SKILLS = [\n\t\"artifact-capabilities\",\n\t\"artifact-design\",\n\t\"claude-api\",\n\t\"code-review\",\n\t\"codebase-design\",\n\t\"dataviz\",\n\t\"diagnosing-bugs\",\n\t\"domain-modeling\",\n\t\"fewer-permission-prompts\",\n\t\"grilling\",\n\t\"init\",\n\t\"keybindings-help\",\n\t\"loop\",\n\t\"prototype\",\n\t\"research\",\n\t\"review\",\n\t\"run\",\n\t\"schedule\",\n\t\"security-review\",\n\t\"simplify\",\n\t\"tdd\",\n\t\"update-config\",\n] as const;\n\n/** Claude Code's own slash commands. */\nconst BUILTIN_SLASH_COMMANDS = [\n\t\"add-dir\",\n\t\"agents\",\n\t\"bug\",\n\t\"clear\",\n\t\"compact\",\n\t\"config\",\n\t\"context\",\n\t\"cost\",\n\t\"doctor\",\n\t\"effort\",\n\t\"exit\",\n\t\"export\",\n\t\"fast\",\n\t\"help\",\n\t\"hooks\",\n\t\"ide\",\n\t\"init\",\n\t\"login\",\n\t\"logout\",\n\t\"mcp\",\n\t\"memory\",\n\t\"model\",\n\t\"output-style\",\n\t\"permissions\",\n\t\"plugin\",\n\t\"privacy-settings\",\n\t\"release-notes\",\n\t\"resume\",\n\t\"review\",\n\t\"rewind\",\n\t\"security-review\",\n\t\"status\",\n\t\"statusline\",\n\t\"terminal-setup\",\n\t\"todos\",\n\t\"upgrade\",\n\t\"usage\",\n\t\"vim\",\n\t\"workflows\",\n] as const;\n\n/**\n * MCP servers with a public first-party endpoint.\n *\n * Matched against the server segment the analyzer parses out of an\n * `mcp__<server>__<tool>` name, which is the LOCAL alias the user configured —\n * so this only fires when the user kept the conventional name. A renamed server\n * is kept private, which is the correct direction to fail.\n *\n * ONE normalization applies first (#42 decision 5): a server provided by a\n * plugin is observed as `plugin_<plugin>_<server>`, a string Claude Code\n * generates rather than one the user typed. Strip that wrapper before matching,\n * and publish the NORMALIZED name. The safety property is that normalization can\n * only ever emit a string already on this list — a non-matching inner segment\n * emits nothing and the raw name falls through to the gate's review list — so a\n * bug here is bounded by an already-vetted set. If the upstream convention\n * changes, matching reverts to keeping names private: a fail-safe regression.\n */\nconst PUBLIC_MCP_SERVERS = [\n\t\"chrome-devtools\",\n\t\"context7\",\n\t\"deepwiki\",\n\t\"figma\",\n\t\"filesystem\",\n\t\"git\",\n\t\"github\",\n\t\"huggingface\",\n\t\"ide\",\n\t\"linear\",\n\t\"notion\",\n\t\"playwright\",\n\t\"puppeteer\",\n\t\"sentry\",\n\t\"slack\",\n\t\"stripe\",\n] as const;\n\nexport const BUNDLED_CURATED_ALLOWLIST: CuratedAllowlist = {\n\tmcpServers: PUBLIC_MCP_SERVERS,\n\tskills: BUILTIN_SKILLS,\n\tsubagents: BUILTIN_SUBAGENTS,\n\tslashCommands: BUILTIN_SLASH_COMMANDS,\n};\n","// Fail-closed name filtering for the measured layer.\n//\n// Wayfinder ticket #37 (map #29), decisions 2-4 of the wire-format grilling #33.\n//\n// THE INVERSION THIS FILE EXISTS TO PERFORM\n// The prototype's `toolCalls` map was a catch-all: anything that wasn't an\n// `mcp__*` tool, a Skill, or an Agent fell THROUGH into it, and from there into\n// the payload. That is denylist-shaped — a tool name nobody anticipated\n// publishes by default. Here a name publishes only if it matches a known list,\n// and everything else is withheld and published as a per-category count.\n//\n// Two classes of name, two mechanisms:\n// - Built-in Claude Code tool names are VENDOR-assigned and enumerable, so\n// they match a hardcoded literal set (BUILTIN_TOOLS below).\n// - MCP servers / Skills / subagents / slash commands are USER-chosen and can\n// carry a client name, a project codename, or an internal system's name.\n// They match a curated list fetched from aistack, with the bundled copy\n// below as the fallback.\n//\n// Model ids are exempt from all of this — see decision 3 and payload.ts.\n//\n// WHY FETCHED AND NOT ONLY BUNDLED (decision 4)\n// Third-party marketplace plugin auto-update defaults to OFF, and a\n// `plugin.json` whose `version` isn't bumped ships nothing. A bundled-only list\n// is, for an installed user, frozen forever — a Skill that becomes public next\n// month would never publish. The filtering itself still runs client-side:\n// fail-closed only means something if it happens before the send.\n\nimport { isDisplaySafeName } from \"./aggregate.js\";\nimport { BUNDLED_CURATED_ALLOWLIST } from \"./bundled-allowlist.js\";\n\n/**\n * Every built-in tool Claude Code can emit as a `tool_use` block name.\n *\n * Deliberately a literal set and not a pattern: a pattern is a denylist wearing\n * a hat. Grounded in the observed corpus (22 distinct names across 235,961\n * records) plus the documented tool surface, including tools that are deferred\n * or unavailable in most sessions — an unknown-but-real built-in withheld as a\n * count is a small loss; an unknown-and-user-named tool published verbatim is\n * the leak this whole file prevents.\n *\n * `Task` is the pre-rename spelling of `Agent`; the analyzer folds it into\n * `Agent` at ingest, so it is here only to make the set self-documenting.\n */\nexport const BUILTIN_TOOLS: ReadonlySet<string> = new Set([\n\t\"Agent\",\n\t\"Artifact\",\n\t\"AskUserQuestion\",\n\t\"Bash\",\n\t\"BashOutput\",\n\t\"CronCreate\",\n\t\"CronDelete\",\n\t\"CronList\",\n\t\"DesignSync\",\n\t\"Edit\",\n\t\"EndConversation\",\n\t\"EnterPlanMode\",\n\t\"EnterWorktree\",\n\t\"ExitPlanMode\",\n\t\"ExitWorktree\",\n\t\"Glob\",\n\t\"Grep\",\n\t\"KillBash\",\n\t\"KillShell\",\n\t\"ListMcpResourcesTool\",\n\t\"LS\",\n\t\"Monitor\",\n\t\"MultiEdit\",\n\t\"NotebookEdit\",\n\t\"NotebookRead\",\n\t\"PushNotification\",\n\t\"Read\",\n\t\"ReadMcpResourceDirTool\",\n\t\"ReadMcpResourceTool\",\n\t\"RemoteTrigger\",\n\t\"ReportFindings\",\n\t\"ScheduleWakeup\",\n\t\"SendMessage\",\n\t\"SendUserFile\",\n\t\"Skill\",\n\t\"SlashCommand\",\n\t\"Task\",\n\t\"TaskCreate\",\n\t\"TaskGet\",\n\t\"TaskList\",\n\t\"TaskOutput\",\n\t\"TaskStop\",\n\t\"TaskUpdate\",\n\t\"TodoWrite\",\n\t\"ToolSearch\",\n\t\"WebFetch\",\n\t\"WebSearch\",\n\t\"Workflow\",\n\t\"Write\",\n]);\n\n/** The four user-chosen atom classes that need the curated list. */\nexport type CuratedAllowlist = {\n\tmcpServers: readonly string[];\n\tskills: readonly string[];\n\tsubagents: readonly string[];\n\tslashCommands: readonly string[];\n};\n\n/** The five inventory classes the payload carries. */\nexport const NAME_CATEGORIES = [\n\t\"builtinTools\",\n\t\"mcpServers\",\n\t\"skills\",\n\t\"subagents\",\n\t\"slashCommands\",\n] as const;\n\nexport type NameCategory = (typeof NAME_CATEGORIES)[number];\n\n/**\n * Names this stack's owner has explicitly ticked for publication (#42\n * decision 1), served per-stack by the authenticated half of `/api/sync-config`.\n *\n * The curated list is a convenience default, not the coverage mechanism: every\n * user-chosen name class is unbounded and unenumerable, so a hand-curated list\n * can only ever be a rounding error against the real population. Coverage comes\n * from here — from the person who knows which of their names are secret.\n *\n * `builtinTools` is included for symmetry even though that class is\n * vendor-assigned: a built-in this version of the client has never heard of is\n * kept private like anything else, and the owner can tick it.\n */\nexport type OptInNames = Record<NameCategory, readonly string[]>;\n\nexport const EMPTY_OPT_INS: OptInNames = {\n\tbuiltinTools: [],\n\tmcpServers: [],\n\tskills: [],\n\tsubagents: [],\n\tslashCommands: [],\n};\n\nexport type SyncConfig = {\n\tallowlist: CuratedAllowlist;\n\t/**\n\t * Stack-level cost preference (decision 11). When false the payload omits\n\t * cost entirely rather than zeroing it — see payload.ts.\n\t */\n\tpublishCost: boolean;\n\t/** Per-stack ticked names, unioned into the allowlist before filtering. */\n\toptIns: OptInNames;\n\t/**\n\t * Whether this stack stages its kept-private names on the web so the owner\n\t * can tick them there (#48). Off means the machine sends the payload alone\n\t * and the names never leave it.\n\t */\n\treviewKeptPrivate: boolean;\n\t/**\n\t * The stack the bearer token is bound to — where a publish would land.\n\t *\n\t * The approve gate must name its destination BEFORE the send (#33\n\t * decision 7, #41), and beat one points at `/stacks/{slug}/changes` (#48),\n\t * so both ride on the authenticated half of the config fetch. `null` when\n\t * the fetch was anonymous, failed, or the token resolved no stack — and a\n\t * gate that cannot name its destination must not publish.\n\t */\n\tstack: { name: string; slug: string } | null;\n};\n\n/**\n * Used when `/api/sync-config` can't be reached.\n *\n * `publishCost: false` is deliberate. The toggle is a stack-level preference we\n * do not hold locally, and the fail-closed default for a preference we can't\n * read is the one that transmits less. A user whose fetch failed sees cost\n * missing from the gate and can retry; the reverse — publishing cost the stack\n * had opted out of — is not recoverable, because the snapshot is immutable.\n */\nexport const BUNDLED_SYNC_CONFIG: SyncConfig = {\n\tallowlist: BUNDLED_CURATED_ALLOWLIST,\n\tpublishCost: false,\n\t// Empty for the same reason, and it is the load-bearing half of #42\n\t// decision 2: a failed config fetch reverts every ticked name to\n\t// kept-private. Losing the network publishes LESS, never more.\n\toptIns: EMPTY_OPT_INS,\n\t// Same direction again (#48): a machine that cannot read the switch does not\n\t// upload the names it is holding back. The default is ON server-side, so this\n\t// costs the owner one retry and never costs them a name.\n\treviewKeptPrivate: false,\n\t// No fetch, no destination — and the gate refuses to publish without one.\n\tstack: null,\n};\n\n// ---------------------------------------------------------------------------\n// Fetch\n// ---------------------------------------------------------------------------\n\nconst SYNC_CONFIG_PATH = \"/api/sync-config\";\nconst FETCH_TIMEOUT_MS = 5_000;\n\nexport type SyncConfigSource = \"fetched\" | \"bundled\";\n\nexport type LoadedSyncConfig = {\n\tconfig: SyncConfig;\n\tsource: SyncConfigSource;\n\t/** Present when the fetch failed and the bundled copy was used. */\n\terror?: string;\n};\n\n/**\n * A name arriving from the network is no more trusted than one from a\n * transcript. Names are matched by exact equality, so a hostile list can widen\n * what publishes but can never smuggle a wildcard — and the approve gate\n * renders every name that will publish, which is what defuses that residual\n * trust (decision 4). Charset and length are still bounded so a pathological\n * entry can't reach a terminal or a database column.\n */\nconst CURATED_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9 ._:@/-]{0,63}$/;\n\nfunction readNameList(v: unknown): string[] {\n\tif (!Array.isArray(v)) return [];\n\tconst out: string[] = [];\n\tfor (const item of v) {\n\t\tif (typeof item === \"string\" && CURATED_NAME_RE.test(item)) out.push(item);\n\t}\n\treturn out;\n}\n\n/**\n * Opt-ins are read against a LOOSER bar than the curated list.\n *\n * A curated entry is ours and conventional, so the tight charset costs nothing.\n * An opt-in is the user's own name — `(default)`, an accented word, a CJK skill\n * — and dropping it here would silently un-tick a decision they made at the\n * gate. The bar that survives is the one that matters for a string we print and\n * store: no control characters, no bidi overrides, bounded length.\n */\nfunction readOptInList(v: unknown): string[] {\n\tif (!Array.isArray(v)) return [];\n\tconst out: string[] = [];\n\tfor (const item of v) {\n\t\tif (typeof item === \"string\" && isDisplaySafeName(item)) out.push(item);\n\t}\n\treturn out;\n}\n\nfunction readOptIns(v: unknown): OptInNames {\n\tif (typeof v !== \"object\" || v === null || Array.isArray(v))\n\t\treturn EMPTY_OPT_INS;\n\tconst obj = v as Record<string, unknown>;\n\treturn {\n\t\tbuiltinTools: readOptInList(obj.builtinTools),\n\t\tmcpServers: readOptInList(obj.mcpServers),\n\t\tskills: readOptInList(obj.skills),\n\t\tsubagents: readOptInList(obj.subagents),\n\t\tslashCommands: readOptInList(obj.slashCommands),\n\t};\n}\n\n/**\n * A slug becomes a URL path segment the gate prints, so it gets the tightest\n * bar of any string here. The name is display text and gets `isDisplaySafeName`.\n */\nconst STACK_SLUG_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;\n\nfunction readStack(v: unknown): SyncConfig[\"stack\"] {\n\tif (typeof v !== \"object\" || v === null || Array.isArray(v)) return null;\n\tconst obj = v as Record<string, unknown>;\n\tif (typeof obj.name !== \"string\" || !isDisplaySafeName(obj.name)) return null;\n\tif (typeof obj.slug !== \"string\" || !STACK_SLUG_RE.test(obj.slug))\n\t\treturn null;\n\treturn { name: obj.name, slug: obj.slug };\n}\n\nfunction readSyncConfig(raw: unknown): SyncConfig | null {\n\tif (typeof raw !== \"object\" || raw === null || Array.isArray(raw))\n\t\treturn null;\n\tconst obj = raw as Record<string, unknown>;\n\tconst listRaw = obj.allowlist;\n\tif (typeof listRaw !== \"object\" || listRaw === null) return null;\n\tconst list = listRaw as Record<string, unknown>;\n\treturn {\n\t\tallowlist: {\n\t\t\tmcpServers: readNameList(list.mcpServers),\n\t\t\tskills: readNameList(list.skills),\n\t\t\tsubagents: readNameList(list.subagents),\n\t\t\tslashCommands: readNameList(list.slashCommands),\n\t\t},\n\t\t// Anything other than an explicit `true` fails closed.\n\t\tpublishCost: obj.publishCost === true,\n\t\t// Absent means \"no stack resolved\" — an anonymous fetch, or a token bound\n\t\t// to nothing. Both fail closed to publishing no user-chosen names.\n\t\toptIns: readOptIns(obj.optIns),\n\t\t// Anything other than an explicit `true` keeps the names on the machine.\n\t\treviewKeptPrivate: obj.reviewKeptPrivate === true,\n\t\tstack: readStack(obj.stack),\n\t};\n}\n\n/**\n * Fetch the curated allowlist and the cost preference, falling back to the\n * bundled copy on any failure. Never throws — an unreachable aistack must not\n * prevent a local analysis from running, it must only narrow what could publish.\n */\nexport async function loadSyncConfig(opts: {\n\tbaseUrl: string;\n\t/**\n\t * Bearer for the authenticated half: `publishCost`, `optIns`,\n\t * `reviewKeptPrivate` and the destination stack. Absent, the server answers\n\t * with the anonymous fail-closed body — same allowlist, everything else off.\n\t */\n\ttoken?: string;\n\tfetchImpl?: typeof fetch;\n\ttimeoutMs?: number;\n}): Promise<LoadedSyncConfig> {\n\tconst doFetch = opts.fetchImpl ?? fetch;\n\ttry {\n\t\tconst res = await doFetch(`${opts.baseUrl}${SYNC_CONFIG_PATH}`, {\n\t\t\tsignal: AbortSignal.timeout(opts.timeoutMs ?? FETCH_TIMEOUT_MS),\n\t\t\theaders: {\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t...(opts.token ? { Authorization: `Bearer ${opts.token}` } : {}),\n\t\t\t},\n\t\t});\n\t\tif (!res.ok) {\n\t\t\treturn {\n\t\t\t\tconfig: BUNDLED_SYNC_CONFIG,\n\t\t\t\tsource: \"bundled\",\n\t\t\t\terror: `sync-config returned ${res.status}`,\n\t\t\t};\n\t\t}\n\t\tconst parsed = readSyncConfig(await res.json());\n\t\tif (!parsed) {\n\t\t\treturn {\n\t\t\t\tconfig: BUNDLED_SYNC_CONFIG,\n\t\t\t\tsource: \"bundled\",\n\t\t\t\terror: \"sync-config response was not the expected shape\",\n\t\t\t};\n\t\t}\n\t\treturn { config: parsed, source: \"fetched\" };\n\t} catch (err) {\n\t\treturn {\n\t\t\tconfig: BUNDLED_SYNC_CONFIG,\n\t\t\tsource: \"bundled\",\n\t\t\terror: err instanceof Error ? err.message : \"sync-config fetch failed\",\n\t\t};\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Filtering\n// ---------------------------------------------------------------------------\n\nexport type Atom = { name: string; count: number };\n\n/**\n * One observed name that will NOT publish, as the approve gate needs to render\n * it: the raw string, how often it ran, and the plugin it came from.\n *\n * Local only — this never enters the payload. It exists because the gate offers\n * every kept-private name as an explicit, default-off tick (#42 decision 1), and\n * it cannot offer what the analyzer does not hand back.\n */\nexport type KeptPrivateAtom = {\n\tname: string;\n\tcount: number;\n\t/** Plugin prefix, for the gate's grouped bulk tick. `null` when standalone. */\n\tgroup: string | null;\n};\n\nexport type FilteredAtoms = {\n\t/** Publishable names, ordered by count descending. */\n\tallowed: Atom[];\n\t/** The rest, with everything the gate needs to offer them as ticks. */\n\tkeptPrivate: KeptPrivateAtom[];\n\t/** How many DISTINCT names were kept private. */\n\twithheld: number;\n};\n\n/**\n * A server an MCP plugin provides is observed as `plugin_<plugin>_<server>`.\n *\n * That whole string is GENERATED by Claude Code — the user typed none of it —\n * which is a different class from a hand-edited `.mcp.json` alias. Strip the\n * wrapper before matching (#42 decision 5).\n *\n * The split takes the FIRST underscore-free segment as the plugin name. A plugin\n * whose own name carries an underscore therefore splits wrong, the inner segment\n * matches nothing, and the raw name stays kept private — the same direction\n * every other miss fails in.\n */\nconst PLUGIN_MCP_RE = /^plugin_([^_]+)_(.+)$/;\n\n/** `plugin:artifact` is the convention for a plugin's skills and subagents. */\nconst PLUGIN_PREFIX_RE = /^([^:\\s]+):(.+)$/;\n\n/**\n * The plugin a name came from, for the gate's grouped bulk tick.\n *\n * Grouping is a UI affordance only. What the gate STORES is every name in the\n * group, expanded (#42 decision 3): a stored `alp-river:*` would be a standing\n * grant to names that do not exist yet, and nobody can consent to a name they\n * have not thought of.\n */\nexport function pluginGroup(name: string): string | null {\n\treturn (\n\t\tPLUGIN_MCP_RE.exec(name)?.[1] ?? PLUGIN_PREFIX_RE.exec(name)?.[1] ?? null\n\t);\n}\n\nexport type FilterSets = {\n\t/** Curated list UNION this stack's opt-ins. A match here publishes verbatim. */\n\tpublishable: ReadonlySet<string>;\n\t/**\n\t * The curated list alone — the only target normalization may match.\n\t *\n\t * This is what makes the normalization safe to state in one line:\n\t * normalization can only ever emit a string that is already curated. The\n\t * blast radius of a bug in it is an already-vetted set, by construction.\n\t */\n\tcurated: ReadonlySet<string>;\n};\n\n/**\n * Resolve the name an atom would publish under, or `null` to keep it private.\n *\n * Raw match first, so a name the owner ticked publishes exactly as they saw it\n * at the gate. Only an unmatched name is normalized, and only against the\n * curated list.\n */\nfunction publishedName(name: string, sets: FilterSets): string | null {\n\tif (sets.publishable.has(name)) return name;\n\tconst inner = PLUGIN_MCP_RE.exec(name)?.[2];\n\tif (inner && sets.curated.has(inner)) return inner;\n\treturn null;\n}\n\n/**\n * Split observed atoms into what publishes and what stays on the machine.\n *\n * The withheld figure counts distinct names, not calls: it answers \"how much of\n * my inventory is not shown\", which is the honesty question, without leaking\n * how heavily any single kept-private thing is used.\n *\n * Counts are merged by PUBLISHED name, because normalization can map two\n * observed names onto one — a plugin-provided `chrome-devtools` and a directly\n * configured one both publish as `chrome-devtools`, and two rows with the same\n * name would double-count that server in the rendered inventory.\n */\nexport function filterAtoms(\n\tatoms: readonly Atom[],\n\tsets: FilterSets,\n): FilteredAtoms {\n\tconst merged = new Map<string, number>();\n\tconst keptPrivate: KeptPrivateAtom[] = [];\n\tfor (const atom of atoms) {\n\t\tconst published = publishedName(atom.name, sets);\n\t\tif (published === null) {\n\t\t\tkeptPrivate.push({\n\t\t\t\tname: atom.name,\n\t\t\t\tcount: atom.count,\n\t\t\t\tgroup: pluginGroup(atom.name),\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tmerged.set(published, (merged.get(published) ?? 0) + atom.count);\n\t}\n\tconst allowed = [...merged].map(([name, count]) => ({ name, count }));\n\tallowed.sort((a, b) => b.count - a.count || a.name.localeCompare(b.name));\n\tkeptPrivate.sort((a, b) => b.count - a.count || a.name.localeCompare(b.name));\n\treturn { allowed, keptPrivate, withheld: keptPrivate.length };\n}\n","// Pure fold over parsed Claude Code transcript records. No I/O, no console.\n//\n// Wayfinder ticket #37 (map #29), productizing the #32 prototype. Field\n// semantics come from docs/research/claude-code-transcripts-2026-07.md (#30),\n// as corrected by #32 and #33. Every field is treated as untrusted and\n// optional: records arrive as `unknown` and are narrowed here.\n//\n// The shared aggregate/finalize machinery lives in ../shared/aggregate.ts\n// (#67); this file owns what is CLAUDE-specific — the record shapes, and the\n// response dedup below.\n//\n// THE LOAD-BEARING SUBTLETY — read before touching `ingestAssistant`.\n// Claude Code writes ONE API response as SEVERAL JSONL records: each carries a\n// distinct content block (thinking, then tool_use, then tool_use...) and a\n// *cumulative* `usage` snapshot that grows with each record. Measured on a real\n// corpus: 20,073 of 44,280 response groups have differing usage across their\n// records, 20,071 of them monotonically increasing.\n//\n// So there are three wrong ways to count and one right way:\n// - sum every record -> ~2x over\n// - keep the first record -> ~2.1x under\n// - keep the last record -> right, but relies on file order\n// - keep the largest total -> right, order-independent <- this\n// Keeping the largest total is also ccusage's documented rule\n// (`should_replace_deduped_entry`).\n//\n// THE SECOND SUBTLETY — cost accumulates HERE, not in `finalize`.\n// Decision 8 of #33 made pricing time-aware, so a response is priced at the\n// rate in effect at its own timestamp. Summing tokens per model and pricing\n// once at the end cannot express a mid-window rate change, so each response's\n// cost is computed as it is ingested and un-applied on replace.\n\nimport {\n\tasArr,\n\tasName,\n\tasNum,\n\tasObj,\n\tasStr,\n\tbump,\n\tcleanName,\n\tcountsTotal,\n\tcreateAggregate as createSharedAggregate,\n\temptyUsage,\n\ttype Obj,\n\ttype Aggregate as SharedAggregate,\n} from \"../shared/aggregate.js\";\nimport {\n\tapiEquivalentCost,\n\tnormalizeModel,\n\ttype TokenCounts,\n} from \"../shared/pricing.js\";\n\n// Re-exported for the existing import sites (tests, stage, summary); the\n// definitions moved to ../shared/aggregate.ts in #67.\nexport {\n\tcleanName,\n\ttype Finalized,\n\tfinalize,\n\tisDisplaySafeName,\n\ttype ModelRow,\n\ttype ModelUsage,\n\tnewestVersion,\n} from \"../shared/aggregate.js\";\n\ntype Entry = {\n\tmodelKey: string;\n\tcounts: TokenCounts;\n\t/** `null` = no rate applied at this response's timestamp. */\n\tcostUSD: number | null;\n};\n\n/** One API response's full contribution, kept so it can be un-applied on replace. */\ntype Contribution = {\n\tentries: Entry[];\n\ttotal: number;\n\tsidechain: boolean;\n\twebSearch: number;\n\twebFetch: number;\n\t/** Iteration types that mirrored top-level usage, for the diagnostics line. */\n\tmirroredIterationTypes: Array<[string, number]>;\n\t/** Iterations naming a different model, attributed to that model (#33 dec. 9). */\n\tfallbackAttempts: number;\n\t/** Mirror-suspected iterations with no `model` field — skipped, not billed. */\n\tuntypedMirrors: number;\n};\n\ntype SeenEntry = { requestId: string | null; contribution: Contribution };\n\n/**\n * The Claude adapter's aggregate: the shared fold target, with `seen` keyed\n * by `message.id` holding this adapter's replay/continuation bookkeeping.\n */\nexport type Aggregate = SharedAggregate<SeenEntry>;\n\nexport function createAggregate(): Aggregate {\n\treturn createSharedAggregate<SeenEntry>();\n}\n\n// ---------------------------------------------------------------------------\n// Ingest\n// ---------------------------------------------------------------------------\n\nexport type IngestContext = { projectDir: string };\n\n/** Fold one parsed JSONL record into the aggregate. */\nexport function ingestRecord(\n\tagg: Aggregate,\n\traw: unknown,\n\tctx: IngestContext,\n): void {\n\tconst rec = asObj(raw);\n\tif (!rec) return;\n\n\tagg.records++;\n\tagg.projectDirs.add(ctx.projectDir);\n\n\tconst version = asStr(rec.version);\n\tif (version) agg.ccVersions.add(cleanName(version));\n\tconst sessionId = asStr(rec.sessionId);\n\tif (sessionId) agg.sessions.add(sessionId);\n\n\tlet tsMs: number | null = null;\n\tconst timestamp = asStr(rec.timestamp);\n\tif (timestamp) {\n\t\tconst ts = Date.parse(timestamp);\n\t\tif (!Number.isNaN(ts)) {\n\t\t\ttsMs = ts;\n\t\t\tagg.activeDays.add(timestamp.slice(0, 10));\n\t\t\tagg.firstTs = agg.firstTs === null ? ts : Math.min(agg.firstTs, ts);\n\t\t\tagg.lastTs = agg.lastTs === null ? ts : Math.max(agg.lastTs, ts);\n\t\t}\n\t}\n\n\tconst type = asStr(rec.type);\n\tif (type === \"assistant\") ingestAssistant(agg, rec, tsMs);\n\telse if (type === \"user\") ingestUser(agg, rec);\n}\n\nfunction ingestAssistant(agg: Aggregate, rec: Obj, tsMs: number | null): void {\n\tagg.assistantRecords++;\n\tconst msg = asObj(rec.message);\n\tif (!msg) return;\n\n\tconst messageId = asStr(msg.id);\n\tconst requestId = asStr(rec.requestId);\n\tconst existing = messageId === null ? undefined : agg.seen.get(messageId);\n\t// A genuine replay is the same message.id under a NEW requestId. Its records\n\t// repeat content already counted; a continuation's records do not.\n\tconst isReplay = existing !== undefined && existing.requestId !== requestId;\n\n\t// Content blocks are counted per RECORD, deliberately outside the token\n\t// fold: the records of ONE response carry disjoint blocks (verified across\n\t// 44,478 groups — zero overlap), so folding them would drop real blocks.\n\t// Replays are the exception and must be skipped, because `tool_use` has\n\t// `block.id` to dedup on but thinking/text blocks have no identity at all.\n\tif (!isReplay) ingestContentBlocks(agg, msg.content);\n\n\tconst usage = asObj(msg.usage);\n\tif (!usage) return;\n\n\tconst model = asName(msg.model) ?? \"(unknown)\";\n\t// `<synthetic>` is the harness's own pseudo-model for records it generates\n\t// itself. Not a tool the user chose — excluded from inventory and pricing,\n\t// but its tokens are surfaced rather than silently dropped.\n\tif (model.startsWith(\"<\")) {\n\t\tagg.syntheticRecords++;\n\t\tagg.syntheticTokens += countsTotal(readCounts(usage));\n\t\treturn;\n\t}\n\n\tif (tsMs === null) agg.untimestampedResponses++;\n\n\tconst sidechain = rec.isSidechain === true;\n\tconst contribution = buildContribution(usage, model, sidechain, tsMs);\n\n\tif (messageId === null) {\n\t\t// No dedup key available — count it and record that we were unprotected.\n\t\tagg.unkeyedResponses++;\n\t\tacceptContribution(agg, contribution);\n\t\treturn;\n\t}\n\n\tif (existing === undefined) {\n\t\tagg.distinctResponses++;\n\t\tacceptContribution(agg, contribution);\n\t\tagg.seen.set(messageId, { requestId, contribution });\n\t\treturn;\n\t}\n\n\tif (isReplay) agg.realReplaysFolded++;\n\telse agg.continuationsFolded++;\n\n\tif (!supersedes(contribution, existing.contribution)) return;\n\n\tagg.supersededByLarger++;\n\tretractContribution(agg, existing.contribution);\n\tacceptContribution(agg, contribution);\n\t// Keep the FIRST-seen requestId, not this record's. If a genuine replay wins\n\t// on tokens, overwriting it would make the replay's own later records compare\n\t// equal to the stored id, read as continuations, and get their thinking/text\n\t// blocks counted a second time — reopening exactly what the `isReplay` gate\n\t// above exists to close. (tool_use survives either way via `block.id`.)\n\tagg.seen.set(messageId, { requestId: existing.requestId, contribution });\n}\n\n/**\n * Apply a contribution and tally its diagnostics. Paired with\n * `retractContribution` so every per-response census stays per-RESPONSE rather\n * than per-record — these used to be bumped while merely *building* a\n * contribution, which counted every folded continuation too.\n */\nfunction acceptContribution(agg: Aggregate, c: Contribution): void {\n\tapplyContribution(agg, c, +1);\n}\n\nfunction retractContribution(agg: Aggregate, c: Contribution): void {\n\tapplyContribution(agg, c, -1);\n}\n\n/**\n * ccusage's collision rule: a non-sidechain copy beats a sidechain one;\n * otherwise the larger token total wins. Order-independent by construction,\n * so the result does not depend on filesystem traversal order.\n */\nfunction supersedes(next: Contribution, prev: Contribution): boolean {\n\tif (prev.sidechain !== next.sidechain)\n\t\treturn prev.sidechain && !next.sidechain;\n\treturn next.total > prev.total;\n}\n\nfunction readCounts(usage: Obj): TokenCounts {\n\tconst t: TokenCounts = {\n\t\tinput: asNum(usage.input_tokens),\n\t\toutput: asNum(usage.output_tokens),\n\t\tcacheWrite5m: 0,\n\t\tcacheWrite1h: 0,\n\t\tcacheWriteUnsplit: 0,\n\t\tcacheRead: asNum(usage.cache_read_input_tokens),\n\t};\n\tconst cacheWriteTotal = asNum(usage.cache_creation_input_tokens);\n\tconst cc = asObj(usage.cache_creation);\n\tif (cc) {\n\t\tt.cacheWrite5m = asNum(cc.ephemeral_5m_input_tokens);\n\t\tt.cacheWrite1h = asNum(cc.ephemeral_1h_input_tokens);\n\t\tconst residual = cacheWriteTotal - (t.cacheWrite5m + t.cacheWrite1h);\n\t\tif (residual > 0) t.cacheWriteUnsplit = residual;\n\t} else {\n\t\tt.cacheWriteUnsplit = cacheWriteTotal;\n\t}\n\treturn t;\n}\n\n/** `usage.speed === \"fast\"` prices under a separate, higher rate. */\nfunction modelKeyFor(model: string, speed: string | null): string {\n\treturn normalizeModel(speed === \"fast\" ? `${model}#fast` : model);\n}\n\nfunction makeEntry(\n\tmodelKey: string,\n\tcounts: TokenCounts,\n\ttsMs: number | null,\n): Entry {\n\treturn {\n\t\tmodelKey,\n\t\tcounts,\n\t\tcostUSD: apiEquivalentCost(modelKey, counts, tsMs),\n\t};\n}\n\nfunction buildContribution(\n\tusage: Obj,\n\tmodel: string,\n\tsidechain: boolean,\n\ttsMs: number | null,\n): Contribution {\n\tconst modelKey = modelKeyFor(model, asStr(usage.speed));\n\tconst entries: Entry[] = [makeEntry(modelKey, readCounts(usage), tsMs)];\n\tconst mirrored = new Map<string, number>();\n\tlet fallbackAttempts = 0;\n\tlet untypedMirrors = 0;\n\n\tfor (const rawIt of asArr(usage.iterations)) {\n\t\tconst it = asObj(rawIt);\n\t\tif (!it) continue;\n\t\tconst itType = asName(it.type) ?? \"(untyped)\";\n\t\tconst itModel = asName(it.model);\n\t\tconst itKey =\n\t\t\titModel === null ? null : modelKeyFor(itModel, asStr(it.speed));\n\n\t\t// Advisor iterations are a genuinely separate billed call under their own\n\t\t// model, never a mirror of top-level usage (ccusage prices them apart).\n\t\tif (itType === \"advisor_message\") {\n\t\t\tentries.push(makeEntry(itKey ?? modelKey, readCounts(it), tsMs));\n\t\t\tcontinue;\n\t\t}\n\n\t\t// #33 decision 9, SHARPENED — read the whole comment before touching this.\n\t\t//\n\t\t// The prototype skipped EVERY `type: \"message\"` iteration as a mirror of\n\t\t// top-level usage, which was correct by luck rather than construction: a\n\t\t// real `fallback_message` record showed top-level usage equal to the\n\t\t// fallback iteration EXACTLY, while a sibling `type: message` iteration\n\t\t// named a DIFFERENT model and carried tokens recorded nowhere else. So\n\t\t// `message.model` is already the serving model, and the mirror test is the\n\t\t// MODEL, not the type.\n\t\t//\n\t\t// #33 phrased the fix as \"skip it only when `iter.model === message.model`\".\n\t\t// Taken literally that is a ~2x overcount, because the corpus says the\n\t\t// `model` field is almost never there: of 63,638 non-advisor iterations,\n\t\t// 63,634 carry NO `model` at all — and all 63,634 are byte-exact mirrors of\n\t\t// their record's top-level usage (measured: zero differ). They carry 7.24\n\t\t// BILLION tokens, nearly double the corpus total, so attributing them as\n\t\t// separate entries would roughly double both tokens and cost. Only 8\n\t\t// iterations name a model: 4 matching (the `fallback_message` entries) and\n\t\t// 4 differing (the real first attempts).\n\t\t//\n\t\t// So the operative rule is: SKIP UNLESS THE ITERATION NAMES A DIFFERENT\n\t\t// MODEL. Absent is treated as matching — mis-attributing is a double-bill,\n\t\t// skipping is at worst an undercount, and the measurement above says it is\n\t\t// not even that.\n\t\tif (itKey === null) {\n\t\t\tuntypedMirrors++;\n\t\t\tbump(mirrored, itType);\n\t\t\tcontinue;\n\t\t}\n\t\tif (itKey === modelKey) {\n\t\t\tbump(mirrored, itType);\n\t\t\tcontinue;\n\t\t}\n\t\tentries.push(makeEntry(itKey, readCounts(it), tsMs));\n\t\tfallbackAttempts++;\n\t}\n\n\tconst serverTools = asObj(usage.server_tool_use);\n\treturn {\n\t\tentries,\n\t\ttotal: entries.reduce((a, e) => a + countsTotal(e.counts), 0),\n\t\tsidechain,\n\t\twebSearch: serverTools ? asNum(serverTools.web_search_requests) : 0,\n\t\twebFetch: serverTools ? asNum(serverTools.web_fetch_requests) : 0,\n\t\tmirroredIterationTypes: [...mirrored],\n\t\tfallbackAttempts,\n\t\tuntypedMirrors,\n\t};\n}\n\n/** Add (sign +1) or remove (sign -1) a response's contribution from the totals. */\nfunction applyContribution(\n\tagg: Aggregate,\n\tc: Contribution,\n\tsign: 1 | -1,\n): void {\n\tc.entries.forEach(({ modelKey, counts, costUSD }, i) => {\n\t\tlet m = agg.byModel.get(modelKey);\n\t\tif (!m) {\n\t\t\tm = emptyUsage();\n\t\t\tagg.byModel.set(modelKey, m);\n\t\t}\n\t\t// One response is one message, even when a fallback attempt or an advisor\n\t\t// iteration attributes tokens to a second model — counting per entry would\n\t\t// inflate the response total past distinctResponses.\n\t\tif (i === 0) m.messages += sign;\n\t\tm.input += sign * counts.input;\n\t\tm.output += sign * counts.output;\n\t\tm.cacheWrite5m += sign * counts.cacheWrite5m;\n\t\tm.cacheWrite1h += sign * counts.cacheWrite1h;\n\t\tm.cacheWriteUnsplit += sign * counts.cacheWriteUnsplit;\n\t\tm.cacheRead += sign * counts.cacheRead;\n\t\tif (costUSD === null) m.unpricedTokens += sign * countsTotal(counts);\n\t\telse m.costUSD += sign * costUSD;\n\t});\n\tif (c.sidechain) agg.sidechainTokens += sign * c.total;\n\telse agg.mainTokens += sign * c.total;\n\tagg.webSearchRequests += sign * c.webSearch;\n\tagg.webFetchRequests += sign * c.webFetch;\n\tagg.fallbackAttempts += sign * c.fallbackAttempts;\n\tagg.untypedMirrors += sign * c.untypedMirrors;\n\tfor (const [type, count] of c.mirroredIterationTypes) {\n\t\tbump(agg.mirroredIterationTypes, type, sign * count);\n\t}\n}\n\nfunction ingestContentBlocks(agg: Aggregate, content: unknown): void {\n\tfor (const rawBlock of asArr(content)) {\n\t\tconst block = asObj(rawBlock);\n\t\tif (!block) continue;\n\t\tconst type = asStr(block.type);\n\t\tif (type === \"thinking\") agg.thinkingBlocks++;\n\t\telse if (type === \"text\") agg.textBlocks++;\n\t\telse if (type === \"tool_use\") ingestToolUse(agg, block);\n\t}\n}\n\nfunction ingestToolUse(agg: Aggregate, block: Obj): void {\n\tconst name = asName(block.name);\n\tif (!name) return;\n\n\t// `toolu_...` block ids are globally unique, which makes this key both\n\t// collision-proof and replay-proof without a record-level prefix. A block\n\t// with no id is skipped rather than folded under a name-only key, which\n\t// would silently collapse every call to that tool into one.\n\tconst blockId = asStr(block.id);\n\tif (!blockId) {\n\t\tagg.toolBlocksWithoutId++;\n\t\treturn;\n\t}\n\tif (agg.toolCallDedup.has(blockId)) return;\n\tagg.toolCallDedup.add(blockId);\n\n\tconst input = asObj(block.input) ?? {};\n\n\tif (name.startsWith(\"mcp__\")) {\n\t\tconst parts = name.slice(\"mcp__\".length).split(\"__\");\n\t\tbump(agg.mcpServerCalls, parts[0] || \"(unknown)\");\n\t\tbump(agg.mcpToolCalls, name);\n\t\treturn;\n\t}\n\tif (name === \"Skill\") {\n\t\tbump(agg.skillCalls, asName(input.skill) ?? \"(unnamed)\");\n\t\tbump(agg.toolCalls, \"Skill\");\n\t\treturn;\n\t}\n\t// `Task` is the pre-rename spelling of `Agent`.\n\tif (name === \"Agent\" || name === \"Task\") {\n\t\tbump(agg.subagentCalls, asName(input.subagent_type) ?? \"(default)\");\n\t\tbump(agg.toolCalls, \"Agent\");\n\t\treturn;\n\t}\n\tbump(agg.toolCalls, name);\n}\n\nconst SLASH_RE = /<command-name>\\/?([^<\\n\\r]{1,64})<\\/command-name>/g;\n\nfunction ingestUser(agg: Aggregate, rec: Obj): void {\n\tconst msg = asObj(rec.message);\n\tif (!msg) return;\n\tconst content = msg.content;\n\n\tlet text = \"\";\n\tif (typeof content === \"string\") text = content;\n\telse {\n\t\tfor (const rawBlock of asArr(content)) {\n\t\t\tconst block = asObj(rawBlock);\n\t\t\tif (!block) continue;\n\t\t\tif (asStr(block.type) === \"text\") text += asStr(block.text) ?? \"\";\n\t\t}\n\t}\n\tif (!text.includes(\"<command-name>\")) return;\n\n\t// `matchAll` over `exec` in a loop: the regex is module-level and `g`-flagged,\n\t// so an `exec` loop carries a shared `lastIndex` that a forgotten reset turns\n\t// into records being skipped at random.\n\tfor (const match of text.matchAll(SLASH_RE)) {\n\t\tbump(agg.slashCommands, cleanName(match[1]));\n\t}\n}\n","// I/O shell around the pure analyzer: find transcript roots, stream JSONL, hand\n// each parsed record to ingestRecord. Nothing leaves this machine.\n//\n// Wayfinder ticket #37 (map #29).\n//\n// STANDING NON-GOAL (locked in #13): raw transcripts, prompts, absolute paths,\n// and repo names never leave the machine. Two consequences visible here:\n// project directories are counted but their names never escape this module, and\n// read errors are swallowed rather than thrown, because the error object carries\n// the absolute path and the munged project directory.\n\nimport { createReadStream, type Dirent } from \"node:fs\";\nimport { readdir, realpath, stat } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport readline from \"node:readline\";\n\nimport {\n\temptyScanStats,\n\ttype ScanStats,\n\twindowStartMs,\n} from \"../shared/window.js\";\nimport { type Aggregate, ingestRecord } from \"./analyzer.js\";\n\nexport { type ScanStats, windowStartMs };\n\n/** Discovery order mirrors ccusage's adapter: CLAUDE_CONFIG_DIR, then the defaults. */\nexport function transcriptRoots(): string[] {\n\tconst env = process.env.CLAUDE_CONFIG_DIR;\n\tif (env) {\n\t\treturn env\n\t\t\t.split(\",\")\n\t\t\t.map((s) => s.trim())\n\t\t\t.filter(Boolean)\n\t\t\t.map((s) => path.join(s, \"projects\"));\n\t}\n\tconst roots = [path.join(homedir(), \".claude\", \"projects\")];\n\tconst xdg = process.env.XDG_CONFIG_HOME ?? path.join(homedir(), \".config\");\n\troots.push(path.join(xdg, \"claude\", \"projects\"));\n\treturn roots;\n}\n\n/** Recursive *.jsonl walk — the nested `<sessionId>/subagents/` layout is real. */\nasync function* walkJsonl(dir: string): AsyncGenerator<string> {\n\tlet entries: Dirent[];\n\ttry {\n\t\tentries = await readdir(dir, { withFileTypes: true });\n\t} catch {\n\t\treturn;\n\t}\n\tfor (const e of entries) {\n\t\tconst full = path.join(dir, e.name);\n\t\tif (e.isDirectory()) yield* walkJsonl(full);\n\t\telse if (e.isFile() && e.name.endsWith(\".jsonl\")) yield full;\n\t}\n}\n\nexport type ScanOptions = {\n\t/** Only ingest records with a timestamp at or after this epoch ms. */\n\tsinceMs?: number;\n\tonProgress?: (files: number) => void;\n\t/** Override the discovered roots. Tests only. */\n\troots?: string[];\n};\n\n/**\n * KNOWN PERFORMANCE FLOOR — measured, decided, deliberately not fixed.\n *\n * Enumeration walks every project directory and `realpath`+`stat`s every file\n * BEFORE the mtime filter can skip anything, so a narrow window still pays a\n * floor proportional to TOTAL history (~60 ms over 3,206 files today, growing\n * linearly). The obvious fix — prune whole project directories by directory\n * mtime — is UNSOUND, and this was verified rather than assumed: appending to a\n * file does not update its parent directory's mtime (only adding, removing, or\n * renaming an entry does). A session resumed with `--resume` appends to a\n * transcript created before the window opened, inside a directory whose mtime\n * never moves, so dir-mtime pruning would silently drop live in-window records\n * — a wrong number, which is worse than a slow one for a tool whose whole claim\n * is measured-not-claimed.\n *\n * The sound version is a persisted enumeration cache, which cuts against #33\n * decision 1 (a sync is a stateless snapshot-replace, no durable client scan\n * state). So: DEFERRED. 60 ms is two orders of magnitude under the ~3 s full\n * scan and invisible next to the send round-trip; it becomes worth revisiting\n * only when total history reaches a scale where the floor dominates.\n */\nexport async function scan(\n\tagg: Aggregate,\n\topts: ScanOptions = {},\n): Promise<ScanStats> {\n\tconst stats: ScanStats = emptyScanStats();\n\t// Roots can overlap (CLAUDE_CONFIG_DIR may repeat a dir; ~/.claude and\n\t// ~/.config/claude may be symlinked together). Without this guard the same\n\t// file is ingested twice and the record/line/block counters silently double.\n\tconst visited = new Set<string>();\n\n\tfor (const root of opts.roots ?? transcriptRoots()) {\n\t\tif (!(await exists(root))) continue;\n\t\tfor await (const file of walkJsonl(root)) {\n\t\t\tstats.filesFound++;\n\n\t\t\tlet resolved: string;\n\t\t\ttry {\n\t\t\t\tresolved = await realpath(file);\n\t\t\t} catch {\n\t\t\t\tresolved = file;\n\t\t\t}\n\t\t\tif (visited.has(resolved)) {\n\t\t\t\tstats.filesSkippedAsDuplicate++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvisited.add(resolved);\n\n\t\t\t// Transcripts are append-only and chronological, so a file untouched\n\t\t\t// since the window opened cannot hold an in-window record. This is what\n\t\t\t// makes a narrow window actually cheaper rather than merely narrower.\n\t\t\tif (opts.sinceMs !== undefined) {\n\t\t\t\ttry {\n\t\t\t\t\tconst st = await stat(file);\n\t\t\t\t\tif (st.mtimeMs < opts.sinceMs) {\n\t\t\t\t\t\tstats.filesSkippedByMtime++;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t/* unreadable stat — fall through and try to read it */\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Project dir = first path segment under projects/ (privacy-sensitive:\n\t\t\t// it is a munged absolute path, so it is only ever counted, never shown).\n\t\t\tconst rel = path.relative(root, file);\n\t\t\tconst projectDir = rel.split(path.sep)[0] ?? \"(root)\";\n\t\t\tagg.files++;\n\t\t\tstats.filesRead++;\n\t\t\tif (opts.onProgress && agg.files % 200 === 0) opts.onProgress(agg.files);\n\t\t\ttry {\n\t\t\t\tawait ingestFile(agg, file, projectDir, opts.sinceMs);\n\t\t\t} catch {\n\t\t\t\t// Swallow deliberately: the error object carries the absolute path.\n\t\t\t\tstats.filesUnreadable++;\n\t\t\t\tstats.filesRead--;\n\t\t\t}\n\t\t}\n\t}\n\treturn stats;\n}\n\nasync function exists(p: string): Promise<boolean> {\n\ttry {\n\t\tawait stat(p);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function ingestFile(\n\tagg: Aggregate,\n\tfile: string,\n\tprojectDir: string,\n\tsinceMs?: number,\n): Promise<void> {\n\tconst rl = readline.createInterface({\n\t\tinput: createReadStream(file, { encoding: \"utf8\" }),\n\t\tcrlfDelay: Number.POSITIVE_INFINITY,\n\t});\n\tfor await (const line of rl) {\n\t\tif (!line) continue;\n\t\tagg.lines++;\n\t\tlet rec: unknown;\n\t\ttry {\n\t\t\trec = JSON.parse(line);\n\t\t} catch {\n\t\t\tagg.parseErrors++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (sinceMs !== undefined) {\n\t\t\tconst ts =\n\t\t\t\trec &&\n\t\t\t\ttypeof rec === \"object\" &&\n\t\t\t\t\"timestamp\" in rec &&\n\t\t\t\ttypeof (rec as { timestamp?: unknown }).timestamp === \"string\"\n\t\t\t\t\t? Date.parse((rec as { timestamp: string }).timestamp)\n\t\t\t\t\t: Number.NaN;\n\t\t\tif (Number.isNaN(ts) || ts < sinceMs) continue;\n\t\t}\n\t\tingestRecord(agg, rec, { projectDir });\n\t}\n}\n","// The rolling window and the scan-health shape every adapter reports.\n// Shared so the payload builder and each harness scanner agree by import\n// rather than by convention (#67).\n\n/** Rolling window locked by the owner in the #32 prototype resolution. */\nexport const DEFAULT_WINDOW_DAYS = 30;\n\n/**\n * UTC midnight opening a rolling window of `days` calendar days ending on the\n * day containing `now` (inclusive). `days = 30` therefore spans today plus the\n * 29 preceding days.\n *\n * Defined once and shared by the scan filter and the payload's `window.from`, so\n * the reported window and the records actually counted cannot drift apart.\n */\nexport function windowStartMs(now: number, days: number): number {\n\tconst startOfToday = Date.UTC(\n\t\tnew Date(now).getUTCFullYear(),\n\t\tnew Date(now).getUTCMonth(),\n\t\tnew Date(now).getUTCDate(),\n\t);\n\treturn startOfToday - (days - 1) * 86_400_000;\n}\n\nexport type ScanStats = {\n\t/** Files found on disk before any window filter. */\n\tfilesFound: number;\n\t/** Files actually opened and read. */\n\tfilesRead: number;\n\t/** Files skipped because their mtime predates the window. */\n\tfilesSkippedByMtime: number;\n\t/** Files skipped because a resolved path was already scanned (overlapping roots). */\n\tfilesSkippedAsDuplicate: number;\n\t/**\n\t * Files that could not be read (permissions, or pruned mid-scan). Counted\n\t * rather than thrown: an unhandled read error would surface the absolute path\n\t * AND the munged project directory in the crash output, which is exactly what\n\t * this tool promises never to emit.\n\t */\n\tfilesUnreadable: number;\n};\n\nexport function emptyScanStats(): ScanStats {\n\treturn {\n\t\tfilesFound: 0,\n\t\tfilesRead: 0,\n\t\tfilesSkippedByMtime: 0,\n\t\tfilesSkippedAsDuplicate: 0,\n\t\tfilesUnreadable: 0,\n\t};\n}\n","// The Codex CLI harness behind the seam (#66 decision 6, built in #67).\n\nimport { stat } from \"node:fs/promises\";\n\nimport { OPENAI_PRICING_TABLE_VERSION } from \"../shared/pricing.js\";\nimport type {\n\tHarnessAdapter,\n\tHarnessScan,\n\tHarnessScanOptions,\n} from \"../types.js\";\nimport { createAggregate } from \"./analyzer.js\";\nimport { rolloutRoots, scan } from \"./scan.js\";\n\nexport const CODEX_HARNESS_NAME = \"codex\";\n\n/**\n * Codex's vendor-assigned tool surface, as observed in rollouts and pinned in\n * the Codex source (#65 §4). Same fail-closed mechanism as Claude's\n * BUILTIN_TOOLS: a literal set, never a pattern — an unknown-but-real\n * built-in withheld as a count is a small loss; an unknown-and-user-named\n * tool published verbatim is the leak this prevents. The last four are the\n * stable synthetic names the analyzer assigns to non-`function_call` items.\n *\n * Codex v1 publishes builtinTools and mcpServers ONLY (#66 decision 3):\n * slash commands verifiably never reach rollouts, and the skill/subagent\n * surfaces are unverified — those categories ship as empty arrays, absorbed\n * with no schema change if a later Codex version logs them.\n */\nexport const CODEX_BUILTIN_TOOLS: ReadonlySet<string> = new Set([\n\t\"apply_patch\",\n\t\"exec_command\",\n\t\"grep_command\",\n\t\"list_dir\",\n\t\"read_file\",\n\t\"request_user_input\",\n\t\"shell\",\n\t\"unified_exec\",\n\t\"update_plan\",\n\t\"view_image\",\n\t\"write_stdin\",\n\t// synthetic names for non-function_call response items\n\t\"local_shell\",\n\t\"web_search\",\n\t\"tool_search\",\n]);\n\nasync function exists(p: string): Promise<boolean> {\n\ttry {\n\t\tawait stat(p);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport const codexAdapter: HarnessAdapter = {\n\tname: CODEX_HARNESS_NAME,\n\tbuiltinTools: CODEX_BUILTIN_TOOLS,\n\tpricingTableVersion: OPENAI_PRICING_TABLE_VERSION,\n\n\tasync detect(): Promise<boolean> {\n\t\tfor (const root of rolloutRoots()) {\n\t\t\tif (await exists(root)) return true;\n\t\t}\n\t\treturn false;\n\t},\n\n\tasync scan(opts: HarnessScanOptions): Promise<HarnessScan> {\n\t\tconst aggregate = createAggregate();\n\t\tconst stats = await scan(aggregate, {\n\t\t\tsinceMs: opts.sinceMs,\n\t\t\t...(opts.onProgress ? { onProgress: opts.onProgress } : {}),\n\t\t});\n\t\treturn { aggregate, stats };\n\t},\n};\n","// Pure fold over parsed Codex CLI rollout lines. No I/O, no console.\n//\n// Wayfinder ticket #67 (map #60). Field semantics come from\n// docs/research/codex-session-log-anatomy-2026-08.md (#65) as locked by the\n// wire-format grilling #66. Every field is untrusted and optional: lines\n// arrive as `unknown` and are narrowed here.\n//\n// THE LOAD-BEARING SUBTLETY — Claude's cumulative gotcha, INVERTED.\n// Claude Code logs per-message usage that can repeat across snapshot records,\n// so its analyzer dedups by message id. Codex logs a `token_count` event whose\n// `total_token_usage` is the CUMULATIVE session sum — summing it across a\n// session's 20+ events overcounts by orders of magnitude. The rule locked in\n// #66: sum `last_token_usage` (the per-response delta) and never read the\n// totals. Deltas also carry the cached/non-cached split each response's cost\n// needs, which the cumulative figure re-counts every turn.\n//\n// Attribution: `token_count` events carry no model. Each delta is attributed\n// to the model of the nearest preceding `turn_context` in the same file.\n//\n// TokenCounts mapping (#66 decision 6): `cached_input_tokens` is a SUBSET of\n// `input_tokens`, so `input = input_tokens - cached_input`, `cacheRead =\n// cached_input`, and `cacheWrite = 0` — Codex reports no cache writes, and a\n// zero write prices correctly with zero pricing-code changes.\n\nimport {\n\taddModelUsage,\n\tasName,\n\tasNum,\n\tasObj,\n\tasStr,\n\tbump,\n\tcleanName,\n\tcountsTotal,\n\tcreateAggregate as createSharedAggregate,\n\ttype Obj,\n\ttype Aggregate as SharedAggregate,\n} from \"../shared/aggregate.js\";\nimport {\n\tapiEquivalentCost,\n\tnormalizeModel,\n\ttype TokenCounts,\n} from \"../shared/pricing.js\";\n\n/** Codex needs no response dedup bookkeeping — deltas count once by construction. */\nexport type Aggregate = SharedAggregate<never>;\n\nexport function createAggregate(): Aggregate {\n\treturn createSharedAggregate<never>();\n}\n\n/**\n * Per-file fold state. A rollout file is one session; the session id, CLI\n * version, cwd and current model are context lines that may sit BEFORE the\n * window opens, so they update state unconditionally and are only counted\n * when an in-window line lands (`noteActivity`).\n */\nexport type FileState = {\n\tsessionId: string | null;\n\tcliVersion: string | null;\n\tcwd: string | null;\n\t/** Pricing key of the nearest preceding `turn_context`. */\n\tmodelKey: string | null;\n\t/** True once any in-window line was counted for this file. */\n\tcounted: boolean;\n};\n\nexport function createFileState(): FileState {\n\treturn {\n\t\tsessionId: null,\n\t\tcliVersion: null,\n\t\tcwd: null,\n\t\tmodelKey: null,\n\t\tcounted: false,\n\t};\n}\n\n/**\n * Fold one parsed rollout line into the aggregate.\n *\n * `sinceMs` is applied HERE rather than in the scanner because context lines\n * (session_meta, turn_context) must update `state` even when they predate the\n * window — a session resumed today attributes today's deltas to a model named\n * last week.\n */\nexport function ingestLine(\n\tagg: Aggregate,\n\traw: unknown,\n\tstate: FileState,\n\tsinceMs?: number,\n): void {\n\tconst rec = asObj(raw);\n\tif (!rec) return;\n\tagg.records++;\n\n\tlet tsMs: number | null = null;\n\tconst timestamp = asStr(rec.timestamp);\n\tif (timestamp) {\n\t\tconst ts = Date.parse(timestamp);\n\t\tif (!Number.isNaN(ts)) tsMs = ts;\n\t}\n\tconst inWindow = sinceMs === undefined || (tsMs !== null && tsMs >= sinceMs);\n\n\tconst type = asStr(rec.type);\n\tconst payload = asObj(rec.payload);\n\n\tif (type === \"session_meta\" && payload) {\n\t\tstate.sessionId =\n\t\t\tasStr(payload.id) ?? asStr(payload.session_id) ?? state.sessionId;\n\t\tstate.cliVersion = asStr(payload.cli_version) ?? state.cliVersion;\n\t\tstate.cwd = asStr(payload.cwd) ?? state.cwd;\n\t} else if (type === \"turn_context\" && payload) {\n\t\tconst model = asName(payload.model);\n\t\tif (model) state.modelKey = normalizeModel(model);\n\t}\n\n\tif (!inWindow) return;\n\n\tif (tsMs !== null && timestamp) {\n\t\tagg.activeDays.add(timestamp.slice(0, 10));\n\t\tagg.firstTs = agg.firstTs === null ? tsMs : Math.min(agg.firstTs, tsMs);\n\t\tagg.lastTs = agg.lastTs === null ? tsMs : Math.max(agg.lastTs, tsMs);\n\t}\n\tnoteActivity(agg, state);\n\n\tif (type === \"event_msg\" && payload) ingestEvent(agg, payload, state, tsMs);\n\telse if (type === \"response_item\" && payload) ingestItem(agg, payload);\n}\n\n/** Count the file's session/version/cwd once, on its first in-window line. */\nfunction noteActivity(agg: Aggregate, state: FileState): void {\n\tif (state.counted) return;\n\tstate.counted = true;\n\tif (state.sessionId) agg.sessions.add(state.sessionId);\n\tif (state.cliVersion) agg.ccVersions.add(cleanName(state.cliVersion));\n\t// Counted, never published — same standing non-goal as Claude project dirs.\n\tagg.projectDirs.add(state.cwd ?? \"(unknown)\");\n}\n\n// ---------------------------------------------------------------------------\n// Usage — token_count deltas\n// ---------------------------------------------------------------------------\n\nfunction ingestEvent(\n\tagg: Aggregate,\n\tpayload: Obj,\n\tstate: FileState,\n\ttsMs: number | null,\n): void {\n\tif (asStr(payload.type) !== \"token_count\") return;\n\tconst info = asObj(payload.info);\n\tconst last = info ? asObj(info.last_token_usage) : null;\n\tif (!last) return;\n\n\tconst inputTotal = asNum(last.input_tokens);\n\tconst cached = Math.min(asNum(last.cached_input_tokens), inputTotal);\n\tconst counts: TokenCounts = {\n\t\tinput: inputTotal - cached,\n\t\toutput: asNum(last.output_tokens),\n\t\tcacheWrite5m: 0,\n\t\tcacheWrite1h: 0,\n\t\tcacheWriteUnsplit: 0,\n\t\tcacheRead: cached,\n\t};\n\tconst total = countsTotal(counts);\n\t// A zero delta is a rate-limit-only refresh, not a response.\n\tif (total === 0) return;\n\n\tif (tsMs === null) agg.untimestampedResponses++;\n\tagg.distinctResponses++;\n\n\tconst modelKey = state.modelKey ?? \"(unknown)\";\n\taddModelUsage(\n\t\tagg,\n\t\tmodelKey,\n\t\tcounts,\n\t\tapiEquivalentCost(modelKey, counts, tsMs),\n\t);\n\t// Codex rollouts carry no sidechain flag; everything is the main thread,\n\t// which keeps `subagentShare` an honest 0 rather than a guess.\n\tagg.mainTokens += total;\n}\n\n// ---------------------------------------------------------------------------\n// Inventory — response_item tool calls\n// ---------------------------------------------------------------------------\n\n/**\n * MCP tools reach the model as `<server>__<tool>` (MCP_TOOL_NAME_DELIMITER in\n * the Codex source); split on the FIRST `__` to recover the server. Over-long\n * names get a hash suffix on the TOOL side, so the server segment survives.\n */\nfunction ingestCall(agg: Aggregate, name: string, callId: string | null): void {\n\tif (callId) {\n\t\tif (agg.toolCallDedup.has(callId)) return;\n\t\tagg.toolCallDedup.add(callId);\n\t}\n\tconst sep = name.indexOf(\"__\");\n\tif (sep > 0) {\n\t\tbump(agg.mcpServerCalls, cleanName(name.slice(0, sep)));\n\t\tbump(agg.mcpToolCalls, cleanName(name));\n\t\treturn;\n\t}\n\tbump(agg.toolCalls, cleanName(name));\n}\n\nfunction ingestItem(agg: Aggregate, payload: Obj): void {\n\tconst type = asStr(payload.type);\n\tif (type === \"function_call\" || type === \"custom_tool_call\") {\n\t\tconst name = asName(payload.name);\n\t\tif (!name) return;\n\t\tingestCall(agg, name, asStr(payload.call_id) ?? asStr(payload.id));\n\t\treturn;\n\t}\n\t// Non-function tool items publish under stable synthetic names that live in\n\t// CODEX_BUILTIN_TOOLS, so they survive the fail-closed filter.\n\tif (type === \"local_shell_call\") {\n\t\tingestCall(agg, \"local_shell\", asStr(payload.call_id) ?? asStr(payload.id));\n\t} else if (type === \"web_search_call\") {\n\t\tagg.webSearchRequests++;\n\t\tingestCall(agg, \"web_search\", asStr(payload.id));\n\t} else if (type === \"tool_search_call\") {\n\t\tingestCall(agg, \"tool_search\", asStr(payload.id));\n\t}\n}\n\n/**\n * Static MCP inventory from `~/.codex/config.toml` (#66 decision 3): a\n * configured server the window never called still exists. Zero-count entries\n * ride into the inventory (callShare 0) without inventing calls.\n */\nexport function noteConfiguredMcpServers(\n\tagg: Aggregate,\n\tserverNames: Iterable<string>,\n): void {\n\tfor (const raw of serverNames) {\n\t\tconst name = cleanName(raw);\n\t\tif (!agg.mcpServerCalls.has(name)) agg.mcpServerCalls.set(name, 0);\n\t}\n}\n","// I/O shell around the pure Codex analyzer: find rollout files, stream JSONL\n// (plain or zstd), hand each parsed line to ingestLine. Nothing leaves this\n// machine.\n//\n// Wayfinder ticket #67 (map #60), semantics from #65/#66.\n//\n// STANDING NON-GOAL (locked in #13): raw transcripts, prompts, absolute paths,\n// and repo names never leave the machine. `~/.codex/history.jsonl` holds raw\n// prompt text and is NEVER opened here; read errors are swallowed rather than\n// thrown, because the error object carries the absolute path.\n\nimport { type Dirent, readFileSync } from \"node:fs\";\nimport { readdir, realpath, stat } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport * as zlib from \"node:zlib\";\n\nimport { parse as parseToml } from \"smol-toml\";\n\nimport { emptyScanStats, type ScanStats } from \"../shared/window.js\";\nimport {\n\ttype Aggregate,\n\tcreateFileState,\n\tingestLine,\n\tnoteConfiguredMcpServers,\n} from \"./analyzer.js\";\n\n/** `$CODEX_HOME` honored, `~/.codex` the default — mirrors the Codex source. */\nexport function codexHome(): string {\n\treturn process.env.CODEX_HOME || path.join(homedir(), \".codex\");\n}\n\n/**\n * Only `sessions/` is read. `archived_sessions/` is deliberately excluded: an\n * archived session was removed from the user's working set, and the rolling\n * window makes old ones irrelevant anyway. `history.jsonl` is raw prompts and\n * is out of bounds entirely.\n */\nexport function rolloutRoots(): string[] {\n\treturn [path.join(codexHome(), \"sessions\")];\n}\n\nconst ROLLOUT_RE = /^rollout-.*\\.jsonl(\\.zst)?$/;\n\n/** Recursive rollout walk — the YYYY/MM/DD nesting is real. */\nasync function* walkRollouts(dir: string): AsyncGenerator<string> {\n\tlet entries: Dirent[];\n\ttry {\n\t\tentries = await readdir(dir, { withFileTypes: true });\n\t} catch {\n\t\treturn;\n\t}\n\tfor (const e of entries) {\n\t\tconst full = path.join(dir, e.name);\n\t\tif (e.isDirectory()) yield* walkRollouts(full);\n\t\telse if (e.isFile() && ROLLOUT_RE.test(e.name)) yield full;\n\t}\n}\n\n/**\n * zstd support landed in node:zlib after the CLI's floor (`engines: >=18`),\n * so it is feature-detected. On an old runtime a `.zst` rollout counts as\n * unreadable — a visible coverage figure, never a silent skip.\n */\nconst zstdDecompress: ((buf: Buffer) => Buffer) | null =\n\ttypeof (zlib as { zstdDecompressSync?: unknown }).zstdDecompressSync ===\n\t\"function\"\n\t\t? (buf) =>\n\t\t\t\t(\n\t\t\t\t\tzlib as unknown as { zstdDecompressSync: (b: Buffer) => Buffer }\n\t\t\t\t).zstdDecompressSync(buf)\n\t\t: null;\n\nexport type ScanOptions = {\n\t/** Only count records with a timestamp at or after this epoch ms. */\n\tsinceMs?: number;\n\tonProgress?: (files: number) => void;\n\t/** Override the discovered roots. Tests only. */\n\troots?: string[];\n\t/** Override the config.toml path. Tests only. */\n\tconfigFile?: string;\n};\n\nexport async function scan(\n\tagg: Aggregate,\n\topts: ScanOptions = {},\n): Promise<ScanStats> {\n\tconst stats: ScanStats = emptyScanStats();\n\tconst visited = new Set<string>();\n\n\tfor (const root of opts.roots ?? rolloutRoots()) {\n\t\tif (!(await exists(root))) continue;\n\t\tfor await (const file of walkRollouts(root)) {\n\t\t\tstats.filesFound++;\n\n\t\t\tlet resolved: string;\n\t\t\ttry {\n\t\t\t\tresolved = await realpath(file);\n\t\t\t} catch {\n\t\t\t\tresolved = file;\n\t\t\t}\n\t\t\tif (visited.has(resolved)) {\n\t\t\t\tstats.filesSkippedAsDuplicate++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvisited.add(resolved);\n\n\t\t\t// Rollouts are append-only and chronological, so a file untouched since\n\t\t\t// the window opened cannot hold an in-window record.\n\t\t\tif (opts.sinceMs !== undefined) {\n\t\t\t\ttry {\n\t\t\t\t\tconst st = await stat(file);\n\t\t\t\t\tif (st.mtimeMs < opts.sinceMs) {\n\t\t\t\t\t\tstats.filesSkippedByMtime++;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t/* unreadable stat — fall through and try to read it */\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tagg.files++;\n\t\t\tstats.filesRead++;\n\t\t\tif (opts.onProgress && agg.files % 200 === 0) opts.onProgress(agg.files);\n\t\t\ttry {\n\t\t\t\tingestFile(agg, file, opts.sinceMs);\n\t\t\t} catch {\n\t\t\t\t// Swallow deliberately: the error object carries the absolute path.\n\t\t\t\tstats.filesUnreadable++;\n\t\t\t\tstats.filesRead--;\n\t\t\t}\n\t\t}\n\t}\n\n\treadConfiguredMcpServers(agg, opts.configFile);\n\treturn stats;\n}\n\nasync function exists(p: string): Promise<boolean> {\n\ttry {\n\t\tawait stat(p);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Whole-file read rather than a stream: a `.zst` rollout must be decompressed\n * as one buffer anyway, and rollout files are single sessions — megabytes,\n * not gigabytes.\n */\nfunction ingestFile(agg: Aggregate, file: string, sinceMs?: number): void {\n\tlet text: string;\n\tif (file.endsWith(\".zst\")) {\n\t\tif (zstdDecompress === null) {\n\t\t\tthrow new Error(\"zstd not supported by this Node runtime\");\n\t\t}\n\t\ttext = zstdDecompress(readFileSync(file)).toString(\"utf8\");\n\t} else {\n\t\ttext = readFileSync(file, \"utf8\");\n\t}\n\n\tconst state = createFileState();\n\tfor (const line of text.split(\"\\n\")) {\n\t\tif (!line) continue;\n\t\tagg.lines++;\n\t\tlet rec: unknown;\n\t\ttry {\n\t\t\trec = JSON.parse(line);\n\t\t} catch {\n\t\t\tagg.parseErrors++;\n\t\t\tcontinue;\n\t\t}\n\t\tingestLine(agg, rec, state, sinceMs);\n\t}\n}\n\n/**\n * The static half of the MCP inventory (#66 decision 3): `[mcp_servers.*]`\n * in `~/.codex/config.toml`. Unreadable or absent config is silence, not an\n * error — the observed half stands on its own.\n */\nfunction readConfiguredMcpServers(agg: Aggregate, configFile?: string): void {\n\tconst file = configFile ?? path.join(codexHome(), \"config.toml\");\n\tlet names: string[] = [];\n\ttry {\n\t\tconst parsed = parseToml(readFileSync(file, \"utf8\"));\n\t\tconst servers = parsed.mcp_servers;\n\t\tif (servers && typeof servers === \"object\" && !Array.isArray(servers)) {\n\t\t\tnames = Object.keys(servers);\n\t\t}\n\t} catch {\n\t\treturn;\n\t}\n\tnoteConfiguredMcpServers(agg, names);\n}\n","// The wire payload builder — the only thing in this module that decides what\n// leaves the machine.\n//\n// Wayfinder ticket #37 (map #29). Shape fixed by the wire-format grilling #33;\n// nothing here is open design.\n//\n// Two invariants this file is responsible for:\n// 1. FAIL-CLOSED NAMES. Every freeform name is matched against an allowlist\n// before it can reach the payload; unmatched names publish only as\n// per-category counts (#33 decisions 2-4). Model ids are the sole exempt\n// class (decision 3) and are charset/length sanitized instead.\n// 2. COST IS ABSENT, NOT ZEROED. With `publishCost` off, the cost fields are\n// not in the payload at all (#33 decision 11) — there is nothing to\n// \"reveal\" server-side, because nothing was transmitted.\n\nimport {\n\ttype Aggregate,\n\tcleanName,\n\ttype Finalized,\n\tfinalize,\n\ttype ModelRow,\n} from \"./aggregate.js\";\nimport {\n\ttype Atom,\n\tfilterAtoms,\n\ttype KeptPrivateAtom,\n\tNAME_CATEGORIES,\n\ttype NameCategory,\n\ttype SyncConfig,\n} from \"./allowlist.js\";\nimport { baseModelId } from \"./pricing.js\";\nimport { type ScanStats, windowStartMs } from \"./window.js\";\n\nexport const SCHEMA_VERSION = 1;\n\nexport type PayloadModel = {\n\t/** Vendor-assigned id, sanitized. `catalogSlug` is resolved SERVER-side at read time. */\n\tid: string;\n\ttokenShare: number;\n\ttokens: {\n\t\tinput: number;\n\t\toutput: number;\n\t\tcacheWrite: number;\n\t\tcacheRead: number;\n\t};\n\tapiEquivalentUSD?: number;\n};\n\nexport type PayloadAtom = { name: string; callShare: number };\n\nexport type PayloadInventory = {\n\tbuiltinTools: PayloadAtom[];\n\tmcpServers: PayloadAtom[];\n\tskills: PayloadAtom[];\n\tsubagents: PayloadAtom[];\n\tslashCommands: PayloadAtom[];\n\t/** DISTINCT names withheld per category, so the gap in the shares is explained. */\n\twithheld: {\n\t\tbuiltinTools: number;\n\t\tmcpServers: number;\n\t\tskills: number;\n\t\tsubagents: number;\n\t\tslashCommands: number;\n\t};\n};\n\nexport type MeasuredPayload = {\n\tschemaVersion: number;\n\t/** Client clock. The server stamps its own `receivedAt` (#33 decision 6). */\n\tcapturedAt: number;\n\twindow: { days: number; from: string; to: string };\n\tharness: { name: string; version: string | null };\n\t/** `null` when `publishCost` is off — no cost was computed into the payload. */\n\tpricingTable: string | null;\n\tactivity: {\n\t\tsessions: number;\n\t\tactiveDays: number;\n\t\t/** COUNT only. Project directory names are munged absolute paths and never travel. */\n\t\tprojects: number;\n\t\ttotalTokens: number;\n\t\tcacheHitShare: number;\n\t\tsubagentShare: number;\n\t};\n\tmodels: PayloadModel[];\n\tinventory: PayloadInventory;\n\tcoverage: {\n\t\tfilesScanned: number;\n\t\tfilesUnreadable: number;\n\t\tlinesParsed: number;\n\t\tlinesFailed: number;\n\t};\n\texcludedTokens: { unpriced: number; synthetic: number };\n};\n\n// ---------------------------------------------------------------------------\n// Sanitization\n// ---------------------------------------------------------------------------\n\n/**\n * Model ids are exempt from the allowlist (#33 decision 3) precisely because\n * they are vendor-assigned: on the day a new Claude model ships, fail-closing it\n * would make its tokens silently vanish from every sync and understate cost with\n * no visible cause. Exempt is not unchecked, though — the id still becomes a\n * database key and a rendered string, so charset and length are bounded here.\n */\nconst MODEL_ID_UNSAFE_RE = /[^A-Za-z0-9._:-]+/g;\nconst MODEL_ID_MAX = 64;\n\nexport function sanitizeModelId(id: string): string {\n\tconst collapsed = cleanName(id)\n\t\t.replace(MODEL_ID_UNSAFE_RE, \"-\")\n\t\t.replace(/^-+|-+$/g, \"\");\n\tif (collapsed.length === 0) return \"unknown\";\n\treturn collapsed.length > MODEL_ID_MAX\n\t\t? collapsed.slice(0, MODEL_ID_MAX)\n\t\t: collapsed;\n}\n\nconst round4 = (n: number): number => Math.round(n * 10_000) / 10_000;\nconst round2 = (n: number): number => Math.round(n * 100) / 100;\nconst utcDate = (ms: number): string => new Date(ms).toISOString().slice(0, 10);\n\n// ---------------------------------------------------------------------------\n// Inventory\n// ---------------------------------------------------------------------------\n\nconst toAtoms = (pairs: ReadonlyArray<readonly [string, number]>): Atom[] =>\n\tpairs.map(([name, count]) => ({ name, count }));\n\n/**\n * Shares are computed over ALL observed calls, including withheld ones.\n *\n * Renormalizing over only the allowlisted atoms would make the published shares\n * sum to 1.0 and read as a complete inventory — a withheld MCP server carrying\n * 90% of the calls would leave no trace. Keeping the true denominator means the\n * shares sum to less than 1 exactly when something was withheld, and the\n * `withheld` counts say how many things.\n */\nfunction buildCategory(\n\tobserved: ReadonlyArray<readonly [string, number]>,\n\tcurated: ReadonlySet<string>,\n\toptIns: readonly string[],\n\tdenominator: number,\n): { atoms: PayloadAtom[]; withheld: number; keptPrivate: KeptPrivateAtom[] } {\n\t// The union is where #42 decision 1 lands: a name publishes if it is curated\n\t// OR the owner ticked it. Filtering itself is unchanged — still client-side,\n\t// still fail-closed, still before the send. What moves is who judged the name.\n\tconst publishable = new Set([...curated, ...optIns]);\n\tconst {\n\t\tallowed: kept,\n\t\tkeptPrivate,\n\t\twithheld,\n\t} = filterAtoms(toAtoms(observed), { publishable, curated });\n\treturn {\n\t\tatoms: kept.map((a) => ({\n\t\t\tname: a.name,\n\t\t\tcallShare: denominator ? round4(a.count / denominator) : 0,\n\t\t})),\n\t\twithheld,\n\t\tkeptPrivate,\n\t};\n}\n\nconst sumCounts = (pairs: ReadonlyArray<readonly [string, number]>): number => {\n\tlet n = 0;\n\tfor (const [, c] of pairs) n += c;\n\treturn n;\n};\n\n// ---------------------------------------------------------------------------\n// Models\n// ---------------------------------------------------------------------------\n\ntype ModelGroup = {\n\tid: string;\n\ttotalTokens: number;\n\tinput: number;\n\toutput: number;\n\tcacheWrite: number;\n\tcacheRead: number;\n\tcostUSD: number;\n\tunpricedTokens: number;\n\tanyUnpriceable: boolean;\n};\n\n/**\n * Collapse the analyzer's pricing keys into vendor-assigned ids.\n *\n * The analyzer prices fast mode under a synthetic `claude-opus-5#fast` key\n * because it bills at a different rate ($10/$50 vs $5/$25). That suffix is OURS,\n * not the vendor's, so publishing it would hand the server an id that cannot\n * resolve against the models catalog — the exact silent-disappearance failure\n * decision 3 exists to prevent. The rows are therefore merged back onto the base\n * id here. Cost stays exact because it was already accumulated per response at\n * the fast rate; what is lost is the fast-mode share itself, which the payload\n * has no field for and which is a candidate for a later schema bump.\n */\nfunction groupModels(rows: readonly ModelRow[]): ModelGroup[] {\n\tconst groups = new Map<string, ModelGroup>();\n\tfor (const r of rows) {\n\t\tconst id = sanitizeModelId(baseModelId(r.modelKey));\n\t\tlet g = groups.get(id);\n\t\tif (!g) {\n\t\t\tg = {\n\t\t\t\tid,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcostUSD: 0,\n\t\t\t\tunpricedTokens: 0,\n\t\t\t\tanyUnpriceable: false,\n\t\t\t};\n\t\t\tgroups.set(id, g);\n\t\t}\n\t\tg.totalTokens += r.totalTokens;\n\t\tg.input += r.tokens.input;\n\t\tg.output += r.tokens.output;\n\t\tg.cacheWrite +=\n\t\t\tr.tokens.cacheWrite5m +\n\t\t\tr.tokens.cacheWrite1h +\n\t\t\tr.tokens.cacheWriteUnsplit;\n\t\tg.cacheRead += r.tokens.cacheRead;\n\t\tg.costUSD += r.costUSD ?? 0;\n\t\tg.unpricedTokens += r.unpricedTokens;\n\t\tif (r.costUSD === null) g.anyUnpriceable = true;\n\t}\n\treturn [...groups.values()].sort(\n\t\t(a, b) => b.totalTokens - a.totalTokens || a.id.localeCompare(b.id),\n\t);\n}\n\nfunction buildModels(\n\trows: readonly ModelRow[],\n\ttotalTokens: number,\n\tpublishCost: boolean,\n): PayloadModel[] {\n\treturn groupModels(rows).map((g) => {\n\t\tconst model: PayloadModel = {\n\t\t\tid: g.id,\n\t\t\ttokenShare: totalTokens ? round4(g.totalTokens / totalTokens) : 0,\n\t\t\ttokens: {\n\t\t\t\tinput: g.input,\n\t\t\t\toutput: g.output,\n\t\t\t\tcacheWrite: g.cacheWrite,\n\t\t\t\tcacheRead: g.cacheRead,\n\t\t\t},\n\t\t};\n\t\t// Absent, not zero: a partially-priced model reporting a dollar figure\n\t\t// would understate without saying so. `excludedTokens.unpriced` carries\n\t\t// the tokens that were left out.\n\t\tif (publishCost && !g.anyUnpriceable && g.unpricedTokens === 0) {\n\t\t\tmodel.apiEquivalentUSD = round2(g.costUSD);\n\t\t}\n\t\treturn model;\n\t});\n}\n\n// ---------------------------------------------------------------------------\n// Build\n// ---------------------------------------------------------------------------\n\nexport type BuildPayloadInput = {\n\taggregate: Aggregate;\n\tstats: ScanStats;\n\tsyncConfig: SyncConfig;\n\t/** Client clock, epoch ms. The same value used to derive the scan window. */\n\tnow: number;\n\twindowDays: number;\n\t/** The adapter's payload discriminator, e.g. `\"claude-code\"` (#66). */\n\tharnessName: string;\n\t/** The adapter's fail-closed vendor tool set (#66 decision 3). */\n\tbuiltinTools: ReadonlySet<string>;\n\t/** The adapter's pinned price-table id, stamped only when cost publishes. */\n\tpricingTableVersion: string;\n};\n\nexport type BuiltPayload = {\n\tpayload: MeasuredPayload;\n\t/** The same numbers unfiltered, for the local report and the approve gate. */\n\tfinalized: Finalized;\n\t/**\n\t * Every observed name that will NOT publish, by category — the gate's review\n\t * list (#42 decision 1, wired in #44).\n\t *\n\t * This is the one thing here that is deliberately NOT in the payload. It is\n\t * the list of names the user has not agreed to publish, so it stays on the\n\t * machine; the payload carries only the per-category COUNT.\n\t */\n\tkeptPrivate: Record<NameCategory, KeptPrivateAtom[]>;\n};\n\nexport function buildPayload(input: BuildPayloadInput): BuiltPayload {\n\tconst {\n\t\taggregate: agg,\n\t\tstats,\n\t\tsyncConfig,\n\t\tnow,\n\t\twindowDays,\n\t\tharnessName,\n\t\tbuiltinTools,\n\t\tpricingTableVersion,\n\t} = input;\n\tconst finalized = finalize(agg);\n\tconst { publishCost, allowlist, optIns } = syncConfig;\n\n\tconst fromMs = windowStartMs(now, windowDays);\n\tconst from = utcDate(fromMs);\n\tconst to = utcDate(now);\n\n\t// Counted against the reported window rather than taken from the aggregate's\n\t// size: a clock-skewed, imported, or restored transcript dated in the future\n\t// would otherwise push activeDays past `windowDays`, printing an impossible\n\t// value under a payload that claims to be deterministic.\n\tlet activeDays = 0;\n\tfor (const d of agg.activeDays) if (d >= from && d <= to) activeDays++;\n\n\tconst totalToolCalls = finalized.totalToolCalls;\n\tconst builtins = buildCategory(\n\t\tfinalized.tools,\n\t\tbuiltinTools,\n\t\toptIns.builtinTools,\n\t\ttotalToolCalls,\n\t);\n\tconst mcp = buildCategory(\n\t\tfinalized.mcpServers,\n\t\tnew Set(allowlist.mcpServers),\n\t\toptIns.mcpServers,\n\t\tsumCounts(finalized.mcpServers),\n\t);\n\tconst skills = buildCategory(\n\t\tfinalized.skills,\n\t\tnew Set(allowlist.skills),\n\t\toptIns.skills,\n\t\tsumCounts(finalized.skills),\n\t);\n\tconst subagents = buildCategory(\n\t\tfinalized.subagents,\n\t\tnew Set(allowlist.subagents),\n\t\toptIns.subagents,\n\t\tsumCounts(finalized.subagents),\n\t);\n\tconst slash = buildCategory(\n\t\tfinalized.slashCommands,\n\t\tnew Set(allowlist.slashCommands),\n\t\toptIns.slashCommands,\n\t\tsumCounts(finalized.slashCommands),\n\t);\n\n\tconst payload: MeasuredPayload = {\n\t\tschemaVersion: SCHEMA_VERSION,\n\t\tcapturedAt: now,\n\t\twindow: { days: windowDays, from, to },\n\t\tharness: {\n\t\t\tname: harnessName,\n\t\t\tversion:\n\t\t\t\tfinalized.harnessVersion === null\n\t\t\t\t\t? null\n\t\t\t\t\t: sanitizeModelId(finalized.harnessVersion),\n\t\t},\n\t\tpricingTable: publishCost ? pricingTableVersion : null,\n\t\tactivity: {\n\t\t\tsessions: finalized.sessions,\n\t\t\tactiveDays,\n\t\t\tprojects: finalized.projects,\n\t\t\ttotalTokens: finalized.totalTokens,\n\t\t\tcacheHitShare: round4(finalized.cacheHitShare),\n\t\t\tsubagentShare: round4(finalized.sidechainShare),\n\t\t},\n\t\tmodels: buildModels(finalized.models, finalized.totalTokens, publishCost),\n\t\tinventory: {\n\t\t\tbuiltinTools: builtins.atoms,\n\t\t\tmcpServers: mcp.atoms,\n\t\t\tskills: skills.atoms,\n\t\t\tsubagents: subagents.atoms,\n\t\t\tslashCommands: slash.atoms,\n\t\t\twithheld: {\n\t\t\t\tbuiltinTools: builtins.withheld,\n\t\t\t\tmcpServers: mcp.withheld,\n\t\t\t\tskills: skills.withheld,\n\t\t\t\tsubagents: subagents.withheld,\n\t\t\t\tslashCommands: slash.withheld,\n\t\t\t},\n\t\t},\n\t\tcoverage: {\n\t\t\tfilesScanned: stats.filesRead,\n\t\t\tfilesUnreadable: stats.filesUnreadable,\n\t\t\tlinesParsed: agg.lines - agg.parseErrors,\n\t\t\tlinesFailed: agg.parseErrors,\n\t\t},\n\t\texcludedTokens: {\n\t\t\tunpriced: finalized.unpricedTokens,\n\t\t\tsynthetic: agg.syntheticTokens,\n\t\t},\n\t};\n\n\treturn {\n\t\tpayload,\n\t\tfinalized,\n\t\tkeptPrivate: {\n\t\t\tbuiltinTools: builtins.keptPrivate,\n\t\t\tmcpServers: mcp.keptPrivate,\n\t\t\tskills: skills.keptPrivate,\n\t\t\tsubagents: subagents.keptPrivate,\n\t\t\tslashCommands: slash.keptPrivate,\n\t\t},\n\t};\n}\n\n/**\n * What `POST /api/cli/sync` takes: one sealed payload PER DETECTED HARNESS,\n * one unsealed half shared across them (#66 decision 5). The batch is atomic\n * server-side, so two harnesses cannot wipe each other's staged names — which\n * is what two sequential per-harness publishes would have done, because the\n * staged list is a whole-list replace per stack.\n */\nexport type SyncBody = {\n\tpayloads: MeasuredPayload[];\n\tkeptPrivate?: Record<NameCategory, KeptPrivateAtom[]>;\n};\n\n/**\n * Union the per-harness kept-private lists into the one list the wire carries.\n *\n * One list, not one per harness, because consent is per NAME (#66 decision 5):\n * the owner ticks \"alp-river\", not \"alp-river as seen by Codex\". Counts merge\n * by (category, name); the group survives from whichever harness saw it first.\n */\nexport function mergeKeptPrivate(\n\thalves: ReadonlyArray<Record<NameCategory, KeptPrivateAtom[]>>,\n): Record<NameCategory, KeptPrivateAtom[]> {\n\tconst out = {} as Record<NameCategory, KeptPrivateAtom[]>;\n\tfor (const category of NAME_CATEGORIES) {\n\t\tconst merged = new Map<string, KeptPrivateAtom>();\n\t\tfor (const half of halves) {\n\t\t\tfor (const atom of half[category]) {\n\t\t\t\tconst held = merged.get(atom.name);\n\t\t\t\tif (held) held.count += atom.count;\n\t\t\t\telse merged.set(atom.name, { ...atom });\n\t\t\t}\n\t\t}\n\t\tout[category] = [...merged.values()].sort(\n\t\t\t(a, b) => b.count - a.count || a.name.localeCompare(b.name),\n\t\t);\n\t}\n\treturn out;\n}\n\n/**\n * Assemble the request body from the built payloads, one per detected harness.\n *\n * The two halves ride in ONE request (#48): a second call would let them drift\n * against a newer snapshot. They stay SEPARATE objects because the payload's\n * validator is closed and rejects any extra key — that closedness is the privacy\n * claim, so a kept-private name may sit beside the payloads and never inside one.\n *\n * The switch is read from the sync config the server just served. Off — or a\n * config the machine could not fetch, which reads as off — sends the payloads\n * alone and the names stay on the machine.\n */\nexport function buildSyncBody(\n\tbuilt: readonly BuiltPayload[],\n\tsyncConfig: SyncConfig,\n): SyncBody {\n\tconst payloads = built.map((b) => b.payload);\n\tif (!syncConfig.reviewKeptPrivate) return { payloads };\n\treturn {\n\t\tpayloads,\n\t\tkeptPrivate: mergeKeptPrivate(built.map((b) => b.keptPrivate)),\n\t};\n}\n","// Local transcript analysis -> the measured-layer wire payload.\n//\n// Wayfinder ticket #37 (map #29), reshaped around the adapter seam by #67\n// (map #60). Everything here runs on the user's machine; only the payloads\n// returned by `buildPayload` are ever candidates to leave it, and only after\n// the approve gate the send channel owns (ticket #41).\n//\n// Typical use:\n//\n// const now = Date.now();\n// const { config } = await loadSyncConfig({ baseUrl });\n// for (const adapter of await detectedAdapters()) {\n// const { aggregate, stats } = await adapter.scan({\n// sinceMs: windowStartMs(now, DEFAULT_WINDOW_DAYS),\n// });\n// const built = buildPayload({\n// aggregate, stats, syncConfig: config, now,\n// windowDays: DEFAULT_WINDOW_DAYS,\n// harnessName: adapter.name,\n// builtinTools: adapter.builtinTools,\n// pricingTableVersion: adapter.pricingTableVersion,\n// });\n// }\n\nimport { claudeAdapter } from \"./claude/adapter.js\";\nimport { codexAdapter } from \"./codex/adapter.js\";\nimport type { HarnessAdapter } from \"./types.js\";\n\nexport { CLAUDE_HARNESS_NAME, claudeAdapter } from \"./claude/adapter.js\";\nexport {\n\ttype Aggregate as ClaudeAggregate,\n\tcreateAggregate,\n\ttype IngestContext,\n\tingestRecord,\n} from \"./claude/analyzer.js\";\nexport { type ScanOptions, scan, transcriptRoots } from \"./claude/scan.js\";\nexport { CODEX_HARNESS_NAME, codexAdapter } from \"./codex/adapter.js\";\nexport {\n\ttype Aggregate,\n\tcleanName,\n\ttype Finalized,\n\tfinalize,\n\tisDisplaySafeName,\n\ttype ModelRow,\n\ttype ModelUsage,\n\tnewestVersion,\n} from \"./shared/aggregate.js\";\nexport {\n\ttype Atom,\n\tBUILTIN_TOOLS,\n\tBUNDLED_SYNC_CONFIG,\n\ttype CuratedAllowlist,\n\tEMPTY_OPT_INS,\n\ttype FilteredAtoms,\n\ttype FilterSets,\n\tfilterAtoms,\n\ttype KeptPrivateAtom,\n\ttype LoadedSyncConfig,\n\tloadSyncConfig,\n\tNAME_CATEGORIES,\n\ttype NameCategory,\n\ttype OptInNames,\n\tpluginGroup,\n\ttype SyncConfig,\n\ttype SyncConfigSource,\n} from \"./shared/allowlist.js\";\nexport { BUNDLED_CURATED_ALLOWLIST } from \"./shared/bundled-allowlist.js\";\nexport {\n\ttype BuildPayloadInput,\n\ttype BuiltPayload,\n\tbuildPayload,\n\tbuildSyncBody,\n\ttype MeasuredPayload,\n\tmergeKeptPrivate,\n\ttype PayloadAtom,\n\ttype PayloadInventory,\n\ttype PayloadModel,\n\tSCHEMA_VERSION,\n\ttype SyncBody,\n\tsanitizeModelId,\n} from \"./shared/payload.js\";\nexport {\n\tapiEquivalentCost,\n\tbaseModelId,\n\tCACHE_READ_MULTIPLIER,\n\tCACHE_WRITE_1H_MULTIPLIER,\n\tCACHE_WRITE_5M_MULTIPLIER,\n\tisPricedModel,\n\tnormalizeModel,\n\tOPENAI_PRICING_TABLE_VERSION,\n\tPRICING_TABLE_VERSION,\n\ttype PricePeriod,\n\tpriceAt,\n\tSONNET_5_INTRO_ENDS_MS,\n\ttype TokenCounts,\n} from \"./shared/pricing.js\";\nexport {\n\tDEFAULT_WINDOW_DAYS,\n\ttype ScanStats,\n\twindowStartMs,\n} from \"./shared/window.js\";\nexport type {\n\tHarnessAdapter,\n\tHarnessScan,\n\tHarnessScanOptions,\n} from \"./types.js\";\n\n/**\n * Every harness this build can read, in the order their payloads publish.\n * Registration order is also display order at the gate, so Claude Code — the\n * documented default — stays first.\n */\nexport const HARNESS_ADAPTERS: readonly HarnessAdapter[] = [\n\tclaudeAdapter,\n\tcodexAdapter,\n];\n\n/** The adapters whose log roots exist on this machine. */\nexport async function detectedAdapters(): Promise<HarnessAdapter[]> {\n\tconst out: HarnessAdapter[] = [];\n\tfor (const adapter of HARNESS_ADAPTERS) {\n\t\tif (await adapter.detect()) out.push(adapter);\n\t}\n\treturn out;\n}\n","// The approve gate's two beats, as text.\n//\n// Wayfinder ticket #41 (map #29), shape fixed by the spike #35 and the copy\n// locked in #48. Beat one is the FULL summary, printed as ordinary scrollable\n// transcript output. Beat two is the SHORT elicitation message — it must stay\n// short, or `Accept` falls below the fold and the gate times out (#35, 1H).\n//\n// Everything here derives from the exact bytes that will be sent (`body`),\n// plus the local-only kept-private list that deliberately never enters them.\n// Nothing in this file is accepted as a caller-supplied argument beside the\n// payload — the spike promoted that from a caution to a demonstrated property.\n\nimport type {\n\tKeptPrivateAtom,\n\tNameCategory,\n\tSyncConfig,\n\tSyncConfigSource,\n} from \"../harness/shared/allowlist.js\";\nimport { NAME_CATEGORIES } from \"../harness/shared/allowlist.js\";\nimport type { MeasuredPayload, SyncBody } from \"../harness/shared/payload.js\";\n\nexport type GateContext = {\n\t/** The exact request body a publish would send. */\n\tbody: SyncBody;\n\t/** The local-only review list — never inside any payload (#44). */\n\tkeptPrivate: Record<NameCategory, KeptPrivateAtom[]>;\n\tconfig: SyncConfig;\n\tsource: SyncConfigSource;\n\t/** Web origin for the URLs the gate prints, e.g. https://aistack.to */\n\tbaseUrl: string;\n};\n\n// ---------------------------------------------------------------------------\n// Formatting\n// ---------------------------------------------------------------------------\n\n/** `4.27B`, `40.7M`, `216k`, `950` — three significant digits, like #40. */\nexport function fmtTokens(n: number): string {\n\tconst sig = (v: number): string => {\n\t\tconst s = v.toPrecision(3);\n\t\treturn s.includes(\".\") ? s.replace(/\\.?0+$/, \"\") : s;\n\t};\n\tif (n >= 1e9) return `${sig(n / 1e9)}B`;\n\tif (n >= 1e6) return `${sig(n / 1e6)}M`;\n\tif (n >= 1e3) return `${sig(n / 1e3)}k`;\n\treturn String(n);\n}\n\n/** `≈$5,840` — whole dollars; the ≈ and \"at API prices\" wording are #37's. */\nexport function fmtUSD(n: number): string {\n\treturn `≈$${Math.round(n).toLocaleString(\"en-US\")}`;\n}\n\nconst fmtPct = (share: number): string => `${(share * 100).toFixed(1)}%`;\n\n/**\n * The dollar figure the gate names, or `null` when none may render.\n *\n * Mirrors the public display's rule (#46): a dollar figure never renders\n * without its pricing table. Summing only the models that carry the field\n * matches what actually goes up — an unpriceable model publishes tokens, not\n * dollars.\n */\nexport function totalUSD(payload: MeasuredPayload): number | null {\n\tif (payload.pricingTable === null) return null;\n\tlet sum = 0;\n\tlet any = false;\n\tfor (const m of payload.models) {\n\t\tif (m.apiEquivalentUSD !== undefined) {\n\t\t\tsum += m.apiEquivalentUSD;\n\t\t\tany = true;\n\t\t}\n\t}\n\treturn any ? sum : null;\n}\n\n/** DISTINCT kept-private names, from the send bytes (`inventory.withheld`). */\nexport function withheldCount(payload: MeasuredPayload): number {\n\tconst w = payload.inventory.withheld;\n\treturn (\n\t\tw.builtinTools + w.mcpServers + w.skills + w.subagents + w.slashCommands\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Beat two — the elicitation message. Copy locked in #48; keep it SHORT.\n// ---------------------------------------------------------------------------\n\nexport function buildGateDialog(ctx: GateContext): string {\n\tconst { payloads, keptPrivate } = ctx.body;\n\tconst tokens = payloads.reduce((a, p) => a + p.activity.totalTokens, 0);\n\tconst usds = payloads\n\t\t.map((p) => totalUSD(p))\n\t\t.filter((u): u is number => u !== null);\n\tconst usd = usds.length > 0 ? usds.reduce((a, b) => a + b, 0) : null;\n\tconst days = payloads[0]?.window.days ?? 0;\n\tconst facts = [\n\t\t`${fmtTokens(tokens)} tokens`,\n\t\t`${days} days`,\n\t\t...(usd === null ? [] : [fmtUSD(usd)]),\n\t].join(\" · \");\n\n\tconst n = payloads.reduce((a, p) => a + withheldCount(p), 0);\n\tconst lines = [`Publish to aistack? ${facts}`];\n\tif (n > 0) {\n\t\tlines.push(\n\t\t\tkeptPrivate === undefined\n\t\t\t\t? `${n} name${n === 1 ? \"\" : \"s\"} stay${n === 1 ? \"s\" : \"\"} on this machine`\n\t\t\t\t: `${n} name${n === 1 ? \"\" : \"s\"} go${n === 1 ? \"es\" : \"\"} up for you to review`,\n\t\t);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Beat one — the full summary, transcript output.\n// ---------------------------------------------------------------------------\n\nconst CATEGORY_LABEL: Record<NameCategory, string> = {\n\tbuiltinTools: \"tools\",\n\tmcpServers: \"mcp\",\n\tskills: \"skills\",\n\tsubagents: \"agents\",\n\tslashCommands: \"commands\",\n};\n\n/** Kept-private rows for the gate: one row per group, then singles (#48). */\nexport function keptPrivateRows(\n\tkeptPrivate: Record<NameCategory, KeptPrivateAtom[]>,\n): Array<{ label: string; names: number }> {\n\tconst groups = new Map<string, number>();\n\tconst singles: string[] = [];\n\tfor (const category of NAME_CATEGORIES) {\n\t\tfor (const atom of keptPrivate[category]) {\n\t\t\tif (atom.group === null) singles.push(atom.name);\n\t\t\telse groups.set(atom.group, (groups.get(atom.group) ?? 0) + 1);\n\t\t}\n\t}\n\tconst rows = [...groups].map(([label, names]) => ({ label, names }));\n\tfor (const name of singles) rows.push({ label: name, names: 1 });\n\trows.sort((a, b) => b.names - a.names || a.label.localeCompare(b.label));\n\treturn rows;\n}\n\nconst KEPT_PRIVATE_ROWS_SHOWN = 6;\n\n/** Display name for a harness discriminator the gate prints. */\nexport function harnessLabel(name: string): string {\n\tif (name === \"claude-code\") return \"Claude Code\";\n\tif (name === \"codex\") return \"Codex\";\n\treturn name;\n}\n\n/** One harness's payload block: window, activity, cost, models, inventory. */\nfunction payloadBlock(payload: MeasuredPayload, showHeader: boolean): string[] {\n\tconst out: string[] = [];\n\tif (showHeader) {\n\t\tout.push(\n\t\t\t`— ${harnessLabel(payload.harness.name)}${payload.harness.version ? ` ${payload.harness.version}` : \"\"}`,\n\t\t);\n\t}\n\tout.push(\n\t\t`window ${payload.window.days} days · ${payload.window.from} → ${payload.window.to}`,\n\t);\n\tout.push(\n\t\t`activity ${payload.activity.sessions} sessions · ${payload.activity.activeDays} active days · ${fmtTokens(payload.activity.totalTokens)} tokens`,\n\t);\n\tconst usd = totalUSD(payload);\n\tout.push(\n\t\tusd === null\n\t\t\t? \"cost not published\"\n\t\t\t: `cost ${fmtUSD(usd)} at API prices`,\n\t);\n\n\t// Coverage is silent when clean; a degraded scan is named as a floor (#40).\n\tconst cov = payload.coverage;\n\tif (cov.filesUnreadable > 0 || cov.linesFailed > 0) {\n\t\tout.push(\n\t\t\t`coverage ${cov.filesUnreadable} files unreadable · ${cov.linesFailed} lines failed — this reading is a floor`,\n\t\t);\n\t}\n\n\tout.push(\"\");\n\tout.push(\"models\");\n\tfor (const m of payload.models) {\n\t\tconst dollars =\n\t\t\tusd !== null && m.apiEquivalentUSD !== undefined\n\t\t\t\t? ` ${fmtUSD(m.apiEquivalentUSD)}`\n\t\t\t\t: \"\";\n\t\tout.push(` ${m.id.padEnd(28)} ${fmtPct(m.tokenShare)}${dollars}`);\n\t}\n\n\tout.push(\"\");\n\tout.push(\"what publishes\");\n\tfor (const category of NAME_CATEGORIES) {\n\t\tconst atoms = payload.inventory[category];\n\t\tif (atoms.length === 0) continue;\n\t\tconst names = atoms.map((a) => a.name).join(\", \");\n\t\tout.push(` ${CATEGORY_LABEL[category].padEnd(9)} ${names}`);\n\t}\n\treturn out;\n}\n\nexport function buildGateSummary(ctx: GateContext): string {\n\tconst { body, keptPrivate, config, source, baseUrl } = ctx;\n\tconst { payloads } = body;\n\tconst host = baseUrl.replace(/^https?:\\/\\//, \"\");\n\tconst out: string[] = [];\n\n\tout.push(\"from your machine — sync preview\");\n\tout.push(\"\");\n\n\tif (config.stack === null) {\n\t\tout.push(\"to (no linked stack — publish is unavailable)\");\n\t} else {\n\t\tout.push(\n\t\t\t`to ${config.stack.name} · ${host}/stacks/${config.stack.slug}`,\n\t\t);\n\t}\n\n\t// One block per detected harness. With a single harness the header line is\n\t// dropped, so the single-harness preview reads exactly as it always did.\n\tfor (const payload of payloads) {\n\t\tout.push(...payloadBlock(payload, payloads.length > 1));\n\t\tout.push(\"\");\n\t}\n\tif (out[out.length - 1] === \"\") out.pop();\n\n\tconst n = payloads.reduce((a, p) => a + withheldCount(p), 0);\n\tif (n > 0) {\n\t\tout.push(\"\");\n\t\tout.push(`kept private: ${n} name${n === 1 ? \"\" : \"s\"}`);\n\t\tconst rows = keptPrivateRows(keptPrivate);\n\t\tconst shown = rows.slice(0, KEPT_PRIVATE_ROWS_SHOWN);\n\t\tconst width = Math.max(...shown.map((r) => r.label.length));\n\t\tfor (const row of shown) {\n\t\t\tout.push(` ${row.label.padEnd(width)} ${row.names}`);\n\t\t}\n\t\tif (rows.length > shown.length) {\n\t\t\tout.push(` ...${rows.length - shown.length} more`);\n\t\t}\n\t\t// #48: beat one names the switch before the first upload, and points at\n\t\t// the changes page. Both lines are the locked copy, verbatim or near it.\n\t\tif (body.keptPrivate !== undefined && config.stack !== null) {\n\t\t\tout.push(` publish them at ${host}/stacks/${config.stack.slug}/changes`);\n\t\t\tout.push(\n\t\t\t\t\" (they go up for you to review — turn off: Review kept-private names, on your stack)\",\n\t\t\t);\n\t\t} else {\n\t\t\tout.push(\" they stay on this machine\");\n\t\t}\n\t}\n\n\tif (source === \"bundled\") {\n\t\tout.push(\"\");\n\t\tout.push(\n\t\t\t\"! could not fetch your settings from aistack — using the bundled list.\",\n\t\t);\n\t\tout.push(\n\t\t\t\" This publishes less: no cost, no ticked names, nothing staged for review.\",\n\t\t);\n\t}\n\n\treturn out.join(\"\\n\");\n}\n","// The local stdio MCP server — the send channel picked by the spike #35.\n//\n// Wayfinder ticket #41 (map #29). Two tools, two beats:\n//\n// sync_preview — scans locally, stages the exact send bytes, returns the\n// full summary as ordinary transcript output (beat one).\n// sync_publish — takes the stage id, raises a SHORT `elicitation/create`\n// with an ENUM field (beat two), and sends only on\n// `decision: \"publish\"`.\n//\n// Why elicitation and not `requiresUserInteraction`: the spike showed the\n// permission dialog can be silenced forever with one click and writes a grant\n// broader than the sentence shown, while an elicitation is raised INSIDE the\n// call — there is no string a model can spell to route around it, and no\n// \"don't ask again\" exists for it. The enum widget is the working one; the\n// boolean widget is dead in 2.1.220 and must never ship.\n//\n// Fail-closed, by construction: ESC, a timeout, a headless auto-cancel, an\n// error reply, or a client that never declared the elicitation capability all\n// resolve to \"nothing was sent\". The model's arguments count for nothing —\n// the only path to a send runs through the user's own keystrokes.\n//\n// Hand-rolled JSON-RPC over stdio, zero dependencies, structured so tests can\n// drive `handle()` directly and capture every outbound frame.\n\nimport { type SyncPublishResult, syncPublish } from \"../api.js\";\nimport { type StageDeps, type StagedSend, stageSync } from \"./stage.js\";\n\nconst SERVER_NAME = \"aistack\";\nconst SERVER_VERSION = \"0.3.0\";\n\n/** How long a staged preview stays publishable. Stale bytes must re-preview. */\nexport const STAGE_TTL_MS = 10 * 60 * 1000;\n\n/**\n * How long the gate waits for the human. Deliberately WELL past the harness's\n * own 120 s tool timeout (#35, 1H measured 92 s for a one-line answer): the\n * server must never be the first to give up. On expiry it resolves as cancel.\n */\nexport const ELICIT_TIMEOUT_MS = 10 * 60 * 1000;\n\nconst PREVIEW_TOOL = {\n\tname: \"sync_preview\",\n\tdescription:\n\t\t\"Scan local agent transcripts (Claude Code, Codex) and stage a measured-usage snapshot for aistack. \" +\n\t\t\"Returns the full preview of exactly what would publish. \" +\n\t\t\"Show the returned text to the user VERBATIM — it is the review surface. Nothing is sent.\",\n\tinputSchema: { type: \"object\", properties: {} },\n\tannotations: {\n\t\ttitle: \"aistack — preview sync (sends nothing)\",\n\t\treadOnlyHint: true,\n\t\topenWorldHint: true,\n\t},\n};\n\nconst PUBLISH_TOOL = {\n\tname: \"sync_publish\",\n\tdescription:\n\t\t\"Publish the staged aistack snapshot named by preview_id. \" +\n\t\t\"Asks the user for confirmation during the call; only their explicit choice sends anything. \" +\n\t\t\"Call sync_preview first and show its output.\",\n\tinputSchema: {\n\t\ttype: \"object\",\n\t\tproperties: {\n\t\t\tpreview_id: {\n\t\t\t\ttype: \"string\",\n\t\t\t\tdescription: \"The `preview id` line from sync_preview's output.\",\n\t\t\t},\n\t\t},\n\t\trequired: [\"preview_id\"],\n\t},\n\tannotations: {\n\t\ttitle: \"aistack — publish measured usage (asks the user first)\",\n\t\tdestructiveHint: false,\n\t\topenWorldHint: true,\n\t},\n};\n\ntype JsonRpcMessage = {\n\tjsonrpc?: string;\n\tid?: string | number;\n\tmethod?: string;\n\tparams?: Record<string, unknown> | undefined;\n\tresult?: unknown;\n\terror?: unknown;\n};\n\nexport type SyncServerDeps = {\n\tbaseUrl: string;\n\tstageImpl?: (deps: StageDeps) => Promise<StagedSend>;\n\tpublishImpl?: (token: string, bodyJson: string) => Promise<SyncPublishResult>;\n\tnow?: () => number;\n\telicitTimeoutMs?: number;\n\t/** Diagnostics only. NEVER stdout — that would corrupt the protocol. */\n\tlog?: (line: string) => void;\n};\n\nexport type SyncServer = {\n\thandle: (msg: JsonRpcMessage) => void;\n\t/** Test seam: the staged send, if any. */\n\tstaged: () => StagedSend | null;\n};\n\nconst textResult = (text: string, isError = false) => ({\n\tcontent: [{ type: \"text\", text }],\n\t...(isError ? { isError: true } : {}),\n});\n\nexport function createSyncServer(\n\tdeps: SyncServerDeps,\n\tsend: (msg: JsonRpcMessage) => void,\n): SyncServer {\n\tconst now = deps.now ?? Date.now;\n\tconst stage = deps.stageImpl ?? stageSync;\n\tconst publish = deps.publishImpl ?? syncPublish;\n\tconst log = deps.log ?? (() => {});\n\tconst elicitTimeoutMs = deps.elicitTimeoutMs ?? ELICIT_TIMEOUT_MS;\n\n\tlet clientSupportsElicitation = false;\n\tlet staged: StagedSend | null = null;\n\tlet nextRequestId = 1;\n\tconst pending = new Map<string, (reply: JsonRpcMessage | null) => void>();\n\n\tconst ok = (id: string | number | undefined, result: unknown) =>\n\t\tsend({ jsonrpc: \"2.0\", id, result });\n\tconst err = (\n\t\tid: string | number | undefined,\n\t\tcode: number,\n\t\tmessage: string,\n\t) => send({ jsonrpc: \"2.0\", id, error: { code, message } });\n\n\t/** Ask the client something; `null` reply means the gate timed out. */\n\tconst request = (\n\t\tmethod: string,\n\t\tparams: Record<string, unknown>,\n\t\tonReply: (reply: JsonRpcMessage | null) => void,\n\t) => {\n\t\tconst id = `aistack-${nextRequestId++}`;\n\t\tpending.set(id, onReply);\n\t\tsend({ jsonrpc: \"2.0\", id, method, params });\n\t\tconst timer = setTimeout(() => {\n\t\t\tif (pending.delete(id)) onReply(null);\n\t\t}, elicitTimeoutMs);\n\t\t(timer as { unref?: () => void }).unref?.();\n\t};\n\n\tconst runPreview = async (id: string | number | undefined) => {\n\t\ttry {\n\t\t\tstaged = await stage({ baseUrl: deps.baseUrl, now });\n\t\t} catch (e) {\n\t\t\tstaged = null;\n\t\t\tconst message = e instanceof Error ? e.message : String(e);\n\t\t\treturn ok(id, textResult(`Preview failed: ${message}`, true));\n\t\t}\n\t\tconst lines = [staged.summary, \"\"];\n\t\tif (staged.blockedReason === null) {\n\t\t\tlines.push(`preview id: ${staged.id}`);\n\t\t\tlines.push(\n\t\t\t\t\"To publish, call sync_publish with this preview id. The user confirms in a dialog during that call.\",\n\t\t\t);\n\t\t} else {\n\t\t\tlines.push(`publish unavailable: ${staged.blockedReason}`);\n\t\t}\n\t\treturn ok(id, textResult(lines.join(\"\\n\")));\n\t};\n\n\tconst runPublish = (\n\t\tid: string | number | undefined,\n\t\targs: Record<string, unknown> | undefined,\n\t) => {\n\t\t// Every refusal below is fail-closed: no dialog was shown, nothing sent.\n\t\tif (!clientSupportsElicitation) {\n\t\t\treturn ok(\n\t\t\t\tid,\n\t\t\t\ttextResult(\n\t\t\t\t\t\"Not published: this Claude Code version did not declare the elicitation capability, \" +\n\t\t\t\t\t\t\"so the approve dialog cannot be shown. The gate never degrades silently — \" +\n\t\t\t\t\t\t\"update Claude Code and try again.\",\n\t\t\t\t\ttrue,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tconst previewId = args?.preview_id;\n\t\tif (staged === null) {\n\t\t\treturn ok(\n\t\t\t\tid,\n\t\t\t\ttextResult(\n\t\t\t\t\t\"Not published: nothing is staged. Run sync_preview first and show its output to the user.\",\n\t\t\t\t\ttrue,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tif (typeof previewId !== \"string\" || previewId !== staged.id) {\n\t\t\treturn ok(\n\t\t\t\tid,\n\t\t\t\ttextResult(\n\t\t\t\t\t\"Not published: preview_id does not match the staged preview. Run sync_preview again.\",\n\t\t\t\t\ttrue,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tif (staged.blockedReason !== null) {\n\t\t\treturn ok(id, textResult(`Not published: ${staged.blockedReason}`, true));\n\t\t}\n\t\tif (now() - staged.stagedAt > STAGE_TTL_MS) {\n\t\t\tstaged = null;\n\t\t\treturn ok(\n\t\t\t\tid,\n\t\t\t\ttextResult(\n\t\t\t\t\t\"Not published: the staged preview is older than 10 minutes. Run sync_preview again so the user reviews current bytes.\",\n\t\t\t\t\ttrue,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tconst approvedStage = staged;\n\t\tlog(`elicitation raised for stage ${approvedStage.id}`);\n\t\trequest(\n\t\t\t\"elicitation/create\",\n\t\t\t{\n\t\t\t\tmessage: approvedStage.dialog,\n\t\t\t\trequestedSchema: {\n\t\t\t\t\ttype: \"object\",\n\t\t\t\t\tproperties: {\n\t\t\t\t\t\tdecision: {\n\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t// The enum widget is the one that works (#35, 1G). Never a boolean.\n\t\t\t\t\t\t\tenum: [\"publish\", \"cancel\"],\n\t\t\t\t\t\t\tdescription: \"Publish the snapshot described above?\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\trequired: [\"decision\"],\n\t\t\t\t},\n\t\t\t},\n\t\t\t(reply) => {\n\t\t\t\tconst result = reply?.result as\n\t\t\t\t\t| { action?: string; content?: { decision?: string } }\n\t\t\t\t\t| undefined;\n\t\t\t\tconst approved =\n\t\t\t\t\tresult?.action === \"accept\" &&\n\t\t\t\t\tresult?.content?.decision === \"publish\";\n\t\t\t\tif (!approved) {\n\t\t\t\t\tconst outcome =\n\t\t\t\t\t\treply === null ? \"timed out\" : (result?.action ?? \"error\");\n\t\t\t\t\tlog(`elicitation resolved without consent: ${outcome}`);\n\t\t\t\t\treturn ok(\n\t\t\t\t\t\tid,\n\t\t\t\t\t\ttextResult(\n\t\t\t\t\t\t\t`Not published: the confirmation was not accepted (${outcome}). Nothing left this machine.`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tlog(`consent received, sending stage ${approvedStage.id}`);\n\t\t\t\tpublish(approvedStage.token as string, approvedStage.bodyJson).then(\n\t\t\t\t\t(res) => {\n\t\t\t\t\t\tif (staged?.id === approvedStage.id) staged = null;\n\t\t\t\t\t\tconst lines = [\n\t\t\t\t\t\t\t`Published. Snapshot received at ${new Date(res.receivedAt).toISOString()}.`,\n\t\t\t\t\t\t\tres.url,\n\t\t\t\t\t\t];\n\t\t\t\t\t\tconst kp = approvedStage.body.keptPrivate;\n\t\t\t\t\t\tif (res.keptPrivate.refused && kp !== undefined) {\n\t\t\t\t\t\t\tlines.push(\n\t\t\t\t\t\t\t\t\"Note: the kept-private names were refused by the server — the review switch is off there now. They stayed on this machine.\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else if (res.keptPrivate.stored > 0) {\n\t\t\t\t\t\t\tlines.push(\n\t\t\t\t\t\t\t\t`${res.keptPrivate.stored} kept-private names went up for your review at ${res.url}/changes`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tok(id, textResult(lines.join(\"\\n\")));\n\t\t\t\t\t},\n\t\t\t\t\t(e) => {\n\t\t\t\t\t\tconst message = e instanceof Error ? e.message : String(e);\n\t\t\t\t\t\tok(\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\ttextResult(`Publish failed after consent: ${message}`, true),\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\t};\n\n\tconst handle = (msg: JsonRpcMessage) => {\n\t\tconst { id, method, params } = msg;\n\n\t\t// A reply to something we asked, not a new request.\n\t\tif (method === undefined && id !== undefined && pending.has(String(id))) {\n\t\t\tconst onReply = pending.get(String(id));\n\t\t\tpending.delete(String(id));\n\t\t\tonReply?.(msg);\n\t\t\treturn;\n\t\t}\n\n\t\tswitch (method) {\n\t\t\tcase \"initialize\": {\n\t\t\t\tconst capabilities =\n\t\t\t\t\t(params?.capabilities as Record<string, unknown> | undefined) ?? {};\n\t\t\t\tclientSupportsElicitation = \"elicitation\" in capabilities;\n\t\t\t\tlog(\n\t\t\t\t\t`initialize: elicitation ${clientSupportsElicitation ? \"declared\" : \"ABSENT\"}`,\n\t\t\t\t);\n\t\t\t\treturn ok(id, {\n\t\t\t\t\tprotocolVersion:\n\t\t\t\t\t\t(params?.protocolVersion as string | undefined) ?? \"2025-06-18\",\n\t\t\t\t\tcapabilities: { tools: { listChanged: false } },\n\t\t\t\t\tserverInfo: { name: SERVER_NAME, version: SERVER_VERSION },\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"ping\":\n\t\t\t\treturn ok(id, {});\n\n\t\t\tcase \"tools/list\":\n\t\t\t\treturn ok(id, { tools: [PREVIEW_TOOL, PUBLISH_TOOL] });\n\n\t\t\tcase \"tools/call\": {\n\t\t\t\tconst name = params?.name;\n\t\t\t\tconst args = params?.arguments as Record<string, unknown> | undefined;\n\t\t\t\tif (name === \"sync_preview\") return void runPreview(id);\n\t\t\t\tif (name === \"sync_publish\") return runPublish(id, args);\n\t\t\t\treturn err(id, -32602, `Unknown tool: ${String(name)}`);\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tif (method?.startsWith(\"notifications/\")) return;\n\t\t\t\tif (method !== undefined)\n\t\t\t\t\treturn err(id, -32601, `Method not found: ${method}`);\n\t\t}\n\t};\n\n\treturn { handle, staged: () => staged };\n}\n\n/** Wire the server to real stdio. Never returns; the harness owns the process. */\nexport function runStdioSyncServer(deps: SyncServerDeps): void {\n\tconst server = createSyncServer(deps, (msg) => {\n\t\tprocess.stdout.write(`${JSON.stringify(msg)}\\n`);\n\t});\n\tlet buffer = \"\";\n\tprocess.stdin.setEncoding(\"utf8\");\n\tprocess.stdin.on(\"data\", (chunk: string) => {\n\t\tbuffer += chunk;\n\t\tlet nl = buffer.indexOf(\"\\n\");\n\t\twhile (nl !== -1) {\n\t\t\tconst line = buffer.slice(0, nl).trim();\n\t\t\tbuffer = buffer.slice(nl + 1);\n\t\t\tif (line) {\n\t\t\t\ttry {\n\t\t\t\t\tserver.handle(JSON.parse(line));\n\t\t\t\t} catch (e) {\n\t\t\t\t\tdeps.log?.(`parse error: ${String(e)}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tnl = buffer.indexOf(\"\\n\");\n\t\t}\n\t});\n}\n"],"mappings":"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","names":["path","p","dirname","dirname","dirname","path","existsSync","readFileSync","homedir","join","path","existsSync","readFileSync","homedir","join","path","readJson","existsSync","readFileSync","homedir","join","path","p","readJson","existsSync","readFileSync","join","homedir","existsSync","readdirSync","readFileSync","homedir","join","stat","intro","outro","intro","outro","existsSync","homedir","dirname","join","p","join","homedir","dirname","existsSync","intro","outro","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","p","intro","join","existsSync","readFileSync","confirm","dirname","mkdirSync","writeFileSync","outro","p","intro","outro","p","existsSync","mkdirSync","readFileSync","writeFileSync","homedir","dirname","join","p","existsSync","mkdirSync","readFileSync","writeFileSync","homedir","dirname","join","isOurs","mkdirSync","readFileSync","writeFileSync","homedir","dirname","join","createHash","stat","p","p","createAggregate","homedir","homedir","p","exists","p","stat","createAggregate","stat","createAggregate","readFileSync","readdir","realpath","stat","homedir","path","parseToml","codexHome","path","homedir","readdir","scan","exists","realpath","stat","ingestFile","p","readFileSync","parseToml","exists","p","stat","createAggregate","scan","p","lines","createHash","join","homedir","mkdirSync","dirname","lines","readFileSync","writeFileSync","failure","intro","outro","lines","log","request","lines"]}