@kody-ade/kody-engine 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.mjs +90 -19
- package/dist/bin/cli.mjs.map +1 -1
- package/package.json +1 -1
package/dist/bin/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/engine/env.ts","../../../../src/engine/logger.ts","../../../../src/engine/stages/registry.ts","../../../../src/engine/validation.ts","../../../../src/engine/pipeline/task-schema.ts","../../../../src/engine/pipeline/complexity.ts","../../../../src/engine/pipeline/task-io.ts","../../../../src/engine/pipeline-utils.ts","../../../../src/engine/github-api.ts","../../../../src/engine/cli-parser.ts","../../../../src/engine/status-format.ts","../../../../src/engine/kody-utils.ts","../../../../src/engine/preflight.ts","../../../../src/engine/opencode-server.ts","../../../../src/engine/runner-backend.ts","../../../../src/engine/config/constants.ts","../../../../src/engine/engine/types.ts","../../../../src/engine/engine/status.ts","../../../../src/engine/git-utils.ts","../../../../src/engine/content-validators.ts","../../../../src/engine/pipeline/validators.ts","../../../../src/engine/pipeline/verify-failures.ts","../../../../src/engine/pipeline/skip-conditions.ts","../../../../src/engine/pipeline/definitions.ts","../../../../src/engine/engine/pipeline-resolver.ts","../../../../src/engine/pipeline-events.ts","../../../../src/engine/stage-prompts.ts","../../../../src/engine/agent/constants.ts","../../../../src/engine/agent/file-watcher.ts","../../../../src/engine/agent/log-parser.ts","../../../../src/engine/agent/session.ts","../../../../src/engine/agent-runner.ts","../../../../src/engine/chat-history.ts","../../../../src/engine/handlers/agent-handler.ts","../../../../src/engine/config/project-config.ts","../../../../src/engine/scripted-stages.ts","../../../../src/engine/handlers/scripted-handler.ts","../../../../src/engine/handlers/git-handler.ts","../../../../src/engine/clarify-workflow.ts","../../../../src/engine/handlers/gate-handler.ts","../../../../src/engine/handlers/handler.ts","../../../../src/engine/pipeline/post-actions/validate-task-json.ts","../../../../src/engine/pipeline/post-actions/classification.ts","../../../../src/engine/pipeline/post-actions/promoted-stub.ts","../../../../src/engine/pipeline/post-actions/resolve-profile.ts","../../../../src/engine/pipeline/post-actions/gate.ts","../../../../src/engine/pipeline/post-actions/commit.ts","../../../../src/engine/pipeline/error-classifier.ts","../../../../src/engine/pipeline/post-actions/quality.ts","../../../../src/engine/pipeline/post-actions/review.ts","../../../../src/engine/pipeline/post-actions/validators.ts","../../../../src/engine/pipeline/post-actions/knowledge-base.ts","../../../../src/engine/pipeline/post-actions/index.ts","../../../../src/engine/pipeline/observer/observer.ts","../../../../src/engine/engine/state-machine.ts","../../../../src/engine/task-setup.ts","../../../../src/engine/modes/spec.ts","../../../../src/engine/modes/impl.ts","../../../../src/engine/modes/full.ts","../../../../src/engine/brain-health.ts","../../../../src/engine/brain-client.ts","../../../../src/engine/architect-brain.ts","../../../../src/engine/review-brain.ts","../../../../src/engine/modes/brain-full.ts","../../../../src/engine/rerun-utils.ts","../../../../src/engine/modes/rerun.ts","../../../../src/engine/modes/fix.ts","../../../../src/engine/modes/status.ts","../../../../src/engine/modes/design-system.ts","../../../../src/engine/modes/index.ts","../../../../src/engine/entry.ts","../../../../src/engine/parse-safety.ts","../../../../src/engine/parse-inputs.ts","../../../../src/engine/checkout-task-branch.ts","../../src/bin/cli.ts"],"sourcesContent":["/**\n * @fileType utility\n * @domain kody-pipeline\n * @pattern env-validation\n * @ai-summary Centralized environment variable validation for Kody pipeline using znv\n */\n\nimport { parseEnv, z } from 'znv'\n\n// Lazy-loaded env to avoid validation at import time in tests\nlet _env: EnvSchema | null = null\n\ninterface EnvSchema {\n // GitHub CI context\n GITHUB_ACTIONS?: string\n GITHUB_REPOSITORY?: string\n GITHUB_EVENT_NAME?: string\n GITHUB_OUTPUT?: string\n\n // Auth tokens\n GH_TOKEN?: string\n GH_PAT?: string\n\n // Pipeline overrides\n TASK_ID?: string\n MODE?: string\n DRY_RUN?: string\n FEEDBACK?: string\n FROM_STAGE?: string\n CLARIFY?: string\n ISSUE_NUMBER?: string\n TRIGGER_TYPE?: string\n RUN_ID?: string\n RUN_URL?: string\n VERSION?: string\n COMPLEXITY?: string\n COMMENT_BODY?: string\n\n // Dispatch inputs\n DISPATCH_TASK_ID?: string\n DISPATCH_MODE?: string\n DISPATCH_CLARIFY?: string\n DISPATCH_DRY_RUN?: string\n DISPATCH_FROM_STAGE?: string\n DISPATCH_FEEDBACK?: string\n DISPATCH_RUNNER?: string\n DISPATCH_VERSION?: string\n IS_PULL_REQUEST?: string\n\n // Safety\n SAFETY_VALID?: string\n SAFETY_REASON?: string\n AUTHOR?: string\n ASSOCIATION?: string\n\n // Git config\n GIT_USER_EMAIL?: string\n GIT_USER_NAME?: string\n\n // Logging\n LOG_LEVEL?: string\n NODE_ENV?: string\n DEBUG?: string\n\n // Pipeline versioning\n KODY_DEFAULT_VERSION?: string\n}\n\nfunction createEnv(): EnvSchema {\n return parseEnv(process.env, {\n // GitHub CI context\n GITHUB_ACTIONS: z.string().optional(),\n GITHUB_REPOSITORY: z.string().optional(),\n GITHUB_EVENT_NAME: z.string().optional(),\n GITHUB_OUTPUT: z.string().optional(),\n\n // Auth tokens\n GH_TOKEN: z.string().optional(),\n GH_PAT: z.string().optional(),\n\n // Pipeline overrides\n TASK_ID: z.string().optional(),\n MODE: z.string().optional(),\n DRY_RUN: z.string().optional(),\n FEEDBACK: z.string().optional(),\n FROM_STAGE: z.string().optional(),\n CLARIFY: z.string().optional(),\n ISSUE_NUMBER: z.string().optional(),\n TRIGGER_TYPE: z.string().optional(),\n RUN_ID: z.string().optional(),\n RUN_URL: z.string().optional(),\n VERSION: z.string().optional(),\n COMPLEXITY: z.string().optional(),\n COMMENT_BODY: z.string().optional(),\n\n // Dispatch inputs\n DISPATCH_TASK_ID: z.string().optional(),\n DISPATCH_MODE: z.string().optional(),\n DISPATCH_CLARIFY: z.string().optional(),\n DISPATCH_DRY_RUN: z.string().optional(),\n DISPATCH_FROM_STAGE: z.string().optional(),\n DISPATCH_FEEDBACK: z.string().optional(),\n DISPATCH_RUNNER: z.string().optional(),\n DISPATCH_VERSION: z.string().optional(),\n IS_PULL_REQUEST: z.string().optional(),\n\n // Safety\n SAFETY_VALID: z.string().optional(),\n SAFETY_REASON: z.string().optional(),\n AUTHOR: z.string().optional(),\n ASSOCIATION: z.string().optional(),\n\n // Git config\n GIT_USER_EMAIL: z.string().optional(),\n GIT_USER_NAME: z.string().optional(),\n\n // Logging\n // Note: Using string() without enum to avoid znv issues with optional + default\n // Values are validated against allowed options in getEnv()\n LOG_LEVEL: z.string().optional(),\n NODE_ENV: z.string().optional(),\n DEBUG: z.string().optional(),\n\n // Pipeline versioning\n KODY_DEFAULT_VERSION: z.string().optional(),\n }) as EnvSchema\n}\n\n/**\n * Get validated environment variables.\n * Uses lazy initialization to avoid validation failures during test setup.\n */\nexport function getEnv(): EnvSchema {\n if (!_env) {\n const env = createEnv()\n // Validate and set defaults manually\n const validLogLevels = ['debug', 'info', 'warn', 'error', 'silent']\n if (!env.LOG_LEVEL || !validLogLevels.includes(env.LOG_LEVEL)) {\n env.LOG_LEVEL = 'info'\n }\n _env = env\n }\n return _env\n}\n\n/**\n * Reset env cache (for testing)\n */\nexport function resetEnv() {\n _env = null\n}\n","/**\n * @fileType utility\n * @domain ci | kody | observability\n * @pattern structured-logging\n * @ai-summary Structured logging helpers with stage context for the Kody pipeline\n */\n\nimport pino from 'pino'\n\nimport { getEnv } from './env'\n\n// Lazy-initialize pino logger to avoid validation at import time\nlet _logger: ReturnType<typeof pino> | null = null\n\nfunction getPinoLogger() {\n if (!_logger) {\n const env = getEnv()\n const isCI = !!env.GITHUB_ACTIONS\n\n _logger = pino({\n level: env.LOG_LEVEL || 'info',\n transport: {\n target: 'pino-pretty',\n options: {\n colorize: !isCI,\n translateTime: 'SYS:HH:MM:ss',\n ignore: 'pid,hostname',\n },\n },\n })\n }\n return _logger\n}\n\n/**\n * Get the root pino logger instance\n */\nexport function getRootLogger() {\n return getPinoLogger()\n}\n\n/**\n * Create a child logger scoped to a specific pipeline stage.\n */\nexport function createStageLogger(stage: string, taskId?: string) {\n return getPinoLogger().child({ stage, ...(taskId && { taskId }) })\n}\n\n// Re-export pino logger for backward compatibility\nexport const logger = getPinoLogger()\nexport default logger\n\n// ============================================================================\n// CI Log Grouping (GitHub Actions)\n// ============================================================================\n\n/**\n * Emit a GitHub Actions collapsible group header.\n * No-op when not running in CI.\n */\nexport function ciGroup(title: string): void {\n if (process.env.GITHUB_ACTIONS) {\n process.stdout.write(`::group::${title}\\n`)\n }\n}\n\n/**\n * Emit a GitHub Actions collapsible group footer.\n * No-op when not running in CI.\n */\nexport function ciGroupEnd(): void {\n if (process.env.GITHUB_ACTIONS) {\n process.stdout.write('::endgroup::\\n')\n }\n}\n","/**\n * @fileType configuration\n * @domain kody | pipeline\n * @pattern stage-registry\n * @ai-summary Single source of truth for all pipeline stage metadata, types, and order arrays\n */\n\nimport ms from \"ms\";\n\n// ============================================================================\n// Stage Names — the canonical list\n// ============================================================================\n\n/**\n * All valid stage names in the Kody pipeline.\n *\n * Excluded:\n * - 'spec' — merged into 'gap' months ago (ghost stage)\n * - 'autofix' — not a real pipeline stage; it's a sub-behavior of build feedback loops\n */\nexport const STAGE_NAMES = [\n \"taskify\",\n \"gap\",\n \"clarify\",\n \"architect\",\n \"plan-gap\",\n \"test\",\n \"build\",\n \"commit\",\n \"review\",\n \"fix\",\n \"verify\",\n \"docs\",\n \"pr\",\n] as const;\n\nexport type StageName = (typeof STAGE_NAMES)[number];\n\n/**\n * Named constant object for stage names — provides compile-time typo detection\n * and single-point rename capability. Use STAGES.BUILD instead of 'build' in new code.\n */\nexport const STAGES = {\n TASKIFY: \"taskify\",\n GAP: \"gap\",\n CLARIFY: \"clarify\",\n ARCHITECT: \"architect\",\n PLAN_GAP: \"plan-gap\",\n TEST: \"test\",\n BUILD: \"build\",\n COMMIT: \"commit\",\n REVIEW: \"review\",\n FIX: \"fix\",\n VERIFY: \"verify\",\n DOCS: \"docs\",\n PR: \"pr\",\n} as const satisfies Record<string, StageName>;\n\n// ============================================================================\n// Stage Metadata\n// ============================================================================\n\nexport interface StageMetadata {\n /** Expected output file name (e.g., 'task.json', 'plan.md') */\n outputFile: string;\n /** Timeout in milliseconds */\n timeout: number;\n /** Minimum complexity score to run (0 = always runs) */\n complexityThreshold: number;\n /** Files the stage reads for context */\n contextFiles: string[];\n /** Handler dispatch type */\n type: \"agent\" | \"scripted\" | \"git\" | \"gate\";\n}\n\n/**\n * The stage registry — typed as Record<StageName, StageMetadata>.\n * Adding/removing from STAGE_NAMES without updating this record causes a compile error.\n */\nexport const STAGE_REGISTRY: Record<StageName, StageMetadata> = {\n taskify: {\n outputFile: \"task.json\",\n timeout: ms(\"10m\"),\n complexityThreshold: 0,\n contextFiles: [\"task.md\"],\n type: \"agent\",\n },\n gap: {\n outputFile: \"gap.md\",\n timeout: ms(\"15m\"),\n complexityThreshold: 35,\n contextFiles: [\"task.md\", \"task.json\"],\n type: \"agent\",\n },\n clarify: {\n outputFile: \"questions.md\",\n timeout: ms(\"10m\"),\n complexityThreshold: 60,\n contextFiles: [\"task.md\", \"spec.md\"],\n type: \"agent\",\n },\n architect: {\n outputFile: \"plan.md\",\n timeout: ms(\"30m\"),\n complexityThreshold: 10,\n contextFiles: [\n \"spec.md\",\n \"clarified.md\",\n \"rerun-feedback.md\",\n \"prev-run/plan.md\",\n \"prev-run/build.md\",\n \"prev-run/review.md\",\n ],\n type: \"agent\",\n },\n \"plan-gap\": {\n outputFile: \"plan-gap.md\",\n timeout: ms(\"15m\"),\n complexityThreshold: 50,\n contextFiles: [\"spec.md\", \"plan.md\", \"task.json\"],\n type: \"agent\",\n },\n test: {\n outputFile: \"test.md\",\n timeout: ms(\"40m\"),\n complexityThreshold: 0,\n contextFiles: [\"spec.md\", \"clarified.md\", \"plan.md\", \"task.json\"],\n type: \"agent\",\n },\n build: {\n outputFile: \"build.md\",\n timeout: ms(\"60m\"),\n complexityThreshold: 0,\n contextFiles: [\n \"spec.md\",\n \"clarified.md\",\n \"plan.md\",\n \"plan-gap.md\",\n \"context.md\",\n \"rerun-feedback.md\",\n \"build-errors.md\",\n \"review.md\",\n \"prev-run/build.md\",\n \"prev-run/review.md\",\n ],\n type: \"agent\",\n },\n commit: {\n outputFile: \"commit.md\",\n timeout: ms(\"5m\"),\n complexityThreshold: 0,\n contextFiles: [\"task.json\"],\n type: \"git\",\n },\n review: {\n outputFile: \"review.md\",\n timeout: ms(\"15m\"),\n complexityThreshold: 30,\n contextFiles: [\n \"review.md\",\n \"build.md\",\n \"plan.md\",\n \"context.md\",\n \"spec.md\",\n \"clarified.md\",\n ],\n type: \"agent\",\n },\n fix: {\n outputFile: \"fix.md\",\n timeout: ms(\"45m\"), // Increased from 30m — fixes often need more time than original build\n complexityThreshold: 0,\n contextFiles: [\n \"verify-failures.md\",\n \"review.md\",\n \"rerun-feedback.md\",\n \"fix-summary.md\",\n \"build.md\",\n \"plan.md\",\n \"context.md\",\n \"spec.md\",\n \"clarified.md\",\n \"prev-run/build.md\",\n ],\n type: \"agent\",\n },\n verify: {\n outputFile: \"verify.md\",\n timeout: ms(\"10m\"),\n complexityThreshold: 0,\n contextFiles: [],\n type: \"scripted\",\n },\n docs: {\n outputFile: \"docs.md\",\n timeout: ms(\"10m\"),\n complexityThreshold: 30,\n contextFiles: [\"build.md\", \"task.json\", \"review.md\", \"context.md\"],\n type: \"agent\",\n },\n pr: {\n outputFile: \"pr.md\",\n timeout: ms(\"5m\"),\n complexityThreshold: 0,\n contextFiles: [],\n type: \"git\",\n },\n};\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Get the output file name for a stage.\n * Falls back to `${stage}.md` for stages without a specific mapping.\n */\nexport function getStageOutputFile(stage: StageName): string {\n return STAGE_REGISTRY[stage].outputFile;\n}\n\n/**\n * Get the timeout for a stage in milliseconds.\n */\nexport function getStageTimeout(stage: StageName): number {\n return STAGE_REGISTRY[stage].timeout;\n}\n\n/**\n * Get the minimum complexity threshold for a stage.\n */\nexport function getStageComplexityThreshold(stage: StageName): number {\n return STAGE_REGISTRY[stage].complexityThreshold;\n}\n\n/**\n * Get the context files a stage needs to read.\n */\nexport function getStageContextFiles(stage: StageName): string[] {\n return STAGE_REGISTRY[stage].contextFiles;\n}\n\n/**\n * Runtime type guard — checks if a string is a valid StageName.\n */\nexport function isValidStageName(name: string): name is StageName {\n return (STAGE_NAMES as readonly string[]).includes(name);\n}\n\n/**\n * Assert that a string is a valid StageName, or throw.\n */\nexport function assertStageName(name: string): StageName {\n if (!isValidStageName(name)) {\n throw new Error(\n `Invalid stage name: '${name}'. Valid stages: ${STAGE_NAMES.join(\", \")}`,\n );\n }\n return name;\n}\n\n// ============================================================================\n// Resolve output file path on disk\n// ============================================================================\n\n/**\n * Build the full path to a stage's output file.\n * For stages not in the registry, falls back to `${stage}.md`.\n */\nexport function stageOutputFile(taskDir: string, stage: string): string {\n if (isValidStageName(stage)) {\n const filename = STAGE_REGISTRY[stage].outputFile;\n return `${taskDir}/${filename}`;\n }\n // Fallback for unknown stages (backward compat)\n return `${taskDir}/${stage}.md`;\n}\n\n// ============================================================================\n// Pipeline Order Arrays (typed)\n// ============================================================================\n\nexport type TypedPipelineStep = StageName | { parallel: StageName[] };\n\nexport const SPEC_ORDER_STANDARD: StageName[] = [\"taskify\", \"gap\", \"clarify\"];\nexport const SPEC_ORDER_LIGHTWEIGHT: StageName[] = [\"taskify\", \"clarify\"];\n\nexport const IMPL_ORDER_STANDARD: TypedPipelineStep[] = [\n \"architect\",\n \"plan-gap\",\n { parallel: [\"test\", \"build\"] },\n \"commit\",\n \"review\",\n \"fix\",\n // NOTE: No second 'commit' here — fix stage commits via its post-action\n // (commit-task-files with tracked+task). A duplicate 'commit' entry would be\n // skipped by resolveNextStep since state.stages['commit'] is already completed.\n \"verify\",\n \"pr\",\n];\n\nexport const IMPL_ORDER_LIGHTWEIGHT: TypedPipelineStep[] = [\n \"architect\",\n { parallel: [\"test\", \"build\"] },\n \"commit\",\n \"review\",\n \"fix\",\n \"verify\",\n \"pr\",\n];\n\n/** Turbo spec order — minimal: just taskify (no gap/clarify) */\nexport const SPEC_ORDER_TURBO: StageName[] = [\"taskify\"];\n\n/** Turbo impl order — minimal: build→commit→verify→pr (no architect/review/fix) */\nexport const IMPL_ORDER_TURBO: TypedPipelineStep[] = [\n \"build\",\n \"commit\",\n \"verify\",\n \"pr\",\n];\n\n/** Fix-only pipeline order for @kody fix mode */\nexport const FIX_ORDER: TypedPipelineStep[] = [\"review\", \"fix\", \"verify\", \"pr\"];\n\n/** Full pipeline order for fix mode — runs the full impl pipeline with taskify prepended */\nexport const FIX_FULL_ORDER: TypedPipelineStep[] = [\n \"taskify\",\n \"architect\",\n \"plan-gap\",\n { parallel: [\"test\", \"build\"] },\n \"commit\",\n \"review\",\n \"fix\",\n \"verify\",\n \"pr\",\n];\n\n// ============================================================================\n// Pipeline Utility Functions\n// ============================================================================\n\n/**\n * Flatten a typed pipeline step to its constituent stage names.\n */\nexport function flattenTypedStep(step: TypedPipelineStep): StageName[] {\n if (typeof step === \"string\") return [step];\n return step.parallel;\n}\n\n/**\n * Flatten an entire typed pipeline to a flat list of stage names.\n */\nexport function flattenTypedPipeline(steps: TypedPipelineStep[]): StageName[] {\n return steps.flatMap(flattenTypedStep);\n}\n\n/**\n * Spec-only stages (don't produce code).\n */\nexport const SPEC_STAGES: StageName[] = [\"taskify\", \"gap\", \"clarify\"];\n\n/**\n * Scripted stages that run directly without an LLM agent.\n */\nexport const SCRIPTED_STAGES: StageName[] = [\"verify\", \"commit\", \"pr\"];\n","/**\n * @fileType utility\n * @domain kody | validation\n * @pattern shared-validation\n * @ai-summary Shared validation constants and type guards — leaf dependency with no kody imports\n */\n\nimport { STAGE_NAMES } from './stages/registry'\n\nexport const VALID_MODES = [\n 'spec',\n 'impl',\n 'rerun',\n 'fix',\n 'full',\n 'status',\n 'design-system',\n] as const\n\nexport const VALID_STAGES = [...STAGE_NAMES, 'autofix' as const]\n\nexport function isValidMode(mode: string): mode is (typeof VALID_MODES)[number] {\n return (VALID_MODES as readonly string[]).includes(mode)\n}\n\nexport function isValidStage(stage: string): stage is (typeof VALID_STAGES)[number] {\n return (VALID_STAGES as readonly string[]).includes(stage)\n}\n\nexport function validateTaskId(taskId: string): boolean {\n return /^\\d{6}[a-zA-Z0-9-]+$/.test(taskId)\n}\n","/**\n * @fileType schema\n * @domain kody | pipeline\n * @pattern task-schema\n * @ai-summary Task definition types, Zod schemas, and validation for the Kody pipeline\n */\n\nimport { z } from 'zod'\n\nexport const VALID_TASK_TYPES = [\n 'spec_only',\n 'implement_feature',\n 'fix_bug',\n 'refactor',\n 'docs',\n 'ops',\n 'research',\n] as const\n\nexport const VALID_PIPELINES = ['spec_only', 'spec_execute_verify'] as const\nconst VALID_RISK_LEVELS = ['low', 'medium', 'high'] as const\nconst VALID_DOMAINS = ['backend', 'frontend', 'infra', 'data', 'llm', 'devops', 'product'] as const\nexport const VALID_PIPELINE_PROFILES = ['lightweight', 'standard', 'turbo'] as const\n\nexport type TaskType = (typeof VALID_TASK_TYPES)[number]\nexport type Pipeline = (typeof VALID_PIPELINES)[number]\nexport type PipelineProfile = (typeof VALID_PIPELINE_PROFILES)[number]\n\nexport const COMPLEXITY_MIN = 1\nexport const COMPLEXITY_MAX = 100\n\n// --- Input quality levels for smart stage skipping ---\nexport const VALID_INPUT_QUALITY_LEVELS = [\n 'raw_idea',\n 'good_spec',\n 'detailed_plan',\n 'spec_and_plan',\n] as const\n\n// Stages that cannot be skipped (gap analysis always runs)\nexport const NON_SKIPPABLE_STAGES = ['gap', 'plan-gap', 'build', 'commit', 'verify', 'pr'] as const\n\n// Stages that CAN be skipped when input quality is high\nexport const SKIPPABLE_STAGES = ['architect'] as const\n\n// NOTE: STAGE_COMPLEXITY_THRESHOLDS moved to stages/registry.ts\n// Use getStageComplexityThreshold() from registry instead.\n\nexport interface InputQuality {\n level: (typeof VALID_INPUT_QUALITY_LEVELS)[number]\n skip_stages: string[]\n reasoning: string\n}\n\nexport interface TaskDefinition {\n task_type: TaskType\n pipeline: Pipeline\n risk_level: (typeof VALID_RISK_LEVELS)[number]\n confidence: number\n primary_domain: (typeof VALID_DOMAINS)[number]\n scope: string[]\n missing_inputs: Array<{ field: string; question: string }>\n assumptions: string[]\n /** Questions for the reviewer to answer before approving. Derived from assumptions and task ambiguity. */\n review_questions?: string[]\n input_quality?: InputQuality\n pipeline_profile?: (typeof VALID_PIPELINE_PROFILES)[number]\n /** Complexity score (1-100) — determines which pipeline stages run */\n complexity?: number\n /** Brief explanation of complexity scoring breakdown */\n complexity_reasoning?: string\n}\n\n// Pipeline consistency: task_type → allowed pipeline values\nexport const PIPELINE_MAP: Record<TaskType, Pipeline> = {\n spec_only: 'spec_only',\n research: 'spec_only',\n docs: 'spec_only',\n implement_feature: 'spec_execute_verify',\n fix_bug: 'spec_execute_verify',\n refactor: 'spec_execute_verify',\n ops: 'spec_execute_verify',\n}\n\ninterface ValidationResult {\n valid: boolean\n errors: string[]\n}\n\n// --- Task type alias mapping (common LLM mistakes) ---\n\nconst TASK_TYPE_ALIASES: Record<string, TaskType> = {\n feature: 'implement_feature',\n new_feature: 'implement_feature',\n add_feature: 'implement_feature',\n bug: 'fix_bug',\n bugfix: 'fix_bug',\n bug_fix: 'fix_bug',\n hotfix: 'fix_bug',\n refactoring: 'refactor',\n cleanup: 'refactor',\n documentation: 'docs',\n doc: 'docs',\n operations: 'ops',\n devops: 'ops',\n infra: 'ops',\n spec: 'spec_only',\n research_only: 'research',\n investigate: 'research',\n}\n\n// --- Confidence string-to-number mapping ---\n\nexport const CONFIDENCE_MAP: Record<string, number> = {\n high: 0.9,\n medium: 0.7,\n low: 0.5,\n very_high: 0.95,\n very_low: 0.3,\n}\n\n// --- Zod Schema for TaskDefinition ---\n\n/**\n * Zod schema that validates and normalizes a raw task definition.\n * Uses .superRefine() for validation and .transform() for normalization.\n */\nexport const TaskDefinitionSchema = z\n .object({\n task_type: z.string().optional(),\n pipeline: z.string().optional(),\n risk_level: z.string().optional(),\n confidence: z.union([z.string(), z.number()]).optional(),\n primary_domain: z.string().optional(),\n scope: z.union([z.string(), z.array(z.string())]).optional(),\n missing_inputs: z.any().optional(),\n assumptions: z.any().optional(),\n review_questions: z.any().optional(),\n input_quality: z.any().optional(),\n pipeline_profile: z.string().optional(),\n complexity: z.union([z.string(), z.number()]).optional(),\n complexity_reasoning: z.any().optional(),\n })\n .superRefine((raw, ctx) => {\n const data = raw as Record<string, unknown>\n\n // Validate pipeline_profile - add issue on invalid values\n if (data.pipeline_profile !== undefined) {\n if (\n typeof data.pipeline_profile !== 'string' ||\n !VALID_PIPELINE_PROFILES.includes(data.pipeline_profile as PipelineProfile)\n ) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Invalid pipeline_profile: \"${data.pipeline_profile}\". Must be one of: ${VALID_PIPELINE_PROFILES.join(', ')}`,\n })\n }\n }\n\n // Validate input_quality.skip_stages - add issue for non-skippable stages\n if (\n data.input_quality !== undefined &&\n typeof data.input_quality === 'object' &&\n data.input_quality !== null\n ) {\n const iq = data.input_quality as Record<string, unknown>\n\n if (Array.isArray(iq.skip_stages)) {\n for (const stage of iq.skip_stages) {\n if (typeof stage !== 'string') {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Invalid input_quality.skip_stages: each stage must be a string`,\n })\n break\n }\n if (NON_SKIPPABLE_STAGES.includes(stage as (typeof NON_SKIPPABLE_STAGES)[number])) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Cannot skip stage \"${stage}\" - gap and plan-gap must always run for quality assurance`,\n })\n }\n }\n }\n }\n })\n .transform((raw): TaskDefinition => {\n const data = raw as Record<string, unknown>\n\n // 1. Normalize task_type aliases\n let normalizedTaskType: TaskType | undefined\n if (typeof data.task_type === 'string') {\n const alias = TASK_TYPE_ALIASES[data.task_type.toLowerCase()]\n if (alias) {\n normalizedTaskType = alias\n } else if (VALID_TASK_TYPES.includes(data.task_type as TaskType)) {\n normalizedTaskType = data.task_type as TaskType\n } else {\n // Invalid task_type that's not an alias - will be caught in validation\n normalizedTaskType = data.task_type as TaskType\n }\n }\n\n // 2. Always derive pipeline from task_type\n let normalizedPipeline: Pipeline | undefined\n if (normalizedTaskType && PIPELINE_MAP[normalizedTaskType]) {\n normalizedPipeline = PIPELINE_MAP[normalizedTaskType]\n }\n\n // 3. Convert string confidence to number\n let normalizedConfidence: number | undefined\n if (typeof data.confidence === 'string') {\n const mapped = CONFIDENCE_MAP[data.confidence.toLowerCase()]\n if (mapped !== undefined) {\n normalizedConfidence = mapped\n } else {\n // Try parsing as number string (e.g., \"0.9\")\n const parsed = parseFloat(data.confidence)\n if (!isNaN(parsed) && parsed >= 0 && parsed <= 1) {\n normalizedConfidence = parsed\n }\n }\n } else if (typeof data.confidence === 'number') {\n normalizedConfidence = data.confidence\n }\n\n // 4. Normalize scope (wrap string in array)\n let normalizedScope: string[] = []\n if (typeof data.scope === 'string') {\n normalizedScope = [data.scope]\n } else if (Array.isArray(data.scope)) {\n normalizedScope = data.scope\n }\n\n // 5. Default missing arrays\n const missingInputs = Array.isArray(data.missing_inputs)\n ? data.missing_inputs\n : ([] as Array<{ field: string; question: string }>)\n const assumptions = Array.isArray(data.assumptions) ? data.assumptions : []\n const reviewQuestions = Array.isArray(data.review_questions) ? data.review_questions : []\n\n // 6. Normalize complexity\n let normalizedComplexity: number | undefined\n if (data.complexity !== undefined) {\n if (typeof data.complexity === 'string') {\n const parsed = parseInt(data.complexity, 10)\n if (!isNaN(parsed)) {\n normalizedComplexity = Math.max(\n COMPLEXITY_MIN,\n Math.min(COMPLEXITY_MAX, Math.round(parsed)),\n )\n }\n } else if (typeof data.complexity === 'number') {\n normalizedComplexity = Math.max(\n COMPLEXITY_MIN,\n Math.min(COMPLEXITY_MAX, Math.round(data.complexity)),\n )\n }\n }\n\n const complexityReasoning =\n typeof data.complexity_reasoning === 'string'\n ? data.complexity_reasoning\n : typeof data.complexity_reasoning !== 'undefined'\n ? String(data.complexity_reasoning)\n : undefined\n\n // 7. Normalize pipeline_profile (only if valid - validation already done in superRefine)\n let normalizedPipelineProfile: PipelineProfile | undefined\n if (\n data.pipeline_profile !== undefined &&\n typeof data.pipeline_profile === 'string' &&\n VALID_PIPELINE_PROFILES.includes(data.pipeline_profile as PipelineProfile)\n ) {\n normalizedPipelineProfile = data.pipeline_profile as PipelineProfile\n }\n\n // 8. Normalize input_quality\n let normalizedInputQuality: InputQuality | undefined\n if (\n data.input_quality !== undefined &&\n typeof data.input_quality === 'object' &&\n data.input_quality !== null\n ) {\n const iq = data.input_quality as Record<string, unknown>\n\n // Validate level\n let level: InputQuality['level'] = 'raw_idea'\n if (\n typeof iq.level === 'string' &&\n VALID_INPUT_QUALITY_LEVELS.includes(iq.level as InputQuality['level'])\n ) {\n level = iq.level as InputQuality['level']\n }\n\n // Normalize skip_stages (filter out non-skippable - validation done in superRefine)\n const skipStages: string[] = []\n if (Array.isArray(iq.skip_stages)) {\n for (const stage of iq.skip_stages) {\n if (\n typeof stage === 'string' &&\n !NON_SKIPPABLE_STAGES.includes(stage as (typeof NON_SKIPPABLE_STAGES)[number])\n ) {\n skipStages.push(stage)\n }\n }\n }\n\n const reasoning = typeof iq.reasoning === 'string' ? iq.reasoning : ''\n\n normalizedInputQuality = { level, skip_stages: skipStages, reasoning }\n } else {\n // Default input_quality\n normalizedInputQuality = {\n level: 'raw_idea',\n skip_stages: [],\n reasoning: '',\n }\n }\n\n // Build the result object (required fields with defaults for missing)\n const result: TaskDefinition = {\n task_type: normalizedTaskType || 'implement_feature',\n pipeline: normalizedPipeline || 'spec_execute_verify',\n risk_level: (data.risk_level as TaskDefinition['risk_level']) || 'medium',\n confidence: normalizedConfidence ?? 0.7,\n primary_domain: (data.primary_domain as TaskDefinition['primary_domain']) || 'backend',\n scope: normalizedScope,\n missing_inputs: missingInputs as Array<{ field: string; question: string }>,\n assumptions: assumptions as string[],\n review_questions: reviewQuestions as string[] | undefined,\n input_quality: normalizedInputQuality,\n pipeline_profile: normalizedPipelineProfile,\n complexity: normalizedComplexity,\n complexity_reasoning: complexityReasoning,\n }\n\n return result\n })\n\n/**\n * Parse a raw task definition using Zod schema.\n * Throws descriptive errors on validation failure.\n */\nexport function parseTaskDefinition(raw: unknown): TaskDefinition {\n const result = TaskDefinitionSchema.safeParse(raw)\n\n if (!result.success) {\n const errors = result.error.issues.map((issue) => {\n const path = issue.path.join('.')\n return path ? `${path}: ${issue.message}` : issue.message\n })\n throw new Error(\n `TaskDefinition validation failed:\\n${errors.map((e) => ` • ${e}`).join('\\n')}`,\n )\n }\n\n return result.data\n}\n\n/**\n * Normalize a raw task.json object, fixing common LLM mistakes:\n * - Maps task_type aliases (e.g., \"feature\" → \"implement_feature\")\n * - Always derives pipeline from task_type (agent should never set this)\n * - Converts string confidence to number (e.g., \"high\" → 0.9)\n * - Wraps scope in array if it's a string\n * - Defaults missing arrays\n */\nexport function normalizeTask(raw: Record<string, unknown>): Record<string, unknown> {\n const data = { ...raw }\n\n // 1. Normalize task_type aliases\n if (typeof data.task_type === 'string') {\n const alias = TASK_TYPE_ALIASES[data.task_type.toLowerCase()]\n if (alias) {\n data.task_type = alias\n }\n }\n\n // 2. Always derive pipeline from task_type (never trust agent's value)\n if (VALID_TASK_TYPES.includes(data.task_type as TaskType)) {\n data.pipeline = PIPELINE_MAP[data.task_type as TaskType]\n }\n\n // 3. Convert string confidence to number\n if (typeof data.confidence === 'string') {\n const mapped = CONFIDENCE_MAP[data.confidence.toLowerCase()]\n if (mapped !== undefined) {\n data.confidence = mapped\n } else {\n // Try parsing as number string (e.g., \"0.9\")\n const parsed = parseFloat(data.confidence)\n if (!isNaN(parsed) && parsed >= 0 && parsed <= 1) {\n data.confidence = parsed\n }\n }\n }\n\n // 4. Wrap scope in array if string\n if (typeof data.scope === 'string') {\n data.scope = [data.scope]\n }\n\n // 5. Default missing arrays\n if (!Array.isArray(data.missing_inputs)) {\n data.missing_inputs = []\n }\n if (!Array.isArray(data.assumptions)) {\n data.assumptions = []\n }\n if (!Array.isArray(data.review_questions)) {\n data.review_questions = []\n }\n\n // 6. Normalize complexity score\n if (data.complexity !== undefined) {\n if (typeof data.complexity === 'string') {\n const parsed = parseInt(data.complexity as string, 10)\n if (!isNaN(parsed)) {\n data.complexity = parsed\n }\n }\n // Clamp to valid range\n if (typeof data.complexity === 'number') {\n data.complexity = Math.max(\n COMPLEXITY_MIN,\n Math.min(COMPLEXITY_MAX, Math.round(data.complexity)),\n )\n }\n }\n if (typeof data.complexity_reasoning !== 'string' && data.complexity_reasoning !== undefined) {\n data.complexity_reasoning = String(data.complexity_reasoning)\n }\n\n // 7. Default input_quality if missing (for backward compatibility)\n if (!data.input_quality || typeof data.input_quality !== 'object') {\n data.input_quality = {\n level: 'raw_idea',\n skip_stages: [],\n reasoning: '',\n }\n } else {\n // Ensure input_quality has required fields\n const iq = data.input_quality as Record<string, unknown>\n if (!iq.level) {\n iq.level = 'raw_idea'\n }\n if (!Array.isArray(iq.skip_stages)) {\n iq.skip_stages = []\n }\n if (typeof iq.reasoning !== 'string') {\n iq.reasoning = ''\n }\n }\n\n return data\n}\n\nexport function validateTask(raw: unknown): ValidationResult {\n const errors: string[] = []\n\n if (typeof raw !== 'object' || raw === null) {\n return { valid: false, errors: ['task.json is not a JSON object'] }\n }\n\n const data = raw as Record<string, unknown>\n\n // Required fields\n if (!VALID_TASK_TYPES.includes(data.task_type as TaskType)) {\n errors.push(\n `Invalid task_type: \"${data.task_type}\". Must be one of: ${VALID_TASK_TYPES.join(', ')}`,\n )\n }\n\n if (!VALID_PIPELINES.includes(data.pipeline as Pipeline)) {\n errors.push(\n `Invalid pipeline: \"${data.pipeline}\". Must be one of: ${VALID_PIPELINES.join(', ')}`,\n )\n }\n\n // Validate optional pipeline_profile\n if (data.pipeline_profile !== undefined) {\n if (!VALID_PIPELINE_PROFILES.includes(data.pipeline_profile as PipelineProfile)) {\n errors.push(\n `Invalid pipeline_profile: \"${data.pipeline_profile}\". Must be one of: ${VALID_PIPELINE_PROFILES.join(', ')}`,\n )\n }\n }\n\n if (!VALID_RISK_LEVELS.includes(data.risk_level as (typeof VALID_RISK_LEVELS)[number])) {\n errors.push(\n `Invalid risk_level: \"${data.risk_level}\". Must be one of: ${VALID_RISK_LEVELS.join(', ')}`,\n )\n }\n\n if (typeof data.confidence !== 'number' || data.confidence < 0 || data.confidence > 1) {\n errors.push(`Invalid confidence: \"${data.confidence}\". Must be a number between 0.0 and 1.0`)\n }\n\n if (!VALID_DOMAINS.includes(data.primary_domain as (typeof VALID_DOMAINS)[number])) {\n errors.push(\n `Invalid primary_domain: \"${data.primary_domain}\". Must be one of: ${VALID_DOMAINS.join(', ')}`,\n )\n }\n\n if (!Array.isArray(data.scope)) {\n errors.push(`Invalid scope: must be an array of strings`)\n }\n\n if (!Array.isArray(data.missing_inputs)) {\n errors.push(`Invalid missing_inputs: must be an array`)\n } else {\n for (const item of data.missing_inputs) {\n const entry = item as Record<string, unknown>\n if (typeof entry.field !== 'string' || typeof entry.question !== 'string') {\n errors.push(`Invalid missing_inputs entry: each must have \"field\" and \"question\" strings`)\n break\n }\n }\n }\n\n if (!Array.isArray(data.assumptions)) {\n errors.push(`Invalid assumptions: must be an array of strings`)\n }\n\n // Validate review_questions if present\n if (data.review_questions !== undefined) {\n if (!Array.isArray(data.review_questions)) {\n errors.push(`Invalid review_questions: must be an array of strings`)\n } else {\n for (const q of data.review_questions) {\n if (typeof q !== 'string') {\n errors.push(`Invalid review_questions entry: must be an array of strings`)\n break\n }\n }\n }\n }\n\n // Validate input_quality if present\n if (data.input_quality !== undefined) {\n if (typeof data.input_quality !== 'object' || data.input_quality === null) {\n errors.push(`Invalid input_quality: must be an object`)\n } else {\n const iq = data.input_quality as Record<string, unknown>\n // Validate level\n if (\n !VALID_INPUT_QUALITY_LEVELS.includes(\n iq.level as (typeof VALID_INPUT_QUALITY_LEVELS)[number],\n )\n ) {\n errors.push(\n `Invalid input_quality.level: \"${iq.level}\". Must be one of: ${VALID_INPUT_QUALITY_LEVELS.join(', ')}`,\n )\n }\n // Validate skip_stages\n if (!Array.isArray(iq.skip_stages)) {\n errors.push(`Invalid input_quality.skip_stages: must be an array`)\n } else {\n for (const stage of iq.skip_stages) {\n if (typeof stage !== 'string') {\n errors.push(`Invalid input_quality.skip_stages: each stage must be a string`)\n break\n }\n // Check for non-skippable stages\n if (NON_SKIPPABLE_STAGES.includes(stage as (typeof NON_SKIPPABLE_STAGES)[number])) {\n errors.push(\n `Cannot skip stage \"${stage}\" - gap and plan-gap must always run for quality assurance`,\n )\n }\n // Check for unknown stages (optional warning, but we'll be strict)\n if (!SKIPPABLE_STAGES.includes(stage as (typeof SKIPPABLE_STAGES)[number])) {\n // Allow unknown stages but warn - this is informational, not an error\n }\n }\n }\n // Validate reasoning\n if (typeof iq.reasoning !== 'string') {\n errors.push(`Invalid input_quality.reasoning: must be a string`)\n }\n }\n }\n\n // Validate complexity if present\n if (data.complexity !== undefined) {\n if (typeof data.complexity !== 'number' || !Number.isInteger(data.complexity)) {\n errors.push(`Invalid complexity: \"${data.complexity}\". Must be an integer`)\n } else if (data.complexity < COMPLEXITY_MIN || data.complexity > COMPLEXITY_MAX) {\n errors.push(\n `Invalid complexity: ${data.complexity}. Must be between ${COMPLEXITY_MIN} and ${COMPLEXITY_MAX}`,\n )\n }\n }\n\n if (data.complexity_reasoning !== undefined && typeof data.complexity_reasoning !== 'string') {\n errors.push(`Invalid complexity_reasoning: must be a string`)\n }\n\n // Pipeline consistency check\n if (\n errors.length === 0 &&\n PIPELINE_MAP[data.task_type as TaskType] !== (data.pipeline as Pipeline)\n ) {\n errors.push(\n `Pipeline inconsistency: task_type \"${data.task_type}\" requires pipeline \"${PIPELINE_MAP[data.task_type as TaskType]}\", got \"${data.pipeline}\"`,\n )\n }\n\n return { valid: errors.length === 0, errors }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern complexity-scoring\n * @ai-summary Complexity scoring, tiers, control modes, and pipeline profile resolution\n */\n\nimport type { TaskDefinition, TaskType, PipelineProfile } from './task-schema'\nimport { VALID_PIPELINE_PROFILES } from './task-schema'\nimport { STAGE_NAMES, STAGE_REGISTRY, getStageComplexityThreshold } from '../stages/registry'\n\n/** Named complexity tiers for display/logging */\nexport type ComplexityTier = 'trivial' | 'simple' | 'moderate' | 'complex' | 'very_complex'\n\nexport function getComplexityTier(score: number): ComplexityTier {\n if (score < 10) return 'trivial'\n if (score < 20) return 'simple'\n if (score < 35) return 'moderate'\n if (score < 50) return 'complex'\n return 'very_complex'\n}\n\n/**\n * Get stages that would run for a given complexity score.\n * Useful for logging and debugging.\n */\nexport function getStagesForComplexity(score: number): string[] {\n return STAGE_NAMES.filter((stage) => score >= STAGE_REGISTRY[stage].complexityThreshold)\n}\n\n// --- Control mode: determines pipeline autonomy level ---\nexport type ControlMode = 'auto' | 'risk-gated' | 'hard-stop'\n\nexport const CONTROL_MODE_MAP: Record<string, ControlMode> = {\n low: 'auto',\n medium: 'risk-gated',\n high: 'hard-stop',\n}\n\n/**\n * Resolve the control mode for a task based on its risk level.\n * User can override with explicit flags (--auto, --gate, --hard-stop).\n */\nexport function resolveControlMode(taskDef: TaskDefinition, override?: ControlMode): ControlMode {\n // Explicit override always wins (from /kody --auto, --gate, --hard-stop)\n if (override) return override\n\n // Derive from risk_level\n return CONTROL_MODE_MAP[taskDef.risk_level] ?? 'auto'\n}\n\n/**\n * Lightweight tasks: simple fixes that skip heavyweight stages (gap, plan-gap)\n *\n * When complexity score is available, derives profile from it:\n * complexity < 35 → lightweight (below gap threshold)\n * complexity >= 35 → standard (gap and above stages enabled)\n */\nconst LIGHTWEIGHT_TASK_TYPES: TaskType[] = ['fix_bug', 'refactor', 'ops', 'implement_feature']\n\nexport function resolvePipelineProfile(taskDef: TaskDefinition): PipelineProfile {\n // Agent explicit override always wins\n if (taskDef.pipeline_profile && VALID_PIPELINE_PROFILES.includes(taskDef.pipeline_profile)) {\n return taskDef.pipeline_profile\n }\n\n // When complexity score is available, derive profile from it\n if (taskDef.complexity !== undefined) {\n // Threshold = gap complexity threshold (35) — below this is lightweight\n return taskDef.complexity < getStageComplexityThreshold('gap') ? 'lightweight' : 'standard'\n }\n\n // Fallback: legacy heuristic for tasks without complexity score\n if (taskDef.risk_level === 'low' && LIGHTWEIGHT_TASK_TYPES.includes(taskDef.task_type)) {\n return 'lightweight'\n }\n\n // Everything else gets the full standard pipeline\n return 'standard'\n}\n\n// Lightweight tasks: simple fixes that skip heavyweight stages\n// Note: implement_feature added for low-risk features (e.g., adding loading/error files)\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern task-io\n * @ai-summary Task file I/O — reads and normalizes task.json from disk\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { TaskDefinition } from './task-schema'\nimport { normalizeTask, validateTask } from './task-schema'\n\nexport function readTask(taskDir: string): TaskDefinition | null {\n const taskFile = path.join(taskDir, 'task.json')\n if (!fs.existsSync(taskFile)) {\n return null\n }\n\n const content = fs.readFileSync(taskFile, 'utf-8')\n\n let raw: unknown\n try {\n raw = JSON.parse(content)\n } catch {\n const preview = content.slice(0, 200).replace(/\\n/g, '\\\\n')\n throw new Error(\n `task.json is not valid JSON.\\n` +\n ` File: ${taskFile}\\n` +\n ` Preview: ${preview}\\n` +\n ` Common causes:\\n` +\n ` • Agent wrapped JSON in markdown code fences\\n` +\n ` • Trailing comma in JSON\\n` +\n ` • Agent wrote commentary outside the JSON object\\n` +\n ` Fix task.json and re-run, or delete it to re-classify:\\n` +\n ` rm ${taskFile}`,\n )\n }\n\n // Normalize common LLM mistakes before validation\n if (typeof raw === 'object' && raw !== null) {\n raw = normalizeTask(raw as Record<string, unknown>)\n\n // Write back normalized values so subsequent reads are consistent\n fs.writeFileSync(taskFile, JSON.stringify(raw, null, 2) + '\\n')\n }\n\n const result = validateTask(raw)\n\n if (!result.valid) {\n throw new Error(\n `task.json validation failed:\\n${result.errors.map((e) => ` • ${e}`).join('\\n')}`,\n )\n }\n\n return raw as TaskDefinition\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern pipeline-utils\n * @ai-summary Pipeline utility functions — stage output, dry-run, parallel stage helpers\n */\n\nimport * as fs from 'fs'\n\nimport { stageOutputFile } from './stages/registry'\n\n// Re-export everything from extracted modules for backward compatibility\nexport * from './pipeline/task-schema'\nexport * from './pipeline/complexity'\nexport { readTask } from './pipeline/task-io'\n\nexport { stageOutputFile } from './stages/registry'\n\n// --- Pipeline stage definitions ---\n\nexport const SPEC_ONLY_STAGES = ['gap', 'clarify']\n\n// --- Dry-run support ---\n\nconst DRY_RUN_OUTPUTS: Record<string, (taskId: string) => string> = {\n taskify: () =>\n JSON.stringify(\n {\n task_type: 'implement_feature',\n risk_level: 'medium',\n confidence: 0.9,\n primary_domain: 'backend',\n scope: ['[dry-run] Mock scope item'],\n missing_inputs: [],\n assumptions: ['[dry-run] Mock assumption'],\n review_questions: [],\n },\n null,\n 2,\n ),\n gap: (taskId) => `# Gap Analysis (dry-run)\\n\\nNo gaps identified for ${taskId}.\\n`,\n clarify: (taskId) => `# Questions (dry-run)\\n\\n1. Mock question for ${taskId}?\\n`,\n architect: (taskId) => `# Plan (dry-run)\\n\\nMock plan for ${taskId}.\\n`,\n build: (taskId) => `# Build (dry-run)\\n\\nMock build output for ${taskId}.\\n`,\n test: (taskId) => `# Test (dry-run)\\n\\nMock test output for ${taskId}.\\n`,\n verify: (taskId) => `# Verify (dry-run)\\n\\nResult: PASS\\n\\nMock verification for ${taskId}.\\n`,\n commit: (taskId) => `# Commit (dry-run)\n\nMock commit output for ${taskId}.\n`,\n autofix: (taskId) => `# Autofix (dry-run)\n\nNo errors to fix for ${taskId}.\n`,\n pr: (taskId) => `# PR (dry-run)\n\nMock PR output for ${taskId}.\n`,\n}\n\nexport function writeDryRunOutput(taskDir: string, stage: string, taskId: string): void {\n const outputFile = stageOutputFile(taskDir, stage)\n const generator = DRY_RUN_OUTPUTS[stage]\n const content = generator ? generator(taskId) : `# ${stage} (dry-run)\\n\\nMock output.\\n`\n fs.writeFileSync(outputFile, content)\n}\n\n// --- Parallel stage support ---\n\n/**\n * A pipeline stage is either a single stage name (string) or a parallel group.\n * Parallel groups run all contained stages concurrently.\n */\nexport type PipelineStage = string | { parallel: string[] }\n\n/**\n * Check if a pipeline stage is a parallel group\n */\nexport function isParallelStage(stage: PipelineStage): stage is { parallel: string[] } {\n return typeof stage === 'object' && 'parallel' in stage\n}\n\n/**\n * Flatten a pipeline stage definition to its constituent stage names.\n * For a string, returns [stage]. For parallel, returns all contained stages.\n */\nexport function flattenStage(stage: PipelineStage): string[] {\n if (isParallelStage(stage)) {\n return stage.parallel\n }\n return [stage]\n}\n\n/**\n * Flatten an entire pipeline definition to a flat list of stage names.\n */\nexport function flattenPipeline(stages: PipelineStage[]): string[] {\n return stages.flatMap(flattenStage)\n}\n\n// --- Pipeline stage definitions moved to stages/registry.ts ---\n// Use IMPL_ORDER_STANDARD, IMPL_ORDER_LIGHTWEIGHT, etc. from registry.\n","/**\n * @fileType utility\n * @domain kody | github\n * @pattern github-api\n * @ai-summary GitHub API helpers extracted from kody-utils for better modularity\n */\n\nimport { logger } from './logger'\nimport { getComplexityTier } from './pipeline-utils'\nimport { execFileSync } from 'child_process'\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst GH_API_TIMEOUT = 30_000 // 30 seconds max per gh CLI call\n\n// ============================================================================\n// Synchronous Sleep Helper\n// ============================================================================\n\n/**\n * Synchronous sleep using Atomics.wait — blocks thread without busy-looping.\n * Used for retry delays in synchronous fire-and-forget functions.\n */\nexport function syncSleep(ms: number): void {\n const buf = new SharedArrayBuffer(4)\n const arr = new Int32Array(buf)\n Atomics.wait(arr, 0, 0, ms)\n}\n\n// ============================================================================\n// GitHub API Functions\n// ============================================================================\n\n/**\n * Post a comment to an issue.\n * Uses GH_PAT when available so comments are posted under the PAT identity,\n * which allows them to trigger other workflows (e.g. supervisor.yml).\n * Comments posted with GITHUB_TOKEN do NOT trigger other workflows due to\n * GitHub Actions security restrictions.\n */\nexport function postComment(issueNumber: number, body: string): void {\n if (!issueNumber) return\n\n // Use GH_PAT if available so the comment triggers other workflows (supervisor)\n const ghToken = process.env.GH_PAT?.trim() || process.env.GH_TOKEN\n const env = ghToken ? { ...process.env, GH_TOKEN: ghToken } : process.env\n\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n execFileSync('gh', ['issue', 'comment', String(issueNumber), '--body-file', '-'], {\n input: body,\n stdio: ['pipe', 'inherit', 'inherit'],\n env,\n timeout: GH_API_TIMEOUT,\n })\n return // Success\n } catch (error) {\n if (attempt === 0) {\n logger.warn(\n { err: error },\n `postComment attempt 1 failed for issue ${issueNumber}, retrying...`,\n )\n // Brief synchronous delay before retry (2 seconds)\n syncSleep(2000)\n } else {\n logger.error(\n { err: error },\n `Failed to post comment to issue ${issueNumber} after 2 attempts`,\n )\n }\n }\n }\n}\n\n/**\n * Get issue body\n */\nexport function getIssueBody(issueNumber: number): string | null {\n if (!issueNumber) return null\n\n try {\n const output = execFileSync(\n 'gh',\n ['issue', 'view', String(issueNumber), '--json', 'body', '--jq', '.body'],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n return output.trim() || null\n } catch (error) {\n logger.error({ err: error }, `Failed to get issue body for #${issueNumber}:`)\n return null\n }\n}\n\n/**\n * Get full issue data (body and title)\n */\nexport function getIssue(issueNumber: number): { body: string | null; title: string | null } {\n if (!issueNumber) return { body: null, title: null }\n\n try {\n const output = execFileSync(\n 'gh',\n [\n 'issue',\n 'view',\n String(issueNumber),\n '--json',\n 'body,title',\n '--jq',\n '{body: .body, title: .title}',\n ],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n const data = JSON.parse(output)\n return {\n body: data.body?.trim() || null,\n title: data.title?.trim() || null,\n }\n } catch (error) {\n logger.error({ err: error }, `Failed to get issue #${issueNumber}:`)\n return { body: null, title: null }\n }\n}\n\n/**\n * Get issue title\n */\nexport function getIssueTitle(issueNumber: number): string | null {\n if (!issueNumber) return null\n\n try {\n const output = execFileSync(\n 'gh',\n ['issue', 'view', String(issueNumber), '--json', 'title', '--jq', '.title'],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n return output.trim() || null\n } catch (error) {\n logger.error({ err: error }, `Failed to get issue title for #${issueNumber}:`)\n return null\n }\n}\n\n/**\n * Edit an existing comment\n * R6: Rewrote to use stdin instead of temp files for atomicity\n */\nexport function editComment(commentId: string, body: string): void {\n if (!commentId) return\n\n // R6: Replace 'OWNER/REPO' fallback with early return\n const repo = process.env.GITHUB_REPOSITORY\n if (!repo) {\n logger.error('editComment: GITHUB_REPOSITORY not set, skipping')\n return\n }\n\n try {\n // Use --input - to pipe body via stdin (atomic, no temp file)\n execFileSync(\n 'gh',\n ['api', `repos/${repo}/issues/comments/${commentId}`, '-X', 'PATCH', '--input', '-'],\n {\n input: JSON.stringify({ body }),\n stdio: ['pipe', 'inherit', 'inherit'],\n timeout: GH_API_TIMEOUT,\n },\n )\n } catch (error) {\n logger.error({ err: error }, `Failed to edit comment ${commentId}:`)\n }\n}\n\n/**\n * Get the latest comment on an issue (not from the bot, not a /kody command)\n */\nexport function getLatestIssueComment(issueNumber: number, excludeAuthor?: string): string | null {\n if (!issueNumber) return null\n\n try {\n const exclude = (excludeAuthor || 'github-actions[bot]').replace(/[^a-zA-Z0-9\\[\\]_\\-]/g, '')\n // Get comments, exclude bot and /kody commands, return the latest plain-text answer\n const output = execFileSync(\n 'gh',\n [\n 'issue',\n 'view',\n String(issueNumber),\n '--json',\n 'comments',\n '--jq',\n `[.comments[] | select(.author.login != \"${exclude}\" and (.body | startswith(\"/kody\") | not))] | last | .body`,\n ],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n return output.trim() || null\n } catch {\n return null\n }\n}\n\n/**\n * Get the latest approval/rejection command on an issue\n * Used by gate approval to detect /kody approve or /kody reject\n */\nexport function getLatestApprovalComment(\n issueNumber: number,\n excludeAuthor?: string,\n): string | null {\n if (!issueNumber) return null\n\n try {\n const exclude = (excludeAuthor || 'github-actions[bot]').replace(/[^a-zA-Z0-9\\[\\]_\\-]/g, '')\n // Get comments from users (not bot) that contain approval/rejection keywords\n // Matches: approve, approved, yes, go, proceed, y, continue, reject, rejected, no, cancel, stop, n\n // Uses 'i' flag for case-insensitive matching\n const output = execFileSync(\n 'gh',\n [\n 'issue',\n 'view',\n String(issueNumber),\n '--json',\n 'comments',\n '--jq',\n `[.comments[] | select(.author.login != \"${exclude}\" and (.body | test(\"^[/@]kody\\\\s+(approve|approved|yes|go|proceed|y|continue|reject|rejected|no|cancel|stop|n)(\\\\s|$)\"; \"i\")))] | last | .body`,\n ],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n return output.trim() || null\n } catch {\n return null\n }\n}\n\n/**\n * Canonical regex for extracting task-ID from \"Task created: `NNNNNN-slug`\" marker\n * Used by both parse-inputs.sh and TypeScript implementations\n */\nexport const TASK_ID_MARKER_REGEX = /Task created: `(\\d{6}-[a-zA-Z0-9-]+)`/\n\n/**\n * Extract task-ID from text using the canonical marker format\n * Returns null if no valid task-ID found\n */\nexport function extractTaskIdFromMarker(text: string): string | null {\n const match = text.match(TASK_ID_MARKER_REGEX)\n return match ? match[1] : null\n}\n\n/**\n * Discover task-id from a previous Kody run by parsing bot comments on the issue.\n * Looks for \"Task created: `XXXXXX-task-name`\" in any comment.\n */\nexport function discoverTaskIdFromIssue(issueNumber: number): string | null {\n if (!issueNumber) return null\n\n try {\n // Get all comments (don't filter by author - matches parse-inputs.sh behavior)\n // Use execFileSync for defense against shell injection\n const output = execFileSync(\n 'gh',\n ['issue', 'view', String(issueNumber), '--json', 'comments', '--jq', '.comments[].body'],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n // Use canonical task-ID marker regex\n const match = output.match(TASK_ID_MARKER_REGEX)\n return match ? match[1] : null\n } catch {\n return null\n }\n}\n\n// ============================================================================\n// PR Review Functions\n// ============================================================================\n\n/**\n * Fetch PR review feedback: the latest \"changes requested\" review body +\n * all inline review comments. Returns formatted markdown suitable for\n * writing to rerun-feedback.md.\n *\n * Uses `gh api` to fetch PR reviews and review comments.\n * Returns null if no change-request reviews or comments found.\n */\nexport function getPRReviewFeedback(prNumber: number): string | null {\n if (!prNumber) return null\n\n const repo = process.env.GITHUB_REPOSITORY\n if (!repo) {\n logger.warn('getPRReviewFeedback: GITHUB_REPOSITORY not set')\n return null\n }\n\n const sections: string[] = []\n\n // 1. Get the latest \"changes_requested\" review body\n try {\n const reviewsOutput = execFileSync(\n 'gh',\n [\n 'api',\n `repos/${repo}/pulls/${prNumber}/reviews`,\n '--jq',\n '[.[] | select(.state == \"CHANGES_REQUESTED\")] | last | {body: .body, user: .user.login, submitted_at: .submitted_at}',\n ],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n const review = JSON.parse(reviewsOutput.trim())\n if (review?.body) {\n sections.push(`## Change Request from @${review.user}\\n\\n${review.body}`)\n }\n } catch (error) {\n logger.warn({ err: error }, `Failed to fetch PR reviews for #${prNumber}`)\n }\n\n // 2. Get inline review comments (code-level feedback)\n try {\n const commentsOutput = execFileSync(\n 'gh',\n [\n 'api',\n `repos/${repo}/pulls/${prNumber}/comments`,\n '--jq',\n '[.[] | {path: .path, line: .line, body: .body, user: .user.login}]',\n ],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n const comments = JSON.parse(commentsOutput.trim()) as Array<{\n path: string\n line: number | null\n body: string\n user: string\n }>\n\n if (comments.length > 0) {\n const commentLines = comments.map((c) => {\n const location = c.line ? `${c.path}:${c.line}` : c.path\n return `- **${location}** (@${c.user}): ${c.body}`\n })\n const header = '## Inline Comments'\n sections.push(header + '\\n\\n' + commentLines.join('\\n'))\n }\n } catch (error) {\n logger.warn({ err: error }, `Failed to fetch PR review comments for #${prNumber}`)\n }\n\n if (sections.length === 0) return null\n\n return sections.join('\\n\\n')\n}\n\n/**\n * Discover the PR number associated with the current branch.\n * Uses `gh pr view` which finds the PR for the current HEAD branch.\n * Returns null if no PR exists.\n */\nexport function getCurrentPRNumber(): number | null {\n try {\n const output = execFileSync('gh', ['pr', 'view', '--json', 'number', '--jq', '.number'], {\n encoding: 'utf-8',\n timeout: GH_API_TIMEOUT,\n })\n const num = parseInt(output.trim(), 10)\n return isNaN(num) ? null : num\n } catch {\n return null\n }\n}\n\n/**\n * Discover the task ID from a PR by checking bot comments on the PR.\n * PRs are issues in GitHub's API, so we can reuse discoverTaskIdFromIssue.\n */\nexport function discoverTaskIdFromPR(prNumber: number): string | null {\n return discoverTaskIdFromIssue(prNumber)\n}\n\n/**\n * Get the issue number linked to a PR via \"Closes #XXX\" in the PR description.\n * Used in fix mode to find the original issue from a PR.\n */\nexport function getLinkedIssueFromPR(prNumber: number): number | null {\n if (!prNumber) return null\n try {\n const output = execFileSync(\n 'gh',\n [\n 'pr',\n 'view',\n String(prNumber),\n '--json',\n 'closingIssuesReferences',\n '--jq',\n '.closingIssuesReferences[0].number',\n ],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n ).trim()\n return output ? parseInt(output, 10) : null\n } catch {\n return null\n }\n}\n\n/**\n * Extract the gate comment body from a gate-*.md file.\n * The file is written as: `# Gate Request\\n\\n${formatGateComment(...)}\\n`\n * This function strips the `# Gate Request\\n\\n` prefix and trims trailing whitespace,\n * returning the full comment body ready to post to GitHub.\n */\nexport function extractGateCommentBody(fileContent: string): string {\n return fileContent.replace(/^# Gate Request\\n\\n/, '').trim()\n}\n\n/**\n * Ensure the \"Task created\" marker comment exists on the issue.\n *\n * This is critical for task-id discovery: when someone runs `/kody` on an issue,\n * the pipeline discovers the existing task-id by searching for a bot comment\n * containing \"Task created: `XXXXXX-task-name`\". Without this marker,\n * subsequent runs auto-generate a new task-id instead of reusing the existing one.\n */\nexport function ensureTaskMarkerComment(\n issueNumber: number,\n taskId: string,\n mode?: string,\n runUrl?: string,\n): void {\n if (!issueNumber || !taskId) return\n\n // Check if marker already exists for ANY task-id on this issue\n const existingTaskId = discoverTaskIdFromIssue(issueNumber)\n if (existingTaskId) {\n if (existingTaskId === taskId) {\n logger.info(`Task marker already exists on issue #${issueNumber} for ${taskId}`)\n } else {\n logger.info(\n `Task marker exists on issue #${issueNumber} for ${existingTaskId} (current: ${taskId})`,\n )\n }\n // Post a lightweight \"run started\" comment so every invocation has a visible run link\n if (runUrl) {\n const modeLine = mode ? ` (\\`${mode}\\` mode)` : ''\n postComment(\n issueNumber,\n `🔄 Kody re-run for \\`${existingTaskId}\\`${modeLine}\\nRun: ${runUrl}`,\n )\n }\n return\n }\n\n // Build comment with mode and run URL\n const modeLine = mode ? ` (\\`${mode}\\` mode)` : ''\n const runLine = runUrl ? `\\nRun: ${runUrl}` : ''\n\n // No marker found — post one\n logger.info(`Posting task marker comment on issue #${issueNumber} for ${taskId}`)\n postComment(\n issueNumber,\n `🎯 Task created: \\`${taskId}\\`${modeLine}${runLine}\\n\\nKody will now process this task.`,\n )\n}\n\n// ============================================================================\n// Label Functions\n// ============================================================================\n\n/**\n * Add a label to an issue\n */\nexport function addIssueLabel(issueNumber: number, label: string): void {\n if (!issueNumber || !label) return\n\n try {\n execFileSync('gh', ['issue', 'edit', String(issueNumber), '--add-label', label], {\n stdio: ['inherit', 'inherit', 'inherit'],\n timeout: GH_API_TIMEOUT,\n })\n logger.info(` Added label \"${label}\" to issue #${issueNumber}`)\n } catch (error) {\n logger.error({ err: error }, `Failed to add label \"${label}\" to issue ${issueNumber}:`)\n }\n}\n\n/**\n * Remove a label from an issue\n */\nexport function removeIssueLabel(issueNumber: number, label: string): void {\n if (!issueNumber || !label) return\n\n try {\n execFileSync('gh', ['issue', 'edit', String(issueNumber), '--remove-label', label], {\n stdio: ['inherit', 'inherit', 'inherit'],\n timeout: GH_API_TIMEOUT,\n })\n logger.info(` Removed label \"${label}\" from issue #${issueNumber}`)\n } catch (error) {\n logger.error({ err: error }, `Failed to remove label \"${label}\" from issue ${issueNumber}:`)\n }\n}\n\n/**\n * Gate labels for visibility in dashboard\n */\nexport const GATE_LABELS = {\n HARD_STOP: 'hard-stop',\n RISK_GATED: 'risk-gated',\n} as const\n\n// ============================================================================\n// Lifecycle and Classification Label Management\n// ============================================================================\n\n/**\n * Lifecycle labels - mutually exclusive, set by pipeline state machine\n */\nexport const LIFECYCLE_LABELS = [\n 'kody:planning',\n 'kody:building',\n 'kody:review',\n 'kody:done',\n 'kody:failed',\n] as const\n\n/**\n * Task type labels - set by taskify based on task_type field\n */\nexport const TASK_TYPE_LABELS = [\n 'type:bug',\n 'type:feature',\n 'type:refactor',\n 'type:docs',\n 'type:ops',\n] as const\n\n/**\n * Risk level labels - set by taskify based on risk_level field\n */\nexport const RISK_LABELS = ['risk:high', 'risk:medium', 'risk:low'] as const\n\n/**\n * Complexity labels - set by taskify based on complexity score\n * 1-30 = simple, 31-60 = moderate, 61-100 = complex\n */\nexport const COMPLEXITY_LABELS = [\n 'complexity:simple',\n 'complexity:moderate',\n 'complexity:complex',\n] as const\n\n/**\n * Domain labels - set by taskify based on primary_domain field\n */\nexport const DOMAIN_LABELS = [\n 'domain:backend',\n 'domain:frontend',\n 'domain:infra',\n 'domain:llm',\n 'domain:data',\n 'domain:devops',\n 'domain:product',\n] as const\n\n/**\n * Profile labels - set by resolve-profile post-action\n */\nexport const PROFILE_LABELS = ['profile:lightweight', 'profile:standard'] as const\n\n/**\n * Set a lifecycle label - adds new label and removes all other lifecycle labels\n * Fire-and-forget: errors are logged but never thrown\n */\nexport function setLifecycleLabel(issueNumber: number, label: string): void {\n if (!issueNumber || !label) return\n\n // Validate the label is a lifecycle label\n if (!LIFECYCLE_LABELS.includes(label as (typeof LIFECYCLE_LABELS)[number])) {\n logger.error(`Invalid lifecycle label: ${label}`)\n return\n }\n\n // Get all OTHER lifecycle labels to remove (mutual exclusion)\n const labelsToRemove = LIFECYCLE_LABELS.filter((l) => l !== label)\n\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n // Remove all other lifecycle labels, add the new one\n const args = [\n 'issue',\n 'edit',\n String(issueNumber),\n '--remove-label',\n labelsToRemove.join(','),\n '--add-label',\n label,\n ]\n execFileSync('gh', args, {\n stdio: ['inherit', 'inherit', 'inherit'],\n timeout: GH_API_TIMEOUT,\n })\n logger.info(` Set lifecycle label \"${label}\" on issue #${issueNumber}`)\n return // Success\n } catch (error) {\n if (attempt === 0) {\n logger.warn(\n { err: error },\n `setLifecycleLabel attempt 1 failed for issue ${issueNumber}, retrying...`,\n )\n syncSleep(2000)\n } else {\n logger.error(\n { err: error },\n `Failed to set lifecycle label \"${label}\" on issue ${issueNumber} after 2 attempts`,\n )\n }\n }\n }\n}\n\n/**\n * Set classification labels from task.json fields\n * Maps: task_type, risk_level, complexity, primary_domain\n * Fire-and-forget: errors are logged but never thrown\n */\nexport function setClassificationLabels(\n issueNumber: number,\n taskDef: {\n task_type?: string\n risk_level?: string\n complexity?: number\n primary_domain?: string\n },\n): void {\n if (!issueNumber) return\n if (!taskDef) {\n logger.error(`No task definition provided for issue #${issueNumber}`)\n return\n }\n\n const labels: string[] = []\n\n // Map task_type to type:* label\n if (taskDef.task_type) {\n const typeMap: Record<string, string> = {\n fix_bug: 'type:bug',\n implement_feature: 'type:feature',\n refactor: 'type:refactor',\n docs: 'type:docs',\n ops: 'type:ops',\n spec_only: 'type:feature', // treat spec as feature\n research: 'type:ops',\n }\n const label = typeMap[taskDef.task_type]\n if (label && TASK_TYPE_LABELS.includes(label as (typeof TASK_TYPE_LABELS)[number])) {\n labels.push(label)\n }\n }\n\n // Map risk_level to risk:* label\n if (taskDef.risk_level) {\n const riskLabel = `risk:${taskDef.risk_level}`\n if (RISK_LABELS.includes(riskLabel as (typeof RISK_LABELS)[number])) {\n labels.push(riskLabel)\n }\n }\n\n // Map complexity to complexity:* label (uses getComplexityTier for single source of truth)\n if (taskDef.complexity !== undefined) {\n const tier = getComplexityTier(taskDef.complexity)\n let label: string\n if (tier === 'trivial' || tier === 'simple') {\n label = 'complexity:simple'\n } else if (tier === 'moderate') {\n label = 'complexity:moderate'\n } else {\n // complex or very_complex\n label = 'complexity:complex'\n }\n labels.push(label)\n }\n\n // Map primary_domain to domain:* label\n if (taskDef.primary_domain) {\n const domainLabel = `domain:${taskDef.primary_domain}`\n if (DOMAIN_LABELS.includes(domainLabel as (typeof DOMAIN_LABELS)[number])) {\n labels.push(domainLabel)\n }\n }\n\n if (labels.length === 0) {\n logger.info(`No classification labels to set for issue #${issueNumber}`)\n return\n }\n\n // Build list of stale labels to remove (old labels in same category as new ones)\n const labelsToRemove: string[] = []\n const allCategoryLabels: ReadonlyArray<readonly string[]> = [\n TASK_TYPE_LABELS,\n RISK_LABELS,\n COMPLEXITY_LABELS,\n DOMAIN_LABELS,\n ]\n for (const category of allCategoryLabels) {\n const newInCategory = labels.filter((l) => category.includes(l as never))\n if (newInCategory.length > 0) {\n // Remove all OTHER labels in this category\n const stale = category.filter((l) => !newInCategory.includes(l))\n labelsToRemove.push(...stale)\n }\n }\n\n // FIX #8: Add retry logic for the critical add operation.\n // Step 1: Add new labels (critical — retry once on failure)\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n execFileSync('gh', ['issue', 'edit', String(issueNumber), '--add-label', labels.join(',')], {\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: GH_API_TIMEOUT,\n })\n logger.info(` Set classification labels [${labels.join(', ')}] on issue #${issueNumber}`)\n break // Success\n } catch (error) {\n if (attempt === 0) {\n logger.warn(\n { err: error },\n `Classification label add attempt 1 failed for issue ${issueNumber}, retrying...`,\n )\n syncSleep(2000)\n } else {\n logger.error(\n { err: error },\n `Failed to set classification labels on issue ${issueNumber} after 2 attempts`,\n )\n }\n }\n }\n\n // Step 2: Remove stale labels in a separate call (best-effort with retry).\n // This is separate because `gh issue edit --remove-label` fails if ANY label in the\n // list doesn't exist on the repo. By separating add/remove, a remove failure\n // doesn't prevent the add from succeeding.\n if (labelsToRemove.length > 0) {\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n execFileSync(\n 'gh',\n ['issue', 'edit', String(issueNumber), '--remove-label', labelsToRemove.join(',')],\n {\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: GH_API_TIMEOUT,\n },\n )\n break // Success\n } catch {\n if (attempt === 0) {\n syncSleep(1000)\n }\n // Silently ignore on final attempt — labels may not exist on the repo or issue.\n // This is expected for newly added domain/category labels.\n }\n }\n }\n}\n\n/**\n * Set profile label - adds new profile and removes the other\n * Fire-and-forget: errors are logged but never thrown\n */\nexport function setProfileLabel(\n issueNumber: number,\n profile: 'lightweight' | 'standard' | 'turbo',\n): void {\n if (!issueNumber || !profile) return\n\n const label = `profile:${profile}`\n const otherLabel = profile === 'lightweight' ? 'profile:standard' : 'profile:lightweight'\n\n try {\n execFileSync(\n 'gh',\n ['issue', 'edit', String(issueNumber), '--remove-label', otherLabel, '--add-label', label],\n { stdio: ['inherit', 'inherit', 'inherit'], timeout: GH_API_TIMEOUT },\n )\n logger.info(` Set profile label \"${label}\" on issue #${issueNumber}`)\n } catch (error) {\n logger.error({ err: error }, `Failed to set profile label on issue ${issueNumber}:`)\n }\n}\n\n/**\n * Close an issue with a reason\n * Fire-and-forget: errors are logged but never thrown\n */\nexport function closeIssue(\n issueNumber: number,\n reason: 'completed' | 'not planned' = 'completed',\n): void {\n if (!issueNumber) return\n\n try {\n execFileSync('gh', ['issue', 'close', String(issueNumber), '--reason', reason], {\n stdio: ['inherit', 'inherit', 'inherit'],\n timeout: GH_API_TIMEOUT,\n })\n logger.info(` Closed issue #${issueNumber} (${reason})`)\n } catch (error) {\n logger.error({ err: error }, `Failed to close issue ${issueNumber}:`)\n }\n}\n\n/**\n * Close PR associated with an issue and delete the branch\n * Uses --delete-branch to remove both local and remote branches\n * Fire-and-forget: errors are logged but never thrown\n */\nexport function closeLinkedPR(issueNumber: number): boolean {\n if (!issueNumber) return false\n\n try {\n // Find PR linked to this issue\n const listResult = execFileSync(\n 'gh',\n ['pr', 'list', '--search', `closes:#${issueNumber}`, '--json', 'number'],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n const prs = JSON.parse(listResult) as { number: number }[]\n\n if (prs.length === 0) {\n logger.info(` No PR found for issue #${issueNumber}`)\n return false\n }\n\n const prNumber = prs[0].number\n\n // Close PR and delete branch in one command\n execFileSync('gh', ['pr', 'close', String(prNumber), '--delete-branch'], {\n stdio: ['inherit', 'inherit', 'inherit'],\n timeout: GH_API_TIMEOUT,\n })\n logger.info(` ✅ Closed PR #${prNumber} and deleted branch`)\n return true\n } catch (error) {\n logger.error({ err: error }, `Failed to close PR for issue ${issueNumber}:`)\n return false\n }\n}\n\n/**\n * Close an issue, its associated PR, and delete the branch\n * This is a convenience function that combines closeIssue and closeLinkedPR\n * Use this when you want to close an issue and clean up the PR/branch in one action\n * Fire-and-forget: errors are logged but never thrown\n */\nexport function closeIssueWithCleanup(\n issueNumber: number,\n reason: 'completed' | 'not planned' = 'completed',\n): void {\n if (!issueNumber) return\n\n // First close the PR and delete the branch\n closeLinkedPR(issueNumber)\n\n // Then close the issue\n closeIssue(issueNumber, reason)\n}\n","/**\n * @fileType utility\n * @domain kody | cli\n * @pattern cli-parser\n * @ai-summary CLI argument parsing and GitHub comment body parsing for the Kody pipeline\n */\n\nimport { Command } from 'commander'\nimport { randomInt } from 'crypto'\n\nimport * as path from 'path'\n\nimport type { KodyInput } from './kody-utils'\nimport { isValidMode, isValidStage, validateTaskId, VALID_MODES, VALID_STAGES } from './validation'\nimport { discoverTaskIdFromIssue } from './github-api'\nimport { logger } from './logger'\n\n// ============================================================================\n// CLI Argument Parsing\n// ============================================================================\n\nexport function parseCliArgs(argv: string[]): KodyInput {\n // Create Commander program with all CLI options\n const program = new Command()\n .allowUnknownOption()\n .allowExcessArguments()\n .option('--task-id <id>', 'Task ID')\n .option('--mode <mode>', 'Pipeline mode (spec, impl, rerun, full, status)')\n .option('--file <path>', 'Task file path')\n .option('--dry-run', 'Dry run mode')\n .option('--issue-number <n>', 'GitHub issue number')\n .option('--from <stage>', 'Resume from stage')\n .option('--feedback <text>', 'Rerun feedback')\n .option('--auto', 'Autonomous mode')\n .option('--gate', 'Risk-gated mode')\n .option('--hard-stop', 'Hard stop mode')\n .option('--local', 'Local mode')\n .option('--github', 'Use GitHub-hosted runner')\n .option('--ci', 'Use GitHub-hosted runner (alias for --github)')\n .option('--clarify', 'Run clarify stage')\n .option('--complexity <n>', 'Complexity score (1-100)')\n .option('--is-pull-request', 'Comment was on a PR')\n .option('--fresh', 'Force new PR')\n .option('--comment-body <text>', 'Comment body')\n .option('--comment-body-env <var>', 'Env var for comment body')\n .option('--version <ver>', 'Pipeline version')\n .option('--trigger-type <type>', 'Trigger type')\n .option('--run-id <id>', 'CI run ID')\n .option('--run-url <url>', 'CI run URL')\n .exitOverride() // Don't exit on --help, throw instead\n .configureOutput({\n writeOut: () => {}, // Suppress output during parsing\n writeErr: () => {},\n })\n\n let commanderOpts: Record<string, unknown> = {}\n try {\n // Commander handles both --key value and --key=value formats\n program.parse(['node', 'entry.ts', ...argv])\n commanderOpts = program.opts()\n } catch {\n // Commander throws on --help, --version, or unknown options\n // We suppress the error and continue with defaults\n }\n\n const input: KodyInput = {\n mode: 'full',\n taskId: '',\n dryRun: false,\n }\n\n // Track which fields were explicitly set via CLI args\n // Env vars should only be used as fallback when CLI arg wasn't provided\n const cliSet = new Set<string>()\n\n // Map Commander options to KodyInput\n // NOTE: --mode is processed LAST to preserve original behavior where\n // later args override earlier ones (e.g., --mode after --comment-body)\n // Commander returns undefined for options that weren't provided\n\n if (commanderOpts.taskId !== undefined) {\n input.taskId = commanderOpts.taskId as string\n cliSet.add('taskId')\n }\n\n // Process --mode initially (always) so comment-body can override it when appropriate\n // If --mode comes AFTER --comment-body in argv, we'll process it again at the end\n if (commanderOpts.mode !== undefined) {\n const mode = commanderOpts.mode as string\n if (!isValidMode(mode)) {\n throw new Error(`Invalid mode: ${mode}. Valid: ${VALID_MODES.join(', ')}`)\n }\n input.mode = mode\n cliSet.add('mode')\n }\n\n if (commanderOpts.dryRun !== undefined) {\n input.dryRun = true\n cliSet.add('dryRun')\n }\n\n if (commanderOpts.feedback !== undefined) {\n input.feedback = commanderOpts.feedback as string\n cliSet.add('feedback')\n }\n\n if (commanderOpts.from !== undefined) {\n const stage = commanderOpts.from as string\n if (!isValidStage(stage)) {\n throw new Error(`Invalid stage: ${stage}. Valid: ${VALID_STAGES.join(', ')}`)\n }\n input.fromStage = stage\n cliSet.add('fromStage')\n }\n\n // Control mode flags\n if (commanderOpts.auto !== undefined) {\n input.controlMode = 'auto'\n cliSet.add('controlMode')\n } else if (commanderOpts.gate !== undefined) {\n input.controlMode = 'risk-gated'\n cliSet.add('controlMode')\n } else if (commanderOpts.hardStop !== undefined) {\n input.controlMode = 'hard-stop'\n cliSet.add('controlMode')\n }\n\n if (commanderOpts.issueNumber !== undefined) {\n input.issueNumber = parseInt(commanderOpts.issueNumber as string, 10)\n cliSet.add('issueNumber')\n }\n\n if (commanderOpts.triggerType !== undefined) {\n input.triggerType = commanderOpts.triggerType as 'dispatch' | 'comment'\n cliSet.add('triggerType')\n }\n\n if (commanderOpts.runId !== undefined) {\n input.runId = commanderOpts.runId as string\n cliSet.add('runId')\n }\n\n if (commanderOpts.runUrl !== undefined) {\n input.runUrl = commanderOpts.runUrl as string\n cliSet.add('runUrl')\n }\n\n if (commanderOpts.version !== undefined) {\n input.version = commanderOpts.version as string\n cliSet.add('version')\n }\n\n if (commanderOpts.isPullRequest !== undefined) {\n input.isPullRequest = true\n cliSet.add('isPullRequest')\n }\n\n if (commanderOpts.fresh !== undefined) {\n input.fresh = true\n cliSet.add('fresh')\n }\n\n // Handle --comment-body-env=<var> (Commander may not parse this with --key=value pattern)\n const commentBodyEnvArg = argv.find((arg) => arg.startsWith('--comment-body-env='))\n if (commentBodyEnvArg) {\n const envVarName = commentBodyEnvArg.slice('--comment-body-env='.length)\n const commentBodyFromEnv = process.env[envVarName]\n if (commentBodyFromEnv) {\n const parsed = parseCommentBody(commentBodyFromEnv, undefined)\n if (!parsed.success) {\n throw new Error(parsed.error || 'Failed to parse comment body from env var')\n }\n if (parsed.input) {\n input.mode = parsed.input.mode\n cliSet.add('mode')\n if (parsed.input.taskId) {\n input.taskId = parsed.input.taskId\n cliSet.add('taskId')\n }\n input.dryRun = parsed.input.dryRun\n cliSet.add('dryRun')\n if (parsed.input.feedback) {\n input.feedback = parsed.input.feedback\n cliSet.add('feedback')\n }\n if (parsed.input.fromStage) {\n input.fromStage = parsed.input.fromStage\n cliSet.add('fromStage')\n }\n input.triggerType = 'comment'\n cliSet.add('triggerType')\n if (parsed.input.controlMode) {\n input.controlMode = parsed.input.controlMode\n cliSet.add('controlMode')\n }\n if (parsed.input.issueNumber) {\n input.issueNumber = parsed.input.issueNumber\n cliSet.add('issueNumber')\n }\n }\n }\n }\n\n if (commanderOpts.commentBody !== undefined) {\n const commentBody = commanderOpts.commentBody as string\n input.commentBody = commentBody\n const parsed = parseCommentBody(commentBody, undefined)\n\n if (!parsed.success) {\n throw new Error(parsed.error || 'Failed to parse comment body')\n }\n\n if (parsed.input) {\n input.mode = parsed.input.mode\n cliSet.add('mode')\n if (parsed.input.taskId) {\n input.taskId = parsed.input.taskId\n cliSet.add('taskId')\n }\n input.dryRun = parsed.input.dryRun\n cliSet.add('dryRun')\n if (parsed.input.feedback) {\n input.feedback = parsed.input.feedback\n cliSet.add('feedback')\n }\n if (parsed.input.fromStage) {\n input.fromStage = parsed.input.fromStage\n cliSet.add('fromStage')\n }\n input.triggerType = 'comment'\n cliSet.add('triggerType')\n if (parsed.input.controlMode) {\n input.controlMode = parsed.input.controlMode\n cliSet.add('controlMode')\n }\n if (parsed.input.issueNumber) {\n input.issueNumber = parsed.input.issueNumber\n cliSet.add('issueNumber')\n }\n }\n }\n\n if (commanderOpts.file !== undefined) {\n input.file = commanderOpts.file as string\n cliSet.add('file')\n // --file triggers taskId auto-generation, so don't let env var override\n cliSet.add('taskId')\n }\n\n if (commanderOpts.local !== undefined) {\n input.local = true\n cliSet.add('local')\n } else if (commanderOpts.github !== undefined || commanderOpts.ci !== undefined) {\n // --github or --ci explicitly sets local = false\n input.local = false\n cliSet.add('local')\n }\n\n if (commanderOpts.clarify !== undefined) {\n input.clarify = true\n cliSet.add('clarify')\n }\n\n if (commanderOpts.complexity !== undefined) {\n const val = parseInt(commanderOpts.complexity as string, 10)\n if (!isNaN(val) && val >= 1 && val <= 100) {\n input.complexityOverride = val\n cliSet.add('complexityOverride')\n } else {\n throw new Error(`Invalid --complexity value: ${commanderOpts.complexity}. Must be 1-100`)\n }\n }\n\n // Also handle positional arguments (non -- options) and determine arg processing order\n // We need to process --mode AFTER --comment-body ONLY when --mode actually comes AFTER --comment-body in argv\n // to preserve original CLI behavior where later args override earlier ones\n // (run-kody.sh puts --mode BEFORE --comment-body, so comment-body should win)\n const modeArgIndex = argv.findIndex((a) => a.startsWith('--mode'))\n const commentBodyArgIndex = argv.findIndex((a) => a.startsWith('--comment-body'))\n // Only process --mode at the end when it comes AFTER --comment-body\n const processModeLast = modeArgIndex > commentBodyArgIndex && commentBodyArgIndex >= 0\n\n // Options that consume the next arg as their value (--key <value> format)\n const optionsWithValues = new Set([\n '--task-id',\n '--mode',\n '--file',\n '--issue-number',\n '--from',\n '--feedback',\n '--complexity',\n '--comment-body',\n '--comment-body-env',\n '--version',\n '--trigger-type',\n '--run-id',\n '--run-url',\n ])\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i]\n\n // Skip values that belong to --key <value> options\n if (arg.startsWith('--') && optionsWithValues.has(arg) && i + 1 < argv.length) {\n i++ // skip the next arg (option value)\n continue\n }\n // Skip flags and unknown options\n if (arg.startsWith('-')) continue\n\n // Check if it's a valid mode\n if (isValidMode(arg)) {\n input.mode = arg\n cliSet.add('mode')\n continue\n }\n // Otherwise treat as file path (if it looks like a path)\n if (arg.includes('/') || arg.includes('.') || arg.includes('-')) {\n input.file = arg\n cliSet.add('file')\n cliSet.add('taskId') // --file triggers taskId auto-generation\n continue\n }\n }\n\n // Process --mode AFTER --comment-body only when it appears later in argv\n // This preserves the original CLI behavior where later args override earlier ones\n if (processModeLast) {\n if (commanderOpts.mode !== undefined) {\n const mode = commanderOpts.mode as string\n if (!isValidMode(mode)) {\n throw new Error(`Invalid mode: ${mode}. Valid: ${VALID_MODES.join(', ')}`)\n }\n input.mode = mode\n cliSet.add('mode')\n }\n }\n\n // Read from environment variables (for CI workflow)\n // CLI args take precedence over env vars - only use env var if field wasn't CLI-set\n // Use process.env directly (not getEnv()) for test compatibility\n if (!cliSet.has('taskId') && process.env.TASK_ID) {\n input.taskId = process.env.TASK_ID\n }\n if (!cliSet.has('mode') && process.env.MODE && isValidMode(process.env.MODE)) {\n input.mode = process.env.MODE\n }\n if (!cliSet.has('dryRun') && process.env.DRY_RUN === 'true') {\n input.dryRun = true\n }\n if (!cliSet.has('feedback') && process.env.FEEDBACK) {\n input.feedback = process.env.FEEDBACK\n }\n if (!cliSet.has('fromStage') && process.env.FROM_STAGE) {\n input.fromStage = process.env.FROM_STAGE\n }\n if (!cliSet.has('clarify') && process.env.CLARIFY === 'true') {\n input.clarify = true\n }\n if (!cliSet.has('issueNumber') && process.env.ISSUE_NUMBER) {\n input.issueNumber = parseInt(process.env.ISSUE_NUMBER, 10)\n }\n if (!cliSet.has('triggerType') && process.env.TRIGGER_TYPE) {\n input.triggerType = process.env.TRIGGER_TYPE as 'dispatch' | 'comment'\n }\n if (!cliSet.has('runId') && process.env.RUN_ID) {\n input.runId = process.env.RUN_ID\n }\n if (!cliSet.has('runUrl') && process.env.RUN_URL) {\n input.runUrl = process.env.RUN_URL\n }\n if (!cliSet.has('version') && process.env.VERSION) {\n input.version = process.env.VERSION\n }\n if (!cliSet.has('fresh') && process.env.FRESH === 'true') {\n input.fresh = true\n }\n if (!cliSet.has('complexityOverride') && process.env.COMPLEXITY) {\n const val = parseInt(process.env.COMPLEXITY, 10)\n if (!isNaN(val) && val >= 1 && val <= 100) {\n input.complexityOverride = val\n }\n }\n // Store raw comment body for gate approval detection (only for comment triggers)\n if (!input.commentBody && process.env.COMMENT_BODY && input.triggerType === 'comment') {\n input.commentBody = process.env.COMMENT_BODY\n }\n\n // Read IS_PULL_REQUEST from env (set by workflow for PR comments and PR review triggers)\n if (!cliSet.has('isPullRequest') && process.env.IS_PULL_REQUEST === 'true') {\n input.isPullRequest = true\n }\n\n // Read GITHUB_ACTOR — the GitHub login of the person who triggered the workflow\n if (!cliSet.has('actor') && process.env.GITHUB_ACTOR) {\n input.actor = process.env.GITHUB_ACTOR\n }\n\n // Read ISSUE_CREATOR — the GitHub login of the person who created the issue\n if (!cliSet.has('issueCreator') && process.env.ISSUE_CREATOR) {\n input.issueCreator = process.env.ISSUE_CREATOR\n }\n\n // Determine local mode: explicitly set or auto-detect from GITHUB_ACTIONS\n // Use process.env directly (not getEnv()) for test compatibility\n if (input.local === undefined) {\n input.local = !process.env.GITHUB_ACTIONS\n }\n\n // Auto-generate taskId if not provided\n if (!input.taskId) {\n // Try to discover task-id from previous bot comments on the issue\n // Skip discovery when --fresh flag is set — we want a brand-new task ID\n if (input.issueNumber && input.triggerType === 'comment' && !input.fresh) {\n const discovered = discoverTaskIdFromIssue(input.issueNumber)\n if (discovered) {\n input.taskId = discovered\n logger.info(`Discovered task ID from issue: ${input.taskId}`)\n }\n }\n if (input.fresh && input.issueNumber) {\n logger.info(`--fresh flag: skipping task ID discovery for issue #${input.issueNumber}`)\n }\n\n // If still no task-id, generate one\n if (!input.taskId) {\n if (input.file) {\n // Generate from filename: --file path/to/feature.md -> 260218-feature\n const stem = path.basename(input.file, path.extname(input.file))\n const datePrefix = new Date().toISOString().slice(2, 10).replace(/-/g, '')\n input.taskId = `${datePrefix}-${stem.replace(/[^a-zA-Z0-9-]/g, '-').toLowerCase()}`\n } else {\n // Fallback: auto-generate from date\n const datePrefix = new Date().toISOString().slice(2, 10).replace(/-/g, '')\n const counter = randomInt(100, 999)\n input.taskId = `${datePrefix}-auto-${counter}`\n }\n logger.info(`Auto-generated task ID: ${input.taskId}`)\n }\n }\n\n if (!validateTaskId(input.taskId)) {\n throw new Error(`Invalid task-id format: ${input.taskId}. Expected: YYMMDD-description`)\n }\n\n return input\n}\n\n// ============================================================================\n// Comment Body Parsing\n// ============================================================================\n\ninterface ParseCommentResult {\n success: boolean\n input?: KodyInput\n error?: string\n errorComment?: string // Error message to post back to the issue\n}\n\n/**\n * Parse a GitHub issue comment body in the format:\n * /kody <subcommand> <task-id> [options]\n *\n * Examples:\n * /kody 260218-user-metrics -> full mode, task 260218-user-metrics\n * /kody spec 260218-user-metrics -> spec mode\n * /kody impl 260218-user-metrics -> impl mode\n * /kody rerun 260218-user-metrics --feedback \"fix this\"\n * /kody -> full mode, auto-generate task-id\n */\nexport function parseCommentBody(body: string, issueNumber?: number): ParseCommentResult {\n // Decode JSON-encoded body from YAML (jq -Rs . wraps in quotes and escapes)\n let decoded = body\n if (decoded.startsWith('\"') && decoded.endsWith('\"')) {\n try {\n decoded = JSON.parse(decoded)\n } catch {\n // Use raw value if JSON.parse fails\n }\n }\n\n // Normalize literal \\n sequences to real newlines\n // (double-escaping from the GitHub Actions → shell → pnpm → Node.js pipeline\n // can leave literal backslash-n instead of actual newlines)\n decoded = decoded.replace(/\\\\n/g, '\\n')\n\n // Only parse the first line — /kody commands live on line 1;\n // trailing lines are just whitespace or comment noise\n const firstLine = decoded.split('\\n')[0]\n const cmd = firstLine.replace(/^\\/kody\\s*/, '').trim()\n\n // Extract subcommand (first word)\n const spaceIdx = cmd.indexOf(' ')\n const subCmd = spaceIdx === -1 ? cmd : cmd.slice(0, spaceIdx)\n const rest = spaceIdx === -1 ? '' : cmd.slice(spaceIdx + 1).trim()\n\n // Handle empty command: /kody with no subcommand defaults to full\n let mode: KodyInput['mode'] = 'full'\n let taskId = rest\n let implicitFeedback: string | undefined\n\n // Handle task-id as subcommand: /kody 260218-task defaults to full with that task\n const isTaskId = /^[0-9]{6}-[a-zA-Z0-9-]+$/.test(subCmd)\n if (isTaskId) {\n mode = 'full'\n taskId = `${subCmd}${rest ? ' ' + rest : ''}`.trim()\n // When task-id is the subcommand, we need to track what was \"rest\" for options parsing\n // The reconstructed taskId now contains both the ID and options, so use it as original\n } else if (subCmd) {\n // Handle approve/reject specially - these are for gate approval, not mode selection\n const lowerSubCmd = subCmd.toLowerCase()\n if (\n lowerSubCmd === 'approve' ||\n lowerSubCmd === 'reject' ||\n lowerSubCmd === 'yes' ||\n lowerSubCmd === 'no' ||\n lowerSubCmd === 'go' ||\n lowerSubCmd === 'proceed'\n ) {\n // Keep existing mode - gate approval logic will detect these keywords\n // Don't change mode, just pass through. The gate check will handle approval detection.\n // If no mode is set yet, default to full for resuming gated tasks\n if (!mode) mode = 'full'\n } else if (isValidMode(subCmd)) {\n // Validate subcommand\n mode = subCmd as KodyInput['mode']\n } else {\n // Unrecognized subcommand: treat as rerun with implicit feedback\n // e.g., \"/kody adjust tests\" → rerun mode, feedback = \"adjust tests\"\n mode = 'rerun'\n // Capture both the subcommand and rest as implicit feedback\n implicitFeedback = rest ? `${subCmd} ${rest}`.trim() : subCmd\n }\n }\n\n // Extract task-id — ONLY if it matches the task-id pattern (YYMMDD-description)\n // If it doesn't match, for rerun mode treat remaining text as implicit feedback\n // For other modes, leave task-id empty (will be auto-discovered from issue)\n const taskIdPattern = /^[0-9]{6}-[a-zA-Z0-9-]+$/\n\n if (taskId) {\n const firstWord = taskId.split(' ')[0]\n if (taskIdPattern.test(firstWord)) {\n // First word is a valid task-id\n taskId = firstWord\n } else {\n // First word is NOT a task-id\n if (mode === 'rerun' || mode === 'fix') {\n // For rerun/fix: treat all remaining text as implicit feedback\n // This handles \"@kody fix the button isn't showing\" → feedback = \"the button isn't showing\"\n implicitFeedback = taskId\n }\n taskId = '' // will be auto-discovered from issue\n }\n }\n\n // Don't auto-generate task-id here — let parseCliArgs handle discovery + fallback generation\n // This allows discoverTaskIdFromIssue to find the task-id from previous bot comments\n\n // Parse remaining options (--feedback, --from, --dry-run)\n // rest contains: for isTaskId case: \"options\", for explicit mode case: \"task-id options\"\n let optionsStr = ''\n if (isTaskId) {\n // Task-id as subcommand: rest has only options (after task-id)\n optionsStr = rest.trim()\n } else if (taskId) {\n // Explicit mode: rest = \"task-id options...\", skip past the task-id to get options\n const taskIdLen = taskId.length\n optionsStr = rest.slice(taskIdLen).trim()\n } else {\n // No task-id provided: rest is all options\n optionsStr = rest.trim()\n }\n\n const options = optionsStr.split(/\\s+/)\n let dryRun = false\n let feedback: string | undefined\n let fromStage: string | undefined\n let controlMode: KodyInput['controlMode'] = undefined\n let fresh = false\n\n let i = 0\n while (i < options.length) {\n const opt = options[i]\n if (opt === '--dry-run') {\n dryRun = true\n i++\n } else if (opt === '--auto') {\n controlMode = 'auto'\n i++\n } else if (opt === '--gate') {\n controlMode = 'risk-gated'\n i++\n } else if (opt === '--hard-stop') {\n controlMode = 'hard-stop'\n i++\n } else if (opt === '--feedback' && options[i + 1]) {\n // Capture all remaining words until the next --flag as feedback\n const feedbackParts: string[] = []\n let j = i + 1\n while (j < options.length && !options[j].startsWith('--')) {\n feedbackParts.push(options[j])\n j++\n }\n feedback = feedbackParts.join(' ')\n i = j\n } else if (opt === '--fresh') {\n fresh = true\n i++\n } else if (opt === '--from' && options[i + 1]) {\n fromStage = options[i + 1]\n // Validate from stage\n if (!isValidStage(fromStage)) {\n return {\n success: false,\n error: `Invalid stage: ${fromStage}`,\n errorComment: `Invalid stage: \\`${fromStage}\\`. Valid: \\`${VALID_STAGES.join(', ')}\\``,\n }\n }\n i += 2\n } else {\n // Skip unknown options\n i++\n }\n }\n\n // Use implicit feedback if no explicit --feedback was provided (for rerun mode)\n const finalFeedback = feedback || implicitFeedback\n\n return {\n success: true,\n input: {\n mode,\n taskId,\n dryRun,\n feedback: finalFeedback,\n fromStage,\n issueNumber,\n triggerType: 'comment',\n fresh,\n controlMode,\n },\n }\n}\n","/**\n * @fileType utility\n * @domain kody | formatting\n * @pattern status-format\n * @ai-summary Status comment formatting helpers for GitHub issue comments\n */\n\nimport type { KodyInput, KodyPipelineStatus } from './kody-utils'\n\n// ============================================================================\n// Formatting Helpers\n// ============================================================================\n\nexport function formatDuration(ms: number): string {\n const seconds = Math.floor(ms / 1000)\n const minutes = Math.floor(seconds / 60)\n const remainingSeconds = seconds % 60\n\n if (minutes > 0) {\n return `${minutes}m ${remainingSeconds}s`\n }\n return `${seconds}s`\n}\n\nexport function formatStatusComment(\n input: KodyInput,\n status: KodyPipelineStatus,\n currentStage?: string,\n _currentState?: string, // Reserved for future use\n): string {\n const lines: string[] = []\n\n if (status.state === 'running') {\n lines.push(`🔄 Kody running for \\`${input.taskId}\\` (mode: ${input.mode})`)\n lines.push('')\n\n if (currentStage) {\n const stageList = Object.entries(status.stages)\n for (const [stage, stageStatus] of stageList) {\n const icon =\n stageStatus.state === 'completed'\n ? '✅'\n : stageStatus.state === 'failed'\n ? '❌'\n : stageStatus.state === 'running'\n ? '🔄'\n : '⏳'\n const elapsed = stageStatus.elapsed ? ` (${formatDuration(stageStatus.elapsed)})` : ''\n lines.push(` ${icon} ${stage}${elapsed}`)\n }\n }\n } else if (status.state === 'completed') {\n lines.push(`✅ Kody completed for \\`${input.taskId}\\`!`)\n lines.push(`Mode: ${input.mode}`)\n\n // Add per-stage table with timing and cost\n const completedStages = Object.entries(status.stages)\n const hasCostData = completedStages.some(([, s]) => s.cost !== undefined && s.cost > 0)\n\n if (completedStages.length > 0) {\n lines.push('')\n if (hasCostData) {\n // Full table with cost column\n lines.push('| Stage | Status | Duration | Cost |')\n lines.push('|-------|--------|----------|------|')\n for (const [stage, stageStatus] of completedStages) {\n const icon =\n stageStatus.state === 'completed' ? '✅' : stageStatus.state === 'skipped' ? '⏭️' : '❌'\n const elapsed = stageStatus.elapsed ? formatDuration(stageStatus.elapsed) : '—'\n const cost =\n stageStatus.cost !== undefined && stageStatus.cost > 0\n ? `$${stageStatus.cost.toFixed(4)}`\n : '—'\n lines.push(`| ${stage} | ${icon} | ${elapsed} | ${cost} |`)\n }\n // Total row\n if (status.totalCost !== undefined && status.totalCost > 0) {\n lines.push(`| **Total** | | | **$${status.totalCost.toFixed(4)}** |`)\n }\n } else {\n // Simple list without cost (backward compat)\n for (const [stage, stageStatus] of completedStages) {\n const icon = stageStatus.state === 'completed' ? '✅' : '❌'\n const elapsed = stageStatus.elapsed ? ` (${formatDuration(stageStatus.elapsed)})` : ''\n lines.push(` ${icon} ${stage}${elapsed}`)\n }\n }\n }\n } else if (status.state === 'paused') {\n lines.push(`⏸️ Kody paused for \\`${input.taskId}\\``)\n lines.push(\n 'Awaiting approval — reply with `@kody approve` or `/kody approve` to proceed. ' +\n 'Reply with `@kody reject` or `/kody reject` to cancel.',\n )\n } else if (status.state === 'failed') {\n lines.push(`❌ Kody failed for \\`${input.taskId}\\``)\n } else if (status.state === 'timeout') {\n lines.push(`⏰ Kody timed out for \\`${input.taskId}\\``)\n }\n\n // Always append run URL regardless of state\n if (input.runUrl) {\n lines.push(`Run: ${input.runUrl}`)\n }\n\n return lines.join('\\n')\n}\n\nexport async function formatStatusCommentV2(input: KodyInput, stateV2: unknown): Promise<string> {\n if (!stateV2 || typeof stateV2 !== 'object') {\n return `❌ Invalid pipeline state for \\`${input.taskId}\\``\n }\n const { stateToV1 } = await import('./engine/status')\n return formatStatusComment(input, stateToV1(stateV2 as Parameters<typeof stateToV1>[0]))\n}\n","/**\n * @fileType utility\n * @domain ci | kody | github\n * @pattern kody-pipeline | github-api | status-tracking\n * @ai-summary CI-specific utilities for the Kody pipeline: comment parsing, GitHub API helpers, status management\n */\n\nimport { logger } from './logger'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { STAGE_NAMES } from './stages/registry'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface KodyInput {\n mode: 'spec' | 'impl' | 'rerun' | 'fix' | 'full' | 'status' | 'design-system'\n taskId: string\n dryRun: boolean\n fromStage?: string\n feedback?: string\n issueNumber?: number\n triggerType?: 'dispatch' | 'comment'\n runId?: string\n runUrl?: string\n // For comment triggers: raw body to parse\n commentBody?: string\n // Local mode: use pnpm ocode run instead of opencode github run\n local?: boolean\n // Path to task description file (for auto-generating task-id and task.md)\n file?: string\n // Opt-in to run clarify stage (default: skip, auto-create clarified.md)\n clarify?: boolean\n // Control mode override: auto, risk-gated, hard-stop\n controlMode?: 'auto' | 'risk-gated' | 'hard-stop'\n // Pipeline version: branch, tag, or commit to overlay (overrides KODY_DEFAULT_VERSION)\n version?: string\n // Complexity score override (1-100) for testing/debugging\n complexityOverride?: number\n // Whether the trigger was from a PR comment (vs issue comment)\n isPullRequest?: boolean\n // Force create new PR (new branch) - ignores existing PR\n fresh?: boolean\n // Turbo mode: forces minimal pipeline (build→commit→verify→pr), CLI-only flag\n turbo?: boolean\n /** GitHub login of the person who triggered this pipeline run (from GITHUB_ACTOR env var) */\n actor?: string\n /** GitHub login of the person who created the issue (from ISSUE_CREATOR env var) */\n issueCreator?: string\n}\n\nexport interface ActorEvent {\n action: string\n actor: string\n timestamp: string\n stage?: string\n}\n\nexport interface KodyPipelineStatus {\n taskId: string\n mode: string\n pipeline: string\n startedAt: string\n updatedAt: string\n completedAt?: string\n totalElapsed?: number\n state: 'running' | 'completed' | 'failed' | 'timeout' | 'paused'\n currentStage: string | null\n stages: Record<string, StageStatus>\n triggeredBy: string\n issueNumber?: number\n runId?: string\n runUrl?: string\n controlMode?: 'auto' | 'risk-gated' | 'hard-stop'\n gatePoint?: string\n botCommentId?: number\n /** Total accumulated cost across all stages in USD */\n totalCost?: number\n /** GitHub login of the person who triggered this pipeline run */\n triggeredByLogin?: string\n /** GitHub login of the person who created the issue (the \"owner\") */\n issueCreator?: string\n /** Audit trail of actor actions (capped at 50 entries) */\n actorHistory?: ActorEvent[]\n}\n\nexport interface StageStatus {\n state: 'pending' | 'running' | 'completed' | 'failed' | 'timeout' | 'skipped' | 'gate-waiting'\n startedAt?: string\n completedAt?: string\n elapsed?: number\n retries: number\n outputFile?: string\n skipped?: string // Reason for skip (e.g., 'input_quality')\n error?: string\n // Token usage for cost tracking\n tokenUsage?: {\n input: number\n output: number\n }\n /** Cost in USD */\n cost?: number\n}\n\n// ============================================================================\n// Validation\n// ============================================================================\n\nexport const VALID_MODES = ['spec', 'impl', 'rerun', 'fix', 'full', 'status'] as const\n\n// VALID_STAGES derived from registry to avoid duplication\n// Note: includes 'autofix' for backward compat with comment parsing validation\nexport const VALID_STAGES = [...STAGE_NAMES, 'autofix' as const]\n\n// Pipeline-ordered stage list for sorting (avoids `as any` cast on readonly tuple)\nconst STAGE_ORDER: readonly string[] = STAGE_NAMES\n\nexport function isValidMode(mode: string): mode is (typeof VALID_MODES)[number] {\n return VALID_MODES.includes(mode as (typeof VALID_MODES)[number])\n}\n\nexport function isValidStage(stage: string): stage is (typeof VALID_STAGES)[number] {\n return VALID_STAGES.includes(stage as (typeof VALID_STAGES)[number])\n}\n\nexport function validateTaskId(taskId: string): boolean {\n // Format: YYMMDD-description (e.g., 260217-user-metrics)\n return /^[0-9]{6}-[a-zA-Z0-9-]+$/.test(taskId)\n}\n\n// ============================================================================\n// Status Management\n// ============================================================================\n\nexport function getTaskDir(taskId: string): string {\n return path.join(process.cwd(), '.tasks', taskId)\n}\n\nexport function ensureTaskDir(taskId: string): string {\n const dir = getTaskDir(taskId)\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n return dir\n}\n\n/**\n * @deprecated Use engine/status.ts loadState/writeState/completeState instead.\n * This function is kept for backward compatibility with existing tests.\n */\nexport function readStatus(taskId: string): KodyPipelineStatus | null {\n const statusFile = path.join(getTaskDir(taskId), 'status.json')\n if (!fs.existsSync(statusFile)) {\n return null\n }\n try {\n return JSON.parse(fs.readFileSync(statusFile, 'utf-8'))\n } catch {\n return null\n }\n}\n\n/**\n * Get the last failed stage from status.json for smart rerun default.\n * Returns the stage name that most recently failed, or null if none.\n * Updated to use v2 schema (G(utils-1/2)).\n */\nexport function getLastFailedStage(taskId: string): string | null {\n const statusFile = path.join(getTaskDir(taskId), 'status.json')\n if (!fs.existsSync(statusFile)) {\n return null\n }\n\n try {\n const content = fs.readFileSync(statusFile, 'utf-8')\n const status = JSON.parse(content) as {\n version?: number\n stages?: Record<string, { state: string }>\n }\n\n // Check if it's v2 format (has version: 2)\n if (status.version === 2 && status.stages) {\n const failedStages = Object.entries(status.stages)\n .filter(([, s]) => s.state === 'failed' || s.state === 'timeout')\n .map(([name]) => name)\n // Sort by pipeline order (ALL_STAGES index) to get truly last failed stage\n failedStages.sort((a, b) => {\n const idxA = STAGE_ORDER.indexOf(a)\n const idxB = STAGE_ORDER.indexOf(b)\n return idxA - idxB\n })\n return failedStages.length > 0 ? failedStages[failedStages.length - 1] : null\n }\n\n // Fallback to v1 format\n if (status?.stages) {\n const failedStages = Object.entries(status.stages)\n .filter(([, s]) => s.state === 'failed' || s.state === 'timeout')\n .map(([name]) => name)\n // Sort by pipeline order (ALL_STAGES index) to get truly last failed stage\n failedStages.sort((a, b) => {\n const idxA = STAGE_ORDER.indexOf(a)\n const idxB = STAGE_ORDER.indexOf(b)\n return idxA - idxB\n })\n return failedStages.length > 0 ? failedStages[failedStages.length - 1] : null\n }\n\n return null\n } catch {\n return null\n }\n}\n\n/**\n * Get the last paused stage from status.json.\n * Used by rerun mode to detect gates that are waiting for approval.\n * Returns the stage name that has state 'paused', or null if none.\n */\nexport function getLastPausedStage(taskId: string): string | null {\n const statusFile = path.join(getTaskDir(taskId), 'status.json')\n if (!fs.existsSync(statusFile)) {\n return null\n }\n\n try {\n const content = fs.readFileSync(statusFile, 'utf-8')\n const status = JSON.parse(content) as {\n version?: number\n stages?: Record<string, { state: string }>\n }\n\n // Check for paused stages in v2 format\n if (status.version === 2 && status.stages) {\n const pausedStages = Object.entries(status.stages)\n .filter(([, s]) => s.state === 'paused')\n .map(([name]) => name)\n // Sort by pipeline order (ALL_STAGES index) to get truly last paused stage\n pausedStages.sort((a, b) => {\n const idxA = STAGE_ORDER.indexOf(a)\n const idxB = STAGE_ORDER.indexOf(b)\n return idxA - idxB\n })\n // Return the last paused stage (most recent in pipeline order)\n return pausedStages.length > 0 ? pausedStages[pausedStages.length - 1] : null\n }\n\n // Fallback to v1 format\n if (status?.stages) {\n const pausedStages = Object.entries(status.stages)\n .filter(([, s]) => s.state === 'paused')\n .map(([name]) => name)\n // Sort by pipeline order (ALL_STAGES index) to get truly last paused stage\n pausedStages.sort((a, b) => {\n const idxA = STAGE_ORDER.indexOf(a)\n const idxB = STAGE_ORDER.indexOf(b)\n return idxA - idxB\n })\n return pausedStages.length > 0 ? pausedStages[pausedStages.length - 1] : null\n }\n\n return null\n } catch {\n return null\n }\n}\n\n/**\n * @deprecated Use engine/status.ts loadState/writeState/completeState instead.\n */\nexport function writeStatus(taskId: string, status: KodyPipelineStatus): void {\n const statusFile = path.join(getTaskDir(taskId), 'status.json')\n // Atomic write: write to temp file then rename to prevent corruption\n // if the process is killed mid-write (e.g., timeout SIGKILL).\n const tmpFile = statusFile + '.tmp'\n fs.writeFileSync(tmpFile, JSON.stringify(status, null, 2))\n fs.renameSync(tmpFile, statusFile)\n}\n\n/**\n * @deprecated Use engine/status.ts loadState/writeState/completeState instead.\n */\nexport function initStatus(input: KodyInput): KodyPipelineStatus {\n const now = new Date().toISOString()\n const status: KodyPipelineStatus = {\n taskId: input.taskId,\n mode: input.mode,\n pipeline: 'spec_execute_verify', // will be updated after taskify\n startedAt: now,\n updatedAt: now,\n state: 'running',\n currentStage: null,\n stages: {},\n triggeredBy: input.triggerType || 'dispatch',\n issueNumber: input.issueNumber,\n runId: input.runId,\n runUrl: input.runUrl,\n }\n writeStatus(input.taskId, status)\n return status\n}\n\n/**\n * Update stage status with read-modify-write to status.json.\n *\n * Concurrency safety: parallel stages (e.g., verify + pr) call this from\n * separate promise callbacks, but Node.js is single-threaded — only one\n * callback runs at a time, so read-modify-write is atomic on the event loop.\n * The atomic writeStatus (write-to-tmp + rename) guards against corruption\n * from process kills (SIGTERM/SIGKILL during write).\n */\n\n/**\n * @deprecated Use engine/status.ts loadState/writeState/completeState instead.\n */\nexport function updateStageStatus(\n taskId: string,\n stage: string,\n state: StageStatus['state'],\n extras?: Partial<StageStatus>,\n): void {\n const status = readStatus(taskId)\n if (!status) {\n logger.warn(`No status file found for task: ${taskId}`)\n return\n }\n\n const now = new Date().toISOString()\n\n if (!status.stages[stage]) {\n status.stages[stage] = {\n state,\n retries: 0,\n ...extras,\n }\n }\n\n const stageStatus = status.stages[stage]\n\n // Apply extras (retries, outputFile, error) — works for both new and existing stages\n if (extras) {\n if (extras.retries !== undefined) stageStatus.retries = extras.retries\n if (extras.outputFile !== undefined) stageStatus.outputFile = extras.outputFile\n if (extras.error !== undefined) stageStatus.error = extras.error\n }\n\n if (state === 'running') {\n stageStatus.state = 'running'\n stageStatus.startedAt = now\n } else if (state === 'completed' || state === 'failed' || state === 'timeout') {\n stageStatus.state = state\n stageStatus.completedAt = now\n if (stageStatus.startedAt) {\n stageStatus.elapsed = new Date(now).getTime() - new Date(stageStatus.startedAt).getTime()\n }\n }\n\n status.currentStage = state === 'running' ? stage : status.currentStage\n status.updatedAt = now\n writeStatus(taskId, status)\n}\n\n/**\n * @deprecated Use engine/status.ts loadState/writeState/completeState instead.\n */\nexport function completeStatus(taskId: string, state: KodyPipelineStatus['state']): void {\n const status = readStatus(taskId)\n if (!status) return\n\n const now = new Date().toISOString()\n status.state = state\n status.updatedAt = now\n status.completedAt = now\n if (status.startedAt) {\n status.totalElapsed = new Date(now).getTime() - new Date(status.startedAt).getTime()\n }\n writeStatus(taskId, status)\n}\n\n// GitHub API re-exports removed — import directly from './github-api'\n\n// ============================================================================\n// Auth Validation\n// ============================================================================\n\n// Note: opencode github run handles OIDC auth internally via the id-token permission.\n// We don't need to validate a token ourselves - each invocation handles its own auth.\nexport function validateAuth(): void {\n // Check we're in GitHub Actions environment (where OIDC auth is available)\n if (!process.env.GITHUB_ACTIONS) {\n logger.warn('⚠ Not running in GitHub Actions — OIDC auth may not work')\n logger.warn(' Run locally or in CI with id-token: write permission')\n } else {\n logger.info('✓ Running in GitHub Actions — OIDC auth available via id-token permission')\n }\n}\n\n// ============================================================================\n// Re-exports for backward compatibility\n// Import directly from './cli-parser' or './status-format' for new code\n// ============================================================================\n\nexport { parseCliArgs, parseCommentBody } from './cli-parser'\nexport { formatDuration, formatStatusComment, formatStatusCommentV2 } from './status-format'\n","// preflight.ts - Pre-flight validation for Kody\nimport { logger } from \"./logger\";\nimport { execFileSync } from \"child_process\";\nimport * as fs from \"fs\";\n\ninterface Check {\n name: string;\n test: () => void;\n errorMessage?: string;\n}\n\nexport function preflight(): void {\n const checks: Check[] = [\n {\n name: \"ocode CLI (via pnpm)\",\n test: () =>\n execFileSync(\"pnpm\", [\"opencode\", \"--version\"], { stdio: \"pipe\" }),\n errorMessage: \"Run: pnpm install\",\n },\n {\n name: \"Git repository\",\n test: () =>\n execFileSync(\"git\", [\"rev-parse\", \"--git-dir\"], { stdio: \"pipe\" }),\n errorMessage: \"Initialize git: git init\",\n },\n {\n name: \"pnpm\",\n test: () => execFileSync(\"which\", [\"pnpm\"], { stdio: \"pipe\" }),\n errorMessage: \"Install: npm install -g pnpm\",\n },\n {\n name: \"Node.js v18+\",\n test: () => {\n const version = execFileSync(\"node\", [\"--version\"], {\n encoding: \"utf-8\",\n }).trim();\n const major = parseInt(version.slice(1).split(\".\")[0]);\n if (major < 18) {\n throw new Error(`Node ${version} is too old, need v18+`);\n }\n },\n errorMessage: \"Upgrade Node.js to v18 or higher\",\n },\n {\n name: \"package.json\",\n test: () => {\n if (!fs.existsSync(\"./package.json\")) {\n throw new Error(\"package.json not found\");\n }\n },\n errorMessage: \"Run from project root with package.json\",\n },\n {\n name: \"GitHub token (GH_PAT or GH_TOKEN)\",\n test: () => {\n const token =\n process.env.GH_PAT?.trim() || process.env.GH_TOKEN?.trim();\n if (!token) {\n throw new Error(\"No GitHub token found\");\n }\n },\n errorMessage:\n \"Set GH_PAT or GH_TOKEN in .env (needed for PR creation and GitHub API)\",\n },\n ];\n\n logger.info(\"🔍 Pre-flight checks...\");\n let failed = false;\n const errors: string[] = [];\n\n for (const check of checks) {\n try {\n check.test();\n logger.info(` ✅ ${check.name}`);\n } catch {\n logger.info(` ❌ ${check.name}`);\n if (check.errorMessage) {\n errors.push(` ${check.errorMessage}`);\n }\n failed = true;\n }\n }\n\n if (failed) {\n const errorDetails = errors.join(\"\\n\");\n throw new Error(\n `Pre-flight checks failed:\\n${errorDetails}\\n\\nFix issues above before running pipeline.`,\n );\n }\n\n logger.info(\"✅ Pre-flight complete\\n\");\n}\n","/**\n * @fileType utility\n * @domain kody | infrastructure\n * @pattern opencode-server\n * @ai-summary Manages OpenCode server lifecycle for persistent sessions across pipeline stages\n */\n\nimport { spawn, execFileSync, type ChildProcess } from 'child_process'\nimport * as fs from 'fs'\nimport * as os from 'os'\nimport * as path from 'path'\nimport { logger } from './logger'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface OpenCodeServer {\n process: ChildProcess\n url: string\n port: number\n dataDir: string\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_PORT = 4097\nconst HEALTH_CHECK_TIMEOUT_MS = 30_000\nconst HEALTH_CHECK_INTERVAL_MS = 500\nconst SHUTDOWN_GRACE_MS = 5_000\n\n// ============================================================================\n// Binary Resolution\n// ============================================================================\n\n/**\n * Resolve the path to the real opencode binary (v1.2.x installed via curl).\n *\n * When running inside `pnpm tsx`, `node_modules/.bin/opencode` shadows the\n * real binary because pnpm prepends `./node_modules/.bin` to PATH. The npm\n * package (opencode-ai@0.0.0-dev) doesn't support --agent + --attach properly.\n *\n * Resolution order:\n * 1. ~/.opencode/bin/opencode (standard curl install location)\n * 2. 'opencode' (fall back to PATH — works in CI where npm shadow doesn't exist)\n */\nexport function resolveOpenCodeBinary(): string {\n const installDir = path.join(os.homedir(), '.opencode', 'bin', 'opencode')\n if (fs.existsSync(installDir)) {\n return installDir\n }\n return 'opencode'\n}\n/**\n * Verify that `opencode run --attach` can find the server instance.\n * Returns true if the client can connect, false otherwise.\n * This catches the \"No context found for instance\" error early.\n */\nexport function verifyClientAttach(url: string, dataDir: string): boolean {\n try {\n const binary = resolveOpenCodeBinary()\n // Use a minimal prompt that will immediately error with a model issue\n // (which is fine — we just need to confirm it doesn't fail with\n // \"No context found for instance\")\n const result = execFileSync(binary, ['run', '--attach', url, '--format', 'json', 'ping'], {\n env: { ...process.env, XDG_DATA_HOME: dataDir },\n timeout: 15_000,\n stdio: ['ignore', 'pipe', 'pipe'],\n cwd: process.cwd(),\n })\n // If we get here, the command ran (it will likely error with model config issues, but that's fine)\n const output = result.toString()\n return !output.includes('No context found for instance')\n } catch (err: unknown) {\n // The command will exit non-zero (model errors etc), check stderr for the specific instance error\n const stderr = (err as { stderr?: Buffer })?.stderr?.toString() || ''\n const stdout = (err as { stdout?: Buffer })?.stdout?.toString() || ''\n const combined = stderr + stdout\n\n // Fail on known indicators that the server instance is not accessible\n if (\n combined.includes('No context found for instance') ||\n combined.includes('Unexpected error, check log file')\n ) {\n return false\n }\n\n // Also fail if the command timed out (15s) — the attach should respond quickly\n const errObj = err as { killed?: boolean; signal?: string; code?: string }\n if (errObj.killed || errObj.signal === 'SIGTERM' || errObj.code === 'ETIMEDOUT') {\n return false\n }\n\n // Any other error means the attach itself worked (model/agent errors are expected)\n return true\n }\n}\n\n// ============================================================================\n// Server Lifecycle\n// ============================================================================\n\n/**\n * Start an OpenCode server with an isolated data directory for this task.\n * The data dir is set via XDG_DATA_HOME so the SQLite DB and snapshots\n * are scoped per-task and don't interfere with other runs.\n *\n * @param taskDir - The .tasks/<taskId> directory\n * @param port - Port to listen on (default: 4097)\n * @returns The running server, or null if startup failed\n */\nexport async function startServer(\n taskDir: string,\n port: number = DEFAULT_PORT,\n): Promise<OpenCodeServer | null> {\n const dataDir = path.join(taskDir, 'opencode-data')\n const opencodeSub = path.join(dataDir, 'opencode')\n\n // Ensure the data directory structure exists\n fs.mkdirSync(opencodeSub, { recursive: true })\n\n // Copy auth.json from the global data dir if it exists and we don't have one\n // (needed for provider authentication in isolated data dirs)\n const localAuth = path.join(opencodeSub, 'auth.json')\n if (!fs.existsSync(localAuth)) {\n const globalDataDir = process.env.XDG_DATA_HOME\n ? path.join(process.env.XDG_DATA_HOME, 'opencode')\n : path.join(os.homedir(), '.local', 'share', 'opencode')\n const globalAuth = path.join(globalDataDir, 'auth.json')\n if (fs.existsSync(globalAuth)) {\n try {\n fs.copyFileSync(globalAuth, localAuth)\n // Restrict permissions: auth.json contains API credentials\n fs.chmodSync(localAuth, 0o600)\n logger.info(' Copied auth.json to task data dir')\n } catch {\n // Non-fatal: CI uses env vars for auth\n }\n }\n }\n\n const url = `http://127.0.0.1:${port}`\n logger.info(` 🚀 Starting OpenCode server on port ${port}...`)\n\n try {\n const binary = resolveOpenCodeBinary()\n\n // Log version for diagnostics (helps debug CI issues)\n try {\n const ver = execFileSync(binary, ['--version'], { encoding: 'utf-8', timeout: 5000 }).trim()\n logger.info(` OpenCode binary: ${binary} (v${ver})`)\n } catch {\n logger.info(` OpenCode binary: ${binary} (version unknown)`)\n }\n const child = spawn(\n binary,\n ['serve', '--port', String(port), '--print-logs', '--log-level', 'WARN'],\n {\n env: {\n ...process.env,\n XDG_DATA_HOME: dataDir,\n },\n cwd: process.cwd(),\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: false,\n },\n )\n\n // Drain stdout/stderr to prevent buffer overflow\n child.stdout?.resume()\n child.stderr?.resume()\n\n // Race the health check against a spawn-error rejection so we fail fast\n // if the binary is not found or the process exits immediately (e.g. port in use).\n const spawnErrorPromise = new Promise<never>((_, reject) => {\n child.on('error', (err) => reject(err))\n child.on('exit', (code) => {\n if (code !== 0 && code !== null) {\n reject(new Error(`opencode serve exited with code ${code}`))\n }\n })\n })\n\n const healthy = await Promise.race([\n waitForHealthy(url, HEALTH_CHECK_TIMEOUT_MS),\n spawnErrorPromise.then(\n () => false as boolean,\n () => false as boolean,\n ),\n ])\n\n if (!healthy) {\n logger.warn('OpenCode server failed to start (health check failed or process exited)')\n if (!child.killed) child.kill('SIGTERM')\n return null\n }\n\n logger.info(` ✅ OpenCode server ready at ${url}`)\n\n // Health check passed — server is ready. We no longer run verifyClientAttach()\n // because opencode run --attach 'ping' often times out even when the server is\n // fully functional (the short 'ping' prompt triggers slow model initialization).\n // The health endpoint is sufficient proof the server is operational.\n\n return { process: child, url, port, dataDir }\n } catch (err) {\n logger.warn({ err }, 'Failed to start OpenCode server')\n return null\n }\n}\n\n/**\n * Poll the health endpoint until the server reports healthy.\n */\nexport async function waitForHealthy(\n url: string,\n timeoutMs: number = HEALTH_CHECK_TIMEOUT_MS,\n): Promise<boolean> {\n const start = Date.now()\n const healthUrl = `${url}/global/health`\n\n while (Date.now() - start < timeoutMs) {\n try {\n const response = await fetch(healthUrl, { signal: AbortSignal.timeout(2000) })\n if (response.ok) {\n const body = (await response.json()) as { healthy?: boolean }\n if (body.healthy) return true\n }\n } catch {\n // Server not ready yet\n }\n await new Promise((r) => setTimeout(r, HEALTH_CHECK_INTERVAL_MS))\n }\n return false\n}\n\n/**\n * Stop the OpenCode server gracefully.\n */\nexport async function stopServer(server: OpenCodeServer): Promise<void> {\n if (!server.process || server.process.killed) return\n\n logger.info(' 🛑 Stopping OpenCode server...')\n\n return new Promise<void>((resolve) => {\n const forceKillTimer = setTimeout(() => {\n if (!server.process.killed) {\n server.process.kill('SIGKILL')\n }\n resolve()\n }, SHUTDOWN_GRACE_MS)\n\n server.process.on('exit', () => {\n clearTimeout(forceKillTimer)\n resolve()\n })\n\n server.process.kill('SIGTERM')\n })\n}\n\n/**\n * Checkpoint the SQLite WAL into the main DB file.\n * This ensures the .db file is self-contained for git commits.\n * Must be called AFTER stopping the server.\n */\nexport function checkpointDb(taskDir: string): void {\n const dbPath = path.join(taskDir, 'opencode-data', 'opencode', 'opencode.db')\n if (!fs.existsSync(dbPath)) {\n logger.debug('No OpenCode DB to checkpoint')\n return\n }\n\n try {\n execFileSync('sqlite3', [dbPath, 'PRAGMA wal_checkpoint(TRUNCATE);'], {\n stdio: 'pipe',\n timeout: 10_000,\n })\n logger.info(' ✅ OpenCode DB checkpoint complete')\n } catch (err) {\n // Non-fatal: WAL files will just be larger but DB still works\n logger.warn({ err }, 'Failed to checkpoint OpenCode DB (non-fatal)')\n }\n}\n\n/**\n * Find the sessionId of the last completed agent stage.\n * Used on rerun to resume from the last known session.\n */\nexport function findLastSessionId(\n stages: Record<string, { state: string; sessionId?: string }>,\n pipelineOrder: string[],\n): string | undefined {\n // Walk pipeline order in reverse to find the last completed stage with a sessionId\n for (let i = pipelineOrder.length - 1; i >= 0; i--) {\n const stageName = pipelineOrder[i]\n const stage = stages[stageName]\n if (\n stage?.sessionId &&\n (stage.state === 'completed' || stage.state === 'failed' || stage.state === 'timeout')\n ) {\n return stage.sessionId\n }\n }\n return undefined\n}\n","/**\n * @fileType utility\n * @domain ci | kody | agent-execution\n * @pattern runner-backend\n * @ai-summary Pluggable runner backend for Kody: supports both local (ocode) and CI (opencode github run) modes\n */\n\nimport { spawn, type ChildProcess } from 'child_process'\n\nimport { getEnv } from './env'\nimport { resolveOpenCodeBinary } from './opencode-server'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Options passed to runner.spawn() for server mode */\nexport interface RunnerSpawnOptions {\n /** URL of running OpenCode server to attach to */\n serverUrl?: string\n /** Session ID to fork from (requires serverUrl) */\n sessionId?: string\n /** XDG_DATA_HOME directory — must match the server's data dir for instance lookup */\n dataDir?: string\n}\n\nexport interface RunnerBackend {\n name: string\n spawn(\n stage: string,\n prompt: string,\n env: NodeJS.ProcessEnv,\n cwd: string,\n options?: RunnerSpawnOptions,\n ): ChildProcess\n}\n\n// ============================================================================\n// GitHub Runner (CI mode)\n// ============================================================================\n\nexport class GitHubRunner implements RunnerBackend {\n name = 'opencode-github'\n\n spawn(\n stage: string,\n prompt: string,\n env: NodeJS.ProcessEnv,\n cwd: string,\n options?: RunnerSpawnOptions,\n ): ChildProcess {\n // When attaching to a running server, use the real opencode binary directly.\n // `pnpm exec opencode` resolves to the old opencode-ai npm package which\n // doesn't support --agent + --attach properly. The real binary is installed\n // via `curl -fsSL https://opencode.ai/install | bash` to ~/.opencode/bin/.\n // XDG_DATA_HOME must match the server's data dir for instance lookup.\n if (options?.serverUrl) {\n const args = [\n 'run',\n '--agent',\n stage,\n '--format',\n 'json',\n '--attach',\n options.serverUrl,\n '--dir',\n cwd,\n ]\n if (options.sessionId) args.push('--session', options.sessionId, '--fork')\n args.push(prompt)\n return spawn(resolveOpenCodeBinary(), args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: {\n ...env,\n ...(options.dataDir ? { XDG_DATA_HOME: options.dataDir } : {}),\n },\n })\n }\n\n // Without server: use pnpm exec for backward compatibility\n const args = ['exec', 'opencode', 'run', '--agent', stage, '--format', 'json']\n args.push(prompt)\n return spawn('pnpm', args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n env,\n })\n }\n}\n\n// ============================================================================\n// Local Runner (uses pnpm ocode run)\n// ============================================================================\n\nexport class LocalRunner implements RunnerBackend {\n name = 'opencode-local'\n\n spawn(\n stage: string,\n prompt: string,\n env: NodeJS.ProcessEnv,\n cwd: string,\n options?: RunnerSpawnOptions,\n ): ChildProcess {\n // When attaching to a running server, use the real opencode binary directly.\n // `pnpm ocode` resolves to `pnpm exec opencode` which uses the old opencode-ai\n // npm package. The real binary supports --agent + --attach properly.\n // XDG_DATA_HOME must match the server's data dir for instance lookup.\n if (options?.serverUrl) {\n const args = [\n 'run',\n '--agent',\n stage,\n '--format',\n 'json',\n '--attach',\n options.serverUrl,\n '--dir',\n cwd,\n ]\n if (options.sessionId) args.push('--session', options.sessionId, '--fork')\n args.push(prompt)\n return spawn(resolveOpenCodeBinary(), args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: {\n ...env,\n ...(options.dataDir ? { XDG_DATA_HOME: options.dataDir } : {}),\n AGENT: stage,\n MODEL: env.MODEL,\n },\n })\n }\n\n // Without server: use pnpm ocode for backward compatibility\n const args = ['ocode', 'run', '--agent', stage, '--format', 'json']\n args.push(prompt)\n return spawn('pnpm', args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: {\n ...env,\n AGENT: stage,\n MODEL: env.MODEL,\n },\n })\n }\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\n/**\n * Create a runner backend based on the environment.\n *\n * @param local - If true, uses local runner. If false, uses GitHub runner.\n * If undefined, auto-detects: local when GITHUB_ACTIONS is not set.\n */\nexport function createRunner(local?: boolean): RunnerBackend {\n const env = getEnv()\n const useLocal = local ?? !env.GITHUB_ACTIONS\n\n if (useLocal) {\n return new LocalRunner()\n }\n return new GitHubRunner()\n}\n","/**\n * @fileType configuration\n * @domain kody | pipeline\n * @pattern named-constants\n * @ai-summary Centralized named constants for the Kody pipeline — replaces scattered magic numbers\n */\n\n// --- Loop & Retry Limits ---\n\n/** Max iterations of the main state-machine loop before circuit-breaking */\nexport const MAX_PIPELINE_LOOP_ITERATIONS = 200\n\n/** Default max verify→fix loop iterations */\nexport const DEFAULT_MAX_FIX_ATTEMPTS = 1\n\n/** Max build→quality-gate feedback loops */\nexport const MAX_BUILD_FEEDBACK_LOOPS = 2\n\n/** State recovery check frequency (every N loop iterations) */\nexport const RECOVERY_CHECK_INTERVAL = 10\n\n// --- Output Truncation ---\n\n/** Max chars for gate output in verify-failures.md */\nexport const MAX_GATE_OUTPUT_CHARS = 5000\n\n/** Max chars for passed gate output in verify report */\nexport const MAX_PASSED_GATE_OUTPUT_CHARS = 1000\n\n/** Max chars for failed gate output in verify report */\nexport const MAX_FAILED_GATE_OUTPUT_CHARS = 5000\n\n/** Max chars for gate output written to file */\nexport const MAX_GATE_FILE_OUTPUT_CHARS = 10_000\n\n/** Max chars for tsc/test error output in build feedback */\nexport const MAX_QUALITY_ERROR_OUTPUT_CHARS = 3000\n\n/** Max chars for agent text display in logs */\nexport const MAX_AGENT_DISPLAY_TEXT_CHARS = 300\n\n// --- Process Lifecycle ---\n\n/** Grace period (ms) before SIGKILL after SIGTERM */\nexport const SIGKILL_GRACE_MS = 5000\n\n/** Delay (ms) between agent retries */\nexport const AGENT_RETRY_DELAY_MS = 2000\n\n/** Number of stderr tail lines to capture */\nexport const STDERR_TAIL_LINES = 50\n\n// --- Git & PR ---\n\n/** Max PR title length */\nexport const MAX_PR_TITLE_LENGTH = 72\n\n/** Max spec summary length in PR body */\nexport const MAX_SPEC_SUMMARY_LENGTH = 500\n\n// --- Actor History ---\n\n/** Max entries in the actorHistory audit trail */\nexport const MAX_ACTOR_HISTORY_ENTRIES = 50\n","/**\n * @fileType types\n * @domain kody | engine\n * @pattern state-machine\n * @ai-summary Core types for the Kody pipeline state machine architecture\n */\n\nimport { z } from 'zod'\nimport type { StageName } from '../stages/registry'\n\n// ============================================================================\n// Stage Types\n// ============================================================================\n\nexport type StageType = 'agent' | 'scripted' | 'git' | 'gate'\n\nexport type StageOutcome = 'completed' | 'failed' | 'paused' | 'timed_out' | 'skipped'\n\nexport interface StageResult {\n outcome: StageOutcome\n reason?: string\n retries: number\n outputFile?: string\n /** Token usage for this stage */\n tokenUsage?: { input: number; output: number; cacheRead: number }\n /** Cost in USD for this stage */\n cost?: number\n /** OpenCode session ID for this stage */\n sessionId?: string\n}\n\n// ============================================================================\n// Stage Definition\n// ============================================================================\n\nexport interface SkipResult {\n shouldSkip: boolean\n reason?: string\n}\n\n// Re-export ValidationResult from agent-runner\nimport type { ValidationResult } from '../agent-runner'\nexport type { ValidationResult }\n\n/**\n * Optional preExecute hook that runs before the handler.\n * Used by build stage for ensureFeatureBranch.\n */\nexport type StagePreExecute = (ctx: PipelineContext) => Promise<void>\n\nexport interface StageDefinition {\n name: StageName\n type: StageType\n timeout: number\n maxRetries: number\n shouldSkip?: (ctx: PipelineContext) => SkipResult\n validator?: (outputFile: string) => ValidationResult\n postActions?: PostAction[]\n advisory?: boolean\n preExecute?: StagePreExecute\n /**\n * Minimum complexity score (1-100) for this stage to run.\n * Informational only — actual routing uses STAGE_COMPLEXITY_THRESHOLDS\n * in skip-conditions.ts. Keep in sync with STAGE_COMPLEXITY_THRESHOLDS.\n */\n minComplexity?: number\n /**\n * Called when agent exits 0 but doesn't produce the expected output file.\n * Returns the fallback content to write, or null to proceed with normal retry/fail.\n */\n fallbackOnMissingOutput?: (ctx: PipelineContext) => string | null\n /**\n * Override the agent name used by opencode. Defaults to stage name.\n * Used when a stage should run a different agent (e.g., fix stage runs build agent).\n */\n agentName?: string\n /**\n * Declarative retry loop: when this stage fails, reset both this stage\n * and `retryWith.stage` to pending, up to `retryWith.maxAttempts` times.\n */\n retryWith?: {\n stage: StageName\n maxAttempts: number\n /** Called before retry to capture failure details (e.g., write verify-failures.md) */\n onFailure?: (ctx: PipelineContext, taskDir: string) => Promise<void>\n /** When the retryWith.stage times out: 'retry' resets this stage to pending; 'fail' fails the pipeline */\n onTimeout?: 'retry' | 'fail'\n }\n}\n\n// ============================================================================\n// Pipeline Definition\n// ============================================================================\n\nexport type PipelineStep = StageName | { parallel: StageName[] }\n\nexport interface PipelineDefinition {\n stages: Map<StageName, StageDefinition>\n order: PipelineStep[]\n}\n\n// ============================================================================\n// Pipeline Context\n// ============================================================================\n\nimport type { KodyInput } from '../kody-utils'\nimport type { TaskDefinition } from '../pipeline-utils'\nimport type { RunnerBackend } from '../runner-backend'\n\nexport interface PipelineContext {\n taskId: string\n taskDir: string\n input: KodyInput\n taskDef: TaskDefinition | null\n profile: 'standard' | 'lightweight' | 'turbo'\n backend: RunnerBackend\n // Set by resolve-profile post-action to signal engine to rebuild pipeline\n pipelineNeedsRebuild?: boolean\n /** URL of the running OpenCode server (e.g., 'http://localhost:4097') */\n serverUrl?: string\n /** Most recent agent stage's sessionID — downstream stages fork from this */\n lastSessionId?: string\n /** GitHub login of the person who triggered this run (from GITHUB_ACTOR env var) */\n actor?: string\n}\n\n// Note: NO controlMode field — each gate resolves it dynamically via\n// resolveControlMode(ctx.taskDef, ctx.input.controlMode) (G42)\n\n// ============================================================================\n// Pipeline State V2 (status.json schema)\n// ============================================================================\n\nexport interface StageStateV2 {\n state:\n | 'pending'\n | 'running'\n | 'completed'\n | 'failed'\n | 'timeout'\n | 'skipped'\n | 'paused'\n | 'observing'\n startedAt?: string\n completedAt?: string\n elapsed?: number\n retries: number\n outputFile?: string\n skipped?: string\n error?: string\n feedbackLoops?: number\n feedbackErrors?: string[]\n /** Current fix attempt number (for verify→fix loop) */\n fixAttempt?: number\n /** Maximum allowed fix attempts (for verify→fix loop) */\n maxFixAttempts?: number\n /** Whether the review stage found issues that need fixing */\n issuesFound?: boolean\n /** Review summary counts */\n reviewSummary?: {\n critical: number\n major: number\n minor: number\n }\n /** Token usage for cost tracking */\n tokenUsage?: { input: number; output: number; cacheRead: number }\n /** Cost in USD */\n cost?: number\n /** OpenCode session ID for rerun recovery */\n sessionId?: string\n}\n\n/** A single actor event in the pipeline audit trail */\nexport interface ActorEvent {\n /** Action type: pipeline-triggered, gate-approved, gate-rejected, stage-retried, etc. */\n action: string\n /** GitHub login of the person who performed the action */\n actor: string\n /** ISO timestamp */\n timestamp: string\n /** Stage name, if action is stage-specific */\n stage?: string\n}\n\nexport interface PipelineStateV2 {\n version: 2\n taskId: string\n mode: string\n pipeline: string\n startedAt: string\n updatedAt: string\n completedAt?: string\n totalElapsed?: number\n state: 'running' | 'completed' | 'failed' | 'timeout' | 'paused'\n cursor: StageName | null\n stages: Record<string, StageStateV2>\n /** GitHub issue number that triggered this pipeline run */\n issueNumber?: number\n /** Git branch name created for this task (set after ensureFeatureBranch) */\n branchName?: string\n /** Total accumulated cost across all stages in USD */\n totalCost?: number\n /** GitHub login of the person who triggered this pipeline run */\n triggeredBy?: string\n /** GitHub login of the person who created the issue (the \"owner\") */\n issueCreator?: string\n /** Audit trail of actor actions. Capped at 50 entries (oldest dropped first). */\n actorHistory?: ActorEvent[]\n}\n\n// Zod schema for PipelineStateV2\n// Note: Uses z.string() for cursor (not StageName) for backward compat with existing status.json files\nexport const PipelineStateV2Schema = z.object({\n version: z.literal(2),\n taskId: z.string(),\n mode: z.string(),\n pipeline: z.string(),\n startedAt: z.string(),\n updatedAt: z.string(),\n completedAt: z.string().optional(),\n totalElapsed: z.number().optional(),\n state: z.enum(['running', 'completed', 'failed', 'timeout', 'paused']),\n cursor: z.string().nullable(),\n issueNumber: z.number().optional(),\n branchName: z.string().optional(),\n totalCost: z.number().optional(),\n stages: z.record(\n z.string(),\n z.object({\n state: z.enum([\n 'pending',\n 'running',\n 'completed',\n 'failed',\n 'timeout',\n 'skipped',\n 'paused',\n 'observing',\n ]),\n startedAt: z.string().optional(),\n completedAt: z.string().optional(),\n elapsed: z.number().optional(),\n retries: z.number(),\n outputFile: z.string().optional(),\n skipped: z.string().optional(),\n error: z.string().optional(),\n feedbackLoops: z.number().optional(),\n feedbackErrors: z.array(z.string()).optional(),\n fixAttempt: z.number().optional(),\n maxFixAttempts: z.number().optional(),\n issuesFound: z.boolean().optional(),\n reviewSummary: z\n .object({\n critical: z.number(),\n major: z.number(),\n minor: z.number(),\n })\n .optional(),\n tokenUsage: z\n .object({\n input: z.number(),\n output: z.number(),\n cacheRead: z.number(),\n })\n .optional(),\n cost: z.number().optional(),\n sessionId: z.string().optional(),\n }),\n ),\n triggeredBy: z.string().optional(),\n issueCreator: z.string().optional(),\n actorHistory: z\n .array(\n z.object({\n action: z.string(),\n actor: z.string(),\n timestamp: z.string(),\n stage: z.string().optional(),\n }),\n )\n .optional(),\n})\n\n/**\n * Type guard to validate v2 status.json format\n */\nexport function isPipelineStateV2(obj: unknown): obj is PipelineStateV2 {\n if (!obj || typeof obj !== 'object') return false\n const result = PipelineStateV2Schema.safeParse(obj)\n return result.success\n}\n\n// ============================================================================\n// Post-Action Types\n// ============================================================================\n\n/**\n * Enum-like union of all post-action type strings.\n * Used for classification (blocking vs advisory) and switch statements.\n */\nexport type PostActionType =\n | 'validate-task-json'\n | 'set-classification-labels'\n | 'resolve-profile'\n | 'check-gate'\n | 'commit-task-files'\n | 'archive-rerun-feedback'\n | 'validate-plan-exists'\n | 'validate-build-content'\n | 'validate-src-changes'\n | 'run-tsc'\n | 'run-unit-tests'\n | 'run-quality-with-autofix'\n | 'analyze-review-findings'\n | 'clear-verify-failures'\n | 'run-mechanical-autofix'\n | 'parallel'\n\n/**\n * Post-actions that block pipeline progression on failure.\n * These failures cause the pipeline to stop and require user intervention.\n */\nexport const BLOCKING_POST_ACTIONS: PostActionType[] = [\n 'validate-task-json',\n 'resolve-profile',\n 'check-gate',\n 'commit-task-files',\n 'validate-plan-exists',\n 'validate-build-content',\n 'validate-src-changes',\n]\n\n/**\n * Returns true if the given post-action is blocking (fails the pipeline).\n * Advisory actions log warnings but don't stop the pipeline.\n */\nexport function isBlockingPostAction(action: PostAction): boolean {\n return BLOCKING_POST_ACTIONS.includes(action.type as PostActionType)\n}\n\n// Validate-task-json action\nexport type ValidateTaskJsonAction = {\n type: 'validate-task-json'\n}\n\n// Set-classification-labels action\nexport type SetClassificationLabelsAction = {\n type: 'set-classification-labels'\n}\n\n// Resolve-profile action\nexport type ResolveProfileAction = {\n type: 'resolve-profile'\n}\n\n// Check-gate action\nexport type CheckGateAction = {\n type: 'check-gate'\n gate: string\n includeArtifact?: string // e.g., 'plan.md' for architect gate\n}\n\n// Commit-task-files action\nexport type CommitTaskFilesAction = {\n type: 'commit-task-files'\n stagingStrategy: 'task-only' | 'tracked-only' | 'tracked+task'\n push: boolean\n ensureBranch: boolean\n cleanDirtyState?: boolean\n commitMessage?: string\n localOnly?: boolean // G18: only commit in local mode\n}\n\n// Archive-rerun-feedback action\nexport type ArchiveRerunFeedbackAction = {\n type: 'archive-rerun-feedback'\n}\n\n// Validate-plan-exists action\nexport type ValidatePlanExistsAction = {\n type: 'validate-plan-exists'\n}\n\n// Validate-build-content action\nexport type ValidateBuildContentAction = {\n type: 'validate-build-content'\n}\n\n// Run-tsc action\nexport type RunTscAction = {\n type: 'run-tsc'\n}\n\n// Run-unit-tests action\nexport type RunUnitTestsAction = {\n type: 'run-unit-tests'\n}\n\n// Run-quality-with-autofix action — feedback loop that retries with autofix agent\nexport type RunQualityWithAutofixAction = {\n type: 'run-quality-with-autofix'\n gates: Array<{ name: string; command: string; source: 'tsc' | 'lint' | 'format' | 'test' }>\n maxFeedbackLoops: number\n}\n\n// Validate-src-changes action — ensures build agent modified source files\nexport type ValidateSrcChangesAction = {\n type: 'validate-src-changes'\n}\n\n// Analyze-review-findings action - parses review.md to determine if fix needed\nexport type AnalyzeReviewFindingsAction = {\n type: 'analyze-review-findings'\n}\n\n// Clear-verify-failures action - clears previous verify failures for retry\nexport type ClearVerifyFailuresAction = {\n type: 'clear-verify-failures'\n}\n\n// Run-mechanical-autofix action — runs lint:fix + format:fix deterministically (no LLM)\nexport type RunMechanicalAutofixAction = {\n type: 'run-mechanical-autofix'\n}\n\n// Update-knowledge-base action — updates cross-task knowledge base after completion\nexport type UpdateKnowledgeBaseAction = {\n type: 'update-knowledge-base'\n}\n\n// Parallel-post-action - runs multiple actions concurrently\nexport type ParallelPostAction = {\n type: 'parallel'\n actions: PostAction[]\n}\n\n// Post-action discriminated union\nexport type PostAction =\n | ValidateTaskJsonAction\n | SetClassificationLabelsAction\n | ResolveProfileAction\n | CheckGateAction\n | CommitTaskFilesAction\n | ArchiveRerunFeedbackAction\n | ValidatePlanExistsAction\n | ValidateBuildContentAction\n | ValidateSrcChangesAction\n | RunTscAction\n | RunUnitTestsAction\n | RunQualityWithAutofixAction\n | AnalyzeReviewFindingsAction\n | ClearVerifyFailuresAction\n | RunMechanicalAutofixAction\n | UpdateKnowledgeBaseAction\n | ParallelPostAction\n\n// ============================================================================\n// Lifecycle Hooks\n// ============================================================================\n\nexport interface LifecycleHooks {\n onStateChange?: (\n prevState: PipelineStateV2 | null,\n nextState: PipelineStateV2,\n ctx: PipelineContext,\n ) => void\n}\n\n// ============================================================================\n// Pipeline Paused Error\n// ============================================================================\n\n/**\n * Thrown when the pipeline intentionally pauses (e.g., hard-stop / risk gate).\n * Caught in main() to post a ⏸️ comment instead of ✅ completed.\n */\nexport class PipelinePausedError extends Error {\n constructor(reason: string) {\n super(reason)\n this.name = 'PipelinePausedError'\n }\n}\n\n// ============================================================================\n// Re-exports from other modules for convenience\n// ============================================================================\n\n// Re-export KodyInput for use throughout the engine\nexport type { KodyInput } from '../kody-utils'\n\n// Re-export ControlMode and TaskDefinition from pipeline-utils\nexport type { ControlMode, TaskDefinition } from '../pipeline-utils'\n","/**\n * @fileType utility\n * @domain kody | engine\n * @pattern status-tracking\n * @ai-summary Status.json v2 operations with mandatory Zod validation\n */\n\nimport { logger } from '../logger'\nimport { MAX_ACTOR_HISTORY_ENTRIES } from '../config/constants'\nimport type { StageName } from '../stages/registry'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport {\n PipelineStateV2,\n isPipelineStateV2,\n type PipelineContext,\n type StageStateV2,\n type ActorEvent,\n} from './types'\n\n// C3 FIX: Import stageOutputFile for correct path resolution in resetFromStage\nimport { stageOutputFile } from '../stages/registry'\n\n// ============================================================================\n// Status File Operations\n// ============================================================================\n\n/**\n * Get the status file path for a task\n */\nfunction getStatusFilePath(taskId: string): string {\n const taskDir = path.join(process.cwd(), '.tasks', taskId)\n return path.join(taskDir, 'status.json')\n}\n\n/**\n * Load state from status.json with mandatory Zod validation.\n * Returns null on missing file, invalid JSON, or failed validation.\n */\nexport function loadState(taskId: string): PipelineStateV2 | null {\n const statusFile = getStatusFilePath(taskId)\n\n if (!fs.existsSync(statusFile)) {\n return null\n }\n\n try {\n const content = fs.readFileSync(statusFile, 'utf-8')\n const parsed = JSON.parse(content)\n\n // Validate with Zod schema\n if (!isPipelineStateV2(parsed)) {\n logger.warn(`Status file for ${taskId} is not valid v2 format, ignoring`)\n return null\n }\n\n return parsed\n } catch (error) {\n logger.warn({ err: error }, `Failed to load status for ${taskId}`)\n return null\n }\n}\n\n/**\n * Atomic write with fsync: write to temp file, flush to disk, then rename\n * to prevent corruption if the process is killed mid-write.\n */\nexport function writeState(taskId: string, state: PipelineStateV2): void {\n const statusFile = getStatusFilePath(taskId)\n const tmpFile = statusFile + '.tmp'\n\n // Ensure directory exists\n const dir = path.dirname(statusFile)\n if (!fs.existsSync(dir)) {\n try {\n fs.mkdirSync(dir, { recursive: true })\n } catch (err) {\n throw new Error(`Failed to create status directory ${dir}: ${err}`)\n }\n }\n\n // Atomic write with fsync: write to temp file, flush to disk, then rename\n const data = JSON.stringify(state, null, 2)\n const fd = fs.openSync(tmpFile, 'w')\n try {\n fs.writeSync(fd, data)\n fs.fdatasyncSync(fd)\n } finally {\n fs.closeSync(fd)\n }\n fs.renameSync(tmpFile, statusFile)\n}\n\n/**\n * Delete the status.json file for a task.\n * Used by `full` mode to discard failed/completed state from a previous run\n * so that the pipeline starts fresh instead of short-circuiting.\n */\nexport function deleteState(taskId: string): void {\n const statusFile = getStatusFilePath(taskId)\n if (fs.existsSync(statusFile)) {\n fs.unlinkSync(statusFile)\n logger.info(`Deleted previous status.json for ${taskId} (fresh full-mode run)`)\n }\n}\n\n/**\n * Initialize a fresh v2 state\n */\nexport function initState(ctx: PipelineContext, mode: string): PipelineStateV2 {\n const now = new Date().toISOString()\n\n const actorHistory: ActorEvent[] = ctx.actor\n ? [{ action: 'pipeline-triggered', actor: ctx.actor, timestamp: now }]\n : []\n\n const state: PipelineStateV2 = {\n version: 2,\n taskId: ctx.taskId,\n mode,\n pipeline: 'spec_execute_verify', // will be updated after taskify\n startedAt: now,\n updatedAt: now,\n state: 'running',\n cursor: null,\n stages: {},\n // Persist issue number for dashboard lookups (avoids Compare API)\n ...(ctx.input.issueNumber ? { issueNumber: ctx.input.issueNumber } : {}),\n ...(ctx.actor ? { triggeredBy: ctx.actor } : {}),\n ...(ctx.input.issueCreator ? { issueCreator: ctx.input.issueCreator } : {}),\n ...(actorHistory.length > 0 ? { actorHistory } : {}),\n }\n\n writeState(ctx.taskId, state)\n return state\n}\n\n/** Max actor history entries kept in status.json (oldest dropped when exceeded) */\nconst MAX_ACTOR_HISTORY = MAX_ACTOR_HISTORY_ENTRIES\n\n/**\n * Append an actor event to the pipeline's actorHistory in status.json.\n * Automatically trims to MAX_ACTOR_HISTORY entries.\n */\nexport function appendActorEvent(\n taskId: string,\n state: PipelineStateV2,\n event: ActorEvent,\n): PipelineStateV2 {\n const existing = state.actorHistory ?? []\n const updated = [...existing, event]\n // Keep most recent MAX_ACTOR_HISTORY entries\n const trimmed = updated.length > MAX_ACTOR_HISTORY ? updated.slice(-MAX_ACTOR_HISTORY) : updated\n\n const newState: PipelineStateV2 = {\n ...state,\n actorHistory: trimmed,\n updatedAt: new Date().toISOString(),\n }\n writeState(taskId, newState)\n return newState\n}\n\n/**\n * Update the branchName in status.json after ensureFeatureBranch derives it.\n * Called from the build stage preExecute hook.\n */\nexport function setBranchName(\n taskId: string,\n state: PipelineStateV2,\n branchName: string,\n): PipelineStateV2 {\n const updated: PipelineStateV2 = {\n ...state,\n branchName,\n updatedAt: new Date().toISOString(),\n }\n writeState(taskId, updated)\n return updated\n}\n\n/**\n * Immutable update: returns a new state with the stage updated\n */\nexport function updateStage(\n state: PipelineStateV2,\n stageName: string,\n update: Partial<StageStateV2>,\n): PipelineStateV2 {\n const now = new Date().toISOString()\n\n // Create new stages object with the updated stage\n const newStages: Record<string, StageStateV2> = {}\n\n for (const [name, stage] of Object.entries(state.stages)) {\n if (name === stageName) {\n newStages[name] = {\n ...stage,\n ...update,\n }\n } else {\n newStages[name] = stage\n }\n }\n\n // If the stage didn't exist, create it\n if (!state.stages[stageName]) {\n newStages[stageName] = {\n state: update.state || 'pending',\n retries: 0,\n ...update,\n }\n }\n\n return {\n ...state,\n stages: newStages,\n updatedAt: now,\n }\n}\n\n/**\n * Mark pipeline as completed/failed/paused\n */\nexport function completeState(\n state: PipelineStateV2,\n finalState: 'completed' | 'failed' | 'timeout' | 'paused',\n): PipelineStateV2 {\n const now = new Date().toISOString()\n\n // Compute total cost across all stages\n let totalCost = 0\n for (const stage of Object.values(state.stages)) {\n if (stage.cost) {\n totalCost += stage.cost\n }\n }\n\n return {\n ...state,\n state: finalState,\n completedAt: now,\n updatedAt: now,\n ...(totalCost > 0 ? { totalCost } : {}),\n }\n}\n\n// ============================================================================\n// Recovery Functions - handle stale state from interrupted runs\n// ============================================================================\n\n/**\n * Recover stale stages: reset any stage stuck in \"running\" state to \"pending\".\n * This handles cases where the pipeline was killed mid-execution.\n *\n * Returns a new state object (immutable). If no stale stages found, returns\n * the input state unchanged.\n */\nexport function recoverStaleStages(state: PipelineStateV2): PipelineStateV2 {\n let hasChanges = false\n const newStages: Record<string, StageStateV2> = {}\n\n for (const [name, stage] of Object.entries(state.stages)) {\n if (stage.state === 'running') {\n // Reset stale running stage to pending\n newStages[name] = {\n ...stage,\n state: 'pending',\n startedAt: undefined,\n }\n logger.info(`⚠️ Recovered stale stage ${name}: running → pending`)\n hasChanges = true\n } else {\n newStages[name] = stage\n }\n }\n\n if (!hasChanges) {\n // No changes, return original state\n return state\n }\n\n return {\n ...state,\n stages: newStages,\n updatedAt: new Date().toISOString(),\n }\n}\n\n/**\n * Recover pipeline state: if all stages in the pipeline order are completed/skipped,\n * mark the pipeline as completed. If any non-advisory stage failed, mark as failed.\n *\n * Only acts when pipeline state is \"running\" - leaves completed/failed/paused states unchanged.\n *\n * @param state - The current pipeline state\n * @param pipelineOrder - Flat list of stage names in execution order\n * @param advisoryStages - Set of stage names that are advisory (failures don't fail pipeline)\n */\nexport function recoverPipelineState(\n state: PipelineStateV2,\n pipelineOrder: string[],\n advisoryStages: Set<string>,\n): PipelineStateV2 {\n // Only recover if pipeline is stuck in \"running\" state\n if (state.state !== 'running') {\n return state\n }\n\n // Check stages that are in the pipeline order\n let allCompletedOrSkipped = true\n let hasNonAdvisoryFailure = false\n\n for (const stageName of pipelineOrder) {\n const stage = state.stages[stageName]\n\n if (!stage) {\n // Stage not in state - still needs to run\n allCompletedOrSkipped = false\n continue\n }\n\n if (stage.state === 'pending' || stage.state === 'running') {\n // Stage hasn't completed yet\n allCompletedOrSkipped = false\n } else if (stage.state === 'failed') {\n // Check if this is an advisory failure\n if (!advisoryStages.has(stageName)) {\n hasNonAdvisoryFailure = true\n }\n // Advisory failures are OK - continue checking\n }\n // 'completed' and 'skipped' are fine - continue checking\n }\n\n // Determine new pipeline state\n if (hasNonAdvisoryFailure) {\n logger.info(`⚠️ Recovered pipeline state: running → failed (non-advisory stage failed)`)\n return completeState(state, 'failed')\n }\n\n if (allCompletedOrSkipped) {\n logger.info(`⚠️ Recovered pipeline state: running → completed (all stages done)`)\n return completeState(state, 'completed')\n }\n\n // Pipeline still has pending/running stages - leave as running\n return state\n}\n\n/**\n * Resume pipeline from a gate pause. Immutably marks the gate stage as completed\n * and resets the pipeline state to 'running' (removing completedAt).\n *\n * This replaces direct state mutation that was previously in entry.ts:454-461.\n */\nexport function resumeFromGate(state: PipelineStateV2, gateStageName: string): PipelineStateV2 {\n // Use updateStage for immutable stage update\n const updatedState = updateStage(state, gateStageName, {\n state: 'completed',\n completedAt: new Date().toISOString(),\n })\n\n // Reset pipeline from paused to running, remove completedAt\n const { completedAt: _, ...rest } = updatedState\n return {\n ...rest,\n state: 'running',\n updatedAt: new Date().toISOString(),\n }\n}\n\n/**\n * Reset stages from a given point onwards to pending.\n * Also deletes output files for reset stages (G37).\n *\n * C3 FIX: Uses stageOutputFile() instead of hardcoded `${stage}.md`\n * to correctly resolve output file paths for all stages\n * (e.g., taskify→task.json, architect→plan.md, etc.)\n */\nexport function resetFromStage(\n state: PipelineStateV2,\n fromStage: string,\n pipeline: string[],\n taskDir: string,\n): PipelineStateV2 {\n const now = new Date().toISOString()\n\n // Find the index of the fromStage\n const fromIndex = pipeline.indexOf(fromStage)\n if (fromIndex === -1) {\n // Stage not found, return original state\n return state\n }\n\n // Get stages to reset\n const stagesToReset = pipeline.slice(fromIndex)\n\n // C3 FIX: Delete output files using stageOutputFile for correct paths\n // Previously used `${stage}.md` which is wrong for stages like:\n // - taskify → task.json\n // - architect → plan.md\n // - clarify → questions.md\n // - commit → commit.md\n for (const stage of stagesToReset) {\n const outputFile = stageOutputFile(taskDir, stage)\n if (fs.existsSync(outputFile)) {\n fs.unlinkSync(outputFile)\n }\n }\n\n // Reset stages to pending\n const newStages: Record<string, StageStateV2> = {}\n\n // FIX #827: Stages BEFORE fromStage that are still 'paused' should be marked\n // 'completed' — if later stages ran, the paused stage must have been approved.\n // This prevents stale 'paused' states from causing reruns to re-trigger gates.\n const stagesBefore = pipeline.slice(0, fromIndex)\n\n for (const [name, stage] of Object.entries(state.stages)) {\n if (stagesToReset.includes(name)) {\n // Reset this stage to pending\n newStages[name] = {\n state: 'pending',\n retries: 0,\n }\n } else if (stagesBefore.includes(name) && stage.state === 'paused') {\n // Stale paused stage — later stages ran, so this must have been approved\n newStages[name] = {\n ...stage,\n state: 'completed',\n completedAt: stage.completedAt || now,\n }\n } else {\n // Keep existing stage\n newStages[name] = stage\n }\n }\n\n return {\n ...state,\n stages: newStages,\n state: 'running',\n cursor: fromStage as StageName,\n updatedAt: now,\n }\n}\n\n// ============================================================================\n// V1 Adapter for backward compatibility with formatStatusComment\n// ============================================================================\n\nimport type { KodyPipelineStatus, StageStatus } from '../kody-utils'\n\n/**\n * Convert v2 state to v1 format for formatStatusComment compatibility\n */\nexport function stateToV1(state: PipelineStateV2): KodyPipelineStatus {\n const v1Stages: Record<string, StageStatus> = {}\n\n for (const [name, stage] of Object.entries(state.stages)) {\n v1Stages[name] = {\n state:\n stage.state === 'paused'\n ? 'gate-waiting'\n : stage.state === 'observing'\n ? 'running'\n : stage.state,\n startedAt: stage.startedAt,\n completedAt: stage.completedAt,\n elapsed: stage.elapsed,\n retries: stage.retries,\n outputFile: stage.outputFile,\n skipped: stage.skipped,\n error: stage.error,\n tokenUsage: stage.tokenUsage\n ? { input: stage.tokenUsage.input, output: stage.tokenUsage.output }\n : undefined,\n cost: stage.cost,\n }\n }\n\n return {\n taskId: state.taskId,\n mode: state.mode,\n pipeline: state.pipeline,\n startedAt: state.startedAt,\n updatedAt: state.updatedAt,\n completedAt: state.completedAt,\n totalElapsed: state.totalElapsed,\n state: state.state,\n currentStage: state.cursor,\n stages: v1Stages,\n triggeredBy: state.triggeredBy ?? 'dispatch',\n issueNumber: state.issueNumber,\n runId: undefined,\n runUrl: undefined,\n controlMode: undefined,\n gatePoint: undefined,\n botCommentId: undefined,\n totalCost: state.totalCost,\n triggeredByLogin: state.triggeredBy,\n issueCreator: state.issueCreator,\n actorHistory: state.actorHistory,\n }\n}\n","/**\n * @fileType utility\n * @domain ci | kody | git\n * @pattern branch-management\n * @ai-summary Git utilities for feature branch creation in Kody scripts\n */\n\nimport { logger } from './logger'\nimport { execFileSync } from 'child_process'\nimport * as fs from 'fs'\nimport * as path from 'path'\n// FIX #9: Import status functions to persist branch name early\nimport { setBranchName, loadState } from './engine/status'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type TaskType =\n | 'spec_only'\n | 'implement_feature'\n | 'fix_bug'\n | 'refactor'\n | 'docs'\n | 'ops'\n | 'research'\n\n// ============================================================================\n// Branch Prefix Map\n// ============================================================================\n\nexport const BRANCH_PREFIX_MAP: Record<TaskType, string> = {\n spec_only: 'feat',\n implement_feature: 'feat',\n fix_bug: 'fix',\n refactor: 'refactor',\n docs: 'docs',\n ops: 'chore',\n research: 'feat',\n}\n\n// ============================================================================\n// Commit Type Map\n// ============================================================================\n\nexport const COMMIT_TYPE_MAP: Record<TaskType, string> = {\n spec_only: 'docs',\n implement_feature: 'feat',\n fix_bug: 'fix',\n refactor: 'refactor',\n docs: 'docs',\n ops: 'chore',\n research: 'chore',\n}\n\n/** Directories to stage new files from (safe - excludes secrets) */\nexport const SAFE_STAGE_DIRS = ['src/', 'tests/', '.tasks/']\n\n/** Well-known base branches — if the current branch is one of these, create a feature branch */\nconst BASE_BRANCHES = ['dev', 'main', 'master', '']\n\n// ============================================================================\n// Branch Name Derivation\n// ============================================================================\n\n/**\n * Derive a descriptive branch name from task.md\n * Returns: prefix/260225-description-from-title\n * Falls back to taskId if derivation fails\n */\nexport function deriveBranchName(taskDir: string, taskId: string): string {\n const taskMdPath = path.join(taskDir, 'task.md')\n\n if (!fs.existsSync(taskMdPath)) {\n return taskId\n }\n\n try {\n const content = fs.readFileSync(taskMdPath, 'utf-8')\n\n // Try to extract ## Issue Title first (highest priority)\n let title = ''\n const issueTitleMatch = content.match(/^##\\s*Issue\\s*Title\\s*\\n+([^\\n]+)/im)\n if (issueTitleMatch) {\n title = issueTitleMatch[1].trim()\n }\n\n // Fallback: get first meaningful line (skip # Task, headers)\n if (!title) {\n const lines = content.split('\\n')\n for (const line of lines) {\n const trimmed = line.trim()\n // Skip headers, empty lines\n if (trimmed && !trimmed.startsWith('#') && !trimmed.startsWith('##')) {\n title = trimmed\n break\n }\n }\n }\n\n if (!title) {\n return taskId\n }\n\n // Prepend date prefix from taskId for uniqueness\n const datePrefix = taskId.split('-').slice(0, 2).join('-') // e.g., \"260225-auto\"\n\n // Include issue number in branch name for disambiguation\n // Without this, findRemoteBranch() cannot distinguish branches created on the same day\n // for different issues (e.g., feat/260227-auto-... vs fix/260227-auto-...)\n const issueNum = process.env.ISSUE_NUMBER\n const issuePart = issueNum ? `-${issueNum}` : ''\n const maxTitleLength = 50 - datePrefix.length - issuePart.length - 1 // minus 1 for the hyphen\n\n // Sanitize: lowercase, replace spaces/special chars with hyphens, remove non-alphanumeric\n const sanitized = title\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, '') // keep only alphanumeric, spaces, hyphens\n .replace(/\\s+/g, '-') // spaces to hyphens\n .replace(/-+/g, '-') // multiple hyphens to one\n .replace(/^-|-$/g, '') // trim leading/trailing hyphens\n .slice(0, maxTitleLength) // max chars for title portion\n\n return `${datePrefix}${issuePart}-${sanitized}`\n } catch (deriveErr) {\n // FIX #7: Log when branch name derivation falls back to taskId\n logger.warn(\n { err: deriveErr },\n `[branch] Branch name derivation failed, falling back to: ${taskId}`,\n )\n return taskId\n }\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Detect the default branch of the remote repository.\n * Uses `git remote show origin` to find the HEAD branch.\n * Falls back to 'dev' if detection fails (common for this project).\n */\nexport function getDefaultBranch(cwd: string = process.cwd()): string {\n try {\n // Use symbolic-ref which is faster and more reliable than parsing `git remote show origin`\n const ref = execFileSync('git', ['symbolic-ref', 'refs/remotes/origin/HEAD'], {\n cwd,\n encoding: 'utf-8',\n stdio: 'pipe',\n }).trim()\n // ref is like \"refs/remotes/origin/dev\" — extract the branch name\n const branch = ref.replace('refs/remotes/origin/', '')\n if (branch) return branch\n } catch {\n // symbolic-ref may fail if HEAD ref hasn't been set\n }\n\n try {\n // Fallback: parse `git remote show origin` output\n const output = execFileSync('git', ['remote', 'show', 'origin'], {\n cwd,\n encoding: 'utf-8',\n stdio: 'pipe',\n timeout: 10_000,\n })\n const match = output.match(/HEAD branch:\\s*(\\S+)/)\n if (match?.[1]) return match[1]\n } catch {\n // Remote may be unreachable\n }\n\n return 'dev'\n}\n\n/**\n * Merge the default branch into the current branch.\n * This keeps the feature branch up-to-date with the latest changes from dev.\n * If a merge conflict occurs, aborts the merge and throws an error.\n */\n/**\n * Find and checkout a remote branch matching the given task ID.\n * Used by rerun mode to ensure task files are available before reading them.\n * Unlike ensureFeatureBranch, this doesn't need taskType — it searches all\n * remote branches for the task ID pattern.\n *\n * @returns true if a branch was found and checked out, false if not found\n */\nexport function checkoutTaskBranch(taskId: string, taskDir?: string): boolean {\n const cwd = process.cwd()\n const currentBranch = execFileSync('git', ['branch', '--show-current'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n\n // Already on a feature branch — don't switch\n if (!BASE_BRANCHES.includes(currentBranch)) {\n logger.info(`[branch] Already on feature branch: ${currentBranch}`)\n return true\n }\n\n // Fetch latest\n try {\n execFileSync('git', ['fetch', 'origin'], { cwd, stdio: 'inherit', timeout: 120_000 })\n } catch (fetchErr) {\n logger.warn({ err: fetchErr }, '[branch] git fetch failed')\n return false\n }\n\n // Search remote branches for one containing the task ID\n let remoteBranches: string[]\n try {\n const output = execFileSync('git', ['branch', '-r', '--list', `origin/*${taskId}*`], {\n cwd,\n encoding: 'utf-8',\n stdio: 'pipe',\n }).trim()\n remoteBranches = output\n .split('\\n')\n .map((b) => b.trim().replace('origin/', ''))\n .filter(Boolean)\n } catch {\n remoteBranches = []\n }\n\n if (remoteBranches.length === 0) {\n logger.info(`[branch] No remote branch found matching task ID: ${taskId}`)\n return false\n }\n\n // Use the first match (there should only be one branch per task)\n const branchName = remoteBranches[0]\n logger.info(`[branch] Found task branch: ${branchName} (for rerun of ${taskId})`)\n\n try {\n // Clean dirty state in CI before switching\n if (process.env.GITHUB_ACTIONS) {\n try {\n execFileSync('git', ['checkout', '--', '.'], { cwd, stdio: 'pipe' })\n } catch {\n // Working tree may already be clean\n }\n }\n\n execFileSync('git', ['checkout', branchName], { cwd, stdio: 'inherit' })\n execFileSync('git', ['pull', 'origin', branchName], { cwd, stdio: 'inherit' })\n mergeDefaultBranch(cwd)\n\n // Persist branch name to status.json\n try {\n const existingState = loadState(taskDir ? path.basename(taskDir) : taskId)\n if (existingState) {\n setBranchName(taskDir ? path.basename(taskDir) : taskId, existingState, branchName)\n }\n } catch {\n // Non-critical\n }\n\n logger.info(`[branch] Checked out task branch: ${branchName}`)\n return true\n } catch (checkoutErr) {\n logger.error({ err: checkoutErr }, `[branch] Failed to checkout task branch: ${branchName}`)\n return false\n }\n}\n\nexport function mergeDefaultBranch(cwd: string): void {\n const defaultBranch = getDefaultBranch(cwd)\n logger.info(`[branch] Merging latest ${defaultBranch} into current branch`)\n try {\n execFileSync('git', ['merge', `origin/${defaultBranch}`, '--no-edit'], {\n cwd,\n stdio: 'inherit',\n })\n } catch (_error) {\n logger.error(`[branch] Merge conflict detected while merging ${defaultBranch}`)\n logger.info('[branch] Aborting merge')\n try {\n execFileSync('git', ['merge', '--abort'], { cwd, stdio: 'inherit' })\n } catch (abortError) {\n // FIX #6: Log the abort error before falling back to hard reset.\n // merge --abort can fail if merge state was corrupted; hard reset discards ALL\n // uncommitted changes (not just conflicts), which is a last resort.\n const abortMsg = abortError instanceof Error ? abortError.message : String(abortError)\n logger.warn(\n `[branch] merge --abort failed (${abortMsg}), falling back to git reset --hard HEAD`,\n )\n logger.warn('[branch] \\u26a0\\ufe0f Hard reset will discard ALL uncommitted changes')\n execFileSync('git', ['reset', '--hard', 'HEAD'], { cwd, stdio: 'inherit' })\n }\n throw new Error(\n `Merge conflict while merging ${defaultBranch} into feature branch. Please resolve conflicts manually.`,\n )\n }\n}\n\n/**\n * Creates a feature branch before the build stage if needed.\n * This ensures the branch follows project conventions: fix/260225-description\n *\n * @param taskId - The task ID (e.g., \"260218-user-metrics\")\n * @param taskType - The task type (e.g., \"fix_bug\", \"implement_feature\")\n * @param projectDir - Optional project directory (defaults to cwd)\n * @param taskDir - Optional task directory for deriving descriptive branch name\n */\nexport function ensureFeatureBranch(\n taskId: string,\n taskType: string,\n projectDir?: string,\n taskDir?: string,\n): void {\n const cwd = projectDir || process.cwd()\n\n const currentBranch = execFileSync('git', ['branch', '--show-current'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n\n // Already on a feature branch - don't recreate\n if (!BASE_BRANCHES.includes(currentBranch)) {\n logger.info(`[branch] Already on feature branch: ${currentBranch}`)\n return\n }\n\n const prefix = BRANCH_PREFIX_MAP[taskType as TaskType] || 'feat'\n\n // Derive descriptive name from task.md if available, otherwise use taskId\n const branchDescription = taskDir ? deriveBranchName(taskDir, taskId) : taskId\n const branchName = `${prefix}/${branchDescription}`\n\n logger.info(`[branch] Ensuring feature branch: ${branchName}`)\n\n // Fetch latest from origin\n execFileSync('git', ['fetch', 'origin'], { cwd, stdio: 'inherit', timeout: 120_000 })\n\n // Check if branch already exists on remote (original behavior)\n let remoteBranchExists = false\n try {\n execFileSync('git', ['rev-parse', '--verify', `origin/${branchName}`], {\n cwd,\n encoding: 'utf-8',\n stdio: 'pipe',\n })\n remoteBranchExists = true\n } catch {\n remoteBranchExists = false\n }\n\n if (remoteBranchExists) {\n // Branch exists on remote — checkout and track it\n logger.info(`[branch] Remote branch exists, checking out: ${branchName}`)\n // Clean dirty state from previous failed runs before switching\n // Only revert tracked file modifications - don't delete untracked files\n // (Deleting untracked files could remove agent-created source files before they're committed)\n if (process.env.GITHUB_ACTIONS) {\n // CI mode: clean dirty tracked files from previous failed runs, then checkout branch\n try {\n execFileSync('git', ['checkout', '--', '.'], { cwd, stdio: 'pipe' })\n } catch {\n // Ignore — working tree may already be clean\n }\n // BUG FIX: Actually checkout the feature branch in CI mode.\n // Previously this only cleaned dirty state but never switched branches,\n // causing commits/pushes to land on dev (which has branch protection).\n execFileSync('git', ['checkout', branchName], { cwd, stdio: 'inherit' })\n execFileSync('git', ['pull', 'origin', branchName], { cwd, stdio: 'inherit' })\n\n // Merge default branch to keep feature branch up-to-date\n mergeDefaultBranch(cwd)\n } else {\n // Local mode: check for uncommitted changes and stash before checkout\n // Track whether we actually stashed to avoid popping unrelated stashes\n let didStash = false\n try {\n const status = execFileSync('git', ['status', '--porcelain'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n if (status) {\n logger.warn('[branch] ⚠ Working tree has uncommitted changes — stashing before checkout')\n execFileSync('git', ['stash', '--include-untracked'], { cwd, stdio: 'pipe' })\n didStash = true\n }\n } catch {\n // Ignore status check errors\n }\n execFileSync('git', ['checkout', branchName], { cwd, stdio: 'inherit' })\n execFileSync('git', ['pull', 'origin', branchName], { cwd, stdio: 'inherit' })\n\n // Merge default branch after pulling feature branch to keep it up-to-date\n mergeDefaultBranch(cwd)\n\n // Restore stashed changes only if we actually stashed something\n if (didStash) {\n try {\n logger.info('[branch] Restoring stashed changes...')\n execFileSync('git', ['stash', 'pop'], { cwd, stdio: 'inherit' })\n } catch {\n logger.warn('[branch] ⚠ Could not restore stash — may need manual recovery')\n }\n }\n }\n // FIX #9: Persist branch name to status.json immediately after checkout,\n // not just in build stage preExecute. This ensures the dashboard can find the\n // branch even for stages that run before build (e.g., gap, architect).\n try {\n const taskIdFromDir = taskDir ? path.basename(taskDir) : taskId\n const existingState = loadState(taskIdFromDir)\n if (existingState) {\n setBranchName(taskIdFromDir, existingState, branchName)\n logger.info(`[branch] Persisted branch name to status.json: ${branchName}`)\n }\n } catch {\n // Non-critical - branch name will be captured in build stage preExecute as fallback\n }\n logger.info(`[branch] Checked out and pulled: ${branchName}`)\n } else {\n // Branch doesn't exist on remote — check if it exists locally (from previous failed run)\n let localBranchExists = false\n try {\n execFileSync('git', ['rev-parse', '--verify', branchName], {\n cwd,\n encoding: 'utf-8',\n stdio: 'pipe',\n })\n localBranchExists = true\n } catch {\n localBranchExists = false\n }\n\n // If branch exists locally, checkout and resume work (stages will skip if already completed)\n if (localBranchExists) {\n logger.info(`[branch] Local branch exists, resuming: ${branchName}`)\n // Stash dirty state before switching (only in local mode, not CI)\n // Track whether we actually stashed to avoid popping unrelated stashes\n let didStash = false\n if (!process.env.GITHUB_ACTIONS) {\n try {\n const status = execFileSync('git', ['status', '--porcelain'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n if (status) {\n logger.info('[branch] Stashing uncommitted changes before checkout...')\n execFileSync('git', ['stash', '--include-untracked'], { cwd, stdio: 'pipe' })\n didStash = true\n }\n } catch {\n /* ignore */\n }\n } else {\n // CI mode: revert tracked files only - don't delete untracked files\n try {\n execFileSync('git', ['checkout', '--', '.'], { cwd, stdio: 'pipe' })\n } catch {\n // Ignore — working tree may already be clean\n }\n }\n\n execFileSync('git', ['checkout', branchName], { cwd, stdio: 'inherit' })\n\n // Merge default branch after checking out local branch to keep it up-to-date\n mergeDefaultBranch(cwd)\n\n // Restore stashed changes only if we actually stashed something\n if (didStash) {\n try {\n logger.info('[branch] Restoring stashed changes...')\n execFileSync('git', ['stash', 'pop'], { cwd, stdio: 'inherit' })\n } catch {\n logger.warn('[branch] Could not restore stash — may need manual recovery')\n }\n }\n\n // Try to push if remote doesn't have it yet\n try {\n execFileSync('git', ['push', '-u', 'origin', branchName], { cwd, stdio: 'inherit' })\n } catch {\n // Remote doesn't have it yet - that's fine\n }\n logger.info(`[branch] Checked out local branch: ${branchName}`)\n return\n }\n\n // Branch doesn't exist locally either — create new from default branch\n const defaultBranch = getDefaultBranch(cwd)\n logger.info(`[branch] Creating new branch from ${defaultBranch}: ${branchName}`)\n execFileSync('git', ['checkout', defaultBranch], { cwd, stdio: 'inherit' })\n execFileSync('git', ['pull', 'origin', defaultBranch], { cwd, stdio: 'inherit' })\n execFileSync('git', ['checkout', '-b', branchName], { cwd, stdio: 'inherit' })\n logger.info(`[branch] Created and switched to: ${branchName}`)\n }\n}\n\n// R2-FIX #7: Cache hook-safe env to avoid recreating on every git call (hot path).\n// process.env changes are rare during pipeline execution, so caching is safe.\nlet _hookSafeEnvCache: NodeJS.ProcessEnv | null = null\nfunction getHookSafeEnv(): NodeJS.ProcessEnv {\n if (!_hookSafeEnvCache) {\n _hookSafeEnvCache = { ...process.env, HUSKY: '0', SKIP_HOOKS: '1' }\n }\n return _hookSafeEnvCache\n}\n\n// ============================================================================\n// Pending Commit Patch — Persist build output across failed pushes\n// ============================================================================\n\nconst PENDING_PATCH_FILE = 'pending-commit.patch'\nconst PENDING_MESSAGE_FILE = 'pending-commit-message.txt'\n\n/**\n * Save the last commit as a patch file in the task directory.\n * Called when commit succeeds but push fails, so the build output\n * can be recovered on the next rerun without re-running the build stage.\n */\nexport function savePendingPatch(taskDir: string, cwd: string): boolean {\n try {\n // Generate patch from HEAD commit\n const patch = execFileSync('git', ['format-patch', '-1', 'HEAD', '--stdout'], {\n cwd,\n encoding: 'utf-8',\n timeout: 30_000,\n })\n\n if (!patch.trim()) {\n logger.warn('[patch] No patch content generated')\n return false\n }\n\n // Save patch to task directory\n const patchPath = path.join(taskDir, PENDING_PATCH_FILE)\n fs.writeFileSync(patchPath, patch)\n\n // Save commit message separately (format-patch includes it but we need it standalone)\n const message = execFileSync('git', ['log', '-1', '--format=%B'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n const messagePath = path.join(taskDir, PENDING_MESSAGE_FILE)\n fs.writeFileSync(messagePath, message)\n\n // Reset HEAD back so the patch can be cleanly re-applied on next run\n // (the commit exists locally but was never pushed)\n execFileSync('git', ['reset', 'HEAD~1'], {\n cwd,\n stdio: 'pipe',\n })\n\n logger.info(`[patch] Saved pending patch to ${PENDING_PATCH_FILE} (build output preserved)`)\n return true\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err)\n logger.error(`[patch] Failed to save pending patch: ${msg}`)\n return false\n }\n}\n\n/**\n * Check if a pending patch exists and apply it.\n * Called at the start of commitAndPush to restore build output\n * from a previous failed push attempt.\n *\n * @returns true if patch was applied, false if no patch or apply failed\n */\nexport function restorePendingPatch(taskDir: string, cwd: string): boolean {\n const patchPath = path.join(taskDir, PENDING_PATCH_FILE)\n if (!fs.existsSync(patchPath)) {\n return false\n }\n\n try {\n logger.info('[patch] Found pending patch — restoring build output from previous run...')\n\n // Apply the patch (--3way handles conflicts gracefully)\n execFileSync('git', ['apply', '--3way', patchPath], {\n cwd,\n stdio: 'pipe',\n timeout: 30_000,\n })\n\n // Clean up the patch file (it will be re-saved if push fails again)\n fs.unlinkSync(patchPath)\n const messagePath = path.join(taskDir, PENDING_MESSAGE_FILE)\n if (fs.existsSync(messagePath)) {\n fs.unlinkSync(messagePath)\n }\n\n logger.info('[patch] Successfully restored build output from pending patch')\n return true\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err)\n logger.warn(`[patch] Failed to apply pending patch (may need rebuild): ${msg}`)\n\n // Clean up the failed patch so we don't keep retrying it\n try {\n fs.unlinkSync(patchPath)\n } catch {\n // ignore\n }\n return false\n }\n}\n\n/**\n * Push to origin with automatic pull-rebase-retry on rejection.\n * Handles the case where the remote branch has been updated by a previous\n * pipeline run (e.g., gate approval pushed new commits before rerun started).\n *\n * FIX: Use origin/<branch> instead of HEAD for pull, and add force-with-lease fallback.\n * FIX: Fallback to GITHUB_TOKEN if App token fails with \"Write access to repository not granted\".\n *\n * @returns true if push succeeded, false if it failed even after rebase\n */\nexport function pushWithRebase(cwd: string, env?: NodeJS.ProcessEnv): boolean {\n const pushEnv = env || getHookSafeEnv()\n const pushOpts = { cwd, stdio: 'inherit' as const, env: pushEnv, timeout: 120_000 }\n\n // Get current branch name for proper remote tracking reference\n let branchName = ''\n try {\n branchName = execFileSync('git', ['branch', '--show-current'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n } catch {\n logger.warn('[push] Could not determine branch name, falling back to HEAD')\n branchName = ''\n }\n\n // Try push with provided env (typically App token)\n const tryPush = (pushEnvVar: NodeJS.ProcessEnv): boolean => {\n const opts = { cwd, stdio: 'inherit' as const, env: pushEnvVar, timeout: 120_000 }\n try {\n execFileSync('git', ['push', '-u', 'origin', 'HEAD'], opts)\n return true\n } catch {\n return false\n }\n }\n\n // First attempt with provided env (App token)\n if (tryPush(pushEnv)) {\n return true\n }\n\n // Push rejected — remote has new commits. Pull with rebase and retry.\n logger.info('[push] Push rejected, pulling with rebase...')\n try {\n // FIX: Use origin/<branch> instead of HEAD for proper remote tracking\n execFileSync('git', ['pull', '--rebase', 'origin', branchName], {\n cwd,\n stdio: 'inherit',\n timeout: 120_000,\n env: pushEnv,\n })\n\n // Retry push after rebase with App token\n if (tryPush(pushEnv)) {\n logger.info('[push] Push succeeded after rebase')\n return true\n }\n } catch {\n // Rebase failed — try force-with-lease\n }\n\n // Try force-with-lease as last resort with App token\n logger.info('[push] Rebase push failed, trying force-with-lease...')\n try {\n execFileSync('git', ['push', '-u', 'origin', 'HEAD', '--force-with-lease'], pushOpts)\n logger.info('[push] Push succeeded with force-with-lease')\n return true\n } catch (forceError: unknown) {\n const msg = forceError instanceof Error ? forceError.message : String(forceError)\n\n // Check if this is a permission error (App token lacks workflows permission)\n // Error: \"refusing to allow a GitHub App to create or update workflow .github/workflows/ci.yml\n // without workflows permission\"\n if (\n msg.includes('Write access to repository not granted') ||\n msg.includes('workflow') ||\n msg.includes('permission')\n ) {\n logger.warn('[push] App token push failed due to permissions — falling back to GITHUB_TOKEN')\n\n // Fallback: Use GITHUB_TOKEN for push (it can push source files but not workflows)\n // IMPORTANT: Unset the git url substitution that forces App token, so GITHUB_TOKEN is used\n const fallbackEnv = {\n ...getHookSafeEnv(),\n GH_TOKEN: undefined,\n GITHUB_TOKEN: process.env.GITHUB_TOKEN,\n }\n const fallbackOpts = { cwd, stdio: 'inherit' as const, env: fallbackEnv, timeout: 120_000 }\n\n // Remove the App token git config so fallback uses GITHUB_TOKEN\n try {\n execFileSync(\n 'git',\n ['config', '--global', '--unset', 'url.https://x-access-token:@github.com/.insteadOf'],\n {\n cwd,\n stdio: 'inherit',\n },\n )\n } catch {\n // Ignore if not set\n }\n\n // Try push with GITHUB_TOKEN\n try {\n execFileSync('git', ['push', '-u', 'origin', 'HEAD'], fallbackOpts)\n logger.info('[push] Push succeeded with GITHUB_TOKEN fallback')\n return true\n } catch (fallbackError: unknown) {\n const fallbackMsg =\n fallbackError instanceof Error ? fallbackError.message : String(fallbackError)\n logger.error(`[push] GITHUB_TOKEN fallback also failed: ${fallbackMsg}`)\n }\n }\n\n logger.error(`[push] Push failed after all retries: ${msg}`)\n return false\n }\n}\n\n/**\n * Derive conventional commit type from task type.\n */\nexport function deriveCommitType(taskType: string): string {\n return COMMIT_TYPE_MAP[taskType as TaskType] || 'feat'\n}\n\n/**\n * Extract commit subject from task.md content.\n * Uses first non-empty line after the title.\n */\nexport function extractCommitSubject(taskMdContent: string): string {\n const lines = taskMdContent.split('\\n')\n let foundTitle = false\n\n for (const line of lines) {\n // Skip the # Task title line\n if (line.match(/^#\\s+Task/i)) {\n foundTitle = true\n continue\n }\n // Skip empty lines\n if (!line.trim()) continue\n // First non-empty line after title is the subject\n if (foundTitle || line.match(/^#/)) {\n // Clean up the subject: remove leading -, *, numbers, etc.\n const subject = line\n .replace(/^[-*\\d.]\\s*/, '')\n .replace(/^#+\\s*/, '') // strip markdown headers\n .replace(/\\*\\*(.*?)\\*\\*/g, '$1') // strip bold markers\n .replace(/`(.*?)`/g, '$1') // strip inline code\n .trim()\n // Truncate to 72 chars (conventional commit subject max)\n return subject.length > 72 ? subject.slice(0, 69) + '...' : subject\n }\n }\n\n // Fallback: use first non-empty line\n const firstNonEmpty = lines.find((l) => l.trim())\n if (firstNonEmpty) {\n return firstNonEmpty.replace(/^#\\s*/, '').slice(0, 72)\n }\n\n return 'implement changes'\n}\n\n/**\n * Extract commit body from build.md content.\n * Uses the ## Changes section.\n */\nexport function extractCommitBody(buildMdContent: string): string {\n const changesMatch = buildMdContent.match(/##\\s*Changes\\s*\\n([\\s\\S]*?)(?=\\n##\\s|$)/i)\n\n if (changesMatch && changesMatch[1]) {\n // Take first few bullet points as body\n const bullets = changesMatch[1]\n .split('\\n')\n .filter((line) => line.trim().match(/^[-*•]/))\n .slice(0, 5)\n .map((line) =>\n line\n .replace(/^[-*•]\\s*/, '')\n .replace(/\\*\\*(.*?)\\*\\*/g, '$1') // strip bold\n .replace(/`(.*?)`/g, '$1') // strip inline code\n .trim(),\n )\n .join('. ')\n\n if (bullets.length > 20) return bullets\n }\n\n // Fallback: generic body\n return 'See build report for details.'\n}\n\n/**\n * Commit and push changes to the current branch.\n * Uses conventional commit format.\n */\nexport function commitAndPush(\n taskId: string,\n taskDir: string,\n cwd?: string,\n): {\n hash: string\n branch: string\n success: boolean\n message: string\n} {\n const workDir = cwd || process.cwd()\n\n // Get current branch\n let branch = execFileSync('git', ['branch', '--show-current'], {\n cwd: workDir,\n encoding: 'utf-8',\n }).trim()\n\n // Handle detached HEAD state (empty branch name)\n if (!branch) {\n branch =\n execFileSync('git', ['rev-parse', '--short', 'HEAD'], {\n cwd: workDir,\n encoding: 'utf-8',\n }).trim() || 'detached'\n logger.warn(`[commit] Detached HEAD detected, using ref: ${branch}`)\n }\n\n // Read task.json for commit type\n const taskJsonPath = path.join(taskDir, 'task.json')\n let taskType = 'implement_feature'\n let commitType = 'feat'\n\n if (fs.existsSync(taskJsonPath)) {\n try {\n const taskJson = JSON.parse(fs.readFileSync(taskJsonPath, 'utf-8'))\n taskType = taskJson.task_type || taskType\n commitType = deriveCommitType(taskType)\n } catch {\n // Use default\n }\n }\n\n // Read task.md for subject\n const taskMdPath = path.join(taskDir, 'task.md')\n let subject = 'implement changes'\n if (fs.existsSync(taskMdPath)) {\n const taskMdContent = fs.readFileSync(taskMdPath, 'utf-8')\n subject = extractCommitSubject(taskMdContent)\n }\n\n // Read build.md for body\n const buildMdPath = path.join(taskDir, 'build.md')\n let body = 'See build report for details.'\n if (fs.existsSync(buildMdPath)) {\n const buildMdContent = fs.readFileSync(buildMdPath, 'utf-8')\n body = extractCommitBody(buildMdContent)\n }\n\n // Build commit message\n const commitMessage = `${commitType}(${taskId}): ${subject}\\n\\n${body}`\n\n try {\n // Check if there are changes\n const status = execFileSync('git', ['status', '--porcelain'], {\n cwd: workDir,\n encoding: 'utf-8',\n }).trim()\n\n if (!status) {\n // Try restoring from a pending patch (build output from a previous failed push)\n const restored = restorePendingPatch(taskDir, workDir)\n if (!restored) {\n return {\n hash: '',\n branch,\n success: false,\n message: 'No changes to commit',\n }\n }\n // Re-check status after patch restore\n const newStatus = execFileSync('git', ['status', '--porcelain'], {\n cwd: workDir,\n encoding: 'utf-8',\n }).trim()\n if (!newStatus) {\n return {\n hash: '',\n branch,\n success: false,\n message: 'No changes to commit (patch restore produced no changes)',\n }\n }\n }\n\n // Stage tracked changes (modifications + deletions)\n execFileSync('git', ['add', '-u'], { cwd: workDir, stdio: 'inherit' })\n\n // Stage new files from safe directories only (BUG-15: avoid root-level .env files)\n // Pre-commit hooks (check-secrets, check-no-css) provide additional safety\n const safeDirs = ['src', 'tests', 'scripts', 'public', 'docs', '.tasks']\n for (const dir of safeDirs) {\n const dirPath = path.join(workDir, dir)\n if (fs.existsSync(dirPath)) {\n try {\n execFileSync('git', ['add', '--', dirPath], { cwd: workDir, stdio: 'pipe' })\n } catch {\n // Directory may have no new files - that's fine\n }\n }\n }\n\n // H6 FIX: Also stage new root config files that are needed for builds\n // These are safe config files (not .env) that the project needs\n const rootConfigPatterns = [\n 'package.json',\n 'pnpm-lock.yaml',\n 'tsconfig.json',\n /^tsconfig\\..*\\.json$/,\n /^next\\.config\\..+$/,\n 'payload.config.ts',\n /^tailwind\\.config\\..+$/,\n /^postcss\\.config\\..+$/,\n /^eslint\\.config\\..+$/,\n /^\\.prettierrc/,\n /^jest\\.config\\..+$/,\n /^vitest\\.config\\..+$/,\n ]\n\n const rootFiles = fs.readdirSync(workDir)\n for (const pattern of rootConfigPatterns) {\n const matches =\n typeof pattern === 'string'\n ? rootFiles.filter((f: string) => f === pattern)\n : rootFiles.filter((f: string) => pattern.test(f))\n for (const file of matches) {\n try {\n execFileSync('git', ['add', '--', file], { cwd: workDir, stdio: 'pipe' })\n } catch {\n // File may not be git-addable - that's fine\n }\n }\n }\n\n // Commit using execFileSync to prevent shell injection (BUG-4 fix)\n // Skip husky/commitlint hooks in CI - they run their own quality gates\n const hookSafeEnv = getHookSafeEnv()\n execFileSync('git', ['commit', '--no-gpg-sign', '-m', commitMessage], {\n cwd: workDir,\n stdio: 'inherit',\n env: hookSafeEnv,\n })\n\n // Get commit hash\n const hash = execFileSync('git', ['rev-parse', 'HEAD'], {\n cwd: workDir,\n encoding: 'utf-8',\n })\n .trim()\n .slice(0, 7)\n\n // Push with automatic rebase-retry on rejection (fixes rejected pushes on reruns)\n const pushed = pushWithRebase(workDir, hookSafeEnv)\n if (!pushed) {\n // Save the commit as a patch so it can be restored on next rerun\n // This preserves build output across failed pushes\n savePendingPatch(taskDir, workDir)\n return {\n hash,\n branch,\n success: false,\n message: `Committed (${hash}) but push failed after rebase`,\n }\n }\n\n return {\n hash,\n branch,\n success: true,\n message: `Committed and pushed: ${hash} ${subject}`,\n }\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : String(error)\n return {\n hash: '',\n branch,\n success: false,\n message: `Commit failed: ${msg}`,\n }\n }\n}\n\n// ============================================================================\n// Pipeline Files Commit - Unified commit function\n// ============================================================================\n\nexport type StagingStrategy = 'task-only' | 'tracked+task' | 'all'\n\n/**\n * Files that are always excluded from task-only commits (internal state markers).\n * NOTE: OpenCode runtime file patterns here must be kept in sync with\n * the .gitignore entries under \"OpenCode runtime files (per-task isolated data dirs)\".\n */\nconst TASK_FILES_ALWAYS_EXCLUDE = [\n 'gate-*.md',\n 'rerun-feedback.consumed.md',\n // OpenCode runtime files (only opencode.db is committed for session reuse)\n 'opencode-data/opencode/opencode.db-wal',\n 'opencode-data/opencode/opencode.db-shm',\n 'opencode-data/opencode/snapshot/',\n 'opencode-data/opencode/logs/',\n 'opencode-data/opencode/auth.json',\n 'opencode-data/opencode/bin/',\n 'opencode-data/opencode/tool-output/',\n 'opencode-data/opencode/storage/',\n 'opencode-data/opencode/worktree/',\n]\n\n/**\n * Debug artifacts — only committed when the pipeline fails (black box data).\n * On success these add noise to PRs; on failure they're essential for diagnosis.\n */\nconst TASK_FILES_DEBUG_ONLY = ['*-events.jsonl', '*-stderr.log']\n\nexport interface CommitPipelineFilesOptions {\n /** Task directory path */\n taskDir: string\n /** Task ID for branch/commit messages */\n taskId: string\n /** Commit message */\n message: string\n /** Whether to ensure feature branch exists first (default: true in CI) */\n ensureBranch?: boolean\n /** Whether to clean dirty state before commit (default: true in CI) */\n cleanDirtyState?: boolean\n /** Staging strategy: which files to stage */\n stagingStrategy?: StagingStrategy\n /** Whether to push after commit (default: true in CI) */\n push?: boolean\n /** Working directory (default: process.cwd()) */\n cwd?: string\n /** Whether this is CI mode (affects defaults) */\n isCI?: boolean\n /** Whether this is a dry run */\n dryRun?: boolean\n /** Whether the pipeline has failed — includes debug artifacts (*-events.jsonl, *-stderr.log) */\n pipelineFailed?: boolean\n}\n\nexport interface CommitPipelineFilesResult {\n success: boolean\n message: string\n committed?: boolean\n pushed?: boolean\n}\n\n/**\n * Unified function to commit pipeline files.\n * Consolidates 3 patterns from kody.ts:\n * - commitTaskFilesCI (CI mode with branch/cleanup)\n * - commitTaskFiles (local mode)\n * - autofix commit (tracked + task files)\n */\nexport function commitPipelineFiles(\n options: CommitPipelineFilesOptions,\n): CommitPipelineFilesResult {\n const {\n taskDir,\n taskId,\n message,\n ensureBranch = false,\n cleanDirtyState = false,\n stagingStrategy = 'task-only',\n push = false,\n cwd = process.cwd(),\n isCI = false,\n dryRun = false,\n pipelineFailed = false,\n } = options\n\n // Skip in dry-run mode\n if (dryRun) {\n return { success: true, message: 'Dry run - skipped', committed: false, pushed: false }\n }\n\n try {\n // 1. Optionally ensure feature branch exists\n if (ensureBranch) {\n // Read task type from task.json\n const taskJsonPath = path.join(taskDir, 'task.json')\n let taskType = 'implement_feature'\n if (fs.existsSync(taskJsonPath)) {\n try {\n const taskData = JSON.parse(fs.readFileSync(taskJsonPath, 'utf-8'))\n taskType = taskData.task_type || 'implement_feature'\n } catch {\n // Use default\n }\n }\n ensureFeatureBranch(taskId, taskType, cwd, taskDir)\n }\n\n // 2. Optionally clean dirty state (CI mode)\n // Only revert tracked file modifications - don't delete untracked files\n // (Deleting untracked files could remove agent-created source files before they're committed)\n if (cleanDirtyState && isCI) {\n try {\n execFileSync('git', ['checkout', '--', '.'], { cwd, stdio: 'pipe' })\n } catch {\n // Working tree may already be clean\n }\n }\n\n // 3. Stage files based on strategy\n // Use execFileSync to prevent shell injection via taskDir paths\n // Don't throw on staging errors - silent fail is ok for staging\n switch (stagingStrategy) {\n case 'all':\n try {\n execFileSync('git', ['add', '-A'], { cwd, stdio: 'inherit' })\n } catch (stageErr) {\n // FIX #7: Log staging errors instead of silently swallowing them\n logger.warn({ err: stageErr }, '[commit] git add -A failed (non-fatal)')\n }\n break\n case 'tracked+task':\n try {\n execFileSync('git', ['add', '-u'], { cwd, stdio: 'inherit' })\n } catch (stageErr) {\n // FIX #7: Log instead of silent swallow\n logger.warn({ err: stageErr }, '[commit] git add -u failed (non-fatal)')\n }\n try {\n execFileSync('git', ['add', '--', taskDir], { cwd, stdio: 'inherit' })\n } catch (stageErr) {\n logger.warn({ err: stageErr }, '[commit] git add task dir failed (non-fatal)')\n }\n break\n case 'task-only':\n default:\n try {\n execFileSync('git', ['add', '--', taskDir], { cwd, stdio: 'inherit' })\n } catch (stageErr) {\n // FIX #7: Log instead of silent swallow\n logger.warn({ err: stageErr }, '[commit] git add task-only failed (non-fatal)')\n }\n break\n }\n\n // 3b. Unstage excluded task artifacts to keep PRs clean\n // Always exclude gate markers; only include debug artifacts on failure\n if (stagingStrategy === 'task-only' || stagingStrategy === 'tracked+task') {\n const excludePatterns = [\n ...TASK_FILES_ALWAYS_EXCLUDE,\n ...(!pipelineFailed ? TASK_FILES_DEBUG_ONLY : []),\n ]\n for (const pattern of excludePatterns) {\n try {\n execFileSync('git', ['reset', 'HEAD', '--', path.join(taskDir, pattern)], {\n cwd,\n stdio: 'pipe',\n })\n } catch {\n // Pattern may not match any staged files — that's fine\n }\n }\n }\n\n // 4. Commit using execFileSync to prevent shell injection (BUG-5 fix)\n // Skip husky/commitlint hooks in CI - they run their own quality gates\n // Use stdio: 'pipe' to capture git output in error object for \"nothing to commit\" detection\n const hookSafeEnv = getHookSafeEnv()\n let committed = false\n try {\n execFileSync('git', ['commit', '--no-gpg-sign', '-m', message], {\n cwd,\n stdio: 'pipe',\n env: hookSafeEnv,\n })\n committed = true\n logger.info(`[commit] ${message}`)\n } catch (commitError: unknown) {\n const commitMsg = commitError instanceof Error ? commitError.message : String(commitError)\n // Also check stdout for git output (execFileSync error.message doesn't include git stdout)\n const commitStdout =\n commitError instanceof Error && 'stdout' in commitError\n ? String((commitError as Record<string, unknown>).stdout || '')\n : ''\n const fullOutput = commitMsg + commitStdout\n // Handle various git \"nothing to commit\" messages\n if (\n fullOutput.includes('nothing to commit') ||\n fullOutput.includes('no changes added') ||\n fullOutput.includes('nothing added to commit')\n ) {\n return { success: true, message: 'No changes to commit', committed: false }\n }\n throw commitError\n }\n\n // 5. Optionally push (with rebase-retry on rejection)\n // Use hook-safe env to skip pre-push hooks (e.g., Prettier/verify)\n // which may fail on unrelated files and block the pipeline\n let pushed = false\n if (push) {\n pushed = pushWithRebase(cwd, hookSafeEnv)\n if (pushed) {\n logger.info(`[commit] Pushed to origin`)\n } else {\n logger.error(`[commit] Push failed — remote may have diverged`)\n }\n }\n\n return { success: true, message: 'Committed successfully', committed, pushed }\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : String(error)\n logger.error(`[commit] Error: ${msg}`)\n return { success: false, message: msg }\n }\n}\n","/**\n * @fileType utility\n * @domain ci | kody\n * @pattern content-validation\n * @ai-summary Pure validation functions for pipeline stage outputs — extracted from kody.ts for testability\n */\n\nimport * as fs from 'fs'\n\n// ============================================================================\n// Question Detection\n// ============================================================================\n\n/**\n * Check if questions.md contains actual questions that need answering\n */\nexport function checkForQuestions(questionsPath: string): boolean {\n const content = fs.readFileSync(questionsPath, 'utf-8').trim()\n\n // If file is empty or just placeholder text, no questions\n if (!content || content.length < 10) {\n return false\n }\n\n // Check for question patterns:\n // - Lines starting with numbers followed by period or parenthesis (1. 2. 1) 2))\n // - Lines containing \"?\" character\n // - Sections like \"## Questions\" or \"### Clarifications Needed\"\n const hasNumberedQuestions = /^\\d+[.)]\\s+/m.test(content)\n // Match ? at end of a sentence (after a word char), not in URLs or code\n const hasQuestionMarks = /\\w\\?\\s*$/m.test(content)\n const hasQuestionHeader = /^#{1,3}\\s*(Questions|Clarifications|Needs Clarification)/m.test(\n content,\n )\n\n // Also check for \"APPROVED\" or \"No clarifications needed\" as indicators of no questions\n const isApproved = /^#{1,3}\\s*APPROVED/im.test(content)\n const noClarifications = /no clarifications needed/i.test(content)\n\n // Has questions if there's question content AND not explicitly approved\n const hasQuestionContent = hasNumberedQuestions || hasQuestionMarks || hasQuestionHeader\n\n return hasQuestionContent && !isApproved && !noClarifications\n}\n\n// ============================================================================\n// Spec Content Validation\n// ============================================================================\n\n/**\n * Validate that spec content contains required sections.\n * Returns true if valid, false otherwise.\n */\nexport function validateSpecContent(specContent: string): boolean {\n const hasRequirements = /##\\s*(Requirements|Functional|FR-|NFR-)/i.test(specContent)\n const hasAcceptance = /##\\s*Acceptance/i.test(specContent)\n return hasRequirements || hasAcceptance\n}\n\n/**\n * Validate spec file and return validation result.\n * Throws if spec is invalid.\n */\nexport function validateSpecFile(specFilePath: string): void {\n if (!fs.existsSync(specFilePath)) {\n throw new Error(`Spec file not found: ${specFilePath}`)\n }\n\n const specContent = fs.readFileSync(specFilePath, 'utf-8')\n if (!validateSpecContent(specContent)) {\n throw new Error('Spec missing ## Requirements or ## Acceptance Criteria sections')\n }\n}\n\n// ============================================================================\n// Build Report Validation\n// ============================================================================\n\n/**\n * Validate that build report contains a changes section.\n * Returns true if valid, false otherwise.\n */\nexport function validateBuildReport(buildContent: string): boolean {\n return /##\\s*(Changes|Files)/i.test(buildContent)\n}\n\n/**\n * Validate build file and return validation result.\n * Returns warning string if missing Changes section, empty string if valid.\n */\nexport function validateBuildFile(buildFilePath: string): string {\n if (!fs.existsSync(buildFilePath)) {\n return ''\n }\n\n const buildContent = fs.readFileSync(buildFilePath, 'utf-8')\n if (!validateBuildReport(buildContent)) {\n return 'Build report missing Changes section — agent may not have implemented anything'\n }\n return ''\n}\n\n// ============================================================================\n// Plan Gap Report Validation\n// ============================================================================\n\n/**\n * Validate plan-gap report content.\n * Reuses same logic as validateGapReport - both follow same format.\n * Returns true if valid, false otherwise.\n */\nexport function validatePlanGapReport(gapContent: string): boolean {\n const trimmed = gapContent.trim()\n\n // Empty content is invalid\n if (!trimmed || trimmed.length < 10) {\n return false\n }\n\n // Check for required sections\n const hasGapsFound = /##\\s*Gaps?\\s*(Found|Identified)/i.test(gapContent)\n const hasChangesMade = /##\\s*Changes Made/i.test(gapContent)\n const hasNoGaps = /no gaps identified/i.test(gapContent.toLowerCase())\n\n return hasGapsFound || hasChangesMade || hasNoGaps\n}\n\n// ============================================================================\n// Verify Summary Extraction\n// ============================================================================\n\n/**\n * Extract verification summary from verify output content\n */\nexport interface VerifySummary {\n typeScriptErrors: number\n testFailures: number\n lintErrors: number\n errorSamples: string[]\n}\n\nexport function extractVerifySummary(content: string): VerifySummary {\n const summary: VerifySummary = {\n typeScriptErrors: 0,\n testFailures: 0,\n lintErrors: 0,\n errorSamples: [],\n }\n\n const tsMatch = content.match(/TypeScript.*?(\\d+)\\s+error/i)\n if (tsMatch) summary.typeScriptErrors = parseInt(tsMatch[1])\n\n const testMatch = content.match(/Tests?.*?(\\d+)\\s+fail/i)\n if (testMatch) summary.testFailures = parseInt(testMatch[1])\n\n const lintMatch = content.match(/Lint.*?(\\d+)\\s+error/i)\n if (lintMatch) summary.lintErrors = parseInt(lintMatch[1])\n\n const lines = content.split('\\n')\n for (const line of lines) {\n if (\n (line.trim().startsWith('-') || line.trim().startsWith('•')) &&\n (line.includes('error') || line.includes('Error') || line.includes('✗'))\n ) {\n const cleaned = line.trim().replace(/^[-•]\\s*/, '')\n if (cleaned.length > 10 && summary.errorSamples.length < 5) {\n summary.errorSamples.push(cleaned)\n }\n }\n }\n return summary\n}\n\n/**\n * Check if verify content indicates failure.\n * Matches \"Result: FAIL\" anywhere in content, not per-gate failures like \"TypeScript: FAIL\".\n */\nexport function isVerifyFailed(verifyContent: string): boolean {\n return /\\bResult:\\s*FAIL\\b/i.test(verifyContent)\n}\n\n// ============================================================================\n// Build Tests Validation\n// ============================================================================\n\n/**\n * Validate that build report has tests written.\n * For implement_feature and fix_bug task types, tests are required.\n * For other types (refactor, docs, ops), tests are optional (warning only).\n */\nexport function validateBuildTests(buildContent: string): { hasTests: boolean; warning: string } {\n // Look for \"Tests Written\" section (case insensitive)\n // Split content by ## to find the section\n const sections = buildContent.split(/\\n## /i)\n\n // Find the Tests Written section\n const testsSection = sections.find((section) => /^Tests?\\s*Written/i.test(section))\n\n // If no Tests Written section at all\n if (!testsSection) {\n return {\n hasTests: false,\n warning: 'Build report missing ## Tests Written section',\n }\n }\n\n // Get content after the header (first line is \"Tests Written\\n\")\n const lines = testsSection.split('\\n')\n // Skip the first line (header) and get remaining content\n const contentAfterHeader = lines.slice(1).join('\\n').trim()\n\n // Check for empty content (just whitespace or empty string)\n if (!contentAfterHeader) {\n return {\n hasTests: false,\n warning: 'Build report indicates no tests were written',\n }\n }\n\n const testsContent = contentAfterHeader.toLowerCase()\n\n // Check for indicators that no tests were written\n const noTestsIndicators = ['no tests', 'none', 'n/a', 'not applicable', 'skipped', 'skip']\n const hasNoTestsIndicator = noTestsIndicators.some((indicator) =>\n testsContent.includes(indicator),\n )\n\n if (hasNoTestsIndicator) {\n return {\n hasTests: false,\n warning: 'Build report indicates no tests were written',\n }\n }\n\n // Tests were written (section exists and has content)\n return { hasTests: true, warning: '' }\n}\n\n// ============================================================================\n// Gap Report Validation\n// ============================================================================\n\n/**\n * Validate that gap report contains required sections.\n * Returns true if valid, false otherwise.\n */\nexport function validateGapReport(gapContent: string): boolean {\n const trimmed = gapContent.trim()\n\n // Empty content is invalid\n if (!trimmed || trimmed.length < 10) {\n return false\n }\n\n // Check for required sections\n const hasGapsFound = /##\\s*Gaps?\\s*(Found|Identified)/i.test(gapContent)\n const hasChangesMade = /##\\s*Changes Made/i.test(gapContent)\n const hasNoGaps = /no gaps identified/i.test(gapContent.toLowerCase())\n\n return hasGapsFound || hasChangesMade || hasNoGaps\n}\n\n// ============================================================================\n// Test Report Validation\n// ============================================================================\n\n/**\n * Validate that test.md contains required sections indicating tests were written.\n */\nexport function validateTestReport(content: string): boolean {\n const hasTestsWritten = /##\\s*Tests?\\s*Written/i.test(content)\n const hasTestCases = /##\\s*Test\\s*Cases/i.test(content)\n const hasTestFiles = /##\\s*Test\\s*Files/i.test(content)\n\n return hasTestsWritten || hasTestCases || hasTestFiles\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern validators\n * @ai-summary Pipeline validators moved from kody.ts for testability\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext, ValidationResult } from '../engine/types'\nimport {\n validateGapReport,\n validatePlanGapReport,\n validateBuildReport,\n validateSpecContent,\n validateTestReport,\n} from '../content-validators'\n\n/**\n * Create a validator for the gap stage.\n * Gap now writes BOTH spec.md and gap.md (spec stage was merged into gap).\n * Validates gap.md format AND ensures spec.md exists with proper structure.\n */\nexport function createGapValidator(ctx: PipelineContext): (outputFile: string) => ValidationResult {\n return (outputFile: string) => {\n const content = fs.readFileSync(outputFile, 'utf-8')\n if (!validateGapReport(content)) {\n return {\n valid: false,\n error:\n 'gap.md must contain ## Gaps Found, ## Changes Made, or \"No gaps identified\" (you wrote something else)',\n }\n }\n\n // Validate spec.md was created by gap agent with proper structure\n const specFile = path.join(ctx.taskDir, 'spec.md')\n if (!fs.existsSync(specFile)) {\n return {\n valid: false,\n error:\n 'gap agent must write spec.md with ## Requirements or ## Acceptance Criteria sections',\n }\n }\n\n const specContent = fs.readFileSync(specFile, 'utf-8')\n if (!validateSpecContent(specContent)) {\n return {\n valid: false,\n error: 'spec.md must contain ## Requirements or ## Acceptance Criteria sections',\n }\n }\n\n return { valid: true }\n }\n}\n\n/**\n * Create a validator for the plan-gap stage.\n * Validates plan-gap format AND checks plan.md still exists.\n */\nexport function createPlanGapValidator(\n ctx: PipelineContext,\n): (outputFile: string) => ValidationResult {\n return (outputFile: string) => {\n const content = fs.readFileSync(outputFile, 'utf-8')\n if (!validatePlanGapReport(content)) {\n return {\n valid: false,\n error: 'plan-gap.md must contain ## Gaps Found, ## Changes Made, or \"No gaps identified\"',\n }\n }\n\n // Verify plan.md still exists (gap agent shouldn't delete it)\n const planFile = path.join(ctx.taskDir, 'plan.md')\n if (!fs.existsSync(planFile)) {\n return {\n valid: false,\n error: 'plan-gap agent deleted plan.md - it must not delete the plan file',\n }\n }\n return { valid: true }\n }\n}\n\n/**\n * Create a validator for the build stage.\n */\nexport function createBuildValidator(): (outputFile: string) => ValidationResult {\n return (outputFile: string) => {\n const content = fs.readFileSync(outputFile, 'utf-8')\n if (!validateBuildReport(content)) {\n return {\n valid: false,\n error:\n 'build.md must contain ## Changes or ## Files section describing what was implemented',\n }\n }\n return { valid: true }\n }\n}\n\n/**\n * Create a validator for the docs stage.\n * Validates docs.md was written with minimum content.\n */\nexport function createDocsValidator(): (outputFile: string) => ValidationResult {\n return (outputFile: string) => {\n if (!fs.existsSync(outputFile)) {\n return {\n valid: false,\n error: 'docs.md must exist in the task directory',\n }\n }\n const content = fs.readFileSync(outputFile, 'utf-8')\n const minLength = 100\n if (content.length < minLength) {\n return {\n valid: false,\n error: `docs.md must have at least ${minLength} characters of content`,\n }\n }\n return { valid: true }\n }\n}\n\n/**\n * Create a validator for the test stage.\n * Validates test.md contains test case sections.\n */\nexport function createTestValidator(): (outputFile: string) => ValidationResult {\n return (outputFile: string) => {\n const content = fs.readFileSync(outputFile, 'utf-8')\n if (!validateTestReport(content)) {\n return {\n valid: false,\n error: 'test.md must contain ## Tests Written, ## Test Cases, or ## Test Files section',\n }\n }\n return { valid: true }\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern verify-failures\n * @ai-summary Captures gate output files into verify-failures.md for the fix stage\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext } from '../engine/types'\nimport { MAX_GATE_OUTPUT_CHARS } from '../config/constants'\nimport { logger } from '../logger'\n\n/** Gate output file definitions — maps human-readable names to filenames */\nconst GATE_FILES = [\n { name: 'TypeScript Errors', file: 'typescript-output.txt' },\n { name: 'Lint Errors', file: 'lint-output.txt' },\n { name: 'Format Errors', file: 'format-output.txt' },\n { name: 'Unit Test Errors', file: 'unit-tests-output.txt' },\n] as const\n\n/**\n * Capture gate output files into verify-failures.md.\n *\n * Reads gate output files written by runVerifyStage, assembles them into\n * a markdown document, and writes it to the task directory for the fix\n * stage to read.\n *\n * This function is used as `retryWith.onFailure` in the verify stage definition.\n */\nexport async function captureVerifyFailures(ctx: PipelineContext, taskDir: string): Promise<void> {\n const verifyFailuresPath = path.join(taskDir, 'verify-failures.md')\n\n // Read the verify stage's output file for the error summary\n const verifyOutputPath = path.join(taskDir, 'verify.md')\n let errorSummary = 'Verify failed - check logs'\n if (fs.existsSync(verifyOutputPath)) {\n const content = fs.readFileSync(verifyOutputPath, 'utf-8').trim()\n if (content.length > 0) {\n errorSummary = content.slice(0, MAX_GATE_OUTPUT_CHARS)\n }\n }\n\n // Assemble detailed output from individual gate output files\n let detailedOutput = errorSummary\n try {\n const parts = [`# Verify Failures\\n\\n${errorSummary}`]\n for (const gate of GATE_FILES) {\n const gatePath = path.join(taskDir, gate.file)\n if (fs.existsSync(gatePath)) {\n const gateOutput = fs.readFileSync(gatePath, 'utf-8').slice(0, MAX_GATE_OUTPUT_CHARS)\n parts.push(`## ${gate.name}\\n\\`\\`\\`\\n${gateOutput}\\n\\`\\`\\``)\n }\n }\n detailedOutput = parts.join('\\n\\n')\n } catch {\n // Gate output files may not exist, use basic error\n }\n\n try {\n fs.writeFileSync(verifyFailuresPath, detailedOutput)\n if (!fs.existsSync(verifyFailuresPath)) {\n logger.warn('verify-failures.md was not created after write — fix stage may skip')\n }\n } catch (writeErr) {\n logger.warn(`Failed to write verify-failures.md: ${writeErr}`)\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern skip-conditions\n * @ai-summary Pure functions that determine if a stage should be skipped\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext, SkipResult } from '../engine/types'\nimport { getStageComplexityThreshold, isValidStageName } from '../stages/registry'\nimport { getComplexityTier } from '../pipeline-utils'\n\n/**\n * Check if stage should be skipped due to input_quality skip_stages\n */\nexport function skipIfInputQuality(ctx: PipelineContext, stageName: string): SkipResult {\n const taskDef = ctx.taskDef\n if (!taskDef?.input_quality?.skip_stages) {\n return { shouldSkip: false }\n }\n\n const skipStages = taskDef.input_quality.skip_stages\n if (!skipStages.includes(stageName as 'gap' | 'clarify' | 'architect' | 'plan-gap' | 'build')) {\n return { shouldSkip: false }\n }\n\n // Check if promoted file exists AND has valid content\n // FIX #4: Don't just check existence - validate content is meaningful\n // A stub file from an interrupted run should not cause skip\n const outputFile = path.join(ctx.taskDir, `${stageName}.md`)\n if (!fs.existsSync(outputFile)) {\n return { shouldSkip: false }\n }\n\n // Validate the file has meaningful content (not just a stub)\n const fileContent = fs.readFileSync(outputFile, 'utf-8').trim()\n const minContentLength = 50 // Minimum meaningful content length\n\n if (\n fileContent.length < minContentLength ||\n (fileContent.includes('(promoted)') && fileContent.length < 200)\n ) {\n // File is too short or appears to be an incomplete stub\n // Don't skip - let the stage run to regenerate proper content\n return { shouldSkip: false }\n }\n\n return {\n shouldSkip: true,\n reason: `Promoted via input_quality (valid file exists)`,\n }\n}\n\n/**\n * Check if clarify stage should be skipped when --clarify is disabled.\n * Also handles auto-create of clarified.md and cleanup of questions.md.\n */\nexport function skipIfClarifyDisabled(ctx: PipelineContext): SkipResult {\n // Only applies when clarify is DISABLED\n if (ctx.input.clarify) {\n return { shouldSkip: false }\n }\n\n const clarifiedPath = path.join(ctx.taskDir, 'clarified.md')\n\n // Create default clarified.md if it doesn't exist\n if (!fs.existsSync(clarifiedPath)) {\n fs.writeFileSync(clarifiedPath, '# Clarified\\n\\nUse recommended answers.\\n')\n }\n\n // Clean up residual questions.md from previous clarify-enabled run\n const questionsPath = path.join(ctx.taskDir, 'questions.md')\n if (fs.existsSync(questionsPath)) {\n fs.unlinkSync(questionsPath)\n }\n\n return { shouldSkip: true, reason: 'Clarify disabled, auto-created clarified.md' }\n}\n\n/**\n * Check if clarify stage should be skipped when spec has no open questions.\n * ONLY applies when clarify IS enabled (G12).\n */\nexport function skipIfSpecHasNoOpenQuestions(ctx: PipelineContext): SkipResult {\n // Only applies when clarify IS enabled\n if (!ctx.input.clarify) {\n return { shouldSkip: false }\n }\n\n const specFile = path.join(ctx.taskDir, 'spec.md')\n if (!fs.existsSync(specFile)) {\n return { shouldSkip: false }\n }\n\n const specContent = fs.readFileSync(specFile, 'utf-8')\n const hasOpenQuestions = /##\\s*Open Questions/i.test(specContent)\n\n if (!hasOpenQuestions) {\n return { shouldSkip: true, reason: 'Spec has no Open Questions' }\n }\n\n return { shouldSkip: false }\n}\n\n/**\n * Check if impl stages should be skipped for spec_only pipelines\n */\nexport function skipIfSpecOnly(ctx: PipelineContext): SkipResult {\n const taskDef = ctx.taskDef\n if (taskDef?.pipeline === 'spec_only') {\n return { shouldSkip: true, reason: 'Pipeline is spec_only' }\n }\n return { shouldSkip: false }\n}\n\n/**\n * Check if a stage should be skipped based on the task's complexity score.\n * Each stage has a minimum complexity threshold defined in STAGE_COMPLEXITY_THRESHOLDS.\n * If the task's complexity is below the threshold, the stage is skipped.\n *\n * Returns { shouldSkip: false } when:\n * - No complexity score is set (backward compat — fall through to other skip logic)\n * - The stage has no threshold (always runs)\n * - The task's complexity meets or exceeds the threshold\n */\nexport function skipIfBelowComplexity(ctx: PipelineContext, stageName: string): SkipResult {\n const complexity = ctx.taskDef?.complexity\n // No complexity score → don't skip (backward compatibility)\n if (complexity === undefined) {\n return { shouldSkip: false }\n }\n\n if (!isValidStageName(stageName)) {\n return { shouldSkip: false }\n }\n const threshold = getStageComplexityThreshold(stageName)\n // No threshold defined for this stage → don't skip\n if (threshold === 0) {\n return { shouldSkip: false }\n }\n\n if (complexity < threshold) {\n const tier = getComplexityTier(complexity)\n return {\n shouldSkip: true,\n reason: `Complexity ${complexity} (${tier}) below threshold ${threshold} for ${stageName}`,\n }\n }\n\n return { shouldSkip: false }\n}\n","/**\n * @fileType configuration\n * @domain kody | pipeline\n * @pattern pipeline-definitions\n * @ai-summary Declarative stage configurations for the Kody pipeline state machine\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type {\n PipelineDefinition,\n PipelineContext,\n StageDefinition,\n PipelineStep,\n} from '../engine/types'\nimport {\n type StageName,\n getStageTimeout,\n getStageComplexityThreshold,\n SPEC_ORDER_STANDARD,\n SPEC_ORDER_LIGHTWEIGHT,\n IMPL_ORDER_STANDARD,\n IMPL_ORDER_LIGHTWEIGHT,\n SPEC_ORDER_TURBO,\n IMPL_ORDER_TURBO,\n} from '../stages/registry'\nimport { ensureFeatureBranch } from '../git-utils'\nimport { readTask } from '../pipeline-utils'\nimport { setBranchName, loadState } from '../engine/status'\nimport { execFileSync } from 'child_process'\nimport {\n createGapValidator,\n createPlanGapValidator,\n createBuildValidator,\n createDocsValidator,\n createTestValidator,\n} from './validators'\nimport { captureVerifyFailures } from './verify-failures'\nimport { DEFAULT_MAX_FIX_ATTEMPTS } from '../config/constants'\nimport {\n skipIfInputQuality,\n skipIfClarifyDisabled,\n skipIfSpecHasNoOpenQuestions,\n skipIfSpecOnly,\n skipIfBelowComplexity,\n} from './skip-conditions'\nimport { logger } from '../logger'\n\n// Re-export pipeline order arrays from registry for backward compatibility\nexport {\n SPEC_ORDER_STANDARD,\n SPEC_ORDER_LIGHTWEIGHT,\n IMPL_ORDER_STANDARD,\n IMPL_ORDER_LIGHTWEIGHT,\n SPEC_ORDER_TURBO,\n IMPL_ORDER_TURBO,\n FIX_ORDER,\n FIX_FULL_ORDER,\n} from '../stages/registry'\n\n// ============================================================================\n// Prev-Run File Restoration\n// ============================================================================\n\n/**\n * Restore prev-run files from git if they're missing.\n * This handles the case where pipeline restarts after a previous run\n * already created the output files (e.g., architect succeeded but pipeline\n * restarted from taskify).\n */\nasync function restorePrevRunFiles(taskDir: string, _taskId: string): Promise<void> {\n const prevRunDir = path.join(taskDir, 'prev-run')\n\n // Files to restore from git\n const filesToRestore = ['plan.md', 'build.md', 'review.md']\n\n for (const file of filesToRestore) {\n const prevRunPath = path.join(prevRunDir, file)\n const mainPath = path.join(taskDir, file)\n\n // If prev-run version exists, nothing to do\n if (fs.existsSync(prevRunPath)) {\n continue\n }\n\n // Try to get the file from git (current branch's latest commit)\n try {\n const gitShowOutput = execFileSync('git', ['show', `HEAD:${taskDir}/${file}`], {\n encoding: 'utf-8',\n timeout: 10000,\n })\n\n // Ensure prev-run directory exists\n if (!fs.existsSync(prevRunDir)) {\n fs.mkdirSync(prevRunDir, { recursive: true })\n }\n\n // Write to prev-run/\n fs.writeFileSync(prevRunPath, gitShowOutput)\n logger.info(` 🔄 Restored ${file} from git to prev-run/`)\n\n // Also restore to main location if the main file doesn't exist\n if (!fs.existsSync(mainPath)) {\n fs.writeFileSync(mainPath, gitShowOutput)\n logger.info(` 🔄 Restored ${file} from git to main location`)\n }\n } catch {\n // File not in git, that's OK - it may not have been created yet\n }\n }\n}\n\n// ============================================================================\n// Stage Definitions\n// ============================================================================\n\n/**\n * Create all stage definitions\n */\nfunction createStageDefinitions(ctx: PipelineContext): Map<StageName, StageDefinition> {\n const stages = new Map<StageName, StageDefinition>()\n\n // taskify stage\n stages.set('taskify', {\n name: 'taskify',\n type: 'agent',\n timeout: getStageTimeout('taskify'),\n maxRetries: 1,\n postActions: [\n { type: 'validate-task-json' },\n { type: 'set-classification-labels' },\n // NOTE: resolve-profile MUST be last to ensure profile is resolved before check-gate runs\n // see issue #1 in pipeline analysis - profile race condition fix\n { type: 'check-gate', gate: 'taskify' },\n {\n type: 'commit-task-files',\n stagingStrategy: 'task-only',\n push: true,\n ensureBranch: true,\n },\n { type: 'resolve-profile' }, // Must be last - triggers pipeline rebuild for next stages\n ],\n })\n\n // gap stage (also writes spec.md — spec stage was merged into gap)\n stages.set('gap', {\n name: 'gap',\n type: 'agent',\n timeout: getStageTimeout('gap'),\n maxRetries: 1,\n minComplexity: getStageComplexityThreshold('gap'),\n shouldSkip: (ctx) => {\n const complexitySkip = skipIfBelowComplexity(ctx, 'gap')\n if (complexitySkip.shouldSkip) return complexitySkip\n return skipIfInputQuality(ctx, 'gap')\n },\n validator: createGapValidator(ctx),\n })\n\n // clarify stage - NO post-actions (G17)\n stages.set('clarify', {\n name: 'clarify',\n type: 'agent',\n timeout: getStageTimeout('clarify'),\n maxRetries: 1,\n minComplexity: getStageComplexityThreshold('clarify'),\n shouldSkip: (ctx) => {\n // First check complexity threshold\n const complexitySkip = skipIfBelowComplexity(ctx, 'clarify')\n if (complexitySkip.shouldSkip) return complexitySkip\n\n // Then try input quality skip\n const inputQualitySkip = skipIfInputQuality(ctx, 'clarify')\n if (inputQualitySkip.shouldSkip) return inputQualitySkip\n\n // Then try clarify disabled skip\n const clarifyDisabledSkip = skipIfClarifyDisabled(ctx)\n if (clarifyDisabledSkip.shouldSkip) return clarifyDisabledSkip\n\n // Then try no open questions skip (only when clarify IS enabled)\n const noQuestionsSkip = skipIfSpecHasNoOpenQuestions(ctx)\n return noQuestionsSkip\n },\n })\n\n // architect stage\n stages.set('architect', {\n name: 'architect',\n type: 'agent',\n timeout: getStageTimeout('architect'),\n maxRetries: 1,\n minComplexity: getStageComplexityThreshold('architect'),\n shouldSkip: (ctx) => {\n const complexitySkip = skipIfBelowComplexity(ctx, 'architect')\n if (complexitySkip.shouldSkip) return complexitySkip\n return skipIfSpecOnly(ctx)\n },\n preExecute: async (ctx) => {\n // Restore prev-run files from git if they're missing\n // This handles the case where pipeline restarts after architect previously succeeded\n await restorePrevRunFiles(ctx.taskDir, ctx.taskId)\n },\n postActions: [\n { type: 'archive-rerun-feedback' },\n { type: 'check-gate', gate: 'architect', includeArtifact: 'plan.md' },\n ],\n fallbackOnMissingOutput: (ctx) => {\n // Fallback: try to use existing plan.md, context.md, or restore from git\n const planFile = path.join(ctx.taskDir, 'plan.md')\n if (fs.existsSync(planFile)) return null // File exists, no fallback needed\n\n // First try: restore from git (handles case where pipeline restarted but git has the file)\n const prevRunPlan = path.join(ctx.taskDir, 'prev-run', 'plan.md')\n if (fs.existsSync(prevRunPlan)) {\n // Copy to main location\n fs.copyFileSync(prevRunPlan, planFile)\n logger.info(` ℹ️ Restored plan.md from prev-run/`)\n return null // File now exists, let stage proceed\n }\n\n // Second try: use context.md as a rough plan\n // This happens when agent does extensive research but runs out of output capacity\n const contextFile = path.join(ctx.taskDir, 'context.md')\n if (fs.existsSync(contextFile)) {\n logger.warn(\n ` ⚠️ Architect fallback: using context.md as plan substitute for ${ctx.taskId}`,\n )\n const contextContent = fs.readFileSync(contextFile, 'utf-8')\n return `# Plan: ${ctx.taskId}\n\n## Summary\n\nArchitect agent completed research but did not write plan.md. Using context.md as fallback plan.\n\n${contextContent}\n\n## Note\n\nThis plan was auto-generated from context.md because architect failed to produce plan.md.\nThe implementation should proceed using the file list in context.md.\n`\n }\n return null\n },\n })\n\n // plan-gap stage\n stages.set('plan-gap', {\n name: 'plan-gap',\n type: 'agent',\n timeout: getStageTimeout('plan-gap'),\n maxRetries: 1,\n minComplexity: getStageComplexityThreshold('plan-gap'),\n shouldSkip: (ctx) => {\n // Skip plan-gap when pipeline is spec_only (no plan.md exists to gap-check)\n const specOnlySkip = skipIfSpecOnly(ctx)\n if (specOnlySkip.shouldSkip) return specOnlySkip\n const complexitySkip = skipIfBelowComplexity(ctx, 'plan-gap')\n if (complexitySkip.shouldSkip) return complexitySkip\n return skipIfInputQuality(ctx, 'plan-gap')\n },\n postActions: [{ type: 'validate-plan-exists' }],\n validator: createPlanGapValidator(ctx),\n fallbackOnMissingOutput: (ctx) => {\n // If agent edited plan.md but forgot to write plan-gap.md, create a fallback\n const planFile = path.join(ctx.taskDir, 'plan.md')\n if (fs.existsSync(planFile)) {\n logger.warn(\n ` ⚠️ Plan-gap fallback: agent edited plan.md directly without writing plan-gap.md for ${ctx.taskId}`,\n )\n return `# Plan Gap Analysis: ${ctx.taskId}\n\n## Summary\n\n- Gaps Found: 0\n- Plan Revised: Yes (agent edited plan.md directly)\n\n## Changes Made to Plan\n\nAgent revised plan.md but did not produce a separate gap report.\nSee plan.md for the revised plan.\n\n## No Gaps Found\n\nNo critical gaps identified. Plan was refined in-place.\n`\n }\n return null\n },\n })\n\n // test stage — TDD red phase: writes failing tests in parallel with build\n stages.set('test', {\n name: 'test',\n type: 'agent',\n timeout: getStageTimeout('test'),\n maxRetries: 1,\n minComplexity: getStageComplexityThreshold('test'),\n shouldSkip: (ctx) => skipIfInputQuality(ctx, 'test'),\n preExecute: async (ctx) => {\n // Ensure feature branch for deferred test runs (triggered by inspector plugin).\n // Without this, the test stage would try to commit/push to dev (branch-protected).\n if (!ctx.input.dryRun) {\n try {\n const td = readTask(ctx.taskDir)\n if (td) {\n ensureFeatureBranch(ctx.taskId, td.task_type, undefined, ctx.taskDir)\n }\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error)\n throw new Error(`Test stage preExecute failed: ${msg}`)\n }\n }\n },\n postActions: [\n // Commit test files after test stage completes (for deferred test runs)\n {\n type: 'commit-task-files',\n stagingStrategy: 'tracked+task',\n push: true,\n ensureBranch: true,\n },\n ],\n validator: createTestValidator(),\n })\n // build stage - has preExecute for ensureFeatureBranch (G20)\n stages.set('build', {\n name: 'build',\n type: 'agent',\n timeout: getStageTimeout('build'),\n maxRetries: 1,\n minComplexity: getStageComplexityThreshold('build'),\n shouldSkip: (ctx) => skipIfInputQuality(ctx, 'build'),\n preExecute: async (ctx) => {\n if (!ctx.input.dryRun) {\n try {\n const td = readTask(ctx.taskDir)\n if (td) {\n ensureFeatureBranch(ctx.taskId, td.task_type, undefined, ctx.taskDir)\n\n // Capture the branch name and persist to status.json for dashboard lookups\n try {\n const currentBranch = execFileSync('git', ['branch', '--show-current'], {\n encoding: 'utf-8',\n timeout: 10000, // 10 seconds\n }).trim()\n if (currentBranch) {\n const state = loadState(ctx.taskId)\n if (state) {\n setBranchName(ctx.taskId, state, currentBranch)\n }\n }\n } catch {\n // Non-critical — branch name is a convenience field\n }\n }\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error)\n throw new Error(`Build stage preExecute failed: ${msg}`)\n }\n }\n },\n postActions: [\n { type: 'validate-src-changes' },\n { type: 'validate-build-content' },\n // Commit code BEFORE quality gates so work is preserved even if gates fail.\n // Without this, a gate failure means all build agent work is lost.\n {\n type: 'commit-task-files',\n stagingStrategy: 'tracked+task',\n push: true,\n ensureBranch: true,\n },\n // Run lint:fix + format:fix mechanically BEFORE quality gates.\n // This is deterministic (no LLM needed) and prevents trivial format/lint\n // failures from reaching verify stage or wasting LLM fix attempts.\n { type: 'run-mechanical-autofix' },\n {\n type: 'run-quality-with-autofix',\n gates: [\n { name: 'TypeScript', command: 'pnpm -s tsc --noEmit', source: 'tsc' as const },\n // No unit test gate — test stage handles test validation\n ],\n maxFeedbackLoops: 2,\n },\n ],\n validator: createBuildValidator(),\n // No fallback for build stage — a missing build.md is a real failure.\n // The agent handler will retry or fail the stage explicitly.\n // Previously generated a degraded substitute from `git diff --name-only`,\n // which masked failures and gave downstream stages (review, verify) incomplete input.\n })\n\n // review stage - architect agent reviews generated code\n stages.set('review', {\n name: 'review',\n type: 'agent',\n timeout: getStageTimeout('review'),\n maxRetries: 0,\n minComplexity: getStageComplexityThreshold('review'),\n shouldSkip: (ctx) => {\n const complexitySkip = skipIfBelowComplexity(ctx, 'review')\n if (complexitySkip.shouldSkip) return complexitySkip\n return { shouldSkip: false }\n },\n postActions: [\n { type: 'analyze-review-findings' },\n { type: 'commit-task-files', stagingStrategy: 'task-only', push: true, ensureBranch: false },\n ],\n })\n\n // fix stage — re-invokes build agent to fix review findings\n // The build agent has full context (spec, plan, code intent) and wrote the code.\n stages.set('fix', {\n name: 'fix',\n type: 'agent',\n agentName: 'build', // Build agent fixes its own code based on review.md\n timeout: getStageTimeout('fix'),\n maxRetries: 1,\n shouldSkip: (ctx) => {\n // In fix mode, never skip — user explicitly requested fixes\n if (ctx.input.mode === 'fix') {\n return { shouldSkip: false }\n }\n const state = loadState(ctx.taskId)\n const fixStage = state?.stages?.fix\n if (\n fixStage?.fixAttempt !== undefined &&\n fixStage.fixAttempt >= (fixStage.maxFixAttempts ?? 2)\n ) {\n return { shouldSkip: true, reason: 'Max fix attempts reached' }\n }\n const reviewStage = state?.stages?.review\n if (!reviewStage?.issuesFound) {\n const verifyFailuresPath = path.join(ctx.taskDir, 'verify-failures.md')\n if (!fs.existsSync(verifyFailuresPath)) {\n return { shouldSkip: true, reason: 'No issues to fix' }\n }\n }\n return { shouldSkip: false }\n },\n postActions: [\n {\n type: 'commit-task-files',\n stagingStrategy: 'tracked+task',\n push: true,\n ensureBranch: false,\n },\n { type: 'clear-verify-failures' },\n ],\n })\n\n // commit stage\n stages.set('commit', {\n name: 'commit',\n type: 'git',\n timeout: getStageTimeout('commit'),\n maxRetries: 0,\n })\n\n // verify stage\n stages.set('verify', {\n name: 'verify',\n type: 'scripted',\n timeout: getStageTimeout('verify'),\n maxRetries: 0,\n // R2-FIX: Clear stale verify-failures.md before running verify.\n // Without this, a retry loop (verify→fix→verify) may process stale failures\n // from the previous attempt, causing the fix agent to work on wrong errors.\n preExecute: async (ctx) => {\n const failuresPath = path.join(ctx.taskDir, 'verify-failures.md')\n if (fs.existsSync(failuresPath)) {\n fs.unlinkSync(failuresPath)\n }\n },\n retryWith: {\n stage: 'fix',\n maxAttempts: DEFAULT_MAX_FIX_ATTEMPTS,\n onFailure: captureVerifyFailures,\n onTimeout: 'retry',\n },\n postActions: [\n // LOCAL-ONLY commit of task files after verify completes (G18)\n // NOT the autofix commit - that's inside ScriptedVerifyHandler\n {\n type: 'commit-task-files',\n stagingStrategy: 'task-only',\n push: false,\n ensureBranch: false,\n localOnly: true,\n },\n // Update knowledge base with patterns learned from this task\n // Non-blocking: executeUpdateKnowledgeBase handles errors gracefully\n { type: 'update-knowledge-base' },\n ],\n })\n\n // docs stage - deferred to nightly inspector (Knowledge Gardener plugin).\n // Kept here so the state machine can execute it if triggered directly (e.g., manual rerun).\n // Complexity threshold raised to 30 (moderate+) — trivial/simple tasks skip docs.\n stages.set('docs', {\n name: 'docs',\n type: 'agent',\n timeout: getStageTimeout('docs'),\n maxRetries: 1,\n minComplexity: getStageComplexityThreshold('docs'),\n shouldSkip: (ctx) => {\n const complexitySkip = skipIfBelowComplexity(ctx, 'docs')\n if (complexitySkip.shouldSkip) return complexitySkip\n return { shouldSkip: false }\n },\n validator: createDocsValidator(),\n postActions: [\n {\n type: 'commit-task-files',\n stagingStrategy: 'tracked+task',\n push: true,\n ensureBranch: false,\n },\n ],\n })\n\n // pr stage\n stages.set('pr', {\n name: 'pr',\n type: 'git',\n timeout: getStageTimeout('pr'),\n maxRetries: 0,\n })\n\n return stages\n}\n\n// ============================================================================\n// Pipeline Builder\n// ============================================================================\n\n/**\n * Rebuild pipeline after taskify completes\n * Extends the pipeline with remaining stages based on profile\n */\nexport function rebuildPipelineAfterTaskify(\n _currentPipeline: PipelineDefinition,\n ctx: PipelineContext,\n): PipelineDefinition {\n // For full mode, we need BOTH spec stages (completed) AND impl stages (to run)\n // Build spec stages based on profile\n const specOrder = ctx.profile === 'standard' ? SPEC_ORDER_STANDARD : SPEC_ORDER_LIGHTWEIGHT\n const filteredSpecOrder = ctx.input.clarify ? specOrder : specOrder.filter((s) => s !== 'clarify')\n\n // For spec_only pipelines, don't include impl stages — there's no plan.md to build from\n if (ctx.taskDef?.pipeline === 'spec_only') {\n return {\n stages: createStageDefinitions(ctx),\n order: [...filteredSpecOrder],\n }\n }\n\n // Build impl stages based on profile\n const implOrder = ctx.profile === 'standard' ? IMPL_ORDER_STANDARD : IMPL_ORDER_LIGHTWEIGHT\n\n // Combine: spec stages first (already completed), then impl stages (to run)\n return {\n stages: createStageDefinitions(ctx),\n order: [...filteredSpecOrder, ...implOrder],\n }\n}\n\n/**\n * Build pipeline definition based on mode, profile, and clarify flag\n */\nexport function buildPipeline(\n mode: 'spec' | 'impl' | 'full' | 'rerun',\n profile: 'standard' | 'lightweight' | 'turbo',\n clarify: boolean,\n ctx: PipelineContext,\n): PipelineDefinition {\n const stages = createStageDefinitions(ctx)\n\n // Determine stage order based on mode and profile\n let order: PipelineStep[] = []\n\n if (mode === 'spec') {\n // Spec stages only\n const specOrder =\n profile === 'standard'\n ? SPEC_ORDER_STANDARD\n : profile === 'turbo'\n ? SPEC_ORDER_TURBO\n : SPEC_ORDER_LIGHTWEIGHT\n // If clarify is disabled, remove it from the spec order\n const filteredSpecOrder = clarify ? specOrder : specOrder.filter((s) => s !== 'clarify')\n order = [...filteredSpecOrder]\n } else if (mode === 'impl') {\n // Implementation stages only\n const implOrder =\n profile === 'standard'\n ? IMPL_ORDER_STANDARD\n : profile === 'turbo'\n ? IMPL_ORDER_TURBO\n : IMPL_ORDER_LIGHTWEIGHT\n order = [...implOrder]\n } else if (mode === 'full' || mode === 'rerun') {\n // Full/rerun mode: include both spec and impl stages\n // This ensures the pipeline survives restarts — all stages are present\n // and the state machine efficiently skips completed ones\n const specOrder =\n profile === 'standard'\n ? SPEC_ORDER_STANDARD\n : profile === 'turbo'\n ? SPEC_ORDER_TURBO\n : SPEC_ORDER_LIGHTWEIGHT\n const implOrder =\n profile === 'standard'\n ? IMPL_ORDER_STANDARD\n : profile === 'turbo'\n ? IMPL_ORDER_TURBO\n : IMPL_ORDER_LIGHTWEIGHT\n const filteredSpecOrder = clarify ? specOrder : specOrder.filter((s) => s !== 'clarify')\n order = [...filteredSpecOrder, ...implOrder]\n }\n\n return { stages, order }\n}\n\n/**\n * Flatten pipeline order (including parallel stages) into a flat array of stage names\n */\nexport function flattenPipelineOrder(order: PipelineStep[]): StageName[] {\n const result: StageName[] = []\n for (const step of order) {\n if (typeof step === 'string') {\n result.push(step)\n } else if ('parallel' in step) {\n result.push(...step.parallel)\n }\n }\n return result\n}\n","/**\n * @fileType engine\n * @domain kody | engine\n * @pattern pipeline-resolver\n * @ai-summary Pipeline construction based on mode and profile\n */\n\nimport type { PipelineDefinition, PipelineContext } from '../engine/types'\nimport {\n buildPipeline,\n rebuildPipelineAfterTaskify as rebuildFromDefinitions,\n FIX_FULL_ORDER,\n} from '../pipeline/definitions'\n\n/**\n * Resolve pipeline for a given mode\n */\nexport function resolvePipelineForMode(\n mode: 'spec' | 'impl' | 'full' | 'rerun' | 'fix' | 'status',\n profile: 'standard' | 'lightweight' | 'turbo',\n clarify: boolean,\n ctx: PipelineContext,\n): PipelineDefinition {\n switch (mode) {\n case 'spec':\n case 'full':\n return buildPipeline(mode, profile, clarify, ctx)\n case 'impl':\n return buildPipeline('impl', profile, clarify, ctx)\n case 'rerun':\n // Rerun needs BOTH spec and impl stages to support resuming from any stage\n return buildPipeline('rerun', profile, clarify, ctx)\n case 'fix': {\n // Fix mode uses FIX_FULL_ORDER (taskify → architect → plan-gap → build → ... → pr)\n // This runs the full pipeline with previous artifacts as context\n const fixPipeline = buildPipeline('full', profile, clarify, ctx)\n return { stages: fixPipeline.stages, order: FIX_FULL_ORDER }\n }\n case 'status':\n // No pipeline for status mode\n return { stages: new Map(), order: [] }\n default:\n return buildPipeline('full', profile, clarify, ctx)\n }\n}\n\n/**\n * Rebuild pipeline after taskify completes\n * Extends the pipeline with remaining stages based on profile.\n *\n * Uses the dedicated rebuildPipelineAfterTaskify from definitions.ts\n * which correctly respects the resolved profile for spec stage order,\n * unlike buildPipeline('rerun') which always uses SPEC_ORDER_STANDARD.\n */\nexport function rebuildPipelineAfterTaskify(\n currentPipeline: PipelineDefinition,\n ctx: PipelineContext,\n): PipelineDefinition {\n return rebuildFromDefinitions(currentPipeline, ctx)\n}\n\n/**\n * Create rebuild callback for the engine\n */\nexport function createRebuildCallback(\n _mode: 'spec' | 'impl' | 'full' | 'rerun' | 'fix',\n _clarify: boolean,\n): (ctx: PipelineContext) => PipelineDefinition {\n return (ctx) => rebuildPipelineAfterTaskify({ stages: new Map(), order: [] }, ctx)\n}\n","/**\n * @fileType utility\n * @domain kody | observability | structured-logging\n * @pattern structured-logging | pipeline-events\n * @ai-summary Structured event logging for Kody pipeline observability\n */\n\nimport { logger } from './logger'\nimport type { StageName } from './stages/registry'\n\n/**\n * All pipeline event types for structured logging.\n * Use these as the `event` field in log calls for consistent event classification.\n */\nexport const PIPELINE_EVENTS = {\n // Pipeline lifecycle\n PIPELINE_START: 'pipeline:start',\n PIPELINE_COMPLETE: 'pipeline:complete',\n PIPELINE_FAIL: 'pipeline:fail',\n PIPELINE_TIMEOUT: 'pipeline:timeout',\n PIPELINE_PAUSE: 'pipeline:pause',\n\n // Stage lifecycle\n STAGE_START: 'stage:start',\n STAGE_COMPLETE: 'stage:complete',\n STAGE_SKIP: 'stage:skip',\n STAGE_FAIL: 'stage:fail',\n STAGE_RETRY: 'stage:retry',\n STAGE_TIMEOUT: 'stage:timeout',\n\n // Gate events\n GATE_WAIT: 'gate:wait',\n GATE_APPROVE: 'gate:approve',\n GATE_REJECT: 'gate:reject',\n\n // Post-action events\n POST_ACTION_START: 'post-action:start',\n POST_ACTION_COMPLETE: 'post-action:complete',\n POST_ACTION_FAIL: 'post-action:fail',\n\n // Recovery events\n RECOVERY_TRIGGERED: 'recovery:triggered',\n RECOVERY_COMPLETE: 'recovery:complete',\n} as const\n\nexport type PipelineEventType = (typeof PIPELINE_EVENTS)[keyof typeof PIPELINE_EVENTS]\n\n/**\n * Structured log a stage start event.\n */\nexport function logStageStart(stageName: StageName, taskId: string, attempt?: number): void {\n logger.info(\n { event: PIPELINE_EVENTS.STAGE_START, stage: stageName, taskId, attempt },\n `▶ Starting stage: ${stageName}`,\n )\n}\n\n/**\n * Structured log a stage completion event.\n */\nexport function logStageComplete(\n stageName: StageName,\n taskId: string,\n outcome: string,\n duration?: number,\n): void {\n logger.info(\n { event: PIPELINE_EVENTS.STAGE_COMPLETE, stage: stageName, taskId, outcome, duration },\n `✅ Completed stage: ${stageName} (${outcome})`,\n )\n}\n\n/**\n * Structured log a stage skip event.\n */\nexport function logStageSkip(stageName: StageName | string, taskId: string, reason?: string): void {\n logger.info(\n { event: PIPELINE_EVENTS.STAGE_SKIP, stage: stageName, taskId, reason },\n `⏭ Skipped stage: ${stageName}${reason ? ` (${reason})` : ''}`,\n )\n}\n\n/**\n * Structured log a stage failure event.\n */\nexport function logStageFail(\n stageName: StageName | string,\n taskId: string,\n error?: string,\n retry?: boolean,\n): void {\n logger.error(\n { event: PIPELINE_EVENTS.STAGE_FAIL, stage: stageName, taskId, error, retry },\n `❌ Failed stage: ${stageName}${error ? ` - ${error}` : ''}${retry ? ' (will retry)' : ''}`,\n )\n}\n\n/**\n * Structured log a stage retry event.\n */\nexport function logStageRetry(\n stageName: StageName | string,\n taskId: string,\n attempt: number,\n maxRetries: number,\n): void {\n logger.warn(\n { event: PIPELINE_EVENTS.STAGE_RETRY, stage: stageName, taskId, attempt, maxRetries },\n `🔄 Retrying stage: ${stageName} (attempt ${attempt}/${maxRetries})`,\n )\n}\n\n/**\n * Structured log a pipeline start event.\n */\nexport function logPipelineStart(taskId: string, mode: string, profile: string): void {\n logger.info(\n { event: PIPELINE_EVENTS.PIPELINE_START, taskId, mode, profile },\n `🚀 Pipeline started: ${taskId} (${mode}, ${profile})`,\n )\n}\n\n/**\n * Structured log a pipeline completion event.\n */\nexport function logPipelineComplete(taskId: string, duration?: number, totalCost?: number): void {\n logger.info(\n { event: PIPELINE_EVENTS.PIPELINE_COMPLETE, taskId, duration, totalCost },\n `✅ Pipeline completed: ${taskId}${duration ? ` (${duration}ms)` : ''}`,\n )\n}\n\n/**\n * Structured log a gate wait event.\n */\nexport function logGateWait(gateName: string, taskId: string): void {\n logger.info(\n { event: PIPELINE_EVENTS.GATE_WAIT, gate: gateName, taskId },\n `⏸ Waiting for gate: ${gateName}`,\n )\n}\n\n/**\n * Structured log a recovery action.\n */\nexport function logRecovery(stageName: StageName | string, taskId: string, reason: string): void {\n logger.info(\n { event: PIPELINE_EVENTS.RECOVERY_TRIGGERED, stage: stageName, taskId, reason },\n `🔧 Recovery triggered: ${stageName} - ${reason}`,\n )\n}\n\n/**\n * Structured log a post-action event.\n */\nexport function logPostAction(\n actionType: string,\n taskId: string,\n status: 'start' | 'complete' | 'fail',\n error?: string,\n): void {\n const event =\n status === 'start'\n ? PIPELINE_EVENTS.POST_ACTION_START\n : status === 'complete'\n ? PIPELINE_EVENTS.POST_ACTION_COMPLETE\n : PIPELINE_EVENTS.POST_ACTION_FAIL\n\n const logFn = status === 'fail' ? logger.error : status === 'start' ? logger.info : logger.info\n\n logFn(\n { event, actionType, taskId, error },\n `${status === 'start' ? '▶' : status === 'complete' ? '✅' : '❌'} Post-action [${actionType}]: ${status}${error ? ` - ${error}` : ''}`,\n )\n}\n","/**\n * @fileType utility\n * @domain ci | kody | prompts\n * @pattern stage-prompts\n * @ai-summary Stage runtime context for OpenCode agents — behavioral instructions live in .opencode/agents/*.md\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { KodyInput } from './kody-utils'\nimport {\n getStageContextFiles,\n stageOutputFile,\n isValidStageName,\n SPEC_ORDER_STANDARD,\n SPEC_ORDER_LIGHTWEIGHT,\n flattenTypedPipeline,\n IMPL_ORDER_STANDARD,\n IMPL_ORDER_LIGHTWEIGHT,\n} from './stages/registry'\n\n// Re-export for backward compatibility\nexport { SPEC_STAGES, SCRIPTED_STAGES } from './stages/registry'\n\n// ============================================================================\n// Stage Context — which files each stage needs to read\n// ============================================================================\n\n// ============================================================================\n// Stage Instructions — runtime context ONLY (not behavioral)\n//\n// Behavioral instructions (how to act, output format, rules) live in\n// .opencode/agents/<stage>.md. These instructions provide ONLY:\n// - Spec-only guard (don't modify code)\n// - Stage-specific runtime context hints (e.g., \"this is a rerun\")\n// ============================================================================\n\n// Use absolute path to avoid OpenCode path interpretation issues with task IDs containing hyphens\nconst specOnlyInstructionTemplate = (taskDir: string) =>\n `CRITICAL: This is a SPEC-ONLY pipeline. DO NOT create branches, commits, or pull requests. DO NOT modify any code files. Only read from and write to the ${taskDir}/ directory.`\n\nexport const stageInstructions: Record<string, (taskId: string) => string> = {\n taskify: (taskId) => {\n const taskDir = path.join(process.cwd(), '.tasks', taskId)\n return specOnlyInstructionTemplate(taskDir)\n },\n\n gap: (taskId) => {\n const taskDir = path.join(process.cwd(), '.tasks', taskId)\n return specOnlyInstructionTemplate(taskDir)\n },\n\n clarify: (taskId) => {\n const taskDir = path.join(process.cwd(), '.tasks', taskId)\n return specOnlyInstructionTemplate(taskDir)\n },\n\n architect: () => ``,\n\n 'plan-gap': () => ``,\n\n test: () => `TDD RED PHASE: Write failing tests from the plan.\nYou run in PARALLEL with the build agent. Write tests to tests/ ONLY.\nDo NOT modify src/. Do NOT run tests (they will fail without implementation).`,\n\n build: () => `CRITICAL: IMPLEMENTATION STAGE - NOT DOCUMENTATION ONLY\n\nYou must ACTUALLY IMPLEMENT the code changes, not just document them.\n\nYour job is to:\n1. Use Edit/Write tools to modify source files in src/\n2. Create new files as needed\n3. Run tests to verify\n4. **MUST write build.md** summarizing what was implemented before exiting\n\nThe build.md file format:\n- Must include a ## Changes or ## Files section (required by pipeline validation)\n- Should be a SUMMARY of what was implemented\n- Write it to: .tasks/<taskId>/build.md\n\nExample format:\n\\`\\`\\`markdown\n# Build Summary\n\n## Changes\n- Created src/infra/utils/pipeline-health.ts\n- Added PipelineHealthReport class\n- Added integration tests\n\n## Files\n- src/infra/utils/pipeline-health.ts\n- tests/unit/infra/utils/pipeline-health.test.ts\n\\`\\`\\`\n\nDO NOT skip writing build.md - the pipeline REQUIRES this file!`,\n\n commit: () => ``,\n\n review: () => `CRITICAL: CODE REVIEW + SPEC SATISFACTION STAGE\n\nYou are reviewing already-generated code AND verifying spec satisfaction. DO NOT modify code files.\n\nYour #1 job is the GOAL-BACKWARD SPEC CHECK: for every requirement in spec.md, verify there is matching code.\nYour #2 job is standard code review (security, correctness, quality).\nNOTE: Tests are written separately via the deferred-tests inspector plugin. Do NOT flag missing tests as issues.\n\nProduce review.md with a Spec Satisfaction matrix (requirement → code location → status) FIRST, then code quality findings.\nIf ANY spec requirement has no corresponding code: mark as Critical issue.`,\n\n fix: () => `CRITICAL: TARGETED FIX STAGE\n\nYou are applying MINIMAL fixes to resolve identified issues.\nDO NOT regenerate entire codebase.\nDO NOT refactor or rewrite working code.\nOnly fix the specific issues identified in verify-failures.md, review.md, or rerun-feedback.md.\n\nFor fix_bug tasks: follow the SCIENTIFIC DEBUG PROTOCOL in your agent instructions.\nHypothesis first, reproduction test second, minimal fix third.\n\nIMPORTANT: If review.md lists many issues (dozens+), focus on the CRITICAL issues first, then MAJOR issues.\nDo NOT try to fix every single issue — prioritize the most impactful ones.\nThe goal is to make the code substantially better, not perfectly bug-free.\nWrite fix-summary.md summarizing what you changed.`,\n\n // Scripted stages — these prompts are never sent to an LLM\n verify: () => ``,\n autofix: () => ``,\n docs: () => `DOCUMENTATION STAGE\n\nYou are updating project documentation based on task changes.\nDO NOT modify source code files — only documentation files (.md, .json indexes).\nWrite docs.md as your output summarizing documentation changes.`,\n pr: () => ``,\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Read task_type from task.json for the given task.\n * Returns 'implement_feature' as default if task.json doesn't exist or is invalid.\n */\nfunction getTaskType(taskId: string): string {\n const taskJsonPath = path.join(process.cwd(), '.tasks', taskId, 'task.json')\n try {\n if (fs.existsSync(taskJsonPath)) {\n const content = fs.readFileSync(taskJsonPath, 'utf-8')\n const data = JSON.parse(content)\n if (data.task_type && typeof data.task_type === 'string') {\n return data.task_type\n }\n }\n } catch {\n // Ignore errors, return default\n }\n return 'implement_feature'\n}\n\n/**\n * Build the prompt for a given stage.\n * @param input - Orchestrator input with taskId\n * @param stage - The stage to build the prompt for\n * @param feedback - Optional feedback from a previous validation failure to include in the prompt\n * @returns The complete prompt string to pass to the agent\n */\nexport function buildStagePrompt(input: KodyInput, stage: string, feedback?: string): string {\n const { taskId } = input\n // Use absolute path to avoid OpenCode path interpretation issues with task IDs containing hyphens\n const taskDir = path.join(process.cwd(), '.tasks', taskId)\n\n // Get task_type for stages that need it (architect, build)\n const taskType = getTaskType(taskId)\n\n const instructionFn = stageInstructions[stage]\n const instruction = instructionFn ? instructionFn(taskId) : ''\n\n // Build file list for this stage\n const contextFiles = isValidStageName(stage) ? getStageContextFiles(stage) : []\n const fileList = contextFiles.map((f) => `- ${taskDir}/${f}`).join('\\n')\n\n const filesSection =\n contextFiles.length > 0\n ? `\\nRead these files for context:\\n${fileList}`\n : ''\n\n // Add task_type for stages that need it (architect, build)\n const taskTypeSection =\n stage === 'architect' || stage === 'build' ? `\\nTask Type: ${taskType}` : ''\n\n const outputFile = stageOutputFile(taskDir, stage)\n\n // Add feedback section if provided\n const feedbackSection = feedback\n ? `\\n⚠️ VALIDATION ERROR FROM PREVIOUS ATTEMPT:\\n${feedback}\\n\\nPlease fix this in your next attempt.`\n : ''\n\n const parts = [\n instruction,\n `Task ID: ${taskId}`,\n taskTypeSection,\n filesSection,\n feedbackSection,\n `Write your output to ${outputFile}`,\n ].filter(Boolean)\n\n return parts.join('\\n\\n')\n}\n\n/**\n * Get spec pipeline stages (taskify, gap — without clarify by default)\n * @param profile - Optional pipeline profile ('lightweight' | 'standard'), defaults to 'standard'\n */\nexport function getSpecStages(profile?: 'lightweight' | 'standard'): string[] {\n const order = profile === 'lightweight' ? SPEC_ORDER_LIGHTWEIGHT : SPEC_ORDER_STANDARD\n // Default: exclude clarify (backward compat with old getSpecStagesForProfile(profile, false))\n return order.filter((s) => s !== 'clarify')\n}\n\n/**\n * Get implementation pipeline stages\n * @param profile - Optional pipeline profile ('lightweight' | 'standard'), defaults to 'standard'\n */\nexport function getImplStages(profile?: 'lightweight' | 'standard'): string[] {\n return flattenTypedPipeline(\n profile === 'lightweight' ? IMPL_ORDER_LIGHTWEIGHT : IMPL_ORDER_STANDARD,\n )\n}\n","/**\n * @fileType configuration\n * @domain ci | kody | agent-execution\n * @pattern constants\n * @ai-summary Agent runner constants — timeouts, retry limits, buffer sizes\n */\n\nimport ms from 'ms'\n\n/** Delay between stability checks after process exit (milliseconds) */\nexport const STABILITY_CHECK_INTERVAL = 500\n\n/** Number of consecutive stable size checks before settling */\nexport const STABILITY_CHECK_COUNT = 2\n\n/** Additional delay to wait after process exit before checking (filesystem flush) */\nexport const POST_EXIT_DELAY = 500\n\n/** Timeout for session nudge attempt (seconds) — lightweight continuation before full retry */\nexport const NUDGE_TIMEOUT = 90\n\n/** Maximum retry attempts for failed stages */\nexport const MAX_RETRIES = 2\n\n/** Maximum size of stdout buffer to prevent memory leaks (1 MB) */\nexport const MAX_STDOUT_BUFFER_SIZE = 1_048_576\n\n/** Default timeout for stages (10 minutes) */\nexport const DEFAULT_TIMEOUT = ms('10m')\n\n/** LLM-specific timeout - max time to wait for LLM API response (3 minutes) */\nexport const LLM_TIMEOUT = ms('3m')\n\n/** Stall detection: if no stdout events for this many ms, kill and retry the agent.\n * Prevents wasting the full stage timeout when the LLM API hangs silently. */\nexport const STALL_TIMEOUT = ms('5m')\n","/**\n * @fileType utility\n * @domain ci | kody | agent-execution\n * @pattern file-watcher\n * @ai-summary File watching and stability checking for agent output detection\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport ms from 'ms'\n\nimport { STABILITY_CHECK_INTERVAL, STABILITY_CHECK_COUNT } from './constants'\n\n/**\n * Wait for a file to become stable (size doesn't change for N consecutive checks).\n * This handles filesystem flush delays after the agent process exits.\n *\n * @param filePath - Path to the file to check\n * @param options - Stability check configuration\n * @returns Promise that resolves when file is stable, or rejects on timeout/error\n */\nexport async function waitForFileStable(\n filePath: string,\n options: {\n interval?: number\n stableCount?: number\n timeout?: number\n onCheck?: (size: number, checkNumber: number) => void\n } = {},\n): Promise<{ stable: boolean; finalSize: number }> {\n const {\n interval = STABILITY_CHECK_INTERVAL,\n stableCount = STABILITY_CHECK_COUNT,\n timeout = ms('30s'),\n onCheck,\n } = options\n\n const startTime = Date.now()\n let lastSize = 0\n let stableCheckCount = 0\n\n while (true) {\n // Check timeout\n if (Date.now() - startTime > timeout) {\n return { stable: false, finalSize: lastSize }\n }\n\n // Check if file exists\n if (!fs.existsSync(filePath)) {\n stableCheckCount = 0\n lastSize = 0\n await sleep(interval)\n continue\n }\n\n // Get current file size\n const stat = fs.statSync(filePath)\n const currentSize = stat.size\n\n if (onCheck) {\n onCheck(currentSize, stableCheckCount)\n }\n\n // Check if size is stable (skip first check - we need 2 consecutive stable checks)\n if (currentSize > 0 && currentSize === lastSize) {\n stableCheckCount++\n if (stableCheckCount >= stableCount) {\n return { stable: true, finalSize: currentSize }\n }\n } else {\n stableCheckCount = 0\n }\n\n lastSize = currentSize\n await sleep(interval)\n }\n}\n\n/**\n * Simple sleep utility\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n/**\n * Find output file in directory (supports timestamped variants like spec-123456.md)\n */\nexport function findOutputFile(\n taskDir: string,\n expectedBase: string,\n outputExt: string,\n): string | null {\n if (fs.existsSync(path.join(taskDir, expectedBase + outputExt))) {\n return path.join(taskDir, expectedBase + outputExt)\n }\n\n // Check for timestamped variants\n const files = fs.readdirSync(taskDir)\n const prefixMatch = files.find((f) => f.startsWith(expectedBase + '-') && f.endsWith(outputExt))\n return prefixMatch ? path.join(taskDir, prefixMatch) : null\n}\n","/**\n * @fileType utility\n * @domain ci | kody | agent-execution\n * @pattern log-parser\n * @ai-summary Parses JSON event lines from opencode into human-readable log output\n */\n\n/**\n * Format a JSON event line from opencode into a human-readable log line.\n * Returns the formatted string, or null to skip (for noisy/unimportant events).\n * Also extracts sessionID from events when found.\n */\nexport function formatJsonEvent(line: string): {\n display: string | null\n sessionId?: string\n stepTokens?: { input: number; output: number; cacheRead: number }\n stepCost?: number\n completed?: boolean\n} {\n try {\n const event = JSON.parse(line)\n const type: string = event.type\n const sessionId: string | undefined = event.sessionID\n\n switch (type) {\n case 'session_start':\n return { display: `🎯 Session started: ${sessionId?.slice(0, 16) || 'unknown'}`, sessionId }\n\n case 'step_start':\n return { display: null, sessionId } // Quiet — step_finish is more useful\n\n case 'step_finish': {\n const tokens = event.part?.tokens?.total || 0\n const cost = event.part?.cost ?? 0\n const reason = event.part?.reason || ''\n const cached = event.part?.tokens?.cache?.read || 0\n const inputTokens = event.part?.tokens?.input || 0\n const outputTokens = event.part?.tokens?.output || 0\n const costStr = typeof cost === 'number' && cost > 0 ? ` · $${cost.toFixed(4)}` : ''\n const cacheStr = cached > 0 ? ` · ${cached} cached` : ''\n const isCompletion = reason === 'stop'\n return {\n display: ` ✅ Step done (${tokens} tok${cacheStr}${costStr}) [${reason}]`,\n sessionId,\n stepTokens: { input: inputTokens, output: outputTokens, cacheRead: cached },\n stepCost: typeof cost === 'number' ? cost : 0,\n completed: isCompletion,\n }\n }\n\n case 'tool_use': {\n const tool = event.part?.tool || 'unknown'\n const status = event.part?.state?.status || ''\n const title = event.part?.state?.title || event.part?.state?.input?.description || ''\n const exit = event.part?.state?.metadata?.exit\n const exitStr = exit !== undefined && exit !== 0 ? ` exit=${exit}` : ''\n const titleStr = title ? `: ${title}` : ''\n if (status === 'completed') {\n return { display: ` 🔧 ${tool}${titleStr}${exitStr}`, sessionId }\n }\n return { display: null, sessionId } // Skip pending/running states\n }\n\n case 'text': {\n // Agent reasoning — complete thought blocks (not char-by-char deltas)\n // Typically 6-17 per stage, ~100-200 chars each — not noisy\n const text = (event.part?.text || '').trim()\n if (!text) return { display: null, sessionId }\n const truncated = text.length > 300 ? text.slice(0, 297) + '...' : text\n return { display: ` 💭 ${truncated}`, sessionId }\n }\n\n case 'text_delta':\n case 'content':\n return { display: null, sessionId } // Skip streaming text deltas (too noisy)\n\n case 'error': {\n const msg = event.part?.message || event.message || JSON.stringify(event.part)\n return { display: ` 🔴 Error: ${msg}`, sessionId }\n }\n\n default:\n return { display: null, sessionId } // Skip unknown event types\n }\n } catch {\n // Not valid JSON — might be a plain log line from pino/logger\n // Show it as-is if it looks meaningful\n const trimmed = line.trim()\n if (!trimmed) return { display: null }\n return { display: trimmed }\n }\n}\n\n/**\n * Format a timestamp as HH:MM:SS for log prefixing.\n */\nexport function formatTimestamp(): string {\n const now = new Date()\n return [now.getHours(), now.getMinutes(), now.getSeconds()]\n .map((n) => String(n).padStart(2, '0'))\n .join(':')\n}\n\n/**\n * Prefix a display line with [stage HH:MM:SS] for log context.\n */\nexport function prefixLogLine(stage: string, display: string): string {\n return `[${stage} ${formatTimestamp()}] ${display.trimStart()}`\n}\n","/**\n * @fileType utility\n * @domain ci | kody | agent-execution\n * @pattern session-management\n * @ai-summary Session recovery and nudge logic for agent continuation\n */\n\nimport * as path from 'path'\nimport { execFileSync } from 'child_process'\n\nimport { logger } from '../logger'\nimport type { RunnerBackend } from '../runner-backend'\nimport { resolveOpenCodeBinary } from '../opencode-server'\nimport { NUDGE_TIMEOUT, POST_EXIT_DELAY } from './constants'\nimport { findOutputFile, sleep } from './file-watcher'\n\n/**\n * Recover the latest session ID from OpenCode's database when JSON events\n * didn't include sessionID (e.g., some model providers omit it).\n * Uses `opencode session list` to query the local SQLite DB.\n */\nexport function recoverSessionId(dataDir?: string): string | undefined {\n if (!dataDir) return undefined\n\n try {\n const binary = resolveOpenCodeBinary()\n const output = execFileSync(binary, ['session', 'list', '--format', 'json', '-n', '1'], {\n encoding: 'utf-8',\n timeout: 10_000,\n env: { ...process.env, XDG_DATA_HOME: dataDir },\n })\n\n const sessions = JSON.parse(output)\n if (Array.isArray(sessions) && sessions.length > 0 && sessions[0].id) {\n logger.info(` 🔍 Recovered session ID from DB: ${sessions[0].id.slice(0, 16)}...`)\n return sessions[0].id\n }\n } catch (err) {\n logger.debug({ err }, 'Failed to recover session ID from OpenCode DB')\n }\n return undefined\n}\n\n/**\n * Nudge an agent session to write the missing output file.\n * When an agent exits 0 but forgets the output file, this sends a short\n * continuation message into the same session. Much cheaper than a full retry\n * since the agent still has all context loaded.\n *\n * Returns the detected output file path on success, or null on failure.\n */\nexport async function nudgeSession(\n backend: RunnerBackend,\n stage: string,\n outputFile: string,\n env: NodeJS.ProcessEnv,\n cwd: string,\n serverUrl: string,\n sessionId: string,\n dataDir?: string,\n): Promise<string | null> {\n const nudgePrompt = `CRITICAL: You exited without writing the required output file. Write it NOW to: ${outputFile}`\n\n logger.info(` 🔔 Nudging session ${sessionId.slice(0, 16)}... to write output file`)\n\n return new Promise((resolve) => {\n const nudgeChild = backend.spawn(stage, nudgePrompt, env, cwd, {\n serverUrl,\n sessionId,\n dataDir,\n })\n\n // Close stdin\n if (nudgeChild.stdin) nudgeChild.stdin.end()\n\n // Log nudge output for debugging\n if (nudgeChild.stdout) {\n nudgeChild.stdout.on('data', () => {\n // Silently consume — we only care about the file appearing\n })\n }\n if (nudgeChild.stderr) {\n nudgeChild.stderr.on('data', () => {\n // Silently consume\n })\n }\n\n // Timeout\n // R2-FIX #12: Use the smaller of NUDGE_TIMEOUT and remaining stage timeout.\n // Without this, a stuck nudge could cause the stage to exceed its overall timeout.\n const nudgeTimeoutMs = NUDGE_TIMEOUT * 1000\n const timer = setTimeout(() => {\n logger.info(` 🔔 Nudge timed out after ${NUDGE_TIMEOUT}s`)\n try {\n nudgeChild.kill()\n } catch {\n /* ignore */\n }\n resolve(null)\n }, nudgeTimeoutMs)\n\n nudgeChild.on('exit', async (nudgeCode) => {\n clearTimeout(timer)\n logger.info(` 🔔 Nudge process exited with code: ${nudgeCode}`)\n\n // Brief delay for filesystem flush\n await sleep(POST_EXIT_DELAY)\n\n // Check if the file appeared\n const outputExt = path.extname(outputFile)\n const expectedBase = path.basename(outputFile, outputExt)\n const taskDirForPoll = path.dirname(outputFile)\n const detected = findOutputFile(taskDirForPoll, expectedBase, outputExt)\n if (detected) {\n logger.info(` 🔔 ✅ Nudge succeeded — output file detected`)\n resolve(detected)\n } else {\n logger.info(` 🔔 ❌ Nudge failed — output file still missing`)\n resolve(null)\n }\n })\n })\n}\n","/**\n * @fileType utility\n * @domain ci | kody | agent-execution\n * @pattern agent-runner\n * @ai-summary Agent execution orchestrator — spawns agents, monitors output, handles retries.\n * File watching, session management, and log parsing are in agent/ submodules.\n */\n\nimport type { ChildProcess } from 'child_process'\nimport * as fs from 'fs'\nimport ms from 'ms'\nimport * as path from 'path'\n\nimport type { KodyInput } from './kody-utils'\nimport { buildStagePrompt } from './stage-prompts'\nimport { createRunner, type RunnerBackend } from './runner-backend'\nimport { logger } from './logger'\nimport { STDERR_TAIL_LINES } from './config/constants'\n\n// Re-export split modules for backward compatibility\nexport {\n STABILITY_CHECK_INTERVAL,\n STABILITY_CHECK_COUNT,\n POST_EXIT_DELAY,\n NUDGE_TIMEOUT,\n MAX_RETRIES,\n MAX_STDOUT_BUFFER_SIZE,\n DEFAULT_TIMEOUT,\n LLM_TIMEOUT,\n STALL_TIMEOUT,\n} from './agent/constants'\nexport { waitForFileStable } from './agent/file-watcher'\nexport { formatJsonEvent } from './agent/log-parser'\n\n// Import from split modules for internal use\nimport {\n MAX_RETRIES,\n MAX_STDOUT_BUFFER_SIZE,\n DEFAULT_TIMEOUT,\n STABILITY_CHECK_INTERVAL,\n STABILITY_CHECK_COUNT,\n POST_EXIT_DELAY,\n STALL_TIMEOUT,\n} from './agent/constants'\nimport { waitForFileStable, findOutputFile, sleep } from './agent/file-watcher'\nimport { recoverSessionId, nudgeSession } from './agent/session'\nimport { formatJsonEvent, prefixLogLine } from './agent/log-parser'\n\n// ============================================================================\n// Model Resolution\n// ============================================================================\n\n/** Cache for opencode.json model config */\nlet opencodeConfigCache: { agent?: Record<string, { model?: string }> } | null = null\n\n/**\n * Get the model name for a stage from opencode.json\n */\nfunction getStageModel(stage: string): string {\n if (!opencodeConfigCache) {\n try {\n const configPath = path.resolve(process.cwd(), 'opencode.json')\n if (fs.existsSync(configPath)) {\n opencodeConfigCache = JSON.parse(fs.readFileSync(configPath, 'utf-8'))\n }\n } catch {\n opencodeConfigCache = {}\n }\n }\n return opencodeConfigCache?.agent?.[stage]?.model ?? 'unknown'\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Result of content validation after agent produces output\n */\nexport interface ValidationResult {\n /** Whether the output is valid */\n valid: boolean\n /** Error message if validation failed (for feedback to agent on retry) */\n error?: string\n}\n\nexport interface AgentRunnerOptions {\n /** Custom stage timeouts (merges with defaults) */\n stageTimeouts?: Record<string, number>\n /** Custom default timeout */\n defaultTimeout?: number\n /** Maximum retry attempts (0 = no retries) */\n maxRetries?: number\n /** Additional environment variables */\n env?: NodeJS.ProcessEnv\n /** Working directory */\n cwd?: string\n /** Runner backend (defaults to auto-detect from GITHUB_ACTIONS env) */\n backend?: RunnerBackend\n /** Content validation function to run after output file is detected.\n * On validation failure, the output file is deleted and the agent is retried with the error in the prompt. */\n validateOutput?: (outputFile: string) => ValidationResult\n /** URL of running OpenCode server (for --attach mode) */\n serverUrl?: string\n /** Session ID to fork from (for session continuation) */\n sessionId?: string\n /** XDG_DATA_HOME directory for OpenCode server mode (must match server's data dir) */\n dataDir?: string\n /** Override agent name (for stages that use a different agent, e.g., fix stage uses build agent) */\n agentName?: string\n}\n\nexport interface AgentRunResult {\n succeeded: boolean\n timedOut: boolean\n retries: number\n /** Validation errors from failed content validation attempts */\n validationErrors?: string[]\n /** Session ID from opencode for chat history capture */\n sessionId?: string\n /** Accumulated token usage across all steps */\n tokenUsage?: { input: number; output: number; cacheRead: number }\n /** Accumulated cost in USD across all steps */\n cost?: number\n}\n\n// ============================================================================\n// Main Runner\n// ============================================================================\n\n/**\n * Run an OpenCode agent with file watching, timeouts, and optional retry logic.\n *\n * This function spawns the `opencode github run` command and monitors for the\n * output file. It handles:\n * - Wait for process exit, then check for stable output file (no continuous polling)\n * - Timeout enforcement\n * - Retry on failure (configurable)\n * - Process cleanup on completion\n * - Content validation with retry on failure\n *\n * @param input - Orchestrator input with taskId\n * @param stage - The stage to run (e.g., 'build', 'test')\n * @param outputFile - Expected output file path\n * @param timeout - Timeout in milliseconds (defaults to stage-specific or 10min)\n * @param options - Optional configuration\n * @returns Promise resolving to success/timedOut/retries\n */\nexport function runAgentWithFileWatch(\n input: KodyInput,\n stage: string,\n outputFile: string,\n timeout?: number,\n options: AgentRunnerOptions = {},\n): Promise<AgentRunResult> {\n const {\n maxRetries = MAX_RETRIES,\n env: extraEnv = {},\n cwd = process.cwd(),\n backend = createRunner(),\n validateOutput,\n serverUrl,\n sessionId,\n dataDir,\n agentName,\n } = options\n\n // Resolve timeout — stage-specific timeouts are now passed from StageDefinition\n const effectiveTimeout = timeout ?? DEFAULT_TIMEOUT\n\n // Use agentName override if provided, otherwise use stage\n const effectiveAgent = agentName ?? stage\n\n return new Promise((resolve) => {\n // Build environment for the agent\n const agentEnv = {\n ...process.env,\n ...extraEnv,\n // Skip Next.js build in pre-push hook — CI uses scripted verify (no build)\n SKIP_BUILD: '1',\n // Skip husky hooks for all pipeline stages - the pipeline runs its own quality gates\n // before committing, so pre-commit hooks would be redundant and could cause issues\n SKIP_HOOKS: '1',\n }\n\n let retries = 0\n const validationErrors: string[] = []\n let currentChild: ChildProcess | null = null\n const startTime = Date.now()\n\n const attemptWithRetry = (feedback?: string): void => {\n logger.info(` Attempt ${retries + 1}/${maxRetries + 1}`)\n\n // FIX #2: Delete stale output files before retry to prevent agent confusion\n // The agent might see old output and think work is already done\n if (retries > 0 && fs.existsSync(outputFile)) {\n fs.unlinkSync(outputFile)\n logger.info(` 🗑️ Deleted stale output file before retry`)\n }\n\n // FIX #10: Calculate remaining timeout (subtract elapsed time from ALL previous attempts).\n // startTime is captured once before the first attempt, so elapsed accurately reflects\n // total time spent across all retries including inter-retry delays.\n const elapsed = Date.now() - startTime\n const remainingTimeout = effectiveTimeout - elapsed\n if (remainingTimeout <= 0) {\n logger.info(\n ` ⏱️ No time remaining after ${retries} retries (${Math.round(elapsed / 1000)}s elapsed)`,\n )\n resolve({ succeeded: false, timedOut: true, retries, validationErrors })\n return\n }\n if (remainingTimeout < 60_000 && retries > 0) {\n logger.warn(\n ` ⚠️ Only ${Math.round(remainingTimeout / 1000)}s remaining for attempt ${retries + 1}`,\n )\n }\n\n // Build the prompt for the stage (rebuilt each attempt to include feedback)\n const prompt = buildStagePrompt(input, stage, feedback)\n\n // Log the model being used for this stage\n const model = getStageModel(stage)\n logger.info(` 🤖 Running ${stage} with model: ${model}`)\n\n // Spawn using the configured backend (local or GitHub)\n // Use effectiveAgent for the --agent flag (may be overridden via agentName option)\n currentChild = backend.spawn(effectiveAgent, prompt, agentEnv, cwd, {\n serverUrl,\n sessionId,\n dataDir,\n })\n\n // Explicitly close stdin to prevent opencode from waiting for input\n if (currentChild.stdin) {\n currentChild.stdin.end()\n }\n\n let resolved = false\n let timeoutTimer: NodeJS.Timeout | null = null\n let stallTimer: NodeJS.Timeout | null = null\n let stdoutBuffer = ''\n let extractedSessionId: string | undefined\n let hasCompleted = false // Track if we've detected completion via step_finish event\n const accumulatedTokens = { input: 0, output: 0, cacheRead: 0 }\n let accumulatedCost = 0\n // Write raw JSON events to artifact file for full debugging\n let jsonLogFd: number | null = null\n try {\n const jsonLogPath = path.join(path.dirname(outputFile), `${stage}-events.jsonl`)\n jsonLogFd = fs.openSync(jsonLogPath, 'w')\n } catch {\n // Non-fatal: skip artifact file if can't create\n }\n\n // Stderr capture for failure debugging\n let stderrLineCount = 0\n const stderrTailLines: string[] = [] // Rolling buffer of last N lines\n const STDERR_TAIL_SIZE = STDERR_TAIL_LINES\n let stderrLogFd: number | null = null\n try {\n const stderrLogPath = path.join(path.dirname(outputFile), `${stage}-stderr.log`)\n stderrLogFd = fs.openSync(stderrLogPath, 'w')\n } catch {\n // Non-fatal: skip stderr file if can't create\n }\n\n // Register cleanup handler to prevent FD leak on unexpected exit\n const cleanupFd = () => {\n if (jsonLogFd !== null) {\n try {\n fs.closeSync(jsonLogFd)\n } catch {\n /* ignore */\n }\n jsonLogFd = null\n }\n if (stderrLogFd !== null) {\n try {\n fs.closeSync(stderrLogFd)\n } catch {\n /* ignore */\n }\n stderrLogFd = null\n }\n }\n process.on('exit', cleanupFd)\n\n // Handle stdout - parse JSON events and display formatted output\n if (currentChild.stdout) {\n currentChild.stdout.on('data', (data: Buffer) => {\n const chunk = data.toString()\n stdoutBuffer += chunk\n\n // Reset stall timer on any stdout activity\n resetStallTimer()\n\n // Process line by line (JSON events are one per line)\n const lines = stdoutBuffer.split('\\n')\n stdoutBuffer = lines.pop() || '' // Keep incomplete line in buffer\n\n for (const line of lines) {\n if (!line.trim()) continue\n\n // Write raw JSON to artifact file for debugging\n if (jsonLogFd !== null) {\n fs.writeSync(jsonLogFd, line + '\\n')\n }\n\n // Parse and format for human-readable output\n const result = formatJsonEvent(line)\n\n // Extract sessionId from first event that has it\n if (result.sessionId && !extractedSessionId) {\n extractedSessionId = result.sessionId\n }\n\n // Accumulate token/cost data from step_finish events\n if (result.stepTokens) {\n accumulatedTokens.input += result.stepTokens.input\n accumulatedTokens.output += result.stepTokens.output\n accumulatedTokens.cacheRead += result.stepTokens.cacheRead\n }\n if (result.stepCost) {\n accumulatedCost += result.stepCost\n }\n\n // Display formatted output\n if (result.display) {\n process.stderr.write(prefixLogLine(stage, result.display) + '\\n')\n }\n\n // R2-FIX #13: Detect completion via step_finish event.\n // This fixes the hang in fork mode where process never exits.\n // When we detect completion, call finish() to trigger file detection,\n // nudge logic, and retry - all the fallback logic that normally runs\n // in the exit handler.\n if (result.completed && !hasCompleted && !resolved) {\n hasCompleted = true\n logger.info(` 🎯 Agent signaled completion via event, triggering finish...`)\n // Call finish with succeeded=true - it handles all the fallback logic\n finish({ succeeded: true, timedOut: false })\n }\n }\n\n // FIX #5: Cap buffer size to prevent memory leaks on verbose agents.\n // When the buffer exceeds MAX, discard the oldest data and keep the most\n // recent MAX/2 bytes, breaking at a newline boundary for clean parsing.\n if (stdoutBuffer.length > MAX_STDOUT_BUFFER_SIZE) {\n const keepFrom = stdoutBuffer.length - MAX_STDOUT_BUFFER_SIZE / 2\n const nextNewline = stdoutBuffer.indexOf('\\n', keepFrom)\n stdoutBuffer =\n nextNewline > 0 ? stdoutBuffer.slice(nextNewline + 1) : stdoutBuffer.slice(keepFrom)\n }\n })\n }\n\n // Handle stderr - write to file, surface on failure\n if (currentChild.stderr) {\n let stderrBuffer = ''\n currentChild.stderr.on('data', (data: Buffer) => {\n const chunk = data.toString()\n stderrBuffer += chunk\n\n const lines = stderrBuffer.split('\\n')\n stderrBuffer = lines.pop() || ''\n\n for (const line of lines) {\n if (!line.trim()) continue\n stderrLineCount++\n\n // Write to file\n if (stderrLogFd !== null) {\n try {\n fs.writeSync(stderrLogFd, line + '\\n')\n } catch {\n /* ignore */\n }\n }\n\n // Keep rolling tail buffer\n stderrTailLines.push(line)\n if (stderrTailLines.length > STDERR_TAIL_SIZE) {\n stderrTailLines.shift()\n }\n }\n })\n }\n\n const finish = (result: { succeeded: boolean; timedOut: boolean }) => {\n if (resolved) return\n resolved = true\n\n if (timeoutTimer) clearTimeout(timeoutTimer)\n if (stallTimer) clearTimeout(stallTimer)\n\n // Flush remaining stdout buffer\n if (stdoutBuffer.trim()) {\n if (jsonLogFd !== null) {\n fs.writeSync(jsonLogFd, stdoutBuffer + '\\n')\n }\n const lastResult = formatJsonEvent(stdoutBuffer)\n if (lastResult.sessionId && !extractedSessionId) {\n extractedSessionId = lastResult.sessionId\n }\n if (lastResult.display) {\n process.stderr.write(prefixLogLine(stage, lastResult.display) + '\\n')\n }\n }\n\n // Kill process if still running\n if (currentChild && !currentChild.killed) {\n currentChild.kill('SIGTERM')\n setTimeout(() => {\n if (currentChild && !currentChild.killed) currentChild.kill('SIGKILL')\n }, ms('5s'))\n }\n\n // Close JSON log file descriptor\n if (jsonLogFd !== null) {\n try {\n fs.closeSync(jsonLogFd)\n } catch {\n /* ignore */\n }\n jsonLogFd = null\n }\n // Close stderr log file descriptor\n if (stderrLogFd !== null) {\n try {\n fs.closeSync(stderrLogFd)\n } catch {\n /* ignore */\n }\n stderrLogFd = null\n }\n // Remove exit cleanup handler (FD already closed)\n process.removeListener('exit', cleanupFd)\n const tokenUsage =\n accumulatedTokens.input > 0 || accumulatedTokens.output > 0\n ? accumulatedTokens\n : undefined\n const cost = accumulatedCost > 0 ? accumulatedCost : undefined\n resolve({\n ...result,\n retries,\n validationErrors,\n sessionId: extractedSessionId,\n tokenUsage,\n cost,\n })\n }\n\n // Parse output file path\n const outputExt = path.extname(outputFile)\n const expectedBase = path.basename(outputFile, outputExt)\n const taskDirForPoll = path.dirname(outputFile)\n\n // Timeout (uses remaining time to prevent accumulation across retries)\n timeoutTimer = setTimeout(() => {\n logger.info(` ⏱️ Timeout reached (${remainingTimeout / 1000 / 60} minutes)`)\n finish({ succeeded: false, timedOut: true })\n }, remainingTimeout)\n\n // Stall detection: if no stdout events for STALL_TIMEOUT, the LLM is likely\n // hung (API stall, infinite generation). Kill early and retry instead of\n // wasting the full stage timeout sitting idle.\n const resetStallTimer = () => {\n if (stallTimer) clearTimeout(stallTimer)\n const stallLimit = Math.min(STALL_TIMEOUT, remainingTimeout)\n stallTimer = setTimeout(() => {\n if (resolved) return\n logger.warn(\n ` ⚠️ Agent stalled — no output for ${STALL_TIMEOUT / 1000 / 60} minutes, killing`,\n )\n finish({ succeeded: false, timedOut: true })\n }, stallLimit)\n }\n resetStallTimer()\n\n // Process exit handler - wait for file stability after exit\n currentChild.on('exit', async (code) => {\n logger.info(` 📡 Process exited with code: ${code}`)\n\n // Surface stderr on failure\n if (code !== 0 && stderrTailLines.length > 0) {\n const isCI = !!process.env.GITHUB_ACTIONS\n if (isCI) process.stderr.write('::group::Agent stderr (last lines)\\n')\n for (const line of stderrTailLines) {\n process.stderr.write(' ' + line + '\\n')\n }\n if (isCI) process.stderr.write('::endgroup::\\n')\n } else if (stderrLineCount > 0) {\n logger.info(\n ` 📝 Agent stderr: ${stderrLineCount} lines captured (see ${stage}-stderr.log)`,\n )\n }\n\n if (resolved) return\n\n // Brief delay to allow filesystem to flush\n logger.info(` ⏳ Waiting for filesystem to flush...`)\n await sleep(POST_EXIT_DELAY)\n\n // Find the output file (exact match or timestamped variant)\n const detectedFile = findOutputFile(taskDirForPoll, expectedBase, outputExt)\n\n if (!detectedFile) {\n // Nudge: If agent exited cleanly (code 0) and we have a live session,\n // try a lightweight continuation before burning a full retry.\n // The agent still has all context — it just forgot to write the file.\n // If extractedSessionId is missing (some models don't emit sessionID in events),\n // try to recover it from the OpenCode DB before giving up on nudge.\n if (code === 0 && serverUrl && !extractedSessionId) {\n extractedSessionId = recoverSessionId(dataDir)\n }\n if (code === 0 && serverUrl && extractedSessionId) {\n // R2-FIX #12: Skip nudge if insufficient time remaining (need at least 30s)\n const nudgeElapsed = Date.now() - startTime\n const nudgeRemaining = effectiveTimeout - nudgeElapsed\n if (nudgeRemaining < 30_000) {\n logger.info(\n ` 🔔 Skipping nudge — only ${Math.round(nudgeRemaining / 1000)}s remaining`,\n )\n }\n const nudgedFile =\n nudgeRemaining >= 30_000\n ? await nudgeSession(\n backend,\n effectiveAgent,\n outputFile,\n agentEnv,\n cwd,\n serverUrl,\n extractedSessionId,\n dataDir,\n )\n : null\n if (nudgedFile) {\n // Nudge succeeded — continue to file stability check\n // Re-assign detectedFile by jumping to the stability check below\n const { stable, finalSize } = await waitForFileStable(nudgedFile, {\n interval: STABILITY_CHECK_INTERVAL,\n stableCount: STABILITY_CHECK_COUNT,\n timeout: Math.min(ms('30s'), remainingTimeout),\n onCheck: (size, checkNum) => {\n if (checkNum === 0) {\n logger.info(` 🔍 File size: ${size} bytes, waiting for stability...`)\n }\n },\n })\n if (stable && finalSize > 0) {\n logger.info(` ✅ Output file stable (${finalSize} bytes) after nudge`)\n finish({ succeeded: true, timedOut: false })\n return\n }\n // Nudge produced file but it's not stable — fall through to retry\n logger.info(` ⚠️ Nudge produced file but it's not stable, falling through to retry`)\n }\n }\n\n // File not found (or nudge failed) - retry or fail\n if (retries < maxRetries) {\n retries++\n const reason = code === 0 ? 'no output file' : `exit ${code}`\n const feedbackMsg =\n code === 0\n ? `CRITICAL FAILURE: You exited with code 0 but did NOT produce the required output file. You MUST write the output file before exiting. Check that your tool calls are actually writing to the correct path.`\n : `CRITICAL FAILURE: You exited with code ${code}. Fix the error and ensure you write the output file before exiting.`\n\n // Debug: List files in task directory on failure\n try {\n const files = fs.readdirSync(taskDirForPoll)\n logger.info(\n ` 🔍 Debug: Files in ${path.basename(taskDirForPoll)}: ${files.join(', ')}`,\n )\n } catch {\n // Ignore errors\n }\n\n logger.info(` ⚠️ Stage failed (${reason}), retrying (${retries}/${maxRetries})...`)\n setTimeout(() => {\n try {\n attemptWithRetry(feedbackMsg)\n } catch (err) {\n logger.error(` ❌ attemptWithRetry threw: ${err}`)\n finish({ succeeded: false, timedOut: false })\n }\n }, ms('2s'))\n return\n } else {\n // Exhausted retries\n try {\n const files = fs.readdirSync(taskDirForPoll)\n logger.info(\n ` 🔍 Debug: Files in ${path.basename(taskDirForPoll)}: ${files.join(', ')}`,\n )\n } catch {\n // Ignore errors\n }\n logger.info(` ❌ Agent exited ${code} without producing output file`)\n finish({ succeeded: false, timedOut: false })\n return\n }\n }\n\n // File found - wait for it to stabilize\n logger.info(\n ` 📄 Output file detected: ${path.basename(detectedFile)}, checking stability...`,\n )\n\n try {\n const { stable, finalSize } = await waitForFileStable(detectedFile, {\n interval: STABILITY_CHECK_INTERVAL,\n stableCount: STABILITY_CHECK_COUNT,\n timeout: remainingTimeout,\n onCheck: (size, checkNum) => {\n if (checkNum === 0) {\n logger.info(` 🔍 File size: ${size} bytes, waiting for stability...`)\n }\n },\n })\n\n if (!stable) {\n logger.info(` ⚠️ File did not stabilize within timeout`)\n if (retries < maxRetries) {\n retries++\n const feedbackMsg = `CRITICAL FAILURE: Output file was not fully written. The file size changed during stability check. Please ensure you write the complete file before exiting.`\n logger.info(` ⚠️ Retrying with feedback (${retries}/${maxRetries})...`)\n setTimeout(() => {\n try {\n attemptWithRetry(feedbackMsg)\n } catch (err) {\n logger.error(` ❌ attemptWithRetry threw: ${err}`)\n finish({ succeeded: false, timedOut: false })\n }\n }, ms('2s'))\n return\n } else {\n logger.info(` ❌ File stability check failed, retries exhausted`)\n finish({ succeeded: false, timedOut: false })\n return\n }\n }\n\n logger.info(` ✅ File stable (${finalSize} bytes)`)\n\n // Rename if timestamped variant\n if (detectedFile !== outputFile) {\n logger.info(\n ` 📄 Renaming: ${path.basename(detectedFile)} → ${path.basename(outputFile)}`,\n )\n fs.renameSync(detectedFile, outputFile)\n }\n\n // VALIDATION: Check content if validator provided\n if (validateOutput) {\n const validationResult = validateOutput(outputFile)\n if (!validationResult.valid) {\n const errorMsg = validationResult.error || 'Content validation failed'\n logger.info(` ⚠️ Validation failed: ${errorMsg}`)\n\n // Delete the invalid output file\n try {\n fs.unlinkSync(outputFile)\n logger.info(` 🗑️ Deleted invalid output file`)\n } catch {\n // File might not exist, continue\n }\n\n // Store validation error for feedback\n validationErrors.push(errorMsg)\n\n // Retry with feedback if we have retries left\n if (retries < maxRetries) {\n retries++\n const feedbackMsg = `VALIDATION ERROR from previous attempt:\\n${errorMsg}\\n\\nFix this issue in your output. Ensure your output follows the exact required format.`\n logger.info(` 🔄 Retrying with validation feedback (${retries}/${maxRetries})...`)\n setTimeout(() => {\n try {\n attemptWithRetry(feedbackMsg)\n } catch (err) {\n logger.error(` ❌ attemptWithRetry threw: ${err}`)\n finish({ succeeded: false, timedOut: false })\n }\n }, ms('2s'))\n return\n } else {\n logger.info(` ❌ Validation failed and retries exhausted`)\n finish({ succeeded: false, timedOut: false })\n return\n }\n }\n }\n\n // Success!\n logger.info(` ✅ Stage completed successfully`)\n finish({ succeeded: true, timedOut: false })\n } catch (error) {\n logger.info(` ❌ Error waiting for file stability: ${error}`)\n finish({ succeeded: false, timedOut: false })\n }\n })\n\n // Handle spawn errors (e.g., command not found)\n currentChild.on('error', (err) => {\n if (resolved) return\n const error = err as NodeJS.ErrnoException\n if (error.code === 'ENOENT') {\n logger.error(` ❌ Command not found: ${error.path || 'opencode'}. Is it installed?`)\n logger.error(' Install with: npm install -g opencode')\n } else {\n logger.error(` ❌ Agent process error: ${err.message}`)\n }\n finish({ succeeded: false, timedOut: false })\n })\n }\n\n // Start first attempt (no feedback)\n try {\n attemptWithRetry(undefined)\n } catch (err) {\n logger.error(` ❌ attemptWithRetry initial call threw: ${err}`)\n resolve({ succeeded: false, timedOut: false, retries: 0, validationErrors: [] })\n }\n })\n}\n\n/**\n * Simple agent runner without retries (for use with external retry logic)\n */\nexport function runAgentOnce(\n input: KodyInput,\n stage: string,\n outputFile: string,\n timeout?: number,\n options: Omit<AgentRunnerOptions, 'maxRetries'> = {},\n): Promise<AgentRunResult> {\n return runAgentWithFileWatch(input, stage, outputFile, timeout, {\n ...options,\n maxRetries: 0,\n })\n}\n","/**\n * @fileType utility\n * @domain kody | agent-execution\n * @pattern chat-history\n * @ai-summary Capture and manage agent conversation history from opencode sessions\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { execFileSync } from 'child_process'\n\nimport { logger } from './logger'\nimport { resolveOpenCodeBinary } from './opencode-server'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ChatMessage {\n role: 'user' | 'assistant'\n stage: string\n text: string\n tools: string[]\n timestamp: string\n model?: string\n}\n\nexport interface ChatSession {\n stage: string\n sessionId: string\n startedAt: string\n messages: ChatMessage[]\n}\n\nexport interface ChatHistory {\n version: 1\n taskId: string\n sessions: ChatSession[]\n}\n\n// ============================================================================\n// Helper: Trim raw opencode export to compact chat session\n// ============================================================================\n\n/**\n * Trim a raw opencode session export to a compact ChatSession structure.\n * Extracts role, text content, tool names, and timestamps.\n * Drops tool arguments/outputs and internal metadata for compactness.\n */\nfunction trimSession(\n rawExport: {\n info?: { id?: string; time?: { created?: number } }\n messages?: Array<{\n info?: { role?: string; time?: { created?: number }; model?: string }\n parts?: Array<{\n type?: string\n text?: string\n tool?: string\n }>\n }>\n },\n stage: string,\n): ChatSession | null {\n try {\n const info = rawExport.info || {}\n const messages = rawExport.messages || []\n\n const sessionId = info.id || 'unknown'\n const startedAt = info.time?.created\n ? new Date(info.time.created).toISOString()\n : new Date().toISOString()\n\n const trimmedMessages: ChatMessage[] = []\n\n for (const msg of messages) {\n const msgInfo = msg.info || {}\n // Cast role - opencode may return other values but we only handle user/assistant\n const role: 'user' | 'assistant' = msgInfo.role === 'assistant' ? 'assistant' : 'user'\n\n // Extract text from parts\n let text = ''\n const tools: string[] = []\n\n for (const part of msg.parts || []) {\n if (part.type === 'text' && part.text) {\n text += part.text\n }\n if (part.type === 'tool' && part.tool) {\n tools.push(part.tool)\n }\n }\n\n // Skip messages with no content\n if (!text && tools.length === 0) continue\n\n trimmedMessages.push({\n role,\n stage,\n text: text.trim(),\n tools,\n timestamp: msgInfo.time?.created\n ? new Date(msgInfo.time.created).toISOString()\n : new Date().toISOString(),\n model: msgInfo.model ? JSON.stringify(msgInfo.model) : undefined,\n })\n }\n\n return {\n stage,\n sessionId,\n startedAt,\n messages: trimmedMessages,\n }\n } catch (err) {\n logger.warn({ err }, `Failed to trim session for stage ${stage}`)\n return null\n }\n}\n\n// ============================================================================\n// Helper: Extract JSON object from potentially noisy CLI output\n// ============================================================================\n\n/**\n * Extract a JSON object from CLI output that may contain non-JSON lines\n * (e.g., progress messages, \"Exporting session:\" prefix, warnings).\n * Finds the first '{' and last '}' and parses the substring between them.\n */\nexport function extractJson(output: string): unknown {\n const firstBrace = output.indexOf('{')\n const lastBrace = output.lastIndexOf('}')\n\n if (firstBrace === -1 || lastBrace === -1 || lastBrace <= firstBrace) {\n throw new SyntaxError(\n `No JSON object found in output (length=${output.length}, first 200 chars: ${output.slice(0, 200)})`,\n )\n }\n\n const jsonStr = output.slice(firstBrace, lastBrace + 1)\n return JSON.parse(jsonStr)\n}\n\n// ============================================================================\n// Helper: Load existing chat history\n// ============================================================================\n\nexport function loadChatHistory(taskDir: string): ChatHistory | null {\n const chatPath = path.join(taskDir, 'chat.json')\n if (!fs.existsSync(chatPath)) {\n return null\n }\n try {\n const data = fs.readFileSync(chatPath, 'utf-8')\n return JSON.parse(data) as ChatHistory\n } catch (err) {\n logger.warn({ err, chatPath }, 'Failed to load chat history, starting fresh')\n return null\n }\n}\n\n// ============================================================================\n// Helper: Save chat history\n// ============================================================================\n\nfunction saveChatHistory(taskDir: string, history: ChatHistory): void {\n const chatPath = path.join(taskDir, 'chat.json')\n fs.writeFileSync(chatPath, JSON.stringify(history, null, 2), 'utf-8')\n}\n\n// ============================================================================\n// Main: Append a session to the task's chat history\n// ============================================================================\n\n/**\n * Export an opencode session and append its trimmed content to the task's chat.json.\n * This is called after a successful agent stage completes.\n *\n * @param taskDir - The .tasks/<taskId> directory\n * @param stage - The stage name (e.g., 'spec', 'build')\n * @param sessionId - The opencode session ID to export\n */\nexport async function appendSession(\n taskDir: string,\n stage: string,\n sessionId: string,\n serverUrl?: string,\n): Promise<void> {\n if (!sessionId) {\n logger.debug('No sessionId, skipping chat export')\n return\n }\n\n logger.info(` 📝 Exporting chat session ${sessionId} for stage ${stage}...`)\n\n try {\n // Export session as JSON from the OpenCode SQLite DB.\n // `opencode export` reads directly from the DB — it does NOT support --attach.\n // When serverUrl is set, the DB lives in the task-specific data dir, so we use\n // the real binary + XDG_DATA_HOME. Without server mode, use pnpm exec (old binary).\n let output: string\n if (serverUrl) {\n const args = ['export', sessionId]\n const dataDir = path.join(taskDir, 'opencode-data')\n output = execFileSync(resolveOpenCodeBinary(), args, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n cwd: process.cwd(),\n maxBuffer: 50 * 1024 * 1024,\n env: { ...process.env, XDG_DATA_HOME: dataDir },\n })\n } else {\n const args = ['exec', 'opencode', 'export', sessionId]\n output = execFileSync('pnpm', args, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n cwd: process.cwd(),\n maxBuffer: 50 * 1024 * 1024,\n })\n }\n\n // Extract JSON from potentially noisy CLI output (may contain\n // \"Exporting session:\" prefix, progress messages, or other non-JSON lines)\n const rawExport = extractJson(output) as Parameters<typeof trimSession>[0]\n\n // Trim to compact format\n const session = trimSession(rawExport, stage)\n if (!session) {\n logger.warn(`Failed to trim session ${sessionId}`)\n return\n }\n\n // Load or create chat history\n let history = loadChatHistory(taskDir)\n if (!history) {\n // Extract taskId from taskDir path\n const taskId = path.basename(taskDir)\n history = {\n version: 1,\n taskId,\n sessions: [],\n }\n }\n\n // Append the new session\n history.sessions.push(session)\n\n // R2-FIX #8: Cap sessions to prevent unbounded growth during retry loops.\n // Keep last 30 sessions — enough for full pipeline + several verify→fix loops.\n const MAX_CHAT_SESSIONS = 30\n if (history.sessions.length > MAX_CHAT_SESSIONS) {\n history.sessions = history.sessions.slice(-MAX_CHAT_SESSIONS)\n logger.info(` ℹ️ Chat history trimmed to last ${MAX_CHAT_SESSIONS} sessions`)\n }\n\n // Save\n saveChatHistory(taskDir, history)\n\n // Count total tools used across all messages\n const totalTools = session.messages.reduce((acc, m) => acc + m.tools.length, 0)\n\n logger.info(\n ` ✅ Saved chat for ${stage}: ${session.messages.length} messages, ${totalTools} tools used`,\n )\n } catch (err) {\n // Non-fatal — log and continue\n logger.warn({ err, sessionId, stage }, 'Failed to export/append chat session')\n }\n}\n\n// ============================================================================\n// Utility: Get chat history for a task (for debugging/loading)\n// ============================================================================\n\nexport function getChatHistoryForTask(taskId: string): ChatHistory | null {\n const taskDir = path.join(process.cwd(), '.tasks', taskId)\n return loadChatHistory(taskDir)\n}\n","/**\n * @fileType handler\n * @domain kody | handlers\n * @pattern agent-handler\n * @ai-summary Agent stage handler that runs LLM agents\n */\n\nimport { logger } from '../logger'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext, StageDefinition, StageResult } from '../engine/types'\nimport { runAgentWithFileWatch } from '../agent-runner'\nimport { stageOutputFile } from '../stages/registry'\nimport { appendSession } from '../chat-history'\nimport type { StageHandler } from './handler'\n\n/**\n * Agent handler - runs LLM agents via opencode\n */\nexport class AgentHandler implements StageHandler {\n async execute(ctx: PipelineContext, def: StageDefinition): Promise<StageResult> {\n // Use stageOutputFile to get the correct output file (respects STAGE_OUTPUT_MAP)\n const outputFile = stageOutputFile(ctx.taskDir, def.name)\n\n // Run agent — pass def.name as stage for prompt/model, but use agentName for the agent execution\n if (def.agentName && def.agentName !== def.name) {\n logger.info(` ⚙️ Stage \"${def.name}\" using agent: ${def.agentName}`)\n }\n const result = await runAgentWithFileWatch(ctx.input, def.name, outputFile, def.timeout, {\n backend: ctx.backend,\n validateOutput: def.validator,\n maxRetries: def.maxRetries,\n serverUrl: ctx.serverUrl,\n sessionId: ctx.lastSessionId,\n // XDG_DATA_HOME must match the server's data dir for instance lookup\n dataDir: ctx.serverUrl ? path.join(ctx.taskDir, 'opencode-data') : undefined,\n // Pass agentName override if different from stage name (e.g., fix stage uses build agent)\n agentName: def.agentName && def.agentName !== def.name ? def.agentName : undefined,\n })\n\n // Map result to StageResult\n if (result.timedOut) {\n return {\n outcome: 'timed_out',\n retries: result.retries,\n }\n }\n\n if (!result.succeeded) {\n // Try fallback: if agent exited 0 but didn't write output file, create one\n if (def.fallbackOnMissingOutput && !fs.existsSync(outputFile)) {\n const fallbackContent = def.fallbackOnMissingOutput(ctx)\n if (fallbackContent) {\n fs.writeFileSync(outputFile, fallbackContent)\n logger.info(` ℹ️ Created fallback output: ${def.name}.md`)\n return {\n outcome: 'completed',\n retries: result.retries,\n outputFile: `${def.name}.md`,\n tokenUsage: result.tokenUsage,\n cost: result.cost,\n sessionId: result.sessionId,\n }\n }\n }\n\n const details: string[] = [`Agent \"${def.agentName ?? def.name}\" failed`]\n if (result.validationErrors?.length) {\n details.push(`Validation errors: ${result.validationErrors.join('; ')}`)\n }\n details.push(`Artifacts: ${def.name}-stderr.log, ${def.name}-events.jsonl`)\n return {\n outcome: 'failed',\n reason: details.join('. '),\n retries: result.retries,\n tokenUsage: result.tokenUsage,\n cost: result.cost,\n }\n }\n\n // Success - try to save chat history\n if (result.sessionId) {\n try {\n await appendSession(ctx.taskDir, def.name, result.sessionId, ctx.serverUrl)\n } catch (err) {\n // Non-fatal — don't fail the stage if chat export fails\n logger.warn({ err, stage: def.name }, 'Failed to save chat history')\n }\n\n // Propagate sessionId for downstream stage forking\n ctx.lastSessionId = result.sessionId\n }\n\n return {\n outcome: 'completed',\n retries: result.retries,\n outputFile: `${def.name}.md`,\n tokenUsage: result.tokenUsage,\n cost: result.cost,\n sessionId: result.sessionId,\n }\n }\n}\n","/**\n * @fileType configuration\n * @domain kody | pipeline\n * @pattern project-config\n * @ai-summary Configurable project settings — replaces hardcoded quality commands\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nexport interface QualityCommands {\n typecheck: string\n lint: string\n lintFix: string\n format: string\n formatFix: string\n testUnit: string\n testE2e?: string\n}\n\nexport interface GitConfig {\n defaultBranch: string\n userEmail?: string\n userName?: string\n}\n\nexport interface GitHubConfig {\n owner: string\n repo: string\n appId?: number\n}\n\nexport interface AgentConfig {\n /** Project-specific instruction files to inject into agent prompts */\n instructions: string[]\n /** Domain agent → territory glob mapping */\n domainMap: Record<string, string[]>\n}\n\nexport interface KodyProjectConfig {\n quality: QualityCommands\n git: GitConfig\n github: GitHubConfig\n agents: AgentConfig\n paths: {\n taskDir: string\n }\n}\n\nconst DEFAULT_CONFIG: KodyProjectConfig = {\n quality: {\n typecheck: 'pnpm -s tsc --noEmit',\n lint: 'pnpm -s lint',\n lintFix: 'pnpm lint:fix',\n format: 'pnpm -s format:check',\n formatFix: 'pnpm format:fix',\n testUnit: 'pnpm -s test:unit',\n },\n git: {\n defaultBranch: 'dev',\n },\n github: {\n owner: '',\n repo: '',\n },\n agents: {\n instructions: [],\n domainMap: {},\n },\n paths: {\n taskDir: '.tasks',\n },\n}\n\nlet _config: KodyProjectConfig | null = null\n\n/**\n * Load project config from kody.config.json in the project root.\n * Falls back to defaults if no config file exists.\n */\nexport function loadProjectConfig(projectRoot: string = process.cwd()): KodyProjectConfig {\n if (_config) return _config\n\n const configPath = path.join(projectRoot, 'kody.config.json')\n\n if (fs.existsSync(configPath)) {\n try {\n const raw = JSON.parse(fs.readFileSync(configPath, 'utf-8'))\n _config = {\n quality: { ...DEFAULT_CONFIG.quality, ...raw.quality },\n git: { ...DEFAULT_CONFIG.git, ...raw.git },\n github: { ...DEFAULT_CONFIG.github, ...raw.github },\n agents: {\n instructions: raw.agents?.instructions ?? DEFAULT_CONFIG.agents.instructions,\n domainMap: raw.agents?.domainMap ?? DEFAULT_CONFIG.agents.domainMap,\n },\n paths: { ...DEFAULT_CONFIG.paths, ...raw.paths },\n }\n } catch {\n _config = DEFAULT_CONFIG\n }\n } else {\n _config = DEFAULT_CONFIG\n }\n\n return _config\n}\n\n/**\n * Get the current project config (must call loadProjectConfig first).\n */\nexport function getProjectConfig(): KodyProjectConfig {\n if (!_config) return loadProjectConfig()\n return _config\n}\n\n/**\n * Reset config cache (for testing).\n */\nexport function resetProjectConfig(): void {\n _config = null\n}\n","/**\n * @fileType utility\n * @domain ci | kody | pipeline\n * @pattern scripted-stages\n * @ai-summary Direct script execution for verify and PR stages — no LLM needed for mechanical tasks\n */\n\nimport { logger } from './logger'\nimport { execFileSync } from 'child_process'\nimport * as fs from 'fs'\nimport ms from 'ms'\nimport * as path from 'path'\nimport { getDefaultBranch, commitAndPush } from './git-utils'\nimport { postComment, setLifecycleLabel } from './github-api'\nimport { getProjectConfig } from './config/project-config'\n\n// ============================================================================\n// Verify Stage — run quality gates directly\n// ============================================================================\n\ninterface VerifyResult {\n passed: boolean\n report: string\n}\n\ninterface GateResult {\n name: string\n passed: boolean\n output: string\n}\n\n/** Default timeout per gate (2 minutes) */\nconst DEFAULT_GATE_TIMEOUT = ms('2m')\n\nfunction runGate(\n name: string,\n program: string,\n args: string[],\n cwd: string,\n timeout: number = DEFAULT_GATE_TIMEOUT,\n): GateResult {\n logger.info(` Running ${name}...`)\n try {\n const output = execFileSync(program, args, { cwd, encoding: 'utf-8', timeout })\n logger.info(` ✅ ${name} passed`)\n return { name, passed: true, output: output.slice(0, 1000) }\n } catch (error: unknown) {\n const err = error as { stdout?: string; stderr?: string; message?: string }\n const output = (err.stdout || '') + (err.stderr || '') || err.message || 'Unknown error'\n logger.info(` ❌ ${name} failed`)\n return { name, passed: false, output: output.slice(0, 5000) }\n }\n}\n\nexport function runVerifyStage(\n outputFile: string,\n cwd: string = process.cwd(),\n timeout?: number,\n taskDir?: string,\n): VerifyResult {\n logger.info('\\n🔍 Running verification (scripted)...\\n')\n\n // Aggregate timeout - total time allowed for all gates combined\n const startTime = Date.now()\n const aggregateTimeout = timeout ?? Infinity\n\n // Quality commands from project config (configurable per-project)\n const config = getProjectConfig()\n const parseCmd = (cmd: string) => {\n const parts = cmd.split(/\\s+/)\n return { program: parts[0], args: parts.slice(1) }\n }\n const tsc = parseCmd(config.quality.typecheck)\n const lint = parseCmd(config.quality.lint)\n const fmt = parseCmd(config.quality.format)\n\n const gateDefinitions = [\n { name: 'TypeScript', program: tsc.program, args: tsc.args },\n { name: 'Lint', program: lint.program, args: lint.args },\n { name: 'Format', program: fmt.program, args: fmt.args },\n // Unit Tests gate removed — tests are deferred to inspector plugin (kody-deferred-tests)\n ]\n\n const gates: GateResult[] = []\n for (const gateDef of gateDefinitions) {\n const elapsed = Date.now() - startTime\n const remaining = aggregateTimeout - elapsed\n\n if (remaining <= 0) {\n // Aggregate timeout exceeded - skip remaining gates\n gates.push({\n name: gateDef.name,\n passed: false,\n output: 'SKIPPED: aggregate timeout exceeded',\n })\n continue\n }\n\n // Use smaller of remaining aggregate time or per-gate default\n const gateTimeout = Math.min(remaining, DEFAULT_GATE_TIMEOUT)\n gates.push(runGate(gateDef.name, gateDef.program, gateDef.args, cwd, gateTimeout))\n }\n\n const allPassed = gates.every((g) => g.passed)\n\n // Write individual gate output files for failed gates.\n // These files provide detailed error context to the fix stage agent\n // (state-machine.ts reads tsc-output.txt / lint-output.txt when building verify-failures.md).\n if (taskDir) {\n for (const gate of gates) {\n if (!gate.passed) {\n const slug = gate.name.toLowerCase().replace(/\\s+/g, '-')\n const gateOutputPath = path.join(taskDir, `${slug}-output.txt`)\n try {\n fs.writeFileSync(gateOutputPath, gate.output.slice(0, 10000))\n } catch {\n // Non-critical — gate output is supplementary context\n }\n }\n }\n }\n\n const lines: string[] = ['# Verification Report\\n']\n for (const gate of gates) {\n const icon = gate.passed\n ? 'PASS ✅'\n : gate.output.includes('SKIPPED')\n ? 'SKIPPED ❌'\n : 'FAIL ❌'\n lines.push(`## ${gate.name}: ${icon}\\n`)\n if (!gate.passed) {\n lines.push('```')\n lines.push(gate.output)\n lines.push('```\\n')\n }\n }\n\n lines.push(`\\n## Result: ${allPassed ? 'PASS' : 'FAIL'}`)\n\n const report = lines.join('\\n')\n fs.writeFileSync(outputFile, report)\n logger.info(`\\n${allPassed ? '✅' : '❌'} Verification ${allPassed ? 'passed' : 'failed'}`)\n\n return { passed: allPassed, report }\n}\n\n// ============================================================================\n// PR Stage — create PR directly via gh CLI\n// ============================================================================\n\ninterface PrResult {\n created: boolean\n url: string\n report: string\n}\n\nfunction getBranchName(cwd: string): string {\n const branch = execFileSync('git', ['branch', '--show-current'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n if (!branch) {\n // Detached HEAD — use short commit hash as fallback\n return (\n execFileSync('git', ['rev-parse', '--short', 'HEAD'], {\n cwd,\n encoding: 'utf-8',\n }).trim() || 'detached'\n )\n }\n return branch\n}\n\nfunction getExistingPr(branch: string, cwd: string): string | null {\n // BUG-F fix: Use GH_PAT if non-empty, fall back to GH_TOKEN (don't use empty string)\n const ghToken = process.env.GH_PAT?.trim() || process.env.GH_TOKEN\n try {\n const output = execFileSync(\n 'gh',\n ['pr', 'list', '--head', branch, '--json', 'url', '--jq', '.[0].url'],\n {\n cwd,\n encoding: 'utf-8',\n env: { ...process.env, GH_TOKEN: ghToken },\n },\n ).trim()\n return output || null\n } catch {\n return null\n }\n}\n\nfunction getCommitSummary(defaultBranch: string, cwd: string): string {\n try {\n // Use execFileSync to prevent shell injection via branch names\n return execFileSync('git', ['log', '--oneline', `${defaultBranch}..HEAD`], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n } catch {\n return ''\n }\n}\n\n/**\n * Create a fresh branch with incremented version suffix for --fresh flag.\n * Lists remote branches matching pattern, finds highest -vN suffix, creates -v(N+1).\n * Strips existing -vN suffix to prevent chains like branch-v2-v3.\n */\nexport function createFreshBranch(currentBranch: string, cwd: string = process.cwd()): string {\n // Strip existing -vN suffix to prevent chains (e.g., feat/260225-task-v2 -> feat/260225-task)\n const baseBranch = currentBranch.replace(/-v\\d+$/, '')\n\n // List remote branches matching the pattern\n let maxVersion = 1\n try {\n const output = execFileSync('git', ['branch', '-r', '--list', `${baseBranch}-v*`], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n\n if (output) {\n // Extract version numbers from branch names\n const versions = output.split('\\n').map((b) => {\n const match = b.trim().match(/-v(\\d+)$/)\n return match ? parseInt(match[1], 10) : 0\n })\n maxVersion = Math.max(...versions, 1)\n }\n } catch {\n // No matching branches, start at v2\n maxVersion = 1\n }\n\n const newBranch = `${baseBranch}-v${maxVersion + 1}`\n\n // Create the new branch locally from current HEAD (carries all commits)\n try {\n execFileSync('git', ['checkout', '-b', newBranch], {\n cwd,\n encoding: 'utf-8',\n })\n logger.info(` Created fresh branch: ${newBranch}`)\n } catch (error) {\n // If branch already exists locally, checkout to it\n if (String(error).includes('already exists')) {\n execFileSync('git', ['checkout', newBranch], { cwd, encoding: 'utf-8' })\n logger.info(` Checked out existing fresh branch: ${newBranch}`)\n } else {\n throw error\n }\n }\n\n return newBranch\n}\n\nfunction buildPrTitle(\n taskDir: string,\n defaultBranch: string,\n cwd: string,\n issueNumber?: number,\n): string {\n // Read task.md for context\n const taskMdPath = path.join(taskDir, 'task.md')\n let taskDescription = ''\n let issueTitle = ''\n if (fs.existsSync(taskMdPath)) {\n const taskMdContent = fs.readFileSync(taskMdPath, 'utf-8')\n\n // First try to extract ## Issue Title section (highest priority)\n // More forgiving regex: accepts variable whitespace between heading and value\n const issueTitleMatch = taskMdContent.match(/^##\\s*Issue\\s*Title\\s*\\n+([^\\n]+)/im)\n if (issueTitleMatch) {\n issueTitle = issueTitleMatch[1].trim()\n }\n\n // Then get the rest of the description (strip both # Task and ## Issue Title sections)\n taskDescription = taskMdContent\n .replace(/^#\\s*Task\\s*/i, '')\n .replace(/^##\\s*Issue\\s*Title\\s*\\n+[^\\n]*\\n*/gim, '')\n .trim()\n }\n\n // Read task.json for type\n const taskJsonPath = path.join(taskDir, 'task.json')\n let taskType = 'feat'\n if (fs.existsSync(taskJsonPath)) {\n try {\n const taskJson = JSON.parse(fs.readFileSync(taskJsonPath, 'utf-8'))\n const typeMap: Record<string, string> = {\n fix_bug: 'fix',\n implement_feature: 'feat',\n refactor: 'refactor',\n docs: 'docs',\n ops: 'chore',\n research: 'chore',\n }\n taskType = typeMap[taskJson.task_type] || 'feat'\n } catch {\n // ignore\n }\n }\n\n // Priority: 1) Issue title from task.md, 2) First content line from task.md, 3) Commit messages\n\n // Strip severity tags from issue title (e.g., [MEDIUM], [HIGH], [LOW], [BUG], etc.)\n const cleanedIssueTitle = issueTitle.replace(/^\\[[^\\]]+\\]\\s*/, '')\n\n // Get first non-empty, non-heading line of task description as summary\n // More robust heading detection: track lines that were originally markdown headings\n const commonHeadings = ['description', 'summary', 'overview', 'details', 'background']\n const firstLine =\n taskDescription\n .split('\\n')\n .map((l) => {\n const originalLine = l\n\n // Strip conventional commit prefix first (fix:, feat:, etc.)\n let cleaned = l.replace(\n /^(fix|feat|refactor|docs|chore|test|style|perf|ci|build)(\\([^)]*\\))?:/i,\n '',\n )\n // Trim leading space left by prefix removal\n cleaned = cleaned.trim()\n // Then strip markdown heading markers\n cleaned = cleaned.replace(/^#+\\s*/, '').trim()\n\n return { original: originalLine, cleaned }\n })\n // Exclude lines that were headings (matched /^#+\\s*\\S/) AND ended up as common heading words\n .filter(({ original, cleaned }) => {\n const isCommonHeading = commonHeadings.includes(cleaned.toLowerCase())\n const wasHeading = /^#+\\s*\\S/.test(original.trim())\n return cleaned.length > 0 && !(wasHeading && isCommonHeading)\n })[0]?.cleaned ?? ''\n\n // Use issue title if available, otherwise fall back to first content line\n const titleSource = cleanedIssueTitle || firstLine\n\n // Use commit messages as fallback\n if (!titleSource) {\n const commits = getCommitSummary(defaultBranch, cwd)\n const firstCommit = commits.split('\\n')[0] || 'implement changes'\n // Strip commit hash\n return `${taskType}: ${firstCommit.replace(/^[a-f0-9]+\\s+/, '')}`\n }\n\n // Truncate to reasonable length\n const summary = titleSource.length > 72 ? titleSource.slice(0, 69) + '...' : titleSource\n\n // Add issue reference to title for GitHub auto-linking\n const issueRef = issueNumber ? ` - Closes #${issueNumber}` : ''\n\n return `${taskType}: ${summary.toLowerCase()}${issueRef}`\n}\n\nfunction buildPrBody(\n taskDir: string,\n defaultBranch: string,\n cwd: string,\n issueNumber?: number,\n): string {\n const commits = getCommitSummary(defaultBranch, cwd)\n\n // Read spec for context — extract ## Overview section if present\n const specPath = path.join(taskDir, 'spec.md')\n let specSummary = ''\n if (fs.existsSync(specPath)) {\n const spec = fs.readFileSync(specPath, 'utf-8')\n // Try to extract the ## Overview section\n const overviewMatch = spec.match(/##\\s*Overview\\n([\\s\\S]*?)(?=\\n##\\s|$)/)\n if (overviewMatch) {\n specSummary = overviewMatch[1].trim()\n } else {\n // Fallback: first paragraph (up to first blank line or 500 chars)\n const firstPara = spec.split(/\\n\\n/)[0] || ''\n specSummary = firstPara.slice(0, 500).trim()\n }\n }\n\n const lines = ['## Summary\\n']\n\n if (specSummary) {\n lines.push(specSummary)\n lines.push('')\n }\n\n if (commits) {\n lines.push('## Commits\\n')\n lines.push('```')\n lines.push(commits)\n lines.push('```')\n }\n\n if (issueNumber) {\n lines.push(`\\nCloses #${issueNumber}`)\n }\n\n lines.push('\\n---\\n🤖 Generated by Kody pipeline')\n lines.push('<!-- TODO: update docs -->')\n\n return lines.join('\\n')\n}\n\nexport async function runPrStage(\n taskDir: string,\n outputFile: string,\n cwd: string = process.cwd(),\n issueNumber?: number,\n options?: {\n fresh?: boolean // Force create new PR (new branch)\n },\n): Promise<PrResult> {\n logger.info('\\n📝 Creating PR (scripted)...\\n')\n\n const branch = getBranchName(cwd)\n const defaultBranch = getDefaultBranch(cwd)\n\n // Step 1: Check for existing PR (unless --fresh is set)\n const existingUrl = !options?.fresh ? getExistingPr(branch, cwd) : null\n if (existingUrl && !options?.fresh) {\n logger.info(` PR already exists: ${existingUrl}`)\n const report = `# PR Stage\\n\\nExisting PR found: ${existingUrl}\\n`\n fs.writeFileSync(outputFile, report)\n return { created: false, url: existingUrl, report }\n }\n\n if (options?.fresh && existingUrl) {\n logger.info(` --fresh flag: creating new PR (ignoring existing: ${existingUrl})`)\n }\n\n // Step 2: Push branch (skip pre-push hooks to avoid blocking on unrelated checks)\n logger.info(' Pushing branch ' + branch + '...')\n let pushSuccess = false\n try {\n execFileSync('git', ['push', '-u', 'origin', branch], {\n cwd,\n stdio: 'inherit',\n timeout: 120_000,\n env: { ...process.env, HUSKY: '0', SKIP_HOOKS: '1' },\n })\n pushSuccess = true\n } catch (_error) {\n // Push was rejected - remote has changes, try pull --rebase and retry\n logger.info(' Push rejected, pulling and rebasing...')\n try {\n execFileSync('git', ['pull', '--rebase', 'origin', branch], {\n cwd,\n stdio: 'inherit',\n timeout: 120_000,\n env: { ...process.env, HUSKY: '0', SKIP_HOOKS: '1' },\n })\n // Retry push after rebase\n execFileSync('git', ['push', '-u', 'origin', branch], {\n cwd,\n stdio: 'inherit',\n timeout: 120_000,\n env: { ...process.env, HUSKY: '0', SKIP_HOOKS: '1' },\n })\n pushSuccess = true\n logger.info(' Push succeeded after rebase')\n } catch (_rebaseError) {\n logger.info(' Push failed even after rebase')\n }\n }\n\n if (!pushSuccess) {\n // R3-FIX #1: Abort PR creation if push failed — GitHub API will reject the PR\n // with \"branch not reachable\" since the branch doesn't exist on the remote.\n logger.error(' ❌ Push failed — cannot create PR for unpushed branch')\n const report =\n '# PR Stage\\n\\nFailed to create PR: git push failed. Branch not available on remote.\\n'\n fs.writeFileSync(outputFile, report)\n return { created: false, url: '', report }\n }\n // Step 3: Build title and body\n const title = buildPrTitle(taskDir, defaultBranch, cwd, issueNumber)\n const body = buildPrBody(taskDir, defaultBranch, cwd, issueNumber)\n\n logger.info(` Title: ${title}`)\n\n // Step 4: Create PR via GitHub REST API (more reliable than gh CLI in CI)\n // BUG-F fix: Use GH_PAT if non-empty, fall back to GH_TOKEN (don't use empty string)\n const ghToken = process.env.GH_PAT?.trim() || process.env.GH_TOKEN\n\n if (!ghToken) {\n logger.error(' ❌ No GitHub token found (GH_PAT or GH_TOKEN)')\n const report = `# PR Stage\\n\\nFailed to create PR: No GitHub token found. Set GH_PAT or GH_TOKEN.\\n`\n fs.writeFileSync(outputFile, report)\n return { created: false, url: '', report }\n }\n\n // Extract owner and repo from git remote\n let owner = ''\n let repo = ''\n try {\n const remoteUrl = execFileSync('git', ['remote', 'get-url', 'origin'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n // Parse from: https://github.com/owner/repo.git or git@github.com:owner/repo.git\n const match = remoteUrl.match(/github\\.com[/:]([^/]+)\\/([^/.]+)/)\n if (match) {\n owner = match[1]\n repo = match[2]\n }\n } catch {\n logger.error(' ❌ Could not determine repo from git remote')\n const report = `# PR Stage\\n\\nFailed to determine repository from git remote\\n`\n fs.writeFileSync(outputFile, report)\n return { created: false, url: '', report }\n }\n\n let prUrl = ''\n try {\n const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/pulls`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${ghToken}`,\n Accept: 'application/vnd.github.v3+json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n title,\n body,\n head: branch,\n base: defaultBranch,\n draft: false,\n }),\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new Error(`GitHub API error: ${response.status} - ${errorText}`)\n }\n\n const prData = (await response.json()) as { html_url: string }\n prUrl = prData.html_url\n logger.info(` ✅ PR created: ${prUrl}`)\n\n // Post comment to issue linking to PR\n if (issueNumber) {\n const cleanUrl = prUrl.replace(/\\n/g, '').trim()\n postComment(issueNumber, `🎉 PR created: ${cleanUrl}`)\n logger.info(` ✅ Commented on issue #${issueNumber}`)\n }\n\n // Set lifecycle label to review\n if (issueNumber) {\n setLifecycleLabel(issueNumber, 'kody:review')\n }\n } catch (error: unknown) {\n const err = error as { message?: string }\n const msg = err.message || 'Unknown error'\n logger.error(` ❌ PR creation failed: ${msg}`)\n const report = `# PR Stage\n\nFailed to create PR: ${msg}\n\nTitle: ${title}\n\n${body}\n`\n fs.writeFileSync(outputFile, report)\n return { created: false, url: '', report }\n }\n\n const report = `# PR Stage\n\nPR created: ${prUrl}\n\nTitle: ${title}\n\n${body}\n`\n fs.writeFileSync(outputFile, report)\n return { created: true, url: prUrl, report }\n}\n\n// ============================================================================\n// Commit Stage — commit and push changes via git-utils\n// ============================================================================\n\ninterface CommitResult {\n success: boolean\n hash: string\n branch: string\n message: string\n report: string\n}\n\nexport function runCommitStage(\n taskDir: string,\n outputFile: string,\n cwd: string = process.cwd(),\n): CommitResult {\n logger.info('\\n📦 Committing changes (scripted)...\\n')\n\n // Extract task ID from taskDir path\n const taskId = path.basename(taskDir)\n\n const result = commitAndPush(taskId, taskDir, cwd)\n\n const lines = [`# Commit Stage\\n`]\n\n if (result.success) {\n lines.push(`✅ **Committed and pushed**\\n`)\n lines.push(`- **Branch:** ${result.branch}`)\n lines.push(`- **Hash:** ${result.hash}`)\n logger.info(` ✅ ${result.message}`)\n } else {\n lines.push(`⚠️ **Commit status:** ${result.message}\\n`)\n if (result.message.includes('No changes')) {\n logger.info(` ℹ️ ${result.message}`)\n } else {\n logger.error(` ❌ ${result.message}`)\n }\n }\n\n const report = lines.join('\\n')\n fs.writeFileSync(outputFile, report)\n\n return {\n success: result.success,\n hash: result.hash,\n branch: result.branch,\n message: result.message,\n report,\n }\n}\n","/**\n * @fileType handler\n * @domain kody | handlers\n * @pattern scripted-handler\n * @ai-summary Scripted verify handler with auto-fix for lint/format\n */\n\nimport type { PipelineContext, StageDefinition, StageResult } from '../engine/types'\nimport { logger } from '../logger'\nimport { runVerifyStage } from '../scripted-stages'\nimport { commitPipelineFiles } from '../git-utils'\nimport type { StageHandler } from './handler'\nimport { DEFAULT_TIMEOUT } from '../agent-runner'\nimport { existsSync, unlinkSync } from 'fs'\nimport { execFileSync } from 'child_process'\nimport { getProjectConfig } from '../config/project-config'\n\nconst MAX_AUTOFIX_ATTEMPTS = 2\n\n/**\n * Scripted verify handler with scripted auto-fix loop.\n *\n * When verify fails on lint/format, runs `pnpm lint:fix` + `pnpm format:fix`\n * directly instead of invoking an LLM agent. The build agent already handled\n * all substantive failures (tsc, tests) in its own feedback loop.\n */\nexport class ScriptedVerifyHandler implements StageHandler {\n async execute(ctx: PipelineContext, def: StageDefinition): Promise<StageResult> {\n const outputFile = `${ctx.taskDir}/${def.name}.md`\n\n const startTime = Date.now()\n const totalTimeout = def.timeout ?? DEFAULT_TIMEOUT\n\n // Run initial verify\n const verifyResult = runVerifyStage(outputFile, undefined, def.timeout, ctx.taskDir)\n\n if (verifyResult.passed) {\n return {\n outcome: 'completed',\n retries: 0,\n outputFile: `${def.name}.md`,\n }\n }\n\n // Failed — try scripted auto-fix loop (lint:fix + format:fix)\n let fixed = false\n\n for (let attempt = 1; attempt <= MAX_AUTOFIX_ATTEMPTS; attempt++) {\n const elapsed = Date.now() - startTime\n const remaining = totalTimeout - elapsed\n\n if (remaining <= 0) {\n logger.info(\n ` \\u23f1\\ufe0f Aggregate timeout exceeded (${totalTimeout / 1000 / 60} minutes) — stopping auto-fix loop`,\n )\n return {\n outcome: 'timed_out',\n reason: `Aggregate timeout exceeded during auto-fix loop after ${attempt - 1} attempts`,\n retries: 0,\n }\n }\n\n logger.info(\n `\\n\\ud83d\\udd27 Scripted auto-fix attempt ${attempt}/${MAX_AUTOFIX_ATTEMPTS} (${(remaining / 1000 / 60).toFixed(1)}m remaining)...`,\n )\n\n // Run lint:fix and format:fix directly — no LLM needed for mechanical fixes\n const config = getProjectConfig()\n const runFixCmd = (label: string, cmd: string) => {\n const parts = cmd.split(/\\s+/)\n try {\n logger.info(` Running ${cmd}...`)\n execFileSync(parts[0], parts.slice(1), {\n stdio: 'pipe',\n timeout: 2 * 60 * 1000,\n maxBuffer: 10 * 1024 * 1024,\n })\n logger.info(` \\u2713 ${label} completed`)\n } catch {\n logger.info(` \\u2717 ${label} had errors (some may need manual fix)`)\n }\n }\n\n runFixCmd('lint:fix', config.quality.lintFix)\n runFixCmd('format:fix', config.quality.formatFix)\n\n // Re-run verify after fixes\n logger.info(' Re-running verification...')\n if (existsSync(outputFile)) {\n unlinkSync(outputFile)\n }\n\n const elapsedAfter = Date.now() - startTime\n const remainingAfter = totalTimeout - elapsedAfter\n\n if (remainingAfter <= 0) {\n logger.info(` \\u23f1\\ufe0f Aggregate timeout exceeded — stopping before verify re-run`)\n return {\n outcome: 'timed_out',\n reason: `Aggregate timeout exceeded during auto-fix loop`,\n retries: 0,\n }\n }\n\n const reVerify = runVerifyStage(outputFile, undefined, remainingAfter, ctx.taskDir)\n if (reVerify.passed) {\n logger.info(` \\u2705 Verification passed after auto-fix attempt ${attempt}`)\n fixed = true\n break\n } else {\n logger.error(` \\u274c Verification still failing after auto-fix attempt ${attempt}`)\n }\n }\n\n if (!fixed) {\n return {\n outcome: 'failed',\n reason: 'Verification failed after auto-fix attempts',\n retries: 0,\n }\n }\n\n // Commit auto-fix changes\n const commitResult = commitPipelineFiles({\n taskDir: ctx.taskDir,\n taskId: ctx.taskId,\n message: `fix: Auto-fix lint/format for ${ctx.taskId}\\n\\nApply automated lint and format fixes`,\n stagingStrategy: 'tracked+task',\n push: true,\n dryRun: ctx.input.dryRun,\n })\n\n if (!commitResult.success && !commitResult.message.includes('No changes')) {\n logger.error(` \\u274c Failed to commit/push auto-fix changes: ${commitResult.message}`)\n return {\n outcome: 'failed',\n reason: 'Auto-fix changes could not be pushed',\n retries: 0,\n }\n }\n\n return {\n outcome: 'completed',\n retries: 0,\n outputFile: `${def.name}.md`,\n }\n }\n}\n","/**\n * @fileType handler\n * @domain kody | handlers\n * @pattern git-handler\n * @ai-summary Git handlers for commit and PR stages\n */\n\nimport { execFileSync } from 'child_process'\n\nimport type { PipelineContext, StageDefinition, StageResult } from '../engine/types'\nimport { runCommitStage, runPrStage } from '../scripted-stages'\nimport { getDefaultBranch } from '../git-utils'\nimport type { StageHandler } from './handler'\n\n/**\n * Git commit handler\n */\nexport class GitCommitHandler implements StageHandler {\n async execute(_ctx: PipelineContext, _def: StageDefinition): Promise<StageResult> {\n const outputFile = `${_ctx.taskDir}/commit.md`\n\n const result = runCommitStage(_ctx.taskDir, outputFile)\n\n if (!result.success) {\n // \"No changes\" is OK — fix/autofix may produce no file changes.\n // Real \"empty build\" errors are caught by validate-src-changes post-action.\n if (result.message.includes('No changes')) {\n return { outcome: 'completed', retries: 0 }\n }\n return {\n outcome: 'failed',\n reason: result.message,\n retries: 0,\n }\n }\n\n return {\n outcome: 'completed',\n retries: 0,\n }\n }\n}\n\n/**\n * Git PR handler\n *\n * H3 FIX: Uses getDefaultBranch() instead of hardcoded 'origin/dev'\n * to support repos with different default branch names (main, master, etc.)\n */\nexport class GitPrHandler implements StageHandler {\n async execute(ctx: PipelineContext, _def: StageDefinition): Promise<StageResult> {\n const outputFile = `${ctx.taskDir}/pr.md`\n\n // H3 FIX: Get the actual default branch dynamically instead of hardcoding 'dev'\n const defaultBranch = getDefaultBranch()\n\n // Final guard: verify branch has source changes before creating PR\n // C4 FIX: Use execFileSync instead of execSync to prevent shell injection\n try {\n const diff = execFileSync('git', ['diff', '--name-only', `origin/${defaultBranch}...HEAD`], {\n encoding: 'utf-8',\n }).trim()\n const srcChanges = diff.split('\\n').filter((f) => f && !f.startsWith('.tasks/'))\n if (srcChanges.length === 0) {\n return {\n outcome: 'failed',\n reason: 'No source files changed vs base branch — refusing to create empty PR',\n retries: 0,\n }\n }\n } catch {\n // Non-blocking — proceed if git check fails (e.g., shallow clone)\n }\n\n // R5: Pass issueNumber to link PR to the issue\n const result = await runPrStage(ctx.taskDir, outputFile, undefined, ctx.input.issueNumber, {\n fresh: ctx.input.fresh,\n })\n\n if (!result.created && !result.url) {\n return {\n outcome: 'failed',\n reason: result.report || 'PR creation failed',\n retries: 0,\n }\n }\n\n return {\n outcome: 'completed',\n retries: 0,\n }\n }\n}\n","/**\n * @fileType utility\n * @domain ci | kody\n * @pattern clarify-workflow\n * @ai-summary Question/answer workflow for clarification stage - extracted from kody.ts for testability\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { getLatestIssueComment, getLatestApprovalComment } from './github-api'\nimport type { KodyInput } from './kody-utils'\nimport { checkForQuestions } from './content-validators'\nimport { logger } from './logger'\n\n// ============================================================================\n// Safe File Write Helper\n// ============================================================================\n\n/**\n * Safe file write with error logging. Re-throws on failure so callers can handle.\n */\nfunction safeWriteFile(filePath: string, content: string): void {\n try {\n fs.writeFileSync(filePath, content)\n } catch (error) {\n logger.error({ err: error }, `Failed to write file: ${filePath}`)\n throw error\n }\n}\n\n// ============================================================================\n// Answer Extraction\n// ============================================================================\n\n/**\n * Extract the answer from a GitHub comment body\n * The comment format is: /kody [command] [task-id] [optional answer text]\n * Also handles: @kody approve [answer], @kody reject [answer]\n */\nexport function extractAnswerFromComment(commentBody: string): string | null {\n // Decode JSON-encoded body if needed (from jq -Rs .)\n let decoded = commentBody\n if (decoded.startsWith('\"') && decoded.endsWith('\"')) {\n try {\n decoded = JSON.parse(decoded)\n } catch {\n // Use raw value if JSON.parse fails\n }\n }\n\n // Normalize literal \\n to real newlines\n decoded = decoded.replace(/\\\\n/g, '\\n')\n\n // Remove /kody or @kody prefix\n const withoutKody = decoded.replace(/^[\\/]?@?kody\\s*/, '').trim()\n\n // If there's content after the command, treat it as the answer\n if (withoutKody.length > 0) {\n // Remove task-id if present (format: /kody [task-id] or /kody full [task-id])\n const taskIdMatch = withoutKody.match(/^([a-z]+\\s+)?([0-9]{6}-[a-z0-9-]+\\s*)/i)\n let answer = withoutKody\n if (taskIdMatch) {\n answer = withoutKody.slice(taskIdMatch[0].length).trim()\n }\n\n // Also remove approval/rejection keywords (user wrote \"@kody approve\" + answers)\n const lowerAnswer = answer.toLowerCase()\n for (const keyword of [...APPROVAL_KEYWORDS, ...REJECTION_KEYWORDS]) {\n if (lowerAnswer.startsWith(keyword)) {\n answer = answer.slice(keyword.length).trim()\n break\n }\n }\n\n // If there's answer content, return it\n if (answer.length > 0) {\n return answer\n }\n }\n\n return null\n}\n\n// ============================================================================\n// Clarification Handler\n// ============================================================================\n\n/**\n * Result of handling clarification\n */\nexport type ClarifyResult = 'answered' | 'waiting' | 'no-questions'\n\n/**\n * Handle clarification workflow for the spec pipeline.\n * Checks if questions.md exists, extracts answer from comment if provided,\n * and creates clarified.md.\n *\n * @param input - The KodyInput with commentBody and trigger info\n * @param taskDir - Path to the task directory\n * @returns 'answered' if user provided answer, 'waiting' if questions exist, 'no-questions' if no clarification needed\n */\nexport function handleClarification(input: KodyInput, taskDir: string): ClarifyResult {\n const questionsPath = path.join(taskDir, 'questions.md')\n const clarifiedPath = path.join(taskDir, 'clarified.md')\n\n // If questions.md doesn't exist, no clarification needed - create default clarified.md\n if (!fs.existsSync(questionsPath)) {\n if (!fs.existsSync(clarifiedPath)) {\n safeWriteFile(clarifiedPath, '# Clarified\\n\\nUse recommended answers.\\n')\n }\n return 'no-questions'\n }\n\n let answer: string | null = null\n\n // Try to get answer from:\n // 1. Comment body (if user wrote \"/kody answer text\")\n if (input.commentBody && input.triggerType === 'comment') {\n answer = extractAnswerFromComment(input.commentBody)\n }\n\n // 2. Latest comment on the issue (plain text answer)\n if (!answer && input.issueNumber && input.triggerType === 'comment') {\n // Get the latest comment (not from bot) as the answer\n answer = getLatestIssueComment(input.issueNumber, 'github-actions[bot]')\n }\n\n // If we have an answer, create clarified.md\n if (answer) {\n safeWriteFile(clarifiedPath, `# Clarified\\n\\n${answer}\\n`)\n return 'answered'\n }\n\n // Check if there are pending questions\n const hasQuestions = !fs.existsSync(clarifiedPath) && checkForQuestions(questionsPath)\n\n if (hasQuestions) {\n return 'waiting'\n }\n\n // No questions - create default clarified.md\n if (!fs.existsSync(clarifiedPath)) {\n safeWriteFile(clarifiedPath, '# Clarified\\n\\nUse recommended answers.\\n')\n }\n\n return 'no-questions'\n}\n\n// ============================================================================\n// Gate Approval Handler\n// ============================================================================\n\n/**\n * Result of handling gate approval\n */\nexport type GateResult = 'approved' | 'rejected' | 'waiting'\n\n/**\n * Structured gate commands — only `approve` and `reject` are accepted.\n * Previously accepted ambiguous keywords (yes, go, y, continue, no, n, stop, cancel)\n * which could cause accidental approvals/rejections from natural language comments.\n */\nconst APPROVAL_KEYWORDS = ['approve'] as const\nconst REJECTION_KEYWORDS = ['reject'] as const\n\n/**\n * Get the gate file paths for a specific gate point\n */\nfunction getGateFiles(\n taskDir: string,\n gatePoint: string,\n): { requestPath: string; approvedPath: string } {\n const requestPath = path.join(taskDir, `gate-${gatePoint}.md`)\n const approvedPath = path.join(taskDir, `gate-${gatePoint}-approved.md`)\n return { requestPath, approvedPath }\n}\n\n/**\n * Result of detecting approval from comment - includes optional answer content\n */\nexport interface ApprovalDetection {\n status: 'approved' | 'rejected' | null\n /** Answer content after the approve/reject keyword (preserves newlines for multi-line answers) */\n answerContent?: string | null\n}\n\n/**\n * Check if a comment contains structured gate commands (`approve` or `reject`).\n * Only exact commands are accepted — no ambiguous keywords.\n * Also extracts any answer content provided after the keyword (preserves newlines!)\n */\nexport function detectApprovalFromComment(commentBody: string | null): ApprovalDetection {\n if (!commentBody) return { status: null }\n\n // Decode if JSON-encoded\n let decoded = commentBody\n if (decoded.startsWith('\"') && decoded.endsWith('\"')) {\n try {\n decoded = JSON.parse(decoded)\n } catch {\n // Use raw value\n }\n }\n\n // Normalize literal \\n to real newlines (preserving them for answer extraction)\n decoded = decoded.replace(/\\\\n/g, '\\n')\n\n // Get original for answer extraction (before lowercasing)\n const originalWithNewlines = decoded\n\n // Lowercase for keyword matching (but we still check original position)\n const lowerDecoded = decoded.toLowerCase()\n\n // Remove /kody or @kody prefix\n const withoutPrefix = lowerDecoded.replace(/^[\\/]?@?kody\\s*/, '').trim()\n // Also get the original (with case preserved) after prefix removal (use regex with limit)\n const originalWithoutPrefix = originalWithNewlines.replace(/^[\\/]?@?kody\\s*/i, '').trim()\n\n // Check for rejection keywords first (more specific)\n for (const keyword of REJECTION_KEYWORDS) {\n if (\n withoutPrefix === keyword ||\n withoutPrefix.startsWith(keyword + ' ') ||\n withoutPrefix.startsWith(keyword + '\\n')\n ) {\n // Extract any content after the rejection keyword\n const answerContent = extractContentAfterKeyword(originalWithoutPrefix, keyword)\n return { status: 'rejected', answerContent }\n }\n }\n\n // Check for approval keywords\n for (const keyword of APPROVAL_KEYWORDS) {\n if (\n withoutPrefix === keyword ||\n withoutPrefix.startsWith(keyword + ' ') ||\n withoutPrefix.startsWith(keyword + '\\n')\n ) {\n // Extract any content after the approval keyword (this preserves newlines!)\n const answerContent = extractContentAfterKeyword(originalWithoutPrefix, keyword)\n return { status: 'approved', answerContent: answerContent }\n }\n }\n\n return { status: null }\n}\n\n/**\n * Extract content after a keyword (approve/reject) while preserving newlines\n */\nfunction extractContentAfterKeyword(text: string, keyword: string): string | null {\n const lowerText = text.toLowerCase()\n const keywordIndex = lowerText.indexOf(keyword)\n\n if (keywordIndex === -1) return null\n\n // Get everything after the keyword\n const afterKeyword = text.slice(keywordIndex + keyword.length).trim()\n\n // If there's content after the keyword, return it (preserves newlines!)\n if (afterKeyword.length > 0) {\n return afterKeyword\n }\n\n return null\n}\n\n/**\n * Format the gate comment for posting to the issue\n */\nfunction formatGateComment(\n controlMode: string,\n riskLevel: string,\n taskType: string,\n confidence: number,\n scope: string[],\n taskSummary: string,\n gatePoint: string,\n planContent?: string,\n assumptions?: string[],\n reviewQuestions?: string[],\n): string {\n const lines: string[] = []\n\n if (controlMode === 'hard-stop') {\n lines.push('## 🚫 Hard Stop: Approval Required\\n')\n lines.push(\n 'This task has been classified as **high risk** and requires mandatory approval before proceeding.\\n',\n )\n } else {\n lines.push('## 🚦 Risk Gate: Approval Required\\n')\n lines.push(\n 'This task has been classified as **medium risk** and is paused for review before building.\\n',\n )\n }\n\n const scopeDisplay =\n scope.length <= 5 ? scope.map((f) => `\\`${f}\\``).join(', ') : `${scope.length} files`\n\n lines.push('| Field | Value |')\n lines.push('|-------|-------|')\n lines.push(`| **Control Mode** | ${controlMode} |`)\n lines.push(`| **Risk Level** | ${riskLevel} |`)\n lines.push(`| **Task Type** | ${taskType} |`)\n lines.push(`| **Confidence** | ${confidence} |`)\n lines.push(`| **Scope** | ${scopeDisplay} |`)\n lines.push('')\n\n lines.push('### Task Summary')\n lines.push(`> ${taskSummary.split('\\n')[0]}`)\n lines.push('')\n\n if (assumptions && assumptions.length > 0) {\n lines.push('### Assumptions')\n for (const assumption of assumptions) {\n lines.push(`- ${assumption}`)\n }\n lines.push('')\n }\n\n if (reviewQuestions && reviewQuestions.length > 0) {\n lines.push('### Review Questions')\n reviewQuestions.forEach((question, index) => {\n lines.push(`${index + 1}. ${question}`)\n })\n lines.push('')\n }\n\n if (planContent && gatePoint === 'architect') {\n lines.push('### Plan')\n // First 20 lines of plan\n const planLines = planContent.split('\\n').slice(0, 20).join('\\n')\n lines.push('```')\n lines.push(planLines)\n lines.push('```')\n lines.push('')\n }\n\n lines.push('---')\n lines.push('')\n lines.push('Reply `approve` to proceed.')\n lines.push('Reply `reject` to cancel.')\n\n return lines.join('\\n')\n}\n\n/**\n * Handle gate approval workflow for risk-gated and hard-stop modes.\n * Similar to clarification workflow but for approval gates.\n *\n * @param input - The KodyInput with commentBody and trigger info\n * @param taskDir - Path to the task directory\n * @param gatePoint - Which gate: 'taskify' or 'architect'\n * @param taskDef - The task definition (for context in the gate comment)\n * @param planContent - Optional plan content (for architect gate)\n * @returns 'approved' if user approved, 'rejected' if user rejected, 'waiting' if awaiting approval\n */\nexport function handleGateApproval(\n input: KodyInput,\n taskDir: string,\n gatePoint: string,\n taskDef: { risk_level: string; task_type: string; confidence: number; scope: string[] },\n planContent?: string,\n): GateResult {\n const { requestPath, approvedPath } = getGateFiles(taskDir, gatePoint)\n\n // If already approved, return approved\n if (fs.existsSync(approvedPath)) {\n return 'approved'\n }\n\n // Check for approval/rejection in the current comment\n const approval = detectApprovalFromComment(input.commentBody || null)\n\n // Also check latest issue comment if not found in current trigger\n if (!approval.status && input.issueNumber && input.triggerType === 'comment') {\n // Use getLatestApprovalComment to find /kody approve or /kody reject commands\n const latestComment = getLatestApprovalComment(input.issueNumber, 'github-actions[bot]')\n const latestApproval = detectApprovalFromComment(latestComment)\n if (latestApproval.status) {\n // User replied with approve/reject - write the approved file\n if (latestApproval.status === 'approved') {\n const approvedBy = input.actor || 'unknown'\n const approvedAt = new Date().toISOString()\n safeWriteFile(\n approvedPath,\n `# Gate Approved\\n\\nApproved at ${gatePoint} gate.\\nApproved by: @${approvedBy}\\nApproved at: ${approvedAt}\\n`,\n )\n // If there's also answer content in the comment, create clarified.md\n if (latestApproval.answerContent) {\n const clarifiedPath = path.join(taskDir, 'clarified.md')\n safeWriteFile(clarifiedPath, `# Clarified\\n\\n${latestApproval.answerContent}\\n`)\n }\n return 'approved'\n } else {\n // Write rejection marker\n const rejectedBy = input.actor || 'unknown'\n safeWriteFile(\n requestPath,\n `# Gate Rejected\\n\\nRejected at ${gatePoint} gate.\\nRejected by: @${rejectedBy}\\n`,\n )\n return 'rejected'\n }\n }\n }\n\n // If we have approval in current trigger\n if (approval.status === 'approved') {\n const approvedBy = input.actor || 'unknown'\n const approvedAt = new Date().toISOString()\n safeWriteFile(\n approvedPath,\n `# Gate Approved\\n\\nApproved at ${gatePoint} gate.\\nApproved by: @${approvedBy}\\nApproved at: ${approvedAt}\\n`,\n )\n // If there's also answer content in the comment, create clarified.md\n if (approval.answerContent) {\n const clarifiedPath = path.join(taskDir, 'clarified.md')\n safeWriteFile(clarifiedPath, `# Clarified\\n\\n${approval.answerContent}\\n`)\n }\n return 'approved'\n } else if (approval.status === 'rejected') {\n const rejectedBy = input.actor || 'unknown'\n safeWriteFile(\n requestPath,\n `# Gate Rejected\\n\\nRejected at ${gatePoint} gate.\\nRejected by: @${rejectedBy}\\n`,\n )\n return 'rejected'\n }\n\n // If request file already exists, we're waiting\n if (fs.existsSync(requestPath)) {\n return 'waiting'\n }\n\n // First time hitting the gate - create request and return waiting\n // Read task summary from task.md (skip markdown headers and blank lines)\n const taskMdPath = path.join(taskDir, 'task.md')\n let taskSummary = 'See task.md for details'\n if (fs.existsSync(taskMdPath)) {\n const taskContent = fs.readFileSync(taskMdPath, 'utf-8')\n const contentLine = taskContent\n .split('\\n')\n .find((line) => line.trim().length > 0 && !line.trim().startsWith('#'))\n taskSummary = contentLine?.trim() || taskSummary\n }\n\n // Read task.json for assumptions and review_questions\n const taskJsonPath = path.join(taskDir, 'task.json')\n let assumptions: string[] = []\n let reviewQuestions: string[] = []\n if (fs.existsSync(taskJsonPath)) {\n try {\n const taskJson = JSON.parse(fs.readFileSync(taskJsonPath, 'utf-8'))\n if (Array.isArray(taskJson.assumptions)) {\n assumptions = taskJson.assumptions\n }\n if (Array.isArray(taskJson.review_questions)) {\n reviewQuestions = taskJson.review_questions\n }\n } catch {\n // Ignore parse errors\n }\n }\n\n const comment = formatGateComment(\n taskDef.risk_level === 'high' ? 'hard-stop' : 'risk-gated',\n taskDef.risk_level,\n taskDef.task_type,\n taskDef.confidence,\n taskDef.scope,\n taskSummary,\n gatePoint,\n planContent,\n assumptions,\n reviewQuestions,\n )\n\n // Write gate request file\n safeWriteFile(requestPath, `# Gate Request\\n\\n${comment}\\n`)\n\n // Return waiting - caller will post the comment to the issue\n return 'waiting'\n}\n","/**\n * @fileType handler\n * @domain kody | handlers\n * @pattern gate-handler\n * @ai-summary Gate handler for approval workflow\n */\n\nimport type { PipelineContext, StageDefinition, StageResult } from '../engine/types'\nimport { handleGateApproval } from '../clarify-workflow'\nimport { resolveControlMode } from '../pipeline-utils'\nimport type { StageHandler } from './handler'\n\n/**\n * Gate handler - resolves controlMode dynamically and handles approval\n */\nexport class GateHandler implements StageHandler {\n async execute(ctx: PipelineContext, def: StageDefinition): Promise<StageResult> {\n // Guard: taskDef must be loaded before gate can run\n if (!ctx.taskDef) {\n return {\n outcome: 'failed',\n reason: 'task.json not loaded - gate stage requires task definition',\n retries: 0,\n }\n }\n\n // Resolve controlMode dynamically (G42)\n const controlMode = resolveControlMode(ctx.taskDef, ctx.input.controlMode)\n\n // Determine gate name from stage name (architect or taskify)\n const gate = def.name === 'architect' ? 'architect' : 'taskify'\n\n // Call gate approval handler\n const gateResult = handleGateApproval(ctx.input, ctx.taskDir, gate, ctx.taskDef)\n\n if (gateResult === 'waiting') {\n return {\n outcome: 'paused',\n reason: `${controlMode} gate: awaiting approval`,\n retries: 0,\n }\n }\n\n if (gateResult === 'rejected') {\n return {\n outcome: 'failed',\n reason: `Task rejected at ${controlMode} gate`,\n retries: 0,\n }\n }\n\n // Approved\n return {\n outcome: 'completed',\n retries: 0,\n }\n }\n}\n","/**\n * @fileType interface\n * @domain kody | handlers\n * @pattern handler-registry\n * @ai-summary Handler interface and registry for pipeline stages\n */\n\nimport type { PipelineContext, StageDefinition, StageResult, StageType } from '../engine/types'\nimport type { StageName } from '../stages/registry'\nimport { AgentHandler } from './agent-handler'\nimport { ScriptedVerifyHandler } from './scripted-handler'\nimport { GitCommitHandler, GitPrHandler } from './git-handler'\nimport { GateHandler } from './gate-handler'\n\n/**\n * Interface for all stage handlers\n */\nexport interface StageHandler {\n execute(ctx: PipelineContext, def: StageDefinition): Promise<StageResult>\n}\n\n// ============================================================================\n// Handler Registry\n// ============================================================================\n\n/**\n * Get handler for a stage based on its name and type.\n * Uses name-based lookup first (R3), then falls back to type-based default.\n */\nexport function getHandler(stageName: StageName, stageType: StageType): StageHandler {\n // Named handlers first - for stages that need special handling\n switch (stageName) {\n case 'commit':\n return new GitCommitHandler()\n case 'pr':\n return new GitPrHandler()\n case 'verify':\n return new ScriptedVerifyHandler()\n }\n\n // Type-based default handlers\n switch (stageType) {\n case 'agent':\n return new AgentHandler()\n case 'scripted':\n return new ScriptedVerifyHandler()\n case 'gate':\n return new GateHandler()\n case 'git':\n // Default git handler - shouldn't reach here normally\n return new GitCommitHandler()\n default:\n // R12: Exhaustiveness check - fail at compile time if new StageType is added\n const _exhaustive: never = stageType\n throw new Error(`Unknown stage type: ${stageType}`)\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Validates task.json after taskify stage, deletes invalid file for retry\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext } from '../../engine/types'\nimport { readTask } from '../../pipeline-utils'\n\nexport async function executeValidateTaskJson(ctx: PipelineContext): Promise<void> {\n try {\n readTask(ctx.taskDir)\n logger.info(' ✓ task.json validated')\n } catch (error) {\n // G13: Delete invalid file so retry can recreate\n const taskJsonPath = path.join(ctx.taskDir, 'task.json')\n if (fs.existsSync(taskJsonPath)) {\n fs.unlinkSync(taskJsonPath)\n }\n const msg = error instanceof Error ? error.message : String(error)\n throw new Error(`Invalid task.json: ${msg}`)\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Sets classification labels (type, risk, complexity, domain) on GitHub issue\n */\n\nimport type { PipelineContext } from '../../engine/types'\nimport { readTask } from '../../pipeline-utils'\nimport { setClassificationLabels } from '../../github-api'\n\nexport async function executeSetClassificationLabels(ctx: PipelineContext): Promise<void> {\n const taskDef = readTask(ctx.taskDir)\n if (ctx.input.issueNumber && taskDef) {\n setClassificationLabels(ctx.input.issueNumber, {\n task_type: taskDef.task_type,\n risk_level: taskDef.risk_level,\n complexity: taskDef.complexity,\n primary_domain: taskDef.primary_domain,\n })\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Builds promoted stub files for stages skipped via input_quality.skip_stages\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\n/**\n * Build a promoted stub file for a skipped stage.\n * Includes sections that downstream validators expect.\n */\nexport function buildPromotedStub(stage: string, taskDir: string): string {\n const title = stage.charAt(0).toUpperCase() + stage.slice(1)\n\n if (stage === 'spec') {\n // Gap validator checks for ## Requirements or ## Acceptance Criteria\n // Pull description from task.md if available\n const taskMdPath = path.join(taskDir, 'task.md')\n let description = 'See task.md and task.json for full details.'\n if (fs.existsSync(taskMdPath)) {\n description = fs.readFileSync(taskMdPath, 'utf-8')\n }\n return `# Specification (promoted)\n\nSkipped via input_quality — taskify determined spec is unnecessary.\n\n## Requirements\n\n${description}\n\n## Acceptance Criteria\n\n- [ ] Fix applied as described in task.md\n- [ ] TypeScript compilation passes\n- [ ] Unit tests pass\n`\n }\n\n if (stage === 'architect' || stage === 'plan-gap') {\n // Build stage reads plan.md; plan-gap validator checks plan.md exists\n return `# ${title} (promoted)\n\nSkipped via input_quality — taskify determined this stage is unnecessary.\nSee task.json input_quality.reasoning for details.\n\n## Changes\n\nSee task.md for implementation details.\n`\n }\n\n // Generic stub for other stages\n return `# ${title} (promoted)\n\nSkipped via input_quality — taskify determined this stage is unnecessary.\nSee task.json input_quality.reasoning for details.\n`\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Resolves pipeline profile (standard/lightweight) based on task definition,\n * triggers two-phase pipeline rebuild, creates promoted stubs for skipped stages\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext } from '../../engine/types'\nimport { readTask } from '../../pipeline-utils'\nimport { setProfileLabel } from '../../github-api'\nimport { buildPromotedStub } from './promoted-stub'\n\nexport async function executeResolveProfile(ctx: PipelineContext): Promise<void> {\n const taskDef = readTask(ctx.taskDir)\n if (taskDef) {\n // Apply --complexity override if provided (for testing/debugging)\n if (ctx.input.complexityOverride !== undefined) {\n const oldComplexity = taskDef.complexity\n taskDef.complexity = ctx.input.complexityOverride\n taskDef.complexity_reasoning = `Override via --complexity=${ctx.input.complexityOverride}`\n if (oldComplexity !== undefined) {\n logger.info(` ℹ️ Complexity override: ${oldComplexity} → ${ctx.input.complexityOverride}`)\n } else {\n logger.info(` ℹ️ Complexity override applied: ${ctx.input.complexityOverride}`)\n }\n }\n // Update ctx.taskDef so subsequent post-actions can access it\n ctx.taskDef = taskDef\n const { resolvePipelineProfile, getComplexityTier } = await import('../../pipeline-utils')\n ctx.profile = resolvePipelineProfile(taskDef)\n // Set profile label on the issue\n if (ctx.input.issueNumber) {\n setProfileLabel(ctx.input.issueNumber, ctx.profile)\n }\n // Signal engine to rebuild pipeline with new profile (two-phase construction)\n ctx.pipelineNeedsRebuild = true\n if (taskDef.complexity !== undefined) {\n const tier = getComplexityTier(taskDef.complexity)\n logger.info(` ℹ️ Complexity: ${taskDef.complexity} (${tier}) → profile: ${ctx.profile}`)\n\n // R2-FIX #6: Warn when complexity seems mismatched with profile.\n // A lightweight profile with high complexity may skip important stages.\n if (ctx.profile === 'lightweight' && taskDef.complexity >= 35) {\n logger.warn(\n ` ⚠️ Profile/complexity mismatch: lightweight profile with complexity ${taskDef.complexity} (complex tier). ` +\n `Some stages may be unexpectedly skipped. Consider overriding with --profile=standard.`,\n )\n }\n } else {\n logger.info(\n ` ℹ️ Resolved profile: ${ctx.profile} (no complexity score, using legacy heuristic)`,\n )\n }\n\n // Create stub promoted files for stages in skip_stages\n // The skip condition checks file existence, so we must ensure the file exists\n // Stubs must include sections that downstream validators expect\n const skipStages = taskDef.input_quality?.skip_stages ?? []\n for (const stage of skipStages) {\n const outputFile = path.join(ctx.taskDir, `${stage}.md`)\n if (!fs.existsSync(outputFile)) {\n const stub = buildPromotedStub(stage, ctx.taskDir)\n fs.writeFileSync(outputFile, stub)\n logger.info(` ℹ️ Created promoted stub: ${stage}.md`)\n }\n }\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Gate check lifecycle event — pauses pipeline for human approval,\n * posts gate comment on GitHub, writes paused state, throws PipelinePausedError\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext, PostAction, PipelineStateV2 } from '../../engine/types'\nimport { PipelinePausedError } from '../../engine/types'\nimport { readTask } from '../../pipeline-utils'\nimport { commitPipelineFiles } from '../../git-utils'\nimport { handleGateApproval } from '../../clarify-workflow'\nimport {\n extractGateCommentBody,\n postComment,\n addIssueLabel,\n removeIssueLabel,\n GATE_LABELS,\n} from '../../github-api'\nimport { updateStage, completeState, writeState, appendActorEvent } from '../../engine/status'\n\nexport async function executeCheckGate(\n ctx: PipelineContext,\n action: PostAction & { type: 'check-gate' },\n state: PipelineStateV2 | null,\n): Promise<void> {\n // BUG-F fix: taskDef might be null if resolve-profile hasn't run yet\n const taskDef = ctx.taskDef ?? readTask(ctx.taskDir)\n if (!taskDef) {\n throw new Error(`Cannot check gate \"${action.gate}\": task.json not found or invalid`)\n }\n // Skip gate when controlMode is 'auto' (low risk tasks don't need approval)\n const { resolveControlMode } = await import('../../pipeline-utils')\n const controlMode = resolveControlMode(taskDef, ctx.input.controlMode)\n if (controlMode === 'auto') {\n logger.info(` ✓ gate ${action.gate} skipped (controlMode: auto)`)\n return\n }\n const gateResult = handleGateApproval(ctx.input, ctx.taskDir, action.gate, taskDef)\n\n // Determine gate label based on risk level\n const gateLabel = taskDef.risk_level === 'high' ? GATE_LABELS.HARD_STOP : GATE_LABELS.RISK_GATED\n\n if (gateResult === 'waiting') {\n // Add gate label for dashboard visibility\n if (ctx.input.issueNumber) {\n addIssueLabel(ctx.input.issueNumber, gateLabel)\n }\n // Read gate file and extract comment body\n const gateFilePath = path.join(ctx.taskDir, `gate-${action.gate}.md`)\n if (fs.existsSync(gateFilePath)) {\n const gateContent = fs.readFileSync(gateFilePath, 'utf-8')\n const commentBody = extractGateCommentBody(gateContent)\n if (ctx.input.issueNumber && commentBody) {\n postComment(ctx.input.issueNumber, commentBody)\n }\n }\n // Pre-write paused state to status.json BEFORE commit+push,\n // so the persisted status.json on the branch reflects 'paused' (not 'running').\n // The state machine will also set paused after PipelinePausedError, but that\n // only writes locally — the commit here is what the next CI run reads.\n const currentState = state\n if (currentState) {\n let pausedState = updateStage(currentState, action.gate, { state: 'paused' })\n pausedState = completeState(pausedState, 'paused')\n writeState(ctx.taskId, pausedState)\n }\n\n // Commit and pause\n commitPipelineFiles({\n taskDir: ctx.taskDir,\n taskId: ctx.taskId,\n message: `ci(kody): pause at ${action.gate} gate for ${ctx.taskId}`,\n ensureBranch: true,\n stagingStrategy: 'task-only',\n push: true,\n isCI: !ctx.input.local,\n dryRun: ctx.input.dryRun,\n })\n throw new PipelinePausedError(`${action.gate} gate: awaiting approval for ${ctx.taskId}`)\n }\n if (gateResult === 'rejected') {\n // Remove gate label when rejected\n if (ctx.input.issueNumber) {\n removeIssueLabel(ctx.input.issueNumber, GATE_LABELS.HARD_STOP)\n removeIssueLabel(ctx.input.issueNumber, GATE_LABELS.RISK_GATED)\n }\n // Record gate rejection actor event\n if (ctx.actor && state) {\n appendActorEvent(ctx.taskId, state, {\n action: 'gate-rejected',\n actor: ctx.actor,\n timestamp: new Date().toISOString(),\n stage: action.gate,\n })\n }\n throw new Error(`Task rejected at ${action.gate} gate`)\n }\n // Approved - remove gate label so dashboard shows it's no longer waiting\n if (ctx.input.issueNumber) {\n removeIssueLabel(ctx.input.issueNumber, GATE_LABELS.HARD_STOP)\n removeIssueLabel(ctx.input.issueNumber, GATE_LABELS.RISK_GATED)\n }\n // Record gate approval actor event\n if (ctx.actor && state) {\n appendActorEvent(ctx.taskId, state, {\n action: 'gate-approved',\n actor: ctx.actor,\n timestamp: new Date().toISOString(),\n stage: action.gate,\n })\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Commits and pushes pipeline task files to remote branch\n */\n\nimport type { PipelineContext, PostAction } from '../../engine/types'\nimport { commitPipelineFiles } from '../../git-utils'\n\nexport async function executeCommitTaskFiles(\n ctx: PipelineContext,\n action: PostAction & { type: 'commit-task-files' },\n): Promise<void> {\n // G18: Skip if localOnly and not in local mode\n if (action.localOnly && !ctx.input.local) {\n return\n }\n // Skip if dryRun\n if (ctx.input.dryRun) {\n return\n }\n\n const result = commitPipelineFiles({\n taskDir: ctx.taskDir,\n taskId: ctx.taskId,\n message: action.commitMessage || `ci(kody): commit task files for ${ctx.taskId}`,\n ensureBranch: action.ensureBranch,\n cleanDirtyState: action.cleanDirtyState,\n stagingStrategy: action.stagingStrategy === 'tracked-only' ? 'all' : action.stagingStrategy,\n push: action.push,\n isCI: !ctx.input.local,\n dryRun: ctx.input.dryRun,\n })\n if (!result.success) {\n throw new Error(`commit-task-files failed: ${result.message}`)\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline | errors\n * @pattern error-classification\n * @ai-summary Classifies build/test/lint errors and formats them as actionable markdown for autofix agent\n */\n\nimport { MAX_GATE_OUTPUT_CHARS } from '../config/constants'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type ErrorCategory =\n | 'type_error'\n | 'lint_error'\n | 'format_error'\n | 'test_failure'\n | 'unknown'\n\nexport interface ClassifiedError {\n category: ErrorCategory\n summary: string\n fullOutput: string\n fileHints: string[]\n fixInstructions: string\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst MAX_OUTPUT_LENGTH = MAX_GATE_OUTPUT_CHARS\nconst MAX_SUMMARY_LENGTH = 500\n\nconst FIX_INSTRUCTIONS: Record<ErrorCategory, string> = {\n type_error:\n 'Fix TypeScript type errors. Check the affected files for type mismatches, missing imports, or incorrect function signatures.',\n lint_error: 'Fix lint errors. Run `pnpm lint:fix` first, then manually fix any remaining issues.',\n format_error: 'Fix format errors. Run `pnpm format:fix` to auto-format all files.',\n test_failure:\n 'Fix failing test(s). The tests may not match the implementation. Update the tests to correctly reflect what the code actually does.',\n unknown: 'Unknown error type. Read the full output below and fix the underlying issue.',\n}\n\n// ============================================================================\n// Regex patterns\n// ============================================================================\n\n/** Matches TSC output like: src/foo.ts(10,5): error TS2345: ... */\nconst TSC_FILE_REGEX = /([^\\s:]+\\.tsx?)\\(\\d+,\\d+\\)/g\n\n/** Matches vitest FAIL lines like: FAIL tests/unit/foo.test.ts > should work */\nconst TEST_FILE_REGEX = /(?:FAIL|❌)\\s+(\\S+\\.(?:test|spec)\\.\\w+)/g\n\n/** Matches eslint file paths from output like: /path/to/src/foo.ts */\nconst LINT_FILE_REGEX = /^(\\/\\S+\\.(?:ts|tsx|js|jsx))$/gm\n\n/** Matches prettier [warn] lines with file paths */\nconst FORMAT_FILE_REGEX = /\\[warn\\]\\s+(\\S+\\.\\w+)/g\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Extract specific test details for smarter autofix guidance\n */\nfunction extractTestDetails(rawOutput: string): { summary?: string; specificFix?: string } {\n // Extract test names\n const testNameMatch = rawOutput.match(/(?:FAIL|❌).*?>\\s*(.+)$/m)\n const testName = testNameMatch?.[1]?.trim()\n\n // Extract expected vs actual\n const expectedMatch = rawOutput.match(/Expected:?\\s*(.+)/i)\n const actualMatch = rawOutput.match(/Actual:?\\s*(.+)/i)\n\n // Check for common fixable errors\n let specificFix: string | undefined\n\n if (rawOutput.includes('Cannot find module')) {\n const moduleMatch = rawOutput.match(/Cannot find module ['\"]([^'\"]+)['\"]/)\n const moduleName = moduleMatch?.[1]\n if (moduleName) {\n specificFix =\n \"Missing import: Install '\" + moduleName + \"' or add to package.json dependencies.\"\n }\n }\n\n if (rawOutput.includes('is not defined') || rawOutput.includes('is not declared')) {\n specificFix =\n 'Reference error: The variable/function is not defined. Check imports or declare the variable.'\n }\n\n if (rawOutput.includes('is not a function') || rawOutput.includes('is not a constructor')) {\n specificFix = 'Type error: Check the import - may need .default or the export name is wrong.'\n }\n\n if (rawOutput.includes('TypeError') && rawOutput.includes('undefined')) {\n specificFix =\n 'Undefined error: Check if variable is initialized before use, or if property exists.'\n }\n\n if (rawOutput.includes('expected') && rawOutput.includes('received')) {\n specificFix =\n 'Assertion mismatch: Update source code to match expected behavior, OR if test is wrong, fix the test.'\n }\n\n if (rawOutput.includes('timeout') || rawOutput.includes('Timed out')) {\n specificFix =\n 'Test timeout: The test or the code it tests is too slow. Consider increasing timeout or optimizing.'\n }\n\n if (rawOutput.includes('ENOENT') || rawOutput.includes('No such file')) {\n specificFix =\n 'Missing file: The test references a file that does not exist. Check the path or create the file.'\n }\n\n // Build summary with test name if found\n let summary: string | undefined\n if (testName) {\n summary = 'Test: ' + testName\n if (expectedMatch && actualMatch) {\n summary += ' | Expected: ' + expectedMatch[1].trim() + ' | Actual: ' + actualMatch[1].trim()\n }\n }\n\n return { summary, specificFix }\n}\n\n/**\n * Classify a raw error output string into a structured error object.\n *\n * @param rawOutput - The raw stderr/stdout from the failed command\n * @param source - What generated this output: 'tsc', 'test', 'lint', 'format'\n */\nexport function classifyError(rawOutput: string, source: string): ClassifiedError {\n if (!rawOutput || rawOutput.trim().length === 0) {\n return {\n category: 'unknown',\n summary: 'Empty error output',\n fullOutput: '',\n fileHints: [],\n fixInstructions: FIX_INSTRUCTIONS.unknown,\n }\n }\n\n const truncatedOutput =\n rawOutput.length > MAX_OUTPUT_LENGTH ? rawOutput.slice(0, MAX_OUTPUT_LENGTH) : rawOutput\n\n const summary =\n rawOutput.length > MAX_SUMMARY_LENGTH ? rawOutput.slice(0, MAX_SUMMARY_LENGTH) : rawOutput\n\n switch (source) {\n case 'tsc': {\n const fileHints = extractUniqueFiles(rawOutput, TSC_FILE_REGEX)\n return {\n category: 'type_error',\n summary,\n fullOutput: truncatedOutput,\n fileHints,\n fixInstructions: FIX_INSTRUCTIONS.type_error,\n }\n }\n\n case 'test': {\n const fileHints = extractUniqueFiles(rawOutput, TEST_FILE_REGEX)\n\n // Extract specific test details for better autofix guidance\n const testDetails = extractTestDetails(rawOutput)\n const fixInstructions = testDetails.specificFix\n ? testDetails.specificFix\n : FIX_INSTRUCTIONS.test_failure\n\n return {\n category: 'test_failure',\n summary: testDetails.summary || summary,\n fullOutput: truncatedOutput,\n fileHints,\n fixInstructions,\n }\n }\n\n case 'lint': {\n const fileHints = extractUniqueFiles(rawOutput, LINT_FILE_REGEX)\n return {\n category: 'lint_error',\n summary,\n fullOutput: truncatedOutput,\n fileHints,\n fixInstructions: FIX_INSTRUCTIONS.lint_error,\n }\n }\n\n case 'format': {\n const fileHints = extractUniqueFiles(rawOutput, FORMAT_FILE_REGEX)\n return {\n category: 'format_error',\n summary,\n fullOutput: truncatedOutput,\n fileHints,\n fixInstructions: FIX_INSTRUCTIONS.format_error,\n }\n }\n\n default: {\n return {\n category: 'unknown',\n summary,\n fullOutput: truncatedOutput,\n fileHints: [],\n fixInstructions: FIX_INSTRUCTIONS.unknown,\n }\n }\n }\n}\n\n/**\n * Format an array of classified errors into a markdown document for the autofix agent.\n *\n * @param errors - Array of classified errors from failed quality gates\n * @param attempt - Current attempt number (1-indexed)\n * @param maxAttempts - Maximum number of autofix attempts\n */\nexport function formatErrorsAsMarkdown(\n errors: ClassifiedError[],\n attempt: number,\n maxAttempts: number,\n): string {\n const sections = errors.map((error, i) => {\n const fileList =\n error.fileHints.length > 0\n ? '\\n**Affected Files**:\\n' + error.fileHints.map((f) => '- `' + f + '`').join('\\n')\n : ''\n\n return (\n '## Error ' +\n (i + 1) +\n ': ' +\n error.category +\n '\\n\\n' +\n '**Fix Instructions**: ' +\n error.fixInstructions +\n '\\n' +\n fileList +\n '\\n\\n' +\n '**Error Output**:\\n' +\n '```\\n' +\n error.fullOutput +\n '```\\n'\n )\n })\n\n return (\n '# Build Errors\\n\\n' +\n 'Attempt ' +\n attempt +\n '/' +\n maxAttempts +\n '. Fix the errors below and the quality gates will be re-run.\\n\\n' +\n sections.join('\\n---\\n\\n')\n )\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Extract unique file paths from a string using a regex.\n * The regex must have a capture group for the file path.\n */\nfunction extractUniqueFiles(text: string, regex: RegExp): string[] {\n const files = new Set<string>()\n let match: RegExpExecArray | null\n\n // Reset regex state (global regexes are stateful)\n regex.lastIndex = 0\n\n while ((match = regex.exec(text)) !== null) {\n if (match[1]) {\n files.add(match[1])\n }\n }\n\n return Array.from(files)\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Quality gate lifecycle events — runs tsc, unit tests, and autofix feedback loops.\n * Also includes mechanical autofix (lint:fix + format:fix).\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { execFileSync } from 'child_process'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext, PostAction, PipelineStateV2 } from '../../engine/types'\nimport { updateStage, writeState } from '../../engine/status'\nimport { classifyError, formatErrorsAsMarkdown } from '../error-classifier'\nimport { runAgentWithFileWatch } from '../../agent-runner'\nimport { getStageTimeout } from '../../stages/registry'\n\nexport async function executeRunTsc(ctx: PipelineContext): Promise<void> {\n if (ctx.input.dryRun) return\n\n logger.info(' Running tsc...')\n try {\n execFileSync('pnpm', ['-s', 'tsc', '--noEmit'], {\n encoding: 'utf-8',\n maxBuffer: 10 * 1024 * 1024,\n })\n logger.info(' ✓ tsc passed')\n } catch (error) {\n const err = error as { stdout?: string; stderr?: string; message?: string }\n const output = (err.stdout || '') + (err.stderr || '') || err.message || ''\n throw new Error(`TypeScript compilation failed:\\n${output.slice(0, 3000)}`)\n }\n}\n\nexport async function executeRunUnitTests(ctx: PipelineContext): Promise<void> {\n if (ctx.input.dryRun) return\n\n logger.info(' Running unit tests...')\n try {\n execFileSync('pnpm', ['-s', 'test:unit'], {\n encoding: 'utf-8',\n maxBuffer: 10 * 1024 * 1024,\n })\n logger.info(' ✓ Unit tests passed')\n } catch (error) {\n // G25: Include output text (3000 chars) for supervisor retry\n const err = error as { stdout?: string; stderr?: string; message?: string }\n const output = (err.stdout || '') + (err.stderr || '') + (err.message || '')\n throw new Error(`Unit tests failed after build. Fix and re-run.\\n\\n${output.slice(0, 3000)}`)\n }\n}\n\nexport async function executeRunQualityWithAutofix(\n ctx: PipelineContext,\n action: PostAction & { type: 'run-quality-with-autofix' },\n state: PipelineStateV2 | null,\n): Promise<void> {\n if (ctx.input.dryRun) return\n\n type GateResult = {\n name: string\n command: string\n source: 'tsc' | 'lint' | 'format' | 'test'\n passed: boolean\n error?: string\n }\n\n // Helper: split a simple shell command into program + args for execFileSync\n const parseCommand = (cmd: string): { program: string; args: string[] } => {\n const parts = cmd.split(/\\s+/).filter(Boolean)\n return { program: parts[0], args: parts.slice(1) }\n }\n\n const runGates = (gates: typeof action.gates): GateResult[] => {\n return gates.map((gate) => {\n try {\n logger.info(` Running ${gate.name}...`)\n const { program, args } = parseCommand(gate.command)\n execFileSync(program, args, {\n stdio: 'pipe',\n timeout: 5 * 60 * 1000, // 5 minutes per gate\n maxBuffer: 10 * 1024 * 1024, // 10MB buffer\n })\n logger.info(` ✓ ${gate.name} passed`)\n return { ...gate, passed: true }\n } catch (error) {\n const err = error as {\n stdout?: Buffer | string\n stderr?: Buffer | string\n message?: string\n }\n const stdout = err.stdout\n ? Buffer.isBuffer(err.stdout)\n ? err.stdout.toString()\n : err.stdout\n : ''\n const stderr = err.stderr\n ? Buffer.isBuffer(err.stderr)\n ? err.stderr.toString()\n : err.stderr\n : ''\n const output = stdout + stderr + (err.message || '')\n logger.info(` ✗ ${gate.name} failed`)\n const truncated = output.slice(-2000).trim()\n if (truncated) {\n logger.info(` Error output (last 2000 chars):\\n${truncated}`)\n }\n return { ...gate, passed: false, error: output }\n }\n })\n }\n\n // Initial run — all gates\n let results = runGates(action.gates)\n let failures = results.filter((r) => !r.passed)\n\n if (failures.length === 0) return // All passed on first try\n\n // Track feedback loop metrics for status.json observability\n let completedLoops = 0\n const encounteredErrors = new Set<string>()\n\n // Build agent feedback loop — the build agent wrote the code, so it fixes\n // ALL failures (tsc, lint, format, tests). No separate autofix agent needed\n // here because the build agent has full context (spec, plan, code intent).\n for (let attempt = 1; attempt <= action.maxFeedbackLoops; attempt++) {\n logger.info(\n `\\n🔧 Build agent fix attempt ${attempt}/${action.maxFeedbackLoops} (${failures.map((f) => f.name).join(', ')})...`,\n )\n\n // Classify errors and write build-errors.md for the build agent to read\n const errors = failures.map((f) => classifyError(f.error || '', f.source))\n errors.forEach((e) => encounteredErrors.add(e.category))\n completedLoops = attempt\n const markdown = formatErrorsAsMarkdown(errors, attempt, action.maxFeedbackLoops)\n const errorsFile = path.join(ctx.taskDir, 'build-errors.md')\n fs.writeFileSync(errorsFile, markdown)\n\n // Re-invoke the build agent — it has spec, plan, and wrote the code\n const buildOutput = path.join(ctx.taskDir, 'build.md')\n const buildTimeout = getStageTimeout('build')\n let buildResult: { succeeded: boolean } | undefined\n try {\n buildResult = await runAgentWithFileWatch(ctx.input, 'build', buildOutput, buildTimeout, {\n backend: ctx.backend,\n })\n } catch (agentError) {\n logger.error(\n { err: agentError },\n ` ❌ Build agent threw exception (fix attempt ${attempt}/${action.maxFeedbackLoops})`,\n )\n continue\n }\n\n if (!buildResult?.succeeded) {\n logger.error(` ❌ Build agent failed (fix attempt ${attempt})`)\n continue\n }\n\n // Re-run ALL gates after build agent changes\n results = runGates(action.gates)\n failures = results.filter((r) => !r.passed)\n\n if (failures.length === 0) {\n logger.info(` ✅ All quality gates passed after build agent fix attempt ${attempt}`)\n if (fs.existsSync(errorsFile)) fs.unlinkSync(errorsFile)\n break\n }\n }\n\n // Record feedback loop metrics in status.json for observability\n if (completedLoops > 0) {\n const currentState = state\n if (currentState && currentState.stages?.build) {\n const updatedState = updateStage(currentState, 'build', {\n feedbackLoops: completedLoops,\n feedbackErrors: Array.from(encounteredErrors),\n })\n writeState(ctx.taskId, updatedState)\n }\n }\n\n if (failures.length > 0) {\n const errorsFile = path.join(ctx.taskDir, 'build-errors.md')\n if (fs.existsSync(errorsFile)) fs.unlinkSync(errorsFile)\n const failedNames = failures.map((f) => f.name).join(', ')\n throw new Error(\n `Quality gates failed after ${action.maxFeedbackLoops} build agent fix attempts: ${failedNames}`,\n )\n }\n}\n\nexport async function executeRunMechanicalAutofix(ctx: PipelineContext): Promise<void> {\n // Run lint:fix + format:fix deterministically — no LLM needed for mechanical fixes.\n // This prevents trivial format/lint failures from reaching verify stage.\n if (ctx.input.dryRun) return\n\n logger.info(' 🔧 Running mechanical auto-fix (lint:fix + format:fix)...')\n\n try {\n execFileSync('pnpm', ['lint:fix'], {\n stdio: 'pipe',\n timeout: 2 * 60 * 1000, // 2 minutes\n maxBuffer: 10 * 1024 * 1024,\n })\n logger.info(' ✓ lint:fix completed')\n } catch {\n logger.info(' ✗ lint:fix had errors (some may need manual fix)')\n }\n\n try {\n execFileSync('pnpm', ['format:fix'], {\n stdio: 'pipe',\n timeout: 2 * 60 * 1000, // 2 minutes\n maxBuffer: 10 * 1024 * 1024,\n })\n logger.info(' ✓ format:fix completed')\n } catch {\n logger.info(' ✗ format:fix had errors (some may need manual fix)')\n }\n\n logger.info(' ✅ Mechanical auto-fix complete')\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Analyzes review.md findings to determine if fix stage is needed\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext, PipelineStateV2 } from '../../engine/types'\nimport { updateStage, writeState } from '../../engine/status'\n\nexport async function executeAnalyzeReviewFindings(\n ctx: PipelineContext,\n state: PipelineStateV2 | null,\n): Promise<void> {\n const reviewPath = path.join(ctx.taskDir, 'review.md')\n\n let fixNeeded = false\n const reviewSummary = { critical: 0, major: 0, minor: 0 }\n\n if (fs.existsSync(reviewPath)) {\n const reviewContent = fs.readFileSync(reviewPath, 'utf-8')\n const contentLower = reviewContent.toLowerCase()\n\n // Parse review findings with multiple robust patterns\n // Pattern 1: \"Critical: N\" or \"Critical Issues: N\" or \"**Critical**: N\"\n const criticalPatterns = [/critical[^:]*:\\s*(\\d+)/i, /(\\d+)[ \\t]+critical/i]\n // Pattern 2: \"Major: N\" or \"Major Issues: N\" or \"**Major**: N\"\n const majorPatterns = [/major[^:]*:\\s*(\\d+)/i, /(\\d+)[ \\t]+major/i]\n // Pattern 3: \"Minor: N\"\n const minorPatterns = [/minor[^:]*:\\s*(\\d+)/i, /(\\d+)[ \\t]+minor/i]\n\n for (const pat of criticalPatterns) {\n const match = reviewContent.match(pat)\n if (match) {\n reviewSummary.critical = Math.max(reviewSummary.critical, parseInt(match[1]))\n }\n }\n for (const pat of majorPatterns) {\n const match = reviewContent.match(pat)\n if (match) {\n reviewSummary.major = Math.max(reviewSummary.major, parseInt(match[1]))\n }\n }\n for (const pat of minorPatterns) {\n const match = reviewContent.match(pat)\n if (match) {\n reviewSummary.minor = Math.max(reviewSummary.minor, parseInt(match[1]))\n }\n }\n\n // Check for explicit fix-required indicators\n const fixRequiredMatch =\n reviewContent.match(/fix\\s*required[^\\n]*\\[\\s*x\\s*\\]/i) ||\n reviewContent.match(/\\[\\s*x\\s*\\][^\\n]*fix\\s*required/i) ||\n reviewContent.match(/fix\\s*required[^\\n]*yes/i)\n\n // Also check for issue-indicating keywords as fallback\n const hasIssueKeywords =\n contentLower.includes('must fix') ||\n contentLower.includes('needs fix') ||\n contentLower.includes('should fix') ||\n contentLower.includes('bug found') ||\n contentLower.includes('security issue') ||\n contentLower.includes('vulnerability')\n\n fixNeeded =\n reviewSummary.critical > 0 ||\n reviewSummary.major > 0 ||\n fixRequiredMatch !== null ||\n hasIssueKeywords\n }\n\n // In fix mode, always set fixNeeded to true — user explicitly asked for fixes\n if (ctx.input.mode === 'fix') {\n fixNeeded = true\n }\n\n // Update state to track findings\n if (state) {\n const updatedState = updateStage(state, 'review', {\n issuesFound: fixNeeded,\n reviewSummary,\n })\n writeState(ctx.taskId, updatedState)\n }\n\n logger.info(\n ` Review findings: ${reviewSummary.critical} critical, ${reviewSummary.major} major, fixNeeded=${fixNeeded}`,\n )\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Build/source validation post-actions — validates plan exists,\n * build content has required sections, and build agent modified source files\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { execFileSync } from 'child_process'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext } from '../../engine/types'\n\nexport async function executeValidatePlanExists(ctx: PipelineContext): Promise<void> {\n const planFile = path.join(ctx.taskDir, 'plan.md')\n const gapFile = path.join(ctx.taskDir, 'gap.md')\n\n if (!fs.existsSync(planFile)) {\n throw new Error('plan.md not found - gap agent may have deleted it')\n }\n\n const gapContent = fs.existsSync(gapFile) ? fs.readFileSync(gapFile, 'utf-8') : ''\n\n // Basic validation - check for expected sections\n if (!gapContent.includes('## ') && !gapContent.includes('No gaps identified')) {\n throw new Error('gap.md must contain ## sections or \"No gaps identified\"')\n }\n}\n\nexport async function executeValidateBuildContent(ctx: PipelineContext): Promise<void> {\n const buildFile = path.join(ctx.taskDir, 'build.md')\n if (!fs.existsSync(buildFile)) {\n throw new Error('build.md not found')\n }\n\n const buildContent = fs.readFileSync(buildFile, 'utf-8')\n\n // Check for required sections\n if (!buildContent.includes('## Changes') && !buildContent.includes('## Files')) {\n throw new Error('build.md must contain ## Changes or ## Files section')\n }\n}\n\nexport async function executeValidateSrcChanges(ctx: PipelineContext): Promise<void> {\n if (ctx.input.dryRun) return\n\n // Check that the build agent actually modified source files, not just .tasks/\n let diff = ''\n let untracked = ''\n let gitFailed = false\n try {\n diff = execFileSync('git', ['diff', '--name-only'], { encoding: 'utf-8' }).trim()\n } catch (error) {\n logger.error({ err: error }, 'git diff failed during src validation')\n gitFailed = true\n }\n try {\n untracked = execFileSync('git', ['ls-files', '--others', '--exclude-standard'], {\n encoding: 'utf-8',\n }).trim()\n } catch (error) {\n logger.error({ err: error }, 'git ls-files failed during src validation')\n gitFailed = true\n }\n\n if (gitFailed) {\n throw new Error(\n 'validate-src-changes: git commands failed — cannot verify source changes. Check git state.',\n )\n }\n\n const allChanged = [...diff.split('\\n'), ...untracked.split('\\n')]\n .filter(Boolean)\n .filter((f) => !f.startsWith('.tasks/'))\n\n if (allChanged.length === 0) {\n throw new Error(\n 'Build agent wrote build.md but did NOT modify any source files. ' +\n 'The agent must use Edit/Write tools to implement actual code changes, not just document them in build.md.',\n )\n }\n\n logger.info(` ✓ ${allChanged.length} source file(s) changed by build agent`)\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline | post-action\n * @pattern knowledge-base | learning\n * @ai-summary Updates the cross-task knowledge base with patterns learned from completed tasks\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext, PipelineStateV2 } from '../../engine/types'\nimport { loadState } from '../../engine/status'\nimport { readTask } from '../../pipeline-utils'\nimport type { TaskDefinition } from '../task-schema'\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface KnowledgeEntry {\n taskId: string\n date: string\n domain: string\n taskType: string\n complexity: number\n patterns: string[]\n summary: string\n feedbackLoops?: number\n errorPatterns?: string[]\n}\n\ninterface KnowledgeBase {\n version: number\n description: string\n entries: KnowledgeEntry[]\n patternFrequency: Record<string, number>\n skillsCreated: string[]\n lastUpdated: string\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst KNOWLEDGE_BASE_PATH = '.tasks/knowledge/index.json'\nconst MAX_KNOWLEDGE_ENTRIES = 100\n\n// Pattern detection keywords (detected in scope text)\nconst PATTERN_KEYWORDS: Record<string, string[]> = {\n 'type-error': ['typescript', 'type', 'interface', 'type error'],\n 'lint-error': ['lint', 'eslint', 'prettier'],\n 'format-error': ['format', 'prettier', 'indentation'],\n 'test-failure': ['test', 'vitest', 'assertion', 'expected'],\n 'css-styling': ['tailwind', 'css', 'className', 'style'],\n 'frontend-bugfix': ['ui', 'component', 'render', 'state'],\n 'api-design': ['endpoint', 'route', 'request', 'response'],\n 'data-modeling': ['collection', 'schema', 'field', 'relationship'],\n performance: ['optimize', 'cache', 'lazy', 'memo'],\n security: ['auth', 'sanitize', 'validate', 'permission'],\n hook: ['hook', 'beforeChange', 'afterChange', 'beforeValidate'],\n 'access-control': ['access', 'permission', 'isAdmin', 'isOwner'],\n}\n\n// ============================================================================\n// Helper: Detect patterns from task scope and error data\n// ============================================================================\n\nfunction detectPatterns(\n taskDef: TaskDefinition,\n errorPatterns: string[],\n feedbackLoops: number,\n): string[] {\n const patterns: string[] = []\n\n // Detect from task scope (array of scope items joined)\n const scopeText = (taskDef.scope || []).join(' ').toLowerCase()\n const typeText = taskDef.task_type.toLowerCase()\n\n for (const [pattern, keywords] of Object.entries(PATTERN_KEYWORDS)) {\n if (keywords.some((kw) => scopeText.includes(kw) || typeText.includes(kw))) {\n patterns.push(pattern)\n }\n }\n\n // Add error patterns that were encountered\n for (const error of errorPatterns) {\n const normalized = error.toLowerCase()\n if (normalized.includes('type') || normalized.includes('ts')) {\n patterns.push('type-error')\n }\n if (normalized.includes('lint') || normalized.includes('eslint')) {\n patterns.push('lint-error')\n }\n if (normalized.includes('format') || normalized.includes('prettier')) {\n patterns.push('format-error')\n }\n if (normalized.includes('test') || normalized.includes('vitest')) {\n patterns.push('test-failure')\n }\n }\n\n // If feedback loops were needed, mark as needing iteration\n if (feedbackLoops > 0) {\n patterns.push('iterative-fix')\n }\n\n // Deduplicate\n return [...new Set(patterns)]\n}\n\n// ============================================================================\n// Helper: Load existing knowledge base\n// ============================================================================\n\nfunction loadKnowledgeBase(): KnowledgeBase {\n const kbPath = path.join(process.cwd(), KNOWLEDGE_BASE_PATH)\n\n if (!fs.existsSync(kbPath)) {\n return {\n version: 1,\n description:\n 'Cross-task knowledge base for Kody pipeline self-learning. Updated by the pipeline after each task completion.',\n entries: [],\n patternFrequency: {},\n skillsCreated: [],\n lastUpdated: new Date().toISOString(),\n }\n }\n\n try {\n const data = fs.readFileSync(kbPath, 'utf-8')\n return JSON.parse(data) as KnowledgeBase\n } catch (err) {\n logger.warn({ err }, 'Failed to load knowledge base, starting fresh')\n return {\n version: 1,\n description: 'Cross-task knowledge base for Kody pipeline self-learning.',\n entries: [],\n patternFrequency: {},\n skillsCreated: [],\n lastUpdated: new Date().toISOString(),\n }\n }\n}\n\n// ============================================================================\n// Helper: Save knowledge base\n// ============================================================================\n\nfunction saveKnowledgeBase(kb: KnowledgeBase): void {\n const kbPath = path.join(process.cwd(), KNOWLEDGE_BASE_PATH)\n const dir = path.dirname(kbPath)\n\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n\n kb.lastUpdated = new Date().toISOString()\n fs.writeFileSync(kbPath, JSON.stringify(kb, null, 2), 'utf-8')\n logger.info(` 📚 Updated knowledge base with ${kb.entries.length} entries`)\n}\n\n// ============================================================================\n// Main: Execute knowledge base update\n// ============================================================================\n\n/**\n * Post-action that updates the cross-task knowledge base after task completion.\n *\n * This captures:\n * - Task domain and type\n * - Complexity score\n * - Patterns detected (from scope and error patterns)\n * - Feedback loops needed (indicates difficulty)\n * - Error patterns encountered\n *\n * The knowledge base is read by the architect stage to inform planning.\n */\nexport async function executeUpdateKnowledgeBase(\n ctx: PipelineContext,\n _state: PipelineStateV2 | null,\n): Promise<void> {\n if (ctx.input.dryRun) {\n logger.info(' ℹ️ Dry run, skipping knowledge base update')\n return\n }\n\n logger.info(' 📚 Updating knowledge base...')\n\n try {\n // Load task definition\n const taskDef = readTask(ctx.taskDir)\n if (!taskDef) {\n logger.warn(' ⚠️ No task definition found, skipping knowledge base update')\n return\n }\n\n // Load pipeline state for metrics\n const state = loadState(ctx.taskId)\n const buildStage = state?.stages?.build\n\n // Extract error patterns from verify failures if they exist\n let errorPatterns: string[] = []\n const verifyFailuresPath = path.join(ctx.taskDir, 'verify-failures.md')\n if (fs.existsSync(verifyFailuresPath)) {\n const content = fs.readFileSync(verifyFailuresPath, 'utf-8')\n // Extract error categories from the failures file\n const errorMatches = content.match(/##\\s+Error\\s+\\d+:\\s+(\\S+)/g) || []\n errorPatterns = errorMatches.map((m) => m.replace(/##\\s+Error\\s+\\d+:\\s+/, ''))\n }\n\n // Detect patterns\n const patterns = detectPatterns(taskDef, errorPatterns, buildStage?.feedbackLoops || 0)\n\n // Create knowledge entry\n const entry: KnowledgeEntry = {\n taskId: ctx.taskId,\n date: new Date().toISOString(),\n domain: taskDef.primary_domain,\n taskType: taskDef.task_type,\n complexity: taskDef.complexity || 0,\n patterns,\n summary: taskDef.scope?.slice(0, 3).join(', ') || 'No scope',\n feedbackLoops: buildStage?.feedbackLoops,\n errorPatterns: errorPatterns.length > 0 ? errorPatterns : undefined,\n }\n\n // Load and update knowledge base\n const kb = loadKnowledgeBase()\n\n // Check for duplicate entry (same taskId)\n const existingIndex = kb.entries.findIndex((e) => e.taskId === ctx.taskId)\n if (existingIndex >= 0) {\n // Update existing entry\n kb.entries[existingIndex] = entry\n logger.info(` 📝 Updated existing knowledge entry for ${ctx.taskId}`)\n } else {\n // Add new entry\n kb.entries.push(entry)\n logger.info(` ✅ Added new knowledge entry for ${ctx.taskId}`)\n }\n\n // Trim entries if too many\n if (kb.entries.length > MAX_KNOWLEDGE_ENTRIES) {\n kb.entries = kb.entries.slice(-MAX_KNOWLEDGE_ENTRIES)\n logger.info(` ℹ️ Trimmed knowledge base to ${MAX_KNOWLEDGE_ENTRIES} entries`)\n }\n\n // Update pattern frequency\n for (const pattern of patterns) {\n kb.patternFrequency[pattern] = (kb.patternFrequency[pattern] || 0) + 1\n }\n\n // Save updated knowledge base\n saveKnowledgeBase(kb)\n\n logger.info(\n ` ✅ Knowledge base updated: domain=${taskDef.primary_domain}, patterns=[${patterns.join(', ')}], feedbackLoops=${buildStage?.feedbackLoops || 0}`,\n )\n } catch (err) {\n // Non-fatal — log and continue\n logger.warn({ err }, 'Failed to update knowledge base, continuing pipeline')\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-actions\n * @ai-summary Post-stage action dispatcher — routes to focused modules.\n * Small/simple actions remain inlined here; larger actions are in separate files.\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext, PostAction, PipelineStateV2 } from '../../engine/types'\nimport { PipelinePausedError, isBlockingPostAction } from '../../engine/types'\n\n// Focused modules\nimport { executeValidateTaskJson } from './validate-task-json'\nimport { executeSetClassificationLabels } from './classification'\nimport { executeResolveProfile } from './resolve-profile'\nimport { executeCheckGate } from './gate'\nimport { executeCommitTaskFiles } from './commit'\nimport {\n executeRunTsc,\n executeRunUnitTests,\n executeRunQualityWithAutofix,\n executeRunMechanicalAutofix,\n} from './quality'\nimport { executeAnalyzeReviewFindings } from './review'\nimport {\n executeValidatePlanExists,\n executeValidateBuildContent,\n executeValidateSrcChanges,\n} from './validators'\nimport { executeUpdateKnowledgeBase } from './knowledge-base'\n\n/**\n * Execute a post-action by dispatching to the appropriate module\n */\nexport async function executePostAction(\n ctx: PipelineContext,\n action: PostAction,\n _state: PipelineStateV2 | null,\n): Promise<void> {\n switch (action.type) {\n case 'validate-task-json':\n return executeValidateTaskJson(ctx)\n\n case 'set-classification-labels':\n return executeSetClassificationLabels(ctx)\n\n case 'resolve-profile':\n return executeResolveProfile(ctx)\n\n case 'check-gate':\n return executeCheckGate(ctx, action as PostAction & { type: 'check-gate' }, _state)\n\n case 'commit-task-files':\n return executeCommitTaskFiles(ctx, action as PostAction & { type: 'commit-task-files' })\n\n case 'validate-plan-exists':\n return executeValidatePlanExists(ctx)\n\n case 'validate-build-content':\n return executeValidateBuildContent(ctx)\n\n case 'validate-src-changes':\n return executeValidateSrcChanges(ctx)\n\n case 'run-tsc':\n return executeRunTsc(ctx)\n\n case 'run-unit-tests':\n return executeRunUnitTests(ctx)\n\n case 'run-quality-with-autofix':\n return executeRunQualityWithAutofix(\n ctx,\n action as PostAction & { type: 'run-quality-with-autofix' },\n _state,\n )\n\n case 'run-mechanical-autofix':\n return executeRunMechanicalAutofix(ctx)\n\n case 'analyze-review-findings':\n return executeAnalyzeReviewFindings(ctx, _state)\n\n // Small actions inlined — not worth separate files\n case 'archive-rerun-feedback': {\n const rerunFeedbackPath = path.join(ctx.taskDir, 'rerun-feedback.md')\n if (fs.existsSync(rerunFeedbackPath)) {\n const consumed = path.join(ctx.taskDir, 'rerun-feedback.consumed.md')\n fs.renameSync(rerunFeedbackPath, consumed)\n logger.info(' Consumed rerun-feedback.md')\n }\n break\n }\n\n case 'clear-verify-failures': {\n const verifyFailuresPath = path.join(ctx.taskDir, 'verify-failures.md')\n if (fs.existsSync(verifyFailuresPath)) {\n fs.unlinkSync(verifyFailuresPath)\n logger.info(' Cleared verify-failures.md')\n }\n break\n }\n\n case 'update-knowledge-base':\n return executeUpdateKnowledgeBase(ctx, _state)\n\n case 'parallel': {\n if (!('actions' in action) || !Array.isArray((action as { actions?: unknown }).actions)) {\n throw new Error(`'parallel' post-action missing required 'actions' array`)\n }\n const parallelActions = (action as { actions: PostAction[] }).actions\n logger.info(` Running ${parallelActions.length} actions in parallel...`)\n\n // Timeout wrapper to prevent hanging on slow post-actions\n const PARALLEL_POST_ACTION_TIMEOUT_MS = 60_000 // 60 seconds\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(\n () =>\n reject(\n new Error(\n `Parallel post-actions exceeded ${PARALLEL_POST_ACTION_TIMEOUT_MS / 1000}s timeout`,\n ),\n ),\n PARALLEL_POST_ACTION_TIMEOUT_MS,\n )\n })\n\n const results = await Promise.race([\n Promise.allSettled(\n parallelActions.map(async (a) => {\n await executePostAction(ctx, a, _state)\n }),\n ),\n timeoutPromise,\n ])\n\n // Check for PipelinePausedError first — re-throw it directly to preserve the type\n const pauseResult = results.find(\n (r): r is PromiseRejectedResult =>\n r.status === 'rejected' && r.reason instanceof PipelinePausedError,\n )\n if (pauseResult) {\n throw pauseResult.reason\n }\n\n // Classify failures into blocking vs advisory\n const failures = results.filter((r): r is PromiseRejectedResult => r.status === 'rejected')\n if (failures.length > 0) {\n // Check if any blocking actions failed\n const blockingFailures: { action: PostAction; error: string }[] = []\n const advisoryFailures: { action: PostAction; error: string }[] = []\n\n for (let i = 0; i < results.length; i++) {\n const result = results[i]\n if (result.status === 'rejected') {\n const action = parallelActions[i]\n const err =\n result.reason instanceof Error ? result.reason.message : String(result.reason)\n if (isBlockingPostAction(action)) {\n blockingFailures.push({ action, error: err })\n } else {\n advisoryFailures.push({ action, error: err })\n }\n }\n }\n\n // Log advisory failures as warnings (don't fail the pipeline)\n for (const { action, error } of advisoryFailures) {\n logger.warn({ actionType: action.type }, ` Advisory post-action failed: ${error}`)\n }\n\n // Throw only if blocking actions failed\n if (blockingFailures.length > 0) {\n const errors = blockingFailures.map((f) => f.error).join('; ')\n throw new Error(`Parallel post-actions failed (blocking): ${errors}`)\n }\n }\n logger.info(` ✅ All ${parallelActions.length} parallel actions completed`)\n break\n }\n\n default:\n throw new Error(\n `Unknown post-action type: \"${(action as PostAction).type}\". This is a configuration bug.`,\n )\n }\n}\n","/**\n * @fileType observer\n * @domain kody | pipeline | observer\n * @pattern observer\n * @ai-summary Pipeline Observer - delegates complex failures to OpenCode agent\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { logger } from '../../logger'\nimport { createRunner, type RunnerBackend } from '../../runner-backend'\nimport type { StageName } from '../../stages/registry'\nimport {\n type StageFailure,\n type ObserverResult,\n type ObserverDecision,\n type ObserverContext,\n} from './types'\nimport { updateStage, loadState, writeState } from '../../engine/status'\nimport type { PipelineStateV2 } from '../../engine/types'\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst MAX_OBSERVER_ATTEMPTS = 1\nconst OBSERVER_TIMEOUT_MS = 120_000 // 120 seconds\n\n// ============================================================================\n// Observer Class\n// ============================================================================\n\nexport class PipelineObserver {\n private readonly backend: RunnerBackend\n\n constructor(\n private readonly taskId: string,\n private readonly taskDir: string,\n private readonly serverUrl: string,\n private readonly sessionId: string,\n private readonly dataDir: string,\n ) {\n this.backend = createRunner()\n }\n\n /**\n * Handle a stage failure by delegating to the same OpenCode agent.\n * Pipeline is PAUSED while we wait for the agent to decide.\n */\n async handle(failure: StageFailure): Promise<ObserverResult> {\n const observerAttempt = this.getObserverAttempt(failure)\n\n // Check recursion cap\n if (observerAttempt > MAX_OBSERVER_ATTEMPTS) {\n logger.info(`[Observer] Max attempts (${MAX_OBSERVER_ATTEMPTS}) exceeded, auto-escalating`)\n return this.autoEscalate(failure, 'Max Observer attempts exceeded')\n }\n\n logger.info(\n `[Observer] Handling failure for stage '${failure.stageName}' (Observer attempt ${observerAttempt}/${MAX_OBSERVER_ATTEMPTS})`,\n )\n\n // Mark stage as observing\n const state = loadState(this.taskId)\n if (state) {\n const updatedState = updateStage(state, failure.stageName, {\n state: 'observing',\n error: `Observer handling: ${failure.error.message}`,\n })\n writeState(this.taskId, updatedState)\n }\n\n // Delegate to agent with timeout\n try {\n const result = await this.withTimeout(\n this.delegateToAgent(failure, observerAttempt),\n OBSERVER_TIMEOUT_MS,\n )\n\n // Log decision\n this.logDecision(failure, result, observerAttempt)\n\n return { ...result, observerAttempt }\n } catch (error) {\n logger.error({ err: error }, `[Observer] Error during agent delegation`)\n\n // Timeout or error - auto-escalate\n const reason = error instanceof Error ? error.message : 'Unknown error'\n return this.autoEscalate(failure, reason)\n }\n }\n\n /**\n * Delegate failure handling to the same OpenCode agent that ran the stage.\n */\n private async delegateToAgent(\n failure: StageFailure,\n observerAttempt: number,\n ): Promise<ObserverResult> {\n // Write context file for the agent to read\n const contextFile = path.join(this.taskDir, '.observer-context.json')\n const context: ObserverContext = {\n stageName: failure.stageName,\n error: {\n message: failure.error.message,\n stack: failure.error.stack,\n },\n attempt: failure.attempt,\n maxAttempts: failure.maxAttempts,\n taskDir: this.taskDir,\n observerAttempt,\n }\n fs.writeFileSync(contextFile, JSON.stringify(context, null, 2))\n\n // Decision file path\n const decisionFile = path.join(this.taskDir, '.observer-decision.json')\n\n // Delete any existing decision file\n if (fs.existsSync(decisionFile)) {\n fs.unlinkSync(decisionFile)\n }\n\n // Build the prompt for the agent\n const prompt = this.buildFailureHandlingPrompt(failure, context)\n\n // Spawn agent process that attaches to existing session (forks it)\n logger.info(`[Observer] Spawning agent '${failure.stageName}' to handle failure`)\n\n const agentProcess = this.backend.spawn(failure.stageName, prompt, process.env, this.taskDir, {\n serverUrl: this.serverUrl,\n sessionId: this.sessionId,\n dataDir: this.dataDir,\n })\n\n // Wait for the agent to complete\n await this.waitForAgent(agentProcess)\n\n // Read decision file\n if (!fs.existsSync(decisionFile)) {\n throw new Error(`Agent did not write decision file: ${decisionFile}`)\n }\n\n const decisionContent = fs.readFileSync(decisionFile, 'utf-8')\n const decision: ObserverDecision = JSON.parse(decisionContent)\n\n // Validate decision\n if (!decision.action || !['retry', 'escalate', 'halt'].includes(decision.action)) {\n throw new Error(`Invalid decision action: ${decision.action}`)\n }\n\n logger.info(`[Observer] Agent returned: ${decision.action} - ${decision.reason}`)\n\n return {\n action: decision.action,\n reason: decision.reason,\n fix: decision.fix,\n observerAttempt,\n }\n }\n\n /**\n * Build the prompt for the agent to handle the failure.\n */\n private buildFailureHandlingPrompt(failure: StageFailure, context: ObserverContext): string {\n return `## Task: Handle Stage Failure\n\nStage \"${failure.stageName}\" failed during pipeline execution.\n\n### Error Context\n\\`\\`\\`json\n${JSON.stringify(context, null, 2)}\n\\`\\`\\`\n\n### Context File\nFull context is available at: ${this.taskDir}/.observer-context.json\n\n### Decision File\nWrite your decision to: ${this.taskDir}/.observer-decision.json\n\n### Your Task\n\n1. Read .observer-context.json to understand the failure\n2. Investigate the error - read relevant files, understand root cause\n3. If fixable:\n - Apply the fix to the relevant files\n - Write .observer-decision.json with action: \"retry\"\n4. If not fixable:\n - Write .observer-decision.json with action: \"escalate\" and reason\n5. If fundamentally broken:\n - Write .observer-decision.json with action: \"halt\" and reason\n\n### Decision File Format\nWrite to ${this.taskDir}/.observer-decision.json:\n\\`\\`\\`json\n{\n \"action\": \"retry\",\n \"reason\": \"Fixed TypeScript error in src/foo.ts\",\n \"fix\": {\n \"description\": \"Fixed type mismatch in calculateTotal function\",\n \"filesModified\": [\"src/foo.ts\"]\n }\n}\n\\`\\`\\`\n\nOr for escalation:\n\\`\\`\\`json\n{\n \"action\": \"escalate\",\n \"reason\": \"Context overflow - needs human to simplify requirements\"\n}\n\\`\\`\\`\n\nOr for halt:\n\\`\\`\\`json\n{\n \"action\": \"halt\",\n \"reason\": \"Invalid task.json - fundamental data quality issue\"\n}\n\\`\\`\\`\n\n### Rules\n- Do NOT write partial JSON - write complete valid JSON to the decision file\n- If you cannot fix, escalate - don't guess\n- You have 120 seconds before timeout\n- Write the decision file BEFORE exiting\n- The pipeline is PAUSED waiting for your decision\n`\n }\n\n /**\n * Wait for agent process to complete.\n */\n private waitForAgent(agentProcess: {\n on: (event: string, cb: (...args: unknown[]) => void) => void\n kill?: () => void\n }): Promise<void> {\n return new Promise((resolve, reject) => {\n // Set timeout\n const timeout = setTimeout(() => {\n logger.warn(`[Observer] Agent timed out after ${OBSERVER_TIMEOUT_MS}ms`)\n try {\n agentProcess.kill?.()\n } catch {\n // ignore\n }\n reject(new Error('Observer timeout'))\n }, OBSERVER_TIMEOUT_MS)\n\n // Agent process emits 'exit' when done\n agentProcess.on('exit', (...args: unknown[]) => {\n clearTimeout(timeout)\n const code = args[0] as number | undefined\n logger.info(`[Observer] Agent exited with code: ${code}`)\n resolve()\n })\n\n // Fallback if no explicit exit event\n setTimeout(() => {\n clearTimeout(timeout)\n resolve()\n }, OBSERVER_TIMEOUT_MS + 1000)\n })\n }\n\n /**\n * Wrap promise with timeout.\n */\n private async withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n return Promise.race([\n promise,\n new Promise<T>((_, reject) => setTimeout(() => reject(new Error('Observer timeout')), ms)),\n ])\n }\n\n /**\n * Auto-escalate when max attempts reached or error occurs.\n */\n private autoEscalate(failure: StageFailure, reason: string): ObserverResult {\n return {\n action: 'escalate',\n reason: `Auto-escalated: ${reason}`,\n observerAttempt: this.getObserverAttempt(failure),\n }\n }\n\n /**\n * Get current Observer attempt number for this stage.\n */\n private getObserverAttempt(failure: StageFailure): number {\n const state = loadState(this.taskId)\n if (!state) return 1\n\n const stageState = state.stages[failure.stageName]\n if (!stageState) return 1\n\n // Count previous observer attempts in history\n const history =\n (state as PipelineStateV2 & { observerHistory?: Array<{ stage: string }> }).observerHistory ||\n []\n const stageHistory = history.filter((e) => e.stage === failure.stageName)\n return stageHistory.length + 1\n }\n\n /**\n * Log decision to status.json observerHistory.\n */\n private logDecision(\n failure: StageFailure,\n result: {\n action: string\n reason: string\n fix?: { description: string; filesModified: string[] }\n },\n observerAttempt: number,\n ): void {\n const state = loadState(this.taskId)\n if (!state) return\n\n const historyEntry = {\n stage: failure.stageName,\n observerAttempt,\n error: failure.error.message,\n action: result.action,\n reason: result.reason,\n wasAgent: true,\n agentName: failure.stageName,\n timestamp: new Date().toISOString(),\n fixApplied: result.fix,\n }\n\n const observerHistory = [\n ...((state as PipelineStateV2 & { observerHistory?: unknown[] }).observerHistory || []),\n historyEntry,\n ]\n\n const updatedState = {\n ...state,\n observerHistory,\n } as PipelineStateV2\n\n writeState(this.taskId, updatedState)\n }\n}\n\n// ============================================================================\n// Factory function\n// ============================================================================\n\nexport function createPipelineObserver(\n taskId: string,\n taskDir: string,\n serverUrl: string,\n sessionId: string,\n dataDir: string,\n): PipelineObserver {\n return new PipelineObserver(taskId, taskDir, serverUrl, sessionId, dataDir)\n}\n","/**\n * @fileType engine\n * @domain kody | engine\n * @pattern state-machine\n * @ai-summary Core deterministic pipeline execution engine\n */\n\nimport type {\n PipelineDefinition,\n PipelineContext,\n PipelineStateV2,\n LifecycleHooks,\n StageDefinition,\n StageResult,\n PipelineStep,\n} from './types'\nimport type { StageName } from '../stages/registry'\nimport { logger, ciGroup, ciGroupEnd } from '../logger'\nimport { MAX_PIPELINE_LOOP_ITERATIONS, RECOVERY_CHECK_INTERVAL } from '../config/constants'\nimport { PipelinePausedError } from './types'\nimport {\n logStageStart,\n logStageComplete,\n logStageSkip,\n logStageFail,\n logStageRetry,\n logPipelineStart,\n logPipelineComplete,\n logRecovery,\n} from '../pipeline-events'\nimport {\n loadState,\n writeState,\n initState,\n updateStage,\n completeState,\n recoverStaleStages,\n recoverPipelineState,\n} from './status'\nimport { getHandler } from '../handlers/handler'\nimport { setLifecycleLabel } from '../github-api'\nimport { executePostAction } from '../pipeline/post-actions'\nimport { flattenPipelineOrder } from '../pipeline/definitions'\nimport { execFileSync } from 'node:child_process'\nimport { commitPipelineFiles } from '../git-utils'\nimport { PipelineObserver } from '../pipeline/observer/observer'\n\n/**\n * Error subclass that carries the originating stage name for parallel error attribution\n */\nclass StageError extends Error {\n public readonly stageName: string\n public readonly cause?: Error\n constructor(message: string, stageName: string, cause?: Error) {\n super(message)\n this.name = 'StageError'\n this.stageName = stageName\n this.cause = cause\n }\n}\n\n// ============================================================================\n// Engine\n// ============================================================================\n\n/**\n * Main pipeline execution function\n */\nexport async function runPipeline(\n ctx: PipelineContext,\n pipeline: PipelineDefinition,\n hooks?: LifecycleHooks,\n rebuildPipeline?: (ctx: PipelineContext) => PipelineDefinition,\n): Promise<PipelineStateV2> {\n // Load or init state\n logPipelineStart(ctx.taskId, ctx.input.mode, ctx.profile)\n let state = loadState(ctx.taskId)\n if (!state) {\n state = initState(ctx, ctx.input.mode)\n // Set initial lifecycle label based on mode\n if (ctx.input.issueNumber) {\n const initialLabel =\n ctx.input.mode === 'spec' || ctx.input.mode === 'full' ? 'kody:planning' : 'kody:building'\n setLifecycleLabel(ctx.input.issueNumber, initialLabel)\n }\n\n // Early push: overwrite stale status.json on branch so dashboard sees 'running' immediately.\n // Only when the feature branch already exists (re-runs / gate resumes).\n // First runs create the branch in taskify's post-action commit-task-files with ensureBranch.\n if (!ctx.input.dryRun && !ctx.input.local) {\n try {\n const currentBranch = execFileSync('git', ['branch', '--show-current'], {\n encoding: 'utf-8',\n }).trim()\n const isFeatureBranch = !['dev', 'main', 'master'].includes(currentBranch)\n if (isFeatureBranch) {\n commitPipelineFiles({\n taskDir: ctx.taskDir,\n taskId: ctx.taskId,\n message: `ci(kody): reset status to running for ${ctx.taskId}`,\n stagingStrategy: 'task-only',\n push: true,\n isCI: true,\n })\n logger.info(' ✓ Pushed fresh running status.json to branch')\n }\n } catch (earlyPushErr) {\n // Non-fatal — dashboard will update once the first stage completes\n logger.warn({ err: earlyPushErr }, 'Early status push failed (non-fatal)')\n }\n }\n } else {\n // Recovery: handle stale state from previous interrupted runs\n // Step 1: Reset any stages stuck in \"running\" to \"pending\"\n state = recoverStaleStages(state)\n\n // Step 2: Build advisory stages set from pipeline definitions\n const advisoryStages = new Set<string>()\n for (const [name, def] of pipeline.stages) {\n if (def.advisory) advisoryStages.add(name)\n }\n\n // Step 3: Auto-complete/fail pipeline if all stages are done\n const flatOrder = flattenPipelineOrder(pipeline.order)\n state = recoverPipelineState(state, flatOrder, advisoryStages)\n writeState(ctx.taskId, state)\n\n // Step 4: If pipeline was previously failed, check if any stages were reset to pending\n // (which means a rerun is happening). Only update the label if we're actually restarting.\n // R2-FIX #5: Don't blindly set 'building' — verify we have pending work to do first.\n if (state.state === 'failed' && ctx.input.issueNumber) {\n const hasPendingStages = Object.values(state.stages).some(\n (s) => s.state === 'pending' || s.state === 'running',\n )\n if (hasPendingStages) {\n setLifecycleLabel(ctx.input.issueNumber, 'kody:building')\n }\n }\n\n // Step 5: Handle paused pipeline with no paused stages (gate was approved)\n // This handles the case where resumeFromGate() was called to mark the gate stage\n // as completed, but the pipeline-level state is still \"paused\"\n if (state.state === 'paused') {\n const anyPausedStage = Object.values(state.stages).some((s) => s.state === 'paused')\n if (!anyPausedStage) {\n // Gate was approved - no stages are actually paused, so resume the pipeline\n state = {\n ...state,\n state: 'running',\n updatedAt: new Date().toISOString(),\n }\n writeState(ctx.taskId, state)\n }\n }\n\n // If recovery determined pipeline is already done, return immediately\n if (state.state === 'completed' || state.state === 'failed') {\n return state\n }\n }\n\n // Main execution loop\n let loopCount = 0\n while (true) {\n loopCount++\n\n // Circuit breaker: prevent infinite loops from stage state management bugs\n if (loopCount > MAX_PIPELINE_LOOP_ITERATIONS) {\n logger.error(\n `Pipeline loop exceeded ${MAX_PIPELINE_LOOP_ITERATIONS} iterations — aborting to prevent infinite loop`,\n )\n state = completeState(state, 'failed')\n writeState(ctx.taskId, state)\n throw new Error(\n `Pipeline loop guard triggered after ${MAX_PIPELINE_LOOP_ITERATIONS} iterations. ` +\n 'This is likely a bug in stage state management.',\n )\n }\n\n // FIX #9: Periodic recovery check\n // This handles mid-run corruption of status.json\n if (loopCount % RECOVERY_CHECK_INTERVAL === 0) {\n const currentState = loadState(ctx.taskId)\n if (currentState) {\n // Check for stale running stages\n const recoveredState = recoverStaleStages(currentState)\n if (recoveredState !== currentState) {\n logger.info('⚠️ Periodic recovery: reset stale running stages')\n logRecovery('stale-stage-recovery', ctx.taskId, 'Reset stale running stages')\n state = recoveredState\n writeState(ctx.taskId, state)\n }\n }\n }\n\n // Check if pipeline needs rebuilding (two-phase construction)\n if (ctx.pipelineNeedsRebuild && rebuildPipeline) {\n pipeline = rebuildPipeline(ctx)\n ctx.pipelineNeedsRebuild = false\n\n // FIX #1/#4: Validate state stages against rebuilt pipeline.\n // New stages (from impl phase) may not exist in state yet — initialize them.\n // Stale stages (removed during rebuild) are harmless (ignored by resolveNextStep).\n const newOrder = flattenPipelineOrder(pipeline.order)\n for (const stageName of newOrder) {\n if (!state.stages[stageName]) {\n state = updateStage(state, stageName, { state: 'pending', retries: 0 })\n }\n }\n writeState(ctx.taskId, state)\n\n // Transition from planning to building after spec stages complete\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, 'kody:building')\n }\n }\n\n const nextStep = resolveNextStep(state, pipeline)\n if (!nextStep) {\n // All stages completed - mark pipeline as completed\n state = completeState(state, 'completed')\n writeState(ctx.taskId, state)\n // Set lifecycle label to done\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, 'kody:done')\n }\n logPipelineComplete(ctx.taskId, state.totalElapsed)\n break\n }\n\n const prevState: PipelineStateV2 | null = state\n\n // Handle parallel vs sequential\n const step = nextStep as StageName | { parallel: StageName[] }\n if (step && typeof step === 'object' && 'parallel' in step) {\n state = await executeParallelStep(ctx, pipeline, state, step.parallel)\n } else if (step && typeof step === 'string') {\n state = await executeSingleStep(ctx, pipeline, state, step)\n }\n\n // Persist state\n writeState(ctx.taskId, state)\n\n // Call lifecycle hook\n if (hooks?.onStateChange && state !== prevState) {\n hooks.onStateChange(prevState, state, ctx)\n }\n\n // Stop if failed or paused\n if (state.state === 'failed' || state.state === 'paused') {\n break\n }\n }\n\n // Throw if pipeline failed so caller can handle the failure properly\n if (state.state === 'failed') {\n // Find either failed or timeout stage for better error reporting\n const failedStage = Object.entries(state.stages).find(\n ([, s]) => s.state === 'failed' || s.state === 'timeout',\n )\n const stageName = failedStage?.[0] || 'unknown'\n const stageState = failedStage?.[1]\n const stageOutcome = stageState?.state || 'unknown'\n const stageError = stageState?.error ? `: ${stageState.error}` : ''\n throw new Error(`Pipeline failed at stage: ${stageName} (${stageOutcome})${stageError}`)\n }\n\n return state\n}\n\n/**\n * Resolve the next step to execute\n */\nfunction resolveNextStep(\n state: PipelineStateV2,\n pipeline: PipelineDefinition,\n): PipelineStep | null {\n for (const step of pipeline.order) {\n if (typeof step === 'string') {\n // Single stage\n const stageState = state.stages[step]\n // Only run pending stages - failed stages should not auto-retry\n // User can use --from to restart from a specific stage\n // Also run stages that were interrupted (running state from previous run)\n if (!stageState || stageState.state === 'pending' || stageState.state === 'running') {\n return step\n }\n } else if ('parallel' in step) {\n // Parallel stages - check if any need to run\n const needsRun = step.parallel.some((s) => {\n const stageState = state.stages[s]\n return !stageState || stageState.state === 'pending' || stageState.state === 'running'\n })\n if (needsRun) {\n return step\n }\n }\n }\n return null\n}\n\n/**\n * Execute a single stage\n */\nasync function executeSingleStep(\n ctx: PipelineContext,\n pipeline: PipelineDefinition,\n state: PipelineStateV2,\n stageName: StageName,\n): Promise<PipelineStateV2> {\n const def = pipeline.stages.get(stageName)\n if (!def) {\n const msg = `Stage '${stageName}' not found in pipeline definitions — check pipeline order vs stage definitions`\n logger.error(msg)\n throw new Error(msg)\n }\n\n // Check skip conditions\n if (def.shouldSkip) {\n const skipResult = def.shouldSkip(ctx)\n if (skipResult.shouldSkip) {\n logger.info(` ${stageName} skipped — ${skipResult.reason}`)\n logStageSkip(stageName, ctx.taskId, skipResult.reason)\n return updateStage(state, stageName, {\n state: 'skipped',\n skipped: skipResult.reason,\n })\n }\n }\n\n // Check if already completed (resume)\n const stageState = state.stages[stageName]\n if (stageState?.state === 'completed') {\n logger.info(` ${stageName} already completed, skipping`)\n return state\n }\n\n // Mark as running\n state = updateStage(state, stageName, { state: 'running', startedAt: new Date().toISOString() })\n writeState(ctx.taskId, state)\n logStageStart(stageName, ctx.taskId)\n\n // Dry-run: mark completed without running\n if (ctx.input.dryRun) {\n return updateStage(state, stageName, { state: 'completed', retries: 0 })\n }\n\n // Run preExecute hook if defined (G20)\n if (def.preExecute) {\n try {\n await def.preExecute(ctx)\n } catch (error) {\n logger.error({ err: error }, ` ❌ preExecute failed for ${stageName}:`)\n return updateStage(state, stageName, {\n state: 'failed',\n error: error instanceof Error ? error.message : String(error),\n })\n }\n }\n\n // Get handler and execute\n ciGroup(`Stage: ${stageName}`)\n try {\n const handler = getHandler(def.name, def.type)\n const result = await handler.execute(ctx, def)\n ciGroupEnd()\n return await handleStageResult(ctx, pipeline, state, stageName, result, def)\n } catch (error) {\n ciGroupEnd()\n if (error instanceof PipelinePausedError) {\n // Handle paused - mark stage as paused and pipeline as paused\n state = updateStage(state, stageName, { state: 'paused' })\n return completeState(state, 'paused')\n }\n\n // Handle failure - mark stage as failed\n const errorMessage = error instanceof Error ? error.message : String(error)\n logger.error({ err: error }, ` ❌ ${stageName} failed:`)\n logStageFail(stageName, ctx.taskId, errorMessage)\n\n // Check if Observer is available (requires serverUrl and sessionId)\n const canObserve = ctx.serverUrl && ctx.lastSessionId && !ctx.input.dryRun\n\n if (canObserve && !def.advisory) {\n // Delegate to Observer for complex failure handling\n // Pipeline is PAUSED while Observer waits for agent decision\n try {\n const observer = new PipelineObserver(\n ctx.taskId,\n ctx.taskDir,\n ctx.serverUrl!,\n ctx.lastSessionId!,\n ctx.taskDir, // dataDir is taskDir/opencode-data derived in Observer\n )\n\n const failure = {\n stageName,\n error: error instanceof Error ? error : new Error(String(error)),\n attempt: (state.stages[stageName]?.retries ?? 0) + 1,\n maxAttempts: def.maxRetries,\n taskDir: ctx.taskDir,\n }\n\n const observerResult = await observer.handle(failure)\n\n logger.info(\n `[StateMachine] Observer decision: ${observerResult.action} - ${observerResult.reason}`,\n )\n\n // Apply Observer's decision\n switch (observerResult.action) {\n case 'retry':\n // Reset stage to pending for retry\n state = updateStage(state, stageName, {\n state: 'pending',\n retries: observerResult.observerAttempt,\n error: `Observer retry: ${observerResult.reason}`,\n })\n return state\n\n case 'escalate':\n // Pause pipeline and notify (GitHub issue comment)\n state = updateStage(state, stageName, {\n state: 'failed',\n error: `Observer escalate: ${observerResult.reason}`,\n })\n return completeState(state, 'paused')\n\n case 'halt':\n default:\n // Mark pipeline as failed\n state = updateStage(state, stageName, {\n state: 'failed',\n error: `Observer halt: ${observerResult.reason}`,\n })\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, 'kody:failed')\n }\n return completeState(state, 'failed')\n }\n } catch (observerError) {\n // Observer failed - fall back to default failure handling\n logger.error({ err: observerError }, `[StateMachine] Observer error, falling back`)\n state = updateStage(state, stageName, {\n state: 'failed',\n error: errorMessage,\n })\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, 'kody:failed')\n }\n return completeState(state, 'failed')\n }\n }\n\n // Default failure handling (no Observer available or advisory stage)\n state = updateStage(state, stageName, {\n state: 'failed',\n error: errorMessage,\n })\n // For non-advisory stages, mark pipeline as failed to stop the loop\n if (!def.advisory) {\n // Set lifecycle label to failed\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, 'kody:failed')\n }\n return completeState(state, 'failed')\n }\n return state\n }\n}\n\n/**\n * Execute parallel stages\n */\nasync function executeParallelStep(\n ctx: PipelineContext,\n pipeline: PipelineDefinition,\n state: PipelineStateV2,\n stageNames: StageName[],\n): Promise<PipelineStateV2> {\n logger.info(` Running parallel: [${stageNames.join(', ')}]...`)\n\n // Filter out already completed/terminal stages (for resume)\n const stagesToRun = stageNames.filter((stageName) => {\n const stageState = state.stages[stageName]\n if (\n stageState?.state === 'completed' ||\n stageState?.state === 'skipped' ||\n stageState?.state === 'timeout' ||\n stageState?.state === 'failed'\n ) {\n logger.info(` ${stageName} already ${stageState.state}, skipping`)\n return false\n }\n return true\n })\n\n // If all stages already completed, return current state\n if (stagesToRun.length === 0) {\n return state\n }\n\n // Dry-run: mark all parallel stages as completed without running\n if (ctx.input.dryRun) {\n for (const stageName of stagesToRun) {\n state = updateStage(state, stageName, { state: 'completed', retries: 0 })\n }\n return state\n }\n\n const results = await Promise.allSettled(\n stagesToRun.map(async (stageName) => {\n const def = pipeline.stages.get(stageName)\n if (!def) {\n throw new StageError(`Stage '${stageName}' not found in pipeline definitions`, stageName)\n }\n\n // Check skip first\n if (def.shouldSkip) {\n const skipResult = def.shouldSkip(ctx)\n if (skipResult.shouldSkip) {\n return {\n stageName,\n result: {\n outcome: 'skipped' as const,\n reason: skipResult.reason,\n retries: 0,\n },\n }\n }\n }\n\n // R10: Run preExecute hook if defined\n if (def.preExecute) {\n try {\n await def.preExecute(ctx)\n } catch (preError) {\n // Wrap error with stageName for rejection handler\n throw new StageError(\n preError instanceof Error ? preError.message : String(preError),\n stageName,\n preError instanceof Error ? preError : undefined,\n )\n }\n }\n\n // Execute - wrap to tag errors with stageName\n try {\n const handler = getHandler(def.name, def.type)\n const result = await handler.execute(ctx, def)\n return { stageName, result }\n } catch (error) {\n // Wrap error with stageName for rejection handler\n throw new StageError(\n error instanceof Error ? error.message : String(error),\n stageName,\n error instanceof Error ? error : undefined,\n )\n }\n }),\n )\n\n // Process results - distinguish critical vs advisory failures (R7)\n const criticalFailures: { name: string; reason: string }[] = []\n const advisoryFailures: { name: string; reason: string }[] = []\n let pausedStage: string | null = null\n\n for (const result of results) {\n if (result.status === 'rejected') {\n // G30: Check if this is a PipelinePausedError (direct or wrapped in StageError)\n const rejectedErr = result.reason\n const isPaused =\n rejectedErr instanceof PipelinePausedError ||\n (rejectedErr instanceof StageError && rejectedErr.cause instanceof PipelinePausedError)\n if (isPaused) {\n // Mark the stage as paused and collect — don't return early\n // This allows other parallel stages to complete their post-actions\n const pausedStageName =\n rejectedErr instanceof StageError ? rejectedErr.stageName : 'unknown'\n state = updateStage(state, pausedStageName, { state: 'paused' })\n pausedStage = pausedStageName\n continue\n }\n\n const reason = (result as PromiseRejectedResult).reason\n const name =\n reason instanceof StageError\n ? reason.stageName\n : (((reason as Record<string, unknown>)?.stageName as string) ?? 'unknown')\n const message = reason instanceof Error ? reason.message : String(reason)\n // R7: Use dynamic advisory lookup from pipeline definition\n const isAdvisory = pipeline.stages.get(name as StageName)?.advisory === true\n if (isAdvisory) {\n // R2: Mark advisory rejected stage as failed in state\n state = updateStage(state, name, { state: 'failed', error: message })\n advisoryFailures.push({ name, reason: message })\n } else {\n // R1: Mark stage as failed in state before throwing\n state = updateStage(state, name, { state: 'failed', error: message })\n criticalFailures.push({ name, reason: message })\n }\n continue\n }\n\n const { stageName, result: stageResult } = result.value\n if (!stageResult) continue\n\n // Handle PipelinePausedError specially (G30) — collect pauses instead of returning early\n if (stageResult.outcome === 'paused') {\n state = updateStage(state, stageName, { state: 'paused' })\n pausedStage = stageName\n continue\n }\n\n // Update state based on outcome\n if (stageResult.outcome === 'completed') {\n state = updateStage(state, stageName, {\n state: 'completed',\n completedAt: new Date().toISOString(),\n retries: stageResult.retries,\n outputFile: stageResult.outputFile,\n sessionId: stageResult.sessionId,\n })\n\n // FIX #2: Propagate sessionId deterministically — use the stage that comes\n // last in the pipeline order, regardless of which parallel stage completes first.\n // This ensures consistent session forking across runs.\n if (stageResult.sessionId) {\n if (!ctx.lastSessionId) {\n ctx.lastSessionId = stageResult.sessionId\n } else {\n // Overwrite only if this stage comes after the current lastSessionId owner\n // in the pipeline order. Since we process results in order, the last\n // successful stage's sessionId is used.\n ctx.lastSessionId = stageResult.sessionId\n }\n }\n\n // R8: Run post-actions for completed parallel stages\n const def = pipeline.stages.get(stageName)\n if (def?.postActions && !ctx.input.dryRun) {\n try {\n for (const action of def.postActions) {\n await executePostAction(ctx, action, state)\n }\n } catch (postError) {\n // Handle post-action errors - mirroring executeSingleStep pattern\n // Collect pauses instead of returning early — allows other stages to complete\n if (postError instanceof PipelinePausedError) {\n state = updateStage(state, stageName, { state: 'paused' })\n pausedStage = stageName\n continue\n }\n // FIX #3: Don't immediately fail - collect failures and process at end\n // This allows other successful parallel stages to complete\n logger.error({ err: postError }, ` Post-action failed for parallel stage ${stageName}:`)\n const postErrorMsg = postError instanceof Error ? postError.message : String(postError)\n state = updateStage(state, stageName, {\n state: 'failed',\n error: postErrorMsg,\n })\n const isAdvisory = pipeline.stages.get(stageName)?.advisory === true\n if (isAdvisory) {\n advisoryFailures.push({ name: stageName, reason: postErrorMsg })\n } else {\n criticalFailures.push({ name: stageName, reason: postErrorMsg })\n }\n }\n }\n } else if (stageResult.outcome === 'skipped') {\n state = updateStage(state, stageName, {\n state: 'skipped',\n skipped: stageResult.reason,\n })\n } else if (stageResult.outcome === 'timed_out') {\n // Handle timeout in parallel stages — previously missing, causing infinite retry loops\n const isAdvisory = pipeline.stages.get(stageName)?.advisory === true\n state = updateStage(state, stageName, {\n state: 'timeout',\n error: stageResult.reason || 'timed out',\n })\n if (!isAdvisory) {\n criticalFailures.push({ name: stageName, reason: stageResult.reason || 'timed out' })\n }\n } else if (stageResult.outcome === 'failed') {\n // R7: Use dynamic advisory lookup from pipeline definition\n const isAdvisory = pipeline.stages.get(stageName)?.advisory === true\n if (isAdvisory) {\n // R1: Mark stage as failed in state\n state = updateStage(state, stageName, {\n state: 'failed',\n error: stageResult.reason || 'failed',\n })\n advisoryFailures.push({ name: stageName, reason: stageResult.reason || 'failed' })\n } else {\n // R1: Mark stage as failed in state before returning failed state\n state = updateStage(state, stageName, {\n state: 'failed',\n error: stageResult.reason || 'failed',\n })\n criticalFailures.push({ name: stageName, reason: stageResult.reason || 'failed' })\n }\n }\n }\n\n // R2: Return failed state instead of throwing (main loop sees failed state and breaks cleanly)\n if (criticalFailures.length > 0) {\n const errors = criticalFailures.map((f) => f.reason).join('; ')\n const names = criticalFailures.map((f) => f.name)\n logger.error(` ❌ Parallel stages [${names.join(', ')}] failed: ${errors}`)\n // Set lifecycle label to failed\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, 'kody:failed')\n }\n return completeState(state, 'failed')\n }\n\n // Return paused state if any stage paused — after all other stages processed\n if (pausedStage) {\n writeState(ctx.taskId, state)\n return completeState(state, 'paused')\n }\n\n return state\n}\n\n/**\n * Handle stage result and run post-actions\n */\nasync function handleStageResult(\n ctx: PipelineContext,\n pipeline: PipelineDefinition,\n state: PipelineStateV2,\n stageName: StageName,\n result: StageResult,\n def: StageDefinition,\n): Promise<PipelineStateV2> {\n // Compute elapsed time from startedAt\n const startedAt = state.stages[stageName]?.startedAt\n const elapsed = startedAt\n ? Math.round((Date.now() - new Date(startedAt).getTime()) / 1000)\n : undefined\n\n if (result.outcome === 'completed') {\n state = updateStage(state, stageName, {\n state: 'completed',\n completedAt: new Date().toISOString(),\n elapsed,\n retries: result.retries,\n outputFile: result.outputFile,\n tokenUsage: result.tokenUsage,\n cost: result.cost,\n sessionId: result.sessionId,\n })\n logStageComplete(stageName, ctx.taskId, 'completed', elapsed ? elapsed * 1000 : undefined)\n\n // Propagate sessionId for downstream stage forking\n if (result.sessionId) {\n ctx.lastSessionId = result.sessionId\n }\n\n // Run post-actions if defined\n if (def.postActions) {\n for (const action of def.postActions) {\n await executePostAction(ctx, action, state)\n // Note: executePostAction may throw PipelinePausedError\n // which propagates up to executeSingleStep's catch block\n }\n }\n } else if (result.outcome === 'failed') {\n // Generic declarative retry via retryWith\n if (def.retryWith && !def.advisory) {\n const { stage: retryStage, maxAttempts, onFailure } = def.retryWith\n const retryState = state.stages[retryStage]\n const currentAttempt = retryState?.fixAttempt ?? 0\n\n if (currentAttempt < maxAttempts) {\n if (onFailure) {\n await onFailure(ctx, ctx.taskDir)\n }\n\n const newAttempt = currentAttempt + 1\n state = updateStage(state, retryStage, {\n state: 'pending',\n fixAttempt: newAttempt,\n maxFixAttempts: maxAttempts,\n })\n state = updateStage(state, stageName, { state: 'pending' })\n writeState(ctx.taskId, state)\n\n logStageRetry(stageName, ctx.taskId, newAttempt, maxAttempts)\n logger.info(\n `🔄 ${stageName} failed, looping to ${retryStage} (attempt ${newAttempt}/${maxAttempts})`,\n )\n return state\n } else {\n logger.error(\n `Max retry attempts (${maxAttempts}) reached for ${retryStage}, pipeline failing`,\n )\n // Fall through to normal failure handling\n }\n }\n\n // Normal failure handling\n state = updateStage(state, stageName, {\n state: 'failed',\n elapsed,\n error: result.reason,\n })\n\n // If non-advisory stage failed, mark pipeline as failed\n if (!def.advisory) {\n // Set lifecycle label to failed\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, 'kody:failed')\n }\n return completeState(state, 'failed')\n }\n } else if (result.outcome === 'timed_out') {\n state = updateStage(state, stageName, {\n state: 'timeout',\n elapsed,\n error: result.reason,\n })\n\n // Generic timeout recovery: if any stage declares retryWith pointing to this\n // timed-out stage with onTimeout: 'retry', reset that stage to pending so it\n // can re-evaluate (e.g., verify checks if partial fix work was enough).\n const retryingDef = [...pipeline.stages.values()].find(\n (s) => s.retryWith?.stage === stageName && s.retryWith.onTimeout === 'retry',\n )\n if (retryingDef) {\n logger.info(\n `⚠️ ${stageName} timed out — running ${retryingDef.name} to check if partial work suffices`,\n )\n state = updateStage(state, retryingDef.name, { state: 'pending' })\n writeState(ctx.taskId, state)\n return state // Don't fail pipeline — let the retrying stage check\n }\n\n if (!def.advisory) {\n // Set lifecycle label to failed\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, 'kody:failed')\n }\n return completeState(state, 'failed')\n }\n }\n\n return state\n}\n","/**\n * @fileType utility\n * @domain kody | task\n * @pattern task-setup\n * @ai-summary Task directory and file preparation — extracted to avoid circular dependency between entry.ts and modes/\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext } from './engine/types'\nimport { logger } from './logger'\n\n/**\n * Ensures task.md exists before pipeline runs (needed for taskify agent).\n * - Uses --file flag content if provided\n * - Fetches from GitHub issue body if --issue-number provided\n * - Throws if neither available and task.md doesn't exist\n */\nexport async function ensureTaskMd(ctx: PipelineContext): Promise<void> {\n const { input, taskDir } = ctx\n const taskMdPath = path.join(taskDir, 'task.md')\n\n // --file flag has priority\n if (input.file) {\n const resolvedFile = path.resolve(input.file)\n if (!fs.existsSync(resolvedFile)) {\n throw new Error(`File not found: ${resolvedFile}`)\n }\n const content = fs.readFileSync(resolvedFile, 'utf-8').trim()\n if (!content) {\n throw new Error(`File is empty: ${resolvedFile}`)\n }\n fs.writeFileSync(taskMdPath, `# Task\\n\\n${content}\\n`)\n logger.info(`Created task.md from ${resolvedFile}`)\n return\n }\n\n // Create task.md from issue body if it doesn't exist\n if (!fs.existsSync(taskMdPath)) {\n if (input.issueNumber) {\n const { getIssue } = await import('./github-api')\n logger.info('task.md not found, fetching issue body to create it...')\n const { body: issueBody, title: issueTitle } = getIssue(input.issueNumber)\n if (issueBody) {\n const titleSection = issueTitle ? `## Issue Title\\n\\n${issueTitle}\\n` : ''\n fs.writeFileSync(taskMdPath, `# Task\\n\\n${titleSection}${issueBody}\\n`)\n logger.info(`Created task.md from issue #${input.issueNumber}`)\n } else {\n throw new Error(\n `task.md not found in .tasks/${input.taskId}/ and issue #${input.issueNumber} has no body. Create it first.`,\n )\n }\n } else {\n throw new Error(`task.md not found in .tasks/${input.taskId}/. Create it first.`)\n }\n }\n}\n","/**\n * @fileType handler\n * @domain kody | modes\n * @ai-summary Pipeline mode handler — extracted from entry.ts for modularity\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext } from '../engine/types'\nimport { PipelinePausedError } from '../engine/types'\nimport { runPipeline } from '../engine/state-machine'\nimport { resolvePipelineForMode } from '../engine/pipeline-resolver'\nimport { logger } from '../logger'\nimport { commitPipelineFiles } from '../git-utils'\n\nimport { ensureTaskMd } from '../task-setup'\nimport { handleClarification } from '../clarify-workflow'\nimport { postComment } from '../github-api'\n\nexport async function runSpecMode(ctx: PipelineContext): Promise<void> {\n const { input, taskDir } = ctx\n\n // R4: Ensure task.md exists before running pipeline\n await ensureTaskMd(ctx)\n\n // Run spec pipeline\n const pipeline = resolvePipelineForMode('spec', 'standard', input.clarify ?? false, ctx)\n await runPipeline(ctx, pipeline)\n\n // G17: Post-spec clarification logic\n if (input.clarify) {\n const clarifyResult = handleClarification(input, taskDir)\n if (clarifyResult === 'waiting') {\n logger.info('\\n⚠️ Clarify stage has questions that need answering')\n const questionsPath = path.join(taskDir, 'questions.md')\n if (input.issueNumber) {\n let preview = '(questions file not found)'\n try {\n if (fs.existsSync(questionsPath)) {\n const questionsContent = fs.readFileSync(questionsPath, 'utf-8')\n preview = questionsContent.slice(0, 1500)\n }\n } catch (readErr) {\n logger.warn({ err: readErr }, 'Failed to read questions.md for preview')\n }\n postComment(\n input.issueNumber,\n `🔄 Kody stopped at clarify stage - questions need answering:\\n\\n${preview}\\n\\nPlease answer these questions and call \\`/kody\\` again to proceed with implementation.`,\n )\n }\n // Commit task files and pause\n commitPipelineFiles({\n taskDir,\n taskId: input.taskId,\n message: `ci(kody): Save task files for ${input.taskId}\\n\\nAuto-committed by Kody pipeline`,\n ensureBranch: true,\n cleanDirtyState: true,\n stagingStrategy: 'task-only',\n push: true,\n isCI: !input.local,\n dryRun: input.dryRun,\n })\n throw new PipelinePausedError(`clarify stage: awaiting answers for ${input.taskId}`)\n }\n }\n\n // Commit spec task files\n commitPipelineFiles({\n taskDir,\n taskId: input.taskId,\n message: `ci(kody): Save task files for ${input.taskId}\\n\\nAuto-committed by Kody pipeline`,\n ensureBranch: true,\n cleanDirtyState: true,\n stagingStrategy: 'task-only',\n push: true,\n isCI: !input.local,\n dryRun: input.dryRun,\n })\n\n logger.info('\\n✅ Kody SPEC pipeline complete')\n}\n","/**\n * @fileType handler\n * @domain kody | modes\n * @ai-summary Pipeline mode handler — extracted from entry.ts for modularity\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext } from '../engine/types'\nimport { runPipeline } from '../engine/state-machine'\nimport { resolvePipelineForMode, createRebuildCallback } from '../engine/pipeline-resolver'\nimport { logger } from '../logger'\nimport { readTask } from '../pipeline-utils'\n\nexport async function runImplMode(ctx: PipelineContext): Promise<void> {\n const { taskDir } = ctx\n\n // Validate clarified.md exists\n const clarifiedPath = path.join(taskDir, 'clarified.md')\n if (!fs.existsSync(clarifiedPath)) {\n throw new Error(`clarified.md not found. Run spec pipeline first or create it.`)\n }\n\n // Get task definition\n let taskDef\n try {\n taskDef = readTask(taskDir)\n ctx.taskDef = taskDef\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error)\n logger.error(`\\n❌ Failed to read task definition: ${msg}`)\n throw new Error(`Invalid task.json: ${msg}`)\n }\n if (!taskDef) {\n throw new Error(`task.json not found. Run spec pipeline first.`)\n }\n\n // Apply --complexity override if provided (for testing/debugging)\n if (ctx.input.complexityOverride !== undefined) {\n const oldComplexity = taskDef.complexity\n taskDef.complexity = ctx.input.complexityOverride\n taskDef.complexity_reasoning = `Override via --complexity=${ctx.input.complexityOverride}`\n if (oldComplexity !== undefined) {\n logger.info(` ℹ️ Complexity override: ${oldComplexity} → ${ctx.input.complexityOverride}`)\n } else {\n logger.info(` ℹ️ Complexity override applied: ${ctx.input.complexityOverride}`)\n }\n }\n\n // Check spec_only pipeline\n if (taskDef.pipeline === 'spec_only') {\n logger.info('Task pipeline is spec_only — skipping implementation stages.')\n return\n }\n\n // Resolve profile\n const { resolvePipelineProfile } = await import('../pipeline-utils')\n ctx.profile = resolvePipelineProfile(taskDef)\n logger.info(`ℹ️ Pipeline profile: ${ctx.profile}`)\n\n // Run impl pipeline (pass rebuild callback for two-phase construction)\n const pipeline = resolvePipelineForMode('impl', ctx.profile, false, ctx)\n const rebuild = createRebuildCallback('full', ctx.input.clarify ?? false)\n await runPipeline(ctx, pipeline, undefined, rebuild)\n\n logger.info('\\n✅ Kody IMPLEMENTATION pipeline complete')\n}\n","/**\n * @fileType handler\n * @domain kody | modes\n * @ai-summary Pipeline mode handler — extracted from entry.ts for modularity\n */\n\nimport type { PipelineContext } from '../engine/types'\nimport { PipelinePausedError } from '../engine/types'\nimport { runPipeline } from '../engine/state-machine'\nimport { resolvePipelineForMode, createRebuildCallback } from '../engine/pipeline-resolver'\nimport { logger } from '../logger'\nimport { readTask } from '../pipeline-utils'\n\nimport { ensureTaskMd } from '../task-setup'\n\nexport async function runFullMode(ctx: PipelineContext): Promise<void> {\n logger.info('Running FULL Kody pipeline (spec + impl)...\\n')\n\n // FIX: If a previous run left state as failed/completed/paused, delete it so the\n // pipeline starts fresh. Without this, runPipeline() sees the terminal state\n // in status.json and returns immediately without executing any stages.\n // Paused state is included because a gate-paused status.json from a previous run\n // causes the dashboard to show stale \"Classifying\" until the new run pushes an update.\n const { loadState: loadSt2, deleteState } = await import('../engine/status')\n const prevState = loadSt2(ctx.taskId)\n if (\n prevState &&\n (prevState.state === 'failed' ||\n prevState.state === 'completed' ||\n prevState.state === 'paused')\n ) {\n logger.info(` Previous run state: ${prevState.state} — resetting for fresh full-mode run`)\n deleteState(ctx.taskId)\n }\n\n // R4: Ensure task.md exists before running pipeline\n await ensureTaskMd(ctx)\n\n // FIX #5: Resolve profile from task.json instead of hardcoding 'standard'\n // This ensures the correct profile (lightweight vs standard) is used\n let profile: 'standard' | 'lightweight' | 'turbo' = 'standard'\n try {\n const taskDef = readTask(ctx.taskDir)\n if (taskDef) {\n ctx.taskDef = taskDef\n const { resolvePipelineProfile } = await import('../pipeline-utils')\n profile = resolvePipelineProfile(taskDef)\n logger.info(`ℹ️ Resolved profile from task.json: ${profile}`)\n }\n } catch {\n // If task.json doesn't exist yet, taskify will create it and resolve profile\n logger.info('ℹ️ task.json not found yet, will resolve profile after taskify')\n }\n ctx.profile = profile\n\n // Run full pipeline - pass rebuild callback for two-phase construction\n // This ensures profile changes after taskify are reflected in later stages\n const pipeline = resolvePipelineForMode('full', profile, ctx.input.clarify ?? false, ctx)\n const rebuild = createRebuildCallback('full', ctx.input.clarify ?? false)\n const finalState = await runPipeline(ctx, pipeline, undefined, rebuild)\n\n // Handle paused state (gate approval required)\n if (finalState.state === 'paused') {\n throw new PipelinePausedError(`Pipeline paused — awaiting gate approval for ${ctx.taskId}`)\n }\n\n logger.info('\\n✅ Full Kody pipeline complete!')\n}\n","/**\n * @fileType utility\n * @domain kody | brain\n * @ai-summary Health check utility for brain server availability\n */\n\n/**\n * Check if brain server is available at the given URL.\n * Returns false if URL is undefined/empty or if the server doesn't respond within 5s.\n */\nexport async function isBrainAvailable(url: string | undefined): Promise<boolean> {\n if (!url) return false\n try {\n // Strip /sse suffix if present to get base URL for health check\n const baseUrl = url.replace(/\\/sse$/, '')\n const resp = await fetch(baseUrl, { signal: AbortSignal.timeout(5000) })\n return resp.ok\n } catch {\n return false\n }\n}\n","/**\n * @fileType utility\n * @domain kody | brain\n * @pattern mcp-client | claude-api\n * @ai-summary MCP client + Claude API wrapper for remote brain server communication\n */\n\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'\nimport Anthropic from '@anthropic-ai/sdk'\n\nexport interface BrainResult {\n output: string\n toolCalls: number\n tokensUsed: number\n}\n\n/**\n * Connect to a remote brain server via SSE MCP.\n * The serverUrl should be the SSE endpoint, e.g. http://100.x.x.x:4097/sse\n */\nexport async function connectBrain(serverUrl: string): Promise<Client> {\n const transport = new SSEClientTransport(new URL(serverUrl))\n const client = new Client({ name: 'kody-brain', version: '1.0.0' })\n await client.connect(transport)\n return client\n}\n\n/**\n * Check if brain server is reachable (HTTP health check with 5s timeout).\n */\nexport async function isBrainHealthy(serverUrl: string): Promise<boolean> {\n try {\n // Strip /sse suffix if present to get base URL for health check\n const baseUrl = serverUrl.replace(/\\/sse$/, '')\n const resp = await fetch(baseUrl, { signal: AbortSignal.timeout(5000) })\n return resp.ok\n } catch {\n return false\n }\n}\n\n/**\n * Run a brain task: connect to MCP, convert tools to Anthropic format,\n * then execute a tool-use loop with Claude API.\n */\nexport async function runBrain(\n serverUrl: string,\n systemPrompt: string,\n userMessage: string,\n model: string = 'claude-opus-4-20250514',\n): Promise<BrainResult> {\n // 1. Connect to Context+ MCP\n const mcpClient = await connectBrain(serverUrl)\n const { tools } = await mcpClient.listTools()\n\n // 2. Convert MCP tools to Anthropic tool format\n // The MCP inputSchema is JSON Schema compatible with Anthropic's tool format.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const anthropicTools: any[] = tools.map((tool) => ({\n name: tool.name,\n description: tool.description || '',\n input_schema: tool.inputSchema,\n }))\n\n // 3. Call Claude with tools\n const anthropic = new Anthropic()\n type MessageRole = 'user' | 'assistant'\n type MessageContent = string | unknown\n const messages: Array<{ role: MessageRole; content: MessageContent }> = [\n { role: 'user', content: userMessage },\n ]\n let toolCalls = 0\n let totalTokens = 0\n\n // 4. Tool-use loop\n while (true) {\n const response = await anthropic.messages.create({\n model,\n max_tokens: 8192,\n system: systemPrompt,\n messages: messages as never,\n tools: anthropicTools,\n })\n\n totalTokens += response.usage.input_tokens + response.usage.output_tokens\n\n // If no tool use, we're done\n if (response.stop_reason === 'end_turn') {\n const textBlock = response.content.find((b) => b.type === 'text')\n await mcpClient.close()\n return {\n output: textBlock?.text || '',\n toolCalls,\n tokensUsed: totalTokens,\n }\n }\n\n // Execute tool calls against Context+ MCP\n const toolResults: Array<{\n type: 'tool_result'\n tool_use_id: string\n content: Array<{ type: 'text'; text: string }>\n }> = []\n for (const block of response.content) {\n if (block.type === 'tool_use') {\n toolCalls++\n const result = await mcpClient.callTool({\n name: block.name,\n arguments: block.input as Record<string, unknown>,\n })\n toolResults.push({\n type: 'tool_result',\n tool_use_id: block.id,\n content: [{ type: 'text', text: String(result.content) }],\n })\n }\n }\n\n // Add assistant response + tool results to conversation\n messages.push({ role: 'assistant', content: response.content as never })\n messages.push({ role: 'user', content: toolResults })\n }\n}\n","/**\n * @fileType handler\n * @domain kody | brain | architect\n * @ai-summary Brain-based architect stage that replaces taskify+gap+architect\n */\n\nimport { runBrain } from './brain-client'\n\nconst ARCHITECT_PROMPT = `You are the architect for the Kody pipeline.\nYour job is to analyze a task and produce two outputs:\n\n1. task.json — structured task definition\n2. plan.md — detailed implementation plan with TDD test gates\n\nYou have access to codebase intelligence tools. USE THEM:\n- semantic_code_search: Find relevant code by meaning\n- get_blast_radius: Check what depends on a symbol before changing it\n- get_file_skeleton: See function signatures without reading full files\n- get_context_tree: Understand project structure\n- search_memory_graph: Check if similar tasks were done before\n- semantic_navigate: Browse codebase by meaning clusters\n\nWORKFLOW:\n1. Read the task description\n2. Use semantic_code_search to find relevant existing code\n3. Use get_blast_radius on any functions you plan to modify\n4. Use get_context_tree to understand the area of the codebase\n5. Use search_memory_graph for lessons from previous tasks\n6. Produce task.json and plan.md\n\nOutput format:\n\\`\\`\\`json:task.json\n{ ... }\n\\`\\`\\`\n\n\\`\\`\\`markdown:plan.md\n# Plan\n...\n\\`\\`\\`\n`\n\nexport interface ArchitectResult {\n taskJson: object\n planMd: string\n}\n\n/**\n * Run the architect stage using the remote brain.\n * Parses task.json and plan.md from the brain's output.\n */\nexport async function runArchitectBrain(\n taskMd: string,\n brainUrl: string,\n): Promise<ArchitectResult> {\n const result = await runBrain(brainUrl, ARCHITECT_PROMPT, taskMd)\n\n // Parse task.json and plan.md from output\n const taskJsonMatch = result.output.match(/```json:task\\.json\\n([\\s\\S]*?)```/)\n const planMdMatch = result.output.match(/```markdown:plan\\.md\\n([\\s\\S]*?)```/)\n\n return {\n taskJson: taskJsonMatch ? JSON.parse(taskJsonMatch[1]) : {},\n planMd: planMdMatch?.[1] || result.output,\n }\n}\n","/**\n * @fileType handler\n * @domain kody | brain | review\n * @ai-summary Brain-based review stage using remote brain server\n */\n\nimport { runBrain } from './brain-client'\n\nconst REVIEW_PROMPT = `You are the code reviewer for the Kody pipeline.\nYour job is to review code changes against the plan and produce a review.\n\nYou have access to codebase intelligence tools. USE THEM:\n- get_blast_radius: Check if changes break anything else\n- semantic_code_search: Find related code that might need updating\n- run_static_analysis: Run linters for type errors and dead code\n- get_file_skeleton: Check if changed functions match existing patterns\n- search_memory_graph: Check for known issues with similar changes\n\nWORKFLOW:\n1. Read the plan and changed files\n2. Use get_blast_radius on every modified function\n3. Use run_static_analysis on changed files\n4. Use semantic_code_search to find related code that might be affected\n5. Produce review.md with findings\n\nBe specific. Reference file paths and line numbers.\nCategorize findings as: critical (blocks merge), warning (should fix), info (suggestion).\n`\n\n/**\n * Run the review stage using the remote brain.\n */\nexport async function runReviewBrain(\n planMd: string,\n changedFiles: string[],\n diffs: string,\n brainUrl: string,\n): Promise<string> {\n const userMessage = `## Plan\\n${planMd}\\n\\n## Changed Files\\n${changedFiles.join('\\n')}\\n\\n## Diffs\\n${diffs}`\n const result = await runBrain(brainUrl, REVIEW_PROMPT, userMessage)\n return result.output\n}\n","/**\n * @fileType handler\n * @domain kody | modes | brain\n * @ai-summary Brain-aware full mode — uses remote brain for architect + review when available\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext } from '../engine/types'\nimport { PipelinePausedError } from '../engine/types'\nimport { runPipeline } from '../engine/state-machine'\nimport { resolvePipelineForMode } from '../engine/pipeline-resolver'\nimport { logger } from '../logger'\nimport { ensureTaskMd } from '../task-setup'\nimport { isBrainAvailable } from '../brain-health'\nimport { runArchitectBrain } from '../architect-brain'\nimport { runReviewBrain } from '../review-brain'\nimport { parseTaskDefinition } from '../pipeline/task-schema'\n\n/**\n * Brain-aware full mode handler.\n *\n * When BRAIN_SERVER_URL is set and brain is reachable:\n * 1. Run remote architect (replaces taskify + gap + architect)\n * 2. Write task.json + plan.md to taskDir\n * 3. Run local impl pipeline (build + verify)\n * 4. Run remote review\n * 5. Write review.md to taskDir\n * 6. Proceed to commit + PR\n *\n * When brain is unavailable:\n * Falls back to standard full pipeline.\n */\nexport async function runBrainFullMode(ctx: PipelineContext): Promise<void> {\n const BRAIN_SERVER_URL = process.env.BRAIN_SERVER_URL\n\n // Check brain availability\n const brainAvailable = await isBrainAvailable(BRAIN_SERVER_URL)\n\n if (!brainAvailable || !BRAIN_SERVER_URL) {\n logger.info('🧠 Brain server unavailable — falling back to standard pipeline')\n // Import and call standard full mode\n const { runFullMode } = await import('./full')\n return runFullMode(ctx)\n }\n\n logger.info('🧠 Brain server available — using remote architect + review')\n\n // R4: Ensure task.md exists before running pipeline\n await ensureTaskMd(ctx)\n\n // Read task.md for architect input\n const taskMdPath = path.join(ctx.taskDir, 'task.md')\n const taskMd = fs.readFileSync(taskMdPath, 'utf-8')\n\n // Phase 1: Remote architect (replaces taskify + gap + architect)\n logger.info(' 🧠 Running remote architect...')\n let taskJson: object = {}\n let planMd = ''\n\n try {\n const result = await runArchitectBrain(taskMd, BRAIN_SERVER_URL)\n taskJson = result.taskJson\n planMd = result.planMd\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error)\n logger.error({ err: error }, ` 🧠 Architect brain failed: ${errorMsg}`)\n logger.info(' Falling back to standard pipeline...')\n const { runFullMode } = await import('./full')\n return runFullMode(ctx)\n }\n\n // Validate and write task.json\n try {\n const validatedTask = parseTaskDefinition(taskJson)\n const taskJsonPath = path.join(ctx.taskDir, 'task.json')\n fs.writeFileSync(taskJsonPath, JSON.stringify(validatedTask, null, 2) + '\\n')\n ctx.taskDef = validatedTask\n logger.info(' ✅ task.json written')\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error)\n logger.warn({ err: error }, ` ⚠️ task.json validation failed, using raw output: ${errorMsg}`)\n // Write raw JSON as fallback\n const taskJsonPath = path.join(ctx.taskDir, 'task.json')\n fs.writeFileSync(taskJsonPath, JSON.stringify(taskJson, null, 2) + '\\n')\n }\n\n // Write plan.md\n const planMdPath = path.join(ctx.taskDir, 'plan.md')\n fs.writeFileSync(planMdPath, planMd)\n logger.info(' ✅ plan.md written')\n\n // Resolve profile from task.json\n let profile: 'standard' | 'lightweight' | 'turbo' = 'standard'\n if (ctx.taskDef?.pipeline_profile) {\n profile = ctx.taskDef.pipeline_profile\n }\n ctx.profile = profile\n logger.info(`ℹ️ Profile: ${profile}`)\n\n // Phase 2: Local impl pipeline (build + verify)\n // Uses 'impl' mode to skip spec stages (already done by brain)\n const pipeline = resolvePipelineForMode('impl', profile, false, ctx)\n logger.info(' 🔨 Running local impl pipeline (build + verify)...')\n const finalState = await runPipeline(ctx, pipeline)\n\n // Handle paused state (gate approval required)\n if (finalState.state === 'paused') {\n throw new PipelinePausedError(`Pipeline paused — awaiting gate approval for ${ctx.taskId}`)\n }\n\n // Phase 3: Remote review\n logger.info(' 🧠 Running remote review...')\n const changedFiles = getChangedFiles(ctx.taskDir)\n const diffs = getDiffs()\n\n try {\n const reviewMd = await runReviewBrain(planMd, changedFiles, diffs, BRAIN_SERVER_URL)\n const reviewMdPath = path.join(ctx.taskDir, 'review.md')\n fs.writeFileSync(reviewMdPath, reviewMd)\n logger.info(' ✅ review.md written')\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error)\n logger.warn({ err: error }, ` ⚠️ Review brain failed: ${errorMsg}`)\n // Write placeholder review\n const reviewMdPath = path.join(ctx.taskDir, 'review.md')\n fs.writeFileSync(\n reviewMdPath,\n `# Review\\n\\nBrain review unavailable: ${errorMsg}\\n\\nRun standard pipeline to get a proper review.`,\n )\n }\n\n logger.info('\\n✅ Brain-aware full Kody pipeline complete!')\n}\n\n/**\n * Get list of changed files from git.\n */\n/* eslint-disable @typescript-eslint/no-require-imports */\nfunction getChangedFiles(_taskDir: string): string[] {\n try {\n const { execFileSync } = require('child_process')\n const diff = execFileSync('git', ['diff', '--name-only'], { encoding: 'utf-8' }).trim()\n const untracked = execFileSync('git', ['ls-files', '--others', '--exclude-standard'], {\n encoding: 'utf-8',\n }).trim()\n const allChanged = [...diff.split('\\n'), ...untracked.split('\\n')]\n .filter(Boolean)\n .filter((f: string) => !f.startsWith('.tasks/') && !f.startsWith('node_modules/'))\n return allChanged\n } catch {\n return []\n }\n}\n\n/**\n * Get git diff for changed files.\n */\n/* eslint-disable @typescript-eslint/no-require-imports */\nfunction getDiffs(): string {\n try {\n const { execFileSync } = require('child_process')\n const diff = execFileSync('git', ['diff'], { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 })\n return diff\n } catch {\n return ''\n }\n}\n","/**\n * @fileType utility\n * @domain kody | rerun\n * @ai-summary Pure function to resolve rerun fromStage with feedback routing\n */\n\nimport { STAGE_NAMES as ALL_STAGES } from './stages/registry'\n\n/**\n * When feedback is provided and fromStage is AFTER architect in the impl pipeline,\n * back up to architect so the plan can be revised with the feedback.\n *\n * Only backs up if fromStage is strictly AFTER plan-gap (i.e., build or later).\n * If fromStage IS architect or plan-gap, keep it (architect already reads feedback,\n * plan-gap is between architect and build so architect would run first anyway on reset).\n *\n * If fromStage is NOT in the impl stages (e.g., a spec stage like 'taskify'),\n * it's left unchanged — spec stages don't have an architect to back up to.\n */\nexport function resolveRerunFromStage(\n fromStage: string,\n feedback: string | undefined,\n implStages: string[],\n): string {\n // No feedback → no change\n if (!feedback) return fromStage\n\n const architectIdx = implStages.indexOf('architect')\n const fromIdx = implStages.indexOf(fromStage)\n\n // fromStage not in impl stages (e.g., spec stage like 'taskify') → no change\n if (fromIdx === -1 || architectIdx === -1) return fromStage\n\n // Only back up if fromStage is strictly after plan-gap (i.e., build or later)\n // architect=0, plan-gap=1, build=2, commit=3, ...\n const planGapIdx = implStages.indexOf('plan-gap')\n const threshold = planGapIdx !== -1 ? planGapIdx : architectIdx\n\n if (fromIdx > threshold) {\n return 'architect'\n }\n\n return fromStage\n}\n\n/**\n * After a gate is approved in rerun mode, determine which stage to reset FROM.\n * We must NOT reset the approved stage itself (that would overwrite the approval).\n * Instead, return the next stage in the pipeline after the approved gate.\n *\n * Fix for issue #673: gate approval overwritten by resetFromStage.\n *\n * @param approvedStage - The stage that was just approved (e.g., 'taskify')\n * @param pipelineOrder - Flat list of all stages in execution order\n * @returns The next stage after the approved one, or the approved stage itself as fallback\n */\nexport function resolveFromStageAfterGateApproval(\n approvedStage: string,\n pipelineOrder: string[],\n): string {\n const approvedIdx = pipelineOrder.indexOf(approvedStage)\n if (approvedIdx === -1) return approvedStage\n\n const nextIdx = approvedIdx + 1\n if (nextIdx < pipelineOrder.length) {\n return pipelineOrder[nextIdx]\n }\n\n // Edge case: approved stage is the last stage — return itself\n return approvedStage\n}\n\n/**\n * Find the nearest earlier stage in the pipeline order.\n * Uses ALL_STAGES as a reference to determine ordering.\n * Falls back to first stage in pipeline if nothing earlier exists.\n *\n * @param missingStage - The stage that is not in the pipeline (e.g., 'gap' in lightweight)\n * @param pipelineOrder - The pipeline's stage order (may not include all ALL_STAGES)\n * @returns The nearest earlier stage that exists in pipelineOrder, or pipelineOrder[0] as fallback\n */\nexport function findNearestEarlierStage(missingStage: string, pipelineOrder: string[]): string {\n const missingIdx = ALL_STAGES.indexOf(missingStage as (typeof ALL_STAGES)[number])\n if (missingIdx === -1) return pipelineOrder[0] // unknown stage -> first stage\n\n // Walk backwards through ALL_STAGES to find the nearest one that exists in pipeline\n for (let i = missingIdx - 1; i >= 0; i--) {\n const stage = ALL_STAGES[i]\n if (pipelineOrder.includes(stage)) {\n return stage\n }\n }\n\n // Nothing earlier exists, use first pipeline stage\n return pipelineOrder[0]\n}\n","/**\n * @fileType handler\n * @domain kody | modes\n * @ai-summary Pipeline mode handler — extracted from entry.ts for modularity\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext } from '../engine/types'\nimport type { StageName } from '../stages/registry'\nimport { runPipeline } from '../engine/state-machine'\nimport { resolvePipelineForMode } from '../engine/pipeline-resolver'\nimport { logger } from '../logger'\nimport { readTask } from '../pipeline-utils'\n\nimport { flattenPipelineOrder } from '../pipeline/definitions'\nimport {\n resolveRerunFromStage,\n resolveFromStageAfterGateApproval,\n findNearestEarlierStage,\n} from '../rerun-utils'\nimport { getLastFailedStage, getLastPausedStage } from '../kody-utils'\nimport { checkoutTaskBranch } from '../git-utils'\nimport { runFullMode } from './full'\n\nexport async function runRerunMode(ctx: PipelineContext): Promise<void> {\n const { input, taskDir } = ctx\n logger.info('Running Kody RERUN pipeline...\\n')\n\n // G33: Check for paused stage FIRST - if we're resuming from a gate approval,\n // we should continue even if spec.md doesn't exist (it may not have been created yet\n // because the gate paused before resolve-profile post-action ran)\n const pausedStage = !input.fromStage ? getLastPausedStage(input.taskId) : null\n let gateApprovedStage: string | null = null\n\n // Early branch checkout: In CI, rerun mode starts on dev but task files\n // (spec.md, task.md, task.json) live on the feature branch. Checkout the\n // task's feature branch BEFORE checking for files, otherwise we'll falsely\n // fall back to full mode and fail with \"task.md not found\".\n if (process.env.GITHUB_ACTIONS && !input.dryRun) {\n const checkedOut = checkoutTaskBranch(input.taskId, taskDir)\n if (!checkedOut) {\n logger.info('No feature branch found for task — falling back to full pipeline')\n input.mode = 'full'\n await runFullMode(ctx)\n return\n }\n }\n\n // G33: Fallback to full only if spec.md missing AND no paused stage to resume\n const specPath = path.join(taskDir, 'spec.md')\n if (!fs.existsSync(specPath) && !pausedStage) {\n logger.info('No spec.md found — falling back to full pipeline')\n input.mode = 'full'\n await runFullMode(ctx)\n return\n }\n\n // FIX #5: Check for paused stage first (gate approval scenario)\n // This handles the case where @kody approve was used to resume a paused pipeline\n if (pausedStage) {\n logger.info(`Detected paused stage: ${pausedStage}`)\n\n // Helper to approve a gate — writes approval file, commits, and updates state\n const approveGate = async (\n ctx: PipelineContext,\n stage: string,\n reason: string,\n ): Promise<void> => {\n logger.info(`Gate ${stage} ${reason} — resuming pipeline`)\n\n // Write gate-{stage}-approved.md with the approval reason\n const approvedPath = path.join(ctx.taskDir, `gate-${stage}-approved.md`)\n fs.writeFileSync(\n approvedPath,\n `# Gate Approved\\n\\nApproved at ${stage} gate.\\nApproved by: ${reason}\\nApproved at: ${new Date().toISOString()}\\n`,\n )\n\n // Commit and push the approval files so subsequent runs can find them\n const { commitPipelineFiles } = await import('../git-utils')\n await commitPipelineFiles({\n taskDir: ctx.taskDir,\n taskId: ctx.input.taskId,\n message: `ci(kody): gate ${stage} ${reason} for ${ctx.input.taskId}`,\n ensureBranch: true,\n stagingStrategy: 'task-only',\n push: true,\n isCI: !ctx.input.local,\n dryRun: ctx.input.dryRun,\n })\n\n // Mark the paused stage as completed in status (immutable update)\n const { loadState, writeState, resumeFromGate } = await import('../engine/status')\n const state = loadState(ctx.input.taskId)\n if (state) {\n const resumedState = resumeFromGate(state, stage)\n writeState(ctx.input.taskId, resumedState)\n }\n }\n\n // Try to approve the gate directly\n try {\n const taskDef = readTask(taskDir)\n if (taskDef) {\n const { handleGateApproval } = await import('../clarify-workflow')\n const gateResult = handleGateApproval(input, taskDir, pausedStage, taskDef)\n\n if (gateResult === 'approved') {\n // Explicit approval via @kody approve — use the helper\n await approveGate(ctx, pausedStage, 'approved by user')\n gateApprovedStage = pausedStage\n\n // After approving a spec-phase gate, continue with the rerun pipeline\n // The rerun pipeline already includes both spec and impl stages\n // No mode switch needed - just continue running\n } else if (gateResult === 'waiting') {\n // Implicit approval: @kody rerun is a clear signal the user wants to proceed\n // No need to separately approve a gate they've already seen\n await approveGate(ctx, pausedStage, 'implicitly approved via @kody rerun')\n gateApprovedStage = pausedStage\n }\n }\n } catch (err) {\n logger.warn({ err }, 'Could not handle gate approval')\n }\n }\n\n // G37: Read task definition for profile resolution (MUST be before fromStage resolution)\n let taskDef = null\n try {\n taskDef = readTask(taskDir)\n } catch {\n logger.warn('Could not read task.json for profile resolution, using default')\n }\n ctx.taskDef = taskDef\n if (taskDef) {\n const { resolvePipelineProfile } = await import('../pipeline-utils')\n ctx.profile = resolvePipelineProfile(taskDef)\n }\n\n // --turbo flag: hard override to turbo profile\n if (ctx.input.turbo) {\n ctx.profile = 'turbo'\n logger.info('⚡ Turbo mode: forcing turbo profile')\n }\n\n // Track if fromStage was explicitly provided (via CLI) vs derived from failed/paused stage\n // If explicitly provided, don't inject default feedback (prevents backup to architect on auto-retries)\n const fromStageExplicitlyProvided = !!input.fromStage\n\n // Determine fromStage\n // FIX #673: After gate approval, use the NEXT stage (not the approved one)\n // to prevent resetFromStage from overwriting the gate approval\n if (!input.fromStage) {\n if (gateApprovedStage) {\n // Gate was just approved — resolve pipeline order to find the next stage\n const tempPipeline = resolvePipelineForMode('rerun', ctx.profile, false, ctx)\n const tempOrder = flattenPipelineOrder(tempPipeline.order)\n input.fromStage = resolveFromStageAfterGateApproval(gateApprovedStage, tempOrder)\n // R3-FIX #2: Trigger pipeline rebuild after gate approval.\n // The profile or task definition may have changed between the original run\n // and this rerun — rebuilding ensures the correct stages are used.\n ctx.pipelineNeedsRebuild = true\n logger.info(` ℹ️ Gate approved at ${gateApprovedStage} — resuming from ${input.fromStage}`)\n } else {\n // FIX #827: When pipeline state is 'failed', prefer failed stage over paused stage.\n // A stale 'paused' state (e.g., taskify gate was approved but state wasn't updated)\n // should not override the actual failed stage (e.g., build).\n const { loadState: loadSt3 } = await import('../engine/status')\n const prevState = loadSt3(input.taskId)\n const failedStage = getLastFailedStage(input.taskId)\n\n if (prevState?.state === 'failed' && failedStage) {\n // Pipeline failed — resume from the failed stage, not from a stale paused stage\n logger.info(\n ` ℹ️ Pipeline state is 'failed' — using failed stage '${failedStage}' over paused stage '${pausedStage}'`,\n )\n input.fromStage = failedStage\n } else {\n // Pipeline is paused or unknown — use paused stage (gate approval scenario)\n input.fromStage = pausedStage || failedStage || 'build'\n }\n }\n }\n\n // Default feedback - but only if fromStage wasn't explicitly provided\n // This prevents unnecessary backup to architect on auto-retries (pipeline-fixer)\n if (!input.feedback && !fromStageExplicitlyProvided) {\n input.feedback = 'Rerun requested via /kody rerun'\n }\n\n // G37: Write feedback file\n const feedbackFile = path.join(taskDir, 'rerun-feedback.md')\n try {\n fs.writeFileSync(\n feedbackFile,\n `# Rerun Feedback - ${new Date().toISOString()}\\n\\n## Issues Found\\n\\n${input.feedback}\\n`,\n )\n } catch (writeErr) {\n logger.error({ err: writeErr }, `Failed to write rerun feedback file: ${feedbackFile}`)\n throw writeErr\n }\n\n logger.info(`Feedback: ${input.feedback}`)\n logger.info(`From stage: ${input.fromStage}\\n`)\n\n // H2 fix: resolve pipeline BEFORE resolveRerunFromStage so we use profile-aware\n // impl stage order. Previously hardcoded IMPL_ORDER_STANDARD which caused turbo\n // rerun with feedback to back up to 'architect' (doesn't exist in turbo).\n const pipeline = resolvePipelineForMode('rerun', ctx.profile, false, ctx)\n const stageOrder = flattenPipelineOrder(pipeline.order)\n\n // P3 fix: Back up to architect when feedback provided so plan can be revised\n // BUT: Don't back up if fromStage was explicitly provided (via CLI --from or pipeline-fixer)\n // This prevents pipeline-fixer retries from unnecessarily re-running architect\n let resolvedFrom = input.fromStage || 'build'\n if (!fromStageExplicitlyProvided && input.feedback) {\n resolvedFrom = resolveRerunFromStage(resolvedFrom, input.feedback, stageOrder)\n if (resolvedFrom !== input.fromStage) {\n logger.info(\n ` ℹ️ Feedback provided — backing up from ${input.fromStage} to ${resolvedFrom} for plan revision`,\n )\n }\n }\n\n // Fix 5: Validate fromStage exists in the resolved pipeline order\n let fromStage = resolvedFrom\n if (!stageOrder.includes(fromStage as StageName)) {\n const fallback = findNearestEarlierStage(fromStage, stageOrder)\n logger.warn(\n `Stage \"${fromStage}\" not in pipeline (valid: ${stageOrder.join(', ')}). Falling back to \"${fallback}\".`,\n )\n fromStage = fallback\n }\n\n const { loadState, resetFromStage, writeState } = await import('../engine/status')\n const state = loadState(input.taskId)\n if (state) {\n // H4 FIX: resetFromStage now handles both state reset AND output file deletion\n // No need to manually delete files here - that was causing double-delete\n const newState = resetFromStage(state, fromStage, stageOrder, taskDir)\n writeState(input.taskId, newState)\n\n // FIX: Update lifecycle label from failed → building so dashboard shows correct status during rerun\n if (input.issueNumber && !input.local) {\n const { setLifecycleLabel } = await import('../github-api')\n setLifecycleLabel(input.issueNumber, 'kody:building')\n }\n }\n\n // Run impl pipeline\n await runPipeline(ctx, pipeline)\n\n logger.info('\\n✅ Rerun complete!')\n}\n","/**\n * @fileType handler\n * @domain kody | modes\n * @ai-summary Pipeline mode handler — extracted from entry.ts for modularity\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext } from '../engine/types'\nimport { PipelinePausedError } from '../engine/types'\nimport { runPipeline } from '../engine/state-machine'\nimport { resolvePipelineForMode } from '../engine/pipeline-resolver'\nimport { logger } from '../logger'\nimport { readTask } from '../pipeline-utils'\nimport { mergeDefaultBranch } from '../git-utils'\n\nimport { getIssueBody, getLinkedIssueFromPR, discoverTaskIdFromIssue } from '../github-api'\nimport { getTaskDir, ensureTaskDir } from '../kody-utils'\nimport { flattenPipelineOrder } from '../pipeline/definitions'\nimport { resetFromStage } from '../engine/status'\n\nexport async function runFixMode(ctx: PipelineContext): Promise<void> {\n const { input } = ctx\n logger.info('Running Kody FIX pipeline (full pipeline with original task context)...\\n')\n\n // ===========================================================================\n // Step 0: Merge default branch to get latest fixes\n // ===========================================================================\n if (input.isPullRequest) {\n try {\n mergeDefaultBranch(process.cwd())\n } catch (error) {\n logger.error({ error }, 'Failed to merge default branch, continuing anyway')\n }\n }\n\n // ===========================================================================\n // Step 1: Resolve original task ID from PR → issue → original task\n // ===========================================================================\n let originalTaskId = input.taskId\n let linkedIssueNumber: number | null = null\n\n if (input.isPullRequest && input.issueNumber) {\n const prNumber = input.issueNumber\n\n // Get linked issue from PR\n linkedIssueNumber = getLinkedIssueFromPR(prNumber)\n if (linkedIssueNumber) {\n logger.info(`Found linked issue #${linkedIssueNumber} from PR #${prNumber}`)\n\n // Discover original task from the issue\n const discoveredTaskId = discoverTaskIdFromIssue(linkedIssueNumber)\n if (discoveredTaskId && discoveredTaskId !== input.taskId) {\n logger.info(`Switching from fix task ${input.taskId} to original task ${discoveredTaskId}`)\n originalTaskId = discoveredTaskId\n\n // Update input and context\n input.taskId = originalTaskId\n }\n } else {\n logger.warn(`No linked issue found for PR #${prNumber}, using current task`)\n }\n }\n\n // Get the original task's directory\n const originalTaskDir = getTaskDir(originalTaskId)\n ctx.taskDir = originalTaskDir\n\n // ===========================================================================\n // Step 2: Archive previous artifacts to prev-run/\n // ===========================================================================\n const prevRunDir = path.join(originalTaskDir, 'prev-run')\n if (!fs.existsSync(prevRunDir)) {\n fs.mkdirSync(prevRunDir, { recursive: true })\n }\n\n // Copy existing markdown files to prev-run/\n const mdFiles = [\n 'spec.md',\n 'plan.md',\n 'gap.md',\n 'build.md',\n 'review.md',\n 'context.md',\n 'test.md',\n 'rerun-feedback.md',\n ]\n for (const mdFile of mdFiles) {\n const srcPath = path.join(originalTaskDir, mdFile)\n const destPath = path.join(prevRunDir, mdFile)\n if (fs.existsSync(srcPath)) {\n fs.copyFileSync(srcPath, destPath)\n logger.info(`Archived ${mdFile} to prev-run/`)\n }\n }\n\n // Copy task.json and status.json if they exist\n const jsonFiles = ['task.json', 'status.json']\n for (const jsonFile of jsonFiles) {\n const srcPath = path.join(originalTaskDir, jsonFile)\n const destPath = path.join(prevRunDir, jsonFile)\n if (fs.existsSync(srcPath)) {\n fs.copyFileSync(srcPath, destPath)\n logger.info(`Archived ${jsonFile} to prev-run/`)\n }\n }\n\n // ===========================================================================\n // Step 3: Compose task.md from issue body + fix comment\n // ===========================================================================\n const issueBody = linkedIssueNumber ? getIssueBody(linkedIssueNumber) : null\n\n // Get the fix comment from input.feedback\n const fixComment = input.feedback || 'Fix requested via @kody fix command'\n\n // Compose task.md content\n let taskMdContent = `# Fix Request\\n\\n`\n if (issueBody) {\n taskMdContent += `## Original Request (Issue #${linkedIssueNumber})\\n\\n${issueBody}\\n\\n`\n }\n taskMdContent += `## Fix Feedback\\n\\n${fixComment}\\n\\n`\n taskMdContent += `---\\n\\n`\n taskMdContent += `*This is a FIX for an existing implementation. Previous artifacts are archived in prev-run/ for context.*\\n`\n\n // Write task.md\n const taskMdPath = path.join(originalTaskDir, 'task.md')\n fs.writeFileSync(taskMdPath, taskMdContent)\n logger.info(`Composed fresh task.md from issue body and fix comment`)\n\n // Also write rerun-feedback.md for architect/build to read\n const feedbackPath = path.join(originalTaskDir, 'rerun-feedback.md')\n fs.writeFileSync(feedbackPath, `# Fix Feedback - ${new Date().toISOString()}\\n\\n${fixComment}\\n`)\n\n // ===========================================================================\n // Step 4: Ensure task directory exists and reset state from taskify\n // ===========================================================================\n ensureTaskDir(originalTaskId)\n\n // Read task definition for profile resolution\n let taskDef = null\n try {\n taskDef = readTask(originalTaskDir)\n } catch {\n logger.warn('Could not read task.json for profile resolution, using default')\n }\n ctx.taskDef = taskDef\n if (taskDef) {\n const { resolvePipelineProfile } = await import('../pipeline-utils')\n ctx.profile = resolvePipelineProfile(taskDef)\n }\n\n // --turbo flag: hard override to turbo profile\n if (ctx.input.turbo) {\n ctx.profile = 'turbo'\n logger.info('⚡ Turbo mode: forcing turbo profile')\n }\n\n // Resolve pipeline - now uses FIX_FULL_ORDER (full impl pipeline with taskify)\n const pipeline = resolvePipelineForMode('fix', ctx.profile, false, ctx)\n const stageOrder = flattenPipelineOrder(pipeline.order)\n\n // Load existing state or create fresh state\n const {\n loadState: loadSt2,\n writeState: writeSt2,\n updateStage: updStage,\n initState: initSt,\n } = await import('../engine/status')\n\n let state = loadSt2(originalTaskId)\n\n // Create fresh state starting from taskify (reset all stages)\n if (!state) {\n state = initSt(ctx, 'fix')\n }\n\n // Reset all stages from taskify onward for a fresh run\n state = resetFromStage(state, 'taskify', stageOrder, originalTaskDir)\n\n // Mark taskify as pending to start fresh\n state = updStage(state, 'taskify', { state: 'pending', retries: 0 })\n\n // Set initial cursor to taskify\n state = {\n ...state,\n cursor: 'taskify',\n state: 'running',\n }\n writeSt2(originalTaskId, state)\n\n // ===========================================================================\n // Step 5: Run the full pipeline\n // ===========================================================================\n const finalState = await runPipeline(ctx, pipeline)\n\n // Handle paused state (gate approval required)\n if (finalState.state === 'paused') {\n throw new PipelinePausedError(`Pipeline paused — awaiting gate approval for ${ctx.taskId}`)\n }\n\n logger.info('\\n✅ Fix complete!')\n}\n","/**\n * @fileType handler\n * @domain kody | modes\n * @ai-summary Status mode handler — shows pipeline status for a task\n */\n\nimport type { PipelineContext } from '../engine/types'\nimport { stateToV1 } from '../engine/status'\nimport { formatStatusComment } from '../status-format'\nimport { postComment } from '../github-api'\nimport { logger } from '../logger'\n\nexport async function runStatusMode(ctx: PipelineContext): Promise<void> {\n const { input } = ctx\n const { loadState } = await import('../engine/status')\n\n const state = loadState(input.taskId)\n\n if (!state) {\n logger.info(`No status found for task: ${input.taskId}`)\n logger.info(`The Kody may not have run yet, or status.json was deleted.`)\n return\n }\n\n logger.info(`Status for ${input.taskId}:`)\n logger.info(state)\n\n if (input.issueNumber) {\n const v1Status = stateToV1(state)\n postComment(input.issueNumber, formatStatusComment(input, v1Status))\n }\n}\n","/**\n * @fileType handler\n * @domain kody | modes\n * @ai-summary Design system audit mode — runs token audit, a11y checks, and creates PR with fixes\n */\n\nimport { execFileSync } from 'child_process'\nimport type { PipelineContext } from '../engine/types'\nimport { logger } from '../logger'\nimport { postComment } from '../github-api'\nimport { writeFileSync, mkdirSync, readFileSync } from 'fs'\nimport { join } from 'path'\n\ninterface AuditResult {\n total: number\n fixable: number\n nonFixable: number\n byCategory: Record<string, number>\n files: string[]\n}\n\ninterface A11yResult {\n violations: number\n critical: number\n serious: number\n}\n\nexport async function runDesignSystemMode(ctx: PipelineContext): Promise<void> {\n const { input, taskId, taskDir } = ctx\n const dryRun = input.dryRun ?? false\n\n logger.info('🎨 Running Design System Audit...\\n')\n\n const results: {\n audit: AuditResult | null\n a11y: A11yResult | null\n codemodApplied: boolean\n prCreated: boolean\n suggestions: string[]\n } = {\n audit: null,\n a11y: null,\n codemodApplied: false,\n prCreated: false,\n suggestions: [],\n }\n\n // Stage 1: Run Token Audit\n logger.info('📊 Stage 1: Running token audit...')\n try {\n const auditOutput = execFileSync('pnpm', ['design:tokens:audit', 'src/ui/web'], {\n encoding: 'utf-8',\n timeout: 60000,\n })\n logger.info(auditOutput)\n\n // Parse audit output\n const auditMatch = auditOutput.match(/Total issues:\\s*(\\d+)/)\n const fixableMatch = auditOutput.match(/Fixable:\\s*(\\d+)/)\n const nonFixableMatch = auditOutput.match(/Non-fixable:\\s*(\\d+)/)\n\n results.audit = {\n total: auditMatch ? parseInt(auditMatch[1]) : 0,\n fixable: fixableMatch ? parseInt(fixableMatch[1]) : 0,\n nonFixable: nonFixableMatch ? parseInt(nonFixableMatch[1]) : 0,\n byCategory: {},\n files: [],\n }\n\n logger.info(`✅ Audit complete: ${results.audit.total} issues found`)\n } catch (error) {\n logger.warn({ err: error }, '⚠️ Token audit failed or found no issues')\n results.audit = { total: 0, fixable: 0, nonFixable: 0, byCategory: {}, files: [] }\n }\n\n // Stage 2: Run Accessibility Check (if test exists)\n logger.info('\\n♿ Stage 2: Running accessibility check...')\n try {\n execFileSync('pnpm', ['test:a11y', '--ci'], {\n encoding: 'utf-8',\n timeout: 120000,\n stdio: 'pipe',\n })\n results.a11y = { violations: 0, critical: 0, serious: 0 }\n logger.info('✅ Accessibility check passed')\n } catch {\n // A11y test might not exist, that's ok\n logger.warn(\n '⚠️ Accessibility test not found or failed (this is ok if test:a11y is not configured)',\n )\n results.a11y = null\n }\n\n // Stage 3: Apply Safe Codemod Fixes\n logger.info('\\n🔧 Stage 3: Applying safe codemod fixes...')\n if (results.audit && results.audit.fixable > 0) {\n if (dryRun) {\n logger.info(`🔍 DRY RUN: Would apply ${results.audit.fixable} codemod fixes`)\n } else {\n try {\n execFileSync('pnpm', ['design:tokens:codemod', 'src/ui/web'], {\n encoding: 'utf-8',\n timeout: 120000,\n })\n results.codemodApplied = true\n logger.info(`✅ Applied ${results.audit.fixable} codemod fixes`)\n } catch (error) {\n logger.error({ err: error }, '⚠️ Codemod failed')\n }\n }\n } else {\n logger.info('✅ No fixable issues found')\n }\n\n // Stage 4: Generate Suggestions\n logger.info('\\n💡 Stage 4: Generating suggestions...')\n if (results.audit && results.audit.nonFixable > 0) {\n results.suggestions.push(\n `Found ${results.audit.nonFixable} non-fixable patterns that may need new design tokens.`,\n )\n }\n\n // Check for components that might need refactoring\n try {\n const chatInterfacePath = join(taskDir, '../../../src/ui/web/chat/ChatInterface/index.tsx')\n const chatContent = readFileSync(chatInterfacePath, 'utf-8')\n const lineCount = chatContent.split('\\n').length\n if (lineCount > 500) {\n results.suggestions.push(\n `ChatInterface is ${lineCount} lines — consider splitting into smaller components.`,\n )\n }\n } catch {\n // File might not exist or be in different location\n }\n\n // Stage 5: Create PR or Post Results\n logger.info('\\n📝 Stage 5: Creating report...')\n\n const report = generateReport(results)\n const reportPath = join(taskDir, 'design-system-report.md')\n writeFileSync(reportPath, report, 'utf-8')\n logger.info(`Report saved to: ${reportPath}`)\n\n // Post comment to issue if available\n if (input.issueNumber) {\n const commentBody = formatComment(results, report)\n postComment(input.issueNumber, commentBody)\n logger.info(`Posted results to issue #${input.issueNumber}`)\n }\n\n // Stage 6: Create PR (if changes were made and not dry run)\n if (results.codemodApplied && !dryRun) {\n try {\n createPr(results)\n results.prCreated = true\n logger.info('✅ Created PR with design system improvements')\n } catch (error) {\n logger.error({ err: error }, '⚠️ Failed to create PR')\n }\n } else if (dryRun && results.audit && results.audit.fixable > 0) {\n logger.info('🔍 DRY RUN: PR not created (use without --dry-run to create PR)')\n }\n\n logger.info('\\n✅ Design System Audit complete!')\n logger.info(\n ` Audit: ${results.audit?.total ?? 0} issues (${results.audit?.fixable ?? 0} fixable)`,\n )\n logger.info(` A11y: ${results.a11y?.violations ?? 'N/A'} violations`)\n logger.info(` Codemod applied: ${results.codemodApplied}`)\n logger.info(` PR created: ${results.prCreated}`)\n logger.info(` Suggestions: ${results.suggestions.length}`)\n}\n\nfunction generateReport(results: {\n audit: AuditResult | null\n a11y: A11yResult | null\n codemodApplied: boolean\n suggestions: string[]\n}): string {\n return `# Design System Audit Report\n\n## Summary\n\n| Metric | Value |\n|--------|-------|\n| Total Issues | ${results.audit?.total ?? 0} |\n| Fixable (auto-applied) | ${results.audit?.fixable ?? 0} |\n| Non-fixable (needs review) | ${results.audit?.nonFixable ?? 0} |\n| A11y Violations | ${results.a11y?.violations ?? 'N/A'} |\n| Codemod Applied | ${results.codemodApplied ? 'Yes' : 'No'} |\n\n## Suggestions\n\n${\n results.suggestions.length > 0\n ? results.suggestions.map((s) => `- ${s}`).join('\\n')\n : '- No suggestions at this time.'\n}\n\n## Details\n\n${\n results.audit && results.audit.total > 0\n ? `\n### Token Issues by Category\n\n${Object.entries(results.audit.byCategory)\n .map(([cat, count]) => `- ${cat}: ${count}`)\n .join('\\n')}\n`\n : ''\n}\n\n${\n results.a11y && results.a11y.violations > 0\n ? `\n### Accessibility Issues\n\n- Critical: ${results.a11y.critical}\n- Serious: ${results.a11y.serious}\n- Total: ${results.a11y.violations}\n`\n : ''\n}\n\n---\n*Generated by Kody Design System Audit*\n`\n}\n\nfunction formatComment(\n results: {\n audit: AuditResult | null\n a11y: A11yResult | null\n codemodApplied: boolean\n suggestions: string[]\n },\n _report: string,\n): string {\n const lines = ['## 🎨 Design System Audit Results']\n\n if (results.audit) {\n lines.push(`\\n| Metric | Value |`)\n lines.push(`|--------|-------|`)\n lines.push(`| Total Issues | ${results.audit.total} |`)\n lines.push(`| Fixable | ${results.audit.fixable} |`)\n lines.push(`| Non-fixable | ${results.audit.nonFixable} |`)\n }\n\n if (results.a11y) {\n lines.push(`| A11y Violations | ${results.a11y.violations} |`)\n }\n\n lines.push(`| Codemod Applied | ${results.codemodApplied ? '✅' : '❌'} |`)\n\n if (results.suggestions.length > 0) {\n lines.push('\\n### 💡 Suggestions')\n results.suggestions.forEach((s) => {\n lines.push(`- ${s}`)\n })\n }\n\n lines.push('\\n---\\n*Triggered by @kody design-system*')\n\n return lines.join('\\n')\n}\n\nfunction createPr(results: { audit: AuditResult | null; codemodApplied: boolean }): void {\n const branchName = `design-system/audit-${new Date().toISOString().slice(0, 10)}`\n\n // Create branch\n execFileSync('git', ['checkout', '-b', branchName], { stdio: 'pipe' })\n\n // Stage changes\n execFileSync('git', ['add', 'src/ui/web/'], { stdio: 'pipe' })\n\n // Check if there are changes to commit\n try {\n execFileSync('git', ['diff', '--cached', '--quiet'], { stdio: 'pipe' })\n } catch {\n // There are changes to commit\n const message = results.audit\n ? `chore(design-system): apply ${results.audit.fixable} token fixes\n\nAutomated design system improvements:\n- Fixed ${results.audit.fixable} raw Tailwind values → design tokens\n- Applied via codemod\n\nGenerated by @kody design-system`\n : `chore(design-system): design system improvements\n\nAutomated design system improvements. Generated by @kody design-system`\n\n execFileSync('git', ['commit', '-m', message], { stdio: 'pipe' })\n\n // Push branch\n execFileSync('git', ['push', '-u', 'origin', branchName], { stdio: 'pipe' })\n\n // Create PR using gh CLI\n execFileSync(\n 'gh',\n [\n 'pr',\n 'create',\n '--title',\n '🎨 Design System Improvements (Automated)',\n '--body',\n '## Summary\\n\\nAutomated design system improvements via @kody design-system\\n\\n| Metric | Value |\\n|--------|-------|\\n| Fixable Issues | ' +\n (results.audit?.fixable ?? 0) +\n ' |\\n\\n_This PR was created automatically by the Kody design system agent._',\n '--base',\n 'main',\n ],\n { stdio: 'inherit' },\n )\n }\n}\n","/**\n * @fileType barrel-export\n * @domain kody | modes\n * @ai-summary Barrel export for pipeline mode handlers\n */\n\nexport { runSpecMode } from './spec'\nexport { runImplMode } from './impl'\nexport { runFullMode } from './full'\nexport { runBrainFullMode } from './brain-full'\nexport { runRerunMode } from './rerun'\nexport { runFixMode } from './fix'\nexport { runStatusMode } from './status'\nexport { runDesignSystemMode } from './design-system'\n","/**\n * @fileType script\n * @domain kody\n * @pattern entry-point\n * @ai-summary New CLI entry point for Kody pipeline state machine\n */\n\n// Load .env before anything else so GH_PAT, API keys, etc. are available.\n// In CI, environment variables are injected by the workflow — this is a no-op\n// if .env doesn't exist (dotenv silently skips missing files).\nimport { config as loadEnv } from 'dotenv'\nloadEnv({ path: '.env' })\n\nimport ms from 'ms'\n\nimport { parseCliArgs, validateAuth, ensureTaskDir } from './kody-utils'\nimport { preflight } from './preflight'\nimport { createRunner } from './runner-backend'\nimport { logger } from './logger'\nimport { commitPipelineFiles } from './git-utils'\n\nimport type { PipelineContext } from './engine/types'\nimport { resolvePipelineForMode } from './engine/pipeline-resolver'\nimport { flattenPipelineOrder } from './pipeline/definitions'\nimport { PipelinePausedError } from './engine/types'\nimport { startServer, stopServer, checkpointDb, findLastSessionId } from './opencode-server'\nimport {\n runSpecMode,\n runImplMode,\n runBrainFullMode,\n runRerunMode,\n runFixMode,\n runStatusMode,\n runDesignSystemMode,\n} from './modes'\n\n// FIX #3: Import status functions at module level instead of dynamic imports in signal handlers.\n// Dynamic `await import()` in signal handlers is unsafe — Node.js signal handlers have limited\n// async support and may be killed before the import resolves.\nimport {\n loadState as loadStateForSignal,\n writeState as writeStateForSignal,\n updateStage as updateStageForSignal,\n completeState as completeStateForSignal,\n} from './engine/status'\n\n// Re-export for backward compatibility (canonical source: ./task-setup)\nexport { ensureTaskMd } from './task-setup'\nimport type { OpenCodeServer } from './opencode-server'\nimport { ensureTaskMarkerComment, postComment } from './github-api'\n\n// ============================================================================\n// Failure Comment Formatting\n// ============================================================================\n\n/**\n * Build an enriched failure comment for GitHub issues.\n * Includes failed stage, error, cost, and stage progression.\n */\nfunction formatFailureComment(\n input: { taskId: string; runUrl?: string },\n state: import('./engine/types').PipelineStateV2 | null,\n error: unknown,\n): string {\n const errorMsg = error instanceof Error ? error.message : String(error)\n const lines: string[] = [`❌ Pipeline failed for \\`${input.taskId}\\``]\n\n if (state?.stages) {\n // Find the failed stage\n const failedEntry = Object.entries(state.stages).find(\n ([, s]) => s.state === 'failed' || s.state === 'timeout',\n )\n if (failedEntry) {\n const [stageName, stageState] = failedEntry\n const elapsedStr =\n stageState.elapsed != null\n ? ` (after ${Math.floor(stageState.elapsed / 60)}m ${stageState.elapsed % 60}s)`\n : ''\n lines.push(`\\n**Failed stage:** \\`${stageName}\\`${elapsedStr}`)\n }\n\n lines.push(`**Error:** ${errorMsg}`)\n\n // Total cost across all stages\n const totalCost = Object.values(state.stages).reduce((sum, s) => sum + (s.cost ?? 0), 0)\n if (totalCost > 0) {\n const completedCount = Object.values(state.stages).filter(\n (s) => s.state === 'completed',\n ).length\n lines.push(`**Cost:** $${totalCost.toFixed(2)} across ${completedCount} stages`)\n }\n\n // Stage progression\n const progression = Object.entries(state.stages)\n .map(([name, s]) => {\n if (s.state === 'completed') return `${name} ✅`\n if (s.state === 'failed' || s.state === 'timeout') return `${name} ❌`\n if (s.state === 'skipped') return `${name} ⏭`\n return null\n })\n .filter(Boolean)\n if (progression.length > 0) {\n lines.push(`**Completed:** ${progression.join(' → ')}`)\n }\n } else {\n lines.push(`\\n**Error:** ${errorMsg}`)\n }\n\n if (input.runUrl) {\n lines.push(`\\nRun: ${input.runUrl}`)\n }\n\n return lines.join('\\n')\n}\n\n// ============================================================================\n// OpenCode Server Lifecycle\n// ============================================================================\n\n/** Module-level reference to the OpenCode server for cleanup in signal handlers */\nlet openCodeServer: OpenCodeServer | null = null\n\n/**\n * Gracefully shut down the OpenCode server, checkpoint the DB, and clear the reference.\n * Safe to call multiple times (idempotent).\n */\nasync function shutdownOpenCodeServer(taskDir?: string): Promise<void> {\n if (!openCodeServer) return\n const server = openCodeServer\n openCodeServer = null\n\n await stopServer(server)\n\n // Checkpoint WAL into main DB so it's self-contained for git commits\n if (taskDir) {\n checkpointDb(taskDir)\n }\n}\n\n// ============================================================================\n\n/**\n * Main entry point\n */\nexport async function main(cliArgs?: string[]): Promise<void> {\n const args = cliArgs ?? process.argv.slice(2)\n\n // Handle --help early\n if (args.includes('--help') || args.includes('-h')) {\n console.log(`\nKody Pipeline CLI\n\nUsage: pnpm tsx scripts/kody/entry.ts [options]\n\nOptions:\n --task-id <id> Task ID (format: YYMMDD-description)\n --mode <mode> Pipeline mode: full, spec, impl, rerun, clarify, status\n --file <path> Path to task file (auto-generates task-id from filename)\n --dry-run Dry run mode\n --issue-number <n> GitHub issue number\n --trigger-type Trigger type: dispatch, comment\n --run-id <id> CI run ID\n --run-url <url> CI run URL\n --comment-body <text> Comment body (for comment triggers)\n --from <stage> Stage to restart from (for rerun mode)\n --feedback <text> Feedback for rerun mode\n --auto Auto mode (non-interactive)\n --gate Risk-gated mode (require approval)\n --hard-stop Hard stop on failure\n --local Run in local mode (skip GitHub API)\n --clarify Run clarify stage\n --complexity <1-100> Override complexity score (for testing)\n --is-pull-request Comment was on a PR (not issue)\n --fresh Force create new PR (new branch)\n\nExamples:\n pnpm tsx scripts/kody/entry.ts --task-id 260225-my-task --mode full\n pnpm tsx scripts/kody/entry.ts --file docs/feature.md\n pnpm tsx scripts/kody/entry.ts --mode rerun --from verify --feedback \"Tests failed\"\n`)\n return\n }\n\n // Parse CLI args\n const input = parseCliArgs(args)\n\n // Create a child logger with task context\n\n // R9: Shutdown guard to prevent double-execution on SIGTERM/SIGINT\n let shuttingDown = false\n // G2: Signal handlers with null guard\n const cleanupOnSignal = async (signal: string) => {\n // Prevent double execution (immediate exit on re-entry during async cleanup)\n if (shuttingDown) {\n process.exit(128 + (signal === 'SIGTERM' ? 15 : 2))\n return // unreachable but satisfies TS\n }\n shuttingDown = true\n logger.error(`\\n⚠ Received ${signal} — CI runner shutting down`)\n try {\n // FIX #3: Use module-level imports instead of dynamic import in signal context\n const state = loadStateForSignal(input.taskId)\n if (state) {\n // Mark all running stages as failed\n let updatedState = state\n for (const [name, stage] of Object.entries(state.stages)) {\n if (stage.state === 'running') {\n updatedState = updateStageForSignal(updatedState, name, {\n state: 'failed',\n error: `Process interrupted by ${signal}`,\n })\n logger.error(` Marked stage \"${name}\" as failed`)\n }\n }\n // Mark pipeline as failed\n const failedState = completeStateForSignal(updatedState, 'failed')\n writeStateForSignal(input.taskId, failedState)\n logger.error(` Updated status.json to \"failed\" for task ${input.taskId}`)\n\n // In CI mode: attempt to commit and push the updated status\n if (process.env.GITHUB_ACTIONS === 'true' && !input.local) {\n logger.error(` Attempting to commit status.json in CI...`)\n try {\n const { execFileSync } = await import('child_process')\n const SIGNAL_TIMEOUT = ms('10s') // 10s max per git op during shutdown\n // Get the directory where status.json is\n const statusPath = `./.tasks/${input.taskId}/status.json`\n execFileSync('git', ['add', statusPath], {\n stdio: 'inherit',\n timeout: SIGNAL_TIMEOUT,\n })\n execFileSync(\n 'git',\n [\n 'commit',\n '--no-gpg-sign',\n '-m',\n `ci(kody): save interrupted state for ${input.taskId}`,\n ],\n { stdio: 'inherit', timeout: SIGNAL_TIMEOUT },\n )\n execFileSync('git', ['push'], {\n stdio: 'inherit',\n timeout: SIGNAL_TIMEOUT,\n })\n logger.error(` ✅ Committed and pushed status.json`)\n } catch (commitErr) {\n logger.error({ err: commitErr }, ` ⚠️ Failed to commit/push status.json`)\n }\n }\n }\n } catch (err) {\n logger.error({ err }, ` Failed to update status`)\n }\n // Kill OpenCode server before exiting (sync-safe: just send SIGTERM).\n // We cannot await stopServer() or checkpointDb() here — the signal context\n // limits async work. The WAL checkpoint is skipped on forced shutdown;\n // SQLite will recover the WAL automatically on the next open.\n if (openCodeServer?.process && !openCodeServer.process.killed) {\n openCodeServer.process.kill('SIGTERM')\n openCodeServer = null\n }\n\n process.exit(128 + (signal === 'SIGTERM' ? 15 : 2))\n }\n\n process.on('SIGTERM', () => cleanupOnSignal('SIGTERM'))\n process.on('SIGINT', () => cleanupOnSignal('SIGINT'))\n\n logger.info(`Task: ${input.taskId}`)\n logger.info(`Mode: ${input.mode}`)\n logger.info(`Dry run: ${input.dryRun}`)\n logger.info(`Local: ${input.local}`)\n if (input.issueNumber) logger.info(`Issue: #${input.issueNumber}`)\n logger.info('')\n\n // Run preflight checks in local mode\n if (input.local) {\n preflight()\n }\n\n // Validate GitHub App authentication (skip in local mode)\n if (!input.local) {\n validateAuth()\n }\n\n // Create runner backend\n const backend = createRunner(input.local)\n\n // Ensure task directory\n const taskDir = ensureTaskDir(input.taskId)\n\n // G3: Ensure task marker comment runs for ALL modes before the mode switch\n if (input.issueNumber) {\n ensureTaskMarkerComment(input.issueNumber, input.taskId, input.mode, input.runUrl)\n }\n\n // Pre-pipeline setup per mode\n const ctx: PipelineContext = {\n taskId: input.taskId,\n taskDir,\n input,\n taskDef: null,\n profile: 'standard',\n backend,\n actor: input.actor,\n }\n\n // Start OpenCode server for persistent sessions across stages\n // Graceful degradation: if startup fails, pipeline runs without server (cold-boot each stage)\n if (input.mode !== 'status') {\n const server = await startServer(taskDir)\n if (server) {\n openCodeServer = server\n ctx.serverUrl = server.url\n logger.info(` OpenCode server available at ${server.url}`)\n\n // On rerun: recover lastSessionId from previous pipeline state\n if (input.mode === 'rerun') {\n const { loadState } = await import('./engine/status')\n const existingState = loadState(input.taskId)\n if (existingState) {\n const pipelineOrder = flattenPipelineOrder(\n resolvePipelineForMode('full', ctx.profile, false, ctx).order,\n )\n const lastSid = findLastSessionId(existingState.stages, pipelineOrder)\n if (lastSid) {\n ctx.lastSessionId = lastSid\n logger.info(` Recovered session ${lastSid} from previous run`)\n }\n }\n }\n }\n }\n\n try {\n switch (input.mode) {\n case 'spec':\n await runSpecMode(ctx)\n break\n case 'impl':\n await runImplMode(ctx)\n break\n case 'full':\n // Brain-aware: uses remote brain for architect + review when BRAIN_SERVER_URL is set\n await runBrainFullMode(ctx)\n break\n case 'rerun':\n await runRerunMode(ctx)\n break\n case 'fix':\n await runFixMode(ctx)\n break\n case 'status':\n await runStatusMode(ctx)\n break\n case 'design-system':\n await runDesignSystemMode(ctx)\n break\n default:\n throw new Error(`Unknown mode: ${input.mode}`)\n }\n } catch (error) {\n if (error instanceof PipelinePausedError) {\n // Pipeline paused — still need to shut down server and checkpoint DB\n await shutdownOpenCodeServer(taskDir)\n return\n }\n\n // G6: process.exit(1) on failure\n // Only update status if state exists and isn't already marked as failed\n // (runPipeline already marks and writes state before throwing)\n const { writeState, loadState: loadSt, completeState } = await import('./engine/status')\n const existingState = loadSt(input.taskId)\n if (existingState && existingState.state !== 'failed') {\n const failedState = completeState(existingState, 'failed')\n writeState(input.taskId, failedState)\n }\n\n const errorMsg = error instanceof Error ? error.message : String(error)\n logger.error({ err: error }, `\\n❌ Kody failed: ${errorMsg}`)\n\n // Shutdown OpenCode server before committing (ensures DB is checkpointed)\n await shutdownOpenCodeServer(taskDir)\n\n // Commit task files on failure — includes debug artifacts (*-events.jsonl, *-stderr.log)\n // for post-mortem diagnosis. On success these are excluded to keep PRs clean.\n try {\n commitPipelineFiles({\n taskDir,\n taskId: input.taskId,\n message: `ci(kody): save failed pipeline state for ${input.taskId}`,\n ensureBranch: true,\n stagingStrategy: 'task-only',\n push: !input.local,\n isCI: !input.local,\n dryRun: input.dryRun,\n pipelineFailed: true,\n })\n } catch (commitErr) {\n logger.warn({ err: commitErr }, 'Failed to commit task files on pipeline failure')\n }\n\n // Skip GitHub API calls in local mode — each call wrapped in try/catch\n // so process.exit(1) is ALWAYS reached even if GitHub API is down\n if (input.issueNumber && !input.local) {\n try {\n const { setLifecycleLabel } = await import('./github-api')\n setLifecycleLabel(input.issueNumber, 'kody:failed')\n } catch (labelErr) {\n logger.warn({ err: labelErr }, 'Failed to set failure lifecycle label')\n }\n try {\n const failureComment = formatFailureComment(input, existingState, error)\n postComment(input.issueNumber, failureComment)\n } catch (commentErr) {\n logger.warn({ err: commentErr }, 'Failed to post failure comment')\n }\n }\n process.exit(1)\n }\n\n // Success path: shutdown OpenCode server and checkpoint DB\n await shutdownOpenCodeServer(taskDir)\n\n // Explicitly exit on success. Without this the process may hang if\n // the OpenCode server left orphan listeners, timers, or file handles\n // that keep the Node event loop alive.\n process.exit(0)\n}\n\n// Run main — skip auto-invocation when imported as a module (e.g., canary tests)\nconst isDirectExecution =\n process.argv[1]?.endsWith('entry.ts') || process.argv[1]?.endsWith('entry')\nif (isDirectExecution) {\n main().catch((err) => {\n const fatalErr = err instanceof Error ? err.message : String(err)\n logger.error({ err }, `Fatal error: ${fatalErr}`)\n process.exit(1)\n })\n}\n","/**\n * @fileType utility\n * @domain kody\n * @ai-summary Validate comment trigger safety filters\n */\n\nimport { writeFileSync } from 'fs'\n\ninterface SafetyResult {\n valid: string\n reason?: string\n}\n\n// Valid author associations\nconst VALID_ASSOCIATIONS = ['OWNER', 'MEMBER', 'COLLABORATOR']\n\n// Known bot accounts (exact match)\nconst KNOWN_BOTS = ['github-actions[bot]']\n\n/**\n * Check if author is a bot\n */\nexport function isBot(author: string): boolean {\n // Exact match for known bots\n if (KNOWN_BOTS.includes(author)) return true\n // Pattern: ends with [bot]\n if (author.endsWith('[bot]')) return true\n return false\n}\n\n/**\n * Check if author association is valid\n */\nexport function isValidAssociation(association: string): boolean {\n return VALID_ASSOCIATIONS.includes(association)\n}\n\n/**\n * Check if comment contains @kody or /kody command\n */\nexport function hasKodyCommand(comment: string): boolean {\n // @kody can be anywhere in the comment\n if (comment.includes('@kody')) return true\n\n // /kody must be on first line\n const firstLine = comment.split('\\n')[0]\n if (/^\\/kody(\\s|$)/.test(firstLine)) return true\n\n return false\n}\n\n/**\n * Validate comment safety\n */\nexport function validateSafety(author: string, association: string, comment: string): SafetyResult {\n // Check if author is a bot\n if (isBot(author)) {\n return { valid: 'false', reason: 'bot' }\n }\n\n // Check author association\n if (!isValidAssociation(association)) {\n return { valid: 'false', reason: 'unauthorized' }\n }\n\n // Check for @kody or /kody pattern\n if (!hasKodyCommand(comment)) {\n return { valid: 'false', reason: 'pattern' }\n }\n\n return { valid: 'true' }\n}\n\n/**\n * Write outputs to GITHUB_OUTPUT\n */\nfunction writeOutputs(result: SafetyResult): void {\n const githubOutput = process.env.GITHUB_OUTPUT || ''\n\n if (!githubOutput) {\n console.error('GITHUB_OUTPUT not set!')\n process.exit(1)\n }\n\n const lines = [`valid=${result.valid}`]\n if (result.reason) {\n lines.push(`reason=${result.reason}`)\n }\n\n writeFileSync(githubOutput, lines.join('\\n') + '\\n')\n}\n\n/**\n * Main entry point\n */\nfunction main(): void {\n const author = process.env.AUTHOR || ''\n const association = process.env.ASSOCIATION || ''\n const comment = process.env.COMMENT_BODY || ''\n\n const result = validateSafety(author, association, comment)\n writeOutputs(result)\n}\n\n// Run if called directly\nif (import.meta.url === `file://${process.argv[1]}`) {\n main()\n}\n","/**\n * @fileType utility\n * @domain kody\n * @ai-summary Parse command inputs from dispatch or comment triggers\n */\n\nimport { logger } from './logger'\nimport { execFileSync } from 'child_process'\nimport { writeFileSync } from 'fs'\n\n// Types for outputs\ninterface ParseOutputs {\n task_id: string\n mode: string\n clarify: string\n dry_run: string\n from_stage: string\n feedback: string\n issue_number: string\n is_pull_request: string\n trigger_type: string\n comment_body: string\n valid: string\n runner: string\n version: string\n fresh: string\n complexity: string\n}\n\n// Task ID format: YYMMDD-description (e.g., 260225-auto-90)\nexport const TASK_ID_REGEX = /^[0-9]{6}-[a-zA-Z0-9-]+$/\n\n// Valid pipeline modes\nexport const VALID_MODES = ['spec', 'impl', 'rerun', 'fix', 'full', 'status']\n\n// Approval keywords (exact match only)\nexport const APPROVAL_KEYWORDS = ['approve', 'approved', 'yes', 'go', 'proceed', 'y', 'continue']\n\n/**\n * Validate task ID format\n */\nexport function isValidTaskId(taskId: string): boolean {\n return TASK_ID_REGEX.test(taskId)\n}\n\n/**\n * Normalize comment body - lowercase and trim\n */\nexport function normalizeComment(comment: string): string {\n return comment.toLowerCase().trim()\n}\n\n/**\n * Extract command after @kody or /kody prefix\n * Handles both single-line and multiline comments\n */\nexport function extractCommandAfterKody(comment: string): string {\n const normalized = normalizeComment(comment)\n // Match @kody or /kody at the start, followed by optional whitespace\n // Use 's' flag so . matches newlines for multiline comments\n const match = normalized.match(/^[\\/@]kody\\s*(.*)$/s)\n if (!match) return ''\n return match[1].trim()\n}\n\n/**\n * Discover task ID from previous bot comments on the issue\n */\nexport function discoverTaskIdFromIssue(issueNumber: string): string | null {\n try {\n const result = execFileSync(\n 'gh',\n ['issue', 'view', issueNumber, '--json', 'comments', '--jq', '.comments[].body'],\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] },\n )\n\n // Find \"Task created: `YYYYMMDD-description`\" pattern\n const match = result.match(/Task created: `([0-9]{6}-[a-zA-Z0-9-]+)`/)\n if (match) {\n return match[1]\n }\n return null\n } catch {\n return null\n }\n}\n\n/**\n * Parse dispatch inputs (workflow_dispatch trigger)\n */\nexport function parseDispatchInputs(): ParseOutputs {\n const taskId = process.env.DISPATCH_TASK_ID || ''\n\n // Validate task_id is provided\n if (!taskId) {\n return {\n ...getDefaultOutputs(),\n issue_number: process.env.DISPATCH_ISSUE_NUMBER || '',\n is_pull_request: process.env.IS_PULL_REQUEST == 'true' ? 'true' : '',\n valid: 'false',\n }\n }\n\n // Validate task-id format\n if (!isValidTaskId(taskId)) {\n logger.info(`=== Error: Invalid task-id format: ${taskId} ===`)\n logger.info('Expected format: YYMMDD-description (e.g., 260225-auto-90)')\n return {\n ...getDefaultOutputs(),\n issue_number: process.env.DISPATCH_ISSUE_NUMBER || '',\n is_pull_request: process.env.IS_PULL_REQUEST == 'true' ? 'true' : '',\n valid: 'false',\n }\n }\n\n const outputs: ParseOutputs = {\n task_id: taskId,\n mode: process.env.DISPATCH_MODE || 'full',\n clarify: process.env.DISPATCH_CLARIFY || 'false',\n dry_run: process.env.DISPATCH_DRY_RUN || 'false',\n from_stage: process.env.DISPATCH_FROM_STAGE || '',\n feedback: process.env.DISPATCH_FEEDBACK || '',\n issue_number: process.env.DISPATCH_ISSUE_NUMBER || '',\n is_pull_request: process.env.IS_PULL_REQUEST == 'true' ? 'true' : '',\n trigger_type: 'dispatch',\n comment_body: '',\n valid: 'true',\n runner: process.env.DISPATCH_RUNNER || 'github-hosted',\n version: process.env.DISPATCH_VERSION || process.env.KODY_DEFAULT_VERSION || '',\n fresh: process.env.FRESH || '',\n complexity: process.env.DISPATCH_COMPLEXITY || '',\n }\n\n logger.info(\n `=== Parsed dispatch: task_id=${outputs.task_id}, mode=${outputs.mode}, clarify=${outputs.clarify}, runner=${outputs.runner} ===`,\n )\n\n return outputs\n}\n\n/**\n * Check if an issue has the \"publish\" label\n */\nfunction hasPublishLabel(issueNumber: string): boolean {\n if (!issueNumber) return false\n try {\n const result = execFileSync(\n 'gh',\n ['issue', 'view', issueNumber, '--json', 'labels', '--jq', '.labels[].name'],\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] },\n )\n const labels = result.trim().split('\\n').filter(Boolean)\n return labels.includes('publish')\n } catch {\n return false\n }\n}\n\n/**\n * Parse comment inputs (issue_comment trigger)\n */\nexport function parseCommentInputs(): ParseOutputs {\n const safetyValid = process.env.SAFETY_VALID\n const safetyReason = process.env.SAFETY_REASON || 'unknown'\n const issueNumber = process.env.ISSUE_NUMBER || ''\n const commentBody = process.env.COMMENT_BODY || ''\n\n // Safety check first\n if (safetyValid !== 'true') {\n logger.info(`=== Safety check failed: ${safetyReason} ===`)\n return {\n ...getDefaultOutputs(),\n issue_number: issueNumber,\n valid: 'false',\n }\n }\n\n // Check for publish label - these are handled by the Publish workflow, not Kody\n if (issueNumber && hasPublishLabel(issueNumber)) {\n logger.info(`=== Issue #${issueNumber} has 'publish' label - skipping Kody pipeline ===`)\n return {\n ...getDefaultOutputs(),\n issue_number: issueNumber,\n valid: 'false',\n feedback: 'Publish issues are handled by the Publish workflow. Do not process with Kody.',\n }\n }\n\n // Initialize outputs\n const outputs: ParseOutputs = {\n ...getDefaultOutputs(),\n issue_number: issueNumber,\n trigger_type: 'comment',\n comment_body: JSON.stringify(commentBody),\n }\n\n // Extract command after @kody or /kody (MUST be before flag detection)\n const cmdAfterKody = commentBody ? extractCommandAfterKody(commentBody) : ''\n\n // Detect --fresh flag - skip taskId discovery if fresh\n const hasFreshFlag = /--fresh\\b/.test(cmdAfterKody)\n if (hasFreshFlag) {\n outputs.fresh = 'true'\n logger.info('=== Detected --fresh flag: will create new task ===')\n }\n\n // Discover task-id from previous bot comments on the issue (skip if fresh)\n if (issueNumber && !hasFreshFlag) {\n const discoveredTaskId = discoverTaskIdFromIssue(issueNumber)\n if (discoveredTaskId) {\n logger.info(`=== Discovered task-id from issue: ${discoveredTaskId} ===`)\n outputs.task_id = discoveredTaskId\n }\n }\n\n // Parse command to determine mode and flags\n if (cmdAfterKody) {\n // Detect --local flag anywhere in the command\n const hasLocalFlag = /--local\\b/.test(cmdAfterKody)\n if (hasLocalFlag) {\n outputs.runner = 'self-hosted'\n logger.info('=== Detected --local flag: will use self-hosted runner ===')\n }\n\n // Detect --github-hosted flag anywhere in the command\n const hasGithubHostedFlag = /--github-hosted\\b/.test(cmdAfterKody)\n if (hasGithubHostedFlag) {\n outputs.runner = 'github-hosted'\n logger.info('=== Detected --github-hosted flag: will use GitHub-hosted runner ===')\n }\n\n // Detect --version flag anywhere in the command\n const versionMatch = cmdAfterKody.match(/--version\\s+(\\S+)/)\n if (versionMatch) {\n outputs.version = versionMatch[1]\n logger.info(`=== Detected --version flag: ${outputs.version} ===`)\n }\n\n // Detect --from flag (both --from=stage and --from stage syntax)\n const fromMatch = cmdAfterKody.match(/--from[=\\s](\\S+)/)\n if (fromMatch) {\n outputs.from_stage = fromMatch[1]\n logger.info(`=== Detected --from flag: ${outputs.from_stage} ===`)\n }\n\n // Detect --feedback flag (both --feedback=text and --feedback text syntax)\n const feedbackMatch = cmdAfterKody.match(/--feedback[=\\s](\\S+)/)\n if (feedbackMatch) {\n outputs.feedback = feedbackMatch[1]\n logger.info(`=== Detected --feedback flag: ${outputs.feedback} ===`)\n }\n\n // Strip flags from command before mode parsing\n const cmdWithoutFlags = cmdAfterKody\n .replace(/--local\\b/g, '')\n .replace(/--github\\b/g, '')\n .replace(/--github-hosted\\b/g, '')\n .replace(/--version\\s+\\S+/g, '')\n .replace(/--fresh\\b/g, '')\n .replace(/--from[=\\s]\\S+/g, '')\n .replace(/--feedback[=\\s]\\S+/g, '')\n .trim()\n\n if (!cmdWithoutFlags) {\n // @kody alone (or @kody --local) - default to full mode\n outputs.mode = 'full'\n logger.info('=== @kody alone - defaulting to full mode ===')\n } else {\n // Check if the first word is a known mode or approval keyword\n // This handles commands like \"/kody rerun 260218-task\" where extra args follow the mode\n const firstWord = cmdWithoutFlags.split(/[\\s\\n]/)[0]\n if (APPROVAL_KEYWORDS.includes(firstWord)) {\n // Approval command with optional answer - use rerun mode\n outputs.mode = 'rerun'\n logger.info(`=== Detected approval keyword: ${firstWord} ===`)\n } else if (VALID_MODES.includes(firstWord)) {\n // First word is a valid mode (e.g., \"rerun\", \"spec\", \"impl\")\n outputs.mode = firstWord\n logger.info(`=== Detected explicit mode: ${firstWord} ===`)\n } else {\n // Not a known command - default to full (might be task-id or description)\n outputs.mode = 'full'\n logger.info('=== Not a known command - defaulting to full mode ===')\n }\n }\n }\n\n // Validate task-id format if set\n if (outputs.task_id && !isValidTaskId(outputs.task_id)) {\n logger.info(`=== Error: Invalid task-id format: ${outputs.task_id} ===`)\n logger.info('Expected format: YYMMDD-description (e.g., 260225-auto-90)')\n outputs.task_id = ''\n outputs.valid = 'false'\n } else {\n outputs.valid = 'true'\n }\n\n logger.info('=== Passing comment to orchestrator for parsing ===')\n\n return outputs\n}\n\n/**\n * Parse PR review inputs (pull_request_review trigger)\n * Automatically routes to fix mode with the review feedback as context.\n */\nexport function parsePRReviewInputs(): ParseOutputs {\n const prNumber = process.env.PR_NUMBER || process.env.ISSUE_NUMBER || ''\n const reviewState = process.env.PR_REVIEW_STATE || ''\n const reviewBody = process.env.PR_REVIEW_BODY || ''\n\n logger.info(`=== PR Review trigger: PR #${prNumber}, state=${reviewState} ===`)\n\n // Only process \"changes_requested\" reviews\n if (reviewState !== 'changes_requested') {\n logger.info(`=== Ignoring PR review with state: ${reviewState} ===`)\n return {\n ...getDefaultOutputs(),\n issue_number: prNumber,\n is_pull_request: 'true',\n valid: 'false',\n }\n }\n\n // Discover existing task ID from PR comments\n let taskId = ''\n if (prNumber) {\n const discoveredTaskId = discoverTaskIdFromIssue(prNumber)\n if (discoveredTaskId) {\n logger.info(`=== Discovered task-id from PR: ${discoveredTaskId} ===`)\n taskId = discoveredTaskId\n }\n }\n\n if (!taskId) {\n logger.info('=== No task-id found on PR — cannot run fix mode ===')\n return {\n ...getDefaultOutputs(),\n issue_number: prNumber,\n is_pull_request: 'true',\n valid: 'false',\n }\n }\n\n const outputs: ParseOutputs = {\n task_id: taskId,\n mode: 'fix',\n clarify: 'false',\n dry_run: 'false',\n from_stage: '',\n feedback: reviewBody || 'Changes requested via PR review',\n issue_number: prNumber,\n is_pull_request: 'true',\n trigger_type: 'pr_review',\n comment_body: '',\n valid: 'true',\n runner: 'github-hosted',\n version: process.env.KODY_DEFAULT_VERSION || '',\n fresh: '',\n complexity: '',\n }\n\n logger.info(\n `=== PR review → fix mode: task_id=${outputs.task_id}, feedback=${outputs.feedback.slice(0, 100)}... ===`,\n )\n\n return outputs\n}\n\n/**\n * Get default output values\n */\nexport function getDefaultOutputs(): ParseOutputs {\n return {\n task_id: '',\n mode: 'full',\n clarify: 'false',\n dry_run: 'false',\n from_stage: '',\n feedback: '',\n issue_number: process.env.DISPATCH_ISSUE_NUMBER || '',\n is_pull_request: process.env.IS_PULL_REQUEST == 'true' ? 'true' : '',\n trigger_type: '',\n comment_body: '',\n valid: 'false',\n runner: 'github-hosted',\n version: process.env.KODY_DEFAULT_VERSION || '',\n fresh: process.env.FRESH || '',\n complexity: process.env.DISPATCH_COMPLEXITY || '',\n }\n}\n\n/**\n * Write outputs to GITHUB_OUTPUT\n */\nfunction writeOutputs(outputs: ParseOutputs): void {\n const githubOutput = process.env.GITHUB_OUTPUT || ''\n\n if (!githubOutput) {\n logger.error('GITHUB_OUTPUT not set!')\n process.exit(1)\n }\n\n const lines = [\n `task_id=${outputs.task_id}`,\n `mode=${outputs.mode}`,\n `clarify=${outputs.clarify}`,\n `dry_run=${outputs.dry_run}`,\n `from_stage=${outputs.from_stage}`,\n `feedback=${outputs.feedback}`,\n `issue_number=${outputs.issue_number}`,\n `is_pull_request=${outputs.is_pull_request}`,\n `trigger_type=${outputs.trigger_type}`,\n `comment_body=${outputs.comment_body}`,\n `valid=${outputs.valid}`,\n `runner=${outputs.runner}`,\n `version=${outputs.version}`,\n `fresh=${outputs.fresh}`,\n `complexity=${outputs.complexity}`,\n ]\n\n writeFileSync(githubOutput, lines.join('\\n') + '\\n')\n}\n\n/**\n * Main entry point\n */\nfunction main(): void {\n const eventName = process.env.GITHUB_EVENT_NAME || ''\n\n let outputs: ParseOutputs\n\n if (eventName === 'workflow_dispatch') {\n outputs = parseDispatchInputs()\n } else if (eventName === 'pull_request_review') {\n outputs = parsePRReviewInputs()\n } else {\n outputs = parseCommentInputs()\n }\n\n writeOutputs(outputs)\n}\n\n// Run if called directly (not imported)\nif (import.meta.url === `file://${process.argv[1]}`) {\n main()\n}\n","/**\n * @fileType utility\n * @domain kody\n * @ai-summary Checkout existing feature branch for a task\n */\n\nimport { logger } from './logger'\nimport { execFileSync } from 'child_process'\nimport { closeLinkedPR } from './github-api'\n\n// Git branch prefixes to try\nconst BRANCH_PREFIXES = ['feat', 'fix', 'refactor', 'docs', 'chore', 'security', 'test']\n\n// Default branch fallback\nconst DEFAULT_BRANCH_FALLBACK = 'dev'\n\n// Git identity for CI (can be overridden via env vars)\nconst GIT_EMAIL = process.env.GIT_USER_EMAIL || '242132053+aguyaharonyair@users.noreply.github.com'\nconst GIT_NAME = process.env.GIT_USER_NAME || 'aguyaharonyair'\n\n/**\n * Execute git command and return output\n */\nfunction gitExec(args: string[], options: { silent?: boolean } = {}): string {\n try {\n return (\n execFileSync('git', args, {\n encoding: 'utf-8',\n stdio: options.silent ? 'ignore' : 'inherit',\n }) || ''\n )\n } catch {\n return ''\n }\n}\n\n/**\n * Execute git command that may fail\n */\nfunction gitExecSilent(args: string[]): string {\n try {\n return (\n execFileSync('git', args, {\n encoding: 'utf-8',\n }) || ''\n )\n } catch {\n return ''\n }\n}\n\n/**\n * Configure git identity\n */\nfunction configureGitIdentity(): void {\n execFileSync('git', ['config', '--global', 'user.email', GIT_EMAIL], { encoding: 'utf-8' })\n execFileSync('git', ['config', '--global', 'user.name', GIT_NAME], { encoding: 'utf-8' })\n}\n\n/**\n * Fetch latest remote refs\n */\nfunction fetchOrigin(): void {\n gitExec(['fetch', 'origin'])\n}\n\n/**\n * Get default branch name\n */\nfunction getDefaultBranch(): string {\n const output = gitExecSilent(['symbolic-ref', 'refs/remotes/origin/HEAD'])\n if (output) {\n const match = output.match(/refs\\/remotes\\/origin\\/(.+)/)\n if (match) {\n return match[1].trim()\n }\n }\n return DEFAULT_BRANCH_FALLBACK\n}\n\n/**\n * Checkout and pull branch\n */\nfunction checkoutAndPull(branch: string): void {\n gitExec(['checkout', branch])\n gitExec(['pull', 'origin', branch])\n}\n\n/**\n * Merge default branch into current branch\n */\nfunction mergeDefaultBranch(defaultBranch: string): boolean {\n try {\n gitExec(['merge', `origin/${defaultBranch}`, '--no-edit'])\n return true\n } catch {\n logger.info('=== CONFLICT: Merge failed ===')\n gitExec(['merge', '--abort'])\n return false\n }\n}\n/**\n * Reset branch if --fresh flag is set.\n * Closes any existing PR for the issue (which also deletes its branch via --delete-branch).\n * Falls back to manual branch deletion if no PR exists.\n */\nexport function resetBranchIfFresh(\n branch: string | null,\n _defaultBranch: string,\n issueNumber?: string,\n): string | null {\n const fresh = process.env.FRESH === 'true'\n if (!fresh) return branch\n\n logger.info(' --fresh flag detected: will reset branch from scratch')\n\n // Close existing PR (also deletes the branch via gh pr close --delete-branch)\n if (issueNumber) {\n logger.info(' Closing existing PR for issue #' + issueNumber)\n const prClosed = closeLinkedPR(parseInt(issueNumber, 10))\n if (prClosed) {\n // closeLinkedPR already deleted the branch via --delete-branch\n return null\n }\n }\n\n // Fallback: manually delete branch if no PR was found (branch may exist without a PR)\n if (branch) {\n logger.info(' Deleting existing branch: ' + branch)\n try {\n gitExec(['push', 'origin', '--delete', branch])\n logger.info(' Deleted remote branch')\n } catch (_e) {\n // May not exist on remote\n }\n try {\n gitExec(['branch', '-D', branch])\n logger.info(' Deleted local branch')\n } catch (_e) {\n // May not exist locally\n }\n }\n\n // Return null to force creating a new branch from default\n return null\n}\n\n/**\n * Find remote branches matching a task ID pattern.\n * Branch names use descriptive suffixes derived from the issue title,\n * so we search by the date prefix from the task ID (e.g., \"260226-auto\")\n * combined with the git branch prefix (fix/, feat/, etc.).\n */\nfunction findRemoteBranch(taskId: string): string | null {\n // Extract date prefix: \"260226-auto-18\" → \"260226-auto\"\n // For manual tasks like \"260226-my-task\" → \"260226-my\"\n const parts = taskId.split('-')\n // Use first two parts as the search pattern (date + descriptor)\n const datePrefix = parts.slice(0, 2).join('-')\n\n const remoteBranches = gitExecSilent(['branch', '-r', '--list'])\n if (!remoteBranches) return null\n\n const branches = remoteBranches\n .split('\\n')\n .map((b) => b.trim())\n .filter((b) => b && !b.includes('->'))\n .map((b) => b.replace('origin/', ''))\n\n // First, try to find branches that match by date prefix AND exact issue number\n // This prevents picking up the wrong branch when multiple issues use the same date\n const issueNumber = process.env.ISSUE_NUMBER\n if (issueNumber) {\n for (const prefix of BRANCH_PREFIXES) {\n const pattern = `${prefix}/${datePrefix}-`\n const matches = branches.filter((b) => b.startsWith(pattern))\n // Must match EXACT issue number: -699- or -699 at end, not -694-\n const issueMatch = matches.find((b) => {\n // Match -699- or -699. or -699_ or end of string\n const regex = new RegExp('-' + issueNumber + '(-|\\.|_|$)')\n return regex.test(b)\n })\n if (issueMatch) return issueMatch\n }\n // If we have an issue number but no matching branch, DON'T fall back - create new branch\n logger.info(' No branch found for issue #' + issueNumber + ', will create new branch')\n return null\n }\n\n // Collect ALL matches across ALL prefixes before deciding\n // Previously this returned on the first prefix with a single match,\n // which could pick feat/ when the correct branch was fix/\n const allMatches: string[] = []\n for (const prefix of BRANCH_PREFIXES) {\n const pattern = `${prefix}/${datePrefix}-`\n const matches = branches.filter((b) => b.startsWith(pattern))\n allMatches.push(...matches)\n }\n\n // Only return if there's exactly ONE match across all prefixes\n if (allMatches.length === 1) {\n return allMatches[0]\n }\n // If multiple matches across different prefixes, don't guess — create new branch\n\n // Also try exact match (legacy/simple branch names)\n for (const prefix of BRANCH_PREFIXES) {\n const exact = `${prefix}/${taskId}`\n if (branches.includes(exact)) return exact\n }\n\n return null\n}\n\n/**\n * Find remote branches matching an issue number (without requiring a task ID).\n * Used when --fresh flag is set and task_id is empty but issue_number is available.\n */\nfunction findRemoteBranchByIssueNumber(issueNumber: string): string | null {\n const remoteBranches = gitExecSilent(['branch', '-r', '--list'])\n if (!remoteBranches) return null\n\n const branches = remoteBranches\n .split('\\n')\n .map((b) => b.trim())\n .filter((b) => b && !b.includes('->'))\n .map((b) => b.replace('origin/', ''))\n\n // Search all prefixes for a branch containing the exact issue number\n for (const prefix of BRANCH_PREFIXES) {\n const matches = branches.filter((b) => b.startsWith(`${prefix}/`))\n const issueMatch = matches.find((b) => {\n const regex = new RegExp('-' + issueNumber + '(-|\\\\.|_|$)')\n return regex.test(b)\n })\n if (issueMatch) return issueMatch\n }\n\n return null\n}\n\n/**\n * Main entry point\n */\nfunction main(): void {\n const taskId = process.env.TASK_ID\n const issueNumber = process.env.ISSUE_NUMBER\n const fresh = process.env.FRESH === 'true'\n\n // When --fresh is used, task_id may be empty. We can still find the old branch\n // by issue number to delete it and start clean.\n if (!taskId && !issueNumber) {\n logger.error('Neither TASK_ID nor ISSUE_NUMBER set!')\n process.exit(1)\n }\n\n // Configure git identity\n configureGitIdentity()\n\n // Fetch latest\n fetchOrigin()\n\n // Get default branch\n const defaultBranch = getDefaultBranch()\n logger.info(`=== Default branch: ${defaultBranch} ===`)\n\n // Find feature branch by pattern matching\n let branch: string | null = null\n if (taskId) {\n branch = findRemoteBranch(taskId)\n } else if (issueNumber) {\n // No task ID (e.g., --fresh mode) — search by issue number\n logger.info(`=== No task ID, searching by issue number #${issueNumber} ===`)\n branch = findRemoteBranchByIssueNumber(issueNumber)\n }\n\n // Reset branch if --fresh flag is set (deletes old branch)\n branch = resetBranchIfFresh(branch, defaultBranch, issueNumber)\n\n if (branch) {\n logger.info(`=== Found feature branch: ${branch} ===`)\n\n checkoutAndPull(branch)\n\n logger.info(`=== Merging latest ${defaultBranch} into ${branch} ===`)\n\n if (!mergeDefaultBranch(defaultBranch)) {\n logger.info('=== Aborting merge ===')\n process.exit(1)\n }\n\n process.exit(0)\n }\n\n // When --fresh with no task ID, we just deleted the old branch (if found).\n // The pipeline will generate a new task ID and ensureFeatureBranch() will create a new branch.\n if (fresh && !taskId) {\n logger.info(\n `=== --fresh mode: old branch cleaned up, staying on ${defaultBranch} for new task ===`,\n )\n process.exit(0)\n }\n\n logger.info(\n `=== No feature branch found for ${taskId || 'issue #' + issueNumber}, staying on default branch ===`,\n )\n}\n\n// Run if called directly\nif (import.meta.url === `file://${process.argv[1]}`) {\n main()\n}\n","/**\n * CLI entry point for @kody-ade/kody-engine\n *\n * Commands:\n * init — Copy kody.yml workflow + opencode config to target repo\n * run — Run the Kody pipeline (default when no command given)\n * version — Print package version\n */\n\nimport { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { fileURLToPath } from \"url\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\n// Resolve paths relative to the package root (dist/bin/cli.mjs → package root)\nconst PKG_ROOT = path.resolve(__dirname, \"..\", \"..\");\n\nfunction getVersion(): string {\n const pkgPath = path.join(PKG_ROOT, \"package.json\");\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n return pkg.version;\n}\n\n// ==========================================================================\n// init command — bootstrap target repo with kody.yml + opencode config\n// ==========================================================================\n\nfunction initCommand(opts: { force: boolean; workflowOnly: boolean }) {\n const cwd = process.cwd();\n const templatesDir = path.join(PKG_ROOT, \"templates\");\n const opencodeDir = path.join(PKG_ROOT, \"opencode\");\n\n // 1. Copy kody.yml\n const workflowSrc = path.join(templatesDir, \"kody.yml\");\n const workflowDest = path.join(cwd, \".github\", \"workflows\", \"kody.yml\");\n\n if (!fs.existsSync(workflowSrc)) {\n console.error(\"Error: Template kody.yml not found in package.\");\n process.exit(1);\n }\n\n if (fs.existsSync(workflowDest) && !opts.force) {\n console.log(\n \"⚠ .github/workflows/kody.yml already exists. Use --force to overwrite.\",\n );\n } else {\n fs.mkdirSync(path.dirname(workflowDest), { recursive: true });\n fs.copyFileSync(workflowSrc, workflowDest);\n console.log(\"✓ Copied .github/workflows/kody.yml\");\n }\n\n // 2. Copy opencode agents + docs\n if (opts.workflowOnly) {\n console.log(\"\\nDone! Configure secrets in your GitHub repo settings.\");\n return;\n }\n\n if (fs.existsSync(opencodeDir)) {\n const destOpencode = path.join(cwd, \".opencode\");\n copyDirRecursive(opencodeDir, destOpencode, opts.force);\n console.log(\"✓ Copied .opencode/ (agents + docs)\");\n }\n\n // 3. Create kody.config.json if it doesn't exist\n const configDest = path.join(cwd, \"kody.config.json\");\n if (!fs.existsSync(configDest)) {\n const defaultConfig = {\n quality: {\n typecheck: \"pnpm -s tsc --noEmit\",\n lint: \"pnpm -s lint\",\n lintFix: \"pnpm lint:fix\",\n format: \"pnpm -s format:check\",\n formatFix: \"pnpm format:fix\",\n testUnit: \"pnpm -s test:unit\",\n },\n git: {\n defaultBranch: \"dev\",\n },\n github: {\n owner: \"\",\n repo: \"\",\n },\n paths: {\n taskDir: \".tasks\",\n },\n };\n fs.writeFileSync(configDest, JSON.stringify(defaultConfig, null, 2) + \"\\n\");\n console.log(\n \"✓ Created kody.config.json (edit github.owner and github.repo)\",\n );\n }\n\n console.log(`\nDone! Next steps:\n 1. Edit kody.config.json — set github.owner and github.repo\n 2. Add secrets to your GitHub repo settings:\n - MINIMAX_API_KEY (or other LLM keys)\n - GH_PAT (optional, for cross-repo operations)\n 3. Commit and push the workflow file\n 4. Comment \"@kody full <task-id>\" on any issue to run the pipeline\n`);\n}\n\n// ==========================================================================\n// run command — execute the Kody pipeline\n// ==========================================================================\n\nasync function runCommand() {\n const { main } = await import(\"@engine/entry\");\n await main(process.argv.slice(3));\n}\n\n// ==========================================================================\n// CI helper commands — used by the workflow in parse/orchestrate jobs\n// ==========================================================================\n\nasync function parseSafetyCommand() {\n await import(\"@engine/parse-safety\");\n}\n\nasync function parseInputsCommand() {\n await import(\"@engine/parse-inputs\");\n}\n\nasync function checkoutBranchCommand() {\n await import(\"@engine/checkout-task-branch\");\n}\n\n// ==========================================================================\n// Utilities\n// ==========================================================================\n\nfunction copyDirRecursive(src: string, dest: string, force: boolean) {\n fs.mkdirSync(dest, { recursive: true });\n for (const entry of fs.readdirSync(src, { withFileTypes: true })) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) {\n copyDirRecursive(srcPath, destPath, force);\n } else {\n if (fs.existsSync(destPath) && !force) continue;\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n\n// ==========================================================================\n// Program\n// ==========================================================================\n\nconst program = new Command()\n .name(\"kody-engine\")\n .version(getVersion())\n .description(\"Kody CI/CD pipeline engine\");\n\nprogram\n .command(\"init\")\n .description(\"Initialize Kody in the current repo (copies workflow + config)\")\n .option(\"-f, --force\", \"Overwrite existing files\", false)\n .option(\"-w, --workflow-only\", \"Only copy the workflow file\", false)\n .action(initCommand);\n\nprogram\n .command(\"run\", { isDefault: true })\n .description(\"Run the Kody pipeline (default command)\")\n .allowUnknownOption()\n .allowExcessArguments()\n .action(runCommand);\n\nprogram\n .command(\"parse-safety\")\n .description(\"Validate comment trigger safety (CI helper)\")\n .action(parseSafetyCommand);\n\nprogram\n .command(\"parse-inputs\")\n .description(\"Parse command inputs from trigger (CI helper)\")\n .action(parseInputsCommand);\n\nprogram\n .command(\"checkout-branch\")\n .description(\"Checkout or create feature branch for task (CI helper)\")\n .action(checkoutBranchCommand);\n\nprogram.parse();\n"],"mappings":"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","names":["z","path","fs","ms","modeLine","path","program","ms","fs","path","VALID_STAGES","execFileSync","fs","execFileSync","fs","path","resolve","spawn","args","z","fs","path","execFileSync","fs","path","fs","fs","path","fs","path","fs","path","fs","path","execFileSync","ctx","rebuildPipelineAfterTaskify","fs","path","ms","init_constants","fs","path","ms","resolve","init_constants","path","execFileSync","resolve","init_constants","fs","ms","path","resolve","init_constants","fs","path","execFileSync","fs","path","fs","path","execFileSync","fs","ms","path","program","report","existsSync","unlinkSync","execFileSync","execFileSync","fs","path","fs","path","fs","path","fs","path","resolvePipelineProfile","getComplexityTier","fs","path","resolveControlMode","fs","path","execFileSync","program","fs","path","fs","path","execFileSync","init_validators","fs","path","fs","path","action","init_validators","fs","path","resolve","ms","execFileSync","fs","path","getIssue","fs","path","fs","path","resolvePipelineProfile","deleteState","resolvePipelineProfile","fs","path","runFullMode","execFileSync","fs","path","ctx","commitPipelineFiles","loadState","writeState","resumeFromGate","state","taskDef","handleGateApproval","resolvePipelineProfile","resetFromStage","setLifecycleLabel","fs","path","resolvePipelineProfile","loadState","init_status","execFileSync","writeFileSync","readFileSync","join","init_status","ms","execFileSync","loadState","writeState","completeState","setLifecycleLabel","writeFileSync","main","APPROVAL_KEYWORDS","VALID_MODES","discoverTaskIdFromIssue","execFileSync","writeFileSync","writeOutputs","main","execFileSync","getDefaultBranch","mergeDefaultBranch","main","Command","fs","path","main"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/engine/env.ts","../../../../src/engine/logger.ts","../../../../src/engine/stages/registry.ts","../../../../src/engine/validation.ts","../../../../src/engine/pipeline/task-schema.ts","../../../../src/engine/pipeline/complexity.ts","../../../../src/engine/pipeline/task-io.ts","../../../../src/engine/pipeline-utils.ts","../../../../src/engine/github-api.ts","../../../../src/engine/cli-parser.ts","../../../../src/engine/status-format.ts","../../../../src/engine/kody-utils.ts","../../../../src/engine/preflight.ts","../../../../src/engine/opencode-server.ts","../../../../src/engine/runner-backend.ts","../../../../src/engine/config/constants.ts","../../../../src/engine/engine/types.ts","../../../../src/engine/engine/status.ts","../../../../src/engine/git-utils.ts","../../../../src/engine/content-validators.ts","../../../../src/engine/pipeline/validators.ts","../../../../src/engine/pipeline/verify-failures.ts","../../../../src/engine/pipeline/skip-conditions.ts","../../../../src/engine/pipeline/definitions.ts","../../../../src/engine/engine/pipeline-resolver.ts","../../../../src/engine/pipeline-events.ts","../../../../src/engine/stage-prompts.ts","../../../../src/engine/agent/constants.ts","../../../../src/engine/agent/file-watcher.ts","../../../../src/engine/agent/log-parser.ts","../../../../src/engine/agent/session.ts","../../../../src/engine/agent-runner.ts","../../../../src/engine/chat-history.ts","../../../../src/engine/handlers/agent-handler.ts","../../../../src/engine/config/project-config.ts","../../../../src/engine/scripted-stages.ts","../../../../src/engine/handlers/scripted-handler.ts","../../../../src/engine/handlers/git-handler.ts","../../../../src/engine/clarify-workflow.ts","../../../../src/engine/handlers/gate-handler.ts","../../../../src/engine/handlers/handler.ts","../../../../src/engine/pipeline/post-actions/validate-task-json.ts","../../../../src/engine/pipeline/post-actions/classification.ts","../../../../src/engine/pipeline/post-actions/promoted-stub.ts","../../../../src/engine/pipeline/post-actions/resolve-profile.ts","../../../../src/engine/pipeline/post-actions/gate.ts","../../../../src/engine/pipeline/post-actions/commit.ts","../../../../src/engine/pipeline/error-classifier.ts","../../../../src/engine/pipeline/post-actions/quality.ts","../../../../src/engine/pipeline/post-actions/review.ts","../../../../src/engine/pipeline/post-actions/validators.ts","../../../../src/engine/pipeline/post-actions/knowledge-base.ts","../../../../src/engine/pipeline/post-actions/index.ts","../../../../src/engine/pipeline/observer/observer.ts","../../../../src/engine/engine/state-machine.ts","../../../../src/engine/task-setup.ts","../../../../src/engine/modes/spec.ts","../../../../src/engine/modes/impl.ts","../../../../src/engine/modes/full.ts","../../../../src/engine/brain-health.ts","../../../../src/engine/brain-client.ts","../../../../src/engine/architect-brain.ts","../../../../src/engine/review-brain.ts","../../../../src/engine/modes/brain-full.ts","../../../../src/engine/rerun-utils.ts","../../../../src/engine/modes/rerun.ts","../../../../src/engine/modes/fix.ts","../../../../src/engine/modes/status.ts","../../../../src/engine/modes/design-system.ts","../../../../src/engine/modes/index.ts","../../../../src/engine/entry.ts","../../../../src/engine/parse-safety.ts","../../../../src/engine/parse-inputs.ts","../../../../src/engine/checkout-task-branch.ts","../../src/bin/cli.ts"],"sourcesContent":["/**\n * @fileType utility\n * @domain kody-pipeline\n * @pattern env-validation\n * @ai-summary Centralized environment variable validation for Kody pipeline using znv\n */\n\nimport { parseEnv, z } from 'znv'\n\n// Lazy-loaded env to avoid validation at import time in tests\nlet _env: EnvSchema | null = null\n\ninterface EnvSchema {\n // GitHub CI context\n GITHUB_ACTIONS?: string\n GITHUB_REPOSITORY?: string\n GITHUB_EVENT_NAME?: string\n GITHUB_OUTPUT?: string\n\n // Auth tokens\n GH_TOKEN?: string\n GH_PAT?: string\n\n // Pipeline overrides\n TASK_ID?: string\n MODE?: string\n DRY_RUN?: string\n FEEDBACK?: string\n FROM_STAGE?: string\n CLARIFY?: string\n ISSUE_NUMBER?: string\n TRIGGER_TYPE?: string\n RUN_ID?: string\n RUN_URL?: string\n VERSION?: string\n COMPLEXITY?: string\n COMMENT_BODY?: string\n\n // Dispatch inputs\n DISPATCH_TASK_ID?: string\n DISPATCH_MODE?: string\n DISPATCH_CLARIFY?: string\n DISPATCH_DRY_RUN?: string\n DISPATCH_FROM_STAGE?: string\n DISPATCH_FEEDBACK?: string\n DISPATCH_RUNNER?: string\n DISPATCH_VERSION?: string\n IS_PULL_REQUEST?: string\n\n // Safety\n SAFETY_VALID?: string\n SAFETY_REASON?: string\n AUTHOR?: string\n ASSOCIATION?: string\n\n // Git config\n GIT_USER_EMAIL?: string\n GIT_USER_NAME?: string\n\n // Logging\n LOG_LEVEL?: string\n NODE_ENV?: string\n DEBUG?: string\n\n // Pipeline versioning\n KODY_DEFAULT_VERSION?: string\n}\n\nfunction createEnv(): EnvSchema {\n return parseEnv(process.env, {\n // GitHub CI context\n GITHUB_ACTIONS: z.string().optional(),\n GITHUB_REPOSITORY: z.string().optional(),\n GITHUB_EVENT_NAME: z.string().optional(),\n GITHUB_OUTPUT: z.string().optional(),\n\n // Auth tokens\n GH_TOKEN: z.string().optional(),\n GH_PAT: z.string().optional(),\n\n // Pipeline overrides\n TASK_ID: z.string().optional(),\n MODE: z.string().optional(),\n DRY_RUN: z.string().optional(),\n FEEDBACK: z.string().optional(),\n FROM_STAGE: z.string().optional(),\n CLARIFY: z.string().optional(),\n ISSUE_NUMBER: z.string().optional(),\n TRIGGER_TYPE: z.string().optional(),\n RUN_ID: z.string().optional(),\n RUN_URL: z.string().optional(),\n VERSION: z.string().optional(),\n COMPLEXITY: z.string().optional(),\n COMMENT_BODY: z.string().optional(),\n\n // Dispatch inputs\n DISPATCH_TASK_ID: z.string().optional(),\n DISPATCH_MODE: z.string().optional(),\n DISPATCH_CLARIFY: z.string().optional(),\n DISPATCH_DRY_RUN: z.string().optional(),\n DISPATCH_FROM_STAGE: z.string().optional(),\n DISPATCH_FEEDBACK: z.string().optional(),\n DISPATCH_RUNNER: z.string().optional(),\n DISPATCH_VERSION: z.string().optional(),\n IS_PULL_REQUEST: z.string().optional(),\n\n // Safety\n SAFETY_VALID: z.string().optional(),\n SAFETY_REASON: z.string().optional(),\n AUTHOR: z.string().optional(),\n ASSOCIATION: z.string().optional(),\n\n // Git config\n GIT_USER_EMAIL: z.string().optional(),\n GIT_USER_NAME: z.string().optional(),\n\n // Logging\n // Note: Using string() without enum to avoid znv issues with optional + default\n // Values are validated against allowed options in getEnv()\n LOG_LEVEL: z.string().optional(),\n NODE_ENV: z.string().optional(),\n DEBUG: z.string().optional(),\n\n // Pipeline versioning\n KODY_DEFAULT_VERSION: z.string().optional(),\n }) as EnvSchema\n}\n\n/**\n * Get validated environment variables.\n * Uses lazy initialization to avoid validation failures during test setup.\n */\nexport function getEnv(): EnvSchema {\n if (!_env) {\n const env = createEnv()\n // Validate and set defaults manually\n const validLogLevels = ['debug', 'info', 'warn', 'error', 'silent']\n if (!env.LOG_LEVEL || !validLogLevels.includes(env.LOG_LEVEL)) {\n env.LOG_LEVEL = 'info'\n }\n _env = env\n }\n return _env\n}\n\n/**\n * Reset env cache (for testing)\n */\nexport function resetEnv() {\n _env = null\n}\n","/**\n * @fileType utility\n * @domain ci | kody | observability\n * @pattern structured-logging\n * @ai-summary Structured logging helpers with stage context for the Kody pipeline\n */\n\nimport pino from 'pino'\n\nimport { getEnv } from './env'\n\n// Lazy-initialize pino logger to avoid validation at import time\nlet _logger: ReturnType<typeof pino> | null = null\n\nfunction getPinoLogger() {\n if (!_logger) {\n const env = getEnv()\n const isCI = !!env.GITHUB_ACTIONS\n\n _logger = pino({\n level: env.LOG_LEVEL || 'info',\n transport: {\n target: 'pino-pretty',\n options: {\n colorize: !isCI,\n translateTime: 'SYS:HH:MM:ss',\n ignore: 'pid,hostname',\n },\n },\n })\n }\n return _logger\n}\n\n/**\n * Get the root pino logger instance\n */\nexport function getRootLogger() {\n return getPinoLogger()\n}\n\n/**\n * Create a child logger scoped to a specific pipeline stage.\n */\nexport function createStageLogger(stage: string, taskId?: string) {\n return getPinoLogger().child({ stage, ...(taskId && { taskId }) })\n}\n\n// Re-export pino logger for backward compatibility\nexport const logger = getPinoLogger()\nexport default logger\n\n// ============================================================================\n// CI Log Grouping (GitHub Actions)\n// ============================================================================\n\n/**\n * Emit a GitHub Actions collapsible group header.\n * No-op when not running in CI.\n */\nexport function ciGroup(title: string): void {\n if (process.env.GITHUB_ACTIONS) {\n process.stdout.write(`::group::${title}\\n`)\n }\n}\n\n/**\n * Emit a GitHub Actions collapsible group footer.\n * No-op when not running in CI.\n */\nexport function ciGroupEnd(): void {\n if (process.env.GITHUB_ACTIONS) {\n process.stdout.write('::endgroup::\\n')\n }\n}\n","/**\n * @fileType configuration\n * @domain kody | pipeline\n * @pattern stage-registry\n * @ai-summary Single source of truth for all pipeline stage metadata, types, and order arrays\n */\n\nimport ms from \"ms\";\n\n// ============================================================================\n// Stage Names — the canonical list\n// ============================================================================\n\n/**\n * All valid stage names in the Kody pipeline.\n *\n * Excluded:\n * - 'spec' — merged into 'gap' months ago (ghost stage)\n * - 'autofix' — not a real pipeline stage; it's a sub-behavior of build feedback loops\n */\nexport const STAGE_NAMES = [\n \"taskify\",\n \"gap\",\n \"clarify\",\n \"architect\",\n \"plan-gap\",\n \"test\",\n \"build\",\n \"commit\",\n \"review\",\n \"fix\",\n \"verify\",\n \"docs\",\n \"pr\",\n] as const;\n\nexport type StageName = (typeof STAGE_NAMES)[number];\n\n/**\n * Named constant object for stage names — provides compile-time typo detection\n * and single-point rename capability. Use STAGES.BUILD instead of 'build' in new code.\n */\nexport const STAGES = {\n TASKIFY: \"taskify\",\n GAP: \"gap\",\n CLARIFY: \"clarify\",\n ARCHITECT: \"architect\",\n PLAN_GAP: \"plan-gap\",\n TEST: \"test\",\n BUILD: \"build\",\n COMMIT: \"commit\",\n REVIEW: \"review\",\n FIX: \"fix\",\n VERIFY: \"verify\",\n DOCS: \"docs\",\n PR: \"pr\",\n} as const satisfies Record<string, StageName>;\n\n// ============================================================================\n// Stage Metadata\n// ============================================================================\n\nexport interface StageMetadata {\n /** Expected output file name (e.g., 'task.json', 'plan.md') */\n outputFile: string;\n /** Timeout in milliseconds */\n timeout: number;\n /** Minimum complexity score to run (0 = always runs) */\n complexityThreshold: number;\n /** Files the stage reads for context */\n contextFiles: string[];\n /** Handler dispatch type */\n type: \"agent\" | \"scripted\" | \"git\" | \"gate\";\n}\n\n/**\n * The stage registry — typed as Record<StageName, StageMetadata>.\n * Adding/removing from STAGE_NAMES without updating this record causes a compile error.\n */\nexport const STAGE_REGISTRY: Record<StageName, StageMetadata> = {\n taskify: {\n outputFile: \"task.json\",\n timeout: ms(\"10m\"),\n complexityThreshold: 0,\n contextFiles: [\"task.md\"],\n type: \"agent\",\n },\n gap: {\n outputFile: \"gap.md\",\n timeout: ms(\"15m\"),\n complexityThreshold: 35,\n contextFiles: [\"task.md\", \"task.json\"],\n type: \"agent\",\n },\n clarify: {\n outputFile: \"questions.md\",\n timeout: ms(\"10m\"),\n complexityThreshold: 60,\n contextFiles: [\"task.md\", \"spec.md\"],\n type: \"agent\",\n },\n architect: {\n outputFile: \"plan.md\",\n timeout: ms(\"30m\"),\n complexityThreshold: 10,\n contextFiles: [\n \"spec.md\",\n \"clarified.md\",\n \"rerun-feedback.md\",\n \"prev-run/plan.md\",\n \"prev-run/build.md\",\n \"prev-run/review.md\",\n ],\n type: \"agent\",\n },\n \"plan-gap\": {\n outputFile: \"plan-gap.md\",\n timeout: ms(\"15m\"),\n complexityThreshold: 50,\n contextFiles: [\"spec.md\", \"plan.md\", \"task.json\"],\n type: \"agent\",\n },\n test: {\n outputFile: \"test.md\",\n timeout: ms(\"40m\"),\n complexityThreshold: 0,\n contextFiles: [\"spec.md\", \"clarified.md\", \"plan.md\", \"task.json\"],\n type: \"agent\",\n },\n build: {\n outputFile: \"build.md\",\n timeout: ms(\"60m\"),\n complexityThreshold: 0,\n contextFiles: [\n \"spec.md\",\n \"clarified.md\",\n \"plan.md\",\n \"plan-gap.md\",\n \"context.md\",\n \"rerun-feedback.md\",\n \"build-errors.md\",\n \"review.md\",\n \"prev-run/build.md\",\n \"prev-run/review.md\",\n ],\n type: \"agent\",\n },\n commit: {\n outputFile: \"commit.md\",\n timeout: ms(\"5m\"),\n complexityThreshold: 0,\n contextFiles: [\"task.json\"],\n type: \"git\",\n },\n review: {\n outputFile: \"review.md\",\n timeout: ms(\"15m\"),\n complexityThreshold: 30,\n contextFiles: [\n \"review.md\",\n \"build.md\",\n \"plan.md\",\n \"context.md\",\n \"spec.md\",\n \"clarified.md\",\n ],\n type: \"agent\",\n },\n fix: {\n outputFile: \"fix.md\",\n timeout: ms(\"45m\"), // Increased from 30m — fixes often need more time than original build\n complexityThreshold: 0,\n contextFiles: [\n \"verify-failures.md\",\n \"review.md\",\n \"rerun-feedback.md\",\n \"fix-summary.md\",\n \"build.md\",\n \"plan.md\",\n \"context.md\",\n \"spec.md\",\n \"clarified.md\",\n \"prev-run/build.md\",\n ],\n type: \"agent\",\n },\n verify: {\n outputFile: \"verify.md\",\n timeout: ms(\"10m\"),\n complexityThreshold: 0,\n contextFiles: [],\n type: \"scripted\",\n },\n docs: {\n outputFile: \"docs.md\",\n timeout: ms(\"10m\"),\n complexityThreshold: 30,\n contextFiles: [\"build.md\", \"task.json\", \"review.md\", \"context.md\"],\n type: \"agent\",\n },\n pr: {\n outputFile: \"pr.md\",\n timeout: ms(\"5m\"),\n complexityThreshold: 0,\n contextFiles: [],\n type: \"git\",\n },\n};\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Get the output file name for a stage.\n * Falls back to `${stage}.md` for stages without a specific mapping.\n */\nexport function getStageOutputFile(stage: StageName): string {\n return STAGE_REGISTRY[stage].outputFile;\n}\n\n/**\n * Get the timeout for a stage in milliseconds.\n */\nexport function getStageTimeout(stage: StageName): number {\n return STAGE_REGISTRY[stage].timeout;\n}\n\n/**\n * Get the minimum complexity threshold for a stage.\n */\nexport function getStageComplexityThreshold(stage: StageName): number {\n return STAGE_REGISTRY[stage].complexityThreshold;\n}\n\n/**\n * Get the context files a stage needs to read.\n */\nexport function getStageContextFiles(stage: StageName): string[] {\n return STAGE_REGISTRY[stage].contextFiles;\n}\n\n/**\n * Runtime type guard — checks if a string is a valid StageName.\n */\nexport function isValidStageName(name: string): name is StageName {\n return (STAGE_NAMES as readonly string[]).includes(name);\n}\n\n/**\n * Assert that a string is a valid StageName, or throw.\n */\nexport function assertStageName(name: string): StageName {\n if (!isValidStageName(name)) {\n throw new Error(\n `Invalid stage name: '${name}'. Valid stages: ${STAGE_NAMES.join(\", \")}`,\n );\n }\n return name;\n}\n\n// ============================================================================\n// Resolve output file path on disk\n// ============================================================================\n\n/**\n * Build the full path to a stage's output file.\n * For stages not in the registry, falls back to `${stage}.md`.\n */\nexport function stageOutputFile(taskDir: string, stage: string): string {\n if (isValidStageName(stage)) {\n const filename = STAGE_REGISTRY[stage].outputFile;\n return `${taskDir}/${filename}`;\n }\n // Fallback for unknown stages (backward compat)\n return `${taskDir}/${stage}.md`;\n}\n\n// ============================================================================\n// Pipeline Order Arrays (typed)\n// ============================================================================\n\nexport type TypedPipelineStep = StageName | { parallel: StageName[] };\n\nexport const SPEC_ORDER_STANDARD: StageName[] = [\"taskify\", \"gap\", \"clarify\"];\nexport const SPEC_ORDER_LIGHTWEIGHT: StageName[] = [\"taskify\", \"clarify\"];\n\nexport const IMPL_ORDER_STANDARD: TypedPipelineStep[] = [\n \"architect\",\n \"plan-gap\",\n { parallel: [\"test\", \"build\"] },\n \"commit\",\n \"review\",\n \"fix\",\n // NOTE: No second 'commit' here — fix stage commits via its post-action\n // (commit-task-files with tracked+task). A duplicate 'commit' entry would be\n // skipped by resolveNextStep since state.stages['commit'] is already completed.\n \"verify\",\n \"pr\",\n];\n\nexport const IMPL_ORDER_LIGHTWEIGHT: TypedPipelineStep[] = [\n \"architect\",\n { parallel: [\"test\", \"build\"] },\n \"commit\",\n \"review\",\n \"fix\",\n \"verify\",\n \"pr\",\n];\n\n/** Turbo spec order — minimal: just taskify (no gap/clarify) */\nexport const SPEC_ORDER_TURBO: StageName[] = [\"taskify\"];\n\n/** Turbo impl order — minimal: build→commit→verify→pr (no architect/review/fix) */\nexport const IMPL_ORDER_TURBO: TypedPipelineStep[] = [\n \"build\",\n \"commit\",\n \"verify\",\n \"pr\",\n];\n\n/** Fix-only pipeline order for @kody fix mode */\nexport const FIX_ORDER: TypedPipelineStep[] = [\"review\", \"fix\", \"verify\", \"pr\"];\n\n/** Full pipeline order for fix mode — runs the full impl pipeline with taskify prepended */\nexport const FIX_FULL_ORDER: TypedPipelineStep[] = [\n \"taskify\",\n \"architect\",\n \"plan-gap\",\n { parallel: [\"test\", \"build\"] },\n \"commit\",\n \"review\",\n \"fix\",\n \"verify\",\n \"pr\",\n];\n\n// ============================================================================\n// Pipeline Utility Functions\n// ============================================================================\n\n/**\n * Flatten a typed pipeline step to its constituent stage names.\n */\nexport function flattenTypedStep(step: TypedPipelineStep): StageName[] {\n if (typeof step === \"string\") return [step];\n return step.parallel;\n}\n\n/**\n * Flatten an entire typed pipeline to a flat list of stage names.\n */\nexport function flattenTypedPipeline(steps: TypedPipelineStep[]): StageName[] {\n return steps.flatMap(flattenTypedStep);\n}\n\n/**\n * Spec-only stages (don't produce code).\n */\nexport const SPEC_STAGES: StageName[] = [\"taskify\", \"gap\", \"clarify\"];\n\n/**\n * Scripted stages that run directly without an LLM agent.\n */\nexport const SCRIPTED_STAGES: StageName[] = [\"verify\", \"commit\", \"pr\"];\n","/**\n * @fileType utility\n * @domain kody | validation\n * @pattern shared-validation\n * @ai-summary Shared validation constants and type guards — leaf dependency with no kody imports\n */\n\nimport { STAGE_NAMES } from './stages/registry'\n\nexport const VALID_MODES = [\n 'spec',\n 'impl',\n 'rerun',\n 'fix',\n 'full',\n 'status',\n 'design-system',\n] as const\n\nexport const VALID_STAGES = [...STAGE_NAMES, 'autofix' as const]\n\nexport function isValidMode(mode: string): mode is (typeof VALID_MODES)[number] {\n return (VALID_MODES as readonly string[]).includes(mode)\n}\n\nexport function isValidStage(stage: string): stage is (typeof VALID_STAGES)[number] {\n return (VALID_STAGES as readonly string[]).includes(stage)\n}\n\nexport function validateTaskId(taskId: string): boolean {\n return /^\\d{6}[a-zA-Z0-9-]+$/.test(taskId)\n}\n","/**\n * @fileType schema\n * @domain kody | pipeline\n * @pattern task-schema\n * @ai-summary Task definition types, Zod schemas, and validation for the Kody pipeline\n */\n\nimport { z } from 'zod'\n\nexport const VALID_TASK_TYPES = [\n 'spec_only',\n 'implement_feature',\n 'fix_bug',\n 'refactor',\n 'docs',\n 'ops',\n 'research',\n] as const\n\nexport const VALID_PIPELINES = ['spec_only', 'spec_execute_verify'] as const\nconst VALID_RISK_LEVELS = ['low', 'medium', 'high'] as const\nconst VALID_DOMAINS = ['backend', 'frontend', 'infra', 'data', 'llm', 'devops', 'product'] as const\nexport const VALID_PIPELINE_PROFILES = ['lightweight', 'standard', 'turbo'] as const\n\nexport type TaskType = (typeof VALID_TASK_TYPES)[number]\nexport type Pipeline = (typeof VALID_PIPELINES)[number]\nexport type PipelineProfile = (typeof VALID_PIPELINE_PROFILES)[number]\n\nexport const COMPLEXITY_MIN = 1\nexport const COMPLEXITY_MAX = 100\n\n// --- Input quality levels for smart stage skipping ---\nexport const VALID_INPUT_QUALITY_LEVELS = [\n 'raw_idea',\n 'good_spec',\n 'detailed_plan',\n 'spec_and_plan',\n] as const\n\n// Stages that cannot be skipped (gap analysis always runs)\nexport const NON_SKIPPABLE_STAGES = ['gap', 'plan-gap', 'build', 'commit', 'verify', 'pr'] as const\n\n// Stages that CAN be skipped when input quality is high\nexport const SKIPPABLE_STAGES = ['architect'] as const\n\n// NOTE: STAGE_COMPLEXITY_THRESHOLDS moved to stages/registry.ts\n// Use getStageComplexityThreshold() from registry instead.\n\nexport interface InputQuality {\n level: (typeof VALID_INPUT_QUALITY_LEVELS)[number]\n skip_stages: string[]\n reasoning: string\n}\n\nexport interface TaskDefinition {\n task_type: TaskType\n pipeline: Pipeline\n risk_level: (typeof VALID_RISK_LEVELS)[number]\n confidence: number\n primary_domain: (typeof VALID_DOMAINS)[number]\n scope: string[]\n missing_inputs: Array<{ field: string; question: string }>\n assumptions: string[]\n /** Questions for the reviewer to answer before approving. Derived from assumptions and task ambiguity. */\n review_questions?: string[]\n input_quality?: InputQuality\n pipeline_profile?: (typeof VALID_PIPELINE_PROFILES)[number]\n /** Complexity score (1-100) — determines which pipeline stages run */\n complexity?: number\n /** Brief explanation of complexity scoring breakdown */\n complexity_reasoning?: string\n}\n\n// Pipeline consistency: task_type → allowed pipeline values\nexport const PIPELINE_MAP: Record<TaskType, Pipeline> = {\n spec_only: 'spec_only',\n research: 'spec_only',\n docs: 'spec_only',\n implement_feature: 'spec_execute_verify',\n fix_bug: 'spec_execute_verify',\n refactor: 'spec_execute_verify',\n ops: 'spec_execute_verify',\n}\n\ninterface ValidationResult {\n valid: boolean\n errors: string[]\n}\n\n// --- Task type alias mapping (common LLM mistakes) ---\n\nconst TASK_TYPE_ALIASES: Record<string, TaskType> = {\n feature: 'implement_feature',\n new_feature: 'implement_feature',\n add_feature: 'implement_feature',\n bug: 'fix_bug',\n bugfix: 'fix_bug',\n bug_fix: 'fix_bug',\n hotfix: 'fix_bug',\n refactoring: 'refactor',\n cleanup: 'refactor',\n documentation: 'docs',\n doc: 'docs',\n operations: 'ops',\n devops: 'ops',\n infra: 'ops',\n spec: 'spec_only',\n research_only: 'research',\n investigate: 'research',\n}\n\n// --- Confidence string-to-number mapping ---\n\nexport const CONFIDENCE_MAP: Record<string, number> = {\n high: 0.9,\n medium: 0.7,\n low: 0.5,\n very_high: 0.95,\n very_low: 0.3,\n}\n\n// --- Zod Schema for TaskDefinition ---\n\n/**\n * Zod schema that validates and normalizes a raw task definition.\n * Uses .superRefine() for validation and .transform() for normalization.\n */\nexport const TaskDefinitionSchema = z\n .object({\n task_type: z.string().optional(),\n pipeline: z.string().optional(),\n risk_level: z.string().optional(),\n confidence: z.union([z.string(), z.number()]).optional(),\n primary_domain: z.string().optional(),\n scope: z.union([z.string(), z.array(z.string())]).optional(),\n missing_inputs: z.any().optional(),\n assumptions: z.any().optional(),\n review_questions: z.any().optional(),\n input_quality: z.any().optional(),\n pipeline_profile: z.string().optional(),\n complexity: z.union([z.string(), z.number()]).optional(),\n complexity_reasoning: z.any().optional(),\n })\n .superRefine((raw, ctx) => {\n const data = raw as Record<string, unknown>\n\n // Validate pipeline_profile - add issue on invalid values\n if (data.pipeline_profile !== undefined) {\n if (\n typeof data.pipeline_profile !== 'string' ||\n !VALID_PIPELINE_PROFILES.includes(data.pipeline_profile as PipelineProfile)\n ) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Invalid pipeline_profile: \"${data.pipeline_profile}\". Must be one of: ${VALID_PIPELINE_PROFILES.join(', ')}`,\n })\n }\n }\n\n // Validate input_quality.skip_stages - add issue for non-skippable stages\n if (\n data.input_quality !== undefined &&\n typeof data.input_quality === 'object' &&\n data.input_quality !== null\n ) {\n const iq = data.input_quality as Record<string, unknown>\n\n if (Array.isArray(iq.skip_stages)) {\n for (const stage of iq.skip_stages) {\n if (typeof stage !== 'string') {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Invalid input_quality.skip_stages: each stage must be a string`,\n })\n break\n }\n if (NON_SKIPPABLE_STAGES.includes(stage as (typeof NON_SKIPPABLE_STAGES)[number])) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Cannot skip stage \"${stage}\" - gap and plan-gap must always run for quality assurance`,\n })\n }\n }\n }\n }\n })\n .transform((raw): TaskDefinition => {\n const data = raw as Record<string, unknown>\n\n // 1. Normalize task_type aliases\n let normalizedTaskType: TaskType | undefined\n if (typeof data.task_type === 'string') {\n const alias = TASK_TYPE_ALIASES[data.task_type.toLowerCase()]\n if (alias) {\n normalizedTaskType = alias\n } else if (VALID_TASK_TYPES.includes(data.task_type as TaskType)) {\n normalizedTaskType = data.task_type as TaskType\n } else {\n // Invalid task_type that's not an alias - will be caught in validation\n normalizedTaskType = data.task_type as TaskType\n }\n }\n\n // 2. Always derive pipeline from task_type\n let normalizedPipeline: Pipeline | undefined\n if (normalizedTaskType && PIPELINE_MAP[normalizedTaskType]) {\n normalizedPipeline = PIPELINE_MAP[normalizedTaskType]\n }\n\n // 3. Convert string confidence to number\n let normalizedConfidence: number | undefined\n if (typeof data.confidence === 'string') {\n const mapped = CONFIDENCE_MAP[data.confidence.toLowerCase()]\n if (mapped !== undefined) {\n normalizedConfidence = mapped\n } else {\n // Try parsing as number string (e.g., \"0.9\")\n const parsed = parseFloat(data.confidence)\n if (!isNaN(parsed) && parsed >= 0 && parsed <= 1) {\n normalizedConfidence = parsed\n }\n }\n } else if (typeof data.confidence === 'number') {\n normalizedConfidence = data.confidence\n }\n\n // 4. Normalize scope (wrap string in array)\n let normalizedScope: string[] = []\n if (typeof data.scope === 'string') {\n normalizedScope = [data.scope]\n } else if (Array.isArray(data.scope)) {\n normalizedScope = data.scope\n }\n\n // 5. Default missing arrays\n const missingInputs = Array.isArray(data.missing_inputs)\n ? data.missing_inputs\n : ([] as Array<{ field: string; question: string }>)\n const assumptions = Array.isArray(data.assumptions) ? data.assumptions : []\n const reviewQuestions = Array.isArray(data.review_questions) ? data.review_questions : []\n\n // 6. Normalize complexity\n let normalizedComplexity: number | undefined\n if (data.complexity !== undefined) {\n if (typeof data.complexity === 'string') {\n const parsed = parseInt(data.complexity, 10)\n if (!isNaN(parsed)) {\n normalizedComplexity = Math.max(\n COMPLEXITY_MIN,\n Math.min(COMPLEXITY_MAX, Math.round(parsed)),\n )\n }\n } else if (typeof data.complexity === 'number') {\n normalizedComplexity = Math.max(\n COMPLEXITY_MIN,\n Math.min(COMPLEXITY_MAX, Math.round(data.complexity)),\n )\n }\n }\n\n const complexityReasoning =\n typeof data.complexity_reasoning === 'string'\n ? data.complexity_reasoning\n : typeof data.complexity_reasoning !== 'undefined'\n ? String(data.complexity_reasoning)\n : undefined\n\n // 7. Normalize pipeline_profile (only if valid - validation already done in superRefine)\n let normalizedPipelineProfile: PipelineProfile | undefined\n if (\n data.pipeline_profile !== undefined &&\n typeof data.pipeline_profile === 'string' &&\n VALID_PIPELINE_PROFILES.includes(data.pipeline_profile as PipelineProfile)\n ) {\n normalizedPipelineProfile = data.pipeline_profile as PipelineProfile\n }\n\n // 8. Normalize input_quality\n let normalizedInputQuality: InputQuality | undefined\n if (\n data.input_quality !== undefined &&\n typeof data.input_quality === 'object' &&\n data.input_quality !== null\n ) {\n const iq = data.input_quality as Record<string, unknown>\n\n // Validate level\n let level: InputQuality['level'] = 'raw_idea'\n if (\n typeof iq.level === 'string' &&\n VALID_INPUT_QUALITY_LEVELS.includes(iq.level as InputQuality['level'])\n ) {\n level = iq.level as InputQuality['level']\n }\n\n // Normalize skip_stages (filter out non-skippable - validation done in superRefine)\n const skipStages: string[] = []\n if (Array.isArray(iq.skip_stages)) {\n for (const stage of iq.skip_stages) {\n if (\n typeof stage === 'string' &&\n !NON_SKIPPABLE_STAGES.includes(stage as (typeof NON_SKIPPABLE_STAGES)[number])\n ) {\n skipStages.push(stage)\n }\n }\n }\n\n const reasoning = typeof iq.reasoning === 'string' ? iq.reasoning : ''\n\n normalizedInputQuality = { level, skip_stages: skipStages, reasoning }\n } else {\n // Default input_quality\n normalizedInputQuality = {\n level: 'raw_idea',\n skip_stages: [],\n reasoning: '',\n }\n }\n\n // Build the result object (required fields with defaults for missing)\n const result: TaskDefinition = {\n task_type: normalizedTaskType || 'implement_feature',\n pipeline: normalizedPipeline || 'spec_execute_verify',\n risk_level: (data.risk_level as TaskDefinition['risk_level']) || 'medium',\n confidence: normalizedConfidence ?? 0.7,\n primary_domain: (data.primary_domain as TaskDefinition['primary_domain']) || 'backend',\n scope: normalizedScope,\n missing_inputs: missingInputs as Array<{ field: string; question: string }>,\n assumptions: assumptions as string[],\n review_questions: reviewQuestions as string[] | undefined,\n input_quality: normalizedInputQuality,\n pipeline_profile: normalizedPipelineProfile,\n complexity: normalizedComplexity,\n complexity_reasoning: complexityReasoning,\n }\n\n return result\n })\n\n/**\n * Parse a raw task definition using Zod schema.\n * Throws descriptive errors on validation failure.\n */\nexport function parseTaskDefinition(raw: unknown): TaskDefinition {\n const result = TaskDefinitionSchema.safeParse(raw)\n\n if (!result.success) {\n const errors = result.error.issues.map((issue) => {\n const path = issue.path.join('.')\n return path ? `${path}: ${issue.message}` : issue.message\n })\n throw new Error(\n `TaskDefinition validation failed:\\n${errors.map((e) => ` • ${e}`).join('\\n')}`,\n )\n }\n\n return result.data\n}\n\n/**\n * Normalize a raw task.json object, fixing common LLM mistakes:\n * - Maps task_type aliases (e.g., \"feature\" → \"implement_feature\")\n * - Always derives pipeline from task_type (agent should never set this)\n * - Converts string confidence to number (e.g., \"high\" → 0.9)\n * - Wraps scope in array if it's a string\n * - Defaults missing arrays\n */\nexport function normalizeTask(raw: Record<string, unknown>): Record<string, unknown> {\n const data = { ...raw }\n\n // 1. Normalize task_type aliases\n if (typeof data.task_type === 'string') {\n const alias = TASK_TYPE_ALIASES[data.task_type.toLowerCase()]\n if (alias) {\n data.task_type = alias\n }\n }\n\n // 2. Always derive pipeline from task_type (never trust agent's value)\n if (VALID_TASK_TYPES.includes(data.task_type as TaskType)) {\n data.pipeline = PIPELINE_MAP[data.task_type as TaskType]\n }\n\n // 3. Convert string confidence to number\n if (typeof data.confidence === 'string') {\n const mapped = CONFIDENCE_MAP[data.confidence.toLowerCase()]\n if (mapped !== undefined) {\n data.confidence = mapped\n } else {\n // Try parsing as number string (e.g., \"0.9\")\n const parsed = parseFloat(data.confidence)\n if (!isNaN(parsed) && parsed >= 0 && parsed <= 1) {\n data.confidence = parsed\n }\n }\n }\n\n // 4. Wrap scope in array if string\n if (typeof data.scope === 'string') {\n data.scope = [data.scope]\n }\n\n // 5. Default missing arrays\n if (!Array.isArray(data.missing_inputs)) {\n data.missing_inputs = []\n }\n if (!Array.isArray(data.assumptions)) {\n data.assumptions = []\n }\n if (!Array.isArray(data.review_questions)) {\n data.review_questions = []\n }\n\n // 6. Normalize complexity score\n if (data.complexity !== undefined) {\n if (typeof data.complexity === 'string') {\n const parsed = parseInt(data.complexity as string, 10)\n if (!isNaN(parsed)) {\n data.complexity = parsed\n }\n }\n // Clamp to valid range\n if (typeof data.complexity === 'number') {\n data.complexity = Math.max(\n COMPLEXITY_MIN,\n Math.min(COMPLEXITY_MAX, Math.round(data.complexity)),\n )\n }\n }\n if (typeof data.complexity_reasoning !== 'string' && data.complexity_reasoning !== undefined) {\n data.complexity_reasoning = String(data.complexity_reasoning)\n }\n\n // 7. Default input_quality if missing (for backward compatibility)\n if (!data.input_quality || typeof data.input_quality !== 'object') {\n data.input_quality = {\n level: 'raw_idea',\n skip_stages: [],\n reasoning: '',\n }\n } else {\n // Ensure input_quality has required fields\n const iq = data.input_quality as Record<string, unknown>\n if (!iq.level) {\n iq.level = 'raw_idea'\n }\n if (!Array.isArray(iq.skip_stages)) {\n iq.skip_stages = []\n }\n if (typeof iq.reasoning !== 'string') {\n iq.reasoning = ''\n }\n }\n\n return data\n}\n\nexport function validateTask(raw: unknown): ValidationResult {\n const errors: string[] = []\n\n if (typeof raw !== 'object' || raw === null) {\n return { valid: false, errors: ['task.json is not a JSON object'] }\n }\n\n const data = raw as Record<string, unknown>\n\n // Required fields\n if (!VALID_TASK_TYPES.includes(data.task_type as TaskType)) {\n errors.push(\n `Invalid task_type: \"${data.task_type}\". Must be one of: ${VALID_TASK_TYPES.join(', ')}`,\n )\n }\n\n if (!VALID_PIPELINES.includes(data.pipeline as Pipeline)) {\n errors.push(\n `Invalid pipeline: \"${data.pipeline}\". Must be one of: ${VALID_PIPELINES.join(', ')}`,\n )\n }\n\n // Validate optional pipeline_profile\n if (data.pipeline_profile !== undefined) {\n if (!VALID_PIPELINE_PROFILES.includes(data.pipeline_profile as PipelineProfile)) {\n errors.push(\n `Invalid pipeline_profile: \"${data.pipeline_profile}\". Must be one of: ${VALID_PIPELINE_PROFILES.join(', ')}`,\n )\n }\n }\n\n if (!VALID_RISK_LEVELS.includes(data.risk_level as (typeof VALID_RISK_LEVELS)[number])) {\n errors.push(\n `Invalid risk_level: \"${data.risk_level}\". Must be one of: ${VALID_RISK_LEVELS.join(', ')}`,\n )\n }\n\n if (typeof data.confidence !== 'number' || data.confidence < 0 || data.confidence > 1) {\n errors.push(`Invalid confidence: \"${data.confidence}\". Must be a number between 0.0 and 1.0`)\n }\n\n if (!VALID_DOMAINS.includes(data.primary_domain as (typeof VALID_DOMAINS)[number])) {\n errors.push(\n `Invalid primary_domain: \"${data.primary_domain}\". Must be one of: ${VALID_DOMAINS.join(', ')}`,\n )\n }\n\n if (!Array.isArray(data.scope)) {\n errors.push(`Invalid scope: must be an array of strings`)\n }\n\n if (!Array.isArray(data.missing_inputs)) {\n errors.push(`Invalid missing_inputs: must be an array`)\n } else {\n for (const item of data.missing_inputs) {\n const entry = item as Record<string, unknown>\n if (typeof entry.field !== 'string' || typeof entry.question !== 'string') {\n errors.push(`Invalid missing_inputs entry: each must have \"field\" and \"question\" strings`)\n break\n }\n }\n }\n\n if (!Array.isArray(data.assumptions)) {\n errors.push(`Invalid assumptions: must be an array of strings`)\n }\n\n // Validate review_questions if present\n if (data.review_questions !== undefined) {\n if (!Array.isArray(data.review_questions)) {\n errors.push(`Invalid review_questions: must be an array of strings`)\n } else {\n for (const q of data.review_questions) {\n if (typeof q !== 'string') {\n errors.push(`Invalid review_questions entry: must be an array of strings`)\n break\n }\n }\n }\n }\n\n // Validate input_quality if present\n if (data.input_quality !== undefined) {\n if (typeof data.input_quality !== 'object' || data.input_quality === null) {\n errors.push(`Invalid input_quality: must be an object`)\n } else {\n const iq = data.input_quality as Record<string, unknown>\n // Validate level\n if (\n !VALID_INPUT_QUALITY_LEVELS.includes(\n iq.level as (typeof VALID_INPUT_QUALITY_LEVELS)[number],\n )\n ) {\n errors.push(\n `Invalid input_quality.level: \"${iq.level}\". Must be one of: ${VALID_INPUT_QUALITY_LEVELS.join(', ')}`,\n )\n }\n // Validate skip_stages\n if (!Array.isArray(iq.skip_stages)) {\n errors.push(`Invalid input_quality.skip_stages: must be an array`)\n } else {\n for (const stage of iq.skip_stages) {\n if (typeof stage !== 'string') {\n errors.push(`Invalid input_quality.skip_stages: each stage must be a string`)\n break\n }\n // Check for non-skippable stages\n if (NON_SKIPPABLE_STAGES.includes(stage as (typeof NON_SKIPPABLE_STAGES)[number])) {\n errors.push(\n `Cannot skip stage \"${stage}\" - gap and plan-gap must always run for quality assurance`,\n )\n }\n // Check for unknown stages (optional warning, but we'll be strict)\n if (!SKIPPABLE_STAGES.includes(stage as (typeof SKIPPABLE_STAGES)[number])) {\n // Allow unknown stages but warn - this is informational, not an error\n }\n }\n }\n // Validate reasoning\n if (typeof iq.reasoning !== 'string') {\n errors.push(`Invalid input_quality.reasoning: must be a string`)\n }\n }\n }\n\n // Validate complexity if present\n if (data.complexity !== undefined) {\n if (typeof data.complexity !== 'number' || !Number.isInteger(data.complexity)) {\n errors.push(`Invalid complexity: \"${data.complexity}\". Must be an integer`)\n } else if (data.complexity < COMPLEXITY_MIN || data.complexity > COMPLEXITY_MAX) {\n errors.push(\n `Invalid complexity: ${data.complexity}. Must be between ${COMPLEXITY_MIN} and ${COMPLEXITY_MAX}`,\n )\n }\n }\n\n if (data.complexity_reasoning !== undefined && typeof data.complexity_reasoning !== 'string') {\n errors.push(`Invalid complexity_reasoning: must be a string`)\n }\n\n // Pipeline consistency check\n if (\n errors.length === 0 &&\n PIPELINE_MAP[data.task_type as TaskType] !== (data.pipeline as Pipeline)\n ) {\n errors.push(\n `Pipeline inconsistency: task_type \"${data.task_type}\" requires pipeline \"${PIPELINE_MAP[data.task_type as TaskType]}\", got \"${data.pipeline}\"`,\n )\n }\n\n return { valid: errors.length === 0, errors }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern complexity-scoring\n * @ai-summary Complexity scoring, tiers, control modes, and pipeline profile resolution\n */\n\nimport type { TaskDefinition, TaskType, PipelineProfile } from './task-schema'\nimport { VALID_PIPELINE_PROFILES } from './task-schema'\nimport { STAGE_NAMES, STAGE_REGISTRY, getStageComplexityThreshold } from '../stages/registry'\n\n/** Named complexity tiers for display/logging */\nexport type ComplexityTier = 'trivial' | 'simple' | 'moderate' | 'complex' | 'very_complex'\n\nexport function getComplexityTier(score: number): ComplexityTier {\n if (score < 10) return 'trivial'\n if (score < 20) return 'simple'\n if (score < 35) return 'moderate'\n if (score < 50) return 'complex'\n return 'very_complex'\n}\n\n/**\n * Get stages that would run for a given complexity score.\n * Useful for logging and debugging.\n */\nexport function getStagesForComplexity(score: number): string[] {\n return STAGE_NAMES.filter((stage) => score >= STAGE_REGISTRY[stage].complexityThreshold)\n}\n\n// --- Control mode: determines pipeline autonomy level ---\nexport type ControlMode = 'auto' | 'risk-gated' | 'hard-stop'\n\nexport const CONTROL_MODE_MAP: Record<string, ControlMode> = {\n low: 'auto',\n medium: 'risk-gated',\n high: 'hard-stop',\n}\n\n/**\n * Resolve the control mode for a task based on its risk level.\n * User can override with explicit flags (--auto, --gate, --hard-stop).\n */\nexport function resolveControlMode(taskDef: TaskDefinition, override?: ControlMode): ControlMode {\n // Explicit override always wins (from /kody --auto, --gate, --hard-stop)\n if (override) return override\n\n // Derive from risk_level\n return CONTROL_MODE_MAP[taskDef.risk_level] ?? 'auto'\n}\n\n/**\n * Lightweight tasks: simple fixes that skip heavyweight stages (gap, plan-gap)\n *\n * When complexity score is available, derives profile from it:\n * complexity < 35 → lightweight (below gap threshold)\n * complexity >= 35 → standard (gap and above stages enabled)\n */\nconst LIGHTWEIGHT_TASK_TYPES: TaskType[] = ['fix_bug', 'refactor', 'ops', 'implement_feature']\n\nexport function resolvePipelineProfile(taskDef: TaskDefinition): PipelineProfile {\n // Agent explicit override always wins\n if (taskDef.pipeline_profile && VALID_PIPELINE_PROFILES.includes(taskDef.pipeline_profile)) {\n return taskDef.pipeline_profile\n }\n\n // When complexity score is available, derive profile from it\n if (taskDef.complexity !== undefined) {\n // Threshold = gap complexity threshold (35) — below this is lightweight\n return taskDef.complexity < getStageComplexityThreshold('gap') ? 'lightweight' : 'standard'\n }\n\n // Fallback: legacy heuristic for tasks without complexity score\n if (taskDef.risk_level === 'low' && LIGHTWEIGHT_TASK_TYPES.includes(taskDef.task_type)) {\n return 'lightweight'\n }\n\n // Everything else gets the full standard pipeline\n return 'standard'\n}\n\n// Lightweight tasks: simple fixes that skip heavyweight stages\n// Note: implement_feature added for low-risk features (e.g., adding loading/error files)\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern task-io\n * @ai-summary Task file I/O — reads and normalizes task.json from disk\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { TaskDefinition } from './task-schema'\nimport { normalizeTask, validateTask } from './task-schema'\n\nexport function readTask(taskDir: string): TaskDefinition | null {\n const taskFile = path.join(taskDir, 'task.json')\n if (!fs.existsSync(taskFile)) {\n return null\n }\n\n const content = fs.readFileSync(taskFile, 'utf-8')\n\n let raw: unknown\n try {\n raw = JSON.parse(content)\n } catch {\n const preview = content.slice(0, 200).replace(/\\n/g, '\\\\n')\n throw new Error(\n `task.json is not valid JSON.\\n` +\n ` File: ${taskFile}\\n` +\n ` Preview: ${preview}\\n` +\n ` Common causes:\\n` +\n ` • Agent wrapped JSON in markdown code fences\\n` +\n ` • Trailing comma in JSON\\n` +\n ` • Agent wrote commentary outside the JSON object\\n` +\n ` Fix task.json and re-run, or delete it to re-classify:\\n` +\n ` rm ${taskFile}`,\n )\n }\n\n // Normalize common LLM mistakes before validation\n if (typeof raw === 'object' && raw !== null) {\n raw = normalizeTask(raw as Record<string, unknown>)\n\n // Write back normalized values so subsequent reads are consistent\n fs.writeFileSync(taskFile, JSON.stringify(raw, null, 2) + '\\n')\n }\n\n const result = validateTask(raw)\n\n if (!result.valid) {\n throw new Error(\n `task.json validation failed:\\n${result.errors.map((e) => ` • ${e}`).join('\\n')}`,\n )\n }\n\n return raw as TaskDefinition\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern pipeline-utils\n * @ai-summary Pipeline utility functions — stage output, dry-run, parallel stage helpers\n */\n\nimport * as fs from 'fs'\n\nimport { stageOutputFile } from './stages/registry'\n\n// Re-export everything from extracted modules for backward compatibility\nexport * from './pipeline/task-schema'\nexport * from './pipeline/complexity'\nexport { readTask } from './pipeline/task-io'\n\nexport { stageOutputFile } from './stages/registry'\n\n// --- Pipeline stage definitions ---\n\nexport const SPEC_ONLY_STAGES = ['gap', 'clarify']\n\n// --- Dry-run support ---\n\nconst DRY_RUN_OUTPUTS: Record<string, (taskId: string) => string> = {\n taskify: () =>\n JSON.stringify(\n {\n task_type: 'implement_feature',\n risk_level: 'medium',\n confidence: 0.9,\n primary_domain: 'backend',\n scope: ['[dry-run] Mock scope item'],\n missing_inputs: [],\n assumptions: ['[dry-run] Mock assumption'],\n review_questions: [],\n },\n null,\n 2,\n ),\n gap: (taskId) => `# Gap Analysis (dry-run)\\n\\nNo gaps identified for ${taskId}.\\n`,\n clarify: (taskId) => `# Questions (dry-run)\\n\\n1. Mock question for ${taskId}?\\n`,\n architect: (taskId) => `# Plan (dry-run)\\n\\nMock plan for ${taskId}.\\n`,\n build: (taskId) => `# Build (dry-run)\\n\\nMock build output for ${taskId}.\\n`,\n test: (taskId) => `# Test (dry-run)\\n\\nMock test output for ${taskId}.\\n`,\n verify: (taskId) => `# Verify (dry-run)\\n\\nResult: PASS\\n\\nMock verification for ${taskId}.\\n`,\n commit: (taskId) => `# Commit (dry-run)\n\nMock commit output for ${taskId}.\n`,\n autofix: (taskId) => `# Autofix (dry-run)\n\nNo errors to fix for ${taskId}.\n`,\n pr: (taskId) => `# PR (dry-run)\n\nMock PR output for ${taskId}.\n`,\n}\n\nexport function writeDryRunOutput(taskDir: string, stage: string, taskId: string): void {\n const outputFile = stageOutputFile(taskDir, stage)\n const generator = DRY_RUN_OUTPUTS[stage]\n const content = generator ? generator(taskId) : `# ${stage} (dry-run)\\n\\nMock output.\\n`\n fs.writeFileSync(outputFile, content)\n}\n\n// --- Parallel stage support ---\n\n/**\n * A pipeline stage is either a single stage name (string) or a parallel group.\n * Parallel groups run all contained stages concurrently.\n */\nexport type PipelineStage = string | { parallel: string[] }\n\n/**\n * Check if a pipeline stage is a parallel group\n */\nexport function isParallelStage(stage: PipelineStage): stage is { parallel: string[] } {\n return typeof stage === 'object' && 'parallel' in stage\n}\n\n/**\n * Flatten a pipeline stage definition to its constituent stage names.\n * For a string, returns [stage]. For parallel, returns all contained stages.\n */\nexport function flattenStage(stage: PipelineStage): string[] {\n if (isParallelStage(stage)) {\n return stage.parallel\n }\n return [stage]\n}\n\n/**\n * Flatten an entire pipeline definition to a flat list of stage names.\n */\nexport function flattenPipeline(stages: PipelineStage[]): string[] {\n return stages.flatMap(flattenStage)\n}\n\n// --- Pipeline stage definitions moved to stages/registry.ts ---\n// Use IMPL_ORDER_STANDARD, IMPL_ORDER_LIGHTWEIGHT, etc. from registry.\n","/**\n * @fileType utility\n * @domain kody | github\n * @pattern github-api\n * @ai-summary GitHub API helpers extracted from kody-utils for better modularity\n */\n\nimport { logger } from './logger'\nimport { getComplexityTier } from './pipeline-utils'\nimport { execFileSync } from 'child_process'\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst GH_API_TIMEOUT = 30_000 // 30 seconds max per gh CLI call\n\n// ============================================================================\n// Synchronous Sleep Helper\n// ============================================================================\n\n/**\n * Synchronous sleep using Atomics.wait — blocks thread without busy-looping.\n * Used for retry delays in synchronous fire-and-forget functions.\n */\nexport function syncSleep(ms: number): void {\n const buf = new SharedArrayBuffer(4)\n const arr = new Int32Array(buf)\n Atomics.wait(arr, 0, 0, ms)\n}\n\n// ============================================================================\n// GitHub API Functions\n// ============================================================================\n\n/**\n * Post a comment to an issue.\n * Uses GH_PAT when available so comments are posted under the PAT identity,\n * which allows them to trigger other workflows (e.g. supervisor.yml).\n * Comments posted with GITHUB_TOKEN do NOT trigger other workflows due to\n * GitHub Actions security restrictions.\n */\nexport function postComment(issueNumber: number, body: string): void {\n if (!issueNumber) return\n\n // Use GH_PAT if available so the comment triggers other workflows (supervisor)\n const ghToken = process.env.GH_PAT?.trim() || process.env.GH_TOKEN\n const env = ghToken ? { ...process.env, GH_TOKEN: ghToken } : process.env\n\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n execFileSync('gh', ['issue', 'comment', String(issueNumber), '--body-file', '-'], {\n input: body,\n stdio: ['pipe', 'inherit', 'inherit'],\n env,\n timeout: GH_API_TIMEOUT,\n })\n return // Success\n } catch (error) {\n if (attempt === 0) {\n logger.warn(\n { err: error },\n `postComment attempt 1 failed for issue ${issueNumber}, retrying...`,\n )\n // Brief synchronous delay before retry (2 seconds)\n syncSleep(2000)\n } else {\n logger.error(\n { err: error },\n `Failed to post comment to issue ${issueNumber} after 2 attempts`,\n )\n }\n }\n }\n}\n\n/**\n * Get issue body\n */\nexport function getIssueBody(issueNumber: number): string | null {\n if (!issueNumber) return null\n\n try {\n const output = execFileSync(\n 'gh',\n ['issue', 'view', String(issueNumber), '--json', 'body', '--jq', '.body'],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n return output.trim() || null\n } catch (error) {\n logger.error({ err: error }, `Failed to get issue body for #${issueNumber}:`)\n return null\n }\n}\n\n/**\n * Get full issue data (body and title)\n */\nexport function getIssue(issueNumber: number): { body: string | null; title: string | null } {\n if (!issueNumber) return { body: null, title: null }\n\n try {\n const output = execFileSync(\n 'gh',\n [\n 'issue',\n 'view',\n String(issueNumber),\n '--json',\n 'body,title',\n '--jq',\n '{body: .body, title: .title}',\n ],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n const data = JSON.parse(output)\n return {\n body: data.body?.trim() || null,\n title: data.title?.trim() || null,\n }\n } catch (error) {\n logger.error({ err: error }, `Failed to get issue #${issueNumber}:`)\n return { body: null, title: null }\n }\n}\n\n/**\n * Get issue title\n */\nexport function getIssueTitle(issueNumber: number): string | null {\n if (!issueNumber) return null\n\n try {\n const output = execFileSync(\n 'gh',\n ['issue', 'view', String(issueNumber), '--json', 'title', '--jq', '.title'],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n return output.trim() || null\n } catch (error) {\n logger.error({ err: error }, `Failed to get issue title for #${issueNumber}:`)\n return null\n }\n}\n\n/**\n * Edit an existing comment\n * R6: Rewrote to use stdin instead of temp files for atomicity\n */\nexport function editComment(commentId: string, body: string): void {\n if (!commentId) return\n\n // R6: Replace 'OWNER/REPO' fallback with early return\n const repo = process.env.GITHUB_REPOSITORY\n if (!repo) {\n logger.error('editComment: GITHUB_REPOSITORY not set, skipping')\n return\n }\n\n try {\n // Use --input - to pipe body via stdin (atomic, no temp file)\n execFileSync(\n 'gh',\n ['api', `repos/${repo}/issues/comments/${commentId}`, '-X', 'PATCH', '--input', '-'],\n {\n input: JSON.stringify({ body }),\n stdio: ['pipe', 'inherit', 'inherit'],\n timeout: GH_API_TIMEOUT,\n },\n )\n } catch (error) {\n logger.error({ err: error }, `Failed to edit comment ${commentId}:`)\n }\n}\n\n/**\n * Get the latest comment on an issue (not from the bot, not a /kody command)\n */\nexport function getLatestIssueComment(issueNumber: number, excludeAuthor?: string): string | null {\n if (!issueNumber) return null\n\n try {\n const exclude = (excludeAuthor || 'github-actions[bot]').replace(/[^a-zA-Z0-9\\[\\]_\\-]/g, '')\n // Get comments, exclude bot and /kody commands, return the latest plain-text answer\n const output = execFileSync(\n 'gh',\n [\n 'issue',\n 'view',\n String(issueNumber),\n '--json',\n 'comments',\n '--jq',\n `[.comments[] | select(.author.login != \"${exclude}\" and (.body | startswith(\"/kody\") | not))] | last | .body`,\n ],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n return output.trim() || null\n } catch {\n return null\n }\n}\n\n/**\n * Get the latest approval/rejection command on an issue\n * Used by gate approval to detect /kody approve or /kody reject\n */\nexport function getLatestApprovalComment(\n issueNumber: number,\n excludeAuthor?: string,\n): string | null {\n if (!issueNumber) return null\n\n try {\n const exclude = (excludeAuthor || 'github-actions[bot]').replace(/[^a-zA-Z0-9\\[\\]_\\-]/g, '')\n // Get comments from users (not bot) that contain approval/rejection keywords\n // Matches: approve, approved, yes, go, proceed, y, continue, reject, rejected, no, cancel, stop, n\n // Uses 'i' flag for case-insensitive matching\n const output = execFileSync(\n 'gh',\n [\n 'issue',\n 'view',\n String(issueNumber),\n '--json',\n 'comments',\n '--jq',\n `[.comments[] | select(.author.login != \"${exclude}\" and (.body | test(\"^[/@]kody\\\\s+(approve|approved|yes|go|proceed|y|continue|reject|rejected|no|cancel|stop|n)(\\\\s|$)\"; \"i\")))] | last | .body`,\n ],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n return output.trim() || null\n } catch {\n return null\n }\n}\n\n/**\n * Canonical regex for extracting task-ID from \"Task created: `NNNNNN-slug`\" marker\n * Used by both parse-inputs.sh and TypeScript implementations\n */\nexport const TASK_ID_MARKER_REGEX = /Task created: `(\\d{6}-[a-zA-Z0-9-]+)`/\n\n/**\n * Extract task-ID from text using the canonical marker format\n * Returns null if no valid task-ID found\n */\nexport function extractTaskIdFromMarker(text: string): string | null {\n const match = text.match(TASK_ID_MARKER_REGEX)\n return match ? match[1] : null\n}\n\n/**\n * Discover task-id from a previous Kody run by parsing bot comments on the issue.\n * Looks for \"Task created: `XXXXXX-task-name`\" in any comment.\n */\nexport function discoverTaskIdFromIssue(issueNumber: number): string | null {\n if (!issueNumber) return null\n\n try {\n // Get all comments (don't filter by author - matches parse-inputs.sh behavior)\n // Use execFileSync for defense against shell injection\n const output = execFileSync(\n 'gh',\n ['issue', 'view', String(issueNumber), '--json', 'comments', '--jq', '.comments[].body'],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n // Use canonical task-ID marker regex\n const match = output.match(TASK_ID_MARKER_REGEX)\n return match ? match[1] : null\n } catch {\n return null\n }\n}\n\n// ============================================================================\n// PR Review Functions\n// ============================================================================\n\n/**\n * Fetch PR review feedback: the latest \"changes requested\" review body +\n * all inline review comments. Returns formatted markdown suitable for\n * writing to rerun-feedback.md.\n *\n * Uses `gh api` to fetch PR reviews and review comments.\n * Returns null if no change-request reviews or comments found.\n */\nexport function getPRReviewFeedback(prNumber: number): string | null {\n if (!prNumber) return null\n\n const repo = process.env.GITHUB_REPOSITORY\n if (!repo) {\n logger.warn('getPRReviewFeedback: GITHUB_REPOSITORY not set')\n return null\n }\n\n const sections: string[] = []\n\n // 1. Get the latest \"changes_requested\" review body\n try {\n const reviewsOutput = execFileSync(\n 'gh',\n [\n 'api',\n `repos/${repo}/pulls/${prNumber}/reviews`,\n '--jq',\n '[.[] | select(.state == \"CHANGES_REQUESTED\")] | last | {body: .body, user: .user.login, submitted_at: .submitted_at}',\n ],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n const review = JSON.parse(reviewsOutput.trim())\n if (review?.body) {\n sections.push(`## Change Request from @${review.user}\\n\\n${review.body}`)\n }\n } catch (error) {\n logger.warn({ err: error }, `Failed to fetch PR reviews for #${prNumber}`)\n }\n\n // 2. Get inline review comments (code-level feedback)\n try {\n const commentsOutput = execFileSync(\n 'gh',\n [\n 'api',\n `repos/${repo}/pulls/${prNumber}/comments`,\n '--jq',\n '[.[] | {path: .path, line: .line, body: .body, user: .user.login}]',\n ],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n const comments = JSON.parse(commentsOutput.trim()) as Array<{\n path: string\n line: number | null\n body: string\n user: string\n }>\n\n if (comments.length > 0) {\n const commentLines = comments.map((c) => {\n const location = c.line ? `${c.path}:${c.line}` : c.path\n return `- **${location}** (@${c.user}): ${c.body}`\n })\n const header = '## Inline Comments'\n sections.push(header + '\\n\\n' + commentLines.join('\\n'))\n }\n } catch (error) {\n logger.warn({ err: error }, `Failed to fetch PR review comments for #${prNumber}`)\n }\n\n if (sections.length === 0) return null\n\n return sections.join('\\n\\n')\n}\n\n/**\n * Discover the PR number associated with the current branch.\n * Uses `gh pr view` which finds the PR for the current HEAD branch.\n * Returns null if no PR exists.\n */\nexport function getCurrentPRNumber(): number | null {\n try {\n const output = execFileSync('gh', ['pr', 'view', '--json', 'number', '--jq', '.number'], {\n encoding: 'utf-8',\n timeout: GH_API_TIMEOUT,\n })\n const num = parseInt(output.trim(), 10)\n return isNaN(num) ? null : num\n } catch {\n return null\n }\n}\n\n/**\n * Discover the task ID from a PR by checking bot comments on the PR.\n * PRs are issues in GitHub's API, so we can reuse discoverTaskIdFromIssue.\n */\nexport function discoverTaskIdFromPR(prNumber: number): string | null {\n return discoverTaskIdFromIssue(prNumber)\n}\n\n/**\n * Get the issue number linked to a PR via \"Closes #XXX\" in the PR description.\n * Used in fix mode to find the original issue from a PR.\n */\nexport function getLinkedIssueFromPR(prNumber: number): number | null {\n if (!prNumber) return null\n try {\n const output = execFileSync(\n 'gh',\n [\n 'pr',\n 'view',\n String(prNumber),\n '--json',\n 'closingIssuesReferences',\n '--jq',\n '.closingIssuesReferences[0].number',\n ],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n ).trim()\n return output ? parseInt(output, 10) : null\n } catch {\n return null\n }\n}\n\n/**\n * Extract the gate comment body from a gate-*.md file.\n * The file is written as: `# Gate Request\\n\\n${formatGateComment(...)}\\n`\n * This function strips the `# Gate Request\\n\\n` prefix and trims trailing whitespace,\n * returning the full comment body ready to post to GitHub.\n */\nexport function extractGateCommentBody(fileContent: string): string {\n return fileContent.replace(/^# Gate Request\\n\\n/, '').trim()\n}\n\n/**\n * Ensure the \"Task created\" marker comment exists on the issue.\n *\n * This is critical for task-id discovery: when someone runs `/kody` on an issue,\n * the pipeline discovers the existing task-id by searching for a bot comment\n * containing \"Task created: `XXXXXX-task-name`\". Without this marker,\n * subsequent runs auto-generate a new task-id instead of reusing the existing one.\n */\nexport function ensureTaskMarkerComment(\n issueNumber: number,\n taskId: string,\n mode?: string,\n runUrl?: string,\n): void {\n if (!issueNumber || !taskId) return\n\n // Check if marker already exists for ANY task-id on this issue\n const existingTaskId = discoverTaskIdFromIssue(issueNumber)\n if (existingTaskId) {\n if (existingTaskId === taskId) {\n logger.info(`Task marker already exists on issue #${issueNumber} for ${taskId}`)\n } else {\n logger.info(\n `Task marker exists on issue #${issueNumber} for ${existingTaskId} (current: ${taskId})`,\n )\n }\n // Post a lightweight \"run started\" comment so every invocation has a visible run link\n if (runUrl) {\n const modeLine = mode ? ` (\\`${mode}\\` mode)` : ''\n postComment(\n issueNumber,\n `🔄 Kody re-run for \\`${existingTaskId}\\`${modeLine}\\nRun: ${runUrl}`,\n )\n }\n return\n }\n\n // Build comment with mode and run URL\n const modeLine = mode ? ` (\\`${mode}\\` mode)` : ''\n const runLine = runUrl ? `\\nRun: ${runUrl}` : ''\n\n // No marker found — post one\n logger.info(`Posting task marker comment on issue #${issueNumber} for ${taskId}`)\n postComment(\n issueNumber,\n `🎯 Task created: \\`${taskId}\\`${modeLine}${runLine}\\n\\nKody will now process this task.`,\n )\n}\n\n// ============================================================================\n// Label Functions\n// ============================================================================\n\n/**\n * Add a label to an issue\n */\nexport function addIssueLabel(issueNumber: number, label: string): void {\n if (!issueNumber || !label) return\n\n try {\n execFileSync('gh', ['issue', 'edit', String(issueNumber), '--add-label', label], {\n stdio: ['inherit', 'inherit', 'inherit'],\n timeout: GH_API_TIMEOUT,\n })\n logger.info(` Added label \"${label}\" to issue #${issueNumber}`)\n } catch (error) {\n logger.error({ err: error }, `Failed to add label \"${label}\" to issue ${issueNumber}:`)\n }\n}\n\n/**\n * Remove a label from an issue\n */\nexport function removeIssueLabel(issueNumber: number, label: string): void {\n if (!issueNumber || !label) return\n\n try {\n execFileSync('gh', ['issue', 'edit', String(issueNumber), '--remove-label', label], {\n stdio: ['inherit', 'inherit', 'inherit'],\n timeout: GH_API_TIMEOUT,\n })\n logger.info(` Removed label \"${label}\" from issue #${issueNumber}`)\n } catch (error) {\n logger.error({ err: error }, `Failed to remove label \"${label}\" from issue ${issueNumber}:`)\n }\n}\n\n/**\n * Gate labels for visibility in dashboard\n */\nexport const GATE_LABELS = {\n HARD_STOP: 'hard-stop',\n RISK_GATED: 'risk-gated',\n} as const\n\n// ============================================================================\n// Lifecycle and Classification Label Management\n// ============================================================================\n\n/**\n * Lifecycle labels - mutually exclusive, set by pipeline state machine\n */\nexport const LIFECYCLE_LABELS = [\n 'kody:planning',\n 'kody:building',\n 'kody:review',\n 'kody:done',\n 'kody:failed',\n] as const\n\n/**\n * Task type labels - set by taskify based on task_type field\n */\nexport const TASK_TYPE_LABELS = [\n 'type:bug',\n 'type:feature',\n 'type:refactor',\n 'type:docs',\n 'type:ops',\n] as const\n\n/**\n * Risk level labels - set by taskify based on risk_level field\n */\nexport const RISK_LABELS = ['risk:high', 'risk:medium', 'risk:low'] as const\n\n/**\n * Complexity labels - set by taskify based on complexity score\n * 1-30 = simple, 31-60 = moderate, 61-100 = complex\n */\nexport const COMPLEXITY_LABELS = [\n 'complexity:simple',\n 'complexity:moderate',\n 'complexity:complex',\n] as const\n\n/**\n * Domain labels - set by taskify based on primary_domain field\n */\nexport const DOMAIN_LABELS = [\n 'domain:backend',\n 'domain:frontend',\n 'domain:infra',\n 'domain:llm',\n 'domain:data',\n 'domain:devops',\n 'domain:product',\n] as const\n\n/**\n * Profile labels - set by resolve-profile post-action\n */\nexport const PROFILE_LABELS = ['profile:lightweight', 'profile:standard'] as const\n\n/**\n * Set a lifecycle label - adds new label and removes all other lifecycle labels\n * Fire-and-forget: errors are logged but never thrown\n */\nexport function setLifecycleLabel(issueNumber: number, label: string): void {\n if (!issueNumber || !label) return\n\n // Validate the label is a lifecycle label\n if (!LIFECYCLE_LABELS.includes(label as (typeof LIFECYCLE_LABELS)[number])) {\n logger.error(`Invalid lifecycle label: ${label}`)\n return\n }\n\n // Get all OTHER lifecycle labels to remove (mutual exclusion)\n const labelsToRemove = LIFECYCLE_LABELS.filter((l) => l !== label)\n\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n // Remove all other lifecycle labels, add the new one\n const args = [\n 'issue',\n 'edit',\n String(issueNumber),\n '--remove-label',\n labelsToRemove.join(','),\n '--add-label',\n label,\n ]\n execFileSync('gh', args, {\n stdio: ['inherit', 'inherit', 'inherit'],\n timeout: GH_API_TIMEOUT,\n })\n logger.info(` Set lifecycle label \"${label}\" on issue #${issueNumber}`)\n return // Success\n } catch (error) {\n if (attempt === 0) {\n logger.warn(\n { err: error },\n `setLifecycleLabel attempt 1 failed for issue ${issueNumber}, retrying...`,\n )\n syncSleep(2000)\n } else {\n logger.error(\n { err: error },\n `Failed to set lifecycle label \"${label}\" on issue ${issueNumber} after 2 attempts`,\n )\n }\n }\n }\n}\n\n/**\n * Set classification labels from task.json fields\n * Maps: task_type, risk_level, complexity, primary_domain\n * Fire-and-forget: errors are logged but never thrown\n */\nexport function setClassificationLabels(\n issueNumber: number,\n taskDef: {\n task_type?: string\n risk_level?: string\n complexity?: number\n primary_domain?: string\n },\n): void {\n if (!issueNumber) return\n if (!taskDef) {\n logger.error(`No task definition provided for issue #${issueNumber}`)\n return\n }\n\n const labels: string[] = []\n\n // Map task_type to type:* label\n if (taskDef.task_type) {\n const typeMap: Record<string, string> = {\n fix_bug: 'type:bug',\n implement_feature: 'type:feature',\n refactor: 'type:refactor',\n docs: 'type:docs',\n ops: 'type:ops',\n spec_only: 'type:feature', // treat spec as feature\n research: 'type:ops',\n }\n const label = typeMap[taskDef.task_type]\n if (label && TASK_TYPE_LABELS.includes(label as (typeof TASK_TYPE_LABELS)[number])) {\n labels.push(label)\n }\n }\n\n // Map risk_level to risk:* label\n if (taskDef.risk_level) {\n const riskLabel = `risk:${taskDef.risk_level}`\n if (RISK_LABELS.includes(riskLabel as (typeof RISK_LABELS)[number])) {\n labels.push(riskLabel)\n }\n }\n\n // Map complexity to complexity:* label (uses getComplexityTier for single source of truth)\n if (taskDef.complexity !== undefined) {\n const tier = getComplexityTier(taskDef.complexity)\n let label: string\n if (tier === 'trivial' || tier === 'simple') {\n label = 'complexity:simple'\n } else if (tier === 'moderate') {\n label = 'complexity:moderate'\n } else {\n // complex or very_complex\n label = 'complexity:complex'\n }\n labels.push(label)\n }\n\n // Map primary_domain to domain:* label\n if (taskDef.primary_domain) {\n const domainLabel = `domain:${taskDef.primary_domain}`\n if (DOMAIN_LABELS.includes(domainLabel as (typeof DOMAIN_LABELS)[number])) {\n labels.push(domainLabel)\n }\n }\n\n if (labels.length === 0) {\n logger.info(`No classification labels to set for issue #${issueNumber}`)\n return\n }\n\n // Build list of stale labels to remove (old labels in same category as new ones)\n const labelsToRemove: string[] = []\n const allCategoryLabels: ReadonlyArray<readonly string[]> = [\n TASK_TYPE_LABELS,\n RISK_LABELS,\n COMPLEXITY_LABELS,\n DOMAIN_LABELS,\n ]\n for (const category of allCategoryLabels) {\n const newInCategory = labels.filter((l) => category.includes(l as never))\n if (newInCategory.length > 0) {\n // Remove all OTHER labels in this category\n const stale = category.filter((l) => !newInCategory.includes(l))\n labelsToRemove.push(...stale)\n }\n }\n\n // FIX #8: Add retry logic for the critical add operation.\n // Step 1: Add new labels (critical — retry once on failure)\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n execFileSync('gh', ['issue', 'edit', String(issueNumber), '--add-label', labels.join(',')], {\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: GH_API_TIMEOUT,\n })\n logger.info(` Set classification labels [${labels.join(', ')}] on issue #${issueNumber}`)\n break // Success\n } catch (error) {\n if (attempt === 0) {\n logger.warn(\n { err: error },\n `Classification label add attempt 1 failed for issue ${issueNumber}, retrying...`,\n )\n syncSleep(2000)\n } else {\n logger.error(\n { err: error },\n `Failed to set classification labels on issue ${issueNumber} after 2 attempts`,\n )\n }\n }\n }\n\n // Step 2: Remove stale labels in a separate call (best-effort with retry).\n // This is separate because `gh issue edit --remove-label` fails if ANY label in the\n // list doesn't exist on the repo. By separating add/remove, a remove failure\n // doesn't prevent the add from succeeding.\n if (labelsToRemove.length > 0) {\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n execFileSync(\n 'gh',\n ['issue', 'edit', String(issueNumber), '--remove-label', labelsToRemove.join(',')],\n {\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: GH_API_TIMEOUT,\n },\n )\n break // Success\n } catch {\n if (attempt === 0) {\n syncSleep(1000)\n }\n // Silently ignore on final attempt — labels may not exist on the repo or issue.\n // This is expected for newly added domain/category labels.\n }\n }\n }\n}\n\n/**\n * Set profile label - adds new profile and removes the other\n * Fire-and-forget: errors are logged but never thrown\n */\nexport function setProfileLabel(\n issueNumber: number,\n profile: 'lightweight' | 'standard' | 'turbo',\n): void {\n if (!issueNumber || !profile) return\n\n const label = `profile:${profile}`\n const otherLabel = profile === 'lightweight' ? 'profile:standard' : 'profile:lightweight'\n\n try {\n execFileSync(\n 'gh',\n ['issue', 'edit', String(issueNumber), '--remove-label', otherLabel, '--add-label', label],\n { stdio: ['inherit', 'inherit', 'inherit'], timeout: GH_API_TIMEOUT },\n )\n logger.info(` Set profile label \"${label}\" on issue #${issueNumber}`)\n } catch (error) {\n logger.error({ err: error }, `Failed to set profile label on issue ${issueNumber}:`)\n }\n}\n\n/**\n * Close an issue with a reason\n * Fire-and-forget: errors are logged but never thrown\n */\nexport function closeIssue(\n issueNumber: number,\n reason: 'completed' | 'not planned' = 'completed',\n): void {\n if (!issueNumber) return\n\n try {\n execFileSync('gh', ['issue', 'close', String(issueNumber), '--reason', reason], {\n stdio: ['inherit', 'inherit', 'inherit'],\n timeout: GH_API_TIMEOUT,\n })\n logger.info(` Closed issue #${issueNumber} (${reason})`)\n } catch (error) {\n logger.error({ err: error }, `Failed to close issue ${issueNumber}:`)\n }\n}\n\n/**\n * Close PR associated with an issue and delete the branch\n * Uses --delete-branch to remove both local and remote branches\n * Fire-and-forget: errors are logged but never thrown\n */\nexport function closeLinkedPR(issueNumber: number): boolean {\n if (!issueNumber) return false\n\n try {\n // Find PR linked to this issue\n const listResult = execFileSync(\n 'gh',\n ['pr', 'list', '--search', `closes:#${issueNumber}`, '--json', 'number'],\n { encoding: 'utf-8', timeout: GH_API_TIMEOUT },\n )\n const prs = JSON.parse(listResult) as { number: number }[]\n\n if (prs.length === 0) {\n logger.info(` No PR found for issue #${issueNumber}`)\n return false\n }\n\n const prNumber = prs[0].number\n\n // Close PR and delete branch in one command\n execFileSync('gh', ['pr', 'close', String(prNumber), '--delete-branch'], {\n stdio: ['inherit', 'inherit', 'inherit'],\n timeout: GH_API_TIMEOUT,\n })\n logger.info(` ✅ Closed PR #${prNumber} and deleted branch`)\n return true\n } catch (error) {\n logger.error({ err: error }, `Failed to close PR for issue ${issueNumber}:`)\n return false\n }\n}\n\n/**\n * Close an issue, its associated PR, and delete the branch\n * This is a convenience function that combines closeIssue and closeLinkedPR\n * Use this when you want to close an issue and clean up the PR/branch in one action\n * Fire-and-forget: errors are logged but never thrown\n */\nexport function closeIssueWithCleanup(\n issueNumber: number,\n reason: 'completed' | 'not planned' = 'completed',\n): void {\n if (!issueNumber) return\n\n // First close the PR and delete the branch\n closeLinkedPR(issueNumber)\n\n // Then close the issue\n closeIssue(issueNumber, reason)\n}\n","/**\n * @fileType utility\n * @domain kody | cli\n * @pattern cli-parser\n * @ai-summary CLI argument parsing and GitHub comment body parsing for the Kody pipeline\n */\n\nimport { Command } from 'commander'\nimport { randomInt } from 'crypto'\n\nimport * as path from 'path'\n\nimport type { KodyInput } from './kody-utils'\nimport { isValidMode, isValidStage, validateTaskId, VALID_MODES, VALID_STAGES } from './validation'\nimport { discoverTaskIdFromIssue } from './github-api'\nimport { logger } from './logger'\n\n// ============================================================================\n// CLI Argument Parsing\n// ============================================================================\n\nexport function parseCliArgs(argv: string[]): KodyInput {\n // Create Commander program with all CLI options\n const program = new Command()\n .allowUnknownOption()\n .allowExcessArguments()\n .option('--task-id <id>', 'Task ID')\n .option('--mode <mode>', 'Pipeline mode (spec, impl, rerun, full, status)')\n .option('--file <path>', 'Task file path')\n .option('--dry-run', 'Dry run mode')\n .option('--issue-number <n>', 'GitHub issue number')\n .option('--from <stage>', 'Resume from stage')\n .option('--feedback <text>', 'Rerun feedback')\n .option('--auto', 'Autonomous mode')\n .option('--gate', 'Risk-gated mode')\n .option('--hard-stop', 'Hard stop mode')\n .option('--local', 'Local mode')\n .option('--github', 'Use GitHub-hosted runner')\n .option('--ci', 'Use GitHub-hosted runner (alias for --github)')\n .option('--clarify', 'Run clarify stage')\n .option('--complexity <n>', 'Complexity score (1-100)')\n .option('--is-pull-request', 'Comment was on a PR')\n .option('--fresh', 'Force new PR')\n .option('--comment-body <text>', 'Comment body')\n .option('--comment-body-env <var>', 'Env var for comment body')\n .option('--version <ver>', 'Pipeline version')\n .option('--trigger-type <type>', 'Trigger type')\n .option('--run-id <id>', 'CI run ID')\n .option('--run-url <url>', 'CI run URL')\n .exitOverride() // Don't exit on --help, throw instead\n .configureOutput({\n writeOut: () => {}, // Suppress output during parsing\n writeErr: () => {},\n })\n\n let commanderOpts: Record<string, unknown> = {}\n try {\n // Commander handles both --key value and --key=value formats\n program.parse(['node', 'entry.ts', ...argv])\n commanderOpts = program.opts()\n } catch {\n // Commander throws on --help, --version, or unknown options\n // We suppress the error and continue with defaults\n }\n\n const input: KodyInput = {\n mode: 'full',\n taskId: '',\n dryRun: false,\n }\n\n // Track which fields were explicitly set via CLI args\n // Env vars should only be used as fallback when CLI arg wasn't provided\n const cliSet = new Set<string>()\n\n // Map Commander options to KodyInput\n // NOTE: --mode is processed LAST to preserve original behavior where\n // later args override earlier ones (e.g., --mode after --comment-body)\n // Commander returns undefined for options that weren't provided\n\n if (commanderOpts.taskId !== undefined) {\n input.taskId = commanderOpts.taskId as string\n cliSet.add('taskId')\n }\n\n // Process --mode initially (always) so comment-body can override it when appropriate\n // If --mode comes AFTER --comment-body in argv, we'll process it again at the end\n if (commanderOpts.mode !== undefined) {\n const mode = commanderOpts.mode as string\n if (!isValidMode(mode)) {\n throw new Error(`Invalid mode: ${mode}. Valid: ${VALID_MODES.join(', ')}`)\n }\n input.mode = mode\n cliSet.add('mode')\n }\n\n if (commanderOpts.dryRun !== undefined) {\n input.dryRun = true\n cliSet.add('dryRun')\n }\n\n if (commanderOpts.feedback !== undefined) {\n input.feedback = commanderOpts.feedback as string\n cliSet.add('feedback')\n }\n\n if (commanderOpts.from !== undefined) {\n const stage = commanderOpts.from as string\n if (!isValidStage(stage)) {\n throw new Error(`Invalid stage: ${stage}. Valid: ${VALID_STAGES.join(', ')}`)\n }\n input.fromStage = stage\n cliSet.add('fromStage')\n }\n\n // Control mode flags\n if (commanderOpts.auto !== undefined) {\n input.controlMode = 'auto'\n cliSet.add('controlMode')\n } else if (commanderOpts.gate !== undefined) {\n input.controlMode = 'risk-gated'\n cliSet.add('controlMode')\n } else if (commanderOpts.hardStop !== undefined) {\n input.controlMode = 'hard-stop'\n cliSet.add('controlMode')\n }\n\n if (commanderOpts.issueNumber !== undefined) {\n input.issueNumber = parseInt(commanderOpts.issueNumber as string, 10)\n cliSet.add('issueNumber')\n }\n\n if (commanderOpts.triggerType !== undefined) {\n input.triggerType = commanderOpts.triggerType as 'dispatch' | 'comment'\n cliSet.add('triggerType')\n }\n\n if (commanderOpts.runId !== undefined) {\n input.runId = commanderOpts.runId as string\n cliSet.add('runId')\n }\n\n if (commanderOpts.runUrl !== undefined) {\n input.runUrl = commanderOpts.runUrl as string\n cliSet.add('runUrl')\n }\n\n if (commanderOpts.version !== undefined) {\n input.version = commanderOpts.version as string\n cliSet.add('version')\n }\n\n if (commanderOpts.isPullRequest !== undefined) {\n input.isPullRequest = true\n cliSet.add('isPullRequest')\n }\n\n if (commanderOpts.fresh !== undefined) {\n input.fresh = true\n cliSet.add('fresh')\n }\n\n // Handle --comment-body-env=<var> (Commander may not parse this with --key=value pattern)\n const commentBodyEnvArg = argv.find((arg) => arg.startsWith('--comment-body-env='))\n if (commentBodyEnvArg) {\n const envVarName = commentBodyEnvArg.slice('--comment-body-env='.length)\n const commentBodyFromEnv = process.env[envVarName]\n if (commentBodyFromEnv) {\n const parsed = parseCommentBody(commentBodyFromEnv, undefined)\n if (!parsed.success) {\n throw new Error(parsed.error || 'Failed to parse comment body from env var')\n }\n if (parsed.input) {\n input.mode = parsed.input.mode\n cliSet.add('mode')\n if (parsed.input.taskId) {\n input.taskId = parsed.input.taskId\n cliSet.add('taskId')\n }\n input.dryRun = parsed.input.dryRun\n cliSet.add('dryRun')\n if (parsed.input.feedback) {\n input.feedback = parsed.input.feedback\n cliSet.add('feedback')\n }\n if (parsed.input.fromStage) {\n input.fromStage = parsed.input.fromStage\n cliSet.add('fromStage')\n }\n input.triggerType = 'comment'\n cliSet.add('triggerType')\n if (parsed.input.controlMode) {\n input.controlMode = parsed.input.controlMode\n cliSet.add('controlMode')\n }\n if (parsed.input.issueNumber) {\n input.issueNumber = parsed.input.issueNumber\n cliSet.add('issueNumber')\n }\n }\n }\n }\n\n if (commanderOpts.commentBody !== undefined) {\n const commentBody = commanderOpts.commentBody as string\n input.commentBody = commentBody\n const parsed = parseCommentBody(commentBody, undefined)\n\n if (!parsed.success) {\n throw new Error(parsed.error || 'Failed to parse comment body')\n }\n\n if (parsed.input) {\n input.mode = parsed.input.mode\n cliSet.add('mode')\n if (parsed.input.taskId) {\n input.taskId = parsed.input.taskId\n cliSet.add('taskId')\n }\n input.dryRun = parsed.input.dryRun\n cliSet.add('dryRun')\n if (parsed.input.feedback) {\n input.feedback = parsed.input.feedback\n cliSet.add('feedback')\n }\n if (parsed.input.fromStage) {\n input.fromStage = parsed.input.fromStage\n cliSet.add('fromStage')\n }\n input.triggerType = 'comment'\n cliSet.add('triggerType')\n if (parsed.input.controlMode) {\n input.controlMode = parsed.input.controlMode\n cliSet.add('controlMode')\n }\n if (parsed.input.issueNumber) {\n input.issueNumber = parsed.input.issueNumber\n cliSet.add('issueNumber')\n }\n }\n }\n\n if (commanderOpts.file !== undefined) {\n input.file = commanderOpts.file as string\n cliSet.add('file')\n // --file triggers taskId auto-generation, so don't let env var override\n cliSet.add('taskId')\n }\n\n if (commanderOpts.local !== undefined) {\n input.local = true\n cliSet.add('local')\n } else if (commanderOpts.github !== undefined || commanderOpts.ci !== undefined) {\n // --github or --ci explicitly sets local = false\n input.local = false\n cliSet.add('local')\n }\n\n if (commanderOpts.clarify !== undefined) {\n input.clarify = true\n cliSet.add('clarify')\n }\n\n if (commanderOpts.complexity !== undefined) {\n const val = parseInt(commanderOpts.complexity as string, 10)\n if (!isNaN(val) && val >= 1 && val <= 100) {\n input.complexityOverride = val\n cliSet.add('complexityOverride')\n } else {\n throw new Error(`Invalid --complexity value: ${commanderOpts.complexity}. Must be 1-100`)\n }\n }\n\n // Also handle positional arguments (non -- options) and determine arg processing order\n // We need to process --mode AFTER --comment-body ONLY when --mode actually comes AFTER --comment-body in argv\n // to preserve original CLI behavior where later args override earlier ones\n // (run-kody.sh puts --mode BEFORE --comment-body, so comment-body should win)\n const modeArgIndex = argv.findIndex((a) => a.startsWith('--mode'))\n const commentBodyArgIndex = argv.findIndex((a) => a.startsWith('--comment-body'))\n // Only process --mode at the end when it comes AFTER --comment-body\n const processModeLast = modeArgIndex > commentBodyArgIndex && commentBodyArgIndex >= 0\n\n // Options that consume the next arg as their value (--key <value> format)\n const optionsWithValues = new Set([\n '--task-id',\n '--mode',\n '--file',\n '--issue-number',\n '--from',\n '--feedback',\n '--complexity',\n '--comment-body',\n '--comment-body-env',\n '--version',\n '--trigger-type',\n '--run-id',\n '--run-url',\n ])\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i]\n\n // Skip values that belong to --key <value> options\n if (arg.startsWith('--') && optionsWithValues.has(arg) && i + 1 < argv.length) {\n i++ // skip the next arg (option value)\n continue\n }\n // Skip flags and unknown options\n if (arg.startsWith('-')) continue\n\n // Check if it's a valid mode\n if (isValidMode(arg)) {\n input.mode = arg\n cliSet.add('mode')\n continue\n }\n // Otherwise treat as file path (if it looks like a path)\n if (arg.includes('/') || arg.includes('.') || arg.includes('-')) {\n input.file = arg\n cliSet.add('file')\n cliSet.add('taskId') // --file triggers taskId auto-generation\n continue\n }\n }\n\n // Process --mode AFTER --comment-body only when it appears later in argv\n // This preserves the original CLI behavior where later args override earlier ones\n if (processModeLast) {\n if (commanderOpts.mode !== undefined) {\n const mode = commanderOpts.mode as string\n if (!isValidMode(mode)) {\n throw new Error(`Invalid mode: ${mode}. Valid: ${VALID_MODES.join(', ')}`)\n }\n input.mode = mode\n cliSet.add('mode')\n }\n }\n\n // Read from environment variables (for CI workflow)\n // CLI args take precedence over env vars - only use env var if field wasn't CLI-set\n // Use process.env directly (not getEnv()) for test compatibility\n if (!cliSet.has('taskId') && process.env.TASK_ID) {\n input.taskId = process.env.TASK_ID\n }\n if (!cliSet.has('mode') && process.env.MODE && isValidMode(process.env.MODE)) {\n input.mode = process.env.MODE\n }\n if (!cliSet.has('dryRun') && process.env.DRY_RUN === 'true') {\n input.dryRun = true\n }\n if (!cliSet.has('feedback') && process.env.FEEDBACK) {\n input.feedback = process.env.FEEDBACK\n }\n if (!cliSet.has('fromStage') && process.env.FROM_STAGE) {\n input.fromStage = process.env.FROM_STAGE\n }\n if (!cliSet.has('clarify') && process.env.CLARIFY === 'true') {\n input.clarify = true\n }\n if (!cliSet.has('issueNumber') && process.env.ISSUE_NUMBER) {\n input.issueNumber = parseInt(process.env.ISSUE_NUMBER, 10)\n }\n if (!cliSet.has('triggerType') && process.env.TRIGGER_TYPE) {\n input.triggerType = process.env.TRIGGER_TYPE as 'dispatch' | 'comment'\n }\n if (!cliSet.has('runId') && process.env.RUN_ID) {\n input.runId = process.env.RUN_ID\n }\n if (!cliSet.has('runUrl') && process.env.RUN_URL) {\n input.runUrl = process.env.RUN_URL\n }\n if (!cliSet.has('version') && process.env.VERSION) {\n input.version = process.env.VERSION\n }\n if (!cliSet.has('fresh') && process.env.FRESH === 'true') {\n input.fresh = true\n }\n if (!cliSet.has('complexityOverride') && process.env.COMPLEXITY) {\n const val = parseInt(process.env.COMPLEXITY, 10)\n if (!isNaN(val) && val >= 1 && val <= 100) {\n input.complexityOverride = val\n }\n }\n // Store raw comment body for gate approval detection (only for comment triggers)\n if (!input.commentBody && process.env.COMMENT_BODY && input.triggerType === 'comment') {\n input.commentBody = process.env.COMMENT_BODY\n }\n\n // Read IS_PULL_REQUEST from env (set by workflow for PR comments and PR review triggers)\n if (!cliSet.has('isPullRequest') && process.env.IS_PULL_REQUEST === 'true') {\n input.isPullRequest = true\n }\n\n // Read GITHUB_ACTOR — the GitHub login of the person who triggered the workflow\n if (!cliSet.has('actor') && process.env.GITHUB_ACTOR) {\n input.actor = process.env.GITHUB_ACTOR\n }\n\n // Read ISSUE_CREATOR — the GitHub login of the person who created the issue\n if (!cliSet.has('issueCreator') && process.env.ISSUE_CREATOR) {\n input.issueCreator = process.env.ISSUE_CREATOR\n }\n\n // Determine local mode: explicitly set or auto-detect from GITHUB_ACTIONS\n // Use process.env directly (not getEnv()) for test compatibility\n if (input.local === undefined) {\n input.local = !process.env.GITHUB_ACTIONS\n }\n\n // Auto-generate taskId if not provided\n if (!input.taskId) {\n // Try to discover task-id from previous bot comments on the issue\n // Skip discovery when --fresh flag is set — we want a brand-new task ID\n if (input.issueNumber && input.triggerType === 'comment' && !input.fresh) {\n const discovered = discoverTaskIdFromIssue(input.issueNumber)\n if (discovered) {\n input.taskId = discovered\n logger.info(`Discovered task ID from issue: ${input.taskId}`)\n }\n }\n if (input.fresh && input.issueNumber) {\n logger.info(`--fresh flag: skipping task ID discovery for issue #${input.issueNumber}`)\n }\n\n // If still no task-id, generate one\n if (!input.taskId) {\n if (input.file) {\n // Generate from filename: --file path/to/feature.md -> 260218-feature\n const stem = path.basename(input.file, path.extname(input.file))\n const datePrefix = new Date().toISOString().slice(2, 10).replace(/-/g, '')\n input.taskId = `${datePrefix}-${stem.replace(/[^a-zA-Z0-9-]/g, '-').toLowerCase()}`\n } else {\n // Fallback: auto-generate from date\n const datePrefix = new Date().toISOString().slice(2, 10).replace(/-/g, '')\n const counter = randomInt(100, 999)\n input.taskId = `${datePrefix}-auto-${counter}`\n }\n logger.info(`Auto-generated task ID: ${input.taskId}`)\n }\n }\n\n if (!validateTaskId(input.taskId)) {\n throw new Error(`Invalid task-id format: ${input.taskId}. Expected: YYMMDD-description`)\n }\n\n return input\n}\n\n// ============================================================================\n// Comment Body Parsing\n// ============================================================================\n\ninterface ParseCommentResult {\n success: boolean\n input?: KodyInput\n error?: string\n errorComment?: string // Error message to post back to the issue\n}\n\n/**\n * Parse a GitHub issue comment body in the format:\n * /kody <subcommand> <task-id> [options]\n *\n * Examples:\n * /kody 260218-user-metrics -> full mode, task 260218-user-metrics\n * /kody spec 260218-user-metrics -> spec mode\n * /kody impl 260218-user-metrics -> impl mode\n * /kody rerun 260218-user-metrics --feedback \"fix this\"\n * /kody -> full mode, auto-generate task-id\n */\nexport function parseCommentBody(body: string, issueNumber?: number): ParseCommentResult {\n // Decode JSON-encoded body from YAML (jq -Rs . wraps in quotes and escapes)\n let decoded = body\n if (decoded.startsWith('\"') && decoded.endsWith('\"')) {\n try {\n decoded = JSON.parse(decoded)\n } catch {\n // Use raw value if JSON.parse fails\n }\n }\n\n // Normalize literal \\n sequences to real newlines\n // (double-escaping from the GitHub Actions → shell → pnpm → Node.js pipeline\n // can leave literal backslash-n instead of actual newlines)\n decoded = decoded.replace(/\\\\n/g, '\\n')\n\n // Only parse the first line — /kody commands live on line 1;\n // trailing lines are just whitespace or comment noise\n const firstLine = decoded.split('\\n')[0]\n const cmd = firstLine.replace(/^\\/kody\\s*/, '').trim()\n\n // Extract subcommand (first word)\n const spaceIdx = cmd.indexOf(' ')\n const subCmd = spaceIdx === -1 ? cmd : cmd.slice(0, spaceIdx)\n const rest = spaceIdx === -1 ? '' : cmd.slice(spaceIdx + 1).trim()\n\n // Handle empty command: /kody with no subcommand defaults to full\n let mode: KodyInput['mode'] = 'full'\n let taskId = rest\n let implicitFeedback: string | undefined\n\n // Handle task-id as subcommand: /kody 260218-task defaults to full with that task\n const isTaskId = /^[0-9]{6}-[a-zA-Z0-9-]+$/.test(subCmd)\n if (isTaskId) {\n mode = 'full'\n taskId = `${subCmd}${rest ? ' ' + rest : ''}`.trim()\n // When task-id is the subcommand, we need to track what was \"rest\" for options parsing\n // The reconstructed taskId now contains both the ID and options, so use it as original\n } else if (subCmd) {\n // Handle approve/reject specially - these are for gate approval, not mode selection\n const lowerSubCmd = subCmd.toLowerCase()\n if (\n lowerSubCmd === 'approve' ||\n lowerSubCmd === 'reject' ||\n lowerSubCmd === 'yes' ||\n lowerSubCmd === 'no' ||\n lowerSubCmd === 'go' ||\n lowerSubCmd === 'proceed'\n ) {\n // Keep existing mode - gate approval logic will detect these keywords\n // Don't change mode, just pass through. The gate check will handle approval detection.\n // If no mode is set yet, default to full for resuming gated tasks\n if (!mode) mode = 'full'\n } else if (isValidMode(subCmd)) {\n // Validate subcommand\n mode = subCmd as KodyInput['mode']\n } else {\n // Unrecognized subcommand: treat as rerun with implicit feedback\n // e.g., \"/kody adjust tests\" → rerun mode, feedback = \"adjust tests\"\n mode = 'rerun'\n // Capture both the subcommand and rest as implicit feedback\n implicitFeedback = rest ? `${subCmd} ${rest}`.trim() : subCmd\n }\n }\n\n // Extract task-id — ONLY if it matches the task-id pattern (YYMMDD-description)\n // If it doesn't match, for rerun mode treat remaining text as implicit feedback\n // For other modes, leave task-id empty (will be auto-discovered from issue)\n const taskIdPattern = /^[0-9]{6}-[a-zA-Z0-9-]+$/\n\n if (taskId) {\n const firstWord = taskId.split(' ')[0]\n if (taskIdPattern.test(firstWord)) {\n // First word is a valid task-id\n taskId = firstWord\n } else {\n // First word is NOT a task-id\n if (mode === 'rerun' || mode === 'fix') {\n // For rerun/fix: treat all remaining text as implicit feedback\n // This handles \"@kody fix the button isn't showing\" → feedback = \"the button isn't showing\"\n implicitFeedback = taskId\n }\n taskId = '' // will be auto-discovered from issue\n }\n }\n\n // Don't auto-generate task-id here — let parseCliArgs handle discovery + fallback generation\n // This allows discoverTaskIdFromIssue to find the task-id from previous bot comments\n\n // Parse remaining options (--feedback, --from, --dry-run)\n // rest contains: for isTaskId case: \"options\", for explicit mode case: \"task-id options\"\n let optionsStr = ''\n if (isTaskId) {\n // Task-id as subcommand: rest has only options (after task-id)\n optionsStr = rest.trim()\n } else if (taskId) {\n // Explicit mode: rest = \"task-id options...\", skip past the task-id to get options\n const taskIdLen = taskId.length\n optionsStr = rest.slice(taskIdLen).trim()\n } else {\n // No task-id provided: rest is all options\n optionsStr = rest.trim()\n }\n\n const options = optionsStr.split(/\\s+/)\n let dryRun = false\n let feedback: string | undefined\n let fromStage: string | undefined\n let controlMode: KodyInput['controlMode'] = undefined\n let fresh = false\n\n let i = 0\n while (i < options.length) {\n const opt = options[i]\n if (opt === '--dry-run') {\n dryRun = true\n i++\n } else if (opt === '--auto') {\n controlMode = 'auto'\n i++\n } else if (opt === '--gate') {\n controlMode = 'risk-gated'\n i++\n } else if (opt === '--hard-stop') {\n controlMode = 'hard-stop'\n i++\n } else if (opt === '--feedback' && options[i + 1]) {\n // Capture all remaining words until the next --flag as feedback\n const feedbackParts: string[] = []\n let j = i + 1\n while (j < options.length && !options[j].startsWith('--')) {\n feedbackParts.push(options[j])\n j++\n }\n feedback = feedbackParts.join(' ')\n i = j\n } else if (opt === '--fresh') {\n fresh = true\n i++\n } else if (opt === '--from' && options[i + 1]) {\n fromStage = options[i + 1]\n // Validate from stage\n if (!isValidStage(fromStage)) {\n return {\n success: false,\n error: `Invalid stage: ${fromStage}`,\n errorComment: `Invalid stage: \\`${fromStage}\\`. Valid: \\`${VALID_STAGES.join(', ')}\\``,\n }\n }\n i += 2\n } else {\n // Skip unknown options\n i++\n }\n }\n\n // Use implicit feedback if no explicit --feedback was provided (for rerun mode)\n const finalFeedback = feedback || implicitFeedback\n\n return {\n success: true,\n input: {\n mode,\n taskId,\n dryRun,\n feedback: finalFeedback,\n fromStage,\n issueNumber,\n triggerType: 'comment',\n fresh,\n controlMode,\n },\n }\n}\n","/**\n * @fileType utility\n * @domain kody | formatting\n * @pattern status-format\n * @ai-summary Status comment formatting helpers for GitHub issue comments\n */\n\nimport type { KodyInput, KodyPipelineStatus } from './kody-utils'\n\n// ============================================================================\n// Formatting Helpers\n// ============================================================================\n\nexport function formatDuration(ms: number): string {\n const seconds = Math.floor(ms / 1000)\n const minutes = Math.floor(seconds / 60)\n const remainingSeconds = seconds % 60\n\n if (minutes > 0) {\n return `${minutes}m ${remainingSeconds}s`\n }\n return `${seconds}s`\n}\n\nexport function formatStatusComment(\n input: KodyInput,\n status: KodyPipelineStatus,\n currentStage?: string,\n _currentState?: string, // Reserved for future use\n): string {\n const lines: string[] = []\n\n if (status.state === 'running') {\n lines.push(`🔄 Kody running for \\`${input.taskId}\\` (mode: ${input.mode})`)\n lines.push('')\n\n if (currentStage) {\n const stageList = Object.entries(status.stages)\n for (const [stage, stageStatus] of stageList) {\n const icon =\n stageStatus.state === 'completed'\n ? '✅'\n : stageStatus.state === 'failed'\n ? '❌'\n : stageStatus.state === 'running'\n ? '🔄'\n : '⏳'\n const elapsed = stageStatus.elapsed ? ` (${formatDuration(stageStatus.elapsed)})` : ''\n lines.push(` ${icon} ${stage}${elapsed}`)\n }\n }\n } else if (status.state === 'completed') {\n lines.push(`✅ Kody completed for \\`${input.taskId}\\`!`)\n lines.push(`Mode: ${input.mode}`)\n\n // Add per-stage table with timing and cost\n const completedStages = Object.entries(status.stages)\n const hasCostData = completedStages.some(([, s]) => s.cost !== undefined && s.cost > 0)\n\n if (completedStages.length > 0) {\n lines.push('')\n if (hasCostData) {\n // Full table with cost column\n lines.push('| Stage | Status | Duration | Cost |')\n lines.push('|-------|--------|----------|------|')\n for (const [stage, stageStatus] of completedStages) {\n const icon =\n stageStatus.state === 'completed' ? '✅' : stageStatus.state === 'skipped' ? '⏭️' : '❌'\n const elapsed = stageStatus.elapsed ? formatDuration(stageStatus.elapsed) : '—'\n const cost =\n stageStatus.cost !== undefined && stageStatus.cost > 0\n ? `$${stageStatus.cost.toFixed(4)}`\n : '—'\n lines.push(`| ${stage} | ${icon} | ${elapsed} | ${cost} |`)\n }\n // Total row\n if (status.totalCost !== undefined && status.totalCost > 0) {\n lines.push(`| **Total** | | | **$${status.totalCost.toFixed(4)}** |`)\n }\n } else {\n // Simple list without cost (backward compat)\n for (const [stage, stageStatus] of completedStages) {\n const icon = stageStatus.state === 'completed' ? '✅' : '❌'\n const elapsed = stageStatus.elapsed ? ` (${formatDuration(stageStatus.elapsed)})` : ''\n lines.push(` ${icon} ${stage}${elapsed}`)\n }\n }\n }\n } else if (status.state === 'paused') {\n lines.push(`⏸️ Kody paused for \\`${input.taskId}\\``)\n lines.push(\n 'Awaiting approval — reply with `@kody approve` or `/kody approve` to proceed. ' +\n 'Reply with `@kody reject` or `/kody reject` to cancel.',\n )\n } else if (status.state === 'failed') {\n lines.push(`❌ Kody failed for \\`${input.taskId}\\``)\n } else if (status.state === 'timeout') {\n lines.push(`⏰ Kody timed out for \\`${input.taskId}\\``)\n }\n\n // Always append run URL regardless of state\n if (input.runUrl) {\n lines.push(`Run: ${input.runUrl}`)\n }\n\n return lines.join('\\n')\n}\n\nexport async function formatStatusCommentV2(input: KodyInput, stateV2: unknown): Promise<string> {\n if (!stateV2 || typeof stateV2 !== 'object') {\n return `❌ Invalid pipeline state for \\`${input.taskId}\\``\n }\n const { stateToV1 } = await import('./engine/status')\n return formatStatusComment(input, stateToV1(stateV2 as Parameters<typeof stateToV1>[0]))\n}\n","/**\n * @fileType utility\n * @domain ci | kody | github\n * @pattern kody-pipeline | github-api | status-tracking\n * @ai-summary CI-specific utilities for the Kody pipeline: comment parsing, GitHub API helpers, status management\n */\n\nimport { logger } from './logger'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { STAGE_NAMES } from './stages/registry'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface KodyInput {\n mode: 'spec' | 'impl' | 'rerun' | 'fix' | 'full' | 'status' | 'design-system'\n taskId: string\n dryRun: boolean\n fromStage?: string\n feedback?: string\n issueNumber?: number\n triggerType?: 'dispatch' | 'comment'\n runId?: string\n runUrl?: string\n // For comment triggers: raw body to parse\n commentBody?: string\n // Local mode: use pnpm ocode run instead of opencode github run\n local?: boolean\n // Path to task description file (for auto-generating task-id and task.md)\n file?: string\n // Opt-in to run clarify stage (default: skip, auto-create clarified.md)\n clarify?: boolean\n // Control mode override: auto, risk-gated, hard-stop\n controlMode?: 'auto' | 'risk-gated' | 'hard-stop'\n // Pipeline version: branch, tag, or commit to overlay (overrides KODY_DEFAULT_VERSION)\n version?: string\n // Complexity score override (1-100) for testing/debugging\n complexityOverride?: number\n // Whether the trigger was from a PR comment (vs issue comment)\n isPullRequest?: boolean\n // Force create new PR (new branch) - ignores existing PR\n fresh?: boolean\n // Turbo mode: forces minimal pipeline (build→commit→verify→pr), CLI-only flag\n turbo?: boolean\n /** GitHub login of the person who triggered this pipeline run (from GITHUB_ACTOR env var) */\n actor?: string\n /** GitHub login of the person who created the issue (from ISSUE_CREATOR env var) */\n issueCreator?: string\n}\n\nexport interface ActorEvent {\n action: string\n actor: string\n timestamp: string\n stage?: string\n}\n\nexport interface KodyPipelineStatus {\n taskId: string\n mode: string\n pipeline: string\n startedAt: string\n updatedAt: string\n completedAt?: string\n totalElapsed?: number\n state: 'running' | 'completed' | 'failed' | 'timeout' | 'paused'\n currentStage: string | null\n stages: Record<string, StageStatus>\n triggeredBy: string\n issueNumber?: number\n runId?: string\n runUrl?: string\n controlMode?: 'auto' | 'risk-gated' | 'hard-stop'\n gatePoint?: string\n botCommentId?: number\n /** Total accumulated cost across all stages in USD */\n totalCost?: number\n /** GitHub login of the person who triggered this pipeline run */\n triggeredByLogin?: string\n /** GitHub login of the person who created the issue (the \"owner\") */\n issueCreator?: string\n /** Audit trail of actor actions (capped at 50 entries) */\n actorHistory?: ActorEvent[]\n}\n\nexport interface StageStatus {\n state: 'pending' | 'running' | 'completed' | 'failed' | 'timeout' | 'skipped' | 'gate-waiting'\n startedAt?: string\n completedAt?: string\n elapsed?: number\n retries: number\n outputFile?: string\n skipped?: string // Reason for skip (e.g., 'input_quality')\n error?: string\n // Token usage for cost tracking\n tokenUsage?: {\n input: number\n output: number\n }\n /** Cost in USD */\n cost?: number\n}\n\n// ============================================================================\n// Validation\n// ============================================================================\n\nexport const VALID_MODES = ['spec', 'impl', 'rerun', 'fix', 'full', 'status'] as const\n\n// VALID_STAGES derived from registry to avoid duplication\n// Note: includes 'autofix' for backward compat with comment parsing validation\nexport const VALID_STAGES = [...STAGE_NAMES, 'autofix' as const]\n\n// Pipeline-ordered stage list for sorting (avoids `as any` cast on readonly tuple)\nconst STAGE_ORDER: readonly string[] = STAGE_NAMES\n\nexport function isValidMode(mode: string): mode is (typeof VALID_MODES)[number] {\n return VALID_MODES.includes(mode as (typeof VALID_MODES)[number])\n}\n\nexport function isValidStage(stage: string): stage is (typeof VALID_STAGES)[number] {\n return VALID_STAGES.includes(stage as (typeof VALID_STAGES)[number])\n}\n\nexport function validateTaskId(taskId: string): boolean {\n // Format: YYMMDD-description (e.g., 260217-user-metrics)\n return /^[0-9]{6}-[a-zA-Z0-9-]+$/.test(taskId)\n}\n\n// ============================================================================\n// Status Management\n// ============================================================================\n\nexport function getTaskDir(taskId: string): string {\n return path.join(process.cwd(), '.tasks', taskId)\n}\n\nexport function ensureTaskDir(taskId: string): string {\n const dir = getTaskDir(taskId)\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n return dir\n}\n\n/**\n * @deprecated Use engine/status.ts loadState/writeState/completeState instead.\n * This function is kept for backward compatibility with existing tests.\n */\nexport function readStatus(taskId: string): KodyPipelineStatus | null {\n const statusFile = path.join(getTaskDir(taskId), 'status.json')\n if (!fs.existsSync(statusFile)) {\n return null\n }\n try {\n return JSON.parse(fs.readFileSync(statusFile, 'utf-8'))\n } catch {\n return null\n }\n}\n\n/**\n * Get the last failed stage from status.json for smart rerun default.\n * Returns the stage name that most recently failed, or null if none.\n * Updated to use v2 schema (G(utils-1/2)).\n */\nexport function getLastFailedStage(taskId: string): string | null {\n const statusFile = path.join(getTaskDir(taskId), 'status.json')\n if (!fs.existsSync(statusFile)) {\n return null\n }\n\n try {\n const content = fs.readFileSync(statusFile, 'utf-8')\n const status = JSON.parse(content) as {\n version?: number\n stages?: Record<string, { state: string }>\n }\n\n // Check if it's v2 format (has version: 2)\n if (status.version === 2 && status.stages) {\n const failedStages = Object.entries(status.stages)\n .filter(([, s]) => s.state === 'failed' || s.state === 'timeout')\n .map(([name]) => name)\n // Sort by pipeline order (ALL_STAGES index) to get truly last failed stage\n failedStages.sort((a, b) => {\n const idxA = STAGE_ORDER.indexOf(a)\n const idxB = STAGE_ORDER.indexOf(b)\n return idxA - idxB\n })\n return failedStages.length > 0 ? failedStages[failedStages.length - 1] : null\n }\n\n // Fallback to v1 format\n if (status?.stages) {\n const failedStages = Object.entries(status.stages)\n .filter(([, s]) => s.state === 'failed' || s.state === 'timeout')\n .map(([name]) => name)\n // Sort by pipeline order (ALL_STAGES index) to get truly last failed stage\n failedStages.sort((a, b) => {\n const idxA = STAGE_ORDER.indexOf(a)\n const idxB = STAGE_ORDER.indexOf(b)\n return idxA - idxB\n })\n return failedStages.length > 0 ? failedStages[failedStages.length - 1] : null\n }\n\n return null\n } catch {\n return null\n }\n}\n\n/**\n * Get the last paused stage from status.json.\n * Used by rerun mode to detect gates that are waiting for approval.\n * Returns the stage name that has state 'paused', or null if none.\n */\nexport function getLastPausedStage(taskId: string): string | null {\n const statusFile = path.join(getTaskDir(taskId), 'status.json')\n if (!fs.existsSync(statusFile)) {\n return null\n }\n\n try {\n const content = fs.readFileSync(statusFile, 'utf-8')\n const status = JSON.parse(content) as {\n version?: number\n stages?: Record<string, { state: string }>\n }\n\n // Check for paused stages in v2 format\n if (status.version === 2 && status.stages) {\n const pausedStages = Object.entries(status.stages)\n .filter(([, s]) => s.state === 'paused')\n .map(([name]) => name)\n // Sort by pipeline order (ALL_STAGES index) to get truly last paused stage\n pausedStages.sort((a, b) => {\n const idxA = STAGE_ORDER.indexOf(a)\n const idxB = STAGE_ORDER.indexOf(b)\n return idxA - idxB\n })\n // Return the last paused stage (most recent in pipeline order)\n return pausedStages.length > 0 ? pausedStages[pausedStages.length - 1] : null\n }\n\n // Fallback to v1 format\n if (status?.stages) {\n const pausedStages = Object.entries(status.stages)\n .filter(([, s]) => s.state === 'paused')\n .map(([name]) => name)\n // Sort by pipeline order (ALL_STAGES index) to get truly last paused stage\n pausedStages.sort((a, b) => {\n const idxA = STAGE_ORDER.indexOf(a)\n const idxB = STAGE_ORDER.indexOf(b)\n return idxA - idxB\n })\n return pausedStages.length > 0 ? pausedStages[pausedStages.length - 1] : null\n }\n\n return null\n } catch {\n return null\n }\n}\n\n/**\n * @deprecated Use engine/status.ts loadState/writeState/completeState instead.\n */\nexport function writeStatus(taskId: string, status: KodyPipelineStatus): void {\n const statusFile = path.join(getTaskDir(taskId), 'status.json')\n // Atomic write: write to temp file then rename to prevent corruption\n // if the process is killed mid-write (e.g., timeout SIGKILL).\n const tmpFile = statusFile + '.tmp'\n fs.writeFileSync(tmpFile, JSON.stringify(status, null, 2))\n fs.renameSync(tmpFile, statusFile)\n}\n\n/**\n * @deprecated Use engine/status.ts loadState/writeState/completeState instead.\n */\nexport function initStatus(input: KodyInput): KodyPipelineStatus {\n const now = new Date().toISOString()\n const status: KodyPipelineStatus = {\n taskId: input.taskId,\n mode: input.mode,\n pipeline: 'spec_execute_verify', // will be updated after taskify\n startedAt: now,\n updatedAt: now,\n state: 'running',\n currentStage: null,\n stages: {},\n triggeredBy: input.triggerType || 'dispatch',\n issueNumber: input.issueNumber,\n runId: input.runId,\n runUrl: input.runUrl,\n }\n writeStatus(input.taskId, status)\n return status\n}\n\n/**\n * Update stage status with read-modify-write to status.json.\n *\n * Concurrency safety: parallel stages (e.g., verify + pr) call this from\n * separate promise callbacks, but Node.js is single-threaded — only one\n * callback runs at a time, so read-modify-write is atomic on the event loop.\n * The atomic writeStatus (write-to-tmp + rename) guards against corruption\n * from process kills (SIGTERM/SIGKILL during write).\n */\n\n/**\n * @deprecated Use engine/status.ts loadState/writeState/completeState instead.\n */\nexport function updateStageStatus(\n taskId: string,\n stage: string,\n state: StageStatus['state'],\n extras?: Partial<StageStatus>,\n): void {\n const status = readStatus(taskId)\n if (!status) {\n logger.warn(`No status file found for task: ${taskId}`)\n return\n }\n\n const now = new Date().toISOString()\n\n if (!status.stages[stage]) {\n status.stages[stage] = {\n state,\n retries: 0,\n ...extras,\n }\n }\n\n const stageStatus = status.stages[stage]\n\n // Apply extras (retries, outputFile, error) — works for both new and existing stages\n if (extras) {\n if (extras.retries !== undefined) stageStatus.retries = extras.retries\n if (extras.outputFile !== undefined) stageStatus.outputFile = extras.outputFile\n if (extras.error !== undefined) stageStatus.error = extras.error\n }\n\n if (state === 'running') {\n stageStatus.state = 'running'\n stageStatus.startedAt = now\n } else if (state === 'completed' || state === 'failed' || state === 'timeout') {\n stageStatus.state = state\n stageStatus.completedAt = now\n if (stageStatus.startedAt) {\n stageStatus.elapsed = new Date(now).getTime() - new Date(stageStatus.startedAt).getTime()\n }\n }\n\n status.currentStage = state === 'running' ? stage : status.currentStage\n status.updatedAt = now\n writeStatus(taskId, status)\n}\n\n/**\n * @deprecated Use engine/status.ts loadState/writeState/completeState instead.\n */\nexport function completeStatus(taskId: string, state: KodyPipelineStatus['state']): void {\n const status = readStatus(taskId)\n if (!status) return\n\n const now = new Date().toISOString()\n status.state = state\n status.updatedAt = now\n status.completedAt = now\n if (status.startedAt) {\n status.totalElapsed = new Date(now).getTime() - new Date(status.startedAt).getTime()\n }\n writeStatus(taskId, status)\n}\n\n// GitHub API re-exports removed — import directly from './github-api'\n\n// ============================================================================\n// Auth Validation\n// ============================================================================\n\n// Note: opencode github run handles OIDC auth internally via the id-token permission.\n// We don't need to validate a token ourselves - each invocation handles its own auth.\nexport function validateAuth(): void {\n // Check we're in GitHub Actions environment (where OIDC auth is available)\n if (!process.env.GITHUB_ACTIONS) {\n logger.warn('⚠ Not running in GitHub Actions — OIDC auth may not work')\n logger.warn(' Run locally or in CI with id-token: write permission')\n } else {\n logger.info('✓ Running in GitHub Actions — OIDC auth available via id-token permission')\n }\n}\n\n// ============================================================================\n// Re-exports for backward compatibility\n// Import directly from './cli-parser' or './status-format' for new code\n// ============================================================================\n\nexport { parseCliArgs, parseCommentBody } from './cli-parser'\nexport { formatDuration, formatStatusComment, formatStatusCommentV2 } from './status-format'\n","// preflight.ts - Pre-flight validation for Kody\nimport { logger } from \"./logger\";\nimport { execFileSync } from \"child_process\";\nimport * as fs from \"fs\";\n\ninterface Check {\n name: string;\n test: () => void;\n errorMessage?: string;\n}\n\nexport function preflight(): void {\n const checks: Check[] = [\n {\n name: \"ocode CLI (via pnpm)\",\n test: () =>\n execFileSync(\"pnpm\", [\"opencode\", \"--version\"], { stdio: \"pipe\" }),\n errorMessage: \"Run: pnpm install\",\n },\n {\n name: \"Git repository\",\n test: () =>\n execFileSync(\"git\", [\"rev-parse\", \"--git-dir\"], { stdio: \"pipe\" }),\n errorMessage: \"Initialize git: git init\",\n },\n {\n name: \"pnpm\",\n test: () => execFileSync(\"which\", [\"pnpm\"], { stdio: \"pipe\" }),\n errorMessage: \"Install: npm install -g pnpm\",\n },\n {\n name: \"Node.js v18+\",\n test: () => {\n const version = execFileSync(\"node\", [\"--version\"], {\n encoding: \"utf-8\",\n }).trim();\n const major = parseInt(version.slice(1).split(\".\")[0]);\n if (major < 18) {\n throw new Error(`Node ${version} is too old, need v18+`);\n }\n },\n errorMessage: \"Upgrade Node.js to v18 or higher\",\n },\n {\n name: \"package.json\",\n test: () => {\n if (!fs.existsSync(\"./package.json\")) {\n throw new Error(\"package.json not found\");\n }\n },\n errorMessage: \"Run from project root with package.json\",\n },\n {\n name: \"GitHub token (GH_PAT or GH_TOKEN)\",\n test: () => {\n const token =\n process.env.GH_PAT?.trim() || process.env.GH_TOKEN?.trim();\n if (!token) {\n throw new Error(\"No GitHub token found\");\n }\n },\n errorMessage:\n \"Set GH_PAT or GH_TOKEN in .env (needed for PR creation and GitHub API)\",\n },\n ];\n\n logger.info(\"🔍 Pre-flight checks...\");\n let failed = false;\n const errors: string[] = [];\n\n for (const check of checks) {\n try {\n check.test();\n logger.info(` ✅ ${check.name}`);\n } catch {\n logger.info(` ❌ ${check.name}`);\n if (check.errorMessage) {\n errors.push(` ${check.errorMessage}`);\n }\n failed = true;\n }\n }\n\n if (failed) {\n const errorDetails = errors.join(\"\\n\");\n throw new Error(\n `Pre-flight checks failed:\\n${errorDetails}\\n\\nFix issues above before running pipeline.`,\n );\n }\n\n logger.info(\"✅ Pre-flight complete\\n\");\n}\n","/**\n * @fileType utility\n * @domain kody | infrastructure\n * @pattern opencode-server\n * @ai-summary Manages OpenCode server lifecycle for persistent sessions across pipeline stages\n */\n\nimport { spawn, execFileSync, type ChildProcess } from 'child_process'\nimport * as fs from 'fs'\nimport * as os from 'os'\nimport * as path from 'path'\nimport { logger } from './logger'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface OpenCodeServer {\n process: ChildProcess\n url: string\n port: number\n dataDir: string\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_PORT = 4097\nconst HEALTH_CHECK_TIMEOUT_MS = 30_000\nconst HEALTH_CHECK_INTERVAL_MS = 500\nconst SHUTDOWN_GRACE_MS = 5_000\n\n// ============================================================================\n// Binary Resolution\n// ============================================================================\n\n/**\n * Resolve the path to the real opencode binary (v1.2.x installed via curl).\n *\n * When running inside `pnpm tsx`, `node_modules/.bin/opencode` shadows the\n * real binary because pnpm prepends `./node_modules/.bin` to PATH. The npm\n * package (opencode-ai@0.0.0-dev) doesn't support --agent + --attach properly.\n *\n * Resolution order:\n * 1. ~/.opencode/bin/opencode (standard curl install location)\n * 2. 'opencode' (fall back to PATH — works in CI where npm shadow doesn't exist)\n */\nexport function resolveOpenCodeBinary(): string {\n const installDir = path.join(os.homedir(), '.opencode', 'bin', 'opencode')\n if (fs.existsSync(installDir)) {\n return installDir\n }\n return 'opencode'\n}\n/**\n * Verify that `opencode run --attach` can find the server instance.\n * Returns true if the client can connect, false otherwise.\n * This catches the \"No context found for instance\" error early.\n */\nexport function verifyClientAttach(url: string, dataDir: string): boolean {\n try {\n const binary = resolveOpenCodeBinary()\n // Use a minimal prompt that will immediately error with a model issue\n // (which is fine — we just need to confirm it doesn't fail with\n // \"No context found for instance\")\n const result = execFileSync(binary, ['run', '--attach', url, '--format', 'json', 'ping'], {\n env: { ...process.env, XDG_DATA_HOME: dataDir },\n timeout: 15_000,\n stdio: ['ignore', 'pipe', 'pipe'],\n cwd: process.cwd(),\n })\n // If we get here, the command ran (it will likely error with model config issues, but that's fine)\n const output = result.toString()\n return !output.includes('No context found for instance')\n } catch (err: unknown) {\n // The command will exit non-zero (model errors etc), check stderr for the specific instance error\n const stderr = (err as { stderr?: Buffer })?.stderr?.toString() || ''\n const stdout = (err as { stdout?: Buffer })?.stdout?.toString() || ''\n const combined = stderr + stdout\n\n // Fail on known indicators that the server instance is not accessible\n if (\n combined.includes('No context found for instance') ||\n combined.includes('Unexpected error, check log file')\n ) {\n return false\n }\n\n // Also fail if the command timed out (15s) — the attach should respond quickly\n const errObj = err as { killed?: boolean; signal?: string; code?: string }\n if (errObj.killed || errObj.signal === 'SIGTERM' || errObj.code === 'ETIMEDOUT') {\n return false\n }\n\n // Any other error means the attach itself worked (model/agent errors are expected)\n return true\n }\n}\n\n// ============================================================================\n// Server Lifecycle\n// ============================================================================\n\n/**\n * Start an OpenCode server with an isolated data directory for this task.\n * The data dir is set via XDG_DATA_HOME so the SQLite DB and snapshots\n * are scoped per-task and don't interfere with other runs.\n *\n * @param taskDir - The .tasks/<taskId> directory\n * @param port - Port to listen on (default: 4097)\n * @returns The running server, or null if startup failed\n */\nexport async function startServer(\n taskDir: string,\n port: number = DEFAULT_PORT,\n): Promise<OpenCodeServer | null> {\n const dataDir = path.join(taskDir, 'opencode-data')\n const opencodeSub = path.join(dataDir, 'opencode')\n\n // Ensure the data directory structure exists\n fs.mkdirSync(opencodeSub, { recursive: true })\n\n // Copy auth.json from the global data dir if it exists and we don't have one\n // (needed for provider authentication in isolated data dirs)\n const localAuth = path.join(opencodeSub, 'auth.json')\n if (!fs.existsSync(localAuth)) {\n const globalDataDir = process.env.XDG_DATA_HOME\n ? path.join(process.env.XDG_DATA_HOME, 'opencode')\n : path.join(os.homedir(), '.local', 'share', 'opencode')\n const globalAuth = path.join(globalDataDir, 'auth.json')\n if (fs.existsSync(globalAuth)) {\n try {\n fs.copyFileSync(globalAuth, localAuth)\n // Restrict permissions: auth.json contains API credentials\n fs.chmodSync(localAuth, 0o600)\n logger.info(' Copied auth.json to task data dir')\n } catch {\n // Non-fatal: CI uses env vars for auth\n }\n }\n }\n\n const url = `http://127.0.0.1:${port}`\n logger.info(` 🚀 Starting OpenCode server on port ${port}...`)\n\n try {\n const binary = resolveOpenCodeBinary()\n\n // Log version for diagnostics (helps debug CI issues)\n try {\n const ver = execFileSync(binary, ['--version'], { encoding: 'utf-8', timeout: 5000 }).trim()\n logger.info(` OpenCode binary: ${binary} (v${ver})`)\n } catch {\n logger.info(` OpenCode binary: ${binary} (version unknown)`)\n }\n const child = spawn(\n binary,\n ['serve', '--port', String(port), '--print-logs', '--log-level', 'WARN'],\n {\n env: {\n ...process.env,\n XDG_DATA_HOME: dataDir,\n },\n cwd: process.cwd(),\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: false,\n },\n )\n\n // Drain stdout/stderr to prevent buffer overflow\n child.stdout?.resume()\n child.stderr?.resume()\n\n // Race the health check against a spawn-error rejection so we fail fast\n // if the binary is not found or the process exits immediately (e.g. port in use).\n const spawnErrorPromise = new Promise<never>((_, reject) => {\n child.on('error', (err) => reject(err))\n child.on('exit', (code) => {\n if (code !== 0 && code !== null) {\n reject(new Error(`opencode serve exited with code ${code}`))\n }\n })\n })\n\n const healthy = await Promise.race([\n waitForHealthy(url, HEALTH_CHECK_TIMEOUT_MS),\n spawnErrorPromise.then(\n () => false as boolean,\n () => false as boolean,\n ),\n ])\n\n if (!healthy) {\n logger.warn('OpenCode server failed to start (health check failed or process exited)')\n if (!child.killed) child.kill('SIGTERM')\n return null\n }\n\n logger.info(` ✅ OpenCode server ready at ${url}`)\n\n // Health check passed — server is ready. We no longer run verifyClientAttach()\n // because opencode run --attach 'ping' often times out even when the server is\n // fully functional (the short 'ping' prompt triggers slow model initialization).\n // The health endpoint is sufficient proof the server is operational.\n\n return { process: child, url, port, dataDir }\n } catch (err) {\n logger.warn({ err }, 'Failed to start OpenCode server')\n return null\n }\n}\n\n/**\n * Poll the health endpoint until the server reports healthy.\n */\nexport async function waitForHealthy(\n url: string,\n timeoutMs: number = HEALTH_CHECK_TIMEOUT_MS,\n): Promise<boolean> {\n const start = Date.now()\n const healthUrl = `${url}/global/health`\n\n while (Date.now() - start < timeoutMs) {\n try {\n const response = await fetch(healthUrl, { signal: AbortSignal.timeout(2000) })\n if (response.ok) {\n const body = (await response.json()) as { healthy?: boolean }\n if (body.healthy) return true\n }\n } catch {\n // Server not ready yet\n }\n await new Promise((r) => setTimeout(r, HEALTH_CHECK_INTERVAL_MS))\n }\n return false\n}\n\n/**\n * Stop the OpenCode server gracefully.\n */\nexport async function stopServer(server: OpenCodeServer): Promise<void> {\n if (!server.process || server.process.killed) return\n\n logger.info(' 🛑 Stopping OpenCode server...')\n\n return new Promise<void>((resolve) => {\n const forceKillTimer = setTimeout(() => {\n if (!server.process.killed) {\n server.process.kill('SIGKILL')\n }\n resolve()\n }, SHUTDOWN_GRACE_MS)\n\n server.process.on('exit', () => {\n clearTimeout(forceKillTimer)\n resolve()\n })\n\n server.process.kill('SIGTERM')\n })\n}\n\n/**\n * Checkpoint the SQLite WAL into the main DB file.\n * This ensures the .db file is self-contained for git commits.\n * Must be called AFTER stopping the server.\n */\nexport function checkpointDb(taskDir: string): void {\n const dbPath = path.join(taskDir, 'opencode-data', 'opencode', 'opencode.db')\n if (!fs.existsSync(dbPath)) {\n logger.debug('No OpenCode DB to checkpoint')\n return\n }\n\n try {\n execFileSync('sqlite3', [dbPath, 'PRAGMA wal_checkpoint(TRUNCATE);'], {\n stdio: 'pipe',\n timeout: 10_000,\n })\n logger.info(' ✅ OpenCode DB checkpoint complete')\n } catch (err) {\n // Non-fatal: WAL files will just be larger but DB still works\n logger.warn({ err }, 'Failed to checkpoint OpenCode DB (non-fatal)')\n }\n}\n\n/**\n * Find the sessionId of the last completed agent stage.\n * Used on rerun to resume from the last known session.\n */\nexport function findLastSessionId(\n stages: Record<string, { state: string; sessionId?: string }>,\n pipelineOrder: string[],\n): string | undefined {\n // Walk pipeline order in reverse to find the last completed stage with a sessionId\n for (let i = pipelineOrder.length - 1; i >= 0; i--) {\n const stageName = pipelineOrder[i]\n const stage = stages[stageName]\n if (\n stage?.sessionId &&\n (stage.state === 'completed' || stage.state === 'failed' || stage.state === 'timeout')\n ) {\n return stage.sessionId\n }\n }\n return undefined\n}\n","/**\n * @fileType utility\n * @domain ci | kody | agent-execution\n * @pattern runner-backend\n * @ai-summary Pluggable runner backend for Kody: supports both local (ocode) and CI (opencode github run) modes\n */\n\nimport { spawn, type ChildProcess } from 'child_process'\n\nimport { getEnv } from './env'\nimport { resolveOpenCodeBinary } from './opencode-server'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Options passed to runner.spawn() for server mode */\nexport interface RunnerSpawnOptions {\n /** URL of running OpenCode server to attach to */\n serverUrl?: string\n /** Session ID to fork from (requires serverUrl) */\n sessionId?: string\n /** XDG_DATA_HOME directory — must match the server's data dir for instance lookup */\n dataDir?: string\n}\n\nexport interface RunnerBackend {\n name: string\n spawn(\n stage: string,\n prompt: string,\n env: NodeJS.ProcessEnv,\n cwd: string,\n options?: RunnerSpawnOptions,\n ): ChildProcess\n}\n\n// ============================================================================\n// GitHub Runner (CI mode)\n// ============================================================================\n\nexport class GitHubRunner implements RunnerBackend {\n name = 'opencode-github'\n\n spawn(\n stage: string,\n prompt: string,\n env: NodeJS.ProcessEnv,\n cwd: string,\n options?: RunnerSpawnOptions,\n ): ChildProcess {\n // When attaching to a running server, use the real opencode binary directly.\n // `pnpm exec opencode` resolves to the old opencode-ai npm package which\n // doesn't support --agent + --attach properly. The real binary is installed\n // via `curl -fsSL https://opencode.ai/install | bash` to ~/.opencode/bin/.\n // XDG_DATA_HOME must match the server's data dir for instance lookup.\n if (options?.serverUrl) {\n const args = [\n 'run',\n '--agent',\n stage,\n '--format',\n 'json',\n '--attach',\n options.serverUrl,\n '--dir',\n cwd,\n ]\n if (options.sessionId) args.push('--session', options.sessionId, '--fork')\n args.push(prompt)\n return spawn(resolveOpenCodeBinary(), args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: {\n ...env,\n ...(options.dataDir ? { XDG_DATA_HOME: options.dataDir } : {}),\n },\n })\n }\n\n // Without server: use pnpm exec for backward compatibility\n const args = ['exec', 'opencode', 'run', '--agent', stage, '--format', 'json']\n args.push(prompt)\n return spawn('pnpm', args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n env,\n })\n }\n}\n\n// ============================================================================\n// Local Runner (uses pnpm ocode run)\n// ============================================================================\n\nexport class LocalRunner implements RunnerBackend {\n name = 'opencode-local'\n\n spawn(\n stage: string,\n prompt: string,\n env: NodeJS.ProcessEnv,\n cwd: string,\n options?: RunnerSpawnOptions,\n ): ChildProcess {\n // When attaching to a running server, use the real opencode binary directly.\n // `pnpm ocode` resolves to `pnpm exec opencode` which uses the old opencode-ai\n // npm package. The real binary supports --agent + --attach properly.\n // XDG_DATA_HOME must match the server's data dir for instance lookup.\n if (options?.serverUrl) {\n const args = [\n 'run',\n '--agent',\n stage,\n '--format',\n 'json',\n '--attach',\n options.serverUrl,\n '--dir',\n cwd,\n ]\n if (options.sessionId) args.push('--session', options.sessionId, '--fork')\n args.push(prompt)\n return spawn(resolveOpenCodeBinary(), args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: {\n ...env,\n ...(options.dataDir ? { XDG_DATA_HOME: options.dataDir } : {}),\n AGENT: stage,\n MODEL: env.MODEL,\n },\n })\n }\n\n // Without server: use pnpm ocode for backward compatibility\n const args = ['ocode', 'run', '--agent', stage, '--format', 'json']\n args.push(prompt)\n return spawn('pnpm', args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: {\n ...env,\n AGENT: stage,\n MODEL: env.MODEL,\n },\n })\n }\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\n/**\n * Create a runner backend based on the environment.\n *\n * @param local - If true, uses local runner. If false, uses GitHub runner.\n * If undefined, auto-detects: local when GITHUB_ACTIONS is not set.\n */\nexport function createRunner(local?: boolean): RunnerBackend {\n const env = getEnv()\n const useLocal = local ?? !env.GITHUB_ACTIONS\n\n if (useLocal) {\n return new LocalRunner()\n }\n return new GitHubRunner()\n}\n","/**\n * @fileType configuration\n * @domain kody | pipeline\n * @pattern named-constants\n * @ai-summary Centralized named constants for the Kody pipeline — replaces scattered magic numbers\n */\n\n// --- Loop & Retry Limits ---\n\n/** Max iterations of the main state-machine loop before circuit-breaking */\nexport const MAX_PIPELINE_LOOP_ITERATIONS = 200\n\n/** Default max verify→fix loop iterations */\nexport const DEFAULT_MAX_FIX_ATTEMPTS = 1\n\n/** Max build→quality-gate feedback loops */\nexport const MAX_BUILD_FEEDBACK_LOOPS = 2\n\n/** State recovery check frequency (every N loop iterations) */\nexport const RECOVERY_CHECK_INTERVAL = 10\n\n// --- Output Truncation ---\n\n/** Max chars for gate output in verify-failures.md */\nexport const MAX_GATE_OUTPUT_CHARS = 5000\n\n/** Max chars for passed gate output in verify report */\nexport const MAX_PASSED_GATE_OUTPUT_CHARS = 1000\n\n/** Max chars for failed gate output in verify report */\nexport const MAX_FAILED_GATE_OUTPUT_CHARS = 5000\n\n/** Max chars for gate output written to file */\nexport const MAX_GATE_FILE_OUTPUT_CHARS = 10_000\n\n/** Max chars for tsc/test error output in build feedback */\nexport const MAX_QUALITY_ERROR_OUTPUT_CHARS = 3000\n\n/** Max chars for agent text display in logs */\nexport const MAX_AGENT_DISPLAY_TEXT_CHARS = 300\n\n// --- Process Lifecycle ---\n\n/** Grace period (ms) before SIGKILL after SIGTERM */\nexport const SIGKILL_GRACE_MS = 5000\n\n/** Delay (ms) between agent retries */\nexport const AGENT_RETRY_DELAY_MS = 2000\n\n/** Number of stderr tail lines to capture */\nexport const STDERR_TAIL_LINES = 50\n\n// --- Git & PR ---\n\n/** Max PR title length */\nexport const MAX_PR_TITLE_LENGTH = 72\n\n/** Max spec summary length in PR body */\nexport const MAX_SPEC_SUMMARY_LENGTH = 500\n\n// --- Actor History ---\n\n/** Max entries in the actorHistory audit trail */\nexport const MAX_ACTOR_HISTORY_ENTRIES = 50\n","/**\n * @fileType types\n * @domain kody | engine\n * @pattern state-machine\n * @ai-summary Core types for the Kody pipeline state machine architecture\n */\n\nimport { z } from 'zod'\nimport type { StageName } from '../stages/registry'\n\n// ============================================================================\n// Stage Types\n// ============================================================================\n\nexport type StageType = 'agent' | 'scripted' | 'git' | 'gate'\n\nexport type StageOutcome = 'completed' | 'failed' | 'paused' | 'timed_out' | 'skipped'\n\nexport interface StageResult {\n outcome: StageOutcome\n reason?: string\n retries: number\n outputFile?: string\n /** Token usage for this stage */\n tokenUsage?: { input: number; output: number; cacheRead: number }\n /** Cost in USD for this stage */\n cost?: number\n /** OpenCode session ID for this stage */\n sessionId?: string\n}\n\n// ============================================================================\n// Stage Definition\n// ============================================================================\n\nexport interface SkipResult {\n shouldSkip: boolean\n reason?: string\n}\n\n// Re-export ValidationResult from agent-runner\nimport type { ValidationResult } from '../agent-runner'\nexport type { ValidationResult }\n\n/**\n * Optional preExecute hook that runs before the handler.\n * Used by build stage for ensureFeatureBranch.\n */\nexport type StagePreExecute = (ctx: PipelineContext) => Promise<void>\n\nexport interface StageDefinition {\n name: StageName\n type: StageType\n timeout: number\n maxRetries: number\n shouldSkip?: (ctx: PipelineContext) => SkipResult\n validator?: (outputFile: string) => ValidationResult\n postActions?: PostAction[]\n advisory?: boolean\n preExecute?: StagePreExecute\n /**\n * Minimum complexity score (1-100) for this stage to run.\n * Informational only — actual routing uses STAGE_COMPLEXITY_THRESHOLDS\n * in skip-conditions.ts. Keep in sync with STAGE_COMPLEXITY_THRESHOLDS.\n */\n minComplexity?: number\n /**\n * Called when agent exits 0 but doesn't produce the expected output file.\n * Returns the fallback content to write, or null to proceed with normal retry/fail.\n */\n fallbackOnMissingOutput?: (ctx: PipelineContext) => string | null\n /**\n * Override the agent name used by opencode. Defaults to stage name.\n * Used when a stage should run a different agent (e.g., fix stage runs build agent).\n */\n agentName?: string\n /**\n * Declarative retry loop: when this stage fails, reset both this stage\n * and `retryWith.stage` to pending, up to `retryWith.maxAttempts` times.\n */\n retryWith?: {\n stage: StageName\n maxAttempts: number\n /** Called before retry to capture failure details (e.g., write verify-failures.md) */\n onFailure?: (ctx: PipelineContext, taskDir: string) => Promise<void>\n /** When the retryWith.stage times out: 'retry' resets this stage to pending; 'fail' fails the pipeline */\n onTimeout?: 'retry' | 'fail'\n }\n}\n\n// ============================================================================\n// Pipeline Definition\n// ============================================================================\n\nexport type PipelineStep = StageName | { parallel: StageName[] }\n\nexport interface PipelineDefinition {\n stages: Map<StageName, StageDefinition>\n order: PipelineStep[]\n}\n\n// ============================================================================\n// Pipeline Context\n// ============================================================================\n\nimport type { KodyInput } from '../kody-utils'\nimport type { TaskDefinition } from '../pipeline-utils'\nimport type { RunnerBackend } from '../runner-backend'\n\nexport interface PipelineContext {\n taskId: string\n taskDir: string\n input: KodyInput\n taskDef: TaskDefinition | null\n profile: 'standard' | 'lightweight' | 'turbo'\n backend: RunnerBackend\n // Set by resolve-profile post-action to signal engine to rebuild pipeline\n pipelineNeedsRebuild?: boolean\n /** URL of the running OpenCode server (e.g., 'http://localhost:4097') */\n serverUrl?: string\n /** Most recent agent stage's sessionID — downstream stages fork from this */\n lastSessionId?: string\n /** GitHub login of the person who triggered this run (from GITHUB_ACTOR env var) */\n actor?: string\n}\n\n// Note: NO controlMode field — each gate resolves it dynamically via\n// resolveControlMode(ctx.taskDef, ctx.input.controlMode) (G42)\n\n// ============================================================================\n// Pipeline State V2 (status.json schema)\n// ============================================================================\n\nexport interface StageStateV2 {\n state:\n | 'pending'\n | 'running'\n | 'completed'\n | 'failed'\n | 'timeout'\n | 'skipped'\n | 'paused'\n | 'observing'\n startedAt?: string\n completedAt?: string\n elapsed?: number\n retries: number\n outputFile?: string\n skipped?: string\n error?: string\n feedbackLoops?: number\n feedbackErrors?: string[]\n /** Current fix attempt number (for verify→fix loop) */\n fixAttempt?: number\n /** Maximum allowed fix attempts (for verify→fix loop) */\n maxFixAttempts?: number\n /** Whether the review stage found issues that need fixing */\n issuesFound?: boolean\n /** Review summary counts */\n reviewSummary?: {\n critical: number\n major: number\n minor: number\n }\n /** Token usage for cost tracking */\n tokenUsage?: { input: number; output: number; cacheRead: number }\n /** Cost in USD */\n cost?: number\n /** OpenCode session ID for rerun recovery */\n sessionId?: string\n}\n\n/** A single actor event in the pipeline audit trail */\nexport interface ActorEvent {\n /** Action type: pipeline-triggered, gate-approved, gate-rejected, stage-retried, etc. */\n action: string\n /** GitHub login of the person who performed the action */\n actor: string\n /** ISO timestamp */\n timestamp: string\n /** Stage name, if action is stage-specific */\n stage?: string\n}\n\nexport interface PipelineStateV2 {\n version: 2\n taskId: string\n mode: string\n pipeline: string\n startedAt: string\n updatedAt: string\n completedAt?: string\n totalElapsed?: number\n state: 'running' | 'completed' | 'failed' | 'timeout' | 'paused'\n cursor: StageName | null\n stages: Record<string, StageStateV2>\n /** GitHub issue number that triggered this pipeline run */\n issueNumber?: number\n /** Git branch name created for this task (set after ensureFeatureBranch) */\n branchName?: string\n /** Total accumulated cost across all stages in USD */\n totalCost?: number\n /** GitHub login of the person who triggered this pipeline run */\n triggeredBy?: string\n /** GitHub login of the person who created the issue (the \"owner\") */\n issueCreator?: string\n /** Audit trail of actor actions. Capped at 50 entries (oldest dropped first). */\n actorHistory?: ActorEvent[]\n}\n\n// Zod schema for PipelineStateV2\n// Note: Uses z.string() for cursor (not StageName) for backward compat with existing status.json files\nexport const PipelineStateV2Schema = z.object({\n version: z.literal(2),\n taskId: z.string(),\n mode: z.string(),\n pipeline: z.string(),\n startedAt: z.string(),\n updatedAt: z.string(),\n completedAt: z.string().optional(),\n totalElapsed: z.number().optional(),\n state: z.enum(['running', 'completed', 'failed', 'timeout', 'paused']),\n cursor: z.string().nullable(),\n issueNumber: z.number().optional(),\n branchName: z.string().optional(),\n totalCost: z.number().optional(),\n stages: z.record(\n z.string(),\n z.object({\n state: z.enum([\n 'pending',\n 'running',\n 'completed',\n 'failed',\n 'timeout',\n 'skipped',\n 'paused',\n 'observing',\n ]),\n startedAt: z.string().optional(),\n completedAt: z.string().optional(),\n elapsed: z.number().optional(),\n retries: z.number(),\n outputFile: z.string().optional(),\n skipped: z.string().optional(),\n error: z.string().optional(),\n feedbackLoops: z.number().optional(),\n feedbackErrors: z.array(z.string()).optional(),\n fixAttempt: z.number().optional(),\n maxFixAttempts: z.number().optional(),\n issuesFound: z.boolean().optional(),\n reviewSummary: z\n .object({\n critical: z.number(),\n major: z.number(),\n minor: z.number(),\n })\n .optional(),\n tokenUsage: z\n .object({\n input: z.number(),\n output: z.number(),\n cacheRead: z.number(),\n })\n .optional(),\n cost: z.number().optional(),\n sessionId: z.string().optional(),\n }),\n ),\n triggeredBy: z.string().optional(),\n issueCreator: z.string().optional(),\n actorHistory: z\n .array(\n z.object({\n action: z.string(),\n actor: z.string(),\n timestamp: z.string(),\n stage: z.string().optional(),\n }),\n )\n .optional(),\n})\n\n/**\n * Type guard to validate v2 status.json format\n */\nexport function isPipelineStateV2(obj: unknown): obj is PipelineStateV2 {\n if (!obj || typeof obj !== 'object') return false\n const result = PipelineStateV2Schema.safeParse(obj)\n return result.success\n}\n\n// ============================================================================\n// Post-Action Types\n// ============================================================================\n\n/**\n * Enum-like union of all post-action type strings.\n * Used for classification (blocking vs advisory) and switch statements.\n */\nexport type PostActionType =\n | 'validate-task-json'\n | 'set-classification-labels'\n | 'resolve-profile'\n | 'check-gate'\n | 'commit-task-files'\n | 'archive-rerun-feedback'\n | 'validate-plan-exists'\n | 'validate-build-content'\n | 'validate-src-changes'\n | 'run-tsc'\n | 'run-unit-tests'\n | 'run-quality-with-autofix'\n | 'analyze-review-findings'\n | 'clear-verify-failures'\n | 'run-mechanical-autofix'\n | 'parallel'\n\n/**\n * Post-actions that block pipeline progression on failure.\n * These failures cause the pipeline to stop and require user intervention.\n */\nexport const BLOCKING_POST_ACTIONS: PostActionType[] = [\n 'validate-task-json',\n 'resolve-profile',\n 'check-gate',\n 'commit-task-files',\n 'validate-plan-exists',\n 'validate-build-content',\n 'validate-src-changes',\n]\n\n/**\n * Returns true if the given post-action is blocking (fails the pipeline).\n * Advisory actions log warnings but don't stop the pipeline.\n */\nexport function isBlockingPostAction(action: PostAction): boolean {\n return BLOCKING_POST_ACTIONS.includes(action.type as PostActionType)\n}\n\n// Validate-task-json action\nexport type ValidateTaskJsonAction = {\n type: 'validate-task-json'\n}\n\n// Set-classification-labels action\nexport type SetClassificationLabelsAction = {\n type: 'set-classification-labels'\n}\n\n// Resolve-profile action\nexport type ResolveProfileAction = {\n type: 'resolve-profile'\n}\n\n// Check-gate action\nexport type CheckGateAction = {\n type: 'check-gate'\n gate: string\n includeArtifact?: string // e.g., 'plan.md' for architect gate\n}\n\n// Commit-task-files action\nexport type CommitTaskFilesAction = {\n type: 'commit-task-files'\n stagingStrategy: 'task-only' | 'tracked-only' | 'tracked+task'\n push: boolean\n ensureBranch: boolean\n cleanDirtyState?: boolean\n commitMessage?: string\n localOnly?: boolean // G18: only commit in local mode\n}\n\n// Archive-rerun-feedback action\nexport type ArchiveRerunFeedbackAction = {\n type: 'archive-rerun-feedback'\n}\n\n// Validate-plan-exists action\nexport type ValidatePlanExistsAction = {\n type: 'validate-plan-exists'\n}\n\n// Validate-build-content action\nexport type ValidateBuildContentAction = {\n type: 'validate-build-content'\n}\n\n// Run-tsc action\nexport type RunTscAction = {\n type: 'run-tsc'\n}\n\n// Run-unit-tests action\nexport type RunUnitTestsAction = {\n type: 'run-unit-tests'\n}\n\n// Run-quality-with-autofix action — feedback loop that retries with autofix agent\nexport type RunQualityWithAutofixAction = {\n type: 'run-quality-with-autofix'\n gates: Array<{ name: string; command: string; source: 'tsc' | 'lint' | 'format' | 'test' }>\n maxFeedbackLoops: number\n}\n\n// Validate-src-changes action — ensures build agent modified source files\nexport type ValidateSrcChangesAction = {\n type: 'validate-src-changes'\n}\n\n// Analyze-review-findings action - parses review.md to determine if fix needed\nexport type AnalyzeReviewFindingsAction = {\n type: 'analyze-review-findings'\n}\n\n// Clear-verify-failures action - clears previous verify failures for retry\nexport type ClearVerifyFailuresAction = {\n type: 'clear-verify-failures'\n}\n\n// Run-mechanical-autofix action — runs lint:fix + format:fix deterministically (no LLM)\nexport type RunMechanicalAutofixAction = {\n type: 'run-mechanical-autofix'\n}\n\n// Update-knowledge-base action — updates cross-task knowledge base after completion\nexport type UpdateKnowledgeBaseAction = {\n type: 'update-knowledge-base'\n}\n\n// Parallel-post-action - runs multiple actions concurrently\nexport type ParallelPostAction = {\n type: 'parallel'\n actions: PostAction[]\n}\n\n// Post-action discriminated union\nexport type PostAction =\n | ValidateTaskJsonAction\n | SetClassificationLabelsAction\n | ResolveProfileAction\n | CheckGateAction\n | CommitTaskFilesAction\n | ArchiveRerunFeedbackAction\n | ValidatePlanExistsAction\n | ValidateBuildContentAction\n | ValidateSrcChangesAction\n | RunTscAction\n | RunUnitTestsAction\n | RunQualityWithAutofixAction\n | AnalyzeReviewFindingsAction\n | ClearVerifyFailuresAction\n | RunMechanicalAutofixAction\n | UpdateKnowledgeBaseAction\n | ParallelPostAction\n\n// ============================================================================\n// Lifecycle Hooks\n// ============================================================================\n\nexport interface LifecycleHooks {\n onStateChange?: (\n prevState: PipelineStateV2 | null,\n nextState: PipelineStateV2,\n ctx: PipelineContext,\n ) => void\n}\n\n// ============================================================================\n// Pipeline Paused Error\n// ============================================================================\n\n/**\n * Thrown when the pipeline intentionally pauses (e.g., hard-stop / risk gate).\n * Caught in main() to post a ⏸️ comment instead of ✅ completed.\n */\nexport class PipelinePausedError extends Error {\n constructor(reason: string) {\n super(reason)\n this.name = 'PipelinePausedError'\n }\n}\n\n// ============================================================================\n// Re-exports from other modules for convenience\n// ============================================================================\n\n// Re-export KodyInput for use throughout the engine\nexport type { KodyInput } from '../kody-utils'\n\n// Re-export ControlMode and TaskDefinition from pipeline-utils\nexport type { ControlMode, TaskDefinition } from '../pipeline-utils'\n","/**\n * @fileType utility\n * @domain kody | engine\n * @pattern status-tracking\n * @ai-summary Status.json v2 operations with mandatory Zod validation\n */\n\nimport { logger } from '../logger'\nimport { MAX_ACTOR_HISTORY_ENTRIES } from '../config/constants'\nimport type { StageName } from '../stages/registry'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport {\n PipelineStateV2,\n isPipelineStateV2,\n type PipelineContext,\n type StageStateV2,\n type ActorEvent,\n} from './types'\n\n// C3 FIX: Import stageOutputFile for correct path resolution in resetFromStage\nimport { stageOutputFile } from '../stages/registry'\n\n// ============================================================================\n// Status File Operations\n// ============================================================================\n\n/**\n * Get the status file path for a task\n */\nfunction getStatusFilePath(taskId: string): string {\n const taskDir = path.join(process.cwd(), '.tasks', taskId)\n return path.join(taskDir, 'status.json')\n}\n\n/**\n * Load state from status.json with mandatory Zod validation.\n * Returns null on missing file, invalid JSON, or failed validation.\n */\nexport function loadState(taskId: string): PipelineStateV2 | null {\n const statusFile = getStatusFilePath(taskId)\n\n if (!fs.existsSync(statusFile)) {\n return null\n }\n\n try {\n const content = fs.readFileSync(statusFile, 'utf-8')\n const parsed = JSON.parse(content)\n\n // Validate with Zod schema\n if (!isPipelineStateV2(parsed)) {\n logger.warn(`Status file for ${taskId} is not valid v2 format, ignoring`)\n return null\n }\n\n return parsed\n } catch (error) {\n logger.warn({ err: error }, `Failed to load status for ${taskId}`)\n return null\n }\n}\n\n/**\n * Atomic write with fsync: write to temp file, flush to disk, then rename\n * to prevent corruption if the process is killed mid-write.\n */\nexport function writeState(taskId: string, state: PipelineStateV2): void {\n const statusFile = getStatusFilePath(taskId)\n const tmpFile = statusFile + '.tmp'\n\n // Ensure directory exists\n const dir = path.dirname(statusFile)\n if (!fs.existsSync(dir)) {\n try {\n fs.mkdirSync(dir, { recursive: true })\n } catch (err) {\n throw new Error(`Failed to create status directory ${dir}: ${err}`)\n }\n }\n\n // Atomic write with fsync: write to temp file, flush to disk, then rename\n const data = JSON.stringify(state, null, 2)\n const fd = fs.openSync(tmpFile, 'w')\n try {\n fs.writeSync(fd, data)\n fs.fdatasyncSync(fd)\n } finally {\n fs.closeSync(fd)\n }\n fs.renameSync(tmpFile, statusFile)\n}\n\n/**\n * Delete the status.json file for a task.\n * Used by `full` mode to discard failed/completed state from a previous run\n * so that the pipeline starts fresh instead of short-circuiting.\n */\nexport function deleteState(taskId: string): void {\n const statusFile = getStatusFilePath(taskId)\n if (fs.existsSync(statusFile)) {\n fs.unlinkSync(statusFile)\n logger.info(`Deleted previous status.json for ${taskId} (fresh full-mode run)`)\n }\n}\n\n/**\n * Initialize a fresh v2 state\n */\nexport function initState(ctx: PipelineContext, mode: string): PipelineStateV2 {\n const now = new Date().toISOString()\n\n const actorHistory: ActorEvent[] = ctx.actor\n ? [{ action: 'pipeline-triggered', actor: ctx.actor, timestamp: now }]\n : []\n\n const state: PipelineStateV2 = {\n version: 2,\n taskId: ctx.taskId,\n mode,\n pipeline: 'spec_execute_verify', // will be updated after taskify\n startedAt: now,\n updatedAt: now,\n state: 'running',\n cursor: null,\n stages: {},\n // Persist issue number for dashboard lookups (avoids Compare API)\n ...(ctx.input.issueNumber ? { issueNumber: ctx.input.issueNumber } : {}),\n ...(ctx.actor ? { triggeredBy: ctx.actor } : {}),\n ...(ctx.input.issueCreator ? { issueCreator: ctx.input.issueCreator } : {}),\n ...(actorHistory.length > 0 ? { actorHistory } : {}),\n }\n\n writeState(ctx.taskId, state)\n return state\n}\n\n/** Max actor history entries kept in status.json (oldest dropped when exceeded) */\nconst MAX_ACTOR_HISTORY = MAX_ACTOR_HISTORY_ENTRIES\n\n/**\n * Append an actor event to the pipeline's actorHistory in status.json.\n * Automatically trims to MAX_ACTOR_HISTORY entries.\n */\nexport function appendActorEvent(\n taskId: string,\n state: PipelineStateV2,\n event: ActorEvent,\n): PipelineStateV2 {\n const existing = state.actorHistory ?? []\n const updated = [...existing, event]\n // Keep most recent MAX_ACTOR_HISTORY entries\n const trimmed = updated.length > MAX_ACTOR_HISTORY ? updated.slice(-MAX_ACTOR_HISTORY) : updated\n\n const newState: PipelineStateV2 = {\n ...state,\n actorHistory: trimmed,\n updatedAt: new Date().toISOString(),\n }\n writeState(taskId, newState)\n return newState\n}\n\n/**\n * Update the branchName in status.json after ensureFeatureBranch derives it.\n * Called from the build stage preExecute hook.\n */\nexport function setBranchName(\n taskId: string,\n state: PipelineStateV2,\n branchName: string,\n): PipelineStateV2 {\n const updated: PipelineStateV2 = {\n ...state,\n branchName,\n updatedAt: new Date().toISOString(),\n }\n writeState(taskId, updated)\n return updated\n}\n\n/**\n * Immutable update: returns a new state with the stage updated\n */\nexport function updateStage(\n state: PipelineStateV2,\n stageName: string,\n update: Partial<StageStateV2>,\n): PipelineStateV2 {\n const now = new Date().toISOString()\n\n // Create new stages object with the updated stage\n const newStages: Record<string, StageStateV2> = {}\n\n for (const [name, stage] of Object.entries(state.stages)) {\n if (name === stageName) {\n newStages[name] = {\n ...stage,\n ...update,\n }\n } else {\n newStages[name] = stage\n }\n }\n\n // If the stage didn't exist, create it\n if (!state.stages[stageName]) {\n newStages[stageName] = {\n state: update.state || 'pending',\n retries: 0,\n ...update,\n }\n }\n\n return {\n ...state,\n stages: newStages,\n updatedAt: now,\n }\n}\n\n/**\n * Mark pipeline as completed/failed/paused\n */\nexport function completeState(\n state: PipelineStateV2,\n finalState: 'completed' | 'failed' | 'timeout' | 'paused',\n): PipelineStateV2 {\n const now = new Date().toISOString()\n\n // Compute total cost across all stages\n let totalCost = 0\n for (const stage of Object.values(state.stages)) {\n if (stage.cost) {\n totalCost += stage.cost\n }\n }\n\n return {\n ...state,\n state: finalState,\n completedAt: now,\n updatedAt: now,\n ...(totalCost > 0 ? { totalCost } : {}),\n }\n}\n\n// ============================================================================\n// Recovery Functions - handle stale state from interrupted runs\n// ============================================================================\n\n/**\n * Recover stale stages: reset any stage stuck in \"running\" state to \"pending\".\n * This handles cases where the pipeline was killed mid-execution.\n *\n * Returns a new state object (immutable). If no stale stages found, returns\n * the input state unchanged.\n */\nexport function recoverStaleStages(state: PipelineStateV2): PipelineStateV2 {\n let hasChanges = false\n const newStages: Record<string, StageStateV2> = {}\n\n for (const [name, stage] of Object.entries(state.stages)) {\n if (stage.state === 'running') {\n // Reset stale running stage to pending\n newStages[name] = {\n ...stage,\n state: 'pending',\n startedAt: undefined,\n }\n logger.info(`⚠️ Recovered stale stage ${name}: running → pending`)\n hasChanges = true\n } else {\n newStages[name] = stage\n }\n }\n\n if (!hasChanges) {\n // No changes, return original state\n return state\n }\n\n return {\n ...state,\n stages: newStages,\n updatedAt: new Date().toISOString(),\n }\n}\n\n/**\n * Recover pipeline state: if all stages in the pipeline order are completed/skipped,\n * mark the pipeline as completed. If any non-advisory stage failed, mark as failed.\n *\n * Only acts when pipeline state is \"running\" - leaves completed/failed/paused states unchanged.\n *\n * @param state - The current pipeline state\n * @param pipelineOrder - Flat list of stage names in execution order\n * @param advisoryStages - Set of stage names that are advisory (failures don't fail pipeline)\n */\nexport function recoverPipelineState(\n state: PipelineStateV2,\n pipelineOrder: string[],\n advisoryStages: Set<string>,\n): PipelineStateV2 {\n // Only recover if pipeline is stuck in \"running\" state\n if (state.state !== 'running') {\n return state\n }\n\n // Check stages that are in the pipeline order\n let allCompletedOrSkipped = true\n let hasNonAdvisoryFailure = false\n\n for (const stageName of pipelineOrder) {\n const stage = state.stages[stageName]\n\n if (!stage) {\n // Stage not in state - still needs to run\n allCompletedOrSkipped = false\n continue\n }\n\n if (stage.state === 'pending' || stage.state === 'running') {\n // Stage hasn't completed yet\n allCompletedOrSkipped = false\n } else if (stage.state === 'failed') {\n // Check if this is an advisory failure\n if (!advisoryStages.has(stageName)) {\n hasNonAdvisoryFailure = true\n }\n // Advisory failures are OK - continue checking\n }\n // 'completed' and 'skipped' are fine - continue checking\n }\n\n // Determine new pipeline state\n if (hasNonAdvisoryFailure) {\n logger.info(`⚠️ Recovered pipeline state: running → failed (non-advisory stage failed)`)\n return completeState(state, 'failed')\n }\n\n if (allCompletedOrSkipped) {\n logger.info(`⚠️ Recovered pipeline state: running → completed (all stages done)`)\n return completeState(state, 'completed')\n }\n\n // Pipeline still has pending/running stages - leave as running\n return state\n}\n\n/**\n * Resume pipeline from a gate pause. Immutably marks the gate stage as completed\n * and resets the pipeline state to 'running' (removing completedAt).\n *\n * This replaces direct state mutation that was previously in entry.ts:454-461.\n */\nexport function resumeFromGate(state: PipelineStateV2, gateStageName: string): PipelineStateV2 {\n // Use updateStage for immutable stage update\n const updatedState = updateStage(state, gateStageName, {\n state: 'completed',\n completedAt: new Date().toISOString(),\n })\n\n // Reset pipeline from paused to running, remove completedAt\n const { completedAt: _, ...rest } = updatedState\n return {\n ...rest,\n state: 'running',\n updatedAt: new Date().toISOString(),\n }\n}\n\n/**\n * Reset stages from a given point onwards to pending.\n * Also deletes output files for reset stages (G37).\n *\n * C3 FIX: Uses stageOutputFile() instead of hardcoded `${stage}.md`\n * to correctly resolve output file paths for all stages\n * (e.g., taskify→task.json, architect→plan.md, etc.)\n */\nexport function resetFromStage(\n state: PipelineStateV2,\n fromStage: string,\n pipeline: string[],\n taskDir: string,\n): PipelineStateV2 {\n const now = new Date().toISOString()\n\n // Find the index of the fromStage\n const fromIndex = pipeline.indexOf(fromStage)\n if (fromIndex === -1) {\n // Stage not found, return original state\n return state\n }\n\n // Get stages to reset\n const stagesToReset = pipeline.slice(fromIndex)\n\n // C3 FIX: Delete output files using stageOutputFile for correct paths\n // Previously used `${stage}.md` which is wrong for stages like:\n // - taskify → task.json\n // - architect → plan.md\n // - clarify → questions.md\n // - commit → commit.md\n for (const stage of stagesToReset) {\n const outputFile = stageOutputFile(taskDir, stage)\n if (fs.existsSync(outputFile)) {\n fs.unlinkSync(outputFile)\n }\n }\n\n // Reset stages to pending\n const newStages: Record<string, StageStateV2> = {}\n\n // FIX #827: Stages BEFORE fromStage that are still 'paused' should be marked\n // 'completed' — if later stages ran, the paused stage must have been approved.\n // This prevents stale 'paused' states from causing reruns to re-trigger gates.\n const stagesBefore = pipeline.slice(0, fromIndex)\n\n for (const [name, stage] of Object.entries(state.stages)) {\n if (stagesToReset.includes(name)) {\n // Reset this stage to pending\n newStages[name] = {\n state: 'pending',\n retries: 0,\n }\n } else if (stagesBefore.includes(name) && stage.state === 'paused') {\n // Stale paused stage — later stages ran, so this must have been approved\n newStages[name] = {\n ...stage,\n state: 'completed',\n completedAt: stage.completedAt || now,\n }\n } else {\n // Keep existing stage\n newStages[name] = stage\n }\n }\n\n return {\n ...state,\n stages: newStages,\n state: 'running',\n cursor: fromStage as StageName,\n updatedAt: now,\n }\n}\n\n// ============================================================================\n// V1 Adapter for backward compatibility with formatStatusComment\n// ============================================================================\n\nimport type { KodyPipelineStatus, StageStatus } from '../kody-utils'\n\n/**\n * Convert v2 state to v1 format for formatStatusComment compatibility\n */\nexport function stateToV1(state: PipelineStateV2): KodyPipelineStatus {\n const v1Stages: Record<string, StageStatus> = {}\n\n for (const [name, stage] of Object.entries(state.stages)) {\n v1Stages[name] = {\n state:\n stage.state === 'paused'\n ? 'gate-waiting'\n : stage.state === 'observing'\n ? 'running'\n : stage.state,\n startedAt: stage.startedAt,\n completedAt: stage.completedAt,\n elapsed: stage.elapsed,\n retries: stage.retries,\n outputFile: stage.outputFile,\n skipped: stage.skipped,\n error: stage.error,\n tokenUsage: stage.tokenUsage\n ? { input: stage.tokenUsage.input, output: stage.tokenUsage.output }\n : undefined,\n cost: stage.cost,\n }\n }\n\n return {\n taskId: state.taskId,\n mode: state.mode,\n pipeline: state.pipeline,\n startedAt: state.startedAt,\n updatedAt: state.updatedAt,\n completedAt: state.completedAt,\n totalElapsed: state.totalElapsed,\n state: state.state,\n currentStage: state.cursor,\n stages: v1Stages,\n triggeredBy: state.triggeredBy ?? 'dispatch',\n issueNumber: state.issueNumber,\n runId: undefined,\n runUrl: undefined,\n controlMode: undefined,\n gatePoint: undefined,\n botCommentId: undefined,\n totalCost: state.totalCost,\n triggeredByLogin: state.triggeredBy,\n issueCreator: state.issueCreator,\n actorHistory: state.actorHistory,\n }\n}\n","/**\n * @fileType utility\n * @domain ci | kody | git\n * @pattern branch-management\n * @ai-summary Git utilities for feature branch creation in Kody scripts\n */\n\nimport { logger } from './logger'\nimport { execFileSync } from 'child_process'\nimport * as fs from 'fs'\nimport * as path from 'path'\n// FIX #9: Import status functions to persist branch name early\nimport { setBranchName, loadState } from './engine/status'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type TaskType =\n | 'spec_only'\n | 'implement_feature'\n | 'fix_bug'\n | 'refactor'\n | 'docs'\n | 'ops'\n | 'research'\n\n// ============================================================================\n// Branch Prefix Map\n// ============================================================================\n\nexport const BRANCH_PREFIX_MAP: Record<TaskType, string> = {\n spec_only: 'feat',\n implement_feature: 'feat',\n fix_bug: 'fix',\n refactor: 'refactor',\n docs: 'docs',\n ops: 'chore',\n research: 'feat',\n}\n\n// ============================================================================\n// Commit Type Map\n// ============================================================================\n\nexport const COMMIT_TYPE_MAP: Record<TaskType, string> = {\n spec_only: 'docs',\n implement_feature: 'feat',\n fix_bug: 'fix',\n refactor: 'refactor',\n docs: 'docs',\n ops: 'chore',\n research: 'chore',\n}\n\n/** Directories to stage new files from (safe - excludes secrets) */\nexport const SAFE_STAGE_DIRS = ['src/', 'tests/', '.tasks/']\n\n/** Well-known base branches — if the current branch is one of these, create a feature branch */\nconst BASE_BRANCHES = ['dev', 'main', 'master', '']\n\n// ============================================================================\n// Branch Name Derivation\n// ============================================================================\n\n/**\n * Derive a descriptive branch name from task.md\n * Returns: prefix/260225-description-from-title\n * Falls back to taskId if derivation fails\n */\nexport function deriveBranchName(taskDir: string, taskId: string): string {\n const taskMdPath = path.join(taskDir, 'task.md')\n\n if (!fs.existsSync(taskMdPath)) {\n return taskId\n }\n\n try {\n const content = fs.readFileSync(taskMdPath, 'utf-8')\n\n // Try to extract ## Issue Title first (highest priority)\n let title = ''\n const issueTitleMatch = content.match(/^##\\s*Issue\\s*Title\\s*\\n+([^\\n]+)/im)\n if (issueTitleMatch) {\n title = issueTitleMatch[1].trim()\n }\n\n // Fallback: get first meaningful line (skip # Task, headers)\n if (!title) {\n const lines = content.split('\\n')\n for (const line of lines) {\n const trimmed = line.trim()\n // Skip headers, empty lines\n if (trimmed && !trimmed.startsWith('#') && !trimmed.startsWith('##')) {\n title = trimmed\n break\n }\n }\n }\n\n if (!title) {\n return taskId\n }\n\n // Prepend date prefix from taskId for uniqueness\n const datePrefix = taskId.split('-').slice(0, 2).join('-') // e.g., \"260225-auto\"\n\n // Include issue number in branch name for disambiguation\n // Without this, findRemoteBranch() cannot distinguish branches created on the same day\n // for different issues (e.g., feat/260227-auto-... vs fix/260227-auto-...)\n const issueNum = process.env.ISSUE_NUMBER\n const issuePart = issueNum ? `-${issueNum}` : ''\n const maxTitleLength = 50 - datePrefix.length - issuePart.length - 1 // minus 1 for the hyphen\n\n // Sanitize: lowercase, replace spaces/special chars with hyphens, remove non-alphanumeric\n const sanitized = title\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, '') // keep only alphanumeric, spaces, hyphens\n .replace(/\\s+/g, '-') // spaces to hyphens\n .replace(/-+/g, '-') // multiple hyphens to one\n .replace(/^-|-$/g, '') // trim leading/trailing hyphens\n .slice(0, maxTitleLength) // max chars for title portion\n\n return `${datePrefix}${issuePart}-${sanitized}`\n } catch (deriveErr) {\n // FIX #7: Log when branch name derivation falls back to taskId\n logger.warn(\n { err: deriveErr },\n `[branch] Branch name derivation failed, falling back to: ${taskId}`,\n )\n return taskId\n }\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Detect the default branch of the remote repository.\n * Uses `git remote show origin` to find the HEAD branch.\n * Falls back to 'dev' if detection fails (common for this project).\n */\nexport function getDefaultBranch(cwd: string = process.cwd()): string {\n try {\n // Use symbolic-ref which is faster and more reliable than parsing `git remote show origin`\n const ref = execFileSync('git', ['symbolic-ref', 'refs/remotes/origin/HEAD'], {\n cwd,\n encoding: 'utf-8',\n stdio: 'pipe',\n }).trim()\n // ref is like \"refs/remotes/origin/dev\" — extract the branch name\n const branch = ref.replace('refs/remotes/origin/', '')\n if (branch) return branch\n } catch {\n // symbolic-ref may fail if HEAD ref hasn't been set\n }\n\n try {\n // Fallback: parse `git remote show origin` output\n const output = execFileSync('git', ['remote', 'show', 'origin'], {\n cwd,\n encoding: 'utf-8',\n stdio: 'pipe',\n timeout: 10_000,\n })\n const match = output.match(/HEAD branch:\\s*(\\S+)/)\n if (match?.[1]) return match[1]\n } catch {\n // Remote may be unreachable\n }\n\n return 'dev'\n}\n\n/**\n * Merge the default branch into the current branch.\n * This keeps the feature branch up-to-date with the latest changes from dev.\n * If a merge conflict occurs, aborts the merge and throws an error.\n */\n/**\n * Find and checkout a remote branch matching the given task ID.\n * Used by rerun mode to ensure task files are available before reading them.\n * Unlike ensureFeatureBranch, this doesn't need taskType — it searches all\n * remote branches for the task ID pattern.\n *\n * @returns true if a branch was found and checked out, false if not found\n */\nexport function checkoutTaskBranch(taskId: string, taskDir?: string): boolean {\n const cwd = process.cwd()\n const currentBranch = execFileSync('git', ['branch', '--show-current'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n\n // Already on a feature branch — don't switch\n if (!BASE_BRANCHES.includes(currentBranch)) {\n logger.info(`[branch] Already on feature branch: ${currentBranch}`)\n return true\n }\n\n // Fetch latest\n try {\n execFileSync('git', ['fetch', 'origin'], { cwd, stdio: 'inherit', timeout: 120_000 })\n } catch (fetchErr) {\n logger.warn({ err: fetchErr }, '[branch] git fetch failed')\n return false\n }\n\n // Search remote branches for one containing the task ID\n let remoteBranches: string[]\n try {\n const output = execFileSync('git', ['branch', '-r', '--list', `origin/*${taskId}*`], {\n cwd,\n encoding: 'utf-8',\n stdio: 'pipe',\n }).trim()\n remoteBranches = output\n .split('\\n')\n .map((b) => b.trim().replace('origin/', ''))\n .filter(Boolean)\n } catch {\n remoteBranches = []\n }\n\n if (remoteBranches.length === 0) {\n logger.info(`[branch] No remote branch found matching task ID: ${taskId}`)\n return false\n }\n\n // Use the first match (there should only be one branch per task)\n const branchName = remoteBranches[0]\n logger.info(`[branch] Found task branch: ${branchName} (for rerun of ${taskId})`)\n\n try {\n // Clean dirty state in CI before switching\n if (process.env.GITHUB_ACTIONS) {\n try {\n execFileSync('git', ['checkout', '--', '.'], { cwd, stdio: 'pipe' })\n } catch {\n // Working tree may already be clean\n }\n }\n\n execFileSync('git', ['checkout', branchName], { cwd, stdio: 'inherit' })\n execFileSync('git', ['pull', 'origin', branchName], { cwd, stdio: 'inherit' })\n mergeDefaultBranch(cwd)\n\n // Persist branch name to status.json\n try {\n const existingState = loadState(taskDir ? path.basename(taskDir) : taskId)\n if (existingState) {\n setBranchName(taskDir ? path.basename(taskDir) : taskId, existingState, branchName)\n }\n } catch {\n // Non-critical\n }\n\n logger.info(`[branch] Checked out task branch: ${branchName}`)\n return true\n } catch (checkoutErr) {\n logger.error({ err: checkoutErr }, `[branch] Failed to checkout task branch: ${branchName}`)\n return false\n }\n}\n\nexport function mergeDefaultBranch(cwd: string): void {\n const defaultBranch = getDefaultBranch(cwd)\n logger.info(`[branch] Merging latest ${defaultBranch} into current branch`)\n try {\n execFileSync('git', ['merge', `origin/${defaultBranch}`, '--no-edit'], {\n cwd,\n stdio: 'inherit',\n })\n } catch (_error) {\n logger.error(`[branch] Merge conflict detected while merging ${defaultBranch}`)\n logger.info('[branch] Aborting merge')\n try {\n execFileSync('git', ['merge', '--abort'], { cwd, stdio: 'inherit' })\n } catch (abortError) {\n // FIX #6: Log the abort error before falling back to hard reset.\n // merge --abort can fail if merge state was corrupted; hard reset discards ALL\n // uncommitted changes (not just conflicts), which is a last resort.\n const abortMsg = abortError instanceof Error ? abortError.message : String(abortError)\n logger.warn(\n `[branch] merge --abort failed (${abortMsg}), falling back to git reset --hard HEAD`,\n )\n logger.warn('[branch] \\u26a0\\ufe0f Hard reset will discard ALL uncommitted changes')\n execFileSync('git', ['reset', '--hard', 'HEAD'], { cwd, stdio: 'inherit' })\n }\n throw new Error(\n `Merge conflict while merging ${defaultBranch} into feature branch. Please resolve conflicts manually.`,\n )\n }\n}\n\n/**\n * Creates a feature branch before the build stage if needed.\n * This ensures the branch follows project conventions: fix/260225-description\n *\n * @param taskId - The task ID (e.g., \"260218-user-metrics\")\n * @param taskType - The task type (e.g., \"fix_bug\", \"implement_feature\")\n * @param projectDir - Optional project directory (defaults to cwd)\n * @param taskDir - Optional task directory for deriving descriptive branch name\n */\nexport function ensureFeatureBranch(\n taskId: string,\n taskType: string,\n projectDir?: string,\n taskDir?: string,\n): void {\n const cwd = projectDir || process.cwd()\n\n const currentBranch = execFileSync('git', ['branch', '--show-current'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n\n // Already on a feature branch - don't recreate\n if (!BASE_BRANCHES.includes(currentBranch)) {\n logger.info(`[branch] Already on feature branch: ${currentBranch}`)\n return\n }\n\n const prefix = BRANCH_PREFIX_MAP[taskType as TaskType] || 'feat'\n\n // Derive descriptive name from task.md if available, otherwise use taskId\n const branchDescription = taskDir ? deriveBranchName(taskDir, taskId) : taskId\n const branchName = `${prefix}/${branchDescription}`\n\n logger.info(`[branch] Ensuring feature branch: ${branchName}`)\n\n // Fetch latest from origin\n execFileSync('git', ['fetch', 'origin'], { cwd, stdio: 'inherit', timeout: 120_000 })\n\n // Check if branch already exists on remote (original behavior)\n let remoteBranchExists = false\n try {\n execFileSync('git', ['rev-parse', '--verify', `origin/${branchName}`], {\n cwd,\n encoding: 'utf-8',\n stdio: 'pipe',\n })\n remoteBranchExists = true\n } catch {\n remoteBranchExists = false\n }\n\n if (remoteBranchExists) {\n // Branch exists on remote — checkout and track it\n logger.info(`[branch] Remote branch exists, checking out: ${branchName}`)\n // Clean dirty state from previous failed runs before switching\n // Only revert tracked file modifications - don't delete untracked files\n // (Deleting untracked files could remove agent-created source files before they're committed)\n if (process.env.GITHUB_ACTIONS) {\n // CI mode: clean dirty tracked files from previous failed runs, then checkout branch\n try {\n execFileSync('git', ['checkout', '--', '.'], { cwd, stdio: 'pipe' })\n } catch {\n // Ignore — working tree may already be clean\n }\n // BUG FIX: Actually checkout the feature branch in CI mode.\n // Previously this only cleaned dirty state but never switched branches,\n // causing commits/pushes to land on dev (which has branch protection).\n execFileSync('git', ['checkout', branchName], { cwd, stdio: 'inherit' })\n execFileSync('git', ['pull', 'origin', branchName], { cwd, stdio: 'inherit' })\n\n // Merge default branch to keep feature branch up-to-date\n mergeDefaultBranch(cwd)\n } else {\n // Local mode: check for uncommitted changes and stash before checkout\n // Track whether we actually stashed to avoid popping unrelated stashes\n let didStash = false\n try {\n const status = execFileSync('git', ['status', '--porcelain'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n if (status) {\n logger.warn('[branch] ⚠ Working tree has uncommitted changes — stashing before checkout')\n execFileSync('git', ['stash', '--include-untracked'], { cwd, stdio: 'pipe' })\n didStash = true\n }\n } catch {\n // Ignore status check errors\n }\n execFileSync('git', ['checkout', branchName], { cwd, stdio: 'inherit' })\n execFileSync('git', ['pull', 'origin', branchName], { cwd, stdio: 'inherit' })\n\n // Merge default branch after pulling feature branch to keep it up-to-date\n mergeDefaultBranch(cwd)\n\n // Restore stashed changes only if we actually stashed something\n if (didStash) {\n try {\n logger.info('[branch] Restoring stashed changes...')\n execFileSync('git', ['stash', 'pop'], { cwd, stdio: 'inherit' })\n } catch {\n logger.warn('[branch] ⚠ Could not restore stash — may need manual recovery')\n }\n }\n }\n // FIX #9: Persist branch name to status.json immediately after checkout,\n // not just in build stage preExecute. This ensures the dashboard can find the\n // branch even for stages that run before build (e.g., gap, architect).\n try {\n const taskIdFromDir = taskDir ? path.basename(taskDir) : taskId\n const existingState = loadState(taskIdFromDir)\n if (existingState) {\n setBranchName(taskIdFromDir, existingState, branchName)\n logger.info(`[branch] Persisted branch name to status.json: ${branchName}`)\n }\n } catch {\n // Non-critical - branch name will be captured in build stage preExecute as fallback\n }\n logger.info(`[branch] Checked out and pulled: ${branchName}`)\n } else {\n // Branch doesn't exist on remote — check if it exists locally (from previous failed run)\n let localBranchExists = false\n try {\n execFileSync('git', ['rev-parse', '--verify', branchName], {\n cwd,\n encoding: 'utf-8',\n stdio: 'pipe',\n })\n localBranchExists = true\n } catch {\n localBranchExists = false\n }\n\n // If branch exists locally, checkout and resume work (stages will skip if already completed)\n if (localBranchExists) {\n logger.info(`[branch] Local branch exists, resuming: ${branchName}`)\n // Stash dirty state before switching (only in local mode, not CI)\n // Track whether we actually stashed to avoid popping unrelated stashes\n let didStash = false\n if (!process.env.GITHUB_ACTIONS) {\n try {\n const status = execFileSync('git', ['status', '--porcelain'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n if (status) {\n logger.info('[branch] Stashing uncommitted changes before checkout...')\n execFileSync('git', ['stash', '--include-untracked'], { cwd, stdio: 'pipe' })\n didStash = true\n }\n } catch {\n /* ignore */\n }\n } else {\n // CI mode: revert tracked files only - don't delete untracked files\n try {\n execFileSync('git', ['checkout', '--', '.'], { cwd, stdio: 'pipe' })\n } catch {\n // Ignore — working tree may already be clean\n }\n }\n\n execFileSync('git', ['checkout', branchName], { cwd, stdio: 'inherit' })\n\n // Merge default branch after checking out local branch to keep it up-to-date\n mergeDefaultBranch(cwd)\n\n // Restore stashed changes only if we actually stashed something\n if (didStash) {\n try {\n logger.info('[branch] Restoring stashed changes...')\n execFileSync('git', ['stash', 'pop'], { cwd, stdio: 'inherit' })\n } catch {\n logger.warn('[branch] Could not restore stash — may need manual recovery')\n }\n }\n\n // Try to push if remote doesn't have it yet\n try {\n execFileSync('git', ['push', '-u', 'origin', branchName], { cwd, stdio: 'inherit' })\n } catch {\n // Remote doesn't have it yet - that's fine\n }\n logger.info(`[branch] Checked out local branch: ${branchName}`)\n return\n }\n\n // Branch doesn't exist locally either — create new from default branch\n const defaultBranch = getDefaultBranch(cwd)\n logger.info(`[branch] Creating new branch from ${defaultBranch}: ${branchName}`)\n execFileSync('git', ['checkout', defaultBranch], { cwd, stdio: 'inherit' })\n execFileSync('git', ['pull', 'origin', defaultBranch], { cwd, stdio: 'inherit' })\n execFileSync('git', ['checkout', '-b', branchName], { cwd, stdio: 'inherit' })\n logger.info(`[branch] Created and switched to: ${branchName}`)\n }\n}\n\n// R2-FIX #7: Cache hook-safe env to avoid recreating on every git call (hot path).\n// process.env changes are rare during pipeline execution, so caching is safe.\nlet _hookSafeEnvCache: NodeJS.ProcessEnv | null = null\nfunction getHookSafeEnv(): NodeJS.ProcessEnv {\n if (!_hookSafeEnvCache) {\n _hookSafeEnvCache = { ...process.env, HUSKY: '0', SKIP_HOOKS: '1' }\n }\n return _hookSafeEnvCache\n}\n\n// ============================================================================\n// Pending Commit Patch — Persist build output across failed pushes\n// ============================================================================\n\nconst PENDING_PATCH_FILE = 'pending-commit.patch'\nconst PENDING_MESSAGE_FILE = 'pending-commit-message.txt'\n\n/**\n * Save the last commit as a patch file in the task directory.\n * Called when commit succeeds but push fails, so the build output\n * can be recovered on the next rerun without re-running the build stage.\n */\nexport function savePendingPatch(taskDir: string, cwd: string): boolean {\n try {\n // Generate patch from HEAD commit\n const patch = execFileSync('git', ['format-patch', '-1', 'HEAD', '--stdout'], {\n cwd,\n encoding: 'utf-8',\n timeout: 30_000,\n })\n\n if (!patch.trim()) {\n logger.warn('[patch] No patch content generated')\n return false\n }\n\n // Save patch to task directory\n const patchPath = path.join(taskDir, PENDING_PATCH_FILE)\n fs.writeFileSync(patchPath, patch)\n\n // Save commit message separately (format-patch includes it but we need it standalone)\n const message = execFileSync('git', ['log', '-1', '--format=%B'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n const messagePath = path.join(taskDir, PENDING_MESSAGE_FILE)\n fs.writeFileSync(messagePath, message)\n\n // Reset HEAD back so the patch can be cleanly re-applied on next run\n // (the commit exists locally but was never pushed)\n execFileSync('git', ['reset', 'HEAD~1'], {\n cwd,\n stdio: 'pipe',\n })\n\n logger.info(`[patch] Saved pending patch to ${PENDING_PATCH_FILE} (build output preserved)`)\n return true\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err)\n logger.error(`[patch] Failed to save pending patch: ${msg}`)\n return false\n }\n}\n\n/**\n * Check if a pending patch exists and apply it.\n * Called at the start of commitAndPush to restore build output\n * from a previous failed push attempt.\n *\n * @returns true if patch was applied, false if no patch or apply failed\n */\nexport function restorePendingPatch(taskDir: string, cwd: string): boolean {\n const patchPath = path.join(taskDir, PENDING_PATCH_FILE)\n if (!fs.existsSync(patchPath)) {\n return false\n }\n\n try {\n logger.info('[patch] Found pending patch — restoring build output from previous run...')\n\n // Apply the patch (--3way handles conflicts gracefully)\n execFileSync('git', ['apply', '--3way', patchPath], {\n cwd,\n stdio: 'pipe',\n timeout: 30_000,\n })\n\n // Clean up the patch file (it will be re-saved if push fails again)\n fs.unlinkSync(patchPath)\n const messagePath = path.join(taskDir, PENDING_MESSAGE_FILE)\n if (fs.existsSync(messagePath)) {\n fs.unlinkSync(messagePath)\n }\n\n logger.info('[patch] Successfully restored build output from pending patch')\n return true\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err)\n logger.warn(`[patch] Failed to apply pending patch (may need rebuild): ${msg}`)\n\n // Clean up the failed patch so we don't keep retrying it\n try {\n fs.unlinkSync(patchPath)\n } catch {\n // ignore\n }\n return false\n }\n}\n\n/**\n * Push to origin with automatic pull-rebase-retry on rejection.\n * Handles the case where the remote branch has been updated by a previous\n * pipeline run (e.g., gate approval pushed new commits before rerun started).\n *\n * FIX: Use origin/<branch> instead of HEAD for pull, and add force-with-lease fallback.\n * FIX: Fallback to GITHUB_TOKEN if App token fails with \"Write access to repository not granted\".\n *\n * @returns true if push succeeded, false if it failed even after rebase\n */\nexport function pushWithRebase(cwd: string, env?: NodeJS.ProcessEnv): boolean {\n const pushEnv = env || getHookSafeEnv()\n const pushOpts = { cwd, stdio: 'inherit' as const, env: pushEnv, timeout: 120_000 }\n\n // Get current branch name for proper remote tracking reference\n let branchName = ''\n try {\n branchName = execFileSync('git', ['branch', '--show-current'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n } catch {\n logger.warn('[push] Could not determine branch name, falling back to HEAD')\n branchName = ''\n }\n\n // Try push with provided env (typically App token)\n const tryPush = (pushEnvVar: NodeJS.ProcessEnv): boolean => {\n const opts = { cwd, stdio: 'inherit' as const, env: pushEnvVar, timeout: 120_000 }\n try {\n execFileSync('git', ['push', '-u', 'origin', 'HEAD'], opts)\n return true\n } catch {\n return false\n }\n }\n\n // First attempt with provided env (App token)\n if (tryPush(pushEnv)) {\n return true\n }\n\n // Push rejected — remote has new commits. Pull with rebase and retry.\n logger.info('[push] Push rejected, pulling with rebase...')\n try {\n // FIX: Use origin/<branch> instead of HEAD for proper remote tracking\n execFileSync('git', ['pull', '--rebase', 'origin', branchName], {\n cwd,\n stdio: 'inherit',\n timeout: 120_000,\n env: pushEnv,\n })\n\n // Retry push after rebase with App token\n if (tryPush(pushEnv)) {\n logger.info('[push] Push succeeded after rebase')\n return true\n }\n } catch {\n // Rebase failed — try force-with-lease\n }\n\n // Try force-with-lease as last resort with App token\n logger.info('[push] Rebase push failed, trying force-with-lease...')\n try {\n execFileSync('git', ['push', '-u', 'origin', 'HEAD', '--force-with-lease'], pushOpts)\n logger.info('[push] Push succeeded with force-with-lease')\n return true\n } catch (forceError: unknown) {\n const msg = forceError instanceof Error ? forceError.message : String(forceError)\n\n // Check if this is a permission error (App token lacks workflows permission)\n // Error: \"refusing to allow a GitHub App to create or update workflow .github/workflows/ci.yml\n // without workflows permission\"\n if (\n msg.includes('Write access to repository not granted') ||\n msg.includes('workflow') ||\n msg.includes('permission')\n ) {\n logger.warn('[push] App token push failed due to permissions — falling back to GITHUB_TOKEN')\n\n // Fallback: Use GITHUB_TOKEN for push (it can push source files but not workflows)\n // IMPORTANT: Unset the git url substitution that forces App token, so GITHUB_TOKEN is used\n const fallbackEnv = {\n ...getHookSafeEnv(),\n GH_TOKEN: undefined,\n GITHUB_TOKEN: process.env.GITHUB_TOKEN,\n }\n const fallbackOpts = { cwd, stdio: 'inherit' as const, env: fallbackEnv, timeout: 120_000 }\n\n // Remove the App token git config so fallback uses GITHUB_TOKEN\n try {\n execFileSync(\n 'git',\n ['config', '--global', '--unset', 'url.https://x-access-token:@github.com/.insteadOf'],\n {\n cwd,\n stdio: 'inherit',\n },\n )\n } catch {\n // Ignore if not set\n }\n\n // Try push with GITHUB_TOKEN\n try {\n execFileSync('git', ['push', '-u', 'origin', 'HEAD'], fallbackOpts)\n logger.info('[push] Push succeeded with GITHUB_TOKEN fallback')\n return true\n } catch (fallbackError: unknown) {\n const fallbackMsg =\n fallbackError instanceof Error ? fallbackError.message : String(fallbackError)\n logger.error(`[push] GITHUB_TOKEN fallback also failed: ${fallbackMsg}`)\n }\n }\n\n logger.error(`[push] Push failed after all retries: ${msg}`)\n return false\n }\n}\n\n/**\n * Derive conventional commit type from task type.\n */\nexport function deriveCommitType(taskType: string): string {\n return COMMIT_TYPE_MAP[taskType as TaskType] || 'feat'\n}\n\n/**\n * Extract commit subject from task.md content.\n * Uses first non-empty line after the title.\n */\nexport function extractCommitSubject(taskMdContent: string): string {\n const lines = taskMdContent.split('\\n')\n let foundTitle = false\n\n for (const line of lines) {\n // Skip the # Task title line\n if (line.match(/^#\\s+Task/i)) {\n foundTitle = true\n continue\n }\n // Skip empty lines\n if (!line.trim()) continue\n // First non-empty line after title is the subject\n if (foundTitle || line.match(/^#/)) {\n // Clean up the subject: remove leading -, *, numbers, etc.\n const subject = line\n .replace(/^[-*\\d.]\\s*/, '')\n .replace(/^#+\\s*/, '') // strip markdown headers\n .replace(/\\*\\*(.*?)\\*\\*/g, '$1') // strip bold markers\n .replace(/`(.*?)`/g, '$1') // strip inline code\n .trim()\n // Truncate to 72 chars (conventional commit subject max)\n return subject.length > 72 ? subject.slice(0, 69) + '...' : subject\n }\n }\n\n // Fallback: use first non-empty line\n const firstNonEmpty = lines.find((l) => l.trim())\n if (firstNonEmpty) {\n return firstNonEmpty.replace(/^#\\s*/, '').slice(0, 72)\n }\n\n return 'implement changes'\n}\n\n/**\n * Extract commit body from build.md content.\n * Uses the ## Changes section.\n */\nexport function extractCommitBody(buildMdContent: string): string {\n const changesMatch = buildMdContent.match(/##\\s*Changes\\s*\\n([\\s\\S]*?)(?=\\n##\\s|$)/i)\n\n if (changesMatch && changesMatch[1]) {\n // Take first few bullet points as body\n const bullets = changesMatch[1]\n .split('\\n')\n .filter((line) => line.trim().match(/^[-*•]/))\n .slice(0, 5)\n .map((line) =>\n line\n .replace(/^[-*•]\\s*/, '')\n .replace(/\\*\\*(.*?)\\*\\*/g, '$1') // strip bold\n .replace(/`(.*?)`/g, '$1') // strip inline code\n .trim(),\n )\n .join('. ')\n\n if (bullets.length > 20) return bullets\n }\n\n // Fallback: generic body\n return 'See build report for details.'\n}\n\n/**\n * Commit and push changes to the current branch.\n * Uses conventional commit format.\n */\nexport function commitAndPush(\n taskId: string,\n taskDir: string,\n cwd?: string,\n): {\n hash: string\n branch: string\n success: boolean\n message: string\n} {\n const workDir = cwd || process.cwd()\n\n // Get current branch\n let branch = execFileSync('git', ['branch', '--show-current'], {\n cwd: workDir,\n encoding: 'utf-8',\n }).trim()\n\n // Handle detached HEAD state (empty branch name)\n if (!branch) {\n branch =\n execFileSync('git', ['rev-parse', '--short', 'HEAD'], {\n cwd: workDir,\n encoding: 'utf-8',\n }).trim() || 'detached'\n logger.warn(`[commit] Detached HEAD detected, using ref: ${branch}`)\n }\n\n // Read task.json for commit type\n const taskJsonPath = path.join(taskDir, 'task.json')\n let taskType = 'implement_feature'\n let commitType = 'feat'\n\n if (fs.existsSync(taskJsonPath)) {\n try {\n const taskJson = JSON.parse(fs.readFileSync(taskJsonPath, 'utf-8'))\n taskType = taskJson.task_type || taskType\n commitType = deriveCommitType(taskType)\n } catch {\n // Use default\n }\n }\n\n // Read task.md for subject\n const taskMdPath = path.join(taskDir, 'task.md')\n let subject = 'implement changes'\n if (fs.existsSync(taskMdPath)) {\n const taskMdContent = fs.readFileSync(taskMdPath, 'utf-8')\n subject = extractCommitSubject(taskMdContent)\n }\n\n // Read build.md for body\n const buildMdPath = path.join(taskDir, 'build.md')\n let body = 'See build report for details.'\n if (fs.existsSync(buildMdPath)) {\n const buildMdContent = fs.readFileSync(buildMdPath, 'utf-8')\n body = extractCommitBody(buildMdContent)\n }\n\n // Build commit message\n const commitMessage = `${commitType}(${taskId}): ${subject}\\n\\n${body}`\n\n try {\n // Check if there are changes\n const status = execFileSync('git', ['status', '--porcelain'], {\n cwd: workDir,\n encoding: 'utf-8',\n }).trim()\n\n if (!status) {\n // Try restoring from a pending patch (build output from a previous failed push)\n const restored = restorePendingPatch(taskDir, workDir)\n if (!restored) {\n return {\n hash: '',\n branch,\n success: false,\n message: 'No changes to commit',\n }\n }\n // Re-check status after patch restore\n const newStatus = execFileSync('git', ['status', '--porcelain'], {\n cwd: workDir,\n encoding: 'utf-8',\n }).trim()\n if (!newStatus) {\n return {\n hash: '',\n branch,\n success: false,\n message: 'No changes to commit (patch restore produced no changes)',\n }\n }\n }\n\n // Stage tracked changes (modifications + deletions)\n execFileSync('git', ['add', '-u'], { cwd: workDir, stdio: 'inherit' })\n\n // Stage new files from safe directories only (BUG-15: avoid root-level .env files)\n // Pre-commit hooks (check-secrets, check-no-css) provide additional safety\n const safeDirs = ['src', 'tests', 'scripts', 'public', 'docs', '.tasks']\n for (const dir of safeDirs) {\n const dirPath = path.join(workDir, dir)\n if (fs.existsSync(dirPath)) {\n try {\n execFileSync('git', ['add', '--', dirPath], { cwd: workDir, stdio: 'pipe' })\n } catch {\n // Directory may have no new files - that's fine\n }\n }\n }\n\n // H6 FIX: Also stage new root config files that are needed for builds\n // These are safe config files (not .env) that the project needs\n const rootConfigPatterns = [\n 'package.json',\n 'pnpm-lock.yaml',\n 'tsconfig.json',\n /^tsconfig\\..*\\.json$/,\n /^next\\.config\\..+$/,\n 'payload.config.ts',\n /^tailwind\\.config\\..+$/,\n /^postcss\\.config\\..+$/,\n /^eslint\\.config\\..+$/,\n /^\\.prettierrc/,\n /^jest\\.config\\..+$/,\n /^vitest\\.config\\..+$/,\n ]\n\n const rootFiles = fs.readdirSync(workDir)\n for (const pattern of rootConfigPatterns) {\n const matches =\n typeof pattern === 'string'\n ? rootFiles.filter((f: string) => f === pattern)\n : rootFiles.filter((f: string) => pattern.test(f))\n for (const file of matches) {\n try {\n execFileSync('git', ['add', '--', file], { cwd: workDir, stdio: 'pipe' })\n } catch {\n // File may not be git-addable - that's fine\n }\n }\n }\n\n // Commit using execFileSync to prevent shell injection (BUG-4 fix)\n // Skip husky/commitlint hooks in CI - they run their own quality gates\n const hookSafeEnv = getHookSafeEnv()\n execFileSync('git', ['commit', '--no-gpg-sign', '-m', commitMessage], {\n cwd: workDir,\n stdio: 'inherit',\n env: hookSafeEnv,\n })\n\n // Get commit hash\n const hash = execFileSync('git', ['rev-parse', 'HEAD'], {\n cwd: workDir,\n encoding: 'utf-8',\n })\n .trim()\n .slice(0, 7)\n\n // Push with automatic rebase-retry on rejection (fixes rejected pushes on reruns)\n const pushed = pushWithRebase(workDir, hookSafeEnv)\n if (!pushed) {\n // Save the commit as a patch so it can be restored on next rerun\n // This preserves build output across failed pushes\n savePendingPatch(taskDir, workDir)\n return {\n hash,\n branch,\n success: false,\n message: `Committed (${hash}) but push failed after rebase`,\n }\n }\n\n return {\n hash,\n branch,\n success: true,\n message: `Committed and pushed: ${hash} ${subject}`,\n }\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : String(error)\n return {\n hash: '',\n branch,\n success: false,\n message: `Commit failed: ${msg}`,\n }\n }\n}\n\n// ============================================================================\n// Pipeline Files Commit - Unified commit function\n// ============================================================================\n\nexport type StagingStrategy = 'task-only' | 'tracked+task' | 'all'\n\n/**\n * Files that are always excluded from task-only commits (internal state markers).\n * NOTE: OpenCode runtime file patterns here must be kept in sync with\n * the .gitignore entries under \"OpenCode runtime files (per-task isolated data dirs)\".\n */\nconst TASK_FILES_ALWAYS_EXCLUDE = [\n 'gate-*.md',\n 'rerun-feedback.consumed.md',\n // OpenCode runtime files (only opencode.db is committed for session reuse)\n 'opencode-data/opencode/opencode.db-wal',\n 'opencode-data/opencode/opencode.db-shm',\n 'opencode-data/opencode/snapshot/',\n 'opencode-data/opencode/logs/',\n 'opencode-data/opencode/auth.json',\n 'opencode-data/opencode/bin/',\n 'opencode-data/opencode/tool-output/',\n 'opencode-data/opencode/storage/',\n 'opencode-data/opencode/worktree/',\n]\n\n/**\n * Debug artifacts — only committed when the pipeline fails (black box data).\n * On success these add noise to PRs; on failure they're essential for diagnosis.\n */\nconst TASK_FILES_DEBUG_ONLY = ['*-events.jsonl', '*-stderr.log']\n\nexport interface CommitPipelineFilesOptions {\n /** Task directory path */\n taskDir: string\n /** Task ID for branch/commit messages */\n taskId: string\n /** Commit message */\n message: string\n /** Whether to ensure feature branch exists first (default: true in CI) */\n ensureBranch?: boolean\n /** Whether to clean dirty state before commit (default: true in CI) */\n cleanDirtyState?: boolean\n /** Staging strategy: which files to stage */\n stagingStrategy?: StagingStrategy\n /** Whether to push after commit (default: true in CI) */\n push?: boolean\n /** Working directory (default: process.cwd()) */\n cwd?: string\n /** Whether this is CI mode (affects defaults) */\n isCI?: boolean\n /** Whether this is a dry run */\n dryRun?: boolean\n /** Whether the pipeline has failed — includes debug artifacts (*-events.jsonl, *-stderr.log) */\n pipelineFailed?: boolean\n}\n\nexport interface CommitPipelineFilesResult {\n success: boolean\n message: string\n committed?: boolean\n pushed?: boolean\n}\n\n/**\n * Unified function to commit pipeline files.\n * Consolidates 3 patterns from kody.ts:\n * - commitTaskFilesCI (CI mode with branch/cleanup)\n * - commitTaskFiles (local mode)\n * - autofix commit (tracked + task files)\n */\nexport function commitPipelineFiles(\n options: CommitPipelineFilesOptions,\n): CommitPipelineFilesResult {\n const {\n taskDir,\n taskId,\n message,\n ensureBranch = false,\n cleanDirtyState = false,\n stagingStrategy = 'task-only',\n push = false,\n cwd = process.cwd(),\n isCI = false,\n dryRun = false,\n pipelineFailed = false,\n } = options\n\n // Skip in dry-run mode\n if (dryRun) {\n return { success: true, message: 'Dry run - skipped', committed: false, pushed: false }\n }\n\n try {\n // 1. Optionally ensure feature branch exists\n if (ensureBranch) {\n // Read task type from task.json\n const taskJsonPath = path.join(taskDir, 'task.json')\n let taskType = 'implement_feature'\n if (fs.existsSync(taskJsonPath)) {\n try {\n const taskData = JSON.parse(fs.readFileSync(taskJsonPath, 'utf-8'))\n taskType = taskData.task_type || 'implement_feature'\n } catch {\n // Use default\n }\n }\n ensureFeatureBranch(taskId, taskType, cwd, taskDir)\n }\n\n // 2. Optionally clean dirty state (CI mode)\n // Only revert tracked file modifications - don't delete untracked files\n // (Deleting untracked files could remove agent-created source files before they're committed)\n if (cleanDirtyState && isCI) {\n try {\n execFileSync('git', ['checkout', '--', '.'], { cwd, stdio: 'pipe' })\n } catch {\n // Working tree may already be clean\n }\n }\n\n // 3. Stage files based on strategy\n // Use execFileSync to prevent shell injection via taskDir paths\n // Don't throw on staging errors - silent fail is ok for staging\n switch (stagingStrategy) {\n case 'all':\n try {\n execFileSync('git', ['add', '-A'], { cwd, stdio: 'inherit' })\n } catch (stageErr) {\n // FIX #7: Log staging errors instead of silently swallowing them\n logger.warn({ err: stageErr }, '[commit] git add -A failed (non-fatal)')\n }\n break\n case 'tracked+task':\n try {\n execFileSync('git', ['add', '-u'], { cwd, stdio: 'inherit' })\n } catch (stageErr) {\n // FIX #7: Log instead of silent swallow\n logger.warn({ err: stageErr }, '[commit] git add -u failed (non-fatal)')\n }\n try {\n execFileSync('git', ['add', '--', taskDir], { cwd, stdio: 'inherit' })\n } catch (stageErr) {\n logger.warn({ err: stageErr }, '[commit] git add task dir failed (non-fatal)')\n }\n break\n case 'task-only':\n default:\n try {\n execFileSync('git', ['add', '--', taskDir], { cwd, stdio: 'inherit' })\n } catch (stageErr) {\n // FIX #7: Log instead of silent swallow\n logger.warn({ err: stageErr }, '[commit] git add task-only failed (non-fatal)')\n }\n break\n }\n\n // 3b. Unstage excluded task artifacts to keep PRs clean\n // Always exclude gate markers; only include debug artifacts on failure\n if (stagingStrategy === 'task-only' || stagingStrategy === 'tracked+task') {\n const excludePatterns = [\n ...TASK_FILES_ALWAYS_EXCLUDE,\n ...(!pipelineFailed ? TASK_FILES_DEBUG_ONLY : []),\n ]\n for (const pattern of excludePatterns) {\n try {\n execFileSync('git', ['reset', 'HEAD', '--', path.join(taskDir, pattern)], {\n cwd,\n stdio: 'pipe',\n })\n } catch {\n // Pattern may not match any staged files — that's fine\n }\n }\n }\n\n // 4. Commit using execFileSync to prevent shell injection (BUG-5 fix)\n // Skip husky/commitlint hooks in CI - they run their own quality gates\n // Use stdio: 'pipe' to capture git output in error object for \"nothing to commit\" detection\n const hookSafeEnv = getHookSafeEnv()\n let committed = false\n try {\n execFileSync('git', ['commit', '--no-gpg-sign', '-m', message], {\n cwd,\n stdio: 'pipe',\n env: hookSafeEnv,\n })\n committed = true\n logger.info(`[commit] ${message}`)\n } catch (commitError: unknown) {\n const commitMsg = commitError instanceof Error ? commitError.message : String(commitError)\n // Also check stdout for git output (execFileSync error.message doesn't include git stdout)\n const commitStdout =\n commitError instanceof Error && 'stdout' in commitError\n ? String((commitError as Record<string, unknown>).stdout || '')\n : ''\n const fullOutput = commitMsg + commitStdout\n // Handle various git \"nothing to commit\" messages\n if (\n fullOutput.includes('nothing to commit') ||\n fullOutput.includes('no changes added') ||\n fullOutput.includes('nothing added to commit')\n ) {\n return { success: true, message: 'No changes to commit', committed: false }\n }\n throw commitError\n }\n\n // 5. Optionally push (with rebase-retry on rejection)\n // Use hook-safe env to skip pre-push hooks (e.g., Prettier/verify)\n // which may fail on unrelated files and block the pipeline\n let pushed = false\n if (push) {\n pushed = pushWithRebase(cwd, hookSafeEnv)\n if (pushed) {\n logger.info(`[commit] Pushed to origin`)\n } else {\n logger.error(`[commit] Push failed — remote may have diverged`)\n }\n }\n\n return { success: true, message: 'Committed successfully', committed, pushed }\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : String(error)\n logger.error(`[commit] Error: ${msg}`)\n return { success: false, message: msg }\n }\n}\n","/**\n * @fileType utility\n * @domain ci | kody\n * @pattern content-validation\n * @ai-summary Pure validation functions for pipeline stage outputs — extracted from kody.ts for testability\n */\n\nimport * as fs from 'fs'\n\n// ============================================================================\n// Question Detection\n// ============================================================================\n\n/**\n * Check if questions.md contains actual questions that need answering\n */\nexport function checkForQuestions(questionsPath: string): boolean {\n const content = fs.readFileSync(questionsPath, 'utf-8').trim()\n\n // If file is empty or just placeholder text, no questions\n if (!content || content.length < 10) {\n return false\n }\n\n // Check for question patterns:\n // - Lines starting with numbers followed by period or parenthesis (1. 2. 1) 2))\n // - Lines containing \"?\" character\n // - Sections like \"## Questions\" or \"### Clarifications Needed\"\n const hasNumberedQuestions = /^\\d+[.)]\\s+/m.test(content)\n // Match ? at end of a sentence (after a word char), not in URLs or code\n const hasQuestionMarks = /\\w\\?\\s*$/m.test(content)\n const hasQuestionHeader = /^#{1,3}\\s*(Questions|Clarifications|Needs Clarification)/m.test(\n content,\n )\n\n // Also check for \"APPROVED\" or \"No clarifications needed\" as indicators of no questions\n const isApproved = /^#{1,3}\\s*APPROVED/im.test(content)\n const noClarifications = /no clarifications needed/i.test(content)\n\n // Has questions if there's question content AND not explicitly approved\n const hasQuestionContent = hasNumberedQuestions || hasQuestionMarks || hasQuestionHeader\n\n return hasQuestionContent && !isApproved && !noClarifications\n}\n\n// ============================================================================\n// Spec Content Validation\n// ============================================================================\n\n/**\n * Validate that spec content contains required sections.\n * Returns true if valid, false otherwise.\n */\nexport function validateSpecContent(specContent: string): boolean {\n const hasRequirements = /##\\s*(Requirements|Functional|FR-|NFR-)/i.test(specContent)\n const hasAcceptance = /##\\s*Acceptance/i.test(specContent)\n return hasRequirements || hasAcceptance\n}\n\n/**\n * Validate spec file and return validation result.\n * Throws if spec is invalid.\n */\nexport function validateSpecFile(specFilePath: string): void {\n if (!fs.existsSync(specFilePath)) {\n throw new Error(`Spec file not found: ${specFilePath}`)\n }\n\n const specContent = fs.readFileSync(specFilePath, 'utf-8')\n if (!validateSpecContent(specContent)) {\n throw new Error('Spec missing ## Requirements or ## Acceptance Criteria sections')\n }\n}\n\n// ============================================================================\n// Build Report Validation\n// ============================================================================\n\n/**\n * Validate that build report contains a changes section.\n * Returns true if valid, false otherwise.\n */\nexport function validateBuildReport(buildContent: string): boolean {\n return /##\\s*(Changes|Files)/i.test(buildContent)\n}\n\n/**\n * Validate build file and return validation result.\n * Returns warning string if missing Changes section, empty string if valid.\n */\nexport function validateBuildFile(buildFilePath: string): string {\n if (!fs.existsSync(buildFilePath)) {\n return ''\n }\n\n const buildContent = fs.readFileSync(buildFilePath, 'utf-8')\n if (!validateBuildReport(buildContent)) {\n return 'Build report missing Changes section — agent may not have implemented anything'\n }\n return ''\n}\n\n// ============================================================================\n// Plan Gap Report Validation\n// ============================================================================\n\n/**\n * Validate plan-gap report content.\n * Reuses same logic as validateGapReport - both follow same format.\n * Returns true if valid, false otherwise.\n */\nexport function validatePlanGapReport(gapContent: string): boolean {\n const trimmed = gapContent.trim()\n\n // Empty content is invalid\n if (!trimmed || trimmed.length < 10) {\n return false\n }\n\n // Check for required sections\n const hasGapsFound = /##\\s*Gaps?\\s*(Found|Identified)/i.test(gapContent)\n const hasChangesMade = /##\\s*Changes Made/i.test(gapContent)\n const hasNoGaps = /no gaps identified/i.test(gapContent.toLowerCase())\n\n return hasGapsFound || hasChangesMade || hasNoGaps\n}\n\n// ============================================================================\n// Verify Summary Extraction\n// ============================================================================\n\n/**\n * Extract verification summary from verify output content\n */\nexport interface VerifySummary {\n typeScriptErrors: number\n testFailures: number\n lintErrors: number\n errorSamples: string[]\n}\n\nexport function extractVerifySummary(content: string): VerifySummary {\n const summary: VerifySummary = {\n typeScriptErrors: 0,\n testFailures: 0,\n lintErrors: 0,\n errorSamples: [],\n }\n\n const tsMatch = content.match(/TypeScript.*?(\\d+)\\s+error/i)\n if (tsMatch) summary.typeScriptErrors = parseInt(tsMatch[1])\n\n const testMatch = content.match(/Tests?.*?(\\d+)\\s+fail/i)\n if (testMatch) summary.testFailures = parseInt(testMatch[1])\n\n const lintMatch = content.match(/Lint.*?(\\d+)\\s+error/i)\n if (lintMatch) summary.lintErrors = parseInt(lintMatch[1])\n\n const lines = content.split('\\n')\n for (const line of lines) {\n if (\n (line.trim().startsWith('-') || line.trim().startsWith('•')) &&\n (line.includes('error') || line.includes('Error') || line.includes('✗'))\n ) {\n const cleaned = line.trim().replace(/^[-•]\\s*/, '')\n if (cleaned.length > 10 && summary.errorSamples.length < 5) {\n summary.errorSamples.push(cleaned)\n }\n }\n }\n return summary\n}\n\n/**\n * Check if verify content indicates failure.\n * Matches \"Result: FAIL\" anywhere in content, not per-gate failures like \"TypeScript: FAIL\".\n */\nexport function isVerifyFailed(verifyContent: string): boolean {\n return /\\bResult:\\s*FAIL\\b/i.test(verifyContent)\n}\n\n// ============================================================================\n// Build Tests Validation\n// ============================================================================\n\n/**\n * Validate that build report has tests written.\n * For implement_feature and fix_bug task types, tests are required.\n * For other types (refactor, docs, ops), tests are optional (warning only).\n */\nexport function validateBuildTests(buildContent: string): { hasTests: boolean; warning: string } {\n // Look for \"Tests Written\" section (case insensitive)\n // Split content by ## to find the section\n const sections = buildContent.split(/\\n## /i)\n\n // Find the Tests Written section\n const testsSection = sections.find((section) => /^Tests?\\s*Written/i.test(section))\n\n // If no Tests Written section at all\n if (!testsSection) {\n return {\n hasTests: false,\n warning: 'Build report missing ## Tests Written section',\n }\n }\n\n // Get content after the header (first line is \"Tests Written\\n\")\n const lines = testsSection.split('\\n')\n // Skip the first line (header) and get remaining content\n const contentAfterHeader = lines.slice(1).join('\\n').trim()\n\n // Check for empty content (just whitespace or empty string)\n if (!contentAfterHeader) {\n return {\n hasTests: false,\n warning: 'Build report indicates no tests were written',\n }\n }\n\n const testsContent = contentAfterHeader.toLowerCase()\n\n // Check for indicators that no tests were written\n const noTestsIndicators = ['no tests', 'none', 'n/a', 'not applicable', 'skipped', 'skip']\n const hasNoTestsIndicator = noTestsIndicators.some((indicator) =>\n testsContent.includes(indicator),\n )\n\n if (hasNoTestsIndicator) {\n return {\n hasTests: false,\n warning: 'Build report indicates no tests were written',\n }\n }\n\n // Tests were written (section exists and has content)\n return { hasTests: true, warning: '' }\n}\n\n// ============================================================================\n// Gap Report Validation\n// ============================================================================\n\n/**\n * Validate that gap report contains required sections.\n * Returns true if valid, false otherwise.\n */\nexport function validateGapReport(gapContent: string): boolean {\n const trimmed = gapContent.trim()\n\n // Empty content is invalid\n if (!trimmed || trimmed.length < 10) {\n return false\n }\n\n // Check for required sections\n const hasGapsFound = /##\\s*Gaps?\\s*(Found|Identified)/i.test(gapContent)\n const hasChangesMade = /##\\s*Changes Made/i.test(gapContent)\n const hasNoGaps = /no gaps identified/i.test(gapContent.toLowerCase())\n\n return hasGapsFound || hasChangesMade || hasNoGaps\n}\n\n// ============================================================================\n// Test Report Validation\n// ============================================================================\n\n/**\n * Validate that test.md contains required sections indicating tests were written.\n */\nexport function validateTestReport(content: string): boolean {\n const hasTestsWritten = /##\\s*Tests?\\s*Written/i.test(content)\n const hasTestCases = /##\\s*Test\\s*Cases/i.test(content)\n const hasTestFiles = /##\\s*Test\\s*Files/i.test(content)\n\n return hasTestsWritten || hasTestCases || hasTestFiles\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern validators\n * @ai-summary Pipeline validators moved from kody.ts for testability\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext, ValidationResult } from '../engine/types'\nimport {\n validateGapReport,\n validatePlanGapReport,\n validateBuildReport,\n validateSpecContent,\n validateTestReport,\n} from '../content-validators'\n\n/**\n * Create a validator for the gap stage.\n * Gap now writes BOTH spec.md and gap.md (spec stage was merged into gap).\n * Validates gap.md format AND ensures spec.md exists with proper structure.\n */\nexport function createGapValidator(ctx: PipelineContext): (outputFile: string) => ValidationResult {\n return (outputFile: string) => {\n const content = fs.readFileSync(outputFile, 'utf-8')\n if (!validateGapReport(content)) {\n return {\n valid: false,\n error:\n 'gap.md must contain ## Gaps Found, ## Changes Made, or \"No gaps identified\" (you wrote something else)',\n }\n }\n\n // Validate spec.md was created by gap agent with proper structure\n const specFile = path.join(ctx.taskDir, 'spec.md')\n if (!fs.existsSync(specFile)) {\n return {\n valid: false,\n error:\n 'gap agent must write spec.md with ## Requirements or ## Acceptance Criteria sections',\n }\n }\n\n const specContent = fs.readFileSync(specFile, 'utf-8')\n if (!validateSpecContent(specContent)) {\n return {\n valid: false,\n error: 'spec.md must contain ## Requirements or ## Acceptance Criteria sections',\n }\n }\n\n return { valid: true }\n }\n}\n\n/**\n * Create a validator for the plan-gap stage.\n * Validates plan-gap format AND checks plan.md still exists.\n */\nexport function createPlanGapValidator(\n ctx: PipelineContext,\n): (outputFile: string) => ValidationResult {\n return (outputFile: string) => {\n const content = fs.readFileSync(outputFile, 'utf-8')\n if (!validatePlanGapReport(content)) {\n return {\n valid: false,\n error: 'plan-gap.md must contain ## Gaps Found, ## Changes Made, or \"No gaps identified\"',\n }\n }\n\n // Verify plan.md still exists (gap agent shouldn't delete it)\n const planFile = path.join(ctx.taskDir, 'plan.md')\n if (!fs.existsSync(planFile)) {\n return {\n valid: false,\n error: 'plan-gap agent deleted plan.md - it must not delete the plan file',\n }\n }\n return { valid: true }\n }\n}\n\n/**\n * Create a validator for the build stage.\n */\nexport function createBuildValidator(): (outputFile: string) => ValidationResult {\n return (outputFile: string) => {\n const content = fs.readFileSync(outputFile, 'utf-8')\n if (!validateBuildReport(content)) {\n return {\n valid: false,\n error:\n 'build.md must contain ## Changes or ## Files section describing what was implemented',\n }\n }\n return { valid: true }\n }\n}\n\n/**\n * Create a validator for the docs stage.\n * Validates docs.md was written with minimum content.\n */\nexport function createDocsValidator(): (outputFile: string) => ValidationResult {\n return (outputFile: string) => {\n if (!fs.existsSync(outputFile)) {\n return {\n valid: false,\n error: 'docs.md must exist in the task directory',\n }\n }\n const content = fs.readFileSync(outputFile, 'utf-8')\n const minLength = 100\n if (content.length < minLength) {\n return {\n valid: false,\n error: `docs.md must have at least ${minLength} characters of content`,\n }\n }\n return { valid: true }\n }\n}\n\n/**\n * Create a validator for the test stage.\n * Validates test.md contains test case sections.\n */\nexport function createTestValidator(): (outputFile: string) => ValidationResult {\n return (outputFile: string) => {\n const content = fs.readFileSync(outputFile, 'utf-8')\n if (!validateTestReport(content)) {\n return {\n valid: false,\n error: 'test.md must contain ## Tests Written, ## Test Cases, or ## Test Files section',\n }\n }\n return { valid: true }\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern verify-failures\n * @ai-summary Captures gate output files into verify-failures.md for the fix stage\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext } from '../engine/types'\nimport { MAX_GATE_OUTPUT_CHARS } from '../config/constants'\nimport { logger } from '../logger'\n\n/** Gate output file definitions — maps human-readable names to filenames */\nconst GATE_FILES = [\n { name: 'TypeScript Errors', file: 'typescript-output.txt' },\n { name: 'Lint Errors', file: 'lint-output.txt' },\n { name: 'Format Errors', file: 'format-output.txt' },\n { name: 'Unit Test Errors', file: 'unit-tests-output.txt' },\n] as const\n\n/**\n * Capture gate output files into verify-failures.md.\n *\n * Reads gate output files written by runVerifyStage, assembles them into\n * a markdown document, and writes it to the task directory for the fix\n * stage to read.\n *\n * This function is used as `retryWith.onFailure` in the verify stage definition.\n */\nexport async function captureVerifyFailures(ctx: PipelineContext, taskDir: string): Promise<void> {\n const verifyFailuresPath = path.join(taskDir, 'verify-failures.md')\n\n // Read the verify stage's output file for the error summary\n const verifyOutputPath = path.join(taskDir, 'verify.md')\n let errorSummary = 'Verify failed - check logs'\n if (fs.existsSync(verifyOutputPath)) {\n const content = fs.readFileSync(verifyOutputPath, 'utf-8').trim()\n if (content.length > 0) {\n errorSummary = content.slice(0, MAX_GATE_OUTPUT_CHARS)\n }\n }\n\n // Assemble detailed output from individual gate output files\n let detailedOutput = errorSummary\n try {\n const parts = [`# Verify Failures\\n\\n${errorSummary}`]\n for (const gate of GATE_FILES) {\n const gatePath = path.join(taskDir, gate.file)\n if (fs.existsSync(gatePath)) {\n const gateOutput = fs.readFileSync(gatePath, 'utf-8').slice(0, MAX_GATE_OUTPUT_CHARS)\n parts.push(`## ${gate.name}\\n\\`\\`\\`\\n${gateOutput}\\n\\`\\`\\``)\n }\n }\n detailedOutput = parts.join('\\n\\n')\n } catch {\n // Gate output files may not exist, use basic error\n }\n\n try {\n fs.writeFileSync(verifyFailuresPath, detailedOutput)\n if (!fs.existsSync(verifyFailuresPath)) {\n logger.warn('verify-failures.md was not created after write — fix stage may skip')\n }\n } catch (writeErr) {\n logger.warn(`Failed to write verify-failures.md: ${writeErr}`)\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern skip-conditions\n * @ai-summary Pure functions that determine if a stage should be skipped\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext, SkipResult } from '../engine/types'\nimport { getStageComplexityThreshold, isValidStageName } from '../stages/registry'\nimport { getComplexityTier } from '../pipeline-utils'\n\n/**\n * Check if stage should be skipped due to input_quality skip_stages\n */\nexport function skipIfInputQuality(ctx: PipelineContext, stageName: string): SkipResult {\n const taskDef = ctx.taskDef\n if (!taskDef?.input_quality?.skip_stages) {\n return { shouldSkip: false }\n }\n\n const skipStages = taskDef.input_quality.skip_stages\n if (!skipStages.includes(stageName as 'gap' | 'clarify' | 'architect' | 'plan-gap' | 'build')) {\n return { shouldSkip: false }\n }\n\n // Check if promoted file exists AND has valid content\n // FIX #4: Don't just check existence - validate content is meaningful\n // A stub file from an interrupted run should not cause skip\n const outputFile = path.join(ctx.taskDir, `${stageName}.md`)\n if (!fs.existsSync(outputFile)) {\n return { shouldSkip: false }\n }\n\n // Validate the file has meaningful content (not just a stub)\n const fileContent = fs.readFileSync(outputFile, 'utf-8').trim()\n const minContentLength = 50 // Minimum meaningful content length\n\n if (\n fileContent.length < minContentLength ||\n (fileContent.includes('(promoted)') && fileContent.length < 200)\n ) {\n // File is too short or appears to be an incomplete stub\n // Don't skip - let the stage run to regenerate proper content\n return { shouldSkip: false }\n }\n\n return {\n shouldSkip: true,\n reason: `Promoted via input_quality (valid file exists)`,\n }\n}\n\n/**\n * Check if clarify stage should be skipped when --clarify is disabled.\n * Also handles auto-create of clarified.md and cleanup of questions.md.\n */\nexport function skipIfClarifyDisabled(ctx: PipelineContext): SkipResult {\n // Only applies when clarify is DISABLED\n if (ctx.input.clarify) {\n return { shouldSkip: false }\n }\n\n const clarifiedPath = path.join(ctx.taskDir, 'clarified.md')\n\n // Create default clarified.md if it doesn't exist\n if (!fs.existsSync(clarifiedPath)) {\n fs.writeFileSync(clarifiedPath, '# Clarified\\n\\nUse recommended answers.\\n')\n }\n\n // Clean up residual questions.md from previous clarify-enabled run\n const questionsPath = path.join(ctx.taskDir, 'questions.md')\n if (fs.existsSync(questionsPath)) {\n fs.unlinkSync(questionsPath)\n }\n\n return { shouldSkip: true, reason: 'Clarify disabled, auto-created clarified.md' }\n}\n\n/**\n * Check if clarify stage should be skipped when spec has no open questions.\n * ONLY applies when clarify IS enabled (G12).\n */\nexport function skipIfSpecHasNoOpenQuestions(ctx: PipelineContext): SkipResult {\n // Only applies when clarify IS enabled\n if (!ctx.input.clarify) {\n return { shouldSkip: false }\n }\n\n const specFile = path.join(ctx.taskDir, 'spec.md')\n if (!fs.existsSync(specFile)) {\n return { shouldSkip: false }\n }\n\n const specContent = fs.readFileSync(specFile, 'utf-8')\n const hasOpenQuestions = /##\\s*Open Questions/i.test(specContent)\n\n if (!hasOpenQuestions) {\n return { shouldSkip: true, reason: 'Spec has no Open Questions' }\n }\n\n return { shouldSkip: false }\n}\n\n/**\n * Check if impl stages should be skipped for spec_only pipelines\n */\nexport function skipIfSpecOnly(ctx: PipelineContext): SkipResult {\n const taskDef = ctx.taskDef\n if (taskDef?.pipeline === 'spec_only') {\n return { shouldSkip: true, reason: 'Pipeline is spec_only' }\n }\n return { shouldSkip: false }\n}\n\n/**\n * Check if a stage should be skipped based on the task's complexity score.\n * Each stage has a minimum complexity threshold defined in STAGE_COMPLEXITY_THRESHOLDS.\n * If the task's complexity is below the threshold, the stage is skipped.\n *\n * Returns { shouldSkip: false } when:\n * - No complexity score is set (backward compat — fall through to other skip logic)\n * - The stage has no threshold (always runs)\n * - The task's complexity meets or exceeds the threshold\n */\nexport function skipIfBelowComplexity(ctx: PipelineContext, stageName: string): SkipResult {\n const complexity = ctx.taskDef?.complexity\n // No complexity score → don't skip (backward compatibility)\n if (complexity === undefined) {\n return { shouldSkip: false }\n }\n\n if (!isValidStageName(stageName)) {\n return { shouldSkip: false }\n }\n const threshold = getStageComplexityThreshold(stageName)\n // No threshold defined for this stage → don't skip\n if (threshold === 0) {\n return { shouldSkip: false }\n }\n\n if (complexity < threshold) {\n const tier = getComplexityTier(complexity)\n return {\n shouldSkip: true,\n reason: `Complexity ${complexity} (${tier}) below threshold ${threshold} for ${stageName}`,\n }\n }\n\n return { shouldSkip: false }\n}\n","/**\n * @fileType configuration\n * @domain kody | pipeline\n * @pattern pipeline-definitions\n * @ai-summary Declarative stage configurations for the Kody pipeline state machine\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type {\n PipelineDefinition,\n PipelineContext,\n StageDefinition,\n PipelineStep,\n} from '../engine/types'\nimport {\n type StageName,\n getStageTimeout,\n getStageComplexityThreshold,\n SPEC_ORDER_STANDARD,\n SPEC_ORDER_LIGHTWEIGHT,\n IMPL_ORDER_STANDARD,\n IMPL_ORDER_LIGHTWEIGHT,\n SPEC_ORDER_TURBO,\n IMPL_ORDER_TURBO,\n} from '../stages/registry'\nimport { ensureFeatureBranch } from '../git-utils'\nimport { readTask } from '../pipeline-utils'\nimport { setBranchName, loadState } from '../engine/status'\nimport { execFileSync } from 'child_process'\nimport {\n createGapValidator,\n createPlanGapValidator,\n createBuildValidator,\n createDocsValidator,\n createTestValidator,\n} from './validators'\nimport { captureVerifyFailures } from './verify-failures'\nimport { DEFAULT_MAX_FIX_ATTEMPTS } from '../config/constants'\nimport {\n skipIfInputQuality,\n skipIfClarifyDisabled,\n skipIfSpecHasNoOpenQuestions,\n skipIfSpecOnly,\n skipIfBelowComplexity,\n} from './skip-conditions'\nimport { logger } from '../logger'\n\n// Re-export pipeline order arrays from registry for backward compatibility\nexport {\n SPEC_ORDER_STANDARD,\n SPEC_ORDER_LIGHTWEIGHT,\n IMPL_ORDER_STANDARD,\n IMPL_ORDER_LIGHTWEIGHT,\n SPEC_ORDER_TURBO,\n IMPL_ORDER_TURBO,\n FIX_ORDER,\n FIX_FULL_ORDER,\n} from '../stages/registry'\n\n// ============================================================================\n// Prev-Run File Restoration\n// ============================================================================\n\n/**\n * Restore prev-run files from git if they're missing.\n * This handles the case where pipeline restarts after a previous run\n * already created the output files (e.g., architect succeeded but pipeline\n * restarted from taskify).\n */\nasync function restorePrevRunFiles(taskDir: string, _taskId: string): Promise<void> {\n const prevRunDir = path.join(taskDir, 'prev-run')\n\n // Files to restore from git\n const filesToRestore = ['plan.md', 'build.md', 'review.md']\n\n for (const file of filesToRestore) {\n const prevRunPath = path.join(prevRunDir, file)\n const mainPath = path.join(taskDir, file)\n\n // If prev-run version exists, nothing to do\n if (fs.existsSync(prevRunPath)) {\n continue\n }\n\n // Try to get the file from git (current branch's latest commit)\n try {\n const gitShowOutput = execFileSync('git', ['show', `HEAD:${taskDir}/${file}`], {\n encoding: 'utf-8',\n timeout: 10000,\n })\n\n // Ensure prev-run directory exists\n if (!fs.existsSync(prevRunDir)) {\n fs.mkdirSync(prevRunDir, { recursive: true })\n }\n\n // Write to prev-run/\n fs.writeFileSync(prevRunPath, gitShowOutput)\n logger.info(` 🔄 Restored ${file} from git to prev-run/`)\n\n // Also restore to main location if the main file doesn't exist\n if (!fs.existsSync(mainPath)) {\n fs.writeFileSync(mainPath, gitShowOutput)\n logger.info(` 🔄 Restored ${file} from git to main location`)\n }\n } catch {\n // File not in git, that's OK - it may not have been created yet\n }\n }\n}\n\n// ============================================================================\n// Stage Definitions\n// ============================================================================\n\n/**\n * Create all stage definitions\n */\nfunction createStageDefinitions(ctx: PipelineContext): Map<StageName, StageDefinition> {\n const stages = new Map<StageName, StageDefinition>()\n\n // taskify stage\n stages.set('taskify', {\n name: 'taskify',\n type: 'agent',\n timeout: getStageTimeout('taskify'),\n maxRetries: 1,\n postActions: [\n { type: 'validate-task-json' },\n { type: 'set-classification-labels' },\n // NOTE: resolve-profile MUST be last to ensure profile is resolved before check-gate runs\n // see issue #1 in pipeline analysis - profile race condition fix\n { type: 'check-gate', gate: 'taskify' },\n {\n type: 'commit-task-files',\n stagingStrategy: 'task-only',\n push: true,\n ensureBranch: true,\n },\n { type: 'resolve-profile' }, // Must be last - triggers pipeline rebuild for next stages\n ],\n })\n\n // gap stage (also writes spec.md — spec stage was merged into gap)\n stages.set('gap', {\n name: 'gap',\n type: 'agent',\n timeout: getStageTimeout('gap'),\n maxRetries: 1,\n minComplexity: getStageComplexityThreshold('gap'),\n shouldSkip: (ctx) => {\n const complexitySkip = skipIfBelowComplexity(ctx, 'gap')\n if (complexitySkip.shouldSkip) return complexitySkip\n return skipIfInputQuality(ctx, 'gap')\n },\n validator: createGapValidator(ctx),\n })\n\n // clarify stage - NO post-actions (G17)\n stages.set('clarify', {\n name: 'clarify',\n type: 'agent',\n timeout: getStageTimeout('clarify'),\n maxRetries: 1,\n minComplexity: getStageComplexityThreshold('clarify'),\n shouldSkip: (ctx) => {\n // First check complexity threshold\n const complexitySkip = skipIfBelowComplexity(ctx, 'clarify')\n if (complexitySkip.shouldSkip) return complexitySkip\n\n // Then try input quality skip\n const inputQualitySkip = skipIfInputQuality(ctx, 'clarify')\n if (inputQualitySkip.shouldSkip) return inputQualitySkip\n\n // Then try clarify disabled skip\n const clarifyDisabledSkip = skipIfClarifyDisabled(ctx)\n if (clarifyDisabledSkip.shouldSkip) return clarifyDisabledSkip\n\n // Then try no open questions skip (only when clarify IS enabled)\n const noQuestionsSkip = skipIfSpecHasNoOpenQuestions(ctx)\n return noQuestionsSkip\n },\n })\n\n // architect stage\n stages.set('architect', {\n name: 'architect',\n type: 'agent',\n timeout: getStageTimeout('architect'),\n maxRetries: 1,\n minComplexity: getStageComplexityThreshold('architect'),\n shouldSkip: (ctx) => {\n const complexitySkip = skipIfBelowComplexity(ctx, 'architect')\n if (complexitySkip.shouldSkip) return complexitySkip\n return skipIfSpecOnly(ctx)\n },\n preExecute: async (ctx) => {\n // Restore prev-run files from git if they're missing\n // This handles the case where pipeline restarts after architect previously succeeded\n await restorePrevRunFiles(ctx.taskDir, ctx.taskId)\n },\n postActions: [\n { type: 'archive-rerun-feedback' },\n { type: 'check-gate', gate: 'architect', includeArtifact: 'plan.md' },\n ],\n fallbackOnMissingOutput: (ctx) => {\n // Fallback: try to use existing plan.md, context.md, or restore from git\n const planFile = path.join(ctx.taskDir, 'plan.md')\n if (fs.existsSync(planFile)) return null // File exists, no fallback needed\n\n // First try: restore from git (handles case where pipeline restarted but git has the file)\n const prevRunPlan = path.join(ctx.taskDir, 'prev-run', 'plan.md')\n if (fs.existsSync(prevRunPlan)) {\n // Copy to main location\n fs.copyFileSync(prevRunPlan, planFile)\n logger.info(` ℹ️ Restored plan.md from prev-run/`)\n return null // File now exists, let stage proceed\n }\n\n // Second try: use context.md as a rough plan\n // This happens when agent does extensive research but runs out of output capacity\n const contextFile = path.join(ctx.taskDir, 'context.md')\n if (fs.existsSync(contextFile)) {\n logger.warn(\n ` ⚠️ Architect fallback: using context.md as plan substitute for ${ctx.taskId}`,\n )\n const contextContent = fs.readFileSync(contextFile, 'utf-8')\n return `# Plan: ${ctx.taskId}\n\n## Summary\n\nArchitect agent completed research but did not write plan.md. Using context.md as fallback plan.\n\n${contextContent}\n\n## Note\n\nThis plan was auto-generated from context.md because architect failed to produce plan.md.\nThe implementation should proceed using the file list in context.md.\n`\n }\n return null\n },\n })\n\n // plan-gap stage\n stages.set('plan-gap', {\n name: 'plan-gap',\n type: 'agent',\n timeout: getStageTimeout('plan-gap'),\n maxRetries: 1,\n minComplexity: getStageComplexityThreshold('plan-gap'),\n shouldSkip: (ctx) => {\n // Skip plan-gap when pipeline is spec_only (no plan.md exists to gap-check)\n const specOnlySkip = skipIfSpecOnly(ctx)\n if (specOnlySkip.shouldSkip) return specOnlySkip\n const complexitySkip = skipIfBelowComplexity(ctx, 'plan-gap')\n if (complexitySkip.shouldSkip) return complexitySkip\n return skipIfInputQuality(ctx, 'plan-gap')\n },\n postActions: [{ type: 'validate-plan-exists' }],\n validator: createPlanGapValidator(ctx),\n fallbackOnMissingOutput: (ctx) => {\n // If agent edited plan.md but forgot to write plan-gap.md, create a fallback\n const planFile = path.join(ctx.taskDir, 'plan.md')\n if (fs.existsSync(planFile)) {\n logger.warn(\n ` ⚠️ Plan-gap fallback: agent edited plan.md directly without writing plan-gap.md for ${ctx.taskId}`,\n )\n return `# Plan Gap Analysis: ${ctx.taskId}\n\n## Summary\n\n- Gaps Found: 0\n- Plan Revised: Yes (agent edited plan.md directly)\n\n## Changes Made to Plan\n\nAgent revised plan.md but did not produce a separate gap report.\nSee plan.md for the revised plan.\n\n## No Gaps Found\n\nNo critical gaps identified. Plan was refined in-place.\n`\n }\n return null\n },\n })\n\n // test stage — TDD red phase: writes failing tests in parallel with build\n stages.set('test', {\n name: 'test',\n type: 'agent',\n timeout: getStageTimeout('test'),\n maxRetries: 1,\n minComplexity: getStageComplexityThreshold('test'),\n shouldSkip: (ctx) => skipIfInputQuality(ctx, 'test'),\n preExecute: async (ctx) => {\n // Ensure feature branch for deferred test runs (triggered by inspector plugin).\n // Without this, the test stage would try to commit/push to dev (branch-protected).\n if (!ctx.input.dryRun) {\n try {\n const td = readTask(ctx.taskDir)\n if (td) {\n ensureFeatureBranch(ctx.taskId, td.task_type, undefined, ctx.taskDir)\n }\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error)\n throw new Error(`Test stage preExecute failed: ${msg}`)\n }\n }\n },\n postActions: [\n // Commit test files after test stage completes (for deferred test runs)\n {\n type: 'commit-task-files',\n stagingStrategy: 'tracked+task',\n push: true,\n ensureBranch: true,\n },\n ],\n validator: createTestValidator(),\n })\n // build stage - has preExecute for ensureFeatureBranch (G20)\n stages.set('build', {\n name: 'build',\n type: 'agent',\n timeout: getStageTimeout('build'),\n maxRetries: 1,\n minComplexity: getStageComplexityThreshold('build'),\n shouldSkip: (ctx) => skipIfInputQuality(ctx, 'build'),\n preExecute: async (ctx) => {\n if (!ctx.input.dryRun) {\n try {\n const td = readTask(ctx.taskDir)\n if (td) {\n ensureFeatureBranch(ctx.taskId, td.task_type, undefined, ctx.taskDir)\n\n // Capture the branch name and persist to status.json for dashboard lookups\n try {\n const currentBranch = execFileSync('git', ['branch', '--show-current'], {\n encoding: 'utf-8',\n timeout: 10000, // 10 seconds\n }).trim()\n if (currentBranch) {\n const state = loadState(ctx.taskId)\n if (state) {\n setBranchName(ctx.taskId, state, currentBranch)\n }\n }\n } catch {\n // Non-critical — branch name is a convenience field\n }\n }\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error)\n throw new Error(`Build stage preExecute failed: ${msg}`)\n }\n }\n },\n postActions: [\n { type: 'validate-src-changes' },\n { type: 'validate-build-content' },\n // Commit code BEFORE quality gates so work is preserved even if gates fail.\n // Without this, a gate failure means all build agent work is lost.\n {\n type: 'commit-task-files',\n stagingStrategy: 'tracked+task',\n push: true,\n ensureBranch: true,\n },\n // Run lint:fix + format:fix mechanically BEFORE quality gates.\n // This is deterministic (no LLM needed) and prevents trivial format/lint\n // failures from reaching verify stage or wasting LLM fix attempts.\n { type: 'run-mechanical-autofix' },\n {\n type: 'run-quality-with-autofix',\n gates: [\n { name: 'TypeScript', command: 'pnpm -s tsc --noEmit', source: 'tsc' as const },\n // No unit test gate — test stage handles test validation\n ],\n maxFeedbackLoops: 2,\n },\n ],\n validator: createBuildValidator(),\n // No fallback for build stage — a missing build.md is a real failure.\n // The agent handler will retry or fail the stage explicitly.\n // Previously generated a degraded substitute from `git diff --name-only`,\n // which masked failures and gave downstream stages (review, verify) incomplete input.\n })\n\n // review stage - architect agent reviews generated code\n stages.set('review', {\n name: 'review',\n type: 'agent',\n timeout: getStageTimeout('review'),\n maxRetries: 0,\n minComplexity: getStageComplexityThreshold('review'),\n shouldSkip: (ctx) => {\n const complexitySkip = skipIfBelowComplexity(ctx, 'review')\n if (complexitySkip.shouldSkip) return complexitySkip\n return { shouldSkip: false }\n },\n postActions: [\n { type: 'analyze-review-findings' },\n { type: 'commit-task-files', stagingStrategy: 'task-only', push: true, ensureBranch: false },\n ],\n })\n\n // fix stage — re-invokes build agent to fix review findings\n // The build agent has full context (spec, plan, code intent) and wrote the code.\n stages.set('fix', {\n name: 'fix',\n type: 'agent',\n agentName: 'build', // Build agent fixes its own code based on review.md\n timeout: getStageTimeout('fix'),\n maxRetries: 1,\n shouldSkip: (ctx) => {\n // In fix mode, never skip — user explicitly requested fixes\n if (ctx.input.mode === 'fix') {\n return { shouldSkip: false }\n }\n const state = loadState(ctx.taskId)\n const fixStage = state?.stages?.fix\n if (\n fixStage?.fixAttempt !== undefined &&\n fixStage.fixAttempt >= (fixStage.maxFixAttempts ?? 2)\n ) {\n return { shouldSkip: true, reason: 'Max fix attempts reached' }\n }\n const reviewStage = state?.stages?.review\n if (!reviewStage?.issuesFound) {\n const verifyFailuresPath = path.join(ctx.taskDir, 'verify-failures.md')\n if (!fs.existsSync(verifyFailuresPath)) {\n return { shouldSkip: true, reason: 'No issues to fix' }\n }\n }\n return { shouldSkip: false }\n },\n postActions: [\n {\n type: 'commit-task-files',\n stagingStrategy: 'tracked+task',\n push: true,\n ensureBranch: false,\n },\n { type: 'clear-verify-failures' },\n ],\n })\n\n // commit stage\n stages.set('commit', {\n name: 'commit',\n type: 'git',\n timeout: getStageTimeout('commit'),\n maxRetries: 0,\n })\n\n // verify stage\n stages.set('verify', {\n name: 'verify',\n type: 'scripted',\n timeout: getStageTimeout('verify'),\n maxRetries: 0,\n // R2-FIX: Clear stale verify-failures.md before running verify.\n // Without this, a retry loop (verify→fix→verify) may process stale failures\n // from the previous attempt, causing the fix agent to work on wrong errors.\n preExecute: async (ctx) => {\n const failuresPath = path.join(ctx.taskDir, 'verify-failures.md')\n if (fs.existsSync(failuresPath)) {\n fs.unlinkSync(failuresPath)\n }\n },\n retryWith: {\n stage: 'fix',\n maxAttempts: DEFAULT_MAX_FIX_ATTEMPTS,\n onFailure: captureVerifyFailures,\n onTimeout: 'retry',\n },\n postActions: [\n // LOCAL-ONLY commit of task files after verify completes (G18)\n // NOT the autofix commit - that's inside ScriptedVerifyHandler\n {\n type: 'commit-task-files',\n stagingStrategy: 'task-only',\n push: false,\n ensureBranch: false,\n localOnly: true,\n },\n // Update knowledge base with patterns learned from this task\n // Non-blocking: executeUpdateKnowledgeBase handles errors gracefully\n { type: 'update-knowledge-base' },\n ],\n })\n\n // docs stage - deferred to nightly inspector (Knowledge Gardener plugin).\n // Kept here so the state machine can execute it if triggered directly (e.g., manual rerun).\n // Complexity threshold raised to 30 (moderate+) — trivial/simple tasks skip docs.\n stages.set('docs', {\n name: 'docs',\n type: 'agent',\n timeout: getStageTimeout('docs'),\n maxRetries: 1,\n minComplexity: getStageComplexityThreshold('docs'),\n shouldSkip: (ctx) => {\n const complexitySkip = skipIfBelowComplexity(ctx, 'docs')\n if (complexitySkip.shouldSkip) return complexitySkip\n return { shouldSkip: false }\n },\n validator: createDocsValidator(),\n postActions: [\n {\n type: 'commit-task-files',\n stagingStrategy: 'tracked+task',\n push: true,\n ensureBranch: false,\n },\n ],\n })\n\n // pr stage\n stages.set('pr', {\n name: 'pr',\n type: 'git',\n timeout: getStageTimeout('pr'),\n maxRetries: 0,\n })\n\n return stages\n}\n\n// ============================================================================\n// Pipeline Builder\n// ============================================================================\n\n/**\n * Rebuild pipeline after taskify completes\n * Extends the pipeline with remaining stages based on profile\n */\nexport function rebuildPipelineAfterTaskify(\n _currentPipeline: PipelineDefinition,\n ctx: PipelineContext,\n): PipelineDefinition {\n // For full mode, we need BOTH spec stages (completed) AND impl stages (to run)\n // Build spec stages based on profile\n const specOrder = ctx.profile === 'standard' ? SPEC_ORDER_STANDARD : SPEC_ORDER_LIGHTWEIGHT\n const filteredSpecOrder = ctx.input.clarify ? specOrder : specOrder.filter((s) => s !== 'clarify')\n\n // For spec_only pipelines, don't include impl stages — there's no plan.md to build from\n if (ctx.taskDef?.pipeline === 'spec_only') {\n return {\n stages: createStageDefinitions(ctx),\n order: [...filteredSpecOrder],\n }\n }\n\n // Build impl stages based on profile\n const implOrder = ctx.profile === 'standard' ? IMPL_ORDER_STANDARD : IMPL_ORDER_LIGHTWEIGHT\n\n // Combine: spec stages first (already completed), then impl stages (to run)\n return {\n stages: createStageDefinitions(ctx),\n order: [...filteredSpecOrder, ...implOrder],\n }\n}\n\n/**\n * Build pipeline definition based on mode, profile, and clarify flag\n */\nexport function buildPipeline(\n mode: 'spec' | 'impl' | 'full' | 'rerun',\n profile: 'standard' | 'lightweight' | 'turbo',\n clarify: boolean,\n ctx: PipelineContext,\n): PipelineDefinition {\n const stages = createStageDefinitions(ctx)\n\n // Determine stage order based on mode and profile\n let order: PipelineStep[] = []\n\n if (mode === 'spec') {\n // Spec stages only\n const specOrder =\n profile === 'standard'\n ? SPEC_ORDER_STANDARD\n : profile === 'turbo'\n ? SPEC_ORDER_TURBO\n : SPEC_ORDER_LIGHTWEIGHT\n // If clarify is disabled, remove it from the spec order\n const filteredSpecOrder = clarify ? specOrder : specOrder.filter((s) => s !== 'clarify')\n order = [...filteredSpecOrder]\n } else if (mode === 'impl') {\n // Implementation stages only\n const implOrder =\n profile === 'standard'\n ? IMPL_ORDER_STANDARD\n : profile === 'turbo'\n ? IMPL_ORDER_TURBO\n : IMPL_ORDER_LIGHTWEIGHT\n order = [...implOrder]\n } else if (mode === 'full' || mode === 'rerun') {\n // Full/rerun mode: include both spec and impl stages\n // This ensures the pipeline survives restarts — all stages are present\n // and the state machine efficiently skips completed ones\n const specOrder =\n profile === 'standard'\n ? SPEC_ORDER_STANDARD\n : profile === 'turbo'\n ? SPEC_ORDER_TURBO\n : SPEC_ORDER_LIGHTWEIGHT\n const implOrder =\n profile === 'standard'\n ? IMPL_ORDER_STANDARD\n : profile === 'turbo'\n ? IMPL_ORDER_TURBO\n : IMPL_ORDER_LIGHTWEIGHT\n const filteredSpecOrder = clarify ? specOrder : specOrder.filter((s) => s !== 'clarify')\n order = [...filteredSpecOrder, ...implOrder]\n }\n\n return { stages, order }\n}\n\n/**\n * Flatten pipeline order (including parallel stages) into a flat array of stage names\n */\nexport function flattenPipelineOrder(order: PipelineStep[]): StageName[] {\n const result: StageName[] = []\n for (const step of order) {\n if (typeof step === 'string') {\n result.push(step)\n } else if ('parallel' in step) {\n result.push(...step.parallel)\n }\n }\n return result\n}\n","/**\n * @fileType engine\n * @domain kody | engine\n * @pattern pipeline-resolver\n * @ai-summary Pipeline construction based on mode and profile\n */\n\nimport type { PipelineDefinition, PipelineContext } from '../engine/types'\nimport {\n buildPipeline,\n rebuildPipelineAfterTaskify as rebuildFromDefinitions,\n FIX_FULL_ORDER,\n} from '../pipeline/definitions'\n\n/**\n * Resolve pipeline for a given mode\n */\nexport function resolvePipelineForMode(\n mode: 'spec' | 'impl' | 'full' | 'rerun' | 'fix' | 'status',\n profile: 'standard' | 'lightweight' | 'turbo',\n clarify: boolean,\n ctx: PipelineContext,\n): PipelineDefinition {\n switch (mode) {\n case 'spec':\n case 'full':\n return buildPipeline(mode, profile, clarify, ctx)\n case 'impl':\n return buildPipeline('impl', profile, clarify, ctx)\n case 'rerun':\n // Rerun needs BOTH spec and impl stages to support resuming from any stage\n return buildPipeline('rerun', profile, clarify, ctx)\n case 'fix': {\n // Fix mode uses FIX_FULL_ORDER (taskify → architect → plan-gap → build → ... → pr)\n // This runs the full pipeline with previous artifacts as context\n const fixPipeline = buildPipeline('full', profile, clarify, ctx)\n return { stages: fixPipeline.stages, order: FIX_FULL_ORDER }\n }\n case 'status':\n // No pipeline for status mode\n return { stages: new Map(), order: [] }\n default:\n return buildPipeline('full', profile, clarify, ctx)\n }\n}\n\n/**\n * Rebuild pipeline after taskify completes\n * Extends the pipeline with remaining stages based on profile.\n *\n * Uses the dedicated rebuildPipelineAfterTaskify from definitions.ts\n * which correctly respects the resolved profile for spec stage order,\n * unlike buildPipeline('rerun') which always uses SPEC_ORDER_STANDARD.\n */\nexport function rebuildPipelineAfterTaskify(\n currentPipeline: PipelineDefinition,\n ctx: PipelineContext,\n): PipelineDefinition {\n return rebuildFromDefinitions(currentPipeline, ctx)\n}\n\n/**\n * Create rebuild callback for the engine\n */\nexport function createRebuildCallback(\n _mode: 'spec' | 'impl' | 'full' | 'rerun' | 'fix',\n _clarify: boolean,\n): (ctx: PipelineContext) => PipelineDefinition {\n return (ctx) => rebuildPipelineAfterTaskify({ stages: new Map(), order: [] }, ctx)\n}\n","/**\n * @fileType utility\n * @domain kody | observability | structured-logging\n * @pattern structured-logging | pipeline-events\n * @ai-summary Structured event logging for Kody pipeline observability\n */\n\nimport { logger } from './logger'\nimport type { StageName } from './stages/registry'\n\n/**\n * All pipeline event types for structured logging.\n * Use these as the `event` field in log calls for consistent event classification.\n */\nexport const PIPELINE_EVENTS = {\n // Pipeline lifecycle\n PIPELINE_START: 'pipeline:start',\n PIPELINE_COMPLETE: 'pipeline:complete',\n PIPELINE_FAIL: 'pipeline:fail',\n PIPELINE_TIMEOUT: 'pipeline:timeout',\n PIPELINE_PAUSE: 'pipeline:pause',\n\n // Stage lifecycle\n STAGE_START: 'stage:start',\n STAGE_COMPLETE: 'stage:complete',\n STAGE_SKIP: 'stage:skip',\n STAGE_FAIL: 'stage:fail',\n STAGE_RETRY: 'stage:retry',\n STAGE_TIMEOUT: 'stage:timeout',\n\n // Gate events\n GATE_WAIT: 'gate:wait',\n GATE_APPROVE: 'gate:approve',\n GATE_REJECT: 'gate:reject',\n\n // Post-action events\n POST_ACTION_START: 'post-action:start',\n POST_ACTION_COMPLETE: 'post-action:complete',\n POST_ACTION_FAIL: 'post-action:fail',\n\n // Recovery events\n RECOVERY_TRIGGERED: 'recovery:triggered',\n RECOVERY_COMPLETE: 'recovery:complete',\n} as const\n\nexport type PipelineEventType = (typeof PIPELINE_EVENTS)[keyof typeof PIPELINE_EVENTS]\n\n/**\n * Structured log a stage start event.\n */\nexport function logStageStart(stageName: StageName, taskId: string, attempt?: number): void {\n logger.info(\n { event: PIPELINE_EVENTS.STAGE_START, stage: stageName, taskId, attempt },\n `▶ Starting stage: ${stageName}`,\n )\n}\n\n/**\n * Structured log a stage completion event.\n */\nexport function logStageComplete(\n stageName: StageName,\n taskId: string,\n outcome: string,\n duration?: number,\n): void {\n logger.info(\n { event: PIPELINE_EVENTS.STAGE_COMPLETE, stage: stageName, taskId, outcome, duration },\n `✅ Completed stage: ${stageName} (${outcome})`,\n )\n}\n\n/**\n * Structured log a stage skip event.\n */\nexport function logStageSkip(stageName: StageName | string, taskId: string, reason?: string): void {\n logger.info(\n { event: PIPELINE_EVENTS.STAGE_SKIP, stage: stageName, taskId, reason },\n `⏭ Skipped stage: ${stageName}${reason ? ` (${reason})` : ''}`,\n )\n}\n\n/**\n * Structured log a stage failure event.\n */\nexport function logStageFail(\n stageName: StageName | string,\n taskId: string,\n error?: string,\n retry?: boolean,\n): void {\n logger.error(\n { event: PIPELINE_EVENTS.STAGE_FAIL, stage: stageName, taskId, error, retry },\n `❌ Failed stage: ${stageName}${error ? ` - ${error}` : ''}${retry ? ' (will retry)' : ''}`,\n )\n}\n\n/**\n * Structured log a stage retry event.\n */\nexport function logStageRetry(\n stageName: StageName | string,\n taskId: string,\n attempt: number,\n maxRetries: number,\n): void {\n logger.warn(\n { event: PIPELINE_EVENTS.STAGE_RETRY, stage: stageName, taskId, attempt, maxRetries },\n `🔄 Retrying stage: ${stageName} (attempt ${attempt}/${maxRetries})`,\n )\n}\n\n/**\n * Structured log a pipeline start event.\n */\nexport function logPipelineStart(taskId: string, mode: string, profile: string): void {\n logger.info(\n { event: PIPELINE_EVENTS.PIPELINE_START, taskId, mode, profile },\n `🚀 Pipeline started: ${taskId} (${mode}, ${profile})`,\n )\n}\n\n/**\n * Structured log a pipeline completion event.\n */\nexport function logPipelineComplete(taskId: string, duration?: number, totalCost?: number): void {\n logger.info(\n { event: PIPELINE_EVENTS.PIPELINE_COMPLETE, taskId, duration, totalCost },\n `✅ Pipeline completed: ${taskId}${duration ? ` (${duration}ms)` : ''}`,\n )\n}\n\n/**\n * Structured log a gate wait event.\n */\nexport function logGateWait(gateName: string, taskId: string): void {\n logger.info(\n { event: PIPELINE_EVENTS.GATE_WAIT, gate: gateName, taskId },\n `⏸ Waiting for gate: ${gateName}`,\n )\n}\n\n/**\n * Structured log a recovery action.\n */\nexport function logRecovery(stageName: StageName | string, taskId: string, reason: string): void {\n logger.info(\n { event: PIPELINE_EVENTS.RECOVERY_TRIGGERED, stage: stageName, taskId, reason },\n `🔧 Recovery triggered: ${stageName} - ${reason}`,\n )\n}\n\n/**\n * Structured log a post-action event.\n */\nexport function logPostAction(\n actionType: string,\n taskId: string,\n status: 'start' | 'complete' | 'fail',\n error?: string,\n): void {\n const event =\n status === 'start'\n ? PIPELINE_EVENTS.POST_ACTION_START\n : status === 'complete'\n ? PIPELINE_EVENTS.POST_ACTION_COMPLETE\n : PIPELINE_EVENTS.POST_ACTION_FAIL\n\n const logFn = status === 'fail' ? logger.error : status === 'start' ? logger.info : logger.info\n\n logFn(\n { event, actionType, taskId, error },\n `${status === 'start' ? '▶' : status === 'complete' ? '✅' : '❌'} Post-action [${actionType}]: ${status}${error ? ` - ${error}` : ''}`,\n )\n}\n","/**\n * @fileType utility\n * @domain ci | kody | prompts\n * @pattern stage-prompts\n * @ai-summary Stage runtime context for OpenCode agents — behavioral instructions live in .opencode/agents/*.md\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { KodyInput } from './kody-utils'\nimport {\n getStageContextFiles,\n stageOutputFile,\n isValidStageName,\n SPEC_ORDER_STANDARD,\n SPEC_ORDER_LIGHTWEIGHT,\n flattenTypedPipeline,\n IMPL_ORDER_STANDARD,\n IMPL_ORDER_LIGHTWEIGHT,\n} from './stages/registry'\n\n// Re-export for backward compatibility\nexport { SPEC_STAGES, SCRIPTED_STAGES } from './stages/registry'\n\n// ============================================================================\n// Stage Context — which files each stage needs to read\n// ============================================================================\n\n// ============================================================================\n// Stage Instructions — runtime context ONLY (not behavioral)\n//\n// Behavioral instructions (how to act, output format, rules) live in\n// .opencode/agents/<stage>.md. These instructions provide ONLY:\n// - Spec-only guard (don't modify code)\n// - Stage-specific runtime context hints (e.g., \"this is a rerun\")\n// ============================================================================\n\n// Use absolute path to avoid OpenCode path interpretation issues with task IDs containing hyphens\nconst specOnlyInstructionTemplate = (taskDir: string) =>\n `CRITICAL: This is a SPEC-ONLY pipeline. DO NOT create branches, commits, or pull requests. DO NOT modify any code files. Only read from and write to the ${taskDir}/ directory.`\n\nexport const stageInstructions: Record<string, (taskId: string) => string> = {\n taskify: (taskId) => {\n const taskDir = path.join(process.cwd(), '.tasks', taskId)\n return specOnlyInstructionTemplate(taskDir)\n },\n\n gap: (taskId) => {\n const taskDir = path.join(process.cwd(), '.tasks', taskId)\n return specOnlyInstructionTemplate(taskDir)\n },\n\n clarify: (taskId) => {\n const taskDir = path.join(process.cwd(), '.tasks', taskId)\n return specOnlyInstructionTemplate(taskDir)\n },\n\n architect: () => ``,\n\n 'plan-gap': () => ``,\n\n test: () => `TDD RED PHASE: Write failing tests from the plan.\nYou run in PARALLEL with the build agent. Write tests to tests/ ONLY.\nDo NOT modify src/. Do NOT run tests (they will fail without implementation).`,\n\n build: () => `CRITICAL: IMPLEMENTATION STAGE - NOT DOCUMENTATION ONLY\n\nYou must ACTUALLY IMPLEMENT the code changes, not just document them.\n\nYour job is to:\n1. Use Edit/Write tools to modify source files in src/\n2. Create new files as needed\n3. Run tests to verify\n4. **MUST write build.md** summarizing what was implemented before exiting\n\nThe build.md file format:\n- Must include a ## Changes or ## Files section (required by pipeline validation)\n- Should be a SUMMARY of what was implemented\n- Write it to: .tasks/<taskId>/build.md\n\nExample format:\n\\`\\`\\`markdown\n# Build Summary\n\n## Changes\n- Created src/infra/utils/pipeline-health.ts\n- Added PipelineHealthReport class\n- Added integration tests\n\n## Files\n- src/infra/utils/pipeline-health.ts\n- tests/unit/infra/utils/pipeline-health.test.ts\n\\`\\`\\`\n\nDO NOT skip writing build.md - the pipeline REQUIRES this file!`,\n\n commit: () => ``,\n\n review: () => `CRITICAL: CODE REVIEW + SPEC SATISFACTION STAGE\n\nYou are reviewing already-generated code AND verifying spec satisfaction. DO NOT modify code files.\n\nYour #1 job is the GOAL-BACKWARD SPEC CHECK: for every requirement in spec.md, verify there is matching code.\nYour #2 job is standard code review (security, correctness, quality).\nNOTE: Tests are written separately via the deferred-tests inspector plugin. Do NOT flag missing tests as issues.\n\nProduce review.md with a Spec Satisfaction matrix (requirement → code location → status) FIRST, then code quality findings.\nIf ANY spec requirement has no corresponding code: mark as Critical issue.`,\n\n fix: () => `CRITICAL: TARGETED FIX STAGE\n\nYou are applying MINIMAL fixes to resolve identified issues.\nDO NOT regenerate entire codebase.\nDO NOT refactor or rewrite working code.\nOnly fix the specific issues identified in verify-failures.md, review.md, or rerun-feedback.md.\n\nFor fix_bug tasks: follow the SCIENTIFIC DEBUG PROTOCOL in your agent instructions.\nHypothesis first, reproduction test second, minimal fix third.\n\nIMPORTANT: If review.md lists many issues (dozens+), focus on the CRITICAL issues first, then MAJOR issues.\nDo NOT try to fix every single issue — prioritize the most impactful ones.\nThe goal is to make the code substantially better, not perfectly bug-free.\nWrite fix-summary.md summarizing what you changed.`,\n\n // Scripted stages — these prompts are never sent to an LLM\n verify: () => ``,\n autofix: () => ``,\n docs: () => `DOCUMENTATION STAGE\n\nYou are updating project documentation based on task changes.\nDO NOT modify source code files — only documentation files (.md, .json indexes).\nWrite docs.md as your output summarizing documentation changes.`,\n pr: () => ``,\n}\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Read task_type from task.json for the given task.\n * Returns 'implement_feature' as default if task.json doesn't exist or is invalid.\n */\nfunction getTaskType(taskId: string): string {\n const taskJsonPath = path.join(process.cwd(), '.tasks', taskId, 'task.json')\n try {\n if (fs.existsSync(taskJsonPath)) {\n const content = fs.readFileSync(taskJsonPath, 'utf-8')\n const data = JSON.parse(content)\n if (data.task_type && typeof data.task_type === 'string') {\n return data.task_type\n }\n }\n } catch {\n // Ignore errors, return default\n }\n return 'implement_feature'\n}\n\n/**\n * Build the prompt for a given stage.\n * @param input - Orchestrator input with taskId\n * @param stage - The stage to build the prompt for\n * @param feedback - Optional feedback from a previous validation failure to include in the prompt\n * @returns The complete prompt string to pass to the agent\n */\nexport function buildStagePrompt(input: KodyInput, stage: string, feedback?: string): string {\n const { taskId } = input\n // Use absolute path to avoid OpenCode path interpretation issues with task IDs containing hyphens\n const taskDir = path.join(process.cwd(), '.tasks', taskId)\n\n // Get task_type for stages that need it (architect, build)\n const taskType = getTaskType(taskId)\n\n const instructionFn = stageInstructions[stage]\n const instruction = instructionFn ? instructionFn(taskId) : ''\n\n // Build file list for this stage\n const contextFiles = isValidStageName(stage) ? getStageContextFiles(stage) : []\n const fileList = contextFiles.map((f) => `- ${taskDir}/${f}`).join('\\n')\n\n const filesSection =\n contextFiles.length > 0\n ? `\\nRead these files for context:\\n${fileList}`\n : ''\n\n // Add task_type for stages that need it (architect, build)\n const taskTypeSection =\n stage === 'architect' || stage === 'build' ? `\\nTask Type: ${taskType}` : ''\n\n const outputFile = stageOutputFile(taskDir, stage)\n\n // Add feedback section if provided\n const feedbackSection = feedback\n ? `\\n⚠️ VALIDATION ERROR FROM PREVIOUS ATTEMPT:\\n${feedback}\\n\\nPlease fix this in your next attempt.`\n : ''\n\n const parts = [\n instruction,\n `Task ID: ${taskId}`,\n taskTypeSection,\n filesSection,\n feedbackSection,\n `Write your output to ${outputFile}`,\n ].filter(Boolean)\n\n return parts.join('\\n\\n')\n}\n\n/**\n * Get spec pipeline stages (taskify, gap — without clarify by default)\n * @param profile - Optional pipeline profile ('lightweight' | 'standard'), defaults to 'standard'\n */\nexport function getSpecStages(profile?: 'lightweight' | 'standard'): string[] {\n const order = profile === 'lightweight' ? SPEC_ORDER_LIGHTWEIGHT : SPEC_ORDER_STANDARD\n // Default: exclude clarify (backward compat with old getSpecStagesForProfile(profile, false))\n return order.filter((s) => s !== 'clarify')\n}\n\n/**\n * Get implementation pipeline stages\n * @param profile - Optional pipeline profile ('lightweight' | 'standard'), defaults to 'standard'\n */\nexport function getImplStages(profile?: 'lightweight' | 'standard'): string[] {\n return flattenTypedPipeline(\n profile === 'lightweight' ? IMPL_ORDER_LIGHTWEIGHT : IMPL_ORDER_STANDARD,\n )\n}\n","/**\n * @fileType configuration\n * @domain ci | kody | agent-execution\n * @pattern constants\n * @ai-summary Agent runner constants — timeouts, retry limits, buffer sizes\n */\n\nimport ms from 'ms'\n\n/** Delay between stability checks after process exit (milliseconds) */\nexport const STABILITY_CHECK_INTERVAL = 500\n\n/** Number of consecutive stable size checks before settling */\nexport const STABILITY_CHECK_COUNT = 2\n\n/** Additional delay to wait after process exit before checking (filesystem flush) */\nexport const POST_EXIT_DELAY = 500\n\n/** Timeout for session nudge attempt (seconds) — lightweight continuation before full retry */\nexport const NUDGE_TIMEOUT = 90\n\n/** Maximum retry attempts for failed stages */\nexport const MAX_RETRIES = 2\n\n/** Maximum size of stdout buffer to prevent memory leaks (1 MB) */\nexport const MAX_STDOUT_BUFFER_SIZE = 1_048_576\n\n/** Default timeout for stages (10 minutes) */\nexport const DEFAULT_TIMEOUT = ms('10m')\n\n/** LLM-specific timeout - max time to wait for LLM API response (3 minutes) */\nexport const LLM_TIMEOUT = ms('3m')\n\n/** Stall detection: if no stdout events for this many ms, kill and retry the agent.\n * Prevents wasting the full stage timeout when the LLM API hangs silently. */\nexport const STALL_TIMEOUT = ms('5m')\n","/**\n * @fileType utility\n * @domain ci | kody | agent-execution\n * @pattern file-watcher\n * @ai-summary File watching and stability checking for agent output detection\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport ms from 'ms'\n\nimport { STABILITY_CHECK_INTERVAL, STABILITY_CHECK_COUNT } from './constants'\n\n/**\n * Wait for a file to become stable (size doesn't change for N consecutive checks).\n * This handles filesystem flush delays after the agent process exits.\n *\n * @param filePath - Path to the file to check\n * @param options - Stability check configuration\n * @returns Promise that resolves when file is stable, or rejects on timeout/error\n */\nexport async function waitForFileStable(\n filePath: string,\n options: {\n interval?: number\n stableCount?: number\n timeout?: number\n onCheck?: (size: number, checkNumber: number) => void\n } = {},\n): Promise<{ stable: boolean; finalSize: number }> {\n const {\n interval = STABILITY_CHECK_INTERVAL,\n stableCount = STABILITY_CHECK_COUNT,\n timeout = ms('30s'),\n onCheck,\n } = options\n\n const startTime = Date.now()\n let lastSize = 0\n let stableCheckCount = 0\n\n while (true) {\n // Check timeout\n if (Date.now() - startTime > timeout) {\n return { stable: false, finalSize: lastSize }\n }\n\n // Check if file exists\n if (!fs.existsSync(filePath)) {\n stableCheckCount = 0\n lastSize = 0\n await sleep(interval)\n continue\n }\n\n // Get current file size\n const stat = fs.statSync(filePath)\n const currentSize = stat.size\n\n if (onCheck) {\n onCheck(currentSize, stableCheckCount)\n }\n\n // Check if size is stable (skip first check - we need 2 consecutive stable checks)\n if (currentSize > 0 && currentSize === lastSize) {\n stableCheckCount++\n if (stableCheckCount >= stableCount) {\n return { stable: true, finalSize: currentSize }\n }\n } else {\n stableCheckCount = 0\n }\n\n lastSize = currentSize\n await sleep(interval)\n }\n}\n\n/**\n * Simple sleep utility\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n/**\n * Find output file in directory (supports timestamped variants like spec-123456.md)\n */\nexport function findOutputFile(\n taskDir: string,\n expectedBase: string,\n outputExt: string,\n): string | null {\n if (fs.existsSync(path.join(taskDir, expectedBase + outputExt))) {\n return path.join(taskDir, expectedBase + outputExt)\n }\n\n // Check for timestamped variants\n const files = fs.readdirSync(taskDir)\n const prefixMatch = files.find((f) => f.startsWith(expectedBase + '-') && f.endsWith(outputExt))\n return prefixMatch ? path.join(taskDir, prefixMatch) : null\n}\n","/**\n * @fileType utility\n * @domain ci | kody | agent-execution\n * @pattern log-parser\n * @ai-summary Parses JSON event lines from opencode into human-readable log output\n */\n\n/**\n * Format a JSON event line from opencode into a human-readable log line.\n * Returns the formatted string, or null to skip (for noisy/unimportant events).\n * Also extracts sessionID from events when found.\n */\nexport function formatJsonEvent(line: string): {\n display: string | null\n sessionId?: string\n stepTokens?: { input: number; output: number; cacheRead: number }\n stepCost?: number\n completed?: boolean\n} {\n try {\n const event = JSON.parse(line)\n const type: string = event.type\n const sessionId: string | undefined = event.sessionID\n\n switch (type) {\n case 'session_start':\n return { display: `🎯 Session started: ${sessionId?.slice(0, 16) || 'unknown'}`, sessionId }\n\n case 'step_start':\n return { display: null, sessionId } // Quiet — step_finish is more useful\n\n case 'step_finish': {\n const tokens = event.part?.tokens?.total || 0\n const cost = event.part?.cost ?? 0\n const reason = event.part?.reason || ''\n const cached = event.part?.tokens?.cache?.read || 0\n const inputTokens = event.part?.tokens?.input || 0\n const outputTokens = event.part?.tokens?.output || 0\n const costStr = typeof cost === 'number' && cost > 0 ? ` · $${cost.toFixed(4)}` : ''\n const cacheStr = cached > 0 ? ` · ${cached} cached` : ''\n const isCompletion = reason === 'stop'\n return {\n display: ` ✅ Step done (${tokens} tok${cacheStr}${costStr}) [${reason}]`,\n sessionId,\n stepTokens: { input: inputTokens, output: outputTokens, cacheRead: cached },\n stepCost: typeof cost === 'number' ? cost : 0,\n completed: isCompletion,\n }\n }\n\n case 'tool_use': {\n const tool = event.part?.tool || 'unknown'\n const status = event.part?.state?.status || ''\n const title = event.part?.state?.title || event.part?.state?.input?.description || ''\n const exit = event.part?.state?.metadata?.exit\n const exitStr = exit !== undefined && exit !== 0 ? ` exit=${exit}` : ''\n const titleStr = title ? `: ${title}` : ''\n if (status === 'completed') {\n return { display: ` 🔧 ${tool}${titleStr}${exitStr}`, sessionId }\n }\n return { display: null, sessionId } // Skip pending/running states\n }\n\n case 'text': {\n // Agent reasoning — complete thought blocks (not char-by-char deltas)\n // Typically 6-17 per stage, ~100-200 chars each — not noisy\n const text = (event.part?.text || '').trim()\n if (!text) return { display: null, sessionId }\n const truncated = text.length > 300 ? text.slice(0, 297) + '...' : text\n return { display: ` 💭 ${truncated}`, sessionId }\n }\n\n case 'text_delta':\n case 'content':\n return { display: null, sessionId } // Skip streaming text deltas (too noisy)\n\n case 'error': {\n const msg = event.part?.message || event.message || JSON.stringify(event.part)\n return { display: ` 🔴 Error: ${msg}`, sessionId }\n }\n\n default:\n return { display: null, sessionId } // Skip unknown event types\n }\n } catch {\n // Not valid JSON — might be a plain log line from pino/logger\n // Show it as-is if it looks meaningful\n const trimmed = line.trim()\n if (!trimmed) return { display: null }\n return { display: trimmed }\n }\n}\n\n/**\n * Format a timestamp as HH:MM:SS for log prefixing.\n */\nexport function formatTimestamp(): string {\n const now = new Date()\n return [now.getHours(), now.getMinutes(), now.getSeconds()]\n .map((n) => String(n).padStart(2, '0'))\n .join(':')\n}\n\n/**\n * Prefix a display line with [stage HH:MM:SS] for log context.\n */\nexport function prefixLogLine(stage: string, display: string): string {\n return `[${stage} ${formatTimestamp()}] ${display.trimStart()}`\n}\n","/**\n * @fileType utility\n * @domain ci | kody | agent-execution\n * @pattern session-management\n * @ai-summary Session recovery and nudge logic for agent continuation\n */\n\nimport * as path from 'path'\nimport { execFileSync } from 'child_process'\n\nimport { logger } from '../logger'\nimport type { RunnerBackend } from '../runner-backend'\nimport { resolveOpenCodeBinary } from '../opencode-server'\nimport { NUDGE_TIMEOUT, POST_EXIT_DELAY } from './constants'\nimport { findOutputFile, sleep } from './file-watcher'\n\n/**\n * Recover the latest session ID from OpenCode's database when JSON events\n * didn't include sessionID (e.g., some model providers omit it).\n * Uses `opencode session list` to query the local SQLite DB.\n */\nexport function recoverSessionId(dataDir?: string): string | undefined {\n if (!dataDir) return undefined\n\n try {\n const binary = resolveOpenCodeBinary()\n const output = execFileSync(binary, ['session', 'list', '--format', 'json', '-n', '1'], {\n encoding: 'utf-8',\n timeout: 10_000,\n env: { ...process.env, XDG_DATA_HOME: dataDir },\n })\n\n const sessions = JSON.parse(output)\n if (Array.isArray(sessions) && sessions.length > 0 && sessions[0].id) {\n logger.info(` 🔍 Recovered session ID from DB: ${sessions[0].id.slice(0, 16)}...`)\n return sessions[0].id\n }\n } catch (err) {\n logger.debug({ err }, 'Failed to recover session ID from OpenCode DB')\n }\n return undefined\n}\n\n/**\n * Nudge an agent session to write the missing output file.\n * When an agent exits 0 but forgets the output file, this sends a short\n * continuation message into the same session. Much cheaper than a full retry\n * since the agent still has all context loaded.\n *\n * Returns the detected output file path on success, or null on failure.\n */\nexport async function nudgeSession(\n backend: RunnerBackend,\n stage: string,\n outputFile: string,\n env: NodeJS.ProcessEnv,\n cwd: string,\n serverUrl: string,\n sessionId: string,\n dataDir?: string,\n): Promise<string | null> {\n const nudgePrompt = `CRITICAL: You exited without writing the required output file. Write it NOW to: ${outputFile}`\n\n logger.info(` 🔔 Nudging session ${sessionId.slice(0, 16)}... to write output file`)\n\n return new Promise((resolve) => {\n const nudgeChild = backend.spawn(stage, nudgePrompt, env, cwd, {\n serverUrl,\n sessionId,\n dataDir,\n })\n\n // Close stdin\n if (nudgeChild.stdin) nudgeChild.stdin.end()\n\n // Log nudge output for debugging\n if (nudgeChild.stdout) {\n nudgeChild.stdout.on('data', () => {\n // Silently consume — we only care about the file appearing\n })\n }\n if (nudgeChild.stderr) {\n nudgeChild.stderr.on('data', () => {\n // Silently consume\n })\n }\n\n // Timeout\n // R2-FIX #12: Use the smaller of NUDGE_TIMEOUT and remaining stage timeout.\n // Without this, a stuck nudge could cause the stage to exceed its overall timeout.\n const nudgeTimeoutMs = NUDGE_TIMEOUT * 1000\n const timer = setTimeout(() => {\n logger.info(` 🔔 Nudge timed out after ${NUDGE_TIMEOUT}s`)\n try {\n nudgeChild.kill()\n } catch {\n /* ignore */\n }\n resolve(null)\n }, nudgeTimeoutMs)\n\n nudgeChild.on('exit', async (nudgeCode) => {\n clearTimeout(timer)\n logger.info(` 🔔 Nudge process exited with code: ${nudgeCode}`)\n\n // Brief delay for filesystem flush\n await sleep(POST_EXIT_DELAY)\n\n // Check if the file appeared\n const outputExt = path.extname(outputFile)\n const expectedBase = path.basename(outputFile, outputExt)\n const taskDirForPoll = path.dirname(outputFile)\n const detected = findOutputFile(taskDirForPoll, expectedBase, outputExt)\n if (detected) {\n logger.info(` 🔔 ✅ Nudge succeeded — output file detected`)\n resolve(detected)\n } else {\n logger.info(` 🔔 ❌ Nudge failed — output file still missing`)\n resolve(null)\n }\n })\n })\n}\n","/**\n * @fileType utility\n * @domain ci | kody | agent-execution\n * @pattern agent-runner\n * @ai-summary Agent execution orchestrator — spawns agents, monitors output, handles retries.\n * File watching, session management, and log parsing are in agent/ submodules.\n */\n\nimport type { ChildProcess } from 'child_process'\nimport * as fs from 'fs'\nimport ms from 'ms'\nimport * as path from 'path'\n\nimport type { KodyInput } from './kody-utils'\nimport { buildStagePrompt } from './stage-prompts'\nimport { createRunner, type RunnerBackend } from './runner-backend'\nimport { logger } from './logger'\nimport { STDERR_TAIL_LINES } from './config/constants'\n\n// Re-export split modules for backward compatibility\nexport {\n STABILITY_CHECK_INTERVAL,\n STABILITY_CHECK_COUNT,\n POST_EXIT_DELAY,\n NUDGE_TIMEOUT,\n MAX_RETRIES,\n MAX_STDOUT_BUFFER_SIZE,\n DEFAULT_TIMEOUT,\n LLM_TIMEOUT,\n STALL_TIMEOUT,\n} from './agent/constants'\nexport { waitForFileStable } from './agent/file-watcher'\nexport { formatJsonEvent } from './agent/log-parser'\n\n// Import from split modules for internal use\nimport {\n MAX_RETRIES,\n MAX_STDOUT_BUFFER_SIZE,\n DEFAULT_TIMEOUT,\n STABILITY_CHECK_INTERVAL,\n STABILITY_CHECK_COUNT,\n POST_EXIT_DELAY,\n STALL_TIMEOUT,\n} from './agent/constants'\nimport { waitForFileStable, findOutputFile, sleep } from './agent/file-watcher'\nimport { recoverSessionId, nudgeSession } from './agent/session'\nimport { formatJsonEvent, prefixLogLine } from './agent/log-parser'\n\n// ============================================================================\n// Model Resolution\n// ============================================================================\n\n/** Cache for opencode.json model config */\nlet opencodeConfigCache: { agent?: Record<string, { model?: string }> } | null = null\n\n/**\n * Get the model name for a stage from opencode.json\n */\nfunction getStageModel(stage: string): string {\n if (!opencodeConfigCache) {\n try {\n const configPath = path.resolve(process.cwd(), 'opencode.json')\n if (fs.existsSync(configPath)) {\n opencodeConfigCache = JSON.parse(fs.readFileSync(configPath, 'utf-8'))\n }\n } catch {\n opencodeConfigCache = {}\n }\n }\n return opencodeConfigCache?.agent?.[stage]?.model ?? 'unknown'\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Result of content validation after agent produces output\n */\nexport interface ValidationResult {\n /** Whether the output is valid */\n valid: boolean\n /** Error message if validation failed (for feedback to agent on retry) */\n error?: string\n}\n\nexport interface AgentRunnerOptions {\n /** Custom stage timeouts (merges with defaults) */\n stageTimeouts?: Record<string, number>\n /** Custom default timeout */\n defaultTimeout?: number\n /** Maximum retry attempts (0 = no retries) */\n maxRetries?: number\n /** Additional environment variables */\n env?: NodeJS.ProcessEnv\n /** Working directory */\n cwd?: string\n /** Runner backend (defaults to auto-detect from GITHUB_ACTIONS env) */\n backend?: RunnerBackend\n /** Content validation function to run after output file is detected.\n * On validation failure, the output file is deleted and the agent is retried with the error in the prompt. */\n validateOutput?: (outputFile: string) => ValidationResult\n /** URL of running OpenCode server (for --attach mode) */\n serverUrl?: string\n /** Session ID to fork from (for session continuation) */\n sessionId?: string\n /** XDG_DATA_HOME directory for OpenCode server mode (must match server's data dir) */\n dataDir?: string\n /** Override agent name (for stages that use a different agent, e.g., fix stage uses build agent) */\n agentName?: string\n}\n\nexport interface AgentRunResult {\n succeeded: boolean\n timedOut: boolean\n retries: number\n /** Validation errors from failed content validation attempts */\n validationErrors?: string[]\n /** Session ID from opencode for chat history capture */\n sessionId?: string\n /** Accumulated token usage across all steps */\n tokenUsage?: { input: number; output: number; cacheRead: number }\n /** Accumulated cost in USD across all steps */\n cost?: number\n}\n\n// ============================================================================\n// Main Runner\n// ============================================================================\n\n/**\n * Run an OpenCode agent with file watching, timeouts, and optional retry logic.\n *\n * This function spawns the `opencode github run` command and monitors for the\n * output file. It handles:\n * - Wait for process exit, then check for stable output file (no continuous polling)\n * - Timeout enforcement\n * - Retry on failure (configurable)\n * - Process cleanup on completion\n * - Content validation with retry on failure\n *\n * @param input - Orchestrator input with taskId\n * @param stage - The stage to run (e.g., 'build', 'test')\n * @param outputFile - Expected output file path\n * @param timeout - Timeout in milliseconds (defaults to stage-specific or 10min)\n * @param options - Optional configuration\n * @returns Promise resolving to success/timedOut/retries\n */\nexport function runAgentWithFileWatch(\n input: KodyInput,\n stage: string,\n outputFile: string,\n timeout?: number,\n options: AgentRunnerOptions = {},\n): Promise<AgentRunResult> {\n const {\n maxRetries = MAX_RETRIES,\n env: extraEnv = {},\n cwd = process.cwd(),\n backend = createRunner(),\n validateOutput,\n serverUrl,\n sessionId,\n dataDir,\n agentName,\n } = options\n\n // Resolve timeout — stage-specific timeouts are now passed from StageDefinition\n const effectiveTimeout = timeout ?? DEFAULT_TIMEOUT\n\n // Use agentName override if provided, otherwise use stage\n const effectiveAgent = agentName ?? stage\n\n return new Promise((resolve) => {\n // Build environment for the agent\n const agentEnv = {\n ...process.env,\n ...extraEnv,\n // Skip Next.js build in pre-push hook — CI uses scripted verify (no build)\n SKIP_BUILD: '1',\n // Skip husky hooks for all pipeline stages - the pipeline runs its own quality gates\n // before committing, so pre-commit hooks would be redundant and could cause issues\n SKIP_HOOKS: '1',\n }\n\n let retries = 0\n const validationErrors: string[] = []\n let currentChild: ChildProcess | null = null\n const startTime = Date.now()\n\n const attemptWithRetry = (feedback?: string): void => {\n logger.info(` Attempt ${retries + 1}/${maxRetries + 1}`)\n\n // FIX #2: Delete stale output files before retry to prevent agent confusion\n // The agent might see old output and think work is already done\n if (retries > 0 && fs.existsSync(outputFile)) {\n fs.unlinkSync(outputFile)\n logger.info(` 🗑️ Deleted stale output file before retry`)\n }\n\n // FIX #10: Calculate remaining timeout (subtract elapsed time from ALL previous attempts).\n // startTime is captured once before the first attempt, so elapsed accurately reflects\n // total time spent across all retries including inter-retry delays.\n const elapsed = Date.now() - startTime\n const remainingTimeout = effectiveTimeout - elapsed\n if (remainingTimeout <= 0) {\n logger.info(\n ` ⏱️ No time remaining after ${retries} retries (${Math.round(elapsed / 1000)}s elapsed)`,\n )\n resolve({ succeeded: false, timedOut: true, retries, validationErrors })\n return\n }\n if (remainingTimeout < 60_000 && retries > 0) {\n logger.warn(\n ` ⚠️ Only ${Math.round(remainingTimeout / 1000)}s remaining for attempt ${retries + 1}`,\n )\n }\n\n // Build the prompt for the stage (rebuilt each attempt to include feedback)\n const prompt = buildStagePrompt(input, stage, feedback)\n\n // Log the model being used for this stage\n const model = getStageModel(stage)\n logger.info(` 🤖 Running ${stage} with model: ${model}`)\n\n // Spawn using the configured backend (local or GitHub)\n // Use effectiveAgent for the --agent flag (may be overridden via agentName option)\n currentChild = backend.spawn(effectiveAgent, prompt, agentEnv, cwd, {\n serverUrl,\n sessionId,\n dataDir,\n })\n\n // Explicitly close stdin to prevent opencode from waiting for input\n if (currentChild.stdin) {\n currentChild.stdin.end()\n }\n\n let resolved = false\n let timeoutTimer: NodeJS.Timeout | null = null\n let stallTimer: NodeJS.Timeout | null = null\n let stdoutBuffer = ''\n let extractedSessionId: string | undefined\n let hasCompleted = false // Track if we've detected completion via step_finish event\n const accumulatedTokens = { input: 0, output: 0, cacheRead: 0 }\n let accumulatedCost = 0\n // Write raw JSON events to artifact file for full debugging\n let jsonLogFd: number | null = null\n try {\n const jsonLogPath = path.join(path.dirname(outputFile), `${stage}-events.jsonl`)\n jsonLogFd = fs.openSync(jsonLogPath, 'w')\n } catch {\n // Non-fatal: skip artifact file if can't create\n }\n\n // Stderr capture for failure debugging\n let stderrLineCount = 0\n const stderrTailLines: string[] = [] // Rolling buffer of last N lines\n const STDERR_TAIL_SIZE = STDERR_TAIL_LINES\n let stderrLogFd: number | null = null\n try {\n const stderrLogPath = path.join(path.dirname(outputFile), `${stage}-stderr.log`)\n stderrLogFd = fs.openSync(stderrLogPath, 'w')\n } catch {\n // Non-fatal: skip stderr file if can't create\n }\n\n // Register cleanup handler to prevent FD leak on unexpected exit\n const cleanupFd = () => {\n if (jsonLogFd !== null) {\n try {\n fs.closeSync(jsonLogFd)\n } catch {\n /* ignore */\n }\n jsonLogFd = null\n }\n if (stderrLogFd !== null) {\n try {\n fs.closeSync(stderrLogFd)\n } catch {\n /* ignore */\n }\n stderrLogFd = null\n }\n }\n process.on('exit', cleanupFd)\n\n // Handle stdout - parse JSON events and display formatted output\n if (currentChild.stdout) {\n currentChild.stdout.on('data', (data: Buffer) => {\n const chunk = data.toString()\n stdoutBuffer += chunk\n\n // Reset stall timer on any stdout activity\n resetStallTimer()\n\n // Process line by line (JSON events are one per line)\n const lines = stdoutBuffer.split('\\n')\n stdoutBuffer = lines.pop() || '' // Keep incomplete line in buffer\n\n for (const line of lines) {\n if (!line.trim()) continue\n\n // Write raw JSON to artifact file for debugging\n if (jsonLogFd !== null) {\n fs.writeSync(jsonLogFd, line + '\\n')\n }\n\n // Parse and format for human-readable output\n const result = formatJsonEvent(line)\n\n // Extract sessionId from first event that has it\n if (result.sessionId && !extractedSessionId) {\n extractedSessionId = result.sessionId\n }\n\n // Accumulate token/cost data from step_finish events\n if (result.stepTokens) {\n accumulatedTokens.input += result.stepTokens.input\n accumulatedTokens.output += result.stepTokens.output\n accumulatedTokens.cacheRead += result.stepTokens.cacheRead\n }\n if (result.stepCost) {\n accumulatedCost += result.stepCost\n }\n\n // Display formatted output\n if (result.display) {\n process.stderr.write(prefixLogLine(stage, result.display) + '\\n')\n }\n\n // R2-FIX #13: Detect completion via step_finish event.\n // This fixes the hang in fork mode where process never exits.\n // When we detect completion, call finish() to trigger file detection,\n // nudge logic, and retry - all the fallback logic that normally runs\n // in the exit handler.\n if (result.completed && !hasCompleted && !resolved) {\n hasCompleted = true\n logger.info(` 🎯 Agent signaled completion via event, triggering finish...`)\n // Call finish with succeeded=true - it handles all the fallback logic\n finish({ succeeded: true, timedOut: false })\n }\n }\n\n // FIX #5: Cap buffer size to prevent memory leaks on verbose agents.\n // When the buffer exceeds MAX, discard the oldest data and keep the most\n // recent MAX/2 bytes, breaking at a newline boundary for clean parsing.\n if (stdoutBuffer.length > MAX_STDOUT_BUFFER_SIZE) {\n const keepFrom = stdoutBuffer.length - MAX_STDOUT_BUFFER_SIZE / 2\n const nextNewline = stdoutBuffer.indexOf('\\n', keepFrom)\n stdoutBuffer =\n nextNewline > 0 ? stdoutBuffer.slice(nextNewline + 1) : stdoutBuffer.slice(keepFrom)\n }\n })\n }\n\n // Handle stderr - write to file, surface on failure\n if (currentChild.stderr) {\n let stderrBuffer = ''\n currentChild.stderr.on('data', (data: Buffer) => {\n const chunk = data.toString()\n stderrBuffer += chunk\n\n const lines = stderrBuffer.split('\\n')\n stderrBuffer = lines.pop() || ''\n\n for (const line of lines) {\n if (!line.trim()) continue\n stderrLineCount++\n\n // Write to file\n if (stderrLogFd !== null) {\n try {\n fs.writeSync(stderrLogFd, line + '\\n')\n } catch {\n /* ignore */\n }\n }\n\n // Keep rolling tail buffer\n stderrTailLines.push(line)\n if (stderrTailLines.length > STDERR_TAIL_SIZE) {\n stderrTailLines.shift()\n }\n }\n })\n }\n\n const finish = (result: { succeeded: boolean; timedOut: boolean }) => {\n if (resolved) return\n resolved = true\n\n if (timeoutTimer) clearTimeout(timeoutTimer)\n if (stallTimer) clearTimeout(stallTimer)\n\n // Flush remaining stdout buffer\n if (stdoutBuffer.trim()) {\n if (jsonLogFd !== null) {\n fs.writeSync(jsonLogFd, stdoutBuffer + '\\n')\n }\n const lastResult = formatJsonEvent(stdoutBuffer)\n if (lastResult.sessionId && !extractedSessionId) {\n extractedSessionId = lastResult.sessionId\n }\n if (lastResult.display) {\n process.stderr.write(prefixLogLine(stage, lastResult.display) + '\\n')\n }\n }\n\n // Kill process if still running\n if (currentChild && !currentChild.killed) {\n currentChild.kill('SIGTERM')\n setTimeout(() => {\n if (currentChild && !currentChild.killed) currentChild.kill('SIGKILL')\n }, ms('5s'))\n }\n\n // Close JSON log file descriptor\n if (jsonLogFd !== null) {\n try {\n fs.closeSync(jsonLogFd)\n } catch {\n /* ignore */\n }\n jsonLogFd = null\n }\n // Close stderr log file descriptor\n if (stderrLogFd !== null) {\n try {\n fs.closeSync(stderrLogFd)\n } catch {\n /* ignore */\n }\n stderrLogFd = null\n }\n // Remove exit cleanup handler (FD already closed)\n process.removeListener('exit', cleanupFd)\n const tokenUsage =\n accumulatedTokens.input > 0 || accumulatedTokens.output > 0\n ? accumulatedTokens\n : undefined\n const cost = accumulatedCost > 0 ? accumulatedCost : undefined\n resolve({\n ...result,\n retries,\n validationErrors,\n sessionId: extractedSessionId,\n tokenUsage,\n cost,\n })\n }\n\n // Parse output file path\n const outputExt = path.extname(outputFile)\n const expectedBase = path.basename(outputFile, outputExt)\n const taskDirForPoll = path.dirname(outputFile)\n\n // Timeout (uses remaining time to prevent accumulation across retries)\n timeoutTimer = setTimeout(() => {\n logger.info(` ⏱️ Timeout reached (${remainingTimeout / 1000 / 60} minutes)`)\n finish({ succeeded: false, timedOut: true })\n }, remainingTimeout)\n\n // Stall detection: if no stdout events for STALL_TIMEOUT, the LLM is likely\n // hung (API stall, infinite generation). Kill early and retry instead of\n // wasting the full stage timeout sitting idle.\n const resetStallTimer = () => {\n if (stallTimer) clearTimeout(stallTimer)\n const stallLimit = Math.min(STALL_TIMEOUT, remainingTimeout)\n stallTimer = setTimeout(() => {\n if (resolved) return\n logger.warn(\n ` ⚠️ Agent stalled — no output for ${STALL_TIMEOUT / 1000 / 60} minutes, killing`,\n )\n finish({ succeeded: false, timedOut: true })\n }, stallLimit)\n }\n resetStallTimer()\n\n // Process exit handler - wait for file stability after exit\n currentChild.on('exit', async (code) => {\n logger.info(` 📡 Process exited with code: ${code}`)\n\n // Surface stderr on failure\n if (code !== 0 && stderrTailLines.length > 0) {\n const isCI = !!process.env.GITHUB_ACTIONS\n if (isCI) process.stderr.write('::group::Agent stderr (last lines)\\n')\n for (const line of stderrTailLines) {\n process.stderr.write(' ' + line + '\\n')\n }\n if (isCI) process.stderr.write('::endgroup::\\n')\n } else if (stderrLineCount > 0) {\n logger.info(\n ` 📝 Agent stderr: ${stderrLineCount} lines captured (see ${stage}-stderr.log)`,\n )\n }\n\n if (resolved) return\n\n // Brief delay to allow filesystem to flush\n logger.info(` ⏳ Waiting for filesystem to flush...`)\n await sleep(POST_EXIT_DELAY)\n\n // Find the output file (exact match or timestamped variant)\n const detectedFile = findOutputFile(taskDirForPoll, expectedBase, outputExt)\n\n if (!detectedFile) {\n // Nudge: If agent exited cleanly (code 0) and we have a live session,\n // try a lightweight continuation before burning a full retry.\n // The agent still has all context — it just forgot to write the file.\n // If extractedSessionId is missing (some models don't emit sessionID in events),\n // try to recover it from the OpenCode DB before giving up on nudge.\n if (code === 0 && serverUrl && !extractedSessionId) {\n extractedSessionId = recoverSessionId(dataDir)\n }\n if (code === 0 && serverUrl && extractedSessionId) {\n // R2-FIX #12: Skip nudge if insufficient time remaining (need at least 30s)\n const nudgeElapsed = Date.now() - startTime\n const nudgeRemaining = effectiveTimeout - nudgeElapsed\n if (nudgeRemaining < 30_000) {\n logger.info(\n ` 🔔 Skipping nudge — only ${Math.round(nudgeRemaining / 1000)}s remaining`,\n )\n }\n const nudgedFile =\n nudgeRemaining >= 30_000\n ? await nudgeSession(\n backend,\n effectiveAgent,\n outputFile,\n agentEnv,\n cwd,\n serverUrl,\n extractedSessionId,\n dataDir,\n )\n : null\n if (nudgedFile) {\n // Nudge succeeded — continue to file stability check\n // Re-assign detectedFile by jumping to the stability check below\n const { stable, finalSize } = await waitForFileStable(nudgedFile, {\n interval: STABILITY_CHECK_INTERVAL,\n stableCount: STABILITY_CHECK_COUNT,\n timeout: Math.min(ms('30s'), remainingTimeout),\n onCheck: (size, checkNum) => {\n if (checkNum === 0) {\n logger.info(` 🔍 File size: ${size} bytes, waiting for stability...`)\n }\n },\n })\n if (stable && finalSize > 0) {\n logger.info(` ✅ Output file stable (${finalSize} bytes) after nudge`)\n finish({ succeeded: true, timedOut: false })\n return\n }\n // Nudge produced file but it's not stable — fall through to retry\n logger.info(` ⚠️ Nudge produced file but it's not stable, falling through to retry`)\n }\n }\n\n // File not found (or nudge failed) - retry or fail\n if (retries < maxRetries) {\n retries++\n const reason = code === 0 ? 'no output file' : `exit ${code}`\n const feedbackMsg =\n code === 0\n ? `CRITICAL FAILURE: You exited with code 0 but did NOT produce the required output file. You MUST write the output file before exiting. Check that your tool calls are actually writing to the correct path.`\n : `CRITICAL FAILURE: You exited with code ${code}. Fix the error and ensure you write the output file before exiting.`\n\n // Debug: List files in task directory on failure\n try {\n const files = fs.readdirSync(taskDirForPoll)\n logger.info(\n ` 🔍 Debug: Files in ${path.basename(taskDirForPoll)}: ${files.join(', ')}`,\n )\n } catch {\n // Ignore errors\n }\n\n logger.info(` ⚠️ Stage failed (${reason}), retrying (${retries}/${maxRetries})...`)\n setTimeout(() => {\n try {\n attemptWithRetry(feedbackMsg)\n } catch (err) {\n logger.error(` ❌ attemptWithRetry threw: ${err}`)\n finish({ succeeded: false, timedOut: false })\n }\n }, ms('2s'))\n return\n } else {\n // Exhausted retries\n try {\n const files = fs.readdirSync(taskDirForPoll)\n logger.info(\n ` 🔍 Debug: Files in ${path.basename(taskDirForPoll)}: ${files.join(', ')}`,\n )\n } catch {\n // Ignore errors\n }\n logger.info(` ❌ Agent exited ${code} without producing output file`)\n finish({ succeeded: false, timedOut: false })\n return\n }\n }\n\n // File found - wait for it to stabilize\n logger.info(\n ` 📄 Output file detected: ${path.basename(detectedFile)}, checking stability...`,\n )\n\n try {\n const { stable, finalSize } = await waitForFileStable(detectedFile, {\n interval: STABILITY_CHECK_INTERVAL,\n stableCount: STABILITY_CHECK_COUNT,\n timeout: remainingTimeout,\n onCheck: (size, checkNum) => {\n if (checkNum === 0) {\n logger.info(` 🔍 File size: ${size} bytes, waiting for stability...`)\n }\n },\n })\n\n if (!stable) {\n logger.info(` ⚠️ File did not stabilize within timeout`)\n if (retries < maxRetries) {\n retries++\n const feedbackMsg = `CRITICAL FAILURE: Output file was not fully written. The file size changed during stability check. Please ensure you write the complete file before exiting.`\n logger.info(` ⚠️ Retrying with feedback (${retries}/${maxRetries})...`)\n setTimeout(() => {\n try {\n attemptWithRetry(feedbackMsg)\n } catch (err) {\n logger.error(` ❌ attemptWithRetry threw: ${err}`)\n finish({ succeeded: false, timedOut: false })\n }\n }, ms('2s'))\n return\n } else {\n logger.info(` ❌ File stability check failed, retries exhausted`)\n finish({ succeeded: false, timedOut: false })\n return\n }\n }\n\n logger.info(` ✅ File stable (${finalSize} bytes)`)\n\n // Rename if timestamped variant\n if (detectedFile !== outputFile) {\n logger.info(\n ` 📄 Renaming: ${path.basename(detectedFile)} → ${path.basename(outputFile)}`,\n )\n fs.renameSync(detectedFile, outputFile)\n }\n\n // VALIDATION: Check content if validator provided\n if (validateOutput) {\n const validationResult = validateOutput(outputFile)\n if (!validationResult.valid) {\n const errorMsg = validationResult.error || 'Content validation failed'\n logger.info(` ⚠️ Validation failed: ${errorMsg}`)\n\n // Delete the invalid output file\n try {\n fs.unlinkSync(outputFile)\n logger.info(` 🗑️ Deleted invalid output file`)\n } catch {\n // File might not exist, continue\n }\n\n // Store validation error for feedback\n validationErrors.push(errorMsg)\n\n // Retry with feedback if we have retries left\n if (retries < maxRetries) {\n retries++\n const feedbackMsg = `VALIDATION ERROR from previous attempt:\\n${errorMsg}\\n\\nFix this issue in your output. Ensure your output follows the exact required format.`\n logger.info(` 🔄 Retrying with validation feedback (${retries}/${maxRetries})...`)\n setTimeout(() => {\n try {\n attemptWithRetry(feedbackMsg)\n } catch (err) {\n logger.error(` ❌ attemptWithRetry threw: ${err}`)\n finish({ succeeded: false, timedOut: false })\n }\n }, ms('2s'))\n return\n } else {\n logger.info(` ❌ Validation failed and retries exhausted`)\n finish({ succeeded: false, timedOut: false })\n return\n }\n }\n }\n\n // Success!\n logger.info(` ✅ Stage completed successfully`)\n finish({ succeeded: true, timedOut: false })\n } catch (error) {\n logger.info(` ❌ Error waiting for file stability: ${error}`)\n finish({ succeeded: false, timedOut: false })\n }\n })\n\n // Handle spawn errors (e.g., command not found)\n currentChild.on('error', (err) => {\n if (resolved) return\n const error = err as NodeJS.ErrnoException\n if (error.code === 'ENOENT') {\n logger.error(` ❌ Command not found: ${error.path || 'opencode'}. Is it installed?`)\n logger.error(' Install with: npm install -g opencode')\n } else {\n logger.error(` ❌ Agent process error: ${err.message}`)\n }\n finish({ succeeded: false, timedOut: false })\n })\n }\n\n // Start first attempt (no feedback)\n try {\n attemptWithRetry(undefined)\n } catch (err) {\n logger.error(` ❌ attemptWithRetry initial call threw: ${err}`)\n resolve({ succeeded: false, timedOut: false, retries: 0, validationErrors: [] })\n }\n })\n}\n\n/**\n * Simple agent runner without retries (for use with external retry logic)\n */\nexport function runAgentOnce(\n input: KodyInput,\n stage: string,\n outputFile: string,\n timeout?: number,\n options: Omit<AgentRunnerOptions, 'maxRetries'> = {},\n): Promise<AgentRunResult> {\n return runAgentWithFileWatch(input, stage, outputFile, timeout, {\n ...options,\n maxRetries: 0,\n })\n}\n","/**\n * @fileType utility\n * @domain kody | agent-execution\n * @pattern chat-history\n * @ai-summary Capture and manage agent conversation history from opencode sessions\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { execFileSync } from 'child_process'\n\nimport { logger } from './logger'\nimport { resolveOpenCodeBinary } from './opencode-server'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ChatMessage {\n role: 'user' | 'assistant'\n stage: string\n text: string\n tools: string[]\n timestamp: string\n model?: string\n}\n\nexport interface ChatSession {\n stage: string\n sessionId: string\n startedAt: string\n messages: ChatMessage[]\n}\n\nexport interface ChatHistory {\n version: 1\n taskId: string\n sessions: ChatSession[]\n}\n\n// ============================================================================\n// Helper: Trim raw opencode export to compact chat session\n// ============================================================================\n\n/**\n * Trim a raw opencode session export to a compact ChatSession structure.\n * Extracts role, text content, tool names, and timestamps.\n * Drops tool arguments/outputs and internal metadata for compactness.\n */\nfunction trimSession(\n rawExport: {\n info?: { id?: string; time?: { created?: number } }\n messages?: Array<{\n info?: { role?: string; time?: { created?: number }; model?: string }\n parts?: Array<{\n type?: string\n text?: string\n tool?: string\n }>\n }>\n },\n stage: string,\n): ChatSession | null {\n try {\n const info = rawExport.info || {}\n const messages = rawExport.messages || []\n\n const sessionId = info.id || 'unknown'\n const startedAt = info.time?.created\n ? new Date(info.time.created).toISOString()\n : new Date().toISOString()\n\n const trimmedMessages: ChatMessage[] = []\n\n for (const msg of messages) {\n const msgInfo = msg.info || {}\n // Cast role - opencode may return other values but we only handle user/assistant\n const role: 'user' | 'assistant' = msgInfo.role === 'assistant' ? 'assistant' : 'user'\n\n // Extract text from parts\n let text = ''\n const tools: string[] = []\n\n for (const part of msg.parts || []) {\n if (part.type === 'text' && part.text) {\n text += part.text\n }\n if (part.type === 'tool' && part.tool) {\n tools.push(part.tool)\n }\n }\n\n // Skip messages with no content\n if (!text && tools.length === 0) continue\n\n trimmedMessages.push({\n role,\n stage,\n text: text.trim(),\n tools,\n timestamp: msgInfo.time?.created\n ? new Date(msgInfo.time.created).toISOString()\n : new Date().toISOString(),\n model: msgInfo.model ? JSON.stringify(msgInfo.model) : undefined,\n })\n }\n\n return {\n stage,\n sessionId,\n startedAt,\n messages: trimmedMessages,\n }\n } catch (err) {\n logger.warn({ err }, `Failed to trim session for stage ${stage}`)\n return null\n }\n}\n\n// ============================================================================\n// Helper: Extract JSON object from potentially noisy CLI output\n// ============================================================================\n\n/**\n * Extract a JSON object from CLI output that may contain non-JSON lines\n * (e.g., progress messages, \"Exporting session:\" prefix, warnings).\n * Finds the first '{' and last '}' and parses the substring between them.\n */\nexport function extractJson(output: string): unknown {\n const firstBrace = output.indexOf('{')\n const lastBrace = output.lastIndexOf('}')\n\n if (firstBrace === -1 || lastBrace === -1 || lastBrace <= firstBrace) {\n throw new SyntaxError(\n `No JSON object found in output (length=${output.length}, first 200 chars: ${output.slice(0, 200)})`,\n )\n }\n\n const jsonStr = output.slice(firstBrace, lastBrace + 1)\n return JSON.parse(jsonStr)\n}\n\n// ============================================================================\n// Helper: Load existing chat history\n// ============================================================================\n\nexport function loadChatHistory(taskDir: string): ChatHistory | null {\n const chatPath = path.join(taskDir, 'chat.json')\n if (!fs.existsSync(chatPath)) {\n return null\n }\n try {\n const data = fs.readFileSync(chatPath, 'utf-8')\n return JSON.parse(data) as ChatHistory\n } catch (err) {\n logger.warn({ err, chatPath }, 'Failed to load chat history, starting fresh')\n return null\n }\n}\n\n// ============================================================================\n// Helper: Save chat history\n// ============================================================================\n\nfunction saveChatHistory(taskDir: string, history: ChatHistory): void {\n const chatPath = path.join(taskDir, 'chat.json')\n fs.writeFileSync(chatPath, JSON.stringify(history, null, 2), 'utf-8')\n}\n\n// ============================================================================\n// Main: Append a session to the task's chat history\n// ============================================================================\n\n/**\n * Export an opencode session and append its trimmed content to the task's chat.json.\n * This is called after a successful agent stage completes.\n *\n * @param taskDir - The .tasks/<taskId> directory\n * @param stage - The stage name (e.g., 'spec', 'build')\n * @param sessionId - The opencode session ID to export\n */\nexport async function appendSession(\n taskDir: string,\n stage: string,\n sessionId: string,\n serverUrl?: string,\n): Promise<void> {\n if (!sessionId) {\n logger.debug('No sessionId, skipping chat export')\n return\n }\n\n logger.info(` 📝 Exporting chat session ${sessionId} for stage ${stage}...`)\n\n try {\n // Export session as JSON from the OpenCode SQLite DB.\n // `opencode export` reads directly from the DB — it does NOT support --attach.\n // When serverUrl is set, the DB lives in the task-specific data dir, so we use\n // the real binary + XDG_DATA_HOME. Without server mode, use pnpm exec (old binary).\n let output: string\n if (serverUrl) {\n const args = ['export', sessionId]\n const dataDir = path.join(taskDir, 'opencode-data')\n output = execFileSync(resolveOpenCodeBinary(), args, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n cwd: process.cwd(),\n maxBuffer: 50 * 1024 * 1024,\n env: { ...process.env, XDG_DATA_HOME: dataDir },\n })\n } else {\n const args = ['exec', 'opencode', 'export', sessionId]\n output = execFileSync('pnpm', args, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n cwd: process.cwd(),\n maxBuffer: 50 * 1024 * 1024,\n })\n }\n\n // Extract JSON from potentially noisy CLI output (may contain\n // \"Exporting session:\" prefix, progress messages, or other non-JSON lines)\n const rawExport = extractJson(output) as Parameters<typeof trimSession>[0]\n\n // Trim to compact format\n const session = trimSession(rawExport, stage)\n if (!session) {\n logger.warn(`Failed to trim session ${sessionId}`)\n return\n }\n\n // Load or create chat history\n let history = loadChatHistory(taskDir)\n if (!history) {\n // Extract taskId from taskDir path\n const taskId = path.basename(taskDir)\n history = {\n version: 1,\n taskId,\n sessions: [],\n }\n }\n\n // Append the new session\n history.sessions.push(session)\n\n // R2-FIX #8: Cap sessions to prevent unbounded growth during retry loops.\n // Keep last 30 sessions — enough for full pipeline + several verify→fix loops.\n const MAX_CHAT_SESSIONS = 30\n if (history.sessions.length > MAX_CHAT_SESSIONS) {\n history.sessions = history.sessions.slice(-MAX_CHAT_SESSIONS)\n logger.info(` ℹ️ Chat history trimmed to last ${MAX_CHAT_SESSIONS} sessions`)\n }\n\n // Save\n saveChatHistory(taskDir, history)\n\n // Count total tools used across all messages\n const totalTools = session.messages.reduce((acc, m) => acc + m.tools.length, 0)\n\n logger.info(\n ` ✅ Saved chat for ${stage}: ${session.messages.length} messages, ${totalTools} tools used`,\n )\n } catch (err) {\n // Non-fatal — log and continue\n logger.warn({ err, sessionId, stage }, 'Failed to export/append chat session')\n }\n}\n\n// ============================================================================\n// Utility: Get chat history for a task (for debugging/loading)\n// ============================================================================\n\nexport function getChatHistoryForTask(taskId: string): ChatHistory | null {\n const taskDir = path.join(process.cwd(), '.tasks', taskId)\n return loadChatHistory(taskDir)\n}\n","/**\n * @fileType handler\n * @domain kody | handlers\n * @pattern agent-handler\n * @ai-summary Agent stage handler that runs LLM agents\n */\n\nimport { logger } from '../logger'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext, StageDefinition, StageResult } from '../engine/types'\nimport { runAgentWithFileWatch } from '../agent-runner'\nimport { stageOutputFile } from '../stages/registry'\nimport { appendSession } from '../chat-history'\nimport type { StageHandler } from './handler'\n\n/**\n * Agent handler - runs LLM agents via opencode\n */\nexport class AgentHandler implements StageHandler {\n async execute(ctx: PipelineContext, def: StageDefinition): Promise<StageResult> {\n // Use stageOutputFile to get the correct output file (respects STAGE_OUTPUT_MAP)\n const outputFile = stageOutputFile(ctx.taskDir, def.name)\n\n // Run agent — pass def.name as stage for prompt/model, but use agentName for the agent execution\n if (def.agentName && def.agentName !== def.name) {\n logger.info(` ⚙️ Stage \"${def.name}\" using agent: ${def.agentName}`)\n }\n const result = await runAgentWithFileWatch(ctx.input, def.name, outputFile, def.timeout, {\n backend: ctx.backend,\n validateOutput: def.validator,\n maxRetries: def.maxRetries,\n serverUrl: ctx.serverUrl,\n sessionId: ctx.lastSessionId,\n // XDG_DATA_HOME must match the server's data dir for instance lookup\n dataDir: ctx.serverUrl ? path.join(ctx.taskDir, 'opencode-data') : undefined,\n // Pass agentName override if different from stage name (e.g., fix stage uses build agent)\n agentName: def.agentName && def.agentName !== def.name ? def.agentName : undefined,\n })\n\n // Map result to StageResult\n if (result.timedOut) {\n return {\n outcome: 'timed_out',\n retries: result.retries,\n }\n }\n\n if (!result.succeeded) {\n // Try fallback: if agent exited 0 but didn't write output file, create one\n if (def.fallbackOnMissingOutput && !fs.existsSync(outputFile)) {\n const fallbackContent = def.fallbackOnMissingOutput(ctx)\n if (fallbackContent) {\n fs.writeFileSync(outputFile, fallbackContent)\n logger.info(` ℹ️ Created fallback output: ${def.name}.md`)\n return {\n outcome: 'completed',\n retries: result.retries,\n outputFile: `${def.name}.md`,\n tokenUsage: result.tokenUsage,\n cost: result.cost,\n sessionId: result.sessionId,\n }\n }\n }\n\n const details: string[] = [`Agent \"${def.agentName ?? def.name}\" failed`]\n if (result.validationErrors?.length) {\n details.push(`Validation errors: ${result.validationErrors.join('; ')}`)\n }\n details.push(`Artifacts: ${def.name}-stderr.log, ${def.name}-events.jsonl`)\n return {\n outcome: 'failed',\n reason: details.join('. '),\n retries: result.retries,\n tokenUsage: result.tokenUsage,\n cost: result.cost,\n }\n }\n\n // Success - try to save chat history\n if (result.sessionId) {\n try {\n await appendSession(ctx.taskDir, def.name, result.sessionId, ctx.serverUrl)\n } catch (err) {\n // Non-fatal — don't fail the stage if chat export fails\n logger.warn({ err, stage: def.name }, 'Failed to save chat history')\n }\n\n // Propagate sessionId for downstream stage forking\n ctx.lastSessionId = result.sessionId\n }\n\n return {\n outcome: 'completed',\n retries: result.retries,\n outputFile: `${def.name}.md`,\n tokenUsage: result.tokenUsage,\n cost: result.cost,\n sessionId: result.sessionId,\n }\n }\n}\n","/**\n * @fileType configuration\n * @domain kody | pipeline\n * @pattern project-config\n * @ai-summary Configurable project settings — replaces hardcoded quality commands\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nexport interface QualityCommands {\n typecheck: string\n lint: string\n lintFix: string\n format: string\n formatFix: string\n testUnit: string\n testE2e?: string\n}\n\nexport interface GitConfig {\n defaultBranch: string\n userEmail?: string\n userName?: string\n}\n\nexport interface GitHubConfig {\n owner: string\n repo: string\n appId?: number\n}\n\nexport interface AgentConfig {\n /** Project-specific instruction files to inject into agent prompts */\n instructions: string[]\n /** Domain agent → territory glob mapping */\n domainMap: Record<string, string[]>\n}\n\nexport interface KodyProjectConfig {\n quality: QualityCommands\n git: GitConfig\n github: GitHubConfig\n agents: AgentConfig\n paths: {\n taskDir: string\n }\n}\n\nconst DEFAULT_CONFIG: KodyProjectConfig = {\n quality: {\n typecheck: 'pnpm -s tsc --noEmit',\n lint: 'pnpm -s lint',\n lintFix: 'pnpm lint:fix',\n format: 'pnpm -s format:check',\n formatFix: 'pnpm format:fix',\n testUnit: 'pnpm -s test:unit',\n },\n git: {\n defaultBranch: 'dev',\n },\n github: {\n owner: '',\n repo: '',\n },\n agents: {\n instructions: [],\n domainMap: {},\n },\n paths: {\n taskDir: '.tasks',\n },\n}\n\nlet _config: KodyProjectConfig | null = null\n\n/**\n * Load project config from kody.config.json in the project root.\n * Falls back to defaults if no config file exists.\n */\nexport function loadProjectConfig(projectRoot: string = process.cwd()): KodyProjectConfig {\n if (_config) return _config\n\n const configPath = path.join(projectRoot, 'kody.config.json')\n\n if (fs.existsSync(configPath)) {\n try {\n const raw = JSON.parse(fs.readFileSync(configPath, 'utf-8'))\n _config = {\n quality: { ...DEFAULT_CONFIG.quality, ...raw.quality },\n git: { ...DEFAULT_CONFIG.git, ...raw.git },\n github: { ...DEFAULT_CONFIG.github, ...raw.github },\n agents: {\n instructions: raw.agents?.instructions ?? DEFAULT_CONFIG.agents.instructions,\n domainMap: raw.agents?.domainMap ?? DEFAULT_CONFIG.agents.domainMap,\n },\n paths: { ...DEFAULT_CONFIG.paths, ...raw.paths },\n }\n } catch {\n _config = DEFAULT_CONFIG\n }\n } else {\n _config = DEFAULT_CONFIG\n }\n\n return _config\n}\n\n/**\n * Get the current project config (must call loadProjectConfig first).\n */\nexport function getProjectConfig(): KodyProjectConfig {\n if (!_config) return loadProjectConfig()\n return _config\n}\n\n/**\n * Reset config cache (for testing).\n */\nexport function resetProjectConfig(): void {\n _config = null\n}\n","/**\n * @fileType utility\n * @domain ci | kody | pipeline\n * @pattern scripted-stages\n * @ai-summary Direct script execution for verify and PR stages — no LLM needed for mechanical tasks\n */\n\nimport { logger } from './logger'\nimport { execFileSync } from 'child_process'\nimport * as fs from 'fs'\nimport ms from 'ms'\nimport * as path from 'path'\nimport { getDefaultBranch, commitAndPush } from './git-utils'\nimport { postComment, setLifecycleLabel } from './github-api'\nimport { getProjectConfig } from './config/project-config'\n\n// ============================================================================\n// Verify Stage — run quality gates directly\n// ============================================================================\n\ninterface VerifyResult {\n passed: boolean\n report: string\n}\n\ninterface GateResult {\n name: string\n passed: boolean\n output: string\n}\n\n/** Default timeout per gate (2 minutes) */\nconst DEFAULT_GATE_TIMEOUT = ms('2m')\n\nfunction runGate(\n name: string,\n program: string,\n args: string[],\n cwd: string,\n timeout: number = DEFAULT_GATE_TIMEOUT,\n): GateResult {\n logger.info(` Running ${name}...`)\n try {\n const output = execFileSync(program, args, { cwd, encoding: 'utf-8', timeout })\n logger.info(` ✅ ${name} passed`)\n return { name, passed: true, output: output.slice(0, 1000) }\n } catch (error: unknown) {\n const err = error as { stdout?: string; stderr?: string; message?: string }\n const output = (err.stdout || '') + (err.stderr || '') || err.message || 'Unknown error'\n logger.info(` ❌ ${name} failed`)\n return { name, passed: false, output: output.slice(0, 5000) }\n }\n}\n\nexport function runVerifyStage(\n outputFile: string,\n cwd: string = process.cwd(),\n timeout?: number,\n taskDir?: string,\n): VerifyResult {\n logger.info('\\n🔍 Running verification (scripted)...\\n')\n\n // Aggregate timeout - total time allowed for all gates combined\n const startTime = Date.now()\n const aggregateTimeout = timeout ?? Infinity\n\n // Quality commands from project config (configurable per-project)\n const config = getProjectConfig()\n const parseCmd = (cmd: string) => {\n const parts = cmd.split(/\\s+/)\n return { program: parts[0], args: parts.slice(1) }\n }\n const tsc = parseCmd(config.quality.typecheck)\n const lint = parseCmd(config.quality.lint)\n const fmt = parseCmd(config.quality.format)\n\n const gateDefinitions = [\n { name: 'TypeScript', program: tsc.program, args: tsc.args },\n { name: 'Lint', program: lint.program, args: lint.args },\n { name: 'Format', program: fmt.program, args: fmt.args },\n // Unit Tests gate removed — tests are deferred to inspector plugin (kody-deferred-tests)\n ]\n\n const gates: GateResult[] = []\n for (const gateDef of gateDefinitions) {\n const elapsed = Date.now() - startTime\n const remaining = aggregateTimeout - elapsed\n\n if (remaining <= 0) {\n // Aggregate timeout exceeded - skip remaining gates\n gates.push({\n name: gateDef.name,\n passed: false,\n output: 'SKIPPED: aggregate timeout exceeded',\n })\n continue\n }\n\n // Use smaller of remaining aggregate time or per-gate default\n const gateTimeout = Math.min(remaining, DEFAULT_GATE_TIMEOUT)\n gates.push(runGate(gateDef.name, gateDef.program, gateDef.args, cwd, gateTimeout))\n }\n\n const allPassed = gates.every((g) => g.passed)\n\n // Write individual gate output files for failed gates.\n // These files provide detailed error context to the fix stage agent\n // (state-machine.ts reads tsc-output.txt / lint-output.txt when building verify-failures.md).\n if (taskDir) {\n for (const gate of gates) {\n if (!gate.passed) {\n const slug = gate.name.toLowerCase().replace(/\\s+/g, '-')\n const gateOutputPath = path.join(taskDir, `${slug}-output.txt`)\n try {\n fs.writeFileSync(gateOutputPath, gate.output.slice(0, 10000))\n } catch {\n // Non-critical — gate output is supplementary context\n }\n }\n }\n }\n\n const lines: string[] = ['# Verification Report\\n']\n for (const gate of gates) {\n const icon = gate.passed\n ? 'PASS ✅'\n : gate.output.includes('SKIPPED')\n ? 'SKIPPED ❌'\n : 'FAIL ❌'\n lines.push(`## ${gate.name}: ${icon}\\n`)\n if (!gate.passed) {\n lines.push('```')\n lines.push(gate.output)\n lines.push('```\\n')\n }\n }\n\n lines.push(`\\n## Result: ${allPassed ? 'PASS' : 'FAIL'}`)\n\n const report = lines.join('\\n')\n fs.writeFileSync(outputFile, report)\n logger.info(`\\n${allPassed ? '✅' : '❌'} Verification ${allPassed ? 'passed' : 'failed'}`)\n\n return { passed: allPassed, report }\n}\n\n// ============================================================================\n// PR Stage — create PR directly via gh CLI\n// ============================================================================\n\ninterface PrResult {\n created: boolean\n url: string\n report: string\n}\n\nfunction getBranchName(cwd: string): string {\n const branch = execFileSync('git', ['branch', '--show-current'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n if (!branch) {\n // Detached HEAD — use short commit hash as fallback\n return (\n execFileSync('git', ['rev-parse', '--short', 'HEAD'], {\n cwd,\n encoding: 'utf-8',\n }).trim() || 'detached'\n )\n }\n return branch\n}\n\nfunction getExistingPr(branch: string, cwd: string): string | null {\n // BUG-F fix: Use GH_PAT if non-empty, fall back to GH_TOKEN (don't use empty string)\n const ghToken = process.env.GH_PAT?.trim() || process.env.GH_TOKEN\n try {\n const output = execFileSync(\n 'gh',\n ['pr', 'list', '--head', branch, '--json', 'url', '--jq', '.[0].url'],\n {\n cwd,\n encoding: 'utf-8',\n env: { ...process.env, GH_TOKEN: ghToken },\n },\n ).trim()\n return output || null\n } catch {\n return null\n }\n}\n\nfunction getCommitSummary(defaultBranch: string, cwd: string): string {\n try {\n // Use execFileSync to prevent shell injection via branch names\n return execFileSync('git', ['log', '--oneline', `${defaultBranch}..HEAD`], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n } catch {\n return ''\n }\n}\n\n/**\n * Create a fresh branch with incremented version suffix for --fresh flag.\n * Lists remote branches matching pattern, finds highest -vN suffix, creates -v(N+1).\n * Strips existing -vN suffix to prevent chains like branch-v2-v3.\n */\nexport function createFreshBranch(currentBranch: string, cwd: string = process.cwd()): string {\n // Strip existing -vN suffix to prevent chains (e.g., feat/260225-task-v2 -> feat/260225-task)\n const baseBranch = currentBranch.replace(/-v\\d+$/, '')\n\n // List remote branches matching the pattern\n let maxVersion = 1\n try {\n const output = execFileSync('git', ['branch', '-r', '--list', `${baseBranch}-v*`], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n\n if (output) {\n // Extract version numbers from branch names\n const versions = output.split('\\n').map((b) => {\n const match = b.trim().match(/-v(\\d+)$/)\n return match ? parseInt(match[1], 10) : 0\n })\n maxVersion = Math.max(...versions, 1)\n }\n } catch {\n // No matching branches, start at v2\n maxVersion = 1\n }\n\n const newBranch = `${baseBranch}-v${maxVersion + 1}`\n\n // Create the new branch locally from current HEAD (carries all commits)\n try {\n execFileSync('git', ['checkout', '-b', newBranch], {\n cwd,\n encoding: 'utf-8',\n })\n logger.info(` Created fresh branch: ${newBranch}`)\n } catch (error) {\n // If branch already exists locally, checkout to it\n if (String(error).includes('already exists')) {\n execFileSync('git', ['checkout', newBranch], { cwd, encoding: 'utf-8' })\n logger.info(` Checked out existing fresh branch: ${newBranch}`)\n } else {\n throw error\n }\n }\n\n return newBranch\n}\n\nfunction buildPrTitle(\n taskDir: string,\n defaultBranch: string,\n cwd: string,\n issueNumber?: number,\n): string {\n // Read task.md for context\n const taskMdPath = path.join(taskDir, 'task.md')\n let taskDescription = ''\n let issueTitle = ''\n if (fs.existsSync(taskMdPath)) {\n const taskMdContent = fs.readFileSync(taskMdPath, 'utf-8')\n\n // First try to extract ## Issue Title section (highest priority)\n // More forgiving regex: accepts variable whitespace between heading and value\n const issueTitleMatch = taskMdContent.match(/^##\\s*Issue\\s*Title\\s*\\n+([^\\n]+)/im)\n if (issueTitleMatch) {\n issueTitle = issueTitleMatch[1].trim()\n }\n\n // Then get the rest of the description (strip both # Task and ## Issue Title sections)\n taskDescription = taskMdContent\n .replace(/^#\\s*Task\\s*/i, '')\n .replace(/^##\\s*Issue\\s*Title\\s*\\n+[^\\n]*\\n*/gim, '')\n .trim()\n }\n\n // Read task.json for type\n const taskJsonPath = path.join(taskDir, 'task.json')\n let taskType = 'feat'\n if (fs.existsSync(taskJsonPath)) {\n try {\n const taskJson = JSON.parse(fs.readFileSync(taskJsonPath, 'utf-8'))\n const typeMap: Record<string, string> = {\n fix_bug: 'fix',\n implement_feature: 'feat',\n refactor: 'refactor',\n docs: 'docs',\n ops: 'chore',\n research: 'chore',\n }\n taskType = typeMap[taskJson.task_type] || 'feat'\n } catch {\n // ignore\n }\n }\n\n // Priority: 1) Issue title from task.md, 2) First content line from task.md, 3) Commit messages\n\n // Strip severity tags from issue title (e.g., [MEDIUM], [HIGH], [LOW], [BUG], etc.)\n const cleanedIssueTitle = issueTitle.replace(/^\\[[^\\]]+\\]\\s*/, '')\n\n // Get first non-empty, non-heading line of task description as summary\n // More robust heading detection: track lines that were originally markdown headings\n const commonHeadings = ['description', 'summary', 'overview', 'details', 'background']\n const firstLine =\n taskDescription\n .split('\\n')\n .map((l) => {\n const originalLine = l\n\n // Strip conventional commit prefix first (fix:, feat:, etc.)\n let cleaned = l.replace(\n /^(fix|feat|refactor|docs|chore|test|style|perf|ci|build)(\\([^)]*\\))?:/i,\n '',\n )\n // Trim leading space left by prefix removal\n cleaned = cleaned.trim()\n // Then strip markdown heading markers\n cleaned = cleaned.replace(/^#+\\s*/, '').trim()\n\n return { original: originalLine, cleaned }\n })\n // Exclude lines that were headings (matched /^#+\\s*\\S/) AND ended up as common heading words\n .filter(({ original, cleaned }) => {\n const isCommonHeading = commonHeadings.includes(cleaned.toLowerCase())\n const wasHeading = /^#+\\s*\\S/.test(original.trim())\n return cleaned.length > 0 && !(wasHeading && isCommonHeading)\n })[0]?.cleaned ?? ''\n\n // Use issue title if available, otherwise fall back to first content line\n const titleSource = cleanedIssueTitle || firstLine\n\n // Use commit messages as fallback\n if (!titleSource) {\n const commits = getCommitSummary(defaultBranch, cwd)\n const firstCommit = commits.split('\\n')[0] || 'implement changes'\n // Strip commit hash\n return `${taskType}: ${firstCommit.replace(/^[a-f0-9]+\\s+/, '')}`\n }\n\n // Truncate to reasonable length\n const summary = titleSource.length > 72 ? titleSource.slice(0, 69) + '...' : titleSource\n\n // Add issue reference to title for GitHub auto-linking\n const issueRef = issueNumber ? ` - Closes #${issueNumber}` : ''\n\n return `${taskType}: ${summary.toLowerCase()}${issueRef}`\n}\n\nfunction buildPrBody(\n taskDir: string,\n defaultBranch: string,\n cwd: string,\n issueNumber?: number,\n): string {\n const commits = getCommitSummary(defaultBranch, cwd)\n\n // Read spec for context — extract ## Overview section if present\n const specPath = path.join(taskDir, 'spec.md')\n let specSummary = ''\n if (fs.existsSync(specPath)) {\n const spec = fs.readFileSync(specPath, 'utf-8')\n // Try to extract the ## Overview section\n const overviewMatch = spec.match(/##\\s*Overview\\n([\\s\\S]*?)(?=\\n##\\s|$)/)\n if (overviewMatch) {\n specSummary = overviewMatch[1].trim()\n } else {\n // Fallback: first paragraph (up to first blank line or 500 chars)\n const firstPara = spec.split(/\\n\\n/)[0] || ''\n specSummary = firstPara.slice(0, 500).trim()\n }\n }\n\n const lines = ['## Summary\\n']\n\n if (specSummary) {\n lines.push(specSummary)\n lines.push('')\n }\n\n if (commits) {\n lines.push('## Commits\\n')\n lines.push('```')\n lines.push(commits)\n lines.push('```')\n }\n\n if (issueNumber) {\n lines.push(`\\nCloses #${issueNumber}`)\n }\n\n lines.push('\\n---\\n🤖 Generated by Kody pipeline')\n lines.push('<!-- TODO: update docs -->')\n\n return lines.join('\\n')\n}\n\nexport async function runPrStage(\n taskDir: string,\n outputFile: string,\n cwd: string = process.cwd(),\n issueNumber?: number,\n options?: {\n fresh?: boolean // Force create new PR (new branch)\n },\n): Promise<PrResult> {\n logger.info('\\n📝 Creating PR (scripted)...\\n')\n\n const branch = getBranchName(cwd)\n const defaultBranch = getDefaultBranch(cwd)\n\n // Step 1: Check for existing PR (unless --fresh is set)\n const existingUrl = !options?.fresh ? getExistingPr(branch, cwd) : null\n if (existingUrl && !options?.fresh) {\n logger.info(` PR already exists: ${existingUrl}`)\n const report = `# PR Stage\\n\\nExisting PR found: ${existingUrl}\\n`\n fs.writeFileSync(outputFile, report)\n return { created: false, url: existingUrl, report }\n }\n\n if (options?.fresh && existingUrl) {\n logger.info(` --fresh flag: creating new PR (ignoring existing: ${existingUrl})`)\n }\n\n // Step 2: Push branch (skip pre-push hooks to avoid blocking on unrelated checks)\n logger.info(' Pushing branch ' + branch + '...')\n let pushSuccess = false\n try {\n execFileSync('git', ['push', '-u', 'origin', branch], {\n cwd,\n stdio: 'inherit',\n timeout: 120_000,\n env: { ...process.env, HUSKY: '0', SKIP_HOOKS: '1' },\n })\n pushSuccess = true\n } catch (_error) {\n // Push was rejected - remote has changes, try pull --rebase and retry\n logger.info(' Push rejected, pulling and rebasing...')\n try {\n execFileSync('git', ['pull', '--rebase', 'origin', branch], {\n cwd,\n stdio: 'inherit',\n timeout: 120_000,\n env: { ...process.env, HUSKY: '0', SKIP_HOOKS: '1' },\n })\n // Retry push after rebase\n execFileSync('git', ['push', '-u', 'origin', branch], {\n cwd,\n stdio: 'inherit',\n timeout: 120_000,\n env: { ...process.env, HUSKY: '0', SKIP_HOOKS: '1' },\n })\n pushSuccess = true\n logger.info(' Push succeeded after rebase')\n } catch (_rebaseError) {\n logger.info(' Push failed even after rebase')\n }\n }\n\n if (!pushSuccess) {\n // R3-FIX #1: Abort PR creation if push failed — GitHub API will reject the PR\n // with \"branch not reachable\" since the branch doesn't exist on the remote.\n logger.error(' ❌ Push failed — cannot create PR for unpushed branch')\n const report =\n '# PR Stage\\n\\nFailed to create PR: git push failed. Branch not available on remote.\\n'\n fs.writeFileSync(outputFile, report)\n return { created: false, url: '', report }\n }\n // Step 3: Build title and body\n const title = buildPrTitle(taskDir, defaultBranch, cwd, issueNumber)\n const body = buildPrBody(taskDir, defaultBranch, cwd, issueNumber)\n\n logger.info(` Title: ${title}`)\n\n // Step 4: Create PR via GitHub REST API (more reliable than gh CLI in CI)\n // BUG-F fix: Use GH_PAT if non-empty, fall back to GH_TOKEN (don't use empty string)\n const ghToken = process.env.GH_PAT?.trim() || process.env.GH_TOKEN\n\n if (!ghToken) {\n logger.error(' ❌ No GitHub token found (GH_PAT or GH_TOKEN)')\n const report = `# PR Stage\\n\\nFailed to create PR: No GitHub token found. Set GH_PAT or GH_TOKEN.\\n`\n fs.writeFileSync(outputFile, report)\n return { created: false, url: '', report }\n }\n\n // Extract owner and repo from git remote\n let owner = ''\n let repo = ''\n try {\n const remoteUrl = execFileSync('git', ['remote', 'get-url', 'origin'], {\n cwd,\n encoding: 'utf-8',\n }).trim()\n // Parse from: https://github.com/owner/repo.git or git@github.com:owner/repo.git\n const match = remoteUrl.match(/github\\.com[/:]([^/]+)\\/([^/.]+)/)\n if (match) {\n owner = match[1]\n repo = match[2]\n }\n } catch {\n logger.error(' ❌ Could not determine repo from git remote')\n const report = `# PR Stage\\n\\nFailed to determine repository from git remote\\n`\n fs.writeFileSync(outputFile, report)\n return { created: false, url: '', report }\n }\n\n let prUrl = ''\n try {\n const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/pulls`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${ghToken}`,\n Accept: 'application/vnd.github.v3+json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n title,\n body,\n head: branch,\n base: defaultBranch,\n draft: false,\n }),\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new Error(`GitHub API error: ${response.status} - ${errorText}`)\n }\n\n const prData = (await response.json()) as { html_url: string }\n prUrl = prData.html_url\n logger.info(` ✅ PR created: ${prUrl}`)\n\n // Post comment to issue linking to PR\n if (issueNumber) {\n const cleanUrl = prUrl.replace(/\\n/g, '').trim()\n postComment(issueNumber, `🎉 PR created: ${cleanUrl}`)\n logger.info(` ✅ Commented on issue #${issueNumber}`)\n }\n\n // Set lifecycle label to review\n if (issueNumber) {\n setLifecycleLabel(issueNumber, 'kody:review')\n }\n } catch (error: unknown) {\n const err = error as { message?: string }\n const msg = err.message || 'Unknown error'\n logger.error(` ❌ PR creation failed: ${msg}`)\n const report = `# PR Stage\n\nFailed to create PR: ${msg}\n\nTitle: ${title}\n\n${body}\n`\n fs.writeFileSync(outputFile, report)\n return { created: false, url: '', report }\n }\n\n const report = `# PR Stage\n\nPR created: ${prUrl}\n\nTitle: ${title}\n\n${body}\n`\n fs.writeFileSync(outputFile, report)\n return { created: true, url: prUrl, report }\n}\n\n// ============================================================================\n// Commit Stage — commit and push changes via git-utils\n// ============================================================================\n\ninterface CommitResult {\n success: boolean\n hash: string\n branch: string\n message: string\n report: string\n}\n\nexport function runCommitStage(\n taskDir: string,\n outputFile: string,\n cwd: string = process.cwd(),\n): CommitResult {\n logger.info('\\n📦 Committing changes (scripted)...\\n')\n\n // Extract task ID from taskDir path\n const taskId = path.basename(taskDir)\n\n const result = commitAndPush(taskId, taskDir, cwd)\n\n const lines = [`# Commit Stage\\n`]\n\n if (result.success) {\n lines.push(`✅ **Committed and pushed**\\n`)\n lines.push(`- **Branch:** ${result.branch}`)\n lines.push(`- **Hash:** ${result.hash}`)\n logger.info(` ✅ ${result.message}`)\n } else {\n lines.push(`⚠️ **Commit status:** ${result.message}\\n`)\n if (result.message.includes('No changes')) {\n logger.info(` ℹ️ ${result.message}`)\n } else {\n logger.error(` ❌ ${result.message}`)\n }\n }\n\n const report = lines.join('\\n')\n fs.writeFileSync(outputFile, report)\n\n return {\n success: result.success,\n hash: result.hash,\n branch: result.branch,\n message: result.message,\n report,\n }\n}\n","/**\n * @fileType handler\n * @domain kody | handlers\n * @pattern scripted-handler\n * @ai-summary Scripted verify handler with auto-fix for lint/format\n */\n\nimport type { PipelineContext, StageDefinition, StageResult } from '../engine/types'\nimport { logger } from '../logger'\nimport { runVerifyStage } from '../scripted-stages'\nimport { commitPipelineFiles } from '../git-utils'\nimport type { StageHandler } from './handler'\nimport { DEFAULT_TIMEOUT } from '../agent-runner'\nimport { existsSync, unlinkSync } from 'fs'\nimport { execFileSync } from 'child_process'\nimport { getProjectConfig } from '../config/project-config'\n\nconst MAX_AUTOFIX_ATTEMPTS = 2\n\n/**\n * Scripted verify handler with scripted auto-fix loop.\n *\n * When verify fails on lint/format, runs `pnpm lint:fix` + `pnpm format:fix`\n * directly instead of invoking an LLM agent. The build agent already handled\n * all substantive failures (tsc, tests) in its own feedback loop.\n */\nexport class ScriptedVerifyHandler implements StageHandler {\n async execute(ctx: PipelineContext, def: StageDefinition): Promise<StageResult> {\n const outputFile = `${ctx.taskDir}/${def.name}.md`\n\n const startTime = Date.now()\n const totalTimeout = def.timeout ?? DEFAULT_TIMEOUT\n\n // Run initial verify\n const verifyResult = runVerifyStage(outputFile, undefined, def.timeout, ctx.taskDir)\n\n if (verifyResult.passed) {\n return {\n outcome: 'completed',\n retries: 0,\n outputFile: `${def.name}.md`,\n }\n }\n\n // Failed — try scripted auto-fix loop (lint:fix + format:fix)\n let fixed = false\n\n for (let attempt = 1; attempt <= MAX_AUTOFIX_ATTEMPTS; attempt++) {\n const elapsed = Date.now() - startTime\n const remaining = totalTimeout - elapsed\n\n if (remaining <= 0) {\n logger.info(\n ` \\u23f1\\ufe0f Aggregate timeout exceeded (${totalTimeout / 1000 / 60} minutes) — stopping auto-fix loop`,\n )\n return {\n outcome: 'timed_out',\n reason: `Aggregate timeout exceeded during auto-fix loop after ${attempt - 1} attempts`,\n retries: 0,\n }\n }\n\n logger.info(\n `\\n\\ud83d\\udd27 Scripted auto-fix attempt ${attempt}/${MAX_AUTOFIX_ATTEMPTS} (${(remaining / 1000 / 60).toFixed(1)}m remaining)...`,\n )\n\n // Run lint:fix and format:fix directly — no LLM needed for mechanical fixes\n const config = getProjectConfig()\n const runFixCmd = (label: string, cmd: string) => {\n const parts = cmd.split(/\\s+/)\n try {\n logger.info(` Running ${cmd}...`)\n execFileSync(parts[0], parts.slice(1), {\n stdio: 'pipe',\n timeout: 2 * 60 * 1000,\n maxBuffer: 10 * 1024 * 1024,\n })\n logger.info(` \\u2713 ${label} completed`)\n } catch {\n logger.info(` \\u2717 ${label} had errors (some may need manual fix)`)\n }\n }\n\n runFixCmd('lint:fix', config.quality.lintFix)\n runFixCmd('format:fix', config.quality.formatFix)\n\n // Re-run verify after fixes\n logger.info(' Re-running verification...')\n if (existsSync(outputFile)) {\n unlinkSync(outputFile)\n }\n\n const elapsedAfter = Date.now() - startTime\n const remainingAfter = totalTimeout - elapsedAfter\n\n if (remainingAfter <= 0) {\n logger.info(` \\u23f1\\ufe0f Aggregate timeout exceeded — stopping before verify re-run`)\n return {\n outcome: 'timed_out',\n reason: `Aggregate timeout exceeded during auto-fix loop`,\n retries: 0,\n }\n }\n\n const reVerify = runVerifyStage(outputFile, undefined, remainingAfter, ctx.taskDir)\n if (reVerify.passed) {\n logger.info(` \\u2705 Verification passed after auto-fix attempt ${attempt}`)\n fixed = true\n break\n } else {\n logger.error(` \\u274c Verification still failing after auto-fix attempt ${attempt}`)\n }\n }\n\n if (!fixed) {\n return {\n outcome: 'failed',\n reason: 'Verification failed after auto-fix attempts',\n retries: 0,\n }\n }\n\n // Commit auto-fix changes\n const commitResult = commitPipelineFiles({\n taskDir: ctx.taskDir,\n taskId: ctx.taskId,\n message: `fix: Auto-fix lint/format for ${ctx.taskId}\\n\\nApply automated lint and format fixes`,\n stagingStrategy: 'tracked+task',\n push: true,\n dryRun: ctx.input.dryRun,\n })\n\n if (!commitResult.success && !commitResult.message.includes('No changes')) {\n logger.error(` \\u274c Failed to commit/push auto-fix changes: ${commitResult.message}`)\n return {\n outcome: 'failed',\n reason: 'Auto-fix changes could not be pushed',\n retries: 0,\n }\n }\n\n return {\n outcome: 'completed',\n retries: 0,\n outputFile: `${def.name}.md`,\n }\n }\n}\n","/**\n * @fileType handler\n * @domain kody | handlers\n * @pattern git-handler\n * @ai-summary Git handlers for commit and PR stages\n */\n\nimport { execFileSync } from 'child_process'\n\nimport type { PipelineContext, StageDefinition, StageResult } from '../engine/types'\nimport { runCommitStage, runPrStage } from '../scripted-stages'\nimport { getDefaultBranch } from '../git-utils'\nimport type { StageHandler } from './handler'\n\n/**\n * Git commit handler\n */\nexport class GitCommitHandler implements StageHandler {\n async execute(_ctx: PipelineContext, _def: StageDefinition): Promise<StageResult> {\n const outputFile = `${_ctx.taskDir}/commit.md`\n\n const result = runCommitStage(_ctx.taskDir, outputFile)\n\n if (!result.success) {\n // \"No changes\" is OK — fix/autofix may produce no file changes.\n // Real \"empty build\" errors are caught by validate-src-changes post-action.\n if (result.message.includes('No changes')) {\n return { outcome: 'completed', retries: 0 }\n }\n return {\n outcome: 'failed',\n reason: result.message,\n retries: 0,\n }\n }\n\n return {\n outcome: 'completed',\n retries: 0,\n }\n }\n}\n\n/**\n * Git PR handler\n *\n * H3 FIX: Uses getDefaultBranch() instead of hardcoded 'origin/dev'\n * to support repos with different default branch names (main, master, etc.)\n */\nexport class GitPrHandler implements StageHandler {\n async execute(ctx: PipelineContext, _def: StageDefinition): Promise<StageResult> {\n const outputFile = `${ctx.taskDir}/pr.md`\n\n // H3 FIX: Get the actual default branch dynamically instead of hardcoding 'dev'\n const defaultBranch = getDefaultBranch()\n\n // Final guard: verify branch has source changes before creating PR\n // C4 FIX: Use execFileSync instead of execSync to prevent shell injection\n try {\n const diff = execFileSync('git', ['diff', '--name-only', `origin/${defaultBranch}...HEAD`], {\n encoding: 'utf-8',\n }).trim()\n const srcChanges = diff.split('\\n').filter((f) => f && !f.startsWith('.tasks/'))\n if (srcChanges.length === 0) {\n return {\n outcome: 'failed',\n reason: 'No source files changed vs base branch — refusing to create empty PR',\n retries: 0,\n }\n }\n } catch {\n // Non-blocking — proceed if git check fails (e.g., shallow clone)\n }\n\n // R5: Pass issueNumber to link PR to the issue\n const result = await runPrStage(ctx.taskDir, outputFile, undefined, ctx.input.issueNumber, {\n fresh: ctx.input.fresh,\n })\n\n if (!result.created && !result.url) {\n return {\n outcome: 'failed',\n reason: result.report || 'PR creation failed',\n retries: 0,\n }\n }\n\n return {\n outcome: 'completed',\n retries: 0,\n }\n }\n}\n","/**\n * @fileType utility\n * @domain ci | kody\n * @pattern clarify-workflow\n * @ai-summary Question/answer workflow for clarification stage - extracted from kody.ts for testability\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { getLatestIssueComment, getLatestApprovalComment } from './github-api'\nimport type { KodyInput } from './kody-utils'\nimport { checkForQuestions } from './content-validators'\nimport { logger } from './logger'\n\n// ============================================================================\n// Safe File Write Helper\n// ============================================================================\n\n/**\n * Safe file write with error logging. Re-throws on failure so callers can handle.\n */\nfunction safeWriteFile(filePath: string, content: string): void {\n try {\n fs.writeFileSync(filePath, content)\n } catch (error) {\n logger.error({ err: error }, `Failed to write file: ${filePath}`)\n throw error\n }\n}\n\n// ============================================================================\n// Answer Extraction\n// ============================================================================\n\n/**\n * Extract the answer from a GitHub comment body\n * The comment format is: /kody [command] [task-id] [optional answer text]\n * Also handles: @kody approve [answer], @kody reject [answer]\n */\nexport function extractAnswerFromComment(commentBody: string): string | null {\n // Decode JSON-encoded body if needed (from jq -Rs .)\n let decoded = commentBody\n if (decoded.startsWith('\"') && decoded.endsWith('\"')) {\n try {\n decoded = JSON.parse(decoded)\n } catch {\n // Use raw value if JSON.parse fails\n }\n }\n\n // Normalize literal \\n to real newlines\n decoded = decoded.replace(/\\\\n/g, '\\n')\n\n // Remove /kody or @kody prefix\n const withoutKody = decoded.replace(/^[\\/]?@?kody\\s*/, '').trim()\n\n // If there's content after the command, treat it as the answer\n if (withoutKody.length > 0) {\n // Remove task-id if present (format: /kody [task-id] or /kody full [task-id])\n const taskIdMatch = withoutKody.match(/^([a-z]+\\s+)?([0-9]{6}-[a-z0-9-]+\\s*)/i)\n let answer = withoutKody\n if (taskIdMatch) {\n answer = withoutKody.slice(taskIdMatch[0].length).trim()\n }\n\n // Also remove approval/rejection keywords (user wrote \"@kody approve\" + answers)\n const lowerAnswer = answer.toLowerCase()\n for (const keyword of [...APPROVAL_KEYWORDS, ...REJECTION_KEYWORDS]) {\n if (lowerAnswer.startsWith(keyword)) {\n answer = answer.slice(keyword.length).trim()\n break\n }\n }\n\n // If there's answer content, return it\n if (answer.length > 0) {\n return answer\n }\n }\n\n return null\n}\n\n// ============================================================================\n// Clarification Handler\n// ============================================================================\n\n/**\n * Result of handling clarification\n */\nexport type ClarifyResult = 'answered' | 'waiting' | 'no-questions'\n\n/**\n * Handle clarification workflow for the spec pipeline.\n * Checks if questions.md exists, extracts answer from comment if provided,\n * and creates clarified.md.\n *\n * @param input - The KodyInput with commentBody and trigger info\n * @param taskDir - Path to the task directory\n * @returns 'answered' if user provided answer, 'waiting' if questions exist, 'no-questions' if no clarification needed\n */\nexport function handleClarification(input: KodyInput, taskDir: string): ClarifyResult {\n const questionsPath = path.join(taskDir, 'questions.md')\n const clarifiedPath = path.join(taskDir, 'clarified.md')\n\n // If questions.md doesn't exist, no clarification needed - create default clarified.md\n if (!fs.existsSync(questionsPath)) {\n if (!fs.existsSync(clarifiedPath)) {\n safeWriteFile(clarifiedPath, '# Clarified\\n\\nUse recommended answers.\\n')\n }\n return 'no-questions'\n }\n\n let answer: string | null = null\n\n // Try to get answer from:\n // 1. Comment body (if user wrote \"/kody answer text\")\n if (input.commentBody && input.triggerType === 'comment') {\n answer = extractAnswerFromComment(input.commentBody)\n }\n\n // 2. Latest comment on the issue (plain text answer)\n if (!answer && input.issueNumber && input.triggerType === 'comment') {\n // Get the latest comment (not from bot) as the answer\n answer = getLatestIssueComment(input.issueNumber, 'github-actions[bot]')\n }\n\n // If we have an answer, create clarified.md\n if (answer) {\n safeWriteFile(clarifiedPath, `# Clarified\\n\\n${answer}\\n`)\n return 'answered'\n }\n\n // Check if there are pending questions\n const hasQuestions = !fs.existsSync(clarifiedPath) && checkForQuestions(questionsPath)\n\n if (hasQuestions) {\n return 'waiting'\n }\n\n // No questions - create default clarified.md\n if (!fs.existsSync(clarifiedPath)) {\n safeWriteFile(clarifiedPath, '# Clarified\\n\\nUse recommended answers.\\n')\n }\n\n return 'no-questions'\n}\n\n// ============================================================================\n// Gate Approval Handler\n// ============================================================================\n\n/**\n * Result of handling gate approval\n */\nexport type GateResult = 'approved' | 'rejected' | 'waiting'\n\n/**\n * Structured gate commands — only `approve` and `reject` are accepted.\n * Previously accepted ambiguous keywords (yes, go, y, continue, no, n, stop, cancel)\n * which could cause accidental approvals/rejections from natural language comments.\n */\nconst APPROVAL_KEYWORDS = ['approve'] as const\nconst REJECTION_KEYWORDS = ['reject'] as const\n\n/**\n * Get the gate file paths for a specific gate point\n */\nfunction getGateFiles(\n taskDir: string,\n gatePoint: string,\n): { requestPath: string; approvedPath: string } {\n const requestPath = path.join(taskDir, `gate-${gatePoint}.md`)\n const approvedPath = path.join(taskDir, `gate-${gatePoint}-approved.md`)\n return { requestPath, approvedPath }\n}\n\n/**\n * Result of detecting approval from comment - includes optional answer content\n */\nexport interface ApprovalDetection {\n status: 'approved' | 'rejected' | null\n /** Answer content after the approve/reject keyword (preserves newlines for multi-line answers) */\n answerContent?: string | null\n}\n\n/**\n * Check if a comment contains structured gate commands (`approve` or `reject`).\n * Only exact commands are accepted — no ambiguous keywords.\n * Also extracts any answer content provided after the keyword (preserves newlines!)\n */\nexport function detectApprovalFromComment(commentBody: string | null): ApprovalDetection {\n if (!commentBody) return { status: null }\n\n // Decode if JSON-encoded\n let decoded = commentBody\n if (decoded.startsWith('\"') && decoded.endsWith('\"')) {\n try {\n decoded = JSON.parse(decoded)\n } catch {\n // Use raw value\n }\n }\n\n // Normalize literal \\n to real newlines (preserving them for answer extraction)\n decoded = decoded.replace(/\\\\n/g, '\\n')\n\n // Get original for answer extraction (before lowercasing)\n const originalWithNewlines = decoded\n\n // Lowercase for keyword matching (but we still check original position)\n const lowerDecoded = decoded.toLowerCase()\n\n // Remove /kody or @kody prefix\n const withoutPrefix = lowerDecoded.replace(/^[\\/]?@?kody\\s*/, '').trim()\n // Also get the original (with case preserved) after prefix removal (use regex with limit)\n const originalWithoutPrefix = originalWithNewlines.replace(/^[\\/]?@?kody\\s*/i, '').trim()\n\n // Check for rejection keywords first (more specific)\n for (const keyword of REJECTION_KEYWORDS) {\n if (\n withoutPrefix === keyword ||\n withoutPrefix.startsWith(keyword + ' ') ||\n withoutPrefix.startsWith(keyword + '\\n')\n ) {\n // Extract any content after the rejection keyword\n const answerContent = extractContentAfterKeyword(originalWithoutPrefix, keyword)\n return { status: 'rejected', answerContent }\n }\n }\n\n // Check for approval keywords\n for (const keyword of APPROVAL_KEYWORDS) {\n if (\n withoutPrefix === keyword ||\n withoutPrefix.startsWith(keyword + ' ') ||\n withoutPrefix.startsWith(keyword + '\\n')\n ) {\n // Extract any content after the approval keyword (this preserves newlines!)\n const answerContent = extractContentAfterKeyword(originalWithoutPrefix, keyword)\n return { status: 'approved', answerContent: answerContent }\n }\n }\n\n return { status: null }\n}\n\n/**\n * Extract content after a keyword (approve/reject) while preserving newlines\n */\nfunction extractContentAfterKeyword(text: string, keyword: string): string | null {\n const lowerText = text.toLowerCase()\n const keywordIndex = lowerText.indexOf(keyword)\n\n if (keywordIndex === -1) return null\n\n // Get everything after the keyword\n const afterKeyword = text.slice(keywordIndex + keyword.length).trim()\n\n // If there's content after the keyword, return it (preserves newlines!)\n if (afterKeyword.length > 0) {\n return afterKeyword\n }\n\n return null\n}\n\n/**\n * Format the gate comment for posting to the issue\n */\nfunction formatGateComment(\n controlMode: string,\n riskLevel: string,\n taskType: string,\n confidence: number,\n scope: string[],\n taskSummary: string,\n gatePoint: string,\n planContent?: string,\n assumptions?: string[],\n reviewQuestions?: string[],\n): string {\n const lines: string[] = []\n\n if (controlMode === 'hard-stop') {\n lines.push('## 🚫 Hard Stop: Approval Required\\n')\n lines.push(\n 'This task has been classified as **high risk** and requires mandatory approval before proceeding.\\n',\n )\n } else {\n lines.push('## 🚦 Risk Gate: Approval Required\\n')\n lines.push(\n 'This task has been classified as **medium risk** and is paused for review before building.\\n',\n )\n }\n\n const scopeDisplay =\n scope.length <= 5 ? scope.map((f) => `\\`${f}\\``).join(', ') : `${scope.length} files`\n\n lines.push('| Field | Value |')\n lines.push('|-------|-------|')\n lines.push(`| **Control Mode** | ${controlMode} |`)\n lines.push(`| **Risk Level** | ${riskLevel} |`)\n lines.push(`| **Task Type** | ${taskType} |`)\n lines.push(`| **Confidence** | ${confidence} |`)\n lines.push(`| **Scope** | ${scopeDisplay} |`)\n lines.push('')\n\n lines.push('### Task Summary')\n lines.push(`> ${taskSummary.split('\\n')[0]}`)\n lines.push('')\n\n if (assumptions && assumptions.length > 0) {\n lines.push('### Assumptions')\n for (const assumption of assumptions) {\n lines.push(`- ${assumption}`)\n }\n lines.push('')\n }\n\n if (reviewQuestions && reviewQuestions.length > 0) {\n lines.push('### Review Questions')\n reviewQuestions.forEach((question, index) => {\n lines.push(`${index + 1}. ${question}`)\n })\n lines.push('')\n }\n\n if (planContent && gatePoint === 'architect') {\n lines.push('### Plan')\n // First 20 lines of plan\n const planLines = planContent.split('\\n').slice(0, 20).join('\\n')\n lines.push('```')\n lines.push(planLines)\n lines.push('```')\n lines.push('')\n }\n\n lines.push('---')\n lines.push('')\n lines.push('Reply `approve` to proceed.')\n lines.push('Reply `reject` to cancel.')\n\n return lines.join('\\n')\n}\n\n/**\n * Handle gate approval workflow for risk-gated and hard-stop modes.\n * Similar to clarification workflow but for approval gates.\n *\n * @param input - The KodyInput with commentBody and trigger info\n * @param taskDir - Path to the task directory\n * @param gatePoint - Which gate: 'taskify' or 'architect'\n * @param taskDef - The task definition (for context in the gate comment)\n * @param planContent - Optional plan content (for architect gate)\n * @returns 'approved' if user approved, 'rejected' if user rejected, 'waiting' if awaiting approval\n */\nexport function handleGateApproval(\n input: KodyInput,\n taskDir: string,\n gatePoint: string,\n taskDef: { risk_level: string; task_type: string; confidence: number; scope: string[] },\n planContent?: string,\n): GateResult {\n const { requestPath, approvedPath } = getGateFiles(taskDir, gatePoint)\n\n // If already approved, return approved\n if (fs.existsSync(approvedPath)) {\n return 'approved'\n }\n\n // Check for approval/rejection in the current comment\n const approval = detectApprovalFromComment(input.commentBody || null)\n\n // Also check latest issue comment if not found in current trigger\n if (!approval.status && input.issueNumber && input.triggerType === 'comment') {\n // Use getLatestApprovalComment to find /kody approve or /kody reject commands\n const latestComment = getLatestApprovalComment(input.issueNumber, 'github-actions[bot]')\n const latestApproval = detectApprovalFromComment(latestComment)\n if (latestApproval.status) {\n // User replied with approve/reject - write the approved file\n if (latestApproval.status === 'approved') {\n const approvedBy = input.actor || 'unknown'\n const approvedAt = new Date().toISOString()\n safeWriteFile(\n approvedPath,\n `# Gate Approved\\n\\nApproved at ${gatePoint} gate.\\nApproved by: @${approvedBy}\\nApproved at: ${approvedAt}\\n`,\n )\n // If there's also answer content in the comment, create clarified.md\n if (latestApproval.answerContent) {\n const clarifiedPath = path.join(taskDir, 'clarified.md')\n safeWriteFile(clarifiedPath, `# Clarified\\n\\n${latestApproval.answerContent}\\n`)\n }\n return 'approved'\n } else {\n // Write rejection marker\n const rejectedBy = input.actor || 'unknown'\n safeWriteFile(\n requestPath,\n `# Gate Rejected\\n\\nRejected at ${gatePoint} gate.\\nRejected by: @${rejectedBy}\\n`,\n )\n return 'rejected'\n }\n }\n }\n\n // If we have approval in current trigger\n if (approval.status === 'approved') {\n const approvedBy = input.actor || 'unknown'\n const approvedAt = new Date().toISOString()\n safeWriteFile(\n approvedPath,\n `# Gate Approved\\n\\nApproved at ${gatePoint} gate.\\nApproved by: @${approvedBy}\\nApproved at: ${approvedAt}\\n`,\n )\n // If there's also answer content in the comment, create clarified.md\n if (approval.answerContent) {\n const clarifiedPath = path.join(taskDir, 'clarified.md')\n safeWriteFile(clarifiedPath, `# Clarified\\n\\n${approval.answerContent}\\n`)\n }\n return 'approved'\n } else if (approval.status === 'rejected') {\n const rejectedBy = input.actor || 'unknown'\n safeWriteFile(\n requestPath,\n `# Gate Rejected\\n\\nRejected at ${gatePoint} gate.\\nRejected by: @${rejectedBy}\\n`,\n )\n return 'rejected'\n }\n\n // If request file already exists, we're waiting\n if (fs.existsSync(requestPath)) {\n return 'waiting'\n }\n\n // First time hitting the gate - create request and return waiting\n // Read task summary from task.md (skip markdown headers and blank lines)\n const taskMdPath = path.join(taskDir, 'task.md')\n let taskSummary = 'See task.md for details'\n if (fs.existsSync(taskMdPath)) {\n const taskContent = fs.readFileSync(taskMdPath, 'utf-8')\n const contentLine = taskContent\n .split('\\n')\n .find((line) => line.trim().length > 0 && !line.trim().startsWith('#'))\n taskSummary = contentLine?.trim() || taskSummary\n }\n\n // Read task.json for assumptions and review_questions\n const taskJsonPath = path.join(taskDir, 'task.json')\n let assumptions: string[] = []\n let reviewQuestions: string[] = []\n if (fs.existsSync(taskJsonPath)) {\n try {\n const taskJson = JSON.parse(fs.readFileSync(taskJsonPath, 'utf-8'))\n if (Array.isArray(taskJson.assumptions)) {\n assumptions = taskJson.assumptions\n }\n if (Array.isArray(taskJson.review_questions)) {\n reviewQuestions = taskJson.review_questions\n }\n } catch {\n // Ignore parse errors\n }\n }\n\n const comment = formatGateComment(\n taskDef.risk_level === 'high' ? 'hard-stop' : 'risk-gated',\n taskDef.risk_level,\n taskDef.task_type,\n taskDef.confidence,\n taskDef.scope,\n taskSummary,\n gatePoint,\n planContent,\n assumptions,\n reviewQuestions,\n )\n\n // Write gate request file\n safeWriteFile(requestPath, `# Gate Request\\n\\n${comment}\\n`)\n\n // Return waiting - caller will post the comment to the issue\n return 'waiting'\n}\n","/**\n * @fileType handler\n * @domain kody | handlers\n * @pattern gate-handler\n * @ai-summary Gate handler for approval workflow\n */\n\nimport type { PipelineContext, StageDefinition, StageResult } from '../engine/types'\nimport { handleGateApproval } from '../clarify-workflow'\nimport { resolveControlMode } from '../pipeline-utils'\nimport type { StageHandler } from './handler'\n\n/**\n * Gate handler - resolves controlMode dynamically and handles approval\n */\nexport class GateHandler implements StageHandler {\n async execute(ctx: PipelineContext, def: StageDefinition): Promise<StageResult> {\n // Guard: taskDef must be loaded before gate can run\n if (!ctx.taskDef) {\n return {\n outcome: 'failed',\n reason: 'task.json not loaded - gate stage requires task definition',\n retries: 0,\n }\n }\n\n // Resolve controlMode dynamically (G42)\n const controlMode = resolveControlMode(ctx.taskDef, ctx.input.controlMode)\n\n // Determine gate name from stage name (architect or taskify)\n const gate = def.name === 'architect' ? 'architect' : 'taskify'\n\n // Call gate approval handler\n const gateResult = handleGateApproval(ctx.input, ctx.taskDir, gate, ctx.taskDef)\n\n if (gateResult === 'waiting') {\n return {\n outcome: 'paused',\n reason: `${controlMode} gate: awaiting approval`,\n retries: 0,\n }\n }\n\n if (gateResult === 'rejected') {\n return {\n outcome: 'failed',\n reason: `Task rejected at ${controlMode} gate`,\n retries: 0,\n }\n }\n\n // Approved\n return {\n outcome: 'completed',\n retries: 0,\n }\n }\n}\n","/**\n * @fileType interface\n * @domain kody | handlers\n * @pattern handler-registry\n * @ai-summary Handler interface and registry for pipeline stages\n */\n\nimport type { PipelineContext, StageDefinition, StageResult, StageType } from '../engine/types'\nimport type { StageName } from '../stages/registry'\nimport { AgentHandler } from './agent-handler'\nimport { ScriptedVerifyHandler } from './scripted-handler'\nimport { GitCommitHandler, GitPrHandler } from './git-handler'\nimport { GateHandler } from './gate-handler'\n\n/**\n * Interface for all stage handlers\n */\nexport interface StageHandler {\n execute(ctx: PipelineContext, def: StageDefinition): Promise<StageResult>\n}\n\n// ============================================================================\n// Handler Registry\n// ============================================================================\n\n/**\n * Get handler for a stage based on its name and type.\n * Uses name-based lookup first (R3), then falls back to type-based default.\n */\nexport function getHandler(stageName: StageName, stageType: StageType): StageHandler {\n // Named handlers first - for stages that need special handling\n switch (stageName) {\n case 'commit':\n return new GitCommitHandler()\n case 'pr':\n return new GitPrHandler()\n case 'verify':\n return new ScriptedVerifyHandler()\n }\n\n // Type-based default handlers\n switch (stageType) {\n case 'agent':\n return new AgentHandler()\n case 'scripted':\n return new ScriptedVerifyHandler()\n case 'gate':\n return new GateHandler()\n case 'git':\n // Default git handler - shouldn't reach here normally\n return new GitCommitHandler()\n default:\n // R12: Exhaustiveness check - fail at compile time if new StageType is added\n const _exhaustive: never = stageType\n throw new Error(`Unknown stage type: ${stageType}`)\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Validates task.json after taskify stage, deletes invalid file for retry\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext } from '../../engine/types'\nimport { readTask } from '../../pipeline-utils'\n\nexport async function executeValidateTaskJson(ctx: PipelineContext): Promise<void> {\n try {\n readTask(ctx.taskDir)\n logger.info(' ✓ task.json validated')\n } catch (error) {\n // G13: Delete invalid file so retry can recreate\n const taskJsonPath = path.join(ctx.taskDir, 'task.json')\n if (fs.existsSync(taskJsonPath)) {\n fs.unlinkSync(taskJsonPath)\n }\n const msg = error instanceof Error ? error.message : String(error)\n throw new Error(`Invalid task.json: ${msg}`)\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Sets classification labels (type, risk, complexity, domain) on GitHub issue\n */\n\nimport type { PipelineContext } from '../../engine/types'\nimport { readTask } from '../../pipeline-utils'\nimport { setClassificationLabels } from '../../github-api'\n\nexport async function executeSetClassificationLabels(ctx: PipelineContext): Promise<void> {\n const taskDef = readTask(ctx.taskDir)\n if (ctx.input.issueNumber && taskDef) {\n setClassificationLabels(ctx.input.issueNumber, {\n task_type: taskDef.task_type,\n risk_level: taskDef.risk_level,\n complexity: taskDef.complexity,\n primary_domain: taskDef.primary_domain,\n })\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Builds promoted stub files for stages skipped via input_quality.skip_stages\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\n/**\n * Build a promoted stub file for a skipped stage.\n * Includes sections that downstream validators expect.\n */\nexport function buildPromotedStub(stage: string, taskDir: string): string {\n const title = stage.charAt(0).toUpperCase() + stage.slice(1)\n\n if (stage === 'spec') {\n // Gap validator checks for ## Requirements or ## Acceptance Criteria\n // Pull description from task.md if available\n const taskMdPath = path.join(taskDir, 'task.md')\n let description = 'See task.md and task.json for full details.'\n if (fs.existsSync(taskMdPath)) {\n description = fs.readFileSync(taskMdPath, 'utf-8')\n }\n return `# Specification (promoted)\n\nSkipped via input_quality — taskify determined spec is unnecessary.\n\n## Requirements\n\n${description}\n\n## Acceptance Criteria\n\n- [ ] Fix applied as described in task.md\n- [ ] TypeScript compilation passes\n- [ ] Unit tests pass\n`\n }\n\n if (stage === 'architect' || stage === 'plan-gap') {\n // Build stage reads plan.md; plan-gap validator checks plan.md exists\n return `# ${title} (promoted)\n\nSkipped via input_quality — taskify determined this stage is unnecessary.\nSee task.json input_quality.reasoning for details.\n\n## Changes\n\nSee task.md for implementation details.\n`\n }\n\n // Generic stub for other stages\n return `# ${title} (promoted)\n\nSkipped via input_quality — taskify determined this stage is unnecessary.\nSee task.json input_quality.reasoning for details.\n`\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Resolves pipeline profile (standard/lightweight) based on task definition,\n * triggers two-phase pipeline rebuild, creates promoted stubs for skipped stages\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext } from '../../engine/types'\nimport { readTask } from '../../pipeline-utils'\nimport { setProfileLabel } from '../../github-api'\nimport { buildPromotedStub } from './promoted-stub'\n\nexport async function executeResolveProfile(ctx: PipelineContext): Promise<void> {\n const taskDef = readTask(ctx.taskDir)\n if (taskDef) {\n // Apply --complexity override if provided (for testing/debugging)\n if (ctx.input.complexityOverride !== undefined) {\n const oldComplexity = taskDef.complexity\n taskDef.complexity = ctx.input.complexityOverride\n taskDef.complexity_reasoning = `Override via --complexity=${ctx.input.complexityOverride}`\n if (oldComplexity !== undefined) {\n logger.info(` ℹ️ Complexity override: ${oldComplexity} → ${ctx.input.complexityOverride}`)\n } else {\n logger.info(` ℹ️ Complexity override applied: ${ctx.input.complexityOverride}`)\n }\n }\n // Update ctx.taskDef so subsequent post-actions can access it\n ctx.taskDef = taskDef\n const { resolvePipelineProfile, getComplexityTier } = await import('../../pipeline-utils')\n ctx.profile = resolvePipelineProfile(taskDef)\n // Set profile label on the issue\n if (ctx.input.issueNumber) {\n setProfileLabel(ctx.input.issueNumber, ctx.profile)\n }\n // Signal engine to rebuild pipeline with new profile (two-phase construction)\n ctx.pipelineNeedsRebuild = true\n if (taskDef.complexity !== undefined) {\n const tier = getComplexityTier(taskDef.complexity)\n logger.info(` ℹ️ Complexity: ${taskDef.complexity} (${tier}) → profile: ${ctx.profile}`)\n\n // R2-FIX #6: Warn when complexity seems mismatched with profile.\n // A lightweight profile with high complexity may skip important stages.\n if (ctx.profile === 'lightweight' && taskDef.complexity >= 35) {\n logger.warn(\n ` ⚠️ Profile/complexity mismatch: lightweight profile with complexity ${taskDef.complexity} (complex tier). ` +\n `Some stages may be unexpectedly skipped. Consider overriding with --profile=standard.`,\n )\n }\n } else {\n logger.info(\n ` ℹ️ Resolved profile: ${ctx.profile} (no complexity score, using legacy heuristic)`,\n )\n }\n\n // Create stub promoted files for stages in skip_stages\n // The skip condition checks file existence, so we must ensure the file exists\n // Stubs must include sections that downstream validators expect\n const skipStages = taskDef.input_quality?.skip_stages ?? []\n for (const stage of skipStages) {\n const outputFile = path.join(ctx.taskDir, `${stage}.md`)\n if (!fs.existsSync(outputFile)) {\n const stub = buildPromotedStub(stage, ctx.taskDir)\n fs.writeFileSync(outputFile, stub)\n logger.info(` ℹ️ Created promoted stub: ${stage}.md`)\n }\n }\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Gate check lifecycle event — pauses pipeline for human approval,\n * posts gate comment on GitHub, writes paused state, throws PipelinePausedError\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext, PostAction, PipelineStateV2 } from '../../engine/types'\nimport { PipelinePausedError } from '../../engine/types'\nimport { readTask } from '../../pipeline-utils'\nimport { commitPipelineFiles } from '../../git-utils'\nimport { handleGateApproval } from '../../clarify-workflow'\nimport {\n extractGateCommentBody,\n postComment,\n addIssueLabel,\n removeIssueLabel,\n GATE_LABELS,\n} from '../../github-api'\nimport { updateStage, completeState, writeState, appendActorEvent } from '../../engine/status'\n\nexport async function executeCheckGate(\n ctx: PipelineContext,\n action: PostAction & { type: 'check-gate' },\n state: PipelineStateV2 | null,\n): Promise<void> {\n // BUG-F fix: taskDef might be null if resolve-profile hasn't run yet\n const taskDef = ctx.taskDef ?? readTask(ctx.taskDir)\n if (!taskDef) {\n throw new Error(`Cannot check gate \"${action.gate}\": task.json not found or invalid`)\n }\n // Skip gate when controlMode is 'auto' (low risk tasks don't need approval)\n const { resolveControlMode } = await import('../../pipeline-utils')\n const controlMode = resolveControlMode(taskDef, ctx.input.controlMode)\n if (controlMode === 'auto') {\n logger.info(` ✓ gate ${action.gate} skipped (controlMode: auto)`)\n return\n }\n const gateResult = handleGateApproval(ctx.input, ctx.taskDir, action.gate, taskDef)\n\n // Determine gate label based on risk level\n const gateLabel = taskDef.risk_level === 'high' ? GATE_LABELS.HARD_STOP : GATE_LABELS.RISK_GATED\n\n if (gateResult === 'waiting') {\n // Add gate label for dashboard visibility\n if (ctx.input.issueNumber) {\n addIssueLabel(ctx.input.issueNumber, gateLabel)\n }\n // Read gate file and extract comment body\n const gateFilePath = path.join(ctx.taskDir, `gate-${action.gate}.md`)\n if (fs.existsSync(gateFilePath)) {\n const gateContent = fs.readFileSync(gateFilePath, 'utf-8')\n const commentBody = extractGateCommentBody(gateContent)\n if (ctx.input.issueNumber && commentBody) {\n postComment(ctx.input.issueNumber, commentBody)\n }\n }\n // Pre-write paused state to status.json BEFORE commit+push,\n // so the persisted status.json on the branch reflects 'paused' (not 'running').\n // The state machine will also set paused after PipelinePausedError, but that\n // only writes locally — the commit here is what the next CI run reads.\n const currentState = state\n if (currentState) {\n let pausedState = updateStage(currentState, action.gate, { state: 'paused' })\n pausedState = completeState(pausedState, 'paused')\n writeState(ctx.taskId, pausedState)\n }\n\n // Commit and pause\n commitPipelineFiles({\n taskDir: ctx.taskDir,\n taskId: ctx.taskId,\n message: `ci(kody): pause at ${action.gate} gate for ${ctx.taskId}`,\n ensureBranch: true,\n stagingStrategy: 'task-only',\n push: true,\n isCI: !ctx.input.local,\n dryRun: ctx.input.dryRun,\n })\n throw new PipelinePausedError(`${action.gate} gate: awaiting approval for ${ctx.taskId}`)\n }\n if (gateResult === 'rejected') {\n // Remove gate label when rejected\n if (ctx.input.issueNumber) {\n removeIssueLabel(ctx.input.issueNumber, GATE_LABELS.HARD_STOP)\n removeIssueLabel(ctx.input.issueNumber, GATE_LABELS.RISK_GATED)\n }\n // Record gate rejection actor event\n if (ctx.actor && state) {\n appendActorEvent(ctx.taskId, state, {\n action: 'gate-rejected',\n actor: ctx.actor,\n timestamp: new Date().toISOString(),\n stage: action.gate,\n })\n }\n throw new Error(`Task rejected at ${action.gate} gate`)\n }\n // Approved - remove gate label so dashboard shows it's no longer waiting\n if (ctx.input.issueNumber) {\n removeIssueLabel(ctx.input.issueNumber, GATE_LABELS.HARD_STOP)\n removeIssueLabel(ctx.input.issueNumber, GATE_LABELS.RISK_GATED)\n }\n // Record gate approval actor event\n if (ctx.actor && state) {\n appendActorEvent(ctx.taskId, state, {\n action: 'gate-approved',\n actor: ctx.actor,\n timestamp: new Date().toISOString(),\n stage: action.gate,\n })\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Commits and pushes pipeline task files to remote branch\n */\n\nimport type { PipelineContext, PostAction } from '../../engine/types'\nimport { commitPipelineFiles } from '../../git-utils'\n\nexport async function executeCommitTaskFiles(\n ctx: PipelineContext,\n action: PostAction & { type: 'commit-task-files' },\n): Promise<void> {\n // G18: Skip if localOnly and not in local mode\n if (action.localOnly && !ctx.input.local) {\n return\n }\n // Skip if dryRun\n if (ctx.input.dryRun) {\n return\n }\n\n const result = commitPipelineFiles({\n taskDir: ctx.taskDir,\n taskId: ctx.taskId,\n message: action.commitMessage || `ci(kody): commit task files for ${ctx.taskId}`,\n ensureBranch: action.ensureBranch,\n cleanDirtyState: action.cleanDirtyState,\n stagingStrategy: action.stagingStrategy === 'tracked-only' ? 'all' : action.stagingStrategy,\n push: action.push,\n isCI: !ctx.input.local,\n dryRun: ctx.input.dryRun,\n })\n if (!result.success) {\n throw new Error(`commit-task-files failed: ${result.message}`)\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline | errors\n * @pattern error-classification\n * @ai-summary Classifies build/test/lint errors and formats them as actionable markdown for autofix agent\n */\n\nimport { MAX_GATE_OUTPUT_CHARS } from '../config/constants'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type ErrorCategory =\n | 'type_error'\n | 'lint_error'\n | 'format_error'\n | 'test_failure'\n | 'unknown'\n\nexport interface ClassifiedError {\n category: ErrorCategory\n summary: string\n fullOutput: string\n fileHints: string[]\n fixInstructions: string\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst MAX_OUTPUT_LENGTH = MAX_GATE_OUTPUT_CHARS\nconst MAX_SUMMARY_LENGTH = 500\n\nconst FIX_INSTRUCTIONS: Record<ErrorCategory, string> = {\n type_error:\n 'Fix TypeScript type errors. Check the affected files for type mismatches, missing imports, or incorrect function signatures.',\n lint_error: 'Fix lint errors. Run `pnpm lint:fix` first, then manually fix any remaining issues.',\n format_error: 'Fix format errors. Run `pnpm format:fix` to auto-format all files.',\n test_failure:\n 'Fix failing test(s). The tests may not match the implementation. Update the tests to correctly reflect what the code actually does.',\n unknown: 'Unknown error type. Read the full output below and fix the underlying issue.',\n}\n\n// ============================================================================\n// Regex patterns\n// ============================================================================\n\n/** Matches TSC output like: src/foo.ts(10,5): error TS2345: ... */\nconst TSC_FILE_REGEX = /([^\\s:]+\\.tsx?)\\(\\d+,\\d+\\)/g\n\n/** Matches vitest FAIL lines like: FAIL tests/unit/foo.test.ts > should work */\nconst TEST_FILE_REGEX = /(?:FAIL|❌)\\s+(\\S+\\.(?:test|spec)\\.\\w+)/g\n\n/** Matches eslint file paths from output like: /path/to/src/foo.ts */\nconst LINT_FILE_REGEX = /^(\\/\\S+\\.(?:ts|tsx|js|jsx))$/gm\n\n/** Matches prettier [warn] lines with file paths */\nconst FORMAT_FILE_REGEX = /\\[warn\\]\\s+(\\S+\\.\\w+)/g\n\n// ============================================================================\n// Functions\n// ============================================================================\n\n/**\n * Extract specific test details for smarter autofix guidance\n */\nfunction extractTestDetails(rawOutput: string): { summary?: string; specificFix?: string } {\n // Extract test names\n const testNameMatch = rawOutput.match(/(?:FAIL|❌).*?>\\s*(.+)$/m)\n const testName = testNameMatch?.[1]?.trim()\n\n // Extract expected vs actual\n const expectedMatch = rawOutput.match(/Expected:?\\s*(.+)/i)\n const actualMatch = rawOutput.match(/Actual:?\\s*(.+)/i)\n\n // Check for common fixable errors\n let specificFix: string | undefined\n\n if (rawOutput.includes('Cannot find module')) {\n const moduleMatch = rawOutput.match(/Cannot find module ['\"]([^'\"]+)['\"]/)\n const moduleName = moduleMatch?.[1]\n if (moduleName) {\n specificFix =\n \"Missing import: Install '\" + moduleName + \"' or add to package.json dependencies.\"\n }\n }\n\n if (rawOutput.includes('is not defined') || rawOutput.includes('is not declared')) {\n specificFix =\n 'Reference error: The variable/function is not defined. Check imports or declare the variable.'\n }\n\n if (rawOutput.includes('is not a function') || rawOutput.includes('is not a constructor')) {\n specificFix = 'Type error: Check the import - may need .default or the export name is wrong.'\n }\n\n if (rawOutput.includes('TypeError') && rawOutput.includes('undefined')) {\n specificFix =\n 'Undefined error: Check if variable is initialized before use, or if property exists.'\n }\n\n if (rawOutput.includes('expected') && rawOutput.includes('received')) {\n specificFix =\n 'Assertion mismatch: Update source code to match expected behavior, OR if test is wrong, fix the test.'\n }\n\n if (rawOutput.includes('timeout') || rawOutput.includes('Timed out')) {\n specificFix =\n 'Test timeout: The test or the code it tests is too slow. Consider increasing timeout or optimizing.'\n }\n\n if (rawOutput.includes('ENOENT') || rawOutput.includes('No such file')) {\n specificFix =\n 'Missing file: The test references a file that does not exist. Check the path or create the file.'\n }\n\n // Build summary with test name if found\n let summary: string | undefined\n if (testName) {\n summary = 'Test: ' + testName\n if (expectedMatch && actualMatch) {\n summary += ' | Expected: ' + expectedMatch[1].trim() + ' | Actual: ' + actualMatch[1].trim()\n }\n }\n\n return { summary, specificFix }\n}\n\n/**\n * Classify a raw error output string into a structured error object.\n *\n * @param rawOutput - The raw stderr/stdout from the failed command\n * @param source - What generated this output: 'tsc', 'test', 'lint', 'format'\n */\nexport function classifyError(rawOutput: string, source: string): ClassifiedError {\n if (!rawOutput || rawOutput.trim().length === 0) {\n return {\n category: 'unknown',\n summary: 'Empty error output',\n fullOutput: '',\n fileHints: [],\n fixInstructions: FIX_INSTRUCTIONS.unknown,\n }\n }\n\n const truncatedOutput =\n rawOutput.length > MAX_OUTPUT_LENGTH ? rawOutput.slice(0, MAX_OUTPUT_LENGTH) : rawOutput\n\n const summary =\n rawOutput.length > MAX_SUMMARY_LENGTH ? rawOutput.slice(0, MAX_SUMMARY_LENGTH) : rawOutput\n\n switch (source) {\n case 'tsc': {\n const fileHints = extractUniqueFiles(rawOutput, TSC_FILE_REGEX)\n return {\n category: 'type_error',\n summary,\n fullOutput: truncatedOutput,\n fileHints,\n fixInstructions: FIX_INSTRUCTIONS.type_error,\n }\n }\n\n case 'test': {\n const fileHints = extractUniqueFiles(rawOutput, TEST_FILE_REGEX)\n\n // Extract specific test details for better autofix guidance\n const testDetails = extractTestDetails(rawOutput)\n const fixInstructions = testDetails.specificFix\n ? testDetails.specificFix\n : FIX_INSTRUCTIONS.test_failure\n\n return {\n category: 'test_failure',\n summary: testDetails.summary || summary,\n fullOutput: truncatedOutput,\n fileHints,\n fixInstructions,\n }\n }\n\n case 'lint': {\n const fileHints = extractUniqueFiles(rawOutput, LINT_FILE_REGEX)\n return {\n category: 'lint_error',\n summary,\n fullOutput: truncatedOutput,\n fileHints,\n fixInstructions: FIX_INSTRUCTIONS.lint_error,\n }\n }\n\n case 'format': {\n const fileHints = extractUniqueFiles(rawOutput, FORMAT_FILE_REGEX)\n return {\n category: 'format_error',\n summary,\n fullOutput: truncatedOutput,\n fileHints,\n fixInstructions: FIX_INSTRUCTIONS.format_error,\n }\n }\n\n default: {\n return {\n category: 'unknown',\n summary,\n fullOutput: truncatedOutput,\n fileHints: [],\n fixInstructions: FIX_INSTRUCTIONS.unknown,\n }\n }\n }\n}\n\n/**\n * Format an array of classified errors into a markdown document for the autofix agent.\n *\n * @param errors - Array of classified errors from failed quality gates\n * @param attempt - Current attempt number (1-indexed)\n * @param maxAttempts - Maximum number of autofix attempts\n */\nexport function formatErrorsAsMarkdown(\n errors: ClassifiedError[],\n attempt: number,\n maxAttempts: number,\n): string {\n const sections = errors.map((error, i) => {\n const fileList =\n error.fileHints.length > 0\n ? '\\n**Affected Files**:\\n' + error.fileHints.map((f) => '- `' + f + '`').join('\\n')\n : ''\n\n return (\n '## Error ' +\n (i + 1) +\n ': ' +\n error.category +\n '\\n\\n' +\n '**Fix Instructions**: ' +\n error.fixInstructions +\n '\\n' +\n fileList +\n '\\n\\n' +\n '**Error Output**:\\n' +\n '```\\n' +\n error.fullOutput +\n '```\\n'\n )\n })\n\n return (\n '# Build Errors\\n\\n' +\n 'Attempt ' +\n attempt +\n '/' +\n maxAttempts +\n '. Fix the errors below and the quality gates will be re-run.\\n\\n' +\n sections.join('\\n---\\n\\n')\n )\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Extract unique file paths from a string using a regex.\n * The regex must have a capture group for the file path.\n */\nfunction extractUniqueFiles(text: string, regex: RegExp): string[] {\n const files = new Set<string>()\n let match: RegExpExecArray | null\n\n // Reset regex state (global regexes are stateful)\n regex.lastIndex = 0\n\n while ((match = regex.exec(text)) !== null) {\n if (match[1]) {\n files.add(match[1])\n }\n }\n\n return Array.from(files)\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Quality gate lifecycle events — runs tsc, unit tests, and autofix feedback loops.\n * Also includes mechanical autofix (lint:fix + format:fix).\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { execFileSync } from 'child_process'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext, PostAction, PipelineStateV2 } from '../../engine/types'\nimport { updateStage, writeState } from '../../engine/status'\nimport { classifyError, formatErrorsAsMarkdown } from '../error-classifier'\nimport { runAgentWithFileWatch } from '../../agent-runner'\nimport { getStageTimeout } from '../../stages/registry'\n\nexport async function executeRunTsc(ctx: PipelineContext): Promise<void> {\n if (ctx.input.dryRun) return\n\n logger.info(' Running tsc...')\n try {\n execFileSync('pnpm', ['-s', 'tsc', '--noEmit'], {\n encoding: 'utf-8',\n maxBuffer: 10 * 1024 * 1024,\n })\n logger.info(' ✓ tsc passed')\n } catch (error) {\n const err = error as { stdout?: string; stderr?: string; message?: string }\n const output = (err.stdout || '') + (err.stderr || '') || err.message || ''\n throw new Error(`TypeScript compilation failed:\\n${output.slice(0, 3000)}`)\n }\n}\n\nexport async function executeRunUnitTests(ctx: PipelineContext): Promise<void> {\n if (ctx.input.dryRun) return\n\n logger.info(' Running unit tests...')\n try {\n execFileSync('pnpm', ['-s', 'test:unit'], {\n encoding: 'utf-8',\n maxBuffer: 10 * 1024 * 1024,\n })\n logger.info(' ✓ Unit tests passed')\n } catch (error) {\n // G25: Include output text (3000 chars) for supervisor retry\n const err = error as { stdout?: string; stderr?: string; message?: string }\n const output = (err.stdout || '') + (err.stderr || '') + (err.message || '')\n throw new Error(`Unit tests failed after build. Fix and re-run.\\n\\n${output.slice(0, 3000)}`)\n }\n}\n\nexport async function executeRunQualityWithAutofix(\n ctx: PipelineContext,\n action: PostAction & { type: 'run-quality-with-autofix' },\n state: PipelineStateV2 | null,\n): Promise<void> {\n if (ctx.input.dryRun) return\n\n type GateResult = {\n name: string\n command: string\n source: 'tsc' | 'lint' | 'format' | 'test'\n passed: boolean\n error?: string\n }\n\n // Helper: split a simple shell command into program + args for execFileSync\n const parseCommand = (cmd: string): { program: string; args: string[] } => {\n const parts = cmd.split(/\\s+/).filter(Boolean)\n return { program: parts[0], args: parts.slice(1) }\n }\n\n const runGates = (gates: typeof action.gates): GateResult[] => {\n return gates.map((gate) => {\n try {\n logger.info(` Running ${gate.name}...`)\n const { program, args } = parseCommand(gate.command)\n execFileSync(program, args, {\n stdio: 'pipe',\n timeout: 5 * 60 * 1000, // 5 minutes per gate\n maxBuffer: 10 * 1024 * 1024, // 10MB buffer\n })\n logger.info(` ✓ ${gate.name} passed`)\n return { ...gate, passed: true }\n } catch (error) {\n const err = error as {\n stdout?: Buffer | string\n stderr?: Buffer | string\n message?: string\n }\n const stdout = err.stdout\n ? Buffer.isBuffer(err.stdout)\n ? err.stdout.toString()\n : err.stdout\n : ''\n const stderr = err.stderr\n ? Buffer.isBuffer(err.stderr)\n ? err.stderr.toString()\n : err.stderr\n : ''\n const output = stdout + stderr + (err.message || '')\n logger.info(` ✗ ${gate.name} failed`)\n const truncated = output.slice(-2000).trim()\n if (truncated) {\n logger.info(` Error output (last 2000 chars):\\n${truncated}`)\n }\n return { ...gate, passed: false, error: output }\n }\n })\n }\n\n // Initial run — all gates\n let results = runGates(action.gates)\n let failures = results.filter((r) => !r.passed)\n\n if (failures.length === 0) return // All passed on first try\n\n // Track feedback loop metrics for status.json observability\n let completedLoops = 0\n const encounteredErrors = new Set<string>()\n\n // Build agent feedback loop — the build agent wrote the code, so it fixes\n // ALL failures (tsc, lint, format, tests). No separate autofix agent needed\n // here because the build agent has full context (spec, plan, code intent).\n for (let attempt = 1; attempt <= action.maxFeedbackLoops; attempt++) {\n logger.info(\n `\\n🔧 Build agent fix attempt ${attempt}/${action.maxFeedbackLoops} (${failures.map((f) => f.name).join(', ')})...`,\n )\n\n // Classify errors and write build-errors.md for the build agent to read\n const errors = failures.map((f) => classifyError(f.error || '', f.source))\n errors.forEach((e) => encounteredErrors.add(e.category))\n completedLoops = attempt\n const markdown = formatErrorsAsMarkdown(errors, attempt, action.maxFeedbackLoops)\n const errorsFile = path.join(ctx.taskDir, 'build-errors.md')\n fs.writeFileSync(errorsFile, markdown)\n\n // Re-invoke the build agent — it has spec, plan, and wrote the code\n const buildOutput = path.join(ctx.taskDir, 'build.md')\n const buildTimeout = getStageTimeout('build')\n let buildResult: { succeeded: boolean } | undefined\n try {\n buildResult = await runAgentWithFileWatch(ctx.input, 'build', buildOutput, buildTimeout, {\n backend: ctx.backend,\n })\n } catch (agentError) {\n logger.error(\n { err: agentError },\n ` ❌ Build agent threw exception (fix attempt ${attempt}/${action.maxFeedbackLoops})`,\n )\n continue\n }\n\n if (!buildResult?.succeeded) {\n logger.error(` ❌ Build agent failed (fix attempt ${attempt})`)\n continue\n }\n\n // Re-run ALL gates after build agent changes\n results = runGates(action.gates)\n failures = results.filter((r) => !r.passed)\n\n if (failures.length === 0) {\n logger.info(` ✅ All quality gates passed after build agent fix attempt ${attempt}`)\n if (fs.existsSync(errorsFile)) fs.unlinkSync(errorsFile)\n break\n }\n }\n\n // Record feedback loop metrics in status.json for observability\n if (completedLoops > 0) {\n const currentState = state\n if (currentState && currentState.stages?.build) {\n const updatedState = updateStage(currentState, 'build', {\n feedbackLoops: completedLoops,\n feedbackErrors: Array.from(encounteredErrors),\n })\n writeState(ctx.taskId, updatedState)\n }\n }\n\n if (failures.length > 0) {\n const errorsFile = path.join(ctx.taskDir, 'build-errors.md')\n if (fs.existsSync(errorsFile)) fs.unlinkSync(errorsFile)\n const failedNames = failures.map((f) => f.name).join(', ')\n throw new Error(\n `Quality gates failed after ${action.maxFeedbackLoops} build agent fix attempts: ${failedNames}`,\n )\n }\n}\n\nexport async function executeRunMechanicalAutofix(ctx: PipelineContext): Promise<void> {\n // Run lint:fix + format:fix deterministically — no LLM needed for mechanical fixes.\n // This prevents trivial format/lint failures from reaching verify stage.\n if (ctx.input.dryRun) return\n\n logger.info(' 🔧 Running mechanical auto-fix (lint:fix + format:fix)...')\n\n try {\n execFileSync('pnpm', ['lint:fix'], {\n stdio: 'pipe',\n timeout: 2 * 60 * 1000, // 2 minutes\n maxBuffer: 10 * 1024 * 1024,\n })\n logger.info(' ✓ lint:fix completed')\n } catch {\n logger.info(' ✗ lint:fix had errors (some may need manual fix)')\n }\n\n try {\n execFileSync('pnpm', ['format:fix'], {\n stdio: 'pipe',\n timeout: 2 * 60 * 1000, // 2 minutes\n maxBuffer: 10 * 1024 * 1024,\n })\n logger.info(' ✓ format:fix completed')\n } catch {\n logger.info(' ✗ format:fix had errors (some may need manual fix)')\n }\n\n logger.info(' ✅ Mechanical auto-fix complete')\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Analyzes review.md findings to determine if fix stage is needed\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext, PipelineStateV2 } from '../../engine/types'\nimport { updateStage, writeState } from '../../engine/status'\n\nexport async function executeAnalyzeReviewFindings(\n ctx: PipelineContext,\n state: PipelineStateV2 | null,\n): Promise<void> {\n const reviewPath = path.join(ctx.taskDir, 'review.md')\n\n let fixNeeded = false\n const reviewSummary = { critical: 0, major: 0, minor: 0 }\n\n if (fs.existsSync(reviewPath)) {\n const reviewContent = fs.readFileSync(reviewPath, 'utf-8')\n const contentLower = reviewContent.toLowerCase()\n\n // Parse review findings with multiple robust patterns\n // Pattern 1: \"Critical: N\" or \"Critical Issues: N\" or \"**Critical**: N\"\n const criticalPatterns = [/critical[^:]*:\\s*(\\d+)/i, /(\\d+)[ \\t]+critical/i]\n // Pattern 2: \"Major: N\" or \"Major Issues: N\" or \"**Major**: N\"\n const majorPatterns = [/major[^:]*:\\s*(\\d+)/i, /(\\d+)[ \\t]+major/i]\n // Pattern 3: \"Minor: N\"\n const minorPatterns = [/minor[^:]*:\\s*(\\d+)/i, /(\\d+)[ \\t]+minor/i]\n\n for (const pat of criticalPatterns) {\n const match = reviewContent.match(pat)\n if (match) {\n reviewSummary.critical = Math.max(reviewSummary.critical, parseInt(match[1]))\n }\n }\n for (const pat of majorPatterns) {\n const match = reviewContent.match(pat)\n if (match) {\n reviewSummary.major = Math.max(reviewSummary.major, parseInt(match[1]))\n }\n }\n for (const pat of minorPatterns) {\n const match = reviewContent.match(pat)\n if (match) {\n reviewSummary.minor = Math.max(reviewSummary.minor, parseInt(match[1]))\n }\n }\n\n // Check for explicit fix-required indicators\n const fixRequiredMatch =\n reviewContent.match(/fix\\s*required[^\\n]*\\[\\s*x\\s*\\]/i) ||\n reviewContent.match(/\\[\\s*x\\s*\\][^\\n]*fix\\s*required/i) ||\n reviewContent.match(/fix\\s*required[^\\n]*yes/i)\n\n // Also check for issue-indicating keywords as fallback\n const hasIssueKeywords =\n contentLower.includes('must fix') ||\n contentLower.includes('needs fix') ||\n contentLower.includes('should fix') ||\n contentLower.includes('bug found') ||\n contentLower.includes('security issue') ||\n contentLower.includes('vulnerability')\n\n fixNeeded =\n reviewSummary.critical > 0 ||\n reviewSummary.major > 0 ||\n fixRequiredMatch !== null ||\n hasIssueKeywords\n }\n\n // In fix mode, always set fixNeeded to true — user explicitly asked for fixes\n if (ctx.input.mode === 'fix') {\n fixNeeded = true\n }\n\n // Update state to track findings\n if (state) {\n const updatedState = updateStage(state, 'review', {\n issuesFound: fixNeeded,\n reviewSummary,\n })\n writeState(ctx.taskId, updatedState)\n }\n\n logger.info(\n ` Review findings: ${reviewSummary.critical} critical, ${reviewSummary.major} major, fixNeeded=${fixNeeded}`,\n )\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-action\n * @ai-summary Build/source validation post-actions — validates plan exists,\n * build content has required sections, and build agent modified source files\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { execFileSync } from 'child_process'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext } from '../../engine/types'\n\nexport async function executeValidatePlanExists(ctx: PipelineContext): Promise<void> {\n const planFile = path.join(ctx.taskDir, 'plan.md')\n const gapFile = path.join(ctx.taskDir, 'gap.md')\n\n if (!fs.existsSync(planFile)) {\n throw new Error('plan.md not found - gap agent may have deleted it')\n }\n\n const gapContent = fs.existsSync(gapFile) ? fs.readFileSync(gapFile, 'utf-8') : ''\n\n // Basic validation - check for expected sections\n if (!gapContent.includes('## ') && !gapContent.includes('No gaps identified')) {\n throw new Error('gap.md must contain ## sections or \"No gaps identified\"')\n }\n}\n\nexport async function executeValidateBuildContent(ctx: PipelineContext): Promise<void> {\n const buildFile = path.join(ctx.taskDir, 'build.md')\n if (!fs.existsSync(buildFile)) {\n throw new Error('build.md not found')\n }\n\n const buildContent = fs.readFileSync(buildFile, 'utf-8')\n\n // Check for required sections\n if (!buildContent.includes('## Changes') && !buildContent.includes('## Files')) {\n throw new Error('build.md must contain ## Changes or ## Files section')\n }\n}\n\nexport async function executeValidateSrcChanges(ctx: PipelineContext): Promise<void> {\n if (ctx.input.dryRun) return\n\n // Check that the build agent actually modified source files, not just .tasks/\n let diff = ''\n let untracked = ''\n let gitFailed = false\n try {\n diff = execFileSync('git', ['diff', '--name-only'], { encoding: 'utf-8' }).trim()\n } catch (error) {\n logger.error({ err: error }, 'git diff failed during src validation')\n gitFailed = true\n }\n try {\n untracked = execFileSync('git', ['ls-files', '--others', '--exclude-standard'], {\n encoding: 'utf-8',\n }).trim()\n } catch (error) {\n logger.error({ err: error }, 'git ls-files failed during src validation')\n gitFailed = true\n }\n\n if (gitFailed) {\n throw new Error(\n 'validate-src-changes: git commands failed — cannot verify source changes. Check git state.',\n )\n }\n\n const allChanged = [...diff.split('\\n'), ...untracked.split('\\n')]\n .filter(Boolean)\n .filter((f) => !f.startsWith('.tasks/'))\n\n if (allChanged.length === 0) {\n throw new Error(\n 'Build agent wrote build.md but did NOT modify any source files. ' +\n 'The agent must use Edit/Write tools to implement actual code changes, not just document them in build.md.',\n )\n }\n\n logger.info(` ✓ ${allChanged.length} source file(s) changed by build agent`)\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline | post-action\n * @pattern knowledge-base | learning\n * @ai-summary Updates the cross-task knowledge base with patterns learned from completed tasks\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext, PipelineStateV2 } from '../../engine/types'\nimport { loadState } from '../../engine/status'\nimport { readTask } from '../../pipeline-utils'\nimport type { TaskDefinition } from '../task-schema'\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface KnowledgeEntry {\n taskId: string\n date: string\n domain: string\n taskType: string\n complexity: number\n patterns: string[]\n summary: string\n feedbackLoops?: number\n errorPatterns?: string[]\n}\n\ninterface KnowledgeBase {\n version: number\n description: string\n entries: KnowledgeEntry[]\n patternFrequency: Record<string, number>\n skillsCreated: string[]\n lastUpdated: string\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst KNOWLEDGE_BASE_PATH = '.tasks/knowledge/index.json'\nconst MAX_KNOWLEDGE_ENTRIES = 100\n\n// Pattern detection keywords (detected in scope text)\nconst PATTERN_KEYWORDS: Record<string, string[]> = {\n 'type-error': ['typescript', 'type', 'interface', 'type error'],\n 'lint-error': ['lint', 'eslint', 'prettier'],\n 'format-error': ['format', 'prettier', 'indentation'],\n 'test-failure': ['test', 'vitest', 'assertion', 'expected'],\n 'css-styling': ['tailwind', 'css', 'className', 'style'],\n 'frontend-bugfix': ['ui', 'component', 'render', 'state'],\n 'api-design': ['endpoint', 'route', 'request', 'response'],\n 'data-modeling': ['collection', 'schema', 'field', 'relationship'],\n performance: ['optimize', 'cache', 'lazy', 'memo'],\n security: ['auth', 'sanitize', 'validate', 'permission'],\n hook: ['hook', 'beforeChange', 'afterChange', 'beforeValidate'],\n 'access-control': ['access', 'permission', 'isAdmin', 'isOwner'],\n}\n\n// ============================================================================\n// Helper: Detect patterns from task scope and error data\n// ============================================================================\n\nfunction detectPatterns(\n taskDef: TaskDefinition,\n errorPatterns: string[],\n feedbackLoops: number,\n): string[] {\n const patterns: string[] = []\n\n // Detect from task scope (array of scope items joined)\n const scopeText = (taskDef.scope || []).join(' ').toLowerCase()\n const typeText = taskDef.task_type.toLowerCase()\n\n for (const [pattern, keywords] of Object.entries(PATTERN_KEYWORDS)) {\n if (keywords.some((kw) => scopeText.includes(kw) || typeText.includes(kw))) {\n patterns.push(pattern)\n }\n }\n\n // Add error patterns that were encountered\n for (const error of errorPatterns) {\n const normalized = error.toLowerCase()\n if (normalized.includes('type') || normalized.includes('ts')) {\n patterns.push('type-error')\n }\n if (normalized.includes('lint') || normalized.includes('eslint')) {\n patterns.push('lint-error')\n }\n if (normalized.includes('format') || normalized.includes('prettier')) {\n patterns.push('format-error')\n }\n if (normalized.includes('test') || normalized.includes('vitest')) {\n patterns.push('test-failure')\n }\n }\n\n // If feedback loops were needed, mark as needing iteration\n if (feedbackLoops > 0) {\n patterns.push('iterative-fix')\n }\n\n // Deduplicate\n return [...new Set(patterns)]\n}\n\n// ============================================================================\n// Helper: Load existing knowledge base\n// ============================================================================\n\nfunction loadKnowledgeBase(): KnowledgeBase {\n const kbPath = path.join(process.cwd(), KNOWLEDGE_BASE_PATH)\n\n if (!fs.existsSync(kbPath)) {\n return {\n version: 1,\n description:\n 'Cross-task knowledge base for Kody pipeline self-learning. Updated by the pipeline after each task completion.',\n entries: [],\n patternFrequency: {},\n skillsCreated: [],\n lastUpdated: new Date().toISOString(),\n }\n }\n\n try {\n const data = fs.readFileSync(kbPath, 'utf-8')\n return JSON.parse(data) as KnowledgeBase\n } catch (err) {\n logger.warn({ err }, 'Failed to load knowledge base, starting fresh')\n return {\n version: 1,\n description: 'Cross-task knowledge base for Kody pipeline self-learning.',\n entries: [],\n patternFrequency: {},\n skillsCreated: [],\n lastUpdated: new Date().toISOString(),\n }\n }\n}\n\n// ============================================================================\n// Helper: Save knowledge base\n// ============================================================================\n\nfunction saveKnowledgeBase(kb: KnowledgeBase): void {\n const kbPath = path.join(process.cwd(), KNOWLEDGE_BASE_PATH)\n const dir = path.dirname(kbPath)\n\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n\n kb.lastUpdated = new Date().toISOString()\n fs.writeFileSync(kbPath, JSON.stringify(kb, null, 2), 'utf-8')\n logger.info(` 📚 Updated knowledge base with ${kb.entries.length} entries`)\n}\n\n// ============================================================================\n// Main: Execute knowledge base update\n// ============================================================================\n\n/**\n * Post-action that updates the cross-task knowledge base after task completion.\n *\n * This captures:\n * - Task domain and type\n * - Complexity score\n * - Patterns detected (from scope and error patterns)\n * - Feedback loops needed (indicates difficulty)\n * - Error patterns encountered\n *\n * The knowledge base is read by the architect stage to inform planning.\n */\nexport async function executeUpdateKnowledgeBase(\n ctx: PipelineContext,\n _state: PipelineStateV2 | null,\n): Promise<void> {\n if (ctx.input.dryRun) {\n logger.info(' ℹ️ Dry run, skipping knowledge base update')\n return\n }\n\n logger.info(' 📚 Updating knowledge base...')\n\n try {\n // Load task definition\n const taskDef = readTask(ctx.taskDir)\n if (!taskDef) {\n logger.warn(' ⚠️ No task definition found, skipping knowledge base update')\n return\n }\n\n // Load pipeline state for metrics\n const state = loadState(ctx.taskId)\n const buildStage = state?.stages?.build\n\n // Extract error patterns from verify failures if they exist\n let errorPatterns: string[] = []\n const verifyFailuresPath = path.join(ctx.taskDir, 'verify-failures.md')\n if (fs.existsSync(verifyFailuresPath)) {\n const content = fs.readFileSync(verifyFailuresPath, 'utf-8')\n // Extract error categories from the failures file\n const errorMatches = content.match(/##\\s+Error\\s+\\d+:\\s+(\\S+)/g) || []\n errorPatterns = errorMatches.map((m) => m.replace(/##\\s+Error\\s+\\d+:\\s+/, ''))\n }\n\n // Detect patterns\n const patterns = detectPatterns(taskDef, errorPatterns, buildStage?.feedbackLoops || 0)\n\n // Create knowledge entry\n const entry: KnowledgeEntry = {\n taskId: ctx.taskId,\n date: new Date().toISOString(),\n domain: taskDef.primary_domain,\n taskType: taskDef.task_type,\n complexity: taskDef.complexity || 0,\n patterns,\n summary: taskDef.scope?.slice(0, 3).join(', ') || 'No scope',\n feedbackLoops: buildStage?.feedbackLoops,\n errorPatterns: errorPatterns.length > 0 ? errorPatterns : undefined,\n }\n\n // Load and update knowledge base\n const kb = loadKnowledgeBase()\n\n // Check for duplicate entry (same taskId)\n const existingIndex = kb.entries.findIndex((e) => e.taskId === ctx.taskId)\n if (existingIndex >= 0) {\n // Update existing entry\n kb.entries[existingIndex] = entry\n logger.info(` 📝 Updated existing knowledge entry for ${ctx.taskId}`)\n } else {\n // Add new entry\n kb.entries.push(entry)\n logger.info(` ✅ Added new knowledge entry for ${ctx.taskId}`)\n }\n\n // Trim entries if too many\n if (kb.entries.length > MAX_KNOWLEDGE_ENTRIES) {\n kb.entries = kb.entries.slice(-MAX_KNOWLEDGE_ENTRIES)\n logger.info(` ℹ️ Trimmed knowledge base to ${MAX_KNOWLEDGE_ENTRIES} entries`)\n }\n\n // Update pattern frequency\n for (const pattern of patterns) {\n kb.patternFrequency[pattern] = (kb.patternFrequency[pattern] || 0) + 1\n }\n\n // Save updated knowledge base\n saveKnowledgeBase(kb)\n\n logger.info(\n ` ✅ Knowledge base updated: domain=${taskDef.primary_domain}, patterns=[${patterns.join(', ')}], feedbackLoops=${buildStage?.feedbackLoops || 0}`,\n )\n } catch (err) {\n // Non-fatal — log and continue\n logger.warn({ err }, 'Failed to update knowledge base, continuing pipeline')\n }\n}\n","/**\n * @fileType utility\n * @domain kody | pipeline\n * @pattern post-actions\n * @ai-summary Post-stage action dispatcher — routes to focused modules.\n * Small/simple actions remain inlined here; larger actions are in separate files.\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { logger } from '../../logger'\nimport type { PipelineContext, PostAction, PipelineStateV2 } from '../../engine/types'\nimport { PipelinePausedError, isBlockingPostAction } from '../../engine/types'\n\n// Focused modules\nimport { executeValidateTaskJson } from './validate-task-json'\nimport { executeSetClassificationLabels } from './classification'\nimport { executeResolveProfile } from './resolve-profile'\nimport { executeCheckGate } from './gate'\nimport { executeCommitTaskFiles } from './commit'\nimport {\n executeRunTsc,\n executeRunUnitTests,\n executeRunQualityWithAutofix,\n executeRunMechanicalAutofix,\n} from './quality'\nimport { executeAnalyzeReviewFindings } from './review'\nimport {\n executeValidatePlanExists,\n executeValidateBuildContent,\n executeValidateSrcChanges,\n} from './validators'\nimport { executeUpdateKnowledgeBase } from './knowledge-base'\n\n/**\n * Execute a post-action by dispatching to the appropriate module\n */\nexport async function executePostAction(\n ctx: PipelineContext,\n action: PostAction,\n _state: PipelineStateV2 | null,\n): Promise<void> {\n switch (action.type) {\n case 'validate-task-json':\n return executeValidateTaskJson(ctx)\n\n case 'set-classification-labels':\n return executeSetClassificationLabels(ctx)\n\n case 'resolve-profile':\n return executeResolveProfile(ctx)\n\n case 'check-gate':\n return executeCheckGate(ctx, action as PostAction & { type: 'check-gate' }, _state)\n\n case 'commit-task-files':\n return executeCommitTaskFiles(ctx, action as PostAction & { type: 'commit-task-files' })\n\n case 'validate-plan-exists':\n return executeValidatePlanExists(ctx)\n\n case 'validate-build-content':\n return executeValidateBuildContent(ctx)\n\n case 'validate-src-changes':\n return executeValidateSrcChanges(ctx)\n\n case 'run-tsc':\n return executeRunTsc(ctx)\n\n case 'run-unit-tests':\n return executeRunUnitTests(ctx)\n\n case 'run-quality-with-autofix':\n return executeRunQualityWithAutofix(\n ctx,\n action as PostAction & { type: 'run-quality-with-autofix' },\n _state,\n )\n\n case 'run-mechanical-autofix':\n return executeRunMechanicalAutofix(ctx)\n\n case 'analyze-review-findings':\n return executeAnalyzeReviewFindings(ctx, _state)\n\n // Small actions inlined — not worth separate files\n case 'archive-rerun-feedback': {\n const rerunFeedbackPath = path.join(ctx.taskDir, 'rerun-feedback.md')\n if (fs.existsSync(rerunFeedbackPath)) {\n const consumed = path.join(ctx.taskDir, 'rerun-feedback.consumed.md')\n fs.renameSync(rerunFeedbackPath, consumed)\n logger.info(' Consumed rerun-feedback.md')\n }\n break\n }\n\n case 'clear-verify-failures': {\n const verifyFailuresPath = path.join(ctx.taskDir, 'verify-failures.md')\n if (fs.existsSync(verifyFailuresPath)) {\n fs.unlinkSync(verifyFailuresPath)\n logger.info(' Cleared verify-failures.md')\n }\n break\n }\n\n case 'update-knowledge-base':\n return executeUpdateKnowledgeBase(ctx, _state)\n\n case 'parallel': {\n if (!('actions' in action) || !Array.isArray((action as { actions?: unknown }).actions)) {\n throw new Error(`'parallel' post-action missing required 'actions' array`)\n }\n const parallelActions = (action as { actions: PostAction[] }).actions\n logger.info(` Running ${parallelActions.length} actions in parallel...`)\n\n // Timeout wrapper to prevent hanging on slow post-actions\n const PARALLEL_POST_ACTION_TIMEOUT_MS = 60_000 // 60 seconds\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(\n () =>\n reject(\n new Error(\n `Parallel post-actions exceeded ${PARALLEL_POST_ACTION_TIMEOUT_MS / 1000}s timeout`,\n ),\n ),\n PARALLEL_POST_ACTION_TIMEOUT_MS,\n )\n })\n\n const results = await Promise.race([\n Promise.allSettled(\n parallelActions.map(async (a) => {\n await executePostAction(ctx, a, _state)\n }),\n ),\n timeoutPromise,\n ])\n\n // Check for PipelinePausedError first — re-throw it directly to preserve the type\n const pauseResult = results.find(\n (r): r is PromiseRejectedResult =>\n r.status === 'rejected' && r.reason instanceof PipelinePausedError,\n )\n if (pauseResult) {\n throw pauseResult.reason\n }\n\n // Classify failures into blocking vs advisory\n const failures = results.filter((r): r is PromiseRejectedResult => r.status === 'rejected')\n if (failures.length > 0) {\n // Check if any blocking actions failed\n const blockingFailures: { action: PostAction; error: string }[] = []\n const advisoryFailures: { action: PostAction; error: string }[] = []\n\n for (let i = 0; i < results.length; i++) {\n const result = results[i]\n if (result.status === 'rejected') {\n const action = parallelActions[i]\n const err =\n result.reason instanceof Error ? result.reason.message : String(result.reason)\n if (isBlockingPostAction(action)) {\n blockingFailures.push({ action, error: err })\n } else {\n advisoryFailures.push({ action, error: err })\n }\n }\n }\n\n // Log advisory failures as warnings (don't fail the pipeline)\n for (const { action, error } of advisoryFailures) {\n logger.warn({ actionType: action.type }, ` Advisory post-action failed: ${error}`)\n }\n\n // Throw only if blocking actions failed\n if (blockingFailures.length > 0) {\n const errors = blockingFailures.map((f) => f.error).join('; ')\n throw new Error(`Parallel post-actions failed (blocking): ${errors}`)\n }\n }\n logger.info(` ✅ All ${parallelActions.length} parallel actions completed`)\n break\n }\n\n default:\n throw new Error(\n `Unknown post-action type: \"${(action as PostAction).type}\". This is a configuration bug.`,\n )\n }\n}\n","/**\n * @fileType observer\n * @domain kody | pipeline | observer\n * @pattern observer\n * @ai-summary Pipeline Observer - delegates complex failures to OpenCode agent\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport { logger } from '../../logger'\nimport { createRunner, type RunnerBackend } from '../../runner-backend'\nimport type { StageName } from '../../stages/registry'\nimport {\n type StageFailure,\n type ObserverResult,\n type ObserverDecision,\n type ObserverContext,\n} from './types'\nimport { updateStage, loadState, writeState } from '../../engine/status'\nimport type { PipelineStateV2 } from '../../engine/types'\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst MAX_OBSERVER_ATTEMPTS = 1\nconst OBSERVER_TIMEOUT_MS = 120_000 // 120 seconds\n\n// ============================================================================\n// Observer Class\n// ============================================================================\n\nexport class PipelineObserver {\n private readonly backend: RunnerBackend\n\n constructor(\n private readonly taskId: string,\n private readonly taskDir: string,\n private readonly serverUrl: string,\n private readonly sessionId: string,\n private readonly dataDir: string,\n ) {\n this.backend = createRunner()\n }\n\n /**\n * Handle a stage failure by delegating to the same OpenCode agent.\n * Pipeline is PAUSED while we wait for the agent to decide.\n */\n async handle(failure: StageFailure): Promise<ObserverResult> {\n const observerAttempt = this.getObserverAttempt(failure)\n\n // Check recursion cap\n if (observerAttempt > MAX_OBSERVER_ATTEMPTS) {\n logger.info(`[Observer] Max attempts (${MAX_OBSERVER_ATTEMPTS}) exceeded, auto-escalating`)\n return this.autoEscalate(failure, 'Max Observer attempts exceeded')\n }\n\n logger.info(\n `[Observer] Handling failure for stage '${failure.stageName}' (Observer attempt ${observerAttempt}/${MAX_OBSERVER_ATTEMPTS})`,\n )\n\n // Mark stage as observing\n const state = loadState(this.taskId)\n if (state) {\n const updatedState = updateStage(state, failure.stageName, {\n state: 'observing',\n error: `Observer handling: ${failure.error.message}`,\n })\n writeState(this.taskId, updatedState)\n }\n\n // Delegate to agent with timeout\n try {\n const result = await this.withTimeout(\n this.delegateToAgent(failure, observerAttempt),\n OBSERVER_TIMEOUT_MS,\n )\n\n // Log decision\n this.logDecision(failure, result, observerAttempt)\n\n return { ...result, observerAttempt }\n } catch (error) {\n logger.error({ err: error }, `[Observer] Error during agent delegation`)\n\n // Timeout or error - auto-escalate\n const reason = error instanceof Error ? error.message : 'Unknown error'\n return this.autoEscalate(failure, reason)\n }\n }\n\n /**\n * Delegate failure handling to the same OpenCode agent that ran the stage.\n */\n private async delegateToAgent(\n failure: StageFailure,\n observerAttempt: number,\n ): Promise<ObserverResult> {\n // Write context file for the agent to read\n const contextFile = path.join(this.taskDir, '.observer-context.json')\n const context: ObserverContext = {\n stageName: failure.stageName,\n error: {\n message: failure.error.message,\n stack: failure.error.stack,\n },\n attempt: failure.attempt,\n maxAttempts: failure.maxAttempts,\n taskDir: this.taskDir,\n observerAttempt,\n }\n fs.writeFileSync(contextFile, JSON.stringify(context, null, 2))\n\n // Decision file path\n const decisionFile = path.join(this.taskDir, '.observer-decision.json')\n\n // Delete any existing decision file\n if (fs.existsSync(decisionFile)) {\n fs.unlinkSync(decisionFile)\n }\n\n // Build the prompt for the agent\n const prompt = this.buildFailureHandlingPrompt(failure, context)\n\n // Spawn agent process that attaches to existing session (forks it)\n logger.info(`[Observer] Spawning agent '${failure.stageName}' to handle failure`)\n\n const agentProcess = this.backend.spawn(failure.stageName, prompt, process.env, this.taskDir, {\n serverUrl: this.serverUrl,\n sessionId: this.sessionId,\n dataDir: this.dataDir,\n })\n\n // Wait for the agent to complete\n await this.waitForAgent(agentProcess)\n\n // Read decision file\n if (!fs.existsSync(decisionFile)) {\n throw new Error(`Agent did not write decision file: ${decisionFile}`)\n }\n\n const decisionContent = fs.readFileSync(decisionFile, 'utf-8')\n const decision: ObserverDecision = JSON.parse(decisionContent)\n\n // Validate decision\n if (!decision.action || !['retry', 'escalate', 'halt'].includes(decision.action)) {\n throw new Error(`Invalid decision action: ${decision.action}`)\n }\n\n logger.info(`[Observer] Agent returned: ${decision.action} - ${decision.reason}`)\n\n return {\n action: decision.action,\n reason: decision.reason,\n fix: decision.fix,\n observerAttempt,\n }\n }\n\n /**\n * Build the prompt for the agent to handle the failure.\n */\n private buildFailureHandlingPrompt(failure: StageFailure, context: ObserverContext): string {\n return `## Task: Handle Stage Failure\n\nStage \"${failure.stageName}\" failed during pipeline execution.\n\n### Error Context\n\\`\\`\\`json\n${JSON.stringify(context, null, 2)}\n\\`\\`\\`\n\n### Context File\nFull context is available at: ${this.taskDir}/.observer-context.json\n\n### Decision File\nWrite your decision to: ${this.taskDir}/.observer-decision.json\n\n### Your Task\n\n1. Read .observer-context.json to understand the failure\n2. Investigate the error - read relevant files, understand root cause\n3. If fixable:\n - Apply the fix to the relevant files\n - Write .observer-decision.json with action: \"retry\"\n4. If not fixable:\n - Write .observer-decision.json with action: \"escalate\" and reason\n5. If fundamentally broken:\n - Write .observer-decision.json with action: \"halt\" and reason\n\n### Decision File Format\nWrite to ${this.taskDir}/.observer-decision.json:\n\\`\\`\\`json\n{\n \"action\": \"retry\",\n \"reason\": \"Fixed TypeScript error in src/foo.ts\",\n \"fix\": {\n \"description\": \"Fixed type mismatch in calculateTotal function\",\n \"filesModified\": [\"src/foo.ts\"]\n }\n}\n\\`\\`\\`\n\nOr for escalation:\n\\`\\`\\`json\n{\n \"action\": \"escalate\",\n \"reason\": \"Context overflow - needs human to simplify requirements\"\n}\n\\`\\`\\`\n\nOr for halt:\n\\`\\`\\`json\n{\n \"action\": \"halt\",\n \"reason\": \"Invalid task.json - fundamental data quality issue\"\n}\n\\`\\`\\`\n\n### Rules\n- Do NOT write partial JSON - write complete valid JSON to the decision file\n- If you cannot fix, escalate - don't guess\n- You have 120 seconds before timeout\n- Write the decision file BEFORE exiting\n- The pipeline is PAUSED waiting for your decision\n`\n }\n\n /**\n * Wait for agent process to complete.\n */\n private waitForAgent(agentProcess: {\n on: (event: string, cb: (...args: unknown[]) => void) => void\n kill?: () => void\n }): Promise<void> {\n return new Promise((resolve, reject) => {\n // Set timeout\n const timeout = setTimeout(() => {\n logger.warn(`[Observer] Agent timed out after ${OBSERVER_TIMEOUT_MS}ms`)\n try {\n agentProcess.kill?.()\n } catch {\n // ignore\n }\n reject(new Error('Observer timeout'))\n }, OBSERVER_TIMEOUT_MS)\n\n // Agent process emits 'exit' when done\n agentProcess.on('exit', (...args: unknown[]) => {\n clearTimeout(timeout)\n const code = args[0] as number | undefined\n logger.info(`[Observer] Agent exited with code: ${code}`)\n resolve()\n })\n\n // Fallback if no explicit exit event\n setTimeout(() => {\n clearTimeout(timeout)\n resolve()\n }, OBSERVER_TIMEOUT_MS + 1000)\n })\n }\n\n /**\n * Wrap promise with timeout.\n */\n private async withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n return Promise.race([\n promise,\n new Promise<T>((_, reject) => setTimeout(() => reject(new Error('Observer timeout')), ms)),\n ])\n }\n\n /**\n * Auto-escalate when max attempts reached or error occurs.\n */\n private autoEscalate(failure: StageFailure, reason: string): ObserverResult {\n return {\n action: 'escalate',\n reason: `Auto-escalated: ${reason}`,\n observerAttempt: this.getObserverAttempt(failure),\n }\n }\n\n /**\n * Get current Observer attempt number for this stage.\n */\n private getObserverAttempt(failure: StageFailure): number {\n const state = loadState(this.taskId)\n if (!state) return 1\n\n const stageState = state.stages[failure.stageName]\n if (!stageState) return 1\n\n // Count previous observer attempts in history\n const history =\n (state as PipelineStateV2 & { observerHistory?: Array<{ stage: string }> }).observerHistory ||\n []\n const stageHistory = history.filter((e) => e.stage === failure.stageName)\n return stageHistory.length + 1\n }\n\n /**\n * Log decision to status.json observerHistory.\n */\n private logDecision(\n failure: StageFailure,\n result: {\n action: string\n reason: string\n fix?: { description: string; filesModified: string[] }\n },\n observerAttempt: number,\n ): void {\n const state = loadState(this.taskId)\n if (!state) return\n\n const historyEntry = {\n stage: failure.stageName,\n observerAttempt,\n error: failure.error.message,\n action: result.action,\n reason: result.reason,\n wasAgent: true,\n agentName: failure.stageName,\n timestamp: new Date().toISOString(),\n fixApplied: result.fix,\n }\n\n const observerHistory = [\n ...((state as PipelineStateV2 & { observerHistory?: unknown[] }).observerHistory || []),\n historyEntry,\n ]\n\n const updatedState = {\n ...state,\n observerHistory,\n } as PipelineStateV2\n\n writeState(this.taskId, updatedState)\n }\n}\n\n// ============================================================================\n// Factory function\n// ============================================================================\n\nexport function createPipelineObserver(\n taskId: string,\n taskDir: string,\n serverUrl: string,\n sessionId: string,\n dataDir: string,\n): PipelineObserver {\n return new PipelineObserver(taskId, taskDir, serverUrl, sessionId, dataDir)\n}\n","/**\n * @fileType engine\n * @domain kody | engine\n * @pattern state-machine\n * @ai-summary Core deterministic pipeline execution engine\n */\n\nimport type {\n PipelineDefinition,\n PipelineContext,\n PipelineStateV2,\n LifecycleHooks,\n StageDefinition,\n StageResult,\n PipelineStep,\n} from \"./types\";\nimport type { StageName } from \"../stages/registry\";\nimport { logger, ciGroup, ciGroupEnd } from \"../logger\";\nimport {\n MAX_PIPELINE_LOOP_ITERATIONS,\n RECOVERY_CHECK_INTERVAL,\n} from \"../config/constants\";\nimport { PipelinePausedError } from \"./types\";\nimport {\n logStageStart,\n logStageComplete,\n logStageSkip,\n logStageFail,\n logStageRetry,\n logPipelineStart,\n logPipelineComplete,\n logRecovery,\n} from \"../pipeline-events\";\nimport {\n loadState,\n writeState,\n initState,\n updateStage,\n completeState,\n recoverStaleStages,\n recoverPipelineState,\n} from \"./status\";\nimport { getHandler } from \"../handlers/handler\";\nimport { setLifecycleLabel } from \"../github-api\";\nimport { executePostAction } from \"../pipeline/post-actions\";\nimport { flattenPipelineOrder } from \"../pipeline/definitions\";\nimport { execFileSync } from \"node:child_process\";\nimport { commitPipelineFiles } from \"../git-utils\";\nimport { PipelineObserver } from \"../pipeline/observer/observer\";\n\n/**\n * Error subclass that carries the originating stage name for parallel error attribution\n */\nclass StageError extends Error {\n public readonly stageName: string;\n public readonly cause?: Error;\n constructor(message: string, stageName: string, cause?: Error) {\n super(message);\n this.name = \"StageError\";\n this.stageName = stageName;\n this.cause = cause;\n }\n}\n\n// ============================================================================\n// Engine\n// ============================================================================\n\n/**\n * Main pipeline execution function\n */\nexport async function runPipeline(\n ctx: PipelineContext,\n pipeline: PipelineDefinition,\n hooks?: LifecycleHooks,\n rebuildPipeline?: (ctx: PipelineContext) => PipelineDefinition,\n): Promise<PipelineStateV2> {\n // Load or init state\n logPipelineStart(ctx.taskId, ctx.input.mode, ctx.profile);\n let state = loadState(ctx.taskId);\n if (!state) {\n state = initState(ctx, ctx.input.mode);\n // Set initial lifecycle label based on mode\n if (ctx.input.issueNumber) {\n const initialLabel =\n ctx.input.mode === \"spec\" || ctx.input.mode === \"full\"\n ? \"kody:planning\"\n : \"kody:building\";\n setLifecycleLabel(ctx.input.issueNumber, initialLabel);\n }\n\n // Early push: overwrite stale status.json on branch so dashboard sees 'running' immediately.\n // Only when the feature branch already exists (re-runs / gate resumes).\n // First runs create the branch in taskify's post-action commit-task-files with ensureBranch.\n if (!ctx.input.dryRun && !ctx.input.local) {\n try {\n const currentBranch = execFileSync(\n \"git\",\n [\"branch\", \"--show-current\"],\n {\n encoding: \"utf-8\",\n },\n ).trim();\n const isFeatureBranch = ![\"dev\", \"main\", \"master\"].includes(\n currentBranch,\n );\n if (isFeatureBranch) {\n commitPipelineFiles({\n taskDir: ctx.taskDir,\n taskId: ctx.taskId,\n message: `ci(kody): reset status to running for ${ctx.taskId}`,\n stagingStrategy: \"task-only\",\n push: true,\n isCI: true,\n });\n logger.info(\" ✓ Pushed fresh running status.json to branch\");\n }\n } catch (earlyPushErr) {\n // Non-fatal — dashboard will update once the first stage completes\n logger.warn(\n { err: earlyPushErr },\n \"Early status push failed (non-fatal)\",\n );\n }\n }\n } else {\n // Recovery: handle stale state from previous interrupted runs\n // Step 1: Reset any stages stuck in \"running\" to \"pending\"\n state = recoverStaleStages(state);\n\n // Step 2: Build advisory stages set from pipeline definitions\n const advisoryStages = new Set<string>();\n for (const [name, def] of pipeline.stages) {\n if (def.advisory) advisoryStages.add(name);\n }\n\n // Step 3: Auto-complete/fail pipeline if all stages are done\n const flatOrder = flattenPipelineOrder(pipeline.order);\n state = recoverPipelineState(state, flatOrder, advisoryStages);\n writeState(ctx.taskId, state);\n\n // Step 4: If pipeline was previously failed, check if any stages were reset to pending\n // (which means a rerun is happening). Only update the label if we're actually restarting.\n // R2-FIX #5: Don't blindly set 'building' — verify we have pending work to do first.\n if (state.state === \"failed\" && ctx.input.issueNumber) {\n const hasPendingStages = Object.values(state.stages).some(\n (s) => s.state === \"pending\" || s.state === \"running\",\n );\n if (hasPendingStages) {\n setLifecycleLabel(ctx.input.issueNumber, \"kody:building\");\n }\n }\n\n // Step 5: Handle paused pipeline with no paused stages (gate was approved)\n // This handles the case where resumeFromGate() was called to mark the gate stage\n // as completed, but the pipeline-level state is still \"paused\"\n if (state.state === \"paused\") {\n const anyPausedStage = Object.values(state.stages).some(\n (s) => s.state === \"paused\",\n );\n if (!anyPausedStage) {\n // Gate was approved - no stages are actually paused, so resume the pipeline\n state = {\n ...state,\n state: \"running\",\n updatedAt: new Date().toISOString(),\n };\n writeState(ctx.taskId, state);\n }\n }\n\n // If recovery determined pipeline is already done, return immediately\n if (state.state === \"completed\" || state.state === \"failed\") {\n return state;\n }\n }\n\n // Main execution loop\n let loopCount = 0;\n while (true) {\n loopCount++;\n\n // Circuit breaker: prevent infinite loops from stage state management bugs\n if (loopCount > MAX_PIPELINE_LOOP_ITERATIONS) {\n logger.error(\n `Pipeline loop exceeded ${MAX_PIPELINE_LOOP_ITERATIONS} iterations — aborting to prevent infinite loop`,\n );\n state = completeState(state, \"failed\");\n writeState(ctx.taskId, state);\n throw new Error(\n `Pipeline loop guard triggered after ${MAX_PIPELINE_LOOP_ITERATIONS} iterations. ` +\n \"This is likely a bug in stage state management.\",\n );\n }\n\n // FIX #9: Periodic recovery check\n // This handles mid-run corruption of status.json\n if (loopCount % RECOVERY_CHECK_INTERVAL === 0) {\n const currentState = loadState(ctx.taskId);\n if (currentState) {\n // Check for stale running stages\n const recoveredState = recoverStaleStages(currentState);\n if (recoveredState !== currentState) {\n logger.info(\"⚠️ Periodic recovery: reset stale running stages\");\n logRecovery(\n \"stale-stage-recovery\",\n ctx.taskId,\n \"Reset stale running stages\",\n );\n state = recoveredState;\n writeState(ctx.taskId, state);\n }\n }\n }\n\n // Check if pipeline needs rebuilding (two-phase construction)\n if (ctx.pipelineNeedsRebuild && rebuildPipeline) {\n pipeline = rebuildPipeline(ctx);\n ctx.pipelineNeedsRebuild = false;\n\n // FIX #1/#4: Validate state stages against rebuilt pipeline.\n // New stages (from impl phase) may not exist in state yet — initialize them.\n // Stale stages (removed during rebuild) are harmless (ignored by resolveNextStep).\n const newOrder = flattenPipelineOrder(pipeline.order);\n for (const stageName of newOrder) {\n if (!state.stages[stageName]) {\n state = updateStage(state, stageName, {\n state: \"pending\",\n retries: 0,\n });\n }\n }\n writeState(ctx.taskId, state);\n\n // Transition from planning to building after spec stages complete\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, \"kody:building\");\n }\n }\n\n const nextStep = resolveNextStep(state, pipeline);\n if (!nextStep) {\n // All stages completed - mark pipeline as completed\n state = completeState(state, \"completed\");\n writeState(ctx.taskId, state);\n // Set lifecycle label to done\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, \"kody:done\");\n }\n logPipelineComplete(ctx.taskId, state.totalElapsed);\n break;\n }\n\n const prevState: PipelineStateV2 | null = state;\n\n // Handle parallel vs sequential\n const step = nextStep as StageName | { parallel: StageName[] };\n if (step && typeof step === \"object\" && \"parallel\" in step) {\n state = await executeParallelStep(ctx, pipeline, state, step.parallel);\n } else if (step && typeof step === \"string\") {\n state = await executeSingleStep(ctx, pipeline, state, step);\n }\n\n // Persist state\n writeState(ctx.taskId, state);\n\n // Call lifecycle hook\n if (hooks?.onStateChange && state !== prevState) {\n hooks.onStateChange(prevState, state, ctx);\n }\n\n // Stop if failed or paused\n if (state.state === \"failed\" || state.state === \"paused\") {\n break;\n }\n }\n\n // Throw if pipeline failed so caller can handle the failure properly\n if (state.state === \"failed\") {\n // Find either failed or timeout stage for better error reporting\n const failedStage = Object.entries(state.stages).find(\n ([, s]) => s.state === \"failed\" || s.state === \"timeout\",\n );\n const stageName = failedStage?.[0] || \"unknown\";\n const stageState = failedStage?.[1];\n const stageOutcome = stageState?.state || \"unknown\";\n const stageError = stageState?.error ? `: ${stageState.error}` : \"\";\n throw new Error(\n `Pipeline failed at stage: ${stageName} (${stageOutcome})${stageError}`,\n );\n }\n\n return state;\n}\n\n/**\n * Resolve the next step to execute\n */\nfunction resolveNextStep(\n state: PipelineStateV2,\n pipeline: PipelineDefinition,\n): PipelineStep | null {\n for (const step of pipeline.order) {\n if (typeof step === \"string\") {\n // Single stage\n const stageState = state.stages[step];\n // Only run pending stages - failed stages should not auto-retry\n // User can use --from to restart from a specific stage\n // Also run stages that were interrupted (running state from previous run)\n if (\n !stageState ||\n stageState.state === \"pending\" ||\n stageState.state === \"running\"\n ) {\n return step;\n }\n } else if (\"parallel\" in step) {\n // Parallel stages - check if any need to run\n const needsRun = step.parallel.some((s) => {\n const stageState = state.stages[s];\n return (\n !stageState ||\n stageState.state === \"pending\" ||\n stageState.state === \"running\"\n );\n });\n if (needsRun) {\n return step;\n }\n }\n }\n return null;\n}\n\n/**\n * Execute a single stage\n */\nasync function executeSingleStep(\n ctx: PipelineContext,\n pipeline: PipelineDefinition,\n state: PipelineStateV2,\n stageName: StageName,\n): Promise<PipelineStateV2> {\n const def = pipeline.stages.get(stageName);\n if (!def) {\n const msg = `Stage '${stageName}' not found in pipeline definitions — check pipeline order vs stage definitions`;\n logger.error(msg);\n throw new Error(msg);\n }\n\n // Check skip conditions\n if (def.shouldSkip) {\n const skipResult = def.shouldSkip(ctx);\n if (skipResult.shouldSkip) {\n logger.info(` ${stageName} skipped — ${skipResult.reason}`);\n logStageSkip(stageName, ctx.taskId, skipResult.reason);\n return updateStage(state, stageName, {\n state: \"skipped\",\n skipped: skipResult.reason,\n });\n }\n }\n\n // Check if already completed (resume)\n const stageState = state.stages[stageName];\n if (stageState?.state === \"completed\") {\n logger.info(` ${stageName} already completed, skipping`);\n return state;\n }\n\n // Mark as running\n state = updateStage(state, stageName, {\n state: \"running\",\n startedAt: new Date().toISOString(),\n });\n writeState(ctx.taskId, state);\n logStageStart(stageName, ctx.taskId);\n\n // Dry-run: mark completed without running\n if (ctx.input.dryRun) {\n return updateStage(state, stageName, { state: \"completed\", retries: 0 });\n }\n\n // Run preExecute hook if defined (G20)\n if (def.preExecute) {\n try {\n await def.preExecute(ctx);\n } catch (error) {\n logger.error({ err: error }, ` ❌ preExecute failed for ${stageName}:`);\n return updateStage(state, stageName, {\n state: \"failed\",\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Get handler and execute\n ciGroup(`Stage: ${stageName}`);\n try {\n const handler = getHandler(def.name, def.type);\n const result = await handler.execute(ctx, def);\n ciGroupEnd();\n\n // Route non-success outcomes through Observer for decision\n if (result.outcome === \"failed\" || result.outcome === \"timed_out\") {\n // Run post-actions FIRST to commit partial work\n if (def.postActions && !ctx.input.dryRun) {\n try {\n for (const action of def.postActions) {\n await executePostAction(ctx, action, state);\n }\n } catch (postError) {\n // Post-action failed — log but continue to Observer\n logger.error(\n { err: postError },\n ` Post-action failed for ${stageName}:`,\n );\n }\n }\n\n // Throw to route through Observer catch block below\n const errorMessage = `${stageName} ${result.outcome === \"timed_out\" ? \"timed out\" : \"failed\"}: ${result.reason || \"unknown\"}`;\n throw new Error(errorMessage);\n }\n\n return await handleStageResult(\n ctx,\n pipeline,\n state,\n stageName,\n result,\n def,\n );\n } catch (error) {\n ciGroupEnd();\n if (error instanceof PipelinePausedError) {\n // Handle paused - mark stage as paused and pipeline as paused\n state = updateStage(state, stageName, { state: \"paused\" });\n return completeState(state, \"paused\");\n }\n\n // Handle failure - mark stage as failed\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.error({ err: error }, ` ❌ ${stageName} failed:`);\n logStageFail(stageName, ctx.taskId, errorMessage);\n\n // Check if Observer is available (requires serverUrl and sessionId)\n const canObserve = ctx.serverUrl && ctx.lastSessionId && !ctx.input.dryRun;\n\n if (canObserve && !def.advisory) {\n // Delegate to Observer for complex failure handling\n // Pipeline is PAUSED while Observer waits for agent decision\n try {\n const observer = new PipelineObserver(\n ctx.taskId,\n ctx.taskDir,\n ctx.serverUrl!,\n ctx.lastSessionId!,\n ctx.taskDir, // dataDir is taskDir/opencode-data derived in Observer\n );\n\n const failure = {\n stageName,\n error: error instanceof Error ? error : new Error(String(error)),\n attempt: (state.stages[stageName]?.retries ?? 0) + 1,\n maxAttempts: def.maxRetries,\n taskDir: ctx.taskDir,\n };\n\n const observerResult = await observer.handle(failure);\n\n logger.info(\n `[StateMachine] Observer decision: ${observerResult.action} - ${observerResult.reason}`,\n );\n\n // Apply Observer's decision\n switch (observerResult.action) {\n case \"retry\":\n // Reset stage to pending for retry\n state = updateStage(state, stageName, {\n state: \"pending\",\n retries: observerResult.observerAttempt,\n error: `Observer retry: ${observerResult.reason}`,\n });\n return state;\n\n case \"escalate\":\n // Pause pipeline and notify (GitHub issue comment)\n state = updateStage(state, stageName, {\n state: \"failed\",\n error: `Observer escalate: ${observerResult.reason}`,\n });\n return completeState(state, \"paused\");\n\n case \"halt\":\n default:\n // Mark pipeline as failed\n state = updateStage(state, stageName, {\n state: \"failed\",\n error: `Observer halt: ${observerResult.reason}`,\n });\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, \"kody:failed\");\n }\n return completeState(state, \"failed\");\n }\n } catch (observerError) {\n // Observer failed - fall back to default failure handling\n logger.error(\n { err: observerError },\n `[StateMachine] Observer error, falling back`,\n );\n state = updateStage(state, stageName, {\n state: \"failed\",\n error: errorMessage,\n });\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, \"kody:failed\");\n }\n return completeState(state, \"failed\");\n }\n }\n\n // Default failure handling (no Observer available or advisory stage)\n state = updateStage(state, stageName, {\n state: \"failed\",\n error: errorMessage,\n });\n // For non-advisory stages, mark pipeline as failed to stop the loop\n if (!def.advisory) {\n // Set lifecycle label to failed\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, \"kody:failed\");\n }\n return completeState(state, \"failed\");\n }\n return state;\n }\n}\n\n/**\n * Execute parallel stages\n */\nasync function executeParallelStep(\n ctx: PipelineContext,\n pipeline: PipelineDefinition,\n state: PipelineStateV2,\n stageNames: StageName[],\n): Promise<PipelineStateV2> {\n logger.info(` Running parallel: [${stageNames.join(\", \")}]...`);\n\n // Filter out already completed/terminal stages (for resume)\n const stagesToRun = stageNames.filter((stageName) => {\n const stageState = state.stages[stageName];\n if (\n stageState?.state === \"completed\" ||\n stageState?.state === \"skipped\" ||\n stageState?.state === \"timeout\" ||\n stageState?.state === \"failed\"\n ) {\n logger.info(` ${stageName} already ${stageState.state}, skipping`);\n return false;\n }\n return true;\n });\n\n // If all stages already completed, return current state\n if (stagesToRun.length === 0) {\n return state;\n }\n\n // Dry-run: mark all parallel stages as completed without running\n if (ctx.input.dryRun) {\n for (const stageName of stagesToRun) {\n state = updateStage(state, stageName, { state: \"completed\", retries: 0 });\n }\n return state;\n }\n\n const results = await Promise.allSettled(\n stagesToRun.map(async (stageName) => {\n const def = pipeline.stages.get(stageName);\n if (!def) {\n throw new StageError(\n `Stage '${stageName}' not found in pipeline definitions`,\n stageName,\n );\n }\n\n // Check skip first\n if (def.shouldSkip) {\n const skipResult = def.shouldSkip(ctx);\n if (skipResult.shouldSkip) {\n return {\n stageName,\n result: {\n outcome: \"skipped\" as const,\n reason: skipResult.reason,\n retries: 0,\n },\n };\n }\n }\n\n // R10: Run preExecute hook if defined\n if (def.preExecute) {\n try {\n await def.preExecute(ctx);\n } catch (preError) {\n // Wrap error with stageName for rejection handler\n throw new StageError(\n preError instanceof Error ? preError.message : String(preError),\n stageName,\n preError instanceof Error ? preError : undefined,\n );\n }\n }\n\n // Execute - wrap to tag errors with stageName\n try {\n const handler = getHandler(def.name, def.type);\n const result = await handler.execute(ctx, def);\n return { stageName, result };\n } catch (error) {\n // Wrap error with stageName for rejection handler\n throw new StageError(\n error instanceof Error ? error.message : String(error),\n stageName,\n error instanceof Error ? error : undefined,\n );\n }\n }),\n );\n\n // Process results - distinguish critical vs advisory failures (R7)\n const criticalFailures: { name: string; reason: string }[] = [];\n const advisoryFailures: { name: string; reason: string }[] = [];\n let pausedStage: string | null = null;\n\n for (const result of results) {\n if (result.status === \"rejected\") {\n // G30: Check if this is a PipelinePausedError (direct or wrapped in StageError)\n const rejectedErr = result.reason;\n const isPaused =\n rejectedErr instanceof PipelinePausedError ||\n (rejectedErr instanceof StageError &&\n rejectedErr.cause instanceof PipelinePausedError);\n if (isPaused) {\n // Mark the stage as paused and collect — don't return early\n // This allows other parallel stages to complete their post-actions\n const pausedStageName =\n rejectedErr instanceof StageError ? rejectedErr.stageName : \"unknown\";\n state = updateStage(state, pausedStageName, { state: \"paused\" });\n pausedStage = pausedStageName;\n continue;\n }\n\n const reason = (result as PromiseRejectedResult).reason;\n const name =\n reason instanceof StageError\n ? reason.stageName\n : (((reason as Record<string, unknown>)?.stageName as string) ??\n \"unknown\");\n const message = reason instanceof Error ? reason.message : String(reason);\n // R7: Use dynamic advisory lookup from pipeline definition\n const isAdvisory =\n pipeline.stages.get(name as StageName)?.advisory === true;\n if (isAdvisory) {\n // R2: Mark advisory rejected stage as failed in state\n state = updateStage(state, name, { state: \"failed\", error: message });\n advisoryFailures.push({ name, reason: message });\n } else {\n // R1: Mark stage as failed in state before throwing\n state = updateStage(state, name, { state: \"failed\", error: message });\n criticalFailures.push({ name, reason: message });\n }\n continue;\n }\n\n const { stageName, result: stageResult } = result.value;\n if (!stageResult) continue;\n\n // Handle PipelinePausedError specially (G30) — collect pauses instead of returning early\n if (stageResult.outcome === \"paused\") {\n state = updateStage(state, stageName, { state: \"paused\" });\n pausedStage = stageName;\n continue;\n }\n\n // Update state based on outcome\n if (stageResult.outcome === \"completed\") {\n state = updateStage(state, stageName, {\n state: \"completed\",\n completedAt: new Date().toISOString(),\n retries: stageResult.retries,\n outputFile: stageResult.outputFile,\n sessionId: stageResult.sessionId,\n });\n\n // FIX #2: Propagate sessionId deterministically — use the stage that comes\n // last in the pipeline order, regardless of which parallel stage completes first.\n // This ensures consistent session forking across runs.\n if (stageResult.sessionId) {\n if (!ctx.lastSessionId) {\n ctx.lastSessionId = stageResult.sessionId;\n } else {\n // Overwrite only if this stage comes after the current lastSessionId owner\n // in the pipeline order. Since we process results in order, the last\n // successful stage's sessionId is used.\n ctx.lastSessionId = stageResult.sessionId;\n }\n }\n\n // R8: Run post-actions for completed parallel stages\n const def = pipeline.stages.get(stageName);\n if (def?.postActions && !ctx.input.dryRun) {\n try {\n for (const action of def.postActions) {\n await executePostAction(ctx, action, state);\n }\n } catch (postError) {\n // Handle post-action errors - mirroring executeSingleStep pattern\n // Collect pauses instead of returning early — allows other stages to complete\n if (postError instanceof PipelinePausedError) {\n state = updateStage(state, stageName, { state: \"paused\" });\n pausedStage = stageName;\n continue;\n }\n // FIX #3: Don't immediately fail - collect failures and process at end\n // This allows other successful parallel stages to complete\n logger.error(\n { err: postError },\n ` Post-action failed for parallel stage ${stageName}:`,\n );\n const postErrorMsg =\n postError instanceof Error ? postError.message : String(postError);\n state = updateStage(state, stageName, {\n state: \"failed\",\n error: postErrorMsg,\n });\n const isAdvisory = pipeline.stages.get(stageName)?.advisory === true;\n if (isAdvisory) {\n advisoryFailures.push({ name: stageName, reason: postErrorMsg });\n } else {\n criticalFailures.push({ name: stageName, reason: postErrorMsg });\n }\n }\n }\n } else if (stageResult.outcome === \"skipped\") {\n state = updateStage(state, stageName, {\n state: \"skipped\",\n skipped: stageResult.reason,\n });\n } else if (stageResult.outcome === \"timed_out\") {\n // Handle timeout in parallel stages — previously missing, causing infinite retry loops\n const isAdvisory = pipeline.stages.get(stageName)?.advisory === true;\n state = updateStage(state, stageName, {\n state: \"timeout\",\n error: stageResult.reason || \"timed out\",\n });\n if (!isAdvisory) {\n criticalFailures.push({\n name: stageName,\n reason: stageResult.reason || \"timed out\",\n });\n }\n } else if (stageResult.outcome === \"failed\") {\n // R7: Use dynamic advisory lookup from pipeline definition\n const isAdvisory = pipeline.stages.get(stageName)?.advisory === true;\n if (isAdvisory) {\n // R1: Mark stage as failed in state\n state = updateStage(state, stageName, {\n state: \"failed\",\n error: stageResult.reason || \"failed\",\n });\n advisoryFailures.push({\n name: stageName,\n reason: stageResult.reason || \"failed\",\n });\n } else {\n // R1: Mark stage as failed in state before returning failed state\n state = updateStage(state, stageName, {\n state: \"failed\",\n error: stageResult.reason || \"failed\",\n });\n criticalFailures.push({\n name: stageName,\n reason: stageResult.reason || \"failed\",\n });\n }\n }\n }\n\n // R2: Return failed state instead of throwing (main loop sees failed state and breaks cleanly)\n if (criticalFailures.length > 0) {\n const errors = criticalFailures.map((f) => f.reason).join(\"; \");\n const names = criticalFailures.map((f) => f.name);\n logger.error(\n ` ❌ Parallel stages [${names.join(\", \")}] failed: ${errors}`,\n );\n // Set lifecycle label to failed\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, \"kody:failed\");\n }\n return completeState(state, \"failed\");\n }\n\n // Return paused state if any stage paused — after all other stages processed\n if (pausedStage) {\n writeState(ctx.taskId, state);\n return completeState(state, \"paused\");\n }\n\n return state;\n}\n\n/**\n * Handle stage result and run post-actions\n */\nasync function handleStageResult(\n ctx: PipelineContext,\n pipeline: PipelineDefinition,\n state: PipelineStateV2,\n stageName: StageName,\n result: StageResult,\n def: StageDefinition,\n): Promise<PipelineStateV2> {\n // Compute elapsed time from startedAt\n const startedAt = state.stages[stageName]?.startedAt;\n const elapsed = startedAt\n ? Math.round((Date.now() - new Date(startedAt).getTime()) / 1000)\n : undefined;\n\n if (result.outcome === \"completed\") {\n state = updateStage(state, stageName, {\n state: \"completed\",\n completedAt: new Date().toISOString(),\n elapsed,\n retries: result.retries,\n outputFile: result.outputFile,\n tokenUsage: result.tokenUsage,\n cost: result.cost,\n sessionId: result.sessionId,\n });\n logStageComplete(\n stageName,\n ctx.taskId,\n \"completed\",\n elapsed ? elapsed * 1000 : undefined,\n );\n\n // Propagate sessionId for downstream stage forking\n if (result.sessionId) {\n ctx.lastSessionId = result.sessionId;\n }\n\n // Run post-actions if defined\n if (def.postActions) {\n for (const action of def.postActions) {\n await executePostAction(ctx, action, state);\n // Note: executePostAction may throw PipelinePausedError\n // which propagates up to executeSingleStep's catch block\n }\n }\n } else if (result.outcome === \"failed\") {\n // Generic declarative retry via retryWith\n if (def.retryWith && !def.advisory) {\n const { stage: retryStage, maxAttempts, onFailure } = def.retryWith;\n const retryState = state.stages[retryStage];\n const currentAttempt = retryState?.fixAttempt ?? 0;\n\n if (currentAttempt < maxAttempts) {\n if (onFailure) {\n await onFailure(ctx, ctx.taskDir);\n }\n\n const newAttempt = currentAttempt + 1;\n state = updateStage(state, retryStage, {\n state: \"pending\",\n fixAttempt: newAttempt,\n maxFixAttempts: maxAttempts,\n });\n state = updateStage(state, stageName, { state: \"pending\" });\n writeState(ctx.taskId, state);\n\n logStageRetry(stageName, ctx.taskId, newAttempt, maxAttempts);\n logger.info(\n `🔄 ${stageName} failed, looping to ${retryStage} (attempt ${newAttempt}/${maxAttempts})`,\n );\n return state;\n } else {\n logger.error(\n `Max retry attempts (${maxAttempts}) reached for ${retryStage}, pipeline failing`,\n );\n // Fall through to normal failure handling\n }\n }\n\n // Normal failure handling\n state = updateStage(state, stageName, {\n state: \"failed\",\n elapsed,\n error: result.reason,\n });\n\n // If non-advisory stage failed, mark pipeline as failed\n if (!def.advisory) {\n // Set lifecycle label to failed\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, \"kody:failed\");\n }\n return completeState(state, \"failed\");\n }\n } else if (result.outcome === \"timed_out\") {\n state = updateStage(state, stageName, {\n state: \"timeout\",\n elapsed,\n error: result.reason,\n });\n\n // Generic timeout recovery: if any stage declares retryWith pointing to this\n // timed-out stage with onTimeout: 'retry', reset that stage to pending so it\n // can re-evaluate (e.g., verify checks if partial fix work was enough).\n const retryingDef = [...pipeline.stages.values()].find(\n (s) =>\n s.retryWith?.stage === stageName && s.retryWith.onTimeout === \"retry\",\n );\n if (retryingDef) {\n logger.info(\n `⚠️ ${stageName} timed out — running ${retryingDef.name} to check if partial work suffices`,\n );\n state = updateStage(state, retryingDef.name, { state: \"pending\" });\n writeState(ctx.taskId, state);\n return state; // Don't fail pipeline — let the retrying stage check\n }\n\n if (!def.advisory) {\n // Set lifecycle label to failed\n if (ctx.input.issueNumber) {\n setLifecycleLabel(ctx.input.issueNumber, \"kody:failed\");\n }\n return completeState(state, \"failed\");\n }\n }\n\n return state;\n}\n","/**\n * @fileType utility\n * @domain kody | task\n * @pattern task-setup\n * @ai-summary Task directory and file preparation — extracted to avoid circular dependency between entry.ts and modes/\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext } from './engine/types'\nimport { logger } from './logger'\n\n/**\n * Ensures task.md exists before pipeline runs (needed for taskify agent).\n * - Uses --file flag content if provided\n * - Fetches from GitHub issue body if --issue-number provided\n * - Throws if neither available and task.md doesn't exist\n */\nexport async function ensureTaskMd(ctx: PipelineContext): Promise<void> {\n const { input, taskDir } = ctx\n const taskMdPath = path.join(taskDir, 'task.md')\n\n // --file flag has priority\n if (input.file) {\n const resolvedFile = path.resolve(input.file)\n if (!fs.existsSync(resolvedFile)) {\n throw new Error(`File not found: ${resolvedFile}`)\n }\n const content = fs.readFileSync(resolvedFile, 'utf-8').trim()\n if (!content) {\n throw new Error(`File is empty: ${resolvedFile}`)\n }\n fs.writeFileSync(taskMdPath, `# Task\\n\\n${content}\\n`)\n logger.info(`Created task.md from ${resolvedFile}`)\n return\n }\n\n // Create task.md from issue body if it doesn't exist\n if (!fs.existsSync(taskMdPath)) {\n if (input.issueNumber) {\n const { getIssue } = await import('./github-api')\n logger.info('task.md not found, fetching issue body to create it...')\n const { body: issueBody, title: issueTitle } = getIssue(input.issueNumber)\n if (issueBody) {\n const titleSection = issueTitle ? `## Issue Title\\n\\n${issueTitle}\\n` : ''\n fs.writeFileSync(taskMdPath, `# Task\\n\\n${titleSection}${issueBody}\\n`)\n logger.info(`Created task.md from issue #${input.issueNumber}`)\n } else {\n throw new Error(\n `task.md not found in .tasks/${input.taskId}/ and issue #${input.issueNumber} has no body. Create it first.`,\n )\n }\n } else {\n throw new Error(`task.md not found in .tasks/${input.taskId}/. Create it first.`)\n }\n }\n}\n","/**\n * @fileType handler\n * @domain kody | modes\n * @ai-summary Pipeline mode handler — extracted from entry.ts for modularity\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext } from '../engine/types'\nimport { PipelinePausedError } from '../engine/types'\nimport { runPipeline } from '../engine/state-machine'\nimport { resolvePipelineForMode } from '../engine/pipeline-resolver'\nimport { logger } from '../logger'\nimport { commitPipelineFiles } from '../git-utils'\n\nimport { ensureTaskMd } from '../task-setup'\nimport { handleClarification } from '../clarify-workflow'\nimport { postComment } from '../github-api'\n\nexport async function runSpecMode(ctx: PipelineContext): Promise<void> {\n const { input, taskDir } = ctx\n\n // R4: Ensure task.md exists before running pipeline\n await ensureTaskMd(ctx)\n\n // Run spec pipeline\n const pipeline = resolvePipelineForMode('spec', 'standard', input.clarify ?? false, ctx)\n await runPipeline(ctx, pipeline)\n\n // G17: Post-spec clarification logic\n if (input.clarify) {\n const clarifyResult = handleClarification(input, taskDir)\n if (clarifyResult === 'waiting') {\n logger.info('\\n⚠️ Clarify stage has questions that need answering')\n const questionsPath = path.join(taskDir, 'questions.md')\n if (input.issueNumber) {\n let preview = '(questions file not found)'\n try {\n if (fs.existsSync(questionsPath)) {\n const questionsContent = fs.readFileSync(questionsPath, 'utf-8')\n preview = questionsContent.slice(0, 1500)\n }\n } catch (readErr) {\n logger.warn({ err: readErr }, 'Failed to read questions.md for preview')\n }\n postComment(\n input.issueNumber,\n `🔄 Kody stopped at clarify stage - questions need answering:\\n\\n${preview}\\n\\nPlease answer these questions and call \\`/kody\\` again to proceed with implementation.`,\n )\n }\n // Commit task files and pause\n commitPipelineFiles({\n taskDir,\n taskId: input.taskId,\n message: `ci(kody): Save task files for ${input.taskId}\\n\\nAuto-committed by Kody pipeline`,\n ensureBranch: true,\n cleanDirtyState: true,\n stagingStrategy: 'task-only',\n push: true,\n isCI: !input.local,\n dryRun: input.dryRun,\n })\n throw new PipelinePausedError(`clarify stage: awaiting answers for ${input.taskId}`)\n }\n }\n\n // Commit spec task files\n commitPipelineFiles({\n taskDir,\n taskId: input.taskId,\n message: `ci(kody): Save task files for ${input.taskId}\\n\\nAuto-committed by Kody pipeline`,\n ensureBranch: true,\n cleanDirtyState: true,\n stagingStrategy: 'task-only',\n push: true,\n isCI: !input.local,\n dryRun: input.dryRun,\n })\n\n logger.info('\\n✅ Kody SPEC pipeline complete')\n}\n","/**\n * @fileType handler\n * @domain kody | modes\n * @ai-summary Pipeline mode handler — extracted from entry.ts for modularity\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext } from '../engine/types'\nimport { runPipeline } from '../engine/state-machine'\nimport { resolvePipelineForMode, createRebuildCallback } from '../engine/pipeline-resolver'\nimport { logger } from '../logger'\nimport { readTask } from '../pipeline-utils'\n\nexport async function runImplMode(ctx: PipelineContext): Promise<void> {\n const { taskDir } = ctx\n\n // Validate clarified.md exists\n const clarifiedPath = path.join(taskDir, 'clarified.md')\n if (!fs.existsSync(clarifiedPath)) {\n throw new Error(`clarified.md not found. Run spec pipeline first or create it.`)\n }\n\n // Get task definition\n let taskDef\n try {\n taskDef = readTask(taskDir)\n ctx.taskDef = taskDef\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error)\n logger.error(`\\n❌ Failed to read task definition: ${msg}`)\n throw new Error(`Invalid task.json: ${msg}`)\n }\n if (!taskDef) {\n throw new Error(`task.json not found. Run spec pipeline first.`)\n }\n\n // Apply --complexity override if provided (for testing/debugging)\n if (ctx.input.complexityOverride !== undefined) {\n const oldComplexity = taskDef.complexity\n taskDef.complexity = ctx.input.complexityOverride\n taskDef.complexity_reasoning = `Override via --complexity=${ctx.input.complexityOverride}`\n if (oldComplexity !== undefined) {\n logger.info(` ℹ️ Complexity override: ${oldComplexity} → ${ctx.input.complexityOverride}`)\n } else {\n logger.info(` ℹ️ Complexity override applied: ${ctx.input.complexityOverride}`)\n }\n }\n\n // Check spec_only pipeline\n if (taskDef.pipeline === 'spec_only') {\n logger.info('Task pipeline is spec_only — skipping implementation stages.')\n return\n }\n\n // Resolve profile\n const { resolvePipelineProfile } = await import('../pipeline-utils')\n ctx.profile = resolvePipelineProfile(taskDef)\n logger.info(`ℹ️ Pipeline profile: ${ctx.profile}`)\n\n // Run impl pipeline (pass rebuild callback for two-phase construction)\n const pipeline = resolvePipelineForMode('impl', ctx.profile, false, ctx)\n const rebuild = createRebuildCallback('full', ctx.input.clarify ?? false)\n await runPipeline(ctx, pipeline, undefined, rebuild)\n\n logger.info('\\n✅ Kody IMPLEMENTATION pipeline complete')\n}\n","/**\n * @fileType handler\n * @domain kody | modes\n * @ai-summary Pipeline mode handler — extracted from entry.ts for modularity\n */\n\nimport type { PipelineContext } from '../engine/types'\nimport { PipelinePausedError } from '../engine/types'\nimport { runPipeline } from '../engine/state-machine'\nimport { resolvePipelineForMode, createRebuildCallback } from '../engine/pipeline-resolver'\nimport { logger } from '../logger'\nimport { readTask } from '../pipeline-utils'\n\nimport { ensureTaskMd } from '../task-setup'\n\nexport async function runFullMode(ctx: PipelineContext): Promise<void> {\n logger.info('Running FULL Kody pipeline (spec + impl)...\\n')\n\n // FIX: If a previous run left state as failed/completed/paused, delete it so the\n // pipeline starts fresh. Without this, runPipeline() sees the terminal state\n // in status.json and returns immediately without executing any stages.\n // Paused state is included because a gate-paused status.json from a previous run\n // causes the dashboard to show stale \"Classifying\" until the new run pushes an update.\n const { loadState: loadSt2, deleteState } = await import('../engine/status')\n const prevState = loadSt2(ctx.taskId)\n if (\n prevState &&\n (prevState.state === 'failed' ||\n prevState.state === 'completed' ||\n prevState.state === 'paused')\n ) {\n logger.info(` Previous run state: ${prevState.state} — resetting for fresh full-mode run`)\n deleteState(ctx.taskId)\n }\n\n // R4: Ensure task.md exists before running pipeline\n await ensureTaskMd(ctx)\n\n // FIX #5: Resolve profile from task.json instead of hardcoding 'standard'\n // This ensures the correct profile (lightweight vs standard) is used\n let profile: 'standard' | 'lightweight' | 'turbo' = 'standard'\n try {\n const taskDef = readTask(ctx.taskDir)\n if (taskDef) {\n ctx.taskDef = taskDef\n const { resolvePipelineProfile } = await import('../pipeline-utils')\n profile = resolvePipelineProfile(taskDef)\n logger.info(`ℹ️ Resolved profile from task.json: ${profile}`)\n }\n } catch {\n // If task.json doesn't exist yet, taskify will create it and resolve profile\n logger.info('ℹ️ task.json not found yet, will resolve profile after taskify')\n }\n ctx.profile = profile\n\n // Run full pipeline - pass rebuild callback for two-phase construction\n // This ensures profile changes after taskify are reflected in later stages\n const pipeline = resolvePipelineForMode('full', profile, ctx.input.clarify ?? false, ctx)\n const rebuild = createRebuildCallback('full', ctx.input.clarify ?? false)\n const finalState = await runPipeline(ctx, pipeline, undefined, rebuild)\n\n // Handle paused state (gate approval required)\n if (finalState.state === 'paused') {\n throw new PipelinePausedError(`Pipeline paused — awaiting gate approval for ${ctx.taskId}`)\n }\n\n logger.info('\\n✅ Full Kody pipeline complete!')\n}\n","/**\n * @fileType utility\n * @domain kody | brain\n * @ai-summary Health check utility for brain server availability\n */\n\n/**\n * Check if brain server is available at the given URL.\n * Returns false if URL is undefined/empty or if the server doesn't respond within 5s.\n */\nexport async function isBrainAvailable(url: string | undefined): Promise<boolean> {\n if (!url) return false\n try {\n // Strip /sse suffix if present to get base URL for health check\n const baseUrl = url.replace(/\\/sse$/, '')\n const resp = await fetch(baseUrl, { signal: AbortSignal.timeout(5000) })\n return resp.ok\n } catch {\n return false\n }\n}\n","/**\n * @fileType utility\n * @domain kody | brain\n * @pattern mcp-client | claude-api\n * @ai-summary MCP client + Claude API wrapper for remote brain server communication\n */\n\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'\nimport Anthropic from '@anthropic-ai/sdk'\n\nexport interface BrainResult {\n output: string\n toolCalls: number\n tokensUsed: number\n}\n\n/**\n * Connect to a remote brain server via SSE MCP.\n * The serverUrl should be the SSE endpoint, e.g. http://100.x.x.x:4097/sse\n */\nexport async function connectBrain(serverUrl: string): Promise<Client> {\n const transport = new SSEClientTransport(new URL(serverUrl))\n const client = new Client({ name: 'kody-brain', version: '1.0.0' })\n await client.connect(transport)\n return client\n}\n\n/**\n * Check if brain server is reachable (HTTP health check with 5s timeout).\n */\nexport async function isBrainHealthy(serverUrl: string): Promise<boolean> {\n try {\n // Strip /sse suffix if present to get base URL for health check\n const baseUrl = serverUrl.replace(/\\/sse$/, '')\n const resp = await fetch(baseUrl, { signal: AbortSignal.timeout(5000) })\n return resp.ok\n } catch {\n return false\n }\n}\n\n/**\n * Run a brain task: connect to MCP, convert tools to Anthropic format,\n * then execute a tool-use loop with Claude API.\n */\nexport async function runBrain(\n serverUrl: string,\n systemPrompt: string,\n userMessage: string,\n model: string = 'claude-opus-4-20250514',\n): Promise<BrainResult> {\n // 1. Connect to Context+ MCP\n const mcpClient = await connectBrain(serverUrl)\n const { tools } = await mcpClient.listTools()\n\n // 2. Convert MCP tools to Anthropic tool format\n // The MCP inputSchema is JSON Schema compatible with Anthropic's tool format.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const anthropicTools: any[] = tools.map((tool) => ({\n name: tool.name,\n description: tool.description || '',\n input_schema: tool.inputSchema,\n }))\n\n // 3. Call Claude with tools\n const anthropic = new Anthropic()\n type MessageRole = 'user' | 'assistant'\n type MessageContent = string | unknown\n const messages: Array<{ role: MessageRole; content: MessageContent }> = [\n { role: 'user', content: userMessage },\n ]\n let toolCalls = 0\n let totalTokens = 0\n\n // 4. Tool-use loop\n while (true) {\n const response = await anthropic.messages.create({\n model,\n max_tokens: 8192,\n system: systemPrompt,\n messages: messages as never,\n tools: anthropicTools,\n })\n\n totalTokens += response.usage.input_tokens + response.usage.output_tokens\n\n // If no tool use, we're done\n if (response.stop_reason === 'end_turn') {\n const textBlock = response.content.find((b) => b.type === 'text')\n await mcpClient.close()\n return {\n output: textBlock?.text || '',\n toolCalls,\n tokensUsed: totalTokens,\n }\n }\n\n // Execute tool calls against Context+ MCP\n const toolResults: Array<{\n type: 'tool_result'\n tool_use_id: string\n content: Array<{ type: 'text'; text: string }>\n }> = []\n for (const block of response.content) {\n if (block.type === 'tool_use') {\n toolCalls++\n const result = await mcpClient.callTool({\n name: block.name,\n arguments: block.input as Record<string, unknown>,\n })\n toolResults.push({\n type: 'tool_result',\n tool_use_id: block.id,\n content: [{ type: 'text', text: String(result.content) }],\n })\n }\n }\n\n // Add assistant response + tool results to conversation\n messages.push({ role: 'assistant', content: response.content as never })\n messages.push({ role: 'user', content: toolResults })\n }\n}\n","/**\n * @fileType handler\n * @domain kody | brain | architect\n * @ai-summary Brain-based architect stage that replaces taskify+gap+architect\n */\n\nimport { runBrain } from './brain-client'\n\nconst ARCHITECT_PROMPT = `You are the architect for the Kody pipeline.\nYour job is to analyze a task and produce two outputs:\n\n1. task.json — structured task definition\n2. plan.md — detailed implementation plan with TDD test gates\n\nYou have access to codebase intelligence tools. USE THEM:\n- semantic_code_search: Find relevant code by meaning\n- get_blast_radius: Check what depends on a symbol before changing it\n- get_file_skeleton: See function signatures without reading full files\n- get_context_tree: Understand project structure\n- search_memory_graph: Check if similar tasks were done before\n- semantic_navigate: Browse codebase by meaning clusters\n\nWORKFLOW:\n1. Read the task description\n2. Use semantic_code_search to find relevant existing code\n3. Use get_blast_radius on any functions you plan to modify\n4. Use get_context_tree to understand the area of the codebase\n5. Use search_memory_graph for lessons from previous tasks\n6. Produce task.json and plan.md\n\nOutput format:\n\\`\\`\\`json:task.json\n{ ... }\n\\`\\`\\`\n\n\\`\\`\\`markdown:plan.md\n# Plan\n...\n\\`\\`\\`\n`\n\nexport interface ArchitectResult {\n taskJson: object\n planMd: string\n}\n\n/**\n * Run the architect stage using the remote brain.\n * Parses task.json and plan.md from the brain's output.\n */\nexport async function runArchitectBrain(\n taskMd: string,\n brainUrl: string,\n): Promise<ArchitectResult> {\n const result = await runBrain(brainUrl, ARCHITECT_PROMPT, taskMd)\n\n // Parse task.json and plan.md from output\n const taskJsonMatch = result.output.match(/```json:task\\.json\\n([\\s\\S]*?)```/)\n const planMdMatch = result.output.match(/```markdown:plan\\.md\\n([\\s\\S]*?)```/)\n\n return {\n taskJson: taskJsonMatch ? JSON.parse(taskJsonMatch[1]) : {},\n planMd: planMdMatch?.[1] || result.output,\n }\n}\n","/**\n * @fileType handler\n * @domain kody | brain | review\n * @ai-summary Brain-based review stage using remote brain server\n */\n\nimport { runBrain } from './brain-client'\n\nconst REVIEW_PROMPT = `You are the code reviewer for the Kody pipeline.\nYour job is to review code changes against the plan and produce a review.\n\nYou have access to codebase intelligence tools. USE THEM:\n- get_blast_radius: Check if changes break anything else\n- semantic_code_search: Find related code that might need updating\n- run_static_analysis: Run linters for type errors and dead code\n- get_file_skeleton: Check if changed functions match existing patterns\n- search_memory_graph: Check for known issues with similar changes\n\nWORKFLOW:\n1. Read the plan and changed files\n2. Use get_blast_radius on every modified function\n3. Use run_static_analysis on changed files\n4. Use semantic_code_search to find related code that might be affected\n5. Produce review.md with findings\n\nBe specific. Reference file paths and line numbers.\nCategorize findings as: critical (blocks merge), warning (should fix), info (suggestion).\n`\n\n/**\n * Run the review stage using the remote brain.\n */\nexport async function runReviewBrain(\n planMd: string,\n changedFiles: string[],\n diffs: string,\n brainUrl: string,\n): Promise<string> {\n const userMessage = `## Plan\\n${planMd}\\n\\n## Changed Files\\n${changedFiles.join('\\n')}\\n\\n## Diffs\\n${diffs}`\n const result = await runBrain(brainUrl, REVIEW_PROMPT, userMessage)\n return result.output\n}\n","/**\n * @fileType handler\n * @domain kody | modes | brain\n * @ai-summary Brain-aware full mode — uses remote brain for architect + review when available\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext } from '../engine/types'\nimport { PipelinePausedError } from '../engine/types'\nimport { runPipeline } from '../engine/state-machine'\nimport { resolvePipelineForMode } from '../engine/pipeline-resolver'\nimport { logger } from '../logger'\nimport { ensureTaskMd } from '../task-setup'\nimport { isBrainAvailable } from '../brain-health'\nimport { runArchitectBrain } from '../architect-brain'\nimport { runReviewBrain } from '../review-brain'\nimport { parseTaskDefinition } from '../pipeline/task-schema'\n\n/**\n * Brain-aware full mode handler.\n *\n * When BRAIN_SERVER_URL is set and brain is reachable:\n * 1. Run remote architect (replaces taskify + gap + architect)\n * 2. Write task.json + plan.md to taskDir\n * 3. Run local impl pipeline (build + verify)\n * 4. Run remote review\n * 5. Write review.md to taskDir\n * 6. Proceed to commit + PR\n *\n * When brain is unavailable:\n * Falls back to standard full pipeline.\n */\nexport async function runBrainFullMode(ctx: PipelineContext): Promise<void> {\n const BRAIN_SERVER_URL = process.env.BRAIN_SERVER_URL\n\n // Check brain availability\n const brainAvailable = await isBrainAvailable(BRAIN_SERVER_URL)\n\n if (!brainAvailable || !BRAIN_SERVER_URL) {\n logger.info('🧠 Brain server unavailable — falling back to standard pipeline')\n // Import and call standard full mode\n const { runFullMode } = await import('./full')\n return runFullMode(ctx)\n }\n\n logger.info('🧠 Brain server available — using remote architect + review')\n\n // R4: Ensure task.md exists before running pipeline\n await ensureTaskMd(ctx)\n\n // Read task.md for architect input\n const taskMdPath = path.join(ctx.taskDir, 'task.md')\n const taskMd = fs.readFileSync(taskMdPath, 'utf-8')\n\n // Phase 1: Remote architect (replaces taskify + gap + architect)\n logger.info(' 🧠 Running remote architect...')\n let taskJson: object = {}\n let planMd = ''\n\n try {\n const result = await runArchitectBrain(taskMd, BRAIN_SERVER_URL)\n taskJson = result.taskJson\n planMd = result.planMd\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error)\n logger.error({ err: error }, ` 🧠 Architect brain failed: ${errorMsg}`)\n logger.info(' Falling back to standard pipeline...')\n const { runFullMode } = await import('./full')\n return runFullMode(ctx)\n }\n\n // Validate and write task.json\n try {\n const validatedTask = parseTaskDefinition(taskJson)\n const taskJsonPath = path.join(ctx.taskDir, 'task.json')\n fs.writeFileSync(taskJsonPath, JSON.stringify(validatedTask, null, 2) + '\\n')\n ctx.taskDef = validatedTask\n logger.info(' ✅ task.json written')\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error)\n logger.warn({ err: error }, ` ⚠️ task.json validation failed, using raw output: ${errorMsg}`)\n // Write raw JSON as fallback\n const taskJsonPath = path.join(ctx.taskDir, 'task.json')\n fs.writeFileSync(taskJsonPath, JSON.stringify(taskJson, null, 2) + '\\n')\n }\n\n // Write plan.md\n const planMdPath = path.join(ctx.taskDir, 'plan.md')\n fs.writeFileSync(planMdPath, planMd)\n logger.info(' ✅ plan.md written')\n\n // Resolve profile from task.json\n let profile: 'standard' | 'lightweight' | 'turbo' = 'standard'\n if (ctx.taskDef?.pipeline_profile) {\n profile = ctx.taskDef.pipeline_profile\n }\n ctx.profile = profile\n logger.info(`ℹ️ Profile: ${profile}`)\n\n // Phase 2: Local impl pipeline (build + verify)\n // Uses 'impl' mode to skip spec stages (already done by brain)\n const pipeline = resolvePipelineForMode('impl', profile, false, ctx)\n logger.info(' 🔨 Running local impl pipeline (build + verify)...')\n const finalState = await runPipeline(ctx, pipeline)\n\n // Handle paused state (gate approval required)\n if (finalState.state === 'paused') {\n throw new PipelinePausedError(`Pipeline paused — awaiting gate approval for ${ctx.taskId}`)\n }\n\n // Phase 3: Remote review\n logger.info(' 🧠 Running remote review...')\n const changedFiles = getChangedFiles(ctx.taskDir)\n const diffs = getDiffs()\n\n try {\n const reviewMd = await runReviewBrain(planMd, changedFiles, diffs, BRAIN_SERVER_URL)\n const reviewMdPath = path.join(ctx.taskDir, 'review.md')\n fs.writeFileSync(reviewMdPath, reviewMd)\n logger.info(' ✅ review.md written')\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error)\n logger.warn({ err: error }, ` ⚠️ Review brain failed: ${errorMsg}`)\n // Write placeholder review\n const reviewMdPath = path.join(ctx.taskDir, 'review.md')\n fs.writeFileSync(\n reviewMdPath,\n `# Review\\n\\nBrain review unavailable: ${errorMsg}\\n\\nRun standard pipeline to get a proper review.`,\n )\n }\n\n logger.info('\\n✅ Brain-aware full Kody pipeline complete!')\n}\n\n/**\n * Get list of changed files from git.\n */\n/* eslint-disable @typescript-eslint/no-require-imports */\nfunction getChangedFiles(_taskDir: string): string[] {\n try {\n const { execFileSync } = require('child_process')\n const diff = execFileSync('git', ['diff', '--name-only'], { encoding: 'utf-8' }).trim()\n const untracked = execFileSync('git', ['ls-files', '--others', '--exclude-standard'], {\n encoding: 'utf-8',\n }).trim()\n const allChanged = [...diff.split('\\n'), ...untracked.split('\\n')]\n .filter(Boolean)\n .filter((f: string) => !f.startsWith('.tasks/') && !f.startsWith('node_modules/'))\n return allChanged\n } catch {\n return []\n }\n}\n\n/**\n * Get git diff for changed files.\n */\n/* eslint-disable @typescript-eslint/no-require-imports */\nfunction getDiffs(): string {\n try {\n const { execFileSync } = require('child_process')\n const diff = execFileSync('git', ['diff'], { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 })\n return diff\n } catch {\n return ''\n }\n}\n","/**\n * @fileType utility\n * @domain kody | rerun\n * @ai-summary Pure function to resolve rerun fromStage with feedback routing\n */\n\nimport { STAGE_NAMES as ALL_STAGES } from './stages/registry'\n\n/**\n * When feedback is provided and fromStage is AFTER architect in the impl pipeline,\n * back up to architect so the plan can be revised with the feedback.\n *\n * Only backs up if fromStage is strictly AFTER plan-gap (i.e., build or later).\n * If fromStage IS architect or plan-gap, keep it (architect already reads feedback,\n * plan-gap is between architect and build so architect would run first anyway on reset).\n *\n * If fromStage is NOT in the impl stages (e.g., a spec stage like 'taskify'),\n * it's left unchanged — spec stages don't have an architect to back up to.\n */\nexport function resolveRerunFromStage(\n fromStage: string,\n feedback: string | undefined,\n implStages: string[],\n): string {\n // No feedback → no change\n if (!feedback) return fromStage\n\n const architectIdx = implStages.indexOf('architect')\n const fromIdx = implStages.indexOf(fromStage)\n\n // fromStage not in impl stages (e.g., spec stage like 'taskify') → no change\n if (fromIdx === -1 || architectIdx === -1) return fromStage\n\n // Only back up if fromStage is strictly after plan-gap (i.e., build or later)\n // architect=0, plan-gap=1, build=2, commit=3, ...\n const planGapIdx = implStages.indexOf('plan-gap')\n const threshold = planGapIdx !== -1 ? planGapIdx : architectIdx\n\n if (fromIdx > threshold) {\n return 'architect'\n }\n\n return fromStage\n}\n\n/**\n * After a gate is approved in rerun mode, determine which stage to reset FROM.\n * We must NOT reset the approved stage itself (that would overwrite the approval).\n * Instead, return the next stage in the pipeline after the approved gate.\n *\n * Fix for issue #673: gate approval overwritten by resetFromStage.\n *\n * @param approvedStage - The stage that was just approved (e.g., 'taskify')\n * @param pipelineOrder - Flat list of all stages in execution order\n * @returns The next stage after the approved one, or the approved stage itself as fallback\n */\nexport function resolveFromStageAfterGateApproval(\n approvedStage: string,\n pipelineOrder: string[],\n): string {\n const approvedIdx = pipelineOrder.indexOf(approvedStage)\n if (approvedIdx === -1) return approvedStage\n\n const nextIdx = approvedIdx + 1\n if (nextIdx < pipelineOrder.length) {\n return pipelineOrder[nextIdx]\n }\n\n // Edge case: approved stage is the last stage — return itself\n return approvedStage\n}\n\n/**\n * Find the nearest earlier stage in the pipeline order.\n * Uses ALL_STAGES as a reference to determine ordering.\n * Falls back to first stage in pipeline if nothing earlier exists.\n *\n * @param missingStage - The stage that is not in the pipeline (e.g., 'gap' in lightweight)\n * @param pipelineOrder - The pipeline's stage order (may not include all ALL_STAGES)\n * @returns The nearest earlier stage that exists in pipelineOrder, or pipelineOrder[0] as fallback\n */\nexport function findNearestEarlierStage(missingStage: string, pipelineOrder: string[]): string {\n const missingIdx = ALL_STAGES.indexOf(missingStage as (typeof ALL_STAGES)[number])\n if (missingIdx === -1) return pipelineOrder[0] // unknown stage -> first stage\n\n // Walk backwards through ALL_STAGES to find the nearest one that exists in pipeline\n for (let i = missingIdx - 1; i >= 0; i--) {\n const stage = ALL_STAGES[i]\n if (pipelineOrder.includes(stage)) {\n return stage\n }\n }\n\n // Nothing earlier exists, use first pipeline stage\n return pipelineOrder[0]\n}\n","/**\n * @fileType handler\n * @domain kody | modes\n * @ai-summary Pipeline mode handler — extracted from entry.ts for modularity\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext } from '../engine/types'\nimport type { StageName } from '../stages/registry'\nimport { runPipeline } from '../engine/state-machine'\nimport { resolvePipelineForMode } from '../engine/pipeline-resolver'\nimport { logger } from '../logger'\nimport { readTask } from '../pipeline-utils'\n\nimport { flattenPipelineOrder } from '../pipeline/definitions'\nimport {\n resolveRerunFromStage,\n resolveFromStageAfterGateApproval,\n findNearestEarlierStage,\n} from '../rerun-utils'\nimport { getLastFailedStage, getLastPausedStage } from '../kody-utils'\nimport { checkoutTaskBranch } from '../git-utils'\nimport { runFullMode } from './full'\n\nexport async function runRerunMode(ctx: PipelineContext): Promise<void> {\n const { input, taskDir } = ctx\n logger.info('Running Kody RERUN pipeline...\\n')\n\n // G33: Check for paused stage FIRST - if we're resuming from a gate approval,\n // we should continue even if spec.md doesn't exist (it may not have been created yet\n // because the gate paused before resolve-profile post-action ran)\n const pausedStage = !input.fromStage ? getLastPausedStage(input.taskId) : null\n let gateApprovedStage: string | null = null\n\n // Early branch checkout: In CI, rerun mode starts on dev but task files\n // (spec.md, task.md, task.json) live on the feature branch. Checkout the\n // task's feature branch BEFORE checking for files, otherwise we'll falsely\n // fall back to full mode and fail with \"task.md not found\".\n if (process.env.GITHUB_ACTIONS && !input.dryRun) {\n const checkedOut = checkoutTaskBranch(input.taskId, taskDir)\n if (!checkedOut) {\n logger.info('No feature branch found for task — falling back to full pipeline')\n input.mode = 'full'\n await runFullMode(ctx)\n return\n }\n }\n\n // G33: Fallback to full only if spec.md missing AND no paused stage to resume\n const specPath = path.join(taskDir, 'spec.md')\n if (!fs.existsSync(specPath) && !pausedStage) {\n logger.info('No spec.md found — falling back to full pipeline')\n input.mode = 'full'\n await runFullMode(ctx)\n return\n }\n\n // FIX #5: Check for paused stage first (gate approval scenario)\n // This handles the case where @kody approve was used to resume a paused pipeline\n if (pausedStage) {\n logger.info(`Detected paused stage: ${pausedStage}`)\n\n // Helper to approve a gate — writes approval file, commits, and updates state\n const approveGate = async (\n ctx: PipelineContext,\n stage: string,\n reason: string,\n ): Promise<void> => {\n logger.info(`Gate ${stage} ${reason} — resuming pipeline`)\n\n // Write gate-{stage}-approved.md with the approval reason\n const approvedPath = path.join(ctx.taskDir, `gate-${stage}-approved.md`)\n fs.writeFileSync(\n approvedPath,\n `# Gate Approved\\n\\nApproved at ${stage} gate.\\nApproved by: ${reason}\\nApproved at: ${new Date().toISOString()}\\n`,\n )\n\n // Commit and push the approval files so subsequent runs can find them\n const { commitPipelineFiles } = await import('../git-utils')\n await commitPipelineFiles({\n taskDir: ctx.taskDir,\n taskId: ctx.input.taskId,\n message: `ci(kody): gate ${stage} ${reason} for ${ctx.input.taskId}`,\n ensureBranch: true,\n stagingStrategy: 'task-only',\n push: true,\n isCI: !ctx.input.local,\n dryRun: ctx.input.dryRun,\n })\n\n // Mark the paused stage as completed in status (immutable update)\n const { loadState, writeState, resumeFromGate } = await import('../engine/status')\n const state = loadState(ctx.input.taskId)\n if (state) {\n const resumedState = resumeFromGate(state, stage)\n writeState(ctx.input.taskId, resumedState)\n }\n }\n\n // Try to approve the gate directly\n try {\n const taskDef = readTask(taskDir)\n if (taskDef) {\n const { handleGateApproval } = await import('../clarify-workflow')\n const gateResult = handleGateApproval(input, taskDir, pausedStage, taskDef)\n\n if (gateResult === 'approved') {\n // Explicit approval via @kody approve — use the helper\n await approveGate(ctx, pausedStage, 'approved by user')\n gateApprovedStage = pausedStage\n\n // After approving a spec-phase gate, continue with the rerun pipeline\n // The rerun pipeline already includes both spec and impl stages\n // No mode switch needed - just continue running\n } else if (gateResult === 'waiting') {\n // Implicit approval: @kody rerun is a clear signal the user wants to proceed\n // No need to separately approve a gate they've already seen\n await approveGate(ctx, pausedStage, 'implicitly approved via @kody rerun')\n gateApprovedStage = pausedStage\n }\n }\n } catch (err) {\n logger.warn({ err }, 'Could not handle gate approval')\n }\n }\n\n // G37: Read task definition for profile resolution (MUST be before fromStage resolution)\n let taskDef = null\n try {\n taskDef = readTask(taskDir)\n } catch {\n logger.warn('Could not read task.json for profile resolution, using default')\n }\n ctx.taskDef = taskDef\n if (taskDef) {\n const { resolvePipelineProfile } = await import('../pipeline-utils')\n ctx.profile = resolvePipelineProfile(taskDef)\n }\n\n // --turbo flag: hard override to turbo profile\n if (ctx.input.turbo) {\n ctx.profile = 'turbo'\n logger.info('⚡ Turbo mode: forcing turbo profile')\n }\n\n // Track if fromStage was explicitly provided (via CLI) vs derived from failed/paused stage\n // If explicitly provided, don't inject default feedback (prevents backup to architect on auto-retries)\n const fromStageExplicitlyProvided = !!input.fromStage\n\n // Determine fromStage\n // FIX #673: After gate approval, use the NEXT stage (not the approved one)\n // to prevent resetFromStage from overwriting the gate approval\n if (!input.fromStage) {\n if (gateApprovedStage) {\n // Gate was just approved — resolve pipeline order to find the next stage\n const tempPipeline = resolvePipelineForMode('rerun', ctx.profile, false, ctx)\n const tempOrder = flattenPipelineOrder(tempPipeline.order)\n input.fromStage = resolveFromStageAfterGateApproval(gateApprovedStage, tempOrder)\n // R3-FIX #2: Trigger pipeline rebuild after gate approval.\n // The profile or task definition may have changed between the original run\n // and this rerun — rebuilding ensures the correct stages are used.\n ctx.pipelineNeedsRebuild = true\n logger.info(` ℹ️ Gate approved at ${gateApprovedStage} — resuming from ${input.fromStage}`)\n } else {\n // FIX #827: When pipeline state is 'failed', prefer failed stage over paused stage.\n // A stale 'paused' state (e.g., taskify gate was approved but state wasn't updated)\n // should not override the actual failed stage (e.g., build).\n const { loadState: loadSt3 } = await import('../engine/status')\n const prevState = loadSt3(input.taskId)\n const failedStage = getLastFailedStage(input.taskId)\n\n if (prevState?.state === 'failed' && failedStage) {\n // Pipeline failed — resume from the failed stage, not from a stale paused stage\n logger.info(\n ` ℹ️ Pipeline state is 'failed' — using failed stage '${failedStage}' over paused stage '${pausedStage}'`,\n )\n input.fromStage = failedStage\n } else {\n // Pipeline is paused or unknown — use paused stage (gate approval scenario)\n input.fromStage = pausedStage || failedStage || 'build'\n }\n }\n }\n\n // Default feedback - but only if fromStage wasn't explicitly provided\n // This prevents unnecessary backup to architect on auto-retries (pipeline-fixer)\n if (!input.feedback && !fromStageExplicitlyProvided) {\n input.feedback = 'Rerun requested via /kody rerun'\n }\n\n // G37: Write feedback file\n const feedbackFile = path.join(taskDir, 'rerun-feedback.md')\n try {\n fs.writeFileSync(\n feedbackFile,\n `# Rerun Feedback - ${new Date().toISOString()}\\n\\n## Issues Found\\n\\n${input.feedback}\\n`,\n )\n } catch (writeErr) {\n logger.error({ err: writeErr }, `Failed to write rerun feedback file: ${feedbackFile}`)\n throw writeErr\n }\n\n logger.info(`Feedback: ${input.feedback}`)\n logger.info(`From stage: ${input.fromStage}\\n`)\n\n // H2 fix: resolve pipeline BEFORE resolveRerunFromStage so we use profile-aware\n // impl stage order. Previously hardcoded IMPL_ORDER_STANDARD which caused turbo\n // rerun with feedback to back up to 'architect' (doesn't exist in turbo).\n const pipeline = resolvePipelineForMode('rerun', ctx.profile, false, ctx)\n const stageOrder = flattenPipelineOrder(pipeline.order)\n\n // P3 fix: Back up to architect when feedback provided so plan can be revised\n // BUT: Don't back up if fromStage was explicitly provided (via CLI --from or pipeline-fixer)\n // This prevents pipeline-fixer retries from unnecessarily re-running architect\n let resolvedFrom = input.fromStage || 'build'\n if (!fromStageExplicitlyProvided && input.feedback) {\n resolvedFrom = resolveRerunFromStage(resolvedFrom, input.feedback, stageOrder)\n if (resolvedFrom !== input.fromStage) {\n logger.info(\n ` ℹ️ Feedback provided — backing up from ${input.fromStage} to ${resolvedFrom} for plan revision`,\n )\n }\n }\n\n // Fix 5: Validate fromStage exists in the resolved pipeline order\n let fromStage = resolvedFrom\n if (!stageOrder.includes(fromStage as StageName)) {\n const fallback = findNearestEarlierStage(fromStage, stageOrder)\n logger.warn(\n `Stage \"${fromStage}\" not in pipeline (valid: ${stageOrder.join(', ')}). Falling back to \"${fallback}\".`,\n )\n fromStage = fallback\n }\n\n const { loadState, resetFromStage, writeState } = await import('../engine/status')\n const state = loadState(input.taskId)\n if (state) {\n // H4 FIX: resetFromStage now handles both state reset AND output file deletion\n // No need to manually delete files here - that was causing double-delete\n const newState = resetFromStage(state, fromStage, stageOrder, taskDir)\n writeState(input.taskId, newState)\n\n // FIX: Update lifecycle label from failed → building so dashboard shows correct status during rerun\n if (input.issueNumber && !input.local) {\n const { setLifecycleLabel } = await import('../github-api')\n setLifecycleLabel(input.issueNumber, 'kody:building')\n }\n }\n\n // Run impl pipeline\n await runPipeline(ctx, pipeline)\n\n logger.info('\\n✅ Rerun complete!')\n}\n","/**\n * @fileType handler\n * @domain kody | modes\n * @ai-summary Pipeline mode handler — extracted from entry.ts for modularity\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nimport type { PipelineContext } from '../engine/types'\nimport { PipelinePausedError } from '../engine/types'\nimport { runPipeline } from '../engine/state-machine'\nimport { resolvePipelineForMode } from '../engine/pipeline-resolver'\nimport { logger } from '../logger'\nimport { readTask } from '../pipeline-utils'\nimport { mergeDefaultBranch } from '../git-utils'\n\nimport { getIssueBody, getLinkedIssueFromPR, discoverTaskIdFromIssue } from '../github-api'\nimport { getTaskDir, ensureTaskDir } from '../kody-utils'\nimport { flattenPipelineOrder } from '../pipeline/definitions'\nimport { resetFromStage } from '../engine/status'\n\nexport async function runFixMode(ctx: PipelineContext): Promise<void> {\n const { input } = ctx\n logger.info('Running Kody FIX pipeline (full pipeline with original task context)...\\n')\n\n // ===========================================================================\n // Step 0: Merge default branch to get latest fixes\n // ===========================================================================\n if (input.isPullRequest) {\n try {\n mergeDefaultBranch(process.cwd())\n } catch (error) {\n logger.error({ error }, 'Failed to merge default branch, continuing anyway')\n }\n }\n\n // ===========================================================================\n // Step 1: Resolve original task ID from PR → issue → original task\n // ===========================================================================\n let originalTaskId = input.taskId\n let linkedIssueNumber: number | null = null\n\n if (input.isPullRequest && input.issueNumber) {\n const prNumber = input.issueNumber\n\n // Get linked issue from PR\n linkedIssueNumber = getLinkedIssueFromPR(prNumber)\n if (linkedIssueNumber) {\n logger.info(`Found linked issue #${linkedIssueNumber} from PR #${prNumber}`)\n\n // Discover original task from the issue\n const discoveredTaskId = discoverTaskIdFromIssue(linkedIssueNumber)\n if (discoveredTaskId && discoveredTaskId !== input.taskId) {\n logger.info(`Switching from fix task ${input.taskId} to original task ${discoveredTaskId}`)\n originalTaskId = discoveredTaskId\n\n // Update input and context\n input.taskId = originalTaskId\n }\n } else {\n logger.warn(`No linked issue found for PR #${prNumber}, using current task`)\n }\n }\n\n // Get the original task's directory\n const originalTaskDir = getTaskDir(originalTaskId)\n ctx.taskDir = originalTaskDir\n\n // ===========================================================================\n // Step 2: Archive previous artifacts to prev-run/\n // ===========================================================================\n const prevRunDir = path.join(originalTaskDir, 'prev-run')\n if (!fs.existsSync(prevRunDir)) {\n fs.mkdirSync(prevRunDir, { recursive: true })\n }\n\n // Copy existing markdown files to prev-run/\n const mdFiles = [\n 'spec.md',\n 'plan.md',\n 'gap.md',\n 'build.md',\n 'review.md',\n 'context.md',\n 'test.md',\n 'rerun-feedback.md',\n ]\n for (const mdFile of mdFiles) {\n const srcPath = path.join(originalTaskDir, mdFile)\n const destPath = path.join(prevRunDir, mdFile)\n if (fs.existsSync(srcPath)) {\n fs.copyFileSync(srcPath, destPath)\n logger.info(`Archived ${mdFile} to prev-run/`)\n }\n }\n\n // Copy task.json and status.json if they exist\n const jsonFiles = ['task.json', 'status.json']\n for (const jsonFile of jsonFiles) {\n const srcPath = path.join(originalTaskDir, jsonFile)\n const destPath = path.join(prevRunDir, jsonFile)\n if (fs.existsSync(srcPath)) {\n fs.copyFileSync(srcPath, destPath)\n logger.info(`Archived ${jsonFile} to prev-run/`)\n }\n }\n\n // ===========================================================================\n // Step 3: Compose task.md from issue body + fix comment\n // ===========================================================================\n const issueBody = linkedIssueNumber ? getIssueBody(linkedIssueNumber) : null\n\n // Get the fix comment from input.feedback\n const fixComment = input.feedback || 'Fix requested via @kody fix command'\n\n // Compose task.md content\n let taskMdContent = `# Fix Request\\n\\n`\n if (issueBody) {\n taskMdContent += `## Original Request (Issue #${linkedIssueNumber})\\n\\n${issueBody}\\n\\n`\n }\n taskMdContent += `## Fix Feedback\\n\\n${fixComment}\\n\\n`\n taskMdContent += `---\\n\\n`\n taskMdContent += `*This is a FIX for an existing implementation. Previous artifacts are archived in prev-run/ for context.*\\n`\n\n // Write task.md\n const taskMdPath = path.join(originalTaskDir, 'task.md')\n fs.writeFileSync(taskMdPath, taskMdContent)\n logger.info(`Composed fresh task.md from issue body and fix comment`)\n\n // Also write rerun-feedback.md for architect/build to read\n const feedbackPath = path.join(originalTaskDir, 'rerun-feedback.md')\n fs.writeFileSync(feedbackPath, `# Fix Feedback - ${new Date().toISOString()}\\n\\n${fixComment}\\n`)\n\n // ===========================================================================\n // Step 4: Ensure task directory exists and reset state from taskify\n // ===========================================================================\n ensureTaskDir(originalTaskId)\n\n // Read task definition for profile resolution\n let taskDef = null\n try {\n taskDef = readTask(originalTaskDir)\n } catch {\n logger.warn('Could not read task.json for profile resolution, using default')\n }\n ctx.taskDef = taskDef\n if (taskDef) {\n const { resolvePipelineProfile } = await import('../pipeline-utils')\n ctx.profile = resolvePipelineProfile(taskDef)\n }\n\n // --turbo flag: hard override to turbo profile\n if (ctx.input.turbo) {\n ctx.profile = 'turbo'\n logger.info('⚡ Turbo mode: forcing turbo profile')\n }\n\n // Resolve pipeline - now uses FIX_FULL_ORDER (full impl pipeline with taskify)\n const pipeline = resolvePipelineForMode('fix', ctx.profile, false, ctx)\n const stageOrder = flattenPipelineOrder(pipeline.order)\n\n // Load existing state or create fresh state\n const {\n loadState: loadSt2,\n writeState: writeSt2,\n updateStage: updStage,\n initState: initSt,\n } = await import('../engine/status')\n\n let state = loadSt2(originalTaskId)\n\n // Create fresh state starting from taskify (reset all stages)\n if (!state) {\n state = initSt(ctx, 'fix')\n }\n\n // Reset all stages from taskify onward for a fresh run\n state = resetFromStage(state, 'taskify', stageOrder, originalTaskDir)\n\n // Mark taskify as pending to start fresh\n state = updStage(state, 'taskify', { state: 'pending', retries: 0 })\n\n // Set initial cursor to taskify\n state = {\n ...state,\n cursor: 'taskify',\n state: 'running',\n }\n writeSt2(originalTaskId, state)\n\n // ===========================================================================\n // Step 5: Run the full pipeline\n // ===========================================================================\n const finalState = await runPipeline(ctx, pipeline)\n\n // Handle paused state (gate approval required)\n if (finalState.state === 'paused') {\n throw new PipelinePausedError(`Pipeline paused — awaiting gate approval for ${ctx.taskId}`)\n }\n\n logger.info('\\n✅ Fix complete!')\n}\n","/**\n * @fileType handler\n * @domain kody | modes\n * @ai-summary Status mode handler — shows pipeline status for a task\n */\n\nimport type { PipelineContext } from '../engine/types'\nimport { stateToV1 } from '../engine/status'\nimport { formatStatusComment } from '../status-format'\nimport { postComment } from '../github-api'\nimport { logger } from '../logger'\n\nexport async function runStatusMode(ctx: PipelineContext): Promise<void> {\n const { input } = ctx\n const { loadState } = await import('../engine/status')\n\n const state = loadState(input.taskId)\n\n if (!state) {\n logger.info(`No status found for task: ${input.taskId}`)\n logger.info(`The Kody may not have run yet, or status.json was deleted.`)\n return\n }\n\n logger.info(`Status for ${input.taskId}:`)\n logger.info(state)\n\n if (input.issueNumber) {\n const v1Status = stateToV1(state)\n postComment(input.issueNumber, formatStatusComment(input, v1Status))\n }\n}\n","/**\n * @fileType handler\n * @domain kody | modes\n * @ai-summary Design system audit mode — runs token audit, a11y checks, and creates PR with fixes\n */\n\nimport { execFileSync } from 'child_process'\nimport type { PipelineContext } from '../engine/types'\nimport { logger } from '../logger'\nimport { postComment } from '../github-api'\nimport { writeFileSync, mkdirSync, readFileSync } from 'fs'\nimport { join } from 'path'\n\ninterface AuditResult {\n total: number\n fixable: number\n nonFixable: number\n byCategory: Record<string, number>\n files: string[]\n}\n\ninterface A11yResult {\n violations: number\n critical: number\n serious: number\n}\n\nexport async function runDesignSystemMode(ctx: PipelineContext): Promise<void> {\n const { input, taskId, taskDir } = ctx\n const dryRun = input.dryRun ?? false\n\n logger.info('🎨 Running Design System Audit...\\n')\n\n const results: {\n audit: AuditResult | null\n a11y: A11yResult | null\n codemodApplied: boolean\n prCreated: boolean\n suggestions: string[]\n } = {\n audit: null,\n a11y: null,\n codemodApplied: false,\n prCreated: false,\n suggestions: [],\n }\n\n // Stage 1: Run Token Audit\n logger.info('📊 Stage 1: Running token audit...')\n try {\n const auditOutput = execFileSync('pnpm', ['design:tokens:audit', 'src/ui/web'], {\n encoding: 'utf-8',\n timeout: 60000,\n })\n logger.info(auditOutput)\n\n // Parse audit output\n const auditMatch = auditOutput.match(/Total issues:\\s*(\\d+)/)\n const fixableMatch = auditOutput.match(/Fixable:\\s*(\\d+)/)\n const nonFixableMatch = auditOutput.match(/Non-fixable:\\s*(\\d+)/)\n\n results.audit = {\n total: auditMatch ? parseInt(auditMatch[1]) : 0,\n fixable: fixableMatch ? parseInt(fixableMatch[1]) : 0,\n nonFixable: nonFixableMatch ? parseInt(nonFixableMatch[1]) : 0,\n byCategory: {},\n files: [],\n }\n\n logger.info(`✅ Audit complete: ${results.audit.total} issues found`)\n } catch (error) {\n logger.warn({ err: error }, '⚠️ Token audit failed or found no issues')\n results.audit = { total: 0, fixable: 0, nonFixable: 0, byCategory: {}, files: [] }\n }\n\n // Stage 2: Run Accessibility Check (if test exists)\n logger.info('\\n♿ Stage 2: Running accessibility check...')\n try {\n execFileSync('pnpm', ['test:a11y', '--ci'], {\n encoding: 'utf-8',\n timeout: 120000,\n stdio: 'pipe',\n })\n results.a11y = { violations: 0, critical: 0, serious: 0 }\n logger.info('✅ Accessibility check passed')\n } catch {\n // A11y test might not exist, that's ok\n logger.warn(\n '⚠️ Accessibility test not found or failed (this is ok if test:a11y is not configured)',\n )\n results.a11y = null\n }\n\n // Stage 3: Apply Safe Codemod Fixes\n logger.info('\\n🔧 Stage 3: Applying safe codemod fixes...')\n if (results.audit && results.audit.fixable > 0) {\n if (dryRun) {\n logger.info(`🔍 DRY RUN: Would apply ${results.audit.fixable} codemod fixes`)\n } else {\n try {\n execFileSync('pnpm', ['design:tokens:codemod', 'src/ui/web'], {\n encoding: 'utf-8',\n timeout: 120000,\n })\n results.codemodApplied = true\n logger.info(`✅ Applied ${results.audit.fixable} codemod fixes`)\n } catch (error) {\n logger.error({ err: error }, '⚠️ Codemod failed')\n }\n }\n } else {\n logger.info('✅ No fixable issues found')\n }\n\n // Stage 4: Generate Suggestions\n logger.info('\\n💡 Stage 4: Generating suggestions...')\n if (results.audit && results.audit.nonFixable > 0) {\n results.suggestions.push(\n `Found ${results.audit.nonFixable} non-fixable patterns that may need new design tokens.`,\n )\n }\n\n // Check for components that might need refactoring\n try {\n const chatInterfacePath = join(taskDir, '../../../src/ui/web/chat/ChatInterface/index.tsx')\n const chatContent = readFileSync(chatInterfacePath, 'utf-8')\n const lineCount = chatContent.split('\\n').length\n if (lineCount > 500) {\n results.suggestions.push(\n `ChatInterface is ${lineCount} lines — consider splitting into smaller components.`,\n )\n }\n } catch {\n // File might not exist or be in different location\n }\n\n // Stage 5: Create PR or Post Results\n logger.info('\\n📝 Stage 5: Creating report...')\n\n const report = generateReport(results)\n const reportPath = join(taskDir, 'design-system-report.md')\n writeFileSync(reportPath, report, 'utf-8')\n logger.info(`Report saved to: ${reportPath}`)\n\n // Post comment to issue if available\n if (input.issueNumber) {\n const commentBody = formatComment(results, report)\n postComment(input.issueNumber, commentBody)\n logger.info(`Posted results to issue #${input.issueNumber}`)\n }\n\n // Stage 6: Create PR (if changes were made and not dry run)\n if (results.codemodApplied && !dryRun) {\n try {\n createPr(results)\n results.prCreated = true\n logger.info('✅ Created PR with design system improvements')\n } catch (error) {\n logger.error({ err: error }, '⚠️ Failed to create PR')\n }\n } else if (dryRun && results.audit && results.audit.fixable > 0) {\n logger.info('🔍 DRY RUN: PR not created (use without --dry-run to create PR)')\n }\n\n logger.info('\\n✅ Design System Audit complete!')\n logger.info(\n ` Audit: ${results.audit?.total ?? 0} issues (${results.audit?.fixable ?? 0} fixable)`,\n )\n logger.info(` A11y: ${results.a11y?.violations ?? 'N/A'} violations`)\n logger.info(` Codemod applied: ${results.codemodApplied}`)\n logger.info(` PR created: ${results.prCreated}`)\n logger.info(` Suggestions: ${results.suggestions.length}`)\n}\n\nfunction generateReport(results: {\n audit: AuditResult | null\n a11y: A11yResult | null\n codemodApplied: boolean\n suggestions: string[]\n}): string {\n return `# Design System Audit Report\n\n## Summary\n\n| Metric | Value |\n|--------|-------|\n| Total Issues | ${results.audit?.total ?? 0} |\n| Fixable (auto-applied) | ${results.audit?.fixable ?? 0} |\n| Non-fixable (needs review) | ${results.audit?.nonFixable ?? 0} |\n| A11y Violations | ${results.a11y?.violations ?? 'N/A'} |\n| Codemod Applied | ${results.codemodApplied ? 'Yes' : 'No'} |\n\n## Suggestions\n\n${\n results.suggestions.length > 0\n ? results.suggestions.map((s) => `- ${s}`).join('\\n')\n : '- No suggestions at this time.'\n}\n\n## Details\n\n${\n results.audit && results.audit.total > 0\n ? `\n### Token Issues by Category\n\n${Object.entries(results.audit.byCategory)\n .map(([cat, count]) => `- ${cat}: ${count}`)\n .join('\\n')}\n`\n : ''\n}\n\n${\n results.a11y && results.a11y.violations > 0\n ? `\n### Accessibility Issues\n\n- Critical: ${results.a11y.critical}\n- Serious: ${results.a11y.serious}\n- Total: ${results.a11y.violations}\n`\n : ''\n}\n\n---\n*Generated by Kody Design System Audit*\n`\n}\n\nfunction formatComment(\n results: {\n audit: AuditResult | null\n a11y: A11yResult | null\n codemodApplied: boolean\n suggestions: string[]\n },\n _report: string,\n): string {\n const lines = ['## 🎨 Design System Audit Results']\n\n if (results.audit) {\n lines.push(`\\n| Metric | Value |`)\n lines.push(`|--------|-------|`)\n lines.push(`| Total Issues | ${results.audit.total} |`)\n lines.push(`| Fixable | ${results.audit.fixable} |`)\n lines.push(`| Non-fixable | ${results.audit.nonFixable} |`)\n }\n\n if (results.a11y) {\n lines.push(`| A11y Violations | ${results.a11y.violations} |`)\n }\n\n lines.push(`| Codemod Applied | ${results.codemodApplied ? '✅' : '❌'} |`)\n\n if (results.suggestions.length > 0) {\n lines.push('\\n### 💡 Suggestions')\n results.suggestions.forEach((s) => {\n lines.push(`- ${s}`)\n })\n }\n\n lines.push('\\n---\\n*Triggered by @kody design-system*')\n\n return lines.join('\\n')\n}\n\nfunction createPr(results: { audit: AuditResult | null; codemodApplied: boolean }): void {\n const branchName = `design-system/audit-${new Date().toISOString().slice(0, 10)}`\n\n // Create branch\n execFileSync('git', ['checkout', '-b', branchName], { stdio: 'pipe' })\n\n // Stage changes\n execFileSync('git', ['add', 'src/ui/web/'], { stdio: 'pipe' })\n\n // Check if there are changes to commit\n try {\n execFileSync('git', ['diff', '--cached', '--quiet'], { stdio: 'pipe' })\n } catch {\n // There are changes to commit\n const message = results.audit\n ? `chore(design-system): apply ${results.audit.fixable} token fixes\n\nAutomated design system improvements:\n- Fixed ${results.audit.fixable} raw Tailwind values → design tokens\n- Applied via codemod\n\nGenerated by @kody design-system`\n : `chore(design-system): design system improvements\n\nAutomated design system improvements. Generated by @kody design-system`\n\n execFileSync('git', ['commit', '-m', message], { stdio: 'pipe' })\n\n // Push branch\n execFileSync('git', ['push', '-u', 'origin', branchName], { stdio: 'pipe' })\n\n // Create PR using gh CLI\n execFileSync(\n 'gh',\n [\n 'pr',\n 'create',\n '--title',\n '🎨 Design System Improvements (Automated)',\n '--body',\n '## Summary\\n\\nAutomated design system improvements via @kody design-system\\n\\n| Metric | Value |\\n|--------|-------|\\n| Fixable Issues | ' +\n (results.audit?.fixable ?? 0) +\n ' |\\n\\n_This PR was created automatically by the Kody design system agent._',\n '--base',\n 'main',\n ],\n { stdio: 'inherit' },\n )\n }\n}\n","/**\n * @fileType barrel-export\n * @domain kody | modes\n * @ai-summary Barrel export for pipeline mode handlers\n */\n\nexport { runSpecMode } from './spec'\nexport { runImplMode } from './impl'\nexport { runFullMode } from './full'\nexport { runBrainFullMode } from './brain-full'\nexport { runRerunMode } from './rerun'\nexport { runFixMode } from './fix'\nexport { runStatusMode } from './status'\nexport { runDesignSystemMode } from './design-system'\n","/**\n * @fileType script\n * @domain kody\n * @pattern entry-point\n * @ai-summary New CLI entry point for Kody pipeline state machine\n */\n\n// Load .env before anything else so GH_PAT, API keys, etc. are available.\n// In CI, environment variables are injected by the workflow — this is a no-op\n// if .env doesn't exist (dotenv silently skips missing files).\nimport { config as loadEnv } from 'dotenv'\nloadEnv({ path: '.env' })\n\nimport ms from 'ms'\n\nimport { parseCliArgs, validateAuth, ensureTaskDir } from './kody-utils'\nimport { preflight } from './preflight'\nimport { createRunner } from './runner-backend'\nimport { logger } from './logger'\nimport { commitPipelineFiles } from './git-utils'\n\nimport type { PipelineContext } from './engine/types'\nimport { resolvePipelineForMode } from './engine/pipeline-resolver'\nimport { flattenPipelineOrder } from './pipeline/definitions'\nimport { PipelinePausedError } from './engine/types'\nimport { startServer, stopServer, checkpointDb, findLastSessionId } from './opencode-server'\nimport {\n runSpecMode,\n runImplMode,\n runBrainFullMode,\n runRerunMode,\n runFixMode,\n runStatusMode,\n runDesignSystemMode,\n} from './modes'\n\n// FIX #3: Import status functions at module level instead of dynamic imports in signal handlers.\n// Dynamic `await import()` in signal handlers is unsafe — Node.js signal handlers have limited\n// async support and may be killed before the import resolves.\nimport {\n loadState as loadStateForSignal,\n writeState as writeStateForSignal,\n updateStage as updateStageForSignal,\n completeState as completeStateForSignal,\n} from './engine/status'\n\n// Re-export for backward compatibility (canonical source: ./task-setup)\nexport { ensureTaskMd } from './task-setup'\nimport type { OpenCodeServer } from './opencode-server'\nimport { ensureTaskMarkerComment, postComment } from './github-api'\n\n// ============================================================================\n// Failure Comment Formatting\n// ============================================================================\n\n/**\n * Build an enriched failure comment for GitHub issues.\n * Includes failed stage, error, cost, and stage progression.\n */\nfunction formatFailureComment(\n input: { taskId: string; runUrl?: string },\n state: import('./engine/types').PipelineStateV2 | null,\n error: unknown,\n): string {\n const errorMsg = error instanceof Error ? error.message : String(error)\n const lines: string[] = [`❌ Pipeline failed for \\`${input.taskId}\\``]\n\n if (state?.stages) {\n // Find the failed stage\n const failedEntry = Object.entries(state.stages).find(\n ([, s]) => s.state === 'failed' || s.state === 'timeout',\n )\n if (failedEntry) {\n const [stageName, stageState] = failedEntry\n const elapsedStr =\n stageState.elapsed != null\n ? ` (after ${Math.floor(stageState.elapsed / 60)}m ${stageState.elapsed % 60}s)`\n : ''\n lines.push(`\\n**Failed stage:** \\`${stageName}\\`${elapsedStr}`)\n }\n\n lines.push(`**Error:** ${errorMsg}`)\n\n // Total cost across all stages\n const totalCost = Object.values(state.stages).reduce((sum, s) => sum + (s.cost ?? 0), 0)\n if (totalCost > 0) {\n const completedCount = Object.values(state.stages).filter(\n (s) => s.state === 'completed',\n ).length\n lines.push(`**Cost:** $${totalCost.toFixed(2)} across ${completedCount} stages`)\n }\n\n // Stage progression\n const progression = Object.entries(state.stages)\n .map(([name, s]) => {\n if (s.state === 'completed') return `${name} ✅`\n if (s.state === 'failed' || s.state === 'timeout') return `${name} ❌`\n if (s.state === 'skipped') return `${name} ⏭`\n return null\n })\n .filter(Boolean)\n if (progression.length > 0) {\n lines.push(`**Completed:** ${progression.join(' → ')}`)\n }\n } else {\n lines.push(`\\n**Error:** ${errorMsg}`)\n }\n\n if (input.runUrl) {\n lines.push(`\\nRun: ${input.runUrl}`)\n }\n\n return lines.join('\\n')\n}\n\n// ============================================================================\n// OpenCode Server Lifecycle\n// ============================================================================\n\n/** Module-level reference to the OpenCode server for cleanup in signal handlers */\nlet openCodeServer: OpenCodeServer | null = null\n\n/**\n * Gracefully shut down the OpenCode server, checkpoint the DB, and clear the reference.\n * Safe to call multiple times (idempotent).\n */\nasync function shutdownOpenCodeServer(taskDir?: string): Promise<void> {\n if (!openCodeServer) return\n const server = openCodeServer\n openCodeServer = null\n\n await stopServer(server)\n\n // Checkpoint WAL into main DB so it's self-contained for git commits\n if (taskDir) {\n checkpointDb(taskDir)\n }\n}\n\n// ============================================================================\n\n/**\n * Main entry point\n */\nexport async function main(cliArgs?: string[]): Promise<void> {\n const args = cliArgs ?? process.argv.slice(2)\n\n // Handle --help early\n if (args.includes('--help') || args.includes('-h')) {\n console.log(`\nKody Pipeline CLI\n\nUsage: pnpm tsx scripts/kody/entry.ts [options]\n\nOptions:\n --task-id <id> Task ID (format: YYMMDD-description)\n --mode <mode> Pipeline mode: full, spec, impl, rerun, clarify, status\n --file <path> Path to task file (auto-generates task-id from filename)\n --dry-run Dry run mode\n --issue-number <n> GitHub issue number\n --trigger-type Trigger type: dispatch, comment\n --run-id <id> CI run ID\n --run-url <url> CI run URL\n --comment-body <text> Comment body (for comment triggers)\n --from <stage> Stage to restart from (for rerun mode)\n --feedback <text> Feedback for rerun mode\n --auto Auto mode (non-interactive)\n --gate Risk-gated mode (require approval)\n --hard-stop Hard stop on failure\n --local Run in local mode (skip GitHub API)\n --clarify Run clarify stage\n --complexity <1-100> Override complexity score (for testing)\n --is-pull-request Comment was on a PR (not issue)\n --fresh Force create new PR (new branch)\n\nExamples:\n pnpm tsx scripts/kody/entry.ts --task-id 260225-my-task --mode full\n pnpm tsx scripts/kody/entry.ts --file docs/feature.md\n pnpm tsx scripts/kody/entry.ts --mode rerun --from verify --feedback \"Tests failed\"\n`)\n return\n }\n\n // Parse CLI args\n const input = parseCliArgs(args)\n\n // Create a child logger with task context\n\n // R9: Shutdown guard to prevent double-execution on SIGTERM/SIGINT\n let shuttingDown = false\n // G2: Signal handlers with null guard\n const cleanupOnSignal = async (signal: string) => {\n // Prevent double execution (immediate exit on re-entry during async cleanup)\n if (shuttingDown) {\n process.exit(128 + (signal === 'SIGTERM' ? 15 : 2))\n return // unreachable but satisfies TS\n }\n shuttingDown = true\n logger.error(`\\n⚠ Received ${signal} — CI runner shutting down`)\n try {\n // FIX #3: Use module-level imports instead of dynamic import in signal context\n const state = loadStateForSignal(input.taskId)\n if (state) {\n // Mark all running stages as failed\n let updatedState = state\n for (const [name, stage] of Object.entries(state.stages)) {\n if (stage.state === 'running') {\n updatedState = updateStageForSignal(updatedState, name, {\n state: 'failed',\n error: `Process interrupted by ${signal}`,\n })\n logger.error(` Marked stage \"${name}\" as failed`)\n }\n }\n // Mark pipeline as failed\n const failedState = completeStateForSignal(updatedState, 'failed')\n writeStateForSignal(input.taskId, failedState)\n logger.error(` Updated status.json to \"failed\" for task ${input.taskId}`)\n\n // In CI mode: attempt to commit and push the updated status\n if (process.env.GITHUB_ACTIONS === 'true' && !input.local) {\n logger.error(` Attempting to commit status.json in CI...`)\n try {\n const { execFileSync } = await import('child_process')\n const SIGNAL_TIMEOUT = ms('10s') // 10s max per git op during shutdown\n // Get the directory where status.json is\n const statusPath = `./.tasks/${input.taskId}/status.json`\n execFileSync('git', ['add', statusPath], {\n stdio: 'inherit',\n timeout: SIGNAL_TIMEOUT,\n })\n execFileSync(\n 'git',\n [\n 'commit',\n '--no-gpg-sign',\n '-m',\n `ci(kody): save interrupted state for ${input.taskId}`,\n ],\n { stdio: 'inherit', timeout: SIGNAL_TIMEOUT },\n )\n execFileSync('git', ['push'], {\n stdio: 'inherit',\n timeout: SIGNAL_TIMEOUT,\n })\n logger.error(` ✅ Committed and pushed status.json`)\n } catch (commitErr) {\n logger.error({ err: commitErr }, ` ⚠️ Failed to commit/push status.json`)\n }\n }\n }\n } catch (err) {\n logger.error({ err }, ` Failed to update status`)\n }\n // Kill OpenCode server before exiting (sync-safe: just send SIGTERM).\n // We cannot await stopServer() or checkpointDb() here — the signal context\n // limits async work. The WAL checkpoint is skipped on forced shutdown;\n // SQLite will recover the WAL automatically on the next open.\n if (openCodeServer?.process && !openCodeServer.process.killed) {\n openCodeServer.process.kill('SIGTERM')\n openCodeServer = null\n }\n\n process.exit(128 + (signal === 'SIGTERM' ? 15 : 2))\n }\n\n process.on('SIGTERM', () => cleanupOnSignal('SIGTERM'))\n process.on('SIGINT', () => cleanupOnSignal('SIGINT'))\n\n logger.info(`Task: ${input.taskId}`)\n logger.info(`Mode: ${input.mode}`)\n logger.info(`Dry run: ${input.dryRun}`)\n logger.info(`Local: ${input.local}`)\n if (input.issueNumber) logger.info(`Issue: #${input.issueNumber}`)\n logger.info('')\n\n // Run preflight checks in local mode\n if (input.local) {\n preflight()\n }\n\n // Validate GitHub App authentication (skip in local mode)\n if (!input.local) {\n validateAuth()\n }\n\n // Create runner backend\n const backend = createRunner(input.local)\n\n // Ensure task directory\n const taskDir = ensureTaskDir(input.taskId)\n\n // G3: Ensure task marker comment runs for ALL modes before the mode switch\n if (input.issueNumber) {\n ensureTaskMarkerComment(input.issueNumber, input.taskId, input.mode, input.runUrl)\n }\n\n // Pre-pipeline setup per mode\n const ctx: PipelineContext = {\n taskId: input.taskId,\n taskDir,\n input,\n taskDef: null,\n profile: 'standard',\n backend,\n actor: input.actor,\n }\n\n // Start OpenCode server for persistent sessions across stages\n // Graceful degradation: if startup fails, pipeline runs without server (cold-boot each stage)\n if (input.mode !== 'status') {\n const server = await startServer(taskDir)\n if (server) {\n openCodeServer = server\n ctx.serverUrl = server.url\n logger.info(` OpenCode server available at ${server.url}`)\n\n // On rerun: recover lastSessionId from previous pipeline state\n if (input.mode === 'rerun') {\n const { loadState } = await import('./engine/status')\n const existingState = loadState(input.taskId)\n if (existingState) {\n const pipelineOrder = flattenPipelineOrder(\n resolvePipelineForMode('full', ctx.profile, false, ctx).order,\n )\n const lastSid = findLastSessionId(existingState.stages, pipelineOrder)\n if (lastSid) {\n ctx.lastSessionId = lastSid\n logger.info(` Recovered session ${lastSid} from previous run`)\n }\n }\n }\n }\n }\n\n try {\n switch (input.mode) {\n case 'spec':\n await runSpecMode(ctx)\n break\n case 'impl':\n await runImplMode(ctx)\n break\n case 'full':\n // Brain-aware: uses remote brain for architect + review when BRAIN_SERVER_URL is set\n await runBrainFullMode(ctx)\n break\n case 'rerun':\n await runRerunMode(ctx)\n break\n case 'fix':\n await runFixMode(ctx)\n break\n case 'status':\n await runStatusMode(ctx)\n break\n case 'design-system':\n await runDesignSystemMode(ctx)\n break\n default:\n throw new Error(`Unknown mode: ${input.mode}`)\n }\n } catch (error) {\n if (error instanceof PipelinePausedError) {\n // Pipeline paused — still need to shut down server and checkpoint DB\n await shutdownOpenCodeServer(taskDir)\n return\n }\n\n // G6: process.exit(1) on failure\n // Only update status if state exists and isn't already marked as failed\n // (runPipeline already marks and writes state before throwing)\n const { writeState, loadState: loadSt, completeState } = await import('./engine/status')\n const existingState = loadSt(input.taskId)\n if (existingState && existingState.state !== 'failed') {\n const failedState = completeState(existingState, 'failed')\n writeState(input.taskId, failedState)\n }\n\n const errorMsg = error instanceof Error ? error.message : String(error)\n logger.error({ err: error }, `\\n❌ Kody failed: ${errorMsg}`)\n\n // Shutdown OpenCode server before committing (ensures DB is checkpointed)\n await shutdownOpenCodeServer(taskDir)\n\n // Commit task files on failure — includes debug artifacts (*-events.jsonl, *-stderr.log)\n // for post-mortem diagnosis. On success these are excluded to keep PRs clean.\n try {\n commitPipelineFiles({\n taskDir,\n taskId: input.taskId,\n message: `ci(kody): save failed pipeline state for ${input.taskId}`,\n ensureBranch: true,\n stagingStrategy: 'task-only',\n push: !input.local,\n isCI: !input.local,\n dryRun: input.dryRun,\n pipelineFailed: true,\n })\n } catch (commitErr) {\n logger.warn({ err: commitErr }, 'Failed to commit task files on pipeline failure')\n }\n\n // Skip GitHub API calls in local mode — each call wrapped in try/catch\n // so process.exit(1) is ALWAYS reached even if GitHub API is down\n if (input.issueNumber && !input.local) {\n try {\n const { setLifecycleLabel } = await import('./github-api')\n setLifecycleLabel(input.issueNumber, 'kody:failed')\n } catch (labelErr) {\n logger.warn({ err: labelErr }, 'Failed to set failure lifecycle label')\n }\n try {\n const failureComment = formatFailureComment(input, existingState, error)\n postComment(input.issueNumber, failureComment)\n } catch (commentErr) {\n logger.warn({ err: commentErr }, 'Failed to post failure comment')\n }\n }\n process.exit(1)\n }\n\n // Success path: shutdown OpenCode server and checkpoint DB\n await shutdownOpenCodeServer(taskDir)\n\n // Explicitly exit on success. Without this the process may hang if\n // the OpenCode server left orphan listeners, timers, or file handles\n // that keep the Node event loop alive.\n process.exit(0)\n}\n\n// Run main — skip auto-invocation when imported as a module (e.g., canary tests)\nconst isDirectExecution =\n process.argv[1]?.endsWith('entry.ts') || process.argv[1]?.endsWith('entry')\nif (isDirectExecution) {\n main().catch((err) => {\n const fatalErr = err instanceof Error ? err.message : String(err)\n logger.error({ err }, `Fatal error: ${fatalErr}`)\n process.exit(1)\n })\n}\n","/**\n * @fileType utility\n * @domain kody\n * @ai-summary Validate comment trigger safety filters\n */\n\nimport { writeFileSync } from 'fs'\n\ninterface SafetyResult {\n valid: string\n reason?: string\n}\n\n// Valid author associations\nconst VALID_ASSOCIATIONS = ['OWNER', 'MEMBER', 'COLLABORATOR']\n\n// Known bot accounts (exact match)\nconst KNOWN_BOTS = ['github-actions[bot]']\n\n/**\n * Check if author is a bot\n */\nexport function isBot(author: string): boolean {\n // Exact match for known bots\n if (KNOWN_BOTS.includes(author)) return true\n // Pattern: ends with [bot]\n if (author.endsWith('[bot]')) return true\n return false\n}\n\n/**\n * Check if author association is valid\n */\nexport function isValidAssociation(association: string): boolean {\n return VALID_ASSOCIATIONS.includes(association)\n}\n\n/**\n * Check if comment contains @kody or /kody command\n */\nexport function hasKodyCommand(comment: string): boolean {\n // @kody can be anywhere in the comment\n if (comment.includes('@kody')) return true\n\n // /kody must be on first line\n const firstLine = comment.split('\\n')[0]\n if (/^\\/kody(\\s|$)/.test(firstLine)) return true\n\n return false\n}\n\n/**\n * Validate comment safety\n */\nexport function validateSafety(author: string, association: string, comment: string): SafetyResult {\n // Check if author is a bot\n if (isBot(author)) {\n return { valid: 'false', reason: 'bot' }\n }\n\n // Check author association\n if (!isValidAssociation(association)) {\n return { valid: 'false', reason: 'unauthorized' }\n }\n\n // Check for @kody or /kody pattern\n if (!hasKodyCommand(comment)) {\n return { valid: 'false', reason: 'pattern' }\n }\n\n return { valid: 'true' }\n}\n\n/**\n * Write outputs to GITHUB_OUTPUT\n */\nfunction writeOutputs(result: SafetyResult): void {\n const githubOutput = process.env.GITHUB_OUTPUT || ''\n\n if (!githubOutput) {\n console.error('GITHUB_OUTPUT not set!')\n process.exit(1)\n }\n\n const lines = [`valid=${result.valid}`]\n if (result.reason) {\n lines.push(`reason=${result.reason}`)\n }\n\n writeFileSync(githubOutput, lines.join('\\n') + '\\n')\n}\n\n/**\n * Main entry point\n */\nfunction main(): void {\n const author = process.env.AUTHOR || ''\n const association = process.env.ASSOCIATION || ''\n const comment = process.env.COMMENT_BODY || ''\n\n const result = validateSafety(author, association, comment)\n writeOutputs(result)\n}\n\n// Run if called directly\nif (import.meta.url === `file://${process.argv[1]}`) {\n main()\n}\n","/**\n * @fileType utility\n * @domain kody\n * @ai-summary Parse command inputs from dispatch or comment triggers\n */\n\nimport { logger } from './logger'\nimport { execFileSync } from 'child_process'\nimport { writeFileSync } from 'fs'\n\n// Types for outputs\ninterface ParseOutputs {\n task_id: string\n mode: string\n clarify: string\n dry_run: string\n from_stage: string\n feedback: string\n issue_number: string\n is_pull_request: string\n trigger_type: string\n comment_body: string\n valid: string\n runner: string\n version: string\n fresh: string\n complexity: string\n}\n\n// Task ID format: YYMMDD-description (e.g., 260225-auto-90)\nexport const TASK_ID_REGEX = /^[0-9]{6}-[a-zA-Z0-9-]+$/\n\n// Valid pipeline modes\nexport const VALID_MODES = ['spec', 'impl', 'rerun', 'fix', 'full', 'status']\n\n// Approval keywords (exact match only)\nexport const APPROVAL_KEYWORDS = ['approve', 'approved', 'yes', 'go', 'proceed', 'y', 'continue']\n\n/**\n * Validate task ID format\n */\nexport function isValidTaskId(taskId: string): boolean {\n return TASK_ID_REGEX.test(taskId)\n}\n\n/**\n * Normalize comment body - lowercase and trim\n */\nexport function normalizeComment(comment: string): string {\n return comment.toLowerCase().trim()\n}\n\n/**\n * Extract command after @kody or /kody prefix\n * Handles both single-line and multiline comments\n */\nexport function extractCommandAfterKody(comment: string): string {\n const normalized = normalizeComment(comment)\n // Match @kody or /kody at the start, followed by optional whitespace\n // Use 's' flag so . matches newlines for multiline comments\n const match = normalized.match(/^[\\/@]kody\\s*(.*)$/s)\n if (!match) return ''\n return match[1].trim()\n}\n\n/**\n * Discover task ID from previous bot comments on the issue\n */\nexport function discoverTaskIdFromIssue(issueNumber: string): string | null {\n try {\n const result = execFileSync(\n 'gh',\n ['issue', 'view', issueNumber, '--json', 'comments', '--jq', '.comments[].body'],\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] },\n )\n\n // Find \"Task created: `YYYYMMDD-description`\" pattern\n const match = result.match(/Task created: `([0-9]{6}-[a-zA-Z0-9-]+)`/)\n if (match) {\n return match[1]\n }\n return null\n } catch {\n return null\n }\n}\n\n/**\n * Parse dispatch inputs (workflow_dispatch trigger)\n */\nexport function parseDispatchInputs(): ParseOutputs {\n const taskId = process.env.DISPATCH_TASK_ID || ''\n\n // Validate task_id is provided\n if (!taskId) {\n return {\n ...getDefaultOutputs(),\n issue_number: process.env.DISPATCH_ISSUE_NUMBER || '',\n is_pull_request: process.env.IS_PULL_REQUEST == 'true' ? 'true' : '',\n valid: 'false',\n }\n }\n\n // Validate task-id format\n if (!isValidTaskId(taskId)) {\n logger.info(`=== Error: Invalid task-id format: ${taskId} ===`)\n logger.info('Expected format: YYMMDD-description (e.g., 260225-auto-90)')\n return {\n ...getDefaultOutputs(),\n issue_number: process.env.DISPATCH_ISSUE_NUMBER || '',\n is_pull_request: process.env.IS_PULL_REQUEST == 'true' ? 'true' : '',\n valid: 'false',\n }\n }\n\n const outputs: ParseOutputs = {\n task_id: taskId,\n mode: process.env.DISPATCH_MODE || 'full',\n clarify: process.env.DISPATCH_CLARIFY || 'false',\n dry_run: process.env.DISPATCH_DRY_RUN || 'false',\n from_stage: process.env.DISPATCH_FROM_STAGE || '',\n feedback: process.env.DISPATCH_FEEDBACK || '',\n issue_number: process.env.DISPATCH_ISSUE_NUMBER || '',\n is_pull_request: process.env.IS_PULL_REQUEST == 'true' ? 'true' : '',\n trigger_type: 'dispatch',\n comment_body: '',\n valid: 'true',\n runner: process.env.DISPATCH_RUNNER || 'github-hosted',\n version: process.env.DISPATCH_VERSION || process.env.KODY_DEFAULT_VERSION || '',\n fresh: process.env.FRESH || '',\n complexity: process.env.DISPATCH_COMPLEXITY || '',\n }\n\n logger.info(\n `=== Parsed dispatch: task_id=${outputs.task_id}, mode=${outputs.mode}, clarify=${outputs.clarify}, runner=${outputs.runner} ===`,\n )\n\n return outputs\n}\n\n/**\n * Check if an issue has the \"publish\" label\n */\nfunction hasPublishLabel(issueNumber: string): boolean {\n if (!issueNumber) return false\n try {\n const result = execFileSync(\n 'gh',\n ['issue', 'view', issueNumber, '--json', 'labels', '--jq', '.labels[].name'],\n { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] },\n )\n const labels = result.trim().split('\\n').filter(Boolean)\n return labels.includes('publish')\n } catch {\n return false\n }\n}\n\n/**\n * Parse comment inputs (issue_comment trigger)\n */\nexport function parseCommentInputs(): ParseOutputs {\n const safetyValid = process.env.SAFETY_VALID\n const safetyReason = process.env.SAFETY_REASON || 'unknown'\n const issueNumber = process.env.ISSUE_NUMBER || ''\n const commentBody = process.env.COMMENT_BODY || ''\n\n // Safety check first\n if (safetyValid !== 'true') {\n logger.info(`=== Safety check failed: ${safetyReason} ===`)\n return {\n ...getDefaultOutputs(),\n issue_number: issueNumber,\n valid: 'false',\n }\n }\n\n // Check for publish label - these are handled by the Publish workflow, not Kody\n if (issueNumber && hasPublishLabel(issueNumber)) {\n logger.info(`=== Issue #${issueNumber} has 'publish' label - skipping Kody pipeline ===`)\n return {\n ...getDefaultOutputs(),\n issue_number: issueNumber,\n valid: 'false',\n feedback: 'Publish issues are handled by the Publish workflow. Do not process with Kody.',\n }\n }\n\n // Initialize outputs\n const outputs: ParseOutputs = {\n ...getDefaultOutputs(),\n issue_number: issueNumber,\n trigger_type: 'comment',\n comment_body: JSON.stringify(commentBody),\n }\n\n // Extract command after @kody or /kody (MUST be before flag detection)\n const cmdAfterKody = commentBody ? extractCommandAfterKody(commentBody) : ''\n\n // Detect --fresh flag - skip taskId discovery if fresh\n const hasFreshFlag = /--fresh\\b/.test(cmdAfterKody)\n if (hasFreshFlag) {\n outputs.fresh = 'true'\n logger.info('=== Detected --fresh flag: will create new task ===')\n }\n\n // Discover task-id from previous bot comments on the issue (skip if fresh)\n if (issueNumber && !hasFreshFlag) {\n const discoveredTaskId = discoverTaskIdFromIssue(issueNumber)\n if (discoveredTaskId) {\n logger.info(`=== Discovered task-id from issue: ${discoveredTaskId} ===`)\n outputs.task_id = discoveredTaskId\n }\n }\n\n // Parse command to determine mode and flags\n if (cmdAfterKody) {\n // Detect --local flag anywhere in the command\n const hasLocalFlag = /--local\\b/.test(cmdAfterKody)\n if (hasLocalFlag) {\n outputs.runner = 'self-hosted'\n logger.info('=== Detected --local flag: will use self-hosted runner ===')\n }\n\n // Detect --github-hosted flag anywhere in the command\n const hasGithubHostedFlag = /--github-hosted\\b/.test(cmdAfterKody)\n if (hasGithubHostedFlag) {\n outputs.runner = 'github-hosted'\n logger.info('=== Detected --github-hosted flag: will use GitHub-hosted runner ===')\n }\n\n // Detect --version flag anywhere in the command\n const versionMatch = cmdAfterKody.match(/--version\\s+(\\S+)/)\n if (versionMatch) {\n outputs.version = versionMatch[1]\n logger.info(`=== Detected --version flag: ${outputs.version} ===`)\n }\n\n // Detect --from flag (both --from=stage and --from stage syntax)\n const fromMatch = cmdAfterKody.match(/--from[=\\s](\\S+)/)\n if (fromMatch) {\n outputs.from_stage = fromMatch[1]\n logger.info(`=== Detected --from flag: ${outputs.from_stage} ===`)\n }\n\n // Detect --feedback flag (both --feedback=text and --feedback text syntax)\n const feedbackMatch = cmdAfterKody.match(/--feedback[=\\s](\\S+)/)\n if (feedbackMatch) {\n outputs.feedback = feedbackMatch[1]\n logger.info(`=== Detected --feedback flag: ${outputs.feedback} ===`)\n }\n\n // Strip flags from command before mode parsing\n const cmdWithoutFlags = cmdAfterKody\n .replace(/--local\\b/g, '')\n .replace(/--github\\b/g, '')\n .replace(/--github-hosted\\b/g, '')\n .replace(/--version\\s+\\S+/g, '')\n .replace(/--fresh\\b/g, '')\n .replace(/--from[=\\s]\\S+/g, '')\n .replace(/--feedback[=\\s]\\S+/g, '')\n .trim()\n\n if (!cmdWithoutFlags) {\n // @kody alone (or @kody --local) - default to full mode\n outputs.mode = 'full'\n logger.info('=== @kody alone - defaulting to full mode ===')\n } else {\n // Check if the first word is a known mode or approval keyword\n // This handles commands like \"/kody rerun 260218-task\" where extra args follow the mode\n const firstWord = cmdWithoutFlags.split(/[\\s\\n]/)[0]\n if (APPROVAL_KEYWORDS.includes(firstWord)) {\n // Approval command with optional answer - use rerun mode\n outputs.mode = 'rerun'\n logger.info(`=== Detected approval keyword: ${firstWord} ===`)\n } else if (VALID_MODES.includes(firstWord)) {\n // First word is a valid mode (e.g., \"rerun\", \"spec\", \"impl\")\n outputs.mode = firstWord\n logger.info(`=== Detected explicit mode: ${firstWord} ===`)\n } else {\n // Not a known command - default to full (might be task-id or description)\n outputs.mode = 'full'\n logger.info('=== Not a known command - defaulting to full mode ===')\n }\n }\n }\n\n // Validate task-id format if set\n if (outputs.task_id && !isValidTaskId(outputs.task_id)) {\n logger.info(`=== Error: Invalid task-id format: ${outputs.task_id} ===`)\n logger.info('Expected format: YYMMDD-description (e.g., 260225-auto-90)')\n outputs.task_id = ''\n outputs.valid = 'false'\n } else {\n outputs.valid = 'true'\n }\n\n logger.info('=== Passing comment to orchestrator for parsing ===')\n\n return outputs\n}\n\n/**\n * Parse PR review inputs (pull_request_review trigger)\n * Automatically routes to fix mode with the review feedback as context.\n */\nexport function parsePRReviewInputs(): ParseOutputs {\n const prNumber = process.env.PR_NUMBER || process.env.ISSUE_NUMBER || ''\n const reviewState = process.env.PR_REVIEW_STATE || ''\n const reviewBody = process.env.PR_REVIEW_BODY || ''\n\n logger.info(`=== PR Review trigger: PR #${prNumber}, state=${reviewState} ===`)\n\n // Only process \"changes_requested\" reviews\n if (reviewState !== 'changes_requested') {\n logger.info(`=== Ignoring PR review with state: ${reviewState} ===`)\n return {\n ...getDefaultOutputs(),\n issue_number: prNumber,\n is_pull_request: 'true',\n valid: 'false',\n }\n }\n\n // Discover existing task ID from PR comments\n let taskId = ''\n if (prNumber) {\n const discoveredTaskId = discoverTaskIdFromIssue(prNumber)\n if (discoveredTaskId) {\n logger.info(`=== Discovered task-id from PR: ${discoveredTaskId} ===`)\n taskId = discoveredTaskId\n }\n }\n\n if (!taskId) {\n logger.info('=== No task-id found on PR — cannot run fix mode ===')\n return {\n ...getDefaultOutputs(),\n issue_number: prNumber,\n is_pull_request: 'true',\n valid: 'false',\n }\n }\n\n const outputs: ParseOutputs = {\n task_id: taskId,\n mode: 'fix',\n clarify: 'false',\n dry_run: 'false',\n from_stage: '',\n feedback: reviewBody || 'Changes requested via PR review',\n issue_number: prNumber,\n is_pull_request: 'true',\n trigger_type: 'pr_review',\n comment_body: '',\n valid: 'true',\n runner: 'github-hosted',\n version: process.env.KODY_DEFAULT_VERSION || '',\n fresh: '',\n complexity: '',\n }\n\n logger.info(\n `=== PR review → fix mode: task_id=${outputs.task_id}, feedback=${outputs.feedback.slice(0, 100)}... ===`,\n )\n\n return outputs\n}\n\n/**\n * Get default output values\n */\nexport function getDefaultOutputs(): ParseOutputs {\n return {\n task_id: '',\n mode: 'full',\n clarify: 'false',\n dry_run: 'false',\n from_stage: '',\n feedback: '',\n issue_number: process.env.DISPATCH_ISSUE_NUMBER || '',\n is_pull_request: process.env.IS_PULL_REQUEST == 'true' ? 'true' : '',\n trigger_type: '',\n comment_body: '',\n valid: 'false',\n runner: 'github-hosted',\n version: process.env.KODY_DEFAULT_VERSION || '',\n fresh: process.env.FRESH || '',\n complexity: process.env.DISPATCH_COMPLEXITY || '',\n }\n}\n\n/**\n * Write outputs to GITHUB_OUTPUT\n */\nfunction writeOutputs(outputs: ParseOutputs): void {\n const githubOutput = process.env.GITHUB_OUTPUT || ''\n\n if (!githubOutput) {\n logger.error('GITHUB_OUTPUT not set!')\n process.exit(1)\n }\n\n const lines = [\n `task_id=${outputs.task_id}`,\n `mode=${outputs.mode}`,\n `clarify=${outputs.clarify}`,\n `dry_run=${outputs.dry_run}`,\n `from_stage=${outputs.from_stage}`,\n `feedback=${outputs.feedback}`,\n `issue_number=${outputs.issue_number}`,\n `is_pull_request=${outputs.is_pull_request}`,\n `trigger_type=${outputs.trigger_type}`,\n `comment_body=${outputs.comment_body}`,\n `valid=${outputs.valid}`,\n `runner=${outputs.runner}`,\n `version=${outputs.version}`,\n `fresh=${outputs.fresh}`,\n `complexity=${outputs.complexity}`,\n ]\n\n writeFileSync(githubOutput, lines.join('\\n') + '\\n')\n}\n\n/**\n * Main entry point\n */\nfunction main(): void {\n const eventName = process.env.GITHUB_EVENT_NAME || ''\n\n let outputs: ParseOutputs\n\n if (eventName === 'workflow_dispatch') {\n outputs = parseDispatchInputs()\n } else if (eventName === 'pull_request_review') {\n outputs = parsePRReviewInputs()\n } else {\n outputs = parseCommentInputs()\n }\n\n writeOutputs(outputs)\n}\n\n// Run if called directly (not imported)\nif (import.meta.url === `file://${process.argv[1]}`) {\n main()\n}\n","/**\n * @fileType utility\n * @domain kody\n * @ai-summary Checkout existing feature branch for a task\n */\n\nimport { logger } from './logger'\nimport { execFileSync } from 'child_process'\nimport { closeLinkedPR } from './github-api'\n\n// Git branch prefixes to try\nconst BRANCH_PREFIXES = ['feat', 'fix', 'refactor', 'docs', 'chore', 'security', 'test']\n\n// Default branch fallback\nconst DEFAULT_BRANCH_FALLBACK = 'dev'\n\n// Git identity for CI (can be overridden via env vars)\nconst GIT_EMAIL = process.env.GIT_USER_EMAIL || '242132053+aguyaharonyair@users.noreply.github.com'\nconst GIT_NAME = process.env.GIT_USER_NAME || 'aguyaharonyair'\n\n/**\n * Execute git command and return output\n */\nfunction gitExec(args: string[], options: { silent?: boolean } = {}): string {\n try {\n return (\n execFileSync('git', args, {\n encoding: 'utf-8',\n stdio: options.silent ? 'ignore' : 'inherit',\n }) || ''\n )\n } catch {\n return ''\n }\n}\n\n/**\n * Execute git command that may fail\n */\nfunction gitExecSilent(args: string[]): string {\n try {\n return (\n execFileSync('git', args, {\n encoding: 'utf-8',\n }) || ''\n )\n } catch {\n return ''\n }\n}\n\n/**\n * Configure git identity\n */\nfunction configureGitIdentity(): void {\n execFileSync('git', ['config', '--global', 'user.email', GIT_EMAIL], { encoding: 'utf-8' })\n execFileSync('git', ['config', '--global', 'user.name', GIT_NAME], { encoding: 'utf-8' })\n}\n\n/**\n * Fetch latest remote refs\n */\nfunction fetchOrigin(): void {\n gitExec(['fetch', 'origin'])\n}\n\n/**\n * Get default branch name\n */\nfunction getDefaultBranch(): string {\n const output = gitExecSilent(['symbolic-ref', 'refs/remotes/origin/HEAD'])\n if (output) {\n const match = output.match(/refs\\/remotes\\/origin\\/(.+)/)\n if (match) {\n return match[1].trim()\n }\n }\n return DEFAULT_BRANCH_FALLBACK\n}\n\n/**\n * Checkout and pull branch\n */\nfunction checkoutAndPull(branch: string): void {\n gitExec(['checkout', branch])\n gitExec(['pull', 'origin', branch])\n}\n\n/**\n * Merge default branch into current branch\n */\nfunction mergeDefaultBranch(defaultBranch: string): boolean {\n try {\n gitExec(['merge', `origin/${defaultBranch}`, '--no-edit'])\n return true\n } catch {\n logger.info('=== CONFLICT: Merge failed ===')\n gitExec(['merge', '--abort'])\n return false\n }\n}\n/**\n * Reset branch if --fresh flag is set.\n * Closes any existing PR for the issue (which also deletes its branch via --delete-branch).\n * Falls back to manual branch deletion if no PR exists.\n */\nexport function resetBranchIfFresh(\n branch: string | null,\n _defaultBranch: string,\n issueNumber?: string,\n): string | null {\n const fresh = process.env.FRESH === 'true'\n if (!fresh) return branch\n\n logger.info(' --fresh flag detected: will reset branch from scratch')\n\n // Close existing PR (also deletes the branch via gh pr close --delete-branch)\n if (issueNumber) {\n logger.info(' Closing existing PR for issue #' + issueNumber)\n const prClosed = closeLinkedPR(parseInt(issueNumber, 10))\n if (prClosed) {\n // closeLinkedPR already deleted the branch via --delete-branch\n return null\n }\n }\n\n // Fallback: manually delete branch if no PR was found (branch may exist without a PR)\n if (branch) {\n logger.info(' Deleting existing branch: ' + branch)\n try {\n gitExec(['push', 'origin', '--delete', branch])\n logger.info(' Deleted remote branch')\n } catch (_e) {\n // May not exist on remote\n }\n try {\n gitExec(['branch', '-D', branch])\n logger.info(' Deleted local branch')\n } catch (_e) {\n // May not exist locally\n }\n }\n\n // Return null to force creating a new branch from default\n return null\n}\n\n/**\n * Find remote branches matching a task ID pattern.\n * Branch names use descriptive suffixes derived from the issue title,\n * so we search by the date prefix from the task ID (e.g., \"260226-auto\")\n * combined with the git branch prefix (fix/, feat/, etc.).\n */\nfunction findRemoteBranch(taskId: string): string | null {\n // Extract date prefix: \"260226-auto-18\" → \"260226-auto\"\n // For manual tasks like \"260226-my-task\" → \"260226-my\"\n const parts = taskId.split('-')\n // Use first two parts as the search pattern (date + descriptor)\n const datePrefix = parts.slice(0, 2).join('-')\n\n const remoteBranches = gitExecSilent(['branch', '-r', '--list'])\n if (!remoteBranches) return null\n\n const branches = remoteBranches\n .split('\\n')\n .map((b) => b.trim())\n .filter((b) => b && !b.includes('->'))\n .map((b) => b.replace('origin/', ''))\n\n // First, try to find branches that match by date prefix AND exact issue number\n // This prevents picking up the wrong branch when multiple issues use the same date\n const issueNumber = process.env.ISSUE_NUMBER\n if (issueNumber) {\n for (const prefix of BRANCH_PREFIXES) {\n const pattern = `${prefix}/${datePrefix}-`\n const matches = branches.filter((b) => b.startsWith(pattern))\n // Must match EXACT issue number: -699- or -699 at end, not -694-\n const issueMatch = matches.find((b) => {\n // Match -699- or -699. or -699_ or end of string\n const regex = new RegExp('-' + issueNumber + '(-|\\.|_|$)')\n return regex.test(b)\n })\n if (issueMatch) return issueMatch\n }\n // If we have an issue number but no matching branch, DON'T fall back - create new branch\n logger.info(' No branch found for issue #' + issueNumber + ', will create new branch')\n return null\n }\n\n // Collect ALL matches across ALL prefixes before deciding\n // Previously this returned on the first prefix with a single match,\n // which could pick feat/ when the correct branch was fix/\n const allMatches: string[] = []\n for (const prefix of BRANCH_PREFIXES) {\n const pattern = `${prefix}/${datePrefix}-`\n const matches = branches.filter((b) => b.startsWith(pattern))\n allMatches.push(...matches)\n }\n\n // Only return if there's exactly ONE match across all prefixes\n if (allMatches.length === 1) {\n return allMatches[0]\n }\n // If multiple matches across different prefixes, don't guess — create new branch\n\n // Also try exact match (legacy/simple branch names)\n for (const prefix of BRANCH_PREFIXES) {\n const exact = `${prefix}/${taskId}`\n if (branches.includes(exact)) return exact\n }\n\n return null\n}\n\n/**\n * Find remote branches matching an issue number (without requiring a task ID).\n * Used when --fresh flag is set and task_id is empty but issue_number is available.\n */\nfunction findRemoteBranchByIssueNumber(issueNumber: string): string | null {\n const remoteBranches = gitExecSilent(['branch', '-r', '--list'])\n if (!remoteBranches) return null\n\n const branches = remoteBranches\n .split('\\n')\n .map((b) => b.trim())\n .filter((b) => b && !b.includes('->'))\n .map((b) => b.replace('origin/', ''))\n\n // Search all prefixes for a branch containing the exact issue number\n for (const prefix of BRANCH_PREFIXES) {\n const matches = branches.filter((b) => b.startsWith(`${prefix}/`))\n const issueMatch = matches.find((b) => {\n const regex = new RegExp('-' + issueNumber + '(-|\\\\.|_|$)')\n return regex.test(b)\n })\n if (issueMatch) return issueMatch\n }\n\n return null\n}\n\n/**\n * Main entry point\n */\nfunction main(): void {\n const taskId = process.env.TASK_ID\n const issueNumber = process.env.ISSUE_NUMBER\n const fresh = process.env.FRESH === 'true'\n\n // When --fresh is used, task_id may be empty. We can still find the old branch\n // by issue number to delete it and start clean.\n if (!taskId && !issueNumber) {\n logger.error('Neither TASK_ID nor ISSUE_NUMBER set!')\n process.exit(1)\n }\n\n // Configure git identity\n configureGitIdentity()\n\n // Fetch latest\n fetchOrigin()\n\n // Get default branch\n const defaultBranch = getDefaultBranch()\n logger.info(`=== Default branch: ${defaultBranch} ===`)\n\n // Find feature branch by pattern matching\n let branch: string | null = null\n if (taskId) {\n branch = findRemoteBranch(taskId)\n } else if (issueNumber) {\n // No task ID (e.g., --fresh mode) — search by issue number\n logger.info(`=== No task ID, searching by issue number #${issueNumber} ===`)\n branch = findRemoteBranchByIssueNumber(issueNumber)\n }\n\n // Reset branch if --fresh flag is set (deletes old branch)\n branch = resetBranchIfFresh(branch, defaultBranch, issueNumber)\n\n if (branch) {\n logger.info(`=== Found feature branch: ${branch} ===`)\n\n checkoutAndPull(branch)\n\n logger.info(`=== Merging latest ${defaultBranch} into ${branch} ===`)\n\n if (!mergeDefaultBranch(defaultBranch)) {\n logger.info('=== Aborting merge ===')\n process.exit(1)\n }\n\n process.exit(0)\n }\n\n // When --fresh with no task ID, we just deleted the old branch (if found).\n // The pipeline will generate a new task ID and ensureFeatureBranch() will create a new branch.\n if (fresh && !taskId) {\n logger.info(\n `=== --fresh mode: old branch cleaned up, staying on ${defaultBranch} for new task ===`,\n )\n process.exit(0)\n }\n\n logger.info(\n `=== No feature branch found for ${taskId || 'issue #' + issueNumber}, staying on default branch ===`,\n )\n}\n\n// Run if called directly\nif (import.meta.url === `file://${process.argv[1]}`) {\n main()\n}\n","/**\n * CLI entry point for @kody-ade/kody-engine\n *\n * Commands:\n * init — Copy kody.yml workflow + opencode config to target repo\n * run — Run the Kody pipeline (default when no command given)\n * version — Print package version\n */\n\nimport { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { fileURLToPath } from \"url\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\n// Resolve paths relative to the package root (dist/bin/cli.mjs → package root)\nconst PKG_ROOT = path.resolve(__dirname, \"..\", \"..\");\n\nfunction getVersion(): string {\n const pkgPath = path.join(PKG_ROOT, \"package.json\");\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n return pkg.version;\n}\n\n// ==========================================================================\n// init command — bootstrap target repo with kody.yml + opencode config\n// ==========================================================================\n\nfunction initCommand(opts: { force: boolean; workflowOnly: boolean }) {\n const cwd = process.cwd();\n const templatesDir = path.join(PKG_ROOT, \"templates\");\n const opencodeDir = path.join(PKG_ROOT, \"opencode\");\n\n // 1. Copy kody.yml\n const workflowSrc = path.join(templatesDir, \"kody.yml\");\n const workflowDest = path.join(cwd, \".github\", \"workflows\", \"kody.yml\");\n\n if (!fs.existsSync(workflowSrc)) {\n console.error(\"Error: Template kody.yml not found in package.\");\n process.exit(1);\n }\n\n if (fs.existsSync(workflowDest) && !opts.force) {\n console.log(\n \"⚠ .github/workflows/kody.yml already exists. Use --force to overwrite.\",\n );\n } else {\n fs.mkdirSync(path.dirname(workflowDest), { recursive: true });\n fs.copyFileSync(workflowSrc, workflowDest);\n console.log(\"✓ Copied .github/workflows/kody.yml\");\n }\n\n // 2. Copy opencode agents + docs\n if (opts.workflowOnly) {\n console.log(\"\\nDone! Configure secrets in your GitHub repo settings.\");\n return;\n }\n\n if (fs.existsSync(opencodeDir)) {\n const destOpencode = path.join(cwd, \".opencode\");\n copyDirRecursive(opencodeDir, destOpencode, opts.force);\n console.log(\"✓ Copied .opencode/ (agents + docs)\");\n }\n\n // 3. Create kody.config.json if it doesn't exist\n const configDest = path.join(cwd, \"kody.config.json\");\n if (!fs.existsSync(configDest)) {\n const defaultConfig = {\n quality: {\n typecheck: \"pnpm -s tsc --noEmit\",\n lint: \"pnpm -s lint\",\n lintFix: \"pnpm lint:fix\",\n format: \"pnpm -s format:check\",\n formatFix: \"pnpm format:fix\",\n testUnit: \"pnpm -s test:unit\",\n },\n git: {\n defaultBranch: \"dev\",\n },\n github: {\n owner: \"\",\n repo: \"\",\n },\n paths: {\n taskDir: \".tasks\",\n },\n };\n fs.writeFileSync(configDest, JSON.stringify(defaultConfig, null, 2) + \"\\n\");\n console.log(\n \"✓ Created kody.config.json (edit github.owner and github.repo)\",\n );\n }\n\n console.log(`\nDone! Next steps:\n 1. Edit kody.config.json — set github.owner and github.repo\n 2. Add secrets to your GitHub repo settings:\n - MINIMAX_API_KEY (or other LLM keys)\n - GH_PAT (optional, for cross-repo operations)\n 3. Commit and push the workflow file\n 4. Comment \"@kody full <task-id>\" on any issue to run the pipeline\n`);\n}\n\n// ==========================================================================\n// run command — execute the Kody pipeline\n// ==========================================================================\n\nasync function runCommand() {\n const { main } = await import(\"@engine/entry\");\n await main(process.argv.slice(3));\n}\n\n// ==========================================================================\n// CI helper commands — used by the workflow in parse/orchestrate jobs\n// ==========================================================================\n\nasync function parseSafetyCommand() {\n await import(\"@engine/parse-safety\");\n}\n\nasync function parseInputsCommand() {\n await import(\"@engine/parse-inputs\");\n}\n\nasync function checkoutBranchCommand() {\n await import(\"@engine/checkout-task-branch\");\n}\n\n// ==========================================================================\n// Utilities\n// ==========================================================================\n\nfunction copyDirRecursive(src: string, dest: string, force: boolean) {\n fs.mkdirSync(dest, { recursive: true });\n for (const entry of fs.readdirSync(src, { withFileTypes: true })) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) {\n copyDirRecursive(srcPath, destPath, force);\n } else {\n if (fs.existsSync(destPath) && !force) continue;\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n\n// ==========================================================================\n// Program\n// ==========================================================================\n\nconst program = new Command()\n .name(\"kody-engine\")\n .version(getVersion())\n .description(\"Kody CI/CD pipeline engine\");\n\nprogram\n .command(\"init\")\n .description(\"Initialize Kody in the current repo (copies workflow + config)\")\n .option(\"-f, --force\", \"Overwrite existing files\", false)\n .option(\"-w, --workflow-only\", \"Only copy the workflow file\", false)\n .action(initCommand);\n\nprogram\n .command(\"run\", { isDefault: true })\n .description(\"Run the Kody pipeline (default command)\")\n .allowUnknownOption()\n .allowExcessArguments()\n .action(runCommand);\n\nprogram\n .command(\"parse-safety\")\n .description(\"Validate comment trigger safety (CI helper)\")\n .action(parseSafetyCommand);\n\nprogram\n .command(\"parse-inputs\")\n .description(\"Parse command inputs from trigger (CI helper)\")\n .action(parseInputsCommand);\n\nprogram\n .command(\"checkout-branch\")\n .description(\"Checkout or create feature branch for task (CI helper)\")\n .action(checkoutBranchCommand);\n\nprogram.parse();\n"],"mappings":"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","names":["z","path","fs","ms","modeLine","path","program","ms","fs","path","VALID_STAGES","execFileSync","fs","execFileSync","fs","path","resolve","spawn","args","z","fs","path","execFileSync","fs","path","fs","fs","path","fs","path","fs","path","fs","path","execFileSync","ctx","rebuildPipelineAfterTaskify","fs","path","ms","init_constants","fs","path","ms","resolve","init_constants","path","execFileSync","resolve","init_constants","fs","ms","path","resolve","init_constants","fs","path","execFileSync","fs","path","fs","path","execFileSync","fs","ms","path","program","report","existsSync","unlinkSync","execFileSync","execFileSync","fs","path","fs","path","fs","path","fs","path","resolvePipelineProfile","getComplexityTier","fs","path","resolveControlMode","fs","path","execFileSync","program","fs","path","fs","path","execFileSync","init_validators","fs","path","fs","path","action","init_validators","fs","path","resolve","ms","execFileSync","fs","path","getIssue","fs","path","fs","path","resolvePipelineProfile","deleteState","resolvePipelineProfile","fs","path","runFullMode","execFileSync","fs","path","ctx","commitPipelineFiles","loadState","writeState","resumeFromGate","state","taskDef","handleGateApproval","resolvePipelineProfile","resetFromStage","setLifecycleLabel","fs","path","resolvePipelineProfile","loadState","init_status","execFileSync","writeFileSync","readFileSync","join","init_status","ms","execFileSync","loadState","writeState","completeState","setLifecycleLabel","writeFileSync","main","APPROVAL_KEYWORDS","VALID_MODES","discoverTaskIdFromIssue","execFileSync","writeFileSync","writeOutputs","main","execFileSync","getDefaultBranch","mergeDefaultBranch","main","Command","fs","path","main"]}
|