relay-kit 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../src/commands/ask.ts","../src/core/clipboard.ts","../src/core/command-runner.ts","../src/core/git.ts","../src/core/excludes.ts","../src/core/constants.ts","../src/core/config.ts","../src/core/fs.ts","../src/core/relayignore.ts","../src/core/redaction.ts","../src/core/context-safety.ts","../src/core/openspec.ts","../src/core/runs.ts","../src/core/templates.ts","../src/core/state.ts","../src/commands/doctor.ts","../src/core/project.ts","../src/commands/init.ts","../src/core/skills.ts","../src/commands/resume.ts","../src/commands/review.ts","../src/commands/start.ts","../src/core/skills-sync.ts","../src/commands/sync.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { registerAskCommand } from \"./commands/ask.js\";\nimport { registerDoctorCommand } from \"./commands/doctor.js\";\nimport { registerInitCommand } from \"./commands/init.js\";\nimport { registerResumeCommand } from \"./commands/resume.js\";\nimport { registerReviewCommand } from \"./commands/review.js\";\nimport { registerStartCommand } from \"./commands/start.js\";\nimport { registerSyncCommand } from \"./commands/sync.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"relay\")\n .description(\"Skills-first, CLI-assisted AI programming relay workflow toolkit.\")\n .version(\"0.2.0\");\n\nregisterInitCommand(program);\nregisterStartCommand(program);\nregisterAskCommand(program);\nregisterResumeCommand(program);\nregisterReviewCommand(program);\nregisterDoctorCommand(program);\nregisterSyncCommand(program);\n\nprogram.parseAsync(process.argv).catch((error: unknown) => {\n console.error(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n});\n","import type { Command } from \"commander\";\nimport path from \"node:path\";\nimport { copyToClipboard } from \"../core/clipboard.js\";\nimport { runShellCommand } from \"../core/command-runner.js\";\nimport { loadConfig } from \"../core/config.js\";\nimport { createContextSafety } from \"../core/context-safety.js\";\nimport { safeWriteFile, readTextIfExists } from \"../core/fs.js\";\nimport { collectGitContext } from \"../core/git.js\";\nimport { formatOpenSpecContext, readOpenSpecContext } from \"../core/openspec.js\";\nimport { getRunContext } from \"../core/runs.js\";\nimport { loadState } from \"../core/state.js\";\nimport { loadTemplate, renderTemplate } from \"../core/templates.js\";\n\ninterface AskOptions {\n run?: \"build\" | \"test\";\n copy?: boolean;\n force?: boolean;\n}\n\nexport function registerAskCommand(program: Command): void {\n program\n .command(\"ask\")\n .description(\"Create a relay escalation request when the executor is stuck.\")\n .option(\"--run <target>\", \"Explicitly run build or test before generating ASK_ADVISOR.md.\")\n .option(\"--copy\", \"Copy generated content to clipboard.\")\n .option(\"--force\", \"Overwrite ASK_ADVISOR.md.\")\n .action(async (options: AskOptions) => {\n const result = await runAsk(process.cwd(), options);\n console.log(result.summary);\n });\n}\n\nexport async function runAsk(root: string, options: AskOptions = {}): Promise<{ file: string; summary: string }> {\n if (options.run && options.run !== \"build\" && options.run !== \"test\") {\n throw new Error(\"--run must be build or test.\");\n }\n\n const config = await loadConfig(root);\n const state = await loadState(root);\n const run = requireCurrentRun(root, config, state.currentRun, state.currentLane);\n const contextSafety = await createContextSafety(root, config);\n const git = await collectGitContext(root, {\n maxDiffLines: config.maxDiffLines,\n gitExcludePathspecs: contextSafety.ignore.gitExcludePathspecs,\n shouldIgnorePath: contextSafety.shouldIgnorePath,\n redactText: contextSafety.redactText,\n });\n const currentTask = contextSafety.redactText(await readTextIfExists(path.join(run.laneDir, \"EXECUTOR_TASK.md\")));\n const commandResult = await maybeRunCommand(root, config, options.run);\n const openSpecText =\n state.mode === \"openspec\" && state.currentChange\n ? contextSafety.redactText(formatOpenSpecContext(await readOpenSpecContext(root, state.currentChange)))\n : \"\";\n\n const errorLog = contextSafety.redactText(commandResult\n ? [`Command: ${commandResult.command}`, `Exit Code: ${commandResult.exitCode}`, commandResult.output].join(\"\\n\")\n : \"No build/test command was run. Pass --run build or --run test to include command output.\");\n\n const content = renderTemplate(await loadTemplate(\"ASK_ADVISOR.template.md\"), {\n projectName: config.projectName,\n runId: state.currentRun,\n lane: state.currentLane,\n branch: git.branch,\n ignoreRulesStatus: contextSafety.ignoreRulesStatus,\n redactionRulesStatus: contextSafety.redactionRulesStatus,\n currentTask: [currentTask || \"(missing EXECUTOR_TASK.md)\", openSpecText].filter(Boolean).join(\"\\n\\n\"),\n errorLog,\n gitStatus: git.status || \"(clean)\",\n gitDiffStat: git.diffStat || \"(no diff)\",\n });\n\n const relative = path.relative(root, path.join(run.laneDir, \"ASK_ADVISOR.md\"));\n const file = await safeWriteFile(root, relative, content, { force: options.force });\n const copied = options.copy ? await copyToClipboard(content) : undefined;\n\n return {\n file,\n summary: [`Created ${path.relative(root, file)}`, copied === false ? \"Clipboard copy failed; file was still generated.\" : \"\"]\n .filter(Boolean)\n .join(\"\\n\"),\n };\n}\n\nfunction requireCurrentRun(root: string, config: Awaited<ReturnType<typeof loadConfig>>, runId: string, lane: string) {\n if (!runId) {\n throw new Error(\"No current run. Run relay start first.\");\n }\n\n return getRunContext(root, config, runId, lane);\n}\n\nasync function maybeRunCommand(\n root: string,\n config: Awaited<ReturnType<typeof loadConfig>>,\n target?: \"build\" | \"test\",\n) {\n if (!target) {\n return undefined;\n }\n\n const command = target === \"build\" ? config.buildCommand : config.testCommand;\n\n if (!command) {\n throw new Error(`No ${target} command configured or detected.`);\n }\n\n const contextSafety = await createContextSafety(root, config);\n return runShellCommand(root, command, {\n maxLogLines: config.maxLogLines,\n redactText: contextSafety.redactText,\n });\n}\n","import { spawn } from \"node:child_process\";\n\nexport async function copyToClipboard(content: string): Promise<boolean> {\n const command = process.platform === \"win32\" ? \"clip\" : process.platform === \"darwin\" ? \"pbcopy\" : \"xclip\";\n const args = process.platform === \"linux\" ? [\"-selection\", \"clipboard\"] : [];\n\n return new Promise((resolve) => {\n const child = spawn(command, args, { stdio: [\"pipe\", \"ignore\", \"ignore\"], windowsHide: true });\n child.on(\"error\", () => resolve(false));\n child.on(\"close\", (code) => resolve(code === 0));\n child.stdin.end(content);\n });\n}\n","import { exec } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { truncateLines } from \"./git.js\";\n\nconst execAsync = promisify(exec);\n\nexport interface CommandResult {\n command: string;\n exitCode: number;\n output: string;\n}\n\nexport interface RunShellCommandOptions {\n maxLogLines: number;\n redactText?: (value: string) => string;\n}\n\nexport async function runShellCommand(\n root: string,\n command: string,\n options: RunShellCommandOptions = { maxLogLines: 160 },\n): Promise<CommandResult> {\n try {\n const { stdout, stderr } = await execAsync(command, {\n cwd: root,\n maxBuffer: 1024 * 1024 * 2,\n windowsHide: true,\n });\n\n return { command, exitCode: 0, output: sanitizeCommandOutput(`${stdout}${stderr}`.trim(), options) };\n } catch (error) {\n const failed = error as { code?: number; stdout?: string; stderr?: string };\n return {\n command,\n exitCode: typeof failed.code === \"number\" ? failed.code : 1,\n output: sanitizeCommandOutput(`${failed.stdout ?? \"\"}${failed.stderr ?? \"\"}`.trim(), options),\n };\n }\n}\n\nfunction sanitizeCommandOutput(output: string, options: RunShellCommandOptions): string {\n const redacted = options.redactText ? options.redactText(output) : output;\n return truncateLines(redacted, options.maxLogLines);\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { filterExcludedLines, isExcludedPath } from \"./excludes.js\";\n\nconst execFileAsync = promisify(execFile);\n\nexport interface GitContextOptions {\n maxDiffLines: number;\n gitExcludePathspecs?: string[];\n shouldIgnorePath?: (candidate: string) => boolean;\n redactText?: (value: string) => string;\n}\n\nasync function git(root: string, args: string[]): Promise<string> {\n try {\n const { stdout, stderr } = await execFileAsync(\"git\", args, {\n cwd: root,\n maxBuffer: 1024 * 1024 * 5,\n windowsHide: true,\n });\n\n return `${stdout}${stderr}`.trim();\n } catch (error) {\n if (error && typeof error === \"object\" && \"stdout\" in error) {\n const failed = error as { stdout?: string; stderr?: string };\n return `${failed.stdout ?? \"\"}${failed.stderr ?? \"\"}`.trim();\n }\n\n return \"\";\n }\n}\n\nexport interface GitContext {\n branch: string;\n status: string;\n diffStat: string;\n diff: string;\n}\n\nexport async function collectGitContext(root: string, options: GitContextOptions | number): Promise<GitContext> {\n const contextOptions = typeof options === \"number\" ? { maxDiffLines: options } : options;\n const insideWorkTree = await git(root, [\"rev-parse\", \"--is-inside-work-tree\"]);\n\n if (insideWorkTree.trim() !== \"true\") {\n return {\n branch: \"(not a git repository)\",\n status: \"\",\n diffStat: \"\",\n diff: \"\",\n };\n }\n\n const pathspecs = contextOptions.gitExcludePathspecs ?? [];\n const branch = sanitizeGitText(await git(root, [\"branch\", \"--show-current\"]), contextOptions) || \"(unknown)\";\n const status = sanitizeGitText(await git(root, [\"status\", \"--short\", \"--\", \".\", ...pathspecs]), contextOptions);\n const diffStat = sanitizeGitText(await git(root, [\"diff\", \"--stat\", \"--\", \".\", ...pathspecs]), contextOptions);\n const diff = sanitizeGitDiff(await git(root, [\"diff\", \"--\", \".\", ...pathspecs]), contextOptions);\n const truncatedDiff = truncateLines(diff, contextOptions.maxDiffLines);\n\n return {\n branch,\n status,\n diffStat,\n diff: truncatedDiff,\n };\n}\n\nexport function truncateLines(text: string, maxLines: number): string {\n const lines = text.split(/\\r?\\n/);\n\n if (lines.length <= maxLines) {\n return text;\n }\n\n return `${lines.slice(0, maxLines).join(\"\\n\")}\\n... truncated ${lines.length - maxLines} lines ...`;\n}\n\nfunction sanitizeGitText(text: string, options: GitContextOptions): string {\n const filtered = filterIgnoredLines(filterExcludedLines(text), options.shouldIgnorePath);\n return applyRedaction(filtered, options).trim();\n}\n\nfunction sanitizeGitDiff(text: string, options: GitContextOptions): string {\n const filtered = filterIgnoredLines(filterIgnoredDiffBlocks(text, options.shouldIgnorePath), options.shouldIgnorePath);\n return applyRedaction(filtered, options).trim();\n}\n\nfunction applyRedaction(text: string, options: GitContextOptions): string {\n return options.redactText ? options.redactText(text) : text;\n}\n\nfunction filterIgnoredLines(text: string, shouldIgnorePath?: (candidate: string) => boolean): string {\n return text\n .split(/\\r?\\n/)\n .filter((line) => !lineReferencesIgnoredPath(line, shouldIgnorePath ?? (() => false)))\n .join(\"\\n\")\n .trim();\n}\n\nfunction filterIgnoredDiffBlocks(text: string, shouldIgnorePath?: (candidate: string) => boolean): string {\n const lines = text.split(/\\r?\\n/);\n const kept: string[] = [];\n let skipping = false;\n const ignore = shouldIgnorePath ?? (() => false);\n\n for (const line of lines) {\n if (line.startsWith(\"diff --git \")) {\n skipping = lineReferencesIgnoredPath(line, ignore);\n }\n\n if (!skipping) {\n kept.push(line);\n }\n }\n\n return kept.join(\"\\n\").trim();\n}\n\nfunction lineReferencesIgnoredPath(line: string, shouldIgnorePath: (candidate: string) => boolean): boolean {\n return extractCandidatePaths(line).some((candidate) => shouldIgnorePath(candidate) || isExcludedPath(candidate));\n}\n\nfunction extractCandidatePaths(line: string): string[] {\n const candidates = new Set<string>();\n const statusPath = line.match(/^[ MADRCU?!]{1,2}\\s+(.+)$/)?.[1];\n\n if (statusPath) {\n for (const part of statusPath.split(/\\s+->\\s+/)) {\n candidates.add(stripGitPathDecorations(part));\n }\n }\n\n const diffPaths = line.matchAll(/\\b[ab]\\/([^\\s]+)/g);\n for (const match of diffPaths) {\n candidates.add(stripGitPathDecorations(match[1]));\n }\n\n const statPath = line.includes(\"|\") ? line.split(\"|\")[0]?.trim() : \"\";\n if (statPath) {\n candidates.add(stripGitPathDecorations(statPath));\n }\n\n return [...candidates].filter(Boolean);\n}\n\nfunction stripGitPathDecorations(value: string): string {\n return value.replace(/^\"|\"$/g, \"\").replace(/\\\\/g, \"/\").trim();\n}\n","import path from \"node:path\";\nimport { EXCLUDED_NAMES } from \"./constants.js\";\n\nfunction normalizePath(value: string): string {\n return value.replace(/\\\\/g, \"/\");\n}\n\nexport function isExcludedPath(candidate: string): boolean {\n const normalized = normalizePath(candidate);\n const parts = normalized.split(\"/\").filter(Boolean);\n const basename = parts.at(-1) ?? normalized;\n\n if (basename === \".env\" || basename.startsWith(\".env.\")) {\n return true;\n }\n\n if (/\\.(pem|key|crt|p12|log)$/i.test(basename)) {\n return true;\n }\n\n return parts.some((part) => EXCLUDED_NAMES.has(part));\n}\n\nexport function filterExcludedLines(text: string): string {\n return text\n .split(/\\r?\\n/)\n .filter((line) => {\n // Git output and diff headers can expose sensitive paths even when file content is excluded.\n return !isExcludedPath(line);\n })\n .join(\"\\n\")\n .trim();\n}\n\nexport function assertInsideRoot(root: string, target: string): string {\n const resolvedRoot = path.resolve(root);\n const resolvedTarget = path.resolve(root, target);\n const relative = path.relative(resolvedRoot, resolvedTarget);\n\n if (relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative))) {\n return resolvedTarget;\n }\n\n throw new Error(`Refusing to write outside project root: ${target}`);\n}\n","export const RELAY_DIR = \".relay\";\nexport const RELAYIGNORE_FILE = \".relayignore\";\nexport const CONFIG_FILE = `${RELAY_DIR}/config.json`;\nexport const STATE_FILE = `${RELAY_DIR}/state.json`;\nexport const DEFAULT_HANDOFF_DIR = \"docs/agent-handoffs\";\nexport const DEFAULT_LANE = \"main\";\nexport const DEFAULT_MAX_DIFF_LINES = 500;\nexport const DEFAULT_MAX_LOG_LINES = 160;\nexport const AGENTS_START_MARKER = \"<!-- relay-kit:start -->\";\nexport const AGENTS_END_MARKER = \"<!-- relay-kit:end -->\";\n\nexport const DEFAULT_SKILLS = [\n \"relay-planner\",\n \"relay-delegator\",\n \"relay-escalation\",\n \"relay-reviewer\",\n] as const;\n\nexport const EXCLUDED_NAMES = new Set([\n \".env\",\n \".git\",\n \"node_modules\",\n \"dist\",\n \"build\",\n \"coverage\",\n]);\n\nexport const EXCLUDED_GLOBS = [\n \".env\",\n \".env.*\",\n \"node_modules/\",\n \"dist/\",\n \"build/\",\n \"coverage/\",\n \".git/\",\n \"*.pem\",\n \"*.key\",\n \"*.crt\",\n \"*.p12\",\n \"*.log\",\n];\n\nexport const DEFAULT_RELAYIGNORE_CONTENT = `# relay-kit context ignore rules\n.env\n.env.*\nnode_modules/\ndist/\nbuild/\ncoverage/\n.git/\n*.pem\n*.key\n*.crt\n*.p12\n*.log\n`;\n","import path from \"node:path\";\nimport {\n CONFIG_FILE,\n DEFAULT_HANDOFF_DIR,\n DEFAULT_LANE,\n DEFAULT_MAX_DIFF_LINES,\n DEFAULT_MAX_LOG_LINES,\n EXCLUDED_GLOBS,\n} from \"./constants.js\";\nimport { readJsonIfExists, writeJsonFile } from \"./fs.js\";\nimport type { RelayConfig, RelayMode, ProjectInfo } from \"./types.js\";\n\nexport function createDefaultConfig(project: ProjectInfo, mode: RelayMode): RelayConfig {\n return {\n projectName: project.name,\n language: \"zh\",\n mode,\n handoffDir: DEFAULT_HANDOFF_DIR,\n openSpecDir: \"openspec\",\n sourceDirs: [\"src\", \"apps\", \"packages\"],\n packageManager: project.packageManager === \"unknown\" ? \"auto\" : project.packageManager,\n devCommand: project.packageScripts.dev ? packageScript(project.packageManager, \"dev\") : \"\",\n buildCommand: project.packageScripts.build ? packageScript(project.packageManager, \"build\") : \"\",\n testCommand: project.packageScripts.test ? packageScript(project.packageManager, \"test\") : \"\",\n defaultExecutor: \"opencode\",\n defaultAdvisor: \"\",\n maxDiffLines: DEFAULT_MAX_DIFF_LINES,\n maxLogLines: DEFAULT_MAX_LOG_LINES,\n includeGitDiff: true,\n includeOpenSpec: mode === \"openspec\",\n includePackageScripts: true,\n runLayout: \"runs-lanes\",\n defaultLane: DEFAULT_LANE,\n excludePatterns: EXCLUDED_GLOBS,\n skills: {\n install: {\n manager: true,\n claudeProject: true,\n codexProject: true,\n claudeUser: false,\n codexUser: false,\n },\n enabled: [\"relay-planner\", \"relay-delegator\", \"relay-escalation\", \"relay-reviewer\"],\n optional: [\"relay-lane-planner\", \"relay-docs\"],\n },\n };\n}\n\nexport async function loadConfig(root: string): Promise<RelayConfig> {\n const config = await readJsonIfExists<RelayConfig>(path.join(root, CONFIG_FILE));\n\n if (!config) {\n throw new Error(\"Missing .relay/config.json. Run relay init first.\");\n }\n\n return normalizeConfig(config);\n}\n\nexport async function writeConfig(root: string, config: RelayConfig): Promise<void> {\n await writeJsonFile(path.join(root, CONFIG_FILE), config);\n}\n\nfunction packageScript(packageManager: ProjectInfo[\"packageManager\"], script: string): string {\n const runner = packageManager === \"unknown\" ? \"npm\" : packageManager;\n return `${runner} run ${script}`;\n}\n\nfunction normalizeConfig(config: RelayConfig): RelayConfig {\n return {\n ...config,\n maxDiffLines: config.maxDiffLines ?? DEFAULT_MAX_DIFF_LINES,\n maxLogLines: config.maxLogLines ?? DEFAULT_MAX_LOG_LINES,\n excludePatterns: config.excludePatterns ?? EXCLUDED_GLOBS,\n };\n}\n","import { constants as fsConstants } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { assertInsideRoot } from \"./excludes.js\";\n\nexport async function pathExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath, fsConstants.F_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function ensureDir(dirPath: string): Promise<void> {\n await fs.mkdir(dirPath, { recursive: true });\n}\n\nexport async function readTextIfExists(filePath: string): Promise<string> {\n if (!(await pathExists(filePath))) {\n return \"\";\n }\n return fs.readFile(filePath, \"utf8\");\n}\n\nexport async function readJsonIfExists<T>(filePath: string): Promise<T | undefined> {\n if (!(await pathExists(filePath))) {\n return undefined;\n }\n return JSON.parse(stripBom(await fs.readFile(filePath, \"utf8\"))) as T;\n}\n\nexport async function writeJsonFile(filePath: string, value: unknown): Promise<void> {\n await ensureDir(path.dirname(filePath));\n await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}\\n`, \"utf8\");\n}\n\nexport async function safeWriteFile(\n root: string,\n relativePath: string,\n content: string,\n options: { force?: boolean } = {},\n): Promise<string> {\n const target = assertInsideRoot(root, relativePath);\n await ensureDir(path.dirname(target));\n\n if (!options.force && (await pathExists(target))) {\n throw new Error(`Refusing to overwrite existing file without --force: ${relativePath}`);\n }\n\n await fs.writeFile(target, content, \"utf8\");\n return target;\n}\n\nexport async function copyDirectory(source: string, target: string, options: { force?: boolean } = {}): Promise<void> {\n if (!(await pathExists(source))) {\n throw new Error(`Missing source directory: ${source}`);\n }\n\n await ensureDir(target);\n const entries = await fs.readdir(source, { withFileTypes: true });\n\n for (const entry of entries) {\n const sourcePath = path.join(source, entry.name);\n const targetPath = path.join(target, entry.name);\n\n if (entry.isDirectory()) {\n await copyDirectory(sourcePath, targetPath, options);\n continue;\n }\n\n if (!entry.isFile()) {\n continue;\n }\n\n if (!options.force && (await pathExists(targetPath))) {\n continue;\n }\n\n await fs.copyFile(sourcePath, targetPath);\n }\n}\n\nexport function stripBom(value: string): string {\n return value.charCodeAt(0) === 0xfeff ? value.slice(1) : value;\n}\n","import path from \"node:path\";\nimport { RELAYIGNORE_FILE, EXCLUDED_GLOBS } from \"./constants.js\";\nimport { pathExists, readTextIfExists, stripBom } from \"./fs.js\";\n\nexport interface RelayIgnoreRule {\n pattern: string;\n raw: string;\n directory: boolean;\n rootOnly: boolean;\n hasGlob: boolean;\n}\n\nexport interface RelayIgnoreMatcher {\n hasRelayIgnore: boolean;\n patterns: string[];\n gitExcludePathspecs: string[];\n shouldIgnorePath(candidate: string): boolean;\n}\n\nexport async function loadRelayIgnoreMatcher(root: string, extraPatterns: string[] = []): Promise<RelayIgnoreMatcher> {\n const relayIgnorePath = path.join(root, RELAYIGNORE_FILE);\n const hasRelayIgnore = await pathExists(relayIgnorePath);\n const relayIgnorePatterns = hasRelayIgnore ? parseRelayIgnore(await readTextIfExists(relayIgnorePath)) : [];\n const patterns = uniquePatterns([...EXCLUDED_GLOBS, ...extraPatterns, ...relayIgnorePatterns]);\n const rules = patterns.map(parseRule).filter((rule): rule is RelayIgnoreRule => Boolean(rule));\n\n return {\n hasRelayIgnore,\n patterns,\n gitExcludePathspecs: buildGitExcludePathspecs(rules),\n shouldIgnorePath(candidate: string): boolean {\n const normalized = normalizePath(candidate);\n return rules.some((rule) => matchesRule(rule, normalized));\n },\n };\n}\n\nexport function parseRelayIgnore(content: string): string[] {\n return stripBom(content)\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter((line) => line && !line.startsWith(\"#\"))\n .filter((line) => !line.startsWith(\"!\"));\n}\n\nexport function normalizePath(value: string): string {\n return value.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\").replace(/^\\/+/, \"\");\n}\n\nfunction parseRule(rawPattern: string): RelayIgnoreRule | undefined {\n const raw = rawPattern.trim();\n\n if (!raw || raw.startsWith(\"#\") || raw.startsWith(\"!\")) {\n return undefined;\n }\n\n const rootOnly = raw.startsWith(\"/\");\n const directory = raw.endsWith(\"/\");\n const pattern = normalizePath(raw).replace(/\\/$/, \"\");\n\n if (!pattern) {\n return undefined;\n }\n\n return {\n pattern,\n raw,\n directory,\n rootOnly,\n hasGlob: pattern.includes(\"*\"),\n };\n}\n\nfunction matchesRule(rule: RelayIgnoreRule, candidate: string): boolean {\n const normalized = normalizePath(candidate);\n const parts = normalized.split(\"/\").filter(Boolean);\n\n if (rule.directory) {\n if (rule.hasGlob || rule.pattern.includes(\"/\")) {\n return pathMatchesPattern(normalized, rule.pattern) || normalized.startsWith(`${rule.pattern}/`);\n }\n\n return parts.includes(rule.pattern);\n }\n\n if (rule.hasGlob) {\n const target = rule.pattern.includes(\"/\") || rule.rootOnly ? normalized : parts.at(-1) ?? normalized;\n return pathMatchesPattern(target, rule.pattern);\n }\n\n if (rule.pattern.includes(\"/\") || rule.rootOnly) {\n return normalized === rule.pattern;\n }\n\n return parts.includes(rule.pattern);\n}\n\nfunction pathMatchesPattern(candidate: string, pattern: string): boolean {\n return globToRegExp(pattern).test(candidate);\n}\n\nfunction globToRegExp(pattern: string): RegExp {\n const source = pattern\n .split(\"*\")\n .map((part) => part.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\"))\n .join(\".*\");\n return new RegExp(`^${source}$`);\n}\n\nfunction buildGitExcludePathspecs(rules: RelayIgnoreRule[]): string[] {\n const pathspecs: string[] = [];\n\n for (const rule of rules) {\n const pattern = gitGlobForRule(rule);\n pathspecs.push(`:(exclude,glob)${pattern}`);\n\n if (!rule.rootOnly && !pattern.startsWith(\"**/\")) {\n pathspecs.push(`:(exclude,glob)**/${pattern}`);\n }\n }\n\n return [...new Set(pathspecs)];\n}\n\nfunction gitGlobForRule(rule: RelayIgnoreRule): string {\n if (rule.directory) {\n return `${rule.pattern}/**`;\n }\n\n return rule.pattern;\n}\n\nfunction uniquePatterns(patterns: string[]): string[] {\n return [...new Set(patterns.map((pattern) => pattern.trim()).filter(Boolean))];\n}\n","const PRIVATE_KEY_BLOCK = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\\s\\S]*?-----END [A-Z ]*PRIVATE KEY-----/g;\nconst BEARER_TOKEN = /\\b(Bearer\\s+)([A-Za-z0-9._~+/=-]{6,})/gi;\nconst SENSITIVE_KEY_VALUE =\n /([\"']?[\\w.-]*(?:api[_-]?key|token|secret|password)[\\w.-]*[\"']?\\s*[:=]\\s*)([\"']?)([^\\s\"',;]+)/gi;\n\nexport function redactSensitiveText(value: string): string {\n if (!value) {\n return value;\n }\n\n return value\n .replace(PRIVATE_KEY_BLOCK, \"[REDACTED_PRIVATE_KEY]\")\n .replace(BEARER_TOKEN, \"$1[REDACTED]\")\n .replace(SENSITIVE_KEY_VALUE, (_match, prefix: string, quote: string) => `${prefix}${quote}[REDACTED]`);\n}\n","import type { RelayConfig } from \"./types.js\";\nimport { loadRelayIgnoreMatcher, type RelayIgnoreMatcher } from \"./relayignore.js\";\nimport { redactSensitiveText } from \"./redaction.js\";\n\nexport interface ContextSafety {\n ignore: RelayIgnoreMatcher;\n ignoreRulesStatus: string;\n redactionRulesStatus: string;\n shouldIgnorePath(candidate: string): boolean;\n redactText(value: string): string;\n}\n\nexport async function createContextSafety(root: string, config: RelayConfig): Promise<ContextSafety> {\n const ignore = await loadRelayIgnoreMatcher(root, config.excludePatterns);\n\n return {\n ignore,\n ignoreRulesStatus: ignore.hasRelayIgnore\n ? \"applied: default rules + .relayignore\"\n : \"applied: default rules only\",\n redactionRulesStatus: \"applied: basic sensitive value redaction\",\n shouldIgnorePath(candidate: string): boolean {\n return ignore.shouldIgnorePath(candidate);\n },\n redactText(value: string): string {\n return redactSensitiveText(value);\n },\n };\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { filterExcludedLines } from \"./excludes.js\";\nimport { pathExists, readTextIfExists } from \"./fs.js\";\n\nexport interface OpenSpecContext {\n change: string;\n proposal: string;\n design: string;\n tasks: string;\n}\n\nexport async function listOpenSpecChanges(root: string): Promise<string[]> {\n const changesDir = path.join(root, \"openspec\", \"changes\");\n\n if (!(await pathExists(changesDir))) {\n return [];\n }\n\n const entries = await fs.readdir(changesDir, { withFileTypes: true });\n return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();\n}\n\nexport async function resolveOpenSpecChange(root: string, requested?: string): Promise<string> {\n if (requested) {\n const changeDir = path.join(root, \"openspec\", \"changes\", requested);\n\n if (!(await pathExists(changeDir))) {\n throw new Error(`OpenSpec change not found: ${requested}`);\n }\n\n return requested;\n }\n\n const changes = await listOpenSpecChanges(root);\n\n if (changes.length === 1) {\n return changes[0];\n }\n\n if (changes.length === 0) {\n throw new Error(\"No OpenSpec changes found.\");\n }\n\n throw new Error(`Multiple OpenSpec changes found. Specify one with --change: ${changes.join(\", \")}`);\n}\n\nexport async function readOpenSpecContext(root: string, change: string): Promise<OpenSpecContext> {\n const changeDir = path.join(root, \"openspec\", \"changes\", change);\n return {\n change,\n proposal: filterExcludedLines(await readTextIfExists(path.join(changeDir, \"proposal.md\"))),\n design: filterExcludedLines(await readTextIfExists(path.join(changeDir, \"design.md\"))),\n tasks: filterExcludedLines(await readTextIfExists(path.join(changeDir, \"tasks.md\"))),\n };\n}\n\nexport function formatOpenSpecContext(context?: OpenSpecContext): string {\n if (!context) {\n return \"\";\n }\n\n return [\n `# OpenSpec Change: ${context.change}`,\n \"## proposal.md\",\n context.proposal || \"(missing)\",\n \"## design.md\",\n context.design || \"(missing)\",\n \"## tasks.md\",\n context.tasks || \"(missing)\",\n ].join(\"\\n\\n\");\n}\n","import path from \"node:path\";\nimport { DEFAULT_LANE } from \"./constants.js\";\nimport { ensureDir, safeWriteFile } from \"./fs.js\";\nimport { loadTemplate, renderTemplate } from \"./templates.js\";\nimport type { RelayConfig, RunContext } from \"./types.js\";\n\nexport function slugify(value: string): string {\n const slug = value\n .toLowerCase()\n .replace(/[^a-z0-9\\u4e00-\\u9fa5]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 48);\n\n return slug || \"task\";\n}\n\nexport function createRunId(title: string, date = new Date()): string {\n const day = date.toISOString().slice(0, 10);\n return `${day}-${slugify(title)}`;\n}\n\nexport function getRunContext(root: string, config: RelayConfig, runId: string, lane = DEFAULT_LANE): RunContext {\n const runDir = path.join(root, config.handoffDir, \"runs\", runId);\n return {\n runId,\n lane,\n runDir,\n laneDir: path.join(runDir, \"lanes\", lane),\n };\n}\n\nexport async function createRunStructure(\n root: string,\n config: RelayConfig,\n runId: string,\n lane = DEFAULT_LANE,\n options: { force?: boolean } = {},\n): Promise<RunContext> {\n const context = getRunContext(root, config, runId, lane);\n await ensureDir(context.laneDir);\n await ensureDir(path.join(context.runDir, \"history\"));\n\n const runRelative = path.relative(root, path.join(context.runDir, \"RUN.md\"));\n await safeWriteFile(root, runRelative, `# RUN\\n\\n- Run: ${runId}\\n- Lane: ${lane}\\n`, options);\n\n const board = renderTemplate(await loadTemplate(\"TASK_BOARD.template.md\"), { runId });\n const boardRelative = path.relative(root, path.join(context.runDir, \"TASK_BOARD.md\"));\n await safeWriteFile(root, boardRelative, board, options);\n\n return context;\n}\n","import fsSync from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport function getPackageRoot(): string {\n const moduleDir = path.dirname(fileURLToPath(import.meta.url));\n const candidates = [\n moduleDir,\n path.resolve(moduleDir, \"..\"),\n path.resolve(moduleDir, \"..\", \"..\"),\n ];\n\n for (const candidate of candidates) {\n if (fsSync.existsSync(path.join(candidate, \"templates\")) && fsSync.existsSync(path.join(candidate, \"skills\"))) {\n return candidate;\n }\n }\n\n // Keep the source-tree default in error paths so missing template messages stay actionable.\n return path.resolve(moduleDir, \"..\", \"..\");\n}\n\nexport function renderTemplate(template: string, values: Record<string, string>): string {\n return template.replace(/\\{\\{([A-Za-z0-9_]+)\\}\\}/g, (_, rawKey: string) => {\n return values[rawKey] ?? \"\";\n });\n}\n\nexport async function loadTemplate(name: string): Promise<string> {\n const templatePath = path.join(getPackageRoot(), \"templates\", name);\n\n try {\n return await fs.readFile(templatePath, \"utf8\");\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n throw new Error(`Missing template ${name}: ${detail}`);\n }\n}\n","import path from \"node:path\";\nimport { DEFAULT_LANE, STATE_FILE } from \"./constants.js\";\nimport { readJsonIfExists, writeJsonFile } from \"./fs.js\";\nimport type { RelayMode, RelayState } from \"./types.js\";\n\nexport function createDefaultState(mode: RelayMode): RelayState {\n return {\n currentRun: \"\",\n currentLane: DEFAULT_LANE,\n mode,\n currentChange: \"\",\n updatedAt: new Date().toISOString(),\n advisorMode: \"review\",\n executorFailures: {\n currentTask: 0,\n totalEscalations: 0,\n },\n directFixLog: [],\n };\n}\n\nexport async function loadState(root: string): Promise<RelayState> {\n const state = await readJsonIfExists<RelayState>(path.join(root, STATE_FILE));\n\n if (!state) {\n throw new Error(\"Missing .relay/state.json. Run relay init first.\");\n }\n\n return state;\n}\n\nexport async function writeState(root: string, state: RelayState): Promise<void> {\n await writeJsonFile(path.join(root, STATE_FILE), state);\n}\n\nexport async function updateState(root: string, patch: Partial<RelayState>): Promise<RelayState> {\n const current = await loadState(root);\n const next = { ...current, ...patch, updatedAt: new Date().toISOString() };\n await writeState(root, next);\n return next;\n}\n","import type { Command } from \"commander\";\nimport path from \"node:path\";\nimport { AGENTS_START_MARKER, CONFIG_FILE, DEFAULT_SKILLS, STATE_FILE } from \"../core/constants.js\";\nimport { loadConfig } from \"../core/config.js\";\nimport { pathExists, readTextIfExists } from \"../core/fs.js\";\nimport { listOpenSpecChanges } from \"../core/openspec.js\";\nimport { detectProject } from \"../core/project.js\";\nimport { getRunContext } from \"../core/runs.js\";\nimport { loadState } from \"../core/state.js\";\n\nexport function registerDoctorCommand(program: Command): void {\n program\n .command(\"doctor\")\n .description(\"Check relay-kit project integration status.\")\n .action(async () => {\n console.log(await runDoctor(process.cwd()));\n });\n}\n\nexport async function runDoctor(root: string): Promise<string> {\n const project = await detectProject(root);\n const checks: string[] = [];\n const configExists = await pathExists(path.join(root, CONFIG_FILE));\n const stateExists = await pathExists(path.join(root, STATE_FILE));\n\n checks.push(formatCheck(configExists, CONFIG_FILE, \"Run relay init.\"));\n checks.push(formatCheck(stateExists, STATE_FILE, \"Run relay init.\"));\n\n const agents = await readTextIfExists(path.join(root, \"AGENTS.md\"));\n checks.push(formatCheck(agents.includes(AGENTS_START_MARKER), \"AGENTS.md relay-kit block\", \"Run relay init --force.\"));\n\n if (configExists && stateExists) {\n const config = await loadConfig(root);\n const state = await loadState(root);\n checks.push(formatCheck(await pathExists(path.join(root, config.handoffDir, \"runs\")), `${config.handoffDir}/runs`, \"Run relay init.\"));\n\n for (const target of [\".relay/skills\", \".claude/skills\", \".agents/skills\"]) {\n for (const skill of DEFAULT_SKILLS) {\n checks.push(formatCheck(await pathExists(path.join(root, target, skill, \"SKILL.md\")), `${target}/${skill}`, \"Run relay init --force.\"));\n }\n }\n\n if (state.currentRun) {\n const run = getRunContext(root, config, state.currentRun, state.currentLane);\n checks.push(formatCheck(await pathExists(run.laneDir), `current lane ${path.relative(root, run.laneDir)}`, \"Run relay start.\"));\n checks.push(formatPending(!(await pathExists(path.join(run.laneDir, \"ASK_ADVISOR.md\"))), \"ASK_ADVISOR.md\", \"Advisor response may be needed.\"));\n checks.push(formatPending(!(await pathExists(path.join(run.laneDir, \"ADVISOR_DECISION.md\"))), \"ADVISOR_DECISION.md\", \"Run relay resume if ready.\"));\n }\n }\n\n checks.push(formatCheck(project.hasPackageJson, \"package.json\", \"CLI works without it, but build/test detection will be limited.\"));\n checks.push(formatCheck(project.packageScripts.build !== undefined, \"package script: build\", \"Add a build script to enable relay ask --run build.\"));\n checks.push(formatCheck(project.packageScripts.test !== undefined, \"package script: test\", \"Add a test script to enable relay ask --run test.\"));\n\n if (project.hasOpenSpec) {\n const changes = await listOpenSpecChanges(root);\n checks.push(`ok OpenSpec changes: ${changes.length ? changes.join(\", \") : \"(none)\"}`);\n } else {\n checks.push(\"warn OpenSpec: not detected; simple mode is supported.\");\n }\n\n return [\"relay doctor\", ...checks].join(\"\\n\");\n}\n\nfunction formatCheck(ok: boolean, label: string, fix: string): string {\n return ok ? `ok ${label}` : `warn ${label} - ${fix}`;\n}\n\nfunction formatPending(clear: boolean, fileName: string, fix: string): string {\n return clear ? `ok no pending ${fileName}` : `warn pending ${fileName} - ${fix}`;\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { pathExists, stripBom } from \"./fs.js\";\nimport type { PackageManager, ProjectInfo } from \"./types.js\";\n\nasync function readPackageScripts(root: string): Promise<Record<string, string>> {\n const packageJsonPath = path.join(root, \"package.json\");\n\n if (!(await pathExists(packageJsonPath))) {\n return {};\n }\n\n const packageJson = JSON.parse(stripBom(await fs.readFile(packageJsonPath, \"utf8\"))) as {\n scripts?: Record<string, string>;\n };\n\n return packageJson.scripts ?? {};\n}\n\nasync function detectPackageManager(root: string): Promise<PackageManager> {\n if (await pathExists(path.join(root, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (await pathExists(path.join(root, \"package-lock.json\"))) return \"npm\";\n if (await pathExists(path.join(root, \"yarn.lock\"))) return \"yarn\";\n if (await pathExists(path.join(root, \"bun.lockb\"))) return \"bun\";\n return \"unknown\";\n}\n\nexport async function detectProject(root = process.cwd()): Promise<ProjectInfo> {\n const resolvedRoot = path.resolve(root);\n const packageJsonPath = path.join(resolvedRoot, \"package.json\");\n const packageJson = (await pathExists(packageJsonPath))\n ? (JSON.parse(stripBom(await fs.readFile(packageJsonPath, \"utf8\"))) as { name?: string })\n : {};\n\n return {\n root: resolvedRoot,\n name: packageJson.name ?? path.basename(resolvedRoot),\n hasGit: await pathExists(path.join(resolvedRoot, \".git\")),\n hasPackageJson: await pathExists(packageJsonPath),\n packageManager: await detectPackageManager(resolvedRoot),\n packageScripts: await readPackageScripts(resolvedRoot),\n hasOpenSpec: await hasOpenSpecStructure(resolvedRoot),\n };\n}\n\nexport async function hasOpenSpecStructure(root: string): Promise<boolean> {\n return (\n (await pathExists(path.join(root, \"openspec\"))) &&\n ((await pathExists(path.join(root, \"openspec\", \"changes\"))) ||\n (await pathExists(path.join(root, \"openspec\", \"specs\"))))\n );\n}\n","import type { Command } from \"commander\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n RELAYIGNORE_FILE,\n AGENTS_END_MARKER,\n AGENTS_START_MARKER,\n CONFIG_FILE,\n DEFAULT_RELAYIGNORE_CONTENT,\n DEFAULT_HANDOFF_DIR,\n STATE_FILE,\n} from \"../core/constants.js\";\nimport { createDefaultConfig, writeConfig } from \"../core/config.js\";\nimport { ensureDir, pathExists, readTextIfExists, safeWriteFile } from \"../core/fs.js\";\nimport { detectProject } from \"../core/project.js\";\nimport { createDefaultState, writeState } from \"../core/state.js\";\nimport { loadTemplate } from \"../core/templates.js\";\nimport { installProjectSkills } from \"../core/skills.js\";\nimport type { RelayMode } from \"../core/types.js\";\n\ninterface InitOptions {\n mode?: RelayMode;\n withOpenspec?: boolean;\n yes?: boolean;\n force?: boolean;\n}\n\nexport function registerInitCommand(program: Command): void {\n program\n .command(\"init\")\n .description(\"Initialize relay-kit in the current project.\")\n .option(\"--mode <mode>\", \"Initialization mode: simple or openspec.\")\n .option(\"--with-openspec\", \"Show OpenSpec setup guidance without silently creating openspec/.\")\n .option(\"--yes\", \"Accept non-destructive defaults.\")\n .option(\"--force\", \"Overwrite relay-kit managed files.\")\n .action(async (options: InitOptions) => {\n const result = await runInit(process.cwd(), options);\n console.log(result.summary);\n });\n}\n\nexport async function runInit(root: string, options: InitOptions = {}): Promise<{ summary: string }> {\n const project = await detectProject(root);\n const mode = resolveMode(project.hasOpenSpec, options.mode);\n\n if (options.mode === \"openspec\" && !project.hasOpenSpec) {\n throw new Error(\"Cannot use --mode openspec because openspec/ was not detected.\");\n }\n\n const config = createDefaultConfig(project, mode);\n const state = createDefaultState(mode);\n await ensureDir(path.join(root, \".relay\"));\n\n if (!options.force && ((await pathExists(path.join(root, CONFIG_FILE))) || (await pathExists(path.join(root, STATE_FILE))))) {\n throw new Error(\"relay-kit is already initialized. Use --force to rewrite managed config/state files.\");\n }\n\n await writeConfig(root, config);\n await writeState(root, state);\n await ensureDir(path.join(root, DEFAULT_HANDOFF_DIR, \"runs\"));\n const relayIgnoreStatus = await ensureRelayIgnore(root);\n await injectAgentsRules(root, options.force);\n const skillTargets = await installProjectSkills(root, config, { force: options.force });\n\n const guidance =\n options.withOpenspec && !project.hasOpenSpec\n ? \"\\nOpenSpec was requested, but relay-kit did not create openspec/. Install/init OpenSpec explicitly, then rerun relay init --mode openspec --force.\"\n : \"\";\n\n return {\n summary: [\n `relay init complete (${mode}).`,\n `Config: ${CONFIG_FILE}`,\n `State: ${STATE_FILE}`,\n `Relay ignore: ${relayIgnoreStatus}`,\n `Skills: ${skillTargets.map((target) => path.relative(root, target)).join(\", \")}`,\n guidance,\n ]\n .filter(Boolean)\n .join(\"\\n\"),\n };\n}\n\nasync function ensureRelayIgnore(root: string): Promise<string> {\n if (await pathExists(path.join(root, RELAYIGNORE_FILE))) {\n return `${RELAYIGNORE_FILE} (kept existing)`;\n }\n\n await safeWriteFile(root, RELAYIGNORE_FILE, DEFAULT_RELAYIGNORE_CONTENT);\n return RELAYIGNORE_FILE;\n}\n\nfunction resolveMode(hasOpenSpec: boolean, requested?: RelayMode): RelayMode {\n if (requested && requested !== \"simple\" && requested !== \"openspec\") {\n throw new Error(\"--mode must be simple or openspec.\");\n }\n\n return requested ?? (hasOpenSpec ? \"openspec\" : \"simple\");\n}\n\nasync function injectAgentsRules(root: string, force = false): Promise<void> {\n const agentsPath = path.join(root, \"AGENTS.md\");\n const existing = await readTextIfExists(agentsPath);\n const block = (await loadTemplate(\"AGENTS.relay.md\")).trim();\n\n if (existing.includes(AGENTS_START_MARKER) && existing.includes(AGENTS_END_MARKER)) {\n if (!force) {\n return;\n }\n\n const pattern = new RegExp(`${escapeRegExp(AGENTS_START_MARKER)}[\\\\s\\\\S]*?${escapeRegExp(AGENTS_END_MARKER)}`);\n await fs.writeFile(agentsPath, `${existing.replace(pattern, block).trim()}\\n`, \"utf8\");\n return;\n }\n\n const next = existing.trim() ? `${existing.trim()}\\n\\n${block}\\n` : `${block}\\n`;\n // AGENTS.md may already exist with user rules; force only bypasses safeWriteFile's create-only guard for this merged content.\n await safeWriteFile(root, \"AGENTS.md\", next, { force: true });\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n","import path from \"node:path\";\nimport { DEFAULT_HANDOFF_DIR, DEFAULT_SKILLS } from \"./constants.js\";\nimport { copyDirectory, ensureDir } from \"./fs.js\";\nimport { getPackageRoot } from \"./templates.js\";\nimport type { RelayConfig } from \"./types.js\";\n\nexport async function installProjectSkills(\n root: string,\n config: RelayConfig,\n options: { force?: boolean } = {},\n): Promise<string[]> {\n const sourceRoot = path.join(getPackageRoot(), \"skills\");\n const targets: string[] = [];\n\n if (config.skills.install.manager) targets.push(path.join(root, \".relay\", \"skills\"));\n if (config.skills.install.claudeProject) targets.push(path.join(root, \".claude\", \"skills\"));\n if (config.skills.install.codexProject) targets.push(path.join(root, \".agents\", \"skills\"));\n\n for (const targetRoot of targets) {\n await ensureDir(targetRoot);\n\n for (const skill of DEFAULT_SKILLS) {\n await copyDirectory(path.join(sourceRoot, skill), path.join(targetRoot, skill), options);\n }\n }\n\n return targets;\n}\n","import type { Command } from \"commander\";\nimport path from \"node:path\";\nimport { copyToClipboard } from \"../core/clipboard.js\";\nimport { loadConfig } from \"../core/config.js\";\nimport { readTextIfExists, safeWriteFile } from \"../core/fs.js\";\nimport { getRunContext } from \"../core/runs.js\";\nimport { loadState } from \"../core/state.js\";\nimport { loadTemplate, renderTemplate } from \"../core/templates.js\";\n\ninterface ResumeOptions {\n from?: string;\n copy?: boolean;\n force?: boolean;\n}\n\nexport function registerResumeCommand(program: Command): void {\n program\n .command(\"resume\")\n .description(\"Create a resume prompt from a relay decision.\")\n .option(\"--from <path>\", \"Read Advisor decision from a specific file.\")\n .option(\"--copy\", \"Copy generated content to clipboard.\")\n .option(\"--force\", \"Overwrite RESUME_PROMPT.md.\")\n .action(async (options: ResumeOptions) => {\n const result = await runResume(process.cwd(), options);\n console.log(result.summary);\n });\n}\n\nexport async function runResume(root: string, options: ResumeOptions = {}): Promise<{ file: string; summary: string }> {\n const config = await loadConfig(root);\n const state = await loadState(root);\n\n if (!state.currentRun) {\n throw new Error(\"No current run. Run relay start first.\");\n }\n\n const run = getRunContext(root, config, state.currentRun, state.currentLane);\n const sourcePath = options.from ? path.resolve(root, options.from) : path.join(run.laneDir, \"ADVISOR_DECISION.md\");\n const decision = await readTextIfExists(sourcePath);\n\n if (!decision.trim()) {\n throw new Error(`Decision is missing or empty: ${path.relative(root, sourcePath)}`);\n }\n\n const prompt = extractPromptForExecutor(decision);\n\n if (!prompt.trim()) {\n throw new Error(\"Decision does not contain a non-empty 'Prompt For Executor' section.\");\n }\n\n const content = renderTemplate(await loadTemplate(\"RESUME_PROMPT.template.md\"), {\n promptForExecutor: prompt,\n });\n const relative = path.relative(root, path.join(run.laneDir, \"RESUME_PROMPT.md\"));\n const file = await safeWriteFile(root, relative, content, { force: options.force });\n const copied = options.copy ? await copyToClipboard(content) : undefined;\n\n return {\n file,\n summary: [`Created ${path.relative(root, file)}`, copied === false ? \"Clipboard copy failed; file was still generated.\" : \"\"]\n .filter(Boolean)\n .join(\"\\n\"),\n };\n}\n\nexport function extractPromptForExecutor(decision: string): string {\n const heading = /^## Prompt For Executor\\s*$/im.exec(decision);\n\n if (!heading) {\n return \"\";\n }\n\n const bodyStart = heading.index + heading[0].length;\n const rest = decision.slice(bodyStart);\n const nextHeading = /^##\\s.+$/im.exec(rest);\n return rest.slice(0, nextHeading?.index).trim();\n}\n","import type { Command } from \"commander\";\nimport path from \"node:path\";\nimport { copyToClipboard } from \"../core/clipboard.js\";\nimport { loadConfig } from \"../core/config.js\";\nimport { createContextSafety } from \"../core/context-safety.js\";\nimport { readTextIfExists, safeWriteFile } from \"../core/fs.js\";\nimport { collectGitContext } from \"../core/git.js\";\nimport { formatOpenSpecContext, readOpenSpecContext } from \"../core/openspec.js\";\nimport { getRunContext } from \"../core/runs.js\";\nimport { loadState } from \"../core/state.js\";\nimport { loadTemplate, renderTemplate } from \"../core/templates.js\";\n\ninterface ReviewOptions {\n copy?: boolean;\n force?: boolean;\n}\n\nexport function registerReviewCommand(program: Command): void {\n program\n .command(\"review\")\n .description(\"Create a relay review request for the current implementation.\")\n .option(\"--copy\", \"Copy generated content to clipboard.\")\n .option(\"--force\", \"Overwrite REVIEW_REQUEST.md.\")\n .action(async (options: ReviewOptions) => {\n const result = await runReview(process.cwd(), options);\n console.log(result.summary);\n });\n}\n\nexport async function runReview(root: string, options: ReviewOptions = {}): Promise<{ file: string; summary: string }> {\n const config = await loadConfig(root);\n const state = await loadState(root);\n\n if (!state.currentRun) {\n throw new Error(\"No current run. Run relay start first.\");\n }\n\n const run = getRunContext(root, config, state.currentRun, state.currentLane);\n const contextSafety = await createContextSafety(root, config);\n const git = await collectGitContext(root, {\n maxDiffLines: config.maxDiffLines,\n gitExcludePathspecs: contextSafety.ignore.gitExcludePathspecs,\n shouldIgnorePath: contextSafety.shouldIgnorePath,\n redactText: contextSafety.redactText,\n });\n const task = contextSafety.redactText(await readTextIfExists(path.join(run.laneDir, \"EXECUTOR_TASK.md\")));\n const openSpecText =\n state.mode === \"openspec\" && state.currentChange\n ? contextSafety.redactText(formatOpenSpecContext(await readOpenSpecContext(root, state.currentChange)))\n : \"\";\n\n const content = renderTemplate(await loadTemplate(\"REVIEW_REQUEST.template.md\"), {\n projectName: config.projectName,\n runId: state.currentRun,\n lane: state.currentLane,\n ignoreRulesStatus: contextSafety.ignoreRulesStatus,\n redactionRulesStatus: contextSafety.redactionRulesStatus,\n gitDiffStat: git.diffStat || \"(no diff)\",\n gitDiff: [git.diff || \"(no diff)\", task ? `\\n\\n# Current Executor Task\\n${task}` : \"\", openSpecText].filter(Boolean).join(\"\\n\"),\n });\n const relative = path.relative(root, path.join(run.laneDir, \"REVIEW_REQUEST.md\"));\n const file = await safeWriteFile(root, relative, content, { force: options.force });\n const copied = options.copy ? await copyToClipboard(content) : undefined;\n\n return {\n file,\n summary: [`Created ${path.relative(root, file)}`, copied === false ? \"Clipboard copy failed; file was still generated.\" : \"\"]\n .filter(Boolean)\n .join(\"\\n\"),\n };\n}\n","import type { Command } from \"commander\";\nimport path from \"node:path\";\nimport { createInterface } from \"node:readline/promises\";\nimport { stdin as input, stdout as output } from \"node:process\";\nimport { DEFAULT_LANE } from \"../core/constants.js\";\nimport { copyToClipboard } from \"../core/clipboard.js\";\nimport { loadConfig } from \"../core/config.js\";\nimport { safeWriteFile } from \"../core/fs.js\";\nimport { formatOpenSpecContext, readOpenSpecContext, resolveOpenSpecChange } from \"../core/openspec.js\";\nimport { createRunId, createRunStructure } from \"../core/runs.js\";\nimport { loadState, updateState } from \"../core/state.js\";\nimport { loadTemplate, renderTemplate } from \"../core/templates.js\";\n\ninterface StartOptions {\n title?: string;\n scope?: string;\n blockedScope?: string;\n change?: string;\n copy?: boolean;\n force?: boolean;\n}\n\nexport function registerStartCommand(program: Command): void {\n program\n .command(\"start\")\n .description(\"Start a relay handoff run and create an executor task.\")\n .option(\"--title <title>\", \"Simple mode task title.\")\n .option(\"--scope <scope>\", \"Allowed implementation scope.\")\n .option(\"--blocked-scope <scope>\", \"Scope that must not be changed.\")\n .option(\"--change <change>\", \"OpenSpec change name.\")\n .option(\"--copy\", \"Copy generated handoff content to clipboard.\")\n .option(\"--force\", \"Overwrite generated run files.\")\n .action(async (options: StartOptions) => {\n const result = await runStart(process.cwd(), options);\n console.log(result.summary);\n });\n}\n\nexport async function runStart(root: string, options: StartOptions = {}): Promise<{ file: string; summary: string }> {\n const config = await loadConfig(root);\n const state = await loadState(root);\n const mode = state.mode || config.mode;\n const answers = mode === \"simple\" ? await collectSimpleInputs(options) : options;\n const title = answers.title || (mode === \"openspec\" ? \"OpenSpec handoff\" : \"Untitled task\");\n const runId = createRunId(title);\n const run = await createRunStructure(root, config, runId, DEFAULT_LANE, { force: options.force });\n\n let change = options.change || state.currentChange;\n let openSpecText = \"\";\n\n if (mode === \"openspec\") {\n change = await resolveOpenSpecChange(root, change || undefined);\n openSpecText = formatOpenSpecContext(await readOpenSpecContext(root, change));\n }\n\n const content = renderTemplate(await loadTemplate(\"EXECUTOR_TASK.template.md\"), {\n projectName: config.projectName,\n runId,\n lane: DEFAULT_LANE,\n mode,\n change: change || \"\",\n taskTitle: title,\n allowedScope: [answers.scope || \"Follow the current task only.\", openSpecText].filter(Boolean).join(\"\\n\\n\"),\n blockedScope: answers.blockedScope || \"Do not expand scope beyond EXECUTOR_TASK.md.\",\n });\n\n const relative = path.relative(root, path.join(run.laneDir, \"EXECUTOR_TASK.md\"));\n const file = await safeWriteFile(root, relative, content, { force: options.force });\n await updateState(root, { currentRun: runId, currentLane: DEFAULT_LANE, mode, currentChange: change || \"\" });\n\n const copied = options.copy ? await copyToClipboard(content) : undefined;\n\n return {\n file,\n summary: [`Created ${path.relative(root, file)}`, copied === false ? \"Clipboard copy failed; file was still generated.\" : \"\"]\n .filter(Boolean)\n .join(\"\\n\"),\n };\n}\n\nasync function collectSimpleInputs(options: StartOptions): Promise<StartOptions> {\n if (options.title && options.scope && options.blockedScope) {\n return options;\n }\n\n if (!input.isTTY || !output.isTTY) {\n return options;\n }\n\n const rl = createInterface({ input, output });\n\n try {\n return {\n ...options,\n title: options.title || (await rl.question(\"Task title: \")),\n scope: options.scope || (await rl.question(\"Allowed scope: \")),\n blockedScope: options.blockedScope || (await rl.question(\"Blocked scope: \")),\n };\n } finally {\n rl.close();\n }\n}\n","import crypto from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { RELAY_DIR } from \"./constants.js\";\nimport { ensureDir, pathExists, readJsonIfExists, writeJsonFile } from \"./fs.js\";\nimport type { RelayConfig } from \"./types.js\";\n\nexport type SkillSyncTool = \"claude\" | \"codex\";\nexport type SkillSyncTargetOption = SkillSyncTool | \"all\";\nexport type SkillSyncScope = \"project\" | \"user\";\nexport type SkillSyncAction = \"create\" | \"update\" | \"unchanged\" | \"conflict\" | \"skip\";\n\nexport interface SkillSyncOptions {\n target?: SkillSyncTargetOption;\n scope?: SkillSyncScope;\n dryRun?: boolean;\n force?: boolean;\n homeDir?: string;\n}\n\nexport interface SkillSyncTarget {\n tool: SkillSyncTool;\n scope: SkillSyncScope;\n root: string;\n}\n\nexport interface SkillSyncEntry {\n action: SkillSyncAction;\n tool: SkillSyncTool;\n scope: SkillSyncScope;\n skill: string;\n relativePath: string;\n sourcePath: string;\n targetPath: string;\n reason: string;\n}\n\nexport interface SkillSyncReport {\n sourceRoot: string;\n targetOption: SkillSyncTargetOption | \"configured\";\n scope: SkillSyncScope;\n dryRun: boolean;\n force: boolean;\n targets: SkillSyncTarget[];\n entries: SkillSyncEntry[];\n summary: Record<SkillSyncAction, number>;\n}\n\ninterface SkillSourceFile {\n skill: string;\n relativePath: string;\n absolutePath: string;\n hash: string;\n content: Buffer;\n}\n\ninterface SkillSyncManifest {\n version: 1;\n records: Record<string, SkillSyncManifestRecord>;\n}\n\ninterface SkillSyncManifestRecord {\n sourceHash: string;\n targetHash: string;\n syncedAt: string;\n}\n\nexport class SkillSyncConflictError extends Error {\n constructor(public readonly report: SkillSyncReport) {\n super(\"Skills sync encountered conflicts. Re-run with --force to overwrite conflicted files.\");\n }\n}\n\nconst MANIFEST_FILE = path.join(RELAY_DIR, \"skills-sync.json\");\nconst ACTIONS: SkillSyncAction[] = [\"create\", \"update\", \"unchanged\", \"conflict\", \"skip\"];\n\nexport async function syncSkills(root: string, config: RelayConfig, options: SkillSyncOptions = {}): Promise<SkillSyncReport> {\n const sourceRoot = path.join(root, RELAY_DIR, \"skills\");\n const scope = options.scope ?? \"project\";\n const targets = resolveSkillSyncTargets(root, config, { ...options, scope });\n const sources = await collectSkillSourceFiles(sourceRoot);\n const manifest = await readManifest(root);\n const report = await planSkillSync(sourceRoot, sources, targets, manifest, options.target ?? \"configured\", scope, options);\n\n if (!options.force && report.summary.conflict > 0) {\n throw new SkillSyncConflictError(report);\n }\n\n if (!options.dryRun) {\n await applySkillSync(report, sources, manifest);\n await writeJsonFile(path.join(root, MANIFEST_FILE), manifest);\n }\n\n return report;\n}\n\nexport function resolveSkillSyncTargets(root: string, config: RelayConfig, options: SkillSyncOptions = {}): SkillSyncTarget[] {\n const scope = options.scope ?? \"project\";\n const homeDir = options.homeDir ?? os.homedir();\n const tools = resolveTools(config, options.target, scope);\n\n return tools.map((tool) => ({\n tool,\n scope,\n root: resolveTargetRoot(root, homeDir, tool, scope),\n }));\n}\n\nexport function formatSkillSyncReport(report: SkillSyncReport): string {\n const targetLabels = report.targets.map((target) => pathLabel(target.root)).join(\", \") || \"(none)\";\n const lines = [\n \"relay sync --skills\",\n `source: ${pathLabel(report.sourceRoot)}`,\n `scope: ${report.scope}`,\n `target: ${report.targetOption}`,\n `dry-run: ${report.dryRun ? \"yes\" : \"no\"}`,\n `force: ${report.force ? \"yes\" : \"no\"}`,\n `targets: ${targetLabels}`,\n `summary: create ${report.summary.create}, update ${report.summary.update}, unchanged ${report.summary.unchanged}, conflict ${report.summary.conflict}, skip ${report.summary.skip}`,\n ];\n\n if (report.entries.length) {\n lines.push(\"files:\");\n for (const entry of report.entries) {\n lines.push(`- ${entry.action} ${entry.tool}/${entry.scope} ${entry.skill}/${entry.relativePath} -> ${pathLabel(entry.targetPath)} (${entry.reason})`);\n }\n }\n\n if (report.summary.conflict > 0) {\n lines.push(\"conflicts:\");\n for (const entry of report.entries.filter((item) => item.action === \"conflict\")) {\n lines.push(`- ${pathLabel(entry.targetPath)}`);\n }\n lines.push(\"Use --force to overwrite conflicted files after reviewing them.\");\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction resolveTools(config: RelayConfig, target: SkillSyncTargetOption | undefined, scope: SkillSyncScope): SkillSyncTool[] {\n if (target) {\n if (target === \"all\") {\n return [\"claude\", \"codex\"];\n }\n\n return [target];\n }\n\n if (scope === \"project\") {\n return [\n config.skills.install.claudeProject ? \"claude\" : undefined,\n config.skills.install.codexProject ? \"codex\" : undefined,\n ].filter((tool): tool is SkillSyncTool => Boolean(tool));\n }\n\n const tools = [\n config.skills.install.claudeUser ? \"claude\" : undefined,\n config.skills.install.codexUser ? \"codex\" : undefined,\n ].filter((tool): tool is SkillSyncTool => Boolean(tool));\n\n if (tools.length === 0) {\n throw new Error(\"No user-level skills targets are enabled. Pass --target claude, --target codex, or --target all with --scope user.\");\n }\n\n return tools;\n}\n\nfunction resolveTargetRoot(root: string, homeDir: string, tool: SkillSyncTool, scope: SkillSyncScope): string {\n if (scope === \"user\") {\n return path.join(homeDir, tool === \"claude\" ? \".claude\" : \".agents\", \"skills\");\n }\n\n return path.join(root, tool === \"claude\" ? \".claude\" : \".agents\", \"skills\");\n}\n\nasync function collectSkillSourceFiles(sourceRoot: string): Promise<SkillSourceFile[]> {\n if (!(await pathExists(sourceRoot))) {\n throw new Error(\"Missing .relay/skills. Run relay init first.\");\n }\n\n const entries = await fs.readdir(sourceRoot, { withFileTypes: true });\n const files: SkillSourceFile[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory() || !entry.name.startsWith(\"relay-\")) {\n continue;\n }\n\n const skillRoot = path.join(sourceRoot, entry.name);\n if (!(await pathExists(path.join(skillRoot, \"SKILL.md\")))) {\n continue;\n }\n\n files.push(...(await collectFiles(skillRoot, entry.name, \"\")));\n }\n\n if (files.length === 0) {\n throw new Error(\"No relay skills found in .relay/skills.\");\n }\n\n return files;\n}\n\nasync function collectFiles(skillRoot: string, skill: string, relativeDir: string): Promise<SkillSourceFile[]> {\n const dir = path.join(skillRoot, relativeDir);\n const entries = await fs.readdir(dir, { withFileTypes: true });\n const files: SkillSourceFile[] = [];\n\n for (const entry of entries) {\n const relativePath = path.join(relativeDir, entry.name);\n const absolutePath = path.join(skillRoot, relativePath);\n\n if (entry.isDirectory()) {\n files.push(...(await collectFiles(skillRoot, skill, relativePath)));\n continue;\n }\n\n if (!entry.isFile()) {\n continue;\n }\n\n const content = await fs.readFile(absolutePath);\n files.push({\n skill,\n relativePath,\n absolutePath,\n content,\n hash: hashBuffer(content),\n });\n }\n\n return files;\n}\n\nasync function planSkillSync(\n sourceRoot: string,\n sources: SkillSourceFile[],\n targets: SkillSyncTarget[],\n manifest: SkillSyncManifest,\n targetOption: SkillSyncTargetOption | \"configured\",\n scope: SkillSyncScope,\n options: SkillSyncOptions,\n): Promise<SkillSyncReport> {\n const entries: SkillSyncEntry[] = [];\n const summary = createEmptySummary();\n\n for (const target of targets) {\n for (const source of sources) {\n const targetPath = path.join(target.root, source.skill, source.relativePath);\n const recordKey = manifestKey(target, source.skill, source.relativePath);\n const record = manifest.records[recordKey];\n const targetExists = await pathExists(targetPath);\n const targetHash = targetExists ? hashBuffer(await fs.readFile(targetPath)) : \"\";\n const action = resolveAction(source.hash, targetExists, targetHash, record, Boolean(options.force));\n const reason = actionReason(action, targetExists, record, Boolean(options.force));\n\n entries.push({\n action,\n tool: target.tool,\n scope: target.scope,\n skill: source.skill,\n relativePath: normalizeRelative(source.relativePath),\n sourcePath: source.absolutePath,\n targetPath,\n reason,\n });\n summary[action] += 1;\n }\n }\n\n return {\n sourceRoot,\n targetOption,\n scope,\n dryRun: Boolean(options.dryRun),\n force: Boolean(options.force),\n targets,\n entries,\n summary,\n };\n}\n\nasync function applySkillSync(report: SkillSyncReport, sources: SkillSourceFile[], manifest: SkillSyncManifest): Promise<void> {\n const sourceByKey = new Map(sources.map((source) => [`${source.skill}/${normalizeRelative(source.relativePath)}`, source]));\n const syncedAt = new Date().toISOString();\n\n for (const entry of report.entries) {\n const source = sourceByKey.get(`${entry.skill}/${entry.relativePath}`);\n if (!source) {\n continue;\n }\n\n if (entry.action === \"create\" || entry.action === \"update\") {\n await ensureDir(path.dirname(entry.targetPath));\n await fs.writeFile(entry.targetPath, source.content);\n }\n\n if (entry.action === \"create\" || entry.action === \"update\" || entry.action === \"unchanged\") {\n manifest.records[manifestKey(entry, entry.skill, entry.relativePath)] = {\n sourceHash: source.hash,\n targetHash: source.hash,\n syncedAt,\n };\n }\n }\n}\n\nfunction resolveAction(\n sourceHash: string,\n targetExists: boolean,\n targetHash: string,\n record: SkillSyncManifestRecord | undefined,\n force: boolean,\n): SkillSyncAction {\n if (!targetExists) {\n return \"create\";\n }\n\n if (targetHash === sourceHash) {\n return \"unchanged\";\n }\n\n if (record?.targetHash === targetHash || force) {\n return \"update\";\n }\n\n return \"conflict\";\n}\n\nfunction actionReason(action: SkillSyncAction, targetExists: boolean, record: SkillSyncManifestRecord | undefined, force: boolean): string {\n if (action === \"create\") return \"target file does not exist\";\n if (action === \"unchanged\") return record ? \"target already matches source\" : \"target matches source; recording sync state\";\n if (action === \"update\") return force ? \"force enabled\" : \"target unchanged since last sync\";\n if (action === \"conflict\") return targetExists ? \"target differs and is not safe to overwrite\" : \"not applicable\";\n return \"skipped\";\n}\n\nasync function readManifest(root: string): Promise<SkillSyncManifest> {\n const manifest = await readJsonIfExists<SkillSyncManifest>(path.join(root, MANIFEST_FILE));\n\n if (!manifest || manifest.version !== 1 || typeof manifest.records !== \"object\") {\n return { version: 1, records: {} };\n }\n\n return manifest;\n}\n\nfunction manifestKey(target: Pick<SkillSyncTarget, \"scope\" | \"tool\">, skill: string, relativePath: string): string {\n return `${target.scope}:${target.tool}:${skill}/${normalizeRelative(relativePath)}`;\n}\n\nfunction hashBuffer(value: Buffer): string {\n return `sha256:${crypto.createHash(\"sha256\").update(value).digest(\"hex\")}`;\n}\n\nfunction createEmptySummary(): Record<SkillSyncAction, number> {\n return Object.fromEntries(ACTIONS.map((action) => [action, 0])) as Record<SkillSyncAction, number>;\n}\n\nfunction normalizeRelative(value: string): string {\n return value.replace(/\\\\/g, \"/\");\n}\n\nfunction pathLabel(value: string): string {\n return value.replace(/\\\\/g, \"/\");\n}\n","import type { Command } from \"commander\";\nimport { loadConfig } from \"../core/config.js\";\nimport { formatSkillSyncReport, SkillSyncConflictError, syncSkills, type SkillSyncScope, type SkillSyncTargetOption } from \"../core/skills-sync.js\";\n\ninterface SyncOptions {\n skills?: boolean;\n target?: SkillSyncTargetOption;\n scope?: SkillSyncScope;\n dryRun?: boolean;\n force?: boolean;\n homeDir?: string;\n}\n\nexport function registerSyncCommand(program: Command): void {\n program\n .command(\"sync\")\n .description(\"Synchronize relay-kit managed resources.\")\n .option(\"--skills\", \"Synchronize relay Skills from .relay/skills.\")\n .option(\"--target <target>\", \"Skill target: claude, codex, or all.\")\n .option(\"--scope <scope>\", \"Skill sync scope: project or user.\", \"project\")\n .option(\"--dry-run\", \"Preview the sync plan without writing files.\")\n .option(\"--force\", \"Overwrite conflicted skill files.\")\n .action(async (options: SyncOptions) => {\n const result = await runSync(process.cwd(), options);\n console.log(result.summary);\n });\n}\n\nexport async function runSync(root: string, options: SyncOptions = {}): Promise<{ summary: string }> {\n if (!options.skills) {\n throw new Error(\"relay sync currently supports only --skills.\");\n }\n\n validateTarget(options.target);\n validateScope(options.scope);\n\n const config = await loadConfig(root);\n\n try {\n const report = await syncSkills(root, config, options);\n return { summary: formatSkillSyncReport(report) };\n } catch (error) {\n if (error instanceof SkillSyncConflictError) {\n throw new Error(`${formatSkillSyncReport(error.report)}\\n${error.message}`);\n }\n\n throw error;\n }\n}\n\nfunction validateTarget(target: string | undefined): asserts target is SkillSyncTargetOption | undefined {\n if (target === undefined || target === \"claude\" || target === \"codex\" || target === \"all\") {\n return;\n }\n\n throw new Error(\"--target must be claude, codex, or all.\");\n}\n\nfunction validateScope(scope: string | undefined): asserts scope is SkillSyncScope | undefined {\n if (scope === undefined || scope === \"project\" || scope === \"user\") {\n return;\n }\n\n throw new Error(\"--scope must be project or user.\");\n}\n"],"mappings":"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","names":["path","promisify","promisify","output","path","path","path","path","path","path","normalizePath","fs","path","path","fs","path","fs","path","path","path","path","program","git","path","path","fs","path","path","fs","program","path","fs","path","path","path","program","path","fs","path","program","path","path","program","git","path","path","program","path","fs","path","path","fs","program"]}
@@ -0,0 +1,121 @@
1
+ # CLI 规格
2
+
3
+ ## 1. MVP 命令
4
+
5
+ ```bash
6
+ relay init
7
+ relay start
8
+ relay ask
9
+ relay resume
10
+ relay review
11
+ relay doctor
12
+ ```
13
+
14
+ ## 2. relay init
15
+
16
+ 初始化当前项目。
17
+
18
+ ```bash
19
+ relay init
20
+ relay init --mode simple
21
+ relay init --mode openspec
22
+ relay init --with-openspec
23
+ relay init --yes
24
+ relay init --force
25
+ relay init --skills claude,codex
26
+ relay init --skills-manager-only
27
+ ```
28
+
29
+ 行为:检测项目、检测 OpenSpec、选择模式、生成配置、创建 handoff 目录、注入 AGENTS.md、导出 Skills。
30
+
31
+ ## 3. relay start
32
+
33
+ 开始一个任务,生成 `EXECUTOR_TASK.md`。
34
+
35
+ ```bash
36
+ relay start
37
+ relay start --change add-local-project-storage --tasks "1-2" --copy
38
+ relay start --title "优化人工确认页面 UI" --scope "src/pages/HumanConfirm.tsx,src/components/**" --copy
39
+ relay start --lane ui --tasks "3-4" --copy
40
+ ```
41
+
42
+ 无参数时走交互式选择。
43
+
44
+ ## 4. relay ask
45
+
46
+ 卡住时生成 `ASK_ADVISOR.md`。
47
+
48
+ ```bash
49
+ relay ask
50
+ relay ask --run build
51
+ relay ask --lane ui --copy
52
+ relay ask --change add-local-project-storage --copy
53
+ ```
54
+
55
+ 收集:git status、git diff、OpenSpec、构建/测试错误、当前 Executor task。
56
+
57
+ ## 5. relay resume
58
+
59
+ 顾问回复后生成继续执行提示。
60
+
61
+ ```bash
62
+ relay resume
63
+ relay resume --from clipboard
64
+ relay resume --lane ui --copy
65
+ ```
66
+
67
+ 读取 `ADVISOR_DECISION.md`,输出 `RESUME_PROMPT.md`。
68
+
69
+ ## 6. relay review
70
+
71
+ 生成 Review 请求。
72
+
73
+ ```bash
74
+ relay review
75
+ relay review --lane ui --copy
76
+ relay review --run current --copy
77
+ ```
78
+
79
+ 输出 `REVIEW_REQUEST.md`。
80
+
81
+ ## 7. relay doctor
82
+
83
+ 检查:config、AGENTS.md、skills、handoff 目录、OpenSpec、package scripts、current run/lane、未处理 ASK/DECISION。
84
+
85
+
86
+ ## 9. relay sync --skills
87
+
88
+ 同步 relay Skills。
89
+
90
+ ```bash
91
+ relay sync --skills
92
+ relay sync --skills --target claude
93
+ relay sync --skills --target codex
94
+ relay sync --skills --target all --scope project
95
+ relay sync --skills --target all --scope user
96
+ relay sync --skills --dry-run
97
+ relay sync --skills --force
98
+ ```
99
+
100
+ 默认从:
101
+
102
+ ```text
103
+ .relay/skills/
104
+ ```
105
+
106
+ 同步到项目级目标:
107
+
108
+ ```text
109
+ .claude/skills/
110
+ .agents/skills/
111
+ ```
112
+
113
+ 规则:
114
+
115
+ 1. 默认只同步当前项目配置启用的项目级目标;
116
+ 2. 用户级目录只在显式传入 `--scope user` 时写入;
117
+ 3. Codex 目标使用 `.agents/skills` 或 `~/.agents/skills`,不使用 `.codex/skills`;
118
+ 4. 默认不覆盖疑似被用户修改过的目标 Skill;
119
+ 5. `--force` 允许覆盖冲突文件;
120
+ 6. `--dry-run` 只输出同步计划,不写入文件或同步状态;
121
+ 7. 命令输出同步报告,包含目标、文件动作和汇总结果。
@@ -0,0 +1,144 @@
1
+ # 最终方案:relay-kit
2
+
3
+ ## 1. 产品一句话
4
+
5
+ `relay-kit` 是一个面向 AI 编程的 **Relay Strategy 工作流工具包**,通过 Skills、CLI、规则文档和 handoff 文件,帮助开发者把任务安全地交给小模型执行,并在卡住或完成时交给聪明模型决策与 Review。
6
+
7
+ ## 2. 解决的问题
8
+
9
+ AI 编程常见问题:
10
+
11
+ 1. 小模型卡住后反复猜测,越改越乱;
12
+ 2. 不同 AI 工具之间缺少稳定交接协议;
13
+ 3. 需求、任务、报错、diff、决策散落在聊天记录里;
14
+ 4. 大模型全程执行成本高,但关键决策又必须依赖大模型;
15
+ 5. 多个项目复用流程困难;
16
+ 6. 并行 Agent 开发容易互相覆盖文件。
17
+
18
+ `relay-kit` 通过如下机制解决:
19
+
20
+ ```text
21
+ AGENTS.md 约束 Executor
22
+ relay-* Skills 约束 Relay
23
+ relay CLI 收集上下文
24
+ handoff markdown 文件沉淀过程
25
+ run / lane 结构支持后续并行
26
+ ```
27
+
28
+ ## 3. 总体架构
29
+
30
+ ```text
31
+ 用户自然语言
32
+
33
+ relay-* Skills
34
+
35
+ relay CLI
36
+
37
+ handoff files
38
+
39
+ OpenCode / Claude Code / Codex / 其他 Executor
40
+
41
+ git diff / build / test
42
+
43
+ Relay Review
44
+ ```
45
+
46
+ ## 4. 分层设计
47
+
48
+ ### 4.1 规则层
49
+
50
+ `AGENTS.md` 注入 relay-kit 规则,主要约束小模型 / Executor:
51
+
52
+ - 小步执行;
53
+ - 不扩大范围;
54
+ - 不引入依赖;
55
+ - 不大规模重构;
56
+ - 连续失败 2 次必须停止;
57
+ - 需要改架构 / 状态 / 数据模型时必须 ask;
58
+ - 完成后必须说明修改文件和验证方式。
59
+
60
+ ### 4.2 Skills 层
61
+
62
+ `relay-*` Skills 约束聪明模型 / Relay:
63
+
64
+ - `relay-planner`:规划、判断 simple/OpenSpec、拆 tasks;
65
+ - `relay-delegator`:把任务委派给小模型,生成执行说明;
66
+ - `relay-escalation`:分析求助包,输出决策;
67
+ - `relay-reviewer`:Review 当前实现;
68
+ - `relay-lane-planner`:后续支持并行 lane;
69
+ - `relay-docs`:后续支持进度和文档沉淀。
70
+
71
+ ### 4.3 CLI 层
72
+
73
+ CLI 是底层能力,不要求用户记复杂参数。
74
+
75
+ ```bash
76
+ relay init # 初始化项目
77
+ relay start # 开始任务,生成 EXECUTOR_TASK.md
78
+ relay ask # 卡住时生成 ASK_ADVISOR.md
79
+ relay resume # 顾问回复后生成继续执行提示
80
+ relay review # 完成后生成 REVIEW_REQUEST.md
81
+ relay doctor # 检查接入状态
82
+ ```
83
+
84
+ ### 4.4 Handoff 文件层
85
+
86
+ 每次任务都会沉淀为文件:
87
+
88
+ ```text
89
+ EXECUTOR_TASK.md
90
+ ASK_ADVISOR.md
91
+ ADVISOR_DECISION.md
92
+ RESUME_PROMPT.md
93
+ REVIEW_REQUEST.md
94
+ REVIEW_REPORT.md
95
+ ```
96
+
97
+ ### 4.5 OpenSpec 适配层
98
+
99
+ - 没有 OpenSpec:simple 模式;
100
+ - 检测到 OpenSpec:启用 openspec 模式;
101
+ - 用户选择“引导初始化”:只提示和确认,不静默安装;
102
+ - 不替代 `/opsx:apply`,只负责任务交接与求助。
103
+
104
+ ## 5. 最重要的边界
105
+
106
+ `relay-kit` 不做:
107
+
108
+ 1. 不自动调用大模型 API;
109
+ 2. 不自动写业务代码;
110
+ 3. 不自动提交 git;
111
+ 4. 不替代 OpenCode / Claude Code;
112
+ 5. 不强制安装 OpenSpec;
113
+ 6. 不静默初始化 OpenSpec;
114
+ 7. MVP 不做 GUI;
115
+ 8. MVP 不做真正自动多 Agent 调度。
116
+
117
+ 它做的是:初始化规则、生成任务交接材料、收集求助上下文、规范 Relay 输出、生成 Review 请求、让流程跨项目复用。
118
+
119
+ ## 6. Skills 安装策略
120
+
121
+ `relay init` 默认采用项目级安装:
122
+
123
+ ```text
124
+ .relay/skills 管理副本,必选
125
+ .claude/skills Claude Code 项目级
126
+ .agents/skills Codex 项目级
127
+ ```
128
+
129
+ 不默认安装用户级 Skills:
130
+
131
+ ```text
132
+ ~/.claude/skills
133
+ ~/.agents/skills
134
+ ```
135
+
136
+ 用户级只在用户明确选择时安装。
137
+
138
+ 这样可以避免污染所有项目,同时保证每个项目都能携带自己的 relay 工作流。
139
+
140
+ 完整规则见:
141
+
142
+ ```text
143
+ docs/SKILLS_INSTALLATION.md
144
+ ```
@@ -0,0 +1,52 @@
1
+ # OpenSpec 集成策略
2
+
3
+ ## 1. 基本原则
4
+
5
+ `relay-kit` 不替代 OpenSpec。
6
+
7
+ ```text
8
+ OpenSpec 管任务定义
9
+ relay-kit 管任务交接、求助、Review
10
+ ```
11
+
12
+ ## 2. 没有 OpenSpec 时
13
+
14
+ `relay init` 提供选择:Simple 模式、OpenSpec 模式、引导初始化 OpenSpec。
15
+
16
+ 默认不安装、不初始化。
17
+
18
+ ## 3. 有 OpenSpec 时
19
+
20
+ 检测到:
21
+
22
+ ```text
23
+ openspec/
24
+ project.md
25
+ changes/
26
+ ```
27
+
28
+ 启用:
29
+
30
+ ```json
31
+ {
32
+ "mode": "openspec",
33
+ "includeOpenSpec": true
34
+ }
35
+ ```
36
+
37
+ `relay start` 会读取 proposal/design/tasks。
38
+
39
+ ## 4. 和 /opsx:apply 的关系
40
+
41
+ 不冲突。
42
+
43
+ ```text
44
+ /opsx:apply = OpenSpec 原生执行
45
+ relay start = 生成给 Executor 的任务交接说明,不执行代码
46
+ relay ask = 卡住时整理求助包
47
+ relay review = 完成后整理 Review 请求
48
+ ```
49
+
50
+ ## 5. Change 策略
51
+
52
+ 可以先规划多个 change,但一次只激活和执行一个 change。追求效率时,在一个 change 内拆 lane。
@@ -0,0 +1,37 @@
1
+ # Run / Lane 设计
2
+
3
+ ## 概念
4
+
5
+ ```text
6
+ run = 一次开发运行,例如 add-local-project-storage
7
+ lane = run 里的一个执行分支,例如 storage / ui / tests
8
+ ```
9
+
10
+ ## 目录结构
11
+
12
+ ```text
13
+ docs/agent-handoffs/
14
+ runs/
15
+ 2026-05-10-add-local-project-storage/
16
+ RUN.md
17
+ TASK_BOARD.md
18
+ lanes/
19
+ main/
20
+ EXECUTOR_TASK.md
21
+ ASK_ADVISOR.md
22
+ ADVISOR_DECISION.md
23
+ RESUME_PROMPT.md
24
+ REVIEW_REQUEST.md
25
+ REVIEW_REPORT.md
26
+ history/
27
+ ```
28
+
29
+ MVP 即使只有单线,也使用 `lanes/main/`,后续并行时不用重构。
30
+
31
+ ## 并行原则
32
+
33
+ 适合并行:UI 细节、测试、文档、独立组件、独立页面。
34
+
35
+ 不适合并行:数据模型、状态管理、路由、API contract、数据库 schema、核心业务流程。
36
+
37
+ 并行时推荐使用 git worktree,避免多个 Executor 在同一工作区互相覆盖。