@twin-build-orchestrate/cli 1.0.0-prerelease.1
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/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/cli.js +5609 -0
- package/dist/cli.js.map +1 -0
- package/package.json +45 -0
- package/scripts/orchestrator-status-line.mjs +179 -0
- package/templates/CLAUDE.md +43 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/orchestrator/cli.ts","../../../src/logger.ts","../../../src/usecases/config/load-twin-build-config.ts","../../../src/orchestrator/config.ts","../../../src/orchestrator/detach-log-paths.ts","../../../src/orchestrator/dispatcher.ts","../../../src/orchestrator/http-client.ts","../../../src/orchestrator/backlog-poller.ts","../../../src/orchestrator/backpressure.ts","../../../src/orchestrator/session-supervisor.ts","../../../src/orchestrator/worker-spawner.ts","../../../src/orchestrator/chain-runner.ts","../../../src/orchestrator/chain-runner-eval.ts","../../../src/orchestrator/event-emitter.ts","../../../src/orchestrator/progress-detector.ts","../../../src/orchestrator/worktree.ts","../../../src/orchestrator/gate-watcher-eval.ts","../../../src/orchestrator/gate-watcher.ts","../../../src/orchestrator/merge-gatekeeper.ts","../../../src/orchestrator/merge-policy-eval.ts","../../../src/cli/init.ts","../../../src/cli/lib/cache-base.ts","../../../src/cli/lib/paths.ts","../../../src/cli/lib/settings-json.ts","../../../src/cli/doctor.ts","../../../src/cli/lib/integrity.ts","../../../src/cli/sync.ts","../../../src/cli/lib/merge.ts","../../../src/cli/lib/conflict-prompter.ts","../../../src/cli/lib/upstream-fetcher.ts","../../../src/cli/migrate.ts","../../../src/cli/lib/audit.ts","../../../src/cli/lib/backup.ts","../../../src/cli/lib/migrate-types.ts","../../../src/cli/lib/execute.ts","../../../src/cli/lib/lock.ts","../../../src/cli/lib/migration-path.ts","../../../src/cli/lib/plan.ts","../../../src/usecases/compatibility/schemas.ts"],"sourcesContent":["#!/usr/bin/env node\nimport {\n readFileSync,\n writeFileSync,\n unlinkSync,\n existsSync,\n mkdirSync,\n openSync,\n closeSync,\n} from \"node:fs\";\nimport { spawn } from \"node:child_process\";\nimport { resolve, join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { Command } from \"commander\";\nimport { logger } from \"../logger.js\";\nimport {\n ORCHESTRATOR_CONFIG,\n getPidFilePath,\n logProjectIdFilterStatus,\n} from \"./config.js\";\nimport { buildDetachLogPaths, getDetachLogDir } from \"./detach-log-paths.js\";\nimport { runDispatcher } from \"./dispatcher.js\";\nimport { getOrchestratorClient } from \"./http-client.js\";\nimport { randomUUID } from \"node:crypto\";\nimport { renderInitNextSteps, runInit } from \"../cli/init.js\";\nimport { renderDoctorReport, runDoctor } from \"../cli/doctor.js\";\nimport { runSync } from \"../cli/sync.js\";\nimport { InteractiveConflictPrompter } from \"../cli/lib/conflict-prompter.js\";\nimport { NpmUpstreamFetcher } from \"../cli/lib/upstream-fetcher.js\";\nimport { renderMigrateSummary, runMigrate } from \"../cli/migrate.js\";\nimport {\n pruneBackups,\n rollback,\n BackupNotFoundError,\n PluginVersionMissingError,\n} from \"../cli/lib/backup.js\";\n\n// PID file is project-aware (Stage 5 Theme 2 A 案): TWIN_BUILD_PROJECT_ID set 時は\n// .orchestrator-<short-id>.pid、未設定時は .orchestrator.pid (back-compat)。\nconst PID_FILE = resolve(process.cwd(), getPidFilePath());\n\n\n// ──────────────────────────────────────────────\n// PID file utilities\n// ──────────────────────────────────────────────\n\nfunction readPid(): number | null {\n if (!existsSync(PID_FILE)) return null;\n const content = readFileSync(PID_FILE, \"utf-8\").trim();\n const pid = parseInt(content, 10);\n return isNaN(pid) ? null : pid;\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Write PID file, using O_EXCL semantics via try/catch on existence check. */\nfunction writePid(): void {\n if (existsSync(PID_FILE)) {\n const existingPid = readPid();\n if (existingPid !== null && isProcessAlive(existingPid)) {\n logger.error(\n { existingPid, pidFile: PID_FILE },\n \"Another dispatcher is already running\",\n );\n console.error(\n `Error: Another dispatcher is already running (PID ${existingPid}).`,\n );\n console.error(\n \"Run 'twin-build-orchestrate stop' first, or delete the PID file:\",\n );\n console.error(` rm ${PID_FILE}`);\n process.exit(1);\n }\n // Stale PID file — remove it\n unlinkSync(PID_FILE);\n }\n writeFileSync(PID_FILE, String(process.pid), \"utf-8\");\n}\n\nfunction removePid(): void {\n try {\n if (existsSync(PID_FILE)) unlinkSync(PID_FILE);\n } catch {\n // Ignore cleanup errors\n }\n}\n\n// ──────────────────────────────────────────────\n// CLI\n// ──────────────────────────────────────────────\n\nconst program = new Command();\n\n// Detect bin name (twin-build vs twin-build-orchestrate) for help output.\nconst invokedAs = (process.argv[1] ?? \"\").split(/[/\\\\]/).pop() ?? \"\";\nconst isShortBin = invokedAs === \"twin-build\";\n\nprogram\n .name(isShortBin ? \"twin-build\" : \"twin-build-orchestrate\")\n .description(\n isShortBin\n ? \"twin-build framework CLI (init / sync / doctor + orchestrator daemon)\"\n : \"Local Orchestrator — dispatcher CLI (Stage 2 MVP)\",\n )\n .version(\"1.0.0-prerelease.1\");\n\n// ── start ──\nprogram\n .command(\"start\")\n .description(\"Start the dispatcher\")\n .option(\"--foreground\", \"Run in foreground (default)\", true)\n .option(\"--detach\", \"Run as background daemon (detached from terminal)\")\n .action(async (options) => {\n if (options.detach) {\n const scriptPath = process.argv[1];\n // Ticket 38835f74: redirect detached dispatcher's stdout/stderr to log\n // files instead of /dev/null. Without this, pino (configured to write to\n // fd=1) silently discards all logs, leaving no way to diagnose crashes /\n // hangs / persistent halts. v0.x had this behavior; v1.0 regressed to\n // `stdio: \"ignore\"`. We open the files in the parent so any open error\n // surfaces here (not in the orphaned child), then close our FDs after\n // spawn so only the child holds them.\n const { outPath, errPath } = buildDetachLogPaths();\n mkdirSync(getDetachLogDir(), { recursive: true });\n const outFd = openSync(outPath, \"a\");\n const errFd = openSync(errPath, \"a\");\n const child = spawn(process.execPath, [scriptPath, \"start\"], {\n detached: true,\n stdio: [\"ignore\", outFd, errFd],\n env: { ...process.env },\n });\n child.unref();\n closeSync(outFd);\n closeSync(errFd);\n console.log(\"Dispatcher starting in background...\");\n console.log(`PID file: ${PID_FILE}`);\n console.log(`Log files: ${outPath} / ${errPath}`);\n console.log(\"Run 'twin-build-orchestrate status' to check.\");\n process.exit(0);\n return;\n }\n\n writePid();\n\n // PID file cleanup on any exit (normal or abnormal).\n // SIGTERM/SIGINT are handled inside runDispatcher, which sets a shutdown\n // flag and exits the poll loop gracefully. Do NOT call process.exit here —\n // that would bypass the graceful shutdown.\n process.on(\"exit\", removePid);\n process.on(\"unhandledRejection\", (reason) => {\n logger.error({ reason }, \"dispatcher: unhandled rejection\");\n });\n\n console.log(`Dispatcher starting (PID ${process.pid})...`);\n console.log(`Poll interval: ${ORCHESTRATOR_CONFIG.pollIntervalMs / 1000}s`);\n console.log(\"Press Ctrl-C to stop.\");\n\n // G-R5-3 (review fix): 起動時 1 回だけ TWIN_BUILD_PROJECT_ID 設定状態を warn。\n // cycle 内で warn を出すと dispatcher 常駐運用で 10s 毎に積み上がるため。\n logProjectIdFilterStatus(logger);\n\n try {\n await runDispatcher();\n } finally {\n removePid();\n }\n });\n\n// ── stop ──\nprogram\n .command(\"stop\")\n .description(\"Stop a running dispatcher\")\n .action(() => {\n const pid = readPid();\n if (pid === null) {\n console.log(\"No dispatcher is running (PID file not found).\");\n process.exit(0);\n }\n if (!isProcessAlive(pid)) {\n console.log(`Stale PID file found (PID ${pid} is not running). Cleaning up.`);\n removePid();\n process.exit(0);\n }\n process.kill(pid, \"SIGTERM\");\n console.log(`Sent SIGTERM to dispatcher (PID ${pid}).`);\n });\n\n// ── status ──\nprogram\n .command(\"status\")\n .description(\"Show dispatcher and worker session status\")\n .action(async () => {\n const pid = readPid();\n\n if (pid === null || !isProcessAlive(pid)) {\n console.log(\"Dispatcher: NOT RUNNING\");\n if (pid !== null) {\n console.log(` Stale PID file (${PID_FILE}) — run 'stop' to clean up.`);\n }\n } else {\n console.log(`Dispatcher: RUNNING (PID ${pid})`);\n }\n\n // Show running sessions via HTTP (best-effort)\n try {\n const sessions = await getOrchestratorClient().listRunningSessions();\n\n if (sessions.length === 0) {\n console.log(\"Workers: none running\");\n } else {\n console.log(`Workers: ${sessions.length} running`);\n for (const s of sessions) {\n console.log(\n ` [${s.scope}] session=${s.id.slice(0, 8)} pid=${s.workerPid ?? \"?\"} started=${String(s.startedAt)}`,\n );\n }\n }\n } catch (err) {\n console.error(\" (could not query worker sessions:\", err instanceof Error ? err.message : String(err), \")\");\n }\n\n process.exit(0);\n });\n\n// ── init ──\nprogram\n .command(\"init\")\n .description(\"Initialize twin-build in this project\")\n .option(\"--name <name>\", \"project name (default: basename of cwd)\")\n .option(\"--plugin-version <version>\", \"pin Plugin version\", \"0.1.0-prerelease.1\")\n .option(\"--cli-version <version>\", \"pin CLI version\", \"1.0.0-prerelease.1\")\n .option(\"--rules-schema-version <version>\", \"pin rules schema version\", \"1.0.0\")\n .option(\"--mcp-tool-schema-version <version>\", \"pin MCP tool schema version\")\n .option(\"--link-strategy <strategy>\", \"symlink | copy (default: auto)\")\n .option(\"--marketplace-path <path>\", \"absolute path of marketplace clone (for extraKnownMarketplaces)\")\n .option(\"--dry-run\", \"print what would be written without touching files\")\n .action(async (options) => {\n try {\n const result = await runInit({\n repoRoot: process.cwd(),\n projectName: options.name,\n pluginVersion: options.pluginVersion,\n cliVersion: options.cliVersion,\n rulesSchemaVersion: options.rulesSchemaVersion,\n mcpToolSchemaVersion: options.mcpToolSchemaVersion,\n linkStrategy: options.linkStrategy,\n marketplacePath: options.marketplacePath,\n dryRun: Boolean(options.dryRun),\n });\n console.log(renderInitNextSteps(result));\n } catch (err) {\n console.error(\n err instanceof Error ? err.message : String(err),\n );\n process.exit(1);\n }\n });\n\n// ── sync ──\nprogram\n .command(\"sync\")\n .description(\"Pull upstream changes via 3-way merge\")\n .argument(\"[version]\", \"target version (default: latest of @twin-build-orchestrate/cli)\")\n .option(\"--axis <axis>\", \"plugin | cli | rulesSchema\", \"cli\")\n .option(\"--dry-run\", \"do not write files; print plan only\")\n .option(\"--yes-all\", \"non-interactive: accept upstream on conflict\")\n .option(\"--keep-ours-on-conflict\", \"non-interactive: keep ours on conflict\")\n .option(\"--strategy <strategy>\", \"ours | theirs (alias of the flags above)\")\n .option(\"--skip-claude-md\", \"skip CLAUDE.md (after F9 halt for retry)\")\n .action(async (versionArg, options) => {\n const version: string = versionArg ?? \"latest\";\n const agentMode = Boolean(process.env.TWIN_BUILD_AGENT_MODE);\n try {\n const fetcher = new NpmUpstreamFetcher({ repoRoot: process.cwd() });\n const result = await runSync({\n repoRoot: process.cwd(),\n toVersion: version,\n axis: options.axis,\n fetcher,\n prompter: agentMode ? undefined : new InteractiveConflictPrompter(),\n yesAll: Boolean(options.yesAll),\n keepOurs: Boolean(options.keepOursOnConflict),\n strategyTheirs: options.strategy === \"theirs\",\n dryRun: Boolean(options.dryRun),\n skipClaudeMd: Boolean(options.skipClaudeMd),\n agentMode,\n });\n for (const f of result.files) {\n const tag =\n f.status === \"clean-merged\"\n ? \"✓\"\n : f.status === \"conflict-resolved\"\n ? \"△\"\n : f.status === \"conflict-halt\"\n ? \"✗\"\n : f.status === \"skipped\"\n ? \"·\"\n : \"=\";\n console.log(` ${tag} ${f.relPath} (${f.status})`);\n }\n if (result.halted) {\n console.error(`\\nHalted: ${result.haltReason ?? \"(unknown)\"}`);\n process.exit(2);\n }\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ── doctor ──\nprogram\n .command(\"doctor\")\n .description(\"Check twin-build installation for drift / integrity issues\")\n .option(\"--fix\", \"apply automatic fixes\")\n .option(\"--diagnose\", \"include extra detail for each issue\")\n .action(async (options) => {\n try {\n const result = await runDoctor({\n repoRoot: process.cwd(),\n fix: Boolean(options.fix),\n diagnose: Boolean(options.diagnose),\n });\n console.log(renderDoctorReport(result));\n process.exit(result.passed ? 0 : 1);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ── migrate ──\nprogram\n .command(\"migrate\")\n .description(\"Migrate project layout to a new twin-build version (7-phase flow)\")\n .argument(\"[version]\", \"target CLI/Plugin version\", \"latest\")\n .option(\"--to <version>\", \"target version (alias of positional argument)\")\n .option(\"--dry-run\", \"stop after Phase 2 Plan; print plan but make no changes\")\n .option(\"--skip-claude-md\", \"skip CLAUDE.md merge (F9 retry)\")\n .option(\"--yes-all\", \"non-interactive: auto-confirm Phase 3 execute\")\n .option(\"--branch <name>\", \"branch name for migrate commits\", \"chore/twin-build-migrate\")\n .action(async (versionArg, options) => {\n const toVersion: string = options.to ?? versionArg ?? \"latest\";\n const agentMode = Boolean(process.env.TWIN_BUILD_AGENT_MODE);\n try {\n const fetcher = new NpmUpstreamFetcher({ repoRoot: process.cwd() });\n const result = await runMigrate(\n {\n repoRoot: process.cwd(),\n toVersion,\n dryRun: Boolean(options.dryRun),\n skipClaudeMd: Boolean(options.skipClaudeMd),\n yesAll: Boolean(options.yesAll),\n agentMode,\n branchName: options.branch,\n },\n { fetcher },\n );\n console.log(renderMigrateSummary(result));\n if (result.halted) process.exit(2);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ── migrate rollback ──\nconst migrateRollback = program\n .command(\"migrate-rollback\")\n .alias(\"rollback\")\n .description(\"Restore the project state from a migration backup\")\n .option(\"--to <timestamp>\", \"specific backup timestamp (default: latest)\")\n .action(async (options) => {\n const agentMode = Boolean(process.env.TWIN_BUILD_AGENT_MODE);\n try {\n const result = rollback({\n repoRoot: process.cwd(),\n toTimestamp: options.to,\n agentMode,\n });\n console.log(`✓ restored ${result.filesRestored.length} files from ${result.restoredFrom}`);\n for (const w of result.warnings) console.warn(` ⚠ ${w}`);\n } catch (err) {\n if (err instanceof BackupNotFoundError) {\n console.error(err.message);\n process.exit(2);\n }\n if (err instanceof PluginVersionMissingError) {\n console.error(err.message);\n process.exit(3);\n }\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\nvoid migrateRollback;\n\n// ── migrate prune-backups ──\nprogram\n .command(\"migrate-prune-backups\")\n .alias(\"prune-backups\")\n .description(\"Delete migration backups older than --max-age-days (default 30)\")\n .option(\"--max-age-days <days>\", \"max age in days\", (v) => parseInt(v, 10), 30)\n .action(async (options) => {\n try {\n const result = pruneBackups({\n repoRoot: process.cwd(),\n maxAgeDays: options.maxAgeDays,\n });\n console.log(\n `pruned ${result.removed.length} backup(s), kept ${result.kept.length}`,\n );\n for (const slug of result.removed) console.log(` - removed ${slug}`);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\nprogram.parseAsync(process.argv).catch((err) => {\n logger.error({ err }, \"cli: fatal error\");\n process.exit(1);\n});\n","import pino from \"pino\";\n\nconst isProduction = process.env.NODE_ENV === \"production\";\n\nexport const logger = pino({\n level: process.env.LOG_LEVEL ?? (isProduction ? \"info\" : \"debug\"),\n ...(isProduction\n ? {}\n : {\n transport: {\n target: \"pino/file\",\n options: { destination: 1 },\n },\n formatters: {\n level: (label: string) => ({ level: label }),\n },\n }),\n});\n","import { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/**\n * `.twin-build.json` の型定義 (LCD 関連のみを記述)\n *\n * 参照: docs/design/legacy-code-deletion-design.md §5.4\n * 閾値の初期値: \"全数のみ\" で安全側に倒す\n */\nexport interface TwinBuildConfig {\n /** orchestrator の接続設定。env var の fallback として使用 (secret は env var のみ) */\n orchestrator?: {\n /** TWIN_BUILD_SERVER_URL の fallback。MCP server の URL */\n serverUrl?: string;\n /** TWIN_BUILD_PROJECT_ID の fallback */\n projectId?: string;\n };\n deadCode?: {\n escalation?: {\n /** \"all\" = 1 file 内の全 symbol が unused のときだけ file 粒度に格上げ。\n * 将来は \"0.8\" 等の比率指定をサポートする可能性があるため string union。 */\n fileThreshold?: \"all\" | string;\n };\n };\n}\n\n/**\n * リポジトリルートの `.twin-build.json` を読み出す小さな helper。\n *\n * - ファイル不在 → `null` (throw しない)\n * - JSON parse 失敗 → warning ログを残して `null` を返す\n * (設計書は「閾値の初期値 = 全数のみ」と決めているため、\n * config 読み取り失敗は安全側に倒す = 既定値で動かす)\n */\nexport function loadTwinBuildConfig(repoRoot: string): TwinBuildConfig | null {\n const path = join(repoRoot, \".twin-build.json\");\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch {\n // ENOENT 等。設定ファイル不在は正常系。\n return null;\n }\n\n try {\n return JSON.parse(raw) as TwinBuildConfig;\n } catch (e) {\n console.warn(`[load-twin-build-config] JSON parse failed: ${path}: ${e}`);\n return null;\n }\n}\n","import { loadTwinBuildConfig } from \"../usecases/config/load-twin-build-config.js\";\n\n// Orchestrator configuration constants (DEC-LO-12)\nexport const ORCHESTRATOR_CONFIG = {\n // Poll interval in milliseconds (10s)\n pollIntervalMs: 10_000,\n\n // Max concurrent workers by scope (DEC-LO-12)\n maxConcurrent: {\n app: 3,\n framework: 1,\n \"serial-app\": 1,\n } as Record<string, number>,\n\n // Global concurrency cap across all scopes\n globalConcurrencyCap: 5,\n\n // Zombie detection: worker with no heartbeat for this many minutes\n heartbeatTimeoutMinutes: 60,\n\n // Graceful shutdown: wait up to this many seconds for workers to finish\n gracefulShutdownTimeoutMs: 60_000,\n\n // Poll error backoff: exponential, ms\n pollBackoff: {\n initialMs: 5_000,\n maxMs: 60_000,\n multiplier: 2,\n },\n\n // PID file path (project root)\n pidFilePath: \".orchestrator.pid\",\n\n // Log directory\n logDir: \"logs\",\n} as const;\n\nexport type OrchestratorScope = \"app\" | \"framework\" | \"serial-app\";\n\n/**\n * Dispatcher を bind する project_id (G-R5-3 fix, Round 9 dogfood discovery)。\n *\n * Local Orchestrator MVP は 1 Mac / 1 project の前提だが、prod DB は複数\n * プロジェクトの backlog / ticket_tracker / PR を持つ。filter なしの query は\n * 別プロジェクトの PR にラベル変更を試行する副作用を起こす (Round 5 dogfood で\n * 観測、別プロジェクトの GitHub に意図しない gh pr edit が走った)。\n *\n * `TWIN_BUILD_PROJECT_ID` 環境変数で設定する。未設定の場合は null を返し、呼び\n * 出し側は warn ログ + filter なし (legacy 動作) で続行する。本番運用では必ず\n * set すべき。\n */\nexport function getProjectIdFilter(): string | null {\n const envId = process.env.TWIN_BUILD_PROJECT_ID;\n if (envId && envId.trim().length > 0) return envId.trim();\n return loadTwinBuildConfig(process.cwd())?.orchestrator?.projectId ?? null;\n}\n\n/**\n * Stage 5 Theme 2 (A 案): 複数プロジェクトを 1 台で並列 dispatch するための\n * project-isolated PID file path。`TWIN_BUILD_PROJECT_ID` set 時は UUID の\n * 先頭 8 文字を suffix にして `.orchestrator-<suffix>.pid` を返す。未設定時は\n * 既存の `.orchestrator.pid` (back-compat)。\n *\n * 例: TWIN_BUILD_PROJECT_ID=21ffb8a1-... → \".orchestrator-21ffb8a1.pid\"\n *\n * 短縮 ID で衝突するケースは現実には非常にまれ (同じ Mac で 2 億分の 1)。\n * 衝突した場合は dispatcher 起動時に \"already running\" 検知される (PID 一致確認)。\n */\nexport function getPidFilePath(): string {\n const id = getProjectIdFilter();\n if (!id) return ORCHESTRATOR_CONFIG.pidFilePath;\n const suffix = id.slice(0, 8);\n return `.orchestrator-${suffix}.pid`;\n}\n\n/**\n * 起動時 1 回のみ TWIN_BUILD_PROJECT_ID 設定状態を log に出す (review fix)。\n *\n * cycle 内で warn を出すと dispatcher 常駐運用で 10 秒毎に警告が積み上がり\n * (1 時間で 360 件)、本来重要なシグナルが埋もれる。dispatcher 起動時\n * (cli.ts) で 1 回だけ呼び出す。\n */\nexport function logProjectIdFilterStatus(\n log: { warn: (obj: object, msg: string) => void },\n): void {\n const id = getProjectIdFilter();\n if (!id) {\n log.warn(\n {},\n \"TWIN_BUILD_PROJECT_ID env not set — querying all projects (legacy behavior). Set the env var to scope dispatcher to a single project.\",\n );\n }\n}\n","/**\n * Detach log path resolver (ticket 38835f74).\n *\n * `twin-build-orchestrate start --detach` で daemon を起動する際、stdout/stderr を\n * redirect する file の path を組み立てる。v1.0 リファクタで `stdio: \"ignore\"` に\n * 退化して log が完全消失していたバグへの対応。\n *\n * cli.ts は import 時に commander の `program.parseAsync` を実行する副作用を持つため、\n * unit test 可能な純粋関数として本 module に切り出す。\n */\n\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { getProjectIdFilter } from \"./config.js\";\n\n/**\n * `~/.twin-build/logs/dispatcher{-<short>}.{out,err}.log` の path を返す。\n *\n * - projectId が `getProjectIdFilter()` で取得できれば short id (先頭 8 chars) を\n * ファイル名 suffix にして複数 dispatcher の log を分離。\n * - 未設定なら legacy 形式 (`dispatcher.{out,err}.log`)。\n *\n * 本関数は path 文字列だけを返し、ディレクトリ作成や fd open は呼び出し側の責務。\n */\nexport function buildDetachLogPaths(): { outPath: string; errPath: string } {\n const logDir = join(homedir(), \".twin-build\", \"logs\");\n const id = getProjectIdFilter();\n const suffix = id ? `-${id.slice(0, 8)}` : \"\";\n return {\n outPath: join(logDir, `dispatcher${suffix}.out.log`),\n errPath: join(logDir, `dispatcher${suffix}.err.log`),\n };\n}\n\n/**\n * Log directory の絶対 path を返す。`mkdirSync(..., { recursive: true })` の引数用。\n */\nexport function getDetachLogDir(): string {\n return join(homedir(), \".twin-build\", \"logs\");\n}\n","import { randomUUID } from \"node:crypto\";\nimport { logger } from \"../logger.js\";\nimport { getOrchestratorClient } from \"./http-client.js\";\nimport { ORCHESTRATOR_CONFIG } from \"./config.js\";\nimport { getProjectIdFilter } from \"./config.js\";\nimport {\n countOpenGatesByProject,\n countRunningTasksByScope,\n markTaskHalted,\n pollAndReserveReadyTasks,\n requeueTasks,\n setTaskSession,\n} from \"./backlog-poller.js\";\nimport {\n diffPauseState,\n evaluatePauseDecisions,\n type PauseDecision,\n} from \"./backpressure.js\";\nimport {\n cleanupInFlightSessions,\n detectAndMarkZombies,\n detectStaleTrackerWriteRace,\n} from \"./session-supervisor.js\";\nimport {\n computeBranchAndPath,\n spawnWorker,\n sweepStaleWorktrees,\n WorkerSetupError,\n} from \"./worker-spawner.js\";\nimport { applyGateWatcher } from \"./gate-watcher.js\";\nimport { applyMergeGatekeeper } from \"./merge-gatekeeper.js\";\nimport { cleanupOrphans, emitCompletionEvent } from \"./event-emitter.js\";\nimport { existsSync, readdirSync, statSync } from \"node:fs\";\nimport { removeWorktree as realRemoveWorktree } from \"./worktree.js\";\n\nexport type DispatcherOptions = {\n /** Override poll interval for testing */\n pollIntervalMs?: number;\n};\n\n/**\n * Main dispatcher loop.\n * Polls backlog for agent-ready tasks, spawns workers, supervises sessions.\n *\n * Stage 2 MVP: foreground only, detached=false, dummy workers (sleep 1).\n * Stage 3+: real claude CLI workers with worktree setup.\n */\nexport async function runDispatcher(opts: DispatcherOptions = {}): Promise<void> {\n const instanceId = randomUUID();\n const pollIntervalMs = opts.pollIntervalMs ?? ORCHESTRATOR_CONFIG.pollIntervalMs;\n\n logger.info({ instanceId, pollIntervalMs }, \"dispatcher: starting\");\n\n // 起動時に過去 test 漏れの orphan event file を best-effort で掃除する。\n // (event-emitter.ts: TWIN_BUILD_EVENTS_DIR override + VITEST guard で再発は防止)\n const cleanedOrphans = cleanupOrphans();\n if (cleanedOrphans > 0) {\n logger.info({ cleanedOrphans }, \"dispatcher: cleaned up orphan event files\");\n }\n\n // Layer 1b (本 PR): 起動時に stale worktrees を sweep する。1h 以上 mtime が\n // 古いディレクトリは前 dispatcher / 異常終了の遺物と見做して除去。観測例:\n // 11 日放置の `worktrees/b2e0ea4f-*` が再 dispatch の `linkClaudeAssets` を\n // 構造的に阻害していたパターン (2026-05-19 報告)。\n try {\n const removed = await sweepStaleWorktrees(process.cwd(), {\n fs: { existsSync, readdirSync, statSync },\n removeWorktree: realRemoveWorktree,\n now: () => new Date(),\n });\n if (removed.length > 0) {\n logger.info(\n { removed, count: removed.length },\n \"dispatcher: swept stale worktrees on startup (Layer 1b)\",\n );\n }\n } catch (err) {\n logger.error(\n { err },\n \"dispatcher: stale worktree sweep failed on startup (continuing)\",\n );\n }\n\n let shuttingDown = false;\n let currentBackoffMs: number = ORCHESTRATOR_CONFIG.pollBackoff.initialMs;\n let gateWatcherLastCheckAt: Date | null = null;\n\n // DEC-LO-04: in-memory backpressure state. Multi-instance is not currently\n // a goal (single-process assumption); each dispatcher tracks its own\n // pausedSet. `isInitial` suppresses spurious resume events on startup.\n let pausedProjects: ReadonlySet<string> = new Set();\n let isInitial = true;\n\n // DEC-126 (GATE-038): in-flight worker promise tracking for fire-and-forget\n // dispatch. Set membership is mutated only by spawn (.add) and promise\n // finally (.delete); concurrent reads from `inFlight.size` are safe under\n // Node's single-threaded execution model. graceful shutdown (line 192) awaits\n // these promises so SIGTERM does not orphan in-flight chain runs.\n const inFlight = new Set<Promise<unknown>>();\n\n // Spawn a worker for a task as fire-and-forget. Internal try/catch ensures\n // requeue (transient) or halt (persistent) on failure and avoids unhandled\n // promise rejection. Caller wraps the returned promise with `inFlight.add`\n // and a `.finally` cleanup.\n //\n // Persistent halt path (WorkerSetupError category='persistent'):\n // - Stops the infinite retry loop on permanent setup errors (e.g. EEXIST\n // symlink conflicts, missing settings template, write-protected worktree)\n // - Marks backlog_items.status='failed' and ticket_tracker.orchestratorState='failed'\n // so the task is excluded from poll WHERE status='todo'\n // - Emits 'agent_halt' event with a recommendedAction so operator gets a\n // statusLine notification and a recovery hint\n // - Does NOT requeue (operator must fix the underlying issue and reset status)\n const spawnAndTrack = async (\n task: Awaited<ReturnType<typeof pollAndReserveReadyTasks>>[number],\n dispatcherInstanceId: string,\n ): Promise<void> => {\n const projectRoot = process.cwd();\n const { worktreePath } = computeBranchAndPath(task, projectRoot);\n let succeeded = false;\n try {\n const result = await spawnWorker(task, dispatcherInstanceId);\n await setTaskSession(task.id, result.sessionId);\n succeeded = true;\n } catch (spawnErr) {\n const isPersistent =\n spawnErr instanceof WorkerSetupError && spawnErr.category === \"persistent\";\n if (isPersistent) {\n const reason = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);\n logger.error(\n { err: spawnErr, taskId: task.id, ticketId: task.ticketId },\n \"dispatcher: spawn failed (persistent) — halting task, no requeue\",\n );\n try {\n await markTaskHalted(task.id, reason);\n } catch (haltErr) {\n // Distinguish 404 (server lacks /halt-task — twin-build-server < 0.5.1)\n // from other failures so operators see a precise upgrade instruction\n // instead of a generic transient error.\n const haltMsg = haltErr instanceof Error ? haltErr.message : String(haltErr);\n if (/→ 404/.test(haltMsg)) {\n logger.warn(\n { err: haltErr, taskId: task.id },\n \"dispatcher: /halt-task endpoint missing on server (requires twin-build-server >= 0.5.1) — task left in 'in_progress'; manual intervention required\",\n );\n } else {\n logger.error(\n { err: haltErr, taskId: task.id },\n \"dispatcher: markTaskHalted failed (task may remain in-progress)\",\n );\n }\n }\n try {\n // Note: unlike chain-runner's agent_halt (emitted mid-phase with\n // `phase` and `haltReason` from HALT_REASON.md), this variant\n // originates from the worker setup stage before any phase begins,\n // so phase / haltReason fields are intentionally omitted.\n emitCompletionEvent({\n type: \"agent_halt\",\n ticketId: task.ticketId,\n projectId: task.projectId,\n at: new Date().toISOString(),\n dispatcherInstanceId,\n message: `worker setup failed (persistent): ${reason}`,\n recommendedAction:\n \"See the halt 'message' for cause-specific recovery steps. \" +\n \"General recipe: (1) fix the underlying worktree issue (e.g. `rm -rf` conflicting files in .claude/), \" +\n \"(2) flip backlog status back to 'todo' (`manage_backlog action=update id=<ticketId> changes.status=todo`), \" +\n \"(3) re-run `dispatch_to_agent`.\",\n });\n } catch (emitErr) {\n logger.error(\n { err: emitErr, taskId: task.id },\n \"dispatcher: agent_halt event emit failed\",\n );\n }\n return;\n }\n // Transient error — requeue and let the next poll cycle retry.\n logger.error(\n { err: spawnErr, taskId: task.id },\n \"dispatcher: spawn failed (transient), requeueing task\",\n );\n try {\n await requeueTasks([task.id]);\n } catch (requeueErr) {\n logger.error(\n { err: requeueErr, taskId: task.id },\n \"dispatcher: requeue failed after spawn fail (task may be stuck in-progress)\",\n );\n }\n } finally {\n // Layer 1a (本 PR): worker 終了 hook で worktree を即時除去する。\n // success → 常に除去\n // failure → DEBUG_KEEP_FAILED_WORKTREES=1 set 時は debug のため保持、それ以外は除去\n // `git worktree remove --force` は path 不在 / locked などで稀に失敗するが、その場合は\n // warn ログのみで dispatcher loop は継続させる (best-effort cleanup)。\n const keepForDebug =\n !succeeded && process.env.DEBUG_KEEP_FAILED_WORKTREES === \"1\";\n if (!keepForDebug) {\n try {\n await realRemoveWorktree({\n worktreePath,\n force: true,\n cwd: projectRoot,\n });\n } catch (removeErr) {\n logger.warn(\n {\n err: removeErr instanceof Error ? removeErr.message : String(removeErr),\n worktreePath,\n taskId: task.id,\n succeeded,\n },\n \"dispatcher: worktree remove on completion failed (best-effort, continuing)\",\n );\n }\n } else {\n logger.info(\n { worktreePath, taskId: task.id },\n \"dispatcher: retaining failed worktree (DEBUG_KEEP_FAILED_WORKTREES=1)\",\n );\n }\n }\n };\n\n const shutdown = () => {\n if (shuttingDown) return;\n shuttingDown = true;\n logger.info({ instanceId }, \"dispatcher: shutdown signal received\");\n };\n\n process.on(\"SIGTERM\", shutdown);\n process.on(\"SIGINT\", shutdown);\n\n // Startup: detect zombie sessions from previous dispatcher run\n try {\n const zombies = await detectAndMarkZombies(instanceId);\n if (zombies.length > 0) {\n logger.warn(\n { count: zombies.length },\n \"dispatcher: zombie sessions found on startup\",\n );\n }\n } catch (err) {\n logger.error({ err }, \"dispatcher: zombie scan on startup failed (continuing)\");\n }\n\n // Startup: detect Round 21 Meta-finding pattern (chain-runner / worker-spawner\n // tracker write race — pr phase completed success but tracker.pr_url null).\n // Read-only — operators must inspect and decide manual merge / backlog flip.\n try {\n const staleRows = await detectStaleTrackerWriteRace();\n if (staleRows.length > 0) {\n logger.warn(\n {\n count: staleRows.length,\n rows: staleRows.slice(0, 5),\n },\n \"dispatcher: tracker write race detected (Round 21 Meta-finding pattern) — manual review required\",\n );\n }\n } catch (err) {\n logger.error(\n { err },\n \"dispatcher: stale tracker write race scan failed (continuing)\",\n );\n }\n\n while (!shuttingDown) {\n try {\n // Zombie supervision\n await detectAndMarkZombies(instanceId);\n\n // Gate watcher: Gate 決定で blocked backlog を ready 化 (DEC-103, B案)\n gateWatcherLastCheckAt = await applyGateWatcher(gateWatcherLastCheckAt);\n\n // DEC-LO-04: backpressure pre-check. Compute pausedSet, emit transition\n // events (warn for new pause / info for resume), and exclude paused\n // projects from the next poll. Failures are logged but do not block\n // dispatch (the poll still runs with the prior pausedSet).\n pausedProjects = await applyBackpressure(pausedProjects, isInitial);\n isInitial = false;\n\n // Determine capacity\n // Ticket 0b88d925: scope the count to this dispatcher's project so other\n // projects sharing the same API key do not saturate our cap. `1 dispatcher\n // = 1 project` (DEC-LO-12) makes per-project semantics the correct default.\n // Legacy account-wide fallback when no projectIdFilter is configured\n // (logged once at boot via logProjectIdFilterStatus).\n const runningByScope = await countRunningTasksByScope(getProjectIdFilter());\n const totalRunning = Object.values(runningByScope).reduce((a, b) => a + b, 0);\n\n const availableGlobal = ORCHESTRATOR_CONFIG.globalConcurrencyCap - totalRunning;\n if (availableGlobal <= 0) {\n logger.debug({ totalRunning }, \"dispatcher: global cap reached, skipping poll\");\n await sleep(pollIntervalMs);\n continue;\n }\n\n // DEC-127 (Round 14 follow-up): fetch limit = sum of per-scope free\n // slots, capped at availableGlobal. Previously we computed\n // `min(availableGlobal, max - running across all scopes)` which gave\n // the SMALLEST scope's free slot — for the default config (app=3,\n // framework=1, serial-app=1) this floored fetchLimit at 1 even when\n // app had 3 slots free. As a result Round 14 PROD observed\n // \"tasks reserved count:1\" per cycle despite ample app capacity.\n //\n // The per-task scope cap check below (line ~152) requeues tasks for\n // scopes that are over their cap, so over-fetching for one scope is\n // safe — at worst we waste a SKIP LOCKED row and a requeue.\n let totalScopeAvailable = 0;\n for (const [scope, max] of Object.entries(ORCHESTRATOR_CONFIG.maxConcurrent)) {\n const running = runningByScope[scope] ?? 0;\n totalScopeAvailable += Math.max(0, max - running);\n }\n const fetchLimit = Math.min(availableGlobal, totalScopeAvailable);\n logger.debug(\n { fetchLimit, availableGlobal, totalScopeAvailable, runningByScope },\n \"dispatcher: capacity computed\",\n );\n if (fetchLimit === 0) {\n logger.debug({ runningByScope }, \"dispatcher: all scope caps reached, skipping poll\");\n await sleep(pollIntervalMs);\n continue;\n }\n\n // Atomically poll + reserve (marks status='in_progress' in a single TX)\n const tasks = await pollAndReserveReadyTasks(\n fetchLimit,\n Array.from(pausedProjects),\n );\n\n if (tasks.length > 0) {\n const toRequeue: string[] = [];\n let dispatchedCount = 0;\n\n for (const task of tasks) {\n // Per-scope cap check (after reservation — if over, re-queue)\n const scopeMax = ORCHESTRATOR_CONFIG.maxConcurrent[task.scope] ?? ORCHESTRATOR_CONFIG.maxConcurrent[\"app\"];\n const scopeRunning = runningByScope[task.scope] ?? 0;\n if (scopeRunning >= scopeMax) {\n logger.debug(\n { scope: task.scope, scopeRunning, scopeMax },\n \"dispatcher: scope cap reached, requeueing reserved task\",\n );\n toRequeue.push(task.id);\n continue;\n }\n\n // DEC-126 (A 案、GATE-038): fire-and-forget で spawn を起動し inFlight Set\n // で追跡する。chain 完走を await しないため、同 cycle 内で 3 task 同時 spawn が\n // 可能になる (DEC-LO-28 Stage 3 の前提)。promise の lifecycle:\n // - 成功 → setTaskSession で worker_session ID を backlog に紐付け\n // - 失敗 → requeueTasks で再 pickup 可能化\n // - finally → inFlight Set から削除 (graceful shutdown 用 tracking)\n // runningByScope は cycle ローカルなので増分のみ実施。次 cycle 冒頭で\n // countRunningTasksByScope() が DB から再取得するので減分は不要。\n runningByScope[task.scope] = (runningByScope[task.scope] ?? 0) + 1;\n dispatchedCount++;\n\n const taskPromise = spawnAndTrack(task, instanceId);\n inFlight.add(taskPromise);\n taskPromise.finally(() => {\n inFlight.delete(taskPromise);\n });\n }\n\n if (toRequeue.length > 0) {\n await requeueTasks(toRequeue);\n }\n if (dispatchedCount > 0) {\n logger.info(\n { count: dispatchedCount, inFlightSize: inFlight.size },\n \"dispatcher: tasks dispatched (fire-and-forget)\",\n );\n }\n }\n\n // merge-gatekeeper (Stage 5, DEC-LO-05): Auto PR を自動マージ。\n // 状態は ticket_tracker.merge_status (DB) のみで管理し、dispatcher\n // インスタンスは in-memory state を持たない。これにより異常終了からの\n // 復帰が DB 駆動で idempotent になる (DEC-105 / B案)。\n try {\n const result = await applyMergeGatekeeper();\n if (result.eligibleCount > 0) {\n logger.debug(\n {\n eligible: result.eligibleCount,\n processed: result.processedCount,\n merged: result.mergedCount,\n blocked: result.blockedCount,\n },\n \"merge-gatekeeper: cycle complete\",\n );\n }\n } catch (err) {\n logger.error(\n { err },\n \"merge-gatekeeper: cycle failed (continuing dispatcher)\",\n );\n }\n\n // Reset backoff on successful poll\n currentBackoffMs = ORCHESTRATOR_CONFIG.pollBackoff.initialMs;\n await sleep(pollIntervalMs);\n } catch (err) {\n logger.error({ err, backoffMs: currentBackoffMs }, \"dispatcher: poll cycle error\");\n await sleep(currentBackoffMs);\n currentBackoffMs = Math.min(\n currentBackoffMs * ORCHESTRATOR_CONFIG.pollBackoff.multiplier,\n ORCHESTRATOR_CONFIG.pollBackoff.maxMs,\n );\n }\n }\n\n // DEC-126 (GATE-038): graceful shutdown awaits in-flight worker promises.\n // Worker chains can take ~10 min for L size, so we cap the wait at\n // gracefulShutdownTimeoutMs and abandon stragglers (DEC-LO-12 detached:false\n // ensures workers die with the dispatcher process anyway).\n logger.info(\n { instanceId, inFlightSize: inFlight.size },\n \"dispatcher: graceful shutdown starting\",\n );\n if (inFlight.size > 0) {\n const settleAll = Promise.allSettled(Array.from(inFlight));\n const timeout = sleep(ORCHESTRATOR_CONFIG.gracefulShutdownTimeoutMs).then(\n () => \"timeout\" as const,\n );\n const result = await Promise.race([settleAll.then(() => \"settled\" as const), timeout]);\n if (result === \"timeout\") {\n logger.warn(\n { instanceId, remaining: inFlight.size },\n \"dispatcher: graceful shutdown timed out, abandoning in-flight workers\",\n );\n }\n }\n\n // DEC-128 (Round 16 follow-up): cleanup any worker_sessions still in\n // 'running' state for this dispatcher instance. Workers die with us via\n // DEC-LO-12 (detached:false), so the running state is necessarily stale.\n // Without this, the next dispatcher instance must wait `heartbeatTimeoutMinutes`\n // for session-supervisor.detectAndMarkZombies to catch them, during which\n // they consume `maxConcurrent` capacity (Round 16 PROD observation).\n try {\n const cleaned = await cleanupInFlightSessions(instanceId);\n if (cleaned.length > 0) {\n logger.info(\n { instanceId, cleanedCount: cleaned.length },\n \"dispatcher: in-flight sessions cleaned up on shutdown (DEC-128)\",\n );\n }\n } catch (err) {\n logger.error(\n { err, instanceId },\n \"dispatcher: shutdown session cleanup failed (next instance will rely on zombie detection)\",\n );\n }\n\n logger.info({ instanceId }, \"dispatcher: stopped\");\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function applyBackpressure(\n previousPaused: ReadonlySet<string>,\n isInitial: boolean,\n): Promise<ReadonlySet<string>> {\n let loads;\n try {\n loads = await countOpenGatesByProject();\n } catch (err) {\n logger.error(\n { err },\n \"dispatcher: backpressure load query failed (keeping previous pausedSet)\",\n );\n return previousPaused;\n }\n\n const decisions = evaluatePauseDecisions(loads);\n const diff = diffPauseState(decisions, previousPaused);\n\n if (isInitial) {\n // Suppress spurious resume events for projects that were never paused\n // by this dispatcher instance. Still emit pause events so the operator\n // sees the current backlog state.\n if (diff.newlyPaused.length > 0) {\n await emitTransitionEvents(diff.newlyPaused, \"pause\");\n }\n return diff.pausedSet;\n }\n\n if (diff.newlyPaused.length > 0) {\n await emitTransitionEvents(diff.newlyPaused, \"pause\");\n }\n if (diff.newlyResumed.length > 0) {\n await emitTransitionEvents(diff.newlyResumed, \"resume\");\n }\n return diff.pausedSet;\n}\n\nasync function emitTransitionEvents(\n decisions: PauseDecision[],\n kind: \"pause\" | \"resume\",\n): Promise<void> {\n const significance = kind === \"pause\" ? \"warn\" : \"info\";\n for (const d of decisions) {\n try {\n await getOrchestratorClient().insertOrchestratorEvent({\n projectId: d.projectId,\n eventType: kind === \"pause\" ? \"dispatcher.paused\" : \"dispatcher.resumed\",\n summary:\n kind === \"pause\"\n ? `dispatcher paused (${d.threshold === \"high\" ? \"high importance\" : \"total\"} threshold reached)`\n : \"dispatcher resumed (open gates below threshold)\",\n sourceEntity: \"dispatcher\",\n affectedDomains: [\"orchestrator\"],\n significance,\n metadata: {\n openCount: d.load.totalOpen,\n highOpenCount: d.load.highOpen,\n maxOpen: d.load.maxOpen,\n maxHigh: d.load.maxHigh,\n threshold: d.threshold ?? null,\n },\n createdBy: \"dispatcher\",\n });\n } catch (err) {\n logger.warn(\n { err, projectId: d.projectId, kind },\n \"dispatcher: failed to insert backpressure event (continuing)\",\n );\n }\n }\n}\n","import { loadTwinBuildConfig } from \"../usecases/config/load-twin-build-config.js\";\nimport type {\n ReadyTask,\n} from \"../usecases/orchestrator/poll.js\";\nimport type {\n ProjectGateLoad,\n GateUnblockCandidate,\n} from \"../usecases/orchestrator/gate-ops.js\";\nimport type {\n ZombieSession,\n StaleTrackerWriteRace,\n CreateWorkerSessionArgs,\n UpdateWorkerSessionArgs,\n TrackerPhases,\n ProgressSignalsResult,\n RunningSessionSummary,\n} from \"../usecases/orchestrator/supervision.js\";\nimport type {\n EligibleTicket,\n MergeStatusValue,\n GatekeeperEventType,\n BackpressureEventArgs,\n} from \"../usecases/orchestrator/merge-ops.js\";\n\nexport type OrchestratorHttpConfig = {\n serverUrl: string;\n apiKey: string;\n};\n\nexport function getHttpConfig(): OrchestratorHttpConfig {\n const serverUrl =\n process.env.TWIN_BUILD_SERVER_URL ??\n loadTwinBuildConfig(process.cwd())?.orchestrator?.serverUrl;\n const apiKey = process.env.TWIN_BUILD_API_KEY;\n if (!serverUrl)\n throw new Error(\n \"Missing: TWIN_BUILD_SERVER_URL env var or .twin-build.json orchestrator.serverUrl\",\n );\n if (!apiKey) throw new Error(\"Missing required env var: TWIN_BUILD_API_KEY\");\n return { serverUrl: serverUrl.replace(/\\/$/, \"\"), apiKey };\n}\n\nexport class OrchestratorHttpClient {\n private baseUrl: string;\n private headers: Record<string, string>;\n\n constructor(config: OrchestratorHttpConfig) {\n this.baseUrl = `${config.serverUrl}/api/v1/orchestrator`;\n this.headers = {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": config.apiKey,\n };\n }\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const init: RequestInit = {\n method,\n headers: this.headers,\n };\n if (body !== undefined) {\n init.body = JSON.stringify(body);\n }\n\n const res = await fetch(url, init);\n if (!res.ok) {\n const text = await res.text().catch(() => \"(no body)\");\n throw new Error(`Orchestrator API ${method} ${path} → ${res.status}: ${text}`);\n }\n if (res.status === 204) return undefined as T;\n return res.json() as Promise<T>;\n }\n\n // ── Poll ──\n\n async pollAndReserveReadyTasks(args: {\n limit: number;\n excludedProjectIds: string[];\n projectIdFilter: string | null;\n }): Promise<ReadyTask[]> {\n const resp = await this.request<{ tasks: ReadyTask[] }>(\"POST\", \"/poll\", args);\n return resp.tasks;\n }\n\n async requeueTasks(taskIds: string[]): Promise<void> {\n await this.request(\"POST\", \"/requeue\", { taskIds });\n }\n\n async markTaskHalted(taskId: string, reason?: string): Promise<void> {\n await this.request(\"POST\", \"/halt-task\", { taskId, reason });\n }\n\n async setTaskSession(taskId: string, sessionId: string): Promise<void> {\n await this.request(\"PATCH\", \"/backlog-session\", { taskId, sessionId });\n }\n\n async countRunningTasksByScope(\n projectIdFilter: string | null = null,\n ): Promise<Record<string, number>> {\n const qs = projectIdFilter\n ? `?projectId=${encodeURIComponent(projectIdFilter)}`\n : \"\";\n const resp = await this.request<{ counts: Record<string, number> }>(\n \"GET\",\n `/running-count${qs}`,\n );\n return resp.counts;\n }\n\n // ── Gate ops ──\n\n async countOpenGatesByProject(): Promise<ProjectGateLoad[]> {\n const resp = await this.request<{ loads: ProjectGateLoad[] }>(\"GET\", \"/gate-load\");\n return resp.loads;\n }\n\n async findRecentlyDecidedGates(\n since: Date | null,\n projectIdFilter: string | null,\n ): Promise<{ id: string; blockedItems: unknown }[]> {\n const params = new URLSearchParams();\n if (since) params.set(\"since\", since.toISOString());\n if (projectIdFilter) params.set(\"projectId\", projectIdFilter);\n const qs = params.toString();\n const resp = await this.request<{ gates: { id: string; blockedItems: unknown }[] }>(\n \"GET\",\n `/decided-gates${qs ? `?${qs}` : \"\"}`,\n );\n return resp.gates;\n }\n\n async findCandidateBacklogs(ids: string[]): Promise<GateUnblockCandidate[]> {\n const resp = await this.request<{ candidates: GateUnblockCandidate[] }>(\n \"POST\",\n \"/candidate-backlogs\",\n { ids },\n );\n return resp.candidates;\n }\n\n async findBlockerStatuses(ids: string[]): Promise<Map<string, string>> {\n const resp = await this.request<{ statuses: { id: string; status: string }[] }>(\n \"POST\",\n \"/blocker-statuses\",\n { ids },\n );\n return new Map(resp.statuses.map((r) => [r.id, r.status]));\n }\n\n async findOpenGateBacklogIds(candidateIds: string[]): Promise<Set<string>> {\n const resp = await this.request<{ ids: string[] }>(\n \"POST\",\n \"/open-gate-backlog-ids\",\n { candidateIds },\n );\n return new Set(resp.ids);\n }\n\n async unblockBacklogItems(ids: string[]): Promise<void> {\n await this.request(\"POST\", \"/unblock-backlogs\", { ids });\n }\n\n // ── Supervision ──\n\n async detectAndMarkZombies(args: {\n dispatcherInstanceId: string;\n heartbeatTimeoutMinutes?: number;\n }): Promise<ZombieSession[]> {\n const resp = await this.request<{ zombies: ZombieSession[] }>(\n \"POST\",\n \"/detect-zombies\",\n args,\n );\n return resp.zombies;\n }\n\n async cleanupInFlightSessions(dispatcherInstanceId: string): Promise<string[]> {\n const resp = await this.request<{ cleanedIds: string[] }>(\n \"POST\",\n \"/cleanup-sessions\",\n { dispatcherInstanceId },\n );\n return resp.cleanedIds;\n }\n\n async detectStaleTrackerWriteRace(\n projectIdFilter: string | null,\n ): Promise<StaleTrackerWriteRace[]> {\n const qs = projectIdFilter ? `?projectId=${encodeURIComponent(projectIdFilter)}` : \"\";\n const resp = await this.request<{ races: StaleTrackerWriteRace[] }>(\n \"GET\",\n `/stale-write-races${qs}`,\n );\n return resp.races;\n }\n\n async verifyTrackerPostChain(args: {\n ticketId: string;\n taskId: string;\n branchName: string | null;\n }): Promise<boolean> {\n const result = await this.request<{ ok: boolean }>(\"POST\", \"/verify-tracker\", args);\n return result.ok;\n }\n\n async createWorkerSession(args: CreateWorkerSessionArgs): Promise<string> {\n const result = await this.request<{ sessionId: string }>(\n \"POST\",\n \"/worker-sessions\",\n {\n ...args,\n startedAt: args.startedAt.toISOString(),\n },\n );\n return result.sessionId;\n }\n\n async updateWorkerSession(\n sessionId: string,\n args: UpdateWorkerSessionArgs,\n ): Promise<void> {\n await this.request(\"PATCH\", `/worker-sessions/${encodeURIComponent(sessionId)}`, {\n ...args,\n completedAt: args.completedAt?.toISOString(),\n });\n }\n\n async getTrackerPhases(ticketId: string): Promise<TrackerPhases> {\n const resp = await this.request<{ phases: TrackerPhases }>(\n \"GET\",\n `/tracker-phases/${encodeURIComponent(ticketId)}`,\n );\n return resp.phases;\n }\n\n async updateTrackerPhaseCompleted(args: {\n ticketId: string;\n trackerKey: string;\n nextPhase: number;\n now: Date;\n }): Promise<void> {\n await this.request(\"PATCH\", \"/tracker-phases\", {\n ...args,\n now: args.now.toISOString(),\n });\n }\n\n async gatherProgressSignals(args: {\n projectId: string;\n ticketId: string;\n startedAt: Date;\n }): Promise<ProgressSignalsResult> {\n return this.request(\"POST\", \"/progress-signals\", {\n ...args,\n startedAt: args.startedAt.toISOString(),\n });\n }\n\n async listRunningSessions(dispatcherInstanceId?: string): Promise<RunningSessionSummary[]> {\n const qs = dispatcherInstanceId\n ? `?dispatcherInstanceId=${encodeURIComponent(dispatcherInstanceId)}`\n : \"\";\n const resp = await this.request<{ sessions: RunningSessionSummary[] }>(\n \"GET\",\n `/sessions-status${qs}`,\n );\n return resp.sessions;\n }\n\n // ── Merge ops ──\n\n async findEligibleTickets(projectIdFilter: string | null): Promise<EligibleTicket[]> {\n const qs = projectIdFilter ? `?projectId=${encodeURIComponent(projectIdFilter)}` : \"\";\n const resp = await this.request<{ tickets: EligibleTicket[] }>(\n \"GET\",\n `/merge-eligible${qs}`,\n );\n return resp.tickets;\n }\n\n async markMergeStatus(trackerId: string, status: MergeStatusValue): Promise<void> {\n await this.request(\n \"PATCH\",\n `/merge-status/${encodeURIComponent(trackerId)}`,\n { status },\n );\n }\n\n async flipBacklogDone(args: {\n trackerRowId: string;\n prUrl: string;\n prBody: string;\n projectId: string;\n }): Promise<void> {\n await this.request(\"POST\", \"/flip-backlog-done\", args);\n }\n\n async emitGatekeeperEvent(\n ticket: EligibleTicket,\n eventType: GatekeeperEventType,\n metadata: { prNumber: number; tier: string; reason: string },\n ): Promise<void> {\n await this.request(\"POST\", \"/merge-events\", { ticket, eventType, metadata });\n }\n\n async insertOrchestratorEvent(args: BackpressureEventArgs): Promise<void> {\n await this.request(\"POST\", \"/events\", args);\n }\n}\n\nlet _client: OrchestratorHttpClient | null = null;\n\nexport function getOrchestratorClient(): OrchestratorHttpClient {\n if (!_client) {\n _client = new OrchestratorHttpClient(getHttpConfig());\n }\n return _client;\n}\n\nexport function resetOrchestratorClient(): void {\n _client = null;\n}\n","import { getOrchestratorClient } from \"./http-client.js\";\nimport { getProjectIdFilter } from \"./config.js\";\nimport type { BlockerStatus, GateUnblockCandidate } from \"./gate-watcher-eval.js\";\nimport type { ReadyTask } from \"../usecases/orchestrator/poll.js\";\nimport type { ProjectGateLoad } from \"../usecases/orchestrator/gate-ops.js\";\n\nexport type { ReadyTask };\nexport type { ProjectGateLoad };\n\nexport async function pollAndReserveReadyTasks(\n limit: number,\n excludedProjectIds: string[] = [],\n): Promise<ReadyTask[]> {\n if (limit <= 0) return [];\n return getOrchestratorClient().pollAndReserveReadyTasks({\n limit,\n excludedProjectIds,\n projectIdFilter: getProjectIdFilter(),\n });\n}\n\nexport async function setTaskSession(taskId: string, sessionId: string): Promise<void> {\n return getOrchestratorClient().setTaskSession(taskId, sessionId);\n}\n\nexport async function requeueTasks(taskIds: string[]): Promise<void> {\n if (taskIds.length === 0) return;\n return getOrchestratorClient().requeueTasks(taskIds);\n}\n\n/**\n * Mark a reserved task as halted due to a persistent worker setup failure.\n *\n * The server transitions backlog_items.status='in_progress' → 'failed' and\n * ticket_tracker.orchestratorState → 'failed'. This excludes the task from\n * future poll cycles (poll filters status='todo'), preventing infinite retry\n * loops on permanent setup errors (e.g. EEXIST symlink conflicts in worktree).\n *\n * Recovery: operator inspects the worker setup, fixes the underlying issue,\n * then resets backlog_items.status to 'todo' via manage_backlog or UI.\n */\nexport async function markTaskHalted(taskId: string, reason?: string): Promise<void> {\n return getOrchestratorClient().markTaskHalted(taskId, reason);\n}\n\nexport async function countOpenGatesByProject(): Promise<ProjectGateLoad[]> {\n return getOrchestratorClient().countOpenGatesByProject();\n}\n\nexport async function findRecentlyDecidedGates(\n since: Date | null,\n): Promise<{ id: string; blockedItems: unknown }[]> {\n return getOrchestratorClient().findRecentlyDecidedGates(since, getProjectIdFilter());\n}\n\nexport async function findCandidateBacklogs(ids: string[]): Promise<GateUnblockCandidate[]> {\n if (ids.length === 0) return [];\n const result = await getOrchestratorClient().findCandidateBacklogs(ids);\n return result as GateUnblockCandidate[];\n}\n\nexport async function findBlockerStatuses(ids: string[]): Promise<Map<string, BlockerStatus>> {\n if (ids.length === 0) return new Map();\n const result = await getOrchestratorClient().findBlockerStatuses(ids);\n return result as Map<string, BlockerStatus>;\n}\n\nexport async function findOpenGateBacklogIds(candidateIds: string[]): Promise<Set<string>> {\n if (candidateIds.length === 0) return new Set();\n return getOrchestratorClient().findOpenGateBacklogIds(candidateIds);\n}\n\nexport async function unblockBacklogItems(ids: string[]): Promise<void> {\n if (ids.length === 0) return;\n return getOrchestratorClient().unblockBacklogItems(ids);\n}\n\n/**\n * Count running tasks by scope.\n *\n * Pass `getProjectIdFilter()` to scope to a single project — this is the\n * normal mode for `1 dispatcher = 1 project` cap computation (DEC-LO-12).\n *\n * `null` falls back to account-wide count for legacy diagnostics. The\n * dispatcher used to call this with null and was bitten by other projects\n * under the same API key saturating its cap (ticket 0b88d925 / formerly\n * 28a019f9). The semantics flipped: per-project is now the default for cap\n * computation; account-wide remains available for cross-project dashboards.\n */\nexport async function countRunningTasksByScope(\n projectIdFilter: string | null = null,\n): Promise<Record<string, number>> {\n return getOrchestratorClient().countRunningTasksByScope(projectIdFilter);\n}\n","import type { ProjectGateLoad } from \"./backlog-poller.js\";\n\n/**\n * DEC-LO-04: backpressure pause logic.\n *\n * A project is considered paused when EITHER:\n * - totalOpen >= maxOpen (interpretation A: total includes high)\n * - highOpen >= maxHigh\n *\n * Boundary: `>=` (the threshold value itself blocks). Chosen during Phase 5\n * Gate to avoid off-by-one ambiguity (max=5 with open=5 starts pause).\n */\nexport type PauseThreshold = \"total\" | \"high\";\n\nexport type PauseDecision = {\n projectId: string;\n paused: boolean;\n /** Which threshold triggered pause. Undefined when not paused. */\n threshold?: PauseThreshold;\n load: ProjectGateLoad;\n};\n\nexport function evaluatePauseDecisions(loads: ProjectGateLoad[]): PauseDecision[] {\n return loads.map((load) => {\n if (load.totalOpen >= load.maxOpen) {\n return { projectId: load.projectId, paused: true, threshold: \"total\", load };\n }\n if (load.highOpen >= load.maxHigh) {\n return { projectId: load.projectId, paused: true, threshold: \"high\", load };\n }\n return { projectId: load.projectId, paused: false, load };\n });\n}\n\nexport type PauseDiff = {\n newlyPaused: PauseDecision[];\n newlyResumed: PauseDecision[];\n stillPaused: PauseDecision[];\n pausedSet: Set<string>;\n};\n\n/**\n * Compare current decisions against the previous pausedSet and emit\n * transition events. Pure function — no I/O. The caller persists events\n * for newlyPaused / newlyResumed only.\n *\n * `previousPaused` is the snapshot at the end of the prior cycle. On the\n * very first invocation after dispatcher startup, callers should pass\n * `null` (or use the isInitial flag) to suppress spurious resume events\n * for projects whose load is already below threshold at startup.\n */\nexport function diffPauseState(\n decisions: PauseDecision[],\n previousPaused: ReadonlySet<string>,\n): PauseDiff {\n const pausedSet = new Set<string>();\n const newlyPaused: PauseDecision[] = [];\n const newlyResumed: PauseDecision[] = [];\n const stillPaused: PauseDecision[] = [];\n\n for (const d of decisions) {\n if (d.paused) {\n pausedSet.add(d.projectId);\n if (previousPaused.has(d.projectId)) {\n stillPaused.push(d);\n } else {\n newlyPaused.push(d);\n }\n }\n }\n\n for (const projectId of previousPaused) {\n if (!pausedSet.has(projectId)) {\n const decision = decisions.find((d) => d.projectId === projectId);\n newlyResumed.push(\n decision ?? {\n projectId,\n paused: false,\n load: {\n projectId,\n totalOpen: 0,\n highOpen: 0,\n maxOpen: 0,\n maxHigh: 0,\n },\n },\n );\n }\n }\n\n return { newlyPaused, newlyResumed, stillPaused, pausedSet };\n}\n","import { getOrchestratorClient } from \"./http-client.js\";\nimport { getProjectIdFilter } from \"./config.js\";\nimport type { ZombieSession, StaleTrackerWriteRace, RunningSessionSummary } from \"../usecases/orchestrator/supervision.js\";\n\nexport type { ZombieSession };\nexport type { StaleTrackerWriteRace };\n\nexport async function detectAndMarkZombies(dispatcherInstanceId: string): Promise<ZombieSession[]> {\n return getOrchestratorClient().detectAndMarkZombies({ dispatcherInstanceId });\n}\n\nexport async function cleanupInFlightSessions(dispatcherInstanceId: string): Promise<string[]> {\n return getOrchestratorClient().cleanupInFlightSessions(dispatcherInstanceId);\n}\n\nexport async function countRunningSessions(dispatcherInstanceId: string): Promise<number> {\n const sessions = await getOrchestratorClient().listRunningSessions(dispatcherInstanceId);\n return sessions.length;\n}\n\nexport async function detectStaleTrackerWriteRace(): Promise<StaleTrackerWriteRace[]> {\n return getOrchestratorClient().detectStaleTrackerWriteRace(getProjectIdFilter());\n}\n\nexport async function verifyTrackerPostChain(args: {\n ticketId: string;\n taskId: string;\n branchName: string | null;\n}): Promise<boolean> {\n return getOrchestratorClient().verifyTrackerPostChain(args);\n}\n\nexport async function getRunningSessionsSummary(\n dispatcherInstanceId: string,\n): Promise<RunningSessionSummary[]> {\n return getOrchestratorClient().listRunningSessions(dispatcherInstanceId);\n}\n","import {\n spawn as nodeSpawn,\n spawnSync as nodeSpawnSync,\n type ChildProcess,\n} from \"node:child_process\";\nimport {\n closeSync,\n copyFileSync,\n cpSync,\n lstatSync,\n mkdirSync,\n openSync,\n readdirSync,\n readlinkSync,\n statSync,\n symlinkSync,\n unlinkSync,\n existsSync,\n type Stats,\n} from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { logger } from \"../logger.js\";\nimport { type ReadyTask } from \"./backlog-poller.js\";\nimport {\n runChainPhases as defaultRunChainPhases,\n type ChainRunResult,\n type ChainRunnerDeps,\n} from \"./chain-runner.js\";\nimport { ORCHESTRATOR_CONFIG } from \"./config.js\";\nimport { verifyTrackerPostChain as defaultVerifyTrackerPostChain } from \"./session-supervisor.js\";\nimport { emitCompletionEvent } from \"./event-emitter.js\";\nimport {\n addWorktree as realAddWorktree,\n classifyWorktreeError,\n fetchRemote as realFetchRemote,\n removeWorktree as realRemoveWorktree,\n} from \"./worktree.js\";\n\nexport class WorkerSetupError extends Error {\n constructor(\n message: string,\n public readonly category: \"transient\" | \"persistent\",\n ) {\n super(message);\n this.name = \"WorkerSetupError\";\n }\n}\n\nexport type SpawnResult = {\n /** chain-runner が作成した最初の phase (implement) の worker_session ID。 */\n sessionId: string;\n /**\n * 最初の phase の worker process PID。chain-runner blocking 戻り後、\n * すでに exit している点に注意 (pid は記録目的)。\n */\n pid: number;\n taskId: string;\n /** chain 実行結果。dispatcher は完走可否や失敗 phase を確認可能。 */\n chainResult: ChainRunResult;\n /**\n * worktree HEAD と origin/main の divergence 観測結果 (DEC-125, Round 12 Meta-finding)。\n * 取得失敗 / 完全一致時は undefined。divergedCommits > 0 の場合 worker は古い main 上で\n * implement した可能性があり、人間レビュー時に確認推奨。\n */\n staleness?: { divergedCommits: number; mainHash: string };\n};\n\ntype SpawnFn = (\n command: string,\n args: readonly string[],\n options: Parameters<typeof nodeSpawn>[2],\n) => ChildProcess;\n\nexport type WorkerSpawnDeps = {\n spawn: SpawnFn;\n addWorktree: typeof realAddWorktree;\n fetchRemote: typeof realFetchRemote;\n removeWorktree: typeof realRemoveWorktree;\n fs: {\n openSync: typeof openSync;\n closeSync: typeof closeSync;\n mkdirSync: typeof mkdirSync;\n copyFileSync: typeof copyFileSync;\n cpSync: typeof cpSync;\n existsSync: typeof existsSync;\n lstatSync: typeof lstatSync;\n readlinkSync: typeof readlinkSync;\n readdirSync: (path: string) => string[];\n statSync: typeof statSync;\n symlinkSync: typeof symlinkSync;\n unlinkSync: typeof unlinkSync;\n };\n git: LinkClaudeAssetsGit;\n now: () => Date;\n projectRoot?: string;\n /** chain-runner を override 可能 (テスト用)。default: defaultRunChainPhases */\n runChainPhases?: typeof defaultRunChainPhases;\n /** post-chain tracker verify を override 可能 (テスト用)。default: defaultVerifyTrackerPostChain */\n verifyTrackerPostChain?: typeof defaultVerifyTrackerPostChain;\n};\n\nconst defaultDeps: WorkerSpawnDeps = {\n spawn: nodeSpawn as SpawnFn,\n addWorktree: realAddWorktree,\n fetchRemote: realFetchRemote,\n removeWorktree: realRemoveWorktree,\n fs: {\n openSync,\n closeSync,\n mkdirSync,\n copyFileSync,\n cpSync,\n existsSync,\n lstatSync,\n readlinkSync,\n readdirSync,\n statSync,\n symlinkSync,\n unlinkSync,\n },\n git: {\n inspectAssetStatus: defaultInspectAssetStatus,\n },\n now: () => new Date(),\n};\n\nconst BRANCH_SLUG_MAX_LEN = 40;\n\nfunction slugify(raw: string, maxLen = BRANCH_SLUG_MAX_LEN): string {\n const slug = raw\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, maxLen)\n .replace(/-+$/g, \"\");\n return slug || \"task\";\n}\n\nexport function computeBranchAndPath(\n task: ReadyTask,\n projectRoot: string,\n): { branchName: string; worktreePath: string; name: string } {\n const shortId = task.id.replace(/-/g, \"\").slice(0, 8);\n const slug = slugify(task.title);\n const name = `${shortId}-${slug}`;\n return {\n branchName: `orchestrator/${name}`,\n worktreePath: resolve(projectRoot, \"worktrees\", name),\n name,\n };\n}\n\ntype ValidateClaudeAssetsFs = {\n lstatSync: (path: string) => Stats;\n readlinkSync: (path: string) => string;\n statSync: (path: string) => Stats;\n};\n\n/**\n * Layer 3 (本 PR): worker spawn 前に source 側の `.claude/{rules,skills}` を\n * 健全性チェックする。\n *\n * 期待形態:\n * - symlink (dev twin-build-server style) — link target が実在すること\n * - directory (forsight 等の他プロジェクト style)\n *\n * 期待外(ファイル化、broken symlink)は worker spawn 自体を `persistent` halt させる。\n * これにより linkClaudeAssets 内で起きていた obscure な失敗を早期に明示化する。\n *\n * `.claude/<name>` が source 側に存在しない場合 (ENOENT) は OK skip する\n * (一部プロジェクトでは `rules` だけ等の partial 配置がありえる)。\n */\nexport function validateProjectClaudeAssets(\n projectRoot: string,\n deps: ValidateClaudeAssetsFs,\n): void {\n for (const name of CLAUDE_ASSET_NAMES) {\n const srcAbs = join(projectRoot, \".claude\", name);\n let stat: Stats;\n try {\n stat = deps.lstatSync(srcAbs);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") continue;\n throw new WorkerSetupError(\n `.claude/${name} health check failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n \"persistent\",\n );\n }\n if (!stat.isSymbolicLink() && !stat.isDirectory()) {\n throw new WorkerSetupError(\n `.claude/${name} at ${srcAbs} is neither a symlink nor a directory (likely corrupted). ` +\n \"Expected either a symlink into the twin-build framework checkout (dev) \" +\n \"or a directory with tracked rule/skill files (other projects). \" +\n \"Recover: remove the corrupted entry and re-run /init or restore from git.\",\n \"persistent\",\n );\n }\n if (stat.isSymbolicLink()) {\n const targetRaw = deps.readlinkSync(srcAbs);\n const targetAbs = resolve(dirname(srcAbs), targetRaw);\n try {\n deps.statSync(targetAbs);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n throw new WorkerSetupError(\n `.claude/${name} symlink at ${srcAbs} targets non-existent path ${targetAbs}. ` +\n \"Recover: re-clone the twin-build framework checkout or update the symlink to a valid path.\",\n \"persistent\",\n );\n }\n throw err;\n }\n }\n }\n}\n\n/**\n * Detect divergence between worktree HEAD and origin/main (DEC-125, Round 12 Meta-finding).\n *\n * 用途: agent worker が autonomous に implement する際、main の最新差分を見落とすケース\n * (Round 12 PR #63 で観測した重複 Appendix 追加) を検知する。merge は試みず、warning と\n * staleness 構造体を返すのみ。merge / rebase は人間レビューに委ねる (将来 DEC-125 C 案へ進化候補)。\n *\n * 戻り値: divergedCommits > 0 なら staleness 情報、=0 か取得失敗なら undefined。\n *\n * 前提: worker-spawner.spawnWorker の fetchRemote(origin/main) が直前に成功している。\n * worktree が broken state (HEAD 取得不可) の場合は fall-through で undefined を返し\n * dispatcher は通常 path を継続する (warning logger.warn のみ)。\n */\nasync function detectMainDivergence(args: {\n worktreePath: string;\n runGit: (args: {\n args: readonly string[];\n cwd: string;\n }) => Promise<{ exitCode: number; stdout: string }>;\n}): Promise<{ divergedCommits: number; mainHash: string } | undefined> {\n const { worktreePath, runGit } = args;\n // git rev-list --count HEAD..origin/main → \"<N>\\n\"\n const countResult = await runGit({\n args: [\"rev-list\", \"--count\", \"HEAD..origin/main\"],\n cwd: worktreePath,\n });\n if (countResult.exitCode !== 0) {\n return undefined;\n }\n const divergedCommits = Number.parseInt(countResult.stdout.trim(), 10);\n if (!Number.isFinite(divergedCommits) || divergedCommits <= 0) {\n return undefined;\n }\n // origin/main の commit hash も取得 (詳細追跡用)\n const hashResult = await runGit({\n args: [\"rev-parse\", \"origin/main\"],\n cwd: worktreePath,\n });\n const mainHash =\n hashResult.exitCode === 0 ? hashResult.stdout.trim().slice(0, 12) : \"unknown\";\n return { divergedCommits, mainHash };\n}\n\n/**\n * Stage 5 Theme 5: Attempt auto-rebase of worktree feature branch onto origin/main.\n *\n * Called when detectMainDivergence reports `divergedCommits > 0`. Tries\n * `git rebase origin/main`. Result:\n * - \"rebased\": rebase succeeded, worktree is now on fresh base, worker can spawn safely.\n * - \"no_change\": rebase reported \"Current branch X is up to date\" (race-after-detect).\n * - \"conflict\": rebase had conflicts; we run `git rebase --abort` to leave worktree clean,\n * and the caller should NOT spawn a worker (operator manual intervention required).\n * - \"error\": rebase failed for non-conflict reasons (e.g., uncommitted changes); abort\n * attempted, caller should fall back to legacy stale-warn behavior.\n *\n * Conflict detection: git rebase exits non-zero on conflict, and stdout/stderr typically\n * contains \"CONFLICT\" or \"Failed to merge\". Other non-zero exits we treat as \"error\"\n * (best-effort) rather than over-aggressively mark as conflict.\n */\nasync function attemptAutoRebase(args: {\n worktreePath: string;\n runGit: (args: {\n args: readonly string[];\n cwd: string;\n }) => Promise<{ exitCode: number; stdout: string }>;\n}): Promise<\"rebased\" | \"no_change\" | \"conflict\" | \"error\"> {\n const { worktreePath, runGit } = args;\n const result = await runGit({\n args: [\"rebase\", \"origin/main\"],\n cwd: worktreePath,\n });\n if (result.exitCode === 0) {\n if (/up.to.date/i.test(result.stdout)) {\n return \"no_change\";\n }\n return \"rebased\";\n }\n\n // Non-zero exit: try to determine if conflict. Always best-effort abort to leave\n // worktree in a clean state regardless of cause.\n const isConflict =\n /CONFLICT|Failed to merge|could not apply/i.test(result.stdout);\n\n await runGit({\n args: [\"rebase\", \"--abort\"],\n cwd: worktreePath,\n }).catch(() => undefined); // abort failure is non-fatal; worktree may already be clean\n\n return isConflict ? \"conflict\" : \"error\";\n}\n\n/**\n * Sentinel error thrown by spawnWorker when auto-rebase hits a conflict.\n * dispatcher.spawnAndTrack catches all spawn errors and requeues — operator will\n * see the requeue loop in logs and can manually rebase or close the ticket.\n */\nexport class RebaseConflictError extends Error {\n constructor(args: { ticketId: string; worktreePath: string; mainHash: string }) {\n super(\n `worker-spawner: auto-rebase conflict on ticket=${args.ticketId} worktree=${args.worktreePath} main=${args.mainHash}; operator must rebase manually`,\n );\n this.name = \"RebaseConflictError\";\n }\n}\n\n/**\n * DEC-127 (G-R15-1): Module-level mutex for git operations that mutate the main\n * repo's .git/ state (notably .git/config when adding worktree entries). Round\n * 15 PROD observed `error: could not lock config file .git/config: File exists`\n * when DEC-126 enabled true 3-parallel spawns and 3 `git worktree add` ran\n * concurrently. git uses `.git/config.lock` as an atomic file lockfile and only\n * one process can hold it; concurrent attempts fail.\n *\n * In-process Promise-chain mutex serializes the critical section\n * (fetchRemote + addWorktree, ~100ms) within a single dispatcher process.\n * Workers' chains still run in parallel (DEC-126 maintained); only worktree\n * creation is sequential.\n *\n * Multi-process protection is out of scope (DEC-LO-04: single-process\n * dispatcher assumption). If a human runs concurrent git commands on the same\n * repo while dispatcher is running, races can still occur — operational rule.\n */\nlet worktreeMutex: Promise<void> = Promise.resolve();\n\nasync function withWorktreeMutex<T>(fn: () => Promise<T>): Promise<T> {\n const prev = worktreeMutex;\n let release: () => void = () => undefined;\n worktreeMutex = new Promise<void>((r) => {\n release = r;\n });\n try {\n await prev;\n } catch {\n // Previous holder rejected — proceed (we don't propagate prior errors).\n }\n try {\n return await fn();\n } finally {\n release();\n }\n}\n\nfunction buildWorkerEnv(): NodeJS.ProcessEnv {\n const env = process.env;\n const minimal: NodeJS.ProcessEnv = {};\n const allow = [\"PATH\", \"HOME\", \"USER\", \"LANG\", \"TZ\", \"TWIN_BUILD_API_KEY\"];\n for (const key of allow) {\n if (env[key] !== undefined) minimal[key] = env[key];\n }\n // G-R7-1 / G-R5-2 fix: skill が non-interactive worker mode を検出するための env。\n // /ticket-implement の commit confirmation や /ticket-pr の PR 作成 confirmation\n // を skill 側で auto-confirm する分岐に使う (chain-runner auto-commit と二重防御)。\n minimal.TWIN_BUILD_AGENT_MODE = \"1\";\n return minimal;\n}\n\nexport const CLAUDE_ASSET_NAMES = [\"skills\", \"rules\"] as const;\n\ntype LinkClaudeAssetsFs = {\n lstatSync: (path: string) => Stats;\n readlinkSync: (path: string) => string;\n symlinkSync: (target: string, path: string) => void;\n unlinkSync: (path: string) => void;\n readdirSync: (path: string) => string[];\n};\n\ntype LinkClaudeAssetsGit = {\n /**\n * Inspect whether `<worktreePath>/<relativePath>` is tracked-clean.\n *\n * Returns `{ clean: true, raw: \"\" }` when the path has no modified tracked\n * files and no untracked entries inside it. Returns `{ clean: false, raw }`\n * when porcelain output is non-empty (dirty — must halt for operator).\n *\n * Throws when git itself fails (missing binary, locked index, broken repo).\n * Callers should treat a throw as **transient** (request a requeue) rather\n * than persistent — the worktree state is unverifiable, not known-bad.\n */\n inspectAssetStatus: (\n worktreePath: string,\n relativePath: string,\n ) => { clean: boolean; raw: string };\n};\n\ntype LinkClaudeAssetsDeps = {\n fs: LinkClaudeAssetsFs;\n git: LinkClaudeAssetsGit;\n};\n\nfunction defaultInspectAssetStatus(\n worktreePath: string,\n relativePath: string,\n): { clean: boolean; raw: string } {\n const result = nodeSpawnSync(\n \"git\",\n [\"-C\", worktreePath, \"status\", \"--porcelain\", \"--\", relativePath],\n { encoding: \"utf-8\", stdio: [\"ignore\", \"pipe\", \"pipe\"] },\n );\n if (result.error) throw result.error;\n if (result.status !== 0) {\n throw new Error(\n `git status --porcelain failed in ${worktreePath} for ${relativePath}: ` +\n `exit=${result.status ?? \"null\"}, stderr=${(result.stderr ?? \"\").trim()}`,\n );\n }\n const raw = result.stdout;\n return { clean: raw.length === 0, raw };\n}\n\n/**\n * Materialize `.claude/skills` and `.claude/rules` inside a fresh worktree as\n * absolute symlinks so the claude CLI can discover them.\n *\n * In twin-build-server these entries live as relative symlinks (`../../twin-build/...`)\n * in the main checkout but are untracked, so `git worktree add` does not carry\n * them into the new tree. Re-linking with absolute paths keeps the worker\n * decoupled from the worktree's directory depth.\n */\nexport function linkClaudeAssets(\n projectRoot: string,\n worktreePath: string,\n deps: LinkClaudeAssetsDeps,\n): void {\n const { fs, git } = deps;\n for (const name of CLAUDE_ASSET_NAMES) {\n const srcAbs = join(projectRoot, \".claude\", name);\n const dstAbs = join(worktreePath, \".claude\", name);\n\n let target: string;\n try {\n const stat = fs.lstatSync(srcAbs);\n if (stat.isSymbolicLink()) {\n target = resolve(dirname(srcAbs), fs.readlinkSync(srcAbs));\n } else if (stat.isDirectory()) {\n target = srcAbs;\n } else {\n continue;\n }\n } catch {\n continue;\n }\n\n // Case-sensitivity guard (macOS HFS+/APFS).\n //\n // On case-insensitive filesystems, `lstatSync(dstAbs)` succeeds even when\n // the actual on-disk entry has a different case (e.g. `.claude/Rules/`\n // vs the canonical `.claude/rules/`). Git's index, however, is\n // case-sensitive: a tracked `.claude/Rules/` entry would produce a clean\n // porcelain reading for `.claude/rules`, leading us to incorrectly skip\n // symlinking while the worker later fails to resolve the canonical path.\n // List the parent directory and reject anything other than an exact match.\n try {\n const parentEntries = fs.readdirSync(join(worktreePath, \".claude\"));\n const matched = parentEntries.find(\n (entry) => entry.toLowerCase() === name && entry !== name,\n );\n if (matched) {\n throw new WorkerSetupError(\n `case mismatch at ${dstAbs}: worktree has '${matched}' but the canonical asset name is '${name}'. ` +\n \"twin-build expects lowercase asset directory names ('skills', 'rules'). \" +\n `Rename the directory in your repo (git mv .claude/${matched} .claude/${name}) and retry.`,\n \"persistent\",\n );\n }\n } catch (err) {\n if (err instanceof WorkerSetupError) throw err;\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") throw err;\n // .claude/ does not exist in the worktree — nothing to validate, continue.\n }\n\n // Dispose of any prior entry at dstAbs before symlinking. The earlier\n // implementation called unlinkSync inside a swallow-all catch, which left\n // a pre-existing directory in place and produced an EEXIST loop on the\n // following symlinkSync (observed in PROD when a worktree was reused with\n // a real `.claude/rules` directory left over from a prior worker run).\n // - symlink / regular file → unlink (idempotent setup for normal reuse)\n // - directory → defer to tracked-clean check below\n // - missing (ENOENT) → no-op\n let existingStat: Stats | undefined;\n try {\n existingStat = fs.lstatSync(dstAbs);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") throw err;\n }\n if (existingStat) {\n if (existingStat.isSymbolicLink() || existingStat.isFile()) {\n try {\n fs.unlinkSync(dstAbs);\n } catch (err) {\n // TOCTOU: entry vanished between lstat and unlink — benign, proceed.\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") throw err;\n }\n } else if (existingStat.isDirectory()) {\n // A real directory at the destination has two distinct causes:\n //\n // (a) The project commits `.claude/<asset>/*` to git (e.g. forsight).\n // `git worktree add origin/main` materialised those tracked files\n // into the worktree. The worker can read them directly. We must\n // NOT replace the directory with a symlink — that would show as\n // `deleted: ...` + an untracked symlink in `git status`, which\n // the worker would then carry into its commit (catastrophic).\n //\n // (b) A prior worker run left intermediate output behind, or the\n // operator edited rules in the worktree mid-task. Round 9\n // protection: refuse to touch unknown content.\n //\n // `git status --porcelain` separates (a) from (b): empty output means\n // tracked-clean (case a, safe to skip), non-empty means dirty (case\n // b, must halt persistently). If git itself fails (locked index,\n // missing binary), the state is unverifiable — neither known-clean\n // nor known-dirty — so we surface a **transient** error so the\n // dispatcher requeues rather than halting on a recoverable hiccup.\n let inspection: { clean: boolean; raw: string };\n try {\n inspection = git.inspectAssetStatus(\n worktreePath,\n join(\".claude\", name),\n );\n } catch (gitErr) {\n const reason = gitErr instanceof Error ? gitErr.message : String(gitErr);\n logger.warn(\n { dstAbs, err: reason },\n \"linkClaudeAssets: git status failed; requesting requeue (transient)\",\n );\n throw new WorkerSetupError(\n `could not inspect git status at ${dstAbs}: ${reason}. ` +\n \"The worktree's cleanliness is unverifiable (locked index, missing git binary, \" +\n \"or concurrent git operation). Dispatcher will requeue.\",\n \"transient\",\n );\n }\n\n if (inspection.clean) {\n // debug, not info: this fires on every spawn for projects that\n // commit .claude/<asset>/* to git (forsight pattern), so info-level\n // logging would dominate the dispatcher log. The branch itself is\n // the documented, expected path for those projects.\n logger.debug(\n { dstAbs, asset: name },\n \"linkClaudeAssets: destination is a tracked-clean directory; skipping symlink (worker reads tracked files directly)\",\n );\n continue;\n }\n\n throw new WorkerSetupError(\n `refuse to overwrite existing directory at ${dstAbs}.\\n` +\n ` Cause: the worktree's .claude/${name} contains uncommitted/untracked entries.\\n` +\n \" Likely from: (a) a prior worker run that left intermediate files, or\\n\" +\n ` (b) .claude/${name}/* is tracked in git AND has local edits.\\n` +\n \" Recovery: 1) rm -rf this directory inside the worktree\\n\" +\n \" 2) `manage_backlog action=update id=<ticketId> changes.status=todo`\\n\" +\n \" 3) re-run dispatch_to_agent\\n\" +\n ` Long-term: add .claude/${name}/* to .gitignore (twin-build convention),\\n` +\n \" or keep the worktree's .claude assets clean between runs.\",\n \"persistent\",\n );\n } else {\n throw new Error(`unexpected file type at ${dstAbs}`);\n }\n }\n\n fs.symlinkSync(target, dstAbs);\n }\n}\n\ntype InjectMcpConfigFs = {\n existsSync: (path: string) => boolean;\n copyFileSync: typeof copyFileSync;\n};\n\n/**\n * Materialize `.mcp.json` inside a fresh worktree (Round 5 dogfood discovery).\n *\n * `.mcp.json` は secret token (twin-build / render API key) を含むため `.gitignore`\n * 対象であり、`origin/main` から作成された worktree には存在しない。worker の\n * claude CLI は `.mcp.json` がないと `mcp__twin-build__*` ツール (fetch_prompt /\n * manage_ticket_tracker 等) を呼べず、`/ticket-implement` 起動直後に失敗する。\n *\n * dispatcher 側で host の `.mcp.json` を worktree にコピーすることでこのギャップを\n * 埋める。host に存在しない場合 (CI 環境等) はスキップする。\n */\nexport function injectMcpConfig(\n projectRoot: string,\n worktreePath: string,\n fs: InjectMcpConfigFs,\n): void {\n const src = join(projectRoot, \".mcp.json\");\n if (!fs.existsSync(src)) {\n return;\n }\n const dst = join(worktreePath, \".mcp.json\");\n fs.copyFileSync(src, dst);\n}\n\ntype InjectWorkItemsFs = {\n existsSync: (path: string) => boolean;\n mkdirSync: typeof mkdirSync;\n cpSync: typeof cpSync;\n};\n\n/**\n * Materialize `work/items/<ticketId>/` inside a fresh worktree (DEC-112, GATE-027).\n *\n * Worker は `git worktree add ... origin/main` から起動するため、ticket workflow\n * (/ticket-context, /ticket-decision, /ticket-review, /ticket-gate) が host 側で\n * 生成した work/items/<ticketId>/ ファイル群が origin/main に存在せず、\n * /ticket-implement の前提ゲートチェック (context.md / decision.md /\n * reviews/integrated-review.md) で失敗する。\n *\n * dispatcher 側で host の work/items/<ticketId>/ を worktree に再帰コピーすることで\n * このギャップを埋める。host に存在しない場合 (S size 等) はスキップする。\n */\nexport function injectWorkItems(\n projectRoot: string,\n worktreePath: string,\n ticketId: string,\n fs: InjectWorkItemsFs,\n): void {\n const srcDir = join(projectRoot, \"work\", \"items\", ticketId);\n if (!fs.existsSync(srcDir)) {\n return;\n }\n const dstDir = join(worktreePath, \"work\", \"items\", ticketId);\n fs.mkdirSync(dirname(dstDir), { recursive: true });\n fs.cpSync(srcDir, dstDir, { recursive: true });\n}\n\ntype SweepStaleWorktreesDeps = {\n fs: {\n existsSync: (path: string) => boolean;\n readdirSync: (path: string) => string[];\n statSync: (path: string) => Stats;\n };\n removeWorktree: typeof realRemoveWorktree;\n now: () => Date;\n /** 1h 等の age 閾値 (millis) */\n staleMs?: number;\n};\n\n/**\n * Layer 1b (本 PR): dispatcher 起動時に `worktrees/<...>/` 配下を sweep し、\n * mtime > staleMs (default 1h) のディレクトリを `git worktree remove --force` する。\n *\n * 起動直後はそのインスタンスが create したばかりの worktree が存在しないため、\n * 残っている worktree は前 dispatcher / 異常終了の遺物と見做して安全に除去できる。\n *\n * - sweep は best-effort: 個別 entry の remove 失敗は warn にとどめ次に進める\n * - `worktrees/` 自体が無い (新規プロジェクト等) は no-op\n * - mtime <= 1h のエントリは保護 (並行 dispatcher / 直近 manual worktree への配慮)\n *\n * @returns 削除した worktree path の配列 (debug 用)\n */\nexport async function sweepStaleWorktrees(\n projectRoot: string,\n deps: SweepStaleWorktreesDeps,\n): Promise<string[]> {\n const worktreesDir = join(projectRoot, \"worktrees\");\n if (!deps.fs.existsSync(worktreesDir)) return [];\n const staleMs = deps.staleMs ?? 60 * 60 * 1000;\n const nowMs = deps.now().getTime();\n let entries: string[];\n try {\n entries = deps.fs.readdirSync(worktreesDir);\n } catch (err) {\n logger.warn(\n { err, worktreesDir },\n \"sweepStaleWorktrees: failed to list worktrees dir (continuing)\",\n );\n return [];\n }\n const removed: string[] = [];\n for (const entry of entries) {\n const entryPath = join(worktreesDir, entry);\n let stat: Stats;\n try {\n stat = deps.fs.statSync(entryPath);\n } catch {\n continue; // race or broken entry — skip silently\n }\n if (!stat.isDirectory()) continue;\n const ageMs = nowMs - stat.mtimeMs;\n if (ageMs < staleMs) continue;\n try {\n await deps.removeWorktree({\n worktreePath: entryPath,\n force: true,\n cwd: projectRoot,\n });\n removed.push(entryPath);\n } catch (err) {\n logger.warn(\n { err: err instanceof Error ? err.message : String(err), entryPath },\n \"sweepStaleWorktrees: git worktree remove failed (continuing)\",\n );\n }\n }\n return removed;\n}\n\nexport function classifyExitCode(\n code: number | null,\n signal: NodeJS.Signals | null,\n): \"transient\" | \"persistent\" {\n if (signal === \"SIGTERM\" || signal === \"SIGKILL\" || signal === \"SIGINT\") {\n return \"transient\";\n }\n if (code === null) return \"transient\";\n if (code === 0) return \"transient\";\n if (code === 127) return \"persistent\";\n if (code === 126) return \"persistent\";\n if (code === 2) return \"persistent\";\n return \"transient\";\n}\n\n/**\n * Spawn a claude CLI worker chain for a ready backlog task (DEC-LO-06, DEC-LO-08,\n * DEC-LO-12, DEC-114).\n *\n * 動作:\n * - app / serial-app: create git worktree under ./worktrees/<name>, copy\n * settings.worker-app.json as .claude/settings.local.json, then drive\n * `runChainPhases` for implement → verify → pr (or implement → verify for S).\n * - framework: not supported in Stage 3 MVP (follow-up).\n *\n * 各 phase の worker_session 作成 / spawn / auto-commit / tracker phase 更新は\n * chain-runner.runChainPhases に委譲する。worker-spawner は worktree セットアップ\n * (worktree / .claude assets / work/items / .mcp.json / settings) に責任を限定する。\n *\n * **同期実行 (await)**: Round 6 MVP では chain 完走まで dispatcher cycle がブロック\n * する。並列性向上は次 PR で fire-and-forget へ移行を検討。\n *\n * detached: false per DEC-LO-12 (worker dies with dispatcher)。\n * shell: false to avoid command injection。\n */\nexport async function spawnWorker(\n task: ReadyTask,\n dispatcherInstanceId: string,\n overrides: Partial<WorkerSpawnDeps> = {},\n): Promise<SpawnResult> {\n const deps: WorkerSpawnDeps = { ...defaultDeps, ...overrides };\n const projectRoot = deps.projectRoot ?? process.cwd();\n\n if (task.scope === \"framework\") {\n // Persistent: dispatcher must halt instead of requeueing. Without this\n // category tag the dispatcher catches a plain Error, classifies it as\n // transient, and starts an infinite requeue loop the moment a UI lets\n // operators pick the 'framework' scope (defensive — currently unreachable\n // because no caller emits framework-scoped tasks in Stage 3 MVP).\n throw new WorkerSetupError(\n `worker-spawner: scope 'framework' is not supported in Stage 3 MVP (task=${task.id})`,\n \"persistent\",\n );\n }\n\n // Layer 3 health check: source-side .claude/{rules,skills} の形態を事前確認。\n // 期待外なら linkClaudeAssets の手前で persistent halt して obscure failure を回避。\n validateProjectClaudeAssets(projectRoot, deps.fs);\n\n const { branchName, worktreePath } = computeBranchAndPath(task, projectRoot);\n\n // ── worktree セットアップ (DEC-127 mutex で serialize) ──\n // DEC-LO-27: fetch origin/main first so worktree is branched from the\n // latest remote tip, not a stale local main.\n // DEC-124 (G-R11-2): existing worktree is reused; addWorktree skipped.\n // DEC-127 (G-R15-1): fetchRemote + addWorktree are wrapped in a module-level\n // mutex to serialize concurrent worktree creation across parallel spawns\n // (Round 15 PROD observed `.git/config` lock race when 3 spawns ran in\n // parallel via DEC-126 fire-and-forget).\n const reused = deps.fs.existsSync(worktreePath);\n await withWorktreeMutex(async () => {\n await deps.fetchRemote({\n remote: \"origin\",\n ref: \"main\",\n cwd: projectRoot,\n });\n if (reused) {\n logger.info(\n { worktreePath, branchName, ticketId: task.ticketId, route: task.route },\n \"worker-spawner: reusing existing worktree (DEC-124)\",\n );\n return;\n }\n try {\n await deps.addWorktree({\n worktreePath,\n branchName,\n baseRef: \"origin/main\",\n cwd: projectRoot,\n });\n } catch (err) {\n const { category, reason } = classifyWorktreeError(err);\n throw new WorkerSetupError(\n `worker-spawner: failed to create worktree at ${worktreePath}: ${reason}`,\n category,\n );\n }\n });\n\n const settingsDir = join(worktreePath, \".claude\");\n deps.fs.mkdirSync(settingsDir, { recursive: true });\n\n try {\n linkClaudeAssets(projectRoot, worktreePath, {\n fs: deps.fs,\n git: deps.git,\n });\n } catch (err) {\n // linkClaudeAssets surfaces WorkerSetupError directly for the two cases\n // it can classify (persistent: dirty directory / case mismatch; transient:\n // git inspection failure). Preserve that category so the dispatcher can\n // route correctly. Anything else is an unexpected fs error and stays\n // persistent (operator action required).\n if (err instanceof WorkerSetupError) throw err;\n throw new WorkerSetupError(\n `worker-spawner: failed to link .claude assets into worktree: ${\n err instanceof Error ? err.message : String(err)\n }`,\n \"persistent\",\n );\n }\n\n // DEC-112: host の work/items/<ticketId>/ を worktree に注入する。\n try {\n injectWorkItems(projectRoot, worktreePath, task.ticketId, deps.fs);\n } catch (err) {\n throw new WorkerSetupError(\n `worker-spawner: failed to inject work/items into worktree: ${\n err instanceof Error ? err.message : String(err)\n }`,\n \"persistent\",\n );\n }\n\n // Round 5 dogfood: .mcp.json を worktree にコピーして worker の MCP ツールを有効化。\n try {\n injectMcpConfig(projectRoot, worktreePath, deps.fs);\n } catch (err) {\n throw new WorkerSetupError(\n `worker-spawner: failed to inject .mcp.json into worktree: ${\n err instanceof Error ? err.message : String(err)\n }`,\n \"persistent\",\n );\n }\n\n const templateName = \"settings.worker-app.json\";\n const templateSrc = join(projectRoot, \".claude\", templateName);\n const templateDst = join(settingsDir, \"settings.local.json\");\n try {\n deps.fs.copyFileSync(templateSrc, templateDst);\n } catch (err) {\n throw new WorkerSetupError(\n `worker-spawner: failed to copy settings template (${templateSrc}): ${\n err instanceof Error ? err.message : String(err)\n }`,\n \"persistent\",\n );\n }\n\n // ── chain-runner deps adapter ──\n const logDir = join(projectRoot, ORCHESTRATOR_CONFIG.logDir, \"workers\");\n deps.fs.mkdirSync(logDir, { recursive: true });\n\n const runGit = async ({\n args,\n cwd,\n }: {\n args: readonly string[];\n cwd: string;\n }): Promise<{ exitCode: number; stdout: string }> =>\n new Promise((resolve, reject) => {\n const child = deps.spawn(\"git\", args, {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n shell: false,\n });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout?.on(\"data\", (chunk) => {\n stdout += chunk.toString();\n });\n child.stderr?.on(\"data\", (chunk) => {\n stderr += chunk.toString();\n });\n child.on(\"error\", (err) => {\n reject(err);\n });\n child.on(\"close\", (code) => {\n // stdout には git の出力、stderr の警告も合わせて返却\n const combined = stdout + (stderr ? `\\n${stderr}` : \"\");\n resolve({ exitCode: code ?? -1, stdout: combined });\n });\n });\n\n // DEC-125 (Round 12 Meta-finding): worktree HEAD と origin/main の divergence を検知。\n // Stage 5 Theme 5 (本 PR): divergence 観測時に auto-rebase を試行。\n // - rebase 成功: staleness を unset し worker は新しい base で動作 (silent)\n // - conflict: rebase --abort + RebaseConflictError throw → dispatcher が requeue\n // - error (rebase 不可): 旧 path (warn + staleness signal) に fallback\n // detection 失敗自体は warning のみで chain 起動継続 (defensive)\n let staleness: { divergedCommits: number; mainHash: string } | undefined;\n try {\n staleness = await detectMainDivergence({ worktreePath, runGit });\n if (staleness) {\n const rebaseResult = await attemptAutoRebase({ worktreePath, runGit });\n if (rebaseResult === \"rebased\" || rebaseResult === \"no_change\") {\n logger.info(\n {\n worktreePath,\n branchName,\n ticketId: task.ticketId,\n divergedCommits: staleness.divergedCommits,\n mainHash: staleness.mainHash,\n rebaseResult,\n },\n \"worker-spawner: auto-rebase succeeded — worktree is now on fresh base\",\n );\n staleness = undefined; // signal は外す (もう stale ではない)\n } else if (rebaseResult === \"conflict\") {\n logger.error(\n {\n worktreePath,\n branchName,\n ticketId: task.ticketId,\n divergedCommits: staleness.divergedCommits,\n mainHash: staleness.mainHash,\n },\n \"worker-spawner: auto-rebase conflict — worker spawn aborted, manual rebase required\",\n );\n throw new RebaseConflictError({\n ticketId: task.ticketId,\n worktreePath,\n mainHash: staleness.mainHash,\n });\n } else {\n // rebaseResult === \"error\": 旧 path (warn + staleness を維持)\n logger.warn(\n {\n worktreePath,\n branchName,\n ticketId: task.ticketId,\n route: task.route,\n divergedCommits: staleness.divergedCommits,\n mainHash: staleness.mainHash,\n },\n \"worker-spawner: stale worktree detected — auto-rebase failed (non-conflict). Falling back to staleness warn.\",\n );\n }\n }\n } catch (err) {\n // RebaseConflictError は意図的 throw、再 throw して spawn を中止\n if (err instanceof RebaseConflictError) throw err;\n // それ以外の detection 失敗は warning にとどめ chain 起動は継続\n logger.warn(\n { worktreePath, err: err instanceof Error ? err.message : String(err) },\n \"worker-spawner: stale detection failed (continuing without staleness signal)\",\n );\n }\n\n const chainDeps: ChainRunnerDeps = {\n spawn: ({ args, cwd, env, logFd }) =>\n deps.spawn(\"claude\", args, {\n cwd,\n env,\n detached: false,\n stdio: [\"ignore\", logFd, logFd],\n shell: false,\n }),\n runGit,\n openLogFd: (sessionId: string) =>\n deps.fs.openSync(join(logDir, `${sessionId}.log`), \"a\"),\n closeLogFd: (fd: number) => {\n try {\n deps.fs.closeSync(fd);\n } catch (err) {\n logger.warn({ err }, \"worker-spawner: log fd close failed\");\n }\n },\n buildEnv: buildWorkerEnv,\n now: deps.now,\n };\n\n // ── chain 実行 ──\n const runChainPhasesFn = deps.runChainPhases ?? defaultRunChainPhases;\n const chainResult = await runChainPhasesFn({\n task,\n worktreePath,\n branchName,\n dispatcherInstanceId,\n deps: chainDeps,\n });\n\n // Finding 5 fix: SpawnResult.sessionId は dispatcher.setTaskSession で\n // backlog_items.agent_session_id (uuid 型) に書き込まれるため、skipped phase の\n // nil UUID sentinel ではなく、実 worker_session 行が存在する non-skipped phase の\n // sessionId を優先する。全 phase が skipped (chain として何も実行しなかった) の\n // 場合のみ fallback で先頭 phase を使う (= nil UUID、書き込みは valid だが\n // worker_sessions に対応 row なし)。\n const firstNonSkipped = chainResult.phases.find((p) => !p.skipped);\n const firstPhase = firstNonSkipped ?? chainResult.phases[0];\n if (!firstPhase) {\n throw new Error(\n `worker-spawner: chain-runner returned no phases for task=${task.id}`,\n );\n }\n\n logger.info(\n {\n taskId: task.id,\n ticketId: task.ticketId,\n worktreePath,\n branchName,\n completed: chainResult.completed,\n failedPhase: chainResult.failedPhase,\n phaseCount: chainResult.phases.length,\n },\n \"worker-spawner: chain completed\",\n );\n\n // Theme 4 (Stage 5 Roadmap): chain が success で完走したのに tracker.pr_url が\n // 空ならば、Round 21 Meta-finding (worker の MCP tracker.update 漏れ) と同じ症状。\n // PR #106 の startup detector が「過去の race」を捕捉するのに対し、こちらは\n // 「直後の race」を捕捉するので、root cause 調査の証拠が確実に残る。失敗しても\n // chain 結果は変えない (verify はあくまで観測役)。\n if (chainResult.completed && !chainResult.failedPhase) {\n // Phase 2-S Step B (2026-05-15): pre_gate route 廃止。route は常に \"post_gate\"。\n const verifyFn =\n deps.verifyTrackerPostChain ?? defaultVerifyTrackerPostChain;\n const verifyOk = await verifyFn({\n ticketId: task.ticketId,\n taskId: task.id,\n branchName,\n });\n\n // file-based completion event (Stage 5 Theme 1 補助、push 通知用)。\n // DB events table とは別に local file に書き、statusLine が unread 件数を\n // 表示できるようにする。\n //\n // Round 21 Meta-finding 検出時は別 event 型を発火し、人間が statusLine の\n // unread 件数からも区別できるようにする (3b9a2bce / scope A)。\n if (verifyOk) {\n emitCompletionEvent({\n type: \"chain_completed\",\n ticketId: task.ticketId,\n projectId: task.projectId,\n at: new Date().toISOString(),\n message: `chain completed (${chainResult.phases.length} phases) on ${branchName}`,\n branchName,\n dispatcherInstanceId,\n });\n } else {\n emitCompletionEvent({\n type: \"chain_completed_no_pr\",\n ticketId: task.ticketId,\n projectId: task.projectId,\n at: new Date().toISOString(),\n message: `chain completed but tracker.pr_url is NULL (${chainResult.phases.length} phases) on ${branchName} — manual review required`,\n branchName,\n recommendedAction:\n \"Inspect commits on the worktree branch. If implementation is correct, push the branch and create a PR manually. If broken, discard the worktree. See memory: feedback_round21_pattern_human_judgment.md\",\n dispatcherInstanceId,\n });\n }\n }\n\n return {\n sessionId: firstPhase.sessionId,\n pid: 0, // chain-runner records each phase's pid; outer SpawnResult is post-chain\n taskId: task.id,\n chainResult,\n ...(staleness ? { staleness } : {}),\n };\n}\n","/**\n * Chain runner: dispatcher 経由 worker chain を sequential 実行する (DEC-114).\n *\n * Round 5 dogfood で発見した G-R5-1 (chain 継続) と G-R5-2 (commit silent skip)\n * の修正。worker-spawner が単一 phase (`/ticket-implement`) のみ spawn し、worker\n * 完了後に backlog status='in_progress' で固定されて chain が止まる問題を解決する。\n *\n * 各 phase で以下を実行:\n * 1. 新 worker_session を `running` で作成\n * 2. claude --print /ticket-<phase> <slug> を spawn し exit を await\n * 3. session を `completed` (or `failed`) に更新\n * 4. worktree 内の uncommitted changes があれば auto-commit (G-R5-2)\n * 5. ticket_tracker の phase を completed に更新\n *\n * 中途失敗時は次 phase を実行せず、result.completed=false で返す。\n * DEC-LO-24 resume protocol との整合: tracker phase 完了状態から次回 dispatcher\n * pickup 時に再開可能。\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { ChildProcess } from \"node:child_process\";\nimport { logger } from \"../logger.js\";\nimport { getOrchestratorClient } from \"./http-client.js\";\nimport type { ReadyTask } from \"./backlog-poller.js\";\nimport {\n buildAutoCommitMessage,\n buildPhaseSpawnArgs,\n PHASE_DEFS,\n phasesForRoute,\n type ChainPhase,\n} from \"./chain-runner-eval.js\";\nimport { emitCompletionEvent } from \"./event-emitter.js\";\nimport {\n detectProgress,\n haltReasonRelativePath,\n type ProgressSignals,\n} from \"./progress-detector.js\";\n\nexport type PhaseSpawnFn = (args: {\n args: readonly string[];\n cwd: string;\n env: NodeJS.ProcessEnv;\n logFd: number;\n}) => ChildProcess;\n\nexport type RunGitFn = (args: {\n args: readonly string[];\n cwd: string;\n}) => Promise<{ exitCode: number; stdout: string }>;\n\nexport type LogFdProvider = (sessionId: string) => number;\n\n/**\n * DB から phase 進捗シグナルを収集する関数の型 (Finding B β、DEC-132)。\n *\n * worktree commit は呼び出し側で別経路で観測するので、本関数は DB only。\n * テストでは inject して任意の進捗パターンを再現できる。\n */\nexport type GatherDbProgressFn = (args: {\n projectId: string;\n ticketId: string;\n startedAt: Date;\n /** phase キー (例: \"6_implement\"). tracker.phases[trackerKey].status の検査に使う。 */\n trackerKey: string;\n}) => Promise<{\n gateCreated: boolean;\n ticketDecisionAdded: boolean;\n ticketReviewAdded: boolean;\n ticketVerifyResultAdded: boolean;\n artifactNodeAdded: boolean;\n trackerPrUrlPresent: boolean;\n /**\n * ticket_tracker.phases[trackerKey].status === 'completed' か (ticket 58be8a8f)。\n * skill が `update_phase` で markedな証拠。implement / verify race への defense in depth。\n */\n trackerPhaseCompleted: boolean;\n}>;\n\n/**\n * `work/items/<ticketId>/HALT_REASON.md` を読む関数の型 (Tier 2 sentinel)。\n * 不在なら null を返す。\n */\nexport type ReadHaltReasonFn = (args: {\n worktreePath: string;\n ticketId: string;\n}) => string | null;\n\nexport type ChainRunnerDeps = {\n spawn: PhaseSpawnFn;\n runGit: RunGitFn;\n openLogFd: LogFdProvider;\n closeLogFd: (fd: number) => void;\n buildEnv: () => NodeJS.ProcessEnv;\n now: () => Date;\n /** DB 進捗シグナル収集 (Finding B、optional)。未指定なら本 module の default impl を使う。 */\n gatherDbProgress?: GatherDbProgressFn;\n /** HALT_REASON.md reader (Finding B、optional)。未指定なら本 module の default impl を使う。 */\n readHaltReason?: ReadHaltReasonFn;\n};\n\nexport type PhaseSessionResult = {\n phase: ChainPhase;\n sessionId: string;\n exitCode: number;\n durationMs: number;\n committed: boolean;\n /** Finding B β: phase 完了後に観測した進捗シグナル (halt path 含む全ケースで埋める) */\n progressEvidence?: readonly string[];\n /**\n * 既に完走済の phase を再実行時に spawn せず skip した場合に true。sessionId は\n * `skipped:<trackerKey>` 形式の sentinel で worker_session 実体は無い (DB row 作成しない)。\n * (旧 BL-6ffa82ba fix: pre_gate route 再実行ケース。Phase 2-S Step B で pre-gate 廃止後も、\n * post-gate 再実行ケース等で skip 経路は維持。)\n */\n skipped?: boolean;\n};\n\nexport type ChainRunResult = {\n phases: PhaseSessionResult[];\n completed: boolean;\n failedPhase: ChainPhase | null;\n /** Finding B β: halt 検出時のみ true。failedPhase と併せて agent_halt と process exit error を区別 */\n haltedByNoProgress?: boolean;\n};\n\n/**\n * 1 phase の spawn → wait → exit code 取得を Promise でラップする。\n *\n * detached: false (DEC-LO-12) を維持、shell: false (command injection 防止)。\n * 親プロセスが先に死んだ場合、child は SIGHUP で道連れになる前提。\n */\nasync function awaitPhaseExit(\n child: ChildProcess,\n): Promise<{ code: number | null; signal: NodeJS.Signals | null }> {\n return new Promise((resolve) => {\n let resolved = false;\n child.on(\"close\", (code, signal) => {\n if (resolved) return;\n resolved = true;\n resolve({ code, signal });\n });\n child.on(\"error\", () => {\n if (resolved) return;\n resolved = true;\n resolve({ code: 1, signal: null });\n });\n });\n}\n\n/**\n * Default DB 進捗シグナル収集 (Finding B β、DEC-132).\n * HTTP client 経由で server-side の gatherProgressSignals を呼ぶ。\n */\nasync function defaultGatherDbProgress(args: {\n projectId: string;\n ticketId: string;\n startedAt: Date;\n trackerKey: string;\n}): Promise<{\n gateCreated: boolean;\n ticketDecisionAdded: boolean;\n ticketReviewAdded: boolean;\n ticketVerifyResultAdded: boolean;\n artifactNodeAdded: boolean;\n trackerPrUrlPresent: boolean;\n trackerPhaseCompleted: boolean;\n}> {\n // Server-side `gatherProgressSignals` を呼んで DB シグナルを取得。\n // tracker phase status は別 endpoint (`getTrackerPhases`) で取得し、\n // ticket 58be8a8f race condition の defense in depth として合流させる。\n const [serverSignals, trackerPhases] = await Promise.all([\n getOrchestratorClient().gatherProgressSignals({\n projectId: args.projectId,\n ticketId: args.ticketId,\n startedAt: args.startedAt,\n }),\n getOrchestratorClient().getTrackerPhases(args.ticketId),\n ]);\n const trackerPhaseCompleted =\n trackerPhases[args.trackerKey]?.status === \"completed\";\n return {\n ...serverSignals,\n trackerPhaseCompleted,\n };\n}\n\n/**\n * Default HALT_REASON.md reader (Tier 2 sentinel、Finding B β、DEC-132).\n *\n * worktree 内 `work/items/<ticketId>/HALT_REASON.md` を同期 read。\n * 不在 / read 失敗時は null を返す (halt 自体は別経路で確定しているので、\n * reason 取得失敗で chain 判定を変えない)。\n */\nfunction defaultReadHaltReason(args: {\n worktreePath: string;\n ticketId: string;\n}): string | null {\n const path = join(args.worktreePath, haltReasonRelativePath(args.ticketId));\n try {\n if (!existsSync(path)) return null;\n return readFileSync(path, \"utf8\");\n } catch (err) {\n logger.warn(\n {\n path,\n err: err instanceof Error ? err.message : String(err),\n },\n \"chain-runner: HALT_REASON.md read failed (continuing without reason)\",\n );\n return null;\n }\n}\n\n/**\n * worktree の uncommitted changes を git status で検出。\n *\n * 戻り値: 変更ファイルが存在するか。\n */\nasync function hasUncommittedChanges(\n worktreePath: string,\n runGit: RunGitFn,\n): Promise<boolean> {\n const result = await runGit({\n args: [\"status\", \"--porcelain\"],\n cwd: worktreePath,\n });\n return result.stdout.trim().length > 0;\n}\n\n/**\n * worktree の変更を auto-commit する (G-R5-2 fix).\n *\n * git add -A で全変更を staging、message には ticket_id / phase / sessionId を含める。\n * 変更が無い場合は no-op (空 commit を作らない)。\n */\nasync function autoCommitPhaseChanges(args: {\n worktreePath: string;\n ticketId: string;\n phase: ChainPhase;\n sessionId: string;\n runGit: RunGitFn;\n}): Promise<boolean> {\n const { worktreePath, ticketId, phase, sessionId, runGit } = args;\n\n if (!(await hasUncommittedChanges(worktreePath, runGit))) {\n return false;\n }\n\n const addResult = await runGit({\n args: [\"add\", \"-A\"],\n cwd: worktreePath,\n });\n if (addResult.exitCode !== 0) {\n logger.error(\n { worktreePath, exitCode: addResult.exitCode, stdout: addResult.stdout },\n \"chain-runner: git add -A failed\",\n );\n return false;\n }\n\n const message = buildAutoCommitMessage(ticketId, phase, sessionId);\n const commitResult = await runGit({\n args: [\"commit\", \"-m\", message],\n cwd: worktreePath,\n });\n if (commitResult.exitCode !== 0) {\n logger.error(\n { worktreePath, exitCode: commitResult.exitCode, stdout: commitResult.stdout },\n \"chain-runner: git commit failed\",\n );\n return false;\n }\n\n return true;\n}\n\n/**\n * 1 phase の worker_session を作成し running で記録する。\n */\nasync function createPhaseSession(args: {\n task: ReadyTask;\n dispatcherInstanceId: string;\n phase: ChainPhase;\n worktreePath: string;\n branchName: string;\n startedAt: Date;\n}): Promise<string> {\n return getOrchestratorClient().createWorkerSession({\n projectId: args.task.projectId,\n dispatcherInstance: args.dispatcherInstanceId,\n dispatcherHost: process.env.HOSTNAME ?? \"localhost\",\n scope: args.task.scope,\n ticketSize: args.task.ticketSize,\n worktreePath: args.worktreePath,\n branchName: args.branchName,\n startedAt: args.startedAt,\n startEvent: {\n type: \"start\" as const,\n at: args.startedAt.toISOString(),\n phase: args.phase,\n },\n });\n}\n\n/**\n * worker_session の状態を更新する。\n */\nasync function finalizePhaseSession(args: {\n sessionId: string;\n status: \"completed\" | \"failed\";\n finalStatus: \"success\" | \"failed\";\n durationMs: number;\n completedAt: Date;\n}): Promise<void> {\n await getOrchestratorClient().updateWorkerSession(args.sessionId, {\n status: args.status,\n finalStatus: args.finalStatus,\n durationMs: args.durationMs,\n completedAt: args.completedAt,\n });\n}\n\n/**\n * ticket_tracker の phase を completed に更新する。\n */\nasync function updateTrackerPhaseCompleted(args: {\n ticketId: string;\n phase: ChainPhase;\n now: Date;\n}): Promise<void> {\n const trackerKey = PHASE_DEFS[args.phase].trackerKey;\n // currentPhase を次に進める (Phase 2-S Step B: pre_gate phase 廃止)。\n const trackerKeyToNum: Record<string, number> = {\n \"6_implement\": 7,\n \"7_verify\": 8,\n \"8_pr\": 9,\n };\n const nextPhase = trackerKeyToNum[trackerKey] ?? 9;\n\n await getOrchestratorClient().updateTrackerPhaseCompleted({\n ticketId: args.ticketId,\n trackerKey,\n nextPhase,\n now: args.now,\n });\n}\n\n/**\n * dispatcher chain runner のメインエントリポイント。\n *\n * task.ticketSize に応じた phase 列を順に実行し、各 phase 完了後に auto-commit\n * + tracker 更新を行う。中途失敗時は失敗 phase で停止し result.completed=false。\n *\n * 各 phase は独立した worker_session として記録され、観測性 (durationMs, exit code,\n * events) を保つ。DEC-LO-26 worker_sessions スキーマと整合。\n */\nexport async function runChainPhases(args: {\n task: ReadyTask;\n worktreePath: string;\n branchName: string;\n dispatcherInstanceId: string;\n deps: ChainRunnerDeps;\n}): Promise<ChainRunResult> {\n const { task, worktreePath, branchName, dispatcherInstanceId, deps } = args;\n // Phase 2-S Step B (2026-05-15): route は常に \"post_gate\"。pre_gate route 廃止。\n // 旧 task の互換のため route 未設定 / 旧 \"pre_gate\" は post_gate にフォールバック。\n const route = task.route ?? \"post_gate\";\n const phases = phasesForRoute(route, task.ticketSize);\n if (\n task.ticketSize !== \"S\" &&\n task.ticketSize !== \"M\" &&\n task.ticketSize !== \"L\"\n ) {\n logger.warn(\n { ticketId: task.ticketId, ticketSize: task.ticketSize },\n \"chain-runner: unknown ticketSize, falling back to S (no PR phase)\",\n );\n }\n const phaseResults: PhaseSessionResult[] = [];\n\n // BL-6ffa82ba fix: tracker.phases から既存 phase 状態を取得し、completed/skipped を skip。\n // 既に implement/verify が完走している場合 (再実行ケース) worker /ticket-implement は\n // no-op で exit するが progress-detector が「no progress」と誤検知して agent_halt を\n // 起こす可能性があるため、chain-runner 側で先回り skip することで誤検知を防止する。\n const initialPhaseStatuses = await getOrchestratorClient().getTrackerPhases(task.ticketId);\n\n // Finding 5 fix: skipped phase の sessionId は nil UUID。\n // Finding 2 fix の初版で `skipped:${trackerKey}` 形式の文字列を使ったが、\n // backlog_items.agent_session_id は uuid 型のため downstream 書き込みで PG エラー\n // (`invalid input syntax for type uuid`) が出た。nil UUID は valid UUID なので安全。\n // skipped フラグで「synthetic」判定可能。FK は agent_session_id に無い (schema 確認済)。\n const NIL_UUID = \"00000000-0000-0000-0000-000000000000\";\n\n for (const phase of phases) {\n const trackerKey = PHASE_DEFS[phase].trackerKey;\n const existingStatus = initialPhaseStatuses[trackerKey]?.status;\n if (existingStatus === \"completed\" || existingStatus === \"skipped\") {\n logger.info(\n { phase, trackerKey, existingStatus, ticketId: task.ticketId },\n \"chain-runner: skipping phase (already completed in prior chain)\",\n );\n phaseResults.push({\n phase,\n sessionId: NIL_UUID,\n exitCode: 0,\n durationMs: 0,\n committed: false,\n skipped: true,\n });\n continue;\n }\n\n const startedAt = deps.now();\n\n // 1. worker_session 作成\n const sessionId = await createPhaseSession({\n task,\n dispatcherInstanceId,\n phase,\n worktreePath,\n branchName,\n startedAt,\n });\n\n // 2. log fd 取得 + spawn\n const logFd = deps.openLogFd(sessionId);\n const child = deps.spawn({\n args: buildPhaseSpawnArgs(phase, task.ticketId),\n cwd: worktreePath,\n env: deps.buildEnv(),\n logFd,\n });\n\n // 3. PID 記録\n const pid = child.pid;\n if (pid) {\n await getOrchestratorClient().updateWorkerSession(sessionId, { workerPid: pid });\n }\n\n logger.info(\n {\n sessionId,\n pid,\n phase,\n taskId: task.id,\n ticketId: task.ticketId,\n worktreePath,\n },\n \"chain-runner: phase spawned\",\n );\n\n // 4. exit を await\n const { code, signal } = await awaitPhaseExit(child);\n deps.closeLogFd(logFd);\n const completedAt = deps.now();\n const durationMs = completedAt.getTime() - startedAt.getTime();\n const exitCode = code ?? -1;\n const isSuccess = code === 0;\n\n // 5. session を completed/failed に更新\n await finalizePhaseSession({\n sessionId,\n status: isSuccess ? \"completed\" : \"failed\",\n finalStatus: isSuccess ? \"success\" : \"failed\",\n durationMs,\n completedAt,\n });\n\n if (!isSuccess) {\n logger.warn(\n { sessionId, phase, code, signal, ticketId: task.ticketId },\n \"chain-runner: phase failed, stopping chain\",\n );\n phaseResults.push({\n phase,\n sessionId,\n exitCode,\n durationMs,\n committed: false,\n });\n return {\n phases: phaseResults,\n completed: false,\n failedPhase: phase,\n };\n }\n\n // 6. auto-commit (G-R5-2 fix)\n const committed = await autoCommitPhaseChanges({\n worktreePath,\n ticketId: task.ticketId,\n phase,\n sessionId,\n runGit: deps.runGit,\n });\n\n // 6.5 Finding B β (DEC-132): no-progress detection.\n // exit=0 + worktree clean だけだと「agent が halt 表明したが何も触らず exit」\n // ケースを silent に許してしまう。worktree commit / DB 新規 row /\n // tracker.pr_url の何れも観測されなければ implicit halt と判定し、\n // chain abort + agent_halt event 発火。HALT_REASON.md があれば payload に同梱。\n const dbProgressFn = deps.gatherDbProgress ?? defaultGatherDbProgress;\n const dbSignals = await dbProgressFn({\n projectId: task.projectId,\n ticketId: task.ticketId,\n startedAt,\n trackerKey,\n });\n const signals: ProgressSignals = {\n worktree_commit: committed,\n gate_created: dbSignals.gateCreated,\n ticket_decision: dbSignals.ticketDecisionAdded,\n ticket_review: dbSignals.ticketReviewAdded,\n ticket_verify_result: dbSignals.ticketVerifyResultAdded,\n artifact_node: dbSignals.artifactNodeAdded,\n tracker_pr_url: dbSignals.trackerPrUrlPresent,\n tracker_phase_completed: dbSignals.trackerPhaseCompleted,\n };\n const progress = detectProgress(phase, signals);\n\n if (!progress.hasProgress) {\n // Tier 2: agent が意図的 halt 時の reason 取得 (任意)。\n const readHaltReasonFn = deps.readHaltReason ?? defaultReadHaltReason;\n const haltReason = readHaltReasonFn({\n worktreePath,\n ticketId: task.ticketId,\n });\n\n logger.warn(\n {\n sessionId,\n phase,\n ticketId: task.ticketId,\n durationMs,\n committed,\n dbSignals,\n haltReason,\n },\n \"chain-runner: no progress detected after phase, halting chain (Finding B β)\",\n );\n\n // session を failed に上書き (5 で completed にした分を再 update)\n await finalizePhaseSession({\n sessionId,\n status: \"failed\",\n finalStatus: \"failed\",\n durationMs,\n completedAt,\n });\n\n // agent_halt event 発火 (statusLine inbox に届く)\n emitCompletionEvent({\n type: \"agent_halt\",\n ticketId: task.ticketId,\n projectId: task.projectId,\n at: deps.now().toISOString(),\n message: `agent halted in ${phase} phase: no progress observed (commit=${committed}, db signals all empty)`,\n phase,\n haltReason: haltReason ?? null,\n branchName,\n dispatcherInstanceId,\n recommendedAction:\n \"Inspect worker session log for halt reason. If agent intent was unclear, check work/items/<ticketId>/HALT_REASON.md.\",\n });\n\n phaseResults.push({\n phase,\n sessionId,\n exitCode,\n durationMs,\n committed,\n progressEvidence: progress.evidence,\n });\n\n return {\n phases: phaseResults,\n completed: false,\n failedPhase: phase,\n haltedByNoProgress: true,\n };\n }\n\n // 7. tracker phase 完了に更新\n await updateTrackerPhaseCompleted({\n ticketId: task.ticketId,\n phase,\n now: deps.now(),\n });\n\n logger.info(\n {\n sessionId,\n phase,\n ticketId: task.ticketId,\n durationMs,\n committed,\n progressEvidence: progress.evidence,\n },\n \"chain-runner: phase completed\",\n );\n\n phaseResults.push({\n phase,\n sessionId,\n exitCode,\n durationMs,\n committed,\n progressEvidence: progress.evidence,\n });\n }\n\n return {\n phases: phaseResults,\n completed: true,\n failedPhase: null,\n };\n}\n","/**\n * Pure phase ordering / decision logic for the dispatcher chain runner.\n *\n * I/O や DB 操作を含まないため単体テストしやすい。\n * I/O 統合は chain-runner.ts (Round 6 / DEC-114) を参照。\n */\n\nexport type TicketSize = \"S\" | \"M\" | \"L\";\nexport type ChainPhase = \"implement\" | \"verify\" | \"pr\";\n\n/**\n * dispatcher pickup の経路区分。\n *\n * Phase 2-S Step B (2026-05-15): pre_gate route は完全廃止。agent dispatch は post-gate のみ。\n * 型としては単一値だが、ReadyTask との互換性のため型エイリアスを残している。\n */\nexport type Route = \"post_gate\";\n\nexport type PhaseTrackerKey =\n | \"6_implement\"\n | \"7_verify\"\n | \"8_pr\";\n\n/**\n * Phase ごとの skill 名と tracker key の対応表。\n *\n * implement/verify/pr: post-gate chain (DEC-114)。\n * Phase 2-S Step B: pre_gate phase エントリは削除済み(agent は post-gate のみ受け付け)。\n */\nexport const PHASE_DEFS: Record<\n ChainPhase,\n { skill: string; trackerKey: PhaseTrackerKey }\n> = {\n implement: { skill: \"/ticket-implement\", trackerKey: \"6_implement\" },\n verify: { skill: \"/ticket-verify\", trackerKey: \"7_verify\" },\n pr: { skill: \"/ticket-pr\", trackerKey: \"8_pr\" },\n};\n\n/**\n * ticketSize から post-gate chain として実行すべき phase 列を決定する。\n *\n * - L: implement → verify → pr (フル chain)\n * - M: implement → verify → pr (フル chain、現状 L と同じ)\n * - S: implement → verify (PR なし、commit のみ — DEC-LO-30 の方針)\n * - null/不明: S 既定(意図しない PR 作成を防ぐ安全側フォールバック)\n *\n * S はサイズ別ワークフローに従い PR まで進めない(implement-lw / verify-lw を\n * 模倣)。M / L は本 chain runner で完走させる。\n */\nexport function phasesForSize(\n size: TicketSize | string | null,\n): readonly ChainPhase[] {\n if (size === \"M\" || size === \"L\") {\n return [\"implement\", \"verify\", \"pr\"] as const;\n }\n // S または不明なサイズは PR なし(安全側フォールバック)\n return [\"implement\", \"verify\"] as const;\n}\n\n/**\n * route と ticketSize から chain として実行すべき phase 列を決定する。\n *\n * Phase 2-S Step B 以降: route は常に \"post_gate\"。phasesForSize と同じ結果を返すが、\n * dispatcher 経路の API 互換性のため関数は残している。\n */\nexport function phasesForRoute(\n _route: Route | null | undefined,\n size: TicketSize | string | null,\n): readonly ChainPhase[] {\n return phasesForSize(size);\n}\n\n/**\n * 現在の tracker phase ステータスから、chain で次に実行すべき phase を返す。\n *\n * 未完了 phase が無ければ null(chain 完走済み)。\n *\n * @param phaseStatuses key=phase tracker key, value=\"pending\" | \"completed\" | \"skipped\"\n * @param phases 実行対象の phase 列(phasesForSize で取得)\n */\nexport function nextPendingPhase(\n phaseStatuses: Partial<Record<PhaseTrackerKey, \"pending\" | \"completed\" | \"skipped\">>,\n phases: readonly ChainPhase[],\n): ChainPhase | null {\n for (const phase of phases) {\n const trackerKey = PHASE_DEFS[phase].trackerKey;\n const status = phaseStatuses[trackerKey] ?? \"pending\";\n if (status !== \"completed\" && status !== \"skipped\") {\n return phase;\n }\n }\n return null;\n}\n\n/**\n * 自動 commit のメッセージを生成する。\n *\n * フォーマット: `chore(<ticketId>): auto-commit after <phase> phase (worker-session <sessionId>)`\n */\nexport function buildAutoCommitMessage(\n ticketId: string,\n phase: ChainPhase,\n sessionId: string,\n): string {\n return `chore(${ticketId}): auto-commit after ${phase} phase (worker-session ${sessionId})`;\n}\n\n/**\n * /ticket-<phase> <ticketId> の spawn 引数を組み立てる。\n *\n * worker-spawner の spawn 呼び出しと一致させるための単一ソース。\n */\nexport function buildPhaseSpawnArgs(\n phase: ChainPhase,\n ticketId: string,\n): readonly string[] {\n const skill = PHASE_DEFS[phase].skill;\n return [\"--print\", `${skill} ${ticketId}`] as const;\n}\n","// Stage 5 Theme 1 補助 — file-based completion event\n//\n// dispatcher が chain 完走 / PR auto-merge / 人手レビュー要 / conflict を観測した\n// タイミングで `~/.twin-build/events/` に 1 file ずつ JSON を書く。Claude Code の\n// statusLine (scripts/orchestrator-status-line.mjs) が cwd ベースではなく\n// この dir を ls して未読件数を 📬 で表示するため、push 通知相当を実現する。\n//\n// 設計:\n// - DB events table は永続監査用に残す (重複でも責務分離)\n// - file は ms 単位の read latency を担保 (statusLine が毎 prompt 実行)\n// - read = file 存在、ack = 明示削除 (ls しただけでは消えない)\n// - 7 日経過した未読は emit 時に自動削除 (orphan 防止)\n// - cross-platform (`os.homedir()` で Mac/Win/Linux 対応)\n// - test isolation: `TWIN_BUILD_EVENTS_DIR` env var で events dir を override 可能。\n// さらに vitest 実行中 (`VITEST=true`) は override 未設定なら emit を no-op に倒し、\n// test fixture が本番 inbox を汚染するのを構造的に防止する。\n//\n// EVENT TYPES (将来追加可、reader 側は unknown type も件数だけ数える):\n// - chain_completed worker chain 全 phase success かつ tracker.pr_url 設定済\n// - chain_completed_no_pr chain success だが tracker.pr_url is NULL (Round 21 Meta-finding)\n// - agent_halt chain-runner が phase 中で no-progress を検出 (Finding B β、DEC-132)\n// - pr_merged merge-gatekeeper auto-merge 成功\n// - pr_review_required ready_for_review tier\n// - pr_blocked human_required / blocked_conflict tier\n// - gate_decided Gate 決定 → 並行セッション人間に push 通知 (型12 PoC #1 F3 federation)\n// (Phase 2-S Step B / 2026-05-15: pre_gate_paused は廃止 — agent は post-gate のみ受け付け)\n\nimport { existsSync, mkdirSync, readdirSync, statSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { logger } from \"../logger.js\";\n\nexport type CompletionEventType =\n | \"chain_completed\"\n | \"chain_completed_no_pr\"\n | \"agent_halt\"\n | \"pr_merged\"\n | \"pr_review_required\"\n | \"pr_blocked\"\n | \"gate_decided\";\n\n/**\n * type 別 audience 固定マッピング。\n * human = 人間が statusLine で確認・ack すべきイベント。\n * ai = orchestrator が読めばよいイベント (statusLine badge から除外される)。\n * 後方互換: audience フィールドを持たない古い event ファイルは \"human\" として扱う。\n */\nexport const EVENT_AUDIENCE_MAP: Record<CompletionEventType, \"human\" | \"ai\"> = {\n chain_completed: \"human\",\n chain_completed_no_pr: \"human\",\n agent_halt: \"human\",\n pr_merged: \"human\",\n pr_review_required: \"human\",\n pr_blocked: \"human\",\n gate_decided: \"human\",\n};\n\nexport interface CompletionEvent {\n type: CompletionEventType;\n /** ticketId は dispatcher 系では tracker id、Gate 系では gateId を流用する (filename 衝突回避用 ID) */\n ticketId: string;\n /** project boundary を event に保持 (全 fact-table とも一致)。consumer が他プロジェクトの event を filter するために使う。 */\n projectId: string;\n /** ISO 8601 timestamp (emit 時刻) */\n at: string;\n /**\n * イベントの受信者。\n * \"human\" = statusLine に表示し人間が ack すべき。\n * \"ai\" = orchestrator が読めばよい (statusLine badge から除外)。\n * 未指定時は emitCompletionEvent が EVENT_AUDIENCE_MAP から自動補完する。\n * 後方互換: 古い event ファイルに audience が無い場合は \"human\" として扱う。\n */\n audience?: \"human\" | \"ai\";\n /** PR 番号 (chain_completed 時は null) */\n prNumber?: number | null;\n /** PR URL (同上) */\n prUrl?: string | null;\n /** 自由形式の補足。ヒューマン向けに読まれる */\n message?: string;\n /** dispatcher instance ID (debug 用) */\n dispatcherInstanceId?: string;\n /** worktree branch name (chain_completed_no_pr 等で worktree 場所の特定に使う) */\n branchName?: string | null;\n /** 人間向けの推奨アクション (chain_completed_no_pr で worker が PR を作らなかった場合の手順) */\n recommendedAction?: string;\n /** halt 発生 phase (agent_halt のみ) */\n phase?: string;\n /** Tier 2 sentinel `work/items/<ticketId>/HALT_REASON.md` の中身 (agent_halt のみ、agent が書いた場合のみ含まれる) */\n haltReason?: string | null;\n /** Gate uuid (gate_decided のみ。ticketId にも入るが明示用) */\n gateId?: string;\n /** GATE-xxx 表示 ID (gate_decided のみ、ヒューマン向け) */\n gateDisplayId?: string;\n /** 採択された option label (gate_decided のみ) */\n chosen?: string;\n /** Gate importance (gate_decided のみ、人間が重要 Gate を識別する用途) */\n importance?: \"high\" | \"medium\" | \"low\";\n}\n\nconst EXPIRY_MS = 7 * 24 * 60 * 60 * 1000; // 7 日\n\n/**\n * Known test fixture ticket ID patterns — events with these IDs in production\n * inbox indicate test pollution and can be cleaned up unconditionally.\n *\n * NOTE: 観測 (2026-05-03) で残置していた orphan の ticketId 群を初期セットとする。\n * 新規 fixture が追加されたら patterns も更新すること。\n */\nexport const ORPHAN_FIXTURE_PATTERNS: readonly RegExp[] = [\n /^t-\\d+$/, // merge-gatekeeper.test.ts: t-1, t-2\n /^stage3-claude-cli-worktree$/, // worker-spawner.test.ts\n /^round22-[a-z0-9-]+$/, // event-emitter.test.ts\n /^fresh$/, // event-emitter.test.ts (expire test)\n /^any$/, // event-emitter.test.ts (best-effort test)\n];\n\n/**\n * Resolve events directory. Honors `TWIN_BUILD_EVENTS_DIR` env var for test\n * isolation; falls back to `~/.twin-build/events/`.\n */\nfunction eventsDir(): string {\n const override = process.env.TWIN_BUILD_EVENTS_DIR;\n if (override && override.length > 0) return override;\n return join(homedir(), \".twin-build\", \"events\");\n}\n\n/**\n * vitest 実行中かつ `TWIN_BUILD_EVENTS_DIR` 未設定なら true。\n * 本番 inbox 汚染の最終防衛線として emit を no-op に倒すための判定。\n */\nfunction isUnsafeTestContext(): boolean {\n const inVitest = process.env.VITEST === \"true\" || process.env.NODE_ENV === \"test\";\n const hasOverride =\n typeof process.env.TWIN_BUILD_EVENTS_DIR === \"string\" &&\n process.env.TWIN_BUILD_EVENTS_DIR.length > 0;\n return inVitest && !hasOverride;\n}\n\nfunction ensureDir(): void {\n const dir = eventsDir();\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n}\n\n/**\n * 7 日超の未読 file を削除 (orphan 防止)。emit 時に best-effort で 1 度走る。\n * 失敗してもイベント発行自体は継続。\n */\nfunction expireOldEvents(): void {\n try {\n const dir = eventsDir();\n if (!existsSync(dir)) return;\n const cutoff = Date.now() - EXPIRY_MS;\n for (const entry of readdirSync(dir)) {\n if (!entry.endsWith(\".json\")) continue;\n const path = join(dir, entry);\n try {\n const stat = statSync(path);\n if (stat.mtimeMs < cutoff) {\n unlinkSync(path);\n }\n } catch {\n // 個別 file の expire 失敗は他に影響させない\n }\n }\n } catch (err) {\n logger.warn(\n { err: err instanceof Error ? err.message : String(err) },\n \"event-emitter: expireOldEvents failed (continuing)\",\n );\n }\n}\n\n/**\n * 1 イベントを `<eventsDir>/<ts>-<ticketId>-<type>.json` に書き出す。\n * eventsDir は `TWIN_BUILD_EVENTS_DIR` env var で override 可能、未設定時は\n * `~/.twin-build/events/`。失敗してもエラーを throw しない\n * (dispatcher の主処理を絶対に止めない)。\n *\n * vitest 実行中で override 未設定なら no-op (本番 inbox 汚染防止)。\n */\nexport function emitCompletionEvent(event: CompletionEvent): void {\n if (isUnsafeTestContext()) {\n return;\n }\n try {\n ensureDir();\n expireOldEvents();\n // audience が未指定なら type 別マッピングから補完する\n const eventWithAudience: CompletionEvent = event.audience !== undefined\n ? event\n : { ...event, audience: EVENT_AUDIENCE_MAP[event.type] ?? \"human\" };\n const ts = eventWithAudience.at.replace(/[^0-9]/g, \"\").slice(0, 14); // YYYYMMDDHHMMSS\n const safeTicket = eventWithAudience.ticketId.replace(/[^a-zA-Z0-9_-]/g, \"_\").slice(0, 60);\n const filename = `${ts}-${safeTicket}-${eventWithAudience.type}.json`;\n const path = join(eventsDir(), filename);\n writeFileSync(path, JSON.stringify(eventWithAudience, null, 2) + \"\\n\", { mode: 0o644 });\n } catch (err) {\n logger.warn(\n { err: err instanceof Error ? err.message : String(err), event },\n \"event-emitter: failed to write completion event (continuing)\",\n );\n }\n}\n\n/**\n * Events dir 内で test fixture らしい ticketId を持つ orphan file を削除する。\n * dispatcher 起動時に best-effort で 1 度走らせ、過去の test 漏れを掃除する。\n *\n * @returns 削除した file 数 (失敗時は 0)\n */\nexport function cleanupOrphans(\n patterns: readonly RegExp[] = ORPHAN_FIXTURE_PATTERNS,\n): number {\n let deleted = 0;\n try {\n const dir = eventsDir();\n if (!existsSync(dir)) return 0;\n for (const entry of readdirSync(dir)) {\n if (!entry.endsWith(\".json\")) continue;\n // filename は `<ts(14digits)>-<ticketId>-<type>.json`\n // ticketId は `[^a-zA-Z0-9_-]` を `_` に sanitize 済みなので、\n // パターンマッチには元の sanitize 済み形式を使う\n const match = entry.match(/^\\d{14}-(.+)-(chain_completed|chain_completed_no_pr|agent_halt|pr_merged|pr_review_required|pr_blocked|gate_decided|pre_gate_paused)\\.json$/);\n if (!match) continue;\n const ticketId = match[1];\n if (patterns.some((p) => p.test(ticketId))) {\n try {\n unlinkSync(join(dir, entry));\n deleted++;\n } catch {\n // 個別 file の削除失敗は他に影響させない\n }\n }\n }\n } catch (err) {\n logger.warn(\n { err: err instanceof Error ? err.message : String(err) },\n \"event-emitter: cleanupOrphans failed (continuing)\",\n );\n }\n return deleted;\n}\n","/**\n * Progress detection for chain-runner phases (Finding B β = E + A 併用、DEC-132).\n *\n * Tier 1 (E): no-progress detection — phase 完了後に worktree commit / DB 新規 row /\n * tracker フィールド更新の何れも無ければ implicit halt と判定する。agent 規約遵守を\n * 信頼せず、経験的シグナルだけで halt を捕捉する structural defense。\n *\n * Tier 2 (A): HALT_REASON.md sentinel file — agent が意図的 halt 時に reason を file\n * に書く規約。書かれていれば event payload に reason を載せる。書き忘れても Tier 1\n * が必ず検出するので defense in depth が成立。\n *\n * 本 module は pure logic のみを扱い、DB / fs I/O は呼び出し側 (chain-runner.ts) に\n * 任せる。これにより phase 別 progress 定義の test が容易になる。\n */\n\nimport type { ChainPhase } from \"./chain-runner-eval.js\";\n\n/**\n * 1 phase 中に観測しうる進捗シグナルの種別。\n *\n * - worktree_commit: chain-runner.autoCommitPhaseChanges が commit を作成した\n * - ticket_decision: ticket_decisions に project+ticket 一致の新規 row\n * - ticket_review: ticket_reviews に project+ticket 一致の新規 row\n * - ticket_verify_result: ticket_verify_results に project+ticket 一致の新規 row\n * - artifact_node: artifact_nodes に project 一致の新規 row (implement で生成される)\n * - tracker_pr_url: ticket_tracker.pr_url が phase 開始時から更新された (pr phase)\n * - tracker_phase_completed: ticket_tracker.phases[<phase>].status='completed' が set されている\n * (skill 内で `update_phase` MCP tool が呼ばれた証拠、ticket 58be8a8f\n * implement phase race condition への defense in depth)。pr phase では\n * DEC-140 で意図的に PR-creation を厳格化しているため使用しない。\n *\n * (Phase 2-S Step B / 2026-05-15: `gate_created` シグナルは pre_gate phase 廃止に伴い未使用化、\n * 互換性のため型からは保持。)\n */\nexport type PhaseProgressSignal =\n | \"worktree_commit\"\n | \"gate_created\"\n | \"ticket_decision\"\n | \"ticket_review\"\n | \"ticket_verify_result\"\n | \"artifact_node\"\n | \"tracker_pr_url\"\n | \"tracker_phase_completed\";\n\n/**\n * Phase 別に「何が起きたら進捗とみなすか」を定義する正典 table。\n *\n * いずれか 1 つでも観測されれば「進捗あり」と判定する (OR 結合)。\n *\n * - implement: コード変更 (commit) または ticket_decisions/ticket_reviews/\n * artifact_nodes 新規追加、あるいは tracker.phases.6_implement.status='completed'\n * (skill の `update_phase` 呼び出し)。design-only の implement でも何かしら残る。\n * - verify: verify-report の commit または ticket_verify_results 新規、あるいは\n * tracker.phases.7_verify.status='completed'。\n * - pr: tracker.pr_url 更新のみが正典シグナル (DEC-140、Round 21 pattern 構造解消)。\n * commit のみで通過させると Sub-pattern A (PR 作成 skip) を silent に許してしまう。\n * tracker_phase_completed も使わない (PR を作る前に completed を呼ぶ skill バグ\n * が将来出ても silent pass しない保証)。pr_url 更新がなければ Finding B β\n * no-progress detection が halt を発火する。\n * gh pr create が失敗した場合は worktree_commit が観測されても halt 扱い。\n *\n * implement / verify への tracker_phase_completed 追加は ticket 58be8a8f の race condition\n * (M2 d16f1178 2026-05-07 観測: tracker `completed_at` set と auto-commit の間で dispatcher\n * poll が走り false-positive halt) への defense in depth。実装が tracker phase を completed に\n * mark してさえいれば、commit 検出 race / 並行 dispatcher race / DB row 書き込み遅延いずれも\n * halt を防げる。\n *\n * (Phase 2-S Step B / 2026-05-15: pre_gate phase エントリは廃止。)\n */\nexport const PHASE_PROGRESS_SIGNALS: Record<\n ChainPhase,\n readonly PhaseProgressSignal[]\n> = {\n implement: [\n \"worktree_commit\",\n \"ticket_decision\",\n \"ticket_review\",\n \"artifact_node\",\n \"tracker_phase_completed\",\n ],\n verify: [\n \"worktree_commit\",\n \"ticket_verify_result\",\n \"tracker_phase_completed\",\n ],\n pr: [\"tracker_pr_url\"],\n} as const;\n\nexport type ProgressSignals = Partial<Record<PhaseProgressSignal, boolean>>;\n\nexport interface DetectedProgress {\n hasProgress: boolean;\n evidence: readonly PhaseProgressSignal[];\n}\n\n/**\n * 観測したシグナル集合から phase 進捗の有無を判定する。\n *\n * @param phase 対象 phase\n * @param signals 観測結果 (true のキーが「観測された」)。未指定キーは false 扱い。\n */\nexport function detectProgress(\n phase: ChainPhase,\n signals: ProgressSignals,\n): DetectedProgress {\n const expected = PHASE_PROGRESS_SIGNALS[phase];\n const evidence = expected.filter((sig) => signals[sig] === true);\n return {\n hasProgress: evidence.length > 0,\n evidence,\n };\n}\n\n/**\n * `work/items/<ticketId>/HALT_REASON.md` のパスを組み立てる (Tier 2 sentinel)。\n *\n * worktree 内の相対 path 規約: `work/items/<ticketId>/HALT_REASON.md`。\n * dispatcher が host から worktree に注入する `work/items/<ticketId>/` 配下に\n * agent が halt 表明として作成する。\n */\nexport function haltReasonRelativePath(ticketId: string): string {\n return `work/items/${ticketId}/HALT_REASON.md`;\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nexport type GitExec = (\n command: string,\n args: readonly string[],\n options?: { cwd?: string },\n) => Promise<{ stdout: string; stderr: string }>;\n\nconst defaultExec: GitExec = promisify(execFile) as GitExec;\n\nexport type AddWorktreeOptions = {\n worktreePath: string;\n branchName: string;\n baseRef: string;\n cwd?: string;\n exec?: GitExec;\n};\n\nexport type AddWorktreeResult = { path: string; branch: string };\n\nexport async function addWorktree(\n options: AddWorktreeOptions,\n): Promise<AddWorktreeResult> {\n const exec = options.exec ?? defaultExec;\n await exec(\n \"git\",\n [\n \"worktree\",\n \"add\",\n \"-b\",\n options.branchName,\n options.worktreePath,\n options.baseRef,\n ],\n { cwd: options.cwd },\n );\n return { path: options.worktreePath, branch: options.branchName };\n}\n\nexport type FetchRemoteOptions = {\n remote: string;\n ref: string;\n cwd?: string;\n exec?: GitExec;\n};\n\nexport async function fetchRemote(options: FetchRemoteOptions): Promise<void> {\n const exec = options.exec ?? defaultExec;\n await exec(\"git\", [\"fetch\", options.remote, options.ref], {\n cwd: options.cwd,\n });\n}\n\nexport type RemoveWorktreeOptions = {\n worktreePath: string;\n force?: boolean;\n cwd?: string;\n exec?: GitExec;\n};\n\nexport async function removeWorktree(\n options: RemoveWorktreeOptions,\n): Promise<void> {\n const exec = options.exec ?? defaultExec;\n const args = [\"worktree\", \"remove\"];\n if (options.force) args.push(\"--force\");\n args.push(options.worktreePath);\n await exec(\"git\", args, { cwd: options.cwd });\n}\n\nexport type Worktree = { path: string; branch: string | null; head: string };\n\nexport async function listWorktrees(\n options: { cwd?: string; exec?: GitExec } = {},\n): Promise<Worktree[]> {\n const exec = options.exec ?? defaultExec;\n const { stdout } = await exec(\"git\", [\"worktree\", \"list\", \"--porcelain\"], {\n cwd: options.cwd,\n });\n return parseWorktreeList(stdout);\n}\n\nexport function parseWorktreeList(stdout: string): Worktree[] {\n const results: Worktree[] = [];\n let current: Partial<Worktree> = {};\n const flush = () => {\n if (current.path !== undefined) {\n results.push({\n path: current.path,\n branch: current.branch ?? null,\n head: current.head ?? \"\",\n });\n }\n current = {};\n };\n\n for (const line of stdout.split(\"\\n\")) {\n if (line.startsWith(\"worktree \")) {\n flush();\n current.path = line.slice(\"worktree \".length);\n } else if (line.startsWith(\"HEAD \")) {\n current.head = line.slice(\"HEAD \".length);\n } else if (line.startsWith(\"branch \")) {\n current.branch = line.slice(\"branch refs/heads/\".length);\n } else if (line === \"detached\") {\n current.branch = null;\n } else if (line === \"\") {\n flush();\n }\n }\n flush();\n return results;\n}\n\nexport type WorktreeFailureCategory = \"transient\" | \"persistent\";\n\nexport type WorktreeFailure = {\n category: WorktreeFailureCategory;\n reason: string;\n};\n\nconst PERSISTENT_PATTERNS: readonly RegExp[] = [\n /already exists/i,\n /already used by worktree/i,\n /invalid reference/i,\n /not a valid object name/i,\n /is not a working tree/i,\n];\n\nexport function classifyWorktreeError(err: unknown): WorktreeFailure {\n const stderr =\n typeof err === \"object\" && err !== null && \"stderr\" in err\n ? String((err as { stderr: unknown }).stderr ?? \"\")\n : \"\";\n const message = err instanceof Error ? err.message : String(err);\n const combined = `${stderr}\\n${message}`;\n\n const isPersistent = PERSISTENT_PATTERNS.some((pattern) =>\n pattern.test(combined),\n );\n return {\n category: isPersistent ? \"persistent\" : \"transient\",\n reason: combined.trim(),\n };\n}\n","export type BlockerStatus = \"todo\" | \"in_progress\" | \"done\" | \"dropped\";\n\nexport type GateUnblockCandidate = {\n id: string;\n blockedBy: string[];\n};\n\nexport type GateUnblockWarning = {\n candidateId: string;\n reason: \"blocker_not_found\" | \"still_blocked_by_open_gate\";\n detail: string;\n};\n\nexport type GateUnblockInput = {\n candidates: GateUnblockCandidate[];\n blockerStatuses: Map<string, BlockerStatus>;\n openGateBacklogIds: Set<string>;\n};\n\nexport type GateUnblockResult = {\n unblockTargets: string[];\n warnings: GateUnblockWarning[];\n};\n\n/**\n * 採用条件 (DEC-103, B案): 候補 backlog ごとに以下を判定し、unblock 対象を決定する。\n * - 他の open Gate にまだブロックされていない (openGateBacklogIds にない)\n * - blocked_by 配列内のすべての参照先が done/dropped\n *\n * 参照先が見つからない場合は保守的に unblock しない (整合性破れを可視化)。\n */\nexport function evaluateGateUnblock(\n input: GateUnblockInput,\n): GateUnblockResult {\n const unblockTargets: string[] = [];\n const warnings: GateUnblockWarning[] = [];\n\n for (const cand of input.candidates) {\n if (input.openGateBacklogIds.has(cand.id)) {\n warnings.push({\n candidateId: cand.id,\n reason: \"still_blocked_by_open_gate\",\n detail: \"candidate is still referenced by an open gate's blockedItems\",\n });\n continue;\n }\n\n let allBlockersResolved = true;\n for (const blockerId of cand.blockedBy) {\n const status = input.blockerStatuses.get(blockerId);\n if (status === undefined) {\n warnings.push({\n candidateId: cand.id,\n reason: \"blocker_not_found\",\n detail: blockerId,\n });\n allBlockersResolved = false;\n break;\n }\n if (status !== \"done\" && status !== \"dropped\") {\n allBlockersResolved = false;\n break;\n }\n }\n\n if (allBlockersResolved) {\n unblockTargets.push(cand.id);\n }\n }\n\n return { unblockTargets, warnings };\n}\n\n/**\n * UUID v1-v5 形式判定 (G-R5-4 fix)。\n *\n * blockedItems.ref は backlog の UUID を期待するが、人間が手動 gate 作成した\n * 際に \"BL-42cdb221\" のような表示 ID を入れているケースがある。表示 ID を\n * `id IN ($1::uuid, ...)` クエリに渡すと PostgresError になり gate-watcher\n * cycle が失敗する。invalid 形式は extract 時点で除外する。\n */\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nexport function isUuid(value: string): boolean {\n return UUID_RE.test(value);\n}\n\n/**\n * decided gates の blockedItems(type=backlog) から候補 backlog ID を抽出する。\n * 重複は Set で除去。G-R5-4 fix: UUID 形式でない ref は invalidRefs に分離して\n * 返す (呼び出し側で warn ログを出せる)。\n */\nexport function extractCandidateIdsFromGates(\n gates: { id: string; blockedItems: unknown }[],\n): { ids: string[]; invalidRefs: { gateId: string; ref: string }[] } {\n const ids = new Set<string>();\n const invalidRefs: { gateId: string; ref: string }[] = [];\n for (const gate of gates) {\n if (!Array.isArray(gate.blockedItems)) continue;\n for (const item of gate.blockedItems) {\n if (\n item != null &&\n typeof item === \"object\" &&\n \"type\" in item &&\n \"ref\" in item &&\n (item as { type: unknown }).type === \"backlog\" &&\n typeof (item as { ref: unknown }).ref === \"string\"\n ) {\n const ref = (item as { ref: string }).ref;\n if (isUuid(ref)) {\n ids.add(ref);\n } else {\n invalidRefs.push({ gateId: gate.id, ref });\n }\n }\n }\n }\n return { ids: Array.from(ids), invalidRefs };\n}\n","import { logger } from \"../logger.js\";\nimport {\n findRecentlyDecidedGates,\n findCandidateBacklogs,\n findBlockerStatuses,\n findOpenGateBacklogIds,\n unblockBacklogItems,\n} from \"./backlog-poller.js\";\nimport {\n evaluateGateUnblock,\n extractCandidateIdsFromGates,\n} from \"./gate-watcher-eval.js\";\n\nexport type {\n BlockerStatus,\n GateUnblockCandidate,\n GateUnblockWarning,\n GateUnblockInput,\n GateUnblockResult,\n} from \"./gate-watcher-eval.js\";\nexport {\n evaluateGateUnblock,\n extractCandidateIdsFromGates,\n} from \"./gate-watcher-eval.js\";\n\n/**\n * dispatcher の cycle 内で呼び出される統合関数。\n *\n * - `lastCheckAt = null` で起動時 (safety net): 全 decided gate を一度評価\n * - 以後は `decided_at > lastCheckAt` の増分のみ評価\n *\n * 戻り値: 次サイクルで使う lastCheckAt (= 本サイクル開始時刻)\n */\nexport async function applyGateWatcher(\n lastCheckAt: Date | null,\n): Promise<Date> {\n const cycleStartAt = new Date();\n\n try {\n const decidedGates = await findRecentlyDecidedGates(lastCheckAt);\n if (decidedGates.length === 0) {\n return cycleStartAt;\n }\n\n const { ids: candidateIds, invalidRefs } =\n extractCandidateIdsFromGates(decidedGates);\n\n // G-R5-4 fix: UUID 形式でない ref は警告ログを出して skip\n if (invalidRefs.length > 0) {\n logger.warn(\n { invalidRefCount: invalidRefs.length, samples: invalidRefs.slice(0, 3) },\n \"gate-watcher: skipped non-UUID blockedItems.ref entries (likely display IDs like BL-XXX); fix gate creator to pass UUIDs\",\n );\n }\n\n if (candidateIds.length === 0) {\n logger.debug(\n { gateCount: decidedGates.length },\n \"gate-watcher: decided gates have no type=backlog blockedItems with UUID refs\",\n );\n return cycleStartAt;\n }\n\n const candidates = await findCandidateBacklogs(candidateIds);\n if (candidates.length === 0) {\n return cycleStartAt;\n }\n\n const blockerIds = new Set<string>();\n for (const cand of candidates) {\n for (const id of cand.blockedBy) blockerIds.add(id);\n }\n\n const blockerStatuses =\n blockerIds.size > 0\n ? await findBlockerStatuses(Array.from(blockerIds))\n : new Map();\n\n const openGateBacklogIds = await findOpenGateBacklogIds(\n candidates.map((c) => c.id),\n );\n\n const result = evaluateGateUnblock({\n candidates,\n blockerStatuses,\n openGateBacklogIds,\n });\n\n if (result.unblockTargets.length > 0) {\n await unblockBacklogItems(result.unblockTargets);\n logger.info(\n {\n gateCount: decidedGates.length,\n candidateCount: candidates.length,\n unblockCount: result.unblockTargets.length,\n },\n \"gate-watcher: unblocked backlog items\",\n );\n }\n\n if (result.warnings.length > 0) {\n logger.warn(\n { warnings: result.warnings },\n \"gate-watcher: warnings during unblock evaluation\",\n );\n }\n } catch (err) {\n logger.error({ err }, \"gate-watcher: cycle failed (continuing dispatcher)\");\n }\n\n return cycleStartAt;\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { z } from \"zod\";\nimport { logger } from \"../logger.js\";\nimport type { EligibleTicket, GatekeeperEventType, MergeStatusValue } from \"../usecases/orchestrator/merge-ops.js\";\nimport { getProjectIdFilter } from \"./config.js\";\nimport { emitCompletionEvent } from \"./event-emitter.js\";\nimport { getOrchestratorClient } from \"./http-client.js\";\nimport {\n evaluateMergePolicy,\n MERGE_TERMINAL_STATES,\n type CiState,\n type FileChange,\n type MergeStateStatus,\n type PrState,\n type PrSummary,\n} from \"./merge-policy-eval.js\";\n\nexport type GhExec = (\n command: string,\n args: readonly string[],\n options?: { cwd?: string },\n) => Promise<{ stdout: string; stderr: string }>;\n\nconst defaultExec: GhExec = promisify(execFile) as GhExec;\n\nconst PR_URL_RE =\n /^https:\\/\\/github\\.com\\/([^/]+)\\/([^/]+)\\/pull\\/(\\d+)$/;\n\n/** DEC-137 B案: harness 違反数ラベルのパターン */\nconst HARNESS_LABEL_RE = /^harness:violations-(\\d+)$/;\nconst HARNESS_VIOLATION_THRESHOLD = 3;\n\n/** `gh pr view --json` の出力 schema (DEC-LO-05 / B案 のコントラクトテスト対象)。 */\nconst GhPrViewSchema = z.object({\n number: z.number().int(),\n state: z.enum([\"OPEN\", \"CLOSED\", \"MERGED\"]),\n mergeStateStatus: z.enum([\n \"CLEAN\",\n \"BEHIND\",\n \"DIRTY\",\n \"BLOCKED\",\n \"UNKNOWN\",\n \"UNSTABLE\",\n ]),\n // GitHub の `statusCheckRollup` は2種類の entry が混在する:\n // - CheckRun (GitHub Actions 等): `status` (lifecycle) + `conclusion` (result)\n // - StatusContext (legacy commit status): `state` (フラット)\n // どちらも受け入れて aggregateCiState で正規化する。\n statusCheckRollup: z\n .array(\n z.object({\n __typename: z.string().optional(),\n state: z.string().optional(),\n status: z.string().optional(),\n conclusion: z.string().nullable().optional(),\n name: z.string().optional(),\n }),\n )\n .nullable(),\n files: z.array(\n z.object({\n path: z.string(),\n additions: z.number().int(),\n deletions: z.number().int(),\n }),\n ),\n additions: z.number().int(),\n deletions: z.number().int(),\n labels: z.array(z.object({ name: z.string() })),\n body: z.string().default(\"\"),\n});\n\nexport type GhPrView = z.infer<typeof GhPrViewSchema>;\n\nexport type { EligibleTicket };\n\nexport type MergeGatekeeperResult = {\n eligibleCount: number;\n processedCount: number;\n mergedCount: number;\n blockedCount: number;\n};\n\n/**\n * dispatcher cycle 末尾で呼ばれる統合関数。\n *\n * 1. 候補 PR (`prUrl != null` かつ terminal でない `mergeStatus`) を取得\n * 2. 各 PR を `gh pr view --json` で取得 → Zod parse\n * 3. `evaluateMergePolicy` で判定\n * 4. action に応じて `gh pr merge`, label 付与, status 更新\n *\n * 失敗は warn ログ + skip (dispatcher cycle を止めない、idempotent)。\n */\nexport async function applyMergeGatekeeper(\n exec: GhExec = defaultExec,\n): Promise<MergeGatekeeperResult> {\n const eligibles = await findEligibleTickets();\n if (eligibles.length === 0) {\n return {\n eligibleCount: 0,\n processedCount: 0,\n mergedCount: 0,\n blockedCount: 0,\n };\n }\n\n let processedCount = 0;\n let mergedCount = 0;\n let blockedCount = 0;\n\n for (const ticket of eligibles) {\n try {\n const handled = await processTicket(ticket, exec);\n if (handled.processed) processedCount++;\n if (handled.merged) mergedCount++;\n if (handled.blocked) blockedCount++;\n } catch (err) {\n logger.warn(\n { err, ticketId: ticket.ticketId, prUrl: ticket.prUrl },\n \"merge-gatekeeper: ticket processing failed (continuing)\",\n );\n }\n }\n\n if (processedCount === 0 && eligibles.length > 0) {\n logger.warn(\n { eligibleCount: eligibles.length },\n \"merge-gatekeeper: 0 PRs processed despite eligible candidates\",\n );\n }\n\n return {\n eligibleCount: eligibles.length,\n processedCount,\n mergedCount,\n blockedCount,\n };\n}\n\nasync function processTicket(\n ticket: EligibleTicket,\n exec: GhExec,\n): Promise<{ processed: boolean; merged: boolean; blocked: boolean }> {\n const locator = parsePrLocator(ticket.prUrl);\n if (locator === null) {\n logger.warn(\n { ticketId: ticket.ticketId, prUrl: ticket.prUrl },\n \"merge-gatekeeper: invalid PR URL format, skipping\",\n );\n return { processed: false, merged: false, blocked: false };\n }\n const prNumber = locator.number;\n const repo = `${locator.owner}/${locator.repo}`;\n\n let view: GhPrView;\n try {\n const { stdout } = await exec(\n \"gh\",\n [\n \"pr\",\n \"view\",\n String(prNumber),\n \"--repo\",\n repo,\n \"--json\",\n \"number,state,mergeStateStatus,statusCheckRollup,files,additions,deletions,labels,body\",\n ],\n );\n view = GhPrViewSchema.parse(JSON.parse(stdout));\n } catch (err) {\n logger.warn(\n { err, ticketId: ticket.ticketId, prNumber, repo },\n \"merge-gatekeeper: gh pr view failed or schema mismatch, skipping\",\n );\n return { processed: false, merged: false, blocked: false };\n }\n\n // DEC-137 B案: harness 違反ラベルチェック (evaluateMergePolicy より前に short-circuit)\n const violationCount = parseHarnessViolationCount(view.labels);\n if (violationCount === null) {\n logger.warn(\n { ticketId: ticket.ticketId, prNumber },\n \"merge-gatekeeper: no harness:violations-N label found — auto-continuing (fallback)\",\n );\n } else if (violationCount >= HARNESS_VIOLATION_THRESHOLD) {\n await tryPostHarnessComment(prNumber, repo, violationCount, exec);\n await markMergeStatus(ticket.id, \"manual_review\");\n await emitGatekeeperEvent(ticket, \"dispatcher.merge_blocked\", {\n prNumber,\n tier: \"manual_review\",\n reason: `harness violations: ${violationCount} >= ${HARNESS_VIOLATION_THRESHOLD}`,\n });\n emitCompletionEvent({\n type: \"pr_blocked\",\n ticketId: ticket.ticketId,\n projectId: ticket.projectId,\n at: new Date().toISOString(),\n prNumber,\n message: `PR #${prNumber} blocked: harness violations ${violationCount} >= threshold ${HARNESS_VIOLATION_THRESHOLD}`,\n });\n return { processed: true, merged: false, blocked: true };\n }\n\n const summary = toPrSummary(view);\n const decision = evaluateMergePolicy(summary);\n\n switch (decision.action.type) {\n case \"merge\": {\n await markMergeStatus(ticket.id, \"auto_merging\");\n try {\n await exec(\"gh\", [\n \"pr\",\n \"merge\",\n String(prNumber),\n \"--repo\",\n repo,\n \"--merge\",\n ]);\n await markMergeStatus(ticket.id, \"merged\");\n // DEC-129 (Round 20 Meta-finding): chain 完走 + PR auto-merge 後に\n // backlog_items.status を 'done' に flip する。これがないと\n // dispatcher.countRunningTasksByScope (backlog_items.status='in_progress' を\n // count) が永遠に古い値を返し、scope cap saturated で次 batch が dispatch\n // されない (Round 20 PROD で観測)。\n // flip は non-fatal: PR は既にマージ済みなのでエラーを merge 失敗として\n // 扱わず、次 cycle で zombie detection が拾う。\n try {\n await getOrchestratorClient().flipBacklogDone({\n trackerRowId: ticket.id,\n prUrl: ticket.prUrl,\n prBody: view.body,\n projectId: ticket.projectId,\n });\n } catch (flipErr) {\n logger.warn(\n { err: flipErr, ticketId: ticket.ticketId },\n \"merge-gatekeeper: flipBacklogDone failed (non-fatal, PR already merged)\",\n );\n }\n await emitGatekeeperEvent(ticket, \"dispatcher.merge_succeeded\", {\n prNumber,\n tier: decision.tier,\n reason: decision.reason,\n });\n emitCompletionEvent({\n type: \"pr_merged\",\n ticketId: ticket.ticketId,\n projectId: ticket.projectId,\n at: new Date().toISOString(),\n prNumber,\n message: `PR #${prNumber} auto-merged (tier=${decision.tier})`,\n });\n logger.info(\n { ticketId: ticket.ticketId, prNumber },\n \"merge-gatekeeper: PR merged\",\n );\n return { processed: true, merged: true, blocked: false };\n } catch (err) {\n logger.warn(\n { err, ticketId: ticket.ticketId, prNumber },\n \"merge-gatekeeper: gh pr merge failed, will re-evaluate next cycle\",\n );\n await markMergeStatus(ticket.id, \"pending\");\n return { processed: false, merged: false, blocked: false };\n }\n }\n case \"skip\": {\n const skipReason = decision.action.reason;\n if (skipReason === \"merged\") {\n await markMergeStatus(ticket.id, \"merged\");\n return { processed: true, merged: false, blocked: false };\n }\n if (skipReason === \"closed\") {\n await markMergeStatus(ticket.id, \"human_required\");\n await emitGatekeeperEvent(ticket, \"dispatcher.merge_blocked\", {\n prNumber,\n tier: decision.tier,\n reason: \"PR closed without merge\",\n });\n return { processed: true, merged: false, blocked: true };\n }\n // wait_ci / wait_behind / wait_unknown: 状態維持して次 cycle で再判定\n if (ticket.mergeStatus !== \"pending\") {\n await markMergeStatus(ticket.id, \"pending\");\n }\n return { processed: true, merged: false, blocked: false };\n }\n case \"label_human_required\": {\n await tryAddLabel(prNumber, repo, \"merge:human-required\", exec);\n // dedup: 同じ status への再評価では file event を emit しない (DB / label は冪等更新)\n const wasAlreadyHumanRequired = ticket.mergeStatus === \"human_required\";\n await markMergeStatus(ticket.id, \"human_required\");\n await emitGatekeeperEvent(ticket, \"dispatcher.merge_blocked\", {\n prNumber,\n tier: decision.tier,\n reason: decision.reason,\n });\n if (!wasAlreadyHumanRequired) {\n emitCompletionEvent({\n type: \"pr_review_required\",\n ticketId: ticket.ticketId,\n projectId: ticket.projectId,\n at: new Date().toISOString(),\n prNumber,\n message: `PR #${prNumber} requires human merge (tier=human_required: ${decision.reason})`,\n });\n }\n return { processed: true, merged: false, blocked: true };\n }\n case \"label_blocked_conflict\": {\n await tryAddLabel(prNumber, repo, \"merge:blocked-conflict\", exec);\n const wasAlreadyBlocked = ticket.mergeStatus === \"blocked_conflict\";\n await markMergeStatus(ticket.id, \"blocked_conflict\");\n await emitGatekeeperEvent(ticket, \"dispatcher.merge_blocked\", {\n prNumber,\n tier: decision.tier,\n reason: decision.reason,\n });\n if (!wasAlreadyBlocked) {\n emitCompletionEvent({\n type: \"pr_blocked\",\n ticketId: ticket.ticketId,\n projectId: ticket.projectId,\n at: new Date().toISOString(),\n prNumber,\n message: `PR #${prNumber} blocked by merge conflict — manual rebase required`,\n });\n }\n return { processed: true, merged: false, blocked: true };\n }\n case \"label_ready_for_review\": {\n await tryAddLabel(prNumber, repo, \"merge:ready-for-review\", exec);\n const wasAlreadyReady = ticket.mergeStatus === \"ready_for_review\";\n await markMergeStatus(ticket.id, \"ready_for_review\");\n await emitGatekeeperEvent(ticket, \"dispatcher.merge_blocked\", {\n prNumber,\n tier: decision.tier,\n reason: decision.reason,\n });\n if (!wasAlreadyReady) {\n emitCompletionEvent({\n type: \"pr_review_required\",\n ticketId: ticket.ticketId,\n projectId: ticket.projectId,\n at: new Date().toISOString(),\n prNumber,\n message: `PR #${prNumber} ready for human review (tier=ready_for_review)`,\n });\n }\n return { processed: true, merged: false, blocked: true };\n }\n }\n}\n\nasync function findEligibleTickets(): Promise<EligibleTicket[]> {\n return getOrchestratorClient().findEligibleTickets(getProjectIdFilter());\n}\n\nexport type PrLocator = { owner: string; repo: string; number: number };\n\n/**\n * PR URL から owner / repo / number を抽出する。\n * fork ベース開発で `gh` コマンドが upstream を解決してしまう問題を回避するため、\n * 全 gh 呼び出しで `--repo {owner}/{repo}` を渡せるようにする (DEC-LO-05 / fork-aware)。\n */\nexport function parsePrLocator(prUrl: string): PrLocator | null {\n const m = prUrl.match(PR_URL_RE);\n if (!m) return null;\n const n = Number.parseInt(m[3], 10);\n if (!Number.isFinite(n)) return null;\n return { owner: m[1], repo: m[2], number: n };\n}\n\nexport function parsePrNumber(prUrl: string): number | null {\n return parsePrLocator(prUrl)?.number ?? null;\n}\n\nexport function toPrSummary(view: GhPrView): PrSummary {\n return {\n number: view.number,\n state: view.state as PrState,\n mergeStateStatus: view.mergeStateStatus as MergeStateStatus,\n ciState: aggregateCiState(view.statusCheckRollup),\n files: view.files.map(\n (f): FileChange => ({\n path: f.path,\n additions: f.additions,\n deletions: f.deletions,\n }),\n ),\n additions: view.additions,\n deletions: view.deletions,\n };\n}\n\n/**\n * 個別 entry を `CiState` に正規化する。\n * - StatusContext (`state` あり): そのまま\n * - CheckRun (`status` + `conclusion`):\n * - `status !== COMPLETED` → PENDING\n * - `conclusion ∈ {SUCCESS, NEUTRAL, SKIPPED}` → SUCCESS(merge を阻害しない)\n * - 上記以外(FAILURE, TIMED_OUT, CANCELLED, ACTION_REQUIRED, STARTUP_FAILURE, STALE 等) → FAILURE\n * - どちらにも該当しない(不明 entry) → null(無視扱い)\n */\nfunction normalizeCheckEntry(entry: {\n state?: string;\n status?: string;\n conclusion?: string | null;\n}): CiState | null {\n if (entry.state) {\n if (\n entry.state === \"SUCCESS\" ||\n entry.state === \"FAILURE\" ||\n entry.state === \"PENDING\" ||\n entry.state === \"EXPECTED\" ||\n entry.state === \"ERROR\"\n ) {\n return entry.state;\n }\n return null;\n }\n if (entry.status) {\n if (entry.status !== \"COMPLETED\") return \"PENDING\";\n const c = entry.conclusion;\n if (c === \"SUCCESS\" || c === \"NEUTRAL\" || c === \"SKIPPED\") return \"SUCCESS\";\n if (!c) return \"PENDING\";\n return \"FAILURE\";\n }\n return null;\n}\n\n/**\n * `statusCheckRollup` を単一の `CiState` に集約する。\n * - null or 空配列 → null (CI 未設定 or 該当 check なし)\n * - 各 entry を normalizeCheckEntry で CiState に変換した後に集約\n * - いずれかが FAILURE/ERROR → その値\n * - いずれかが PENDING/EXPECTED → PENDING\n * - 全て SUCCESS → SUCCESS\n * - 有効な entry が一つもなければ null\n */\nexport function aggregateCiState(\n rollup: GhPrView[\"statusCheckRollup\"],\n): CiState | null {\n if (rollup === null || rollup.length === 0) return null;\n const states = rollup\n .map((c) => normalizeCheckEntry(c))\n .filter((s): s is CiState => s !== null);\n if (states.length === 0) return null;\n if (states.some((s) => s === \"FAILURE\")) return \"FAILURE\";\n if (states.some((s) => s === \"ERROR\")) return \"ERROR\";\n if (states.some((s) => s === \"PENDING\")) return \"PENDING\";\n if (states.some((s) => s === \"EXPECTED\")) return \"EXPECTED\";\n return \"SUCCESS\";\n}\n\nasync function markMergeStatus(rowId: string, status: MergeStatusValue): Promise<void> {\n await getOrchestratorClient().markMergeStatus(rowId, status);\n}\n\nconst UUID_V4_RE =\n /[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/gi;\n\n/**\n * PR body テキストから UUID v4 形式の文字列を全件抽出する。\n * backlog-hygiene-2: pr_merged 時に PR body から BL-uuid を取得するために使用。\n * UUID v4 に限定(version ビット `4` + variant ビット `[89ab]`)して誤マッチを防止。\n */\nexport function extractBlUuids(prBody: string): string[] {\n const matches = prBody.match(UUID_V4_RE);\n return matches ? [...new Set(matches.map((m) => m.toLowerCase()))] : [];\n}\n\n\n/**\n * DEC-137 B案: `harness:violations-N` ラベルから違反数を取得する。\n * 複数ラベルが共存する場合は最大値を採用(保守的)。\n * ラベルなしまたは parse 失敗は null を返す(fallback: auto 継続)。\n */\nexport function parseHarnessViolationCount(\n labels: Array<{ name: string }>,\n): number | null {\n let max: number | null = null;\n for (const { name } of labels) {\n const m = name.match(HARNESS_LABEL_RE);\n if (!m) continue;\n const n = parseInt(m[1], 10);\n if (isNaN(n)) continue;\n if (max === null || n > max) max = n;\n }\n return max;\n}\n\nasync function tryPostHarnessComment(\n prNumber: number,\n repo: string,\n count: number,\n exec: GhExec,\n): Promise<void> {\n try {\n await exec(\"gh\", [\n \"pr\",\n \"comment\",\n String(prNumber),\n \"--repo\",\n repo,\n \"--body\",\n `[harness] ${count} 件の違反が検出されました (threshold: ${HARNESS_VIOLATION_THRESHOLD})。手動レビューが必要です。`,\n ]);\n } catch (err) {\n logger.warn(\n { err, prNumber, repo },\n \"merge-gatekeeper: failed to post harness comment (non-fatal)\",\n );\n }\n}\n\nasync function tryAddLabel(\n prNumber: number,\n repo: string,\n label: string,\n exec: GhExec,\n): Promise<void> {\n try {\n await exec(\"gh\", [\n \"pr\",\n \"edit\",\n String(prNumber),\n \"--repo\",\n repo,\n \"--add-label\",\n label,\n ]);\n } catch (err) {\n logger.warn(\n { err, prNumber, repo, label },\n \"merge-gatekeeper: failed to add label (continuing)\",\n );\n }\n}\n\nasync function emitGatekeeperEvent(\n ticket: EligibleTicket,\n eventType: GatekeeperEventType,\n metadata: { prNumber: number; tier: string; reason: string },\n): Promise<void> {\n try {\n await getOrchestratorClient().emitGatekeeperEvent(ticket, eventType, metadata);\n } catch (err) {\n logger.warn(\n { err, ticketId: ticket.ticketId, eventType },\n \"merge-gatekeeper: failed to emit event (continuing)\",\n );\n }\n}\n\n// Internal helpers exported for tests\nexport const __internal = {\n parsePrLocator,\n parsePrNumber,\n toPrSummary,\n aggregateCiState,\n GhPrViewSchema,\n parseHarnessViolationCount,\n extractBlUuids,\n};\n","/**\n * merge-gatekeeper の純粋判定ロジック (Stage 5, DEC-LO-05 / DEC-LO-09)。\n *\n * 入力は I/O 層で `gh pr view` の出力から組み立てた `PrSummary`。\n * 副作用なしで `MergeDecision` を返す。matrix イテレーションテストで全 enum 組合せを網羅できる。\n */\n\nexport type MergeTier = \"auto\" | \"ready_for_review\" | \"human_required\" | \"manual_review\";\n\nexport type CiState =\n | \"SUCCESS\"\n | \"FAILURE\"\n | \"PENDING\"\n | \"EXPECTED\"\n | \"ERROR\";\n\nexport type MergeStateStatus =\n | \"CLEAN\"\n | \"BEHIND\"\n | \"DIRTY\"\n | \"BLOCKED\"\n | \"UNKNOWN\"\n | \"UNSTABLE\";\n\nexport type PrState = \"OPEN\" | \"CLOSED\" | \"MERGED\";\n\nexport type FileChange = {\n path: string;\n additions: number;\n deletions: number;\n};\n\nexport type PrSummary = {\n number: number;\n state: PrState;\n mergeStateStatus: MergeStateStatus;\n /** 集約済み CI 状態。`statusCheckRollup` が空配列または null の場合は `null` */\n ciState: CiState | null;\n files: FileChange[];\n additions: number;\n deletions: number;\n};\n\nexport type MergeAction =\n | { type: \"merge\"; prNumber: number }\n | {\n type: \"skip\";\n reason: \"merged\" | \"closed\" | \"wait_ci\" | \"wait_behind\" | \"wait_unknown\";\n }\n | { type: \"label_human_required\"; detail: string }\n | { type: \"label_blocked_conflict\"; detail: string }\n | { type: \"label_ready_for_review\"; detail: string };\n\nexport type MergeDecision = {\n action: MergeAction;\n tier: MergeTier;\n reason: string;\n};\n\n/**\n * Auto 自動マージ判定ポリシー (DEC-LO-05, DEC-LO-09)。\n *\n * - allowlist: 軽量な変更先(docs / outputs / *.test.ts / CLAUDE.md /\n * work/items/**.md)\n * - denylist: 必ず人手レビューが必要なクリティカル path\n * - maxFiles / maxLines: 境界値\n *\n * G-R8-1 (Round 8 dogfood discovery, 2026-04-29): chain-runner 駆動の dogfood\n * PR は `/ticket-implement → /ticket-verify → /ticket-pr` の各 phase で\n * `work/items/<slug>/{result.md, test.log, verify-report.md, pr-draft.md}` を\n * 自動生成・auto-commit する。これらを allowlist に含めないと、target docs を\n * 1 行変更しただけでも PR が allowlist 超過で Human-required に分類されてしまう。\n * orchestrator artifact として正規に allowlist に追加し、maxFiles / maxLines も\n * chain-runner artifact 数に合わせて調整する。\n *\n * scope-detector.ts と同様 RegExp 直書き(picomatch 等の依存は導入しない)。\n */\n/**\n * `merge_status` の terminal 状態。`findEligibleTickets` の WHERE 句で除外され、\n * 以後のサイクルでは再評価されない。`pending` と `auto_merging` は非 terminal\n * (次サイクルで再評価される — `auto_merging` は dispatcher 異常終了時に残存し得る)。\n */\nexport const MERGE_TERMINAL_STATES = [\n \"merged\",\n \"human_required\",\n \"blocked_conflict\",\n \"ready_for_review\",\n \"manual_review\",\n] as const;\n\nexport type MergeTerminalState = (typeof MERGE_TERMINAL_STATES)[number];\n\nexport const MERGE_POLICY = {\n allowlist: [\n /^outputs\\/.+\\.md$/,\n /^docs\\/.+\\.md$/,\n /^.+\\.test\\.ts$/,\n /^CLAUDE\\.md$/,\n // G-R8-1: chain-runner orchestrator artifacts\n // work/items/<slug>/{ticket,context,decision,result,test,verify-report,pr-draft}.md など\n // chain-runner が自動生成・auto-commit する作業履歴ファイル。\n // これらは worker の自律実行の証跡であり、人手レビュー不要の \"metadata\" 扱い。\n /^work\\/items\\/[^/]+\\/.+\\.md$/,\n /^work\\/items\\/[^/]+\\/test\\.log$/,\n /^work\\/items\\/[^/]+\\/decision\\.json$/,\n /^work\\/items\\/[^/]+\\/reviews\\/.+\\.md$/,\n ],\n denylist: [\n /^src\\/db\\//,\n /^drizzle\\//,\n /^package\\.json$/,\n /^package-lock\\.json$/,\n /^vite\\.config\\.ts$/,\n /^drizzle\\.config\\.ts$/,\n /^\\.claude\\//,\n /^\\.env(\\..*)?$/,\n /^\\.mcp\\.json$/,\n /^src\\/routes\\//,\n /^src\\/auth\\//,\n /^src\\/usecases\\//,\n /^scripts\\//,\n /^\\.github\\//,\n ],\n // G-R8-1: chain-runner driven PR は target docs (1) + work/items artifacts\n // (result.md, test.log, verify-report.md, pr-draft.md = 4) で 5 ファイルが\n // 自然な下限。さらに ticket.md / context.md / decision.md / reviews/*.md\n // が含まれるケースもあるため余裕を見て 8 を上限とする。\n maxFiles: 8,\n // G-R8-1: chain-runner artifacts は phase 別に詳細レポートを生成するため、\n // dogfood 規模 (Round 8 で計 281 行) を許容しつつ、本物の hand-coded 変更が\n // 急増しないよう 300 行で抑制。\n maxLines: 300,\n} as const satisfies {\n allowlist: readonly RegExp[];\n denylist: readonly RegExp[];\n maxFiles: number;\n maxLines: number;\n};\n\n/**\n * PR 1 件のマージ可否を評価する。副作用なし。\n *\n * 評価順序 (短絡):\n * 1. terminal state (MERGED/CLOSED)\n * 2. mergeStateStatus = DIRTY → blocked_conflict\n * 3. mergeStateStatus = BLOCKED → human_required (branch protection)\n * 4. CI = FAILURE/ERROR → human_required\n * 5. CI = PENDING/EXPECTED → wait_ci\n * 6. mergeStateStatus = BEHIND → wait_behind (CI 再実行待ち)\n * 7. mergeStateStatus = UNKNOWN/UNSTABLE → wait_unknown\n * 8. CLEAN + (CI=SUCCESS or null) → 3 層分類で tier 判定\n */\nexport function evaluateMergePolicy(pr: PrSummary): MergeDecision {\n if (pr.state === \"MERGED\") {\n return {\n action: { type: \"skip\", reason: \"merged\" },\n tier: \"auto\",\n reason: \"already merged\",\n };\n }\n if (pr.state === \"CLOSED\") {\n return {\n action: { type: \"skip\", reason: \"closed\" },\n tier: \"human_required\",\n reason: \"PR closed without merge\",\n };\n }\n\n if (pr.mergeStateStatus === \"DIRTY\") {\n return {\n action: { type: \"label_blocked_conflict\", detail: \"DIRTY (conflict)\" },\n tier: \"human_required\",\n reason: \"merge conflict\",\n };\n }\n\n if (pr.mergeStateStatus === \"BLOCKED\") {\n return {\n action: {\n type: \"label_human_required\",\n detail: \"BLOCKED by branch protection\",\n },\n tier: \"human_required\",\n reason: \"branch protection blocked\",\n };\n }\n\n if (pr.ciState === \"FAILURE\" || pr.ciState === \"ERROR\") {\n return {\n action: {\n type: \"label_human_required\",\n detail: `CI ${pr.ciState}`,\n },\n tier: \"human_required\",\n reason: `CI ${pr.ciState}`,\n };\n }\n\n if (pr.ciState === \"PENDING\" || pr.ciState === \"EXPECTED\") {\n return {\n action: { type: \"skip\", reason: \"wait_ci\" },\n tier: \"auto\",\n reason: \"CI pending\",\n };\n }\n\n if (pr.mergeStateStatus === \"BEHIND\") {\n return {\n action: { type: \"skip\", reason: \"wait_behind\" },\n tier: \"auto\",\n reason: \"BEHIND (waiting for sync)\",\n };\n }\n\n if (\n pr.mergeStateStatus === \"UNKNOWN\" ||\n pr.mergeStateStatus === \"UNSTABLE\"\n ) {\n return {\n action: { type: \"skip\", reason: \"wait_unknown\" },\n tier: \"auto\",\n reason: `mergeStateStatus=${pr.mergeStateStatus}`,\n };\n }\n\n // CLEAN かつ CI=SUCCESS or null\n const tier = classifyTier(pr);\n if (tier === \"human_required\") {\n return {\n action: {\n type: \"label_human_required\",\n detail: \"denylist hit\",\n },\n tier,\n reason: \"file path matches denylist\",\n };\n }\n if (tier === \"ready_for_review\") {\n return {\n action: {\n type: \"label_ready_for_review\",\n detail: \"exceeds auto threshold\",\n },\n tier,\n reason: \"files/lines/allowlist threshold exceeded\",\n };\n }\n return {\n action: { type: \"merge\", prNumber: pr.number },\n tier: \"auto\",\n reason: \"all auto criteria met\",\n };\n}\n\n/**\n * 3 層分類 (CLEAN + CI=SUCCESS/null 前提)。\n * denylist 優先で short-circuit。\n */\nfunction classifyTier(pr: PrSummary): MergeTier {\n if (\n pr.files.some((f) =>\n MERGE_POLICY.denylist.some((re) => re.test(f.path)),\n )\n ) {\n return \"human_required\";\n }\n if (\n !pr.files.every((f) =>\n MERGE_POLICY.allowlist.some((re) => re.test(f.path)),\n )\n ) {\n return \"ready_for_review\";\n }\n if (pr.files.length > MERGE_POLICY.maxFiles) {\n return \"ready_for_review\";\n }\n if (pr.additions + pr.deletions > MERGE_POLICY.maxLines) {\n return \"ready_for_review\";\n }\n return \"auto\";\n}\n","/**\n * `npx twin-build init` — 新規プロジェクト初期化。\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §3-§6\n *\n * 動作:\n * 1. `.twin-build.json` を生成 (4 軸 pin + integrity sha256 + history 初期 entry)\n * 2. `.claude/settings.json` を deep merge (statusLine / extraKnownMarketplaces / enabledPlugins)\n * 3. `.gitattributes` を追記 (`.claude/settings.json merge=json`)\n * 4. `.twin-build/cache/.gitignore` を生成\n * 5. 初回 doctor (lightweight)\n * 6. Plugin install 案内 / `/init` skill 案内を表示\n */\n\nimport { createHash } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n} from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\nimport { ensureCacheStructure, ensureGitignoreEntry } from \"./lib/cache-base.js\";\nimport {\n detectInstalledPluginVersion,\n orchestrateFallbackStatusLinePath,\n pluginStatusLinePath,\n} from \"./lib/paths.js\";\nimport {\n type JsonObject,\n type JsonValue,\n mergeSettings,\n stringifySettings,\n} from \"./lib/settings-json.js\";\n\nexport interface InitOptions {\n /** Repository root (default: process.cwd()). */\n repoRoot: string;\n /** Project name; defaults to basename(repoRoot). */\n projectName?: string;\n /** Pinned versions (4-axis). Required for non-interactive init. */\n pluginVersion: string;\n cliVersion: string;\n rulesSchemaVersion: string;\n mcpToolSchemaVersion?: string;\n /** Override link strategy (default: auto). */\n linkStrategy?: \"symlink\" | \"copy\";\n /** Pre-detected marketplace path for `extraKnownMarketplaces`. */\n marketplacePath?: string;\n /** Override $HOME for tests. */\n home?: string;\n /** When true, do not write files — return what would be written. */\n dryRun?: boolean;\n /**\n * CI / non-interactive mode (P3-F).\n * - Skip every prompt; require all pinned versions to be supplied up-front\n * (Phase 2 §9.1 T1-5)\n * - Emit `.devcontainer/devcontainer.json` template so the project\n * immediately works in Codespaces / VS Code Remote (T1-6)\n * - Fail-fast on incompatible versions (CI exits non-zero) — enforced by\n * the caller via the same `compatibility.json` check used by `migrate`\n */\n ci?: boolean;\n}\n\nexport interface InitResult {\n projectName: string;\n twinBuildJson: TwinBuildJsonDoc;\n settingsJson: JsonObject;\n filesWritten: string[];\n warnings: string[];\n}\n\nexport interface TwinBuildJsonDoc {\n projectName: string;\n twinBuild: {\n pluginVersion: string;\n cliVersion: string;\n rulesSchemaVersion: string;\n mcpToolSchemaVersion?: string;\n linkStrategy: \"symlink\" | \"copy\";\n integrity: {\n pluginVersion: string;\n cliVersion: string;\n rulesSchemaVersion: string;\n };\n history: Array<{\n at: string;\n pluginVersion: string;\n cliVersion: string;\n rulesSchemaVersion: string;\n mcpToolSchemaVersion?: string;\n }>;\n };\n}\n\nconst TWIN_BUILD_JSON = \".twin-build.json\";\nconst SETTINGS_JSON = \".claude/settings.json\";\nconst GITATTRIBUTES = \".gitattributes\";\n\n/** Default link strategy: symlink on POSIX, copy on Windows native. */\nexport function defaultLinkStrategy(): \"symlink\" | \"copy\" {\n return process.platform === \"win32\" ? \"copy\" : \"symlink\";\n}\n\n/**\n * Compute the SHA-256 integrity hash for one axis value.\n * (4-axis pin の手書き編集検知用。横断警告 #1)\n */\nexport function integrityHash(value: string): string {\n return \"sha256:\" + createHash(\"sha256\").update(value, \"utf8\").digest(\"hex\");\n}\n\n/**\n * Build the `.twin-build.json` document for first-time init.\n */\nexport function buildTwinBuildJson(opts: InitOptions): TwinBuildJsonDoc {\n const projectName = opts.projectName ?? basename(opts.repoRoot);\n const linkStrategy = opts.linkStrategy ?? defaultLinkStrategy();\n const at = new Date().toISOString();\n return {\n projectName,\n twinBuild: {\n pluginVersion: opts.pluginVersion,\n cliVersion: opts.cliVersion,\n rulesSchemaVersion: opts.rulesSchemaVersion,\n mcpToolSchemaVersion: opts.mcpToolSchemaVersion,\n linkStrategy,\n integrity: {\n pluginVersion: integrityHash(opts.pluginVersion),\n cliVersion: integrityHash(opts.cliVersion),\n rulesSchemaVersion: integrityHash(opts.rulesSchemaVersion),\n },\n history: [\n {\n at,\n pluginVersion: opts.pluginVersion,\n cliVersion: opts.cliVersion,\n rulesSchemaVersion: opts.rulesSchemaVersion,\n mcpToolSchemaVersion: opts.mcpToolSchemaVersion,\n },\n ],\n },\n };\n}\n\n/**\n * Build the `.claude/settings.json` additions for first-time init.\n * Deep-merges with existing user settings (existing values win).\n */\nexport function buildSettingsAdditions(opts: InitOptions): JsonObject {\n const installedPluginVersion = detectInstalledPluginVersion(opts.home);\n const statusLineCommand =\n installedPluginVersion\n ? pluginStatusLinePath(installedPluginVersion, opts.home)\n : orchestrateFallbackStatusLinePath(opts.repoRoot);\n\n const marketplacePath = opts.marketplacePath;\n const additions: JsonObject = {\n statusLine: {\n type: \"command\",\n command: `node ${statusLineCommand}`,\n padding: 1,\n },\n };\n if (marketplacePath) {\n additions.extraKnownMarketplaces = {\n \"twin-build-marketplace\": {\n source: {\n source: \"directory\",\n path: marketplacePath,\n },\n },\n };\n }\n additions.enabledPlugins = {\n \"twin-build@twin-build-marketplace\": true,\n };\n return additions;\n}\n\n/**\n * Execute `init` end-to-end. Returns the documents written + warnings.\n * Pure-ish: all filesystem effects flow through opts.repoRoot.\n */\nexport async function runInit(opts: InitOptions): Promise<InitResult> {\n const projectName = opts.projectName ?? basename(opts.repoRoot);\n const warnings: string[] = [];\n const filesWritten: string[] = [];\n\n // 1. .twin-build.json — refuse if already initialized with twinBuild block.\n const twinBuildJsonPath = join(opts.repoRoot, TWIN_BUILD_JSON);\n let existingTwinBuild: Partial<TwinBuildJsonDoc> | null = null;\n if (existsSync(twinBuildJsonPath)) {\n try {\n existingTwinBuild = JSON.parse(\n readFileSync(twinBuildJsonPath, \"utf8\"),\n ) as Partial<TwinBuildJsonDoc>;\n } catch (err) {\n warnings.push(\n `existing .twin-build.json could not be parsed: ${err instanceof Error ? err.message : String(err)}. Overwriting.`,\n );\n }\n }\n if (existingTwinBuild?.twinBuild) {\n throw new Error(\n \"This project already has .twin-build.json with a twinBuild block. \" +\n \"Use `twin-build sync` to update versions, or `twin-build doctor --repair` to fix drift.\",\n );\n }\n\n const newDoc = buildTwinBuildJson({ ...opts, projectName });\n // Preserve unknown keys (e.g. legacy `projectName` only files might carry\n // user-extended fields).\n const merged: TwinBuildJsonDoc = {\n ...(existingTwinBuild as JsonObject),\n ...newDoc,\n } as TwinBuildJsonDoc;\n\n if (!opts.dryRun) {\n writeFileSync(\n twinBuildJsonPath,\n JSON.stringify(merged, null, 2) + \"\\n\",\n \"utf8\",\n );\n filesWritten.push(TWIN_BUILD_JSON);\n }\n\n // 2. .claude/settings.json — deep merge\n const settingsPath = join(opts.repoRoot, SETTINGS_JSON);\n let existingSettings: JsonValue = {};\n if (existsSync(settingsPath)) {\n try {\n existingSettings = JSON.parse(readFileSync(settingsPath, \"utf8\")) as JsonValue;\n } catch (err) {\n warnings.push(\n `.claude/settings.json could not be parsed; keeping additions only (${err instanceof Error ? err.message : String(err)})`,\n );\n existingSettings = {};\n }\n }\n const additions = buildSettingsAdditions(opts);\n const mergedSettings = mergeSettings(existingSettings, additions);\n if (!opts.dryRun) {\n mkdirSync(dirname(settingsPath), { recursive: true });\n writeFileSync(settingsPath, stringifySettings(mergedSettings), \"utf8\");\n filesWritten.push(SETTINGS_JSON);\n }\n\n // 3. .gitattributes — append `.claude/settings.json merge=json`\n if (!opts.dryRun) {\n ensureGitignoreEntry(\n opts.repoRoot,\n \".claude/settings.json merge=json\",\n join(opts.repoRoot, GITATTRIBUTES),\n );\n filesWritten.push(GITATTRIBUTES);\n }\n\n // 4. .twin-build/cache/ structure (gitignored base/)\n if (!opts.dryRun) {\n ensureCacheStructure(opts.repoRoot);\n filesWritten.push(\".twin-build/cache/.gitignore\");\n }\n\n // 5. .devcontainer/ template (P3-F, ci mode only — opt-in to avoid touching\n // projects that already curate their own devcontainer/Codespaces setup).\n if (opts.ci) {\n if (!opts.dryRun) {\n const devcontainerWritten = writeDevcontainerTemplate(opts.repoRoot);\n filesWritten.push(...devcontainerWritten);\n } else {\n filesWritten.push(\n \".devcontainer/devcontainer.json\",\n \".devcontainer/post-create.sh\",\n );\n }\n }\n\n return {\n projectName,\n twinBuildJson: merged,\n settingsJson: mergedSettings as JsonObject,\n filesWritten,\n warnings,\n };\n}\n\n/**\n * Write `.devcontainer/devcontainer.json` + `post-create.sh` template.\n * Does not overwrite existing files — projects that already curate their own\n * devcontainer keep their version (P3-F principle: opt-in additions only).\n * Returns the list of file paths that were actually written.\n */\nfunction writeDevcontainerTemplate(repoRoot: string): string[] {\n const written: string[] = [];\n const devcontainerDir = join(repoRoot, \".devcontainer\");\n mkdirSync(devcontainerDir, { recursive: true });\n\n const jsonPath = join(devcontainerDir, \"devcontainer.json\");\n if (!existsSync(jsonPath)) {\n writeFileSync(jsonPath, DEVCONTAINER_JSON, \"utf8\");\n written.push(\".devcontainer/devcontainer.json\");\n }\n\n const scriptPath = join(devcontainerDir, \"post-create.sh\");\n if (!existsSync(scriptPath)) {\n writeFileSync(scriptPath, DEVCONTAINER_POST_CREATE_SH, { mode: 0o755 });\n written.push(\".devcontainer/post-create.sh\");\n }\n\n return written;\n}\n\n/**\n * Minimum-viable devcontainer config for twin-build projects.\n * - Node 20 LTS (matches @twin-build-orchestrate/cli engine constraint)\n * - GitHub CLI feature (used by `migrate` for draft PR creation)\n * - post-create hook: install deps + run doctor to verify the setup\n *\n * The hook is invoked through `bash -c` with `chmod +x` baked in, so that\n * Windows-checked-out clones (where executable bits are not preserved in NTFS)\n * still run the script. This avoids the classic devcontainer pitfall where\n * `postCreateCommand: \"./post-create.sh\"` silently no-ops on Windows hosts.\n *\n * Project owners are expected to extend with their own language/runtime\n * features (Python, Go etc.) on top of this baseline.\n */\nconst DEVCONTAINER_JSON = `{\n \"name\": \"twin-build project\",\n \"image\": \"mcr.microsoft.com/devcontainers/javascript-node:20\",\n \"features\": {\n \"ghcr.io/devcontainers/features/github-cli:1\": {}\n },\n \"postCreateCommand\": \"chmod +x .devcontainer/post-create.sh && bash .devcontainer/post-create.sh\",\n \"remoteUser\": \"node\"\n}\n`;\n\nconst DEVCONTAINER_POST_CREATE_SH = `#!/usr/bin/env bash\n# Codespaces / VS Code Remote 用 post-create hook (P3-F)\n# - npm 依存をインストール\n# - twin-build doctor で symlink / integrity の健全性を確認\n# Plugin install は image build 時に実行不能なので、Codespaces 起動後に\n# ユーザーが Claude Code の /plugin Marketplace から手動 install する。\nset -euo pipefail\n\nnpm ci || npm install\n\nif command -v npx >/dev/null 2>&1; then\n npx --no-install twin-build doctor || true\nfi\n\necho\necho \"twin-build devcontainer ready.\"\necho \"次のステップ: Claude Code で /plugin install twin-build を実行してください。\"\n`;\n\n/**\n * Render a human-readable next-step message for after init.\n */\nexport function renderInitNextSteps(result: InitResult): string {\n const wroteGitattributes = result.filesWritten.includes(GITATTRIBUTES);\n const lines = [\n `✓ twin-build initialised in ${result.projectName}`,\n \"\",\n \"Files written:\",\n ...result.filesWritten.map((f) => ` - ${f}`),\n \"\",\n \"Next steps:\",\n \" 1. Install the Plugin (Claude Code → /plugin Marketplace → twin-build).\",\n \" 2. Run `/init` inside Claude Code to configure rules.\",\n \" 3. Run `npx twin-build doctor` to verify the setup.\",\n ];\n if (wroteGitattributes) {\n lines.push(\n \"\",\n \"Optional — register the `json` merge driver so `.gitattributes` takes effect:\",\n \" git config merge.json.name 'JSON merge driver (preserves user keys)'\",\n \" git config merge.json.driver 'npx twin-build doctor --fix --merge-json %A %O %B'\",\n \" (without this, `merge=json` in .gitattributes is a no-op and git falls back to the default text merge)\",\n );\n }\n if (result.warnings.length > 0) {\n lines.push(\"\", \"Warnings:\");\n for (const w of result.warnings) lines.push(` ⚠ ${w}`);\n }\n return lines.join(\"\\n\");\n}\n","/**\n * `.twin-build/cache/base/` の取得・管理。\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §6 (Cache 配置と git ポリシー)\n *\n * - `.twin-build/cache/upstream-version.json` ← git commit する (compatibility check の根拠)\n * - `.twin-build/cache/base/` ← gitignore (再現可能 / ノイズ)\n *\n * 不在時 fallback: `npm view @twin-build-orchestrate/cli@<recorded-version>` で再取得。\n */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n appendFileSync,\n} from \"node:fs\";\nimport { dirname, join, relative } from \"node:path\";\n\nexport const CACHE_DIR = \".twin-build/cache\";\nexport const BASE_DIR = \".twin-build/cache/base\";\nexport const UPSTREAM_VERSION_FILE = \".twin-build/cache/upstream-version.json\";\n\nexport interface UpstreamVersionRecord {\n pluginVersion: string;\n cliVersion: string;\n rulesSchemaVersion: string;\n mcpToolSchemaVersion?: string;\n upstreamCommitSha?: string;\n syncedAt: string;\n}\n\n/** Ensure `.twin-build/cache/` exists + `base/` is gitignored. */\nexport function ensureCacheStructure(repoRoot: string): void {\n const cachePath = join(repoRoot, CACHE_DIR);\n const basePath = join(repoRoot, BASE_DIR);\n mkdirSync(basePath, { recursive: true });\n ensureGitignoreEntry(repoRoot, \"base/\", join(cachePath, \".gitignore\"));\n}\n\n/**\n * Append `entry` to a `.gitignore`-style file unless already present.\n * Idempotent.\n */\nexport function ensureGitignoreEntry(\n _repoRoot: string,\n entry: string,\n gitignorePath: string,\n): void {\n let existing = \"\";\n if (existsSync(gitignorePath)) {\n existing = readFileSync(gitignorePath, \"utf8\");\n const lines = existing.split(/\\r?\\n/).map((l) => l.trim());\n if (lines.includes(entry.trim())) return;\n }\n const needsNewline = existing.length > 0 && !existing.endsWith(\"\\n\");\n appendFileSync(\n gitignorePath,\n (needsNewline ? \"\\n\" : \"\") + entry + \"\\n\",\n \"utf8\",\n );\n}\n\n/**\n * Read base content for a tracked file at the last-recorded upstream version.\n * Returns `null` if cache miss — caller should fetch from npm and call\n * `writeBaseContent`.\n */\nexport function readBaseContent(\n repoRoot: string,\n relPath: string,\n): string | null {\n const fullPath = join(repoRoot, BASE_DIR, relPath);\n if (!existsSync(fullPath)) return null;\n return readFileSync(fullPath, \"utf8\");\n}\n\n/** Write base content for a tracked file. Creates parent dirs as needed. */\nexport function writeBaseContent(\n repoRoot: string,\n relPath: string,\n content: string,\n): void {\n const fullPath = join(repoRoot, BASE_DIR, relPath);\n mkdirSync(dirname(fullPath), { recursive: true });\n writeFileSync(fullPath, content, \"utf8\");\n}\n\n/** Read the recorded upstream version JSON, or `null` if absent. */\nexport function readUpstreamVersion(\n repoRoot: string,\n): UpstreamVersionRecord | null {\n const path = join(repoRoot, UPSTREAM_VERSION_FILE);\n if (!existsSync(path)) return null;\n try {\n return JSON.parse(readFileSync(path, \"utf8\")) as UpstreamVersionRecord;\n } catch {\n return null;\n }\n}\n\n/** Persist the upstream version record (commit-worthy file). */\nexport function writeUpstreamVersion(\n repoRoot: string,\n record: UpstreamVersionRecord,\n): void {\n const path = join(repoRoot, UPSTREAM_VERSION_FILE);\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, JSON.stringify(record, null, 2) + \"\\n\", \"utf8\");\n}\n\n/**\n * Compute a stable relative path inside the base/ tree from an arbitrary\n * absolute or relative source path. Strips `..` and normalises separators.\n */\nexport function toBaseRelativePath(repoRoot: string, sourcePath: string): string {\n const baseRoot = join(repoRoot, BASE_DIR);\n const rel = relative(baseRoot, sourcePath);\n // If sourcePath is already a project-relative path (not inside base/), use\n // it as-is after normalising backslashes.\n if (rel.startsWith(\"..\")) {\n return sourcePath.replace(/\\\\/g, \"/\");\n }\n return rel.replace(/\\\\/g, \"/\");\n}\n","/**\n * Path helpers for the twin-build CLI.\n *\n * Plugin cache 戦略:\n * - Plugin install path: ~/.claude/plugins/cache/twin-build-marketplace/twin-build/<version>/\n * - statusLine script: <plugin-cache>/scripts/orchestrator-status-line.mjs\n * - fallback: node_modules/@twin-build-orchestrate/cli/dist/scripts/orchestrator-status-line.mjs\n */\n\nimport { existsSync, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst MARKETPLACE_NAME = \"twin-build-marketplace\";\nconst PLUGIN_NAME = \"twin-build\";\n\nexport const ORCHESTRATE_PACKAGE = \"@twin-build-orchestrate/cli\";\nexport const STATUSLINE_SCRIPT_NAME = \"orchestrator-status-line.mjs\";\n\n/** `~/.claude/plugins/` (cross-platform). */\nexport function claudePluginsRoot(home: string = homedir()): string {\n return join(home, \".claude\", \"plugins\");\n}\n\n/** `~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/`. */\nexport function pluginCachePath(\n version: string,\n home: string = homedir(),\n): string {\n return join(\n claudePluginsRoot(home),\n \"cache\",\n MARKETPLACE_NAME,\n PLUGIN_NAME,\n version,\n );\n}\n\n/** Path to the bundled statusLine script inside the Plugin cache. */\nexport function pluginStatusLinePath(\n version: string,\n home: string = homedir(),\n): string {\n return join(pluginCachePath(version, home), \"scripts\", STATUSLINE_SCRIPT_NAME);\n}\n\n/** Path to the fallback statusLine script shipped with the npm package. */\nexport function orchestrateFallbackStatusLinePath(repoRoot: string): string {\n return join(\n repoRoot,\n \"node_modules\",\n ORCHESTRATE_PACKAGE,\n \"scripts\",\n STATUSLINE_SCRIPT_NAME,\n );\n}\n\nexport interface InstalledPluginEntry {\n name?: string;\n version?: string;\n marketplace?: string;\n source?: { source?: string; path?: string; repository?: string };\n enabled?: boolean;\n}\n\n/**\n * Read `~/.claude/plugins/installed_plugins.json` and return the entries.\n * Returns `null` when the file is absent or unreadable.\n */\nexport function readInstalledPlugins(\n home: string = homedir(),\n): InstalledPluginEntry[] | null {\n const path = join(claudePluginsRoot(home), \"installed_plugins.json\");\n if (!existsSync(path)) return null;\n try {\n const raw = JSON.parse(readFileSync(path, \"utf8\"));\n if (Array.isArray(raw)) return raw as InstalledPluginEntry[];\n if (Array.isArray(raw?.plugins)) return raw.plugins as InstalledPluginEntry[];\n if (raw && typeof raw === \"object\") {\n // older format: { \"<name>\": { ... } }\n return Object.entries(raw as Record<string, unknown>).map(\n ([name, value]) => {\n const v = (value ?? {}) as Record<string, unknown>;\n return { name, ...v } as InstalledPluginEntry;\n },\n );\n }\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Detect the installed twin-build plugin version.\n *\n * Strategy:\n * 1. read `installed_plugins.json` and look for `name === \"twin-build\"` (GitHub-source path)\n * 2. otherwise scan `~/.claude/plugins/cache/twin-build-marketplace/twin-build/`\n * for version directories (directory-source path — see P3-B handoff)\n * 3. return `null` when neither yields anything\n */\nexport function detectInstalledPluginVersion(\n home: string = homedir(),\n): string | null {\n const fromJson = readInstalledPlugins(home);\n const match = fromJson?.find(\n (p) => (p.name ?? \"\").toLowerCase() === PLUGIN_NAME,\n );\n if (match?.version) return match.version;\n\n // Directory-source fallback: list child dirs of the cache root.\n const cacheRoot = join(\n claudePluginsRoot(home),\n \"cache\",\n MARKETPLACE_NAME,\n PLUGIN_NAME,\n );\n try {\n if (!existsSync(cacheRoot)) return null;\n const children = readdirSync(cacheRoot)\n .filter((name) => statSync(join(cacheRoot, name)).isDirectory());\n if (children.length === 0) return null;\n return [...children].sort(compareSemverDesc)[0] ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Compare two semver-ish version strings in descending order.\n * Higher version sorts first. Prerelease identifiers (e.g. `-prerelease.1`)\n * are treated as lower than their bare release counterpart, matching the\n * common semver intuition. Non-numeric segments fall back to lexicographic\n * comparison so totally arbitrary tags still get a stable order.\n *\n * Examples:\n * 1.10.0 > 1.2.0 (numeric compare, not lex)\n * 1.0.0 > 1.0.0-rc.1 (prerelease ranks lower than release)\n * 2.0.0 > 1.10.0\n * 1.0.0-rc.10 > 1.0.0-rc.2 (prerelease segments compared numerically when numeric)\n */\nexport function compareSemverDesc(a: string, b: string): number {\n const va = parseSemver(a);\n const vb = parseSemver(b);\n const len = Math.max(va.parts.length, vb.parts.length);\n for (let i = 0; i < len; i++) {\n const x = va.parts[i] ?? 0;\n const y = vb.parts[i] ?? 0;\n if (typeof x === \"number\" && typeof y === \"number\") {\n if (x !== y) return y - x; // descending\n } else {\n const cmp = String(y).localeCompare(String(x));\n if (cmp !== 0) return cmp;\n }\n }\n return comparePrereleaseDesc(va.pre, vb.pre);\n}\n\nfunction parseSemver(v: string): { parts: Array<number | string>; pre: string } {\n const [core = \"\", pre = \"\"] = v.split(/-(.+)/, 2);\n const parts = core.split(\".\").map((seg) => {\n const n = Number(seg);\n return Number.isFinite(n) && /^\\d+$/.test(seg) ? n : seg;\n });\n return { parts, pre };\n}\n\n/**\n * Compare two prerelease identifier strings in descending order.\n * Implements SemVer §11 precedence:\n * 1. An empty prerelease (i.e. a final release) ranks HIGHER than any prerelease.\n * 2. Each dot-separated identifier is compared in order:\n * - both numeric → compare numerically\n * - both non-numeric → compare lexically (ASCII)\n * - mixed → the numeric identifier has LOWER precedence\n * 3. If all preceding identifiers are equal, the one with MORE identifiers\n * has higher precedence.\n */\nfunction comparePrereleaseDesc(aPre: string, bPre: string): number {\n if (aPre === bPre) return 0;\n // Final release vs prerelease: release wins.\n if (aPre === \"\" && bPre !== \"\") return -1;\n if (aPre !== \"\" && bPre === \"\") return 1;\n\n const aSegs = aPre.split(\".\");\n const bSegs = bPre.split(\".\");\n const len = Math.max(aSegs.length, bSegs.length);\n for (let i = 0; i < len; i++) {\n const aSeg = aSegs[i];\n const bSeg = bSegs[i];\n // Longer prerelease set has higher precedence when all preceding are equal.\n if (aSeg === undefined) return 1;\n if (bSeg === undefined) return -1;\n\n const aIsNum = /^\\d+$/.test(aSeg);\n const bIsNum = /^\\d+$/.test(bSeg);\n if (aIsNum && bIsNum) {\n const an = Number(aSeg);\n const bn = Number(bSeg);\n if (an !== bn) return bn - an; // descending\n } else if (aIsNum !== bIsNum) {\n // Numeric identifiers have LOWER precedence than non-numeric.\n // Returning positive places `a` after `b` in descending order.\n return aIsNum ? 1 : -1;\n } else {\n const cmp = bSeg.localeCompare(aSeg);\n if (cmp !== 0) return cmp;\n }\n }\n return 0;\n}\n","/**\n * `.claude/settings.json` の deep merge ヘルパー。\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §3 / §6\n *\n * 戦略:\n * - 既存設定保護: 同名 key は **既存値を尊重** (defaultMode に従う)\n * - `hooks` のような **配列フィールドは concat** (重複 entry は除外)\n * - object は再帰的 deep merge\n * - primitive は既存値優先 (additions が \"default\" として振る舞う)\n *\n * Plugin / orchestrate v1 が settings.json に書き込む内容:\n * - `statusLine.command`\n * - `extraKnownMarketplaces[name]`\n * - `enabledPlugins[]` (flag)\n * - hooks (PreToolUse 等の自動化、init オプション)\n */\n\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\n\nexport type JsonObject = { [key: string]: JsonValue };\n\nexport interface MergeSettingsOptions {\n /**\n * 同名 key の primitive / array をどう扱うか。\n * - \"prefer-existing\" (default): 既存値を残す (init の追記用、安全側)\n * - \"prefer-incoming\": additions の値で上書き (--force 系)\n */\n primitiveStrategy?: \"prefer-existing\" | \"prefer-incoming\";\n /**\n * 配列フィールドの扱い。\n * - \"concat-unique\" (default): 既存 + additions の union (重複除外、deep equal で判定)\n * - \"prefer-existing\": 既存配列をそのまま\n * - \"prefer-incoming\": additions の配列で置換\n */\n arrayStrategy?: \"concat-unique\" | \"prefer-existing\" | \"prefer-incoming\";\n}\n\n/**\n * Deep-merge two JSON objects.\n * 既存 (`existing`) を尊重しつつ additions を「不足分の補完」として適用する。\n */\nexport function mergeSettings(\n existing: JsonValue,\n additions: JsonValue,\n options: MergeSettingsOptions = {},\n): JsonValue {\n const primitiveStrategy = options.primitiveStrategy ?? \"prefer-existing\";\n const arrayStrategy = options.arrayStrategy ?? \"concat-unique\";\n\n if (existing === null || existing === undefined) return additions;\n if (additions === null || additions === undefined) return existing;\n\n // Arrays\n if (Array.isArray(existing) && Array.isArray(additions)) {\n if (arrayStrategy === \"prefer-existing\") return existing;\n if (arrayStrategy === \"prefer-incoming\") return additions;\n return concatUnique(existing, additions);\n }\n\n // Objects\n if (isPlainObject(existing) && isPlainObject(additions)) {\n const out: JsonObject = { ...existing };\n for (const [key, addValue] of Object.entries(additions)) {\n if (!(key in out)) {\n out[key] = addValue;\n } else {\n out[key] = mergeSettings(out[key], addValue, options);\n }\n }\n return out;\n }\n\n // Type mismatch or primitive: defer to strategy.\n return primitiveStrategy === \"prefer-incoming\" ? additions : existing;\n}\n\n/**\n * Concatenate two arrays without duplicating entries (deep equality).\n * 順序: existing → additions の新規分のみ追記。\n */\nexport function concatUnique(a: JsonValue[], b: JsonValue[]): JsonValue[] {\n const out: JsonValue[] = [...a];\n for (const item of b) {\n if (!out.some((existing) => deepEqual(existing, item))) {\n out.push(item);\n }\n }\n return out;\n}\n\n/** Strict structural equality for JsonValue. */\nexport function deepEqual(a: JsonValue, b: JsonValue): boolean {\n if (a === b) return true;\n if (a === null || b === null) return false;\n if (typeof a !== typeof b) return false;\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((v, i) => deepEqual(v, b[i]));\n }\n if (isPlainObject(a) && isPlainObject(b)) {\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every(\n (k) => Object.prototype.hasOwnProperty.call(b, k) && deepEqual(a[k], b[k]),\n );\n }\n return false;\n}\n\nexport function isPlainObject(value: unknown): value is JsonObject {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n Object.getPrototypeOf(value) === Object.prototype\n );\n}\n\n/**\n * Stringify settings JSON with 2-space indent + trailing newline.\n * Claude Code が読み書きする形式に合わせる。\n */\nexport function stringifySettings(value: JsonValue): string {\n return JSON.stringify(value, null, 2) + \"\\n\";\n}\n","/**\n * `npx twin-build doctor` — drift / integrity check + optional `--fix`.\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §6 (F6 revert drift)\n *\n * 検査項目:\n * - .twin-build.json 存在 + twinBuild block 整合性\n * - integrity sha256 (4-axis pin の手書き編集検知)\n * - linkStrategy が OS と整合 (Windows=copy / POSIX=symlink)\n * - Plugin cache reachability (`~/.claude/plugins/`)\n * - .claude/settings.json の statusLine 設定\n * - statusLine script の実在\n */\n\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { integrityHash, defaultLinkStrategy } from \"./init.js\";\nimport { verifyIntegrity } from \"./lib/integrity.js\";\nimport {\n detectInstalledPluginVersion,\n orchestrateFallbackStatusLinePath,\n pluginStatusLinePath,\n} from \"./lib/paths.js\";\nimport {\n type JsonObject,\n type JsonValue,\n isPlainObject,\n mergeSettings,\n stringifySettings,\n} from \"./lib/settings-json.js\";\n\nexport type IssueSeverity = \"error\" | \"warning\" | \"info\";\nexport type FixCategory =\n | \"linkStrategy\"\n | \"integrity\"\n | \"statusLine\"\n | \"pluginCache\"\n | \"settingsMissing\"\n | \"twinBuildJson\";\n\nexport interface DoctorIssue {\n code: string;\n severity: IssueSeverity;\n category: FixCategory;\n message: string;\n fixable: boolean;\n details?: Record<string, unknown>;\n}\n\nexport interface DoctorOptions {\n repoRoot: string;\n /** Apply automatic fixes (settings.json merge, integrity rewrite). */\n fix?: boolean;\n /** Print extra detail per issue (Plugin cache contents etc.). */\n diagnose?: boolean;\n /** Override $HOME for tests. */\n home?: string;\n}\n\nexport interface DoctorResult {\n issues: DoctorIssue[];\n fixed: DoctorIssue[];\n passed: boolean;\n}\n\nconst TWIN_BUILD_JSON = \".twin-build.json\";\nconst SETTINGS_JSON = \".claude/settings.json\";\n\n/**\n * Run the doctor checks against the repo. Pure-ish: only writes when `fix` is true.\n */\nexport async function runDoctor(opts: DoctorOptions): Promise<DoctorResult> {\n const issues: DoctorIssue[] = [];\n const fixed: DoctorIssue[] = [];\n const home = opts.home ?? homedir();\n\n // 1. .twin-build.json existence + structure\n const twinBuildPath = join(opts.repoRoot, TWIN_BUILD_JSON);\n let tbDoc: JsonObject | null = null;\n if (!existsSync(twinBuildPath)) {\n issues.push({\n code: \"TBJSON_MISSING\",\n severity: \"error\",\n category: \"twinBuildJson\",\n message:\n \".twin-build.json not found. Run `npx twin-build init` to bootstrap the project.\",\n fixable: false,\n });\n return { issues, fixed, passed: false };\n }\n try {\n tbDoc = JSON.parse(readFileSync(twinBuildPath, \"utf8\")) as JsonObject;\n } catch (err) {\n issues.push({\n code: \"TBJSON_PARSE\",\n severity: \"error\",\n category: \"twinBuildJson\",\n message: `.twin-build.json could not be parsed: ${err instanceof Error ? err.message : String(err)}`,\n fixable: false,\n });\n return { issues, fixed, passed: false };\n }\n\n const tb = (tbDoc.twinBuild ?? null) as JsonObject | null;\n if (!tb) {\n issues.push({\n code: \"TBJSON_LEGACY\",\n severity: \"warning\",\n category: \"twinBuildJson\",\n message:\n \".twin-build.json has no twinBuild block (legacy single-key format). Run `npx twin-build init` to upgrade.\",\n fixable: false,\n });\n return { issues, fixed, passed: false };\n }\n\n // 2. integrity sha256 check (4-axis pin の手書き編集検知 / F6)\n const integrity = isPlainObject(tb.integrity) ? tb.integrity : null;\n for (const axis of [\"pluginVersion\", \"cliVersion\", \"rulesSchemaVersion\"] as const) {\n const declared = typeof tb[axis] === \"string\" ? (tb[axis] as string) : null;\n const declaredHash = integrity?.[axis] as string | undefined;\n if (!declared) continue;\n const computed = integrityHash(declared);\n if (declaredHash && declaredHash !== computed) {\n const issue: DoctorIssue = {\n code: `INTEGRITY_${axis.toUpperCase()}`,\n severity: \"error\",\n category: \"integrity\",\n message:\n `integrity mismatch on ${axis}: declared=${declaredHash}, computed=${computed}. ` +\n `This usually means the version was hand-edited. Use --fix to re-seal.`,\n fixable: true,\n details: { axis, declared, declaredHash, computed },\n };\n issues.push(issue);\n if (opts.fix && integrity) {\n integrity[axis] = computed;\n fixed.push(issue);\n }\n } else if (!declaredHash && opts.fix && integrity) {\n // Missing integrity entry — seed it on --fix.\n integrity[axis] = computed;\n fixed.push({\n code: `INTEGRITY_${axis.toUpperCase()}_SEEDED`,\n severity: \"info\",\n category: \"integrity\",\n message: `integrity hash seeded for ${axis}`,\n fixable: true,\n });\n }\n }\n\n // 3. linkStrategy compatibility\n const declaredStrategy = (tb.linkStrategy as string) ?? \"symlink\";\n const expectedStrategy = defaultLinkStrategy();\n if (declaredStrategy !== expectedStrategy) {\n const issue: DoctorIssue = {\n code: \"LINKSTRATEGY_MISMATCH\",\n severity: declaredStrategy === \"copy\" ? \"info\" : \"warning\",\n category: \"linkStrategy\",\n message: `linkStrategy in .twin-build.json is \"${declaredStrategy}\" but this OS prefers \"${expectedStrategy}\".`,\n fixable: true,\n details: { declared: declaredStrategy, expected: expectedStrategy },\n };\n issues.push(issue);\n if (opts.fix) {\n tb.linkStrategy = expectedStrategy;\n fixed.push(issue);\n }\n }\n\n // 4. Plugin cache reachability\n const installedVersion = detectInstalledPluginVersion(home);\n if (!installedVersion) {\n issues.push({\n code: \"PLUGIN_NOT_INSTALLED\",\n severity: \"warning\",\n category: \"pluginCache\",\n message:\n \"Plugin not detected in ~/.claude/plugins/. Open Claude Code → /plugin Marketplace → install twin-build. \" +\n \"Until then, fallback statusLine via @twin-build-orchestrate/cli will be used.\",\n fixable: false,\n details: opts.diagnose\n ? { lookedAt: join(home, \".claude\", \"plugins\") }\n : undefined,\n });\n } else if (\n typeof tb.pluginVersion === \"string\" &&\n tb.pluginVersion !== installedVersion\n ) {\n issues.push({\n code: \"PLUGIN_VERSION_DRIFT\",\n severity: \"warning\",\n category: \"pluginCache\",\n message:\n `Plugin v${installedVersion} is installed but .twin-build.json pins v${tb.pluginVersion}. ` +\n `Run \\`npx twin-build sync\\` to align.`,\n fixable: false,\n details: { installed: installedVersion, pinned: tb.pluginVersion },\n });\n }\n\n // 4.5. SKILL.md copy integrity check (P3-F, linkStrategy=copy のみ)\n if (declaredStrategy === \"copy\") {\n const verify = verifyIntegrity(opts.repoRoot);\n if (verify.recordCorrupted) {\n issues.push({\n code: \"INTEGRITY_RECORD_CORRUPT\",\n severity: \"warning\",\n category: \"integrity\",\n message:\n \".twin-build/cache/integrity.json could not be parsed (corrupted or wrong schema). \" +\n \"Plugin copy integrity cannot be verified. \" +\n \"Run `npx twin-build sync` to regenerate the integrity record.\",\n fixable: false,\n });\n }\n for (const rel of verify.corrupt) {\n issues.push({\n code: \"SKILL_INTEGRITY_CORRUPT\",\n severity: \"warning\",\n category: \"integrity\",\n message:\n `${rel} differs from the recorded sha256. ` +\n `The file may have been edited locally or corrupted. ` +\n `Run \\`npx twin-build sync\\` to restore the Plugin copy.`,\n fixable: false,\n details: { relPath: rel },\n });\n }\n for (const rel of verify.missing) {\n issues.push({\n code: \"SKILL_INTEGRITY_MISSING\",\n severity: \"warning\",\n category: \"integrity\",\n message:\n `${rel} was recorded in integrity.json but no longer exists on disk. ` +\n `Run \\`npx twin-build sync\\` to repopulate the Plugin copy.`,\n fixable: false,\n details: { relPath: rel },\n });\n }\n }\n\n // 5. .claude/settings.json statusLine\n const settingsPath = join(opts.repoRoot, SETTINGS_JSON);\n let settings: JsonValue = {};\n if (existsSync(settingsPath)) {\n try {\n settings = JSON.parse(readFileSync(settingsPath, \"utf8\")) as JsonValue;\n } catch (err) {\n issues.push({\n code: \"SETTINGS_PARSE\",\n severity: \"error\",\n category: \"settingsMissing\",\n message: `.claude/settings.json could not be parsed: ${err instanceof Error ? err.message : String(err)}`,\n fixable: false,\n });\n return { issues, fixed, passed: false };\n }\n } else {\n const issue: DoctorIssue = {\n code: \"SETTINGS_MISSING\",\n severity: \"warning\",\n category: \"settingsMissing\",\n message:\n \".claude/settings.json is missing. statusLine + extraKnownMarketplaces will be reseeded with --fix.\",\n fixable: true,\n };\n issues.push(issue);\n if (opts.fix) {\n settings = {};\n }\n }\n\n const expectedStatusLine = installedVersion\n ? pluginStatusLinePath(installedVersion, home)\n : orchestrateFallbackStatusLinePath(opts.repoRoot);\n const settingsObj = isPlainObject(settings) ? settings : {};\n const statusLineNode = isPlainObject(settingsObj.statusLine)\n ? (settingsObj.statusLine as JsonObject)\n : null;\n const currentCommand =\n typeof statusLineNode?.command === \"string\"\n ? (statusLineNode.command as string)\n : null;\n if (!currentCommand) {\n const issue: DoctorIssue = {\n code: \"STATUSLINE_MISSING\",\n severity: \"warning\",\n category: \"statusLine\",\n message:\n `statusLine.command is not set in .claude/settings.json. ` +\n `Recommended: node ${expectedStatusLine}`,\n fixable: true,\n };\n issues.push(issue);\n if (opts.fix) {\n const merged = mergeSettings(settings, {\n statusLine: {\n type: \"command\",\n command: `node ${expectedStatusLine}`,\n padding: 1,\n },\n });\n settings = merged;\n fixed.push(issue);\n }\n } else if (!currentCommand.includes(\"orchestrator-status-line\")) {\n issues.push({\n code: \"STATUSLINE_UNRECOGNISED\",\n severity: \"info\",\n category: \"statusLine\",\n message:\n `statusLine.command does not look like twin-build's (got: \"${currentCommand}\"). ` +\n `If this is intentional, ignore. Otherwise, run \\`npx twin-build doctor --fix\\` to reseed.`,\n fixable: false,\n });\n } else {\n // Verify the script file actually exists.\n const matched = currentCommand.match(/orchestrator-status-line[^\\s]*/);\n if (matched) {\n // The command may include `node ` prefix and args. Extract the path.\n const pathPart = currentCommand.replace(/^node\\s+/, \"\").split(/\\s+/)[0];\n if (pathPart && !existsSync(pathPart)) {\n const issue: DoctorIssue = {\n code: \"STATUSLINE_SCRIPT_MISSING\",\n severity: \"warning\",\n category: \"statusLine\",\n message:\n `statusLine command points to \"${pathPart}\" but the file is missing. ` +\n (installedVersion\n ? `Plugin v${installedVersion} may have moved. Try --fix or reinstall.`\n : \"Try --fix or install @twin-build-orchestrate/cli.\"),\n fixable: true,\n details: { pathPart, expected: expectedStatusLine },\n };\n issues.push(issue);\n if (opts.fix && statusLineNode) {\n statusLineNode.command = `node ${expectedStatusLine}`;\n fixed.push(issue);\n }\n }\n }\n }\n\n if (opts.fix && fixed.length > 0) {\n writeFileSync(\n twinBuildPath,\n JSON.stringify(tbDoc, null, 2) + \"\\n\",\n \"utf8\",\n );\n writeFileSync(settingsPath, stringifySettings(settings), \"utf8\");\n }\n\n const passed = !issues.some((i) => i.severity === \"error\");\n return { issues, fixed, passed };\n}\n\n/** Render doctor result as a human-readable report. */\nexport function renderDoctorReport(result: DoctorResult): string {\n if (result.issues.length === 0) {\n return \"✓ twin-build doctor: no issues found.\";\n }\n const lines: string[] = [];\n for (const issue of result.issues) {\n const icon =\n issue.severity === \"error\" ? \"✗\" : issue.severity === \"warning\" ? \"⚠\" : \"ℹ\";\n lines.push(`${icon} [${issue.code}] ${issue.message}`);\n if (issue.details) {\n for (const [k, v] of Object.entries(issue.details)) {\n lines.push(` ${k}: ${typeof v === \"object\" ? JSON.stringify(v) : v}`);\n }\n }\n }\n if (result.fixed.length > 0) {\n lines.push(\"\", `Auto-fixed ${result.fixed.length} issue(s):`);\n for (const f of result.fixed) lines.push(` ✓ ${f.code}`);\n }\n lines.push(\"\", result.passed ? \"Result: PASS (with warnings)\" : \"Result: FAIL\");\n return lines.join(\"\\n\");\n}\n","/**\n * `src/cli/lib/integrity.ts` — sha256-based copy integrity for Plugin files.\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §9.2 F3、横断警告 #5\n *\n * 目的:\n * linkStrategy=copy で物理 copy された Plugin SKILL.md ファイルが Plugin\n * update / 手動編集 / FS 破損で変質した場合に、doctor が検知できるよう\n * sha256 hash を `.twin-build/cache/integrity.json` に保存する。\n *\n * 対象範囲 (P3-F B 案):\n * `.claude/skills/<skill>/SKILL.md` のみ。rules / templates / other は対象外。\n * 理由: SKILL.md は Plugin の主要 surface であり、破損による影響が最大。\n * 全 Plugin ファイル網羅は将来の C 案拡張で別 ticket 化する。\n */\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nconst INTEGRITY_JSON = \".twin-build/cache/integrity.json\";\n\n/** Entries recorded per file. */\nexport interface IntegrityEntry {\n /** Path relative to repo root (e.g. `.claude/skills/ticket/SKILL.md`). */\n relPath: string;\n /** sha256:hex string. */\n hash: string;\n}\n\nexport interface IntegrityRecord {\n /** Schema version (forward-compatible). */\n version: 1;\n /** Plugin linkStrategy at record time. */\n linkStrategy: \"symlink\" | \"copy\";\n /** ISO-8601 timestamp. */\n recordedAt: string;\n /** Map of relPath → sha256:hex. */\n files: Record<string, string>;\n}\n\nexport interface VerifyResult {\n /** Files whose recorded hash matches the on-disk content. */\n intact: string[];\n /** Files whose hash differs from the record (tampered or corrupted). */\n corrupt: string[];\n /** Files recorded but missing on disk. */\n missing: string[];\n /**\n * True when the integrity.json file exists but could not be parsed\n * (invalid JSON or wrong schema version). doctor surfaces this as a\n * separate `INTEGRITY_RECORD_CORRUPT` issue so the silent-no-op path\n * is observable.\n */\n recordCorrupted: boolean;\n}\n\n/** Compute sha256:hex of a file's content. Returns null when missing. */\nexport function computeFileHash(absPath: string): string | null {\n if (!existsSync(absPath)) return null;\n const buf = readFileSync(absPath);\n return \"sha256:\" + createHash(\"sha256\").update(buf).digest(\"hex\");\n}\n\n/** True if relPath is a Plugin SKILL.md (the scope tracked by P3-F B 案). */\nexport function isIntegrityTrackedPath(relPath: string): boolean {\n // Normalize separators so Windows paths (`.claude\\skills\\...`) match too.\n const normalized = relPath.replace(/\\\\/g, \"/\");\n return /^\\.claude\\/skills\\/[^/]+\\/SKILL\\.md$/.test(normalized);\n}\n\n/**\n * Read the integrity record. Returns one of:\n * - `{ state: \"absent\" }` when no integrity.json exists (never recorded)\n * - `{ state: \"corrupted\" }` when the file exists but cannot be parsed\n * - `{ state: \"ok\", record }` for a valid v1 record\n *\n * doctor surfaces the `corrupted` state explicitly so silent-no-op verifies\n * are observable (see verifyIntegrity / INTEGRITY_RECORD_CORRUPT).\n */\nexport type LoadResult =\n | { state: \"absent\" }\n | { state: \"corrupted\" }\n | { state: \"ok\"; record: IntegrityRecord };\n\nexport function loadIntegrity(repoRoot: string): LoadResult {\n const path = join(repoRoot, INTEGRITY_JSON);\n if (!existsSync(path)) return { state: \"absent\" };\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf8\")) as IntegrityRecord;\n if (parsed.version !== 1) return { state: \"corrupted\" };\n return { state: \"ok\", record: parsed };\n } catch {\n return { state: \"corrupted\" };\n }\n}\n\n/** Write the integrity record. Creates `.twin-build/cache/` if missing. */\nexport function saveIntegrity(repoRoot: string, record: IntegrityRecord): void {\n const path = join(repoRoot, INTEGRITY_JSON);\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, JSON.stringify(record, null, 2) + \"\\n\", \"utf8\");\n}\n\n/**\n * Record hashes for tracked Plugin SKILL.md files.\n *\n * @param repoRoot Project root.\n * @param linkStrategy Current strategy. Determines whether file hashes are\n * actually computed (see below).\n * @param trackedRelPaths Plugin file paths under `.claude/skills/<name>/SKILL.md`.\n * Non-matching entries are silently filtered.\n *\n * ## Why we still write a record under `symlink` strategy\n *\n * `linkStrategy === \"symlink\"` writes an integrity.json with `files: {}` rather\n * than skipping the file entirely. This is intentional:\n *\n * 1. `linkStrategy` can be flipped per-machine (e.g. a project shared between\n * macOS developers and a Windows CI runner). When a machine flips to\n * `copy`, recordIntegrity is called with the new strategy and the prior\n * symlink record is overwritten with real hashes — no stale \"phantom\"\n * hashes from a previous copy run remain on disk.\n * 2. `verifyIntegrity` short-circuits on `record.linkStrategy !== \"copy\"` and\n * returns empty lists, so the empty record is never accidentally treated\n * as \"all files missing\".\n *\n * Tampering of symlink targets is caught by the doctor symlink-target check\n * (doctor.ts step #3), not by hash.\n */\nexport function recordIntegrity(\n repoRoot: string,\n linkStrategy: \"symlink\" | \"copy\",\n trackedRelPaths: readonly string[],\n): IntegrityRecord {\n if (linkStrategy !== \"copy\") {\n // See JSDoc above for rationale on persisting an empty record.\n const empty: IntegrityRecord = {\n version: 1,\n linkStrategy,\n recordedAt: new Date().toISOString(),\n files: {},\n };\n saveIntegrity(repoRoot, empty);\n return empty;\n }\n const files: Record<string, string> = {};\n for (const rel of trackedRelPaths) {\n if (!isIntegrityTrackedPath(rel)) continue;\n const hash = computeFileHash(join(repoRoot, rel));\n if (hash !== null) files[rel] = hash;\n }\n const record: IntegrityRecord = {\n version: 1,\n linkStrategy,\n recordedAt: new Date().toISOString(),\n files,\n };\n saveIntegrity(repoRoot, record);\n return record;\n}\n\n/**\n * Verify recorded hashes against on-disk content. Returns intact / corrupt /\n * missing lists.\n *\n * - When no integrity.json exists, all lists are empty (no record to verify).\n * - When linkStrategy was recorded as `symlink`, no files are tracked; result\n * is all-empty.\n */\nexport function verifyIntegrity(repoRoot: string): VerifyResult {\n const empty: VerifyResult = {\n intact: [],\n corrupt: [],\n missing: [],\n recordCorrupted: false,\n };\n const loaded = loadIntegrity(repoRoot);\n if (loaded.state === \"absent\") return empty;\n if (loaded.state === \"corrupted\") return { ...empty, recordCorrupted: true };\n if (loaded.record.linkStrategy !== \"copy\") return empty;\n\n const result: VerifyResult = { ...empty };\n for (const [rel, expectedHash] of Object.entries(loaded.record.files)) {\n const actualHash = computeFileHash(join(repoRoot, rel));\n if (actualHash === null) {\n result.missing.push(rel);\n } else if (actualHash === expectedHash) {\n result.intact.push(rel);\n } else {\n result.corrupt.push(rel);\n }\n }\n return result;\n}\n","/**\n * `npx twin-build sync` — 3-way merge codemod from upstream into the project.\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §6 (軸 4 Codemod) / §4 (Compatibility)\n *\n * フロー:\n * 1. .twin-build.json から現在の pin (base) を取得\n * 2. target version を解決 (CLI args or \"latest\")\n * 3. compatibility check (warning/incompatible は prompt or halt)\n * 4. 各 tracked file (CLAUDE.md, templates/*) について:\n * a. base = .twin-build/cache/base/<path> から (なければ fetch)\n * b. ours = project ファイル\n * c. theirs = upstream fetcher から取得\n * d. 3-way merge\n * e. clean → write、conflict → prompt (Rails-style) or halt\n * 5. CLAUDE.md の conflict ratio > 60% → halt + `--skip-claude-md` 提示 (F9)\n * 6. agent mode (TWIN_BUILD_AGENT_MODE=1): conflict は必ず halt + event 発火\n * 7. 完了時に upstream-version.json + .twin-build.json history 更新\n */\n\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport {\n readBaseContent,\n readUpstreamVersion,\n writeBaseContent,\n writeUpstreamVersion,\n type UpstreamVersionRecord,\n} from \"./lib/cache-base.js\";\nimport { mergeThreeWay, type MergeResult } from \"./lib/merge.js\";\n\nfunction integrityHash(value: string): string {\n return \"sha256:\" + createHash(\"sha256\").update(value, \"utf8\").digest(\"hex\");\n}\n\nconst TWIN_BUILD_JSON = \".twin-build.json\";\nconst CLAUDE_MD = \"CLAUDE.md\";\nconst CONFLICT_RATIO_HALT_THRESHOLD = 0.6;\n\nexport type ConflictChoice = \"yes\" | \"no\" | \"diff\" | \"merge\" | \"all\" | \"skip\" | \"quit\";\n\nexport interface UpstreamFetcher {\n /**\n * Return the upstream content for the given version.\n * Should fail (throw or return null) if version is unavailable.\n */\n fetchFile(version: string, relPath: string): Promise<string | null>;\n /** List the files this upstream version distributes (for sync iteration). */\n listFiles(version: string): Promise<string[]>;\n}\n\nexport interface PromptResult {\n choice: ConflictChoice;\n /**\n * When `choice === \"merge\"` and the user produced a clean resolution in an\n * external editor, this carries the resolved content back to the caller.\n * The caller writes it as the project file content (replacing the conflict\n * markers). Omitted (or undefined) when the editor was cancelled / left\n * markers — in that case the caller falls back to leaving conflict markers.\n */\n resolvedContent?: string;\n}\n\nexport interface ConflictPrompt {\n /**\n * Called for each conflicted file. Returns the user's resolution choice and,\n * for the `merge` case, optionally the editor-resolved content.\n * `all` means \"accept upstream for this and all remaining conflicts\".\n */\n prompt(relPath: string, mergeResult: MergeResult): Promise<PromptResult>;\n}\n\nexport interface SyncOptions {\n repoRoot: string;\n /** Target upstream version. */\n toVersion: string;\n /** Same axis label as .twin-build.json (e.g. \"cli\", \"plugin\"). */\n axis?: \"plugin\" | \"cli\" | \"rulesSchema\";\n fetcher: UpstreamFetcher;\n /** Interactive prompt; required outside `--yes-all` mode. */\n prompter?: ConflictPrompt;\n /** Non-interactive: auto-accept upstream on conflict. */\n yesAll?: boolean;\n /** Non-interactive: keep ours on conflict. */\n keepOurs?: boolean;\n /** Non-interactive: drop ours, take theirs. */\n strategyTheirs?: boolean;\n /** Dry-run: do not write files, return plan. */\n dryRun?: boolean;\n /** Skip CLAUDE.md (used after F9 halt for retry). */\n skipClaudeMd?: boolean;\n /** Agent mode (TWIN_BUILD_AGENT_MODE=1). Halt on first conflict. */\n agentMode?: boolean;\n /** Override clock for testing. */\n now?: () => Date;\n}\n\nexport interface FileSyncOutcome {\n relPath: string;\n status: \"skipped\" | \"no-change\" | \"clean-merged\" | \"conflict-resolved\" | \"conflict-halt\";\n choice?: ConflictChoice;\n conflictCount: number;\n conflictRatio: number;\n engine?: MergeResult[\"engine\"];\n}\n\nexport interface SyncResult {\n fromVersion: string;\n toVersion: string;\n files: FileSyncOutcome[];\n halted: boolean;\n haltReason?: string;\n}\n\ninterface TwinBuildAxes {\n pluginVersion?: string;\n cliVersion?: string;\n rulesSchemaVersion?: string;\n}\n\n/** Read .twin-build.json and return the current pinned axes. */\nfunction readPins(repoRoot: string): TwinBuildAxes {\n const path = join(repoRoot, TWIN_BUILD_JSON);\n if (!existsSync(path)) return {};\n try {\n const doc = JSON.parse(readFileSync(path, \"utf8\")) as Record<string, unknown>;\n const tb = (doc.twinBuild ?? {}) as Record<string, unknown>;\n return {\n pluginVersion: tb.pluginVersion as string | undefined,\n cliVersion: tb.cliVersion as string | undefined,\n rulesSchemaVersion: tb.rulesSchemaVersion as string | undefined,\n };\n } catch {\n return {};\n }\n}\n\n/** Update .twin-build.json with new pin + history entry. Returns the new pin. */\nfunction updatePinsAndHistory(\n repoRoot: string,\n axis: SyncOptions[\"axis\"],\n toVersion: string,\n now: Date,\n): void {\n const path = join(repoRoot, TWIN_BUILD_JSON);\n if (!existsSync(path)) return;\n let doc: Record<string, unknown>;\n try {\n doc = JSON.parse(readFileSync(path, \"utf8\")) as Record<string, unknown>;\n } catch {\n return;\n }\n const tb = ((doc.twinBuild ?? {}) as Record<string, unknown>) ?? {};\n const axisKey = axis ? `${axis}Version` : \"cliVersion\";\n tb[axisKey] = toVersion;\n // Re-seal integrity for the bumped axis (横断警告 #1 / F6).\n const integrity =\n (tb.integrity as Record<string, string> | undefined) ?? {};\n integrity[axisKey] = integrityHash(toVersion);\n tb.integrity = integrity;\n const history = Array.isArray(tb.history) ? (tb.history as unknown[]) : [];\n history.push({\n at: now.toISOString(),\n pluginVersion: tb.pluginVersion,\n cliVersion: tb.cliVersion,\n rulesSchemaVersion: tb.rulesSchemaVersion,\n mcpToolSchemaVersion: tb.mcpToolSchemaVersion,\n });\n tb.history = history;\n doc.twinBuild = tb;\n writeFileSync(path, JSON.stringify(doc, null, 2) + \"\\n\", \"utf8\");\n}\n\n/**\n * Decide the merge outcome for a single tracked file.\n * Pure function: no filesystem effects.\n */\nexport function applyNonInteractiveStrategy(\n options: SyncOptions,\n mergeResult: MergeResult,\n ours: string,\n theirs: string,\n): { content: string; choice: ConflictChoice } | null {\n if (mergeResult.status === \"clean\") {\n return { content: mergeResult.content, choice: \"yes\" };\n }\n if (options.yesAll) return { content: theirs, choice: \"all\" };\n if (options.keepOurs) return { content: ours, choice: \"no\" };\n if (options.strategyTheirs) return { content: theirs, choice: \"yes\" };\n return null; // requires interactive prompt\n}\n\n/** Execute the sync flow. */\nexport async function runSync(options: SyncOptions): Promise<SyncResult> {\n const now = options.now ?? (() => new Date());\n const pins = readPins(options.repoRoot);\n const axis = options.axis ?? \"cli\";\n const fromVersion =\n axis === \"plugin\"\n ? pins.pluginVersion\n : axis === \"rulesSchema\"\n ? pins.rulesSchemaVersion\n : pins.cliVersion;\n\n const files = await options.fetcher.listFiles(options.toVersion);\n const outcomes: FileSyncOutcome[] = [];\n let halted = false;\n let haltReason: string | undefined;\n\n for (const relPath of files) {\n if (relPath === CLAUDE_MD && options.skipClaudeMd) {\n outcomes.push({\n relPath,\n status: \"skipped\",\n conflictCount: 0,\n conflictRatio: 0,\n });\n continue;\n }\n\n const theirs = await options.fetcher.fetchFile(options.toVersion, relPath);\n if (theirs === null) {\n outcomes.push({\n relPath,\n status: \"skipped\",\n conflictCount: 0,\n conflictRatio: 0,\n });\n continue;\n }\n\n const projectPath = join(options.repoRoot, relPath);\n const ours = existsSync(projectPath) ? readFileSync(projectPath, \"utf8\") : \"\";\n let base = readBaseContent(options.repoRoot, relPath);\n if (base === null) {\n // First sync: no cached base. Fetch from previous version if available,\n // otherwise degrade to 2-way (base = ours).\n base = fromVersion\n ? await options.fetcher.fetchFile(fromVersion, relPath)\n : null;\n if (base === null) base = ours;\n }\n\n const mergeResult = await mergeThreeWay(base, ours, theirs, {\n labels: {\n base: fromVersion ? `base ${axis} v${fromVersion}` : \"base\",\n ours: \"ours\",\n theirs: `theirs ${axis} v${options.toVersion}`,\n },\n });\n\n // Order:\n // 1. non-interactive strategy (--yes-all / --keep-ours / --strategy=theirs) or clean merge\n // 2. agentMode halt (no prompt available)\n // 3. F9: CLAUDE.md conflict ratio > 60% halt (human-only UX guardrail)\n // 4. Interactive prompt\n const nonInteractive = applyNonInteractiveStrategy(\n options,\n mergeResult,\n ours,\n theirs,\n );\n\n let resolvedContent: string;\n let choice: ConflictChoice;\n\n if (nonInteractive) {\n resolvedContent = nonInteractive.content;\n choice = nonInteractive.choice;\n } else if (options.agentMode) {\n halted = true;\n haltReason =\n `Conflict in ${relPath} (${mergeResult.conflictCount} hunks). ` +\n \"Agent mode is non-interactive; resolve via human session.\";\n outcomes.push({\n relPath,\n status: \"conflict-halt\",\n conflictCount: mergeResult.conflictCount,\n conflictRatio: mergeResult.conflictRatio,\n engine: mergeResult.engine,\n });\n break;\n } else if (\n relPath === CLAUDE_MD &&\n mergeResult.conflictRatio > CONFLICT_RATIO_HALT_THRESHOLD\n ) {\n halted = true;\n haltReason =\n `${CLAUDE_MD} conflict ratio ${(mergeResult.conflictRatio * 100).toFixed(1)}% exceeds ${(\n CONFLICT_RATIO_HALT_THRESHOLD * 100\n ).toFixed(0)}% threshold. ` +\n `Re-run with --skip-claude-md and resolve CLAUDE.md manually.`;\n outcomes.push({\n relPath,\n status: \"conflict-halt\",\n conflictCount: mergeResult.conflictCount,\n conflictRatio: mergeResult.conflictRatio,\n engine: mergeResult.engine,\n });\n break;\n } else {\n if (!options.prompter) {\n halted = true;\n haltReason = `Conflict in ${relPath} requires interactive prompt; no prompter supplied.`;\n outcomes.push({\n relPath,\n status: \"conflict-halt\",\n conflictCount: mergeResult.conflictCount,\n conflictRatio: mergeResult.conflictRatio,\n engine: mergeResult.engine,\n });\n break;\n }\n const promptResult = await options.prompter.prompt(relPath, mergeResult);\n const userChoice = promptResult.choice;\n choice = userChoice;\n if (userChoice === \"quit\") {\n halted = true;\n haltReason = \"User quit sync.\";\n outcomes.push({\n relPath,\n status: \"conflict-halt\",\n conflictCount: mergeResult.conflictCount,\n conflictRatio: mergeResult.conflictRatio,\n engine: mergeResult.engine,\n });\n break;\n }\n if (userChoice === \"skip\") {\n outcomes.push({\n relPath,\n status: \"skipped\",\n choice: userChoice,\n conflictCount: mergeResult.conflictCount,\n conflictRatio: mergeResult.conflictRatio,\n engine: mergeResult.engine,\n });\n continue;\n }\n if (userChoice === \"yes\" || userChoice === \"all\") {\n resolvedContent = theirs;\n } else if (userChoice === \"no\") {\n resolvedContent = ours;\n } else if (userChoice === \"merge\" && promptResult.resolvedContent !== undefined) {\n // Editor-resolved content takes priority. The prompter validated the\n // result is conflict-marker-free before returning it.\n resolvedContent = promptResult.resolvedContent;\n } else {\n // diff / merge-without-clean-result: leave conflict markers in place.\n // The user can edit the file manually and rerun sync.\n resolvedContent = mergeResult.content;\n }\n }\n\n if (!options.dryRun) {\n writeFileToProject(projectPath, resolvedContent);\n // Update cached base only when the file was actually written without\n // unresolved markers; otherwise keep the previous base for later retry.\n const finalIsClean = !resolvedContent.includes(\"<<<<<<<\");\n if (finalIsClean) {\n writeBaseContent(options.repoRoot, relPath, theirs);\n }\n }\n\n outcomes.push({\n relPath,\n status:\n mergeResult.status === \"clean\"\n ? mergeResult.content === ours\n ? \"no-change\"\n : \"clean-merged\"\n : \"conflict-resolved\",\n choice,\n conflictCount: mergeResult.conflictCount,\n conflictRatio: mergeResult.conflictRatio,\n engine: mergeResult.engine,\n });\n }\n\n // Update pins + history if we got all the way through.\n if (!halted && !options.dryRun) {\n updatePinsAndHistory(options.repoRoot, axis, options.toVersion, now());\n const prevRecord = readUpstreamVersion(options.repoRoot);\n const record: UpstreamVersionRecord = {\n pluginVersion:\n axis === \"plugin\" ? options.toVersion : pins.pluginVersion ?? \"\",\n cliVersion: axis === \"cli\" ? options.toVersion : pins.cliVersion ?? \"\",\n rulesSchemaVersion:\n axis === \"rulesSchema\"\n ? options.toVersion\n : pins.rulesSchemaVersion ?? \"\",\n mcpToolSchemaVersion: prevRecord?.mcpToolSchemaVersion,\n syncedAt: now().toISOString(),\n };\n writeUpstreamVersion(options.repoRoot, record);\n }\n\n return {\n fromVersion: fromVersion ?? \"(none)\",\n toVersion: options.toVersion,\n files: outcomes,\n halted,\n haltReason,\n };\n}\n\nfunction writeFileToProject(absPath: string, content: string): void {\n const dir = dirname(absPath);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n writeFileSync(absPath, content, \"utf8\");\n}\n","/**\n * 3-way merge engine for twin-build sync.\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §6 (軸 4 Codemod)\n *\n * Engine 戦略 (decision.md):\n * 1. `git merge-file --diff3` (POSIX 標準、conflict format zdiff3)\n * 2. `node-diff3` fallback (Windows native / git 不在)\n *\n * Output は zdiff3 形式 (`<<<<<<< / ||||||| base / ======= / >>>>>>>`)。\n * git 1.7+ / VS Code / Vim Fugitive が解釈する。独自フォーマットは発明しない。\n */\n\nimport { spawn } from \"node:child_process\";\nimport { mkdtempSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport type MergeEngine = \"git\" | \"node-diff3\";\n\nexport interface MergeLabels {\n base?: string;\n ours?: string;\n theirs?: string;\n}\n\nexport interface MergeOptions {\n /** Force a specific engine. Default: auto-detect (git first, then node-diff3). */\n engine?: MergeEngine;\n /** Labels embedded into conflict markers. */\n labels?: MergeLabels;\n}\n\nexport interface MergeResult {\n status: \"clean\" | \"conflict\";\n /** Merged content, with conflict markers if conflicts remain. */\n content: string;\n /** Number of conflict hunks (`<<<<<<<` occurrences). */\n conflictCount: number;\n /** Total line count of merged content. */\n totalLines: number;\n /** Lines inside `<<<<<<< ... >>>>>>>` ranges (inclusive). */\n conflictLines: number;\n /** conflictLines / totalLines (0..1). Used for F9 60% halt. */\n conflictRatio: number;\n /** Engine actually used. */\n engine: MergeEngine;\n}\n\n/** Run a 3-way merge of `ours` vs `theirs` against common `base`. */\nexport async function mergeThreeWay(\n base: string,\n ours: string,\n theirs: string,\n options: MergeOptions = {},\n): Promise<MergeResult> {\n const requested = options.engine;\n if (requested === \"git\") return mergeWithGit(base, ours, theirs, options.labels);\n if (requested === \"node-diff3\")\n return mergeWithNodeDiff3(base, ours, theirs, options.labels);\n\n // Auto-detect: git first, fallback to node-diff3.\n if (await isGitAvailable()) {\n return mergeWithGit(base, ours, theirs, options.labels);\n }\n return mergeWithNodeDiff3(base, ours, theirs, options.labels);\n}\n\n/** Detect whether `git` CLI is on PATH. */\nexport async function isGitAvailable(): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn(\"git\", [\"--version\"], { stdio: \"ignore\" });\n child.on(\"close\", (code) => resolve(code === 0));\n child.on(\"error\", () => resolve(false));\n });\n}\n\nasync function mergeWithGit(\n base: string,\n ours: string,\n theirs: string,\n labels: MergeLabels | undefined,\n): Promise<MergeResult> {\n const dir = mkdtempSync(join(tmpdir(), \"twin-build-merge-\"));\n try {\n const oursPath = join(dir, \"ours\");\n const basePath = join(dir, \"base\");\n const theirsPath = join(dir, \"theirs\");\n writeFileSync(oursPath, ours, \"utf8\");\n writeFileSync(basePath, base, \"utf8\");\n writeFileSync(theirsPath, theirs, \"utf8\");\n\n const args = [\n \"merge-file\",\n \"-p\",\n \"--diff3\",\n \"-L\",\n labels?.ours ?? \"ours\",\n \"-L\",\n labels?.base ?? \"base\",\n \"-L\",\n labels?.theirs ?? \"theirs\",\n oursPath,\n basePath,\n theirsPath,\n ];\n\n const { stdout, stderr, exitCode } = await runCommand(\"git\", args);\n // git merge-file exit codes:\n // 0 → clean merge\n // > 0 → conflict count (truncated at 127)\n // < 0 → I/O or invocation error (e.g. -1 from libc on read/write failure)\n // We must not silently treat a negative exit code as a clean merge — that\n // would empty the project file when stdout is empty. Throw so the caller\n // can fall back to node-diff3 or surface the failure.\n if (exitCode < 0) {\n throw new Error(\n `git merge-file failed (exit code ${exitCode}): ${stderr.trim() || \"no stderr\"}. ` +\n \"Re-run with TWIN_BUILD_MERGE_ENGINE=node-diff3 if git is unstable on this platform.\",\n );\n }\n const content = stdout;\n const stats = scanConflicts(content);\n // Guard against the case where git reported a conflict count but the\n // stdout contains no conflict markers — this would indicate the output\n // was truncated or the merge failed in an unexpected way.\n if (exitCode > 0 && stats.conflictCount === 0) {\n throw new Error(\n `git merge-file reported ${exitCode} conflict(s) but no markers were found in output. ` +\n `stderr: ${stderr.trim() || \"(empty)\"}`,\n );\n }\n return {\n status: stats.conflictCount === 0 ? \"clean\" : \"conflict\",\n content,\n conflictCount: stats.conflictCount,\n totalLines: stats.totalLines,\n conflictLines: stats.conflictLines,\n conflictRatio:\n stats.totalLines === 0 ? 0 : stats.conflictLines / stats.totalLines,\n engine: \"git\",\n };\n } finally {\n rmSync(dir, { recursive: true, force: true });\n }\n}\n\ninterface NodeDiff3Module {\n merge: (\n a: string,\n o: string,\n b: string,\n options?: unknown,\n ) => { conflict: boolean; result: string[] | string };\n}\n\nasync function mergeWithNodeDiff3(\n base: string,\n ours: string,\n theirs: string,\n labels: MergeLabels | undefined,\n): Promise<MergeResult> {\n let mod: NodeDiff3Module;\n try {\n // Loaded dynamically so the package only needs to be installed in the\n // fallback path (Windows native without git). Resolved at runtime via the\n // npm dep added to packages/orchestrate.\n mod = (await import(/* @vite-ignore */ \"node-diff3\" as string)) as NodeDiff3Module;\n } catch (err) {\n throw new Error(\n \"node-diff3 is required when git merge-file is unavailable. \" +\n \"Install via `npm i node-diff3`. (original error: \" +\n (err instanceof Error ? err.message : String(err)) +\n \")\",\n );\n }\n\n const result = mod.merge(ours, base, theirs, {\n label: {\n a: labels?.ours ?? \"ours\",\n o: labels?.base ?? \"base\",\n b: labels?.theirs ?? \"theirs\",\n },\n stringSeparator: \"\\n\",\n });\n\n const content = Array.isArray(result.result)\n ? result.result.join(\"\\n\")\n : String(result.result);\n\n const stats = scanConflicts(content);\n return {\n status: stats.conflictCount === 0 ? \"clean\" : \"conflict\",\n content,\n conflictCount: stats.conflictCount,\n totalLines: stats.totalLines,\n conflictLines: stats.conflictLines,\n conflictRatio:\n stats.totalLines === 0 ? 0 : stats.conflictLines / stats.totalLines,\n engine: \"node-diff3\",\n };\n}\n\ninterface ConflictStats {\n conflictCount: number;\n conflictLines: number;\n totalLines: number;\n}\n\n/** Scan zdiff3-formatted content for conflict statistics. */\nexport function scanConflicts(content: string): ConflictStats {\n const lines = content.split(\"\\n\");\n let conflictCount = 0;\n let conflictLines = 0;\n let inConflict = false;\n for (const line of lines) {\n if (line.startsWith(\"<<<<<<<\")) {\n conflictCount++;\n inConflict = true;\n }\n if (inConflict) conflictLines++;\n if (line.startsWith(\">>>>>>>\")) inConflict = false;\n }\n return { conflictCount, conflictLines, totalLines: lines.length };\n}\n\nfunction runCommand(\n cmd: string,\n args: string[],\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n return new Promise((resolve, reject) => {\n const child = spawn(cmd, args);\n let stdout = \"\";\n let stderr = \"\";\n child.stdout.on(\"data\", (chunk: Buffer) => {\n stdout += chunk.toString(\"utf8\");\n });\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString(\"utf8\");\n });\n child.on(\"close\", (code) => {\n resolve({ stdout, stderr, exitCode: code ?? 0 });\n });\n child.on(\"error\", reject);\n });\n}\n","/**\n * Rails-style conflict prompter for `npx twin-build sync`.\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §6 Q4\n *\n * Choose: (Y)es overwrite (n)o keep (d)iff (m)erge in editor\n * (a)ll-yes (s)kip-all-conflicts (q)uit (?)help\n */\n\nimport { spawn } from \"node:child_process\";\nimport { mkdtempSync, rmSync, writeFileSync, readFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createInterface, type Interface } from \"node:readline\";\nimport { Writable, Readable } from \"node:stream\";\nimport type { ConflictPrompt, PromptResult } from \"../sync.js\";\nimport type { MergeResult } from \"./merge.js\";\n\nconst HELP = `\n (Y) yes overwrite take upstream\n (n) no keep keep our version\n (d) diff show inline conflict markers\n (m) merge in editor open $TWIN_BUILD_MERGETOOL (default: code --wait)\n (a) all-yes accept upstream for this + remaining conflicts\n (s) skip-all-conflicts skip this + remaining conflicts\n (q) quit abort sync\n (?) help show this help\n`.trim();\n\nexport interface InteractivePromptOptions {\n /** Read line from this stream. Default: process.stdin. */\n input?: Readable;\n /** Write prompts/output to this stream. Default: process.stdout. */\n output?: Writable;\n /** Override env (mainly for tests). */\n env?: NodeJS.ProcessEnv;\n /** Whether `a)` / `s)` decisions should carry over to subsequent files. */\n rememberAll?: boolean;\n}\n\nexport class InteractiveConflictPrompter implements ConflictPrompt {\n private readonly input: Readable;\n private readonly output: Writable;\n private readonly env: NodeJS.ProcessEnv;\n private remembered: \"all\" | \"skip\" | null = null;\n\n constructor(options: InteractivePromptOptions = {}) {\n this.input = options.input ?? process.stdin;\n this.output = options.output ?? process.stdout;\n this.env = options.env ?? process.env;\n }\n\n async prompt(relPath: string, mergeResult: MergeResult): Promise<PromptResult> {\n if (this.remembered === \"all\") return { choice: \"all\" };\n if (this.remembered === \"skip\") return { choice: \"skip\" };\n\n const rl: Interface = createInterface({\n input: this.input,\n output: this.output,\n terminal: false,\n });\n\n this.write(\n `\\n[conflict] ${relPath} — ${mergeResult.conflictCount} hunk(s), ` +\n `${(mergeResult.conflictRatio * 100).toFixed(1)}% conflict ratio\\n`,\n );\n\n try {\n while (true) {\n const answer = (\n await this.askLine(\n rl,\n \" Choose: (Y)es (n)o (d)iff (m)erge (a)ll (s)kip (q)uit (?)help > \",\n )\n )\n .trim()\n .toLowerCase();\n switch (answer) {\n case \"\":\n case \"y\":\n case \"yes\":\n return { choice: \"yes\" };\n case \"n\":\n case \"no\":\n return { choice: \"no\" };\n case \"d\":\n case \"diff\":\n this.write(\"\\n\" + mergeResult.content + \"\\n\");\n continue;\n case \"m\":\n case \"merge\": {\n const merged = await this.openInEditor(relPath, mergeResult.content);\n if (merged !== null && !merged.includes(\"<<<<<<<\")) {\n this.write(\n \" editor returned clean content — applying as resolution.\\n\",\n );\n return { choice: \"merge\", resolvedContent: merged };\n }\n this.write(\" editor closed with conflicts unresolved.\\n\");\n continue;\n }\n case \"a\":\n case \"all\":\n this.remembered = \"all\";\n return { choice: \"all\" };\n case \"s\":\n case \"skip\":\n this.remembered = \"skip\";\n return { choice: \"skip\" };\n case \"q\":\n case \"quit\":\n return { choice: \"quit\" };\n case \"?\":\n case \"help\":\n this.write(\"\\n\" + HELP + \"\\n\");\n continue;\n default:\n this.write(` unknown answer: \"${answer}\". Type ? for help.\\n`);\n continue;\n }\n }\n } finally {\n rl.close();\n }\n }\n\n private write(s: string): void {\n this.output.write(s);\n }\n\n private askLine(rl: Interface, q: string): Promise<string> {\n return new Promise((resolve) => rl.question(q, resolve));\n }\n\n private async openInEditor(relPath: string, content: string): Promise<string | null> {\n const cmd = this.env.TWIN_BUILD_MERGETOOL ?? \"code --wait\";\n const [bin, ...baseArgs] = cmd.split(/\\s+/);\n if (!bin) return null;\n const dir = mkdtempSync(join(tmpdir(), \"twin-build-merge-edit-\"));\n const filePath = join(dir, relPath.replace(/[/\\\\]/g, \"_\"));\n writeFileSync(filePath, content, \"utf8\");\n try {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(bin, [...baseArgs, filePath], { stdio: \"inherit\" });\n child.on(\"close\", (code) =>\n code === 0\n ? resolve()\n : reject(new Error(`mergetool exited with code ${code}`)),\n );\n child.on(\"error\", reject);\n });\n return readFileSync(filePath, \"utf8\");\n } catch (err) {\n this.write(\n ` failed to launch ${bin}: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n return null;\n } finally {\n rmSync(dir, { recursive: true, force: true });\n }\n }\n}\n","/**\n * Upstream fetcher: download `@twin-build-orchestrate/cli@<version>` and read its\n * templates / CLAUDE.md.\n *\n * 戦略:\n * 1. local cache: `.twin-build/cache/upstream/<version>/` を first source\n * 2. npm view + npm pack: cache miss 時に取得\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §6 (Cache 配置と git ポリシー)\n */\n\nimport { spawn } from \"node:child_process\";\nimport {\n cpSync,\n existsSync,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n readdirSync,\n rmSync,\n statSync,\n} from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join, relative } from \"node:path\";\nimport type { UpstreamFetcher } from \"../sync.js\";\n\nconst UPSTREAM_CACHE_DIR = \".twin-build/cache/upstream\";\nconst DEFAULT_PACKAGE = \"@twin-build-orchestrate/cli\";\n/**\n * Files tracked by sync. The fetcher only exposes these — `.claude/skills/` and\n * other Plugin-owned paths are intentionally excluded.\n */\nconst TRACKED_GLOBS = [\"CLAUDE.md\", \"templates/\"];\n\nexport interface NpmFetcherOptions {\n repoRoot: string;\n packageName?: string;\n /** Override npm executable for testing. */\n npmBin?: string;\n}\n\nexport class NpmUpstreamFetcher implements UpstreamFetcher {\n private readonly cacheDir: string;\n private readonly packageName: string;\n private readonly npmBin: string;\n /** version -> root dir of extracted package. */\n private readonly resolved = new Map<string, string>();\n\n constructor(options: NpmFetcherOptions) {\n this.cacheDir = join(options.repoRoot, UPSTREAM_CACHE_DIR);\n this.packageName = options.packageName ?? DEFAULT_PACKAGE;\n this.npmBin = options.npmBin ?? \"npm\";\n }\n\n async listFiles(version: string): Promise<string[]> {\n const root = await this.ensureExtracted(version);\n return walkTracked(root);\n }\n\n async fetchFile(version: string, relPath: string): Promise<string | null> {\n const root = await this.ensureExtracted(version);\n const path = join(root, relPath);\n if (!existsSync(path)) return null;\n return readFileSync(path, \"utf8\");\n }\n\n private async ensureExtracted(version: string): Promise<string> {\n const cached = this.resolved.get(version);\n if (cached) return cached;\n const versionDir = join(this.cacheDir, version);\n if (existsSync(versionDir) && statSync(versionDir).isDirectory()) {\n this.resolved.set(version, versionDir);\n return versionDir;\n }\n\n mkdirSync(versionDir, { recursive: true });\n const tmpDir = mkdtempSync(join(tmpdir(), \"twin-build-fetch-\"));\n try {\n // npm pack writes a tarball to cwd; we run it inside tmpDir.\n await run(this.npmBin, [\"pack\", `${this.packageName}@${version}`], tmpDir);\n const entries = readdirSync(tmpDir).filter((f) => f.endsWith(\".tgz\"));\n if (entries.length === 0) {\n throw new Error(\n `npm pack produced no tarball for ${this.packageName}@${version}`,\n );\n }\n const tarball = join(tmpDir, entries[0]!);\n await run(\"tar\", [\"xf\", tarball], tmpDir);\n // npm tarballs extract into ./package/\n const pkgDir = join(tmpDir, \"package\");\n if (!existsSync(pkgDir)) {\n throw new Error(`extracted tarball missing 'package' dir at ${tmpDir}`);\n }\n cpSync(pkgDir, versionDir, { recursive: true });\n } finally {\n rmSync(tmpDir, { recursive: true, force: true });\n }\n this.resolved.set(version, versionDir);\n return versionDir;\n }\n}\n\n/**\n * In-memory fetcher for tests. Pre-loaded with `{ version: { path: content } }`.\n */\nexport class MemoryUpstreamFetcher implements UpstreamFetcher {\n constructor(private readonly versions: Record<string, Record<string, string>>) {}\n async listFiles(version: string): Promise<string[]> {\n const files = this.versions[version];\n if (!files) throw new Error(`unknown version: ${version}`);\n return Object.keys(files);\n }\n async fetchFile(version: string, relPath: string): Promise<string | null> {\n return this.versions[version]?.[relPath] ?? null;\n }\n}\n\nfunction walkTracked(root: string): string[] {\n const out: string[] = [];\n const stack: string[] = [];\n for (const entry of TRACKED_GLOBS) {\n const abs = join(root, entry.replace(/\\/$/, \"\"));\n if (!existsSync(abs)) continue;\n if (statSync(abs).isFile()) {\n out.push(entry.replace(/\\/$/, \"\"));\n } else {\n stack.push(abs);\n }\n }\n while (stack.length > 0) {\n const dir = stack.pop()!;\n for (const child of readdirSync(dir)) {\n const abs = join(dir, child);\n const st = statSync(abs);\n if (st.isDirectory()) {\n stack.push(abs);\n } else if (st.isFile()) {\n out.push(relative(root, abs).replace(/\\\\/g, \"/\"));\n }\n }\n }\n return out.sort();\n}\n\nfunction run(cmd: string, args: string[], cwd: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(cmd, args, { cwd, stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n let stderr = \"\";\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString(\"utf8\");\n });\n child.on(\"close\", (code) => {\n if (code === 0) resolve();\n else reject(new Error(`${cmd} ${args.join(\" \")} exited ${code}: ${stderr}`));\n });\n child.on(\"error\", reject);\n });\n}\n","/**\n * `npx twin-build migrate` — 7-phase migration orchestrator.\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §7\n *\n * Phases:\n * 0. Preflight — clean working tree, lock acquire, Plugin / Node / git checks\n * 1. Audit — classify project files against the installed Plugin\n * 2. Plan — emit dispositions, halt on CLAUDE.md conflict > 60%\n * 3. Execute — atomic pre-fetch → write → per-step commit on a new branch\n * 4. Verify — run `twin-build doctor`, sanity-check symlinks/copies\n * 5. PR draft — `gh pr create --draft` carrying audit + plan + verify body\n * 6. Runbook — emit post-merge runbook (markdown)\n *\n * Atomicity (§9.2 F5): the executor pre-fetches every resource before touching\n * the working tree. If any fetch fails the whole run aborts having written\n * nothing. The branch + lock + backup combine to give a robust transaction.\n */\nimport { spawn } from \"node:child_process\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join, relative } from \"node:path\";\nimport { runAudit, renderAuditSummary } from \"./lib/audit.js\";\nimport { createBackup } from \"./lib/backup.js\";\nimport { runExecute } from \"./lib/execute.js\";\nimport { acquireLock, releaseLock, LockBusyError } from \"./lib/lock.js\";\nimport { resolveMigrationChain } from \"./lib/migration-path.js\";\nimport {\n detectInstalledPluginVersion,\n} from \"./lib/paths.js\";\nimport { runPlan, renderPlanMarkdown } from \"./lib/plan.js\";\nimport { runDoctor, renderDoctorReport } from \"./doctor.js\";\nimport type { UpstreamFetcher } from \"./sync.js\";\nimport type {\n MigrateOptions,\n MigrateResult,\n} from \"./lib/migrate-types.js\";\nimport {\n compatibilityMatrixSchema,\n type CompatibilityMatrix,\n type MigrationPath,\n} from \"../usecases/compatibility/schemas.js\";\n\nconst TWIN_BUILD_JSON = \".twin-build.json\";\nconst COMPATIBILITY_JSON = \".twin-build/cache/compatibility.json\";\nconst COMPATIBILITY_FALLBACK = \"src/prompts/compatibility.json\";\nconst DEFAULT_BRANCH = \"chore/twin-build-migrate\";\n\nexport interface RunMigrateDeps {\n fetcher: UpstreamFetcher;\n /** Override compatibility matrix loader (defaults to filesystem). */\n loadCompatibility?: (repoRoot: string) => CompatibilityMatrix;\n /** Skip git operations in tests. */\n noGit?: boolean;\n /** Skip gh pr create in tests. */\n noPr?: boolean;\n /** Override Plugin detection for tests. */\n installedPluginVersion?: string | null;\n /** Override git executable. */\n gitBin?: string;\n /** Override gh executable. */\n ghBin?: string;\n}\n\nexport async function runMigrate(\n opts: MigrateOptions,\n deps: RunMigrateDeps,\n): Promise<MigrateResult> {\n const result: MigrateResult = {\n reachedPhase: 0,\n halted: false,\n warnings: [],\n };\n\n // ── Phase 0: Preflight ────────────────────────────────────────────────\n const branchName = opts.branchName ?? DEFAULT_BRANCH;\n let lockTaken = false;\n try {\n const lock = acquireLock({\n repoRoot: opts.repoRoot,\n reason: `migrate --to ${opts.toVersion}`,\n });\n lockTaken = true;\n if (lock.takeover) {\n result.warnings.push(\n `removed stale migrate.lock from pid=${lock.payload.pid}`,\n );\n }\n\n if (!opts.dryRun && !deps.noGit) {\n const dirty = await gitDirty(opts.repoRoot, deps.gitBin);\n if (dirty) {\n return halt(\n result,\n 0,\n \"working tree is not clean — commit/stash changes before running migrate\",\n );\n }\n }\n\n const pluginVersion =\n deps.installedPluginVersion === undefined\n ? detectInstalledPluginVersion()\n : deps.installedPluginVersion;\n\n const config = detectTwinBuildConfig(opts.repoRoot);\n\n // Gap B: legacy / uninitialized project → halt and guide to init\n if (!pluginVersion && config.cliVersion === null) {\n return halt(\n result,\n 0,\n \"This project has not been initialized with twin-build \" +\n \"(Plugin not installed AND .twin-build.json has no twinBuild.cliVersion). \" +\n \"Migration would produce empty audit data. Run `npx twin-build init` first.\",\n );\n }\n\n if (!pluginVersion) {\n result.warnings.push(\n \"Plugin is not installed; some Phase 1 audit data will be marked unknown.\",\n );\n }\n\n // Gap C: legacy .twin-build.json schema (e.g. {project_name: \"...\"} only)\n if (config.legacySchema) {\n result.warnings.push(\n \".twin-build.json appears to use a legacy format (missing `twinBuild` block). \" +\n \"Run `npx twin-build init` to update to the current schema.\",\n );\n }\n\n // ── Phase 1: Audit ──────────────────────────────────────────────────\n result.reachedPhase = 1;\n const audit = await runAudit({\n repoRoot: opts.repoRoot,\n baseVersion: config.cliVersion,\n });\n result.audit = audit;\n\n // ── Resolve migration chain (F4 multi-step) ────────────────────────\n const matrix = deps.loadCompatibility?.(opts.repoRoot) ?? loadCompatibilityMatrix(opts.repoRoot);\n const chain = resolveChainForVersions(\n matrix.migrationPaths,\n audit.baseVersion,\n opts.toVersion,\n );\n\n // ── Phase 2: Plan ──────────────────────────────────────────────────\n result.reachedPhase = 2;\n const plan = await runPlan({\n audit,\n fromVersion: audit.baseVersion,\n toVersion: opts.toVersion,\n via: chain.via,\n skipClaudeMd: opts.skipClaudeMd,\n loadCodemodInputs: async (rel) => {\n const ours = safeRead(join(opts.repoRoot, rel));\n const theirs = await deps.fetcher.fetchFile(opts.toVersion, rel);\n if (theirs === null) return null;\n return { base: null, ours, theirs };\n },\n });\n result.plan = plan;\n\n // Always write plan.md for the PR body / Dry-run inspection.\n writePlanMarkdown(opts.repoRoot, plan);\n\n if (plan.halted) {\n return halt(result, 2, plan.haltReason ?? \"plan halted\");\n }\n if (opts.dryRun) {\n result.reachedPhase = 2;\n return result;\n }\n\n // ── Phase 3: Confirm + Execute ─────────────────────────────────────\n result.reachedPhase = 3;\n if (!deps.noGit) {\n await gitCheckoutNew(opts.repoRoot, branchName, deps.gitBin);\n }\n\n // Pre-fetch every upstream resource (atomic transaction property).\n const preFetched = new Map<string, string>();\n const preFetchedOurs = new Map<string, string>();\n const preFetchedBase = new Map<string, string | null>();\n for (const step of plan.steps) {\n if (step.disposition === \"keep\" || step.disposition === \"replace-with-symlink\") {\n continue;\n }\n const upstream = await deps.fetcher.fetchFile(opts.toVersion, step.relPath);\n if (upstream === null) {\n return halt(\n result,\n 3,\n `upstream content missing for ${step.relPath} — atomic transaction aborted`,\n );\n }\n preFetched.set(step.relPath, upstream);\n if (step.disposition === \"merge-claude-md\") {\n preFetchedOurs.set(step.relPath, safeRead(join(opts.repoRoot, step.relPath)));\n preFetchedBase.set(step.relPath, null);\n }\n }\n\n // Backup before mutating.\n const backup = createBackup({\n repoRoot: opts.repoRoot,\n fromVersion: audit.baseVersion,\n toVersion: opts.toVersion,\n requiredPluginVersion: pluginVersion ?? \"unknown\",\n files: filesToBackup(opts.repoRoot, plan),\n branch: branchName,\n planRef: relative(opts.repoRoot, join(opts.repoRoot, \".twin-build\", \"migration-plan.md\")),\n });\n result.backupDir = backup.dir;\n\n const execute = await runExecute({\n repoRoot: opts.repoRoot,\n plan,\n preFetched,\n preFetchedBase,\n preFetchedOurs,\n toVersion: opts.toVersion,\n branch: branchName,\n pluginVersion,\n agentMode: opts.agentMode,\n linkStrategy: opts.repoRoot\n ? detectLinkStrategy(opts.repoRoot)\n : \"symlink\",\n gitBin: deps.gitBin,\n noCommit: deps.noGit,\n });\n if (execute.haltedAtFile) {\n return halt(\n result,\n 3,\n `${execute.haltReason ?? \"execute halt\"} (at ${execute.haltedAtFile})`,\n );\n }\n result.commits = execute.commits;\n\n // Update .twin-build.json history.\n if (!deps.noGit) {\n updateTwinBuildHistory(opts.repoRoot, opts.toVersion);\n const gitBin = deps.gitBin ?? \"git\";\n await run(gitBin, [\"add\", \"--\", TWIN_BUILD_JSON], opts.repoRoot).catch(() => undefined);\n await run(gitBin, [\"commit\", \"-m\", `chore(migrate): bump .twin-build.json history to ${opts.toVersion}`], opts.repoRoot).catch(() => undefined);\n }\n\n // ── Phase 4: Verify ────────────────────────────────────────────────\n result.reachedPhase = 4;\n const doctor = await runDoctor({\n repoRoot: opts.repoRoot,\n fix: false,\n diagnose: false,\n });\n if (!doctor.passed) {\n result.warnings.push(\"twin-build doctor reported issues — see Phase 5 PR body\");\n }\n writeVerifyReport(opts.repoRoot, doctor);\n\n // ── Phase 5: PR draft ─────────────────────────────────────────────\n result.reachedPhase = 5;\n if (!deps.noGit && !deps.noPr) {\n const prUrl = await ghPrCreate(opts.repoRoot, opts.toVersion, deps.ghBin);\n if (prUrl) {\n result.prUrl = prUrl;\n } else {\n result.warnings.push(\n \"gh pr create did not return a URL (gh CLI missing, unauthenticated, or remote unset) — create the PR manually using .twin-build/migration-plan.md as the body\",\n );\n }\n }\n\n // ── Phase 6: Runbook ──────────────────────────────────────────────\n result.reachedPhase = 6;\n writeRunbook(opts.repoRoot, opts.toVersion, audit.baseVersion);\n\n return result;\n } catch (err) {\n if (err instanceof LockBusyError) {\n return halt(result, 0, err.message);\n }\n throw err;\n } finally {\n if (lockTaken) releaseLock(opts.repoRoot);\n }\n}\n\nfunction halt(\n result: MigrateResult,\n phase: MigrateResult[\"reachedPhase\"],\n reason: string,\n): MigrateResult {\n result.reachedPhase = phase;\n result.halted = true;\n result.haltReason = reason;\n return result;\n}\n\ninterface TwinBuildConfig {\n /** CLI version recorded by `twin-build init`, or null if not set. */\n cliVersion: string | null;\n /**\n * True when .twin-build.json exists but lacks the `twinBuild` key —\n * indicating a legacy format (e.g. `{\"project_name\": \"...\"}` only).\n */\n legacySchema: boolean;\n}\n\nfunction detectTwinBuildConfig(repoRoot: string): TwinBuildConfig {\n const path = join(repoRoot, TWIN_BUILD_JSON);\n if (!existsSync(path)) return { cliVersion: null, legacySchema: false };\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf8\")) as Record<string, unknown>;\n const hasTwinBuildKey = \"twinBuild\" in parsed;\n const twinBuild = parsed[\"twinBuild\"] as { cliVersion?: string } | undefined;\n return {\n cliVersion: twinBuild?.cliVersion ?? null,\n legacySchema: !hasTwinBuildKey,\n };\n } catch {\n return { cliVersion: null, legacySchema: false };\n }\n}\n\nfunction loadCompatibilityMatrix(repoRoot: string): CompatibilityMatrix {\n for (const rel of [COMPATIBILITY_JSON, COMPATIBILITY_FALLBACK]) {\n const path = join(repoRoot, rel);\n if (!existsSync(path)) continue;\n try {\n return compatibilityMatrixSchema.parse(\n JSON.parse(readFileSync(path, \"utf8\")),\n );\n } catch {\n // try next\n }\n }\n // Empty matrix → forces direct hop with warning.\n return compatibilityMatrixSchema.parse({ rules: [] });\n}\n\nfunction resolveChainForVersions(\n paths: MigrationPath[],\n from: string | null,\n to: string,\n): { via: string[]; unrecorded: boolean } {\n if (!from) return { via: [], unrecorded: true };\n const resolved = resolveMigrationChain(paths, from, to, { allowDirectHop: true });\n // chain is [..via, to]; we record only the intermediate hops.\n const via = resolved.chain.slice(0, -1);\n return { via, unrecorded: resolved.unrecordedDirect };\n}\n\nfunction detectLinkStrategy(repoRoot: string): \"symlink\" | \"copy\" {\n // Read .twin-build.json if available; fall back to OS default.\n const path = join(repoRoot, TWIN_BUILD_JSON);\n if (existsSync(path)) {\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf8\")) as {\n twinBuild?: { linkStrategy?: \"symlink\" | \"copy\" };\n };\n if (parsed.twinBuild?.linkStrategy) return parsed.twinBuild.linkStrategy;\n } catch {\n // ignore\n }\n }\n return process.platform === \"win32\" ? \"copy\" : \"symlink\";\n}\n\nfunction filesToBackup(repoRoot: string, plan: { steps: Array<{ relPath: string }> }): string[] {\n const set = new Set<string>();\n set.add(TWIN_BUILD_JSON);\n for (const s of plan.steps) {\n if (existsSync(join(repoRoot, s.relPath))) set.add(s.relPath);\n }\n return [...set];\n}\n\nfunction writePlanMarkdown(repoRoot: string, plan: import(\"./lib/migrate-types.js\").MigrationPlan): void {\n const dest = join(repoRoot, \".twin-build\", \"migration-plan.md\");\n const md = renderPlanMarkdown(plan);\n try {\n mkdirSync(dirname(dest), { recursive: true });\n writeFileSync(dest, md + \"\\n\", \"utf8\");\n } catch {\n // best effort\n }\n}\n\nfunction writeVerifyReport(repoRoot: string, doctor: Parameters<typeof renderDoctorReport>[0]): void {\n const dest = join(repoRoot, \".twin-build\", \"migration-verify.md\");\n try {\n mkdirSync(dirname(dest), { recursive: true });\n writeFileSync(\n dest,\n \"# Migrate verify report\\n\\n```\\n\" + renderDoctorReport(doctor) + \"\\n```\\n\",\n \"utf8\",\n );\n } catch {\n // best effort\n }\n}\n\nfunction writeRunbook(repoRoot: string, toVersion: string, fromVersion: string | null): void {\n const dest = join(repoRoot, \".twin-build\", \"migration-runbook.md\");\n try {\n mkdirSync(dirname(dest), { recursive: true });\n } catch {\n // best effort\n }\n const md = [\n `# Migration runbook (${fromVersion ?? \"?\"} → ${toVersion})`,\n \"\",\n \"## For each team member\",\n \"1. `git pull` the merged migration commit.\",\n \"2. Run `npx twin-build doctor` to confirm the local cache + symlinks are healthy.\",\n \"3. If Plugin install is required: open Claude Code → /plugin → Marketplace → twin-build.\",\n \"\",\n \"## For CI\",\n \"1. Update version pins in CI workflows to match the new `.twin-build.json`.\",\n \"2. Re-run pipelines after PR merge to confirm no regression.\",\n \"\",\n \"## Rollback\",\n `- A backup is recorded under \\`.twin-build/migration-backup/\\`. To revert, run:`,\n \" `npx twin-build migrate rollback`\",\n \"- A specific timestamp can be selected with `--to <timestamp>`.\",\n \"\",\n \"## Deprecation warning\",\n \"- The previous fork-based layout enters a 6-month deprecation window. CI\",\n \" pipelines should emit a warning until the next major release.\",\n ];\n try {\n writeFileSync(dest, md.join(\"\\n\") + \"\\n\", \"utf8\");\n } catch {\n // best effort\n }\n}\n\nfunction updateTwinBuildHistory(repoRoot: string, toVersion: string): void {\n const path = join(repoRoot, TWIN_BUILD_JSON);\n if (!existsSync(path)) return;\n try {\n const doc = JSON.parse(readFileSync(path, \"utf8\")) as {\n twinBuild?: {\n cliVersion?: string;\n history?: Array<{ at: string; cliVersion?: string }>;\n };\n };\n if (!doc.twinBuild) return;\n doc.twinBuild.cliVersion = toVersion;\n doc.twinBuild.history = doc.twinBuild.history ?? [];\n doc.twinBuild.history.push({\n at: new Date().toISOString(),\n cliVersion: toVersion,\n });\n writeFileSync(path, JSON.stringify(doc, null, 2) + \"\\n\", \"utf8\");\n } catch {\n // best effort\n }\n}\n\nfunction safeRead(path: string): string {\n try {\n return readFileSync(path, \"utf8\");\n } catch {\n return \"\";\n }\n}\n\nasync function gitDirty(repoRoot: string, gitBin = \"git\"): Promise<boolean> {\n try {\n const out = await capture(gitBin, [\"status\", \"--porcelain\"], repoRoot);\n return out.trim().length > 0;\n } catch {\n return false;\n }\n}\n\nasync function gitCheckoutNew(repoRoot: string, branch: string, gitBin = \"git\"): Promise<void> {\n try {\n await run(gitBin, [\"checkout\", \"-b\", branch], repoRoot);\n } catch {\n // Branch may already exist; try plain checkout.\n await run(gitBin, [\"checkout\", branch], repoRoot);\n }\n}\n\nasync function ghPrCreate(\n repoRoot: string,\n toVersion: string,\n ghBin = \"gh\",\n): Promise<string | null> {\n const title = `chore(migrate): twin-build → ${toVersion}`;\n const body =\n \"Generated by `twin-build migrate`. See `.twin-build/migration-plan.md` and `.twin-build/migration-verify.md` for the audit, plan, and verify details.\\n\\n**auto-merge disabled**\";\n try {\n const stdout = await capture(\n ghBin,\n [\"pr\", \"create\", \"--draft\", \"--title\", title, \"--body\", body],\n repoRoot,\n );\n const match = stdout.match(/https?:\\/\\/\\S+/);\n return match ? match[0] : null;\n } catch {\n return null;\n }\n}\n\nfunction run(cmd: string, args: string[], cwd: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(cmd, args, { cwd, stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n let stderr = \"\";\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString(\"utf8\");\n });\n child.on(\"close\", (code) => {\n if (code === 0) resolve();\n else reject(new Error(`${cmd} ${args.join(\" \")} exited ${code}: ${stderr}`));\n });\n child.on(\"error\", reject);\n });\n}\n\nfunction capture(cmd: string, args: string[], cwd: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn(cmd, args, { cwd, stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout.on(\"data\", (chunk: Buffer) => {\n stdout += chunk.toString(\"utf8\");\n });\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString(\"utf8\");\n });\n child.on(\"close\", (code) => {\n if (code === 0) resolve(stdout);\n else reject(new Error(`${cmd} ${args.join(\" \")} exited ${code}: ${stderr}`));\n });\n child.on(\"error\", reject);\n });\n}\n\n/** Render a human-readable summary of a migrate run. */\nexport function renderMigrateSummary(result: MigrateResult): string {\n const lines = [\n `twin-build migrate — reached phase ${result.reachedPhase}${result.halted ? \" (halted)\" : \"\"}`,\n ];\n if (result.haltReason) lines.push(` halt: ${result.haltReason}`);\n if (result.audit) lines.push(renderAuditSummary(result.audit));\n if (result.plan) lines.push(renderPlanMarkdown(result.plan));\n if (result.commits && result.commits.length > 0) {\n lines.push(` commits: ${result.commits.length}`);\n for (const sha of result.commits) lines.push(` - ${sha}`);\n }\n if (result.prUrl) lines.push(` PR: ${result.prUrl}`);\n if (result.backupDir) lines.push(` backup: ${result.backupDir}`);\n if (result.warnings.length > 0) {\n lines.push(\" warnings:\");\n for (const w of result.warnings) lines.push(` - ${w}`);\n }\n return lines.join(\"\\n\");\n}\n\n","/**\n * Phase 1: Audit — walk the project tree and classify each skill / rules file\n * against the installed Plugin's catalog and the upstream package's tracked\n * files.\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §7 Phase 1\n *\n * Origin classes:\n * - \"upstream\" — file is byte-identical to the Plugin/upstream\n * counterpart (= safe to replace with symlink/copy)\n * - \"upstream-modified\" — file exists in Plugin/upstream but was edited\n * (= conflict candidate; needs codemod)\n * - \"project-only\" — no upstream counterpart (= keep as-is, never touch)\n * - \"unknown\" — could not determine (e.g. Plugin not installed)\n */\nimport { createHash } from \"node:crypto\";\nimport {\n existsSync,\n readFileSync,\n readdirSync,\n statSync,\n} from \"node:fs\";\nimport { join, relative } from \"node:path\";\n// `relative` retained for walk() repoRoot-relativisation.\nimport {\n detectInstalledPluginVersion,\n pluginCachePath,\n} from \"./paths.js\";\nimport type {\n AuditEntry,\n AuditResult,\n SkillOrigin,\n} from \"./migrate-types.js\";\n\nconst SKILLS_DIR = \".claude/skills\";\nconst RULES_DIR = \".claude/rules\";\nconst CLAUDE_MD = \"CLAUDE.md\";\n\nexport interface AuditOptions {\n repoRoot: string;\n /** Override $HOME for tests. */\n home?: string;\n /** Base version recorded by sync (for trace). */\n baseVersion?: string | null;\n /** Pre-resolved Plugin cache root (for tests that bypass detection). */\n pluginCacheRoot?: string;\n /** When supplied, use these files instead of scanning the Plugin cache. */\n pluginInventory?: Map<string, string>;\n}\n\nexport async function runAudit(opts: AuditOptions): Promise<AuditResult> {\n const generatedAt = new Date().toISOString();\n const pluginVersion =\n detectInstalledPluginVersion(opts.home) ?? null;\n const pluginInventory = await loadPluginInventory(opts, pluginVersion);\n const pluginInstalled = pluginVersion !== null || opts.pluginCacheRoot !== undefined;\n\n const entries: AuditEntry[] = [];\n\n // CLAUDE.md\n const claudeMdPath = join(opts.repoRoot, CLAUDE_MD);\n if (existsSync(claudeMdPath)) {\n entries.push(\n classifyFile(CLAUDE_MD, claudeMdPath, \"claude-md\", pluginInventory),\n );\n }\n\n // .claude/skills/**\n const skillsRoot = join(opts.repoRoot, SKILLS_DIR);\n if (existsSync(skillsRoot)) {\n for (const rel of walk(skillsRoot, opts.repoRoot)) {\n entries.push(classifyFile(rel, join(opts.repoRoot, rel), \"skill\", pluginInventory));\n }\n }\n\n // .claude/rules/**\n const rulesRoot = join(opts.repoRoot, RULES_DIR);\n if (existsSync(rulesRoot)) {\n for (const rel of walk(rulesRoot, opts.repoRoot)) {\n entries.push(classifyFile(rel, join(opts.repoRoot, rel), \"rules\", pluginInventory));\n }\n }\n\n // Stable order for deterministic plan generation.\n entries.sort((a, b) => a.relPath.localeCompare(b.relPath));\n\n return {\n generatedAt,\n baseVersion: opts.baseVersion ?? null,\n pluginInstalled,\n pluginVersion,\n entries,\n };\n}\n\nasync function loadPluginInventory(\n opts: AuditOptions,\n pluginVersion: string | null,\n): Promise<Map<string, string>> {\n if (opts.pluginInventory) return opts.pluginInventory;\n let root: string | null = null;\n if (opts.pluginCacheRoot) {\n root = opts.pluginCacheRoot;\n } else if (pluginVersion) {\n root = pluginCachePath(pluginVersion, opts.home);\n }\n if (!root || !existsSync(root)) return new Map();\n const inventory = new Map<string, string>();\n // The Plugin layout mirrors `.claude/` (skills/, rules/, CLAUDE.md).\n const claudeMdAbs = join(root, CLAUDE_MD);\n if (existsSync(claudeMdAbs) && statSync(claudeMdAbs).isFile()) {\n inventory.set(CLAUDE_MD, sha256(readFileSync(claudeMdAbs, \"utf8\")));\n }\n for (const sub of [\"skills\", \"rules\"]) {\n const abs = join(root, sub);\n if (!existsSync(abs)) continue;\n for (const relFromRoot of walk(abs, root)) {\n const projectRel = `.claude/${relFromRoot}`;\n inventory.set(\n projectRel,\n sha256(readFileSync(join(root, relFromRoot), \"utf8\")),\n );\n }\n }\n return inventory;\n}\n\nfunction classifyFile(\n relPath: string,\n absPath: string,\n kind: AuditEntry[\"kind\"],\n pluginInventory: Map<string, string>,\n): AuditEntry {\n const origin = determineOrigin(relPath, absPath, pluginInventory);\n return { relPath, kind, origin };\n}\n\nfunction determineOrigin(\n relPath: string,\n absPath: string,\n pluginInventory: Map<string, string>,\n): SkillOrigin {\n if (pluginInventory.size === 0) return \"unknown\";\n const upstreamHash = pluginInventory.get(relPath);\n if (!upstreamHash) return \"project-only\";\n // Compare file vs upstream. Symlinks resolve transparently via readFileSync.\n let projectContent: string;\n try {\n projectContent = readFileSync(absPath, \"utf8\");\n } catch {\n return \"unknown\";\n }\n return sha256(projectContent) === upstreamHash\n ? \"upstream\"\n : \"upstream-modified\";\n}\n\nfunction sha256(value: string): string {\n return createHash(\"sha256\").update(value, \"utf8\").digest(\"hex\");\n}\n\nfunction walk(root: string, repoRoot: string): string[] {\n const out: string[] = [];\n const stack = [root];\n while (stack.length > 0) {\n const dir = stack.pop()!;\n for (const child of readdirSync(dir)) {\n const abs = join(dir, child);\n let st;\n try {\n st = statSync(abs);\n } catch {\n // Broken symlink (common when Plugin uninstalled but .claude/skills/\n // still points at a vanished cache dir). Treat as missing entry.\n continue;\n }\n if (st.isDirectory()) {\n stack.push(abs);\n } else if (st.isFile()) {\n out.push(relative(repoRoot, abs).replace(/\\\\/g, \"/\"));\n }\n }\n }\n return out;\n}\n\n/** Summarise an audit result as human-readable text. */\nexport function renderAuditSummary(audit: AuditResult): string {\n const buckets = new Map<SkillOrigin, number>();\n for (const e of audit.entries) {\n buckets.set(e.origin, (buckets.get(e.origin) ?? 0) + 1);\n }\n const lines = [\n `Audit (generated ${audit.generatedAt}):`,\n ` Plugin installed: ${audit.pluginInstalled ? `yes (${audit.pluginVersion})` : \"no\"}`,\n ` Base version: ${audit.baseVersion ?? \"(unknown)\"}`,\n ` Total files: ${audit.entries.length}`,\n ];\n for (const [origin, n] of buckets) {\n lines.push(` - ${origin}: ${n}`);\n }\n return lines.join(\"\\n\");\n}\n","/**\n * Backup / rollback / prune for `twin-build migrate`.\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §7 Phase 3 / §9.4 T2-14\n *\n * Layout:\n * .twin-build/migration-backup/<ISO-timestamp-safe>/\n * ├── manifest.json ({ createdAt, fromVersion, toVersion,\n * │ requiredPluginVersion, files, branch?, planRef? })\n * └── files/\n * ├── CLAUDE.md\n * ├── .twin-build.json\n * └── .claude/skills/...\n *\n * Rollback Phase 0:\n * - confirm `<requiredPluginVersion>` is installed (T2-14). If not, halt\n * with `/plugin install <requiredPluginVersion>` guidance.\n */\nimport {\n cpSync,\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n rmSync,\n statSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport {\n detectInstalledPluginVersion,\n} from \"./paths.js\";\nimport {\n backupManifestSchema,\n type BackupManifest,\n type PruneOptions,\n type PruneResult,\n type RollbackOptions,\n type RollbackResult,\n} from \"./migrate-types.js\";\n\nconst BACKUP_ROOT = \".twin-build/migration-backup\";\nconst MS_PER_DAY = 24 * 60 * 60 * 1000;\n\n/** Make a filesystem-safe timestamp slug (no `:` characters). */\nexport function timestampSlug(now: Date): string {\n return now.toISOString().replace(/[:]/g, \"-\");\n}\n\nexport interface CreateBackupOptions {\n repoRoot: string;\n fromVersion: string | null;\n toVersion: string;\n /** Plugin version required to roll back (T2-14). */\n requiredPluginVersion: string;\n /** Files (relative to repoRoot) to capture. */\n files: string[];\n branch?: string;\n planRef?: string;\n now?: () => Date;\n}\n\nexport interface CreateBackupResult {\n dir: string;\n manifest: BackupManifest;\n filesCaptured: string[];\n}\n\nexport function createBackup(\n opts: CreateBackupOptions,\n): CreateBackupResult {\n const now = (opts.now?.() ?? new Date()).toISOString();\n const slug = timestampSlug(opts.now?.() ?? new Date(now));\n const dir = join(opts.repoRoot, BACKUP_ROOT, slug);\n const filesDir = join(dir, \"files\");\n mkdirSync(filesDir, { recursive: true });\n\n const captured: string[] = [];\n for (const rel of opts.files) {\n const src = join(opts.repoRoot, rel);\n if (!existsSync(src)) continue;\n const dest = join(filesDir, rel);\n mkdirSync(dirname(dest), { recursive: true });\n // dereference symlinks so the backup can restore the actual content even\n // if the original Plugin cache moved.\n cpSync(src, dest, { recursive: true, dereference: true });\n captured.push(rel);\n }\n captured.sort();\n\n const manifest: BackupManifest = {\n createdAt: now,\n fromVersion: opts.fromVersion,\n toVersion: opts.toVersion,\n requiredPluginVersion: opts.requiredPluginVersion,\n files: captured,\n branch: opts.branch,\n planRef: opts.planRef,\n };\n writeFileSync(\n join(dir, \"manifest.json\"),\n JSON.stringify(manifest, null, 2) + \"\\n\",\n \"utf8\",\n );\n\n return { dir, manifest, filesCaptured: captured };\n}\n\nexport class BackupNotFoundError extends Error {\n readonly code = \"BACKUP_NOT_FOUND\";\n constructor(\n readonly repoRoot: string,\n readonly target?: string,\n ) {\n super(\n target\n ? `backup ${target} not found under ${BACKUP_ROOT}/`\n : `no backups available under ${BACKUP_ROOT}/`,\n );\n }\n}\n\nexport class PluginVersionMissingError extends Error {\n readonly code = \"ROLLBACK_PLUGIN_MISSING\";\n constructor(\n readonly required: string,\n readonly installed: string | null,\n ) {\n super(\n `rollback requires Plugin ${required}; installed: ${installed ?? \"none\"}. ` +\n `Run \\`/plugin install twin-build@${required}\\` and retry.`,\n );\n }\n}\n\nexport function listBackups(repoRoot: string): string[] {\n const root = join(repoRoot, BACKUP_ROOT);\n if (!existsSync(root)) return [];\n return readdirSync(root)\n .filter((name) => existsSync(join(root, name, \"manifest.json\")))\n .sort();\n}\n\nexport function readBackupManifest(\n repoRoot: string,\n slug: string,\n): BackupManifest {\n const manifestPath = join(repoRoot, BACKUP_ROOT, slug, \"manifest.json\");\n if (!existsSync(manifestPath)) {\n throw new BackupNotFoundError(repoRoot, slug);\n }\n const text = readFileSync(manifestPath, \"utf8\");\n const parsed = backupManifestSchema.parse(JSON.parse(text));\n return parsed;\n}\n\nexport function rollback(opts: RollbackOptions): RollbackResult {\n const slug = resolveTargetSlug(opts);\n const manifest = readBackupManifest(opts.repoRoot, slug);\n\n // Phase 0: ensure required Plugin version is installed (T2-14).\n const installed = detectInstalledPluginVersion(opts.home);\n if (installed !== manifest.requiredPluginVersion) {\n throw new PluginVersionMissingError(\n manifest.requiredPluginVersion,\n installed,\n );\n }\n\n const warnings: string[] = [];\n const filesDir = join(opts.repoRoot, BACKUP_ROOT, slug, \"files\");\n if (!existsSync(filesDir)) {\n throw new BackupNotFoundError(opts.repoRoot, slug);\n }\n\n const restored: string[] = [];\n for (const rel of manifest.files) {\n const src = join(filesDir, rel);\n const dest = join(opts.repoRoot, rel);\n if (!existsSync(src)) {\n warnings.push(`backup is missing ${rel}; skipping`);\n continue;\n }\n mkdirSync(dirname(dest), { recursive: true });\n const st = statSync(src);\n if (st.isDirectory()) {\n // Restore directories by overwriting recursively.\n cpSync(src, dest, { recursive: true });\n } else {\n cpSync(src, dest, { force: true });\n }\n restored.push(rel);\n }\n\n return {\n restoredFrom: slug,\n manifest,\n filesRestored: restored,\n warnings,\n };\n}\n\nexport function pruneBackups(opts: PruneOptions): PruneResult {\n const root = join(opts.repoRoot, BACKUP_ROOT);\n const result: PruneResult = { removed: [], kept: [] };\n if (!existsSync(root)) return result;\n const maxAgeDays = opts.maxAgeDays ?? 30;\n const cutoff =\n (opts.now?.() ?? new Date()).getTime() - maxAgeDays * MS_PER_DAY;\n\n for (const slug of readdirSync(root)) {\n const dir = join(root, slug);\n const manifestPath = join(dir, \"manifest.json\");\n if (!existsSync(manifestPath)) {\n result.kept.push(slug);\n continue;\n }\n let createdMs: number;\n try {\n const parsed = backupManifestSchema.parse(\n JSON.parse(readFileSync(manifestPath, \"utf8\")),\n );\n createdMs = new Date(parsed.createdAt).getTime();\n } catch {\n // Unparsable manifest → keep (safer than delete).\n result.kept.push(slug);\n continue;\n }\n if (Number.isFinite(createdMs) && createdMs < cutoff) {\n rmSync(dir, { recursive: true, force: true });\n result.removed.push(slug);\n } else {\n result.kept.push(slug);\n }\n }\n return result;\n}\n\nfunction resolveTargetSlug(opts: RollbackOptions): string {\n if (opts.toTimestamp) {\n const explicit = opts.toTimestamp;\n if (!existsSync(join(opts.repoRoot, BACKUP_ROOT, explicit, \"manifest.json\"))) {\n throw new BackupNotFoundError(opts.repoRoot, explicit);\n }\n return explicit;\n }\n const all = listBackups(opts.repoRoot);\n if (all.length === 0) throw new BackupNotFoundError(opts.repoRoot);\n return all[all.length - 1]!;\n}\n","/**\n * Shared types and Zod schemas used by `twin-build migrate`.\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §7\n *\n * 中央集権的に型を定義することで、audit/plan/execute/backup/migration-path\n * が相互に参照できるようにする。\n */\nimport { z } from \"zod\";\n\n/** Origin classification for a skill / rules file. */\nexport type SkillOrigin =\n | \"upstream\"\n | \"upstream-modified\"\n | \"project-only\"\n | \"unknown\";\n\nexport const skillOriginSchema = z.enum([\n \"upstream\",\n \"upstream-modified\",\n \"project-only\",\n \"unknown\",\n]);\n\n/** Per-file disposition decided by Phase 2 Plan. */\nexport type PlanDisposition =\n | \"keep\"\n | \"replace-with-symlink\"\n | \"replace-with-copy\"\n | \"archive\"\n | \"merge-claude-md\";\n\nexport const planDispositionSchema = z.enum([\n \"keep\",\n \"replace-with-symlink\",\n \"replace-with-copy\",\n \"archive\",\n \"merge-claude-md\",\n]);\n\n/** Audit result for one skill / rules file. */\nexport const auditEntrySchema = z.object({\n relPath: z.string().min(1),\n kind: z.enum([\"skill\", \"rules\", \"claude-md\", \"other\"]),\n origin: skillOriginSchema,\n notes: z.string().optional(),\n});\nexport type AuditEntry = z.infer<typeof auditEntrySchema>;\n\nexport const auditResultSchema = z.object({\n generatedAt: z.string(),\n baseVersion: z.string().nullable(),\n pluginInstalled: z.boolean(),\n pluginVersion: z.string().nullable(),\n entries: z.array(auditEntrySchema),\n});\nexport type AuditResult = z.infer<typeof auditResultSchema>;\n\n/** Plan step — what will happen to one file. */\nexport const planStepSchema = z.object({\n relPath: z.string().min(1),\n disposition: planDispositionSchema,\n reason: z.string(),\n /** Estimated conflict ratio for the codemod patch (0..1). */\n conflictRatio: z.number().min(0).max(1).optional(),\n});\nexport type PlanStep = z.infer<typeof planStepSchema>;\n\nexport const migrationPlanSchema = z.object({\n fromVersion: z.string().nullable(),\n toVersion: z.string(),\n via: z.array(z.string()).default([]),\n steps: z.array(planStepSchema),\n /** True when CLAUDE.md conflict ratio exceeded threshold and Phase 2 halted. */\n halted: z.boolean().default(false),\n haltReason: z.string().optional(),\n});\nexport type MigrationPlan = z.infer<typeof migrationPlanSchema>;\n\n/** Backup manifest stored under .twin-build/migration-backup/<ts>/manifest.json */\nexport const backupManifestSchema = z.object({\n /** ISO-8601 timestamp when the backup was created. */\n createdAt: z.string(),\n /** Source version (pre-migrate) — for rollback target verification. */\n fromVersion: z.string().nullable(),\n toVersion: z.string(),\n /** Plugin version required to safely rollback (T2-14). */\n requiredPluginVersion: z.string(),\n /** Relative paths captured in the backup, relative to <ts>/files/. */\n files: z.array(z.string()),\n /** Branch the migrate operation ran on. */\n branch: z.string().optional(),\n /** Migration plan reference (for traceability). */\n planRef: z.string().optional(),\n});\nexport type BackupManifest = z.infer<typeof backupManifestSchema>;\n\n/** Lock file payload (PID + timestamp). */\nexport const lockFileSchema = z.object({\n pid: z.number().int().positive(),\n acquiredAt: z.string(),\n hostname: z.string().optional(),\n reason: z.string().optional(),\n});\nexport type LockFilePayload = z.infer<typeof lockFileSchema>;\n\n/** Top-level migrate options consumed by the handler. */\nexport interface MigrateOptions {\n repoRoot: string;\n /** Target version (axis = cli for now). Defaults to \"latest\". */\n toVersion: string;\n /** Dry-run halts after Phase 2 Plan. */\n dryRun: boolean;\n /** Skip the CLAUDE.md merge step (Phase 2 F9 retry). */\n skipClaudeMd: boolean;\n /** Auto-confirm Phase 3 Execute (CI / agent mode). */\n yesAll: boolean;\n /** Agent mode — conflict triggers halt + event (横断警告 #3). */\n agentMode: boolean;\n /** Branch name override; default `chore/twin-build-migrate`. */\n branchName?: string;\n /** Inject Date.now() for prune testing. */\n now?: () => Date;\n}\n\n/** Result returned by runMigrate. */\nexport interface MigrateResult {\n /** Phase the run reached. */\n reachedPhase: 0 | 1 | 2 | 3 | 4 | 5 | 6;\n /** True when the operation halted partway. */\n halted: boolean;\n haltReason?: string;\n audit?: AuditResult;\n plan?: MigrationPlan;\n backupDir?: string;\n prUrl?: string;\n commits?: string[];\n warnings: string[];\n}\n\n/** Rollback options. */\nexport interface RollbackOptions {\n repoRoot: string;\n /** Specific backup timestamp; default = latest. */\n toTimestamp?: string;\n /** Agent mode — halt instead of prompting. */\n agentMode: boolean;\n /** Override Date.now() / home for tests. */\n now?: () => Date;\n home?: string;\n}\n\nexport interface RollbackResult {\n restoredFrom: string;\n manifest: BackupManifest;\n filesRestored: string[];\n warnings: string[];\n}\n\n/** Prune-backups options. */\nexport interface PruneOptions {\n repoRoot: string;\n /** Max age in days (default 30). */\n maxAgeDays?: number;\n /** Inject Date.now() for testing. */\n now?: () => Date;\n}\n\nexport interface PruneResult {\n removed: string[];\n kept: string[];\n}\n","/**\n * Phase 3: Confirm + Execute — the actual file mutations.\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §7 Phase 3 / §9.2 F5\n *\n * Atomic guarantees:\n * 1. All upstream content is pre-fetched (codemod inputs + upstream files)\n * before we touch the working tree. If fetching any resource fails the\n * handler aborts without writing anything (Copier-style transaction).\n * 2. Each plan step is applied to the working tree, then committed\n * individually so the resulting branch carries a per-step revert unit.\n * 3. agent mode (`TWIN_BUILD_AGENT_MODE=1`): a conflict on a non-claude file\n * halts and surfaces an `audience: human` event payload — never overwrite\n * silently (横断警告 #3 / Yeoman #725).\n */\nimport { spawn } from \"node:child_process\";\nimport {\n cpSync,\n existsSync,\n mkdirSync,\n readFileSync,\n rmSync,\n statSync,\n symlinkSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join, relative } from \"node:path\";\nimport { mergeThreeWay } from \"./merge.js\";\nimport { pluginCachePath } from \"./paths.js\";\nimport { isIntegrityTrackedPath, recordIntegrity } from \"./integrity.js\";\nimport type {\n MigrationPlan,\n PlanStep,\n} from \"./migrate-types.js\";\n\nconst CLAUDE_MD = \"CLAUDE.md\";\n\nexport interface ExecuteOptions {\n repoRoot: string;\n plan: MigrationPlan;\n /** Pre-resolved upstream content for each plan step. Pre-fetched before\n * any mutations (atomic transaction property). */\n preFetched: Map<string, string>;\n /** Pre-resolved base content for codemod inputs (CLAUDE.md only). */\n preFetchedBase?: Map<string, string | null>;\n /** Pre-resolved ours content for codemod inputs. */\n preFetchedOurs?: Map<string, string>;\n /** Target version to record after success. */\n toVersion: string;\n /** Branch on which the executor is operating (for commit messages). */\n branch: string;\n /** Pre-resolved Plugin version to symlink against. */\n pluginVersion: string | null;\n /** Override $HOME for tests. */\n home?: string;\n /** Agent mode — halt instead of writing conflict markers. */\n agentMode: boolean;\n /** Default link strategy. */\n linkStrategy: \"symlink\" | \"copy\";\n /** Override git executable for tests. */\n gitBin?: string;\n /** Skip git commits — used by tests / dry-run. */\n noCommit?: boolean;\n}\n\nexport interface ExecuteResult {\n /** True when at least one plan step ran. */\n applied: boolean;\n /** Commits made (sha1). Empty when noCommit=true. */\n commits: string[];\n /** Files touched (relative to repoRoot). */\n filesTouched: string[];\n /** Conflict-halted file (when agentMode + conflict). */\n haltedAtFile?: string;\n haltReason?: string;\n}\n\nexport async function runExecute(\n opts: ExecuteOptions,\n): Promise<ExecuteResult> {\n const result: ExecuteResult = {\n applied: false,\n commits: [],\n filesTouched: [],\n };\n\n // Per-step write-then-commit loop.\n for (const step of opts.plan.steps) {\n const stepHalt = await applyStep(step, opts);\n if (stepHalt) {\n result.haltedAtFile = step.relPath;\n result.haltReason = stepHalt;\n return result;\n }\n result.applied = true;\n result.filesTouched.push(step.relPath);\n if (!opts.noCommit) {\n const sha = await commitStep(step, opts);\n if (sha) result.commits.push(sha);\n }\n }\n\n // P3-F Gap: record sha256 hashes for SKILL.md files when copy strategy was\n // used. doctor will later detect tampering/corruption via verifyIntegrity().\n // symlink mode is a no-op (recordIntegrity short-circuits) because tampering\n // there is caught by the doctor symlink-target check, not by hash.\n if (result.applied) {\n const trackedPaths = result.filesTouched.filter(isIntegrityTrackedPath);\n recordIntegrity(opts.repoRoot, opts.linkStrategy, trackedPaths);\n }\n\n return result;\n}\n\nasync function applyStep(\n step: PlanStep,\n opts: ExecuteOptions,\n): Promise<string | null> {\n const abs = join(opts.repoRoot, step.relPath);\n\n switch (step.disposition) {\n case \"keep\":\n return null;\n\n case \"replace-with-symlink\": {\n if (!opts.pluginVersion) {\n return `Plugin not installed; cannot create symlink for ${step.relPath}`;\n }\n const target = join(pluginCachePath(opts.pluginVersion, opts.home), step.relPath.replace(/^\\.claude\\//, \"\"));\n ensureParentDir(abs);\n removeIfExists(abs);\n if (opts.linkStrategy === \"symlink\") {\n symlinkSync(target, abs);\n } else {\n cpSync(target, abs, { recursive: true, force: true });\n }\n return null;\n }\n\n case \"replace-with-copy\": {\n const upstream = opts.preFetched.get(step.relPath);\n if (upstream === undefined) {\n return `upstream content missing for ${step.relPath}`;\n }\n ensureParentDir(abs);\n writeFileSync(abs, upstream, \"utf8\");\n return null;\n }\n\n case \"archive\": {\n // Move the project-modified file to .twin-build/archive/<rel>.\n const archiveDest = join(\n opts.repoRoot,\n \".twin-build\",\n \"archive\",\n step.relPath,\n );\n if (existsSync(abs)) {\n ensureParentDir(archiveDest);\n cpSync(abs, archiveDest, { recursive: true, dereference: true });\n }\n // Replace with upstream version when available.\n const upstream = opts.preFetched.get(step.relPath);\n if (upstream !== undefined) {\n ensureParentDir(abs);\n writeFileSync(abs, upstream, \"utf8\");\n }\n return null;\n }\n\n case \"merge-claude-md\": {\n const base = opts.preFetchedBase?.get(step.relPath) ?? null;\n const ours = opts.preFetchedOurs?.get(step.relPath) ?? readSafely(abs);\n const theirs = opts.preFetched.get(step.relPath);\n if (theirs === undefined) {\n return `upstream content missing for ${step.relPath}`;\n }\n const merge = await mergeThreeWay(base ?? \"\", ours, theirs, {\n labels: {\n base: `base@${opts.plan.fromVersion ?? \"unknown\"}`,\n ours: \"project\",\n theirs: `upstream@${opts.toVersion}`,\n },\n });\n if (merge.status === \"conflict\" && opts.agentMode) {\n return (\n `CLAUDE.md conflict (ratio ${(merge.conflictRatio * 100).toFixed(0)}%) ` +\n `— agent mode halt; emitting audience:human event for manual review`\n );\n }\n ensureParentDir(abs);\n writeFileSync(abs, merge.content, \"utf8\");\n return null;\n }\n\n default:\n return `unknown disposition ${(step as PlanStep).disposition}`;\n }\n}\n\nfunction ensureParentDir(abs: string): void {\n const dir = dirname(abs);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n}\n\nfunction removeIfExists(abs: string): void {\n try {\n const st = statSync(abs);\n if (st.isDirectory()) {\n rmSync(abs, { recursive: true, force: true });\n } else {\n unlinkSync(abs);\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") throw err;\n }\n}\n\nfunction readSafely(abs: string): string {\n try {\n return readFileSync(abs, \"utf8\");\n } catch {\n return \"\";\n }\n}\n\nasync function commitStep(\n step: PlanStep,\n opts: ExecuteOptions,\n): Promise<string | null> {\n const gitBin = opts.gitBin ?? \"git\";\n // git status check after each step — abort if working tree has unrelated\n // changes that would be swept up by a blanket `git add .`.\n await run(gitBin, [\"add\", \"--\", step.relPath], opts.repoRoot);\n const message = `chore(migrate): ${step.disposition} ${step.relPath} (${opts.plan.fromVersion ?? \"unknown\"} -> ${opts.toVersion})`;\n try {\n await run(gitBin, [\"commit\", \"-m\", message], opts.repoRoot);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (/nothing to commit/i.test(msg)) return null;\n throw err;\n }\n const sha = await capture(gitBin, [\"rev-parse\", \"HEAD\"], opts.repoRoot);\n return sha.trim();\n}\n\nfunction run(cmd: string, args: string[], cwd: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(cmd, args, { cwd, stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n let stderr = \"\";\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString(\"utf8\");\n });\n child.on(\"close\", (code) => {\n if (code === 0) return resolve();\n reject(new Error(`${cmd} ${args.join(\" \")} exited ${code}: ${stderr}`));\n });\n child.on(\"error\", reject);\n });\n}\n\nfunction capture(cmd: string, args: string[], cwd: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn(cmd, args, { cwd, stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout.on(\"data\", (chunk: Buffer) => {\n stdout += chunk.toString(\"utf8\");\n });\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString(\"utf8\");\n });\n child.on(\"close\", (code) => {\n if (code === 0) return resolve(stdout);\n reject(new Error(`${cmd} ${args.join(\" \")} exited ${code}: ${stderr}`));\n });\n child.on(\"error\", reject);\n });\n}\n","/**\n * `.twin-build/migrate.lock` — single-writer guard for `twin-build migrate`.\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §9.4 T2-18\n *\n * Behaviour:\n * - acquire(): atomic create with O_EXCL semantics. If a lock already exists,\n * check whether the holding PID is alive. Stale (dead PID) → take over.\n * Live PID → throw LockBusyError so the caller can halt with a useful\n * message.\n * - release(): idempotent unlink. Never throws on a missing lock file.\n * - inspect(): read-only; returns null when no lock present.\n *\n * The lockfile is JSON ({ pid, acquiredAt, hostname?, reason? }) so future\n * tooling can audit who is holding it.\n */\nimport {\n closeSync,\n existsSync,\n mkdirSync,\n openSync,\n readFileSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { hostname } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { lockFileSchema, type LockFilePayload } from \"./migrate-types.js\";\n\nexport const LOCK_PATH = \".twin-build/migrate.lock\";\n\nexport class LockBusyError extends Error {\n readonly code = \"MIGRATE_LOCK_BUSY\";\n constructor(\n readonly holder: LockFilePayload,\n readonly path: string,\n ) {\n super(\n `migrate is already running (pid=${holder.pid}, acquiredAt=${holder.acquiredAt}); ` +\n `delete ${path} only if no other migrate is in progress.`,\n );\n }\n}\n\nfunction isProcessAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n // ESRCH → not alive. EPERM → alive but inaccessible (still alive).\n return (err as NodeJS.ErrnoException).code === \"EPERM\";\n }\n}\n\nexport interface AcquireOptions {\n repoRoot: string;\n reason?: string;\n /** Override pid for testing (default: process.pid). */\n pid?: number;\n /** Override clock for testing. */\n now?: () => Date;\n}\n\nexport interface AcquireResult {\n path: string;\n payload: LockFilePayload;\n /** True when we removed a stale lock to acquire. */\n takeover: boolean;\n}\n\nexport function acquireLock(opts: AcquireOptions): AcquireResult {\n const lockPath = join(opts.repoRoot, LOCK_PATH);\n const pid = opts.pid ?? process.pid;\n const acquiredAt = (opts.now?.() ?? new Date()).toISOString();\n const payload: LockFilePayload = {\n pid,\n acquiredAt,\n hostname: hostname() || undefined,\n reason: opts.reason,\n };\n\n mkdirSync(dirname(lockPath), { recursive: true });\n\n let takeover = false;\n if (existsSync(lockPath)) {\n const existing = readLockFile(lockPath);\n if (existing && isProcessAlive(existing.pid) && existing.pid !== pid) {\n throw new LockBusyError(existing, lockPath);\n }\n // Stale (dead PID or unparsable) — remove and take over.\n try {\n unlinkSync(lockPath);\n } catch {\n // race: another acquirer may have just released; ignore.\n }\n takeover = true;\n }\n\n // Atomic create — fail if the file exists between our existsSync and now.\n let fd: number;\n try {\n fd = openSync(lockPath, \"wx\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"EEXIST\") {\n // Someone beat us; surface as busy with whoever is in the file.\n const existing = readLockFile(lockPath);\n if (existing) throw new LockBusyError(existing, lockPath);\n throw new LockBusyError(payload, lockPath);\n }\n throw err;\n }\n try {\n writeFileSync(fd, JSON.stringify(payload, null, 2) + \"\\n\", \"utf8\");\n } finally {\n closeSync(fd);\n }\n\n return { path: lockPath, payload, takeover };\n}\n\nexport function releaseLock(repoRoot: string): boolean {\n const lockPath = join(repoRoot, LOCK_PATH);\n try {\n unlinkSync(lockPath);\n return true;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw err;\n }\n}\n\nexport function inspectLock(repoRoot: string): LockFilePayload | null {\n const lockPath = join(repoRoot, LOCK_PATH);\n return readLockFile(lockPath);\n}\n\nfunction readLockFile(path: string): LockFilePayload | null {\n if (!existsSync(path)) return null;\n try {\n const text = readFileSync(path, \"utf8\");\n const parsed = JSON.parse(text);\n const result = lockFileSchema.safeParse(parsed);\n return result.success ? result.data : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Helper for guarded execution — acquire, run fn, release in finally.\n */\nexport async function withLock<T>(\n opts: AcquireOptions,\n fn: (acquired: AcquireResult) => Promise<T>,\n): Promise<T> {\n const acquired = acquireLock(opts);\n try {\n return await fn(acquired);\n } finally {\n releaseLock(opts.repoRoot);\n }\n}\n","/**\n * `compatibility.json.migrationPaths` resolver for F4 multi-step migration.\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §9.2 F4\n *\n * Pure function — no I/O. Caller passes the loaded matrix.\n *\n * Behaviour:\n * - Direct hop (`from === current && to === target`) → return [target]\n * - Multi-step (`via: [...]`) → return [...via, target]\n * - No path entry but versions equal → return [] (already at target)\n * - No path entry and versions differ → return [target] (caller decides\n * whether to allow direct jump; we surface a \"no recorded path\" warning)\n * - Detect cycles in the via chain and throw.\n */\nimport type { MigrationPath } from \"../../usecases/compatibility/schemas.js\";\n\nexport class CircularMigrationPathError extends Error {\n readonly code = \"MIGRATION_PATH_CIRCULAR\";\n constructor(readonly chain: string[]) {\n super(`circular migration path detected: ${chain.join(\" -> \")}`);\n }\n}\n\nexport class UnreachableMigrationTargetError extends Error {\n readonly code = \"MIGRATION_PATH_UNREACHABLE\";\n constructor(\n readonly from: string,\n readonly to: string,\n ) {\n super(`no migration path from ${from} to ${to} in compatibility.json`);\n }\n}\n\nexport interface ResolveOptions {\n /** When true, allow direct hop even if no rule recorded. */\n allowDirectHop?: boolean;\n}\n\nexport interface ResolveResult {\n /** Ordered list of versions to apply (excluding `from`). */\n chain: string[];\n /** Hop is multi-step (via list non-empty). */\n multiStep: boolean;\n /** No matrix entry — caller should warn (only when allowDirectHop=true). */\n unrecordedDirect: boolean;\n}\n\n/**\n * Resolve the version chain to apply when migrating from `from` to `to`.\n */\nexport function resolveMigrationChain(\n paths: MigrationPath[],\n from: string,\n to: string,\n opts: ResolveOptions = {},\n): ResolveResult {\n if (from === to) {\n return { chain: [], multiStep: false, unrecordedDirect: false };\n }\n\n const match = paths.find((p) => p.from === from && p.to === to);\n\n if (match) {\n const chain = [...match.via, to];\n detectCycle(chain, from);\n return {\n chain,\n multiStep: match.via.length > 0,\n unrecordedDirect: false,\n };\n }\n\n // Try transitive resolution via BFS — useful when matrix only records\n // adjacent hops (v0.5→v0.6, v0.6→v0.7, …) and the caller wants v0.5→v0.7.\n const transitive = resolveTransitive(paths, from, to);\n if (transitive) {\n detectCycle(transitive, from);\n return {\n chain: transitive,\n multiStep: transitive.length > 1,\n unrecordedDirect: false,\n };\n }\n\n if (opts.allowDirectHop) {\n return { chain: [to], multiStep: false, unrecordedDirect: true };\n }\n\n throw new UnreachableMigrationTargetError(from, to);\n}\n\nfunction detectCycle(chain: string[], from: string): void {\n const seen = new Set<string>([from]);\n for (const v of chain) {\n if (seen.has(v)) {\n throw new CircularMigrationPathError([from, ...chain]);\n }\n seen.add(v);\n }\n}\n\nfunction resolveTransitive(\n paths: MigrationPath[],\n from: string,\n to: string,\n): string[] | null {\n // Build adjacency: from → [{ next, via }]\n const adj = new Map<string, Array<{ next: string; via: string[] }>>();\n for (const p of paths) {\n const list = adj.get(p.from) ?? [];\n list.push({ next: p.to, via: p.via });\n adj.set(p.from, list);\n }\n if (!adj.has(from)) return null;\n\n // BFS, tracking the path to reconstruct.\n type Node = { version: string; trail: string[] };\n const queue: Node[] = [{ version: from, trail: [] }];\n const visited = new Set<string>([from]);\n while (queue.length > 0) {\n const node = queue.shift()!;\n const next = adj.get(node.version) ?? [];\n for (const edge of next) {\n if (visited.has(edge.next)) continue;\n const newTrail = [...node.trail, ...edge.via, edge.next];\n if (edge.next === to) return newTrail;\n visited.add(edge.next);\n queue.push({ version: edge.next, trail: newTrail });\n }\n }\n return null;\n}\n","/**\n * Phase 2: Plan — turn an audit + a target version into a list of dispositions\n * the executor will apply.\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §7 Phase 2 + §9.2 F9\n *\n * Halt conditions:\n * - CLAUDE.md conflict ratio > CONFLICT_RATIO_HALT_THRESHOLD (60%) → halt\n * unless `skipClaudeMd` is true. Halt reason is surfaced for the handler\n * to print `--skip-claude-md` retry guidance.\n */\nimport { mergeThreeWay } from \"./merge.js\";\nimport type {\n AuditResult,\n MigrationPlan,\n PlanStep,\n PlanDisposition,\n} from \"./migrate-types.js\";\n\nconst CONFLICT_RATIO_HALT_THRESHOLD = 0.6;\nconst CLAUDE_MD = \"CLAUDE.md\";\n\nexport interface PlanOptions {\n audit: AuditResult;\n fromVersion: string | null;\n toVersion: string;\n via?: string[];\n /** Whether to plan a CLAUDE.md merge step. Default: true unless audit shows\n * the file is missing or it's pure project-only. */\n skipClaudeMd?: boolean;\n /** Default link strategy for replacing upstream files. */\n linkStrategy?: \"symlink\" | \"copy\";\n /** Loader returning (relPath) → { base, ours, theirs }. When omitted we\n * cannot compute conflict ratios and only record dispositions. */\n loadCodemodInputs?: (\n relPath: string,\n ) => Promise<{ base: string | null; ours: string; theirs: string } | null>;\n}\n\nexport async function runPlan(opts: PlanOptions): Promise<MigrationPlan> {\n const link: PlanDisposition =\n opts.linkStrategy === \"copy\" ? \"replace-with-copy\" : \"replace-with-symlink\";\n\n const steps: PlanStep[] = [];\n let halted = false;\n let haltReason: string | undefined;\n\n for (const entry of opts.audit.entries) {\n const step = await planEntry(entry, link, opts);\n if (!step) continue;\n\n if (step.relPath === CLAUDE_MD && step.disposition === \"merge-claude-md\") {\n const ratio = step.conflictRatio ?? 0;\n if (\n ratio > CONFLICT_RATIO_HALT_THRESHOLD &&\n !opts.skipClaudeMd\n ) {\n halted = true;\n haltReason =\n `CLAUDE.md conflict ratio ${(ratio * 100).toFixed(0)}% exceeds ` +\n `${(CONFLICT_RATIO_HALT_THRESHOLD * 100).toFixed(0)}% threshold. ` +\n `Re-run with --skip-claude-md to retry without touching CLAUDE.md.`;\n }\n }\n steps.push(step);\n if (halted) break;\n }\n\n return {\n fromVersion: opts.fromVersion,\n toVersion: opts.toVersion,\n via: opts.via ?? [],\n steps,\n halted,\n haltReason,\n };\n}\n\nasync function planEntry(\n entry: AuditResult[\"entries\"][number],\n link: PlanDisposition,\n opts: PlanOptions,\n): Promise<PlanStep | null> {\n // CLAUDE.md is handled via 3-way merge (codemod).\n if (entry.relPath === CLAUDE_MD) {\n if (opts.skipClaudeMd) {\n return {\n relPath: entry.relPath,\n disposition: \"keep\",\n reason: \"user requested --skip-claude-md\",\n };\n }\n const ratio = await estimateConflictRatio(entry.relPath, opts);\n return {\n relPath: entry.relPath,\n disposition: \"merge-claude-md\",\n reason: `Phase 3 will run 3-way merge (zdiff3)`,\n conflictRatio: ratio,\n };\n }\n\n switch (entry.origin) {\n case \"upstream\":\n return {\n relPath: entry.relPath,\n disposition: link,\n reason: \"byte-identical to upstream — safe to replace with link\",\n };\n case \"upstream-modified\":\n return {\n relPath: entry.relPath,\n disposition: \"archive\",\n reason: \"diverged from upstream — archived for review\",\n };\n case \"project-only\":\n return {\n relPath: entry.relPath,\n disposition: \"keep\",\n reason: \"no upstream counterpart — left in place\",\n };\n case \"unknown\":\n return {\n relPath: entry.relPath,\n disposition: \"keep\",\n reason: \"could not determine origin (Plugin not installed?)\",\n };\n default:\n return null;\n }\n}\n\nasync function estimateConflictRatio(\n relPath: string,\n opts: PlanOptions,\n): Promise<number | undefined> {\n if (!opts.loadCodemodInputs) return undefined;\n const inputs = await opts.loadCodemodInputs(relPath);\n if (!inputs) return undefined;\n const merge = await mergeThreeWay(\n inputs.base ?? \"\",\n inputs.ours,\n inputs.theirs,\n );\n if (merge.status === \"clean\") return 0;\n return merge.conflictRatio;\n}\n\n/** Render a plan as a markdown table for /tmp/migration-plan.md / PR body. */\nexport function renderPlanMarkdown(plan: MigrationPlan): string {\n const lines = [\n \"# Migration plan\",\n \"\",\n `From: ${plan.fromVersion ?? \"(unknown)\"}`,\n `To: ${plan.toVersion}`,\n ];\n if (plan.via.length > 0) lines.push(`Via: ${plan.via.join(\" → \")}`);\n lines.push(\"\", \"| File | Disposition | Reason | Conflict % |\", \"| --- | --- | --- | --- |\");\n for (const s of plan.steps) {\n const ratio =\n s.conflictRatio === undefined ? \"-\" : `${(s.conflictRatio * 100).toFixed(0)}%`;\n lines.push(\n `| ${s.relPath} | ${s.disposition} | ${s.reason} | ${ratio} |`,\n );\n }\n if (plan.halted) {\n lines.push(\"\", `**Halted**: ${plan.haltReason ?? \"(unknown reason)\"}`);\n }\n return lines.join(\"\\n\");\n}\n","/**\n * Compatibility Matrix + .twin-build.json 4-axis pin schemas.\n *\n * 設計: docs/design/twin-build-distribution-redesign-phase2.md §4 (軸 2)\n * 親チケット: 96b3681a-e653-4f6d-bd7a-42c99d1a46f1 (P3-A 348c11cd)\n *\n * 配布構造再設計案 C (Hybrid) の 4 軸 version pin の整合性を検査するための schema 群:\n * - plugin (Claude Code Plugin)\n * - cli (@twin-build-orchestrate/cli npm)\n * - rulesSchema (MCP server 配信 rules)\n * - mcpToolSchema (MCP tool schema、server-wide deploy 単位)\n *\n * compatibility.json は server / Plugin に同梱される静的 JSON で、first-match-wins で評価される。\n */\n\nimport { z } from \"zod\";\n\n/** 互換性 status — compatible (続行) / warning (確認 prompt) / incompatible (halt) */\nexport const compatibilityStatusSchema = z.enum([\n \"compatible\",\n \"warning\",\n \"incompatible\",\n]);\nexport type CompatibilityStatus = z.infer<typeof compatibilityStatusSchema>;\n\n/** linkStrategy — symlink (POSIX) / copy (Windows native) */\nexport const linkStrategySchema = z.enum([\"symlink\", \"copy\"]);\nexport type LinkStrategy = z.infer<typeof linkStrategySchema>;\n\n/**\n * 推奨更新 — incompatible 時に提示する推奨 version 組合せ。\n * 未指定 axis は「現状維持で OK」を意味する。\n */\nexport const recommendedVersionsSchema = z.object({\n plugin: z.string().min(1).optional(),\n cli: z.string().min(1).optional(),\n rulesSchema: z.string().min(1).optional(),\n mcpToolSchema: z.string().min(1).optional(),\n});\nexport type RecommendedVersions = z.infer<typeof recommendedVersionsSchema>;\n\n/**\n * Compatibility rule — 1 件の互換性判定エントリ。\n * - plugin / cli は npm semver range (例: `^1.5.0`, `>=0.3.0 <0.4.0`, `*` wildcard)\n * - rulesSchema / mcpToolSchema は monotonic version string で literal 一致 (`*` wildcard 対応)\n * - mcpToolSchema は省略時 wildcard (任意の値で match)\n */\nexport const compatibilityRuleSchema = z.object({\n id: z.string().min(1).describe(\"rule 識別子 (debug 用、ユニーク推奨)\"),\n plugin: z.string().min(1).describe(\"npm semver range or '*'\"),\n cli: z.string().min(1).describe(\"npm semver range or '*'\"),\n rulesSchema: z.string().min(1).describe(\"rules schema version string or '*'\"),\n mcpToolSchema: z\n .string()\n .min(1)\n .optional()\n .describe(\"MCP tool schema version string or '*' (省略 = wildcard)\"),\n status: compatibilityStatusSchema,\n code: z.string().optional().describe(\"error/warning code (例: CLI_BEHIND_PLUGIN)\"),\n message: z.string().optional().describe(\"人間向け説明文\"),\n recommended: recommendedVersionsSchema.optional(),\n});\nexport type CompatibilityRule = z.infer<typeof compatibilityRuleSchema>;\n\n/** Migration path — F4 多段 migration 用、`from` から `to` への中間 version 列 */\nexport const migrationPathSchema = z.object({\n from: z.string().min(1),\n to: z.string().min(1),\n via: z.array(z.string().min(1)).default([]),\n});\nexport type MigrationPath = z.infer<typeof migrationPathSchema>;\n\n/** Fallback — 全 rule が match しなかった時の挙動 (推奨: warning) */\nexport const compatibilityFallbackSchema = z.object({\n status: compatibilityStatusSchema,\n code: z.string().optional(),\n message: z.string().optional(),\n});\nexport type CompatibilityFallback = z.infer<typeof compatibilityFallbackSchema>;\n\n/** Top-level compatibility.json の root schema */\nexport const compatibilityMatrixSchema = z.object({\n schemaVersion: z.string().default(\"1.0.0\"),\n generatedAt: z.string().optional(),\n rules: z.array(compatibilityRuleSchema),\n migrationPaths: z.array(migrationPathSchema).default([]),\n fallback: compatibilityFallbackSchema.default({\n status: \"warning\",\n code: \"UNKNOWN_COMBINATION\",\n message: \"未検証の組合せです。動作する可能性は高いですが、issue 報告を歓迎します。\",\n }),\n});\nexport type CompatibilityMatrix = z.infer<typeof compatibilityMatrixSchema>;\n\n/** integrity sha256 hash の各 axis 値 (横断警告 #1: 手書き編集検知用) */\nexport const integrityBlockSchema = z.object({\n pluginVersion: z.string().optional(),\n cliVersion: z.string().optional(),\n rulesSchemaVersion: z.string().optional(),\n});\nexport type IntegrityBlock = z.infer<typeof integrityBlockSchema>;\n\n/** history entry — bump 履歴 1 件 */\nexport const twinBuildHistoryEntrySchema = z.object({\n at: z.string().describe(\"ISO 8601 timestamp\"),\n pluginVersion: z.string().optional(),\n cliVersion: z.string().optional(),\n rulesSchemaVersion: z.string().optional(),\n mcpToolSchemaVersion: z.string().optional(),\n});\nexport type TwinBuildHistoryEntry = z.infer<typeof twinBuildHistoryEntrySchema>;\n\n/**\n * .twin-build.json の twinBuild block (4 軸 + integrity + history + linkStrategy)。\n * 既存 .twin-build.json は { projectName: \"...\" } 単純構造のため、互換性のため\n * twinBuild block は optional にする (既存 project は不在で OK、新規 project に追加)。\n */\nexport const twinBuildConfigBlockSchema = z.object({\n pluginVersion: z.string().min(1),\n cliVersion: z.string().min(1),\n rulesSchemaVersion: z.string().min(1),\n mcpToolSchemaVersion: z.string().min(1).optional(),\n linkStrategy: linkStrategySchema.default(\"symlink\"),\n integrity: integrityBlockSchema.optional(),\n history: z.array(twinBuildHistoryEntrySchema).default([]),\n});\nexport type TwinBuildConfigBlock = z.infer<typeof twinBuildConfigBlockSchema>;\n\n/**\n * .twin-build.json の root schema。\n * projectName は必須、twinBuild は optional (案 C 対応 project のみ持つ)。\n */\nexport const twinBuildConfigSchema = z.object({\n projectName: z.string().min(1),\n twinBuild: twinBuildConfigBlockSchema.optional(),\n});\nexport type TwinBuildConfig = z.infer<typeof twinBuildConfigSchema>;\n\n/** getCompatibilityMatrix tool の input */\nexport const compatibilityQuerySchema = z.object({\n plugin: z.string().min(1).describe(\"Plugin version (例: '1.5.2')\"),\n cli: z.string().min(1).describe(\"CLI version (例: '0.3.0')\"),\n rulesSchema: z.string().min(1).describe(\"Rules schema version (例: 'v3.2')\"),\n mcpToolSchema: z\n .string()\n .min(1)\n .optional()\n .describe(\"MCP tool schema version (省略可)\"),\n});\nexport type CompatibilityQuery = z.infer<typeof compatibilityQuerySchema>;\n\n/** getCompatibilityMatrix tool の output */\nexport const compatibilityResultSchema = z.object({\n status: compatibilityStatusSchema,\n ruleId: z.string().optional(),\n code: z.string().optional(),\n message: z.string().optional(),\n recommended: recommendedVersionsSchema.optional(),\n});\nexport type CompatibilityResult = z.infer<typeof compatibilityResultSchema>;\n"],"mappings":"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","names":["readFileSync","writeFileSync","unlinkSync","existsSync","mkdirSync","openSync","closeSync","spawn","resolve","join","join","mkdirSync","readdirSync","statSync","unlinkSync","existsSync","join","existsSync","readFileSync","join","homedir","join","join","homedir","resolve","join","existsSync","readFileSync","mkdirSync","existsSync","readdirSync","statSync","unlinkSync","join","join","resolve","execFile","promisify","defaultExec","promisify","execFile","existsSync","readdirSync","statSync","existsSync","readdirSync","statSync","resolve","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","existsSync","readFileSync","readdirSync","statSync","homedir","join","join","existsSync","readFileSync","writeFileSync","mkdirSync","dirname","existsSync","readFileSync","writeFileSync","homedir","join","createHash","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","TWIN_BUILD_JSON","SETTINGS_JSON","homedir","join","existsSync","readFileSync","writeFileSync","createHash","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","writeFileSync","join","resolve","integrityHash","createHash","TWIN_BUILD_JSON","join","existsSync","readFileSync","writeFileSync","dirname","mkdirSync","spawn","mkdtempSync","rmSync","writeFileSync","readFileSync","tmpdir","join","resolve","spawn","cpSync","existsSync","mkdirSync","mkdtempSync","readFileSync","readdirSync","rmSync","statSync","tmpdir","join","relative","join","existsSync","statSync","readdirSync","relative","resolve","spawn","spawn","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","relative","createHash","existsSync","readFileSync","readdirSync","statSync","join","relative","CLAUDE_MD","join","existsSync","statSync","readFileSync","createHash","readdirSync","relative","cpSync","existsSync","mkdirSync","readFileSync","readdirSync","rmSync","statSync","writeFileSync","dirname","join","z","join","mkdirSync","existsSync","dirname","cpSync","writeFileSync","readdirSync","readFileSync","statSync","rmSync","spawn","cpSync","existsSync","mkdirSync","readFileSync","rmSync","statSync","symlinkSync","unlinkSync","writeFileSync","dirname","join","join","symlinkSync","cpSync","writeFileSync","existsSync","dirname","mkdirSync","statSync","rmSync","unlinkSync","readFileSync","run","resolve","spawn","closeSync","existsSync","mkdirSync","openSync","readFileSync","unlinkSync","writeFileSync","dirname","join","join","mkdirSync","dirname","existsSync","unlinkSync","openSync","writeFileSync","closeSync","existsSync","readFileSync","CONFLICT_RATIO_HALT_THRESHOLD","CLAUDE_MD","z","TWIN_BUILD_JSON","join","relative","run","existsSync","readFileSync","mkdirSync","dirname","writeFileSync","capture","resolve","spawn","resolve","existsSync","readFileSync","isProcessAlive","unlinkSync","writeFileSync","mkdirSync","openSync","spawn","closeSync"]}
|