@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,237 @@
|
|
|
1
|
+
# ngent v0.5 Specification
|
|
2
|
+
**Date:** 2026-02-17
|
|
3
|
+
**Status:** Approved
|
|
4
|
+
|
|
5
|
+
## Theme: Cost Intelligence
|
|
6
|
+
|
|
7
|
+
v0.5 makes ngent cost-aware — track spending, control routing, and auto-optimize model selection based on observed data.
|
|
8
|
+
|
|
9
|
+
## Feature 1: Metrics Tracking
|
|
10
|
+
|
|
11
|
+
### Problem
|
|
12
|
+
No visibility into where money goes. Users can't answer: "Which stories cost the most?", "What's my haiku pass rate?", "Am I wasting money on sonnet for simple tasks?"
|
|
13
|
+
|
|
14
|
+
### Solution
|
|
15
|
+
Log structured metrics per run and per story. Persist to `ngent/metrics.json`.
|
|
16
|
+
|
|
17
|
+
### Data Model
|
|
18
|
+
```typescript
|
|
19
|
+
interface RunMetrics {
|
|
20
|
+
runId: string;
|
|
21
|
+
feature: string;
|
|
22
|
+
startedAt: string;
|
|
23
|
+
completedAt: string;
|
|
24
|
+
totalCost: number;
|
|
25
|
+
totalStories: number;
|
|
26
|
+
storiesCompleted: number;
|
|
27
|
+
storiesFailed: number;
|
|
28
|
+
totalDurationMs: number;
|
|
29
|
+
stories: StoryMetrics[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface StoryMetrics {
|
|
33
|
+
storyId: string;
|
|
34
|
+
complexity: string;
|
|
35
|
+
modelTier: string;
|
|
36
|
+
modelUsed: string;
|
|
37
|
+
attempts: number; // how many tries (escalations)
|
|
38
|
+
finalTier: string; // tier that succeeded
|
|
39
|
+
success: boolean;
|
|
40
|
+
cost: number;
|
|
41
|
+
durationMs: number;
|
|
42
|
+
firstPassSuccess: boolean; // passed on first attempt?
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface AggregateMetrics {
|
|
46
|
+
totalRuns: number;
|
|
47
|
+
totalCost: number;
|
|
48
|
+
totalStories: number;
|
|
49
|
+
firstPassRate: number; // % passing on first attempt
|
|
50
|
+
escalationRate: number; // % needing model upgrade
|
|
51
|
+
avgCostPerStory: number;
|
|
52
|
+
avgCostPerFeature: number;
|
|
53
|
+
modelEfficiency: Record<string, {
|
|
54
|
+
attempts: number;
|
|
55
|
+
successes: number;
|
|
56
|
+
passRate: number;
|
|
57
|
+
avgCost: number;
|
|
58
|
+
totalCost: number;
|
|
59
|
+
}>;
|
|
60
|
+
complexityAccuracy: Record<string, {
|
|
61
|
+
predicted: number;
|
|
62
|
+
actualTierUsed: string; // most common final tier
|
|
63
|
+
mismatchRate: number; // predicted simple but needed sonnet
|
|
64
|
+
}>;
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### CLI
|
|
69
|
+
```bash
|
|
70
|
+
ngent status --cost # show aggregate metrics
|
|
71
|
+
ngent status --cost --last # show last run metrics
|
|
72
|
+
ngent status --cost --model # show per-model efficiency
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Acceptance Criteria
|
|
76
|
+
- [ ] Per-story metrics logged during run
|
|
77
|
+
- [ ] Per-run summary persisted to metrics.json
|
|
78
|
+
- [ ] Aggregate metrics calculated across all runs
|
|
79
|
+
- [ ] `ngent status --cost` displays formatted report
|
|
80
|
+
- [ ] Metrics survive across runs (append, not overwrite)
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Feature 2: Pluggable Routing
|
|
85
|
+
|
|
86
|
+
### Problem
|
|
87
|
+
Routing is hardcoded — keyword matching or LLM classification. Developers can't inject domain knowledge like "always use opus for database migrations" or "use haiku for all docs tasks".
|
|
88
|
+
|
|
89
|
+
### Solution
|
|
90
|
+
`RoutingStrategy` interface. Built-in strategies + custom strategy loading.
|
|
91
|
+
|
|
92
|
+
### Interface
|
|
93
|
+
```typescript
|
|
94
|
+
interface RoutingStrategy {
|
|
95
|
+
readonly name: string;
|
|
96
|
+
route(story: UserStory, context: RoutingContext): RoutingDecision;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
interface RoutingContext {
|
|
100
|
+
config: NgentConfig;
|
|
101
|
+
codebaseContext?: string;
|
|
102
|
+
metrics?: AggregateMetrics;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
interface RoutingDecision {
|
|
106
|
+
complexity: string;
|
|
107
|
+
modelTier: ModelTier;
|
|
108
|
+
testStrategy: string;
|
|
109
|
+
reasoning: string;
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Built-in Strategies
|
|
114
|
+
- `keyword` — current keyword matching (default fallback)
|
|
115
|
+
- `llm` — LLM classification (v0.3)
|
|
116
|
+
- `adaptive` — metrics-driven (v0.5, see Feature 3)
|
|
117
|
+
- `manual` — user specifies tier per story in prd.json
|
|
118
|
+
|
|
119
|
+
### Custom Strategy
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"routing": {
|
|
123
|
+
"strategy": "custom",
|
|
124
|
+
"customStrategyPath": "./my-router.ts"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
// my-router.ts
|
|
131
|
+
import type { RoutingStrategy } from "ngent";
|
|
132
|
+
|
|
133
|
+
export default {
|
|
134
|
+
name: "my-project-router",
|
|
135
|
+
route(story, context) {
|
|
136
|
+
if (story.tags.includes("migration")) return { modelTier: "powerful", ... };
|
|
137
|
+
if (story.tags.includes("docs")) return { modelTier: "fast", ... };
|
|
138
|
+
// fallback to keyword
|
|
139
|
+
return null; // null = use fallback strategy
|
|
140
|
+
},
|
|
141
|
+
} satisfies RoutingStrategy;
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Strategy Chain
|
|
145
|
+
Custom strategy can return `null` to delegate to next strategy:
|
|
146
|
+
```
|
|
147
|
+
custom → adaptive → llm → keyword
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Acceptance Criteria
|
|
151
|
+
- [ ] RoutingStrategy interface exported
|
|
152
|
+
- [ ] Custom strategy loaded from config path
|
|
153
|
+
- [ ] Strategy chain with null-delegation fallback
|
|
154
|
+
- [ ] Built-in strategies: keyword, llm, manual
|
|
155
|
+
- [ ] Config validation for strategy selection
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Feature 3: Adaptive Routing
|
|
160
|
+
|
|
161
|
+
### Problem
|
|
162
|
+
Static routing wastes money. Haiku might handle 90% of "medium" stories, but routing always sends them to sonnet.
|
|
163
|
+
|
|
164
|
+
### Solution
|
|
165
|
+
Use historical metrics to auto-adjust routing thresholds.
|
|
166
|
+
|
|
167
|
+
### Algorithm
|
|
168
|
+
```
|
|
169
|
+
For each complexity level:
|
|
170
|
+
1. Check metrics: what's haiku's pass rate for this complexity?
|
|
171
|
+
2. Calculate: effectiveCost = haikuCost + (failRate × escalationCost)
|
|
172
|
+
3. Compare: is effectiveCost < sonnetCost?
|
|
173
|
+
4. If yes → route to haiku (escalation handles failures)
|
|
174
|
+
5. If no → route to sonnet (haiku wastes more than it saves)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Thresholds
|
|
178
|
+
```json
|
|
179
|
+
{
|
|
180
|
+
"routing": {
|
|
181
|
+
"strategy": "adaptive",
|
|
182
|
+
"adaptive": {
|
|
183
|
+
"minSamples": 10, // need 10 stories before adapting
|
|
184
|
+
"costThreshold": 0.8, // switch when effectiveCost > 80% of next tier
|
|
185
|
+
"fallbackStrategy": "llm" // use before enough data collected
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Acceptance Criteria
|
|
192
|
+
- [ ] Reads historical metrics for routing decisions
|
|
193
|
+
- [ ] Falls back to configured strategy when insufficient data
|
|
194
|
+
- [ ] Respects minSamples threshold
|
|
195
|
+
- [ ] Calculates effective cost including escalation
|
|
196
|
+
- [ ] Auto-adjusts routing per complexity level
|
|
197
|
+
- [ ] Logs reasoning for adaptive decisions
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Implementation Plan
|
|
202
|
+
|
|
203
|
+
### Phase 1: Metrics Tracking
|
|
204
|
+
**Files:** `src/metrics/tracker.ts`, `src/metrics/aggregator.ts`, `src/metrics/index.ts`
|
|
205
|
+
- StoryMetrics collection during pipeline execution
|
|
206
|
+
- RunMetrics summary on completion
|
|
207
|
+
- AggregateMetrics calculation
|
|
208
|
+
- Persistence to `ngent/metrics.json`
|
|
209
|
+
- `ngent status --cost` display
|
|
210
|
+
|
|
211
|
+
**Commit:** `feat(metrics): add per-story and per-run cost tracking`
|
|
212
|
+
|
|
213
|
+
### Phase 2: Pluggable Routing
|
|
214
|
+
**Files:** `src/routing/strategy.ts`, `src/routing/chain.ts`, `src/routing/strategies/`
|
|
215
|
+
- RoutingStrategy interface
|
|
216
|
+
- Strategy chain with fallback
|
|
217
|
+
- Custom strategy loader (dynamic import)
|
|
218
|
+
- Manual strategy (read from prd.json)
|
|
219
|
+
- Config schema update
|
|
220
|
+
|
|
221
|
+
**Commit:** `feat(routing): add pluggable routing strategy system`
|
|
222
|
+
|
|
223
|
+
### Phase 3: Adaptive Routing
|
|
224
|
+
**Files:** `src/routing/strategies/adaptive.ts`
|
|
225
|
+
- Read AggregateMetrics
|
|
226
|
+
- Calculate effective cost per complexity
|
|
227
|
+
- Route based on cost optimization
|
|
228
|
+
- Fallback when insufficient data
|
|
229
|
+
|
|
230
|
+
**Commit:** `feat(routing): add adaptive metrics-driven routing strategy`
|
|
231
|
+
|
|
232
|
+
## Test Strategy
|
|
233
|
+
- Mode: test-after
|
|
234
|
+
- Run `bun test && bun run typecheck` after each phase
|
|
235
|
+
|
|
236
|
+
## Estimated Effort
|
|
237
|
+
~500-700 LOC across 3 phases.
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
# nax v0.6 Specification
|
|
2
|
+
**Date:** 2026-02-17
|
|
3
|
+
**Status:** Draft
|
|
4
|
+
|
|
5
|
+
## Theme: Terminal User Interface
|
|
6
|
+
|
|
7
|
+
v0.6 adds an interactive TUI that wraps the orchestration loop, giving developers real-time visibility and control over agent execution — without leaving the terminal.
|
|
8
|
+
|
|
9
|
+
### Core Insight
|
|
10
|
+
|
|
11
|
+
**Relentless TUI = monitoring dashboard. nax TUI = interactive co-pilot.**
|
|
12
|
+
|
|
13
|
+
Relentless streams piped text into a read-only panel. nax embeds the actual Claude Code session in a PTY — the developer can **approve permission prompts, intervene mid-execution, and steer** while nax handles the orchestration loop around it.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Feature 1: PTY-Embedded Agent Sessions
|
|
18
|
+
|
|
19
|
+
### Problem
|
|
20
|
+
`nax run` currently spawns Claude Code with `-p` (print mode) — fully non-interactive. The developer has no visibility into what the agent is doing or ability to intervene. For `--dangerously-skip-permissions` this is fine, but for interactive use (where the developer approves each tool call), there's no way to see/interact with the agent.
|
|
21
|
+
|
|
22
|
+
### Solution
|
|
23
|
+
Embed the agent session in a PTY panel within the TUI. Agent output streams in real-time. Keyboard input routes to the agent's stdin when the agent panel is focused.
|
|
24
|
+
|
|
25
|
+
### Design
|
|
26
|
+
```
|
|
27
|
+
┌─ nax run ─────────────────────────────────────────────────────┐
|
|
28
|
+
│ ┌─ Stories ──────────┐ ┌─ Agent ────────────────────────────┐ │
|
|
29
|
+
│ │ ✅ US-001 setup │ │ $ claude │ │
|
|
30
|
+
│ │ ✅ US-002 models │ │ │ │
|
|
31
|
+
│ │ 🔄 US-003 api │ │ I'll implement the API routes... │ │
|
|
32
|
+
│ │ ⬚ US-004 tests │ │ │ │
|
|
33
|
+
│ │ ⬚ US-005 docs │ │ > Allow: Write src/routes/api.ts? │ │
|
|
34
|
+
│ │ │ │ [Y/n] _ │ │
|
|
35
|
+
│ │ Cost: $0.42 │ │ │ │
|
|
36
|
+
│ │ Time: 4m 23s │ │ │ │
|
|
37
|
+
│ └────────────────────┘ └────────────────────────────────────┘ │
|
|
38
|
+
│ ┌─ Status ──────────────────────────────────────────────────┐ │
|
|
39
|
+
│ │ Story 3/5 · US-003 · medium · sonnet · single-session │ │
|
|
40
|
+
│ └───────────────────────────────────────────────────────────┘ │
|
|
41
|
+
└───────────────────────────────────────────────────────────────┘
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### PTY Architecture (Agent-Agnostic)
|
|
45
|
+
|
|
46
|
+
The PTY embedding is **agent-agnostic by design**. The agent panel is a terminal emulator widget — it doesn't parse or understand agent-specific output. Whatever the agent prints, we display. Whatever the user types, we forward. This means any coding agent that runs in a terminal works automatically:
|
|
47
|
+
|
|
48
|
+
| Agent | Interactive PTY? | Notes |
|
|
49
|
+
|:---|:---|:---|
|
|
50
|
+
| Claude Code | ✅ | Permission prompts, rich ANSI output |
|
|
51
|
+
| Codex CLI | ✅ | Similar interactive flow |
|
|
52
|
+
| Aider | ✅ | Chat-style terminal UI |
|
|
53
|
+
| OpenCode | ✅ | Terminal-based |
|
|
54
|
+
| Any CLI tool | ✅ | If it runs in a terminal, it works in the panel |
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
// Agent adapter spawns with PTY instead of piped stdio
|
|
58
|
+
interface AgentSpawnOptions {
|
|
59
|
+
mode: 'pty' | 'pipe'; // pty = interactive TUI, pipe = headless (-p mode)
|
|
60
|
+
onOutput?: (data: string) => void; // stream to TUI panel
|
|
61
|
+
onInput?: () => ReadableStream; // keyboard from TUI
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- **`node-pty`** for PTY allocation (battle-tested, used by VS Code)
|
|
66
|
+
- Agent panel captures all PTY output (ANSI codes preserved)
|
|
67
|
+
- Focused panel routes keystrokes to PTY stdin
|
|
68
|
+
- When not in TUI mode, behavior is unchanged (pipe mode, `-p`)
|
|
69
|
+
- Adding a new agent to the TUI requires only implementing `runInteractive()` on the adapter — zero TUI code changes
|
|
70
|
+
|
|
71
|
+
### Acceptance Criteria
|
|
72
|
+
- [ ] Agent session runs in embedded PTY
|
|
73
|
+
- [ ] Real-time output streaming to TUI panel
|
|
74
|
+
- [ ] Keyboard input routes to agent when panel focused
|
|
75
|
+
- [ ] Permission prompts visible and answerable
|
|
76
|
+
- [ ] Falls back to pipe mode when `--headless` flag or no TTY
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Feature 2: Story Progress Panel
|
|
81
|
+
|
|
82
|
+
### Problem
|
|
83
|
+
During a run, the developer has no idea which stories are done, which failed, or what's currently executing without reading log output.
|
|
84
|
+
|
|
85
|
+
### Solution
|
|
86
|
+
Left sidebar showing all stories with live status icons, cost accumulator, and elapsed time.
|
|
87
|
+
|
|
88
|
+
### Story States
|
|
89
|
+
```
|
|
90
|
+
⬚ pending — not started
|
|
91
|
+
🔄 running — agent working on it
|
|
92
|
+
✅ passed — completed successfully
|
|
93
|
+
❌ failed — all attempts exhausted
|
|
94
|
+
⏭️ skipped — skipped by queue command or dependency failure
|
|
95
|
+
🔁 retrying — escalating to higher tier
|
|
96
|
+
⏸️ paused — queue PAUSE received
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Data Source
|
|
100
|
+
Pipeline context already tracks story status. The TUI subscribes to pipeline events:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
interface PipelineEvents {
|
|
104
|
+
'story:start': (story: UserStory, routing: RoutingResult) => void;
|
|
105
|
+
'story:complete': (story: UserStory, result: StageResult) => void;
|
|
106
|
+
'story:escalate': (story: UserStory, fromTier: string, toTier: string) => void;
|
|
107
|
+
'stage:enter': (stage: string, story: UserStory) => void;
|
|
108
|
+
'stage:exit': (stage: string, result: StageResult) => void;
|
|
109
|
+
'run:complete': (summary: RunSummary) => void;
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Cost Display
|
|
114
|
+
- Per-story cost (from metrics tracker, v0.5)
|
|
115
|
+
- Running total
|
|
116
|
+
- Projected total (based on avg cost × remaining stories)
|
|
117
|
+
|
|
118
|
+
### Acceptance Criteria
|
|
119
|
+
- [ ] All stories listed with real-time status icons
|
|
120
|
+
- [ ] Cost accumulator updates per story completion
|
|
121
|
+
- [ ] Elapsed time displayed
|
|
122
|
+
- [ ] Current stage shown in status bar (routing → constitution → prompt → execution → verify → review)
|
|
123
|
+
- [ ] Pipeline events emitted from runner
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Feature 3: Interactive Controls
|
|
128
|
+
|
|
129
|
+
### Problem
|
|
130
|
+
Queue commands (`PAUSE`, `ABORT`, `SKIP`) require writing to a file. Developers want keyboard shortcuts.
|
|
131
|
+
|
|
132
|
+
### Solution
|
|
133
|
+
Keyboard shortcuts that write queue commands + additional TUI-only controls.
|
|
134
|
+
|
|
135
|
+
### Keybindings
|
|
136
|
+
```
|
|
137
|
+
p — Pause after current story (writes PAUSE to queue)
|
|
138
|
+
a — Abort run (writes ABORT to queue)
|
|
139
|
+
s — Skip current story (writes SKIP <current-story-id>)
|
|
140
|
+
Tab — Toggle focus between Stories panel and Agent panel
|
|
141
|
+
q — Quit TUI (confirms if run is active)
|
|
142
|
+
? — Show help overlay
|
|
143
|
+
Esc — Close overlay / unfocus agent panel
|
|
144
|
+
r — Retry last failed story
|
|
145
|
+
c — Show cost breakdown overlay
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
When the Agent panel is focused, all keys route to the PTY **except**:
|
|
149
|
+
- `Ctrl+]` — escape back to TUI controls (like `screen`/`tmux` prefix)
|
|
150
|
+
|
|
151
|
+
### Acceptance Criteria
|
|
152
|
+
- [ ] Keyboard shortcuts trigger queue commands
|
|
153
|
+
- [ ] Focus mode for agent panel (keys → PTY)
|
|
154
|
+
- [ ] Escape sequence to return to TUI controls
|
|
155
|
+
- [ ] Help overlay with keybinding reference
|
|
156
|
+
- [ ] Confirmation prompt before abort/quit during active run
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Feature 4: Headless Mode Compatibility
|
|
161
|
+
|
|
162
|
+
### Problem
|
|
163
|
+
CI/CD, cron jobs, and `nax run` via scripts need headless operation. TUI should be opt-in, not forced.
|
|
164
|
+
|
|
165
|
+
### Solution
|
|
166
|
+
TUI activates only when:
|
|
167
|
+
1. stdout is a TTY, AND
|
|
168
|
+
2. `--headless` flag is NOT passed
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
nax run # TUI mode (if TTY)
|
|
172
|
+
nax run --headless # pipe mode (current behavior)
|
|
173
|
+
nax run | tee log.txt # pipe mode (not a TTY)
|
|
174
|
+
NAX_HEADLESS=1 nax run # pipe mode (env override)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Acceptance Criteria
|
|
178
|
+
- [ ] TUI auto-activates on TTY
|
|
179
|
+
- [ ] `--headless` forces pipe mode
|
|
180
|
+
- [ ] Non-TTY detection falls back to pipe mode
|
|
181
|
+
- [ ] `NAX_HEADLESS` env var override
|
|
182
|
+
- [ ] All existing functionality works in headless mode (no regressions)
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Feature 5: Responsive Layout
|
|
187
|
+
|
|
188
|
+
### Problem
|
|
189
|
+
Terminal widths vary (80–200+ columns). The 2-panel layout needs to adapt.
|
|
190
|
+
|
|
191
|
+
### Solution
|
|
192
|
+
Three layout breakpoints:
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
< 80 cols: Single column (stories above, agent below, stacked)
|
|
196
|
+
80–140 cols: 2-column (stories left, agent right)
|
|
197
|
+
> 140 cols: 2-column with wider agent panel + stage detail in status bar
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Vertical: Agent panel takes remaining height. Stories panel scrolls if >15 stories.
|
|
201
|
+
|
|
202
|
+
### Acceptance Criteria
|
|
203
|
+
- [ ] Layout adapts to terminal width
|
|
204
|
+
- [ ] Resize events handled (SIGWINCH)
|
|
205
|
+
- [ ] Single-column mode functional on 80-col terminals
|
|
206
|
+
- [ ] Stories panel scrollable
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Non-Goals (v0.6)
|
|
211
|
+
|
|
212
|
+
- **3-column layout** — Relentless-style message queue panel. Not needed; nax doesn't have a message queue concept.
|
|
213
|
+
- **Animated effects** — Typing animations, pulsing cursors. Keep it clean and fast.
|
|
214
|
+
- **Mouse support** — Keyboard-only for v0.6. Mouse can come later.
|
|
215
|
+
- **Theming/colors config** — Hardcoded color scheme (chalk). Configurable themes deferred.
|
|
216
|
+
- **Log panel** — Agent output IS the log. No separate log panel needed.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Technical Stack
|
|
221
|
+
|
|
222
|
+
| Component | Choice | Rationale |
|
|
223
|
+
|:---|:---|:---|
|
|
224
|
+
| **UI framework** | [Ink](https://github.com/vadimdemedes/ink) (React for terminal) | Declarative, Bun-compatible, used by Relentless |
|
|
225
|
+
| **PTY library** | [node-pty](https://github.com/microsoft/node-pty) | Battle-tested (VS Code), split I/O, cross-platform |
|
|
226
|
+
| **Terminal detection** | `process.stdout.isTTY` + `--headless` flag | Standard approach |
|
|
227
|
+
| **Layout** | Ink `<Box>` with flexbox | Built into Ink |
|
|
228
|
+
|
|
229
|
+
### Component Tree
|
|
230
|
+
```
|
|
231
|
+
<App>
|
|
232
|
+
<Layout cols={termWidth}>
|
|
233
|
+
<StoriesPanel stories={stories} costs={costs} elapsed={elapsed} />
|
|
234
|
+
<AgentPanel pty={ptyProcess} focused={agentFocused} />
|
|
235
|
+
</Layout>
|
|
236
|
+
<StatusBar story={current} stage={currentStage} routing={routing} />
|
|
237
|
+
{showHelp && <HelpOverlay />}
|
|
238
|
+
{showCosts && <CostOverlay metrics={metrics} />}
|
|
239
|
+
</App>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### File Structure
|
|
243
|
+
```
|
|
244
|
+
src/
|
|
245
|
+
tui/
|
|
246
|
+
index.ts # TUI entry point, Ink render()
|
|
247
|
+
App.tsx # Root component
|
|
248
|
+
components/
|
|
249
|
+
StoriesPanel.tsx # Story list with status icons
|
|
250
|
+
AgentPanel.tsx # PTY output display + input routing
|
|
251
|
+
StatusBar.tsx # Current story/stage info
|
|
252
|
+
HelpOverlay.tsx # Keybinding reference
|
|
253
|
+
CostOverlay.tsx # Cost breakdown table
|
|
254
|
+
hooks/
|
|
255
|
+
usePty.ts # PTY lifecycle management
|
|
256
|
+
usePipelineEvents.ts # Subscribe to pipeline events
|
|
257
|
+
useKeyboard.ts # Keyboard shortcut handler
|
|
258
|
+
useLayout.ts # Terminal size + breakpoint detection
|
|
259
|
+
types.ts # TUI-specific types
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Agent Adapter Changes
|
|
263
|
+
```typescript
|
|
264
|
+
// src/agents/types.ts — extend AgentAdapter
|
|
265
|
+
interface AgentAdapter {
|
|
266
|
+
// existing
|
|
267
|
+
run(command: string[], options: RunOptions): Promise<AgentResult>;
|
|
268
|
+
|
|
269
|
+
// new: PTY mode for TUI
|
|
270
|
+
runInteractive?(
|
|
271
|
+
command: string[],
|
|
272
|
+
options: RunOptions & {
|
|
273
|
+
onOutput: (data: Buffer) => void;
|
|
274
|
+
onExit: (code: number) => void;
|
|
275
|
+
}
|
|
276
|
+
): PtyHandle;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
interface PtyHandle {
|
|
280
|
+
write(data: string): void; // send input to agent
|
|
281
|
+
resize(cols: number, rows: number): void;
|
|
282
|
+
kill(): void;
|
|
283
|
+
pid: number;
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Implementation Plan
|
|
290
|
+
|
|
291
|
+
### Phase 1: Pipeline Events + Headless Flag
|
|
292
|
+
**Files:** `src/pipeline/runner.ts`, `src/pipeline/events.ts`, `src/cli/run.ts`
|
|
293
|
+
- Add EventEmitter to pipeline runner
|
|
294
|
+
- Emit story/stage lifecycle events
|
|
295
|
+
- Add `--headless` flag and TTY detection
|
|
296
|
+
- No visual changes — just the event plumbing
|
|
297
|
+
|
|
298
|
+
**Commit:** `feat(pipeline): add event emitter for TUI integration`
|
|
299
|
+
|
|
300
|
+
### Phase 2: Ink Scaffolding + Stories Panel
|
|
301
|
+
**Files:** `src/tui/`, `package.json` (add ink, react, node-pty deps)
|
|
302
|
+
- Ink app bootstrap
|
|
303
|
+
- StoriesPanel with mock data
|
|
304
|
+
- StatusBar
|
|
305
|
+
- Layout with breakpoints
|
|
306
|
+
- Wire to pipeline events (stories update live)
|
|
307
|
+
|
|
308
|
+
**Commit:** `feat(tui): add Ink-based TUI with stories panel`
|
|
309
|
+
|
|
310
|
+
### Phase 3: PTY Agent Panel
|
|
311
|
+
**Files:** `src/tui/components/AgentPanel.tsx`, `src/tui/hooks/usePty.ts`, `src/agents/claude.ts`
|
|
312
|
+
- node-pty integration in Claude adapter
|
|
313
|
+
- AgentPanel rendering PTY output
|
|
314
|
+
- Focus management (Tab to switch, Ctrl+] to escape)
|
|
315
|
+
- Input routing to PTY stdin
|
|
316
|
+
|
|
317
|
+
**Commit:** `feat(tui): embed agent PTY session in TUI`
|
|
318
|
+
|
|
319
|
+
### Phase 4: Interactive Controls + Overlays
|
|
320
|
+
**Files:** `src/tui/hooks/useKeyboard.ts`, `src/tui/components/HelpOverlay.tsx`, `src/tui/components/CostOverlay.tsx`
|
|
321
|
+
- Keyboard shortcuts (p/a/s/q/?)
|
|
322
|
+
- Help overlay
|
|
323
|
+
- Cost breakdown overlay
|
|
324
|
+
- Confirmation prompts
|
|
325
|
+
|
|
326
|
+
**Commit:** `feat(tui): add keyboard controls and overlays`
|
|
327
|
+
|
|
328
|
+
### Phase 5: Responsive Layout + Polish
|
|
329
|
+
**Files:** `src/tui/hooks/useLayout.ts`, `src/tui/App.tsx`
|
|
330
|
+
- SIGWINCH handling
|
|
331
|
+
- Single-column breakpoint
|
|
332
|
+
- Scrollable stories panel
|
|
333
|
+
- Edge cases (tiny terminals, rapid resize)
|
|
334
|
+
|
|
335
|
+
**Commit:** `feat(tui): responsive layout and polish`
|
|
336
|
+
|
|
337
|
+
## Test Strategy
|
|
338
|
+
- **Unit tests:** Pipeline events, layout breakpoint logic, keybinding handler
|
|
339
|
+
- **Snapshot tests:** Ink component rendering (ink-testing-library)
|
|
340
|
+
- **Integration:** Full TUI with mock agent adapter (no real Claude Code)
|
|
341
|
+
- Mode: test-after per phase
|
|
342
|
+
|
|
343
|
+
## Dependencies (new)
|
|
344
|
+
```json
|
|
345
|
+
{
|
|
346
|
+
"ink": "^5.0.0",
|
|
347
|
+
"react": "^18.3.0",
|
|
348
|
+
"node-pty": "^1.0.0"
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
DevDependencies:
|
|
353
|
+
```json
|
|
354
|
+
{
|
|
355
|
+
"ink-testing-library": "^4.0.0",
|
|
356
|
+
"@types/react": "^18.3.0"
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
## Estimated Effort
|
|
361
|
+
~1,200–1,500 LOC across 5 phases. Largest phase is Phase 3 (PTY integration).
|
|
362
|
+
|
|
363
|
+
## Risk Assessment
|
|
364
|
+
|
|
365
|
+
| Risk | Mitigation |
|
|
366
|
+
|:---|:---|
|
|
367
|
+
| `node-pty` native compilation on different platforms | Provide fallback to pipe mode; node-pty is well-maintained |
|
|
368
|
+
| Ink + Bun compatibility | Ink 5.x works with Bun; verify in Phase 2 before investing in Phase 3 |
|
|
369
|
+
| PTY output flooding (fast agent output) | Buffer/throttle rendering to 30fps; Ink handles this natively |
|
|
370
|
+
| ANSI escape code rendering in Ink | Use `<Static>` or raw output mode for agent panel |
|
|
371
|
+
| node-pty adds ~5MB to install size | Acceptable tradeoff; it's optional (headless mode works without it) |
|