@vaubaan/harness 1.3.0 → 1.3.2

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/init.js CHANGED
@@ -543,18 +543,26 @@ ${body}` });
543
543
  renderStopHook() {
544
544
  const content = `import { spawnSync } from "node:child_process";
545
545
 
546
- export const HarnessStopHook = async ({ client, directory }) => ({
546
+ // Runs the harness lint and returns the report to inject, or "" when the
547
+ // turn may end.
548
+ const lintReport = (directory, sessionID) => {
549
+ const r = spawnSync(
550
+ "npx",
551
+ ["-y", "${STOP_HOOK_PACKAGE}", "stop-hook", "--engine", "opencode", "--cwd", directory],
552
+ { input: JSON.stringify({ sessionID }), encoding: "utf-8" },
553
+ );
554
+ const report = (r.stderr ?? "").trim();
555
+ return r.status === 2 ? report : "";
556
+ };
557
+
558
+ // OpenCode 1.x entry point, exposed as server() below.
559
+ const HarnessStopHook = async ({ client, directory }) => ({
547
560
  event: async ({ event }) => {
548
561
  if (event.type !== "session.idle") return;
549
562
  const sessionID = event.properties?.sessionID;
550
563
  if (!sessionID) return;
551
- const r = spawnSync(
552
- "npx",
553
- ["-y", "${STOP_HOOK_PACKAGE}", "stop-hook", "--engine", "opencode", "--cwd", directory],
554
- { input: JSON.stringify({ sessionID }), encoding: "utf-8" },
555
- );
556
- const report = (r.stderr ?? "").trim();
557
- if (r.status !== 2 || report === "") return;
564
+ const report = lintReport(directory, sessionID);
565
+ if (report === "") return;
558
566
  // OpenCode defaults to its build agent when a prompt omits agent.
559
567
  // Preserve the last conversation persona, excluding compaction summaries.
560
568
  const history = await client.session.messages({ path: { id: sessionID } }).catch(() => undefined);
@@ -570,6 +578,31 @@ export const HarnessStopHook = async ({ client, directory }) => ({
570
578
  });
571
579
  },
572
580
  });
581
+
582
+ // One default export for both majors: OpenCode 1.x calls server(),
583
+ // OpenCode 2.x calls setup(). A V2 session keeps its agent, so the report
584
+ // is sent without naming the persona.
585
+ export default {
586
+ id: "vaubaan-harness-stop-hook",
587
+ server: HarnessStopHook,
588
+ setup(context) {
589
+ const directory = context.location.directory;
590
+ const controller = new AbortController();
591
+ const listen = async () => {
592
+ for await (const event of context.event.subscribe({ signal: controller.signal })) {
593
+ if (event.type !== "session.idle") continue;
594
+ if (event.location?.directory && event.location.directory !== directory) continue;
595
+ const sessionID = event.data?.sessionID;
596
+ if (!sessionID) continue;
597
+ const report = lintReport(directory, sessionID);
598
+ if (report === "") continue;
599
+ await context.session.prompt({ sessionID, text: report }).catch(() => undefined);
600
+ }
601
+ };
602
+ listen().catch(() => undefined);
603
+ return () => controller.abort();
604
+ },
605
+ };
573
606
  `;
574
607
  return {
575
608
  files: [{ path: `${BASE3}/plugins/harness-stop-hook.ts`, content }],
@@ -766,7 +799,7 @@ import { join as join5 } from "path";
766
799
  import { z as z5 } from "zod";
767
800
 
768
801
  // src/version.ts
769
- var VERSION = "1.3.0";
802
+ var VERSION = "1.3.2";
770
803
 
771
804
  // src/cli/opencode-config.ts
772
805
  import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
package/dist/init.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/init.ts","../src/loader.ts","../src/parser/common.ts","../src/parser/schemas.ts","../src/types.ts","../src/parser/agent.ts","../src/parser/cmd.ts","../src/parser/skill.ts","../src/util/yaml.ts","../src/mcp.ts","../src/renderers/common.ts","../src/renderers/claude-code.ts","../src/renderers/codex-cli.ts","../src/renderers/opencode.ts","../src/renderers/index.ts","../src/render.ts","../src/cli/managed-paths.ts","../src/cli/manifest.ts","../src/version.ts","../src/cli/opencode-config.ts","../src/cli/update-config.ts","../src/cli/uninstall.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { loadHarness, loadOverrides, loadProjectSkills } from \"../loader.js\";\nimport { resolveMcpIds } from \"../mcp.js\";\nimport { type RenderOutput, render } from \"../render.js\";\nimport { ENGINES, type Engine, type RenderedFile } from \"../types.js\";\nimport { assertManagedPaths } from \"./managed-paths.js\";\nimport { MANIFEST_FILENAME, readManifest, writeManifest } from \"./manifest.js\";\nimport { OPENCODE_CONFIG_PATH, planOpenCodeConfig } from \"./opencode-config.js\";\nimport { removeRenderedFiles } from \"./uninstall.js\";\n\n/** Cardinal file of the optional `docs/quality/` pillar. */\nconst QUALITY_DOC_PATH = \"docs/quality/code-quality.md\";\n\nexport interface InitArgs {\n targetDir: string;\n engines?: ReadonlyArray<string>;\n overridesDir?: string;\n /**\n * Directory containing the harness content (agents/, skills/, commands/,\n * templates/). Defaults to the harness package's own `dist/` (resolved\n * via `import.meta.url`), so programmatic callers usually omit it.\n */\n packageDir?: string;\n mcpServers?: ReadonlyArray<string>;\n /**\n * Stop-hook installation. Default `true`. When enabled, each engine\n * receives a hook config that calls `vaubaan-harness stop-hook\n * --engine <engine>` and injects the lint report (with skill\n * suggestions) into the running session whenever the worktree is\n * dirty and lint fails at end-of-turn. Pass `false` to skip the\n * hook configs entirely (runtime kill-switch remains available via\n * `HARNESS_LINT_DISABLE=1`).\n */\n withStopHook?: boolean;\n}\n\nexport interface InitResult {\n filesWritten: string[];\n /** Files a previous `init` rendered that this one no longer does (layout change, engine dropped). */\n staleFilesRemoved: string[];\n warnings: string[];\n stopHookInstalled: boolean;\n}\n\nfunction resolveEngineList(requested: ReadonlyArray<string> | undefined): Engine[] {\n if (!requested || requested.length === 0) return [...ENGINES];\n return requested.map((e) => {\n if (!ENGINES.includes(e as Engine)) {\n throw new Error(`unknown engine: ${e} (expected one of ${ENGINES.join(\", \")})`);\n }\n return e as Engine;\n });\n}\n\n/**\n * Resolves the harness package's bundled content directory. The CAH\n * tsup config emits this module to both `dist/init.js` (programmatic\n * `./init` export) and inlines it into `dist/cli/index.js` (CLI use). The\n * content (`agents/`, `skills/`, `commands/`, `templates/`) always sits\n * at `dist/` — same dir as `dist/init.js`, parent of `dist/cli/index.js`.\n * In dev (`src/cli/init.ts`) the content also sits at `src/`. We\n * disambiguate by checking which ancestor contains `agents/`.\n */\nfunction defaultPackageDir(): string {\n const here = dirname(fileURLToPath(import.meta.url));\n if (existsSync(join(here, \"agents\"))) return here;\n return resolve(here, \"..\");\n}\n\nexport function planInit(args: InitArgs): {\n engines: Engine[];\n output: RenderOutput;\n stopHookInstalled: boolean;\n} {\n const engines = resolveEngineList(args.engines);\n const packageDir = args.packageDir ?? defaultPackageDir();\n const harness = loadHarness(packageDir);\n const overrides = args.overridesDir ? loadOverrides(args.overridesDir) : undefined;\n const projectSkills = loadProjectSkills(args.targetDir);\n const hasQualityDoc = existsSync(join(args.targetDir, QUALITY_DOC_PATH));\n const mcpServers = args.mcpServers ? resolveMcpIds(args.mcpServers) : undefined;\n const stopHookInstalled = args.withStopHook !== false;\n const output = render({\n harness,\n engines,\n overrides,\n projectSkills,\n hasQualityDoc,\n mcpServers,\n withStopHook: stopHookInstalled,\n });\n return { engines, output, stopHookInstalled };\n}\n\nexport function writeFilesToTarget(\n files: ReadonlyArray<RenderedFile>,\n targetDir: string,\n): string[] {\n assertManagedPaths(\n targetDir,\n files.map((file) => file.path),\n );\n const written: string[] = [];\n for (const f of files) {\n const full = join(targetDir, f.path);\n mkdirSync(dirname(full), { recursive: true });\n writeFileSync(full, f.content);\n written.push(f.path);\n }\n return written;\n}\n\nexport function initCommand(args: InitArgs): InitResult {\n const { engines, output, stopHookInstalled } = planInit(args);\n const previous = readManifest(args.targetDir);\n assertManagedPaths(args.targetDir, [\n MANIFEST_FILENAME,\n ...(previous?.files ?? []),\n ...output.files.map((file) => file.path),\n ...(previous?.opencodeConfig ? [OPENCODE_CONFIG_PATH] : []),\n ]);\n const desiredConfig = output.files.find((file) => file.path === OPENCODE_CONFIG_PATH);\n const config = planOpenCodeConfig(args.targetDir, desiredConfig, previous?.opencodeConfig);\n const next = new Set(output.files.map((f) => f.path));\n const stale = (previous?.files ?? []).filter((f) => !next.has(f) && f !== OPENCODE_CONFIG_PATH);\n if (config.remove) stale.push(OPENCODE_CONFIG_PATH);\n const staleFilesRemoved = removeRenderedFiles(resolve(args.targetDir), stale).filesRemoved;\n const ownedFiles = output.files.filter((file) => file.path !== OPENCODE_CONFIG_PATH);\n const filesWritten = writeFilesToTarget(ownedFiles, args.targetDir);\n if (config.write) writeFilesToTarget([config.write], args.targetDir);\n writeManifest(args.targetDir, engines, filesWritten, {\n stopHookInstalled,\n stopHookEngines: stopHookInstalled ? engines : undefined,\n opencodeConfig: config.ownership,\n overridesDir: args.overridesDir\n ? resolve(args.overridesDir) === resolve(args.targetDir)\n ? \".\"\n : resolve(args.overridesDir)\n : undefined,\n });\n if (config.write) filesWritten.push(OPENCODE_CONFIG_PATH);\n const warnings = [...output.warnings, ...config.warnings];\n if (previous?.files.includes(OPENCODE_CONFIG_PATH) && !previous.opencodeConfig) {\n warnings.push(`preserved legacy shared configuration: ${OPENCODE_CONFIG_PATH}`);\n }\n return { filesWritten, staleFilesRemoved, warnings, stopHookInstalled };\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport fg from \"fast-glob\";\nimport { z } from \"zod\";\nimport { parseAgent } from \"./parser/agent.js\";\nimport { parseCmd } from \"./parser/cmd.js\";\nimport { type Skill, parseSkill } from \"./parser/skill.js\";\nimport type { Harness, HarnessOverrides } from \"./render.js\";\nimport { parseYAML } from \"./util/yaml.js\";\n\nexport const DisableYamlSchema = z\n .object({ disable: z.array(z.string()).optional() })\n .passthrough();\n\nexport interface LoadOptions {\n agentsDir?: string;\n skillsDir?: string;\n commandsDir?: string;\n}\n\nexport function loadHarness(packageDir: string, opts: LoadOptions = {}): Harness {\n const agentsDir = opts.agentsDir ?? join(packageDir, \"agents\");\n const skillsDir = opts.skillsDir ?? join(packageDir, \"skills\");\n const commandsDir = opts.commandsDir ?? join(packageDir, \"commands\");\n\n const agentFiles = fg.sync(\"*.agent.md\", { cwd: agentsDir, absolute: true });\n const skillFiles = fg.sync(\"*.skill.md\", { cwd: skillsDir, absolute: true });\n const cmdFiles = fg.sync(\"*.cmd.md\", { cwd: commandsDir, absolute: true });\n\n return {\n agents: agentFiles.map((f) => parseAgent(f, readFileSync(f, \"utf8\"))),\n skills: skillFiles.map((f) => parseSkill(f, readFileSync(f, \"utf8\"))),\n cmds: cmdFiles.map((f) => parseCmd(f, readFileSync(f, \"utf8\"))),\n };\n}\n\nexport function loadProjectSkills(targetDir: string): Skill[] {\n const skillsDir = join(targetDir, \"docs\", \"skills\");\n if (!existsSync(skillsDir)) return [];\n const skillFiles = fg.sync(\"*.skill.md\", { cwd: skillsDir, absolute: true });\n return skillFiles.map((f) => parseSkill(f, readFileSync(f, \"utf8\")));\n}\n\nexport function loadOverrides(worktreeDir: string): HarnessOverrides | undefined {\n const overridesDir = join(worktreeDir, \".harness-overrides\");\n if (!existsSync(overridesDir)) return undefined;\n\n const added = loadHarness(overridesDir, {\n agentsDir: join(overridesDir, \"agents\"),\n skillsDir: join(overridesDir, \"skills\"),\n commandsDir: join(overridesDir, \"commands\"),\n });\n\n const disablePath = join(overridesDir, \"disable.yaml\");\n let disable: string[] = [];\n if (existsSync(disablePath)) {\n try {\n const parsed = DisableYamlSchema.safeParse(parseYAML(readFileSync(disablePath, \"utf8\")));\n if (parsed.success && parsed.data.disable) {\n disable = parsed.data.disable;\n }\n } catch {\n // corrupt YAML — leave disable as []\n }\n }\n\n return { add: added, disable };\n}\n","import { readFileSync } from \"node:fs\";\nimport matter from \"gray-matter\";\nimport type { z } from \"zod\";\nimport { ParseError } from \"./schemas.js\";\n\nexport interface ParsedFile<T> {\n meta: T;\n body: string;\n sourcePath: string;\n}\n\nexport function parseWithSchema<T extends z.ZodTypeAny>(\n filePath: string,\n source: string,\n schema: T,\n): ParsedFile<z.infer<T>> {\n const parsed = matter(source);\n const result = schema.safeParse(parsed.data);\n if (!result.success) {\n throw new ParseError(filePath, result.error.issues);\n }\n return {\n meta: result.data,\n body: parsed.content.trim(),\n sourcePath: filePath,\n };\n}\n\nexport function parseFileWithSchema<T extends z.ZodTypeAny>(\n filePath: string,\n schema: T,\n): ParsedFile<z.infer<T>> {\n const source = readFileSync(filePath, \"utf8\");\n return parseWithSchema(filePath, source, schema);\n}\n","import { z } from \"zod\";\nimport { AGENT_IDS, CAPABILITIES, ENGINES } from \"../types.js\";\n\nconst IdSchema = z\n .string()\n .min(1)\n .regex(/^[a-z][a-z0-9-]*$/, \"id must be kebab-case (lowercase + digits + hyphens)\");\n\nconst SkillFrontmatterSchema = z\n .object({\n id: IdSchema,\n description: z.string().min(1),\n engines: z.array(z.enum(ENGINES)).min(1).optional(),\n requires: z.array(z.enum(CAPABILITIES)).optional(),\n tags: z.array(z.string()).optional(),\n })\n .strict();\n\nexport type SkillFrontmatter = z.infer<typeof SkillFrontmatterSchema>;\n\nconst CmdArgEnumSchema = z\n .object({\n name: z.string().min(1),\n type: z.literal(\"enum\"),\n values: z.array(z.string()).min(1),\n default: z.string().optional(),\n })\n .strict();\n\nconst CmdArgStringSchema = z\n .object({\n name: z.string().min(1),\n type: z.literal(\"string\"),\n default: z.string().optional(),\n })\n .strict();\n\nconst CmdArgSchema = z.discriminatedUnion(\"type\", [CmdArgEnumSchema, CmdArgStringSchema]);\n\nexport type CmdArg = z.infer<typeof CmdArgSchema>;\n\nconst CmdFrontmatterSchema = z\n .object({\n id: IdSchema,\n trigger: z.string().regex(/^\\/[a-z][a-z0-9-]*$/, \"trigger must be /kebab-case\"),\n invokes_skill: IdSchema,\n args: z.array(CmdArgSchema).optional(),\n description: z.string().min(1),\n })\n .strict();\n\nexport type CmdFrontmatter = z.infer<typeof CmdFrontmatterSchema>;\n\nconst AgentFrontmatterSchema = z\n .object({\n id: z.enum(AGENT_IDS),\n description: z.string().min(1),\n })\n .strict();\n\nexport type AgentFrontmatter = z.infer<typeof AgentFrontmatterSchema>;\n\nexport const Schemas = {\n Skill: SkillFrontmatterSchema,\n Cmd: CmdFrontmatterSchema,\n Agent: AgentFrontmatterSchema,\n} as const;\n\nexport class ParseError extends Error {\n constructor(\n public readonly file: string,\n public readonly issues: z.ZodIssue[],\n ) {\n const messages = issues\n .map((i) => ` - ${i.path.join(\".\") || \"<root>\"}: ${i.message}`)\n .join(\"\\n\");\n super(`Frontmatter validation failed for ${file}:\\n${messages}`);\n this.name = \"ParseError\";\n }\n}\n","export const AGENT_IDS = [\"coding\", \"review\", \"merge\", \"planning\"] as const;\nexport type AgentId = (typeof AGENT_IDS)[number];\n\nexport const ENGINES = [\"claude-code\", \"codex-cli\", \"opencode\"] as const;\nexport type Engine = (typeof ENGINES)[number];\n\nexport const ENGINE_ROOT_DIR: Record<Engine, string> = {\n \"claude-code\": \".claude\",\n \"codex-cli\": \".codex\",\n opencode: \".opencode\",\n};\n\nexport const CAPABILITIES = [\"multi-step\", \"slash-command\", \"inline-exec\"] as const;\nexport type Capability = (typeof CAPABILITIES)[number];\n\nexport interface RenderedFile {\n path: string;\n content: string;\n}\n\nexport interface CapabilitiesMatrix {\n [engine: string]: ReadonlyArray<Capability>;\n}\n\nexport const CAPABILITIES_MATRIX: Record<Engine, ReadonlyArray<Capability>> = {\n \"claude-code\": [\"multi-step\", \"slash-command\", \"inline-exec\"],\n \"codex-cli\": [\"multi-step\", \"slash-command\", \"inline-exec\"],\n opencode: [\"multi-step\", \"slash-command\", \"inline-exec\"],\n};\n\nexport const DEGRADED_CAPABILITIES: Partial<Record<Engine, ReadonlyArray<Capability>>> = {\n \"codex-cli\": [\"multi-step\"],\n};\n\nexport function engineSupports(engine: Engine, capability: Capability): boolean {\n return CAPABILITIES_MATRIX[engine].includes(capability);\n}\n","import { parseFileWithSchema, parseWithSchema } from \"./common.js\";\nimport type { ParsedFile } from \"./common.js\";\nimport { type AgentFrontmatter, Schemas } from \"./schemas.js\";\n\nexport type Agent = ParsedFile<AgentFrontmatter>;\n\nexport function parseAgent(filePath: string, source: string): Agent {\n return parseWithSchema(filePath, source, Schemas.Agent);\n}\n\nexport function parseAgentFile(filePath: string): Agent {\n return parseFileWithSchema(filePath, Schemas.Agent);\n}\n","import { parseFileWithSchema, parseWithSchema } from \"./common.js\";\nimport type { ParsedFile } from \"./common.js\";\nimport { type CmdFrontmatter, Schemas } from \"./schemas.js\";\n\nexport type Cmd = ParsedFile<CmdFrontmatter>;\n\nexport function parseCmd(filePath: string, source: string): Cmd {\n return parseWithSchema(filePath, source, Schemas.Cmd);\n}\n\nexport function parseCmdFile(filePath: string): Cmd {\n return parseFileWithSchema(filePath, Schemas.Cmd);\n}\n","import { parseFileWithSchema, parseWithSchema } from \"./common.js\";\nimport type { ParsedFile } from \"./common.js\";\nimport { Schemas, type SkillFrontmatter } from \"./schemas.js\";\n\nexport type Skill = ParsedFile<SkillFrontmatter>;\n\nexport function parseSkill(filePath: string, source: string): Skill {\n return parseWithSchema(filePath, source, Schemas.Skill);\n}\n\nexport function parseSkillFile(filePath: string): Skill {\n return parseFileWithSchema(filePath, Schemas.Skill);\n}\n","import { parse as yamlParse } from \"yaml\";\n\nexport function parseYAML(source: string): unknown {\n return yamlParse(source);\n}\n","export const MCP_SERVER_IDS = [\"context7\"] as const;\nexport type McpServerId = (typeof MCP_SERVER_IDS)[number];\n\nexport interface McpServerSpec {\n id: McpServerId;\n description: string;\n command: string;\n args: ReadonlyArray<string>;\n env?: Record<string, string>;\n}\n\nexport const MCP_SERVERS: Record<McpServerId, McpServerSpec> = {\n context7: {\n id: \"context7\",\n description:\n \"Upstash Context7 — fetches up-to-date library docs via resolve-library-id + get-library-docs.\",\n command: \"npx\",\n args: [\"-y\", \"@upstash/context7-mcp\"],\n },\n};\n\nexport function resolveMcpIds(requested: ReadonlyArray<string>): McpServerId[] {\n return requested.map((id) => {\n if (!(MCP_SERVER_IDS as ReadonlyArray<string>).includes(id)) {\n throw new Error(`unknown MCP server: ${id} (expected one of ${MCP_SERVER_IDS.join(\", \")})`);\n }\n return id as McpServerId;\n });\n}\n","import { stringify as yamlStringify } from \"yaml\";\nimport type { McpServerSpec } from \"../mcp.js\";\nimport type { Agent } from \"../parser/agent.js\";\nimport type { Cmd } from \"../parser/cmd.js\";\nimport type { Skill } from \"../parser/skill.js\";\nimport {\n CAPABILITIES_MATRIX,\n type Capability,\n DEGRADED_CAPABILITIES,\n type Engine,\n type RenderedFile,\n} from \"../types.js\";\n\nexport interface UmbrellaExtras {\n availableSkills: ReadonlyArray<Skill>;\n availableCommands: ReadonlyArray<Cmd>;\n hasProjectSkills?: boolean;\n hasQualityDoc?: boolean;\n}\n\nexport interface RenderResult {\n files: RenderedFile[];\n warnings: string[];\n}\n\nexport interface Renderer {\n readonly engine: Engine;\n renderSkill(skill: Skill): RenderResult;\n renderCmd(cmd: Cmd): RenderResult;\n renderAgents(agents: ReadonlyArray<Agent>): RenderResult;\n renderMcp(servers: ReadonlyArray<McpServerSpec>): RenderResult;\n renderStopHook(): RenderResult;\n}\n\nexport const STOP_HOOK_PACKAGE = \"@vaubaan/harness\";\n\nexport interface CapabilityCheck {\n blockingWarnings: string[];\n degradedWarnings: string[];\n}\n\nexport function checkSkillCapabilities(skill: Skill, engine: Engine): CapabilityCheck {\n const blockingWarnings: string[] = [];\n const degradedWarnings: string[] = [];\n const supported = CAPABILITIES_MATRIX[engine];\n const degraded = DEGRADED_CAPABILITIES[engine] ?? [];\n if (!skill.meta.requires) return { blockingWarnings, degradedWarnings };\n for (const cap of skill.meta.requires) {\n if (!supported.includes(cap as Capability)) {\n blockingWarnings.push(\n `skill \"${skill.meta.id}\" requires \"${cap}\" not supported by \"${engine}\" — skipped`,\n );\n } else if (degraded.includes(cap as Capability)) {\n degradedWarnings.push(\n `skill \"${skill.meta.id}\" requires \"${cap}\" — supported by \"${engine}\" with degradation`,\n );\n }\n }\n return { blockingWarnings, degradedWarnings };\n}\n\nexport function isSkillEngineAllowed(skill: Skill, engine: Engine): boolean {\n if (!skill.meta.engines) return true;\n return skill.meta.engines.includes(engine);\n}\n\nexport function yamlFrontmatter(data: Record<string, unknown>): string {\n const rendered = yamlStringify(data, { lineWidth: 0 }).trimEnd();\n return `---\\n${rendered}\\n---\\n`;\n}\n\nconst SCALAR_NEEDS_QUOTE = /[^a-zA-Z0-9_./-]/;\n\nfunction tomlEscapeString(s: string): string {\n return `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"').replace(/\\n/g, \"\\\\n\")}\"`;\n}\n\nfunction tomlValue(v: unknown): string {\n if (Array.isArray(v)) {\n return `[${v.map((x) => tomlValue(x)).join(\", \")}]`;\n }\n if (typeof v === \"string\") {\n if (v.includes(\"\\n\")) return tomlEscapeString(v);\n return SCALAR_NEEDS_QUOTE.test(v) ? tomlEscapeString(v) : `\"${v}\"`;\n }\n if (typeof v === \"boolean\" || typeof v === \"number\") {\n return String(v);\n }\n return tomlEscapeString(String(v));\n}\n\n/** TOML multi-line basic string (`\"\"\"…\"\"\"`), used for Codex `developer_instructions`. */\nexport function tomlMultilineString(s: string): string {\n const escaped = s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"\"\"/g, '\"\"\\\\\"');\n return `\"\"\"\\n${escaped}\\n\"\"\"`;\n}\n\nexport function tomlQuoteString(s: string): string {\n return tomlValue(s);\n}\n\nexport function tomlInlineArray(items: ReadonlyArray<unknown>): string {\n return tomlValue([...items]);\n}\n\nexport function tomlInlineTable(table: Record<string, string>): string {\n const entries = Object.entries(table).map(([k, v]) => `${k} = ${tomlValue(v)}`);\n return `{ ${entries.join(\", \")} }`;\n}\n\nexport function frontmatterDataForSkill(skill: Skill): Record<string, unknown> {\n // Agent Skills spec (agentskills.io): `name` must match the directory name.\n const data: Record<string, unknown> = {\n name: skill.meta.id,\n description: skill.meta.description,\n };\n if (skill.meta.tags && skill.meta.tags.length > 0) data.tags = skill.meta.tags;\n return data;\n}\n\nexport function frontmatterDataForCmd(cmd: Cmd): Record<string, unknown> {\n const data: Record<string, unknown> = {\n id: cmd.meta.id,\n trigger: cmd.meta.trigger,\n description: cmd.meta.description,\n };\n if (cmd.meta.args && cmd.meta.args.length > 0) {\n data.args = cmd.meta.args.map((a) => {\n if (a.type === \"enum\") {\n return a.default !== undefined\n ? { name: a.name, type: a.type, values: a.values, default: a.default }\n : { name: a.name, type: a.type, values: a.values };\n }\n return a.default !== undefined\n ? { name: a.name, type: a.type, default: a.default }\n : { name: a.name, type: a.type };\n });\n }\n return data;\n}\n\n/**\n * Personas carry their role contract only: engines discover skills and\n * commands natively, so listing them per persona is pure context cost.\n */\nexport function buildAgentBody(agent: Agent): string {\n return `${agent.body.trim()}\\n`;\n}\n\nexport function buildUmbrellaBody(_agents: ReadonlyArray<Agent>, extras: UmbrellaExtras): string {\n const triggerBySkill = new Map(\n extras.availableCommands.map((c) => [c.meta.invokes_skill, c.meta.trigger]),\n );\n const skillLines = extras.availableSkills.map((s) => {\n const trigger = triggerBySkill.get(s.meta.id);\n const label = trigger ? `\\`${s.meta.id}\\` (\\`${trigger}\\`)` : `\\`${s.meta.id}\\``;\n return `- ${label} — ${s.meta.description.split(\"\\n\")[0]}`;\n });\n const sections: string[] = [\n \"# How we work\",\n \"\",\n \"This file describes **how to work in this project**. The **business context** (what the project does, how to run it, which subsystems it contains) lives in `README.md` and `docs/`. Read them first.\",\n \"\",\n \"## Project map\",\n \"\",\n \"- `README.md` — pitch, quick start, scripts. Entry point.\",\n \"- `docs/spec/<subsystem>.md` — *what* and *why* (tech-agnostic).\",\n \"- `docs/handbook/<feature>.md` — *how it actually works* today.\",\n \"- `docs/decisions/<slug>.md` — ADRs: structural choices and rejected alternatives.\",\n \"- `docs/tests/integration-tests.md` & `e2e-tests.md` — core scenarios.\",\n \"- `docs/workflow/coding-workflow.md` — CI, branches, PR, release.\",\n ...(extras.hasProjectSkills\n ? [\"- `docs/skills/*.skill.md` — the project's domain skills.\"]\n : []),\n ...(extras.hasQualityDoc\n ? [\n \"- `docs/quality/code-quality.md` — the project's code-quality rules: mechanical checks, judgment rules, accepted deviations. Read it before writing or auditing code.\",\n ]\n : []),\n \"\",\n \"## Doc-first\",\n \"\",\n \"The order is: **understand the docs → fill the gaps → code → update the docs → commit**. If the docs are silent or stale on something you change, fill the gap upfront with the doc-skill writers — not downstream, not after the fact.\",\n \"\",\n \"- Missing spec for a subsystem you touch → **do not code**, report the gap.\",\n \"- Implicit structural decision in your changes → an ADR (`/decision`).\",\n \"- Changed feature behavior → update the matching handbook (`/handbook`).\",\n \"- Suspected code ↔ doc drift → `/drift` before moving on.\",\n ];\n if (skillLines.length > 0) {\n sections.push(\"\", \"## Doc-skills\", \"\", skillLines.join(\"\\n\"));\n }\n return `${sections.join(\"\\n\")}\\n`;\n}\n","import type { McpServerSpec } from \"../mcp.js\";\nimport type { Agent } from \"../parser/agent.js\";\nimport type { Cmd } from \"../parser/cmd.js\";\nimport type { Skill } from \"../parser/skill.js\";\nimport type { Engine } from \"../types.js\";\nimport {\n type RenderResult,\n type Renderer,\n STOP_HOOK_PACKAGE,\n buildAgentBody,\n checkSkillCapabilities,\n frontmatterDataForCmd,\n frontmatterDataForSkill,\n isSkillEngineAllowed,\n yamlFrontmatter,\n} from \"./common.js\";\n\nconst ENGINE: Engine = \"claude-code\";\nconst BASE = \".claude\";\n\nexport const claudeCodeRenderer: Renderer = {\n engine: ENGINE,\n renderSkill(skill: Skill): RenderResult {\n if (!isSkillEngineAllowed(skill, ENGINE)) {\n return {\n files: [],\n warnings: [`skill \"${skill.meta.id}\" excluded from engine \"${ENGINE}\"`],\n };\n }\n const check = checkSkillCapabilities(skill, ENGINE);\n if (check.blockingWarnings.length > 0) {\n return { files: [], warnings: check.blockingWarnings };\n }\n const content = `${yamlFrontmatter(frontmatterDataForSkill(skill))}\\n${skill.body}\\n`;\n return {\n files: [{ path: `${BASE}/skills/${skill.meta.id}/SKILL.md`, content }],\n warnings: check.degradedWarnings,\n };\n },\n renderCmd(cmd: Cmd): RenderResult {\n const content = `${yamlFrontmatter(frontmatterDataForCmd(cmd))}\\n${cmd.body}\\n`;\n return {\n files: [{ path: `${BASE}/commands/${cmd.meta.id}.md`, content }],\n warnings: [],\n };\n },\n renderAgents(agents: ReadonlyArray<Agent>): RenderResult {\n const files = [];\n for (const agent of agents) {\n const subagentFrontmatter = yamlFrontmatter({\n name: agent.meta.id,\n description: agent.meta.description,\n });\n const body = buildAgentBody(agent);\n const content = `${subagentFrontmatter}\\n${body}`;\n files.push({ path: `${BASE}/agents/${agent.meta.id}.md`, content });\n }\n return { files, warnings: [] };\n },\n renderMcp(servers: ReadonlyArray<McpServerSpec>): RenderResult {\n if (servers.length === 0) return { files: [], warnings: [] };\n const mcpServers: Record<string, Record<string, unknown>> = {};\n for (const s of servers) {\n const entry: Record<string, unknown> = { command: s.command, args: [...s.args] };\n if (s.env) entry.env = s.env;\n mcpServers[s.id] = entry;\n }\n const content = `${JSON.stringify({ mcpServers }, null, 2)}\\n`;\n return { files: [{ path: \".mcp.json\", content }], warnings: [] };\n },\n renderStopHook(): RenderResult {\n const settings = {\n hooks: {\n Stop: [\n {\n matcher: \"\",\n hooks: [\n {\n type: \"command\",\n command: `npx -y ${STOP_HOOK_PACKAGE} stop-hook --engine claude`,\n },\n ],\n },\n ],\n },\n };\n return {\n files: [{ path: `${BASE}/settings.json`, content: `${JSON.stringify(settings, null, 2)}\\n` }],\n warnings: [],\n };\n },\n};\n","import type { McpServerSpec } from \"../mcp.js\";\nimport type { Agent } from \"../parser/agent.js\";\nimport type { Cmd } from \"../parser/cmd.js\";\nimport type { Skill } from \"../parser/skill.js\";\nimport type { Engine } from \"../types.js\";\nimport {\n type RenderResult,\n type Renderer,\n STOP_HOOK_PACKAGE,\n buildAgentBody,\n checkSkillCapabilities,\n frontmatterDataForSkill,\n isSkillEngineAllowed,\n tomlInlineArray,\n tomlInlineTable,\n tomlMultilineString,\n tomlQuoteString,\n yamlFrontmatter,\n} from \"./common.js\";\n\nconst ENGINE: Engine = \"codex-cli\";\nconst BASE = \".codex\";\n// Codex discovers repo skills under `.agents/skills/` only — `.codex/skills/` is not scanned.\nconst SKILLS_BASE = \".agents/skills\";\n\nexport const codexCliRenderer: Renderer = {\n engine: ENGINE,\n renderSkill(skill: Skill): RenderResult {\n if (!isSkillEngineAllowed(skill, ENGINE)) {\n return {\n files: [],\n warnings: [`skill \"${skill.meta.id}\" excluded from engine \"${ENGINE}\"`],\n };\n }\n const check = checkSkillCapabilities(skill, ENGINE);\n if (check.blockingWarnings.length > 0) {\n return { files: [], warnings: check.blockingWarnings };\n }\n const content = `${yamlFrontmatter(frontmatterDataForSkill(skill))}\\n${skill.body}\\n`;\n return {\n files: [{ path: `${SKILLS_BASE}/${skill.meta.id}/SKILL.md`, content }],\n warnings: check.degradedWarnings,\n };\n },\n // Codex custom prompts are deprecated in favour of skills: nothing to render.\n renderCmd(_cmd: Cmd): RenderResult {\n return { files: [], warnings: [] };\n },\n renderAgents(agents: ReadonlyArray<Agent>): RenderResult {\n const files = [];\n for (const agent of agents) {\n const content = [\n `name = ${tomlQuoteString(agent.meta.id)}`,\n `description = ${tomlQuoteString(agent.meta.description)}`,\n `developer_instructions = ${tomlMultilineString(buildAgentBody(agent).trimEnd())}`,\n \"\",\n ].join(\"\\n\");\n files.push({ path: `${BASE}/agents/${agent.meta.id}.toml`, content });\n }\n return { files, warnings: [] };\n },\n renderMcp(servers: ReadonlyArray<McpServerSpec>): RenderResult {\n if (servers.length === 0) return { files: [], warnings: [] };\n const blocks: string[] = [];\n for (const s of servers) {\n const lines = [\n `[mcp_servers.${s.id}]`,\n `command = ${tomlQuoteString(s.command)}`,\n `args = ${tomlInlineArray([...s.args])}`,\n ];\n if (s.env) lines.push(`env = ${tomlInlineTable(s.env)}`);\n blocks.push(lines.join(\"\\n\"));\n }\n const content = `${blocks.join(\"\\n\\n\")}\\n`;\n return { files: [{ path: `${BASE}/config.toml`, content }], warnings: [] };\n },\n renderStopHook(): RenderResult {\n const hooks = {\n hooks: {\n Stop: [\n {\n hooks: [\n {\n type: \"command\",\n command: `npx -y ${STOP_HOOK_PACKAGE} stop-hook --engine codex`,\n },\n ],\n },\n ],\n },\n };\n return {\n files: [{ path: `${BASE}/hooks.json`, content: `${JSON.stringify(hooks, null, 2)}\\n` }],\n warnings: [],\n };\n },\n};\n","import type { McpServerSpec } from \"../mcp.js\";\nimport type { Agent } from \"../parser/agent.js\";\nimport type { Cmd } from \"../parser/cmd.js\";\nimport type { Skill } from \"../parser/skill.js\";\nimport type { Engine } from \"../types.js\";\nimport {\n type RenderResult,\n type Renderer,\n STOP_HOOK_PACKAGE,\n buildAgentBody,\n checkSkillCapabilities,\n frontmatterDataForSkill,\n isSkillEngineAllowed,\n yamlFrontmatter,\n} from \"./common.js\";\n\nconst ENGINE: Engine = \"opencode\";\nconst BASE = \".opencode\";\n\nexport const opencodeRenderer: Renderer = {\n engine: ENGINE,\n renderSkill(skill: Skill): RenderResult {\n if (!isSkillEngineAllowed(skill, ENGINE)) {\n return {\n files: [],\n warnings: [`skill \"${skill.meta.id}\" excluded from engine \"${ENGINE}\"`],\n };\n }\n const check = checkSkillCapabilities(skill, ENGINE);\n if (check.blockingWarnings.length > 0) {\n return { files: [], warnings: check.blockingWarnings };\n }\n const content = `${yamlFrontmatter(frontmatterDataForSkill(skill))}\\n${skill.body}\\n`;\n return {\n files: [{ path: `${BASE}/skills/${skill.meta.id}/SKILL.md`, content }],\n warnings: check.degradedWarnings,\n };\n },\n renderCmd(cmd: Cmd): RenderResult {\n // OpenCode names the command after the file; only `description` is a known key.\n const content = `${yamlFrontmatter({ description: cmd.meta.description })}\\n${cmd.body}\\n`;\n return {\n files: [{ path: `${BASE}/commands/${cmd.meta.id}.md`, content }],\n warnings: [],\n };\n },\n renderAgents(agents: ReadonlyArray<Agent>): RenderResult {\n const files = [];\n for (const agent of agents) {\n // The file name is the agent name. `mode: all` keeps each persona usable\n // both as a session's primary agent and as a subagent.\n const fm = yamlFrontmatter({\n description: agent.meta.description,\n mode: \"all\",\n });\n const body = buildAgentBody(agent);\n files.push({ path: `${BASE}/agents/${agent.meta.id}.md`, content: `${fm}\\n${body}` });\n }\n return { files, warnings: [] };\n },\n renderMcp(servers: ReadonlyArray<McpServerSpec>): RenderResult {\n if (servers.length === 0) return { files: [], warnings: [] };\n const mcp: Record<string, Record<string, unknown>> = {};\n for (const s of servers) {\n const entry: Record<string, unknown> = {\n type: \"local\",\n command: [s.command, ...s.args],\n enabled: true,\n };\n if (s.env) entry.environment = s.env;\n mcp[s.id] = entry;\n }\n const config = { $schema: \"https://opencode.ai/config.json\", mcp };\n const content = `${JSON.stringify(config, null, 2)}\\n`;\n return { files: [{ path: `${BASE}/opencode.json`, content }], warnings: [] };\n },\n renderStopHook(): RenderResult {\n const content = `import { spawnSync } from \"node:child_process\";\n\nexport const HarnessStopHook = async ({ client, directory }) => ({\n event: async ({ event }) => {\n if (event.type !== \"session.idle\") return;\n const sessionID = event.properties?.sessionID;\n if (!sessionID) return;\n const r = spawnSync(\n \"npx\",\n [\"-y\", \"${STOP_HOOK_PACKAGE}\", \"stop-hook\", \"--engine\", \"opencode\", \"--cwd\", directory],\n { input: JSON.stringify({ sessionID }), encoding: \"utf-8\" },\n );\n const report = (r.stderr ?? \"\").trim();\n if (r.status !== 2 || report === \"\") return;\n // OpenCode defaults to its build agent when a prompt omits agent.\n // Preserve the last conversation persona, excluding compaction summaries.\n const history = await client.session.messages({ path: { id: sessionID } }).catch(() => undefined);\n if (history?.error || !Array.isArray(history?.data)) return;\n const current = history.data.findLast(({ info }) =>\n (info.role === \"user\" || (info.role === \"assistant\" && !info.summary)) &&\n typeof info.agent === \"string\" && info.agent.trim() !== \"\",\n );\n if (!current) return;\n await client.session.prompt({\n path: { id: sessionID },\n body: { agent: current.info.agent, parts: [{ type: \"text\", text: report }] },\n });\n },\n});\n`;\n return {\n files: [{ path: `${BASE}/plugins/harness-stop-hook.ts`, content }],\n warnings: [],\n };\n },\n};\n","import type { Engine } from \"../types.js\";\nimport { claudeCodeRenderer } from \"./claude-code.js\";\nimport { codexCliRenderer } from \"./codex-cli.js\";\nimport type { Renderer } from \"./common.js\";\nimport { opencodeRenderer } from \"./opencode.js\";\n\nexport const RENDERERS: Record<Engine, Renderer> = {\n \"claude-code\": claudeCodeRenderer,\n \"codex-cli\": codexCliRenderer,\n opencode: opencodeRenderer,\n};\n\nexport function getRenderer(engine: Engine): Renderer {\n return RENDERERS[engine];\n}\n\nexport type { Renderer, RenderResult } from \"./common.js\";\n","import { MCP_SERVERS, type McpServerId } from \"./mcp.js\";\nimport type { Agent } from \"./parser/agent.js\";\nimport type { Cmd } from \"./parser/cmd.js\";\nimport type { Skill } from \"./parser/skill.js\";\nimport { buildUmbrellaBody } from \"./renderers/common.js\";\nimport { getRenderer } from \"./renderers/index.js\";\nimport type { Engine, RenderedFile } from \"./types.js\";\n\nexport interface Harness {\n agents: ReadonlyArray<Agent>;\n skills: ReadonlyArray<Skill>;\n cmds: ReadonlyArray<Cmd>;\n}\n\nexport interface HarnessOverrides {\n add?: Partial<Harness>;\n disable?: ReadonlyArray<string>;\n}\n\nexport interface RenderInput {\n harness: Harness;\n engines: ReadonlyArray<Engine>;\n overrides?: HarnessOverrides;\n projectSkills?: ReadonlyArray<Skill>;\n /** True when the target project ships `docs/quality/code-quality.md` (optional pillar). */\n hasQualityDoc?: boolean;\n mcpServers?: ReadonlyArray<McpServerId>;\n /**\n * When true (default), each engine's renderer emits a Stop-hook config\n * that calls `vaubaan-harness stop-hook --engine <engine>` and injects\n * the lint report (with skill suggestions) into the running session\n * whenever the worktree is dirty and lint fails. Pass `false` to skip\n * the hook configs entirely (kill-switch at install time; runtime\n * kill-switch is `HARNESS_LINT_DISABLE=1`).\n */\n withStopHook?: boolean;\n}\n\nexport interface RenderOutput {\n files: RenderedFile[];\n warnings: string[];\n}\n\nexport class RenderError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"RenderError\";\n }\n}\n\nfunction mergeById<T extends { meta: { id: string } }>(\n stock: ReadonlyArray<T>,\n added: ReadonlyArray<T> | undefined,\n): T[] {\n const result = new Map<string, T>();\n for (const item of stock) result.set(item.meta.id, item);\n if (added) {\n for (const item of added) result.set(item.meta.id, item);\n }\n return Array.from(result.values());\n}\n\nfunction removeByIds<T extends { meta: { id: string } }>(\n items: ReadonlyArray<T>,\n disabled: ReadonlyArray<string>,\n): T[] {\n if (disabled.length === 0) return [...items];\n const disabledSet = new Set(disabled);\n return items.filter((item) => !disabledSet.has(item.meta.id));\n}\n\nexport function applyOverrides(harness: Harness, overrides: HarnessOverrides | undefined): Harness {\n const disabled = overrides?.disable ?? [];\n return {\n agents: removeByIds(mergeById(harness.agents, overrides?.add?.agents), disabled),\n skills: removeByIds(mergeById(harness.skills, overrides?.add?.skills), disabled),\n cmds: removeByIds(mergeById(harness.cmds, overrides?.add?.cmds), disabled),\n };\n}\n\n// `@AGENTS.md` is Claude Code's import syntax: the umbrella is really loaded,\n// on every version and provider, and never read twice alongside native\n// AGENTS.md support (cf. ADR engine-native-layouts-1-0).\nconst CLAUDE_MD_STUB = \"@AGENTS.md\\n\";\n\n// OpenCode also scans `.claude/skills/` and `.agents/skills/`. It goes last so\n// its own copy of a skill is dropped when another rendered engine exposes it.\nfunction opencodeLast(engines: ReadonlyArray<Engine>): Engine[] {\n return [...engines].sort((a, b) => Number(a === \"opencode\") - Number(b === \"opencode\"));\n}\n\nexport function render(input: RenderInput): RenderOutput {\n const { engines } = input;\n if (engines.length === 0) {\n throw new RenderError(\"at least one engine must be selected\");\n }\n const base: Harness = input.projectSkills?.length\n ? { ...input.harness, skills: mergeById(input.harness.skills, input.projectSkills) }\n : input.harness;\n const harness = applyOverrides(base, input.overrides);\n if (harness.agents.length === 0) {\n throw new RenderError(\"No agents found in harness\");\n }\n\n const files: RenderedFile[] = [];\n const warnings: string[] = [];\n\n // Track skills + commands successfully exposed on at least one engine,\n // for the engine-neutral umbrella's \"Available skills/commands\" sections.\n const exposedSkills = new Map<string, Skill>();\n const exposedCmds = new Map<string, Cmd>();\n\n for (const engine of opencodeLast(engines)) {\n const renderer = getRenderer(engine);\n\n const renderedSkills: Skill[] = [];\n for (const skill of harness.skills) {\n const result = renderer.renderSkill(skill);\n warnings.push(...result.warnings);\n if (result.files.length > 0) {\n const alreadyVisible = engine === \"opencode\" && exposedSkills.has(skill.meta.id);\n if (!alreadyVisible) files.push(...result.files);\n renderedSkills.push(skill);\n exposedSkills.set(skill.meta.id, skill);\n }\n }\n\n const renderedSkillIds = new Set(renderedSkills.map((s) => s.meta.id));\n const renderedCmds: Cmd[] = [];\n for (const cmd of harness.cmds) {\n if (!renderedSkillIds.has(cmd.meta.invokes_skill)) continue;\n const result = renderer.renderCmd(cmd);\n warnings.push(...result.warnings);\n if (result.files.length > 0) {\n files.push(...result.files);\n renderedCmds.push(cmd);\n exposedCmds.set(cmd.meta.id, cmd);\n }\n }\n\n const agentsResult = renderer.renderAgents(harness.agents);\n warnings.push(...agentsResult.warnings);\n files.push(...agentsResult.files);\n\n if (input.mcpServers && input.mcpServers.length > 0) {\n const specs = input.mcpServers.map((id) => MCP_SERVERS[id]);\n const mcpResult = renderer.renderMcp(specs);\n warnings.push(...mcpResult.warnings);\n files.push(...mcpResult.files);\n }\n\n if (input.withStopHook !== false) {\n const hookResult = renderer.renderStopHook();\n warnings.push(...hookResult.warnings);\n files.push(...hookResult.files);\n }\n }\n\n // Engine-neutral umbrella at the root\n const hasProjectSkills = (input.projectSkills?.length ?? 0) > 0;\n const umbrellaContent = buildUmbrellaBody(harness.agents, {\n availableSkills: Array.from(exposedSkills.values()),\n availableCommands: Array.from(exposedCmds.values()),\n hasProjectSkills,\n hasQualityDoc: input.hasQualityDoc === true,\n });\n files.push({ path: \"AGENTS.md\", content: umbrellaContent });\n\n // CLAUDE.md stub only if claude-code is enabled (Claude Code reads it historically)\n if (engines.includes(\"claude-code\")) {\n files.push({ path: \"CLAUDE.md\", content: CLAUDE_MD_STUB });\n }\n\n return { files, warnings };\n}\n","import { lstatSync, realpathSync, statSync } from \"node:fs\";\nimport { basename, dirname, isAbsolute, join, resolve, win32 } from \"node:path\";\n\nconst MANAGED_FILES = new Set([\n \"AGENTS.md\",\n \"CLAUDE.md\",\n \".mcp.json\",\n \".harness-manifest.json\",\n \".claude/settings.json\",\n \".codex/config.toml\",\n \".codex/hooks.json\",\n \".opencode/opencode.json\",\n \".opencode/mcp.json\",\n]);\n\n// Includes legacy layouts so upgrades can remove their generated artifacts.\nconst MANAGED_DIRECTORIES = [\n \".claude/agents/\",\n \".claude/commands/\",\n \".claude/skills/\",\n \".codex/agents/\",\n \".codex/commands/\",\n \".codex/skills/\",\n \".agents/skills/\",\n \".opencode/agents/\",\n \".opencode/commands/\",\n \".opencode/skills/\",\n \".opencode/plugins/\",\n];\n\nfunction canonicalTargetRoot(root: string): string {\n let ancestor = resolve(root);\n const missing: string[] = [];\n while (!lstatSync(ancestor, { throwIfNoEntry: false })) {\n missing.unshift(basename(ancestor));\n ancestor = dirname(ancestor);\n }\n const canonical = realpathSync(ancestor);\n if (!statSync(canonical).isDirectory()) {\n throw new Error(`harness target is not a directory: ${root}`);\n }\n return join(canonical, ...missing);\n}\n\nfunction assertManagedLocation(path: string): void {\n const invalidSegment = path\n .split(\"/\")\n .some((part) => part === \"\" || part === \".\" || part === \"..\");\n if (\n isAbsolute(path) ||\n win32.isAbsolute(path) ||\n path.includes(\"\\\\\") ||\n path.includes(\"\\0\") ||\n invalidSegment\n ) {\n throw new Error(`unsafe harness path: ${path}`);\n }\n if (!MANAGED_FILES.has(path) && !MANAGED_DIRECTORIES.some((prefix) => path.startsWith(prefix))) {\n throw new Error(`path is outside harness-managed locations: ${path}`);\n }\n}\n\nfunction assertNoSymbolicComponents(root: string, path: string): void {\n const parts = path.split(\"/\");\n let current = root;\n for (const [index, part] of parts.entries()) {\n current = join(current, part);\n const info = lstatSync(current, { throwIfNoEntry: false });\n if (!info) return;\n if (info.isSymbolicLink()) {\n throw new Error(`symbolic link in harness path: ${path}`);\n }\n const isLeaf = index === parts.length - 1;\n if (isLeaf ? !info.isFile() : !info.isDirectory()) {\n throw new Error(`unexpected file type in harness path: ${path}`);\n }\n }\n}\n\n/**\n * Preflight the complete list before callers mutate any artifact. The target\n * itself may resolve through a symlink; every component below it, including\n * leaf files and the manifest, must be a regular file or directory, never a\n * symlink (even one pointing inside the target). Missing targets are allowed.\n * This checks the current filesystem, not concurrent changes by other processes.\n */\nexport function assertManagedPaths(root: string, files: ReadonlyArray<string>): void {\n for (const path of files) assertManagedLocation(path);\n const canonicalRoot = canonicalTargetRoot(root);\n for (const path of files) assertNoSymbolicComponents(canonicalRoot, path);\n}\n","import { createHash } from \"node:crypto\";\nimport { chmodSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { z } from \"zod\";\nimport type { Engine } from \"../types.js\";\nimport { VERSION } from \"../version.js\";\nimport { assertManagedPaths } from \"./managed-paths.js\";\nimport { type OpenCodeConfigOwnership, OpenCodeConfigOwnershipSchema } from \"./opencode-config.js\";\nimport { type HookConfigsOwnership, HookConfigsOwnershipSchema } from \"./update-config.js\";\n\nexport const MANIFEST_FILENAME = \".harness-manifest.json\";\nexport const MANIFEST_VERSION = \"6\";\n\nconst ManifestSchema = z.object({\n version: z.enum([\"4\", \"5\", MANIFEST_VERSION]),\n engines: z.array(z.string()),\n renderedAt: z.string(),\n files: z.array(z.string()),\n stopHookInstalled: z.boolean().optional(),\n stopHookEngines: z.array(z.string()).optional(),\n opencodeConfig: OpenCodeConfigOwnershipSchema.optional(),\n hookConfigs: HookConfigsOwnershipSchema.optional(),\n harnessVersion: z.string().optional(),\n overridesDir: z.string().optional(),\n fileHashes: z.record(z.string().regex(/^[a-f0-9]{64}$/)).optional(),\n preservedFiles: z.array(z.string()).optional(),\n});\n\nexport type Manifest = z.infer<typeof ManifestSchema>;\n\nexport interface WriteManifestExtras {\n stopHookInstalled?: boolean;\n stopHookEngines?: ReadonlyArray<Engine>;\n opencodeConfig?: OpenCodeConfigOwnership;\n hookConfigs?: HookConfigsOwnership;\n overridesDir?: string;\n preservedFiles?: string[];\n}\n\nexport function manifestPath(targetDir: string): string {\n return join(targetDir, MANIFEST_FILENAME);\n}\n\nexport function writeManifest(\n targetDir: string,\n engines: ReadonlyArray<Engine>,\n files: string[],\n extras: WriteManifestExtras = {},\n): void {\n assertManagedPaths(targetDir, [MANIFEST_FILENAME]);\n const manifest: Manifest = {\n version: MANIFEST_VERSION,\n harnessVersion: VERSION,\n engines: [...engines].sort(),\n renderedAt: new Date().toISOString(),\n files: [...files].sort(),\n fileHashes: Object.fromEntries(\n files\n .filter((file) => existsSync(join(targetDir, file)))\n .sort()\n .map((file) => [file, hashContent(readFileSync(join(targetDir, file)))]),\n ),\n ...(extras.overridesDir ? { overridesDir: extras.overridesDir } : {}),\n ...(extras.preservedFiles ? { preservedFiles: extras.preservedFiles } : {}),\n ...(extras.hookConfigs ? { hookConfigs: extras.hookConfigs } : {}),\n ...(extras.opencodeConfig ? { opencodeConfig: extras.opencodeConfig } : {}),\n ...(extras.stopHookInstalled !== undefined\n ? { stopHookInstalled: extras.stopHookInstalled }\n : {}),\n ...(extras.stopHookEngines !== undefined\n ? { stopHookEngines: [...extras.stopHookEngines].sort() }\n : {}),\n };\n const path = manifestPath(targetDir);\n if (existsSync(path)) chmodSync(path, 0o600);\n writeFileSync(path, `${JSON.stringify(manifest, null, 2)}\\n`, { mode: 0o600 });\n}\n\nexport function hashContent(content: string | Buffer): string {\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\nexport function readManifest(targetDir: string): Manifest | null {\n assertManagedPaths(targetDir, [MANIFEST_FILENAME]);\n const path = manifestPath(targetDir);\n if (!existsSync(path)) return null;\n const raw = JSON.parse(readFileSync(path, \"utf8\"));\n return ManifestSchema.parse(raw);\n}\n","export const VERSION = \"1.3.0\";\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport { z } from \"zod\";\nimport type { RenderedFile } from \"../types.js\";\n\nexport const OPENCODE_CONFIG_PATH = \".opencode/opencode.json\";\nconst OPENCODE_SCHEMA = \"https://opencode.ai/config.json\";\nconst ObjectSchema = z.record(z.unknown());\n\nexport const OpenCodeConfigOwnershipSchema = z.object({\n createdFile: z.boolean(),\n addedMcp: z.boolean(),\n addedSchema: z.boolean(),\n entries: z.record(ObjectSchema),\n});\n\nexport type OpenCodeConfigOwnership = z.infer<typeof OpenCodeConfigOwnershipSchema>;\n\nexport interface OpenCodeConfigPlan {\n write?: RenderedFile;\n remove: boolean;\n ownership?: OpenCodeConfigOwnership;\n warnings: string[];\n}\n\nfunction parseConfig(content: string): Record<string, unknown> {\n try {\n const config = ObjectSchema.parse(JSON.parse(content));\n if (Object.hasOwn(config, \"mcp\")) ObjectSchema.parse(config.mcp);\n return config;\n } catch {\n throw new Error(`invalid ${OPENCODE_CONFIG_PATH}: expected a JSON object with an MCP object`);\n }\n}\n\nfunction removeOwnedEntries(\n config: Record<string, unknown>,\n ownership: OpenCodeConfigOwnership,\n warnings: string[],\n): void {\n if (Object.hasOwn(config, \"mcp\")) {\n const mcp = ObjectSchema.parse(config.mcp);\n for (const [id, installed] of Object.entries(ownership.entries)) {\n if (!Object.hasOwn(mcp, id)) continue;\n if (isDeepStrictEqual(mcp[id], installed)) delete mcp[id];\n else warnings.push(`preserved modified OpenCode MCP server: ${id}`);\n }\n config.mcp = mcp;\n if (ownership.addedMcp && Object.keys(mcp).length === 0) Reflect.deleteProperty(config, \"mcp\");\n }\n if (ownership.addedSchema && config.$schema === OPENCODE_SCHEMA)\n Reflect.deleteProperty(config, \"$schema\");\n}\n\nfunction addMissingEntries(\n config: Record<string, unknown>,\n desired: RenderedFile,\n createdFile: boolean,\n warnings: string[],\n): OpenCodeConfigOwnership | undefined {\n const requested = ObjectSchema.parse(parseConfig(desired.content).mcp);\n const mcp = ObjectSchema.parse(config.mcp ?? {});\n const entries: Record<string, Record<string, unknown>> = {};\n for (const [id, entry] of Object.entries(requested)) {\n if (Object.hasOwn(mcp, id)) {\n if (!isDeepStrictEqual(mcp[id], entry)) {\n warnings.push(`preserved existing OpenCode MCP server instead of replacing it: ${id}`);\n }\n continue;\n }\n entries[id] = ObjectSchema.parse(entry);\n mcp[id] = entry;\n }\n if (Object.keys(entries).length === 0) return undefined;\n const ownership = {\n createdFile,\n addedMcp: !Object.hasOwn(config, \"mcp\"),\n addedSchema: !Object.hasOwn(config, \"$schema\"),\n entries,\n };\n config.mcp = mcp;\n if (ownership.addedSchema) config.$schema = OPENCODE_SCHEMA;\n return ownership;\n}\n\n/** Plans shared configuration edits before init/uninstall mutate any project files. */\nexport function planOpenCodeConfig(\n root: string,\n desired: RenderedFile | undefined,\n previous: OpenCodeConfigOwnership | undefined,\n): OpenCodeConfigPlan {\n const warnings: string[] = [];\n if (!desired && !previous) return { remove: false, warnings };\n const path = join(root, OPENCODE_CONFIG_PATH);\n const existed = existsSync(path);\n if (!existed && !desired) return { remove: false, warnings };\n const original = existed ? readFileSync(path, \"utf8\") : undefined;\n const config = original === undefined ? {} : parseConfig(original);\n const before = structuredClone(config);\n if (previous) removeOwnedEntries(config, previous, warnings);\n const createdFile = !existed || previous?.createdFile === true;\n const ownership = desired ? addMissingEntries(config, desired, createdFile, warnings) : undefined;\n if (!ownership && createdFile && Object.keys(config).length === 0) {\n return { remove: existed, warnings };\n }\n return {\n remove: false,\n ownership,\n warnings,\n ...(!existed || !isDeepStrictEqual(before, config)\n ? { write: { path: OPENCODE_CONFIG_PATH, content: `${JSON.stringify(config, null, 2)}\\n` } }\n : {}),\n };\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport { z } from \"zod\";\nimport { getRenderer } from \"../renderers/index.js\";\nimport type { Engine, RenderedFile } from \"../types.js\";\nimport { assertManagedPaths } from \"./managed-paths.js\";\nimport {\n OPENCODE_CONFIG_PATH,\n type OpenCodeConfigOwnership,\n planOpenCodeConfig,\n} from \"./opencode-config.js\";\n\nconst LEGACY_OPENCODE_CONFIG = \".opencode/mcp.json\";\nexport const SHARED_CONFIG_PATHS: ReadonlyArray<string> = [\n \".mcp.json\",\n \".codex/config.toml\",\n OPENCODE_CONFIG_PATH,\n LEGACY_OPENCODE_CONFIG,\n \".claude/settings.json\",\n \".codex/hooks.json\",\n];\n\nconst ObjectSchema = z.record(z.unknown());\nconst HookEntrySchema = z.object({ group: ObjectSchema, hook: ObjectSchema });\nconst HookConfigOwnershipSchema = z.object({\n createdFile: z.boolean(),\n addedHooks: z.boolean(),\n addedStop: z.boolean(),\n entries: z.array(HookEntrySchema),\n});\nexport const HookConfigsOwnershipSchema = z\n .object({\n \".claude/settings.json\": HookConfigOwnershipSchema.optional(),\n \".codex/hooks.json\": HookConfigOwnershipSchema.optional(),\n })\n .strict();\nexport type HookConfigsOwnership = z.infer<typeof HookConfigsOwnershipSchema>;\ntype HookConfigOwnership = z.infer<typeof HookConfigOwnershipSchema>;\ntype HookEntry = z.infer<typeof HookEntrySchema>;\ntype HookPath = keyof HookConfigsOwnership;\n\nconst HOOK_ENGINES: Record<HookPath, Engine> = {\n \".claude/settings.json\": \"claude-code\",\n \".codex/hooks.json\": \"codex-cli\",\n};\n\nexport interface ConfigMutations {\n writes: RenderedFile[];\n removals: string[];\n warnings: string[];\n}\n\nexport interface UpdateConfigPrevious {\n files: ReadonlyArray<string>;\n opencodeConfig?: OpenCodeConfigOwnership;\n hookConfigs?: HookConfigsOwnership;\n}\n\nexport interface UpdateConfigPlan extends ConfigMutations {\n ownedFiles: string[];\n opencodeConfig?: OpenCodeConfigOwnership;\n hookConfigs?: HookConfigsOwnership;\n}\n\nfunction parseObject(content: string, path: string): Record<string, unknown> {\n try {\n return ObjectSchema.parse(JSON.parse(content));\n } catch {\n throw new Error(`invalid shared configuration ${path}: expected a JSON object`);\n }\n}\n\nfunction asObject(value: unknown): Record<string, unknown> | undefined {\n const parsed = ObjectSchema.safeParse(value);\n return parsed.success ? parsed.data : undefined;\n}\n\nfunction stopHooks(config: Record<string, unknown>, path: string): unknown[] {\n if (!Object.hasOwn(config, \"hooks\")) return [];\n const hooks = asObject(config.hooks);\n if (!hooks || (Object.hasOwn(hooks, \"Stop\") && !Array.isArray(hooks.Stop))) {\n throw new Error(`invalid shared configuration ${path}: expected hooks.Stop to be an array`);\n }\n return Array.isArray(hooks.Stop) ? hooks.Stop : [];\n}\n\nfunction groupMetadata(group: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(Object.entries(group).filter(([key]) => key !== \"hooks\"));\n}\n\nfunction sameEntry(left: HookEntry, right: HookEntry): boolean {\n return isDeepStrictEqual(left.group, right.group) && isDeepStrictEqual(left.hook, right.hook);\n}\n\nfunction appendEntry(entries: HookEntry[], entry: HookEntry): void {\n if (!entries.some((existing) => sameEntry(existing, entry))) entries.push(entry);\n}\n\nfunction defaultStopGroup(engine: Engine): Record<string, unknown> {\n const file = getRenderer(engine).renderStopHook().files[0];\n if (!file) throw new Error(`missing Stop hook renderer for ${engine}`);\n const group = asObject(stopHooks(parseObject(file.content, file.path), file.path)[0]);\n if (!group || !Array.isArray(group.hooks) || !asObject(group.hooks[0])) {\n throw new Error(`invalid Stop hook renderer for ${engine}`);\n }\n return group;\n}\n\nfunction normalizeHarnessHooks(\n groups: unknown[],\n expected: Record<string, unknown>,\n previous: HookConfigOwnership | undefined,\n claimExisting: boolean,\n warnings: string[],\n path: HookPath,\n): { groups: unknown[]; entries: HookEntry[] } {\n const defaultHook = ObjectSchema.parse((expected.hooks as unknown[])[0]);\n const entries = [...(previous?.entries ?? [])];\n let found = false;\n const normalized = groups.map((value) => {\n const group = asObject(value);\n if (!group) return value;\n const flat = group.type === \"command\" && group.command === defaultHook.command;\n const hooks = flat ? [group] : Array.isArray(group.hooks) ? group.hooks : [];\n const metadata = flat ? groupMetadata(expected) : groupMetadata(group);\n for (const value of hooks) {\n const hook = asObject(value);\n if (!hook || hook.type !== \"command\" || hook.command !== defaultHook.command) continue;\n found = true;\n const entry = { group: metadata, hook };\n if (!claimExisting) continue;\n if (previous && !previous.entries.some((old) => sameEntry(old, entry))) {\n warnings.push(`preserved modified harness Stop hook: ${path}`);\n } else {\n appendEntry(entries, entry);\n }\n }\n return flat && claimExisting ? { ...metadata, hooks: [group] } : value;\n });\n if (!found && !previous?.entries.length) {\n normalized.push(expected);\n appendEntry(entries, { group: groupMetadata(expected), hook: defaultHook });\n } else if (!found) {\n warnings.push(`preserved removed or modified harness Stop hook: ${path}`);\n }\n return { groups: normalized, entries };\n}\n\nfunction removeOwnedHooks(\n config: Record<string, unknown>,\n ownership: HookConfigOwnership,\n path: HookPath,\n warnings: string[],\n): void {\n const groups = stopHooks(config, path);\n const remaining: unknown[] = [];\n const matched = new Set<HookEntry>();\n for (const value of groups) {\n const group = asObject(value);\n if (!group || !Array.isArray(group.hooks)) {\n remaining.push(value);\n continue;\n }\n const metadata = groupMetadata(group);\n const hooks = group.hooks.filter((value) => {\n const hook = asObject(value);\n const entry =\n hook && ownership.entries.find((old) => sameEntry(old, { group: metadata, hook }));\n if (entry) matched.add(entry);\n return !entry;\n });\n if (hooks.length > 0 || hooks.length === group.hooks.length) {\n remaining.push({ ...group, hooks });\n }\n }\n if (matched.size < ownership.entries.length) {\n warnings.push(`preserved removed or modified harness Stop hook: ${path}`);\n }\n const hooks = asObject(config.hooks);\n if (!hooks) return;\n if (ownership.addedStop && remaining.length === 0) Reflect.deleteProperty(hooks, \"Stop\");\n else if (Object.hasOwn(hooks, \"Stop\")) hooks.Stop = remaining;\n if (ownership.addedHooks && Object.keys(hooks).length === 0)\n Reflect.deleteProperty(config, \"hooks\");\n else config.hooks = hooks;\n}\n\nfunction recordMutation(\n plan: ConfigMutations,\n path: string,\n before: Record<string, unknown> | undefined,\n after: Record<string, unknown>,\n createdFile: boolean,\n): void {\n if (createdFile && Object.keys(after).length === 0) {\n if (before) plan.removals.push(path);\n } else if (!isDeepStrictEqual(before, after)) {\n plan.writes.push({ path, content: `${JSON.stringify(after, null, 2)}\\n` });\n }\n}\n\nexport function planHookConfigCleanup(\n root: string,\n ownership: HookConfigsOwnership | undefined,\n): ConfigMutations {\n const plan: ConfigMutations = { writes: [], removals: [], warnings: [] };\n if (!ownership) return plan;\n const validated = HookConfigsOwnershipSchema.parse(ownership);\n assertManagedPaths(root, Object.keys(validated));\n for (const path of Object.keys(HOOK_ENGINES) as HookPath[]) {\n const owned = validated[path];\n if (!owned || !existsSync(join(root, path))) continue;\n const before = parseObject(readFileSync(join(root, path), \"utf8\"), path);\n const config = structuredClone(before);\n removeOwnedHooks(config, owned, path, plan.warnings);\n recordMutation(plan, path, before, config, owned.createdFile);\n }\n return plan;\n}\n\nfunction planActiveHook(\n root: string,\n path: HookPath,\n previous: HookConfigOwnership | undefined,\n claimExisting: boolean,\n plan: UpdateConfigPlan,\n): HookConfigOwnership | undefined {\n assertManagedPaths(root, [path]);\n const existed = existsSync(join(root, path));\n if (!existed && previous?.entries.length) {\n plan.warnings.push(`preserved removed harness Stop hook configuration: ${path}`);\n return previous;\n }\n const before = existed ? parseObject(readFileSync(join(root, path), \"utf8\"), path) : undefined;\n const config = structuredClone(before ?? {});\n const groups = stopHooks(config, path);\n const hooks = asObject(config.hooks) ?? {};\n const normalized = normalizeHarnessHooks(\n groups,\n defaultStopGroup(HOOK_ENGINES[path]),\n previous,\n claimExisting,\n plan.warnings,\n path,\n );\n const ownership = {\n createdFile: !existed || previous?.createdFile === true,\n addedHooks: previous?.addedHooks ?? !Object.hasOwn(config, \"hooks\"),\n addedStop: previous?.addedStop ?? !Object.hasOwn(hooks, \"Stop\"),\n entries: normalized.entries,\n };\n if (!isDeepStrictEqual(groups, normalized.groups)) {\n config.hooks = { ...hooks, Stop: normalized.groups };\n }\n recordMutation(plan, path, before, config, ownership.createdFile);\n return ownership.entries.length > 0 ? ownership : undefined;\n}\n\nfunction planLegacyOpenCode(\n root: string,\n previous: UpdateConfigPrevious,\n plan: UpdateConfigPlan,\n): void {\n if (!previous.files.includes(LEGACY_OPENCODE_CONFIG)) return;\n const legacyPath = join(root, LEGACY_OPENCODE_CONFIG);\n if (!existsSync(legacyPath)) return;\n assertManagedPaths(root, [LEGACY_OPENCODE_CONFIG, OPENCODE_CONFIG_PATH]);\n const legacy = parseObject(readFileSync(legacyPath, \"utf8\"), LEGACY_OPENCODE_CONFIG);\n if (!asObject(legacy.mcp)) {\n throw new Error(\n `invalid shared configuration ${LEGACY_OPENCODE_CONFIG}: expected an MCP object`,\n );\n }\n const merged = planOpenCodeConfig(\n root,\n { path: OPENCODE_CONFIG_PATH, content: JSON.stringify(legacy) },\n undefined,\n );\n if (merged.write) plan.writes.push(merged.write);\n plan.warnings.push(...merged.warnings);\n if (merged.ownership) {\n const old = previous.opencodeConfig;\n plan.opencodeConfig = {\n createdFile: merged.ownership.createdFile || old?.createdFile === true,\n addedMcp: merged.ownership.addedMcp || old?.addedMcp === true,\n addedSchema: merged.ownership.addedSchema || old?.addedSchema === true,\n entries: { ...old?.entries, ...merged.ownership.entries },\n };\n }\n plan.removals.push(LEGACY_OPENCODE_CONFIG);\n}\n\n/** Preserve existing MCP settings and plan only shared hook/legacy-layout changes. */\nexport function planUpdateConfigs(\n root: string,\n previous: UpdateConfigPrevious,\n hookEngines: ReadonlyArray<Engine>,\n): UpdateConfigPlan {\n const plan: UpdateConfigPlan = {\n writes: [],\n removals: [],\n ownedFiles: [],\n warnings: [],\n ...(previous.opencodeConfig ? { opencodeConfig: previous.opencodeConfig } : {}),\n };\n planLegacyOpenCode(root, previous, plan);\n const hookConfigs: HookConfigsOwnership = {};\n for (const path of Object.keys(HOOK_ENGINES) as HookPath[]) {\n const owned = previous.hookConfigs?.[path];\n if (hookEngines.includes(HOOK_ENGINES[path])) {\n hookConfigs[path] = planActiveHook(\n root,\n path,\n owned,\n previous.files.includes(path) || Boolean(owned),\n plan,\n );\n } else if (owned) {\n const cleanup = planHookConfigCleanup(root, { [path]: owned });\n plan.writes.push(...cleanup.writes);\n plan.removals.push(...cleanup.removals);\n plan.warnings.push(...cleanup.warnings);\n }\n }\n if (Object.values(hookConfigs).some(Boolean)) plan.hookConfigs = hookConfigs;\n if (hookEngines.includes(\"opencode\")) {\n const plugin = getRenderer(\"opencode\").renderStopHook();\n plan.writes.push(...plugin.files);\n plan.ownedFiles.push(...plugin.files.map((file) => file.path));\n plan.warnings.push(...plugin.warnings);\n }\n return plan;\n}\n","import { existsSync, readdirSync, rmdirSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, relative, resolve } from \"node:path\";\nimport { assertManagedPaths } from \"./managed-paths.js\";\nimport { MANIFEST_FILENAME, manifestPath, readManifest } from \"./manifest.js\";\nimport { OPENCODE_CONFIG_PATH, planOpenCodeConfig } from \"./opencode-config.js\";\nimport { planHookConfigCleanup } from \"./update-config.js\";\n\nexport interface UninstallArgs {\n targetDir: string;\n}\n\nexport interface UninstallResult {\n filesRemoved: string[];\n dirsPruned: string[];\n warnings: string[];\n}\n\nexport function uninstallCommand(args: UninstallArgs): UninstallResult {\n const root = resolve(args.targetDir);\n const warnings: string[] = [];\n assertManagedPaths(root, [MANIFEST_FILENAME]);\n const manifest = readManifest(root);\n if (!manifest) {\n warnings.push(`no manifest found at ${manifestPath(root)} — nothing to uninstall`);\n return { filesRemoved: [], dirsPruned: [], warnings };\n }\n\n assertManagedPaths(root, [\n ...manifest.files,\n ...(manifest.opencodeConfig ? [OPENCODE_CONFIG_PATH] : []),\n ...Object.keys(manifest.hookConfigs ?? {}),\n ]);\n const config = planOpenCodeConfig(root, undefined, manifest.opencodeConfig);\n const hooks = planHookConfigCleanup(root, manifest.hookConfigs);\n const sharedHooks = new Set(Object.keys(manifest.hookConfigs ?? {}));\n const ownedFiles = manifest.files.filter(\n (file) => file !== OPENCODE_CONFIG_PATH && !sharedHooks.has(file),\n );\n if (config.remove) ownedFiles.push(OPENCODE_CONFIG_PATH);\n ownedFiles.push(...hooks.removals);\n const { filesRemoved, dirsPruned, missing } = removeRenderedFiles(root, ownedFiles);\n if (config.write) writeFileSync(join(root, config.write.path), config.write.content);\n for (const file of hooks.writes) writeFileSync(join(root, file.path), file.content);\n warnings.push(...config.warnings, ...hooks.warnings);\n if (manifest.files.includes(OPENCODE_CONFIG_PATH) && !manifest.opencodeConfig) {\n warnings.push(`preserved legacy shared configuration: ${OPENCODE_CONFIG_PATH}`);\n }\n for (const rel of missing) warnings.push(`file in manifest is already missing: ${rel}`);\n\n unlinkSync(manifestPath(root));\n return { filesRemoved, dirsPruned, warnings };\n}\n\nexport function removeRenderedFiles(\n root: string,\n files: ReadonlyArray<string>,\n): { filesRemoved: string[]; dirsPruned: string[]; missing: string[] } {\n assertManagedPaths(root, files);\n const filesRemoved: string[] = [];\n const missing: string[] = [];\n const dirsToConsider = new Set<string>();\n for (const rel of files) {\n const full = join(root, rel);\n if (existsSync(full)) {\n unlinkSync(full);\n filesRemoved.push(rel);\n dirsToConsider.add(dirname(full));\n } else {\n missing.push(rel);\n }\n }\n return { filesRemoved, dirsPruned: pruneEmptyDirs(root, dirsToConsider), missing };\n}\n\nfunction pruneEmptyDirs(root: string, leaves: Set<string>): string[] {\n const candidates = new Set<string>();\n for (const leaf of leaves) {\n let cur = leaf;\n while (cur !== root && cur.startsWith(`${root}/`)) {\n candidates.add(cur);\n cur = dirname(cur);\n }\n }\n const pruned: string[] = [];\n const sorted = [...candidates].sort((a, b) => b.length - a.length);\n for (const dir of sorted) {\n if (!existsSync(dir)) continue;\n if (readdirSync(dir).length > 0) continue;\n rmdirSync(dir);\n pruned.push(relative(root, dir));\n }\n return pruned;\n}\n"],"mappings":"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","names":["existsSync","writeFileSync","dirname","join","resolve","readFileSync","z","z","readFileSync","ENGINE","BASE","ENGINE","BASE","join","existsSync","readFileSync","join","z","existsSync","readFileSync","join","z","existsSync","readFileSync","join","isDeepStrictEqual","z","ObjectSchema","z","z","join","existsSync","readFileSync","existsSync","writeFileSync","dirname","join","resolve","join","existsSync","dirname","dirname","existsSync","join","resolve","writeFileSync"]}
1
+ {"version":3,"sources":["../src/cli/init.ts","../src/loader.ts","../src/parser/common.ts","../src/parser/schemas.ts","../src/types.ts","../src/parser/agent.ts","../src/parser/cmd.ts","../src/parser/skill.ts","../src/util/yaml.ts","../src/mcp.ts","../src/renderers/common.ts","../src/renderers/claude-code.ts","../src/renderers/codex-cli.ts","../src/renderers/opencode.ts","../src/renderers/index.ts","../src/render.ts","../src/cli/managed-paths.ts","../src/cli/manifest.ts","../src/version.ts","../src/cli/opencode-config.ts","../src/cli/update-config.ts","../src/cli/uninstall.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { loadHarness, loadOverrides, loadProjectSkills } from \"../loader.js\";\nimport { resolveMcpIds } from \"../mcp.js\";\nimport { type RenderOutput, render } from \"../render.js\";\nimport { ENGINES, type Engine, type RenderedFile } from \"../types.js\";\nimport { assertManagedPaths } from \"./managed-paths.js\";\nimport { MANIFEST_FILENAME, readManifest, writeManifest } from \"./manifest.js\";\nimport { OPENCODE_CONFIG_PATH, planOpenCodeConfig } from \"./opencode-config.js\";\nimport { removeRenderedFiles } from \"./uninstall.js\";\n\n/** Cardinal file of the optional `docs/quality/` pillar. */\nconst QUALITY_DOC_PATH = \"docs/quality/code-quality.md\";\n\nexport interface InitArgs {\n targetDir: string;\n engines?: ReadonlyArray<string>;\n overridesDir?: string;\n /**\n * Directory containing the harness content (agents/, skills/, commands/,\n * templates/). Defaults to the harness package's own `dist/` (resolved\n * via `import.meta.url`), so programmatic callers usually omit it.\n */\n packageDir?: string;\n mcpServers?: ReadonlyArray<string>;\n /**\n * Stop-hook installation. Default `true`. When enabled, each engine\n * receives a hook config that calls `vaubaan-harness stop-hook\n * --engine <engine>` and injects the lint report (with skill\n * suggestions) into the running session whenever the worktree is\n * dirty and lint fails at end-of-turn. Pass `false` to skip the\n * hook configs entirely (runtime kill-switch remains available via\n * `HARNESS_LINT_DISABLE=1`).\n */\n withStopHook?: boolean;\n}\n\nexport interface InitResult {\n filesWritten: string[];\n /** Files a previous `init` rendered that this one no longer does (layout change, engine dropped). */\n staleFilesRemoved: string[];\n warnings: string[];\n stopHookInstalled: boolean;\n}\n\nfunction resolveEngineList(requested: ReadonlyArray<string> | undefined): Engine[] {\n if (!requested || requested.length === 0) return [...ENGINES];\n return requested.map((e) => {\n if (!ENGINES.includes(e as Engine)) {\n throw new Error(`unknown engine: ${e} (expected one of ${ENGINES.join(\", \")})`);\n }\n return e as Engine;\n });\n}\n\n/**\n * Resolves the harness package's bundled content directory. The harness\n * tsup config emits this module to both `dist/init.js` (programmatic\n * `./init` export) and inlines it into `dist/cli/index.js` (CLI use). The\n * content (`agents/`, `skills/`, `commands/`, `templates/`) always sits\n * at `dist/` — same dir as `dist/init.js`, parent of `dist/cli/index.js`.\n * In dev (`src/cli/init.ts`) the content also sits at `src/`. We\n * disambiguate by checking which ancestor contains `agents/`.\n */\nfunction defaultPackageDir(): string {\n const here = dirname(fileURLToPath(import.meta.url));\n if (existsSync(join(here, \"agents\"))) return here;\n return resolve(here, \"..\");\n}\n\nexport function planInit(args: InitArgs): {\n engines: Engine[];\n output: RenderOutput;\n stopHookInstalled: boolean;\n} {\n const engines = resolveEngineList(args.engines);\n const packageDir = args.packageDir ?? defaultPackageDir();\n const harness = loadHarness(packageDir);\n const overrides = args.overridesDir ? loadOverrides(args.overridesDir) : undefined;\n const projectSkills = loadProjectSkills(args.targetDir);\n const hasQualityDoc = existsSync(join(args.targetDir, QUALITY_DOC_PATH));\n const mcpServers = args.mcpServers ? resolveMcpIds(args.mcpServers) : undefined;\n const stopHookInstalled = args.withStopHook !== false;\n const output = render({\n harness,\n engines,\n overrides,\n projectSkills,\n hasQualityDoc,\n mcpServers,\n withStopHook: stopHookInstalled,\n });\n return { engines, output, stopHookInstalled };\n}\n\nexport function writeFilesToTarget(\n files: ReadonlyArray<RenderedFile>,\n targetDir: string,\n): string[] {\n assertManagedPaths(\n targetDir,\n files.map((file) => file.path),\n );\n const written: string[] = [];\n for (const f of files) {\n const full = join(targetDir, f.path);\n mkdirSync(dirname(full), { recursive: true });\n writeFileSync(full, f.content);\n written.push(f.path);\n }\n return written;\n}\n\nexport function initCommand(args: InitArgs): InitResult {\n const { engines, output, stopHookInstalled } = planInit(args);\n const previous = readManifest(args.targetDir);\n assertManagedPaths(args.targetDir, [\n MANIFEST_FILENAME,\n ...(previous?.files ?? []),\n ...output.files.map((file) => file.path),\n ...(previous?.opencodeConfig ? [OPENCODE_CONFIG_PATH] : []),\n ]);\n const desiredConfig = output.files.find((file) => file.path === OPENCODE_CONFIG_PATH);\n const config = planOpenCodeConfig(args.targetDir, desiredConfig, previous?.opencodeConfig);\n const next = new Set(output.files.map((f) => f.path));\n const stale = (previous?.files ?? []).filter((f) => !next.has(f) && f !== OPENCODE_CONFIG_PATH);\n if (config.remove) stale.push(OPENCODE_CONFIG_PATH);\n const staleFilesRemoved = removeRenderedFiles(resolve(args.targetDir), stale).filesRemoved;\n const ownedFiles = output.files.filter((file) => file.path !== OPENCODE_CONFIG_PATH);\n const filesWritten = writeFilesToTarget(ownedFiles, args.targetDir);\n if (config.write) writeFilesToTarget([config.write], args.targetDir);\n writeManifest(args.targetDir, engines, filesWritten, {\n stopHookInstalled,\n stopHookEngines: stopHookInstalled ? engines : undefined,\n opencodeConfig: config.ownership,\n overridesDir: args.overridesDir\n ? resolve(args.overridesDir) === resolve(args.targetDir)\n ? \".\"\n : resolve(args.overridesDir)\n : undefined,\n });\n if (config.write) filesWritten.push(OPENCODE_CONFIG_PATH);\n const warnings = [...output.warnings, ...config.warnings];\n if (previous?.files.includes(OPENCODE_CONFIG_PATH) && !previous.opencodeConfig) {\n warnings.push(`preserved legacy shared configuration: ${OPENCODE_CONFIG_PATH}`);\n }\n return { filesWritten, staleFilesRemoved, warnings, stopHookInstalled };\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport fg from \"fast-glob\";\nimport { z } from \"zod\";\nimport { parseAgent } from \"./parser/agent.js\";\nimport { parseCmd } from \"./parser/cmd.js\";\nimport { type Skill, parseSkill } from \"./parser/skill.js\";\nimport type { Harness, HarnessOverrides } from \"./render.js\";\nimport { parseYAML } from \"./util/yaml.js\";\n\nexport const DisableYamlSchema = z\n .object({ disable: z.array(z.string()).optional() })\n .passthrough();\n\nexport interface LoadOptions {\n agentsDir?: string;\n skillsDir?: string;\n commandsDir?: string;\n}\n\nexport function loadHarness(packageDir: string, opts: LoadOptions = {}): Harness {\n const agentsDir = opts.agentsDir ?? join(packageDir, \"agents\");\n const skillsDir = opts.skillsDir ?? join(packageDir, \"skills\");\n const commandsDir = opts.commandsDir ?? join(packageDir, \"commands\");\n\n const agentFiles = fg.sync(\"*.agent.md\", { cwd: agentsDir, absolute: true });\n const skillFiles = fg.sync(\"*.skill.md\", { cwd: skillsDir, absolute: true });\n const cmdFiles = fg.sync(\"*.cmd.md\", { cwd: commandsDir, absolute: true });\n\n return {\n agents: agentFiles.map((f) => parseAgent(f, readFileSync(f, \"utf8\"))),\n skills: skillFiles.map((f) => parseSkill(f, readFileSync(f, \"utf8\"))),\n cmds: cmdFiles.map((f) => parseCmd(f, readFileSync(f, \"utf8\"))),\n };\n}\n\nexport function loadProjectSkills(targetDir: string): Skill[] {\n const skillsDir = join(targetDir, \"docs\", \"skills\");\n if (!existsSync(skillsDir)) return [];\n const skillFiles = fg.sync(\"*.skill.md\", { cwd: skillsDir, absolute: true });\n return skillFiles.map((f) => parseSkill(f, readFileSync(f, \"utf8\")));\n}\n\nexport function loadOverrides(worktreeDir: string): HarnessOverrides | undefined {\n const overridesDir = join(worktreeDir, \".harness-overrides\");\n if (!existsSync(overridesDir)) return undefined;\n\n const added = loadHarness(overridesDir, {\n agentsDir: join(overridesDir, \"agents\"),\n skillsDir: join(overridesDir, \"skills\"),\n commandsDir: join(overridesDir, \"commands\"),\n });\n\n const disablePath = join(overridesDir, \"disable.yaml\");\n let disable: string[] = [];\n if (existsSync(disablePath)) {\n try {\n const parsed = DisableYamlSchema.safeParse(parseYAML(readFileSync(disablePath, \"utf8\")));\n if (parsed.success && parsed.data.disable) {\n disable = parsed.data.disable;\n }\n } catch {\n // corrupt YAML — leave disable as []\n }\n }\n\n return { add: added, disable };\n}\n","import { readFileSync } from \"node:fs\";\nimport matter from \"gray-matter\";\nimport type { z } from \"zod\";\nimport { ParseError } from \"./schemas.js\";\n\nexport interface ParsedFile<T> {\n meta: T;\n body: string;\n sourcePath: string;\n}\n\nexport function parseWithSchema<T extends z.ZodTypeAny>(\n filePath: string,\n source: string,\n schema: T,\n): ParsedFile<z.infer<T>> {\n const parsed = matter(source);\n const result = schema.safeParse(parsed.data);\n if (!result.success) {\n throw new ParseError(filePath, result.error.issues);\n }\n return {\n meta: result.data,\n body: parsed.content.trim(),\n sourcePath: filePath,\n };\n}\n\nexport function parseFileWithSchema<T extends z.ZodTypeAny>(\n filePath: string,\n schema: T,\n): ParsedFile<z.infer<T>> {\n const source = readFileSync(filePath, \"utf8\");\n return parseWithSchema(filePath, source, schema);\n}\n","import { z } from \"zod\";\nimport { AGENT_IDS, CAPABILITIES, ENGINES } from \"../types.js\";\n\nconst IdSchema = z\n .string()\n .min(1)\n .regex(/^[a-z][a-z0-9-]*$/, \"id must be kebab-case (lowercase + digits + hyphens)\");\n\nconst SkillFrontmatterSchema = z\n .object({\n id: IdSchema,\n description: z.string().min(1),\n engines: z.array(z.enum(ENGINES)).min(1).optional(),\n requires: z.array(z.enum(CAPABILITIES)).optional(),\n tags: z.array(z.string()).optional(),\n })\n .strict();\n\nexport type SkillFrontmatter = z.infer<typeof SkillFrontmatterSchema>;\n\nconst CmdArgEnumSchema = z\n .object({\n name: z.string().min(1),\n type: z.literal(\"enum\"),\n values: z.array(z.string()).min(1),\n default: z.string().optional(),\n })\n .strict();\n\nconst CmdArgStringSchema = z\n .object({\n name: z.string().min(1),\n type: z.literal(\"string\"),\n default: z.string().optional(),\n })\n .strict();\n\nconst CmdArgSchema = z.discriminatedUnion(\"type\", [CmdArgEnumSchema, CmdArgStringSchema]);\n\nexport type CmdArg = z.infer<typeof CmdArgSchema>;\n\nconst CmdFrontmatterSchema = z\n .object({\n id: IdSchema,\n trigger: z.string().regex(/^\\/[a-z][a-z0-9-]*$/, \"trigger must be /kebab-case\"),\n invokes_skill: IdSchema,\n args: z.array(CmdArgSchema).optional(),\n description: z.string().min(1),\n })\n .strict();\n\nexport type CmdFrontmatter = z.infer<typeof CmdFrontmatterSchema>;\n\nconst AgentFrontmatterSchema = z\n .object({\n id: z.enum(AGENT_IDS),\n description: z.string().min(1),\n })\n .strict();\n\nexport type AgentFrontmatter = z.infer<typeof AgentFrontmatterSchema>;\n\nexport const Schemas = {\n Skill: SkillFrontmatterSchema,\n Cmd: CmdFrontmatterSchema,\n Agent: AgentFrontmatterSchema,\n} as const;\n\nexport class ParseError extends Error {\n constructor(\n public readonly file: string,\n public readonly issues: z.ZodIssue[],\n ) {\n const messages = issues\n .map((i) => ` - ${i.path.join(\".\") || \"<root>\"}: ${i.message}`)\n .join(\"\\n\");\n super(`Frontmatter validation failed for ${file}:\\n${messages}`);\n this.name = \"ParseError\";\n }\n}\n","export const AGENT_IDS = [\"coding\", \"review\", \"merge\", \"planning\"] as const;\nexport type AgentId = (typeof AGENT_IDS)[number];\n\nexport const ENGINES = [\"claude-code\", \"codex-cli\", \"opencode\"] as const;\nexport type Engine = (typeof ENGINES)[number];\n\nexport const ENGINE_ROOT_DIR: Record<Engine, string> = {\n \"claude-code\": \".claude\",\n \"codex-cli\": \".codex\",\n opencode: \".opencode\",\n};\n\nexport const CAPABILITIES = [\"multi-step\", \"slash-command\", \"inline-exec\"] as const;\nexport type Capability = (typeof CAPABILITIES)[number];\n\nexport interface RenderedFile {\n path: string;\n content: string;\n}\n\nexport interface CapabilitiesMatrix {\n [engine: string]: ReadonlyArray<Capability>;\n}\n\nexport const CAPABILITIES_MATRIX: Record<Engine, ReadonlyArray<Capability>> = {\n \"claude-code\": [\"multi-step\", \"slash-command\", \"inline-exec\"],\n \"codex-cli\": [\"multi-step\", \"slash-command\", \"inline-exec\"],\n opencode: [\"multi-step\", \"slash-command\", \"inline-exec\"],\n};\n\nexport const DEGRADED_CAPABILITIES: Partial<Record<Engine, ReadonlyArray<Capability>>> = {\n \"codex-cli\": [\"multi-step\"],\n};\n\nexport function engineSupports(engine: Engine, capability: Capability): boolean {\n return CAPABILITIES_MATRIX[engine].includes(capability);\n}\n","import { parseFileWithSchema, parseWithSchema } from \"./common.js\";\nimport type { ParsedFile } from \"./common.js\";\nimport { type AgentFrontmatter, Schemas } from \"./schemas.js\";\n\nexport type Agent = ParsedFile<AgentFrontmatter>;\n\nexport function parseAgent(filePath: string, source: string): Agent {\n return parseWithSchema(filePath, source, Schemas.Agent);\n}\n\nexport function parseAgentFile(filePath: string): Agent {\n return parseFileWithSchema(filePath, Schemas.Agent);\n}\n","import { parseFileWithSchema, parseWithSchema } from \"./common.js\";\nimport type { ParsedFile } from \"./common.js\";\nimport { type CmdFrontmatter, Schemas } from \"./schemas.js\";\n\nexport type Cmd = ParsedFile<CmdFrontmatter>;\n\nexport function parseCmd(filePath: string, source: string): Cmd {\n return parseWithSchema(filePath, source, Schemas.Cmd);\n}\n\nexport function parseCmdFile(filePath: string): Cmd {\n return parseFileWithSchema(filePath, Schemas.Cmd);\n}\n","import { parseFileWithSchema, parseWithSchema } from \"./common.js\";\nimport type { ParsedFile } from \"./common.js\";\nimport { Schemas, type SkillFrontmatter } from \"./schemas.js\";\n\nexport type Skill = ParsedFile<SkillFrontmatter>;\n\nexport function parseSkill(filePath: string, source: string): Skill {\n return parseWithSchema(filePath, source, Schemas.Skill);\n}\n\nexport function parseSkillFile(filePath: string): Skill {\n return parseFileWithSchema(filePath, Schemas.Skill);\n}\n","import { parse as yamlParse } from \"yaml\";\n\nexport function parseYAML(source: string): unknown {\n return yamlParse(source);\n}\n","export const MCP_SERVER_IDS = [\"context7\"] as const;\nexport type McpServerId = (typeof MCP_SERVER_IDS)[number];\n\nexport interface McpServerSpec {\n id: McpServerId;\n description: string;\n command: string;\n args: ReadonlyArray<string>;\n env?: Record<string, string>;\n}\n\nexport const MCP_SERVERS: Record<McpServerId, McpServerSpec> = {\n context7: {\n id: \"context7\",\n description:\n \"Upstash Context7 — fetches up-to-date library docs via resolve-library-id + get-library-docs.\",\n command: \"npx\",\n args: [\"-y\", \"@upstash/context7-mcp\"],\n },\n};\n\nexport function resolveMcpIds(requested: ReadonlyArray<string>): McpServerId[] {\n return requested.map((id) => {\n if (!(MCP_SERVER_IDS as ReadonlyArray<string>).includes(id)) {\n throw new Error(`unknown MCP server: ${id} (expected one of ${MCP_SERVER_IDS.join(\", \")})`);\n }\n return id as McpServerId;\n });\n}\n","import { stringify as yamlStringify } from \"yaml\";\nimport type { McpServerSpec } from \"../mcp.js\";\nimport type { Agent } from \"../parser/agent.js\";\nimport type { Cmd } from \"../parser/cmd.js\";\nimport type { Skill } from \"../parser/skill.js\";\nimport {\n CAPABILITIES_MATRIX,\n type Capability,\n DEGRADED_CAPABILITIES,\n type Engine,\n type RenderedFile,\n} from \"../types.js\";\n\nexport interface UmbrellaExtras {\n availableSkills: ReadonlyArray<Skill>;\n availableCommands: ReadonlyArray<Cmd>;\n hasProjectSkills?: boolean;\n hasQualityDoc?: boolean;\n}\n\nexport interface RenderResult {\n files: RenderedFile[];\n warnings: string[];\n}\n\nexport interface Renderer {\n readonly engine: Engine;\n renderSkill(skill: Skill): RenderResult;\n renderCmd(cmd: Cmd): RenderResult;\n renderAgents(agents: ReadonlyArray<Agent>): RenderResult;\n renderMcp(servers: ReadonlyArray<McpServerSpec>): RenderResult;\n renderStopHook(): RenderResult;\n}\n\nexport const STOP_HOOK_PACKAGE = \"@vaubaan/harness\";\n\nexport interface CapabilityCheck {\n blockingWarnings: string[];\n degradedWarnings: string[];\n}\n\nexport function checkSkillCapabilities(skill: Skill, engine: Engine): CapabilityCheck {\n const blockingWarnings: string[] = [];\n const degradedWarnings: string[] = [];\n const supported = CAPABILITIES_MATRIX[engine];\n const degraded = DEGRADED_CAPABILITIES[engine] ?? [];\n if (!skill.meta.requires) return { blockingWarnings, degradedWarnings };\n for (const cap of skill.meta.requires) {\n if (!supported.includes(cap as Capability)) {\n blockingWarnings.push(\n `skill \"${skill.meta.id}\" requires \"${cap}\" not supported by \"${engine}\" — skipped`,\n );\n } else if (degraded.includes(cap as Capability)) {\n degradedWarnings.push(\n `skill \"${skill.meta.id}\" requires \"${cap}\" — supported by \"${engine}\" with degradation`,\n );\n }\n }\n return { blockingWarnings, degradedWarnings };\n}\n\nexport function isSkillEngineAllowed(skill: Skill, engine: Engine): boolean {\n if (!skill.meta.engines) return true;\n return skill.meta.engines.includes(engine);\n}\n\nexport function yamlFrontmatter(data: Record<string, unknown>): string {\n const rendered = yamlStringify(data, { lineWidth: 0 }).trimEnd();\n return `---\\n${rendered}\\n---\\n`;\n}\n\nconst SCALAR_NEEDS_QUOTE = /[^a-zA-Z0-9_./-]/;\n\nfunction tomlEscapeString(s: string): string {\n return `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"').replace(/\\n/g, \"\\\\n\")}\"`;\n}\n\nfunction tomlValue(v: unknown): string {\n if (Array.isArray(v)) {\n return `[${v.map((x) => tomlValue(x)).join(\", \")}]`;\n }\n if (typeof v === \"string\") {\n if (v.includes(\"\\n\")) return tomlEscapeString(v);\n return SCALAR_NEEDS_QUOTE.test(v) ? tomlEscapeString(v) : `\"${v}\"`;\n }\n if (typeof v === \"boolean\" || typeof v === \"number\") {\n return String(v);\n }\n return tomlEscapeString(String(v));\n}\n\n/** TOML multi-line basic string (`\"\"\"…\"\"\"`), used for Codex `developer_instructions`. */\nexport function tomlMultilineString(s: string): string {\n const escaped = s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"\"\"/g, '\"\"\\\\\"');\n return `\"\"\"\\n${escaped}\\n\"\"\"`;\n}\n\nexport function tomlQuoteString(s: string): string {\n return tomlValue(s);\n}\n\nexport function tomlInlineArray(items: ReadonlyArray<unknown>): string {\n return tomlValue([...items]);\n}\n\nexport function tomlInlineTable(table: Record<string, string>): string {\n const entries = Object.entries(table).map(([k, v]) => `${k} = ${tomlValue(v)}`);\n return `{ ${entries.join(\", \")} }`;\n}\n\nexport function frontmatterDataForSkill(skill: Skill): Record<string, unknown> {\n // Agent Skills spec (agentskills.io): `name` must match the directory name.\n const data: Record<string, unknown> = {\n name: skill.meta.id,\n description: skill.meta.description,\n };\n if (skill.meta.tags && skill.meta.tags.length > 0) data.tags = skill.meta.tags;\n return data;\n}\n\nexport function frontmatterDataForCmd(cmd: Cmd): Record<string, unknown> {\n const data: Record<string, unknown> = {\n id: cmd.meta.id,\n trigger: cmd.meta.trigger,\n description: cmd.meta.description,\n };\n if (cmd.meta.args && cmd.meta.args.length > 0) {\n data.args = cmd.meta.args.map((a) => {\n if (a.type === \"enum\") {\n return a.default !== undefined\n ? { name: a.name, type: a.type, values: a.values, default: a.default }\n : { name: a.name, type: a.type, values: a.values };\n }\n return a.default !== undefined\n ? { name: a.name, type: a.type, default: a.default }\n : { name: a.name, type: a.type };\n });\n }\n return data;\n}\n\n/**\n * Personas carry their role contract only: engines discover skills and\n * commands natively, so listing them per persona is pure context cost.\n */\nexport function buildAgentBody(agent: Agent): string {\n return `${agent.body.trim()}\\n`;\n}\n\nexport function buildUmbrellaBody(_agents: ReadonlyArray<Agent>, extras: UmbrellaExtras): string {\n const triggerBySkill = new Map(\n extras.availableCommands.map((c) => [c.meta.invokes_skill, c.meta.trigger]),\n );\n const skillLines = extras.availableSkills.map((s) => {\n const trigger = triggerBySkill.get(s.meta.id);\n const label = trigger ? `\\`${s.meta.id}\\` (\\`${trigger}\\`)` : `\\`${s.meta.id}\\``;\n return `- ${label} — ${s.meta.description.split(\"\\n\")[0]}`;\n });\n const sections: string[] = [\n \"# How we work\",\n \"\",\n \"This file describes **how to work in this project**. The **business context** (what the project does, how to run it, which subsystems it contains) lives in `README.md` and `docs/`. Read them first.\",\n \"\",\n \"## Project map\",\n \"\",\n \"- `README.md` — pitch, quick start, scripts. Entry point.\",\n \"- `docs/spec/<subsystem>.md` — *what* and *why* (tech-agnostic).\",\n \"- `docs/handbook/<feature>.md` — *how it actually works* today.\",\n \"- `docs/decisions/<slug>.md` — ADRs: structural choices and rejected alternatives.\",\n \"- `docs/tests/integration-tests.md` & `e2e-tests.md` — core scenarios.\",\n \"- `docs/workflow/coding-workflow.md` — CI, branches, PR, release.\",\n ...(extras.hasProjectSkills\n ? [\"- `docs/skills/*.skill.md` — the project's domain skills.\"]\n : []),\n ...(extras.hasQualityDoc\n ? [\n \"- `docs/quality/code-quality.md` — the project's code-quality rules: mechanical checks, judgment rules, accepted deviations. Read it before writing or auditing code.\",\n ]\n : []),\n \"\",\n \"## Doc-first\",\n \"\",\n \"The order is: **understand the docs → fill the gaps → code → update the docs → commit**. If the docs are silent or stale on something you change, fill the gap upfront with the doc-skill writers — not downstream, not after the fact.\",\n \"\",\n \"- Missing spec for a subsystem you touch → **do not code**, report the gap.\",\n \"- Implicit structural decision in your changes → an ADR (`/decision`).\",\n \"- Changed feature behavior → update the matching handbook (`/handbook`).\",\n \"- Suspected code ↔ doc drift → `/drift` before moving on.\",\n ];\n if (skillLines.length > 0) {\n sections.push(\"\", \"## Doc-skills\", \"\", skillLines.join(\"\\n\"));\n }\n return `${sections.join(\"\\n\")}\\n`;\n}\n","import type { McpServerSpec } from \"../mcp.js\";\nimport type { Agent } from \"../parser/agent.js\";\nimport type { Cmd } from \"../parser/cmd.js\";\nimport type { Skill } from \"../parser/skill.js\";\nimport type { Engine } from \"../types.js\";\nimport {\n type RenderResult,\n type Renderer,\n STOP_HOOK_PACKAGE,\n buildAgentBody,\n checkSkillCapabilities,\n frontmatterDataForCmd,\n frontmatterDataForSkill,\n isSkillEngineAllowed,\n yamlFrontmatter,\n} from \"./common.js\";\n\nconst ENGINE: Engine = \"claude-code\";\nconst BASE = \".claude\";\n\nexport const claudeCodeRenderer: Renderer = {\n engine: ENGINE,\n renderSkill(skill: Skill): RenderResult {\n if (!isSkillEngineAllowed(skill, ENGINE)) {\n return {\n files: [],\n warnings: [`skill \"${skill.meta.id}\" excluded from engine \"${ENGINE}\"`],\n };\n }\n const check = checkSkillCapabilities(skill, ENGINE);\n if (check.blockingWarnings.length > 0) {\n return { files: [], warnings: check.blockingWarnings };\n }\n const content = `${yamlFrontmatter(frontmatterDataForSkill(skill))}\\n${skill.body}\\n`;\n return {\n files: [{ path: `${BASE}/skills/${skill.meta.id}/SKILL.md`, content }],\n warnings: check.degradedWarnings,\n };\n },\n renderCmd(cmd: Cmd): RenderResult {\n const content = `${yamlFrontmatter(frontmatterDataForCmd(cmd))}\\n${cmd.body}\\n`;\n return {\n files: [{ path: `${BASE}/commands/${cmd.meta.id}.md`, content }],\n warnings: [],\n };\n },\n renderAgents(agents: ReadonlyArray<Agent>): RenderResult {\n const files = [];\n for (const agent of agents) {\n const subagentFrontmatter = yamlFrontmatter({\n name: agent.meta.id,\n description: agent.meta.description,\n });\n const body = buildAgentBody(agent);\n const content = `${subagentFrontmatter}\\n${body}`;\n files.push({ path: `${BASE}/agents/${agent.meta.id}.md`, content });\n }\n return { files, warnings: [] };\n },\n renderMcp(servers: ReadonlyArray<McpServerSpec>): RenderResult {\n if (servers.length === 0) return { files: [], warnings: [] };\n const mcpServers: Record<string, Record<string, unknown>> = {};\n for (const s of servers) {\n const entry: Record<string, unknown> = { command: s.command, args: [...s.args] };\n if (s.env) entry.env = s.env;\n mcpServers[s.id] = entry;\n }\n const content = `${JSON.stringify({ mcpServers }, null, 2)}\\n`;\n return { files: [{ path: \".mcp.json\", content }], warnings: [] };\n },\n renderStopHook(): RenderResult {\n const settings = {\n hooks: {\n Stop: [\n {\n matcher: \"\",\n hooks: [\n {\n type: \"command\",\n command: `npx -y ${STOP_HOOK_PACKAGE} stop-hook --engine claude`,\n },\n ],\n },\n ],\n },\n };\n return {\n files: [{ path: `${BASE}/settings.json`, content: `${JSON.stringify(settings, null, 2)}\\n` }],\n warnings: [],\n };\n },\n};\n","import type { McpServerSpec } from \"../mcp.js\";\nimport type { Agent } from \"../parser/agent.js\";\nimport type { Cmd } from \"../parser/cmd.js\";\nimport type { Skill } from \"../parser/skill.js\";\nimport type { Engine } from \"../types.js\";\nimport {\n type RenderResult,\n type Renderer,\n STOP_HOOK_PACKAGE,\n buildAgentBody,\n checkSkillCapabilities,\n frontmatterDataForSkill,\n isSkillEngineAllowed,\n tomlInlineArray,\n tomlInlineTable,\n tomlMultilineString,\n tomlQuoteString,\n yamlFrontmatter,\n} from \"./common.js\";\n\nconst ENGINE: Engine = \"codex-cli\";\nconst BASE = \".codex\";\n// Codex discovers repo skills under `.agents/skills/` only — `.codex/skills/` is not scanned.\nconst SKILLS_BASE = \".agents/skills\";\n\nexport const codexCliRenderer: Renderer = {\n engine: ENGINE,\n renderSkill(skill: Skill): RenderResult {\n if (!isSkillEngineAllowed(skill, ENGINE)) {\n return {\n files: [],\n warnings: [`skill \"${skill.meta.id}\" excluded from engine \"${ENGINE}\"`],\n };\n }\n const check = checkSkillCapabilities(skill, ENGINE);\n if (check.blockingWarnings.length > 0) {\n return { files: [], warnings: check.blockingWarnings };\n }\n const content = `${yamlFrontmatter(frontmatterDataForSkill(skill))}\\n${skill.body}\\n`;\n return {\n files: [{ path: `${SKILLS_BASE}/${skill.meta.id}/SKILL.md`, content }],\n warnings: check.degradedWarnings,\n };\n },\n // Codex custom prompts are deprecated in favour of skills: nothing to render.\n renderCmd(_cmd: Cmd): RenderResult {\n return { files: [], warnings: [] };\n },\n renderAgents(agents: ReadonlyArray<Agent>): RenderResult {\n const files = [];\n for (const agent of agents) {\n const content = [\n `name = ${tomlQuoteString(agent.meta.id)}`,\n `description = ${tomlQuoteString(agent.meta.description)}`,\n `developer_instructions = ${tomlMultilineString(buildAgentBody(agent).trimEnd())}`,\n \"\",\n ].join(\"\\n\");\n files.push({ path: `${BASE}/agents/${agent.meta.id}.toml`, content });\n }\n return { files, warnings: [] };\n },\n renderMcp(servers: ReadonlyArray<McpServerSpec>): RenderResult {\n if (servers.length === 0) return { files: [], warnings: [] };\n const blocks: string[] = [];\n for (const s of servers) {\n const lines = [\n `[mcp_servers.${s.id}]`,\n `command = ${tomlQuoteString(s.command)}`,\n `args = ${tomlInlineArray([...s.args])}`,\n ];\n if (s.env) lines.push(`env = ${tomlInlineTable(s.env)}`);\n blocks.push(lines.join(\"\\n\"));\n }\n const content = `${blocks.join(\"\\n\\n\")}\\n`;\n return { files: [{ path: `${BASE}/config.toml`, content }], warnings: [] };\n },\n renderStopHook(): RenderResult {\n const hooks = {\n hooks: {\n Stop: [\n {\n hooks: [\n {\n type: \"command\",\n command: `npx -y ${STOP_HOOK_PACKAGE} stop-hook --engine codex`,\n },\n ],\n },\n ],\n },\n };\n return {\n files: [{ path: `${BASE}/hooks.json`, content: `${JSON.stringify(hooks, null, 2)}\\n` }],\n warnings: [],\n };\n },\n};\n","import type { McpServerSpec } from \"../mcp.js\";\nimport type { Agent } from \"../parser/agent.js\";\nimport type { Cmd } from \"../parser/cmd.js\";\nimport type { Skill } from \"../parser/skill.js\";\nimport type { Engine } from \"../types.js\";\nimport {\n type RenderResult,\n type Renderer,\n STOP_HOOK_PACKAGE,\n buildAgentBody,\n checkSkillCapabilities,\n frontmatterDataForSkill,\n isSkillEngineAllowed,\n yamlFrontmatter,\n} from \"./common.js\";\n\nconst ENGINE: Engine = \"opencode\";\nconst BASE = \".opencode\";\n\nexport const opencodeRenderer: Renderer = {\n engine: ENGINE,\n renderSkill(skill: Skill): RenderResult {\n if (!isSkillEngineAllowed(skill, ENGINE)) {\n return {\n files: [],\n warnings: [`skill \"${skill.meta.id}\" excluded from engine \"${ENGINE}\"`],\n };\n }\n const check = checkSkillCapabilities(skill, ENGINE);\n if (check.blockingWarnings.length > 0) {\n return { files: [], warnings: check.blockingWarnings };\n }\n const content = `${yamlFrontmatter(frontmatterDataForSkill(skill))}\\n${skill.body}\\n`;\n return {\n files: [{ path: `${BASE}/skills/${skill.meta.id}/SKILL.md`, content }],\n warnings: check.degradedWarnings,\n };\n },\n renderCmd(cmd: Cmd): RenderResult {\n // OpenCode names the command after the file; only `description` is a known key.\n const content = `${yamlFrontmatter({ description: cmd.meta.description })}\\n${cmd.body}\\n`;\n return {\n files: [{ path: `${BASE}/commands/${cmd.meta.id}.md`, content }],\n warnings: [],\n };\n },\n renderAgents(agents: ReadonlyArray<Agent>): RenderResult {\n const files = [];\n for (const agent of agents) {\n // The file name is the agent name. `mode: all` keeps each persona usable\n // both as a session's primary agent and as a subagent.\n const fm = yamlFrontmatter({\n description: agent.meta.description,\n mode: \"all\",\n });\n const body = buildAgentBody(agent);\n files.push({ path: `${BASE}/agents/${agent.meta.id}.md`, content: `${fm}\\n${body}` });\n }\n return { files, warnings: [] };\n },\n renderMcp(servers: ReadonlyArray<McpServerSpec>): RenderResult {\n if (servers.length === 0) return { files: [], warnings: [] };\n const mcp: Record<string, Record<string, unknown>> = {};\n for (const s of servers) {\n const entry: Record<string, unknown> = {\n type: \"local\",\n command: [s.command, ...s.args],\n enabled: true,\n };\n if (s.env) entry.environment = s.env;\n mcp[s.id] = entry;\n }\n const config = { $schema: \"https://opencode.ai/config.json\", mcp };\n const content = `${JSON.stringify(config, null, 2)}\\n`;\n return { files: [{ path: `${BASE}/opencode.json`, content }], warnings: [] };\n },\n renderStopHook(): RenderResult {\n const content = `import { spawnSync } from \"node:child_process\";\n\n// Runs the harness lint and returns the report to inject, or \"\" when the\n// turn may end.\nconst lintReport = (directory, sessionID) => {\n const r = spawnSync(\n \"npx\",\n [\"-y\", \"${STOP_HOOK_PACKAGE}\", \"stop-hook\", \"--engine\", \"opencode\", \"--cwd\", directory],\n { input: JSON.stringify({ sessionID }), encoding: \"utf-8\" },\n );\n const report = (r.stderr ?? \"\").trim();\n return r.status === 2 ? report : \"\";\n};\n\n// OpenCode 1.x entry point, exposed as server() below.\nconst HarnessStopHook = async ({ client, directory }) => ({\n event: async ({ event }) => {\n if (event.type !== \"session.idle\") return;\n const sessionID = event.properties?.sessionID;\n if (!sessionID) return;\n const report = lintReport(directory, sessionID);\n if (report === \"\") return;\n // OpenCode defaults to its build agent when a prompt omits agent.\n // Preserve the last conversation persona, excluding compaction summaries.\n const history = await client.session.messages({ path: { id: sessionID } }).catch(() => undefined);\n if (history?.error || !Array.isArray(history?.data)) return;\n const current = history.data.findLast(({ info }) =>\n (info.role === \"user\" || (info.role === \"assistant\" && !info.summary)) &&\n typeof info.agent === \"string\" && info.agent.trim() !== \"\",\n );\n if (!current) return;\n await client.session.prompt({\n path: { id: sessionID },\n body: { agent: current.info.agent, parts: [{ type: \"text\", text: report }] },\n });\n },\n});\n\n// One default export for both majors: OpenCode 1.x calls server(),\n// OpenCode 2.x calls setup(). A V2 session keeps its agent, so the report\n// is sent without naming the persona.\nexport default {\n id: \"vaubaan-harness-stop-hook\",\n server: HarnessStopHook,\n setup(context) {\n const directory = context.location.directory;\n const controller = new AbortController();\n const listen = async () => {\n for await (const event of context.event.subscribe({ signal: controller.signal })) {\n if (event.type !== \"session.idle\") continue;\n if (event.location?.directory && event.location.directory !== directory) continue;\n const sessionID = event.data?.sessionID;\n if (!sessionID) continue;\n const report = lintReport(directory, sessionID);\n if (report === \"\") continue;\n await context.session.prompt({ sessionID, text: report }).catch(() => undefined);\n }\n };\n listen().catch(() => undefined);\n return () => controller.abort();\n },\n};\n`;\n return {\n files: [{ path: `${BASE}/plugins/harness-stop-hook.ts`, content }],\n warnings: [],\n };\n },\n};\n","import type { Engine } from \"../types.js\";\nimport { claudeCodeRenderer } from \"./claude-code.js\";\nimport { codexCliRenderer } from \"./codex-cli.js\";\nimport type { Renderer } from \"./common.js\";\nimport { opencodeRenderer } from \"./opencode.js\";\n\nexport const RENDERERS: Record<Engine, Renderer> = {\n \"claude-code\": claudeCodeRenderer,\n \"codex-cli\": codexCliRenderer,\n opencode: opencodeRenderer,\n};\n\nexport function getRenderer(engine: Engine): Renderer {\n return RENDERERS[engine];\n}\n\nexport type { Renderer, RenderResult } from \"./common.js\";\n","import { MCP_SERVERS, type McpServerId } from \"./mcp.js\";\nimport type { Agent } from \"./parser/agent.js\";\nimport type { Cmd } from \"./parser/cmd.js\";\nimport type { Skill } from \"./parser/skill.js\";\nimport { buildUmbrellaBody } from \"./renderers/common.js\";\nimport { getRenderer } from \"./renderers/index.js\";\nimport type { Engine, RenderedFile } from \"./types.js\";\n\nexport interface Harness {\n agents: ReadonlyArray<Agent>;\n skills: ReadonlyArray<Skill>;\n cmds: ReadonlyArray<Cmd>;\n}\n\nexport interface HarnessOverrides {\n add?: Partial<Harness>;\n disable?: ReadonlyArray<string>;\n}\n\nexport interface RenderInput {\n harness: Harness;\n engines: ReadonlyArray<Engine>;\n overrides?: HarnessOverrides;\n projectSkills?: ReadonlyArray<Skill>;\n /** True when the target project ships `docs/quality/code-quality.md` (optional pillar). */\n hasQualityDoc?: boolean;\n mcpServers?: ReadonlyArray<McpServerId>;\n /**\n * When true (default), each engine's renderer emits a Stop-hook config\n * that calls `vaubaan-harness stop-hook --engine <engine>` and injects\n * the lint report (with skill suggestions) into the running session\n * whenever the worktree is dirty and lint fails. Pass `false` to skip\n * the hook configs entirely (kill-switch at install time; runtime\n * kill-switch is `HARNESS_LINT_DISABLE=1`).\n */\n withStopHook?: boolean;\n}\n\nexport interface RenderOutput {\n files: RenderedFile[];\n warnings: string[];\n}\n\nexport class RenderError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"RenderError\";\n }\n}\n\nfunction mergeById<T extends { meta: { id: string } }>(\n stock: ReadonlyArray<T>,\n added: ReadonlyArray<T> | undefined,\n): T[] {\n const result = new Map<string, T>();\n for (const item of stock) result.set(item.meta.id, item);\n if (added) {\n for (const item of added) result.set(item.meta.id, item);\n }\n return Array.from(result.values());\n}\n\nfunction removeByIds<T extends { meta: { id: string } }>(\n items: ReadonlyArray<T>,\n disabled: ReadonlyArray<string>,\n): T[] {\n if (disabled.length === 0) return [...items];\n const disabledSet = new Set(disabled);\n return items.filter((item) => !disabledSet.has(item.meta.id));\n}\n\nexport function applyOverrides(harness: Harness, overrides: HarnessOverrides | undefined): Harness {\n const disabled = overrides?.disable ?? [];\n return {\n agents: removeByIds(mergeById(harness.agents, overrides?.add?.agents), disabled),\n skills: removeByIds(mergeById(harness.skills, overrides?.add?.skills), disabled),\n cmds: removeByIds(mergeById(harness.cmds, overrides?.add?.cmds), disabled),\n };\n}\n\n// `@AGENTS.md` is Claude Code's import syntax: the umbrella is really loaded,\n// on every version and provider, and never read twice alongside native\n// AGENTS.md support (cf. ADR engine-native-layouts-1-0).\nconst CLAUDE_MD_STUB = \"@AGENTS.md\\n\";\n\n// OpenCode also scans `.claude/skills/` and `.agents/skills/`. It goes last so\n// its own copy of a skill is dropped when another rendered engine exposes it.\nfunction opencodeLast(engines: ReadonlyArray<Engine>): Engine[] {\n return [...engines].sort((a, b) => Number(a === \"opencode\") - Number(b === \"opencode\"));\n}\n\nexport function render(input: RenderInput): RenderOutput {\n const { engines } = input;\n if (engines.length === 0) {\n throw new RenderError(\"at least one engine must be selected\");\n }\n const base: Harness = input.projectSkills?.length\n ? { ...input.harness, skills: mergeById(input.harness.skills, input.projectSkills) }\n : input.harness;\n const harness = applyOverrides(base, input.overrides);\n if (harness.agents.length === 0) {\n throw new RenderError(\"No agents found in harness\");\n }\n\n const files: RenderedFile[] = [];\n const warnings: string[] = [];\n\n // Track skills + commands successfully exposed on at least one engine,\n // for the engine-neutral umbrella's \"Available skills/commands\" sections.\n const exposedSkills = new Map<string, Skill>();\n const exposedCmds = new Map<string, Cmd>();\n\n for (const engine of opencodeLast(engines)) {\n const renderer = getRenderer(engine);\n\n const renderedSkills: Skill[] = [];\n for (const skill of harness.skills) {\n const result = renderer.renderSkill(skill);\n warnings.push(...result.warnings);\n if (result.files.length > 0) {\n const alreadyVisible = engine === \"opencode\" && exposedSkills.has(skill.meta.id);\n if (!alreadyVisible) files.push(...result.files);\n renderedSkills.push(skill);\n exposedSkills.set(skill.meta.id, skill);\n }\n }\n\n const renderedSkillIds = new Set(renderedSkills.map((s) => s.meta.id));\n const renderedCmds: Cmd[] = [];\n for (const cmd of harness.cmds) {\n if (!renderedSkillIds.has(cmd.meta.invokes_skill)) continue;\n const result = renderer.renderCmd(cmd);\n warnings.push(...result.warnings);\n if (result.files.length > 0) {\n files.push(...result.files);\n renderedCmds.push(cmd);\n exposedCmds.set(cmd.meta.id, cmd);\n }\n }\n\n const agentsResult = renderer.renderAgents(harness.agents);\n warnings.push(...agentsResult.warnings);\n files.push(...agentsResult.files);\n\n if (input.mcpServers && input.mcpServers.length > 0) {\n const specs = input.mcpServers.map((id) => MCP_SERVERS[id]);\n const mcpResult = renderer.renderMcp(specs);\n warnings.push(...mcpResult.warnings);\n files.push(...mcpResult.files);\n }\n\n if (input.withStopHook !== false) {\n const hookResult = renderer.renderStopHook();\n warnings.push(...hookResult.warnings);\n files.push(...hookResult.files);\n }\n }\n\n // Engine-neutral umbrella at the root\n const hasProjectSkills = (input.projectSkills?.length ?? 0) > 0;\n const umbrellaContent = buildUmbrellaBody(harness.agents, {\n availableSkills: Array.from(exposedSkills.values()),\n availableCommands: Array.from(exposedCmds.values()),\n hasProjectSkills,\n hasQualityDoc: input.hasQualityDoc === true,\n });\n files.push({ path: \"AGENTS.md\", content: umbrellaContent });\n\n // CLAUDE.md stub only if claude-code is enabled (Claude Code reads it historically)\n if (engines.includes(\"claude-code\")) {\n files.push({ path: \"CLAUDE.md\", content: CLAUDE_MD_STUB });\n }\n\n return { files, warnings };\n}\n","import { lstatSync, realpathSync, statSync } from \"node:fs\";\nimport { basename, dirname, isAbsolute, join, resolve, win32 } from \"node:path\";\n\nconst MANAGED_FILES = new Set([\n \"AGENTS.md\",\n \"CLAUDE.md\",\n \".mcp.json\",\n \".harness-manifest.json\",\n \".claude/settings.json\",\n \".codex/config.toml\",\n \".codex/hooks.json\",\n \".opencode/opencode.json\",\n \".opencode/mcp.json\",\n]);\n\n// Includes legacy layouts so upgrades can remove their generated artifacts.\nconst MANAGED_DIRECTORIES = [\n \".claude/agents/\",\n \".claude/commands/\",\n \".claude/skills/\",\n \".codex/agents/\",\n \".codex/commands/\",\n \".codex/skills/\",\n \".agents/skills/\",\n \".opencode/agents/\",\n \".opencode/commands/\",\n \".opencode/skills/\",\n \".opencode/plugins/\",\n];\n\nfunction canonicalTargetRoot(root: string): string {\n let ancestor = resolve(root);\n const missing: string[] = [];\n while (!lstatSync(ancestor, { throwIfNoEntry: false })) {\n missing.unshift(basename(ancestor));\n ancestor = dirname(ancestor);\n }\n const canonical = realpathSync(ancestor);\n if (!statSync(canonical).isDirectory()) {\n throw new Error(`harness target is not a directory: ${root}`);\n }\n return join(canonical, ...missing);\n}\n\nfunction assertManagedLocation(path: string): void {\n const invalidSegment = path\n .split(\"/\")\n .some((part) => part === \"\" || part === \".\" || part === \"..\");\n if (\n isAbsolute(path) ||\n win32.isAbsolute(path) ||\n path.includes(\"\\\\\") ||\n path.includes(\"\\0\") ||\n invalidSegment\n ) {\n throw new Error(`unsafe harness path: ${path}`);\n }\n if (!MANAGED_FILES.has(path) && !MANAGED_DIRECTORIES.some((prefix) => path.startsWith(prefix))) {\n throw new Error(`path is outside harness-managed locations: ${path}`);\n }\n}\n\nfunction assertNoSymbolicComponents(root: string, path: string): void {\n const parts = path.split(\"/\");\n let current = root;\n for (const [index, part] of parts.entries()) {\n current = join(current, part);\n const info = lstatSync(current, { throwIfNoEntry: false });\n if (!info) return;\n if (info.isSymbolicLink()) {\n throw new Error(`symbolic link in harness path: ${path}`);\n }\n const isLeaf = index === parts.length - 1;\n if (isLeaf ? !info.isFile() : !info.isDirectory()) {\n throw new Error(`unexpected file type in harness path: ${path}`);\n }\n }\n}\n\n/**\n * Preflight the complete list before callers mutate any artifact. The target\n * itself may resolve through a symlink; every component below it, including\n * leaf files and the manifest, must be a regular file or directory, never a\n * symlink (even one pointing inside the target). Missing targets are allowed.\n * This checks the current filesystem, not concurrent changes by other processes.\n */\nexport function assertManagedPaths(root: string, files: ReadonlyArray<string>): void {\n for (const path of files) assertManagedLocation(path);\n const canonicalRoot = canonicalTargetRoot(root);\n for (const path of files) assertNoSymbolicComponents(canonicalRoot, path);\n}\n","import { createHash } from \"node:crypto\";\nimport { chmodSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { z } from \"zod\";\nimport type { Engine } from \"../types.js\";\nimport { VERSION } from \"../version.js\";\nimport { assertManagedPaths } from \"./managed-paths.js\";\nimport { type OpenCodeConfigOwnership, OpenCodeConfigOwnershipSchema } from \"./opencode-config.js\";\nimport { type HookConfigsOwnership, HookConfigsOwnershipSchema } from \"./update-config.js\";\n\nexport const MANIFEST_FILENAME = \".harness-manifest.json\";\nexport const MANIFEST_VERSION = \"6\";\n\nconst ManifestSchema = z.object({\n version: z.enum([\"4\", \"5\", MANIFEST_VERSION]),\n engines: z.array(z.string()),\n renderedAt: z.string(),\n files: z.array(z.string()),\n stopHookInstalled: z.boolean().optional(),\n stopHookEngines: z.array(z.string()).optional(),\n opencodeConfig: OpenCodeConfigOwnershipSchema.optional(),\n hookConfigs: HookConfigsOwnershipSchema.optional(),\n harnessVersion: z.string().optional(),\n overridesDir: z.string().optional(),\n fileHashes: z.record(z.string().regex(/^[a-f0-9]{64}$/)).optional(),\n preservedFiles: z.array(z.string()).optional(),\n});\n\nexport type Manifest = z.infer<typeof ManifestSchema>;\n\nexport interface WriteManifestExtras {\n stopHookInstalled?: boolean;\n stopHookEngines?: ReadonlyArray<Engine>;\n opencodeConfig?: OpenCodeConfigOwnership;\n hookConfigs?: HookConfigsOwnership;\n overridesDir?: string;\n preservedFiles?: string[];\n}\n\nexport function manifestPath(targetDir: string): string {\n return join(targetDir, MANIFEST_FILENAME);\n}\n\nexport function writeManifest(\n targetDir: string,\n engines: ReadonlyArray<Engine>,\n files: string[],\n extras: WriteManifestExtras = {},\n): void {\n assertManagedPaths(targetDir, [MANIFEST_FILENAME]);\n const manifest: Manifest = {\n version: MANIFEST_VERSION,\n harnessVersion: VERSION,\n engines: [...engines].sort(),\n renderedAt: new Date().toISOString(),\n files: [...files].sort(),\n fileHashes: Object.fromEntries(\n files\n .filter((file) => existsSync(join(targetDir, file)))\n .sort()\n .map((file) => [file, hashContent(readFileSync(join(targetDir, file)))]),\n ),\n ...(extras.overridesDir ? { overridesDir: extras.overridesDir } : {}),\n ...(extras.preservedFiles ? { preservedFiles: extras.preservedFiles } : {}),\n ...(extras.hookConfigs ? { hookConfigs: extras.hookConfigs } : {}),\n ...(extras.opencodeConfig ? { opencodeConfig: extras.opencodeConfig } : {}),\n ...(extras.stopHookInstalled !== undefined\n ? { stopHookInstalled: extras.stopHookInstalled }\n : {}),\n ...(extras.stopHookEngines !== undefined\n ? { stopHookEngines: [...extras.stopHookEngines].sort() }\n : {}),\n };\n const path = manifestPath(targetDir);\n if (existsSync(path)) chmodSync(path, 0o600);\n writeFileSync(path, `${JSON.stringify(manifest, null, 2)}\\n`, { mode: 0o600 });\n}\n\nexport function hashContent(content: string | Buffer): string {\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\nexport function readManifest(targetDir: string): Manifest | null {\n assertManagedPaths(targetDir, [MANIFEST_FILENAME]);\n const path = manifestPath(targetDir);\n if (!existsSync(path)) return null;\n const raw = JSON.parse(readFileSync(path, \"utf8\"));\n return ManifestSchema.parse(raw);\n}\n","export const VERSION = \"1.3.2\";\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport { z } from \"zod\";\nimport type { RenderedFile } from \"../types.js\";\n\nexport const OPENCODE_CONFIG_PATH = \".opencode/opencode.json\";\nconst OPENCODE_SCHEMA = \"https://opencode.ai/config.json\";\nconst ObjectSchema = z.record(z.unknown());\n\nexport const OpenCodeConfigOwnershipSchema = z.object({\n createdFile: z.boolean(),\n addedMcp: z.boolean(),\n addedSchema: z.boolean(),\n entries: z.record(ObjectSchema),\n});\n\nexport type OpenCodeConfigOwnership = z.infer<typeof OpenCodeConfigOwnershipSchema>;\n\nexport interface OpenCodeConfigPlan {\n write?: RenderedFile;\n remove: boolean;\n ownership?: OpenCodeConfigOwnership;\n warnings: string[];\n}\n\nfunction parseConfig(content: string): Record<string, unknown> {\n try {\n const config = ObjectSchema.parse(JSON.parse(content));\n if (Object.hasOwn(config, \"mcp\")) ObjectSchema.parse(config.mcp);\n return config;\n } catch {\n throw new Error(`invalid ${OPENCODE_CONFIG_PATH}: expected a JSON object with an MCP object`);\n }\n}\n\nfunction removeOwnedEntries(\n config: Record<string, unknown>,\n ownership: OpenCodeConfigOwnership,\n warnings: string[],\n): void {\n if (Object.hasOwn(config, \"mcp\")) {\n const mcp = ObjectSchema.parse(config.mcp);\n for (const [id, installed] of Object.entries(ownership.entries)) {\n if (!Object.hasOwn(mcp, id)) continue;\n if (isDeepStrictEqual(mcp[id], installed)) delete mcp[id];\n else warnings.push(`preserved modified OpenCode MCP server: ${id}`);\n }\n config.mcp = mcp;\n if (ownership.addedMcp && Object.keys(mcp).length === 0) Reflect.deleteProperty(config, \"mcp\");\n }\n if (ownership.addedSchema && config.$schema === OPENCODE_SCHEMA)\n Reflect.deleteProperty(config, \"$schema\");\n}\n\nfunction addMissingEntries(\n config: Record<string, unknown>,\n desired: RenderedFile,\n createdFile: boolean,\n warnings: string[],\n): OpenCodeConfigOwnership | undefined {\n const requested = ObjectSchema.parse(parseConfig(desired.content).mcp);\n const mcp = ObjectSchema.parse(config.mcp ?? {});\n const entries: Record<string, Record<string, unknown>> = {};\n for (const [id, entry] of Object.entries(requested)) {\n if (Object.hasOwn(mcp, id)) {\n if (!isDeepStrictEqual(mcp[id], entry)) {\n warnings.push(`preserved existing OpenCode MCP server instead of replacing it: ${id}`);\n }\n continue;\n }\n entries[id] = ObjectSchema.parse(entry);\n mcp[id] = entry;\n }\n if (Object.keys(entries).length === 0) return undefined;\n const ownership = {\n createdFile,\n addedMcp: !Object.hasOwn(config, \"mcp\"),\n addedSchema: !Object.hasOwn(config, \"$schema\"),\n entries,\n };\n config.mcp = mcp;\n if (ownership.addedSchema) config.$schema = OPENCODE_SCHEMA;\n return ownership;\n}\n\n/** Plans shared configuration edits before init/uninstall mutate any project files. */\nexport function planOpenCodeConfig(\n root: string,\n desired: RenderedFile | undefined,\n previous: OpenCodeConfigOwnership | undefined,\n): OpenCodeConfigPlan {\n const warnings: string[] = [];\n if (!desired && !previous) return { remove: false, warnings };\n const path = join(root, OPENCODE_CONFIG_PATH);\n const existed = existsSync(path);\n if (!existed && !desired) return { remove: false, warnings };\n const original = existed ? readFileSync(path, \"utf8\") : undefined;\n const config = original === undefined ? {} : parseConfig(original);\n const before = structuredClone(config);\n if (previous) removeOwnedEntries(config, previous, warnings);\n const createdFile = !existed || previous?.createdFile === true;\n const ownership = desired ? addMissingEntries(config, desired, createdFile, warnings) : undefined;\n if (!ownership && createdFile && Object.keys(config).length === 0) {\n return { remove: existed, warnings };\n }\n return {\n remove: false,\n ownership,\n warnings,\n ...(!existed || !isDeepStrictEqual(before, config)\n ? { write: { path: OPENCODE_CONFIG_PATH, content: `${JSON.stringify(config, null, 2)}\\n` } }\n : {}),\n };\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport { z } from \"zod\";\nimport { getRenderer } from \"../renderers/index.js\";\nimport type { Engine, RenderedFile } from \"../types.js\";\nimport { assertManagedPaths } from \"./managed-paths.js\";\nimport {\n OPENCODE_CONFIG_PATH,\n type OpenCodeConfigOwnership,\n planOpenCodeConfig,\n} from \"./opencode-config.js\";\n\nconst LEGACY_OPENCODE_CONFIG = \".opencode/mcp.json\";\nexport const SHARED_CONFIG_PATHS: ReadonlyArray<string> = [\n \".mcp.json\",\n \".codex/config.toml\",\n OPENCODE_CONFIG_PATH,\n LEGACY_OPENCODE_CONFIG,\n \".claude/settings.json\",\n \".codex/hooks.json\",\n];\n\nconst ObjectSchema = z.record(z.unknown());\nconst HookEntrySchema = z.object({ group: ObjectSchema, hook: ObjectSchema });\nconst HookConfigOwnershipSchema = z.object({\n createdFile: z.boolean(),\n addedHooks: z.boolean(),\n addedStop: z.boolean(),\n entries: z.array(HookEntrySchema),\n});\nexport const HookConfigsOwnershipSchema = z\n .object({\n \".claude/settings.json\": HookConfigOwnershipSchema.optional(),\n \".codex/hooks.json\": HookConfigOwnershipSchema.optional(),\n })\n .strict();\nexport type HookConfigsOwnership = z.infer<typeof HookConfigsOwnershipSchema>;\ntype HookConfigOwnership = z.infer<typeof HookConfigOwnershipSchema>;\ntype HookEntry = z.infer<typeof HookEntrySchema>;\ntype HookPath = keyof HookConfigsOwnership;\n\nconst HOOK_ENGINES: Record<HookPath, Engine> = {\n \".claude/settings.json\": \"claude-code\",\n \".codex/hooks.json\": \"codex-cli\",\n};\n\nexport interface ConfigMutations {\n writes: RenderedFile[];\n removals: string[];\n warnings: string[];\n}\n\nexport interface UpdateConfigPrevious {\n files: ReadonlyArray<string>;\n opencodeConfig?: OpenCodeConfigOwnership;\n hookConfigs?: HookConfigsOwnership;\n}\n\nexport interface UpdateConfigPlan extends ConfigMutations {\n ownedFiles: string[];\n opencodeConfig?: OpenCodeConfigOwnership;\n hookConfigs?: HookConfigsOwnership;\n}\n\nfunction parseObject(content: string, path: string): Record<string, unknown> {\n try {\n return ObjectSchema.parse(JSON.parse(content));\n } catch {\n throw new Error(`invalid shared configuration ${path}: expected a JSON object`);\n }\n}\n\nfunction asObject(value: unknown): Record<string, unknown> | undefined {\n const parsed = ObjectSchema.safeParse(value);\n return parsed.success ? parsed.data : undefined;\n}\n\nfunction stopHooks(config: Record<string, unknown>, path: string): unknown[] {\n if (!Object.hasOwn(config, \"hooks\")) return [];\n const hooks = asObject(config.hooks);\n if (!hooks || (Object.hasOwn(hooks, \"Stop\") && !Array.isArray(hooks.Stop))) {\n throw new Error(`invalid shared configuration ${path}: expected hooks.Stop to be an array`);\n }\n return Array.isArray(hooks.Stop) ? hooks.Stop : [];\n}\n\nfunction groupMetadata(group: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(Object.entries(group).filter(([key]) => key !== \"hooks\"));\n}\n\nfunction sameEntry(left: HookEntry, right: HookEntry): boolean {\n return isDeepStrictEqual(left.group, right.group) && isDeepStrictEqual(left.hook, right.hook);\n}\n\nfunction appendEntry(entries: HookEntry[], entry: HookEntry): void {\n if (!entries.some((existing) => sameEntry(existing, entry))) entries.push(entry);\n}\n\nfunction defaultStopGroup(engine: Engine): Record<string, unknown> {\n const file = getRenderer(engine).renderStopHook().files[0];\n if (!file) throw new Error(`missing Stop hook renderer for ${engine}`);\n const group = asObject(stopHooks(parseObject(file.content, file.path), file.path)[0]);\n if (!group || !Array.isArray(group.hooks) || !asObject(group.hooks[0])) {\n throw new Error(`invalid Stop hook renderer for ${engine}`);\n }\n return group;\n}\n\nfunction normalizeHarnessHooks(\n groups: unknown[],\n expected: Record<string, unknown>,\n previous: HookConfigOwnership | undefined,\n claimExisting: boolean,\n warnings: string[],\n path: HookPath,\n): { groups: unknown[]; entries: HookEntry[] } {\n const defaultHook = ObjectSchema.parse((expected.hooks as unknown[])[0]);\n const entries = [...(previous?.entries ?? [])];\n let found = false;\n const normalized = groups.map((value) => {\n const group = asObject(value);\n if (!group) return value;\n const flat = group.type === \"command\" && group.command === defaultHook.command;\n const hooks = flat ? [group] : Array.isArray(group.hooks) ? group.hooks : [];\n const metadata = flat ? groupMetadata(expected) : groupMetadata(group);\n for (const value of hooks) {\n const hook = asObject(value);\n if (!hook || hook.type !== \"command\" || hook.command !== defaultHook.command) continue;\n found = true;\n const entry = { group: metadata, hook };\n if (!claimExisting) continue;\n if (previous && !previous.entries.some((old) => sameEntry(old, entry))) {\n warnings.push(`preserved modified harness Stop hook: ${path}`);\n } else {\n appendEntry(entries, entry);\n }\n }\n return flat && claimExisting ? { ...metadata, hooks: [group] } : value;\n });\n if (!found && !previous?.entries.length) {\n normalized.push(expected);\n appendEntry(entries, { group: groupMetadata(expected), hook: defaultHook });\n } else if (!found) {\n warnings.push(`preserved removed or modified harness Stop hook: ${path}`);\n }\n return { groups: normalized, entries };\n}\n\nfunction removeOwnedHooks(\n config: Record<string, unknown>,\n ownership: HookConfigOwnership,\n path: HookPath,\n warnings: string[],\n): void {\n const groups = stopHooks(config, path);\n const remaining: unknown[] = [];\n const matched = new Set<HookEntry>();\n for (const value of groups) {\n const group = asObject(value);\n if (!group || !Array.isArray(group.hooks)) {\n remaining.push(value);\n continue;\n }\n const metadata = groupMetadata(group);\n const hooks = group.hooks.filter((value) => {\n const hook = asObject(value);\n const entry =\n hook && ownership.entries.find((old) => sameEntry(old, { group: metadata, hook }));\n if (entry) matched.add(entry);\n return !entry;\n });\n if (hooks.length > 0 || hooks.length === group.hooks.length) {\n remaining.push({ ...group, hooks });\n }\n }\n if (matched.size < ownership.entries.length) {\n warnings.push(`preserved removed or modified harness Stop hook: ${path}`);\n }\n const hooks = asObject(config.hooks);\n if (!hooks) return;\n if (ownership.addedStop && remaining.length === 0) Reflect.deleteProperty(hooks, \"Stop\");\n else if (Object.hasOwn(hooks, \"Stop\")) hooks.Stop = remaining;\n if (ownership.addedHooks && Object.keys(hooks).length === 0)\n Reflect.deleteProperty(config, \"hooks\");\n else config.hooks = hooks;\n}\n\nfunction recordMutation(\n plan: ConfigMutations,\n path: string,\n before: Record<string, unknown> | undefined,\n after: Record<string, unknown>,\n createdFile: boolean,\n): void {\n if (createdFile && Object.keys(after).length === 0) {\n if (before) plan.removals.push(path);\n } else if (!isDeepStrictEqual(before, after)) {\n plan.writes.push({ path, content: `${JSON.stringify(after, null, 2)}\\n` });\n }\n}\n\nexport function planHookConfigCleanup(\n root: string,\n ownership: HookConfigsOwnership | undefined,\n): ConfigMutations {\n const plan: ConfigMutations = { writes: [], removals: [], warnings: [] };\n if (!ownership) return plan;\n const validated = HookConfigsOwnershipSchema.parse(ownership);\n assertManagedPaths(root, Object.keys(validated));\n for (const path of Object.keys(HOOK_ENGINES) as HookPath[]) {\n const owned = validated[path];\n if (!owned || !existsSync(join(root, path))) continue;\n const before = parseObject(readFileSync(join(root, path), \"utf8\"), path);\n const config = structuredClone(before);\n removeOwnedHooks(config, owned, path, plan.warnings);\n recordMutation(plan, path, before, config, owned.createdFile);\n }\n return plan;\n}\n\nfunction planActiveHook(\n root: string,\n path: HookPath,\n previous: HookConfigOwnership | undefined,\n claimExisting: boolean,\n plan: UpdateConfigPlan,\n): HookConfigOwnership | undefined {\n assertManagedPaths(root, [path]);\n const existed = existsSync(join(root, path));\n if (!existed && previous?.entries.length) {\n plan.warnings.push(`preserved removed harness Stop hook configuration: ${path}`);\n return previous;\n }\n const before = existed ? parseObject(readFileSync(join(root, path), \"utf8\"), path) : undefined;\n const config = structuredClone(before ?? {});\n const groups = stopHooks(config, path);\n const hooks = asObject(config.hooks) ?? {};\n const normalized = normalizeHarnessHooks(\n groups,\n defaultStopGroup(HOOK_ENGINES[path]),\n previous,\n claimExisting,\n plan.warnings,\n path,\n );\n const ownership = {\n createdFile: !existed || previous?.createdFile === true,\n addedHooks: previous?.addedHooks ?? !Object.hasOwn(config, \"hooks\"),\n addedStop: previous?.addedStop ?? !Object.hasOwn(hooks, \"Stop\"),\n entries: normalized.entries,\n };\n if (!isDeepStrictEqual(groups, normalized.groups)) {\n config.hooks = { ...hooks, Stop: normalized.groups };\n }\n recordMutation(plan, path, before, config, ownership.createdFile);\n return ownership.entries.length > 0 ? ownership : undefined;\n}\n\nfunction planLegacyOpenCode(\n root: string,\n previous: UpdateConfigPrevious,\n plan: UpdateConfigPlan,\n): void {\n if (!previous.files.includes(LEGACY_OPENCODE_CONFIG)) return;\n const legacyPath = join(root, LEGACY_OPENCODE_CONFIG);\n if (!existsSync(legacyPath)) return;\n assertManagedPaths(root, [LEGACY_OPENCODE_CONFIG, OPENCODE_CONFIG_PATH]);\n const legacy = parseObject(readFileSync(legacyPath, \"utf8\"), LEGACY_OPENCODE_CONFIG);\n if (!asObject(legacy.mcp)) {\n throw new Error(\n `invalid shared configuration ${LEGACY_OPENCODE_CONFIG}: expected an MCP object`,\n );\n }\n const merged = planOpenCodeConfig(\n root,\n { path: OPENCODE_CONFIG_PATH, content: JSON.stringify(legacy) },\n undefined,\n );\n if (merged.write) plan.writes.push(merged.write);\n plan.warnings.push(...merged.warnings);\n if (merged.ownership) {\n const old = previous.opencodeConfig;\n plan.opencodeConfig = {\n createdFile: merged.ownership.createdFile || old?.createdFile === true,\n addedMcp: merged.ownership.addedMcp || old?.addedMcp === true,\n addedSchema: merged.ownership.addedSchema || old?.addedSchema === true,\n entries: { ...old?.entries, ...merged.ownership.entries },\n };\n }\n plan.removals.push(LEGACY_OPENCODE_CONFIG);\n}\n\n/** Preserve existing MCP settings and plan only shared hook/legacy-layout changes. */\nexport function planUpdateConfigs(\n root: string,\n previous: UpdateConfigPrevious,\n hookEngines: ReadonlyArray<Engine>,\n): UpdateConfigPlan {\n const plan: UpdateConfigPlan = {\n writes: [],\n removals: [],\n ownedFiles: [],\n warnings: [],\n ...(previous.opencodeConfig ? { opencodeConfig: previous.opencodeConfig } : {}),\n };\n planLegacyOpenCode(root, previous, plan);\n const hookConfigs: HookConfigsOwnership = {};\n for (const path of Object.keys(HOOK_ENGINES) as HookPath[]) {\n const owned = previous.hookConfigs?.[path];\n if (hookEngines.includes(HOOK_ENGINES[path])) {\n hookConfigs[path] = planActiveHook(\n root,\n path,\n owned,\n previous.files.includes(path) || Boolean(owned),\n plan,\n );\n } else if (owned) {\n const cleanup = planHookConfigCleanup(root, { [path]: owned });\n plan.writes.push(...cleanup.writes);\n plan.removals.push(...cleanup.removals);\n plan.warnings.push(...cleanup.warnings);\n }\n }\n if (Object.values(hookConfigs).some(Boolean)) plan.hookConfigs = hookConfigs;\n if (hookEngines.includes(\"opencode\")) {\n const plugin = getRenderer(\"opencode\").renderStopHook();\n plan.writes.push(...plugin.files);\n plan.ownedFiles.push(...plugin.files.map((file) => file.path));\n plan.warnings.push(...plugin.warnings);\n }\n return plan;\n}\n","import { existsSync, readdirSync, rmdirSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, relative, resolve } from \"node:path\";\nimport { assertManagedPaths } from \"./managed-paths.js\";\nimport { MANIFEST_FILENAME, manifestPath, readManifest } from \"./manifest.js\";\nimport { OPENCODE_CONFIG_PATH, planOpenCodeConfig } from \"./opencode-config.js\";\nimport { planHookConfigCleanup } from \"./update-config.js\";\n\nexport interface UninstallArgs {\n targetDir: string;\n}\n\nexport interface UninstallResult {\n filesRemoved: string[];\n dirsPruned: string[];\n warnings: string[];\n}\n\nexport function uninstallCommand(args: UninstallArgs): UninstallResult {\n const root = resolve(args.targetDir);\n const warnings: string[] = [];\n assertManagedPaths(root, [MANIFEST_FILENAME]);\n const manifest = readManifest(root);\n if (!manifest) {\n warnings.push(`no manifest found at ${manifestPath(root)} — nothing to uninstall`);\n return { filesRemoved: [], dirsPruned: [], warnings };\n }\n\n assertManagedPaths(root, [\n ...manifest.files,\n ...(manifest.opencodeConfig ? [OPENCODE_CONFIG_PATH] : []),\n ...Object.keys(manifest.hookConfigs ?? {}),\n ]);\n const config = planOpenCodeConfig(root, undefined, manifest.opencodeConfig);\n const hooks = planHookConfigCleanup(root, manifest.hookConfigs);\n const sharedHooks = new Set(Object.keys(manifest.hookConfigs ?? {}));\n const ownedFiles = manifest.files.filter(\n (file) => file !== OPENCODE_CONFIG_PATH && !sharedHooks.has(file),\n );\n if (config.remove) ownedFiles.push(OPENCODE_CONFIG_PATH);\n ownedFiles.push(...hooks.removals);\n const { filesRemoved, dirsPruned, missing } = removeRenderedFiles(root, ownedFiles);\n if (config.write) writeFileSync(join(root, config.write.path), config.write.content);\n for (const file of hooks.writes) writeFileSync(join(root, file.path), file.content);\n warnings.push(...config.warnings, ...hooks.warnings);\n if (manifest.files.includes(OPENCODE_CONFIG_PATH) && !manifest.opencodeConfig) {\n warnings.push(`preserved legacy shared configuration: ${OPENCODE_CONFIG_PATH}`);\n }\n for (const rel of missing) warnings.push(`file in manifest is already missing: ${rel}`);\n\n unlinkSync(manifestPath(root));\n return { filesRemoved, dirsPruned, warnings };\n}\n\nexport function removeRenderedFiles(\n root: string,\n files: ReadonlyArray<string>,\n): { filesRemoved: string[]; dirsPruned: string[]; missing: string[] } {\n assertManagedPaths(root, files);\n const filesRemoved: string[] = [];\n const missing: string[] = [];\n const dirsToConsider = new Set<string>();\n for (const rel of files) {\n const full = join(root, rel);\n if (existsSync(full)) {\n unlinkSync(full);\n filesRemoved.push(rel);\n dirsToConsider.add(dirname(full));\n } else {\n missing.push(rel);\n }\n }\n return { filesRemoved, dirsPruned: pruneEmptyDirs(root, dirsToConsider), missing };\n}\n\nfunction pruneEmptyDirs(root: string, leaves: Set<string>): string[] {\n const candidates = new Set<string>();\n for (const leaf of leaves) {\n let cur = leaf;\n while (cur !== root && cur.startsWith(`${root}/`)) {\n candidates.add(cur);\n cur = dirname(cur);\n }\n }\n const pruned: string[] = [];\n const sorted = [...candidates].sort((a, b) => b.length - a.length);\n for (const dir of sorted) {\n if (!existsSync(dir)) continue;\n if (readdirSync(dir).length > 0) continue;\n rmdirSync(dir);\n pruned.push(relative(root, dir));\n }\n return pruned;\n}\n"],"mappings":"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","names":["existsSync","writeFileSync","dirname","join","resolve","readFileSync","z","z","readFileSync","ENGINE","BASE","ENGINE","BASE","join","existsSync","readFileSync","join","z","existsSync","readFileSync","join","z","existsSync","readFileSync","join","isDeepStrictEqual","z","ObjectSchema","z","z","join","existsSync","readFileSync","existsSync","writeFileSync","dirname","join","resolve","join","existsSync","dirname","dirname","existsSync","join","resolve","writeFileSync"]}
@@ -350,9 +350,10 @@ var frontmatterTracks = {
350
350
  };
351
351
 
352
352
  // src/linters/gitignore-harness.ts
353
- var REQUIRED_ENTRIES = [
353
+ var REQUIRED_GITIGNORE_ENTRIES = [
354
354
  ".harness-overrides/",
355
355
  ".harness-manifest.json",
356
+ ".harness/",
356
357
  ".claude/",
357
358
  ".codex/",
358
359
  ".opencode/",
@@ -381,7 +382,7 @@ var gitignoreHarness = {
381
382
  const lines = new Set(
382
383
  text.split("\n").map((l) => l.trim()).filter(Boolean)
383
384
  );
384
- for (const entry of REQUIRED_ENTRIES) {
385
+ for (const entry of REQUIRED_GITIGNORE_ENTRIES) {
385
386
  const variants = [entry, entry.replace(/\/$/, "")];
386
387
  if (!variants.some((v) => lines.has(v))) {
387
388
  issues.push({