arcane-cli 0.33.3 → 0.33.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/modules/copier.ts","../src/modules/manifest.ts","../src/config/profiles.ts","../src/modules/registry.ts","../src/modules/banner.ts","../src/modules/agents.ts","../src/config/agent-roles.ts","../src/config/agent-profiles.ts","../src/modules/naming.ts","../src/modules/agent-loader.ts","../src/modules/agent-schema.ts","../src/modules/agent-generator.ts","../src/modules/merger.ts","../src/modules/push-safety.ts","../src/modules/git.ts","../src/modules/secrets-scan.ts","../src/commands/add.ts","../src/commands/update.ts","../src/modules/hub.ts","../src/modules/merge3.ts","../src/modules/npm-registry.ts","../src/modules/version-check.ts","../src/modules/diagram-generator.ts","../src/commands/status.ts","../src/commands/uninstall.ts","../src/commands/doctor.ts","../src/config/incidents.ts","../src/modules/incident-gate.ts","../src/modules/denylist-scan.ts","../src/modules/platform-policy.ts","../src/modules/ward.ts","../src/commands/ward.ts","../src/commands/unblock-push.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { createRequire } from \"node:module\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport { runInit } from \"./commands/init.js\";\nimport { runAdd } from \"./commands/add.js\";\nimport { runUpdate } from \"./commands/update.js\";\nimport { runStatus } from \"./commands/status.js\";\nimport { runUninstall } from \"./commands/uninstall.js\";\nimport { runDoctor } from \"./commands/doctor.js\";\nimport { runWardCli } from \"./commands/ward.js\";\nimport { runUnblockPush } from \"./commands/unblock-push.js\";\nimport { runAgentsInit, runAgentsList, runAgentsSync } from \"./modules/agents.js\";\nimport { printWelcome } from \"./modules/banner.js\";\nimport type { Profile, AgentInitOptions, AgentProfileId, NamingStrategy, AgentSyncOptions } from \"./types.js\";\n\nconst require = createRequire(import.meta.url);\nconst pkg = require(\"../package.json\") as { version: string };\n\n/**\n * Resolved path to the bundled assets directory.\n * Points to src/assets/ during tests (vitest runs source directly) and\n * dist/assets/ in the published package (tsup bundles to dist/index.js).\n * Can be overridden via ARCANE_ASSETS_DIR env var for testing the built binary.\n */\nexport const ASSETS_DIR =\n process.env[\"ARCANE_ASSETS_DIR\"] ??\n join(dirname(fileURLToPath(import.meta.url)), \"assets\");\n\nconst program = new Command();\n\nprogram\n .name(\"spell\")\n .description(\"Arcane framework CLI — scaffold and manage governance files\")\n .version(pkg.version)\n .action(async () => {\n // Commander routes an unrecognized subcommand here too (no root\n // `.arguments()` is declared, so it doesn't emit `command:*`) — the only\n // way to tell \"no subcommand\" from \"an unrecognized one\" is the leftover\n // positional args.\n if (program.args.length > 0) {\n const [attempted] = program.args;\n console.error(`spell: unrecognized command '${attempted}'`);\n console.error();\n console.error(\n `Spells are prompts, not CLI commands — run /spell-${attempted} in your agent client.`,\n );\n console.error();\n console.error(\"Real CLI commands:\");\n for (const cmd of program.commands) {\n console.error(` ${cmd.name().padEnd(14)} ${cmd.description()}`);\n }\n process.exitCode = 1;\n return;\n }\n // Bare `spell` with no subcommand — show the welcome (banner + real repo\n // state + Spell Loop), then the command reference.\n await printWelcome(pkg.version, process.cwd());\n program.outputHelp();\n });\n\nprogram\n .command(\"init\")\n .description(\"Scaffold Arcane framework files into the current repository\")\n .option(\"--profile <profile>\", \"Profile: full | lite | methodology | docs | governance-only\")\n .option(\"--force\", \"Overwrite existing files without error\")\n .option(\"--dry-run\", \"Preview what would be installed without making changes\")\n .action(\n async (opts: { profile?: string; force?: boolean; dryRun?: boolean }) => {\n await runInit(\n {\n profile: opts.profile as Profile | undefined,\n force: opts.force,\n dryRun: opts.dryRun,\n },\n process.cwd(),\n ASSETS_DIR,\n pkg.version,\n );\n },\n );\n\nprogram\n .command(\"add <component>\")\n .description(\"Add a component to an existing Arcane installation\")\n .option(\"--force\", \"Overwrite existing files without error\")\n .option(\"--dry-run\", \"Preview what would be added without making changes\")\n .action(\n async (\n component: string,\n opts: { force?: boolean; dryRun?: boolean },\n ) => {\n await runAdd(\n component,\n { force: opts.force, dryRun: opts.dryRun },\n process.cwd(),\n ASSETS_DIR,\n pkg.version,\n );\n },\n );\n\nprogram\n .command(\"update\")\n .description(\"Update installed components to the current package version\")\n .option(\"--dry-run\", \"Preview what would be updated without making changes\")\n .option(\n \"--prune\",\n \"Also delete orphaned managed files (tracked before this update, no longer part of any current component). Hash-checked: an edited file is reported, never silently deleted\",\n )\n .action(async (opts: { dryRun?: boolean; prune?: boolean }) => {\n await runUpdate(\n { dryRun: opts.dryRun, prune: opts.prune },\n process.cwd(),\n ASSETS_DIR,\n pkg.version,\n );\n });\n\nprogram\n .command(\"status\")\n .description(\"Show installed components and check for updates\")\n .action(async () => {\n await runStatus(process.cwd(), pkg.version);\n });\n\nprogram\n .command(\"uninstall\")\n .description(\"Remove all installed Arcane framework files\")\n .option(\"--yes\", \"Skip confirmation prompt\")\n .option(\"--dry-run\", \"Preview what would be removed without deleting files\")\n .action(async (opts: { yes?: boolean; dryRun?: boolean }) => {\n await runUninstall({ yes: opts.yes, dryRun: opts.dryRun }, process.cwd());\n });\n\nprogram\n .command(\"unblock-push\")\n .description(\"Lift this repository's push block (interactive terminal only)\")\n .action(async () => {\n await runUnblockPush(process.cwd());\n });\n\nprogram\n .command(\"doctor\")\n .description(\"Check your environment for Arcane prerequisites\")\n .option(\"--fix\", \"Automatically create missing session continuity files\")\n .option(\"--leaks\", \"Run only the on-demand secrets/credential scan (ARC-037), skipping the default checks\")\n .action(async (opts: { fix?: boolean; leaks?: boolean }) => {\n await runDoctor(process.cwd(), { fix: opts.fix, leaks: opts.leaks }, ASSETS_DIR);\n });\n\n// ─── spell ward ───────────────────────────────────────────────────────────────\n\nprogram\n .command(\"ward\")\n .description(\"Scan the repo for leaked identifiers -- third-party trademarks and the operator's own personal identifiers alike (T18)\")\n .option(\n \"--terms <terms>\",\n \"Comma-separated denylist terms, in addition to the built-in vendor-identifier list. Seed this from your OWN identity too, not just org/venture names -- usernames, machine names, and personal handles leak the same way a private venture name does (I1)\",\n )\n .option(\"--gate\", \"Exit non-zero if any leak is found (for CI)\")\n .action(async (opts: { terms?: string; gate?: boolean }) => {\n await runWardCli(process.cwd(), opts);\n });\n\n// ─── spell agents ─────────────────────────────────────────────────────────────\n\nconst agentsCommand = program\n .command(\"agents\")\n .description(\"Manage the portable agent system (init, sync, list)\");\n\nagentsCommand\n .command(\"init\")\n .description(\n \"Interactive agent roster setup — choose profile, naming strategy, and install definitions\",\n )\n .option(\n \"--profile <profile>\",\n \"Agent profile: base | full | custom\",\n )\n .option(\n \"--naming <strategy>\",\n \"Naming strategy: arcanos | generic | random | custom\",\n )\n .option(\"--force\", \"Reinitialize even if roster already exists\")\n .option(\"--dry-run\", \"Preview what would be created without writing files\")\n .action(\n async (opts: {\n profile?: string;\n naming?: string;\n force?: boolean;\n dryRun?: boolean;\n }) => {\n await runAgentsInit(\n {\n profile: opts.profile as AgentProfileId | undefined,\n naming: opts.naming as NamingStrategy | undefined,\n force: opts.force,\n dryRun: opts.dryRun,\n } satisfies AgentInitOptions,\n process.cwd(),\n ASSETS_DIR,\n );\n },\n );\n\nagentsCommand\n .command(\"sync\")\n .description(\n \"Regenerate all client instruction files from canonical agent definitions\",\n )\n .option(\"--dry-run\", \"Preview what would be generated without writing files\")\n .option(\"--no-openclaw\", \"Skip OpenClaw workspace output\")\n .option(\"--no-copilot\", \"Skip Copilot output\")\n .option(\"--no-claude\", \"Skip Claude output\")\n .option(\"--no-codex\", \"Skip Codex output\")\n .action(\n async (opts: {\n dryRun?: boolean;\n openclaw?: boolean;\n copilot?: boolean;\n claude?: boolean;\n codex?: boolean;\n }) => {\n await runAgentsSync(\n {\n dryRun: opts.dryRun,\n openclaw: opts.openclaw,\n copilot: opts.copilot,\n claude: opts.claude,\n codex: opts.codex,\n } satisfies AgentSyncOptions,\n process.cwd(),\n ASSETS_DIR,\n );\n },\n );\n\nagentsCommand\n .command(\"list\")\n .description(\"Show the current agent roster with assigned names and roles\")\n .action(async () => {\n await runAgentsList(process.cwd());\n });\n\n// Only parse argv when executed directly — not when imported in tests.\n// Use realpathSync to resolve symlinks (e.g. npm global bin → dist/index.js).\nimport { realpathSync } from \"node:fs\";\nif (realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) {\n await program.parseAsync(process.argv);\n}\n\nexport { program };\n","import { select, confirm, input } from \"@inquirer/prompts\";\nimport { join } from \"node:path\";\nimport chalk from \"chalk\";\nimport { copyFile, copyDirectory } from \"../modules/copier.js\";\nimport {\n readManifest,\n writeManifest,\n isValidSubjectRoot,\n ManifestNotFoundError,\n} from \"../modules/manifest.js\";\nimport { getProfile, listProfiles } from \"../modules/registry.js\";\nimport {\n printDryRun,\n printStep,\n printSuccess,\n printSection,\n printInfo,\n printNextStep,\n printWarning,\n} from \"../modules/banner.js\";\nimport { runAgentsInit } from \"../modules/agents.js\";\nimport {\n installPrePushHook,\n installClosedPrWarningHook,\n disablePushUrls,\n describeConfigScope,\n ARCANE_HOOKS_DIR,\n} from \"../modules/push-safety.js\";\nimport { installSecretsPrecommitHook } from \"../modules/secrets-scan.js\";\nimport {\n correctUnbornMasterDefault,\n ensureLocalPullRebase,\n inspectGitRepository,\n} from \"../modules/git.js\";\nimport type {\n ArcaneManifest,\n ContentSensitivity,\n ExternalProvider,\n HubRole,\n InstalledComponent,\n Profile,\n RegistryComponent,\n PushPolicy,\n SpellInitOptions,\n TrackingMode,\n} from \"../types.js\";\n\nconst VALID_PROFILES: Profile[] = [\"full\", \"lite\", \"governance-only\", \"methodology\", \"docs\"];\n\n/** Menu glyph per profile. Falls back to 📋 for any profile not listed. */\nconst PROFILE_ICONS: Partial<Record<Profile, string>> = {\n full: \"🧙\",\n lite: \"⚡\",\n docs: \"📖\",\n};\n\n/** True for the capability-scoped spell components (see registry.ts). */\nfunction isSpellComponent(name: string): boolean {\n return name.startsWith(\"spells-\");\n}\n\n// ─── Category labels for preview ─────────────────────────────────────────────\n\ninterface ComponentGroup {\n icon: string;\n label: string;\n count: number;\n}\n\nfunction categorizeComponents(components: RegistryComponent[]): ComponentGroup[] {\n const groups: ComponentGroup[] = [];\n\n // Spells now arrive as several capability components rather than one\n // monolith, and each carries both client formats of the same spell, so\n // count by file destination rather than by component.\n const spellFiles = components.filter((c) => isSpellComponent(c.name)).flatMap((c) => c.files);\n\n const promptCount = spellFiles.filter((f) => f.startsWith(\".github/prompts/\")).length;\n if (promptCount > 0) {\n groups.push({ icon: \"✨\", label: \"Copilot Spells\", count: promptCount });\n }\n\n const claudeCount = spellFiles.filter((f) => f.startsWith(\".claude/commands/\")).length;\n if (claudeCount > 0) {\n groups.push({ icon: \"⚡\", label: \"Claude Spells\", count: claudeCount });\n }\n\n const governance = components.filter(\n (c) =>\n !isSpellComponent(c.name) &&\n c.name !== \"venture-template\" &&\n c.name !== \"agent-definitions\" &&\n c.files.some((f) => f.startsWith(\".arcane/governance/\")),\n );\n if (governance.length > 0) {\n groups.push({\n icon: \"📋\",\n label: \"Governance Docs\",\n count: governance.reduce((n, c) => n + c.files.length, 0),\n });\n }\n\n const agentDef = components.find((c) => c.name === \"agent-definitions\");\n if (agentDef) {\n groups.push({\n icon: \"🛡️\",\n label: \"Agent Policies\",\n count: agentDef.files.length,\n });\n }\n\n const templates = components.find((c) => c.name === \"venture-template\");\n if (templates) {\n groups.push({\n icon: \"📄\",\n label: \"Templates\",\n count: templates.files.length,\n });\n }\n\n return groups;\n}\n\n/**\n * Builds a hover description string for the profile selection menu.\n * Shows the category breakdown so users know what they're getting.\n */\nfunction buildProfileDescription(components: RegistryComponent[], profile: Profile): string {\n const groups = categorizeComponents(components);\n const parts = groups.map((g) => `${g.icon} ${g.count} ${g.label}`);\n if (profile === \"full\" || profile === \"lite\") {\n // Insert agent roles before governance docs (spells + agents first, then the rest)\n const govIndex = groups.findIndex((g) => g.label === \"Governance Docs\");\n parts.splice(govIndex >= 0 ? govIndex : parts.length, 0, \"🤖 12 Agent Roles\");\n }\n return \"\\n\" + parts.join(\"\\n\");\n}\n\n// ─── Main ─────────────────────────────────────────────────────────────────────\n\n/**\n * Runs the `spell init` command.\n *\n * @param options CLI flags (profile, force, dryRun)\n * @param targetDir Directory to initialize (defaults to cwd in CLI)\n * @param assetsDir Path to the bundled assets root (dist/assets/ in prod, src/assets/ in tests)\n * @param packageVersion Current package version string (passed from CLI entry to avoid require path issues)\n */\nexport async function runInit(\n options: SpellInitOptions,\n targetDir: string,\n assetsDir: string,\n packageVersion: string,\n): Promise<void> {\n // Validate profile option if provided\n if (options.profile && !VALID_PROFILES.includes(options.profile)) {\n throw new Error(\n `Invalid profile \"${options.profile}\". Valid options: ${VALID_PROFILES.join(\", \")}`,\n );\n }\n\n // Check if already initialized\n try {\n await readManifest(targetDir);\n console.log(chalk.hex(\"#a855f7\")(`\\n ✦ Arcane v${packageVersion}\\n`));\n console.log('Already initialized. Run \"spell update\" to update existing files.');\n return;\n } catch (err) {\n if (!(err instanceof ManifestNotFoundError)) throw err;\n // ManifestNotFoundError = not initialized — proceed\n }\n\n console.log(chalk.hex(\"#a855f7\")(`\\n ✦ Arcane v${packageVersion}\\n`));\n\n // ── Git-state checks (EF-05, EF-32) ─────────────────────────────────────\n // Never runs `git init` or creates a commit -- see\n // features/init-git-state-contract/PRD.md's \"Design decision\" section for\n // why that's declined rather than deferred. Only acts where it's provably\n // safe (an unborn repo has no commits to conflict with) or where the\n // operator already explicitly confirmed continuing (uncommitted changes).\n let repoNotFound = false;\n if (!options.dryRun) {\n const gitState = await inspectGitRepository(targetDir);\n\n if (gitState.status === \"not-repository\") {\n repoNotFound = true;\n } else {\n if (gitState.status === \"no-commits\") {\n const correction = await correctUnbornMasterDefault(targetDir);\n if (correction.corrected) {\n printInfo(\n `Repointed the unborn branch from \"${correction.from}\" to \"${correction.to}\" (avoids the Git for Windows default-branch trap).`,\n );\n } else if (correction.blockedReason === \"target-unreadable\") {\n printWarning(\n 'This repo\\'s \"main\" branch ref exists but could not be read (broken ref). Left the current branch alone — ' +\n \"repointing onto an unreadable ref risks attaching your staged work to history Arcane cannot see. \" +\n \"Check `git for-each-ref refs/heads/main` before committing.\",\n );\n }\n }\n\n if (gitState.status === \"ready\" && gitState.uncommittedChanges > 0) {\n printWarning(\n `This repo has ${gitState.uncommittedChanges} uncommitted change${gitState.uncommittedChanges === 1 ? \"\" : \"s\"}.`,\n );\n printInfo(\"Running spell init will add new files to your working tree.\");\n console.log();\n const continueAnyway = await confirm({\n message: \"Continue anyway?\",\n default: true,\n });\n if (!continueAnyway) {\n console.log(\"\\nCancelled. Commit or stash your changes first.\");\n return;\n }\n console.log();\n }\n\n const rebaseResult = await ensureLocalPullRebase(targetDir);\n if (rebaseResult.action === \"explicit-false-preserved\") {\n printWarning(\n \"This repo's pull.rebase is explicitly set to false, but Arcane's governance mandates rebase-and-fast-forward (see .arcane/governance/git-conventions.md). Left as-is since you set it explicitly.\",\n );\n }\n }\n }\n\n // ── Step 1: Resolve profile (prompt if not provided) ───────────────────\n let profile: Profile = options.profile as Profile;\n if (!profile) {\n const profiles = listProfiles();\n profile = (await select({\n message: \"Select an installation profile:\\n\",\n choices: profiles.map((p) => {\n const profileComponents = getProfile(p.id);\n return {\n value: p.id,\n name: `${PROFILE_ICONS[p.id] ?? \"📋\"} ${p.displayName} — ${p.description}`,\n description: buildProfileDescription(profileComponents, p.id),\n };\n }),\n })) as Profile;\n }\n\n // ── Step 2: Resolve components ─────────────────────────────────────────\n const components = getProfile(profile);\n\n // ── Step 3: Preview what will be installed ─────────────────────────────\n const groups = categorizeComponents(components);\n\n console.log();\n printSection(`📦 Profile: ${profile}`);\n console.log();\n\n // Show agent setup as upcoming interactive step\n const hasAgents = profile === \"full\" || profile === \"lite\";\n\n // Build summary parts (same style as hover description)\n const previewParts = groups.map((g) => `${g.icon} ${g.count} ${g.label}`);\n if (hasAgents) {\n // Insert agent roles before governance docs\n const govIndex = groups.findIndex((g) => g.label === \"Governance Docs\");\n previewParts.splice(govIndex >= 0 ? govIndex : previewParts.length, 0, \"🤖 12 Agent Roles\");\n }\n console.log(` ${previewParts.join(\" · \")}`);\n\n console.log();\n\n // ── Step 4: Confirm (skip in non-interactive mode) ─────────────────────\n if (!options.dryRun && !options.profile) {\n const proceed = await confirm({\n message: \"Proceed with installation?\",\n default: true,\n });\n if (!proceed) {\n console.log(\"\\nCancelled.\");\n return;\n }\n }\n\n // ── Step 5: Copy files ─────────────────────────────────────────────────\n const installedComponents: InstalledComponent[] = [];\n let fileCount = 0;\n\n for (const component of components) {\n const installedFiles: string[] = [];\n const fileHashes: Record<string, string> = {};\n\n for (const file of component.files) {\n const srcPath = join(assetsDir, component.sourceOverrides?.[file] ?? file);\n if (options.dryRun) {\n printDryRun(`Would copy: ${file}`);\n } else {\n try {\n fileHashes[file] = await copyFile(srcPath, targetDir, file, { force: options.force });\n } catch (err) {\n // skipExisting components silently skip files that already exist\n if (component.skipExisting && err instanceof Error && err.message.includes(\"already exists\")) {\n continue;\n }\n throw err;\n }\n }\n installedFiles.push(file);\n fileCount++;\n }\n\n for (const dir of component.directories ?? []) {\n const srcDirPath = join(assetsDir, dir);\n if (options.dryRun) {\n printDryRun(`Would copy directory: ${dir}/`);\n } else {\n const copied = await copyDirectory(srcDirPath, targetDir, dir, { force: options.force });\n for (const { path: copiedPath, hash } of copied) {\n installedFiles.push(copiedPath);\n fileHashes[copiedPath] = hash;\n }\n fileCount += copied.length;\n }\n }\n\n if (!options.dryRun) {\n installedComponents.push({\n name: component.name,\n files: installedFiles,\n installedVersion: packageVersion,\n fileHashes,\n });\n }\n }\n\n // Show compact category summary (not 60 individual file paths)\n if (!options.dryRun) {\n for (const group of groups) {\n printStep(`${group.icon} ${group.count} ${group.label}`);\n }\n }\n\n if (options.dryRun) {\n // Show what agent setup would install\n if (hasAgents) {\n const agentFiles = await import(\"node:fs\").then((fsModule) =>\n fsModule.promises.readdir(join(assetsDir, \"agents\")),\n );\n const yamlFiles = agentFiles.filter((f) => f.endsWith(\".yaml\")).sort();\n printDryRun(\"Would run agent setup (interactive):\");\n printDryRun(\"Would write: .arcane/agents.yaml\");\n for (const f of yamlFiles) {\n printDryRun(`Would copy: .arcane/agents/${f}`);\n }\n }\n printDryRun(`Would initialize with profile \"${profile}\" — ${fileCount} files`);\n return;\n }\n\n // ── Step 5a: Hub question ───────────────────────────────────────────────\n // Explicit opt-in only -- never inferred from repo content (a `ventures/`\n // directory can legitimately exist in a consumer repo too, e.g. one this\n // very init run just created via a governance-only profile). Written\n // explicitly either way so a future `spell update` retrofit wizard can\n // tell \"asked and declined\" apart from \"predates this feature\".\n let role: HubRole | undefined;\n if (!options.profile) {\n console.log();\n const isHub = await confirm({\n message: \"Will this repo manage other ventures as a hub? (idea books, spell-manifest promotion, venture registry)\",\n default: false,\n });\n role = isHub ? \"hub\" : \"consumer\";\n }\n\n // ── Step 5b: Tracking-mode question (EF-14) ─────────────────────────────\n // governance-only/methodology profiles have no code-tracking surface --\n // default without asking, even under --profile (deterministic, no prompt\n // to skip). full/lite ask once, interactively only, mirroring the hub\n // question's own gating exactly -- a scripted full/lite install leaves\n // this unset, resolved later by spell update's retrofit wizard.\n let tracking_mode: TrackingMode | undefined;\n let external_provider: ExternalProvider | null | undefined;\n if (profile === \"governance-only\" || profile === \"methodology\" || profile === \"docs\") {\n tracking_mode = \"internal\";\n external_provider = null;\n } else if (!options.profile) {\n console.log();\n tracking_mode = (await select({\n message: \"How will work be tracked in this repo?\",\n choices: [\n { value: \"internal\", name: \"Track work in this repo (TODO.md / PRDs)\" },\n { value: \"external\", name: \"Track work in an external tracker (Azure DevOps / GitHub / Jira / other)\" },\n ],\n })) as TrackingMode;\n if (tracking_mode === \"external\") {\n external_provider = (await select({\n message: \"Which external tracker?\",\n choices: [\n { value: \"ado\", name: \"Azure DevOps\" },\n { value: \"github\", name: \"GitHub Issues\" },\n { value: \"jira\", name: \"Jira\" },\n { value: \"other\", name: \"Other\" },\n ],\n })) as ExternalProvider;\n } else {\n external_provider = null;\n }\n }\n\n // ── Step 5c: Subject shape (EF-07) ──────────────────────────────────────\n // Asked for the docs profile only. Other profiles describe code or a\n // venture portfolio, where \"what is this repo about\" is already answered by\n // business_root or by the code itself; a docs/records repo is the case where\n // the repository IS one subject and nothing currently expresses that.\n // Interactive only, like every other manifest question.\n let subject_root: string | null | undefined;\n if (profile === \"docs\" && !options.profile) {\n console.log();\n const shape = await select({\n message: \"What does this repository hold?\",\n choices: [\n {\n value: \"root\",\n name: \"One subject, at the repository root (documents sit alongside Arcane's files)\",\n },\n { value: \"subdir\", name: \"One subject, in its own directory\" },\n { value: \"portfolio\", name: \"Several subjects or ventures (decide per-document later)\" },\n ],\n });\n if (shape === \"root\") {\n // \".\" is deliberate, not a placeholder: it lets an existing archive come\n // under governance without being restructured first (EF-07 / MH-02).\n subject_root = \".\";\n } else if (shape === \"subdir\") {\n const answer = await input({\n message: \"Directory holding the subject's documents:\",\n default: \"docs\",\n validate: (v) =>\n isValidSubjectRoot(v.trim() || \"docs\") ||\n \"Must be a relative path inside the repository (no leading /, drive letter, or ..).\",\n });\n subject_root = answer.trim() || \"docs\";\n }\n else if (shape === \"portfolio\") {\n // Explicit null, not unset: records that the question was asked and\n // answered, so spell update's retrofit doesn't put it again every run.\n subject_root = null;\n }\n }\n\n // ── Step 5d: Content sensitivity (EF-12) ────────────────────────────────\n // Asked on every interactive install, not just docs: a code repo can hold\n // sensitive records too. Declared once for the whole repository -- per-file\n // detection is unreliable for general documents, which is why the docs-mode\n // PRD rejects scanning as a primary mechanism.\n let content_sensitivity: ContentSensitivity | undefined;\n if (!options.profile) {\n console.log();\n content_sensitivity = (await select({\n message: \"How should agents treat this repository's contents?\",\n choices: [\n { value: \"standard\", name: \"Standard — agents may quote contents in journals and decisions\" },\n {\n value: \"sensitive\",\n name: \"Sensitive — agents reference documents by path, never transcribe them\",\n },\n ],\n default: \"standard\",\n })) as ContentSensitivity;\n }\n\n // ── Step 5e: Push policy (EF-09) ────────────────────────────────────────\n // Default \"open\" — strictly additive, so every existing repository and every\n // scripted install behaves exactly as before. Asked interactively only.\n let push_policy: PushPolicy | undefined;\n if (!options.profile) {\n console.log();\n push_policy = (await select({\n message: \"Should this repository be allowed to push to a remote?\",\n choices: [\n { value: \"open\", name: \"Yes — normal repository\" },\n { value: \"guarded\", name: \"Sensitive, but keep push working — remind me instead\" },\n {\n value: \"blocked\",\n name: \"No — block pushes (a pre-push hook plus a disabled push URL)\",\n },\n ],\n default: \"open\",\n })) as PushPolicy;\n }\n\n // ── Step 6: Write manifest ─────────────────────────────────────────────\n const manifest: ArcaneManifest = {\n version: packageVersion,\n profile,\n installedAt: new Date().toISOString(),\n components: installedComponents,\n ...(role ? { role } : {}),\n ...(tracking_mode ? { tracking_mode, external_provider } : {}),\n ...(subject_root !== undefined ? { subject_root } : {}),\n ...(content_sensitivity ? { content_sensitivity } : {}),\n ...(push_policy ? { push_policy } : {}),\n };\n await writeManifest(targetDir, manifest);\n\n printSuccess(`Initialized with profile \"${profile}\" — ${fileCount} files installed`);\n\n // ── Push-safety controls (EF-09 R2/R3/R4/R7) ────────────────────────────\n // Wrapped: a failure here must not surface as a raw stack trace after\n // \"Initialized successfully\", leaving a manifest that says \"blocked\" while\n // the operator believes they are protected.\n if (push_policy === \"blocked\" || push_policy === \"guarded\") {\n try {\n if (push_policy === \"blocked\") {\n const hook = await installPrePushHook(targetDir);\n if (hook.status === \"refused-unreadable-config\") {\n // Fail closed: we could not determine whether another hook manager\n // owns core.hooksPath, and installing on a guess could disable it.\n printWarning(\n \"Did not install the pre-push hook: git could not report the current core.hooksPath \" +\n \"(unreadable config, or a git too old for `--show-scope`). Installing without knowing \" +\n \"whether another hook manager owns that setting could silently disable it. Fix the \" +\n \"config and run `spell doctor`.\",\n );\n } else if (hook.status === \"refused-default-hooks\") {\n // Same harm as a foreign core.hooksPath, reached by the route the R7\n // guard wasn't watching: this repository's hooks live in git's\n // default directory and have no config key to collide with, so\n // taking the slot would switch every one of them off silently.\n printWarning(\n `Did not install the pre-push hook: this repository has hooks in git's default ` +\n `directory (${hook.hooks.join(\", \")}). Setting core.hooksPath would silently stop ` +\n `them running. Move them under \\`${ARCANE_HOOKS_DIR}\\` yourself and re-run, or add ` +\n \"the push guard to your existing pre-push hook.\",\n );\n } else if (hook.status === \"refused-foreign-hooks-path\") {\n // R7: core.hooksPath is one exclusive slot, at local OR global\n // scope, so pointing it at Arcane would silently disable whatever\n // hook manager already owns it.\n printWarning(\n `Did not install the pre-push hook: core.hooksPath is already \"${hook.existing}\" ` +\n `(${describeConfigScope(hook.scope)}), so another hook manager owns it. Overwriting ` +\n \"would silently disable those hooks. Chain an Arcane pre-push guard into that \" +\n \"directory yourself, or unset core.hooksPath first.\",\n );\n } else {\n printInfo(\"Installed a pre-push hook that blocks pushes from this repository.\");\n }\n\n const urls = await disablePushUrls(targetDir);\n const unprotected = urls.filter((u) => u.status === \"failed\");\n if (unprotected.length > 0) {\n // Never let a partial application read as a full one.\n printWarning(\n `Could not disable the push URL for: ${unprotected\n .map((u) => `${u.remote} (${u.reason ?? \"unknown error\"})`)\n .join(\"; \")}. Those remotes are still pushable with \\`--no-verify\\`. ` +\n \"Run `spell doctor` — it lists exactly which remotes are still live.\",\n );\n }\n if (urls.length === 0) {\n // Be precise: nothing is protecting a remote added later, because\n // this only disables remotes that exist right now. Claiming\n // otherwise would be exactly the false confidence ARC-034 warns of.\n printWarning(\n \"No remote is configured, so only the pre-push hook is active. A remote added later \" +\n \"will NOT have its push URL disabled automatically, and a `--no-verify` push to it \" +\n \"would succeed. Run `spell doctor` after adding one — it reports this gap.\",\n );\n } else {\n const covered = urls.filter((u) => u.status !== \"failed\").map((u) => u.remote);\n if (covered.length > 0) {\n printInfo(`Disabled the push URL for: ${covered.join(\", \")} (fetch still works).`);\n }\n }\n printInfo(\"Run `spell unblock-push` from a terminal to undo this.\");\n } else {\n printInfo(\n \"Marked as push-guarded. No technical control was installed — check the remote is the \" +\n \"one you intend before pushing. `spell doctor` will keep reminding you.\",\n );\n }\n } catch (err) {\n printWarning(\n `Could not fully apply push-safety controls: ${err instanceof Error ? err.message : String(err)}. ` +\n `The manifest records push_policy: \"${push_policy}\", but this repository may not actually be ` +\n \"protected. Run `spell doctor` to see exactly what is and isn't in place.\",\n );\n }\n }\n\n // ── Closed-PR push warning (ARC-035 decision 4) ─────────────────────────\n // Every tier except \"blocked\" gets this: a \"blocked\" repo already refuses\n // every push outright and has no use for a warning about which PR it\n // would have gone to (installing here would also silently downgrade that\n // stronger control, since both share the \"pre-push\" hook slot). Wrapped\n // the same way as the blocks above -- a failure here must not surface as\n // a raw stack trace after \"Initialized successfully\".\n if (push_policy !== \"blocked\") {\n try {\n const hook = await installClosedPrWarningHook(targetDir);\n if (hook.status === \"installed\") {\n printInfo(\"Installed a pre-push hook that warns when the current branch's PR is already closed or merged.\");\n }\n // Other outcomes (refused-*, already-ours) mirror the blocking hook's\n // own install path and are silent here on purpose: this hook is a\n // convenience warning, not a security control, so a refusal doesn't\n // leave the repository in a worse-than-before state the way a silently\n // skipped block would -- `spell doctor` still surfaces the refusal\n // reason for the shared hooks-path collision case.\n } catch {\n // Never let this convenience warning's own failure surface as a raw\n // stack trace after \"Initialized successfully\" -- it is strictly\n // additive, so a failure here means the repo is exactly as protected\n // as it was before this block ran, not less.\n }\n }\n\n // ── Secrets pre-commit hook (ARC-037 decision 2) ────────────────────────\n // Deliberately push_policy-independent: every profile gets this, since\n // credential leakage is a risk regardless of whether history may reach a\n // remote. Mandatory, not an interactive question -- see secrets-scan.ts's\n // own reasoning for why. Wrapped the same way as the push-safety block\n // above: a failure here must not surface as a raw stack trace after\n // \"Initialized successfully\".\n try {\n const hook = await installSecretsPrecommitHook(targetDir);\n if (hook.status === \"installed\") {\n printInfo(\"Installed a pre-commit hook that scans staged content for leaked credentials.\");\n } else if (hook.status === \"refused-unreadable-config\") {\n printWarning(\n \"Did not install the secrets pre-commit hook: git could not report the current \" +\n \"core.hooksPath (unreadable config, or a git too old for `--show-scope`).\",\n );\n } else if (hook.status === \"refused-default-hooks\") {\n printWarning(\n `Did not install the secrets pre-commit hook: this repository has hooks in git's default ` +\n `directory (${hook.hooks.join(\", \")}). Setting core.hooksPath would silently stop them ` +\n `running. Move them under \\`${ARCANE_HOOKS_DIR}\\` yourself and re-run.`,\n );\n } else if (hook.status === \"refused-foreign-hooks-path\") {\n printWarning(\n `Did not install the secrets pre-commit hook: core.hooksPath is already \"${hook.existing}\" ` +\n `(${describeConfigScope(hook.scope)}), so another hook manager owns it.`,\n );\n }\n // \"already-ours\": nothing to report, matches the prior install exactly.\n } catch (err) {\n printWarning(\n `Could not install the secrets pre-commit hook: ${err instanceof Error ? err.message : String(err)}. ` +\n \"Run `spell doctor --leaks` directly to scan on demand instead.\",\n );\n }\n\n // ── Step 7: Offer agent setup (for full and lite profiles) ─────────────\n let agentsConfigured = false;\n if (hasAgents && !options.profile) {\n console.log();\n const setupAgents = await confirm({\n message: \"🤖 Set up your agent team? (names, roles, AI tool configs)\",\n default: true,\n });\n\n if (setupAgents) {\n await runAgentsInit({}, targetDir, assetsDir);\n agentsConfigured = true;\n }\n }\n\n // ── Step 8: Print next steps ───────────────────────────────────────────\n console.log();\n printSection(\"🚀 Next steps\");\n console.log();\n let step = 1;\n\n if (!agentsConfigured && profile !== \"governance-only\") {\n printNextStep(step++, \"Run `spell agents init` to set up your agent team\");\n }\n if (agentsConfigured) {\n printNextStep(\n step++,\n \"Edit .arcane/agents.yaml to customize roles → `spell agents sync` to regenerate AI tool configs\",\n );\n }\n if (profile !== \"governance-only\") {\n printNextStep(\n step++,\n \"Review .arcane/governance/ docs and customize for your project\",\n );\n }\n if (repoNotFound) {\n printNextStep(\n step++,\n 'Initialize Git for this project: `git init -b main` (avoids defaulting to \"master\" on systems where that\\'s the system default)',\n );\n }\n printNextStep(\n step++,\n \"Commit the new files: git add .arcane .github .claude AGENTS.md CLAUDE.md .arcane.json\",\n );\n console.log();\n}\n","import {\n mkdir,\n access,\n readdir,\n readFile,\n writeFile,\n} from \"node:fs/promises\";\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\n\n/** SHA-256 hex digest of a file's content (ARC-038 decision 1). */\nexport async function hashFile(filePath: string): Promise<string> {\n const content = await readFile(filePath);\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\n/**\n * Validates that relativePath stays within targetDir.\n * Throws if the resolved path escapes the target directory boundary.\n */\nexport function validateTargetPath(\n targetDir: string,\n relativePath: string,\n): void {\n const resolvedBase = path.resolve(targetDir);\n const resolvedFull = path.resolve(targetDir, relativePath);\n\n if (\n resolvedFull !== resolvedBase &&\n !resolvedFull.startsWith(resolvedBase + path.sep)\n ) {\n throw new Error(\n `Path traversal detected: \"${relativePath}\" escapes target directory \"${targetDir}\"`,\n );\n }\n}\n\n/**\n * Creates a directory and all parent directories if they don't exist.\n */\nexport async function ensureDir(dirPath: string): Promise<void> {\n await mkdir(dirPath, { recursive: true });\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Copies srcPath into targetDir at relativePath.\n * Validates path traversal before any I/O.\n * Throws if the destination already exists and opts.force is not set.\n * Returns the copied content's SHA-256 hex digest (ARC-038 decision 1) --\n * read once into memory and reused for both the hash and the write, rather\n * than hashing srcPath and then separately copying it: reading every source\n * file twice measurably slowed a full `spell init` (~90 files) once every\n * file started being hashed, enough to push some CI/test runs over their\n * timeout under contention. One read, one write; no redundant I/O.\n */\nexport async function copyFile(\n srcPath: string,\n targetDir: string,\n relativePath: string,\n opts: { force?: boolean } = {},\n): Promise<string> {\n validateTargetPath(targetDir, relativePath);\n\n const destPath = path.resolve(targetDir, relativePath);\n await ensureDir(path.dirname(destPath));\n\n if (!opts.force && (await fileExists(destPath))) {\n throw new Error(\n `Destination already exists: \"${relativePath}\". Use --force to overwrite.`,\n );\n }\n\n const content = await readFile(srcPath);\n const hash = createHash(\"sha256\").update(content).digest(\"hex\");\n await writeFile(destPath, content);\n return hash;\n}\n\nexport interface CopiedFile {\n path: string;\n hash: string;\n}\n\n/**\n * Recursively copies a directory from srcDir to targetDir/relativeDir.\n * Validates the target path to prevent traversal attacks.\n * Returns each copied file's relative path and content hash (ARC-038\n * decision 1), for manifest tracking.\n */\nexport async function copyDirectory(\n srcDir: string,\n targetDir: string,\n relativeDir: string,\n opts: { force?: boolean } = {},\n): Promise<CopiedFile[]> {\n validateTargetPath(targetDir, relativeDir);\n\n const copiedFiles: CopiedFile[] = [];\n const entries = await readdir(srcDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcEntryPath = path.join(srcDir, entry.name);\n const relEntryPath = `${relativeDir}/${entry.name}`;\n\n if (entry.isDirectory()) {\n const subFiles = await copyDirectory(srcEntryPath, targetDir, relEntryPath, opts);\n copiedFiles.push(...subFiles);\n } else {\n const hash = await copyFile(srcEntryPath, targetDir, relEntryPath, opts);\n copiedFiles.push({ path: relEntryPath, hash });\n }\n }\n\n return copiedFiles;\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type {\n ArcaneManifest,\n ContentSensitivity,\n ExternalProvider,\n InstalledComponent,\n Profile,\n PushPolicy,\n TrackingMode,\n} from \"../types.js\";\n\nexport class ManifestNotFoundError extends Error {\n constructor(manifestPath: string) {\n super(`Manifest not found at \"${manifestPath}\". Run \"spell init\" first.`);\n this.name = \"ManifestNotFoundError\";\n }\n}\n\nexport class ManifestCorruptError extends Error {\n constructor(manifestPath: string) {\n super(\n `Manifest at \"${manifestPath}\" contains invalid JSON. It may be corrupted.`,\n );\n this.name = \"ManifestCorruptError\";\n }\n}\n\n/**\n * Distinct from ManifestCorruptError: the file IS valid JSON, but a field\n * holds a value outside its supported enum (EF-14 point 2 -- \"reject\n * unsupported values rather than silently treating them as a provider\").\n */\nexport class ManifestInvalidFieldError extends Error {\n constructor(manifestPath: string, field: string, value: unknown) {\n super(\n `Manifest at \"${manifestPath}\" has an unsupported value for \"${field}\": ${JSON.stringify(value)}.`,\n );\n this.name = \"ManifestInvalidFieldError\";\n }\n}\n\nconst MANIFEST_FILE = \".arcane.json\";\n\nconst VALID_TRACKING_MODES: TrackingMode[] = [\"internal\", \"external\"];\nconst VALID_EXTERNAL_PROVIDERS: ExternalProvider[] = [\"ado\", \"github\", \"jira\", \"other\"];\nconst VALID_CONTENT_SENSITIVITY: ContentSensitivity[] = [\"standard\", \"sensitive\"];\nconst VALID_PUSH_POLICIES: PushPolicy[] = [\"open\", \"guarded\", \"blocked\"];\n\n/**\n * `subject_root` is a free-form relative path, so it gets shape rules rather\n * than an enum. It is resolved against the repository root and handed to\n * spells, so a value that escapes the repo (absolute, or containing `..`)\n * would point agents at files outside the project entirely. \".\" is explicitly\n * legal: it means the repository root IS the subject tree (EF-07).\n */\n/**\n * True when a subject_root value is safe to store. Exported so the interactive\n * prompt can reject a bad value in place rather than writing it and failing on\n * every subsequent command until the operator hand-edits .arcane.json.\n */\nexport function isValidSubjectRoot(value: string): boolean {\n const invalid =\n value.trim() === \"\" ||\n path.isAbsolute(value) ||\n // Windows drive-relative (\"C:docs\") and UNC-ish values also escape.\n /^[a-zA-Z]:/.test(value) ||\n value.startsWith(\"\\\\\\\\\") ||\n value.startsWith(\"\\\\\") ||\n value.split(/[\\\\/]/).includes(\"..\") ||\n // A stored subject_root is interpolated into agent prompts downstream, so\n // keep it a single path-shaped token rather than a multi-line payload.\n /[\\r\\n\\0]/.test(value);\n return !invalid;\n}\n\nfunction validateSubjectRoot(value: string, filePath: string): void {\n if (!isValidSubjectRoot(value)) {\n throw new ManifestInvalidFieldError(filePath, \"subject_root\", value);\n }\n}\n\n/**\n * True when a secretsScanExcludePrefixes value is safe to store: an array of\n * non-empty strings. Deliberately looser than `isValidSubjectRoot` -- a scan\n * exclusion is a path *prefix* match, not a path handed to spells, so it has\n * no traversal-escape risk to guard against; it only needs to be a real,\n * matchable string.\n */\nexport function isValidSecretsScanExcludePrefixes(value: unknown): value is string[] {\n return (\n Array.isArray(value) &&\n value.every((entry) => typeof entry === \"string\" && entry.length > 0)\n );\n}\n\nfunction validateSecretsScanExcludePrefixes(value: unknown, filePath: string): void {\n if (!isValidSecretsScanExcludePrefixes(value)) {\n throw new ManifestInvalidFieldError(filePath, \"secretsScanExcludePrefixes\", value);\n }\n}\n\nfunction manifestPath(targetDir: string): string {\n return path.join(targetDir, MANIFEST_FILE);\n}\n\nfunction validateTrackingFields(manifest: ArcaneManifest, filePath: string): void {\n if (\n manifest.tracking_mode !== undefined &&\n !VALID_TRACKING_MODES.includes(manifest.tracking_mode)\n ) {\n throw new ManifestInvalidFieldError(filePath, \"tracking_mode\", manifest.tracking_mode);\n }\n if (\n manifest.external_provider !== undefined &&\n manifest.external_provider !== null &&\n !VALID_EXTERNAL_PROVIDERS.includes(manifest.external_provider)\n ) {\n throw new ManifestInvalidFieldError(filePath, \"external_provider\", manifest.external_provider);\n }\n if (\n manifest.content_sensitivity !== undefined &&\n !VALID_CONTENT_SENSITIVITY.includes(manifest.content_sensitivity)\n ) {\n throw new ManifestInvalidFieldError(\n filePath,\n \"content_sensitivity\",\n manifest.content_sensitivity,\n );\n }\n if (\n manifest.push_policy !== undefined &&\n !VALID_PUSH_POLICIES.includes(manifest.push_policy)\n ) {\n throw new ManifestInvalidFieldError(filePath, \"push_policy\", manifest.push_policy);\n }\n if (manifest.subject_root !== undefined && manifest.subject_root !== null) {\n if (typeof manifest.subject_root !== \"string\") {\n throw new ManifestInvalidFieldError(filePath, \"subject_root\", manifest.subject_root);\n }\n validateSubjectRoot(manifest.subject_root, filePath);\n }\n if (manifest.secretsScanExcludePrefixes !== undefined) {\n validateSecretsScanExcludePrefixes(manifest.secretsScanExcludePrefixes, filePath);\n }\n}\n\n/**\n * Reads .arcane.json from targetDir.\n * Throws ManifestNotFoundError if the file is missing.\n * Throws ManifestCorruptError if the file contains invalid JSON.\n * Throws ManifestInvalidFieldError if tracking_mode/external_provider hold\n * an unsupported value.\n */\nexport async function readManifest(targetDir: string): Promise<ArcaneManifest> {\n const filePath = manifestPath(targetDir);\n let content: string;\n\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n throw new ManifestNotFoundError(filePath);\n }\n throw err;\n }\n\n let manifest: ArcaneManifest;\n try {\n manifest = JSON.parse(content) as ArcaneManifest;\n } catch {\n throw new ManifestCorruptError(filePath);\n }\n\n validateTrackingFields(manifest, filePath);\n return manifest;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Resolves the effective `secretsScanExcludePrefixes` list for a target\n * directory (ARC-037). Self-hosted-aware: falls back to reading\n * src/assets/.arcane.json when there is no root .arcane.json, mirroring\n * doctor.ts's own self-hosted-manifest detection (this repo's own case --\n * it ships no root manifest, only the self-hosted marker file). Shared by\n * the build-time scan (scripts/copy-assets.ts) and `spell doctor --leaks`,\n * so a repository configures its exclusions in exactly one place regardless\n * of which path runs the scan.\n */\nexport async function resolveSecretsScanExcludePrefixes(targetDir: string): Promise<string[]> {\n try {\n const manifest = await readManifest(targetDir);\n return manifest.secretsScanExcludePrefixes ?? [];\n } catch {\n // No root manifest -- fall through to the self-hosted case below.\n }\n\n try {\n const raw = await readFile(path.join(targetDir, \"src\", \"assets\", \".arcane.json\"), \"utf-8\");\n const parsed: unknown = JSON.parse(raw);\n if (isRecord(parsed) && parsed[\"selfHosted\"] === true && parsed[\"tracking_mode\"] === \"internal\") {\n const prefixes = parsed[\"secretsScanExcludePrefixes\"];\n if (isValidSecretsScanExcludePrefixes(prefixes)) return prefixes;\n }\n } catch {\n // No self-hosted manifest either -- scan with no exclusions.\n }\n\n return [];\n}\n\n/**\n * Writes the manifest to .arcane.json in targetDir with 2-space indentation.\n */\nexport async function writeManifest(\n targetDir: string,\n manifest: ArcaneManifest,\n): Promise<void> {\n const filePath = manifestPath(targetDir);\n await writeFile(filePath, JSON.stringify(manifest, null, 2), \"utf-8\");\n}\n\n/**\n * Creates a new .arcane.json in targetDir with an empty components array.\n * Returns the created manifest.\n */\nexport async function createManifest(\n targetDir: string,\n profile: Profile,\n version: string,\n): Promise<ArcaneManifest> {\n const manifest: ArcaneManifest = {\n version,\n profile,\n installedAt: new Date().toISOString(),\n components: [],\n };\n await writeManifest(targetDir, manifest);\n return manifest;\n}\n\n/**\n * Pure function — returns a new manifest with the component appended.\n * Does not write to disk.\n */\nexport function addComponent(\n manifest: ArcaneManifest,\n component: InstalledComponent,\n): ArcaneManifest {\n return {\n ...manifest,\n components: [...manifest.components, component],\n };\n}\n\n/**\n * Pure function — returns a new manifest with the named component removed.\n * Does not write to disk.\n */\nexport function removeComponent(\n manifest: ArcaneManifest,\n name: string,\n): ArcaneManifest {\n return {\n ...manifest,\n components: manifest.components.filter((c) => c.name !== name),\n };\n}\n\n/**\n * Returns true if a component with the given name exists in the manifest.\n */\nexport function hasComponent(manifest: ArcaneManifest, name: string): boolean {\n return manifest.components.some((c) => c.name === name);\n}\n","/**\n * Profile configuration — the canonical source of truth for Arcane profiles.\n *\n * A profile bundles a curated set of components for a common use case.\n * Changing which components an EXISTING profile bundles requires only editing\n * this file. Adding a NEW profile id additionally touches the `Profile` union\n * in types.ts, `VALID_PROFILES` and the presentation/gating branches in\n * commands/init.ts, the --profile help string in index.ts, and the retrofit\n * mirror in modules/hub.ts -- the registry itself needs no change.\n *\n * The special value \"*\" for `components` means \"all registered components\"\n * and is expanded by the registry at runtime.\n */\n\nimport type { Profile } from \"../types.js\";\n\nexport interface ProfileConfig {\n id: Profile;\n displayName: string;\n description: string;\n /**\n * Component names included in this profile.\n * Use the special value \"*\" to mean \"all registered components\" (full install).\n */\n components: string[] | \"*\";\n}\n\nexport const PROFILE_CONFIGS: ProfileConfig[] = [\n {\n id: \"full\",\n displayName: \"Full Suite\",\n description: \"All components — spells, governance, agents, templates\",\n components: \"*\",\n },\n {\n id: \"lite\",\n displayName: \"Essentials\",\n description: \"Spells + core governance — fast start\",\n components: [\n \"spells-session\",\n \"spells-capture\",\n \"spells-delivery\",\n \"spells-review\",\n \"spells-planning\",\n \"spells-build\",\n \"spells-venture\",\n \"spells-meta\",\n \"agent-output-instructions\",\n \"git-conventions\",\n \"testing-standards\",\n \"framework-decisions\",\n \"session-continuity\",\n ],\n },\n {\n id: \"methodology\",\n displayName: \"Methodology Suite\",\n description: \"Spells + governance — full methodology without security/infra docs\",\n components: [\n \"spells-session\",\n \"spells-capture\",\n \"spells-delivery\",\n \"spells-review\",\n \"spells-planning\",\n \"spells-build\",\n \"spells-venture\",\n \"spells-meta\",\n \"agent-output-instructions\",\n \"git-conventions\",\n \"testing-standards\",\n \"framework-decisions\",\n \"session-continuity\",\n \"decision-documentation-standard\",\n \"agent-work-queue-model\",\n \"development-methodology\",\n \"spell-authoring-standards\",\n ],\n },\n {\n id: \"docs\",\n displayName: \"Docs / Records\",\n description: \"Documentation and records repositories — no code, test, or deployment workflows\",\n components: [\n // Deliberate exclusions, per docs-mode PRD MH-01: \"spells-build\"\n // (implementation, tests, stack experts, release, deployment, PRD\n // enchantment, asset tooling), \"spells-review\" (adversarial CODE review\n // -- its own workflow validates test coverage against source, which a\n // docs repo has neither of), and \"spells-venture\" (hub-only).\n //\n // MH-01 requires every retained spell to complete its core workflow\n // without source code, tests, CI, or an external tracker. Asserted --\n // exclusions included, which MH-01 requires explicitly -- in\n // test/docs-profile-registry-split.test.ts.\n \"spells-session\",\n \"spells-capture\",\n \"spells-delivery\",\n \"spells-planning\",\n \"spells-meta\",\n \"spells-docs\",\n \"docs-baseline\",\n \"records-conventions\",\n \"agent-output-instructions\",\n \"git-conventions\",\n // Four retained docs spells link to agent-policies; it carries no code\n // implication, so shipping it closes a dangling reference cheaply.\n \"agent-policies\",\n \"framework-decisions\",\n \"session-continuity\",\n \"decision-documentation-standard\",\n \"agent-work-queue-model\",\n \"development-methodology\",\n \"naming-conventions\",\n \"universal-agent-rules\",\n \"spell-authoring-standards\",\n ],\n },\n {\n id: \"governance-only\",\n displayName: \"Governance Only\",\n description: \"Standards docs only — no spells or agents\",\n components: [\n \"agent-output-instructions\",\n \"git-conventions\",\n \"testing-standards\",\n \"framework-decisions\",\n \"decision-documentation-standard\",\n \"agent-work-queue-model\",\n \"naming-conventions\",\n \"agent-policies\",\n \"threat-model\",\n \"hardening-checklist\",\n \"authentication-strategy\",\n \"new-business-setup\",\n \"agent-approved-paths\",\n \"portable-bootstrap\",\n \"development-methodology\",\n \"cicd-standards\",\n \"poc-management-pattern\",\n \"product-excellence-standards\",\n \"rca-process-standard\",\n \"universal-agent-rules\",\n \"spell-authoring-standards\",\n \"external-verification-standards\",\n \"web-discoverability-standards\",\n \"mobile-release-standards\",\n \"compliance-standards\",\n ],\n },\n];\n","import type { Profile, RegistryComponent, ProfileDefinition } from \"../types.js\";\nimport { PROFILE_CONFIGS } from \"../config/profiles.js\";\n\nexport class ComponentNotFoundError extends Error {\n constructor(name: string, available: string[]) {\n super(\n `Component \"${name}\" not found. Available components: ${available.join(\", \")}`,\n );\n this.name = \"ComponentNotFoundError\";\n }\n}\n\n// ─── Component definitions ───────────────────────────────────────────────────\n// File paths are relative to src/assets/ (source) / dist/assets/ (published).\n\nconst COMPONENTS: RegistryComponent[] = [\n // Governance\n {\n name: \"git-conventions\",\n description: \"Git branching, commit message, and PR conventions\",\n files: [\".arcane/governance/git-conventions.md\"],\n },\n {\n name: \"testing-standards\",\n description: \"Testing framework selection, coverage thresholds, and CI gates\",\n files: [\".arcane/governance/testing-standards.md\"],\n },\n {\n name: \"framework-decisions\",\n description: \"Offline reference for legacy framework ADR citations\",\n files: [\".arcane/governance/framework-decisions.md\"],\n },\n {\n name: \"decision-documentation-standard\",\n description: \"ADR format and decision-logging conventions\",\n files: [\".arcane/governance/decision-documentation-standard.md\"],\n },\n {\n name: \"agent-work-queue-model\",\n description: \"Work queue model for AI agent task assignment and tracking\",\n files: [\".arcane/governance/agent-work-queue-model.md\"],\n },\n {\n name: \"naming-conventions\",\n description: \"Machine, agent, and service naming rules (three-tier model)\",\n files: [\".arcane/governance/naming-conventions.md\"],\n },\n {\n name: \"agent-policies\",\n description: \"Agent autonomy levels, power levels, and operational constraints\",\n files: [\".arcane/governance/agent-policies.md\"],\n },\n {\n name: \"threat-model\",\n description: \"Security threat model covering STRIDE categories and mitigations\",\n files: [\".arcane/governance/threat-model.md\"],\n },\n {\n name: \"hardening-checklist\",\n description: \"Production hardening checklist for infrastructure and agents\",\n files: [\".arcane/governance/hardening-checklist.md\"],\n },\n {\n name: \"authentication-strategy\",\n description: \"Authentication patterns, token management, and identity strategy\",\n files: [\".arcane/governance/authentication-strategy.md\"],\n },\n {\n name: \"new-business-setup\",\n description: \"Step-by-step playbook for bootstrapping a new business unit\",\n files: [\".arcane/governance/new-business-setup.md\"],\n },\n {\n name: \"agent-approved-paths\",\n description: \"Approved repository paths and access boundaries for agents\",\n files: [\".arcane/governance/agent-approved-paths.md\"],\n },\n {\n name: \"portable-bootstrap\",\n description: \"Portable AI context bootstrap for onboarding new AI clients\",\n files: [\".arcane/governance/portable-bootstrap.md\"],\n },\n // Governance — methodology\n {\n name: \"development-methodology\",\n description: \"Spell Loop development methodology\",\n files: [\".arcane/governance/development-methodology.md\"],\n },\n {\n name: \"cicd-standards\",\n description: \"CI/CD pipeline standards and quality gates\",\n files: [\".arcane/governance/cicd-standards.md\"],\n },\n {\n name: \"poc-management-pattern\",\n description: \"POC lifecycle management pattern\",\n files: [\".arcane/governance/poc-management-pattern.md\"],\n },\n {\n name: \"product-excellence-standards\",\n description: \"Product quality gate standards and spell-enchant requirements\",\n files: [\".arcane/governance/product-excellence-standards.md\"],\n },\n {\n name: \"spell-authoring-standards\",\n description: \"Spell Quality Rubric — the authoring bar for spell prompts (8 dimensions)\",\n files: [\".arcane/governance/spell-authoring-standards.md\"],\n },\n {\n name: \"rca-process-standard\",\n description: \"Root cause analysis process standard\",\n files: [\".arcane/governance/rca-process-standard.md\"],\n },\n {\n name: \"universal-agent-rules\",\n description: \"Universal rules for all AI agents operating in any Arcane-managed repo\",\n files: [\".arcane/governance/universal-agent-rules.md\"],\n },\n // VS Code Copilot instructions — installed to .github/instructions/\n {\n name: \"agent-output-instructions\",\n description: \"Copilot enforcement rules: PR link format, merge strategy, and branch naming\",\n files: [\".github/instructions/agent-output.instructions.md\"],\n },\n // Repository baseline files (EF-10 + EF-17). skipExisting: these are\n // user-owned once written -- a repo with its own .gitattributes has an\n // intentional policy Arcane must not overwrite. Sources are stored under a\n // non-dotfile path and mapped via sourceOverrides; see RegistryComponent.\n {\n name: \"docs-baseline\",\n description: \"Line-ending and binary-format baseline for document repositories (.gitattributes/.gitignore)\",\n files: [\".gitattributes\", \".gitignore\"],\n sourceOverrides: {\n \".gitattributes\": \"docs-baseline/gitattributes\",\n \".gitignore\": \"docs-baseline/gitignore\",\n },\n skipExisting: true,\n initOnly: true,\n },\n // Optional MCP config scaffold (BC-22/I12). skipExisting: a repo's own\n // .mcp.json is user-owned server config Arcane must never overwrite.\n // Not initOnly -- useful to retrofit via `spell add` on an existing repo too.\n {\n name: \"mcp-config-template\",\n description: \"Example .mcp.json with a per-server timeout, companion to the MCP fail-fast rule\",\n files: [\".mcp.json\"],\n skipExisting: true,\n },\n {\n name: \"records-conventions\",\n description: \"Supersession, tombstone, and retention conventions for records repositories\",\n files: [\".arcane/governance/records-conventions.md\"],\n },\n {\n name: \"external-verification-standards\",\n description: \"Rules for confirming a write took effect in a system you don't control — consoles, pipelines, DNS, deployed endpoints\",\n files: [\".arcane/governance/external-verification-standards.md\"],\n },\n {\n name: \"web-discoverability-standards\",\n description: \"Search-engine and AI-assistant discoverability rules for web properties\",\n files: [\".arcane/governance/web-discoverability-standards.md\"],\n },\n {\n name: \"mobile-release-standards\",\n description: \"Durable App Store / Google Play console and release-track facts consumed by spell-eas-store-deploy\",\n files: [\".arcane/governance/mobile-release-standards.md\"],\n },\n {\n name: \"compliance-standards\",\n description: \"GDPR/CCPA/SOC 2/HIPAA obligations and a tiered applicability guide, consumed by spell-compliance\",\n files: [\".arcane/governance/compliance-standards.md\"],\n },\n // ─── Spells ────────────────────────────────────────────────────────────────\n // Split from the former monolithic `spell-prompts` + `claude-commands` pair\n // so a profile can select spells by capability (see ARC-0NN). Grouping lives\n // here and only here -- every spell file stays flat and unrenamed on disk.\n //\n // Each component carries BOTH client formats of the same spell: the Copilot\n // prompt (.github/prompts/*.prompt.md) and the Claude Code wrapper\n // (.claude/commands/*.md). They are never independently selectable -- every\n // profile that wanted one always wanted the other -- and pairing them here\n // makes it structurally impossible for the two formats of one spell to drift\n // apart across profiles.\n {\n name: \"spells-session\",\n description: \"Session lifecycle — open, close, commit, status, version\",\n files: [\n \".github/prompts/spell-open-session.prompt.md\",\n \".claude/commands/spell-open-session.md\",\n \".github/prompts/spell-close-session.prompt.md\",\n \".claude/commands/spell-close-session.md\",\n \".github/prompts/spell-commit-work.prompt.md\",\n \".claude/commands/spell-commit-work.md\",\n \".github/prompts/spell-status.prompt.md\",\n \".claude/commands/spell-status.md\",\n \".github/prompts/spell-arcane-version.prompt.md\",\n \".claude/commands/spell-arcane-version.md\",\n ],\n },\n {\n name: \"spells-capture\",\n description: \"Idea, todo, feedback and explanation capture\",\n files: [\n \".github/prompts/spell-save-idea.prompt.md\",\n \".claude/commands/spell-save-idea.md\",\n \".github/prompts/spell-todo.prompt.md\",\n \".claude/commands/spell-todo.md\",\n \".github/prompts/spell-feedback.prompt.md\",\n \".claude/commands/spell-feedback.md\",\n \".github/prompts/spell-suggest-feature.prompt.md\",\n \".claude/commands/spell-suggest-feature.md\",\n \".github/prompts/spell-document.prompt.md\",\n \".claude/commands/spell-document.md\",\n \".github/prompts/spell-verification-ledger.prompt.md\",\n \".claude/commands/spell-verification-ledger.md\",\n \".github/prompts/spell-brainstorm.prompt.md\",\n \".claude/commands/spell-brainstorm.md\",\n \".github/prompts/spell-explain-concept.prompt.md\",\n \".claude/commands/spell-explain-concept.md\",\n ],\n },\n {\n name: \"spells-delivery\",\n description: \"Pull-request lifecycle — open a PR, sync a stale one, respond to review feedback\",\n files: [\n \".github/prompts/spell-create-pull-request.prompt.md\",\n \".claude/commands/spell-create-pull-request.md\",\n \".github/prompts/spell-sync-pull-request.prompt.md\",\n \".claude/commands/spell-sync-pull-request.md\",\n \".github/prompts/spell-address-review.prompt.md\",\n \".claude/commands/spell-address-review.md\",\n ],\n },\n {\n name: \"spells-review\",\n description: \"Adversarial code review — requires source and tests, so excluded from docs-only profiles\",\n files: [\n \".github/prompts/spell-review.prompt.md\",\n \".claude/commands/spell-review.md\",\n \".github/prompts/spell-review-batch.prompt.md\",\n \".claude/commands/spell-review-batch.md\",\n ],\n },\n {\n name: \"spells-planning\",\n description: \"PRD, architecture, scoping and product review\",\n files: [\n \".github/prompts/spell-plan.prompt.md\",\n \".claude/commands/spell-plan.md\",\n \".github/prompts/spell-architect.prompt.md\",\n \".claude/commands/spell-architect.md\",\n \".github/prompts/spell-scope.prompt.md\",\n \".claude/commands/spell-scope.md\",\n \".github/prompts/spell-product-review.prompt.md\",\n \".claude/commands/spell-product-review.md\",\n ],\n },\n {\n name: \"spells-build\",\n description: \"Code and product delivery — implementation, tests, stack experts, release, deployment, asset tooling\",\n files: [\n \".github/prompts/spell-implement.prompt.md\",\n \".claude/commands/spell-implement.md\",\n \".github/prompts/spell-test.prompt.md\",\n \".claude/commands/spell-test.md\",\n \".github/prompts/spell-full-cycle.prompt.md\",\n \".claude/commands/spell-full-cycle.md\",\n \".github/prompts/spell-bug.prompt.md\",\n \".claude/commands/spell-bug.md\",\n \".github/prompts/spell-bump.prompt.md\",\n \".claude/commands/spell-bump.md\",\n \".github/prompts/spell-dotnet-expert.prompt.md\",\n \".claude/commands/spell-dotnet-expert.md\",\n \".github/prompts/spell-security-review.prompt.md\",\n \".claude/commands/spell-security-review.md\",\n \".github/prompts/spell-ship.prompt.md\",\n \".claude/commands/spell-ship.md\",\n \".github/prompts/spell-enchant.prompt.md\",\n \".claude/commands/spell-enchant.md\",\n \".github/prompts/spell-generate-bot-icons.prompt.md\",\n \".claude/commands/spell-generate-bot-icons.md\",\n \".github/prompts/spell-make-discoverable.prompt.md\",\n \".claude/commands/spell-make-discoverable.md\",\n \".github/prompts/spell-scry.prompt.md\",\n \".claude/commands/spell-scry.md\",\n \".github/prompts/spell-eas-store-deploy.prompt.md\",\n \".claude/commands/spell-eas-store-deploy.md\",\n \".github/prompts/spell-compliance.prompt.md\",\n \".claude/commands/spell-compliance.md\",\n ],\n },\n {\n name: \"spells-docs\",\n description: \"Documentation and records workflows — adopt an existing document tree\",\n files: [\n \".github/prompts/spell-adopt-docs.prompt.md\",\n \".claude/commands/spell-adopt-docs.md\",\n ],\n },\n {\n name: \"spells-venture\",\n description: \"Hub-only venture management\",\n files: [\n \".github/prompts/spell-summon-venture.prompt.md\",\n \".claude/commands/spell-summon-venture.md\",\n \".github/prompts/spell-manifest.prompt.md\",\n \".claude/commands/spell-manifest.md\",\n ],\n },\n {\n name: \"spells-meta\",\n description: \"Arcane-about-Arcane — presentation and documentation drift detection\",\n files: [\n \".github/prompts/spell-present-arcane.prompt.md\",\n \".claude/commands/spell-present-arcane.md\",\n \".github/prompts/spell-check-drift.prompt.md\",\n \".claude/commands/spell-check-drift.md\",\n ],\n },\n // Templates\n {\n name: \"venture-template\",\n description: \"Starter template for a new business venture folder — overview plus idea/todo books\",\n files: [\n \".arcane/templates/venture-template/overview.md\",\n \".arcane/templates/venture-template/IDEAS.md\",\n \".arcane/templates/venture-template/TODO.md\",\n ],\n },\n // Session continuity — files required for spell-close-session / spell-open-session\n {\n name: \"session-continuity\",\n description: \"Install-once project orientation and session lifecycle files\",\n skipExisting: true,\n files: [\n \"README.md\",\n \"project.md\",\n \"TODO.md\",\n \"DECISIONS.md\",\n \"ai-context/system-prompt-context.md\",\n \"journal/.gitkeep\",\n ],\n },\n // Agent definitions\n // NOTE: the full portable agent system is managed by `spell agents init` / sync / list.\n // This component only installs the policy reference template for governance-only setups.\n {\n name: \"agent-definitions\",\n description: \"Agent policy reference template (for governance-only setups — use `spell agents init` for the full agent system)\",\n files: [\".arcane/agents/agent-policies-template.md\"],\n },\n // NOTE: the static `agent-files` component was retired — `.github/agents/*.agent.md`\n // files are generated per-roster by `spell agents init` / `spell agents sync`, so\n // installing a fixed-name set via `spell init` shipped stale names and collided\n // with the generated output.\n];\n\n// ─── Profile map (derived from config) ───────────────────────────────────────\n\nfunction buildProfileMap(): Record<Profile, string[]> {\n const allNames = COMPONENTS.map((c) => c.name);\n const map = {} as Record<Profile, string[]>;\n for (const config of PROFILE_CONFIGS) {\n map[config.id] = config.components === \"*\" ? allNames : config.components;\n }\n return map;\n}\n\nconst PROFILE_MAP = buildProfileMap();\n\n// ─── API ──────────────────────────────────────────────────────────────────────\n\nconst componentIndex = new Map(COMPONENTS.map((c) => [c.name, c]));\n\n/**\n * Returns a component by name.\n * Throws ComponentNotFoundError if not found.\n */\n/** Names of the capability-scoped spell components, derived not hand-listed. */\nexport const SPELL_COMPONENT_NAMES: string[] = COMPONENTS.map((c) => c.name).filter((n) =>\n n.startsWith(\"spells-\"),\n);\n\n/**\n * The exact set of components that reconstitutes what the retired monolithic\n * `spell-prompts` / `claude-commands` pair used to install.\n *\n * **Deliberately a frozen literal, not derived from `SPELL_COMPONENT_NAMES`.**\n * Deriving it would mean every future `spells-*` group silently joins this\n * list, so a legacy install would be handed brand-new spells it never had —\n * and a test asserting `migration === SPELL_COMPONENT_NAMES` would be\n * self-referential, passing while the behaviour changed underneath it. This\n * list describes history: what the old monolith contained, as of the 0.18.0\n * split. It must not grow.\n */\nconst LEGACY_MONOLITH_REPLACEMENTS = [\n \"spells-session\",\n \"spells-capture\",\n \"spells-delivery\",\n \"spells-review\",\n \"spells-planning\",\n \"spells-build\",\n \"spells-venture\",\n \"spells-meta\",\n] as const;\n\n/**\n * Components that no longer exist under their old name, mapped to the set that\n * replaces them.\n *\n * `spell-prompts` and `claude-commands` were one monolithic pair holding all 34\n * spells in each client format. Both map to the same replacements, because\n * those components now carry both formats of every spell — so a manifest\n * listing either legacy name (or both, which every profile that had one did)\n * converges on the same result. Callers must dedupe.\n *\n * Without this, `spell update` would hit `ComponentNotFoundError` for the\n * legacy names, print \"not in registry — skipping\", preserve the dead entry,\n * and silently never update that repo's spells again.\n *\n * Null-prototype so a manifest component named `constructor` or `toString`\n * can't resolve to an inherited function and blow up the lookup.\n */\nexport const LEGACY_COMPONENT_MIGRATIONS: Readonly<Record<string, readonly string[]>> =\n Object.assign(Object.create(null) as Record<string, readonly string[]>, {\n \"spell-prompts\": LEGACY_MONOLITH_REPLACEMENTS,\n \"claude-commands\": LEGACY_MONOLITH_REPLACEMENTS,\n });\n\nexport function getComponent(name: string): RegistryComponent {\n const component = componentIndex.get(name);\n if (!component) {\n throw new ComponentNotFoundError(name, Array.from(componentIndex.keys()));\n }\n return component;\n}\n\n/**\n * Returns all components for the given profile.\n */\nexport function getProfile(profile: Profile): RegistryComponent[] {\n return PROFILE_MAP[profile].map((name) => getComponent(name));\n}\n\n/**\n * Returns all registered components.\n */\nexport function getAllComponents(): RegistryComponent[] {\n return [...COMPONENTS];\n}\n\n/**\n * Returns all profile definitions with their component lists expanded.\n * Profiles are sourced from src/config/profiles.ts.\n */\nexport function listProfiles(): ProfileDefinition[] {\n const allNames = COMPONENTS.map((c) => c.name);\n return PROFILE_CONFIGS.map((config) => ({\n id: config.id,\n displayName: config.displayName,\n description: config.description,\n components:\n config.components === \"*\" ? [...allNames] : [...config.components],\n }));\n}\n","import chalk from \"chalk\";\nimport gradient from \"gradient-string\";\nimport { readManifest } from \"./manifest.js\";\n\nconst TAGLINE = \"Cast spells to ship software\";\n\n// ─── Brand palette — steel blue (#6F9FD8) ────────────────────────────────────\nconst STEEL = \"#6f9fd8\";\nconst STEEL_DEEP = \"#3a6ea5\";\nconst STEEL_DIM = \"#5d6f93\";\nconst INK_LABEL = \"#c7d2ee\";\nconst FAINT = \"#2c3658\";\n\nconst STOPS = [\"#2a4d7d\", \"#4a7bb5\", \"#6f9fd8\", \"#a9c8ec\"];\nconst arcaneGradient = gradient(STOPS);\n\n// ─── ARCANE wordmark ─────────────────────────────────────────────────────────\nconst WORDMARK = [\n \" █████╗ ██████╗ ██████╗ █████╗ ███╗ ██╗███████╗\",\n \"██╔══██╗██╔══██╗██╔════╝██╔══██╗████╗ ██║██╔════╝\",\n \"███████║██████╔╝██║ ███████║██╔██╗ ██║█████╗\",\n \"██╔══██║██╔══██╗██║ ██╔══██║██║╚██╗██║██╔══╝\",\n \"██║ ██║██║ ██║╚██████╗██║ ██║██║ ╚████║███████╗\",\n \"╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝\",\n];\nconst INDENT = \" \";\nconst LOCKUP_WIDTH = INDENT.length + Math.max(...WORDMARK.map((l) => l.length));\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** True when the terminal can render the fade-in safely. */\nfunction isAnimatable(): boolean {\n return (\n !!process.stdout.isTTY &&\n process.env[\"TERM\"] !== \"dumb\" &&\n process.env[\"CI\"] !== \"true\" &&\n process.env[\"ARCANE_DISABLE_ANIMATION\"] !== \"true\" &&\n (process.stdout.columns ?? 80) >= LOCKUP_WIDTH\n );\n}\n\n/** Scale a hex color toward black by factor f (0..1) — used for the fade-in. */\nfunction scale(hex: string, f: number): string {\n const v = (i: number): number =>\n Math.max(0, Math.min(255, Math.round(parseInt(hex.slice(i, i + 2), 16) * f)));\n return \"#\" + [v(1), v(3), v(5)].map((x) => x.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n/** Build the ARCANE wordmark lines at brightness f (1 = full color). */\nfunction lockupLines(f = 1): string[] {\n const g = f >= 1 ? arcaneGradient : gradient(STOPS.map((c) => scale(c, f)));\n return WORDMARK.map((line) => INDENT + g(line));\n}\n\nfunction printFooter(version: string): void {\n const taglineText = ` ${TAGLINE} · agent-native SDLC · v${version}`;\n const width = Math.max(LOCKUP_WIDTH, taglineText.length);\n const border = chalk.hex(STEEL_DEEP)(\"─\".repeat(width));\n console.log(border);\n console.log(\n chalk.hex(STEEL)(` ${TAGLINE}`),\n chalk.hex(STEEL_DIM)(`· agent-native SDLC · v${version}`),\n );\n console.log(border);\n}\n\n/**\n * Prints the ARCANE wordmark static, with tagline and version.\n * Used by subcommands (init, etc.).\n */\nexport function printBanner(version: string): void {\n console.log();\n for (const line of lockupLines()) console.log(line);\n printFooter(version);\n console.log();\n}\n\n/**\n * Headline counts for the welcome — turns the installed component file list into\n * \"N spells · N agents · N standards\" (the manifest stores registry-relative,\n * forward-slash paths). Returns [] when nothing categorizable is installed, so\n * the caller can fall back to a plain component count.\n */\nfunction installSummary(components: { files: string[] }[]): string[] {\n const files = components.flatMap((c) =>\n c.files.map((f) => f.replace(/\\\\/g, \"/\")),\n );\n const spells = new Set(\n files\n .filter((f) => /\\/(prompts|commands)\\/spell-.+\\.md$/.test(f))\n .map((f) => f.split(\"/\").pop()!.replace(/\\.prompt\\.md$|\\.md$/, \"\")),\n ).size;\n const agents = files.filter((f) => /\\/agents\\/[^/]+\\.agent\\.md$/.test(f)).length;\n const standards = files.filter((f) =>\n /\\/governance\\/[^/]+\\.md$/.test(f),\n ).length;\n const parts: string[] = [];\n if (spells) parts.push(`${spells} spell${spells === 1 ? \"\" : \"s\"}`);\n if (agents) parts.push(`${agents} agent${agents === 1 ? \"\" : \"s\"}`);\n if (standards) parts.push(`${standards} standard${standards === 1 ? \"\" : \"s\"}`);\n return parts;\n}\n\n/**\n * The bare-`spell` welcome screen: a soft fade-in of the lockup followed by a\n * single gentle pulse (strobe-safe — monotonic brightness ramps, no color\n * cycling), then real current state: whether Arcane is installed in this repo\n * (profile, components, version) and the Spell Loop. Falls back to a static\n * lockup on non-TTY / CI / narrow terminals.\n */\nexport async function printWelcome(version: string, cwd: string): Promise<void> {\n console.log();\n if (isAnimatable()) {\n const draw = (lines: string[], redraw: boolean): void => {\n if (redraw) process.stdout.write(`\\x1b[${lines.length}A`);\n for (const line of lines) process.stdout.write(`\\r\\x1b[2K${line}\\n`);\n };\n // 1. Fade in from dark — the mark materializes.\n const fade = [0.1, 0.22, 0.36, 0.52, 0.68, 0.84, 1];\n for (let i = 0; i < fade.length; i++) {\n draw(lockupLines(fade[i]!), i > 0);\n await sleep(90);\n }\n // 2. One gentle settling pulse — a single slow breath of brightness.\n const pulse = [1, 0.9, 0.82, 0.9, 1];\n for (let i = 0; i < pulse.length; i++) {\n draw(lockupLines(pulse[i]!), true);\n await sleep(140);\n }\n } else {\n for (const line of lockupLines()) console.log(line);\n }\n printFooter(version);\n console.log();\n\n const label = (s: string): string => chalk.hex(STEEL_DIM)(s.padEnd(11));\n const dot = chalk.hex(FAINT)(\"·\");\n\n let repoLine: string;\n try {\n const manifest = await readManifest(cwd);\n const parts = installSummary(manifest.components);\n const summary = parts.length\n ? parts\n : [`${manifest.components.length} components`];\n repoLine =\n `${chalk.hex(STEEL)(\"✓\")} Arcane ${chalk.hex(INK_LABEL)(`«${manifest.profile}»`)} ${dot} ` +\n summary.map((p) => chalk.hex(INK_LABEL)(p)).join(` ${dot} `) +\n ` ${dot} ${chalk.hex(STEEL_DIM)(`v${manifest.version}`)}`;\n } catch {\n repoLine =\n `${chalk.hex(STEEL_DIM)(\"○\")} not initialized ${chalk.hex(FAINT)(\"—\")} run ` +\n `${chalk.hex(STEEL).inverse(\" spell init \")} ${chalk.hex(STEEL_DIM)(\"to scaffold\")}`;\n }\n console.log(` ${label(\"This repo\")}${repoLine}`);\n\n const phases = [\"plan\", \"architect\", \"implement\", \"test\", \"review\", \"ship\"].join(\n chalk.hex(STEEL_DEEP)(\" → \"),\n );\n console.log(` ${label(\"Spell Loop\")}${chalk.hex(\"#dbe3f7\")(phases)}`);\n\n // loop-back hint under the implement → test → review cycle\n const flat = [\"plan\", \"architect\", \"implement\", \"test\", \"review\", \"ship\"].join(\" → \");\n const loopStart = 13 + flat.indexOf(\"implement\"); // col under \"implement\"\n const loopEnd = 13 + flat.indexOf(\"review\") + 5; // col under last char of \"review\"\n const inner = loopEnd - loopStart - 1;\n const lp = Math.floor((inner - 19) / 2); // 19 = visible width of \" ↺ until it passes \"\n const rp = inner - 19 - lp;\n const dash = (n: number): string => chalk.hex(STEEL_DEEP)(\"─\".repeat(Math.max(0, n)));\n console.log(\n \" \".repeat(loopStart) +\n chalk.hex(STEEL_DEEP)(\"╰\") +\n dash(lp) +\n chalk.hex(STEEL)(\" ↺ \") +\n chalk.hex(STEEL_DIM)(\"until it passes\") +\n \" \" +\n dash(rp) +\n chalk.hex(STEEL_DEEP)(\"╯\"),\n );\n console.log();\n}\n\nexport function printSuccess(message: string): void {\n console.log(`\\n${chalk.hex(STEEL)(\"✦\")} ${chalk.bold(message)}`);\n}\n\nexport function printStep(message: string): void {\n console.log(` ${chalk.hex(STEEL_DEEP)(\"▸\")} ${message}`);\n}\n\nexport function printDryRun(message: string): void {\n console.log(` ${chalk.yellow(\"◌\")} ${chalk.dim(message)}`);\n}\n\nexport function printSection(title: string): void {\n console.log(`\\n${chalk.hex(STEEL)(\"─\")} ${chalk.bold(title)}`);\n}\n\nexport function printInfo(message: string): void {\n console.log(` ${chalk.dim(message)}`);\n}\n\nexport function printNextStep(step: number, message: string): void {\n console.log(` ${chalk.hex(STEEL_DEEP)(`${step}.`)} ${message}`);\n}\n\nexport function printWarning(message: string): void {\n console.log(` ${chalk.yellow(\"⚠\")} ${chalk.yellow(message)}`);\n}\n","/**\n * `spell agents` subcommand group.\n *\n * Subcommands:\n * spell agents init — Interactive roster setup (naming strategy + role selection)\n * spell agents sync — Regenerate all client instruction files from canonical defs\n * spell agents list — Show current roster with assigned names and roles\n */\n\nimport { select, checkbox, Separator } from \"@inquirer/prompts\";\nimport { mkdir, writeFile, copyFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { stringify } from \"yaml\";\nimport type {\n AgentInitOptions,\n AgentRoster,\n AgentRosterEntry,\n AgentSyncOptions,\n NamingStrategy,\n AgentProfileId,\n} from \"../types.js\";\nimport { AGENT_ROLES } from \"../config/agent-roles.js\";\nimport {\n AGENT_PROFILE_CONFIGS,\n getAgentProfileConfig,\n} from \"../config/agent-profiles.js\";\nimport { applyNamingStrategy } from \"./naming.js\";\nimport {\n loadRoster,\n rosterExists,\n AgentConfigValidationError,\n AgentRosterNotFoundError,\n} from \"./agent-loader.js\";\nimport { syncAgents } from \"./agent-generator.js\";\nimport { printStep, printSuccess } from \"./banner.js\";\n\n// ─── spell agents init ────────────────────────────────────────────────────────\n\n/**\n * Interactive agent roster setup.\n *\n * 1. Prompts for agent profile (base | full | custom)\n * 2. Prompts for naming strategy (generic | random | custom)\n * 3. Applies naming and writes .arcane/agents.yaml + copies definition files\n */\nexport async function runAgentsInit(\n options: AgentInitOptions,\n targetDir: string,\n assetsDir: string,\n): Promise<void> {\n // Check for existing roster\n if (!options.force && (await rosterExists(targetDir))) {\n console.log(\n 'Agent roster already exists at .arcane/agents.yaml. ' +\n 'Run \"spell agents sync\" to regenerate outputs, or use --force to reinitialize.',\n );\n return;\n }\n\n console.log();\n\n // ── Step 1: Agent profile ────────────────────────────────────────────────\n let profileId: AgentProfileId = options.profile ?? \"full\";\n if (!options.profile) {\n const baseRoles = getAgentProfileConfig(\"base\").roles;\n const baseRoleNames = baseRoles.map((id) => {\n const role = AGENT_ROLES.find((r) => r.id === id);\n return role ? role.role : id;\n });\n const allCategories = [...new Set(AGENT_ROLES.map((r) => r.category))];\n\n profileId = (await select({\n message: \"Select an agent profile:\",\n choices: AGENT_PROFILE_CONFIGS.map((p) => ({\n value: p.id,\n name: `${p.id === \"base\" ? \"🎯\" : p.id === \"full\" ? \"🧙\" : \"🎨\"} ${p.displayName}`,\n description:\n p.id === \"base\"\n ? `\\n4 core roles: ${baseRoleNames.join(\", \")}`\n : p.id === \"full\"\n ? `\\nAll 12 roles across ${allCategories.join(\", \")}`\n : \"\\nPick individual roles from the full roster\",\n })),\n })) as AgentProfileId;\n }\n\n // Resolve role IDs for selected profile\n let selectedRoleIds: string[];\n if (profileId === \"custom\") {\n // Group roles by category with separators\n const categories = [...new Set(AGENT_ROLES.map((r) => r.category))];\n const choicesWithSeparators: Array<\n | { value: string; name: string; checked: boolean }\n | Separator\n > = [];\n for (const cat of categories) {\n choicesWithSeparators.push(new Separator(`── ${cat.charAt(0).toUpperCase() + cat.slice(1)} ──`));\n for (const r of AGENT_ROLES.filter((r) => r.category === cat)) {\n choicesWithSeparators.push({\n value: r.id,\n name: `${r.id} — ${r.role}`,\n checked: true,\n });\n }\n }\n\n console.log();\n selectedRoleIds = await checkbox({\n message: \"Select roles to install:\",\n choices: choicesWithSeparators,\n validate: (choices) =>\n choices.length > 0 ? true : \"Select at least one role\",\n });\n } else {\n selectedRoleIds = getAgentProfileConfig(profileId).roles;\n }\n\n // ── Step 2: Naming strategy ──────────────────────────────────────────────\n let namingStrategy: NamingStrategy = options.naming ?? \"arcanos\";\n if (!options.naming) {\n console.log();\n namingStrategy = (await select({\n message: \"Choose a naming strategy for your agents:\",\n choices: [\n {\n value: \"arcanos\" as NamingStrategy,\n name: \"🃏 Arcanos\",\n description: \"\\nPersona names: Kellar, Merlin, Lafayette, Lince, Prospero...\",\n },\n {\n value: \"generic\" as NamingStrategy,\n name: \"🏷️ Generic\",\n description: \"\\nRole-derived labels: Orchestrator, Architect, Developer, QA Lead...\",\n },\n {\n value: \"random\" as NamingStrategy,\n name: \"🎲 Random\",\n description: \"\\nCommon first names shuffled randomly: Blake, Morgan, Casey...\",\n },\n {\n value: \"custom\" as NamingStrategy,\n name: \"✏️ Custom\",\n description: \"\\nType a unique name for each role interactively\",\n },\n ],\n })) as NamingStrategy;\n }\n\n // ── Step 3: Apply naming ─────────────────────────────────────────────────\n printStep(\"Assigning names...\");\n const named = await applyNamingStrategy(namingStrategy, selectedRoleIds);\n\n // ── Step 4: Build roster ─────────────────────────────────────────────────\n const rosterEntries: AgentRosterEntry[] = named.map(({ definition, name, epithet }) => {\n // Orchestrator gets the \"main\" OpenClaw ID by convention\n const id = definition === \"orchestrator\" ? \"main\" : name.toLowerCase().replace(/\\s+/g, \"-\");\n return epithet ? { definition, name, id, epithet } : { definition, name, id };\n });\n\n const roster: AgentRoster = {\n schema_version: 2,\n naming_strategy: namingStrategy,\n agent_profile: profileId,\n openclaw: {\n enabled: true,\n workspace_root: \"~/.openclaw\",\n },\n roster: rosterEntries,\n };\n\n // ── Step 5: Write .arcane/agents.yaml ────────────────────────────────────\n const arcaneDir = join(targetDir, \".arcane\", \"agents\");\n if (!options.dryRun) {\n await mkdir(arcaneDir, { recursive: true });\n await writeFile(\n join(targetDir, \".arcane\", \"agents.yaml\"),\n stringify(roster),\n \"utf8\",\n );\n } else {\n console.log(\" [dry-run] Would write: .arcane/agents.yaml\");\n }\n\n // ── Step 6: Copy bundled definition files ─────────────────────────────────\n for (const roleId of selectedRoleIds) {\n const src = join(assetsDir, \"agents\", `${roleId}.yaml`);\n const dest = join(arcaneDir, `${roleId}.yaml`);\n if (!options.dryRun) {\n try {\n await copyFile(src, dest);\n } catch {\n console.warn(` ! Could not copy definition for \"${roleId}\" — skipping`);\n }\n } else {\n console.log(` [dry-run] Would copy: .arcane/agents/${roleId}.yaml`);\n }\n }\n\n if (options.dryRun) {\n console.log(\n `\\n [dry-run] Would initialize roster with ${selectedRoleIds.length} agents`,\n );\n return;\n }\n\n // ── Step 7: Auto-sync all clients ────────────────────────────────────────\n printStep(\"Syncing agent definitions to all clients...\");\n const { synced, skipped, hasUnresolvedRoles } = await syncAgents(\n targetDir,\n assetsDir,\n roster,\n { dryRun: false },\n );\n\n printSuccess(\"Agent roster initialized\");\n console.log(` 📋 Profile: ${profileId} · Naming: ${namingStrategy} · Agents: ${rosterEntries.length}`);\n console.log(` 🔄 Synced: ${synced.length} outputs (Copilot, Claude, Codex, OpenClaw)`);\n if (skipped.length > 0) {\n console.log(` ⚠️ Skipped: ${skipped.length} (${skipped.join(\", \")})`);\n }\n console.log();\n console.log(` 💡 Customize: edit .arcane/agents.yaml → spell agents sync`);\n console.log();\n if (hasUnresolvedRoles) {\n console.error(\n \" ✗ One or more rostered roles could not be resolved (see \\\"Skipped\\\" above) — \" +\n \"a malformed or missing agent template must not pass silently.\",\n );\n process.exitCode = 1;\n }\n}\n\n// ─── spell agents sync ────────────────────────────────────────────────────────\n\n/** Regenerates all client instruction files from the current roster + definitions. */\nexport async function runAgentsSync(\n options: AgentSyncOptions,\n targetDir: string,\n assetsDir: string,\n): Promise<void> {\n let roster: AgentRoster;\n try {\n roster = await loadRoster(targetDir);\n } catch (err) {\n if (\n err instanceof AgentRosterNotFoundError\n || err instanceof AgentConfigValidationError\n ) {\n console.error(err.message);\n process.exit(1);\n return;\n }\n throw err;\n }\n\n if (options.dryRun) {\n console.log(\"\\n [dry-run] Would sync agents from roster:\\n\");\n } else {\n console.log(\"\\n Syncing agents...\\n\");\n }\n\n const { synced, skipped, hasUnresolvedRoles } = await syncAgents(\n targetDir,\n assetsDir,\n roster,\n options,\n );\n\n if (options.dryRun) {\n console.log(`\\n [dry-run] ${synced.length} outputs would be generated`);\n return;\n }\n\n console.log(`\\n ✓ Synced ${synced.length} outputs`);\n for (const item of synced) {\n console.log(` + ${item}`);\n }\n if (skipped.length > 0) {\n console.log(`\\n ! Skipped ${skipped.length}:`);\n for (const item of skipped) {\n console.log(` - ${item}`);\n }\n }\n console.log();\n if (hasUnresolvedRoles) {\n console.error(\n \" ✗ One or more rostered roles could not be resolved (see \\\"Skipped\\\" above) — \" +\n \"a malformed or missing agent template must not pass silently.\",\n );\n process.exitCode = 1;\n }\n}\n\n// ─── spell agents list ────────────────────────────────────────────────────────\n\n/** Displays the current agent roster in a table. */\nexport async function runAgentsList(targetDir: string): Promise<void> {\n let roster: AgentRoster;\n try {\n roster = await loadRoster(targetDir);\n } catch (err) {\n if (\n err instanceof AgentRosterNotFoundError\n || err instanceof AgentConfigValidationError\n ) {\n console.error(err.message);\n process.exit(1);\n return;\n }\n throw err;\n }\n\n const nameWidth = Math.max(\n \"Name\".length,\n ...roster.roster.map((e) => (e.name ?? e.definition).length),\n );\n const defWidth = Math.max(\n \"Role ID\".length,\n ...roster.roster.map((e) => e.definition.length),\n );\n const idWidth = Math.max(\n \"OpenClaw ID\".length,\n ...roster.roster.map((e) => e.id.length),\n );\n\n const pad = (s: string, n: number) => s.padEnd(n);\n\n console.log(\n `\\n Profile: ${roster.agent_profile} | Naming: ${roster.naming_strategy} | Agents: ${roster.roster.length}\\n`,\n );\n console.log(\n ` ${pad(\"Name\", nameWidth)} ${pad(\"Role ID\", defWidth)} ${pad(\"OpenClaw ID\", idWidth)}`,\n );\n console.log(\n ` ${\"-\".repeat(nameWidth)} ${\"-\".repeat(defWidth)} ${\"-\".repeat(idWidth)}`,\n );\n for (const entry of roster.roster) {\n console.log(\n ` ${pad(entry.name ?? \"(unnamed)\", nameWidth)} ${pad(entry.definition, defWidth)} ${pad(entry.id, idWidth)}`,\n );\n }\n console.log();\n}\n","/**\n * Canonical agent role definitions.\n * Each entry maps to a YAML template file at src/assets/agents/{id}.yaml.\n * These are the 12 standard roles that ship with Arcane.\n */\n\nimport type { AgentCategory } from \"../types.js\";\n\nexport interface AgentRoleConfig {\n id: string;\n role: string;\n category: AgentCategory;\n}\n\nexport const AGENT_ROLES: AgentRoleConfig[] = [\n {\n id: \"orchestrator\",\n role: \"Product Operations Manager\",\n category: \"operations\",\n },\n {\n id: \"architecture-lead\",\n role: \"CTO / Architecture Lead\",\n category: \"engineering\",\n },\n {\n id: \"fullstack-dev\",\n role: \"Full-Stack Developer\",\n category: \"engineering\",\n },\n {\n id: \"qa-lead\",\n role: \"QA Lead\",\n category: \"quality\",\n },\n {\n id: \"devops\",\n role: \"DevOps / CI/CD Engineer\",\n category: \"engineering\",\n },\n {\n id: \"frontend-dev\",\n role: \"Frontend Developer\",\n category: \"engineering\",\n },\n {\n id: \"mobile-dev\",\n role: \"Mobile Developer\",\n category: \"engineering\",\n },\n {\n id: \"research-analyst\",\n role: \"Research & Backlog Analyst\",\n category: \"research\",\n },\n {\n id: \"marketing-strategist\",\n role: \"Marketing Strategist\",\n category: \"operations\",\n },\n {\n id: \"operations-comms\",\n role: \"Operations Communications\",\n category: \"operations\",\n },\n {\n id: \"collaborator\",\n role: \"External Collaboration Lead\",\n category: \"operations\",\n },\n {\n id: \"security-ops\",\n role: \"Security Operations\",\n category: \"quality\",\n },\n];\n\n/** Lookup by role ID. */\nexport function getAgentRole(id: string): AgentRoleConfig | undefined {\n return AGENT_ROLES.find((r) => r.id === id);\n}\n","/**\n * Agent profile configurations.\n * Controls which roles are included when running `spell agents init`.\n * Separate from src/config/profiles.ts (which governs governance/prompts components).\n */\n\nimport type { AgentProfileId } from \"../types.js\";\n\nexport interface AgentProfileConfig {\n id: AgentProfileId;\n displayName: string;\n description: string;\n /** Role IDs included in this profile. Empty means user selects interactively. */\n roles: string[];\n}\n\nexport const AGENT_PROFILE_CONFIGS: AgentProfileConfig[] = [\n {\n id: \"base\",\n displayName: \"Base\",\n description: \"Core team: orchestrator, architecture-lead, fullstack-dev, qa-lead\",\n roles: [\"orchestrator\", \"architecture-lead\", \"fullstack-dev\", \"qa-lead\"],\n },\n {\n id: \"full\",\n displayName: \"Full\",\n description: \"Complete roster — all 12 roles\",\n roles: [\n \"orchestrator\",\n \"architecture-lead\",\n \"fullstack-dev\",\n \"qa-lead\",\n \"devops\",\n \"frontend-dev\",\n \"mobile-dev\",\n \"research-analyst\",\n \"marketing-strategist\",\n \"operations-comms\",\n \"collaborator\",\n \"security-ops\",\n ],\n },\n {\n id: \"custom\",\n displayName: \"Custom\",\n description: \"Select roles interactively\",\n roles: [], // populated at runtime via checkbox prompt\n },\n];\n\n/** Lookup by profile ID. */\nexport function getAgentProfileConfig(id: AgentProfileId): AgentProfileConfig {\n const config = AGENT_PROFILE_CONFIGS.find((p) => p.id === id);\n if (!config) throw new Error(`Unknown agent profile: \"${id}\"`);\n return config;\n}\n","/**\n * Naming strategy logic for agent roster setup.\n *\n * Four strategies:\n * arcanos — the built-in persona roster (default): twelve legendary agents\n * generic — maps each role to a short, memorable generic label\n * random — assigns random common names from a curated pool\n * custom — prompts the user to type a name for each role\n */\n\nimport { input } from \"@inquirer/prompts\";\nimport type { NamingStrategy } from \"../types.js\";\nimport { getAgentRole } from \"../config/agent-roles.js\";\n\n// ─── Generic names ────────────────────────────────────────────────────────────\n\n/** Short, role-derived display names for the generic strategy. */\nconst GENERIC_NAME_MAP: Record<string, string> = {\n \"orchestrator\": \"Orchestrator\",\n \"architecture-lead\": \"Architect\",\n \"fullstack-dev\": \"Developer\",\n \"qa-lead\": \"QA Lead\",\n \"devops\": \"DevOps\",\n \"frontend-dev\": \"Frontend\",\n \"mobile-dev\": \"Mobile\",\n \"research-analyst\": \"Researcher\",\n \"marketing-strategist\": \"Marketer\",\n \"operations-comms\": \"Comms\",\n \"collaborator\": \"Collaborator\",\n \"security-ops\": \"Security\",\n};\n\n// ─── Arcanos preset names ─────────────────────────────────────────────────────\n\n/** Persona names from the Arcanos roster — twelve legendary agents. */\nconst ARCANOS_NAME_MAP: Record<string, string> = {\n \"orchestrator\": \"Kellar\",\n \"architecture-lead\": \"Merlin\",\n \"fullstack-dev\": \"Lafayette\",\n \"qa-lead\": \"Lince\",\n \"devops\": \"Prospero\",\n \"frontend-dev\": \"Adelaide\",\n \"mobile-dev\": \"Mercurio\",\n \"research-analyst\": \"Alexander\",\n \"marketing-strategist\": \"Circe\",\n \"operations-comms\": \"Bess\",\n \"collaborator\": \"Iris\",\n \"security-ops\": \"Custodio\",\n};\n\n/**\n * Arcanos epithets (naming-conventions.md's roster table) — bound to the\n * PERSONA NAME, not the role archetype: \"the Archmage\" belongs to Merlin,\n * not to \"architecture-lead\" itself. Deliberately not a field on the role\n * YAML (src/assets/agents/*.yaml), which is naming-strategy-agnostic and\n * reused by generic/random/custom naming — putting it there would force\n * Arcanos-flavored text onto strategies designed to be epithet-less (the\n * \"generic role labels\" option naming-conventions.md documents).\n */\nconst ARCANOS_EPITHET_MAP: Record<string, string> = {\n \"orchestrator\": \"the Maestro\",\n \"architecture-lead\": \"the Archmage\",\n \"fullstack-dev\": \"the Conjuror\",\n \"qa-lead\": \"the Unmasker\",\n \"devops\": \"the Stormcaller\",\n \"frontend-dev\": \"the Illusionist\",\n \"mobile-dev\": \"the Swift\",\n \"research-analyst\": \"the Man Who Knows\",\n \"marketing-strategist\": \"the Charmweaver\",\n \"operations-comms\": \"the Herald\",\n \"collaborator\": \"the Emissary\",\n \"security-ops\": \"the Warden\",\n};\n\n// ─── Random name pool ─────────────────────────────────────────────────────────\n\n/**\n * Curated pool of common single-word names.\n * Gender-neutral where possible to avoid unintentional character typecasting.\n */\nconst RANDOM_NAME_POOL: string[] = [\n \"Aiden\", \"Blake\", \"Casey\", \"Dana\", \"Ellis\", \"Finley\", \"Gray\", \"Harper\",\n \"Indigo\", \"Jordan\", \"Kai\", \"Lane\", \"Morgan\", \"Nova\", \"Owen\", \"Parker\",\n \"Quinn\", \"River\", \"Sage\", \"Taylor\", \"Uma\", \"Vale\", \"Wren\", \"Xander\",\n \"Yael\", \"Zara\", \"Avery\", \"Brett\", \"Charlie\", \"Devon\",\n];\n\n// ─── Strategy implementations ────────────────────────────────────────────────\n\nexport interface NamingResult {\n definition: string;\n name: string;\n /** Present only for the arcanos strategy — other strategies are deliberately epithet-less. */\n epithet?: string;\n}\n\n/** Assigns short generic labels derived from each role. */\nexport function applyGenericNames(roleIds: string[]): NamingResult[] {\n return roleIds.map((id) => ({\n definition: id,\n name: GENERIC_NAME_MAP[id] ?? id,\n }));\n}\n\n/** Assigns Arcanos persona names (Kellar, Merlin, Lafayette, etc.). */\nexport function applyArcanosNames(roleIds: string[]): NamingResult[] {\n return roleIds.map((id) => {\n const name = ARCANOS_NAME_MAP[id] ?? GENERIC_NAME_MAP[id] ?? id;\n const epithet = ARCANOS_NAME_MAP[id] ? ARCANOS_EPITHET_MAP[id] : undefined;\n return epithet ? { definition: id, name, epithet } : { definition: id, name };\n });\n}\n\n/**\n * Assigns random names from the pool, shuffled per call.\n * If more roles than pool entries, wraps around.\n */\nexport function applyRandomNames(roleIds: string[]): NamingResult[] {\n const shuffled = [...RANDOM_NAME_POOL].sort(() => Math.random() - 0.5);\n return roleIds.map((id, i) => ({\n definition: id,\n name: shuffled[i % shuffled.length]!,\n }));\n}\n\n/**\n * Prompts the user to type a name for each role interactively.\n * Defaults to the generic name to speed up entry.\n */\nexport async function promptCustomNames(roleIds: string[]): Promise<NamingResult[]> {\n const results: NamingResult[] = [];\n for (const id of roleIds) {\n const role = getAgentRole(id);\n const defaultName = GENERIC_NAME_MAP[id] ?? id;\n const name = await input({\n message: `Name for ${role?.role ?? id}:`,\n default: defaultName,\n validate: (v) =>\n v.trim().length > 0 ? true : \"Name cannot be empty\",\n });\n results.push({ definition: id, name: name.trim() });\n }\n return results;\n}\n\n/**\n * Applies the selected naming strategy to a list of role IDs.\n * Returns an array of definition→name pairs.\n */\nexport async function applyNamingStrategy(\n strategy: NamingStrategy,\n roleIds: string[],\n): Promise<NamingResult[]> {\n switch (strategy) {\n case \"arcanos\":\n return applyArcanosNames(roleIds);\n case \"generic\":\n return applyGenericNames(roleIds);\n case \"random\":\n return applyRandomNames(roleIds);\n case \"custom\":\n return promptCustomNames(roleIds);\n }\n}\n","/**\n * Agent definition and roster loader.\n *\n * Reads canonical agent YAML files from two locations:\n * - assetsDir/agents/ — bundled templates (used during init/add)\n * - targetDir/.arcane/agents/ — project's installed/customized definitions (used during sync)\n */\n\nimport { readFile, readdir, access } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { parse } from \"yaml\";\nimport type { AgentDefinition, AgentRoster } from \"../types.js\";\nimport {\n AgentConfigValidationError,\n validateAgentDefinition,\n validateAgentRoster,\n} from \"./agent-schema.js\";\n\nexport { AgentConfigValidationError } from \"./agent-schema.js\";\n\n// ─── Error types ──────────────────────────────────────────────────────────────\n\nexport class AgentDefinitionNotFoundError extends Error {\n constructor(id: string, searchDir: string) {\n super(\n `Agent definition \"${id}\" not found in \"${searchDir}\". ` +\n `Check that ${id}.yaml exists or run \"spell agents add ${id}\".`,\n );\n this.name = \"AgentDefinitionNotFoundError\";\n }\n}\n\nexport class AgentRosterNotFoundError extends Error {\n constructor() {\n super(\n 'No agent roster found at .arcane/agents.yaml. ' +\n 'Run \"spell agents init\" to create one.',\n );\n this.name = \"AgentRosterNotFoundError\";\n }\n}\n\nfunction parseYaml(content: string, source: string): unknown {\n try {\n return parse(content);\n } catch (err) {\n const detail = err instanceof Error ? err.message : \"unknown YAML parse error\";\n throw new AgentConfigValidationError(source, [`malformed YAML: ${detail}`]);\n }\n}\n\n// ─── Definition loaders ───────────────────────────────────────────────────────\n\n/**\n * Loads a single agent definition from a directory.\n * Used by `spell agents sync` (reads from .arcane/agents/).\n */\nexport async function loadAgentDefinition(\n agentsDir: string,\n id: string,\n): Promise<AgentDefinition> {\n const filePath = join(agentsDir, `${id}.yaml`);\n let content: string;\n try {\n content = await readFile(filePath, \"utf8\");\n } catch {\n throw new AgentDefinitionNotFoundError(id, agentsDir);\n }\n return validateAgentDefinition(parseYaml(content, filePath), filePath);\n}\n\n/**\n * Loads all agent definition files from a directory.\n * Skips non-YAML files and the agents.yaml roster file.\n */\nexport async function loadAllAgentDefinitions(\n agentsDir: string,\n): Promise<AgentDefinition[]> {\n let entries: string[];\n try {\n entries = await readdir(agentsDir);\n } catch {\n return [];\n }\n\n const definitions: AgentDefinition[] = [];\n for (const file of entries) {\n if (!file.endsWith(\".yaml\") || file === \"agents.yaml\") continue;\n const filePath = join(agentsDir, file);\n const content = await readFile(filePath, \"utf8\");\n definitions.push(validateAgentDefinition(parseYaml(content, filePath), filePath));\n }\n return definitions;\n}\n\n// ─── Roster loaders ───────────────────────────────────────────────────────────\n\n/**\n * Loads the agent roster from .arcane/agents.yaml in the target directory.\n * Throws AgentRosterNotFoundError if not initialized.\n */\nexport async function loadRoster(targetDir: string): Promise<AgentRoster> {\n const rosterPath = join(targetDir, \".arcane\", \"agents.yaml\");\n let content: string;\n try {\n content = await readFile(rosterPath, \"utf8\");\n } catch {\n throw new AgentRosterNotFoundError();\n }\n return validateAgentRoster(parseYaml(content, rosterPath), rosterPath);\n}\n\n/**\n * Returns true if a roster file exists in the target directory.\n */\nexport async function rosterExists(targetDir: string): Promise<boolean> {\n try {\n await access(join(targetDir, \".arcane\", \"agents.yaml\"));\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Returns the path to the project's agent definitions directory.\n */\nexport function projectAgentsDir(targetDir: string): string {\n return join(targetDir, \".arcane\", \"agents\");\n}\n","import type { AgentDefinition, AgentRoster } from \"../types.js\";\n\nconst CURRENT_ROSTER_SCHEMA_VERSION = 2;\nconst POWER_LEVELS = new Set([\n \"Spectator\",\n \"Apprentice\",\n \"Wizard\",\n \"Sorcerer\",\n \"Magus\",\n \"Archmage\",\n]);\nconst AGENT_CATEGORIES = new Set([\n \"engineering\",\n \"operations\",\n \"quality\",\n \"research\",\n]);\nconst NAMING_STRATEGIES = new Set([\"arcanos\", \"generic\", \"random\", \"custom\"]);\nconst AGENT_PROFILES = new Set([\"base\", \"full\", \"custom\"]);\n\ntype RecordValue = Record<string, unknown>;\n\nexport class AgentConfigValidationError extends Error {\n constructor(source: string, issues: string[]) {\n super(`Invalid agent configuration in ${source}:\\n- ${issues.join(\"\\n- \")}`);\n this.name = \"AgentConfigValidationError\";\n }\n}\n\nfunction isRecord(value: unknown): value is RecordValue {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction requireRecord(\n value: unknown,\n path: string,\n issues: string[],\n): RecordValue | undefined {\n if (!isRecord(value)) {\n issues.push(`${path} must be an object`);\n return undefined;\n }\n return value;\n}\n\nfunction requireString(value: unknown, path: string, issues: string[]) {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n issues.push(`${path} must be a non-empty string`);\n }\n}\n\nfunction requireBoolean(value: unknown, path: string, issues: string[]) {\n if (typeof value !== \"boolean\") issues.push(`${path} must be a boolean`);\n}\n\nfunction requireStringArray(value: unknown, path: string, issues: string[]) {\n if (!Array.isArray(value) || value.some((entry) => typeof entry !== \"string\")) {\n issues.push(`${path} must be an array of strings`);\n }\n}\n\nfunction requireEnum(\n value: unknown,\n allowed: Set<string>,\n path: string,\n issues: string[],\n) {\n if (typeof value !== \"string\" || !allowed.has(value)) {\n issues.push(`${path} must be one of: ${[...allowed].join(\", \")}`);\n }\n}\n\nfunction validateOptionalClient(\n clients: RecordValue,\n key: string,\n property: string,\n expected: \"string\" | \"boolean\",\n issues: string[],\n) {\n if (clients[key] === undefined) return;\n const client = requireRecord(clients[key], `clients.${key}`, issues);\n if (!client) return;\n if (expected === \"string\") {\n requireString(client[property], `clients.${key}.${property}`, issues);\n } else {\n requireBoolean(client[property], `clients.${key}.${property}`, issues);\n }\n}\n\nexport function validateAgentDefinition(\n value: unknown,\n source: string,\n): AgentDefinition {\n const issues: string[] = [];\n const definition = requireRecord(value, \"definition\", issues);\n if (!definition) throw new AgentConfigValidationError(source, issues);\n\n requireString(definition.id, \"id\", issues);\n requireString(definition.role, \"role\", issues);\n requireEnum(definition.category, AGENT_CATEGORIES, \"category\", issues);\n\n const persona = requireRecord(definition.persona, \"persona\", issues);\n if (persona) {\n requireString(persona.description, \"persona.description\", issues);\n requireStringArray(persona.behavioral_rules, \"persona.behavioral_rules\", issues);\n for (const key of [\"personality\", \"voice\", \"visual_description\"] as const) {\n if (persona[key] !== undefined) requireString(persona[key], `persona.${key}`, issues);\n }\n if (persona.catchphrases !== undefined) {\n requireStringArray(persona.catchphrases, \"persona.catchphrases\", issues);\n }\n }\n\n const model = requireRecord(definition.model, \"model\", issues);\n if (model) {\n requireString(model.primary, \"model.primary\", issues);\n requireStringArray(model.fallback, \"model.fallback\", issues);\n }\n\n const tools = requireRecord(definition.tools, \"tools\", issues);\n if (tools) {\n requireStringArray(tools.allowed, \"tools.allowed\", issues);\n requireStringArray(tools.denied, \"tools.denied\", issues);\n }\n\n const autonomy = requireRecord(definition.autonomy, \"autonomy\", issues);\n if (autonomy) {\n requireEnum(\n autonomy.default_power_level,\n POWER_LEVELS,\n \"autonomy.default_power_level\",\n issues,\n );\n requireBoolean(autonomy.exec_allowed, \"autonomy.exec_allowed\", issues);\n }\n\n const spawn = requireRecord(definition.spawn, \"spawn\", issues);\n if (spawn) {\n requireBoolean(spawn.can_spawn, \"spawn.can_spawn\", issues);\n requireStringArray(spawn.spawnable_by, \"spawn.spawnable_by\", issues);\n }\n\n const clients = requireRecord(definition.clients, \"clients\", issues);\n if (clients) {\n validateOptionalClient(clients, \"openclaw\", \"workspace_prefix\", \"string\", issues);\n validateOptionalClient(clients, \"copilot\", \"agent_file\", \"boolean\", issues);\n validateOptionalClient(clients, \"claude\", \"include_in_instructions\", \"boolean\", issues);\n validateOptionalClient(clients, \"codex\", \"include_in_agents_md\", \"boolean\", issues);\n }\n\n if (issues.length > 0) throw new AgentConfigValidationError(source, issues);\n return definition as unknown as AgentDefinition;\n}\n\nexport function validateAgentRoster(value: unknown, source: string): AgentRoster {\n const issues: string[] = [];\n const parsed = requireRecord(value, \"roster\", issues);\n if (!parsed) throw new AgentConfigValidationError(source, issues);\n\n const version = parsed.schema_version;\n if (!Number.isInteger(version)) {\n throw new AgentConfigValidationError(source, [\n \"schema_version must be an integer; run \\\"spell agents init\\\" with a compatible Arcane CLI\",\n ]);\n }\n if ((version as number) > CURRENT_ROSTER_SCHEMA_VERSION) {\n throw new AgentConfigValidationError(source, [\n `schema_version ${version} is newer than supported version ${CURRENT_ROSTER_SCHEMA_VERSION}; upgrade Arcane before reading this roster`,\n ]);\n }\n if ((version as number) < 1) {\n throw new AgentConfigValidationError(source, [\n `schema_version ${version} is unsupported; supported versions are 1 and ${CURRENT_ROSTER_SCHEMA_VERSION}`,\n ]);\n }\n\n const roster = version === 1\n ? { ...parsed, schema_version: CURRENT_ROSTER_SCHEMA_VERSION }\n : parsed;\n requireEnum(roster.naming_strategy, NAMING_STRATEGIES, \"naming_strategy\", issues);\n requireEnum(roster.agent_profile, AGENT_PROFILES, \"agent_profile\", issues);\n\n const openclaw = requireRecord(roster.openclaw, \"openclaw\", issues);\n if (openclaw) {\n requireBoolean(openclaw.enabled, \"openclaw.enabled\", issues);\n requireString(openclaw.workspace_root, \"openclaw.workspace_root\", issues);\n }\n\n if (!Array.isArray(roster.roster)) {\n issues.push(\"roster must be an array\");\n } else {\n roster.roster.forEach((entry, index) => {\n const item = requireRecord(entry, `roster[${index}]`, issues);\n if (!item) return;\n requireString(item.definition, `roster[${index}].definition`, issues);\n if (item.name !== null) requireString(item.name, `roster[${index}].name`, issues);\n requireString(item.id, `roster[${index}].id`, issues);\n if (item.epithet !== undefined) requireString(item.epithet, `roster[${index}].epithet`, issues);\n });\n }\n\n if (issues.length > 0) throw new AgentConfigValidationError(source, issues);\n return roster as unknown as AgentRoster;\n}","/**\n * Agent generator — multi-client fan-out engine.\n *\n * Reads canonical agent definitions and an agent roster, then generates\n * client-specific instruction files for each enabled AI client:\n * - OpenClaw: IDENTITY.md, SOUL.md, TOOLS.md per agent workspace\n * - Copilot: .github/agents/{name}.agent.md per agent\n * - Claude: CLAUDE.md ← arcane marker merge\n * - Codex: AGENTS.md ← arcane marker merge\n *\n * Each L1 merge (CLAUDE.md, AGENTS.md, .github/copilot-instructions.md) also\n * injects a static intent→spell routing table ahead of the roster table,\n * independent of whether any roster entries resolved — the routing guidance\n * (\"if a spell exists for this workflow, invoke it\") applies with or without\n * agent personas configured.\n *\n * NOTE: openclaw.json is NEVER modified directly — a patch file is generated\n * at .arcane/generated/openclaw-roster.json for the user to apply manually.\n */\n\nimport { writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type {\n AgentDefinition,\n AgentRoster,\n AgentRosterEntry,\n AgentSyncOptions,\n} from \"../types.js\";\nimport { mergeIntoFile } from \"./merger.js\";\nimport { loadAgentDefinition, projectAgentsDir } from \"./agent-loader.js\";\n\n// ─── Resolved entry (definition + roster entry joined) ───────────────────────\n\ninterface ResolvedEntry {\n entry: AgentRosterEntry;\n def: AgentDefinition;\n displayName: string;\n}\n\n// ─── Content renderers ───────────────────────────────────────────────────────\n\nfunction renderIdentity(def: AgentDefinition, name: string): string {\n const mottosLine =\n def.persona.catchphrases && def.persona.catchphrases.length > 0\n ? `\\n## Mottos\\n\\n${def.persona.catchphrases.map((c) => `- \"${c}\"`).join(\"\\n\")}\\n`\n : \"\";\n return `# ${name} — ${def.role}\n\n## Role\n\n${def.persona.description.trim()}\n\n## Category\n\n${def.category}\n${mottosLine}`;\n}\n\nfunction renderSoul(def: AgentDefinition, name: string): string {\n const rules = def.persona.behavioral_rules.map((r) => `- ${r}`).join(\"\\n\");\n return `# ${name} — Behavioral Directives\n\n## Rules\n\n${rules}\n\n## Autonomy\n\n- **Default Power Level:** ${def.autonomy.default_power_level}\n- **Exec Allowed:** ${def.autonomy.exec_allowed ? \"Yes\" : \"No\"}\n`;\n}\n\nfunction renderTools(def: AgentDefinition, name: string): string {\n const allowed = def.tools.allowed.map((t) => `- \\`${t}\\``).join(\"\\n\");\n const denied = def.tools.denied.map((t) => `- \\`${t}\\``).join(\"\\n\");\n return `# ${name} — Tool Capabilities\n\n## Allowed\n\n${allowed}\n\n## Denied\n\n${denied}\n`;\n}\n\nexport function renderCopilotAgent(def: AgentDefinition, name: string): string {\n const firstLine = def.persona.description.split(\"\\n\")[0]?.trim() ?? def.role;\n const rules = def.persona.behavioral_rules.map((r) => `- ${r}`).join(\"\\n\");\n const personalityBlock = def.persona.personality\n ? `\\n## Personality\\n\\n${def.persona.personality.trim()}\\n`\n : \"\";\n const voiceBlock = def.persona.voice\n ? `\\n## Voice\\n\\n${def.persona.voice.trim()}\\n`\n : \"\";\n const mottosBlock =\n def.persona.catchphrases && def.persona.catchphrases.length > 0\n ? `\\n## Mottos\\n\\n${def.persona.catchphrases.map((c) => `- \"${c}\"`).join(\"\\n\")}\\n`\n : \"\";\n return `---\nname: ${name}\ndescription: ${def.role} — ${firstLine}\n---\n${mottosBlock}\n## Role\n\n${def.persona.description.trim()}\n${personalityBlock}${voiceBlock}\n## Behavioral Rules\n\n${rules}\n\n## Tools\n\n**Allowed:** ${def.tools.allowed.join(\", \")}\n**Denied:** ${def.tools.denied.join(\", \")}\n`;\n}\n\nfunction renderSpellRoutingSection(): string {\n return `## Spell Routing\n\n| When you're about to... | Invoke |\n|---|---|\n| Commit work | \\`spell-commit-work\\` |\n| Open a session | \\`spell-open-session\\` |\n| Close a session | \\`spell-close-session\\` |\n| Open a pull request | \\`spell-create-pull-request\\` |\n| Ship a feature end-to-end | \\`spell-full-cycle\\` |\n| Fix a bug | \\`spell-bug\\` |\n| Review code or a PR | \\`spell-review\\` |\n\nIf a spell exists for the workflow you are about to perform, invoke it — do not improvise the workflow from general knowledge, even when the user doesn't name the spell.\n`;\n}\n\nfunction renderAgentRosterSection(entries: ResolvedEntry[]): string {\n const rows = entries\n .map(({ def, displayName }) =>\n `| **${displayName}** | ${def.role} | ${def.category} |`,\n )\n .join(\"\\n\");\n\n return `## Agent Roster\n\n| Agent | Role | Category |\n|-------|------|----------|\n${rows}\n`;\n}\n\n// ─── Sync result ─────────────────────────────────────────────────────────────\n\nexport interface SyncResult {\n synced: string[];\n skipped: string[];\n /**\n * True when a rostered role's definition could not be loaded from either\n * the project or bundled source (the mobile-dev bug class: a malformed\n * template silently dropped from the roster with a zero exit code).\n * Distinct from an openclaw-workspace write failure, which is an I/O\n * problem, not a role-resolution failure, and does not set this.\n */\n hasUnresolvedRoles: boolean;\n}\n\n// ─── Main sync function ───────────────────────────────────────────────────────\n\n/**\n * Generates all client-specific output files from the agent roster and definitions.\n *\n * @param targetDir Root of the consuming repo (where .arcane/ lives)\n * @param assetsDir Path to bundled assets (used as fallback for definitions not yet in project)\n * @param roster Parsed agent roster (from .arcane/agents.yaml)\n * @param options Sync options (dry-run, client filters)\n */\nexport async function syncAgents(\n targetDir: string,\n assetsDir: string,\n roster: AgentRoster,\n options: AgentSyncOptions = {},\n): Promise<SyncResult> {\n const synced: string[] = [];\n const skipped: string[] = [];\n let hasUnresolvedRoles = false;\n\n // ── Load all definitions ──────────────────────────────────────────────────\n const projectDefs = projectAgentsDir(targetDir);\n const bundledDefs = join(assetsDir, \"agents\");\n\n const resolved: ResolvedEntry[] = [];\n for (const entry of roster.roster) {\n let def: AgentDefinition;\n try {\n // Prefer the project's customized version\n def = await loadAgentDefinition(projectDefs, entry.definition);\n } catch {\n try {\n // Fall back to bundled template\n def = await loadAgentDefinition(bundledDefs, entry.definition);\n } catch {\n skipped.push(`${entry.definition} (definition not found)`);\n hasUnresolvedRoles = true;\n continue;\n }\n }\n resolved.push({\n entry,\n def,\n displayName: entry.name ?? entry.definition,\n });\n }\n\n // ── OpenClaw output ──────────────────────────────────────────────────────\n if (roster.openclaw.enabled && options.openclaw !== false) {\n const openclawRoot = roster.openclaw.workspace_root.replace(\n /^~/,\n homedir(),\n );\n\n for (const { entry, def, displayName } of resolved) {\n if (!def.clients.openclaw) continue;\n\n const workspaceName =\n entry.id === \"main\" ? \"workspace\" : `workspace-${entry.id}`;\n const workspaceDir = join(openclawRoot, workspaceName);\n\n try {\n if (!options.dryRun) {\n await mkdir(workspaceDir, { recursive: true });\n await writeFile(\n join(workspaceDir, \"IDENTITY.md\"),\n renderIdentity(def, displayName),\n \"utf8\",\n );\n await writeFile(\n join(workspaceDir, \"SOUL.md\"),\n renderSoul(def, displayName),\n \"utf8\",\n );\n await writeFile(\n join(workspaceDir, \"TOOLS.md\"),\n renderTools(def, displayName),\n \"utf8\",\n );\n } else {\n console.log(` [dry-run] Would write: ${workspaceDir}/IDENTITY.md`);\n console.log(` [dry-run] Would write: ${workspaceDir}/SOUL.md`);\n console.log(` [dry-run] Would write: ${workspaceDir}/TOOLS.md`);\n }\n synced.push(`openclaw:${entry.id}:IDENTITY+SOUL+TOOLS`);\n } catch {\n skipped.push(`openclaw:${entry.id} (workspace not accessible)`);\n }\n }\n\n // Generate openclaw-roster.json patch — never modifies openclaw.json directly\n const patch = {\n $comment:\n \"Apply this to your openclaw.json agents section. \" +\n \"Do not edit manually — regenerated by `spell agents sync`.\",\n agents: resolved.map(({ entry, def }) => ({\n id: entry.id,\n identity: {\n name: entry.name ?? entry.definition,\n ...(entry.epithet ? { epithet: entry.epithet } : {}),\n role: def.role,\n },\n })),\n };\n\n const generatedDir = join(targetDir, \".arcane\", \"generated\");\n if (!options.dryRun) {\n await mkdir(generatedDir, { recursive: true });\n await writeFile(\n join(generatedDir, \"openclaw-roster.json\"),\n JSON.stringify(patch, null, 2) + \"\\n\",\n \"utf8\",\n );\n } else {\n console.log(\n \" [dry-run] Would write: .arcane/generated/openclaw-roster.json\",\n );\n }\n synced.push(\"openclaw-roster.json\");\n }\n\n // ── Copilot output ───────────────────────────────────────────────────────\n if (options.copilot !== false) {\n const agentsDir = join(targetDir, \".github\", \"agents\");\n\n if (!options.dryRun) {\n await mkdir(agentsDir, { recursive: true });\n }\n\n for (const { def, displayName } of resolved) {\n if (!def.clients.copilot?.agent_file) continue;\n // Slugify: lowercase, spaces → hyphens (e.g. \"QA Lead\" → \"qa-lead.agent.md\")\n const slug = displayName.toLowerCase().replace(/\\s+/g, \"-\");\n const fileName = `${slug}.agent.md`;\n if (!options.dryRun) {\n await writeFile(\n join(agentsDir, fileName),\n renderCopilotAgent(def, displayName),\n \"utf8\",\n );\n } else {\n console.log(` [dry-run] Would write: .github/agents/${fileName}`);\n }\n synced.push(`.github/agents/${fileName}`);\n }\n\n // Merge spell routing + roster into copilot-instructions.md\n const copilotSection = `${renderSpellRoutingSection()}\\n${renderAgentRosterSection(resolved)}`;\n const copilotMerged = await mergeIntoFile(\n targetDir,\n \".github/copilot-instructions.md\",\n copilotSection,\n { force: true, dryRun: options.dryRun },\n );\n if (copilotMerged)\n synced.push(\".github/copilot-instructions.md (agents section)\");\n }\n\n // ── Claude output ────────────────────────────────────────────────────────\n if (options.claude !== false) {\n const claudeSection = `${renderSpellRoutingSection()}\\n${renderAgentRosterSection(resolved)}`;\n const claudeMerged = await mergeIntoFile(\n targetDir,\n \"CLAUDE.md\",\n claudeSection,\n { force: true, dryRun: options.dryRun },\n );\n if (claudeMerged) synced.push(\"CLAUDE.md (agents section)\");\n }\n\n // ── Codex output ─────────────────────────────────────────────────────────\n if (options.codex !== false) {\n const codexSection = `${renderSpellRoutingSection()}\\n${renderAgentRosterSection(resolved)}`;\n const codexMerged = await mergeIntoFile(\n targetDir,\n \"AGENTS.md\",\n codexSection,\n { force: true, dryRun: options.dryRun },\n );\n if (codexMerged) synced.push(\"AGENTS.md (agents section)\");\n }\n\n return { synced, skipped, hasUnresolvedRoles };\n}\n","import { readFile, writeFile, rm } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { validateTargetPath } from \"./copier.js\";\n\nexport const MARKER_START = \"<!-- arcane:start -->\";\nexport const MARKER_END = \"<!-- arcane:end -->\";\n\nexport class MalformedMarkersError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"MalformedMarkersError\";\n }\n}\n\n/**\n * Merges `content` into `targetDir/relativePath` using arcane marker comments.\n *\n * Behaviour:\n * - If both markers exist: replaces everything between them with `content`.\n * - If neither marker exists and `force` is true: appends markers + content.\n * - If neither marker exists and `force` is false: no-op, returns false.\n * - If only one marker is present: throws MalformedMarkersError.\n * - If file doesn't exist and `force` is true: creates the file with markers.\n * - If file doesn't exist and `force` is false: no-op, returns false.\n *\n * @returns true if the file was modified (or would be on dry-run), false if untouched.\n */\nexport async function mergeIntoFile(\n targetDir: string,\n relativePath: string,\n content: string,\n opts: { force?: boolean; dryRun?: boolean } = {},\n): Promise<boolean> {\n validateTargetPath(targetDir, relativePath);\n\n const destPath = path.resolve(targetDir, relativePath);\n\n let existing: string | null;\n try {\n existing = await readFile(destPath, \"utf8\");\n } catch (err) {\n const e = err as NodeJS.ErrnoException;\n if (e.code === \"ENOENT\") {\n existing = null;\n } else {\n throw err;\n }\n }\n\n if (existing === null) {\n // File doesn't exist — create with markers only if --force\n if (!opts.force) return false;\n const newContent = `${MARKER_START}\\n${content}\\n${MARKER_END}\\n`;\n if (!opts.dryRun) {\n await writeFile(destPath, newContent, \"utf8\");\n }\n return true;\n }\n\n const startIdx = existing.indexOf(MARKER_START);\n const endIdx = existing.indexOf(MARKER_END);\n\n const hasStart = startIdx !== -1;\n const hasEnd = endIdx !== -1;\n\n if (hasStart !== hasEnd) {\n throw new MalformedMarkersError(\n `File \"${relativePath}\" has mismatched arcane markers: ` +\n `${hasStart ? \"start found\" : \"start missing\"}, ` +\n `${hasEnd ? \"end found\" : \"end missing\"}.`,\n );\n }\n\n if (hasStart && hasEnd) {\n if (startIdx > endIdx) {\n throw new MalformedMarkersError(\n `File \"${relativePath}\" has arcane markers in wrong order (end before start).`,\n );\n }\n // Replace content between the markers (keeps marker lines themselves intact)\n const beforeMarker = existing.slice(0, startIdx + MARKER_START.length);\n const afterMarker = existing.slice(endIdx);\n const updated = `${beforeMarker}\\n${content}\\n${afterMarker}`;\n if (!opts.dryRun) {\n await writeFile(destPath, updated, \"utf8\");\n }\n return true;\n }\n\n // No markers — append only if --force\n if (!opts.force) return false;\n\n const appended =\n `${existing}${existing.endsWith(\"\\n\") ? \"\" : \"\\n\"}` +\n `${MARKER_START}\\n${content}\\n${MARKER_END}\\n`;\n if (!opts.dryRun) {\n await writeFile(destPath, appended, \"utf8\");\n }\n return true;\n}\n\n/**\n * Removes the `<!-- arcane:start -->…<!-- arcane:end -->` block from a file.\n *\n * - If the file has no markers, returns false (no-op).\n * - If the file is empty (or whitespace-only) after stripping, deletes the file.\n * - Otherwise rewrites the file without the marker block.\n *\n * @returns true if the file was modified or deleted, false if untouched.\n */\nexport async function stripMarkerSection(\n targetDir: string,\n relativePath: string,\n opts: { dryRun?: boolean } = {},\n): Promise<boolean> {\n const destPath = path.resolve(targetDir, relativePath);\n\n let existing: string;\n try {\n existing = await readFile(destPath, \"utf8\");\n } catch {\n return false; // file doesn't exist\n }\n\n const startIdx = existing.indexOf(MARKER_START);\n const endIdx = existing.indexOf(MARKER_END);\n if (startIdx === -1 || endIdx === -1) return false;\n\n const before = existing.slice(0, startIdx);\n const after = existing.slice(endIdx + MARKER_END.length);\n const stripped = (before + after).replace(/\\n{3,}/g, \"\\n\\n\").trim();\n\n if (!opts.dryRun) {\n if (stripped.length === 0) {\n await rm(destPath, { force: true });\n } else {\n await writeFile(destPath, stripped + \"\\n\", \"utf8\");\n }\n }\n return true;\n}\n","/**\n * Push safety (EF-09 / features/push-safety/PRD.md) and shared git-hooks\n * management (ARC-037 decision 2).\n *\n * Two layered controls for a repository whose history must not reach a remote:\n * a `pre-push` hook, and disabled push URLs. Neither is tamper-proof, and the\n * PRD is explicit that they are not meant to be — the threat modelled is an\n * *accidental* push (wrong remote, muscle memory, an unsupervised agent), not a\n * determined operator. Overclaiming here would be its own hazard.\n *\n * The two layers cover different bypasses, which is why both exist:\n * - `git push --no-verify` skips hooks entirely → the disabled URL catches it.\n * - `git push <url> main`, or a second remote, never consults the first\n * remote's URL → the hook catches it.\n * Only combining both bypasses in one command gets through, which is squarely\n * the determined-operator case this does not claim to stop.\n *\n * `installHook`/`isHookInstalled`/`removeHook` below are the generalized form\n * of this module's original pre-push-only machinery: any Arcane hook (pre-push,\n * and now the consumer-facing secrets-scan pre-commit hook) claims the SAME\n * shared `.arcane/hooks/` directory and `core.hooksPath` slot through the SAME\n * R7 collision-guarded path, rather than each hook re-implementing its own\n * claim-and-refuse logic. `installPrePushHook`/`isHookEnforced`/\n * `removePrePushHook` are now thin wrappers over the generic functions, kept\n * for every existing caller (doctor.ts, init.ts, unblock-push.ts, uninstall.ts)\n * and this file's own extensive test suite -- their behavior is unchanged.\n */\nimport { mkdir, readFile, writeFile, chmod, access, rm, readdir } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { join, resolve, dirname, basename } from \"node:path\";\nimport { fileExists } from \"./copier.js\";\nimport { runGit } from \"./git.js\";\n\n/**\n * Sentinel push URL. Not a real scheme, so git fails to resolve a helper.\n *\n * The scheme name carries the recovery instruction because it is the ONLY text\n * git shows the operator here. With both layers in place the URL fails first and\n * the hook never runs, so the hook's carefully worded message is never seen --\n * all git prints is `fatal: remote helper '<scheme>' aborted session`. Encoding\n * the fix in the scheme turns a dead end into an instruction.\n */\nexport const DISABLED_PUSH_URL = \"arcane-push-blocked-run-spell-unblock-push://this-repository\";\n\n/**\n * Marks that a remote had NO `pushurl` key before the block. Restoring must then\n * *remove* the key rather than write the fetch URL into it -- otherwise a later\n * `git remote set-url` would change fetch only and pushes would silently keep\n * going to the old location.\n *\n * A separate boolean key rather than a magic value stored in the URL slot: a\n * remote whose genuine push URL happened to equal that magic string would\n * otherwise be recorded as \"there was no key\" and lose its original on restore.\n */\nconst NO_PUSH_URL_MARKER = (remote: string): string => `remote.${remote}.arcaneHadNoPushUrl`;\n\n/** Directory Arcane points `core.hooksPath` at when it owns the hooks. */\nexport const ARCANE_HOOKS_DIR = \".arcane/hooks\";\n\n/**\n * Where a config value is set, as git itself reports it via `--show-scope`.\n * `worktree` matters here: a linked worktree can carry its own `config.worktree`\n * value that `--local` does not see, which an earlier local-vs-effective\n * heuristic misfiled as inherited-from-global.\n */\nexport type ConfigScope = \"local\" | \"worktree\" | \"global\" | \"system\" | \"command\" | \"unknown\";\n\nexport interface HooksPathInfo {\n /** The effective value git would use, respecting scope precedence. */\n value: string;\n /** Where it is set, as reported by git rather than inferred. */\n scope: ConfigScope;\n /** Git could not be asked. Callers must fail closed, never assume \"unset\". */\n unreadable?: boolean;\n}\n\nexport type HookInstallOutcome =\n | { status: \"installed\"; path: string }\n | { status: \"already-ours\" }\n | { status: \"refused-foreign-hooks-path\"; existing: string; scope: ConfigScope }\n | { status: \"refused-default-hooks\"; hooks: string[] }\n | { status: \"refused-unreadable-config\" };\n\n/**\n * Reads the EFFECTIVE `core.hooksPath` — not just the repository-local one.\n *\n * Reading only `--local` was a real defect: a `core.hooksPath` set at *global*\n * scope (the standard way organisations deploy pre-commit and corporate hook\n * managers) was invisible, so installation reported success while silently\n * disabling it, since a local value overrides a global one. That is precisely\n * the harm R7 exists to prevent.\n */\nexport async function readHooksPath(cwd: string): Promise<HooksPathInfo | undefined> {\n let raw: string;\n try {\n // `--show-scope` makes git report the scope rather than us inferring it by\n // comparing --local against the effective value. That inference was wrong\n // for a per-worktree `config.worktree` value, which --local does not see:\n // a genuinely repository-scoped setting was reported as inherited.\n const { stdout } = await runGit(cwd, [\"config\", \"--show-scope\", \"--get\", \"core.hooksPath\"]);\n raw = stdout.trim();\n } catch (error) {\n // ONLY exit 1 means \"not set anywhere\". Anything else -- an unparseable\n // config file, a permission error, an older git that rejects --show-scope --\n // means we could not determine whether someone else owns core.hooksPath.\n // Treating that as \"no claim\" made the R7 collision guard fail OPEN, which\n // is the one direction it must never fail: it would install over an org hook\n // manager it simply failed to see.\n if ((error as { code?: unknown }).code !== 1) {\n return { value: \"\", scope: \"unknown\", unreadable: true };\n }\n return undefined;\n }\n if (raw === \"\") return undefined;\n\n // Format is `<scope>\\t<value>`. The value may itself contain whitespace.\n const separator = raw.indexOf(\"\\t\");\n if (separator === -1) return { value: raw, scope: \"unknown\" };\n\n const scope = raw.slice(0, separator).trim();\n const value = raw.slice(separator + 1).trim();\n if (value === \"\") return undefined;\n\n const known: readonly ConfigScope[] = [\"local\", \"worktree\", \"global\", \"system\", \"command\"];\n const matched = known.find((candidate) => candidate === scope);\n return { value, scope: matched ?? \"unknown\" };\n}\n\n/**\n * True when two `core.hooksPath` values name the same directory.\n *\n * Exact string equality misreported every equivalent spelling git accepts --\n * `.arcane/hooks/`, `./.arcane/hooks`, `.arcane\\hooks`, and an absolute path all\n * point where our hook actually lives and all fire on a real push, yet compared\n * unequal. That direction fails safe (we refuse rather than clobber, and report\n * \"not enforced\" for something that is), but it means doctor contradicts what\n * git does, which is the exact class of confusion this module exists to remove.\n */\nfunction isArcaneHooksPath(root: string, value: string): boolean {\n // Case folding only where the filesystem actually folds case. On POSIX,\n // `.arcane/HOOKS` is a genuinely different directory, and treating it as ours\n // would make the R7 guard fail OPEN -- installing over someone else's hooks.\n // Backslash-to-slash folding is Windows-only for the same reason as case\n // folding: on POSIX a backslash is a legal filename character, so a directory\n // genuinely named `.arcane\\hooks` would normalise onto ours and the R7 guard\n // would fail OPEN -- installing over someone else's hooks.\n const windows = process.platform === \"win32\";\n const normalize = (p: string): string => {\n const separated = windows ? p.replace(/\\\\/g, \"/\") : p;\n // Relative values resolve against the repository ROOT, matching how git\n // itself resolves core.hooksPath -- against the worktree top level, never\n // against the process's working directory.\n const absolute = resolve(root, separated).replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n return windows ? absolute.toLowerCase() : absolute;\n };\n return normalize(value) === normalize(ARCANE_HOOKS_DIR);\n}\n\nconst PRE_PUSH_HOOK_BODY = `#!/bin/sh\n# Installed by Arcane because this repository's .arcane.json sets\n# push_policy: \"blocked\".\n#\n# This is deliberately not tamper-proof. It guards against an accidental push\n# -- the wrong remote, muscle memory, an unsupervised agent -- not against a\n# determined operator, who can always bypass it.\n#\n# To push legitimately, undo the policy first:\n#\n# spell unblock-push\n#\n# That command is interactive-only and asks you to confirm the repository by\n# name. Do not work around this hook by other means: the manifest would then\n# claim a protection this repository no longer has.\necho \"arcane: push blocked (push_policy: blocked). Run 'spell unblock-push' to undo.\" >&2\nexit 1\n`;\n\n/**\n * Human phrasing for a config scope.\n *\n * Worth its own function because \"globally\" was previously printed for anything\n * not local — including a system-scope value and a per-worktree one, neither of\n * which the operator would find where that message sends them.\n */\nexport function describeConfigScope(scope: ConfigScope): string {\n switch (scope) {\n case \"local\":\n return \"set for this repository\";\n case \"worktree\":\n return \"set for this worktree\";\n case \"global\":\n return \"set globally, for your user\";\n case \"system\":\n return \"set system-wide\";\n case \"command\":\n return \"set on the command line\";\n default:\n return \"scope unknown\";\n }\n}\n\n/**\n * The repository's top level — where the hook must live.\n *\n * `targetDir` is whatever directory the CLI was run from, and\n * `--is-inside-work-tree` is true from any subdirectory. Installing the hook\n * relative to `targetDir` while pointing repo-wide `core.hooksPath` at the\n * literal `.arcane/hooks` put the file somewhere git never looks: git resolves a\n * relative hooksPath against the *worktree top-level*, so a `spell init` run\n * inside a monorepo package disabled the repository's hooks entirely and\n * reported the block installed.\n */\nasync function repositoryRoot(cwd: string): Promise<string> {\n // Anchored on the COMMON git dir, so every linked worktree resolves to the\n // same directory as the main one. `--show-toplevel` would give each worktree\n // its own root, which is exactly the mistake being fixed: the hook lives in\n // one place, and `core.hooksPath` is shared config that must point there from\n // everywhere.\n try {\n const { stdout } = await runGit(cwd, [\n \"rev-parse\",\n \"--path-format=absolute\",\n \"--git-common-dir\",\n ]);\n const commonDir = stdout.trim();\n if (commonDir !== \"\") {\n // `<main>/.git` -> `<main>`. A bare repository has no working tree above\n // its git dir, so fall through to the worktree top level there.\n const parent = dirname(commonDir);\n if (basename(commonDir) === \".git\" && parent !== \"\") return parent;\n }\n } catch {\n // Older git without --path-format; fall back below.\n }\n try {\n const { stdout } = await runGit(cwd, [\"rev-parse\", \"--show-toplevel\"]);\n const top = stdout.trim();\n if (top !== \"\") return top;\n } catch {\n // Not a work tree (bare repo).\n }\n return cwd;\n}\n\n/**\n * Absolute path of a named hook file Arcane installs, resolved against the\n * repository top level rather than the working directory. Defaults to\n * \"pre-push\" -- this module's original and, until ARC-037, only hook -- so\n * every existing single-argument call site (this file's own internals and\n * this file's test suite) is unaffected by the generalization to other\n * hook names.\n */\nexport async function hookFilePath(cwd: string, hookName: string = \"pre-push\"): Promise<string> {\n return join(await repositoryRoot(cwd), ARCANE_HOOKS_DIR, hookName);\n}\n\n/**\n * The value written to `core.hooksPath`: an ABSOLUTE path.\n *\n * A relative value is re-resolved per worktree, and `core.hooksPath` lives in\n * shared local config while `.arcane/hooks/` is an untracked directory that\n * exists only in the checkout where it was created. So every linked worktree\n * inherited the config and had no hook file — the hook layer was simply absent\n * there, and `git push <url>` (the bypass only the hook covers) delivered the\n * full history in one ordinary command while `doctor` reported the repository\n * blocked. That is not an edge case here: Arcane's own methodology sends\n * concurrent sessions into linked worktrees.\n */\nasync function hooksPathValue(cwd: string): Promise<string> {\n return join(await repositoryRoot(cwd), ARCANE_HOOKS_DIR).replace(/\\\\/g, \"/\");\n}\n\n/**\n * Installs a named hook (its body written verbatim), refusing rather than\n * clobbering someone else's hook manager (R7).\n *\n * `core.hooksPath` is a single exclusive slot — Git reads one directory, never\n * several — so pointing it at Arcane's directory silently disables Husky,\n * Lefthook, pre-commit, or anything else already using it, at either local or\n * global scope. This repository's own `core.hooksPath` is `.husky/_`, running\n * lint, typecheck and the full test suite; a naive install would have turned\n * that off while appearing to add protection.\n *\n * Safe to call for a SECOND hook name once a first has already claimed the\n * directory: the collision guard above only refuses a FOREIGN path, and\n * Arcane's own already-claimed `.arcane/hooks/` is not foreign to a second\n * Arcane hook — the two hooks share the one slot rather than racing for it.\n */\nexport async function installHook(cwd: string, hookName: string, body: string): Promise<HookInstallOutcome> {\n const root = await repositoryRoot(cwd);\n const existing = await readHooksPath(cwd);\n\n if (existing?.unreadable === true) return { status: \"refused-unreadable-config\" };\n\n if (existing !== undefined && !isArcaneHooksPath(root, existing.value)) {\n return {\n status: \"refused-foreign-hooks-path\",\n existing: existing.value,\n scope: existing.scope,\n };\n }\n\n // The guard above only sees hook managers that announce themselves via\n // core.hooksPath. A repository using git's DEFAULT hooks directory has no\n // such key, so taking the slot silently disabled every hook it had -- the\n // exact harm R7 names, reached by the one route R7 wasn't looking at.\n // Only relevant on the FIRST claim: once existing is defined (ours), a\n // second hook joining the same directory displaces nothing new.\n if (existing === undefined) {\n const displaced = await defaultHooks(cwd);\n if (displaced.length > 0) {\n return { status: \"refused-default-hooks\", hooks: displaced };\n }\n }\n\n const hookPath = join(root, ARCANE_HOOKS_DIR, hookName);\n\n if (existing !== undefined && (await hookFileMatches(cwd, hookName, body))) {\n return { status: \"already-ours\" };\n }\n\n await mkdir(join(root, ARCANE_HOOKS_DIR), { recursive: true });\n await writeFile(hookPath, body, \"utf-8\");\n // Git requires the hook be executable on POSIX. chmod is a no-op for the\n // owner on Windows, which is fine -- Git for Windows does not check the bit.\n await chmod(hookPath, 0o755);\n await runGit(cwd, [\"config\", \"--local\", \"core.hooksPath\", await hooksPathValue(cwd)]);\n\n return { status: \"installed\", path: hookPath };\n}\n\n/** Installs the pre-push hook. Thin wrapper over {@link installHook}. */\nexport async function installPrePushHook(cwd: string): Promise<HookInstallOutcome> {\n return installHook(cwd, \"pre-push\", PRE_PUSH_HOOK_BODY);\n}\n\n/**\n * True only if the named hook is genuinely in force: the config points at\n * Arcane's directory AND that hook's file actually exists there with the\n * expected body.\n *\n * Checking the config alone is a declaration check, not an enforcement check —\n * deleting the hook file leaves the config intact and pushes succeed.\n */\nexport async function isHookInstalled(cwd: string, hookName: string, body: string): Promise<boolean> {\n const hooksPath = await readHooksPath(cwd);\n if (hooksPath === undefined || hooksPath.unreadable === true) return false;\n if (!isArcaneHooksPath(await repositoryRoot(cwd), hooksPath.value)) return false;\n return hookFileMatches(cwd, hookName, body);\n}\n\n/** Whether the pre-push hook is genuinely enforced. Thin wrapper over {@link isHookInstalled}. */\nexport async function isHookEnforced(cwd: string): Promise<boolean> {\n return isHookInstalled(cwd, \"pre-push\", PRE_PUSH_HOOK_BODY);\n}\n\n/**\n * Warns -- never blocks -- when the branch being pushed already has a\n * CLOSED or MERGED pull request (ARC-035 decision 4: the silent\n * stranded-commit mode that shipped as PR #63's incident is made loud by\n * extending this same hook slot, not by adding a second, competing one).\n *\n * Shares the \"pre-push\" hook name with {@link PRE_PUSH_HOOK_BODY}, so the\n * two are mutually exclusive per repository by construction -- a repo with\n * `push_policy: \"blocked\"` already refuses every push outright and has no\n * use for a warning about which PR it would have gone to; every other\n * tier (`guarded`, `open`, unset) gets this one instead. GitHub-only,\n * matching the ADR's own cited mechanism (`gh pr view --json state`); a\n * non-GitHub remote or a missing/unauthenticated `gh` is a silent no-op,\n * never a blocked or errored push.\n */\nconst CLOSED_PR_WARNING_HOOK_BODY = `#!/bin/sh\n# Installed by Arcane (ARC-035 decision 4): warns when the branch being\n# pushed already has a closed or merged PR, instead of accepting the push\n# into a void with no signal at all. Never blocks -- pushing to a branch\n# behind a closed PR is sometimes intentional.\nremote_url=\"$2\"\ncase \"$remote_url\" in\n *github.com*) ;;\n *) exit 0 ;;\nesac\ncommand -v gh >/dev/null 2>&1 || exit 0\nbranch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) || exit 0\nstate=$(gh pr view \"$branch\" --json state --jq .state 2>/dev/null) || exit 0\ncase \"$state\" in\n CLOSED|MERGED)\n echo \"arcane: WARNING -- the PR for branch '$branch' is already $state. Pushing anyway (not blocked).\" >&2\n ;;\nesac\nexit 0\n`;\n\n/** Installs the closed-PR warning hook. Thin wrapper over {@link installHook}. */\nexport async function installClosedPrWarningHook(cwd: string): Promise<HookInstallOutcome> {\n return installHook(cwd, \"pre-push\", CLOSED_PR_WARNING_HOOK_BODY);\n}\n\n/** True only if the closed-PR warning hook (not the blocking one) is the one currently installed. */\nexport async function isClosedPrWarningHookInstalled(cwd: string): Promise<boolean> {\n return isHookInstalled(cwd, \"pre-push\", CLOSED_PR_WARNING_HOOK_BODY);\n}\n\n/**\n * Real hooks living in git's default directory, which taking `core.hooksPath`\n * would silently switch off. `.sample` files are git's own inert templates.\n */\nasync function defaultHooks(cwd: string): Promise<string[]> {\n let hooksDir: string;\n try {\n const { stdout } = await runGit(cwd, [\"rev-parse\", \"--git-common-dir\"]);\n hooksDir = join(resolve(cwd, stdout.trim()), \"hooks\");\n } catch {\n return [];\n }\n try {\n return (await readdir(hooksDir)).filter((name) => !name.endsWith(\".sample\")).sort();\n } catch {\n return [];\n }\n}\n\n/**\n * True when a named hook file on disk is the one Arcane wrote, byte for byte.\n *\n * Existence alone is not enforcement: a zero-byte file, or one edited down to\n * `exit 0`, leaves the config pointing at a hook that blocks nothing while\n * `doctor` reports a pass. That is the same declaration-versus-enforcement\n * confusion review already found one level up, so the check compares content --\n * which `installHook` already needed for its `already-ours` decision.\n */\nasync function hookFileMatches(cwd: string, hookName: string, body: string): Promise<boolean> {\n const hookPath = await hookFilePath(cwd, hookName);\n if (!(await fileExists(hookPath))) return false;\n try {\n if ((await readFile(hookPath, \"utf-8\")) !== body) return false;\n } catch {\n return false;\n }\n\n // On POSIX, git silently skips a hook that is not executable, so the right\n // body in a non-executable file is still not enforcement. Git for Windows\n // does not consult the bit, and chmod there is largely advisory, so checking\n // it would produce a false \"not enforced\" for a hook that demonstrably fires.\n if (process.platform === \"win32\") return true;\n try {\n await access(hookPath, constants.X_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Removes a named hook's wiring. Leaves a foreign `core.hooksPath` untouched.\n *\n * Only unclaims `core.hooksPath` itself once NO Arcane-installed hook remains\n * in the shared directory: since ARC-037, `.arcane/hooks/` can hold more than\n * one hook (pre-push and pre-commit), and removing one must not silently\n * disable a sibling that still needs the same claimed path. Verified rather\n * than assumed by re-listing the directory after deleting -- not by counting\n * known hook names, which this module has no reason to enumerate.\n */\nexport async function removeHook(cwd: string, hookName: string): Promise<void> {\n const existing = await readHooksPath(cwd);\n if (existing === undefined || existing.unreadable === true) return;\n const root = await repositoryRoot(cwd);\n if (!isArcaneHooksPath(root, existing.value)) return;\n if (existing.scope !== \"local\" && existing.scope !== \"worktree\") return;\n\n // Remove the hook file first. Leaving it behind means a later `spell init`\n // that re-points core.hooksPath silently re-arms a block the operator\n // lifted.\n try {\n await rm(await hookFilePath(cwd, hookName), { force: true });\n } catch {\n // Non-fatal: if core.hooksPath ends up unset below, git no longer reads\n // this directory anyway.\n }\n\n const hooksDir = join(root, ARCANE_HOOKS_DIR);\n let remaining: string[] = [];\n try {\n remaining = await readdir(hooksDir);\n } catch {\n remaining = [];\n }\n if (remaining.length > 0) return; // a sibling hook still needs core.hooksPath\n\n // Unset at the scope the value actually lives in. `--local` cannot touch a\n // per-worktree `config.worktree` value, so accepting worktree scope above and\n // then unsetting locally left the hook fully in force while `unblock-push`\n // printed \"Push unblocked\".\n const scopeFlag = existing.scope === \"worktree\" ? \"--worktree\" : \"--local\";\n try {\n await runGit(cwd, [\"config\", scopeFlag, \"--unset\", \"core.hooksPath\"]);\n } catch {\n // Already unset; nothing to undo.\n }\n}\n\n/** Removes the pre-push hook's wiring. Thin wrapper over {@link removeHook}. */\nexport async function removePrePushHook(cwd: string): Promise<void> {\n return removeHook(cwd, \"pre-push\");\n}\n\n/** Every configured remote name, in git's own order. */\nexport async function listRemotes(cwd: string): Promise<string[]> {\n try {\n const { stdout } = await runGit(cwd, [\"remote\"]);\n return stdout\n .split(\"\\n\")\n .map((r) => r.trim())\n .filter(Boolean);\n } catch {\n return [];\n }\n}\n\n/**\n * Each remote with the URL(s) a push would actually reach.\n *\n * The `guarded` reminder exists to catch a *wrong remote*, and a bare name like\n * `origin` says nothing about where it points — which is the entire question.\n */\nexport async function pushTargets(cwd: string): Promise<{ remote: string; urls: string[] }[]> {\n const targets: { remote: string; urls: string[] }[] = [];\n for (const remote of await listRemotes(cwd)) {\n try {\n const { stdout } = await runGit(cwd, [\"remote\", \"get-url\", \"--push\", \"--all\", remote]);\n targets.push({\n remote,\n urls: stdout\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(Boolean),\n });\n } catch {\n targets.push({ remote, urls: [] });\n }\n }\n return targets;\n}\n\nexport type PushUrlStatus =\n | \"disabled\"\n | \"already-disabled\"\n | \"restored\"\n | \"nothing-recorded\"\n | \"failed\";\n\nexport interface PushUrlResult {\n remote: string;\n status: PushUrlStatus;\n /** Present only on \"failed\". Why this remote could not be covered. */\n reason?: string;\n}\n\n/**\n * Where a remote's original push URL is recorded.\n *\n * Deliberately a key *inside the remote's own section* rather than a flat\n * `arcane.originalPushUrl.<remote>`, which review broke three ways:\n *\n * - `my_remote` is a legal remote name but an illegal trailing config key\n * (that segment must be alphanumeric or `-`), so `git config` errored and\n * aborted the whole loop, leaving every later remote live while the operator\n * had been told the repository was blocked.\n * - Trailing key segments are case-INSENSITIVE, so remotes `origin` and\n * `Origin` collided on one key: one original was lost and restore pointed a\n * remote at the other's URL -- the wrong-remote push this feature exists to\n * prevent.\n * - `git remote rename` left the flat key orphaned, so restore silently found\n * nothing while `unblock-push` still reported success.\n *\n * A `remote.<name>.*` subsection has none of those problems: git accepts any\n * legal remote name there, subsection names ARE case-sensitive, and `git remote\n * rename` moves the whole section including keys it has never heard of. All\n * three verified directly against git 2.53 before this was written.\n */\nfunction originalPushUrlKey(remote: string): string {\n return `remote.${remote}.arcaneOriginalPushUrl`;\n}\n\n/** Reads every value of a possibly-multivalued local config key. */\nasync function readLocalAll(cwd: string, key: string): Promise<string[]> {\n try {\n const { stdout } = await runGit(cwd, [\"config\", \"--local\", \"--get-all\", key]);\n return stdout\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(Boolean);\n } catch {\n // Exit 1 == key absent.\n return [];\n }\n}\n\n/**\n * Every value of a multivalued key, WITH the scope each came from.\n *\n * `remote.<name>.pushurl` is multivalued and git collects values across system,\n * global and local scope. Reading only `--local` was a silent hole: a pushurl\n * configured globally stayed invisible, a local `--replace-all` *appended* the\n * sentinel instead of replacing the live URL, and because the global value sorts\n * first git delivered the push to it and only then failed on the sentinel. The\n * exit code was 128 and the history was already gone -- with `doctor` reporting\n * the repository fully covered.\n */\nasync function readScopedAll(cwd: string, key: string): Promise<{ scope: string; value: string }[]> {\n let stdout: string;\n try {\n ({ stdout } = await runGit(cwd, [\"config\", \"--show-scope\", \"--get-all\", key]));\n } catch {\n return [];\n }\n return stdout\n .split(\"\\n\")\n .filter((line) => line !== \"\")\n .map((line) => {\n // `<scope>\\t<value>`; split BEFORE trimming. Trimming first ate the\n // separator tab on an empty-valued entry (`global\\t`), which then parsed\n // as `{scope: \"unknown\", value: \"global\"}` and produced a remedy telling\n // the operator to run `git config --unknown`, which is not a command.\n const separator = line.indexOf(\"\\t\");\n if (separator === -1) return { scope: \"unknown\", value: line.trim() };\n return { scope: line.slice(0, separator).trim(), value: line.slice(separator + 1).trim() };\n });\n}\n\n/** Push URLs git would actually use for a remote, across every config scope. */\nasync function effectivePushUrls(cwd: string, remote: string): Promise<string[]> {\n const scoped = await readScopedAll(cwd, `remote.${remote}.pushurl`);\n return scoped.map((entry) => entry.value);\n}\n\n/**\n * Points every remote's PUSH url at a sentinel, so `git push` fails at the\n * transport layer. Fetch is unaffected: fetch URLs are left alone, so a blocked\n * repository can still pull.\n *\n * Applies to ALL remotes, not just `origin` — a repository commonly has an\n * `upstream` or `backup` too, and protecting only one of them protects nothing\n * in particular.\n *\n * Each original is recorded in `arcane.originalPushUrl.<remote>` so\n * `spell unblock-push` restores exactly what was there rather than guessing\n * from the fetch URL, which is legitimately allowed to differ.\n */\nexport async function disablePushUrls(cwd: string): Promise<PushUrlResult[]> {\n const results: PushUrlResult[] = [];\n for (const remote of await listRemotes(cwd)) {\n // One remote must never take the others down with it. The previous loop let\n // a single `git config` error propagate, so an oddly-named remote left every\n // remote after it in git's ordering completely unprotected -- silently, in a\n // repository the operator had just been told was blocked. Failures are now\n // recorded per remote and reported, and the loop continues.\n try {\n results.push(await disableOneRemote(cwd, remote));\n } catch (error) {\n results.push({ remote, status: \"failed\", reason: describeError(error) });\n }\n }\n return results;\n}\n\nasync function disableOneRemote(cwd: string, remote: string): Promise<PushUrlResult> {\n const scoped = await readScopedAll(cwd, `remote.${remote}.pushurl`);\n\n // A pushurl set outside this repository cannot be neutralised from inside it.\n // Config is additive for multivalued keys: a local write ADDS to git's list,\n // it cannot subtract the outside value, and the outside value sorts first --\n // so the push is delivered and only then fails on the sentinel. Refuse and say\n // so, rather than writing a sentinel that makes the repository look covered\n // while the history walks out the front door.\n // `worktree` scope is writable from inside the repository, so it is ours to\n // manage, not foreign. Only genuinely outer scopes are unreachable.\n const OVERRIDABLE = new Set([\"local\", \"worktree\"]);\n const foreign = scoped.filter(\n (entry) => !OVERRIDABLE.has(entry.scope) && entry.value !== DISABLED_PUSH_URL,\n );\n if (foreign.length > 0) {\n const scopes = [...new Set(foreign.map((entry) => entry.scope))];\n const where = scopes.join(\", \");\n const flag = scopes[0] === \"unknown\" ? \"<scope>\" : `--${scopes[0]}`;\n return {\n remote,\n status: \"failed\",\n reason:\n `a push URL for this remote is configured at ${where} scope, which this repository cannot ` +\n `override — git would still deliver the push there. Remove it with ` +\n `\\`git config ${flag} --unset-all remote.${remote}.pushurl\\` and re-apply.`,\n };\n }\n\n const currentPushUrls = scoped.map((entry) => entry.value);\n if (currentPushUrls.length === 1 && currentPushUrls[0] === DISABLED_PUSH_URL) {\n return { remote, status: \"already-disabled\" };\n }\n\n const key = originalPushUrlKey(remote);\n // Record what was there BEFORE overwriting, and only if we have not already\n // recorded it -- otherwise a second disable would enshrine the sentinel as the\n // \"original\" and make restore impossible.\n if ((await readLocalAll(cwd, key)).length === 0 && !(await hadNoPushUrl(cwd, remote))) {\n if (currentPushUrls.length > 0) {\n await runGit(cwd, [\"config\", \"--local\", \"--replace-all\", key, currentPushUrls[0]!]);\n for (const extra of currentPushUrls.slice(1)) {\n await runGit(cwd, [\"config\", \"--local\", \"--add\", key, extra]);\n }\n } else {\n // A remote with no pushurl key pushes to its fetch URL. Record that as a\n // separate marker rather than a magic URL value, so restore removes the\n // key instead of pinning one that was never there -- and so a remote whose\n // genuine URL happened to equal the marker cannot be misread as \"none\".\n await runGit(cwd, [\"config\", \"--local\", NO_PUSH_URL_MARKER(remote), \"true\"]);\n }\n }\n\n // `--replace-all` rather than `git remote set-url --push`: a mirror remote\n // with two push URLs makes set-url refuse outright (\"has multiple values\"),\n // which used to abort the run and leave BOTH mirrors pushable.\n await runGit(cwd, [\n \"config\",\n \"--local\",\n \"--replace-all\",\n `remote.${remote}.pushurl`,\n DISABLED_PUSH_URL,\n ]);\n\n // Re-read what git ACTUALLY resolves, rather than trusting that the write did\n // what we intended. The scope-based refusal above catches the cases git labels\n // as an outer scope, but not all of them: a value contributed by a file the\n // repository `include`s is reported as scope `local`, survives\n // `--replace-all`, and — if the include precedes the remote section — sorts\n // first and delivers the push. Verifying the outcome closes that whole class\n // rather than the enumerated members of it, which is the difference between\n // this check and the last three rounds of enumerating members.\n const after = await effectivePushUrls(cwd, remote);\n if (after.length !== 1 || after[0] !== DISABLED_PUSH_URL) {\n const live = after.filter((url) => url !== DISABLED_PUSH_URL);\n return {\n remote,\n status: \"failed\",\n reason:\n `the sentinel was written but git still resolves a live push URL for this remote ` +\n `(${live.join(\", \")}). It most likely comes from a file this repository \\`include\\`s, ` +\n `which \\`--replace-all\\` cannot remove. Run \\`git config --show-origin --get-all ` +\n `remote.${remote}.pushurl\\` to find the file, and clear it there.`,\n };\n }\n return { remote, status: \"disabled\" };\n}\n\n/**\n * Remotes whose push URL is NOT fully disabled. Empty when fully covered.\n *\n * A remote counts as open if ANY of its push URLs is live — a mirror with one\n * blocked and one live URL still delivers the push.\n */\nexport async function undisabledRemotes(cwd: string): Promise<string[]> {\n const open: string[] = [];\n for (const remote of await listRemotes(cwd)) {\n // Effective, not local: a pushurl inherited from global or system scope is\n // a live delivery path, and reading only local scope reported such a remote\n // as covered while `--no-verify` alone still delivered the history.\n const urls = await effectivePushUrls(cwd, remote);\n if (urls.length === 0 || urls.some((url) => url !== DISABLED_PUSH_URL)) open.push(remote);\n }\n return open;\n}\n\n/**\n * Remotes still carrying the sentinel push URL.\n *\n * The inverse of `undisabledRemotes`, and needed after an unblock: if a remote\n * was renamed while blocked, its recorded original moved with it but a different\n * remote can be left holding the sentinel with nothing to restore from. Checked\n * directly rather than inferred from what the restore believes it did.\n */\nexport async function blockedRemotes(cwd: string): Promise<string[]> {\n const blocked: string[] = [];\n for (const remote of await listRemotes(cwd)) {\n const urls = await effectivePushUrls(cwd, remote);\n if (urls.some((url) => url === DISABLED_PUSH_URL)) blocked.push(remote);\n }\n return blocked;\n}\n\n/** Restores every recorded push URL. Used only by `spell unblock-push`. */\nexport async function restorePushUrls(cwd: string): Promise<PushUrlResult[]> {\n const results: PushUrlResult[] = [];\n for (const remote of await listRemotes(cwd)) {\n try {\n results.push(await restoreOneRemote(cwd, remote));\n } catch (error) {\n results.push({ remote, status: \"failed\", reason: describeError(error) });\n }\n }\n return results;\n}\n\nasync function restoreOneRemote(cwd: string, remote: string): Promise<PushUrlResult> {\n const key = originalPushUrlKey(remote);\n let recorded = await readLocalAll(cwd, key);\n let hadNone = await hadNoPushUrl(cwd, remote);\n\n if (recorded.length === 0 && !hadNone) {\n const legacy = await readLegacyRecord(cwd, remote);\n if (legacy.status !== \"usable\") return { remote, status: legacy.status, reason: legacy.reason };\n recorded = legacy.values;\n hadNone = false;\n }\n\n if (hadNone) {\n // `--unset-all` exits 5 when the key is already absent. That is the goal\n // state, not a failure -- letting it throw skipped the stale-key cleanup\n // below, and a surviving `arcaneHadNoPushUrl` marker made the NEXT block\n // record nothing and the next restore delete a genuine push URL.\n await unsetIgnoringMissing(cwd, `remote.${remote}.pushurl`);\n } else {\n await runGit(cwd, [\n \"config\",\n \"--local\",\n \"--replace-all\",\n `remote.${remote}.pushurl`,\n recorded[0]!,\n ]);\n for (const extra of recorded.slice(1)) {\n await runGit(cwd, [\"config\", \"--local\", \"--add\", `remote.${remote}.pushurl`, extra]);\n }\n }\n\n // Clear our bookkeeping only on success. Doing this unconditionally would\n // destroy a record we had *deliberately* declined to apply -- the legacy-key\n // refusal above prints the value for the operator to apply by hand, and\n // wiping it in the same breath makes that instruction unfollowable.\n //\n // The stale-marker hazard this used to guard against is closed at its source:\n // `unsetIgnoringMissing` treats git's exit 5 (\"key already absent\") as\n // success, so the throw that previously skipped this cleanup no longer\n // happens.\n for (const staleKey of [key, NO_PUSH_URL_MARKER(remote), `arcane.originalPushUrl.${remote}`]) {\n try {\n await unsetIgnoringMissing(cwd, staleKey);\n } catch {\n // Non-fatal: the URL is restored, which is what matters.\n }\n }\n return { remote, status: \"restored\" };\n}\n\n/**\n * Unsets a config key, treating \"it was already absent\" as success.\n *\n * `git config --unset-all` exits **5** for a missing key. Letting that throw\n * turned a no-op into a reported failure and, worse, skipped whatever cleanup\n * followed it.\n */\nasync function unsetIgnoringMissing(cwd: string, key: string): Promise<void> {\n try {\n await runGit(cwd, [\"config\", \"--local\", \"--unset-all\", key]);\n } catch (error) {\n if ((error as { code?: unknown }).code !== 5) throw error;\n }\n}\n\nasync function hadNoPushUrl(cwd: string, remote: string): Promise<boolean> {\n return (await readLocalAll(cwd, NO_PUSH_URL_MARKER(remote)))[0] === \"true\";\n}\n\n/**\n * Reads a record left by the released `0.20.0`, which stored originals in a flat\n * `arcane.originalPushUrl.<remote>` key -- and only applies it when it can be\n * trusted.\n *\n * Applying it unconditionally reintroduced, for exactly the population told to\n * upgrade, the wrong-remote push this release fixes. Two ways, both reproduced:\n *\n * - Trailing config-key segments are case-insensitive, so `0.20.0` wrote one\n * key for both `origin` and `Origin` and only the last writer survived.\n * Restoring it points one remote at the OTHER remote's URL, reported as a\n * clean success.\n * - Unlike a `remote.<name>.*` key, the flat key survives `git remote remove`.\n * A remote deleted and re-added to a different URL gets silently restored to\n * the old target.\n *\n * So the record is used only when the remote is still carrying OUR sentinel\n * (which a re-added remote is not) and no two remote names collide\n * case-insensitively. Otherwise the value is reported for the operator to apply\n * by hand: a restore that might pick the wrong remote is worse than none.\n */\nasync function readLegacyRecord(\n cwd: string,\n remote: string,\n): Promise<\n | { status: \"usable\"; values: string[] }\n | { status: \"nothing-recorded\" | \"failed\"; reason?: string }\n> {\n const values = await readLocalAll(cwd, `arcane.originalPushUrl.${remote}`);\n if (values.length === 0) return { status: \"nothing-recorded\" };\n\n const current = await effectivePushUrls(cwd, remote);\n if (!current.includes(DISABLED_PUSH_URL)) {\n return {\n status: \"failed\",\n reason:\n `found a push URL recorded by 0.20.0 (\"${values.join(\", \")}\") but this remote is not ` +\n \"currently blocked by Arcane, so the record may belong to a different remote of the same \" +\n \"name. Not applying it — set the URL yourself if it is correct.\",\n };\n }\n\n const names = await listRemotes(cwd);\n const collides = names.some(\n (other) => other !== remote && other.toLowerCase() === remote.toLowerCase(),\n );\n if (collides) {\n return {\n status: \"failed\",\n reason:\n `this repository has remotes whose names differ only by case, and 0.20.0 stored their ` +\n `original push URLs under one shared key, so the recorded value (\"${values.join(\", \")}\") ` +\n \"cannot be attributed to a specific remote. Not applying it — set the URLs yourself.\",\n };\n }\n\n return { status: \"usable\", values };\n}\n\nfunction describeError(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return message.split(\"\\n\")[0]!.trim();\n}\n","import { execFile } from \"node:child_process\";\n\nexport type GitRepositoryState =\n | { status: \"ready\"; uncommittedChanges: number }\n | { status: \"not-repository\" }\n | { status: \"no-commits\" };\n\nexport type GitCommandClass = \"read\" | \"write\" | \"network\";\n\nexport interface RunGitOptions {\n /** Override auto-classification from the subcommand. */\n commandClass?: GitCommandClass;\n /** Override the command class's default timeout, in milliseconds. */\n timeoutMs?: number;\n}\n\nexport interface GitResult {\n stdout: string;\n stderr: string;\n}\n\n/**\n * EF-20: thrown when a `git` subprocess exceeds its runGit-assigned timeout\n * and Node reports the resulting kill via `error.killed`. Note this reflects\n * \"the child was killed by a signal Node sent it,\" which today only ever\n * happens through runGit's own timeout, since no caller retains the\n * underlying ChildProcess to kill it independently -- if a future caller\n * gains that ability, `error.killed` alone would no longer distinguish\n * runGit's timeout from an external kill of the same handle.\n */\nexport class GitTimeoutError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"GitTimeoutError\";\n }\n}\n\nconst NETWORK_SUBCOMMANDS = new Set([\"fetch\", \"pull\", \"push\", \"clone\", \"ls-remote\", \"send-email\"]);\n\nconst WRITE_SUBCOMMANDS = new Set([\n \"init\",\n \"commit\",\n \"add\",\n \"checkout\",\n \"switch\",\n \"merge\",\n \"rebase\",\n \"reset\",\n \"tag\",\n \"mv\",\n \"rm\",\n \"cherry-pick\",\n \"revert\",\n \"stash\",\n \"apply\",\n \"am\",\n \"restore\",\n \"submodule\",\n \"sparse-checkout\",\n \"maintenance\",\n \"notes\",\n]);\n\n// These subcommands can be read-only (`branch --list`, `config --get`) or\n// mutating (`branch -m`, `config user.name x`) depending on flags. Classified\n// as \"write\" -- the safer over-estimate: a read given write's longer timeout\n// just waits a little longer, while a write given read's shorter timeout\n// risks being killed mid-operation.\nconst AMBIGUOUS_AS_WRITE = new Set([\"branch\", \"config\", \"remote\", \"worktree\"]);\n\n// Known read-only subcommands get the fast 15s budget explicitly. Anything\n// NOT in this list, NOT in WRITE_SUBCOMMANDS/AMBIGUOUS_AS_WRITE, and NOT in\n// NETWORK_SUBCOMMANDS is a subcommand this module doesn't recognize at all --\n// that case defaults to \"write\" (see classifyGitCommand), the safer\n// over-estimate for a genuinely unknown operation.\nconst READ_SUBCOMMANDS = new Set([\n \"status\",\n \"rev-parse\",\n \"log\",\n \"diff\",\n \"show\",\n \"describe\",\n \"cat-file\",\n \"ls-files\",\n \"ls-tree\",\n \"symbolic-ref\",\n \"show-ref\",\n \"for-each-ref\",\n \"merge-base\",\n \"blame\",\n \"shortlog\",\n \"grep\",\n \"reflog\",\n \"diff-tree\",\n \"rev-list\",\n \"name-rev\",\n \"count-objects\",\n \"verify-commit\",\n \"verify-tag\",\n \"help\",\n \"version\",\n]);\n\n// Global options that take their value as a SEPARATE following token (not\n// `--opt=value`). Without skipping the value too, `args.find(a =>\n// !a.startsWith(\"-\"))` would grab the value itself (e.g. \"user.name=x\" from\n// `-c user.name=x commit`) and misclassify the real subcommand that follows.\nconst GLOBAL_FLAGS_WITH_SEPARATE_VALUE = new Set([\"-c\", \"-C\"]);\n\nconst DEFAULT_TIMEOUTS_MS: Record<GitCommandClass, number> = {\n read: 15_000,\n write: 30_000,\n network: 120_000,\n};\n\n/**\n * Classify a git invocation by its first real subcommand token, skipping any\n * leading global flags (and, for `-c`/`-C`, their separate-token values) to\n * find it. Exported for tests.\n */\nexport function classifyGitCommand(args: string[]): GitCommandClass {\n let subcommand: string | undefined;\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (GLOBAL_FLAGS_WITH_SEPARATE_VALUE.has(arg)) {\n i++; // skip this flag's value token too\n continue;\n }\n if (arg.startsWith(\"-\")) continue;\n subcommand = arg;\n break;\n }\n if (!subcommand) return \"read\";\n if (NETWORK_SUBCOMMANDS.has(subcommand)) return \"network\";\n if (WRITE_SUBCOMMANDS.has(subcommand) || AMBIGUOUS_AS_WRITE.has(subcommand)) return \"write\";\n if (READ_SUBCOMMANDS.has(subcommand)) return \"read\";\n // A subcommand this module doesn't recognize at all: default to \"write\"\n // (the safer over-estimate) rather than \"read\" -- see READ_SUBCOMMANDS.\n return \"write\";\n}\n\n/**\n * EF-20/EF-13: the non-interactive execution environment applied to every\n * git invocation. GIT_TERMINAL_PROMPT and GCM_INTERACTIVE suppress credential\n * and terminal prompts; GIT_OPTIONAL_LOCKS disables git's speculative index\n * lock during `status` (git-config(1): \"core.optionalLocks\" affects only\n * status/update-index, so this is safe to apply blanket rather than per\n * command class) -- the mitigation for EF-13's stranded-lock report on\n * filesystems that reject unlink. Exported for tests.\n */\nexport function buildGitEnv(): NodeJS.ProcessEnv {\n return {\n ...process.env,\n GIT_TERMINAL_PROMPT: \"0\",\n GCM_INTERACTIVE: \"Never\",\n GIT_OPTIONAL_LOCKS: \"0\",\n };\n}\n\n/**\n * Single chokepoint for every production `git` invocation. Closes stdin\n * immediately (EF-20: an interactive prompt reading from stdin gets instant\n * EOF instead of hanging on an open, unwritten pipe) and enforces a\n * command-class-scoped timeout (EF-20: no git operation can block an\n * autonomous session indefinitely with no completion signal).\n */\nexport function runGit(cwd: string, args: string[], options: RunGitOptions = {}): Promise<GitResult> {\n const commandClass = options.commandClass ?? classifyGitCommand(args);\n // Falls back to the \"write\" budget if commandClass ever reaches here as\n // something outside the GitCommandClass union (only reachable from an\n // untyped caller) -- an undefined timeoutMs would mean NO timeout at all,\n // silently defeating the one guarantee this module exists to provide.\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUTS_MS[commandClass] ?? DEFAULT_TIMEOUTS_MS.write;\n\n return new Promise((resolve, reject) => {\n const child = execFile(\n \"git\",\n args,\n {\n cwd,\n env: buildGitEnv(),\n timeout: timeoutMs,\n // SIGTERM (Node's default) rather than SIGKILL: gives git a chance\n // to run its own cleanup on POSIX, relevant to EF-20's own concern\n // about a killed operation leaving refs/locks in an uncertain state.\n // Moot on Windows -- Node docs: both map to an abrupt TerminateProcess\n // there -- but this module isn't Windows-gated.\n killSignal: \"SIGTERM\",\n windowsHide: true,\n encoding: \"utf8\",\n },\n (error, stdout, stderr) => {\n if (error) {\n if (error.killed) {\n reject(\n new GitTimeoutError(\n // NOTE: embeds the raw args, including any secrets a future\n // network-class caller might pass (e.g. a credentialed\n // clone URL). No current caller does; redact before one does.\n `git ${args.join(\" \")} timed out after ${timeoutMs}ms (class: ${commandClass})`,\n { cause: error },\n ),\n );\n return;\n }\n reject(error);\n return;\n }\n resolve({ stdout, stderr });\n },\n );\n // EF-20: never leave stdin as an open, unread pipe -- see module doc.\n child.stdin?.end();\n });\n}\n\n/**\n * Returns the repository state required before a destructive managed update.\n */\nexport async function inspectGitRepository(cwd: string): Promise<GitRepositoryState> {\n try {\n const { stdout } = await runGit(cwd, [\"rev-parse\", \"--is-inside-work-tree\"]);\n if (stdout.trim() !== \"true\") {\n return { status: \"not-repository\" };\n }\n } catch {\n return { status: \"not-repository\" };\n }\n\n try {\n await runGit(cwd, [\"rev-parse\", \"--verify\", \"HEAD\"]);\n } catch {\n return { status: \"no-commits\" };\n }\n\n const { stdout } = await runGit(cwd, [\"status\", \"--porcelain\", \"-uall\"]);\n const lines = stdout.trim();\n return {\n status: \"ready\",\n uncommittedChanges: lines.length === 0 ? 0 : lines.split(\"\\n\").length,\n };\n}\n\n/**\n * Returns the number of uncommitted changes in the working tree, or 0\n * if the directory is not a git repo or git is not installed.\n */\nexport async function countUncommittedChanges(cwd: string): Promise<number> {\n try {\n const { stdout } = await runGit(cwd, [\"status\", \"--porcelain\", \"-uall\"]);\n const lines = stdout.trim();\n return lines.length === 0 ? 0 : lines.split(\"\\n\").length;\n } catch {\n return 0;\n }\n}\n\nexport interface UnbornBranchCorrection {\n corrected: boolean;\n from?: string;\n to: \"main\";\n /**\n * Set when the correction was declined because the target ref could not be\n * read (a broken/unreadable `refs/heads/main`) rather than because it was\n * absent or already healthy. Callers should surface this: the repo has a\n * real integrity problem the operator will want to know about, but it is\n * not severe enough to abort an install over a cosmetic branch rename.\n */\n blockedReason?: \"target-unreadable\";\n}\n\n/**\n * EF-05: on an unborn repository (git init has run, no commit yet) whose\n * HEAD currently targets exactly \"master\" -- the reported Git for Windows\n * system-default leak (init.defaultBranch=master at the system config\n * level) -- repoint it to \"main\" via `symbolic-ref`. Safe because no commit\n * objects exist yet to conflict with; equivalent to what `git init -b main`\n * does internally. Any OTHER branch name, including one an operator\n * deliberately chose, is left untouched -- this corrects the specific\n * reported default-leak, not a general \"Arcane requires main\" policy.\n * No-op (not corrected) if `cwd` isn't an unborn repo at all.\n */\nexport async function correctUnbornMasterDefault(cwd: string): Promise<UnbornBranchCorrection> {\n let current: string;\n try {\n const { stdout } = await runGit(cwd, [\"symbolic-ref\", \"--short\", \"HEAD\"]);\n current = stdout.trim();\n } catch {\n return { corrected: false, to: \"main\" };\n }\n\n if (current !== \"master\") {\n return { corrected: false, to: \"main\" };\n }\n\n // Verify unborn-ness internally rather than trusting the caller: on a\n // BORN repo already on \"master\", `symbolic-ref HEAD refs/heads/main`\n // would detach HEAD's branch pointer from its commit history without\n // moving any commits -- `main` would exist as an empty ref while every\n // real commit stays reachable only via the abandoned `master` ref. This\n // check is the same one `inspectGitRepository` uses to distinguish\n // \"no-commits\" from \"ready\".\n try {\n await runGit(cwd, [\"rev-parse\", \"--verify\", \"HEAD\"]);\n return { corrected: false, to: \"main\" }; // HEAD resolves -- repo is born, don't touch it\n } catch {\n // rev-parse --verify HEAD failing IS the unborn signal -- proceed.\n }\n\n // Also verify the TARGET doesn't already exist with real history.\n // Confirming the source is unborn is not sufficient: if `refs/heads/main`\n // already resolves (e.g. created earlier in this repo, or shared across\n // git worktrees -- refs/heads/* is shared while HEAD is per-worktree, so\n // an unborn \"master\" HEAD in one worktree can coexist with a fully born\n // \"main\" from another), repointing HEAD onto it would silently attach\n // whatever's currently staged/uncommitted on the unborn HEAD to main's\n // real commit history -- a history splice, not a safe unborn-HEAD\n // repoint, and the next `git commit` an operator runs would commit it.\n // Distinguishing \"absent\" from \"unreadable\" needs stdout/stderr, not an\n // exit code. Verified empirically against git 2.x -- BOTH `rev-parse\n // --verify` and `show-ref --verify --quiet` return the same nonzero status\n // for a corrupt ref as for a missing one (128 and 1 respectively), so\n // either one behind a bare catch reads \"this branch is broken\" as \"this\n // branch does not exist\" and repoints HEAD onto real history anyway.\n //\n // `for-each-ref` usually exits 0 and reports the state through its streams:\n // healthy -> stdout = the object id, stderr empty\n // corrupt -> stdout empty, stderr \"warning: ignoring broken ref ...\"\n // absent -> stdout empty, stderr empty\n // Only the third is safe to treat as absence, and even it needs a second\n // probe (see the symref check below). The stderr test is on emptiness, not\n // on git's English wording, so a translated locale can't defeat it.\n let mainRef: { stdout: string; stderr: string };\n try {\n mainRef = await runGit(cwd, [\"for-each-ref\", \"--format=%(objectname)\", \"refs/heads/main\"]);\n } catch {\n // for-each-ref itself failed -- a corrupt .git/packed-refs exits 128, and\n // a timeout rejects too. Either way we learned nothing about whether main\n // exists, so absence is not a conclusion we're entitled to draw.\n return { corrected: false, to: \"main\", blockedReason: \"target-unreadable\" };\n }\n\n if (mainRef.stdout.trim() !== \"\") {\n return { corrected: false, to: \"main\" }; // main already exists -- don't touch it\n }\n\n if (mainRef.stderr.trim() !== \"\") {\n // Broken ref: it may still hold real history we cannot see. Fail closed\n // -- decline the correction, and tell the caller why so it can warn.\n return { corrected: false, to: \"main\", blockedReason: \"target-unreadable\" };\n }\n\n // Empty/empty is still ambiguous: a DANGLING SYMREF (refs/heads/main is\n // `ref: refs/heads/<missing>`) reports exactly the same shape as an absent\n // ref. Repointing onto it would leave HEAD on the symref's target while\n // reporting \"repointed to main\" -- untrue, even though nothing is spliced.\n // `symbolic-ref -q` is the discriminator: 0 = main exists as a symref,\n // 1 = genuinely absent. Anything else is another unreadable state.\n try {\n await runGit(cwd, [\"symbolic-ref\", \"-q\", \"refs/heads/main\"]);\n return { corrected: false, to: \"main\", blockedReason: \"target-unreadable\" };\n } catch (error) {\n if ((error as { code?: unknown }).code !== 1) {\n return { corrected: false, to: \"main\", blockedReason: \"target-unreadable\" };\n }\n // Exit 1 -- refs/heads/main genuinely does not exist. Safe to target it.\n }\n\n await runGit(cwd, [\"symbolic-ref\", \"HEAD\", \"refs/heads/main\"]);\n return { corrected: true, from: current, to: \"main\" };\n}\n\nexport type PullRebaseResult =\n | { action: \"set\" }\n | { action: \"already-set\" }\n | { action: \"explicit-false-preserved\" };\n\n/**\n * EF-32: ensure `pull.rebase` is set at the repository-LOCAL level so the\n * mandated rebase-and-fast-forward workflow (git-conventions.md) doesn't\n * silently depend on the operator's machine-wide default (Git for Windows\n * ships pull.rebase=false at the system level). Distinguishes \"unset\n * locally\" (safe to set -- it was only ever inheriting a machine default)\n * from \"explicitly set locally, even to false\" (never silently overridden\n * -- the caller is expected to surface this as a warning instead).\n */\nexport async function ensureLocalPullRebase(cwd: string): Promise<PullRebaseResult> {\n let rawLocalValue: string | undefined;\n try {\n const { stdout } = await runGit(cwd, [\"config\", \"--local\", \"--get\", \"pull.rebase\"]);\n rawLocalValue = stdout.trim();\n } catch {\n rawLocalValue = undefined; // nothing set locally at all (may be inherited from global/system)\n }\n\n if (rawLocalValue === undefined) {\n await runGit(cwd, [\"config\", \"--local\", \"pull.rebase\", \"true\"]);\n return { action: \"set\" };\n }\n\n // Something IS set locally. Determine whether it's a falsy boolean via\n // git's own boolean parser (`--type=bool` normalizes any of git's valid\n // spellings -- true/yes/on/1 and false/no/off/0 -- to canonical\n // \"true\"/\"false\"), rather than hand-matching the literal string \"false\"\n // and missing every other valid spelling. A value `--type=bool` can't\n // coerce (e.g. \"merges\" or \"interactive\" -- both valid, deliberate\n // pull.rebase settings) means the operator explicitly chose something\n // else entirely; that's still an explicit local choice and must never be\n // overwritten, so it's treated the same as \"already-set\".\n try {\n const { stdout } = await runGit(cwd, [\"config\", \"--local\", \"--type=bool\", \"--get\", \"pull.rebase\"]);\n if (stdout.trim() === \"false\") {\n return { action: \"explicit-false-preserved\" };\n }\n return { action: \"already-set\" };\n } catch {\n return { action: \"already-set\" };\n }\n}\n","/**\n * Regex-based credential-pattern denylist, sharing denylist-scan.ts's generic\n * file-walking/matching engine (also used by org-token-lint.ts and spell\n * ward). Extracted from scripts/copy-assets.ts (ARC-037) so the same pattern\n * set backs both the pre-existing src/assets/-scoped copy-time scan and the\n * repository-wide CI backstop / pre-commit hook this ADR adds.\n *\n * Patterns are deliberately conservative -- common credential shapes. A false\n * positive blocks a build or a commit, which is the safe direction to fail.\n */\nimport type { DenylistRule } from \"./denylist-scan.js\";\nimport { installHook, isHookInstalled, removeHook, type HookInstallOutcome } from \"./push-safety.js\";\n\nexport const SECRETS_RULES: DenylistRule[] = [\n { label: \"api-key\", pattern: /API[_-]KEY\\s*[:=]\\s*\\S+/i },\n // Case-sensitive and requiring an all-caps/underscore identifier (SECRET,\n // MY_SECRET, API_SECRET_KEY...) -- the real config/env-var convention for a\n // credential-holding key. Widening this repository-wide (ARC-037 decision 3)\n // surfaced that the original case-insensitive form matched ANY lowercase\n // `secret`/`token` code identifier (e.g. `const token = value.trim();`),\n // which is overwhelmingly a parsed/resolved value, never a literal\n // credential. The `(?!\\$?\\{)` guard additionally excludes any\n // brace-delimited placeholder -- GitHub Actions/templating references\n // (`TOKEN: ${{ secrets.X }}`, a reference to a secret store, never the\n // secret itself) and this codebase's own documented `{UPPER_SNAKE}`\n // placeholder convention (denylist-scan.ts's `scanFile` already strips\n // those before matching for the sibling org-token scan; a bare single\n // brace, with no `scanFile`-style stripping in the copy-time call path,\n // needed the same exclusion here rather than only the double-brace case).\n // A minimum length of 8 further excludes short non-secret values like\n // `write` (`id-token: write`).\n { label: \"generic-secret\", pattern: /\\b[A-Z0-9_]*SECRET[A-Z0-9_]*\\s*[:=]\\s*(?!\\$?\\{)\\S{8,}/ },\n { label: \"generic-token\", pattern: /\\b[A-Z0-9_]*TOKEN[A-Z0-9_]*\\s*[:=]\\s*(?!\\$?\\{)\\S{8,}/ },\n { label: \"bearer-token\", pattern: /Bearer\\s+[A-Za-z0-9._~+/-]{20,}/ }, // real tokens are long\n { label: \"openai-key\", pattern: /sk-[A-Za-z0-9]{20,}/ },\n { label: \"pem-key\", pattern: /-----BEGIN [A-Z ]+-----/ },\n { label: \"slack-token\", pattern: /xox[bpars]-[A-Za-z0-9-]+/ },\n { label: \"aws-access-key\", pattern: /AKIA[0-9A-Z]{16}/ },\n { label: \"github-pat\", pattern: /ghp_[A-Za-z0-9]{36}/ },\n];\n\n/**\n * Back-compat plain-pattern list for `scripts/copy-assets.ts`'s existing\n * per-line copy-time scan, which predates `DenylistRule` and iterates raw\n * `RegExp`s directly. Derived from `SECRETS_RULES` so there is exactly one\n * place these patterns are authored.\n */\nexport const SECRETS_PATTERNS: RegExp[] = SECRETS_RULES.map((rule) => rule.pattern);\n\n// ─── Consumer-facing pre-commit hook (ARC-037 decision 2 / decision 4b) ──────\n// This repo's OWN pre-commit scan is a Husky step (.husky/pre-commit calls\n// `npm run doctor:leaks`); a fresh consumer repo has no Husky. This installs\n// the same `spell doctor --leaks` check via push-safety.ts's generalized,\n// push_policy-independent hook-install path (ARC-037 decision 2) instead --\n// every profile gets it regardless of push_policy, since credential leakage\n// is a risk independent of whether a repository's history may reach a\n// remote. Mandatory rather than an opt-in prompt: the check is cheap, local,\n// and `--no-verify`-bypassable by design (decision 6) -- the repository-wide\n// CI backstop this ADR also adds is the real, unavoidable defense, not this.\n\nexport const SECRETS_PRECOMMIT_HOOK_NAME = \"pre-commit\";\n\n/**\n * Pure code, not a shipped asset file -- the same shape as push-safety.ts's\n * own PRE_PUSH_HOOK_BODY. `spell` is expected on PATH per the documented\n * global-install pattern (README.md); a missing binary skips the scan rather\n * than blocking the commit; a misconfigured PATH has nothing to do with\n * whatever the operator is actually committing.\n */\nexport const SECRETS_PRECOMMIT_HOOK_BODY = `#!/bin/sh\n# Installed by Arcane (ARC-037) to scan staged content for accidentally\n# committed credentials before they enter history.\n#\n# This is deliberately not tamper-proof: \\`git commit --no-verify\\` skips it\n# entirely. The real defense is the repository-wide scan Arcane's own build\n# runs in CI on every push -- this hook exists to catch a leak locally, for\n# free, before it ever reaches a commit.\nif ! command -v spell >/dev/null 2>&1; then\n echo \"arcane: 'spell' not found on PATH -- skipping secrets scan (see: npm install -g arcane-cli)\" >&2\n exit 0\nfi\nspell doctor --leaks\n`;\n\nexport async function installSecretsPrecommitHook(cwd: string): Promise<HookInstallOutcome> {\n return installHook(cwd, SECRETS_PRECOMMIT_HOOK_NAME, SECRETS_PRECOMMIT_HOOK_BODY);\n}\n\nexport async function isSecretsPrecommitHookInstalled(cwd: string): Promise<boolean> {\n return isHookInstalled(cwd, SECRETS_PRECOMMIT_HOOK_NAME, SECRETS_PRECOMMIT_HOOK_BODY);\n}\n\nexport async function removeSecretsPrecommitHook(cwd: string): Promise<void> {\n return removeHook(cwd, SECRETS_PRECOMMIT_HOOK_NAME);\n}\n","import { join } from \"node:path\";\nimport { copyFile, copyDirectory } from \"../modules/copier.js\";\nimport {\n readManifest,\n writeManifest,\n addComponent,\n hasComponent,\n ManifestNotFoundError,\n} from \"../modules/manifest.js\";\nimport { getComponent, ComponentNotFoundError } from \"../modules/registry.js\";\nimport type { InstalledComponent, SpellAddOptions } from \"../types.js\";\n\n/**\n * Runs the `spell add <component>` command.\n *\n * @param name Component name to install\n * @param options CLI flags (force, dryRun)\n * @param targetDir Directory containing the Arcane installation\n * @param assetsDir Path to the bundled assets root\n * @param packageVersion Current package version string\n */\nexport async function runAdd(\n name: string,\n options: SpellAddOptions,\n targetDir: string,\n assetsDir: string,\n packageVersion: string,\n): Promise<void> {\n // Read existing manifest (must be initialized first)\n let manifest;\n try {\n manifest = await readManifest(targetDir);\n } catch (err) {\n if (err instanceof ManifestNotFoundError) {\n console.error(\n 'Not initialized. Run \"spell init\" first before adding components.',\n );\n process.exit(1);\n return; // guard: process.exit is mocked in tests\n }\n throw err;\n }\n\n // Look up the component in the registry\n let component;\n try {\n component = getComponent(name);\n } catch (err) {\n if (err instanceof ComponentNotFoundError) {\n console.error(err.message);\n process.exit(1);\n return; // guard: process.exit is mocked in tests\n }\n throw err;\n }\n\n // Check if already installed\n if (hasComponent(manifest, name)) {\n console.log(\n `Component \"${name}\" is already installed. Use \"spell update\" to update it.`,\n );\n return;\n }\n\n // Copy files and directories\n let fileCount = 0;\n const installedFiles: string[] = [];\n const fileHashes: Record<string, string> = {};\n for (const file of component.files) {\n const srcPath = join(assetsDir, component.sourceOverrides?.[file] ?? file);\n if (options.dryRun) {\n console.log(` [dry-run] Would copy: ${file}`);\n } else {\n fileHashes[file] = await copyFile(srcPath, targetDir, file, { force: options.force });\n }\n installedFiles.push(file);\n fileCount++;\n }\n for (const dir of component.directories ?? []) {\n const srcDirPath = join(assetsDir, dir);\n if (options.dryRun) {\n console.log(` [dry-run] Would copy directory: ${dir}/`);\n } else {\n const copied = await copyDirectory(srcDirPath, targetDir, dir, { force: options.force });\n for (const { path: copiedPath, hash } of copied) {\n installedFiles.push(copiedPath);\n fileHashes[copiedPath] = hash;\n }\n fileCount += copied.length;\n }\n }\n\n if (options.dryRun) {\n console.log(\n `\\n[dry-run] Would add component \"${name}\" \\u2014 ${fileCount} files`,\n );\n return;\n }\n\n // Update manifest\n const newComponent: InstalledComponent = {\n name,\n files: installedFiles,\n installedVersion: packageVersion,\n fileHashes,\n };\n const updated = addComponent(manifest, newComponent);\n await writeManifest(targetDir, updated);\n\n console.log(\n `\\n\\u2713 Added component \"${name}\" \\u2014 ${fileCount} files copied`,\n );\n}\n","import { join } from \"node:path\";\nimport { readFile, writeFile, rm } from \"node:fs/promises\";\nimport { copyFile, copyDirectory, fileExists, hashFile } from \"../modules/copier.js\";\nimport {\n readManifest,\n writeManifest,\n ManifestNotFoundError,\n} from \"../modules/manifest.js\";\nimport { inspectGitRepository } from \"../modules/git.js\";\nimport {\n getComponent,\n ComponentNotFoundError,\n LEGACY_COMPONENT_MIGRATIONS,\n} from \"../modules/registry.js\";\nimport { MANIFEST_RETROFITS, runManifestRetrofits, offerRegistryScaffold } from \"../modules/hub.js\";\nimport { merge3 } from \"../modules/merge3.js\";\nimport { fetchPublishedFile } from \"../modules/npm-registry.js\";\nimport type { ArcaneManifest, InstalledComponent, SpellUpdateOptions } from \"../types.js\";\n\n/**\n * Runs the `spell update` command.\n *\n * For each installed component, looks up the current registry definition and\n * re-copies files from the current package assets. User-owned files in a\n * skipExisting component are preserved when present and backfilled when absent.\n * The manifest is updated with the new file paths so future updates remain\n * correct even when source paths change between versions.\n *\n * @param options CLI flags (dryRun)\n * @param targetDir Directory containing the Arcane installation\n * @param assetsDir Path to the bundled assets root\n * @param packageVersion Current package version string\n */\n/**\n * Rewrites manifest entries whose component was split or renamed in a later\n * release, so `update` can refresh their files instead of skipping them.\n *\n * Deterministic and idempotent: an already-migrated manifest contains no\n * legacy names, so this returns it unchanged. Entry order is preserved, with\n * each legacy entry's replacements expanded in place. Replacements inherit the\n * legacy entry's `installedVersion` and an empty file list -- the caller\n * immediately re-derives both from the registry, which is the source of truth\n * for what a component contains.\n *\n * Both legacy spell components map to the same replacement set, so a manifest\n * listing both (the common case) is deduped rather than producing doubles.\n */\nexport function migrateLegacyComponents(\n components: InstalledComponent[],\n): InstalledComponent[] {\n const out: InstalledComponent[] = [];\n const seen = new Set<string>();\n\n for (const entry of components) {\n const replacements = LEGACY_COMPONENT_MIGRATIONS[entry.name];\n if (!replacements) {\n if (seen.has(entry.name)) continue;\n seen.add(entry.name);\n out.push(entry);\n continue;\n }\n for (const name of replacements) {\n if (seen.has(name)) continue;\n seen.add(name);\n out.push({ name, files: [], installedVersion: entry.installedVersion });\n }\n }\n\n return out;\n}\n\nexport type OrphanStatus = \"pruned\" | \"reported\" | \"not-found\";\n\n/**\n * Resolves one orphaned file: previously tracked, no longer part of any\n * current component (TODO.md T10). Report-only unless `prune` is set, and\n * even then only deletes when the on-disk content still matches the hash\n * Arcane last recorded -- an operator edit is exactly as worth preserving\n * here as it is in the main update loop (ARC-038 decision 1's \"do not\n * silently discard the edit\" applies to deleting a file, not only\n * overwriting one). A file with no recorded hash (predates ARC-038, or was\n * never hashed) is reported but never auto-pruned -- there is nothing to\n * verify it against, and guessing is not this feature's job.\n */\nexport async function resolveOrphan(\n targetDir: string,\n file: string,\n recordedHash: string | undefined,\n prune: boolean,\n): Promise<OrphanStatus> {\n const filePath = join(targetDir, file);\n if (!(await fileExists(filePath))) return \"not-found\";\n if (!prune) return \"reported\";\n\n if (recordedHash === undefined) {\n console.log(` ! Orphaned, not pruned (no recorded hash to verify it's untouched): ${file}`);\n return \"reported\";\n }\n const currentHash = await hashFile(filePath);\n if (currentHash !== recordedHash) {\n console.log(` ! Orphaned but edited since install — not pruning: ${file}`);\n return \"reported\";\n }\n await rm(filePath, { force: true });\n console.log(` Pruned orphaned file: ${file}`);\n return \"pruned\";\n}\n\nexport async function runUpdate(\n options: SpellUpdateOptions,\n targetDir: string,\n assetsDir: string,\n packageVersion: string,\n): Promise<void> {\n // Read existing manifest\n let manifest;\n try {\n manifest = await readManifest(targetDir);\n } catch (err) {\n if (err instanceof ManifestNotFoundError) {\n console.error(\n 'Not initialized. Run \"spell init\" first before updating.',\n );\n process.exit(1);\n return; // guard: process.exit is mocked in tests\n }\n throw err;\n }\n\n console.warn(\n `WARNING: Arcane v${packageVersion} update safety notice: commit your work before updating.`,\n );\n console.warn(\n \"Updates can replace managed files. A clean committed baseline is required for recovery.\",\n );\n\n const gitState = await inspectGitRepository(targetDir);\n if (gitState.status === \"not-repository\") {\n console.error(\n \"Update refused: this directory is not a Git repository or Git is unavailable.\",\n );\n process.exit(1);\n return;\n }\n if (gitState.status === \"no-commits\") {\n console.error(\n \"Update refused: this repository has no commits. Commit the current baseline before updating.\",\n );\n process.exit(1);\n return;\n }\n if (gitState.uncommittedChanges > 0) {\n console.error(\n `Update refused: this repository has ${gitState.uncommittedChanges} uncommitted change${gitState.uncommittedChanges === 1 ? \"\" : \"s\"}. Commit or otherwise clean the working tree before updating.`,\n );\n process.exit(1);\n return;\n }\n\n // Already up to date\n if (manifest.version === packageVersion && manifest.components.length > 0) {\n console.log(\"Already up to date.\");\n return;\n }\n\n if (manifest.components.length === 0) {\n console.log(\"No components installed. Nothing to update.\");\n return;\n }\n\n let fileCount = 0;\n const updatedComponents: InstalledComponent[] = [];\n // ARC-038 decision 1: files whose merge produced genuine conflict markers,\n // collected across every component so the operator gets one summary at the\n // end rather than a per-file interruption -- the update still completes\n // for every other file either way.\n const conflictedFiles: string[] = [];\n // TODO.md T10: files tracked before this update that no longer belong to\n // any current component, reported always and deleted only with --prune\n // (and only when untouched -- see resolveOrphan).\n const orphanReport: Array<{ file: string; status: OrphanStatus }> = [];\n\n const componentsToUpdate = migrateLegacyComponents(manifest.components);\n\n for (const installed of componentsToUpdate) {\n // Look up the current registry definition (source of truth for file paths)\n let component;\n try {\n component = getComponent(installed.name);\n } catch (err) {\n if (err instanceof ComponentNotFoundError) {\n // Component removed from registry entirely -- every file it used to\n // track is now orphaned, not just individually dropped ones. Report\n // even during dry-run (that's the point of a preview); only the\n // actual deletion is dry-run-gated, inside resolveOrphan's `prune`.\n console.log(` ! ${installed.name} not in registry — skipping.`);\n for (const file of installed.files) {\n const status = await resolveOrphan(\n targetDir,\n file,\n installed.fileHashes?.[file],\n Boolean(options.prune) && !options.dryRun,\n );\n orphanReport.push({ file, status });\n }\n // Drop the manifest entry once every file it tracked is gone or was\n // never there; otherwise keep it so a future update can retry\n // pruning what --prune (or a hash mismatch) left behind.\n if (\n options.prune &&\n !options.dryRun &&\n installed.files.every((f) => orphanReport.find((o) => o.file === f)?.status !== \"reported\")\n ) {\n continue;\n }\n updatedComponents.push(installed);\n continue;\n }\n throw err;\n }\n\n // Copy files using current registry paths (handles path changes between versions)\n const updatedFiles: string[] = [];\n const fileHashes: Record<string, string> = {};\n for (const file of component.files) {\n const srcPath = join(assetsDir, component.sourceOverrides?.[file] ?? file);\n const targetExists = await fileExists(join(targetDir, file));\n const preserveExisting = Boolean(component.skipExisting) && targetExists;\n\n // initOnly: update never creates these. Their appearance alone changes\n // how Git treats the whole repository, so adding one mid-life is the\n // operator's call, not a side effect of a version upgrade (EF-17).\n if (component.initOnly && !targetExists) {\n console.log(\n ` ! Missing: ${file} — not added automatically, because doing so would change how Git treats existing files. Run \"spell add ${component.name}\" if you want it.`,\n );\n continue;\n }\n\n if (preserveExisting) {\n // skipExisting keeps its pre-ARC-038 whole-file behavior unchanged --\n // no hash tracking, no merge machinery (ARC-038 decision 1).\n console.log(` ${options.dryRun ? \"[dry-run] Would preserve\" : \"Preserved\"}: ${file}`);\n } else if (options.dryRun) {\n console.log(` [dry-run] Would update: ${file}`);\n fileCount++;\n } else {\n const recordedHash = installed.fileHashes?.[file];\n let handled = false;\n\n if (recordedHash !== undefined && targetExists) {\n const currentHash = await hashFile(join(targetDir, file));\n if (currentHash !== recordedHash) {\n // On-disk content no longer matches what Arcane last wrote --\n // the operator edited this file. Do not silently discard that\n // edit by overwriting it (ARC-038 decision 1).\n const oldVendorContent = await fetchPublishedFile(installed.installedVersion, file);\n if (oldVendorContent === undefined) {\n console.log(\n ` ! Could not fetch the previously published version of ${file} to merge your edits — left your version untouched. Update it manually if you want the latest.`,\n );\n handled = true;\n } else {\n const [currentContent, newContent] = await Promise.all([\n readFile(join(targetDir, file), \"utf-8\"),\n readFile(srcPath, \"utf-8\"),\n ]);\n const result = merge3(oldVendorContent, currentContent, newContent);\n await writeFile(join(targetDir, file), result.content, \"utf-8\");\n fileHashes[file] = await hashFile(join(targetDir, file));\n if (result.hasConflict) {\n conflictedFiles.push(file);\n console.log(` ⚠ Merge conflict in ${file} — resolve the <<<<<<< markers before committing.`);\n } else {\n console.log(` Merged your edits into: ${file}`);\n }\n handled = true;\n }\n }\n }\n\n if (!handled) {\n fileHashes[file] = await copyFile(srcPath, targetDir, file, { force: true });\n }\n fileCount++;\n }\n\n // Only record a preserved file if Arcane installed it in the first\n // place. Recording one it merely declined to overwrite would claim\n // ownership of an operator-authored file, and `spell uninstall` deletes\n // everything the manifest lists -- so an operator's own .gitignore or\n // DECISIONS.md would be destroyed by an uninstall that never wrote it.\n // A file Arcane DID write must stay recorded, or uninstall leaks it.\n if (!preserveExisting || installed.files.includes(file)) {\n updatedFiles.push(file);\n }\n }\n // Also copy directories\n for (const dir of component.directories ?? []) {\n const srcDirPath = join(assetsDir, dir);\n if (options.dryRun) {\n console.log(` [dry-run] Would update directory: ${dir}/`);\n } else {\n // Directory-tracked files are always freshly generated content\n // (agent rosters, etc.), never hand-edited in place -- unconditional\n // overwrite, same as before ARC-038, is still correct here.\n const copied = await copyDirectory(srcDirPath, targetDir, dir, { force: true });\n for (const { path: copiedPath, hash } of copied) {\n updatedFiles.push(copiedPath);\n fileHashes[copiedPath] = hash;\n }\n fileCount += copied.length;\n }\n }\n\n // TODO.md T10: a file this component tracked before this update but no\n // longer does (dropped from the registry's current file/directory list)\n // is orphaned -- still on disk, no longer represented in the manifest\n // this update is about to write.\n for (const file of installed.files) {\n if (updatedFiles.includes(file)) continue;\n const status = await resolveOrphan(\n targetDir,\n file,\n installed.fileHashes?.[file],\n Boolean(options.prune) && !options.dryRun,\n );\n orphanReport.push({ file, status });\n }\n\n updatedComponents.push({\n ...installed,\n files: updatedFiles,\n installedVersion: packageVersion,\n fileHashes,\n });\n }\n\n // TODO.md T10: report orphans -- files tracked before this update but no\n // longer part of any current component -- in both dry-run and real runs.\n // Only files still present matter; anything already gone needs no action.\n const orphansToReport = orphanReport.filter((o) => o.status !== \"not-found\");\n if (orphansToReport.length > 0) {\n const verb = options.dryRun ? \"[dry-run] Found\" : \"Found\";\n console.log(\n `\\n${verb} ${orphansToReport.length} orphaned file(s) (tracked before this update, no longer part of any current component):`,\n );\n for (const { file, status } of orphansToReport) {\n const marker = status === \"pruned\" ? \"pruned\" : options.prune ? \"kept (see reason above)\" : \"not removed\";\n console.log(` ${file} — ${marker}`);\n }\n if (!options.prune) {\n console.log(\" Run `spell update --prune` to remove the ones that are safe to delete.\");\n }\n }\n\n if (options.dryRun) {\n console.log(\n `\\n[dry-run] Would update ${fileCount} files.`,\n );\n const applicableRetrofits = MANIFEST_RETROFITS.filter((r) => r.needsRetrofit(manifest));\n if (applicableRetrofits.length > 0) {\n console.log(\n `[dry-run] Would ask ${applicableRetrofits.length} manifest retrofit question${applicableRetrofits.length === 1 ? \"\" : \"s\"}: ${applicableRetrofits.map((r) => r.field).join(\", \")}.`,\n );\n }\n return;\n }\n\n // Retrofit wizard: ask about any manifest field this install predates\n // (e.g. `role`), once, before writing the updated manifest.\n //\n // Skipped without a TTY. These are interactive questions, and @inquirer\n // throws ExitPromptError on a closed stdin -- which would crash `update`\n // AFTER files were copied but BEFORE the manifest was written, leaving the\n // repo with new files and a stale recorded version. CI, piped input, and\n // scripted upgrades all land here. The fields stay unset and are asked on\n // the next interactive run, which is exactly how a scripted `init` already\n // behaves.\n const interactive = Boolean(process.stdin.isTTY);\n const retrofitPatch = interactive ? await runManifestRetrofits(manifest) : {};\n if (!interactive) {\n const pending = MANIFEST_RETROFITS.filter((r) => r.needsRetrofit(manifest));\n if (pending.length > 0) {\n console.log(\n ` ! Skipped ${pending.length} manifest question${pending.length === 1 ? \"\" : \"s\"} (${pending\n .map((r) => r.field)\n .join(\", \")}) — no interactive terminal. Run \\`spell update\\` from a terminal to answer.`,\n );\n }\n }\n\n // Update manifest with new version, refreshed component file paths, and\n // any retrofit answers.\n const updated: ArcaneManifest = {\n ...manifest,\n version: packageVersion,\n components: updatedComponents,\n ...retrofitPatch,\n };\n await writeManifest(targetDir, updated);\n\n console.log(\n `\\n\\u2713 Updated ${fileCount} files.`,\n );\n\n // ARC-038 decision 1: the update completes regardless of conflicts -- a\n // conflicted file blocking every other file's update would be a worse\n // outcome than a clearly flagged conflict the operator resolves before\n // committing (this repository's own pre-commit/pre-push hooks, and any\n // CI the operator has, still catch an unresolved <<<<<<< marker before it\n // reaches main).\n if (conflictedFiles.length > 0) {\n console.log(\n `\\n\\u26a0 ${conflictedFiles.length} file(s) have unresolved merge conflicts:\\n` +\n conflictedFiles.map((f) => ` ${f}`).join(\"\\n\") +\n `\\n Search for \"<<<<<<< yours\" and resolve before committing.`,\n );\n }\n\n // If this update just turned the repo into a hub, offer to scaffold the\n // venture registry from whatever already exists under business_root.\n if (manifest.role !== \"hub\" && updated.role === \"hub\") {\n await offerRegistryScaffold(targetDir, updated.business_root ?? \"ventures\");\n }\n}\n","import { confirm, select, input } from \"@inquirer/prompts\";\nimport { readdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { fileExists } from \"./copier.js\";\nimport { isValidSubjectRoot } from \"./manifest.js\";\nimport type {\n ArcaneManifest,\n ContentSensitivity,\n ExternalProvider,\n HubRole,\n PushPolicy,\n TrackingMode,\n} from \"../types.js\";\n\n/**\n * A manifest-field retrofit: a schema question `spell update` asks exactly\n * once, for an installed manifest that predates the field. This is a general\n * migration mechanism, not a one-off for `role` -- future manifest fields\n * register a retrofit here instead of leaving older installs permanently\n * unset.\n */\nexport interface ManifestRetrofit {\n /** Field this retrofit introduces on ArcaneManifest, for logging only. */\n field: string;\n /** True if the installed manifest predates this field and should be asked. */\n needsRetrofit(manifest: ArcaneManifest): boolean;\n /**\n * Ask the operator (or apply a deterministic default); return the partial\n * patch to merge into the manifest. Receives the manifest so a retrofit\n * can branch on already-known fields (e.g. profile) the way the\n * tracking_mode retrofit below does -- entries that don't need it (role)\n * simply ignore the parameter.\n */\n ask(manifest: ArcaneManifest): Promise<Partial<ArcaneManifest>>;\n}\n\nexport const MANIFEST_RETROFITS: ManifestRetrofit[] = [\n {\n field: \"role\",\n needsRetrofit: (m) => m.role === undefined,\n ask: async () => {\n const isHub = await confirm({\n message:\n \"Will this repo manage other ventures as a hub? (idea books, spell-manifest promotion, venture registry)\",\n default: false,\n });\n return { role: (isHub ? \"hub\" : \"consumer\") as HubRole };\n },\n },\n {\n field: \"tracking_mode\",\n needsRetrofit: (m) => m.tracking_mode === undefined,\n // Mirrors init.ts's Step 5b branching exactly (EF-14 D5): docs-only\n // profiles get a silent default, full/lite get asked.\n ask: async (manifest) => {\n if (\n manifest.profile === \"governance-only\" ||\n manifest.profile === \"methodology\" ||\n manifest.profile === \"docs\"\n ) {\n return { tracking_mode: \"internal\" as TrackingMode, external_provider: null };\n }\n const tracking_mode = (await select({\n message: \"How will work be tracked in this repo?\",\n choices: [\n { value: \"internal\", name: \"Track work in this repo (TODO.md / PRDs)\" },\n { value: \"external\", name: \"Track work in an external tracker (Azure DevOps / GitHub / Jira / other)\" },\n ],\n })) as TrackingMode;\n if (tracking_mode === \"external\") {\n const external_provider = (await select({\n message: \"Which external tracker?\",\n choices: [\n { value: \"ado\", name: \"Azure DevOps\" },\n { value: \"github\", name: \"GitHub Issues\" },\n { value: \"jira\", name: \"Jira\" },\n { value: \"other\", name: \"Other\" },\n ],\n })) as ExternalProvider;\n return { tracking_mode, external_provider };\n }\n return { tracking_mode, external_provider: null };\n },\n },\n {\n field: \"content_sensitivity\",\n needsRetrofit: (m) => m.content_sensitivity === undefined,\n // EF-12. Asked for every profile -- a code repo can hold sensitive records\n // too -- and defaults to \"standard\", so an operator who just presses enter\n // keeps today's behaviour exactly.\n ask: async () => {\n const content_sensitivity = (await select({\n message: \"How should agents treat this repository's contents?\",\n choices: [\n {\n value: \"standard\",\n name: \"Standard — agents may quote contents in journals and decisions\",\n },\n {\n value: \"sensitive\",\n name: \"Sensitive — agents reference documents by path, never transcribe them\",\n },\n ],\n default: \"standard\",\n })) as ContentSensitivity;\n return { content_sensitivity };\n },\n },\n {\n field: \"subject_root\",\n // EF-07. Only the docs profile is asked: other profiles describe code or a\n // venture portfolio, where \"what is this repo about\" is already answered.\n // A docs install that legitimately holds several subjects answers\n // \"portfolio\" and stays unset -- so this retrofit deliberately does NOT\n // re-ask on every update. It is gated on the field being absent AND the\n // profile being docs, and once answered (either way) it never fires again,\n // because \"portfolio\" writes an explicit empty marker.\n needsRetrofit: (m) => m.profile === \"docs\" && m.subject_root === undefined,\n ask: async () => {\n const shape = await select({\n message: \"What does this repository hold?\",\n choices: [\n {\n value: \"root\",\n name: \"One subject, at the repository root (documents sit alongside Arcane's files)\",\n },\n { value: \"subdir\", name: \"One subject, in its own directory\" },\n { value: \"portfolio\", name: \"Several subjects or ventures\" },\n ],\n });\n if (shape === \"root\") return { subject_root: \".\" };\n if (shape === \"subdir\") {\n const answer = await input({\n message: \"Directory holding the subject's documents:\",\n default: \"docs\",\n validate: (v) =>\n isValidSubjectRoot(v.trim() || \"docs\") ||\n \"Must be a relative path inside the repository (no leading /, drive letter, or ..).\",\n });\n return { subject_root: answer.trim() || \"docs\" };\n }\n // Portfolio: business_root covers this shape. Recorded as an explicit\n // null rather than left unset, so the question isn't re-asked on every\n // future update.\n return { subject_root: null };\n },\n },\n {\n field: \"push_policy\",\n needsRetrofit: (m) => m.push_policy === undefined,\n // EF-09. Defaults to \"open\", so an operator who just presses enter keeps\n // today's behaviour exactly. NOTE: this only records the choice -- unlike\n // init, the retrofit does not install the hook or disable the push URL,\n // because an update should not silently start blocking pushes in a repo\n // someone is mid-workflow in. doctor reports the gap instead.\n ask: async () => {\n const push_policy = (await select({\n message: \"Should this repository be allowed to push to a remote?\",\n choices: [\n { value: \"open\", name: \"Yes — normal repository\" },\n { value: \"guarded\", name: \"Sensitive, but keep push working — remind me instead\" },\n { value: \"blocked\", name: \"No — block pushes\" },\n ],\n default: \"open\",\n })) as PushPolicy;\n return { push_policy };\n },\n },\n];\n\n/**\n * Runs every retrofit question the installed manifest predates, in order.\n * Returns the partial patch to merge into the manifest being written.\n * Returns {} immediately (no questions, no console output) if nothing\n * applies -- callers should only invoke this outside dry-run and\n * non-interactive modes.\n */\nexport async function runManifestRetrofits(\n manifest: ArcaneManifest,\n): Promise<Partial<ArcaneManifest>> {\n const applicable = MANIFEST_RETROFITS.filter((r) => r.needsRetrofit(manifest));\n if (applicable.length === 0) return {};\n\n console.log();\n console.log(\n `This install predates ${applicable.length} manifest field${applicable.length === 1 ? \"\" : \"s\"} -- a couple of quick questions:`,\n );\n\n let patch: Partial<ArcaneManifest> = {};\n for (const retrofit of applicable) {\n const answer = await retrofit.ask({ ...manifest, ...patch });\n patch = { ...patch, ...answer };\n }\n return patch;\n}\n\n/**\n * Offers to scaffold `{business_root}/registry.json` from existing venture\n * folders, once `role` has just become \"hub\" (via init or retrofit). Never\n * overwrites an existing registry. No-ops silently (no prompt, no output) if\n * the business root doesn't exist or holds no venture folders -- a brand new\n * hub with nothing under `ventures/` yet has nothing to scaffold.\n */\nexport async function offerRegistryScaffold(\n targetDir: string,\n businessRoot: string,\n): Promise<void> {\n const registryPath = join(targetDir, businessRoot, \"registry.json\");\n if (await fileExists(registryPath)) return;\n\n const businessRootPath = join(targetDir, businessRoot);\n let ventureDirs: string[];\n try {\n const entries = await readdir(businessRootPath, { withFileTypes: true });\n ventureDirs = entries\n .filter((e) => e.isDirectory() && e.name !== \"_template\")\n .map((e) => e.name);\n } catch {\n return;\n }\n if (ventureDirs.length === 0) return;\n\n console.log();\n const scaffold = await confirm({\n message: `Found ${ventureDirs.length} folder${ventureDirs.length === 1 ? \"\" : \"s\"} under ${businessRoot}/ -- scaffold ${businessRoot}/registry.json from them?`,\n default: true,\n });\n if (!scaffold) return;\n\n const ventures: Record<string, unknown> = {};\n for (const slug of ventureDirs) {\n const include = await confirm({ message: ` Include \"${slug}\"?`, default: true });\n if (!include) continue;\n ventures[slug] = {\n name: slug,\n aliases: [],\n status: \"active\",\n visibility: \"private\",\n ownership: \"llc\",\n tracking: \"none\",\n repos: [],\n };\n }\n if (Object.keys(ventures).length === 0) {\n console.log(\" No ventures selected -- registry not created.\");\n return;\n }\n\n const registry = {\n _comment:\n \"Hub-owned venture registry. Private. Never installed or modified by spell update. \" +\n \"Seeded by the retrofit wizard -- review and enrich (aliases, ownership, tracking, \" +\n \"clones) before relying on it.\",\n updated: new Date().toISOString().slice(0, 10),\n ventures,\n };\n await writeFile(registryPath, JSON.stringify(registry, null, 2) + \"\\n\", \"utf-8\");\n console.log(\n ` ✓ Scaffolded ${businessRoot}/registry.json with ${Object.keys(ventures).length} venture(s).`,\n );\n}\n","/**\n * Line-based three-way text merge (ARC-038 decision 1).\n *\n * `spell update` uses this to reconcile an operator's edited copy of a\n * shipped file against a new vendor version, without silently discarding the\n * edit: `base` is the OLD vendor content the operator's edit started from,\n * `ours` is the operator's current on-disk content, `theirs` is the NEW\n * vendor content about to be installed. Non-overlapping changes on each side\n * merge automatically; a region both sides changed differently becomes a\n * conflict, marked the same way `git merge` marks one.\n *\n * Deliberately line-granular, not character-granular -- the same mental\n * model a human resolving a merge conflict already has, and the one ARC-038\n * itself names (\"the same shape copier's regenerate-old/diff/regenerate-new/\n * merge approach uses\").\n */\n\nexport const CONFLICT_START = \"<<<<<<< yours (edited)\";\nexport const CONFLICT_MID = \"=======\";\nexport const CONFLICT_END = \">>>>>>> incoming (vendor update)\";\n\ninterface DiffOp {\n type: \"equal\" | \"replace\";\n baseStart: number;\n baseEnd: number;\n otherStart: number;\n otherEnd: number;\n}\n\n/**\n * Line-based LCS diff of `base` against `other`. DP table is O(n*m) time and\n * space -- fine for governance-doc-sized files (hundreds to low thousands of\n * lines); `merge3` falls back to a whole-file conflict rather than running\n * this on pathologically large inputs (see MAX_LINES_FOR_LCS below).\n */\nfunction computeLcsDiff(base: string[], other: string[]): DiffOp[] {\n const n = base.length;\n const m = other.length;\n const dp: Uint32Array[] = Array.from({ length: n + 1 }, () => new Uint32Array(m + 1));\n for (let i = n - 1; i >= 0; i--) {\n for (let j = m - 1; j >= 0; j--) {\n dp[i]![j] =\n base[i] === other[j] ? dp[i + 1]![j + 1]! + 1 : Math.max(dp[i + 1]![j]!, dp[i]![j + 1]!);\n }\n }\n\n const ops: DiffOp[] = [];\n let i = 0;\n let j = 0;\n let pendingBaseStart = 0;\n let pendingOtherStart = 0;\n\n const flushReplace = (baseEnd: number, otherEnd: number) => {\n if (baseEnd > pendingBaseStart || otherEnd > pendingOtherStart) {\n ops.push({\n type: \"replace\",\n baseStart: pendingBaseStart,\n baseEnd,\n otherStart: pendingOtherStart,\n otherEnd,\n });\n }\n };\n\n while (i < n && j < m) {\n if (base[i] === other[j]) {\n flushReplace(i, j);\n const eqBaseStart = i;\n const eqOtherStart = j;\n while (i < n && j < m && base[i] === other[j]) {\n i++;\n j++;\n }\n ops.push({ type: \"equal\", baseStart: eqBaseStart, baseEnd: i, otherStart: eqOtherStart, otherEnd: j });\n pendingBaseStart = i;\n pendingOtherStart = j;\n } else if (dp[i + 1]![j]! >= dp[i]![j + 1]!) {\n i++;\n } else {\n j++;\n }\n }\n flushReplace(n, m);\n return ops;\n}\n\nfunction arraysEqual(a: string[], b: string[]): boolean {\n if (a.length !== b.length) return false;\n return a.every((line, idx) => line === b[idx]);\n}\n\nexport interface Merge3Result {\n content: string;\n hasConflict: boolean;\n}\n\n/**\n * Files larger than this fall back to a single whole-file conflict rather\n * than running the O(n*m) LCS diff -- a correctness-preserving degradation\n * (the operator is never silently overwritten, they're just not offered an\n * auto-merge for a file this large), not a crash or a silent choice of one\n * side. No governance/prompt content shipped by Arcane comes close to this.\n */\nconst MAX_LINES_FOR_LCS = 4000;\n\n/** Splits on \\n, preserving trailing-newline presence as the final \"\" element does. */\nfunction splitLines(text: string): string[] {\n return text.split(\"\\n\");\n}\n\n/**\n * Merges `theirs` (new vendor content) onto `ours` (the operator's edited\n * content), using `base` (old vendor content) as the common ancestor.\n *\n * Never throws and never silently prefers one side: a region changed\n * differently by both sides is always marked as a conflict in the returned\n * content, and `hasConflict` tells the caller whether any such region\n * existed, so update.ts can report it rather than commit it quietly.\n */\nexport function merge3(base: string, ours: string, theirs: string): Merge3Result {\n const baseLines = splitLines(base);\n const oursLines = splitLines(ours);\n const theirsLines = splitLines(theirs);\n\n if (\n baseLines.length > MAX_LINES_FOR_LCS ||\n oursLines.length > MAX_LINES_FOR_LCS ||\n theirsLines.length > MAX_LINES_FOR_LCS\n ) {\n return {\n content: [CONFLICT_START, ours, CONFLICT_MID, theirs, CONFLICT_END].join(\"\\n\"),\n hasConflict: true,\n };\n }\n\n const oursOps = computeLcsDiff(baseLines, oursLines).filter((op) => op.type === \"replace\");\n const theirsOps = computeLcsDiff(baseLines, theirsLines).filter((op) => op.type === \"replace\");\n\n if (oursOps.length === 0 && theirsOps.length === 0) {\n return { content: base, hasConflict: false };\n }\n\n interface ChangedInterval {\n baseStart: number;\n baseEnd: number;\n source: \"ours\" | \"theirs\";\n lines: string[];\n }\n const intervals: ChangedInterval[] = [\n ...oursOps.map((op) => ({\n baseStart: op.baseStart,\n baseEnd: op.baseEnd,\n source: \"ours\" as const,\n lines: oursLines.slice(op.otherStart, op.otherEnd),\n })),\n ...theirsOps.map((op) => ({\n baseStart: op.baseStart,\n baseEnd: op.baseEnd,\n source: \"theirs\" as const,\n lines: theirsLines.slice(op.otherStart, op.otherEnd),\n })),\n ].sort((a, b) => a.baseStart - b.baseStart || a.baseEnd - b.baseEnd);\n\n // Coalesce intervals that overlap in BASE-line space, from either side,\n // into groups -- two edits any distance apart in \"ours\" and \"theirs\" text\n // can still collide if they touch the same base lines, which is exactly\n // the case a merge must resolve as one unit, not two independent ones.\n const groups: ChangedInterval[][] = [];\n let groupMaxEnd = -1;\n for (const iv of intervals) {\n const current = groups[groups.length - 1];\n if (current && iv.baseStart < groupMaxEnd) {\n current.push(iv);\n groupMaxEnd = Math.max(groupMaxEnd, iv.baseEnd);\n } else {\n groups.push([iv]);\n groupMaxEnd = iv.baseEnd;\n }\n }\n\n const resultLines: string[] = [];\n let hasConflict = false;\n let basePos = 0;\n\n for (const group of groups) {\n const groupStart = Math.min(...group.map((g) => g.baseStart));\n const groupEnd = Math.max(...group.map((g) => g.baseEnd));\n\n resultLines.push(...baseLines.slice(basePos, groupStart));\n\n const oursInGroup = group.filter((g) => g.source === \"ours\");\n const theirsInGroup = group.filter((g) => g.source === \"theirs\");\n\n if (oursInGroup.length > 0 && theirsInGroup.length === 0) {\n for (const g of oursInGroup) resultLines.push(...g.lines);\n } else if (theirsInGroup.length > 0 && oursInGroup.length === 0) {\n for (const g of theirsInGroup) resultLines.push(...g.lines);\n } else {\n const oursGroupLines = oursInGroup.flatMap((g) => g.lines);\n const theirsGroupLines = theirsInGroup.flatMap((g) => g.lines);\n if (arraysEqual(oursGroupLines, theirsGroupLines)) {\n // Converged edit -- both sides changed this region to the same\n // result, so there is nothing to actually resolve.\n resultLines.push(...oursGroupLines);\n } else {\n hasConflict = true;\n resultLines.push(CONFLICT_START, ...oursGroupLines, CONFLICT_MID, ...theirsGroupLines, CONFLICT_END);\n }\n }\n\n basePos = groupEnd;\n }\n resultLines.push(...baseLines.slice(basePos));\n\n return { content: resultLines.join(\"\\n\"), hasConflict };\n}\n","/**\n * Fetches one file's content from a specific PUBLISHED version of this\n * package (ARC-038 decision 1) -- the merge base for `spell update`'s\n * content-preserving update, without vendoring a second copy of every past\n * release: npm's own registry already permanently retains every published\n * tarball.\n *\n * npm's registry API has no \"browse one file from one version\" endpoint, and\n * hand-rolling tarball extraction for a read-one-file use case is a\n * correctness risk this project has no existing dependency to cover safely.\n * unpkg.com serves directly from that same registry tarball, so this reaches\n * the identical permanent history the ADR describes, through a widely-used,\n * purpose-built CDN rather than new vendoring infrastructure. Resolved\n * in-implementation (ARC-038 left the exact fetch mechanism open); no local\n * caching, also resolved in-implementation -- within one `spell update` run\n * each (version, file) pair is fetched at most once already, and this\n * command runs rarely enough that cross-run caching is not worth the extra\n * invalidation surface.\n */\nconst NPM_PACKAGE_NAME = \"arcane-cli\";\n\n/**\n * Returns the file's text content, or `undefined` if it could not be\n * fetched (network failure, non-2xx response, or any other error) --\n * callers must treat `undefined` as \"cannot verify what changed,\" never as\n * \"no prior content,\" since silently treating a fetch failure as an empty\n * base would make the merge invent a huge fake diff instead of correctly\n * refusing to guess.\n */\nexport async function fetchPublishedFile(\n version: string,\n relativeAssetPath: string,\n): Promise<string | undefined> {\n const normalized = relativeAssetPath.replace(/\\\\/g, \"/\").replace(/^\\/+/, \"\");\n const url = `https://unpkg.com/${NPM_PACKAGE_NAME}@${version}/dist/assets/${normalized}`;\n try {\n const response = await fetch(url);\n if (!response.ok) return undefined;\n return await response.text();\n } catch {\n return undefined;\n }\n}\n","import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { createRequire } from \"node:module\";\nimport type { VersionCheckResult } from \"../types.js\";\n\nconst require = createRequire(import.meta.url);\n\ninterface PackageJson {\n publishConfig?: { registry?: string };\n}\n\n/** Read the feed URL from the package's own publishConfig.registry — never hardcoded. */\nexport function getFeedUrl(): string {\n const pkg = require(\"../../package.json\") as PackageJson;\n const url = pkg.publishConfig?.registry;\n if (!url) {\n throw new Error(\n \"publishConfig.registry is not set in package.json. Cannot resolve npm feed URL.\",\n );\n }\n return url;\n}\n\nconst DEFAULT_CACHE_PATH = join(homedir(), \".arcane\", \"version-cache.json\");\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours\n\ninterface CacheEntry {\n latest: string;\n checkedAt: string;\n}\n\n/**\n * Reads the version cache file. Returns null if missing or malformed.\n */\nexport async function readCache(\n cachePath: string,\n): Promise<CacheEntry | null> {\n try {\n const content = await readFile(cachePath, \"utf-8\");\n const parsed = JSON.parse(content) as CacheEntry;\n if (typeof parsed.latest !== \"string\" || typeof parsed.checkedAt !== \"string\") {\n return null;\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\n/**\n * Writes the version cache file, creating parent directories as needed.\n */\nexport async function writeCache(\n cachePath: string,\n latest: string,\n): Promise<void> {\n await mkdir(dirname(cachePath), { recursive: true });\n const entry: CacheEntry = { latest, checkedAt: new Date().toISOString() };\n await writeFile(cachePath, JSON.stringify(entry, null, 2), \"utf-8\");\n}\n\n/**\n * Fetches the latest published version of arcane-cli from the public npm\n * registry. Returns null (does not throw) on any network failure.\n */\nexport async function getLatestVersion(feedUrl: string): Promise<string | null> {\n const normalizedBase = feedUrl.endsWith(\"/\") ? feedUrl : feedUrl + \"/\";\n const url = `${normalizedBase}arcane-cli`;\n try {\n const response = await fetch(url, {\n headers: { Accept: \"application/json\" },\n signal: AbortSignal.timeout(5000),\n });\n if (!response.ok) return null;\n const body = await response.json() as { \"dist-tags\"?: { latest?: string } };\n return body[\"dist-tags\"]?.latest ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Checks for a newer version of the package, using a 24h file cache.\n * Never throws — errors are captured in VersionCheckResult.error.\n */\nexport async function checkForUpdate(\n currentVersion: string,\n feedUrl: string,\n cachePath: string = DEFAULT_CACHE_PATH,\n): Promise<VersionCheckResult> {\n try {\n let latest: string | null = null;\n\n const cached = await readCache(cachePath);\n if (cached) {\n const age = Date.now() - new Date(cached.checkedAt).getTime();\n if (age < CACHE_TTL_MS) {\n latest = cached.latest;\n }\n }\n\n if (latest === null) {\n latest = await getLatestVersion(feedUrl);\n if (latest !== null) {\n try {\n await writeCache(cachePath, latest);\n } catch {\n // Cache write failure is non-fatal\n }\n }\n }\n\n return {\n current: currentVersion,\n latest,\n updateAvailable: latest !== null && latest !== currentVersion,\n };\n } catch (err) {\n return {\n current: currentVersion,\n latest: null,\n updateAvailable: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n}\n","/**\n * Generates the canonical version-drift gitGraph diagram (ARC-036, R2) from\n * the three already-computed version readings. Pure — no I/O, no network\n * calls. Mirrors spell-open-session.prompt.md's \"Arcane version check\n * (two-axis)\" template exactly, so the CLI (`spell status`) and the prompt\n * produce the identical shape from the same three inputs.\n */\n\n/**\n * Returns the gitGraph body (no ```mermaid fence — the caller chooses\n * fencing per R5) for the three-reading version-drift diagram, or `null`\n * when all three readings match (the applicability guard — nothing to\n * visualize for a single, matching reading).\n *\n * One commit per *distinct* value among the three readings, in\n * repo-files -> installed-CLI -> npm-latest order; a consecutive repeated\n * value collapses into its neighbor's commit rather than repeating it.\n * Branches off after the commit for each axis that drifts.\n */\nexport function generateVersionDriftDiagram(\n repoFilesVersion: string,\n installedCliVersion: string,\n npmLatestVersion: string,\n): string | null {\n if (\n repoFilesVersion === installedCliVersion &&\n installedCliVersion === npmLatestVersion\n ) {\n return null;\n }\n\n const lines = [\"gitGraph\", ` commit id: \"${repoFilesVersion}\"`];\n let lastDistinctVersion = repoFilesVersion;\n\n if (installedCliVersion !== repoFilesVersion) {\n lines.push(\n \" branch repo-files\",\n \" checkout main\",\n ` commit id: \"${installedCliVersion}\"`,\n );\n lastDistinctVersion = installedCliVersion;\n }\n\n if (npmLatestVersion !== lastDistinctVersion) {\n lines.push(\n \" branch installed-cli\",\n \" checkout main\",\n ` commit id: \"${npmLatestVersion}\" tag: \"latest\"`,\n );\n } else {\n lines[lines.length - 1] += ' tag: \"latest\"';\n }\n\n return lines.join(\"\\n\");\n}\n","import {\n readManifest,\n ManifestNotFoundError,\n} from \"../modules/manifest.js\";\nimport {\n checkForUpdate,\n getFeedUrl,\n} from \"../modules/version-check.js\";\nimport { generateVersionDriftDiagram } from \"../modules/diagram-generator.js\";\n\n/**\n * Runs the `spell status` command.\n *\n * Reads .arcane.json, checks for an available update, then prints\n * a formatted table of installed components + a version footer.\n *\n * @param targetDir Directory containing the Arcane installation\n * @param packageVersion Current package version string\n */\nexport async function runStatus(\n targetDir: string,\n packageVersion: string,\n): Promise<void> {\n // Read existing manifest\n let manifest;\n try {\n manifest = await readManifest(targetDir);\n } catch (err) {\n if (err instanceof ManifestNotFoundError) {\n console.error(\n 'Not initialized. Run \"spell init\" first.',\n );\n process.exit(1);\n return; // guard: process.exit is mocked in tests\n }\n throw err;\n }\n\n if (manifest.components.length === 0) {\n console.log(\"No components installed.\");\n return;\n }\n\n // Check for update (never throws)\n let feedUrl: string;\n try {\n feedUrl = getFeedUrl();\n } catch {\n feedUrl = \"\";\n }\n\n const versionResult = feedUrl\n ? await checkForUpdate(packageVersion, feedUrl)\n : { current: packageVersion, latest: null, updateAvailable: false, error: \"Feed URL unavailable\" };\n\n // ─── Print component table ─────────────────────────────────────────────────\n\n // Compute column widths\n const nameWidth = Math.max(\n \"Component\".length,\n ...manifest.components.map((c) => c.name.length),\n );\n const filesWidth = \"Files\".length;\n const versionWidth = Math.max(\n \"Version\".length,\n ...manifest.components.map((c) => c.installedVersion.length),\n );\n\n const pad = (s: string, n: number) => s.padEnd(n);\n const rpad = (s: string, n: number) => s.padStart(n);\n\n console.log(\n ` ${pad(\"Component\", nameWidth)} ${rpad(\"Files\", filesWidth)} ${pad(\"Version\", versionWidth)}`,\n );\n console.log(\n ` ${\"-\".repeat(nameWidth)} ${\"-\".repeat(filesWidth)} ${\"-\".repeat(versionWidth)}`,\n );\n\n for (const component of manifest.components) {\n const label = component.name;\n const fileCount = component.files.length.toString();\n const displayVersion = component.installedVersion;\n console.log(\n ` ${pad(label, nameWidth)} ${rpad(fileCount, filesWidth)} ${displayVersion}`,\n );\n }\n\n // ─── Version footer ────────────────────────────────────────────────────────\n\n console.log(\"\");\n\n const latestStr = versionResult.error\n ? \"unable to check\"\n : (versionResult.latest ?? manifest.version);\n\n let footer = ` Installed: ${packageVersion} Latest: ${latestStr}`;\n\n if (versionResult.updateAvailable) {\n footer += \" (spell update available)\";\n }\n\n console.log(footer);\n\n // ─── Version-drift diagram (ARC-036 R8) ────────────────────────────────────\n // Axis A (repo-files vs installed CLI) needs no network call and is always\n // checkable. Axis B (installed CLI vs npm-latest) needs versionResult.latest,\n // which is null when the npm check failed — skip the diagram entirely in\n // that case rather than showing a partial, potentially misleading picture;\n // the \"Latest: unable to check\" footer above already covers that failure.\n if (versionResult.latest !== null) {\n const diagram = generateVersionDriftDiagram(\n manifest.version,\n packageVersion,\n versionResult.latest,\n );\n\n if (diagram !== null) {\n console.log(\"\");\n if (process.stdout.isTTY) {\n // Interactive terminal: a fenced Mermaid block doesn't render here —\n // print the same three readings as plain aligned text instead.\n console.log(\" Version drift:\");\n console.log(` repo-files: ${manifest.version}`);\n console.log(` installed-cli: ${packageVersion}`);\n console.log(` latest (npm): ${versionResult.latest}`);\n } else {\n // Piped (file, another tool, a captured PR body): emit the real\n // diagram so the redirected output is directly usable.\n console.log(\"```mermaid\");\n console.log(diagram);\n console.log(\"```\");\n }\n }\n }\n}\n","import { rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { confirm } from \"@inquirer/prompts\";\nimport {\n readManifest,\n ManifestNotFoundError,\n} from \"../modules/manifest.js\";\nimport { stripMarkerSection } from \"../modules/merger.js\";\nimport { isHookEnforced, blockedRemotes } from \"../modules/push-safety.js\";\nimport { removeSecretsPrecommitHook } from \"../modules/secrets-scan.js\";\n\n/**\n * Runs the `spell uninstall` command.\n *\n * Deletes every file tracked in .arcane.json then removes .arcane.json itself.\n * Prompts for confirmation unless --yes is passed.\n *\n * @param options.yes Skip confirmation prompt\n * @param options.dryRun Preview what would be removed without deleting files\n * @param targetDir Directory containing the Arcane installation\n */\nexport async function runUninstall(\n options: { yes?: boolean; dryRun?: boolean },\n targetDir: string,\n): Promise<void> {\n // Read existing manifest\n let manifest;\n try {\n manifest = await readManifest(targetDir);\n } catch (err) {\n if (err instanceof ManifestNotFoundError) {\n console.error('Not initialized. Run \"spell init\" first.');\n process.exit(1);\n return; // guard: process.exit is mocked in tests\n }\n throw err;\n }\n\n // A push-blocked repository must not be uninstalled while the block stands.\n //\n // Uninstall deletes .arcane.json but has no idea about core.hooksPath or the\n // sentinel push URLs, so the repo was left unable to push while `spell\n // unblock-push` -- the only supported way out -- refused to run because the\n // manifest it reads was gone. The operator was told \"Uninstalled\" and handed\n // a repository whose recovery required hand-editing git config.\n //\n // Refusing is the right shape rather than silently unblocking: ARC-034 R5\n // makes lifting the block a deliberate, interactive, separately-confirmed act,\n // and quietly doing it as a side effect of `uninstall --yes` would hand any\n // script exactly the bypass that command exists to deny.\n // Keyed on what the repository ACTUALLY has, not only on what the manifest\n // declares. A manifest-only check is the same declaration-versus-enforcement\n // confusion this feature exists to remove, and it is reachable without anyone\n // hand-editing: a partially-failed `unblock-push` writes push_policy \"open\"\n // while remotes stay blocked, after which uninstall would strand the repo\n // exactly as before.\n const policy = manifest.push_policy ?? \"open\";\n const controlsInForce =\n (await isHookEnforced(targetDir)) || (await blockedRemotes(targetDir)).length > 0;\n if ((policy === \"blocked\" || controlsInForce) && !options.dryRun) {\n const why =\n policy === \"blocked\"\n ? `this repository's push_policy is \"blocked\"`\n : `this repository still has Arcane's push block in force (the manifest says \"${policy}\", ` +\n \"but the controls are actually installed)\";\n console.error(\n `Refusing to uninstall: ${why}.\\n` +\n \"Uninstalling now would delete .arcane.json while leaving the pre-push hook and the\\n\" +\n \"disabled push URLs in place — the repository could not push, and `spell unblock-push`\\n\" +\n \"would no longer recognise it.\\n\\n\" +\n \"Run `spell unblock-push` first (interactive), then uninstall.\",\n );\n process.exit(1);\n return; // guard: process.exit is mocked in tests\n }\n\n // Count total tracked files\n const allFiles = manifest.components.flatMap((c) => c.files);\n const totalFiles = allFiles.length;\n\n // Dry-run: print what would be removed without deleting\n if (options.dryRun) {\n for (const file of allFiles) {\n console.log(`[dry-run] Would remove: ${file}`);\n }\n console.log(`[dry-run] Would remove: .arcane.json`);\n console.log(`[dry-run] Would remove: .github/agents/ (directory)`);\n console.log(`[dry-run] Would remove: .arcane/agents/ (directory)`);\n console.log(`[dry-run] Would remove: .arcane/generated/ (directory)`);\n console.log(`[dry-run] Would remove: .arcane/agents.yaml`);\n console.log(`[dry-run] Would strip arcane sections from: CLAUDE.md, AGENTS.md, copilot-instructions.md`);\n console.log(`\\n[dry-run] ${totalFiles} file(s) + manifest + agent outputs would be removed.`);\n if (policy === \"blocked\" || controlsInForce) {\n console.log(\n `[dry-run] BUT the real run would refuse: Arcane's push block is in force. Run \\`spell unblock-push\\` first.`,\n );\n }\n return;\n }\n\n // Confirmation prompt (skipped with --yes)\n if (!options.yes) {\n const confirmed = await confirm({\n message: `This will remove ${totalFiles} files and .arcane.json. Continue?`,\n default: false,\n });\n\n if (!confirmed) {\n console.log(\"Uninstall cancelled.\");\n return;\n }\n }\n\n // Delete each file tracked in the manifest\n let removed = 0;\n for (const component of manifest.components) {\n for (const file of component.files) {\n const filePath = join(targetDir, file);\n try {\n await rm(filePath, { force: true });\n removed++;\n } catch {\n // Non-existent files are fine (force: true), but other errors propagate\n }\n }\n }\n\n // Delete .arcane.json\n await rm(join(targetDir, \".arcane.json\"), { force: true });\n\n // ── Clean up agent sync outputs (not tracked in manifest) ──────────────\n // Directories created by agent init/sync\n const agentDirs = [\n \".github/agents\",\n \".arcane/agents\",\n \".arcane/generated\",\n ];\n for (const dir of agentDirs) {\n await rm(join(targetDir, dir), { recursive: true, force: true });\n }\n // Roster file\n await rm(join(targetDir, \".arcane/agents.yaml\"), { force: true });\n\n // Strip arcane marker sections from merged files (keeps user content intact)\n const markerFiles = [\n \"CLAUDE.md\",\n \"AGENTS.md\",\n \".github/copilot-instructions.md\",\n ];\n for (const file of markerFiles) {\n await stripMarkerSection(targetDir, file, { dryRun: false });\n }\n\n // Secrets pre-commit hook (ARC-037): installed unconditionally by `spell\n // init` regardless of push_policy, so -- unlike the push-safety pre-push\n // hook -- there is no push_policy invariant above already guaranteeing\n // nothing is left behind. Without this, the hook would keep running\n // `spell doctor --leaks` against a project that no longer has an\n // .arcane.json to configure it, since `spell` itself is a separate global\n // install this command never touches. Best-effort: a failure here is a\n // leftover local convenience hook, not a reason to report uninstall itself\n // as failed.\n try {\n await removeSecretsPrecommitHook(targetDir);\n } catch {\n // Non-fatal.\n }\n\n console.log(`\\n✓ Uninstalled — ${removed} files removed.`);\n}\n","import { access, readFile, mkdir, copyFile as fsCopyFile } from \"node:fs/promises\";\nimport { join, dirname } from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { INCIDENT_QUEUE } from \"../config/incidents.js\";\nimport type { Delegation, DelegationsFile } from \"../types.js\";\nimport { evaluateIncidentGate } from \"../modules/incident-gate.js\";\nimport { runGit } from \"../modules/git.js\";\nimport { readManifest, resolveSecretsScanExcludePrefixes } from \"../modules/manifest.js\";\nimport { scanRepository } from \"../modules/denylist-scan.js\";\nimport { SECRETS_RULES } from \"../modules/secrets-scan.js\";\nimport {\n isHookEnforced,\n listRemotes,\n undisabledRemotes,\n pushTargets,\n} from \"../modules/push-safety.js\";\nimport {\n parseGitHubRemote,\n parseAdoRemote,\n fetchGitHubRulesets,\n fetchAdoMergeTypePolicies,\n evaluateGitHubMergePolicy,\n evaluateAdoMergePolicy,\n} from \"../modules/platform-policy.js\";\n\nconst execFileAsync = promisify(execFile);\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\ninterface CheckResult {\n name: string;\n passed: boolean;\n message: string;\n /** If false, this is a warning, not a blocker. Defaults to true (blocking). */\n blocking?: boolean;\n}\n\n// ─── Runtime validation helpers ───────────────────────────────────────────────\n// Every JSON file below is an external boundary (hand-editable, or written by\n// an older/foreign version of this tool) -- `JSON.parse` only proves \"valid\n// JSON\", never \"matches the shape this code assumes\". An unchecked `as` cast\n// on a non-object parse (e.g. a file containing the literal `null`) let a\n// later `.foo` access throw *outside* the surrounding try/catch, crashing\n// the whole `spell doctor` run instead of reporting one degraded check.\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n// ─── Individual checks ────────────────────────────────────────────────────────\n\nasync function checkNodeVersion(): Promise<CheckResult> {\n const name = \"Node.js version\";\n const raw = process.version; // e.g. \"v20.11.0\"\n const major = parseInt(raw.replace(/^v/, \"\").split(\".\")[0] ?? \"0\", 10);\n if (major >= 18) {\n return { name, passed: true, message: `${raw} (>=18 required)` };\n }\n return {\n name,\n passed: false,\n message: `${raw} — Node.js 18 or later is required`,\n };\n}\n\nasync function checkVSCodeExtension(\n id: string,\n label: string,\n): Promise<CheckResult> {\n const name = `VS Code extension: ${label}`;\n // Check extension directories on disk — more reliable than --list-extensions\n // in child process contexts (snap binaries may not output to non-TTY stdout).\n const home = process.env[\"HOME\"] ?? \"\";\n const extDirs = [\n join(home, \".vscode\", \"extensions\"),\n join(home, \".vscode-insiders\", \"extensions\"),\n ];\n\n for (const dir of extDirs) {\n try {\n const { readdir } = await import(\"node:fs/promises\");\n const entries = await readdir(dir);\n const prefix = id.toLowerCase() + \"-\";\n const found = entries.some(\n (e) => e.toLowerCase() === id.toLowerCase() || e.toLowerCase().startsWith(prefix),\n );\n if (found) {\n return { name, passed: true, message: `${id} is installed` };\n }\n } catch {\n // Directory doesn't exist — skip\n }\n }\n\n // Determine install command (prefer code-insiders if present)\n let installBin = \"code\";\n for (const bin of [\"code\", \"code-insiders\"]) {\n try {\n await execFileAsync(bin, [\"--version\"]);\n installBin = bin;\n break;\n } catch {\n // not found\n }\n }\n\n return {\n name,\n passed: false,\n message: `${id} not found. Install via: ${installBin} --install-extension ${id}`,\n blocking: false,\n };\n}\n\nexport async function checkArcaneManifest(targetDir: string): Promise<CheckResult> {\n const name = \"Arcane manifest (.arcane.json)\";\n const manifestPath = join(targetDir, \".arcane.json\");\n try {\n await access(manifestPath);\n } catch {\n const selfHostedManifestPath = join(targetDir, \"src\", \"assets\", \".arcane.json\");\n try {\n const raw = await readFile(selfHostedManifestPath, \"utf8\");\n const manifest: unknown = JSON.parse(raw);\n if (\n isRecord(manifest) &&\n manifest[\"selfHosted\"] === true &&\n manifest[\"tracking_mode\"] === \"internal\"\n ) {\n return {\n name,\n passed: true,\n message: \"self-hosted source tree — committed source manifest is authoritative\",\n };\n }\n } catch {\n // No valid self-hosting marker — report the normal missing-manifest warning.\n }\n return {\n name,\n passed: false,\n message: \"No .arcane.json found. Run `spell init` to initialize Arcane in this project.\",\n blocking: false,\n };\n }\n\n try {\n const raw = await readFile(manifestPath, \"utf8\");\n const manifest: unknown = JSON.parse(raw);\n if (\n !isRecord(manifest) ||\n typeof manifest[\"version\"] !== \"string\" ||\n !manifest[\"version\"] ||\n !Array.isArray(manifest[\"components\"])\n ) {\n return {\n name,\n passed: false,\n message: \".arcane.json is present but missing required fields (version, components). Re-run `spell init`.\",\n };\n }\n return {\n name,\n passed: true,\n message: `v${manifest[\"version\"]} — ${manifest[\"components\"].length} component(s) installed`,\n };\n } catch {\n return {\n name,\n passed: false,\n message: \".arcane.json is present but contains invalid JSON. Re-run `spell init`.\",\n };\n }\n}\n\n/**\n * EF-32: independently verify the EFFECTIVE (not just repository-local)\n * pull.rebase resolves to \"true\", catching drift regardless of source --\n * an install that predates `spell init`'s own fix, a value unset again\n * later, or any other path that bypassed init's one-time correction.\n * Non-blocking: this repo has no CI job running inside the operator's own\n * working copy, so a doctor warning is the only enforcement mode available\n * here (see ARC-023's inline-enforcement-contract requirement).\n */\nexport async function checkPullRebase(targetDir: string): Promise<CheckResult> {\n const name = \"Git pull.rebase (rebase-and-fast-forward mandate)\";\n try {\n // --type=bool normalizes any of git's valid boolean spellings\n // (true/yes/on/1, false/no/off/0) to canonical \"true\"/\"false\" -- a raw\n // string comparison against \"true\" alone would false-positive-warn on\n // a fully compliant \"yes\"/\"on\"/\"1\".\n const { stdout } = await runGit(targetDir, [\"config\", \"--type=bool\", \"--get\", \"pull.rebase\"]);\n const value = stdout.trim();\n if (value === \"true\") {\n return { name, passed: true, message: \"pull.rebase=true\" };\n }\n return {\n name,\n passed: false,\n message: `pull.rebase resolves to \"${value}\", not \"true\" -- a bare \\`git pull\\` will create merge commits, contradicting git-conventions.md's rebase-and-fast-forward mandate. Run: git config --local pull.rebase true`,\n blocking: false,\n };\n } catch {\n // Two cases collapse here: unset entirely, or set to a non-boolean\n // value (e.g. \"merges\") --type=bool can't coerce -- both mean\n // \"not affirmatively true\", which is what this check cares about.\n return {\n name,\n passed: false,\n message: \"pull.rebase is unset, not a recognized boolean, or this isn't a Git repository -- effective behavior may not be rebase-and-fast-forward, and Git for Windows defaults this to false when unset. Run: git config --local pull.rebase true\",\n blocking: false,\n };\n }\n}\n\nexport function checkIncidentReleaseGate(): CheckResult {\n const result = evaluateIncidentGate(INCIDENT_QUEUE);\n if (result.blocked) {\n return {\n name: \"Incident release gate (ARC-024)\",\n passed: false,\n message: result.blockers.join(\"; \"),\n };\n }\n const accepted = result.acceptedRisks.length > 0\n ? `; ${result.acceptedRisks.length} explicitly deferred`\n : \"\";\n return {\n name: \"Incident release gate (ARC-024)\",\n passed: true,\n message: `${result.checked} incidents classified${accepted}`,\n };\n}\n\n/**\n * ARC-037 decision 7: `spell check-leaks` folded into `spell doctor` as an\n * on-demand mode (`--leaks`) instead of a standalone command -- one fewer\n * entry point for the same scan the build's own CI backstop already runs\n * (scripts/copy-assets.ts). Not part of the default battery below: a\n * full-repository walk is a different cost profile than doctor's other\n * checks, and (per decision 6) the real defense is the CI backstop --\n * this is a fast, opt-in, run-it-yourself pass, mirroring `spell ward`'s\n * own separateness from the default battery.\n */\nexport async function checkSecrets(targetDir: string): Promise<CheckResult> {\n const name = \"Secrets scan (ARC-037)\";\n const excludePrefixes = await resolveSecretsScanExcludePrefixes(targetDir);\n const findings = await scanRepository(targetDir, SECRETS_RULES, undefined, excludePrefixes);\n if (findings.length === 0) {\n return { name, passed: true, message: \"no credential-shaped patterns found\" };\n }\n\n const summary = findings.map((f) => `${f.file}:${f.line} [${f.rule}]`).join(\"; \");\n return {\n name,\n passed: false,\n message: `${findings.length} credential-shaped pattern(s) found: ${summary}`,\n };\n}\n\n// ─── Session continuity checks ────────────────────────────────────────────────\n\n/** Files required for spell-close-session / spell-open-session to function. */\nexport const SESSION_CONTINUITY_FILES = [\n \"TODO.md\",\n \"DECISIONS.md\",\n \"ai-context/system-prompt-context.md\",\n \"journal/.gitkeep\",\n];\n\nexport async function checkSessionContinuity(targetDir: string): Promise<CheckResult[]> {\n const results: CheckResult[] = [];\n\n for (const file of SESSION_CONTINUITY_FILES) {\n const name = `Session file: ${file}`;\n const filePath = join(targetDir, file);\n try {\n await access(filePath);\n results.push({ name, passed: true, message: \"present\" });\n } catch {\n results.push({\n name,\n passed: false,\n message: `Missing. Required for spell-close-session. Run \\`spell doctor --fix\\` to create it.`,\n blocking: false,\n });\n }\n }\n\n return results;\n}\n\nexport async function fixSessionContinuity(targetDir: string, assetsDir: string): Promise<string[]> {\n const created: string[] = [];\n\n for (const file of SESSION_CONTINUITY_FILES) {\n const destPath = join(targetDir, file);\n try {\n await access(destPath);\n // File exists — skip\n } catch {\n // File missing — create from template\n const srcPath = join(assetsDir, file);\n await mkdir(dirname(destPath), { recursive: true });\n await fsCopyFile(srcPath, destPath);\n created.push(file);\n }\n }\n\n return created;\n}\n\n// ─── Main ─────────────────────────────────────────────────────────────────────\n\nexport interface DoctorOptions {\n fix?: boolean;\n /** ARC-037 decision 7: run only the on-demand secrets scan, skipping the default battery. */\n leaks?: boolean;\n}\n\n/**\n * EF-09 R4. Reports the repository's declared push posture and, for a\n * \"blocked\" repo, whether the controls are actually in place.\n *\n * Deliberately fires for every \"guarded\" repo REGARDLESS of remote state. An\n * earlier draft only reported when no remote was configured, which meant the\n * reminder went silent the instant any remote was added -- including a wrong\n * one -- making \"guarded\" behave identically to \"open\" exactly when it\n * mattered most.\n */\nexport async function checkPushPolicy(targetDir: string): Promise<CheckResult> {\n const name = \"Push policy (EF-09)\";\n let manifest;\n try {\n manifest = await readManifest(targetDir);\n } catch {\n return { name, passed: true, message: \"not initialized — nothing to check\" };\n }\n\n const policy = manifest.push_policy ?? \"open\";\n\n if (policy === \"open\") {\n return { name, passed: true, message: \"open — pushes allowed\" };\n }\n\n if (policy === \"guarded\") {\n // Name AND URL: the reminder's whole job is catching a wrong remote, and the\n // name alone reveals nothing about where it points.\n const targets = await pushTargets(targetDir);\n const where =\n targets.length === 0\n ? \"none configured\"\n : targets\n .map(({ remote, urls }) => `${remote} → ${urls.length > 0 ? urls.join(\", \") : \"unknown\"}`)\n .join(\"; \");\n return {\n name,\n passed: false,\n blocking: false,\n message: `guarded — no technical control installed. Push targets: ${where}. Confirm those are the remotes you intend before pushing.`,\n };\n }\n\n // blocked: verify the controls are genuinely IN FORCE, not merely declared.\n // Checking config alone was a declaration check wearing an enforcement\n // check's name -- deleting the hook file leaves core.hooksPath intact and\n // pushes succeed, while this reported the hook as present.\n const hookActive = await isHookEnforced(targetDir);\n const remotes = await listRemotes(targetDir);\n const open = await undisabledRemotes(targetDir);\n\n if (hookActive && open.length === 0) {\n if (remotes.length === 0) {\n // Don't claim a push URL is \"in place\" when there is no remote at all.\n // The hook is the only live control here, and it is the one a\n // `--no-verify` push walks straight past -- so say that plainly rather\n // than reporting full protection.\n return {\n name,\n passed: false,\n blocking: false,\n message:\n \"blocked — pre-push hook in place, but no remote is configured, so no push URL is disabled. If a remote is added later, run `spell doctor` again: a --no-verify push to it would succeed until the URL is disabled too.\",\n };\n }\n return {\n name,\n passed: true,\n message: `blocked — pre-push hook in place and push URL disabled for ${remotes.join(\", \")}`,\n };\n }\n\n const missing = [\n hookActive ? null : \"pre-push hook (config or hook file absent)\",\n open.length > 0 ? `push URL still live for: ${open.join(\", \")}` : null,\n ].filter(Boolean);\n\n return {\n name,\n passed: false,\n blocking: false,\n message: `declared \"blocked\" but not enforced — ${missing.join(\"; \")}. The manifest claims a protection this repository does not have.`,\n };\n}\n\ninterface McpServerConfig {\n timeout?: number;\n}\n\ninterface McpConfigFile {\n mcpServers?: Record<string, McpServerConfig>;\n}\n\n/**\n * I12/BC-22. Checks that any configured .mcp.json server sets a per-server\n * \"timeout\" -- companion to the MCP fail-fast/fallback rule in\n * git-conventions.md. Without one, a hung server runs to the client's own\n * default idle limit (as long as 30 minutes) instead of a predictable one.\n * A missing .mcp.json is a silent pass -- MCP is optional.\n */\nexport async function checkMcpConfig(targetDir: string): Promise<CheckResult> {\n const name = \"MCP config (per-server timeout, I12)\";\n const filePath = join(targetDir, \".mcp.json\");\n\n let raw: string;\n try {\n raw = await readFile(filePath, \"utf8\");\n } catch {\n return { name, passed: true, blocking: false, message: \"no .mcp.json — nothing to check\" };\n }\n\n let rawParsed: unknown;\n try {\n rawParsed = JSON.parse(raw);\n } catch {\n return {\n name,\n passed: false,\n blocking: false,\n message: \".mcp.json exists but contains invalid JSON\",\n };\n }\n\n if (!isRecord(rawParsed)) {\n return {\n name,\n passed: false,\n blocking: false,\n message: \".mcp.json exists but is not a JSON object\",\n };\n }\n\n // Field-level shape (mcpServers, per-server timeout) is untrusted beyond\n // this point -- every access below is `?.`-guarded rather than assumed.\n const parsed = rawParsed as McpConfigFile;\n const servers = parsed.mcpServers ?? {};\n const serverNames = Object.keys(servers);\n if (serverNames.length === 0) {\n return { name, passed: true, blocking: false, message: \"no MCP servers configured\" };\n }\n\n const missingTimeout = serverNames.filter((n) => typeof servers[n]?.timeout !== \"number\");\n if (missingTimeout.length > 0) {\n return {\n name,\n passed: false,\n blocking: false,\n message: `server(s) missing a \"timeout\": ${missingTimeout.join(\", \")} — a hang runs to the client's own default idle limit (up to 30 min) instead of a predictable one`,\n };\n }\n\n return {\n name,\n passed: true,\n blocking: false,\n message: `${serverNames.length} server(s) configured, all with a timeout set`,\n };\n}\n\nfunction isDelegation(value: unknown): value is Delegation {\n return (\n isRecord(value) &&\n typeof value[\"id\"] === \"string\" &&\n typeof value[\"status\"] === \"string\" &&\n typeof value[\"scope\"] === \"string\" &&\n Array.isArray(value[\"excludedActions\"])\n );\n}\n\nfunction isDelegationsFile(value: unknown): value is DelegationsFile {\n return isRecord(value) && Array.isArray(value[\"delegations\"]) && value[\"delegations\"].every(isDelegation);\n}\n\n/**\n * T13/BC-19. Lists standing-authority delegations recorded in\n * `.arcane/delegations.json` -- the solo-operator/no-roster counterpart to\n * agent-policies.md's roster-based power-level matrix. A missing file is a\n * silent pass, not a warning: a repo with no ad hoc grants has nothing to\n * report. This check only reports; it never grants, revokes, or validates\n * authority -- revocation is the git-native act of editing the file itself.\n */\nexport async function checkDelegations(targetDir: string): Promise<CheckResult> {\n const name = \"Standing delegations (T13)\";\n const filePath = join(targetDir, \".arcane\", \"delegations.json\");\n\n let raw: string;\n try {\n raw = await readFile(filePath, \"utf8\");\n } catch {\n return { name, passed: true, blocking: false, message: \"no delegations recorded\" };\n }\n\n let rawParsed: unknown;\n try {\n rawParsed = JSON.parse(raw);\n } catch {\n return {\n name,\n passed: false,\n blocking: false,\n message: `.arcane/delegations.json exists but contains invalid JSON`,\n };\n }\n\n if (!isDelegationsFile(rawParsed)) {\n return {\n name,\n passed: false,\n blocking: false,\n message: `.arcane/delegations.json exists but is not a valid delegations file (expected a \"delegations\" array of well-formed entries)`,\n };\n }\n const parsed = rawParsed;\n\n const active = parsed.delegations.filter((d) => d.status === \"active\");\n if (active.length === 0) {\n return { name, passed: true, blocking: false, message: \"no active delegations\" };\n }\n\n const summary = active\n .map((d) => `${d.id} (scope: ${d.scope}; excludes: ${d.excludedActions.length} action(s))`)\n .join(\"; \");\n return {\n name,\n passed: true,\n blocking: false,\n message: `${active.length} active: ${summary}`,\n };\n}\n\n/**\n * T11/BC-17. Verifies the live platform branch/merge policy matches the\n * declared ladder (git-conventions.md: merge + rebase sanctioned, squash\n * never sanctioned). GitHub is checked via Rulesets, never the classic\n * `/branches/{branch}/protection` endpoint alone -- that endpoint 404s\n * \"not protected\" for a Rulesets-only repo (confirmed live against this\n * repo's own main branch), a false negative this check must not repeat.\n * Report-only: never mutates a platform setting. Degrades to a\n * non-blocking warning for any provider it can't resolve, any CLI it\n * can't reach, or any auth/network failure -- this check depends on\n * external state doctor's other checks never do, so it must never be the\n * reason `doctor` crashes.\n */\nexport async function checkPlatformBranchPolicy(targetDir: string): Promise<CheckResult> {\n const name = \"Platform branch/merge policy (T11)\";\n const targets = await pushTargets(targetDir);\n const origin = targets.find((t) => t.remote === \"origin\") ?? targets[0];\n const url = origin?.urls[0];\n\n if (!url) {\n return { name, passed: true, message: \"no remote configured — nothing to check\", blocking: false };\n }\n\n const github = parseGitHubRemote(url);\n if (github) {\n const rulesets = await fetchGitHubRulesets(github.owner, github.repo);\n if (rulesets === null) {\n return {\n name,\n passed: false,\n blocking: false,\n message: `could not query GitHub Rulesets for ${github.owner}/${github.repo} — is \\`gh\\` installed and authenticated? Verify manually: gh api repos/${github.owner}/${github.repo}/rulesets`,\n };\n }\n const result = evaluateGitHubMergePolicy(rulesets);\n return { name, passed: result.passed, blocking: false, message: result.message };\n }\n\n const ado = parseAdoRemote(url);\n if (ado) {\n const policies = await fetchAdoMergeTypePolicies(ado.org, ado.project, ado.repo, \"main\");\n if (policies === null) {\n return {\n name,\n passed: false,\n blocking: false,\n message: `could not query the Azure DevOps \"Limit merge types\" branch policy for ${ado.org}/${ado.project}/${ado.repo} — is \\`az\\` installed and authenticated? Verify manually in the ADO web UI under Branch Policies.`,\n };\n }\n const result = evaluateAdoMergePolicy(policies);\n return { name, passed: result.passed, blocking: false, message: result.message };\n }\n\n return {\n name,\n passed: true,\n blocking: false,\n message: \"remote is neither GitHub nor Azure DevOps — platform policy verification not available for this provider\",\n };\n}\n\nexport async function runDoctor(targetDir: string, options: DoctorOptions = {}, assetsDir?: string): Promise<void> {\n console.log(\"\\nspell doctor — checking your Arcane environment\\n\");\n\n if (options.leaks) {\n const result = await checkSecrets(targetDir);\n const icon = result.passed ? \"✓\" : \"✗\";\n console.log(` ${icon} [${result.passed ? \"pass\" : \"FAIL\"}] ${result.name}`);\n if (!result.passed) {\n console.log(` ${result.message}`);\n console.log(\"\\n One or more checks failed. Fix the issues above before proceeding.\\n\");\n process.exitCode = 1;\n } else {\n console.log(\"\\n All checks passed. Your environment is ready.\\n\");\n }\n return;\n }\n\n const results = await Promise.all([\n checkNodeVersion(),\n checkVSCodeExtension(\"GitHub.copilot-chat\", \"GitHub Copilot (Chat)\"),\n checkArcaneManifest(targetDir),\n Promise.resolve(checkIncidentReleaseGate()),\n checkPullRebase(targetDir),\n checkPushPolicy(targetDir),\n checkPlatformBranchPolicy(targetDir),\n checkDelegations(targetDir),\n checkMcpConfig(targetDir),\n ]);\n\n // Add session continuity checks\n const sessionResults = await checkSessionContinuity(targetDir);\n results.push(...sessionResults);\n\n let allPassed = true;\n\n for (const result of results) {\n const icon = result.passed ? \"✓\" : result.blocking === false ? \"⚠\" : \"✗\";\n const label = result.passed\n ? \"pass\"\n : result.blocking === false\n ? \"warn\"\n : \"FAIL\";\n console.log(` ${icon} [${label}] ${result.name}`);\n if (!result.passed) {\n console.log(` ${result.message}`);\n }\n if (!result.passed && result.blocking !== false) {\n allPassed = false;\n }\n }\n\n console.log();\n\n if (allPassed) {\n console.log(\" All checks passed. Your environment is ready.\\n\");\n } else {\n console.log(\" One or more checks failed. Fix the issues above before proceeding.\\n\");\n\n // --fix: remediate missing session continuity files\n const hasMissingSession = sessionResults.some((r) => !r.passed);\n if (options.fix && hasMissingSession && assetsDir) {\n console.log(\" 🔧 Fixing missing session continuity files...\\n\");\n const created = await fixSessionContinuity(targetDir, assetsDir);\n if (created.length > 0) {\n for (const file of created) {\n console.log(` ✓ Created: ${file}`);\n }\n console.log(`\\n ${created.length} file(s) created. Repo is now close-session-ready.\\n`);\n } else {\n console.log(\" No files needed creation (all present).\\n\");\n }\n } else if (hasMissingSession && !options.fix) {\n console.log(\" 💡 Run `spell doctor --fix` to create missing session files.\\n\");\n }\n\n if (!allPassed) {\n process.exitCode = 1;\n }\n }\n}\n","export type IncidentSeverity = \"critical\" | \"high\" | \"medium\" | \"low\";\nexport type IncidentImpact = \"data-integrity\" | \"security\" | \"other\";\nexport type IncidentConfidence = \"confirmed\" | \"research\";\nexport type IncidentState = \"open\" | \"resolved\" | \"deferred\";\n\nexport interface IncidentRecord {\n id: string;\n severity?: IncidentSeverity;\n impact: IncidentImpact;\n confidence: IncidentConfidence;\n state: IncidentState;\n detectedOn: string;\n resolution?: string;\n deferral?: string;\n}\n\nexport const INCIDENT_QUEUE: IncidentRecord[] = [\n { id: \"EF-05\", severity: \"medium\", impact: \"other\", confidence: \"confirmed\", state: \"open\", detectedOn: \"2026-07-31\" },\n { id: \"EF-08\", severity: \"medium\", impact: \"other\", confidence: \"confirmed\", state: \"open\", detectedOn: \"2026-07-31\" },\n { id: \"EF-16\", severity: \"high\", impact: \"other\", confidence: \"confirmed\", state: \"open\", detectedOn: \"2026-07-31\" },\n { id: \"EF-17\", severity: \"high\", impact: \"other\", confidence: \"confirmed\", state: \"open\", detectedOn: \"2026-07-31\" },\n { id: \"EF-20\", severity: \"high\", impact: \"other\", confidence: \"research\", state: \"open\", detectedOn: \"2026-07-31\" },\n { id: \"EF-21\", severity: \"high\", impact: \"other\", confidence: \"confirmed\", state: \"open\", detectedOn: \"2026-07-31\" },\n { id: \"EF-23\", severity: \"medium\", impact: \"other\", confidence: \"confirmed\", state: \"open\", detectedOn: \"2026-07-31\" },\n { id: \"EF-25\", severity: \"high\", impact: \"data-integrity\", confidence: \"confirmed\", state: \"resolved\", detectedOn: \"2026-07-14\", resolution: \"PRs 13 and 14\" },\n { id: \"EF-26\", severity: \"high\", impact: \"security\", confidence: \"confirmed\", state: \"resolved\", detectedOn: \"2026-07-31\", resolution: \"PR 15\" },\n { id: \"EF-27\", severity: \"high\", impact: \"security\", confidence: \"confirmed\", state: \"resolved\", detectedOn: \"2026-07-31\", resolution: \"PR 16\" },\n { id: \"EF-28\", severity: \"high\", impact: \"security\", confidence: \"confirmed\", state: \"resolved\", detectedOn: \"2026-07-31\", resolution: \"PR 17\" },\n { id: \"EF-29\", severity: \"medium\", impact: \"other\", confidence: \"confirmed\", state: \"resolved\", detectedOn: \"2026-07-31\", resolution: \"PR 18\" },\n];","import type { IncidentRecord } from \"../config/incidents.js\";\n\nconst DEFERRAL_PATTERN = /^Deferred \\d{4}-\\d{2}-\\d{2} — known open, accepting the risk\\.$/;\nconst BLOCKING_SEVERITIES = new Set([\"critical\", \"high\"]);\nconst PROTECTED_IMPACTS = new Set([\"data-integrity\", \"security\"]);\n\nexport interface IncidentGateResult {\n blocked: boolean;\n blockers: string[];\n acceptedRisks: string[];\n checked: number;\n}\n\nexport function evaluateIncidentGate(records: IncidentRecord[]): IncidentGateResult {\n const blockers: string[] = [];\n const acceptedRisks: string[] = [];\n const seen = new Set<string>();\n\n for (const record of records) {\n if (seen.has(record.id)) {\n blockers.push(`${record.id}: duplicate incident record`);\n continue;\n }\n seen.add(record.id);\n\n if (record.confidence === \"research\") continue;\n if (!PROTECTED_IMPACTS.has(record.impact)) continue;\n\n if (!record.severity) {\n blockers.push(`${record.id}: confirmed ${record.impact} incident is missing severity`);\n continue;\n }\n if (!BLOCKING_SEVERITIES.has(record.severity)) continue;\n\n if (record.state === \"resolved\") {\n if (!record.resolution?.trim()) {\n blockers.push(`${record.id}: resolved incident is missing resolution evidence`);\n }\n continue;\n }\n\n if (record.state === \"deferred\") {\n if (!record.deferral || !DEFERRAL_PATTERN.test(record.deferral)) {\n blockers.push(\n `${record.id}: deferral must be exactly \"Deferred <date> — known open, accepting the risk.\"`,\n );\n } else {\n acceptedRisks.push(`${record.id}: ${record.deferral}`);\n }\n continue;\n }\n\n blockers.push(\n `${record.id}: unresolved ${record.severity} ${record.impact} incident blocks release`,\n );\n }\n\n return {\n blocked: blockers.length > 0,\n blockers,\n acceptedRisks,\n checked: records.length,\n };\n}","/**\n * Generic denylist scanning engine: word-boundary matching, tree-walking,\n * and dedup -- shared by `scripts/org-token-lint.ts` (Arcane's own private\n * build gate) and `spell ward` (BC-21, a shipped CLI command any consumer\n * repo can run). Extracted here because these functions were never actually\n * org-token-specific -- only the *resolution* of which tokens to scan for\n * (an env var, a CLI flag, a mandatory vendor list) differs per caller.\n */\n\nimport { readFile, readdir } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\n\nexport interface DenylistRule {\n label: string;\n pattern: RegExp;\n}\n\nexport interface DenylistFinding {\n file: string;\n line: number;\n rule: string;\n}\n\nexport function escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/** Word-boundary rules: a token must not be flanked by another word character. */\nexport function createDenylistRules(\n tokens: string[],\n labelPrefix: string,\n): DenylistRule[] {\n return tokens.map((token, index) => ({\n label: `${labelPrefix}-${index + 1}`,\n pattern: new RegExp(\n `(?:^|[^A-Za-z0-9])${escapeRegExp(token)}(?=$|[^A-Za-z0-9])`,\n \"i\",\n ),\n }));\n}\n\n/**\n * Scans one file for denylist rules. Documented {UPPER_SNAKE} placeholders\n * are stripped before matching so they never trip a rule.\n */\nexport async function scanFile(\n absolutePath: string,\n displayPath: string,\n rules: DenylistRule[],\n): Promise<DenylistFinding[]> {\n const findings: DenylistFinding[] = [];\n let content: string;\n try {\n content = await readFile(absolutePath, \"utf8\");\n } catch {\n return findings;\n }\n\n const lines = content.split(\"\\n\");\n for (let index = 0; index < lines.length; index++) {\n const searchable = lines[index]!.replace(/\\{[A-Z][A-Z0-9_]*\\}/g, \"\");\n for (const rule of rules) {\n if (rule.pattern.test(searchable)) {\n findings.push({ file: displayPath, line: index + 1, rule: rule.label });\n break;\n }\n }\n }\n\n return findings;\n}\n\n/**\n * Directories never worth scanning -- generated output, dependencies, VCS\n * metadata. \".claude\" specifically covers `.claude/worktrees/`: each entry\n * there is a full nested checkout of this same repository (a linked git\n * worktree), so anything real inside one is scanned again at the primary\n * checkout's own path -- walking it too only triples every finding without\n * surfacing anything new (confirmed empirically widening the ARC-037 scan\n * repository-wide: every one of a worktree's findings duplicated a root-path\n * finding byte-for-byte).\n */\nexport const SKIP_DIRECTORIES = new Set([\n \"node_modules\",\n \".git\",\n \"dist\",\n \"coverage\",\n \".vitest\",\n \".claude\",\n]);\n\nexport const DEFAULT_SCANNABLE_EXTENSIONS = [\".md\", \".ts\", \".js\", \".json\", \".yml\", \".yaml\"];\n\n/**\n * Recursively collects every scannable file under `root`, returning\n * [absolutePath, repoRelativePath] pairs. `extensions` defaults to text\n * formats; a caller scanning binary asset strings (ward) passes its own list.\n */\nexport async function collectScannableFiles(\n root: string,\n repoRoot: string = root,\n extensions: string[] = DEFAULT_SCANNABLE_EXTENSIONS,\n): Promise<Array<[string, string]>> {\n const collected: Array<[string, string]> = [];\n let entries;\n try {\n entries = await readdir(root, { withFileTypes: true });\n } catch {\n return collected;\n }\n\n for (const entry of entries) {\n const absolutePath = join(root, entry.name);\n if (entry.isDirectory()) {\n if (SKIP_DIRECTORIES.has(entry.name)) continue;\n collected.push(...(await collectScannableFiles(absolutePath, repoRoot, extensions)));\n } else if (extensions.some((ext) => entry.name.endsWith(ext))) {\n const displayPath = relative(repoRoot, absolutePath).replace(/\\\\/g, \"/\");\n collected.push([absolutePath, displayPath]);\n }\n }\n\n return collected;\n}\n\n/**\n * Scans an entire repository tree (text files by default) for denylist rules.\n * `excludePrefixes` drops any file whose repo-relative display path contains\n * one of the given literal substrings before it's ever read -- a scan blind\n * spot the caller opted into, not a post-hoc filter on findings (ARC-037).\n */\nexport async function scanRepository(\n repoRoot: string,\n rules: DenylistRule[],\n extensions?: string[],\n excludePrefixes: string[] = [],\n): Promise<DenylistFinding[]> {\n if (rules.length === 0) return [];\n\n const findings: DenylistFinding[] = [];\n for (const [absolutePath, displayPath] of await collectScannableFiles(repoRoot, repoRoot, extensions)) {\n if (excludePrefixes.some((prefix) => displayPath.includes(prefix))) continue;\n findings.push(...(await scanFile(absolutePath, displayPath, rules)));\n }\n return findings;\n}\n\n/** Merges finding lists, collapsing duplicates reported at the same file:line. */\nexport function dedupeFindings(...lists: DenylistFinding[][]): DenylistFinding[] {\n const seen = new Map<string, DenylistFinding>();\n for (const list of lists) {\n for (const finding of list) {\n const key = `${finding.file}:${finding.line}`;\n if (!seen.has(key)) seen.set(key, finding);\n }\n }\n return [...seen.values()];\n}\n","/**\n * Platform branch/merge policy verification (T11/BC-17).\n *\n * Report-only: nothing here mutates a repository or organization setting.\n * Rule-interpretation logic is split into pure functions taking\n * already-fetched JSON (evaluate*) so it is unit-testable with fixture\n * data, separate from the thin CLI-invocation wrappers (fetch*) that are\n * not exercised in CI (no live GitHub/ADO credentials to test against).\n *\n * GitHub Rulesets path is live-verified against this repo's own real\n * ruleset. The Azure DevOps path is implemented from documented API\n * shape only -- this repo has no ADO remote to test against -- and that\n * limitation is disclosed here rather than presented as verified.\n */\n\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\n// ─── Declared ladder (git-conventions.md § Merge Strategy by Repo Risk) ──────\n\nexport type MergeMethod = \"merge\" | \"squash\" | \"rebase\";\nexport const SANCTIONED_MERGE_METHODS: readonly MergeMethod[] = [\"merge\", \"rebase\"];\n\nexport interface PolicyEvaluation {\n passed: boolean;\n /** null when no policy/ruleset was found to evaluate at all. */\n effectiveMergeMethods: MergeMethod[] | null;\n /** Methods the raw config nominally allows but a separate rule silently blocks. */\n declaredButBlocked: MergeMethod[];\n /** Methods effectively permitted despite never being sanctioned. */\n disallowedButPermitted: MergeMethod[];\n message: string;\n}\n\nfunction compareToLadder(\n effective: MergeMethod[],\n declaredButBlocked: MergeMethod[],\n interactionNote?: string,\n): PolicyEvaluation {\n const disallowedButPermitted = effective.filter(\n (m) => !SANCTIONED_MERGE_METHODS.includes(m),\n );\n const missingSanctioned = SANCTIONED_MERGE_METHODS.filter(\n (m) => !effective.includes(m),\n );\n const passed = disallowedButPermitted.length === 0 && missingSanctioned.length === 0;\n\n const messages: string[] = [];\n if (interactionNote) messages.push(interactionNote);\n if (disallowedButPermitted.length > 0) {\n messages.push(\n `disallowed method(s) effectively permitted: ${disallowedButPermitted.join(\", \")} (never sanctioned per git-conventions.md)`,\n );\n }\n if (missingSanctioned.length > 0) {\n messages.push(\n `sanctioned method(s) not effectively available: ${missingSanctioned.join(\", \")}`,\n );\n }\n\n return {\n passed,\n effectiveMergeMethods: effective,\n declaredButBlocked,\n disallowedButPermitted,\n message: passed\n ? `effective merge methods [${effective.join(\", \")}] match the declared ladder`\n : messages.join(\"; \"),\n };\n}\n\n// ─── GitHub Rulesets ──────────────────────────────────────────────────────────\n\nexport interface GitHubRulesetRule {\n type: string;\n parameters?: Record<string, unknown>;\n}\n\nexport interface GitHubRuleset {\n id: number;\n target: string;\n enforcement: string;\n rules: GitHubRulesetRule[];\n}\n\n/**\n * Pure evaluation: given already-fetched ruleset detail JSON for the rulesets\n * covering the target branch, determines the EFFECTIVE merge-method policy.\n *\n * Detects the interaction this repo's own 2026-08-24/25 incident found:\n * a `required_linear_history` rule silently blocks merge-commit PRs\n * regardless of what a `pull_request` rule's `allowed_merge_methods`\n * parameter declares.\n */\nexport function evaluateGitHubMergePolicy(\n rulesets: GitHubRuleset[],\n): PolicyEvaluation {\n const active = rulesets.filter(\n (r) => r.enforcement === \"active\" && r.target === \"branch\",\n );\n\n if (active.length === 0) {\n return {\n passed: false,\n effectiveMergeMethods: null,\n declaredButBlocked: [],\n disallowedButPermitted: [],\n message:\n \"No active branch ruleset covers the target branch (checked via Rulesets, not the classic protection endpoint, which false-negatives on Rulesets-only repos).\",\n };\n }\n\n // GitHub applies the most restrictive union when multiple rulesets target\n // the same ref -- intersect allowed_merge_methods across all of them.\n let allowedMergeMethods: MergeMethod[] | null = null;\n let hasRequiredLinearHistory = false;\n\n for (const ruleset of active) {\n for (const rule of ruleset.rules) {\n if (rule.type === \"required_linear_history\") {\n hasRequiredLinearHistory = true;\n }\n if (rule.type === \"pull_request\") {\n const methods = rule.parameters?.[\"allowed_merge_methods\"];\n if (Array.isArray(methods)) {\n const typed = methods as MergeMethod[];\n allowedMergeMethods =\n allowedMergeMethods === null\n ? typed\n : allowedMergeMethods.filter((m) => typed.includes(m));\n }\n }\n }\n }\n\n // No pull_request rule set allowed_merge_methods at all -- GitHub's\n // platform default (all three methods) applies, which is never compliant.\n const nominal = allowedMergeMethods ?? [\"merge\", \"squash\", \"rebase\"];\n const effective = hasRequiredLinearHistory\n ? nominal.filter((m) => m !== \"merge\")\n : nominal;\n const declaredButBlocked: MergeMethod[] =\n hasRequiredLinearHistory && nominal.includes(\"merge\") ? [\"merge\"] : [];\n\n const interactionNote =\n declaredButBlocked.length > 0\n ? `allowed_merge_methods declares [${nominal.join(\", \")}] but a required_linear_history rule silently blocks merge commits regardless -- effective methods are [${effective.join(\", \")}]`\n : undefined;\n\n return compareToLadder(effective, declaredButBlocked, interactionNote);\n}\n\nexport async function fetchGitHubRulesets(\n owner: string,\n repo: string,\n): Promise<GitHubRuleset[] | null> {\n try {\n const { stdout: listOut } = await execFileAsync(\"gh\", [\n \"api\",\n `repos/${owner}/${repo}/rulesets`,\n ]);\n const summaries = JSON.parse(listOut) as Array<{ id: number }>;\n const detailed = await Promise.all(\n summaries.map(async (s) => {\n const { stdout } = await execFileAsync(\"gh\", [\n \"api\",\n `repos/${owner}/${repo}/rulesets/${s.id}`,\n ]);\n return JSON.parse(stdout) as GitHubRuleset;\n }),\n );\n return detailed;\n } catch {\n return null;\n }\n}\n\n// ─── Azure DevOps branch policy ───────────────────────────────────────────────\n// NOT live-verified (see module doc comment and the PRD's Open Questions).\n\nexport interface AdoMergeTypePolicy {\n isEnabled: boolean;\n isBlocking: boolean;\n settings?: {\n useSquashMerge?: boolean;\n allowNoFastForward?: boolean;\n allowRebase?: boolean;\n allowRebaseMerge?: boolean;\n };\n}\n\nexport function evaluateAdoMergePolicy(\n policies: AdoMergeTypePolicy[],\n): PolicyEvaluation {\n const enabled = policies.filter((p) => p.isEnabled);\n if (enabled.length === 0) {\n return {\n passed: false,\n effectiveMergeMethods: null,\n declaredButBlocked: [],\n disallowedButPermitted: [],\n message: \"No enabled \\\"Limit merge types\\\" branch policy found for the target branch.\",\n };\n }\n\n const effective = new Set<MergeMethod>();\n for (const policy of enabled) {\n const s = policy.settings ?? {};\n if (s.allowNoFastForward) effective.add(\"merge\");\n if (s.allowRebase || s.allowRebaseMerge) effective.add(\"rebase\");\n if (s.useSquashMerge) effective.add(\"squash\");\n }\n\n return compareToLadder([...effective], []);\n}\n\nexport async function fetchAdoMergeTypePolicies(\n org: string,\n project: string,\n repoName: string,\n branch: string,\n): Promise<AdoMergeTypePolicy[] | null> {\n try {\n const orgUrl = `https://dev.azure.com/${org}`;\n // az repos policy list needs the repository's GUID, not its name.\n const { stdout: repoOut } = await execFileAsync(\"az\", [\n \"repos\",\n \"show\",\n \"--repository\",\n repoName,\n \"--org\",\n orgUrl,\n \"--project\",\n project,\n \"--query\",\n \"id\",\n \"--output\",\n \"tsv\",\n ]);\n const repositoryId = repoOut.trim();\n if (!repositoryId) return null;\n\n const { stdout } = await execFileAsync(\"az\", [\n \"repos\",\n \"policy\",\n \"list\",\n \"--repository-id\",\n repositoryId,\n \"--branch\",\n branch,\n \"--org\",\n orgUrl,\n \"--project\",\n project,\n \"--output\",\n \"json\",\n ]);\n return JSON.parse(stdout) as AdoMergeTypePolicy[];\n } catch {\n return null;\n }\n}\n\n// ─── Remote URL parsing ───────────────────────────────────────────────────────\n\nexport function parseGitHubRemote(url: string): { owner: string; repo: string } | null {\n const match = /github\\.com[/:]([^/]+)\\/([^/.]+?)(?:\\.git)?\\/?$/.exec(url);\n if (!match) return null;\n const [, owner, repo] = match;\n if (!owner || !repo) return null;\n return { owner, repo };\n}\n\nexport function parseAdoRemote(\n url: string,\n): { org: string; project: string; repo: string } | null {\n // Modern: https://dev.azure.com/{org}/{project}/_git/{repo}\n const modern = /dev\\.azure\\.com\\/([^/]+)\\/([^/]+)\\/_git\\/([^/?]+)/.exec(url);\n if (modern) {\n const [, org, project, repo] = modern;\n if (org && project && repo) return { org, project, repo };\n }\n // Legacy: https://{org}.visualstudio.com/{project}/_git/{repo}\n const legacy = /([^./]+)\\.visualstudio\\.com\\/([^/]+)\\/_git\\/([^/?]+)/.exec(url);\n if (legacy) {\n const [, org, project, repo] = legacy;\n if (org && project && repo) return { org, project, repo };\n }\n return null;\n}\n","/**\n * spell ward (T18/BC-21): local IP/trademark leakage scan.\n *\n * Finds what leaked IN -- third-party identifiers, brand tokens, org names --\n * baked into a repo's content, filenames, or binary assets. `--terms` is a\n * generic denylist: seed it from the operator's OWN identity too, not just\n * the org's -- a username, machine name, or personal handle leaks the same\n * way a private venture name does (I1; the motivating incident was exactly\n * this -- a branch name containing a username, sitting in this repo's own\n * ai-context file, in a public repo). The opposite concern from spell scry\n * (T18), which clears a candidate name before it ships OUT.\n *\n * Deliberately out of scope: secret/credential detection. That is a\n * different scanning concern reserved for BC-10's secret-detection ADR\n * (ARC-037, still Proposed) -- ward never attempts pattern-matching on\n * keys, tokens, or credentials, only on identifiers and trademarks.\n */\n\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\nimport {\n createDenylistRules,\n collectScannableFiles,\n SKIP_DIRECTORIES,\n type DenylistRule,\n type DenylistFinding,\n} from \"./denylist-scan.js\";\n\n/**\n * Ward's own content scan, deliberately NOT reusing denylist-scan.ts's\n * `scanFile` -- that function stops at the first matching rule per line\n * (correct for org-token-lint, which only needs \"does this line have any\n * hit\"), but ward must distinguish a leak from a protected-vendor-identifier\n * hit even when both land on the same line, so it needs every matching rule\n * per line, not just the first.\n */\nasync function scanFileAllRules(\n absolutePath: string,\n displayPath: string,\n rules: DenylistRule[],\n): Promise<DenylistFinding[]> {\n const findings: DenylistFinding[] = [];\n let content: string;\n try {\n content = await readFile(absolutePath, \"utf8\");\n } catch {\n return findings;\n }\n\n const lines = content.split(\"\\n\");\n for (let index = 0; index < lines.length; index++) {\n const searchable = lines[index]!.replace(/\\{[A-Z][A-Z0-9_]*\\}/g, \"\");\n for (const rule of rules) {\n if (rule.pattern.test(searchable)) {\n findings.push({ file: displayPath, line: index + 1, rule: rule.label });\n }\n }\n }\n\n return findings;\n}\n\n// ─── Mandatory vendor-identifier protection list ─────────────────────────────\n\n/**\n * Always active, independent of any user-supplied terms. A reasonable\n * starting set (not exhaustive -- see the PRD's Open Questions), covering\n * widely-referenced third-party AI model and vendor identifiers that an\n * automated rename/refactor pass could plausibly mistake for a project-local\n * token and \"correct\" into something else, corrupting a real API reference.\n * A match here is reported as PROTECTED, never as a plain leak finding --\n * ward's job for these terms is to stop automated correction, not to flag\n * their legitimate presence as a problem.\n */\nexport const VENDOR_IDENTIFIER_PROTECTION_LIST: readonly string[] = [\n \"claude\",\n \"gpt-4\",\n \"gpt-3.5\",\n \"gemini\",\n \"llama\",\n \"mistral\",\n \"copilot\",\n \"anthropic\",\n \"openai\",\n];\n\nexport interface WardExclusion {\n /** The denylist rule label this exclusion applies to. */\n rule: string;\n /** A substring that, if present on the same line as a match, suppresses it. */\n context: string;\n reason: string;\n}\n\nexport interface WardOptions {\n /** User-supplied terms, in addition to the mandatory vendor list. */\n terms?: string[];\n /** Substring-hazard exclusions (the \"author/provision\" class). */\n exclusions?: WardExclusion[];\n /** Extra file extensions to treat as scannable binary-asset carriers. */\n binaryExtensions?: string[];\n}\n\nexport interface WardFinding extends DenylistFinding {\n category: \"leak\" | \"protected-vendor-identifier\";\n}\n\nexport interface WardMediaFlag {\n file: string;\n reason: string;\n}\n\nexport interface WardReport {\n findings: WardFinding[];\n /** Grep-proof media flagged for manual review, never silently cleared. */\n mediaFlags: WardMediaFlag[];\n}\n\n/** Binary media formats where reliable text extraction isn't possible. */\nconst GREP_PROOF_EXTENSIONS = [\".gif\", \".png\", \".jpg\", \".jpeg\", \".mp4\", \".mov\", \".mp3\", \".wav\"];\n\n/** Extensions ward treats as text-scannable content, beyond denylist-scan's default set. */\nconst WARD_TEXT_EXTENSIONS = [\n \".md\", \".ts\", \".tsx\", \".js\", \".jsx\", \".json\", \".yml\", \".yaml\", \".txt\", \".mdx\",\n];\n\nfunction applyExclusions(\n findings: DenylistFinding[],\n fileLines: Map<string, string[]>,\n exclusions: WardExclusion[],\n): DenylistFinding[] {\n if (exclusions.length === 0) return findings;\n return findings.filter((finding) => {\n const applicable = exclusions.filter((e) => e.rule === finding.rule);\n if (applicable.length === 0) return true;\n const lines = fileLines.get(finding.file);\n const lineText = lines?.[finding.line - 1] ?? \"\";\n return !applicable.some((e) => lineText.includes(e.context));\n });\n}\n\n/** Scans filenames themselves (not just content) against the denylist rules. */\nasync function scanFilenames(\n root: string,\n rules: DenylistRule[],\n repoRoot: string = root,\n): Promise<DenylistFinding[]> {\n const findings: DenylistFinding[] = [];\n let entries;\n try {\n entries = await readdir(root, { withFileTypes: true });\n } catch {\n return findings;\n }\n\n for (const entry of entries) {\n const absolutePath = join(root, entry.name);\n if (entry.isDirectory()) {\n if (SKIP_DIRECTORIES.has(entry.name)) continue;\n findings.push(...(await scanFilenames(absolutePath, rules, repoRoot)));\n continue;\n }\n const displayPath = relative(repoRoot, absolutePath).replace(/\\\\/g, \"/\");\n for (const rule of rules) {\n if (rule.pattern.test(entry.name)) {\n findings.push({ file: displayPath, line: 0, rule: rule.label });\n break;\n }\n }\n }\n\n return findings;\n}\n\n/** Flags grep-proof media files for manual review -- never silently cleared. */\nasync function flagGrepProofMedia(root: string, repoRoot: string = root): Promise<WardMediaFlag[]> {\n const files = await collectScannableFiles(root, repoRoot, GREP_PROOF_EXTENSIONS);\n return files.map(([, displayPath]) => ({\n file: displayPath,\n reason: \"binary media format -- text extraction is unreliable; review manually for embedded identifiers\",\n }));\n}\n\n/**\n * Runs the full ward scan: content, filenames, and grep-proof media flags.\n * Report-only -- never mutates anything. Categorizes each finding as a plain\n * leak or a protected-vendor-identifier hit per VENDOR_IDENTIFIER_PROTECTION_LIST.\n */\nexport async function runWard(repoRoot: string, options: WardOptions = {}): Promise<WardReport> {\n const userTerms = options.terms ?? [];\n const exclusions = options.exclusions ?? [];\n const extensions = [...WARD_TEXT_EXTENSIONS, ...(options.binaryExtensions ?? [])];\n\n const userRules = createDenylistRules(userTerms, \"ward-term\");\n const vendorRules = createDenylistRules([...VENDOR_IDENTIFIER_PROTECTION_LIST], \"ward-vendor\");\n const allRules = [...userRules, ...vendorRules];\n\n const contentFiles = await collectScannableFiles(repoRoot, repoRoot, extensions);\n const fileLines = new Map<string, string[]>();\n const contentFindings: DenylistFinding[] = [];\n for (const [absolutePath, displayPath] of contentFiles) {\n const findings = await scanFileAllRules(absolutePath, displayPath, allRules);\n if (findings.length > 0) {\n try {\n fileLines.set(displayPath, (await readFile(absolutePath, \"utf8\")).split(\"\\n\"));\n } catch {\n // Unreadable after the initial scan (rare race) -- leave unmapped; exclusions simply won't match.\n }\n }\n contentFindings.push(...findings);\n }\n\n // Not dedupeFindings: that collapses on file:line alone, which would\n // wrongly merge a leak and a protected-vendor-identifier hit that land on\n // the same line -- exactly the case ward needs to keep distinct. Content\n // (line >= 1) and filename (line 0) findings can never collide on\n // file:line, and scanFileAllRules never double-reports the same rule on\n // the same line, so a plain concatenation is already duplicate-free.\n const filenameFindings = await scanFilenames(repoRoot, allRules);\n const combined = [...contentFindings, ...filenameFindings];\n const excluded = applyExclusions(combined, fileLines, exclusions);\n\n const vendorLabels = new Set(vendorRules.map((r) => r.label));\n const findings: WardFinding[] = excluded.map((f) => ({\n ...f,\n category: vendorLabels.has(f.rule) ? \"protected-vendor-identifier\" : \"leak\",\n }));\n\n const mediaFlags = await flagGrepProofMedia(repoRoot);\n\n return { findings, mediaFlags };\n}\n","import { runWard, type WardExclusion } from \"../modules/ward.js\";\n\nexport interface WardCliOptions {\n terms?: string;\n gate?: boolean;\n}\n\nfunction parseTerms(raw?: string): string[] {\n if (!raw) return [];\n return raw\n .split(\",\")\n .map((t) => t.trim())\n .filter(Boolean);\n}\n\n/**\n * spell ward CLI entry point. Report-only by default (matching\n * spell-check-drift's own convention); --gate exits non-zero on any `leak`\n * finding so it can be wired into CI. A `protected-vendor-identifier`\n * finding is informational -- it exists to make a human look before an\n * automated rename touches a real vendor identifier, not to fail a build by\n * itself.\n */\nexport async function runWardCli(\n targetDir: string,\n options: WardCliOptions = {},\n exclusions: WardExclusion[] = [],\n): Promise<void> {\n const terms = parseTerms(options.terms);\n const report = await runWard(targetDir, { terms, exclusions });\n\n console.log(\"\\nspell ward — scanning for leaked identifiers\\n\");\n\n const leaks = report.findings.filter((f) => f.category === \"leak\");\n const protectedHits = report.findings.filter((f) => f.category === \"protected-vendor-identifier\");\n\n if (leaks.length === 0 && protectedHits.length === 0) {\n console.log(\" ✓ No denylisted terms found.\");\n }\n\n for (const finding of leaks) {\n const where = finding.line === 0 ? `${finding.file} (filename)` : `${finding.file}:${finding.line}`;\n console.log(` ✗ [leak] ${where} — rule: ${finding.rule}`);\n }\n\n for (const finding of protectedHits) {\n const where = finding.line === 0 ? `${finding.file} (filename)` : `${finding.file}:${finding.line}`;\n console.log(\n ` ⚠ [protected-vendor-identifier] ${where} — rule: ${finding.rule} — verify before any automated rename touches this line`,\n );\n }\n\n if (report.mediaFlags.length > 0) {\n console.log(\"\\n Grep-proof media flagged for manual review:\");\n for (const flag of report.mediaFlags) {\n console.log(` ? ${flag.file} — ${flag.reason}`);\n }\n }\n\n console.log();\n\n if (options.gate && leaks.length > 0) {\n console.log(` ${leaks.length} leak(s) found. Failing (--gate mode).\\n`);\n process.exitCode = 1;\n return;\n }\n\n if (leaks.length > 0) {\n console.log(` ${leaks.length} leak(s) found. Run with --gate to fail CI on this.\\n`);\n }\n}\n","import { basename, resolve } from \"node:path\";\nimport { input } from \"@inquirer/prompts\";\nimport { readManifest, writeManifest, ManifestNotFoundError } from \"../modules/manifest.js\";\nimport {\n removePrePushHook,\n restorePushUrls,\n blockedRemotes,\n isHookEnforced,\n} from \"../modules/push-safety.js\";\nimport { printInfo, printSuccess, printWarning } from \"../modules/banner.js\";\nimport type { ArcaneManifest } from \"../types.js\";\n\n/**\n * Runs `spell unblock-push` (EF-09 R5).\n *\n * Deliberately its own command and never a side effect of `init`/`update`:\n * a protection that can be lifted by a routine command is not a protection.\n *\n * Two gates, and the PRD is honest about what each one is worth:\n *\n * - **Interactive TTY only.** This is the real bar against a scripted agent —\n * the threat actor the PRD ranks second, since a push is irreversible. It is\n * not absolute (a pseudo-TTY defeats it), and the PRD says so rather than\n * claiming otherwise.\n * - **Typed repository name.** This guards a human against unblocking the wrong\n * repository. It is explicitly NOT agent-resistance: anything that can read\n * `.arcane.json` can read the name back.\n */\nexport async function runUnblockPush(targetDir: string): Promise<void> {\n let manifest: ArcaneManifest;\n try {\n manifest = await readManifest(targetDir);\n } catch (err) {\n if (err instanceof ManifestNotFoundError) {\n console.error('Not initialized. Run \"spell init\" first.');\n process.exit(1);\n return; // guard: process.exit is mocked in tests\n }\n throw err;\n }\n\n // Gate on the CONTROLS, not the declaration. A partial lift writes\n // push_policy \"open\" while the hook or a sentinel URL is still in force, and\n // keying the early return on the manifest meant that state made this command\n // refuse to run again — the failed attempt closed its own retry path. Making\n // partial lifts visible (0.20.1) is not the same as making them recoverable.\n const policy = manifest.push_policy ?? \"open\";\n const stillInForce =\n (await isHookEnforced(targetDir)) || (await blockedRemotes(targetDir)).length > 0;\n if (policy === \"open\" && !stillInForce) {\n printInfo(\"This repository is not push-blocked — nothing to undo.\");\n return;\n }\n if (policy === \"open\") {\n printWarning(\n \"The manifest says push_policy: open, but this repository still has Arcane's push block \" +\n \"in force — most likely a previous unblock only partly succeeded. Continuing so it can \" +\n \"be finished.\",\n );\n }\n\n if (!process.stdin.isTTY) {\n console.error(\n \"spell unblock-push must be run from an interactive terminal.\\n\" +\n \"Lifting a push block is a deliberate decision, so it cannot be scripted, piped, or run in CI.\",\n );\n process.exit(1);\n return;\n }\n\n const repoName = basename(resolve(targetDir));\n if (repoName === \"\") {\n // A repository at a filesystem root has no basename, which would turn the\n // confirmation into \"press Enter\". A gate that can silently become vacuous\n // must fail closed instead.\n console.error(\n \"Could not determine a repository name to confirm against (is this repository at a filesystem root?). Refusing to unblock.\",\n );\n process.exit(1);\n return;\n }\n\n printWarning(`This repository's push_policy is \"${policy}\".`);\n printInfo(\n \"Unblocking restores the ability to push this repository's full history to its remote. \" +\n \"Deleting a file later does not undo a push: the content stays in history, in any clone \" +\n \"already made, and in the remote's own backups.\",\n );\n console.log();\n\n const typed = await input({\n message: `Type the repository name to confirm (${repoName}):`,\n });\n\n if (typed.trim() !== repoName) {\n console.error(`\\nName did not match (\"${typed.trim()}\" ≠ \"${repoName}\"). Nothing changed.`);\n process.exit(1);\n return;\n }\n\n await removePrePushHook(targetDir);\n const results = await restorePushUrls(targetDir);\n const restored = results.filter((r) => r.status === \"restored\").map((r) => r.remote);\n const failed = results.filter((r) => r.status === \"failed\");\n // A remote still carrying the sentinel after we claimed to have unblocked it\n // is the manifest-lies-about-posture failure in the opposite direction, so it\n // is checked directly rather than inferred from what we think we did.\n const stillBlocked = await blockedRemotes(targetDir);\n\n // No \"just this once\" mode: the manifest must never claim a protection the\n // repository no longer has.\n const updated: ArcaneManifest = {\n ...manifest,\n push_policy: \"open\",\n push_policy_unblocked_at: new Date().toISOString(),\n };\n await writeManifest(targetDir, updated);\n\n // Check the hook too, not just the URLs: `removePrePushHook` declines to touch\n // a foreign or unreadable core.hooksPath, so it can legitimately do nothing.\n const hookStillOn = await isHookEnforced(targetDir);\n const fullyLifted = failed.length === 0 && stillBlocked.length === 0 && !hookStillOn;\n\n // Never let a partial result read as a clean one. Reporting success first and\n // appending warnings underneath is exactly the shape this feature refuses to\n // accept elsewhere.\n if (fullyLifted) {\n printSuccess(`Push unblocked for \"${repoName}\".`);\n } else {\n printWarning(\n `Push only PARTIALLY unblocked for \"${repoName}\". The manifest now says open; the ` +\n \"repository is not fully open yet. Details below.\",\n );\n }\n if (restored.length > 0) {\n printInfo(`Restored push URL for: ${restored.join(\", \")}.`);\n }\n if (hookStillOn) {\n printWarning(\n \"The pre-push hook is still in force. Arcane did not remove it because `core.hooksPath` is \" +\n \"not one it owns, or could not be read. Check `git config --show-scope --get core.hooksPath`.\",\n );\n }\n if (failed.length > 0) {\n printWarning(\n `Could not restore the push URL for: ${failed\n .map((r) => `${r.remote} (${r.reason ?? \"unknown error\"})`)\n .join(\"; \")}.`,\n );\n }\n if (stillBlocked.length > 0) {\n // Most likely cause: the remote was renamed while blocked, so the recorded\n // original moved with it but a *different* remote now carries the sentinel.\n printWarning(\n `These remotes still have a blocked push URL and no recorded original: ${stillBlocked.join(\", \")}. ` +\n \"Set them yourself with `git remote set-url --push <name> <url>` — until then, pushing to \" +\n \"them will fail even though the manifest now says open.\",\n );\n }\n printInfo(\n \"Recorded in .arcane.json as push_policy: open, with the time it was lifted. \" +\n \"Commit that change so the repository's actual posture stays visible to everyone.\",\n );\n}\n"],"mappings":"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","names":["createRequire","dirname","join","select","input","join","chalk","readFile","writeFile","path","manifestPath","resolve","mkdir","writeFile","copyFile","join","readFile","readdir","access","isRecord","path","readFile","readFile","access","writeFile","mkdir","join","readFile","writeFile","path","path","readFile","writeFile","join","mkdir","writeFile","r","join","mkdir","writeFile","copyFile","mkdir","readFile","writeFile","access","rm","readdir","join","resolve","stdout","join","mkdir","writeFile","join","readdir","readFile","access","rm","chalk","select","join","input","join","join","join","readFile","writeFile","rm","confirm","select","input","readdir","writeFile","join","confirm","select","input","join","readdir","writeFile","i","j","join","rm","readFile","writeFile","readFile","writeFile","mkdir","dirname","join","homedir","require","pkg","rm","join","confirm","confirm","join","rm","access","readFile","mkdir","join","dirname","execFile","promisify","readFile","readdir","join","execFile","execFileAsync","promisify","execFile","isRecord","join","readdir","manifestPath","access","readFile","mkdir","dirname","readdir","readFile","join","relative","readFile","readdir","join","relative","findings","basename","resolve","input","basename","resolve","input","require","createRequire","join","dirname"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/modules/copier.ts","../src/modules/manifest.ts","../src/config/profiles.ts","../src/modules/registry.ts","../src/modules/banner.ts","../src/modules/agents.ts","../src/config/agent-roles.ts","../src/config/agent-profiles.ts","../src/modules/naming.ts","../src/modules/agent-loader.ts","../src/modules/agent-schema.ts","../src/modules/agent-generator.ts","../src/modules/merger.ts","../src/modules/push-safety.ts","../src/modules/git.ts","../src/modules/secrets-scan.ts","../src/commands/add.ts","../src/commands/update.ts","../src/modules/hub.ts","../src/modules/merge3.ts","../src/modules/npm-registry.ts","../src/modules/version-check.ts","../src/modules/diagram-generator.ts","../src/commands/status.ts","../src/commands/uninstall.ts","../src/commands/doctor.ts","../src/config/incidents.ts","../src/modules/incident-gate.ts","../src/modules/denylist-scan.ts","../src/modules/platform-policy.ts","../src/modules/ward.ts","../src/commands/ward.ts","../src/commands/unblock-push.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { createRequire } from \"node:module\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport { runInit } from \"./commands/init.js\";\nimport { runAdd } from \"./commands/add.js\";\nimport { runUpdate } from \"./commands/update.js\";\nimport { runStatus } from \"./commands/status.js\";\nimport { runUninstall } from \"./commands/uninstall.js\";\nimport { runDoctor } from \"./commands/doctor.js\";\nimport { runWardCli } from \"./commands/ward.js\";\nimport { runUnblockPush } from \"./commands/unblock-push.js\";\nimport { runAgentsInit, runAgentsList, runAgentsSync } from \"./modules/agents.js\";\nimport { printWelcome } from \"./modules/banner.js\";\nimport type { Profile, AgentInitOptions, AgentProfileId, NamingStrategy, AgentSyncOptions } from \"./types.js\";\n\nconst require = createRequire(import.meta.url);\nconst pkg = require(\"../package.json\") as { version: string };\n\n/**\n * Resolved path to the bundled assets directory.\n * Points to src/assets/ during tests (vitest runs source directly) and\n * dist/assets/ in the published package (tsup bundles to dist/index.js).\n * Can be overridden via ARCANE_ASSETS_DIR env var for testing the built binary.\n */\nexport const ASSETS_DIR =\n process.env[\"ARCANE_ASSETS_DIR\"] ??\n join(dirname(fileURLToPath(import.meta.url)), \"assets\");\n\nconst program = new Command();\n\nprogram\n .name(\"spell\")\n .description(\"Arcane framework CLI — scaffold and manage governance files\")\n .version(pkg.version)\n .action(async () => {\n // Commander routes an unrecognized subcommand here too (no root\n // `.arguments()` is declared, so it doesn't emit `command:*`) — the only\n // way to tell \"no subcommand\" from \"an unrecognized one\" is the leftover\n // positional args.\n if (program.args.length > 0) {\n const [attempted] = program.args;\n console.error(`spell: unrecognized command '${attempted}'`);\n console.error();\n console.error(\n `Spells are prompts, not CLI commands — run /spell-${attempted} in your agent client.`,\n );\n console.error();\n console.error(\"Real CLI commands:\");\n for (const cmd of program.commands) {\n console.error(` ${cmd.name().padEnd(14)} ${cmd.description()}`);\n }\n process.exitCode = 1;\n return;\n }\n // Bare `spell` with no subcommand — show the welcome (banner + real repo\n // state + Spell Loop), then the command reference.\n await printWelcome(pkg.version, process.cwd());\n program.outputHelp();\n });\n\nprogram\n .command(\"init\")\n .description(\"Scaffold Arcane framework files into the current repository\")\n .option(\"--profile <profile>\", \"Profile: full | lite | methodology | docs | governance-only\")\n .option(\"--force\", \"Overwrite existing files without error\")\n .option(\"--dry-run\", \"Preview what would be installed without making changes\")\n .action(\n async (opts: { profile?: string; force?: boolean; dryRun?: boolean }) => {\n await runInit(\n {\n profile: opts.profile as Profile | undefined,\n force: opts.force,\n dryRun: opts.dryRun,\n },\n process.cwd(),\n ASSETS_DIR,\n pkg.version,\n );\n },\n );\n\nprogram\n .command(\"add <component>\")\n .description(\"Add a component to an existing Arcane installation\")\n .option(\"--force\", \"Overwrite existing files without error\")\n .option(\"--dry-run\", \"Preview what would be added without making changes\")\n .action(\n async (\n component: string,\n opts: { force?: boolean; dryRun?: boolean },\n ) => {\n await runAdd(\n component,\n { force: opts.force, dryRun: opts.dryRun },\n process.cwd(),\n ASSETS_DIR,\n pkg.version,\n );\n },\n );\n\nprogram\n .command(\"update\")\n .description(\"Update installed components to the current package version\")\n .option(\"--dry-run\", \"Preview what would be updated without making changes\")\n .option(\n \"--prune\",\n \"Also delete orphaned managed files (tracked before this update, no longer part of any current component). Hash-checked: an edited file is reported, never silently deleted\",\n )\n .action(async (opts: { dryRun?: boolean; prune?: boolean }) => {\n await runUpdate(\n { dryRun: opts.dryRun, prune: opts.prune },\n process.cwd(),\n ASSETS_DIR,\n pkg.version,\n );\n });\n\nprogram\n .command(\"status\")\n .description(\"Show installed components and check for updates\")\n .action(async () => {\n await runStatus(process.cwd(), pkg.version);\n });\n\nprogram\n .command(\"uninstall\")\n .description(\"Remove all installed Arcane framework files\")\n .option(\"--yes\", \"Skip confirmation prompt\")\n .option(\"--dry-run\", \"Preview what would be removed without deleting files\")\n .action(async (opts: { yes?: boolean; dryRun?: boolean }) => {\n await runUninstall({ yes: opts.yes, dryRun: opts.dryRun }, process.cwd());\n });\n\nprogram\n .command(\"unblock-push\")\n .description(\"Lift this repository's push block (interactive terminal only)\")\n .action(async () => {\n await runUnblockPush(process.cwd());\n });\n\nprogram\n .command(\"doctor\")\n .description(\"Check your environment for Arcane prerequisites\")\n .option(\"--fix\", \"Automatically create missing session continuity files\")\n .option(\"--leaks\", \"Run only the on-demand secrets/credential scan (ARC-037), skipping the default checks\")\n .action(async (opts: { fix?: boolean; leaks?: boolean }) => {\n await runDoctor(process.cwd(), { fix: opts.fix, leaks: opts.leaks }, ASSETS_DIR);\n });\n\n// ─── spell ward ───────────────────────────────────────────────────────────────\n\nprogram\n .command(\"ward\")\n .description(\"Scan the repo for leaked identifiers -- third-party trademarks and the operator's own personal identifiers alike (T18)\")\n .option(\n \"--terms <terms>\",\n \"Comma-separated denylist terms, in addition to the built-in vendor-identifier list. Seed this from your OWN identity too, not just org/venture names -- usernames, machine names, and personal handles leak the same way a private venture name does (I1)\",\n )\n .option(\"--gate\", \"Exit non-zero if any leak is found (for CI)\")\n .action(async (opts: { terms?: string; gate?: boolean }) => {\n await runWardCli(process.cwd(), opts);\n });\n\n// ─── spell agents ─────────────────────────────────────────────────────────────\n\nconst agentsCommand = program\n .command(\"agents\")\n .description(\"Manage the portable agent system (init, sync, list)\");\n\nagentsCommand\n .command(\"init\")\n .description(\n \"Interactive agent roster setup — choose profile, naming strategy, and install definitions\",\n )\n .option(\n \"--profile <profile>\",\n \"Agent profile: base | full | custom\",\n )\n .option(\n \"--naming <strategy>\",\n \"Naming strategy: arcanos | generic | random | custom\",\n )\n .option(\"--force\", \"Reinitialize even if roster already exists\")\n .option(\"--dry-run\", \"Preview what would be created without writing files\")\n .action(\n async (opts: {\n profile?: string;\n naming?: string;\n force?: boolean;\n dryRun?: boolean;\n }) => {\n await runAgentsInit(\n {\n profile: opts.profile as AgentProfileId | undefined,\n naming: opts.naming as NamingStrategy | undefined,\n force: opts.force,\n dryRun: opts.dryRun,\n } satisfies AgentInitOptions,\n process.cwd(),\n ASSETS_DIR,\n );\n },\n );\n\nagentsCommand\n .command(\"sync\")\n .description(\n \"Regenerate all client instruction files from canonical agent definitions\",\n )\n .option(\"--dry-run\", \"Preview what would be generated without writing files\")\n .option(\"--no-openclaw\", \"Skip OpenClaw workspace output\")\n .option(\"--no-copilot\", \"Skip Copilot output\")\n .option(\"--no-claude\", \"Skip Claude output\")\n .option(\"--no-codex\", \"Skip Codex output\")\n .action(\n async (opts: {\n dryRun?: boolean;\n openclaw?: boolean;\n copilot?: boolean;\n claude?: boolean;\n codex?: boolean;\n }) => {\n await runAgentsSync(\n {\n dryRun: opts.dryRun,\n openclaw: opts.openclaw,\n copilot: opts.copilot,\n claude: opts.claude,\n codex: opts.codex,\n } satisfies AgentSyncOptions,\n process.cwd(),\n ASSETS_DIR,\n );\n },\n );\n\nagentsCommand\n .command(\"list\")\n .description(\"Show the current agent roster with assigned names and roles\")\n .action(async () => {\n await runAgentsList(process.cwd());\n });\n\n// Only parse argv when executed directly — not when imported in tests.\n// Use realpathSync to resolve symlinks (e.g. npm global bin → dist/index.js).\nimport { realpathSync } from \"node:fs\";\nif (realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) {\n await program.parseAsync(process.argv);\n}\n\nexport { program };\n","import { select, confirm, input } from \"@inquirer/prompts\";\nimport { join } from \"node:path\";\nimport chalk from \"chalk\";\nimport { copyFile, copyDirectory } from \"../modules/copier.js\";\nimport {\n readManifest,\n writeManifest,\n isValidSubjectRoot,\n ManifestNotFoundError,\n} from \"../modules/manifest.js\";\nimport { getProfile, listProfiles } from \"../modules/registry.js\";\nimport {\n printDryRun,\n printStep,\n printSuccess,\n printSection,\n printInfo,\n printNextStep,\n printWarning,\n} from \"../modules/banner.js\";\nimport { runAgentsInit } from \"../modules/agents.js\";\nimport {\n installPrePushHook,\n installClosedPrWarningHook,\n disablePushUrls,\n describeConfigScope,\n ARCANE_HOOKS_DIR,\n} from \"../modules/push-safety.js\";\nimport { installSecretsPrecommitHook } from \"../modules/secrets-scan.js\";\nimport {\n correctUnbornMasterDefault,\n ensureLocalPullRebase,\n inspectGitRepository,\n} from \"../modules/git.js\";\nimport type {\n ArcaneManifest,\n ContentSensitivity,\n ExternalProvider,\n HubRole,\n InstalledComponent,\n Profile,\n RegistryComponent,\n PushPolicy,\n SpellInitOptions,\n TrackingMode,\n} from \"../types.js\";\n\nconst VALID_PROFILES: Profile[] = [\"full\", \"lite\", \"governance-only\", \"methodology\", \"docs\"];\n\n/** Menu glyph per profile. Falls back to 📋 for any profile not listed. */\nconst PROFILE_ICONS: Partial<Record<Profile, string>> = {\n full: \"🧙\",\n lite: \"⚡\",\n docs: \"📖\",\n};\n\n/** True for the capability-scoped spell components (see registry.ts). */\nfunction isSpellComponent(name: string): boolean {\n return name.startsWith(\"spells-\");\n}\n\n// ─── Category labels for preview ─────────────────────────────────────────────\n\ninterface ComponentGroup {\n icon: string;\n label: string;\n count: number;\n}\n\nfunction categorizeComponents(components: RegistryComponent[]): ComponentGroup[] {\n const groups: ComponentGroup[] = [];\n\n // Spells now arrive as several capability components rather than one\n // monolith, and each carries both client formats of the same spell, so\n // count by file destination rather than by component.\n const spellFiles = components.filter((c) => isSpellComponent(c.name)).flatMap((c) => c.files);\n\n const promptCount = spellFiles.filter((f) => f.startsWith(\".github/prompts/\")).length;\n if (promptCount > 0) {\n groups.push({ icon: \"✨\", label: \"Copilot Spells\", count: promptCount });\n }\n\n const claudeCount = spellFiles.filter((f) => f.startsWith(\".claude/commands/\")).length;\n if (claudeCount > 0) {\n groups.push({ icon: \"⚡\", label: \"Claude Spells\", count: claudeCount });\n }\n\n const governance = components.filter(\n (c) =>\n !isSpellComponent(c.name) &&\n c.name !== \"venture-template\" &&\n c.name !== \"agent-definitions\" &&\n c.files.some((f) => f.startsWith(\".arcane/governance/\")),\n );\n if (governance.length > 0) {\n groups.push({\n icon: \"📋\",\n label: \"Governance Docs\",\n count: governance.reduce((n, c) => n + c.files.length, 0),\n });\n }\n\n const agentDef = components.find((c) => c.name === \"agent-definitions\");\n if (agentDef) {\n groups.push({\n icon: \"🛡️\",\n label: \"Agent Policies\",\n count: agentDef.files.length,\n });\n }\n\n const templates = components.find((c) => c.name === \"venture-template\");\n if (templates) {\n groups.push({\n icon: \"📄\",\n label: \"Templates\",\n count: templates.files.length,\n });\n }\n\n return groups;\n}\n\n/**\n * Builds a hover description string for the profile selection menu.\n * Shows the category breakdown so users know what they're getting.\n */\nfunction buildProfileDescription(components: RegistryComponent[], profile: Profile): string {\n const groups = categorizeComponents(components);\n const parts = groups.map((g) => `${g.icon} ${g.count} ${g.label}`);\n if (profile === \"full\" || profile === \"lite\") {\n // Insert agent roles before governance docs (spells + agents first, then the rest)\n const govIndex = groups.findIndex((g) => g.label === \"Governance Docs\");\n parts.splice(govIndex >= 0 ? govIndex : parts.length, 0, \"🤖 12 Agent Roles\");\n }\n return \"\\n\" + parts.join(\"\\n\");\n}\n\n// ─── Main ─────────────────────────────────────────────────────────────────────\n\n/**\n * Runs the `spell init` command.\n *\n * @param options CLI flags (profile, force, dryRun)\n * @param targetDir Directory to initialize (defaults to cwd in CLI)\n * @param assetsDir Path to the bundled assets root (dist/assets/ in prod, src/assets/ in tests)\n * @param packageVersion Current package version string (passed from CLI entry to avoid require path issues)\n */\nexport async function runInit(\n options: SpellInitOptions,\n targetDir: string,\n assetsDir: string,\n packageVersion: string,\n): Promise<void> {\n // Validate profile option if provided\n if (options.profile && !VALID_PROFILES.includes(options.profile)) {\n throw new Error(\n `Invalid profile \"${options.profile}\". Valid options: ${VALID_PROFILES.join(\", \")}`,\n );\n }\n\n // Check if already initialized\n try {\n await readManifest(targetDir);\n console.log(chalk.hex(\"#a855f7\")(`\\n ✦ Arcane v${packageVersion}\\n`));\n console.log('Already initialized. Run \"spell update\" to update existing files.');\n return;\n } catch (err) {\n if (!(err instanceof ManifestNotFoundError)) throw err;\n // ManifestNotFoundError = not initialized — proceed\n }\n\n console.log(chalk.hex(\"#a855f7\")(`\\n ✦ Arcane v${packageVersion}\\n`));\n\n // ── Git-state checks (EF-05, EF-32) ─────────────────────────────────────\n // Never runs `git init` or creates a commit -- see\n // features/init-git-state-contract/PRD.md's \"Design decision\" section for\n // why that's declined rather than deferred. Only acts where it's provably\n // safe (an unborn repo has no commits to conflict with) or where the\n // operator already explicitly confirmed continuing (uncommitted changes).\n let repoNotFound = false;\n if (!options.dryRun) {\n const gitState = await inspectGitRepository(targetDir);\n\n if (gitState.status === \"not-repository\") {\n repoNotFound = true;\n } else {\n if (gitState.status === \"no-commits\") {\n const correction = await correctUnbornMasterDefault(targetDir);\n if (correction.corrected) {\n printInfo(\n `Repointed the unborn branch from \"${correction.from}\" to \"${correction.to}\" (avoids the Git for Windows default-branch trap).`,\n );\n } else if (correction.blockedReason === \"target-unreadable\") {\n printWarning(\n 'This repo\\'s \"main\" branch ref exists but could not be read (broken ref). Left the current branch alone — ' +\n \"repointing onto an unreadable ref risks attaching your staged work to history Arcane cannot see. \" +\n \"Check `git for-each-ref refs/heads/main` before committing.\",\n );\n }\n }\n\n if (gitState.status === \"ready\" && gitState.uncommittedChanges > 0) {\n printWarning(\n `This repo has ${gitState.uncommittedChanges} uncommitted change${gitState.uncommittedChanges === 1 ? \"\" : \"s\"}.`,\n );\n printInfo(\"Running spell init will add new files to your working tree.\");\n console.log();\n const continueAnyway = await confirm({\n message: \"Continue anyway?\",\n default: true,\n });\n if (!continueAnyway) {\n console.log(\"\\nCancelled. Commit or stash your changes first.\");\n return;\n }\n console.log();\n }\n\n const rebaseResult = await ensureLocalPullRebase(targetDir);\n if (rebaseResult.action === \"explicit-false-preserved\") {\n printWarning(\n \"This repo's pull.rebase is explicitly set to false, but Arcane's governance mandates rebase-and-fast-forward (see .arcane/governance/git-conventions.md). Left as-is since you set it explicitly.\",\n );\n }\n }\n }\n\n // ── Step 1: Resolve profile (prompt if not provided) ───────────────────\n let profile: Profile = options.profile as Profile;\n if (!profile) {\n const profiles = listProfiles();\n profile = (await select({\n message: \"Select an installation profile:\\n\",\n choices: profiles.map((p) => {\n const profileComponents = getProfile(p.id);\n return {\n value: p.id,\n name: `${PROFILE_ICONS[p.id] ?? \"📋\"} ${p.displayName} — ${p.description}`,\n description: buildProfileDescription(profileComponents, p.id),\n };\n }),\n })) as Profile;\n }\n\n // ── Step 2: Resolve components ─────────────────────────────────────────\n const components = getProfile(profile);\n\n // ── Step 3: Preview what will be installed ─────────────────────────────\n const groups = categorizeComponents(components);\n\n console.log();\n printSection(`📦 Profile: ${profile}`);\n console.log();\n\n // Show agent setup as upcoming interactive step\n const hasAgents = profile === \"full\" || profile === \"lite\";\n\n // Build summary parts (same style as hover description)\n const previewParts = groups.map((g) => `${g.icon} ${g.count} ${g.label}`);\n if (hasAgents) {\n // Insert agent roles before governance docs\n const govIndex = groups.findIndex((g) => g.label === \"Governance Docs\");\n previewParts.splice(govIndex >= 0 ? govIndex : previewParts.length, 0, \"🤖 12 Agent Roles\");\n }\n console.log(` ${previewParts.join(\" · \")}`);\n\n console.log();\n\n // ── Step 4: Confirm (skip in non-interactive mode) ─────────────────────\n if (!options.dryRun && !options.profile) {\n const proceed = await confirm({\n message: \"Proceed with installation?\",\n default: true,\n });\n if (!proceed) {\n console.log(\"\\nCancelled.\");\n return;\n }\n }\n\n // ── Step 5: Copy files ─────────────────────────────────────────────────\n const installedComponents: InstalledComponent[] = [];\n let fileCount = 0;\n\n for (const component of components) {\n const installedFiles: string[] = [];\n const fileHashes: Record<string, string> = {};\n\n for (const file of component.files) {\n const srcPath = join(assetsDir, component.sourceOverrides?.[file] ?? file);\n if (options.dryRun) {\n printDryRun(`Would copy: ${file}`);\n } else {\n try {\n fileHashes[file] = await copyFile(srcPath, targetDir, file, { force: options.force });\n } catch (err) {\n // skipExisting components silently skip files that already exist\n if (component.skipExisting && err instanceof Error && err.message.includes(\"already exists\")) {\n continue;\n }\n throw err;\n }\n }\n installedFiles.push(file);\n fileCount++;\n }\n\n for (const dir of component.directories ?? []) {\n const srcDirPath = join(assetsDir, dir);\n if (options.dryRun) {\n printDryRun(`Would copy directory: ${dir}/`);\n } else {\n const copied = await copyDirectory(srcDirPath, targetDir, dir, { force: options.force });\n for (const { path: copiedPath, hash } of copied) {\n installedFiles.push(copiedPath);\n fileHashes[copiedPath] = hash;\n }\n fileCount += copied.length;\n }\n }\n\n if (!options.dryRun) {\n installedComponents.push({\n name: component.name,\n files: installedFiles,\n installedVersion: packageVersion,\n fileHashes,\n });\n }\n }\n\n // Show compact category summary (not 60 individual file paths)\n if (!options.dryRun) {\n for (const group of groups) {\n printStep(`${group.icon} ${group.count} ${group.label}`);\n }\n }\n\n if (options.dryRun) {\n // Show what agent setup would install\n if (hasAgents) {\n const agentFiles = await import(\"node:fs\").then((fsModule) =>\n fsModule.promises.readdir(join(assetsDir, \"agents\")),\n );\n const yamlFiles = agentFiles.filter((f) => f.endsWith(\".yaml\")).sort();\n printDryRun(\"Would run agent setup (interactive):\");\n printDryRun(\"Would write: .arcane/agents.yaml\");\n for (const f of yamlFiles) {\n printDryRun(`Would copy: .arcane/agents/${f}`);\n }\n }\n printDryRun(`Would initialize with profile \"${profile}\" — ${fileCount} files`);\n return;\n }\n\n // ── Step 5a: Hub question ───────────────────────────────────────────────\n // Explicit opt-in only -- never inferred from repo content (a `ventures/`\n // directory can legitimately exist in a consumer repo too, e.g. one this\n // very init run just created via a governance-only profile). Written\n // explicitly either way so a future `spell update` retrofit wizard can\n // tell \"asked and declined\" apart from \"predates this feature\".\n let role: HubRole | undefined;\n if (!options.profile) {\n console.log();\n const isHub = await confirm({\n message: \"Will this repo manage other ventures as a hub? (idea books, spell-manifest promotion, venture registry)\",\n default: false,\n });\n role = isHub ? \"hub\" : \"consumer\";\n }\n\n // ── Step 5b: Tracking-mode question (EF-14) ─────────────────────────────\n // governance-only/methodology profiles have no code-tracking surface --\n // default without asking, even under --profile (deterministic, no prompt\n // to skip). full/lite ask once, interactively only, mirroring the hub\n // question's own gating exactly -- a scripted full/lite install leaves\n // this unset, resolved later by spell update's retrofit wizard.\n let tracking_mode: TrackingMode | undefined;\n let external_provider: ExternalProvider | null | undefined;\n if (profile === \"governance-only\" || profile === \"methodology\" || profile === \"docs\") {\n tracking_mode = \"internal\";\n external_provider = null;\n } else if (!options.profile) {\n console.log();\n tracking_mode = (await select({\n message: \"How will work be tracked in this repo?\",\n choices: [\n { value: \"internal\", name: \"Track work in this repo (TODO.md / PRDs)\" },\n { value: \"external\", name: \"Track work in an external tracker (Azure DevOps / GitHub / Jira / other)\" },\n ],\n })) as TrackingMode;\n if (tracking_mode === \"external\") {\n external_provider = (await select({\n message: \"Which external tracker?\",\n choices: [\n { value: \"ado\", name: \"Azure DevOps\" },\n { value: \"github\", name: \"GitHub Issues\" },\n { value: \"jira\", name: \"Jira\" },\n { value: \"other\", name: \"Other\" },\n ],\n })) as ExternalProvider;\n } else {\n external_provider = null;\n }\n }\n\n // ── Step 5c: Subject shape (EF-07) ──────────────────────────────────────\n // Asked for the docs profile only. Other profiles describe code or a\n // venture portfolio, where \"what is this repo about\" is already answered by\n // business_root or by the code itself; a docs/records repo is the case where\n // the repository IS one subject and nothing currently expresses that.\n // Interactive only, like every other manifest question.\n let subject_root: string | null | undefined;\n if (profile === \"docs\" && !options.profile) {\n console.log();\n const shape = await select({\n message: \"What does this repository hold?\",\n choices: [\n {\n value: \"root\",\n name: \"One subject, at the repository root (documents sit alongside Arcane's files)\",\n },\n { value: \"subdir\", name: \"One subject, in its own directory\" },\n { value: \"portfolio\", name: \"Several subjects or ventures (decide per-document later)\" },\n ],\n });\n if (shape === \"root\") {\n // \".\" is deliberate, not a placeholder: it lets an existing archive come\n // under governance without being restructured first (EF-07 / MH-02).\n subject_root = \".\";\n } else if (shape === \"subdir\") {\n const answer = await input({\n message: \"Directory holding the subject's documents:\",\n default: \"docs\",\n validate: (v) =>\n isValidSubjectRoot(v.trim() || \"docs\") ||\n \"Must be a relative path inside the repository (no leading /, drive letter, or ..).\",\n });\n subject_root = answer.trim() || \"docs\";\n }\n else if (shape === \"portfolio\") {\n // Explicit null, not unset: records that the question was asked and\n // answered, so spell update's retrofit doesn't put it again every run.\n subject_root = null;\n }\n }\n\n // ── Step 5d: Content sensitivity (EF-12) ────────────────────────────────\n // Asked on every interactive install, not just docs: a code repo can hold\n // sensitive records too. Declared once for the whole repository -- per-file\n // detection is unreliable for general documents, which is why the docs-mode\n // PRD rejects scanning as a primary mechanism.\n let content_sensitivity: ContentSensitivity | undefined;\n if (!options.profile) {\n console.log();\n content_sensitivity = (await select({\n message: \"How should agents treat this repository's contents?\",\n choices: [\n { value: \"standard\", name: \"Standard — agents may quote contents in journals and decisions\" },\n {\n value: \"sensitive\",\n name: \"Sensitive — agents reference documents by path, never transcribe them\",\n },\n ],\n default: \"standard\",\n })) as ContentSensitivity;\n }\n\n // ── Step 5e: Push policy (EF-09) ────────────────────────────────────────\n // Default \"open\" — strictly additive, so every existing repository and every\n // scripted install behaves exactly as before. Asked interactively only.\n let push_policy: PushPolicy | undefined;\n if (!options.profile) {\n console.log();\n push_policy = (await select({\n message: \"Should this repository be allowed to push to a remote?\",\n choices: [\n { value: \"open\", name: \"Yes — normal repository\" },\n { value: \"guarded\", name: \"Sensitive, but keep push working — remind me instead\" },\n {\n value: \"blocked\",\n name: \"No — block pushes (a pre-push hook plus a disabled push URL)\",\n },\n ],\n default: \"open\",\n })) as PushPolicy;\n }\n\n // ── Step 6: Write manifest ─────────────────────────────────────────────\n const manifest: ArcaneManifest = {\n version: packageVersion,\n profile,\n installedAt: new Date().toISOString(),\n components: installedComponents,\n ...(role ? { role } : {}),\n ...(tracking_mode ? { tracking_mode, external_provider } : {}),\n ...(subject_root !== undefined ? { subject_root } : {}),\n ...(content_sensitivity ? { content_sensitivity } : {}),\n ...(push_policy ? { push_policy } : {}),\n };\n await writeManifest(targetDir, manifest);\n\n printSuccess(`Initialized with profile \"${profile}\" — ${fileCount} files installed`);\n\n // ── Push-safety controls (EF-09 R2/R3/R4/R7) ────────────────────────────\n // Wrapped: a failure here must not surface as a raw stack trace after\n // \"Initialized successfully\", leaving a manifest that says \"blocked\" while\n // the operator believes they are protected.\n if (push_policy === \"blocked\" || push_policy === \"guarded\") {\n try {\n if (push_policy === \"blocked\") {\n const hook = await installPrePushHook(targetDir);\n if (hook.status === \"refused-unreadable-config\") {\n // Fail closed: we could not determine whether another hook manager\n // owns core.hooksPath, and installing on a guess could disable it.\n printWarning(\n \"Did not install the pre-push hook: git could not report the current core.hooksPath \" +\n \"(unreadable config, or a git too old for `--show-scope`). Installing without knowing \" +\n \"whether another hook manager owns that setting could silently disable it. Fix the \" +\n \"config and run `spell doctor`.\",\n );\n } else if (hook.status === \"refused-default-hooks\") {\n // Same harm as a foreign core.hooksPath, reached by the route the R7\n // guard wasn't watching: this repository's hooks live in git's\n // default directory and have no config key to collide with, so\n // taking the slot would switch every one of them off silently.\n printWarning(\n `Did not install the pre-push hook: this repository has hooks in git's default ` +\n `directory (${hook.hooks.join(\", \")}). Setting core.hooksPath would silently stop ` +\n `them running. Move them under \\`${ARCANE_HOOKS_DIR}\\` yourself and re-run, or add ` +\n \"the push guard to your existing pre-push hook.\",\n );\n } else if (hook.status === \"refused-foreign-hooks-path\") {\n // R7: core.hooksPath is one exclusive slot, at local OR global\n // scope, so pointing it at Arcane would silently disable whatever\n // hook manager already owns it.\n printWarning(\n `Did not install the pre-push hook: core.hooksPath is already \"${hook.existing}\" ` +\n `(${describeConfigScope(hook.scope)}), so another hook manager owns it. Overwriting ` +\n \"would silently disable those hooks. Chain an Arcane pre-push guard into that \" +\n \"directory yourself, or unset core.hooksPath first.\",\n );\n } else {\n printInfo(\"Installed a pre-push hook that blocks pushes from this repository.\");\n }\n\n const urls = await disablePushUrls(targetDir);\n const unprotected = urls.filter((u) => u.status === \"failed\");\n if (unprotected.length > 0) {\n // Never let a partial application read as a full one.\n printWarning(\n `Could not disable the push URL for: ${unprotected\n .map((u) => `${u.remote} (${u.reason ?? \"unknown error\"})`)\n .join(\"; \")}. Those remotes are still pushable with \\`--no-verify\\`. ` +\n \"Run `spell doctor` — it lists exactly which remotes are still live.\",\n );\n }\n if (urls.length === 0) {\n // Be precise: nothing is protecting a remote added later, because\n // this only disables remotes that exist right now. Claiming\n // otherwise would be exactly the false confidence ARC-034 warns of.\n printWarning(\n \"No remote is configured, so only the pre-push hook is active. A remote added later \" +\n \"will NOT have its push URL disabled automatically, and a `--no-verify` push to it \" +\n \"would succeed. Run `spell doctor` after adding one — it reports this gap.\",\n );\n } else {\n const covered = urls.filter((u) => u.status !== \"failed\").map((u) => u.remote);\n if (covered.length > 0) {\n printInfo(`Disabled the push URL for: ${covered.join(\", \")} (fetch still works).`);\n }\n }\n printInfo(\"Run `spell unblock-push` from a terminal to undo this.\");\n } else {\n printInfo(\n \"Marked as push-guarded. No technical control was installed — check the remote is the \" +\n \"one you intend before pushing. `spell doctor` will keep reminding you.\",\n );\n }\n } catch (err) {\n printWarning(\n `Could not fully apply push-safety controls: ${err instanceof Error ? err.message : String(err)}. ` +\n `The manifest records push_policy: \"${push_policy}\", but this repository may not actually be ` +\n \"protected. Run `spell doctor` to see exactly what is and isn't in place.\",\n );\n }\n }\n\n // ── Closed-PR push warning (ARC-035 decision 4) ─────────────────────────\n // Every tier except \"blocked\" gets this: a \"blocked\" repo already refuses\n // every push outright and has no use for a warning about which PR it\n // would have gone to (installing here would also silently downgrade that\n // stronger control, since both share the \"pre-push\" hook slot). Wrapped\n // the same way as the blocks above -- a failure here must not surface as\n // a raw stack trace after \"Initialized successfully\".\n if (push_policy !== \"blocked\") {\n try {\n const hook = await installClosedPrWarningHook(targetDir);\n if (hook.status === \"installed\") {\n printInfo(\"Installed a pre-push hook that warns when the current branch's PR is already closed or merged.\");\n }\n // Other outcomes (refused-*, already-ours) mirror the blocking hook's\n // own install path and are silent here on purpose: this hook is a\n // convenience warning, not a security control, so a refusal doesn't\n // leave the repository in a worse-than-before state the way a silently\n // skipped block would -- `spell doctor` still surfaces the refusal\n // reason for the shared hooks-path collision case.\n } catch {\n // Never let this convenience warning's own failure surface as a raw\n // stack trace after \"Initialized successfully\" -- it is strictly\n // additive, so a failure here means the repo is exactly as protected\n // as it was before this block ran, not less.\n }\n }\n\n // ── Secrets pre-commit hook (ARC-037 decision 2) ────────────────────────\n // Deliberately push_policy-independent: every profile gets this, since\n // credential leakage is a risk regardless of whether history may reach a\n // remote. Mandatory, not an interactive question -- see secrets-scan.ts's\n // own reasoning for why. Wrapped the same way as the push-safety block\n // above: a failure here must not surface as a raw stack trace after\n // \"Initialized successfully\".\n try {\n const hook = await installSecretsPrecommitHook(targetDir);\n if (hook.status === \"installed\") {\n printInfo(\"Installed a pre-commit hook that scans staged content for leaked credentials.\");\n } else if (hook.status === \"refused-unreadable-config\") {\n printWarning(\n \"Did not install the secrets pre-commit hook: git could not report the current \" +\n \"core.hooksPath (unreadable config, or a git too old for `--show-scope`).\",\n );\n } else if (hook.status === \"refused-default-hooks\") {\n printWarning(\n `Did not install the secrets pre-commit hook: this repository has hooks in git's default ` +\n `directory (${hook.hooks.join(\", \")}). Setting core.hooksPath would silently stop them ` +\n `running. Move them under \\`${ARCANE_HOOKS_DIR}\\` yourself and re-run.`,\n );\n } else if (hook.status === \"refused-foreign-hooks-path\") {\n printWarning(\n `Did not install the secrets pre-commit hook: core.hooksPath is already \"${hook.existing}\" ` +\n `(${describeConfigScope(hook.scope)}), so another hook manager owns it.`,\n );\n }\n // \"already-ours\": nothing to report, matches the prior install exactly.\n } catch (err) {\n printWarning(\n `Could not install the secrets pre-commit hook: ${err instanceof Error ? err.message : String(err)}. ` +\n \"Run `spell doctor --leaks` directly to scan on demand instead.\",\n );\n }\n\n // ── Step 7: Offer agent setup (for full and lite profiles) ─────────────\n let agentsConfigured = false;\n if (hasAgents && !options.profile) {\n console.log();\n const setupAgents = await confirm({\n message: \"🤖 Set up your agent team? (names, roles, AI tool configs)\",\n default: true,\n });\n\n if (setupAgents) {\n await runAgentsInit({}, targetDir, assetsDir);\n agentsConfigured = true;\n }\n }\n\n // ── Step 8: Print next steps ───────────────────────────────────────────\n console.log();\n printSection(\"🚀 Next steps\");\n console.log();\n let step = 1;\n\n if (!agentsConfigured && profile !== \"governance-only\") {\n printNextStep(step++, \"Run `spell agents init` to set up your agent team\");\n }\n if (agentsConfigured) {\n printNextStep(\n step++,\n \"Edit .arcane/agents.yaml to customize roles → `spell agents sync` to regenerate AI tool configs\",\n );\n }\n if (profile !== \"governance-only\") {\n printNextStep(\n step++,\n \"Review .arcane/governance/ docs and customize for your project\",\n );\n }\n if (repoNotFound) {\n printNextStep(\n step++,\n 'Initialize Git for this project: `git init -b main` (avoids defaulting to \"master\" on systems where that\\'s the system default)',\n );\n }\n printNextStep(\n step++,\n \"Commit the new files: git add .arcane .github .claude AGENTS.md CLAUDE.md .arcane.json\",\n );\n console.log();\n}\n","import {\n mkdir,\n access,\n readdir,\n readFile,\n writeFile,\n} from \"node:fs/promises\";\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\n\n/** SHA-256 hex digest of a file's content (ARC-038 decision 1). */\nexport async function hashFile(filePath: string): Promise<string> {\n const content = await readFile(filePath);\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\n/**\n * Validates that relativePath stays within targetDir.\n * Throws if the resolved path escapes the target directory boundary.\n */\nexport function validateTargetPath(\n targetDir: string,\n relativePath: string,\n): void {\n const resolvedBase = path.resolve(targetDir);\n const resolvedFull = path.resolve(targetDir, relativePath);\n\n if (\n resolvedFull !== resolvedBase &&\n !resolvedFull.startsWith(resolvedBase + path.sep)\n ) {\n throw new Error(\n `Path traversal detected: \"${relativePath}\" escapes target directory \"${targetDir}\"`,\n );\n }\n}\n\n/**\n * Creates a directory and all parent directories if they don't exist.\n */\nexport async function ensureDir(dirPath: string): Promise<void> {\n await mkdir(dirPath, { recursive: true });\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Copies srcPath into targetDir at relativePath.\n * Validates path traversal before any I/O.\n * Throws if the destination already exists and opts.force is not set.\n * Returns the copied content's SHA-256 hex digest (ARC-038 decision 1) --\n * read once into memory and reused for both the hash and the write, rather\n * than hashing srcPath and then separately copying it: reading every source\n * file twice measurably slowed a full `spell init` (~90 files) once every\n * file started being hashed, enough to push some CI/test runs over their\n * timeout under contention. One read, one write; no redundant I/O.\n */\nexport async function copyFile(\n srcPath: string,\n targetDir: string,\n relativePath: string,\n opts: { force?: boolean } = {},\n): Promise<string> {\n validateTargetPath(targetDir, relativePath);\n\n const destPath = path.resolve(targetDir, relativePath);\n await ensureDir(path.dirname(destPath));\n\n if (!opts.force && (await fileExists(destPath))) {\n throw new Error(\n `Destination already exists: \"${relativePath}\". Use --force to overwrite.`,\n );\n }\n\n const content = await readFile(srcPath);\n const hash = createHash(\"sha256\").update(content).digest(\"hex\");\n await writeFile(destPath, content);\n return hash;\n}\n\nexport interface CopiedFile {\n path: string;\n hash: string;\n}\n\n/**\n * Recursively copies a directory from srcDir to targetDir/relativeDir.\n * Validates the target path to prevent traversal attacks.\n * Returns each copied file's relative path and content hash (ARC-038\n * decision 1), for manifest tracking.\n */\nexport async function copyDirectory(\n srcDir: string,\n targetDir: string,\n relativeDir: string,\n opts: { force?: boolean } = {},\n): Promise<CopiedFile[]> {\n validateTargetPath(targetDir, relativeDir);\n\n const copiedFiles: CopiedFile[] = [];\n const entries = await readdir(srcDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcEntryPath = path.join(srcDir, entry.name);\n const relEntryPath = `${relativeDir}/${entry.name}`;\n\n if (entry.isDirectory()) {\n const subFiles = await copyDirectory(srcEntryPath, targetDir, relEntryPath, opts);\n copiedFiles.push(...subFiles);\n } else {\n const hash = await copyFile(srcEntryPath, targetDir, relEntryPath, opts);\n copiedFiles.push({ path: relEntryPath, hash });\n }\n }\n\n return copiedFiles;\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type {\n ArcaneManifest,\n ContentSensitivity,\n ExternalProvider,\n InstalledComponent,\n Profile,\n PushPolicy,\n TrackingMode,\n} from \"../types.js\";\n\nexport class ManifestNotFoundError extends Error {\n constructor(manifestPath: string) {\n super(`Manifest not found at \"${manifestPath}\". Run \"spell init\" first.`);\n this.name = \"ManifestNotFoundError\";\n }\n}\n\nexport class ManifestCorruptError extends Error {\n constructor(manifestPath: string) {\n super(\n `Manifest at \"${manifestPath}\" contains invalid JSON. It may be corrupted.`,\n );\n this.name = \"ManifestCorruptError\";\n }\n}\n\n/**\n * Distinct from ManifestCorruptError: the file IS valid JSON, but a field\n * holds a value outside its supported enum (EF-14 point 2 -- \"reject\n * unsupported values rather than silently treating them as a provider\").\n */\nexport class ManifestInvalidFieldError extends Error {\n constructor(manifestPath: string, field: string, value: unknown) {\n super(\n `Manifest at \"${manifestPath}\" has an unsupported value for \"${field}\": ${JSON.stringify(value)}.`,\n );\n this.name = \"ManifestInvalidFieldError\";\n }\n}\n\nconst MANIFEST_FILE = \".arcane.json\";\n\nconst VALID_TRACKING_MODES: TrackingMode[] = [\"internal\", \"external\"];\nconst VALID_EXTERNAL_PROVIDERS: ExternalProvider[] = [\"ado\", \"github\", \"jira\", \"other\"];\nconst VALID_CONTENT_SENSITIVITY: ContentSensitivity[] = [\"standard\", \"sensitive\"];\nconst VALID_PUSH_POLICIES: PushPolicy[] = [\"open\", \"guarded\", \"blocked\"];\n\n/**\n * `subject_root` is a free-form relative path, so it gets shape rules rather\n * than an enum. It is resolved against the repository root and handed to\n * spells, so a value that escapes the repo (absolute, or containing `..`)\n * would point agents at files outside the project entirely. \".\" is explicitly\n * legal: it means the repository root IS the subject tree (EF-07).\n */\n/**\n * True when a subject_root value is safe to store. Exported so the interactive\n * prompt can reject a bad value in place rather than writing it and failing on\n * every subsequent command until the operator hand-edits .arcane.json.\n */\nexport function isValidSubjectRoot(value: string): boolean {\n const invalid =\n value.trim() === \"\" ||\n path.isAbsolute(value) ||\n // Windows drive-relative (\"C:docs\") and UNC-ish values also escape.\n /^[a-zA-Z]:/.test(value) ||\n value.startsWith(\"\\\\\\\\\") ||\n value.startsWith(\"\\\\\") ||\n value.split(/[\\\\/]/).includes(\"..\") ||\n // A stored subject_root is interpolated into agent prompts downstream, so\n // keep it a single path-shaped token rather than a multi-line payload.\n /[\\r\\n\\0]/.test(value);\n return !invalid;\n}\n\nfunction validateSubjectRoot(value: string, filePath: string): void {\n if (!isValidSubjectRoot(value)) {\n throw new ManifestInvalidFieldError(filePath, \"subject_root\", value);\n }\n}\n\n/**\n * True when a secretsScanExcludePrefixes value is safe to store: an array of\n * non-empty strings. Deliberately looser than `isValidSubjectRoot` -- a scan\n * exclusion is a path *prefix* match, not a path handed to spells, so it has\n * no traversal-escape risk to guard against; it only needs to be a real,\n * matchable string.\n */\nexport function isValidSecretsScanExcludePrefixes(value: unknown): value is string[] {\n return (\n Array.isArray(value) &&\n value.every((entry) => typeof entry === \"string\" && entry.length > 0)\n );\n}\n\nfunction validateSecretsScanExcludePrefixes(value: unknown, filePath: string): void {\n if (!isValidSecretsScanExcludePrefixes(value)) {\n throw new ManifestInvalidFieldError(filePath, \"secretsScanExcludePrefixes\", value);\n }\n}\n\nfunction manifestPath(targetDir: string): string {\n return path.join(targetDir, MANIFEST_FILE);\n}\n\nfunction validateTrackingFields(manifest: ArcaneManifest, filePath: string): void {\n if (\n manifest.tracking_mode !== undefined &&\n !VALID_TRACKING_MODES.includes(manifest.tracking_mode)\n ) {\n throw new ManifestInvalidFieldError(filePath, \"tracking_mode\", manifest.tracking_mode);\n }\n if (\n manifest.external_provider !== undefined &&\n manifest.external_provider !== null &&\n !VALID_EXTERNAL_PROVIDERS.includes(manifest.external_provider)\n ) {\n throw new ManifestInvalidFieldError(filePath, \"external_provider\", manifest.external_provider);\n }\n if (\n manifest.content_sensitivity !== undefined &&\n !VALID_CONTENT_SENSITIVITY.includes(manifest.content_sensitivity)\n ) {\n throw new ManifestInvalidFieldError(\n filePath,\n \"content_sensitivity\",\n manifest.content_sensitivity,\n );\n }\n if (\n manifest.push_policy !== undefined &&\n !VALID_PUSH_POLICIES.includes(manifest.push_policy)\n ) {\n throw new ManifestInvalidFieldError(filePath, \"push_policy\", manifest.push_policy);\n }\n if (manifest.subject_root !== undefined && manifest.subject_root !== null) {\n if (typeof manifest.subject_root !== \"string\") {\n throw new ManifestInvalidFieldError(filePath, \"subject_root\", manifest.subject_root);\n }\n validateSubjectRoot(manifest.subject_root, filePath);\n }\n if (manifest.secretsScanExcludePrefixes !== undefined) {\n validateSecretsScanExcludePrefixes(manifest.secretsScanExcludePrefixes, filePath);\n }\n}\n\n/**\n * Reads .arcane.json from targetDir.\n * Throws ManifestNotFoundError if the file is missing.\n * Throws ManifestCorruptError if the file contains invalid JSON.\n * Throws ManifestInvalidFieldError if tracking_mode/external_provider hold\n * an unsupported value.\n */\nexport async function readManifest(targetDir: string): Promise<ArcaneManifest> {\n const filePath = manifestPath(targetDir);\n let content: string;\n\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n throw new ManifestNotFoundError(filePath);\n }\n throw err;\n }\n\n let manifest: ArcaneManifest;\n try {\n manifest = JSON.parse(content) as ArcaneManifest;\n } catch {\n throw new ManifestCorruptError(filePath);\n }\n\n validateTrackingFields(manifest, filePath);\n return manifest;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Resolves the effective `secretsScanExcludePrefixes` list for a target\n * directory (ARC-037). Self-hosted-aware: falls back to reading\n * src/assets/.arcane.json when there is no root .arcane.json, mirroring\n * doctor.ts's own self-hosted-manifest detection (this repo's own case --\n * it ships no root manifest, only the self-hosted marker file). Shared by\n * the build-time scan (scripts/copy-assets.ts) and `spell doctor --leaks`,\n * so a repository configures its exclusions in exactly one place regardless\n * of which path runs the scan.\n */\nexport async function resolveSecretsScanExcludePrefixes(targetDir: string): Promise<string[]> {\n try {\n const manifest = await readManifest(targetDir);\n return manifest.secretsScanExcludePrefixes ?? [];\n } catch {\n // No root manifest -- fall through to the self-hosted case below.\n }\n\n try {\n const raw = await readFile(path.join(targetDir, \"src\", \"assets\", \".arcane.json\"), \"utf-8\");\n const parsed: unknown = JSON.parse(raw);\n if (isRecord(parsed) && parsed[\"selfHosted\"] === true && parsed[\"tracking_mode\"] === \"internal\") {\n const prefixes = parsed[\"secretsScanExcludePrefixes\"];\n if (isValidSecretsScanExcludePrefixes(prefixes)) return prefixes;\n }\n } catch {\n // No self-hosted manifest either -- scan with no exclusions.\n }\n\n return [];\n}\n\n/**\n * Writes the manifest to .arcane.json in targetDir with 2-space indentation.\n */\nexport async function writeManifest(\n targetDir: string,\n manifest: ArcaneManifest,\n): Promise<void> {\n const filePath = manifestPath(targetDir);\n await writeFile(filePath, JSON.stringify(manifest, null, 2), \"utf-8\");\n}\n\n/**\n * Creates a new .arcane.json in targetDir with an empty components array.\n * Returns the created manifest.\n */\nexport async function createManifest(\n targetDir: string,\n profile: Profile,\n version: string,\n): Promise<ArcaneManifest> {\n const manifest: ArcaneManifest = {\n version,\n profile,\n installedAt: new Date().toISOString(),\n components: [],\n };\n await writeManifest(targetDir, manifest);\n return manifest;\n}\n\n/**\n * Pure function — returns a new manifest with the component appended.\n * Does not write to disk.\n */\nexport function addComponent(\n manifest: ArcaneManifest,\n component: InstalledComponent,\n): ArcaneManifest {\n return {\n ...manifest,\n components: [...manifest.components, component],\n };\n}\n\n/**\n * Pure function — returns a new manifest with the named component removed.\n * Does not write to disk.\n */\nexport function removeComponent(\n manifest: ArcaneManifest,\n name: string,\n): ArcaneManifest {\n return {\n ...manifest,\n components: manifest.components.filter((c) => c.name !== name),\n };\n}\n\n/**\n * Returns true if a component with the given name exists in the manifest.\n */\nexport function hasComponent(manifest: ArcaneManifest, name: string): boolean {\n return manifest.components.some((c) => c.name === name);\n}\n","/**\n * Profile configuration — the canonical source of truth for Arcane profiles.\n *\n * A profile bundles a curated set of components for a common use case.\n * Changing which components an EXISTING profile bundles requires only editing\n * this file. Adding a NEW profile id additionally touches the `Profile` union\n * in types.ts, `VALID_PROFILES` and the presentation/gating branches in\n * commands/init.ts, the --profile help string in index.ts, and the retrofit\n * mirror in modules/hub.ts -- the registry itself needs no change.\n *\n * The special value \"*\" for `components` means \"all registered components\"\n * and is expanded by the registry at runtime.\n */\n\nimport type { Profile } from \"../types.js\";\n\nexport interface ProfileConfig {\n id: Profile;\n displayName: string;\n description: string;\n /**\n * Component names included in this profile.\n * Use the special value \"*\" to mean \"all registered components\" (full install).\n */\n components: string[] | \"*\";\n}\n\nexport const PROFILE_CONFIGS: ProfileConfig[] = [\n {\n id: \"full\",\n displayName: \"Full Suite\",\n description: \"All components — spells, governance, agents, templates\",\n components: \"*\",\n },\n {\n id: \"lite\",\n displayName: \"Essentials\",\n description: \"Spells + core governance — fast start\",\n components: [\n \"spells-session\",\n \"spells-capture\",\n \"spells-delivery\",\n \"spells-review\",\n \"spells-planning\",\n \"spells-build\",\n \"spells-venture\",\n \"spells-meta\",\n \"agent-output-instructions\",\n \"git-conventions\",\n \"testing-standards\",\n \"framework-decisions\",\n \"session-continuity\",\n ],\n },\n {\n id: \"methodology\",\n displayName: \"Methodology Suite\",\n description: \"Spells + governance — full methodology without security/infra docs\",\n components: [\n \"spells-session\",\n \"spells-capture\",\n \"spells-delivery\",\n \"spells-review\",\n \"spells-planning\",\n \"spells-build\",\n \"spells-venture\",\n \"spells-meta\",\n \"agent-output-instructions\",\n \"git-conventions\",\n \"testing-standards\",\n \"framework-decisions\",\n \"session-continuity\",\n \"decision-documentation-standard\",\n \"agent-work-queue-model\",\n \"development-methodology\",\n \"spell-authoring-standards\",\n ],\n },\n {\n id: \"docs\",\n displayName: \"Docs / Records\",\n description: \"Documentation and records repositories — no code, test, or deployment workflows\",\n components: [\n // Deliberate exclusions, per docs-mode PRD MH-01: \"spells-build\"\n // (implementation, tests, stack experts, release, deployment, PRD\n // enchantment, asset tooling), \"spells-review\" (adversarial CODE review\n // -- its own workflow validates test coverage against source, which a\n // docs repo has neither of), and \"spells-venture\" (hub-only).\n //\n // MH-01 requires every retained spell to complete its core workflow\n // without source code, tests, CI, or an external tracker. Asserted --\n // exclusions included, which MH-01 requires explicitly -- in\n // test/docs-profile-registry-split.test.ts.\n \"spells-session\",\n \"spells-capture\",\n \"spells-delivery\",\n \"spells-planning\",\n \"spells-meta\",\n \"spells-docs\",\n \"docs-baseline\",\n \"records-conventions\",\n \"agent-output-instructions\",\n \"git-conventions\",\n // Four retained docs spells link to agent-policies; it carries no code\n // implication, so shipping it closes a dangling reference cheaply.\n \"agent-policies\",\n \"framework-decisions\",\n \"session-continuity\",\n \"decision-documentation-standard\",\n \"agent-work-queue-model\",\n \"development-methodology\",\n \"naming-conventions\",\n \"universal-agent-rules\",\n \"spell-authoring-standards\",\n ],\n },\n {\n id: \"governance-only\",\n displayName: \"Governance Only\",\n description: \"Standards docs only — no spells or agents\",\n components: [\n \"agent-output-instructions\",\n \"git-conventions\",\n \"testing-standards\",\n \"framework-decisions\",\n \"decision-documentation-standard\",\n \"agent-work-queue-model\",\n \"naming-conventions\",\n \"agent-policies\",\n \"threat-model\",\n \"hardening-checklist\",\n \"authentication-strategy\",\n \"new-business-setup\",\n \"agent-approved-paths\",\n \"portable-bootstrap\",\n \"development-methodology\",\n \"cicd-standards\",\n \"poc-management-pattern\",\n \"product-excellence-standards\",\n \"rca-process-standard\",\n \"universal-agent-rules\",\n \"spell-authoring-standards\",\n \"external-verification-standards\",\n \"web-discoverability-standards\",\n \"mobile-release-standards\",\n \"records-conventions\",\n \"compliance-standards\",\n ],\n },\n];\n","import type { Profile, RegistryComponent, ProfileDefinition } from \"../types.js\";\nimport { PROFILE_CONFIGS } from \"../config/profiles.js\";\n\nexport class ComponentNotFoundError extends Error {\n constructor(name: string, available: string[]) {\n super(\n `Component \"${name}\" not found. Available components: ${available.join(\", \")}`,\n );\n this.name = \"ComponentNotFoundError\";\n }\n}\n\n// ─── Component definitions ───────────────────────────────────────────────────\n// File paths are relative to src/assets/ (source) / dist/assets/ (published).\n\nconst COMPONENTS: RegistryComponent[] = [\n // Governance\n {\n name: \"git-conventions\",\n description: \"Git branching, commit message, and PR conventions\",\n files: [\".arcane/governance/git-conventions.md\"],\n },\n {\n name: \"testing-standards\",\n description: \"Testing framework selection, coverage thresholds, and CI gates\",\n files: [\".arcane/governance/testing-standards.md\"],\n },\n {\n name: \"framework-decisions\",\n description: \"Offline reference for legacy framework ADR citations\",\n files: [\".arcane/governance/framework-decisions.md\"],\n },\n {\n name: \"decision-documentation-standard\",\n description: \"ADR format and decision-logging conventions\",\n files: [\".arcane/governance/decision-documentation-standard.md\"],\n },\n {\n name: \"agent-work-queue-model\",\n description: \"Work queue model for AI agent task assignment and tracking\",\n files: [\".arcane/governance/agent-work-queue-model.md\"],\n },\n {\n name: \"naming-conventions\",\n description: \"Machine, agent, and service naming rules (three-tier model)\",\n files: [\".arcane/governance/naming-conventions.md\"],\n },\n {\n name: \"agent-policies\",\n description: \"Agent autonomy levels, power levels, and operational constraints\",\n files: [\".arcane/governance/agent-policies.md\"],\n },\n {\n name: \"threat-model\",\n description: \"Security threat model covering STRIDE categories and mitigations\",\n files: [\".arcane/governance/threat-model.md\"],\n },\n {\n name: \"hardening-checklist\",\n description: \"Production hardening checklist for infrastructure and agents\",\n files: [\".arcane/governance/hardening-checklist.md\"],\n },\n {\n name: \"authentication-strategy\",\n description: \"Authentication patterns, token management, and identity strategy\",\n files: [\".arcane/governance/authentication-strategy.md\"],\n },\n {\n name: \"new-business-setup\",\n description: \"Step-by-step playbook for bootstrapping a new business unit\",\n files: [\".arcane/governance/new-business-setup.md\"],\n },\n {\n name: \"agent-approved-paths\",\n description: \"Approved repository paths and access boundaries for agents\",\n files: [\".arcane/governance/agent-approved-paths.md\"],\n },\n {\n name: \"portable-bootstrap\",\n description: \"Portable AI context bootstrap for onboarding new AI clients\",\n files: [\".arcane/governance/portable-bootstrap.md\"],\n },\n // Governance — methodology\n {\n name: \"development-methodology\",\n description: \"Spell Loop development methodology\",\n files: [\".arcane/governance/development-methodology.md\"],\n },\n {\n name: \"cicd-standards\",\n description: \"CI/CD pipeline standards and quality gates\",\n files: [\".arcane/governance/cicd-standards.md\"],\n },\n {\n name: \"poc-management-pattern\",\n description: \"POC lifecycle management pattern\",\n files: [\".arcane/governance/poc-management-pattern.md\"],\n },\n {\n name: \"product-excellence-standards\",\n description: \"Product quality gate standards and spell-enchant requirements\",\n files: [\".arcane/governance/product-excellence-standards.md\"],\n },\n {\n name: \"spell-authoring-standards\",\n description: \"Spell Quality Rubric — the authoring bar for spell prompts (8 dimensions)\",\n files: [\".arcane/governance/spell-authoring-standards.md\"],\n },\n {\n name: \"rca-process-standard\",\n description: \"Root cause analysis process standard\",\n files: [\".arcane/governance/rca-process-standard.md\"],\n },\n {\n name: \"universal-agent-rules\",\n description: \"Universal rules for all AI agents operating in any Arcane-managed repo\",\n files: [\".arcane/governance/universal-agent-rules.md\"],\n },\n // VS Code Copilot instructions — installed to .github/instructions/\n {\n name: \"agent-output-instructions\",\n description: \"Copilot enforcement rules: PR link format, merge strategy, and branch naming\",\n files: [\".github/instructions/agent-output.instructions.md\"],\n },\n // Repository baseline files (EF-10 + EF-17). skipExisting: these are\n // user-owned once written -- a repo with its own .gitattributes has an\n // intentional policy Arcane must not overwrite. Sources are stored under a\n // non-dotfile path and mapped via sourceOverrides; see RegistryComponent.\n {\n name: \"docs-baseline\",\n description: \"Line-ending and binary-format baseline for document repositories (.gitattributes/.gitignore)\",\n files: [\".gitattributes\", \".gitignore\"],\n sourceOverrides: {\n \".gitattributes\": \"docs-baseline/gitattributes\",\n \".gitignore\": \"docs-baseline/gitignore\",\n },\n skipExisting: true,\n initOnly: true,\n },\n // Optional MCP config scaffold (BC-22/I12). skipExisting: a repo's own\n // .mcp.json is user-owned server config Arcane must never overwrite.\n // Not initOnly -- useful to retrofit via `spell add` on an existing repo too.\n {\n name: \"mcp-config-template\",\n description: \"Example .mcp.json with a per-server timeout, companion to the MCP fail-fast rule\",\n files: [\".mcp.json\"],\n skipExisting: true,\n },\n {\n name: \"records-conventions\",\n description: \"Supersession, tombstone, and retention conventions for records repositories\",\n files: [\".arcane/governance/records-conventions.md\"],\n },\n {\n name: \"external-verification-standards\",\n description: \"Rules for confirming a write took effect in a system you don't control — consoles, pipelines, DNS, deployed endpoints\",\n files: [\".arcane/governance/external-verification-standards.md\"],\n },\n {\n name: \"web-discoverability-standards\",\n description: \"Search-engine and AI-assistant discoverability rules for web properties\",\n files: [\".arcane/governance/web-discoverability-standards.md\"],\n },\n {\n name: \"mobile-release-standards\",\n description: \"Durable App Store / Google Play console and release-track facts consumed by spell-eas-store-deploy\",\n files: [\".arcane/governance/mobile-release-standards.md\"],\n },\n {\n name: \"compliance-standards\",\n description: \"GDPR/CCPA/SOC 2/HIPAA obligations and a tiered applicability guide, consumed by spell-compliance\",\n files: [\".arcane/governance/compliance-standards.md\"],\n },\n // ─── Spells ────────────────────────────────────────────────────────────────\n // Split from the former monolithic `spell-prompts` + `claude-commands` pair\n // so a profile can select spells by capability (see ARC-0NN). Grouping lives\n // here and only here -- every spell file stays flat and unrenamed on disk.\n //\n // Each component carries BOTH client formats of the same spell: the Copilot\n // prompt (.github/prompts/*.prompt.md) and the Claude Code wrapper\n // (.claude/commands/*.md). They are never independently selectable -- every\n // profile that wanted one always wanted the other -- and pairing them here\n // makes it structurally impossible for the two formats of one spell to drift\n // apart across profiles.\n {\n name: \"spells-session\",\n description: \"Session lifecycle — open, close, commit, status, version\",\n files: [\n \".github/prompts/spell-open-session.prompt.md\",\n \".claude/commands/spell-open-session.md\",\n \".github/prompts/spell-close-session.prompt.md\",\n \".claude/commands/spell-close-session.md\",\n \".github/prompts/spell-commit-work.prompt.md\",\n \".claude/commands/spell-commit-work.md\",\n \".github/prompts/spell-status.prompt.md\",\n \".claude/commands/spell-status.md\",\n \".github/prompts/spell-arcane-version.prompt.md\",\n \".claude/commands/spell-arcane-version.md\",\n ],\n },\n {\n name: \"spells-capture\",\n description: \"Idea, todo, feedback and explanation capture\",\n files: [\n \".github/prompts/spell-save-idea.prompt.md\",\n \".claude/commands/spell-save-idea.md\",\n \".github/prompts/spell-todo.prompt.md\",\n \".claude/commands/spell-todo.md\",\n \".github/prompts/spell-feedback.prompt.md\",\n \".claude/commands/spell-feedback.md\",\n \".github/prompts/spell-suggest-feature.prompt.md\",\n \".claude/commands/spell-suggest-feature.md\",\n \".github/prompts/spell-document.prompt.md\",\n \".claude/commands/spell-document.md\",\n \".github/prompts/spell-verification-ledger.prompt.md\",\n \".claude/commands/spell-verification-ledger.md\",\n \".github/prompts/spell-brainstorm.prompt.md\",\n \".claude/commands/spell-brainstorm.md\",\n \".github/prompts/spell-explain-concept.prompt.md\",\n \".claude/commands/spell-explain-concept.md\",\n ],\n },\n {\n name: \"spells-delivery\",\n description: \"Pull-request lifecycle — open a PR, sync a stale one, respond to review feedback\",\n files: [\n \".github/prompts/spell-create-pull-request.prompt.md\",\n \".claude/commands/spell-create-pull-request.md\",\n \".github/prompts/spell-sync-pull-request.prompt.md\",\n \".claude/commands/spell-sync-pull-request.md\",\n \".github/prompts/spell-address-review.prompt.md\",\n \".claude/commands/spell-address-review.md\",\n ],\n },\n {\n name: \"spells-review\",\n description: \"Adversarial code review — requires source and tests, so excluded from docs-only profiles\",\n files: [\n \".github/prompts/spell-review.prompt.md\",\n \".claude/commands/spell-review.md\",\n \".github/prompts/spell-review-batch.prompt.md\",\n \".claude/commands/spell-review-batch.md\",\n ],\n },\n {\n name: \"spells-planning\",\n description: \"PRD, architecture, scoping and product review\",\n files: [\n \".github/prompts/spell-plan.prompt.md\",\n \".claude/commands/spell-plan.md\",\n \".github/prompts/spell-architect.prompt.md\",\n \".claude/commands/spell-architect.md\",\n \".github/prompts/spell-scope.prompt.md\",\n \".claude/commands/spell-scope.md\",\n \".github/prompts/spell-product-review.prompt.md\",\n \".claude/commands/spell-product-review.md\",\n ],\n },\n {\n name: \"spells-build\",\n description: \"Code and product delivery — implementation, tests, stack experts, release, deployment, asset tooling\",\n files: [\n \".github/prompts/spell-implement.prompt.md\",\n \".claude/commands/spell-implement.md\",\n \".github/prompts/spell-test.prompt.md\",\n \".claude/commands/spell-test.md\",\n \".github/prompts/spell-full-cycle.prompt.md\",\n \".claude/commands/spell-full-cycle.md\",\n \".github/prompts/spell-bug.prompt.md\",\n \".claude/commands/spell-bug.md\",\n \".github/prompts/spell-bump.prompt.md\",\n \".claude/commands/spell-bump.md\",\n \".github/prompts/spell-dotnet-expert.prompt.md\",\n \".claude/commands/spell-dotnet-expert.md\",\n \".github/prompts/spell-security-review.prompt.md\",\n \".claude/commands/spell-security-review.md\",\n \".github/prompts/spell-ship.prompt.md\",\n \".claude/commands/spell-ship.md\",\n \".github/prompts/spell-enchant.prompt.md\",\n \".claude/commands/spell-enchant.md\",\n \".github/prompts/spell-generate-bot-icons.prompt.md\",\n \".claude/commands/spell-generate-bot-icons.md\",\n \".github/prompts/spell-make-discoverable.prompt.md\",\n \".claude/commands/spell-make-discoverable.md\",\n \".github/prompts/spell-scry.prompt.md\",\n \".claude/commands/spell-scry.md\",\n \".github/prompts/spell-eas-store-deploy.prompt.md\",\n \".claude/commands/spell-eas-store-deploy.md\",\n \".github/prompts/spell-compliance.prompt.md\",\n \".claude/commands/spell-compliance.md\",\n ],\n },\n {\n name: \"spells-docs\",\n description: \"Documentation and records workflows — adopt an existing document tree\",\n files: [\n \".github/prompts/spell-adopt-docs.prompt.md\",\n \".claude/commands/spell-adopt-docs.md\",\n ],\n },\n {\n name: \"spells-venture\",\n description: \"Hub-only venture management\",\n files: [\n \".github/prompts/spell-summon-venture.prompt.md\",\n \".claude/commands/spell-summon-venture.md\",\n \".github/prompts/spell-manifest.prompt.md\",\n \".claude/commands/spell-manifest.md\",\n ],\n },\n {\n name: \"spells-meta\",\n description: \"Arcane-about-Arcane — presentation and documentation drift detection\",\n files: [\n \".github/prompts/spell-present-arcane.prompt.md\",\n \".claude/commands/spell-present-arcane.md\",\n \".github/prompts/spell-check-drift.prompt.md\",\n \".claude/commands/spell-check-drift.md\",\n ],\n },\n // Templates\n {\n name: \"venture-template\",\n description: \"Starter template for a new business venture folder — overview plus idea/todo books\",\n files: [\n \".arcane/templates/venture-template/overview.md\",\n \".arcane/templates/venture-template/IDEAS.md\",\n \".arcane/templates/venture-template/TODO.md\",\n ],\n },\n // Session continuity — files required for spell-close-session / spell-open-session\n {\n name: \"session-continuity\",\n description: \"Install-once project orientation and session lifecycle files\",\n skipExisting: true,\n files: [\n \"README.md\",\n \"project.md\",\n \"TODO.md\",\n \"DECISIONS.md\",\n \"ai-context/system-prompt-context.md\",\n \"journal/.gitkeep\",\n ],\n },\n // Agent definitions\n // NOTE: the full portable agent system is managed by `spell agents init` / sync / list.\n // This component only installs the policy reference template for governance-only setups.\n {\n name: \"agent-definitions\",\n description: \"Agent policy reference template (for governance-only setups — use `spell agents init` for the full agent system)\",\n files: [\".arcane/agents/agent-policies-template.md\"],\n },\n // NOTE: the static `agent-files` component was retired — `.github/agents/*.agent.md`\n // files are generated per-roster by `spell agents init` / `spell agents sync`, so\n // installing a fixed-name set via `spell init` shipped stale names and collided\n // with the generated output.\n];\n\n// ─── Profile map (derived from config) ───────────────────────────────────────\n\nfunction buildProfileMap(): Record<Profile, string[]> {\n const allNames = COMPONENTS.map((c) => c.name);\n const map = {} as Record<Profile, string[]>;\n for (const config of PROFILE_CONFIGS) {\n map[config.id] = config.components === \"*\" ? allNames : config.components;\n }\n return map;\n}\n\nconst PROFILE_MAP = buildProfileMap();\n\n// ─── API ──────────────────────────────────────────────────────────────────────\n\nconst componentIndex = new Map(COMPONENTS.map((c) => [c.name, c]));\n\n/**\n * Returns a component by name.\n * Throws ComponentNotFoundError if not found.\n */\n/** Names of the capability-scoped spell components, derived not hand-listed. */\nexport const SPELL_COMPONENT_NAMES: string[] = COMPONENTS.map((c) => c.name).filter((n) =>\n n.startsWith(\"spells-\"),\n);\n\n/**\n * The exact set of components that reconstitutes what the retired monolithic\n * `spell-prompts` / `claude-commands` pair used to install.\n *\n * **Deliberately a frozen literal, not derived from `SPELL_COMPONENT_NAMES`.**\n * Deriving it would mean every future `spells-*` group silently joins this\n * list, so a legacy install would be handed brand-new spells it never had —\n * and a test asserting `migration === SPELL_COMPONENT_NAMES` would be\n * self-referential, passing while the behaviour changed underneath it. This\n * list describes history: what the old monolith contained, as of the 0.18.0\n * split. It must not grow.\n */\nconst LEGACY_MONOLITH_REPLACEMENTS = [\n \"spells-session\",\n \"spells-capture\",\n \"spells-delivery\",\n \"spells-review\",\n \"spells-planning\",\n \"spells-build\",\n \"spells-venture\",\n \"spells-meta\",\n] as const;\n\n/**\n * Components that no longer exist under their old name, mapped to the set that\n * replaces them.\n *\n * `spell-prompts` and `claude-commands` were one monolithic pair holding all 34\n * spells in each client format. Both map to the same replacements, because\n * those components now carry both formats of every spell — so a manifest\n * listing either legacy name (or both, which every profile that had one did)\n * converges on the same result. Callers must dedupe.\n *\n * Without this, `spell update` would hit `ComponentNotFoundError` for the\n * legacy names, print \"not in registry — skipping\", preserve the dead entry,\n * and silently never update that repo's spells again.\n *\n * Null-prototype so a manifest component named `constructor` or `toString`\n * can't resolve to an inherited function and blow up the lookup.\n */\nexport const LEGACY_COMPONENT_MIGRATIONS: Readonly<Record<string, readonly string[]>> =\n Object.assign(Object.create(null) as Record<string, readonly string[]>, {\n \"spell-prompts\": LEGACY_MONOLITH_REPLACEMENTS,\n \"claude-commands\": LEGACY_MONOLITH_REPLACEMENTS,\n });\n\nexport function getComponent(name: string): RegistryComponent {\n const component = componentIndex.get(name);\n if (!component) {\n throw new ComponentNotFoundError(name, Array.from(componentIndex.keys()));\n }\n return component;\n}\n\n/**\n * Returns all components for the given profile.\n */\nexport function getProfile(profile: Profile): RegistryComponent[] {\n return PROFILE_MAP[profile].map((name) => getComponent(name));\n}\n\n/**\n * Returns all registered components.\n */\nexport function getAllComponents(): RegistryComponent[] {\n return [...COMPONENTS];\n}\n\n/**\n * Returns all profile definitions with their component lists expanded.\n * Profiles are sourced from src/config/profiles.ts.\n */\nexport function listProfiles(): ProfileDefinition[] {\n const allNames = COMPONENTS.map((c) => c.name);\n return PROFILE_CONFIGS.map((config) => ({\n id: config.id,\n displayName: config.displayName,\n description: config.description,\n components:\n config.components === \"*\" ? [...allNames] : [...config.components],\n }));\n}\n","import chalk from \"chalk\";\nimport gradient from \"gradient-string\";\nimport { readManifest } from \"./manifest.js\";\n\nconst TAGLINE = \"Cast spells to ship software\";\n\n// ─── Brand palette — steel blue (#6F9FD8) ────────────────────────────────────\nconst STEEL = \"#6f9fd8\";\nconst STEEL_DEEP = \"#3a6ea5\";\nconst STEEL_DIM = \"#5d6f93\";\nconst INK_LABEL = \"#c7d2ee\";\nconst FAINT = \"#2c3658\";\n\nconst STOPS = [\"#2a4d7d\", \"#4a7bb5\", \"#6f9fd8\", \"#a9c8ec\"];\nconst arcaneGradient = gradient(STOPS);\n\n// ─── ARCANE wordmark ─────────────────────────────────────────────────────────\nconst WORDMARK = [\n \" █████╗ ██████╗ ██████╗ █████╗ ███╗ ██╗███████╗\",\n \"██╔══██╗██╔══██╗██╔════╝██╔══██╗████╗ ██║██╔════╝\",\n \"███████║██████╔╝██║ ███████║██╔██╗ ██║█████╗\",\n \"██╔══██║██╔══██╗██║ ██╔══██║██║╚██╗██║██╔══╝\",\n \"██║ ██║██║ ██║╚██████╗██║ ██║██║ ╚████║███████╗\",\n \"╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝\",\n];\nconst INDENT = \" \";\nconst LOCKUP_WIDTH = INDENT.length + Math.max(...WORDMARK.map((l) => l.length));\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** True when the terminal can render the fade-in safely. */\nfunction isAnimatable(): boolean {\n return (\n !!process.stdout.isTTY &&\n process.env[\"TERM\"] !== \"dumb\" &&\n process.env[\"CI\"] !== \"true\" &&\n process.env[\"ARCANE_DISABLE_ANIMATION\"] !== \"true\" &&\n (process.stdout.columns ?? 80) >= LOCKUP_WIDTH\n );\n}\n\n/** Scale a hex color toward black by factor f (0..1) — used for the fade-in. */\nfunction scale(hex: string, f: number): string {\n const v = (i: number): number =>\n Math.max(0, Math.min(255, Math.round(parseInt(hex.slice(i, i + 2), 16) * f)));\n return \"#\" + [v(1), v(3), v(5)].map((x) => x.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n/** Build the ARCANE wordmark lines at brightness f (1 = full color). */\nfunction lockupLines(f = 1): string[] {\n const g = f >= 1 ? arcaneGradient : gradient(STOPS.map((c) => scale(c, f)));\n return WORDMARK.map((line) => INDENT + g(line));\n}\n\nfunction printFooter(version: string): void {\n const taglineText = ` ${TAGLINE} · agent-native SDLC · v${version}`;\n const width = Math.max(LOCKUP_WIDTH, taglineText.length);\n const border = chalk.hex(STEEL_DEEP)(\"─\".repeat(width));\n console.log(border);\n console.log(\n chalk.hex(STEEL)(` ${TAGLINE}`),\n chalk.hex(STEEL_DIM)(`· agent-native SDLC · v${version}`),\n );\n console.log(border);\n}\n\n/**\n * Prints the ARCANE wordmark static, with tagline and version.\n * Used by subcommands (init, etc.).\n */\nexport function printBanner(version: string): void {\n console.log();\n for (const line of lockupLines()) console.log(line);\n printFooter(version);\n console.log();\n}\n\n/**\n * Headline counts for the welcome — turns the installed component file list into\n * \"N spells · N agents · N standards\" (the manifest stores registry-relative,\n * forward-slash paths). Returns [] when nothing categorizable is installed, so\n * the caller can fall back to a plain component count.\n */\nfunction installSummary(components: { files: string[] }[]): string[] {\n const files = components.flatMap((c) =>\n c.files.map((f) => f.replace(/\\\\/g, \"/\")),\n );\n const spells = new Set(\n files\n .filter((f) => /\\/(prompts|commands)\\/spell-.+\\.md$/.test(f))\n .map((f) => f.split(\"/\").pop()!.replace(/\\.prompt\\.md$|\\.md$/, \"\")),\n ).size;\n const agents = files.filter((f) => /\\/agents\\/[^/]+\\.agent\\.md$/.test(f)).length;\n const standards = files.filter((f) =>\n /\\/governance\\/[^/]+\\.md$/.test(f),\n ).length;\n const parts: string[] = [];\n if (spells) parts.push(`${spells} spell${spells === 1 ? \"\" : \"s\"}`);\n if (agents) parts.push(`${agents} agent${agents === 1 ? \"\" : \"s\"}`);\n if (standards) parts.push(`${standards} standard${standards === 1 ? \"\" : \"s\"}`);\n return parts;\n}\n\n/**\n * The bare-`spell` welcome screen: a soft fade-in of the lockup followed by a\n * single gentle pulse (strobe-safe — monotonic brightness ramps, no color\n * cycling), then real current state: whether Arcane is installed in this repo\n * (profile, components, version) and the Spell Loop. Falls back to a static\n * lockup on non-TTY / CI / narrow terminals.\n */\nexport async function printWelcome(version: string, cwd: string): Promise<void> {\n console.log();\n if (isAnimatable()) {\n const draw = (lines: string[], redraw: boolean): void => {\n if (redraw) process.stdout.write(`\\x1b[${lines.length}A`);\n for (const line of lines) process.stdout.write(`\\r\\x1b[2K${line}\\n`);\n };\n // 1. Fade in from dark — the mark materializes.\n const fade = [0.1, 0.22, 0.36, 0.52, 0.68, 0.84, 1];\n for (let i = 0; i < fade.length; i++) {\n draw(lockupLines(fade[i]!), i > 0);\n await sleep(90);\n }\n // 2. One gentle settling pulse — a single slow breath of brightness.\n const pulse = [1, 0.9, 0.82, 0.9, 1];\n for (let i = 0; i < pulse.length; i++) {\n draw(lockupLines(pulse[i]!), true);\n await sleep(140);\n }\n } else {\n for (const line of lockupLines()) console.log(line);\n }\n printFooter(version);\n console.log();\n\n const label = (s: string): string => chalk.hex(STEEL_DIM)(s.padEnd(11));\n const dot = chalk.hex(FAINT)(\"·\");\n\n let repoLine: string;\n try {\n const manifest = await readManifest(cwd);\n const parts = installSummary(manifest.components);\n const summary = parts.length\n ? parts\n : [`${manifest.components.length} components`];\n repoLine =\n `${chalk.hex(STEEL)(\"✓\")} Arcane ${chalk.hex(INK_LABEL)(`«${manifest.profile}»`)} ${dot} ` +\n summary.map((p) => chalk.hex(INK_LABEL)(p)).join(` ${dot} `) +\n ` ${dot} ${chalk.hex(STEEL_DIM)(`v${manifest.version}`)}`;\n } catch {\n repoLine =\n `${chalk.hex(STEEL_DIM)(\"○\")} not initialized ${chalk.hex(FAINT)(\"—\")} run ` +\n `${chalk.hex(STEEL).inverse(\" spell init \")} ${chalk.hex(STEEL_DIM)(\"to scaffold\")}`;\n }\n console.log(` ${label(\"This repo\")}${repoLine}`);\n\n const phases = [\"plan\", \"architect\", \"implement\", \"test\", \"review\", \"ship\"].join(\n chalk.hex(STEEL_DEEP)(\" → \"),\n );\n console.log(` ${label(\"Spell Loop\")}${chalk.hex(\"#dbe3f7\")(phases)}`);\n\n // loop-back hint under the implement → test → review cycle\n const flat = [\"plan\", \"architect\", \"implement\", \"test\", \"review\", \"ship\"].join(\" → \");\n const loopStart = 13 + flat.indexOf(\"implement\"); // col under \"implement\"\n const loopEnd = 13 + flat.indexOf(\"review\") + 5; // col under last char of \"review\"\n const inner = loopEnd - loopStart - 1;\n const lp = Math.floor((inner - 19) / 2); // 19 = visible width of \" ↺ until it passes \"\n const rp = inner - 19 - lp;\n const dash = (n: number): string => chalk.hex(STEEL_DEEP)(\"─\".repeat(Math.max(0, n)));\n console.log(\n \" \".repeat(loopStart) +\n chalk.hex(STEEL_DEEP)(\"╰\") +\n dash(lp) +\n chalk.hex(STEEL)(\" ↺ \") +\n chalk.hex(STEEL_DIM)(\"until it passes\") +\n \" \" +\n dash(rp) +\n chalk.hex(STEEL_DEEP)(\"╯\"),\n );\n console.log();\n}\n\nexport function printSuccess(message: string): void {\n console.log(`\\n${chalk.hex(STEEL)(\"✦\")} ${chalk.bold(message)}`);\n}\n\nexport function printStep(message: string): void {\n console.log(` ${chalk.hex(STEEL_DEEP)(\"▸\")} ${message}`);\n}\n\nexport function printDryRun(message: string): void {\n console.log(` ${chalk.yellow(\"◌\")} ${chalk.dim(message)}`);\n}\n\nexport function printSection(title: string): void {\n console.log(`\\n${chalk.hex(STEEL)(\"─\")} ${chalk.bold(title)}`);\n}\n\nexport function printInfo(message: string): void {\n console.log(` ${chalk.dim(message)}`);\n}\n\nexport function printNextStep(step: number, message: string): void {\n console.log(` ${chalk.hex(STEEL_DEEP)(`${step}.`)} ${message}`);\n}\n\nexport function printWarning(message: string): void {\n console.log(` ${chalk.yellow(\"⚠\")} ${chalk.yellow(message)}`);\n}\n","/**\n * `spell agents` subcommand group.\n *\n * Subcommands:\n * spell agents init — Interactive roster setup (naming strategy + role selection)\n * spell agents sync — Regenerate all client instruction files from canonical defs\n * spell agents list — Show current roster with assigned names and roles\n */\n\nimport { select, checkbox, Separator } from \"@inquirer/prompts\";\nimport { mkdir, writeFile, copyFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { stringify } from \"yaml\";\nimport type {\n AgentInitOptions,\n AgentRoster,\n AgentRosterEntry,\n AgentSyncOptions,\n NamingStrategy,\n AgentProfileId,\n} from \"../types.js\";\nimport { AGENT_ROLES } from \"../config/agent-roles.js\";\nimport {\n AGENT_PROFILE_CONFIGS,\n getAgentProfileConfig,\n} from \"../config/agent-profiles.js\";\nimport { applyNamingStrategy } from \"./naming.js\";\nimport {\n loadRoster,\n rosterExists,\n AgentConfigValidationError,\n AgentRosterNotFoundError,\n} from \"./agent-loader.js\";\nimport { syncAgents } from \"./agent-generator.js\";\nimport { printStep, printSuccess } from \"./banner.js\";\n\n// ─── spell agents init ────────────────────────────────────────────────────────\n\n/**\n * Interactive agent roster setup.\n *\n * 1. Prompts for agent profile (base | full | custom)\n * 2. Prompts for naming strategy (generic | random | custom)\n * 3. Applies naming and writes .arcane/agents.yaml + copies definition files\n */\nexport async function runAgentsInit(\n options: AgentInitOptions,\n targetDir: string,\n assetsDir: string,\n): Promise<void> {\n // Check for existing roster\n if (!options.force && (await rosterExists(targetDir))) {\n console.log(\n 'Agent roster already exists at .arcane/agents.yaml. ' +\n 'Run \"spell agents sync\" to regenerate outputs, or use --force to reinitialize.',\n );\n return;\n }\n\n console.log();\n\n // ── Step 1: Agent profile ────────────────────────────────────────────────\n let profileId: AgentProfileId = options.profile ?? \"full\";\n if (!options.profile) {\n const baseRoles = getAgentProfileConfig(\"base\").roles;\n const baseRoleNames = baseRoles.map((id) => {\n const role = AGENT_ROLES.find((r) => r.id === id);\n return role ? role.role : id;\n });\n const allCategories = [...new Set(AGENT_ROLES.map((r) => r.category))];\n\n profileId = (await select({\n message: \"Select an agent profile:\",\n choices: AGENT_PROFILE_CONFIGS.map((p) => ({\n value: p.id,\n name: `${p.id === \"base\" ? \"🎯\" : p.id === \"full\" ? \"🧙\" : \"🎨\"} ${p.displayName}`,\n description:\n p.id === \"base\"\n ? `\\n4 core roles: ${baseRoleNames.join(\", \")}`\n : p.id === \"full\"\n ? `\\nAll 12 roles across ${allCategories.join(\", \")}`\n : \"\\nPick individual roles from the full roster\",\n })),\n })) as AgentProfileId;\n }\n\n // Resolve role IDs for selected profile\n let selectedRoleIds: string[];\n if (profileId === \"custom\") {\n // Group roles by category with separators\n const categories = [...new Set(AGENT_ROLES.map((r) => r.category))];\n const choicesWithSeparators: Array<\n | { value: string; name: string; checked: boolean }\n | Separator\n > = [];\n for (const cat of categories) {\n choicesWithSeparators.push(new Separator(`── ${cat.charAt(0).toUpperCase() + cat.slice(1)} ──`));\n for (const r of AGENT_ROLES.filter((r) => r.category === cat)) {\n choicesWithSeparators.push({\n value: r.id,\n name: `${r.id} — ${r.role}`,\n checked: true,\n });\n }\n }\n\n console.log();\n selectedRoleIds = await checkbox({\n message: \"Select roles to install:\",\n choices: choicesWithSeparators,\n validate: (choices) =>\n choices.length > 0 ? true : \"Select at least one role\",\n });\n } else {\n selectedRoleIds = getAgentProfileConfig(profileId).roles;\n }\n\n // ── Step 2: Naming strategy ──────────────────────────────────────────────\n let namingStrategy: NamingStrategy = options.naming ?? \"arcanos\";\n if (!options.naming) {\n console.log();\n namingStrategy = (await select({\n message: \"Choose a naming strategy for your agents:\",\n choices: [\n {\n value: \"arcanos\" as NamingStrategy,\n name: \"🃏 Arcanos\",\n description: \"\\nPersona names: Kellar, Merlin, Lafayette, Lince, Prospero...\",\n },\n {\n value: \"generic\" as NamingStrategy,\n name: \"🏷️ Generic\",\n description: \"\\nRole-derived labels: Orchestrator, Architect, Developer, QA Lead...\",\n },\n {\n value: \"random\" as NamingStrategy,\n name: \"🎲 Random\",\n description: \"\\nCommon first names shuffled randomly: Blake, Morgan, Casey...\",\n },\n {\n value: \"custom\" as NamingStrategy,\n name: \"✏️ Custom\",\n description: \"\\nType a unique name for each role interactively\",\n },\n ],\n })) as NamingStrategy;\n }\n\n // ── Step 3: Apply naming ─────────────────────────────────────────────────\n printStep(\"Assigning names...\");\n const named = await applyNamingStrategy(namingStrategy, selectedRoleIds);\n\n // ── Step 4: Build roster ─────────────────────────────────────────────────\n const rosterEntries: AgentRosterEntry[] = named.map(({ definition, name, epithet }) => {\n // Orchestrator gets the \"main\" OpenClaw ID by convention\n const id = definition === \"orchestrator\" ? \"main\" : name.toLowerCase().replace(/\\s+/g, \"-\");\n return epithet ? { definition, name, id, epithet } : { definition, name, id };\n });\n\n const roster: AgentRoster = {\n schema_version: 2,\n naming_strategy: namingStrategy,\n agent_profile: profileId,\n openclaw: {\n enabled: true,\n workspace_root: \"~/.openclaw\",\n },\n roster: rosterEntries,\n };\n\n // ── Step 5: Write .arcane/agents.yaml ────────────────────────────────────\n const arcaneDir = join(targetDir, \".arcane\", \"agents\");\n if (!options.dryRun) {\n await mkdir(arcaneDir, { recursive: true });\n await writeFile(\n join(targetDir, \".arcane\", \"agents.yaml\"),\n stringify(roster),\n \"utf8\",\n );\n } else {\n console.log(\" [dry-run] Would write: .arcane/agents.yaml\");\n }\n\n // ── Step 6: Copy bundled definition files ─────────────────────────────────\n for (const roleId of selectedRoleIds) {\n const src = join(assetsDir, \"agents\", `${roleId}.yaml`);\n const dest = join(arcaneDir, `${roleId}.yaml`);\n if (!options.dryRun) {\n try {\n await copyFile(src, dest);\n } catch {\n console.warn(` ! Could not copy definition for \"${roleId}\" — skipping`);\n }\n } else {\n console.log(` [dry-run] Would copy: .arcane/agents/${roleId}.yaml`);\n }\n }\n\n if (options.dryRun) {\n console.log(\n `\\n [dry-run] Would initialize roster with ${selectedRoleIds.length} agents`,\n );\n return;\n }\n\n // ── Step 7: Auto-sync all clients ────────────────────────────────────────\n printStep(\"Syncing agent definitions to all clients...\");\n const { synced, skipped, hasUnresolvedRoles } = await syncAgents(\n targetDir,\n assetsDir,\n roster,\n { dryRun: false },\n );\n\n printSuccess(\"Agent roster initialized\");\n console.log(` 📋 Profile: ${profileId} · Naming: ${namingStrategy} · Agents: ${rosterEntries.length}`);\n console.log(` 🔄 Synced: ${synced.length} outputs (Copilot, Claude, Codex, OpenClaw)`);\n if (skipped.length > 0) {\n console.log(` ⚠️ Skipped: ${skipped.length} (${skipped.join(\", \")})`);\n }\n console.log();\n console.log(` 💡 Customize: edit .arcane/agents.yaml → spell agents sync`);\n console.log();\n if (hasUnresolvedRoles) {\n console.error(\n \" ✗ One or more rostered roles could not be resolved (see \\\"Skipped\\\" above) — \" +\n \"a malformed or missing agent template must not pass silently.\",\n );\n process.exitCode = 1;\n }\n}\n\n// ─── spell agents sync ────────────────────────────────────────────────────────\n\n/** Regenerates all client instruction files from the current roster + definitions. */\nexport async function runAgentsSync(\n options: AgentSyncOptions,\n targetDir: string,\n assetsDir: string,\n): Promise<void> {\n let roster: AgentRoster;\n try {\n roster = await loadRoster(targetDir);\n } catch (err) {\n if (\n err instanceof AgentRosterNotFoundError\n || err instanceof AgentConfigValidationError\n ) {\n console.error(err.message);\n process.exit(1);\n return;\n }\n throw err;\n }\n\n if (options.dryRun) {\n console.log(\"\\n [dry-run] Would sync agents from roster:\\n\");\n } else {\n console.log(\"\\n Syncing agents...\\n\");\n }\n\n const { synced, skipped, hasUnresolvedRoles } = await syncAgents(\n targetDir,\n assetsDir,\n roster,\n options,\n );\n\n if (options.dryRun) {\n console.log(`\\n [dry-run] ${synced.length} outputs would be generated`);\n return;\n }\n\n console.log(`\\n ✓ Synced ${synced.length} outputs`);\n for (const item of synced) {\n console.log(` + ${item}`);\n }\n if (skipped.length > 0) {\n console.log(`\\n ! Skipped ${skipped.length}:`);\n for (const item of skipped) {\n console.log(` - ${item}`);\n }\n }\n console.log();\n if (hasUnresolvedRoles) {\n console.error(\n \" ✗ One or more rostered roles could not be resolved (see \\\"Skipped\\\" above) — \" +\n \"a malformed or missing agent template must not pass silently.\",\n );\n process.exitCode = 1;\n }\n}\n\n// ─── spell agents list ────────────────────────────────────────────────────────\n\n/** Displays the current agent roster in a table. */\nexport async function runAgentsList(targetDir: string): Promise<void> {\n let roster: AgentRoster;\n try {\n roster = await loadRoster(targetDir);\n } catch (err) {\n if (\n err instanceof AgentRosterNotFoundError\n || err instanceof AgentConfigValidationError\n ) {\n console.error(err.message);\n process.exit(1);\n return;\n }\n throw err;\n }\n\n const nameWidth = Math.max(\n \"Name\".length,\n ...roster.roster.map((e) => (e.name ?? e.definition).length),\n );\n const defWidth = Math.max(\n \"Role ID\".length,\n ...roster.roster.map((e) => e.definition.length),\n );\n const idWidth = Math.max(\n \"OpenClaw ID\".length,\n ...roster.roster.map((e) => e.id.length),\n );\n\n const pad = (s: string, n: number) => s.padEnd(n);\n\n console.log(\n `\\n Profile: ${roster.agent_profile} | Naming: ${roster.naming_strategy} | Agents: ${roster.roster.length}\\n`,\n );\n console.log(\n ` ${pad(\"Name\", nameWidth)} ${pad(\"Role ID\", defWidth)} ${pad(\"OpenClaw ID\", idWidth)}`,\n );\n console.log(\n ` ${\"-\".repeat(nameWidth)} ${\"-\".repeat(defWidth)} ${\"-\".repeat(idWidth)}`,\n );\n for (const entry of roster.roster) {\n console.log(\n ` ${pad(entry.name ?? \"(unnamed)\", nameWidth)} ${pad(entry.definition, defWidth)} ${pad(entry.id, idWidth)}`,\n );\n }\n console.log();\n}\n","/**\n * Canonical agent role definitions.\n * Each entry maps to a YAML template file at src/assets/agents/{id}.yaml.\n * These are the 12 standard roles that ship with Arcane.\n */\n\nimport type { AgentCategory } from \"../types.js\";\n\nexport interface AgentRoleConfig {\n id: string;\n role: string;\n category: AgentCategory;\n}\n\nexport const AGENT_ROLES: AgentRoleConfig[] = [\n {\n id: \"orchestrator\",\n role: \"Product Operations Manager\",\n category: \"operations\",\n },\n {\n id: \"architecture-lead\",\n role: \"CTO / Architecture Lead\",\n category: \"engineering\",\n },\n {\n id: \"fullstack-dev\",\n role: \"Full-Stack Developer\",\n category: \"engineering\",\n },\n {\n id: \"qa-lead\",\n role: \"QA Lead\",\n category: \"quality\",\n },\n {\n id: \"devops\",\n role: \"DevOps / CI/CD Engineer\",\n category: \"engineering\",\n },\n {\n id: \"frontend-dev\",\n role: \"Frontend Developer\",\n category: \"engineering\",\n },\n {\n id: \"mobile-dev\",\n role: \"Mobile Developer\",\n category: \"engineering\",\n },\n {\n id: \"research-analyst\",\n role: \"Research & Backlog Analyst\",\n category: \"research\",\n },\n {\n id: \"marketing-strategist\",\n role: \"Marketing Strategist\",\n category: \"operations\",\n },\n {\n id: \"operations-comms\",\n role: \"Operations Communications\",\n category: \"operations\",\n },\n {\n id: \"collaborator\",\n role: \"External Collaboration Lead\",\n category: \"operations\",\n },\n {\n id: \"security-ops\",\n role: \"Security Operations\",\n category: \"quality\",\n },\n];\n\n/** Lookup by role ID. */\nexport function getAgentRole(id: string): AgentRoleConfig | undefined {\n return AGENT_ROLES.find((r) => r.id === id);\n}\n","/**\n * Agent profile configurations.\n * Controls which roles are included when running `spell agents init`.\n * Separate from src/config/profiles.ts (which governs governance/prompts components).\n */\n\nimport type { AgentProfileId } from \"../types.js\";\n\nexport interface AgentProfileConfig {\n id: AgentProfileId;\n displayName: string;\n description: string;\n /** Role IDs included in this profile. Empty means user selects interactively. */\n roles: string[];\n}\n\nexport const AGENT_PROFILE_CONFIGS: AgentProfileConfig[] = [\n {\n id: \"base\",\n displayName: \"Base\",\n description: \"Core team: orchestrator, architecture-lead, fullstack-dev, qa-lead\",\n roles: [\"orchestrator\", \"architecture-lead\", \"fullstack-dev\", \"qa-lead\"],\n },\n {\n id: \"full\",\n displayName: \"Full\",\n description: \"Complete roster — all 12 roles\",\n roles: [\n \"orchestrator\",\n \"architecture-lead\",\n \"fullstack-dev\",\n \"qa-lead\",\n \"devops\",\n \"frontend-dev\",\n \"mobile-dev\",\n \"research-analyst\",\n \"marketing-strategist\",\n \"operations-comms\",\n \"collaborator\",\n \"security-ops\",\n ],\n },\n {\n id: \"custom\",\n displayName: \"Custom\",\n description: \"Select roles interactively\",\n roles: [], // populated at runtime via checkbox prompt\n },\n];\n\n/** Lookup by profile ID. */\nexport function getAgentProfileConfig(id: AgentProfileId): AgentProfileConfig {\n const config = AGENT_PROFILE_CONFIGS.find((p) => p.id === id);\n if (!config) throw new Error(`Unknown agent profile: \"${id}\"`);\n return config;\n}\n","/**\n * Naming strategy logic for agent roster setup.\n *\n * Four strategies:\n * arcanos — the built-in persona roster (default): twelve legendary agents\n * generic — maps each role to a short, memorable generic label\n * random — assigns random common names from a curated pool\n * custom — prompts the user to type a name for each role\n */\n\nimport { input } from \"@inquirer/prompts\";\nimport type { NamingStrategy } from \"../types.js\";\nimport { getAgentRole } from \"../config/agent-roles.js\";\n\n// ─── Generic names ────────────────────────────────────────────────────────────\n\n/** Short, role-derived display names for the generic strategy. */\nconst GENERIC_NAME_MAP: Record<string, string> = {\n \"orchestrator\": \"Orchestrator\",\n \"architecture-lead\": \"Architect\",\n \"fullstack-dev\": \"Developer\",\n \"qa-lead\": \"QA Lead\",\n \"devops\": \"DevOps\",\n \"frontend-dev\": \"Frontend\",\n \"mobile-dev\": \"Mobile\",\n \"research-analyst\": \"Researcher\",\n \"marketing-strategist\": \"Marketer\",\n \"operations-comms\": \"Comms\",\n \"collaborator\": \"Collaborator\",\n \"security-ops\": \"Security\",\n};\n\n// ─── Arcanos preset names ─────────────────────────────────────────────────────\n\n/** Persona names from the Arcanos roster — twelve legendary agents. */\nconst ARCANOS_NAME_MAP: Record<string, string> = {\n \"orchestrator\": \"Kellar\",\n \"architecture-lead\": \"Merlin\",\n \"fullstack-dev\": \"Lafayette\",\n \"qa-lead\": \"Lince\",\n \"devops\": \"Prospero\",\n \"frontend-dev\": \"Adelaide\",\n \"mobile-dev\": \"Mercurio\",\n \"research-analyst\": \"Alexander\",\n \"marketing-strategist\": \"Circe\",\n \"operations-comms\": \"Bess\",\n \"collaborator\": \"Iris\",\n \"security-ops\": \"Custodio\",\n};\n\n/**\n * Arcanos epithets (naming-conventions.md's roster table) — bound to the\n * PERSONA NAME, not the role archetype: \"the Archmage\" belongs to Merlin,\n * not to \"architecture-lead\" itself. Deliberately not a field on the role\n * YAML (src/assets/agents/*.yaml), which is naming-strategy-agnostic and\n * reused by generic/random/custom naming — putting it there would force\n * Arcanos-flavored text onto strategies designed to be epithet-less (the\n * \"generic role labels\" option naming-conventions.md documents).\n */\nconst ARCANOS_EPITHET_MAP: Record<string, string> = {\n \"orchestrator\": \"the Maestro\",\n \"architecture-lead\": \"the Archmage\",\n \"fullstack-dev\": \"the Conjuror\",\n \"qa-lead\": \"the Unmasker\",\n \"devops\": \"the Stormcaller\",\n \"frontend-dev\": \"the Illusionist\",\n \"mobile-dev\": \"the Swift\",\n \"research-analyst\": \"the Man Who Knows\",\n \"marketing-strategist\": \"the Charmweaver\",\n \"operations-comms\": \"the Herald\",\n \"collaborator\": \"the Emissary\",\n \"security-ops\": \"the Warden\",\n};\n\n// ─── Random name pool ─────────────────────────────────────────────────────────\n\n/**\n * Curated pool of common single-word names.\n * Gender-neutral where possible to avoid unintentional character typecasting.\n */\nconst RANDOM_NAME_POOL: string[] = [\n \"Aiden\", \"Blake\", \"Casey\", \"Dana\", \"Ellis\", \"Finley\", \"Gray\", \"Harper\",\n \"Indigo\", \"Jordan\", \"Kai\", \"Lane\", \"Morgan\", \"Nova\", \"Owen\", \"Parker\",\n \"Quinn\", \"River\", \"Sage\", \"Taylor\", \"Uma\", \"Vale\", \"Wren\", \"Xander\",\n \"Yael\", \"Zara\", \"Avery\", \"Brett\", \"Charlie\", \"Devon\",\n];\n\n// ─── Strategy implementations ────────────────────────────────────────────────\n\nexport interface NamingResult {\n definition: string;\n name: string;\n /** Present only for the arcanos strategy — other strategies are deliberately epithet-less. */\n epithet?: string;\n}\n\n/** Assigns short generic labels derived from each role. */\nexport function applyGenericNames(roleIds: string[]): NamingResult[] {\n return roleIds.map((id) => ({\n definition: id,\n name: GENERIC_NAME_MAP[id] ?? id,\n }));\n}\n\n/** Assigns Arcanos persona names (Kellar, Merlin, Lafayette, etc.). */\nexport function applyArcanosNames(roleIds: string[]): NamingResult[] {\n return roleIds.map((id) => {\n const name = ARCANOS_NAME_MAP[id] ?? GENERIC_NAME_MAP[id] ?? id;\n const epithet = ARCANOS_NAME_MAP[id] ? ARCANOS_EPITHET_MAP[id] : undefined;\n return epithet ? { definition: id, name, epithet } : { definition: id, name };\n });\n}\n\n/**\n * Assigns random names from the pool, shuffled per call.\n * If more roles than pool entries, wraps around.\n */\nexport function applyRandomNames(roleIds: string[]): NamingResult[] {\n const shuffled = [...RANDOM_NAME_POOL].sort(() => Math.random() - 0.5);\n return roleIds.map((id, i) => ({\n definition: id,\n name: shuffled[i % shuffled.length]!,\n }));\n}\n\n/**\n * Prompts the user to type a name for each role interactively.\n * Defaults to the generic name to speed up entry.\n */\nexport async function promptCustomNames(roleIds: string[]): Promise<NamingResult[]> {\n const results: NamingResult[] = [];\n for (const id of roleIds) {\n const role = getAgentRole(id);\n const defaultName = GENERIC_NAME_MAP[id] ?? id;\n const name = await input({\n message: `Name for ${role?.role ?? id}:`,\n default: defaultName,\n validate: (v) =>\n v.trim().length > 0 ? true : \"Name cannot be empty\",\n });\n results.push({ definition: id, name: name.trim() });\n }\n return results;\n}\n\n/**\n * Applies the selected naming strategy to a list of role IDs.\n * Returns an array of definition→name pairs.\n */\nexport async function applyNamingStrategy(\n strategy: NamingStrategy,\n roleIds: string[],\n): Promise<NamingResult[]> {\n switch (strategy) {\n case \"arcanos\":\n return applyArcanosNames(roleIds);\n case \"generic\":\n return applyGenericNames(roleIds);\n case \"random\":\n return applyRandomNames(roleIds);\n case \"custom\":\n return promptCustomNames(roleIds);\n }\n}\n","/**\n * Agent definition and roster loader.\n *\n * Reads canonical agent YAML files from two locations:\n * - assetsDir/agents/ — bundled templates (used during init/add)\n * - targetDir/.arcane/agents/ — project's installed/customized definitions (used during sync)\n */\n\nimport { readFile, readdir, access } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { parse } from \"yaml\";\nimport type { AgentDefinition, AgentRoster } from \"../types.js\";\nimport {\n AgentConfigValidationError,\n validateAgentDefinition,\n validateAgentRoster,\n} from \"./agent-schema.js\";\n\nexport { AgentConfigValidationError } from \"./agent-schema.js\";\n\n// ─── Error types ──────────────────────────────────────────────────────────────\n\nexport class AgentDefinitionNotFoundError extends Error {\n constructor(id: string, searchDir: string) {\n super(\n `Agent definition \"${id}\" not found in \"${searchDir}\". ` +\n `Check that ${id}.yaml exists or run \"spell agents add ${id}\".`,\n );\n this.name = \"AgentDefinitionNotFoundError\";\n }\n}\n\nexport class AgentRosterNotFoundError extends Error {\n constructor() {\n super(\n 'No agent roster found at .arcane/agents.yaml. ' +\n 'Run \"spell agents init\" to create one.',\n );\n this.name = \"AgentRosterNotFoundError\";\n }\n}\n\nfunction parseYaml(content: string, source: string): unknown {\n try {\n return parse(content);\n } catch (err) {\n const detail = err instanceof Error ? err.message : \"unknown YAML parse error\";\n throw new AgentConfigValidationError(source, [`malformed YAML: ${detail}`]);\n }\n}\n\n// ─── Definition loaders ───────────────────────────────────────────────────────\n\n/**\n * Loads a single agent definition from a directory.\n * Used by `spell agents sync` (reads from .arcane/agents/).\n */\nexport async function loadAgentDefinition(\n agentsDir: string,\n id: string,\n): Promise<AgentDefinition> {\n const filePath = join(agentsDir, `${id}.yaml`);\n let content: string;\n try {\n content = await readFile(filePath, \"utf8\");\n } catch {\n throw new AgentDefinitionNotFoundError(id, agentsDir);\n }\n return validateAgentDefinition(parseYaml(content, filePath), filePath);\n}\n\n/**\n * Loads all agent definition files from a directory.\n * Skips non-YAML files and the agents.yaml roster file.\n */\nexport async function loadAllAgentDefinitions(\n agentsDir: string,\n): Promise<AgentDefinition[]> {\n let entries: string[];\n try {\n entries = await readdir(agentsDir);\n } catch {\n return [];\n }\n\n const definitions: AgentDefinition[] = [];\n for (const file of entries) {\n if (!file.endsWith(\".yaml\") || file === \"agents.yaml\") continue;\n const filePath = join(agentsDir, file);\n const content = await readFile(filePath, \"utf8\");\n definitions.push(validateAgentDefinition(parseYaml(content, filePath), filePath));\n }\n return definitions;\n}\n\n// ─── Roster loaders ───────────────────────────────────────────────────────────\n\n/**\n * Loads the agent roster from .arcane/agents.yaml in the target directory.\n * Throws AgentRosterNotFoundError if not initialized.\n */\nexport async function loadRoster(targetDir: string): Promise<AgentRoster> {\n const rosterPath = join(targetDir, \".arcane\", \"agents.yaml\");\n let content: string;\n try {\n content = await readFile(rosterPath, \"utf8\");\n } catch {\n throw new AgentRosterNotFoundError();\n }\n return validateAgentRoster(parseYaml(content, rosterPath), rosterPath);\n}\n\n/**\n * Returns true if a roster file exists in the target directory.\n */\nexport async function rosterExists(targetDir: string): Promise<boolean> {\n try {\n await access(join(targetDir, \".arcane\", \"agents.yaml\"));\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Returns the path to the project's agent definitions directory.\n */\nexport function projectAgentsDir(targetDir: string): string {\n return join(targetDir, \".arcane\", \"agents\");\n}\n","import type { AgentDefinition, AgentRoster } from \"../types.js\";\n\nconst CURRENT_ROSTER_SCHEMA_VERSION = 2;\nconst POWER_LEVELS = new Set([\n \"Spectator\",\n \"Apprentice\",\n \"Wizard\",\n \"Sorcerer\",\n \"Magus\",\n \"Archmage\",\n]);\nconst AGENT_CATEGORIES = new Set([\n \"engineering\",\n \"operations\",\n \"quality\",\n \"research\",\n]);\nconst NAMING_STRATEGIES = new Set([\"arcanos\", \"generic\", \"random\", \"custom\"]);\nconst AGENT_PROFILES = new Set([\"base\", \"full\", \"custom\"]);\n\ntype RecordValue = Record<string, unknown>;\n\nexport class AgentConfigValidationError extends Error {\n constructor(source: string, issues: string[]) {\n super(`Invalid agent configuration in ${source}:\\n- ${issues.join(\"\\n- \")}`);\n this.name = \"AgentConfigValidationError\";\n }\n}\n\nfunction isRecord(value: unknown): value is RecordValue {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction requireRecord(\n value: unknown,\n path: string,\n issues: string[],\n): RecordValue | undefined {\n if (!isRecord(value)) {\n issues.push(`${path} must be an object`);\n return undefined;\n }\n return value;\n}\n\nfunction requireString(value: unknown, path: string, issues: string[]) {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n issues.push(`${path} must be a non-empty string`);\n }\n}\n\nfunction requireBoolean(value: unknown, path: string, issues: string[]) {\n if (typeof value !== \"boolean\") issues.push(`${path} must be a boolean`);\n}\n\nfunction requireStringArray(value: unknown, path: string, issues: string[]) {\n if (!Array.isArray(value) || value.some((entry) => typeof entry !== \"string\")) {\n issues.push(`${path} must be an array of strings`);\n }\n}\n\nfunction requireEnum(\n value: unknown,\n allowed: Set<string>,\n path: string,\n issues: string[],\n) {\n if (typeof value !== \"string\" || !allowed.has(value)) {\n issues.push(`${path} must be one of: ${[...allowed].join(\", \")}`);\n }\n}\n\nfunction validateOptionalClient(\n clients: RecordValue,\n key: string,\n property: string,\n expected: \"string\" | \"boolean\",\n issues: string[],\n) {\n if (clients[key] === undefined) return;\n const client = requireRecord(clients[key], `clients.${key}`, issues);\n if (!client) return;\n if (expected === \"string\") {\n requireString(client[property], `clients.${key}.${property}`, issues);\n } else {\n requireBoolean(client[property], `clients.${key}.${property}`, issues);\n }\n}\n\nexport function validateAgentDefinition(\n value: unknown,\n source: string,\n): AgentDefinition {\n const issues: string[] = [];\n const definition = requireRecord(value, \"definition\", issues);\n if (!definition) throw new AgentConfigValidationError(source, issues);\n\n requireString(definition.id, \"id\", issues);\n requireString(definition.role, \"role\", issues);\n requireEnum(definition.category, AGENT_CATEGORIES, \"category\", issues);\n\n const persona = requireRecord(definition.persona, \"persona\", issues);\n if (persona) {\n requireString(persona.description, \"persona.description\", issues);\n requireStringArray(persona.behavioral_rules, \"persona.behavioral_rules\", issues);\n for (const key of [\"personality\", \"voice\", \"visual_description\"] as const) {\n if (persona[key] !== undefined) requireString(persona[key], `persona.${key}`, issues);\n }\n if (persona.catchphrases !== undefined) {\n requireStringArray(persona.catchphrases, \"persona.catchphrases\", issues);\n }\n }\n\n const model = requireRecord(definition.model, \"model\", issues);\n if (model) {\n requireString(model.primary, \"model.primary\", issues);\n requireStringArray(model.fallback, \"model.fallback\", issues);\n }\n\n const tools = requireRecord(definition.tools, \"tools\", issues);\n if (tools) {\n requireStringArray(tools.allowed, \"tools.allowed\", issues);\n requireStringArray(tools.denied, \"tools.denied\", issues);\n }\n\n const autonomy = requireRecord(definition.autonomy, \"autonomy\", issues);\n if (autonomy) {\n requireEnum(\n autonomy.default_power_level,\n POWER_LEVELS,\n \"autonomy.default_power_level\",\n issues,\n );\n requireBoolean(autonomy.exec_allowed, \"autonomy.exec_allowed\", issues);\n }\n\n const spawn = requireRecord(definition.spawn, \"spawn\", issues);\n if (spawn) {\n requireBoolean(spawn.can_spawn, \"spawn.can_spawn\", issues);\n requireStringArray(spawn.spawnable_by, \"spawn.spawnable_by\", issues);\n }\n\n const clients = requireRecord(definition.clients, \"clients\", issues);\n if (clients) {\n validateOptionalClient(clients, \"openclaw\", \"workspace_prefix\", \"string\", issues);\n validateOptionalClient(clients, \"copilot\", \"agent_file\", \"boolean\", issues);\n validateOptionalClient(clients, \"claude\", \"include_in_instructions\", \"boolean\", issues);\n validateOptionalClient(clients, \"codex\", \"include_in_agents_md\", \"boolean\", issues);\n }\n\n if (issues.length > 0) throw new AgentConfigValidationError(source, issues);\n return definition as unknown as AgentDefinition;\n}\n\nexport function validateAgentRoster(value: unknown, source: string): AgentRoster {\n const issues: string[] = [];\n const parsed = requireRecord(value, \"roster\", issues);\n if (!parsed) throw new AgentConfigValidationError(source, issues);\n\n const version = parsed.schema_version;\n if (!Number.isInteger(version)) {\n throw new AgentConfigValidationError(source, [\n \"schema_version must be an integer; run \\\"spell agents init\\\" with a compatible Arcane CLI\",\n ]);\n }\n if ((version as number) > CURRENT_ROSTER_SCHEMA_VERSION) {\n throw new AgentConfigValidationError(source, [\n `schema_version ${version} is newer than supported version ${CURRENT_ROSTER_SCHEMA_VERSION}; upgrade Arcane before reading this roster`,\n ]);\n }\n if ((version as number) < 1) {\n throw new AgentConfigValidationError(source, [\n `schema_version ${version} is unsupported; supported versions are 1 and ${CURRENT_ROSTER_SCHEMA_VERSION}`,\n ]);\n }\n\n const roster = version === 1\n ? { ...parsed, schema_version: CURRENT_ROSTER_SCHEMA_VERSION }\n : parsed;\n requireEnum(roster.naming_strategy, NAMING_STRATEGIES, \"naming_strategy\", issues);\n requireEnum(roster.agent_profile, AGENT_PROFILES, \"agent_profile\", issues);\n\n const openclaw = requireRecord(roster.openclaw, \"openclaw\", issues);\n if (openclaw) {\n requireBoolean(openclaw.enabled, \"openclaw.enabled\", issues);\n requireString(openclaw.workspace_root, \"openclaw.workspace_root\", issues);\n }\n\n if (!Array.isArray(roster.roster)) {\n issues.push(\"roster must be an array\");\n } else {\n roster.roster.forEach((entry, index) => {\n const item = requireRecord(entry, `roster[${index}]`, issues);\n if (!item) return;\n requireString(item.definition, `roster[${index}].definition`, issues);\n if (item.name !== null) requireString(item.name, `roster[${index}].name`, issues);\n requireString(item.id, `roster[${index}].id`, issues);\n if (item.epithet !== undefined) requireString(item.epithet, `roster[${index}].epithet`, issues);\n });\n }\n\n if (issues.length > 0) throw new AgentConfigValidationError(source, issues);\n return roster as unknown as AgentRoster;\n}","/**\n * Agent generator — multi-client fan-out engine.\n *\n * Reads canonical agent definitions and an agent roster, then generates\n * client-specific instruction files for each enabled AI client:\n * - OpenClaw: IDENTITY.md, SOUL.md, TOOLS.md per agent workspace\n * - Copilot: .github/agents/{name}.agent.md per agent\n * - Claude: CLAUDE.md ← arcane marker merge\n * - Codex: AGENTS.md ← arcane marker merge\n *\n * Each L1 merge (CLAUDE.md, AGENTS.md, .github/copilot-instructions.md) also\n * injects a static intent→spell routing table ahead of the roster table,\n * independent of whether any roster entries resolved — the routing guidance\n * (\"if a spell exists for this workflow, invoke it\") applies with or without\n * agent personas configured.\n *\n * NOTE: openclaw.json is NEVER modified directly — a patch file is generated\n * at .arcane/generated/openclaw-roster.json for the user to apply manually.\n */\n\nimport { writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type {\n AgentDefinition,\n AgentRoster,\n AgentRosterEntry,\n AgentSyncOptions,\n} from \"../types.js\";\nimport { mergeIntoFile } from \"./merger.js\";\nimport { loadAgentDefinition, projectAgentsDir } from \"./agent-loader.js\";\n\n// ─── Resolved entry (definition + roster entry joined) ───────────────────────\n\ninterface ResolvedEntry {\n entry: AgentRosterEntry;\n def: AgentDefinition;\n displayName: string;\n}\n\n// ─── Content renderers ───────────────────────────────────────────────────────\n\nfunction renderIdentity(def: AgentDefinition, name: string): string {\n const mottosLine =\n def.persona.catchphrases && def.persona.catchphrases.length > 0\n ? `\\n## Mottos\\n\\n${def.persona.catchphrases.map((c) => `- \"${c}\"`).join(\"\\n\")}\\n`\n : \"\";\n return `# ${name} — ${def.role}\n\n## Role\n\n${def.persona.description.trim()}\n\n## Category\n\n${def.category}\n${mottosLine}`;\n}\n\nfunction renderSoul(def: AgentDefinition, name: string): string {\n const rules = def.persona.behavioral_rules.map((r) => `- ${r}`).join(\"\\n\");\n return `# ${name} — Behavioral Directives\n\n## Rules\n\n${rules}\n\n## Autonomy\n\n- **Default Power Level:** ${def.autonomy.default_power_level}\n- **Exec Allowed:** ${def.autonomy.exec_allowed ? \"Yes\" : \"No\"}\n`;\n}\n\nfunction renderTools(def: AgentDefinition, name: string): string {\n const allowed = def.tools.allowed.map((t) => `- \\`${t}\\``).join(\"\\n\");\n const denied = def.tools.denied.map((t) => `- \\`${t}\\``).join(\"\\n\");\n return `# ${name} — Tool Capabilities\n\n## Allowed\n\n${allowed}\n\n## Denied\n\n${denied}\n`;\n}\n\nexport function renderCopilotAgent(def: AgentDefinition, name: string): string {\n const firstLine = def.persona.description.split(\"\\n\")[0]?.trim() ?? def.role;\n const rules = def.persona.behavioral_rules.map((r) => `- ${r}`).join(\"\\n\");\n const personalityBlock = def.persona.personality\n ? `\\n## Personality\\n\\n${def.persona.personality.trim()}\\n`\n : \"\";\n const voiceBlock = def.persona.voice\n ? `\\n## Voice\\n\\n${def.persona.voice.trim()}\\n`\n : \"\";\n const mottosBlock =\n def.persona.catchphrases && def.persona.catchphrases.length > 0\n ? `\\n## Mottos\\n\\n${def.persona.catchphrases.map((c) => `- \"${c}\"`).join(\"\\n\")}\\n`\n : \"\";\n return `---\nname: ${name}\ndescription: ${def.role} — ${firstLine}\n---\n${mottosBlock}\n## Role\n\n${def.persona.description.trim()}\n${personalityBlock}${voiceBlock}\n## Behavioral Rules\n\n${rules}\n\n## Tools\n\n**Allowed:** ${def.tools.allowed.join(\", \")}\n**Denied:** ${def.tools.denied.join(\", \")}\n`;\n}\n\nfunction renderSpellRoutingSection(): string {\n return `## Spell Routing\n\n| When you're about to... | Invoke |\n|---|---|\n| Commit work | \\`spell-commit-work\\` |\n| Open a session | \\`spell-open-session\\` |\n| Close a session | \\`spell-close-session\\` |\n| Open a pull request | \\`spell-create-pull-request\\` |\n| Ship a feature end-to-end | \\`spell-full-cycle\\` |\n| Fix a bug | \\`spell-bug\\` |\n| Review code or a PR | \\`spell-review\\` |\n\nIf a spell exists for the workflow you are about to perform, invoke it — do not improvise the workflow from general knowledge, even when the user doesn't name the spell.\n`;\n}\n\nfunction renderAgentRosterSection(entries: ResolvedEntry[]): string {\n const rows = entries\n .map(({ def, displayName }) =>\n `| **${displayName}** | ${def.role} | ${def.category} |`,\n )\n .join(\"\\n\");\n\n return `## Agent Roster\n\n| Agent | Role | Category |\n|-------|------|----------|\n${rows}\n`;\n}\n\n// ─── Sync result ─────────────────────────────────────────────────────────────\n\nexport interface SyncResult {\n synced: string[];\n skipped: string[];\n /**\n * True when a rostered role's definition could not be loaded from either\n * the project or bundled source (the mobile-dev bug class: a malformed\n * template silently dropped from the roster with a zero exit code).\n * Distinct from an openclaw-workspace write failure, which is an I/O\n * problem, not a role-resolution failure, and does not set this.\n */\n hasUnresolvedRoles: boolean;\n}\n\n// ─── Main sync function ───────────────────────────────────────────────────────\n\n/**\n * Generates all client-specific output files from the agent roster and definitions.\n *\n * @param targetDir Root of the consuming repo (where .arcane/ lives)\n * @param assetsDir Path to bundled assets (used as fallback for definitions not yet in project)\n * @param roster Parsed agent roster (from .arcane/agents.yaml)\n * @param options Sync options (dry-run, client filters)\n */\nexport async function syncAgents(\n targetDir: string,\n assetsDir: string,\n roster: AgentRoster,\n options: AgentSyncOptions = {},\n): Promise<SyncResult> {\n const synced: string[] = [];\n const skipped: string[] = [];\n let hasUnresolvedRoles = false;\n\n // ── Load all definitions ──────────────────────────────────────────────────\n const projectDefs = projectAgentsDir(targetDir);\n const bundledDefs = join(assetsDir, \"agents\");\n\n const resolved: ResolvedEntry[] = [];\n for (const entry of roster.roster) {\n let def: AgentDefinition;\n try {\n // Prefer the project's customized version\n def = await loadAgentDefinition(projectDefs, entry.definition);\n } catch {\n try {\n // Fall back to bundled template\n def = await loadAgentDefinition(bundledDefs, entry.definition);\n } catch {\n skipped.push(`${entry.definition} (definition not found)`);\n hasUnresolvedRoles = true;\n continue;\n }\n }\n resolved.push({\n entry,\n def,\n displayName: entry.name ?? entry.definition,\n });\n }\n\n // ── OpenClaw output ──────────────────────────────────────────────────────\n if (roster.openclaw.enabled && options.openclaw !== false) {\n const openclawRoot = roster.openclaw.workspace_root.replace(\n /^~/,\n homedir(),\n );\n\n for (const { entry, def, displayName } of resolved) {\n if (!def.clients.openclaw) continue;\n\n const workspaceName =\n entry.id === \"main\" ? \"workspace\" : `workspace-${entry.id}`;\n const workspaceDir = join(openclawRoot, workspaceName);\n\n try {\n if (!options.dryRun) {\n await mkdir(workspaceDir, { recursive: true });\n await writeFile(\n join(workspaceDir, \"IDENTITY.md\"),\n renderIdentity(def, displayName),\n \"utf8\",\n );\n await writeFile(\n join(workspaceDir, \"SOUL.md\"),\n renderSoul(def, displayName),\n \"utf8\",\n );\n await writeFile(\n join(workspaceDir, \"TOOLS.md\"),\n renderTools(def, displayName),\n \"utf8\",\n );\n } else {\n console.log(` [dry-run] Would write: ${workspaceDir}/IDENTITY.md`);\n console.log(` [dry-run] Would write: ${workspaceDir}/SOUL.md`);\n console.log(` [dry-run] Would write: ${workspaceDir}/TOOLS.md`);\n }\n synced.push(`openclaw:${entry.id}:IDENTITY+SOUL+TOOLS`);\n } catch {\n skipped.push(`openclaw:${entry.id} (workspace not accessible)`);\n }\n }\n\n // Generate openclaw-roster.json patch — never modifies openclaw.json directly\n const patch = {\n $comment:\n \"Apply this to your openclaw.json agents section. \" +\n \"Do not edit manually — regenerated by `spell agents sync`.\",\n agents: resolved.map(({ entry, def }) => ({\n id: entry.id,\n identity: {\n name: entry.name ?? entry.definition,\n ...(entry.epithet ? { epithet: entry.epithet } : {}),\n role: def.role,\n },\n })),\n };\n\n const generatedDir = join(targetDir, \".arcane\", \"generated\");\n if (!options.dryRun) {\n await mkdir(generatedDir, { recursive: true });\n await writeFile(\n join(generatedDir, \"openclaw-roster.json\"),\n JSON.stringify(patch, null, 2) + \"\\n\",\n \"utf8\",\n );\n } else {\n console.log(\n \" [dry-run] Would write: .arcane/generated/openclaw-roster.json\",\n );\n }\n synced.push(\"openclaw-roster.json\");\n }\n\n // ── Copilot output ───────────────────────────────────────────────────────\n if (options.copilot !== false) {\n const agentsDir = join(targetDir, \".github\", \"agents\");\n\n if (!options.dryRun) {\n await mkdir(agentsDir, { recursive: true });\n }\n\n for (const { def, displayName } of resolved) {\n if (!def.clients.copilot?.agent_file) continue;\n // Slugify: lowercase, spaces → hyphens (e.g. \"QA Lead\" → \"qa-lead.agent.md\")\n const slug = displayName.toLowerCase().replace(/\\s+/g, \"-\");\n const fileName = `${slug}.agent.md`;\n if (!options.dryRun) {\n await writeFile(\n join(agentsDir, fileName),\n renderCopilotAgent(def, displayName),\n \"utf8\",\n );\n } else {\n console.log(` [dry-run] Would write: .github/agents/${fileName}`);\n }\n synced.push(`.github/agents/${fileName}`);\n }\n\n // Merge spell routing + roster into copilot-instructions.md\n const copilotSection = `${renderSpellRoutingSection()}\\n${renderAgentRosterSection(resolved)}`;\n const copilotMerged = await mergeIntoFile(\n targetDir,\n \".github/copilot-instructions.md\",\n copilotSection,\n { force: true, dryRun: options.dryRun },\n );\n if (copilotMerged)\n synced.push(\".github/copilot-instructions.md (agents section)\");\n }\n\n // ── Claude output ────────────────────────────────────────────────────────\n if (options.claude !== false) {\n const claudeSection = `${renderSpellRoutingSection()}\\n${renderAgentRosterSection(resolved)}`;\n const claudeMerged = await mergeIntoFile(\n targetDir,\n \"CLAUDE.md\",\n claudeSection,\n { force: true, dryRun: options.dryRun },\n );\n if (claudeMerged) synced.push(\"CLAUDE.md (agents section)\");\n }\n\n // ── Codex output ─────────────────────────────────────────────────────────\n if (options.codex !== false) {\n const codexSection = `${renderSpellRoutingSection()}\\n${renderAgentRosterSection(resolved)}`;\n const codexMerged = await mergeIntoFile(\n targetDir,\n \"AGENTS.md\",\n codexSection,\n { force: true, dryRun: options.dryRun },\n );\n if (codexMerged) synced.push(\"AGENTS.md (agents section)\");\n }\n\n return { synced, skipped, hasUnresolvedRoles };\n}\n","import { readFile, writeFile, rm } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { validateTargetPath } from \"./copier.js\";\n\nexport const MARKER_START = \"<!-- arcane:start -->\";\nexport const MARKER_END = \"<!-- arcane:end -->\";\n\nexport class MalformedMarkersError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"MalformedMarkersError\";\n }\n}\n\n/**\n * Merges `content` into `targetDir/relativePath` using arcane marker comments.\n *\n * Behaviour:\n * - If both markers exist: replaces everything between them with `content`.\n * - If neither marker exists and `force` is true: appends markers + content.\n * - If neither marker exists and `force` is false: no-op, returns false.\n * - If only one marker is present: throws MalformedMarkersError.\n * - If file doesn't exist and `force` is true: creates the file with markers.\n * - If file doesn't exist and `force` is false: no-op, returns false.\n *\n * @returns true if the file was modified (or would be on dry-run), false if untouched.\n */\nexport async function mergeIntoFile(\n targetDir: string,\n relativePath: string,\n content: string,\n opts: { force?: boolean; dryRun?: boolean } = {},\n): Promise<boolean> {\n validateTargetPath(targetDir, relativePath);\n\n const destPath = path.resolve(targetDir, relativePath);\n\n let existing: string | null;\n try {\n existing = await readFile(destPath, \"utf8\");\n } catch (err) {\n const e = err as NodeJS.ErrnoException;\n if (e.code === \"ENOENT\") {\n existing = null;\n } else {\n throw err;\n }\n }\n\n if (existing === null) {\n // File doesn't exist — create with markers only if --force\n if (!opts.force) return false;\n const newContent = `${MARKER_START}\\n${content}\\n${MARKER_END}\\n`;\n if (!opts.dryRun) {\n await writeFile(destPath, newContent, \"utf8\");\n }\n return true;\n }\n\n const startIdx = existing.indexOf(MARKER_START);\n const endIdx = existing.indexOf(MARKER_END);\n\n const hasStart = startIdx !== -1;\n const hasEnd = endIdx !== -1;\n\n if (hasStart !== hasEnd) {\n throw new MalformedMarkersError(\n `File \"${relativePath}\" has mismatched arcane markers: ` +\n `${hasStart ? \"start found\" : \"start missing\"}, ` +\n `${hasEnd ? \"end found\" : \"end missing\"}.`,\n );\n }\n\n if (hasStart && hasEnd) {\n if (startIdx > endIdx) {\n throw new MalformedMarkersError(\n `File \"${relativePath}\" has arcane markers in wrong order (end before start).`,\n );\n }\n // Replace content between the markers (keeps marker lines themselves intact)\n const beforeMarker = existing.slice(0, startIdx + MARKER_START.length);\n const afterMarker = existing.slice(endIdx);\n const updated = `${beforeMarker}\\n${content}\\n${afterMarker}`;\n if (!opts.dryRun) {\n await writeFile(destPath, updated, \"utf8\");\n }\n return true;\n }\n\n // No markers — append only if --force\n if (!opts.force) return false;\n\n const appended =\n `${existing}${existing.endsWith(\"\\n\") ? \"\" : \"\\n\"}` +\n `${MARKER_START}\\n${content}\\n${MARKER_END}\\n`;\n if (!opts.dryRun) {\n await writeFile(destPath, appended, \"utf8\");\n }\n return true;\n}\n\n/**\n * Removes the `<!-- arcane:start -->…<!-- arcane:end -->` block from a file.\n *\n * - If the file has no markers, returns false (no-op).\n * - If the file is empty (or whitespace-only) after stripping, deletes the file.\n * - Otherwise rewrites the file without the marker block.\n *\n * @returns true if the file was modified or deleted, false if untouched.\n */\nexport async function stripMarkerSection(\n targetDir: string,\n relativePath: string,\n opts: { dryRun?: boolean } = {},\n): Promise<boolean> {\n const destPath = path.resolve(targetDir, relativePath);\n\n let existing: string;\n try {\n existing = await readFile(destPath, \"utf8\");\n } catch {\n return false; // file doesn't exist\n }\n\n const startIdx = existing.indexOf(MARKER_START);\n const endIdx = existing.indexOf(MARKER_END);\n if (startIdx === -1 || endIdx === -1) return false;\n\n const before = existing.slice(0, startIdx);\n const after = existing.slice(endIdx + MARKER_END.length);\n const stripped = (before + after).replace(/\\n{3,}/g, \"\\n\\n\").trim();\n\n if (!opts.dryRun) {\n if (stripped.length === 0) {\n await rm(destPath, { force: true });\n } else {\n await writeFile(destPath, stripped + \"\\n\", \"utf8\");\n }\n }\n return true;\n}\n","/**\n * Push safety (EF-09 / features/push-safety/PRD.md) and shared git-hooks\n * management (ARC-037 decision 2).\n *\n * Two layered controls for a repository whose history must not reach a remote:\n * a `pre-push` hook, and disabled push URLs. Neither is tamper-proof, and the\n * PRD is explicit that they are not meant to be — the threat modelled is an\n * *accidental* push (wrong remote, muscle memory, an unsupervised agent), not a\n * determined operator. Overclaiming here would be its own hazard.\n *\n * The two layers cover different bypasses, which is why both exist:\n * - `git push --no-verify` skips hooks entirely → the disabled URL catches it.\n * - `git push <url> main`, or a second remote, never consults the first\n * remote's URL → the hook catches it.\n * Only combining both bypasses in one command gets through, which is squarely\n * the determined-operator case this does not claim to stop.\n *\n * `installHook`/`isHookInstalled`/`removeHook` below are the generalized form\n * of this module's original pre-push-only machinery: any Arcane hook (pre-push,\n * and now the consumer-facing secrets-scan pre-commit hook) claims the SAME\n * shared `.arcane/hooks/` directory and `core.hooksPath` slot through the SAME\n * R7 collision-guarded path, rather than each hook re-implementing its own\n * claim-and-refuse logic. `installPrePushHook`/`isHookEnforced`/\n * `removePrePushHook` are now thin wrappers over the generic functions, kept\n * for every existing caller (doctor.ts, init.ts, unblock-push.ts, uninstall.ts)\n * and this file's own extensive test suite -- their behavior is unchanged.\n */\nimport { mkdir, readFile, writeFile, chmod, access, rm, readdir } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { join, resolve, dirname, basename } from \"node:path\";\nimport { fileExists } from \"./copier.js\";\nimport { runGit } from \"./git.js\";\n\n/**\n * Sentinel push URL. Not a real scheme, so git fails to resolve a helper.\n *\n * The scheme name carries the recovery instruction because it is the ONLY text\n * git shows the operator here. With both layers in place the URL fails first and\n * the hook never runs, so the hook's carefully worded message is never seen --\n * all git prints is `fatal: remote helper '<scheme>' aborted session`. Encoding\n * the fix in the scheme turns a dead end into an instruction.\n */\nexport const DISABLED_PUSH_URL = \"arcane-push-blocked-run-spell-unblock-push://this-repository\";\n\n/**\n * Marks that a remote had NO `pushurl` key before the block. Restoring must then\n * *remove* the key rather than write the fetch URL into it -- otherwise a later\n * `git remote set-url` would change fetch only and pushes would silently keep\n * going to the old location.\n *\n * A separate boolean key rather than a magic value stored in the URL slot: a\n * remote whose genuine push URL happened to equal that magic string would\n * otherwise be recorded as \"there was no key\" and lose its original on restore.\n */\nconst NO_PUSH_URL_MARKER = (remote: string): string => `remote.${remote}.arcaneHadNoPushUrl`;\n\n/** Directory Arcane points `core.hooksPath` at when it owns the hooks. */\nexport const ARCANE_HOOKS_DIR = \".arcane/hooks\";\n\n/**\n * Where a config value is set, as git itself reports it via `--show-scope`.\n * `worktree` matters here: a linked worktree can carry its own `config.worktree`\n * value that `--local` does not see, which an earlier local-vs-effective\n * heuristic misfiled as inherited-from-global.\n */\nexport type ConfigScope = \"local\" | \"worktree\" | \"global\" | \"system\" | \"command\" | \"unknown\";\n\nexport interface HooksPathInfo {\n /** The effective value git would use, respecting scope precedence. */\n value: string;\n /** Where it is set, as reported by git rather than inferred. */\n scope: ConfigScope;\n /** Git could not be asked. Callers must fail closed, never assume \"unset\". */\n unreadable?: boolean;\n}\n\nexport type HookInstallOutcome =\n | { status: \"installed\"; path: string }\n | { status: \"already-ours\" }\n | { status: \"refused-foreign-hooks-path\"; existing: string; scope: ConfigScope }\n | { status: \"refused-default-hooks\"; hooks: string[] }\n | { status: \"refused-unreadable-config\" };\n\n/**\n * Reads the EFFECTIVE `core.hooksPath` — not just the repository-local one.\n *\n * Reading only `--local` was a real defect: a `core.hooksPath` set at *global*\n * scope (the standard way organisations deploy pre-commit and corporate hook\n * managers) was invisible, so installation reported success while silently\n * disabling it, since a local value overrides a global one. That is precisely\n * the harm R7 exists to prevent.\n */\nexport async function readHooksPath(cwd: string): Promise<HooksPathInfo | undefined> {\n let raw: string;\n try {\n // `--show-scope` makes git report the scope rather than us inferring it by\n // comparing --local against the effective value. That inference was wrong\n // for a per-worktree `config.worktree` value, which --local does not see:\n // a genuinely repository-scoped setting was reported as inherited.\n const { stdout } = await runGit(cwd, [\"config\", \"--show-scope\", \"--get\", \"core.hooksPath\"]);\n raw = stdout.trim();\n } catch (error) {\n // ONLY exit 1 means \"not set anywhere\". Anything else -- an unparseable\n // config file, a permission error, an older git that rejects --show-scope --\n // means we could not determine whether someone else owns core.hooksPath.\n // Treating that as \"no claim\" made the R7 collision guard fail OPEN, which\n // is the one direction it must never fail: it would install over an org hook\n // manager it simply failed to see.\n if ((error as { code?: unknown }).code !== 1) {\n return { value: \"\", scope: \"unknown\", unreadable: true };\n }\n return undefined;\n }\n if (raw === \"\") return undefined;\n\n // Format is `<scope>\\t<value>`. The value may itself contain whitespace.\n const separator = raw.indexOf(\"\\t\");\n if (separator === -1) return { value: raw, scope: \"unknown\" };\n\n const scope = raw.slice(0, separator).trim();\n const value = raw.slice(separator + 1).trim();\n if (value === \"\") return undefined;\n\n const known: readonly ConfigScope[] = [\"local\", \"worktree\", \"global\", \"system\", \"command\"];\n const matched = known.find((candidate) => candidate === scope);\n return { value, scope: matched ?? \"unknown\" };\n}\n\n/**\n * True when two `core.hooksPath` values name the same directory.\n *\n * Exact string equality misreported every equivalent spelling git accepts --\n * `.arcane/hooks/`, `./.arcane/hooks`, `.arcane\\hooks`, and an absolute path all\n * point where our hook actually lives and all fire on a real push, yet compared\n * unequal. That direction fails safe (we refuse rather than clobber, and report\n * \"not enforced\" for something that is), but it means doctor contradicts what\n * git does, which is the exact class of confusion this module exists to remove.\n */\nfunction isArcaneHooksPath(root: string, value: string): boolean {\n // Case folding only where the filesystem actually folds case. On POSIX,\n // `.arcane/HOOKS` is a genuinely different directory, and treating it as ours\n // would make the R7 guard fail OPEN -- installing over someone else's hooks.\n // Backslash-to-slash folding is Windows-only for the same reason as case\n // folding: on POSIX a backslash is a legal filename character, so a directory\n // genuinely named `.arcane\\hooks` would normalise onto ours and the R7 guard\n // would fail OPEN -- installing over someone else's hooks.\n const windows = process.platform === \"win32\";\n const normalize = (p: string): string => {\n const separated = windows ? p.replace(/\\\\/g, \"/\") : p;\n // Relative values resolve against the repository ROOT, matching how git\n // itself resolves core.hooksPath -- against the worktree top level, never\n // against the process's working directory.\n const absolute = resolve(root, separated).replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n return windows ? absolute.toLowerCase() : absolute;\n };\n return normalize(value) === normalize(ARCANE_HOOKS_DIR);\n}\n\nconst PRE_PUSH_HOOK_BODY = `#!/bin/sh\n# Installed by Arcane because this repository's .arcane.json sets\n# push_policy: \"blocked\".\n#\n# This is deliberately not tamper-proof. It guards against an accidental push\n# -- the wrong remote, muscle memory, an unsupervised agent -- not against a\n# determined operator, who can always bypass it.\n#\n# To push legitimately, undo the policy first:\n#\n# spell unblock-push\n#\n# That command is interactive-only and asks you to confirm the repository by\n# name. Do not work around this hook by other means: the manifest would then\n# claim a protection this repository no longer has.\necho \"arcane: push blocked (push_policy: blocked). Run 'spell unblock-push' to undo.\" >&2\nexit 1\n`;\n\n/**\n * Human phrasing for a config scope.\n *\n * Worth its own function because \"globally\" was previously printed for anything\n * not local — including a system-scope value and a per-worktree one, neither of\n * which the operator would find where that message sends them.\n */\nexport function describeConfigScope(scope: ConfigScope): string {\n switch (scope) {\n case \"local\":\n return \"set for this repository\";\n case \"worktree\":\n return \"set for this worktree\";\n case \"global\":\n return \"set globally, for your user\";\n case \"system\":\n return \"set system-wide\";\n case \"command\":\n return \"set on the command line\";\n default:\n return \"scope unknown\";\n }\n}\n\n/**\n * The repository's top level — where the hook must live.\n *\n * `targetDir` is whatever directory the CLI was run from, and\n * `--is-inside-work-tree` is true from any subdirectory. Installing the hook\n * relative to `targetDir` while pointing repo-wide `core.hooksPath` at the\n * literal `.arcane/hooks` put the file somewhere git never looks: git resolves a\n * relative hooksPath against the *worktree top-level*, so a `spell init` run\n * inside a monorepo package disabled the repository's hooks entirely and\n * reported the block installed.\n */\nasync function repositoryRoot(cwd: string): Promise<string> {\n // Anchored on the COMMON git dir, so every linked worktree resolves to the\n // same directory as the main one. `--show-toplevel` would give each worktree\n // its own root, which is exactly the mistake being fixed: the hook lives in\n // one place, and `core.hooksPath` is shared config that must point there from\n // everywhere.\n try {\n const { stdout } = await runGit(cwd, [\n \"rev-parse\",\n \"--path-format=absolute\",\n \"--git-common-dir\",\n ]);\n const commonDir = stdout.trim();\n if (commonDir !== \"\") {\n // `<main>/.git` -> `<main>`. A bare repository has no working tree above\n // its git dir, so fall through to the worktree top level there.\n const parent = dirname(commonDir);\n if (basename(commonDir) === \".git\" && parent !== \"\") return parent;\n }\n } catch {\n // Older git without --path-format; fall back below.\n }\n try {\n const { stdout } = await runGit(cwd, [\"rev-parse\", \"--show-toplevel\"]);\n const top = stdout.trim();\n if (top !== \"\") return top;\n } catch {\n // Not a work tree (bare repo).\n }\n return cwd;\n}\n\n/**\n * Absolute path of a named hook file Arcane installs, resolved against the\n * repository top level rather than the working directory. Defaults to\n * \"pre-push\" -- this module's original and, until ARC-037, only hook -- so\n * every existing single-argument call site (this file's own internals and\n * this file's test suite) is unaffected by the generalization to other\n * hook names.\n */\nexport async function hookFilePath(cwd: string, hookName: string = \"pre-push\"): Promise<string> {\n return join(await repositoryRoot(cwd), ARCANE_HOOKS_DIR, hookName);\n}\n\n/**\n * The value written to `core.hooksPath`: an ABSOLUTE path.\n *\n * A relative value is re-resolved per worktree, and `core.hooksPath` lives in\n * shared local config while `.arcane/hooks/` is an untracked directory that\n * exists only in the checkout where it was created. So every linked worktree\n * inherited the config and had no hook file — the hook layer was simply absent\n * there, and `git push <url>` (the bypass only the hook covers) delivered the\n * full history in one ordinary command while `doctor` reported the repository\n * blocked. That is not an edge case here: Arcane's own methodology sends\n * concurrent sessions into linked worktrees.\n */\nasync function hooksPathValue(cwd: string): Promise<string> {\n return join(await repositoryRoot(cwd), ARCANE_HOOKS_DIR).replace(/\\\\/g, \"/\");\n}\n\n/**\n * Installs a named hook (its body written verbatim), refusing rather than\n * clobbering someone else's hook manager (R7).\n *\n * `core.hooksPath` is a single exclusive slot — Git reads one directory, never\n * several — so pointing it at Arcane's directory silently disables Husky,\n * Lefthook, pre-commit, or anything else already using it, at either local or\n * global scope. This repository's own `core.hooksPath` is `.husky/_`, running\n * lint, typecheck and the full test suite; a naive install would have turned\n * that off while appearing to add protection.\n *\n * Safe to call for a SECOND hook name once a first has already claimed the\n * directory: the collision guard above only refuses a FOREIGN path, and\n * Arcane's own already-claimed `.arcane/hooks/` is not foreign to a second\n * Arcane hook — the two hooks share the one slot rather than racing for it.\n */\nexport async function installHook(cwd: string, hookName: string, body: string): Promise<HookInstallOutcome> {\n const root = await repositoryRoot(cwd);\n const existing = await readHooksPath(cwd);\n\n if (existing?.unreadable === true) return { status: \"refused-unreadable-config\" };\n\n if (existing !== undefined && !isArcaneHooksPath(root, existing.value)) {\n return {\n status: \"refused-foreign-hooks-path\",\n existing: existing.value,\n scope: existing.scope,\n };\n }\n\n // The guard above only sees hook managers that announce themselves via\n // core.hooksPath. A repository using git's DEFAULT hooks directory has no\n // such key, so taking the slot silently disabled every hook it had -- the\n // exact harm R7 names, reached by the one route R7 wasn't looking at.\n // Only relevant on the FIRST claim: once existing is defined (ours), a\n // second hook joining the same directory displaces nothing new.\n if (existing === undefined) {\n const displaced = await defaultHooks(cwd);\n if (displaced.length > 0) {\n return { status: \"refused-default-hooks\", hooks: displaced };\n }\n }\n\n const hookPath = join(root, ARCANE_HOOKS_DIR, hookName);\n\n if (existing !== undefined && (await hookFileMatches(cwd, hookName, body))) {\n return { status: \"already-ours\" };\n }\n\n await mkdir(join(root, ARCANE_HOOKS_DIR), { recursive: true });\n await writeFile(hookPath, body, \"utf-8\");\n // Git requires the hook be executable on POSIX. chmod is a no-op for the\n // owner on Windows, which is fine -- Git for Windows does not check the bit.\n await chmod(hookPath, 0o755);\n await runGit(cwd, [\"config\", \"--local\", \"core.hooksPath\", await hooksPathValue(cwd)]);\n\n return { status: \"installed\", path: hookPath };\n}\n\n/** Installs the pre-push hook. Thin wrapper over {@link installHook}. */\nexport async function installPrePushHook(cwd: string): Promise<HookInstallOutcome> {\n return installHook(cwd, \"pre-push\", PRE_PUSH_HOOK_BODY);\n}\n\n/**\n * True only if the named hook is genuinely in force: the config points at\n * Arcane's directory AND that hook's file actually exists there with the\n * expected body.\n *\n * Checking the config alone is a declaration check, not an enforcement check —\n * deleting the hook file leaves the config intact and pushes succeed.\n */\nexport async function isHookInstalled(cwd: string, hookName: string, body: string): Promise<boolean> {\n const hooksPath = await readHooksPath(cwd);\n if (hooksPath === undefined || hooksPath.unreadable === true) return false;\n if (!isArcaneHooksPath(await repositoryRoot(cwd), hooksPath.value)) return false;\n return hookFileMatches(cwd, hookName, body);\n}\n\n/** Whether the pre-push hook is genuinely enforced. Thin wrapper over {@link isHookInstalled}. */\nexport async function isHookEnforced(cwd: string): Promise<boolean> {\n return isHookInstalled(cwd, \"pre-push\", PRE_PUSH_HOOK_BODY);\n}\n\n/**\n * Warns -- never blocks -- when the branch being pushed already has a\n * CLOSED or MERGED pull request (ARC-035 decision 4: the silent\n * stranded-commit mode that shipped as PR #63's incident is made loud by\n * extending this same hook slot, not by adding a second, competing one).\n *\n * Shares the \"pre-push\" hook name with {@link PRE_PUSH_HOOK_BODY}, so the\n * two are mutually exclusive per repository by construction -- a repo with\n * `push_policy: \"blocked\"` already refuses every push outright and has no\n * use for a warning about which PR it would have gone to; every other\n * tier (`guarded`, `open`, unset) gets this one instead. GitHub-only,\n * matching the ADR's own cited mechanism (`gh pr view --json state`); a\n * non-GitHub remote or a missing/unauthenticated `gh` is a silent no-op,\n * never a blocked or errored push.\n */\nconst CLOSED_PR_WARNING_HOOK_BODY = `#!/bin/sh\n# Installed by Arcane (ARC-035 decision 4): warns when the branch being\n# pushed already has a closed or merged PR, instead of accepting the push\n# into a void with no signal at all. Never blocks -- pushing to a branch\n# behind a closed PR is sometimes intentional.\nremote_url=\"$2\"\ncase \"$remote_url\" in\n *github.com*) ;;\n *) exit 0 ;;\nesac\ncommand -v gh >/dev/null 2>&1 || exit 0\nbranch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) || exit 0\nstate=$(gh pr view \"$branch\" --json state --jq .state 2>/dev/null) || exit 0\ncase \"$state\" in\n CLOSED|MERGED)\n echo \"arcane: WARNING -- the PR for branch '$branch' is already $state. Pushing anyway (not blocked).\" >&2\n ;;\nesac\nexit 0\n`;\n\n/** Installs the closed-PR warning hook. Thin wrapper over {@link installHook}. */\nexport async function installClosedPrWarningHook(cwd: string): Promise<HookInstallOutcome> {\n return installHook(cwd, \"pre-push\", CLOSED_PR_WARNING_HOOK_BODY);\n}\n\n/** True only if the closed-PR warning hook (not the blocking one) is the one currently installed. */\nexport async function isClosedPrWarningHookInstalled(cwd: string): Promise<boolean> {\n return isHookInstalled(cwd, \"pre-push\", CLOSED_PR_WARNING_HOOK_BODY);\n}\n\n/**\n * Real hooks living in git's default directory, which taking `core.hooksPath`\n * would silently switch off. `.sample` files are git's own inert templates.\n */\nasync function defaultHooks(cwd: string): Promise<string[]> {\n let hooksDir: string;\n try {\n const { stdout } = await runGit(cwd, [\"rev-parse\", \"--git-common-dir\"]);\n hooksDir = join(resolve(cwd, stdout.trim()), \"hooks\");\n } catch {\n return [];\n }\n try {\n return (await readdir(hooksDir)).filter((name) => !name.endsWith(\".sample\")).sort();\n } catch {\n return [];\n }\n}\n\n/**\n * True when a named hook file on disk is the one Arcane wrote, byte for byte.\n *\n * Existence alone is not enforcement: a zero-byte file, or one edited down to\n * `exit 0`, leaves the config pointing at a hook that blocks nothing while\n * `doctor` reports a pass. That is the same declaration-versus-enforcement\n * confusion review already found one level up, so the check compares content --\n * which `installHook` already needed for its `already-ours` decision.\n */\nasync function hookFileMatches(cwd: string, hookName: string, body: string): Promise<boolean> {\n const hookPath = await hookFilePath(cwd, hookName);\n if (!(await fileExists(hookPath))) return false;\n try {\n if ((await readFile(hookPath, \"utf-8\")) !== body) return false;\n } catch {\n return false;\n }\n\n // On POSIX, git silently skips a hook that is not executable, so the right\n // body in a non-executable file is still not enforcement. Git for Windows\n // does not consult the bit, and chmod there is largely advisory, so checking\n // it would produce a false \"not enforced\" for a hook that demonstrably fires.\n if (process.platform === \"win32\") return true;\n try {\n await access(hookPath, constants.X_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Removes a named hook's wiring. Leaves a foreign `core.hooksPath` untouched.\n *\n * Only unclaims `core.hooksPath` itself once NO Arcane-installed hook remains\n * in the shared directory: since ARC-037, `.arcane/hooks/` can hold more than\n * one hook (pre-push and pre-commit), and removing one must not silently\n * disable a sibling that still needs the same claimed path. Verified rather\n * than assumed by re-listing the directory after deleting -- not by counting\n * known hook names, which this module has no reason to enumerate.\n */\nexport async function removeHook(cwd: string, hookName: string): Promise<void> {\n const existing = await readHooksPath(cwd);\n if (existing === undefined || existing.unreadable === true) return;\n const root = await repositoryRoot(cwd);\n if (!isArcaneHooksPath(root, existing.value)) return;\n if (existing.scope !== \"local\" && existing.scope !== \"worktree\") return;\n\n // Remove the hook file first. Leaving it behind means a later `spell init`\n // that re-points core.hooksPath silently re-arms a block the operator\n // lifted.\n try {\n await rm(await hookFilePath(cwd, hookName), { force: true });\n } catch {\n // Non-fatal: if core.hooksPath ends up unset below, git no longer reads\n // this directory anyway.\n }\n\n const hooksDir = join(root, ARCANE_HOOKS_DIR);\n let remaining: string[] = [];\n try {\n remaining = await readdir(hooksDir);\n } catch {\n remaining = [];\n }\n if (remaining.length > 0) return; // a sibling hook still needs core.hooksPath\n\n // Unset at the scope the value actually lives in. `--local` cannot touch a\n // per-worktree `config.worktree` value, so accepting worktree scope above and\n // then unsetting locally left the hook fully in force while `unblock-push`\n // printed \"Push unblocked\".\n const scopeFlag = existing.scope === \"worktree\" ? \"--worktree\" : \"--local\";\n try {\n await runGit(cwd, [\"config\", scopeFlag, \"--unset\", \"core.hooksPath\"]);\n } catch {\n // Already unset; nothing to undo.\n }\n}\n\n/** Removes the pre-push hook's wiring. Thin wrapper over {@link removeHook}. */\nexport async function removePrePushHook(cwd: string): Promise<void> {\n return removeHook(cwd, \"pre-push\");\n}\n\n/** Every configured remote name, in git's own order. */\nexport async function listRemotes(cwd: string): Promise<string[]> {\n try {\n const { stdout } = await runGit(cwd, [\"remote\"]);\n return stdout\n .split(\"\\n\")\n .map((r) => r.trim())\n .filter(Boolean);\n } catch {\n return [];\n }\n}\n\n/**\n * Each remote with the URL(s) a push would actually reach.\n *\n * The `guarded` reminder exists to catch a *wrong remote*, and a bare name like\n * `origin` says nothing about where it points — which is the entire question.\n */\nexport async function pushTargets(cwd: string): Promise<{ remote: string; urls: string[] }[]> {\n const targets: { remote: string; urls: string[] }[] = [];\n for (const remote of await listRemotes(cwd)) {\n try {\n const { stdout } = await runGit(cwd, [\"remote\", \"get-url\", \"--push\", \"--all\", remote]);\n targets.push({\n remote,\n urls: stdout\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(Boolean),\n });\n } catch {\n targets.push({ remote, urls: [] });\n }\n }\n return targets;\n}\n\nexport type PushUrlStatus =\n | \"disabled\"\n | \"already-disabled\"\n | \"restored\"\n | \"nothing-recorded\"\n | \"failed\";\n\nexport interface PushUrlResult {\n remote: string;\n status: PushUrlStatus;\n /** Present only on \"failed\". Why this remote could not be covered. */\n reason?: string;\n}\n\n/**\n * Where a remote's original push URL is recorded.\n *\n * Deliberately a key *inside the remote's own section* rather than a flat\n * `arcane.originalPushUrl.<remote>`, which review broke three ways:\n *\n * - `my_remote` is a legal remote name but an illegal trailing config key\n * (that segment must be alphanumeric or `-`), so `git config` errored and\n * aborted the whole loop, leaving every later remote live while the operator\n * had been told the repository was blocked.\n * - Trailing key segments are case-INSENSITIVE, so remotes `origin` and\n * `Origin` collided on one key: one original was lost and restore pointed a\n * remote at the other's URL -- the wrong-remote push this feature exists to\n * prevent.\n * - `git remote rename` left the flat key orphaned, so restore silently found\n * nothing while `unblock-push` still reported success.\n *\n * A `remote.<name>.*` subsection has none of those problems: git accepts any\n * legal remote name there, subsection names ARE case-sensitive, and `git remote\n * rename` moves the whole section including keys it has never heard of. All\n * three verified directly against git 2.53 before this was written.\n */\nfunction originalPushUrlKey(remote: string): string {\n return `remote.${remote}.arcaneOriginalPushUrl`;\n}\n\n/** Reads every value of a possibly-multivalued local config key. */\nasync function readLocalAll(cwd: string, key: string): Promise<string[]> {\n try {\n const { stdout } = await runGit(cwd, [\"config\", \"--local\", \"--get-all\", key]);\n return stdout\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(Boolean);\n } catch {\n // Exit 1 == key absent.\n return [];\n }\n}\n\n/**\n * Every value of a multivalued key, WITH the scope each came from.\n *\n * `remote.<name>.pushurl` is multivalued and git collects values across system,\n * global and local scope. Reading only `--local` was a silent hole: a pushurl\n * configured globally stayed invisible, a local `--replace-all` *appended* the\n * sentinel instead of replacing the live URL, and because the global value sorts\n * first git delivered the push to it and only then failed on the sentinel. The\n * exit code was 128 and the history was already gone -- with `doctor` reporting\n * the repository fully covered.\n */\nasync function readScopedAll(cwd: string, key: string): Promise<{ scope: string; value: string }[]> {\n let stdout: string;\n try {\n ({ stdout } = await runGit(cwd, [\"config\", \"--show-scope\", \"--get-all\", key]));\n } catch {\n return [];\n }\n return stdout\n .split(\"\\n\")\n .filter((line) => line !== \"\")\n .map((line) => {\n // `<scope>\\t<value>`; split BEFORE trimming. Trimming first ate the\n // separator tab on an empty-valued entry (`global\\t`), which then parsed\n // as `{scope: \"unknown\", value: \"global\"}` and produced a remedy telling\n // the operator to run `git config --unknown`, which is not a command.\n const separator = line.indexOf(\"\\t\");\n if (separator === -1) return { scope: \"unknown\", value: line.trim() };\n return { scope: line.slice(0, separator).trim(), value: line.slice(separator + 1).trim() };\n });\n}\n\n/** Push URLs git would actually use for a remote, across every config scope. */\nasync function effectivePushUrls(cwd: string, remote: string): Promise<string[]> {\n const scoped = await readScopedAll(cwd, `remote.${remote}.pushurl`);\n return scoped.map((entry) => entry.value);\n}\n\n/**\n * Points every remote's PUSH url at a sentinel, so `git push` fails at the\n * transport layer. Fetch is unaffected: fetch URLs are left alone, so a blocked\n * repository can still pull.\n *\n * Applies to ALL remotes, not just `origin` — a repository commonly has an\n * `upstream` or `backup` too, and protecting only one of them protects nothing\n * in particular.\n *\n * Each original is recorded in `arcane.originalPushUrl.<remote>` so\n * `spell unblock-push` restores exactly what was there rather than guessing\n * from the fetch URL, which is legitimately allowed to differ.\n */\nexport async function disablePushUrls(cwd: string): Promise<PushUrlResult[]> {\n const results: PushUrlResult[] = [];\n for (const remote of await listRemotes(cwd)) {\n // One remote must never take the others down with it. The previous loop let\n // a single `git config` error propagate, so an oddly-named remote left every\n // remote after it in git's ordering completely unprotected -- silently, in a\n // repository the operator had just been told was blocked. Failures are now\n // recorded per remote and reported, and the loop continues.\n try {\n results.push(await disableOneRemote(cwd, remote));\n } catch (error) {\n results.push({ remote, status: \"failed\", reason: describeError(error) });\n }\n }\n return results;\n}\n\nasync function disableOneRemote(cwd: string, remote: string): Promise<PushUrlResult> {\n const scoped = await readScopedAll(cwd, `remote.${remote}.pushurl`);\n\n // A pushurl set outside this repository cannot be neutralised from inside it.\n // Config is additive for multivalued keys: a local write ADDS to git's list,\n // it cannot subtract the outside value, and the outside value sorts first --\n // so the push is delivered and only then fails on the sentinel. Refuse and say\n // so, rather than writing a sentinel that makes the repository look covered\n // while the history walks out the front door.\n // `worktree` scope is writable from inside the repository, so it is ours to\n // manage, not foreign. Only genuinely outer scopes are unreachable.\n const OVERRIDABLE = new Set([\"local\", \"worktree\"]);\n const foreign = scoped.filter(\n (entry) => !OVERRIDABLE.has(entry.scope) && entry.value !== DISABLED_PUSH_URL,\n );\n if (foreign.length > 0) {\n const scopes = [...new Set(foreign.map((entry) => entry.scope))];\n const where = scopes.join(\", \");\n const flag = scopes[0] === \"unknown\" ? \"<scope>\" : `--${scopes[0]}`;\n return {\n remote,\n status: \"failed\",\n reason:\n `a push URL for this remote is configured at ${where} scope, which this repository cannot ` +\n `override — git would still deliver the push there. Remove it with ` +\n `\\`git config ${flag} --unset-all remote.${remote}.pushurl\\` and re-apply.`,\n };\n }\n\n const currentPushUrls = scoped.map((entry) => entry.value);\n if (currentPushUrls.length === 1 && currentPushUrls[0] === DISABLED_PUSH_URL) {\n return { remote, status: \"already-disabled\" };\n }\n\n const key = originalPushUrlKey(remote);\n // Record what was there BEFORE overwriting, and only if we have not already\n // recorded it -- otherwise a second disable would enshrine the sentinel as the\n // \"original\" and make restore impossible.\n if ((await readLocalAll(cwd, key)).length === 0 && !(await hadNoPushUrl(cwd, remote))) {\n if (currentPushUrls.length > 0) {\n await runGit(cwd, [\"config\", \"--local\", \"--replace-all\", key, currentPushUrls[0]!]);\n for (const extra of currentPushUrls.slice(1)) {\n await runGit(cwd, [\"config\", \"--local\", \"--add\", key, extra]);\n }\n } else {\n // A remote with no pushurl key pushes to its fetch URL. Record that as a\n // separate marker rather than a magic URL value, so restore removes the\n // key instead of pinning one that was never there -- and so a remote whose\n // genuine URL happened to equal the marker cannot be misread as \"none\".\n await runGit(cwd, [\"config\", \"--local\", NO_PUSH_URL_MARKER(remote), \"true\"]);\n }\n }\n\n // `--replace-all` rather than `git remote set-url --push`: a mirror remote\n // with two push URLs makes set-url refuse outright (\"has multiple values\"),\n // which used to abort the run and leave BOTH mirrors pushable.\n await runGit(cwd, [\n \"config\",\n \"--local\",\n \"--replace-all\",\n `remote.${remote}.pushurl`,\n DISABLED_PUSH_URL,\n ]);\n\n // Re-read what git ACTUALLY resolves, rather than trusting that the write did\n // what we intended. The scope-based refusal above catches the cases git labels\n // as an outer scope, but not all of them: a value contributed by a file the\n // repository `include`s is reported as scope `local`, survives\n // `--replace-all`, and — if the include precedes the remote section — sorts\n // first and delivers the push. Verifying the outcome closes that whole class\n // rather than the enumerated members of it, which is the difference between\n // this check and the last three rounds of enumerating members.\n const after = await effectivePushUrls(cwd, remote);\n if (after.length !== 1 || after[0] !== DISABLED_PUSH_URL) {\n const live = after.filter((url) => url !== DISABLED_PUSH_URL);\n return {\n remote,\n status: \"failed\",\n reason:\n `the sentinel was written but git still resolves a live push URL for this remote ` +\n `(${live.join(\", \")}). It most likely comes from a file this repository \\`include\\`s, ` +\n `which \\`--replace-all\\` cannot remove. Run \\`git config --show-origin --get-all ` +\n `remote.${remote}.pushurl\\` to find the file, and clear it there.`,\n };\n }\n return { remote, status: \"disabled\" };\n}\n\n/**\n * Remotes whose push URL is NOT fully disabled. Empty when fully covered.\n *\n * A remote counts as open if ANY of its push URLs is live — a mirror with one\n * blocked and one live URL still delivers the push.\n */\nexport async function undisabledRemotes(cwd: string): Promise<string[]> {\n const open: string[] = [];\n for (const remote of await listRemotes(cwd)) {\n // Effective, not local: a pushurl inherited from global or system scope is\n // a live delivery path, and reading only local scope reported such a remote\n // as covered while `--no-verify` alone still delivered the history.\n const urls = await effectivePushUrls(cwd, remote);\n if (urls.length === 0 || urls.some((url) => url !== DISABLED_PUSH_URL)) open.push(remote);\n }\n return open;\n}\n\n/**\n * Remotes still carrying the sentinel push URL.\n *\n * The inverse of `undisabledRemotes`, and needed after an unblock: if a remote\n * was renamed while blocked, its recorded original moved with it but a different\n * remote can be left holding the sentinel with nothing to restore from. Checked\n * directly rather than inferred from what the restore believes it did.\n */\nexport async function blockedRemotes(cwd: string): Promise<string[]> {\n const blocked: string[] = [];\n for (const remote of await listRemotes(cwd)) {\n const urls = await effectivePushUrls(cwd, remote);\n if (urls.some((url) => url === DISABLED_PUSH_URL)) blocked.push(remote);\n }\n return blocked;\n}\n\n/** Restores every recorded push URL. Used only by `spell unblock-push`. */\nexport async function restorePushUrls(cwd: string): Promise<PushUrlResult[]> {\n const results: PushUrlResult[] = [];\n for (const remote of await listRemotes(cwd)) {\n try {\n results.push(await restoreOneRemote(cwd, remote));\n } catch (error) {\n results.push({ remote, status: \"failed\", reason: describeError(error) });\n }\n }\n return results;\n}\n\nasync function restoreOneRemote(cwd: string, remote: string): Promise<PushUrlResult> {\n const key = originalPushUrlKey(remote);\n let recorded = await readLocalAll(cwd, key);\n let hadNone = await hadNoPushUrl(cwd, remote);\n\n if (recorded.length === 0 && !hadNone) {\n const legacy = await readLegacyRecord(cwd, remote);\n if (legacy.status !== \"usable\") return { remote, status: legacy.status, reason: legacy.reason };\n recorded = legacy.values;\n hadNone = false;\n }\n\n if (hadNone) {\n // `--unset-all` exits 5 when the key is already absent. That is the goal\n // state, not a failure -- letting it throw skipped the stale-key cleanup\n // below, and a surviving `arcaneHadNoPushUrl` marker made the NEXT block\n // record nothing and the next restore delete a genuine push URL.\n await unsetIgnoringMissing(cwd, `remote.${remote}.pushurl`);\n } else {\n await runGit(cwd, [\n \"config\",\n \"--local\",\n \"--replace-all\",\n `remote.${remote}.pushurl`,\n recorded[0]!,\n ]);\n for (const extra of recorded.slice(1)) {\n await runGit(cwd, [\"config\", \"--local\", \"--add\", `remote.${remote}.pushurl`, extra]);\n }\n }\n\n // Clear our bookkeeping only on success. Doing this unconditionally would\n // destroy a record we had *deliberately* declined to apply -- the legacy-key\n // refusal above prints the value for the operator to apply by hand, and\n // wiping it in the same breath makes that instruction unfollowable.\n //\n // The stale-marker hazard this used to guard against is closed at its source:\n // `unsetIgnoringMissing` treats git's exit 5 (\"key already absent\") as\n // success, so the throw that previously skipped this cleanup no longer\n // happens.\n for (const staleKey of [key, NO_PUSH_URL_MARKER(remote), `arcane.originalPushUrl.${remote}`]) {\n try {\n await unsetIgnoringMissing(cwd, staleKey);\n } catch {\n // Non-fatal: the URL is restored, which is what matters.\n }\n }\n return { remote, status: \"restored\" };\n}\n\n/**\n * Unsets a config key, treating \"it was already absent\" as success.\n *\n * `git config --unset-all` exits **5** for a missing key. Letting that throw\n * turned a no-op into a reported failure and, worse, skipped whatever cleanup\n * followed it.\n */\nasync function unsetIgnoringMissing(cwd: string, key: string): Promise<void> {\n try {\n await runGit(cwd, [\"config\", \"--local\", \"--unset-all\", key]);\n } catch (error) {\n if ((error as { code?: unknown }).code !== 5) throw error;\n }\n}\n\nasync function hadNoPushUrl(cwd: string, remote: string): Promise<boolean> {\n return (await readLocalAll(cwd, NO_PUSH_URL_MARKER(remote)))[0] === \"true\";\n}\n\n/**\n * Reads a record left by the released `0.20.0`, which stored originals in a flat\n * `arcane.originalPushUrl.<remote>` key -- and only applies it when it can be\n * trusted.\n *\n * Applying it unconditionally reintroduced, for exactly the population told to\n * upgrade, the wrong-remote push this release fixes. Two ways, both reproduced:\n *\n * - Trailing config-key segments are case-insensitive, so `0.20.0` wrote one\n * key for both `origin` and `Origin` and only the last writer survived.\n * Restoring it points one remote at the OTHER remote's URL, reported as a\n * clean success.\n * - Unlike a `remote.<name>.*` key, the flat key survives `git remote remove`.\n * A remote deleted and re-added to a different URL gets silently restored to\n * the old target.\n *\n * So the record is used only when the remote is still carrying OUR sentinel\n * (which a re-added remote is not) and no two remote names collide\n * case-insensitively. Otherwise the value is reported for the operator to apply\n * by hand: a restore that might pick the wrong remote is worse than none.\n */\nasync function readLegacyRecord(\n cwd: string,\n remote: string,\n): Promise<\n | { status: \"usable\"; values: string[] }\n | { status: \"nothing-recorded\" | \"failed\"; reason?: string }\n> {\n const values = await readLocalAll(cwd, `arcane.originalPushUrl.${remote}`);\n if (values.length === 0) return { status: \"nothing-recorded\" };\n\n const current = await effectivePushUrls(cwd, remote);\n if (!current.includes(DISABLED_PUSH_URL)) {\n return {\n status: \"failed\",\n reason:\n `found a push URL recorded by 0.20.0 (\"${values.join(\", \")}\") but this remote is not ` +\n \"currently blocked by Arcane, so the record may belong to a different remote of the same \" +\n \"name. Not applying it — set the URL yourself if it is correct.\",\n };\n }\n\n const names = await listRemotes(cwd);\n const collides = names.some(\n (other) => other !== remote && other.toLowerCase() === remote.toLowerCase(),\n );\n if (collides) {\n return {\n status: \"failed\",\n reason:\n `this repository has remotes whose names differ only by case, and 0.20.0 stored their ` +\n `original push URLs under one shared key, so the recorded value (\"${values.join(\", \")}\") ` +\n \"cannot be attributed to a specific remote. Not applying it — set the URLs yourself.\",\n };\n }\n\n return { status: \"usable\", values };\n}\n\nfunction describeError(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return message.split(\"\\n\")[0]!.trim();\n}\n","import { execFile } from \"node:child_process\";\n\nexport type GitRepositoryState =\n | { status: \"ready\"; uncommittedChanges: number }\n | { status: \"not-repository\" }\n | { status: \"no-commits\" };\n\nexport type GitCommandClass = \"read\" | \"write\" | \"network\";\n\nexport interface RunGitOptions {\n /** Override auto-classification from the subcommand. */\n commandClass?: GitCommandClass;\n /** Override the command class's default timeout, in milliseconds. */\n timeoutMs?: number;\n}\n\nexport interface GitResult {\n stdout: string;\n stderr: string;\n}\n\n/**\n * EF-20: thrown when a `git` subprocess exceeds its runGit-assigned timeout\n * and Node reports the resulting kill via `error.killed`. Note this reflects\n * \"the child was killed by a signal Node sent it,\" which today only ever\n * happens through runGit's own timeout, since no caller retains the\n * underlying ChildProcess to kill it independently -- if a future caller\n * gains that ability, `error.killed` alone would no longer distinguish\n * runGit's timeout from an external kill of the same handle.\n */\nexport class GitTimeoutError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"GitTimeoutError\";\n }\n}\n\nconst NETWORK_SUBCOMMANDS = new Set([\"fetch\", \"pull\", \"push\", \"clone\", \"ls-remote\", \"send-email\"]);\n\nconst WRITE_SUBCOMMANDS = new Set([\n \"init\",\n \"commit\",\n \"add\",\n \"checkout\",\n \"switch\",\n \"merge\",\n \"rebase\",\n \"reset\",\n \"tag\",\n \"mv\",\n \"rm\",\n \"cherry-pick\",\n \"revert\",\n \"stash\",\n \"apply\",\n \"am\",\n \"restore\",\n \"submodule\",\n \"sparse-checkout\",\n \"maintenance\",\n \"notes\",\n]);\n\n// These subcommands can be read-only (`branch --list`, `config --get`) or\n// mutating (`branch -m`, `config user.name x`) depending on flags. Classified\n// as \"write\" -- the safer over-estimate: a read given write's longer timeout\n// just waits a little longer, while a write given read's shorter timeout\n// risks being killed mid-operation.\nconst AMBIGUOUS_AS_WRITE = new Set([\"branch\", \"config\", \"remote\", \"worktree\"]);\n\n// Known read-only subcommands get the fast 15s budget explicitly. Anything\n// NOT in this list, NOT in WRITE_SUBCOMMANDS/AMBIGUOUS_AS_WRITE, and NOT in\n// NETWORK_SUBCOMMANDS is a subcommand this module doesn't recognize at all --\n// that case defaults to \"write\" (see classifyGitCommand), the safer\n// over-estimate for a genuinely unknown operation.\nconst READ_SUBCOMMANDS = new Set([\n \"status\",\n \"rev-parse\",\n \"log\",\n \"diff\",\n \"show\",\n \"describe\",\n \"cat-file\",\n \"ls-files\",\n \"ls-tree\",\n \"symbolic-ref\",\n \"show-ref\",\n \"for-each-ref\",\n \"merge-base\",\n \"blame\",\n \"shortlog\",\n \"grep\",\n \"reflog\",\n \"diff-tree\",\n \"rev-list\",\n \"name-rev\",\n \"count-objects\",\n \"verify-commit\",\n \"verify-tag\",\n \"help\",\n \"version\",\n]);\n\n// Global options that take their value as a SEPARATE following token (not\n// `--opt=value`). Without skipping the value too, `args.find(a =>\n// !a.startsWith(\"-\"))` would grab the value itself (e.g. \"user.name=x\" from\n// `-c user.name=x commit`) and misclassify the real subcommand that follows.\nconst GLOBAL_FLAGS_WITH_SEPARATE_VALUE = new Set([\"-c\", \"-C\"]);\n\nconst DEFAULT_TIMEOUTS_MS: Record<GitCommandClass, number> = {\n read: 15_000,\n write: 30_000,\n network: 120_000,\n};\n\n/**\n * Classify a git invocation by its first real subcommand token, skipping any\n * leading global flags (and, for `-c`/`-C`, their separate-token values) to\n * find it. Exported for tests.\n */\nexport function classifyGitCommand(args: string[]): GitCommandClass {\n let subcommand: string | undefined;\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (GLOBAL_FLAGS_WITH_SEPARATE_VALUE.has(arg)) {\n i++; // skip this flag's value token too\n continue;\n }\n if (arg.startsWith(\"-\")) continue;\n subcommand = arg;\n break;\n }\n if (!subcommand) return \"read\";\n if (NETWORK_SUBCOMMANDS.has(subcommand)) return \"network\";\n if (WRITE_SUBCOMMANDS.has(subcommand) || AMBIGUOUS_AS_WRITE.has(subcommand)) return \"write\";\n if (READ_SUBCOMMANDS.has(subcommand)) return \"read\";\n // A subcommand this module doesn't recognize at all: default to \"write\"\n // (the safer over-estimate) rather than \"read\" -- see READ_SUBCOMMANDS.\n return \"write\";\n}\n\n/**\n * EF-20/EF-13: the non-interactive execution environment applied to every\n * git invocation. GIT_TERMINAL_PROMPT and GCM_INTERACTIVE suppress credential\n * and terminal prompts; GIT_OPTIONAL_LOCKS disables git's speculative index\n * lock during `status` (git-config(1): \"core.optionalLocks\" affects only\n * status/update-index, so this is safe to apply blanket rather than per\n * command class) -- the mitigation for EF-13's stranded-lock report on\n * filesystems that reject unlink. Exported for tests.\n */\nexport function buildGitEnv(): NodeJS.ProcessEnv {\n return {\n ...process.env,\n GIT_TERMINAL_PROMPT: \"0\",\n GCM_INTERACTIVE: \"Never\",\n GIT_OPTIONAL_LOCKS: \"0\",\n };\n}\n\n/**\n * Single chokepoint for every production `git` invocation. Closes stdin\n * immediately (EF-20: an interactive prompt reading from stdin gets instant\n * EOF instead of hanging on an open, unwritten pipe) and enforces a\n * command-class-scoped timeout (EF-20: no git operation can block an\n * autonomous session indefinitely with no completion signal).\n */\nexport function runGit(cwd: string, args: string[], options: RunGitOptions = {}): Promise<GitResult> {\n const commandClass = options.commandClass ?? classifyGitCommand(args);\n // Falls back to the \"write\" budget if commandClass ever reaches here as\n // something outside the GitCommandClass union (only reachable from an\n // untyped caller) -- an undefined timeoutMs would mean NO timeout at all,\n // silently defeating the one guarantee this module exists to provide.\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUTS_MS[commandClass] ?? DEFAULT_TIMEOUTS_MS.write;\n\n return new Promise((resolve, reject) => {\n const child = execFile(\n \"git\",\n args,\n {\n cwd,\n env: buildGitEnv(),\n timeout: timeoutMs,\n // SIGTERM (Node's default) rather than SIGKILL: gives git a chance\n // to run its own cleanup on POSIX, relevant to EF-20's own concern\n // about a killed operation leaving refs/locks in an uncertain state.\n // Moot on Windows -- Node docs: both map to an abrupt TerminateProcess\n // there -- but this module isn't Windows-gated.\n killSignal: \"SIGTERM\",\n windowsHide: true,\n encoding: \"utf8\",\n },\n (error, stdout, stderr) => {\n if (error) {\n if (error.killed) {\n reject(\n new GitTimeoutError(\n // NOTE: embeds the raw args, including any secrets a future\n // network-class caller might pass (e.g. a credentialed\n // clone URL). No current caller does; redact before one does.\n `git ${args.join(\" \")} timed out after ${timeoutMs}ms (class: ${commandClass})`,\n { cause: error },\n ),\n );\n return;\n }\n reject(error);\n return;\n }\n resolve({ stdout, stderr });\n },\n );\n // EF-20: never leave stdin as an open, unread pipe -- see module doc.\n child.stdin?.end();\n });\n}\n\n/**\n * Returns the repository state required before a destructive managed update.\n */\nexport async function inspectGitRepository(cwd: string): Promise<GitRepositoryState> {\n try {\n const { stdout } = await runGit(cwd, [\"rev-parse\", \"--is-inside-work-tree\"]);\n if (stdout.trim() !== \"true\") {\n return { status: \"not-repository\" };\n }\n } catch {\n return { status: \"not-repository\" };\n }\n\n try {\n await runGit(cwd, [\"rev-parse\", \"--verify\", \"HEAD\"]);\n } catch {\n return { status: \"no-commits\" };\n }\n\n const { stdout } = await runGit(cwd, [\"status\", \"--porcelain\", \"-uall\"]);\n const lines = stdout.trim();\n return {\n status: \"ready\",\n uncommittedChanges: lines.length === 0 ? 0 : lines.split(\"\\n\").length,\n };\n}\n\n/**\n * Returns the number of uncommitted changes in the working tree, or 0\n * if the directory is not a git repo or git is not installed.\n */\nexport async function countUncommittedChanges(cwd: string): Promise<number> {\n try {\n const { stdout } = await runGit(cwd, [\"status\", \"--porcelain\", \"-uall\"]);\n const lines = stdout.trim();\n return lines.length === 0 ? 0 : lines.split(\"\\n\").length;\n } catch {\n return 0;\n }\n}\n\nexport interface UnbornBranchCorrection {\n corrected: boolean;\n from?: string;\n to: \"main\";\n /**\n * Set when the correction was declined because the target ref could not be\n * read (a broken/unreadable `refs/heads/main`) rather than because it was\n * absent or already healthy. Callers should surface this: the repo has a\n * real integrity problem the operator will want to know about, but it is\n * not severe enough to abort an install over a cosmetic branch rename.\n */\n blockedReason?: \"target-unreadable\";\n}\n\n/**\n * EF-05: on an unborn repository (git init has run, no commit yet) whose\n * HEAD currently targets exactly \"master\" -- the reported Git for Windows\n * system-default leak (init.defaultBranch=master at the system config\n * level) -- repoint it to \"main\" via `symbolic-ref`. Safe because no commit\n * objects exist yet to conflict with; equivalent to what `git init -b main`\n * does internally. Any OTHER branch name, including one an operator\n * deliberately chose, is left untouched -- this corrects the specific\n * reported default-leak, not a general \"Arcane requires main\" policy.\n * No-op (not corrected) if `cwd` isn't an unborn repo at all.\n */\nexport async function correctUnbornMasterDefault(cwd: string): Promise<UnbornBranchCorrection> {\n let current: string;\n try {\n const { stdout } = await runGit(cwd, [\"symbolic-ref\", \"--short\", \"HEAD\"]);\n current = stdout.trim();\n } catch {\n return { corrected: false, to: \"main\" };\n }\n\n if (current !== \"master\") {\n return { corrected: false, to: \"main\" };\n }\n\n // Verify unborn-ness internally rather than trusting the caller: on a\n // BORN repo already on \"master\", `symbolic-ref HEAD refs/heads/main`\n // would detach HEAD's branch pointer from its commit history without\n // moving any commits -- `main` would exist as an empty ref while every\n // real commit stays reachable only via the abandoned `master` ref. This\n // check is the same one `inspectGitRepository` uses to distinguish\n // \"no-commits\" from \"ready\".\n try {\n await runGit(cwd, [\"rev-parse\", \"--verify\", \"HEAD\"]);\n return { corrected: false, to: \"main\" }; // HEAD resolves -- repo is born, don't touch it\n } catch {\n // rev-parse --verify HEAD failing IS the unborn signal -- proceed.\n }\n\n // Also verify the TARGET doesn't already exist with real history.\n // Confirming the source is unborn is not sufficient: if `refs/heads/main`\n // already resolves (e.g. created earlier in this repo, or shared across\n // git worktrees -- refs/heads/* is shared while HEAD is per-worktree, so\n // an unborn \"master\" HEAD in one worktree can coexist with a fully born\n // \"main\" from another), repointing HEAD onto it would silently attach\n // whatever's currently staged/uncommitted on the unborn HEAD to main's\n // real commit history -- a history splice, not a safe unborn-HEAD\n // repoint, and the next `git commit` an operator runs would commit it.\n // Distinguishing \"absent\" from \"unreadable\" needs stdout/stderr, not an\n // exit code. Verified empirically against git 2.x -- BOTH `rev-parse\n // --verify` and `show-ref --verify --quiet` return the same nonzero status\n // for a corrupt ref as for a missing one (128 and 1 respectively), so\n // either one behind a bare catch reads \"this branch is broken\" as \"this\n // branch does not exist\" and repoints HEAD onto real history anyway.\n //\n // `for-each-ref` usually exits 0 and reports the state through its streams:\n // healthy -> stdout = the object id, stderr empty\n // corrupt -> stdout empty, stderr \"warning: ignoring broken ref ...\"\n // absent -> stdout empty, stderr empty\n // Only the third is safe to treat as absence, and even it needs a second\n // probe (see the symref check below). The stderr test is on emptiness, not\n // on git's English wording, so a translated locale can't defeat it.\n let mainRef: { stdout: string; stderr: string };\n try {\n mainRef = await runGit(cwd, [\"for-each-ref\", \"--format=%(objectname)\", \"refs/heads/main\"]);\n } catch {\n // for-each-ref itself failed -- a corrupt .git/packed-refs exits 128, and\n // a timeout rejects too. Either way we learned nothing about whether main\n // exists, so absence is not a conclusion we're entitled to draw.\n return { corrected: false, to: \"main\", blockedReason: \"target-unreadable\" };\n }\n\n if (mainRef.stdout.trim() !== \"\") {\n return { corrected: false, to: \"main\" }; // main already exists -- don't touch it\n }\n\n if (mainRef.stderr.trim() !== \"\") {\n // Broken ref: it may still hold real history we cannot see. Fail closed\n // -- decline the correction, and tell the caller why so it can warn.\n return { corrected: false, to: \"main\", blockedReason: \"target-unreadable\" };\n }\n\n // Empty/empty is still ambiguous: a DANGLING SYMREF (refs/heads/main is\n // `ref: refs/heads/<missing>`) reports exactly the same shape as an absent\n // ref. Repointing onto it would leave HEAD on the symref's target while\n // reporting \"repointed to main\" -- untrue, even though nothing is spliced.\n // `symbolic-ref -q` is the discriminator: 0 = main exists as a symref,\n // 1 = genuinely absent. Anything else is another unreadable state.\n try {\n await runGit(cwd, [\"symbolic-ref\", \"-q\", \"refs/heads/main\"]);\n return { corrected: false, to: \"main\", blockedReason: \"target-unreadable\" };\n } catch (error) {\n if ((error as { code?: unknown }).code !== 1) {\n return { corrected: false, to: \"main\", blockedReason: \"target-unreadable\" };\n }\n // Exit 1 -- refs/heads/main genuinely does not exist. Safe to target it.\n }\n\n await runGit(cwd, [\"symbolic-ref\", \"HEAD\", \"refs/heads/main\"]);\n return { corrected: true, from: current, to: \"main\" };\n}\n\nexport type PullRebaseResult =\n | { action: \"set\" }\n | { action: \"already-set\" }\n | { action: \"explicit-false-preserved\" };\n\n/**\n * EF-32: ensure `pull.rebase` is set at the repository-LOCAL level so the\n * mandated rebase-and-fast-forward workflow (git-conventions.md) doesn't\n * silently depend on the operator's machine-wide default (Git for Windows\n * ships pull.rebase=false at the system level). Distinguishes \"unset\n * locally\" (safe to set -- it was only ever inheriting a machine default)\n * from \"explicitly set locally, even to false\" (never silently overridden\n * -- the caller is expected to surface this as a warning instead).\n */\nexport async function ensureLocalPullRebase(cwd: string): Promise<PullRebaseResult> {\n let rawLocalValue: string | undefined;\n try {\n const { stdout } = await runGit(cwd, [\"config\", \"--local\", \"--get\", \"pull.rebase\"]);\n rawLocalValue = stdout.trim();\n } catch {\n rawLocalValue = undefined; // nothing set locally at all (may be inherited from global/system)\n }\n\n if (rawLocalValue === undefined) {\n await runGit(cwd, [\"config\", \"--local\", \"pull.rebase\", \"true\"]);\n return { action: \"set\" };\n }\n\n // Something IS set locally. Determine whether it's a falsy boolean via\n // git's own boolean parser (`--type=bool` normalizes any of git's valid\n // spellings -- true/yes/on/1 and false/no/off/0 -- to canonical\n // \"true\"/\"false\"), rather than hand-matching the literal string \"false\"\n // and missing every other valid spelling. A value `--type=bool` can't\n // coerce (e.g. \"merges\" or \"interactive\" -- both valid, deliberate\n // pull.rebase settings) means the operator explicitly chose something\n // else entirely; that's still an explicit local choice and must never be\n // overwritten, so it's treated the same as \"already-set\".\n try {\n const { stdout } = await runGit(cwd, [\"config\", \"--local\", \"--type=bool\", \"--get\", \"pull.rebase\"]);\n if (stdout.trim() === \"false\") {\n return { action: \"explicit-false-preserved\" };\n }\n return { action: \"already-set\" };\n } catch {\n return { action: \"already-set\" };\n }\n}\n","/**\n * Regex-based credential-pattern denylist, sharing denylist-scan.ts's generic\n * file-walking/matching engine (also used by org-token-lint.ts and spell\n * ward). Extracted from scripts/copy-assets.ts (ARC-037) so the same pattern\n * set backs both the pre-existing src/assets/-scoped copy-time scan and the\n * repository-wide CI backstop / pre-commit hook this ADR adds.\n *\n * Patterns are deliberately conservative -- common credential shapes. A false\n * positive blocks a build or a commit, which is the safe direction to fail.\n */\nimport type { DenylistRule } from \"./denylist-scan.js\";\nimport { installHook, isHookInstalled, removeHook, type HookInstallOutcome } from \"./push-safety.js\";\n\nexport const SECRETS_RULES: DenylistRule[] = [\n { label: \"api-key\", pattern: /API[_-]KEY\\s*[:=]\\s*\\S+/i },\n // Case-sensitive and requiring an all-caps/underscore identifier (SECRET,\n // MY_SECRET, API_SECRET_KEY...) -- the real config/env-var convention for a\n // credential-holding key. Widening this repository-wide (ARC-037 decision 3)\n // surfaced that the original case-insensitive form matched ANY lowercase\n // `secret`/`token` code identifier (e.g. `const token = value.trim();`),\n // which is overwhelmingly a parsed/resolved value, never a literal\n // credential. The `(?!\\$?\\{)` guard additionally excludes any\n // brace-delimited placeholder -- GitHub Actions/templating references\n // (`TOKEN: ${{ secrets.X }}`, a reference to a secret store, never the\n // secret itself) and this codebase's own documented `{UPPER_SNAKE}`\n // placeholder convention (denylist-scan.ts's `scanFile` already strips\n // those before matching for the sibling org-token scan; a bare single\n // brace, with no `scanFile`-style stripping in the copy-time call path,\n // needed the same exclusion here rather than only the double-brace case).\n // A minimum length of 8 further excludes short non-secret values like\n // `write` (`id-token: write`).\n { label: \"generic-secret\", pattern: /\\b[A-Z0-9_]*SECRET[A-Z0-9_]*\\s*[:=]\\s*(?!\\$?\\{)\\S{8,}/ },\n { label: \"generic-token\", pattern: /\\b[A-Z0-9_]*TOKEN[A-Z0-9_]*\\s*[:=]\\s*(?!\\$?\\{)\\S{8,}/ },\n { label: \"bearer-token\", pattern: /Bearer\\s+[A-Za-z0-9._~+/-]{20,}/ }, // real tokens are long\n { label: \"openai-key\", pattern: /sk-[A-Za-z0-9]{20,}/ },\n { label: \"pem-key\", pattern: /-----BEGIN [A-Z ]+-----/ },\n { label: \"slack-token\", pattern: /xox[bpars]-[A-Za-z0-9-]+/ },\n { label: \"aws-access-key\", pattern: /AKIA[0-9A-Z]{16}/ },\n { label: \"github-pat\", pattern: /ghp_[A-Za-z0-9]{36}/ },\n];\n\n/**\n * Back-compat plain-pattern list for `scripts/copy-assets.ts`'s existing\n * per-line copy-time scan, which predates `DenylistRule` and iterates raw\n * `RegExp`s directly. Derived from `SECRETS_RULES` so there is exactly one\n * place these patterns are authored.\n */\nexport const SECRETS_PATTERNS: RegExp[] = SECRETS_RULES.map((rule) => rule.pattern);\n\n// ─── Consumer-facing pre-commit hook (ARC-037 decision 2 / decision 4b) ──────\n// This repo's OWN pre-commit scan is a Husky step (.husky/pre-commit calls\n// `npm run doctor:leaks`); a fresh consumer repo has no Husky. This installs\n// the same `spell doctor --leaks` check via push-safety.ts's generalized,\n// push_policy-independent hook-install path (ARC-037 decision 2) instead --\n// every profile gets it regardless of push_policy, since credential leakage\n// is a risk independent of whether a repository's history may reach a\n// remote. Mandatory rather than an opt-in prompt: the check is cheap, local,\n// and `--no-verify`-bypassable by design (decision 6) -- the repository-wide\n// CI backstop this ADR also adds is the real, unavoidable defense, not this.\n\nexport const SECRETS_PRECOMMIT_HOOK_NAME = \"pre-commit\";\n\n/**\n * Pure code, not a shipped asset file -- the same shape as push-safety.ts's\n * own PRE_PUSH_HOOK_BODY. `spell` is expected on PATH per the documented\n * global-install pattern (README.md); a missing binary skips the scan rather\n * than blocking the commit; a misconfigured PATH has nothing to do with\n * whatever the operator is actually committing.\n */\nexport const SECRETS_PRECOMMIT_HOOK_BODY = `#!/bin/sh\n# Installed by Arcane (ARC-037) to scan staged content for accidentally\n# committed credentials before they enter history.\n#\n# This is deliberately not tamper-proof: \\`git commit --no-verify\\` skips it\n# entirely. The real defense is the repository-wide scan Arcane's own build\n# runs in CI on every push -- this hook exists to catch a leak locally, for\n# free, before it ever reaches a commit.\nif ! command -v spell >/dev/null 2>&1; then\n echo \"arcane: 'spell' not found on PATH -- skipping secrets scan (see: npm install -g arcane-cli)\" >&2\n exit 0\nfi\nspell doctor --leaks\n`;\n\nexport async function installSecretsPrecommitHook(cwd: string): Promise<HookInstallOutcome> {\n return installHook(cwd, SECRETS_PRECOMMIT_HOOK_NAME, SECRETS_PRECOMMIT_HOOK_BODY);\n}\n\nexport async function isSecretsPrecommitHookInstalled(cwd: string): Promise<boolean> {\n return isHookInstalled(cwd, SECRETS_PRECOMMIT_HOOK_NAME, SECRETS_PRECOMMIT_HOOK_BODY);\n}\n\nexport async function removeSecretsPrecommitHook(cwd: string): Promise<void> {\n return removeHook(cwd, SECRETS_PRECOMMIT_HOOK_NAME);\n}\n","import { join } from \"node:path\";\nimport { copyFile, copyDirectory } from \"../modules/copier.js\";\nimport {\n readManifest,\n writeManifest,\n addComponent,\n hasComponent,\n ManifestNotFoundError,\n} from \"../modules/manifest.js\";\nimport { getComponent, ComponentNotFoundError } from \"../modules/registry.js\";\nimport type { InstalledComponent, SpellAddOptions } from \"../types.js\";\n\n/**\n * Runs the `spell add <component>` command.\n *\n * @param name Component name to install\n * @param options CLI flags (force, dryRun)\n * @param targetDir Directory containing the Arcane installation\n * @param assetsDir Path to the bundled assets root\n * @param packageVersion Current package version string\n */\nexport async function runAdd(\n name: string,\n options: SpellAddOptions,\n targetDir: string,\n assetsDir: string,\n packageVersion: string,\n): Promise<void> {\n // Read existing manifest (must be initialized first)\n let manifest;\n try {\n manifest = await readManifest(targetDir);\n } catch (err) {\n if (err instanceof ManifestNotFoundError) {\n console.error(\n 'Not initialized. Run \"spell init\" first before adding components.',\n );\n process.exit(1);\n return; // guard: process.exit is mocked in tests\n }\n throw err;\n }\n\n // Look up the component in the registry\n let component;\n try {\n component = getComponent(name);\n } catch (err) {\n if (err instanceof ComponentNotFoundError) {\n console.error(err.message);\n process.exit(1);\n return; // guard: process.exit is mocked in tests\n }\n throw err;\n }\n\n // Check if already installed\n if (hasComponent(manifest, name)) {\n console.log(\n `Component \"${name}\" is already installed. Use \"spell update\" to update it.`,\n );\n return;\n }\n\n // Copy files and directories\n let fileCount = 0;\n const installedFiles: string[] = [];\n const fileHashes: Record<string, string> = {};\n for (const file of component.files) {\n const srcPath = join(assetsDir, component.sourceOverrides?.[file] ?? file);\n if (options.dryRun) {\n console.log(` [dry-run] Would copy: ${file}`);\n } else {\n fileHashes[file] = await copyFile(srcPath, targetDir, file, { force: options.force });\n }\n installedFiles.push(file);\n fileCount++;\n }\n for (const dir of component.directories ?? []) {\n const srcDirPath = join(assetsDir, dir);\n if (options.dryRun) {\n console.log(` [dry-run] Would copy directory: ${dir}/`);\n } else {\n const copied = await copyDirectory(srcDirPath, targetDir, dir, { force: options.force });\n for (const { path: copiedPath, hash } of copied) {\n installedFiles.push(copiedPath);\n fileHashes[copiedPath] = hash;\n }\n fileCount += copied.length;\n }\n }\n\n if (options.dryRun) {\n console.log(\n `\\n[dry-run] Would add component \"${name}\" \\u2014 ${fileCount} files`,\n );\n return;\n }\n\n // Update manifest\n const newComponent: InstalledComponent = {\n name,\n files: installedFiles,\n installedVersion: packageVersion,\n fileHashes,\n };\n const updated = addComponent(manifest, newComponent);\n await writeManifest(targetDir, updated);\n\n console.log(\n `\\n\\u2713 Added component \"${name}\" \\u2014 ${fileCount} files copied`,\n );\n}\n","import { join } from \"node:path\";\nimport { readFile, writeFile, rm } from \"node:fs/promises\";\nimport { copyFile, copyDirectory, fileExists, hashFile } from \"../modules/copier.js\";\nimport {\n readManifest,\n writeManifest,\n ManifestNotFoundError,\n} from \"../modules/manifest.js\";\nimport { inspectGitRepository } from \"../modules/git.js\";\nimport {\n getComponent,\n ComponentNotFoundError,\n LEGACY_COMPONENT_MIGRATIONS,\n} from \"../modules/registry.js\";\nimport { MANIFEST_RETROFITS, runManifestRetrofits, offerRegistryScaffold } from \"../modules/hub.js\";\nimport { merge3 } from \"../modules/merge3.js\";\nimport { fetchPublishedFile } from \"../modules/npm-registry.js\";\nimport type { ArcaneManifest, InstalledComponent, SpellUpdateOptions } from \"../types.js\";\n\n/**\n * Runs the `spell update` command.\n *\n * For each installed component, looks up the current registry definition and\n * re-copies files from the current package assets. User-owned files in a\n * skipExisting component are preserved when present and backfilled when absent.\n * The manifest is updated with the new file paths so future updates remain\n * correct even when source paths change between versions.\n *\n * @param options CLI flags (dryRun)\n * @param targetDir Directory containing the Arcane installation\n * @param assetsDir Path to the bundled assets root\n * @param packageVersion Current package version string\n */\n/**\n * Rewrites manifest entries whose component was split or renamed in a later\n * release, so `update` can refresh their files instead of skipping them.\n *\n * Deterministic and idempotent: an already-migrated manifest contains no\n * legacy names, so this returns it unchanged. Entry order is preserved, with\n * each legacy entry's replacements expanded in place. Replacements inherit the\n * legacy entry's `installedVersion` and an empty file list -- the caller\n * immediately re-derives both from the registry, which is the source of truth\n * for what a component contains.\n *\n * Both legacy spell components map to the same replacement set, so a manifest\n * listing both (the common case) is deduped rather than producing doubles.\n */\nexport function migrateLegacyComponents(\n components: InstalledComponent[],\n): InstalledComponent[] {\n const out: InstalledComponent[] = [];\n const seen = new Set<string>();\n\n for (const entry of components) {\n const replacements = LEGACY_COMPONENT_MIGRATIONS[entry.name];\n if (!replacements) {\n if (seen.has(entry.name)) continue;\n seen.add(entry.name);\n out.push(entry);\n continue;\n }\n for (const name of replacements) {\n if (seen.has(name)) continue;\n seen.add(name);\n out.push({ name, files: [], installedVersion: entry.installedVersion });\n }\n }\n\n return out;\n}\n\nexport type OrphanStatus = \"pruned\" | \"reported\" | \"not-found\";\n\n/**\n * Resolves one orphaned file: previously tracked, no longer part of any\n * current component (TODO.md T10). Report-only unless `prune` is set, and\n * even then only deletes when the on-disk content still matches the hash\n * Arcane last recorded -- an operator edit is exactly as worth preserving\n * here as it is in the main update loop (ARC-038 decision 1's \"do not\n * silently discard the edit\" applies to deleting a file, not only\n * overwriting one). A file with no recorded hash (predates ARC-038, or was\n * never hashed) is reported but never auto-pruned -- there is nothing to\n * verify it against, and guessing is not this feature's job.\n */\nexport async function resolveOrphan(\n targetDir: string,\n file: string,\n recordedHash: string | undefined,\n prune: boolean,\n): Promise<OrphanStatus> {\n const filePath = join(targetDir, file);\n if (!(await fileExists(filePath))) return \"not-found\";\n if (!prune) return \"reported\";\n\n if (recordedHash === undefined) {\n console.log(` ! Orphaned, not pruned (no recorded hash to verify it's untouched): ${file}`);\n return \"reported\";\n }\n const currentHash = await hashFile(filePath);\n if (currentHash !== recordedHash) {\n console.log(` ! Orphaned but edited since install — not pruning: ${file}`);\n return \"reported\";\n }\n await rm(filePath, { force: true });\n console.log(` Pruned orphaned file: ${file}`);\n return \"pruned\";\n}\n\nexport async function runUpdate(\n options: SpellUpdateOptions,\n targetDir: string,\n assetsDir: string,\n packageVersion: string,\n): Promise<void> {\n // Read existing manifest\n let manifest;\n try {\n manifest = await readManifest(targetDir);\n } catch (err) {\n if (err instanceof ManifestNotFoundError) {\n console.error(\n 'Not initialized. Run \"spell init\" first before updating.',\n );\n process.exit(1);\n return; // guard: process.exit is mocked in tests\n }\n throw err;\n }\n\n console.warn(\n `WARNING: Arcane v${packageVersion} update safety notice: commit your work before updating.`,\n );\n console.warn(\n \"Updates can replace managed files. A clean committed baseline is required for recovery.\",\n );\n\n const gitState = await inspectGitRepository(targetDir);\n if (gitState.status === \"not-repository\") {\n console.error(\n \"Update refused: this directory is not a Git repository or Git is unavailable.\",\n );\n process.exit(1);\n return;\n }\n if (gitState.status === \"no-commits\") {\n console.error(\n \"Update refused: this repository has no commits. Commit the current baseline before updating.\",\n );\n process.exit(1);\n return;\n }\n if (gitState.uncommittedChanges > 0) {\n console.error(\n `Update refused: this repository has ${gitState.uncommittedChanges} uncommitted change${gitState.uncommittedChanges === 1 ? \"\" : \"s\"}. Commit or otherwise clean the working tree before updating.`,\n );\n process.exit(1);\n return;\n }\n\n // Already up to date\n if (manifest.version === packageVersion && manifest.components.length > 0) {\n console.log(\"Already up to date.\");\n return;\n }\n\n if (manifest.components.length === 0) {\n console.log(\"No components installed. Nothing to update.\");\n return;\n }\n\n let fileCount = 0;\n const updatedComponents: InstalledComponent[] = [];\n // ARC-038 decision 1: files whose merge produced genuine conflict markers,\n // collected across every component so the operator gets one summary at the\n // end rather than a per-file interruption -- the update still completes\n // for every other file either way.\n const conflictedFiles: string[] = [];\n // TODO.md T10: files tracked before this update that no longer belong to\n // any current component, reported always and deleted only with --prune\n // (and only when untouched -- see resolveOrphan).\n const orphanReport: Array<{ file: string; status: OrphanStatus }> = [];\n\n const componentsToUpdate = migrateLegacyComponents(manifest.components);\n\n for (const installed of componentsToUpdate) {\n // Look up the current registry definition (source of truth for file paths)\n let component;\n try {\n component = getComponent(installed.name);\n } catch (err) {\n if (err instanceof ComponentNotFoundError) {\n // Component removed from registry entirely -- every file it used to\n // track is now orphaned, not just individually dropped ones. Report\n // even during dry-run (that's the point of a preview); only the\n // actual deletion is dry-run-gated, inside resolveOrphan's `prune`.\n console.log(` ! ${installed.name} not in registry — skipping.`);\n for (const file of installed.files) {\n const status = await resolveOrphan(\n targetDir,\n file,\n installed.fileHashes?.[file],\n Boolean(options.prune) && !options.dryRun,\n );\n orphanReport.push({ file, status });\n }\n // Drop the manifest entry once every file it tracked is gone or was\n // never there; otherwise keep it so a future update can retry\n // pruning what --prune (or a hash mismatch) left behind.\n if (\n options.prune &&\n !options.dryRun &&\n installed.files.every((f) => orphanReport.find((o) => o.file === f)?.status !== \"reported\")\n ) {\n continue;\n }\n updatedComponents.push(installed);\n continue;\n }\n throw err;\n }\n\n // Copy files using current registry paths (handles path changes between versions)\n const updatedFiles: string[] = [];\n const fileHashes: Record<string, string> = {};\n for (const file of component.files) {\n const srcPath = join(assetsDir, component.sourceOverrides?.[file] ?? file);\n const targetExists = await fileExists(join(targetDir, file));\n const preserveExisting = Boolean(component.skipExisting) && targetExists;\n\n // initOnly: update never creates these. Their appearance alone changes\n // how Git treats the whole repository, so adding one mid-life is the\n // operator's call, not a side effect of a version upgrade (EF-17).\n if (component.initOnly && !targetExists) {\n console.log(\n ` ! Missing: ${file} — not added automatically, because doing so would change how Git treats existing files. Run \"spell add ${component.name}\" if you want it.`,\n );\n continue;\n }\n\n if (preserveExisting) {\n // skipExisting keeps its pre-ARC-038 whole-file behavior unchanged --\n // no hash tracking, no merge machinery (ARC-038 decision 1).\n console.log(` ${options.dryRun ? \"[dry-run] Would preserve\" : \"Preserved\"}: ${file}`);\n } else if (options.dryRun) {\n console.log(` [dry-run] Would update: ${file}`);\n fileCount++;\n } else {\n const recordedHash = installed.fileHashes?.[file];\n let handled = false;\n\n if (recordedHash !== undefined && targetExists) {\n const currentHash = await hashFile(join(targetDir, file));\n if (currentHash !== recordedHash) {\n // On-disk content no longer matches what Arcane last wrote --\n // the operator edited this file. Do not silently discard that\n // edit by overwriting it (ARC-038 decision 1).\n const oldVendorContent = await fetchPublishedFile(installed.installedVersion, file);\n if (oldVendorContent === undefined) {\n console.log(\n ` ! Could not fetch the previously published version of ${file} to merge your edits — left your version untouched. Update it manually if you want the latest.`,\n );\n handled = true;\n } else {\n const [currentContent, newContent] = await Promise.all([\n readFile(join(targetDir, file), \"utf-8\"),\n readFile(srcPath, \"utf-8\"),\n ]);\n const result = merge3(oldVendorContent, currentContent, newContent);\n await writeFile(join(targetDir, file), result.content, \"utf-8\");\n fileHashes[file] = await hashFile(join(targetDir, file));\n if (result.hasConflict) {\n conflictedFiles.push(file);\n console.log(` ⚠ Merge conflict in ${file} — resolve the <<<<<<< markers before committing.`);\n } else {\n console.log(` Merged your edits into: ${file}`);\n }\n handled = true;\n }\n }\n }\n\n if (!handled) {\n fileHashes[file] = await copyFile(srcPath, targetDir, file, { force: true });\n }\n fileCount++;\n }\n\n // Only record a preserved file if Arcane installed it in the first\n // place. Recording one it merely declined to overwrite would claim\n // ownership of an operator-authored file, and `spell uninstall` deletes\n // everything the manifest lists -- so an operator's own .gitignore or\n // DECISIONS.md would be destroyed by an uninstall that never wrote it.\n // A file Arcane DID write must stay recorded, or uninstall leaks it.\n if (!preserveExisting || installed.files.includes(file)) {\n updatedFiles.push(file);\n }\n }\n // Also copy directories\n for (const dir of component.directories ?? []) {\n const srcDirPath = join(assetsDir, dir);\n if (options.dryRun) {\n console.log(` [dry-run] Would update directory: ${dir}/`);\n } else {\n // Directory-tracked files are always freshly generated content\n // (agent rosters, etc.), never hand-edited in place -- unconditional\n // overwrite, same as before ARC-038, is still correct here.\n const copied = await copyDirectory(srcDirPath, targetDir, dir, { force: true });\n for (const { path: copiedPath, hash } of copied) {\n updatedFiles.push(copiedPath);\n fileHashes[copiedPath] = hash;\n }\n fileCount += copied.length;\n }\n }\n\n // TODO.md T10: a file this component tracked before this update but no\n // longer does (dropped from the registry's current file/directory list)\n // is orphaned -- still on disk, no longer represented in the manifest\n // this update is about to write.\n for (const file of installed.files) {\n if (updatedFiles.includes(file)) continue;\n const status = await resolveOrphan(\n targetDir,\n file,\n installed.fileHashes?.[file],\n Boolean(options.prune) && !options.dryRun,\n );\n orphanReport.push({ file, status });\n }\n\n updatedComponents.push({\n ...installed,\n files: updatedFiles,\n installedVersion: packageVersion,\n fileHashes,\n });\n }\n\n // TODO.md T10: report orphans -- files tracked before this update but no\n // longer part of any current component -- in both dry-run and real runs.\n // Only files still present matter; anything already gone needs no action.\n const orphansToReport = orphanReport.filter((o) => o.status !== \"not-found\");\n if (orphansToReport.length > 0) {\n const verb = options.dryRun ? \"[dry-run] Found\" : \"Found\";\n console.log(\n `\\n${verb} ${orphansToReport.length} orphaned file(s) (tracked before this update, no longer part of any current component):`,\n );\n for (const { file, status } of orphansToReport) {\n const marker = status === \"pruned\" ? \"pruned\" : options.prune ? \"kept (see reason above)\" : \"not removed\";\n console.log(` ${file} — ${marker}`);\n }\n if (!options.prune) {\n console.log(\" Run `spell update --prune` to remove the ones that are safe to delete.\");\n }\n }\n\n if (options.dryRun) {\n console.log(\n `\\n[dry-run] Would update ${fileCount} files.`,\n );\n const applicableRetrofits = MANIFEST_RETROFITS.filter((r) => r.needsRetrofit(manifest));\n if (applicableRetrofits.length > 0) {\n console.log(\n `[dry-run] Would ask ${applicableRetrofits.length} manifest retrofit question${applicableRetrofits.length === 1 ? \"\" : \"s\"}: ${applicableRetrofits.map((r) => r.field).join(\", \")}.`,\n );\n }\n return;\n }\n\n // Retrofit wizard: ask about any manifest field this install predates\n // (e.g. `role`), once, before writing the updated manifest.\n //\n // Skipped without a TTY. These are interactive questions, and @inquirer\n // throws ExitPromptError on a closed stdin -- which would crash `update`\n // AFTER files were copied but BEFORE the manifest was written, leaving the\n // repo with new files and a stale recorded version. CI, piped input, and\n // scripted upgrades all land here. The fields stay unset and are asked on\n // the next interactive run, which is exactly how a scripted `init` already\n // behaves.\n const interactive = Boolean(process.stdin.isTTY);\n const retrofitPatch = interactive ? await runManifestRetrofits(manifest) : {};\n if (!interactive) {\n const pending = MANIFEST_RETROFITS.filter((r) => r.needsRetrofit(manifest));\n if (pending.length > 0) {\n console.log(\n ` ! Skipped ${pending.length} manifest question${pending.length === 1 ? \"\" : \"s\"} (${pending\n .map((r) => r.field)\n .join(\", \")}) — no interactive terminal. Run \\`spell update\\` from a terminal to answer.`,\n );\n }\n }\n\n // Update manifest with new version, refreshed component file paths, and\n // any retrofit answers.\n const updated: ArcaneManifest = {\n ...manifest,\n version: packageVersion,\n components: updatedComponents,\n ...retrofitPatch,\n };\n await writeManifest(targetDir, updated);\n\n console.log(\n `\\n\\u2713 Updated ${fileCount} files.`,\n );\n\n // ARC-038 decision 1: the update completes regardless of conflicts -- a\n // conflicted file blocking every other file's update would be a worse\n // outcome than a clearly flagged conflict the operator resolves before\n // committing (this repository's own pre-commit/pre-push hooks, and any\n // CI the operator has, still catch an unresolved <<<<<<< marker before it\n // reaches main).\n if (conflictedFiles.length > 0) {\n console.log(\n `\\n\\u26a0 ${conflictedFiles.length} file(s) have unresolved merge conflicts:\\n` +\n conflictedFiles.map((f) => ` ${f}`).join(\"\\n\") +\n `\\n Search for \"<<<<<<< yours\" and resolve before committing.`,\n );\n }\n\n // If this update just turned the repo into a hub, offer to scaffold the\n // venture registry from whatever already exists under business_root.\n if (manifest.role !== \"hub\" && updated.role === \"hub\") {\n await offerRegistryScaffold(targetDir, updated.business_root ?? \"ventures\");\n }\n}\n","import { confirm, select, input } from \"@inquirer/prompts\";\nimport { readdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { fileExists } from \"./copier.js\";\nimport { isValidSubjectRoot } from \"./manifest.js\";\nimport type {\n ArcaneManifest,\n ContentSensitivity,\n ExternalProvider,\n HubRole,\n PushPolicy,\n TrackingMode,\n} from \"../types.js\";\n\n/**\n * A manifest-field retrofit: a schema question `spell update` asks exactly\n * once, for an installed manifest that predates the field. This is a general\n * migration mechanism, not a one-off for `role` -- future manifest fields\n * register a retrofit here instead of leaving older installs permanently\n * unset.\n */\nexport interface ManifestRetrofit {\n /** Field this retrofit introduces on ArcaneManifest, for logging only. */\n field: string;\n /** True if the installed manifest predates this field and should be asked. */\n needsRetrofit(manifest: ArcaneManifest): boolean;\n /**\n * Ask the operator (or apply a deterministic default); return the partial\n * patch to merge into the manifest. Receives the manifest so a retrofit\n * can branch on already-known fields (e.g. profile) the way the\n * tracking_mode retrofit below does -- entries that don't need it (role)\n * simply ignore the parameter.\n */\n ask(manifest: ArcaneManifest): Promise<Partial<ArcaneManifest>>;\n}\n\nexport const MANIFEST_RETROFITS: ManifestRetrofit[] = [\n {\n field: \"role\",\n needsRetrofit: (m) => m.role === undefined,\n ask: async () => {\n const isHub = await confirm({\n message:\n \"Will this repo manage other ventures as a hub? (idea books, spell-manifest promotion, venture registry)\",\n default: false,\n });\n return { role: (isHub ? \"hub\" : \"consumer\") as HubRole };\n },\n },\n {\n field: \"tracking_mode\",\n needsRetrofit: (m) => m.tracking_mode === undefined,\n // Mirrors init.ts's Step 5b branching exactly (EF-14 D5): docs-only\n // profiles get a silent default, full/lite get asked.\n ask: async (manifest) => {\n if (\n manifest.profile === \"governance-only\" ||\n manifest.profile === \"methodology\" ||\n manifest.profile === \"docs\"\n ) {\n return { tracking_mode: \"internal\" as TrackingMode, external_provider: null };\n }\n const tracking_mode = (await select({\n message: \"How will work be tracked in this repo?\",\n choices: [\n { value: \"internal\", name: \"Track work in this repo (TODO.md / PRDs)\" },\n { value: \"external\", name: \"Track work in an external tracker (Azure DevOps / GitHub / Jira / other)\" },\n ],\n })) as TrackingMode;\n if (tracking_mode === \"external\") {\n const external_provider = (await select({\n message: \"Which external tracker?\",\n choices: [\n { value: \"ado\", name: \"Azure DevOps\" },\n { value: \"github\", name: \"GitHub Issues\" },\n { value: \"jira\", name: \"Jira\" },\n { value: \"other\", name: \"Other\" },\n ],\n })) as ExternalProvider;\n return { tracking_mode, external_provider };\n }\n return { tracking_mode, external_provider: null };\n },\n },\n {\n field: \"content_sensitivity\",\n needsRetrofit: (m) => m.content_sensitivity === undefined,\n // EF-12. Asked for every profile -- a code repo can hold sensitive records\n // too -- and defaults to \"standard\", so an operator who just presses enter\n // keeps today's behaviour exactly.\n ask: async () => {\n const content_sensitivity = (await select({\n message: \"How should agents treat this repository's contents?\",\n choices: [\n {\n value: \"standard\",\n name: \"Standard — agents may quote contents in journals and decisions\",\n },\n {\n value: \"sensitive\",\n name: \"Sensitive — agents reference documents by path, never transcribe them\",\n },\n ],\n default: \"standard\",\n })) as ContentSensitivity;\n return { content_sensitivity };\n },\n },\n {\n field: \"subject_root\",\n // EF-07. Only the docs profile is asked: other profiles describe code or a\n // venture portfolio, where \"what is this repo about\" is already answered.\n // A docs install that legitimately holds several subjects answers\n // \"portfolio\" and stays unset -- so this retrofit deliberately does NOT\n // re-ask on every update. It is gated on the field being absent AND the\n // profile being docs, and once answered (either way) it never fires again,\n // because \"portfolio\" writes an explicit empty marker.\n needsRetrofit: (m) => m.profile === \"docs\" && m.subject_root === undefined,\n ask: async () => {\n const shape = await select({\n message: \"What does this repository hold?\",\n choices: [\n {\n value: \"root\",\n name: \"One subject, at the repository root (documents sit alongside Arcane's files)\",\n },\n { value: \"subdir\", name: \"One subject, in its own directory\" },\n { value: \"portfolio\", name: \"Several subjects or ventures\" },\n ],\n });\n if (shape === \"root\") return { subject_root: \".\" };\n if (shape === \"subdir\") {\n const answer = await input({\n message: \"Directory holding the subject's documents:\",\n default: \"docs\",\n validate: (v) =>\n isValidSubjectRoot(v.trim() || \"docs\") ||\n \"Must be a relative path inside the repository (no leading /, drive letter, or ..).\",\n });\n return { subject_root: answer.trim() || \"docs\" };\n }\n // Portfolio: business_root covers this shape. Recorded as an explicit\n // null rather than left unset, so the question isn't re-asked on every\n // future update.\n return { subject_root: null };\n },\n },\n {\n field: \"push_policy\",\n needsRetrofit: (m) => m.push_policy === undefined,\n // EF-09. Defaults to \"open\", so an operator who just presses enter keeps\n // today's behaviour exactly. NOTE: this only records the choice -- unlike\n // init, the retrofit does not install the hook or disable the push URL,\n // because an update should not silently start blocking pushes in a repo\n // someone is mid-workflow in. doctor reports the gap instead.\n ask: async () => {\n const push_policy = (await select({\n message: \"Should this repository be allowed to push to a remote?\",\n choices: [\n { value: \"open\", name: \"Yes — normal repository\" },\n { value: \"guarded\", name: \"Sensitive, but keep push working — remind me instead\" },\n { value: \"blocked\", name: \"No — block pushes\" },\n ],\n default: \"open\",\n })) as PushPolicy;\n return { push_policy };\n },\n },\n];\n\n/**\n * Runs every retrofit question the installed manifest predates, in order.\n * Returns the partial patch to merge into the manifest being written.\n * Returns {} immediately (no questions, no console output) if nothing\n * applies -- callers should only invoke this outside dry-run and\n * non-interactive modes.\n */\nexport async function runManifestRetrofits(\n manifest: ArcaneManifest,\n): Promise<Partial<ArcaneManifest>> {\n const applicable = MANIFEST_RETROFITS.filter((r) => r.needsRetrofit(manifest));\n if (applicable.length === 0) return {};\n\n console.log();\n console.log(\n `This install predates ${applicable.length} manifest field${applicable.length === 1 ? \"\" : \"s\"} -- a couple of quick questions:`,\n );\n\n let patch: Partial<ArcaneManifest> = {};\n for (const retrofit of applicable) {\n const answer = await retrofit.ask({ ...manifest, ...patch });\n patch = { ...patch, ...answer };\n }\n return patch;\n}\n\n/**\n * Offers to scaffold `{business_root}/registry.json` from existing venture\n * folders, once `role` has just become \"hub\" (via init or retrofit). Never\n * overwrites an existing registry. No-ops silently (no prompt, no output) if\n * the business root doesn't exist or holds no venture folders -- a brand new\n * hub with nothing under `ventures/` yet has nothing to scaffold.\n */\nexport async function offerRegistryScaffold(\n targetDir: string,\n businessRoot: string,\n): Promise<void> {\n const registryPath = join(targetDir, businessRoot, \"registry.json\");\n if (await fileExists(registryPath)) return;\n\n const businessRootPath = join(targetDir, businessRoot);\n let ventureDirs: string[];\n try {\n const entries = await readdir(businessRootPath, { withFileTypes: true });\n ventureDirs = entries\n .filter((e) => e.isDirectory() && e.name !== \"_template\")\n .map((e) => e.name);\n } catch {\n return;\n }\n if (ventureDirs.length === 0) return;\n\n console.log();\n const scaffold = await confirm({\n message: `Found ${ventureDirs.length} folder${ventureDirs.length === 1 ? \"\" : \"s\"} under ${businessRoot}/ -- scaffold ${businessRoot}/registry.json from them?`,\n default: true,\n });\n if (!scaffold) return;\n\n const ventures: Record<string, unknown> = {};\n for (const slug of ventureDirs) {\n const include = await confirm({ message: ` Include \"${slug}\"?`, default: true });\n if (!include) continue;\n ventures[slug] = {\n name: slug,\n aliases: [],\n status: \"active\",\n visibility: \"private\",\n ownership: \"llc\",\n tracking: \"none\",\n repos: [],\n };\n }\n if (Object.keys(ventures).length === 0) {\n console.log(\" No ventures selected -- registry not created.\");\n return;\n }\n\n const registry = {\n _comment:\n \"Hub-owned venture registry. Private. Never installed or modified by spell update. \" +\n \"Seeded by the retrofit wizard -- review and enrich (aliases, ownership, tracking, \" +\n \"clones) before relying on it.\",\n updated: new Date().toISOString().slice(0, 10),\n ventures,\n };\n await writeFile(registryPath, JSON.stringify(registry, null, 2) + \"\\n\", \"utf-8\");\n console.log(\n ` ✓ Scaffolded ${businessRoot}/registry.json with ${Object.keys(ventures).length} venture(s).`,\n );\n}\n","/**\n * Line-based three-way text merge (ARC-038 decision 1).\n *\n * `spell update` uses this to reconcile an operator's edited copy of a\n * shipped file against a new vendor version, without silently discarding the\n * edit: `base` is the OLD vendor content the operator's edit started from,\n * `ours` is the operator's current on-disk content, `theirs` is the NEW\n * vendor content about to be installed. Non-overlapping changes on each side\n * merge automatically; a region both sides changed differently becomes a\n * conflict, marked the same way `git merge` marks one.\n *\n * Deliberately line-granular, not character-granular -- the same mental\n * model a human resolving a merge conflict already has, and the one ARC-038\n * itself names (\"the same shape copier's regenerate-old/diff/regenerate-new/\n * merge approach uses\").\n */\n\nexport const CONFLICT_START = \"<<<<<<< yours (edited)\";\nexport const CONFLICT_MID = \"=======\";\nexport const CONFLICT_END = \">>>>>>> incoming (vendor update)\";\n\ninterface DiffOp {\n type: \"equal\" | \"replace\";\n baseStart: number;\n baseEnd: number;\n otherStart: number;\n otherEnd: number;\n}\n\n/**\n * Line-based LCS diff of `base` against `other`. DP table is O(n*m) time and\n * space -- fine for governance-doc-sized files (hundreds to low thousands of\n * lines); `merge3` falls back to a whole-file conflict rather than running\n * this on pathologically large inputs (see MAX_LINES_FOR_LCS below).\n */\nfunction computeLcsDiff(base: string[], other: string[]): DiffOp[] {\n const n = base.length;\n const m = other.length;\n const dp: Uint32Array[] = Array.from({ length: n + 1 }, () => new Uint32Array(m + 1));\n for (let i = n - 1; i >= 0; i--) {\n for (let j = m - 1; j >= 0; j--) {\n dp[i]![j] =\n base[i] === other[j] ? dp[i + 1]![j + 1]! + 1 : Math.max(dp[i + 1]![j]!, dp[i]![j + 1]!);\n }\n }\n\n const ops: DiffOp[] = [];\n let i = 0;\n let j = 0;\n let pendingBaseStart = 0;\n let pendingOtherStart = 0;\n\n const flushReplace = (baseEnd: number, otherEnd: number) => {\n if (baseEnd > pendingBaseStart || otherEnd > pendingOtherStart) {\n ops.push({\n type: \"replace\",\n baseStart: pendingBaseStart,\n baseEnd,\n otherStart: pendingOtherStart,\n otherEnd,\n });\n }\n };\n\n while (i < n && j < m) {\n if (base[i] === other[j]) {\n flushReplace(i, j);\n const eqBaseStart = i;\n const eqOtherStart = j;\n while (i < n && j < m && base[i] === other[j]) {\n i++;\n j++;\n }\n ops.push({ type: \"equal\", baseStart: eqBaseStart, baseEnd: i, otherStart: eqOtherStart, otherEnd: j });\n pendingBaseStart = i;\n pendingOtherStart = j;\n } else if (dp[i + 1]![j]! >= dp[i]![j + 1]!) {\n i++;\n } else {\n j++;\n }\n }\n flushReplace(n, m);\n return ops;\n}\n\nfunction arraysEqual(a: string[], b: string[]): boolean {\n if (a.length !== b.length) return false;\n return a.every((line, idx) => line === b[idx]);\n}\n\nexport interface Merge3Result {\n content: string;\n hasConflict: boolean;\n}\n\n/**\n * Files larger than this fall back to a single whole-file conflict rather\n * than running the O(n*m) LCS diff -- a correctness-preserving degradation\n * (the operator is never silently overwritten, they're just not offered an\n * auto-merge for a file this large), not a crash or a silent choice of one\n * side. No governance/prompt content shipped by Arcane comes close to this.\n */\nconst MAX_LINES_FOR_LCS = 4000;\n\n/** Splits on \\n, preserving trailing-newline presence as the final \"\" element does. */\nfunction splitLines(text: string): string[] {\n return text.split(\"\\n\");\n}\n\n/**\n * Merges `theirs` (new vendor content) onto `ours` (the operator's edited\n * content), using `base` (old vendor content) as the common ancestor.\n *\n * Never throws and never silently prefers one side: a region changed\n * differently by both sides is always marked as a conflict in the returned\n * content, and `hasConflict` tells the caller whether any such region\n * existed, so update.ts can report it rather than commit it quietly.\n */\nexport function merge3(base: string, ours: string, theirs: string): Merge3Result {\n const baseLines = splitLines(base);\n const oursLines = splitLines(ours);\n const theirsLines = splitLines(theirs);\n\n if (\n baseLines.length > MAX_LINES_FOR_LCS ||\n oursLines.length > MAX_LINES_FOR_LCS ||\n theirsLines.length > MAX_LINES_FOR_LCS\n ) {\n return {\n content: [CONFLICT_START, ours, CONFLICT_MID, theirs, CONFLICT_END].join(\"\\n\"),\n hasConflict: true,\n };\n }\n\n const oursOps = computeLcsDiff(baseLines, oursLines).filter((op) => op.type === \"replace\");\n const theirsOps = computeLcsDiff(baseLines, theirsLines).filter((op) => op.type === \"replace\");\n\n if (oursOps.length === 0 && theirsOps.length === 0) {\n return { content: base, hasConflict: false };\n }\n\n interface ChangedInterval {\n baseStart: number;\n baseEnd: number;\n source: \"ours\" | \"theirs\";\n lines: string[];\n }\n const intervals: ChangedInterval[] = [\n ...oursOps.map((op) => ({\n baseStart: op.baseStart,\n baseEnd: op.baseEnd,\n source: \"ours\" as const,\n lines: oursLines.slice(op.otherStart, op.otherEnd),\n })),\n ...theirsOps.map((op) => ({\n baseStart: op.baseStart,\n baseEnd: op.baseEnd,\n source: \"theirs\" as const,\n lines: theirsLines.slice(op.otherStart, op.otherEnd),\n })),\n ].sort((a, b) => a.baseStart - b.baseStart || a.baseEnd - b.baseEnd);\n\n // Coalesce intervals that overlap in BASE-line space, from either side,\n // into groups -- two edits any distance apart in \"ours\" and \"theirs\" text\n // can still collide if they touch the same base lines, which is exactly\n // the case a merge must resolve as one unit, not two independent ones.\n const groups: ChangedInterval[][] = [];\n let groupMaxEnd = -1;\n for (const iv of intervals) {\n const current = groups[groups.length - 1];\n if (current && iv.baseStart < groupMaxEnd) {\n current.push(iv);\n groupMaxEnd = Math.max(groupMaxEnd, iv.baseEnd);\n } else {\n groups.push([iv]);\n groupMaxEnd = iv.baseEnd;\n }\n }\n\n const resultLines: string[] = [];\n let hasConflict = false;\n let basePos = 0;\n\n for (const group of groups) {\n const groupStart = Math.min(...group.map((g) => g.baseStart));\n const groupEnd = Math.max(...group.map((g) => g.baseEnd));\n\n resultLines.push(...baseLines.slice(basePos, groupStart));\n\n const oursInGroup = group.filter((g) => g.source === \"ours\");\n const theirsInGroup = group.filter((g) => g.source === \"theirs\");\n\n if (oursInGroup.length > 0 && theirsInGroup.length === 0) {\n for (const g of oursInGroup) resultLines.push(...g.lines);\n } else if (theirsInGroup.length > 0 && oursInGroup.length === 0) {\n for (const g of theirsInGroup) resultLines.push(...g.lines);\n } else {\n const oursGroupLines = oursInGroup.flatMap((g) => g.lines);\n const theirsGroupLines = theirsInGroup.flatMap((g) => g.lines);\n if (arraysEqual(oursGroupLines, theirsGroupLines)) {\n // Converged edit -- both sides changed this region to the same\n // result, so there is nothing to actually resolve.\n resultLines.push(...oursGroupLines);\n } else {\n hasConflict = true;\n resultLines.push(CONFLICT_START, ...oursGroupLines, CONFLICT_MID, ...theirsGroupLines, CONFLICT_END);\n }\n }\n\n basePos = groupEnd;\n }\n resultLines.push(...baseLines.slice(basePos));\n\n return { content: resultLines.join(\"\\n\"), hasConflict };\n}\n","/**\n * Fetches one file's content from a specific PUBLISHED version of this\n * package (ARC-038 decision 1) -- the merge base for `spell update`'s\n * content-preserving update, without vendoring a second copy of every past\n * release: npm's own registry already permanently retains every published\n * tarball.\n *\n * npm's registry API has no \"browse one file from one version\" endpoint, and\n * hand-rolling tarball extraction for a read-one-file use case is a\n * correctness risk this project has no existing dependency to cover safely.\n * unpkg.com serves directly from that same registry tarball, so this reaches\n * the identical permanent history the ADR describes, through a widely-used,\n * purpose-built CDN rather than new vendoring infrastructure. Resolved\n * in-implementation (ARC-038 left the exact fetch mechanism open); no local\n * caching, also resolved in-implementation -- within one `spell update` run\n * each (version, file) pair is fetched at most once already, and this\n * command runs rarely enough that cross-run caching is not worth the extra\n * invalidation surface.\n */\nconst NPM_PACKAGE_NAME = \"arcane-cli\";\n\n/**\n * Returns the file's text content, or `undefined` if it could not be\n * fetched (network failure, non-2xx response, or any other error) --\n * callers must treat `undefined` as \"cannot verify what changed,\" never as\n * \"no prior content,\" since silently treating a fetch failure as an empty\n * base would make the merge invent a huge fake diff instead of correctly\n * refusing to guess.\n */\nexport async function fetchPublishedFile(\n version: string,\n relativeAssetPath: string,\n): Promise<string | undefined> {\n const normalized = relativeAssetPath.replace(/\\\\/g, \"/\").replace(/^\\/+/, \"\");\n const url = `https://unpkg.com/${NPM_PACKAGE_NAME}@${version}/dist/assets/${normalized}`;\n try {\n const response = await fetch(url);\n if (!response.ok) return undefined;\n return await response.text();\n } catch {\n return undefined;\n }\n}\n","import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { createRequire } from \"node:module\";\nimport type { VersionCheckResult } from \"../types.js\";\n\nconst require = createRequire(import.meta.url);\n\ninterface PackageJson {\n publishConfig?: { registry?: string };\n}\n\n/** Read the feed URL from the package's own publishConfig.registry — never hardcoded. */\nexport function getFeedUrl(): string {\n const pkg = require(\"../../package.json\") as PackageJson;\n const url = pkg.publishConfig?.registry;\n if (!url) {\n throw new Error(\n \"publishConfig.registry is not set in package.json. Cannot resolve npm feed URL.\",\n );\n }\n return url;\n}\n\nconst DEFAULT_CACHE_PATH = join(homedir(), \".arcane\", \"version-cache.json\");\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours\n\ninterface CacheEntry {\n latest: string;\n checkedAt: string;\n}\n\n/**\n * Reads the version cache file. Returns null if missing or malformed.\n */\nexport async function readCache(\n cachePath: string,\n): Promise<CacheEntry | null> {\n try {\n const content = await readFile(cachePath, \"utf-8\");\n const parsed = JSON.parse(content) as CacheEntry;\n if (typeof parsed.latest !== \"string\" || typeof parsed.checkedAt !== \"string\") {\n return null;\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\n/**\n * Writes the version cache file, creating parent directories as needed.\n */\nexport async function writeCache(\n cachePath: string,\n latest: string,\n): Promise<void> {\n await mkdir(dirname(cachePath), { recursive: true });\n const entry: CacheEntry = { latest, checkedAt: new Date().toISOString() };\n await writeFile(cachePath, JSON.stringify(entry, null, 2), \"utf-8\");\n}\n\n/**\n * Fetches the latest published version of arcane-cli from the public npm\n * registry. Returns null (does not throw) on any network failure.\n */\nexport async function getLatestVersion(feedUrl: string): Promise<string | null> {\n const normalizedBase = feedUrl.endsWith(\"/\") ? feedUrl : feedUrl + \"/\";\n const url = `${normalizedBase}arcane-cli`;\n try {\n const response = await fetch(url, {\n headers: { Accept: \"application/json\" },\n signal: AbortSignal.timeout(5000),\n });\n if (!response.ok) return null;\n const body = await response.json() as { \"dist-tags\"?: { latest?: string } };\n return body[\"dist-tags\"]?.latest ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Checks for a newer version of the package, using a 24h file cache.\n * Never throws — errors are captured in VersionCheckResult.error.\n */\nexport async function checkForUpdate(\n currentVersion: string,\n feedUrl: string,\n cachePath: string = DEFAULT_CACHE_PATH,\n): Promise<VersionCheckResult> {\n try {\n let latest: string | null = null;\n\n const cached = await readCache(cachePath);\n if (cached) {\n const age = Date.now() - new Date(cached.checkedAt).getTime();\n if (age < CACHE_TTL_MS) {\n latest = cached.latest;\n }\n }\n\n if (latest === null) {\n latest = await getLatestVersion(feedUrl);\n if (latest !== null) {\n try {\n await writeCache(cachePath, latest);\n } catch {\n // Cache write failure is non-fatal\n }\n }\n }\n\n return {\n current: currentVersion,\n latest,\n updateAvailable: latest !== null && latest !== currentVersion,\n };\n } catch (err) {\n return {\n current: currentVersion,\n latest: null,\n updateAvailable: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n}\n","/**\n * Generates the canonical version-drift gitGraph diagram (ARC-036, R2) from\n * the three already-computed version readings. Pure — no I/O, no network\n * calls. Mirrors spell-open-session.prompt.md's \"Arcane version check\n * (two-axis)\" template exactly, so the CLI (`spell status`) and the prompt\n * produce the identical shape from the same three inputs.\n */\n\n/**\n * Returns the gitGraph body (no ```mermaid fence — the caller chooses\n * fencing per R5) for the three-reading version-drift diagram, or `null`\n * when all three readings match (the applicability guard — nothing to\n * visualize for a single, matching reading).\n *\n * One commit per *distinct* value among the three readings, in\n * repo-files -> installed-CLI -> npm-latest order; a consecutive repeated\n * value collapses into its neighbor's commit rather than repeating it.\n * Branches off after the commit for each axis that drifts.\n */\nexport function generateVersionDriftDiagram(\n repoFilesVersion: string,\n installedCliVersion: string,\n npmLatestVersion: string,\n): string | null {\n if (\n repoFilesVersion === installedCliVersion &&\n installedCliVersion === npmLatestVersion\n ) {\n return null;\n }\n\n const lines = [\"gitGraph\", ` commit id: \"${repoFilesVersion}\"`];\n let lastDistinctVersion = repoFilesVersion;\n\n if (installedCliVersion !== repoFilesVersion) {\n lines.push(\n \" branch repo-files\",\n \" checkout main\",\n ` commit id: \"${installedCliVersion}\"`,\n );\n lastDistinctVersion = installedCliVersion;\n }\n\n if (npmLatestVersion !== lastDistinctVersion) {\n lines.push(\n \" branch installed-cli\",\n \" checkout main\",\n ` commit id: \"${npmLatestVersion}\" tag: \"latest\"`,\n );\n } else {\n lines[lines.length - 1] += ' tag: \"latest\"';\n }\n\n return lines.join(\"\\n\");\n}\n","import {\n readManifest,\n ManifestNotFoundError,\n} from \"../modules/manifest.js\";\nimport {\n checkForUpdate,\n getFeedUrl,\n} from \"../modules/version-check.js\";\nimport { generateVersionDriftDiagram } from \"../modules/diagram-generator.js\";\n\n/**\n * Runs the `spell status` command.\n *\n * Reads .arcane.json, checks for an available update, then prints\n * a formatted table of installed components + a version footer.\n *\n * @param targetDir Directory containing the Arcane installation\n * @param packageVersion Current package version string\n */\nexport async function runStatus(\n targetDir: string,\n packageVersion: string,\n): Promise<void> {\n // Read existing manifest\n let manifest;\n try {\n manifest = await readManifest(targetDir);\n } catch (err) {\n if (err instanceof ManifestNotFoundError) {\n console.error(\n 'Not initialized. Run \"spell init\" first.',\n );\n process.exit(1);\n return; // guard: process.exit is mocked in tests\n }\n throw err;\n }\n\n if (manifest.components.length === 0) {\n console.log(\"No components installed.\");\n return;\n }\n\n // Check for update (never throws)\n let feedUrl: string;\n try {\n feedUrl = getFeedUrl();\n } catch {\n feedUrl = \"\";\n }\n\n const versionResult = feedUrl\n ? await checkForUpdate(packageVersion, feedUrl)\n : { current: packageVersion, latest: null, updateAvailable: false, error: \"Feed URL unavailable\" };\n\n // ─── Print component table ─────────────────────────────────────────────────\n\n // Compute column widths\n const nameWidth = Math.max(\n \"Component\".length,\n ...manifest.components.map((c) => c.name.length),\n );\n const filesWidth = \"Files\".length;\n const versionWidth = Math.max(\n \"Version\".length,\n ...manifest.components.map((c) => c.installedVersion.length),\n );\n\n const pad = (s: string, n: number) => s.padEnd(n);\n const rpad = (s: string, n: number) => s.padStart(n);\n\n console.log(\n ` ${pad(\"Component\", nameWidth)} ${rpad(\"Files\", filesWidth)} ${pad(\"Version\", versionWidth)}`,\n );\n console.log(\n ` ${\"-\".repeat(nameWidth)} ${\"-\".repeat(filesWidth)} ${\"-\".repeat(versionWidth)}`,\n );\n\n for (const component of manifest.components) {\n const label = component.name;\n const fileCount = component.files.length.toString();\n const displayVersion = component.installedVersion;\n console.log(\n ` ${pad(label, nameWidth)} ${rpad(fileCount, filesWidth)} ${displayVersion}`,\n );\n }\n\n // ─── Version footer ────────────────────────────────────────────────────────\n\n console.log(\"\");\n\n const latestStr = versionResult.error\n ? \"unable to check\"\n : (versionResult.latest ?? manifest.version);\n\n let footer = ` Installed: ${packageVersion} Latest: ${latestStr}`;\n\n if (versionResult.updateAvailable) {\n footer += \" (spell update available)\";\n }\n\n console.log(footer);\n\n // ─── Version-drift diagram (ARC-036 R8) ────────────────────────────────────\n // Axis A (repo-files vs installed CLI) needs no network call and is always\n // checkable. Axis B (installed CLI vs npm-latest) needs versionResult.latest,\n // which is null when the npm check failed — skip the diagram entirely in\n // that case rather than showing a partial, potentially misleading picture;\n // the \"Latest: unable to check\" footer above already covers that failure.\n if (versionResult.latest !== null) {\n const diagram = generateVersionDriftDiagram(\n manifest.version,\n packageVersion,\n versionResult.latest,\n );\n\n if (diagram !== null) {\n console.log(\"\");\n if (process.stdout.isTTY) {\n // Interactive terminal: a fenced Mermaid block doesn't render here —\n // print the same three readings as plain aligned text instead.\n console.log(\" Version drift:\");\n console.log(` repo-files: ${manifest.version}`);\n console.log(` installed-cli: ${packageVersion}`);\n console.log(` latest (npm): ${versionResult.latest}`);\n } else {\n // Piped (file, another tool, a captured PR body): emit the real\n // diagram so the redirected output is directly usable.\n console.log(\"```mermaid\");\n console.log(diagram);\n console.log(\"```\");\n }\n }\n }\n}\n","import { rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { confirm } from \"@inquirer/prompts\";\nimport {\n readManifest,\n ManifestNotFoundError,\n} from \"../modules/manifest.js\";\nimport { stripMarkerSection } from \"../modules/merger.js\";\nimport { isHookEnforced, blockedRemotes } from \"../modules/push-safety.js\";\nimport { removeSecretsPrecommitHook } from \"../modules/secrets-scan.js\";\n\n/**\n * Runs the `spell uninstall` command.\n *\n * Deletes every file tracked in .arcane.json then removes .arcane.json itself.\n * Prompts for confirmation unless --yes is passed.\n *\n * @param options.yes Skip confirmation prompt\n * @param options.dryRun Preview what would be removed without deleting files\n * @param targetDir Directory containing the Arcane installation\n */\nexport async function runUninstall(\n options: { yes?: boolean; dryRun?: boolean },\n targetDir: string,\n): Promise<void> {\n // Read existing manifest\n let manifest;\n try {\n manifest = await readManifest(targetDir);\n } catch (err) {\n if (err instanceof ManifestNotFoundError) {\n console.error('Not initialized. Run \"spell init\" first.');\n process.exit(1);\n return; // guard: process.exit is mocked in tests\n }\n throw err;\n }\n\n // A push-blocked repository must not be uninstalled while the block stands.\n //\n // Uninstall deletes .arcane.json but has no idea about core.hooksPath or the\n // sentinel push URLs, so the repo was left unable to push while `spell\n // unblock-push` -- the only supported way out -- refused to run because the\n // manifest it reads was gone. The operator was told \"Uninstalled\" and handed\n // a repository whose recovery required hand-editing git config.\n //\n // Refusing is the right shape rather than silently unblocking: ARC-034 R5\n // makes lifting the block a deliberate, interactive, separately-confirmed act,\n // and quietly doing it as a side effect of `uninstall --yes` would hand any\n // script exactly the bypass that command exists to deny.\n // Keyed on what the repository ACTUALLY has, not only on what the manifest\n // declares. A manifest-only check is the same declaration-versus-enforcement\n // confusion this feature exists to remove, and it is reachable without anyone\n // hand-editing: a partially-failed `unblock-push` writes push_policy \"open\"\n // while remotes stay blocked, after which uninstall would strand the repo\n // exactly as before.\n const policy = manifest.push_policy ?? \"open\";\n const controlsInForce =\n (await isHookEnforced(targetDir)) || (await blockedRemotes(targetDir)).length > 0;\n if ((policy === \"blocked\" || controlsInForce) && !options.dryRun) {\n const why =\n policy === \"blocked\"\n ? `this repository's push_policy is \"blocked\"`\n : `this repository still has Arcane's push block in force (the manifest says \"${policy}\", ` +\n \"but the controls are actually installed)\";\n console.error(\n `Refusing to uninstall: ${why}.\\n` +\n \"Uninstalling now would delete .arcane.json while leaving the pre-push hook and the\\n\" +\n \"disabled push URLs in place — the repository could not push, and `spell unblock-push`\\n\" +\n \"would no longer recognise it.\\n\\n\" +\n \"Run `spell unblock-push` first (interactive), then uninstall.\",\n );\n process.exit(1);\n return; // guard: process.exit is mocked in tests\n }\n\n // Count total tracked files\n const allFiles = manifest.components.flatMap((c) => c.files);\n const totalFiles = allFiles.length;\n\n // Dry-run: print what would be removed without deleting\n if (options.dryRun) {\n for (const file of allFiles) {\n console.log(`[dry-run] Would remove: ${file}`);\n }\n console.log(`[dry-run] Would remove: .arcane.json`);\n console.log(`[dry-run] Would remove: .github/agents/ (directory)`);\n console.log(`[dry-run] Would remove: .arcane/agents/ (directory)`);\n console.log(`[dry-run] Would remove: .arcane/generated/ (directory)`);\n console.log(`[dry-run] Would remove: .arcane/agents.yaml`);\n console.log(`[dry-run] Would strip arcane sections from: CLAUDE.md, AGENTS.md, copilot-instructions.md`);\n console.log(`\\n[dry-run] ${totalFiles} file(s) + manifest + agent outputs would be removed.`);\n if (policy === \"blocked\" || controlsInForce) {\n console.log(\n `[dry-run] BUT the real run would refuse: Arcane's push block is in force. Run \\`spell unblock-push\\` first.`,\n );\n }\n return;\n }\n\n // Confirmation prompt (skipped with --yes)\n if (!options.yes) {\n const confirmed = await confirm({\n message: `This will remove ${totalFiles} files and .arcane.json. Continue?`,\n default: false,\n });\n\n if (!confirmed) {\n console.log(\"Uninstall cancelled.\");\n return;\n }\n }\n\n // Delete each file tracked in the manifest\n let removed = 0;\n for (const component of manifest.components) {\n for (const file of component.files) {\n const filePath = join(targetDir, file);\n try {\n await rm(filePath, { force: true });\n removed++;\n } catch {\n // Non-existent files are fine (force: true), but other errors propagate\n }\n }\n }\n\n // Delete .arcane.json\n await rm(join(targetDir, \".arcane.json\"), { force: true });\n\n // ── Clean up agent sync outputs (not tracked in manifest) ──────────────\n // Directories created by agent init/sync\n const agentDirs = [\n \".github/agents\",\n \".arcane/agents\",\n \".arcane/generated\",\n ];\n for (const dir of agentDirs) {\n await rm(join(targetDir, dir), { recursive: true, force: true });\n }\n // Roster file\n await rm(join(targetDir, \".arcane/agents.yaml\"), { force: true });\n\n // Strip arcane marker sections from merged files (keeps user content intact)\n const markerFiles = [\n \"CLAUDE.md\",\n \"AGENTS.md\",\n \".github/copilot-instructions.md\",\n ];\n for (const file of markerFiles) {\n await stripMarkerSection(targetDir, file, { dryRun: false });\n }\n\n // Secrets pre-commit hook (ARC-037): installed unconditionally by `spell\n // init` regardless of push_policy, so -- unlike the push-safety pre-push\n // hook -- there is no push_policy invariant above already guaranteeing\n // nothing is left behind. Without this, the hook would keep running\n // `spell doctor --leaks` against a project that no longer has an\n // .arcane.json to configure it, since `spell` itself is a separate global\n // install this command never touches. Best-effort: a failure here is a\n // leftover local convenience hook, not a reason to report uninstall itself\n // as failed.\n try {\n await removeSecretsPrecommitHook(targetDir);\n } catch {\n // Non-fatal.\n }\n\n console.log(`\\n✓ Uninstalled — ${removed} files removed.`);\n}\n","import { access, readFile, mkdir, copyFile as fsCopyFile } from \"node:fs/promises\";\nimport { join, dirname } from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { INCIDENT_QUEUE } from \"../config/incidents.js\";\nimport type { Delegation, DelegationsFile } from \"../types.js\";\nimport { evaluateIncidentGate } from \"../modules/incident-gate.js\";\nimport { runGit } from \"../modules/git.js\";\nimport { readManifest, resolveSecretsScanExcludePrefixes } from \"../modules/manifest.js\";\nimport { scanRepository } from \"../modules/denylist-scan.js\";\nimport { SECRETS_RULES } from \"../modules/secrets-scan.js\";\nimport {\n isHookEnforced,\n listRemotes,\n undisabledRemotes,\n pushTargets,\n} from \"../modules/push-safety.js\";\nimport {\n parseGitHubRemote,\n parseAdoRemote,\n fetchGitHubRulesets,\n fetchAdoMergeTypePolicies,\n evaluateGitHubMergePolicy,\n evaluateAdoMergePolicy,\n} from \"../modules/platform-policy.js\";\n\nconst execFileAsync = promisify(execFile);\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\ninterface CheckResult {\n name: string;\n passed: boolean;\n message: string;\n /** If false, this is a warning, not a blocker. Defaults to true (blocking). */\n blocking?: boolean;\n}\n\n// ─── Runtime validation helpers ───────────────────────────────────────────────\n// Every JSON file below is an external boundary (hand-editable, or written by\n// an older/foreign version of this tool) -- `JSON.parse` only proves \"valid\n// JSON\", never \"matches the shape this code assumes\". An unchecked `as` cast\n// on a non-object parse (e.g. a file containing the literal `null`) let a\n// later `.foo` access throw *outside* the surrounding try/catch, crashing\n// the whole `spell doctor` run instead of reporting one degraded check.\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n// ─── Individual checks ────────────────────────────────────────────────────────\n\nasync function checkNodeVersion(): Promise<CheckResult> {\n const name = \"Node.js version\";\n const raw = process.version; // e.g. \"v20.11.0\"\n const major = parseInt(raw.replace(/^v/, \"\").split(\".\")[0] ?? \"0\", 10);\n if (major >= 18) {\n return { name, passed: true, message: `${raw} (>=18 required)` };\n }\n return {\n name,\n passed: false,\n message: `${raw} — Node.js 18 or later is required`,\n };\n}\n\nasync function checkVSCodeExtension(\n id: string,\n label: string,\n): Promise<CheckResult> {\n const name = `VS Code extension: ${label}`;\n // Check extension directories on disk — more reliable than --list-extensions\n // in child process contexts (snap binaries may not output to non-TTY stdout).\n const home = process.env[\"HOME\"] ?? \"\";\n const extDirs = [\n join(home, \".vscode\", \"extensions\"),\n join(home, \".vscode-insiders\", \"extensions\"),\n ];\n\n for (const dir of extDirs) {\n try {\n const { readdir } = await import(\"node:fs/promises\");\n const entries = await readdir(dir);\n const prefix = id.toLowerCase() + \"-\";\n const found = entries.some(\n (e) => e.toLowerCase() === id.toLowerCase() || e.toLowerCase().startsWith(prefix),\n );\n if (found) {\n return { name, passed: true, message: `${id} is installed` };\n }\n } catch {\n // Directory doesn't exist — skip\n }\n }\n\n // Determine install command (prefer code-insiders if present)\n let installBin = \"code\";\n for (const bin of [\"code\", \"code-insiders\"]) {\n try {\n await execFileAsync(bin, [\"--version\"]);\n installBin = bin;\n break;\n } catch {\n // not found\n }\n }\n\n return {\n name,\n passed: false,\n message: `${id} not found. Install via: ${installBin} --install-extension ${id}`,\n blocking: false,\n };\n}\n\nexport async function checkArcaneManifest(targetDir: string): Promise<CheckResult> {\n const name = \"Arcane manifest (.arcane.json)\";\n const manifestPath = join(targetDir, \".arcane.json\");\n try {\n await access(manifestPath);\n } catch {\n const selfHostedManifestPath = join(targetDir, \"src\", \"assets\", \".arcane.json\");\n try {\n const raw = await readFile(selfHostedManifestPath, \"utf8\");\n const manifest: unknown = JSON.parse(raw);\n if (\n isRecord(manifest) &&\n manifest[\"selfHosted\"] === true &&\n manifest[\"tracking_mode\"] === \"internal\"\n ) {\n return {\n name,\n passed: true,\n message: \"self-hosted source tree — committed source manifest is authoritative\",\n };\n }\n } catch {\n // No valid self-hosting marker — report the normal missing-manifest warning.\n }\n return {\n name,\n passed: false,\n message: \"No .arcane.json found. Run `spell init` to initialize Arcane in this project.\",\n blocking: false,\n };\n }\n\n try {\n const raw = await readFile(manifestPath, \"utf8\");\n const manifest: unknown = JSON.parse(raw);\n if (\n !isRecord(manifest) ||\n typeof manifest[\"version\"] !== \"string\" ||\n !manifest[\"version\"] ||\n !Array.isArray(manifest[\"components\"])\n ) {\n return {\n name,\n passed: false,\n message: \".arcane.json is present but missing required fields (version, components). Re-run `spell init`.\",\n };\n }\n return {\n name,\n passed: true,\n message: `v${manifest[\"version\"]} — ${manifest[\"components\"].length} component(s) installed`,\n };\n } catch {\n return {\n name,\n passed: false,\n message: \".arcane.json is present but contains invalid JSON. Re-run `spell init`.\",\n };\n }\n}\n\n/**\n * EF-32: independently verify the EFFECTIVE (not just repository-local)\n * pull.rebase resolves to \"true\", catching drift regardless of source --\n * an install that predates `spell init`'s own fix, a value unset again\n * later, or any other path that bypassed init's one-time correction.\n * Non-blocking: this repo has no CI job running inside the operator's own\n * working copy, so a doctor warning is the only enforcement mode available\n * here (see ARC-023's inline-enforcement-contract requirement).\n */\nexport async function checkPullRebase(targetDir: string): Promise<CheckResult> {\n const name = \"Git pull.rebase (rebase-and-fast-forward mandate)\";\n try {\n // --type=bool normalizes any of git's valid boolean spellings\n // (true/yes/on/1, false/no/off/0) to canonical \"true\"/\"false\" -- a raw\n // string comparison against \"true\" alone would false-positive-warn on\n // a fully compliant \"yes\"/\"on\"/\"1\".\n const { stdout } = await runGit(targetDir, [\"config\", \"--type=bool\", \"--get\", \"pull.rebase\"]);\n const value = stdout.trim();\n if (value === \"true\") {\n return { name, passed: true, message: \"pull.rebase=true\" };\n }\n return {\n name,\n passed: false,\n message: `pull.rebase resolves to \"${value}\", not \"true\" -- a bare \\`git pull\\` will create merge commits, contradicting git-conventions.md's rebase-and-fast-forward mandate. Run: git config --local pull.rebase true`,\n blocking: false,\n };\n } catch {\n // Two cases collapse here: unset entirely, or set to a non-boolean\n // value (e.g. \"merges\") --type=bool can't coerce -- both mean\n // \"not affirmatively true\", which is what this check cares about.\n return {\n name,\n passed: false,\n message: \"pull.rebase is unset, not a recognized boolean, or this isn't a Git repository -- effective behavior may not be rebase-and-fast-forward, and Git for Windows defaults this to false when unset. Run: git config --local pull.rebase true\",\n blocking: false,\n };\n }\n}\n\nexport function checkIncidentReleaseGate(): CheckResult {\n const result = evaluateIncidentGate(INCIDENT_QUEUE);\n if (result.blocked) {\n return {\n name: \"Incident release gate (ARC-024)\",\n passed: false,\n message: result.blockers.join(\"; \"),\n };\n }\n const accepted = result.acceptedRisks.length > 0\n ? `; ${result.acceptedRisks.length} explicitly deferred`\n : \"\";\n return {\n name: \"Incident release gate (ARC-024)\",\n passed: true,\n message: `${result.checked} incidents classified${accepted}`,\n };\n}\n\n/**\n * ARC-037 decision 7: `spell check-leaks` folded into `spell doctor` as an\n * on-demand mode (`--leaks`) instead of a standalone command -- one fewer\n * entry point for the same scan the build's own CI backstop already runs\n * (scripts/copy-assets.ts). Not part of the default battery below: a\n * full-repository walk is a different cost profile than doctor's other\n * checks, and (per decision 6) the real defense is the CI backstop --\n * this is a fast, opt-in, run-it-yourself pass, mirroring `spell ward`'s\n * own separateness from the default battery.\n */\nexport async function checkSecrets(targetDir: string): Promise<CheckResult> {\n const name = \"Secrets scan (ARC-037)\";\n const excludePrefixes = await resolveSecretsScanExcludePrefixes(targetDir);\n const findings = await scanRepository(targetDir, SECRETS_RULES, undefined, excludePrefixes);\n if (findings.length === 0) {\n return { name, passed: true, message: \"no credential-shaped patterns found\" };\n }\n\n const summary = findings.map((f) => `${f.file}:${f.line} [${f.rule}]`).join(\"; \");\n return {\n name,\n passed: false,\n message: `${findings.length} credential-shaped pattern(s) found: ${summary}`,\n };\n}\n\n// ─── Session continuity checks ────────────────────────────────────────────────\n\n/** Files required for spell-close-session / spell-open-session to function. */\nexport const SESSION_CONTINUITY_FILES = [\n \"TODO.md\",\n \"DECISIONS.md\",\n \"ai-context/system-prompt-context.md\",\n \"journal/.gitkeep\",\n];\n\nexport async function checkSessionContinuity(targetDir: string): Promise<CheckResult[]> {\n const results: CheckResult[] = [];\n\n for (const file of SESSION_CONTINUITY_FILES) {\n const name = `Session file: ${file}`;\n const filePath = join(targetDir, file);\n try {\n await access(filePath);\n results.push({ name, passed: true, message: \"present\" });\n } catch {\n results.push({\n name,\n passed: false,\n message: `Missing. Required for spell-close-session. Run \\`spell doctor --fix\\` to create it.`,\n blocking: false,\n });\n }\n }\n\n return results;\n}\n\nexport async function fixSessionContinuity(targetDir: string, assetsDir: string): Promise<string[]> {\n const created: string[] = [];\n\n for (const file of SESSION_CONTINUITY_FILES) {\n const destPath = join(targetDir, file);\n try {\n await access(destPath);\n // File exists — skip\n } catch {\n // File missing — create from template\n const srcPath = join(assetsDir, file);\n await mkdir(dirname(destPath), { recursive: true });\n await fsCopyFile(srcPath, destPath);\n created.push(file);\n }\n }\n\n return created;\n}\n\n// ─── Main ─────────────────────────────────────────────────────────────────────\n\nexport interface DoctorOptions {\n fix?: boolean;\n /** ARC-037 decision 7: run only the on-demand secrets scan, skipping the default battery. */\n leaks?: boolean;\n}\n\n/**\n * EF-09 R4. Reports the repository's declared push posture and, for a\n * \"blocked\" repo, whether the controls are actually in place.\n *\n * Deliberately fires for every \"guarded\" repo REGARDLESS of remote state. An\n * earlier draft only reported when no remote was configured, which meant the\n * reminder went silent the instant any remote was added -- including a wrong\n * one -- making \"guarded\" behave identically to \"open\" exactly when it\n * mattered most.\n */\nexport async function checkPushPolicy(targetDir: string): Promise<CheckResult> {\n const name = \"Push policy (EF-09)\";\n let manifest;\n try {\n manifest = await readManifest(targetDir);\n } catch {\n return { name, passed: true, message: \"not initialized — nothing to check\" };\n }\n\n const policy = manifest.push_policy ?? \"open\";\n\n if (policy === \"open\") {\n return { name, passed: true, message: \"open — pushes allowed\" };\n }\n\n if (policy === \"guarded\") {\n // Name AND URL: the reminder's whole job is catching a wrong remote, and the\n // name alone reveals nothing about where it points.\n const targets = await pushTargets(targetDir);\n const where =\n targets.length === 0\n ? \"none configured\"\n : targets\n .map(({ remote, urls }) => `${remote} → ${urls.length > 0 ? urls.join(\", \") : \"unknown\"}`)\n .join(\"; \");\n return {\n name,\n passed: false,\n blocking: false,\n message: `guarded — no technical control installed. Push targets: ${where}. Confirm those are the remotes you intend before pushing.`,\n };\n }\n\n // blocked: verify the controls are genuinely IN FORCE, not merely declared.\n // Checking config alone was a declaration check wearing an enforcement\n // check's name -- deleting the hook file leaves core.hooksPath intact and\n // pushes succeed, while this reported the hook as present.\n const hookActive = await isHookEnforced(targetDir);\n const remotes = await listRemotes(targetDir);\n const open = await undisabledRemotes(targetDir);\n\n if (hookActive && open.length === 0) {\n if (remotes.length === 0) {\n // Don't claim a push URL is \"in place\" when there is no remote at all.\n // The hook is the only live control here, and it is the one a\n // `--no-verify` push walks straight past -- so say that plainly rather\n // than reporting full protection.\n return {\n name,\n passed: false,\n blocking: false,\n message:\n \"blocked — pre-push hook in place, but no remote is configured, so no push URL is disabled. If a remote is added later, run `spell doctor` again: a --no-verify push to it would succeed until the URL is disabled too.\",\n };\n }\n return {\n name,\n passed: true,\n message: `blocked — pre-push hook in place and push URL disabled for ${remotes.join(\", \")}`,\n };\n }\n\n const missing = [\n hookActive ? null : \"pre-push hook (config or hook file absent)\",\n open.length > 0 ? `push URL still live for: ${open.join(\", \")}` : null,\n ].filter(Boolean);\n\n return {\n name,\n passed: false,\n blocking: false,\n message: `declared \"blocked\" but not enforced — ${missing.join(\"; \")}. The manifest claims a protection this repository does not have.`,\n };\n}\n\ninterface McpServerConfig {\n timeout?: number;\n}\n\ninterface McpConfigFile {\n mcpServers?: Record<string, McpServerConfig>;\n}\n\n/**\n * I12/BC-22. Checks that any configured .mcp.json server sets a per-server\n * \"timeout\" -- companion to the MCP fail-fast/fallback rule in\n * git-conventions.md. Without one, a hung server runs to the client's own\n * default idle limit (as long as 30 minutes) instead of a predictable one.\n * A missing .mcp.json is a silent pass -- MCP is optional.\n */\nexport async function checkMcpConfig(targetDir: string): Promise<CheckResult> {\n const name = \"MCP config (per-server timeout, I12)\";\n const filePath = join(targetDir, \".mcp.json\");\n\n let raw: string;\n try {\n raw = await readFile(filePath, \"utf8\");\n } catch {\n return { name, passed: true, blocking: false, message: \"no .mcp.json — nothing to check\" };\n }\n\n let rawParsed: unknown;\n try {\n rawParsed = JSON.parse(raw);\n } catch {\n return {\n name,\n passed: false,\n blocking: false,\n message: \".mcp.json exists but contains invalid JSON\",\n };\n }\n\n if (!isRecord(rawParsed)) {\n return {\n name,\n passed: false,\n blocking: false,\n message: \".mcp.json exists but is not a JSON object\",\n };\n }\n\n // Field-level shape (mcpServers, per-server timeout) is untrusted beyond\n // this point -- every access below is `?.`-guarded rather than assumed.\n const parsed = rawParsed as McpConfigFile;\n const servers = parsed.mcpServers ?? {};\n const serverNames = Object.keys(servers);\n if (serverNames.length === 0) {\n return { name, passed: true, blocking: false, message: \"no MCP servers configured\" };\n }\n\n const missingTimeout = serverNames.filter((n) => typeof servers[n]?.timeout !== \"number\");\n if (missingTimeout.length > 0) {\n return {\n name,\n passed: false,\n blocking: false,\n message: `server(s) missing a \"timeout\": ${missingTimeout.join(\", \")} — a hang runs to the client's own default idle limit (up to 30 min) instead of a predictable one`,\n };\n }\n\n return {\n name,\n passed: true,\n blocking: false,\n message: `${serverNames.length} server(s) configured, all with a timeout set`,\n };\n}\n\nfunction isDelegation(value: unknown): value is Delegation {\n return (\n isRecord(value) &&\n typeof value[\"id\"] === \"string\" &&\n typeof value[\"status\"] === \"string\" &&\n typeof value[\"scope\"] === \"string\" &&\n Array.isArray(value[\"excludedActions\"])\n );\n}\n\nfunction isDelegationsFile(value: unknown): value is DelegationsFile {\n return isRecord(value) && Array.isArray(value[\"delegations\"]) && value[\"delegations\"].every(isDelegation);\n}\n\n/**\n * T13/BC-19. Lists standing-authority delegations recorded in\n * `.arcane/delegations.json` -- the solo-operator/no-roster counterpart to\n * agent-policies.md's roster-based power-level matrix. A missing file is a\n * silent pass, not a warning: a repo with no ad hoc grants has nothing to\n * report. This check only reports; it never grants, revokes, or validates\n * authority -- revocation is the git-native act of editing the file itself.\n */\nexport async function checkDelegations(targetDir: string): Promise<CheckResult> {\n const name = \"Standing delegations (T13)\";\n const filePath = join(targetDir, \".arcane\", \"delegations.json\");\n\n let raw: string;\n try {\n raw = await readFile(filePath, \"utf8\");\n } catch {\n return { name, passed: true, blocking: false, message: \"no delegations recorded\" };\n }\n\n let rawParsed: unknown;\n try {\n rawParsed = JSON.parse(raw);\n } catch {\n return {\n name,\n passed: false,\n blocking: false,\n message: `.arcane/delegations.json exists but contains invalid JSON`,\n };\n }\n\n if (!isDelegationsFile(rawParsed)) {\n return {\n name,\n passed: false,\n blocking: false,\n message: `.arcane/delegations.json exists but is not a valid delegations file (expected a \"delegations\" array of well-formed entries)`,\n };\n }\n const parsed = rawParsed;\n\n const active = parsed.delegations.filter((d) => d.status === \"active\");\n if (active.length === 0) {\n return { name, passed: true, blocking: false, message: \"no active delegations\" };\n }\n\n const summary = active\n .map((d) => `${d.id} (scope: ${d.scope}; excludes: ${d.excludedActions.length} action(s))`)\n .join(\"; \");\n return {\n name,\n passed: true,\n blocking: false,\n message: `${active.length} active: ${summary}`,\n };\n}\n\n/**\n * T11/BC-17. Verifies the live platform branch/merge policy matches the\n * declared ladder (git-conventions.md: merge + rebase sanctioned, squash\n * never sanctioned). GitHub is checked via Rulesets, never the classic\n * `/branches/{branch}/protection` endpoint alone -- that endpoint 404s\n * \"not protected\" for a Rulesets-only repo (confirmed live against this\n * repo's own main branch), a false negative this check must not repeat.\n * Report-only: never mutates a platform setting. Degrades to a\n * non-blocking warning for any provider it can't resolve, any CLI it\n * can't reach, or any auth/network failure -- this check depends on\n * external state doctor's other checks never do, so it must never be the\n * reason `doctor` crashes.\n */\nexport async function checkPlatformBranchPolicy(targetDir: string): Promise<CheckResult> {\n const name = \"Platform branch/merge policy (T11)\";\n const targets = await pushTargets(targetDir);\n const origin = targets.find((t) => t.remote === \"origin\") ?? targets[0];\n const url = origin?.urls[0];\n\n if (!url) {\n return { name, passed: true, message: \"no remote configured — nothing to check\", blocking: false };\n }\n\n const github = parseGitHubRemote(url);\n if (github) {\n const rulesets = await fetchGitHubRulesets(github.owner, github.repo);\n if (rulesets === null) {\n return {\n name,\n passed: false,\n blocking: false,\n message: `could not query GitHub Rulesets for ${github.owner}/${github.repo} — is \\`gh\\` installed and authenticated? Verify manually: gh api repos/${github.owner}/${github.repo}/rulesets`,\n };\n }\n const result = evaluateGitHubMergePolicy(rulesets);\n return { name, passed: result.passed, blocking: false, message: result.message };\n }\n\n const ado = parseAdoRemote(url);\n if (ado) {\n const policies = await fetchAdoMergeTypePolicies(ado.org, ado.project, ado.repo, \"main\");\n if (policies === null) {\n return {\n name,\n passed: false,\n blocking: false,\n message: `could not query the Azure DevOps \"Limit merge types\" branch policy for ${ado.org}/${ado.project}/${ado.repo} — is \\`az\\` installed and authenticated? Verify manually in the ADO web UI under Branch Policies.`,\n };\n }\n const result = evaluateAdoMergePolicy(policies);\n return { name, passed: result.passed, blocking: false, message: result.message };\n }\n\n return {\n name,\n passed: true,\n blocking: false,\n message: \"remote is neither GitHub nor Azure DevOps — platform policy verification not available for this provider\",\n };\n}\n\nexport async function runDoctor(targetDir: string, options: DoctorOptions = {}, assetsDir?: string): Promise<void> {\n console.log(\"\\nspell doctor — checking your Arcane environment\\n\");\n\n if (options.leaks) {\n const result = await checkSecrets(targetDir);\n const icon = result.passed ? \"✓\" : \"✗\";\n console.log(` ${icon} [${result.passed ? \"pass\" : \"FAIL\"}] ${result.name}`);\n if (!result.passed) {\n console.log(` ${result.message}`);\n console.log(\"\\n One or more checks failed. Fix the issues above before proceeding.\\n\");\n process.exitCode = 1;\n } else {\n console.log(\"\\n All checks passed. Your environment is ready.\\n\");\n }\n return;\n }\n\n const results = await Promise.all([\n checkNodeVersion(),\n checkVSCodeExtension(\"GitHub.copilot-chat\", \"GitHub Copilot (Chat)\"),\n checkArcaneManifest(targetDir),\n Promise.resolve(checkIncidentReleaseGate()),\n checkPullRebase(targetDir),\n checkPushPolicy(targetDir),\n checkPlatformBranchPolicy(targetDir),\n checkDelegations(targetDir),\n checkMcpConfig(targetDir),\n ]);\n\n // Add session continuity checks\n const sessionResults = await checkSessionContinuity(targetDir);\n results.push(...sessionResults);\n\n let allPassed = true;\n\n for (const result of results) {\n const icon = result.passed ? \"✓\" : result.blocking === false ? \"⚠\" : \"✗\";\n const label = result.passed\n ? \"pass\"\n : result.blocking === false\n ? \"warn\"\n : \"FAIL\";\n console.log(` ${icon} [${label}] ${result.name}`);\n if (!result.passed) {\n console.log(` ${result.message}`);\n }\n if (!result.passed && result.blocking !== false) {\n allPassed = false;\n }\n }\n\n console.log();\n\n if (allPassed) {\n console.log(\" All checks passed. Your environment is ready.\\n\");\n } else {\n console.log(\" One or more checks failed. Fix the issues above before proceeding.\\n\");\n\n // --fix: remediate missing session continuity files\n const hasMissingSession = sessionResults.some((r) => !r.passed);\n if (options.fix && hasMissingSession && assetsDir) {\n console.log(\" 🔧 Fixing missing session continuity files...\\n\");\n const created = await fixSessionContinuity(targetDir, assetsDir);\n if (created.length > 0) {\n for (const file of created) {\n console.log(` ✓ Created: ${file}`);\n }\n console.log(`\\n ${created.length} file(s) created. Repo is now close-session-ready.\\n`);\n } else {\n console.log(\" No files needed creation (all present).\\n\");\n }\n } else if (hasMissingSession && !options.fix) {\n console.log(\" 💡 Run `spell doctor --fix` to create missing session files.\\n\");\n }\n\n if (!allPassed) {\n process.exitCode = 1;\n }\n }\n}\n","export type IncidentSeverity = \"critical\" | \"high\" | \"medium\" | \"low\";\nexport type IncidentImpact = \"data-integrity\" | \"security\" | \"other\";\nexport type IncidentConfidence = \"confirmed\" | \"research\";\nexport type IncidentState = \"open\" | \"resolved\" | \"deferred\";\n\nexport interface IncidentRecord {\n id: string;\n severity?: IncidentSeverity;\n impact: IncidentImpact;\n confidence: IncidentConfidence;\n state: IncidentState;\n detectedOn: string;\n resolution?: string;\n deferral?: string;\n}\n\nexport const INCIDENT_QUEUE: IncidentRecord[] = [\n { id: \"EF-05\", severity: \"medium\", impact: \"other\", confidence: \"confirmed\", state: \"open\", detectedOn: \"2026-07-31\" },\n { id: \"EF-08\", severity: \"medium\", impact: \"other\", confidence: \"confirmed\", state: \"open\", detectedOn: \"2026-07-31\" },\n { id: \"EF-16\", severity: \"high\", impact: \"other\", confidence: \"confirmed\", state: \"open\", detectedOn: \"2026-07-31\" },\n { id: \"EF-17\", severity: \"high\", impact: \"other\", confidence: \"confirmed\", state: \"open\", detectedOn: \"2026-07-31\" },\n { id: \"EF-20\", severity: \"high\", impact: \"other\", confidence: \"research\", state: \"open\", detectedOn: \"2026-07-31\" },\n { id: \"EF-21\", severity: \"high\", impact: \"other\", confidence: \"confirmed\", state: \"open\", detectedOn: \"2026-07-31\" },\n { id: \"EF-23\", severity: \"medium\", impact: \"other\", confidence: \"confirmed\", state: \"open\", detectedOn: \"2026-07-31\" },\n { id: \"EF-25\", severity: \"high\", impact: \"data-integrity\", confidence: \"confirmed\", state: \"resolved\", detectedOn: \"2026-07-14\", resolution: \"PRs 13 and 14\" },\n { id: \"EF-26\", severity: \"high\", impact: \"security\", confidence: \"confirmed\", state: \"resolved\", detectedOn: \"2026-07-31\", resolution: \"PR 15\" },\n { id: \"EF-27\", severity: \"high\", impact: \"security\", confidence: \"confirmed\", state: \"resolved\", detectedOn: \"2026-07-31\", resolution: \"PR 16\" },\n { id: \"EF-28\", severity: \"high\", impact: \"security\", confidence: \"confirmed\", state: \"resolved\", detectedOn: \"2026-07-31\", resolution: \"PR 17\" },\n { id: \"EF-29\", severity: \"medium\", impact: \"other\", confidence: \"confirmed\", state: \"resolved\", detectedOn: \"2026-07-31\", resolution: \"PR 18\" },\n];","import type { IncidentRecord } from \"../config/incidents.js\";\n\nconst DEFERRAL_PATTERN = /^Deferred \\d{4}-\\d{2}-\\d{2} — known open, accepting the risk\\.$/;\nconst BLOCKING_SEVERITIES = new Set([\"critical\", \"high\"]);\nconst PROTECTED_IMPACTS = new Set([\"data-integrity\", \"security\"]);\n\nexport interface IncidentGateResult {\n blocked: boolean;\n blockers: string[];\n acceptedRisks: string[];\n checked: number;\n}\n\nexport function evaluateIncidentGate(records: IncidentRecord[]): IncidentGateResult {\n const blockers: string[] = [];\n const acceptedRisks: string[] = [];\n const seen = new Set<string>();\n\n for (const record of records) {\n if (seen.has(record.id)) {\n blockers.push(`${record.id}: duplicate incident record`);\n continue;\n }\n seen.add(record.id);\n\n if (record.confidence === \"research\") continue;\n if (!PROTECTED_IMPACTS.has(record.impact)) continue;\n\n if (!record.severity) {\n blockers.push(`${record.id}: confirmed ${record.impact} incident is missing severity`);\n continue;\n }\n if (!BLOCKING_SEVERITIES.has(record.severity)) continue;\n\n if (record.state === \"resolved\") {\n if (!record.resolution?.trim()) {\n blockers.push(`${record.id}: resolved incident is missing resolution evidence`);\n }\n continue;\n }\n\n if (record.state === \"deferred\") {\n if (!record.deferral || !DEFERRAL_PATTERN.test(record.deferral)) {\n blockers.push(\n `${record.id}: deferral must be exactly \"Deferred <date> — known open, accepting the risk.\"`,\n );\n } else {\n acceptedRisks.push(`${record.id}: ${record.deferral}`);\n }\n continue;\n }\n\n blockers.push(\n `${record.id}: unresolved ${record.severity} ${record.impact} incident blocks release`,\n );\n }\n\n return {\n blocked: blockers.length > 0,\n blockers,\n acceptedRisks,\n checked: records.length,\n };\n}","/**\n * Generic denylist scanning engine: word-boundary matching, tree-walking,\n * and dedup -- shared by `scripts/org-token-lint.ts` (Arcane's own private\n * build gate) and `spell ward` (BC-21, a shipped CLI command any consumer\n * repo can run). Extracted here because these functions were never actually\n * org-token-specific -- only the *resolution* of which tokens to scan for\n * (an env var, a CLI flag, a mandatory vendor list) differs per caller.\n */\n\nimport { readFile, readdir } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\n\nexport interface DenylistRule {\n label: string;\n pattern: RegExp;\n}\n\nexport interface DenylistFinding {\n file: string;\n line: number;\n rule: string;\n}\n\nexport function escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/** Word-boundary rules: a token must not be flanked by another word character. */\nexport function createDenylistRules(\n tokens: string[],\n labelPrefix: string,\n): DenylistRule[] {\n return tokens.map((token, index) => ({\n label: `${labelPrefix}-${index + 1}`,\n pattern: new RegExp(\n `(?:^|[^A-Za-z0-9])${escapeRegExp(token)}(?=$|[^A-Za-z0-9])`,\n \"i\",\n ),\n }));\n}\n\n/**\n * Scans one file for denylist rules. Documented {UPPER_SNAKE} placeholders\n * are stripped before matching so they never trip a rule.\n */\nexport async function scanFile(\n absolutePath: string,\n displayPath: string,\n rules: DenylistRule[],\n): Promise<DenylistFinding[]> {\n const findings: DenylistFinding[] = [];\n let content: string;\n try {\n content = await readFile(absolutePath, \"utf8\");\n } catch {\n return findings;\n }\n\n const lines = content.split(\"\\n\");\n for (let index = 0; index < lines.length; index++) {\n const searchable = lines[index]!.replace(/\\{[A-Z][A-Z0-9_]*\\}/g, \"\");\n for (const rule of rules) {\n if (rule.pattern.test(searchable)) {\n findings.push({ file: displayPath, line: index + 1, rule: rule.label });\n break;\n }\n }\n }\n\n return findings;\n}\n\n/**\n * Directories never worth scanning -- generated output, dependencies, VCS\n * metadata. \".claude\" specifically covers `.claude/worktrees/`: each entry\n * there is a full nested checkout of this same repository (a linked git\n * worktree), so anything real inside one is scanned again at the primary\n * checkout's own path -- walking it too only triples every finding without\n * surfacing anything new (confirmed empirically widening the ARC-037 scan\n * repository-wide: every one of a worktree's findings duplicated a root-path\n * finding byte-for-byte).\n */\nexport const SKIP_DIRECTORIES = new Set([\n \"node_modules\",\n \".git\",\n \"dist\",\n \"coverage\",\n \".vitest\",\n \".claude\",\n]);\n\nexport const DEFAULT_SCANNABLE_EXTENSIONS = [\".md\", \".ts\", \".js\", \".json\", \".yml\", \".yaml\"];\n\n/**\n * Recursively collects every scannable file under `root`, returning\n * [absolutePath, repoRelativePath] pairs. `extensions` defaults to text\n * formats; a caller scanning binary asset strings (ward) passes its own list.\n */\nexport async function collectScannableFiles(\n root: string,\n repoRoot: string = root,\n extensions: string[] = DEFAULT_SCANNABLE_EXTENSIONS,\n): Promise<Array<[string, string]>> {\n const collected: Array<[string, string]> = [];\n let entries;\n try {\n entries = await readdir(root, { withFileTypes: true });\n } catch {\n return collected;\n }\n\n for (const entry of entries) {\n const absolutePath = join(root, entry.name);\n if (entry.isDirectory()) {\n if (SKIP_DIRECTORIES.has(entry.name)) continue;\n collected.push(...(await collectScannableFiles(absolutePath, repoRoot, extensions)));\n } else if (extensions.some((ext) => entry.name.endsWith(ext))) {\n const displayPath = relative(repoRoot, absolutePath).replace(/\\\\/g, \"/\");\n collected.push([absolutePath, displayPath]);\n }\n }\n\n return collected;\n}\n\n/**\n * Scans an entire repository tree (text files by default) for denylist rules.\n * `excludePrefixes` drops any file whose repo-relative display path contains\n * one of the given literal substrings before it's ever read -- a scan blind\n * spot the caller opted into, not a post-hoc filter on findings (ARC-037).\n */\nexport async function scanRepository(\n repoRoot: string,\n rules: DenylistRule[],\n extensions?: string[],\n excludePrefixes: string[] = [],\n): Promise<DenylistFinding[]> {\n if (rules.length === 0) return [];\n\n const findings: DenylistFinding[] = [];\n for (const [absolutePath, displayPath] of await collectScannableFiles(repoRoot, repoRoot, extensions)) {\n if (excludePrefixes.some((prefix) => displayPath.includes(prefix))) continue;\n findings.push(...(await scanFile(absolutePath, displayPath, rules)));\n }\n return findings;\n}\n\n/** Merges finding lists, collapsing duplicates reported at the same file:line. */\nexport function dedupeFindings(...lists: DenylistFinding[][]): DenylistFinding[] {\n const seen = new Map<string, DenylistFinding>();\n for (const list of lists) {\n for (const finding of list) {\n const key = `${finding.file}:${finding.line}`;\n if (!seen.has(key)) seen.set(key, finding);\n }\n }\n return [...seen.values()];\n}\n","/**\n * Platform branch/merge policy verification (T11/BC-17).\n *\n * Report-only: nothing here mutates a repository or organization setting.\n * Rule-interpretation logic is split into pure functions taking\n * already-fetched JSON (evaluate*) so it is unit-testable with fixture\n * data, separate from the thin CLI-invocation wrappers (fetch*) that are\n * not exercised in CI (no live GitHub/ADO credentials to test against).\n *\n * GitHub Rulesets path is live-verified against this repo's own real\n * ruleset. The Azure DevOps path is implemented from documented API\n * shape only -- this repo has no ADO remote to test against -- and that\n * limitation is disclosed here rather than presented as verified.\n */\n\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\n// ─── Declared ladder (git-conventions.md § Merge Strategy by Repo Risk) ──────\n\nexport type MergeMethod = \"merge\" | \"squash\" | \"rebase\";\nexport const SANCTIONED_MERGE_METHODS: readonly MergeMethod[] = [\"merge\", \"rebase\"];\n\nexport interface PolicyEvaluation {\n passed: boolean;\n /** null when no policy/ruleset was found to evaluate at all. */\n effectiveMergeMethods: MergeMethod[] | null;\n /** Methods the raw config nominally allows but a separate rule silently blocks. */\n declaredButBlocked: MergeMethod[];\n /** Methods effectively permitted despite never being sanctioned. */\n disallowedButPermitted: MergeMethod[];\n message: string;\n}\n\nfunction compareToLadder(\n effective: MergeMethod[],\n declaredButBlocked: MergeMethod[],\n interactionNote?: string,\n): PolicyEvaluation {\n const disallowedButPermitted = effective.filter(\n (m) => !SANCTIONED_MERGE_METHODS.includes(m),\n );\n const missingSanctioned = SANCTIONED_MERGE_METHODS.filter(\n (m) => !effective.includes(m),\n );\n const passed = disallowedButPermitted.length === 0 && missingSanctioned.length === 0;\n\n const messages: string[] = [];\n if (interactionNote) messages.push(interactionNote);\n if (disallowedButPermitted.length > 0) {\n messages.push(\n `disallowed method(s) effectively permitted: ${disallowedButPermitted.join(\", \")} (never sanctioned per git-conventions.md)`,\n );\n }\n if (missingSanctioned.length > 0) {\n messages.push(\n `sanctioned method(s) not effectively available: ${missingSanctioned.join(\", \")}`,\n );\n }\n\n return {\n passed,\n effectiveMergeMethods: effective,\n declaredButBlocked,\n disallowedButPermitted,\n message: passed\n ? `effective merge methods [${effective.join(\", \")}] match the declared ladder`\n : messages.join(\"; \"),\n };\n}\n\n// ─── GitHub Rulesets ──────────────────────────────────────────────────────────\n\nexport interface GitHubRulesetRule {\n type: string;\n parameters?: Record<string, unknown>;\n}\n\nexport interface GitHubRuleset {\n id: number;\n target: string;\n enforcement: string;\n rules: GitHubRulesetRule[];\n}\n\n/**\n * Pure evaluation: given already-fetched ruleset detail JSON for the rulesets\n * covering the target branch, determines the EFFECTIVE merge-method policy.\n *\n * Detects the interaction this repo's own 2026-08-24/25 incident found:\n * a `required_linear_history` rule silently blocks merge-commit PRs\n * regardless of what a `pull_request` rule's `allowed_merge_methods`\n * parameter declares.\n */\nexport function evaluateGitHubMergePolicy(\n rulesets: GitHubRuleset[],\n): PolicyEvaluation {\n const active = rulesets.filter(\n (r) => r.enforcement === \"active\" && r.target === \"branch\",\n );\n\n if (active.length === 0) {\n return {\n passed: false,\n effectiveMergeMethods: null,\n declaredButBlocked: [],\n disallowedButPermitted: [],\n message:\n \"No active branch ruleset covers the target branch (checked via Rulesets, not the classic protection endpoint, which false-negatives on Rulesets-only repos).\",\n };\n }\n\n // GitHub applies the most restrictive union when multiple rulesets target\n // the same ref -- intersect allowed_merge_methods across all of them.\n let allowedMergeMethods: MergeMethod[] | null = null;\n let hasRequiredLinearHistory = false;\n\n for (const ruleset of active) {\n for (const rule of ruleset.rules) {\n if (rule.type === \"required_linear_history\") {\n hasRequiredLinearHistory = true;\n }\n if (rule.type === \"pull_request\") {\n const methods = rule.parameters?.[\"allowed_merge_methods\"];\n if (Array.isArray(methods)) {\n const typed = methods as MergeMethod[];\n allowedMergeMethods =\n allowedMergeMethods === null\n ? typed\n : allowedMergeMethods.filter((m) => typed.includes(m));\n }\n }\n }\n }\n\n // No pull_request rule set allowed_merge_methods at all -- GitHub's\n // platform default (all three methods) applies, which is never compliant.\n const nominal = allowedMergeMethods ?? [\"merge\", \"squash\", \"rebase\"];\n const effective = hasRequiredLinearHistory\n ? nominal.filter((m) => m !== \"merge\")\n : nominal;\n const declaredButBlocked: MergeMethod[] =\n hasRequiredLinearHistory && nominal.includes(\"merge\") ? [\"merge\"] : [];\n\n const interactionNote =\n declaredButBlocked.length > 0\n ? `allowed_merge_methods declares [${nominal.join(\", \")}] but a required_linear_history rule silently blocks merge commits regardless -- effective methods are [${effective.join(\", \")}]`\n : undefined;\n\n return compareToLadder(effective, declaredButBlocked, interactionNote);\n}\n\nexport async function fetchGitHubRulesets(\n owner: string,\n repo: string,\n): Promise<GitHubRuleset[] | null> {\n try {\n const { stdout: listOut } = await execFileAsync(\"gh\", [\n \"api\",\n `repos/${owner}/${repo}/rulesets`,\n ]);\n const summaries = JSON.parse(listOut) as Array<{ id: number }>;\n const detailed = await Promise.all(\n summaries.map(async (s) => {\n const { stdout } = await execFileAsync(\"gh\", [\n \"api\",\n `repos/${owner}/${repo}/rulesets/${s.id}`,\n ]);\n return JSON.parse(stdout) as GitHubRuleset;\n }),\n );\n return detailed;\n } catch {\n return null;\n }\n}\n\n// ─── Azure DevOps branch policy ───────────────────────────────────────────────\n// NOT live-verified (see module doc comment and the PRD's Open Questions).\n\nexport interface AdoMergeTypePolicy {\n isEnabled: boolean;\n isBlocking: boolean;\n settings?: {\n useSquashMerge?: boolean;\n allowNoFastForward?: boolean;\n allowRebase?: boolean;\n allowRebaseMerge?: boolean;\n };\n}\n\nexport function evaluateAdoMergePolicy(\n policies: AdoMergeTypePolicy[],\n): PolicyEvaluation {\n const enabled = policies.filter((p) => p.isEnabled);\n if (enabled.length === 0) {\n return {\n passed: false,\n effectiveMergeMethods: null,\n declaredButBlocked: [],\n disallowedButPermitted: [],\n message: \"No enabled \\\"Limit merge types\\\" branch policy found for the target branch.\",\n };\n }\n\n const effective = new Set<MergeMethod>();\n for (const policy of enabled) {\n const s = policy.settings ?? {};\n if (s.allowNoFastForward) effective.add(\"merge\");\n if (s.allowRebase || s.allowRebaseMerge) effective.add(\"rebase\");\n if (s.useSquashMerge) effective.add(\"squash\");\n }\n\n return compareToLadder([...effective], []);\n}\n\nexport async function fetchAdoMergeTypePolicies(\n org: string,\n project: string,\n repoName: string,\n branch: string,\n): Promise<AdoMergeTypePolicy[] | null> {\n try {\n const orgUrl = `https://dev.azure.com/${org}`;\n // az repos policy list needs the repository's GUID, not its name.\n const { stdout: repoOut } = await execFileAsync(\"az\", [\n \"repos\",\n \"show\",\n \"--repository\",\n repoName,\n \"--org\",\n orgUrl,\n \"--project\",\n project,\n \"--query\",\n \"id\",\n \"--output\",\n \"tsv\",\n ]);\n const repositoryId = repoOut.trim();\n if (!repositoryId) return null;\n\n const { stdout } = await execFileAsync(\"az\", [\n \"repos\",\n \"policy\",\n \"list\",\n \"--repository-id\",\n repositoryId,\n \"--branch\",\n branch,\n \"--org\",\n orgUrl,\n \"--project\",\n project,\n \"--output\",\n \"json\",\n ]);\n return JSON.parse(stdout) as AdoMergeTypePolicy[];\n } catch {\n return null;\n }\n}\n\n// ─── Remote URL parsing ───────────────────────────────────────────────────────\n\nexport function parseGitHubRemote(url: string): { owner: string; repo: string } | null {\n const match = /github\\.com[/:]([^/]+)\\/([^/.]+?)(?:\\.git)?\\/?$/.exec(url);\n if (!match) return null;\n const [, owner, repo] = match;\n if (!owner || !repo) return null;\n return { owner, repo };\n}\n\nexport function parseAdoRemote(\n url: string,\n): { org: string; project: string; repo: string } | null {\n // Modern: https://dev.azure.com/{org}/{project}/_git/{repo}\n const modern = /dev\\.azure\\.com\\/([^/]+)\\/([^/]+)\\/_git\\/([^/?]+)/.exec(url);\n if (modern) {\n const [, org, project, repo] = modern;\n if (org && project && repo) return { org, project, repo };\n }\n // Legacy: https://{org}.visualstudio.com/{project}/_git/{repo}\n const legacy = /([^./]+)\\.visualstudio\\.com\\/([^/]+)\\/_git\\/([^/?]+)/.exec(url);\n if (legacy) {\n const [, org, project, repo] = legacy;\n if (org && project && repo) return { org, project, repo };\n }\n return null;\n}\n","/**\n * spell ward (T18/BC-21): local IP/trademark leakage scan.\n *\n * Finds what leaked IN -- third-party identifiers, brand tokens, org names --\n * baked into a repo's content, filenames, or binary assets. `--terms` is a\n * generic denylist: seed it from the operator's OWN identity too, not just\n * the org's -- a username, machine name, or personal handle leaks the same\n * way a private venture name does (I1; the motivating incident was exactly\n * this -- a branch name containing a username, sitting in this repo's own\n * ai-context file, in a public repo). The opposite concern from spell scry\n * (T18), which clears a candidate name before it ships OUT.\n *\n * Deliberately out of scope: secret/credential detection. That is a\n * different scanning concern reserved for BC-10's secret-detection ADR\n * (ARC-037, still Proposed) -- ward never attempts pattern-matching on\n * keys, tokens, or credentials, only on identifiers and trademarks.\n */\n\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\nimport {\n createDenylistRules,\n collectScannableFiles,\n SKIP_DIRECTORIES,\n type DenylistRule,\n type DenylistFinding,\n} from \"./denylist-scan.js\";\n\n/**\n * Ward's own content scan, deliberately NOT reusing denylist-scan.ts's\n * `scanFile` -- that function stops at the first matching rule per line\n * (correct for org-token-lint, which only needs \"does this line have any\n * hit\"), but ward must distinguish a leak from a protected-vendor-identifier\n * hit even when both land on the same line, so it needs every matching rule\n * per line, not just the first.\n */\nasync function scanFileAllRules(\n absolutePath: string,\n displayPath: string,\n rules: DenylistRule[],\n): Promise<DenylistFinding[]> {\n const findings: DenylistFinding[] = [];\n let content: string;\n try {\n content = await readFile(absolutePath, \"utf8\");\n } catch {\n return findings;\n }\n\n const lines = content.split(\"\\n\");\n for (let index = 0; index < lines.length; index++) {\n const searchable = lines[index]!.replace(/\\{[A-Z][A-Z0-9_]*\\}/g, \"\");\n for (const rule of rules) {\n if (rule.pattern.test(searchable)) {\n findings.push({ file: displayPath, line: index + 1, rule: rule.label });\n }\n }\n }\n\n return findings;\n}\n\n// ─── Mandatory vendor-identifier protection list ─────────────────────────────\n\n/**\n * Always active, independent of any user-supplied terms. A reasonable\n * starting set (not exhaustive -- see the PRD's Open Questions), covering\n * widely-referenced third-party AI model and vendor identifiers that an\n * automated rename/refactor pass could plausibly mistake for a project-local\n * token and \"correct\" into something else, corrupting a real API reference.\n * A match here is reported as PROTECTED, never as a plain leak finding --\n * ward's job for these terms is to stop automated correction, not to flag\n * their legitimate presence as a problem.\n */\nexport const VENDOR_IDENTIFIER_PROTECTION_LIST: readonly string[] = [\n \"claude\",\n \"gpt-4\",\n \"gpt-3.5\",\n \"gemini\",\n \"llama\",\n \"mistral\",\n \"copilot\",\n \"anthropic\",\n \"openai\",\n];\n\nexport interface WardExclusion {\n /** The denylist rule label this exclusion applies to. */\n rule: string;\n /** A substring that, if present on the same line as a match, suppresses it. */\n context: string;\n reason: string;\n}\n\nexport interface WardOptions {\n /** User-supplied terms, in addition to the mandatory vendor list. */\n terms?: string[];\n /** Substring-hazard exclusions (the \"author/provision\" class). */\n exclusions?: WardExclusion[];\n /** Extra file extensions to treat as scannable binary-asset carriers. */\n binaryExtensions?: string[];\n}\n\nexport interface WardFinding extends DenylistFinding {\n category: \"leak\" | \"protected-vendor-identifier\";\n}\n\nexport interface WardMediaFlag {\n file: string;\n reason: string;\n}\n\nexport interface WardReport {\n findings: WardFinding[];\n /** Grep-proof media flagged for manual review, never silently cleared. */\n mediaFlags: WardMediaFlag[];\n}\n\n/** Binary media formats where reliable text extraction isn't possible. */\nconst GREP_PROOF_EXTENSIONS = [\".gif\", \".png\", \".jpg\", \".jpeg\", \".mp4\", \".mov\", \".mp3\", \".wav\"];\n\n/** Extensions ward treats as text-scannable content, beyond denylist-scan's default set. */\nconst WARD_TEXT_EXTENSIONS = [\n \".md\", \".ts\", \".tsx\", \".js\", \".jsx\", \".json\", \".yml\", \".yaml\", \".txt\", \".mdx\",\n];\n\nfunction applyExclusions(\n findings: DenylistFinding[],\n fileLines: Map<string, string[]>,\n exclusions: WardExclusion[],\n): DenylistFinding[] {\n if (exclusions.length === 0) return findings;\n return findings.filter((finding) => {\n const applicable = exclusions.filter((e) => e.rule === finding.rule);\n if (applicable.length === 0) return true;\n const lines = fileLines.get(finding.file);\n const lineText = lines?.[finding.line - 1] ?? \"\";\n return !applicable.some((e) => lineText.includes(e.context));\n });\n}\n\n/** Scans filenames themselves (not just content) against the denylist rules. */\nasync function scanFilenames(\n root: string,\n rules: DenylistRule[],\n repoRoot: string = root,\n): Promise<DenylistFinding[]> {\n const findings: DenylistFinding[] = [];\n let entries;\n try {\n entries = await readdir(root, { withFileTypes: true });\n } catch {\n return findings;\n }\n\n for (const entry of entries) {\n const absolutePath = join(root, entry.name);\n if (entry.isDirectory()) {\n if (SKIP_DIRECTORIES.has(entry.name)) continue;\n findings.push(...(await scanFilenames(absolutePath, rules, repoRoot)));\n continue;\n }\n const displayPath = relative(repoRoot, absolutePath).replace(/\\\\/g, \"/\");\n for (const rule of rules) {\n if (rule.pattern.test(entry.name)) {\n findings.push({ file: displayPath, line: 0, rule: rule.label });\n break;\n }\n }\n }\n\n return findings;\n}\n\n/** Flags grep-proof media files for manual review -- never silently cleared. */\nasync function flagGrepProofMedia(root: string, repoRoot: string = root): Promise<WardMediaFlag[]> {\n const files = await collectScannableFiles(root, repoRoot, GREP_PROOF_EXTENSIONS);\n return files.map(([, displayPath]) => ({\n file: displayPath,\n reason: \"binary media format -- text extraction is unreliable; review manually for embedded identifiers\",\n }));\n}\n\n/**\n * Runs the full ward scan: content, filenames, and grep-proof media flags.\n * Report-only -- never mutates anything. Categorizes each finding as a plain\n * leak or a protected-vendor-identifier hit per VENDOR_IDENTIFIER_PROTECTION_LIST.\n */\nexport async function runWard(repoRoot: string, options: WardOptions = {}): Promise<WardReport> {\n const userTerms = options.terms ?? [];\n const exclusions = options.exclusions ?? [];\n const extensions = [...WARD_TEXT_EXTENSIONS, ...(options.binaryExtensions ?? [])];\n\n const userRules = createDenylistRules(userTerms, \"ward-term\");\n const vendorRules = createDenylistRules([...VENDOR_IDENTIFIER_PROTECTION_LIST], \"ward-vendor\");\n const allRules = [...userRules, ...vendorRules];\n\n const contentFiles = await collectScannableFiles(repoRoot, repoRoot, extensions);\n const fileLines = new Map<string, string[]>();\n const contentFindings: DenylistFinding[] = [];\n for (const [absolutePath, displayPath] of contentFiles) {\n const findings = await scanFileAllRules(absolutePath, displayPath, allRules);\n if (findings.length > 0) {\n try {\n fileLines.set(displayPath, (await readFile(absolutePath, \"utf8\")).split(\"\\n\"));\n } catch {\n // Unreadable after the initial scan (rare race) -- leave unmapped; exclusions simply won't match.\n }\n }\n contentFindings.push(...findings);\n }\n\n // Not dedupeFindings: that collapses on file:line alone, which would\n // wrongly merge a leak and a protected-vendor-identifier hit that land on\n // the same line -- exactly the case ward needs to keep distinct. Content\n // (line >= 1) and filename (line 0) findings can never collide on\n // file:line, and scanFileAllRules never double-reports the same rule on\n // the same line, so a plain concatenation is already duplicate-free.\n const filenameFindings = await scanFilenames(repoRoot, allRules);\n const combined = [...contentFindings, ...filenameFindings];\n const excluded = applyExclusions(combined, fileLines, exclusions);\n\n const vendorLabels = new Set(vendorRules.map((r) => r.label));\n const findings: WardFinding[] = excluded.map((f) => ({\n ...f,\n category: vendorLabels.has(f.rule) ? \"protected-vendor-identifier\" : \"leak\",\n }));\n\n const mediaFlags = await flagGrepProofMedia(repoRoot);\n\n return { findings, mediaFlags };\n}\n","import { runWard, type WardExclusion } from \"../modules/ward.js\";\n\nexport interface WardCliOptions {\n terms?: string;\n gate?: boolean;\n}\n\nfunction parseTerms(raw?: string): string[] {\n if (!raw) return [];\n return raw\n .split(\",\")\n .map((t) => t.trim())\n .filter(Boolean);\n}\n\n/**\n * spell ward CLI entry point. Report-only by default (matching\n * spell-check-drift's own convention); --gate exits non-zero on any `leak`\n * finding so it can be wired into CI. A `protected-vendor-identifier`\n * finding is informational -- it exists to make a human look before an\n * automated rename touches a real vendor identifier, not to fail a build by\n * itself.\n */\nexport async function runWardCli(\n targetDir: string,\n options: WardCliOptions = {},\n exclusions: WardExclusion[] = [],\n): Promise<void> {\n const terms = parseTerms(options.terms);\n const report = await runWard(targetDir, { terms, exclusions });\n\n console.log(\"\\nspell ward — scanning for leaked identifiers\\n\");\n\n const leaks = report.findings.filter((f) => f.category === \"leak\");\n const protectedHits = report.findings.filter((f) => f.category === \"protected-vendor-identifier\");\n\n if (leaks.length === 0 && protectedHits.length === 0) {\n console.log(\" ✓ No denylisted terms found.\");\n }\n\n for (const finding of leaks) {\n const where = finding.line === 0 ? `${finding.file} (filename)` : `${finding.file}:${finding.line}`;\n console.log(` ✗ [leak] ${where} — rule: ${finding.rule}`);\n }\n\n for (const finding of protectedHits) {\n const where = finding.line === 0 ? `${finding.file} (filename)` : `${finding.file}:${finding.line}`;\n console.log(\n ` ⚠ [protected-vendor-identifier] ${where} — rule: ${finding.rule} — verify before any automated rename touches this line`,\n );\n }\n\n if (report.mediaFlags.length > 0) {\n console.log(\"\\n Grep-proof media flagged for manual review:\");\n for (const flag of report.mediaFlags) {\n console.log(` ? ${flag.file} — ${flag.reason}`);\n }\n }\n\n console.log();\n\n if (options.gate && leaks.length > 0) {\n console.log(` ${leaks.length} leak(s) found. Failing (--gate mode).\\n`);\n process.exitCode = 1;\n return;\n }\n\n if (leaks.length > 0) {\n console.log(` ${leaks.length} leak(s) found. Run with --gate to fail CI on this.\\n`);\n }\n}\n","import { basename, resolve } from \"node:path\";\nimport { input } from \"@inquirer/prompts\";\nimport { readManifest, writeManifest, ManifestNotFoundError } from \"../modules/manifest.js\";\nimport {\n removePrePushHook,\n restorePushUrls,\n blockedRemotes,\n isHookEnforced,\n} from \"../modules/push-safety.js\";\nimport { printInfo, printSuccess, printWarning } from \"../modules/banner.js\";\nimport type { ArcaneManifest } from \"../types.js\";\n\n/**\n * Runs `spell unblock-push` (EF-09 R5).\n *\n * Deliberately its own command and never a side effect of `init`/`update`:\n * a protection that can be lifted by a routine command is not a protection.\n *\n * Two gates, and the PRD is honest about what each one is worth:\n *\n * - **Interactive TTY only.** This is the real bar against a scripted agent —\n * the threat actor the PRD ranks second, since a push is irreversible. It is\n * not absolute (a pseudo-TTY defeats it), and the PRD says so rather than\n * claiming otherwise.\n * - **Typed repository name.** This guards a human against unblocking the wrong\n * repository. It is explicitly NOT agent-resistance: anything that can read\n * `.arcane.json` can read the name back.\n */\nexport async function runUnblockPush(targetDir: string): Promise<void> {\n let manifest: ArcaneManifest;\n try {\n manifest = await readManifest(targetDir);\n } catch (err) {\n if (err instanceof ManifestNotFoundError) {\n console.error('Not initialized. Run \"spell init\" first.');\n process.exit(1);\n return; // guard: process.exit is mocked in tests\n }\n throw err;\n }\n\n // Gate on the CONTROLS, not the declaration. A partial lift writes\n // push_policy \"open\" while the hook or a sentinel URL is still in force, and\n // keying the early return on the manifest meant that state made this command\n // refuse to run again — the failed attempt closed its own retry path. Making\n // partial lifts visible (0.20.1) is not the same as making them recoverable.\n const policy = manifest.push_policy ?? \"open\";\n const stillInForce =\n (await isHookEnforced(targetDir)) || (await blockedRemotes(targetDir)).length > 0;\n if (policy === \"open\" && !stillInForce) {\n printInfo(\"This repository is not push-blocked — nothing to undo.\");\n return;\n }\n if (policy === \"open\") {\n printWarning(\n \"The manifest says push_policy: open, but this repository still has Arcane's push block \" +\n \"in force — most likely a previous unblock only partly succeeded. Continuing so it can \" +\n \"be finished.\",\n );\n }\n\n if (!process.stdin.isTTY) {\n console.error(\n \"spell unblock-push must be run from an interactive terminal.\\n\" +\n \"Lifting a push block is a deliberate decision, so it cannot be scripted, piped, or run in CI.\",\n );\n process.exit(1);\n return;\n }\n\n const repoName = basename(resolve(targetDir));\n if (repoName === \"\") {\n // A repository at a filesystem root has no basename, which would turn the\n // confirmation into \"press Enter\". A gate that can silently become vacuous\n // must fail closed instead.\n console.error(\n \"Could not determine a repository name to confirm against (is this repository at a filesystem root?). Refusing to unblock.\",\n );\n process.exit(1);\n return;\n }\n\n printWarning(`This repository's push_policy is \"${policy}\".`);\n printInfo(\n \"Unblocking restores the ability to push this repository's full history to its remote. \" +\n \"Deleting a file later does not undo a push: the content stays in history, in any clone \" +\n \"already made, and in the remote's own backups.\",\n );\n console.log();\n\n const typed = await input({\n message: `Type the repository name to confirm (${repoName}):`,\n });\n\n if (typed.trim() !== repoName) {\n console.error(`\\nName did not match (\"${typed.trim()}\" ≠ \"${repoName}\"). Nothing changed.`);\n process.exit(1);\n return;\n }\n\n await removePrePushHook(targetDir);\n const results = await restorePushUrls(targetDir);\n const restored = results.filter((r) => r.status === \"restored\").map((r) => r.remote);\n const failed = results.filter((r) => r.status === \"failed\");\n // A remote still carrying the sentinel after we claimed to have unblocked it\n // is the manifest-lies-about-posture failure in the opposite direction, so it\n // is checked directly rather than inferred from what we think we did.\n const stillBlocked = await blockedRemotes(targetDir);\n\n // No \"just this once\" mode: the manifest must never claim a protection the\n // repository no longer has.\n const updated: ArcaneManifest = {\n ...manifest,\n push_policy: \"open\",\n push_policy_unblocked_at: new Date().toISOString(),\n };\n await writeManifest(targetDir, updated);\n\n // Check the hook too, not just the URLs: `removePrePushHook` declines to touch\n // a foreign or unreadable core.hooksPath, so it can legitimately do nothing.\n const hookStillOn = await isHookEnforced(targetDir);\n const fullyLifted = failed.length === 0 && stillBlocked.length === 0 && !hookStillOn;\n\n // Never let a partial result read as a clean one. Reporting success first and\n // appending warnings underneath is exactly the shape this feature refuses to\n // accept elsewhere.\n if (fullyLifted) {\n printSuccess(`Push unblocked for \"${repoName}\".`);\n } else {\n printWarning(\n `Push only PARTIALLY unblocked for \"${repoName}\". The manifest now says open; the ` +\n \"repository is not fully open yet. Details below.\",\n );\n }\n if (restored.length > 0) {\n printInfo(`Restored push URL for: ${restored.join(\", \")}.`);\n }\n if (hookStillOn) {\n printWarning(\n \"The pre-push hook is still in force. Arcane did not remove it because `core.hooksPath` is \" +\n \"not one it owns, or could not be read. Check `git config --show-scope --get core.hooksPath`.\",\n );\n }\n if (failed.length > 0) {\n printWarning(\n `Could not restore the push URL for: ${failed\n .map((r) => `${r.remote} (${r.reason ?? \"unknown error\"})`)\n .join(\"; \")}.`,\n );\n }\n if (stillBlocked.length > 0) {\n // Most likely cause: the remote was renamed while blocked, so the recorded\n // original moved with it but a *different* remote now carries the sentinel.\n printWarning(\n `These remotes still have a blocked push URL and no recorded original: ${stillBlocked.join(\", \")}. ` +\n \"Set them yourself with `git remote set-url --push <name> <url>` — until then, pushing to \" +\n \"them will fail even though the manifest now says open.\",\n );\n }\n printInfo(\n \"Recorded in .arcane.json as push_policy: open, with the time it was lifted. \" +\n \"Commit that change so the repository's actual posture stays visible to everyone.\",\n );\n}\n"],"mappings":"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","names":["createRequire","dirname","join","select","input","join","chalk","readFile","writeFile","path","manifestPath","resolve","mkdir","writeFile","copyFile","join","readFile","readdir","access","isRecord","path","readFile","readFile","access","writeFile","mkdir","join","readFile","writeFile","path","path","readFile","writeFile","join","mkdir","writeFile","r","join","mkdir","writeFile","copyFile","mkdir","readFile","writeFile","access","rm","readdir","join","resolve","stdout","join","mkdir","writeFile","join","readdir","readFile","access","rm","chalk","select","join","input","join","join","join","readFile","writeFile","rm","confirm","select","input","readdir","writeFile","join","confirm","select","input","join","readdir","writeFile","i","j","join","rm","readFile","writeFile","readFile","writeFile","mkdir","dirname","join","homedir","require","pkg","rm","join","confirm","confirm","join","rm","access","readFile","mkdir","join","dirname","execFile","promisify","readFile","readdir","join","execFile","execFileAsync","promisify","execFile","isRecord","join","readdir","manifestPath","access","readFile","mkdir","dirname","readdir","readFile","join","relative","readFile","readdir","join","relative","findings","basename","resolve","input","basename","resolve","input","require","createRequire","join","dirname"]}