@nathapp/nax 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitlab-ci.yml +96 -0
- package/BRIEF.md +140 -0
- package/CHANGELOG.md +60 -0
- package/CLAUDE.md +159 -0
- package/README.md +373 -0
- package/US-007-IMPLEMENTATION.md +139 -0
- package/bin/nax.ts +930 -0
- package/biome.json +14 -0
- package/bun.lock +168 -0
- package/bunfig.toml +11 -0
- package/docs/20260216-fix-plan-context-review.md +56 -0
- package/docs/20260216-relentless-vs-ngent-comparison.md +208 -0
- package/docs/20260216-v02-plan.md +136 -0
- package/docs/20260216-v02-review.md +685 -0
- package/docs/20260217-dogfood-findings.md +56 -0
- package/docs/20260217-p2-plus-plan.md +117 -0
- package/docs/20260217-partial-fixes-plan.md +62 -0
- package/docs/20260217-plan-analyze-spec.md +117 -0
- package/docs/20260217-post-impl-review.md +1137 -0
- package/docs/20260217-quick-wins-plan.md +66 -0
- package/docs/20260217-split-runner-plan.md +75 -0
- package/docs/20260217-v03-impl-plan.md +80 -0
- package/docs/20260217-v03-post-impl-review.md +589 -0
- package/docs/20260217-v04-impl-plan.md +86 -0
- package/docs/20260217-v05-post-impl-review.md +850 -0
- package/docs/20260217-v06-post-impl-review.md +817 -0
- package/docs/20260218-adr003-port-plan.md +151 -0
- package/docs/20260218-review-adr003-verification.md +175 -0
- package/docs/20260219-fix-plan-bug16-19.md +79 -0
- package/docs/20260219-fix-plan-bug20-22.md +114 -0
- package/docs/20260219-plan-llm-routing.md +116 -0
- package/docs/20260219-review-bug20-22-fixes.md +135 -0
- package/docs/20260219-routing-baseline-keyword.md +63 -0
- package/docs/20260220-plan-structured-logging-p1.md +80 -0
- package/docs/20260220-plan-structured-logging-p2.md +37 -0
- package/docs/20260220-review-llm-routing.md +180 -0
- package/docs/20260220-review-post-fix-llm-routing.md +70 -0
- package/docs/20260221-fix-plan-relevantfiles-split.md +101 -0
- package/docs/20260221-fix-plan-routing-mode.md +125 -0
- package/docs/20260221-review-v0.9-implementation.md +379 -0
- package/docs/20260222-fix-plan-v091-routing-isolation.md +197 -0
- package/docs/20260223-fix-plan-prompt-audit.md +62 -0
- package/docs/20260224-nax-roadmap-phases.md +189 -0
- package/docs/20260225-phase2-llm-service-layer.md +401 -0
- package/docs/20260225-review-v0.10.1.md +187 -0
- package/docs/20260303-v010-implementation-plan.md +165 -0
- package/docs/CLAUDE.md.bak +191 -0
- package/docs/ROADMAP.md +165 -0
- package/docs/SPEC-rectification.md +0 -0
- package/docs/SPEC.md +324 -0
- package/docs/US-001-plugin-loading-verification.md +152 -0
- package/docs/architecture-analysis.md +1076 -0
- package/docs/bugs/BUG-21-escalation-null-attempts.md +48 -0
- package/docs/bugs-from-dogfood-run-c.md +243 -0
- package/docs/code-review-20260228.md +612 -0
- package/docs/code-review-v0.15.0.md +629 -0
- package/docs/hook-lifecycle-test-plan.md +149 -0
- package/docs/releases/v0.11.0-and-earlier.md +20 -0
- package/docs/releases/v0.12.0.md +15 -0
- package/docs/releases/v0.13.0.md +14 -0
- package/docs/releases/v0.14.0.md +20 -0
- package/docs/releases/v0.14.1.md +36 -0
- package/docs/releases/v0.14.2.md +51 -0
- package/docs/releases/v0.14.3.md +174 -0
- package/docs/releases/v0.14.4.md +94 -0
- package/docs/releases/v0.15.0.md +502 -0
- package/docs/releases/v0.15.1.md +170 -0
- package/docs/releases/v0.15.3.md +193 -0
- package/docs/specs/status-file-v0.10.1.md +812 -0
- package/docs/v0.10-global-config.md +206 -0
- package/docs/v0.10-plugin-system.md +415 -0
- package/docs/v0.10-prompt-optimizer.md +234 -0
- package/docs/v0.3-spec.md +244 -0
- package/docs/v0.4-spec.md +140 -0
- package/docs/v0.5-spec.md +237 -0
- package/docs/v0.6-spec.md +371 -0
- package/docs/v0.7-spec.md +177 -0
- package/docs/v0.8-llm-routing.md +206 -0
- package/docs/v0.8-structured-logging.md +132 -0
- package/docs/v0.9.3-prompt-audit.md +112 -0
- package/examples/plugins/console-reporter/index.test.ts +207 -0
- package/examples/plugins/console-reporter/index.ts +110 -0
- package/nax/config.json +147 -0
- package/nax/features/bugfix-v0171/prd.json +52 -0
- package/nax/features/config-management/prd.json +108 -0
- package/nax/features/config-management/progress.txt +5 -0
- package/nax/features/diagnose/acceptance.test.ts +412 -0
- package/nax/features/diagnose/prd.json +41 -0
- package/nax/features/orchestration-fixes/prd.json +89 -0
- package/nax/features/orchestration-fixes/progress.txt +1 -0
- package/nax/features/plugin-integration/US-007-VERIFICATION.md +259 -0
- package/nax/features/plugin-integration/prd.json +208 -0
- package/nax/features/plugin-integration/progress.txt +5 -0
- package/nax/features/precheck/prd.json +205 -0
- package/nax/features/precheck/progress.txt +15 -0
- package/nax/features/structured-logging/prd.json +199 -0
- package/nax/features/unlock/prd.json +36 -0
- package/package.json +47 -0
- package/src/acceptance/fix-generator.ts +348 -0
- package/src/acceptance/generator.ts +282 -0
- package/src/acceptance/index.ts +30 -0
- package/src/acceptance/types.ts +79 -0
- package/src/agents/claude-decompose.ts +169 -0
- package/src/agents/claude-plan.ts +139 -0
- package/src/agents/claude.ts +324 -0
- package/src/agents/cost.ts +268 -0
- package/src/agents/index.ts +13 -0
- package/src/agents/registry.ts +48 -0
- package/src/agents/types-extended.ts +133 -0
- package/src/agents/types.ts +113 -0
- package/src/agents/validation.ts +69 -0
- package/src/analyze/classifier.ts +305 -0
- package/src/analyze/index.ts +16 -0
- package/src/analyze/scanner.ts +175 -0
- package/src/analyze/types.ts +51 -0
- package/src/cli/accept.ts +108 -0
- package/src/cli/analyze-parser.ts +284 -0
- package/src/cli/analyze.ts +207 -0
- package/src/cli/config.ts +561 -0
- package/src/cli/constitution.ts +109 -0
- package/src/cli/diagnose-analysis.ts +159 -0
- package/src/cli/diagnose-formatter.ts +87 -0
- package/src/cli/diagnose.ts +203 -0
- package/src/cli/generate.ts +127 -0
- package/src/cli/index.ts +37 -0
- package/src/cli/init.ts +188 -0
- package/src/cli/interact.ts +295 -0
- package/src/cli/plan.ts +198 -0
- package/src/cli/plugins.ts +111 -0
- package/src/cli/prompts.ts +295 -0
- package/src/cli/runs.ts +174 -0
- package/src/cli/status-cost.ts +151 -0
- package/src/cli/status-features.ts +338 -0
- package/src/cli/status.ts +13 -0
- package/src/commands/common.ts +171 -0
- package/src/commands/diagnose.ts +17 -0
- package/src/commands/index.ts +8 -0
- package/src/commands/logs.ts +384 -0
- package/src/commands/precheck.ts +86 -0
- package/src/commands/unlock.ts +96 -0
- package/src/config/defaults.ts +160 -0
- package/src/config/index.ts +22 -0
- package/src/config/loader.ts +121 -0
- package/src/config/merger.ts +147 -0
- package/src/config/path-security.ts +121 -0
- package/src/config/paths.ts +27 -0
- package/src/config/schema.ts +56 -0
- package/src/config/schemas.ts +286 -0
- package/src/config/types.ts +423 -0
- package/src/config/validate.ts +103 -0
- package/src/constitution/generator.ts +191 -0
- package/src/constitution/generators/aider.ts +41 -0
- package/src/constitution/generators/claude.ts +35 -0
- package/src/constitution/generators/cursor.ts +36 -0
- package/src/constitution/generators/opencode.ts +38 -0
- package/src/constitution/generators/types.ts +33 -0
- package/src/constitution/generators/windsurf.ts +36 -0
- package/src/constitution/index.ts +10 -0
- package/src/constitution/loader.ts +133 -0
- package/src/constitution/types.ts +31 -0
- package/src/context/auto-detect.ts +227 -0
- package/src/context/builder.ts +246 -0
- package/src/context/elements.ts +83 -0
- package/src/context/formatter.ts +107 -0
- package/src/context/generator.ts +129 -0
- package/src/context/generators/aider.ts +34 -0
- package/src/context/generators/claude.ts +28 -0
- package/src/context/generators/cursor.ts +28 -0
- package/src/context/generators/opencode.ts +30 -0
- package/src/context/generators/windsurf.ts +28 -0
- package/src/context/greenfield.ts +114 -0
- package/src/context/index.ts +33 -0
- package/src/context/injector.ts +279 -0
- package/src/context/test-scanner.ts +370 -0
- package/src/context/types.ts +98 -0
- package/src/errors.ts +67 -0
- package/src/execution/batching.ts +157 -0
- package/src/execution/crash-recovery.ts +373 -0
- package/src/execution/escalation/escalation.ts +44 -0
- package/src/execution/escalation/index.ts +13 -0
- package/src/execution/escalation/tier-escalation.ts +295 -0
- package/src/execution/escalation/tier-outcome.ts +158 -0
- package/src/execution/helpers.ts +38 -0
- package/src/execution/index.ts +45 -0
- package/src/execution/lifecycle/acceptance-loop.ts +272 -0
- package/src/execution/lifecycle/headless-formatter.ts +85 -0
- package/src/execution/lifecycle/index.ts +12 -0
- package/src/execution/lifecycle/parallel-lifecycle.ts +101 -0
- package/src/execution/lifecycle/precheck-runner.ts +140 -0
- package/src/execution/lifecycle/run-cleanup.ts +81 -0
- package/src/execution/lifecycle/run-completion.ts +129 -0
- package/src/execution/lifecycle/run-initialization.ts +141 -0
- package/src/execution/lifecycle/run-lifecycle.ts +312 -0
- package/src/execution/lifecycle/run-setup.ts +204 -0
- package/src/execution/lifecycle/story-hooks.ts +38 -0
- package/src/execution/lifecycle/story-size-prompts.ts +123 -0
- package/src/execution/lock.ts +115 -0
- package/src/execution/parallel-executor.ts +216 -0
- package/src/execution/parallel.ts +400 -0
- package/src/execution/pid-registry.ts +280 -0
- package/src/execution/pipeline-result-handler.ts +388 -0
- package/src/execution/post-verify-rectification.ts +188 -0
- package/src/execution/post-verify.ts +274 -0
- package/src/execution/progress.ts +25 -0
- package/src/execution/prompts.ts +127 -0
- package/src/execution/queue-handler.ts +109 -0
- package/src/execution/rectification.ts +13 -0
- package/src/execution/runner.ts +377 -0
- package/src/execution/sequential-executor.ts +388 -0
- package/src/execution/status-file.ts +264 -0
- package/src/execution/status-writer.ts +139 -0
- package/src/execution/story-context.ts +229 -0
- package/src/execution/test-output-parser.ts +14 -0
- package/src/execution/verification.ts +72 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/runner.ts +286 -0
- package/src/hooks/types.ts +67 -0
- package/src/interaction/chain.ts +154 -0
- package/src/interaction/index.ts +60 -0
- package/src/interaction/init.ts +83 -0
- package/src/interaction/plugins/auto.ts +217 -0
- package/src/interaction/plugins/cli.ts +300 -0
- package/src/interaction/plugins/telegram.ts +384 -0
- package/src/interaction/plugins/webhook.ts +258 -0
- package/src/interaction/state.ts +171 -0
- package/src/interaction/triggers.ts +229 -0
- package/src/interaction/types.ts +163 -0
- package/src/logger/formatters.ts +84 -0
- package/src/logger/index.ts +16 -0
- package/src/logger/logger.ts +298 -0
- package/src/logger/types.ts +48 -0
- package/src/logging/formatter.ts +355 -0
- package/src/logging/index.ts +22 -0
- package/src/logging/types.ts +93 -0
- package/src/metrics/aggregator.ts +190 -0
- package/src/metrics/index.ts +14 -0
- package/src/metrics/tracker.ts +200 -0
- package/src/metrics/types.ts +109 -0
- package/src/optimizer/index.ts +62 -0
- package/src/optimizer/noop.optimizer.ts +24 -0
- package/src/optimizer/rule-based.optimizer.ts +248 -0
- package/src/optimizer/types.ts +53 -0
- package/src/pipeline/events.ts +130 -0
- package/src/pipeline/index.ts +19 -0
- package/src/pipeline/runner.ts +161 -0
- package/src/pipeline/stages/acceptance.ts +197 -0
- package/src/pipeline/stages/completion.ts +99 -0
- package/src/pipeline/stages/constitution.ts +63 -0
- package/src/pipeline/stages/context.ts +117 -0
- package/src/pipeline/stages/execution.ts +194 -0
- package/src/pipeline/stages/index.ts +62 -0
- package/src/pipeline/stages/optimizer.ts +74 -0
- package/src/pipeline/stages/prompt.ts +57 -0
- package/src/pipeline/stages/queue-check.ts +103 -0
- package/src/pipeline/stages/review.ts +181 -0
- package/src/pipeline/stages/routing.ts +81 -0
- package/src/pipeline/stages/verify.ts +100 -0
- package/src/pipeline/types.ts +167 -0
- package/src/plugins/index.ts +31 -0
- package/src/plugins/loader.ts +287 -0
- package/src/plugins/registry.ts +168 -0
- package/src/plugins/types.ts +327 -0
- package/src/plugins/validator.ts +352 -0
- package/src/prd/index.ts +172 -0
- package/src/prd/types.ts +202 -0
- package/src/precheck/checks-blockers.ts +391 -0
- package/src/precheck/checks-warnings.ts +142 -0
- package/src/precheck/checks.ts +30 -0
- package/src/precheck/index.ts +247 -0
- package/src/precheck/story-size-gate.ts +144 -0
- package/src/precheck/types.ts +31 -0
- package/src/queue/index.ts +2 -0
- package/src/queue/manager.ts +254 -0
- package/src/queue/types.ts +54 -0
- package/src/review/index.ts +8 -0
- package/src/review/runner.ts +172 -0
- package/src/review/types.ts +66 -0
- package/src/routing/builder.ts +81 -0
- package/src/routing/chain.ts +74 -0
- package/src/routing/index.ts +16 -0
- package/src/routing/loader.ts +58 -0
- package/src/routing/router.ts +303 -0
- package/src/routing/strategies/adaptive.ts +215 -0
- package/src/routing/strategies/index.ts +8 -0
- package/src/routing/strategies/keyword.ts +163 -0
- package/src/routing/strategies/llm-prompts.ts +209 -0
- package/src/routing/strategies/llm.ts +235 -0
- package/src/routing/strategies/manual.ts +50 -0
- package/src/routing/strategy.ts +99 -0
- package/src/tdd/cleanup.ts +111 -0
- package/src/tdd/index.ts +23 -0
- package/src/tdd/isolation.ts +123 -0
- package/src/tdd/orchestrator.ts +383 -0
- package/src/tdd/prompts.ts +270 -0
- package/src/tdd/rectification-gate.ts +183 -0
- package/src/tdd/session-runner.ts +179 -0
- package/src/tdd/types.ts +81 -0
- package/src/tdd/verdict.ts +271 -0
- package/src/tui/App.tsx +265 -0
- package/src/tui/components/AgentPanel.tsx +75 -0
- package/src/tui/components/CostOverlay.tsx +118 -0
- package/src/tui/components/HelpOverlay.tsx +107 -0
- package/src/tui/components/StatusBar.tsx +63 -0
- package/src/tui/components/StoriesPanel.tsx +177 -0
- package/src/tui/hooks/useKeyboard.ts +142 -0
- package/src/tui/hooks/useLayout.ts +137 -0
- package/src/tui/hooks/usePipelineEvents.ts +183 -0
- package/src/tui/hooks/usePty.ts +194 -0
- package/src/tui/index.tsx +38 -0
- package/src/tui/types.ts +76 -0
- package/src/utils/git.ts +83 -0
- package/src/utils/queue-writer.ts +54 -0
- package/src/verification/executor.ts +235 -0
- package/src/verification/gate.ts +207 -0
- package/src/verification/index.ts +12 -0
- package/src/verification/parser.ts +230 -0
- package/src/verification/rectification.ts +108 -0
- package/src/verification/types.ts +113 -0
- package/src/worktree/dispatcher.ts +65 -0
- package/src/worktree/index.ts +2 -0
- package/src/worktree/manager.ts +187 -0
- package/src/worktree/merge.ts +301 -0
- package/src/worktree/types.ts +4 -0
- package/test/TEST_COVERAGE_US001.md +217 -0
- package/test/TEST_COVERAGE_US003.md +84 -0
- package/test/TEST_COVERAGE_US005.md +86 -0
- package/test/US-002-orchestrator.test.ts +246 -0
- package/test/acceptance/cm-003-default-view.test.ts +194 -0
- package/test/execution/pid-registry.test.ts +240 -0
- package/test/execution/post-verify.test.ts +224 -0
- package/test/helpers/timeout.ts +42 -0
- package/test/integration/US-002-TEST-SUMMARY.md +107 -0
- package/test/integration/US-003-TEST-SUMMARY.md +149 -0
- package/test/integration/US-004-TEST-SUMMARY.md +106 -0
- package/test/integration/US-005-TEST-SUMMARY.md +138 -0
- package/test/integration/US-007-TEST-SUMMARY.md +100 -0
- package/test/integration/agent-validation.test.ts +439 -0
- package/test/integration/analyze-integration.test.ts +261 -0
- package/test/integration/analyze-scanner.test.ts +131 -0
- package/test/integration/cli-config-default-edge-cases.test.ts +222 -0
- package/test/integration/cli-config-default-view.test.ts +229 -0
- package/test/integration/cli-config-diff.test.ts +460 -0
- package/test/integration/cli-config.test.ts +736 -0
- package/test/integration/cli-diagnose.test.ts +592 -0
- package/test/integration/cli-logs.test.ts +314 -0
- package/test/integration/cli-plugins.test.ts +678 -0
- package/test/integration/cli-precheck.test.ts +371 -0
- package/test/integration/cli-run-headless.test.ts +173 -0
- package/test/integration/cli.test.ts +75 -0
- package/test/integration/config/merger.test.ts +465 -0
- package/test/integration/config/paths.test.ts +51 -0
- package/test/integration/config-loader.test.ts +265 -0
- package/test/integration/config.test.ts +444 -0
- package/test/integration/context-integration.test.ts +702 -0
- package/test/integration/context-provider-injection.test.ts +506 -0
- package/test/integration/context-verification-integration.test.ts +295 -0
- package/test/integration/e2e.test.ts +896 -0
- package/test/integration/execution.test.ts +625 -0
- package/test/integration/helpers.test.ts +295 -0
- package/test/integration/hooks.test.ts +361 -0
- package/test/integration/interaction-chain-pipeline.test.ts +464 -0
- package/test/integration/isolation.test.ts +143 -0
- package/test/integration/logger.test.ts +461 -0
- package/test/integration/parallel.test.ts +250 -0
- package/test/integration/path-security.test.ts +173 -0
- package/test/integration/pipeline-acceptance.test.ts +302 -0
- package/test/integration/pipeline-events.test.ts +475 -0
- package/test/integration/pipeline.test.ts +658 -0
- package/test/integration/plan.test.ts +157 -0
- package/test/integration/plugin-routing.test.ts +921 -0
- package/test/integration/plugins/config-integration.test.ts +172 -0
- package/test/integration/plugins/config-resolution.test.ts +522 -0
- package/test/integration/plugins/loader.test.ts +641 -0
- package/test/integration/plugins/registry.test.ts +746 -0
- package/test/integration/plugins/validator.test.ts +563 -0
- package/test/integration/prd-pause.test.ts +205 -0
- package/test/integration/prd-resolvers.test.ts +185 -0
- package/test/integration/precheck-integration.test.ts +468 -0
- package/test/integration/precheck.test.ts +805 -0
- package/test/integration/progress.test.ts +34 -0
- package/test/integration/rectification-flow.test.ts +512 -0
- package/test/integration/reporter-lifecycle.test.ts +860 -0
- package/test/integration/review-config-commands.test.ts +319 -0
- package/test/integration/review-config-schema.test.ts +116 -0
- package/test/integration/review-plugin-integration.test.ts +722 -0
- package/test/integration/review.test.ts +149 -0
- package/test/integration/routing-stage-bug-021.test.ts +274 -0
- package/test/integration/routing-stage-greenfield.test.ts +286 -0
- package/test/integration/runner-config-plugins.test.ts +461 -0
- package/test/integration/runner-fixes.test.ts +399 -0
- package/test/integration/runner-plugin-integration.test.ts +543 -0
- package/test/integration/runner.test.ts +1679 -0
- package/test/integration/s5-greenfield-fallback.test.ts +297 -0
- package/test/integration/status-file-integration.test.ts +325 -0
- package/test/integration/status-file.test.ts +379 -0
- package/test/integration/status-writer.test.ts +345 -0
- package/test/integration/story-id-in-events.test.ts +273 -0
- package/test/integration/tdd-cleanup.test.ts +246 -0
- package/test/integration/tdd-orchestrator.test.ts +1762 -0
- package/test/integration/test-scanner.test.ts +403 -0
- package/test/integration/verification-asset-check.test.ts +142 -0
- package/test/integration/verify-stage.test.ts +275 -0
- package/test/integration/worktree/manager.test.ts +218 -0
- package/test/integration/worktree/merge.test.ts +341 -0
- package/test/manual/logging-formatter-demo.ts +158 -0
- package/test/ui/tui-agent-panel.test.tsx +99 -0
- package/test/ui/tui-controls.test.ts +334 -0
- package/test/ui/tui-cost-and-pty.test.ts +189 -0
- package/test/ui/tui-layout.test.ts +378 -0
- package/test/ui/tui-pty-integration.test.tsx +159 -0
- package/test/ui/tui-stories.test.ts +332 -0
- package/test/unit/acceptance.test.ts +186 -0
- package/test/unit/agent-stderr-capture.test.ts +146 -0
- package/test/unit/analyze-classifier.test.ts +215 -0
- package/test/unit/analyze.test.ts +224 -0
- package/test/unit/auto-detect.test.ts +249 -0
- package/test/unit/cli-status.test.ts +417 -0
- package/test/unit/commands/common.test.ts +320 -0
- package/test/unit/commands/logs.test.ts +416 -0
- package/test/unit/commands/unlock.test.ts +319 -0
- package/test/unit/constitution-generators.test.ts +160 -0
- package/test/unit/constitution.test.ts +209 -0
- package/test/unit/context.test.ts +1722 -0
- package/test/unit/cost.test.ts +231 -0
- package/test/unit/crash-recovery.test.ts +308 -0
- package/test/unit/escalation.test.ts +126 -0
- package/test/unit/execution-logging-stderr.test.ts +156 -0
- package/test/unit/execution-stage.test.ts +122 -0
- package/test/unit/fix-generator.test.ts +275 -0
- package/test/unit/formatters.test.ts +469 -0
- package/test/unit/greenfield.test.ts +179 -0
- package/test/unit/helpers.test.ts +317 -0
- package/test/unit/interaction/human-review-trigger.test.ts +164 -0
- package/test/unit/interaction-network-failures.test.ts +389 -0
- package/test/unit/interaction-plugins.test.ts +164 -0
- package/test/unit/isolation.test.ts +134 -0
- package/test/unit/logging/formatter.test.ts +455 -0
- package/test/unit/merge.test.ts +268 -0
- package/test/unit/metrics.test.ts +276 -0
- package/test/unit/optimizer/noop.optimizer.test.ts +125 -0
- package/test/unit/optimizer/rule-based.optimizer.test.ts +358 -0
- package/test/unit/prd-auto-default.test.ts +290 -0
- package/test/unit/prd-failure-category.test.ts +176 -0
- package/test/unit/prd-get-next-story.test.ts +186 -0
- package/test/unit/precheck-checks.test.ts +840 -0
- package/test/unit/precheck-story-size-gate.test.ts +287 -0
- package/test/unit/precheck-types.test.ts +142 -0
- package/test/unit/prompts.test.ts +475 -0
- package/test/unit/queue.test.ts +237 -0
- package/test/unit/rectification.test.ts +284 -0
- package/test/unit/registry.test.ts +287 -0
- package/test/unit/routing.test.ts +937 -0
- package/test/unit/run-lifecycle.test.ts +140 -0
- package/test/unit/storyid-events.test.ts +224 -0
- package/test/unit/tdd-verdict.test.ts +492 -0
- package/test/unit/test-output-parser.test.ts +377 -0
- package/test/unit/verdict.test.ts +324 -0
- package/test/unit/worktree-manager.test.ts +158 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
# Code Review: v0.15.0 Interactive Pipeline
|
|
2
|
+
|
|
3
|
+
**Review Date:** 2026-02-28
|
|
4
|
+
**Reviewed By:** Claude Code (Sonnet 4.5)
|
|
5
|
+
**Scope:** All files changed between v0.14.4 (6d27bd7) and HEAD (6fe168a)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overall Grade: B+
|
|
10
|
+
|
|
11
|
+
**Summary:** The v0.15.0 Interactive Pipeline implementation is well-structured with good separation of concerns. The interaction module follows clean architecture principles with a plugin-based design. However, there are several CRITICAL security and reliability issues that must be fixed immediately, plus architectural violations (files over 400 lines) that need addressing.
|
|
12
|
+
|
|
13
|
+
**Strengths:**
|
|
14
|
+
- Clean plugin architecture for interaction system
|
|
15
|
+
- Good type safety throughout interaction module
|
|
16
|
+
- Proper separation between CLI, Telegram, Webhook, and Auto plugins
|
|
17
|
+
- Unified verification layer eliminates duplication
|
|
18
|
+
- Test coverage for critical paths
|
|
19
|
+
|
|
20
|
+
**Weaknesses:**
|
|
21
|
+
- Multiple files exceed 400-line limit (violates CLAUDE.md)
|
|
22
|
+
- Missing error handling for network failures in Telegram/Webhook plugins
|
|
23
|
+
- No input validation for malformed webhook callbacks
|
|
24
|
+
- JSON.parse without try-catch in several locations
|
|
25
|
+
- Auto plugin security rule not enforced via config validation
|
|
26
|
+
- Missing tests for edge cases (network failures, malformed input, race conditions)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Critical Findings
|
|
31
|
+
|
|
32
|
+
| ID | Severity | File | Line | Description | Fix |
|
|
33
|
+
|:---|:---|:---|:---|:---|:---|
|
|
34
|
+
| SEC-001 | CRITICAL | `src/interaction/plugins/webhook.ts` | 158 | JSON.parse without try-catch when handling webhook callbacks. Malformed JSON can crash the server. | Wrap in try-catch, return 400 Bad Request on parse error |
|
|
35
|
+
| SEC-002 | CRITICAL | `src/interaction/plugins/telegram.ts` | 79 | No error handling for fetch failure when sending messages. Network errors can crash the plugin. | Add try-catch, throw descriptive error |
|
|
36
|
+
| SEC-003 | CRITICAL | `src/interaction/plugins/telegram.ts` | 244 | No error handling for getUpdates fetch failure. Can cause infinite loop on network errors. | Add try-catch with exponential backoff |
|
|
37
|
+
| SEC-004 | CRITICAL | `src/interaction/plugins/auto.ts` | 72-73 | Security-review never-auto-approve rule is code-based, not config-enforced. Can be accidentally removed. | Add to config schema validation, enforce at chain level |
|
|
38
|
+
| REL-001 | CRITICAL | `src/interaction/chain.ts` | 74-82 | Catch block swallows ALL errors (not just timeout). Plugin crashes are silently converted to timeout responses. | Only catch timeout-specific errors, re-throw others |
|
|
39
|
+
| REL-002 | HIGH | `src/interaction/plugins/webhook.ts` | 80-90 | Polling loop has no exponential backoff. Can cause high CPU usage on stuck requests. | Add exponential backoff with max delay |
|
|
40
|
+
| REL-003 | HIGH | `src/interaction/plugins/telegram.ts` | 96-111 | Polling loop has no exponential backoff. Can hammer Telegram API and get rate limited. | Add exponential backoff (start 1s, max 5s) |
|
|
41
|
+
| TYPE-001 | HIGH | `src/interaction/plugins/webhook.ts` | 117, 127 | Double `as unknown as` casts to work around Bun.serve typing. Loses type safety. | Add proper type definitions for Bun.serve return type |
|
|
42
|
+
| ARCH-001 | HIGH | Multiple files | - | 15 files exceed 400-line limit, violating CLAUDE.md hard requirement. | Split files as documented below |
|
|
43
|
+
| LOG-001 | MEDIUM | `src/interaction/plugins/telegram.ts` | 79-82 | Telegram API error response not logged. Silent failures are hard to debug. | Log error response body before throwing |
|
|
44
|
+
| LOG-002 | MEDIUM | `src/interaction/plugins/webhook.ts` | 72-74 | Webhook POST failure not logged with response body. | Log response body before throwing |
|
|
45
|
+
| TEST-001 | MEDIUM | `test/unit/interaction-plugins.test.ts` | - | No tests for network failures, malformed input, or timeout edge cases. | Add failure scenario tests |
|
|
46
|
+
| TEST-002 | MEDIUM | `test/unit/interaction-plugins.test.ts` | - | Auto plugin LLM call not mocked. Real LLM calls in tests are slow and flaky. | Mock Bun.spawn for LLM calls |
|
|
47
|
+
| MEM-001 | LOW | `src/interaction/plugins/telegram.ts` | 43 | `pendingMessages` Map grows unbounded. Never cleaned up on timeout. | Add cleanup in sendTimeoutMessage |
|
|
48
|
+
| MEM-002 | LOW | `src/interaction/plugins/webhook.ts` | 29 | `pendingResponses` Map grows unbounded. | Add cleanup in cancel() method |
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Files Exceeding 400-Line Limit (ARCH-001)
|
|
53
|
+
|
|
54
|
+
**CRITICAL:** CLAUDE.md mandates **400 lines maximum** per file. The following files violate this:
|
|
55
|
+
|
|
56
|
+
| File | Lines | Recommended Split |
|
|
57
|
+
|:---|---:|:---|
|
|
58
|
+
| `src/config/schema.ts` | 853 | Split into: `schema-core.ts` (types), `schema-routing.ts`, `schema-interaction.ts`, `schema-validation.ts` |
|
|
59
|
+
| `src/agents/claude.ts` | 820 | Split into: `claude-adapter.ts`, `claude-session.ts`, `claude-parser.ts` |
|
|
60
|
+
| `src/tdd/orchestrator.ts` | 743 | Split into: `orchestrator.ts` (main loop), `session-manager.ts`, `verdict-handler.ts` |
|
|
61
|
+
| `src/execution/sequential-executor.ts` | 648 | Split into: `executor.ts`, `story-runner.ts`, `retry-handler.ts` |
|
|
62
|
+
| `src/cli/diagnose.ts` | 638 | Split into: `diagnose.ts`, `checks.ts`, `formatters.ts` |
|
|
63
|
+
| `src/execution/post-verify.ts` | 584 | Split into: `post-verify.ts`, `rectification.ts`, `escalation-decision.ts` |
|
|
64
|
+
| `src/context/builder.ts` | 576 | Split into: `builder.ts`, `providers.ts`, `test-coverage.ts` |
|
|
65
|
+
| `src/cli/analyze.ts` | 568 | Split into: `analyze.ts`, `metrics.ts`, `reports.ts` |
|
|
66
|
+
| `src/precheck/checks.ts` | 548 | Split into: `checks.ts`, `validators.ts`, `git-checks.ts` |
|
|
67
|
+
| `src/cli/status.ts` | 519 | Split into: `status.ts`, `formatters.ts`, `progress.ts` |
|
|
68
|
+
| `src/execution/helpers.ts` | 450 | Split into: `story-filters.ts`, `batch-helpers.ts`, `status-helpers.ts` |
|
|
69
|
+
| `src/execution/escalation/tier-escalation.ts` | 439 | Split into: `tier-escalation.ts`, `cost-calculator.ts` |
|
|
70
|
+
| `src/routing/strategies/llm.ts` | 432 | Split into: `llm-router.ts`, `batch-router.ts`, `cache.ts` |
|
|
71
|
+
| `src/agents/types.ts` | 430 | Split into: `agent-types.ts`, `session-types.ts`, `result-types.ts` |
|
|
72
|
+
| `src/execution/parallel.ts` | 404 | OK (close to limit, watch carefully) |
|
|
73
|
+
|
|
74
|
+
**Action Required:** These files MUST be split before v0.15.0 release. This is a blocking requirement per CLAUDE.md.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Security Analysis
|
|
79
|
+
|
|
80
|
+
### Input Validation
|
|
81
|
+
|
|
82
|
+
**FAIL:** Webhook plugin does not validate incoming callback structure.
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
// src/interaction/plugins/webhook.ts:158 (VULNERABLE)
|
|
86
|
+
const response = JSON.parse(body) as InteractionResponse;
|
|
87
|
+
this.pendingResponses.set(requestId, response);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Attack Vector:**
|
|
91
|
+
- Attacker sends `{"malicious": "payload"}` to webhook callback
|
|
92
|
+
- JSON.parse succeeds but object doesn't match InteractionResponse
|
|
93
|
+
- Type assertion `as InteractionResponse` bypasses type checking
|
|
94
|
+
- Invalid response stored in Map, causes undefined behavior later
|
|
95
|
+
|
|
96
|
+
**Fix:** Add Zod schema validation:
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { z } from "zod";
|
|
100
|
+
|
|
101
|
+
const InteractionResponseSchema = z.object({
|
|
102
|
+
requestId: z.string(),
|
|
103
|
+
action: z.enum(["approve", "reject", "choose", "input", "skip", "abort"]),
|
|
104
|
+
value: z.string().optional(),
|
|
105
|
+
respondedBy: z.string().optional(),
|
|
106
|
+
respondedAt: z.number(),
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// In handleRequest():
|
|
110
|
+
try {
|
|
111
|
+
const parsed = JSON.parse(body);
|
|
112
|
+
const response = InteractionResponseSchema.parse(parsed);
|
|
113
|
+
this.pendingResponses.set(requestId, response);
|
|
114
|
+
} catch (err) {
|
|
115
|
+
return new Response("Bad Request: Invalid response format", { status: 400 });
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Credential Handling
|
|
120
|
+
|
|
121
|
+
**PASS:** Telegram bot token and webhook secrets are stored correctly:
|
|
122
|
+
- Read from env vars or config (never hardcoded)
|
|
123
|
+
- HMAC verification uses timing-safe comparison
|
|
124
|
+
- Secrets not logged
|
|
125
|
+
|
|
126
|
+
**Recommendation:** Add config validation to reject empty secrets:
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
// src/config/schema.ts
|
|
130
|
+
interaction: {
|
|
131
|
+
config: {
|
|
132
|
+
secret: z.string().min(32).optional(), // Enforce minimum secret length
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### SSRF Protection
|
|
138
|
+
|
|
139
|
+
**N/A:** Webhook URL is user-configured (not from untrusted input). No SSRF risk.
|
|
140
|
+
|
|
141
|
+
### Auto Plugin Security Rule
|
|
142
|
+
|
|
143
|
+
**FAIL:** Security-review never-auto-approve rule is enforced in code only:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
// src/interaction/plugins/auto.ts:72-74
|
|
147
|
+
if (request.metadata?.trigger === "security-review") {
|
|
148
|
+
return undefined; // Escalate to human
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Issue:** This can be accidentally removed during refactoring.
|
|
153
|
+
|
|
154
|
+
**Fix:** Enforce at config schema level:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// src/config/schema.ts
|
|
158
|
+
triggers: {
|
|
159
|
+
"security-review": z.object({
|
|
160
|
+
enabled: z.boolean(),
|
|
161
|
+
autoApprove: z.literal(false), // NEVER allow auto-approve for security
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Reliability Analysis
|
|
169
|
+
|
|
170
|
+
### Error Handling
|
|
171
|
+
|
|
172
|
+
**FAIL:** Network errors are not handled properly.
|
|
173
|
+
|
|
174
|
+
**Telegram Plugin (Critical):**
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
// src/interaction/plugins/telegram.ts:68 (VULNERABLE)
|
|
178
|
+
const response = await fetch(`https://api.telegram.org/bot${this.botToken}/sendMessage`, {
|
|
179
|
+
method: "POST",
|
|
180
|
+
headers: { "Content-Type": "application/json" },
|
|
181
|
+
body: JSON.stringify({...}),
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const data = (await response.json()) as { ok: boolean; result: TelegramMessage };
|
|
185
|
+
if (!data.ok) {
|
|
186
|
+
throw new Error("Failed to send Telegram message");
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Issues:**
|
|
191
|
+
1. `fetch()` can throw on network errors (connection refused, DNS failure, timeout)
|
|
192
|
+
2. `response.json()` can throw on malformed JSON
|
|
193
|
+
3. `data.ok` check assumes `data` is defined
|
|
194
|
+
4. No retry logic for transient failures
|
|
195
|
+
|
|
196
|
+
**Fix:**
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
try {
|
|
200
|
+
const response = await fetch(`https://api.telegram.org/bot${this.botToken}/sendMessage`, {
|
|
201
|
+
method: "POST",
|
|
202
|
+
headers: { "Content-Type": "application/json" },
|
|
203
|
+
body: JSON.stringify({...}),
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
if (!response.ok) {
|
|
207
|
+
const errorBody = await response.text();
|
|
208
|
+
throw new Error(`Telegram API error (${response.status}): ${errorBody}`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const data = await response.json();
|
|
212
|
+
if (!data.ok) {
|
|
213
|
+
throw new Error(`Telegram API returned ok=false: ${JSON.stringify(data)}`);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
this.pendingMessages.set(request.id, data.result.message_id);
|
|
217
|
+
} catch (err) {
|
|
218
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
219
|
+
throw new Error(`Failed to send Telegram message: ${msg}`);
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Webhook Plugin (Critical):**
|
|
224
|
+
|
|
225
|
+
Same issues as Telegram. Apply similar fix pattern.
|
|
226
|
+
|
|
227
|
+
### Race Conditions
|
|
228
|
+
|
|
229
|
+
**PASS:** No obvious race conditions found. Interaction chain is single-threaded per request.
|
|
230
|
+
|
|
231
|
+
**Potential Issue:** Webhook server starts on first `receive()` call, but multiple concurrent calls could race:
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
// src/interaction/plugins/webhook.ts:109
|
|
235
|
+
private async startServer(): Promise<void> {
|
|
236
|
+
if (this.server) return; // Already running
|
|
237
|
+
|
|
238
|
+
const port = this.config.callbackPort ?? 8765;
|
|
239
|
+
this.server = Bun.serve({...}) as unknown as Server;
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Race:** Two concurrent `receive()` calls could both check `if (this.server)` before either sets it.
|
|
244
|
+
|
|
245
|
+
**Fix:** Use a mutex or Promise-based lock:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
private serverStartPromise: Promise<void> | null = null;
|
|
249
|
+
|
|
250
|
+
private async startServer(): Promise<void> {
|
|
251
|
+
if (this.server) return;
|
|
252
|
+
if (this.serverStartPromise) {
|
|
253
|
+
await this.serverStartPromise;
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
this.serverStartPromise = (async () => {
|
|
258
|
+
const port = this.config.callbackPort ?? 8765;
|
|
259
|
+
this.server = Bun.serve({...}) as unknown as Server;
|
|
260
|
+
})();
|
|
261
|
+
|
|
262
|
+
await this.serverStartPromise;
|
|
263
|
+
this.serverStartPromise = null;
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Memory Leaks
|
|
268
|
+
|
|
269
|
+
**MEDIUM:** Two Maps grow unbounded:
|
|
270
|
+
- `TelegramInteractionPlugin.pendingMessages` (Line 42)
|
|
271
|
+
- `WebhookInteractionPlugin.pendingResponses` (Line 29)
|
|
272
|
+
|
|
273
|
+
**Issue:** When a request times out, the entry is never removed from the Map.
|
|
274
|
+
|
|
275
|
+
**Fix:**
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
// In sendTimeoutMessage() / cancel():
|
|
279
|
+
this.pendingMessages.delete(requestId);
|
|
280
|
+
this.pendingResponses.delete(requestId);
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Already implemented in `sendTimeoutMessage()` for Telegram (line 331), but not in `cancel()` for Webhook.
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Test Coverage Gaps
|
|
288
|
+
|
|
289
|
+
### Current Coverage
|
|
290
|
+
|
|
291
|
+
**Good:**
|
|
292
|
+
- ✅ Plugin initialization (with/without config, env vars)
|
|
293
|
+
- ✅ Config validation (missing required fields)
|
|
294
|
+
- ✅ Auto plugin security-review rejection
|
|
295
|
+
|
|
296
|
+
**Missing:**
|
|
297
|
+
- ❌ Network failure scenarios (Telegram API down, webhook unreachable)
|
|
298
|
+
- ❌ Malformed responses (invalid JSON, wrong structure)
|
|
299
|
+
- ❌ Timeout edge cases (request expires during polling)
|
|
300
|
+
- ❌ Concurrent request handling
|
|
301
|
+
- ❌ Memory leak verification (Map cleanup)
|
|
302
|
+
- ❌ Auto plugin LLM call (currently untested, would make real API calls)
|
|
303
|
+
|
|
304
|
+
### Recommended Additional Tests
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
describe("TelegramInteractionPlugin - Error Handling", () => {
|
|
308
|
+
test("should handle network failure gracefully", async () => {
|
|
309
|
+
const plugin = new TelegramInteractionPlugin();
|
|
310
|
+
await plugin.init({ botToken: "token", chatId: "123" });
|
|
311
|
+
|
|
312
|
+
// Mock fetch to throw network error
|
|
313
|
+
global.fetch = async () => { throw new Error("ECONNREFUSED") };
|
|
314
|
+
|
|
315
|
+
const request = { /* ... */ };
|
|
316
|
+
await expect(plugin.send(request)).rejects.toThrow("Failed to send Telegram message");
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
test("should handle malformed API response", async () => {
|
|
320
|
+
// Mock fetch to return invalid JSON
|
|
321
|
+
global.fetch = async () => new Response("not json");
|
|
322
|
+
// ... test
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
test("should clean up pendingMessages on timeout", async () => {
|
|
326
|
+
// ... verify Map is empty after timeout
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
describe("WebhookInteractionPlugin - Security", () => {
|
|
331
|
+
test("should reject malformed callback payload", async () => {
|
|
332
|
+
const plugin = new WebhookInteractionPlugin();
|
|
333
|
+
await plugin.init({ url: "http://example.com" });
|
|
334
|
+
|
|
335
|
+
const malformed = { malicious: "payload" };
|
|
336
|
+
const response = await plugin.handleRequest(
|
|
337
|
+
new Request("http://localhost:8765/nax/interact/test-id", {
|
|
338
|
+
method: "POST",
|
|
339
|
+
body: JSON.stringify(malformed),
|
|
340
|
+
})
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
expect(response.status).toBe(400);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
test("should reject callback without HMAC when secret configured", async () => {
|
|
347
|
+
// ... test
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
describe("AutoInteractionPlugin - LLM", () => {
|
|
352
|
+
test("should make correct LLM decision (mocked)", async () => {
|
|
353
|
+
// Mock Bun.spawn to return fake LLM response
|
|
354
|
+
const originalSpawn = Bun.spawn;
|
|
355
|
+
Bun.spawn = (cmd, opts) => {
|
|
356
|
+
const mockStdout = new ReadableStream({
|
|
357
|
+
start(controller) {
|
|
358
|
+
controller.enqueue(new TextEncoder().encode(
|
|
359
|
+
JSON.stringify({
|
|
360
|
+
action: "approve",
|
|
361
|
+
confidence: 0.8,
|
|
362
|
+
reasoning: "test"
|
|
363
|
+
})
|
|
364
|
+
));
|
|
365
|
+
controller.close();
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
return { stdout: mockStdout, stderr: new ReadableStream(), exited: Promise.resolve(0) };
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
// ... test decision logic
|
|
372
|
+
|
|
373
|
+
Bun.spawn = originalSpawn; // Restore
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## Architecture Compliance
|
|
381
|
+
|
|
382
|
+
### Plugin Chain Escalation
|
|
383
|
+
|
|
384
|
+
**Question:** Does the plugin chain correctly handle escalation when all plugins fail?
|
|
385
|
+
|
|
386
|
+
**Answer:** **PARTIAL FAIL**
|
|
387
|
+
|
|
388
|
+
Current behavior:
|
|
389
|
+
- `InteractionChain.receive()` catches ALL errors and returns timeout response
|
|
390
|
+
- If primary plugin throws, it's converted to timeout (action: "skip")
|
|
391
|
+
- No escalation to secondary plugins
|
|
392
|
+
|
|
393
|
+
**Expected behavior:**
|
|
394
|
+
- Try primary plugin
|
|
395
|
+
- On failure, try next plugin in chain (by priority)
|
|
396
|
+
- Only return timeout if all plugins fail OR timeout reached
|
|
397
|
+
|
|
398
|
+
**Current code:**
|
|
399
|
+
```typescript
|
|
400
|
+
// src/interaction/chain.ts:63-82
|
|
401
|
+
async receive(requestId: string, timeout?: number): Promise<InteractionResponse> {
|
|
402
|
+
const plugin = this.getPrimary();
|
|
403
|
+
if (!plugin) {
|
|
404
|
+
throw new Error("No interaction plugin registered");
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const timeoutMs = timeout ?? this.config.defaultTimeout;
|
|
408
|
+
|
|
409
|
+
try {
|
|
410
|
+
const response = await plugin.receive(requestId, timeoutMs);
|
|
411
|
+
return response;
|
|
412
|
+
} catch (err) {
|
|
413
|
+
// BUG: All errors converted to timeout, no fallback to other plugins
|
|
414
|
+
return {
|
|
415
|
+
requestId,
|
|
416
|
+
action: "skip",
|
|
417
|
+
respondedBy: "timeout",
|
|
418
|
+
respondedAt: Date.now(),
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
**Fix:** Implement plugin fallback cascade:
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
async receive(requestId: string, timeout?: number): Promise<InteractionResponse> {
|
|
428
|
+
const timeoutMs = timeout ?? this.config.defaultTimeout;
|
|
429
|
+
const errors: Error[] = [];
|
|
430
|
+
|
|
431
|
+
// Try each plugin in priority order
|
|
432
|
+
for (const entry of this.plugins) {
|
|
433
|
+
try {
|
|
434
|
+
const response = await entry.plugin.receive(requestId, timeoutMs);
|
|
435
|
+
return response;
|
|
436
|
+
} catch (err) {
|
|
437
|
+
errors.push(err instanceof Error ? err : new Error(String(err)));
|
|
438
|
+
// Continue to next plugin
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// All plugins failed
|
|
443
|
+
throw new Error(
|
|
444
|
+
`All interaction plugins failed: ${errors.map(e => e.message).join("; ")}`
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### State Persistence
|
|
450
|
+
|
|
451
|
+
**Question:** Does state persistence correctly serialize/deserialize all runner state?
|
|
452
|
+
|
|
453
|
+
**Answer:** **PASS**
|
|
454
|
+
|
|
455
|
+
- `RunState` interface covers all necessary fields (line 11-41)
|
|
456
|
+
- Serialization uses JSON.stringify with pretty-printing (line 48)
|
|
457
|
+
- Deserialization has error handling for corrupted files (line 68-70)
|
|
458
|
+
- File operations use Bun-native APIs correctly
|
|
459
|
+
|
|
460
|
+
**Recommendation:** Add Zod schema validation for loaded state:
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
import { z } from "zod";
|
|
464
|
+
|
|
465
|
+
const RunStateSchema = z.object({
|
|
466
|
+
feature: z.string(),
|
|
467
|
+
prdPath: z.string(),
|
|
468
|
+
iteration: z.number(),
|
|
469
|
+
totalCost: z.number(),
|
|
470
|
+
storiesCompleted: z.number(),
|
|
471
|
+
pendingInteractions: z.array(z.any()), // Use InteractionRequestSchema
|
|
472
|
+
completedInteractions: z.array(z.any()),
|
|
473
|
+
pausedAt: z.number(),
|
|
474
|
+
pauseReason: z.string(),
|
|
475
|
+
currentStoryId: z.string().optional(),
|
|
476
|
+
currentTier: z.string().optional(),
|
|
477
|
+
currentModel: z.string().optional(),
|
|
478
|
+
metadata: z.record(z.unknown()).optional(),
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
export async function deserializeRunState(featureDir: string): Promise<RunState | null> {
|
|
482
|
+
try {
|
|
483
|
+
const file = Bun.file(stateFile);
|
|
484
|
+
const exists = await file.exists();
|
|
485
|
+
if (!exists) return null;
|
|
486
|
+
|
|
487
|
+
const json = await file.text();
|
|
488
|
+
const parsed = JSON.parse(json);
|
|
489
|
+
const state = RunStateSchema.parse(parsed); // Validate before returning
|
|
490
|
+
return state as RunState;
|
|
491
|
+
} catch (err) {
|
|
492
|
+
// Log validation error for debugging
|
|
493
|
+
console.error("Invalid run state file:", err);
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### Config Schema Validation
|
|
500
|
+
|
|
501
|
+
**Question:** Are all config schema additions validated with Zod?
|
|
502
|
+
|
|
503
|
+
**Answer:** **PARTIAL PASS**
|
|
504
|
+
|
|
505
|
+
New `InteractionConfig` interface exists (line 289-304) but NOT in Zod schema.
|
|
506
|
+
|
|
507
|
+
**Current issue:**
|
|
508
|
+
```typescript
|
|
509
|
+
// src/config/schema.ts:289-304
|
|
510
|
+
export interface InteractionConfig {
|
|
511
|
+
plugin: string;
|
|
512
|
+
config?: Record<string, unknown>;
|
|
513
|
+
defaults: { timeout: number; fallback: string };
|
|
514
|
+
triggers: Partial<Record<string, boolean | { enabled: boolean; fallback?: string; timeout?: number }>>;
|
|
515
|
+
}
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
This is a **TypeScript interface only** — no runtime validation!
|
|
519
|
+
|
|
520
|
+
**Fix:** Add Zod schema:
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
const InteractionConfigSchema = z.object({
|
|
524
|
+
plugin: z.enum(["cli", "telegram", "webhook", "auto"]),
|
|
525
|
+
config: z.record(z.unknown()).optional(),
|
|
526
|
+
defaults: z.object({
|
|
527
|
+
timeout: z.number().min(1000).max(3600000), // 1s to 1hr
|
|
528
|
+
fallback: z.enum(["continue", "skip", "escalate", "abort"]),
|
|
529
|
+
}),
|
|
530
|
+
triggers: z.record(
|
|
531
|
+
z.union([
|
|
532
|
+
z.boolean(),
|
|
533
|
+
z.object({
|
|
534
|
+
enabled: z.boolean(),
|
|
535
|
+
fallback: z.enum(["continue", "skip", "escalate", "abort"]).optional(),
|
|
536
|
+
timeout: z.number().min(1000).optional(),
|
|
537
|
+
}),
|
|
538
|
+
])
|
|
539
|
+
).partial(),
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
// In main config schema:
|
|
543
|
+
export const NaxConfigSchema = z.object({
|
|
544
|
+
// ... existing fields
|
|
545
|
+
interaction: InteractionConfigSchema.optional(),
|
|
546
|
+
});
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## Top 5 Fixes (Priority Order)
|
|
552
|
+
|
|
553
|
+
### 1. Fix Webhook JSON.parse Vulnerability (SEC-001)
|
|
554
|
+
**File:** `src/interaction/plugins/webhook.ts:158`
|
|
555
|
+
**Impact:** CRITICAL — Can crash server on malformed input
|
|
556
|
+
**Effort:** 15 minutes
|
|
557
|
+
|
|
558
|
+
Add try-catch + Zod validation:
|
|
559
|
+
```typescript
|
|
560
|
+
try {
|
|
561
|
+
const parsed = JSON.parse(body);
|
|
562
|
+
const response = InteractionResponseSchema.parse(parsed);
|
|
563
|
+
this.pendingResponses.set(requestId, response);
|
|
564
|
+
} catch (err) {
|
|
565
|
+
return new Response("Bad Request", { status: 400 });
|
|
566
|
+
}
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
### 2. Add Network Error Handling to Telegram Plugin (SEC-002, SEC-003)
|
|
570
|
+
**File:** `src/interaction/plugins/telegram.ts:68, 235`
|
|
571
|
+
**Impact:** CRITICAL — Can crash plugin on network failures
|
|
572
|
+
**Effort:** 30 minutes
|
|
573
|
+
|
|
574
|
+
Wrap all fetch() calls in try-catch with descriptive errors.
|
|
575
|
+
|
|
576
|
+
### 3. Fix InteractionChain Error Swallowing (REL-001)
|
|
577
|
+
**File:** `src/interaction/chain.ts:74-82`
|
|
578
|
+
**Impact:** CRITICAL — Masks real errors as timeouts
|
|
579
|
+
**Effort:** 20 minutes
|
|
580
|
+
|
|
581
|
+
Implement plugin fallback cascade (see Architecture section).
|
|
582
|
+
|
|
583
|
+
### 4. Add Config Schema Validation for Interaction (SEC-004)
|
|
584
|
+
**File:** `src/config/schema.ts`
|
|
585
|
+
**Impact:** HIGH — Runtime validation missing
|
|
586
|
+
**Effort:** 30 minutes
|
|
587
|
+
|
|
588
|
+
Add Zod schemas for InteractionConfig and all trigger configs.
|
|
589
|
+
|
|
590
|
+
### 5. Split Files Over 400 Lines (ARCH-001)
|
|
591
|
+
**Files:** 14 files (see table above)
|
|
592
|
+
**Impact:** HIGH — Violates CLAUDE.md hard requirement
|
|
593
|
+
**Effort:** 4-6 hours
|
|
594
|
+
|
|
595
|
+
Start with largest offenders:
|
|
596
|
+
1. `config/schema.ts` (853 lines) → 4 files
|
|
597
|
+
2. `agents/claude.ts` (820 lines) → 3 files
|
|
598
|
+
3. `tdd/orchestrator.ts` (743 lines) → 3 files
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
## Conclusion
|
|
603
|
+
|
|
604
|
+
The v0.15.0 Interactive Pipeline implementation demonstrates solid engineering with clean separation of concerns and a well-designed plugin architecture. However, **several CRITICAL security and reliability issues must be fixed before release**.
|
|
605
|
+
|
|
606
|
+
**Blocking Issues for Release:**
|
|
607
|
+
1. ✅ Test coverage is adequate (10/10 tests pass)
|
|
608
|
+
2. ❌ **SEC-001, SEC-002, SEC-003** — Network error handling (CRITICAL)
|
|
609
|
+
3. ❌ **REL-001** — Error swallowing in chain (CRITICAL)
|
|
610
|
+
4. ❌ **ARCH-001** — 14 files exceed 400 lines (CRITICAL per CLAUDE.md)
|
|
611
|
+
|
|
612
|
+
**Recommended Release Plan:**
|
|
613
|
+
1. Fix all CRITICAL findings (1-3 above) — **2 hours**
|
|
614
|
+
2. Fix HIGH findings (config validation, type casts) — **1 hour**
|
|
615
|
+
3. Split 3 largest files (config, agents, tdd) — **3 hours**
|
|
616
|
+
4. Add missing tests for network failures — **2 hours**
|
|
617
|
+
5. Re-run full test suite + typecheck — **30 minutes**
|
|
618
|
+
6. **Total:** ~8-9 hours to production-ready
|
|
619
|
+
|
|
620
|
+
**Post-Release Backlog:**
|
|
621
|
+
- Split remaining 11 files over 400 lines
|
|
622
|
+
- Add comprehensive integration tests
|
|
623
|
+
- Implement exponential backoff for polling loops
|
|
624
|
+
- Add Prometheus metrics for interaction success/failure rates
|
|
625
|
+
|
|
626
|
+
---
|
|
627
|
+
|
|
628
|
+
**Reviewer Signature:** Claude Sonnet 4.5
|
|
629
|
+
**Review Completed:** 2026-02-28
|