@fabricorg/cli 0.3.6 → 0.4.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bin/fabric.ts","../package.json","../src/commands/agents/index.ts","../src/lib/client.ts","../src/lib/config.ts","../src/lib/output.ts","../src/lib/context.ts","../src/commands/auth/keys.ts","../src/commands/auth/login.ts","../src/commands/auth/logout.ts","../src/commands/auth/whoami.ts","../src/commands/chats/index.ts","../src/commands/completion/index.ts","../src/commands/context/index.ts","../src/lib/command-boundary.ts","../src/lib/context-sync/lock.ts","../src/lib/instructions/safe-write.ts","../src/lib/instructions/paths.ts","../src/lib/context-sync/source-path.ts","../src/lib/context-sync/classify.ts","../src/lib/context-sync/ignore.ts","../src/lib/context-sync/walk.ts","../src/lib/context-sync/plan.ts","../src/lib/context-sync/push.ts","../src/lib/context-sync/report.ts","../src/commands/ctx/index.ts","../src/commands/features/index.ts","../src/commands/frames/index.ts","../src/commands/instructions/index.ts","../src/lib/instructions/apply.ts","../src/lib/instructions/bundle.ts","../src/lib/instructions/hook.ts","../src/lib/instructions/lock.ts","../src/lib/instructions/manifest.ts","../src/lib/instructions/plan.ts","../src/lib/instructions/push.ts","../src/commands/mcp/index.ts","../src/commands/orgs/index.ts","../src/commands/projects/index.ts","../src/commands/prompts/index.ts","../src/commands/reports/index.ts","../src/commands/skills/index.ts","../src/commands/workflows/index.ts","../src/commands/workspaces/index.ts"],"sourcesContent":["/**\n * @fabricorg/cli — fabric command\n *\n * Usage: fabric <command> [subcommand] [options]\n *\n * Exit codes:\n * 0 success\n * 1 general failure\n * 2 invalid usage / bad arguments\n * 3 auth failure\n * 4 not found\n * 5 forbidden\n * 6 rate limited\n * 7 validation error\n */\n\nimport { Command } from \"commander\";\nimport packageJson from \"../../package.json\";\nimport { buildAgentsCommand } from \"../commands/agents/index.js\";\nimport { buildKeysCommand } from \"../commands/auth/keys.js\";\nimport { buildLoginCommand } from \"../commands/auth/login.js\";\nimport { buildLogoutCommand } from \"../commands/auth/logout.js\";\nimport { buildWhoamiCommand } from \"../commands/auth/whoami.js\";\nimport { buildChatsCommand } from \"../commands/chats/index.js\";\nimport { buildCompletionCommand } from \"../commands/completion/index.js\";\nimport { buildContextCommand } from \"../commands/context/index.js\";\nimport { buildCtxCommand } from \"../commands/ctx/index.js\";\nimport { buildFeaturesCommand } from \"../commands/features/index.js\";\nimport { buildFramesCommand } from \"../commands/frames/index.js\";\nimport { buildInstructionsCommand } from \"../commands/instructions/index.js\";\nimport { buildMcpCommand } from \"../commands/mcp/index.js\";\nimport { buildOrgsCommand } from \"../commands/orgs/index.js\";\nimport { buildProjectsCommand } from \"../commands/projects/index.js\";\nimport { buildPromptsCommand } from \"../commands/prompts/index.js\";\nimport { buildReportsCommand } from \"../commands/reports/index.js\";\nimport { buildSkillsCommand } from \"../commands/skills/index.js\";\nimport { buildWorkflowsCommand } from \"../commands/workflows/index.js\";\nimport { buildWorkspacesCommand } from \"../commands/workspaces/index.js\";\nimport { getConfigPath } from \"../lib/config.js\";\n\nconst program = new Command();\n\nprogram\n\t.name(\"fabric\")\n\t.description(\"Fabric AI platform CLI\")\n\t.version(packageJson.version)\n\t.option(\n\t\t\"--format <format>\",\n\t\t\"Output format: table|json|yaml|csv\",\n\t\tprocess.env.FABRIC_FORMAT ?? \"table\",\n\t);\n\n// ---------------------------------------------------------------------------\n// fabric auth\n// ---------------------------------------------------------------------------\nconst auth = new Command(\"auth\").description(\n\t\"Authenticate and manage API keys\",\n);\nauth.addCommand(buildLoginCommand());\nauth.addCommand(buildLogoutCommand());\nauth.addCommand(buildWhoamiCommand());\nauth.addCommand(buildKeysCommand());\nprogram.addCommand(auth);\n\n// ---------------------------------------------------------------------------\n// fabric ctx\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildCtxCommand());\n\n// ---------------------------------------------------------------------------\n// fabric orgs\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildOrgsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric projects\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildProjectsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric features\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildFeaturesCommand());\n\n// ---------------------------------------------------------------------------\n// fabric workflows\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildWorkflowsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric prompts\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildPromptsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric agents\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildAgentsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric skills\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildSkillsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric instructions\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildInstructionsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric context — project Context (knowledge sources), not `fabric ctx`\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildContextCommand());\n\n// ---------------------------------------------------------------------------\n// fabric mcp\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildMcpCommand());\n\n// ---------------------------------------------------------------------------\n// fabric frames\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildFramesCommand());\n\n// ---------------------------------------------------------------------------\n// fabric workspaces\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildWorkspacesCommand());\n\n// ---------------------------------------------------------------------------\n// fabric chats\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildChatsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric reports\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildReportsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric completion\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildCompletionCommand());\n\n// ---------------------------------------------------------------------------\n// fabric config\n// ---------------------------------------------------------------------------\nconst config = new Command(\"config\").description(\"Show CLI configuration\");\nconfig\n\t.command(\"path\")\n\t.description(\"Print the path to the config file\")\n\t.action(() => {\n\t\tprocess.stdout.write(`${getConfigPath()}\\n`);\n\t});\nprogram.addCommand(config);\n\n// ---------------------------------------------------------------------------\n// Global error handler — structured JSON for --format json\n// ---------------------------------------------------------------------------\nprocess.on(\"unhandledRejection\", (reason) => {\n\tconst message = reason instanceof Error ? reason.message : String(reason);\n\tif (process.env.FABRIC_FORMAT === \"json\") {\n\t\tprocess.stderr.write(\n\t\t\tJSON.stringify({ error: { message, code: \"UNHANDLED_ERROR\" } }) +\n\t\t\t\t\"\\n\",\n\t\t);\n\t} else {\n\t\tprocess.stderr.write(`✗ ${message}\\n`);\n\t}\n\tprocess.exit(1);\n});\n\nprogram.parse(process.argv);\n","{\n\t\"name\": \"@fabricorg/cli\",\n\t\"version\": \"0.3.6\",\n\t\"description\": \"CLI for the Fabric AI platform\",\n\t\"keywords\": [\n\t\t\"fabric\",\n\t\t\"ai\",\n\t\t\"cli\",\n\t\t\"developer-tools\"\n\t],\n\t\"homepage\": \"https://fabric.pro\",\n\t\"license\": \"MIT\",\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"git+https://github.com/Fabric-Pro/fabric-oss.git\",\n\t\t\"directory\": \"packages/cli\"\n\t},\n\t\"type\": \"module\",\n\t\"bin\": {\n\t\t\"fabric\": \"./dist/fabric.js\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"publishConfig\": {\n\t\t\"access\": \"public\"\n\t},\n\t\"scripts\": {\n\t\t\"build\": \"tsup\",\n\t\t\"dev\": \"tsup --watch\",\n\t\t\"type-check\": \"tsc --noEmit\",\n\t\t\"test\": \"vitest run\",\n\t\t\"test:watch\": \"vitest\",\n\t\t\"fabric\": \"node --import tsx/esm src/bin/fabric.ts\"\n\t},\n\t\"dependencies\": {\n\t\t\"@fabricorg/sdk\": \"workspace:*\",\n\t\t\"@fabricorg/sdk-mcp\": \"workspace:*\",\n\t\t\"cli-table3\": \"^0.6.5\",\n\t\t\"commander\": \"^13.1.0\",\n\t\t\"conf\": \"^13.1.0\",\n\t\t\"fflate\": \"^0.8.3\",\n\t\t\"ignore\": \"7.0.9\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@repo/tsconfig\": \"workspace:*\",\n\t\t\"tsup\": \"^8.0.0\",\n\t\t\"tsx\": \"^4.21.0\",\n\t\t\"typescript\": \"5.9.3\",\n\t\t\"vitest\": \"^4.1.11\"\n\t}\n}\n","/**\n * fabric agents\n *\n * fabric agents list List agents\n * fabric agents show <id> Show agent details\n */\n\nimport type { FabricAgent } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildAgentsCommand(): Command {\n\tconst agents = new Command(\"agents\").description(\"Manage agents\");\n\n\t// -- list ----------------------------------------------------------------\n\tagents\n\t\t.command(\"list\")\n\t\t.description(\"List agents\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--status <status>\", \"Filter: ACTIVE|INACTIVE|DEPRECATED\")\n\t\t.option(\"--limit <n>\", \"Max results\", \"50\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tstatus?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricAgent[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.agents.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tstatus: opts.status as\n\t\t\t\t\t\t\t| FabricAgent[\"status\"]\n\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const a of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${a.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\"displayName\",\n\t\t\t\t\t\t\"framework\",\n\t\t\t\t\t\t\"status\",\n\t\t\t\t\t\t\"createdAt\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- show ----------------------------------------------------------------\n\tagents\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show agent details\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet agent: FabricAgent;\n\t\t\t\ttry {\n\t\t\t\t\tagent = await client.agents.get(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(agent, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: agent.id,\n\t\t\t\t\t\"Agent ID\": agent.agentId,\n\t\t\t\t\tName: agent.name,\n\t\t\t\t\t\"Display name\": agent.displayName,\n\t\t\t\t\tFramework: agent.framework,\n\t\t\t\t\tStatus: agent.status,\n\t\t\t\t\t\"Deployment URL\": agent.deploymentUrl ?? \"(none)\",\n\t\t\t\t\tCreated: agent.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- execute -------------------------------------------------------------\n\tagents\n\t\t.command(\"execute <id>\")\n\t\t.description(\"Execute an agent\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--input <json>\", 'Input JSON (e.g. \\'{\"key\":\"value\"}\\')')\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: {\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\tinput?: string;\n\t\t\t\t\tformat: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\n\t\t\t\tlet inputObj: Record<string, unknown> = {};\n\t\t\t\tif (opts.input) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tinputObj = JSON.parse(opts.input);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tprintError(\"--input must be valid JSON\", 2);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlet result: import(\"@fabricorg/sdk\").FabricAgentExecution;\n\t\t\t\ttry {\n\t\t\t\t\tresult = await client.agents.execute(id, {\n\t\t\t\t\t\tinput: inputObj,\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(result, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\t\"Task ID\": result.taskId,\n\t\t\t\t\t\"Workflow ID\": result.workflowId,\n\t\t\t\t\t\"Run ID\": result.runId ?? \"(pending)\",\n\t\t\t\t\tStatus: result.status,\n\t\t\t\t\t...(result.warning ? { Warning: result.warning } : {}),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn agents;\n}\n","/**\n * Returns a configured FabricClient for CLI commands.\n * Exits with a clear error if no API key is available.\n */\n\nimport { FabricAuthError, FabricClient } from \"@fabricorg/sdk\";\nimport { getApiKey, getBaseUrl } from \"./config.js\";\nimport { printError } from \"./output.js\";\n\nexport interface ClientOverrides {\n\t/**\n\t * Retry policy. The SDK's default retries twice, and its timeout is PER\n\t * ATTEMPT, so a \"5 second\" call can really take about 15.75 seconds with\n\t * backoff. Session-hook mode turns retries off so its own deadline is the\n\t * only bound that matters.\n\t */\n\tretry?: { maxRetries: number };\n\t/**\n\t * Per-request timeout. The SDK sets this on the CLIENT, not per call, so\n\t * a command that must answer fast — the session-start instructions check\n\t * — builds its own client rather than reaching for a per-call option that\n\t * does not exist.\n\t */\n\ttimeoutMs?: number;\n}\n\nexport function getClient(overrides: ClientOverrides = {}): FabricClient {\n\tconst apiKey = getApiKey();\n\n\tif (!apiKey) {\n\t\tprintError(\n\t\t\t\"Not authenticated. Run:\\n fabric auth login --key <api-key>\",\n\t\t\t3,\n\t\t);\n\t}\n\n\ttry {\n\t\treturn new FabricClient({\n\t\t\tapiKey,\n\t\t\tbaseUrl: getBaseUrl(),\n\t\t\t...(overrides.timeoutMs !== undefined\n\t\t\t\t? { timeoutMs: overrides.timeoutMs }\n\t\t\t\t: {}),\n\t\t\t...(overrides.retry !== undefined\n\t\t\t\t? { retry: overrides.retry }\n\t\t\t\t: {}),\n\t\t});\n\t} catch (err: unknown) {\n\t\tif (err instanceof FabricAuthError) {\n\t\t\tprintError(err.message, 3);\n\t\t}\n\t\tthrow err;\n\t}\n}\n","/**\n * Config storage for @fabricorg/cli\n *\n * Persists to XDG_CONFIG_HOME/fabricai/config.json (Linux/macOS)\n * or %APPDATA%\\fabricai\\config.json (Windows).\n *\n * The API key is stored as-is in the config file with 0600 permissions.\n * Future: migrate to system keychain.\n */\n\nimport Conf from \"conf\";\n\ninterface CliConfig {\n\t/** Active profile name */\n\tactiveProfile: string;\n\tprofiles: Record<string, ProfileConfig>;\n\t/** Default output format */\n\tdefaultFormat: \"table\" | \"json\" | \"yaml\" | \"csv\";\n}\n\ninterface ProfileConfig {\n\t/** API key for this profile */\n\tapiKey?: string;\n\t/** Override base URL (e.g. for self-hosted) */\n\tbaseUrl?: string;\n\t/** Default context for commands */\n\tdefaultContext?: ContextConfig;\n}\n\nexport type ContextConfig =\n\t| { type: \"personal\" }\n\t| { type: \"org\"; slug: string };\n\nconst DEFAULTS: CliConfig = {\n\tactiveProfile: \"default\",\n\tprofiles: {},\n\tdefaultFormat: \"table\",\n};\n\nlet _store: Conf<CliConfig> | undefined;\n\nfunction getStore(): Conf<CliConfig> {\n\tif (!_store) {\n\t\t_store = new Conf<CliConfig>({\n\t\t\tprojectName: \"fabricai\",\n\t\t\tdefaults: DEFAULTS,\n\t\t});\n\t}\n\treturn _store;\n}\n\nfunction getConfig(): CliConfig {\n\treturn getStore().store;\n}\n\nfunction getActiveProfile(): ProfileConfig {\n\tconst cfg = getConfig();\n\treturn cfg.profiles[cfg.activeProfile] ?? {};\n}\n\nexport function getApiKey(): string | undefined {\n\t// Env var takes precedence over stored config\n\tif (process.env.FABRIC_API_KEY) {\n\t\treturn process.env.FABRIC_API_KEY;\n\t}\n\treturn getActiveProfile().apiKey;\n}\n\nexport function getBaseUrl(): string | undefined {\n\tif (process.env.FABRIC_BASE_URL) {\n\t\treturn process.env.FABRIC_BASE_URL;\n\t}\n\treturn getActiveProfile().baseUrl;\n}\n\nexport function getDefaultContext(): ContextConfig | undefined {\n\t// Env var takes precedence\n\tif (process.env.FABRIC_ORG) {\n\t\treturn { type: \"org\", slug: process.env.FABRIC_ORG };\n\t}\n\tif (process.env.FABRIC_PERSONAL === \"1\") {\n\t\treturn { type: \"personal\" };\n\t}\n\treturn getActiveProfile().defaultContext;\n}\n\nexport function getOutputFormat(): \"table\" | \"json\" | \"yaml\" | \"csv\" {\n\tif (\n\t\tprocess.env.FABRIC_FORMAT === \"json\" ||\n\t\tprocess.env.FABRIC_FORMAT === \"yaml\" ||\n\t\tprocess.env.FABRIC_FORMAT === \"csv\"\n\t) {\n\t\treturn process.env.FABRIC_FORMAT as \"json\" | \"yaml\" | \"csv\";\n\t}\n\treturn getConfig().defaultFormat;\n}\n\nexport interface SaveApiKeyOptions {\n\t/** Persisted only when a login explicitly selected a deployment URL. */\n\tbaseUrl?: string;\n}\n\n/**\n * Save credentials into the active profile in one profile update.\n *\n * `FABRIC_BASE_URL` remains an execution-time override: callers only pass a\n * base URL here when the person explicitly chose it with `--base-url`.\n */\nexport function saveApiKey(\n\tapiKey: string,\n\t{ baseUrl }: SaveApiKeyOptions = {},\n): void {\n\tconst store = getStore();\n\tconst profile = store.get(\"activeProfile\") as string;\n\tconst profiles = store.get(\"profiles\") as CliConfig[\"profiles\"];\n\tconst current = profiles[profile] ?? {};\n\tstore.set(\"profiles\", {\n\t\t...profiles,\n\t\t[profile]: {\n\t\t\t...current,\n\t\t\tapiKey,\n\t\t\t...(baseUrl === undefined ? {} : { baseUrl }),\n\t\t},\n\t});\n}\n\nexport function clearApiKey(profile?: string): void {\n\tconst store = getStore();\n\tconst active = profile ?? (store.get(\"activeProfile\") as string);\n\tconst profiles = store.get(\"profiles\") as CliConfig[\"profiles\"];\n\tconst { apiKey: _, ...rest } = profiles[active] ?? {};\n\tstore.set(\"profiles\", { ...profiles, [active]: rest });\n}\n\nexport function saveDefaultContext(ctx: ContextConfig, profile?: string): void {\n\tconst store = getStore();\n\tconst active = profile ?? (store.get(\"activeProfile\") as string);\n\tconst profiles = store.get(\"profiles\") as CliConfig[\"profiles\"];\n\tstore.set(\"profiles\", {\n\t\t...profiles,\n\t\t[active]: { ...(profiles[active] ?? {}), defaultContext: ctx },\n\t});\n}\n\nexport function getConfigPath(): string {\n\treturn getStore().path;\n}\n","/**\n * Output formatting for @fabricorg/cli\n *\n * Supports: table (default), json, yaml, csv, quiet (IDs only)\n */\n\nimport Table from \"cli-table3\";\nimport { getOutputFormat } from \"./config.js\";\n\ntype OutputFormat = \"table\" | \"json\" | \"yaml\" | \"csv\" | \"quiet\";\n\nexport interface OutputOptions {\n\tformat?: OutputFormat;\n\t/** Column names to include in table/csv output (in order) */\n\tcolumns?: string[];\n\t/** Key to use for --quiet / IDs-only output */\n\tidKey?: string;\n}\n\n/** Print data to stdout in the selected format. */\nexport function printOutput(data: unknown, opts: OutputOptions = {}): void {\n\tconst format = opts.format ?? (getOutputFormat() as OutputFormat);\n\n\tif (format === \"json\") {\n\t\tprocess.stdout.write(`${JSON.stringify(data, null, 2)}\\n`);\n\t\treturn;\n\t}\n\n\tif (format === \"yaml\") {\n\t\tprocess.stdout.write(`${toYaml(data)}\\n`);\n\t\treturn;\n\t}\n\n\tif (format === \"quiet\") {\n\t\tconst rows = Array.isArray(data) ? data : [data];\n\t\tconst key = opts.idKey ?? \"id\";\n\t\tfor (const row of rows) {\n\t\t\tconst val = (row as Record<string, unknown>)[key];\n\t\t\tif (val !== undefined) {\n\t\t\t\tprocess.stdout.write(`${String(val)}\\n`);\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\n\tif (format === \"csv\") {\n\t\tconst rows = Array.isArray(data) ? data : [data];\n\t\tif (rows.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst cols = opts.columns ?? Object.keys(rows[0] as object);\n\t\tprocess.stdout.write(`${cols.map(csvEscape).join(\",\")}\\n`);\n\t\tfor (const row of rows) {\n\t\t\tprocess.stdout.write(\n\t\t\t\t`${cols\n\t\t\t\t\t.map((c) =>\n\t\t\t\t\t\tcsvEscape(\n\t\t\t\t\t\t\tString((row as Record<string, unknown>)[c] ?? \"\"),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\t.join(\",\")}\\n`,\n\t\t\t);\n\t\t}\n\t\treturn;\n\t}\n\n\t// Default: table\n\tconst rows = Array.isArray(data) ? data : [data];\n\tif (rows.length === 0) {\n\t\tprocess.stdout.write(\"(no results)\\n\");\n\t\treturn;\n\t}\n\tconst cols = opts.columns ?? Object.keys(rows[0] as object);\n\tconst table = new Table({ head: cols, style: { head: [\"cyan\"] } });\n\tfor (const row of rows) {\n\t\ttable.push(\n\t\t\tcols.map((c) => formatCell((row as Record<string, unknown>)[c])),\n\t\t);\n\t}\n\tprocess.stdout.write(`${table.toString()}\\n`);\n}\n\n/** Print a single key-value object as aligned pairs */\nexport function printRecord(\n\tdata: Record<string, unknown>,\n\topts: OutputOptions = {},\n): void {\n\tconst format = opts.format ?? (getOutputFormat() as OutputFormat);\n\tif (format === \"json\") {\n\t\tprintOutput(data, opts);\n\t\treturn;\n\t}\n\tif (format === \"yaml\") {\n\t\tprintOutput(data, opts);\n\t\treturn;\n\t}\n\tconst table = new Table({ style: { head: [\"cyan\"] } });\n\tfor (const [key, val] of Object.entries(data)) {\n\t\ttable.push({ [key]: formatCell(val) });\n\t}\n\tprocess.stdout.write(`${table.toString()}\\n`);\n}\n\n/** Print a success message to stdout */\nexport function printSuccess(message: string): void {\n\tprocess.stdout.write(`✓ ${message}\\n`);\n}\n\n/** Print an error message to stderr and exit with given code */\nexport function printError(message: string, exitCode = 1): never {\n\tprocess.stderr.write(`✗ ${message}\\n`);\n\tprocess.exit(exitCode);\n}\n\n/** Print a warning to stderr (no exit) */\nexport function printWarning(message: string): void {\n\tprocess.stderr.write(`⚠ ${message}\\n`);\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatCell(val: unknown): string {\n\tif (val === null || val === undefined) {\n\t\treturn \"\";\n\t}\n\tif (typeof val === \"boolean\") {\n\t\treturn val ? \"yes\" : \"no\";\n\t}\n\tif (typeof val === \"object\") {\n\t\treturn JSON.stringify(val);\n\t}\n\tconst s = String(val);\n\t// Truncate ISO dates to just the date portion for readability in tables\n\tif (/^\\d{4}-\\d{2}-\\d{2}T/.test(s)) {\n\t\treturn s.slice(0, 10);\n\t}\n\treturn s;\n}\n\nfunction csvEscape(s: string): string {\n\tif (s.includes(\",\") || s.includes('\"') || s.includes(\"\\n\")) {\n\t\treturn `\"${s.replace(/\"/g, '\"\"')}\"`;\n\t}\n\treturn s;\n}\n\n/** Minimal YAML serializer (no dependencies) */\nfunction toYaml(val: unknown, indent = 0): string {\n\tconst pad = \" \".repeat(indent);\n\tif (val === null || val === undefined) {\n\t\treturn \"~\";\n\t}\n\tif (typeof val === \"boolean\" || typeof val === \"number\") {\n\t\treturn String(val);\n\t}\n\tif (typeof val === \"string\") {\n\t\tif (val.includes(\"\\n\") || val.includes(\":\") || val.includes('\"')) {\n\t\t\treturn `\"${val.replace(/\"/g, '\\\\\"')}\"`;\n\t\t}\n\t\treturn val;\n\t}\n\tif (Array.isArray(val)) {\n\t\tif (val.length === 0) {\n\t\t\treturn \"[]\";\n\t\t}\n\t\treturn val\n\t\t\t.map((item) => `${pad}- ${toYaml(item, indent + 1)}`)\n\t\t\t.join(\"\\n\");\n\t}\n\tif (typeof val === \"object\") {\n\t\tconst entries = Object.entries(val as Record<string, unknown>);\n\t\tif (entries.length === 0) {\n\t\t\treturn \"{}\";\n\t\t}\n\t\treturn entries\n\t\t\t.map(([k, v]) => {\n\t\t\t\tconst valStr = toYaml(v, indent + 1);\n\t\t\t\tconst isMultiline = valStr.includes(\"\\n\");\n\t\t\t\treturn isMultiline\n\t\t\t\t\t? `${pad}${k}:\\n${valStr}`\n\t\t\t\t\t: `${pad}${k}: ${valStr}`;\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\t}\n\treturn String(val);\n}\n","/**\n * Context resolution for @fabricorg/cli\n *\n * Every resource command runs inside exactly one organization. Personal context\n * is gone (Fizzy #1875, PO-9): the flag, the environment variable and the\n * stored default that selected it are retired here.\n *\n * The stored shape still PARSES a personal default, and that is deliberate.\n * Configs written by earlier versions have one on disk, and a client that\n * crashed on its own config file would be a worse failure than the one being\n * fixed. It is read, recognised, and refused with a message that says how to\n * replace it — never silently treated as \"no default\", which would send the\n * user hunting for a setting they can see is set.\n */\n\nimport type { ContextConfig } from \"./config.js\";\nimport { getDefaultContext } from \"./config.js\";\nimport { printError } from \"./output.js\";\n\nexport interface ResolvedContext {\n\ttype: \"org\";\n\tslug: string;\n}\n\n/**\n * The same resolution as `resolveContext`, as a VALUE instead of an exit.\n *\n * `resolveContext` calls `printError`, which calls `process.exit` — correct\n * for a command a person is watching, and fatal to the session-start hook\n * contract in `commands/instructions`, which must never exit non-zero for\n * any reason. `process.exit` cannot be caught by the `try/catch` that owns\n * that contract, so a stored personal default (or a stale\n * `FABRIC_PERSONAL=1`) took the whole process down with code 2 before the\n * boundary ever saw it.\n *\n * `resolveContext` below is a thin exiting wrapper over it, so the two cannot\n * drift.\n */\ntype ContextResolution =\n\t| { ok: true; context: ResolvedContext | undefined }\n\t| { ok: false; message: string; exitCode: number };\n\nconst PERSONAL_RETIRED_HINT =\n\t\"selects personal context, which no longer exists — every command runs inside an organization.\\n\" +\n\t\"Name one with --org <slug>, or set a default with:\\n fabric ctx use org <slug>\";\n\nfunction tryResolveContext(\n\tpersonal: boolean | undefined,\n\torg: string | undefined,\n\trequired = true,\n): ContextResolution {\n\tif (personal) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tmessage: `--personal ${PERSONAL_RETIRED_HINT}`,\n\t\t\texitCode: 2,\n\t\t};\n\t}\n\tif (org) {\n\t\treturn { ok: true, context: { type: \"org\", slug: org } };\n\t}\n\n\tconst stored: ContextConfig | undefined = getDefaultContext();\n\tif (stored?.type === \"personal\") {\n\t\tconst source =\n\t\t\tprocess.env.FABRIC_PERSONAL === \"1\"\n\t\t\t\t? \"FABRIC_PERSONAL=1\"\n\t\t\t\t: \"Your stored default context\";\n\t\treturn {\n\t\t\tok: false,\n\t\t\tmessage: `${source} ${PERSONAL_RETIRED_HINT}`,\n\t\t\texitCode: 2,\n\t\t};\n\t}\n\tif (stored?.type === \"org\") {\n\t\treturn { ok: true, context: { type: \"org\", slug: stored.slug } };\n\t}\n\n\tif (required) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tmessage:\n\t\t\t\t\"Context is required. Use --org <slug>, or set a default with:\\n fabric ctx use org <slug>\",\n\t\t\texitCode: 2,\n\t\t};\n\t}\n\n\treturn { ok: true, context: undefined };\n}\n\n/**\n * Resolves tenant context from CLI flags, env vars, or stored default.\n * Exits with code 2 when context is ambiguous or names a retired one.\n *\n * A thin wrapper over `tryResolveContext`, which holds the actual rules —\n * see there for why the non-exiting form exists.\n *\n * @param personal - value of the retired --personal flag\n * @param org - value of --org flag\n * @param required - if false, returns undefined when context is unset (for auth commands)\n */\nexport function resolveContext(\n\tpersonal: boolean | undefined,\n\torg: string | undefined,\n\trequired = true,\n): ResolvedContext | undefined {\n\tconst resolution = tryResolveContext(personal, org, required);\n\tif (!resolution.ok) {\n\t\tprintError(resolution.message, resolution.exitCode);\n\t}\n\treturn resolution.context;\n}\n","/**\n * fabric auth keys\n *\n * fabric auth keys list\n * fabric auth keys create --name \"CI deploy\" --scopes workflows:run,agents:read\n * fabric auth keys revoke <id>\n */\n\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { printError, printOutput, printSuccess } from \"../../lib/output.js\";\n\nexport function buildKeysCommand(): Command {\n\tconst keys = new Command(\"keys\").description(\"Manage API keys\");\n\n\t// -- list ----------------------------------------------------------------\n\tkeys.command(\"list\")\n\t\t.description(\"List your API keys\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.action(async (opts: { format: string }) => {\n\t\t\tconst client = getClient();\n\t\t\tlet list: Awaited<ReturnType<typeof client.auth.listKeys>>;\n\t\t\ttry {\n\t\t\t\tlist = await client.auth.listKeys();\n\t\t\t} catch (err: unknown) {\n\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t}\n\t\t\tprintOutput(list, {\n\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\tcolumns: [\n\t\t\t\t\t\"id\",\n\t\t\t\t\t\"name\",\n\t\t\t\t\t\"keyPrefix\",\n\t\t\t\t\t\"scopes\",\n\t\t\t\t\t\"lastUsedAt\",\n\t\t\t\t\t\"expiresAt\",\n\t\t\t\t\t\"createdAt\",\n\t\t\t\t],\n\t\t\t});\n\t\t});\n\n\t// -- create --------------------------------------------------------------\n\tkeys.command(\"create\")\n\t\t.description(\"Create a new API key (raw key shown only once)\")\n\t\t.requiredOption(\"-n, --name <name>\", \"Key name\")\n\t\t.option(\n\t\t\t\"-s, --scopes <scopes>\",\n\t\t\t\"Comma-separated scopes (e.g. projects:read,workflows:run)\",\n\t\t\t\"orgs:read\",\n\t\t)\n\t\t.option(\n\t\t\t\"-e, --expires <days>\",\n\t\t\t\"Days until expiry (1–365, omit for no expiry)\",\n\t\t)\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\tname: string;\n\t\t\t\tscopes: string;\n\t\t\t\texpires?: string;\n\t\t\t\tformat: string;\n\t\t\t}) => {\n\t\t\t\tconst client = getClient();\n\t\t\t\tconst scopes = opts.scopes.split(\",\").map((s) => s.trim());\n\t\t\t\tconst expiresInDays = opts.expires\n\t\t\t\t\t? Number.parseInt(opts.expires, 10)\n\t\t\t\t\t: undefined;\n\n\t\t\t\tif (\n\t\t\t\t\texpiresInDays !== undefined &&\n\t\t\t\t\tNumber.isNaN(expiresInDays)\n\t\t\t\t) {\n\t\t\t\t\tprintError(\"--expires must be a number\", 2);\n\t\t\t\t}\n\n\t\t\t\tlet created: Awaited<ReturnType<typeof client.auth.createKey>>;\n\t\t\t\ttry {\n\t\t\t\t\tcreated = await client.auth.createKey({\n\t\t\t\t\t\tname: opts.name,\n\t\t\t\t\t\tscopes,\n\t\t\t\t\t\texpiresInDays,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(created, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprocess.stdout.write(\"\\n\");\n\t\t\t\tprintSuccess(`API key created: ${created.name}`);\n\t\t\t\tprocess.stdout.write(`\\n Key: ${created.rawKey}\\n`);\n\t\t\t\tprocess.stdout.write(` Prefix: ${created.keyPrefix}\\n`);\n\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t` Scopes: ${created.scopes.join(\", \")}\\n`,\n\t\t\t\t);\n\t\t\t\tif (created.expiresAt) {\n\t\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t\t` Expires: ${String(created.expiresAt).slice(0, 10)}\\n`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t\"\\n ⚠ Store this key now — it will never be shown again.\\n\\n\",\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\n\t// -- revoke --------------------------------------------------------------\n\tkeys.command(\"revoke <id>\")\n\t\t.description(\"Permanently revoke an API key\")\n\t\t.action(async (id: string) => {\n\t\t\tconst client = getClient();\n\t\t\ttry {\n\t\t\t\tawait client.auth.revokeKey(id);\n\t\t\t} catch (err: unknown) {\n\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t}\n\t\t\tprintSuccess(`API key ${id} revoked.`);\n\t\t});\n\n\treturn keys;\n}\n","/**\n * fabric auth login\n *\n * Stores an API key for subsequent commands.\n *\n * fabric auth login --key fab_...\n * fabric auth login (prompts interactively)\n */\n\nimport * as readline from \"node:readline\";\nimport { FabricAuthError, FabricClient, FabricError } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getBaseUrl, saveApiKey } from \"../../lib/config.js\";\nimport { printError, printSuccess } from \"../../lib/output.js\";\n\nconst DEFAULT_BASE_URL = \"https://fabric.pro\";\n\nfunction displayBaseUrl(baseUrl: string): string {\n\ttry {\n\t\treturn new URL(baseUrl).origin;\n\t} catch {\n\t\treturn \"the configured Fabric deployment\";\n\t}\n}\n\nasync function promptApiKey(): Promise<string> {\n\tconst rl = readline.createInterface({\n\t\tinput: process.stdin,\n\t\toutput: process.stdout,\n\t});\n\n\treturn new Promise((resolve) => {\n\t\t// Don't echo the key\n\t\tprocess.stdout.write(\"Fabric API Key: \");\n\t\tprocess.stdin.resume();\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\n\t\tlet key = \"\";\n\t\tprocess.stdin.once(\"data\", (chunk) => {\n\t\t\tkey = String(chunk).trim();\n\t\t\tprocess.stdout.write(\"\\n\");\n\t\t\trl.close();\n\t\t\tresolve(key);\n\t\t});\n\t});\n}\n\nexport function buildLoginCommand(): Command {\n\treturn new Command(\"login\")\n\t\t.description(\"Authenticate with a Fabric API key\")\n\t\t.option(\"-k, --key <api-key>\", \"API key (fab_... or org_...)\")\n\t\t.option(\"--base-url <url>\", \"Override the Fabric base URL\")\n\t\t.action(async (opts: { key?: string; baseUrl?: string }) => {\n\t\t\tlet apiKey = opts.key?.trim();\n\n\t\t\tif (!apiKey) {\n\t\t\t\tapiKey = await promptApiKey();\n\t\t\t}\n\n\t\t\tif (!apiKey) {\n\t\t\t\tprintError(\"API key is required\", 2);\n\t\t\t}\n\n\t\t\tif (!apiKey.startsWith(\"fab_\") && !apiKey.startsWith(\"org_\")) {\n\t\t\t\tprintError(\n\t\t\t\t\t\"Invalid API key format. Keys must start with fab_ or org_\",\n\t\t\t\t\t2,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Verify the key works before saving\n\t\t\tconst baseUrl = opts.baseUrl ?? getBaseUrl();\n\t\t\tconst effectiveBaseUrl = displayBaseUrl(\n\t\t\t\tbaseUrl ?? DEFAULT_BASE_URL,\n\t\t\t);\n\t\t\tconst client = new FabricClient({ apiKey, baseUrl });\n\n\t\t\tlet name: string;\n\t\t\tlet email: string;\n\t\t\ttry {\n\t\t\t\tconst me = await client.auth.whoami();\n\t\t\t\tname = me.user.name ?? me.user.email;\n\t\t\t\temail = me.user.email;\n\t\t\t} catch (error) {\n\t\t\t\tif (\n\t\t\t\t\terror instanceof FabricAuthError ||\n\t\t\t\t\t(error instanceof FabricError && error.status === 401)\n\t\t\t\t) {\n\t\t\t\t\tprintError(\n\t\t\t\t\t\t\"Authentication failed. Check that the key is valid and not expired.\",\n\t\t\t\t\t\t3,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (error instanceof FabricError && error.status > 0) {\n\t\t\t\t\tprintError(\n\t\t\t\t\t\t`Authentication request to ${effectiveBaseUrl} failed with HTTP ${error.status}.`,\n\t\t\t\t\t\t3,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tprintError(\n\t\t\t\t\t`Could not connect to ${effectiveBaseUrl}. Check that the deployment URL is correct and reachable.`,\n\t\t\t\t\t3,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// An environment override selects the verification target for this\n\t\t\t// invocation only. Persist a deployment only when the person supplied\n\t\t\t// `--base-url`, so FABRIC_BASE_URL remains an explicit override.\n\t\t\tsaveApiKey(apiKey, {\n\t\t\t\t...(opts.baseUrl === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: { baseUrl: opts.baseUrl }),\n\t\t\t});\n\t\t\tprintSuccess(`Authenticated as ${name} (${email})`);\n\t\t});\n}\n","/**\n * fabric auth logout\n * Removes the stored API key from config.\n */\n\nimport { Command } from \"commander\";\nimport { clearApiKey, getApiKey } from \"../../lib/config.js\";\nimport { printSuccess, printWarning } from \"../../lib/output.js\";\n\nexport function buildLogoutCommand(): Command {\n\treturn new Command(\"logout\")\n\t\t.description(\"Remove stored API key\")\n\t\t.action(() => {\n\t\t\tif (!getApiKey()) {\n\t\t\t\tprintWarning(\"No API key stored — already logged out.\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tclearApiKey();\n\t\t\tprintSuccess(\"Logged out. API key removed.\");\n\t\t});\n}\n","/**\n * fabric auth whoami\n * Prints the authenticated identity and org memberships.\n */\n\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildWhoamiCommand(): Command {\n\treturn new Command(\"whoami\")\n\t\t.description(\"Show current authentication and identity\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(async (opts: { format: string }) => {\n\t\t\tconst client = getClient();\n\n\t\t\tlet me: Awaited<ReturnType<typeof client.auth.whoami>>;\n\t\t\ttry {\n\t\t\t\tme = await client.auth.whoami();\n\t\t\t} catch (err: unknown) {\n\t\t\t\tprintError((err as Error).message ?? \"Request failed\", 3);\n\t\t\t}\n\n\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\n\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\tprintOutput(me, { format: fmt });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Human-readable\n\t\t\tprintRecord({\n\t\t\t\tUser: me.user.name ?? \"(no name)\",\n\t\t\t\tEmail: me.user.email,\n\t\t\t\tRole: me.user.role,\n\t\t\t\t\"Key type\": me.keyType,\n\t\t\t\t\"Key prefix\": me.keyPrefix,\n\t\t\t\tScopes: me.scopes.join(\", \"),\n\t\t\t\t\"Orgs count\": String(me.orgs.length),\n\t\t\t\t\"Member since\": me.user.createdAt.slice(0, 10),\n\t\t\t});\n\n\t\t\tif (me.orgs.length > 0) {\n\t\t\t\tprocess.stdout.write(\"\\nOrganizations:\\n\");\n\t\t\t\tprintOutput(me.orgs, {\n\t\t\t\t\tformat: \"table\",\n\t\t\t\t\tcolumns: [\"name\", \"slug\", \"role\", \"joinedAt\"],\n\t\t\t\t});\n\t\t\t}\n\t\t});\n}\n","/**\n * fabric chats\n *\n * fabric chats list List AI chat sessions\n * fabric chats show <id> Show chat details\n */\n\nimport type { FabricChat } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildChatsCommand(): Command {\n\tconst chats = new Command(\"chats\").description(\"Manage AI chat sessions\");\n\n\tchats\n\t\t.command(\"list\")\n\t\t.description(\"List AI chat sessions\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--limit <n>\", \"Max results (default 20)\", \"20\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricChat[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.chats.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const c of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${c.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\"id\", \"title\", \"updatedAt\"],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\tchats\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show chat details\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet chat: FabricChat;\n\t\t\t\ttry {\n\t\t\t\t\tchat = await client.chats.get(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(chat, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: chat.id,\n\t\t\t\t\tTitle: chat.title ?? \"(untitled)\",\n\t\t\t\t\tUpdated: chat.updatedAt.slice(0, 16).replace(\"T\", \" \"),\n\t\t\t\t\tCreated: chat.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn chats;\n}\n","/**\n * fabric completion\n *\n * fabric completion bash Output bash completion script\n * fabric completion zsh Output zsh completion script\n * fabric completion fish Output fish completion script\n */\n\nimport { Command } from \"commander\";\n\nconst BASH_COMPLETION = `\n# fabric bash completion\n_fabric_completion() {\n local cur prev words cword\n _init_completion || return\n\n local commands=\"auth ctx orgs projects features workflows prompts agents skills mcp frames workspaces chats reports config completion\"\n\n case \"$prev\" in\n fabric)\n COMPREPLY=($(compgen -W \"$commands\" -- \"$cur\"))\n return ;;\n auth)\n COMPREPLY=($(compgen -W \"login logout whoami keys\" -- \"$cur\"))\n return ;;\n keys)\n COMPREPLY=($(compgen -W \"list create revoke\" -- \"$cur\"))\n return ;;\n ctx)\n COMPREPLY=($(compgen -W \"current use\" -- \"$cur\"))\n return ;;\n orgs)\n COMPREPLY=($(compgen -W \"list show\" -- \"$cur\"))\n return ;;\n projects)\n COMPREPLY=($(compgen -W \"list show create update\" -- \"$cur\"))\n return ;;\n features)\n COMPREPLY=($(compgen -W \"list show create update tasks\" -- \"$cur\"))\n return ;;\n workflows)\n COMPREPLY=($(compgen -W \"list show trigger status\" -- \"$cur\"))\n return ;;\n prompts)\n COMPREPLY=($(compgen -W \"list get create update\" -- \"$cur\"))\n return ;;\n agents)\n COMPREPLY=($(compgen -W \"list show execute\" -- \"$cur\"))\n return ;;\n skills)\n COMPREPLY=($(compgen -W \"list show\" -- \"$cur\"))\n return ;;\n mcp)\n COMPREPLY=($(compgen -W \"servers configs\" -- \"$cur\"))\n return ;;\n configs)\n COMPREPLY=($(compgen -W \"list show delete\" -- \"$cur\"))\n return ;;\n frames)\n COMPREPLY=($(compgen -W \"list show\" -- \"$cur\"))\n return ;;\n workspaces)\n COMPREPLY=($(compgen -W \"list show\" -- \"$cur\"))\n return ;;\n chats)\n COMPREPLY=($(compgen -W \"list show\" -- \"$cur\"))\n return ;;\n reports)\n COMPREPLY=($(compgen -W \"templates executions\" -- \"$cur\"))\n return ;;\n templates)\n COMPREPLY=($(compgen -W \"list show\" -- \"$cur\"))\n return ;;\n executions)\n COMPREPLY=($(compgen -W \"list\" -- \"$cur\"))\n return ;;\n completion)\n COMPREPLY=($(compgen -W \"bash zsh fish\" -- \"$cur\"))\n return ;;\n esac\n\n COMPREPLY=($(compgen -W \"--format --org --personal --quiet --help\" -- \"$cur\"))\n}\n\ncomplete -F _fabric_completion fabric\n`.trim();\n\nconst ZSH_COMPLETION = `\n#compdef fabric\n\n_fabric() {\n local state\n\n _arguments \\\\\n '--format[Output format]:format:(table json yaml csv)' \\\\\n '--version[Show version]' \\\\\n '--help[Show help]' \\\\\n '1: :->command' \\\\\n '*: :->args'\n\n case $state in\n command)\n local commands=(\n 'auth:Authenticate and manage API keys'\n 'ctx:Manage active context'\n 'orgs:List organizations'\n 'projects:Manage projects'\n 'features:Manage project features'\n 'workflows:Manage workflows'\n 'prompts:Manage prompts'\n 'agents:Manage agents'\n 'skills:Browse skills'\n 'mcp:Manage MCP servers and configs'\n 'frames:Manage AI-generated frames'\n 'workspaces:Manage workspaces'\n 'chats:View AI chat history'\n 'reports:Manage reports'\n 'config:Show CLI configuration'\n 'completion:Output shell completion script'\n )\n _describe 'command' commands\n ;;\n args)\n case $words[2] in\n auth)\n local subcmds=('login:Log in' 'logout:Log out' 'whoami:Show current user' 'keys:Manage API keys')\n _describe 'subcommand' subcmds ;;\n projects)\n local subcmds=('list:List projects' 'show:Show project' 'create:Create project' 'update:Update project')\n _describe 'subcommand' subcmds ;;\n features)\n local subcmds=('list:List features' 'show:Show feature' 'create:Create feature' 'update:Update feature' 'tasks:List tasks')\n _describe 'subcommand' subcmds ;;\n workflows)\n local subcmds=('list:List workflows' 'show:Show workflow' 'trigger:Trigger workflow' 'status:Check status')\n _describe 'subcommand' subcmds ;;\n prompts)\n local subcmds=('list:List prompts' 'get:Get prompt' 'create:Create prompt' 'update:Update prompt')\n _describe 'subcommand' subcmds ;;\n agents)\n local subcmds=('list:List agents' 'show:Show agent' 'execute:Execute agent')\n _describe 'subcommand' subcmds ;;\n mcp)\n local subcmds=('servers:List MCP servers' 'configs:Manage MCP configs')\n _describe 'subcommand' subcmds ;;\n frames)\n local subcmds=('list:List frames' 'show:Show frame')\n _describe 'subcommand' subcmds ;;\n workspaces)\n local subcmds=('list:List workspaces' 'show:Show workspace')\n _describe 'subcommand' subcmds ;;\n skills)\n local subcmds=('list:List skills' 'show:Show skill')\n _describe 'subcommand' subcmds ;;\n chats)\n local subcmds=('list:List chats' 'show:Show chat')\n _describe 'subcommand' subcmds ;;\n reports)\n local subcmds=('templates:Manage report templates' 'executions:List report executions')\n _describe 'subcommand' subcmds ;;\n completion)\n local subcmds=('bash:Bash completion' 'zsh:Zsh completion' 'fish:Fish completion')\n _describe 'subcommand' subcmds ;;\n esac ;;\n esac\n}\n\n_fabric \"$@\"\n`.trim();\n\nconst FISH_COMPLETION = `\n# fabric fish completion\nset -l fabric_commands auth ctx orgs projects features workflows prompts agents skills mcp frames workspaces chats reports config completion\n\ncomplete -c fabric -f\n\n# Top-level commands\ncomplete -c fabric -n '__fish_use_subcommand' -a auth -d 'Authenticate and manage API keys'\ncomplete -c fabric -n '__fish_use_subcommand' -a ctx -d 'Manage active context'\ncomplete -c fabric -n '__fish_use_subcommand' -a orgs -d 'List organizations'\ncomplete -c fabric -n '__fish_use_subcommand' -a projects -d 'Manage projects'\ncomplete -c fabric -n '__fish_use_subcommand' -a features -d 'Manage project features'\ncomplete -c fabric -n '__fish_use_subcommand' -a workflows -d 'Manage workflows'\ncomplete -c fabric -n '__fish_use_subcommand' -a prompts -d 'Manage prompts'\ncomplete -c fabric -n '__fish_use_subcommand' -a agents -d 'Manage agents'\ncomplete -c fabric -n '__fish_use_subcommand' -a skills -d 'Browse skills'\ncomplete -c fabric -n '__fish_use_subcommand' -a mcp -d 'Manage MCP servers and configs'\ncomplete -c fabric -n '__fish_use_subcommand' -a frames -d 'Manage AI-generated frames'\ncomplete -c fabric -n '__fish_use_subcommand' -a workspaces -d 'Manage workspaces'\ncomplete -c fabric -n '__fish_use_subcommand' -a chats -d 'View AI chat history'\ncomplete -c fabric -n '__fish_use_subcommand' -a reports -d 'Manage reports'\ncomplete -c fabric -n '__fish_use_subcommand' -a config -d 'Show CLI configuration'\ncomplete -c fabric -n '__fish_use_subcommand' -a completion -d 'Output shell completion script'\n\n# Subcommands\ncomplete -c fabric -n '__fish_seen_subcommand_from auth' -a 'login logout whoami keys'\ncomplete -c fabric -n '__fish_seen_subcommand_from ctx' -a 'current use'\ncomplete -c fabric -n '__fish_seen_subcommand_from orgs' -a 'list show'\ncomplete -c fabric -n '__fish_seen_subcommand_from projects' -a 'list show create update'\ncomplete -c fabric -n '__fish_seen_subcommand_from features' -a 'list show create update tasks'\ncomplete -c fabric -n '__fish_seen_subcommand_from workflows' -a 'list show trigger status'\ncomplete -c fabric -n '__fish_seen_subcommand_from prompts' -a 'list get create update'\ncomplete -c fabric -n '__fish_seen_subcommand_from agents' -a 'list show execute'\ncomplete -c fabric -n '__fish_seen_subcommand_from skills' -a 'list show'\ncomplete -c fabric -n '__fish_seen_subcommand_from mcp' -a 'servers configs'\ncomplete -c fabric -n '__fish_seen_subcommand_from configs' -a 'list show delete'\ncomplete -c fabric -n '__fish_seen_subcommand_from frames' -a 'list show'\ncomplete -c fabric -n '__fish_seen_subcommand_from workspaces' -a 'list show'\ncomplete -c fabric -n '__fish_seen_subcommand_from chats' -a 'list show'\ncomplete -c fabric -n '__fish_seen_subcommand_from reports' -a 'templates executions'\ncomplete -c fabric -n '__fish_seen_subcommand_from templates' -a 'list show'\ncomplete -c fabric -n '__fish_seen_subcommand_from executions' -a 'list'\ncomplete -c fabric -n '__fish_seen_subcommand_from completion' -a 'bash zsh fish'\n\n# Common flags\ncomplete -c fabric -l format -d 'Output format' -a 'table json yaml csv'\ncomplete -c fabric -l org -d 'Organization context' -r\ncomplete -c fabric -l personal -d 'Personal context'\ncomplete -c fabric -s q -l quiet -d 'Quiet output'\ncomplete -c fabric -l help -d 'Show help'\n`.trim();\n\nexport function buildCompletionCommand(): Command {\n\tconst completion = new Command(\"completion\").description(\n\t\t\"Output shell completion script\",\n\t);\n\n\tcompletion\n\t\t.command(\"bash\")\n\t\t.description(\"Output bash completion script\")\n\t\t.action(() => {\n\t\t\tprocess.stdout.write(`${BASH_COMPLETION}\\n`);\n\t\t\tprocess.stderr.write(\n\t\t\t\t'# Add to ~/.bashrc:\\n# eval \"$(fabric completion bash)\"\\n',\n\t\t\t);\n\t\t});\n\n\tcompletion\n\t\t.command(\"zsh\")\n\t\t.description(\"Output zsh completion script\")\n\t\t.action(() => {\n\t\t\tprocess.stdout.write(`${ZSH_COMPLETION}\\n`);\n\t\t\tprocess.stderr.write(\n\t\t\t\t'# Add to ~/.zshrc:\\n# eval \"$(fabric completion zsh)\"\\n',\n\t\t\t);\n\t\t});\n\n\tcompletion\n\t\t.command(\"fish\")\n\t\t.description(\"Output fish completion script\")\n\t\t.action(() => {\n\t\t\tprocess.stdout.write(`${FISH_COMPLETION}\\n`);\n\t\t\tprocess.stderr.write(\n\t\t\t\t\"# Save to ~/.config/fish/completions/fabric.fish\\n\",\n\t\t\t);\n\t\t});\n\n\treturn completion;\n}\n","/**\n * fabric context\n *\n * fabric context push <dir> --project <id> Sync a local knowledge folder\n * into the project's Context.\n *\n * PROJECT Context — the knowledge sources a project's AI features read — and\n * not `fabric ctx`, which switches the CLI's default organization and never\n * talks to a project.\n *\n * Every file under `<dir>` that the ignore rules leave in and that is text is\n * pushed by its relative path, one request per file, through\n * `PUT /api/v1/projects/:projectId/contexts/synced-files`. The lock at\n * `<dir>/.fabric/context.lock` remembers what the server confirmed, so a file\n * that has not changed is not sent again, and a file that has changed names\n * the version it replaces — which is what turns somebody else's edit on the\n * server into a conflict instead of a silent overwrite.\n *\n * Everything that touches the filesystem lives in `lib/context-sync/`; this\n * file is argument parsing, the sequence, and the exit code.\n */\nimport { lstat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { FabricClient } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport {\n\tCliFailure,\n\tdescribeError,\n\ttype OutputFormat,\n\toutputFormatFor,\n\twithDeadline,\n} from \"../../lib/command-boundary.js\";\nimport { getApiKey } from \"../../lib/config.js\";\nimport {\n\ttype ContextLock,\n\tcontextLockPath,\n\treadContextLock,\n\twriteContextLock,\n} from \"../../lib/context-sync/lock.js\";\nimport {\n\ttype ContextPlan,\n\tcomputeContextPlan,\n} from \"../../lib/context-sync/plan.js\";\nimport {\n\ttype ContextPushResult,\n\tnextContextLock,\n\tpushContextPlan,\n} from \"../../lib/context-sync/push.js\";\nimport {\n\tcontextPushJson,\n\tformatDryRunReport,\n\tformatPushReport,\n} from \"../../lib/context-sync/report.js\";\nimport { resolveExistingRoot } from \"../../lib/instructions/safe-write.js\";\nimport { printOutput } from \"../../lib/output.js\";\n\n/**\n * Hook mode's one absolute deadline, the same bound `fabric instructions`\n * uses. A hook that cannot finish in time leaves the lock as it was, and the\n * next run finishes the job: content the server already holds is answered\n * `unchanged` and recorded then.\n */\nconst HOOK_DEADLINE_MS = 10_000;\n\n/** Per request, outside hook mode. A file is at most 2 MiB. */\nconst PUSH_TIMEOUT_MS = 60_000;\n\ninterface PushOptions {\n\tproject: string;\n\torg?: string;\n\tforce?: boolean;\n\tdryRun?: boolean;\n\thook?: boolean;\n\texclude?: string[];\n\t/** Read through `optsWithGlobals()`, never off this object. */\n\tformat?: string;\n}\n\nfunction collectPattern(value: string, previous: string[]): string[] {\n\treturn [...previous, value];\n}\n\nexport function buildContextCommand(): Command {\n\tconst context = new Command(\"context\").description(\n\t\t\"Sync local knowledge files into a project's Context\",\n\t);\n\n\tcontext\n\t\t.command(\"push\")\n\t\t.description(\n\t\t\t\"Push every text file under <dir> into the project's Context by its relative path\",\n\t\t)\n\t\t.argument(\n\t\t\t\"<dir>\",\n\t\t\t\"Folder to push (required; never the working directory by default)\",\n\t\t)\n\t\t.requiredOption(\"--project <id>\", \"Project ID\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\n\t\t\t\"--force\",\n\t\t\t\"On a conflict, replace the server's version once with this folder's\",\n\t\t)\n\t\t.option(\"--dry-run\", \"Print the plan; send nothing and write no lock\")\n\t\t.option(\n\t\t\t\"--exclude <pattern>\",\n\t\t\t\"Also leave out paths matching this gitignore pattern (repeatable)\",\n\t\t\tcollectPattern,\n\t\t\t[] as string[],\n\t\t)\n\t\t.option(\n\t\t\t\"--hook\",\n\t\t\t\"Hook mode: never fails, never blocks, one line on stderr on failure\",\n\t\t)\n\t\t.option(\"--format <format>\", \"Output format: text|json\")\n\t\t.action(async function (this: Command, dir: string, opts: PushOptions) {\n\t\t\tawait run(opts, () => runPush(dir, opts, outputFormatFor(this)));\n\t\t});\n\n\treturn context;\n}\n\n/**\n * Every failure becomes an exit code or, under `--hook`, one line on stderr\n * and a zero exit — the same contract as `fabric instructions`, so a hook\n * that pushes notes can never be what stops a session or a commit.\n */\nasync function run(\n\topts: { hook?: boolean },\n\tbody: () => Promise<void>,\n): Promise<void> {\n\ttry {\n\t\tif (opts.hook) {\n\t\t\tawait withDeadline(HOOK_DEADLINE_MS, () => body());\n\t\t} else {\n\t\t\tawait body();\n\t\t}\n\t} catch (error) {\n\t\tconst message = describeError(error);\n\t\tif (opts.hook) {\n\t\t\tprocess.stderr.write(`fabric: context push failed: ${message}\\n`);\n\t\t\tprocess.exit(0);\n\t\t}\n\t\tprocess.stderr.write(`✗ ${message}\\n`);\n\t\tprocess.exit(error instanceof CliFailure ? error.exitCode : 1);\n\t}\n}\n\n/**\n * A client that throws instead of exiting (`getClient` exits 3 on a missing\n * key, which would break the hook contract), with retries off in hook mode.\n *\n * Retries stay ON otherwise, and that is safe for this route in particular:\n * the same content at the same path is answered `unchanged` before the\n * expected hash is compared, so a retry of a request whose response was lost\n * reports the first attempt's write rather than making another.\n *\n * `withoutContext()`: the project decides which organization it is in, so an\n * ambient `FABRIC_ORG` must not bind the request; `--org` still does.\n */\nfunction contextClient(opts: { hook?: boolean }): FabricClient {\n\tif (!getApiKey()) {\n\t\tthrow new CliFailure(\n\t\t\t\"Not authenticated. Run: fabric auth login --key <api-key>\",\n\t\t\t3,\n\t\t);\n\t}\n\treturn getClient(\n\t\topts.hook\n\t\t\t? { timeoutMs: HOOK_DEADLINE_MS, retry: { maxRetries: 0 } }\n\t\t\t: { timeoutMs: PUSH_TIMEOUT_MS },\n\t).withoutContext();\n}\n\nasync function resolveFolder(dir: string): Promise<string> {\n\tconst directory = path.resolve(dir);\n\tconst root = await resolveExistingRoot(directory);\n\tconst stats = await lstat(root).catch(() => null);\n\tif (stats === null || !stats.isDirectory()) {\n\t\tthrow new CliFailure(`${directory} is not a directory.`, 2);\n\t}\n\treturn root;\n}\n\n/** The lock, refused when damaged or when it belongs to another project. */\nasync function readLockForProject(\n\troot: string,\n\tprojectId: string,\n): Promise<ContextLock | null> {\n\tlet lock: ContextLock | null;\n\ttry {\n\t\tlock = await readContextLock(root);\n\t} catch (error) {\n\t\tthrow new CliFailure(describeError(error), 7);\n\t}\n\tif (lock !== null && lock.projectId !== projectId) {\n\t\tthrow new CliFailure(\n\t\t\t`${contextLockPath(root)} belongs to project ${lock.projectId}, not ${projectId}. Push this folder to ${lock.projectId}, or remove that lock if this folder should now feed ${projectId}.`,\n\t\t\t7,\n\t\t);\n\t}\n\treturn lock;\n}\n\nfunction print(lines: string[]): void {\n\tprocess.stdout.write(`${lines.join(\"\\n\")}\\n`);\n}\n\nasync function runPush(\n\tdir: string,\n\topts: PushOptions,\n\tformat: OutputFormat,\n): Promise<void> {\n\tconst root = await resolveFolder(dir);\n\t// Before any file is read: a push that cannot authenticate should not\n\t// spend a walk and a hash of every file finding that out.\n\tconst client = opts.dryRun ? null : contextClient(opts);\n\tconst lock = await readLockForProject(root, opts.project);\n\tconst plan = await computeContextPlan({\n\t\troot,\n\t\tlock,\n\t\texcludes: opts.exclude,\n\t});\n\n\tif (client === null) {\n\t\tif (format === \"json\") {\n\t\t\tprintOutput(\n\t\t\t\tjsonOutcome({\n\t\t\t\t\troot,\n\t\t\t\t\topts,\n\t\t\t\t\tplan,\n\t\t\t\t\tresults: [],\n\t\t\t\t\tlockWritten: false,\n\t\t\t\t}),\n\t\t\t\t{ format: \"json\" },\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tprint(\n\t\t\tformatDryRunReport({\n\t\t\t\tprojectId: opts.project,\n\t\t\t\tdirectory: root,\n\t\t\t\tplan,\n\t\t\t}),\n\t\t);\n\t\treturn;\n\t}\n\n\tconst pushed = await pushContextPlan({\n\t\tclient,\n\t\tprojectId: opts.project,\n\t\torg: opts.org,\n\t\troot,\n\t\tplan,\n\t\tforce: Boolean(opts.force),\n\t});\n\n\t// LAST, after every request, and only with what the server answered.\n\tconst next = nextContextLock({\n\t\tprevious: lock,\n\t\tprojectId: opts.project,\n\t\tresults: pushed.results,\n\t\tforgotten: plan.forgotten,\n\t\tnow: new Date(),\n\t});\n\tif (next !== null) {\n\t\tawait writeContextLock(root, next);\n\t}\n\n\tif (format === \"json\") {\n\t\tprintOutput(\n\t\t\tjsonOutcome({\n\t\t\t\troot,\n\t\t\t\topts,\n\t\t\t\tplan,\n\t\t\t\tresults: pushed.results,\n\t\t\t\tlockWritten: next !== null,\n\t\t\t}),\n\t\t\t{ format: \"json\" },\n\t\t);\n\t} else {\n\t\tprint(\n\t\t\tformatPushReport({\n\t\t\t\tprojectId: opts.project,\n\t\t\t\tdirectory: root,\n\t\t\t\tplan,\n\t\t\t\tresults: pushed.results,\n\t\t\t}),\n\t\t);\n\t}\n\n\tif (pushed.stoppedBy !== null) {\n\t\tthrow pushed.stoppedBy;\n\t}\n\tthrowIfIncomplete(pushed.results);\n}\n\nfunction jsonOutcome(input: {\n\troot: string;\n\topts: PushOptions;\n\tplan: ContextPlan;\n\tresults: ContextPushResult[];\n\tlockWritten: boolean;\n}) {\n\treturn contextPushJson({\n\t\tprojectId: input.opts.project,\n\t\tdirectory: input.root,\n\t\tlockPath: contextLockPath(input.root),\n\t\tlockWritten: input.lockWritten,\n\t\tdryRun: Boolean(input.opts.dryRun),\n\t\tforce: Boolean(input.opts.force),\n\t\tplan: input.plan,\n\t\tresults: input.results,\n\t});\n}\n\n/**\n * The run's exit, once everything that could be pushed has been.\n *\n * A failed request exits with the code its error maps to (a 400 is 7, a 5xx\n * is 1); remaining conflicts alone exit 1. Either way the report above has\n * already named every file, so this sentence only says what to do next.\n */\nfunction throwIfIncomplete(results: readonly ContextPushResult[]): void {\n\tconst failed = results.filter((r) => r.status === \"failed\");\n\tconst conflicts = results.filter((r) => r.status === \"conflict\");\n\tif (failed.length === 0 && conflicts.length === 0) {\n\t\treturn;\n\t}\n\tconst parts: string[] = [];\n\tif (conflicts.length > 0) {\n\t\tparts.push(\n\t\t\t`${conflicts.length} conflict${conflicts.length === 1 ? \"\" : \"s\"}`,\n\t\t);\n\t}\n\tconst first = failed[0];\n\tif (first && first.status === \"failed\") {\n\t\t// The first cause, so a hook's single stderr line says why.\n\t\tparts.push(\n\t\t\t`${failed.length} failed, first ${first.sourcePath}: ${first.error}`,\n\t\t);\n\t}\n\tconst total = conflicts.length + failed.length;\n\tlet message = `${total} of ${results.length} file${results.length === 1 ? \"\" : \"s\"} sent ${total === 1 ? \"was\" : \"were\"} not stored (${parts.join(\", \")}).`;\n\tif (conflicts.length > 0) {\n\t\tmessage +=\n\t\t\t\" A conflict means the server holds a version this folder did not name, or deleted the one it named: compare the two in the project's Context tab, and use --force to replace the version the conflict reported with this folder's (or to send a deleted file again with no version, which recreates it, or answers duplicate if that content is already stored under another path).\";\n\t}\n\tthrow new CliFailure(\n\t\tmessage,\n\t\tfirst && first.status === \"failed\" ? first.exitCode : 1,\n\t);\n}\n","/**\n * The failure boundary the file-syncing command groups share —\n * `fabric instructions` and `fabric context`.\n *\n * Both groups promise the same two things: a failure a person sees maps onto\n * one of the documented exit codes (`src/bin/fabric.ts`), and under `--hook`\n * nothing ever exits non-zero or runs past one absolute deadline. The pieces\n * that make those promises live here so the two groups cannot drift apart on\n * them. Each group keeps its own `run` wrapper, because the one line a hook\n * prints names the group.\n */\nimport type { Command } from \"commander\";\n\n/** The two shapes these commands print: one JSON object, or prose. */\nexport type OutputFormat = \"text\" | \"json\";\n\n/**\n * The format this invocation should print in: `json`, or text.\n *\n * One reader, `optsWithGlobals()`, because Commander has already done the\n * resolving. The root command declares `--format` with a default of\n * `FABRIC_FORMAT ?? \"table\"`, these commands declare their own, and\n * `optsWithGlobals` merges them with the command's own value winning. Reading\n * `FABRIC_FORMAT` again here undid that: `FABRIC_FORMAT=json fabric --format\n * table instructions check` printed JSON at the very moment the flag said not\n * to (review round 2, finding 10).\n *\n * Anything that is not `json` prints text. `table`, `yaml` and `csv` are real\n * values elsewhere in this CLI and these commands have no such shape — one\n * paragraph or one JSON object — so they degrade rather than fail. Refusing\n * them here would also be a promise this cannot keep: when a parent and a\n * subcommand declare the same flag, Commander stores the value on the ROOT,\n * so `fabric instructions check --format yaml` never arrives as a local\n * option at all.\n */\nexport function outputFormatFor(command: Command): OutputFormat {\n\tconst resolved = command.optsWithGlobals() as { format?: string };\n\treturn resolved.format === \"json\" ? \"json\" : \"text\";\n}\n\n/**\n * A failure that already knows which documented exit code it is\n * (`src/bin/fabric.ts`). Errors from the SDK are translated into one of\n * these at the boundary so the command bodies can just throw.\n */\nexport class CliFailure extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\treadonly exitCode: number,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"CliFailure\";\n\t}\n}\n\n/**\n * The absolute bound on hook mode.\n *\n * A race rather than a chain of per-request timeouts: the guarantee has to\n * hold whatever the SDK, the runtime or a wedged socket does, and only the\n * caller can promise that. The losing work is abandoned rather than awaited,\n * which is safe because the boundary above exits the process immediately\n * afterwards.\n *\n * `body` receives the deadline's signal, aborted when the time is up, so work\n * that can be cancelled — a download — is cancelled by the same clock.\n */\nexport async function withDeadline(\n\ttotalMs: number,\n\tbody: (signal: AbortSignal) => Promise<void>,\n): Promise<void> {\n\tconst controller = new AbortController();\n\tlet timer: NodeJS.Timeout | undefined;\n\tconst deadline = new Promise<never>((_resolve, reject) => {\n\t\ttimer = setTimeout(() => {\n\t\t\tcontroller.abort();\n\t\t\treject(\n\t\t\t\tnew Error(\n\t\t\t\t\t`gave up after ${totalMs}ms so the session is not held up`,\n\t\t\t\t),\n\t\t\t);\n\t\t}, totalMs);\n\t});\n\ttry {\n\t\tawait Promise.race([body(controller.signal), deadline]);\n\t} finally {\n\t\tif (timer) {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t}\n}\n\nexport function describeError(error: unknown): string {\n\tif (error instanceof Error) {\n\t\t// Collapsed to one line: under `--hook` this lands in a terminal\n\t\t// banner and, on Claude Code, in the agent's context.\n\t\treturn error.message.replace(/\\s*\\n\\s*/g, \" \");\n\t}\n\treturn String(error);\n}\n\n/**\n * SDK errors carry an HTTP status; the CLI's documented exit codes do not\n * come from it automatically. Mapped once, here.\n */\nexport function asCliFailure(error: unknown): CliFailure {\n\tif (error instanceof CliFailure) {\n\t\treturn error;\n\t}\n\tconst status = (error as { status?: number }).status;\n\tconst message = error instanceof Error ? error.message : String(error);\n\tswitch (status) {\n\t\tcase 401:\n\t\t\treturn new CliFailure(message, 3);\n\t\tcase 403:\n\t\t\treturn new CliFailure(message, 5);\n\t\tcase 404:\n\t\t\treturn new CliFailure(message, 4);\n\t\tcase 429:\n\t\t\treturn new CliFailure(message, 6);\n\t\tcase 400:\n\t\tcase 422:\n\t\t\treturn new CliFailure(message, 7);\n\t\tdefault:\n\t\t\treturn new CliFailure(message, 1);\n\t}\n}\n","/**\n * `<dir>/.fabric/context.lock` — what the server confirmed at the last push.\n *\n * A CONTENT LEDGER: each path with the hash the server holds for it and the\n * context row it is stored as. It decides two things and nothing else:\n *\n * - a file whose bytes still hash to the ledger's value is not sent at all;\n * - a changed file names the ledger's hash as `expectedContentHash`, so the\n * push replaces exactly the version this folder last saw, and anybody\n * else's edit since is a conflict rather than a silent overwrite.\n *\n * It never causes a read (only the walk decides what is read) and never a\n * deletion (this command deletes nothing). A tampered lock can therefore make\n * a push skip a file, or state a version the server will check; it cannot\n * make one reach outside the folder.\n *\n * Written LAST, after every request, with what the server answered:\n * `created`, `updated` or `unchanged` record the hash and the row; a\n * `duplicate` records the hash with `state: \"duplicate\"` and no row, because\n * the path has none of its own (its content is stored under another path).\n * An unchanged duplicate is therefore not sent again, and a changed one is\n * sent naming no version. A conflict and a failure leave their entry as it\n * was. An interrupted run leaves the old lock, and the next run repairs\n * itself: content the server already holds is answered `unchanged` and\n * recorded then.\n *\n * Read and written through the same guarded helpers as the coding-\n * instructions lock (`../instructions/safe-write.ts`), so a `.fabric -> ..`\n * symlink cannot turn either into an access outside the folder.\n */\nimport path from \"node:path\";\nimport { readFileSafely, writeFileSafely } from \"../instructions/safe-write.js\";\nimport { normalizeContextSourcePath } from \"./source-path.js\";\n\nconst CONTEXT_LOCK_DIRECTORY = \".fabric\";\nconst CONTEXT_LOCK_FILENAME = \"context.lock\";\n\n/**\n * Bumped only if the shape below changes incompatibly. The `duplicate` entry\n * was added without a bump: confirmed entries kept their exact shape.\n */\nexport const CONTEXT_LOCK_VERSION = 1;\n\nconst CONTEXT_LOCK_RELATIVE_PATH = `${CONTEXT_LOCK_DIRECTORY}/${CONTEXT_LOCK_FILENAME}`;\n\n/** Generous: one line per pushed file. Bounds a read, it limits nobody. */\nconst MAX_CONTEXT_LOCK_BYTES = 32 * 1024 * 1024;\n\nconst SHA256_HEX = /^[0-9a-f]{64}$/;\n\n/** A path the server stores: its hash when last confirmed, and its row. */\ninterface ConfirmedContextLockEntry {\n\t/** The server's `contentHash` for this path when it was last confirmed. */\n\tsha256: string;\n\tcontextId: string;\n\tstate?: undefined;\n}\n\n/**\n * A path the server answered `duplicate` for: this content is stored under\n * another path, and this path has no row. Kept so an unchanged duplicate is\n * not sent on every run; it names no version when its content changes.\n */\ninterface DuplicateContextLockEntry {\n\t/** The hash of the content that was answered `duplicate`. */\n\tsha256: string;\n\tstate: \"duplicate\";\n\tcontextId?: undefined;\n}\n\ntype ContextLockEntry = ConfirmedContextLockEntry | DuplicateContextLockEntry;\n\nexport interface ContextLock {\n\tversion: number;\n\tprojectId: string;\n\t/** ISO 8601 timestamp of the push that wrote this lock. */\n\tpushedAt: string;\n\t/** Keyed by the normalized `sourcePath` the server stores. */\n\tfiles: Record<string, ContextLockEntry>;\n}\n\nexport function contextLockPath(root: string): string {\n\treturn path.join(root, CONTEXT_LOCK_DIRECTORY, CONTEXT_LOCK_FILENAME);\n}\n\n/**\n * The lock, or `null` when this folder has never been pushed.\n *\n * A lock that exists but does not validate is an ERROR, never a `null`:\n * reading a damaged ledger as \"first push\" would send every file with no\n * expected version, turning every one of them the server already holds into\n * a conflict and hiding the damage behind that noise.\n */\nexport async function readContextLock(\n\troot: string,\n): Promise<ContextLock | null> {\n\tconst file = contextLockPath(root);\n\tconst read = await readFileSafely(root, CONTEXT_LOCK_RELATIVE_PATH, {\n\t\tmaxBytes: MAX_CONTEXT_LOCK_BYTES,\n\t});\n\tif (read === null) {\n\t\treturn null;\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(new TextDecoder().decode(read.bytes));\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`${file} is unreadable: it is not valid JSON. Delete it to push every file again with no expected version.`,\n\t\t);\n\t}\n\tconst problem = lockProblem(parsed);\n\tif (problem !== null) {\n\t\tthrow new Error(\n\t\t\t`${file} is unreadable: ${problem}. Delete it to push every file again with no expected version.`,\n\t\t);\n\t}\n\treturn parsed as ContextLock;\n}\n\n/** Pretty JSON with LF endings and a trailing newline, so a diff of it reads. */\nfunction serializeLock(lock: ContextLock): string {\n\treturn `${JSON.stringify(lock, null, 2).replace(/\\r\\n/g, \"\\n\")}\\n`;\n}\n\n/** Atomic (temp file, then rename), through the guarded writer. */\nexport async function writeContextLock(\n\troot: string,\n\tlock: ContextLock,\n): Promise<void> {\n\tawait writeFileSafely({\n\t\troot,\n\t\trelativePath: CONTEXT_LOCK_RELATIVE_PATH,\n\t\tbytes: new TextEncoder().encode(serializeLock(lock)),\n\t});\n}\n\n/**\n * Why this value is not a lock, or `null` when it is one.\n *\n * Every path must already be in the server's stored spelling. That keeps a\n * hand-edited lock from printing a control character into the terminal when\n * a path is reported, and from naming anything the server could never hold.\n */\nfunction lockProblem(value: unknown): string | null {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n\t\treturn \"it is not a JSON object\";\n\t}\n\tconst candidate = value as Record<string, unknown>;\n\tif (candidate.version !== CONTEXT_LOCK_VERSION) {\n\t\treturn `its version is ${JSON.stringify(candidate.version)} and this build writes version ${CONTEXT_LOCK_VERSION}`;\n\t}\n\tfor (const field of [\"projectId\", \"pushedAt\"] as const) {\n\t\tconst actual = candidate[field];\n\t\tif (typeof actual !== \"string\" || actual.length === 0) {\n\t\t\treturn `its \"${field}\" is not a non-empty string`;\n\t\t}\n\t}\n\tif (\n\t\ttypeof candidate.files !== \"object\" ||\n\t\tcandidate.files === null ||\n\t\tArray.isArray(candidate.files)\n\t) {\n\t\treturn 'its \"files\" is not an object';\n\t}\n\tfor (const [filePath, entry] of Object.entries(\n\t\tcandidate.files as Record<string, unknown>,\n\t)) {\n\t\tconst normalized = normalizeContextSourcePath(filePath);\n\t\tif (!normalized.ok || normalized.sourcePath !== filePath) {\n\t\t\treturn `it names ${JSON.stringify(filePath)}, which is not a path the server stores`;\n\t\t}\n\t\tif (\n\t\t\ttypeof entry !== \"object\" ||\n\t\t\tentry === null ||\n\t\t\tArray.isArray(entry)\n\t\t) {\n\t\t\treturn `its entry for ${JSON.stringify(filePath)} is not an object`;\n\t\t}\n\t\tconst record = entry as Record<string, unknown>;\n\t\tif (\n\t\t\ttypeof record.sha256 !== \"string\" ||\n\t\t\t!SHA256_HEX.test(record.sha256)\n\t\t) {\n\t\t\treturn `its entry for ${JSON.stringify(filePath)} has no 64-character hex sha256`;\n\t\t}\n\t\tif (record.state === \"duplicate\") {\n\t\t\tif (record.contextId !== undefined) {\n\t\t\t\treturn `its duplicate entry for ${JSON.stringify(filePath)} names a contextId, which a duplicate never has`;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (record.state !== undefined) {\n\t\t\treturn `its entry for ${JSON.stringify(filePath)} has an unknown state ${JSON.stringify(record.state)}`;\n\t\t}\n\t\tif (\n\t\t\ttypeof record.contextId !== \"string\" ||\n\t\t\trecord.contextId.length === 0\n\t\t) {\n\t\t\treturn `its entry for ${JSON.stringify(filePath)} has no contextId`;\n\t\t}\n\t}\n\treturn null;\n}\n","/**\n * The one writer every file this feature creates goes through — instruction\n * files, the lock, and the Claude Code settings file alike.\n *\n * It exists because there were three writers before and only one of them was\n * guarded. `.claude -> ..` or `.fabric -> ..` in a checkout turned `init` and\n * `sync` into writes outside the destination, because the hook and the lock\n * never asked the question the instruction files did. A guard that only some\n * writes call is not a guard.\n *\n * What every write proves first:\n *\n * 1. The destination is canonicalised once with `realpath`. Lexical\n * resolution is not enough — `/tmp` is a symlink on macOS, so the\n * literal string a user passes and the directory they mean are\n * routinely different, and containment has to be decided on the real\n * one. The destination itself is resolved rather than refused for that\n * reason; everything BELOW it is held to the stricter rule.\n * 2. No segment between the root and the file is a symlink. Checked with\n * `lstat`, from the first child down to and including the target.\n * 3. The deepest existing ancestor's `realpath` is still inside the root.\n * Layer 2 answers \"is this a link\"; this answers \"did anything else —\n * a bind mount, a replaced directory — move it\".\n * 4. The temp file is created with `wx` and an unpredictable name, so a\n * pre-planted file is an error rather than a file we write through.\n * 5. The parent is re-checked immediately before `rename`, closing the\n * window between the walk and the write.\n *\n * Bytes are preserved exactly: no newline conversion, no re-encoding. The\n * server hashes these files and so does the next sync.\n */\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { constants, type Stats } from \"node:fs\";\nimport type { FileHandle } from \"node:fs/promises\";\nimport {\n\tlstat,\n\tmkdir,\n\topen,\n\treadFile,\n\trealpath,\n\trename,\n\tunlink,\n} from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { describeRejection, type PathCheck } from \"./paths.js\";\n\n/**\n * The modes a published file may carry.\n *\n * The server derives exactly these two from an upload, so anything else is a\n * malformed or hostile manifest rather than a file that needs it. An\n * allow-list rather than a mask, because masking with `0o7777` preserves\n * setuid, setgid, sticky and every write bit — a manifest asking for `04777`\n * would have been honoured.\n */\nconst ALLOWED_MODES = new Set([0o644, 0o755]);\n\nexport function isAllowedMode(mode: number | null | undefined): boolean {\n\tif (mode === null || mode === undefined) {\n\t\treturn true;\n\t}\n\tif (!Number.isInteger(mode) || mode < 0) {\n\t\treturn false;\n\t}\n\t// A manifest records the full `st_mode` (`0o100644`), so compare on the\n\t// permission bits and require the file-type bits to be a regular file or\n\t// absent.\n\tconst type = mode & 0o170000;\n\tif (type !== 0 && type !== 0o100000) {\n\t\treturn false;\n\t}\n\treturn ALLOWED_MODES.has(mode & 0o7777);\n}\n\n/** The permission bits to apply, or null when none were published. */\nexport function permissionBits(mode: number | null | undefined): number | null {\n\tif (mode === null || mode === undefined) {\n\t\treturn null;\n\t}\n\treturn mode & 0o7777;\n}\n\n/**\n * Canonicalise the destination once, for every subsequent check to resolve\n * against. Created if missing: `--dest` naming a directory that does not\n * exist yet is an ordinary first sync.\n */\nexport async function resolveDestinationRoot(\n\tdestination: string,\n): Promise<string> {\n\tawait mkdir(destination, { recursive: true });\n\treturn realpath(destination);\n}\n\n/**\n * Where a relative path lands under an already-canonical root, or why it may\n * not land at all. `relativePath` must already have passed\n * `checkRelativePath`.\n */\nexport async function assertSafeTarget(\n\troot: string,\n\trelativePath: string,\n): Promise<PathCheck> {\n\tconst target = path.resolve(root, relativePath);\n\tif (target === root || !target.startsWith(root + path.sep)) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\treason: \"escapes_destination\",\n\t\t\tdetail: relativePath,\n\t\t};\n\t}\n\n\tconst segments = relativePath.split(\"/\");\n\tlet current = root;\n\tlet deepestExisting = root;\n\tfor (const [index, segment] of segments.entries()) {\n\t\tcurrent = path.join(current, segment);\n\t\tconst stats = await lstatOrNull(current);\n\t\tif (stats === null) {\n\t\t\t// Everything below here is about to be created, and a path that\n\t\t\t// does not exist cannot be a link to somewhere else.\n\t\t\tbreak;\n\t\t}\n\t\tif (stats.isSymbolicLink()) {\n\t\t\treturn { ok: false, reason: \"symlink\", detail: current };\n\t\t}\n\t\t// An ANCESTOR that is not a directory. `lstat` on anything below it\n\t\t// answers ENOTDIR, which used to read as \"absent\" — so a regular file\n\t\t// at `z` let `z/child.md` pass the whole-plan preflight and fail in\n\t\t// `makeParents` after earlier entries had already been written.\n\t\tif (index < segments.length - 1 && !stats.isDirectory()) {\n\t\t\treturn { ok: false, reason: \"not_a_directory\", detail: current };\n\t\t}\n\t\tdeepestExisting = current;\n\t}\n\n\t// Layer 3. `lstat` said no component IS a link; this says the components\n\t// still resolve where they appeared to.\n\tif (deepestExisting !== root) {\n\t\tconst canonical = await realpath(deepestExisting).catch(() => null);\n\t\tif (\n\t\t\tcanonical !== null &&\n\t\t\tcanonical !== root &&\n\t\t\t!canonical.startsWith(root + path.sep)\n\t\t) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: \"escapes_destination\",\n\t\t\t\tdetail: relativePath,\n\t\t\t};\n\t\t}\n\t}\n\n\treturn { ok: true, path: target };\n}\n\n/**\n * `assertSafeTarget`, plus: whatever is already at the final path must be an\n * ordinary file.\n *\n * `assertSafeTarget` answers \"may this land here\" — no symlinked component,\n * nothing resolving outside the root. It does not answer \"is the thing\n * already there a file\". A directory at a manifest path passed it, and the\n * eventual `rename` refused, but only after earlier entries in the same plan\n * had already been written. A fifo, socket or device node would be opened and\n * written through. Both are now refusals, and the caller runs this over EVERY\n * manifest and delete path before it mutates anything.\n */\nexport async function assertWritableTarget(\n\troot: string,\n\trelativePath: string,\n): Promise<PathCheck> {\n\tconst check = await assertSafeTarget(root, relativePath);\n\tif (!check.ok) {\n\t\treturn check;\n\t}\n\tconst stats = await lstatOrNull(check.path);\n\tif (stats === null) {\n\t\treturn check;\n\t}\n\tif (stats.isSymbolicLink()) {\n\t\treturn { ok: false, reason: \"symlink\", detail: check.path };\n\t}\n\tif (!stats.isFile()) {\n\t\treturn { ok: false, reason: \"not_a_regular_file\", detail: check.path };\n\t}\n\treturn check;\n}\n\n/**\n * Read a file under an already-canonical root, through the same guard every\n * write goes through, or `null` when it is not there.\n *\n * READS need the walk as much as writes do. The ledger check and the planner\n * used to `path.join` and `lstat` directly, which meant a lock path of\n * `../outside` read outside the destination, and an ancestor replaced by a\n * symlink was followed to wherever it pointed — hashing, and possibly loading\n * into memory, a file this tool has no business opening. A refusal is the\n * answer in both cases, not a hash.\n */\nexport async function readFileSafely(\n\troot: string,\n\trelativePath: string,\n\toptions: { maxBytes?: number } = {},\n): Promise<{ bytes: Uint8Array; mode: number } | null> {\n\tconst check = await assertWritableTarget(root, relativePath);\n\tif (!check.ok) {\n\t\tthrow new Error(`Refusing to sync: ${describeRejection(check)}.`);\n\t}\n\n\tlet handle: FileHandle;\n\ttry {\n\t\t// `O_NOFOLLOW` makes a final-component swap fail rather than following\n\t\t// it. `O_NONBLOCK` prevents a raced FIFO from holding the command before\n\t\t// the descriptor can be proven to be an ordinary file.\n\t\thandle = await open(\n\t\t\tcheck.path,\n\t\t\tconstants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK,\n\t\t);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\treturn null;\n\t\t}\n\t\tthrow error;\n\t}\n\n\ttry {\n\t\tconst opened = await handle.stat();\n\t\tif (!opened.isFile()) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${relativePath} is not a regular file.`,\n\t\t\t);\n\t\t}\n\t\t// Re-walk after opening, then bind the descriptor to the path that was\n\t\t// just checked. A swapped ancestor may make the path point elsewhere,\n\t\t// but no bytes are read until both checks agree on the same inode.\n\t\tconst afterOpen = await assertWritableTarget(root, relativePath);\n\t\tif (!afterOpen.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection(afterOpen)}.`,\n\t\t\t);\n\t\t}\n\t\tconst current = await lstatOrNull(afterOpen.path);\n\t\tif (\n\t\t\tcurrent === null ||\n\t\t\t!current.isFile() ||\n\t\t\tcurrent.dev !== opened.dev ||\n\t\t\tcurrent.ino !== opened.ino\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${relativePath} changed while it was being opened.`,\n\t\t\t);\n\t\t}\n\n\t\tif (options.maxBytes === undefined) {\n\t\t\treturn { bytes: await handle.readFile(), mode: opened.mode };\n\t\t}\n\t\tif (!Number.isSafeInteger(options.maxBytes) || options.maxBytes < 0) {\n\t\t\tthrow new Error(\n\t\t\t\t\"A safe file-read limit must be a non-negative integer.\",\n\t\t\t);\n\t\t}\n\t\tif (opened.size > options.maxBytes) {\n\t\t\tthrow new Error(\n\t\t\t\t`${relativePath} is too large to read safely (maximum ${options.maxBytes} bytes).`,\n\t\t\t);\n\t\t}\n\n\t\t// The extra byte catches a file that grew after `fstat` without ever\n\t\t// allocating or reading an unbounded body.\n\t\tconst buffer = Buffer.allocUnsafe(options.maxBytes + 1);\n\t\tlet total = 0;\n\t\twhile (total <= options.maxBytes) {\n\t\t\tconst { bytesRead } = await handle.read(\n\t\t\t\tbuffer,\n\t\t\t\ttotal,\n\t\t\t\toptions.maxBytes + 1 - total,\n\t\t\t\ttotal,\n\t\t\t);\n\t\t\tif (bytesRead === 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\ttotal += bytesRead;\n\t\t}\n\t\tif (total > options.maxBytes) {\n\t\t\tthrow new Error(\n\t\t\t\t`${relativePath} is too large to read safely (maximum ${options.maxBytes} bytes).`,\n\t\t\t);\n\t\t}\n\t\treturn { bytes: buffer.subarray(0, total), mode: opened.mode };\n\t} finally {\n\t\tawait handle.close();\n\t}\n}\n\n/**\n * The canonical form of a destination that must NOT be created.\n *\n * `resolveDestinationRoot` makes the directory, which is right for a sync and\n * wrong for `check`, an informational command. A destination that does not\n * exist has no lock either, so the literal resolved path is a fine answer.\n */\nexport async function resolveExistingRoot(\n\tdestination: string,\n): Promise<string> {\n\treturn realpath(destination).catch(() => path.resolve(destination));\n}\n\n/**\n * Create every missing parent directory of `relativePath`, one segment at a\n * time, refusing a symlink at each step.\n *\n * `mkdir(..., { recursive: true })` cannot be used for this: it follows an\n * existing symlinked component silently, which is the whole thing being\n * defended against.\n */\nasync function makeParents(root: string, relativePath: string): Promise<void> {\n\tconst segments = relativePath.split(\"/\").slice(0, -1);\n\tlet current = root;\n\tfor (const segment of segments) {\n\t\tcurrent = path.join(current, segment);\n\t\tconst stats = await lstatOrNull(current);\n\t\tif (stats === null) {\n\t\t\tawait mkdir(current).catch(async (error: NodeJS.ErrnoException) => {\n\t\t\t\t// A concurrent writer got there first. Re-check what landed\n\t\t\t\t// rather than assuming it is a directory.\n\t\t\t\tif (error.code !== \"EEXIST\") {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tconst raced = await lstatOrNull(current);\n\t\t\t\tif (raced?.isSymbolicLink()) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Refusing to sync: ${describeRejection({ ok: false, reason: \"symlink\", detail: current })}.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (stats.isSymbolicLink()) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection({ ok: false, reason: \"symlink\", detail: current })}.`,\n\t\t\t);\n\t\t}\n\t\tif (!stats.isDirectory()) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection({ ok: false, reason: \"not_a_directory\", detail: current })}.`,\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * Write one file atomically under an already-canonical root.\n *\n * `relativePath` must have passed `checkRelativePath` and any policy check\n * the caller owns (reserved paths, collisions) BEFORE this is called — this\n * function enforces the filesystem invariants, not the feature's rules.\n */\nexport async function writeFileSafely(input: {\n\troot: string;\n\trelativePath: string;\n\tbytes: Uint8Array;\n\tmode?: number | null;\n}): Promise<void> {\n\tconst check = await assertSafeTarget(input.root, input.relativePath);\n\tif (!check.ok) {\n\t\tthrow new Error(`Refusing to sync: ${describeRejection(check)}.`);\n\t}\n\tif (!isAllowedMode(input.mode)) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${input.relativePath} asks for file mode ${(input.mode ?? 0).toString(8)}, and only 644 and 755 are accepted.`,\n\t\t);\n\t}\n\n\tawait makeParents(input.root, input.relativePath);\n\n\tconst target = check.path;\n\tconst directory = path.dirname(target);\n\t// The identity of the directory we are about to create the temp file in.\n\t// Cleanup below unlinks BY PATH, and a path no longer names the same\n\t// directory once something has swapped it; unlinking then would delete a\n\t// stranger's file and leave the real temp behind. Node has no\n\t// handle-relative unlink, so the next best thing is to refuse to clean up\n\t// through a path that has moved.\n\tconst directoryBefore = await lstatOrNull(directory);\n\t// Unpredictable, so a pre-planted temp file cannot be waiting for us, and\n\t// `wx` so creating one that already exists is an error rather than a\n\t// write through whatever is there.\n\tconst temporary = path.join(\n\t\tdirectory,\n\t\t`.${path.basename(target)}.${randomBytes(8).toString(\"hex\")}.tmp`,\n\t);\n\n\tlet handle: FileHandle | null = null;\n\ttry {\n\t\thandle = await open(temporary, \"wx\", 0o600);\n\t\tawait handle.writeFile(input.bytes);\n\t\tconst bits = permissionBits(input.mode);\n\t\tif (bits !== null && process.platform !== \"win32\") {\n\t\t\tawait handle.chmod(bits);\n\t\t}\n\t\tawait handle.close();\n\t\thandle = null;\n\n\t\t// The walk above happened before the file was written. Re-check the\n\t\t// parent now, so a directory swapped for a link in between cannot\n\t\t// receive the rename.\n\t\tconst parentStats = await lstatOrNull(directory);\n\t\tif (parentStats === null || parentStats.isSymbolicLink()) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection({ ok: false, reason: \"symlink\", detail: directory })}.`,\n\t\t\t);\n\t\t}\n\t\tconst targetStats = await lstatOrNull(target);\n\t\tif (targetStats?.isSymbolicLink()) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection({ ok: false, reason: \"symlink\", detail: target })}.`,\n\t\t\t);\n\t\t}\n\n\t\tawait rename(temporary, target);\n\t} catch (error) {\n\t\tawait handle?.close().catch(() => {});\n\t\tif (await isSameDirectory(directory, directoryBefore)) {\n\t\t\tawait unlink(temporary).catch(() => {});\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/** Does this path still name the directory we checked earlier? */\nasync function isSameDirectory(\n\tdirectory: string,\n\tbefore: Stats | null,\n): Promise<boolean> {\n\tif (before === null) {\n\t\treturn false;\n\t}\n\tconst now = await lstatOrNull(directory);\n\treturn now !== null && now.dev === before.dev && now.ino === before.ino;\n}\n\nexport type DeleteOutcome = \"deleted\" | \"missing\" | \"modified\";\n\n/**\n * Remove one file under an already-canonical root — but only if it is still\n * the file the caller decided to remove.\n *\n * The plan hashes a departed file during planning, and a download, an\n * extraction and every write happen between then and here. An unconditional\n * `unlink` therefore deleted whatever was at that path by the time it ran,\n * including an edit the developer had saved in the meantime. The expected\n * hash travels with the request and is checked against the bytes on disk\n * immediately before the unlink; a file that no longer matches is left alone\n * and reported as kept.\n *\n * Residual, stated rather than hidden: a write landing between that hash and\n * the `unlink` is still lost. Node offers no way to unlink a specific inode,\n * so closing it entirely would need handle-relative syscalls the runtime does\n * not expose. Concurrent mutation of the destination by the same user during\n * a sync is out of scope for this tool.\n */\nexport async function deleteFileSafely(\n\troot: string,\n\trelativePath: string,\n\texpectedSha256: string,\n): Promise<DeleteOutcome> {\n\tconst check = await assertSafeTarget(root, relativePath);\n\tif (!check.ok) {\n\t\tthrow new Error(`Refusing to sync: ${describeRejection(check)}.`);\n\t}\n\n\tconst stats = await lstatOrNull(check.path);\n\tif (stats === null) {\n\t\treturn \"missing\";\n\t}\n\tif (stats.isSymbolicLink()) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${describeRejection({ ok: false, reason: \"symlink\", detail: check.path })}.`,\n\t\t);\n\t}\n\tif (!stats.isFile()) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${describeRejection({ ok: false, reason: \"not_a_regular_file\", detail: check.path })}.`,\n\t\t);\n\t}\n\n\tlet actual: string;\n\ttry {\n\t\tactual = createHash(\"sha256\")\n\t\t\t.update(await readFile(check.path))\n\t\t\t.digest(\"hex\");\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\treturn \"missing\";\n\t\t}\n\t\tthrow error;\n\t}\n\tif (actual !== expectedSha256) {\n\t\treturn \"modified\";\n\t}\n\n\ttry {\n\t\tawait unlink(check.path);\n\t\treturn \"deleted\";\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\treturn \"missing\";\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * `lstat`, with ONLY `ENOENT` meaning \"nothing there\".\n *\n * `ENOTDIR` used to be folded in here, and it does not mean the same thing at\n * all: it means an ancestor exists and is not a directory. Reading it as\n * \"absent\" is what let a regular file at `z` pass the preflight for\n * `z/child.md`. Callers that walk a path check the ancestors themselves; this\n * one lets the error through so nothing can mistake the two again.\n */\nasync function lstatOrNull(target: string) {\n\ttry {\n\t\treturn await lstat(target);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\treturn null;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * Does `candidate` sit inside `root` once both are resolved as far as the\n * filesystem allows?\n *\n * Used for the credential check in `hook.ts`, where the question is about a\n * path that may not exist yet and whose ancestors may be links. Lexical\n * comparison answered it wrongly in both directions: a config file reached\n * through a symlink into the checkout looked outside it, and a destination\n * under a symlinked parent looked like a mismatch.\n */\nexport async function resolvesInside(\n\troot: string,\n\tcandidate: string,\n): Promise<boolean> {\n\tconst canonicalRoot = await realpath(root).catch(() => path.resolve(root));\n\tconst canonicalCandidate = await realpathDeepest(candidate);\n\treturn (\n\t\tcanonicalCandidate === canonicalRoot ||\n\t\tcanonicalCandidate.startsWith(canonicalRoot + path.sep)\n\t);\n}\n\n/**\n * `realpath` of the deepest existing ancestor, with the not-yet-existing tail\n * appended. `realpath` throws on a missing path, and a config file that has\n * not been written yet still has an answer worth having.\n */\nasync function realpathDeepest(candidate: string): Promise<string> {\n\tconst absolute = path.resolve(candidate);\n\tconst tail: string[] = [];\n\tlet current = absolute;\n\tfor (;;) {\n\t\tconst resolved = await realpath(current).catch(() => null);\n\t\tif (resolved !== null) {\n\t\t\treturn tail.length === 0 ? resolved : path.join(resolved, ...tail);\n\t\t}\n\t\tconst parent = path.dirname(current);\n\t\tif (parent === current) {\n\t\t\treturn absolute;\n\t\t}\n\t\ttail.unshift(path.basename(current));\n\t\tcurrent = parent;\n\t}\n}\n","/**\n * Path safety for the file-writing half of this CLI.\n *\n * The paths this module guards arrive from a server response and from a zip\n * archive, and they are about to become filesystem writes on a developer's\n * machine. That makes the check local: the server validates paths on upload,\n * but a client that trusts a remote path list has moved the decision to the\n * wrong side of the wire. Nothing here asks the network anything.\n *\n * Three layers, and they answer different questions:\n *\n * `checkRelativePath` is this STRING safe to turn into a write?\n * `isReservedPath` is this path one this feature refuses to own?\n * `collisionKey` do two safe strings name the same file anyway?\n *\n * The filesystem half — symlinks, canonical containment, atomic writes —\n * lives in `safe-write.ts`, because it needs a resolved destination root and\n * these functions deliberately do not.\n *\n * The SERVER enforces the same name rules and the same collision key on the\n * way in (`packages/instructions/src/paths.ts`), so a version that stores is\n * a version that installs. It is a separate implementation because this\n * package is published to npm and that one is private, and the duplication is\n * pinned by `packages/instructions/__tests__/portable-names-agree-with-cli.test.ts`,\n * which imports both and asserts they agree on a fixture list of names.\n * Whole-path SYNTAX is where the two legitimately differ: the server\n * normalises separators and `./` prefixes for a browser folder upload, and\n * this module refuses them, because here the string is about to become a\n * write.\n */\n\ntype PathRejectReason =\n\t| \"empty\"\n\t| \"absolute\"\n\t| \"traversal\"\n\t| \"backslash\"\n\t| \"control_char\"\n\t| \"trailing_separator\"\n\t| \"trailing_dot_or_space\"\n\t| \"reserved_device_name\"\n\t| \"forbidden_character\"\n\t| \"reserved_path\"\n\t| \"not_a_regular_file\"\n\t| \"escapes_destination\"\n\t| \"symlink\"\n\t| \"not_a_directory\"\n\t| \"collision\";\n\nexport interface PathRejection {\n\tok: false;\n\treason: PathRejectReason;\n\t/** The offending path, as given, or the link that was in the way. */\n\tdetail: string;\n}\n\nexport type PathCheck = { ok: true; path: string } | PathRejection;\n\nconst DRIVE_LETTER = /^[A-Za-z]:/;\n\n/**\n * Names Windows resolves to a device rather than a file, with or without an\n * extension: `NUL`, `nul.txt` and `CON.md` all reach the device. Writing the\n * tree on Windows would silently discard those files; worse, a manifest could\n * use one to make a write look like it happened.\n */\nconst RESERVED_DEVICE_NAME = /^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(?:\\.|$)/i;\n\n/**\n * The characters Windows will not put in a filename: `< > : \" | ? *`.\n *\n * `/` and `\\` are absent because they are separators and are refused\n * structurally above.\n */\nconst FORBIDDEN_NAME_CHARACTER = /[<>:\"|?*]/;\n\n/**\n * Paths this feature refuses to write or delete, whatever a manifest or a\n * lock says.\n *\n * `.git` is the obvious one: a lock is a plain JSON file inside the checkout,\n * so anything that can edit it could otherwise name `.git/config` — a file\n * whose current hash is easy to know — and have the next sync unlink it.\n * `.fabric` is here because the lock lives there and must never be able to\n * authorise its own deletion or replacement through the manifest path.\n */\nconst RESERVED_ROOTS = [\".git\", \".fabric\"] as const;\n\n/**\n * Single files this feature refuses to own, as opposed to whole roots.\n *\n * `.claude/settings.local.json` and `.codex/hooks.json` are the files `init`\n * itself writes. Instruction files legitimately live elsewhere under either\n * root — skills and commands — so reserving a whole root would refuse the\n * feature's own content. Reserving only these paths stops a published manifest\n * from overwriting a session hook or later authorising its deletion.\n */\nconst RESERVED_EXACT_PATHS = [\n\t\".claude/settings.local.json\",\n\t\".codex/hooks.json\",\n] as const;\n\n/**\n * NUL and friends, found by character code rather than by a regular\n * expression.\n *\n * A character class cannot say this here. Written as unicode escapes, the\n * formatter rewrites each escape into the character it names, which puts\n * a literal NUL byte in this source file and makes git treat it as binary.\n * A loop says the same thing and stays readable in a diff.\n */\nfunction hasControlCharacter(input: string): boolean {\n\tfor (let index = 0; index < input.length; index++) {\n\t\tconst code = input.charCodeAt(index);\n\t\tif (code <= 0x1f || code === 0x7f) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Is this manifest/archive path safe to turn into a write inside a\n * destination? String-level only — see `safe-write.ts` for the filesystem\n * half.\n */\nexport function checkRelativePath(input: string): PathCheck {\n\tif (input.length === 0) {\n\t\treturn { ok: false, reason: \"empty\", detail: input };\n\t}\n\tif (hasControlCharacter(input)) {\n\t\treturn { ok: false, reason: \"control_char\", detail: input };\n\t}\n\tif (input.includes(\"\\\\\")) {\n\t\treturn { ok: false, reason: \"backslash\", detail: input };\n\t}\n\tif (input.startsWith(\"/\") || DRIVE_LETTER.test(input)) {\n\t\treturn { ok: false, reason: \"absolute\", detail: input };\n\t}\n\tif (input.endsWith(\"/\")) {\n\t\treturn { ok: false, reason: \"trailing_separator\", detail: input };\n\t}\n\tconst segments = input.split(\"/\");\n\tif (segments.some((s) => s.length === 0)) {\n\t\t// An empty segment means `a//b` or a leading slash already refused\n\t\t// above; either way the string is not the path it appears to be.\n\t\treturn { ok: false, reason: \"empty\", detail: input };\n\t}\n\tif (segments.some((s) => s === \".\" || s === \"..\")) {\n\t\treturn { ok: false, reason: \"traversal\", detail: input };\n\t}\n\tfor (const segment of segments) {\n\t\t// Windows strips a trailing dot or space from a name, so `a.md.` and\n\t\t// `a.md ` both open `a.md`. Two manifest entries that differ only\n\t\t// there would be two writes to one file, with the lock claiming both.\n\t\tif (/[. ]$/.test(segment)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: \"trailing_dot_or_space\",\n\t\t\t\tdetail: input,\n\t\t\t};\n\t\t}\n\t\tif (RESERVED_DEVICE_NAME.test(segment)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: \"reserved_device_name\",\n\t\t\t\tdetail: input,\n\t\t\t};\n\t\t}\n\t\t// One of the characters Windows refuses in a filename. A colon also\n\t\t// addresses an NTFS alternate data stream on the name before it,\n\t\t// which is a write to a file the manifest never named; `*` and `?`\n\t\t// are glob metacharacters and `<`, `>` and `|` are redirection\n\t\t// operators, so such a name is a hazard in any script over the tree.\n\t\tif (FORBIDDEN_NAME_CHARACTER.test(segment)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: \"forbidden_character\",\n\t\t\t\tdetail: input,\n\t\t\t};\n\t\t}\n\t}\n\treturn { ok: true, path: input };\n}\n\n/**\n * Is this a path this feature refuses to own, whoever asked?\n *\n * Applied to manifest entries AND to lock entries, on writes AND on deletes:\n * the lock is the thing being defended against here, so checking only what\n * the server sent would miss the case entirely.\n */\nexport function isReservedPath(input: string): boolean {\n\tconst first = input.split(\"/\")[0]?.toLowerCase();\n\tif (RESERVED_ROOTS.some((root) => first === root)) {\n\t\treturn true;\n\t}\n\t// Compared by collision key, not by string: on a case-insensitive\n\t// filesystem `.claude/Settings.Local.json` is the same file, and a\n\t// manifest that spells it differently must not slip past.\n\tconst key = collisionKey(input);\n\treturn RESERVED_EXACT_PATHS.some(\n\t\t(reserved) => collisionKey(reserved) === key,\n\t);\n}\n\n/**\n * A key two paths share when the filesystem would treat them as one file.\n *\n * macOS stores names in a normalised form and compares case-insensitively,\n * so `café.md` written as NFC and as NFD are one file with two spellings,\n * and `README.md`/`readme.md` are one file. The server's own collision check\n * catches ordinary case variants; it does not catch Unicode normalisation.\n *\n * Deliberately conservative and platform-independent: a manifest that would\n * collide on macOS is refused on Linux too, because the alternative is a\n * tree that syncs cleanly for one developer and silently loses a file for\n * the next.\n */\nexport function collisionKey(input: string): string {\n\treturn input.normalize(\"NFC\").toLowerCase();\n}\n\n/**\n * The first pair of manifest/lock paths that name the same file, or null.\n */\nexport function findCollision(\n\tpaths: readonly string[],\n): { first: string; second: string } | null {\n\tconst seen = new Map<string, string>();\n\tfor (const candidate of paths) {\n\t\tconst key = collisionKey(candidate);\n\t\tconst previous = seen.get(key);\n\t\tif (previous !== undefined) {\n\t\t\treturn { first: previous, second: candidate };\n\t\t}\n\t\tseen.set(key, candidate);\n\t}\n\treturn null;\n}\n\n/** A one-line reason a reader can act on. */\nexport function describeRejection(rejection: PathRejection): string {\n\tswitch (rejection.reason) {\n\t\tcase \"empty\":\n\t\t\treturn `empty or malformed path (${JSON.stringify(rejection.detail)})`;\n\t\tcase \"absolute\":\n\t\t\treturn `absolute path refused: ${rejection.detail}`;\n\t\tcase \"traversal\":\n\t\t\treturn `path traversal refused: ${rejection.detail}`;\n\t\tcase \"backslash\":\n\t\t\treturn `backslash in path refused: ${rejection.detail}`;\n\t\tcase \"control_char\":\n\t\t\treturn `control character in path refused: ${JSON.stringify(rejection.detail)}`;\n\t\tcase \"trailing_separator\":\n\t\t\treturn `path names a directory, not a file: ${rejection.detail}`;\n\t\tcase \"trailing_dot_or_space\":\n\t\t\treturn `path segment ending in a dot or space refused: ${rejection.detail}`;\n\t\tcase \"reserved_device_name\":\n\t\t\treturn `reserved device name refused: ${rejection.detail}`;\n\t\tcase \"forbidden_character\":\n\t\t\treturn `path contains a character Windows will not put in a filename (< > : \" | ? *): ${rejection.detail}`;\n\t\tcase \"reserved_path\":\n\t\t\treturn `this tool never writes or deletes ${RESERVED_ROOTS.join(\", \")} or ${RESERVED_EXACT_PATHS.join(\", \")}: ${rejection.detail}`;\n\t\tcase \"not_a_regular_file\":\n\t\t\treturn `path is not a regular file: ${rejection.detail}`;\n\t\tcase \"escapes_destination\":\n\t\t\treturn `path resolves outside the destination: ${rejection.detail}`;\n\t\tcase \"symlink\":\n\t\t\t// \"follow\", not \"write through\": the same guard now runs for reads\n\t\t\t// — the ledger check and the planner both go through it — and a\n\t\t\t// read-only `check --verify` should not talk about writing.\n\t\t\treturn `refusing to follow a symlink: ${rejection.detail}`;\n\t\tcase \"not_a_directory\":\n\t\t\treturn `a path component is not a directory: ${rejection.detail}`;\n\t\tcase \"collision\":\n\t\t\treturn `two paths name the same file on a case- or Unicode-insensitive filesystem: ${rejection.detail}`;\n\t}\n}\n","/**\n * The server's rule for a synced context file's path, mirrored so a file the\n * server would refuse is skipped here with the same reason word instead of\n * costing a request that can only fail.\n *\n * The authority is `normalizeContextSourcePath` in\n * `packages/database/prisma/queries/projects/context-source-path.ts`; this is\n * a copy rather than an import because `@fabricorg/cli` is published to npm\n * and that package is private. Keep the two in step: the reason words below\n * are the server's `ContextSourcePathErrorReason` values.\n *\n * - NFC first, so a decomposed name (macOS) and a composed one are one key;\n * - `\\` becomes `/`, repeated separators collapse, a leading `./` goes;\n * - absolute paths (`/…`, `\\\\server\\…`, any drive-letter prefix) refused;\n * - a `.` or `..` segment refused anywhere;\n * - a trailing separator refused;\n * - C0, DEL, C1 and format (`\\p{Cf}`) characters refused;\n * - at most 512 characters after normalising.\n */\n\nconst MAX_CONTEXT_SOURCE_PATH_LENGTH = 512;\n\ntype ContextSourcePathProblem =\n\t| \"empty\"\n\t| \"absolute\"\n\t| \"dot-segment\"\n\t| \"trailing-slash\"\n\t| \"control-character\"\n\t| \"too-long\";\n\nexport type ContextSourcePathCheck =\n\t| { ok: true; sourcePath: string }\n\t| { ok: false; reason: ContextSourcePathProblem };\n\n// Written with escapes so this file itself carries no such characters.\n// biome-ignore lint/suspicious/noControlCharactersInRegex: matching control characters is the point\nconst CONTROL_OR_FORMAT_CHARACTER = /[\\u0000-\\u001f\\u007f-\\u009f\\p{Cf}]/u;\nconst DRIVE_LETTER_PREFIX = /^[A-Za-z]:/;\n\nfunction hasControlOrFormatCharacter(value: string): boolean {\n\treturn CONTROL_OR_FORMAT_CHARACTER.test(value);\n}\n\nexport function normalizeContextSourcePath(\n\tinput: string,\n): ContextSourcePathCheck {\n\tconst slashed = input.normalize(\"NFC\").replace(/\\\\/g, \"/\");\n\n\tif (hasControlOrFormatCharacter(slashed)) {\n\t\treturn { ok: false, reason: \"control-character\" };\n\t}\n\t// Before collapsing, so `//server/share` is still recognisably absolute.\n\tif (slashed.startsWith(\"/\") || DRIVE_LETTER_PREFIX.test(slashed)) {\n\t\treturn { ok: false, reason: \"absolute\" };\n\t}\n\n\tlet path = slashed.replace(/\\/{2,}/g, \"/\");\n\twhile (path.startsWith(\"./\")) {\n\t\tpath = path.slice(2);\n\t}\n\n\tif (path.length === 0) {\n\t\treturn { ok: false, reason: \"empty\" };\n\t}\n\tif (path.endsWith(\"/\")) {\n\t\treturn { ok: false, reason: \"trailing-slash\" };\n\t}\n\tif (\n\t\tpath.split(\"/\").some((segment) => segment === \".\" || segment === \"..\")\n\t) {\n\t\treturn { ok: false, reason: \"dot-segment\" };\n\t}\n\tif (path.length > MAX_CONTEXT_SOURCE_PATH_LENGTH) {\n\t\treturn { ok: false, reason: \"too-long\" };\n\t}\n\treturn { ok: true, sourcePath: path };\n}\n","/**\n * Which walked files are text this command may send, and the hash each one is\n * known by.\n *\n * A first cut that only sends text: an allow-list of extensions, bytes that\n * decode as UTF-8 without a single replacement, no NUL, something other than\n * whitespace, and at most the server's 2 MiB. Everything else is SKIPPED with\n * a reason the report shows, never sent to be refused — the server applies\n * the same rules (`upsertSyncedContext`) and would only say no.\n */\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\n\n/**\n * The server's ceiling on one synced file (`MAX_SYNCED_CONTEXT_BYTES` in\n * `packages/api/modules/projects/lib/upsert-synced-context.ts`).\n */\nexport const MAX_CONTEXT_FILE_BYTES = 2 * 1024 * 1024;\n\n/** Compared lower-cased, so `README.MD` is text too. */\nconst CONTEXT_TEXT_EXTENSIONS: ReadonlySet<string> = new Set([\n\t\".md\",\n\t\".markdown\",\n\t\".txt\",\n\t\".json\",\n\t\".yaml\",\n\t\".yml\",\n]);\n\n/**\n * Why a file under the folder was not sent.\n *\n * - `unsupported-type` not one of the text extensions, or not a regular file\n * - `binary` not valid UTF-8, or contains NUL\n * - `empty` no bytes, or only whitespace\n * - `too-large` over 2 MiB of UTF-8\n * - `invalid-path` a path the server would refuse (`detail` carries the\n * server's reason word) or one two files would share\n * - `symlink` never followed, never sent\n * - `ignored` the lock names it but the ignore rules now leave it\n * out; its server entry is kept\n */\ntype ContextSkipReason =\n\t| \"unsupported-type\"\n\t| \"binary\"\n\t| \"empty\"\n\t| \"too-large\"\n\t| \"invalid-path\"\n\t| \"symlink\"\n\t| \"ignored\";\n\nexport interface SkippedContextFile {\n\tpath: string;\n\treason: ContextSkipReason;\n\tdetail?: string;\n}\n\nconst HAS_NON_WHITESPACE = /\\S/;\n\nexport function hasTextExtension(relativePath: string): boolean {\n\treturn CONTEXT_TEXT_EXTENSIONS.has(\n\t\tpath.posix.extname(relativePath).toLowerCase(),\n\t);\n}\n\n/**\n * The file's text, or why it is not text worth sending.\n *\n * `ignoreBOM: true` keeps a leading byte-order mark IN the string. The server\n * hashes the string it receives; had the decoder stripped the BOM, the hash\n * the server stores would differ from the hash of the bytes on disk, and an\n * untouched file would look changed to every later push.\n *\n * `fatal: true` is what makes \"decodes as UTF-8\" mean anything: the default\n * decoder replaces invalid bytes with U+FFFD silently, which would upload a\n * rewritten file.\n */\nexport function classifyContextBytes(\n\tbytes: Uint8Array,\n):\n\t| { ok: true; content: string }\n\t| { ok: false; reason: \"binary\" | \"empty\" | \"too-large\" } {\n\tif (bytes.byteLength > MAX_CONTEXT_FILE_BYTES) {\n\t\treturn { ok: false, reason: \"too-large\" };\n\t}\n\tlet content: string;\n\ttry {\n\t\tcontent = new TextDecoder(\"utf-8\", {\n\t\t\tfatal: true,\n\t\t\tignoreBOM: true,\n\t\t}).decode(bytes);\n\t} catch {\n\t\treturn { ok: false, reason: \"binary\" };\n\t}\n\t// Valid UTF-8 can still hold U+0000, which Postgres `text` cannot store\n\t// and the server refuses.\n\tif (content.includes(\"\\u0000\")) {\n\t\treturn { ok: false, reason: \"binary\" };\n\t}\n\t// The server's own emptiness test: nothing but whitespace (a lone BOM\n\t// counts as whitespace to `\\s`).\n\tif (!HAS_NON_WHITESPACE.test(content)) {\n\t\treturn { ok: false, reason: \"empty\" };\n\t}\n\treturn { ok: true, content };\n}\n\n/**\n * sha256 hex over the UTF-8 bytes of the content — the server's\n * `hashContextContent`, byte for byte, with nothing normalised first. It is\n * the compare-and-swap token a replace presents, and the lock records it.\n */\nexport function hashContextContent(content: string): string {\n\treturn createHash(\"sha256\").update(content, \"utf8\").digest(\"hex\");\n}\n","/**\n * Which paths under the pushed folder are never candidates at all.\n *\n * Two layers, matched with gitignore semantics by the `ignore` package:\n *\n * 1. DEFAULTS, always applied and never overridable. Version-control and\n * tool state (`.git/`, `.fabric/` — where the lock lives —\n * `node_modules/`), and every coding-instruction file or folder\n * (`CLAUDE.md`, `AGENTS.md`, `GEMINI.md`, `.claude/`, `.cursor/`,\n * `.codex/`, and directories named `skills`, `agents`, `hooks`, `rules`\n * or `scripts` at any depth). Instructions have their own reviewed path\n * into a project — `fabric instructions push` — and pushing them into\n * Context as well would make the same text answer from two places, one\n * of them unreviewed.\n * 2. The USER's: `<dir>/.contextignore` if present, then each `--exclude`.\n *\n * Kept as two matchers rather than one pattern list, because in one list a\n * user's `!CLAUDE.md` would re-include what the defaults exclude. A path the\n * defaults exclude is excluded whatever the user's rules say.\n *\n * Matching is case-insensitive (the package's default), so `claude.md` and\n * `Skills/` are excluded too.\n */\nimport ignore from \"ignore\";\n\ntype Ignore = ReturnType<typeof ignore>;\n\nexport const CONTEXT_IGNORE_FILENAME = \".contextignore\";\n\nconst DEFAULT_CONTEXT_IGNORE_PATTERNS: readonly string[] = [\n\t\".git/\",\n\t\".fabric/\",\n\t\".claude/\",\n\t\".cursor/\",\n\t\".codex/\",\n\t\"node_modules/\",\n\t\"CLAUDE.md\",\n\t\"AGENTS.md\",\n\t\"GEMINI.md\",\n\t\"skills/\",\n\t\"agents/\",\n\t\"hooks/\",\n\t\"rules/\",\n\t\"scripts/\",\n\tCONTEXT_IGNORE_FILENAME,\n];\n\nexport interface ContextIgnoreRules {\n\t/** Is this file (relative, `/`-separated) left out? */\n\tignoresFile(relativePath: string): boolean;\n\t/** Is this directory left out, and so not walked into? */\n\tignoresDirectory(relativePath: string): boolean;\n}\n\nexport function buildContextIgnoreRules(\n\tinput: { contextIgnore?: string | null; excludes?: readonly string[] } = {},\n): ContextIgnoreRules {\n\tconst defaults: Ignore = ignore().add([...DEFAULT_CONTEXT_IGNORE_PATTERNS]);\n\tconst user: Ignore = ignore();\n\tif (input.contextIgnore) {\n\t\tuser.add(input.contextIgnore);\n\t}\n\tif (input.excludes && input.excludes.length > 0) {\n\t\tuser.add([...input.excludes]);\n\t}\n\tconst ignores = (candidate: string) =>\n\t\tdefaults.ignores(candidate) || user.ignores(candidate);\n\treturn {\n\t\tignoresFile: (relativePath) => ignores(relativePath),\n\t\t// The trailing slash is what makes a directory-only pattern\n\t\t// (`drafts/`) match: gitignore semantics, as the package implements\n\t\t// them.\n\t\tignoresDirectory: (relativePath) => ignores(`${relativePath}/`),\n\t};\n}\n","/**\n * Every regular file under the pushed folder that the ignore rules leave in,\n * found without following a single symlink.\n *\n * `lstat` on every entry, never `stat`: a link is reported as a link and not\n * descended into or read, whatever it points at. A folder of notes that\n * happens to hold `secrets -> ~/.ssh` must not upload the key. Ignored paths\n * are dropped before anything else is asked of them, so a link inside\n * `node_modules/` is not reported, and an ignored directory is never walked.\n *\n * The file reads that follow go through `readFileSafely`, which walks the\n * path again segment by segment and refuses a symlinked component, so a\n * directory swapped for a link between this walk and the read is refused\n * there rather than followed.\n */\nimport type { Stats } from \"node:fs\";\nimport { lstat, readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { ContextIgnoreRules } from \"./ignore.js\";\n\ninterface WalkedFile {\n\t/** Relative to the folder, `/`-separated whatever the platform. */\n\tpath: string;\n\tsize: number;\n}\n\nexport interface ContextWalk {\n\tfiles: WalkedFile[];\n\t/** Links, reported and never followed. */\n\tsymlinks: string[];\n\t/** Fifos, sockets, devices: not files, never opened. */\n\tspecial: string[];\n\t/**\n\t * Paths the ignore matcher cannot evaluate (a segment made only of dots,\n\t * such as `...`, reads to it as a relative-path escape).\n\t */\n\tunmatchable: string[];\n\t/**\n\t * Entries the ignore rules dropped, as the listing spelled them: files,\n\t * links, and directories (which are not descended into, so what is\n\t * beneath one is ignored with it). With `files` and the lists above, this\n\t * is everything the walk saw, which is how a lock path is told apart as\n\t * \"still here but excluded\" or \"gone\" without asking the filesystem about\n\t * a spelling it may match case-insensitively.\n\t */\n\tignored: IgnoredEntry[];\n}\n\ninterface IgnoredEntry {\n\tpath: string;\n\tdirectory: boolean;\n}\n\nfunction byPath(a: string, b: string): number {\n\treturn a < b ? -1 : a > b ? 1 : 0;\n}\n\nexport async function walkContextDirectory(\n\troot: string,\n\trules: ContextIgnoreRules,\n): Promise<ContextWalk> {\n\tconst walk: ContextWalk = {\n\t\tfiles: [],\n\t\tsymlinks: [],\n\t\tspecial: [],\n\t\tunmatchable: [],\n\t\tignored: [],\n\t};\n\tconst pending: string[] = [\"\"];\n\twhile (pending.length > 0) {\n\t\tconst relativeDirectory = pending.pop() as string;\n\t\tconst names = await readdir(path.join(root, relativeDirectory));\n\t\tfor (const name of names) {\n\t\t\tconst relative = relativeDirectory\n\t\t\t\t? `${relativeDirectory}/${name}`\n\t\t\t\t: name;\n\t\t\tlet stats: Stats;\n\t\t\ttry {\n\t\t\t\tstats = await lstat(path.join(root, relative));\n\t\t\t} catch (error) {\n\t\t\t\t// Deleted between the listing and the look: nothing to send.\n\t\t\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tlet ignored: boolean;\n\t\t\ttry {\n\t\t\t\t// A link is matched as both a file and a directory: it is\n\t\t\t\t// never followed either way, and `node_modules -> ../x` in a\n\t\t\t\t// workspace package is the ignored directory, not a link\n\t\t\t\t// worth reporting.\n\t\t\t\tignored = stats.isDirectory()\n\t\t\t\t\t? rules.ignoresDirectory(relative)\n\t\t\t\t\t: stats.isSymbolicLink()\n\t\t\t\t\t\t? rules.ignoresFile(relative) ||\n\t\t\t\t\t\t\trules.ignoresDirectory(relative)\n\t\t\t\t\t\t: rules.ignoresFile(relative);\n\t\t\t} catch {\n\t\t\t\twalk.unmatchable.push(relative);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (ignored) {\n\t\t\t\twalk.ignored.push({\n\t\t\t\t\tpath: relative,\n\t\t\t\t\t// A link was matched as a directory too, so what would sit\n\t\t\t\t\t// beneath it counts as ignored with it.\n\t\t\t\t\tdirectory: stats.isDirectory() || stats.isSymbolicLink(),\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (stats.isSymbolicLink()) {\n\t\t\t\twalk.symlinks.push(relative);\n\t\t\t} else if (stats.isDirectory()) {\n\t\t\t\tpending.push(relative);\n\t\t\t} else if (stats.isFile()) {\n\t\t\t\twalk.files.push({ path: relative, size: stats.size });\n\t\t\t} else {\n\t\t\t\twalk.special.push(relative);\n\t\t\t}\n\t\t}\n\t}\n\twalk.files.sort((a, b) => byPath(a.path, b.path));\n\twalk.symlinks.sort(byPath);\n\twalk.special.sort(byPath);\n\twalk.unmatchable.sort(byPath);\n\twalk.ignored.sort((a, b) => byPath(a.path, b.path));\n\treturn walk;\n}\n","/**\n * What `fabric context push <dir>` would send, decided against the folder on\n * disk and the lock together, before a single request is made.\n *\n * Per candidate file, one of:\n *\n * push its hash is not the one the lock holds for its path —\n * sent with the lock's hash as `expectedContentHash`, or\n * with none when the lock does not name the path\n * unchanged-local its hash is the lock's: no request at all\n * skipped not something this command sends (see\n * `ContextSkipReason`), with the reason\n *\n * and per path the lock names that is no longer on disk: `removed`, reported\n * and nothing more. The product has not decided what deleting a local file\n * should do to its server copy, so the server entry — and the lock entry —\n * are kept. The exception is a lock entry recorded as a `duplicate`: the\n * server never stored that path, so there is nothing to keep, and it is\n * `forgotten` (dropped from the lock without a report line).\n *\n * \"No longer on disk\" is decided from the names the walk listed, never by\n * asking the filesystem about the lock's spelling: a case-insensitive\n * filesystem answers \"yes\" for `Docs/Guide.md` after a rename to\n * `docs/guide.md`, and the old path would read as excluded instead of gone.\n *\n * The plan keeps each file's hash and size, not its content: the push reads\n * the file again right before sending it and sends it only if it still\n * hashes to what was planned.\n */\nimport { readFileSafely } from \"../instructions/safe-write.js\";\nimport {\n\tclassifyContextBytes,\n\thashContextContent,\n\thasTextExtension,\n\tMAX_CONTEXT_FILE_BYTES,\n\ttype SkippedContextFile,\n} from \"./classify.js\";\nimport { buildContextIgnoreRules, CONTEXT_IGNORE_FILENAME } from \"./ignore.js\";\nimport type { ContextLock } from \"./lock.js\";\nimport { normalizeContextSourcePath } from \"./source-path.js\";\nimport { walkContextDirectory } from \"./walk.js\";\n\nexport interface ContextPushCandidate {\n\t/** The normalized path the server keys the file on. */\n\tsourcePath: string;\n\t/** The file's path on disk, relative to the folder. */\n\tdiskPath: string;\n\t/** Of the content as planned; the push sends only content that still has it. */\n\tsha256: string;\n\t/** UTF-8 bytes. */\n\tbytes: number;\n\t/**\n\t * The lock's hash for this path; absent when the lock does not name it,\n\t * or names it only as a `duplicate` (a path with no row to replace).\n\t */\n\texpectedContentHash?: string;\n}\n\nexport interface ContextPlan {\n\t/** In sorted `sourcePath` order, which is the order they are sent in. */\n\tpush: ContextPushCandidate[];\n\tunchangedLocal: string[];\n\tremoved: string[];\n\t/** `duplicate` lock entries whose file is gone: dropped from the lock. */\n\tforgotten: string[];\n\tskipped: SkippedContextFile[];\n}\n\nfunction byPath(a: string, b: string): number {\n\treturn a < b ? -1 : a > b ? 1 : 0;\n}\n\n/** The folder's own `.contextignore`, through the guarded reader, or `null`. */\nasync function readContextIgnore(root: string): Promise<string | null> {\n\tconst read = await readFileSafely(root, CONTEXT_IGNORE_FILENAME, {\n\t\tmaxBytes: 1024 * 1024,\n\t});\n\treturn read === null ? null : new TextDecoder().decode(read.bytes);\n}\n\n/**\n * Whether a lock path is one the walk saw and the ignore rules dropped —\n * itself, or beneath a dropped directory — compared in the server's spelling\n * (NFC) and with the case the listing gave it.\n */\nfunction ignoredByWalk(\n\tignored: readonly { path: string; directory: boolean }[],\n): (sourcePath: string) => boolean {\n\tconst exact = new Set(ignored.map((entry) => entry.path.normalize(\"NFC\")));\n\tconst directories = ignored\n\t\t.filter((entry) => entry.directory)\n\t\t.map((entry) => `${entry.path.normalize(\"NFC\")}/`);\n\treturn (sourcePath) =>\n\t\texact.has(sourcePath) ||\n\t\tdirectories.some((prefix) => sourcePath.startsWith(prefix));\n}\n\n/**\n * Why a readable file shares its stored path with another, or `null`. Two\n * files the server would store as ONE path (a composed and a decomposed\n * spelling of a name) would silently drop one of them; two that differ only\n * in case are two rows on the server but one file on a case-insensitive\n * filesystem, where the lock and every later push would confuse them.\n * Neither file of such a pair is sent.\n */\nfunction sharedPathProblem(\n\tentry: { diskPath: string; sourcePath: string },\n\tgroup: readonly { diskPath: string; sourcePath: string }[],\n): string | null {\n\tconst others = group.filter((other) => other.diskPath !== entry.diskPath);\n\tif (others.length === 0) {\n\t\treturn null;\n\t}\n\tconst names = others.map((other) => other.diskPath).join(\", \");\n\treturn others.every((other) => other.sourcePath === entry.sourcePath)\n\t\t? `names the same source as ${names}`\n\t\t: `case-only collision with ${names}`;\n}\n\nexport async function computeContextPlan(input: {\n\t/** Already canonical (`resolveExistingRoot`). */\n\troot: string;\n\tlock: ContextLock | null;\n\texcludes?: readonly string[];\n}): Promise<ContextPlan> {\n\tconst { root, lock } = input;\n\tconst rules = buildContextIgnoreRules({\n\t\tcontextIgnore: await readContextIgnore(root),\n\t\texcludes: input.excludes,\n\t});\n\tconst walk = await walkContextDirectory(root, rules);\n\n\tconst skipped: SkippedContextFile[] = [\n\t\t...walk.symlinks.map((p) => ({ path: p, reason: \"symlink\" as const })),\n\t\t...walk.special.map((p) => ({\n\t\t\tpath: p,\n\t\t\treason: \"unsupported-type\" as const,\n\t\t})),\n\t\t...walk.unmatchable.map((p) => ({\n\t\t\tpath: p,\n\t\t\treason: \"invalid-path\" as const,\n\t\t\tdetail: \"cannot be matched against the ignore rules\",\n\t\t})),\n\t];\n\n\t// Path checks first: they cost nothing and need no read.\n\tconst readable: { diskPath: string; sourcePath: string }[] = [];\n\tfor (const file of walk.files) {\n\t\t// A backslash inside a POSIX file name is not a separator on disk, and\n\t\t// the server would read it as one: the file would be stored under a\n\t\t// path that names something else.\n\t\tif (file.path.includes(\"\\\\\")) {\n\t\t\tskipped.push({\n\t\t\t\tpath: file.path,\n\t\t\t\treason: \"invalid-path\",\n\t\t\t\tdetail: \"backslash\",\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst normalized = normalizeContextSourcePath(file.path);\n\t\tif (!normalized.ok) {\n\t\t\tskipped.push({\n\t\t\t\tpath: file.path,\n\t\t\t\treason: \"invalid-path\",\n\t\t\t\tdetail: normalized.reason,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (!hasTextExtension(file.path)) {\n\t\t\tskipped.push({ path: file.path, reason: \"unsupported-type\" });\n\t\t\tcontinue;\n\t\t}\n\t\tif (file.size > MAX_CONTEXT_FILE_BYTES) {\n\t\t\tskipped.push({ path: file.path, reason: \"too-large\" });\n\t\t\tcontinue;\n\t\t}\n\t\treadable.push({\n\t\t\tdiskPath: file.path,\n\t\t\tsourcePath: normalized.sourcePath,\n\t\t});\n\t}\n\n\t// Grouped by the case-folded stored path, which catches both kinds of\n\t// sharing `sharedPathProblem` describes.\n\tconst byFoldedPath = new Map<string, typeof readable>();\n\tfor (const entry of readable) {\n\t\tconst key = entry.sourcePath.toLowerCase();\n\t\tbyFoldedPath.set(key, [...(byFoldedPath.get(key) ?? []), entry]);\n\t}\n\n\tconst push: ContextPushCandidate[] = [];\n\tconst unchangedLocal: string[] = [];\n\t/** Stored paths the walk found on disk this run, pushed or not. */\n\tconst present = new Set<string>();\n\tfor (const entry of readable) {\n\t\tconst problem = sharedPathProblem(\n\t\t\tentry,\n\t\t\tbyFoldedPath.get(entry.sourcePath.toLowerCase()) ?? [],\n\t\t);\n\t\tif (problem !== null) {\n\t\t\tskipped.push({\n\t\t\t\tpath: entry.diskPath,\n\t\t\t\treason: \"invalid-path\",\n\t\t\t\tdetail: problem,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst read = await readFileSafely(root, entry.diskPath, {\n\t\t\tmaxBytes: MAX_CONTEXT_FILE_BYTES,\n\t\t}).catch((error: unknown) => {\n\t\t\t// Grew past the limit between the walk and the read.\n\t\t\tif (error instanceof Error && /too large/.test(error.message)) {\n\t\t\t\treturn \"too-large\" as const;\n\t\t\t}\n\t\t\tthrow error;\n\t\t});\n\t\tif (read === null) {\n\t\t\t// Deleted since the walk: nothing to send.\n\t\t\tcontinue;\n\t\t}\n\t\tif (read === \"too-large\") {\n\t\t\tskipped.push({ path: entry.diskPath, reason: \"too-large\" });\n\t\t\tcontinue;\n\t\t}\n\t\tconst verdict = classifyContextBytes(read.bytes);\n\t\tif (!verdict.ok) {\n\t\t\tskipped.push({ path: entry.diskPath, reason: verdict.reason });\n\t\t\tcontinue;\n\t\t}\n\t\t// Only the hash and the size are kept; `verdict.content` goes out of\n\t\t// scope here, so planning holds one file's text at a time.\n\t\tconst sha256 = hashContextContent(verdict.content);\n\t\tconst locked = lock?.files[entry.sourcePath];\n\t\tconst plannedFile = {\n\t\t\tsourcePath: entry.sourcePath,\n\t\t\tdiskPath: entry.diskPath,\n\t\t\tsha256,\n\t\t\tbytes: read.bytes.byteLength,\n\t\t};\n\t\tif (locked?.sha256 === sha256) {\n\t\t\tunchangedLocal.push(entry.sourcePath);\n\t\t} else {\n\t\t\tpush.push(\n\t\t\t\t// A duplicate never had a row of its own, so there is no\n\t\t\t\t// version to name: it is sent like a new path.\n\t\t\t\tlocked && locked.state !== \"duplicate\"\n\t\t\t\t\t? { ...plannedFile, expectedContentHash: locked.sha256 }\n\t\t\t\t\t: plannedFile,\n\t\t\t);\n\t\t}\n\t\tpresent.add(entry.sourcePath);\n\t}\n\n\t// Lock paths with no candidate and no skip line. Gone from disk is\n\t// `removed` (or, for a duplicate the server never stored, `forgotten`);\n\t// still there but now excluded by the ignore rules is a skip, so nobody\n\t// reads \"removed\" about a file they can see.\n\tfor (const skip of skipped) {\n\t\tconst check = normalizeContextSourcePath(skip.path);\n\t\tif (check.ok) {\n\t\t\tpresent.add(check.sourcePath);\n\t\t}\n\t}\n\tconst isIgnored = ignoredByWalk(walk.ignored);\n\tconst removed: string[] = [];\n\tconst forgotten: string[] = [];\n\tfor (const [sourcePath, entry] of Object.entries(lock?.files ?? {})) {\n\t\tif (present.has(sourcePath)) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (entry.state === \"duplicate\") {\n\t\t\t// No server entry to keep or to report on, gone or excluded.\n\t\t\tforgotten.push(sourcePath);\n\t\t} else if (isIgnored(sourcePath)) {\n\t\t\tskipped.push({ path: sourcePath, reason: \"ignored\" });\n\t\t} else {\n\t\t\tremoved.push(sourcePath);\n\t\t}\n\t}\n\n\tpush.sort((a, b) => byPath(a.sourcePath, b.sourcePath));\n\tunchangedLocal.sort(byPath);\n\tremoved.sort(byPath);\n\tforgotten.sort(byPath);\n\tskipped.sort((a, b) => byPath(a.path, b.path));\n\treturn { push, unchangedLocal, removed, forgotten, skipped };\n}\n","/**\n * Sending a context plan, one file per request, and what the lock learns\n * from the answers.\n *\n * Sequential and in sorted path order: the report reads in the order things\n * happened, and a folder of notes gains nothing from racing its own requests\n * against the server's per-key rate limit.\n *\n * Outcomes per file:\n *\n * created | updated | unchanged the server holds this content now —\n * recorded in the lock\n * duplicate the path is new and identical content is\n * already stored under another path —\n * nothing stored; recorded as a duplicate\n * (hash, no row), so it is not re-sent\n * until it changes\n * conflict the path holds a version this folder did\n * not name, or the version it named was\n * deleted on the server — nothing written,\n * the lock entry left exactly as it was\n * changed-during-run the file no longer hashes to what was\n * planned — not sent, lock entry untouched;\n * the next run picks the new content up\n * failed this request failed; the others still go\n *\n * Each file is read again, through the guarded reader, immediately before\n * its request: the plan keeps hashes, not contents, so a folder is never held\n * in memory at once, and what is sent is exactly what was planned.\n *\n * `--force` answers a conflict by sending the same content again, once,\n * naming the version the conflict reported — or, when the named version was\n * deleted on the server, naming none, which recreates the file unless that\n * content already exists elsewhere in the project (then the answer is\n * `duplicate`). If that is a conflict too — somebody changed it again in\n * between — it is reported as one. There is no third attempt: `--force`\n * means \"replace the version you just told me about\", never \"win whatever\n * happens\". The file is read again before the resend too, so a file saved\n * while the first request was out is `changed-during-run`, not resent.\n *\n * A refusal that would repeat for every file — the key is invalid, lacks\n * `projects:write`, its owner lost the permission, the project is not\n * there, the rate limit, a server that cannot be reached — stops the run\n * rather than failing every remaining file with the same sentence.\n */\nimport type {\n\tFabricClient,\n\tSyncedContextFileConflict,\n\tSyncedContextFileCurrentVersion,\n\tSyncedContextFileResult,\n} from \"@fabricorg/sdk\";\nimport {\n\tasCliFailure,\n\ttype CliFailure,\n\tdescribeError,\n} from \"../command-boundary.js\";\nimport { readFileSafely } from \"../instructions/safe-write.js\";\nimport {\n\tclassifyContextBytes,\n\thashContextContent,\n\tMAX_CONTEXT_FILE_BYTES,\n} from \"./classify.js\";\nimport type { ContextLock } from \"./lock.js\";\nimport { CONTEXT_LOCK_VERSION } from \"./lock.js\";\nimport type { ContextPlan, ContextPushCandidate } from \"./plan.js\";\n\nexport type ContextPushResult =\n\t| {\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"created\" | \"updated\" | \"unchanged\";\n\t\t\tcontextId: string;\n\t\t\tcontentHash: string;\n\t\t\t/**\n\t\t\t * Present when `--force` replaced a version somebody else had\n\t\t\t * changed: the version it replaced.\n\t\t\t */\n\t\t\toverwrote?: SyncedContextFileCurrentVersion;\n\t }\n\t| {\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"duplicate\";\n\t\t\tcontentHash: string;\n\t\t\tduplicateOfContextId: string;\n\t\t\tduplicateOfSourcePath: string | null;\n\t }\n\t| {\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"conflict\";\n\t\t\tcontentHash: string;\n\t\t\t/** Whether this path was in the lock when it was sent. */\n\t\t\twasLocked: boolean;\n\t\t\t/** True when this is the answer to the one `--force` resend. */\n\t\t\tafterForce: boolean;\n\t\t\t/** `null`: the version this folder named was deleted on the server. */\n\t\t\tcurrent: SyncedContextFileCurrentVersion | null;\n\t }\n\t| {\n\t\t\tsourcePath: string;\n\t\t\t/**\n\t\t\t * The file no longer hashes to what the plan recorded (edited,\n\t\t\t * deleted, or no longer text since). Not sent this run.\n\t\t\t */\n\t\t\tstatus: \"changed-during-run\";\n\t }\n\t| {\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"failed\";\n\t\t\terror: string;\n\t\t\t/** The documented exit code this failure maps to. */\n\t\t\texitCode: number;\n\t };\n\nexport interface ContextPushRun {\n\tresults: ContextPushResult[];\n\t/** A refusal that stopped the run before every file was sent. */\n\tstoppedBy: CliFailure | null;\n}\n\n/** HTTP statuses that are about the key or the project, not the file. */\nconst RUN_LEVEL_STATUSES = new Set([401, 403, 404, 429]);\n\n/**\n * Failures with no HTTP answer at all, after the client's own retries: the\n * server is unreachable or not answering, and the next file would say so too.\n */\nconst RUN_LEVEL_CODES = new Set([\"NETWORK_ERROR\", \"TIMEOUT\"]);\n\nfunction stopsTheRun(error: unknown): boolean {\n\tconst { status, code } = error as { status?: unknown; code?: unknown };\n\treturn (\n\t\t(typeof status === \"number\" && RUN_LEVEL_STATUSES.has(status)) ||\n\t\t(typeof code === \"string\" && RUN_LEVEL_CODES.has(code))\n\t);\n}\n\n/**\n * The conflict payload, from the SDK's typed error. Read by shape rather than\n * by `instanceof`, so a second copy of the SDK in a dependency tree cannot\n * turn a conflict into a generic failure.\n */\nfunction conflictOf(error: unknown): SyncedContextFileConflict | null {\n\tif (typeof error !== \"object\" || error === null) {\n\t\treturn null;\n\t}\n\tconst conflict = (error as { conflict?: unknown }).conflict;\n\tif (\n\t\ttypeof conflict === \"object\" &&\n\t\tconflict !== null &&\n\t\t(conflict as { status?: unknown }).status === \"conflict\" &&\n\t\t\"current\" in conflict &&\n\t\t// An object, or `null` for a named version deleted on the server.\n\t\ttypeof (conflict as { current?: unknown }).current === \"object\"\n\t) {\n\t\treturn conflict as SyncedContextFileConflict;\n\t}\n\treturn null;\n}\n\n/**\n * The file's text as it is now, or `null` when it is no longer what the plan\n * hashed — the same guarded read, classification and hash the plan used, so\n * a file edited, deleted or turned binary since is never sent under the\n * plan's hash.\n */\nasync function readPlannedContent(\n\troot: string,\n\tentry: ContextPushCandidate,\n): Promise<string | null> {\n\tconst read = await readFileSafely(root, entry.diskPath, {\n\t\tmaxBytes: MAX_CONTEXT_FILE_BYTES,\n\t}).catch((error: unknown) => {\n\t\tif (error instanceof Error && /too large/.test(error.message)) {\n\t\t\treturn null;\n\t\t}\n\t\tthrow error;\n\t});\n\tif (read === null) {\n\t\treturn null;\n\t}\n\tconst verdict = classifyContextBytes(read.bytes);\n\tif (!verdict.ok || hashContextContent(verdict.content) !== entry.sha256) {\n\t\treturn null;\n\t}\n\treturn verdict.content;\n}\n\ntype ServerAnswer = Extract<\n\tContextPushResult,\n\t{ status: \"created\" | \"updated\" | \"unchanged\" | \"duplicate\" }\n>;\n\nfunction fromResult(\n\tsourcePath: string,\n\tresult: SyncedContextFileResult,\n): ServerAnswer {\n\tif (result.status === \"duplicate\") {\n\t\treturn {\n\t\t\tsourcePath,\n\t\t\tstatus: \"duplicate\",\n\t\t\tcontentHash: result.contentHash,\n\t\t\tduplicateOfContextId: result.duplicateOfContextId,\n\t\t\tduplicateOfSourcePath: result.duplicateOfSourcePath,\n\t\t};\n\t}\n\treturn {\n\t\tsourcePath,\n\t\tstatus: result.status,\n\t\tcontextId: result.contextId,\n\t\tcontentHash: result.contentHash,\n\t};\n}\n\nexport async function pushContextPlan(input: {\n\tclient: FabricClient;\n\tprojectId: string;\n\torg?: string;\n\t/** The folder the plan was made from (`resolveExistingRoot`). */\n\troot: string;\n\tplan: ContextPlan;\n\tforce: boolean;\n}): Promise<ContextPushRun> {\n\tconst results: ContextPushResult[] = [];\n\n\tconst send = (\n\t\tentry: ContextPushCandidate,\n\t\tcontent: string,\n\t\texpectedContentHash?: string,\n\t) =>\n\t\tinput.client.contexts.upsertSyncedFile(\n\t\t\tinput.projectId,\n\t\t\t{\n\t\t\t\tsourcePath: entry.sourcePath,\n\t\t\t\tcontent,\n\t\t\t\t...(expectedContentHash !== undefined\n\t\t\t\t\t? { expectedContentHash }\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t\t{ org: input.org },\n\t\t);\n\n\tfor (const entry of input.plan.push) {\n\t\ttry {\n\t\t\tconst content = await readPlannedContent(input.root, entry);\n\t\t\tif (content === null) {\n\t\t\t\tresults.push({\n\t\t\t\t\tsourcePath: entry.sourcePath,\n\t\t\t\t\tstatus: \"changed-during-run\",\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tresults.push(\n\t\t\t\t\tfromResult(\n\t\t\t\t\t\tentry.sourcePath,\n\t\t\t\t\t\tawait send(entry, content, entry.expectedContentHash),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tconst conflict = conflictOf(error);\n\t\t\t\tif (conflict === null) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tconst { current } = conflict;\n\t\t\t\t// No hash on the stored row means no version a push can name,\n\t\t\t\t// so `--force` has nothing to replace it with. A deleted one\n\t\t\t\t// (`current: null`) is resent naming no version at all, which\n\t\t\t\t// recreates it or answers `duplicate`.\n\t\t\t\tif (\n\t\t\t\t\t!input.force ||\n\t\t\t\t\t(current !== null && current.contentHash === null)\n\t\t\t\t) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\tsourcePath: entry.sourcePath,\n\t\t\t\t\t\tstatus: \"conflict\",\n\t\t\t\t\t\tcontentHash: conflict.contentHash,\n\t\t\t\t\t\twasLocked: entry.expectedContentHash !== undefined,\n\t\t\t\t\t\tafterForce: false,\n\t\t\t\t\t\tcurrent,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Read the file again: it may have been saved while the first\n\t\t\t\t// request was out, and a resend that names the server's version\n\t\t\t\t// must not replace it with content the folder no longer holds.\n\t\t\t\tconst forcedContent = await readPlannedContent(\n\t\t\t\t\tinput.root,\n\t\t\t\t\tentry,\n\t\t\t\t);\n\t\t\t\tif (forcedContent === null) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\tsourcePath: entry.sourcePath,\n\t\t\t\t\t\tstatus: \"changed-during-run\",\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconst forced = fromResult(\n\t\t\t\t\t\tentry.sourcePath,\n\t\t\t\t\t\tawait send(\n\t\t\t\t\t\t\tentry,\n\t\t\t\t\t\t\tforcedContent,\n\t\t\t\t\t\t\tcurrent === null\n\t\t\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t\t\t: (current.contentHash ?? undefined),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\t// Only a replace overwrote anything. `unchanged` means the\n\t\t\t\t\t// server already held this very content by then, and a\n\t\t\t\t\t// recreate replaced nothing.\n\t\t\t\t\tresults.push(\n\t\t\t\t\t\tforced.status === \"updated\" && current !== null\n\t\t\t\t\t\t\t? { ...forced, overwrote: current }\n\t\t\t\t\t\t\t: forced,\n\t\t\t\t\t);\n\t\t\t\t} catch (retryError) {\n\t\t\t\t\tconst again = conflictOf(retryError);\n\t\t\t\t\tif (again === null) {\n\t\t\t\t\t\tthrow retryError;\n\t\t\t\t\t}\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\tsourcePath: entry.sourcePath,\n\t\t\t\t\t\tstatus: \"conflict\",\n\t\t\t\t\t\tcontentHash: again.contentHash,\n\t\t\t\t\t\twasLocked: entry.expectedContentHash !== undefined,\n\t\t\t\t\t\tafterForce: true,\n\t\t\t\t\t\tcurrent: again.current,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst failure = asCliFailure(error);\n\t\t\tif (stopsTheRun(error)) {\n\t\t\t\treturn { results, stoppedBy: failure };\n\t\t\t}\n\t\t\tresults.push({\n\t\t\t\tsourcePath: entry.sourcePath,\n\t\t\t\tstatus: \"failed\",\n\t\t\t\terror: describeError(error),\n\t\t\t\texitCode: failure.exitCode,\n\t\t\t});\n\t\t}\n\t}\n\treturn { results, stoppedBy: null };\n}\n\n/**\n * The lock after these results, or `null` when it would say nothing new.\n *\n * Starts from the previous ledger, so paths that were not sent this time —\n * unchanged locally, removed locally, skipped, conflicting, changed during\n * the run, failed — keep exactly the entry they had. What the server\n * confirmed moves; a duplicate is recorded as one; a `forgotten` duplicate\n * (its file gone, and the server never stored its path) is dropped.\n */\nexport function nextContextLock(input: {\n\tprevious: ContextLock | null;\n\tprojectId: string;\n\tresults: readonly ContextPushResult[];\n\tforgotten?: readonly string[];\n\tnow: Date;\n}): ContextLock | null {\n\tconst files = { ...(input.previous?.files ?? {}) };\n\tlet changed = false;\n\tfor (const sourcePath of input.forgotten ?? []) {\n\t\tif (sourcePath in files) {\n\t\t\tdelete files[sourcePath];\n\t\t\tchanged = true;\n\t\t}\n\t}\n\tfor (const result of input.results) {\n\t\tif (result.status === \"duplicate\") {\n\t\t\tconst before = files[result.sourcePath];\n\t\t\tif (\n\t\t\t\tbefore?.state === \"duplicate\" &&\n\t\t\t\tbefore.sha256 === result.contentHash\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfiles[result.sourcePath] = {\n\t\t\t\tsha256: result.contentHash,\n\t\t\t\tstate: \"duplicate\",\n\t\t\t};\n\t\t\tchanged = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\tresult.status !== \"created\" &&\n\t\t\tresult.status !== \"updated\" &&\n\t\t\tresult.status !== \"unchanged\"\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst before = files[result.sourcePath];\n\t\tif (\n\t\t\tbefore?.state === undefined &&\n\t\t\tbefore?.sha256 === result.contentHash &&\n\t\t\tbefore.contextId === result.contextId\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\tfiles[result.sourcePath] = {\n\t\t\tsha256: result.contentHash,\n\t\t\tcontextId: result.contextId,\n\t\t};\n\t\tchanged = true;\n\t}\n\tif (!changed) {\n\t\treturn null;\n\t}\n\treturn {\n\t\tversion: CONTEXT_LOCK_VERSION,\n\t\tprojectId: input.projectId,\n\t\tpushedAt: input.now.toISOString(),\n\t\tfiles,\n\t};\n}\n","/**\n * The words and the JSON a `fabric context push` prints.\n *\n * Grouped by outcome with a count on each group, one line per file for every\n * outcome except `unchanged`, which is only counted: a folder of two hundred\n * notes where one changed should read as one line and a count.\n */\nimport type { SkippedContextFile } from \"./classify.js\";\nimport type { ContextPlan } from \"./plan.js\";\nimport type { ContextPushResult } from \"./push.js\";\n\ntype ResultOf<S extends ContextPushResult[\"status\"]> = Extract<\n\tContextPushResult,\n\t{ status: S }\n>;\n\nexport interface ContextPushCounts {\n\tcreated: number;\n\tupdated: number;\n\tunchanged: number;\n\tduplicate: number;\n\tconflict: number;\n\tchangedDuringRun: number;\n\tfailed: number;\n\tremoved: number;\n\tskipped: number;\n}\n\nfunction countOutcomes(\n\tplan: ContextPlan,\n\tresults: readonly ContextPushResult[],\n): ContextPushCounts {\n\tconst count = (status: ContextPushResult[\"status\"]) =>\n\t\tresults.filter((r) => r.status === status).length;\n\treturn {\n\t\tcreated: count(\"created\"),\n\t\tupdated: count(\"updated\"),\n\t\tunchanged: count(\"unchanged\") + plan.unchangedLocal.length,\n\t\tduplicate: count(\"duplicate\"),\n\t\tconflict: count(\"conflict\"),\n\t\tchangedDuringRun: count(\"changed-during-run\"),\n\t\tfailed: count(\"failed\"),\n\t\tremoved: plan.removed.length,\n\t\tskipped: plan.skipped.length,\n\t};\n}\n\nfunction who(current: { contentUpdatedBy: { name: string | null } | null }) {\n\treturn current.contentUpdatedBy?.name ?? \"someone\";\n}\n\nfunction when(current: { contentUpdatedAt: string | null }) {\n\treturn current.contentUpdatedAt ?? \"an unknown time\";\n}\n\nfunction conflictLine(result: ResultOf<\"conflict\">): string {\n\tconst { current } = result;\n\tif (current === null) {\n\t\treturn `${result.sourcePath}: deleted on the server since your last push`;\n\t}\n\tlet text: string;\n\tif (result.afterForce) {\n\t\ttext = `changed on the server again by ${who(current)} at ${when(current)} while --force was replacing it`;\n\t} else if (result.wasLocked) {\n\t\ttext = `changed on the server by ${who(current)} at ${when(current)} since your last push`;\n\t} else {\n\t\ttext = `already on the server with different content, last changed by ${who(current)} at ${when(current)}`;\n\t}\n\tif (current.contentHash === null) {\n\t\ttext +=\n\t\t\t\"; that version has no content hash, so --force cannot replace it\";\n\t}\n\treturn `${result.sourcePath}: ${text}`;\n}\n\nfunction storedLine(result: ResultOf<\"created\" | \"updated\" | \"unchanged\">) {\n\tif (result.overwrote) {\n\t\treturn `${result.sourcePath}: replaced the version ${who(result.overwrote)} changed at ${when(result.overwrote)} (--force)`;\n\t}\n\treturn result.sourcePath;\n}\n\nfunction skippedLine(skip: SkippedContextFile): string {\n\tif (skip.reason === \"ignored\") {\n\t\treturn `${skip.path}: now excluded by the ignore rules; server entry kept`;\n\t}\n\treturn skip.detail\n\t\t? `${skip.path}: ${skip.reason} (${skip.detail})`\n\t\t: `${skip.path}: ${skip.reason}`;\n}\n\nfunction group(lines: string[], label: string, items: readonly string[]) {\n\tif (items.length === 0) {\n\t\treturn;\n\t}\n\tlines.push(`${label} (${items.length})`);\n\tfor (const item of items) {\n\t\tlines.push(` ${item}`);\n\t}\n}\n\n/** The text report for a push that was sent. */\nexport function formatPushReport(input: {\n\tprojectId: string;\n\tdirectory: string;\n\tplan: ContextPlan;\n\tresults: readonly ContextPushResult[];\n}): string[] {\n\tconst { plan, results } = input;\n\tconst of = <S extends ContextPushResult[\"status\"]>(status: S) =>\n\t\tresults.filter((r): r is ResultOf<S> => r.status === status);\n\n\tconst lines = [\n\t\t`Context push from ${input.directory} to project ${input.projectId}:`,\n\t];\n\tgroup(lines, \"created\", of(\"created\").map(storedLine));\n\tgroup(lines, \"updated\", of(\"updated\").map(storedLine));\n\tgroup(\n\t\tlines,\n\t\t\"duplicate\",\n\t\tof(\"duplicate\").map(\n\t\t\t(r) =>\n\t\t\t\t`${r.sourcePath}: duplicate of ${r.duplicateOfSourcePath ?? \"another source in this project\"}`,\n\t\t),\n\t);\n\tgroup(lines, \"conflict\", of(\"conflict\").map(conflictLine));\n\tgroup(\n\t\tlines,\n\t\t\"changed during the run\",\n\t\tof(\"changed-during-run\").map(\n\t\t\t(r) =>\n\t\t\t\t`${r.sourcePath}: changed-during-run; not sent, the next push sends the new content`,\n\t\t),\n\t);\n\tgroup(\n\t\tlines,\n\t\t\"failed\",\n\t\tof(\"failed\").map((r) => `${r.sourcePath}: ${r.error}`),\n\t);\n\tgroup(\n\t\tlines,\n\t\t\"removed\",\n\t\tplan.removed.map((p) => `${p}: removed locally; server entry kept`),\n\t);\n\tgroup(lines, \"skipped\", plan.skipped.map(skippedLine));\n\tconst unchanged = countOutcomes(plan, results).unchanged;\n\tif (unchanged > 0) {\n\t\tlines.push(`unchanged (${unchanged})`);\n\t}\n\treturn lines;\n}\n\n/** The text report for `--dry-run`: what would be sent, and nothing else. */\nexport function formatDryRunReport(input: {\n\tprojectId: string;\n\tdirectory: string;\n\tplan: ContextPlan;\n}): string[] {\n\tconst { plan } = input;\n\tconst lines = [\n\t\t`Dry run of a context push from ${input.directory} to project ${input.projectId}: nothing was sent and the lock was not written.`,\n\t];\n\tgroup(\n\t\tlines,\n\t\t\"new\",\n\t\tplan.push\n\t\t\t.filter((entry) => entry.expectedContentHash === undefined)\n\t\t\t.map((entry) => entry.sourcePath),\n\t);\n\tgroup(\n\t\tlines,\n\t\t\"changed\",\n\t\tplan.push\n\t\t\t.filter((entry) => entry.expectedContentHash !== undefined)\n\t\t\t.map((entry) => entry.sourcePath),\n\t);\n\tgroup(\n\t\tlines,\n\t\t\"removed\",\n\t\tplan.removed.map(\n\t\t\t(p) => `${p}: removed locally; server entry would be kept`,\n\t\t),\n\t);\n\tgroup(lines, \"skipped\", plan.skipped.map(skippedLine));\n\tif (plan.unchangedLocal.length > 0) {\n\t\tlines.push(`unchanged (${plan.unchangedLocal.length})`);\n\t}\n\treturn lines;\n}\n\n/** The `--format json` object: the whole plan and every result, never file content. */\nexport function contextPushJson(input: {\n\tprojectId: string;\n\tdirectory: string;\n\tlockPath: string;\n\tlockWritten: boolean;\n\tdryRun: boolean;\n\tforce: boolean;\n\tplan: ContextPlan;\n\tresults: readonly ContextPushResult[];\n}) {\n\treturn {\n\t\tprojectId: input.projectId,\n\t\tdirectory: input.directory,\n\t\tdryRun: input.dryRun,\n\t\tforce: input.force,\n\t\tlock: input.lockPath,\n\t\tlockWritten: input.lockWritten,\n\t\tplan: {\n\t\t\tpush: input.plan.push.map((entry) => ({\n\t\t\t\tsourcePath: entry.sourcePath,\n\t\t\t\tsha256: entry.sha256,\n\t\t\t\tbytes: entry.bytes,\n\t\t\t\texpectedContentHash: entry.expectedContentHash ?? null,\n\t\t\t})),\n\t\t\tunchangedLocal: input.plan.unchangedLocal,\n\t\t\tremoved: input.plan.removed,\n\t\t\tforgotten: input.plan.forgotten,\n\t\t\tskipped: input.plan.skipped,\n\t\t},\n\t\tresults: input.results,\n\t\tcounts: countOutcomes(input.plan, input.results),\n\t};\n}\n","/**\n * fabric ctx\n *\n * fabric ctx current Show active context\n * fabric ctx use org <slug> Set an org as default\n *\n * `use personal` is retired (Fizzy #1875, PO-9). It is still REGISTERED rather\n * than deleted, so someone who types it — or has it in a script — is told what\n * replaced it instead of meeting \"unknown command\". A config written by an\n * earlier version can still hold a personal default; `current` reports it as\n * needing replacing rather than printing it as if it still worked.\n */\n\nimport { Command } from \"commander\";\nimport { getDefaultContext, saveDefaultContext } from \"../../lib/config.js\";\nimport { printError, printSuccess, printWarning } from \"../../lib/output.js\";\n\nexport function buildCtxCommand(): Command {\n\tconst ctx = new Command(\"ctx\").description(\n\t\t\"Manage the organization commands run in\",\n\t);\n\n\t// -- current ------------------------------------------------------------\n\tctx.command(\"current\")\n\t\t.description(\"Show the active default context\")\n\t\t.action(() => {\n\t\t\tconst stored = getDefaultContext();\n\t\t\tif (!stored) {\n\t\t\t\tprintWarning(\n\t\t\t\t\t\"No default context set. Use --org <slug> on each command, or run:\\n fabric ctx use org <slug>\",\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (stored.type === \"personal\") {\n\t\t\t\t// Reported, not hidden: it is set, the user can see it is set,\n\t\t\t\t// and saying \"none\" would send them looking for a setting that\n\t\t\t\t// is right there.\n\t\t\t\tprintWarning(\n\t\t\t\t\t\"Context: personal — retired, and no command will accept it.\\nReplace it with:\\n fabric ctx use org <slug>\",\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tprocess.stdout.write(`Context: org:${stored.slug}\\n`);\n\t\t});\n\n\t// -- use ----------------------------------------------------------------\n\tconst use = new Command(\"use\").description(\n\t\t\"Set the default organization for commands\",\n\t);\n\n\tuse.command(\"personal\")\n\t\t.description(\"Retired — context is organization-only\")\n\t\t.action(() => {\n\t\t\tprintError(\n\t\t\t\t\"Personal context no longer exists — every command runs inside an organization.\\nSet one with:\\n fabric ctx use org <slug>\",\n\t\t\t\t2,\n\t\t\t);\n\t\t});\n\n\tuse.command(\"org <slug>\")\n\t\t.description(\"Use an org context by default\")\n\t\t.action((slug: string) => {\n\t\t\tsaveDefaultContext({ type: \"org\", slug });\n\t\t\tprintSuccess(`Default context set to: org:${slug}`);\n\t\t});\n\n\tctx.addCommand(use);\n\n\treturn ctx;\n}\n","/**\n * fabric features\n *\n * fabric features list --project <id> List features in a project\n * fabric features show --project <id> <id> Show feature details\n * fabric features create --project <id> <title> Create a feature\n */\n\nimport type { FabricFeature } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport {\n\tprintError,\n\tprintOutput,\n\tprintRecord,\n\tprintSuccess,\n} from \"../../lib/output.js\";\n\nexport function buildFeaturesCommand(): Command {\n\tconst features = new Command(\"features\").description(\n\t\t\"Manage project features\",\n\t);\n\n\t// -- list ----------------------------------------------------------------\n\tfeatures\n\t\t.command(\"list\")\n\t\t.description(\"List features in a project\")\n\t\t.requiredOption(\"-p, --project <id>\", \"Project ID\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\n\t\t\t\"--priority <priority>\",\n\t\t\t\"Filter: P0_CRITICAL|P1_HIGH|P2_MEDIUM|P3_LOW\",\n\t\t)\n\t\t.option(\"--search <query>\", \"Search by title\")\n\t\t.option(\"--limit <n>\", \"Max results (default 50)\", \"50\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\tproject: string;\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tpriority?: string;\n\t\t\t\tsearch?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricFeature[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.projects.listFeatures(opts.project, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tpriority: opts.priority as\n\t\t\t\t\t\t\t| FabricFeature[\"priority\"]\n\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\tsearch: opts.search,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const f of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${f.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\"identifier\", \"title\", \"priority\", \"createdAt\"],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- show ----------------------------------------------------------------\n\tfeatures\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show feature details\")\n\t\t.requiredOption(\"-p, --project <projectId>\", \"Project ID\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: {\n\t\t\t\t\tproject: string;\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\tformat: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet feature: FabricFeature;\n\t\t\t\ttry {\n\t\t\t\t\tfeature = await client.projects.getFeature(\n\t\t\t\t\t\topts.project,\n\t\t\t\t\t\tid,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(feature, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: feature.id,\n\t\t\t\t\tIdentifier: feature.identifier,\n\t\t\t\t\tTitle: feature.title,\n\t\t\t\t\tPriority: feature.priority,\n\t\t\t\t\tDescription: feature.description ?? \"(none)\",\n\t\t\t\t\t\"Acceptance Criteria\":\n\t\t\t\t\t\tfeature.acceptanceCriteria ?? \"(none)\",\n\t\t\t\t\tProject: feature.projectId,\n\t\t\t\t\tAssignee: feature.assigneeId ?? \"(none)\",\n\t\t\t\t\tCreated: feature.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- create --------------------------------------------------------------\n\tfeatures\n\t\t.command(\"create <title>\")\n\t\t.description(\"Create a feature in a project\")\n\t\t.requiredOption(\"-p, --project <projectId>\", \"Project ID\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"-d, --description <text>\", \"Feature description\")\n\t\t.option(\n\t\t\t\"--priority <priority>\",\n\t\t\t\"Priority: P0_CRITICAL|P1_HIGH|P2_MEDIUM|P3_LOW (default: P2_MEDIUM)\",\n\t\t)\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\ttitle: string,\n\t\t\t\topts: {\n\t\t\t\t\tproject: string;\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\tdescription?: string;\n\t\t\t\t\tpriority?: string;\n\t\t\t\t\tformat: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet feature: FabricFeature;\n\t\t\t\ttry {\n\t\t\t\t\tfeature = await client.projects.createFeature(\n\t\t\t\t\t\topts.project,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttitle,\n\t\t\t\t\t\t\tdescription: opts.description,\n\t\t\t\t\t\t\tpriority: opts.priority as\n\t\t\t\t\t\t\t\t| FabricFeature[\"priority\"]\n\t\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(feature, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintSuccess(`Feature ${feature.identifier} created`);\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: feature.id,\n\t\t\t\t\tIdentifier: feature.identifier,\n\t\t\t\t\tTitle: feature.title,\n\t\t\t\t\tPriority: feature.priority,\n\t\t\t\t\tProject: feature.projectId,\n\t\t\t\t\tCreated: feature.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- tasks ---------------------------------------------------------------\n\tfeatures\n\t\t.command(\"tasks\")\n\t\t.description(\"List tasks (sub-items) for a feature\")\n\t\t.requiredOption(\"-p, --project <projectId>\", \"Project ID\")\n\t\t.requiredOption(\"-f, --feature <featureId>\", \"Feature ID\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\tproject: string;\n\t\t\t\tfeature: string;\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet tasks: import(\"@fabricorg/sdk\").FabricTask[];\n\t\t\t\ttry {\n\t\t\t\t\ttasks = await client.projects.listTasks(\n\t\t\t\t\t\topts.project,\n\t\t\t\t\t\topts.feature,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const t of tasks) {\n\t\t\t\t\t\tprocess.stdout.write(`${t.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(tasks, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"identifier\",\n\t\t\t\t\t\t\"title\",\n\t\t\t\t\t\t\"status\",\n\t\t\t\t\t\t\"estimatedHours\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- update --------------------------------------------------------------\n\tfeatures\n\t\t.command(\"update <id>\")\n\t\t.description(\"Update a feature\")\n\t\t.requiredOption(\"-p, --project <projectId>\", \"Project ID\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--title <title>\", \"New title\")\n\t\t.option(\"-d, --description <text>\", \"New description\")\n\t\t.option(\n\t\t\t\"--priority <priority>\",\n\t\t\t\"Priority: P0_CRITICAL|P1_HIGH|P2_MEDIUM|P3_LOW\",\n\t\t)\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: {\n\t\t\t\t\tproject: string;\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\ttitle?: string;\n\t\t\t\t\tdescription?: string;\n\t\t\t\t\tpriority?: string;\n\t\t\t\t\tformat: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet feature: FabricFeature;\n\t\t\t\ttry {\n\t\t\t\t\tfeature = await client.projects.updateFeature(\n\t\t\t\t\t\topts.project,\n\t\t\t\t\t\tid,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttitle: opts.title,\n\t\t\t\t\t\t\tdescription: opts.description,\n\t\t\t\t\t\t\tpriority: opts.priority as\n\t\t\t\t\t\t\t\t| FabricFeature[\"priority\"]\n\t\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(feature, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: feature.id,\n\t\t\t\t\tIdentifier: feature.identifier,\n\t\t\t\t\tTitle: feature.title,\n\t\t\t\t\tPriority: feature.priority,\n\t\t\t\t\tUpdated: feature.updatedAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn features;\n}\n","/**\n * fabric frames\n *\n * fabric frames list List frames and slideshows\n * fabric frames show <id> Show frame details\n */\n\nimport type { FabricFrame } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildFramesCommand(): Command {\n\tconst frames = new Command(\"frames\").description(\n\t\t\"Manage AI-generated frames and slideshows\",\n\t);\n\n\t// -- list ----------------------------------------------------------------\n\tframes\n\t\t.command(\"list\")\n\t\t.description(\"List frames and slideshows\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--limit <n>\", \"Max results (default 50)\", \"50\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricFrame[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.frames.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const f of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${f.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"title\",\n\t\t\t\t\t\t\"fileType\",\n\t\t\t\t\t\t\"status\",\n\t\t\t\t\t\t\"isPublic\",\n\t\t\t\t\t\t\"updatedAt\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- show ----------------------------------------------------------------\n\tframes\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show frame details\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet frame: FabricFrame;\n\t\t\t\ttry {\n\t\t\t\t\tframe = await client.frames.get(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(frame, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: frame.id,\n\t\t\t\t\tTitle: frame.title,\n\t\t\t\t\tKind: frame.kind ?? \"(none)\",\n\t\t\t\t\t\"File Type\": frame.fileType,\n\t\t\t\t\tStatus: frame.status,\n\t\t\t\t\tPublic: frame.isPublic ? \"yes\" : \"no\",\n\t\t\t\t\t\"Share Token\": frame.shareToken ?? \"(none)\",\n\t\t\t\t\tDescription: frame.description ?? \"(none)\",\n\t\t\t\t\tUpdated: frame.updatedAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn frames;\n}\n","/**\n * fabric instructions\n *\n * fabric instructions check --project <id> Is the local copy current?\n * fabric instructions sync --project <id> Make it current.\n * fabric instructions push --project <id> Suggest the local edits back.\n * fabric instructions init --project <id> --tool claude-code|codex\n * Take the first copy, then write the session hook.\n *\n * The first file-writing commands in this CLI. Everything that touches the\n * filesystem lives in `lib/instructions/` as small testable modules; this\n * file is argument parsing, the sequence, and the words a developer reads.\n *\n * `--hook` is the contract that makes this safe to run at session start: it\n * NEVER exits non-zero, it has ONE absolute deadline covering every request\n * it makes, and it never prints more than it has to. A coding session that\n * cannot start because Fabric is unreachable would be a far worse failure\n * than instructions that are one version stale.\n */\nimport path from \"node:path\";\nimport type { FabricClient, PublishedInstructions } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport {\n\tasCliFailure,\n\tCliFailure,\n\tdescribeError,\n\ttype OutputFormat,\n\toutputFormatFor,\n\twithDeadline,\n} from \"../../lib/command-boundary.js\";\nimport { getApiKey, getConfigPath } from \"../../lib/config.js\";\nimport { applyPlan } from \"../../lib/instructions/apply.js\";\nimport { extractBundle, fetchBundle } from \"../../lib/instructions/bundle.js\";\nimport {\n\tassertKeyStaysOutside,\n\tbuildHookCommand,\n\tCLAUDE_SETTINGS_RELATIVE_PATH,\n\tCODEX_HOOKS_RELATIVE_PATH,\n\ttype InstructionsHookTool,\n\tmergeSessionStartHook,\n} from \"../../lib/instructions/hook.js\";\nimport {\n\ttype InstructionsLock,\n\tLOCK_DIRECTORY,\n\tlockPath,\n\treadLock,\n\twriteLock,\n} from \"../../lib/instructions/lock.js\";\nimport {\n\tassertValidManifest,\n\tmaxArchiveBytes,\n} from \"../../lib/instructions/manifest.js\";\nimport {\n\tcomputeSyncPlan,\n\tnextLock,\n\ttype SyncPlan,\n\tverifyLedger,\n} from \"../../lib/instructions/plan.js\";\nimport {\n\tcomputePushPlan,\n\tMAX_PUSH_CHANGES,\n} from \"../../lib/instructions/push.js\";\nimport {\n\tresolveDestinationRoot,\n\tresolveExistingRoot,\n} from \"../../lib/instructions/safe-write.js\";\nimport { printOutput } from \"../../lib/output.js\";\n\n/**\n * The whole of hook mode, end to end, including the bundle download.\n *\n * One ABSOLUTE deadline rather than one per request. The SDK's timeout is\n * per attempt and it retries twice by default, so three \"5 second\" calls\n * plus backoff is about 15.75 seconds — past the point where Claude Code\n * kills the hook itself, possibly mid-write. Retries are off in hook mode\n * and this bound covers everything.\n */\nconst HOOK_DEADLINE_MS = 10_000;\n\n/** A manual check: no writes, so one short request and no more. */\nconst CHECK_TIMEOUT_MS = 5_000;\n\n/** A manual sync may wait longer for the manifest, but not indefinitely. */\nconst SYNC_TIMEOUT_MS = 15_000;\n\n/**\n * The archive, when a person is waiting rather than a session start — and the\n * request that ASKS for the archive, not just the transfer that follows it.\n *\n * `createDownloadUrl` is normally sub-second, because publishing a version\n * pre-builds its archive. When the pre-build did not happen (it failed, or\n * the object was swept) the server builds the zip inside that request, which\n * on a large tree takes far longer than any manifest read — and under the\n * manifest's 15-second budget the call timed out, retried, and each retry\n * started ANOTHER full build on the server rather than waiting for the first.\n * So the download-link call gets this budget and no retries.\n */\nconst BUNDLE_TIMEOUT_MS = 60_000;\n\n/**\n * A push carries file bytes up and starts a validation run, so it waits longer\n * than the manifest calls do — and it gets ONE attempt, so the timeout is the\n * whole budget rather than a third of it.\n */\nconst PUSH_TIMEOUT_MS = 60_000;\n\n/**\n * Commander's accumulator for a repeatable `--add`.\n *\n * Declared with an initial `[]`, so `previous` is always an array and this\n * never has to guess.\n */\nfunction collectAdded(value: string, previous: string[]): string[] {\n\treturn [...previous, value];\n}\n\ninterface CommonOptions {\n\tproject: string;\n\tdest?: string;\n\torg?: string;\n\thook?: boolean;\n\t/**\n\t * Declared for `--help` and read through `optsWithGlobals()`, never off\n\t * this object: Commander stores a flag both a parent and a subcommand\n\t * declare on the parent.\n\t */\n\tformat?: string;\n}\n\nexport function buildInstructionsCommand(): Command {\n\tconst instructions = new Command(\"instructions\").description(\n\t\t\"Keep a checkout current with a project's published coding instructions\",\n\t);\n\n\tinstructions\n\t\t.command(\"check\")\n\t\t.description(\n\t\t\t\"Report whether the local copy is behind the published one\",\n\t\t)\n\t\t.requiredOption(\"--project <id>\", \"Project ID\")\n\t\t.option(\"--dest <dir>\", \"Destination directory (default: cwd)\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\n\t\t\t\"--verify\",\n\t\t\t\"Also hash the local files against the lock and report any that drifted\",\n\t\t)\n\t\t.option(\n\t\t\t\"--hook\",\n\t\t\t\"Session-hook mode: plain text, never fails, never blocks a session\",\n\t\t)\n\t\t// No default: a default here would shadow the program-level --format,\n\t\t// which is where `FABRIC_FORMAT` enters.\n\t\t.option(\"--format <format>\", \"Output format: text|json\")\n\t\t.action(async function (\n\t\t\tthis: Command,\n\t\t\topts: CommonOptions & { verify?: boolean },\n\t\t) {\n\t\t\tawait run(opts, \"check\", () =>\n\t\t\t\trunCheck(opts, outputFormatFor(this)),\n\t\t\t);\n\t\t});\n\n\tinstructions\n\t\t.command(\"sync\")\n\t\t.description(\n\t\t\t\"Write the published coding instructions into the checkout\",\n\t\t)\n\t\t.requiredOption(\"--project <id>\", \"Project ID\")\n\t\t.option(\"--dest <dir>\", \"Destination directory (default: cwd)\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--dry-run\", \"Print the plan and write nothing\")\n\t\t.option(\n\t\t\t\"--hook\",\n\t\t\t\"Session-hook mode: plain text, never fails, never blocks a session\",\n\t\t)\n\t\t.option(\"--format <format>\", \"Output format: text|json\")\n\t\t.action(async function (\n\t\t\tthis: Command,\n\t\t\topts: CommonOptions & { dryRun?: boolean },\n\t\t) {\n\t\t\tawait run(opts, \"sync\", () => runSync(opts, outputFormatFor(this)));\n\t\t});\n\n\tinstructions\n\t\t.command(\"push\")\n\t\t.description(\n\t\t\t\"Propose this checkout's edits to the project's coding instructions, or publish them with --publish\",\n\t\t)\n\t\t.requiredOption(\"--project <id>\", \"Project ID\")\n\t\t.option(\"--dest <dir>\", \"Destination directory (default: cwd)\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\n\t\t\t\"--add <path>\",\n\t\t\t\"Also send a file the last sync did not write (repeatable)\",\n\t\t\tcollectAdded,\n\t\t\t[] as string[],\n\t\t)\n\t\t.option(\n\t\t\t\"--publish\",\n\t\t\t\"Publish the change as a new version instead of proposing it (needs a key with instructions:publish)\",\n\t\t)\n\t\t.option(\"--dry-run\", \"Print the change set and send nothing\")\n\t\t.option(\"--format <format>\", \"Output format: text|json\")\n\t\t.action(async function (\n\t\t\tthis: Command,\n\t\t\topts: CommonOptions & {\n\t\t\t\tadd?: string[];\n\t\t\t\tpublish?: boolean;\n\t\t\t\tdryRun?: boolean;\n\t\t\t},\n\t\t) {\n\t\t\t// Never hook mode: a session start does not push. Stated rather\n\t\t\t// than inherited, because `run`'s never-fail branch exists for\n\t\t\t// commands a hook runs and this is not one.\n\t\t\tawait run({ ...opts, hook: false }, \"push\", () =>\n\t\t\t\trunPush(opts, outputFormatFor(this)),\n\t\t\t);\n\t\t});\n\n\tinstructions\n\t\t.command(\"init\")\n\t\t.description(\n\t\t\t\"Write a SessionStart hook for a coding tool and take the first copy\",\n\t\t)\n\t\t.requiredOption(\"--project <id>\", \"Project ID\")\n\t\t.requiredOption(\n\t\t\t\"--tool <tool>\",\n\t\t\t\"Coding tool to configure: claude-code|codex\",\n\t\t)\n\t\t.option(\"--dest <dir>\", \"Destination directory (default: cwd)\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\n\t\t\t\"--apply\",\n\t\t\t\"Let the hook apply changes instead of only reporting them\",\n\t\t)\n\t\t.option(\"--format <format>\", \"Output format: text|json\")\n\t\t.action(async function (\n\t\t\tthis: Command,\n\t\t\topts: CommonOptions & { tool: string; apply?: boolean },\n\t\t) {\n\t\t\t// Never hook mode: `init` is run by a person, so its failures\n\t\t\t// are real failures with real exit codes.\n\t\t\tawait run({ ...opts, hook: false }, \"init\", () =>\n\t\t\t\trunInit(opts, outputFormatFor(this)),\n\t\t\t);\n\t\t});\n\n\treturn instructions;\n}\n\n// ---------------------------------------------------------------------------\n// The never-fail boundary\n// ---------------------------------------------------------------------------\n\n/**\n * One place where every failure is turned into either an exit code or, under\n * `--hook`, a single line on stderr and a zero exit.\n *\n * \"Every\" is literal: network, auth, HTTP, timeout, a bad lock file, a\n * refused path, a retired context default. Nothing inside may call\n * `process.exit` itself — `printError` does, and `process.exit` cannot be\n * caught here, which is why these commands build their own client rather than\n * reaching for the exiting helpers the other commands use, and why they read\n * no stored context at all.\n */\nasync function run(\n\topts: { hook?: boolean },\n\tverb: string,\n\tbody: () => Promise<void>,\n): Promise<void> {\n\ttry {\n\t\tif (opts.hook) {\n\t\t\t// The deadline's signal is published for the bundle download\n\t\t\t// (`activeDeadline`) and withdrawn the moment the race settles,\n\t\t\t// whichever side won it.\n\t\t\tawait withDeadline(HOOK_DEADLINE_MS, (signal) => {\n\t\t\t\tactiveDeadline = signal;\n\t\t\t\treturn body();\n\t\t\t}).finally(() => {\n\t\t\t\tactiveDeadline = undefined;\n\t\t\t});\n\t\t} else {\n\t\t\tawait body();\n\t\t}\n\t} catch (error) {\n\t\tconst message = describeError(error);\n\t\tif (opts.hook) {\n\t\t\tprocess.stderr.write(\n\t\t\t\t`fabric: coding instructions ${verb} skipped: ${message}\\n`,\n\t\t\t);\n\t\t\tprocess.exit(0);\n\t\t}\n\t\tprocess.stderr.write(`✗ ${message}\\n`);\n\t\tprocess.exit(error instanceof CliFailure ? error.exitCode : 1);\n\t}\n}\n\n/**\n * The deadline signal in force, if any, so the bundle download can be\n * cancelled by the same clock that bounds the command. Module state rather\n * than a threaded parameter because every command body is single-shot within\n * one process.\n */\nlet activeDeadline: AbortSignal | undefined;\n\n// ---------------------------------------------------------------------------\n// Shared steps\n// ---------------------------------------------------------------------------\n\nfunction destinationOf(opts: { dest?: string }): string {\n\treturn path.resolve(opts.dest ?? process.cwd());\n}\n\n/**\n * A client that throws instead of exiting, and that never retries in hook\n * mode.\n *\n * `getClient` calls `printError`, which exits with code 3 — correct for every\n * other command and fatal to the `--hook` contract, which must never exit\n * non-zero for any reason.\n */\nfunction instructionsClient(\n\topts: { hook?: boolean },\n\ttimeoutMs: number,\n\t{ neverRetry = false }: { neverRetry?: boolean } = {},\n): FabricClient {\n\tif (!getApiKey()) {\n\t\tthrow new CliFailure(\n\t\t\t\"Not authenticated. Run: fabric auth login --key <api-key>\",\n\t\t\t3,\n\t\t);\n\t}\n\t// `withoutContext()`: the SDK constructor adopts `FABRIC_ORG` /\n\t// `FABRIC_PERSONAL` and injects them into every URL that does not name a\n\t// context. On a project-authoritative surface that ambient default is not\n\t// a default, it is a contradiction waiting to be refused — see\n\t// `orgSlugFor`.\n\treturn getClient(\n\t\topts.hook\n\t\t\t? {\n\t\t\t\t\t// Hook mode has ONE absolute deadline covering every\n\t\t\t\t\t// call it makes, so it cannot spend it on retries: a\n\t\t\t\t\t// session that will not start is worse than instructions\n\t\t\t\t\t// one version stale.\n\t\t\t\t\ttimeoutMs: Math.min(timeoutMs, HOOK_DEADLINE_MS),\n\t\t\t\t\tretry: { maxRetries: 0 },\n\t\t\t\t}\n\t\t\t: neverRetry\n\t\t\t\t? { timeoutMs, retry: { maxRetries: 0 } }\n\t\t\t\t: { timeoutMs },\n\t).withoutContext();\n}\n\n/**\n * A separate client for `createDownloadUrl`, because that one call is not a\n * manifest read.\n *\n * It gets the BUNDLE budget. Publishing a version pre-builds its archive, so\n * this is normally sub-second — but when the archive is not there the server\n * builds it inside this request, which on a large tree runs well past the\n * manifest timeout. Sharing the manifest client meant a sync of a brand-new\n * version failed with \"Request timed out after 15000ms\".\n *\n * `neverRetry: true` is belt-and-suspenders here, not load-bearing: the SDK's\n * `createDownloadUrl` itself now sends `{ maxRetries: 0 }` on every call\n * (`packages/sdk/src/resources/instructions.ts`), because a retry of this\n * route does not wait for the build already running on the server — it starts\n * a second, and then a third, of the same archive. Kept here so this client\n * stays never-retry even if `createDownloadUrl` is ever swapped for a call\n * that does not make that guarantee itself.\n */\nfunction downloadUrlClient(opts: { hook?: boolean }): FabricClient {\n\treturn instructionsClient(\n\t\topts,\n\t\topts.hook ? HOOK_DEADLINE_MS : BUNDLE_TIMEOUT_MS,\n\t\t{ neverRetry: true },\n\t);\n}\n\n/**\n * The org slug to send: the one on the command line, or none at all.\n *\n * These commands are PROJECT-AUTHORITATIVE — the project decides which\n * organization it is in, and the route resolves that from the project itself.\n * Sending a stored default context (or `FABRIC_ORG`) turned that resolution\n * into a contradiction for anyone whose default is not the project's host\n * organization, and the clearest case is the one the route exists to support:\n * an invited guest, whose own default organization is never the one hosting a\n * project they were invited to. Their request carried `?org=<their own org>`,\n * the route compared it with the project's, and refused.\n *\n * So the ambient default is not consulted here and the client is built\n * without one. `--org` remains available for the caller who wants the request\n * bound explicitly; an explicit slug that disagrees with the project is still\n * a 404, which is the point of passing it.\n */\nfunction orgSlugFor(opts: CommonOptions): string | undefined {\n\treturn opts.org;\n}\n\nasync function fetchPublished(\n\tclient: FabricClient,\n\topts: CommonOptions,\n\tsinceDigest?: string,\n): Promise<PublishedInstructions> {\n\tconst org = orgSlugFor(opts);\n\tlet published: PublishedInstructions;\n\ttry {\n\t\tpublished = await client.instructions.getPublished(opts.project, {\n\t\t\torg,\n\t\t\tsinceDigest,\n\t\t});\n\t} catch (error) {\n\t\tthrow asCliFailure(error);\n\t}\n\tassertHookMayAct(opts, published);\n\treturn published;\n}\n\n/**\n * A hook may not act on a project whose instructions come from git.\n *\n * Asserted on EVERY response rather than on the first one, because a command\n * can make two calls: a delta answer, and then — when the local tree has\n * drifted — a full refetch. Checking only the first meant a project switched\n * to `REPOSITORY` between the two was planned, downloaded and applied by a\n * hook, which is the second writer `init` refuses to create.\n *\n * `init` refuses such a project outright; a person running `sync` or `check`\n * by hand is unaffected, because for someone without access to that\n * repository a download is the only way to read the instructions at all.\n */\nfunction assertHookMayAct(\n\topts: { hook?: boolean },\n\tpublished: PublishedInstructions,\n): void {\n\tif (opts.hook && published.sourceOfTruth === \"REPOSITORY\") {\n\t\tthrow new CliFailure(\n\t\t\t\"this project's instructions now come from a git repository; run `fabric instructions init` again or remove the hook\",\n\t\t\t4,\n\t\t);\n\t}\n}\n\n/**\n * The lock, refused when it belongs to a different project.\n *\n * A lock is a per-destination file and a destination holds one project's\n * tree. `sync --project B` in a directory synced from project A would\n * otherwise send A's digest, receive B's manifest, and then use A's ledger to\n * decide what to delete — classifying every A-only file as \"the sync wrote\n * this, remove it\". Equal digests across the two could even report \"up to\n * date\" for a tree that holds the wrong project's instructions entirely.\n */\nasync function readLockForProject(\n\tdestination: string,\n\tprojectId: string,\n): Promise<InstructionsLock | null> {\n\tconst lock = await readLock(destination);\n\tif (lock !== null && lock.projectId !== projectId) {\n\t\tthrow new CliFailure(\n\t\t\t`${lockPath(destination)} belongs to project ${lock.projectId}, not ${projectId}. Use a different --dest, or remove that lock if this directory should now follow ${projectId}.`,\n\t\t\t7,\n\t\t);\n\t}\n\treturn lock;\n}\n\nfunction line(text: string): void {\n\tprocess.stdout.write(`${text}\\n`);\n}\n\nfunction listPaths(label: string, paths: string[]): void {\n\tif (paths.length === 0) {\n\t\treturn;\n\t}\n\tline(` ${label}:`);\n\tfor (const p of paths) {\n\t\tline(` ${p}`);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// check\n// ---------------------------------------------------------------------------\n\nasync function runCheck(\n\topts: CommonOptions & { verify?: boolean },\n\tformat: OutputFormat,\n): Promise<void> {\n\tconst destination = destinationOf(opts);\n\t// Canonical, but NOT created: `check` is informational and must not make a\n\t// directory as a side effect. Every guarded read resolves against this,\n\t// and a literal path would refuse legitimately — `/tmp` is a symlink on\n\t// macOS, so the string a user passes and the directory they mean differ.\n\tconst root = await resolveExistingRoot(destination);\n\tconst lock = await readLockForProject(destination, opts.project);\n\tconst client = instructionsClient(opts, CHECK_TIMEOUT_MS);\n\tconst published = await fetchPublished(client, opts, lock?.digest);\n\n\t// Deliberately NOT validated against `assertValidManifest`: `check`\n\t// writes nothing, so a skewed manifest here can only produce a less\n\t// useful report, and refusing would make the informational command the\n\t// fragile one. `sync` validates before it can act on it.\n\n\t// Off by default, and that is the trade rather than an oversight: this is\n\t// the command a session start runs, one request and no local reads. With\n\t// `--verify` it also hashes every file the lock names, which is what\n\t// answers \"is my checkout still what was published\" as opposed to \"has\n\t// the published version moved\". `sync` always does this.\n\tconst drifted =\n\t\topts.verify && lock !== null ? await verifyLedger({ root, lock }) : [];\n\n\tif (format === \"json\") {\n\t\tprintOutput(\n\t\t\t{\n\t\t\t\tprojectId: opts.project,\n\t\t\t\tdestination,\n\t\t\t\tsynced: lock !== null,\n\t\t\t\tlocalDigest: lock?.digest ?? null,\n\t\t\t\tverified: Boolean(opts.verify),\n\t\t\t\tdrifted,\n\t\t\t\t...published,\n\t\t\t},\n\t\t\t{ format: \"json\" },\n\t\t);\n\t\treturn;\n\t}\n\n\treportPublishedState(opts, destination, lock, published);\n\n\t// The common tail. Every text-mode branch returns through here, because\n\t// `--verify` promises to report local drift and three of those branches\n\t// used to return before saying a word about it.\n\tif (opts.verify) {\n\t\treportDrift(opts, destination, drifted);\n\t}\n}\n\n/** What the server said about the published snapshot, in text. */\nfunction reportPublishedState(\n\topts: CommonOptions,\n\tdestination: string,\n\tlock: InstructionsLock | null,\n\tpublished: PublishedInstructions,\n): void {\n\tif (!published.published) {\n\t\tline(\"This project has no published coding instructions yet.\");\n\t\treturn;\n\t}\n\n\tconst version = published.snapshot?.version;\n\n\tif (!lock) {\n\t\tline(\n\t\t\t`Coding instructions have not been synced into ${destination} yet (published version ${version}, ${published.snapshot?.fileCount} files).`,\n\t\t);\n\t\tline(\n\t\t\t`Run \\`fabric instructions sync --project ${opts.project}\\` to take a copy.`,\n\t\t);\n\t\treturn;\n\t}\n\n\tif (published.unchanged) {\n\t\t// \"the published version has not moved\" — NOT \"your files are\n\t\t// correct\". Without `--verify` nothing local has been read at all, and\n\t\t// saying \"up to date\" invited exactly the wrong conclusion.\n\t\tline(`Published coding instructions unchanged (version ${version}).`);\n\t\treturn;\n\t}\n\n\tif (published.changes === null || published.changes === undefined) {\n\t\tline(\n\t\t\t`Coding instructions changed, and the version in ${destination} is not one the server still recognises, so what changed cannot be listed. A full sync is needed (published version ${version}).`,\n\t\t);\n\t\tline(\n\t\t\t`Run \\`fabric instructions sync --project ${opts.project}\\` to apply.`,\n\t\t);\n\t\treturn;\n\t}\n\n\tconst { added, changed, removed } = published.changes;\n\tline(\n\t\t`Coding instructions updated: ${added.length} added, ${changed.length} changed, ${removed.length} removed (version ${version}).`,\n\t);\n\tlistPaths(\"added\", added);\n\tlistPaths(\"changed\", changed);\n\tlistPaths(\"removed\", removed);\n\tline(\n\t\t`Run \\`fabric instructions sync --project ${opts.project}\\` to apply.`,\n\t);\n}\n\n/** What `--verify` found, in the two places the report can end. */\nfunction reportDrift(\n\topts: CommonOptions,\n\tdestination: string,\n\tdrifted: string[],\n): void {\n\tif (drifted.length === 0) {\n\t\tline(`Every file in ${destination} matches the lock.`);\n\t\treturn;\n\t}\n\tline(`${drifted.length} local file(s) no longer match the lock:`);\n\tlistPaths(\"drifted\", drifted);\n\tline(\n\t\t`Run \\`fabric instructions sync --project ${opts.project}\\` to put them back.`,\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// sync\n// ---------------------------------------------------------------------------\n\nasync function runSync(\n\topts: CommonOptions & { dryRun?: boolean },\n\tformat: OutputFormat,\n): Promise<void> {\n\tconst result = await syncOnce(opts);\n\tif (format === \"json\") {\n\t\tprintOutput(result, { format: \"json\" });\n\t\treturn;\n\t}\n\treportSync(result, opts);\n}\n\ninterface SyncOutcome {\n\tprojectId: string;\n\tdestination: string;\n\tpublished: boolean;\n\tunchanged: boolean;\n\tdryRun: boolean;\n\tversion: number | null;\n\tdigest: string | null;\n\tadded: string[];\n\tupdated: string[];\n\treplaced: string[];\n\tremoved: string[];\n\tkeptModified: string[];\n\t/**\n\t * Paths the lock still names under an old spelling that the manifest now\n\t * spells differently. Reported rather than removed: on a case-insensitive\n\t * filesystem they ARE the file the sync just wrote.\n\t */\n\tkeptRenamed: string[];\n\t/**\n\t * Paths the lock claimed that the working tree no longer matched, when the\n\t * published snapshot itself had not moved. Non-empty means this run\n\t * repaired local drift rather than applying a new version.\n\t */\n\tdrifted: string[];\n\tverified: number;\n\tlockPath: string;\n}\n\nfunction emptyOutcome(\n\topts: CommonOptions & { dryRun?: boolean },\n\tdestination: string,\n): SyncOutcome {\n\treturn {\n\t\tprojectId: opts.project,\n\t\tdestination,\n\t\tpublished: true,\n\t\tunchanged: false,\n\t\tdryRun: Boolean(opts.dryRun),\n\t\tversion: null,\n\t\tdigest: null,\n\t\tadded: [],\n\t\tupdated: [],\n\t\treplaced: [],\n\t\tremoved: [],\n\t\tkeptModified: [],\n\t\tkeptRenamed: [],\n\t\tdrifted: [],\n\t\tverified: 0,\n\t\tlockPath: lockPath(destination),\n\t};\n}\n\nasync function syncOnce(\n\topts: CommonOptions & { dryRun?: boolean; rejectRepository?: boolean },\n): Promise<SyncOutcome> {\n\t// Canonical from here on: every write resolves against this, so a\n\t// symlinked `--dest` (or `/tmp` on macOS) is decided once rather than at\n\t// each write.\n\tconst root = await resolveDestinationRoot(destinationOf(opts));\n\tconst outcome = emptyOutcome(opts, root);\n\n\tconst lock = await readLockForProject(root, opts.project);\n\tconst client = instructionsClient(opts, SYNC_TIMEOUT_MS);\n\tlet published = await fetchPublished(client, opts, lock?.digest);\n\tassertInitSyncMayAct(opts, published);\n\n\t// Hook mode rejects repository-backed instructions in `fetchPublished`;\n\t// init's first sync performs the same check above so its drift refetch does\n\t// not trust only the first response.\n\n\tif (!published.published || !published.snapshot) {\n\t\t// A real failure for a person who asked for a copy; the `--hook`\n\t\t// boundary turns it into one quiet line for a session start.\n\t\tthrow new CliFailure(\n\t\t\t\"This project has no published coding instructions yet.\",\n\t\t\t4,\n\t\t);\n\t}\n\n\toutcome.version = published.snapshot.version;\n\toutcome.digest = published.snapshot.digest;\n\n\tif (published.unchanged) {\n\t\t// \"Unchanged\" is the SERVER's answer about the SNAPSHOT, and it says\n\t\t// nothing about the checkout. Accepting it as \"nothing to do\" let an\n\t\t// edited, deleted or chmod-ed instruction file stay that way until\n\t\t// some later publication happened to move the digest — so a tampered\n\t\t// tree reported success indefinitely. The ledger is the local half of\n\t\t// the question, and hashing it is the price of a command that applies\n\t\t// things.\n\t\tconst drifted = lock === null ? [] : await verifyLedger({ root, lock });\n\t\tif (drifted.length === 0) {\n\t\t\toutcome.unchanged = true;\n\t\t\treturn outcome;\n\t\t}\n\n\t\toutcome.drifted = drifted;\n\t\t// The first call answered with a delta and therefore carries no\n\t\t// manifest. Ask again without a base digest: the plan needs the whole\n\t\t// published list to put the tree back.\n\t\tpublished = await fetchPublished(client, opts);\n\t\tassertInitSyncMayAct(opts, published);\n\t\tif (!published.published || !published.snapshot) {\n\t\t\tthrow new CliFailure(\n\t\t\t\t\"This project has no published coding instructions yet.\",\n\t\t\t\t4,\n\t\t\t);\n\t\t}\n\t\toutcome.version = published.snapshot.version;\n\t\toutcome.digest = published.snapshot.digest;\n\t}\n\n\t// An absent manifest is a refusal, never an empty one. `[]` means\n\t// \"delete everything the lock names\", so a version-skewed or truncated\n\t// response was one step from emptying the tree and writing a ledger that\n\t// agreed with it.\n\tconst manifest = assertValidManifest({\n\t\tmanifest: published.manifest,\n\t\tsnapshot: published.snapshot,\n\t});\n\n\tconst plan = await computeSyncPlan({ destination: root, manifest, lock });\n\tfillPlanPaths(outcome, plan);\n\n\tif (opts.dryRun) {\n\t\t// The plan is computable from the manifest alone, so a dry run\n\t\t// downloads nothing at all.\n\t\treturn outcome;\n\t}\n\n\tlet contents = new Map<string, Uint8Array>();\n\tif (plan.writes.length > 0) {\n\t\tconst org = orgSlugFor(opts);\n\t\tlet download: { url: string };\n\t\ttry {\n\t\t\tdownload = await downloadUrlClient(\n\t\t\t\topts,\n\t\t\t).instructions.createDownloadUrl(opts.project, { org });\n\t\t} catch (error) {\n\t\t\tthrow asCliFailure(error);\n\t\t}\n\t\tconst sizes = new Map(\n\t\t\tmanifest.map((entry) => [entry.path, entry.size] as const),\n\t\t);\n\t\tconst archive = await fetchBundle(download.url, {\n\t\t\ttimeoutMs: opts.hook ? HOOK_DEADLINE_MS : BUNDLE_TIMEOUT_MS,\n\t\t\t// Bounded by what this manifest says it holds, not by what the\n\t\t\t// response claims. The manifest has already been checked against\n\t\t\t// the published snapshot limits, so this is a number the client\n\t\t\t// decided.\n\t\t\tmaxBytes: maxArchiveBytes(manifest),\n\t\t\t// In hook mode the same clock that bounds the command bounds the\n\t\t\t// download, rather than a second independent budget after it.\n\t\t\tsignal: activeDeadline,\n\t\t});\n\t\tcontents = extractBundle(\n\t\t\tarchive,\n\t\t\tplan.writes.map((entry) => ({\n\t\t\t\tpath: entry.path,\n\t\t\t\tsize: sizes.get(entry.path) ?? -1,\n\t\t\t})),\n\t\t);\n\t}\n\n\tconst applied = await applyPlan({ root, plan, contents });\n\t// What actually happened, not what was planned: a delete whose file was\n\t// edited between planning and the unlink is reported as kept, because that\n\t// is what it is.\n\toutcome.removed = applied.deleted;\n\toutcome.keptModified = [\n\t\t...outcome.keptModified,\n\t\t...applied.keptModified,\n\t].sort();\n\n\t// Last, and only now: a lock written before the files would claim\n\t// ownership of paths that are not there, and the next run would delete\n\t// whatever the developer had in their place.\n\tconst lockToWrite: InstructionsLock = nextLock({\n\t\tprojectId: opts.project,\n\t\tsnapshot: {\n\t\t\tid: published.snapshot.id,\n\t\t\tversion: published.snapshot.version,\n\t\t\tdigest: published.snapshot.digest,\n\t\t},\n\t\tmanifest,\n\t});\n\tawait writeLock(root, lockToWrite);\n\n\treturn outcome;\n}\n\n/**\n * `init` uses a manual sync for its first copy, but it must still reject a\n * project that switches to repository-backed instructions during that sync.\n * Keeping this distinct from hook mode preserves manual `sync` behavior.\n */\nfunction assertInitSyncMayAct(\n\topts: { rejectRepository?: boolean },\n\tpublished: PublishedInstructions,\n): void {\n\tif (opts.rejectRepository && published.sourceOfTruth === \"REPOSITORY\") {\n\t\tthrow new CliFailure(\n\t\t\t\"This project's coding instructions come from its repository, so they arrive with `git pull`. A session hook would fight it; nothing was written.\",\n\t\t\t7,\n\t\t);\n\t}\n}\n\nfunction fillPlanPaths(outcome: SyncOutcome, plan: SyncPlan): void {\n\toutcome.added = plan.entries\n\t\t.filter((entry) => entry.action === \"added\")\n\t\t.map((entry) => entry.path);\n\toutcome.updated = plan.entries\n\t\t.filter((entry) => entry.action === \"updated\")\n\t\t.map((entry) => entry.path);\n\toutcome.replaced = plan.entries\n\t\t.filter((entry) => entry.action === \"replaced\")\n\t\t.map((entry) => entry.path);\n\toutcome.removed = plan.deletes.map((entry) => entry.path);\n\toutcome.keptModified = plan.keptModified.map((entry) => entry.path);\n\toutcome.keptRenamed = plan.keptRenamed.map((entry) => entry.path);\n\toutcome.verified = plan.verified.length;\n}\n\nfunction reportSync(\n\toutcome: SyncOutcome,\n\topts: CommonOptions & { dryRun?: boolean },\n): void {\n\tif (outcome.unchanged) {\n\t\tline(\n\t\t\t`Coding instructions are up to date (version ${outcome.version}).`,\n\t\t);\n\t\treturn;\n\t}\n\n\tconst total =\n\t\toutcome.added.length +\n\t\toutcome.updated.length +\n\t\toutcome.replaced.length +\n\t\toutcome.removed.length;\n\tif (outcome.drifted.length > 0) {\n\t\tline(\n\t\t\t`Coding instructions version ${outcome.version} is still the published one, but ${outcome.drifted.length} local file(s) no longer match it:`,\n\t\t);\n\t\tlistPaths(\"drifted\", outcome.drifted);\n\t}\n\n\tconst prefix = opts.dryRun ? \"Would apply\" : \"Applied\";\n\tline(\n\t\t`${prefix} coding instructions version ${outcome.version}: ${outcome.added.length} added, ${outcome.updated.length} updated, ${outcome.replaced.length} replaced, ${outcome.removed.length} removed (${outcome.verified} already current).`,\n\t);\n\tlistPaths(\"added\", outcome.added);\n\tlistPaths(\"updated\", outcome.updated);\n\tlistPaths(\"replaced local edits\", outcome.replaced);\n\tlistPaths(\"removed\", outcome.removed);\n\tlistPaths(\"kept, modified locally\", outcome.keptModified);\n\tlistPaths(\"kept, renamed in the published snapshot\", outcome.keptRenamed);\n\tif (!opts.dryRun) {\n\t\tline(`Lock: ${outcome.lockPath}`);\n\t}\n\tif (\n\t\ttotal === 0 &&\n\t\toutcome.keptModified.length === 0 &&\n\t\toutcome.keptRenamed.length === 0\n\t) {\n\t\tline(`Everything in ${outcome.destination} already matched.`);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// push\n// ---------------------------------------------------------------------------\n\ninterface PushOutcome {\n\tprojectId: string;\n\tdestination: string;\n\tdryRun: boolean;\n\t/** `--publish`: what this push ASKED for, known before anything is sent. */\n\tpublish: boolean;\n\t/** The snapshot the change set was stated against — the lock's. */\n\tbaseSnapshotId: string;\n\tbaseVersion: number;\n\tput: string[];\n\tdeleted: string[];\n\tunchanged: number;\n\t/** Null on a dry run; otherwise what the server made of it. */\n\tsnapshotId: string | null;\n\tversion: number | null;\n\tproposalStatus: string | null;\n\tstatus: string | null;\n\t/**\n\t * Whether this version has been observed published at least once. Null on\n\t * a dry run. `status === \"READY\"` does NOT imply this — see the SDK's\n\t * `SubmittedInstructionChange.published` doc — so `pushVerdict` reads this\n\t * field rather than inferring publication from `status`. `false` means\n\t * \"not yet confirmed\", never \"refused\": a publish this call started can\n\t * still land after the command has already returned.\n\t */\n\tpublished: boolean | null;\n}\n\n/**\n * Suggest the checkout's edits back to the project, or publish them.\n *\n * Without `--publish` it opens a PROPOSAL, which is what the key the Connect\n * dialog mints can do: that key carries `instructions:write`, a scope offered\n * to read-only roles and described as review-gated.\n *\n * `--publish` is a DIFFERENT authority, not a mode of the same one. It calls a\n * different route, gated on `instructions:publish` — a scope the Connect\n * dialog never mints, that a read-only role cannot be granted, and that has to\n * be put on a key deliberately in the organization's API-key settings. The\n * server then re-checks, on that call, that the key's creator still holds the\n * permission the Coding Instructions tab requires to publish. Both halves are\n * needed: neither the flag nor the scope alone publishes anything.\n *\n * Everything else is identical in both modes — the same local diff, the same\n * lock rules, the same `PULL_FIRST` refusal for a stale base — because a\n * publish is a fast-forward on the published pointer just as a proposal is a\n * claim on it.\n *\n * The diff is computed against `.fabric/instructions.lock` — the snapshot the\n * last sync applied — and that snapshot id is sent as the base. A push whose\n * base is no longer the published version is REFUSED rather than rebased: the\n * spec's `PULL_FIRST` rule (§6.12), and the reason there is no server-side\n * merge in any version.\n *\n * The published manifest is fetched FIRST, and it decides two things before a\n * file is opened: whether the lock still names the published version, and\n * whether the lock's ledger is that version. The lock is a plain JSON file in\n * the checkout, so anything that can write to the working tree can add a path\n * to it — and a command that read its ledger on trust would read and upload\n * whatever was added. See `computePushPlan`.\n *\n * The lock is NOT rewritten, on any outcome, `--publish` included. A proposal\n * changes nothing about what is published, so a lock claiming otherwise would\n * make the next `sync` believe this checkout already held a version nobody has\n * approved. A publish changes it only once the server's validation run passes,\n * which is after this command has returned — and what it publishes is the\n * SERVER's manifest, inherited files and all, not the local tree. Writing a\n * lock for a version that may never exist, from a file list this side cannot\n * compute, would be a guess; `fabric instructions sync` is how the checkout\n * catches up, and it is what the command says to run.\n */\nasync function runPush(\n\topts: CommonOptions & {\n\t\tadd?: string[];\n\t\tpublish?: boolean;\n\t\tdryRun?: boolean;\n\t},\n\tformat: OutputFormat,\n): Promise<void> {\n\t// Canonical but NOT created: push reads the tree, and a command that makes\n\t// a directory in order to discover it is empty is doing the wrong thing.\n\tconst destination = destinationOf(opts);\n\tconst root = await resolveExistingRoot(destination);\n\tconst lock = await readLockForProject(root, opts.project);\n\tif (lock === null) {\n\t\tthrow new CliFailure(\n\t\t\t`No coding-instructions lock in ${destination}. Run \\`fabric instructions sync --project ${opts.project}\\` first: a push is a diff against the version that was last applied here, and without that ledger there is nothing to diff against.`,\n\t\t\t7,\n\t\t);\n\t}\n\n\t// The SDK's ordinary retry policy. Retries used to be off here: the change\n\t// route wrote a snapshot row per POST, so a push whose response was lost\n\t// opened a second proposal for one edit. The route now recognises a change\n\t// set it has already admitted and answers with the proposal it opened, so\n\t// a retry repairs a dropped response instead of duplicating it.\n\tconst client = instructionsClient(\n\t\t{ ...opts, hook: false },\n\t\tPUSH_TIMEOUT_MS,\n\t);\n\n\t// BEFORE any file is read. Two questions, both answered by this one call:\n\t// is the lock still the published version, and is its ledger actually\n\t// that version's manifest.\n\tconst published = await fetchPublished(client, opts);\n\tif (!published.published || !published.snapshot) {\n\t\tthrow new CliFailure(\n\t\t\t\"this project has no published coding instructions to change yet; the first version is uploaded from the Coding Instructions tab\",\n\t\t\t4,\n\t\t);\n\t}\n\tif (published.snapshot.id !== lock.snapshotId) {\n\t\t// Exactly what the server would answer, decided locally so nothing is\n\t\t// read or sent first.\n\t\tthrow new CliFailure(\n\t\t\t\"published instructions moved past your last sync; run `fabric instructions sync` then push again\",\n\t\t\t7,\n\t\t);\n\t}\n\n\tconst plan = await computePushPlan({\n\t\troot,\n\t\tlock,\n\t\tmanifest: published.manifest ?? [],\n\t\tadded: opts.add,\n\t});\n\n\tif (plan.changes.length === 0) {\n\t\tthrow new CliFailure(\n\t\t\t`Nothing to push: every file the last sync wrote still matches version ${lock.snapshotVersion}. Add a new file with --add <path> if you meant to suggest one.`,\n\t\t\t7,\n\t\t);\n\t}\n\tif (plan.changes.length > MAX_PUSH_CHANGES) {\n\t\tthrow new CliFailure(\n\t\t\t`Too many changes to push (${plan.changes.length} > ${MAX_PUSH_CHANGES}). A change set this large is a replacement rather than an edit — upload the folder from the project's Coding Instructions tab, which is also the only path that re-reads the project's exclusion rules.`,\n\t\t\t7,\n\t\t);\n\t}\n\n\tconst outcome: PushOutcome = {\n\t\tprojectId: opts.project,\n\t\tdestination: root,\n\t\tdryRun: Boolean(opts.dryRun),\n\t\tpublish: Boolean(opts.publish),\n\t\tbaseSnapshotId: lock.snapshotId,\n\t\tbaseVersion: lock.snapshotVersion,\n\t\tput: plan.entries\n\t\t\t.filter((entry) => entry.action === \"put\")\n\t\t\t.map((entry) => entry.path),\n\t\tdeleted: plan.entries\n\t\t\t.filter((entry) => entry.action === \"delete\")\n\t\t\t.map((entry) => entry.path),\n\t\tunchanged: plan.unchanged.length,\n\t\tsnapshotId: null,\n\t\tversion: null,\n\t\tproposalStatus: null,\n\t\tstatus: null,\n\t\tpublished: null,\n\t};\n\n\tif (!opts.dryRun) {\n\t\ttry {\n\t\t\t// Two methods, not one method with a flag: they are two routes\n\t\t\t// behind two scopes, and choosing between them here is what makes\n\t\t\t// a key that cannot publish fail with a scope refusal rather than\n\t\t\t// quietly proposing instead.\n\t\t\tconst submitted = opts.publish\n\t\t\t\t? await client.instructions.publishChange(\n\t\t\t\t\t\topts.project,\n\t\t\t\t\t\tlock.snapshotId,\n\t\t\t\t\t\tplan.changes,\n\t\t\t\t\t\t{ org: orgSlugFor(opts) },\n\t\t\t\t\t)\n\t\t\t\t: await client.instructions.submitChange(\n\t\t\t\t\t\topts.project,\n\t\t\t\t\t\tlock.snapshotId,\n\t\t\t\t\t\tplan.changes,\n\t\t\t\t\t\t{ org: orgSlugFor(opts) },\n\t\t\t\t\t);\n\t\t\toutcome.snapshotId = submitted.snapshotId;\n\t\t\toutcome.version = submitted.version;\n\t\t\toutcome.proposalStatus = submitted.proposalStatus;\n\t\t\toutcome.status = submitted.status;\n\t\t\toutcome.published = submitted.published;\n\t\t} catch (error) {\n\t\t\tthrow asPushFailure(error);\n\t\t}\n\t}\n\n\tif (format === \"json\") {\n\t\tprintOutput(outcome, { format: \"json\" });\n\t\treturn;\n\t}\n\treportPush(outcome);\n}\n\n/**\n * The refusals a push has to say something useful about, by the reason code\n * the route sends (`packages/api/modules/v1/instructions.ts`).\n *\n * Everything else falls through to `asCliFailure`'s status mapping, which is\n * already right for auth, permission and rate limits.\n */\nfunction asPushFailure(error: unknown): CliFailure {\n\tconst code = (error as { code?: string }).code;\n\tconst message = error instanceof Error ? error.message : String(error);\n\tswitch (code) {\n\t\tcase \"PULL_FIRST\":\n\t\t\treturn new CliFailure(\n\t\t\t\t\"published instructions moved past your last sync; run `fabric instructions sync` then push again\",\n\t\t\t\t7,\n\t\t\t);\n\t\tcase \"REPOSITORY_SOURCE_OF_TRUTH\":\n\t\t\treturn new CliFailure(\n\t\t\t\t\"this project's coding instructions come from its repository, so they are changed there and mirrored into Fabric — commit and push to the repository instead; nothing was sent\",\n\t\t\t\t7,\n\t\t\t);\n\t\tcase \"NOTHING_PUBLISHED\":\n\t\t\treturn new CliFailure(\n\t\t\t\t\"this project has no published coding instructions to change yet; the first version is uploaded from the Coding Instructions tab\",\n\t\t\t\t4,\n\t\t\t);\n\t\tcase \"PROPOSAL_PROPOSER_LIMIT\":\n\t\tcase \"PROPOSAL_PROJECT_LIMIT\":\n\t\t\treturn new CliFailure(`${message} Nothing was sent.`, 7);\n\t\tdefault:\n\t\t\treturn asCliFailure(error);\n\t}\n}\n\n/**\n * The one sentence a completed push ends on.\n *\n * A push that repeats an earlier one is answered with the proposal that one\n * opened, so this has to read every state that proposal can be in — not just\n * the fresh-proposal case. The rule each branch obeys: NEVER advise an action\n * the server's content dedup will swallow. A proposal still PENDING is exactly\n * what the next push would match, so those branches describe the state or name\n * the one thing that changes it, and \"push again\" appears only once the\n * proposal has stopped being PENDING.\n */\nfunction pushVerdict(outcome: PushOutcome): string {\n\t// A publish has no review state to read, so none of the proposal\n\t// branches below apply to it; what it has instead is a validation run\n\t// that has only just started. Saying \"published version 9\" here would be\n\t// a claim this command cannot make — the verify and secret-scan gate runs\n\t// after the response, and a change set that fails it publishes nothing.\n\t//\n\t// Branched on `outcome.published`, never on `outcome.status === \"READY\"`\n\t// alone: the auto-publish runs as its own step, normally AFTER this\n\t// command has already gotten its response — `READY` says the checks\n\t// passed, `published` is the server's own observation of whether the\n\t// publish had already happened by the time it answered. This command\n\t// classifies nothing further: it cannot know, at response time, whether\n\t// an unpublished READY version is still catching up or has genuinely lost\n\t// out to a concurrent edit — that is what the tab's history is for, and\n\t// this never guesses at it with words like \"superseded\" or \"moved\".\n\tif (outcome.publish) {\n\t\tif (outcome.published) {\n\t\t\treturn `Published version ${outcome.version}. Run \\`fabric instructions sync\\` to bring this checkout onto it.`;\n\t\t}\n\t\tif (outcome.status === \"FAILED\" || outcome.status === \"REJECTED\") {\n\t\t\treturn `Version ${outcome.version} did not pass its checks (${outcome.status}), so nothing was published; open the project's Coding Instructions tab to see why.`;\n\t\t}\n\t\tconst sent = `Sent as version ${outcome.version}. It publishes on its own once its checks pass (${outcome.status}) — then run \\`fabric instructions sync\\` to bring this checkout onto it.`;\n\t\t// READY gets one more sentence: the checks are done, so what remains\n\t\t// unknown is only whether the publish step has landed, and the tab is\n\t\t// where that is answered — not a guess printed here.\n\t\treturn outcome.status === \"READY\"\n\t\t\t? `${sent} It has passed its checks; its publication state is shown in the project's Coding Instructions tab.`\n\t\t\t: sent;\n\t}\n\n\t// The row is still receiving bytes: an earlier attempt at this same change\n\t// is mid-flight. No push closes it out at any age — the browser tab opens\n\t// proposals through the same query and keeps its upload capabilities for\n\t// an hour, so a row that looks stalled from here may be one somebody is\n\t// still filling. What does move it: its proposer can cancel it in the tab\n\t// (a RECEIVING proposal is cancellable), and the reaper closes an\n\t// abandoned one after six hours.\n\tif (\n\t\toutcome.proposalStatus === \"PENDING\" &&\n\t\toutcome.status === \"RECEIVING\"\n\t) {\n\t\treturn `An earlier attempt is still sending this change; if version ${outcome.version} stays unfinished, cancel it in the project's Coding Instructions tab, or leave it and it is closed out automatically after six hours.`;\n\t}\n\t// Its checks failed, and it stays PENDING — so the next push dedups\n\t// straight back onto it. The tab's \"Try again\" is the only thing that\n\t// moves it, which is why no push is offered here. Both of these branches\n\t// require PENDING: a row that vanished after the finalizer reports\n\t// `proposalStatus: null` beside the finalizer's last status, and telling\n\t// the user to retry or cancel a version that no longer exists would be\n\t// wrong — that case falls through to \"push again\", which is right.\n\tif (outcome.proposalStatus === \"PENDING\" && outcome.status === \"FAILED\") {\n\t\treturn `This proposal did not pass its checks; retry version ${outcome.version} from the project's Coding Instructions tab.`;\n\t}\n\tif (outcome.proposalStatus === \"PENDING\") {\n\t\t// Unreachable in practice — the gate closes a rejected proposal's\n\t\t// review state in the same transaction — but a PENDING row is one the\n\t\t// dedup matches, so the advice has to be the thing that clears it.\n\t\tif (outcome.status === \"REJECTED\") {\n\t\t\treturn `Version ${outcome.version} was rejected by its checks — cancel it in the project's Coding Instructions tab before proposing this change again.`;\n\t\t}\n\t\treturn `Proposed as version ${outcome.version}. It is pending review — nothing is published until somebody who can edit this project's coding instructions approves it in the Coding Instructions tab.`;\n\t}\n\tif (outcome.proposalStatus === \"APPROVED\") {\n\t\treturn `Version ${outcome.version} has already been approved and published — run \\`fabric instructions sync\\` to bring this checkout up to it.`;\n\t}\n\treturn `Version ${outcome.version} is no longer open for review (${outcome.proposalStatus ?? outcome.status}): an earlier attempt at this same change was closed out, so push again.`;\n}\n\nfunction reportPush(outcome: PushOutcome): void {\n\tconst prefix = outcome.dryRun ? \"Would send\" : \"Sent\";\n\tline(\n\t\t`${prefix} ${outcome.put.length} changed file(s) and ${outcome.deleted.length} deletion(s) against version ${outcome.baseVersion} (${outcome.unchanged} unchanged).`,\n\t);\n\tlistPaths(\"changed\", outcome.put);\n\tlistPaths(\"deleted\", outcome.deleted);\n\n\tif (outcome.dryRun) {\n\t\tline(\n\t\t\toutcome.publish\n\t\t\t\t? \"Nothing was sent. Without --dry-run this would create a new version that publishes on its own once its checks pass, with no review.\"\n\t\t\t\t: \"Nothing was sent. Without --dry-run this would open a proposal for review.\",\n\t\t);\n\t\treturn;\n\t}\n\n\tline(pushVerdict(outcome));\n\tline(\n\t\toutcome.publish\n\t\t\t? `Your lock was not changed: it still names version ${outcome.baseVersion}, which is what \\`fabric instructions sync\\` compares against.`\n\t\t\t: \"Your lock was not changed: it still names the published version, which is what `fabric instructions sync` compares against.\",\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// init\n// ---------------------------------------------------------------------------\n\nasync function runInit(\n\topts: CommonOptions & { tool: string; apply?: boolean },\n\tformat: OutputFormat,\n): Promise<void> {\n\tif (!isInstructionsHookTool(opts.tool)) {\n\t\tthrow new CliFailure(\n\t\t\t`Unsupported tool \"${opts.tool}\". Use --tool claude-code or --tool codex.`,\n\t\t\t2,\n\t\t);\n\t}\n\tconst tool = opts.tool;\n\n\tconst root = await resolveDestinationRoot(destinationOf(opts));\n\n\t// Two local preconditions, both answered before any network call: a lock\n\t// that belongs to another project, and a credential file that would end\n\t// up inside the checkout. Neither needs the server to decide, and making\n\t// a reader wait on a request to learn about them is backwards.\n\tawait readLockForProject(root, opts.project);\n\ttry {\n\t\tawait assertKeyStaysOutside(root, getConfigPath());\n\t} catch (error) {\n\t\tthrow new CliFailure(describeError(error), 7);\n\t}\n\n\tconst client = instructionsClient(opts, SYNC_TIMEOUT_MS);\n\tconst published = await fetchPublished(client, opts);\n\n\tif (published.sourceOfTruth === \"REPOSITORY\") {\n\t\t// A sync hook on a repository-backed project would fight `git pull`:\n\t\t// the files arrive through the repository, and two writers with no\n\t\t// merge between them is worse than one.\n\t\tthrow new CliFailure(\n\t\t\t\"This project's coding instructions come from its repository, so they arrive with `git pull`. A session hook would fight it; nothing was written.\",\n\t\t\t7,\n\t\t);\n\t}\n\n\tconst outcome = published.published\n\t\t? // A second manifest call, deliberately: the one above answered \"may\n\t\t\t// a hook be installed for this project at all\", and this one is the\n\t\t\t// sync's own. Do it before the hook write: a failed first copy must\n\t\t\t// not leave a new or updated hook behind.\n\t\t\tawait syncOnce({ ...opts, hook: false, rejectRepository: true })\n\t\t: null;\n\n\tconst command = buildHookCommand(\n\t\topts.project,\n\t\tBoolean(opts.apply),\n\t\topts.org,\n\t);\n\tconst merged = await mergeSessionStartHook({\n\t\troot,\n\t\tprojectId: opts.project,\n\t\tcommand,\n\t\ttool,\n\t});\n\n\tif (format === \"json\") {\n\t\tprintOutput(\n\t\t\t{\n\t\t\t\tprojectId: opts.project,\n\t\t\t\tdestination: root,\n\t\t\t\tsettingsPath: merged.settingsPath,\n\t\t\t\thookCommand: merged.command,\n\t\t\t\tcreatedSettingsFile: merged.createdFile,\n\t\t\t\treplacedHooks: merged.replacedCount,\n\t\t\t\tsync: outcome,\n\t\t\t},\n\t\t\t{ format: \"json\" },\n\t\t);\n\t\treturn;\n\t}\n\n\tline(\n\t\tmerged.replacedCount > 0\n\t\t\t? `Updated the SessionStart hook in ${merged.settingsPath}.`\n\t\t\t: `Added a SessionStart hook to ${merged.settingsPath}.`,\n\t);\n\tline(` ${command}`);\n\tline(\n\t\topts.apply\n\t\t\t? \" It applies changes at session start.\"\n\t\t\t: \" It only reports changes; add --apply to init to have it apply them.\",\n\t);\n\tif (tool === \"codex\") {\n\t\tline(\n\t\t\t\" Start Codex in this checkout, then use `/hooks` to review and trust the project hook.\",\n\t\t);\n\t}\n\n\tif (outcome === null) {\n\t\tline(\n\t\t\t\"This project has nothing published yet, so there is nothing to copy — the hook will pick it up once there is.\",\n\t\t);\n\t} else {\n\t\tline(\"\");\n\t\treportSync(outcome, opts);\n\t}\n\n\tline(\"\");\n\tline(\n\t\t`${hookPathFor(tool)} and ${LOCK_DIRECTORY}/ are local to this machine. If this repository does not ignore them already, add them to your own ignore rules — this command does not edit .gitignore.`,\n\t);\n}\n\nfunction isInstructionsHookTool(tool: string): tool is InstructionsHookTool {\n\treturn tool === \"claude-code\" || tool === \"codex\";\n}\n\nfunction hookPathFor(tool: InstructionsHookTool): string {\n\treturn tool === \"codex\"\n\t\t? CODEX_HOOKS_RELATIVE_PATH\n\t\t: CLAUDE_SETTINGS_RELATIVE_PATH;\n}\n","/**\n * Turning a plan into files, with two rules that decide the shape of\n * everything below.\n *\n * First: verify every byte before writing any byte. Each entry's sha256 is\n * checked against the manifest up front, so a corrupt or tampered archive\n * aborts with nothing written at all, rather than half a tree of good files\n * and one bad one. The caller then does not rewrite the lock, so the next run\n * plans from the last known-good state.\n *\n * Second: every write goes through `safe-write.ts` — the same writer the\n * lock and the Claude Code settings file use. Symlink refusal, canonical\n * containment, exclusive temp creation and the pre-rename recheck all live\n * there, so there is exactly one implementation of \"may this land here\".\n */\nimport { createHash } from \"node:crypto\";\nimport { chmod } from \"node:fs/promises\";\nimport { describeRejection } from \"./paths.js\";\nimport type { PlanEntry, SyncPlan } from \"./plan.js\";\nimport {\n\tassertWritableTarget,\n\tdeleteFileSafely,\n\tisAllowedMode,\n\tpermissionBits,\n\twriteFileSafely,\n} from \"./safe-write.js\";\n\nexport interface ApplyResult {\n\twritten: string[];\n\tdeleted: string[];\n\t/** Paths whose mode was corrected without rewriting their bytes. */\n\tremoded: string[];\n\t/**\n\t * Paths the plan meant to delete that no longer matched the hash it\n\t * decided on — someone edited them between planning and now, so they were\n\t * left where they are.\n\t */\n\tkeptModified: string[];\n}\n\nexport interface ApplyInput {\n\t/** An already-canonical destination from `resolveDestinationRoot`. */\n\troot: string;\n\tplan: SyncPlan;\n\t/** Extracted archive entries, keyed by the manifest path. */\n\tcontents: Map<string, Uint8Array>;\n}\n\nexport async function applyPlan(input: ApplyInput): Promise<ApplyResult> {\n\tconst { root, plan, contents } = input;\n\n\t// ---- Phase 1: prove the whole plan before touching the tree ----------\n\t//\n\t// EVERY path the plan names, including the ones it does not intend to\n\t// write. A `verified` entry is one whose local bytes already match, and a\n\t// symlink pointing at those bytes used to reach exactly that verdict: no\n\t// write, no check, and a lock written over a path that is not a file.\n\t// This runs before the platform and mode short-circuits further down for\n\t// the same reason — a check that only some plans reach is not a check.\n\tfor (const entry of [\n\t\t...plan.writes,\n\t\t...plan.verified,\n\t\t...plan.deletes,\n\t\t...plan.keptRenamed,\n\t]) {\n\t\tconst check = await assertWritableTarget(root, entry.path);\n\t\tif (!check.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection(check)}. Nothing was written.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tfor (const entry of plan.writes) {\n\t\tif (!isAllowedMode(entry.mode)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${entry.path} asks for file mode ${(entry.mode ?? 0).toString(8)}, and only 644 and 755 are accepted. Nothing was written.`,\n\t\t\t);\n\t\t}\n\t\tconst bytes = contents.get(entry.path);\n\t\tif (!bytes) {\n\t\t\tthrow new Error(\n\t\t\t\t`The downloaded bundle is missing ${entry.path}. Nothing was written.`,\n\t\t\t);\n\t\t}\n\t\tconst actual = createHash(\"sha256\").update(bytes).digest(\"hex\");\n\t\tif (actual !== entry.sha256) {\n\t\t\tthrow new Error(\n\t\t\t\t`Checksum mismatch for ${entry.path}: the published snapshot expects ${entry.sha256} and the downloaded bundle contains ${actual}. Nothing was written.`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// ---- Phase 2: apply --------------------------------------------------\n\tconst written: string[] = [];\n\tconst deleted: string[] = [];\n\tconst remoded: string[] = [];\n\tconst keptModified: string[] = [];\n\n\tfor (const entry of plan.writes) {\n\t\t// Non-null: phase 1 refused the whole plan if any byte was missing.\n\t\tconst bytes = contents.get(entry.path) as Uint8Array;\n\t\tawait writeFileSafely({\n\t\t\troot,\n\t\t\trelativePath: entry.path,\n\t\t\tbytes,\n\t\t\tmode: entry.mode ?? null,\n\t\t});\n\t\twritten.push(entry.path);\n\t}\n\n\t// A file whose bytes already match still has to carry the published\n\t// mode: a script that arrives non-executable is as broken as one that\n\t// arrives with the wrong contents, and `verified` would otherwise never\n\t// fix it.\n\tfor (const entry of plan.verified) {\n\t\tif (await applyMode(root, entry)) {\n\t\t\tremoded.push(entry.path);\n\t\t}\n\t}\n\n\tfor (const entry of plan.deletes) {\n\t\t// The hash the plan decided on travels with the unlink. Planning ran\n\t\t// before the download, the extraction and every write above, and an\n\t\t// editor saving in that window would otherwise have its work deleted\n\t\t// on the strength of a hash that no longer describes the file.\n\t\tif (entry.sha256 === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to delete ${entry.path}: the plan carries no hash for it.`,\n\t\t\t);\n\t\t}\n\t\tconst outcome = await deleteFileSafely(root, entry.path, entry.sha256);\n\t\tif (outcome === \"deleted\") {\n\t\t\tdeleted.push(entry.path);\n\t\t} else if (outcome === \"modified\") {\n\t\t\tkeptModified.push(entry.path);\n\t\t}\n\t}\n\t// Directories are deliberately left behind. An empty directory is\n\t// harmless; removing one races with anything the developer put in it.\n\n\treturn { written, deleted, remoded, keptModified };\n}\n\n/** Returns true when a mode was actually applied. */\nasync function applyMode(root: string, entry: PlanEntry): Promise<boolean> {\n\tconst bits = permissionBits(entry.mode);\n\tif (bits === null || process.platform === \"win32\") {\n\t\treturn false;\n\t}\n\tif (!isAllowedMode(entry.mode)) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${entry.path} asks for file mode ${(entry.mode ?? 0).toString(8)}, and only 644 and 755 are accepted.`,\n\t\t);\n\t}\n\t// The same guard the writes use: a `chmod` is a mutation too, and phase 1\n\t// proving this path was a regular file does not make it one now.\n\tconst check = await assertWritableTarget(root, entry.path);\n\tif (!check.ok) {\n\t\tthrow new Error(`Refusing to sync: ${describeRejection(check)}.`);\n\t}\n\ttry {\n\t\tawait chmod(check.path, bits);\n\t\treturn true;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\treturn false;\n\t\t}\n\t\tthrow error;\n\t}\n}\n","/**\n * Fetching and unpacking the published bundle.\n *\n * The archive is held in memory and never written to disk as an archive. A\n * temp zip on disk would be one more thing to clean up after an interrupted\n * run — but \"in memory\" only works while the size is bounded by something the\n * CLIENT decided, which is what `maxBytes` is. The response body is read in\n * chunks and abandoned the moment it exceeds that; `arrayBuffer()` buffered\n * whatever the server sent before anything could look at it, so a malformed\n * or hostile response sized the allocation itself.\n *\n * Only the paths the plan asked for are extracted, and the manifest's own\n * sizes bound the decompression. The filter is the only place that runs\n * before `fflate` allocates, so per-entry and aggregate limits belong there\n * rather than after the fact: the sha256 check in `apply.ts` catches\n * substituted CONTENT, but it runs on bytes that have already been\n * decompressed into memory.\n */\nimport { unzipSync } from \"fflate\";\n\nexport interface FetchBundleOptions {\n\t/** Per-attempt budget when no shared signal is supplied. */\n\ttimeoutMs: number;\n\t/**\n\t * The most compressed bytes worth reading, from `maxArchiveBytes`. A\n\t * declared `Content-Length` above it is refused before the body is read;\n\t * a body that grows past it is abandoned mid-stream.\n\t */\n\tmaxBytes: number;\n\t/**\n\t * A deadline owned by the caller. In hook mode one signal covers the\n\t * manifest call and this download together, so the whole command has a\n\t * single absolute bound rather than one per request.\n\t */\n\tsignal?: AbortSignal;\n\t/** Injectable for tests; defaults to the global fetch. */\n\tfetchImpl?: typeof fetch;\n}\n\nexport async function fetchBundle(\n\turl: string,\n\toptions: FetchBundleOptions,\n): Promise<Uint8Array> {\n\tconst fetchImpl = options.fetchImpl ?? fetch;\n\tconst controller = new AbortController();\n\tconst timer = setTimeout(() => controller.abort(), options.timeoutMs);\n\tconst onExternalAbort = () => controller.abort();\n\toptions.signal?.addEventListener(\"abort\", onExternalAbort, { once: true });\n\tif (options.signal?.aborted) {\n\t\tcontroller.abort();\n\t}\n\ttry {\n\t\tconst response = await fetchImpl(url, { signal: controller.signal });\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Downloading the coding-instructions bundle failed with HTTP ${response.status}.`,\n\t\t\t);\n\t\t}\n\n\t\tconst declared = Number(response.headers.get(\"content-length\"));\n\t\tif (Number.isFinite(declared) && declared > options.maxBytes) {\n\t\t\tthrow new Error(\n\t\t\t\t`The coding-instructions bundle declares ${declared} bytes and this snapshot's manifest allows at most ${options.maxBytes}. Nothing was written.`,\n\t\t\t);\n\t\t}\n\n\t\treturn await readBounded(response, options.maxBytes);\n\t} catch (error) {\n\t\tif (error instanceof Error && error.name === \"AbortError\") {\n\t\t\tthrow new Error(\n\t\t\t\t`Downloading the coding-instructions bundle timed out after ${options.timeoutMs}ms.`,\n\t\t\t);\n\t\t}\n\t\tthrow error;\n\t} finally {\n\t\tclearTimeout(timer);\n\t\toptions.signal?.removeEventListener(\"abort\", onExternalAbort);\n\t}\n}\n\n/**\n * Read a response body, refusing it the moment it passes `maxBytes`.\n *\n * The cap is compared against bytes ALREADY RECEIVED, so the refusal costs at\n * most one chunk beyond it rather than the whole body. A response with no\n * readable stream — an older polyfill, a test double built from a string —\n * falls back to `arrayBuffer()` and is length-checked after the fact, which\n * is the best available answer when the body cannot be consumed in pieces.\n */\nasync function readBounded(\n\tresponse: Response,\n\tmaxBytes: number,\n): Promise<Uint8Array> {\n\tconst body = response.body;\n\tif (!body) {\n\t\tconst bytes = new Uint8Array(await response.arrayBuffer());\n\t\tif (bytes.length > maxBytes) {\n\t\t\tthrow new Error(\n\t\t\t\t`The coding-instructions bundle is larger than the ${maxBytes} bytes this snapshot's manifest allows. Nothing was written.`,\n\t\t\t);\n\t\t}\n\t\treturn bytes;\n\t}\n\n\tconst reader = body.getReader();\n\tconst chunks: Uint8Array[] = [];\n\tlet total = 0;\n\ttry {\n\t\tfor (;;) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!value) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\ttotal += value.length;\n\t\t\tif (total > maxBytes) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`The coding-instructions bundle is larger than the ${maxBytes} bytes this snapshot's manifest allows. Nothing was written.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tchunks.push(value);\n\t\t}\n\t} finally {\n\t\tawait reader.cancel().catch(() => {});\n\t}\n\n\tconst archive = new Uint8Array(total);\n\tlet offset = 0;\n\tfor (const chunk of chunks) {\n\t\tarchive.set(chunk, offset);\n\t\toffset += chunk.length;\n\t}\n\treturn archive;\n}\n\nexport interface WantedEntry {\n\tpath: string;\n\t/** The manifest's size for this path, in bytes. */\n\tsize: number;\n}\n\n/**\n * Extract exactly the wanted paths, within exactly the wanted sizes.\n *\n * A zip entry name is matched literally against the manifest path. Nothing\n * here normalises, joins or resolves anything — a name that does not appear\n * in `wanted` is simply not returned, so an archive carrying `../../etc/x`\n * cannot reach the filesystem even before the path guard sees it.\n *\n * Three bounds, all enforced inside the filter so a hostile archive is\n * refused before it is decompressed:\n *\n * - a name the manifest does not list is skipped;\n * - an entry whose declared original size is not the manifest's size for\n * that path is refused (a zip bomb declaring 4 GB for a 200-byte file\n * never gets allocated);\n * - a second entry with a wanted name is refused rather than allowed to\n * win, which is what \"last one wins\" would otherwise let it do.\n */\nexport function extractBundle(\n\tarchive: Uint8Array,\n\twanted: Iterable<WantedEntry>,\n): Map<string, Uint8Array> {\n\tconst sizes = new Map<string, number>();\n\tfor (const entry of wanted) {\n\t\tsizes.set(entry.path, entry.size);\n\t}\n\tif (sizes.size === 0) {\n\t\treturn new Map();\n\t}\n\n\tconst seen = new Set<string>();\n\tconst unzipped = unzipSync(archive, {\n\t\tfilter: (file) => {\n\t\t\tconst expected = sizes.get(file.name);\n\t\t\tif (expected === undefined) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (seen.has(file.name)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`The downloaded bundle contains ${file.name} more than once. Nothing was written.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tseen.add(file.name);\n\t\t\tif (\n\t\t\t\tfile.originalSize !== undefined &&\n\t\t\t\tfile.originalSize !== expected\n\t\t\t) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`The downloaded bundle declares ${file.originalSize} bytes for ${file.name} and the manifest says ${expected}. Nothing was written.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t});\n\n\tconst contents = new Map<string, Uint8Array>();\n\tfor (const [name, bytes] of Object.entries(unzipped)) {\n\t\tconst expected = sizes.get(name);\n\t\tif (expected === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\t// The declared size is a claim; this is the measurement.\n\t\tif (bytes.length !== expected) {\n\t\t\tthrow new Error(\n\t\t\t\t`The downloaded bundle holds ${bytes.length} bytes for ${name} and the manifest says ${expected}. Nothing was written.`,\n\t\t\t);\n\t\t}\n\t\tcontents.set(name, bytes);\n\t}\n\treturn contents;\n}\n","/**\n * The coding-tool SessionStart hook that keeps a checkout current.\n *\n * Claude Code writes `.claude/settings.local.json` and never `settings.json`;\n * Codex writes `.codex/hooks.json`. Both are per-developer, normally\n * untracked files. A hook committed into a repository runs on everybody's\n * machine with whatever credentials they happen to have.\n *\n * The command never carries the key. It names a project and nothing else —\n * the CLI reads its credential from `FABRIC_API_KEY` or from the per-user\n * config file, both outside the repository. `assertKeyStaysOutside` is what\n * makes that a guarantee rather than a habit, and it compares REAL paths:\n * a config directory reached through a symlink into the checkout is inside\n * it however the string is spelled.\n *\n * `matcher` is deliberately omitted so the hook runs on startup, resume,\n * clear and compact alike: a session resumed after a pull is exactly when the\n * published version is most likely to have moved.\n */\nimport path from \"node:path\";\nimport {\n\treadFileSafely,\n\tresolvesInside,\n\twriteFileSafely,\n} from \"./safe-write.js\";\n\nexport type InstructionsHookTool = \"claude-code\" | \"codex\";\n\nexport const CLAUDE_SETTINGS_RELATIVE_PATH = path.join(\n\t\".claude\",\n\t\"settings.local.json\",\n);\n\nexport const CODEX_HOOKS_RELATIVE_PATH = path.join(\".codex\", \"hooks.json\");\n\n/** The same path in the POSIX spelling the guarded writer expects. */\nconst CLAUDE_SETTINGS_POSIX_PATH = \".claude/settings.local.json\";\nconst CODEX_HOOKS_POSIX_PATH = \".codex/hooks.json\";\n\n/** Seconds. Long enough for a cold start plus one manifest call, short enough to be invisible. */\nconst HOOK_TIMEOUT_SECONDS = 15;\n\n/** Local hook configuration is small; a bound prevents an untrusted file from consuming memory. */\nconst MAX_HOOK_CONFIG_BYTES = 1024 * 1024;\n\n/** The subcommands a hook this tool wrote may name. */\nconst HOOK_SUBCOMMANDS = new Set([\"check\", \"sync\"]);\n\ninterface CommandHook {\n\ttype: \"command\";\n\tcommand: string;\n\ttimeout?: number;\n\t[key: string]: unknown;\n}\n\ninterface HookGroup {\n\tmatcher?: string;\n\thooks: CommandHook[];\n\t[key: string]: unknown;\n}\n\nexport interface MergeHookResult {\n\tsettingsPath: string;\n\tcommand: string;\n\t/** True when the settings file did not exist before. */\n\tcreatedFile: boolean;\n\t/** How many existing Fabric hooks for this project were replaced or dropped. */\n\treplacedCount: number;\n}\n\n/**\n * The command the session hook runs.\n *\n * An explicit `--org` is carried through when `init` was given one. These\n * commands do not consult a stored default context, so a slug that was\n * supplied once on the command line has nowhere else to live — leaving it out\n * would install a hook that binds differently from the `init` that created\n * it. It still never carries the key.\n */\nexport function buildHookCommand(\n\tprojectId: string,\n\tapply: boolean,\n\torg?: string,\n): string {\n\tconst verb = apply ? \"sync\" : \"check\";\n\tconst context = org ? ` --org ${org}` : \"\";\n\treturn `fabric instructions ${verb} --project ${projectId}${context} --hook`;\n}\n\n/**\n * Would writing this hook put the API key inside the repository?\n *\n * The hook itself carries no key, so the only way one lands in the tree is\n * the CLI's own config file being stored there — which happens when\n * `XDG_CONFIG_HOME` or `APPDATA` points inside the checkout, including\n * through a symlink. Refuse rather than write a hook whose credential source\n * a `git add -A` would commit.\n */\nexport async function assertKeyStaysOutside(\n\tdestination: string,\n\tconfigPath: string,\n): Promise<void> {\n\tif (await resolvesInside(destination, configPath)) {\n\t\tthrow new Error(\n\t\t\t`The CLI stores its API key at ${configPath}, which resolves inside ${destination}. Writing a session hook here would leave a live credential in the repository. Move the CLI config outside the project (set XDG_CONFIG_HOME) or export FABRIC_API_KEY instead, then run this again.`,\n\t\t);\n\t}\n}\n\n/**\n * Add — or replace — the Fabric SessionStart hook for one project.\n *\n * Idempotent by project id, and idempotent across a file that already has\n * duplicates: EVERY matching entry is removed and exactly one is written\n * back. Matching is on parsed argv tokens, not on a substring — `--project\n * abc` must not match `--project abc-extra`, and `--project=abc` is the same\n * request written differently. Every other key in the file, and every other\n * hook, is preserved exactly.\n */\nexport async function mergeSessionStartHook(input: {\n\t/** An already-canonical destination from `resolveDestinationRoot`. */\n\troot: string;\n\tprojectId: string;\n\tcommand: string;\n\ttool?: InstructionsHookTool;\n}): Promise<MergeHookResult> {\n\tconst hookTarget = hookTargetFor(input.tool ?? \"claude-code\");\n\tconst settingsPath = path.join(input.root, hookTarget.relativePath);\n\n\tlet existingRaw: string | null;\n\ttry {\n\t\tconst existing = await readFileSafely(\n\t\t\tinput.root,\n\t\t\thookTarget.posixPath,\n\t\t\t{ maxBytes: MAX_HOOK_CONFIG_BYTES },\n\t\t);\n\t\texistingRaw =\n\t\t\texisting === null ? null : new TextDecoder().decode(existing.bytes);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(\n\t\t\t`${settingsPath} could not be read safely: ${message}. It was left untouched.`,\n\t\t);\n\t}\n\n\tlet settings: Record<string, unknown> = {};\n\tif (existingRaw !== null) {\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = JSON.parse(existingRaw);\n\t\t} catch {\n\t\t\t// Refused, never rewritten: this file is the developer's own, and\n\t\t\t// a JSON error in it is nearly always a half-finished edit rather\n\t\t\t// than something to discard.\n\t\t\tthrow new Error(\n\t\t\t\t`${settingsPath} is not valid JSON. Fix or remove it, then run this again — it was left untouched.`,\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\ttypeof parsed !== \"object\" ||\n\t\t\tparsed === null ||\n\t\t\tArray.isArray(parsed)\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t`${settingsPath} does not contain a JSON object. It was left untouched.`,\n\t\t\t);\n\t\t}\n\t\tsettings = parsed as Record<string, unknown>;\n\t}\n\n\t// Every nested shape is checked before anything is rebuilt. Top-level JSON\n\t// was refused carefully and these were not: `{\"hooks\": [\"custom\"]}` or a\n\t// `SessionStart` that is not an array used to be replaced with a\n\t// freshly-built hooks object, discarding whatever the developer had. A\n\t// shape this tool does not understand is no more ours to normalise than a\n\t// half-finished edit is.\n\tif (settings.hooks !== undefined && !isRecord(settings.hooks)) {\n\t\tthrow refuseShape(settingsPath, '\"hooks\" is not an object');\n\t}\n\tconst hooks = isRecord(settings.hooks) ? { ...settings.hooks } : {};\n\tif (\n\t\thooks.SessionStart !== undefined &&\n\t\t!Array.isArray(hooks.SessionStart)\n\t) {\n\t\tthrow refuseShape(settingsPath, '\"hooks.SessionStart\" is not an array');\n\t}\n\tconst rawGroups = Array.isArray(hooks.SessionStart)\n\t\t? hooks.SessionStart\n\t\t: [];\n\tfor (const [index, group] of rawGroups.entries()) {\n\t\tif (!isRecord(group)) {\n\t\t\tthrow refuseShape(\n\t\t\t\tsettingsPath,\n\t\t\t\t`\"hooks.SessionStart[${index}]\" is not an object`,\n\t\t\t);\n\t\t}\n\t\tif (group.hooks !== undefined && !Array.isArray(group.hooks)) {\n\t\t\tthrow refuseShape(\n\t\t\t\tsettingsPath,\n\t\t\t\t`\"hooks.SessionStart[${index}].hooks\" is not an array`,\n\t\t\t);\n\t\t}\n\t}\n\tconst sessionStart: HookGroup[] = (rawGroups as HookGroup[]).map(\n\t\t(group) => ({\n\t\t\t...group,\n\t\t\thooks: Array.isArray(group?.hooks) ? [...group.hooks] : [],\n\t\t}),\n\t);\n\n\tconst replacement: CommandHook = {\n\t\ttype: \"command\",\n\t\tcommand: input.command,\n\t\ttimeout: HOOK_TIMEOUT_SECONDS,\n\t};\n\n\t// Remove EVERY entry for this project first, then add one back. Replacing\n\t// in place and stopping at the first match left duplicates behind, and a\n\t// file that has accumulated two of our hooks should come out with one.\n\tlet replacedCount = 0;\n\tconst pruned: HookGroup[] = [];\n\tfor (const group of sessionStart) {\n\t\tconst kept = group.hooks.filter(\n\t\t\t(hook) => !isFabricHookFor(hook, input.projectId),\n\t\t);\n\t\tconst removed = group.hooks.length - kept.length;\n\t\treplacedCount += removed;\n\t\t// A group we emptied held nothing but our own hook; leaving\n\t\t// `{hooks: []}` behind would accumulate one husk per run. A group\n\t\t// that was ALREADY empty is somebody else's and is kept untouched,\n\t\t// which is why this turns on `removed` rather than on length alone.\n\t\tif (kept.length === 0 && removed > 0) {\n\t\t\tcontinue;\n\t\t}\n\t\tpruned.push({ ...group, hooks: kept });\n\t}\n\n\tpruned.push({ hooks: [replacement] });\n\n\tconst next = {\n\t\t...settings,\n\t\thooks: { ...hooks, SessionStart: pruned },\n\t};\n\n\tawait writeFileSafely({\n\t\troot: input.root,\n\t\trelativePath: hookTarget.posixPath,\n\t\tbytes: new TextEncoder().encode(\n\t\t\t`${JSON.stringify(next, null, 2).replace(/\\r\\n/g, \"\\n\")}\\n`,\n\t\t),\n\t});\n\n\treturn {\n\t\tsettingsPath,\n\t\tcommand: input.command,\n\t\tcreatedFile: existingRaw === null,\n\t\treplacedCount,\n\t};\n}\n\nfunction hookTargetFor(tool: InstructionsHookTool): {\n\trelativePath: string;\n\tposixPath: string;\n} {\n\treturn tool === \"codex\"\n\t\t? {\n\t\t\t\trelativePath: CODEX_HOOKS_RELATIVE_PATH,\n\t\t\t\tposixPath: CODEX_HOOKS_POSIX_PATH,\n\t\t\t}\n\t\t: {\n\t\t\t\trelativePath: CLAUDE_SETTINGS_RELATIVE_PATH,\n\t\t\t\tposixPath: CLAUDE_SETTINGS_POSIX_PATH,\n\t\t\t};\n}\n\n/**\n * Is this hook one this tool wrote for this project?\n *\n * Token-exact. The command is split on whitespace — every command this tool\n * generates is a plain, unquoted argv line, so a command that needs shell\n * quoting to parse is by definition not ours.\n */\nfunction isFabricHookFor(hook: unknown, projectId: string): boolean {\n\tif (!isRecord(hook) || typeof hook.command !== \"string\") {\n\t\treturn false;\n\t}\n\tconst tokens = hook.command.trim().split(/\\s+/);\n\tif (tokens[0] !== \"fabric\" || tokens[1] !== \"instructions\") {\n\t\treturn false;\n\t}\n\tif (tokens[2] === undefined || !HOOK_SUBCOMMANDS.has(tokens[2])) {\n\t\treturn false;\n\t}\n\treturn readProjectToken(tokens) === projectId;\n}\n\n/**\n * The `--project` value, from either `--project X` or `--project=X`, and only\n * when the command names exactly one.\n *\n * `fabric instructions check --project other --project target --hook` is a\n * command Commander resolves to `target`, while reading the first occurrence\n * answers `other`. Either reading makes this matcher wrong about somebody's\n * hook: merging for `other` would delete a hook that syncs `target`, and\n * merging for `target` would leave that entry behind and add a second. A\n * command this tool did not write is not this tool's to rewrite, so an\n * ambiguous one is left exactly as it is.\n */\nfunction readProjectToken(tokens: string[]): string | null {\n\tlet found: string | null = null;\n\tlet occurrences = 0;\n\tfor (let index = 3; index < tokens.length; index++) {\n\t\tconst token = tokens[index] as string;\n\t\tif (token === \"--project\") {\n\t\t\toccurrences++;\n\t\t\tfound = tokens[index + 1] ?? null;\n\t\t\tcontinue;\n\t\t}\n\t\tif (token.startsWith(\"--project=\")) {\n\t\t\toccurrences++;\n\t\t\tfound = token.slice(\"--project=\".length);\n\t\t}\n\t}\n\treturn occurrences === 1 ? found : null;\n}\n\n/** The same refusal shape as an unparseable file: say what, and touch nothing. */\nfunction refuseShape(settingsPath: string, what: string): Error {\n\treturn new Error(\n\t\t`${settingsPath} has a shape this tool does not recognise: ${what}. Fix or remove it, then run this again — it was left untouched.`,\n\t);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","/**\n * `<dest>/.fabric/instructions.lock` — what the last sync wrote.\n *\n * ## What the lock is, and what it is not\n *\n * It is a CONTENT LEDGER: a list of paths with the hash each one had when\n * this tool last wrote it. It is the only reason the sync may delete\n * anything — a path must be in the ledger AND still hash to what the ledger\n * recorded before it can be removed.\n *\n * It is NOT authenticated. It is a plain JSON file inside the checkout, so\n * anything that can write there can write it. That bounds what a tampered\n * lock can do rather than preventing it: an attacker who can already edit\n * files in the tree can make the next sync delete a file whose CURRENT\n * content hash they name correctly. They cannot make it write anywhere new,\n * because writes come from the server manifest, and they cannot name\n * `.git/**` or `.fabric/**` at all (`isReservedPath`). Closing the rest\n * needs a ledger stored outside the checkout, which is a larger change than\n * this feature.\n *\n * The lock is rewritten LAST, after every write has succeeded. A ledger\n * naming files that are not there would authorise deleting whatever is in\n * their place on the next run.\n */\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { writeFileSafely } from \"./safe-write.js\";\n\nexport const LOCK_DIRECTORY = \".fabric\";\nexport const LOCK_FILENAME = \"instructions.lock\";\n\n/** Bumped only if the shape below changes incompatibly. */\nexport const LOCK_VERSION = 1;\n\n/** The lock's own path, relative to the destination — never from a manifest. */\nconst LOCK_RELATIVE_PATH = `${LOCK_DIRECTORY}/${LOCK_FILENAME}`;\n\nconst SHA256_HEX = /^[0-9a-f]{64}$/;\n\ninterface LockFileEntry {\n\tsha256: string;\n\t/** POSIX mode as published, or null when the snapshot recorded none. */\n\tmode: number | null;\n}\n\nexport interface InstructionsLock {\n\tversion: number;\n\tprojectId: string;\n\tsnapshotId: string;\n\tsnapshotVersion: number;\n\tdigest: string;\n\t/** ISO 8601 timestamp of the sync that wrote this lock. */\n\tsyncedAt: string;\n\t/** Every path that sync wrote or verified — the manifest at that time. */\n\tfiles: Record<string, LockFileEntry>;\n}\n\nexport function lockPath(destination: string): string {\n\treturn path.join(destination, LOCK_DIRECTORY, LOCK_FILENAME);\n}\n\n/**\n * The lock, or `null` when this tree has never been synced.\n *\n * A lock that exists but does not validate is an ERROR and never a `null`.\n * Treating a damaged ledger as \"never synced\" would orphan every file the\n * previous sync wrote and hide the damage; the caller stops and says so.\n */\nexport async function readLock(\n\tdestination: string,\n): Promise<InstructionsLock | null> {\n\tconst file = lockPath(destination);\n\tlet raw: string;\n\ttry {\n\t\traw = await readFile(file, \"utf8\");\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\treturn null;\n\t\t}\n\t\tthrow error;\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`${file} is unreadable: it is not valid JSON. Delete it to start from a clean sync.`,\n\t\t);\n\t}\n\tconst problem = lockProblem(parsed);\n\tif (problem !== null) {\n\t\tthrow new Error(\n\t\t\t`${file} is unreadable: ${problem}. Delete it to start from a clean sync.`,\n\t\t);\n\t}\n\treturn parsed as InstructionsLock;\n}\n\n/** Pretty JSON with LF endings and a trailing newline, so a diff of it reads. */\nfunction serializeLock(lock: InstructionsLock): string {\n\treturn `${JSON.stringify(lock, null, 2).replace(/\\r\\n/g, \"\\n\")}\\n`;\n}\n\n/**\n * Write the lock through the same guarded writer as every instruction file.\n * `root` is an already-canonical destination from `resolveDestinationRoot`:\n * a `.fabric -> ..` symlink is how the lock write used to escape the tree.\n */\nexport async function writeLock(\n\troot: string,\n\tlock: InstructionsLock,\n): Promise<void> {\n\tawait writeFileSafely({\n\t\troot,\n\t\trelativePath: LOCK_RELATIVE_PATH,\n\t\tbytes: new TextEncoder().encode(serializeLock(lock)),\n\t});\n}\n\n/**\n * Why this value is not a lock, or `null` when it is one.\n *\n * Every field is checked, including `version`: a future lock this build does\n * not understand must stop the run rather than be half-read.\n */\nfunction lockProblem(value: unknown): string | null {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n\t\treturn \"it is not a JSON object\";\n\t}\n\tconst candidate = value as Record<string, unknown>;\n\n\tif (candidate.version !== LOCK_VERSION) {\n\t\treturn `its version is ${JSON.stringify(candidate.version)} and this build writes version ${LOCK_VERSION}`;\n\t}\n\tfor (const field of [\n\t\t\"projectId\",\n\t\t\"snapshotId\",\n\t\t\"digest\",\n\t\t\"syncedAt\",\n\t] as const) {\n\t\tconst actual = candidate[field];\n\t\tif (typeof actual !== \"string\" || actual.length === 0) {\n\t\t\treturn `its \"${field}\" is not a non-empty string`;\n\t\t}\n\t}\n\tif (\n\t\ttypeof candidate.snapshotVersion !== \"number\" ||\n\t\t!Number.isInteger(candidate.snapshotVersion) ||\n\t\tcandidate.snapshotVersion < 0\n\t) {\n\t\treturn 'its \"snapshotVersion\" is not a non-negative integer';\n\t}\n\tif (\n\t\ttypeof candidate.files !== \"object\" ||\n\t\tcandidate.files === null ||\n\t\tArray.isArray(candidate.files)\n\t) {\n\t\treturn 'its \"files\" is not an object';\n\t}\n\n\tfor (const [filePath, entry] of Object.entries(\n\t\tcandidate.files as Record<string, unknown>,\n\t)) {\n\t\tif (\n\t\t\ttypeof entry !== \"object\" ||\n\t\t\tentry === null ||\n\t\t\tArray.isArray(entry)\n\t\t) {\n\t\t\treturn `its entry for ${JSON.stringify(filePath)} is not an object`;\n\t\t}\n\t\tconst record = entry as Record<string, unknown>;\n\t\tif (\n\t\t\ttypeof record.sha256 !== \"string\" ||\n\t\t\t!SHA256_HEX.test(record.sha256)\n\t\t) {\n\t\t\treturn `its entry for ${JSON.stringify(filePath)} has no 64-character hex sha256`;\n\t\t}\n\t\tif (\n\t\t\trecord.mode !== null &&\n\t\t\t(typeof record.mode !== \"number\" ||\n\t\t\t\t!Number.isInteger(record.mode) ||\n\t\t\t\trecord.mode < 0)\n\t\t) {\n\t\t\treturn `its entry for ${JSON.stringify(filePath)} has a mode that is neither null nor a non-negative integer`;\n\t\t}\n\t}\n\treturn null;\n}\n","/**\n * Deciding whether a server response is a manifest at all.\n *\n * An absent manifest used to become `[]`, and an empty manifest means\n * \"delete everything the lock names\". A version-skewed server, a truncated\n * proxy response or a field rename was therefore one step away from wiping\n * the tree and writing an empty ledger. A manifest is now either complete\n * and self-consistent or it is a refusal.\n *\n * Three independent things are checked, because each catches a different\n * failure:\n *\n * - every ENTRY is well-formed, and no two name the same file;\n * - the COUNT matches the snapshot's own `fileCount`, which catches a\n * truncated list that is otherwise perfectly well-formed;\n * - the DIGEST recomputed from the entries matches the snapshot's, which\n * catches a list that is the right length and the wrong content.\n *\n * The digest recipe is the server's (`packages/instructions/src/manifest.ts`):\n * sha256 over `path\\0sha256\\n` lines sorted by path. It is reimplemented\n * here rather than imported because `@repo/instructions` is a private\n * workspace package and this one is published to npm.\n */\nimport { createHash } from \"node:crypto\";\nimport type { InstructionManifestEntry } from \"@fabricorg/sdk\";\nimport {\n\tcheckRelativePath,\n\tdescribeRejection,\n\tfindCollision,\n\tisReservedPath,\n} from \"./paths.js\";\nimport { isAllowedMode } from \"./safe-write.js\";\n\nconst SHA256_HEX = /^[0-9a-f]{64}$/;\n\n/**\n * What a published snapshot can legitimately be.\n *\n * Mirrors `SNAPSHOT_LIMITS` in `packages/instructions/src/limits.ts`, which\n * bounds what publishing will ACCEPT; these bound what a client will act on.\n * Reimplemented rather than imported for the same reason the digest recipe is:\n * that package is private and this one is published to npm.\n *\n * The point is memory, not policy. Before this, `fileCount` and the per-entry\n * sizes were checked against each other but never against an absolute, so a\n * manifest claiming a million files of 4 GB each was internally consistent and\n * sized the download bound off its own claim.\n *\n * `maxPathBytes` and `maxDepth` are deliberately LOOSER than the server's 512\n * and 32: a client that refuses what the server would happily publish breaks\n * the moment those limits are raised, and 1024 bytes across 5000 files is\n * still bounded. Everything else matches exactly.\n */\nconst MANIFEST_LIMITS = {\n\tmaxFiles: 5000,\n\tmaxTotalBytes: 52_428_800,\n\tmaxFileBytes: 5_242_880,\n\tmaxPathBytes: 1024,\n\tmaxDepth: 64,\n} as const;\n\n/**\n * Per-entry zip framing, in bytes, before the path itself.\n *\n * A zip carries each file twice in structure: a 30-byte local header and a\n * 46-byte central-directory header, each followed by the name, plus optional\n * extra fields and a data descriptor. 512 is generous for all of it, and\n * generous is the right direction — this is a ceiling on what will be\n * DOWNLOADED, and a bound that is too tight refuses a snapshot the server\n * considers perfectly valid.\n */\nconst ZIP_ENTRY_OVERHEAD_BYTES = 512;\n\n/**\n * The largest archive worth downloading for this manifest.\n *\n * A flat slack was wrong: zip framing grows with the number of entries and\n * the length of their names, so a legitimate snapshot of 5000 empty files\n * with 200-byte paths needs about 2.4 MB of pure structure and could not be\n * synced at all. The bound now scales the way the format does.\n */\nexport function maxArchiveBytes(\n\tentries: ReadonlyArray<{ path: string; size: number }>,\n): number {\n\tlet total = 1_048_576;\n\tfor (const entry of entries) {\n\t\ttotal +=\n\t\t\tentry.size +\n\t\t\tZIP_ENTRY_OVERHEAD_BYTES +\n\t\t\t2 * Buffer.byteLength(entry.path, \"utf8\");\n\t}\n\treturn total;\n}\n\n/**\n * The snapshot digest, computed the way the server computes it.\n *\n * Keep in step with `computeSnapshotDigest` in `@repo/instructions`. A\n * divergence here turns every sync into a refusal, which is the safe\n * direction but still a break.\n */\nexport function computeSnapshotDigest(\n\tentries: ReadonlyArray<{ path: string; sha256: string }>,\n): string {\n\tconst lines = [...entries]\n\t\t.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0))\n\t\t.map((entry) => `${entry.path}\\0${entry.sha256}\\n`)\n\t\t.join(\"\");\n\treturn createHash(\"sha256\")\n\t\t.update(Buffer.from(lines, \"utf8\"))\n\t\t.digest(\"hex\");\n}\n\n/**\n * Validate a published manifest, or explain why it is not one.\n *\n * Throws rather than returning a result: every caller's only response to a\n * bad manifest is to stop, and under `--hook` the message becomes the one\n * line a developer sees.\n */\nexport function assertValidManifest(input: {\n\tmanifest: unknown;\n\tsnapshot: { digest: string; fileCount: number; version: number };\n}): InstructionManifestEntry[] {\n\tconst { manifest, snapshot } = input;\n\n\tif (!Array.isArray(manifest)) {\n\t\tthrow new Error(\n\t\t\t`The server described version ${snapshot.version} as published but sent no file manifest. Nothing was changed.`,\n\t\t);\n\t}\n\n\tif (manifest.length > MANIFEST_LIMITS.maxFiles) {\n\t\tthrow new Error(\n\t\t\t`The manifest for version ${snapshot.version} lists ${manifest.length} files and a published snapshot holds at most ${MANIFEST_LIMITS.maxFiles}. Nothing was changed.`,\n\t\t);\n\t}\n\n\tconst entries: InstructionManifestEntry[] = [];\n\tfor (const raw of manifest) {\n\t\tentries.push(validateEntry(raw));\n\t}\n\n\tconst totalBytes = entries.reduce((total, entry) => total + entry.size, 0);\n\tif (totalBytes > MANIFEST_LIMITS.maxTotalBytes) {\n\t\tthrow new Error(\n\t\t\t`The manifest for version ${snapshot.version} describes ${totalBytes} bytes and a published snapshot holds at most ${MANIFEST_LIMITS.maxTotalBytes}. Nothing was changed.`,\n\t\t);\n\t}\n\n\tconst collision = findCollision(entries.map((entry) => entry.path));\n\tif (collision !== null) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${describeRejection({\n\t\t\t\tok: false,\n\t\t\t\treason: \"collision\",\n\t\t\t\tdetail: `${collision.first} and ${collision.second}`,\n\t\t\t})}.`,\n\t\t);\n\t}\n\n\tif (entries.length !== snapshot.fileCount) {\n\t\tthrow new Error(\n\t\t\t`The manifest for version ${snapshot.version} lists ${entries.length} files and the snapshot says ${snapshot.fileCount}. Nothing was changed.`,\n\t\t);\n\t}\n\n\tconst recomputed = computeSnapshotDigest(entries);\n\tif (recomputed !== snapshot.digest) {\n\t\tthrow new Error(\n\t\t\t`The manifest for version ${snapshot.version} does not match its own digest (${snapshot.digest}); it hashes to ${recomputed}. Nothing was changed.`,\n\t\t);\n\t}\n\n\treturn entries;\n}\n\nfunction validateEntry(raw: unknown): InstructionManifestEntry {\n\tif (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n\t\tthrow new Error(\n\t\t\t\"The server sent a manifest entry that is not an object. Nothing was changed.\",\n\t\t);\n\t}\n\tconst entry = raw as Record<string, unknown>;\n\n\tif (typeof entry.path !== \"string\") {\n\t\tthrow new Error(\n\t\t\t\"The server sent a manifest entry with no path. Nothing was changed.\",\n\t\t);\n\t}\n\tconst check = checkRelativePath(entry.path);\n\tif (!check.ok) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${describeRejection(check)}. The published snapshot names a path this tool will not write.`,\n\t\t);\n\t}\n\tconst pathBytes = Buffer.byteLength(entry.path, \"utf8\");\n\tif (pathBytes > MANIFEST_LIMITS.maxPathBytes) {\n\t\tthrow new Error(\n\t\t\t`The manifest entry for ${entry.path.slice(0, 80)}… has a ${pathBytes}-byte path and at most ${MANIFEST_LIMITS.maxPathBytes} is accepted. Nothing was changed.`,\n\t\t);\n\t}\n\tif (entry.path.split(\"/\").length > MANIFEST_LIMITS.maxDepth) {\n\t\tthrow new Error(\n\t\t\t`The manifest entry for ${entry.path} is nested deeper than ${MANIFEST_LIMITS.maxDepth} directories. Nothing was changed.`,\n\t\t);\n\t}\n\tif (isReservedPath(entry.path)) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${describeRejection({\n\t\t\t\tok: false,\n\t\t\t\treason: \"reserved_path\",\n\t\t\t\tdetail: entry.path,\n\t\t\t})}.`,\n\t\t);\n\t}\n\tif (typeof entry.sha256 !== \"string\" || !SHA256_HEX.test(entry.sha256)) {\n\t\tthrow new Error(\n\t\t\t`The manifest entry for ${entry.path} has no 64-character hex sha256. Nothing was changed.`,\n\t\t);\n\t}\n\tif (\n\t\ttypeof entry.size !== \"number\" ||\n\t\t!Number.isInteger(entry.size) ||\n\t\tentry.size < 0\n\t) {\n\t\tthrow new Error(\n\t\t\t`The manifest entry for ${entry.path} has no non-negative integer size. Nothing was changed.`,\n\t\t);\n\t}\n\tif (entry.size > MANIFEST_LIMITS.maxFileBytes) {\n\t\tthrow new Error(\n\t\t\t`The manifest entry for ${entry.path} declares ${entry.size} bytes and a published file holds at most ${MANIFEST_LIMITS.maxFileBytes}. Nothing was changed.`,\n\t\t);\n\t}\n\tif (\n\t\tentry.mode !== null &&\n\t\t(typeof entry.mode !== \"number\" || !Number.isInteger(entry.mode))\n\t) {\n\t\tthrow new Error(\n\t\t\t`The manifest entry for ${entry.path} has a mode that is neither null nor an integer. Nothing was changed.`,\n\t\t);\n\t}\n\tif (!isAllowedMode(entry.mode as number | null)) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${entry.path} asks for file mode ${((entry.mode as number) ?? 0).toString(8)}, and only 644 and 755 are accepted.`,\n\t\t);\n\t}\n\n\treturn {\n\t\tpath: entry.path,\n\t\tsha256: entry.sha256,\n\t\tsize: entry.size,\n\t\tmode: entry.mode as number | null,\n\t\tkind: (entry.kind ?? \"OTHER\") as InstructionManifestEntry[\"kind\"],\n\t};\n}\n","/**\n * What a sync would do, decided against the LOCAL TREE and not only the lock.\n *\n * The lock says what the last sync wrote; the working tree says what is\n * actually there now. Planning from the lock alone gets both interesting\n * cases wrong — a file the developer edited since the sync would be silently\n * overwritten with no notice, and a file they deleted would never come back\n * because the lock still claims it is present. So every path is hashed.\n *\n * Seven outcomes, and the distinctions between them are the whole point:\n *\n * verified local bytes already equal the published bytes — no write\n * added nothing local — a new file\n * updated local matches the lock, so this is the sync's own file\n * moving forward\n * replaced local matches neither the lock nor the manifest — local\n * edits are about to be overwritten, and the report says so\n * deleted gone from the manifest, and local still matches the lock,\n * so the sync wrote it and may remove it\n * kept-modified gone from the manifest, but local differs from the lock —\n * the developer changed it, so it stays\n * kept-renamed gone from the manifest under this spelling, but the\n * manifest names the same physical file another way — the\n * write for the new spelling is the update, so the old one\n * must not be unlinked afterwards\n *\n * A path absent from the lock is never deleted, whatever it is — and a\n * reserved path (`.git/`, `.fabric/`, the tool's own Claude settings file) is\n * refused outright wherever it appears, because the lock is an unauthenticated\n * file in the checkout (see `lock.ts`) and those are the paths a tampered one\n * would most want to name.\n */\nimport { createHash } from \"node:crypto\";\nimport type { InstructionManifestEntry } from \"@fabricorg/sdk\";\nimport { type InstructionsLock, LOCK_VERSION } from \"./lock.js\";\nimport {\n\tcheckRelativePath,\n\tcollisionKey,\n\tdescribeRejection,\n\tfindCollision,\n\tisReservedPath,\n} from \"./paths.js\";\nimport { readFileSafely } from \"./safe-write.js\";\n\ntype PlanAction =\n\t| \"verified\"\n\t| \"added\"\n\t| \"updated\"\n\t| \"replaced\"\n\t| \"deleted\"\n\t| \"kept-modified\"\n\t| \"kept-renamed\";\n\nexport interface PlanEntry {\n\tpath: string;\n\taction: PlanAction;\n\t/** The published hash, for everything the manifest still carries. */\n\tsha256?: string;\n\tmode?: number | null;\n}\n\nexport interface SyncPlan {\n\tentries: PlanEntry[];\n\t/** Entries whose bytes must be fetched and written. */\n\twrites: PlanEntry[];\n\t/** Entries to unlink. Always a subset of the previous lock. */\n\tdeletes: PlanEntry[];\n\tverified: PlanEntry[];\n\tkeptModified: PlanEntry[];\n\t/**\n\t * Lock paths that are the same physical file as a manifest path under a\n\t * different spelling. Never deleted; reported so the old spelling is not\n\t * a surprise on the filesystems where it survives.\n\t */\n\tkeptRenamed: PlanEntry[];\n}\n\n/**\n * Hex sha256 of a local file, or `null` when nothing is there.\n *\n * Every read goes through `readFileSafely`, the same guarded walk the writes\n * use: no symlinked component anywhere on the way down, nothing resolving\n * outside the destination, a regular file or nothing at all. A link pointing\n * at a file that happens to hold the published bytes used to hash EQUAL and\n * become `verified` — no write, no check, and a lock written over a path that\n * is not a file.\n */\nasync function hashLocalFile(\n\troot: string,\n\trelativePath: string,\n): Promise<string | null> {\n\tconst read = await readFileSafely(root, relativePath);\n\treturn read === null\n\t\t? null\n\t\t: createHash(\"sha256\").update(read.bytes).digest(\"hex\");\n}\n\nfunction lockPaths(lock: InstructionsLock | null): string[] {\n\treturn lock === null ? [] : Object.keys(lock.files);\n}\n\n/**\n * Every path the lock names has to survive the same checks a manifest path\n * does, plus the reserved-root rule — a hand-edited or accidentally\n * committed lock is exactly how `.git/config` would otherwise become an\n * unlink target with a hash anyone can read off disk.\n */\nfunction assertSafeLockPaths(paths: readonly string[]): void {\n\tfor (const lockedPath of paths) {\n\t\tconst check = checkRelativePath(lockedPath);\n\t\tif (!check.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection(check)}. The lock names a path this tool will not touch.`,\n\t\t\t);\n\t\t}\n\t\tif (isReservedPath(lockedPath)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection({\n\t\t\t\t\tok: false,\n\t\t\t\t\treason: \"reserved_path\",\n\t\t\t\t\tdetail: lockedPath,\n\t\t\t\t})}. The lock names a path this tool will not touch.`,\n\t\t\t);\n\t\t}\n\t}\n\tconst collision = findCollision(paths);\n\tif (collision !== null) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${describeRejection({\n\t\t\t\tok: false,\n\t\t\t\treason: \"collision\",\n\t\t\t\tdetail: `${collision.first} and ${collision.second}`,\n\t\t\t})}. The lock names two paths this tool cannot tell apart.`,\n\t\t);\n\t}\n}\n\n/**\n * Does the working tree still hold what the lock says it holds?\n *\n * The server answers \"unchanged\" by comparing digests, and a digest describes\n * the PUBLISHED snapshot — it says nothing about the checkout. Accepting that\n * answer as \"nothing to do\" meant an edited, deleted or chmod-ed instruction\n * file stayed that way until some later publication happened to move the\n * digest. For a feature whose point is that an agent reads the same\n * instructions everyone else does, that is the failure that matters most:\n * tampering persists and the tool reports success.\n *\n * Returns the paths that no longer match, as reasons a person can act on.\n * Never throws: a symlink or a directory standing where a file should be is\n * drift to REPORT, and the re-plan that follows is what refuses it.\n */\nexport async function verifyLedger(input: {\n\t/** An already-canonical root — `resolveDestinationRoot` or `resolveExistingRoot`. */\n\troot: string;\n\tlock: InstructionsLock;\n}): Promise<string[]> {\n\t// FIRST, before a single path is joined or opened. This function reads\n\t// paths that come out of an unauthenticated file in the checkout, and it\n\t// used to read them raw: `../outside` reached outside the destination, and\n\t// `rules/` replaced by a symlink was followed wherever it pointed. The\n\t// same validation `computeSyncPlan` runs, run before anything is touched.\n\tassertSafeLockPaths(lockPaths(input.lock));\n\n\tconst drifted: string[] = [];\n\tfor (const [lockedPath, locked] of Object.entries(input.lock.files)) {\n\t\t// A refusal from the guarded reader — a symlinked ancestor, a\n\t\t// directory where a file belongs — is drift, not a crash: the caller\n\t\t// re-plans, and planning refuses it there with the same message.\n\t\tlet read: Awaited<ReturnType<typeof readFileSafely>>;\n\t\ttry {\n\t\t\tread = await readFileSafely(input.root, lockedPath);\n\t\t} catch (error) {\n\t\t\tdrifted.push(\n\t\t\t\t`${lockedPath} (${error instanceof Error ? error.message.replace(/^Refusing to sync: /, \"\").replace(/\\.$/, \"\") : String(error)})`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tif (read === null) {\n\t\t\tdrifted.push(`${lockedPath} (missing)`);\n\t\t\tcontinue;\n\t\t}\n\t\tconst actual = createHash(\"sha256\").update(read.bytes).digest(\"hex\");\n\t\tif (actual !== locked.sha256) {\n\t\t\tdrifted.push(`${lockedPath} (edited)`);\n\t\t\tcontinue;\n\t\t}\n\t\t// Modes are meaningless on Windows and a published `0755` that arrived\n\t\t// as `0644` leaves a script that will not run, so this is checked\n\t\t// wherever it can be.\n\t\tif (\n\t\t\tprocess.platform !== \"win32\" &&\n\t\t\tlocked.mode !== null &&\n\t\t\t(read.mode & 0o7777) !== (locked.mode & 0o7777)\n\t\t) {\n\t\t\tdrifted.push(\n\t\t\t\t`${lockedPath} (mode ${(read.mode & 0o7777).toString(8)}, published as ${(locked.mode & 0o7777).toString(8)})`,\n\t\t\t);\n\t\t}\n\t}\n\treturn drifted;\n}\n\nexport async function computeSyncPlan(input: {\n\t/** An already-canonical root, as every guarded read resolves against it. */\n\tdestination: string;\n\tmanifest: InstructionManifestEntry[];\n\tlock: InstructionsLock | null;\n}): Promise<SyncPlan> {\n\tconst { destination, manifest, lock } = input;\n\n\t// `assertValidManifest` has already checked every manifest entry's path,\n\t// shape, mode, uniqueness, count and digest before this is called. What\n\t// is re-checked here is the LOCK, which no server validated: it is a\n\t// plain file in the checkout, and it is the only thing that can authorise\n\t// a delete.\n\tassertSafeLockPaths(lockPaths(lock));\n\n\t// A Map, not the parsed object: a manifest path of `constructor` or\n\t// `toString` reads a value off `Object.prototype` when the lookup is a\n\t// plain property access, and `__proto__` does not read back at all.\n\tconst lockedFiles = new Map(Object.entries(lock?.files ?? {}));\n\tconst manifestPaths = new Set(manifest.map((entry) => entry.path));\n\t// The union, not the two sets separately. Each list is internally free of\n\t// collisions by now, which says nothing about a path appearing in one under\n\t// a spelling the other uses differently — and that case is a RENAME, not a\n\t// conflict. See `isRenameOf` below for what it costs to get wrong.\n\tconst manifestKeys = new Map(\n\t\tmanifest.map(\n\t\t\t(entry) => [collisionKey(entry.path), entry.path] as const,\n\t\t),\n\t);\n\tconst entries: PlanEntry[] = [];\n\n\tfor (const entry of manifest) {\n\t\tconst localHash = await hashLocalFile(destination, entry.path);\n\t\tif (localHash === entry.sha256) {\n\t\t\tentries.push({\n\t\t\t\tpath: entry.path,\n\t\t\t\taction: \"verified\",\n\t\t\t\tsha256: entry.sha256,\n\t\t\t\tmode: entry.mode,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst lockedHash = lockedFiles.get(entry.path)?.sha256;\n\t\tconst action: PlanAction =\n\t\t\tlocalHash === null\n\t\t\t\t? \"added\"\n\t\t\t\t: localHash === lockedHash\n\t\t\t\t\t? \"updated\"\n\t\t\t\t\t: \"replaced\";\n\t\tentries.push({\n\t\t\tpath: entry.path,\n\t\t\taction,\n\t\t\tsha256: entry.sha256,\n\t\t\tmode: entry.mode,\n\t\t});\n\t}\n\n\tfor (const [lockedPath, locked] of lockedFiles) {\n\t\tif (manifestPaths.has(lockedPath)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// `README.md` in the lock and `readme.md` in the manifest are two\n\t\t// spellings of one file wherever the filesystem folds case or\n\t\t// normalises names — and writes run before deletes, so planning a\n\t\t// delete here unlinked the file the same run had just written and then\n\t\t// wrote a lock claiming it was there. The manifest spelling's own write\n\t\t// IS the update; this one must not be touched. On Linux the two really\n\t\t// are separate files, and skipping the delete is still the right answer:\n\t\t// a tool that deletes a file because another file's name resembles it\n\t\t// would be worse than one that leaves a stale copy and says so.\n\t\tconst renamedTo = manifestKeys.get(collisionKey(lockedPath));\n\t\tif (renamedTo !== undefined) {\n\t\t\tentries.push({\n\t\t\t\tpath: lockedPath,\n\t\t\t\taction: \"kept-renamed\",\n\t\t\t\tsha256: locked.sha256,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst localHash = await hashLocalFile(destination, lockedPath);\n\t\tif (localHash === null) {\n\t\t\tcontinue;\n\t\t}\n\t\tentries.push({\n\t\t\tpath: lockedPath,\n\t\t\taction: localHash === locked.sha256 ? \"deleted\" : \"kept-modified\",\n\t\t\t// Carried so the unlink can prove it is still removing the file\n\t\t\t// this hash described, rather than whatever is at the path by the\n\t\t\t// time the writes are done.\n\t\t\tsha256: locked.sha256,\n\t\t});\n\t}\n\n\tentries.sort((a, b) => a.path.localeCompare(b.path));\n\n\treturn {\n\t\tentries,\n\t\twrites: entries.filter(\n\t\t\t(entry) =>\n\t\t\t\tentry.action === \"added\" ||\n\t\t\t\tentry.action === \"updated\" ||\n\t\t\t\tentry.action === \"replaced\",\n\t\t),\n\t\tdeletes: entries.filter((entry) => entry.action === \"deleted\"),\n\t\tverified: entries.filter((entry) => entry.action === \"verified\"),\n\t\tkeptModified: entries.filter(\n\t\t\t(entry) => entry.action === \"kept-modified\",\n\t\t),\n\t\tkeptRenamed: entries.filter((entry) => entry.action === \"kept-renamed\"),\n\t};\n}\n\n/** The lock the sync should leave behind once `plan` has been applied. */\nexport function nextLock(input: {\n\tprojectId: string;\n\tsnapshot: { id: string; version: number; digest: string };\n\tmanifest: InstructionManifestEntry[];\n\tnow?: Date;\n}): InstructionsLock {\n\t// `Object.fromEntries` rather than assignment into `{}`: assigning\n\t// `files[\"__proto__\"]` sets the prototype instead of creating an own\n\t// property, so a published file called `__proto__` was written to disk and\n\t// then left out of the ledger — and a later snapshot that dropped it could\n\t// not prove the sync had created it.\n\tconst files: InstructionsLock[\"files\"] = Object.fromEntries(\n\t\tinput.manifest.map((entry) => [\n\t\t\tentry.path,\n\t\t\t{ sha256: entry.sha256, mode: entry.mode },\n\t\t]),\n\t);\n\treturn {\n\t\tversion: LOCK_VERSION,\n\t\tprojectId: input.projectId,\n\t\tsnapshotId: input.snapshot.id,\n\t\tsnapshotVersion: input.snapshot.version,\n\t\tdigest: input.snapshot.digest,\n\t\tsyncedAt: (input.now ?? new Date()).toISOString(),\n\t\tfiles,\n\t};\n}\n","/**\n * What `fabric instructions push` would send, decided against the LOCAL TREE\n * and the lock together.\n *\n * ## What a push owns\n *\n * Exactly what `sync` owns: the paths in `.fabric/instructions.lock`. That is\n * not a simplification, it is the only defensible rule available here. `sync`\n * has no include/exclude vocabulary of its own — it writes what the manifest\n * names and remembers it in the ledger (`plan.ts`), and the exclusion rules\n * that decide what a snapshot may hold live server-side in\n * `@repo/instructions`, a package this published CLI cannot depend on. So a\n * tree walk would have to invent a rule about which of a checkout's files are\n * instruction files, and getting that wrong means uploading somebody's source\n * tree into their project's coding instructions.\n *\n * Three outcomes per locked path, and nothing else is ever sent:\n *\n * put local bytes differ from the hash the lock recorded\n * delete the lock names it and nothing is there any more\n * (skip) local bytes still equal the lock — there is nothing to say\n *\n * ## Adding a file the lock does not name\n *\n * By `--add <path>`, explicitly, one flag per file. A new file is the one case\n * the ledger cannot discover, and naming it is both unambiguous and honest\n * about what the tool knows. The path goes through the same refusals a locked\n * one does — no traversal, no reserved root, no symlinked component — and must\n * actually be a regular file.\n *\n * ## Reads are guarded exactly as writes are\n *\n * Every read goes through `readFileSafely`, the same per-segment walk `sync`\n * writes through: nothing resolving outside the destination, no symlinked\n * component anywhere on the way down, a regular file or nothing at all at the\n * end. A push reads files and sends their contents to a server, so a symlink\n * standing where an instruction file belongs is a way to exfiltrate whatever\n * it points at — the one thing this command must not do.\n */\nimport { createHash } from \"node:crypto\";\nimport type {\n\tInstructionChange,\n\tInstructionManifestEntry,\n} from \"@fabricorg/sdk\";\nimport type { InstructionsLock } from \"./lock.js\";\nimport {\n\tcheckRelativePath,\n\tdescribeRejection,\n\tfindCollision,\n\tisReservedPath,\n} from \"./paths.js\";\nimport { readFileSafely } from \"./safe-write.js\";\n\n/** The server's own cap on one change set (`MAX_CHANGES`), mirrored so the refusal happens before the request. */\nexport const MAX_PUSH_CHANGES = 50;\n\ntype PushChangeAction = \"put\" | \"delete\";\n\ninterface PushPlanEntry {\n\tpath: string;\n\taction: PushChangeAction;\n\t/** Present on a `put`: the size of the bytes to send. */\n\tsize?: number;\n}\n\nexport interface PushPlan {\n\tentries: PushPlanEntry[];\n\t/** The change set exactly as the request carries it. */\n\tchanges: InstructionChange[];\n\t/** Locked paths whose bytes still match the ledger. Reported, never sent. */\n\tunchanged: string[];\n}\n\n/**\n * Whether a path is one this tool will read or name at all.\n *\n * The same two refusals `plan.ts` applies to a lock's ledger, for the same\n * reason: the lock is an unauthenticated file in the checkout, and `.git/**`,\n * `.fabric/**` and the tool's own Claude settings file are exactly the paths a\n * tampered one would most want to name — here so it could read them out.\n */\nfunction assertPushablePath(candidate: string, source: string): void {\n\tconst check = checkRelativePath(candidate);\n\tif (!check.ok) {\n\t\tthrow new Error(\n\t\t\t`Refusing to push: ${describeRejection(check)}. ${source}`,\n\t\t);\n\t}\n\tif (isReservedPath(candidate)) {\n\t\tthrow new Error(\n\t\t\t`Refusing to push: ${describeRejection({\n\t\t\t\tok: false,\n\t\t\t\treason: \"reserved_path\",\n\t\t\t\tdetail: candidate,\n\t\t\t})}. ${source}`,\n\t\t);\n\t}\n}\n\n/**\n * How a file's bytes travel in the request.\n *\n * UTF-8 when the bytes are valid UTF-8 and survive the round trip, base64\n * otherwise. Preferring text is not cosmetic: an instruction tree is markdown\n * and JSON, base64 costs a third more request body against a bounded limit,\n * and a readable payload is a readable failure when something goes wrong.\n *\n * The round trip is the test rather than a heuristic on the bytes, because\n * `TextDecoder` replaces anything invalid with U+FFFD silently — a file that\n * \"decoded fine\" would have been sent with its bad bytes rewritten.\n */\nfunction encodeContent(bytes: Uint8Array): {\n\tcontent: string;\n\tencoding: \"utf8\" | \"base64\";\n} {\n\tconst text = new TextDecoder(\"utf-8\", { fatal: false }).decode(bytes);\n\tconst roundTrip = new TextEncoder().encode(text);\n\tif (\n\t\troundTrip.length === bytes.length &&\n\t\troundTrip.every((byte, index) => byte === bytes[index])\n\t) {\n\t\treturn { content: text, encoding: \"utf8\" };\n\t}\n\treturn {\n\t\tcontent: Buffer.from(bytes).toString(\"base64\"),\n\t\tencoding: \"base64\",\n\t};\n}\n\n/**\n * The one refusal every stale- or tampered-ledger case shares.\n *\n * Same sentence, same instruction, whichever direction the disagreement was\n * found in: the ledger is not the published version, and the fix is local.\n */\nfunction refuseStaleLedger(detail: string): never {\n\tthrow new Error(\n\t\t`Refusing to push: the sync lock does not match the published version — ${detail}. Run \\`fabric instructions sync\\` and try again. Nothing was read and nothing was sent.`,\n\t);\n}\n\n/**\n * Refuse unless the lock describes EXACTLY the published version it names.\n *\n * Both directions are checked, and they catch different things.\n *\n * An EXTRA path — one the ledger claims and the manifest does not — is the\n * attack: it is how a file that was never part of the instructions gets read\n * and sent.\n *\n * A MISSING one — published, absent from the ledger — is the quiet half. The\n * diff below only ever walks what the lock names, so deleting an entry from\n * the ledger makes that file invisible to this command: a local edit to it is\n * dropped from the proposal, a local deletion of it is never reported, and a\n * checkout with one file changed can report \"Nothing to push\". Neither is\n * loud, and both produce a proposal that is not the diff it claims to be.\n *\n * A DIFFERENT hash is neither of those and just as unusable: the diff is \"what\n * changed since the last sync\", and a ledger that disagrees with the version\n * it claims to record cannot answer that question.\n *\n * `nextLock` builds the ledger from the manifest with `Object.fromEntries`, so\n * on a tree this tool wrote the two agree entry for entry; anything else has\n * been edited since, and re-syncing rewrites it from the server.\n */\nfunction assertLockMatchesManifest(\n\tlock: InstructionsLock,\n\tmanifest: readonly InstructionManifestEntry[],\n): void {\n\tconst published = new Map(\n\t\tmanifest.map((entry) => [entry.path, entry.sha256]),\n\t);\n\tfor (const [path, entry] of Object.entries(lock.files)) {\n\t\tconst expected = published.get(path);\n\t\tif (expected === undefined) {\n\t\t\trefuseStaleLedger(\n\t\t\t\t`it lists ${path}, which version ${lock.snapshotVersion} does not contain`,\n\t\t\t);\n\t\t}\n\t\tif (expected !== entry.sha256) {\n\t\t\trefuseStaleLedger(\n\t\t\t\t`its record of ${path} is not the published file`,\n\t\t\t);\n\t\t}\n\t}\n\tfor (const entry of manifest) {\n\t\t// `Object.hasOwn` rather than a lookup: a published file named\n\t\t// `constructor` or `toString` would find something on the prototype\n\t\t// and pass a truthiness check while being absent from the ledger.\n\t\tif (!Object.hasOwn(lock.files, entry.path)) {\n\t\t\trefuseStaleLedger(\n\t\t\t\t`version ${lock.snapshotVersion} contains ${entry.path}, which the lock does not list`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport async function computePushPlan(input: {\n\t/** An already-canonical root, as every guarded read resolves against it. */\n\troot: string;\n\tlock: InstructionsLock;\n\t/**\n\t * The PUBLISHED manifest for `lock.snapshotId`, straight from the server.\n\t *\n\t * The lock is an ordinary JSON file inside the checkout, so anything that\n\t * can write into the working tree can write into it. Treating it as the\n\t * list of files to read and send made that a way to exfiltrate: add\n\t * `private-notes.md` to the ledger with a hash that matches nothing, and\n\t * the next push reads that file and uploads its contents to a project\n\t * whose instructions never mentioned it.\n\t *\n\t * So the ledger is checked against the server's own manifest before a\n\t * single file is read. The manifest is the authority for WHICH paths this\n\t * command may touch; the lock only supplies the hashes it compares\n\t * against, and every one of those has to agree with the manifest too.\n\t */\n\tmanifest: readonly InstructionManifestEntry[];\n\t/** Paths to send as new files, from `--add`. */\n\tadded?: readonly string[];\n}): Promise<PushPlan> {\n\tconst { root, lock } = input;\n\tconst lockedPaths = Object.keys(lock.files);\n\n\tfor (const lockedPath of lockedPaths) {\n\t\tassertPushablePath(\n\t\t\tlockedPath,\n\t\t\t\"The lock names a path this tool will not touch.\",\n\t\t);\n\t}\n\tassertLockMatchesManifest(lock, input.manifest);\n\tconst lockCollision = findCollision(lockedPaths);\n\tif (lockCollision !== null) {\n\t\tthrow new Error(\n\t\t\t`Refusing to push: ${describeRejection({\n\t\t\t\tok: false,\n\t\t\t\treason: \"collision\",\n\t\t\t\tdetail: `${lockCollision.first} and ${lockCollision.second}`,\n\t\t\t})}. The lock names two paths this tool cannot tell apart.`,\n\t\t);\n\t}\n\n\tconst added: string[] = [];\n\tconst locked = new Set(lockedPaths);\n\tfor (const candidate of input.added ?? []) {\n\t\tassertPushablePath(candidate, \"That path cannot be pushed.\");\n\t\tif (locked.has(candidate)) {\n\t\t\t// Already part of the diff below, where its hash decides whether\n\t\t\t// anything is sent at all. Accepting it here too would send it\n\t\t\t// twice, and the server refuses a path named twice.\n\t\t\tcontinue;\n\t\t}\n\t\tif (added.includes(candidate)) {\n\t\t\tcontinue;\n\t\t}\n\t\tadded.push(candidate);\n\t}\n\tconst allCollision = findCollision([...lockedPaths, ...added]);\n\tif (allCollision !== null) {\n\t\tthrow new Error(\n\t\t\t`Refusing to push: ${describeRejection({\n\t\t\t\tok: false,\n\t\t\t\treason: \"collision\",\n\t\t\t\tdetail: `${allCollision.first} and ${allCollision.second}`,\n\t\t\t})}. Two of these paths are one file on a case-insensitive filesystem.`,\n\t\t);\n\t}\n\n\tconst entries: PushPlanEntry[] = [];\n\tconst changes: InstructionChange[] = [];\n\tconst unchanged: string[] = [];\n\n\tfor (const lockedPath of lockedPaths.sort()) {\n\t\tconst read = await readFileSafely(root, lockedPath);\n\t\tif (read === null) {\n\t\t\tentries.push({ path: lockedPath, action: \"delete\" });\n\t\t\tchanges.push({ op: \"delete\", path: lockedPath });\n\t\t\tcontinue;\n\t\t}\n\t\tconst actual = createHash(\"sha256\").update(read.bytes).digest(\"hex\");\n\t\tif (actual === lock.files[lockedPath]?.sha256) {\n\t\t\tunchanged.push(lockedPath);\n\t\t\tcontinue;\n\t\t}\n\t\tconst encoded = encodeContent(read.bytes);\n\t\tentries.push({\n\t\t\tpath: lockedPath,\n\t\t\taction: \"put\",\n\t\t\tsize: read.bytes.length,\n\t\t});\n\t\tchanges.push({ op: \"put\", path: lockedPath, ...encoded });\n\t}\n\n\tfor (const newPath of added.sort()) {\n\t\tconst read = await readFileSafely(root, newPath);\n\t\tif (read === null) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to push: there is no file at ${newPath}.`,\n\t\t\t);\n\t\t}\n\t\tconst encoded = encodeContent(read.bytes);\n\t\tentries.push({ path: newPath, action: \"put\", size: read.bytes.length });\n\t\tchanges.push({ op: \"put\", path: newPath, ...encoded });\n\t}\n\n\treturn { entries, changes, unchanged };\n}\n","/**\n * fabric mcp\n *\n * fabric mcp servers List accessible MCP servers\n * fabric mcp configs List your MCP configurations\n * fabric mcp configs show <id> Show a specific MCP configuration\n */\n\nimport type {\n\tFabricMcpConfig,\n\tFabricMcpConfigDetail,\n\tFabricMcpServer,\n} from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildMcpCommand(): Command {\n\tconst mcp = new Command(\"mcp\").description(\n\t\t\"Manage MCP servers and configurations\",\n\t);\n\n\t// -- servers -------------------------------------------------------------\n\tmcp.command(\"servers\")\n\t\t.description(\"List accessible MCP servers (system + custom)\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print server keys only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricMcpServer[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.mcp.listServers({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const s of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${s.key}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"key\",\n\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\"transport\",\n\t\t\t\t\t\t\"category\",\n\t\t\t\t\t\t\"isSystemProvided\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- configs -------------------------------------------------------------\n\tconst configs = new Command(\"configs\").description(\n\t\t\"Manage MCP configurations\",\n\t);\n\n\tconfigs\n\t\t.command(\"list\", { isDefault: true })\n\t\t.description(\"List your MCP configurations\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricMcpConfig[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.mcp.listConfigs({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const c of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${c.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"serverName\",\n\t\t\t\t\t\t\"displayName\",\n\t\t\t\t\t\t\"authType\",\n\t\t\t\t\t\t\"enabled\",\n\t\t\t\t\t\t\"status\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\tconfigs\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show a specific MCP configuration\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet config: FabricMcpConfigDetail;\n\t\t\t\ttry {\n\t\t\t\t\tconfig = await client.mcp.getConfig(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(config, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: config.id,\n\t\t\t\t\tServer: config.serverName ?? config.mcpServerId,\n\t\t\t\t\t\"Server Key\": config.serverKey ?? \"(none)\",\n\t\t\t\t\t\"Display Name\": config.displayName ?? \"(none)\",\n\t\t\t\t\t\"Base URL\": config.baseUrl ?? \"(none)\",\n\t\t\t\t\tTransport: config.transport ?? \"(default)\",\n\t\t\t\t\t\"Auth Type\": config.authType,\n\t\t\t\t\tEnabled: config.enabled ? \"yes\" : \"no\",\n\t\t\t\t\tStatus: config.status,\n\t\t\t\t\t\"Last Health Check\":\n\t\t\t\t\t\tconfig.lastHealthCheckAt?.slice(0, 19) ?? \"(never)\",\n\t\t\t\t\tCreated: config.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\tconfigs\n\t\t.command(\"delete <id>\")\n\t\t.description(\"Delete an MCP configuration\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"-y, --yes\", \"Skip confirmation prompt\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; yes?: boolean },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\n\t\t\t\tif (!opts.yes) {\n\t\t\t\t\tprocess.stderr.write(\n\t\t\t\t\t\t`Delete MCP config ${id}? This cannot be undone. Pass --yes to confirm.\\n`,\n\t\t\t\t\t);\n\t\t\t\t\tprocess.exit(2);\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tawait client.mcp.deleteConfig(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tprocess.stdout.write(`MCP config ${id} deleted.\\n`);\n\t\t\t},\n\t\t);\n\n\tmcp.addCommand(configs);\n\n\t// -- serve ---------------------------------------------------------------\n\tmcp.command(\"serve\")\n\t\t.description(\n\t\t\t\"Run a stdio MCP server exposing this workspace's whole integration catalog. \" +\n\t\t\t\t\"Point Claude Desktop, Cursor, or any MCP client at it.\",\n\t\t)\n\t\t.action(async () => {\n\t\t\t// Lazy import — avoids loading the MCP SDK when running other commands\n\t\t\t// and keeps the CLI binary cold-start fast.\n\t\t\tconst { runStdio } = await import(\"@fabricorg/sdk-mcp/stdio\");\n\t\t\tawait runStdio();\n\t\t});\n\n\treturn mcp;\n}\n","/**\n * fabric orgs\n *\n * fabric orgs list List orgs you belong to\n * fabric orgs show <slug> Show org details\n */\n\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildOrgsCommand(): Command {\n\tconst orgs = new Command(\"orgs\").description(\"Manage organizations\");\n\n\t// -- list ----------------------------------------------------------------\n\torgs.command(\"list\")\n\t\t.description(\"List organizations you belong to\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print slugs only\")\n\t\t.action(async (opts: { format: string; quiet?: boolean }) => {\n\t\t\tconst client = getClient();\n\t\t\tlet list: Awaited<ReturnType<typeof client.orgs.list>>;\n\t\t\ttry {\n\t\t\t\tlist = await client.orgs.list();\n\t\t\t} catch (err: unknown) {\n\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t}\n\n\t\t\tif (opts.quiet) {\n\t\t\t\tfor (const org of list) {\n\t\t\t\t\tprocess.stdout.write(`${org.slug}\\n`);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tprintOutput(list, {\n\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\tcolumns: [\"name\", \"slug\", \"role\", \"joinedAt\"],\n\t\t\t});\n\t\t});\n\n\t// -- show ----------------------------------------------------------------\n\torgs.command(\"show <slug>\")\n\t\t.description(\"Show details for an organization\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(async (slug: string, opts: { format: string }) => {\n\t\t\tconst client = getClient();\n\t\t\tlet list: Awaited<ReturnType<typeof client.orgs.list>>;\n\t\t\ttry {\n\t\t\t\tlist = await client.orgs.list();\n\t\t\t} catch (err: unknown) {\n\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t}\n\n\t\t\tconst org = list.find(\n\t\t\t\t(o: { slug: string; id: string }) =>\n\t\t\t\t\to.slug === slug || o.id === slug,\n\t\t\t);\n\t\t\tif (!org) {\n\t\t\t\tprintError(`Organization not found: ${slug}`, 4);\n\t\t\t}\n\n\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\tprintOutput(org, { format: fmt });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tprintRecord({\n\t\t\t\tName: org.name,\n\t\t\t\tSlug: org.slug,\n\t\t\t\tRole: org.role,\n\t\t\t\t\"Joined at\": String(org.joinedAt).slice(0, 10),\n\t\t\t\tLogo: org.logo ?? \"(none)\",\n\t\t\t});\n\t\t});\n\n\treturn orgs;\n}\n","/**\n * fabric projects\n *\n * fabric projects list List projects\n * fabric projects show <id> Show project details\n * fabric projects create <name> Create a project\n */\n\nimport type { FabricProject } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport {\n\tprintError,\n\tprintOutput,\n\tprintRecord,\n\tprintSuccess,\n} from \"../../lib/output.js\";\n\nexport function buildProjectsCommand(): Command {\n\tconst projects = new Command(\"projects\").description(\"Manage projects\");\n\n\t// -- list ----------------------------------------------------------------\n\tprojects\n\t\t.command(\"list\")\n\t\t.description(\"List projects\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\n\t\t\t\"--status <status>\",\n\t\t\t\"Filter by status: ACTIVE|DRAFT|COMPLETED|ARCHIVED\",\n\t\t)\n\t\t.option(\"--search <query>\", \"Search by name\")\n\t\t.option(\"--limit <n>\", \"Max results (default 20)\", \"20\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tstatus?: string;\n\t\t\t\tsearch?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricProject[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.projects.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tstatus: opts.status as\n\t\t\t\t\t\t\t| FabricProject[\"status\"]\n\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\tsearch: opts.search,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const p of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${p.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\"id\", \"name\", \"status\", \"createdAt\"],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- show ----------------------------------------------------------------\n\tprojects\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show project details\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet project: FabricProject;\n\t\t\t\ttry {\n\t\t\t\t\tproject = await client.projects.get(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(project, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: project.id,\n\t\t\t\t\tName: project.name,\n\t\t\t\t\tStatus: project.status,\n\t\t\t\t\tDescription: project.description ?? \"(none)\",\n\t\t\t\t\tRepository: project.repositoryUrl ?? \"(none)\",\n\t\t\t\t\tCreated: project.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- create --------------------------------------------------------------\n\tprojects\n\t\t.command(\"create <name>\")\n\t\t.description(\"Create a new project\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"-d, --description <text>\", \"Project description\")\n\t\t.option(\"--repo <url>\", \"Repository URL\")\n\t\t.option(\n\t\t\t\"--status <status>\",\n\t\t\t\"Initial status: DRAFT|ACTIVE (default: DRAFT)\",\n\t\t\t\"DRAFT\",\n\t\t)\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tname: string,\n\t\t\t\topts: {\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\tdescription?: string;\n\t\t\t\t\trepo?: string;\n\t\t\t\t\tstatus: string;\n\t\t\t\t\tformat: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet project: FabricProject;\n\t\t\t\ttry {\n\t\t\t\t\tproject = await client.projects.create({\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tdescription: opts.description,\n\t\t\t\t\t\trepositoryUrl: opts.repo,\n\t\t\t\t\t\tstatus: opts.status as \"DRAFT\" | \"ACTIVE\",\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(project, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintSuccess(`Project \"${project.name}\" created`);\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: project.id,\n\t\t\t\t\tName: project.name,\n\t\t\t\t\tStatus: project.status,\n\t\t\t\t\tDescription: project.description ?? \"(none)\",\n\t\t\t\t\tCreated: project.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- update --------------------------------------------------------------\n\tprojects\n\t\t.command(\"update <id>\")\n\t\t.description(\"Update a project\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--name <name>\", \"New name\")\n\t\t.option(\"-d, --description <text>\", \"New description\")\n\t\t.option(\"--repo <url>\", \"Repository URL\")\n\t\t.option(\"--status <status>\", \"Status: DRAFT|ACTIVE|COMPLETED|ARCHIVED\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: {\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\tname?: string;\n\t\t\t\t\tdescription?: string;\n\t\t\t\t\trepo?: string;\n\t\t\t\t\tstatus?: string;\n\t\t\t\t\tformat: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet project: FabricProject;\n\t\t\t\ttry {\n\t\t\t\t\tproject = await client.projects.update(id, {\n\t\t\t\t\t\tname: opts.name,\n\t\t\t\t\t\tdescription: opts.description,\n\t\t\t\t\t\trepositoryUrl: opts.repo,\n\t\t\t\t\t\tstatus: opts.status as\n\t\t\t\t\t\t\t| \"DRAFT\"\n\t\t\t\t\t\t\t| \"ACTIVE\"\n\t\t\t\t\t\t\t| \"COMPLETED\"\n\t\t\t\t\t\t\t| \"ARCHIVED\"\n\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(project, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: project.id,\n\t\t\t\t\tName: project.name,\n\t\t\t\t\tStatus: project.status,\n\t\t\t\t\tDescription: project.description ?? \"(none)\",\n\t\t\t\t\tUpdated: project.updatedAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn projects;\n}\n","/**\n * fabric prompts\n *\n * fabric prompts list List prompt templates\n * fabric prompts get <id> Get a prompt (prints latest version content)\n */\n\nimport type { FabricPrompt } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport {\n\tprintError,\n\tprintOutput,\n\tprintRecord,\n\tprintSuccess,\n} from \"../../lib/output.js\";\n\nexport function buildPromptsCommand(): Command {\n\tconst prompts = new Command(\"prompts\").description(\n\t\t\"Manage prompt templates\",\n\t);\n\n\t// -- list ----------------------------------------------------------------\n\tprompts\n\t\t.command(\"list\")\n\t\t.description(\"List prompt templates\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--search <query>\", \"Search by name\")\n\t\t.option(\"--category <cat>\", \"Filter by category\")\n\t\t.option(\"--limit <n>\", \"Max results\", \"50\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tsearch?: string;\n\t\t\t\tcategory?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricPrompt[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.prompts.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tsearch: opts.search,\n\t\t\t\t\t\tcategory: opts.category,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const p of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${p.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"key\",\n\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\"scope\",\n\t\t\t\t\t\t\"category\",\n\t\t\t\t\t\t\"updatedAt\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- get -----------------------------------------------------------------\n\tprompts\n\t\t.command(\"get <id>\")\n\t\t.description(\"Get a prompt (prints latest version content by default)\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: raw|table|json|yaml (default: raw)\",\n\t\t\t\"raw\",\n\t\t)\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet prompt: FabricPrompt;\n\t\t\t\ttry {\n\t\t\t\t\tprompt = await client.prompts.get(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"raw\" | \"table\" | \"json\" | \"yaml\";\n\n\t\t\t\tif (fmt === \"json\") {\n\t\t\t\t\tprintOutput(prompt, { format: \"json\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(prompt, { format: \"yaml\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst content = prompt.versions?.[0]?.content ?? \"(no content)\";\n\n\t\t\t\tif (fmt === \"raw\") {\n\t\t\t\t\tprocess.stdout.write(`${content}\\n`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// table: metadata + content block\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: prompt.id,\n\t\t\t\t\tKey: prompt.key,\n\t\t\t\t\tName: prompt.name,\n\t\t\t\t\tScope: prompt.scope,\n\t\t\t\t\tCategory: prompt.category ?? \"(none)\",\n\t\t\t\t\tTags: (prompt.tags ?? []).join(\", \") || \"(none)\",\n\t\t\t\t});\n\t\t\t\tprocess.stdout.write(`\\n--- Content ---\\n${content}\\n`);\n\t\t\t},\n\t\t);\n\n\t// -- create --------------------------------------------------------------\n\tprompts\n\t\t.command(\"create\")\n\t\t.description(\"Create a new prompt\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.requiredOption(\"--key <key>\", \"Prompt key (unique identifier)\")\n\t\t.requiredOption(\"--name <name>\", \"Prompt name\")\n\t\t.option(\"-d, --description <text>\", \"Prompt description\")\n\t\t.option(\"--content <text>\", \"Initial prompt content\")\n\t\t.option(\"--category <cat>\", \"Category\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tkey: string;\n\t\t\t\tname: string;\n\t\t\t\tdescription?: string;\n\t\t\t\tcontent?: string;\n\t\t\t\tcategory?: string;\n\t\t\t\tformat: string;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet prompt: FabricPrompt;\n\t\t\t\ttry {\n\t\t\t\t\tprompt = await client.prompts.create({\n\t\t\t\t\t\tkey: opts.key,\n\t\t\t\t\t\tname: opts.name,\n\t\t\t\t\t\tdescription: opts.description,\n\t\t\t\t\t\tcontent: opts.content,\n\t\t\t\t\t\tcategory: opts.category,\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(prompt, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintSuccess(`Prompt \"${prompt.name}\" created`);\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: prompt.id,\n\t\t\t\t\tKey: prompt.key,\n\t\t\t\t\tName: prompt.name,\n\t\t\t\t\tScope: prompt.scope,\n\t\t\t\t\tCreated: prompt.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- update --------------------------------------------------------------\n\tprompts\n\t\t.command(\"update <id>\")\n\t\t.description(\"Update a prompt\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--name <name>\", \"New name\")\n\t\t.option(\"-d, --description <text>\", \"New description\")\n\t\t.option(\"--category <cat>\", \"Category\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: {\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\tname?: string;\n\t\t\t\t\tdescription?: string;\n\t\t\t\t\tcategory?: string;\n\t\t\t\t\tformat: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet prompt: FabricPrompt;\n\t\t\t\ttry {\n\t\t\t\t\tprompt = await client.prompts.update(id, {\n\t\t\t\t\t\tname: opts.name,\n\t\t\t\t\t\tdescription: opts.description,\n\t\t\t\t\t\tcategory: opts.category,\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(prompt, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: prompt.id,\n\t\t\t\t\tKey: prompt.key,\n\t\t\t\t\tName: prompt.name,\n\t\t\t\t\tScope: prompt.scope,\n\t\t\t\t\tUpdated: prompt.updatedAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn prompts;\n}\n","/**\n * fabric reports\n *\n * fabric reports templates list List report templates\n * fabric reports templates show <id> Show template details\n * fabric reports executions list List report executions\n */\n\nimport type {\n\tFabricReportExecution,\n\tFabricReportTemplate,\n} from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildReportsCommand(): Command {\n\tconst reports = new Command(\"reports\").description(\n\t\t\"Manage report templates and executions\",\n\t);\n\n\t// -- templates -----------------------------------------------------------\n\tconst templates = new Command(\"templates\").description(\n\t\t\"Manage report templates\",\n\t);\n\n\ttemplates\n\t\t.command(\"list\", { isDefault: true })\n\t\t.description(\"List report templates\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--search <query>\", \"Search by name\")\n\t\t.option(\"--category <cat>\", \"Filter by category\")\n\t\t.option(\"--limit <n>\", \"Max results (default 20)\", \"20\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tsearch?: string;\n\t\t\t\tcategory?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricReportTemplate[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.reports.listTemplates({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tsearch: opts.search,\n\t\t\t\t\t\tcategory: opts.category,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const t of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${t.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\"templateType\",\n\t\t\t\t\t\t\"scope\",\n\t\t\t\t\t\t\"usageCount\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\ttemplates\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show report template details\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet tmpl: FabricReportTemplate;\n\t\t\t\ttry {\n\t\t\t\t\ttmpl = await client.reports.getTemplate(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(tmpl, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: tmpl.id,\n\t\t\t\t\tName: tmpl.name,\n\t\t\t\t\tType: tmpl.templateType,\n\t\t\t\t\tScope: tmpl.scope,\n\t\t\t\t\tCategory: tmpl.category ?? \"(none)\",\n\t\t\t\t\tTags: tmpl.tags.join(\", \") || \"(none)\",\n\t\t\t\t\tPublic: tmpl.isPublic ? \"yes\" : \"no\",\n\t\t\t\t\t\"Use Count\": String(tmpl.usageCount),\n\t\t\t\t\tDescription: tmpl.description ?? \"(none)\",\n\t\t\t\t\tUpdated: tmpl.updatedAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treports.addCommand(templates);\n\n\t// -- executions ----------------------------------------------------------\n\tconst executions = new Command(\"executions\").description(\n\t\t\"View report executions\",\n\t);\n\n\texecutions\n\t\t.command(\"list\", { isDefault: true })\n\t\t.description(\"List report executions\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--limit <n>\", \"Max results (default 20)\", \"20\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricReportExecution[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.reports.listExecutions({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const e of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${e.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"templateId\",\n\t\t\t\t\t\t\"status\",\n\t\t\t\t\t\t\"startedAt\",\n\t\t\t\t\t\t\"completedAt\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treports.addCommand(executions);\n\n\treturn reports;\n}\n","/**\n * fabric skills\n *\n * fabric skills list Browse skill definitions\n * fabric skills show <id> Show skill details\n */\n\nimport type { FabricSkill } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildSkillsCommand(): Command {\n\tconst skills = new Command(\"skills\").description(\n\t\t\"Browse skill definitions\",\n\t);\n\n\t// -- list ----------------------------------------------------------------\n\tskills\n\t\t.command(\"list\")\n\t\t.description(\"List skills\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--search <query>\", \"Search by name\")\n\t\t.option(\"--category <cat>\", \"Filter by category\")\n\t\t.option(\"--limit <n>\", \"Max results\", \"50\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print slugs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tsearch?: string;\n\t\t\t\tcategory?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricSkill[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.skills.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tsearch: opts.search,\n\t\t\t\t\t\tcategory: opts.category,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const s of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${s.slug}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\"slug\", \"name\", \"category\", \"scope\", \"useCount\"],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- show ----------------------------------------------------------------\n\tskills\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show skill details (accepts ID or slug)\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(async (id: string, opts: { format: string }) => {\n\t\t\tconst client = getClient();\n\t\t\tlet skill: FabricSkill;\n\t\t\ttry {\n\t\t\t\tskill = await client.skills.get(id);\n\t\t\t} catch (err: unknown) {\n\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t}\n\n\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\tprintOutput(skill, { format: fmt });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tprintRecord({\n\t\t\t\tID: skill.id,\n\t\t\t\tSlug: skill.slug,\n\t\t\t\tName: skill.name,\n\t\t\t\tCategory: skill.category ?? \"(none)\",\n\t\t\t\tScope: skill.scope,\n\t\t\t\tTags: skill.tags.join(\", \") || \"(none)\",\n\t\t\t\tPublished: skill.isPublished ? \"yes\" : \"no\",\n\t\t\t\t\"Use Count\": String(skill.useCount),\n\t\t\t\tVersion: String(skill.version),\n\t\t\t\tDescription: skill.description,\n\t\t\t\tUpdated: skill.updatedAt.slice(0, 10),\n\t\t\t});\n\t\t});\n\n\treturn skills;\n}\n","/**\n * fabric workflows\n *\n * fabric workflows list List workflows\n * fabric workflows show <id> Show workflow details\n * fabric workflows trigger <id> Trigger a workflow execution\n * fabric workflows status <id> <execId> Get execution status\n */\n\nimport type { FabricExecution, FabricWorkflow } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport {\n\tprintError,\n\tprintOutput,\n\tprintRecord,\n\tprintSuccess,\n} from \"../../lib/output.js\";\n\nexport function buildWorkflowsCommand(): Command {\n\tconst workflows = new Command(\"workflows\").description(\"Manage workflows\");\n\n\t// -- list ----------------------------------------------------------------\n\tworkflows\n\t\t.command(\"list\")\n\t\t.description(\"List workflows\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--status <status>\", \"Filter: DRAFT|ACTIVE|PAUSED|ARCHIVED\")\n\t\t.option(\"--search <query>\", \"Search by name\")\n\t\t.option(\"--limit <n>\", \"Max results\", \"20\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tstatus?: string;\n\t\t\t\tsearch?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricWorkflow[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.workflows.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tstatus: opts.status as\n\t\t\t\t\t\t\t| FabricWorkflow[\"status\"]\n\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\tsearch: opts.search,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const w of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${w.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\"status\",\n\t\t\t\t\t\t\"triggerType\",\n\t\t\t\t\t\t\"createdAt\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- show ----------------------------------------------------------------\n\tworkflows\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show workflow details\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet wf: FabricWorkflow;\n\t\t\t\ttry {\n\t\t\t\t\twf = await client.workflows.get(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(wf, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: wf.id,\n\t\t\t\t\tName: wf.name,\n\t\t\t\t\tStatus: wf.status,\n\t\t\t\t\tTrigger: wf.triggerType,\n\t\t\t\t\tVersion: String(wf.version),\n\t\t\t\t\tCreated: wf.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- trigger -------------------------------------------------------------\n\tworkflows\n\t\t.command(\"trigger <id>\")\n\t\t.description(\"Trigger a workflow execution\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--input <json>\", \"JSON input for triggerData\", \"{}\")\n\t\t.option(\"--vars <json>\", \"JSON variables\", \"{}\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: {\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\tinput: string;\n\t\t\t\t\tvars: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\n\t\t\t\tlet triggerData: Record<string, unknown> = {};\n\t\t\t\tlet variables: Record<string, unknown> = {};\n\t\t\t\ttry {\n\t\t\t\t\ttriggerData = JSON.parse(opts.input);\n\t\t\t\t\tvariables = JSON.parse(opts.vars);\n\t\t\t\t} catch {\n\t\t\t\t\tprintError(\"--input and --vars must be valid JSON\", 2);\n\t\t\t\t}\n\n\t\t\t\tlet result: {\n\t\t\t\t\texecutionId: string;\n\t\t\t\t\tworkflowId: string;\n\t\t\t\t\tstatus: string;\n\t\t\t\t};\n\t\t\t\ttry {\n\t\t\t\t\tresult = await client.workflows.trigger(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\ttriggerData,\n\t\t\t\t\t\tvariables,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tprintSuccess(\"Workflow triggered\");\n\t\t\t\tprocess.stdout.write(` Execution ID: ${result.executionId}\\n`);\n\t\t\t\tprocess.stdout.write(` Status: ${result.status}\\n`);\n\t\t\t},\n\t\t);\n\n\t// -- status --------------------------------------------------------------\n\tworkflows\n\t\t.command(\"status <id> <execId>\")\n\t\t.description(\"Get workflow execution status\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\texecId: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet exec: FabricExecution;\n\t\t\t\ttry {\n\t\t\t\t\texec = await client.workflows.getExecution(id, execId, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(exec, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: exec.id,\n\t\t\t\t\t\"Workflow ID\": exec.workflowId,\n\t\t\t\t\tStatus: exec.status,\n\t\t\t\t\t\"Trigger type\": exec.triggerType,\n\t\t\t\t\tStarted: exec.startedAt?.slice(0, 19) ?? \"(not started)\",\n\t\t\t\t\tCompleted: exec.completedAt?.slice(0, 19) ?? \"(running)\",\n\t\t\t\t\tError: exec.error ?? \"(none)\",\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn workflows;\n}\n","/**\n * fabric workspaces\n *\n * fabric workspaces list List workspaces\n * fabric workspaces show <id> Show workspace details\n */\n\nimport type { FabricWorkspace, FabricWorkspaceDetail } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildWorkspacesCommand(): Command {\n\tconst workspaces = new Command(\"workspaces\").description(\n\t\t\"Manage workspaces\",\n\t);\n\n\t// -- list ----------------------------------------------------------------\n\tworkspaces\n\t\t.command(\"list\")\n\t\t.description(\"List workspaces\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--search <query>\", \"Search by name\")\n\t\t.option(\"--status <status>\", \"Filter: ACTIVE|ARCHIVED\")\n\t\t.option(\"--limit <n>\", \"Max results (default 20)\", \"20\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tsearch?: string;\n\t\t\t\tstatus?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricWorkspace[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.workspaces.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tsearch: opts.search,\n\t\t\t\t\t\tstatus: opts.status as\n\t\t\t\t\t\t\t| \"ACTIVE\"\n\t\t\t\t\t\t\t| \"ARCHIVED\"\n\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const w of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${w.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\"type\",\n\t\t\t\t\t\t\"status\",\n\t\t\t\t\t\t\"documentCount\",\n\t\t\t\t\t\t\"updatedAt\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- show ----------------------------------------------------------------\n\tworkspaces\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show workspace details\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet ws: FabricWorkspaceDetail;\n\t\t\t\ttry {\n\t\t\t\t\tws = await client.workspaces.get(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(ws, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: ws.id,\n\t\t\t\t\tName: ws.name,\n\t\t\t\t\tType: ws.type,\n\t\t\t\t\tStatus: ws.status,\n\t\t\t\t\tDescription: ws.description ?? \"(none)\",\n\t\t\t\t\tDocuments: String(ws.documentCount),\n\t\t\t\t\tConversations: String(ws.conversationCount),\n\t\t\t\t\tUpdated: ws.updatedAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn workspaces;\n}\n"],"mappings":"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","names":["Command","_a","_a","rows","cols","_a","Command","Command","FabricAuthError","FabricClient","Command","Command","_a","FabricClient","FabricAuthError","Command","Command","Command","Command","_a","Command","Command","_a","Command","lstat","path","Command","path","_a","_a","path","path","createHash","path","lstat","path","path","lstat","byPath","group","_a","_a","before","_a","Command","path","lstat","Command","Command","Command","Command","_a","Command","Command","_a","path","Command","createHash","_a","createHash","_a","path","path","_a","group","readFile","path","SHA256_HEX","path","readFile","lockProblem","serializeLock","createHash","SHA256_HEX","createHash","_a","createHash","createHash","_a","createHash","path","_a","createHash","HOOK_DEADLINE_MS","PUSH_TIMEOUT_MS","Command","run","runPush","_a","path","readLockForProject","Command","Command","_a","config","Command","Command","_a","Command","Command","_a","Command","Command","_a","Command","Command","_a","Command","Command","_a","Command","Command","_a","Command","Command","_a","Command"]}
1
+ {"version":3,"sources":["../src/bin/fabric.ts","../package.json","../src/commands/agents/index.ts","../src/lib/client.ts","../src/lib/config.ts","../src/lib/output.ts","../src/lib/context.ts","../src/commands/auth/keys.ts","../src/commands/auth/login.ts","../src/commands/auth/logout.ts","../src/commands/auth/whoami.ts","../src/commands/chats/index.ts","../src/commands/completion/index.ts","../src/commands/context/index.ts","../src/lib/command-boundary.ts","../src/lib/context-sync/lock.ts","../src/lib/instructions/safe-write.ts","../src/lib/instructions/paths.ts","../src/lib/context-sync/source-path.ts","../src/lib/context-sync/classify.ts","../src/lib/context-sync/ignore.ts","../src/lib/context-sync/walk.ts","../src/lib/context-sync/plan.ts","../src/lib/context-sync/push.ts","../src/lib/context-sync/report.ts","../src/commands/ctx/index.ts","../src/commands/features/index.ts","../src/commands/frames/index.ts","../src/commands/instructions/index.ts","../src/lib/instructions/apply.ts","../src/lib/instructions/plan.ts","../src/lib/instructions/lock.ts","../src/lib/instructions/bundle.ts","../src/lib/instructions/checkout.ts","../src/lib/instructions/checks.ts","../src/lib/instructions/git.ts","../src/lib/instructions/repository-identity.ts","../src/lib/instructions/doctor.ts","../src/lib/instructions/hook.ts","../src/lib/instructions/manifest.ts","../src/lib/instructions/mcp-config.ts","../src/lib/instructions/path-lookup.ts","../src/lib/instructions/hook-timing.ts","../src/lib/instructions/lesson-prompt.ts","../src/lib/instructions/open-proposals.ts","../src/lib/instructions/pull-request-wait.ts","../src/lib/instructions/push.ts","../src/commands/mcp/index.ts","../src/commands/orgs/index.ts","../src/commands/projects/index.ts","../src/commands/prompts/index.ts","../src/commands/reports/index.ts","../src/commands/skills/index.ts","../src/commands/workflows/index.ts","../src/commands/workspaces/index.ts"],"sourcesContent":["/**\n * @fabricorg/cli — fabric command\n *\n * Usage: fabric <command> [subcommand] [options]\n *\n * Exit codes:\n * 0 success\n * 1 general failure\n * 2 invalid usage / bad arguments\n * 3 auth failure\n * 4 not found\n * 5 forbidden\n * 6 rate limited\n * 7 validation error\n */\n\nimport { Command } from \"commander\";\nimport packageJson from \"../../package.json\";\nimport { buildAgentsCommand } from \"../commands/agents/index.js\";\nimport { buildKeysCommand } from \"../commands/auth/keys.js\";\nimport { buildLoginCommand } from \"../commands/auth/login.js\";\nimport { buildLogoutCommand } from \"../commands/auth/logout.js\";\nimport { buildWhoamiCommand } from \"../commands/auth/whoami.js\";\nimport { buildChatsCommand } from \"../commands/chats/index.js\";\nimport { buildCompletionCommand } from \"../commands/completion/index.js\";\nimport { buildContextCommand } from \"../commands/context/index.js\";\nimport { buildCtxCommand } from \"../commands/ctx/index.js\";\nimport { buildFeaturesCommand } from \"../commands/features/index.js\";\nimport { buildFramesCommand } from \"../commands/frames/index.js\";\nimport { buildInstructionsCommand } from \"../commands/instructions/index.js\";\nimport { buildMcpCommand } from \"../commands/mcp/index.js\";\nimport { buildOrgsCommand } from \"../commands/orgs/index.js\";\nimport { buildProjectsCommand } from \"../commands/projects/index.js\";\nimport { buildPromptsCommand } from \"../commands/prompts/index.js\";\nimport { buildReportsCommand } from \"../commands/reports/index.js\";\nimport { buildSkillsCommand } from \"../commands/skills/index.js\";\nimport { buildWorkflowsCommand } from \"../commands/workflows/index.js\";\nimport { buildWorkspacesCommand } from \"../commands/workspaces/index.js\";\nimport { getConfigPath } from \"../lib/config.js\";\n\nconst program = new Command();\n\nprogram\n\t.name(\"fabric\")\n\t.description(\"Fabric AI platform CLI\")\n\t.version(packageJson.version)\n\t.option(\n\t\t\"--format <format>\",\n\t\t\"Output format: table|json|yaml|csv\",\n\t\tprocess.env.FABRIC_FORMAT ?? \"table\",\n\t);\n\n// ---------------------------------------------------------------------------\n// fabric auth\n// ---------------------------------------------------------------------------\nconst auth = new Command(\"auth\").description(\n\t\"Authenticate and manage API keys\",\n);\nauth.addCommand(buildLoginCommand());\nauth.addCommand(buildLogoutCommand());\nauth.addCommand(buildWhoamiCommand());\nauth.addCommand(buildKeysCommand());\nprogram.addCommand(auth);\n\n// ---------------------------------------------------------------------------\n// fabric ctx\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildCtxCommand());\n\n// ---------------------------------------------------------------------------\n// fabric orgs\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildOrgsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric projects\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildProjectsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric features\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildFeaturesCommand());\n\n// ---------------------------------------------------------------------------\n// fabric workflows\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildWorkflowsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric prompts\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildPromptsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric agents\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildAgentsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric skills\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildSkillsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric instructions\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildInstructionsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric context — project Context (knowledge sources), not `fabric ctx`\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildContextCommand());\n\n// ---------------------------------------------------------------------------\n// fabric mcp\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildMcpCommand());\n\n// ---------------------------------------------------------------------------\n// fabric frames\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildFramesCommand());\n\n// ---------------------------------------------------------------------------\n// fabric workspaces\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildWorkspacesCommand());\n\n// ---------------------------------------------------------------------------\n// fabric chats\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildChatsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric reports\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildReportsCommand());\n\n// ---------------------------------------------------------------------------\n// fabric completion\n// ---------------------------------------------------------------------------\nprogram.addCommand(buildCompletionCommand());\n\n// ---------------------------------------------------------------------------\n// fabric config\n// ---------------------------------------------------------------------------\nconst config = new Command(\"config\").description(\"Show CLI configuration\");\nconfig\n\t.command(\"path\")\n\t.description(\"Print the path to the config file\")\n\t.action(() => {\n\t\tprocess.stdout.write(`${getConfigPath()}\\n`);\n\t});\nprogram.addCommand(config);\n\n// ---------------------------------------------------------------------------\n// Global error handler — structured JSON for --format json\n// ---------------------------------------------------------------------------\nprocess.on(\"unhandledRejection\", (reason) => {\n\tconst message = reason instanceof Error ? reason.message : String(reason);\n\tif (process.env.FABRIC_FORMAT === \"json\") {\n\t\tprocess.stderr.write(\n\t\t\tJSON.stringify({ error: { message, code: \"UNHANDLED_ERROR\" } }) +\n\t\t\t\t\"\\n\",\n\t\t);\n\t} else {\n\t\tprocess.stderr.write(`✗ ${message}\\n`);\n\t}\n\tprocess.exit(1);\n});\n\nprogram.parse(process.argv);\n","{\n\t\"name\": \"@fabricorg/cli\",\n\t\"version\": \"0.4.0\",\n\t\"description\": \"CLI for the Fabric AI platform\",\n\t\"keywords\": [\n\t\t\"fabric\",\n\t\t\"ai\",\n\t\t\"cli\",\n\t\t\"developer-tools\"\n\t],\n\t\"homepage\": \"https://fabric.pro\",\n\t\"license\": \"MIT\",\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"git+https://github.com/Fabric-Pro/fabric-oss.git\",\n\t\t\"directory\": \"packages/cli\"\n\t},\n\t\"type\": \"module\",\n\t\"bin\": {\n\t\t\"fabric\": \"./dist/fabric.js\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"publishConfig\": {\n\t\t\"access\": \"public\"\n\t},\n\t\"scripts\": {\n\t\t\"build\": \"tsup\",\n\t\t\"dev\": \"tsup --watch\",\n\t\t\"type-check\": \"tsc --noEmit\",\n\t\t\"test\": \"vitest run\",\n\t\t\"test:watch\": \"vitest\",\n\t\t\"fabric\": \"node --import tsx/esm src/bin/fabric.ts\"\n\t},\n\t\"dependencies\": {\n\t\t\"@fabricorg/sdk\": \"workspace:*\",\n\t\t\"@fabricorg/sdk-mcp\": \"workspace:*\",\n\t\t\"cli-table3\": \"^0.6.5\",\n\t\t\"commander\": \"^13.1.0\",\n\t\t\"conf\": \"^13.1.0\",\n\t\t\"fflate\": \"^0.8.3\",\n\t\t\"ignore\": \"7.0.9\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@repo/tsconfig\": \"workspace:*\",\n\t\t\"tsup\": \"^8.0.0\",\n\t\t\"tsx\": \"^4.21.0\",\n\t\t\"typescript\": \"5.9.3\",\n\t\t\"vitest\": \"^4.1.11\"\n\t}\n}\n","/**\n * fabric agents\n *\n * fabric agents list List agents\n * fabric agents show <id> Show agent details\n */\n\nimport type { FabricAgent } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildAgentsCommand(): Command {\n\tconst agents = new Command(\"agents\").description(\"Manage agents\");\n\n\t// -- list ----------------------------------------------------------------\n\tagents\n\t\t.command(\"list\")\n\t\t.description(\"List agents\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--status <status>\", \"Filter: ACTIVE|INACTIVE|DEPRECATED\")\n\t\t.option(\"--limit <n>\", \"Max results\", \"50\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tstatus?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricAgent[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.agents.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tstatus: opts.status as\n\t\t\t\t\t\t\t| FabricAgent[\"status\"]\n\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const a of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${a.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\"displayName\",\n\t\t\t\t\t\t\"framework\",\n\t\t\t\t\t\t\"status\",\n\t\t\t\t\t\t\"createdAt\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- show ----------------------------------------------------------------\n\tagents\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show agent details\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet agent: FabricAgent;\n\t\t\t\ttry {\n\t\t\t\t\tagent = await client.agents.get(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(agent, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: agent.id,\n\t\t\t\t\t\"Agent ID\": agent.agentId,\n\t\t\t\t\tName: agent.name,\n\t\t\t\t\t\"Display name\": agent.displayName,\n\t\t\t\t\tFramework: agent.framework,\n\t\t\t\t\tStatus: agent.status,\n\t\t\t\t\t\"Deployment URL\": agent.deploymentUrl ?? \"(none)\",\n\t\t\t\t\tCreated: agent.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- execute -------------------------------------------------------------\n\tagents\n\t\t.command(\"execute <id>\")\n\t\t.description(\"Execute an agent\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--input <json>\", 'Input JSON (e.g. \\'{\"key\":\"value\"}\\')')\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: {\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\tinput?: string;\n\t\t\t\t\tformat: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\n\t\t\t\tlet inputObj: Record<string, unknown> = {};\n\t\t\t\tif (opts.input) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tinputObj = JSON.parse(opts.input);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tprintError(\"--input must be valid JSON\", 2);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlet result: import(\"@fabricorg/sdk\").FabricAgentExecution;\n\t\t\t\ttry {\n\t\t\t\t\tresult = await client.agents.execute(id, {\n\t\t\t\t\t\tinput: inputObj,\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(result, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\t\"Task ID\": result.taskId,\n\t\t\t\t\t\"Workflow ID\": result.workflowId,\n\t\t\t\t\t\"Run ID\": result.runId ?? \"(pending)\",\n\t\t\t\t\tStatus: result.status,\n\t\t\t\t\t...(result.warning ? { Warning: result.warning } : {}),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn agents;\n}\n","/**\n * Returns a configured FabricClient for CLI commands.\n * Exits with a clear error if no API key is available.\n */\n\nimport { FabricAuthError, FabricClient } from \"@fabricorg/sdk\";\nimport { getApiKey, getBaseUrl } from \"./config.js\";\nimport { printError } from \"./output.js\";\n\nexport interface ClientOverrides {\n\t/**\n\t * Retry policy. The SDK's default retries twice, and its timeout is PER\n\t * ATTEMPT, so a \"5 second\" call can really take about 15.75 seconds with\n\t * backoff. Session-hook mode turns retries off so its own deadline is the\n\t * only bound that matters.\n\t */\n\tretry?: { maxRetries: number };\n\t/**\n\t * Per-request timeout. The SDK sets this on the CLIENT, not per call, so\n\t * a command that must answer fast — the session-start instructions check\n\t * — builds its own client rather than reaching for a per-call option that\n\t * does not exist.\n\t */\n\ttimeoutMs?: number;\n}\n\nexport function getClient(overrides: ClientOverrides = {}): FabricClient {\n\tconst apiKey = getApiKey();\n\n\tif (!apiKey) {\n\t\tprintError(\n\t\t\t\"Not authenticated. Run:\\n fabric auth login --key <api-key>\",\n\t\t\t3,\n\t\t);\n\t}\n\n\ttry {\n\t\treturn new FabricClient({\n\t\t\tapiKey,\n\t\t\tbaseUrl: getBaseUrl(),\n\t\t\t...(overrides.timeoutMs !== undefined\n\t\t\t\t? { timeoutMs: overrides.timeoutMs }\n\t\t\t\t: {}),\n\t\t\t...(overrides.retry !== undefined\n\t\t\t\t? { retry: overrides.retry }\n\t\t\t\t: {}),\n\t\t});\n\t} catch (err: unknown) {\n\t\tif (err instanceof FabricAuthError) {\n\t\t\tprintError(err.message, 3);\n\t\t}\n\t\tthrow err;\n\t}\n}\n","/**\n * Config storage for @fabricorg/cli\n *\n * Persists to XDG_CONFIG_HOME/fabricai/config.json (Linux/macOS)\n * or %APPDATA%\\fabricai\\config.json (Windows).\n *\n * The API key is stored as-is in the config file with 0600 permissions.\n * Future: migrate to system keychain.\n */\n\nimport Conf from \"conf\";\n\ninterface CliConfig {\n\t/** Active profile name */\n\tactiveProfile: string;\n\tprofiles: Record<string, ProfileConfig>;\n\t/** Default output format */\n\tdefaultFormat: \"table\" | \"json\" | \"yaml\" | \"csv\";\n}\n\ninterface ProfileConfig {\n\t/** API key for this profile */\n\tapiKey?: string;\n\t/** Override base URL (e.g. for self-hosted) */\n\tbaseUrl?: string;\n\t/** Default context for commands */\n\tdefaultContext?: ContextConfig;\n}\n\nexport type ContextConfig =\n\t| { type: \"personal\" }\n\t| { type: \"org\"; slug: string };\n\nconst DEFAULTS: CliConfig = {\n\tactiveProfile: \"default\",\n\tprofiles: {},\n\tdefaultFormat: \"table\",\n};\n\nlet _store: Conf<CliConfig> | undefined;\n\nfunction getStore(): Conf<CliConfig> {\n\tif (!_store) {\n\t\t_store = new Conf<CliConfig>({\n\t\t\tprojectName: \"fabricai\",\n\t\t\tdefaults: DEFAULTS,\n\t\t});\n\t}\n\treturn _store;\n}\n\nfunction getConfig(): CliConfig {\n\treturn getStore().store;\n}\n\nfunction getActiveProfile(): ProfileConfig {\n\tconst cfg = getConfig();\n\treturn cfg.profiles[cfg.activeProfile] ?? {};\n}\n\nexport function getApiKey(): string | undefined {\n\t// Env var takes precedence over stored config\n\tif (process.env.FABRIC_API_KEY) {\n\t\treturn process.env.FABRIC_API_KEY;\n\t}\n\treturn getActiveProfile().apiKey;\n}\n\nexport function getBaseUrl(): string | undefined {\n\tif (process.env.FABRIC_BASE_URL) {\n\t\treturn process.env.FABRIC_BASE_URL;\n\t}\n\treturn getActiveProfile().baseUrl;\n}\n\nexport function getDefaultContext(): ContextConfig | undefined {\n\t// Env var takes precedence\n\tif (process.env.FABRIC_ORG) {\n\t\treturn { type: \"org\", slug: process.env.FABRIC_ORG };\n\t}\n\tif (process.env.FABRIC_PERSONAL === \"1\") {\n\t\treturn { type: \"personal\" };\n\t}\n\treturn getActiveProfile().defaultContext;\n}\n\nexport function getOutputFormat(): \"table\" | \"json\" | \"yaml\" | \"csv\" {\n\tif (\n\t\tprocess.env.FABRIC_FORMAT === \"json\" ||\n\t\tprocess.env.FABRIC_FORMAT === \"yaml\" ||\n\t\tprocess.env.FABRIC_FORMAT === \"csv\"\n\t) {\n\t\treturn process.env.FABRIC_FORMAT as \"json\" | \"yaml\" | \"csv\";\n\t}\n\treturn getConfig().defaultFormat;\n}\n\nexport interface SaveApiKeyOptions {\n\t/** Persisted only when a login explicitly selected a deployment URL. */\n\tbaseUrl?: string;\n}\n\n/**\n * Save credentials into the active profile in one profile update.\n *\n * `FABRIC_BASE_URL` remains an execution-time override: callers only pass a\n * base URL here when the person explicitly chose it with `--base-url`.\n */\nexport function saveApiKey(\n\tapiKey: string,\n\t{ baseUrl }: SaveApiKeyOptions = {},\n): void {\n\tconst store = getStore();\n\tconst profile = store.get(\"activeProfile\") as string;\n\tconst profiles = store.get(\"profiles\") as CliConfig[\"profiles\"];\n\tconst current = profiles[profile] ?? {};\n\tstore.set(\"profiles\", {\n\t\t...profiles,\n\t\t[profile]: {\n\t\t\t...current,\n\t\t\tapiKey,\n\t\t\t...(baseUrl === undefined ? {} : { baseUrl }),\n\t\t},\n\t});\n}\n\nexport function clearApiKey(profile?: string): void {\n\tconst store = getStore();\n\tconst active = profile ?? (store.get(\"activeProfile\") as string);\n\tconst profiles = store.get(\"profiles\") as CliConfig[\"profiles\"];\n\tconst { apiKey: _, ...rest } = profiles[active] ?? {};\n\tstore.set(\"profiles\", { ...profiles, [active]: rest });\n}\n\nexport function saveDefaultContext(ctx: ContextConfig, profile?: string): void {\n\tconst store = getStore();\n\tconst active = profile ?? (store.get(\"activeProfile\") as string);\n\tconst profiles = store.get(\"profiles\") as CliConfig[\"profiles\"];\n\tstore.set(\"profiles\", {\n\t\t...profiles,\n\t\t[active]: { ...(profiles[active] ?? {}), defaultContext: ctx },\n\t});\n}\n\nexport function getConfigPath(): string {\n\treturn getStore().path;\n}\n","/**\n * Output formatting for @fabricorg/cli\n *\n * Supports: table (default), json, yaml, csv, quiet (IDs only)\n */\n\nimport Table from \"cli-table3\";\nimport { getOutputFormat } from \"./config.js\";\n\ntype OutputFormat = \"table\" | \"json\" | \"yaml\" | \"csv\" | \"quiet\";\n\nexport interface OutputOptions {\n\tformat?: OutputFormat;\n\t/** Column names to include in table/csv output (in order) */\n\tcolumns?: string[];\n\t/** Key to use for --quiet / IDs-only output */\n\tidKey?: string;\n}\n\n/** Print data to stdout in the selected format. */\nexport function printOutput(data: unknown, opts: OutputOptions = {}): void {\n\tconst format = opts.format ?? (getOutputFormat() as OutputFormat);\n\n\tif (format === \"json\") {\n\t\tprocess.stdout.write(`${JSON.stringify(data, null, 2)}\\n`);\n\t\treturn;\n\t}\n\n\tif (format === \"yaml\") {\n\t\tprocess.stdout.write(`${toYaml(data)}\\n`);\n\t\treturn;\n\t}\n\n\tif (format === \"quiet\") {\n\t\tconst rows = Array.isArray(data) ? data : [data];\n\t\tconst key = opts.idKey ?? \"id\";\n\t\tfor (const row of rows) {\n\t\t\tconst val = (row as Record<string, unknown>)[key];\n\t\t\tif (val !== undefined) {\n\t\t\t\tprocess.stdout.write(`${String(val)}\\n`);\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\n\tif (format === \"csv\") {\n\t\tconst rows = Array.isArray(data) ? data : [data];\n\t\tif (rows.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst cols = opts.columns ?? Object.keys(rows[0] as object);\n\t\tprocess.stdout.write(`${cols.map(csvEscape).join(\",\")}\\n`);\n\t\tfor (const row of rows) {\n\t\t\tprocess.stdout.write(\n\t\t\t\t`${cols\n\t\t\t\t\t.map((c) =>\n\t\t\t\t\t\tcsvEscape(\n\t\t\t\t\t\t\tString((row as Record<string, unknown>)[c] ?? \"\"),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\t.join(\",\")}\\n`,\n\t\t\t);\n\t\t}\n\t\treturn;\n\t}\n\n\t// Default: table\n\tconst rows = Array.isArray(data) ? data : [data];\n\tif (rows.length === 0) {\n\t\tprocess.stdout.write(\"(no results)\\n\");\n\t\treturn;\n\t}\n\tconst cols = opts.columns ?? Object.keys(rows[0] as object);\n\tconst table = new Table({ head: cols, style: { head: [\"cyan\"] } });\n\tfor (const row of rows) {\n\t\ttable.push(\n\t\t\tcols.map((c) => formatCell((row as Record<string, unknown>)[c])),\n\t\t);\n\t}\n\tprocess.stdout.write(`${table.toString()}\\n`);\n}\n\n/** Print a single key-value object as aligned pairs */\nexport function printRecord(\n\tdata: Record<string, unknown>,\n\topts: OutputOptions = {},\n): void {\n\tconst format = opts.format ?? (getOutputFormat() as OutputFormat);\n\tif (format === \"json\") {\n\t\tprintOutput(data, opts);\n\t\treturn;\n\t}\n\tif (format === \"yaml\") {\n\t\tprintOutput(data, opts);\n\t\treturn;\n\t}\n\tconst table = new Table({ style: { head: [\"cyan\"] } });\n\tfor (const [key, val] of Object.entries(data)) {\n\t\ttable.push({ [key]: formatCell(val) });\n\t}\n\tprocess.stdout.write(`${table.toString()}\\n`);\n}\n\n/** Print a success message to stdout */\nexport function printSuccess(message: string): void {\n\tprocess.stdout.write(`✓ ${message}\\n`);\n}\n\n/** Print an error message to stderr and exit with given code */\nexport function printError(message: string, exitCode = 1): never {\n\tprocess.stderr.write(`✗ ${message}\\n`);\n\tprocess.exit(exitCode);\n}\n\n/** Print a warning to stderr (no exit) */\nexport function printWarning(message: string): void {\n\tprocess.stderr.write(`⚠ ${message}\\n`);\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction formatCell(val: unknown): string {\n\tif (val === null || val === undefined) {\n\t\treturn \"\";\n\t}\n\tif (typeof val === \"boolean\") {\n\t\treturn val ? \"yes\" : \"no\";\n\t}\n\tif (typeof val === \"object\") {\n\t\treturn JSON.stringify(val);\n\t}\n\tconst s = String(val);\n\t// Truncate ISO dates to just the date portion for readability in tables\n\tif (/^\\d{4}-\\d{2}-\\d{2}T/.test(s)) {\n\t\treturn s.slice(0, 10);\n\t}\n\treturn s;\n}\n\nfunction csvEscape(s: string): string {\n\tif (s.includes(\",\") || s.includes('\"') || s.includes(\"\\n\")) {\n\t\treturn `\"${s.replace(/\"/g, '\"\"')}\"`;\n\t}\n\treturn s;\n}\n\n/** Minimal YAML serializer (no dependencies) */\nfunction toYaml(val: unknown, indent = 0): string {\n\tconst pad = \" \".repeat(indent);\n\tif (val === null || val === undefined) {\n\t\treturn \"~\";\n\t}\n\tif (typeof val === \"boolean\" || typeof val === \"number\") {\n\t\treturn String(val);\n\t}\n\tif (typeof val === \"string\") {\n\t\tif (val.includes(\"\\n\") || val.includes(\":\") || val.includes('\"')) {\n\t\t\treturn `\"${val.replace(/\"/g, '\\\\\"')}\"`;\n\t\t}\n\t\treturn val;\n\t}\n\tif (Array.isArray(val)) {\n\t\tif (val.length === 0) {\n\t\t\treturn \"[]\";\n\t\t}\n\t\treturn val\n\t\t\t.map((item) => `${pad}- ${toYaml(item, indent + 1)}`)\n\t\t\t.join(\"\\n\");\n\t}\n\tif (typeof val === \"object\") {\n\t\tconst entries = Object.entries(val as Record<string, unknown>);\n\t\tif (entries.length === 0) {\n\t\t\treturn \"{}\";\n\t\t}\n\t\treturn entries\n\t\t\t.map(([k, v]) => {\n\t\t\t\tconst valStr = toYaml(v, indent + 1);\n\t\t\t\tconst isMultiline = valStr.includes(\"\\n\");\n\t\t\t\treturn isMultiline\n\t\t\t\t\t? `${pad}${k}:\\n${valStr}`\n\t\t\t\t\t: `${pad}${k}: ${valStr}`;\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\t}\n\treturn String(val);\n}\n","/**\n * Context resolution for @fabricorg/cli\n *\n * Every resource command runs inside exactly one organization. Personal context\n * is gone (Fizzy #1875, PO-9): the flag, the environment variable and the\n * stored default that selected it are retired here.\n *\n * The stored shape still PARSES a personal default, and that is deliberate.\n * Configs written by earlier versions have one on disk, and a client that\n * crashed on its own config file would be a worse failure than the one being\n * fixed. It is read, recognised, and refused with a message that says how to\n * replace it — never silently treated as \"no default\", which would send the\n * user hunting for a setting they can see is set.\n */\n\nimport type { ContextConfig } from \"./config.js\";\nimport { getDefaultContext } from \"./config.js\";\nimport { printError } from \"./output.js\";\n\nexport interface ResolvedContext {\n\ttype: \"org\";\n\tslug: string;\n}\n\n/**\n * The same resolution as `resolveContext`, as a VALUE instead of an exit.\n *\n * `resolveContext` calls `printError`, which calls `process.exit` — correct\n * for a command a person is watching, and fatal to the session-start hook\n * contract in `commands/instructions`, which must never exit non-zero for\n * any reason. `process.exit` cannot be caught by the `try/catch` that owns\n * that contract, so a stored personal default (or a stale\n * `FABRIC_PERSONAL=1`) took the whole process down with code 2 before the\n * boundary ever saw it.\n *\n * `resolveContext` below is a thin exiting wrapper over it, so the two cannot\n * drift.\n */\ntype ContextResolution =\n\t| { ok: true; context: ResolvedContext | undefined }\n\t| { ok: false; message: string; exitCode: number };\n\nconst PERSONAL_RETIRED_HINT =\n\t\"selects personal context, which no longer exists — every command runs inside an organization.\\n\" +\n\t\"Name one with --org <slug>, or set a default with:\\n fabric ctx use org <slug>\";\n\nfunction tryResolveContext(\n\tpersonal: boolean | undefined,\n\torg: string | undefined,\n\trequired = true,\n): ContextResolution {\n\tif (personal) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tmessage: `--personal ${PERSONAL_RETIRED_HINT}`,\n\t\t\texitCode: 2,\n\t\t};\n\t}\n\tif (org) {\n\t\treturn { ok: true, context: { type: \"org\", slug: org } };\n\t}\n\n\tconst stored: ContextConfig | undefined = getDefaultContext();\n\tif (stored?.type === \"personal\") {\n\t\tconst source =\n\t\t\tprocess.env.FABRIC_PERSONAL === \"1\"\n\t\t\t\t? \"FABRIC_PERSONAL=1\"\n\t\t\t\t: \"Your stored default context\";\n\t\treturn {\n\t\t\tok: false,\n\t\t\tmessage: `${source} ${PERSONAL_RETIRED_HINT}`,\n\t\t\texitCode: 2,\n\t\t};\n\t}\n\tif (stored?.type === \"org\") {\n\t\treturn { ok: true, context: { type: \"org\", slug: stored.slug } };\n\t}\n\n\tif (required) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tmessage:\n\t\t\t\t\"Context is required. Use --org <slug>, or set a default with:\\n fabric ctx use org <slug>\",\n\t\t\texitCode: 2,\n\t\t};\n\t}\n\n\treturn { ok: true, context: undefined };\n}\n\n/**\n * Resolves tenant context from CLI flags, env vars, or stored default.\n * Exits with code 2 when context is ambiguous or names a retired one.\n *\n * A thin wrapper over `tryResolveContext`, which holds the actual rules —\n * see there for why the non-exiting form exists.\n *\n * @param personal - value of the retired --personal flag\n * @param org - value of --org flag\n * @param required - if false, returns undefined when context is unset (for auth commands)\n */\nexport function resolveContext(\n\tpersonal: boolean | undefined,\n\torg: string | undefined,\n\trequired = true,\n): ResolvedContext | undefined {\n\tconst resolution = tryResolveContext(personal, org, required);\n\tif (!resolution.ok) {\n\t\tprintError(resolution.message, resolution.exitCode);\n\t}\n\treturn resolution.context;\n}\n","/**\n * fabric auth keys\n *\n * fabric auth keys list\n * fabric auth keys create --name \"CI deploy\" --scopes workflows:run,agents:read\n * fabric auth keys revoke <id>\n */\n\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { printError, printOutput, printSuccess } from \"../../lib/output.js\";\n\nexport function buildKeysCommand(): Command {\n\tconst keys = new Command(\"keys\").description(\"Manage API keys\");\n\n\t// -- list ----------------------------------------------------------------\n\tkeys.command(\"list\")\n\t\t.description(\"List your API keys\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.action(async (opts: { format: string }) => {\n\t\t\tconst client = getClient();\n\t\t\tlet list: Awaited<ReturnType<typeof client.auth.listKeys>>;\n\t\t\ttry {\n\t\t\t\tlist = await client.auth.listKeys();\n\t\t\t} catch (err: unknown) {\n\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t}\n\t\t\tprintOutput(list, {\n\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\tcolumns: [\n\t\t\t\t\t\"id\",\n\t\t\t\t\t\"name\",\n\t\t\t\t\t\"keyPrefix\",\n\t\t\t\t\t\"scopes\",\n\t\t\t\t\t\"lastUsedAt\",\n\t\t\t\t\t\"expiresAt\",\n\t\t\t\t\t\"createdAt\",\n\t\t\t\t],\n\t\t\t});\n\t\t});\n\n\t// -- create --------------------------------------------------------------\n\tkeys.command(\"create\")\n\t\t.description(\"Create a new API key (raw key shown only once)\")\n\t\t.requiredOption(\"-n, --name <name>\", \"Key name\")\n\t\t.option(\n\t\t\t\"-s, --scopes <scopes>\",\n\t\t\t\"Comma-separated scopes (e.g. projects:read,workflows:run)\",\n\t\t\t\"orgs:read\",\n\t\t)\n\t\t.option(\n\t\t\t\"-e, --expires <days>\",\n\t\t\t\"Days until expiry (1–365, omit for no expiry)\",\n\t\t)\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\tname: string;\n\t\t\t\tscopes: string;\n\t\t\t\texpires?: string;\n\t\t\t\tformat: string;\n\t\t\t}) => {\n\t\t\t\tconst client = getClient();\n\t\t\t\tconst scopes = opts.scopes.split(\",\").map((s) => s.trim());\n\t\t\t\tconst expiresInDays = opts.expires\n\t\t\t\t\t? Number.parseInt(opts.expires, 10)\n\t\t\t\t\t: undefined;\n\n\t\t\t\tif (\n\t\t\t\t\texpiresInDays !== undefined &&\n\t\t\t\t\tNumber.isNaN(expiresInDays)\n\t\t\t\t) {\n\t\t\t\t\tprintError(\"--expires must be a number\", 2);\n\t\t\t\t}\n\n\t\t\t\tlet created: Awaited<ReturnType<typeof client.auth.createKey>>;\n\t\t\t\ttry {\n\t\t\t\t\tcreated = await client.auth.createKey({\n\t\t\t\t\t\tname: opts.name,\n\t\t\t\t\t\tscopes,\n\t\t\t\t\t\texpiresInDays,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(created, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprocess.stdout.write(\"\\n\");\n\t\t\t\tprintSuccess(`API key created: ${created.name}`);\n\t\t\t\tprocess.stdout.write(`\\n Key: ${created.rawKey}\\n`);\n\t\t\t\tprocess.stdout.write(` Prefix: ${created.keyPrefix}\\n`);\n\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t` Scopes: ${created.scopes.join(\", \")}\\n`,\n\t\t\t\t);\n\t\t\t\tif (created.expiresAt) {\n\t\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t\t` Expires: ${String(created.expiresAt).slice(0, 10)}\\n`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tprocess.stdout.write(\n\t\t\t\t\t\"\\n ⚠ Store this key now — it will never be shown again.\\n\\n\",\n\t\t\t\t);\n\t\t\t},\n\t\t);\n\n\t// -- revoke --------------------------------------------------------------\n\tkeys.command(\"revoke <id>\")\n\t\t.description(\"Permanently revoke an API key\")\n\t\t.action(async (id: string) => {\n\t\t\tconst client = getClient();\n\t\t\ttry {\n\t\t\t\tawait client.auth.revokeKey(id);\n\t\t\t} catch (err: unknown) {\n\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t}\n\t\t\tprintSuccess(`API key ${id} revoked.`);\n\t\t});\n\n\treturn keys;\n}\n","/**\n * fabric auth login\n *\n * Stores an API key for subsequent commands.\n *\n * fabric auth login --key fab_...\n * fabric auth login (prompts interactively)\n */\n\nimport * as readline from \"node:readline\";\nimport { FabricAuthError, FabricClient, FabricError } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getBaseUrl, saveApiKey } from \"../../lib/config.js\";\nimport { printError, printSuccess } from \"../../lib/output.js\";\n\nconst DEFAULT_BASE_URL = \"https://fabric.pro\";\n\nfunction displayBaseUrl(baseUrl: string): string {\n\ttry {\n\t\treturn new URL(baseUrl).origin;\n\t} catch {\n\t\treturn \"the configured Fabric deployment\";\n\t}\n}\n\nasync function promptApiKey(): Promise<string> {\n\tconst rl = readline.createInterface({\n\t\tinput: process.stdin,\n\t\toutput: process.stdout,\n\t});\n\n\treturn new Promise((resolve) => {\n\t\t// Don't echo the key\n\t\tprocess.stdout.write(\"Fabric API Key: \");\n\t\tprocess.stdin.resume();\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\n\t\tlet key = \"\";\n\t\tprocess.stdin.once(\"data\", (chunk) => {\n\t\t\tkey = String(chunk).trim();\n\t\t\tprocess.stdout.write(\"\\n\");\n\t\t\trl.close();\n\t\t\tresolve(key);\n\t\t});\n\t});\n}\n\nexport function buildLoginCommand(): Command {\n\treturn new Command(\"login\")\n\t\t.description(\"Authenticate with a Fabric API key\")\n\t\t.option(\"-k, --key <api-key>\", \"API key (fab_... or org_...)\")\n\t\t.option(\"--base-url <url>\", \"Override the Fabric base URL\")\n\t\t.action(async (opts: { key?: string; baseUrl?: string }) => {\n\t\t\tlet apiKey = opts.key?.trim();\n\n\t\t\tif (!apiKey) {\n\t\t\t\tapiKey = await promptApiKey();\n\t\t\t}\n\n\t\t\tif (!apiKey) {\n\t\t\t\tprintError(\"API key is required\", 2);\n\t\t\t}\n\n\t\t\tif (!apiKey.startsWith(\"fab_\") && !apiKey.startsWith(\"org_\")) {\n\t\t\t\tprintError(\n\t\t\t\t\t\"Invalid API key format. Keys must start with fab_ or org_\",\n\t\t\t\t\t2,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Verify the key works before saving\n\t\t\tconst baseUrl = opts.baseUrl ?? getBaseUrl();\n\t\t\tconst effectiveBaseUrl = displayBaseUrl(\n\t\t\t\tbaseUrl ?? DEFAULT_BASE_URL,\n\t\t\t);\n\t\t\tconst client = new FabricClient({ apiKey, baseUrl });\n\n\t\t\tlet name: string;\n\t\t\tlet email: string;\n\t\t\ttry {\n\t\t\t\tconst me = await client.auth.whoami();\n\t\t\t\tname = me.user.name ?? me.user.email;\n\t\t\t\temail = me.user.email;\n\t\t\t} catch (error) {\n\t\t\t\tif (\n\t\t\t\t\terror instanceof FabricAuthError ||\n\t\t\t\t\t(error instanceof FabricError && error.status === 401)\n\t\t\t\t) {\n\t\t\t\t\tprintError(\n\t\t\t\t\t\t\"Authentication failed. Check that the key is valid and not expired.\",\n\t\t\t\t\t\t3,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (error instanceof FabricError && error.status > 0) {\n\t\t\t\t\tprintError(\n\t\t\t\t\t\t`Authentication request to ${effectiveBaseUrl} failed with HTTP ${error.status}.`,\n\t\t\t\t\t\t3,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tprintError(\n\t\t\t\t\t`Could not connect to ${effectiveBaseUrl}. Check that the deployment URL is correct and reachable.`,\n\t\t\t\t\t3,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// An environment override selects the verification target for this\n\t\t\t// invocation only. Persist a deployment only when the person supplied\n\t\t\t// `--base-url`, so FABRIC_BASE_URL remains an explicit override.\n\t\t\tsaveApiKey(apiKey, {\n\t\t\t\t...(opts.baseUrl === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: { baseUrl: opts.baseUrl }),\n\t\t\t});\n\t\t\tprintSuccess(`Authenticated as ${name} (${email})`);\n\t\t});\n}\n","/**\n * fabric auth logout\n * Removes the stored API key from config.\n */\n\nimport { Command } from \"commander\";\nimport { clearApiKey, getApiKey } from \"../../lib/config.js\";\nimport { printSuccess, printWarning } from \"../../lib/output.js\";\n\nexport function buildLogoutCommand(): Command {\n\treturn new Command(\"logout\")\n\t\t.description(\"Remove stored API key\")\n\t\t.action(() => {\n\t\t\tif (!getApiKey()) {\n\t\t\t\tprintWarning(\"No API key stored — already logged out.\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tclearApiKey();\n\t\t\tprintSuccess(\"Logged out. API key removed.\");\n\t\t});\n}\n","/**\n * fabric auth whoami\n * Prints the authenticated identity and org memberships.\n */\n\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildWhoamiCommand(): Command {\n\treturn new Command(\"whoami\")\n\t\t.description(\"Show current authentication and identity\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(async (opts: { format: string }) => {\n\t\t\tconst client = getClient();\n\n\t\t\tlet me: Awaited<ReturnType<typeof client.auth.whoami>>;\n\t\t\ttry {\n\t\t\t\tme = await client.auth.whoami();\n\t\t\t} catch (err: unknown) {\n\t\t\t\tprintError((err as Error).message ?? \"Request failed\", 3);\n\t\t\t}\n\n\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\n\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\tprintOutput(me, { format: fmt });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Human-readable\n\t\t\tprintRecord({\n\t\t\t\tUser: me.user.name ?? \"(no name)\",\n\t\t\t\tEmail: me.user.email,\n\t\t\t\tRole: me.user.role,\n\t\t\t\t\"Key type\": me.keyType,\n\t\t\t\t\"Key prefix\": me.keyPrefix,\n\t\t\t\tScopes: me.scopes.join(\", \"),\n\t\t\t\t\"Orgs count\": String(me.orgs.length),\n\t\t\t\t\"Member since\": me.user.createdAt.slice(0, 10),\n\t\t\t});\n\n\t\t\tif (me.orgs.length > 0) {\n\t\t\t\tprocess.stdout.write(\"\\nOrganizations:\\n\");\n\t\t\t\tprintOutput(me.orgs, {\n\t\t\t\t\tformat: \"table\",\n\t\t\t\t\tcolumns: [\"name\", \"slug\", \"role\", \"joinedAt\"],\n\t\t\t\t});\n\t\t\t}\n\t\t});\n}\n","/**\n * fabric chats\n *\n * fabric chats list List AI chat sessions\n * fabric chats show <id> Show chat details\n */\n\nimport type { FabricChat } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildChatsCommand(): Command {\n\tconst chats = new Command(\"chats\").description(\"Manage AI chat sessions\");\n\n\tchats\n\t\t.command(\"list\")\n\t\t.description(\"List AI chat sessions\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--limit <n>\", \"Max results (default 20)\", \"20\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricChat[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.chats.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const c of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${c.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\"id\", \"title\", \"updatedAt\"],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\tchats\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show chat details\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet chat: FabricChat;\n\t\t\t\ttry {\n\t\t\t\t\tchat = await client.chats.get(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(chat, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: chat.id,\n\t\t\t\t\tTitle: chat.title ?? \"(untitled)\",\n\t\t\t\t\tUpdated: chat.updatedAt.slice(0, 16).replace(\"T\", \" \"),\n\t\t\t\t\tCreated: chat.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn chats;\n}\n","/**\n * fabric completion\n *\n * fabric completion bash Output bash completion script\n * fabric completion zsh Output zsh completion script\n * fabric completion fish Output fish completion script\n */\n\nimport { Command } from \"commander\";\n\nconst BASH_COMPLETION = `\n# fabric bash completion\n_fabric_completion() {\n local cur prev words cword\n _init_completion || return\n\n local commands=\"auth ctx orgs projects features workflows prompts agents skills mcp frames workspaces chats reports config completion\"\n\n case \"$prev\" in\n fabric)\n COMPREPLY=($(compgen -W \"$commands\" -- \"$cur\"))\n return ;;\n auth)\n COMPREPLY=($(compgen -W \"login logout whoami keys\" -- \"$cur\"))\n return ;;\n keys)\n COMPREPLY=($(compgen -W \"list create revoke\" -- \"$cur\"))\n return ;;\n ctx)\n COMPREPLY=($(compgen -W \"current use\" -- \"$cur\"))\n return ;;\n orgs)\n COMPREPLY=($(compgen -W \"list show\" -- \"$cur\"))\n return ;;\n projects)\n COMPREPLY=($(compgen -W \"list show create update\" -- \"$cur\"))\n return ;;\n features)\n COMPREPLY=($(compgen -W \"list show create update tasks\" -- \"$cur\"))\n return ;;\n workflows)\n COMPREPLY=($(compgen -W \"list show trigger status\" -- \"$cur\"))\n return ;;\n prompts)\n COMPREPLY=($(compgen -W \"list get create update\" -- \"$cur\"))\n return ;;\n agents)\n COMPREPLY=($(compgen -W \"list show execute\" -- \"$cur\"))\n return ;;\n skills)\n COMPREPLY=($(compgen -W \"list show\" -- \"$cur\"))\n return ;;\n mcp)\n COMPREPLY=($(compgen -W \"servers configs\" -- \"$cur\"))\n return ;;\n configs)\n COMPREPLY=($(compgen -W \"list show delete\" -- \"$cur\"))\n return ;;\n frames)\n COMPREPLY=($(compgen -W \"list show\" -- \"$cur\"))\n return ;;\n workspaces)\n COMPREPLY=($(compgen -W \"list show\" -- \"$cur\"))\n return ;;\n chats)\n COMPREPLY=($(compgen -W \"list show\" -- \"$cur\"))\n return ;;\n reports)\n COMPREPLY=($(compgen -W \"templates executions\" -- \"$cur\"))\n return ;;\n templates)\n COMPREPLY=($(compgen -W \"list show\" -- \"$cur\"))\n return ;;\n executions)\n COMPREPLY=($(compgen -W \"list\" -- \"$cur\"))\n return ;;\n completion)\n COMPREPLY=($(compgen -W \"bash zsh fish\" -- \"$cur\"))\n return ;;\n esac\n\n COMPREPLY=($(compgen -W \"--format --org --personal --quiet --help\" -- \"$cur\"))\n}\n\ncomplete -F _fabric_completion fabric\n`.trim();\n\nconst ZSH_COMPLETION = `\n#compdef fabric\n\n_fabric() {\n local state\n\n _arguments \\\\\n '--format[Output format]:format:(table json yaml csv)' \\\\\n '--version[Show version]' \\\\\n '--help[Show help]' \\\\\n '1: :->command' \\\\\n '*: :->args'\n\n case $state in\n command)\n local commands=(\n 'auth:Authenticate and manage API keys'\n 'ctx:Manage active context'\n 'orgs:List organizations'\n 'projects:Manage projects'\n 'features:Manage project features'\n 'workflows:Manage workflows'\n 'prompts:Manage prompts'\n 'agents:Manage agents'\n 'skills:Browse skills'\n 'mcp:Manage MCP servers and configs'\n 'frames:Manage AI-generated frames'\n 'workspaces:Manage workspaces'\n 'chats:View AI chat history'\n 'reports:Manage reports'\n 'config:Show CLI configuration'\n 'completion:Output shell completion script'\n )\n _describe 'command' commands\n ;;\n args)\n case $words[2] in\n auth)\n local subcmds=('login:Log in' 'logout:Log out' 'whoami:Show current user' 'keys:Manage API keys')\n _describe 'subcommand' subcmds ;;\n projects)\n local subcmds=('list:List projects' 'show:Show project' 'create:Create project' 'update:Update project')\n _describe 'subcommand' subcmds ;;\n features)\n local subcmds=('list:List features' 'show:Show feature' 'create:Create feature' 'update:Update feature' 'tasks:List tasks')\n _describe 'subcommand' subcmds ;;\n workflows)\n local subcmds=('list:List workflows' 'show:Show workflow' 'trigger:Trigger workflow' 'status:Check status')\n _describe 'subcommand' subcmds ;;\n prompts)\n local subcmds=('list:List prompts' 'get:Get prompt' 'create:Create prompt' 'update:Update prompt')\n _describe 'subcommand' subcmds ;;\n agents)\n local subcmds=('list:List agents' 'show:Show agent' 'execute:Execute agent')\n _describe 'subcommand' subcmds ;;\n mcp)\n local subcmds=('servers:List MCP servers' 'configs:Manage MCP configs')\n _describe 'subcommand' subcmds ;;\n frames)\n local subcmds=('list:List frames' 'show:Show frame')\n _describe 'subcommand' subcmds ;;\n workspaces)\n local subcmds=('list:List workspaces' 'show:Show workspace')\n _describe 'subcommand' subcmds ;;\n skills)\n local subcmds=('list:List skills' 'show:Show skill')\n _describe 'subcommand' subcmds ;;\n chats)\n local subcmds=('list:List chats' 'show:Show chat')\n _describe 'subcommand' subcmds ;;\n reports)\n local subcmds=('templates:Manage report templates' 'executions:List report executions')\n _describe 'subcommand' subcmds ;;\n completion)\n local subcmds=('bash:Bash completion' 'zsh:Zsh completion' 'fish:Fish completion')\n _describe 'subcommand' subcmds ;;\n esac ;;\n esac\n}\n\n_fabric \"$@\"\n`.trim();\n\nconst FISH_COMPLETION = `\n# fabric fish completion\nset -l fabric_commands auth ctx orgs projects features workflows prompts agents skills mcp frames workspaces chats reports config completion\n\ncomplete -c fabric -f\n\n# Top-level commands\ncomplete -c fabric -n '__fish_use_subcommand' -a auth -d 'Authenticate and manage API keys'\ncomplete -c fabric -n '__fish_use_subcommand' -a ctx -d 'Manage active context'\ncomplete -c fabric -n '__fish_use_subcommand' -a orgs -d 'List organizations'\ncomplete -c fabric -n '__fish_use_subcommand' -a projects -d 'Manage projects'\ncomplete -c fabric -n '__fish_use_subcommand' -a features -d 'Manage project features'\ncomplete -c fabric -n '__fish_use_subcommand' -a workflows -d 'Manage workflows'\ncomplete -c fabric -n '__fish_use_subcommand' -a prompts -d 'Manage prompts'\ncomplete -c fabric -n '__fish_use_subcommand' -a agents -d 'Manage agents'\ncomplete -c fabric -n '__fish_use_subcommand' -a skills -d 'Browse skills'\ncomplete -c fabric -n '__fish_use_subcommand' -a mcp -d 'Manage MCP servers and configs'\ncomplete -c fabric -n '__fish_use_subcommand' -a frames -d 'Manage AI-generated frames'\ncomplete -c fabric -n '__fish_use_subcommand' -a workspaces -d 'Manage workspaces'\ncomplete -c fabric -n '__fish_use_subcommand' -a chats -d 'View AI chat history'\ncomplete -c fabric -n '__fish_use_subcommand' -a reports -d 'Manage reports'\ncomplete -c fabric -n '__fish_use_subcommand' -a config -d 'Show CLI configuration'\ncomplete -c fabric -n '__fish_use_subcommand' -a completion -d 'Output shell completion script'\n\n# Subcommands\ncomplete -c fabric -n '__fish_seen_subcommand_from auth' -a 'login logout whoami keys'\ncomplete -c fabric -n '__fish_seen_subcommand_from ctx' -a 'current use'\ncomplete -c fabric -n '__fish_seen_subcommand_from orgs' -a 'list show'\ncomplete -c fabric -n '__fish_seen_subcommand_from projects' -a 'list show create update'\ncomplete -c fabric -n '__fish_seen_subcommand_from features' -a 'list show create update tasks'\ncomplete -c fabric -n '__fish_seen_subcommand_from workflows' -a 'list show trigger status'\ncomplete -c fabric -n '__fish_seen_subcommand_from prompts' -a 'list get create update'\ncomplete -c fabric -n '__fish_seen_subcommand_from agents' -a 'list show execute'\ncomplete -c fabric -n '__fish_seen_subcommand_from skills' -a 'list show'\ncomplete -c fabric -n '__fish_seen_subcommand_from mcp' -a 'servers configs'\ncomplete -c fabric -n '__fish_seen_subcommand_from configs' -a 'list show delete'\ncomplete -c fabric -n '__fish_seen_subcommand_from frames' -a 'list show'\ncomplete -c fabric -n '__fish_seen_subcommand_from workspaces' -a 'list show'\ncomplete -c fabric -n '__fish_seen_subcommand_from chats' -a 'list show'\ncomplete -c fabric -n '__fish_seen_subcommand_from reports' -a 'templates executions'\ncomplete -c fabric -n '__fish_seen_subcommand_from templates' -a 'list show'\ncomplete -c fabric -n '__fish_seen_subcommand_from executions' -a 'list'\ncomplete -c fabric -n '__fish_seen_subcommand_from completion' -a 'bash zsh fish'\n\n# Common flags\ncomplete -c fabric -l format -d 'Output format' -a 'table json yaml csv'\ncomplete -c fabric -l org -d 'Organization context' -r\ncomplete -c fabric -l personal -d 'Personal context'\ncomplete -c fabric -s q -l quiet -d 'Quiet output'\ncomplete -c fabric -l help -d 'Show help'\n`.trim();\n\nexport function buildCompletionCommand(): Command {\n\tconst completion = new Command(\"completion\").description(\n\t\t\"Output shell completion script\",\n\t);\n\n\tcompletion\n\t\t.command(\"bash\")\n\t\t.description(\"Output bash completion script\")\n\t\t.action(() => {\n\t\t\tprocess.stdout.write(`${BASH_COMPLETION}\\n`);\n\t\t\tprocess.stderr.write(\n\t\t\t\t'# Add to ~/.bashrc:\\n# eval \"$(fabric completion bash)\"\\n',\n\t\t\t);\n\t\t});\n\n\tcompletion\n\t\t.command(\"zsh\")\n\t\t.description(\"Output zsh completion script\")\n\t\t.action(() => {\n\t\t\tprocess.stdout.write(`${ZSH_COMPLETION}\\n`);\n\t\t\tprocess.stderr.write(\n\t\t\t\t'# Add to ~/.zshrc:\\n# eval \"$(fabric completion zsh)\"\\n',\n\t\t\t);\n\t\t});\n\n\tcompletion\n\t\t.command(\"fish\")\n\t\t.description(\"Output fish completion script\")\n\t\t.action(() => {\n\t\t\tprocess.stdout.write(`${FISH_COMPLETION}\\n`);\n\t\t\tprocess.stderr.write(\n\t\t\t\t\"# Save to ~/.config/fish/completions/fabric.fish\\n\",\n\t\t\t);\n\t\t});\n\n\treturn completion;\n}\n","/**\n * fabric context\n *\n * fabric context push <dir> --project <id> Sync a local knowledge folder\n * into the project's Context.\n *\n * PROJECT Context — the knowledge sources a project's AI features read — and\n * not `fabric ctx`, which switches the CLI's default organization and never\n * talks to a project.\n *\n * Every file under `<dir>` that the ignore rules leave in and that is text is\n * pushed by its relative path, one request per file, through\n * `PUT /api/v1/projects/:projectId/contexts/synced-files`. The lock at\n * `<dir>/.fabric/context.lock` remembers what the server confirmed, so a file\n * that has not changed is not sent again, and a file that has changed names\n * the version it replaces — which is what turns somebody else's edit on the\n * server into a conflict instead of a silent overwrite.\n *\n * A file moved or renamed with its content unchanged is one rename on the\n * server, keeping its history and its place in the Context tab. A file\n * removed locally keeps its server entry unless `--prune` is given; then it\n * is deleted, but only in the version the lock names, so an edit somebody\n * made on the server since is a conflict rather than lost (Fizzy #2636).\n *\n * A path a Living Memory repository sync owns refuses a create, a replace, a\n * move or a `--prune` delete the same way every time: nothing is written,\n * it is reported as skipped, and `--force` never retries it — the file\n * changes in the repository, not here (Living Memory design 2026-09-23 §6).\n *\n * Everything that touches the filesystem lives in `lib/context-sync/`; this\n * file is argument parsing, the sequence, and the exit code.\n */\nimport { lstat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { FabricClient } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport {\n\tCliFailure,\n\tdescribeError,\n\ttype OutputFormat,\n\toutputFormatFor,\n\twithDeadline,\n} from \"../../lib/command-boundary.js\";\nimport { getApiKey } from \"../../lib/config.js\";\nimport {\n\ttype ContextLock,\n\tcontextLockPath,\n\treadContextLock,\n\twriteContextLock,\n} from \"../../lib/context-sync/lock.js\";\nimport {\n\ttype ContextPlan,\n\tcomputeContextPlan,\n} from \"../../lib/context-sync/plan.js\";\nimport {\n\ttype ContextPushResult,\n\tDELETE_STATUSES,\n\tnextContextLock,\n\tpushContextPlan,\n} from \"../../lib/context-sync/push.js\";\nimport {\n\tcontextPushJson,\n\tformatDryRunReport,\n\tformatPushReport,\n} from \"../../lib/context-sync/report.js\";\nimport { resolveExistingRoot } from \"../../lib/instructions/safe-write.js\";\nimport { printOutput } from \"../../lib/output.js\";\n\n/**\n * Hook mode's one absolute deadline, the same bound `fabric instructions`\n * uses. A hook that cannot finish in time leaves the lock as it was, and the\n * next run finishes the job: content the server already holds is answered\n * `unchanged` and recorded then.\n */\nconst HOOK_DEADLINE_MS = 10_000;\n\n/** Per request, outside hook mode. A file is at most 2 MiB. */\nconst PUSH_TIMEOUT_MS = 60_000;\n\ninterface PushOptions {\n\tproject: string;\n\torg?: string;\n\tforce?: boolean;\n\tdryRun?: boolean;\n\tprune?: boolean;\n\thook?: boolean;\n\texclude?: string[];\n\t/** Read through `optsWithGlobals()`, never off this object. */\n\tformat?: string;\n}\n\nfunction collectPattern(value: string, previous: string[]): string[] {\n\treturn [...previous, value];\n}\n\nexport function buildContextCommand(): Command {\n\tconst context = new Command(\"context\").description(\n\t\t\"Sync local knowledge files into a project's Context\",\n\t);\n\n\tcontext\n\t\t.command(\"push\")\n\t\t.description(\n\t\t\t\"Push every text file under <dir> into the project's Context by its relative path\",\n\t\t)\n\t\t.argument(\n\t\t\t\"<dir>\",\n\t\t\t\"Folder to push (required; never the working directory by default)\",\n\t\t)\n\t\t.requiredOption(\"--project <id>\", \"Project ID\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\n\t\t\t\"--force\",\n\t\t\t\"On a conflict, replace the server's version once with this folder's; never retries a path a repository sync owns\",\n\t\t)\n\t\t.option(\n\t\t\t\"--prune\",\n\t\t\t\"Delete the server entries of files removed locally, only in the version last pushed\",\n\t\t)\n\t\t.option(\"--dry-run\", \"Print the plan; send nothing and write no lock\")\n\t\t.option(\n\t\t\t\"--exclude <pattern>\",\n\t\t\t\"Also leave out paths matching this gitignore pattern (repeatable)\",\n\t\t\tcollectPattern,\n\t\t\t[] as string[],\n\t\t)\n\t\t.option(\n\t\t\t\"--hook\",\n\t\t\t\"Hook mode: never fails, never blocks, one line on stderr on failure\",\n\t\t)\n\t\t.option(\"--format <format>\", \"Output format: text|json\")\n\t\t.action(async function (this: Command, dir: string, opts: PushOptions) {\n\t\t\tawait run(opts, () => runPush(dir, opts, outputFormatFor(this)));\n\t\t});\n\n\treturn context;\n}\n\n/**\n * Every failure becomes an exit code or, under `--hook`, one line on stderr\n * and a zero exit — the same contract as `fabric instructions`, so a hook\n * that pushes notes can never be what stops a session or a commit.\n */\nasync function run(\n\topts: { hook?: boolean },\n\tbody: () => Promise<void>,\n): Promise<void> {\n\ttry {\n\t\tif (opts.hook) {\n\t\t\tawait withDeadline(HOOK_DEADLINE_MS, () => body());\n\t\t} else {\n\t\t\tawait body();\n\t\t}\n\t} catch (error) {\n\t\tconst message = describeError(error);\n\t\tif (opts.hook) {\n\t\t\tprocess.stderr.write(`fabric: context push failed: ${message}\\n`);\n\t\t\tprocess.exit(0);\n\t\t}\n\t\tprocess.stderr.write(`✗ ${message}\\n`);\n\t\tprocess.exit(error instanceof CliFailure ? error.exitCode : 1);\n\t}\n}\n\n/**\n * A client that throws instead of exiting (`getClient` exits 3 on a missing\n * key, which would break the hook contract), with retries off in hook mode.\n *\n * Retries stay ON otherwise, and that is safe for this route in particular:\n * the same content at the same path is answered `unchanged` before the\n * expected hash is compared, so a retry of a request whose response was lost\n * reports the first attempt's write rather than making another.\n *\n * `withoutContext()`: the project decides which organization it is in, so an\n * ambient `FABRIC_ORG` must not bind the request; `--org` still does.\n */\nfunction contextClient(opts: { hook?: boolean }): FabricClient {\n\tif (!getApiKey()) {\n\t\tthrow new CliFailure(\n\t\t\t\"Not authenticated. Run: fabric auth login --key <api-key>\",\n\t\t\t3,\n\t\t);\n\t}\n\treturn getClient(\n\t\topts.hook\n\t\t\t? { timeoutMs: HOOK_DEADLINE_MS, retry: { maxRetries: 0 } }\n\t\t\t: { timeoutMs: PUSH_TIMEOUT_MS },\n\t).withoutContext();\n}\n\nasync function resolveFolder(dir: string): Promise<string> {\n\tconst directory = path.resolve(dir);\n\tconst root = await resolveExistingRoot(directory);\n\tconst stats = await lstat(root).catch(() => null);\n\tif (stats === null || !stats.isDirectory()) {\n\t\tthrow new CliFailure(`${directory} is not a directory.`, 2);\n\t}\n\treturn root;\n}\n\n/** The lock, refused when damaged or when it belongs to another project. */\nasync function readLockForProject(\n\troot: string,\n\tprojectId: string,\n): Promise<ContextLock | null> {\n\tlet lock: ContextLock | null;\n\ttry {\n\t\tlock = await readContextLock(root);\n\t} catch (error) {\n\t\tthrow new CliFailure(describeError(error), 7);\n\t}\n\tif (lock !== null && lock.projectId !== projectId) {\n\t\tthrow new CliFailure(\n\t\t\t`${contextLockPath(root)} belongs to project ${lock.projectId}, not ${projectId}. Push this folder to ${lock.projectId}, or remove that lock if this folder should now feed ${projectId}.`,\n\t\t\t7,\n\t\t);\n\t}\n\treturn lock;\n}\n\nfunction print(lines: string[]): void {\n\tprocess.stdout.write(`${lines.join(\"\\n\")}\\n`);\n}\n\nasync function runPush(\n\tdir: string,\n\topts: PushOptions,\n\tformat: OutputFormat,\n): Promise<void> {\n\tconst root = await resolveFolder(dir);\n\t// Before any file is read: a push that cannot authenticate should not\n\t// spend a walk and a hash of every file finding that out.\n\tconst client = opts.dryRun ? null : contextClient(opts);\n\tconst lock = await readLockForProject(root, opts.project);\n\tconst plan = await computeContextPlan({\n\t\troot,\n\t\tlock,\n\t\texcludes: opts.exclude,\n\t});\n\n\tif (client === null) {\n\t\tif (format === \"json\") {\n\t\t\tprintOutput(\n\t\t\t\tjsonOutcome({\n\t\t\t\t\troot,\n\t\t\t\t\topts,\n\t\t\t\t\tplan,\n\t\t\t\t\tresults: [],\n\t\t\t\t\tlockWritten: false,\n\t\t\t\t}),\n\t\t\t\t{ format: \"json\" },\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tprint(\n\t\t\tformatDryRunReport({\n\t\t\t\tprojectId: opts.project,\n\t\t\t\tdirectory: root,\n\t\t\t\tplan,\n\t\t\t\tprune: Boolean(opts.prune),\n\t\t\t}),\n\t\t);\n\t\treturn;\n\t}\n\n\tconst pushed = await pushContextPlan({\n\t\tclient,\n\t\tprojectId: opts.project,\n\t\torg: opts.org,\n\t\troot,\n\t\tplan,\n\t\tforce: Boolean(opts.force),\n\t\tprune: Boolean(opts.prune),\n\t\tlock,\n\t});\n\n\t// LAST, after every request, and only with what the server answered.\n\tconst next = nextContextLock({\n\t\tprevious: lock,\n\t\tprojectId: opts.project,\n\t\tresults: pushed.results,\n\t\tforgotten: plan.forgotten,\n\t\tnow: new Date(),\n\t});\n\tif (next !== null) {\n\t\tawait writeContextLock(root, next);\n\t}\n\n\tif (format === \"json\") {\n\t\tprintOutput(\n\t\t\tjsonOutcome({\n\t\t\t\troot,\n\t\t\t\topts,\n\t\t\t\tplan,\n\t\t\t\tresults: pushed.results,\n\t\t\t\tlockWritten: next !== null,\n\t\t\t}),\n\t\t\t{ format: \"json\" },\n\t\t);\n\t} else {\n\t\tprint(\n\t\t\tformatPushReport({\n\t\t\t\tprojectId: opts.project,\n\t\t\t\tdirectory: root,\n\t\t\t\tplan,\n\t\t\t\tresults: pushed.results,\n\t\t\t\tprune: Boolean(opts.prune),\n\t\t\t\tpruneTargets: pushed.pruneTargets,\n\t\t\t}),\n\t\t);\n\t}\n\n\tconst prune = Boolean(opts.prune);\n\tif (pushed.stoppedBy !== null) {\n\t\t// Under --prune, say how far the deletions got: a hook's one line is\n\t\t// all its user sees.\n\t\tthrow prune\n\t\t\t? new CliFailure(\n\t\t\t\t\t`${pushed.stoppedBy.message} (${pruneSummary(pushed.results, pushed.pruneTargets)})`,\n\t\t\t\t\tpushed.stoppedBy.exitCode,\n\t\t\t\t)\n\t\t\t: pushed.stoppedBy;\n\t}\n\tthrowIfIncomplete(pushed.results, prune, pushed.pruneTargets);\n}\n\nfunction jsonOutcome(input: {\n\troot: string;\n\topts: PushOptions;\n\tplan: ContextPlan;\n\tresults: ContextPushResult[];\n\tlockWritten: boolean;\n}) {\n\treturn contextPushJson({\n\t\tprojectId: input.opts.project,\n\t\tdirectory: input.root,\n\t\tlockPath: contextLockPath(input.root),\n\t\tlockWritten: input.lockWritten,\n\t\tdryRun: Boolean(input.opts.dryRun),\n\t\tforce: Boolean(input.opts.force),\n\t\tprune: Boolean(input.opts.prune),\n\t\tplan: input.plan,\n\t\tresults: input.results,\n\t});\n}\n\n/**\n * `--prune: 1 deleted, 0 already gone, 1 not deleted`, with the first\n * failure's cause. Counted from the plan's targets, not only from answers:\n * a target a run-level refusal stopped before it was tried is not deleted\n * too.\n */\nfunction pruneSummary(\n\tresults: readonly ContextPushResult[],\n\ttargets: readonly string[],\n): string {\n\tconst count = (status: ContextPushResult[\"status\"]) =>\n\t\tresults.filter((r) => r.status === status).length;\n\tconst settled = new Set(\n\t\tresults\n\t\t\t.filter(\n\t\t\t\t(r) => r.status === \"deleted\" || r.status === \"already-gone\",\n\t\t\t)\n\t\t\t.map((r) => r.sourcePath),\n\t);\n\tconst notDeleted = targets.filter((path) => !settled.has(path)).length;\n\tlet text = `--prune: ${count(\"deleted\")} deleted, ${count(\"already-gone\")} already gone, ${notDeleted} not deleted`;\n\tconst first = results.find((r) => r.status === \"delete-failed\");\n\tif (first && first.status === \"delete-failed\") {\n\t\ttext += `, first ${first.sourcePath}: ${first.error}`;\n\t}\n\treturn text;\n}\n\n/**\n * The run's exit, once everything that could be pushed has been.\n *\n * A failed request exits with the code its error maps to (a 400 is 7, a 5xx\n * is 1); remaining conflicts, or `--prune` deletions still running on the\n * server, alone exit 1. Either way the report above has\n * already named every file, so this sentence only says what to do next.\n * A push's failure decides the code before a `--prune` deletion's does.\n */\nfunction throwIfIncomplete(\n\tresults: readonly ContextPushResult[],\n\tprune: boolean,\n\tpruneTargets: readonly string[],\n): void {\n\tconst pushes = results.filter((r) => !DELETE_STATUSES.has(r.status));\n\tconst failed = pushes.filter((r) => r.status === \"failed\");\n\tconst conflicts = pushes.filter((r) => r.status === \"conflict\");\n\tconst unsupported = pushes.filter((r) => r.status === \"move-unsupported\");\n\tconst deleteFailed = results.filter((r) => r.status === \"delete-failed\");\n\tconst deleteConflicts = results.filter(\n\t\t(r) => r.status === \"delete-conflict\",\n\t);\n\tconst stillDeleting = results.filter(\n\t\t(r) => r.status === \"delete-in-progress\",\n\t);\n\tif (\n\t\tfailed.length === 0 &&\n\t\tconflicts.length === 0 &&\n\t\tunsupported.length === 0 &&\n\t\tdeleteFailed.length === 0 &&\n\t\tdeleteConflicts.length === 0 &&\n\t\tstillDeleting.length === 0\n\t) {\n\t\treturn;\n\t}\n\tconst sentences: string[] = [];\n\tconst total = conflicts.length + failed.length + unsupported.length;\n\tif (total > 0) {\n\t\tconst parts: string[] = [];\n\t\tif (conflicts.length > 0) {\n\t\t\tparts.push(\n\t\t\t\t`${conflicts.length} conflict${conflicts.length === 1 ? \"\" : \"s\"}`,\n\t\t\t);\n\t\t}\n\t\tif (unsupported.length > 0) {\n\t\t\tparts.push(\n\t\t\t\t`${unsupported.length} move${unsupported.length === 1 ? \"\" : \"s\"} the server does not support yet`,\n\t\t\t);\n\t\t}\n\t\tconst first = failed[0];\n\t\tif (first && first.status === \"failed\") {\n\t\t\t// The first cause, so a hook's single stderr line says why.\n\t\t\tparts.push(\n\t\t\t\t`${failed.length} failed, first ${first.sourcePath}: ${first.error}`,\n\t\t\t);\n\t\t}\n\t\tsentences.push(\n\t\t\t`${total} of ${pushes.length} file${pushes.length === 1 ? \"\" : \"s\"} sent ${total === 1 ? \"was\" : \"were\"} not stored (${parts.join(\", \")}).`,\n\t\t);\n\t\tif (conflicts.length > 0) {\n\t\t\tsentences.push(\n\t\t\t\t\"A conflict means the server holds a version this folder did not name, or deleted the one it named: compare the two in the project's Context tab, and use --force to replace the version the conflict reported with this folder's (or to send a deleted file again with no version, which recreates it, or answers duplicate if that content is already stored under another path).\",\n\t\t\t);\n\t\t}\n\t}\n\tif (unsupported.length > 0) {\n\t\tsentences.push(\n\t\t\t\"This server does not support moves yet: a moved file's old path stays on the server and in the lock, its new path is not pushed, and the move is sent again on the next push.\",\n\t\t);\n\t}\n\tif (prune) {\n\t\tsentences.push(`${pruneSummary(results, pruneTargets)}.`);\n\t\tif (deleteConflicts.length > 0) {\n\t\t\tsentences.push(\n\t\t\t\t\"A file changed on the server since your last push is not deleted: compare it in the project's Context tab, and use --force to delete the version the conflict reported.\",\n\t\t\t);\n\t\t}\n\t\tif (stillDeleting.length > 0) {\n\t\t\tsentences.push(\n\t\t\t\t\"A deletion still running on the server keeps its lock entry: run again to confirm it.\",\n\t\t\t);\n\t\t}\n\t}\n\tconst firstFailure = failed[0] ?? deleteFailed[0];\n\tthrow new CliFailure(\n\t\tsentences.join(\" \"),\n\t\tfirstFailure &&\n\t\t\t(firstFailure.status === \"failed\" ||\n\t\t\t\tfirstFailure.status === \"delete-failed\")\n\t\t\t? firstFailure.exitCode\n\t\t\t: 1,\n\t);\n}\n","/**\n * The failure boundary the file-syncing command groups share —\n * `fabric instructions` and `fabric context`.\n *\n * Both groups promise the same two things: a failure a person sees maps onto\n * one of the documented exit codes (`src/bin/fabric.ts`), and under `--hook`\n * nothing ever exits non-zero or runs past one absolute deadline. The pieces\n * that make those promises live here so the two groups cannot drift apart on\n * them. Each group keeps its own `run` wrapper, because the one line a hook\n * prints names the group.\n */\nimport type { Command } from \"commander\";\n\n/** The two shapes these commands print: one JSON object, or prose. */\nexport type OutputFormat = \"text\" | \"json\";\n\n/**\n * The format this invocation should print in: `json`, or text.\n *\n * One reader, `optsWithGlobals()`, because Commander has already done the\n * resolving. The root command declares `--format` with a default of\n * `FABRIC_FORMAT ?? \"table\"`, these commands declare their own, and\n * `optsWithGlobals` merges them with the command's own value winning. Reading\n * `FABRIC_FORMAT` again here undid that: `FABRIC_FORMAT=json fabric --format\n * table instructions check` printed JSON at the very moment the flag said not\n * to (review round 2, finding 10).\n *\n * Anything that is not `json` prints text. `table`, `yaml` and `csv` are real\n * values elsewhere in this CLI and these commands have no such shape — one\n * paragraph or one JSON object — so they degrade rather than fail. Refusing\n * them here would also be a promise this cannot keep: when a parent and a\n * subcommand declare the same flag, Commander stores the value on the ROOT,\n * so `fabric instructions check --format yaml` never arrives as a local\n * option at all.\n */\nexport function outputFormatFor(command: Command): OutputFormat {\n\tconst resolved = command.optsWithGlobals() as { format?: string };\n\treturn resolved.format === \"json\" ? \"json\" : \"text\";\n}\n\n/**\n * A failure that already knows which documented exit code it is\n * (`src/bin/fabric.ts`). Errors from the SDK are translated into one of\n * these at the boundary so the command bodies can just throw.\n */\nexport class CliFailure extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\treadonly exitCode: number,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"CliFailure\";\n\t}\n}\n\n/**\n * The absolute bound on hook mode.\n *\n * A race rather than a chain of per-request timeouts: the guarantee has to\n * hold whatever the SDK, the runtime or a wedged socket does, and only the\n * caller can promise that. The losing work is abandoned rather than awaited,\n * which is safe because the boundary above exits the process immediately\n * afterwards.\n *\n * `body` receives the deadline's signal, aborted when the time is up, so work\n * that can be cancelled — a download — is cancelled by the same clock.\n */\nexport async function withDeadline(\n\ttotalMs: number,\n\tbody: (signal: AbortSignal) => Promise<void>,\n): Promise<void> {\n\tconst controller = new AbortController();\n\tlet timer: NodeJS.Timeout | undefined;\n\tconst deadline = new Promise<never>((_resolve, reject) => {\n\t\ttimer = setTimeout(() => {\n\t\t\tcontroller.abort();\n\t\t\treject(\n\t\t\t\tnew Error(\n\t\t\t\t\t`gave up after ${totalMs}ms so the session is not held up`,\n\t\t\t\t),\n\t\t\t);\n\t\t}, totalMs);\n\t});\n\ttry {\n\t\tawait Promise.race([body(controller.signal), deadline]);\n\t} finally {\n\t\tif (timer) {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t}\n}\n\nexport function describeError(error: unknown): string {\n\tif (error instanceof Error) {\n\t\t// Collapsed to one line: under `--hook` this lands in a terminal\n\t\t// banner and, on Claude Code, in the agent's context.\n\t\treturn error.message.replace(/\\s*\\n\\s*/g, \" \");\n\t}\n\treturn String(error);\n}\n\n/**\n * SDK errors carry an HTTP status; the CLI's documented exit codes do not\n * come from it automatically. Mapped once, here.\n */\nexport function asCliFailure(error: unknown): CliFailure {\n\tif (error instanceof CliFailure) {\n\t\treturn error;\n\t}\n\tconst status = (error as { status?: number }).status;\n\tconst message = error instanceof Error ? error.message : String(error);\n\tswitch (status) {\n\t\tcase 401:\n\t\t\treturn new CliFailure(message, 3);\n\t\tcase 403:\n\t\t\treturn new CliFailure(message, 5);\n\t\tcase 404:\n\t\t\treturn new CliFailure(message, 4);\n\t\tcase 429:\n\t\t\treturn new CliFailure(message, 6);\n\t\tcase 400:\n\t\tcase 422:\n\t\t\treturn new CliFailure(message, 7);\n\t\tdefault:\n\t\t\treturn new CliFailure(message, 1);\n\t}\n}\n","/**\n * `<dir>/.fabric/context.lock` — what the server confirmed at the last push.\n *\n * A CONTENT LEDGER: each path with the hash the server holds for it and the\n * context row it is stored as. It decides these things and nothing else:\n *\n * - a file whose bytes still hash to the ledger's value is not sent at all;\n * - a changed file names the ledger's hash as `expectedContentHash`, so the\n * push replaces exactly the version this folder last saw, and anybody\n * else's edit since is a conflict rather than a silent overwrite;\n * - a path gone from disk whose hash a new file has is a move, sent naming\n * the old path and that hash (Fizzy #2636);\n * - with `--prune`, a path gone from disk is deleted naming the ledger's\n * hash, so only the version this folder last saw can be deleted.\n *\n * It never causes a read (only the walk decides what is read), and a\n * deletion only under `--prune` and only of the version it names: the server\n * compares that hash before deleting anything, the way it does before a\n * replace. A tampered lock can therefore make a push skip a file, state a\n * version the server will check, or (with `--prune`) ask for a path to be\n * deleted in a version the server will check; it cannot make one reach\n * outside the folder, nor delete anything the key's owner could not delete\n * in the Context tab.\n *\n * Written LAST, after every request, with what the server answered:\n * `created`, `updated` or `unchanged` record the hash and the row; a\n * `duplicate` records the hash with `state: \"duplicate\"` and no row, because\n * the path has none of its own (its content is stored under another path).\n * An unchanged duplicate is therefore not sent again, and a changed one is\n * sent naming no version. A `moved` answer moves the entry to the new path;\n * a `--prune` deletion that happened, or found the path already gone, drops\n * it. A conflict and a failure leave their entry as it was. An interrupted run leaves the old lock, and the next run repairs\n * itself: content the server already holds is answered `unchanged` and\n * recorded then.\n *\n * Read and written through the same guarded helpers as the coding-\n * instructions lock (`../instructions/safe-write.ts`), so a `.fabric -> ..`\n * symlink cannot turn either into an access outside the folder.\n */\nimport path from \"node:path\";\nimport { readFileSafely, writeFileSafely } from \"../instructions/safe-write.js\";\nimport { normalizeContextSourcePath } from \"./source-path.js\";\n\nconst CONTEXT_LOCK_DIRECTORY = \".fabric\";\nconst CONTEXT_LOCK_FILENAME = \"context.lock\";\n\n/**\n * Bumped only if the shape below changes incompatibly. The `duplicate` entry\n * was added without a bump: confirmed entries kept their exact shape.\n */\nexport const CONTEXT_LOCK_VERSION = 1;\n\nconst CONTEXT_LOCK_RELATIVE_PATH = `${CONTEXT_LOCK_DIRECTORY}/${CONTEXT_LOCK_FILENAME}`;\n\n/** Generous: one line per pushed file. Bounds a read, it limits nobody. */\nconst MAX_CONTEXT_LOCK_BYTES = 32 * 1024 * 1024;\n\nconst SHA256_HEX = /^[0-9a-f]{64}$/;\n\n/** A path the server stores: its hash when last confirmed, and its row. */\ninterface ConfirmedContextLockEntry {\n\t/** The server's `contentHash` for this path when it was last confirmed. */\n\tsha256: string;\n\tcontextId: string;\n\tstate?: undefined;\n}\n\n/**\n * A path the server answered `duplicate` for: this content is stored under\n * another path, and this path has no row. Kept so an unchanged duplicate is\n * not sent on every run; it names no version when its content changes.\n */\ninterface DuplicateContextLockEntry {\n\t/** The hash of the content that was answered `duplicate`. */\n\tsha256: string;\n\tstate: \"duplicate\";\n\tcontextId?: undefined;\n}\n\ntype ContextLockEntry = ConfirmedContextLockEntry | DuplicateContextLockEntry;\n\nexport interface ContextLock {\n\tversion: number;\n\tprojectId: string;\n\t/** ISO 8601 timestamp of the push that wrote this lock. */\n\tpushedAt: string;\n\t/** Keyed by the normalized `sourcePath` the server stores. */\n\tfiles: Record<string, ContextLockEntry>;\n}\n\nexport function contextLockPath(root: string): string {\n\treturn path.join(root, CONTEXT_LOCK_DIRECTORY, CONTEXT_LOCK_FILENAME);\n}\n\n/**\n * The lock, or `null` when this folder has never been pushed.\n *\n * A lock that exists but does not validate is an ERROR, never a `null`:\n * reading a damaged ledger as \"first push\" would send every file with no\n * expected version, turning every one of them the server already holds into\n * a conflict and hiding the damage behind that noise.\n */\nexport async function readContextLock(\n\troot: string,\n): Promise<ContextLock | null> {\n\tconst file = contextLockPath(root);\n\tconst read = await readFileSafely(root, CONTEXT_LOCK_RELATIVE_PATH, {\n\t\tmaxBytes: MAX_CONTEXT_LOCK_BYTES,\n\t});\n\tif (read === null) {\n\t\treturn null;\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(new TextDecoder().decode(read.bytes));\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`${file} is unreadable: it is not valid JSON. Delete it to push every file again with no expected version.`,\n\t\t);\n\t}\n\tconst problem = lockProblem(parsed);\n\tif (problem !== null) {\n\t\tthrow new Error(\n\t\t\t`${file} is unreadable: ${problem}. Delete it to push every file again with no expected version.`,\n\t\t);\n\t}\n\treturn parsed as ContextLock;\n}\n\n/** Pretty JSON with LF endings and a trailing newline, so a diff of it reads. */\nfunction serializeLock(lock: ContextLock): string {\n\treturn `${JSON.stringify(lock, null, 2).replace(/\\r\\n/g, \"\\n\")}\\n`;\n}\n\n/** Atomic (temp file, then rename), through the guarded writer. */\nexport async function writeContextLock(\n\troot: string,\n\tlock: ContextLock,\n): Promise<void> {\n\tawait writeFileSafely({\n\t\troot,\n\t\trelativePath: CONTEXT_LOCK_RELATIVE_PATH,\n\t\tbytes: new TextEncoder().encode(serializeLock(lock)),\n\t});\n}\n\n/**\n * Why this value is not a lock, or `null` when it is one.\n *\n * Every path must already be in the server's stored spelling. That keeps a\n * hand-edited lock from printing a control character into the terminal when\n * a path is reported, and from naming anything the server could never hold.\n */\nfunction lockProblem(value: unknown): string | null {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n\t\treturn \"it is not a JSON object\";\n\t}\n\tconst candidate = value as Record<string, unknown>;\n\tif (candidate.version !== CONTEXT_LOCK_VERSION) {\n\t\treturn `its version is ${JSON.stringify(candidate.version)} and this build writes version ${CONTEXT_LOCK_VERSION}`;\n\t}\n\tfor (const field of [\"projectId\", \"pushedAt\"] as const) {\n\t\tconst actual = candidate[field];\n\t\tif (typeof actual !== \"string\" || actual.length === 0) {\n\t\t\treturn `its \"${field}\" is not a non-empty string`;\n\t\t}\n\t}\n\tif (\n\t\ttypeof candidate.files !== \"object\" ||\n\t\tcandidate.files === null ||\n\t\tArray.isArray(candidate.files)\n\t) {\n\t\treturn 'its \"files\" is not an object';\n\t}\n\tfor (const [filePath, entry] of Object.entries(\n\t\tcandidate.files as Record<string, unknown>,\n\t)) {\n\t\tconst normalized = normalizeContextSourcePath(filePath);\n\t\tif (!normalized.ok || normalized.sourcePath !== filePath) {\n\t\t\treturn `it names ${JSON.stringify(filePath)}, which is not a path the server stores`;\n\t\t}\n\t\tif (\n\t\t\ttypeof entry !== \"object\" ||\n\t\t\tentry === null ||\n\t\t\tArray.isArray(entry)\n\t\t) {\n\t\t\treturn `its entry for ${JSON.stringify(filePath)} is not an object`;\n\t\t}\n\t\tconst record = entry as Record<string, unknown>;\n\t\tif (\n\t\t\ttypeof record.sha256 !== \"string\" ||\n\t\t\t!SHA256_HEX.test(record.sha256)\n\t\t) {\n\t\t\treturn `its entry for ${JSON.stringify(filePath)} has no 64-character hex sha256`;\n\t\t}\n\t\tif (record.state === \"duplicate\") {\n\t\t\tif (record.contextId !== undefined) {\n\t\t\t\treturn `its duplicate entry for ${JSON.stringify(filePath)} names a contextId, which a duplicate never has`;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (record.state !== undefined) {\n\t\t\treturn `its entry for ${JSON.stringify(filePath)} has an unknown state ${JSON.stringify(record.state)}`;\n\t\t}\n\t\tif (\n\t\t\ttypeof record.contextId !== \"string\" ||\n\t\t\trecord.contextId.length === 0\n\t\t) {\n\t\t\treturn `its entry for ${JSON.stringify(filePath)} has no contextId`;\n\t\t}\n\t}\n\treturn null;\n}\n","/**\n * The one writer every file this feature creates goes through — instruction\n * files, the lock, and the Claude Code settings file alike.\n *\n * It exists because there were three writers before and only one of them was\n * guarded. `.claude -> ..` or `.fabric -> ..` in a checkout turned `init` and\n * `sync` into writes outside the destination, because the hook and the lock\n * never asked the question the instruction files did. A guard that only some\n * writes call is not a guard.\n *\n * What every write proves first:\n *\n * 1. The destination is canonicalised once with `realpath`. Lexical\n * resolution is not enough — `/tmp` is a symlink on macOS, so the\n * literal string a user passes and the directory they mean are\n * routinely different, and containment has to be decided on the real\n * one. The destination itself is resolved rather than refused for that\n * reason; everything BELOW it is held to the stricter rule.\n * 2. No segment between the root and the file is a symlink. Checked with\n * `lstat`, from the first child down to and including the target.\n * 3. The deepest existing ancestor's `realpath` is still inside the root.\n * Layer 2 answers \"is this a link\"; this answers \"did anything else —\n * a bind mount, a replaced directory — move it\".\n * 4. The temp file is created with `wx` and an unpredictable name, so a\n * pre-planted file is an error rather than a file we write through.\n * 5. The parent is re-checked immediately before `rename`, closing the\n * window between the walk and the write.\n *\n * Bytes are preserved exactly: no newline conversion, no re-encoding. The\n * server hashes these files and so does the next sync.\n */\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { constants, type Stats } from \"node:fs\";\nimport type { FileHandle } from \"node:fs/promises\";\nimport {\n\tlstat,\n\tmkdir,\n\topen,\n\treadFile,\n\trealpath,\n\trename,\n\tunlink,\n} from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { describeRejection, type PathCheck } from \"./paths.js\";\n\n/**\n * The modes a published file may carry.\n *\n * The server derives exactly these two from an upload, so anything else is a\n * malformed or hostile manifest rather than a file that needs it. An\n * allow-list rather than a mask, because masking with `0o7777` preserves\n * setuid, setgid, sticky and every write bit — a manifest asking for `04777`\n * would have been honoured.\n */\nconst ALLOWED_MODES = new Set([0o644, 0o755]);\n\nexport function isAllowedMode(mode: number | null | undefined): boolean {\n\tif (mode === null || mode === undefined) {\n\t\treturn true;\n\t}\n\tif (!Number.isInteger(mode) || mode < 0) {\n\t\treturn false;\n\t}\n\t// A manifest records the full `st_mode` (`0o100644`), so compare on the\n\t// permission bits and require the file-type bits to be a regular file or\n\t// absent.\n\tconst type = mode & 0o170000;\n\tif (type !== 0 && type !== 0o100000) {\n\t\treturn false;\n\t}\n\treturn ALLOWED_MODES.has(mode & 0o7777);\n}\n\n/** The permission bits to apply, or null when none were published. */\nexport function permissionBits(mode: number | null | undefined): number | null {\n\tif (mode === null || mode === undefined) {\n\t\treturn null;\n\t}\n\treturn mode & 0o7777;\n}\n\n/**\n * Canonicalise the destination once, for every subsequent check to resolve\n * against. Created if missing: `--dest` naming a directory that does not\n * exist yet is an ordinary first sync.\n */\nexport async function resolveDestinationRoot(\n\tdestination: string,\n): Promise<string> {\n\tawait mkdir(destination, { recursive: true });\n\treturn realpath(destination);\n}\n\n/**\n * Where a relative path lands under an already-canonical root, or why it may\n * not land at all. `relativePath` must already have passed\n * `checkRelativePath`.\n */\nexport async function assertSafeTarget(\n\troot: string,\n\trelativePath: string,\n): Promise<PathCheck> {\n\tconst target = path.resolve(root, relativePath);\n\tif (target === root || !target.startsWith(root + path.sep)) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\treason: \"escapes_destination\",\n\t\t\tdetail: relativePath,\n\t\t};\n\t}\n\n\tconst segments = relativePath.split(\"/\");\n\tlet current = root;\n\tlet deepestExisting = root;\n\tfor (const [index, segment] of segments.entries()) {\n\t\tcurrent = path.join(current, segment);\n\t\tconst stats = await lstatOrNull(current);\n\t\tif (stats === null) {\n\t\t\t// Everything below here is about to be created, and a path that\n\t\t\t// does not exist cannot be a link to somewhere else.\n\t\t\tbreak;\n\t\t}\n\t\tif (stats.isSymbolicLink()) {\n\t\t\treturn { ok: false, reason: \"symlink\", detail: current };\n\t\t}\n\t\t// An ANCESTOR that is not a directory. `lstat` on anything below it\n\t\t// answers ENOTDIR, which used to read as \"absent\" — so a regular file\n\t\t// at `z` let `z/child.md` pass the whole-plan preflight and fail in\n\t\t// `makeParents` after earlier entries had already been written.\n\t\tif (index < segments.length - 1 && !stats.isDirectory()) {\n\t\t\treturn { ok: false, reason: \"not_a_directory\", detail: current };\n\t\t}\n\t\tdeepestExisting = current;\n\t}\n\n\t// Layer 3. `lstat` said no component IS a link; this says the components\n\t// still resolve where they appeared to.\n\tif (deepestExisting !== root) {\n\t\tconst canonical = await realpath(deepestExisting).catch(() => null);\n\t\tif (\n\t\t\tcanonical !== null &&\n\t\t\tcanonical !== root &&\n\t\t\t!canonical.startsWith(root + path.sep)\n\t\t) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: \"escapes_destination\",\n\t\t\t\tdetail: relativePath,\n\t\t\t};\n\t\t}\n\t}\n\n\treturn { ok: true, path: target };\n}\n\n/**\n * `assertSafeTarget`, plus: whatever is already at the final path must be an\n * ordinary file.\n *\n * `assertSafeTarget` answers \"may this land here\" — no symlinked component,\n * nothing resolving outside the root. It does not answer \"is the thing\n * already there a file\". A directory at a manifest path passed it, and the\n * eventual `rename` refused, but only after earlier entries in the same plan\n * had already been written. A fifo, socket or device node would be opened and\n * written through. Both are now refusals, and the caller runs this over EVERY\n * manifest and delete path before it mutates anything.\n */\nexport async function assertWritableTarget(\n\troot: string,\n\trelativePath: string,\n): Promise<PathCheck> {\n\tconst check = await assertSafeTarget(root, relativePath);\n\tif (!check.ok) {\n\t\treturn check;\n\t}\n\tconst stats = await lstatOrNull(check.path);\n\tif (stats === null) {\n\t\treturn check;\n\t}\n\tif (stats.isSymbolicLink()) {\n\t\treturn { ok: false, reason: \"symlink\", detail: check.path };\n\t}\n\tif (!stats.isFile()) {\n\t\treturn { ok: false, reason: \"not_a_regular_file\", detail: check.path };\n\t}\n\treturn check;\n}\n\n/**\n * Read a file under an already-canonical root, through the same guard every\n * write goes through, or `null` when it is not there.\n *\n * READS need the walk as much as writes do. The ledger check and the planner\n * used to `path.join` and `lstat` directly, which meant a lock path of\n * `../outside` read outside the destination, and an ancestor replaced by a\n * symlink was followed to wherever it pointed — hashing, and possibly loading\n * into memory, a file this tool has no business opening. A refusal is the\n * answer in both cases, not a hash.\n */\nexport async function readFileSafely(\n\troot: string,\n\trelativePath: string,\n\toptions: { maxBytes?: number } = {},\n): Promise<{ bytes: Uint8Array; mode: number } | null> {\n\tconst check = await assertWritableTarget(root, relativePath);\n\tif (!check.ok) {\n\t\tthrow new Error(`Refusing to sync: ${describeRejection(check)}.`);\n\t}\n\n\tlet handle: FileHandle;\n\ttry {\n\t\t// `O_NOFOLLOW` makes a final-component swap fail rather than following\n\t\t// it. `O_NONBLOCK` prevents a raced FIFO from holding the command before\n\t\t// the descriptor can be proven to be an ordinary file.\n\t\thandle = await open(\n\t\t\tcheck.path,\n\t\t\tconstants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK,\n\t\t);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\treturn null;\n\t\t}\n\t\tthrow error;\n\t}\n\n\ttry {\n\t\tconst opened = await handle.stat();\n\t\tif (!opened.isFile()) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${relativePath} is not a regular file.`,\n\t\t\t);\n\t\t}\n\t\t// Re-walk after opening, then bind the descriptor to the path that was\n\t\t// just checked. A swapped ancestor may make the path point elsewhere,\n\t\t// but no bytes are read until both checks agree on the same inode.\n\t\tconst afterOpen = await assertWritableTarget(root, relativePath);\n\t\tif (!afterOpen.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection(afterOpen)}.`,\n\t\t\t);\n\t\t}\n\t\tconst current = await lstatOrNull(afterOpen.path);\n\t\tif (\n\t\t\tcurrent === null ||\n\t\t\t!current.isFile() ||\n\t\t\tcurrent.dev !== opened.dev ||\n\t\t\tcurrent.ino !== opened.ino\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${relativePath} changed while it was being opened.`,\n\t\t\t);\n\t\t}\n\n\t\tif (options.maxBytes === undefined) {\n\t\t\treturn { bytes: await handle.readFile(), mode: opened.mode };\n\t\t}\n\t\tif (!Number.isSafeInteger(options.maxBytes) || options.maxBytes < 0) {\n\t\t\tthrow new Error(\n\t\t\t\t\"A safe file-read limit must be a non-negative integer.\",\n\t\t\t);\n\t\t}\n\t\tif (opened.size > options.maxBytes) {\n\t\t\tthrow new Error(\n\t\t\t\t`${relativePath} is too large to read safely (maximum ${options.maxBytes} bytes).`,\n\t\t\t);\n\t\t}\n\n\t\t// The extra byte catches a file that grew after `fstat` without ever\n\t\t// allocating or reading an unbounded body.\n\t\tconst buffer = Buffer.allocUnsafe(options.maxBytes + 1);\n\t\tlet total = 0;\n\t\twhile (total <= options.maxBytes) {\n\t\t\tconst { bytesRead } = await handle.read(\n\t\t\t\tbuffer,\n\t\t\t\ttotal,\n\t\t\t\toptions.maxBytes + 1 - total,\n\t\t\t\ttotal,\n\t\t\t);\n\t\t\tif (bytesRead === 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\ttotal += bytesRead;\n\t\t}\n\t\tif (total > options.maxBytes) {\n\t\t\tthrow new Error(\n\t\t\t\t`${relativePath} is too large to read safely (maximum ${options.maxBytes} bytes).`,\n\t\t\t);\n\t\t}\n\t\treturn { bytes: buffer.subarray(0, total), mode: opened.mode };\n\t} finally {\n\t\tawait handle.close();\n\t}\n}\n\n/**\n * The canonical form of a destination that must NOT be created.\n *\n * `resolveDestinationRoot` makes the directory, which is right for a sync and\n * wrong for `check`, an informational command. A destination that does not\n * exist has no lock either, so the literal resolved path is a fine answer.\n */\nexport async function resolveExistingRoot(\n\tdestination: string,\n): Promise<string> {\n\treturn realpath(destination).catch(() => path.resolve(destination));\n}\n\n/**\n * Create every missing parent directory of `relativePath`, one segment at a\n * time, refusing a symlink at each step.\n *\n * `mkdir(..., { recursive: true })` cannot be used for this: it follows an\n * existing symlinked component silently, which is the whole thing being\n * defended against.\n */\nasync function makeParents(root: string, relativePath: string): Promise<void> {\n\tconst segments = relativePath.split(\"/\").slice(0, -1);\n\tlet current = root;\n\tfor (const segment of segments) {\n\t\tcurrent = path.join(current, segment);\n\t\tconst stats = await lstatOrNull(current);\n\t\tif (stats === null) {\n\t\t\tawait mkdir(current).catch(async (error: NodeJS.ErrnoException) => {\n\t\t\t\t// A concurrent writer got there first. Re-check what landed\n\t\t\t\t// rather than assuming it is a directory.\n\t\t\t\tif (error.code !== \"EEXIST\") {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tconst raced = await lstatOrNull(current);\n\t\t\t\tif (raced?.isSymbolicLink()) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Refusing to sync: ${describeRejection({ ok: false, reason: \"symlink\", detail: current })}.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (stats.isSymbolicLink()) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection({ ok: false, reason: \"symlink\", detail: current })}.`,\n\t\t\t);\n\t\t}\n\t\tif (!stats.isDirectory()) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection({ ok: false, reason: \"not_a_directory\", detail: current })}.`,\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * Write one file atomically under an already-canonical root.\n *\n * `relativePath` must have passed `checkRelativePath` and any policy check\n * the caller owns (reserved paths, collisions) BEFORE this is called — this\n * function enforces the filesystem invariants, not the feature's rules.\n */\nexport async function writeFileSafely(input: {\n\troot: string;\n\trelativePath: string;\n\tbytes: Uint8Array;\n\tmode?: number | null;\n}): Promise<void> {\n\tconst check = await assertSafeTarget(input.root, input.relativePath);\n\tif (!check.ok) {\n\t\tthrow new Error(`Refusing to sync: ${describeRejection(check)}.`);\n\t}\n\tif (!isAllowedMode(input.mode)) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${input.relativePath} asks for file mode ${(input.mode ?? 0).toString(8)}, and only 644 and 755 are accepted.`,\n\t\t);\n\t}\n\n\tawait makeParents(input.root, input.relativePath);\n\n\tconst target = check.path;\n\tconst directory = path.dirname(target);\n\t// The identity of the directory we are about to create the temp file in.\n\t// Cleanup below unlinks BY PATH, and a path no longer names the same\n\t// directory once something has swapped it; unlinking then would delete a\n\t// stranger's file and leave the real temp behind. Node has no\n\t// handle-relative unlink, so the next best thing is to refuse to clean up\n\t// through a path that has moved.\n\tconst directoryBefore = await lstatOrNull(directory);\n\t// Unpredictable, so a pre-planted temp file cannot be waiting for us, and\n\t// `wx` so creating one that already exists is an error rather than a\n\t// write through whatever is there.\n\tconst temporary = path.join(\n\t\tdirectory,\n\t\t`.${path.basename(target)}.${randomBytes(8).toString(\"hex\")}.tmp`,\n\t);\n\n\tlet handle: FileHandle | null = null;\n\ttry {\n\t\thandle = await open(temporary, \"wx\", 0o600);\n\t\tawait handle.writeFile(input.bytes);\n\t\tconst bits = permissionBits(input.mode);\n\t\tif (bits !== null && process.platform !== \"win32\") {\n\t\t\tawait handle.chmod(bits);\n\t\t}\n\t\tawait handle.close();\n\t\thandle = null;\n\n\t\t// The walk above happened before the file was written. Re-check the\n\t\t// parent now, so a directory swapped for a link in between cannot\n\t\t// receive the rename.\n\t\tconst parentStats = await lstatOrNull(directory);\n\t\tif (parentStats === null || parentStats.isSymbolicLink()) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection({ ok: false, reason: \"symlink\", detail: directory })}.`,\n\t\t\t);\n\t\t}\n\t\tconst targetStats = await lstatOrNull(target);\n\t\tif (targetStats?.isSymbolicLink()) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection({ ok: false, reason: \"symlink\", detail: target })}.`,\n\t\t\t);\n\t\t}\n\n\t\tawait rename(temporary, target);\n\t} catch (error) {\n\t\tawait handle?.close().catch(() => {});\n\t\tif (await isSameDirectory(directory, directoryBefore)) {\n\t\t\tawait unlink(temporary).catch(() => {});\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/** Does this path still name the directory we checked earlier? */\nasync function isSameDirectory(\n\tdirectory: string,\n\tbefore: Stats | null,\n): Promise<boolean> {\n\tif (before === null) {\n\t\treturn false;\n\t}\n\tconst now = await lstatOrNull(directory);\n\treturn now !== null && now.dev === before.dev && now.ino === before.ino;\n}\n\nexport type DeleteOutcome = \"deleted\" | \"missing\" | \"modified\";\n\n/**\n * Remove one file under an already-canonical root — but only if it is still\n * the file the caller decided to remove.\n *\n * The plan hashes a departed file during planning, and a download, an\n * extraction and every write happen between then and here. An unconditional\n * `unlink` therefore deleted whatever was at that path by the time it ran,\n * including an edit the developer had saved in the meantime. The expected\n * hash travels with the request and is checked against the bytes on disk\n * immediately before the unlink; a file that no longer matches is left alone\n * and reported as kept.\n *\n * Residual, stated rather than hidden: a write landing between that hash and\n * the `unlink` is still lost. Node offers no way to unlink a specific inode,\n * so closing it entirely would need handle-relative syscalls the runtime does\n * not expose. Concurrent mutation of the destination by the same user during\n * a sync is out of scope for this tool.\n */\nexport async function deleteFileSafely(\n\troot: string,\n\trelativePath: string,\n\texpectedSha256: string,\n): Promise<DeleteOutcome> {\n\tconst check = await assertSafeTarget(root, relativePath);\n\tif (!check.ok) {\n\t\tthrow new Error(`Refusing to sync: ${describeRejection(check)}.`);\n\t}\n\n\tconst stats = await lstatOrNull(check.path);\n\tif (stats === null) {\n\t\treturn \"missing\";\n\t}\n\tif (stats.isSymbolicLink()) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${describeRejection({ ok: false, reason: \"symlink\", detail: check.path })}.`,\n\t\t);\n\t}\n\tif (!stats.isFile()) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${describeRejection({ ok: false, reason: \"not_a_regular_file\", detail: check.path })}.`,\n\t\t);\n\t}\n\n\tlet actual: string;\n\ttry {\n\t\tactual = createHash(\"sha256\")\n\t\t\t.update(await readFile(check.path))\n\t\t\t.digest(\"hex\");\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\treturn \"missing\";\n\t\t}\n\t\tthrow error;\n\t}\n\tif (actual !== expectedSha256) {\n\t\treturn \"modified\";\n\t}\n\n\ttry {\n\t\tawait unlink(check.path);\n\t\treturn \"deleted\";\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\treturn \"missing\";\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * `lstat`, with ONLY `ENOENT` meaning \"nothing there\".\n *\n * `ENOTDIR` used to be folded in here, and it does not mean the same thing at\n * all: it means an ancestor exists and is not a directory. Reading it as\n * \"absent\" is what let a regular file at `z` pass the preflight for\n * `z/child.md`. Callers that walk a path check the ancestors themselves; this\n * one lets the error through so nothing can mistake the two again.\n */\nasync function lstatOrNull(target: string) {\n\ttry {\n\t\treturn await lstat(target);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\treturn null;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * Does `candidate` sit inside `root` once both are resolved as far as the\n * filesystem allows?\n *\n * Used for the credential check in `hook.ts`, where the question is about a\n * path that may not exist yet and whose ancestors may be links. Lexical\n * comparison answered it wrongly in both directions: a config file reached\n * through a symlink into the checkout looked outside it, and a destination\n * under a symlinked parent looked like a mismatch.\n */\nexport async function resolvesInside(\n\troot: string,\n\tcandidate: string,\n): Promise<boolean> {\n\tconst canonicalRoot = await realpath(root).catch(() => path.resolve(root));\n\tconst canonicalCandidate = await realpathDeepest(candidate);\n\treturn (\n\t\tcanonicalCandidate === canonicalRoot ||\n\t\tcanonicalCandidate.startsWith(canonicalRoot + path.sep)\n\t);\n}\n\n/**\n * `realpath` of the deepest existing ancestor, with the not-yet-existing tail\n * appended. `realpath` throws on a missing path, and a config file that has\n * not been written yet still has an answer worth having.\n */\nasync function realpathDeepest(candidate: string): Promise<string> {\n\tconst absolute = path.resolve(candidate);\n\tconst tail: string[] = [];\n\tlet current = absolute;\n\tfor (;;) {\n\t\tconst resolved = await realpath(current).catch(() => null);\n\t\tif (resolved !== null) {\n\t\t\treturn tail.length === 0 ? resolved : path.join(resolved, ...tail);\n\t\t}\n\t\tconst parent = path.dirname(current);\n\t\tif (parent === current) {\n\t\t\treturn absolute;\n\t\t}\n\t\ttail.unshift(path.basename(current));\n\t\tcurrent = parent;\n\t}\n}\n","/**\n * Path safety for the file-writing half of this CLI.\n *\n * The paths this module guards arrive from a server response and from a zip\n * archive, and they are about to become filesystem writes on a developer's\n * machine. That makes the check local: the server validates paths on upload,\n * but a client that trusts a remote path list has moved the decision to the\n * wrong side of the wire. Nothing here asks the network anything.\n *\n * Three layers, and they answer different questions:\n *\n * `checkRelativePath` is this STRING safe to turn into a write?\n * `isReservedPath` is this path one this feature refuses to own?\n * `collisionKey` do two safe strings name the same file anyway?\n *\n * The filesystem half — symlinks, canonical containment, atomic writes —\n * lives in `safe-write.ts`, because it needs a resolved destination root and\n * these functions deliberately do not.\n *\n * The SERVER enforces the same name rules and the same collision key on the\n * way in (`packages/instructions/src/paths.ts`), so a version that stores is\n * a version that installs. It is a separate implementation because this\n * package is published to npm and that one is private, and the duplication is\n * pinned by `packages/instructions/__tests__/portable-names-agree-with-cli.test.ts`,\n * which imports both and asserts they agree on a fixture list of names.\n * Whole-path SYNTAX is where the two legitimately differ: the server\n * normalises separators and `./` prefixes for a browser folder upload, and\n * this module refuses them, because here the string is about to become a\n * write.\n */\n\ntype PathRejectReason =\n\t| \"empty\"\n\t| \"absolute\"\n\t| \"traversal\"\n\t| \"backslash\"\n\t| \"control_char\"\n\t| \"trailing_separator\"\n\t| \"trailing_dot_or_space\"\n\t| \"reserved_device_name\"\n\t| \"forbidden_character\"\n\t| \"reserved_path\"\n\t| \"not_a_regular_file\"\n\t| \"escapes_destination\"\n\t| \"symlink\"\n\t| \"not_a_directory\"\n\t| \"collision\";\n\nexport interface PathRejection {\n\tok: false;\n\treason: PathRejectReason;\n\t/** The offending path, as given, or the link that was in the way. */\n\tdetail: string;\n}\n\nexport type PathCheck = { ok: true; path: string } | PathRejection;\n\nconst DRIVE_LETTER = /^[A-Za-z]:/;\n\n/**\n * Names Windows resolves to a device rather than a file, with or without an\n * extension: `NUL`, `nul.txt` and `CON.md` all reach the device. Writing the\n * tree on Windows would silently discard those files; worse, a manifest could\n * use one to make a write look like it happened.\n */\nconst RESERVED_DEVICE_NAME = /^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(?:\\.|$)/i;\n\n/**\n * The characters Windows will not put in a filename: `< > : \" | ? *`.\n *\n * `/` and `\\` are absent because they are separators and are refused\n * structurally above.\n */\nconst FORBIDDEN_NAME_CHARACTER = /[<>:\"|?*]/;\n\n/**\n * Paths this feature refuses to write or delete, whatever a manifest or a\n * lock says.\n *\n * `.git` is the obvious one: a lock is a plain JSON file inside the checkout,\n * so anything that can edit it could otherwise name `.git/config` — a file\n * whose current hash is easy to know — and have the next sync unlink it.\n * `.fabric` is here because the lock lives there and must never be able to\n * authorise its own deletion or replacement through the manifest path.\n */\nconst RESERVED_ROOTS = [\".git\", \".fabric\"] as const;\n\n/**\n * Single files this feature refuses to own, as opposed to whole roots.\n *\n * `.claude/settings.local.json` and `.codex/hooks.json` are the files `init`\n * itself writes. Instruction files legitimately live elsewhere under either\n * root — skills and commands — so reserving a whole root would refuse the\n * feature's own content. Reserving only these paths stops a published manifest\n * from overwriting a session hook or later authorising its deletion.\n */\nconst RESERVED_EXACT_PATHS = [\n\t\".claude/settings.local.json\",\n\t\".codex/hooks.json\",\n] as const;\n\n/**\n * Basenames this feature refuses to own AT ANY DEPTH, unlike\n * `RESERVED_EXACT_PATHS` above, which reserves exact root paths only.\n *\n * `CLAUDE.local.md` is Claude Code's convention for machine-personal notes,\n * and Claude Code reads it in any directory it walks — a nested\n * `packages/web/CLAUDE.local.md` is just as personal to one machine as a\n * root one. A published manifest or lock entry naming it would let `sync`\n * write, overwrite, or delete a file that was never meant to leave the\n * machine it was written on, and `push --add` would publish it. Matched by\n * basename, not by whole path, so it applies wherever the file appears.\n */\nconst RESERVED_BASENAMES = [\"CLAUDE.local.md\"] as const;\n\n/**\n * NUL and friends, found by character code rather than by a regular\n * expression.\n *\n * A character class cannot say this here. Written as unicode escapes, the\n * formatter rewrites each escape into the character it names, which puts\n * a literal NUL byte in this source file and makes git treat it as binary.\n * A loop says the same thing and stays readable in a diff.\n */\nfunction hasControlCharacter(input: string): boolean {\n\tfor (let index = 0; index < input.length; index++) {\n\t\tconst code = input.charCodeAt(index);\n\t\tif (code <= 0x1f || code === 0x7f) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Is this manifest/archive path safe to turn into a write inside a\n * destination? String-level only — see `safe-write.ts` for the filesystem\n * half.\n */\nexport function checkRelativePath(input: string): PathCheck {\n\tif (input.length === 0) {\n\t\treturn { ok: false, reason: \"empty\", detail: input };\n\t}\n\tif (hasControlCharacter(input)) {\n\t\treturn { ok: false, reason: \"control_char\", detail: input };\n\t}\n\tif (input.includes(\"\\\\\")) {\n\t\treturn { ok: false, reason: \"backslash\", detail: input };\n\t}\n\tif (input.startsWith(\"/\") || DRIVE_LETTER.test(input)) {\n\t\treturn { ok: false, reason: \"absolute\", detail: input };\n\t}\n\tif (input.endsWith(\"/\")) {\n\t\treturn { ok: false, reason: \"trailing_separator\", detail: input };\n\t}\n\tconst segments = input.split(\"/\");\n\tif (segments.some((s) => s.length === 0)) {\n\t\t// An empty segment means `a//b` or a leading slash already refused\n\t\t// above; either way the string is not the path it appears to be.\n\t\treturn { ok: false, reason: \"empty\", detail: input };\n\t}\n\tif (segments.some((s) => s === \".\" || s === \"..\")) {\n\t\treturn { ok: false, reason: \"traversal\", detail: input };\n\t}\n\tfor (const segment of segments) {\n\t\t// Windows strips a trailing dot or space from a name, so `a.md.` and\n\t\t// `a.md ` both open `a.md`. Two manifest entries that differ only\n\t\t// there would be two writes to one file, with the lock claiming both.\n\t\tif (/[. ]$/.test(segment)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: \"trailing_dot_or_space\",\n\t\t\t\tdetail: input,\n\t\t\t};\n\t\t}\n\t\tif (RESERVED_DEVICE_NAME.test(segment)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: \"reserved_device_name\",\n\t\t\t\tdetail: input,\n\t\t\t};\n\t\t}\n\t\t// One of the characters Windows refuses in a filename. A colon also\n\t\t// addresses an NTFS alternate data stream on the name before it,\n\t\t// which is a write to a file the manifest never named; `*` and `?`\n\t\t// are glob metacharacters and `<`, `>` and `|` are redirection\n\t\t// operators, so such a name is a hazard in any script over the tree.\n\t\tif (FORBIDDEN_NAME_CHARACTER.test(segment)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: \"forbidden_character\",\n\t\t\t\tdetail: input,\n\t\t\t};\n\t\t}\n\t}\n\treturn { ok: true, path: input };\n}\n\n/**\n * Is this a path this feature refuses to own, whoever asked?\n *\n * Applied to manifest entries AND to lock entries, on writes AND on deletes:\n * the lock is the thing being defended against here, so checking only what\n * the server sent would miss the case entirely.\n */\nexport function isReservedPath(input: string): boolean {\n\tconst first = input.split(\"/\")[0]?.toLowerCase();\n\tif (RESERVED_ROOTS.some((root) => first === root)) {\n\t\treturn true;\n\t}\n\t// Compared by collision key, not by string: on a case-insensitive\n\t// filesystem `.claude/Settings.Local.json` is the same file, and a\n\t// manifest that spells it differently must not slip past.\n\tconst key = collisionKey(input);\n\tif (\n\t\tRESERVED_EXACT_PATHS.some((reserved) => collisionKey(reserved) === key)\n\t) {\n\t\treturn true;\n\t}\n\t// Basename, not whole path: `CLAUDE.local.md` is reserved wherever it\n\t// appears, unlike the exact root paths above.\n\tconst segments = input.split(\"/\");\n\tconst basenameKey = collisionKey(segments[segments.length - 1] ?? \"\");\n\treturn RESERVED_BASENAMES.some(\n\t\t(reserved) => collisionKey(reserved) === basenameKey,\n\t);\n}\n\n/**\n * A key two paths share when the filesystem would treat them as one file.\n *\n * macOS stores names in a normalised form and compares case-insensitively,\n * so `café.md` written as NFC and as NFD are one file with two spellings,\n * and `README.md`/`readme.md` are one file. The server's own collision check\n * catches ordinary case variants; it does not catch Unicode normalisation.\n *\n * Deliberately conservative and platform-independent: a manifest that would\n * collide on macOS is refused on Linux too, because the alternative is a\n * tree that syncs cleanly for one developer and silently loses a file for\n * the next.\n */\nexport function collisionKey(input: string): string {\n\treturn input.normalize(\"NFC\").toLowerCase();\n}\n\n/**\n * The first pair of manifest/lock paths that name the same file, or null.\n */\nexport function findCollision(\n\tpaths: readonly string[],\n): { first: string; second: string } | null {\n\tconst seen = new Map<string, string>();\n\tfor (const candidate of paths) {\n\t\tconst key = collisionKey(candidate);\n\t\tconst previous = seen.get(key);\n\t\tif (previous !== undefined) {\n\t\t\treturn { first: previous, second: candidate };\n\t\t}\n\t\tseen.set(key, candidate);\n\t}\n\treturn null;\n}\n\n/** A one-line reason a reader can act on. */\nexport function describeRejection(rejection: PathRejection): string {\n\tswitch (rejection.reason) {\n\t\tcase \"empty\":\n\t\t\treturn `empty or malformed path (${JSON.stringify(rejection.detail)})`;\n\t\tcase \"absolute\":\n\t\t\treturn `absolute path refused: ${rejection.detail}`;\n\t\tcase \"traversal\":\n\t\t\treturn `path traversal refused: ${rejection.detail}`;\n\t\tcase \"backslash\":\n\t\t\treturn `backslash in path refused: ${rejection.detail}`;\n\t\tcase \"control_char\":\n\t\t\treturn `control character in path refused: ${JSON.stringify(rejection.detail)}`;\n\t\tcase \"trailing_separator\":\n\t\t\treturn `path names a directory, not a file: ${rejection.detail}`;\n\t\tcase \"trailing_dot_or_space\":\n\t\t\treturn `path segment ending in a dot or space refused: ${rejection.detail}`;\n\t\tcase \"reserved_device_name\":\n\t\t\treturn `reserved device name refused: ${rejection.detail}`;\n\t\tcase \"forbidden_character\":\n\t\t\treturn `path contains a character Windows will not put in a filename (< > : \" | ? *): ${rejection.detail}`;\n\t\tcase \"reserved_path\":\n\t\t\treturn `this tool never writes or deletes ${RESERVED_ROOTS.join(\", \")}, ${RESERVED_EXACT_PATHS.join(\", \")}, or a ${RESERVED_BASENAMES.join(\", \")} at any depth: ${rejection.detail}`;\n\t\tcase \"not_a_regular_file\":\n\t\t\treturn `path is not a regular file: ${rejection.detail}`;\n\t\tcase \"escapes_destination\":\n\t\t\treturn `path resolves outside the destination: ${rejection.detail}`;\n\t\tcase \"symlink\":\n\t\t\t// \"follow\", not \"write through\": the same guard now runs for reads\n\t\t\t// — the ledger check and the planner both go through it — and a\n\t\t\t// read-only `check --verify` should not talk about writing.\n\t\t\treturn `refusing to follow a symlink: ${rejection.detail}`;\n\t\tcase \"not_a_directory\":\n\t\t\treturn `a path component is not a directory: ${rejection.detail}`;\n\t\tcase \"collision\":\n\t\t\treturn `two paths name the same file on a case- or Unicode-insensitive filesystem: ${rejection.detail}`;\n\t}\n}\n","/**\n * The server's rule for a synced context file's path, mirrored so a file the\n * server would refuse is skipped here with the same reason word instead of\n * costing a request that can only fail.\n *\n * The authority is `normalizeContextSourcePath` in\n * `packages/database/prisma/queries/projects/context-source-path.ts`; this is\n * a copy rather than an import because `@fabricorg/cli` is published to npm\n * and that package is private. Keep the two in step: the reason words below\n * are the server's `ContextSourcePathErrorReason` values.\n *\n * - NFC first, so a decomposed name (macOS) and a composed one are one key;\n * - `\\` becomes `/`, repeated separators collapse, a leading `./` goes;\n * - absolute paths (`/…`, `\\\\server\\…`, any drive-letter prefix) refused;\n * - a `.` or `..` segment refused anywhere;\n * - a trailing separator refused;\n * - C0, DEL, C1 and format (`\\p{Cf}`) characters refused;\n * - at most 512 characters after normalising.\n */\n\nconst MAX_CONTEXT_SOURCE_PATH_LENGTH = 512;\n\ntype ContextSourcePathProblem =\n\t| \"empty\"\n\t| \"absolute\"\n\t| \"dot-segment\"\n\t| \"trailing-slash\"\n\t| \"control-character\"\n\t| \"too-long\";\n\nexport type ContextSourcePathCheck =\n\t| { ok: true; sourcePath: string }\n\t| { ok: false; reason: ContextSourcePathProblem };\n\n// Written with escapes so this file itself carries no such characters.\n// biome-ignore lint/suspicious/noControlCharactersInRegex: matching control characters is the point\nconst CONTROL_OR_FORMAT_CHARACTER = /[\\u0000-\\u001f\\u007f-\\u009f\\p{Cf}]/u;\nconst DRIVE_LETTER_PREFIX = /^[A-Za-z]:/;\n\nfunction hasControlOrFormatCharacter(value: string): boolean {\n\treturn CONTROL_OR_FORMAT_CHARACTER.test(value);\n}\n\nexport function normalizeContextSourcePath(\n\tinput: string,\n): ContextSourcePathCheck {\n\tconst slashed = input.normalize(\"NFC\").replace(/\\\\/g, \"/\");\n\n\tif (hasControlOrFormatCharacter(slashed)) {\n\t\treturn { ok: false, reason: \"control-character\" };\n\t}\n\t// Before collapsing, so `//server/share` is still recognisably absolute.\n\tif (slashed.startsWith(\"/\") || DRIVE_LETTER_PREFIX.test(slashed)) {\n\t\treturn { ok: false, reason: \"absolute\" };\n\t}\n\n\tlet path = slashed.replace(/\\/{2,}/g, \"/\");\n\twhile (path.startsWith(\"./\")) {\n\t\tpath = path.slice(2);\n\t}\n\n\tif (path.length === 0) {\n\t\treturn { ok: false, reason: \"empty\" };\n\t}\n\tif (path.endsWith(\"/\")) {\n\t\treturn { ok: false, reason: \"trailing-slash\" };\n\t}\n\tif (\n\t\tpath.split(\"/\").some((segment) => segment === \".\" || segment === \"..\")\n\t) {\n\t\treturn { ok: false, reason: \"dot-segment\" };\n\t}\n\tif (path.length > MAX_CONTEXT_SOURCE_PATH_LENGTH) {\n\t\treturn { ok: false, reason: \"too-long\" };\n\t}\n\treturn { ok: true, sourcePath: path };\n}\n","/**\n * Which walked files are text this command may send, and the hash each one is\n * known by.\n *\n * A first cut that only sends text: an allow-list of extensions, bytes that\n * decode as UTF-8 without a single replacement, no NUL, something other than\n * whitespace, and at most the server's 2 MiB. Everything else is SKIPPED with\n * a reason the report shows, never sent to be refused — the server applies\n * the same rules (`upsertSyncedContext`) and would only say no.\n */\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\n\n/**\n * The server's ceiling on one synced file (`MAX_SYNCED_CONTEXT_BYTES` in\n * `packages/api/modules/projects/lib/upsert-synced-context.ts`).\n */\nexport const MAX_CONTEXT_FILE_BYTES = 2 * 1024 * 1024;\n\n/**\n * Compared lower-cased, so `README.MD` is text too. The server's canonical\n * copy is `packages/instructions/src/context-sync-rules.ts`, pinned to this\n * one by `context-sync-rules-agree-with-cli.test.ts` there.\n */\nexport const CONTEXT_TEXT_EXTENSIONS: ReadonlySet<string> = new Set([\n\t\".md\",\n\t\".markdown\",\n\t\".txt\",\n\t\".json\",\n\t\".yaml\",\n\t\".yml\",\n]);\n\n/**\n * Why a file under the folder was not sent.\n *\n * - `unsupported-type` not one of the text extensions, or not a regular file\n * - `binary` not valid UTF-8, or contains NUL\n * - `empty` no bytes, or only whitespace\n * - `too-large` over 2 MiB of UTF-8\n * - `invalid-path` a path the server would refuse (`detail` carries the\n * server's reason word) or one two files would share\n * - `symlink` never followed, never sent\n * - `ignored` the lock names it but the ignore rules now leave it\n * out; its server entry is kept\n * - `repository-managed` the server refused a create, a replace, a move or\n * a `--prune` delete because a Living Memory\n * repository sync owns this path (`detail` carries\n * the server's own sentence); final, and never\n * retried with `--force`. Set after the send, not by\n * the planner, but reported through the same\n * `skipped` group as the reasons decided before it.\n */\ntype ContextSkipReason =\n\t| \"unsupported-type\"\n\t| \"binary\"\n\t| \"empty\"\n\t| \"too-large\"\n\t| \"invalid-path\"\n\t| \"symlink\"\n\t| \"ignored\"\n\t| \"repository-managed\";\n\nexport interface SkippedContextFile {\n\tpath: string;\n\treason: ContextSkipReason;\n\tdetail?: string;\n}\n\nconst HAS_NON_WHITESPACE = /\\S/;\n\nexport function hasTextExtension(relativePath: string): boolean {\n\treturn CONTEXT_TEXT_EXTENSIONS.has(\n\t\tpath.posix.extname(relativePath).toLowerCase(),\n\t);\n}\n\n/**\n * The file's text, or why it is not text worth sending.\n *\n * `ignoreBOM: true` keeps a leading byte-order mark IN the string. The server\n * hashes the string it receives; had the decoder stripped the BOM, the hash\n * the server stores would differ from the hash of the bytes on disk, and an\n * untouched file would look changed to every later push.\n *\n * `fatal: true` is what makes \"decodes as UTF-8\" mean anything: the default\n * decoder replaces invalid bytes with U+FFFD silently, which would upload a\n * rewritten file.\n */\nexport function classifyContextBytes(\n\tbytes: Uint8Array,\n):\n\t| { ok: true; content: string }\n\t| { ok: false; reason: \"binary\" | \"empty\" | \"too-large\" } {\n\tif (bytes.byteLength > MAX_CONTEXT_FILE_BYTES) {\n\t\treturn { ok: false, reason: \"too-large\" };\n\t}\n\tlet content: string;\n\ttry {\n\t\tcontent = new TextDecoder(\"utf-8\", {\n\t\t\tfatal: true,\n\t\t\tignoreBOM: true,\n\t\t}).decode(bytes);\n\t} catch {\n\t\treturn { ok: false, reason: \"binary\" };\n\t}\n\t// Valid UTF-8 can still hold U+0000, which Postgres `text` cannot store\n\t// and the server refuses.\n\tif (content.includes(\"\\u0000\")) {\n\t\treturn { ok: false, reason: \"binary\" };\n\t}\n\t// The server's own emptiness test: nothing but whitespace (a lone BOM\n\t// counts as whitespace to `\\s`).\n\tif (!HAS_NON_WHITESPACE.test(content)) {\n\t\treturn { ok: false, reason: \"empty\" };\n\t}\n\treturn { ok: true, content };\n}\n\n/**\n * sha256 hex over the UTF-8 bytes of the content — the server's\n * `hashContextContent`, byte for byte, with nothing normalised first. It is\n * the compare-and-swap token a replace presents, and the lock records it.\n */\nexport function hashContextContent(content: string): string {\n\treturn createHash(\"sha256\").update(content, \"utf8\").digest(\"hex\");\n}\n","/**\n * Which paths under the pushed folder are never candidates at all.\n *\n * Two layers, matched with gitignore semantics by the `ignore` package:\n *\n * 1. DEFAULTS, always applied and never overridable. Version-control and\n * tool state (`.git/`, `.fabric/` — where the lock lives —\n * `node_modules/`), and every coding-instruction file or folder\n * (`CLAUDE.md`, `AGENTS.md`, `GEMINI.md`, `.claude/`, `.cursor/`,\n * `.codex/`, and directories named `skills`, `agents`, `hooks`, `rules`\n * or `scripts` at any depth). Instructions have their own reviewed path\n * into a project — `fabric instructions push` — and pushing them into\n * Context as well would make the same text answer from two places, one\n * of them unreviewed.\n * 2. The USER's: `<dir>/.contextignore` if present, then each `--exclude`.\n *\n * Kept as two matchers rather than one pattern list, because in one list a\n * user's `!CLAUDE.md` would re-include what the defaults exclude. A path the\n * defaults exclude is excluded whatever the user's rules say.\n *\n * Matching is case-insensitive (the package's default), so `claude.md` and\n * `Skills/` are excluded too.\n */\nimport ignore from \"ignore\";\n\ntype Ignore = ReturnType<typeof ignore>;\n\nexport const CONTEXT_IGNORE_FILENAME = \".contextignore\";\n\n/**\n * The server keeps the canonical copy (`packages/instructions/src/context-sync-rules.ts`);\n * `context-sync-rules-agree-with-cli.test.ts` there pins this one to it.\n */\nexport const DEFAULT_CONTEXT_IGNORE_PATTERNS: readonly string[] = [\n\t\".git/\",\n\t\".fabric/\",\n\t\".claude/\",\n\t\".cursor/\",\n\t\".codex/\",\n\t\"node_modules/\",\n\t\"CLAUDE.md\",\n\t\"AGENTS.md\",\n\t\"GEMINI.md\",\n\t\"skills/\",\n\t\"agents/\",\n\t\"hooks/\",\n\t\"rules/\",\n\t\"scripts/\",\n\tCONTEXT_IGNORE_FILENAME,\n];\n\nexport interface ContextIgnoreRules {\n\t/** Is this file (relative, `/`-separated) left out? */\n\tignoresFile(relativePath: string): boolean;\n\t/** Is this directory left out, and so not walked into? */\n\tignoresDirectory(relativePath: string): boolean;\n}\n\nexport function buildContextIgnoreRules(\n\tinput: { contextIgnore?: string | null; excludes?: readonly string[] } = {},\n): ContextIgnoreRules {\n\tconst defaults: Ignore = ignore().add([...DEFAULT_CONTEXT_IGNORE_PATTERNS]);\n\tconst user: Ignore = ignore();\n\tif (input.contextIgnore) {\n\t\tuser.add(input.contextIgnore);\n\t}\n\tif (input.excludes && input.excludes.length > 0) {\n\t\tuser.add([...input.excludes]);\n\t}\n\tconst ignores = (candidate: string) =>\n\t\tdefaults.ignores(candidate) || user.ignores(candidate);\n\treturn {\n\t\tignoresFile: (relativePath) => ignores(relativePath),\n\t\t// The trailing slash is what makes a directory-only pattern\n\t\t// (`drafts/`) match: gitignore semantics, as the package implements\n\t\t// them.\n\t\tignoresDirectory: (relativePath) => ignores(`${relativePath}/`),\n\t};\n}\n","/**\n * Every regular file under the pushed folder that the ignore rules leave in,\n * found without following a single symlink.\n *\n * `lstat` on every entry, never `stat`: a link is reported as a link and not\n * descended into or read, whatever it points at. A folder of notes that\n * happens to hold `secrets -> ~/.ssh` must not upload the key. Ignored paths\n * are dropped before anything else is asked of them, so a link inside\n * `node_modules/` is not reported, and an ignored directory is never walked.\n *\n * The file reads that follow go through `readFileSafely`, which walks the\n * path again segment by segment and refuses a symlinked component, so a\n * directory swapped for a link between this walk and the read is refused\n * there rather than followed.\n */\nimport type { Stats } from \"node:fs\";\nimport { lstat, readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { ContextIgnoreRules } from \"./ignore.js\";\n\ninterface WalkedFile {\n\t/** Relative to the folder, `/`-separated whatever the platform. */\n\tpath: string;\n\tsize: number;\n}\n\nexport interface ContextWalk {\n\tfiles: WalkedFile[];\n\t/** Links, reported and never followed. */\n\tsymlinks: string[];\n\t/** Fifos, sockets, devices: not files, never opened. */\n\tspecial: string[];\n\t/**\n\t * Paths the ignore matcher cannot evaluate (a segment made only of dots,\n\t * such as `...`, reads to it as a relative-path escape).\n\t */\n\tunmatchable: string[];\n\t/**\n\t * Entries the ignore rules dropped, as the listing spelled them: files,\n\t * links, and directories (which are not descended into, so what is\n\t * beneath one is ignored with it). With `files` and the lists above, this\n\t * is everything the walk saw, which is how a lock path is told apart as\n\t * \"still here but excluded\" or \"gone\" without asking the filesystem about\n\t * a spelling it may match case-insensitively.\n\t */\n\tignored: IgnoredEntry[];\n}\n\ninterface IgnoredEntry {\n\tpath: string;\n\tdirectory: boolean;\n}\n\nfunction byPath(a: string, b: string): number {\n\treturn a < b ? -1 : a > b ? 1 : 0;\n}\n\nexport async function walkContextDirectory(\n\troot: string,\n\trules: ContextIgnoreRules,\n): Promise<ContextWalk> {\n\tconst walk: ContextWalk = {\n\t\tfiles: [],\n\t\tsymlinks: [],\n\t\tspecial: [],\n\t\tunmatchable: [],\n\t\tignored: [],\n\t};\n\tconst pending: string[] = [\"\"];\n\twhile (pending.length > 0) {\n\t\tconst relativeDirectory = pending.pop() as string;\n\t\tconst names = await readdir(path.join(root, relativeDirectory));\n\t\tfor (const name of names) {\n\t\t\tconst relative = relativeDirectory\n\t\t\t\t? `${relativeDirectory}/${name}`\n\t\t\t\t: name;\n\t\t\tlet stats: Stats;\n\t\t\ttry {\n\t\t\t\tstats = await lstat(path.join(root, relative));\n\t\t\t} catch (error) {\n\t\t\t\t// Deleted between the listing and the look: nothing to send.\n\t\t\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tlet ignored: boolean;\n\t\t\ttry {\n\t\t\t\t// A link is matched as both a file and a directory: it is\n\t\t\t\t// never followed either way, and `node_modules -> ../x` in a\n\t\t\t\t// workspace package is the ignored directory, not a link\n\t\t\t\t// worth reporting.\n\t\t\t\tignored = stats.isDirectory()\n\t\t\t\t\t? rules.ignoresDirectory(relative)\n\t\t\t\t\t: stats.isSymbolicLink()\n\t\t\t\t\t\t? rules.ignoresFile(relative) ||\n\t\t\t\t\t\t\trules.ignoresDirectory(relative)\n\t\t\t\t\t\t: rules.ignoresFile(relative);\n\t\t\t} catch {\n\t\t\t\twalk.unmatchable.push(relative);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (ignored) {\n\t\t\t\twalk.ignored.push({\n\t\t\t\t\tpath: relative,\n\t\t\t\t\t// A link was matched as a directory too, so what would sit\n\t\t\t\t\t// beneath it counts as ignored with it.\n\t\t\t\t\tdirectory: stats.isDirectory() || stats.isSymbolicLink(),\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (stats.isSymbolicLink()) {\n\t\t\t\twalk.symlinks.push(relative);\n\t\t\t} else if (stats.isDirectory()) {\n\t\t\t\tpending.push(relative);\n\t\t\t} else if (stats.isFile()) {\n\t\t\t\twalk.files.push({ path: relative, size: stats.size });\n\t\t\t} else {\n\t\t\t\twalk.special.push(relative);\n\t\t\t}\n\t\t}\n\t}\n\twalk.files.sort((a, b) => byPath(a.path, b.path));\n\twalk.symlinks.sort(byPath);\n\twalk.special.sort(byPath);\n\twalk.unmatchable.sort(byPath);\n\twalk.ignored.sort((a, b) => byPath(a.path, b.path));\n\treturn walk;\n}\n","/**\n * What `fabric context push <dir>` would send, decided against the folder on\n * disk and the lock together, before a single request is made.\n *\n * Per candidate file, one of:\n *\n * push its hash is not the one the lock holds for its path —\n * sent with the lock's hash as `expectedContentHash`, or\n * with none when the lock does not name the path\n * unchanged-local its hash is the lock's: no request at all\n * skipped not something this command sends (see\n * `ContextSkipReason`), with the reason\n *\n * and per path the lock names that is no longer on disk: `removed`. Without\n * `--prune` that is reported and nothing more — the server entry and the\n * lock entry are kept; with it, the push deletes the server entry, only in\n * the version the lock names (Fizzy #2636). The exception is a lock entry\n * recorded as a `duplicate`: the server never stored that path, so there is\n * nothing to keep or delete, and it is `forgotten` (dropped from the lock\n * without a report line).\n *\n * A removed path and a new file with the same content are a `move` (Fizzy\n * #2636), sent as one rename so the server keeps the row, its id and its\n * history instead of deleting one source and creating another. Pairing is\n * one to one and deterministic: removed paths in sorted order, each taking\n * the first unpaired new file (sorted) with its hash. \"Removed\" is a\n * confirmed lock entry gone from disk; \"new\" is a file the lock does not name\n * at all. A file the lock names is a change to its own row, whatever it now\n * holds.\n *\n * \"No longer on disk\" is decided from the names the walk listed, never by\n * asking the filesystem about the lock's spelling: a case-insensitive\n * filesystem answers \"yes\" for `Docs/Guide.md` after a rename to\n * `docs/guide.md`, and the old path would read as excluded instead of gone.\n *\n * The plan keeps each file's hash and size, not its content: the push reads\n * the file again right before sending it and sends it only if it still\n * hashes to what was planned.\n */\nimport { readFileSafely } from \"../instructions/safe-write.js\";\nimport {\n\tclassifyContextBytes,\n\thashContextContent,\n\thasTextExtension,\n\tMAX_CONTEXT_FILE_BYTES,\n\ttype SkippedContextFile,\n} from \"./classify.js\";\nimport { buildContextIgnoreRules, CONTEXT_IGNORE_FILENAME } from \"./ignore.js\";\nimport type { ContextLock } from \"./lock.js\";\nimport { normalizeContextSourcePath } from \"./source-path.js\";\nimport { walkContextDirectory } from \"./walk.js\";\n\nexport interface ContextPushCandidate {\n\t/** The normalized path the server keys the file on. */\n\tsourcePath: string;\n\t/** The file's path on disk, relative to the folder. */\n\tdiskPath: string;\n\t/** Of the content as planned; the push sends only content that still has it. */\n\tsha256: string;\n\t/** UTF-8 bytes. */\n\tbytes: number;\n\t/**\n\t * The lock's hash for this path; absent when the lock does not name it,\n\t * or names it only as a `duplicate` (a path with no row to replace).\n\t */\n\texpectedContentHash?: string;\n}\n\n/** A confirmed lock path gone from disk, and the new file that holds its content. */\nexport interface ContextMoveCandidate {\n\t/** The lock's path, no longer on disk. */\n\tfrom: string;\n\t/** The new file's normalized path, which the server keys it on. */\n\tto: string;\n\t/** The new file's path on disk, relative to the folder. */\n\tdiskPath: string;\n\t/** Of both: the lock's hash for `from`, and the new file's as planned. */\n\tsha256: string;\n\t/** UTF-8 bytes of the new file. */\n\tbytes: number;\n\t/** The row the lock recorded for `from`. */\n\tcontextId: string;\n}\n\nexport interface ContextPlan {\n\t/** In sorted `sourcePath` order, which is the order they are sent in. */\n\tpush: ContextPushCandidate[];\n\t/** In sorted `from` order; sent before `push`. */\n\tmoves: ContextMoveCandidate[];\n\tunchangedLocal: string[];\n\tremoved: string[];\n\t/** `duplicate` lock entries whose file is gone: dropped from the lock. */\n\tforgotten: string[];\n\tskipped: SkippedContextFile[];\n}\n\nfunction byPath(a: string, b: string): number {\n\treturn a < b ? -1 : a > b ? 1 : 0;\n}\n\n/** The folder's own `.contextignore`, through the guarded reader, or `null`. */\nasync function readContextIgnore(root: string): Promise<string | null> {\n\tconst read = await readFileSafely(root, CONTEXT_IGNORE_FILENAME, {\n\t\tmaxBytes: 1024 * 1024,\n\t});\n\treturn read === null ? null : new TextDecoder().decode(read.bytes);\n}\n\n/**\n * Whether a lock path is one the walk saw and the ignore rules dropped —\n * itself, or beneath a dropped directory — compared in the server's spelling\n * (NFC) and with the case the listing gave it.\n */\nfunction ignoredByWalk(\n\tignored: readonly { path: string; directory: boolean }[],\n): (sourcePath: string) => boolean {\n\tconst exact = new Set(ignored.map((entry) => entry.path.normalize(\"NFC\")));\n\tconst directories = ignored\n\t\t.filter((entry) => entry.directory)\n\t\t.map((entry) => `${entry.path.normalize(\"NFC\")}/`);\n\treturn (sourcePath) =>\n\t\texact.has(sourcePath) ||\n\t\tdirectories.some((prefix) => sourcePath.startsWith(prefix));\n}\n\n/**\n * Why a readable file shares its stored path with another, or `null`. Two\n * files the server would store as ONE path (a composed and a decomposed\n * spelling of a name) would silently drop one of them; two that differ only\n * in case are two rows on the server but one file on a case-insensitive\n * filesystem, where the lock and every later push would confuse them.\n * Neither file of such a pair is sent.\n */\nfunction sharedPathProblem(\n\tentry: { diskPath: string; sourcePath: string },\n\tgroup: readonly { diskPath: string; sourcePath: string }[],\n): string | null {\n\tconst others = group.filter((other) => other.diskPath !== entry.diskPath);\n\tif (others.length === 0) {\n\t\treturn null;\n\t}\n\tconst names = others.map((other) => other.diskPath).join(\", \");\n\treturn others.every((other) => other.sourcePath === entry.sourcePath)\n\t\t? `names the same source as ${names}`\n\t\t: `case-only collision with ${names}`;\n}\n\nexport async function computeContextPlan(input: {\n\t/** Already canonical (`resolveExistingRoot`). */\n\troot: string;\n\tlock: ContextLock | null;\n\texcludes?: readonly string[];\n}): Promise<ContextPlan> {\n\tconst { root, lock } = input;\n\tconst rules = buildContextIgnoreRules({\n\t\tcontextIgnore: await readContextIgnore(root),\n\t\texcludes: input.excludes,\n\t});\n\tconst walk = await walkContextDirectory(root, rules);\n\n\tconst skipped: SkippedContextFile[] = [\n\t\t...walk.symlinks.map((p) => ({ path: p, reason: \"symlink\" as const })),\n\t\t...walk.special.map((p) => ({\n\t\t\tpath: p,\n\t\t\treason: \"unsupported-type\" as const,\n\t\t})),\n\t\t...walk.unmatchable.map((p) => ({\n\t\t\tpath: p,\n\t\t\treason: \"invalid-path\" as const,\n\t\t\tdetail: \"cannot be matched against the ignore rules\",\n\t\t})),\n\t];\n\n\t// Path checks first: they cost nothing and need no read.\n\tconst readable: { diskPath: string; sourcePath: string }[] = [];\n\tfor (const file of walk.files) {\n\t\t// A backslash inside a POSIX file name is not a separator on disk, and\n\t\t// the server would read it as one: the file would be stored under a\n\t\t// path that names something else.\n\t\tif (file.path.includes(\"\\\\\")) {\n\t\t\tskipped.push({\n\t\t\t\tpath: file.path,\n\t\t\t\treason: \"invalid-path\",\n\t\t\t\tdetail: \"backslash\",\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst normalized = normalizeContextSourcePath(file.path);\n\t\tif (!normalized.ok) {\n\t\t\tskipped.push({\n\t\t\t\tpath: file.path,\n\t\t\t\treason: \"invalid-path\",\n\t\t\t\tdetail: normalized.reason,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (!hasTextExtension(file.path)) {\n\t\t\tskipped.push({ path: file.path, reason: \"unsupported-type\" });\n\t\t\tcontinue;\n\t\t}\n\t\tif (file.size > MAX_CONTEXT_FILE_BYTES) {\n\t\t\tskipped.push({ path: file.path, reason: \"too-large\" });\n\t\t\tcontinue;\n\t\t}\n\t\treadable.push({\n\t\t\tdiskPath: file.path,\n\t\t\tsourcePath: normalized.sourcePath,\n\t\t});\n\t}\n\n\t// Grouped by the case-folded stored path, which catches both kinds of\n\t// sharing `sharedPathProblem` describes.\n\tconst byFoldedPath = new Map<string, typeof readable>();\n\tfor (const entry of readable) {\n\t\tconst key = entry.sourcePath.toLowerCase();\n\t\tbyFoldedPath.set(key, [...(byFoldedPath.get(key) ?? []), entry]);\n\t}\n\n\tconst push: ContextPushCandidate[] = [];\n\tconst unchangedLocal: string[] = [];\n\t/** Stored paths the walk found on disk this run, pushed or not. */\n\tconst present = new Set<string>();\n\tfor (const entry of readable) {\n\t\tconst problem = sharedPathProblem(\n\t\t\tentry,\n\t\t\tbyFoldedPath.get(entry.sourcePath.toLowerCase()) ?? [],\n\t\t);\n\t\tif (problem !== null) {\n\t\t\tskipped.push({\n\t\t\t\tpath: entry.diskPath,\n\t\t\t\treason: \"invalid-path\",\n\t\t\t\tdetail: problem,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst read = await readFileSafely(root, entry.diskPath, {\n\t\t\tmaxBytes: MAX_CONTEXT_FILE_BYTES,\n\t\t}).catch((error: unknown) => {\n\t\t\t// Grew past the limit between the walk and the read.\n\t\t\tif (error instanceof Error && /too large/.test(error.message)) {\n\t\t\t\treturn \"too-large\" as const;\n\t\t\t}\n\t\t\tthrow error;\n\t\t});\n\t\tif (read === null) {\n\t\t\t// Deleted since the walk: nothing to send.\n\t\t\tcontinue;\n\t\t}\n\t\tif (read === \"too-large\") {\n\t\t\tskipped.push({ path: entry.diskPath, reason: \"too-large\" });\n\t\t\tcontinue;\n\t\t}\n\t\tconst verdict = classifyContextBytes(read.bytes);\n\t\tif (!verdict.ok) {\n\t\t\tskipped.push({ path: entry.diskPath, reason: verdict.reason });\n\t\t\tcontinue;\n\t\t}\n\t\t// Only the hash and the size are kept; `verdict.content` goes out of\n\t\t// scope here, so planning holds one file's text at a time.\n\t\tconst sha256 = hashContextContent(verdict.content);\n\t\tconst locked = lock?.files[entry.sourcePath];\n\t\tconst plannedFile = {\n\t\t\tsourcePath: entry.sourcePath,\n\t\t\tdiskPath: entry.diskPath,\n\t\t\tsha256,\n\t\t\tbytes: read.bytes.byteLength,\n\t\t};\n\t\tif (locked?.sha256 === sha256) {\n\t\t\tunchangedLocal.push(entry.sourcePath);\n\t\t} else {\n\t\t\tpush.push(\n\t\t\t\t// A duplicate never had a row of its own, so there is no\n\t\t\t\t// version to name: it is sent like a new path.\n\t\t\t\tlocked && locked.state !== \"duplicate\"\n\t\t\t\t\t? { ...plannedFile, expectedContentHash: locked.sha256 }\n\t\t\t\t\t: plannedFile,\n\t\t\t);\n\t\t}\n\t\tpresent.add(entry.sourcePath);\n\t}\n\n\t// Lock paths with no candidate and no skip line. Gone from disk is\n\t// `removed` (or, for a duplicate the server never stored, `forgotten`);\n\t// still there but now excluded by the ignore rules is a skip, so nobody\n\t// reads \"removed\" about a file they can see.\n\tfor (const skip of skipped) {\n\t\tconst check = normalizeContextSourcePath(skip.path);\n\t\tif (check.ok) {\n\t\t\tpresent.add(check.sourcePath);\n\t\t}\n\t}\n\tconst isIgnored = ignoredByWalk(walk.ignored);\n\tconst removed: string[] = [];\n\tconst forgotten: string[] = [];\n\tfor (const [sourcePath, entry] of Object.entries(lock?.files ?? {})) {\n\t\tif (present.has(sourcePath)) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (entry.state === \"duplicate\") {\n\t\t\t// No server entry to keep or to report on, gone or excluded.\n\t\t\tforgotten.push(sourcePath);\n\t\t} else if (isIgnored(sourcePath)) {\n\t\t\tskipped.push({ path: sourcePath, reason: \"ignored\" });\n\t\t} else {\n\t\t\tremoved.push(sourcePath);\n\t\t}\n\t}\n\n\tpush.sort((a, b) => byPath(a.sourcePath, b.sourcePath));\n\tremoved.sort(byPath);\n\tconst moves = pairMoves(lock, removed, push);\n\tconst moved = new Set(moves.map((move) => move.from));\n\tconst arrived = new Set(moves.map((move) => move.to));\n\n\tunchangedLocal.sort(byPath);\n\tforgotten.sort(byPath);\n\tskipped.sort((a, b) => byPath(a.path, b.path));\n\treturn {\n\t\tpush: push.filter((entry) => !arrived.has(entry.sourcePath)),\n\t\tmoves,\n\t\tunchangedLocal,\n\t\tremoved: removed.filter((sourcePath) => !moved.has(sourcePath)),\n\t\tforgotten,\n\t\tskipped,\n\t};\n}\n\n/**\n * The moves among `removed` (confirmed lock paths gone from disk, sorted) and\n * the new files among `push` (sorted, the lock naming none of them): each\n * removed path in order takes the first unpaired new file with its hash.\n */\nfunction pairMoves(\n\tlock: ContextLock | null,\n\tremoved: readonly string[],\n\tpush: readonly ContextPushCandidate[],\n): ContextMoveCandidate[] {\n\tconst added = push.filter(\n\t\t(entry) => lock?.files[entry.sourcePath] === undefined,\n\t);\n\tconst taken = new Set<string>();\n\tconst moves: ContextMoveCandidate[] = [];\n\tfor (const from of removed) {\n\t\tconst entry = lock?.files[from];\n\t\tif (!entry || entry.state === \"duplicate\") {\n\t\t\tcontinue;\n\t\t}\n\t\tconst match = added.find(\n\t\t\t(candidate) =>\n\t\t\t\t!taken.has(candidate.sourcePath) &&\n\t\t\t\tcandidate.sha256 === entry.sha256,\n\t\t);\n\t\tif (!match) {\n\t\t\tcontinue;\n\t\t}\n\t\ttaken.add(match.sourcePath);\n\t\tmoves.push({\n\t\t\tfrom,\n\t\t\tto: match.sourcePath,\n\t\t\tdiskPath: match.diskPath,\n\t\t\tsha256: match.sha256,\n\t\t\tbytes: match.bytes,\n\t\t\tcontextId: entry.contextId,\n\t\t});\n\t}\n\treturn moves;\n}\n","/**\n * Sending a context plan, one file per request, and what the lock learns\n * from the answers.\n *\n * Sequential and in sorted path order: the report reads in the order things\n * happened, and a folder of notes gains nothing from racing its own requests\n * against the server's per-key rate limit.\n *\n * Outcomes per file:\n *\n * created | updated | unchanged the server holds this content now —\n * recorded in the lock\n * duplicate the path is new and identical content is\n * already stored under another path —\n * nothing stored; recorded as a duplicate\n * (hash, no row), so it is not re-sent\n * until it changes\n * conflict the path holds a version this folder did\n * not name, or the version it named was\n * deleted on the server — nothing written,\n * the lock entry left exactly as it was\n * changed-during-run the file no longer hashes to what was\n * planned — not sent, lock entry untouched;\n * the next run picks the new content up\n * failed this request failed; the others still go\n *\n * Each file is read again, through the guarded reader, immediately before\n * its request: the plan keeps hashes, not contents, so a folder is never held\n * in memory at once, and what is sent is exactly what was planned.\n *\n * `--force` answers a conflict by sending the same content again, once,\n * naming the version the conflict reported — or, when the named version was\n * deleted on the server, naming none, which recreates the file unless that\n * content already exists elsewhere in the project (then the answer is\n * `duplicate`). If that is a conflict too — somebody changed it again in\n * between — it is reported as one. There is no third attempt: `--force`\n * means \"replace the version you just told me about\", never \"win whatever\n * happens\". The file is read again before the resend too, so a file saved\n * while the first request was out is `changed-during-run`, not resent.\n *\n * A refusal that would repeat for every file — the key is invalid, lacks\n * `projects:write`, its owner lost the permission, the project is not\n * there, the rate limit, a server that cannot be reached — stops the run\n * rather than failing every remaining file with the same sentence.\n *\n * ## Moves and `--prune` (Fizzy #2636)\n *\n * Moves go first, each one request: the new path, naming the old one as\n * `movedFromSourcePath` and the lock's hash for it as the version. `moved`\n * moves the lock entry. Any other answer records the new path as a push\n * would, and says why the server did not rename: only `source-missing` (the\n * old path has no row) drops the old entry — otherwise the old row is still\n * there, and the old path is a plain removal. A conflict about the old path\n * leaves both entries and sends nothing else for the pair; `--force` resends\n * the move once naming the old path's current version (a move never\n * replaces content, so that stores this folder's version at the new path and\n * keeps the old row), or, when the old row is gone, pushes the new path as a\n * new file.\n *\n * Then the pushes, and LAST, only with `--prune`, the deletions: every\n * removed path, and every old path a move left in place, deleted by\n * `deleteSyncedFile` naming the lock's hash. `deleted` and `absent` drop the\n * entry; a conflict (the file changed on the server since) keeps it, and\n * `--force` resends once naming the version the conflict reported.\n * `in-progress` (the server's deletion has not finished answering) keeps the\n * entry too, since the file may or may not be gone yet: the next `--prune`\n * names the same version and confirms. It is never forced. A run stopped\n * early deletes nothing it had not reached.\n *\n * ## Repository-managed files (Living Memory design 2026-09-23 §6)\n *\n * A Living Memory repository sync is the author of record for the files it\n * produced: the server refuses a create, a replace, a move (either side) or\n * a `--prune` delete that would touch one, with a 409 whose `code` is\n * `REPOSITORY_MANAGED` — recognised by that code, never by matching the\n * message text, which the server is free to reword. Nothing was written, so\n * this is reported as `skipped`, not a failure: `--force` never retries it\n * (a hash conflict has a version to replace; this refusal has none — the\n * repository owns the file, and the fix is to change it there and run \"Sync\n * now\"), and the lock entry for that path — its old, pre-sync version, or\n * none — is left exactly as it was, never recorded and never dropped.\n */\nimport type {\n\tFabricClient,\n\tSyncedContextFileConflict,\n\tSyncedContextFileCurrentVersion,\n\tSyncedContextFileMoveNotAppliedReason,\n\tSyncedContextFileResult,\n} from \"@fabricorg/sdk\";\nimport {\n\tasCliFailure,\n\ttype CliFailure,\n\tdescribeError,\n} from \"../command-boundary.js\";\nimport { readFileSafely } from \"../instructions/safe-write.js\";\nimport {\n\tclassifyContextBytes,\n\thashContextContent,\n\tMAX_CONTEXT_FILE_BYTES,\n} from \"./classify.js\";\nimport type { ContextLock } from \"./lock.js\";\nimport { CONTEXT_LOCK_VERSION } from \"./lock.js\";\nimport type {\n\tContextMoveCandidate,\n\tContextPlan,\n\tContextPushCandidate,\n} from \"./plan.js\";\n\n/** On every result of a planned move, but `moved` itself (Fizzy #2636). */\ninterface MoveFields {\n\t/** The lock path the file moved from, when this result is a move's. */\n\tmovedFrom?: string;\n\t/**\n\t * Why the server did not rename it, when it answered without renaming.\n\t * Only `source-missing` means the old path has no row any more.\n\t */\n\tmoveNotApplied?: SyncedContextFileMoveNotAppliedReason;\n}\n\nexport type ContextPushResult =\n\t| ({\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"created\" | \"updated\" | \"unchanged\";\n\t\t\tcontextId: string;\n\t\t\tcontentHash: string;\n\t\t\t/**\n\t\t\t * Present when `--force` replaced a version somebody else had\n\t\t\t * changed: the version it replaced.\n\t\t\t */\n\t\t\toverwrote?: SyncedContextFileCurrentVersion;\n\t } & MoveFields)\n\t| {\n\t\t\t/** The new path; the row that was at `movedFrom` is here now. */\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"moved\";\n\t\t\tmovedFrom: string;\n\t\t\tcontextId: string;\n\t\t\tcontentHash: string;\n\t }\n\t| ({\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"duplicate\";\n\t\t\tcontentHash: string;\n\t\t\tduplicateOfContextId: string;\n\t\t\tduplicateOfSourcePath: string | null;\n\t } & MoveFields)\n\t| ({\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"conflict\";\n\t\t\tcontentHash: string;\n\t\t\t/**\n\t\t\t * Whether this path was in the lock when it was sent — for a move\n\t\t\t * whose old path changed, whether the conflict is about that old\n\t\t\t * path (which the lock names).\n\t\t\t */\n\t\t\twasLocked: boolean;\n\t\t\t/** True when this is the answer to the one `--force` resend. */\n\t\t\tafterForce: boolean;\n\t\t\t/** `null`: the version this folder named was deleted on the server. */\n\t\t\tcurrent: SyncedContextFileCurrentVersion | null;\n\t } & MoveFields)\n\t| {\n\t\t\t/**\n\t\t\t * The new path of a move the server could not apply because it\n\t\t\t * does not support moves: a server from before Fizzy #2636\n\t\t\t * ignores `movedFromSourcePath` and answers the new path as an\n\t\t\t * ordinary push naming a version it never had. Nothing was\n\t\t\t * stored, nothing more is sent (even with `--force`), and the old\n\t\t\t * path's lock entry stays, so the move is tried again next run.\n\t\t\t */\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"move-unsupported\";\n\t\t\tmovedFrom: string;\n\t }\n\t| ({\n\t\t\tsourcePath: string;\n\t\t\t/**\n\t\t\t * The file no longer hashes to what the plan recorded (edited,\n\t\t\t * deleted, or no longer text since). Not sent this run.\n\t\t\t */\n\t\t\tstatus: \"changed-during-run\";\n\t } & MoveFields)\n\t| ({\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"failed\";\n\t\t\terror: string;\n\t\t\t/** The documented exit code this failure maps to. */\n\t\t\texitCode: number;\n\t } & MoveFields)\n\t// A Living Memory repository sync owns this path: nothing was written or\n\t// deleted, and this is final — `--force` never retries it. Reported as\n\t// `skipped`, for a create, a replace, either side of a move, or a\n\t// `--prune` delete alike.\n\t| ({\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"repository-managed\";\n\t\t\t/**\n\t\t\t * The server's own sentence: \"<path> is synced from <owner/name>\n\t\t\t * @ <ref>; change it in the repository and run Sync now.\" (or\n\t\t\t * \"the connected repository\" in place of the repository and ref\n\t\t\t * when the sync configuration was removed between the reads).\n\t\t\t */\n\t\t\tmessage: string;\n\t } & MoveFields)\n\t// --prune: a removed path's server entry.\n\t| {\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"deleted\";\n\t\t\tcontextId: string;\n\t\t\t/** The hash of the version deleted. */\n\t\t\tcontentHash: string;\n\t\t\t/** Present when `--force` deleted a version somebody else changed. */\n\t\t\toverwrote?: SyncedContextFileCurrentVersion;\n\t }\n\t| {\n\t\t\t/** The server had no row at this path: dropped from the lock. */\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"already-gone\";\n\t }\n\t| {\n\t\t\t/**\n\t\t\t * The server's deletion is still running: the file may or may not\n\t\t\t * be gone yet. The lock entry is kept, so the next `--prune`\n\t\t\t * confirms it. Counted as not deleted.\n\t\t\t */\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"delete-in-progress\";\n\t }\n\t| {\n\t\t\t/** Changed on the server since the last push: not deleted. */\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"delete-conflict\";\n\t\t\tafterForce: boolean;\n\t\t\tcurrent: SyncedContextFileCurrentVersion;\n\t }\n\t| {\n\t\t\tsourcePath: string;\n\t\t\tstatus: \"delete-failed\";\n\t\t\terror: string;\n\t\t\texitCode: number;\n\t };\n\n/** The statuses a `--prune` deletion ends in. */\nexport const DELETE_STATUSES: ReadonlySet<ContextPushResult[\"status\"]> =\n\tnew Set([\n\t\t\"deleted\",\n\t\t\"already-gone\",\n\t\t\"delete-in-progress\",\n\t\t\"delete-conflict\",\n\t\t\"delete-failed\",\n\t]);\n\nexport interface ContextPushRun {\n\tresults: ContextPushResult[];\n\t/** A refusal that stopped the run before every file was sent. */\n\tstoppedBy: CliFailure | null;\n\t/**\n\t * With `--prune`, every path it set out to delete, in order: the removed\n\t * paths and the old paths moves left in place, each with a lock entry\n\t * naming a stored version. Set even when a refusal stopped the run before\n\t * the deletions began, so a summary can count what was never tried as\n\t * not deleted.\n\t */\n\tpruneTargets: string[];\n}\n\n/** HTTP statuses that are about the key or the project, not the file. */\nconst RUN_LEVEL_STATUSES = new Set([401, 403, 404, 429]);\n\n/**\n * Failures with no HTTP answer at all, after the client's own retries: the\n * server is unreachable or not answering, and the next file would say so too.\n */\nconst RUN_LEVEL_CODES = new Set([\"NETWORK_ERROR\", \"TIMEOUT\"]);\n\nfunction stopsTheRun(error: unknown): boolean {\n\tconst { status, code } = error as { status?: unknown; code?: unknown };\n\treturn (\n\t\t(typeof status === \"number\" && RUN_LEVEL_STATUSES.has(status)) ||\n\t\t(typeof code === \"string\" && RUN_LEVEL_CODES.has(code))\n\t);\n}\n\n/**\n * The conflict payload, from the SDK's typed error. Read by shape rather than\n * by `instanceof`, so a second copy of the SDK in a dependency tree cannot\n * turn a conflict into a generic failure.\n */\nfunction conflictOf(error: unknown): SyncedContextFileConflict | null {\n\tif (typeof error !== \"object\" || error === null) {\n\t\treturn null;\n\t}\n\tconst conflict = (error as { conflict?: unknown }).conflict;\n\tif (\n\t\ttypeof conflict === \"object\" &&\n\t\tconflict !== null &&\n\t\t(conflict as { status?: unknown }).status === \"conflict\" &&\n\t\t\"current\" in conflict &&\n\t\t// An object, or `null` for a named version deleted on the server.\n\t\ttypeof (conflict as { current?: unknown }).current === \"object\"\n\t) {\n\t\treturn conflict as SyncedContextFileConflict;\n\t}\n\treturn null;\n}\n\n/**\n * The repository-managed refusal (Living Memory design 2026-09-23 §6), from\n * the SDK's typed error, read by shape as `conflictOf` is — never by\n * matching the message text, which the server is free to reword. The\n * server's `code` is `REPOSITORY_MANAGED` and its `message` is already the\n * exact sentence this prints, so nothing here reconstructs it.\n */\nfunction repositoryManagedOf(error: unknown): string | null {\n\tif (typeof error !== \"object\" || error === null) {\n\t\treturn null;\n\t}\n\tconst { code, message } = error as { code?: unknown; message?: unknown };\n\treturn code === \"REPOSITORY_MANAGED\" && typeof message === \"string\"\n\t\t? message\n\t\t: null;\n}\n\n/**\n * The file's text as it is now, or `null` when it is no longer what the plan\n * hashed — the same guarded read, classification and hash the plan used, so\n * a file edited, deleted or turned binary since is never sent under the\n * plan's hash.\n */\nasync function readPlannedContent(\n\troot: string,\n\tentry: ContextPushCandidate,\n): Promise<string | null> {\n\tconst read = await readFileSafely(root, entry.diskPath, {\n\t\tmaxBytes: MAX_CONTEXT_FILE_BYTES,\n\t}).catch((error: unknown) => {\n\t\tif (error instanceof Error && /too large/.test(error.message)) {\n\t\t\treturn null;\n\t\t}\n\t\tthrow error;\n\t});\n\tif (read === null) {\n\t\treturn null;\n\t}\n\tconst verdict = classifyContextBytes(read.bytes);\n\tif (!verdict.ok || hashContextContent(verdict.content) !== entry.sha256) {\n\t\treturn null;\n\t}\n\treturn verdict.content;\n}\n\ntype ServerAnswer = Extract<\n\tContextPushResult,\n\t{ status: \"created\" | \"updated\" | \"unchanged\" | \"duplicate\" | \"moved\" }\n>;\n\n/**\n * A push's answer as a result. For a move's, `movedFrom` is the lock's old\n * path and `moveNotApplied` the server's reason when it did not rename.\n */\nfunction fromResult(\n\tsourcePath: string,\n\tresult: SyncedContextFileResult,\n\tmovedFrom?: string,\n): ServerAnswer {\n\tif (result.status === \"moved\") {\n\t\treturn {\n\t\t\tsourcePath,\n\t\t\tstatus: \"moved\",\n\t\t\tmovedFrom: movedFrom ?? result.movedFromSourcePath,\n\t\t\tcontextId: result.contextId,\n\t\t\tcontentHash: result.contentHash,\n\t\t};\n\t}\n\tconst move: MoveFields =\n\t\tmovedFrom === undefined\n\t\t\t? {}\n\t\t\t: {\n\t\t\t\t\tmovedFrom,\n\t\t\t\t\t...(result.moveNotApplied\n\t\t\t\t\t\t? { moveNotApplied: result.moveNotApplied.reason }\n\t\t\t\t\t\t: {}),\n\t\t\t\t};\n\tif (result.status === \"duplicate\") {\n\t\treturn {\n\t\t\tsourcePath,\n\t\t\tstatus: \"duplicate\",\n\t\t\tcontentHash: result.contentHash,\n\t\t\tduplicateOfContextId: result.duplicateOfContextId,\n\t\t\tduplicateOfSourcePath: result.duplicateOfSourcePath,\n\t\t\t...move,\n\t\t};\n\t}\n\treturn {\n\t\tsourcePath,\n\t\tstatus: result.status,\n\t\tcontextId: result.contextId,\n\t\tcontentHash: result.contentHash,\n\t\t...move,\n\t};\n}\n\n/**\n * Whether a move's result leaves its old path as a plain removal: the server\n * answered without renaming, and did not say the old row is gone.\n */\nfunction moveKeptOldPath(result: ContextPushResult): string | null {\n\tif (\n\t\t(result.status === \"created\" ||\n\t\t\tresult.status === \"updated\" ||\n\t\t\tresult.status === \"unchanged\" ||\n\t\t\tresult.status === \"duplicate\") &&\n\t\tresult.movedFrom !== undefined &&\n\t\tresult.moveNotApplied !== \"source-missing\"\n\t) {\n\t\treturn result.movedFrom;\n\t}\n\treturn null;\n}\n\nexport async function pushContextPlan(input: {\n\tclient: FabricClient;\n\tprojectId: string;\n\torg?: string;\n\t/** The folder the plan was made from (`resolveExistingRoot`). */\n\troot: string;\n\tplan: ContextPlan;\n\tforce: boolean;\n\t/** Delete removed paths' server entries (Fizzy #2636). */\n\tprune?: boolean;\n\t/** The lock the plan was made against: the versions `--prune` names. */\n\tlock?: ContextLock | null;\n}): Promise<ContextPushRun> {\n\tconst results: ContextPushResult[] = [];\n\tconst pruneTargets: string[] = [];\n\tconst { force } = input;\n\n\tconst send = (\n\t\tsourcePath: string,\n\t\tcontent: string,\n\t\texpectedContentHash?: string,\n\t\tmovedFromSourcePath?: string,\n\t) =>\n\t\tinput.client.contexts.upsertSyncedFile(\n\t\t\tinput.projectId,\n\t\t\t{\n\t\t\t\tsourcePath,\n\t\t\t\tcontent,\n\t\t\t\t...(expectedContentHash !== undefined\n\t\t\t\t\t? { expectedContentHash }\n\t\t\t\t\t: {}),\n\t\t\t\t...(movedFromSourcePath !== undefined\n\t\t\t\t\t? { movedFromSourcePath }\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t\t{ org: input.org },\n\t\t);\n\n\t/** One file's push, with the one `--force` resend a conflict allows. */\n\tconst pushEntry = async (\n\t\tentry: ContextPushCandidate,\n\t): Promise<ContextPushResult> => {\n\t\tconst content = await readPlannedContent(input.root, entry);\n\t\tif (content === null) {\n\t\t\treturn {\n\t\t\t\tsourcePath: entry.sourcePath,\n\t\t\t\tstatus: \"changed-during-run\",\n\t\t\t};\n\t\t}\n\t\ttry {\n\t\t\treturn fromResult(\n\t\t\t\tentry.sourcePath,\n\t\t\t\tawait send(\n\t\t\t\t\tentry.sourcePath,\n\t\t\t\t\tcontent,\n\t\t\t\t\tentry.expectedContentHash,\n\t\t\t\t),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst managed = repositoryManagedOf(error);\n\t\t\tif (managed !== null) {\n\t\t\t\t// Final: no version to name, so --force has nothing to retry.\n\t\t\t\treturn {\n\t\t\t\t\tsourcePath: entry.sourcePath,\n\t\t\t\t\tstatus: \"repository-managed\",\n\t\t\t\t\tmessage: managed,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst conflict = conflictOf(error);\n\t\t\tif (conflict === null) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tconst { current } = conflict;\n\t\t\t// No hash on the stored row means no version a push can name,\n\t\t\t// so `--force` has nothing to replace it with. A deleted one\n\t\t\t// (`current: null`) is resent naming no version at all, which\n\t\t\t// recreates it or answers `duplicate`.\n\t\t\tif (!force || (current !== null && current.contentHash === null)) {\n\t\t\t\treturn {\n\t\t\t\t\tsourcePath: entry.sourcePath,\n\t\t\t\t\tstatus: \"conflict\",\n\t\t\t\t\tcontentHash: conflict.contentHash,\n\t\t\t\t\twasLocked: entry.expectedContentHash !== undefined,\n\t\t\t\t\tafterForce: false,\n\t\t\t\t\tcurrent,\n\t\t\t\t};\n\t\t\t}\n\t\t\t// Read the file again: it may have been saved while the first\n\t\t\t// request was out, and a resend that names the server's version\n\t\t\t// must not replace it with content the folder no longer holds.\n\t\t\tconst forcedContent = await readPlannedContent(input.root, entry);\n\t\t\tif (forcedContent === null) {\n\t\t\t\treturn {\n\t\t\t\t\tsourcePath: entry.sourcePath,\n\t\t\t\t\tstatus: \"changed-during-run\",\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst forced = fromResult(\n\t\t\t\t\tentry.sourcePath,\n\t\t\t\t\tawait send(\n\t\t\t\t\t\tentry.sourcePath,\n\t\t\t\t\t\tforcedContent,\n\t\t\t\t\t\tcurrent === null\n\t\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t\t: (current.contentHash ?? undefined),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\t// Only a replace overwrote anything. `unchanged` means the\n\t\t\t\t// server already held this very content by then, and a\n\t\t\t\t// recreate replaced nothing.\n\t\t\t\treturn forced.status === \"updated\" && current !== null\n\t\t\t\t\t? { ...forced, overwrote: current }\n\t\t\t\t\t: forced;\n\t\t\t} catch (retryError) {\n\t\t\t\tconst managedOnRetry = repositoryManagedOf(retryError);\n\t\t\t\tif (managedOnRetry !== null) {\n\t\t\t\t\t// Adopted by a sync between the conflict and the resend:\n\t\t\t\t\t// still final, still nothing to retry a third time.\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsourcePath: entry.sourcePath,\n\t\t\t\t\t\tstatus: \"repository-managed\",\n\t\t\t\t\t\tmessage: managedOnRetry,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst again = conflictOf(retryError);\n\t\t\t\tif (again === null) {\n\t\t\t\t\tthrow retryError;\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tsourcePath: entry.sourcePath,\n\t\t\t\t\tstatus: \"conflict\",\n\t\t\t\t\tcontentHash: again.contentHash,\n\t\t\t\t\twasLocked: entry.expectedContentHash !== undefined,\n\t\t\t\t\tafterForce: true,\n\t\t\t\t\tcurrent: again.current,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t};\n\n\t/** One move: the new path, naming the old one and the lock's version. */\n\tconst pushMove = async (\n\t\tmove: ContextMoveCandidate,\n\t): Promise<ContextPushResult> => {\n\t\tconst entry: ContextPushCandidate = {\n\t\t\tsourcePath: move.to,\n\t\t\tdiskPath: move.diskPath,\n\t\t\tsha256: move.sha256,\n\t\t\tbytes: move.bytes,\n\t\t};\n\t\tconst moveFields = { movedFrom: move.from };\n\t\tconst content = await readPlannedContent(input.root, entry);\n\t\tif (content === null) {\n\t\t\treturn {\n\t\t\t\tsourcePath: move.to,\n\t\t\t\tstatus: \"changed-during-run\",\n\t\t\t\t...moveFields,\n\t\t\t};\n\t\t}\n\t\tconst asConflict = (\n\t\t\tconflict: SyncedContextFileConflict,\n\t\t\tafterForce: boolean,\n\t\t): ContextPushResult => ({\n\t\t\tsourcePath: move.to,\n\t\t\tstatus: \"conflict\",\n\t\t\tcontentHash: conflict.contentHash,\n\t\t\t// About the old path (which the lock names) or the new one.\n\t\t\twasLocked: conflict.moveNotApplied?.reason === \"source-changed\",\n\t\t\tafterForce,\n\t\t\tcurrent: conflict.current,\n\t\t\t...moveFields,\n\t\t\t...(conflict.moveNotApplied\n\t\t\t\t? { moveNotApplied: conflict.moveNotApplied.reason }\n\t\t\t\t: {}),\n\t\t});\n\t\ttry {\n\t\t\treturn fromResult(\n\t\t\t\tmove.to,\n\t\t\t\tawait send(move.to, content, move.sha256, move.from),\n\t\t\t\tmove.from,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst managed = repositoryManagedOf(error);\n\t\t\tif (managed !== null) {\n\t\t\t\t// The target path is a repository sync's (or its ownership\n\t\t\t\t// predicate refused the write for another reason the server\n\t\t\t\t// reports this way): nothing was stored or renamed, the old\n\t\t\t\t// path is untouched, and --force has nothing to retry.\n\t\t\t\treturn {\n\t\t\t\t\tsourcePath: move.to,\n\t\t\t\t\tstatus: \"repository-managed\",\n\t\t\t\t\tmessage: managed,\n\t\t\t\t\t...moveFields,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst conflict = conflictOf(error);\n\t\t\tif (conflict === null) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tconst { current } = conflict;\n\t\t\t// A server that supports moves says why on every answer to a move\n\t\t\t// that is not a rename, and never answers one with `current:\n\t\t\t// null` without a reason. That shape is a server from before\n\t\t\t// moves: it ignored the old path and answered the new one as a\n\t\t\t// push naming a version it never had. Nothing is stored, and\n\t\t\t// `--force` must not turn the move into a new copy.\n\t\t\tif (current === null && conflict.moveNotApplied === undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tsourcePath: move.to,\n\t\t\t\t\tstatus: \"move-unsupported\",\n\t\t\t\t\tmovedFrom: move.from,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (!force || (current !== null && current.contentHash === null)) {\n\t\t\t\treturn asConflict(conflict, false);\n\t\t\t}\n\t\t\tconst forcedContent = await readPlannedContent(input.root, entry);\n\t\t\tif (forcedContent === null) {\n\t\t\t\treturn {\n\t\t\t\t\tsourcePath: move.to,\n\t\t\t\t\tstatus: \"changed-during-run\",\n\t\t\t\t\t...moveFields,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst aboutOldPath =\n\t\t\t\tconflict.moveNotApplied?.reason === \"source-changed\";\n\t\t\ttry {\n\t\t\t\tif (aboutOldPath && current === null) {\n\t\t\t\t\t// The old row is gone: the new path is a new file, and\n\t\t\t\t\t// the old entry has nothing left to name.\n\t\t\t\t\tconst created = fromResult(\n\t\t\t\t\t\tmove.to,\n\t\t\t\t\t\tawait send(move.to, forcedContent),\n\t\t\t\t\t);\n\t\t\t\t\treturn created.status === \"moved\"\n\t\t\t\t\t\t? created\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t...created,\n\t\t\t\t\t\t\t\t...moveFields,\n\t\t\t\t\t\t\t\tmoveNotApplied: \"source-missing\",\n\t\t\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (aboutOldPath) {\n\t\t\t\t\t// Resend the move naming the old path's current version.\n\t\t\t\t\treturn fromResult(\n\t\t\t\t\t\tmove.to,\n\t\t\t\t\t\tawait send(\n\t\t\t\t\t\t\tmove.to,\n\t\t\t\t\t\t\tforcedContent,\n\t\t\t\t\t\t\tcurrent?.contentHash ?? undefined,\n\t\t\t\t\t\t\tmove.from,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tmove.from,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// The new path's own row holds other content: replace that\n\t\t\t\t// version, as `--force` does for any push; the old row stays.\n\t\t\t\tconst forced = fromResult(\n\t\t\t\t\tmove.to,\n\t\t\t\t\tawait send(\n\t\t\t\t\t\tmove.to,\n\t\t\t\t\t\tforcedContent,\n\t\t\t\t\t\tcurrent?.contentHash ?? undefined,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tif (forced.status === \"moved\") {\n\t\t\t\t\treturn forced;\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\t...(forced.status === \"updated\" && current !== null\n\t\t\t\t\t\t? { ...forced, overwrote: current }\n\t\t\t\t\t\t: forced),\n\t\t\t\t\t...moveFields,\n\t\t\t\t\t...(conflict.moveNotApplied\n\t\t\t\t\t\t? { moveNotApplied: conflict.moveNotApplied.reason }\n\t\t\t\t\t\t: {}),\n\t\t\t\t};\n\t\t\t} catch (retryError) {\n\t\t\t\tconst managedOnRetry = repositoryManagedOf(retryError);\n\t\t\t\tif (managedOnRetry !== null) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsourcePath: move.to,\n\t\t\t\t\t\tstatus: \"repository-managed\",\n\t\t\t\t\t\tmessage: managedOnRetry,\n\t\t\t\t\t\t...moveFields,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst again = conflictOf(retryError);\n\t\t\t\tif (again === null) {\n\t\t\t\t\tthrow retryError;\n\t\t\t\t}\n\t\t\t\tif (again.moveNotApplied !== undefined) {\n\t\t\t\t\treturn asConflict(again, true);\n\t\t\t\t}\n\t\t\t\t// A resend of the move answers for itself. The other two\n\t\t\t\t// resends are not moves, so the server says nothing about the\n\t\t\t\t// old path; what the first answer established still holds.\n\t\t\t\tconst reason:\n\t\t\t\t\t| SyncedContextFileMoveNotAppliedReason\n\t\t\t\t\t| undefined = aboutOldPath\n\t\t\t\t\t? current === null\n\t\t\t\t\t\t? \"source-missing\"\n\t\t\t\t\t\t: undefined\n\t\t\t\t\t: conflict.moveNotApplied?.reason;\n\t\t\t\treturn asConflict(\n\t\t\t\t\treason === undefined\n\t\t\t\t\t\t? again\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t...again,\n\t\t\t\t\t\t\t\tmoveNotApplied: {\n\t\t\t\t\t\t\t\t\tmovedFromSourcePath: move.from,\n\t\t\t\t\t\t\t\t\treason,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t};\n\n\t/** One removed path's server entry, only in the lock's version. */\n\tconst deleteEntry = async (\n\t\tsourcePath: string,\n\t\tsha256: string,\n\t): Promise<ContextPushResult> => {\n\t\tconst remove = (expectedContentHash: string) =>\n\t\t\tinput.client.contexts.deleteSyncedFile(\n\t\t\t\tinput.projectId,\n\t\t\t\t{ sourcePath, expectedContentHash },\n\t\t\t\t{ org: input.org },\n\t\t\t);\n\t\tconst fromAnswer = (\n\t\t\tanswer: Awaited<ReturnType<typeof remove>>,\n\t\t\toverwrote?: SyncedContextFileCurrentVersion,\n\t\t): ContextPushResult => {\n\t\t\tswitch (answer.status) {\n\t\t\t\tcase \"deleted\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsourcePath,\n\t\t\t\t\t\tstatus: \"deleted\",\n\t\t\t\t\t\tcontextId: answer.contextId,\n\t\t\t\t\t\tcontentHash: answer.contentHash,\n\t\t\t\t\t\t...(overwrote ? { overwrote } : {}),\n\t\t\t\t\t};\n\t\t\t\tcase \"absent\":\n\t\t\t\t\treturn { sourcePath, status: \"already-gone\" };\n\t\t\t\tcase \"in-progress\":\n\t\t\t\t\t// Not a conflict, so never resent: the next run confirms.\n\t\t\t\t\treturn { sourcePath, status: \"delete-in-progress\" };\n\t\t\t}\n\t\t};\n\t\ttry {\n\t\t\treturn fromAnswer(await remove(sha256));\n\t\t} catch (error) {\n\t\t\tconst managed = repositoryManagedOf(error);\n\t\t\tif (managed !== null) {\n\t\t\t\t// A repository sync owns this row now: it was not deleted,\n\t\t\t\t// the lock entry stays (the next --prune would only refuse\n\t\t\t\t// again), and --force has nothing to retry.\n\t\t\t\treturn {\n\t\t\t\t\tsourcePath,\n\t\t\t\t\tstatus: \"repository-managed\",\n\t\t\t\t\tmessage: managed,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst conflict = conflictOf(error);\n\t\t\tif (conflict === null || conflict.current === null) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tconst { current } = conflict;\n\t\t\tif (!force || current.contentHash === null) {\n\t\t\t\treturn {\n\t\t\t\t\tsourcePath,\n\t\t\t\t\tstatus: \"delete-conflict\",\n\t\t\t\t\tafterForce: false,\n\t\t\t\t\tcurrent,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn fromAnswer(await remove(current.contentHash), current);\n\t\t\t} catch (retryError) {\n\t\t\t\tconst managedOnRetry = repositoryManagedOf(retryError);\n\t\t\t\tif (managedOnRetry !== null) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsourcePath,\n\t\t\t\t\t\tstatus: \"repository-managed\",\n\t\t\t\t\t\tmessage: managedOnRetry,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst again = conflictOf(retryError);\n\t\t\t\tif (again === null || again.current === null) {\n\t\t\t\t\tthrow retryError;\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tsourcePath,\n\t\t\t\t\tstatus: \"delete-conflict\",\n\t\t\t\t\tafterForce: true,\n\t\t\t\t\tcurrent: again.current,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Run one step. A failure that would repeat for every file stops the run\n\t * (returned); any other is this step's own result.\n\t */\n\tconst step = async (\n\t\trun: () => Promise<ContextPushResult>,\n\t\tfailed: (error: unknown, exitCode: number) => ContextPushResult,\n\t): Promise<CliFailure | null> => {\n\t\ttry {\n\t\t\tresults.push(await run());\n\t\t\treturn null;\n\t\t} catch (error) {\n\t\t\tconst failure = asCliFailure(error);\n\t\t\tif (stopsTheRun(error)) {\n\t\t\t\treturn failure;\n\t\t\t}\n\t\t\tresults.push(failed(error, failure.exitCode));\n\t\t\treturn null;\n\t\t}\n\t};\n\n\t/**\n\t * What `--prune` sets out to delete, given the results so far: the removed\n\t * paths and the old paths moves left in place, each with a lock entry\n\t * naming a stored version (a duplicate's path was never stored).\n\t */\n\tconst pruneTargetsSoFar = (): string[] => {\n\t\tconst keptByMoves = results\n\t\t\t.map(moveKeptOldPath)\n\t\t\t.filter((path): path is string => path !== null);\n\t\treturn [...new Set([...input.plan.removed, ...keptByMoves])]\n\t\t\t.filter((path) => {\n\t\t\t\tconst locked = input.lock?.files[path];\n\t\t\t\treturn locked !== undefined && locked.state !== \"duplicate\";\n\t\t\t})\n\t\t\t.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n\t};\n\n\tconst stopped = (stoppedBy: CliFailure): ContextPushRun => {\n\t\t// Stopped before the deletions began: they were all still to do.\n\t\tif (input.prune && pruneTargets.length === 0) {\n\t\t\tpruneTargets.push(...pruneTargetsSoFar());\n\t\t}\n\t\treturn { results, stoppedBy, pruneTargets };\n\t};\n\n\tfor (const move of input.plan.moves) {\n\t\tconst stoppedBy = await step(\n\t\t\t() => pushMove(move),\n\t\t\t(error, exitCode) => ({\n\t\t\t\tsourcePath: move.to,\n\t\t\t\tstatus: \"failed\",\n\t\t\t\terror: describeError(error),\n\t\t\t\texitCode,\n\t\t\t\tmovedFrom: move.from,\n\t\t\t}),\n\t\t);\n\t\tif (stoppedBy) {\n\t\t\treturn stopped(stoppedBy);\n\t\t}\n\t}\n\n\tfor (const entry of input.plan.push) {\n\t\tconst stoppedBy = await step(\n\t\t\t() => pushEntry(entry),\n\t\t\t(error, exitCode) => ({\n\t\t\t\tsourcePath: entry.sourcePath,\n\t\t\t\tstatus: \"failed\",\n\t\t\t\terror: describeError(error),\n\t\t\t\texitCode,\n\t\t\t}),\n\t\t);\n\t\tif (stoppedBy) {\n\t\t\treturn stopped(stoppedBy);\n\t\t}\n\t}\n\n\tif (input.prune) {\n\t\tpruneTargets.push(...pruneTargetsSoFar());\n\t\tfor (const sourcePath of pruneTargets) {\n\t\t\tconst locked = input.lock?.files[sourcePath];\n\t\t\tif (!locked || locked.state === \"duplicate\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst stoppedBy = await step(\n\t\t\t\t() => deleteEntry(sourcePath, locked.sha256),\n\t\t\t\t(error, exitCode) => ({\n\t\t\t\t\tsourcePath,\n\t\t\t\t\tstatus: \"delete-failed\",\n\t\t\t\t\terror: describeError(error),\n\t\t\t\t\texitCode,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tif (stoppedBy) {\n\t\t\t\treturn stopped(stoppedBy);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { results, stoppedBy: null, pruneTargets };\n}\n\n/**\n * The lock after these results, or `null` when it would say nothing new.\n *\n * Starts from the previous ledger, so paths that were not sent this time —\n * unchanged locally, removed locally (without `--prune`), skipped,\n * conflicting, changed during the run, failed — keep exactly the entry they\n * had. What the server confirmed moves; a duplicate is recorded as one; a\n * `forgotten` duplicate (its file gone, and the server never stored its path)\n * is dropped. A `moved` result moves its entry to the new path; a move the\n * server answered otherwise records the new path and drops the old one only\n * when the server said it has no row there — including when the new path's\n * answer was a conflict, which records nothing for the new path but still\n * says the old one is gone, so the same move is not planned again. A\n * `--prune` deletion that happened, or found nothing to delete, drops its\n * entry; one still running on the server keeps it.\n */\nexport function nextContextLock(input: {\n\tprevious: ContextLock | null;\n\tprojectId: string;\n\tresults: readonly ContextPushResult[];\n\tforgotten?: readonly string[];\n\tnow: Date;\n}): ContextLock | null {\n\tconst files = { ...(input.previous?.files ?? {}) };\n\tlet changed = false;\n\tconst drop = (sourcePath: string) => {\n\t\tif (sourcePath in files) {\n\t\t\tdelete files[sourcePath];\n\t\t\tchanged = true;\n\t\t}\n\t};\n\tconst confirm = (sourcePath: string, sha256: string, contextId: string) => {\n\t\tconst before = files[sourcePath];\n\t\tif (\n\t\t\tbefore?.state === undefined &&\n\t\t\tbefore?.sha256 === sha256 &&\n\t\t\tbefore.contextId === contextId\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tfiles[sourcePath] = { sha256, contextId };\n\t\tchanged = true;\n\t};\n\n\tfor (const sourcePath of input.forgotten ?? []) {\n\t\tdrop(sourcePath);\n\t}\n\tfor (const result of input.results) {\n\t\tswitch (result.status) {\n\t\t\tcase \"deleted\":\n\t\t\tcase \"already-gone\":\n\t\t\t\tdrop(result.sourcePath);\n\t\t\t\tbreak;\n\t\t\tcase \"delete-in-progress\":\n\t\t\t\t// Maybe gone, maybe not: keep the entry, so the next --prune\n\t\t\t\t// names the same version and hears `deleted` or `absent`.\n\t\t\t\tbreak;\n\t\t\tcase \"moved\":\n\t\t\t\tdrop(result.movedFrom);\n\t\t\t\tconfirm(\n\t\t\t\t\tresult.sourcePath,\n\t\t\t\t\tresult.contentHash,\n\t\t\t\t\tresult.contextId,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"duplicate\": {\n\t\t\t\tconst before = files[result.sourcePath];\n\t\t\t\tif (\n\t\t\t\t\tbefore?.state !== \"duplicate\" ||\n\t\t\t\t\tbefore.sha256 !== result.contentHash\n\t\t\t\t) {\n\t\t\t\t\tfiles[result.sourcePath] = {\n\t\t\t\t\t\tsha256: result.contentHash,\n\t\t\t\t\t\tstate: \"duplicate\",\n\t\t\t\t\t};\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\tresult.moveNotApplied === \"source-missing\" &&\n\t\t\t\t\tresult.movedFrom\n\t\t\t\t) {\n\t\t\t\t\tdrop(result.movedFrom);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"created\":\n\t\t\tcase \"updated\":\n\t\t\tcase \"unchanged\":\n\t\t\t\tconfirm(\n\t\t\t\t\tresult.sourcePath,\n\t\t\t\t\tresult.contentHash,\n\t\t\t\t\tresult.contextId,\n\t\t\t\t);\n\t\t\t\tif (\n\t\t\t\t\tresult.moveNotApplied === \"source-missing\" &&\n\t\t\t\t\tresult.movedFrom\n\t\t\t\t) {\n\t\t\t\t\tdrop(result.movedFrom);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"conflict\":\n\t\t\t\t// Nothing was stored at the new path, so it stays unrecorded;\n\t\t\t\t// the old path's entry goes when the server has no row there.\n\t\t\t\tif (\n\t\t\t\t\tresult.moveNotApplied === \"source-missing\" &&\n\t\t\t\t\tresult.movedFrom\n\t\t\t\t) {\n\t\t\t\t\tdrop(result.movedFrom);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tif (!changed) {\n\t\treturn null;\n\t}\n\treturn {\n\t\tversion: CONTEXT_LOCK_VERSION,\n\t\tprojectId: input.projectId,\n\t\tpushedAt: input.now.toISOString(),\n\t\tfiles,\n\t};\n}\n","/**\n * The words and the JSON a `fabric context push` prints.\n *\n * Grouped by outcome with a count on each group, one line per file for every\n * outcome except `unchanged`, which is only counted: a folder of two hundred\n * notes where one changed should read as one line and a count.\n *\n * A move reads `old -> new`. A move the server answered without renaming is\n * listed under `not moved`, saying what happened to each path (including a\n * server that does not support moves yet), and a `--prune` run adds `deleted`,\n * `already gone` and `deletion still running` (the server had not finished\n * when it answered; run again to confirm); its conflicts and failures join\n * the push's under `conflict` and `failed`, each line saying \"not deleted\",\n * and a path it set out to delete but never reached is listed under\n * `removed` with its server entry kept (Fizzy #2636).\n */\nimport type { SkippedContextFile } from \"./classify.js\";\nimport type { ContextPlan } from \"./plan.js\";\nimport { type ContextPushResult, DELETE_STATUSES } from \"./push.js\";\n\ntype ResultOf<S extends ContextPushResult[\"status\"]> = Extract<\n\tContextPushResult,\n\t{ status: S }\n>;\n\nexport interface ContextPushCounts {\n\tcreated: number;\n\tupdated: number;\n\tunchanged: number;\n\tduplicate: number;\n\tmoved: number;\n\t/** Moves a server without move support could not apply. */\n\tmoveUnsupported: number;\n\tconflict: number;\n\tchangedDuringRun: number;\n\tfailed: number;\n\tremoved: number;\n\tskipped: number;\n\t/** `--prune` only; zero otherwise. */\n\tdeleted: number;\n\talreadyGone: number;\n\t/** Still running on the server when it answered: not deleted yet. */\n\tdeleteInProgress: number;\n\tdeleteConflict: number;\n\tdeleteFailed: number;\n}\n\n/**\n * A `repository-managed` result, recast as a `SkippedContextFile` (Living\n * Memory design 2026-09-23 §6): it is decided after the send, not by the\n * planner, but it is reported through the same `skipped` group and count as\n * the reasons the planner decides before sending. The server's own sentence\n * is the line, carried as `detail` — see `skippedLine`.\n */\nfunction managedSkips(\n\tresults: readonly ContextPushResult[],\n): SkippedContextFile[] {\n\treturn results\n\t\t.filter(\n\t\t\t(\n\t\t\t\tr,\n\t\t\t): r is Extract<\n\t\t\t\tContextPushResult,\n\t\t\t\t{ status: \"repository-managed\" }\n\t\t\t> => r.status === \"repository-managed\",\n\t\t)\n\t\t.map((r) => ({\n\t\t\tpath: r.sourcePath,\n\t\t\treason: \"repository-managed\" as const,\n\t\t\tdetail: r.message,\n\t\t}));\n}\n\nfunction countOutcomes(\n\tplan: ContextPlan,\n\tresults: readonly ContextPushResult[],\n): ContextPushCounts {\n\tconst count = (status: ContextPushResult[\"status\"]) =>\n\t\tresults.filter((r) => r.status === status).length;\n\treturn {\n\t\tcreated: count(\"created\"),\n\t\tupdated: count(\"updated\"),\n\t\tunchanged: count(\"unchanged\") + plan.unchangedLocal.length,\n\t\tduplicate: count(\"duplicate\"),\n\t\tmoved: count(\"moved\"),\n\t\tmoveUnsupported: count(\"move-unsupported\"),\n\t\tconflict: count(\"conflict\"),\n\t\tchangedDuringRun: count(\"changed-during-run\"),\n\t\tfailed: count(\"failed\"),\n\t\tremoved: plan.removed.length,\n\t\tskipped: plan.skipped.length + managedSkips(results).length,\n\t\tdeleted: count(\"deleted\"),\n\t\talreadyGone: count(\"already-gone\"),\n\t\tdeleteInProgress: count(\"delete-in-progress\"),\n\t\tdeleteConflict: count(\"delete-conflict\"),\n\t\tdeleteFailed: count(\"delete-failed\"),\n\t};\n}\n\nfunction who(current: { contentUpdatedBy: { name: string | null } | null }) {\n\treturn current.contentUpdatedBy?.name ?? \"someone\";\n}\n\nfunction when(current: { contentUpdatedAt: string | null }) {\n\treturn current.contentUpdatedAt ?? \"an unknown time\";\n}\n\n/** A conflict about a move's old path: that file changed on the server. */\nfunction moveSourceConflictLine(\n\tresult: ResultOf<\"conflict\">,\n\tfrom: string,\n): string {\n\tconst { current } = result;\n\tif (current === null) {\n\t\treturn `${from}: deleted on the server since your last push; not moved to ${result.sourcePath}`;\n\t}\n\tlet text = result.afterForce\n\t\t? `changed on the server again by ${who(current)} at ${when(current)} while --force was moving it`\n\t\t: `changed on the server by ${who(current)} at ${when(current)} since your last push`;\n\tif (current.contentHash === null) {\n\t\ttext += \"; that version has no content hash, so --force cannot move it\";\n\t}\n\treturn `${from}: ${text}; not moved to ${result.sourcePath}`;\n}\n\nfunction conflictLine(result: ResultOf<\"conflict\">): string {\n\tif (result.movedFrom !== undefined) {\n\t\tif (result.moveNotApplied === \"source-changed\") {\n\t\t\treturn moveSourceConflictLine(result, result.movedFrom);\n\t\t}\n\t\t// The old row is gone: its lock entry is dropped, so the next run\n\t\t// sends the new path as an ordinary file rather than this move again.\n\t\tif (result.moveNotApplied === \"source-missing\") {\n\t\t\treturn `${pushConflictLine(result)}; ${result.movedFrom} gone on the server`;\n\t\t}\n\t\treturn `${pushConflictLine(result)}; ${result.movedFrom} not moved`;\n\t}\n\treturn pushConflictLine(result);\n}\n\nfunction pushConflictLine(result: ResultOf<\"conflict\">): string {\n\tconst { current } = result;\n\tif (current === null) {\n\t\treturn `${result.sourcePath}: deleted on the server since your last push`;\n\t}\n\tlet text: string;\n\tif (result.afterForce) {\n\t\ttext = `changed on the server again by ${who(current)} at ${when(current)} while --force was replacing it`;\n\t} else if (result.wasLocked) {\n\t\ttext = `changed on the server by ${who(current)} at ${when(current)} since your last push`;\n\t} else {\n\t\ttext = `already on the server with different content, last changed by ${who(current)} at ${when(current)}`;\n\t}\n\tif (current.contentHash === null) {\n\t\ttext +=\n\t\t\t\"; that version has no content hash, so --force cannot replace it\";\n\t}\n\treturn `${result.sourcePath}: ${text}`;\n}\n\nfunction deleteConflictLine(result: ResultOf<\"delete-conflict\">): string {\n\tconst { current } = result;\n\tlet text = result.afterForce\n\t\t? `changed on the server again by ${who(current)} at ${when(current)} while --force was deleting it`\n\t\t: `changed on the server by ${who(current)} at ${when(current)} since your last push`;\n\tif (current.contentHash === null) {\n\t\ttext +=\n\t\t\t\"; that version has no content hash, so --force cannot delete it\";\n\t}\n\treturn `${result.sourcePath}: ${text}; not deleted`;\n}\n\nfunction storedLine(result: ResultOf<\"created\" | \"updated\" | \"unchanged\">) {\n\tif (result.overwrote) {\n\t\treturn `${result.sourcePath}: replaced the version ${who(result.overwrote)} changed at ${when(result.overwrote)} (--force)`;\n\t}\n\treturn result.sourcePath;\n}\n\ntype MoveFallback = ResultOf<\"created\" | \"updated\" | \"unchanged\" | \"duplicate\">;\n\n/** A move's result that stored the new path without renaming the old one. */\nfunction isMoveFallback(result: ContextPushResult): result is MoveFallback {\n\treturn (\n\t\t(result.status === \"created\" ||\n\t\t\tresult.status === \"updated\" ||\n\t\t\tresult.status === \"unchanged\" ||\n\t\t\tresult.status === \"duplicate\") &&\n\t\tresult.movedFrom !== undefined\n\t);\n}\n\n/**\n * What a move the server did not apply did to each path. The old path is\n * `kept` — its row and its lock entry — unless the server had none, or\n * `--prune` is about to decide it below.\n */\nfunction moveFallbackLine(result: MoveFallback, prune: boolean): string {\n\tconst from = result.movedFrom ?? \"\";\n\tconst to = result.sourcePath;\n\tlet pushed: string;\n\tif (result.status === \"duplicate\") {\n\t\tpushed = `${to} pushed as a duplicate of ${result.duplicateOfSourcePath ?? \"another source in this project\"}`;\n\t} else if (result.overwrote) {\n\t\tpushed = `${to} replaced the version ${who(result.overwrote)} changed at ${when(result.overwrote)} (--force)`;\n\t} else {\n\t\tpushed = `${to} pushed as ${result.status}`;\n\t}\n\tconst kept = prune ? \"\" : `; ${from} kept`;\n\tswitch (result.moveNotApplied) {\n\t\tcase \"source-missing\":\n\t\t\treturn `${from}: gone on the server; ${pushed}`;\n\t\tcase \"target-exists\":\n\t\t\treturn `${from}: not moved, ${to} is already on the server; ${pushed}${kept}`;\n\t\tcase \"content-differs\":\n\t\t\treturn `${from}: not moved, the server's version of it differs from ${to}; ${pushed}${kept}`;\n\t\tdefault:\n\t\t\treturn `${from}: not moved; ${pushed}${kept}`;\n\t}\n}\n\nfunction skippedLine(skip: SkippedContextFile): string {\n\tif (skip.reason === \"ignored\") {\n\t\treturn `${skip.path}: now excluded by the ignore rules; server entry kept`;\n\t}\n\tif (skip.reason === \"repository-managed\") {\n\t\t// `detail` already carries the server's whole sentence, which names\n\t\t// the path itself — nothing to prefix.\n\t\treturn skip.detail ?? `${skip.path}: repository-managed`;\n\t}\n\treturn skip.detail\n\t\t? `${skip.path}: ${skip.reason} (${skip.detail})`\n\t\t: `${skip.path}: ${skip.reason}`;\n}\n\nfunction group(lines: string[], label: string, items: readonly string[]) {\n\tif (items.length === 0) {\n\t\treturn;\n\t}\n\tlines.push(`${label} (${items.length})`);\n\tfor (const item of items) {\n\t\tlines.push(` ${item}`);\n\t}\n}\n\n/** The text report for a push that was sent. */\nexport function formatPushReport(input: {\n\tprojectId: string;\n\tdirectory: string;\n\tplan: ContextPlan;\n\tresults: readonly ContextPushResult[];\n\t/** `--prune` was given: removed paths are reported by what it did. */\n\tprune?: boolean;\n\t/**\n\t * With `--prune`, every path it set out to delete (`ContextPushRun`), so\n\t * one a stopped run never reached, including the kept old path of a move\n\t * the server declined, is still listed.\n\t */\n\tpruneTargets?: readonly string[];\n}): string[] {\n\tconst { plan, results } = input;\n\tconst prune = Boolean(input.prune);\n\t// A move the server did not apply is listed once, under `not moved`.\n\tconst of = <S extends ContextPushResult[\"status\"]>(status: S) =>\n\t\tresults.filter(\n\t\t\t(r): r is ResultOf<S> => r.status === status && !isMoveFallback(r),\n\t\t);\n\n\tconst lines = [\n\t\t`Context push from ${input.directory} to project ${input.projectId}:`,\n\t];\n\tgroup(lines, \"created\", of(\"created\").map(storedLine));\n\tgroup(lines, \"updated\", of(\"updated\").map(storedLine));\n\tgroup(\n\t\tlines,\n\t\t\"moved\",\n\t\tof(\"moved\").map((r) => `${r.movedFrom} -> ${r.sourcePath}`),\n\t);\n\tgroup(lines, \"not moved\", [\n\t\t...results\n\t\t\t.filter(isMoveFallback)\n\t\t\t.map((r) => moveFallbackLine(r, prune)),\n\t\t...of(\"move-unsupported\").map(\n\t\t\t(r) =>\n\t\t\t\t`${r.movedFrom} -> ${r.sourcePath}: the server does not support moves yet; ${r.movedFrom} kept, ${r.sourcePath} not pushed`,\n\t\t),\n\t]);\n\tgroup(\n\t\tlines,\n\t\t\"duplicate\",\n\t\tof(\"duplicate\").map(\n\t\t\t(r) =>\n\t\t\t\t`${r.sourcePath}: duplicate of ${r.duplicateOfSourcePath ?? \"another source in this project\"}`,\n\t\t),\n\t);\n\tgroup(lines, \"conflict\", [\n\t\t...of(\"conflict\").map(conflictLine),\n\t\t...of(\"delete-conflict\").map(deleteConflictLine),\n\t]);\n\tgroup(\n\t\tlines,\n\t\t\"changed during the run\",\n\t\tof(\"changed-during-run\").map(\n\t\t\t(r) =>\n\t\t\t\t`${r.sourcePath}: changed-during-run; not sent, the next push sends the new content`,\n\t\t),\n\t);\n\tgroup(lines, \"failed\", [\n\t\t...of(\"failed\").map((r) => `${r.sourcePath}: ${r.error}`),\n\t\t...of(\"delete-failed\").map(\n\t\t\t(r) => `${r.sourcePath}: ${r.error}; not deleted`,\n\t\t),\n\t]);\n\tgroup(\n\t\tlines,\n\t\t\"deleted\",\n\t\tof(\"deleted\").map((r) =>\n\t\t\tr.overwrote\n\t\t\t\t? `${r.sourcePath}: deleted the version ${who(r.overwrote)} changed at ${when(r.overwrote)} (--force)`\n\t\t\t\t: r.sourcePath,\n\t\t),\n\t);\n\tgroup(\n\t\tlines,\n\t\t\"already gone\",\n\t\tof(\"already-gone\").map(\n\t\t\t(r) => `${r.sourcePath}: already gone on the server`,\n\t\t),\n\t);\n\tgroup(\n\t\tlines,\n\t\t\"deletion still running\",\n\t\tof(\"delete-in-progress\").map(\n\t\t\t(r) =>\n\t\t\t\t`${r.sourcePath}: deletion still running on the server; run again to confirm`,\n\t\t),\n\t);\n\t// Removed paths `--prune` did not reach (a run stopped early) keep their\n\t// server entries, as every removed path does without it; so does the old\n\t// path of a declined move it set out to delete and never reached. A\n\t// `--prune` target a repository sync refused is settled too — it is\n\t// reported under `skipped`, not here, so it must not also read as kept.\n\tconst pruned = new Set(\n\t\tresults\n\t\t\t.filter(\n\t\t\t\t(r) =>\n\t\t\t\t\tDELETE_STATUSES.has(r.status) ||\n\t\t\t\t\tr.status === \"repository-managed\",\n\t\t\t)\n\t\t\t.map((r) => r.sourcePath),\n\t);\n\tconst kept = [\n\t\t...plan.removed,\n\t\t...(input.pruneTargets ?? []).filter((p) => !plan.removed.includes(p)),\n\t];\n\tgroup(\n\t\tlines,\n\t\t\"removed\",\n\t\tkept\n\t\t\t.filter((p) => !pruned.has(p))\n\t\t\t.map((p) => `${p}: removed locally; server entry kept`),\n\t);\n\tgroup(\n\t\tlines,\n\t\t\"skipped\",\n\t\t[...plan.skipped, ...managedSkips(results)].map(skippedLine),\n\t);\n\tconst unchanged = countOutcomes(plan, results).unchanged;\n\tif (unchanged > 0) {\n\t\tlines.push(`unchanged (${unchanged})`);\n\t}\n\treturn lines;\n}\n\n/**\n * The text report for `--dry-run`: what would be sent, and nothing else.\n * With `--prune`, the removed paths are what it would delete; the old path of\n * a move the server declines is only known once it answers.\n */\nexport function formatDryRunReport(input: {\n\tprojectId: string;\n\tdirectory: string;\n\tplan: ContextPlan;\n\tprune?: boolean;\n}): string[] {\n\tconst { plan } = input;\n\tconst lines = [\n\t\t`Dry run of a context push from ${input.directory} to project ${input.projectId}: nothing was sent and the lock was not written.`,\n\t];\n\tgroup(\n\t\tlines,\n\t\t\"moved\",\n\t\tplan.moves.map((move) => `${move.from} -> ${move.to}`),\n\t);\n\tgroup(\n\t\tlines,\n\t\t\"new\",\n\t\tplan.push\n\t\t\t.filter((entry) => entry.expectedContentHash === undefined)\n\t\t\t.map((entry) => entry.sourcePath),\n\t);\n\tgroup(\n\t\tlines,\n\t\t\"changed\",\n\t\tplan.push\n\t\t\t.filter((entry) => entry.expectedContentHash !== undefined)\n\t\t\t.map((entry) => entry.sourcePath),\n\t);\n\tif (input.prune) {\n\t\tgroup(lines, \"would delete\", plan.removed);\n\t} else {\n\t\tgroup(\n\t\t\tlines,\n\t\t\t\"removed\",\n\t\t\tplan.removed.map(\n\t\t\t\t(p) => `${p}: removed locally; server entry would be kept`,\n\t\t\t),\n\t\t);\n\t}\n\tgroup(lines, \"skipped\", plan.skipped.map(skippedLine));\n\tif (plan.unchangedLocal.length > 0) {\n\t\tlines.push(`unchanged (${plan.unchangedLocal.length})`);\n\t}\n\treturn lines;\n}\n\n/** The `--format json` object: the whole plan and every result, never file content. */\nexport function contextPushJson(input: {\n\tprojectId: string;\n\tdirectory: string;\n\tlockPath: string;\n\tlockWritten: boolean;\n\tdryRun: boolean;\n\tforce: boolean;\n\tprune: boolean;\n\tplan: ContextPlan;\n\tresults: readonly ContextPushResult[];\n}) {\n\treturn {\n\t\tprojectId: input.projectId,\n\t\tdirectory: input.directory,\n\t\tdryRun: input.dryRun,\n\t\tforce: input.force,\n\t\tprune: input.prune,\n\t\tlock: input.lockPath,\n\t\tlockWritten: input.lockWritten,\n\t\tplan: {\n\t\t\tpush: input.plan.push.map((entry) => ({\n\t\t\t\tsourcePath: entry.sourcePath,\n\t\t\t\tsha256: entry.sha256,\n\t\t\t\tbytes: entry.bytes,\n\t\t\t\texpectedContentHash: entry.expectedContentHash ?? null,\n\t\t\t})),\n\t\t\tmoves: input.plan.moves.map((move) => ({\n\t\t\t\tfrom: move.from,\n\t\t\t\tto: move.to,\n\t\t\t\tsha256: move.sha256,\n\t\t\t\tcontextId: move.contextId,\n\t\t\t})),\n\t\t\tunchangedLocal: input.plan.unchangedLocal,\n\t\t\tremoved: input.plan.removed,\n\t\t\tforgotten: input.plan.forgotten,\n\t\t\tskipped: input.plan.skipped,\n\t\t},\n\t\tresults: input.results,\n\t\tcounts: countOutcomes(input.plan, input.results),\n\t};\n}\n","/**\n * fabric ctx\n *\n * fabric ctx current Show active context\n * fabric ctx use org <slug> Set an org as default\n *\n * `use personal` is retired (Fizzy #1875, PO-9). It is still REGISTERED rather\n * than deleted, so someone who types it — or has it in a script — is told what\n * replaced it instead of meeting \"unknown command\". A config written by an\n * earlier version can still hold a personal default; `current` reports it as\n * needing replacing rather than printing it as if it still worked.\n */\n\nimport { Command } from \"commander\";\nimport { getDefaultContext, saveDefaultContext } from \"../../lib/config.js\";\nimport { printError, printSuccess, printWarning } from \"../../lib/output.js\";\n\nexport function buildCtxCommand(): Command {\n\tconst ctx = new Command(\"ctx\").description(\n\t\t\"Manage the organization commands run in\",\n\t);\n\n\t// -- current ------------------------------------------------------------\n\tctx.command(\"current\")\n\t\t.description(\"Show the active default context\")\n\t\t.action(() => {\n\t\t\tconst stored = getDefaultContext();\n\t\t\tif (!stored) {\n\t\t\t\tprintWarning(\n\t\t\t\t\t\"No default context set. Use --org <slug> on each command, or run:\\n fabric ctx use org <slug>\",\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (stored.type === \"personal\") {\n\t\t\t\t// Reported, not hidden: it is set, the user can see it is set,\n\t\t\t\t// and saying \"none\" would send them looking for a setting that\n\t\t\t\t// is right there.\n\t\t\t\tprintWarning(\n\t\t\t\t\t\"Context: personal — retired, and no command will accept it.\\nReplace it with:\\n fabric ctx use org <slug>\",\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tprocess.stdout.write(`Context: org:${stored.slug}\\n`);\n\t\t});\n\n\t// -- use ----------------------------------------------------------------\n\tconst use = new Command(\"use\").description(\n\t\t\"Set the default organization for commands\",\n\t);\n\n\tuse.command(\"personal\")\n\t\t.description(\"Retired — context is organization-only\")\n\t\t.action(() => {\n\t\t\tprintError(\n\t\t\t\t\"Personal context no longer exists — every command runs inside an organization.\\nSet one with:\\n fabric ctx use org <slug>\",\n\t\t\t\t2,\n\t\t\t);\n\t\t});\n\n\tuse.command(\"org <slug>\")\n\t\t.description(\"Use an org context by default\")\n\t\t.action((slug: string) => {\n\t\t\tsaveDefaultContext({ type: \"org\", slug });\n\t\t\tprintSuccess(`Default context set to: org:${slug}`);\n\t\t});\n\n\tctx.addCommand(use);\n\n\treturn ctx;\n}\n","/**\n * fabric features\n *\n * fabric features list --project <id> List features in a project\n * fabric features show --project <id> <id> Show feature details\n * fabric features create --project <id> <title> Create a feature\n */\n\nimport type { FabricFeature } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport {\n\tprintError,\n\tprintOutput,\n\tprintRecord,\n\tprintSuccess,\n} from \"../../lib/output.js\";\n\nexport function buildFeaturesCommand(): Command {\n\tconst features = new Command(\"features\").description(\n\t\t\"Manage project features\",\n\t);\n\n\t// -- list ----------------------------------------------------------------\n\tfeatures\n\t\t.command(\"list\")\n\t\t.description(\"List features in a project\")\n\t\t.requiredOption(\"-p, --project <id>\", \"Project ID\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\n\t\t\t\"--priority <priority>\",\n\t\t\t\"Filter: P0_CRITICAL|P1_HIGH|P2_MEDIUM|P3_LOW\",\n\t\t)\n\t\t.option(\"--search <query>\", \"Search by title\")\n\t\t.option(\"--limit <n>\", \"Max results (default 50)\", \"50\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\tproject: string;\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tpriority?: string;\n\t\t\t\tsearch?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricFeature[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.projects.listFeatures(opts.project, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tpriority: opts.priority as\n\t\t\t\t\t\t\t| FabricFeature[\"priority\"]\n\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\tsearch: opts.search,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const f of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${f.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\"identifier\", \"title\", \"priority\", \"createdAt\"],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- show ----------------------------------------------------------------\n\tfeatures\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show feature details\")\n\t\t.requiredOption(\"-p, --project <projectId>\", \"Project ID\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: {\n\t\t\t\t\tproject: string;\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\tformat: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet feature: FabricFeature;\n\t\t\t\ttry {\n\t\t\t\t\tfeature = await client.projects.getFeature(\n\t\t\t\t\t\topts.project,\n\t\t\t\t\t\tid,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(feature, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: feature.id,\n\t\t\t\t\tIdentifier: feature.identifier,\n\t\t\t\t\tTitle: feature.title,\n\t\t\t\t\tPriority: feature.priority,\n\t\t\t\t\tDescription: feature.description ?? \"(none)\",\n\t\t\t\t\t\"Acceptance Criteria\":\n\t\t\t\t\t\tfeature.acceptanceCriteria ?? \"(none)\",\n\t\t\t\t\tProject: feature.projectId,\n\t\t\t\t\tAssignee: feature.assigneeId ?? \"(none)\",\n\t\t\t\t\tCreated: feature.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- create --------------------------------------------------------------\n\tfeatures\n\t\t.command(\"create <title>\")\n\t\t.description(\"Create a feature in a project\")\n\t\t.requiredOption(\"-p, --project <projectId>\", \"Project ID\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"-d, --description <text>\", \"Feature description\")\n\t\t.option(\n\t\t\t\"--priority <priority>\",\n\t\t\t\"Priority: P0_CRITICAL|P1_HIGH|P2_MEDIUM|P3_LOW (default: P2_MEDIUM)\",\n\t\t)\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\ttitle: string,\n\t\t\t\topts: {\n\t\t\t\t\tproject: string;\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\tdescription?: string;\n\t\t\t\t\tpriority?: string;\n\t\t\t\t\tformat: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet feature: FabricFeature;\n\t\t\t\ttry {\n\t\t\t\t\tfeature = await client.projects.createFeature(\n\t\t\t\t\t\topts.project,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttitle,\n\t\t\t\t\t\t\tdescription: opts.description,\n\t\t\t\t\t\t\tpriority: opts.priority as\n\t\t\t\t\t\t\t\t| FabricFeature[\"priority\"]\n\t\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(feature, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintSuccess(`Feature ${feature.identifier} created`);\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: feature.id,\n\t\t\t\t\tIdentifier: feature.identifier,\n\t\t\t\t\tTitle: feature.title,\n\t\t\t\t\tPriority: feature.priority,\n\t\t\t\t\tProject: feature.projectId,\n\t\t\t\t\tCreated: feature.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- tasks ---------------------------------------------------------------\n\tfeatures\n\t\t.command(\"tasks\")\n\t\t.description(\"List tasks (sub-items) for a feature\")\n\t\t.requiredOption(\"-p, --project <projectId>\", \"Project ID\")\n\t\t.requiredOption(\"-f, --feature <featureId>\", \"Feature ID\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\tproject: string;\n\t\t\t\tfeature: string;\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet tasks: import(\"@fabricorg/sdk\").FabricTask[];\n\t\t\t\ttry {\n\t\t\t\t\ttasks = await client.projects.listTasks(\n\t\t\t\t\t\topts.project,\n\t\t\t\t\t\topts.feature,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const t of tasks) {\n\t\t\t\t\t\tprocess.stdout.write(`${t.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(tasks, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"identifier\",\n\t\t\t\t\t\t\"title\",\n\t\t\t\t\t\t\"status\",\n\t\t\t\t\t\t\"estimatedHours\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- update --------------------------------------------------------------\n\tfeatures\n\t\t.command(\"update <id>\")\n\t\t.description(\"Update a feature\")\n\t\t.requiredOption(\"-p, --project <projectId>\", \"Project ID\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--title <title>\", \"New title\")\n\t\t.option(\"-d, --description <text>\", \"New description\")\n\t\t.option(\n\t\t\t\"--priority <priority>\",\n\t\t\t\"Priority: P0_CRITICAL|P1_HIGH|P2_MEDIUM|P3_LOW\",\n\t\t)\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: {\n\t\t\t\t\tproject: string;\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\ttitle?: string;\n\t\t\t\t\tdescription?: string;\n\t\t\t\t\tpriority?: string;\n\t\t\t\t\tformat: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet feature: FabricFeature;\n\t\t\t\ttry {\n\t\t\t\t\tfeature = await client.projects.updateFeature(\n\t\t\t\t\t\topts.project,\n\t\t\t\t\t\tid,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttitle: opts.title,\n\t\t\t\t\t\t\tdescription: opts.description,\n\t\t\t\t\t\t\tpriority: opts.priority as\n\t\t\t\t\t\t\t\t| FabricFeature[\"priority\"]\n\t\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(feature, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: feature.id,\n\t\t\t\t\tIdentifier: feature.identifier,\n\t\t\t\t\tTitle: feature.title,\n\t\t\t\t\tPriority: feature.priority,\n\t\t\t\t\tUpdated: feature.updatedAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn features;\n}\n","/**\n * fabric frames\n *\n * fabric frames list List frames and slideshows\n * fabric frames show <id> Show frame details\n */\n\nimport type { FabricFrame } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildFramesCommand(): Command {\n\tconst frames = new Command(\"frames\").description(\n\t\t\"Manage AI-generated frames and slideshows\",\n\t);\n\n\t// -- list ----------------------------------------------------------------\n\tframes\n\t\t.command(\"list\")\n\t\t.description(\"List frames and slideshows\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--limit <n>\", \"Max results (default 50)\", \"50\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricFrame[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.frames.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const f of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${f.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"title\",\n\t\t\t\t\t\t\"fileType\",\n\t\t\t\t\t\t\"status\",\n\t\t\t\t\t\t\"isPublic\",\n\t\t\t\t\t\t\"updatedAt\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- show ----------------------------------------------------------------\n\tframes\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show frame details\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet frame: FabricFrame;\n\t\t\t\ttry {\n\t\t\t\t\tframe = await client.frames.get(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(frame, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: frame.id,\n\t\t\t\t\tTitle: frame.title,\n\t\t\t\t\tKind: frame.kind ?? \"(none)\",\n\t\t\t\t\t\"File Type\": frame.fileType,\n\t\t\t\t\tStatus: frame.status,\n\t\t\t\t\tPublic: frame.isPublic ? \"yes\" : \"no\",\n\t\t\t\t\t\"Share Token\": frame.shareToken ?? \"(none)\",\n\t\t\t\t\tDescription: frame.description ?? \"(none)\",\n\t\t\t\t\tUpdated: frame.updatedAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn frames;\n}\n","/**\n * fabric instructions\n *\n * fabric instructions check --project <id> Is the local copy current?\n * fabric instructions doctor --project <id> Is this machine set up the way the\n * instructions expect? Reads only; runs nothing.\n * fabric instructions sync --project <id> Make it current.\n * fabric instructions push --project <id> Suggest the local edits back.\n * fabric instructions init --project <id> --tool claude-code|codex\n * Take the first copy, then write the session hook.\n *\n * A repository-sourced project is the exception (Fizzy #2708): in a checkout\n * of its own repository `check`, `sync` and the hook only REPORT whether the\n * published commit is in HEAD's history, and `init` writes the hook without a\n * copy. `lib/instructions/checkout.ts` decides which directory is which.\n *\n * The first file-writing commands in this CLI. Everything that touches the\n * filesystem lives in `lib/instructions/` as small testable modules; this\n * file is argument parsing, the sequence, and the words a developer reads.\n *\n * `--hook` is the contract that makes this safe to run at session start: it\n * NEVER exits non-zero, it has ONE absolute deadline covering every request\n * it makes, and it never prints more than it has to. A coding session that\n * cannot start because Fabric is unreachable would be a far worse failure\n * than instructions that are one version stale.\n */\nimport path from \"node:path\";\nimport type {\n\tFabricClient,\n\tProposalAppend,\n\tProposalBranch,\n\tProposalPullRequest,\n\tProposalPullRequestFailure,\n\tPublishedInstructionRepository,\n\tPublishedInstructionSource,\n\tPublishedInstructions,\n} from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport {\n\tasCliFailure,\n\tCliFailure,\n\tdescribeError,\n\ttype OutputFormat,\n\toutputFormatFor,\n\twithDeadline,\n} from \"../../lib/command-boundary.js\";\nimport { getApiKey, getConfigPath } from \"../../lib/config.js\";\nimport { applyPlan } from \"../../lib/instructions/apply.js\";\nimport { extractBundle, fetchBundle } from \"../../lib/instructions/bundle.js\";\nimport {\n\ttype CheckoutClassification,\n\ttype CheckoutJson,\n\tclassifyCheckout,\n\tclassLine,\n\tcurrentLine,\n\tdownloadsIn,\n\tinstalledLine,\n\tnothingPublishedLine,\n\treportForClassification,\n} from \"../../lib/instructions/checkout.js\";\nimport {\n\tbuildFabricCommand,\n\tformatDoctorText,\n\trunDoctor,\n} from \"../../lib/instructions/doctor.js\";\nimport {\n\tassertKeyStaysOutside,\n\tbuildHookCommand,\n\tbuildLessonPromptCommand,\n\tCLAUDE_SETTINGS_RELATIVE_PATH,\n\tCODEX_HOOKS_RELATIVE_PATH,\n\ttype InstructionsHookTool,\n\tmergeCommandHook,\n\tmergeSessionStartHook,\n\tremoveCommandHook,\n} from \"../../lib/instructions/hook.js\";\nimport { hookTiming } from \"../../lib/instructions/hook-timing.js\";\nimport {\n\treadAllStdin,\n\trunLessonPrompt,\n} from \"../../lib/instructions/lesson-prompt.js\";\nimport {\n\ttype InstructionsLock,\n\tLOCK_DIRECTORY,\n\tlockPath,\n\treadLock,\n\treadLockSafely,\n\twriteLock,\n} from \"../../lib/instructions/lock.js\";\nimport {\n\tassertValidManifest,\n\tmaxArchiveBytes,\n} from \"../../lib/instructions/manifest.js\";\nimport { lookUpOpenProposals } from \"../../lib/instructions/open-proposals.js\";\nimport {\n\tcomputeSyncPlan,\n\tdescribeLedgerDrift,\n\tfindLedgerDrift,\n\ttype LedgerDrift,\n\tnextLock,\n\treconcileKeptInLock,\n\ttype SyncPlan,\n} from \"../../lib/instructions/plan.js\";\nimport {\n\tbranchStoppedByFailure,\n\ttype PullRequestWait,\n\tsplitMessage,\n\twaitForPullRequest,\n} from \"../../lib/instructions/pull-request-wait.js\";\nimport {\n\ttype AlreadyProposed,\n\tcomputePushPlan,\n\tMAX_PUSH_CHANGES,\n\tsetAsideProposed,\n} from \"../../lib/instructions/push.js\";\nimport {\n\tresolveDestinationRoot,\n\tresolveExistingRoot,\n} from \"../../lib/instructions/safe-write.js\";\nimport { printOutput } from \"../../lib/output.js\";\n\n/**\n * The whole of hook mode, end to end, including the bundle download.\n *\n * One ABSOLUTE deadline rather than one per request. The SDK's timeout is\n * per attempt and it retries twice by default, so three \"5 second\" calls\n * plus backoff is about 15.75 seconds — past the point where Claude Code\n * kills the hook itself, possibly mid-write. Retries are off in hook mode\n * and this bound covers everything. The value lives in `hookTiming`\n * (`lib/instructions/hook-timing.ts`) so a test can shorten it.\n */\nfunction hookDeadlineMs(): number {\n\treturn hookTiming.deadlineMs;\n}\n\n/**\n * The read-only git commands a manual run makes to classify a checkout of a\n * repository-sourced project (Fizzy #2708), all together. Hook mode uses what\n * is left of the hook deadline, less `hookTiming.gitMarginMs`, instead.\n */\nconst GIT_BUDGET_MS = 10_000;\n\n/** A manual check: no writes, so one short request and no more. */\nconst CHECK_TIMEOUT_MS = 5_000;\n\n/** A manual sync may wait longer for the manifest, but not indefinitely. */\nconst SYNC_TIMEOUT_MS = 15_000;\n\n/**\n * The archive, when a person is waiting rather than a session start — and the\n * request that ASKS for the archive, not just the transfer that follows it.\n *\n * `createDownloadUrl` is normally sub-second, because publishing a version\n * pre-builds its archive. When the pre-build did not happen (it failed, or\n * the object was swept) the server builds the zip inside that request, which\n * on a large tree takes far longer than any manifest read — and under the\n * manifest's 15-second budget the call timed out, retried, and each retry\n * started ANOTHER full build on the server rather than waiting for the first.\n * So the download-link call gets this budget and no retries.\n */\nconst BUNDLE_TIMEOUT_MS = 60_000;\n\n/**\n * A push carries file bytes up and starts a validation run, so it waits longer\n * than the manifest calls do — and it gets ONE attempt, so the timeout is the\n * whole budget rather than a third of it.\n */\nconst PUSH_TIMEOUT_MS = 60_000;\n\n/**\n * Commander's accumulator for a repeatable `--add`.\n *\n * Declared with an initial `[]`, so `previous` is always an array and this\n * never has to guess.\n */\nfunction collectAdded(value: string, previous: string[]): string[] {\n\treturn [...previous, value];\n}\n\ninterface CommonOptions {\n\tproject: string;\n\tdest?: string;\n\torg?: string;\n\thook?: boolean;\n\t/**\n\t * Declared for `--help` and read through `optsWithGlobals()`, never off\n\t * this object: Commander stores a flag both a parent and a subcommand\n\t * declare on the parent.\n\t */\n\tformat?: string;\n}\n\nexport function buildInstructionsCommand(): Command {\n\tconst instructions = new Command(\"instructions\").description(\n\t\t\"Keep a checkout current with a project's published coding instructions\",\n\t);\n\n\tinstructions\n\t\t.command(\"check\")\n\t\t.description(\n\t\t\t\"Report whether the local copy is behind the published one\",\n\t\t)\n\t\t.requiredOption(\"--project <id>\", \"Project ID\")\n\t\t.option(\"--dest <dir>\", \"Destination directory (default: cwd)\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\n\t\t\t\"--verify\",\n\t\t\t\"Also hash the local files against the lock and report any that drifted\",\n\t\t)\n\t\t.option(\n\t\t\t\"--hook\",\n\t\t\t\"Session-hook mode: plain text, never fails, never blocks a session\",\n\t\t)\n\t\t// No default: a default here would shadow the program-level --format,\n\t\t// which is where `FABRIC_FORMAT` enters.\n\t\t.option(\"--format <format>\", \"Output format: text|json\")\n\t\t.action(async function (\n\t\t\tthis: Command,\n\t\t\topts: CommonOptions & { verify?: boolean },\n\t\t) {\n\t\t\tawait run(opts, \"check\", () =>\n\t\t\t\trunCheck(opts, outputFormatFor(this)),\n\t\t\t);\n\t\t});\n\n\tinstructions\n\t\t.command(\"doctor\")\n\t\t.description(\n\t\t\t\"Check whether this machine is set up the way the project's coding instructions expect\",\n\t\t)\n\t\t.requiredOption(\"--project <id>\", \"Project ID\")\n\t\t.option(\"--dest <dir>\", \"Destination directory (default: cwd)\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\n\t\t\t\"--probe-network\",\n\t\t\t\"Also send one HTTP GET to each url server in .mcp.json to see whether it answers\",\n\t\t)\n\t\t.option(\"--format <format>\", \"Output format: text|json\")\n\t\t.action(async function (\n\t\t\tthis: Command,\n\t\t\topts: CommonOptions & { probeNetwork?: boolean },\n\t\t) {\n\t\t\t// Never hook mode: doctor is run by a person (or an agent acting\n\t\t\t// for one), and a failed check is a real exit code.\n\t\t\tawait run({ ...opts, hook: false }, \"doctor\", () =>\n\t\t\t\trunDoctorCommand(opts, outputFormatFor(this)),\n\t\t\t);\n\t\t});\n\n\tinstructions\n\t\t.command(\"sync\")\n\t\t.description(\n\t\t\t\"Write the published coding instructions into the checkout\",\n\t\t)\n\t\t.requiredOption(\"--project <id>\", \"Project ID\")\n\t\t.option(\"--dest <dir>\", \"Destination directory (default: cwd)\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--dry-run\", \"Print the plan and write nothing\")\n\t\t.option(\n\t\t\t\"--repair\",\n\t\t\t\"Replace local edits to synced files with the published version; without it, sync keeps them\",\n\t\t)\n\t\t.option(\n\t\t\t\"--hook\",\n\t\t\t\"Session-hook mode: plain text, never fails, never blocks a session\",\n\t\t)\n\t\t.option(\"--format <format>\", \"Output format: text|json\")\n\t\t.action(async function (\n\t\t\tthis: Command,\n\t\t\topts: CommonOptions & { dryRun?: boolean; repair?: boolean },\n\t\t) {\n\t\t\tawait run(opts, \"sync\", () => runSync(opts, outputFormatFor(this)));\n\t\t});\n\n\tinstructions\n\t\t.command(\"push\")\n\t\t.description(\n\t\t\t\"Propose this checkout's edits to the project's coding instructions, or publish them with --publish\",\n\t\t)\n\t\t.requiredOption(\"--project <id>\", \"Project ID\")\n\t\t.option(\"--dest <dir>\", \"Destination directory (default: cwd)\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\n\t\t\t\"--add <path>\",\n\t\t\t\"Also send a file the last sync did not write (repeatable)\",\n\t\t\tcollectAdded,\n\t\t\t[] as string[],\n\t\t)\n\t\t.option(\n\t\t\t\"--publish\",\n\t\t\t\"Publish the change as a new version instead of proposing it (needs a key with instructions:publish)\",\n\t\t)\n\t\t.option(\n\t\t\t\"--message <text>\",\n\t\t\t\"Title (first line) and description of the suggested change\",\n\t\t)\n\t\t.option(\n\t\t\t\"--no-wait\",\n\t\t\t\"Return as soon as the suggestion is accepted, without waiting for its pull request\",\n\t\t)\n\t\t.option(\n\t\t\t\"--include-proposed\",\n\t\t\t\"Also send changes your open proposals already carry (left out by default)\",\n\t\t)\n\t\t.option(\"--dry-run\", \"Print the change set and send nothing\")\n\t\t.option(\"--format <format>\", \"Output format: text|json\")\n\t\t.action(async function (\n\t\t\tthis: Command,\n\t\t\topts: CommonOptions & {\n\t\t\t\tadd?: string[];\n\t\t\t\tpublish?: boolean;\n\t\t\t\tmessage?: string;\n\t\t\t\twait?: boolean;\n\t\t\t\tincludeProposed?: boolean;\n\t\t\t\tdryRun?: boolean;\n\t\t\t},\n\t\t) {\n\t\t\t// Never hook mode: a session start does not push. Stated rather\n\t\t\t// than inherited, because `run`'s never-fail branch exists for\n\t\t\t// commands a hook runs and this is not one.\n\t\t\tawait run({ ...opts, hook: false }, \"push\", () =>\n\t\t\t\trunPush(opts, outputFormatFor(this)),\n\t\t\t);\n\t\t});\n\n\tinstructions\n\t\t.command(\"init\")\n\t\t.description(\n\t\t\t\"Write a SessionStart hook for a coding tool and take the first copy\",\n\t\t)\n\t\t.requiredOption(\"--project <id>\", \"Project ID\")\n\t\t.requiredOption(\n\t\t\t\"--tool <tool>\",\n\t\t\t\"Coding tool to configure: claude-code|codex\",\n\t\t)\n\t\t.option(\"--dest <dir>\", \"Destination directory (default: cwd)\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\n\t\t\t\"--apply\",\n\t\t\t\"Let the hook apply changes instead of only reporting them\",\n\t\t)\n\t\t.option(\n\t\t\t\"--lessons\",\n\t\t\t\"Also install a Stop hook that asks, once per session after the assistant has edited files, whether a mistake from the session should become a team lesson\",\n\t\t)\n\t\t.option(\"--format <format>\", \"Output format: text|json\")\n\t\t.action(async function (\n\t\t\tthis: Command,\n\t\t\topts: CommonOptions & {\n\t\t\t\ttool: string;\n\t\t\t\tapply?: boolean;\n\t\t\t\tlessons?: boolean;\n\t\t\t},\n\t\t) {\n\t\t\t// Never hook mode: `init` is run by a person, so its failures\n\t\t\t// are real failures with real exit codes.\n\t\t\tawait run({ ...opts, hook: false }, \"init\", () =>\n\t\t\t\trunInit(opts, outputFormatFor(this)),\n\t\t\t);\n\t\t});\n\n\tinstructions\n\t\t.command(\"lesson-prompt\", { hidden: true })\n\t\t.description(\n\t\t\t\"Stop hook: ask, once per session, whether a mistake should become a team lesson\",\n\t\t)\n\t\t.option(\"--project <id>\", \"Project ID\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\n\t\t\t\"--hook\",\n\t\t\t\"Stop-hook mode: reads JSON from stdin, never fails, never prints unless it is asking\",\n\t\t)\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\tproject?: string;\n\t\t\t\torg?: string;\n\t\t\t\thook?: boolean;\n\t\t\t}) => {\n\t\t\t\tawait runLessonPromptCommand(opts);\n\t\t\t},\n\t\t);\n\n\treturn instructions;\n}\n\n// ---------------------------------------------------------------------------\n// The never-fail boundary\n// ---------------------------------------------------------------------------\n\n/**\n * One place where every failure is turned into either an exit code or, under\n * `--hook`, a single line on stderr and a zero exit.\n *\n * \"Every\" is literal: network, auth, HTTP, timeout, a bad lock file, a\n * refused path, a retired context default. Nothing inside may call\n * `process.exit` itself — `printError` does, and `process.exit` cannot be\n * caught here, which is why these commands build their own client rather than\n * reaching for the exiting helpers the other commands use, and why they read\n * no stored context at all.\n */\nasync function run(\n\topts: { hook?: boolean },\n\tverb: string,\n\tbody: () => Promise<void>,\n): Promise<void> {\n\ttry {\n\t\tif (opts.hook) {\n\t\t\t// The deadline's signal is published for the bundle download\n\t\t\t// (`activeDeadline`) and withdrawn the moment the race settles,\n\t\t\t// whichever side won it.\n\t\t\tconst totalMs = hookDeadlineMs();\n\t\t\tactiveDeadlineAt = Date.now() + totalMs;\n\t\t\tawait withDeadline(totalMs, (signal) => {\n\t\t\t\tactiveDeadline = signal;\n\t\t\t\treturn body();\n\t\t\t}).finally(() => {\n\t\t\t\tactiveDeadline = undefined;\n\t\t\t\tactiveDeadlineAt = undefined;\n\t\t\t});\n\t\t} else {\n\t\t\tawait body();\n\t\t}\n\t} catch (error) {\n\t\tconst message = describeError(error);\n\t\tif (opts.hook) {\n\t\t\tprocess.stderr.write(\n\t\t\t\t`fabric: coding instructions ${verb} skipped: ${message}\\n`,\n\t\t\t);\n\t\t\tprocess.exit(0);\n\t\t}\n\t\tprocess.stderr.write(`✗ ${message}\\n`);\n\t\tprocess.exit(error instanceof CliFailure ? error.exitCode : 1);\n\t}\n}\n\n/**\n * The deadline signal in force, if any, so the bundle download can be\n * cancelled by the same clock that bounds the command. Module state rather\n * than a threaded parameter because every command body is single-shot within\n * one process.\n */\nlet activeDeadline: AbortSignal | undefined;\n\n/**\n * The same deadline as an absolute time, for the git commands a\n * repository-sourced project's hook runs.\n */\nlet activeDeadlineAt: number | undefined;\n\n/**\n * When the git commands this run makes must be done by. Under a hook that is\n * `hookTiming.gitMarginMs` BEFORE the outer deadline, never at it: a git call\n * that runs out answers \"unavailable\", the checkout is `unknown`, and that\n * line reaches stdout with time to spare — rather than racing the outer\n * timer, whose generic \"skipped\" line goes to stderr, which a successful\n * hook's session never sees. A margin already spent makes every git call\n * answer \"timed out\" at once, with the same result.\n */\nfunction gitDeadline(): number {\n\treturn activeDeadlineAt === undefined\n\t\t? Date.now() + GIT_BUDGET_MS\n\t\t: activeDeadlineAt - hookTiming.gitMarginMs;\n}\n\n// ---------------------------------------------------------------------------\n// Shared steps\n// ---------------------------------------------------------------------------\n\nfunction destinationOf(opts: { dest?: string }): string {\n\treturn path.resolve(opts.dest ?? process.cwd());\n}\n\n/**\n * A client that throws instead of exiting, and that never retries in hook\n * mode.\n *\n * `getClient` calls `printError`, which exits with code 3 — correct for every\n * other command and fatal to the `--hook` contract, which must never exit\n * non-zero for any reason.\n */\nfunction instructionsClient(\n\topts: { hook?: boolean },\n\ttimeoutMs: number,\n\t{ neverRetry = false }: { neverRetry?: boolean } = {},\n): FabricClient {\n\tif (!getApiKey()) {\n\t\tthrow new CliFailure(\n\t\t\t\"Not authenticated. Run: fabric auth login --key <api-key>\",\n\t\t\t3,\n\t\t);\n\t}\n\t// `withoutContext()`: the SDK constructor adopts `FABRIC_ORG` /\n\t// `FABRIC_PERSONAL` and injects them into every URL that does not name a\n\t// context. On a project-authoritative surface that ambient default is not\n\t// a default, it is a contradiction waiting to be refused — see\n\t// `orgSlugFor`.\n\treturn getClient(\n\t\topts.hook\n\t\t\t? {\n\t\t\t\t\t// Hook mode has ONE absolute deadline covering every\n\t\t\t\t\t// call it makes, so it cannot spend it on retries: a\n\t\t\t\t\t// session that will not start is worse than instructions\n\t\t\t\t\t// one version stale.\n\t\t\t\t\ttimeoutMs: Math.min(timeoutMs, hookDeadlineMs()),\n\t\t\t\t\tretry: { maxRetries: 0 },\n\t\t\t\t}\n\t\t\t: neverRetry\n\t\t\t\t? { timeoutMs, retry: { maxRetries: 0 } }\n\t\t\t\t: { timeoutMs },\n\t).withoutContext();\n}\n\n/**\n * A separate client for `createDownloadUrl`, because that one call is not a\n * manifest read.\n *\n * It gets the BUNDLE budget. Publishing a version pre-builds its archive, so\n * this is normally sub-second — but when the archive is not there the server\n * builds it inside this request, which on a large tree runs well past the\n * manifest timeout. Sharing the manifest client meant a sync of a brand-new\n * version failed with \"Request timed out after 15000ms\".\n *\n * `neverRetry: true` is belt-and-suspenders here, not load-bearing: the SDK's\n * `createDownloadUrl` itself now sends `{ maxRetries: 0 }` on every call\n * (`packages/sdk/src/resources/instructions.ts`), because a retry of this\n * route does not wait for the build already running on the server — it starts\n * a second, and then a third, of the same archive. Kept here so this client\n * stays never-retry even if `createDownloadUrl` is ever swapped for a call\n * that does not make that guarantee itself.\n */\nfunction downloadUrlClient(opts: { hook?: boolean }): FabricClient {\n\treturn instructionsClient(\n\t\topts,\n\t\topts.hook ? hookDeadlineMs() : BUNDLE_TIMEOUT_MS,\n\t\t{ neverRetry: true },\n\t);\n}\n\n/**\n * The org slug to send: the one on the command line, or none at all.\n *\n * These commands are PROJECT-AUTHORITATIVE — the project decides which\n * organization it is in, and the route resolves that from the project itself.\n * Sending a stored default context (or `FABRIC_ORG`) turned that resolution\n * into a contradiction for anyone whose default is not the project's host\n * organization, and the clearest case is the one the route exists to support:\n * an invited guest, whose own default organization is never the one hosting a\n * project they were invited to. Their request carried `?org=<their own org>`,\n * the route compared it with the project's, and refused.\n *\n * So the ambient default is not consulted here and the client is built\n * without one. `--org` remains available for the caller who wants the request\n * bound explicitly; an explicit slug that disagrees with the project is still\n * a 404, which is the point of passing it.\n */\nfunction orgSlugFor(opts: CommonOptions): string | undefined {\n\treturn opts.org;\n}\n\nasync function fetchPublished(\n\tclient: FabricClient,\n\topts: CommonOptions,\n\tsinceDigest?: string,\n\tguard?: SourceGuard,\n): Promise<PublishedInstructions> {\n\tconst org = orgSlugFor(opts);\n\tlet published: PublishedInstructions;\n\ttry {\n\t\tpublished = await client.instructions.getPublished(opts.project, {\n\t\t\torg,\n\t\t\tsinceDigest,\n\t\t});\n\t} catch (error) {\n\t\tthrow asCliFailure(error);\n\t}\n\tawait guard?.admit(published);\n\treturn published;\n}\n\n/**\n * Where a command's instructions come from, decided once and then held to\n * (Fizzy #2708).\n *\n * The FIRST response decides: for a repository-sourced project it classifies\n * the directory against that response's `repository` block, and that\n * classification governs the whole command — report only in a checkout of the\n * repository, the upload behaviour in a directory that is not a checkout at\n * all. Every LATER response (`sync`'s drift refetch, `init`'s first-copy\n * sync) must then name the same source: a `sourceOfTruth` or repository\n * configuration that moved between two calls means the classification may be\n * wrong for what is now being applied, so the command stops before it plans,\n * downloads or writes anything. Checking only the first response let a\n * project switched between the two be planned, downloaded and applied — a\n * second writer in a checkout that git already keeps current.\n */\nclass SourceGuard {\n\tprivate first: string | undefined;\n\t/** `null` until admitted, and for a project that is not repository-sourced. */\n\tcheckout: CheckoutClassification | null = null;\n\n\tconstructor(private readonly destination: string) {}\n\n\tasync admit(published: PublishedInstructions): Promise<void> {\n\t\tconst identity = sourceIdentity(published);\n\t\tif (this.first === undefined) {\n\t\t\tthis.first = identity;\n\t\t\tif (published.sourceOfTruth === \"REPOSITORY\") {\n\t\t\t\tthis.checkout = await classifyCheckout({\n\t\t\t\t\tdestination: this.destination,\n\t\t\t\t\trepository: published.repository,\n\t\t\t\t\tdeadline: gitDeadline(),\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (identity !== this.first) {\n\t\t\tthrow new CliFailure(\n\t\t\t\t\"this project's instruction source changed while this command ran; nothing was written — run it again\",\n\t\t\t\t7,\n\t\t\t);\n\t\t}\n\t}\n}\n\n/** The fields whose change between two responses stops a command. */\nfunction sourceIdentity(published: PublishedInstructions): string {\n\tconst repository = published.repository ?? null;\n\treturn JSON.stringify([\n\t\tpublished.sourceOfTruth,\n\t\trepository === null\n\t\t\t? null\n\t\t\t: [\n\t\t\t\t\trepository.provider,\n\t\t\t\t\trepository.host,\n\t\t\t\t\trepository.path,\n\t\t\t\t\trepository.ref,\n\t\t\t\t\trepository.rootPath,\n\t\t\t\t\trepository.generation,\n\t\t\t\t],\n\t]);\n}\n\n/**\n * The lock, refused when it belongs to a different project.\n *\n * A lock is a per-destination file and a destination holds one project's\n * tree. `sync --project B` in a directory synced from project A would\n * otherwise send A's digest, receive B's manifest, and then use A's ledger to\n * decide what to delete — classifying every A-only file as \"the sync wrote\n * this, remove it\". Equal digests across the two could even report \"up to\n * date\" for a tree that holds the wrong project's instructions entirely.\n */\nasync function readLockForProject(\n\tdestination: string,\n\tprojectId: string,\n): Promise<InstructionsLock | null> {\n\tconst lock = await readLock(destination);\n\tif (lock !== null && lock.projectId !== projectId) {\n\t\tthrow new CliFailure(\n\t\t\t`${lockPath(destination)} belongs to project ${lock.projectId}, not ${projectId}. Use a different --dest, or remove that lock if this directory should now follow ${projectId}.`,\n\t\t\t7,\n\t\t);\n\t}\n\treturn lock;\n}\n\n/**\n * The lock's digest as a HINT for the first request, or `undefined` — never a\n * failure (Fizzy #2708 review).\n *\n * The lock is validated only once the directory has been classified, and only\n * where this run may use it: a checkout of a repository-sourced project's own\n * repository never has one, so a malformed, symlinked, unsupported or other\n * project's lock left there must not stop the report. The hint keeps the\n * one-request session start for everyone else: when the validated lock later\n * turns out to carry a different digest (or none), `validatedLock` asks again.\n */\nasync function lockDigestHint(\n\troot: string,\n\tprojectId: string,\n): Promise<string | undefined> {\n\ttry {\n\t\t// The guarded, bounded reader: a symlinked `.fabric` or lock is\n\t\t// refused rather than followed out of the checkout.\n\t\tconst lock = await readLockSafely(root, {\n\t\t\tmaxBytes: MAX_HINT_LOCK_BYTES,\n\t\t});\n\t\treturn lock !== null && lock.projectId === projectId\n\t\t\t? lock.digest\n\t\t\t: undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/** A 5000-file lock is about a megabyte; a hint is not worth reading more. */\nconst MAX_HINT_LOCK_BYTES = 16 * 1024 * 1024;\n\n/** Whether this run may use the lock: an uploaded project, or a class that downloads. */\nfunction usesLock(guard: SourceGuard, manual: boolean): boolean {\n\treturn guard.checkout === null || downloadsIn(guard.checkout, manual);\n}\n\n/**\n * The lock, validated, and the response to act on: the one already fetched\n * when it was asked with this lock's digest, otherwise a second request —\n * held to the first by the same guard.\n */\nasync function validatedLock(\n\tclient: FabricClient,\n\topts: CommonOptions,\n\tdestination: string,\n\tguard: SourceGuard,\n\thint: string | undefined,\n\tpublished: PublishedInstructions,\n): Promise<{\n\tlock: InstructionsLock | null;\n\tpublished: PublishedInstructions;\n}> {\n\tconst lock = await readLockForProject(destination, opts.project);\n\tif (lock?.digest === hint) {\n\t\treturn { lock, published };\n\t}\n\treturn {\n\t\tlock,\n\t\tpublished: await fetchPublished(client, opts, lock?.digest, guard),\n\t};\n}\n\n/**\n * A person's manual `sync` in a directory that may be a checkout of the\n * repository but cannot be shown to be a safe place to copy into: refused,\n * with the class line (Fizzy #2708 review — fail closed).\n */\nfunction refuseManualSync(\n\tcheckout: CheckoutClassification,\n\trepository: PublishedInstructions[\"repository\"],\n): CliFailure | null {\n\tif (checkout.class === \"matching\" || checkout.class === \"not-git\") {\n\t\treturn null;\n\t}\n\treturn new CliFailure(classLine(checkout, repository ?? null), 7);\n}\n\nfunction line(text: string): void {\n\tprocess.stdout.write(`${text}\\n`);\n}\n\nfunction listPaths(label: string, paths: string[]): void {\n\tif (paths.length === 0) {\n\t\treturn;\n\t}\n\tline(` ${label}:`);\n\tfor (const p of paths) {\n\t\tline(` ${p}`);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// check\n// ---------------------------------------------------------------------------\n\nasync function runCheck(\n\topts: CommonOptions & { verify?: boolean },\n\tformat: OutputFormat,\n): Promise<void> {\n\tconst destination = destinationOf(opts);\n\t// Canonical, but NOT created: `check` is informational and must not make a\n\t// directory as a side effect. Every guarded read resolves against this,\n\t// and a literal path would refuse legitimately — `/tmp` is a symlink on\n\t// macOS, so the string a user passes and the directory they mean differ.\n\tconst root = await resolveExistingRoot(destination);\n\tconst client = instructionsClient(opts, CHECK_TIMEOUT_MS);\n\tconst guard = new SourceGuard(destination);\n\tconst hint = await lockDigestHint(root, opts.project);\n\tlet published = await fetchPublished(client, opts, hint, guard);\n\n\t// A repository-sourced project (Fizzy #2708): what this directory is\n\t// decides what the check says. Outside any git checkout nothing changes;\n\t// in a checkout of the repository — or anything that might be one — a\n\t// hook prints only the one line below, and nothing at all when current.\n\tconst checkout =\n\t\tguard.checkout === null\n\t\t\t? null\n\t\t\t: await reportForClassification({\n\t\t\t\t\tclassification: guard.checkout,\n\t\t\t\t\trepository: published.repository,\n\t\t\t\t\tsnapshot: published.snapshot,\n\t\t\t\t\tdeadline: gitDeadline(),\n\t\t\t\t});\n\tif (\n\t\topts.hook &&\n\t\tformat !== \"json\" &&\n\t\tcheckout !== null &&\n\t\tcheckout.classification.class !== \"not-git\"\n\t) {\n\t\tif (checkout.line !== null) {\n\t\t\tline(checkout.line);\n\t\t}\n\t\treturn;\n\t}\n\n\t// The lock only where this run may use it; elsewhere the report reads as\n\t// \"not synced here\", which is what such a directory is.\n\tlet lock: InstructionsLock | null = null;\n\tif (usesLock(guard, !opts.hook)) {\n\t\t({ lock, published } = await validatedLock(\n\t\t\tclient,\n\t\t\topts,\n\t\t\tdestination,\n\t\t\tguard,\n\t\t\thint,\n\t\t\tpublished,\n\t\t));\n\t}\n\n\t// Deliberately NOT validated against `assertValidManifest`: `check`\n\t// writes nothing, so a skewed manifest here can only produce a less\n\t// useful report, and refusing would make the informational command the\n\t// fragile one. `sync` validates before it can act on it.\n\n\t// Off by default, and that is the trade rather than an oversight: this is\n\t// the command a session start runs, one request and no local reads. With\n\t// `--verify` it also hashes every file the lock names, which is what\n\t// answers \"is my checkout still what was published\" as opposed to \"has\n\t// the published version moved\". `sync` always does this.\n\tconst drift =\n\t\topts.verify && lock !== null\n\t\t\t? await findLedgerDrift({ root, lock })\n\t\t\t: [];\n\n\tif (format === \"json\") {\n\t\tprintOutput(\n\t\t\t{\n\t\t\t\tprojectId: opts.project,\n\t\t\t\tdestination,\n\t\t\t\tsynced: lock !== null,\n\t\t\t\tlocalDigest: lock?.digest ?? null,\n\t\t\t\tverified: Boolean(opts.verify),\n\t\t\t\tdrifted: drift.map(describeLedgerDrift),\n\t\t\t\t// Spec §6.4: the edits an earlier sync saw and kept.\n\t\t\t\tkeptEdited: drift\n\t\t\t\t\t.filter((entry) => entry.reason === \"edited\" && entry.kept)\n\t\t\t\t\t.map((entry) => entry.path),\n\t\t\t\t...published,\n\t\t\t\tcheckout: checkout?.json ?? null,\n\t\t\t},\n\t\t\t{ format: \"json\" },\n\t\t);\n\t\treturn;\n\t}\n\n\treportPublishedState(opts, destination, lock, published);\n\n\t// The common tail. Every text-mode branch returns through here, because\n\t// `--verify` promises to report local drift and three of those branches\n\t// used to return before saying a word about it.\n\tif (opts.verify) {\n\t\treportDrift(opts, destination, drift);\n\t}\n\tif (checkout?.line) {\n\t\tline(checkout.line);\n\t}\n}\n\n/** What the server said about the published snapshot, in text. */\nfunction reportPublishedState(\n\topts: CommonOptions,\n\tdestination: string,\n\tlock: InstructionsLock | null,\n\tpublished: PublishedInstructions,\n): void {\n\tif (!published.published) {\n\t\tline(\"This project has no published coding instructions yet.\");\n\t\treturn;\n\t}\n\n\tconst version = published.snapshot?.version;\n\tconst source = published.snapshot?.source;\n\tif (source?.kind === \"REPOSITORY\") {\n\t\tline(describeRepositorySource(source, published.repository ?? null));\n\t}\n\n\tif (!lock) {\n\t\tline(\n\t\t\t`Coding instructions have not been synced into ${destination} yet (published version ${version}, ${published.snapshot?.fileCount} files).`,\n\t\t);\n\t\tline(\n\t\t\t`Run \\`fabric instructions sync --project ${opts.project}\\` to take a copy.`,\n\t\t);\n\t\treturn;\n\t}\n\n\tif (published.unchanged) {\n\t\t// \"the published version has not moved\" — NOT \"your files are\n\t\t// correct\". Without `--verify` nothing local has been read at all, and\n\t\t// saying \"up to date\" invited exactly the wrong conclusion.\n\t\tline(`Published coding instructions unchanged (version ${version}).`);\n\t\treturn;\n\t}\n\n\tif (published.changes === null || published.changes === undefined) {\n\t\tline(\n\t\t\t`Coding instructions changed, and the version in ${destination} is not one the server still recognises, so what changed cannot be listed. A full sync is needed (published version ${version}).`,\n\t\t);\n\t\tline(\n\t\t\t`Run \\`fabric instructions sync --project ${opts.project}\\` to apply.`,\n\t\t);\n\t\treturn;\n\t}\n\n\tconst { added, changed, removed } = published.changes;\n\tline(\n\t\t`Coding instructions updated: ${added.length} added, ${changed.length} changed, ${removed.length} removed (version ${version}).`,\n\t);\n\tlistPaths(\"added\", added);\n\tlistPaths(\"changed\", changed);\n\tlistPaths(\"removed\", removed);\n\tline(\n\t\t`Run \\`fabric instructions sync --project ${opts.project}\\` to apply.`,\n\t);\n}\n\n/**\n * The one extra line `check`'s text report adds for a repository-published\n * snapshot; nothing is added for `UPLOAD` (Fizzy #2709). The commit sha is\n * truncated to the same 12 characters this CLI already uses for a digest\n * prefix, with the same `…` marking it as shortened.\n *\n * `repository` is the project's CURRENT sync configuration, not necessarily\n * the one this particular snapshot published from — it is shown only when\n * `source.current` says this snapshot still matches it; otherwise the line\n * says so instead of naming a repository that may no longer apply.\n */\nfunction describeRepositorySource(\n\tsource: Extract<PublishedInstructionSource, { kind: \"REPOSITORY\" }>,\n\trepository: PublishedInstructionRepository | null,\n): string {\n\tconst commit = `${source.commitSha.slice(0, 12)}…`;\n\tconst base = `published from ${commit} on ${source.ref}`;\n\tif (!source.current) {\n\t\treturn `${base} (not the project's current sync configuration)`;\n\t}\n\treturn repository ? `${base} (${repository.path})` : base;\n}\n\n/** What `--verify` found, in the two places the report can end. */\nfunction reportDrift(\n\topts: CommonOptions,\n\tdestination: string,\n\tdrift: LedgerDrift[],\n): void {\n\tif (drift.length === 0) {\n\t\tline(`Every file in ${destination} matches the lock.`);\n\t\treturn;\n\t}\n\tline(`${drift.length} local file(s) no longer match the lock:`);\n\tlistPaths(\"drifted\", drift.map(describeLedgerDrift));\n\t// Spec §6.4: `sync` puts back what is missing or chmod-ed, and keeps an\n\t// edit unless it is given `--repair`.\n\tconst edits = drift.filter((entry) => entry.reason === \"edited\").length;\n\tif (edits < drift.length) {\n\t\tline(\n\t\t\t`Run \\`fabric instructions sync --project ${opts.project}\\` to put ${edits === 0 ? \"them\" : \"the others\"} back.`,\n\t\t);\n\t}\n\tif (edits > 0) {\n\t\tline(\n\t\t\t`Sync keeps local edits. Run ${repairInstruction(opts)} to replace them with the published version.`,\n\t\t);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// doctor\n// ---------------------------------------------------------------------------\n\n/**\n * Nine checks, one report, exit 1 when any of them fails.\n *\n * Informational like `check`: nothing is written, the destination is not\n * created, and every failure inside a check becomes that check's verdict\n * rather than an exception — so a missing key produces a report whose `auth`\n * check fails, not a stack trace. The only thrown failure is the one that\n * turns \"a check failed\" into exit code 1, AFTER the report is printed.\n *\n * The same context-free clients `check` and `sync` use: an ambient\n * `FABRIC_ORG` must not turn a project the key can read into a refusal.\n */\nasync function runDoctorCommand(\n\topts: CommonOptions & { probeNetwork?: boolean },\n\tformat: OutputFormat,\n): Promise<void> {\n\tconst destination = destinationOf(opts);\n\tconst root = await resolveExistingRoot(destination);\n\tconst report = await runDoctor({\n\t\tprojectId: opts.project,\n\t\torg: orgSlugFor(opts),\n\t\tdestination,\n\t\troot,\n\t\tcommandDest: opts.dest === undefined ? undefined : destination,\n\t\tprobeNetwork: Boolean(opts.probeNetwork),\n\t\tenv: process.env,\n\t\tplatform: process.platform,\n\t\tapiKeyPresent: Boolean(getApiKey()),\n\t\tclient: () => instructionsClient({ hook: false }, CHECK_TIMEOUT_MS),\n\t\tcreateDownloadUrl: (projectId, options) =>\n\t\t\tdownloadUrlClient({ hook: false }).instructions.createDownloadUrl(\n\t\t\t\tprojectId,\n\t\t\t\toptions,\n\t\t\t),\n\t\tfetchArchive: (url, maxBytes) =>\n\t\t\tfetchBundle(url, { timeoutMs: BUNDLE_TIMEOUT_MS, maxBytes }),\n\t});\n\n\tif (format === \"json\") {\n\t\tprintOutput(report, { format: \"json\" });\n\t} else {\n\t\tprocess.stdout.write(formatDoctorText(report, destination));\n\t}\n\n\tif (!report.ok) {\n\t\tthrow new CliFailure(\n\t\t\t`${report.summary.fail} check${report.summary.fail === 1 ? \"\" : \"s\"} failed; the report above lists a proposed fix for each`,\n\t\t\t1,\n\t\t);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// sync\n// ---------------------------------------------------------------------------\n\nasync function runSync(\n\topts: CommonOptions & { dryRun?: boolean; repair?: boolean },\n\tformat: OutputFormat,\n): Promise<void> {\n\tconst synced = await syncOnce(opts);\n\tif (synced.kind === \"reported\") {\n\t\t// A checkout of the repository (Fizzy #2708): the files arrive with\n\t\t// git, so this reports and writes nothing. `--dry-run` and `--repair`\n\t\t// describe a download, and there is none to shape.\n\t\tif (format === \"json\") {\n\t\t\tprintOutput(\n\t\t\t\t{\n\t\t\t\t\tprojectId: opts.project,\n\t\t\t\t\tdestination: synced.destination,\n\t\t\t\t\tpublished: synced.published,\n\t\t\t\t\treportOnly: true,\n\t\t\t\t\tversion: synced.version,\n\t\t\t\t\tcheckout: synced.checkout,\n\t\t\t\t},\n\t\t\t\t{ format: \"json\" },\n\t\t\t);\n\t\t} else if (synced.checkout.line !== null) {\n\t\t\tline(synced.checkout.line);\n\t\t} else if (!opts.hook && synced.current !== null) {\n\t\t\t// The hook's silence means \"current\"; a person gets it in words.\n\t\t\tline(synced.current);\n\t\t}\n\t\treturn;\n\t}\n\tconst result = synced.outcome;\n\tif (format === \"json\") {\n\t\tprintOutput(result, { format: \"json\" });\n\t} else {\n\t\treportSync(result, opts);\n\t}\n\t// Spec §6.4: a session start must not bury the one thing the developer\n\t// needs to know, that their edits were kept rather than replaced. One\n\t// line on stderr, the channel the hook boundary already uses.\n\tif (opts.hook && result.keptEdited.length > 0) {\n\t\tprocess.stderr.write(\n\t\t\t`fabric: ${result.keptEdited.length} local edit(s) kept; run ${repairInstruction(opts)} to replace them. Keep notes meant only for this machine in CLAUDE.local.md or .claude/settings.local.json.\\n`,\n\t\t);\n\t}\n}\n\ninterface SyncOutcome {\n\tprojectId: string;\n\tdestination: string;\n\tpublished: boolean;\n\tunchanged: boolean;\n\tdryRun: boolean;\n\tversion: number | null;\n\tdigest: string | null;\n\tadded: string[];\n\tupdated: string[];\n\treplaced: string[];\n\tremoved: string[];\n\tkeptModified: string[];\n\t/**\n\t * Paths the lock still names under an old spelling that the manifest now\n\t * spells differently. Reported rather than removed: on a case-insensitive\n\t * filesystem they ARE the file the sync just wrote.\n\t */\n\tkeptRenamed: string[];\n\t/**\n\t * Paths the lock claimed that the working tree no longer matched, when the\n\t * published snapshot itself had not moved. Non-empty means this run\n\t * repaired local drift rather than applying a new version.\n\t */\n\tdrifted: string[];\n\t/**\n\t * Still-published paths whose local edits this run left in place (spec\n\t * §6.4). Always empty under `--repair`, which reports them as `replaced`.\n\t */\n\tkeptEdited: string[];\n\tverified: number;\n\tlockPath: string;\n}\n\nfunction emptyOutcome(\n\topts: CommonOptions & { dryRun?: boolean },\n\tdestination: string,\n): SyncOutcome {\n\treturn {\n\t\tprojectId: opts.project,\n\t\tdestination,\n\t\tpublished: true,\n\t\tunchanged: false,\n\t\tdryRun: Boolean(opts.dryRun),\n\t\tversion: null,\n\t\tdigest: null,\n\t\tadded: [],\n\t\tupdated: [],\n\t\treplaced: [],\n\t\tremoved: [],\n\t\tkeptModified: [],\n\t\tkeptRenamed: [],\n\t\tdrifted: [],\n\t\tkeptEdited: [],\n\t\tverified: 0,\n\t\tlockPath: lockPath(destination),\n\t};\n}\n\n/**\n * What `syncOnce` did: applied the published snapshot, or — in a checkout of\n * a repository-sourced project's repository, or under a hook anywhere that\n * might be one — only reported, writing nothing (Fizzy #2708).\n */\ntype SyncResult =\n\t| { kind: \"synced\"; outcome: SyncOutcome }\n\t| {\n\t\t\tkind: \"reported\";\n\t\t\tdestination: string;\n\t\t\tpublished: boolean;\n\t\t\tversion: number | null;\n\t\t\tcheckout: CheckoutJson;\n\t\t\t/** A manual run's words for \"already current\"; the hook says nothing. */\n\t\t\tcurrent: string | null;\n\t };\n\nasync function syncOnce(\n\topts: CommonOptions & {\n\t\tdryRun?: boolean;\n\t\trepair?: boolean;\n\t\t/**\n\t\t * `init`'s guard, already holding the response it classified the\n\t\t * checkout from, so this sync's own responses are held to it.\n\t\t */\n\t\tguard?: SourceGuard;\n\t},\n): Promise<SyncResult> {\n\tconst destination = destinationOf(opts);\n\t// Canonical, but not created yet: a run that only reports must not make\n\t// a directory. The lock is read from the same canonical path the writes\n\t// below resolve against.\n\tconst existing = await resolveExistingRoot(destination);\n\t// Spec §6.4: a local edit to a synced file is the developer's, and only\n\t// `--repair` replaces it. `init`'s first sync keeps too: it never passes\n\t// `repair`.\n\tconst keepLocalEdits = !opts.repair;\n\n\tconst client = instructionsClient(opts, SYNC_TIMEOUT_MS);\n\tconst guard = opts.guard ?? new SourceGuard(destination);\n\tconst hint = await lockDigestHint(existing, opts.project);\n\tlet published = await fetchPublished(client, opts, hint, guard);\n\n\tif (guard.checkout !== null && !downloadsIn(guard.checkout, !opts.hook)) {\n\t\tconst refused = opts.hook\n\t\t\t? null\n\t\t\t: refuseManualSync(guard.checkout, published.repository);\n\t\tif (refused !== null) {\n\t\t\tthrow refused;\n\t\t}\n\t\tconst report = await reportForClassification({\n\t\t\tclassification: guard.checkout,\n\t\t\trepository: published.repository,\n\t\t\tsnapshot: published.snapshot,\n\t\t\tdeadline: gitDeadline(),\n\t\t});\n\t\treturn {\n\t\t\tkind: \"reported\",\n\t\t\tdestination: existing,\n\t\t\tpublished: published.published,\n\t\t\tversion: published.snapshot?.version ?? null,\n\t\t\tcheckout: report.json,\n\t\t\tcurrent:\n\t\t\t\treport.line === null &&\n\t\t\t\tpublished.repository &&\n\t\t\t\tpublished.snapshot\n\t\t\t\t\t? currentLine(published.repository, published.snapshot)\n\t\t\t\t\t: null,\n\t\t};\n\t}\n\n\tlet lock: InstructionsLock | null;\n\t({ lock, published } = await validatedLock(\n\t\tclient,\n\t\topts,\n\t\texisting,\n\t\tguard,\n\t\thint,\n\t\tpublished,\n\t));\n\n\t// Canonical from here on: every write resolves against this, so a\n\t// symlinked `--dest` (or `/tmp` on macOS) is decided once rather than at\n\t// each write.\n\tconst root = await resolveDestinationRoot(destination);\n\tconst outcome = emptyOutcome(opts, root);\n\n\tif (!published.published || !published.snapshot) {\n\t\t// A real failure for a person who asked for a copy; the `--hook`\n\t\t// boundary turns it into one quiet line for a session start.\n\t\tthrow new CliFailure(\n\t\t\t\"This project has no published coding instructions yet.\",\n\t\t\t4,\n\t\t);\n\t}\n\n\toutcome.version = published.snapshot.version;\n\toutcome.digest = published.snapshot.digest;\n\n\tif (published.unchanged) {\n\t\t// \"Unchanged\" is the SERVER's answer about the SNAPSHOT, and it says\n\t\t// nothing about the checkout. Accepting it as \"nothing to do\" let an\n\t\t// edited, deleted or chmod-ed instruction file stay that way until\n\t\t// some later publication happened to move the digest — so a tampered\n\t\t// tree reported success indefinitely. The ledger is the local half of\n\t\t// the question, and hashing it is the price of a command that applies\n\t\t// things.\n\t\tconst drift =\n\t\t\tlock === null ? [] : await findLedgerDrift({ root, lock });\n\t\tconst edits = drift.filter((entry) => entry.reason === \"edited\");\n\t\t// Spec §6.4: without `--repair` an edit is kept, so a tree whose only\n\t\t// differences are edits needs no manifest and no download. Recording\n\t\t// the keep in the lock is what lets `check --verify` and doctor say so.\n\t\tif (\n\t\t\tdrift.length === 0 ||\n\t\t\t(keepLocalEdits && edits.length === drift.length)\n\t\t) {\n\t\t\toutcome.unchanged = true;\n\t\t\toutcome.keptEdited = edits.map((entry) => entry.path);\n\t\t\tif (lock !== null && !opts.dryRun) {\n\t\t\t\t// Decision 41: mark what is kept now, and drop a marker whose\n\t\t\t\t// file was put back by hand, so the lock says what is true. A\n\t\t\t\t// run that finds the same edits again writes nothing.\n\t\t\t\tconst reconciled = reconcileKeptInLock(\n\t\t\t\t\tlock,\n\t\t\t\t\toutcome.keptEdited,\n\t\t\t\t);\n\t\t\t\tif (reconciled.changed) {\n\t\t\t\t\tawait writeLock(root, reconciled.lock);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { kind: \"synced\", outcome };\n\t\t}\n\n\t\toutcome.drifted = drift.map(describeLedgerDrift);\n\t\t// The first call answered with a delta and therefore carries no\n\t\t// manifest. Ask again without a base digest: the plan needs the whole\n\t\t// published list to put the tree back.\n\t\tpublished = await fetchPublished(client, opts, undefined, guard);\n\t\tif (!published.published || !published.snapshot) {\n\t\t\tthrow new CliFailure(\n\t\t\t\t\"This project has no published coding instructions yet.\",\n\t\t\t\t4,\n\t\t\t);\n\t\t}\n\t\toutcome.version = published.snapshot.version;\n\t\toutcome.digest = published.snapshot.digest;\n\t}\n\n\t// An absent manifest is a refusal, never an empty one. `[]` means\n\t// \"delete everything the lock names\", so a version-skewed or truncated\n\t// response was one step from emptying the tree and writing a ledger that\n\t// agreed with it.\n\tconst manifest = assertValidManifest({\n\t\tmanifest: published.manifest,\n\t\tsnapshot: published.snapshot,\n\t});\n\n\tconst plan = await computeSyncPlan(\n\t\t{ destination: root, manifest, lock },\n\t\t{ keepLocalEdits },\n\t);\n\tfillPlanPaths(outcome, plan);\n\n\tif (opts.dryRun) {\n\t\t// The plan is computable from the manifest alone, so a dry run\n\t\t// downloads nothing at all.\n\t\treturn { kind: \"synced\", outcome };\n\t}\n\n\tlet contents = new Map<string, Uint8Array>();\n\tif (plan.writes.length > 0) {\n\t\tconst org = orgSlugFor(opts);\n\t\tlet download: { url: string };\n\t\ttry {\n\t\t\tdownload = await downloadUrlClient(\n\t\t\t\topts,\n\t\t\t).instructions.createDownloadUrl(opts.project, { org });\n\t\t} catch (error) {\n\t\t\tthrow asCliFailure(error);\n\t\t}\n\t\tconst sizes = new Map(\n\t\t\tmanifest.map((entry) => [entry.path, entry.size] as const),\n\t\t);\n\t\tconst archive = await fetchBundle(download.url, {\n\t\t\ttimeoutMs: opts.hook ? hookDeadlineMs() : BUNDLE_TIMEOUT_MS,\n\t\t\t// Bounded by what this manifest says it holds, not by what the\n\t\t\t// response claims. The manifest has already been checked against\n\t\t\t// the published snapshot limits, so this is a number the client\n\t\t\t// decided.\n\t\t\tmaxBytes: maxArchiveBytes(manifest),\n\t\t\t// In hook mode the same clock that bounds the command bounds the\n\t\t\t// download, rather than a second independent budget after it.\n\t\t\tsignal: activeDeadline,\n\t\t});\n\t\tcontents = extractBundle(\n\t\t\tarchive,\n\t\t\tplan.writes.map((entry) => ({\n\t\t\t\tpath: entry.path,\n\t\t\t\tsize: sizes.get(entry.path) ?? -1,\n\t\t\t})),\n\t\t);\n\t}\n\n\tconst applied = await applyPlan({ root, plan, contents, keepLocalEdits });\n\t// What actually happened, not what was planned: a delete whose file was\n\t// edited between planning and the unlink is reported as kept, because that\n\t// is what it is. So is a write whose file was saved after planning\n\t// (Decision 37): it is a kept edit, not an add or an update.\n\toutcome.removed = applied.deleted;\n\tif (applied.keptEdited.length > 0) {\n\t\tconst late = new Set(applied.keptEdited);\n\t\toutcome.added = outcome.added.filter((p) => !late.has(p));\n\t\toutcome.updated = outcome.updated.filter((p) => !late.has(p));\n\t\toutcome.keptEdited = [\n\t\t\t...outcome.keptEdited,\n\t\t\t...applied.keptEdited,\n\t\t].sort();\n\t}\n\toutcome.keptModified = [\n\t\t...outcome.keptModified,\n\t\t...applied.keptModified,\n\t].sort();\n\n\t// Last, and only now: a lock written before the files would claim\n\t// ownership of paths that are not there, and the next run would delete\n\t// whatever the developer had in their place.\n\tconst lockToWrite: InstructionsLock = nextLock({\n\t\tprojectId: opts.project,\n\t\tsnapshot: {\n\t\t\tid: published.snapshot.id,\n\t\t\tversion: published.snapshot.version,\n\t\t\tdigest: published.snapshot.digest,\n\t\t\tsource: published.snapshot.source,\n\t\t},\n\t\tmanifest,\n\t\t// Published hash plus `kept: true`: `push` diffs the edit against the\n\t\t// version everyone else has, and the next run still knows it was kept.\n\t\tkept: outcome.keptEdited,\n\t});\n\tawait writeLock(root, lockToWrite);\n\n\treturn { kind: \"synced\", outcome };\n}\n\nfunction fillPlanPaths(outcome: SyncOutcome, plan: SyncPlan): void {\n\toutcome.added = plan.entries\n\t\t.filter((entry) => entry.action === \"added\")\n\t\t.map((entry) => entry.path);\n\toutcome.updated = plan.entries\n\t\t.filter((entry) => entry.action === \"updated\")\n\t\t.map((entry) => entry.path);\n\toutcome.replaced = plan.entries\n\t\t.filter((entry) => entry.action === \"replaced\")\n\t\t.map((entry) => entry.path);\n\toutcome.removed = plan.deletes.map((entry) => entry.path);\n\toutcome.keptModified = plan.keptModified.map((entry) => entry.path);\n\toutcome.keptRenamed = plan.keptRenamed.map((entry) => entry.path);\n\toutcome.keptEdited = plan.keptEdited.map((entry) => entry.path);\n\toutcome.verified = plan.verified.length;\n}\n\nfunction reportSync(\n\toutcome: SyncOutcome,\n\topts: CommonOptions & { dryRun?: boolean },\n): void {\n\tif (outcome.unchanged) {\n\t\tline(\n\t\t\t`Coding instructions are up to date (version ${outcome.version}).`,\n\t\t);\n\t\treportKeptEdits(outcome, opts);\n\t\treturn;\n\t}\n\n\tconst total =\n\t\toutcome.added.length +\n\t\toutcome.updated.length +\n\t\toutcome.replaced.length +\n\t\toutcome.removed.length;\n\tif (outcome.drifted.length > 0) {\n\t\tline(\n\t\t\t`Coding instructions version ${outcome.version} is still the published one, but ${outcome.drifted.length} local file(s) no longer match it:`,\n\t\t);\n\t\tlistPaths(\"drifted\", outcome.drifted);\n\t}\n\n\tconst prefix = opts.dryRun ? \"Would apply\" : \"Applied\";\n\tline(\n\t\t`${prefix} coding instructions version ${outcome.version}: ${outcome.added.length} added, ${outcome.updated.length} updated, ${outcome.replaced.length} replaced, ${outcome.removed.length} removed (${outcome.verified} already current).`,\n\t);\n\tlistPaths(\"added\", outcome.added);\n\tlistPaths(\"updated\", outcome.updated);\n\tlistPaths(\"replaced local edits\", outcome.replaced);\n\tlistPaths(\"removed\", outcome.removed);\n\tlistPaths(\"kept, modified locally\", outcome.keptModified);\n\tlistPaths(\"kept, renamed in the published snapshot\", outcome.keptRenamed);\n\tif (!opts.dryRun) {\n\t\tline(`Lock: ${outcome.lockPath}`);\n\t}\n\tif (\n\t\ttotal === 0 &&\n\t\toutcome.keptModified.length === 0 &&\n\t\toutcome.keptRenamed.length === 0 &&\n\t\toutcome.keptEdited.length === 0\n\t) {\n\t\tline(`Everything in ${outcome.destination} already matched.`);\n\t}\n\treportKeptEdits(outcome, opts);\n}\n\n/**\n * Spec §6.4: what was kept, the command that replaces it, and where notes\n * meant only for this machine belong.\n */\nfunction reportKeptEdits(outcome: SyncOutcome, opts: CommonOptions): void {\n\tif (outcome.keptEdited.length === 0) {\n\t\treturn;\n\t}\n\tlistPaths(\"kept local edits\", outcome.keptEdited);\n\tline(\n\t\t`Sync keeps local edits to synced files. Run ${repairInstruction(opts)} to replace them with the published version. Keep notes meant only for this machine in CLAUDE.local.md or .claude/settings.local.json instead.`,\n\t);\n}\n\n/**\n * The command that replaces kept edits. It carries the `--org` and the\n * resolved `--dest` this run was given, so a pasted copy acts on the same\n * project, context and checkout: the rule doctor's generated fixes follow,\n * through the same guarded builder (Decision 42). `undefined` when a word\n * cannot be pasted safely, such as a `--dest` holding a newline.\n */\nfunction repairCommand(opts: CommonOptions): string | undefined {\n\treturn buildFabricCommand([\n\t\t\"instructions\",\n\t\t\"sync\",\n\t\t\"--project\",\n\t\topts.project,\n\t\t...(opts.org !== undefined ? [\"--org\", opts.org] : []),\n\t\t...(opts.dest !== undefined ? [\"--dest\", destinationOf(opts)] : []),\n\t\t\"--repair\",\n\t]);\n}\n\n/** The repair command in backticks, or what to run when none can be printed. */\nfunction repairInstruction(opts: CommonOptions): string {\n\tconst command = repairCommand(opts);\n\treturn command !== undefined\n\t\t? `\\`${command}\\``\n\t\t: \"`fabric instructions sync --repair` with this run's --project and --dest\";\n}\n\n// ---------------------------------------------------------------------------\n// push\n// ---------------------------------------------------------------------------\n\ninterface PushOutcome {\n\tprojectId: string;\n\tdestination: string;\n\tdryRun: boolean;\n\t/** `--publish`: what this push ASKED for, known before anything is sent. */\n\tpublish: boolean;\n\t/** The snapshot the change set was stated against — the lock's. */\n\tbaseSnapshotId: string;\n\tbaseVersion: number;\n\tput: string[];\n\tdeleted: string[];\n\tunchanged: number;\n\t/**\n\t * Changes left out because one of the caller's open proposals already\n\t * carries them (Fizzy #2739), each with the newest proposal that does.\n\t */\n\talreadyProposed: Array<{\n\t\tpath: string;\n\t\taction: \"put\" | \"delete\";\n\t\tsnapshotId: string;\n\t\tversion: number;\n\t\tpullRequestState: string | null;\n\t\tpullRequestUrl: string | null;\n\t}>;\n\t/**\n\t * Whether open proposals were checked: `skipped` under\n\t * `--include-proposed`, `unavailable` (with the reason) when the lookup\n\t * failed and every change was sent.\n\t */\n\topenProposalCheck: {\n\t\tstate: \"checked\" | \"skipped\" | \"unavailable\";\n\t\treason: string | null;\n\t};\n\t/** Null on a dry run; otherwise what the server made of it. */\n\tsnapshotId: string | null;\n\tversion: number | null;\n\tproposalStatus: string | null;\n\tstatus: string | null;\n\t/**\n\t * Whether this version has been observed published at least once. Null on\n\t * a dry run. `status === \"READY\"` does NOT imply this — see the SDK's\n\t * `SubmittedInstructionChange.published` doc — so `pushVerdict` reads this\n\t * field rather than inferring publication from `status`. `false` means\n\t * \"not yet confirmed\", never \"refused\": a publish this call started can\n\t * still land after the command has already returned.\n\t */\n\tpublished: boolean | null;\n\t/**\n\t * A repository-backed project's suggestion becomes a pull request in the\n\t * repository (Fizzy #2563 spec §12): where it stood when the command\n\t * stopped waiting. `timedOut` means the 60 s wait ended first. Null for a\n\t * suggestion Fabric reviews itself, a publish and a dry run.\n\t *\n\t * `branch` and `append` are the member branch the suggestion is added to\n\t * and what adding it did (Fizzy #2738 spec §10), null for a suggestion\n\t * not on one or from a server that predates member branches. `url` is\n\t * the branch's pull request once it has one.\n\t */\n\tpullRequest: {\n\t\toperationId: string;\n\t\tstate: string;\n\t\turl: string | null;\n\t\tfailure: ProposalPullRequestFailure | null;\n\t\ttimedOut: boolean;\n\t\tbranch: ProposalBranch | null;\n\t\tappend: ProposalAppend | null;\n\t} | null;\n}\n\n/**\n * Suggest the checkout's edits back to the project, or publish them.\n *\n * Without `--publish` it opens a PROPOSAL, which is what the key the Connect\n * dialog mints can do: that key carries `instructions:write`, a scope offered\n * to read-only roles and described as review-gated.\n *\n * `--publish` is a DIFFERENT authority, not a mode of the same one. It calls a\n * different route, gated on `instructions:publish` — a scope the Connect\n * dialog never mints, that a read-only role cannot be granted, and that has to\n * be put on a key deliberately in the organization's API-key settings. The\n * server then re-checks, on that call, that the key's creator still holds the\n * permission the Coding Instructions tab requires to publish. Both halves are\n * needed: neither the flag nor the scope alone publishes anything.\n *\n * Everything else is identical in both modes — the same local diff, the same\n * lock rules, the same `PULL_FIRST` refusal for a stale base — because a\n * publish is a fast-forward on the published pointer just as a proposal is a\n * claim on it.\n *\n * The diff is computed against `.fabric/instructions.lock` — the snapshot the\n * last sync applied — and that snapshot id is sent as the base. A push whose\n * base is no longer the published version is REFUSED rather than rebased: the\n * spec's `PULL_FIRST` rule (§6.12), and the reason there is no server-side\n * merge in any version.\n *\n * The published manifest is fetched FIRST, and it decides two things before a\n * file is opened: whether the lock still names the published version, and\n * whether the lock's ledger is that version. The lock is a plain JSON file in\n * the checkout, so anything that can write to the working tree can add a path\n * to it — and a command that read its ledger on trust would read and upload\n * whatever was added. See `computePushPlan`.\n *\n * A change one of the caller's OPEN proposals already carries — same path,\n * same bytes — is left out and reported (Fizzy #2739): the lock names the\n * published version, which a proposal does not move, so without this a\n * second session on the same checkout re-sent the first one's change.\n * `--publish` follows the same rule: publishing a change that is waiting for\n * review would skip that review, under this push's name. `--include-proposed`\n * sends everything, as before. When the lookup is unavailable everything is\n * sent with a warning; see `lib/instructions/open-proposals.ts`.\n *\n * The lock is NOT rewritten, on any outcome, `--publish` included. A proposal\n * changes nothing about what is published, so a lock claiming otherwise would\n * make the next `sync` believe this checkout already held a version nobody has\n * approved. A publish changes it only once the server's validation run passes,\n * which is after this command has returned — and what it publishes is the\n * SERVER's manifest, inherited files and all, not the local tree. Writing a\n * lock for a version that may never exist, from a file list this side cannot\n * compute, would be a guess; `fabric instructions sync` is how the checkout\n * catches up, and it is what the command says to run.\n */\nasync function runPush(\n\topts: CommonOptions & {\n\t\tadd?: string[];\n\t\tpublish?: boolean;\n\t\tmessage?: string;\n\t\twait?: boolean;\n\t\tincludeProposed?: boolean;\n\t\tdryRun?: boolean;\n\t},\n\tformat: OutputFormat,\n): Promise<void> {\n\t// A usage error, decided before anything is read: a publish makes a\n\t// version with nobody to review it, so it has no title or description to\n\t// carry, and dropping the message silently would lose what was written.\n\tif (opts.message !== undefined && opts.publish) {\n\t\tthrow new CliFailure(\n\t\t\t\"--message describes a suggestion for review; --publish makes a version directly, which carries no message. Drop one of them.\",\n\t\t\t2,\n\t\t);\n\t}\n\tconst note =\n\t\topts.message !== undefined ? splitMessage(opts.message) : undefined;\n\n\t// Canonical but NOT created: push reads the tree, and a command that makes\n\t// a directory in order to discover it is empty is doing the wrong thing.\n\tconst destination = destinationOf(opts);\n\tconst root = await resolveExistingRoot(destination);\n\tconst lock = await readLockForProject(root, opts.project);\n\tif (lock === null) {\n\t\tthrow new CliFailure(\n\t\t\t`No coding-instructions lock in ${destination}. Run \\`fabric instructions sync --project ${opts.project}\\` first: a push is a diff against the version that was last applied here, and without that ledger there is nothing to diff against.`,\n\t\t\t7,\n\t\t);\n\t}\n\n\t// The SDK's ordinary retry policy. Retries used to be off here: the change\n\t// route wrote a snapshot row per POST, so a push whose response was lost\n\t// opened a second proposal for one edit. The route now recognises a change\n\t// set it has already admitted and answers with the proposal it opened, so\n\t// a retry repairs a dropped response instead of duplicating it.\n\tconst client = instructionsClient(\n\t\t{ ...opts, hook: false },\n\t\tPUSH_TIMEOUT_MS,\n\t);\n\n\t// BEFORE any file is read. Two questions, both answered by this one call:\n\t// is the lock still the published version, and is its ledger actually\n\t// that version's manifest.\n\tconst published = await fetchPublished(client, opts);\n\tif (!published.published || !published.snapshot) {\n\t\tthrow new CliFailure(\n\t\t\t\"this project has no published coding instructions to change yet; the first version is uploaded from the Coding Instructions tab\",\n\t\t\t4,\n\t\t);\n\t}\n\tif (published.snapshot.id !== lock.snapshotId) {\n\t\t// Exactly what the server would answer, decided locally so nothing is\n\t\t// read or sent first.\n\t\tthrow new CliFailure(\n\t\t\t\"published instructions moved past your last sync; run `fabric instructions sync` then push again\",\n\t\t\t7,\n\t\t);\n\t}\n\n\tconst computed = await computePushPlan({\n\t\troot,\n\t\tlock,\n\t\tmanifest: published.manifest ?? [],\n\t\tadded: opts.add,\n\t});\n\n\tif (computed.changes.length === 0) {\n\t\tthrow new CliFailure(\n\t\t\t`Nothing to push: every file the last sync wrote still matches version ${lock.snapshotVersion}. Add a new file with --add <path> if you meant to suggest one.`,\n\t\t\t7,\n\t\t);\n\t}\n\n\t// What the caller's open proposals already carry is left out (Fizzy\n\t// #2739). Asked only once there is something to send, and never under\n\t// --include-proposed, which sends everything exactly as before.\n\tlet plan = computed;\n\tlet alreadyProposed: AlreadyProposed[] = [];\n\tlet openProposalCheck: PushOutcome[\"openProposalCheck\"] = {\n\t\tstate: \"skipped\",\n\t\treason: null,\n\t};\n\tif (!opts.includeProposed) {\n\t\tconst lookup = await lookUpOpenProposals(client, opts.project, {\n\t\t\torg: orgSlugFor(opts),\n\t\t});\n\t\tif (lookup.kind === \"found\") {\n\t\t\t({ plan, alreadyProposed } = setAsideProposed(\n\t\t\t\tcomputed,\n\t\t\t\tlookup.proposals,\n\t\t\t\tlock.snapshotId,\n\t\t\t));\n\t\t\topenProposalCheck = { state: \"checked\", reason: null };\n\t\t} else {\n\t\t\topenProposalCheck = { state: \"unavailable\", reason: lookup.reason };\n\t\t\tprocess.stderr.write(\n\t\t\t\t`Could not check your open proposals (${lookup.reason}), so nothing was left out: a change one of them already carries ${opts.dryRun ? \"would be\" : \"is\"} sent again.\\n`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (plan.changes.length > MAX_PUSH_CHANGES) {\n\t\tthrow new CliFailure(\n\t\t\t`Too many changes to push (${plan.changes.length} > ${MAX_PUSH_CHANGES}). A change set this large is a replacement rather than an edit — upload the folder from the project's Coding Instructions tab, which is also the only path that re-reads the project's exclusion rules.`,\n\t\t\t7,\n\t\t);\n\t}\n\n\tconst outcome: PushOutcome = {\n\t\tprojectId: opts.project,\n\t\tdestination: root,\n\t\tdryRun: Boolean(opts.dryRun),\n\t\tpublish: Boolean(opts.publish),\n\t\tbaseSnapshotId: lock.snapshotId,\n\t\tbaseVersion: lock.snapshotVersion,\n\t\tput: plan.entries\n\t\t\t.filter((entry) => entry.action === \"put\")\n\t\t\t.map((entry) => entry.path),\n\t\tdeleted: plan.entries\n\t\t\t.filter((entry) => entry.action === \"delete\")\n\t\t\t.map((entry) => entry.path),\n\t\tunchanged: plan.unchanged.length,\n\t\talreadyProposed: alreadyProposed.map((entry) => ({\n\t\t\tpath: entry.path,\n\t\t\taction: entry.action,\n\t\t\tsnapshotId: entry.proposal.snapshotId,\n\t\t\tversion: entry.proposal.version,\n\t\t\tpullRequestState: entry.proposal.pullRequest?.state ?? null,\n\t\t\tpullRequestUrl: entry.proposal.pullRequest?.url ?? null,\n\t\t})),\n\t\topenProposalCheck,\n\t\tsnapshotId: null,\n\t\tversion: null,\n\t\tproposalStatus: null,\n\t\tstatus: null,\n\t\tpublished: null,\n\t\tpullRequest: null,\n\t};\n\n\t// Everything left was already proposed. For a proposal that is the state\n\t// the developer wanted, and what repeating an identical push used to\n\t// answer, so it is reported and exits 0; a publish has not done what it\n\t// was asked, as \"Nothing to push\" has not, and exits 7 — after printing\n\t// the outcome under --format json, so a script still gets\n\t// `alreadyProposed` and `openProposalCheck` saying why.\n\tif (plan.changes.length === 0 && opts.publish) {\n\t\tif (format === \"json\") {\n\t\t\tprintOutput(outcome, { format: \"json\" });\n\t\t}\n\t\tthrow new CliFailure(\n\t\t\t`Nothing new to publish: every change here is already in an open proposal of yours (${proposalReferences(alreadyProposed)}), and publishing it from here would skip that proposal's review. Add --include-proposed to publish it anyway; nothing was sent.`,\n\t\t\t7,\n\t\t);\n\t}\n\n\t// Whether this push saw its member branch before the branch had a pull\n\t// request: then the pull request it ends on was opened for it, rather\n\t// than an existing one it was added to (spec §10's \"Opened pull request\"\n\t// against \"Added to your pull request\").\n\tlet sawBranchWithoutPullRequest = false;\n\tconst noteBranch = (pullRequest: ProposalPullRequest) => {\n\t\tif (pullRequest.branch && pullRequest.branch.pullRequest === null) {\n\t\t\tsawBranchWithoutPullRequest = true;\n\t\t}\n\t};\n\n\tif (!opts.dryRun && plan.changes.length > 0) {\n\t\ttry {\n\t\t\t// Two methods, not one method with a flag: they are two routes\n\t\t\t// behind two scopes, and choosing between them here is what makes\n\t\t\t// a key that cannot publish fail with a scope refusal rather than\n\t\t\t// quietly proposing instead.\n\t\t\tconst submitted = opts.publish\n\t\t\t\t? await client.instructions.publishChange(\n\t\t\t\t\t\topts.project,\n\t\t\t\t\t\tlock.snapshotId,\n\t\t\t\t\t\tplan.changes,\n\t\t\t\t\t\t{ org: orgSlugFor(opts) },\n\t\t\t\t\t)\n\t\t\t\t: await client.instructions.submitChange(\n\t\t\t\t\t\topts.project,\n\t\t\t\t\t\tlock.snapshotId,\n\t\t\t\t\t\tplan.changes,\n\t\t\t\t\t\t{ org: orgSlugFor(opts), ...(note ? { note } : {}) },\n\t\t\t\t\t);\n\t\t\toutcome.snapshotId = submitted.snapshotId;\n\t\t\toutcome.version = submitted.version;\n\t\t\toutcome.proposalStatus = submitted.proposalStatus;\n\t\t\toutcome.status = submitted.status;\n\t\t\toutcome.published = submitted.published;\n\t\t\toutcome.pullRequest = submitted.pullRequest\n\t\t\t\t? pushPullRequest(submitted.pullRequest, false)\n\t\t\t\t: null;\n\t\t\tif (submitted.pullRequest) {\n\t\t\t\tnoteBranch(submitted.pullRequest);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthrow asPushFailure(error);\n\t\t}\n\t}\n\n\t// The suggestion is accepted; for a repository-backed project it becomes\n\t// a pull request once its files pass their checks, and the push waits a\n\t// bounded while to say where it stands (spec §12). A failure to READ the\n\t// status does not undo the suggestion, so it is reported as that.\n\tif (outcome.pullRequest && outcome.snapshotId && opts.wait !== false) {\n\t\tlet waited: PullRequestWait;\n\t\ttry {\n\t\t\twaited = await waitForPullRequest(\n\t\t\t\tclient,\n\t\t\t\topts.project,\n\t\t\t\toutcome.snapshotId,\n\t\t\t\t{ org: orgSlugFor(opts), observe: noteBranch },\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst failure = asCliFailure(error);\n\t\t\tthrow new CliFailure(\n\t\t\t\t`Suggested as version ${outcome.version}, but its pull request could not be checked (${failure.message}); see the project's Coding Instructions tab.`,\n\t\t\t\tfailure.exitCode,\n\t\t\t);\n\t\t}\n\t\tif (waited.kind === \"settled\") {\n\t\t\toutcome.pullRequest = pushPullRequest(waited.pullRequest, false);\n\t\t} else if (waited.kind === \"timed_out\") {\n\t\t\toutcome.pullRequest = {\n\t\t\t\t...(waited.pullRequest\n\t\t\t\t\t? pushPullRequest(waited.pullRequest, true)\n\t\t\t\t\t: outcome.pullRequest),\n\t\t\t\ttimedOut: true,\n\t\t\t};\n\t\t}\n\t}\n\n\tconst verdict = outcome.pullRequest\n\t\t? pullRequestVerdict(outcome.pullRequest, {\n\t\t\t\twaited: opts.wait !== false,\n\t\t\t\topenedHere: sawBranchWithoutPullRequest,\n\t\t\t})\n\t\t: null;\n\tif (format === \"json\") {\n\t\tprintOutput(outcome, { format: \"json\" });\n\t} else {\n\t\treportPush(outcome);\n\t\tif (verdict && !verdict.fails) {\n\t\t\tline(verdict.text);\n\t\t}\n\t}\n\tif (verdict?.fails) {\n\t\tthrow new CliFailure(verdict.text, 7);\n\t}\n}\n\nfunction pushPullRequest(\n\tpullRequest: ProposalPullRequest,\n\ttimedOut: boolean,\n): NonNullable<PushOutcome[\"pullRequest\"]> {\n\tconst branch = pullRequest.branch ?? null;\n\treturn {\n\t\toperationId: pullRequest.operationId,\n\t\tstate: pullRequest.state,\n\t\turl: branch?.pullRequest?.url ?? pullRequest.url,\n\t\tfailure: pullRequest.failure,\n\t\ttimedOut,\n\t\tbranch,\n\t\tappend: pullRequest.append ?? null,\n\t};\n}\n\n/**\n * Why Fabric could not open the pull request, by the stored failure's code.\n * The codes are the server's (`INSTRUCTION_PULL_REQUEST_FAILURE_CODES`); an\n * unlisted one is named rather than guessed at.\n */\nconst BLOCKED_REASONS: Record<string, string> = {\n\tATTRIBUTION_REJECTED:\n\t\t\"the project's name or your display name looks like an address, a link or a credential, so the commit could not name you safely\",\n\tPERMISSION_REVOKED:\n\t\t\"you no longer have permission to suggest changes to this project's repository\",\n\tCONFIGURATION_CHANGED:\n\t\t\"the project's repository settings changed after you suggested this; push again\",\n\tTARGET_BRANCH_MISSING:\n\t\t\"the repository branch the project syncs from no longer exists\",\n\tBASE_COMMIT_UNAVAILABLE:\n\t\t\"the commit this suggestion was based on is no longer in the repository; sync and push again\",\n\tTREE_CONFLICT:\n\t\t\"the repository changed the same files since your last sync; sync and push again\",\n\tAUTHENTICATION_FAILED:\n\t\t\"the project's repository connection needs to be reconnected\",\n\tREPOSITORY_UNAVAILABLE: \"the repository could not be reached\",\n\tBRANCH_WRITE_REFUSED: \"the repository refused the new branch\",\n\tPR_CREATION_REFUSED: \"the repository refused to open the pull request\",\n\tREMOTE_REF_CONFLICT:\n\t\t\"a branch with the same name already exists in the repository\",\n\tCREATE_OUTCOME_UNKNOWN:\n\t\t\"Fabric could not confirm whether the pull request was created\",\n\tVALIDATION_TIMEOUT: \"the files' checks did not finish in time\",\n\tLIMITS_EXCEEDED:\n\t\t\"the change is larger than Fabric can open as a pull request\",\n\tPROVIDER_RATE_LIMITED: \"the repository's provider is limiting requests\",\n\tPROVIDER_TEMPORARY: \"the repository's provider had a temporary problem\",\n\tLOOKUP_INCONCLUSIVE: \"Fabric could not confirm the pull request's state\",\n\t// Member proposal branches (Fizzy #2738 spec §9). BRANCH_CONFLICT and\n\t// SUPERSEDED_BY_LATER_CHANGE name their paths, in `blockedReason`.\n\tBRANCH_MOVED: \"your branch kept changing while Fabric was adding to it\",\n\tBRANCH_NAME_UNAVAILABLE:\n\t\t\"Fabric could not reserve a branch name for your pull request; ask an owner to remove old proposal branches\",\n\tREPOSITORY_CHANGED:\n\t\t\"the repository connection now points at another repository, so Fabric can no longer reach your pull request; close it in the repository, then stop tracking it in the Coding Instructions tab\",\n\tPUSH_OUTCOME_UNKNOWN:\n\t\t\"Fabric could not confirm whether this change reached your branch, which may have been changed outside Fabric; check the branch, then try again or withdraw it\",\n\tBRANCH_MISSING: \"your branch was deleted in the repository\",\n};\n\n/**\n * How many paths a failure's `params.paths` lists at most: the server's\n * `pathParams` joins the first 20 with \", \", and `params.count` is them all.\n */\nconst FAILURE_PATHS_LISTED = 20;\n\n/**\n * The failure's `params.paths` and, past those, how many more its\n * `params.count` says there are. Counted from the limit, never by splitting\n * the list: a repository path may itself contain \", \".\n */\nfunction failurePaths(failure: { params?: Record<string, unknown> }): string {\n\tconst paths = failure.params?.paths;\n\tconst count = failure.params?.count;\n\tif (typeof paths !== \"string\" || paths === \"\") {\n\t\treturn \"some of its files\";\n\t}\n\treturn typeof count === \"number\" && count > FAILURE_PATHS_LISTED\n\t\t? `${paths} and ${count - FAILURE_PATHS_LISTED} more`\n\t\t: paths;\n}\n\n/** Why a pull request or a change on a branch is blocked, by its code. */\nfunction blockedReason(failure: {\n\tcode: string;\n\tparams?: Record<string, unknown>;\n}): string {\n\tswitch (failure.code) {\n\t\tcase \"BRANCH_CONFLICT\":\n\t\t\treturn `files on your branch were changed outside Fabric (${failurePaths(failure)}), and Fabric does not overwrite them while the pull request is open; make this change on your branch in the repository, or wait until the pull request merges`;\n\t\tcase \"SUPERSEDED_BY_LATER_CHANGE\":\n\t\t\treturn `a newer change of yours already edits ${failurePaths(failure)}; use Try again to apply this one on top of it, or withdraw it`;\n\t\tdefault:\n\t\t\treturn (\n\t\t\t\tBLOCKED_REASONS[failure.code] ??\n\t\t\t\t`it stopped with ${failure.code}`\n\t\t\t);\n\t}\n}\n\n/**\n * The sentence a push ends on for its pull request, and whether it is a\n * failure. `OPEN`, `MERGED`, `CLOSED`, a change already on the member's\n * branch and a wait that ran out exit 0; `BLOCKED`, any other `CANCELED` and\n * an earlier attempt's pending close exit 7.\n *\n * On a member branch (Fizzy #2738 spec §10) `OPEN` names the branch's pull\n * request: \"Opened pull request\" when this push saw the branch before it had\n * one, \"Added to your pull request\" otherwise.\n */\nfunction pullRequestVerdict(\n\tpullRequest: NonNullable<PushOutcome[\"pullRequest\"]>,\n\t{ waited, openedHere }: { waited: boolean; openedHere: boolean },\n): { text: string; fails: boolean } {\n\tconst url = pullRequest.url ? `: ${pullRequest.url}` : \"\";\n\tconst branch = pullRequest.branch;\n\tif (!waited) {\n\t\treturn {\n\t\t\ttext: \"Follow its pull request in the project's Coding Instructions tab.\",\n\t\t\tfails: false,\n\t\t};\n\t}\n\tif (pullRequest.timedOut) {\n\t\treturn {\n\t\t\ttext: \"The pull request is being opened; see the project's Coding Instructions tab.\",\n\t\t\tfails: false,\n\t\t};\n\t}\n\tswitch (pullRequest.state) {\n\t\tcase \"OPEN\": {\n\t\t\tif (!branch) {\n\t\t\t\treturn { text: `Pull request opened${url}`, fails: false };\n\t\t\t}\n\t\t\t// A merged or closed pull request is the outcome whatever failure\n\t\t\t// the branch also carries (classification can record\n\t\t\t// REPOSITORY_CHANGED on a settled branch): what it means for this\n\t\t\t// change is decided separately, so neither claims an open one.\n\t\t\tif (branch.state === \"MERGED\") {\n\t\t\t\treturn {\n\t\t\t\t\ttext: `Your pull request was merged${url} while this change was being added to it; see the project's Coding Instructions tab for whether it carried this change.`,\n\t\t\t\t\tfails: false,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (branch.state === \"CLOSED\") {\n\t\t\t\treturn {\n\t\t\t\t\ttext: `Your pull request was closed without merging${url} while this change was being added to it.`,\n\t\t\t\t\tfails: false,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (\n\t\t\t\tbranch.failure &&\n\t\t\t\t(branch.state === \"BLOCKED\" || branchStoppedByFailure(branch))\n\t\t\t) {\n\t\t\t\tconst next = branch.failure.retryable\n\t\t\t\t\t? \"Fabric will try again on its own; see\"\n\t\t\t\t\t: \"See\";\n\t\t\t\tconst what = branch.pullRequest\n\t\t\t\t\t? `Your change is on your branch, but Fabric can no longer update its pull request${url}`\n\t\t\t\t\t: \"Your change is on your branch, but Fabric could not open its pull request\";\n\t\t\t\treturn {\n\t\t\t\t\ttext: `${what}: ${blockedReason(branch.failure)}. ${next} the project's Coding Instructions tab.`,\n\t\t\t\t\tfails: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (branch.state === \"CLOSE_REQUESTED\") {\n\t\t\t\treturn {\n\t\t\t\t\ttext: \"Your pull request is being closed, and this change leaves with it; push again once it has closed.\",\n\t\t\t\t\tfails: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (branch.state === \"CANCELED\") {\n\t\t\t\treturn {\n\t\t\t\t\ttext: \"Your branch was closed before its pull request opened; push again.\",\n\t\t\t\t\tfails: true,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (branch.pullRequest?.state === \"OPEN\") {\n\t\t\t\treturn {\n\t\t\t\t\ttext: openedHere\n\t\t\t\t\t\t? `Opened pull request ${branch.pullRequest.url}`\n\t\t\t\t\t\t: `Added to your pull request ${branch.pullRequest.url}`,\n\t\t\t\t\tfails: false,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\ttext: \"Your change is on your branch and its pull request is being opened; see the project's Coding Instructions tab.\",\n\t\t\t\tfails: false,\n\t\t\t};\n\t\t}\n\t\tcase \"MERGED\":\n\t\t\treturn {\n\t\t\t\ttext: `Its pull request was already merged${url}. Run \\`fabric instructions sync\\` once the project has synced it.`,\n\t\t\t\tfails: false,\n\t\t\t};\n\t\tcase \"CLOSED\":\n\t\t\treturn {\n\t\t\t\ttext: `Its pull request was closed without merging${url}.`,\n\t\t\t\tfails: false,\n\t\t\t};\n\t\tcase \"CANCELED\":\n\t\t\tif (pullRequest.failure?.code === \"ALREADY_ON_BRANCH\") {\n\t\t\t\treturn {\n\t\t\t\t\ttext: branch?.pullRequest\n\t\t\t\t\t\t? `Already on your branch; nothing to add. Your pull request: ${branch.pullRequest.url}`\n\t\t\t\t\t\t: \"Already on your branch; nothing to add.\",\n\t\t\t\t\tfails: false,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\ttext:\n\t\t\t\t\tpullRequest.failure?.code === \"VALIDATION_REJECTED\"\n\t\t\t\t\t\t? \"The suggestion did not pass Fabric's checks, so no pull request was opened; see the project's Coding Instructions tab.\"\n\t\t\t\t\t\t: branch\n\t\t\t\t\t\t\t? \"The suggestion was withdrawn before it was added to your pull request.\"\n\t\t\t\t\t\t\t: \"The suggestion was withdrawn before a pull request was opened.\",\n\t\t\t\tfails: true,\n\t\t\t};\n\t\tcase \"CLOSE_REQUESTED\":\n\t\t\treturn {\n\t\t\t\ttext: \"An earlier attempt at this change was withdrawn and its pull request is being closed; push again once it has closed.\",\n\t\t\t\tfails: true,\n\t\t\t};\n\t\tcase \"BLOCKED\": {\n\t\t\t// A change blocked before it reached the branch can carry its\n\t\t\t// branch's failure rather than one of its own.\n\t\t\tconst failure = pullRequest.failure ?? branch?.failure ?? null;\n\t\t\tconst reason = failure\n\t\t\t\t? blockedReason(failure)\n\t\t\t\t: \"it stopped with an unknown failure\";\n\t\t\tconst next = failure?.retryable\n\t\t\t\t? \"Fabric will try again on its own; see\"\n\t\t\t\t: \"See\";\n\t\t\tconst what = branch\n\t\t\t\t? \"Fabric could not add this change to your pull request\"\n\t\t\t\t: \"Fabric could not open the pull request\";\n\t\t\treturn {\n\t\t\t\ttext: `${what}: ${reason}. ${next} the project's Coding Instructions tab.`,\n\t\t\t\tfails: true,\n\t\t\t};\n\t\t}\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\ttext: \"The pull request is being opened; see the project's Coding Instructions tab.\",\n\t\t\t\tfails: false,\n\t\t\t};\n\t}\n}\n\n/**\n * The refusals a push has to say something useful about, by the reason code\n * the route sends (`packages/api/modules/v1/instructions.ts`).\n *\n * Everything else falls through to `asCliFailure`'s status mapping, which is\n * already right for auth, permission and rate limits.\n */\nfunction asPushFailure(error: unknown): CliFailure {\n\tconst code = (error as { code?: string }).code;\n\tconst message = error instanceof Error ? error.message : String(error);\n\tswitch (code) {\n\t\tcase \"PULL_FIRST\":\n\t\t\treturn new CliFailure(\n\t\t\t\t\"published instructions moved past your last sync; run `fabric instructions sync` then push again\",\n\t\t\t\t7,\n\t\t\t);\n\t\tcase \"REPOSITORY_SOURCE_OF_TRUTH\":\n\t\t\treturn new CliFailure(\n\t\t\t\t\"this project's coding instructions come from its repository, so they are changed there and mirrored into Fabric — commit and push to the repository instead; nothing was sent\",\n\t\t\t\t7,\n\t\t\t);\n\t\tcase \"NOTHING_PUBLISHED\":\n\t\t\treturn new CliFailure(\n\t\t\t\t\"this project has no published coding instructions to change yet; the first version is uploaded from the Coding Instructions tab\",\n\t\t\t\t4,\n\t\t\t);\n\t\tcase \"PROPOSAL_PROPOSER_LIMIT\":\n\t\tcase \"PROPOSAL_PROJECT_LIMIT\":\n\t\t\treturn new CliFailure(`${message} Nothing was sent.`, 7);\n\t\t// A repository-backed project's admission (Fizzy #2563 spec §5.3).\n\t\tcase \"REPOSITORY_UNAVAILABLE\":\n\t\t\treturn new CliFailure(\n\t\t\t\t`this project's repository connection needs attention before a change can be suggested to it (${message}); nothing was sent`,\n\t\t\t\t7,\n\t\t\t);\n\t\tcase \"REPOSITORY_BASE_UNAVAILABLE\":\n\t\t\treturn new CliFailure(\n\t\t\t\t\"this project's published instructions are not a sync of its repository as it is configured now; sync the project from its Coding Instructions tab, run `fabric instructions sync`, then push again; nothing was sent\",\n\t\t\t\t7,\n\t\t\t);\n\t\tcase \"NOTE_REJECTED\":\n\t\t\treturn new CliFailure(\n\t\t\t\t`${message} Change --message and push again; nothing was sent.`,\n\t\t\t\t7,\n\t\t\t);\n\t\tdefault:\n\t\t\treturn asCliFailure(error);\n\t}\n}\n\n/**\n * The one sentence a completed push ends on.\n *\n * A push that repeats an earlier one is answered with the proposal that one\n * opened, so this has to read every state that proposal can be in — not just\n * the fresh-proposal case. The rule each branch obeys: NEVER advise an action\n * the server's content dedup will swallow. A proposal still PENDING is exactly\n * what the next push would match, so those branches describe the state or name\n * the one thing that changes it, and \"push again\" appears only once the\n * proposal has stopped being PENDING.\n */\nfunction pushVerdict(outcome: PushOutcome): string {\n\t// A publish has no review state to read, so none of the proposal\n\t// branches below apply to it; what it has instead is a validation run\n\t// that has only just started. Saying \"published version 9\" here would be\n\t// a claim this command cannot make — the verify and secret-scan gate runs\n\t// after the response, and a change set that fails it publishes nothing.\n\t//\n\t// Branched on `outcome.published`, never on `outcome.status === \"READY\"`\n\t// alone: the auto-publish runs as its own step, normally AFTER this\n\t// command has already gotten its response — `READY` says the checks\n\t// passed, `published` is the server's own observation of whether the\n\t// publish had already happened by the time it answered. This command\n\t// classifies nothing further: it cannot know, at response time, whether\n\t// an unpublished READY version is still catching up or has genuinely lost\n\t// out to a concurrent edit — that is what the tab's history is for, and\n\t// this never guesses at it with words like \"superseded\" or \"moved\".\n\tif (outcome.publish) {\n\t\tif (outcome.published) {\n\t\t\treturn `Published version ${outcome.version}. Run \\`fabric instructions sync\\` to bring this checkout onto it.`;\n\t\t}\n\t\tif (outcome.status === \"FAILED\" || outcome.status === \"REJECTED\") {\n\t\t\treturn `Version ${outcome.version} did not pass its checks (${outcome.status}), so nothing was published; open the project's Coding Instructions tab to see why.`;\n\t\t}\n\t\tconst sent = `Sent as version ${outcome.version}. It publishes on its own once its checks pass (${outcome.status}) — then run \\`fabric instructions sync\\` to bring this checkout onto it.`;\n\t\t// READY gets one more sentence: the checks are done, so what remains\n\t\t// unknown is only whether the publish step has landed, and the tab is\n\t\t// where that is answered — not a guess printed here.\n\t\treturn outcome.status === \"READY\"\n\t\t\t? `${sent} It has passed its checks; its publication state is shown in the project's Coding Instructions tab.`\n\t\t\t: sent;\n\t}\n\n\t// The row is still receiving bytes: an earlier attempt at this same change\n\t// is mid-flight. No push closes it out at any age — the browser tab opens\n\t// proposals through the same query and keeps its upload capabilities for\n\t// an hour, so a row that looks stalled from here may be one somebody is\n\t// still filling. What does move it: its proposer can cancel it in the tab\n\t// (a RECEIVING proposal is cancellable), and the reaper closes an\n\t// abandoned one after six hours.\n\tif (\n\t\toutcome.proposalStatus === \"PENDING\" &&\n\t\toutcome.status === \"RECEIVING\"\n\t) {\n\t\treturn `An earlier attempt is still sending this change; if version ${outcome.version} stays unfinished, cancel it in the project's Coding Instructions tab, or leave it and it is closed out automatically after six hours.`;\n\t}\n\t// Its checks failed, and it stays PENDING — so the next push dedups\n\t// straight back onto it. The tab's \"Try again\" is the only thing that\n\t// moves it, which is why no push is offered here. Both of these branches\n\t// require PENDING: a row that vanished after the finalizer reports\n\t// `proposalStatus: null` beside the finalizer's last status, and telling\n\t// the user to retry or cancel a version that no longer exists would be\n\t// wrong — that case falls through to \"push again\", which is right.\n\tif (outcome.proposalStatus === \"PENDING\" && outcome.status === \"FAILED\") {\n\t\treturn `This proposal did not pass its checks; retry version ${outcome.version} from the project's Coding Instructions tab.`;\n\t}\n\tif (outcome.proposalStatus === \"PENDING\") {\n\t\t// Unreachable in practice — the gate closes a rejected proposal's\n\t\t// review state in the same transaction — but a PENDING row is one the\n\t\t// dedup matches, so the advice has to be the thing that clears it.\n\t\tif (outcome.status === \"REJECTED\") {\n\t\t\treturn `Version ${outcome.version} was rejected by its checks — cancel it in the project's Coding Instructions tab before proposing this change again.`;\n\t\t}\n\t\t// A repository-backed project: reviewed as a pull request in the\n\t\t// repository, not in the tab (Fizzy #2563 spec §12).\n\t\tif (outcome.pullRequest) {\n\t\t\treturn `Suggested as version ${outcome.version}. This project's coding instructions come from its repository, so once the files pass their checks Fabric adds the change to your pull request there, opening one if you have none, and it is reviewed and merged in the repository.`;\n\t\t}\n\t\treturn `Proposed as version ${outcome.version}. It is pending review — nothing is published until somebody who can edit this project's coding instructions approves it in the Coding Instructions tab.`;\n\t}\n\tif (outcome.proposalStatus === \"APPROVED\") {\n\t\treturn `Version ${outcome.version} has already been approved and published — run \\`fabric instructions sync\\` to bring this checkout up to it.`;\n\t}\n\treturn `Version ${outcome.version} is no longer open for review (${outcome.proposalStatus ?? outcome.status}): an earlier attempt at this same change was closed out, so push again.`;\n}\n\nfunction reportPush(outcome: PushOutcome): void {\n\t// Only reachable for a proposal whose every change is already proposed:\n\t// nothing was sent, on a dry run or not.\n\tif (outcome.put.length === 0 && outcome.deleted.length === 0) {\n\t\tline(\n\t\t\t\"Nothing new to push: every change here is already in your open proposals.\",\n\t\t);\n\t\treportAlreadyProposed(outcome);\n\t\treturn;\n\t}\n\n\tconst prefix = outcome.dryRun ? \"Would send\" : \"Sent\";\n\tconst proposed =\n\t\toutcome.alreadyProposed.length > 0\n\t\t\t? `, ${outcome.alreadyProposed.length} already proposed`\n\t\t\t: \"\";\n\tline(\n\t\t`${prefix} ${outcome.put.length} changed file(s) and ${outcome.deleted.length} deletion(s) against version ${outcome.baseVersion} (${outcome.unchanged} unchanged${proposed}).`,\n\t);\n\tlistPaths(\"changed\", outcome.put);\n\tlistPaths(\"deleted\", outcome.deleted);\n\treportAlreadyProposed(outcome);\n\n\tif (outcome.dryRun) {\n\t\tline(\n\t\t\toutcome.publish\n\t\t\t\t? \"Nothing was sent. Without --dry-run this would create a new version that publishes on its own once its checks pass, with no review.\"\n\t\t\t\t: \"Nothing was sent. Without --dry-run this would open a proposal for review.\",\n\t\t);\n\t\treturn;\n\t}\n\n\tline(pushVerdict(outcome));\n\tline(\n\t\toutcome.publish\n\t\t\t? `Your lock was not changed: it still names version ${outcome.baseVersion}, which is what \\`fabric instructions sync\\` compares against.`\n\t\t\t: \"Your lock was not changed: it still names the published version, which is what `fabric instructions sync` compares against.\",\n\t);\n}\n\n/**\n * Which open proposal carries a change, in the words a developer can find it\n * by: its version, and its pull request when it has one.\n */\nfunction proposalReference(proposal: {\n\tversion: number;\n\tpullRequestState: string | null;\n\tpullRequestUrl: string | null;\n}): string {\n\tif (proposal.pullRequestUrl) {\n\t\treturn `version ${proposal.version}, pull request ${proposal.pullRequestUrl}`;\n\t}\n\tif (proposal.pullRequestState) {\n\t\treturn `version ${proposal.version}, whose pull request is being opened`;\n\t}\n\treturn `version ${proposal.version}`;\n}\n\n/** Every proposal named in `alreadyProposed`, once each, newest first. */\nfunction proposalReferences(alreadyProposed: AlreadyProposed[]): string {\n\tconst byVersion = new Map<number, string>();\n\tfor (const entry of alreadyProposed) {\n\t\tbyVersion.set(\n\t\t\tentry.proposal.version,\n\t\t\tproposalReference({\n\t\t\t\tversion: entry.proposal.version,\n\t\t\t\tpullRequestState: entry.proposal.pullRequest?.state ?? null,\n\t\t\t\tpullRequestUrl: entry.proposal.pullRequest?.url ?? null,\n\t\t\t}),\n\t\t);\n\t}\n\treturn [...byVersion.entries()]\n\t\t.sort(([a], [b]) => b - a)\n\t\t.map(([, reference]) => reference)\n\t\t.join(\"; \");\n}\n\nfunction reportAlreadyProposed(outcome: PushOutcome): void {\n\tif (outcome.alreadyProposed.length === 0) {\n\t\treturn;\n\t}\n\tline(\" already proposed, not sent:\");\n\tfor (const entry of outcome.alreadyProposed) {\n\t\tconst what = entry.action === \"delete\" ? \"deletion already\" : \"already\";\n\t\tline(\n\t\t\t` ${entry.path} — ${what} proposed in ${proposalReference(entry)}`,\n\t\t);\n\t}\n\tline(\n\t\toutcome.publish\n\t\t\t? \"Left out because an open proposal of yours already carries the same change, and publishing it from here would skip that proposal's review; add --include-proposed to publish it anyway. Once this version publishes, that proposal is stated against an older version and can no longer be approved: run `fabric instructions sync`, then push again to propose those files afresh.\"\n\t\t\t: \"Left out because an open proposal of yours already carries the same change; add --include-proposed to send it anyway.\",\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// init\n// ---------------------------------------------------------------------------\n\nasync function runInit(\n\topts: CommonOptions & { tool: string; apply?: boolean; lessons?: boolean },\n\tformat: OutputFormat,\n): Promise<void> {\n\tif (!isInstructionsHookTool(opts.tool)) {\n\t\tthrow new CliFailure(\n\t\t\t`Unsupported tool \"${opts.tool}\". Use --tool claude-code or --tool codex.`,\n\t\t\t2,\n\t\t);\n\t}\n\tconst tool = opts.tool;\n\n\t// Before any write: Codex has no wired Stop hook for lesson capture yet,\n\t// so a `--lessons` request against it is refused rather than silently\n\t// dropped or half-applied.\n\tif (opts.lessons && tool === \"codex\") {\n\t\tthrow new CliFailure(\n\t\t\t\"--lessons is not yet supported for codex; Codex hooks for lesson capture are not wired.\",\n\t\t\t2,\n\t\t);\n\t}\n\n\tconst destination = destinationOf(opts);\n\t// Not created yet: a refusal below must leave nothing behind.\n\tconst existing = await resolveExistingRoot(destination);\n\n\t// A local precondition answered before any network call: a credential\n\t// file that would end up inside the checkout.\n\tawait assertKeyOutside(existing);\n\n\tconst client = instructionsClient(opts, SYNC_TIMEOUT_MS);\n\tconst guard = new SourceGuard(destination);\n\tconst published = await fetchPublished(client, opts, undefined, guard);\n\n\t// A repository-sourced project (Fizzy #2708), classified once, here. In a\n\t// checkout of the repository the files arrive with git: the hook is\n\t// written and reports, and nothing is copied. Outside any checkout the\n\t// upload behaviour applies. Anywhere in between, nothing is written.\n\tconst checkout = guard.checkout;\n\tif (\n\t\tcheckout !== null &&\n\t\tcheckout.class !== \"matching\" &&\n\t\tcheckout.class !== \"not-git\"\n\t) {\n\t\tthrow new CliFailure(\n\t\t\tclassLine(checkout, published.repository ?? null),\n\t\t\t7,\n\t\t);\n\t}\n\tconst repositoryCheckout =\n\t\tcheckout?.class === \"matching\" && published.repository\n\t\t\t? published.repository\n\t\t\t: null;\n\t// A lock that belongs to another project, checked only where a lock is\n\t// used: a checkout of the repository never has one, and whatever is left\n\t// there must not stop the hook being installed (Fizzy #2708 review).\n\tif (repositoryCheckout === null) {\n\t\tawait readLockForProject(existing, opts.project);\n\t}\n\n\tconst root = await resolveDestinationRoot(destination);\n\tif (root !== existing) {\n\t\t// The directory did not exist a moment ago; the key check is about\n\t\t// real paths, so it is asked again of the one that now does.\n\t\tawait assertKeyOutside(root);\n\t}\n\n\tlet outcome: SyncOutcome | null = null;\n\tif (repositoryCheckout === null && published.published) {\n\t\t// A second manifest call, deliberately: the one above answered \"may a\n\t\t// hook be installed for this project at all\", and this one is the\n\t\t// sync's own — held to the first by the same guard. Do it before the\n\t\t// hook write: a failed first copy must not leave a new or updated\n\t\t// hook behind.\n\t\tconst synced = await syncOnce({ ...opts, hook: false, guard });\n\t\tif (synced.kind !== \"synced\") {\n\t\t\tthrow new CliFailure(\n\t\t\t\t\"the first copy was not taken; nothing else was written\",\n\t\t\t\t7,\n\t\t\t);\n\t\t}\n\t\toutcome = synced.outcome;\n\t}\n\n\tconst command = buildHookCommand(\n\t\topts.project,\n\t\tBoolean(opts.apply),\n\t\topts.org,\n\t);\n\tconst merged = await mergeSessionStartHook({\n\t\troot,\n\t\tprojectId: opts.project,\n\t\tcommand,\n\t\ttool,\n\t});\n\n\t// The Stop hook for lesson capture describes the DESIRED state, same as\n\t// the SessionStart hook above: `--lessons` installs it, and its absence\n\t// uninstalls whatever an earlier `init` installed. Always after the\n\t// SessionStart write, so a failure here never leaves that one half-done,\n\t// and always attempted (even for a plain re-run with no lessons hook\n\t// ever installed) because the removal is a no-op — and writes nothing —\n\t// when there is nothing to remove.\n\tconst lessonsHook = Boolean(opts.lessons);\n\tlet lessonsHookLine: string | null = null;\n\tif (lessonsHook) {\n\t\tconst installed = await mergeCommandHook({\n\t\t\troot,\n\t\t\tprojectId: opts.project,\n\t\t\tcommand: buildLessonPromptCommand(opts.project, opts.org),\n\t\t\ttool,\n\t\t\tevent: \"Stop\",\n\t\t});\n\t\tlessonsHookLine = `Added a Stop hook for lesson capture to ${installed.settingsPath}.`;\n\t} else {\n\t\tconst removed = await removeCommandHook({\n\t\t\troot,\n\t\t\tprojectId: opts.project,\n\t\t\tsubcommand: \"lesson-prompt\",\n\t\t\ttool,\n\t\t\tevent: \"Stop\",\n\t\t});\n\t\tif (removed.changed) {\n\t\t\tlessonsHookLine = `Removed the Stop hook for lesson capture from ${removed.settingsPath}.`;\n\t\t}\n\t}\n\n\tif (format === \"json\") {\n\t\tprintOutput(\n\t\t\t{\n\t\t\t\tprojectId: opts.project,\n\t\t\t\tdestination: root,\n\t\t\t\tsettingsPath: merged.settingsPath,\n\t\t\t\thookCommand: merged.command,\n\t\t\t\tcreatedSettingsFile: merged.createdFile,\n\t\t\t\treplacedHooks: merged.replacedCount,\n\t\t\t\tlessonsHook,\n\t\t\t\tsync: outcome,\n\t\t\t\tcheckout:\n\t\t\t\t\tcheckout === null\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: checkout.class === \"matching\"\n\t\t\t\t\t\t\t? { class: checkout.class, remote: checkout.remote }\n\t\t\t\t\t\t\t: { class: checkout.class },\n\t\t\t},\n\t\t\t{ format: \"json\" },\n\t\t);\n\t\treturn;\n\t}\n\n\tline(\n\t\tmerged.replacedCount > 0\n\t\t\t? `Updated the SessionStart hook in ${merged.settingsPath}.`\n\t\t\t: `Added a SessionStart hook to ${merged.settingsPath}.`,\n\t);\n\tline(` ${command}`);\n\tif (repositoryCheckout !== null) {\n\t\tline(` ${installedLine(repositoryCheckout, Boolean(opts.apply))}`);\n\t} else {\n\t\tline(\n\t\t\topts.apply\n\t\t\t\t? \" It applies changes at session start.\"\n\t\t\t\t: \" It only reports changes; add --apply to init to have it apply them.\",\n\t\t);\n\t}\n\tif (lessonsHookLine !== null) {\n\t\tline(lessonsHookLine);\n\t}\n\tif (tool === \"codex\") {\n\t\tline(\n\t\t\t\" Start Codex in this checkout, then use `/hooks` to review and trust the project hook.\",\n\t\t);\n\t}\n\n\tif (repositoryCheckout !== null) {\n\t\tif (published.snapshot?.source?.kind !== \"REPOSITORY\") {\n\t\t\tline(nothingPublishedLine(repositoryCheckout));\n\t\t}\n\t\tline(\"\");\n\t\t// No lock in a checkout of the repository: nothing is copied into it.\n\t\tline(\n\t\t\t`${hookPathFor(tool)} is local to this machine. If this repository does not ignore it already, add it to your own ignore rules — this command does not edit .gitignore.`,\n\t\t);\n\t\treturn;\n\t}\n\n\tif (outcome === null) {\n\t\tline(\n\t\t\t\"This project has nothing published yet, so there is nothing to copy — the hook will pick it up once there is.\",\n\t\t);\n\t} else {\n\t\tline(\"\");\n\t\treportSync(outcome, opts);\n\t}\n\n\tline(\"\");\n\tline(\n\t\t`${hookPathFor(tool)} and ${LOCK_DIRECTORY}/ are local to this machine. If this repository does not ignore them already, add them to your own ignore rules — this command does not edit .gitignore.`,\n\t);\n}\n\nasync function assertKeyOutside(root: string): Promise<void> {\n\ttry {\n\t\tawait assertKeyStaysOutside(root, getConfigPath());\n\t} catch (error) {\n\t\tthrow new CliFailure(describeError(error), 7);\n\t}\n}\n\nfunction isInstructionsHookTool(tool: string): tool is InstructionsHookTool {\n\treturn tool === \"claude-code\" || tool === \"codex\";\n}\n\nfunction hookPathFor(tool: InstructionsHookTool): string {\n\treturn tool === \"codex\"\n\t\t? CODEX_HOOKS_RELATIVE_PATH\n\t\t: CLAUDE_SETTINGS_RELATIVE_PATH;\n}\n\n// ---------------------------------------------------------------------------\n// lesson-prompt\n// ---------------------------------------------------------------------------\n\n/**\n * The `fabric instructions lesson-prompt --hook` wiring: read stdin, ask\n * `runLessonPrompt` what to do, print its answer (if any), and stop.\n *\n * Deliberately outside the `run()` boundary every other command in this file\n * goes through: that boundary still prints one line to stderr and calls\n * `process.exit(0)` on a caught failure, and even that is more than this\n * command's contract allows. `runLessonPrompt` already turns every failure\n * mode — bad stdin, an unreadable transcript, a marker directory it cannot\n * create — into `{ output: null }`, so there is nothing left for this\n * wrapper to catch. It does not call `process.exit` at all: like every other\n * command in this package that does not need to force a specific exit code,\n * it simply returns and lets the process exit on its own once stdout has\n * flushed, which `process.exit` would risk cutting short.\n */\nasync function runLessonPromptCommand(opts: {\n\tproject?: string;\n\torg?: string;\n\thook?: boolean;\n}): Promise<void> {\n\tlet stdinText = \"\";\n\ttry {\n\t\tstdinText = await readAllStdin(process.stdin);\n\t} catch {\n\t\t// An unreadable stdin behaves exactly like empty stdin:\n\t\t// `parseStopHookInput(\"\")` already answers `null`, which\n\t\t// `runLessonPrompt` turns into a silent exit.\n\t}\n\n\tconst markerDir = path.join(\n\t\tpath.dirname(getConfigPath()),\n\t\t\"lesson-prompts\",\n\t);\n\n\tconst result = await runLessonPrompt({\n\t\tstdinText,\n\t\tmarkerDir,\n\t\tnow: new Date(),\n\t\tprojectId: opts.project,\n\t});\n\n\tif (result.output !== null) {\n\t\tprocess.stdout.write(`${result.output}\\n`);\n\t}\n}\n","/**\n * Turning a plan into files, with two rules that decide the shape of\n * everything below.\n *\n * First: verify every byte before writing any byte. Each entry's sha256 is\n * checked against the manifest up front, so a corrupt or tampered archive\n * aborts with nothing written at all, rather than half a tree of good files\n * and one bad one. The caller then does not rewrite the lock, so the next run\n * plans from the last known-good state.\n *\n * Second: every write goes through `safe-write.ts` — the same writer the\n * lock and the Claude Code settings file use. Symlink refusal, canonical\n * containment, exclusive temp creation and the pre-rename recheck all live\n * there, so there is exactly one implementation of \"may this land here\".\n */\nimport { createHash } from \"node:crypto\";\nimport { chmod } from \"node:fs/promises\";\nimport { describeRejection } from \"./paths.js\";\nimport { hashLocalFile, type PlanEntry, type SyncPlan } from \"./plan.js\";\nimport {\n\tassertWritableTarget,\n\tdeleteFileSafely,\n\tisAllowedMode,\n\tpermissionBits,\n\twriteFileSafely,\n} from \"./safe-write.js\";\n\nexport interface ApplyResult {\n\twritten: string[];\n\tdeleted: string[];\n\t/** Paths whose mode was corrected without rewriting their bytes. */\n\tremoded: string[];\n\t/**\n\t * Paths the plan meant to delete that no longer matched the hash it\n\t * decided on — someone edited them between planning and now, so they were\n\t * left where they are.\n\t */\n\tkeptModified: string[];\n\t/**\n\t * Planned writes left alone because the file changed after planning: an\n\t * editor saved over a file the plan meant to update, or created one where\n\t * it meant to add (Decision 37). Only when `keepLocalEdits` is set.\n\t */\n\tkeptEdited: string[];\n}\n\nexport interface ApplyInput {\n\t/** An already-canonical destination from `resolveDestinationRoot`. */\n\troot: string;\n\tplan: SyncPlan;\n\t/** Extracted archive entries, keyed by the manifest path. */\n\tcontents: Map<string, Uint8Array>;\n\t/**\n\t * Re-hash each write's target just before writing it, and leave it alone\n\t * when it no longer holds what the plan saw (`PlanEntry.localSha256`).\n\t * The CLI sets it unless `sync --repair` was given (spec §6.4).\n\t */\n\tkeepLocalEdits?: boolean;\n}\n\nexport async function applyPlan(input: ApplyInput): Promise<ApplyResult> {\n\tconst { root, plan, contents } = input;\n\n\t// ---- Phase 1: prove the whole plan before touching the tree ----------\n\t//\n\t// EVERY path the plan names, including the ones it does not intend to\n\t// write. A `verified` entry is one whose local bytes already match, and a\n\t// symlink pointing at those bytes used to reach exactly that verdict: no\n\t// write, no check, and a lock written over a path that is not a file.\n\t// This runs before the platform and mode short-circuits further down for\n\t// the same reason — a check that only some plans reach is not a check.\n\tfor (const entry of [\n\t\t...plan.writes,\n\t\t...plan.verified,\n\t\t...plan.deletes,\n\t\t...plan.keptRenamed,\n\t\t// Never written, but the lock is about to record it as a synced\n\t\t// file, so it has to be one.\n\t\t...plan.keptEdited,\n\t]) {\n\t\tconst check = await assertWritableTarget(root, entry.path);\n\t\tif (!check.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection(check)}. Nothing was written.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tfor (const entry of plan.writes) {\n\t\tif (!isAllowedMode(entry.mode)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${entry.path} asks for file mode ${(entry.mode ?? 0).toString(8)}, and only 644 and 755 are accepted. Nothing was written.`,\n\t\t\t);\n\t\t}\n\t\tconst bytes = contents.get(entry.path);\n\t\tif (!bytes) {\n\t\t\tthrow new Error(\n\t\t\t\t`The downloaded bundle is missing ${entry.path}. Nothing was written.`,\n\t\t\t);\n\t\t}\n\t\tconst actual = createHash(\"sha256\").update(bytes).digest(\"hex\");\n\t\tif (actual !== entry.sha256) {\n\t\t\tthrow new Error(\n\t\t\t\t`Checksum mismatch for ${entry.path}: the published snapshot expects ${entry.sha256} and the downloaded bundle contains ${actual}. Nothing was written.`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// ---- Phase 2: apply --------------------------------------------------\n\tconst written: string[] = [];\n\tconst deleted: string[] = [];\n\tconst remoded: string[] = [];\n\tconst keptModified: string[] = [];\n\tconst keptEdited: string[] = [];\n\n\tfor (const entry of plan.writes) {\n\t\t// Planning ran before the download and the extraction, and an editor\n\t\t// saving in that window must not lose the save: the same window the\n\t\t// expected hash on each delete below closes (Decision 37). What is\n\t\t// left is the moment between this read and the rename, which no\n\t\t// portable file API closes.\n\t\t//\n\t\t// A re-hash of `null` — the target vanished after planning — proceeds\n\t\t// with the write rather than counting as kept: planning would have\n\t\t// called that same absence `added`, not a conflicting edit, so this\n\t\t// keeps apply time agreeing with plan time (review finding, Fizzy\n\t\t// #2540).\n\t\tif (input.keepLocalEdits && entry.localSha256 !== undefined) {\n\t\t\tconst currentLocalHash = await hashLocalFile(root, entry.path);\n\t\t\tif (\n\t\t\t\tcurrentLocalHash !== null &&\n\t\t\t\tcurrentLocalHash !== entry.localSha256\n\t\t\t) {\n\t\t\t\tkeptEdited.push(entry.path);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t// Non-null: phase 1 refused the whole plan if any byte was missing.\n\t\tconst bytes = contents.get(entry.path) as Uint8Array;\n\t\tawait writeFileSafely({\n\t\t\troot,\n\t\t\trelativePath: entry.path,\n\t\t\tbytes,\n\t\t\tmode: entry.mode ?? null,\n\t\t});\n\t\twritten.push(entry.path);\n\t}\n\n\t// A file whose bytes already match still has to carry the published\n\t// mode: a script that arrives non-executable is as broken as one that\n\t// arrives with the wrong contents, and `verified` would otherwise never\n\t// fix it.\n\tfor (const entry of plan.verified) {\n\t\tif (await applyMode(root, entry)) {\n\t\t\tremoded.push(entry.path);\n\t\t}\n\t}\n\n\tfor (const entry of plan.deletes) {\n\t\t// The hash the plan decided on travels with the unlink. Planning ran\n\t\t// before the download, the extraction and every write above, and an\n\t\t// editor saving in that window would otherwise have its work deleted\n\t\t// on the strength of a hash that no longer describes the file.\n\t\tif (entry.sha256 === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to delete ${entry.path}: the plan carries no hash for it.`,\n\t\t\t);\n\t\t}\n\t\tconst outcome = await deleteFileSafely(root, entry.path, entry.sha256);\n\t\tif (outcome === \"deleted\") {\n\t\t\tdeleted.push(entry.path);\n\t\t} else if (outcome === \"modified\") {\n\t\t\tkeptModified.push(entry.path);\n\t\t}\n\t}\n\t// Directories are deliberately left behind. An empty directory is\n\t// harmless; removing one races with anything the developer put in it.\n\n\treturn { written, deleted, remoded, keptModified, keptEdited };\n}\n\n/** Returns true when a mode was actually applied. */\nasync function applyMode(root: string, entry: PlanEntry): Promise<boolean> {\n\tconst bits = permissionBits(entry.mode);\n\tif (bits === null || process.platform === \"win32\") {\n\t\treturn false;\n\t}\n\tif (!isAllowedMode(entry.mode)) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${entry.path} asks for file mode ${(entry.mode ?? 0).toString(8)}, and only 644 and 755 are accepted.`,\n\t\t);\n\t}\n\t// The same guard the writes use: a `chmod` is a mutation too, and phase 1\n\t// proving this path was a regular file does not make it one now.\n\tconst check = await assertWritableTarget(root, entry.path);\n\tif (!check.ok) {\n\t\tthrow new Error(`Refusing to sync: ${describeRejection(check)}.`);\n\t}\n\ttry {\n\t\tawait chmod(check.path, bits);\n\t\treturn true;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\treturn false;\n\t\t}\n\t\tthrow error;\n\t}\n}\n","/**\n * What a sync would do, decided against the LOCAL TREE and not only the lock.\n *\n * The lock says what the last sync wrote; the working tree says what is\n * actually there now. Planning from the lock alone gets both interesting\n * cases wrong — a file the developer edited since the sync would be silently\n * overwritten with no notice, and a file they deleted would never come back\n * because the lock still claims it is present. So every path is hashed.\n *\n * Eight outcomes, and the distinctions between them are the whole point:\n *\n * verified local bytes already equal the published bytes — no write\n * added nothing local — a new file\n * updated local matches the lock, so this is the sync's own file\n * moving forward\n * replaced local matches neither the lock nor the manifest, and the\n * caller did not ask to keep local edits (`sync --repair`) —\n * they are about to be overwritten, and the report says so\n * kept-edited the same, when the caller keeps local edits (every `sync`\n * without `--repair`, spec §6.4) — the file stays as it is\n * and the lock records the published hash with `kept: true`\n * deleted gone from the manifest, and local still matches the lock,\n * so the sync wrote it and may remove it\n * kept-modified gone from the manifest, but local differs from the lock —\n * the developer changed it, so it stays\n * kept-renamed gone from the manifest under this spelling, but the\n * manifest names the same physical file another way — the\n * write for the new spelling is the update, so the old one\n * must not be unlinked afterwards\n *\n * A path absent from the lock is never deleted, whatever it is — and a\n * reserved path (`.git/`, `.fabric/`, the tool's own Claude settings file) is\n * refused outright wherever it appears, because the lock is an unauthenticated\n * file in the checkout (see `lock.ts`) and those are the paths a tampered one\n * would most want to name.\n */\nimport { createHash } from \"node:crypto\";\nimport type {\n\tInstructionManifestEntry,\n\tPublishedInstructionSource,\n} from \"@fabricorg/sdk\";\nimport { type InstructionsLock, LOCK_VERSION } from \"./lock.js\";\nimport {\n\tcheckRelativePath,\n\tcollisionKey,\n\tdescribeRejection,\n\tfindCollision,\n\tisReservedPath,\n} from \"./paths.js\";\nimport { readFileSafely } from \"./safe-write.js\";\n\ntype PlanAction =\n\t| \"verified\"\n\t| \"added\"\n\t| \"updated\"\n\t| \"replaced\"\n\t| \"deleted\"\n\t| \"kept-modified\"\n\t| \"kept-renamed\"\n\t| \"kept-edited\";\n\nexport interface PlanEntry {\n\tpath: string;\n\taction: PlanAction;\n\t/** The published hash, for everything the manifest still carries. */\n\tsha256?: string;\n\tmode?: number | null;\n\t/**\n\t * For a manifest entry that is not `verified`: the hash the planner read\n\t * at this path, or null when nothing was there. A keeping apply re-hashes\n\t * before it writes and leaves the file alone when it changed since\n\t * (Decision 37).\n\t */\n\tlocalSha256?: string | null;\n}\n\nexport interface SyncPlan {\n\tentries: PlanEntry[];\n\t/** Entries whose bytes must be fetched and written. */\n\twrites: PlanEntry[];\n\t/** Entries to unlink. Always a subset of the previous lock. */\n\tdeletes: PlanEntry[];\n\tverified: PlanEntry[];\n\tkeptModified: PlanEntry[];\n\t/**\n\t * Lock paths that are the same physical file as a manifest path under a\n\t * different spelling. Never deleted; reported so the old spelling is not\n\t * a surprise on the filesystems where it survives.\n\t */\n\tkeptRenamed: PlanEntry[];\n\t/**\n\t * Still-published paths whose local bytes match neither the lock nor the\n\t * manifest, left alone because the caller keeps local edits. Never\n\t * written; the lock records them with the published hash and\n\t * `kept: true`.\n\t */\n\tkeptEdited: PlanEntry[];\n}\n\n/**\n * Hex sha256 of a local file, or `null` when nothing is there.\n *\n * Every read goes through `readFileSafely`, the same guarded walk the writes\n * use: no symlinked component anywhere on the way down, nothing resolving\n * outside the destination, a regular file or nothing at all. A link pointing\n * at a file that happens to hold the published bytes used to hash EQUAL and\n * become `verified` — no write, no check, and a lock written over a path that\n * is not a file.\n */\nexport async function hashLocalFile(\n\troot: string,\n\trelativePath: string,\n): Promise<string | null> {\n\tconst read = await readFileSafely(root, relativePath);\n\treturn read === null\n\t\t? null\n\t\t: createHash(\"sha256\").update(read.bytes).digest(\"hex\");\n}\n\nfunction lockPaths(lock: InstructionsLock | null): string[] {\n\treturn lock === null ? [] : Object.keys(lock.files);\n}\n\n/**\n * Every path the lock names has to survive the same checks a manifest path\n * does, plus the reserved-root rule — a hand-edited or accidentally\n * committed lock is exactly how `.git/config` would otherwise become an\n * unlink target with a hash anyone can read off disk.\n */\nfunction assertSafeLockPaths(paths: readonly string[]): void {\n\tfor (const lockedPath of paths) {\n\t\tconst check = checkRelativePath(lockedPath);\n\t\tif (!check.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection(check)}. The lock names a path this tool will not touch.`,\n\t\t\t);\n\t\t}\n\t\tif (isReservedPath(lockedPath)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to sync: ${describeRejection({\n\t\t\t\t\tok: false,\n\t\t\t\t\treason: \"reserved_path\",\n\t\t\t\t\tdetail: lockedPath,\n\t\t\t\t})}. The lock names a path this tool will not touch.`,\n\t\t\t);\n\t\t}\n\t}\n\tconst collision = findCollision(paths);\n\tif (collision !== null) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${describeRejection({\n\t\t\t\tok: false,\n\t\t\t\treason: \"collision\",\n\t\t\t\tdetail: `${collision.first} and ${collision.second}`,\n\t\t\t})}. The lock names two paths this tool cannot tell apart.`,\n\t\t);\n\t}\n}\n\n/**\n * Does the working tree still hold what the lock says it holds?\n *\n * The server answers \"unchanged\" by comparing digests, and a digest describes\n * the PUBLISHED snapshot — it says nothing about the checkout. Accepting that\n * answer as \"nothing to do\" meant an edited, deleted or chmod-ed instruction\n * file stayed that way until some later publication happened to move the\n * digest. For a feature whose point is that an agent reads the same\n * instructions everyone else does, that is the failure that matters most:\n * tampering persists and the tool reports success.\n *\n * Returns the paths that no longer match, as reasons a person can act on.\n * Never throws: a symlink or a directory standing where a file should be is\n * drift to REPORT, and the re-plan that follows is what refuses it.\n */\nexport async function verifyLedger(input: {\n\t/** An already-canonical root — `resolveDestinationRoot` or `resolveExistingRoot`. */\n\troot: string;\n\tlock: InstructionsLock;\n}): Promise<string[]> {\n\tconst drift = await findLedgerDrift(input);\n\treturn drift.map(describeLedgerDrift);\n}\n\n/**\n * Why one locked path no longer matches, as a class a caller can branch on.\n * `refused` is a guarded-read refusal: a symlinked ancestor, a directory\n * where a file belongs, a path resolving outside the root.\n */\nexport type LedgerDriftReason = \"missing\" | \"edited\" | \"mode\" | \"refused\";\n\nexport interface LedgerDrift {\n\tpath: string;\n\treason: LedgerDriftReason;\n\t/** The parenthetical `verifyLedger` prints after the path. */\n\tdetail: string;\n\t/**\n\t * The lock marks this path as a local edit an earlier sync kept (spec\n\t * §6.4). An `edited` entry with this set has the detail `kept`.\n\t */\n\tkept: boolean;\n}\n\n/** One drift entry as `verifyLedger` prints it: `AGENTS.md (edited)`. */\nexport function describeLedgerDrift(entry: LedgerDrift): string {\n\treturn `${entry.path} (${entry.detail})`;\n}\n\n/**\n * `verifyLedger`, structured: one entry per locked path that no longer\n * matches, with its reason as a class rather than folded into a sentence.\n * `fabric instructions doctor` reports these as check items and must not\n * repeat a refusal's message (it names local paths), so it needs the class.\n */\nexport async function findLedgerDrift(input: {\n\t/** An already-canonical root — `resolveDestinationRoot` or `resolveExistingRoot`. */\n\troot: string;\n\tlock: InstructionsLock;\n}): Promise<LedgerDrift[]> {\n\t// FIRST, before a single path is joined or opened. This function reads\n\t// paths that come out of an unauthenticated file in the checkout, and it\n\t// used to read them raw: `../outside` reached outside the destination, and\n\t// `rules/` replaced by a symlink was followed wherever it pointed. The\n\t// same validation `computeSyncPlan` runs, run before anything is touched.\n\tassertSafeLockPaths(lockPaths(input.lock));\n\n\tconst drifted: LedgerDrift[] = [];\n\tfor (const [lockedPath, locked] of Object.entries(input.lock.files)) {\n\t\t// A refusal from the guarded reader — a symlinked ancestor, a\n\t\t// directory where a file belongs — is drift, not a crash: the caller\n\t\t// re-plans, and planning refuses it there with the same message.\n\t\tlet read: Awaited<ReturnType<typeof readFileSafely>>;\n\t\ttry {\n\t\t\tread = await readFileSafely(input.root, lockedPath);\n\t\t} catch (error) {\n\t\t\tdrifted.push({\n\t\t\t\tpath: lockedPath,\n\t\t\t\treason: \"refused\",\n\t\t\t\tdetail:\n\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t\t\t.replace(/^Refusing to sync: /, \"\")\n\t\t\t\t\t\t\t\t.replace(/\\.$/, \"\")\n\t\t\t\t\t\t: String(error),\n\t\t\t\tkept: locked.kept === true,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (read === null) {\n\t\t\tdrifted.push({\n\t\t\t\tpath: lockedPath,\n\t\t\t\treason: \"missing\",\n\t\t\t\tdetail: \"missing\",\n\t\t\t\tkept: locked.kept === true,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst actual = createHash(\"sha256\").update(read.bytes).digest(\"hex\");\n\t\tif (actual !== locked.sha256) {\n\t\t\tdrifted.push({\n\t\t\t\tpath: lockedPath,\n\t\t\t\treason: \"edited\",\n\t\t\t\tdetail: locked.kept === true ? \"kept\" : \"edited\",\n\t\t\t\tkept: locked.kept === true,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\t// Modes are meaningless on Windows and a published `0755` that arrived\n\t\t// as `0644` leaves a script that will not run, so this is checked\n\t\t// wherever it can be.\n\t\tif (\n\t\t\tprocess.platform !== \"win32\" &&\n\t\t\tlocked.mode !== null &&\n\t\t\t(read.mode & 0o7777) !== (locked.mode & 0o7777)\n\t\t) {\n\t\t\tdrifted.push({\n\t\t\t\tpath: lockedPath,\n\t\t\t\treason: \"mode\",\n\t\t\t\tdetail: `mode ${(read.mode & 0o7777).toString(8)}, published as ${(locked.mode & 0o7777).toString(8)}`,\n\t\t\t\tkept: locked.kept === true,\n\t\t\t});\n\t\t}\n\t}\n\treturn drifted;\n}\n\nexport async function computeSyncPlan(\n\tinput: {\n\t\t/** An already-canonical root, as every guarded read resolves against it. */\n\t\tdestination: string;\n\t\tmanifest: InstructionManifestEntry[];\n\t\tlock: InstructionsLock | null;\n\t},\n\toptions: {\n\t\t/**\n\t\t * Leave a still-published file whose local bytes match neither the\n\t\t * lock nor the manifest as it is (`kept-edited`) instead of\n\t\t * overwriting it (`replaced`). The CLI passes `true` unless\n\t\t * `sync --repair` was given (spec §6.4).\n\t\t */\n\t\tkeepLocalEdits?: boolean;\n\t} = {},\n): Promise<SyncPlan> {\n\tconst { destination, manifest, lock } = input;\n\n\t// `assertValidManifest` has already checked every manifest entry's path,\n\t// shape, mode, uniqueness, count and digest before this is called. What\n\t// is re-checked here is the LOCK, which no server validated: it is a\n\t// plain file in the checkout, and it is the only thing that can authorise\n\t// a delete.\n\tassertSafeLockPaths(lockPaths(lock));\n\n\t// A Map, not the parsed object: a manifest path of `constructor` or\n\t// `toString` reads a value off `Object.prototype` when the lookup is a\n\t// plain property access, and `__proto__` does not read back at all.\n\tconst lockedFiles = new Map(Object.entries(lock?.files ?? {}));\n\tconst manifestPaths = new Set(manifest.map((entry) => entry.path));\n\t// The union, not the two sets separately. Each list is internally free of\n\t// collisions by now, which says nothing about a path appearing in one under\n\t// a spelling the other uses differently — and that case is a RENAME, not a\n\t// conflict. See `isRenameOf` below for what it costs to get wrong.\n\tconst manifestKeys = new Map(\n\t\tmanifest.map(\n\t\t\t(entry) => [collisionKey(entry.path), entry.path] as const,\n\t\t),\n\t);\n\t// The lock's own collision keys. A manifest entry whose EXACT spelling the\n\t// lock does not know may still be the same file the lock already tracks\n\t// under a different spelling — a case-only or Unicode-normalization-only\n\t// rename — and on the filesystems that fold those, reading the manifest's\n\t// spelling returns the OLD spelling's bytes. Without this fallback that\n\t// read looked like a local edit with nothing to compare against, so in\n\t// keep mode the rename's write never happened and the file stayed stale\n\t// until `--repair` (review finding, Fizzy #2540).\n\tconst lockedKeys = new Map(\n\t\tArray.from(lockedFiles.keys()).map(\n\t\t\t(lockedPath) => [collisionKey(lockedPath), lockedPath] as const,\n\t\t),\n\t);\n\tconst entries: PlanEntry[] = [];\n\n\tfor (const entry of manifest) {\n\t\tconst localHash = await hashLocalFile(destination, entry.path);\n\t\tif (localHash === entry.sha256) {\n\t\t\tentries.push({\n\t\t\t\tpath: entry.path,\n\t\t\t\taction: \"verified\",\n\t\t\t\tsha256: entry.sha256,\n\t\t\t\tmode: entry.mode,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst renamedFrom = lockedKeys.get(collisionKey(entry.path));\n\t\tconst locked =\n\t\t\tlockedFiles.get(entry.path) ??\n\t\t\t(renamedFrom === undefined\n\t\t\t\t? undefined\n\t\t\t\t: lockedFiles.get(renamedFrom));\n\t\tconst lockedHash = locked?.sha256;\n\t\t// A path the lock does not name under this spelling OR a renamed one\n\t\t// (a file that was there before the first sync) has no `lockedHash`,\n\t\t// so it lands here too: it is the developer's until `--repair` says\n\t\t// otherwise.\n\t\tconst action: PlanAction =\n\t\t\tlocalHash === null\n\t\t\t\t? \"added\"\n\t\t\t\t: localHash === lockedHash\n\t\t\t\t\t? \"updated\"\n\t\t\t\t\t: options.keepLocalEdits\n\t\t\t\t\t\t? \"kept-edited\"\n\t\t\t\t\t\t: \"replaced\";\n\t\tentries.push({\n\t\t\tpath: entry.path,\n\t\t\taction,\n\t\t\tsha256: entry.sha256,\n\t\t\tmode: entry.mode,\n\t\t\t// What the plan saw here, so a keeping apply can tell a save that\n\t\t\t// landed after planning (Decision 37).\n\t\t\tlocalSha256: localHash,\n\t\t});\n\t}\n\n\tfor (const [lockedPath, locked] of lockedFiles) {\n\t\tif (manifestPaths.has(lockedPath)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// `README.md` in the lock and `readme.md` in the manifest are two\n\t\t// spellings of one file wherever the filesystem folds case or\n\t\t// normalises names — and writes run before deletes, so planning a\n\t\t// delete here unlinked the file the same run had just written and then\n\t\t// wrote a lock claiming it was there. The manifest spelling's own write\n\t\t// IS the update; this one must not be touched. On Linux the two really\n\t\t// are separate files, and skipping the delete is still the right answer:\n\t\t// a tool that deletes a file because another file's name resembles it\n\t\t// would be worse than one that leaves a stale copy and says so.\n\t\tconst renamedTo = manifestKeys.get(collisionKey(lockedPath));\n\t\tif (renamedTo !== undefined) {\n\t\t\tentries.push({\n\t\t\t\tpath: lockedPath,\n\t\t\t\taction: \"kept-renamed\",\n\t\t\t\tsha256: locked.sha256,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst localHash = await hashLocalFile(destination, lockedPath);\n\t\tif (localHash === null) {\n\t\t\tcontinue;\n\t\t}\n\t\tentries.push({\n\t\t\tpath: lockedPath,\n\t\t\taction: localHash === locked.sha256 ? \"deleted\" : \"kept-modified\",\n\t\t\t// Carried so the unlink can prove it is still removing the file\n\t\t\t// this hash described, rather than whatever is at the path by the\n\t\t\t// time the writes are done.\n\t\t\tsha256: locked.sha256,\n\t\t});\n\t}\n\n\tentries.sort((a, b) => a.path.localeCompare(b.path));\n\n\treturn {\n\t\tentries,\n\t\twrites: entries.filter(\n\t\t\t(entry) =>\n\t\t\t\tentry.action === \"added\" ||\n\t\t\t\tentry.action === \"updated\" ||\n\t\t\t\tentry.action === \"replaced\",\n\t\t),\n\t\tdeletes: entries.filter((entry) => entry.action === \"deleted\"),\n\t\tverified: entries.filter((entry) => entry.action === \"verified\"),\n\t\tkeptModified: entries.filter(\n\t\t\t(entry) => entry.action === \"kept-modified\",\n\t\t),\n\t\tkeptRenamed: entries.filter((entry) => entry.action === \"kept-renamed\"),\n\t\tkeptEdited: entries.filter((entry) => entry.action === \"kept-edited\"),\n\t};\n}\n\n/** The lock the sync should leave behind once `plan` has been applied. */\nexport function nextLock(input: {\n\tprojectId: string;\n\tsnapshot: {\n\t\tid: string;\n\t\tversion: number;\n\t\tdigest: string;\n\t\tsource?: PublishedInstructionSource;\n\t};\n\tmanifest: InstructionManifestEntry[];\n\t/**\n\t * Paths the plan kept as local edits. Their entries still carry the\n\t * PUBLISHED hash and mode, so `push` diffs the edit against the published\n\t * file, plus `kept: true`, so `check --verify` and doctor can say so.\n\t */\n\tkept?: readonly string[];\n\tnow?: Date;\n}): InstructionsLock {\n\t// `Object.fromEntries` rather than assignment into `{}`: assigning\n\t// `files[\"__proto__\"]` sets the prototype instead of creating an own\n\t// property, so a published file called `__proto__` was written to disk and\n\t// then left out of the ledger — and a later snapshot that dropped it could\n\t// not prove the sync had created it.\n\tconst kept = new Set(input.kept ?? []);\n\tconst files: InstructionsLock[\"files\"] = Object.fromEntries(\n\t\tinput.manifest.map((entry) => [\n\t\t\tentry.path,\n\t\t\tkept.has(entry.path)\n\t\t\t\t? {\n\t\t\t\t\t\tsha256: entry.sha256,\n\t\t\t\t\t\tmode: entry.mode,\n\t\t\t\t\t\tkept: true as const,\n\t\t\t\t\t}\n\t\t\t\t: { sha256: entry.sha256, mode: entry.mode },\n\t\t]),\n\t);\n\treturn {\n\t\tversion: LOCK_VERSION,\n\t\tprojectId: input.projectId,\n\t\tsnapshotId: input.snapshot.id,\n\t\tsnapshotVersion: input.snapshot.version,\n\t\tdigest: input.snapshot.digest,\n\t\tsyncedAt: (input.now ?? new Date()).toISOString(),\n\t\tfiles,\n\t\t...(input.snapshot.source ? { source: input.snapshot.source } : {}),\n\t};\n}\n\n/**\n * `lock` with `kept: true` on exactly `paths` and on no other entry, for a\n * run that keeps local edits without a manifest in hand (the server answered\n * \"unchanged\"). A marker whose file matches the published bytes again, put\n * back by hand, is dropped, so the lock never claims an edit that is gone\n * (Decision 41). Everything else, including `syncedAt`, is left as it was:\n * nothing was synced, only recorded.\n *\n * The result is always at `LOCK_VERSION`, because only a version 2 lock may\n * carry a marker (Decision 38). `changed` is true only when a marker was\n * added or dropped, so a run that finds the same edits again writes nothing.\n * A copy, so the caller's parsed lock is untouched.\n */\nexport function reconcileKeptInLock(\n\tlock: InstructionsLock,\n\tpaths: readonly string[],\n): { lock: InstructionsLock; changed: boolean } {\n\tconst kept = new Set(paths);\n\tlet changed = false;\n\t// `Object.fromEntries` for the same `__proto__` reason as `nextLock`.\n\tconst files: InstructionsLock[\"files\"] = Object.fromEntries(\n\t\tObject.entries(lock.files).map(([lockedPath, entry]) => {\n\t\t\tconst keep = kept.has(lockedPath);\n\t\t\tif (keep === (entry.kept === true)) {\n\t\t\t\treturn [lockedPath, entry];\n\t\t\t}\n\t\t\tchanged = true;\n\t\t\treturn [\n\t\t\t\tlockedPath,\n\t\t\t\tkeep\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tsha256: entry.sha256,\n\t\t\t\t\t\t\tmode: entry.mode,\n\t\t\t\t\t\t\tkept: true as const,\n\t\t\t\t\t\t}\n\t\t\t\t\t: { sha256: entry.sha256, mode: entry.mode },\n\t\t\t];\n\t\t}),\n\t);\n\treturn { lock: { ...lock, version: LOCK_VERSION, files }, changed };\n}\n","/**\n * `<dest>/.fabric/instructions.lock` — what the last sync wrote.\n *\n * ## What the lock is, and what it is not\n *\n * It is a CONTENT LEDGER: a list of paths with the hash each one had when\n * this tool last wrote it. It is the only reason the sync may delete\n * anything — a path must be in the ledger AND still hash to what the ledger\n * recorded before it can be removed.\n *\n * It is NOT authenticated. It is a plain JSON file inside the checkout, so\n * anything that can write there can write it. That bounds what a tampered\n * lock can do rather than preventing it: an attacker who can already edit\n * files in the tree can make the next sync delete a file whose CURRENT\n * content hash they name correctly. They cannot make it write anywhere new,\n * because writes come from the server manifest, and they cannot name\n * `.git/**` or `.fabric/**` at all (`isReservedPath`). Closing the rest\n * needs a ledger stored outside the checkout, which is a larger change than\n * this feature.\n *\n * The lock is rewritten LAST, after every write has succeeded. A ledger\n * naming files that are not there would authorise deleting whatever is in\n * their place on the next run.\n */\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { PublishedInstructionSource } from \"@fabricorg/sdk\";\nimport { readFileSafely, writeFileSafely } from \"./safe-write.js\";\n\nexport const LOCK_DIRECTORY = \".fabric\";\nexport const LOCK_FILENAME = \"instructions.lock\";\n\n/**\n * The version this build writes. Version 2 adds `LockFileEntry.kept` (spec\n * §6.4, Decision 38). Version 3 adds `InstructionsLock.source` (Fizzy #2709):\n * the published snapshot's provenance (a repository sync's ref, commit and\n * whether it is still the project's CURRENT sync configuration, or plain\n * `UPLOAD`), absent when the server did not report one. Every released build\n * reads only the versions it knows and refuses anything else whole, so a\n * marker or field a build cannot see is never acted on, and never silently\n * overwritten, by one that cannot see it. This build reads versions 1\n * through 3.\n */\nexport const LOCK_VERSION = 3;\n\n/** Every lock version this build reads. It writes only `LOCK_VERSION`. */\nconst READABLE_LOCK_VERSIONS: readonly number[] = [1, 2, LOCK_VERSION];\n\n/** The lock's own path, relative to the destination — never from a manifest. */\nconst LOCK_RELATIVE_PATH = `${LOCK_DIRECTORY}/${LOCK_FILENAME}`;\n\nconst SHA256_HEX = /^[0-9a-f]{64}$/;\n\ninterface LockFileEntry {\n\tsha256: string;\n\t/** POSIX mode as published, or null when the snapshot recorded none. */\n\tmode: number | null;\n\t/**\n\t * Present only when a sync left a local edit at this path in place\n\t * (`fabric instructions sync` without `--repair`, spec §6.4). `sha256`\n\t * and `mode` are still the PUBLISHED values. Only a version 2 lock may\n\t * carry it.\n\t */\n\tkept?: true;\n}\n\nexport interface InstructionsLock {\n\tversion: number;\n\tprojectId: string;\n\tsnapshotId: string;\n\tsnapshotVersion: number;\n\tdigest: string;\n\t/** ISO 8601 timestamp of the sync that wrote this lock. */\n\tsyncedAt: string;\n\t/** Every path that sync wrote or verified — the manifest at that time. */\n\tfiles: Record<string, LockFileEntry>;\n\t/**\n\t * The published snapshot's provenance, as `getPublished` reported it at\n\t * sync time. Absent when the server did not report one (an older server) —\n\t * never defaulted, so an absent value is never mistaken for `UPLOAD`. Only\n\t * a version 3 lock may carry it. The repository itself (owner/name, host,\n\t * root path) is NOT recorded here: it is the project's current\n\t * configuration, not this snapshot's, and is not part of the lock.\n\t */\n\tsource?: PublishedInstructionSource;\n}\n\nexport function lockPath(destination: string): string {\n\treturn path.join(destination, LOCK_DIRECTORY, LOCK_FILENAME);\n}\n\n/**\n * The lock, or `null` when this tree has never been synced.\n *\n * A lock that exists but does not validate is an ERROR and never a `null`.\n * Treating a damaged ledger as \"never synced\" would orphan every file the\n * previous sync wrote and hide the damage; the caller stops and says so.\n */\nexport async function readLock(\n\tdestination: string,\n): Promise<InstructionsLock | null> {\n\tconst file = lockPath(destination);\n\tlet raw: string;\n\ttry {\n\t\traw = await readFile(file, \"utf8\");\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\treturn null;\n\t\t}\n\t\tthrow error;\n\t}\n\treturn parseLock(raw, file);\n}\n\n/**\n * The validating half of `readLock`: the text of a lock file, as a lock, or\n * an error saying why it is not one. `source` names the file in that error.\n */\nexport function parseLock(\n\ttext: string,\n\tsource: string = LOCK_RELATIVE_PATH,\n): InstructionsLock {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(text);\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`${source} is unreadable: it is not valid JSON. Delete it to start from a clean sync.`,\n\t\t);\n\t}\n\tconst problem = lockProblem(parsed);\n\tif (problem !== null) {\n\t\tthrow new Error(\n\t\t\t`${source} is unreadable: ${problem}. Delete it to start from a clean sync.`,\n\t\t);\n\t}\n\treturn parsed as InstructionsLock;\n}\n\n/**\n * `readFileSafely` refused the lock before a byte of it was parsed: a\n * symlinked `.fabric` or lock, something that is not a regular file, or a\n * file over the caller's bound. The guard's own error is the `cause`.\n */\nexport class LockReadRefusedError extends Error {\n\tconstructor(options: { cause: unknown }) {\n\t\tsuper(`${LOCK_RELATIVE_PATH} could not be read safely.`, options);\n\t\tthis.name = \"LockReadRefusedError\";\n\t}\n}\n\n/**\n * `readLock` for a reader that must not be steered outside `root`.\n *\n * `readLock` opens `<destination>/.fabric/instructions.lock` with a plain\n * `readFile`, which follows a symlinked `.fabric` or lock to wherever it\n * points and reads the whole file. This goes through `readFileSafely`\n * instead: descriptor-based, refusing a symlinked ancestor or final\n * component, refusing anything but a regular file, and reading at most\n * `maxBytes`. A refusal throws `LockReadRefusedError`; a file that reads but\n * does not validate throws `parseLock`'s error. `root` must already be\n * canonical, as for every guarded read.\n */\nexport async function readLockSafely(\n\troot: string,\n\toptions: { maxBytes: number },\n): Promise<InstructionsLock | null> {\n\tlet read: Awaited<ReturnType<typeof readFileSafely>>;\n\ttry {\n\t\tread = await readFileSafely(root, LOCK_RELATIVE_PATH, {\n\t\t\tmaxBytes: options.maxBytes,\n\t\t});\n\t} catch (error) {\n\t\tthrow new LockReadRefusedError({ cause: error });\n\t}\n\tif (read === null) {\n\t\treturn null;\n\t}\n\t// The decoder `readFile(file, \"utf8\")` uses, so both readers see the same text.\n\tconst text = Buffer.from(\n\t\tread.bytes.buffer,\n\t\tread.bytes.byteOffset,\n\t\tread.bytes.byteLength,\n\t).toString(\"utf8\");\n\treturn parseLock(text, lockPath(root));\n}\n\n/** Pretty JSON with LF endings and a trailing newline, so a diff of it reads. */\nfunction serializeLock(lock: InstructionsLock): string {\n\treturn `${JSON.stringify(lock, null, 2).replace(/\\r\\n/g, \"\\n\")}\\n`;\n}\n\n/**\n * Write the lock through the same guarded writer as every instruction file.\n * `root` is an already-canonical destination from `resolveDestinationRoot`:\n * a `.fabric -> ..` symlink is how the lock write used to escape the tree.\n */\nexport async function writeLock(\n\troot: string,\n\tlock: InstructionsLock,\n): Promise<void> {\n\tawait writeFileSafely({\n\t\troot,\n\t\trelativePath: LOCK_RELATIVE_PATH,\n\t\tbytes: new TextEncoder().encode(serializeLock(lock)),\n\t});\n}\n\n/**\n * Why this value is not a lock, or `null` when it is one.\n *\n * Every field is checked, including `version`: a future lock this build does\n * not understand must stop the run rather than be half-read.\n */\nfunction lockProblem(value: unknown): string | null {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n\t\treturn \"it is not a JSON object\";\n\t}\n\tconst candidate = value as Record<string, unknown>;\n\n\tif (\n\t\ttypeof candidate.version !== \"number\" ||\n\t\t!READABLE_LOCK_VERSIONS.includes(candidate.version)\n\t) {\n\t\treturn `its version is ${JSON.stringify(candidate.version)} and this build reads versions ${READABLE_LOCK_VERSIONS.join(\" and \")}`;\n\t}\n\tfor (const field of [\n\t\t\"projectId\",\n\t\t\"snapshotId\",\n\t\t\"digest\",\n\t\t\"syncedAt\",\n\t] as const) {\n\t\tconst actual = candidate[field];\n\t\tif (typeof actual !== \"string\" || actual.length === 0) {\n\t\t\treturn `its \"${field}\" is not a non-empty string`;\n\t\t}\n\t}\n\tif (\n\t\ttypeof candidate.snapshotVersion !== \"number\" ||\n\t\t!Number.isInteger(candidate.snapshotVersion) ||\n\t\tcandidate.snapshotVersion < 0\n\t) {\n\t\treturn 'its \"snapshotVersion\" is not a non-negative integer';\n\t}\n\tif (\n\t\ttypeof candidate.files !== \"object\" ||\n\t\tcandidate.files === null ||\n\t\tArray.isArray(candidate.files)\n\t) {\n\t\treturn 'its \"files\" is not an object';\n\t}\n\n\tfor (const [filePath, entry] of Object.entries(\n\t\tcandidate.files as Record<string, unknown>,\n\t)) {\n\t\tif (\n\t\t\ttypeof entry !== \"object\" ||\n\t\t\tentry === null ||\n\t\t\tArray.isArray(entry)\n\t\t) {\n\t\t\treturn `its entry for ${JSON.stringify(filePath)} is not an object`;\n\t\t}\n\t\tconst record = entry as Record<string, unknown>;\n\t\tif (\n\t\t\ttypeof record.sha256 !== \"string\" ||\n\t\t\t!SHA256_HEX.test(record.sha256)\n\t\t) {\n\t\t\treturn `its entry for ${JSON.stringify(filePath)} has no 64-character hex sha256`;\n\t\t}\n\t\tif (\n\t\t\trecord.mode !== null &&\n\t\t\t(typeof record.mode !== \"number\" ||\n\t\t\t\t!Number.isInteger(record.mode) ||\n\t\t\t\trecord.mode < 0)\n\t\t) {\n\t\t\treturn `its entry for ${JSON.stringify(filePath)} has a mode that is neither null nor a non-negative integer`;\n\t\t}\n\t\tif (record.kept !== undefined) {\n\t\t\tif (record.kept !== true) {\n\t\t\t\treturn `its entry for ${JSON.stringify(filePath)} has a \"kept\" that is not true`;\n\t\t\t}\n\t\t\t// A released build reads version 1 and would ignore the marker,\n\t\t\t// so a version 1 lock carrying one is not a lock this tool wrote.\n\t\t\tif (candidate.version === 1) {\n\t\t\t\treturn `its entry for ${JSON.stringify(filePath)} has a \"kept\" marker, which a version 1 lock cannot carry`;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (candidate.source !== undefined) {\n\t\t// Same precedent as `kept` above: a marker introduced by a later\n\t\t// version must not be silently accepted from an earlier one, whether\n\t\t// or not this build itself understands it — a version 1 or 2 lock\n\t\t// carrying `source` is not a lock this tool wrote.\n\t\tif (candidate.version !== 3) {\n\t\t\treturn `it carries a \"source\", which only a version 3 lock can carry (this one is version ${candidate.version})`;\n\t\t}\n\t\tconst problem = sourceProblem(candidate.source);\n\t\tif (problem !== null) {\n\t\t\treturn `its \"source\" ${problem}`;\n\t\t}\n\t}\n\treturn null;\n}\n\n/** Lowercase hex, 7 to 64 characters — a short or full git commit sha. */\nconst COMMIT_SHA_HEX = /^[0-9a-f]{7,64}$/;\n\n/**\n * Why `value` is not a valid `PublishedInstructionSource`, or `null` when it\n * is one. Each arm's key set is exact, not merely a minimum: an \"UPLOAD\"\n * source carries only `kind`, a \"REPOSITORY\" one exactly `kind`, `ref`,\n * `commitSha` and `current` — an extra key is refused rather than ignored,\n * since a future version of this shape would otherwise be silently\n * misread by a build that only checks for the keys it knows (Fizzy #2709\n * review).\n */\nfunction sourceProblem(value: unknown): string | null {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n\t\treturn \"is not an object\";\n\t}\n\tconst source = value as Record<string, unknown>;\n\tconst keys = Object.keys(source);\n\tif (source.kind === \"UPLOAD\") {\n\t\tconst extra = keys.filter((key) => key !== \"kind\");\n\t\tif (extra.length > 0) {\n\t\t\treturn `has a key besides \"kind\" on an \"UPLOAD\" source: ${extra.join(\", \")}`;\n\t\t}\n\t\treturn null;\n\t}\n\tif (source.kind !== \"REPOSITORY\") {\n\t\treturn 'has a \"kind\" that is neither \"UPLOAD\" nor \"REPOSITORY\"';\n\t}\n\tif (typeof source.ref !== \"string\" || source.ref.length === 0) {\n\t\treturn 'has a \"ref\" that is not a non-empty string';\n\t}\n\tif (\n\t\ttypeof source.commitSha !== \"string\" ||\n\t\t!COMMIT_SHA_HEX.test(source.commitSha)\n\t) {\n\t\treturn 'has a \"commitSha\" that is not 7 to 64 lowercase hex characters';\n\t}\n\tif (typeof source.current !== \"boolean\") {\n\t\treturn 'has a \"current\" that is not a boolean';\n\t}\n\tconst allowed = new Set([\"kind\", \"ref\", \"commitSha\", \"current\"]);\n\tconst extra = keys.filter((key) => !allowed.has(key));\n\tif (extra.length > 0) {\n\t\treturn `has a key besides \"kind\", \"ref\", \"commitSha\" and \"current\" on a \"REPOSITORY\" source: ${extra.join(\", \")}`;\n\t}\n\treturn null;\n}\n","/**\n * Fetching and unpacking the published bundle.\n *\n * The archive is held in memory and never written to disk as an archive. A\n * temp zip on disk would be one more thing to clean up after an interrupted\n * run — but \"in memory\" only works while the size is bounded by something the\n * CLIENT decided, which is what `maxBytes` is. The response body is read in\n * chunks and abandoned the moment it exceeds that; `arrayBuffer()` buffered\n * whatever the server sent before anything could look at it, so a malformed\n * or hostile response sized the allocation itself.\n *\n * Only the paths the plan asked for are extracted, and the manifest's own\n * sizes bound the decompression. The filter is the only place that runs\n * before `fflate` allocates, so per-entry and aggregate limits belong there\n * rather than after the fact: the sha256 check in `apply.ts` catches\n * substituted CONTENT, but it runs on bytes that have already been\n * decompressed into memory.\n */\nimport { unzipSync } from \"fflate\";\n\nexport interface FetchBundleOptions {\n\t/** Per-attempt budget when no shared signal is supplied. */\n\ttimeoutMs: number;\n\t/**\n\t * The most compressed bytes worth reading, from `maxArchiveBytes`. A\n\t * declared `Content-Length` above it is refused before the body is read;\n\t * a body that grows past it is abandoned mid-stream.\n\t */\n\tmaxBytes: number;\n\t/**\n\t * A deadline owned by the caller. In hook mode one signal covers the\n\t * manifest call and this download together, so the whole command has a\n\t * single absolute bound rather than one per request.\n\t */\n\tsignal?: AbortSignal;\n\t/** Injectable for tests; defaults to the global fetch. */\n\tfetchImpl?: typeof fetch;\n}\n\nexport async function fetchBundle(\n\turl: string,\n\toptions: FetchBundleOptions,\n): Promise<Uint8Array> {\n\tconst fetchImpl = options.fetchImpl ?? fetch;\n\tconst controller = new AbortController();\n\tconst timer = setTimeout(() => controller.abort(), options.timeoutMs);\n\tconst onExternalAbort = () => controller.abort();\n\toptions.signal?.addEventListener(\"abort\", onExternalAbort, { once: true });\n\tif (options.signal?.aborted) {\n\t\tcontroller.abort();\n\t}\n\ttry {\n\t\tconst response = await fetchImpl(url, { signal: controller.signal });\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Downloading the coding-instructions bundle failed with HTTP ${response.status}.`,\n\t\t\t);\n\t\t}\n\n\t\tconst declared = Number(response.headers.get(\"content-length\"));\n\t\tif (Number.isFinite(declared) && declared > options.maxBytes) {\n\t\t\tthrow new Error(\n\t\t\t\t`The coding-instructions bundle declares ${declared} bytes and this snapshot's manifest allows at most ${options.maxBytes}. Nothing was written.`,\n\t\t\t);\n\t\t}\n\n\t\treturn await readBounded(response, options.maxBytes);\n\t} catch (error) {\n\t\tif (error instanceof Error && error.name === \"AbortError\") {\n\t\t\tthrow new Error(\n\t\t\t\t`Downloading the coding-instructions bundle timed out after ${options.timeoutMs}ms.`,\n\t\t\t);\n\t\t}\n\t\tthrow error;\n\t} finally {\n\t\tclearTimeout(timer);\n\t\toptions.signal?.removeEventListener(\"abort\", onExternalAbort);\n\t}\n}\n\n/**\n * Read a response body, refusing it the moment it passes `maxBytes`.\n *\n * The cap is compared against bytes ALREADY RECEIVED, so the refusal costs at\n * most one chunk beyond it rather than the whole body. A response with no\n * readable stream — an older polyfill, a test double built from a string —\n * falls back to `arrayBuffer()` and is length-checked after the fact, which\n * is the best available answer when the body cannot be consumed in pieces.\n */\nasync function readBounded(\n\tresponse: Response,\n\tmaxBytes: number,\n): Promise<Uint8Array> {\n\tconst body = response.body;\n\tif (!body) {\n\t\tconst bytes = new Uint8Array(await response.arrayBuffer());\n\t\tif (bytes.length > maxBytes) {\n\t\t\tthrow new Error(\n\t\t\t\t`The coding-instructions bundle is larger than the ${maxBytes} bytes this snapshot's manifest allows. Nothing was written.`,\n\t\t\t);\n\t\t}\n\t\treturn bytes;\n\t}\n\n\tconst reader = body.getReader();\n\tconst chunks: Uint8Array[] = [];\n\tlet total = 0;\n\ttry {\n\t\tfor (;;) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!value) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\ttotal += value.length;\n\t\t\tif (total > maxBytes) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`The coding-instructions bundle is larger than the ${maxBytes} bytes this snapshot's manifest allows. Nothing was written.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tchunks.push(value);\n\t\t}\n\t} finally {\n\t\tawait reader.cancel().catch(() => {});\n\t}\n\n\tconst archive = new Uint8Array(total);\n\tlet offset = 0;\n\tfor (const chunk of chunks) {\n\t\tarchive.set(chunk, offset);\n\t\toffset += chunk.length;\n\t}\n\treturn archive;\n}\n\nexport interface WantedEntry {\n\tpath: string;\n\t/** The manifest's size for this path, in bytes. */\n\tsize: number;\n}\n\n/**\n * Extract exactly the wanted paths, within exactly the wanted sizes.\n *\n * A zip entry name is matched literally against the manifest path. Nothing\n * here normalises, joins or resolves anything — a name that does not appear\n * in `wanted` is simply not returned, so an archive carrying `../../etc/x`\n * cannot reach the filesystem even before the path guard sees it.\n *\n * Three bounds, all enforced inside the filter so a hostile archive is\n * refused before it is decompressed:\n *\n * - a name the manifest does not list is skipped;\n * - an entry whose declared original size is not the manifest's size for\n * that path is refused (a zip bomb declaring 4 GB for a 200-byte file\n * never gets allocated);\n * - a second entry with a wanted name is refused rather than allowed to\n * win, which is what \"last one wins\" would otherwise let it do.\n */\nexport function extractBundle(\n\tarchive: Uint8Array,\n\twanted: Iterable<WantedEntry>,\n): Map<string, Uint8Array> {\n\tconst sizes = new Map<string, number>();\n\tfor (const entry of wanted) {\n\t\tsizes.set(entry.path, entry.size);\n\t}\n\tif (sizes.size === 0) {\n\t\treturn new Map();\n\t}\n\n\tconst seen = new Set<string>();\n\tconst unzipped = unzipSync(archive, {\n\t\tfilter: (file) => {\n\t\t\tconst expected = sizes.get(file.name);\n\t\t\tif (expected === undefined) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (seen.has(file.name)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`The downloaded bundle contains ${file.name} more than once. Nothing was written.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tseen.add(file.name);\n\t\t\tif (\n\t\t\t\tfile.originalSize !== undefined &&\n\t\t\t\tfile.originalSize !== expected\n\t\t\t) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`The downloaded bundle declares ${file.originalSize} bytes for ${file.name} and the manifest says ${expected}. Nothing was written.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t});\n\n\tconst contents = new Map<string, Uint8Array>();\n\tfor (const [name, bytes] of Object.entries(unzipped)) {\n\t\tconst expected = sizes.get(name);\n\t\tif (expected === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\t// The declared size is a claim; this is the measurement.\n\t\tif (bytes.length !== expected) {\n\t\t\tthrow new Error(\n\t\t\t\t`The downloaded bundle holds ${bytes.length} bytes for ${name} and the manifest says ${expected}. Nothing was written.`,\n\t\t\t);\n\t\t}\n\t\tcontents.set(name, bytes);\n\t}\n\treturn contents;\n}\n","/**\n * What kind of directory a repository-sourced project's hook is running in,\n * and what it should say there (Fizzy #2708).\n *\n * A project whose coding instructions come from a git repository publishes a\n * snapshot from one commit on one branch. In a checkout of that repository\n * the files already arrive with `git pull`, so the hook's job there is to\n * REPORT — \"the published commit is not in your history yet\" — and never to\n * write: no download, no lock, no git command that changes anything.\n * Automatic fast-forwarding is separate work and not part of this module.\n *\n * Elsewhere — a directory that is not a git checkout at all — the project's\n * published snapshot is the only way to read its instructions, so the upload\n * behaviour applies unchanged. Everything in between (a checkout of some\n * other repository, one this cannot read, one with two remotes for the same\n * repository, the right repository in the wrong directory) gets one line\n * saying which case it is, and nothing is written.\n *\n * `classifyCheckout` decides which case; `inspectMatchingCheckout` gathers the\n * facts for the matching one; `matchingReportLine` and `classLine` are the\n * pure halves that turn those into the one line a session reads.\n */\nimport { realpath } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type {\n\tPublishedInstructionRepository,\n\tPublishedInstructionSnapshot,\n} from \"@fabricorg/sdk\";\nimport { sanitizeDisplayText } from \"./checks.js\";\nimport type { CheckoutTraits, GitDeadline, GitOperation } from \"./git.js\";\nimport * as git from \"./git.js\";\nimport { matches, parseRemoteUrl } from \"./repository-identity.js\";\n\ntype CheckoutClass =\n\t| \"not-git\"\n\t| \"unknown\"\n\t| \"unknown-identity\"\n\t| \"unsupported-provider\"\n\t| \"foreign\"\n\t| \"ambiguous\"\n\t| \"unmapped\"\n\t| \"matching\";\n\nexport type CheckoutClassification =\n\t| { class: \"not-git\" }\n\t| { class: \"unknown\"; reason: string }\n\t| { class: \"unknown-identity\" }\n\t| { class: \"unsupported-provider\"; provider: string }\n\t| { class: \"foreign\" }\n\t| { class: \"ambiguous\"; remotes: string[] }\n\t| { class: \"unmapped\"; rootPath: string }\n\t| {\n\t\t\tclass: \"matching\";\n\t\t\tremote: string;\n\t\t\ttoplevel: string;\n\t\t\ttraits: CheckoutTraits;\n\t };\n\n/** Everything the matching report reads from the checkout. */\nexport interface CheckoutState {\n\t/** The checked-out branch, or `null` for a detached HEAD. */\n\tbranch: string | null;\n\thead: string | null;\n\tclean: boolean;\n\toperation: GitOperation | null;\n\ttraits: CheckoutTraits;\n}\n\n/** `check --format json`'s `checkout` block. */\nexport interface CheckoutJson {\n\tclass: CheckoutClass;\n\tremote?: string;\n\tbranch?: string | null;\n\thead?: string | null;\n\tclean?: boolean;\n\toperation?: GitOperation | null;\n\t/**\n\t * Whether the published commit is in HEAD's history: `null` when git\n\t * could not say (normally, it has not been fetched yet). Absent when\n\t * there was no repository-built, current snapshot to look for.\n\t */\n\tcontains?: boolean | null;\n\ttraits: Array<keyof CheckoutTraits>;\n\t/** The line printed for this checkout, or `null` when it is current. */\n\tline: string | null;\n}\n\nexport interface CheckoutReport {\n\tclassification: CheckoutClassification;\n\t/** Only in the matching class. */\n\tstate: CheckoutState | null;\n\tcontains: boolean | null | undefined;\n\tline: string | null;\n\tjson: CheckoutJson;\n}\n\nconst PREFIX = \"fabric: coding instructions\";\n\n/** Display bounds for every interpolated identifier. */\nconst MAX = { host: 253, path: 300, ref: 200, remote: 100, reason: 200 };\n\n/**\n * Classes in which the upload behaviour (download and lock) still applies:\n * a directory that is not a git checkout at all, and — only when a person\n * runs `sync` by hand, deliberately — a checkout of some OTHER repository.\n * Everything else fails closed in every mode: a checkout of the repository\n * itself (git keeps it current), and every case where this cannot tell\n * whether it is one (unknown, unknown repository, unsupported provider,\n * ambiguous, unmapped).\n */\nexport function downloadsIn(\n\tclassification: CheckoutClassification,\n\tmanual: boolean,\n): boolean {\n\tif (classification.class === \"not-git\") {\n\t\treturn true;\n\t}\n\treturn manual && classification.class === \"foreign\";\n}\n\n// ---------------------------------------------------------------------------\n// Classification\n// ---------------------------------------------------------------------------\n\nfunction isSafeRootPath(rootPath: string): boolean {\n\tif (\n\t\tpath.posix.isAbsolute(rootPath) ||\n\t\tpath.win32.isAbsolute(rootPath) ||\n\t\trootPath.startsWith(\"~\")\n\t) {\n\t\treturn false;\n\t}\n\treturn !rootPath.split(/[\\\\/]/).some((segment) => segment === \"..\");\n}\n\nasync function sameDirectory(a: string, b: string): Promise<boolean> {\n\tconst [left, right] = await Promise.all([\n\t\trealpath(a).catch(() => null),\n\t\trealpath(b).catch(() => null),\n\t]);\n\treturn left !== null && left === right;\n}\n\n/**\n * Which of the eight cases `destination` is, for this project's CURRENT\n * repository configuration. Never throws for anything git or the filesystem\n * can do; an unexpected failure is `unknown`.\n */\nexport async function classifyCheckout(input: {\n\tdestination: string;\n\trepository: PublishedInstructionRepository | null | undefined;\n\tdeadline: GitDeadline;\n}): Promise<CheckoutClassification> {\n\ttry {\n\t\treturn await classify(input);\n\t} catch {\n\t\treturn { class: \"unknown\", reason: \"the checkout could not be read\" };\n\t}\n}\n\nasync function classify({\n\tdestination,\n\trepository,\n\tdeadline,\n}: {\n\tdestination: string;\n\trepository: PublishedInstructionRepository | null | undefined;\n\tdeadline: GitDeadline;\n}): Promise<CheckoutClassification> {\n\tconst tree = await git.findWorkTree(destination, deadline);\n\tif (tree.kind === \"absent\") {\n\t\treturn { class: \"not-git\" };\n\t}\n\tif (tree.kind === \"unavailable\") {\n\t\treturn { class: \"unknown\", reason: tree.reason };\n\t}\n\tif (!repository) {\n\t\treturn { class: \"unknown-identity\" };\n\t}\n\tif (repository.provider !== \"GITHUB\" && repository.provider !== \"GITLAB\") {\n\t\treturn {\n\t\t\tclass: \"unsupported-provider\",\n\t\t\tprovider: String(repository.provider),\n\t\t};\n\t}\n\tconst root = tree.value.toplevel;\n\tif (!isSafeRootPath(repository.rootPath)) {\n\t\treturn {\n\t\t\tclass: \"unknown\",\n\t\t\treason: \"the project's instruction folder is not a path inside the repository\",\n\t\t};\n\t}\n\tconst refOk = await git.checkRefFormat(root, repository.ref, deadline);\n\tif (refOk.kind !== \"ok\") {\n\t\treturn {\n\t\t\tclass: \"unknown\",\n\t\t\treason:\n\t\t\t\trefOk.kind === \"absent\" ? \"not a git checkout\" : refOk.reason,\n\t\t};\n\t}\n\tif (!refOk.value) {\n\t\treturn {\n\t\t\tclass: \"unknown\",\n\t\t\treason: \"the project's branch name is not one this hook will use\",\n\t\t};\n\t}\n\n\tconst names = await git.remotes(root, deadline);\n\tif (names.kind !== \"ok\") {\n\t\treturn {\n\t\t\tclass: \"unknown\",\n\t\t\treason:\n\t\t\t\tnames.kind === \"absent\" ? \"not a git checkout\" : names.reason,\n\t\t};\n\t}\n\tconst matching: string[] = [];\n\tfor (const name of names.value) {\n\t\tconst url = await git.effectiveFetchUrl(root, name, deadline);\n\t\tif (url.kind !== \"ok\") {\n\t\t\treturn {\n\t\t\t\tclass: \"unknown\",\n\t\t\t\treason:\n\t\t\t\t\turl.kind === \"absent\" ? \"not a git checkout\" : url.reason,\n\t\t\t};\n\t\t}\n\t\tif (url.value === null) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst parsed = parseRemoteUrl(url.value);\n\t\tif (parsed && matches(parsed, repository) === \"match\") {\n\t\t\tmatching.push(name);\n\t\t}\n\t}\n\tif (matching.length === 0) {\n\t\treturn { class: \"foreign\" };\n\t}\n\tif (matching.length > 1) {\n\t\treturn { class: \"ambiguous\", remotes: matching };\n\t}\n\n\tconst mapped = path.join(root, repository.rootPath);\n\tif (!(await sameDirectory(destination, mapped))) {\n\t\treturn { class: \"unmapped\", rootPath: repository.rootPath };\n\t}\n\tconst traits = await git.checkoutTraits(root, deadline);\n\tif (traits.kind !== \"ok\") {\n\t\treturn {\n\t\t\tclass: \"unknown\",\n\t\t\treason:\n\t\t\t\ttraits.kind === \"absent\" ? \"not a git checkout\" : traits.reason,\n\t\t};\n\t}\n\treturn {\n\t\tclass: \"matching\",\n\t\tremote: matching[0] as string,\n\t\ttoplevel: root,\n\t\ttraits: traits.value,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// The matching class: facts, then the line\n// ---------------------------------------------------------------------------\n\n/**\n * Read the checkout and decide the line. `snapshot` is the published one;\n * its `source` says which commit it was built from, when it was built from\n * the repository at all.\n */\nasync function inspectMatchingCheckout(input: {\n\tclassification: Extract<CheckoutClassification, { class: \"matching\" }>;\n\trepository: PublishedInstructionRepository;\n\tsnapshot: PublishedInstructionSnapshot | undefined;\n\tdeadline: GitDeadline;\n}): Promise<CheckoutReport> {\n\tconst { classification, repository, snapshot, deadline } = input;\n\tconst root = classification.toplevel;\n\tconst unknown = (reason: string): CheckoutReport =>\n\t\treportFor(repository, { class: \"unknown\", reason });\n\n\tconst branch = await git.currentBranch(root, deadline);\n\tif (branch.kind !== \"ok\") {\n\t\treturn unknown(\n\t\t\tbranch.kind === \"absent\" ? \"not a git checkout\" : branch.reason,\n\t\t);\n\t}\n\tconst head = await git.headSha(root, deadline);\n\tif (head.kind !== \"ok\") {\n\t\treturn unknown(\n\t\t\thead.kind === \"absent\" ? \"not a git checkout\" : head.reason,\n\t\t);\n\t}\n\tconst clean = await git.isClean(root, deadline);\n\tif (clean.kind !== \"ok\") {\n\t\treturn unknown(\n\t\t\tclean.kind === \"absent\" ? \"not a git checkout\" : clean.reason,\n\t\t);\n\t}\n\tconst operation = await git.operationInProgress(root, deadline);\n\tif (operation.kind !== \"ok\") {\n\t\treturn unknown(\n\t\t\toperation.kind === \"absent\"\n\t\t\t\t? \"not a git checkout\"\n\t\t\t\t: operation.reason,\n\t\t);\n\t}\n\tconst state: CheckoutState = {\n\t\tbranch: branch.value,\n\t\thead: head.value,\n\t\tclean: clean.value,\n\t\toperation: operation.value,\n\t\ttraits: classification.traits,\n\t};\n\n\tconst source = snapshot?.source;\n\tlet contains: boolean | null | undefined;\n\tif (\n\t\tsnapshot &&\n\t\tsource?.kind === \"REPOSITORY\" &&\n\t\tsource.current &&\n\t\tgit.isCommitSha(source.commitSha)\n\t) {\n\t\tif (state.head === null) {\n\t\t\tcontains = null;\n\t\t} else {\n\t\t\tconst answer = await git.isAncestor(\n\t\t\t\troot,\n\t\t\t\tsource.commitSha,\n\t\t\t\tstate.head,\n\t\t\t\tdeadline,\n\t\t\t);\n\t\t\tcontains = answer.kind === \"ok\" ? answer.value : null;\n\t\t}\n\t}\n\n\tconst line = matchingReportLine({\n\t\trepository,\n\t\tremote: classification.remote,\n\t\tsnapshot: snapshot\n\t\t\t? { version: snapshot.version, source: snapshot.source }\n\t\t\t: null,\n\t\tstate,\n\t\tcontains,\n\t});\n\treturn {\n\t\tclassification,\n\t\tstate,\n\t\tcontains,\n\t\tline,\n\t\tjson: {\n\t\t\tclass: \"matching\",\n\t\t\tremote: classification.remote,\n\t\t\tbranch: state.branch,\n\t\t\thead: state.head,\n\t\t\tclean: state.clean,\n\t\t\toperation: state.operation,\n\t\t\t...(contains !== undefined ? { contains } : {}),\n\t\t\ttraits: traitNames(state.traits),\n\t\t\tline,\n\t\t},\n\t};\n}\n\n/** The report for a class that is not `matching`: its line, nothing read. */\nexport function reportFor(\n\trepository: PublishedInstructionRepository | null | undefined,\n\tclassification: Exclude<CheckoutClassification, { class: \"matching\" }>,\n): CheckoutReport {\n\tconst line =\n\t\tclassification.class === \"not-git\"\n\t\t\t? null\n\t\t\t: classLine(classification, repository ?? null);\n\treturn {\n\t\tclassification,\n\t\tstate: null,\n\t\tcontains: undefined,\n\t\tline,\n\t\tjson: { class: classification.class, traits: [], line },\n\t};\n}\n\nfunction traitNames(traits: CheckoutTraits): Array<keyof CheckoutTraits> {\n\treturn ([\"shallow\", \"sparse\", \"superproject\"] as const).filter(\n\t\t(trait) => traits[trait],\n\t);\n}\n\nconst SHELL_SAFE = /^[A-Za-z0-9_@%+=:,./-]+$/;\n\n/** POSIX single-quoting, the rule doctor's generated commands use. */\nfunction shellQuote(value: string): string {\n\tif (value.length > 0 && SHELL_SAFE.test(value)) {\n\t\treturn value;\n\t}\n\treturn `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\nfunction show(value: string, max: number): string {\n\treturn sanitizeDisplayText(value, max);\n}\n\nfunction repositoryName(repository: { host: string; path: string }): string {\n\treturn `${show(repository.host, MAX.host)}/${show(repository.path, MAX.path)}`;\n}\n\n/**\n * The one line for the matching class, or `null` when the checkout already\n * holds the published commit. The decision table, over plain data.\n */\nexport function matchingReportLine(input: {\n\trepository: Pick<PublishedInstructionRepository, \"host\" | \"path\" | \"ref\">;\n\tremote: string;\n\tsnapshot: {\n\t\tversion: number;\n\t\tsource?: PublishedInstructionSnapshot[\"source\"];\n\t} | null;\n\tstate: CheckoutState;\n\t/** `undefined` when not evaluated; `null` when git could not say. */\n\tcontains: boolean | null | undefined;\n}): string | null {\n\tconst { repository, remote, snapshot, state, contains } = input;\n\tconst name = repositoryName(repository);\n\tconst ref = show(repository.ref, MAX.ref);\n\tconst source = snapshot?.source;\n\n\tif (!snapshot || source?.kind !== \"REPOSITORY\") {\n\t\treturn `${PREFIX}: the project is repository-sourced but nothing has been published from ${name} yet`;\n\t}\n\tconst version = Number(snapshot.version);\n\tif (!source.current) {\n\t\treturn `${PREFIX} v${version} was published from ${show(source.ref, MAX.ref)}; the project now syncs ${ref} of ${name} — pull ${ref} to pick up the next publication`;\n\t}\n\tif (contains === true) {\n\t\treturn null;\n\t}\n\n\tconst sha7 = show(source.commitSha.slice(0, 7), 7);\n\tconst behind =\n\t\tcontains === false\n\t\t\t? \"this checkout is behind\"\n\t\t\t: \"this checkout has not fetched it yet\";\n\tconst base = `${PREFIX} v${version} (${sha7}) is published on ${ref} of ${name}; ${behind}`;\n\n\tlet advice: string;\n\tif (state.operation !== null) {\n\t\t// Before the branch: a rebase detaches HEAD, and \"check out the\n\t\t// branch\" is the wrong advice in the middle of one.\n\t\tadvice = `; a ${state.operation} is in progress`;\n\t} else if (state.branch === null) {\n\t\tadvice = `; HEAD is detached — check out ${ref} and pull`;\n\t} else if (state.branch !== repository.ref) {\n\t\tadvice = `; you are on ${show(state.branch, MAX.ref)} — pull ${ref} when you switch to it`;\n\t} else if (!state.clean) {\n\t\tadvice = \"; your working tree has changes — pull when it is clean\";\n\t} else {\n\t\tconst pull = [\n\t\t\t\"git\",\n\t\t\t\"pull\",\n\t\t\t\"--ff-only\",\n\t\t\tshellQuote(show(remote, MAX.remote)),\n\t\t\tshellQuote(ref),\n\t\t].join(\" \");\n\t\tadvice = ` — run: ${pull}`;\n\t}\n\n\tconst traits = traitNames(state.traits).map(\n\t\t(trait) =>\n\t\t\t({\n\t\t\t\tshallow: \" (shallow clone)\",\n\t\t\t\tsparse: \" (sparse checkout)\",\n\t\t\t\tsuperproject: \" (inside a superproject)\",\n\t\t\t})[trait],\n\t);\n\treturn `${base}${advice}${traits.join(\"\")}`;\n}\n\n/** The one line for every class that is neither `matching` nor `not-git`. */\nexport function classLine(\n\tclassification: Exclude<\n\t\tCheckoutClassification,\n\t\t{ class: \"matching\" } | { class: \"not-git\" }\n\t>,\n\trepository: Pick<PublishedInstructionRepository, \"host\" | \"path\"> | null,\n): string {\n\tconst name = repository ? repositoryName(repository) : \"its repository\";\n\tconst tail = \"nothing was checked or changed\";\n\tswitch (classification.class) {\n\t\tcase \"foreign\":\n\t\t\treturn `${PREFIX}: no remote of this checkout fetches from ${name} (foreign checkout); ${tail}`;\n\t\tcase \"ambiguous\":\n\t\t\treturn `${PREFIX}: remotes ${classification.remotes\n\t\t\t\t.map((remote) => show(remote, MAX.remote))\n\t\t\t\t.join(\n\t\t\t\t\t\", \",\n\t\t\t\t)} all fetch from ${name} (ambiguous checkout); ${tail}`;\n\t\tcase \"unmapped\": {\n\t\t\tconst where =\n\t\t\t\tclassification.rootPath === \"\"\n\t\t\t\t\t? \"the repository root\"\n\t\t\t\t\t: show(classification.rootPath, MAX.path);\n\t\t\treturn `${PREFIX}: this checkout is ${name}, but the project's instructions are at ${where}, not this directory (unmapped checkout); ${tail}`;\n\t\t}\n\t\tcase \"unknown\":\n\t\t\treturn `${PREFIX}: this git checkout could not be read (${show(classification.reason, MAX.reason)}; unknown checkout); ${tail}`;\n\t\tcase \"unknown-identity\":\n\t\t\treturn `${PREFIX}: the project is repository-sourced but reports no repository to compare with (unknown repository); ${tail}`;\n\t\tcase \"unsupported-provider\":\n\t\t\treturn `${PREFIX}: ${show(classification.provider, 32)} repositories are not compared yet (unsupported provider); ${tail}`;\n\t}\n}\n\n/**\n * Classify, then — in the matching class — read the checkout. The one entry\n * point `check`, `sync` and doctor share, so all three say the same thing.\n */\nexport async function inspectCheckout(input: {\n\tdestination: string;\n\trepository: PublishedInstructionRepository | null | undefined;\n\tsnapshot: PublishedInstructionSnapshot | undefined;\n\tdeadline: GitDeadline;\n}): Promise<CheckoutReport> {\n\tconst classification = await classifyCheckout(input);\n\treturn reportForClassification({ ...input, classification });\n}\n\n/** The report for a classification already made. */\nexport async function reportForClassification(input: {\n\tclassification: CheckoutClassification;\n\trepository: PublishedInstructionRepository | null | undefined;\n\tsnapshot: PublishedInstructionSnapshot | undefined;\n\tdeadline: GitDeadline;\n}): Promise<CheckoutReport> {\n\tconst { classification, repository } = input;\n\tif (classification.class !== \"matching\") {\n\t\treturn reportFor(repository, classification);\n\t}\n\tif (!repository) {\n\t\treturn reportFor(repository, { class: \"unknown-identity\" });\n\t}\n\ttry {\n\t\treturn await inspectMatchingCheckout({\n\t\t\t...input,\n\t\t\tclassification,\n\t\t\trepository,\n\t\t});\n\t} catch {\n\t\treturn reportFor(repository, {\n\t\t\tclass: \"unknown\",\n\t\t\treason: \"the checkout could not be read\",\n\t\t});\n\t}\n}\n\n/**\n * What a person running `sync` by hand reads when the matching checkout\n * already holds the published commit — the case the hook stays silent for.\n */\nexport function currentLine(\n\trepository: Pick<PublishedInstructionRepository, \"host\" | \"path\" | \"ref\">,\n\tsnapshot: Pick<PublishedInstructionSnapshot, \"version\" | \"source\">,\n): string {\n\tconst source = snapshot.source;\n\tconst sha7 =\n\t\tsource?.kind === \"REPOSITORY\"\n\t\t\t? ` (${show(source.commitSha.slice(0, 7), 7)})`\n\t\t\t: \"\";\n\treturn `${PREFIX} v${Number(snapshot.version)}${sha7} from ${show(repository.ref, MAX.ref)} of ${repositoryName(repository)} is already in this checkout's history; nothing to sync`;\n}\n\n/**\n * `init`'s line for a checkout of the repository: the hook it wrote reports\n * and never changes anything.\n */\nexport function installedLine(\n\trepository: Pick<PublishedInstructionRepository, \"host\" | \"path\" | \"ref\">,\n\tapply: boolean,\n): string {\n\tconst base = `installed; this checkout is ${repositoryName(repository)}: the hook reports when ${show(repository.ref, MAX.ref)} has newer instructions and never changes the checkout`;\n\treturn apply\n\t\t? `${base} — automatic updates are not available for repository checkouts yet; the hook reports and you (or your agent) run the pull`\n\t\t: base;\n}\n\n/** `init`'s note when nothing has been published from the repository yet. */\nexport function nothingPublishedLine(\n\trepository: Pick<PublishedInstructionRepository, \"host\" | \"path\">,\n): string {\n\treturn `Nothing has been published from ${repositoryName(repository)} yet; the hook reports once it is.`;\n}\n","/**\n * The shared vocabulary of `fabric instructions doctor` and the MCP\n * `fabric_instruction_checks` tool, plus the `fabric.environment.json`\n * declaration format both of them read.\n *\n * This file is deliberately dependency-free and has a byte-for-byte twin at\n * `apps/web/modules/saas/mcp/lib/gateway/instruction-checks.ts`. The CLI is a\n * published npm package and cannot depend on the private `@repo/*` workspace\n * packages, and the web app does not depend on the SDK, so the two surfaces\n * carry their own copy — the same arrangement as `paths.ts` and\n * `manifest.ts`. `packages/cli/__tests__/checks-agree-with-gateway.test.ts`\n * runs one fixture corpus through both copies and fails on any divergence.\n *\n * Everything named in a declaration is published content: a variable name, a\n * tool name, a version string, a description. Nothing here executes a tool,\n * reads a variable's value, or echoes untrusted text unbounded. The parser's\n * failure reasons refer to positions (`variables[3]`), never to the offending\n * value, so a malformed file cannot smuggle a secret into a diagnostic.\n */\n\n// ---------------------------------------------------------------------------\n// Declaration format\n// ---------------------------------------------------------------------------\n\nexport const INSTRUCTION_ENVIRONMENT_FILE = \"fabric.environment.json\";\nexport const INSTRUCTION_ENVIRONMENT_VERSION = 1;\nexport const INSTRUCTION_ENVIRONMENT_MAX_BYTES = 65_536;\nexport const INSTRUCTION_ENVIRONMENT_MAX_VARIABLES = 200;\nexport const INSTRUCTION_ENVIRONMENT_MAX_TOOLS = 100;\n\n/** POSIX identifier, capped so a name can never double as a payload. */\nexport const ENVIRONMENT_VARIABLE_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;\n/** A bare executable name: no separators, no whitespace, no leading dot. */\nexport const TOOL_NAME = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,63}$/;\n\nconst MAX_DESCRIPTION_CHARS = 200;\nconst MAX_VERSION_CHARS = 64;\n\nexport interface DeclaredVariable {\n\tname: string;\n\trequired: boolean;\n\tdescription?: string;\n}\n\nexport interface DeclaredTool {\n\tname: string;\n\t/** Free-form, informational only — never verified by execution. */\n\tversion?: string;\n\tdescription?: string;\n}\n\nexport interface InstructionEnvironment {\n\tversion: typeof INSTRUCTION_ENVIRONMENT_VERSION;\n\tvariables: DeclaredVariable[];\n\ttools: DeclaredTool[];\n}\n\nexport type InstructionEnvironmentParse =\n\t| { ok: true; declaration: InstructionEnvironment }\n\t| { ok: false; reason: string };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Strip control characters (including ANSI escape introducers) and cap the\n * length, so published text can be printed to a terminal or embedded in JSON\n * without carrying terminal controls or unbounded content.\n */\nexport function sanitizeDisplayText(value: string, maxChars: number): string {\n\t// Work in code points so truncation can never split a surrogate pair.\n\tconst chars: string[] = [];\n\tlet truncated = false;\n\tfor (const ch of value) {\n\t\tif (chars.length >= maxChars) {\n\t\t\ttruncated = true;\n\t\t\tbreak;\n\t\t}\n\t\tconst code = ch.codePointAt(0) ?? 0;\n\t\tconst isControl =\n\t\t\tcode < 0x20 ||\n\t\t\t(code >= 0x7f && code <= 0x9f) ||\n\t\t\tcode === 0x2028 ||\n\t\t\tcode === 0x2029;\n\t\tchars.push(isControl ? \" \" : ch);\n\t}\n\tif (!truncated) {\n\t\treturn chars.join(\"\");\n\t}\n\treturn `${chars.slice(0, Math.max(0, maxChars - 1)).join(\"\")}…`;\n}\n\nfunction optionalText(\n\tvalue: unknown,\n\tmaxChars: number,\n\twhere: string,\n): { ok: true; value: string | undefined } | { ok: false; reason: string } {\n\tif (value === undefined) {\n\t\treturn { ok: true, value: undefined };\n\t}\n\tif (typeof value !== \"string\") {\n\t\treturn { ok: false, reason: `${where} must be a string` };\n\t}\n\tif (value.length > maxChars) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\treason: `${where} is longer than ${maxChars} characters`,\n\t\t};\n\t}\n\treturn { ok: true, value: sanitizeDisplayText(value, maxChars) };\n}\n\n/**\n * Parse the text of a `fabric.environment.json`. The caller is responsible\n * for reading at most `INSTRUCTION_ENVIRONMENT_MAX_BYTES` bytes with a\n * bounded, symlink-refusing read; the size check here is defence in depth.\n */\nexport function parseInstructionEnvironment(\n\ttext: string,\n): InstructionEnvironmentParse {\n\tif (byteLength(text) > INSTRUCTION_ENVIRONMENT_MAX_BYTES) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\treason: `file is larger than ${INSTRUCTION_ENVIRONMENT_MAX_BYTES} bytes`,\n\t\t};\n\t}\n\tlet raw: unknown;\n\ttry {\n\t\traw = JSON.parse(text);\n\t} catch {\n\t\t// Never surface the parser's message: it quotes the input.\n\t\treturn { ok: false, reason: \"file is not valid JSON\" };\n\t}\n\tif (!isRecord(raw)) {\n\t\treturn { ok: false, reason: \"top level must be an object\" };\n\t}\n\tif (raw.version !== INSTRUCTION_ENVIRONMENT_VERSION) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\treason: `version must be the number ${INSTRUCTION_ENVIRONMENT_VERSION}`,\n\t\t};\n\t}\n\n\tconst variables: DeclaredVariable[] = [];\n\tif (raw.variables !== undefined) {\n\t\tif (!Array.isArray(raw.variables)) {\n\t\t\treturn { ok: false, reason: \"variables must be an array\" };\n\t\t}\n\t\tif (raw.variables.length > INSTRUCTION_ENVIRONMENT_MAX_VARIABLES) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: `variables has more than ${INSTRUCTION_ENVIRONMENT_MAX_VARIABLES} entries`,\n\t\t\t};\n\t\t}\n\t\tconst seen = new Set<string>();\n\t\tfor (const [index, entry] of raw.variables.entries()) {\n\t\t\tconst where = `variables[${index}]`;\n\t\t\tif (!isRecord(entry)) {\n\t\t\t\treturn { ok: false, reason: `${where} must be an object` };\n\t\t\t}\n\t\t\tif (\n\t\t\t\ttypeof entry.name !== \"string\" ||\n\t\t\t\t!ENVIRONMENT_VARIABLE_NAME.test(entry.name)\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\treason: `${where}.name must be an environment variable name (letters, digits, underscore; at most 128 characters)`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (seen.has(entry.name)) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\treason: `${where}.name repeats an earlier entry`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tseen.add(entry.name);\n\t\t\tif (\n\t\t\t\tentry.required !== undefined &&\n\t\t\t\ttypeof entry.required !== \"boolean\"\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\treason: `${where}.required must be a boolean`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst description = optionalText(\n\t\t\t\tentry.description,\n\t\t\t\tMAX_DESCRIPTION_CHARS,\n\t\t\t\t`${where}.description`,\n\t\t\t);\n\t\t\tif (!description.ok) {\n\t\t\t\treturn description;\n\t\t\t}\n\t\t\tvariables.push({\n\t\t\t\tname: entry.name,\n\t\t\t\trequired: entry.required ?? true,\n\t\t\t\t...(description.value !== undefined\n\t\t\t\t\t? { description: description.value }\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t}\n\t}\n\n\tconst tools: DeclaredTool[] = [];\n\tif (raw.tools !== undefined) {\n\t\tif (!Array.isArray(raw.tools)) {\n\t\t\treturn { ok: false, reason: \"tools must be an array\" };\n\t\t}\n\t\tif (raw.tools.length > INSTRUCTION_ENVIRONMENT_MAX_TOOLS) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: `tools has more than ${INSTRUCTION_ENVIRONMENT_MAX_TOOLS} entries`,\n\t\t\t};\n\t\t}\n\t\tconst seen = new Set<string>();\n\t\tfor (const [index, entry] of raw.tools.entries()) {\n\t\t\tconst where = `tools[${index}]`;\n\t\t\tif (!isRecord(entry)) {\n\t\t\t\treturn { ok: false, reason: `${where} must be an object` };\n\t\t\t}\n\t\t\tif (typeof entry.name !== \"string\" || !TOOL_NAME.test(entry.name)) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\treason: `${where}.name must be a bare executable name (no path separators or whitespace; at most 64 characters)`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (seen.has(entry.name)) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\treason: `${where}.name repeats an earlier entry`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tseen.add(entry.name);\n\t\t\tconst version = optionalText(\n\t\t\t\tentry.version,\n\t\t\t\tMAX_VERSION_CHARS,\n\t\t\t\t`${where}.version`,\n\t\t\t);\n\t\t\tif (!version.ok) {\n\t\t\t\treturn version;\n\t\t\t}\n\t\t\tconst description = optionalText(\n\t\t\t\tentry.description,\n\t\t\t\tMAX_DESCRIPTION_CHARS,\n\t\t\t\t`${where}.description`,\n\t\t\t);\n\t\t\tif (!description.ok) {\n\t\t\t\treturn description;\n\t\t\t}\n\t\t\ttools.push({\n\t\t\t\tname: entry.name,\n\t\t\t\t...(version.value !== undefined\n\t\t\t\t\t? { version: version.value }\n\t\t\t\t\t: {}),\n\t\t\t\t...(description.value !== undefined\n\t\t\t\t\t? { description: description.value }\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t}\n\t}\n\n\treturn {\n\t\tok: true,\n\t\tdeclaration: {\n\t\t\tversion: INSTRUCTION_ENVIRONMENT_VERSION,\n\t\t\tvariables,\n\t\t\ttools,\n\t\t},\n\t};\n}\n\nfunction byteLength(text: string): number {\n\tif (typeof TextEncoder !== \"undefined\") {\n\t\treturn new TextEncoder().encode(text).length;\n\t}\n\treturn text.length;\n}\n\n// ---------------------------------------------------------------------------\n// Check vocabulary\n// ---------------------------------------------------------------------------\n\nexport type CheckStatus = \"pass\" | \"fail\" | \"warn\" | \"skip\";\n\nexport const CHECK_IDS = [\n\t\"auth\",\n\t\"access\",\n\t\"published\",\n\t\"lock\",\n\t\"drift\",\n\t\"hook\",\n\t\"environment\",\n\t\"tools\",\n\t\"mcp-servers\",\n] as const;\nexport type CheckId = (typeof CHECK_IDS)[number];\n\nexport const CHECK_TITLES: Record<CheckId, string> = {\n\tauth: \"API key\",\n\taccess: \"Project access\",\n\tpublished: \"Published instructions\",\n\tlock: \"Lock\",\n\tdrift: \"Local files\",\n\thook: \"Hook configuration\",\n\tenvironment: \"Environment variables\",\n\ttools: \"Tools\",\n\t\"mcp-servers\": \"MCP servers\",\n};\n\n/**\n * Where a check's verdict comes from. `server` means the surface verified it\n * against authoritative state; `machine` means the CLI observed it on the\n * developer's machine; `caller-reported` means the MCP caller asserted it and\n * the server only compared what it was told.\n */\nexport type CheckEvidence = \"server\" | \"machine\" | \"caller-reported\";\n\nexport interface CheckItem {\n\tname: string;\n\tstatus: CheckStatus;\n\tdetail?: string;\n}\n\nexport interface CheckFix {\n\t/** A copy-pasteable shell line, present only when one exists. */\n\tcommand?: string;\n\tdescription: string;\n}\n\n/**\n * Per-snapshot provenance for a published Coding Instructions snapshot\n * (Fizzy #2709) — distinct from the project setting `sourceOfTruth`, which\n * stays as it is. `current` is true only when this snapshot's repository and\n * branch still match the project's CURRENT sync configuration. Structurally\n * the same shape `@repo/database`'s `resolveInstructionSnapshotSource`\n * returns and the SDK's `PublishedInstructionSnapshot.source` carries;\n * repeated here rather than imported because this file has neither\n * dependency.\n */\nexport type PublishedInstructionSource =\n\t| { kind: \"UPLOAD\" }\n\t| {\n\t\t\tkind: \"REPOSITORY\";\n\t\t\tref: string;\n\t\t\tcommitSha: string;\n\t\t\tcurrent: boolean;\n\t };\n\n/**\n * The project's CURRENT repository-sync configuration (Fizzy #2709),\n * independent of any one snapshot. Structurally the same shape\n * `@repo/database`'s `resolveCurrentInstructionRepository` returns and the\n * SDK's `PublishedInstructions.repository` carries; repeated here for the\n * same reason as `PublishedInstructionSource` above. `host` is a bare,\n * lowercased hostname — never the repository URL, never userinfo.\n */\nexport type PublishedInstructionRepositoryConfig = {\n\tprovider: \"GITHUB\" | \"GITLAB\" | \"AZURE_DEVOPS\";\n\thost: string;\n\tpath: string;\n\tref: string;\n\trootPath: string;\n\tgeneration: number;\n};\n\nexport interface InstructionCheck {\n\tid: CheckId;\n\ttitle: string;\n\tstatus: CheckStatus;\n\tevidence: CheckEvidence;\n\t/** One line. Never a secret, a variable value, or unbounded published text. */\n\tdetail: string;\n\titems?: CheckItem[];\n\tfix?: CheckFix;\n\t/** Set on the `published` check only, when the server reported one. */\n\tsource?: PublishedInstructionSource;\n\t/** Set on the `published` check only, alongside `source`. `null` when not repository-backed. */\n\trepository?: PublishedInstructionRepositoryConfig | null;\n}\n\nexport interface InstructionChecksReport {\n\tprojectId: string;\n\tsurface: \"cli\" | \"mcp\";\n\tchecks: InstructionCheck[];\n\tsummary: Record<CheckStatus, number>;\n\t/** No `fail` among the checks that were evaluated. Not a readiness attestation. */\n\tok: boolean;\n}\n\nexport function summarizeChecks(\n\tchecks: readonly InstructionCheck[],\n): Record<CheckStatus, number> {\n\tconst summary: Record<CheckStatus, number> = {\n\t\tpass: 0,\n\t\tfail: 0,\n\t\twarn: 0,\n\t\tskip: 0,\n\t};\n\tfor (const check of checks) {\n\t\tsummary[check.status] += 1;\n\t}\n\treturn summary;\n}\n\nexport function buildChecksReport(\n\tprojectId: string,\n\tsurface: InstructionChecksReport[\"surface\"],\n\tchecks: readonly InstructionCheck[],\n): InstructionChecksReport {\n\tconst ordered = [...checks].sort(\n\t\t(a, b) => CHECK_IDS.indexOf(a.id) - CHECK_IDS.indexOf(b.id),\n\t);\n\tconst summary = summarizeChecks(ordered);\n\treturn {\n\t\tprojectId,\n\t\tsurface,\n\t\tchecks: ordered,\n\t\tsummary,\n\t\tok: summary.fail === 0,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Evaluation shared by both surfaces\n// ---------------------------------------------------------------------------\n\nexport interface VariableEvaluation {\n\tstatus: CheckStatus;\n\titems: CheckItem[];\n\tmissingRequired: string[];\n\tmissingOptional: string[];\n}\n\n/**\n * Compare declared variable NAMES against the set of names present. Values\n * are never involved. `ignoreCase` is for Windows, where the environment is\n * case-insensitive; the caller normalises nothing — this does.\n */\nexport function evaluateDeclaredVariables(\n\tdeclaration: InstructionEnvironment,\n\tpresentNames: Iterable<string>,\n\toptions: { ignoreCase?: boolean } = {},\n): VariableEvaluation {\n\tconst fold = (name: string) =>\n\t\toptions.ignoreCase ? name.toUpperCase() : name;\n\tconst present = new Set<string>();\n\tfor (const name of presentNames) {\n\t\tpresent.add(fold(name));\n\t}\n\tconst items: CheckItem[] = [];\n\tconst missingRequired: string[] = [];\n\tconst missingOptional: string[] = [];\n\tfor (const variable of declaration.variables) {\n\t\tif (present.has(fold(variable.name))) {\n\t\t\titems.push({\n\t\t\t\tname: variable.name,\n\t\t\t\tstatus: \"pass\",\n\t\t\t\tdetail: \"present\",\n\t\t\t});\n\t\t} else if (variable.required) {\n\t\t\titems.push({\n\t\t\t\tname: variable.name,\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tdetail: \"missing (required)\",\n\t\t\t});\n\t\t\tmissingRequired.push(variable.name);\n\t\t} else {\n\t\t\titems.push({\n\t\t\t\tname: variable.name,\n\t\t\t\tstatus: \"warn\",\n\t\t\t\tdetail: \"missing (optional)\",\n\t\t\t});\n\t\t\tmissingOptional.push(variable.name);\n\t\t}\n\t}\n\tconst status: CheckStatus =\n\t\tdeclaration.variables.length === 0\n\t\t\t? \"skip\"\n\t\t\t: missingRequired.length > 0\n\t\t\t\t? \"fail\"\n\t\t\t\t: missingOptional.length > 0\n\t\t\t\t\t? \"warn\"\n\t\t\t\t\t: \"pass\";\n\treturn { status, items, missingRequired, missingOptional };\n}\n","/**\n * The only way this CLI runs `git`, and it only ever READS (Fizzy #2708).\n *\n * A repository-sourced project's session hook compares the checkout it runs\n * in with the commit the project last published from. That needs a handful\n * of facts about the checkout — where its work tree is, which remotes it\n * fetches from, which branch is checked out, whether the published commit is\n * in its history — and nothing else. So this module exports exactly those\n * questions, one function each, and no way to run an arbitrary git command:\n * nothing here fetches, pulls, merges, checks out, stashes, or writes to a\n * checkout, and a caller cannot make it.\n *\n * Every call is bounded and quiet:\n *\n * - `spawn` with no shell, stdin closed, and a timeout taken from the\n * caller's absolute deadline (SIGTERM, then SIGKILL a second later);\n * - an environment with every `FABRIC_*` variable removed (the API key\n * never reaches git or anything git might run), the variables that\n * redirect git at a different repository removed, prompts disabled, and\n * optional locks, lazy fetches and fsmonitor turned off;\n * - stdout capped at 64 KiB, stderr captured and never printed.\n *\n * Every function answers with a discriminated result rather than throwing for\n * the expected failures: `absent` means \"not a git repository\", and\n * `unavailable` means git could not answer — it is not installed, it timed\n * out, it refused a repository it does not trust, the repository is bare, or\n * its `.git` points nowhere. The reason is fixed text chosen here, never\n * git's own message, which can quote paths and configuration.\n */\nimport { spawn } from \"node:child_process\";\nimport { lstat, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nexport type GitResult<T> =\n\t| { kind: \"ok\"; value: T }\n\t| { kind: \"absent\" }\n\t| { kind: \"unavailable\"; reason: string };\n\n/** An absolute point in time, in epoch milliseconds, that no call may pass. */\nexport type GitDeadline = number;\n\nexport interface WorkTree {\n\t/** The work tree's top level, as git reports it. */\n\ttoplevel: string;\n\tgitDir: string;\n\tshallow: boolean;\n\t/** The superproject's work tree when this is a submodule checkout. */\n\tsuperproject: string | null;\n}\n\nexport type GitOperation =\n\t| \"merge\"\n\t| \"rebase\"\n\t| \"cherry-pick\"\n\t| \"revert\"\n\t| \"bisect\";\n\nexport interface CheckoutTraits {\n\tshallow: boolean;\n\tsparse: boolean;\n\tsuperproject: boolean;\n}\n\nconst STDOUT_CAP_BYTES = 64 * 1024;\nconst STDERR_CAP_BYTES = 8 * 1024;\nconst KILL_GRACE_MS = 1_000;\n\n/** A full, lowercase object name. Anything else is never passed to git. */\nconst COMMIT_SHA = /^[0-9a-f]{40}$/;\n\n/**\n * The branch names this module will pass to git or print as a command: a\n * conservative literal on top of `git check-ref-format --branch`, which alone\n * would accept (and expand) `@{-1}` and friends.\n */\nconst BRANCH_LITERAL = /^[A-Za-z0-9][A-Za-z0-9._/-]*$/;\n\n/** Remote names as `git remote` lists them; never one that reads as an option. */\nconst REMOTE_NAME = /^[A-Za-z0-9._][A-Za-z0-9._/-]*$/;\n\n/**\n * Removed from the inherited environment, alongside every `FABRIC_*` and\n * every `GIT_CONFIG_KEY_<n>` / `GIT_CONFIG_VALUE_<n>`. Compared in upper\n * case, because Windows environment names are case-insensitive.\n *\n * The first group redirects git at a different repository; the\n * `GIT_CONFIG_*` group injects or relocates configuration — an `insteadOf`\n * there would change which URL a remote fetches from, and so which\n * repository this checkout is taken to be.\n */\nconst STRIPPED_VARIABLES = new Set([\n\t\"GIT_DIR\",\n\t\"GIT_WORK_TREE\",\n\t\"GIT_INDEX_FILE\",\n\t\"GIT_OBJECT_DIRECTORY\",\n\t\"GIT_NAMESPACE\",\n\t\"GIT_COMMON_DIR\",\n\t\"GIT_ASKPASS\",\n\t\"SSH_ASKPASS\",\n\t\"GIT_CONFIG_COUNT\",\n\t\"GIT_CONFIG_PARAMETERS\",\n\t\"GIT_CONFIG_GLOBAL\",\n\t\"GIT_CONFIG_SYSTEM\",\n\t\"GIT_CONFIG_NOSYSTEM\",\n]);\n\nconst STRIPPED_PATTERN = /^(?:FABRIC_|GIT_CONFIG_(?:KEY|VALUE)_\\d+$)/;\n\n/** The files and directories git leaves while each operation is in progress. */\nconst OPERATION_MARKERS: ReadonlyArray<{\n\tmarker: string;\n\toperation: GitOperation;\n}> = [\n\t{ marker: \"MERGE_HEAD\", operation: \"merge\" },\n\t{ marker: \"REBASE_HEAD\", operation: \"rebase\" },\n\t{ marker: \"rebase-merge\", operation: \"rebase\" },\n\t{ marker: \"rebase-apply\", operation: \"rebase\" },\n\t{ marker: \"CHERRY_PICK_HEAD\", operation: \"cherry-pick\" },\n\t{ marker: \"REVERT_HEAD\", operation: \"revert\" },\n\t{ marker: \"BISECT_LOG\", operation: \"bisect\" },\n\t// Left by a multi-commit cherry-pick or revert between steps; the two\n\t// HEAD markers above name which one while a step is stopped.\n\t{ marker: \"sequencer\", operation: \"cherry-pick\" },\n];\n\n/**\n * Paths this CLI itself writes into a checkout: the session hook's settings.\n * `init` puts one there in every checkout it sets up, so counting it as \"your\n * working tree has changes\" would make every such checkout permanently dirty.\n */\nconst OWN_PATHS = [\".claude/settings.local.json\", \".codex/hooks.json\"];\n\n/** The environment every git call runs with, derived from `source`. */\nexport function gitEnvironment(\n\tsource: NodeJS.ProcessEnv = process.env,\n): NodeJS.ProcessEnv {\n\tconst env: NodeJS.ProcessEnv = {};\n\tfor (const [name, value] of Object.entries(source)) {\n\t\tconst upper = name.toUpperCase();\n\t\tif (STRIPPED_VARIABLES.has(upper) || STRIPPED_PATTERN.test(upper)) {\n\t\t\tcontinue;\n\t\t}\n\t\tenv[name] = value;\n\t}\n\tenv.GIT_TERMINAL_PROMPT = \"0\";\n\tenv.GIT_OPTIONAL_LOCKS = \"0\";\n\tenv.GIT_NO_LAZY_FETCH = \"1\";\n\tenv.LC_ALL = \"C\";\n\treturn env;\n}\n\ntype Spawned =\n\t| { kind: \"exited\"; code: number; stdout: string; stderr: string }\n\t| { kind: \"unavailable\"; reason: string; missing?: boolean };\n\n/**\n * Run one read-only git command. Private on purpose: the exported functions\n * below are the whole vocabulary.\n */\nfunction runGit(\n\tcwd: string,\n\targs: readonly string[],\n\tdeadline: GitDeadline,\n): Promise<Spawned> {\n\tconst remaining = deadline - Date.now();\n\tif (remaining <= 0) {\n\t\treturn Promise.resolve({\n\t\t\tkind: \"unavailable\",\n\t\t\treason: \"git timed out\",\n\t\t});\n\t}\n\treturn new Promise((resolve) => {\n\t\tlet settled = false;\n\t\tconst finish = (result: Spawned): void => {\n\t\t\tif (!settled) {\n\t\t\t\tsettled = true;\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tresolve(result);\n\t\t\t}\n\t\t};\n\t\tlet child: ReturnType<typeof spawn>;\n\t\ttry {\n\t\t\tchild = spawn(\"git\", [\"-c\", \"core.fsmonitor=false\", ...args], {\n\t\t\t\tcwd,\n\t\t\t\tenv: gitEnvironment(),\n\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\tshell: false,\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tresolve(spawnFailure(error));\n\t\t\treturn;\n\t\t}\n\t\tconst out: Buffer[] = [];\n\t\tlet outBytes = 0;\n\t\tconst err: Buffer[] = [];\n\t\tlet errBytes = 0;\n\t\tchild.stdout?.on(\"data\", (chunk: Buffer) => {\n\t\t\tif (outBytes < STDOUT_CAP_BYTES) {\n\t\t\t\tconst room = STDOUT_CAP_BYTES - outBytes;\n\t\t\t\tout.push(chunk.subarray(0, room));\n\t\t\t\toutBytes += Math.min(room, chunk.length);\n\t\t\t}\n\t\t});\n\t\tchild.stderr?.on(\"data\", (chunk: Buffer) => {\n\t\t\tif (errBytes < STDERR_CAP_BYTES) {\n\t\t\t\tconst room = STDERR_CAP_BYTES - errBytes;\n\t\t\t\terr.push(chunk.subarray(0, room));\n\t\t\t\terrBytes += Math.min(room, chunk.length);\n\t\t\t}\n\t\t});\n\t\tconst timer = setTimeout(() => {\n\t\t\tchild.kill(\"SIGTERM\");\n\t\t\tconst escalate = setTimeout(() => {\n\t\t\t\tchild.kill(\"SIGKILL\");\n\t\t\t}, KILL_GRACE_MS);\n\t\t\tescalate.unref();\n\t\t\tfinish({ kind: \"unavailable\", reason: \"git timed out\" });\n\t\t}, remaining);\n\t\ttimer.unref();\n\t\tchild.on(\"error\", (error) => {\n\t\t\tfinish(spawnFailure(error));\n\t\t});\n\t\tchild.on(\"close\", (code) => {\n\t\t\tfinish({\n\t\t\t\tkind: \"exited\",\n\t\t\t\tcode: code ?? -1,\n\t\t\t\tstdout: Buffer.concat(out).toString(\"utf8\"),\n\t\t\t\tstderr: Buffer.concat(err).toString(\"utf8\"),\n\t\t\t});\n\t\t});\n\t});\n}\n\nfunction spawnFailure(error: unknown): Spawned {\n\tconst code = (error as NodeJS.ErrnoException | null)?.code;\n\tif (code === \"ENOENT\") {\n\t\treturn {\n\t\t\tkind: \"unavailable\",\n\t\t\treason: \"git is not installed\",\n\t\t\tmissing: true,\n\t\t};\n\t}\n\tif (code === \"EACCES\" || code === \"EPERM\") {\n\t\treturn { kind: \"unavailable\", reason: \"git could not be run\" };\n\t}\n\treturn { kind: \"unavailable\", reason: \"git could not be run\" };\n}\n\n/**\n * git's refusal as a fixed reason. Only the SHAPE of stderr is read (with\n * `LC_ALL=C` it is English); none of it is ever returned.\n */\nfunction exitReason(result: { code: number; stderr: string }): string {\n\tconst text = result.stderr;\n\tif (/dubious ownership/i.test(text)) {\n\t\treturn \"git does not trust this repository's owner (safe.directory)\";\n\t}\n\tif (/must be run in a work tree/i.test(text)) {\n\t\treturn \"not a working tree (a bare repository, or inside .git)\";\n\t}\n\tif (/not a git repository/i.test(text)) {\n\t\treturn \"its .git points to a repository that does not exist\";\n\t}\n\tif (/permission denied/i.test(text)) {\n\t\treturn \"permission denied\";\n\t}\n\treturn `git exited with status ${result.code}`;\n}\n\n/** `not a git repository (or any of the parent directories)` — and only that. */\nfunction isNotARepository(stderr: string): boolean {\n\treturn /not a git repository \\(or any/i.test(stderr);\n}\n\nfunction lines(stdout: string): string[] {\n\tconst trimmed = stdout.replace(/\\r?\\n$/, \"\");\n\treturn trimmed === \"\" ? [] : trimmed.split(/\\r?\\n/);\n}\n\n/** The nearest existing directory at or above `dir`, or null. */\nasync function nearestExistingDirectory(dir: string): Promise<string | null> {\n\tlet current = path.resolve(dir);\n\tfor (;;) {\n\t\tconst found = await stat(current).catch(() => null);\n\t\tif (found?.isDirectory()) {\n\t\t\treturn current;\n\t\t}\n\t\tconst parent = path.dirname(current);\n\t\tif (parent === current) {\n\t\t\treturn null;\n\t\t}\n\t\tcurrent = parent;\n\t}\n}\n\n/** Whether any directory at or above `dir` holds a `.git` entry. */\nasync function hasGitEntryAbove(dir: string): Promise<boolean> {\n\tlet current = dir;\n\tfor (;;) {\n\t\tif (\n\t\t\t(await lstat(path.join(current, \".git\")).catch(() => null)) !== null\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t\tconst parent = path.dirname(current);\n\t\tif (parent === current) {\n\t\t\treturn false;\n\t\t}\n\t\tcurrent = parent;\n\t}\n}\n\n/**\n * The work tree `dir` belongs to — `dir` itself, or its nearest existing\n * ancestor when it does not exist yet.\n *\n * When git is not installed, a directory with no `.git` anywhere above it is\n * still answered `absent`: it is certainly not a checkout, and treating it as\n * \"unknown\" would stop a machine without git from doing what it did before.\n */\nexport async function findWorkTree(\n\tdir: string,\n\tdeadline: GitDeadline,\n): Promise<GitResult<WorkTree>> {\n\tconst cwd = await nearestExistingDirectory(dir);\n\tif (cwd === null) {\n\t\treturn { kind: \"absent\" };\n\t}\n\tconst result = await runGit(\n\t\tcwd,\n\t\t[\n\t\t\t\"rev-parse\",\n\t\t\t\"--show-toplevel\",\n\t\t\t\"--is-bare-repository\",\n\t\t\t\"--is-shallow-repository\",\n\t\t\t\"--git-dir\",\n\t\t\t\"--show-superproject-working-tree\",\n\t\t],\n\t\tdeadline,\n\t);\n\tif (result.kind === \"unavailable\") {\n\t\tif (result.missing && !(await hasGitEntryAbove(cwd))) {\n\t\t\treturn { kind: \"absent\" };\n\t\t}\n\t\treturn { kind: \"unavailable\", reason: result.reason };\n\t}\n\tif (result.code !== 0) {\n\t\treturn isNotARepository(result.stderr)\n\t\t\t? { kind: \"absent\" }\n\t\t\t: { kind: \"unavailable\", reason: exitReason(result) };\n\t}\n\tconst [toplevel, bare, shallow, gitDir, superproject, ...rest] = lines(\n\t\tresult.stdout,\n\t);\n\tif (\n\t\t!toplevel ||\n\t\t!gitDir ||\n\t\trest.length > 0 ||\n\t\t(bare !== \"true\" && bare !== \"false\") ||\n\t\t(shallow !== \"true\" && shallow !== \"false\")\n\t) {\n\t\treturn { kind: \"unavailable\", reason: \"git answered unexpectedly\" };\n\t}\n\tif (bare === \"true\") {\n\t\treturn { kind: \"unavailable\", reason: \"a bare repository\" };\n\t}\n\treturn {\n\t\tkind: \"ok\",\n\t\tvalue: {\n\t\t\ttoplevel,\n\t\t\tgitDir: path.resolve(cwd, gitDir),\n\t\t\tshallow: shallow === \"true\",\n\t\t\tsuperproject: superproject ? superproject : null,\n\t\t},\n\t};\n}\n\nasync function simple(\n\troot: string,\n\targs: readonly string[],\n\tdeadline: GitDeadline,\n): Promise<GitResult<{ code: number; stdout: string }>> {\n\tconst result = await runGit(root, args, deadline);\n\tif (result.kind === \"unavailable\") {\n\t\treturn { kind: \"unavailable\", reason: result.reason };\n\t}\n\tif (result.code === 128 && isNotARepository(result.stderr)) {\n\t\treturn { kind: \"absent\" };\n\t}\n\treturn {\n\t\tkind: \"ok\",\n\t\tvalue: { code: result.code, stdout: result.stdout },\n\t};\n}\n\n/** The configured remote names. */\nexport async function remotes(\n\troot: string,\n\tdeadline: GitDeadline,\n): Promise<GitResult<string[]>> {\n\tconst result = await simple(root, [\"remote\"], deadline);\n\tif (result.kind !== \"ok\") {\n\t\treturn result;\n\t}\n\tif (result.value.code !== 0) {\n\t\treturn {\n\t\t\tkind: \"unavailable\",\n\t\t\treason: `git exited with status ${result.value.code}`,\n\t\t};\n\t}\n\treturn { kind: \"ok\", value: lines(result.value.stdout) };\n}\n\n/**\n * The URL git would actually FETCH from for `remote` — after `insteadOf`\n * rewriting, which is why the configured `remote.<name>.url` is not read.\n * `null` when the remote has none: `ls-remote --get-url` echoes a name it\n * cannot resolve, and a name that reads as an option is never passed at all.\n * Contacts no server.\n */\nexport async function effectiveFetchUrl(\n\troot: string,\n\tremote: string,\n\tdeadline: GitDeadline,\n): Promise<GitResult<string | null>> {\n\tif (!REMOTE_NAME.test(remote)) {\n\t\treturn { kind: \"ok\", value: null };\n\t}\n\tconst result = await simple(\n\t\troot,\n\t\t[\"ls-remote\", \"--get-url\", remote],\n\t\tdeadline,\n\t);\n\tif (result.kind !== \"ok\") {\n\t\treturn result;\n\t}\n\tif (result.value.code !== 0) {\n\t\treturn {\n\t\t\tkind: \"unavailable\",\n\t\t\treason: `git exited with status ${result.value.code}`,\n\t\t};\n\t}\n\tconst [url] = lines(result.value.stdout);\n\treturn { kind: \"ok\", value: url && url !== remote ? url : null };\n}\n\n/** The checked-out branch's short name, or `null` for a detached HEAD. */\nexport async function currentBranch(\n\troot: string,\n\tdeadline: GitDeadline,\n): Promise<GitResult<string | null>> {\n\tconst result = await simple(\n\t\troot,\n\t\t[\"symbolic-ref\", \"--short\", \"-q\", \"HEAD\"],\n\t\tdeadline,\n\t);\n\tif (result.kind !== \"ok\") {\n\t\treturn result;\n\t}\n\tif (result.value.code === 1) {\n\t\treturn { kind: \"ok\", value: null };\n\t}\n\tif (result.value.code !== 0) {\n\t\treturn {\n\t\t\tkind: \"unavailable\",\n\t\t\treason: `git exited with status ${result.value.code}`,\n\t\t};\n\t}\n\tconst [branch] = lines(result.value.stdout);\n\treturn { kind: \"ok\", value: branch ?? null };\n}\n\n/** The commit HEAD names, or `null` on a branch with no commits yet. */\nexport async function headSha(\n\troot: string,\n\tdeadline: GitDeadline,\n): Promise<GitResult<string | null>> {\n\tconst result = await simple(\n\t\troot,\n\t\t[\"rev-parse\", \"--verify\", \"-q\", \"HEAD\"],\n\t\tdeadline,\n\t);\n\tif (result.kind !== \"ok\") {\n\t\treturn result;\n\t}\n\tif (result.value.code === 1) {\n\t\treturn { kind: \"ok\", value: null };\n\t}\n\tconst [sha] = lines(result.value.stdout);\n\tif (result.value.code !== 0 || !sha || !COMMIT_SHA.test(sha)) {\n\t\treturn { kind: \"unavailable\", reason: \"git answered unexpectedly\" };\n\t}\n\treturn { kind: \"ok\", value: sha };\n}\n\n/**\n * Whether `ancestorSha` is in `descendantSha`'s history. `unavailable` when\n * git cannot say — most often because the commit has not been fetched into\n * this clone. Both must be full object names; nothing else is passed to git.\n */\nexport async function isAncestor(\n\troot: string,\n\tancestorSha: string,\n\tdescendantSha: string,\n\tdeadline: GitDeadline,\n): Promise<GitResult<boolean>> {\n\tif (!COMMIT_SHA.test(ancestorSha) || !COMMIT_SHA.test(descendantSha)) {\n\t\treturn { kind: \"unavailable\", reason: \"not a commit name\" };\n\t}\n\tconst result = await simple(\n\t\troot,\n\t\t[\"merge-base\", \"--is-ancestor\", ancestorSha, descendantSha],\n\t\tdeadline,\n\t);\n\tif (result.kind !== \"ok\") {\n\t\treturn result;\n\t}\n\tif (result.value.code === 0) {\n\t\treturn { kind: \"ok\", value: true };\n\t}\n\tif (result.value.code === 1) {\n\t\treturn { kind: \"ok\", value: false };\n\t}\n\treturn { kind: \"unavailable\", reason: \"the commit is not in this clone\" };\n}\n\n/**\n * Whether the work tree has no changes, untracked files included — except the\n * session hook's own settings files (`OWN_PATHS`) while they are UNTRACKED,\n * which is how `init` leaves them. A committed copy of either that has been\n * modified is a change like any other.\n *\n * Two questions: everything but the own paths (untracked included), then the\n * own paths among tracked files only.\n */\nexport async function isClean(\n\troot: string,\n\tdeadline: GitDeadline,\n): Promise<GitResult<boolean>> {\n\tconst everythingElse = await porcelainIsEmpty(\n\t\troot,\n\t\t[\n\t\t\t\"--untracked-files=normal\",\n\t\t\t\"--\",\n\t\t\t\":/\",\n\t\t\t...OWN_PATHS.map((own) => `:(exclude,top)${own}`),\n\t\t],\n\t\tdeadline,\n\t);\n\tif (everythingElse.kind !== \"ok\" || !everythingElse.value) {\n\t\treturn everythingElse;\n\t}\n\treturn porcelainIsEmpty(\n\t\troot,\n\t\t[\n\t\t\t\"--untracked-files=no\",\n\t\t\t\"--\",\n\t\t\t...OWN_PATHS.map((own) => `:(top)${own}`),\n\t\t],\n\t\tdeadline,\n\t);\n}\n\nasync function porcelainIsEmpty(\n\troot: string,\n\targs: readonly string[],\n\tdeadline: GitDeadline,\n): Promise<GitResult<boolean>> {\n\tconst result = await simple(\n\t\troot,\n\t\t[\"status\", \"--porcelain=v1\", \"--ignore-submodules=none\", ...args],\n\t\tdeadline,\n\t);\n\tif (result.kind !== \"ok\") {\n\t\treturn result;\n\t}\n\tif (result.value.code !== 0) {\n\t\treturn {\n\t\t\tkind: \"unavailable\",\n\t\t\treason: `git exited with status ${result.value.code}`,\n\t\t};\n\t}\n\treturn { kind: \"ok\", value: result.value.stdout.trim() === \"\" };\n}\n\n/** The operation in progress in this checkout, or `null` when there is none. */\nexport async function operationInProgress(\n\troot: string,\n\tdeadline: GitDeadline,\n): Promise<GitResult<GitOperation | null>> {\n\tconst result = await simple(\n\t\troot,\n\t\t[\n\t\t\t\"rev-parse\",\n\t\t\t...OPERATION_MARKERS.flatMap(({ marker }) => [\n\t\t\t\t\"--git-path\",\n\t\t\t\tmarker,\n\t\t\t]),\n\t\t],\n\t\tdeadline,\n\t);\n\tif (result.kind !== \"ok\") {\n\t\treturn result;\n\t}\n\tconst paths = lines(result.value.stdout);\n\tif (result.value.code !== 0 || paths.length !== OPERATION_MARKERS.length) {\n\t\treturn { kind: \"unavailable\", reason: \"git answered unexpectedly\" };\n\t}\n\tfor (const [index, { operation }] of OPERATION_MARKERS.entries()) {\n\t\tconst marker = path.resolve(root, paths[index] as string);\n\t\tif ((await lstat(marker).catch(() => null)) !== null) {\n\t\t\treturn { kind: \"ok\", value: operation };\n\t\t}\n\t}\n\treturn { kind: \"ok\", value: null };\n}\n\n/** Shallow clone, sparse checkout, submodule of a superproject. */\nexport async function checkoutTraits(\n\troot: string,\n\tdeadline: GitDeadline,\n): Promise<GitResult<CheckoutTraits>> {\n\tconst tree = await simple(\n\t\troot,\n\t\t[\n\t\t\t\"rev-parse\",\n\t\t\t\"--is-shallow-repository\",\n\t\t\t\"--show-superproject-working-tree\",\n\t\t],\n\t\tdeadline,\n\t);\n\tif (tree.kind !== \"ok\") {\n\t\treturn tree;\n\t}\n\tconst [shallow, superproject] = lines(tree.value.stdout);\n\tif (tree.value.code !== 0) {\n\t\treturn { kind: \"unavailable\", reason: \"git answered unexpectedly\" };\n\t}\n\tconst sparse = await simple(\n\t\troot,\n\t\t[\"config\", \"--get\", \"core.sparseCheckout\"],\n\t\tdeadline,\n\t);\n\tif (sparse.kind !== \"ok\") {\n\t\treturn sparse;\n\t}\n\treturn {\n\t\tkind: \"ok\",\n\t\tvalue: {\n\t\t\tshallow: shallow === \"true\",\n\t\t\tsparse:\n\t\t\t\tsparse.value.code === 0 &&\n\t\t\t\tlines(sparse.value.stdout)[0]?.toLowerCase() === \"true\",\n\t\t\tsuperproject: Boolean(superproject),\n\t\t},\n\t};\n}\n\n/**\n * Whether `ref` is a branch name this CLI will compare, print and put in a\n * suggested command: the literal must pass `BRANCH_LITERAL` with no `..`, no\n * `@{`, no trailing `/` or `.lock`, AND git's own `check-ref-format --branch`\n * must accept it unchanged.\n */\nexport async function checkRefFormat(\n\troot: string,\n\tref: string,\n\tdeadline: GitDeadline,\n): Promise<GitResult<boolean>> {\n\tif (!isBranchLiteral(ref)) {\n\t\treturn { kind: \"ok\", value: false };\n\t}\n\tconst result = await simple(\n\t\troot,\n\t\t[\"check-ref-format\", \"--branch\", ref],\n\t\tdeadline,\n\t);\n\tif (result.kind !== \"ok\") {\n\t\treturn result;\n\t}\n\tconst [normalized] = lines(result.value.stdout);\n\treturn { kind: \"ok\", value: result.value.code === 0 && normalized === ref };\n}\n\n/** The literal half of `checkRefFormat`, exported for tests and callers that must not spawn. */\nexport function isBranchLiteral(ref: string): boolean {\n\treturn (\n\t\tref.length <= 255 &&\n\t\tBRANCH_LITERAL.test(ref) &&\n\t\t!ref.includes(\"..\") &&\n\t\t!ref.includes(\"@{\") &&\n\t\t!ref.includes(\"//\") &&\n\t\t!ref.endsWith(\"/\") &&\n\t\t!ref.endsWith(\".\") &&\n\t\t!ref.endsWith(\".lock\")\n\t);\n}\n\n/** Whether `sha` is a full commit name this module would pass to git. */\nexport function isCommitSha(sha: string): boolean {\n\treturn COMMIT_SHA.test(sha);\n}\n","/**\n * Which repository a git remote URL names, compared with the repository a\n * project syncs its coding instructions from (Fizzy #2708). Pure: no I/O.\n *\n * Deliberately narrow. Only three spellings are understood, and only without\n * a port, because the project's configuration is a bare host and path and a\n * URL this cannot reduce to exactly that must never be taken for a match:\n *\n * https://host/path[.git] optional userinfo, dropped\n * ssh://[user@]host/path[.git]\n * [user@]host:path[.git] scp-like\n *\n * Everything else — a port, `file://`, `git://`, a local or UNC path, a\n * Windows drive letter — is `null`. So is a URL whose `insteadOf` rewrite\n * points at a local mirror: the caller parses the EFFECTIVE fetch URL, and a\n * checkout that fetches from somewhere else is not a checkout of this\n * repository as far as the published commit is concerned.\n *\n * Userinfo is never returned. It is where a credential lives in a URL.\n */\nimport type { PublishedInstructionRepository } from \"@fabricorg/sdk\";\n\nexport interface ParsedRemote {\n\t/** Lowercased. */\n\thost: string;\n\t/** Every segment, `.git` stripped: `group/subgroup/repo` on GitLab. */\n\tpath: string;\n}\n\nconst HOST =\n\t/^[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?(?:\\.[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?)*$/;\n\nfunction parsePath(raw: string): string | null {\n\tlet value = raw;\n\twhile (value.endsWith(\"/\")) {\n\t\tvalue = value.slice(0, -1);\n\t}\n\tif (value.endsWith(\".git\")) {\n\t\tvalue = value.slice(0, -\".git\".length);\n\t}\n\tif (value === \"\" || value.startsWith(\"/\")) {\n\t\treturn null;\n\t}\n\tconst segments = value.split(\"/\");\n\tfor (const segment of segments) {\n\t\tif (\n\t\t\tsegment === \"\" ||\n\t\t\tsegment === \".\" ||\n\t\t\tsegment === \"..\" ||\n\t\t\t/[\\s\\\\?#]/.test(segment) ||\n\t\t\t// biome-ignore lint/suspicious/noControlCharactersInRegex: rejecting them is the point\n\t\t\t/[\\u0000-\\u001f\\u007f]/.test(segment)\n\t\t) {\n\t\t\treturn null;\n\t\t}\n\t}\n\treturn segments.join(\"/\");\n}\n\nfunction parseHost(raw: string): string | null {\n\treturn HOST.test(raw) ? raw.toLowerCase() : null;\n}\n\n/** `[user@]host` → host, or null when what remains is not a bare hostname. */\nfunction withoutUser(authority: string): string | null {\n\tconst at = authority.lastIndexOf(\"@\");\n\tconst host = at === -1 ? authority : authority.slice(at + 1);\n\t// A `:` left in the authority is a port (or a password with no user),\n\t// and a port is never matched.\n\treturn host.includes(\":\") ? null : parseHost(host);\n}\n\nexport function parseRemoteUrl(url: string): ParsedRemote | null {\n\tconst value = url.trim();\n\tif (value === \"\" || value.startsWith(\"\\\\\\\\\") || value.startsWith(\"//\")) {\n\t\treturn null;\n\t}\n\n\tconst scheme = /^([A-Za-z][A-Za-z0-9+.-]*):\\/\\//.exec(value);\n\tif (scheme) {\n\t\tconst name = (scheme[1] as string).toLowerCase();\n\t\tif (name !== \"https\" && name !== \"ssh\") {\n\t\t\treturn null;\n\t\t}\n\t\tconst rest = value.slice(scheme[0].length);\n\t\tconst slash = rest.indexOf(\"/\");\n\t\tif (slash <= 0) {\n\t\t\treturn null;\n\t\t}\n\t\tconst host = withoutUser(rest.slice(0, slash));\n\t\tconst repoPath = parsePath(rest.slice(slash + 1));\n\t\treturn host && repoPath ? { host, path: repoPath } : null;\n\t}\n\n\t// scp-like: `[user@]host:path`. Only when no `/` comes before the first\n\t// `:` (otherwise it is a local path), and never a single letter before it\n\t// (a Windows drive, `C:\\…` or `C:/…`).\n\tconst colon = value.indexOf(\":\");\n\tif (colon <= 0) {\n\t\treturn null;\n\t}\n\tconst authority = value.slice(0, colon);\n\tif (authority.includes(\"/\") || authority.includes(\"\\\\\")) {\n\t\treturn null;\n\t}\n\tconst hostPart = authority.slice(authority.lastIndexOf(\"@\") + 1);\n\tif (/^[A-Za-z]$/.test(hostPart)) {\n\t\treturn null;\n\t}\n\tconst host = withoutUser(authority);\n\t// `host:2222/x` is scp syntax for the PATH `2222/x`: scp-like URLs have\n\t// no port, and git reads them exactly this way.\n\tconst repoPath = parsePath(value.slice(colon + 1));\n\treturn host && repoPath ? { host, path: repoPath } : null;\n}\n\nexport type RepositoryMatch = \"match\" | \"mismatch\" | \"unsupported-provider\";\n\n/**\n * Whether a parsed remote is the project's repository. The host always\n * compares case-insensitively; the path does only on GitHub, whose owner and\n * repository names are case-insensitive. GitLab paths compare exactly. Azure\n * DevOps URLs carry an organization, project and `_git` segment the\n * configuration does not spell the same way, so they are not compared at all.\n */\nexport function matches(\n\tparsed: ParsedRemote,\n\trepository: Pick<\n\t\tPublishedInstructionRepository,\n\t\t\"provider\" | \"host\" | \"path\"\n\t>,\n): RepositoryMatch {\n\tif (repository.provider !== \"GITHUB\" && repository.provider !== \"GITLAB\") {\n\t\treturn \"unsupported-provider\";\n\t}\n\tif (parsed.host !== repository.host.toLowerCase()) {\n\t\treturn \"mismatch\";\n\t}\n\tconst expected = repository.path.replace(/^\\/+|\\/+$/g, \"\");\n\tif (repository.provider === \"GITHUB\") {\n\t\treturn parsed.path.toLowerCase() === expected.toLowerCase()\n\t\t\t? \"match\"\n\t\t\t: \"mismatch\";\n\t}\n\treturn parsed.path === expected ? \"match\" : \"mismatch\";\n}\n","/**\n * `fabric instructions doctor` — is this machine set up the way the project's\n * coding instructions expect?\n *\n * Nine checks, in `CHECK_IDS` order, each one a finding with at most one\n * proposed remedy. The shape is the one the MCP `fabric_instruction_checks`\n * tool returns (`checks.ts`), so an agent reads either surface the same way.\n *\n * What this module will not do, and why each line matters:\n *\n * - It never EXECUTES anything a project names. Tools named by the\n * published `fabric.environment.json` and commands named by a\n * repository's `.mcp.json` are checked by PATH lookup (`stat`) only.\n * Running `<tool> --version` would be code execution chosen by whoever\n * can publish the instruction set or commit to the repository. The one\n * program it does run is `git`, and only for a repository-sourced\n * project, through `git.ts`'s fixed read-only questions (which remote,\n * which branch, is the published commit in HEAD's history) with prompts\n * disabled — nothing that fetches or changes the checkout (Fizzy #2708).\n * - It never reads, prints or sends a DECLARED environment variable's\n * VALUE. A declaration names variables; presence is `Object.keys(env)`.\n * The only values this module reads are `PATH` and `PATHEXT`, for the\n * lookup, and it never prints them.\n * - It never repeats an exception message, an input excerpt, or a URL.\n * Every detail is either fixed text, a number, a validated identifier, or\n * published/repository text passed through `sanitizeDisplayText` with a\n * bound. An unexpected exception inside a check becomes that check's\n * `fail` with the error's class name, and the next check runs.\n * - Its fixes are PROPOSALS. A generated `fix.command` is built only from\n * validated, shell-quoted arguments the person gave doctor (project id,\n * `--org`, `--dest`) — never from declaration or repository text — and\n * nothing here acts on one. Installing software, changing credentials\n * and overwriting files are a person's decisions.\n * - It touches the network for three reasons only: the key check, the\n * published manifest, and — when the published declaration is not\n * already on disk and current — the bundle that carries it. `.mcp.json`\n * `url` servers are probed only under `--probe-network`, with no headers\n * from the config, no redirects followed, and the body never read.\n */\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport type {\n\tInstructionDownload,\n\tInstructionManifestEntry,\n\tPublishedInstructionRepository,\n\tPublishedInstructionSnapshot,\n\tPublishedInstructionSource,\n\tPublishedInstructions,\n\tWhoamiResult,\n} from \"@fabricorg/sdk\";\nimport { extractBundle } from \"./bundle.js\";\nimport {\n\ttype CheckoutReport,\n\tdownloadsIn,\n\tinspectCheckout as inspectCheckoutWithGit,\n\treportFor,\n} from \"./checkout.js\";\nimport {\n\tbuildChecksReport,\n\tCHECK_TITLES,\n\ttype CheckEvidence,\n\ttype CheckFix,\n\ttype CheckId,\n\ttype CheckItem,\n\ttype CheckStatus,\n\tevaluateDeclaredVariables,\n\tINSTRUCTION_ENVIRONMENT_FILE,\n\tINSTRUCTION_ENVIRONMENT_MAX_BYTES,\n\ttype InstructionCheck,\n\ttype InstructionChecksReport,\n\ttype InstructionEnvironment,\n\tparseInstructionEnvironment,\n\tsanitizeDisplayText,\n\tTOOL_NAME,\n} from \"./checks.js\";\nimport {\n\tbuildHookCommand,\n\tfindSessionStartHooks,\n\ttype InstructionsHookTool,\n} from \"./hook.js\";\nimport {\n\ttype InstructionsLock,\n\tLockReadRefusedError,\n\tlockPath,\n\treadLockSafely,\n} from \"./lock.js\";\nimport { maxArchiveBytes } from \"./manifest.js\";\nimport {\n\tisTooLarge,\n\tMCP_CONFIG_FILE,\n\ttype McpServerEntry,\n\treadMcpConfig,\n} from \"./mcp-config.js\";\nimport {\n\tisExecutableFile,\n\tisOnPath,\n\ttype PathLookupEnvironment,\n} from \"./path-lookup.js\";\nimport { findLedgerDrift, type LedgerDriftReason } from \"./plan.js\";\nimport { readFileSafely } from \"./safe-write.js\";\n\n// ---------------------------------------------------------------------------\n// Inputs\n// ---------------------------------------------------------------------------\n\n/** The two server calls doctor makes on the manifest client. */\ninterface DoctorClient {\n\tauth: { whoami(): Promise<WhoamiResult> };\n\tinstructions: {\n\t\tgetPublished(\n\t\t\tprojectId: string,\n\t\t\toptions: { org?: string },\n\t\t): Promise<PublishedInstructions>;\n\t};\n}\n\nexport interface DoctorInput {\n\tprojectId: string;\n\t/** `--org` exactly as given, or undefined. Never an ambient default. */\n\torg?: string;\n\t/** The absolute destination, shown in details. */\n\tdestination: string;\n\t/** The canonical root every guarded read resolves against. */\n\troot: string;\n\t/**\n\t * `--dest` as generated fix commands should carry it, or undefined when\n\t * doctor was not given one (the commands then run in the same cwd).\n\t */\n\tcommandDest?: string;\n\tprobeNetwork: boolean;\n\t/** Names are read from here; values are read only for PATH and PATHEXT. */\n\tenv: Readonly<Record<string, string | undefined>>;\n\tplatform: NodeJS.Platform;\n\t/** Whether a key is configured at all. The key itself never reaches this module. */\n\tapiKeyPresent: boolean;\n\t/** Built lazily, and only once a key is known to exist. */\n\tclient: () => DoctorClient;\n\tcreateDownloadUrl: (\n\t\tprojectId: string,\n\t\toptions: { org?: string },\n\t) => Promise<InstructionDownload>;\n\t/** Download the bundle, reading at most `maxBytes`. */\n\tfetchArchive: (url: string, maxBytes: number) => Promise<Uint8Array>;\n\t/** The fetch `--probe-network` uses; the global one when omitted. */\n\tfetchImpl?: typeof fetch;\n\t/**\n\t * What kind of directory `root` is for a repository-sourced project\n\t * (Fizzy #2708); `checkout.ts`'s read-only git inspection when omitted.\n\t */\n\tinspectCheckout?: (input: {\n\t\trepository: PublishedInstructionRepository | null | undefined;\n\t\tsnapshot: PublishedInstructionSnapshot | undefined;\n\t}) => Promise<CheckoutReport>;\n}\n\n// ---------------------------------------------------------------------------\n// Limits and fixed wording\n// ---------------------------------------------------------------------------\n\n/** Items listed per check before the rest are summarised. */\nconst MAX_ITEMS = 50;\n/** Names listed inside one fix description. */\nconst MAX_NAMES_IN_FIX = 20;\n/** A 5000-file lock is about a megabyte; anything near this is not a lock. */\nconst MAX_LOCK_BYTES = 16 * 1024 * 1024;\n/**\n * The largest archive a VALID snapshot can be (`manifest.ts`'s limits: 50 MiB\n * of content, 5000 entries of up to 1024-byte paths, plus framing). The\n * doctor caps the download at this whatever the manifest claims, because it\n * reads the manifest without `assertValidManifest`.\n */\nconst MAX_DOWNLOAD_BYTES = 52_428_800 + 1_048_576 + 5000 * (512 + 2 * 1024);\n\nconst PROBE_TIMEOUT_MS = 5_000;\nconst PROBE_BUDGET_MS = 15_000;\nconst MAX_PROBES = 20;\nconst PROBE_CONCURRENCY = 4;\n\nconst LOGIN_COMMAND = \"fabric auth login --key <api-key>\";\nconst CLI_INSTALL_COMMAND = \"npm install -g @fabricorg/cli\";\n/** The read-only git inspection's whole budget. */\nconst GIT_BUDGET_MS = 10_000;\nconst LOCK_NOT_USED = \"not used in a checkout of the repository\";\nconst SKIP_AFTER_AUTH = \"not evaluated: the API key check failed\";\nconst SKIP_AFTER_ACCESS = \"not evaluated: the project could not be read\";\nconst SKIP_AFTER_PUBLISHED =\n\t\"not evaluated: the published version could not be read\";\nconst NOTHING_PUBLISHED = \"nothing published to compare against\";\nconst HOOK_NOT_VERIFIED =\n\t\"execution, trust and the coding tool's PATH are not verified\";\nconst NETWORK_FIX =\n\t\"check the network connection and the deployment URL (FABRIC_BASE_URL, or the profile's --base-url), then rerun doctor\";\nconst DECLARATION_FORMAT_FIX = `fix ${INSTRUCTION_ENVIRONMENT_FILE} in the instruction set; its format is in docs/guides/coding-instructions-cli.md`;\n\n// ---------------------------------------------------------------------------\n// Small helpers\n// ---------------------------------------------------------------------------\n\nfunction makeCheck(\n\tid: CheckId,\n\tevidence: CheckEvidence,\n\tstatus: CheckStatus,\n\tdetail: string,\n\textra: {\n\t\titems?: CheckItem[];\n\t\tfix?: CheckFix;\n\t\tsource?: PublishedInstructionSource;\n\t\t/**\n\t\t * The project's CURRENT repository-sync configuration (Fizzy #2709) —\n\t\t * a sibling of `source`, which is the per-snapshot provenance. `null`\n\t\t * means the project is UPLOAD-sourced, or is REPOSITORY-sourced with\n\t\t * no sync row; `undefined` (the field left out entirely) means the\n\t\t * caller has nothing to report for this check.\n\t\t */\n\t\trepository?: PublishedInstructionRepository | null;\n\t} = {},\n): InstructionCheck {\n\treturn {\n\t\tid,\n\t\ttitle: CHECK_TITLES[id],\n\t\tstatus,\n\t\tevidence,\n\t\tdetail,\n\t\t...(extra.items !== undefined && extra.items.length > 0\n\t\t\t? { items: extra.items }\n\t\t\t: {}),\n\t\t...(extra.fix !== undefined ? { fix: extra.fix } : {}),\n\t\t...(extra.source !== undefined ? { source: extra.source } : {}),\n\t\t...(extra.repository !== undefined\n\t\t\t? { repository: extra.repository }\n\t\t\t: {}),\n\t};\n}\n\nfunction fixOf(description: string, command?: string): CheckFix {\n\treturn command === undefined ? { description } : { command, description };\n}\n\n/** The error's class name, and nothing it says about itself. */\nfunction errorClassName(error: unknown): string {\n\tconst name =\n\t\terror instanceof Error\n\t\t\t? error.name || error.constructor?.name\n\t\t\t: typeof error;\n\treturn typeof name === \"string\" && /^[A-Za-z0-9_]{1,64}$/.test(name)\n\t\t? name\n\t\t: \"Error\";\n}\n\n/**\n * The fix for a check an exception stopped. Generic on purpose: the only\n * thing known about the failure is its class name, and a fix is promised for\n * every `fail`.\n */\nconst COULD_NOT_RUN_FIX =\n\t\"rerun doctor; if this check keeps failing, report the failure class shown above\";\n\nfunction couldNotRun(\n\tid: CheckId,\n\tevidence: CheckEvidence,\n\terror: unknown,\n): InstructionCheck {\n\treturn makeCheck(\n\t\tid,\n\t\tevidence,\n\t\t\"fail\",\n\t\t`check could not run (${errorClassName(error)})`,\n\t\t{ fix: fixOf(COULD_NOT_RUN_FIX) },\n\t);\n}\n\nasync function guarded(\n\tid: CheckId,\n\tevidence: CheckEvidence,\n\tbody: () => Promise<InstructionCheck>,\n): Promise<InstructionCheck> {\n\ttry {\n\t\treturn await body();\n\t} catch (error) {\n\t\treturn couldNotRun(id, evidence, error);\n\t}\n}\n\nasync function guardedWithState<T>(\n\tid: CheckId,\n\tevidence: CheckEvidence,\n\tfallback: T,\n\tbody: () => Promise<[InstructionCheck, T]>,\n): Promise<[InstructionCheck, T]> {\n\ttry {\n\t\treturn await body();\n\t} catch (error) {\n\t\treturn [couldNotRun(id, evidence, error), fallback];\n\t}\n}\n\nfunction statusOf(error: unknown): number | undefined {\n\tconst status = (error as { status?: unknown } | null)?.status;\n\treturn typeof status === \"number\" ? status : undefined;\n}\n\nfunction codeOf(error: unknown): string | undefined {\n\tconst code = (error as { code?: unknown } | null)?.code;\n\treturn typeof code === \"string\" ? code : undefined;\n}\n\n/** An SDK failure as a class: never the server's or the runtime's message. */\nfunction requestFailureClass(error: unknown): string {\n\tconst code = codeOf(error);\n\tif (code === \"TIMEOUT\") {\n\t\treturn \"timed out\";\n\t}\n\tif (code === \"NETWORK_ERROR\") {\n\t\treturn \"could not reach the server\";\n\t}\n\tconst status = statusOf(error);\n\tif (status !== undefined && status > 0) {\n\t\treturn `HTTP ${status}`;\n\t}\n\treturn `unexpected ${errorClassName(error)}`;\n}\n\nfunction hasControlCharacter(value: string): boolean {\n\tfor (let index = 0; index < value.length; index++) {\n\t\tconst code = value.charCodeAt(index);\n\t\tif (code < 0x20 || (code >= 0x7f && code <= 0x9f)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nconst SHELL_SAFE = /^[A-Za-z0-9_@%+=:,./-]+$/;\n\n/** POSIX single-quoting: safe to paste into sh, bash and zsh. */\nfunction shellQuote(value: string): string {\n\tif (value.length > 0 && SHELL_SAFE.test(value)) {\n\t\treturn value;\n\t}\n\treturn `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\n/**\n * `fabric <args>` as one pasteable POSIX command, or `undefined` when any\n * word carries a control character: a newline in a path cannot be quoted\n * into something a person can safely paste, so no command is offered at all.\n * Doctor's fixes and the sync report's repair command both come from here.\n */\nexport function buildFabricCommand(\n\targs: readonly string[],\n): string | undefined {\n\tif (args.some(hasControlCharacter)) {\n\t\treturn undefined;\n\t}\n\treturn [\"fabric\", ...args].map(shellQuote).join(\" \");\n}\n\nfunction sha256Hex(bytes: Uint8Array): string {\n\treturn createHash(\"sha256\").update(bytes).digest(\"hex\");\n}\n\nfunction listNames(names: readonly string[]): string {\n\tconst shown = names.slice(0, MAX_NAMES_IN_FIX);\n\tconst rest = names.length - shown.length;\n\treturn rest > 0 ? `${shown.join(\", \")} and ${rest} more` : shown.join(\", \");\n}\n\nfunction capItems(items: CheckItem[], status: CheckStatus): CheckItem[] {\n\tif (items.length <= MAX_ITEMS) {\n\t\treturn items;\n\t}\n\treturn [\n\t\t...items.slice(0, MAX_ITEMS),\n\t\t{\n\t\t\tname: `${items.length - MAX_ITEMS} more`,\n\t\t\tstatus,\n\t\t\tdetail: \"not listed\",\n\t\t},\n\t];\n}\n\nfunction plural(count: number, noun: string): string {\n\treturn `${count} ${noun}${count === 1 ? \"\" : \"s\"}`;\n}\n\n// ---------------------------------------------------------------------------\n// Generated commands\n// ---------------------------------------------------------------------------\n\n/**\n * The fix commands doctor proposes, built ONLY from arguments the person\n * gave it. Every one carries `--org` and `--dest` when doctor had them, so a\n * pasted command acts on the same project, context and checkout. A value with\n * a control character produces no command at all rather than one that would\n * not survive a paste.\n */\nclass Commands {\n\tconstructor(private readonly input: DoctorInput) {}\n\n\tprivate context(): string[] {\n\t\treturn [\n\t\t\t...(this.input.org !== undefined ? [\"--org\", this.input.org] : []),\n\t\t\t...(this.input.commandDest !== undefined\n\t\t\t\t? [\"--dest\", this.input.commandDest]\n\t\t\t\t: []),\n\t\t];\n\t}\n\n\tprivate build(args: string[]): string | undefined {\n\t\treturn buildFabricCommand(args);\n\t}\n\n\tsync(): string | undefined {\n\t\treturn this.build([\n\t\t\t\"instructions\",\n\t\t\t\"sync\",\n\t\t\t\"--project\",\n\t\t\tthis.input.projectId,\n\t\t\t...this.context(),\n\t\t]);\n\t}\n\n\trepair(): string | undefined {\n\t\treturn this.build([\n\t\t\t\"instructions\",\n\t\t\t\"sync\",\n\t\t\t\"--project\",\n\t\t\tthis.input.projectId,\n\t\t\t...this.context(),\n\t\t\t\"--repair\",\n\t\t]);\n\t}\n\n\tpush(): string | undefined {\n\t\treturn this.build([\n\t\t\t\"instructions\",\n\t\t\t\"push\",\n\t\t\t\"--project\",\n\t\t\tthis.input.projectId,\n\t\t\t...this.context(),\n\t\t]);\n\t}\n\n\tinit(tool: InstructionsHookTool): string | undefined {\n\t\treturn this.build([\n\t\t\t\"instructions\",\n\t\t\t\"init\",\n\t\t\t\"--project\",\n\t\t\tthis.input.projectId,\n\t\t\t\"--tool\",\n\t\t\ttool,\n\t\t\t...this.context(),\n\t\t]);\n\t}\n\n\tdoctor(): string | undefined {\n\t\treturn this.build([\n\t\t\t\"instructions\",\n\t\t\t\"doctor\",\n\t\t\t\"--project\",\n\t\t\tthis.input.projectId,\n\t\t\t...this.context(),\n\t\t\t...(this.input.probeNetwork ? [\"--probe-network\"] : []),\n\t\t]);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// State carried between checks\n// ---------------------------------------------------------------------------\n\ntype AccessState =\n\t| { kind: \"unavailable\"; reason: string }\n\t| { kind: \"ok\"; published: PublishedInstructions };\n\ntype SnapshotState =\n\t| { kind: \"unavailable\"; reason: string }\n\t| { kind: \"unpublished\" }\n\t| {\n\t\t\tkind: \"published\";\n\t\t\tsnapshot: PublishedInstructionSnapshot;\n\t\t\tmanifest: InstructionManifestEntry[];\n\t };\n\n/**\n * A repository-sourced project's checkout, as `check` and the hook see it\n * (Fizzy #2708). `null` for a project that is not repository-sourced, and\n * when the published answer could not be read.\n */\ntype CheckoutState = CheckoutReport | null;\n\n/** `not-git` and `null` both mean \"the upload behaviour applies here\". */\nfunction checkoutClass(\n\tcheckout: CheckoutState,\n): \"upload\" | \"matching\" | \"other\" {\n\tif (checkout === null || checkout.classification.class === \"not-git\") {\n\t\treturn \"upload\";\n\t}\n\treturn checkout.classification.class === \"matching\" ? \"matching\" : \"other\";\n}\n\n/** A class line as a check detail: the same words, without the prefix. */\nfunction checkoutDetail(checkout: CheckoutReport): string {\n\treturn (checkout.line ?? \"\").replace(/^fabric: /, \"\");\n}\n\ntype LockState =\n\t| { kind: \"not-evaluated\" }\n\t| { kind: \"absent\" }\n\t| { kind: \"unreadable\" }\n\t| { kind: \"foreign\" }\n\t/** `current`: the lock's digest is the published one. */\n\t| { kind: \"usable\"; lock: InstructionsLock; current: boolean };\n\n/**\n * Where the declaration came from. `published`: the snapshot's own file.\n * `local-unpublished`: a file on disk the published snapshot does not carry.\n * `checkout`: a repository-backed project's file, read from the checkout.\n */\ntype Provenance = \"published\" | \"local-unpublished\" | \"checkout\";\n\ntype DeclarationState =\n\t| { kind: \"skip\"; detail: string }\n\t| {\n\t\t\tkind: \"unreadable\";\n\t\t\tstatus: \"fail\" | \"warn\";\n\t\t\tdetail: string;\n\t\t\t/** Required: every `fail` in a report carries a proposed fix. */\n\t\t\tfix: CheckFix;\n\t }\n\t| {\n\t\t\tkind: \"ok\";\n\t\t\tdeclaration: InstructionEnvironment;\n\t\t\tprovenance: Provenance;\n\t };\n\n// ---------------------------------------------------------------------------\n// The run\n// ---------------------------------------------------------------------------\n\nexport async function runDoctor(\n\tinput: DoctorInput,\n): Promise<InstructionChecksReport> {\n\tlet built: DoctorClient | undefined;\n\tconst client = (): DoctorClient => {\n\t\tif (built === undefined) {\n\t\t\tbuilt = input.client();\n\t\t}\n\t\treturn built;\n\t};\n\tconst commands = new Commands(input);\n\n\tconst [auth, authOk] = await guardedWithState<boolean>(\n\t\t\"auth\",\n\t\t\"server\",\n\t\tfalse,\n\t\t() => checkAuth(input, client),\n\t);\n\tconst [access, accessState] = await guardedWithState<AccessState>(\n\t\t\"access\",\n\t\t\"server\",\n\t\t{ kind: \"unavailable\", reason: SKIP_AFTER_ACCESS },\n\t\t() => checkAccess(input, client, authOk),\n\t);\n\tconst [published, snapshot] = await guardedWithState<SnapshotState>(\n\t\t\"published\",\n\t\t\"server\",\n\t\t{ kind: \"unavailable\", reason: SKIP_AFTER_PUBLISHED },\n\t\tasync () => checkPublished(accessState),\n\t);\n\tconst checkout = await resolveCheckout(input, accessState);\n\tconst [lock, lockState] = await guardedWithState<LockState>(\n\t\t\"lock\",\n\t\t\"machine\",\n\t\t{ kind: \"not-evaluated\" },\n\t\t() => checkLock(input, commands, snapshot, checkout),\n\t);\n\tconst drift = await guarded(\"drift\", \"machine\", () =>\n\t\tcheckDrift(input, commands, snapshot, lockState, checkout),\n\t);\n\tconst hook = await guarded(\"hook\", \"machine\", () =>\n\t\tcheckHook(input, commands, snapshot, checkout),\n\t);\n\n\tlet declaration: DeclarationState;\n\ttry {\n\t\tdeclaration = await resolveDeclaration(\n\t\t\tinput,\n\t\t\tcommands,\n\t\t\tclient,\n\t\t\tsnapshot,\n\t\t\tlockState,\n\t\t\tcheckout,\n\t\t);\n\t} catch (error) {\n\t\tdeclaration = {\n\t\t\tkind: \"unreadable\",\n\t\t\tstatus: \"fail\",\n\t\t\tdetail: `check could not run (${errorClassName(error)})`,\n\t\t\tfix: fixOf(COULD_NOT_RUN_FIX),\n\t\t};\n\t}\n\tconst environment = await guarded(\"environment\", \"machine\", async () =>\n\t\tcheckEnvironment(input, declaration),\n\t);\n\tconst tools = await guarded(\"tools\", \"machine\", () =>\n\t\tcheckTools(input, declaration),\n\t);\n\tconst mcpServers = await guarded(\"mcp-servers\", \"machine\", () =>\n\t\tcheckMcpServers(input),\n\t);\n\n\treturn buildChecksReport(input.projectId, \"cli\", [\n\t\tauth,\n\t\taccess,\n\t\tpublished,\n\t\tlock,\n\t\tdrift,\n\t\thook,\n\t\tenvironment,\n\t\ttools,\n\t\tmcpServers,\n\t]);\n}\n\n/**\n * Classify the directory for a repository-sourced project, once, so the lock,\n * drift, hook and declaration checks all read the same answer. Never throws:\n * a failure is the `unknown` class.\n */\nasync function resolveCheckout(\n\tinput: DoctorInput,\n\taccess: AccessState,\n): Promise<CheckoutState> {\n\tif (\n\t\taccess.kind !== \"ok\" ||\n\t\taccess.published.sourceOfTruth !== \"REPOSITORY\"\n\t) {\n\t\treturn null;\n\t}\n\tconst { repository, snapshot } = access.published;\n\ttry {\n\t\treturn input.inspectCheckout\n\t\t\t? await input.inspectCheckout({ repository, snapshot })\n\t\t\t: await inspectCheckoutWithGit({\n\t\t\t\t\tdestination: input.root,\n\t\t\t\t\trepository,\n\t\t\t\t\tsnapshot,\n\t\t\t\t\tdeadline: Date.now() + GIT_BUDGET_MS,\n\t\t\t\t});\n\t} catch {\n\t\treturn reportFor(repository, {\n\t\t\tclass: \"unknown\",\n\t\t\treason: \"the checkout could not be read\",\n\t\t});\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// auth\n// ---------------------------------------------------------------------------\n\nasync function checkAuth(\n\tinput: DoctorInput,\n\tclient: () => DoctorClient,\n): Promise<[InstructionCheck, boolean]> {\n\tconst id = \"auth\";\n\tif (!input.apiKeyPresent) {\n\t\treturn [\n\t\t\tmakeCheck(\n\t\t\t\tid,\n\t\t\t\t\"server\",\n\t\t\t\t\"fail\",\n\t\t\t\t\"no API key: FABRIC_API_KEY is not set and the active profile stores none\",\n\t\t\t\t{\n\t\t\t\t\tfix: fixOf(\n\t\t\t\t\t\t\"log in with an organization API key that carries instructions:read (create one in the organization's Settings → API keys)\",\n\t\t\t\t\t\tLOGIN_COMMAND,\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t),\n\t\t\tfalse,\n\t\t];\n\t}\n\n\tlet who: WhoamiResult;\n\ttry {\n\t\twho = await client().auth.whoami();\n\t} catch (error) {\n\t\tif (statusOf(error) === 401) {\n\t\t\treturn [\n\t\t\t\tmakeCheck(\n\t\t\t\t\tid,\n\t\t\t\t\t\"server\",\n\t\t\t\t\t\"fail\",\n\t\t\t\t\t\"the API key was refused (HTTP 401)\",\n\t\t\t\t\t{\n\t\t\t\t\t\tfix: fixOf(\n\t\t\t\t\t\t\t\"the key is invalid, revoked or expired: log in with a current organization API key that carries instructions:read\",\n\t\t\t\t\t\t\tLOGIN_COMMAND,\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t\tfalse,\n\t\t\t];\n\t\t}\n\t\treturn [\n\t\t\tmakeCheck(\n\t\t\t\tid,\n\t\t\t\t\"server\",\n\t\t\t\t\"fail\",\n\t\t\t\t`the API key could not be checked (${requestFailureClass(error)})`,\n\t\t\t\t{ fix: fixOf(NETWORK_FIX) },\n\t\t\t),\n\t\t\tfalse,\n\t\t];\n\t}\n\n\tconst keyType =\n\t\twho.keyType === \"organization\" || who.keyType === \"personal\"\n\t\t\t? who.keyType\n\t\t\t: \"unknown\";\n\tconst prefix =\n\t\ttypeof who.keyPrefix === \"string\" && who.keyPrefix.length > 0\n\t\t\t? sanitizeDisplayText(who.keyPrefix, 24)\n\t\t\t: \"(no prefix)\";\n\tconst label = `${keyType} key ${prefix}`;\n\n\tif (!Array.isArray(who.scopes)) {\n\t\t// Not a refusal: the project read below is the real test.\n\t\treturn [\n\t\t\tmakeCheck(\n\t\t\t\tid,\n\t\t\t\t\"server\",\n\t\t\t\t\"warn\",\n\t\t\t\t`${label}; its scopes were not reported`,\n\t\t\t),\n\t\t\ttrue,\n\t\t];\n\t}\n\tconst scopes = who.scopes.filter(\n\t\t(scope): scope is string => typeof scope === \"string\",\n\t);\n\tconst satisfying = scopes.includes(\"*\")\n\t\t? \"*\"\n\t\t: scopes.includes(\"instructions:read\")\n\t\t\t? \"instructions:read\"\n\t\t\t: null;\n\tif (satisfying !== null) {\n\t\treturn [\n\t\t\tmakeCheck(id, \"server\", \"pass\", `${label} with ${satisfying}`),\n\t\t\ttrue,\n\t\t];\n\t}\n\tif (keyType === \"personal\") {\n\t\treturn [\n\t\t\tmakeCheck(\n\t\t\t\tid,\n\t\t\t\t\"server\",\n\t\t\t\t\"fail\",\n\t\t\t\t`${label} has no instructions:read scope`,\n\t\t\t\t{\n\t\t\t\t\tfix: fixOf(\n\t\t\t\t\t\t\"personal API keys cannot carry instructions scopes: create an ORGANIZATION API key with instructions:read in the organization's Settings → API keys, then log in with it\",\n\t\t\t\t\t\tLOGIN_COMMAND,\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t),\n\t\t\tfalse,\n\t\t];\n\t}\n\treturn [\n\t\tmakeCheck(\n\t\t\tid,\n\t\t\t\"server\",\n\t\t\t\"fail\",\n\t\t\t`${label} is missing the instructions:read scope`,\n\t\t\t{\n\t\t\t\tfix: fixOf(\n\t\t\t\t\t`add instructions:read to this key in the organization's Settings → API keys, or create a new key with it and run \\`${LOGIN_COMMAND}\\``,\n\t\t\t\t),\n\t\t\t},\n\t\t),\n\t\tfalse,\n\t];\n}\n\n// ---------------------------------------------------------------------------\n// access\n// ---------------------------------------------------------------------------\n\nasync function checkAccess(\n\tinput: DoctorInput,\n\tclient: () => DoctorClient,\n\tauthOk: boolean,\n): Promise<[InstructionCheck, AccessState]> {\n\tconst id = \"access\";\n\tif (!authOk) {\n\t\treturn [\n\t\t\tmakeCheck(id, \"server\", \"skip\", SKIP_AFTER_AUTH),\n\t\t\t{ kind: \"unavailable\", reason: SKIP_AFTER_AUTH },\n\t\t];\n\t}\n\tconst displayId = sanitizeDisplayText(input.projectId, 128);\n\ttry {\n\t\tconst published = await client().instructions.getPublished(\n\t\t\tinput.projectId,\n\t\t\t{ org: input.org },\n\t\t);\n\t\treturn [\n\t\t\tmakeCheck(\n\t\t\t\tid,\n\t\t\t\t\"server\",\n\t\t\t\t\"pass\",\n\t\t\t\t`this key can read project ${displayId}'s coding instructions`,\n\t\t\t),\n\t\t\t{ kind: \"ok\", published },\n\t\t];\n\t} catch (error) {\n\t\treturn [\n\t\t\taccessFailure(displayId, error),\n\t\t\t{ kind: \"unavailable\", reason: SKIP_AFTER_ACCESS },\n\t\t];\n\t}\n}\n\n/**\n * The route's refusals, told apart by status and code\n * (`packages/api/modules/v1/instructions.ts`): a missing SCOPE is the\n * middleware's bare-string 403, which the SDK codes `MISSING_SCOPE`; any other\n * 403 is the live project permission; 404 is \"no such project for this key\".\n */\nfunction accessFailure(displayId: string, error: unknown): InstructionCheck {\n\tconst id = \"access\";\n\tconst status = statusOf(error);\n\tif (status === 403 && codeOf(error) === \"MISSING_SCOPE\") {\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"server\",\n\t\t\t\"fail\",\n\t\t\t\"the API key is missing the instructions:read scope (HTTP 403)\",\n\t\t\t{\n\t\t\t\tfix: fixOf(\n\t\t\t\t\t\"add instructions:read to the key in the organization's Settings → API keys, or log in with an organization API key that carries it\",\n\t\t\t\t\tLOGIN_COMMAND,\n\t\t\t\t),\n\t\t\t},\n\t\t);\n\t}\n\tif (status === 403) {\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"server\",\n\t\t\t\"fail\",\n\t\t\t\"the server refused this project's coding instructions to this key (HTTP 403)\",\n\t\t\t{\n\t\t\t\tfix: fixOf(\n\t\t\t\t\t`ask a project maintainer to grant you access to project ${displayId}: reading coding instructions needs the project's read permission`,\n\t\t\t\t),\n\t\t\t},\n\t\t);\n\t}\n\tif (status === 404) {\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"server\",\n\t\t\t\"fail\",\n\t\t\t\"project not found for this key (HTTP 404)\",\n\t\t\t{\n\t\t\t\tfix: fixOf(\n\t\t\t\t\t\"check the project id and --org: an organization key reaches only projects in its own organization, and --org must name the project's organization\",\n\t\t\t\t),\n\t\t\t},\n\t\t);\n\t}\n\tif (status === 401) {\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"server\",\n\t\t\t\"fail\",\n\t\t\t\"the API key was refused (HTTP 401)\",\n\t\t\t{\n\t\t\t\tfix: fixOf(\n\t\t\t\t\t\"log in with a current organization API key that carries instructions:read\",\n\t\t\t\t\tLOGIN_COMMAND,\n\t\t\t\t),\n\t\t\t},\n\t\t);\n\t}\n\treturn makeCheck(\n\t\tid,\n\t\t\"server\",\n\t\t\"fail\",\n\t\t`could not read the published instructions (${requestFailureClass(error)})`,\n\t\t{ fix: fixOf(NETWORK_FIX) },\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// published\n// ---------------------------------------------------------------------------\n\nfunction checkPublished(\n\taccess: AccessState,\n): [InstructionCheck, SnapshotState] {\n\tconst id = \"published\";\n\tif (access.kind !== \"ok\") {\n\t\treturn [\n\t\t\tmakeCheck(id, \"server\", \"skip\", access.reason),\n\t\t\t{ kind: \"unavailable\", reason: access.reason },\n\t\t];\n\t}\n\tconst answer = access.published;\n\tconst repository = answer.sourceOfTruth === \"REPOSITORY\";\n\t// The project's CURRENT repository-sync configuration (Fizzy #2709); the\n\t// API returns it regardless of whether anything is published. Named\n\t// distinctly from the `repository` boolean above, which answers a\n\t// different question (\"is this project repository-backed at all\") and\n\t// flows into `SnapshotState`.\n\tconst repositoryConfig: PublishedInstructionRepository | null =\n\t\tanswer.repository ?? null;\n\tif (answer.published !== true) {\n\t\treturn [\n\t\t\tmakeCheck(\n\t\t\t\tid,\n\t\t\t\t\"server\",\n\t\t\t\t\"warn\",\n\t\t\t\t\"nothing is published for this project yet\",\n\t\t\t\t{\n\t\t\t\t\tfix: fixOf(\n\t\t\t\t\t\t\"publish a version from the project's Coding Instructions tab\",\n\t\t\t\t\t),\n\t\t\t\t\trepository: repositoryConfig,\n\t\t\t\t},\n\t\t\t),\n\t\t\t{ kind: \"unpublished\" },\n\t\t];\n\t}\n\tif (!answer.snapshot || !Array.isArray(answer.manifest)) {\n\t\treturn [\n\t\t\tmakeCheck(\n\t\t\t\tid,\n\t\t\t\t\"server\",\n\t\t\t\t\"fail\",\n\t\t\t\t\"the server reported a published version without its file list\",\n\t\t\t\t{ fix: fixOf(\"rerun doctor; if it persists, report it\") },\n\t\t\t),\n\t\t\t{ kind: \"unavailable\", reason: SKIP_AFTER_PUBLISHED },\n\t\t];\n\t}\n\tconst snapshot = answer.snapshot;\n\tconst digest = sanitizeDisplayText(\n\t\tString(snapshot.digest).slice(0, 12),\n\t\t12,\n\t);\n\tconst source = snapshot.source;\n\tconst sourceDetail =\n\t\tsource?.kind === \"REPOSITORY\"\n\t\t\t? `, from ${sanitizeDisplayText(String(source.commitSha).slice(0, 12), 12)}… on ${sanitizeDisplayText(String(source.ref), 200)}`\n\t\t\t: \"\";\n\tconst detail = `version ${Number(snapshot.version)} (digest ${digest}…, ${plural(Number(snapshot.fileCount), \"file\")})${repository ? \", mirrored from the project's repository\" : \"\"}${sourceDetail}`;\n\treturn [\n\t\tmakeCheck(id, \"server\", \"pass\", detail, {\n\t\t\t...(source !== undefined ? { source } : {}),\n\t\t\trepository: repositoryConfig,\n\t\t}),\n\t\t{\n\t\t\tkind: \"published\",\n\t\t\tsnapshot,\n\t\t\tmanifest: answer.manifest,\n\t\t},\n\t];\n}\n\n// ---------------------------------------------------------------------------\n// lock\n// ---------------------------------------------------------------------------\n\n/**\n * Why the lock could not be used, as a class: `refused` — a symlinked\n * `.fabric` or lock, or not a regular file, so nothing was read; `too-large`\n * — a regular file over `MAX_LOCK_BYTES`; `invalid` — read, and not a lock.\n */\ntype LockUnreadable = \"refused\" | \"too-large\" | \"invalid\";\n\n/**\n * The lock, through `readLockSafely`: the guarded, bounded reader, so a\n * `.fabric -> elsewhere` link cannot make doctor report on a lock outside the\n * checkout, then `readLock`'s own validator.\n */\nasync function readLockBounded(\n\troot: string,\n): Promise<\n\t| { kind: \"absent\" }\n\t| { kind: \"unreadable\"; reason: LockUnreadable }\n\t| { kind: \"ok\"; lock: InstructionsLock }\n> {\n\ttry {\n\t\tconst lock = await readLockSafely(root, { maxBytes: MAX_LOCK_BYTES });\n\t\treturn lock === null ? { kind: \"absent\" } : { kind: \"ok\", lock };\n\t} catch (error) {\n\t\tif (error instanceof LockReadRefusedError) {\n\t\t\treturn {\n\t\t\t\tkind: \"unreadable\",\n\t\t\t\treason: isTooLarge(error.cause) ? \"too-large\" : \"refused\",\n\t\t\t};\n\t\t}\n\t\treturn { kind: \"unreadable\", reason: \"invalid\" };\n\t}\n}\n\nfunction unreadableLockCheck(\n\tinput: DoctorInput,\n\tcommands: Commands,\n\treason: LockUnreadable,\n): InstructionCheck {\n\tconst where = lockPath(input.destination);\n\tif (reason === \"refused\") {\n\t\t// Never \"remove it\": through a symlinked `.fabric`, the path names a\n\t\t// file outside the checkout, which is exactly what was refused.\n\t\treturn makeCheck(\n\t\t\t\"lock\",\n\t\t\t\"machine\",\n\t\t\t\"fail\",\n\t\t\t\"the lock could not be read safely (a symlink, or not a regular file)\",\n\t\t\t{\n\t\t\t\tfix: fixOf(\n\t\t\t\t\t`${where} or its .fabric directory is a symlink or not a regular file: remove that entry (for a symlink, the link itself, not what it points to), then run this sync to take a fresh copy`,\n\t\t\t\t\tcommands.sync(),\n\t\t\t\t),\n\t\t\t},\n\t\t);\n\t}\n\treturn makeCheck(\n\t\t\"lock\",\n\t\t\"machine\",\n\t\t\"fail\",\n\t\treason === \"too-large\"\n\t\t\t? `the lock is larger than ${MAX_LOCK_BYTES} bytes`\n\t\t\t: \"the lock is unreadable\",\n\t\t{\n\t\t\tfix: fixOf(\n\t\t\t\t`the lock at ${where} is damaged: remove it, then run this sync to take a fresh copy`,\n\t\t\t\tcommands.sync(),\n\t\t\t),\n\t\t},\n\t);\n}\n\nasync function checkLock(\n\tinput: DoctorInput,\n\tcommands: Commands,\n\tsnapshot: SnapshotState,\n\tcheckout: CheckoutState,\n): Promise<[InstructionCheck, LockState]> {\n\tconst id = \"lock\";\n\tconst notEvaluated: LockState = { kind: \"not-evaluated\" };\n\tif (snapshot.kind === \"unavailable\") {\n\t\treturn [\n\t\t\tmakeCheck(id, \"machine\", \"skip\", snapshot.reason),\n\t\t\tnotEvaluated,\n\t\t];\n\t}\n\t// A lock exists only where `sync` copies: outside any git checkout, and\n\t// in a checkout of some other repository when a person syncs by hand. In\n\t// a checkout of the repository the files arrive with git; in every other\n\t// class `sync` refuses, so a lock fix there would be one that fails.\n\tif (checkout !== null && !downloadsIn(checkout.classification, true)) {\n\t\treturn [\n\t\t\tmakeCheck(\n\t\t\t\tid,\n\t\t\t\t\"machine\",\n\t\t\t\t\"skip\",\n\t\t\t\tcheckoutClass(checkout) === \"matching\"\n\t\t\t\t\t? LOCK_NOT_USED\n\t\t\t\t\t: checkoutDetail(checkout),\n\t\t\t),\n\t\t\tnotEvaluated,\n\t\t];\n\t}\n\tif (snapshot.kind === \"unpublished\") {\n\t\treturn [\n\t\t\tmakeCheck(id, \"machine\", \"skip\", NOTHING_PUBLISHED),\n\t\t\tnotEvaluated,\n\t\t];\n\t}\n\n\tconst read = await readLockBounded(input.root);\n\tif (read.kind === \"unreadable\") {\n\t\treturn [\n\t\t\tunreadableLockCheck(input, commands, read.reason),\n\t\t\t{ kind: \"unreadable\" },\n\t\t];\n\t}\n\tif (read.kind === \"absent\") {\n\t\treturn [\n\t\t\tmakeCheck(\n\t\t\t\tid,\n\t\t\t\t\"machine\",\n\t\t\t\t\"fail\",\n\t\t\t\t`no lock: ${input.destination} has not been synced`,\n\t\t\t\t{\n\t\t\t\t\tfix: fixOf(\n\t\t\t\t\t\t\"takes a first copy of the published version and writes the lock\",\n\t\t\t\t\t\tcommands.sync(),\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t),\n\t\t\tread,\n\t\t];\n\t}\n\n\tconst lock = read.lock;\n\tif (lock.projectId !== input.projectId) {\n\t\tconst other = sanitizeDisplayText(lock.projectId, 128);\n\t\treturn [\n\t\t\tmakeCheck(\n\t\t\t\tid,\n\t\t\t\t\"machine\",\n\t\t\t\t\"fail\",\n\t\t\t\t`the lock was written for project ${other}`,\n\t\t\t\t{\n\t\t\t\t\t// Not `sync`: sync refuses a lock that belongs to another\n\t\t\t\t\t// project, and it is right to.\n\t\t\t\t\tfix: fixOf(\n\t\t\t\t\t\t`the lock in ${input.destination} was written for project ${other}; run doctor with the --dest that was synced for this project`,\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t),\n\t\t\t{ kind: \"foreign\" },\n\t\t];\n\t}\n\n\tconst published = snapshot.snapshot;\n\tif (lock.digest !== published.digest) {\n\t\treturn [\n\t\t\tmakeCheck(\n\t\t\t\tid,\n\t\t\t\t\"machine\",\n\t\t\t\t\"fail\",\n\t\t\t\t`lock is at version ${lock.snapshotVersion}, published is ${Number(published.version)}`,\n\t\t\t\t{\n\t\t\t\t\tfix: fixOf(\n\t\t\t\t\t\t\"brings this checkout to the published version; a local edit to an instruction file is kept and listed, and `sync --repair` replaces it\",\n\t\t\t\t\t\tcommands.sync(),\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t),\n\t\t\t{ kind: \"usable\", lock, current: false },\n\t\t];\n\t}\n\n\tconst mismatches = compareLedger(lock, snapshot.manifest);\n\tif (mismatches.length > 0) {\n\t\treturn [\n\t\t\tmakeCheck(\n\t\t\t\tid,\n\t\t\t\t\"machine\",\n\t\t\t\t\"fail\",\n\t\t\t\t\"lock ledger does not match the published manifest\",\n\t\t\t\t{\n\t\t\t\t\titems: capItems(mismatches, \"fail\"),\n\t\t\t\t\tfix: fixOf(\n\t\t\t\t\t\t\"rewrites the lock from the published manifest, restoring any file it names\",\n\t\t\t\t\t\tcommands.sync(),\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t),\n\t\t\t{ kind: \"usable\", lock, current: true },\n\t\t];\n\t}\n\treturn [\n\t\tmakeCheck(\n\t\t\tid,\n\t\t\t\"machine\",\n\t\t\t\"pass\",\n\t\t\t`lock is at the published version ${Number(published.version)}`,\n\t\t),\n\t\t{ kind: \"usable\", lock, current: true },\n\t];\n}\n\n/**\n * The lock's ledger against the published manifest: same path set, same\n * hashes, and the same mode wherever either records one. A lock whose digest\n * matches but whose ledger does not was hand-edited or half-written, and the\n * next sync would decide deletions from it.\n */\nfunction compareLedger(\n\tlock: InstructionsLock,\n\tmanifest: readonly InstructionManifestEntry[],\n): CheckItem[] {\n\tconst published = new Map<string, InstructionManifestEntry>();\n\tfor (const entry of manifest) {\n\t\tpublished.set(entry.path, entry);\n\t}\n\tconst items: CheckItem[] = [];\n\tfor (const [lockedPath, locked] of Object.entries(lock.files)) {\n\t\tconst name = sanitizeDisplayText(lockedPath, 200);\n\t\tconst entry = published.get(lockedPath);\n\t\tif (entry === undefined) {\n\t\t\titems.push({\n\t\t\t\tname,\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tdetail: \"in the lock, not in the published manifest\",\n\t\t\t});\n\t\t} else if (entry.sha256 !== locked.sha256) {\n\t\t\titems.push({\n\t\t\t\tname,\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tdetail: \"hash differs from the published manifest\",\n\t\t\t});\n\t\t} else if ((entry.mode ?? null) !== (locked.mode ?? null)) {\n\t\t\titems.push({\n\t\t\t\tname,\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tdetail: \"mode differs from the published manifest\",\n\t\t\t});\n\t\t}\n\t}\n\tfor (const entry of manifest) {\n\t\tif (!Object.hasOwn(lock.files, entry.path)) {\n\t\t\titems.push({\n\t\t\t\tname: sanitizeDisplayText(String(entry.path), 200),\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tdetail: \"published, not in the lock\",\n\t\t\t});\n\t\t}\n\t}\n\treturn items;\n}\n\n// ---------------------------------------------------------------------------\n// drift\n// ---------------------------------------------------------------------------\n\nconst DRIFT_DETAIL: Record<LedgerDriftReason, string> = {\n\tmissing: \"missing\",\n\tedited: \"edited\",\n\tmode: \"mode differs from the published mode\",\n\trefused: \"could not be read safely (a symlink, or not a regular file)\",\n};\n\nasync function checkDrift(\n\tinput: DoctorInput,\n\tcommands: Commands,\n\tsnapshot: SnapshotState,\n\tlockState: LockState,\n\tcheckout: CheckoutState,\n): Promise<InstructionCheck> {\n\tconst id = \"drift\";\n\tif (snapshot.kind === \"unavailable\") {\n\t\treturn makeCheck(id, \"machine\", \"skip\", snapshot.reason);\n\t}\n\tif (snapshot.kind === \"unpublished\") {\n\t\treturn makeCheck(id, \"machine\", \"skip\", NOTHING_PUBLISHED);\n\t}\n\tif (checkout !== null && checkoutClass(checkout) !== \"upload\") {\n\t\treturn checkoutDrift(snapshot.snapshot, checkout);\n\t}\n\tif (lockState.kind !== \"usable\") {\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"machine\",\n\t\t\t\"skip\",\n\t\t\t\"not evaluated: no usable lock for this project\",\n\t\t);\n\t}\n\n\tlet drift: Awaited<ReturnType<typeof findLedgerDrift>>;\n\ttry {\n\t\tdrift = await findLedgerDrift({\n\t\t\troot: input.root,\n\t\t\tlock: lockState.lock,\n\t\t});\n\t} catch {\n\t\t// `assertSafeLockPaths`: a traversal, a reserved path, or a collision.\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"machine\",\n\t\t\t\"fail\",\n\t\t\t\"the lock names a path this tool will not touch\",\n\t\t\t{\n\t\t\t\tfix: fixOf(\n\t\t\t\t\t`remove the lock at ${lockPath(input.destination)}, then run this sync to take a fresh copy`,\n\t\t\t\t\tcommands.sync(),\n\t\t\t\t),\n\t\t\t},\n\t\t);\n\t}\n\n\tconst total = Object.keys(lockState.lock.files).length;\n\tif (drift.length === 0) {\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"machine\",\n\t\t\t\"pass\",\n\t\t\t`all ${plural(total, \"file\")} the last sync wrote still match the lock`,\n\t\t);\n\t}\n\tconst push = commands.push() ?? \"fabric instructions push\";\n\tconst edits = drift.filter((entry) => entry.reason === \"edited\").length;\n\t// Spec §6.4: `sync` keeps a local edit unless it is given `--repair`, so\n\t// an edit is the intended state and only a warning. Anything else is\n\t// something `sync` puts back, and still fails.\n\tconst status = edits === drift.length ? \"warn\" : \"fail\";\n\tconst items = capItems(\n\t\tdrift.map((entry) => ({\n\t\t\tname: sanitizeDisplayText(entry.path, 200),\n\t\t\tstatus:\n\t\t\t\tentry.reason === \"edited\"\n\t\t\t\t\t? (\"warn\" as const)\n\t\t\t\t\t: (\"fail\" as const),\n\t\t\tdetail:\n\t\t\t\tentry.reason === \"edited\" && entry.kept\n\t\t\t\t\t? \"edited (kept by sync)\"\n\t\t\t\t\t: DRIFT_DETAIL[entry.reason],\n\t\t})),\n\t\tstatus,\n\t);\n\tif (status === \"warn\") {\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"machine\",\n\t\t\t\"warn\",\n\t\t\t`${drift.length} of ${plural(total, \"file\")} the last sync wrote carry local edits, which sync keeps`,\n\t\t\t{\n\t\t\t\titems,\n\t\t\t\tfix: fixOf(\n\t\t\t\t\t`replaces these local edits with the published bytes; to propose them instead, run \\`${push}\\``,\n\t\t\t\t\tcommands.repair(),\n\t\t\t\t),\n\t\t\t},\n\t\t);\n\t}\n\tconst repair = commands.repair() ?? \"fabric instructions sync --repair\";\n\treturn makeCheck(\n\t\tid,\n\t\t\"machine\",\n\t\t\"fail\",\n\t\t`${drift.length} of ${plural(total, \"file\")} the last sync wrote no longer match the lock`,\n\t\t{\n\t\t\titems,\n\t\t\tfix: fixOf(\n\t\t\t\tedits === 0\n\t\t\t\t\t? `restores the published bytes over these local changes; to propose your edits instead, run \\`${push}\\``\n\t\t\t\t\t: `restores the files that are not local edits; sync keeps those, so run \\`${repair}\\` to replace them too, or \\`${push}\\` to propose them`,\n\t\t\t\tcommands.sync(),\n\t\t\t),\n\t\t},\n\t);\n}\n\n/**\n * A repository-sourced project's \"local files\" in a checkout of its\n * repository: whether the published commit is in HEAD's history. Ancestry\n * says the checkout has caught up with that commit, not that its files are\n * byte-for-byte the published ones — the detail says so. Anywhere that might\n * be a checkout but is not this one is not compared at all.\n */\nfunction checkoutDrift(\n\tsnapshot: PublishedInstructionSnapshot,\n\tcheckout: CheckoutReport,\n): InstructionCheck {\n\tconst id = \"drift\";\n\tif (checkoutClass(checkout) !== \"matching\") {\n\t\treturn makeCheck(id, \"machine\", \"skip\", checkoutDetail(checkout));\n\t}\n\tif (checkout.line === null) {\n\t\tconst source = snapshot.source;\n\t\tconst sha7 =\n\t\t\tsource?.kind === \"REPOSITORY\"\n\t\t\t\t? sanitizeDisplayText(String(source.commitSha).slice(0, 7), 7)\n\t\t\t\t: \"\";\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"machine\",\n\t\t\t\"pass\",\n\t\t\t`history contains the published commit ${sha7} (ancestry, not a file comparison)`,\n\t\t);\n\t}\n\treturn makeCheck(id, \"machine\", \"warn\", checkoutDetail(checkout), {\n\t\tfix: fixOf(\n\t\t\t\"bring the checkout up to the published commit with git; Fabric does not change a checkout of the repository\",\n\t\t),\n\t});\n}\n\n// ---------------------------------------------------------------------------\n// hook\n// ---------------------------------------------------------------------------\n\nconst HOOK_TARGETS: ReadonlyArray<{\n\ttool: InstructionsHookTool;\n\tfile: string;\n}> = [\n\t{ tool: \"claude-code\", file: \".claude/settings.local.json\" },\n\t{ tool: \"codex\", file: \".codex/hooks.json\" },\n];\n\n/**\n * Template recognition, per target. The hook stores no binary path and no\n * CLI version, so \"points at the current CLI\" is verifiable in exactly one\n * sense: its command is one of the two strings this CLI would write today for\n * this project and this `--org`.\n */\nasync function checkHook(\n\tinput: DoctorInput,\n\tcommands: Commands,\n\tsnapshot: SnapshotState,\n\tcheckout: CheckoutState,\n): Promise<InstructionCheck> {\n\tconst id = \"hook\";\n\tif (snapshot.kind === \"unavailable\") {\n\t\treturn makeCheck(id, \"machine\", \"skip\", snapshot.reason);\n\t}\n\t// `init` installs a hook only where it will: a checkout of the\n\t// repository, or a directory that is not a checkout at all. Elsewhere it\n\t// refuses, so a fix never proposes running it there.\n\tconst mode = checkoutClass(checkout);\n\tconst init = (tool: InstructionsHookTool): string | undefined =>\n\t\tmode === \"other\" ? undefined : commands.init(tool);\n\tconst initRefused =\n\t\tcheckout !== null && mode === \"other\"\n\t\t\t? `; init refuses in this directory (${checkoutDetail(checkout)})`\n\t\t\t: \"\";\n\n\tconst reportOnly = buildHookCommand(input.projectId, false, input.org);\n\tconst applies = buildHookCommand(input.projectId, true, input.org);\n\tconst items: CheckItem[] = [];\n\tconst passing: InstructionsHookTool[] = [];\n\tconst differing: InstructionsHookTool[] = [];\n\tconst unreadable: InstructionsHookTool[] = [];\n\n\tfor (const target of HOOK_TARGETS) {\n\t\tconst name = `${target.tool} (${target.file})`;\n\t\tconst scan = await findSessionStartHooks({\n\t\t\troot: input.root,\n\t\t\tprojectId: input.projectId,\n\t\t\ttool: target.tool,\n\t\t});\n\t\tif (scan.state === \"unreadable\") {\n\t\t\tunreadable.push(target.tool);\n\t\t\titems.push({\n\t\t\t\tname,\n\t\t\t\tstatus: \"warn\",\n\t\t\t\tdetail: \"settings file could not be read or parsed\",\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (scan.state === \"absent\" || scan.commands.length === 0) {\n\t\t\titems.push({ name, status: \"skip\", detail: \"not configured\" });\n\t\t\tcontinue;\n\t\t}\n\t\tif (scan.commands.includes(applies)) {\n\t\t\tpassing.push(target.tool);\n\t\t\titems.push({\n\t\t\t\tname,\n\t\t\t\tstatus: \"pass\",\n\t\t\t\tdetail: \"canonical hook; applies changes at session start\",\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (scan.commands.includes(reportOnly)) {\n\t\t\tpassing.push(target.tool);\n\t\t\titems.push({\n\t\t\t\tname,\n\t\t\t\tstatus: \"pass\",\n\t\t\t\tdetail: \"canonical hook; reports changes at session start\",\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tdiffering.push(target.tool);\n\t\titems.push({\n\t\t\tname,\n\t\t\tstatus: \"warn\",\n\t\t\tdetail: \"differs from the canonical command (different context or older syntax)\",\n\t\t});\n\t}\n\n\tconst lookup: PathLookupEnvironment = {\n\t\tenv: input.env,\n\t\tplatform: input.platform,\n\t};\n\tconst fabricFound = await isOnPath(\"fabric\", lookup);\n\titems.push({\n\t\tname: \"fabric on PATH\",\n\t\tstatus: fabricFound ? \"pass\" : \"warn\",\n\t\tdetail: fabricFound\n\t\t\t? \"found (not executed)\"\n\t\t\t: `not found; install it with ${CLI_INSTALL_COMMAND}`,\n\t});\n\n\tif (passing.length > 0) {\n\t\tif (!fabricFound) {\n\t\t\treturn makeCheck(\n\t\t\t\tid,\n\t\t\t\t\"machine\",\n\t\t\t\t\"warn\",\n\t\t\t\t`hook configured for ${passing.join(\" and \")}, but fabric is not on this shell's PATH; ${HOOK_NOT_VERIFIED}`,\n\t\t\t\t{\n\t\t\t\t\titems,\n\t\t\t\t\tfix: fixOf(\n\t\t\t\t\t\t\"the hook runs `fabric`; install the CLI globally so the coding tool can find it\",\n\t\t\t\t\t\tCLI_INSTALL_COMMAND,\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"machine\",\n\t\t\t\"pass\",\n\t\t\t`hook configured for ${passing.join(\" and \")}; ${HOOK_NOT_VERIFIED}`,\n\t\t\t{ items },\n\t\t);\n\t}\n\tif (differing.length > 0) {\n\t\tconst tool = differing[0] as InstructionsHookTool;\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"machine\",\n\t\t\t\"warn\",\n\t\t\t`a hook for this project is not in the canonical form; ${HOOK_NOT_VERIFIED}`,\n\t\t\t{\n\t\t\t\titems,\n\t\t\t\tfix: fixOf(\n\t\t\t\t\t`rewrites this project's hook in the canonical form (init also syncs the published version first, except in a checkout of the repository)${initRefused}`,\n\t\t\t\t\tinit(tool),\n\t\t\t\t),\n\t\t\t},\n\t\t);\n\t}\n\tif (unreadable.length > 0) {\n\t\tconst tool = unreadable[0] as InstructionsHookTool;\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"machine\",\n\t\t\t\"warn\",\n\t\t\t`a hook settings file could not be read; ${HOOK_NOT_VERIFIED}`,\n\t\t\t{\n\t\t\t\titems,\n\t\t\t\tfix: fixOf(\n\t\t\t\t\t`fix the settings file so it parses as JSON (init refuses to rewrite a file it cannot read), then run this${initRefused}`,\n\t\t\t\t\tinit(tool),\n\t\t\t\t),\n\t\t\t},\n\t\t);\n\t}\n\treturn makeCheck(\n\t\tid,\n\t\t\"machine\",\n\t\t\"fail\",\n\t\t\"no hook configured for this project\",\n\t\t{\n\t\t\titems,\n\t\t\tfix: fixOf(\n\t\t\t\t`${\n\t\t\t\t\tmode === \"matching\"\n\t\t\t\t\t\t? \"installs the SessionStart hook for Claude Code; in a checkout of the repository it reports when the published commit is newer and copies nothing\"\n\t\t\t\t\t\t: \"installs the SessionStart hook for Claude Code and, when a version is published, takes a first sync\"\n\t\t\t\t}; use --tool codex for Codex${initRefused}`,\n\t\t\t\tinit(\"claude-code\"),\n\t\t\t),\n\t\t},\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// The declaration: environment + tools\n// ---------------------------------------------------------------------------\n\ntype LocalDeclarationRead =\n\t| { kind: \"absent\" }\n\t| { kind: \"refused\"; detail: string }\n\t| { kind: \"ok\"; bytes: Uint8Array };\n\nasync function readLocalDeclaration(\n\troot: string,\n): Promise<LocalDeclarationRead> {\n\ttry {\n\t\tconst read = await readFileSafely(root, INSTRUCTION_ENVIRONMENT_FILE, {\n\t\t\tmaxBytes: INSTRUCTION_ENVIRONMENT_MAX_BYTES,\n\t\t});\n\t\treturn read === null\n\t\t\t? { kind: \"absent\" }\n\t\t\t: { kind: \"ok\", bytes: read.bytes };\n\t} catch (error) {\n\t\treturn {\n\t\t\tkind: \"refused\",\n\t\t\tdetail: isTooLarge(error)\n\t\t\t\t? `file is larger than ${INSTRUCTION_ENVIRONMENT_MAX_BYTES} bytes`\n\t\t\t\t: \"file could not be read safely (a symlink, or not a regular file)\",\n\t\t};\n\t}\n}\n\nconst PROVENANCE_PREFIX: Record<Provenance, string> = {\n\tpublished: \"published declaration: \",\n\t\"local-unpublished\": \"local, unpublished declaration: \",\n\tcheckout: \"from the local checkout: \",\n};\n\n/** Hash-then-parse and parse-only both land here, on the same buffer. */\nfunction parseDeclarationBytes(\n\tbytes: Uint8Array,\n\tprovenance: Provenance,\n): DeclarationState {\n\tlet text: string;\n\ttry {\n\t\ttext = new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes);\n\t} catch {\n\t\treturn {\n\t\t\tkind: \"unreadable\",\n\t\t\tstatus: \"fail\",\n\t\t\tdetail: `${PROVENANCE_PREFIX[provenance]}file is not valid UTF-8`,\n\t\t\tfix: fixOf(DECLARATION_FORMAT_FIX),\n\t\t};\n\t}\n\tconst parsed = parseInstructionEnvironment(text);\n\tif (!parsed.ok) {\n\t\treturn {\n\t\t\tkind: \"unreadable\",\n\t\t\tstatus: \"fail\",\n\t\t\tdetail: `${PROVENANCE_PREFIX[provenance]}${parsed.reason}`,\n\t\t\tfix: fixOf(DECLARATION_FORMAT_FIX),\n\t\t};\n\t}\n\treturn { kind: \"ok\", declaration: parsed.declaration, provenance };\n}\n\nasync function declarationFromDisk(\n\tinput: DoctorInput,\n\tprovenance: \"local-unpublished\" | \"checkout\",\n): Promise<DeclarationState> {\n\tconst read = await readLocalDeclaration(input.root);\n\tif (read.kind === \"absent\") {\n\t\treturn {\n\t\t\tkind: \"skip\",\n\t\t\tdetail:\n\t\t\t\tprovenance === \"checkout\"\n\t\t\t\t\t? `no environment declaration in the local checkout (add ${INSTRUCTION_ENVIRONMENT_FILE} to the repository's instruction set)`\n\t\t\t\t\t: `no environment declaration (add ${INSTRUCTION_ENVIRONMENT_FILE} to the instruction set)`,\n\t\t};\n\t}\n\tif (read.kind === \"refused\") {\n\t\treturn {\n\t\t\tkind: \"unreadable\",\n\t\t\tstatus: \"fail\",\n\t\t\tdetail: `${PROVENANCE_PREFIX[provenance]}${read.detail}`,\n\t\t\tfix: fixOf(DECLARATION_FORMAT_FIX),\n\t\t};\n\t}\n\treturn parseDeclarationBytes(read.bytes, provenance);\n}\n\nfunction hasUsableSize(entry: { size: unknown }): entry is { size: number } {\n\treturn (\n\t\ttypeof entry.size === \"number\" &&\n\t\tNumber.isSafeInteger(entry.size) &&\n\t\tentry.size >= 0\n\t);\n}\n\nasync function resolveDeclaration(\n\tinput: DoctorInput,\n\tcommands: Commands,\n\tclient: () => DoctorClient,\n\tsnapshot: SnapshotState,\n\tlockState: LockState,\n\tcheckout: CheckoutState,\n): Promise<DeclarationState> {\n\tif (snapshot.kind === \"unavailable\") {\n\t\treturn { kind: \"skip\", detail: snapshot.reason };\n\t}\n\tconst mode = checkoutClass(checkout);\n\tif (mode === \"matching\") {\n\t\treturn declarationFromDisk(input, \"checkout\");\n\t}\n\tif (snapshot.kind === \"published\") {\n\t\tconst entry = snapshot.manifest.find(\n\t\t\t(candidate) => candidate.path === INSTRUCTION_ENVIRONMENT_FILE,\n\t\t);\n\t\tif (entry !== undefined) {\n\t\t\treturn declarationFromSnapshot(\n\t\t\t\tinput,\n\t\t\t\tcommands,\n\t\t\t\tclient,\n\t\t\t\tsnapshot,\n\t\t\t\tlockState,\n\t\t\t\tentry,\n\t\t\t);\n\t\t}\n\t}\n\tif (mode === \"other\") {\n\t\t// Maybe a checkout of some other repository: its file is not this\n\t\t// project's declaration, so it is treated as absent rather than read.\n\t\treturn {\n\t\t\tkind: \"skip\",\n\t\t\tdetail: `no environment declaration published (a local ${INSTRUCTION_ENVIRONMENT_FILE} here is not read: this directory is not a checkout of the project's repository)`,\n\t\t};\n\t}\n\treturn declarationFromDisk(input, \"local-unpublished\");\n}\n\nasync function declarationFromSnapshot(\n\tinput: DoctorInput,\n\tcommands: Commands,\n\tclient: () => DoctorClient,\n\tsnapshot: Extract<SnapshotState, { kind: \"published\" }>,\n\tlockState: LockState,\n\tentry: InstructionManifestEntry,\n): Promise<DeclarationState> {\n\tconst tooLarge = sizeRefusal(entry);\n\tif (tooLarge !== null) {\n\t\treturn tooLarge;\n\t}\n\n\t// The local copy is the published one only when the lock names the\n\t// published digest AND the file's bytes hash to the manifest's entry.\n\tif (lockState.kind === \"usable\" && lockState.current) {\n\t\tconst local = await readLocalDeclaration(input.root);\n\t\tif (local.kind === \"ok\" && sha256Hex(local.bytes) === entry.sha256) {\n\t\t\treturn parseDeclarationBytes(local.bytes, \"published\");\n\t\t}\n\t}\n\n\treturn downloadDeclaration(input, commands, client, snapshot, entry);\n}\n\n/** Refused before anything is downloaded. */\nfunction sizeRefusal(entry: InstructionManifestEntry): DeclarationState | null {\n\tif (!hasUsableSize(entry)) {\n\t\treturn {\n\t\t\tkind: \"unreadable\",\n\t\t\tstatus: \"fail\",\n\t\t\tdetail: \"published declaration has an invalid size in the manifest\",\n\t\t\tfix: fixOf(\n\t\t\t\t\"rerun doctor; if it persists, the published manifest is malformed and the project's maintainers should republish\",\n\t\t\t),\n\t\t};\n\t}\n\tif (entry.size > INSTRUCTION_ENVIRONMENT_MAX_BYTES) {\n\t\treturn {\n\t\t\tkind: \"unreadable\",\n\t\t\tstatus: \"fail\",\n\t\t\tdetail: `published declaration is larger than ${INSTRUCTION_ENVIRONMENT_MAX_BYTES} bytes`,\n\t\t\tfix: fixOf(\n\t\t\t\t`shrink ${INSTRUCTION_ENVIRONMENT_FILE} in the instruction set below ${INSTRUCTION_ENVIRONMENT_MAX_BYTES} bytes`,\n\t\t\t),\n\t\t};\n\t}\n\treturn null;\n}\n\n/**\n * The download endpoint re-resolves the CURRENT snapshot, so its answer is\n * compared with the manifest being checked. A publication that lands between\n * the two gets one retry of the pair; a second disagreement is reported\n * rather than guessed at.\n */\nasync function downloadDeclaration(\n\tinput: DoctorInput,\n\tcommands: Commands,\n\tclient: () => DoctorClient,\n\tinitial: Extract<SnapshotState, { kind: \"published\" }>,\n\tinitialEntry: InstructionManifestEntry,\n): Promise<DeclarationState> {\n\tlet snapshot = initial.snapshot;\n\tlet manifest = initial.manifest;\n\tlet entry = initialEntry;\n\n\tfor (let attempt = 0; attempt < 2; attempt++) {\n\t\tlet download: InstructionDownload;\n\t\ttry {\n\t\t\tdownload = await input.createDownloadUrl(input.projectId, {\n\t\t\t\torg: input.org,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tkind: \"unreadable\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tdetail: `could not download the published declaration (${requestFailureClass(error)})`,\n\t\t\t\tfix: fixOf(NETWORK_FIX),\n\t\t\t};\n\t\t}\n\t\tif (\n\t\t\tdownload.snapshotId === snapshot.id &&\n\t\t\tdownload.digest === snapshot.digest\n\t\t) {\n\t\t\treturn fetchVerifiedDeclaration(\n\t\t\t\tinput,\n\t\t\t\tdownload.url,\n\t\t\t\tmanifest,\n\t\t\t\tentry,\n\t\t\t);\n\t\t}\n\t\tif (attempt > 0) {\n\t\t\tbreak;\n\t\t}\n\n\t\tlet again: PublishedInstructions;\n\t\ttry {\n\t\t\tagain = await client().instructions.getPublished(input.projectId, {\n\t\t\t\torg: input.org,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tkind: \"unreadable\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tdetail: `could not re-read the published instructions (${requestFailureClass(error)})`,\n\t\t\t\tfix: fixOf(NETWORK_FIX),\n\t\t\t};\n\t\t}\n\t\tconst nextEntry = Array.isArray(again.manifest)\n\t\t\t? again.manifest.find(\n\t\t\t\t\t(candidate) =>\n\t\t\t\t\t\tcandidate.path === INSTRUCTION_ENVIRONMENT_FILE,\n\t\t\t\t)\n\t\t\t: undefined;\n\t\tif (\n\t\t\tagain.published !== true ||\n\t\t\t!again.snapshot ||\n\t\t\t!Array.isArray(again.manifest) ||\n\t\t\tnextEntry === undefined\n\t\t) {\n\t\t\tbreak;\n\t\t}\n\t\tconst refused = sizeRefusal(nextEntry);\n\t\tif (refused !== null) {\n\t\t\treturn refused;\n\t\t}\n\t\tsnapshot = again.snapshot;\n\t\tmanifest = again.manifest;\n\t\tentry = nextEntry;\n\t}\n\n\treturn {\n\t\tkind: \"unreadable\",\n\t\tstatus: \"warn\",\n\t\tdetail: \"publication changed while checking; rerun\",\n\t\tfix: fixOf(\n\t\t\t\"rerun doctor once publishing has settled\",\n\t\t\tcommands.doctor(),\n\t\t),\n\t};\n}\n\nasync function fetchVerifiedDeclaration(\n\tinput: DoctorInput,\n\turl: string,\n\tmanifest: readonly InstructionManifestEntry[],\n\tentry: InstructionManifestEntry,\n): Promise<DeclarationState> {\n\tconst bound = Math.min(\n\t\tmaxArchiveBytes(\n\t\t\tmanifest.filter(\n\t\t\t\t(candidate) =>\n\t\t\t\t\ttypeof candidate.path === \"string\" &&\n\t\t\t\t\thasUsableSize(candidate),\n\t\t\t),\n\t\t),\n\t\tMAX_DOWNLOAD_BYTES,\n\t);\n\tlet archive: Uint8Array;\n\ttry {\n\t\tarchive = await input.fetchArchive(url, bound);\n\t} catch {\n\t\treturn {\n\t\t\tkind: \"unreadable\",\n\t\t\tstatus: \"fail\",\n\t\t\tdetail: \"could not download the published declaration\",\n\t\t\tfix: fixOf(NETWORK_FIX),\n\t\t};\n\t}\n\n\tconst integrity: DeclarationState = {\n\t\tkind: \"unreadable\",\n\t\tstatus: \"fail\",\n\t\tdetail: \"published declaration failed integrity check\",\n\t\tfix: fixOf(\n\t\t\t\"rerun doctor; if it persists, the published bundle does not match its manifest and the project's maintainers should republish\",\n\t\t),\n\t};\n\tlet files: Map<string, Uint8Array>;\n\ttry {\n\t\t// Only this one path, within the manifest's size for it.\n\t\tfiles = extractBundle(archive, [\n\t\t\t{ path: INSTRUCTION_ENVIRONMENT_FILE, size: entry.size },\n\t\t]);\n\t} catch {\n\t\treturn integrity;\n\t}\n\tconst bytes = files.get(INSTRUCTION_ENVIRONMENT_FILE);\n\tif (bytes === undefined) {\n\t\treturn {\n\t\t\t...integrity,\n\t\t\tdetail: \"published declaration is missing from the downloaded bundle\",\n\t\t};\n\t}\n\t// Hash, then parse, the same buffer.\n\tif (sha256Hex(bytes) !== entry.sha256) {\n\t\treturn integrity;\n\t}\n\treturn parseDeclarationBytes(bytes, \"published\");\n}\n\n/** The provenance note, where the detail says where the declaration came from. */\nfunction withProvenance(detail: string, provenance: Provenance): string {\n\tif (provenance === \"checkout\") {\n\t\treturn `from the local checkout: ${detail}`;\n\t}\n\tif (provenance === \"local-unpublished\") {\n\t\treturn `${detail}; declaration exists locally but is not published`;\n\t}\n\treturn detail;\n}\n\nconst PUBLISH_DECLARATION_FIX = `publish ${INSTRUCTION_ENVIRONMENT_FILE} with the instruction set so every checkout gets the same declaration`;\n\nfunction checkEnvironment(\n\tinput: DoctorInput,\n\tdeclaration: DeclarationState,\n): InstructionCheck {\n\tconst id = \"environment\";\n\tif (declaration.kind === \"skip\") {\n\t\treturn makeCheck(id, \"machine\", \"skip\", declaration.detail);\n\t}\n\tif (declaration.kind === \"unreadable\") {\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"machine\",\n\t\t\tdeclaration.status,\n\t\t\tdeclaration.detail,\n\t\t\t{ fix: declaration.fix },\n\t\t);\n\t}\n\n\tconst { provenance } = declaration;\n\tconst variables = declaration.declaration.variables;\n\tif (variables.length === 0) {\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"machine\",\n\t\t\t\"skip\",\n\t\t\twithProvenance(\"the declaration names no variables\", provenance),\n\t\t);\n\t}\n\n\t// NAMES only. `Object.keys` never touches a value.\n\tconst evaluation = evaluateDeclaredVariables(\n\t\tdeclaration.declaration,\n\t\tObject.keys(input.env),\n\t\t{ ignoreCase: input.platform === \"win32\" },\n\t);\n\tconst missing =\n\t\tevaluation.missingRequired.length + evaluation.missingOptional.length;\n\tlet detail = `${variables.length - missing} of ${plural(variables.length, \"declared variable\")} present`;\n\tif (evaluation.missingRequired.length > 0) {\n\t\tdetail += `; ${evaluation.missingRequired.length} required missing`;\n\t}\n\tif (evaluation.missingOptional.length > 0) {\n\t\tdetail += `; ${evaluation.missingOptional.length} optional missing`;\n\t}\n\n\tlet status = evaluation.status;\n\tlet fix: CheckFix | undefined;\n\tif (evaluation.missingRequired.length > 0) {\n\t\tconst optional =\n\t\t\tevaluation.missingOptional.length > 0\n\t\t\t\t? `; optional and unset: ${listNames(evaluation.missingOptional)}`\n\t\t\t\t: \"\";\n\t\tfix = fixOf(\n\t\t\t`set ${listNames(evaluation.missingRequired)} in your shell environment${optional} (values are never read by this tool)`,\n\t\t);\n\t} else if (evaluation.missingOptional.length > 0) {\n\t\tfix = fixOf(\n\t\t\t`optional and unset: ${listNames(evaluation.missingOptional)}; set them if you need what they enable (values are never read by this tool)`,\n\t\t);\n\t} else if (provenance === \"local-unpublished\") {\n\t\tfix = fixOf(PUBLISH_DECLARATION_FIX);\n\t}\n\tif (provenance === \"local-unpublished\" && status === \"pass\") {\n\t\tstatus = \"warn\";\n\t}\n\n\treturn makeCheck(\n\t\tid,\n\t\t\"machine\",\n\t\tstatus,\n\t\twithProvenance(detail, provenance),\n\t\t{\n\t\t\titems: evaluation.items,\n\t\t\t...(fix !== undefined ? { fix } : {}),\n\t\t},\n\t);\n}\n\nasync function checkTools(\n\tinput: DoctorInput,\n\tdeclaration: DeclarationState,\n): Promise<InstructionCheck> {\n\tconst id = \"tools\";\n\tif (declaration.kind === \"skip\") {\n\t\treturn makeCheck(id, \"machine\", \"skip\", declaration.detail);\n\t}\n\tif (declaration.kind === \"unreadable\") {\n\t\treturn makeCheck(id, \"machine\", \"skip\", \"declaration unreadable\");\n\t}\n\n\tconst { provenance } = declaration;\n\tconst tools = declaration.declaration.tools;\n\tif (tools.length === 0) {\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"machine\",\n\t\t\t\"skip\",\n\t\t\twithProvenance(\"the declaration names no tools\", provenance),\n\t\t);\n\t}\n\n\tconst lookup: PathLookupEnvironment = {\n\t\tenv: input.env,\n\t\tplatform: input.platform,\n\t};\n\tconst items: CheckItem[] = [];\n\tconst missing: string[] = [];\n\tfor (const tool of tools) {\n\t\t// The parser already enforced this; checked again because it is what\n\t\t// makes the name safe to join onto a PATH directory.\n\t\tconst found =\n\t\t\tTOOL_NAME.test(tool.name) && (await isOnPath(tool.name, lookup));\n\t\tconst declared =\n\t\t\ttool.version !== undefined\n\t\t\t\t? `; declared ${tool.version} (not verified)`\n\t\t\t\t: \"\";\n\t\tif (found) {\n\t\t\titems.push({\n\t\t\t\tname: tool.name,\n\t\t\t\tstatus: \"pass\",\n\t\t\t\tdetail: `found on PATH${declared}`,\n\t\t\t});\n\t\t} else {\n\t\t\tmissing.push(tool.name);\n\t\t\titems.push({\n\t\t\t\tname: tool.name,\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tdetail: `not found on PATH${tool.version !== undefined ? `; declared ${tool.version}` : \"\"}`,\n\t\t\t});\n\t\t}\n\t}\n\n\tconst detail = withProvenance(\n\t\t`${tools.length - missing.length} of ${plural(tools.length, \"declared tool\")} found on PATH (presence only; nothing was run)`,\n\t\tprovenance,\n\t);\n\tif (missing.length > 0) {\n\t\treturn makeCheck(id, \"machine\", \"fail\", detail, {\n\t\t\titems,\n\t\t\tfix: fixOf(\n\t\t\t\t`install ${listNames(missing)} and make sure ${missing.length === 1 ? \"it is\" : \"they are\"} on PATH`,\n\t\t\t),\n\t\t});\n\t}\n\tif (provenance === \"local-unpublished\") {\n\t\treturn makeCheck(id, \"machine\", \"warn\", detail, {\n\t\t\titems,\n\t\t\tfix: fixOf(PUBLISH_DECLARATION_FIX),\n\t\t});\n\t}\n\treturn makeCheck(id, \"machine\", \"pass\", detail, { items });\n}\n\n// ---------------------------------------------------------------------------\n// mcp-servers\n// ---------------------------------------------------------------------------\n\nasync function checkMcpServers(input: DoctorInput): Promise<InstructionCheck> {\n\tconst id = \"mcp-servers\";\n\tconst config = await readMcpConfig(input.root);\n\tif (config.state === \"absent\") {\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"machine\",\n\t\t\t\"skip\",\n\t\t\t`no ${MCP_CONFIG_FILE} in ${input.destination}`,\n\t\t);\n\t}\n\tif (config.state === \"invalid\") {\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"machine\",\n\t\t\t\"fail\",\n\t\t\t`could not use ${MCP_CONFIG_FILE}: ${config.reason}`,\n\t\t\t{\n\t\t\t\tfix: fixOf(\n\t\t\t\t\t`fix ${MCP_CONFIG_FILE} so it is a JSON object with an \"mcpServers\" object of named servers`,\n\t\t\t\t),\n\t\t\t},\n\t\t);\n\t}\n\tif (config.servers.length === 0) {\n\t\treturn makeCheck(\n\t\t\tid,\n\t\t\t\"machine\",\n\t\t\t\"skip\",\n\t\t\t`no servers configured in ${MCP_CONFIG_FILE}`,\n\t\t);\n\t}\n\n\tconst lookup: PathLookupEnvironment = {\n\t\tenv: input.env,\n\t\tplatform: input.platform,\n\t};\n\tconst items: CheckItem[] = [];\n\tconst probes: Array<{ index: number; url: URL }> = [];\n\tfor (const server of config.servers) {\n\t\tconst index = items.length;\n\t\titems.push(await evaluateServer(input, lookup, server, probes, index));\n\t}\n\tif (probes.length > 0) {\n\t\tawait runProbes(probes, items, input.fetchImpl ?? fetch);\n\t}\n\n\tconst failing = config.servers\n\t\t.filter((_, index) => items[index]?.status === \"fail\")\n\t\t.map((server) => server.name);\n\tconst anyUrl = config.servers.some((server) => server.kind === \"url\");\n\tconst status: CheckStatus =\n\t\tfailing.length > 0\n\t\t\t? \"fail\"\n\t\t\t: items.some((item) => item.status === \"warn\")\n\t\t\t\t? \"warn\"\n\t\t\t\t: items.some((item) => item.status === \"pass\")\n\t\t\t\t\t? \"pass\"\n\t\t\t\t\t: \"skip\";\n\tlet detail = `${plural(config.servers.length, \"server\")} in ${MCP_CONFIG_FILE}`;\n\tif (anyUrl) {\n\t\tdetail += input.probeNetwork\n\t\t\t? \"; reachable means an HTTP response arrived, not that a working MCP server answered\"\n\t\t\t: \"; url servers not probed (rerun with --probe-network)\";\n\t}\n\treturn makeCheck(id, \"machine\", status, detail, {\n\t\titems,\n\t\t...(failing.length > 0\n\t\t\t? {\n\t\t\t\t\tfix: fixOf(\n\t\t\t\t\t\t`fix or remove the failing server${failing.length === 1 ? \"\" : \"s\"} in ${MCP_CONFIG_FILE}: ${listNames(failing)}`,\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t: {}),\n\t});\n}\n\nasync function evaluateServer(\n\tinput: DoctorInput,\n\tlookup: PathLookupEnvironment,\n\tserver: McpServerEntry,\n\tprobes: Array<{ index: number; url: URL }>,\n\tindex: number,\n): Promise<CheckItem> {\n\tconst name = server.name;\n\tif (server.kind === \"invalid\") {\n\t\treturn { name, status: \"fail\", detail: server.reason };\n\t}\n\tif (server.kind === \"command\") {\n\t\tconst found = await commandResolves(input, lookup, server.command);\n\t\tif (found === \"unsupported\") {\n\t\t\treturn {\n\t\t\t\tname,\n\t\t\t\tstatus: \"warn\",\n\t\t\t\tdetail: \"command is not a bare executable name or a path; not checked\",\n\t\t\t};\n\t\t}\n\t\treturn found === \"found\"\n\t\t\t? { name, status: \"pass\", detail: \"command found (not executed)\" }\n\t\t\t: { name, status: \"fail\", detail: \"command not found\" };\n\t}\n\n\tif (!input.probeNetwork) {\n\t\treturn {\n\t\t\tname,\n\t\t\tstatus: \"skip\",\n\t\t\tdetail: \"network probe disabled (rerun with --probe-network)\",\n\t\t};\n\t}\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(server.url);\n\t} catch {\n\t\treturn { name, status: \"fail\", detail: \"not a valid URL\" };\n\t}\n\tif (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n\t\treturn { name, status: \"fail\", detail: \"unsupported scheme\" };\n\t}\n\tif (url.username !== \"\" || url.password !== \"\") {\n\t\treturn {\n\t\t\tname,\n\t\t\tstatus: \"warn\",\n\t\t\tdetail: \"the URL embeds credentials; not probed\",\n\t\t};\n\t}\n\tprobes.push({ index, url });\n\t// Replaced by the probe's own verdict once it runs.\n\treturn { name, status: \"skip\", detail: \"probe budget exhausted\" };\n}\n\n/**\n * Where an `.mcp.json` `command` would be found — by `stat`, never by running\n * it. A bare name is looked up on PATH; an absolute path is checked where it\n * is; a relative path is resolved against the checkout, where the coding tool\n * starts it.\n */\nasync function commandResolves(\n\tinput: DoctorInput,\n\tlookup: PathLookupEnvironment,\n\tcommand: string,\n): Promise<\"found\" | \"missing\" | \"unsupported\"> {\n\tif (hasControlCharacter(command) || /\\s/.test(command)) {\n\t\treturn \"unsupported\";\n\t}\n\tif (TOOL_NAME.test(command)) {\n\t\treturn (await isOnPath(command, lookup)) ? \"found\" : \"missing\";\n\t}\n\tconst api = input.platform === \"win32\" ? path.win32 : path.posix;\n\tif (api.isAbsolute(command)) {\n\t\treturn (await isExecutableFile(command, input.platform))\n\t\t\t? \"found\"\n\t\t\t: \"missing\";\n\t}\n\tif (command.includes(\"/\") || command.includes(\"\\\\\")) {\n\t\treturn (await isExecutableFile(\n\t\t\tpath.resolve(input.root, command),\n\t\t\tinput.platform,\n\t\t))\n\t\t\t? \"found\"\n\t\t\t: \"missing\";\n\t}\n\treturn \"unsupported\";\n}\n\n/**\n * `--probe-network`: one GET per `url` server, bounded every way it can be.\n * At most `MAX_PROBES` requests, `PROBE_CONCURRENCY` at a time, each under\n * `PROBE_TIMEOUT_MS`, all under `PROBE_BUDGET_MS`. Whatever the budget does\n * not reach keeps its \"probe budget exhausted\" skip.\n */\nasync function runProbes(\n\tprobes: Array<{ index: number; url: URL }>,\n\titems: CheckItem[],\n\tfetchImpl: typeof fetch,\n): Promise<void> {\n\tconst started = Date.now();\n\tlet next = 0;\n\tlet sent = 0;\n\tconst worker = async (): Promise<void> => {\n\t\twhile (next < probes.length) {\n\t\t\tconst probe = probes[next++] as { index: number; url: URL };\n\t\t\tconst remaining = PROBE_BUDGET_MS - (Date.now() - started);\n\t\t\tif (sent >= MAX_PROBES || remaining <= 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsent++;\n\t\t\tconst item = items[probe.index] as CheckItem;\n\t\t\tconst result = await probeUrl(\n\t\t\t\tprobe.url,\n\t\t\t\tMath.min(PROBE_TIMEOUT_MS, remaining),\n\t\t\t\tfetchImpl,\n\t\t\t);\n\t\t\titems[probe.index] = result.ok\n\t\t\t\t? {\n\t\t\t\t\t\tname: item.name,\n\t\t\t\t\t\tstatus: \"pass\",\n\t\t\t\t\t\tdetail: `reachable (${result.status === 0 ? \"a redirect\" : `HTTP ${result.status}`}); an HTTP response is not proof of a working MCP server`,\n\t\t\t\t\t}\n\t\t\t\t: { name: item.name, status: \"fail\", detail: result.failure };\n\t\t}\n\t};\n\tawait Promise.all(\n\t\tArray.from({ length: Math.min(PROBE_CONCURRENCY, probes.length) }, () =>\n\t\t\tworker(),\n\t\t),\n\t);\n}\n\nasync function probeUrl(\n\turl: URL,\n\ttimeoutMs: number,\n\tfetchImpl: typeof fetch,\n): Promise<{ ok: true; status: number } | { ok: false; failure: string }> {\n\tconst controller = new AbortController();\n\tconst timer = setTimeout(() => controller.abort(), timeoutMs);\n\ttry {\n\t\t// No headers from the config, no redirect followed, no body read: the\n\t\t// status line is the whole answer.\n\t\tconst response = await fetchImpl(url.href, {\n\t\t\tmethod: \"GET\",\n\t\t\tredirect: \"manual\",\n\t\t\tsignal: controller.signal,\n\t\t});\n\t\tawait response.body?.cancel().catch(() => undefined);\n\t\treturn { ok: true, status: response.status };\n\t} catch (error) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tfailure: controller.signal.aborted\n\t\t\t\t? \"timed out\"\n\t\t\t\t: classifyNetworkFailure(error),\n\t\t};\n\t} finally {\n\t\tclearTimeout(timer);\n\t}\n}\n\nfunction errorCodes(error: unknown, depth = 0): string[] {\n\tif (depth > 4 || typeof error !== \"object\" || error === null) {\n\t\treturn [];\n\t}\n\tconst candidate = error as {\n\t\tcode?: unknown;\n\t\tcause?: unknown;\n\t\terrors?: unknown;\n\t};\n\tconst codes: string[] = [];\n\tif (typeof candidate.code === \"string\") {\n\t\tcodes.push(candidate.code);\n\t}\n\tif (candidate.cause !== undefined) {\n\t\tcodes.push(...errorCodes(candidate.cause, depth + 1));\n\t}\n\tif (Array.isArray(candidate.errors)) {\n\t\tfor (const inner of candidate.errors.slice(0, 8)) {\n\t\t\tcodes.push(...errorCodes(inner, depth + 1));\n\t\t}\n\t}\n\treturn codes;\n}\n\n/** A failure CLASS, from error codes only — never an error's message. */\nfunction classifyNetworkFailure(error: unknown): string {\n\tif (error instanceof Error && error.name === \"AbortError\") {\n\t\treturn \"timed out\";\n\t}\n\tconst codes = errorCodes(error);\n\tconst any = (test: (code: string) => boolean) => codes.some(test);\n\tif (any((code) => code === \"ECONNREFUSED\")) {\n\t\treturn \"connection refused\";\n\t}\n\tif (\n\t\tany((code) =>\n\t\t\t[\n\t\t\t\t\"ENOTFOUND\",\n\t\t\t\t\"EAI_AGAIN\",\n\t\t\t\t\"EAI_NONAME\",\n\t\t\t\t\"EAI_NODATA\",\n\t\t\t\t\"EAI_FAIL\",\n\t\t\t].includes(code),\n\t\t)\n\t) {\n\t\treturn \"DNS lookup failed\";\n\t}\n\tif (\n\t\tany((code) =>\n\t\t\t[\n\t\t\t\t\"ETIMEDOUT\",\n\t\t\t\t\"UND_ERR_CONNECT_TIMEOUT\",\n\t\t\t\t\"UND_ERR_HEADERS_TIMEOUT\",\n\t\t\t\t\"ABORT_ERR\",\n\t\t\t].includes(code),\n\t\t)\n\t) {\n\t\treturn \"timed out\";\n\t}\n\tif (\n\t\tany(\n\t\t\t(code) =>\n\t\t\t\tcode.startsWith(\"ERR_TLS\") ||\n\t\t\t\tcode.startsWith(\"ERR_SSL\") ||\n\t\t\t\tcode.includes(\"CERT\") ||\n\t\t\t\tcode === \"UNABLE_TO_VERIFY_LEAF_SIGNATURE\" ||\n\t\t\t\tcode === \"EPROTO\",\n\t\t)\n\t) {\n\t\treturn \"TLS error\";\n\t}\n\tif (\n\t\tany((code) => [\"ECONNRESET\", \"EPIPE\", \"UND_ERR_SOCKET\"].includes(code))\n\t) {\n\t\treturn \"connection reset\";\n\t}\n\tif (any((code) => code === \"EHOSTUNREACH\" || code === \"ENETUNREACH\")) {\n\t\treturn \"host unreachable\";\n\t}\n\treturn \"connection failed\";\n}\n\n// ---------------------------------------------------------------------------\n// Text output\n// ---------------------------------------------------------------------------\n\nconst SYMBOL: Record<CheckStatus, string> = {\n\tpass: \"✓\",\n\tfail: \"✗\",\n\twarn: \"!\",\n\tskip: \"-\",\n};\n\n/** Items shown per check in text; `--format json` always carries them all. */\nconst MAX_TEXT_ITEMS = 20;\n\nexport function formatDoctorText(\n\treport: InstructionChecksReport,\n\tdestination: string,\n): string {\n\tconst lines: string[] = [\n\t\t`Coding instructions doctor: project ${sanitizeDisplayText(report.projectId, 128)} in ${sanitizeDisplayText(destination, 1024)}`,\n\t\t\"\",\n\t];\n\tconst titleWidth =\n\t\tMath.max(...report.checks.map((check) => check.title.length)) + 2;\n\tfor (const check of report.checks) {\n\t\tlines.push(\n\t\t\t`${SYMBOL[check.status]} ${check.title.padEnd(titleWidth)}${check.detail}`,\n\t\t);\n\t\tconst items = check.items ?? [];\n\t\tconst shown = items.slice(0, MAX_TEXT_ITEMS);\n\t\tif (shown.length > 0) {\n\t\t\tconst nameWidth =\n\t\t\t\tMath.min(\n\t\t\t\t\tMath.max(...shown.map((item) => item.name.length)),\n\t\t\t\t\t40,\n\t\t\t\t) + 2;\n\t\t\tfor (const item of shown) {\n\t\t\t\tlines.push(\n\t\t\t\t\t` ${SYMBOL[item.status]} ${item.name.padEnd(nameWidth)}${item.detail ?? \"\"}`.trimEnd(),\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (items.length > shown.length) {\n\t\t\t\tlines.push(\n\t\t\t\t\t` … ${items.length - shown.length} more (--format json lists every one)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (check.fix !== undefined) {\n\t\t\tif (check.fix.command !== undefined) {\n\t\t\t\tlines.push(` fix: ${check.fix.command}`);\n\t\t\t\tlines.push(` ${check.fix.description}`);\n\t\t\t} else {\n\t\t\t\tlines.push(` fix: ${check.fix.description}`);\n\t\t\t}\n\t\t}\n\t}\n\tconst { pass, fail, warn, skip } = report.summary;\n\tlines.push(\n\t\t\"\",\n\t\t`${pass} passed, ${fail} failed, ${plural(warn, \"warning\")}, ${skip} skipped`,\n\t\t\"Fixes are proposals: doctor installed nothing, changed no credentials and wrote no files.\",\n\t);\n\treturn `${lines.join(\"\\n\")}\\n`;\n}\n","/**\n * The coding-tool SessionStart hook that keeps a checkout current.\n *\n * Claude Code writes `.claude/settings.local.json` and never `settings.json`;\n * Codex writes `.codex/hooks.json`. Both are per-developer, normally\n * untracked files. A hook committed into a repository runs on everybody's\n * machine with whatever credentials they happen to have.\n *\n * The command never carries the key. It names a project and nothing else —\n * the CLI reads its credential from `FABRIC_API_KEY` or from the per-user\n * config file, both outside the repository. `assertKeyStaysOutside` is what\n * makes that a guarantee rather than a habit, and it compares REAL paths:\n * a config directory reached through a symlink into the checkout is inside\n * it however the string is spelled.\n *\n * `matcher` is deliberately omitted so the hook runs on startup, resume,\n * clear and compact alike: a session resumed after a pull is exactly when the\n * published version is most likely to have moved.\n */\nimport path from \"node:path\";\nimport {\n\treadFileSafely,\n\tresolvesInside,\n\twriteFileSafely,\n} from \"./safe-write.js\";\n\nexport type InstructionsHookTool = \"claude-code\" | \"codex\";\n\nexport const CLAUDE_SETTINGS_RELATIVE_PATH = path.join(\n\t\".claude\",\n\t\"settings.local.json\",\n);\n\nexport const CODEX_HOOKS_RELATIVE_PATH = path.join(\".codex\", \"hooks.json\");\n\n/** The same path in the POSIX spelling the guarded writer expects. */\nconst CLAUDE_SETTINGS_POSIX_PATH = \".claude/settings.local.json\";\nconst CODEX_HOOKS_POSIX_PATH = \".codex/hooks.json\";\n\n/** Seconds. Long enough for a cold start plus one manifest call, short enough to be invisible. */\nconst HOOK_TIMEOUT_SECONDS = 15;\n\n/** Local hook configuration is small; a bound prevents an untrusted file from consuming memory. */\nconst MAX_HOOK_CONFIG_BYTES = 1024 * 1024;\n\n/**\n * Every subcommand a hook this tool wrote may name, across every event.\n * `isFabricHookFor`'s default: a caller that does not need to distinguish\n * `check`/`sync` from `lesson-prompt` still matches anything this tool wrote.\n */\nconst HOOK_SUBCOMMANDS = new Set([\"check\", \"sync\", \"lesson-prompt\"]);\n\n/**\n * The event this feature writes hooks under, and the subcommands each event\n * may hold. A `lesson-prompt` entry must never be matched (and so never\n * removed) by a `SessionStart` merge, and a `check`/`sync` entry must never be\n * matched by the `Stop` merge — even though today the two events already live\n * under different JSON keys and so cannot collide in practice, matching is\n * scoped explicitly rather than resting on that.\n */\nexport type HookEvent = \"SessionStart\" | \"Stop\";\n\nconst SESSION_START_SUBCOMMANDS: ReadonlySet<string> = new Set([\n\t\"check\",\n\t\"sync\",\n]);\nconst STOP_SUBCOMMANDS: ReadonlySet<string> = new Set([\"lesson-prompt\"]);\n\nfunction subcommandsForEvent(event: HookEvent): ReadonlySet<string> {\n\treturn event === \"Stop\" ? STOP_SUBCOMMANDS : SESSION_START_SUBCOMMANDS;\n}\n\ninterface CommandHook {\n\ttype: \"command\";\n\tcommand: string;\n\ttimeout?: number;\n\t[key: string]: unknown;\n}\n\ninterface HookGroup {\n\tmatcher?: string;\n\thooks: CommandHook[];\n\t[key: string]: unknown;\n}\n\nexport interface MergeHookResult {\n\tsettingsPath: string;\n\tcommand: string;\n\t/** True when the settings file did not exist before. */\n\tcreatedFile: boolean;\n\t/** How many existing Fabric hooks for this project were replaced or dropped. */\n\treplacedCount: number;\n}\n\nexport interface RemoveHookResult {\n\tsettingsPath: string;\n\t/**\n\t * Whether any Fabric-authored entry for this project and subcommand was\n\t * removed. `false` means the file was left byte-for-byte untouched — this\n\t * function never creates the settings file and never writes when there is\n\t * nothing to remove.\n\t */\n\tchanged: boolean;\n}\n\n/**\n * The command the session hook runs.\n *\n * An explicit `--org` is carried through when `init` was given one. These\n * commands do not consult a stored default context, so a slug that was\n * supplied once on the command line has nowhere else to live — leaving it out\n * would install a hook that binds differently from the `init` that created\n * it. It still never carries the key.\n */\nexport function buildHookCommand(\n\tprojectId: string,\n\tapply: boolean,\n\torg?: string,\n): string {\n\tconst verb = apply ? \"sync\" : \"check\";\n\tconst context = org ? ` --org ${org}` : \"\";\n\treturn `fabric instructions ${verb} --project ${projectId}${context} --hook`;\n}\n\n/**\n * The command the Stop hook runs for lesson capture. Same shape as\n * {@link buildHookCommand} — no key, an explicit `--org` carried through when\n * `init` was given one — but a fixed subcommand, because there is no\n * apply/report distinction for a hook that only ever asks a question.\n */\nexport function buildLessonPromptCommand(\n\tprojectId: string,\n\torg?: string,\n): string {\n\tconst context = org ? ` --org ${org}` : \"\";\n\treturn `fabric instructions lesson-prompt --project ${projectId}${context} --hook`;\n}\n\n/**\n * Would writing this hook put the API key inside the repository?\n *\n * The hook itself carries no key, so the only way one lands in the tree is\n * the CLI's own config file being stored there — which happens when\n * `XDG_CONFIG_HOME` or `APPDATA` points inside the checkout, including\n * through a symlink. Refuse rather than write a hook whose credential source\n * a `git add -A` would commit.\n */\nexport async function assertKeyStaysOutside(\n\tdestination: string,\n\tconfigPath: string,\n): Promise<void> {\n\tif (await resolvesInside(destination, configPath)) {\n\t\tthrow new Error(\n\t\t\t`The CLI stores its API key at ${configPath}, which resolves inside ${destination}. Writing a session hook here would leave a live credential in the repository. Move the CLI config outside the project (set XDG_CONFIG_HOME) or export FABRIC_API_KEY instead, then run this again.`,\n\t\t);\n\t}\n}\n\n/**\n * Read and shape-check the hook config file, returning the parsed top-level\n * object (`{}` when the file does not exist) and the raw text that was read\n * (`null` when it does not exist). Shared by every reader below so a refusal\n * reads the same regardless of which event it was checking.\n */\nasync function readHookConfig(\n\troot: string,\n\thookTarget: { relativePath: string; posixPath: string },\n): Promise<{ settings: Record<string, unknown>; existingRaw: string | null }> {\n\tconst settingsPath = path.join(root, hookTarget.relativePath);\n\n\tlet existingRaw: string | null;\n\ttry {\n\t\tconst existing = await readFileSafely(root, hookTarget.posixPath, {\n\t\t\tmaxBytes: MAX_HOOK_CONFIG_BYTES,\n\t\t});\n\t\texistingRaw =\n\t\t\texisting === null ? null : new TextDecoder().decode(existing.bytes);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(\n\t\t\t`${settingsPath} could not be read safely: ${message}. It was left untouched.`,\n\t\t);\n\t}\n\n\tif (existingRaw === null) {\n\t\treturn { settings: {}, existingRaw: null };\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(existingRaw);\n\t} catch {\n\t\t// Refused, never rewritten: this file is the developer's own, and\n\t\t// a JSON error in it is nearly always a half-finished edit rather\n\t\t// than something to discard.\n\t\tthrow new Error(\n\t\t\t`${settingsPath} is not valid JSON. Fix or remove it, then run this again — it was left untouched.`,\n\t\t);\n\t}\n\tif (\n\t\ttypeof parsed !== \"object\" ||\n\t\tparsed === null ||\n\t\tArray.isArray(parsed)\n\t) {\n\t\tthrow new Error(\n\t\t\t`${settingsPath} does not contain a JSON object. It was left untouched.`,\n\t\t);\n\t}\n\treturn { settings: parsed as Record<string, unknown>, existingRaw };\n}\n\n/**\n * Shape-check `hooks[event]` and return it as deep-cloned, well-formed\n * groups. Every nested shape is checked before anything is rebuilt: top-level\n * JSON is refused carefully above, and these were not — `{\"hooks\": [\"custom\"]}`\n * or a `SessionStart` that is not an array used to be replaced with a\n * freshly-built hooks object, discarding whatever the developer had. A shape\n * this tool does not understand is no more ours to normalise than a\n * half-finished edit is. Every event OTHER than `event` is left in `hooks` as\n * an opaque, untouched value — this function only looks at the one key it was\n * asked about.\n */\nfunction readEventGroups(\n\tsettingsPath: string,\n\tsettings: Record<string, unknown>,\n\tevent: HookEvent,\n): { hooks: Record<string, unknown>; groups: HookGroup[] } {\n\tif (settings.hooks !== undefined && !isRecord(settings.hooks)) {\n\t\tthrow refuseShape(settingsPath, '\"hooks\" is not an object');\n\t}\n\tconst hooks = isRecord(settings.hooks) ? { ...settings.hooks } : {};\n\tif (hooks[event] !== undefined && !Array.isArray(hooks[event])) {\n\t\tthrow refuseShape(settingsPath, `\"hooks.${event}\" is not an array`);\n\t}\n\tconst rawGroups = Array.isArray(hooks[event]) ? hooks[event] : [];\n\tfor (const [index, group] of rawGroups.entries()) {\n\t\tif (!isRecord(group)) {\n\t\t\tthrow refuseShape(\n\t\t\t\tsettingsPath,\n\t\t\t\t`\"hooks.${event}[${index}]\" is not an object`,\n\t\t\t);\n\t\t}\n\t\tif (group.hooks !== undefined && !Array.isArray(group.hooks)) {\n\t\t\tthrow refuseShape(\n\t\t\t\tsettingsPath,\n\t\t\t\t`\"hooks.${event}[${index}].hooks\" is not an array`,\n\t\t\t);\n\t\t}\n\t}\n\tconst groups: HookGroup[] = (rawGroups as HookGroup[]).map((group) => ({\n\t\t...group,\n\t\thooks: Array.isArray(group?.hooks) ? [...group.hooks] : [],\n\t}));\n\treturn { hooks, groups };\n}\n\n/**\n * Remove every hook matching `projectId` and `subcommands` from `groups`,\n * dropping a group that held nothing else. Shared pruning step behind both\n * the merge (which adds one entry back) and the remove (which does not).\n */\nfunction pruneMatching(\n\tgroups: HookGroup[],\n\tprojectId: string,\n\tsubcommands: ReadonlySet<string>,\n): { pruned: HookGroup[]; removedCount: number } {\n\tlet removedCount = 0;\n\tconst pruned: HookGroup[] = [];\n\tfor (const group of groups) {\n\t\tconst kept = group.hooks.filter(\n\t\t\t(hook) => !isFabricHookFor(hook, projectId, subcommands),\n\t\t);\n\t\tconst removed = group.hooks.length - kept.length;\n\t\tremovedCount += removed;\n\t\t// A group we emptied held nothing but our own hook; leaving\n\t\t// `{hooks: []}` behind would accumulate one husk per run. A group\n\t\t// that was ALREADY empty is somebody else's and is kept untouched,\n\t\t// which is why this turns on `removed` rather than on length alone.\n\t\tif (kept.length === 0 && removed > 0) {\n\t\t\tcontinue;\n\t\t}\n\t\tpruned.push({ ...group, hooks: kept });\n\t}\n\treturn { pruned, removedCount };\n}\n\n/**\n * Add — or replace — the Fabric hook for one project under one event\n * (`SessionStart` or `Stop`).\n *\n * Idempotent by project id, and idempotent across a file that already has\n * duplicates: EVERY matching entry for that event is removed and exactly one\n * is written back. Matching is on parsed argv tokens, not on a substring —\n * `--project abc` must not match `--project abc-extra`, and `--project=abc`\n * is the same request written differently. Every other key in the file,\n * every other event's array, and every other hook, is preserved exactly.\n */\nexport async function mergeCommandHook(input: {\n\t/** An already-canonical destination from `resolveDestinationRoot`. */\n\troot: string;\n\tprojectId: string;\n\tcommand: string;\n\ttool?: InstructionsHookTool;\n\tevent: HookEvent;\n}): Promise<MergeHookResult> {\n\tconst hookTarget = hookTargetFor(input.tool ?? \"claude-code\");\n\tconst settingsPath = path.join(input.root, hookTarget.relativePath);\n\tconst { settings, existingRaw } = await readHookConfig(\n\t\tinput.root,\n\t\thookTarget,\n\t);\n\tconst { hooks, groups } = readEventGroups(\n\t\tsettingsPath,\n\t\tsettings,\n\t\tinput.event,\n\t);\n\n\tconst replacement: CommandHook = {\n\t\ttype: \"command\",\n\t\tcommand: input.command,\n\t\ttimeout: HOOK_TIMEOUT_SECONDS,\n\t};\n\n\t// Remove EVERY entry for this project first, then add one back. Replacing\n\t// in place and stopping at the first match left duplicates behind, and a\n\t// file that has accumulated two of our hooks should come out with one.\n\tconst { pruned, removedCount } = pruneMatching(\n\t\tgroups,\n\t\tinput.projectId,\n\t\tsubcommandsForEvent(input.event),\n\t);\n\tpruned.push({ hooks: [replacement] });\n\n\tconst next = {\n\t\t...settings,\n\t\thooks: { ...hooks, [input.event]: pruned },\n\t};\n\n\tawait writeFileSafely({\n\t\troot: input.root,\n\t\trelativePath: hookTarget.posixPath,\n\t\tbytes: new TextEncoder().encode(\n\t\t\t`${JSON.stringify(next, null, 2).replace(/\\r\\n/g, \"\\n\")}\\n`,\n\t\t),\n\t});\n\n\treturn {\n\t\tsettingsPath,\n\t\tcommand: input.command,\n\t\tcreatedFile: existingRaw === null,\n\t\treplacedCount: removedCount,\n\t};\n}\n\n/**\n * `mergeCommandHook`, fixed to the `SessionStart` event — the shape every\n * existing caller of this module already depends on. Kept as its own export,\n * with its exact original signature, so nothing that already calls it has to\n * change.\n */\nexport async function mergeSessionStartHook(input: {\n\t/** An already-canonical destination from `resolveDestinationRoot`. */\n\troot: string;\n\tprojectId: string;\n\tcommand: string;\n\ttool?: InstructionsHookTool;\n}): Promise<MergeHookResult> {\n\treturn mergeCommandHook({ ...input, event: \"SessionStart\" });\n}\n\n/**\n * Remove every Fabric-authored hook for one project AND one subcommand,\n * under one event. `init` uses this to describe the DESIRED state: re-running\n * it without `--lessons` uninstalls a Stop hook a previous run installed.\n *\n * Never creates the settings file, and never writes to it when nothing\n * matches — the file is left byte-for-byte untouched, which is what lets a\n * plain `init` (no lesson hook ever installed) keep producing exactly the\n * bytes it always has.\n */\nexport async function removeCommandHook(input: {\n\t/** An already-canonical destination from `resolveDestinationRoot`. */\n\troot: string;\n\tprojectId: string;\n\tsubcommand: string;\n\ttool?: InstructionsHookTool;\n\tevent: HookEvent;\n}): Promise<RemoveHookResult> {\n\tconst hookTarget = hookTargetFor(input.tool ?? \"claude-code\");\n\tconst settingsPath = path.join(input.root, hookTarget.relativePath);\n\tconst { settings, existingRaw } = await readHookConfig(\n\t\tinput.root,\n\t\thookTarget,\n\t);\n\n\tif (existingRaw === null) {\n\t\treturn { settingsPath, changed: false };\n\t}\n\n\tconst { hooks, groups } = readEventGroups(\n\t\tsettingsPath,\n\t\tsettings,\n\t\tinput.event,\n\t);\n\tconst { pruned, removedCount } = pruneMatching(\n\t\tgroups,\n\t\tinput.projectId,\n\t\tnew Set([input.subcommand]),\n\t);\n\n\tif (removedCount === 0) {\n\t\t// Nothing matched: leave the file exactly as it was read, not even a\n\t\t// round-tripped re-serialisation of it.\n\t\treturn { settingsPath, changed: false };\n\t}\n\n\tconst next = {\n\t\t...settings,\n\t\thooks: { ...hooks, [input.event]: pruned },\n\t};\n\n\tawait writeFileSafely({\n\t\troot: input.root,\n\t\trelativePath: hookTarget.posixPath,\n\t\tbytes: new TextEncoder().encode(\n\t\t\t`${JSON.stringify(next, null, 2).replace(/\\r\\n/g, \"\\n\")}\\n`,\n\t\t),\n\t});\n\n\treturn { settingsPath, changed: true };\n}\n\n/**\n * What one coding tool's hook file says about this project, read-only.\n *\n * `absent`: no file. `unreadable`: the file is there but could not be read\n * safely, is not JSON, or has a shape `mergeSessionStartHook` would refuse to\n * touch. `ok`: the `command` of every SessionStart hook this tool would\n * recognise as its own for this project — the same token-exact matcher the\n * merge uses, so \"configured\" means the same thing to both.\n *\n * Carries no reason text on purpose: its caller, `fabric instructions\n * doctor`, reports content-free diagnostics, and the file is the developer's.\n */\nexport type SessionStartHookScan =\n\t| { state: \"absent\" }\n\t| { state: \"unreadable\" }\n\t| { state: \"ok\"; commands: string[] };\n\nexport async function findSessionStartHooks(input: {\n\t/** An already-canonical destination. */\n\troot: string;\n\tprojectId: string;\n\ttool: InstructionsHookTool;\n}): Promise<SessionStartHookScan> {\n\tconst hookTarget = hookTargetFor(input.tool);\n\tlet raw: string;\n\ttry {\n\t\tconst existing = await readFileSafely(\n\t\t\tinput.root,\n\t\t\thookTarget.posixPath,\n\t\t\t{ maxBytes: MAX_HOOK_CONFIG_BYTES },\n\t\t);\n\t\tif (existing === null) {\n\t\t\treturn { state: \"absent\" };\n\t\t}\n\t\traw = new TextDecoder().decode(existing.bytes);\n\t} catch {\n\t\treturn { state: \"unreadable\" };\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\treturn { state: \"unreadable\" };\n\t}\n\tif (!isRecord(parsed)) {\n\t\treturn { state: \"unreadable\" };\n\t}\n\tif (parsed.hooks === undefined) {\n\t\treturn { state: \"ok\", commands: [] };\n\t}\n\tif (!isRecord(parsed.hooks)) {\n\t\treturn { state: \"unreadable\" };\n\t}\n\tconst sessionStart = parsed.hooks.SessionStart;\n\tif (sessionStart === undefined) {\n\t\treturn { state: \"ok\", commands: [] };\n\t}\n\tif (!Array.isArray(sessionStart)) {\n\t\treturn { state: \"unreadable\" };\n\t}\n\tconst commands: string[] = [];\n\tfor (const group of sessionStart) {\n\t\tif (!isRecord(group)) {\n\t\t\treturn { state: \"unreadable\" };\n\t\t}\n\t\tif (group.hooks === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (!Array.isArray(group.hooks)) {\n\t\t\treturn { state: \"unreadable\" };\n\t\t}\n\t\tfor (const hook of group.hooks) {\n\t\t\tif (\n\t\t\t\tisFabricHookFor(hook, input.projectId) &&\n\t\t\t\tSESSION_START_SUBCOMMANDS.has(subcommandOf(hook))\n\t\t\t) {\n\t\t\t\tcommands.push((hook as CommandHook).command);\n\t\t\t}\n\t\t}\n\t}\n\treturn { state: \"ok\", commands };\n}\n\nfunction subcommandOf(hook: unknown): string {\n\tconst command = isRecord(hook) ? hook.command : undefined;\n\treturn typeof command === \"string\"\n\t\t? (command.trim().split(/\\s+/)[2] ?? \"\")\n\t\t: \"\";\n}\n\nfunction hookTargetFor(tool: InstructionsHookTool): {\n\trelativePath: string;\n\tposixPath: string;\n} {\n\treturn tool === \"codex\"\n\t\t? {\n\t\t\t\trelativePath: CODEX_HOOKS_RELATIVE_PATH,\n\t\t\t\tposixPath: CODEX_HOOKS_POSIX_PATH,\n\t\t\t}\n\t\t: {\n\t\t\t\trelativePath: CLAUDE_SETTINGS_RELATIVE_PATH,\n\t\t\t\tposixPath: CLAUDE_SETTINGS_POSIX_PATH,\n\t\t\t};\n}\n\n/**\n * Is this hook one this tool wrote for this project (and, when given, one of\n * `subcommands`)?\n *\n * Token-exact. The command is split on whitespace — every command this tool\n * generates is a plain, unquoted argv line, so a command that needs shell\n * quoting to parse is by definition not ours.\n *\n * `subcommands` defaults to every subcommand this tool has ever written\n * (`HOOK_SUBCOMMANDS`) rather than narrowing automatically, so a caller that\n * needs `check`/`sync` kept apart from `lesson-prompt` passes the narrower set\n * explicitly — see `subcommandsForEvent`.\n */\nfunction isFabricHookFor(\n\thook: unknown,\n\tprojectId: string,\n\tsubcommands: ReadonlySet<string> = HOOK_SUBCOMMANDS,\n): boolean {\n\tif (!isRecord(hook) || typeof hook.command !== \"string\") {\n\t\treturn false;\n\t}\n\tconst tokens = hook.command.trim().split(/\\s+/);\n\tif (tokens[0] !== \"fabric\" || tokens[1] !== \"instructions\") {\n\t\treturn false;\n\t}\n\tif (tokens[2] === undefined || !subcommands.has(tokens[2])) {\n\t\treturn false;\n\t}\n\treturn readProjectToken(tokens) === projectId;\n}\n\n/**\n * The `--project` value, from either `--project X` or `--project=X`, and only\n * when the command names exactly one.\n *\n * `fabric instructions check --project other --project target --hook` is a\n * command Commander resolves to `target`, while reading the first occurrence\n * answers `other`. Either reading makes this matcher wrong about somebody's\n * hook: merging for `other` would delete a hook that syncs `target`, and\n * merging for `target` would leave that entry behind and add a second. A\n * command this tool did not write is not this tool's to rewrite, so an\n * ambiguous one is left exactly as it is.\n */\nfunction readProjectToken(tokens: string[]): string | null {\n\tlet found: string | null = null;\n\tlet occurrences = 0;\n\tfor (let index = 3; index < tokens.length; index++) {\n\t\tconst token = tokens[index] as string;\n\t\tif (token === \"--project\") {\n\t\t\toccurrences++;\n\t\t\tfound = tokens[index + 1] ?? null;\n\t\t\tcontinue;\n\t\t}\n\t\tif (token.startsWith(\"--project=\")) {\n\t\t\toccurrences++;\n\t\t\tfound = token.slice(\"--project=\".length);\n\t\t}\n\t}\n\treturn occurrences === 1 ? found : null;\n}\n\n/** The same refusal shape as an unparseable file: say what, and touch nothing. */\nfunction refuseShape(settingsPath: string, what: string): Error {\n\treturn new Error(\n\t\t`${settingsPath} has a shape this tool does not recognise: ${what}. Fix or remove it, then run this again — it was left untouched.`,\n\t);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","/**\n * Deciding whether a server response is a manifest at all.\n *\n * An absent manifest used to become `[]`, and an empty manifest means\n * \"delete everything the lock names\". A version-skewed server, a truncated\n * proxy response or a field rename was therefore one step away from wiping\n * the tree and writing an empty ledger. A manifest is now either complete\n * and self-consistent or it is a refusal.\n *\n * Three independent things are checked, because each catches a different\n * failure:\n *\n * - every ENTRY is well-formed, and no two name the same file;\n * - the COUNT matches the snapshot's own `fileCount`, which catches a\n * truncated list that is otherwise perfectly well-formed;\n * - the DIGEST recomputed from the entries matches the snapshot's, which\n * catches a list that is the right length and the wrong content.\n *\n * The digest recipe is the server's (`packages/instructions/src/manifest.ts`):\n * sha256 over `path\\0sha256\\n` lines sorted by path, with a mode appended to\n * a line when the file's mode is not the default `0o644`. It is\n * reimplemented here rather than imported because `@repo/instructions` is a\n * private workspace package and this one is published to npm. Keep the two\n * copies in step — a divergence turns every sync into a refusal.\n */\nimport { createHash } from \"node:crypto\";\nimport type { InstructionManifestEntry } from \"@fabricorg/sdk\";\nimport {\n\tcheckRelativePath,\n\tdescribeRejection,\n\tfindCollision,\n\tisReservedPath,\n} from \"./paths.js\";\nimport { isAllowedMode } from \"./safe-write.js\";\n\nconst SHA256_HEX = /^[0-9a-f]{64}$/;\n\n/**\n * What a published snapshot can legitimately be.\n *\n * Mirrors `SNAPSHOT_LIMITS` in `packages/instructions/src/limits.ts`, which\n * bounds what publishing will ACCEPT; these bound what a client will act on.\n * Reimplemented rather than imported for the same reason the digest recipe is:\n * that package is private and this one is published to npm.\n *\n * The point is memory, not policy. Before this, `fileCount` and the per-entry\n * sizes were checked against each other but never against an absolute, so a\n * manifest claiming a million files of 4 GB each was internally consistent and\n * sized the download bound off its own claim.\n *\n * `maxPathBytes` and `maxDepth` are deliberately LOOSER than the server's 512\n * and 32: a client that refuses what the server would happily publish breaks\n * the moment those limits are raised, and 1024 bytes across 5000 files is\n * still bounded. Everything else matches exactly.\n */\nconst MANIFEST_LIMITS = {\n\tmaxFiles: 5000,\n\tmaxTotalBytes: 52_428_800,\n\tmaxFileBytes: 5_242_880,\n\tmaxPathBytes: 1024,\n\tmaxDepth: 64,\n} as const;\n\n/**\n * Per-entry zip framing, in bytes, before the path itself.\n *\n * A zip carries each file twice in structure: a 30-byte local header and a\n * 46-byte central-directory header, each followed by the name, plus optional\n * extra fields and a data descriptor. 512 is generous for all of it, and\n * generous is the right direction — this is a ceiling on what will be\n * DOWNLOADED, and a bound that is too tight refuses a snapshot the server\n * considers perfectly valid.\n */\nconst ZIP_ENTRY_OVERHEAD_BYTES = 512;\n\n/**\n * The largest archive worth downloading for this manifest.\n *\n * A flat slack was wrong: zip framing grows with the number of entries and\n * the length of their names, so a legitimate snapshot of 5000 empty files\n * with 200-byte paths needs about 2.4 MB of pure structure and could not be\n * synced at all. The bound now scales the way the format does.\n */\nexport function maxArchiveBytes(\n\tentries: ReadonlyArray<{ path: string; size: number }>,\n): number {\n\tlet total = 1_048_576;\n\tfor (const entry of entries) {\n\t\ttotal +=\n\t\t\tentry.size +\n\t\t\tZIP_ENTRY_OVERHEAD_BYTES +\n\t\t\t2 * Buffer.byteLength(entry.path, \"utf8\");\n\t}\n\treturn total;\n}\n\n/**\n * `0o644` is the mode a file has when no source recorded one at all (an\n * upload's `mode: null`), so it is the one value that never needs to change\n * the digest.\n */\nconst DEFAULT_MODE = 0o644;\n\n/** Everything but the permission bits — setuid/setgid/sticky and the file-type nibble. */\nconst PERMISSION_MASK = 0o7777;\n\n/**\n * The one normalisation every mode-aware comparison in this feature applies\n * before comparing or hashing: `null`/`undefined` reads as the default\n * `0o644`, and anything else is masked down to its permission bits.\n *\n * The mask matters because `isAllowedMode` below validates a manifest\n * entry's mode on `mode & 0o7777` and explicitly accepts a full `st_mode`\n * (e.g. `0o100644`), not only `0o644` itself — two representations of the\n * same permission that skipped this normalisation would hash differently\n * even though `permissionBits` (also below) applies them identically.\n */\nfunction normalizeMode(mode: number | null | undefined): number {\n\treturn mode == null ? DEFAULT_MODE : mode & PERMISSION_MASK;\n}\n\n/**\n * The snapshot digest, computed the way the server computes it.\n *\n * Keep in step with `computeSnapshotDigest` in `@repo/instructions`. A\n * divergence here turns every sync into a refusal, which is the safe\n * direction but still a break.\n *\n * A file's mode is folded in, but only when its normalised value\n * (`normalizeMode`) is not the default: a line for a `null`, `undefined`,\n * `0o644` or `0o100644` entry is byte-identical to the pre-mode-aware recipe\n * (`path\\0sha256\\n`), and only a non-default mode appends a third field\n * (`path\\0sha256\\0755\\n`, always the normalised permission bits). That is\n * what lets every snapshot already published without an executable file\n * keep a digest an old CLI can still verify.\n */\nexport function computeSnapshotDigest(\n\tentries: ReadonlyArray<{\n\t\tpath: string;\n\t\tsha256: string;\n\t\tmode?: number | null;\n\t}>,\n): string {\n\tconst lines = [...entries]\n\t\t.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0))\n\t\t.map((entry) => {\n\t\t\tconst mode = normalizeMode(entry.mode);\n\t\t\treturn mode === DEFAULT_MODE\n\t\t\t\t? `${entry.path}\\0${entry.sha256}\\n`\n\t\t\t\t: `${entry.path}\\0${entry.sha256}\\0${mode.toString(8)}\\n`;\n\t\t})\n\t\t.join(\"\");\n\treturn createHash(\"sha256\")\n\t\t.update(Buffer.from(lines, \"utf8\"))\n\t\t.digest(\"hex\");\n}\n\n/**\n * The digest a snapshot published BEFORE this change would carry, even if it\n * contains a `0755` file: the pre-mode-aware recipe, computed by stripping\n * every entry's mode before hashing rather than duplicating the hashing code\n * a third time.\n *\n * Such a snapshot is never recomputed after the fact, so a new CLI must still\n * be able to install it. Accepting EITHER value is therefore not a laxer\n * check — it is the same check against the two digests a manifest can\n * legitimately carry.\n */\nfunction computeLegacySnapshotDigest(\n\tentries: ReadonlyArray<{ path: string; sha256: string }>,\n): string {\n\treturn computeSnapshotDigest(\n\t\tentries.map((entry) => ({ ...entry, mode: undefined })),\n\t);\n}\n\n/**\n * Validate a published manifest, or explain why it is not one.\n *\n * Throws rather than returning a result: every caller's only response to a\n * bad manifest is to stop, and under `--hook` the message becomes the one\n * line a developer sees.\n */\nexport function assertValidManifest(input: {\n\tmanifest: unknown;\n\tsnapshot: { digest: string; fileCount: number; version: number };\n}): InstructionManifestEntry[] {\n\tconst { manifest, snapshot } = input;\n\n\tif (!Array.isArray(manifest)) {\n\t\tthrow new Error(\n\t\t\t`The server described version ${snapshot.version} as published but sent no file manifest. Nothing was changed.`,\n\t\t);\n\t}\n\n\tif (manifest.length > MANIFEST_LIMITS.maxFiles) {\n\t\tthrow new Error(\n\t\t\t`The manifest for version ${snapshot.version} lists ${manifest.length} files and a published snapshot holds at most ${MANIFEST_LIMITS.maxFiles}. Nothing was changed.`,\n\t\t);\n\t}\n\n\tconst entries: InstructionManifestEntry[] = [];\n\tfor (const raw of manifest) {\n\t\tentries.push(validateEntry(raw));\n\t}\n\n\tconst totalBytes = entries.reduce((total, entry) => total + entry.size, 0);\n\tif (totalBytes > MANIFEST_LIMITS.maxTotalBytes) {\n\t\tthrow new Error(\n\t\t\t`The manifest for version ${snapshot.version} describes ${totalBytes} bytes and a published snapshot holds at most ${MANIFEST_LIMITS.maxTotalBytes}. Nothing was changed.`,\n\t\t);\n\t}\n\n\tconst collision = findCollision(entries.map((entry) => entry.path));\n\tif (collision !== null) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${describeRejection({\n\t\t\t\tok: false,\n\t\t\t\treason: \"collision\",\n\t\t\t\tdetail: `${collision.first} and ${collision.second}`,\n\t\t\t})}.`,\n\t\t);\n\t}\n\n\tif (entries.length !== snapshot.fileCount) {\n\t\tthrow new Error(\n\t\t\t`The manifest for version ${snapshot.version} lists ${entries.length} files and the snapshot says ${snapshot.fileCount}. Nothing was changed.`,\n\t\t);\n\t}\n\n\t// A snapshot published before mode joined the digest recipe carries the\n\t// LEGACY (mode-less) value even when one of its files is 0755, and that\n\t// snapshot is never recomputed — so a manifest is accepted when it\n\t// matches either recipe. The error still reports the new recipe's hash:\n\t// that is the one a fresh publish is expected to match, and the message\n\t// is unchanged either way.\n\tconst recomputed = computeSnapshotDigest(entries);\n\tif (\n\t\trecomputed !== snapshot.digest &&\n\t\tcomputeLegacySnapshotDigest(entries) !== snapshot.digest\n\t) {\n\t\tthrow new Error(\n\t\t\t`The manifest for version ${snapshot.version} does not match its own digest (${snapshot.digest}); it hashes to ${recomputed}. Nothing was changed.`,\n\t\t);\n\t}\n\n\treturn entries;\n}\n\nfunction validateEntry(raw: unknown): InstructionManifestEntry {\n\tif (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n\t\tthrow new Error(\n\t\t\t\"The server sent a manifest entry that is not an object. Nothing was changed.\",\n\t\t);\n\t}\n\tconst entry = raw as Record<string, unknown>;\n\n\tif (typeof entry.path !== \"string\") {\n\t\tthrow new Error(\n\t\t\t\"The server sent a manifest entry with no path. Nothing was changed.\",\n\t\t);\n\t}\n\tconst check = checkRelativePath(entry.path);\n\tif (!check.ok) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${describeRejection(check)}. The published snapshot names a path this tool will not write.`,\n\t\t);\n\t}\n\tconst pathBytes = Buffer.byteLength(entry.path, \"utf8\");\n\tif (pathBytes > MANIFEST_LIMITS.maxPathBytes) {\n\t\tthrow new Error(\n\t\t\t`The manifest entry for ${entry.path.slice(0, 80)}… has a ${pathBytes}-byte path and at most ${MANIFEST_LIMITS.maxPathBytes} is accepted. Nothing was changed.`,\n\t\t);\n\t}\n\tif (entry.path.split(\"/\").length > MANIFEST_LIMITS.maxDepth) {\n\t\tthrow new Error(\n\t\t\t`The manifest entry for ${entry.path} is nested deeper than ${MANIFEST_LIMITS.maxDepth} directories. Nothing was changed.`,\n\t\t);\n\t}\n\tif (isReservedPath(entry.path)) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${describeRejection({\n\t\t\t\tok: false,\n\t\t\t\treason: \"reserved_path\",\n\t\t\t\tdetail: entry.path,\n\t\t\t})}.`,\n\t\t);\n\t}\n\tif (typeof entry.sha256 !== \"string\" || !SHA256_HEX.test(entry.sha256)) {\n\t\tthrow new Error(\n\t\t\t`The manifest entry for ${entry.path} has no 64-character hex sha256. Nothing was changed.`,\n\t\t);\n\t}\n\tif (\n\t\ttypeof entry.size !== \"number\" ||\n\t\t!Number.isInteger(entry.size) ||\n\t\tentry.size < 0\n\t) {\n\t\tthrow new Error(\n\t\t\t`The manifest entry for ${entry.path} has no non-negative integer size. Nothing was changed.`,\n\t\t);\n\t}\n\tif (entry.size > MANIFEST_LIMITS.maxFileBytes) {\n\t\tthrow new Error(\n\t\t\t`The manifest entry for ${entry.path} declares ${entry.size} bytes and a published file holds at most ${MANIFEST_LIMITS.maxFileBytes}. Nothing was changed.`,\n\t\t);\n\t}\n\tif (\n\t\tentry.mode !== null &&\n\t\t(typeof entry.mode !== \"number\" || !Number.isInteger(entry.mode))\n\t) {\n\t\tthrow new Error(\n\t\t\t`The manifest entry for ${entry.path} has a mode that is neither null nor an integer. Nothing was changed.`,\n\t\t);\n\t}\n\tif (!isAllowedMode(entry.mode as number | null)) {\n\t\tthrow new Error(\n\t\t\t`Refusing to sync: ${entry.path} asks for file mode ${((entry.mode as number) ?? 0).toString(8)}, and only 644 and 755 are accepted.`,\n\t\t);\n\t}\n\n\treturn {\n\t\tpath: entry.path,\n\t\tsha256: entry.sha256,\n\t\tsize: entry.size,\n\t\tmode: entry.mode as number | null,\n\t\tkind: (entry.kind ?? \"OTHER\") as InstructionManifestEntry[\"kind\"],\n\t};\n}\n","/**\n * A bounded, read-only reader for a checkout's `.mcp.json`.\n *\n * The Claude Code project format: `{ \"mcpServers\": { \"<name>\": entry } }`,\n * where an entry is a local process (`command`, `args`, `env`) or a remote\n * server (`url`, `type`, `headers`). `fabric instructions doctor` wants to\n * know, per server, whether the thing it names can be reached — and nothing\n * else. So this keeps the server's key, its `command` or its `url`, and drops\n * every other field on the floor: `env` and `headers` are where credentials\n * live, and a value that is never held cannot be printed by mistake.\n *\n * Every failure reason is content-free. A parse error says \"not valid JSON\",\n * never the parser's message (which quotes the input), and never the path the\n * guarded reader refused.\n */\nimport { sanitizeDisplayText } from \"./checks.js\";\nimport { readFileSafely } from \"./safe-write.js\";\n\nexport const MCP_CONFIG_FILE = \".mcp.json\";\nconst MCP_CONFIG_MAX_BYTES = 262_144;\nconst MCP_CONFIG_MAX_SERVERS = 50;\n\n/** How much of a server key is shown. Keys are repository content. */\nconst MAX_SERVER_NAME_CHARS = 64;\n\nexport type McpServerEntry =\n\t| { name: string; kind: \"command\"; command: string }\n\t| { name: string; kind: \"url\"; url: string }\n\t| { name: string; kind: \"invalid\"; reason: string };\n\nexport type McpConfigRead =\n\t| { state: \"absent\" }\n\t| { state: \"invalid\"; reason: string }\n\t| { state: \"ok\"; servers: McpServerEntry[] };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Parse the text of a `.mcp.json`. Pure; `readMcpConfig` supplies the bounded bytes. */\nfunction parseMcpConfig(text: string): McpConfigRead {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(text);\n\t} catch {\n\t\treturn { state: \"invalid\", reason: \"not valid JSON\" };\n\t}\n\tif (!isRecord(parsed)) {\n\t\treturn { state: \"invalid\", reason: \"top level is not an object\" };\n\t}\n\tif (parsed.mcpServers === undefined) {\n\t\treturn { state: \"ok\", servers: [] };\n\t}\n\tif (!isRecord(parsed.mcpServers)) {\n\t\treturn { state: \"invalid\", reason: \"mcpServers is not an object\" };\n\t}\n\tconst keys = Object.keys(parsed.mcpServers);\n\tif (keys.length > MCP_CONFIG_MAX_SERVERS) {\n\t\treturn {\n\t\t\tstate: \"invalid\",\n\t\t\treason: `mcpServers has more than ${MCP_CONFIG_MAX_SERVERS} entries`,\n\t\t};\n\t}\n\tconst servers: McpServerEntry[] = keys.map((key) => {\n\t\tconst name = sanitizeDisplayText(key, MAX_SERVER_NAME_CHARS);\n\t\tconst entry = (parsed.mcpServers as Record<string, unknown>)[key];\n\t\tif (!isRecord(entry)) {\n\t\t\treturn { name, kind: \"invalid\", reason: \"entry is not an object\" };\n\t\t}\n\t\tif (entry.command !== undefined) {\n\t\t\tif (\n\t\t\t\ttypeof entry.command !== \"string\" ||\n\t\t\t\tentry.command.length === 0\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tname,\n\t\t\t\t\tkind: \"invalid\",\n\t\t\t\t\treason: \"command is not a non-empty string\",\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn { name, kind: \"command\", command: entry.command };\n\t\t}\n\t\tif (entry.url !== undefined) {\n\t\t\tif (typeof entry.url !== \"string\" || entry.url.length === 0) {\n\t\t\t\treturn {\n\t\t\t\t\tname,\n\t\t\t\t\tkind: \"invalid\",\n\t\t\t\t\treason: \"url is not a non-empty string\",\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn { name, kind: \"url\", url: entry.url };\n\t\t}\n\t\treturn {\n\t\t\tname,\n\t\t\tkind: \"invalid\",\n\t\t\treason: \"entry has neither a command nor a url\",\n\t\t};\n\t});\n\treturn { state: \"ok\", servers };\n}\n\n/**\n * Read `<root>/.mcp.json` through the guarded reader: bounded, refusing a\n * symlinked component, and refusing anything but a regular file.\n */\nexport async function readMcpConfig(root: string): Promise<McpConfigRead> {\n\tlet read: Awaited<ReturnType<typeof readFileSafely>>;\n\ttry {\n\t\tread = await readFileSafely(root, MCP_CONFIG_FILE, {\n\t\t\tmaxBytes: MCP_CONFIG_MAX_BYTES,\n\t\t});\n\t} catch (error) {\n\t\treturn {\n\t\t\tstate: \"invalid\",\n\t\t\treason: isTooLarge(error)\n\t\t\t\t? `file is larger than ${MCP_CONFIG_MAX_BYTES} bytes`\n\t\t\t\t: \"file could not be read safely (a symlink, or not a regular file)\",\n\t\t};\n\t}\n\tif (read === null) {\n\t\treturn { state: \"absent\" };\n\t}\n\treturn parseMcpConfig(new TextDecoder().decode(read.bytes));\n}\n\n/**\n * `readFileSafely`'s size refusal, told apart from its other refusals so the\n * report can say which limit was hit. Matched on the guard's own wording;\n * the oversize cases in `doctor-command.test.ts` fail if that wording moves.\n */\nexport function isTooLarge(error: unknown): boolean {\n\treturn (\n\t\terror instanceof Error &&\n\t\terror.message.includes(\"too large to read safely\")\n\t);\n}\n","/**\n * Is an executable reachable on PATH — answered WITHOUT running anything.\n *\n * `fabric instructions doctor` checks tools a published declaration names and\n * commands a repository's `.mcp.json` names. Both are content somebody else\n * wrote, so \"does `pnpm --version` work\" is not a question this may ask:\n * running a program because published text named it is remote code execution\n * by whoever can publish. The only operations here are `stat` calls on\n * candidate paths — never `spawn`, `exec`, or a shell.\n *\n * A candidate counts as found when it is a regular file (symlinks are\n * followed, the way a shell follows them) and, on POSIX, carries an execute\n * bit. On Windows the extension decides, so each name is tried with every\n * `PATHEXT` extension unless it already ends in one.\n *\n * Only ABSOLUTE PATH entries are searched. An empty or relative entry means\n * \"the current directory\" to a shell, and whether that resolves depends on\n * where a coding tool happens to start — not something to report as found.\n */\nimport { stat } from \"node:fs/promises\";\nimport path from \"node:path\";\n\n/** Generous bounds, so a pathological environment cannot turn a check into thousands of stats. */\nconst MAX_PATH_ENTRIES = 256;\nconst MAX_PATHEXT_ENTRIES = 32;\nconst DEFAULT_PATHEXT = \".COM;.EXE;.BAT;.CMD\";\n\n/** The one filesystem question asked of a candidate. */\nexport type CandidateStat = (\n\tcandidate: string,\n) => Promise<{ isFile(): boolean; mode: number }>;\n\nexport interface PathLookupEnvironment {\n\tenv: Readonly<Record<string, string | undefined>>;\n\tplatform: NodeJS.Platform;\n\t/**\n\t * `node:fs/promises` `stat` unless given. Injectable so the Windows rules\n\t * (`;`-separated `Path`, `PATHEXT`, no execute bit) can be exercised on a\n\t * POSIX machine, where `path.win32` candidates are not real paths.\n\t */\n\tstat?: CandidateStat;\n}\n\n/**\n * An environment variable by name — case-insensitively on Windows, where the\n * environment is, and where `Path` is the usual spelling of `PATH`.\n */\nfunction readVariable(\n\tlookup: PathLookupEnvironment,\n\tname: string,\n): string | undefined {\n\tif (lookup.platform !== \"win32\") {\n\t\treturn lookup.env[name];\n\t}\n\tconst key = Object.keys(lookup.env).find(\n\t\t(candidate) => candidate.toUpperCase() === name,\n\t);\n\treturn key === undefined ? undefined : lookup.env[key];\n}\n\nfunction pathApi(platform: NodeJS.Platform): typeof path.posix {\n\treturn platform === \"win32\" ? path.win32 : path.posix;\n}\n\nfunction searchDirectories(lookup: PathLookupEnvironment): string[] {\n\tconst api = pathApi(lookup.platform);\n\tconst raw = readVariable(lookup, \"PATH\") ?? \"\";\n\tconst directories: string[] = [];\n\tfor (const entry of raw.split(api.delimiter)) {\n\t\t// Windows tolerates quoted entries; POSIX has no such convention.\n\t\tconst candidate =\n\t\t\tlookup.platform === \"win32\"\n\t\t\t\t? entry.replace(/^\"(.*)\"$/, \"$1\")\n\t\t\t\t: entry;\n\t\tif (candidate.length === 0 || !api.isAbsolute(candidate)) {\n\t\t\tcontinue;\n\t\t}\n\t\tdirectories.push(candidate);\n\t\tif (directories.length >= MAX_PATH_ENTRIES) {\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn directories;\n}\n\nfunction windowsExtensions(lookup: PathLookupEnvironment): string[] {\n\tconst raw = readVariable(lookup, \"PATHEXT\") ?? DEFAULT_PATHEXT;\n\treturn raw\n\t\t.split(\";\")\n\t\t.map((extension) => extension.trim())\n\t\t.filter((extension) => /^\\.[A-Za-z0-9]+$/.test(extension))\n\t\t.slice(0, MAX_PATHEXT_ENTRIES);\n}\n\n/**\n * Is `candidate` something a shell would run? `stat` only — see the module\n * comment. Any error (absent, permission, a loop) is \"no\".\n */\nexport async function isExecutableFile(\n\tcandidate: string,\n\tplatform: NodeJS.Platform,\n\tstatCandidate: CandidateStat = stat,\n): Promise<boolean> {\n\ttry {\n\t\tconst stats = await statCandidate(candidate);\n\t\tif (!stats.isFile()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn platform === \"win32\" || (stats.mode & 0o111) !== 0;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Is a bare executable name — no separators, validated by the caller —\n * found in any absolute PATH directory?\n */\nexport async function isOnPath(\n\tname: string,\n\tlookup: PathLookupEnvironment,\n): Promise<boolean> {\n\tif (\n\t\tname.length === 0 ||\n\t\tname.includes(\"/\") ||\n\t\tname.includes(\"\\\\\") ||\n\t\tname === \".\" ||\n\t\tname === \"..\"\n\t) {\n\t\treturn false;\n\t}\n\tconst api = pathApi(lookup.platform);\n\tlet candidates = [name];\n\tif (lookup.platform === \"win32\") {\n\t\tconst extensions = windowsExtensions(lookup);\n\t\tconst lower = name.toLowerCase();\n\t\tconst hasKnownExtension = extensions.some((extension) =>\n\t\t\tlower.endsWith(extension.toLowerCase()),\n\t\t);\n\t\tcandidates = hasKnownExtension\n\t\t\t? [name]\n\t\t\t: extensions.map((extension) => `${name}${extension}`);\n\t}\n\tfor (const directory of searchDirectories(lookup)) {\n\t\tfor (const candidate of candidates) {\n\t\t\tif (\n\t\t\t\tawait isExecutableFile(\n\t\t\t\t\tapi.join(directory, candidate),\n\t\t\t\t\tlookup.platform,\n\t\t\t\t\tlookup.stat,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n","/**\n * The session hook's clock (Fizzy #2708), in one mutable object so a test can\n * shorten it instead of waiting ten real seconds. Nothing in the CLI writes\n * to it.\n *\n * `deadlineMs` bounds the whole of hook mode, the bundle download included\n * (`withDeadline` in `commands/instructions/index.ts`). `gitMarginMs` is how\n * long before that deadline every git command a repository-sourced project's\n * hook runs must already have stopped: the git calls and the outer timer\n * would otherwise share one instant, and at that instant the outer timer's\n * generic \"skipped\" line on stderr could win over the repository's own\n * `unknown` line on stdout — the one a session actually reads.\n */\nexport const hookTiming = {\n\tdeadlineMs: 10_000,\n\tgitMarginMs: 750,\n};\n","/**\n * The Stop hook that asks, once per session, whether a mistake should become\n * a team lesson (Fizzy lesson-capture).\n *\n * Claude Code runs this as a Stop hook and feeds it JSON on stdin. The\n * contract is the same one `fabric instructions check|sync --hook` already\n * keep, made stricter: this command must NEVER fail the stop. Any error —\n * malformed stdin, an unreadable transcript, a missing `--project`, a marker\n * directory that cannot be created — is silence and exit 0. It also makes no\n * network call and needs no API key, so nothing here can be slow, and nothing\n * here can hold up a session ending because Fabric is unreachable.\n *\n * `runLessonPrompt` is the one function that decides everything; the command\n * in `commands/instructions/index.ts` is just stdin in, its `output` on\n * stdout, and nothing else. Every other export here is a pure or\n * near-pure piece of it, kept separate so each can be tested without going\n * through a child process.\n */\nimport { createHash } from \"node:crypto\";\nimport { createReadStream } from \"node:fs\";\nimport { mkdir, readdir, stat, unlink, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { describeError } from \"../command-boundary.js\";\n\n/** The JSON Claude Code sends a Stop hook on stdin, the fields this cares about. */\nexport interface StopHookInput {\n\tsessionId: string;\n\ttranscriptPath: string;\n\tstopHookActive: boolean;\n\thookEventName: string;\n}\n\n/**\n * Parse and validate the hook's stdin payload. `null` on anything that is not\n * exactly the shape expected — malformed JSON, a non-object, or any of the\n * four fields missing or of the wrong type. Never throws: every caller in\n * this feature must keep running (silently) past a payload it cannot use.\n */\nexport function parseStopHookInput(text: string): StopHookInput | null {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(text);\n\t} catch {\n\t\treturn null;\n\t}\n\tif (\n\t\ttypeof parsed !== \"object\" ||\n\t\tparsed === null ||\n\t\tArray.isArray(parsed)\n\t) {\n\t\treturn null;\n\t}\n\tconst obj = parsed as Record<string, unknown>;\n\tconst sessionId = obj.session_id;\n\tconst transcriptPath = obj.transcript_path;\n\tconst stopHookActive = obj.stop_hook_active;\n\tconst hookEventName = obj.hook_event_name;\n\tif (\n\t\ttypeof sessionId !== \"string\" ||\n\t\tsessionId.length === 0 ||\n\t\ttypeof transcriptPath !== \"string\" ||\n\t\ttranscriptPath.length === 0 ||\n\t\ttypeof stopHookActive !== \"boolean\" ||\n\t\ttypeof hookEventName !== \"string\"\n\t) {\n\t\treturn null;\n\t}\n\treturn { sessionId, transcriptPath, stopHookActive, hookEventName };\n}\n\n/**\n * The tool_use names that count as \"the assistant edited files\" for the\n * purpose of asking about a lesson. A constant, not an inline literal, so the\n * unit tests and the counter agree on exactly one list.\n */\nexport const EDITING_TOOL_NAMES: ReadonlySet<string> = new Set([\n\t\"Edit\",\n\t\"Write\",\n\t\"MultiEdit\",\n\t\"NotebookEdit\",\n]);\n\n/**\n * A transcript this will not read past, even a well-formed one. The\n * transcript is the developer's own session and ordinarily tiny; this exists\n * only so a corrupt or adversarial file cannot turn a Stop hook into an\n * unbounded read.\n */\nconst MAX_TRANSCRIPT_BYTES = 64 * 1024 * 1024;\n\n/**\n * Count assistant `tool_use` entries in a JSONL transcript whose name is one\n * of `EDITING_TOOL_NAMES`.\n *\n * Read streaming and line by line, because a transcript can be large and\n * this only ever needs a running count. A line that is not valid JSON, or\n * whose shape is not `{ message: { content: [...] } }`, is skipped rather\n * than treated as a failure — a Stop hook runs against a transcript file\n * still being written by the very process that invoked it, so a torn final\n * line is normal, not corruption.\n *\n * The cap bounds the underlying file read itself (`createReadStream`'s\n * `end`), not a running byte count checked between lines: a single line\n * larger than the cap would otherwise be buffered in full by `readline`\n * before any check ran, so the advertised cap would not bound memory. Once\n * the stream stops at the byte offset, the final line it handed to\n * `readline` — whole or cut mid-line, and mid-character when the cut lands\n * inside a multi-byte UTF-8 sequence, since `end` is a byte offset — is\n * simply the last one read. A cut line almost always fails `JSON.parse` and\n * is skipped like any other torn line; on the rare byte count where a cut\n * happens to still parse, it is at worst one tool_use undercounted, which\n * this feature does not need to get exactly right.\n *\n * `maxBytes` defaults to {@link MAX_TRANSCRIPT_BYTES} and exists as a\n * parameter only so tests can exercise the cap without a multi-megabyte\n * fixture.\n *\n * Throws when the file itself cannot be opened or read (missing, permission\n * denied, …) — the caller decides what a transcript it cannot reach means.\n */\nexport async function countEditingToolUses(\n\ttranscriptPath: string,\n\t{ maxBytes = MAX_TRANSCRIPT_BYTES }: { maxBytes?: number } = {},\n): Promise<number> {\n\tconst stream = createReadStream(transcriptPath, {\n\t\tencoding: \"utf8\",\n\t\tend: maxBytes - 1,\n\t});\n\tconst rl = createInterface({\n\t\tinput: stream,\n\t\tcrlfDelay: Number.POSITIVE_INFINITY,\n\t});\n\tlet count = 0;\n\ttry {\n\t\tfor await (const line of rl) {\n\t\t\tcount += countEditingToolUsesInLine(line);\n\t\t}\n\t} finally {\n\t\trl.close();\n\t\tstream.destroy();\n\t}\n\treturn count;\n}\n\nfunction countEditingToolUsesInLine(line: string): number {\n\tconst trimmed = line.trim();\n\tif (trimmed.length === 0) {\n\t\treturn 0;\n\t}\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(trimmed);\n\t} catch {\n\t\treturn 0;\n\t}\n\tif (typeof parsed !== \"object\" || parsed === null) {\n\t\treturn 0;\n\t}\n\tconst message = (parsed as Record<string, unknown>).message;\n\tif (typeof message !== \"object\" || message === null) {\n\t\treturn 0;\n\t}\n\tconst content = (message as Record<string, unknown>).content;\n\tif (!Array.isArray(content)) {\n\t\treturn 0;\n\t}\n\tlet count = 0;\n\tfor (const item of content) {\n\t\tif (\n\t\t\ttypeof item === \"object\" &&\n\t\t\titem !== null &&\n\t\t\t(item as Record<string, unknown>).type === \"tool_use\" &&\n\t\t\ttypeof (item as Record<string, unknown>).name === \"string\" &&\n\t\t\tEDITING_TOOL_NAMES.has(\n\t\t\t\t(item as Record<string, unknown>).name as string,\n\t\t\t)\n\t\t) {\n\t\t\tcount++;\n\t\t}\n\t}\n\treturn count;\n}\n\n/**\n * The marker file name for one session and project: a hex SHA-256, never the\n * raw session id or project id, so the marker directory does not itself\n * become a place that leaks either.\n */\nexport function markerKey(sessionId: string, projectId: string): string {\n\treturn createHash(\"sha256\")\n\t\t.update(`${sessionId}:${projectId}`)\n\t\t.digest(\"hex\");\n}\n\n/**\n * The `reason` text sent back to Claude Code when a lesson check fires.\n * Naming the project id and `fabric_add_instruction_lesson` explicitly, and\n * making the \"only after an explicit yes\" rule part of the instruction\n * itself rather than trusting a general system prompt to supply it.\n */\nexport function lessonPromptReason(projectId: string): string {\n\treturn (\n\t\t`Fabric lesson check for project ${projectId}: before you finish, ask the developer once, in one short question: was there a mistake in this session the team should not repeat? ` +\n\t\t\"If they name one, draft it as a lesson (a title, what happened, why it was a mistake, what to do instead, and the instruction files it relates to) and show them the draft. \" +\n\t\t`Only after they confirm, call the MCP tool fabric_add_instruction_lesson with projectId \"${projectId}\", title, body and relatedPaths; it opens a proposal a person approves, so report it as a suggestion awaiting review. ` +\n\t\t\"If they say no, or the tool is not available, say so in one line and stop. Never call the tool without an explicit yes.\"\n\t);\n}\n\n/** A marker older than this is pruned on the next run, best effort. */\nconst MARKER_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;\n\n/**\n * Best-effort removal of marker files older than {@link MARKER_MAX_AGE_MS}.\n * Failure anywhere here — a listing that fails, a stat or unlink that races\n * with another process — is swallowed; pruning is housekeeping, never the\n * reason a session fails to end.\n */\nasync function pruneOldMarkers(markerDir: string, now: Date): Promise<void> {\n\tlet entries: string[];\n\ttry {\n\t\tentries = await readdir(markerDir);\n\t} catch {\n\t\treturn;\n\t}\n\tconst cutoff = now.getTime() - MARKER_MAX_AGE_MS;\n\tawait Promise.all(\n\t\tentries.map(async (name) => {\n\t\t\tconst entryPath = path.join(markerDir, name);\n\t\t\ttry {\n\t\t\t\tconst stats = await stat(entryPath);\n\t\t\t\tif (stats.mtimeMs < cutoff) {\n\t\t\t\t\tawait unlink(entryPath);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Best effort: a racing prune, a permission error, a file that\n\t\t\t\t// vanished between the listing and the stat — none of it is\n\t\t\t\t// this command's problem to solve.\n\t\t\t}\n\t\t}),\n\t);\n}\n\nasync function markerExists(markerPath: string): Promise<boolean> {\n\ttry {\n\t\tawait stat(markerPath);\n\t\treturn true;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\treturn false;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/** Every reason `runLessonPrompt` can end without printing anything. */\ntype RunLessonPromptWhy =\n\t| \"stop-hook-active\"\n\t| \"already-asked\"\n\t| \"no-edits\"\n\t| \"asked\"\n\t| \"invalid-input\"\n\t| \"marker-unavailable\";\n\nexport interface RunLessonPromptResult {\n\t/** The single JSON line to print to stdout, or `null` to print nothing. */\n\toutput: string | null;\n\twhy: RunLessonPromptWhy;\n}\n\nfunction debugLog(message: string): void {\n\t// No debug flag has existed in this CLI before now; `FABRIC_DEBUG` follows\n\t// the same naming as `FABRIC_API_KEY` / `FABRIC_ORG` / `FABRIC_FORMAT`.\n\tif (process.env.FABRIC_DEBUG) {\n\t\tprocess.stderr.write(`fabric: lesson-prompt: ${message}\\n`);\n\t}\n}\n\n/**\n * Decide whether this Stop hook should ask about a lesson, and build the\n * single JSON line to print if so. Pure with respect to its inputs — reads\n * the transcript and the marker directory, and nothing else — so a test can\n * point it at a temp directory and a fixture file without touching stdin,\n * stdout or the real CLI config path.\n *\n * `projectId` is not part of the hook's stdin payload; it comes from the\n * command's own `--project` flag (the exact value `buildLessonPromptCommand`\n * wrote into the hook). It is threaded through explicitly here, alongside\n * `stdinText`, rather than folded into it, because a missing `--project` is\n * itself one of the silent-exit cases and has nothing to do with whether the\n * stdin JSON parsed.\n *\n * The whole body runs inside one try/catch: every failure mode this\n * contract has to tolerate — a transcript that cannot be opened, a marker\n * directory that cannot be listed, anything unanticipated — collapses to the\n * same `{ output: null, why: \"invalid-input\" }` a bad stdin payload gets,\n * which is the never-fail promise made explicit rather than assembled from\n * several narrower try/catches that would each have to get it right.\n */\nexport async function runLessonPrompt(input: {\n\tstdinText: string;\n\tmarkerDir: string;\n\tnow: Date;\n\tprojectId: string | undefined;\n}): Promise<RunLessonPromptResult> {\n\ttry {\n\t\treturn await runLessonPromptInner(input);\n\t} catch (error) {\n\t\tdebugLog(`unexpected error, staying silent: ${describeError(error)}`);\n\t\treturn { output: null, why: \"invalid-input\" };\n\t}\n}\n\nasync function runLessonPromptInner(input: {\n\tstdinText: string;\n\tmarkerDir: string;\n\tnow: Date;\n\tprojectId: string | undefined;\n}): Promise<RunLessonPromptResult> {\n\tconst projectId = input.projectId?.trim();\n\tif (!projectId) {\n\t\tdebugLog(\"no --project supplied\");\n\t\treturn { output: null, why: \"invalid-input\" };\n\t}\n\n\tconst parsedInput = parseStopHookInput(input.stdinText);\n\tif (parsedInput === null) {\n\t\tdebugLog(\"could not parse stop-hook stdin\");\n\t\treturn { output: null, why: \"invalid-input\" };\n\t}\n\n\t// The hook is already re-running because an earlier Stop hook blocked —\n\t// asking again here would either loop or pile a second question onto the\n\t// first. `stop_hook_active` is Claude Code's own signal for exactly this.\n\tif (parsedInput.stopHookActive) {\n\t\treturn { output: null, why: \"stop-hook-active\" };\n\t}\n\n\ttry {\n\t\tawait mkdir(input.markerDir, { recursive: true });\n\t} catch (error) {\n\t\tdebugLog(`marker directory unavailable: ${describeError(error)}`);\n\t\treturn { output: null, why: \"marker-unavailable\" };\n\t}\n\n\tawait pruneOldMarkers(input.markerDir, input.now).catch((error) => {\n\t\tdebugLog(`marker prune failed: ${describeError(error)}`);\n\t});\n\n\tconst key = markerKey(parsedInput.sessionId, projectId);\n\tconst markerPath = path.join(input.markerDir, key);\n\n\tif (await markerExists(markerPath)) {\n\t\treturn { output: null, why: \"already-asked\" };\n\t}\n\n\tlet editCount: number;\n\ttry {\n\t\teditCount = await countEditingToolUses(parsedInput.transcriptPath);\n\t} catch (error) {\n\t\tdebugLog(`could not read transcript: ${describeError(error)}`);\n\t\treturn { output: null, why: \"invalid-input\" };\n\t}\n\n\tif (editCount === 0) {\n\t\treturn { output: null, why: \"no-edits\" };\n\t}\n\n\t// Written FIRST: a crash between here and the `stdout` write below must\n\t// not leave this session able to ask again.\n\ttry {\n\t\tawait writeFile(markerPath, \"\", { flag: \"wx\" });\n\t} catch (error) {\n\t\tdebugLog(`could not write marker: ${describeError(error)}`);\n\t\treturn { output: null, why: \"marker-unavailable\" };\n\t}\n\n\tconst output = JSON.stringify({\n\t\tdecision: \"block\",\n\t\treason: lessonPromptReason(projectId),\n\t});\n\treturn { output, why: \"asked\" };\n}\n\n/** Read a readable stream to completion and return it as one UTF-8 string. */\nexport async function readAllStdin(\n\tstream: NodeJS.ReadableStream = process.stdin,\n): Promise<string> {\n\tconst chunks: Buffer[] = [];\n\tfor await (const chunk of stream) {\n\t\tchunks.push(\n\t\t\tBuffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)),\n\t\t);\n\t}\n\treturn Buffer.concat(chunks).toString(\"utf8\");\n}\n","/**\n * The caller's open proposals, read before `fabric instructions push` sends\n * anything (Fizzy #2739), so a change one of them already carries is not sent\n * a second time. Which of them count is `setAsideProposed`'s decision\n * (`push.ts`); this module only asks, and answers \"unavailable\" instead of\n * throwing.\n *\n * Unavailable means SEND EVERYTHING, with a warning, never refuse. What an\n * unchecked push costs is the duplicate this lookup exists to avoid, and the\n * server already handles that correctly: each proposal is diffed against its\n * own base. Refusing would make every push fail against a server that does\n * not have the lookup yet, and would turn a slow read into a blocked\n * suggestion.\n *\n * The answer decides which changes are left out, so it is checked for shape\n * before it is used, strictly: a malformed answer, or one naming a state\n * this CLI does not know, is unavailable as a whole, never a partial list.\n * Strict matters most where a field is missing — a deletion whose `sha256`\n * is absent rather than `null` is a server that has drifted from the\n * contract, and reading it leniently would leave a local deletion out with\n * no warning at all.\n */\nimport type {\n\tFabricClient,\n\tInstructionSnapshotStatus,\n\tOpenInstructionProposal,\n\tOpenInstructionProposalChange,\n\tProposalPullRequestState,\n} from \"@fabricorg/sdk\";\nimport { describeError } from \"../command-boundary.js\";\n\n/**\n * The whole lookup's budget, retries included, in one mutable object so a\n * test can shorten it. Nothing in the CLI writes to it.\n */\nexport const openProposalTiming = { deadlineMs: 15_000 };\n\ntype OpenProposalLookup =\n\t| { kind: \"found\"; proposals: OpenInstructionProposal[] }\n\t/** `reason` finishes the sentence \"Could not check your open proposals (…)\". */\n\t| { kind: \"unavailable\"; reason: string };\n\n/**\n * Every snapshot status and pull-request state the contract allows, as\n * records so the compiler fails if either union gains or loses a member\n * without this list following it.\n */\nconst SNAPSHOT_STATUSES: Record<InstructionSnapshotStatus, true> = {\n\tRECEIVING: true,\n\tVALIDATING: true,\n\tREADY: true,\n\tREJECTED: true,\n\tFAILED: true,\n};\n\nconst PULL_REQUEST_STATES: Record<ProposalPullRequestState, true> = {\n\tQUEUED: true,\n\tOPENING: true,\n\tOPEN: true,\n\tCLOSE_REQUESTED: true,\n\tBLOCKED: true,\n\tMERGED: true,\n\tCLOSED: true,\n\tCANCELED: true,\n};\n\nfunction isKnown(known: Record<string, true>, value: unknown): value is string {\n\treturn typeof value === \"string\" && Object.hasOwn(known, value);\n}\n\nclass OpenProposalDeadline extends Error {\n\tconstructor(ms: number) {\n\t\tsuper(`it did not answer within ${Math.ceil(ms / 1000)} s`);\n\t\tthis.name = \"OpenProposalDeadline\";\n\t}\n}\n\nexport async function lookUpOpenProposals(\n\tclient: FabricClient,\n\tprojectId: string,\n\toptions: { org?: string } = {},\n): Promise<OpenProposalLookup> {\n\tconst ms = openProposalTiming.deadlineMs;\n\tconst controller = new AbortController();\n\tconst timer = setTimeout(\n\t\t() => controller.abort(new OpenProposalDeadline(ms)),\n\t\tms,\n\t);\n\tlet answer: unknown;\n\ttry {\n\t\tanswer = await client.instructions.getOpenProposals(projectId, {\n\t\t\torg: options.org,\n\t\t\tsignal: controller.signal,\n\t\t});\n\t} catch (error) {\n\t\t// Classified by the signal, never by the error's name: the SDK\n\t\t// rejects a cancelled request with the signal's own reason.\n\t\tif (controller.signal.aborted) {\n\t\t\treturn {\n\t\t\t\tkind: \"unavailable\",\n\t\t\t\treason: describeError(controller.signal.reason),\n\t\t\t};\n\t\t}\n\t\t// The project was just read successfully through the same gate, so a\n\t\t// 404 here is the route, not the project.\n\t\tif ((error as { status?: number }).status === 404) {\n\t\t\treturn {\n\t\t\t\tkind: \"unavailable\",\n\t\t\t\treason: \"this Fabric server does not list open proposals yet\",\n\t\t\t};\n\t\t}\n\t\treturn { kind: \"unavailable\", reason: describeError(error) };\n\t} finally {\n\t\tclearTimeout(timer);\n\t}\n\tif (!Array.isArray(answer) || !answer.every(isOpenProposal)) {\n\t\treturn {\n\t\t\tkind: \"unavailable\",\n\t\t\treason: \"the server's answer was not a list of proposals\",\n\t\t};\n\t}\n\treturn { kind: \"found\", proposals: answer };\n}\n\nfunction isOpenProposal(value: unknown): value is OpenInstructionProposal {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\tconst proposal = value as Record<string, unknown>;\n\tconst pullRequest = proposal.pullRequest as\n\t\t| Record<string, unknown>\n\t\t| null\n\t\t| undefined;\n\treturn (\n\t\ttypeof proposal.snapshotId === \"string\" &&\n\t\ttypeof proposal.version === \"number\" &&\n\t\ttypeof proposal.baseSnapshotId === \"string\" &&\n\t\tisKnown(SNAPSHOT_STATUSES, proposal.status) &&\n\t\t(pullRequest === null ||\n\t\t\t(typeof pullRequest === \"object\" &&\n\t\t\t\tpullRequest !== undefined &&\n\t\t\t\tisKnown(PULL_REQUEST_STATES, pullRequest.state) &&\n\t\t\t\t(pullRequest.url === null ||\n\t\t\t\t\ttypeof pullRequest.url === \"string\"))) &&\n\t\tArray.isArray(proposal.changes) &&\n\t\tproposal.changes.every(isChange)\n\t);\n}\n\nfunction isChange(value: unknown): value is OpenInstructionProposalChange {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\tconst change = value as Record<string, unknown>;\n\treturn (\n\t\ttypeof change.path === \"string\" &&\n\t\t((change.op === \"put\" && typeof change.sha256 === \"string\") ||\n\t\t\t(change.op === \"delete\" && change.sha256 === null))\n\t);\n}\n","/**\n * `fabric instructions push` following a repository proposal's pull request\n * (Fizzy #2563 spec §12).\n *\n * For a project whose coding instructions come from its repository, a\n * suggestion becomes a pull request there, opened by Fabric's workflow after\n * the files pass their checks. The push waits a bounded while to report where\n * that pull request stands: every 2 s, to an ABSOLUTE 60 s deadline. The\n * deadline is the wait's, not a request's: a status request still in flight\n * when it passes is cancelled, whether it is in the fetch, the body read or\n * the SDK's retry backoff, and no request or sleep starts after it.\n *\n * Expiry is classified by the deadline signal's own `aborted` state, never by\n * an error's name: the SDK rejects a cancelled request with the signal's\n * reason, and any other failure is the caller's to report.\n *\n * A suggestion added to the member's own branch (Fizzy #2738 spec §10) is\n * `OPEN` once its commit is on the branch, which for the branch's first\n * change comes before the branch's pull request exists. So on a branch the\n * wait goes on until the branch has its pull request, or has stopped\n * somewhere no amount of waiting moves it.\n */\nimport type { FabricClient, ProposalPullRequestStatus } from \"@fabricorg/sdk\";\n\nexport const PULL_REQUEST_POLL_MS = 2_000;\nexport const PULL_REQUEST_WAIT_MS = 60_000;\n\n/**\n * States the wait stops at. `OPEN` has its URL; `BLOCKED` needs a person;\n * `MERGED`, `CLOSED` and `CANCELED` are final; `CLOSE_REQUESTED` is an earlier\n * attempt's withdrawal, which no amount of waiting turns into an open pull\n * request.\n */\nconst SETTLED_STATES = new Set([\n\t\"OPEN\",\n\t\"BLOCKED\",\n\t\"MERGED\",\n\t\"CLOSED\",\n\t\"CANCELED\",\n\t\"CLOSE_REQUESTED\",\n]);\n\n/**\n * Branch states at which a suggestion that is `OPEN` on the branch stops\n * waiting without a pull request: `BLOCKED` needs a person, the rest are the\n * branch closing or closed.\n */\nconst STOPPED_BRANCH_STATES = new Set([\n\t\"BLOCKED\",\n\t\"MERGED\",\n\t\"CLOSED\",\n\t\"CANCELED\",\n\t\"CLOSE_REQUESTED\",\n]);\n\n/**\n * A failure the branch carries WITHOUT changing its state that still stops\n * it (Fizzy #2738 spec Decision 19 and §14.2): `REPOSITORY_CHANGED` on any\n * branch, and a failure Fabric will not retry on a branch whose pull request\n * is not open yet, which only a person can clear.\n */\nexport function branchStoppedByFailure(\n\tbranch: NonNullable<ProposalPullRequestStatus[\"branch\"]>,\n): boolean {\n\tconst failure = branch.failure;\n\tif (failure === null) {\n\t\treturn false;\n\t}\n\treturn (\n\t\tfailure.code === \"REPOSITORY_CHANGED\" ||\n\t\t(branch.pullRequest === null && !failure.retryable)\n\t);\n}\n\nfunction isSettled(pullRequest: ProposalPullRequestStatus): boolean {\n\tif (!SETTLED_STATES.has(pullRequest.state)) {\n\t\treturn false;\n\t}\n\tconst branch = pullRequest.branch;\n\tif (pullRequest.state === \"OPEN\" && branch) {\n\t\t// Only an OPEN pull request is one the change was added to: a merged\n\t\t// or closed one is the branch settling while this change's own\n\t\t// classification is still to come, and stops the wait as the\n\t\t// branch's state.\n\t\treturn (\n\t\t\tbranch.pullRequest?.state === \"OPEN\" ||\n\t\t\tSTOPPED_BRANCH_STATES.has(branch.state) ||\n\t\t\tbranchStoppedByFailure(branch)\n\t\t);\n\t}\n\treturn true;\n}\n\nexport type PullRequestWait =\n\t| { kind: \"settled\"; pullRequest: ProposalPullRequestStatus }\n\t/** The deadline passed; `pullRequest` is the last state seen, if any. */\n\t| { kind: \"timed_out\"; pullRequest: ProposalPullRequestStatus | null }\n\t/** The proposal has no pull request: Fabric reviews it itself. */\n\t| { kind: \"none\" };\n\nclass PullRequestWaitDeadline extends Error {\n\tconstructor() {\n\t\tsuper(\"the wait for the pull request reached its deadline\");\n\t\tthis.name = \"PullRequestWaitDeadline\";\n\t}\n}\n\n/** A signal that aborts after `ms`, and the way to stop its timer early. */\nfunction deadlineSignal(ms: number): { signal: AbortSignal; clear(): void } {\n\tconst controller = new AbortController();\n\tconst timer = setTimeout(\n\t\t() => controller.abort(new PullRequestWaitDeadline()),\n\t\tms,\n\t);\n\treturn { signal: controller.signal, clear: () => clearTimeout(timer) };\n}\n\nfunction delay(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function waitForPullRequest(\n\tclient: FabricClient,\n\tprojectId: string,\n\tsnapshotId: string,\n\toptions: {\n\t\torg?: string;\n\t\t/** Called with every status read, in order, before it is judged. */\n\t\tobserve?: (pullRequest: ProposalPullRequestStatus) => void;\n\t} = {},\n): Promise<PullRequestWait> {\n\tconst deadline = Date.now() + PULL_REQUEST_WAIT_MS;\n\tlet last: ProposalPullRequestStatus | null = null;\n\tfor (;;) {\n\t\t// Checked before every request.\n\t\tconst remaining = deadline - Date.now();\n\t\tif (remaining <= 0) {\n\t\t\treturn { kind: \"timed_out\", pullRequest: last };\n\t\t}\n\t\tconst expiry = deadlineSignal(remaining);\n\t\tlet pullRequest: ProposalPullRequestStatus | null;\n\t\ttry {\n\t\t\tpullRequest = await client.instructions.getProposalPullRequest(\n\t\t\t\tprojectId,\n\t\t\t\tsnapshotId,\n\t\t\t\t{ org: options.org, signal: expiry.signal },\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (expiry.signal.aborted) {\n\t\t\t\treturn { kind: \"timed_out\", pullRequest: last };\n\t\t\t}\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\texpiry.clear();\n\t\t}\n\t\tif (pullRequest === null) {\n\t\t\treturn { kind: \"none\" };\n\t\t}\n\t\toptions.observe?.(pullRequest);\n\t\tif (isSettled(pullRequest)) {\n\t\t\treturn { kind: \"settled\", pullRequest };\n\t\t}\n\t\tlast = pullRequest;\n\t\t// Checked before every sleep: a sleep that would end at or past the\n\t\t// deadline leaves no time for the request after it.\n\t\tif (deadline - Date.now() <= PULL_REQUEST_POLL_MS) {\n\t\t\treturn { kind: \"timed_out\", pullRequest: last };\n\t\t}\n\t\tawait delay(PULL_REQUEST_POLL_MS);\n\t}\n}\n\n/**\n * `--message`: the first line is the title and the rest the body, with CRLF\n * and a lone CR read as LF (Review Focus 5). Blank lines between the title\n * and the body are dropped; a message with nothing after its first line is a\n * title alone. Length and credential rules are the server's.\n */\nexport function splitMessage(message: string): {\n\ttitle: string;\n\tbody?: string;\n} {\n\tconst [title = \"\", ...rest] = message.replace(/\\r\\n?/g, \"\\n\").split(\"\\n\");\n\tconst body = rest.join(\"\\n\").replace(/^\\n+/, \"\");\n\treturn body === \"\" ? { title } : { title, body };\n}\n","/**\n * What `fabric instructions push` would send, decided against the LOCAL TREE\n * and the lock together.\n *\n * ## What a push owns\n *\n * Exactly what `sync` owns: the paths in `.fabric/instructions.lock`. That is\n * not a simplification, it is the only defensible rule available here. `sync`\n * has no include/exclude vocabulary of its own — it writes what the manifest\n * names and remembers it in the ledger (`plan.ts`), and the exclusion rules\n * that decide what a snapshot may hold live server-side in\n * `@repo/instructions`, a package this published CLI cannot depend on. So a\n * tree walk would have to invent a rule about which of a checkout's files are\n * instruction files, and getting that wrong means uploading somebody's source\n * tree into their project's coding instructions.\n *\n * Three outcomes per locked path, and nothing else is ever sent:\n *\n * put local bytes differ from the hash the lock recorded\n * delete the lock names it and nothing is there any more\n * (skip) local bytes still equal the lock — there is nothing to say\n *\n * ## Adding a file the lock does not name\n *\n * By `--add <path>`, explicitly, one flag per file. A new file is the one case\n * the ledger cannot discover, and naming it is both unambiguous and honest\n * about what the tool knows. The path goes through the same refusals a locked\n * one does — no traversal, no reserved root, no symlinked component — and must\n * actually be a regular file.\n *\n * ## What an open proposal already carries is not sent again\n *\n * The lock names the PUBLISHED version, and a proposal does not change what\n * is published. So the diff above cannot tell an edit this checkout already\n * proposed from a new one: a second session pushing an unrelated edit would\n * send the first session's change again, and its proposal (or pull request)\n * would carry it twice (Fizzy #2739). `setAsideProposed` takes those out of\n * the plan, by the rule on `carryingProposals`; `--include-proposed` skips it.\n *\n * ## Reads are guarded exactly as writes are\n *\n * Every read goes through `readFileSafely`, the same per-segment walk `sync`\n * writes through: nothing resolving outside the destination, no symlinked\n * component anywhere on the way down, a regular file or nothing at all at the\n * end. A push reads files and sends their contents to a server, so a symlink\n * standing where an instruction file belongs is a way to exfiltrate whatever\n * it points at — the one thing this command must not do.\n */\nimport { createHash } from \"node:crypto\";\nimport type {\n\tInstructionChange,\n\tInstructionManifestEntry,\n\tOpenInstructionProposal,\n\tProposalPullRequestState,\n} from \"@fabricorg/sdk\";\nimport type { InstructionsLock } from \"./lock.js\";\nimport {\n\tcheckRelativePath,\n\tdescribeRejection,\n\tfindCollision,\n\tisReservedPath,\n} from \"./paths.js\";\nimport { readFileSafely } from \"./safe-write.js\";\n\n/** The server's own cap on one change set (`MAX_CHANGES`), mirrored so the refusal happens before the request. */\nexport const MAX_PUSH_CHANGES = 50;\n\ntype PushChangeAction = \"put\" | \"delete\";\n\ninterface PushPlanEntry {\n\tpath: string;\n\taction: PushChangeAction;\n\t/** Present on a `put`: the size of the bytes to send. */\n\tsize?: number;\n\t/** Present on a `put`: the sha256 of the bytes to send, hex. */\n\tsha256?: string;\n}\n\nexport interface PushPlan {\n\tentries: PushPlanEntry[];\n\t/** The change set exactly as the request carries it. */\n\tchanges: InstructionChange[];\n\t/** Locked paths whose bytes still match the ledger. Reported, never sent. */\n\tunchanged: string[];\n}\n\n/**\n * Whether a path is one this tool will read or name at all.\n *\n * The same two refusals `plan.ts` applies to a lock's ledger, for the same\n * reason: the lock is an unauthenticated file in the checkout, and `.git/**`,\n * `.fabric/**` and the tool's own Claude settings file are exactly the paths a\n * tampered one would most want to name — here so it could read them out.\n */\nfunction assertPushablePath(candidate: string, source: string): void {\n\tconst check = checkRelativePath(candidate);\n\tif (!check.ok) {\n\t\tthrow new Error(\n\t\t\t`Refusing to push: ${describeRejection(check)}. ${source}`,\n\t\t);\n\t}\n\tif (isReservedPath(candidate)) {\n\t\tthrow new Error(\n\t\t\t`Refusing to push: ${describeRejection({\n\t\t\t\tok: false,\n\t\t\t\treason: \"reserved_path\",\n\t\t\t\tdetail: candidate,\n\t\t\t})}. ${source}`,\n\t\t);\n\t}\n}\n\n/**\n * How a file's bytes travel in the request.\n *\n * UTF-8 when the bytes are valid UTF-8 and survive the round trip, base64\n * otherwise. Preferring text is not cosmetic: an instruction tree is markdown\n * and JSON, base64 costs a third more request body against a bounded limit,\n * and a readable payload is a readable failure when something goes wrong.\n *\n * The round trip is the test rather than a heuristic on the bytes, because\n * `TextDecoder` replaces anything invalid with U+FFFD silently — a file that\n * \"decoded fine\" would have been sent with its bad bytes rewritten.\n */\nfunction encodeContent(bytes: Uint8Array): {\n\tcontent: string;\n\tencoding: \"utf8\" | \"base64\";\n} {\n\tconst text = new TextDecoder(\"utf-8\", { fatal: false }).decode(bytes);\n\tconst roundTrip = new TextEncoder().encode(text);\n\tif (\n\t\troundTrip.length === bytes.length &&\n\t\troundTrip.every((byte, index) => byte === bytes[index])\n\t) {\n\t\treturn { content: text, encoding: \"utf8\" };\n\t}\n\treturn {\n\t\tcontent: Buffer.from(bytes).toString(\"base64\"),\n\t\tencoding: \"base64\",\n\t};\n}\n\nfunction sha256Of(bytes: Uint8Array): string {\n\treturn createHash(\"sha256\").update(bytes).digest(\"hex\");\n}\n\n/**\n * The one refusal every stale- or tampered-ledger case shares.\n *\n * Same sentence, same instruction, whichever direction the disagreement was\n * found in: the ledger is not the published version, and the fix is local.\n */\nfunction refuseStaleLedger(detail: string): never {\n\tthrow new Error(\n\t\t`Refusing to push: the sync lock does not match the published version — ${detail}. Run \\`fabric instructions sync\\` and try again. Nothing was read and nothing was sent.`,\n\t);\n}\n\n/**\n * Refuse unless the lock describes EXACTLY the published version it names.\n *\n * Both directions are checked, and they catch different things.\n *\n * An EXTRA path — one the ledger claims and the manifest does not — is the\n * attack: it is how a file that was never part of the instructions gets read\n * and sent.\n *\n * A MISSING one — published, absent from the ledger — is the quiet half. The\n * diff below only ever walks what the lock names, so deleting an entry from\n * the ledger makes that file invisible to this command: a local edit to it is\n * dropped from the proposal, a local deletion of it is never reported, and a\n * checkout with one file changed can report \"Nothing to push\". Neither is\n * loud, and both produce a proposal that is not the diff it claims to be.\n *\n * A DIFFERENT hash is neither of those and just as unusable: the diff is \"what\n * changed since the last sync\", and a ledger that disagrees with the version\n * it claims to record cannot answer that question.\n *\n * `nextLock` builds the ledger from the manifest with `Object.fromEntries`, so\n * on a tree this tool wrote the two agree entry for entry; anything else has\n * been edited since, and re-syncing rewrites it from the server.\n */\nfunction assertLockMatchesManifest(\n\tlock: InstructionsLock,\n\tmanifest: readonly InstructionManifestEntry[],\n): void {\n\tconst published = new Map(\n\t\tmanifest.map((entry) => [entry.path, entry.sha256]),\n\t);\n\tfor (const [path, entry] of Object.entries(lock.files)) {\n\t\tconst expected = published.get(path);\n\t\tif (expected === undefined) {\n\t\t\trefuseStaleLedger(\n\t\t\t\t`it lists ${path}, which version ${lock.snapshotVersion} does not contain`,\n\t\t\t);\n\t\t}\n\t\tif (expected !== entry.sha256) {\n\t\t\trefuseStaleLedger(\n\t\t\t\t`its record of ${path} is not the published file`,\n\t\t\t);\n\t\t}\n\t}\n\tfor (const entry of manifest) {\n\t\t// `Object.hasOwn` rather than a lookup: a published file named\n\t\t// `constructor` or `toString` would find something on the prototype\n\t\t// and pass a truthiness check while being absent from the ledger.\n\t\tif (!Object.hasOwn(lock.files, entry.path)) {\n\t\t\trefuseStaleLedger(\n\t\t\t\t`version ${lock.snapshotVersion} contains ${entry.path}, which the lock does not list`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport async function computePushPlan(input: {\n\t/** An already-canonical root, as every guarded read resolves against it. */\n\troot: string;\n\tlock: InstructionsLock;\n\t/**\n\t * The PUBLISHED manifest for `lock.snapshotId`, straight from the server.\n\t *\n\t * The lock is an ordinary JSON file inside the checkout, so anything that\n\t * can write into the working tree can write into it. Treating it as the\n\t * list of files to read and send made that a way to exfiltrate: add\n\t * `private-notes.md` to the ledger with a hash that matches nothing, and\n\t * the next push reads that file and uploads its contents to a project\n\t * whose instructions never mentioned it.\n\t *\n\t * So the ledger is checked against the server's own manifest before a\n\t * single file is read. The manifest is the authority for WHICH paths this\n\t * command may touch; the lock only supplies the hashes it compares\n\t * against, and every one of those has to agree with the manifest too.\n\t */\n\tmanifest: readonly InstructionManifestEntry[];\n\t/** Paths to send as new files, from `--add`. */\n\tadded?: readonly string[];\n}): Promise<PushPlan> {\n\tconst { root, lock } = input;\n\tconst lockedPaths = Object.keys(lock.files);\n\n\tfor (const lockedPath of lockedPaths) {\n\t\tassertPushablePath(\n\t\t\tlockedPath,\n\t\t\t\"The lock names a path this tool will not touch.\",\n\t\t);\n\t}\n\tassertLockMatchesManifest(lock, input.manifest);\n\tconst lockCollision = findCollision(lockedPaths);\n\tif (lockCollision !== null) {\n\t\tthrow new Error(\n\t\t\t`Refusing to push: ${describeRejection({\n\t\t\t\tok: false,\n\t\t\t\treason: \"collision\",\n\t\t\t\tdetail: `${lockCollision.first} and ${lockCollision.second}`,\n\t\t\t})}. The lock names two paths this tool cannot tell apart.`,\n\t\t);\n\t}\n\n\tconst added: string[] = [];\n\tconst locked = new Set(lockedPaths);\n\tfor (const candidate of input.added ?? []) {\n\t\tassertPushablePath(candidate, \"That path cannot be pushed.\");\n\t\tif (locked.has(candidate)) {\n\t\t\t// Already part of the diff below, where its hash decides whether\n\t\t\t// anything is sent at all. Accepting it here too would send it\n\t\t\t// twice, and the server refuses a path named twice.\n\t\t\tcontinue;\n\t\t}\n\t\tif (added.includes(candidate)) {\n\t\t\tcontinue;\n\t\t}\n\t\tadded.push(candidate);\n\t}\n\tconst allCollision = findCollision([...lockedPaths, ...added]);\n\tif (allCollision !== null) {\n\t\tthrow new Error(\n\t\t\t`Refusing to push: ${describeRejection({\n\t\t\t\tok: false,\n\t\t\t\treason: \"collision\",\n\t\t\t\tdetail: `${allCollision.first} and ${allCollision.second}`,\n\t\t\t})}. Two of these paths are one file on a case-insensitive filesystem.`,\n\t\t);\n\t}\n\n\tconst entries: PushPlanEntry[] = [];\n\tconst changes: InstructionChange[] = [];\n\tconst unchanged: string[] = [];\n\n\tfor (const lockedPath of lockedPaths.sort()) {\n\t\tconst read = await readFileSafely(root, lockedPath);\n\t\tif (read === null) {\n\t\t\tentries.push({ path: lockedPath, action: \"delete\" });\n\t\t\tchanges.push({ op: \"delete\", path: lockedPath });\n\t\t\tcontinue;\n\t\t}\n\t\tconst actual = sha256Of(read.bytes);\n\t\tif (actual === lock.files[lockedPath]?.sha256) {\n\t\t\tunchanged.push(lockedPath);\n\t\t\tcontinue;\n\t\t}\n\t\tconst encoded = encodeContent(read.bytes);\n\t\tentries.push({\n\t\t\tpath: lockedPath,\n\t\t\taction: \"put\",\n\t\t\tsize: read.bytes.length,\n\t\t\tsha256: actual,\n\t\t});\n\t\tchanges.push({ op: \"put\", path: lockedPath, ...encoded });\n\t}\n\n\tfor (const newPath of added.sort()) {\n\t\tconst read = await readFileSafely(root, newPath);\n\t\tif (read === null) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to push: there is no file at ${newPath}.`,\n\t\t\t);\n\t\t}\n\t\tconst encoded = encodeContent(read.bytes);\n\t\tentries.push({\n\t\t\tpath: newPath,\n\t\t\taction: \"put\",\n\t\t\tsize: read.bytes.length,\n\t\t\tsha256: sha256Of(read.bytes),\n\t\t});\n\t\tchanges.push({ op: \"put\", path: newPath, ...encoded });\n\t}\n\n\treturn { entries, changes, unchanged };\n}\n\n/** A change left out of the plan because an open proposal already carries it. */\nexport interface AlreadyProposed {\n\tpath: string;\n\taction: PushChangeAction;\n\t/** The newest open proposal that carries it. */\n\tproposal: {\n\t\tsnapshotId: string;\n\t\tversion: number;\n\t\tpullRequest: {\n\t\t\tstate: ProposalPullRequestState;\n\t\t\turl: string | null;\n\t\t} | null;\n\t};\n}\n\n/**\n * Pull-request states in which a repository-sourced proposal is still on its\n * way to review. `BLOCKED` needs a person before it goes anywhere,\n * `CLOSE_REQUESTED` and `CANCELED` are withdrawals, and `MERGED` and `CLOSED`\n * are decided — none of those is carrying a change towards review any more.\n */\nconst LIVE_PULL_REQUEST_STATES: ReadonlySet<string> = new Set([\n\t\"QUEUED\",\n\t\"OPENING\",\n\t\"OPEN\",\n]);\n\n/**\n * Snapshot states in which a proposal's files are complete and its checks\n * are running or have passed. `RECEIVING` may never finish; `FAILED` and\n * `REJECTED` land nothing until somebody acts on them.\n */\nconst LIVE_SNAPSHOT_STATUSES: ReadonlySet<string> = new Set([\n\t\"VALIDATING\",\n\t\"READY\",\n]);\n\n/**\n * The open proposals whose changes a push may leave out, newest first.\n *\n * Only a proposal that will reach review as it stands counts, because the\n * two ways of being wrong cost very different things. Sending a change a\n * proposal already carries costs a duplicate, which the server handles\n * correctly; leaving out a change whose proposal will never be approved\n * loses the edit from the only proposal that could have carried it. So:\n *\n * - stated against `baseSnapshotId`, the version this push is stated against\n * and has already confirmed is the published one. A proposal against an\n * older version is stale, and a stale proposal cannot be approved;\n * - its files complete and its checks running or passed;\n * - and, for a repository-sourced project, its pull request queued, being\n * opened, or open.\n */\nfunction carryingProposals(\n\tproposals: readonly OpenInstructionProposal[],\n\tbaseSnapshotId: string,\n): OpenInstructionProposal[] {\n\treturn proposals\n\t\t.filter(\n\t\t\t(proposal) =>\n\t\t\t\tproposal.baseSnapshotId === baseSnapshotId &&\n\t\t\t\tLIVE_SNAPSHOT_STATUSES.has(proposal.status) &&\n\t\t\t\t(proposal.pullRequest === null ||\n\t\t\t\t\tLIVE_PULL_REQUEST_STATES.has(proposal.pullRequest.state)),\n\t\t)\n\t\t.sort((a, b) => b.version - a.version);\n}\n\n/**\n * Take out of `plan` every change one of the caller's open proposals already\n * carries: the same path with the same bytes (sha256) for a put, the same\n * path for a delete. Everything else stays exactly as computed — an edit that\n * differs from what the proposal carries is a new edit, and is sent.\n */\nexport function setAsideProposed(\n\tplan: PushPlan,\n\tproposals: readonly OpenInstructionProposal[],\n\tbaseSnapshotId: string,\n): { plan: PushPlan; alreadyProposed: AlreadyProposed[] } {\n\tconst carrying = carryingProposals(proposals, baseSnapshotId);\n\tconst carriedBy = (entry: PushPlanEntry) =>\n\t\tcarrying.find((proposal) =>\n\t\t\tproposal.changes.some(\n\t\t\t\t(change) =>\n\t\t\t\t\tchange.path === entry.path &&\n\t\t\t\t\tchange.op === entry.action &&\n\t\t\t\t\t(entry.action === \"delete\" ||\n\t\t\t\t\t\tchange.sha256 === entry.sha256),\n\t\t\t),\n\t\t);\n\n\tconst setAside = new Set<string>();\n\tconst alreadyProposed: AlreadyProposed[] = [];\n\tfor (const entry of plan.entries) {\n\t\tconst proposal = carriedBy(entry);\n\t\tif (proposal === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tsetAside.add(entry.path);\n\t\talreadyProposed.push({\n\t\t\tpath: entry.path,\n\t\t\taction: entry.action,\n\t\t\tproposal: {\n\t\t\t\tsnapshotId: proposal.snapshotId,\n\t\t\t\tversion: proposal.version,\n\t\t\t\tpullRequest: proposal.pullRequest,\n\t\t\t},\n\t\t});\n\t}\n\n\treturn {\n\t\tplan: {\n\t\t\tentries: plan.entries.filter((entry) => !setAside.has(entry.path)),\n\t\t\tchanges: plan.changes.filter(\n\t\t\t\t(change) => !setAside.has(change.path),\n\t\t\t),\n\t\t\tunchanged: plan.unchanged,\n\t\t},\n\t\talreadyProposed,\n\t};\n}\n","/**\n * fabric mcp\n *\n * fabric mcp servers List accessible MCP servers\n * fabric mcp configs List your MCP configurations\n * fabric mcp configs show <id> Show a specific MCP configuration\n */\n\nimport type {\n\tFabricMcpConfig,\n\tFabricMcpConfigDetail,\n\tFabricMcpServer,\n} from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildMcpCommand(): Command {\n\tconst mcp = new Command(\"mcp\").description(\n\t\t\"Manage MCP servers and configurations\",\n\t);\n\n\t// -- servers -------------------------------------------------------------\n\tmcp.command(\"servers\")\n\t\t.description(\"List accessible MCP servers (system + custom)\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print server keys only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricMcpServer[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.mcp.listServers({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const s of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${s.key}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"key\",\n\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\"transport\",\n\t\t\t\t\t\t\"category\",\n\t\t\t\t\t\t\"isSystemProvided\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- configs -------------------------------------------------------------\n\tconst configs = new Command(\"configs\").description(\n\t\t\"Manage MCP configurations\",\n\t);\n\n\tconfigs\n\t\t.command(\"list\", { isDefault: true })\n\t\t.description(\"List your MCP configurations\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricMcpConfig[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.mcp.listConfigs({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const c of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${c.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"serverName\",\n\t\t\t\t\t\t\"displayName\",\n\t\t\t\t\t\t\"authType\",\n\t\t\t\t\t\t\"enabled\",\n\t\t\t\t\t\t\"status\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\tconfigs\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show a specific MCP configuration\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet config: FabricMcpConfigDetail;\n\t\t\t\ttry {\n\t\t\t\t\tconfig = await client.mcp.getConfig(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(config, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: config.id,\n\t\t\t\t\tServer: config.serverName ?? config.mcpServerId,\n\t\t\t\t\t\"Server Key\": config.serverKey ?? \"(none)\",\n\t\t\t\t\t\"Display Name\": config.displayName ?? \"(none)\",\n\t\t\t\t\t\"Base URL\": config.baseUrl ?? \"(none)\",\n\t\t\t\t\tTransport: config.transport ?? \"(default)\",\n\t\t\t\t\t\"Auth Type\": config.authType,\n\t\t\t\t\tEnabled: config.enabled ? \"yes\" : \"no\",\n\t\t\t\t\tStatus: config.status,\n\t\t\t\t\t\"Last Health Check\":\n\t\t\t\t\t\tconfig.lastHealthCheckAt?.slice(0, 19) ?? \"(never)\",\n\t\t\t\t\tCreated: config.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\tconfigs\n\t\t.command(\"delete <id>\")\n\t\t.description(\"Delete an MCP configuration\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"-y, --yes\", \"Skip confirmation prompt\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; yes?: boolean },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\n\t\t\t\tif (!opts.yes) {\n\t\t\t\t\tprocess.stderr.write(\n\t\t\t\t\t\t`Delete MCP config ${id}? This cannot be undone. Pass --yes to confirm.\\n`,\n\t\t\t\t\t);\n\t\t\t\t\tprocess.exit(2);\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tawait client.mcp.deleteConfig(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tprocess.stdout.write(`MCP config ${id} deleted.\\n`);\n\t\t\t},\n\t\t);\n\n\tmcp.addCommand(configs);\n\n\t// -- serve ---------------------------------------------------------------\n\tmcp.command(\"serve\")\n\t\t.description(\n\t\t\t\"Run a stdio MCP server exposing this workspace's whole integration catalog. \" +\n\t\t\t\t\"Point Claude Desktop, Cursor, or any MCP client at it.\",\n\t\t)\n\t\t.action(async () => {\n\t\t\t// Lazy import — avoids loading the MCP SDK when running other commands\n\t\t\t// and keeps the CLI binary cold-start fast.\n\t\t\tconst { runStdio } = await import(\"@fabricorg/sdk-mcp/stdio\");\n\t\t\tawait runStdio();\n\t\t});\n\n\treturn mcp;\n}\n","/**\n * fabric orgs\n *\n * fabric orgs list List orgs you belong to\n * fabric orgs show <slug> Show org details\n */\n\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildOrgsCommand(): Command {\n\tconst orgs = new Command(\"orgs\").description(\"Manage organizations\");\n\n\t// -- list ----------------------------------------------------------------\n\torgs.command(\"list\")\n\t\t.description(\"List organizations you belong to\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print slugs only\")\n\t\t.action(async (opts: { format: string; quiet?: boolean }) => {\n\t\t\tconst client = getClient();\n\t\t\tlet list: Awaited<ReturnType<typeof client.orgs.list>>;\n\t\t\ttry {\n\t\t\t\tlist = await client.orgs.list();\n\t\t\t} catch (err: unknown) {\n\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t}\n\n\t\t\tif (opts.quiet) {\n\t\t\t\tfor (const org of list) {\n\t\t\t\t\tprocess.stdout.write(`${org.slug}\\n`);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tprintOutput(list, {\n\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\tcolumns: [\"name\", \"slug\", \"role\", \"joinedAt\"],\n\t\t\t});\n\t\t});\n\n\t// -- show ----------------------------------------------------------------\n\torgs.command(\"show <slug>\")\n\t\t.description(\"Show details for an organization\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(async (slug: string, opts: { format: string }) => {\n\t\t\tconst client = getClient();\n\t\t\tlet list: Awaited<ReturnType<typeof client.orgs.list>>;\n\t\t\ttry {\n\t\t\t\tlist = await client.orgs.list();\n\t\t\t} catch (err: unknown) {\n\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t}\n\n\t\t\tconst org = list.find(\n\t\t\t\t(o: { slug: string; id: string }) =>\n\t\t\t\t\to.slug === slug || o.id === slug,\n\t\t\t);\n\t\t\tif (!org) {\n\t\t\t\tprintError(`Organization not found: ${slug}`, 4);\n\t\t\t}\n\n\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\tprintOutput(org, { format: fmt });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tprintRecord({\n\t\t\t\tName: org.name,\n\t\t\t\tSlug: org.slug,\n\t\t\t\tRole: org.role,\n\t\t\t\t\"Joined at\": String(org.joinedAt).slice(0, 10),\n\t\t\t\tLogo: org.logo ?? \"(none)\",\n\t\t\t});\n\t\t});\n\n\treturn orgs;\n}\n","/**\n * fabric projects\n *\n * fabric projects list List projects\n * fabric projects show <id> Show project details\n * fabric projects create <name> Create a project\n */\n\nimport type { FabricProject } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport {\n\tprintError,\n\tprintOutput,\n\tprintRecord,\n\tprintSuccess,\n} from \"../../lib/output.js\";\n\nexport function buildProjectsCommand(): Command {\n\tconst projects = new Command(\"projects\").description(\"Manage projects\");\n\n\t// -- list ----------------------------------------------------------------\n\tprojects\n\t\t.command(\"list\")\n\t\t.description(\"List projects\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\n\t\t\t\"--status <status>\",\n\t\t\t\"Filter by status: ACTIVE|DRAFT|COMPLETED|ARCHIVED\",\n\t\t)\n\t\t.option(\"--search <query>\", \"Search by name\")\n\t\t.option(\"--limit <n>\", \"Max results (default 20)\", \"20\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tstatus?: string;\n\t\t\t\tsearch?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricProject[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.projects.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tstatus: opts.status as\n\t\t\t\t\t\t\t| FabricProject[\"status\"]\n\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\tsearch: opts.search,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const p of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${p.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\"id\", \"name\", \"status\", \"createdAt\"],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- show ----------------------------------------------------------------\n\tprojects\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show project details\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet project: FabricProject;\n\t\t\t\ttry {\n\t\t\t\t\tproject = await client.projects.get(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(project, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: project.id,\n\t\t\t\t\tName: project.name,\n\t\t\t\t\tStatus: project.status,\n\t\t\t\t\tDescription: project.description ?? \"(none)\",\n\t\t\t\t\tRepository: project.repositoryUrl ?? \"(none)\",\n\t\t\t\t\tCreated: project.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- create --------------------------------------------------------------\n\tprojects\n\t\t.command(\"create <name>\")\n\t\t.description(\"Create a new project\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"-d, --description <text>\", \"Project description\")\n\t\t.option(\"--repo <url>\", \"Repository URL\")\n\t\t.option(\n\t\t\t\"--status <status>\",\n\t\t\t\"Initial status: DRAFT|ACTIVE (default: DRAFT)\",\n\t\t\t\"DRAFT\",\n\t\t)\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tname: string,\n\t\t\t\topts: {\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\tdescription?: string;\n\t\t\t\t\trepo?: string;\n\t\t\t\t\tstatus: string;\n\t\t\t\t\tformat: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet project: FabricProject;\n\t\t\t\ttry {\n\t\t\t\t\tproject = await client.projects.create({\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tdescription: opts.description,\n\t\t\t\t\t\trepositoryUrl: opts.repo,\n\t\t\t\t\t\tstatus: opts.status as \"DRAFT\" | \"ACTIVE\",\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(project, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintSuccess(`Project \"${project.name}\" created`);\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: project.id,\n\t\t\t\t\tName: project.name,\n\t\t\t\t\tStatus: project.status,\n\t\t\t\t\tDescription: project.description ?? \"(none)\",\n\t\t\t\t\tCreated: project.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- update --------------------------------------------------------------\n\tprojects\n\t\t.command(\"update <id>\")\n\t\t.description(\"Update a project\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--name <name>\", \"New name\")\n\t\t.option(\"-d, --description <text>\", \"New description\")\n\t\t.option(\"--repo <url>\", \"Repository URL\")\n\t\t.option(\"--status <status>\", \"Status: DRAFT|ACTIVE|COMPLETED|ARCHIVED\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: {\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\tname?: string;\n\t\t\t\t\tdescription?: string;\n\t\t\t\t\trepo?: string;\n\t\t\t\t\tstatus?: string;\n\t\t\t\t\tformat: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet project: FabricProject;\n\t\t\t\ttry {\n\t\t\t\t\tproject = await client.projects.update(id, {\n\t\t\t\t\t\tname: opts.name,\n\t\t\t\t\t\tdescription: opts.description,\n\t\t\t\t\t\trepositoryUrl: opts.repo,\n\t\t\t\t\t\tstatus: opts.status as\n\t\t\t\t\t\t\t| \"DRAFT\"\n\t\t\t\t\t\t\t| \"ACTIVE\"\n\t\t\t\t\t\t\t| \"COMPLETED\"\n\t\t\t\t\t\t\t| \"ARCHIVED\"\n\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(project, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: project.id,\n\t\t\t\t\tName: project.name,\n\t\t\t\t\tStatus: project.status,\n\t\t\t\t\tDescription: project.description ?? \"(none)\",\n\t\t\t\t\tUpdated: project.updatedAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn projects;\n}\n","/**\n * fabric prompts\n *\n * fabric prompts list List prompt templates\n * fabric prompts get <id> Get a prompt (prints latest version content)\n */\n\nimport type { FabricPrompt } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport {\n\tprintError,\n\tprintOutput,\n\tprintRecord,\n\tprintSuccess,\n} from \"../../lib/output.js\";\n\nexport function buildPromptsCommand(): Command {\n\tconst prompts = new Command(\"prompts\").description(\n\t\t\"Manage prompt templates\",\n\t);\n\n\t// -- list ----------------------------------------------------------------\n\tprompts\n\t\t.command(\"list\")\n\t\t.description(\"List prompt templates\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--search <query>\", \"Search by name\")\n\t\t.option(\"--category <cat>\", \"Filter by category\")\n\t\t.option(\"--limit <n>\", \"Max results\", \"50\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tsearch?: string;\n\t\t\t\tcategory?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricPrompt[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.prompts.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tsearch: opts.search,\n\t\t\t\t\t\tcategory: opts.category,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const p of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${p.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"key\",\n\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\"scope\",\n\t\t\t\t\t\t\"category\",\n\t\t\t\t\t\t\"updatedAt\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- get -----------------------------------------------------------------\n\tprompts\n\t\t.command(\"get <id>\")\n\t\t.description(\"Get a prompt (prints latest version content by default)\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: raw|table|json|yaml (default: raw)\",\n\t\t\t\"raw\",\n\t\t)\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet prompt: FabricPrompt;\n\t\t\t\ttry {\n\t\t\t\t\tprompt = await client.prompts.get(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"raw\" | \"table\" | \"json\" | \"yaml\";\n\n\t\t\t\tif (fmt === \"json\") {\n\t\t\t\t\tprintOutput(prompt, { format: \"json\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(prompt, { format: \"yaml\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst content = prompt.versions?.[0]?.content ?? \"(no content)\";\n\n\t\t\t\tif (fmt === \"raw\") {\n\t\t\t\t\tprocess.stdout.write(`${content}\\n`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// table: metadata + content block\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: prompt.id,\n\t\t\t\t\tKey: prompt.key,\n\t\t\t\t\tName: prompt.name,\n\t\t\t\t\tScope: prompt.scope,\n\t\t\t\t\tCategory: prompt.category ?? \"(none)\",\n\t\t\t\t\tTags: (prompt.tags ?? []).join(\", \") || \"(none)\",\n\t\t\t\t});\n\t\t\t\tprocess.stdout.write(`\\n--- Content ---\\n${content}\\n`);\n\t\t\t},\n\t\t);\n\n\t// -- create --------------------------------------------------------------\n\tprompts\n\t\t.command(\"create\")\n\t\t.description(\"Create a new prompt\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.requiredOption(\"--key <key>\", \"Prompt key (unique identifier)\")\n\t\t.requiredOption(\"--name <name>\", \"Prompt name\")\n\t\t.option(\"-d, --description <text>\", \"Prompt description\")\n\t\t.option(\"--content <text>\", \"Initial prompt content\")\n\t\t.option(\"--category <cat>\", \"Category\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tkey: string;\n\t\t\t\tname: string;\n\t\t\t\tdescription?: string;\n\t\t\t\tcontent?: string;\n\t\t\t\tcategory?: string;\n\t\t\t\tformat: string;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet prompt: FabricPrompt;\n\t\t\t\ttry {\n\t\t\t\t\tprompt = await client.prompts.create({\n\t\t\t\t\t\tkey: opts.key,\n\t\t\t\t\t\tname: opts.name,\n\t\t\t\t\t\tdescription: opts.description,\n\t\t\t\t\t\tcontent: opts.content,\n\t\t\t\t\t\tcategory: opts.category,\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(prompt, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintSuccess(`Prompt \"${prompt.name}\" created`);\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: prompt.id,\n\t\t\t\t\tKey: prompt.key,\n\t\t\t\t\tName: prompt.name,\n\t\t\t\t\tScope: prompt.scope,\n\t\t\t\t\tCreated: prompt.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- update --------------------------------------------------------------\n\tprompts\n\t\t.command(\"update <id>\")\n\t\t.description(\"Update a prompt\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--name <name>\", \"New name\")\n\t\t.option(\"-d, --description <text>\", \"New description\")\n\t\t.option(\"--category <cat>\", \"Category\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: {\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\tname?: string;\n\t\t\t\t\tdescription?: string;\n\t\t\t\t\tcategory?: string;\n\t\t\t\t\tformat: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet prompt: FabricPrompt;\n\t\t\t\ttry {\n\t\t\t\t\tprompt = await client.prompts.update(id, {\n\t\t\t\t\t\tname: opts.name,\n\t\t\t\t\t\tdescription: opts.description,\n\t\t\t\t\t\tcategory: opts.category,\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(prompt, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: prompt.id,\n\t\t\t\t\tKey: prompt.key,\n\t\t\t\t\tName: prompt.name,\n\t\t\t\t\tScope: prompt.scope,\n\t\t\t\t\tUpdated: prompt.updatedAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn prompts;\n}\n","/**\n * fabric reports\n *\n * fabric reports templates list List report templates\n * fabric reports templates show <id> Show template details\n * fabric reports executions list List report executions\n */\n\nimport type {\n\tFabricReportExecution,\n\tFabricReportTemplate,\n} from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildReportsCommand(): Command {\n\tconst reports = new Command(\"reports\").description(\n\t\t\"Manage report templates and executions\",\n\t);\n\n\t// -- templates -----------------------------------------------------------\n\tconst templates = new Command(\"templates\").description(\n\t\t\"Manage report templates\",\n\t);\n\n\ttemplates\n\t\t.command(\"list\", { isDefault: true })\n\t\t.description(\"List report templates\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--search <query>\", \"Search by name\")\n\t\t.option(\"--category <cat>\", \"Filter by category\")\n\t\t.option(\"--limit <n>\", \"Max results (default 20)\", \"20\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tsearch?: string;\n\t\t\t\tcategory?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricReportTemplate[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.reports.listTemplates({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tsearch: opts.search,\n\t\t\t\t\t\tcategory: opts.category,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const t of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${t.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\"templateType\",\n\t\t\t\t\t\t\"scope\",\n\t\t\t\t\t\t\"usageCount\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\ttemplates\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show report template details\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet tmpl: FabricReportTemplate;\n\t\t\t\ttry {\n\t\t\t\t\ttmpl = await client.reports.getTemplate(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(tmpl, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: tmpl.id,\n\t\t\t\t\tName: tmpl.name,\n\t\t\t\t\tType: tmpl.templateType,\n\t\t\t\t\tScope: tmpl.scope,\n\t\t\t\t\tCategory: tmpl.category ?? \"(none)\",\n\t\t\t\t\tTags: tmpl.tags.join(\", \") || \"(none)\",\n\t\t\t\t\tPublic: tmpl.isPublic ? \"yes\" : \"no\",\n\t\t\t\t\t\"Use Count\": String(tmpl.usageCount),\n\t\t\t\t\tDescription: tmpl.description ?? \"(none)\",\n\t\t\t\t\tUpdated: tmpl.updatedAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treports.addCommand(templates);\n\n\t// -- executions ----------------------------------------------------------\n\tconst executions = new Command(\"executions\").description(\n\t\t\"View report executions\",\n\t);\n\n\texecutions\n\t\t.command(\"list\", { isDefault: true })\n\t\t.description(\"List report executions\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--limit <n>\", \"Max results (default 20)\", \"20\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricReportExecution[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.reports.listExecutions({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const e of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${e.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"templateId\",\n\t\t\t\t\t\t\"status\",\n\t\t\t\t\t\t\"startedAt\",\n\t\t\t\t\t\t\"completedAt\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treports.addCommand(executions);\n\n\treturn reports;\n}\n","/**\n * fabric skills\n *\n * fabric skills list Browse skill definitions\n * fabric skills show <id> Show skill details\n */\n\nimport type { FabricSkill } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildSkillsCommand(): Command {\n\tconst skills = new Command(\"skills\").description(\n\t\t\"Browse skill definitions\",\n\t);\n\n\t// -- list ----------------------------------------------------------------\n\tskills\n\t\t.command(\"list\")\n\t\t.description(\"List skills\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--search <query>\", \"Search by name\")\n\t\t.option(\"--category <cat>\", \"Filter by category\")\n\t\t.option(\"--limit <n>\", \"Max results\", \"50\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print slugs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tsearch?: string;\n\t\t\t\tcategory?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricSkill[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.skills.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tsearch: opts.search,\n\t\t\t\t\t\tcategory: opts.category,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const s of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${s.slug}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\"slug\", \"name\", \"category\", \"scope\", \"useCount\"],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- show ----------------------------------------------------------------\n\tskills\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show skill details (accepts ID or slug)\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(async (id: string, opts: { format: string }) => {\n\t\t\tconst client = getClient();\n\t\t\tlet skill: FabricSkill;\n\t\t\ttry {\n\t\t\t\tskill = await client.skills.get(id);\n\t\t\t} catch (err: unknown) {\n\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t}\n\n\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\tprintOutput(skill, { format: fmt });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tprintRecord({\n\t\t\t\tID: skill.id,\n\t\t\t\tSlug: skill.slug,\n\t\t\t\tName: skill.name,\n\t\t\t\tCategory: skill.category ?? \"(none)\",\n\t\t\t\tScope: skill.scope,\n\t\t\t\tTags: skill.tags.join(\", \") || \"(none)\",\n\t\t\t\tPublished: skill.isPublished ? \"yes\" : \"no\",\n\t\t\t\t\"Use Count\": String(skill.useCount),\n\t\t\t\tVersion: String(skill.version),\n\t\t\t\tDescription: skill.description,\n\t\t\t\tUpdated: skill.updatedAt.slice(0, 10),\n\t\t\t});\n\t\t});\n\n\treturn skills;\n}\n","/**\n * fabric workflows\n *\n * fabric workflows list List workflows\n * fabric workflows show <id> Show workflow details\n * fabric workflows trigger <id> Trigger a workflow execution\n * fabric workflows status <id> <execId> Get execution status\n */\n\nimport type { FabricExecution, FabricWorkflow } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport {\n\tprintError,\n\tprintOutput,\n\tprintRecord,\n\tprintSuccess,\n} from \"../../lib/output.js\";\n\nexport function buildWorkflowsCommand(): Command {\n\tconst workflows = new Command(\"workflows\").description(\"Manage workflows\");\n\n\t// -- list ----------------------------------------------------------------\n\tworkflows\n\t\t.command(\"list\")\n\t\t.description(\"List workflows\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--status <status>\", \"Filter: DRAFT|ACTIVE|PAUSED|ARCHIVED\")\n\t\t.option(\"--search <query>\", \"Search by name\")\n\t\t.option(\"--limit <n>\", \"Max results\", \"20\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tstatus?: string;\n\t\t\t\tsearch?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricWorkflow[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.workflows.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tstatus: opts.status as\n\t\t\t\t\t\t\t| FabricWorkflow[\"status\"]\n\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\tsearch: opts.search,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const w of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${w.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\"status\",\n\t\t\t\t\t\t\"triggerType\",\n\t\t\t\t\t\t\"createdAt\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- show ----------------------------------------------------------------\n\tworkflows\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show workflow details\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet wf: FabricWorkflow;\n\t\t\t\ttry {\n\t\t\t\t\twf = await client.workflows.get(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(wf, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: wf.id,\n\t\t\t\t\tName: wf.name,\n\t\t\t\t\tStatus: wf.status,\n\t\t\t\t\tTrigger: wf.triggerType,\n\t\t\t\t\tVersion: String(wf.version),\n\t\t\t\t\tCreated: wf.createdAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- trigger -------------------------------------------------------------\n\tworkflows\n\t\t.command(\"trigger <id>\")\n\t\t.description(\"Trigger a workflow execution\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--input <json>\", \"JSON input for triggerData\", \"{}\")\n\t\t.option(\"--vars <json>\", \"JSON variables\", \"{}\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: {\n\t\t\t\t\torg?: string;\n\t\t\t\t\tpersonal?: boolean;\n\t\t\t\t\tinput: string;\n\t\t\t\t\tvars: string;\n\t\t\t\t},\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\n\t\t\t\tlet triggerData: Record<string, unknown> = {};\n\t\t\t\tlet variables: Record<string, unknown> = {};\n\t\t\t\ttry {\n\t\t\t\t\ttriggerData = JSON.parse(opts.input);\n\t\t\t\t\tvariables = JSON.parse(opts.vars);\n\t\t\t\t} catch {\n\t\t\t\t\tprintError(\"--input and --vars must be valid JSON\", 2);\n\t\t\t\t}\n\n\t\t\t\tlet result: {\n\t\t\t\t\texecutionId: string;\n\t\t\t\t\tworkflowId: string;\n\t\t\t\t\tstatus: string;\n\t\t\t\t};\n\t\t\t\ttry {\n\t\t\t\t\tresult = await client.workflows.trigger(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\ttriggerData,\n\t\t\t\t\t\tvariables,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tprintSuccess(\"Workflow triggered\");\n\t\t\t\tprocess.stdout.write(` Execution ID: ${result.executionId}\\n`);\n\t\t\t\tprocess.stdout.write(` Status: ${result.status}\\n`);\n\t\t\t},\n\t\t);\n\n\t// -- status --------------------------------------------------------------\n\tworkflows\n\t\t.command(\"status <id> <execId>\")\n\t\t.description(\"Get workflow execution status\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\texecId: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet exec: FabricExecution;\n\t\t\t\ttry {\n\t\t\t\t\texec = await client.workflows.getExecution(id, execId, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(exec, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: exec.id,\n\t\t\t\t\t\"Workflow ID\": exec.workflowId,\n\t\t\t\t\tStatus: exec.status,\n\t\t\t\t\t\"Trigger type\": exec.triggerType,\n\t\t\t\t\tStarted: exec.startedAt?.slice(0, 19) ?? \"(not started)\",\n\t\t\t\t\tCompleted: exec.completedAt?.slice(0, 19) ?? \"(running)\",\n\t\t\t\t\tError: exec.error ?? \"(none)\",\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn workflows;\n}\n","/**\n * fabric workspaces\n *\n * fabric workspaces list List workspaces\n * fabric workspaces show <id> Show workspace details\n */\n\nimport type { FabricWorkspace, FabricWorkspaceDetail } from \"@fabricorg/sdk\";\nimport { Command } from \"commander\";\nimport { getClient } from \"../../lib/client.js\";\nimport { resolveContext } from \"../../lib/context.js\";\nimport { printError, printOutput, printRecord } from \"../../lib/output.js\";\n\nexport function buildWorkspacesCommand(): Command {\n\tconst workspaces = new Command(\"workspaces\").description(\n\t\t\"Manage workspaces\",\n\t);\n\n\t// -- list ----------------------------------------------------------------\n\tworkspaces\n\t\t.command(\"list\")\n\t\t.description(\"List workspaces\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--search <query>\", \"Search by name\")\n\t\t.option(\"--status <status>\", \"Filter: ACTIVE|ARCHIVED\")\n\t\t.option(\"--limit <n>\", \"Max results (default 20)\", \"20\")\n\t\t.option(\n\t\t\t\"--format <format>\",\n\t\t\t\"Output format: table|json|yaml|csv\",\n\t\t\t\"table\",\n\t\t)\n\t\t.option(\"-q, --quiet\", \"Print IDs only\")\n\t\t.action(\n\t\t\tasync (opts: {\n\t\t\t\torg?: string;\n\t\t\t\tpersonal?: boolean;\n\t\t\t\tsearch?: string;\n\t\t\t\tstatus?: string;\n\t\t\t\tlimit: string;\n\t\t\t\tformat: string;\n\t\t\t\tquiet?: boolean;\n\t\t\t}) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet list: FabricWorkspace[];\n\t\t\t\ttry {\n\t\t\t\t\tlist = await client.workspaces.list({\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t\tsearch: opts.search,\n\t\t\t\t\t\tstatus: opts.status as\n\t\t\t\t\t\t\t| \"ACTIVE\"\n\t\t\t\t\t\t\t| \"ARCHIVED\"\n\t\t\t\t\t\t\t| undefined,\n\t\t\t\t\t\tlimit: Number(opts.limit),\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tif (opts.quiet) {\n\t\t\t\t\tfor (const w of list) {\n\t\t\t\t\t\tprocess.stdout.write(`${w.id}\\n`);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintOutput(list, {\n\t\t\t\t\tformat: opts.format as \"table\" | \"json\" | \"yaml\" | \"csv\",\n\t\t\t\t\tcolumns: [\n\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\"type\",\n\t\t\t\t\t\t\"status\",\n\t\t\t\t\t\t\"documentCount\",\n\t\t\t\t\t\t\"updatedAt\",\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\t// -- show ----------------------------------------------------------------\n\tworkspaces\n\t\t.command(\"show <id>\")\n\t\t.description(\"Show workspace details\")\n\t\t.option(\"--org <slug>\", \"Organization context\")\n\t\t.option(\"--personal\", \"Retired — context is organization-only\")\n\t\t.option(\"--format <format>\", \"Output format: table|json|yaml\", \"table\")\n\t\t.action(\n\t\t\tasync (\n\t\t\t\tid: string,\n\t\t\t\topts: { org?: string; personal?: boolean; format: string },\n\t\t\t) => {\n\t\t\t\tconst ctx = resolveContext(opts.personal, opts.org, false);\n\t\t\t\tconst client = getClient();\n\t\t\t\tlet ws: FabricWorkspaceDetail;\n\t\t\t\ttry {\n\t\t\t\t\tws = await client.workspaces.get(id, {\n\t\t\t\t\t\torg: ctx?.type === \"org\" ? ctx.slug : undefined,\n\t\t\t\t\t});\n\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\tprintError((err as Error).message, 1);\n\t\t\t\t}\n\n\t\t\t\tconst fmt = opts.format as \"table\" | \"json\" | \"yaml\";\n\t\t\t\tif (fmt === \"json\" || fmt === \"yaml\") {\n\t\t\t\t\tprintOutput(ws, { format: fmt });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprintRecord({\n\t\t\t\t\tID: ws.id,\n\t\t\t\t\tName: ws.name,\n\t\t\t\t\tType: ws.type,\n\t\t\t\t\tStatus: ws.status,\n\t\t\t\t\tDescription: ws.description ?? \"(none)\",\n\t\t\t\t\tDocuments: String(ws.documentCount),\n\t\t\t\t\tConversations: String(ws.conversationCount),\n\t\t\t\t\tUpdated: ws.updatedAt.slice(0, 10),\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\n\treturn workspaces;\n}\n"],"mappings":"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","names":["Command","_a","_a","rows","cols","_a","Command","Command","FabricAuthError","FabricClient","Command","Command","_a","FabricClient","FabricAuthError","Command","Command","Command","Command","_a","Command","Command","_a","Command","lstat","path","Command","path","_a","_a","path","path","createHash","path","lstat","path","path","lstat","byPath","group","_a","_a","run","path","_a","lines","Command","path","lstat","lines","_a","Command","Command","Command","Command","_a","Command","Command","_a","path","Command","createHash","createHash","readFile","path","SHA256_HEX","path","readFile","lockProblem","serializeLock","extra","createHash","createHash","_a","_a","createHash","_a","realpath","path","_a","lstat","path","_a","path","lstat","host","repoPath","path","realpath","line","createHash","path","path","path","isRecord","group","_a","createHash","SHA256_HEX","lines","createHash","_a","isRecord","stat","path","path","_a","stat","_a","hasControlCharacter","SHELL_SAFE","shellQuote","createHash","auth","who","config","path","lines","createHash","mkdir","readdir","stat","unlink","path","createInterface","createInterface","line","createHash","readdir","path","stat","unlink","_a","mkdir","_a","createHash","createHash","path","_a","GIT_BUDGET_MS","PUSH_TIMEOUT_MS","Command","run","runPush","_a","path","readLockForProject","Command","Command","_a","config","Command","Command","_a","Command","Command","_a","Command","Command","_a","Command","Command","_a","Command","Command","_a","Command","Command","_a","Command","Command","_a","Command"]}