@nathapp/nax 0.28.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -2
- package/bin/nax.ts +2 -3
- package/dist/nax.js +72753 -0
- package/package.json +11 -3
- package/src/cli/analyze.ts +2 -7
- package/src/cli/config.ts +3 -1
- package/src/config/defaults.ts +1 -0
- package/src/config/schemas.ts +1 -0
- package/src/config/types.ts +1 -0
- package/src/context/builder.ts +10 -1
- package/src/execution/lifecycle/headless-formatter.ts +2 -4
- package/src/prompts/builder.ts +12 -69
- package/src/prompts/sections/isolation.ts +38 -8
- package/src/prompts/sections/role-task.ts +79 -17
- package/src/review/runner.ts +6 -1
- package/src/version.ts +2 -1
- package/.claude/rules/01-project-conventions.md +0 -34
- package/.claude/rules/02-test-architecture.md +0 -39
- package/.claude/rules/03-test-writing.md +0 -58
- package/.claude/rules/04-forbidden-patterns.md +0 -29
- package/.claude/settings.json +0 -15
- package/.githooks/pre-commit +0 -16
- package/.gitlab-ci.yml +0 -103
- package/.mcp.json +0 -8
- package/BRIEF.md +0 -140
- package/CLAUDE.md +0 -143
- package/US-007-IMPLEMENTATION.md +0 -139
- package/biome.json +0 -14
- package/bun.lock +0 -163
- package/bunfig.toml +0 -12
- package/docker-compose.test.yml +0 -15
- package/docs/20260216-fix-plan-context-review.md +0 -56
- package/docs/20260216-relentless-vs-ngent-comparison.md +0 -208
- package/docs/20260216-v02-plan.md +0 -136
- package/docs/20260216-v02-review.md +0 -685
- package/docs/20260217-dogfood-findings.md +0 -56
- package/docs/20260217-p2-plus-plan.md +0 -117
- package/docs/20260217-partial-fixes-plan.md +0 -62
- package/docs/20260217-plan-analyze-spec.md +0 -117
- package/docs/20260217-post-impl-review.md +0 -1137
- package/docs/20260217-quick-wins-plan.md +0 -66
- package/docs/20260217-split-runner-plan.md +0 -75
- package/docs/20260217-v03-impl-plan.md +0 -80
- package/docs/20260217-v03-post-impl-review.md +0 -589
- package/docs/20260217-v04-impl-plan.md +0 -86
- package/docs/20260217-v05-post-impl-review.md +0 -850
- package/docs/20260217-v06-post-impl-review.md +0 -817
- package/docs/20260218-adr003-port-plan.md +0 -151
- package/docs/20260218-review-adr003-verification.md +0 -175
- package/docs/20260219-fix-plan-bug16-19.md +0 -79
- package/docs/20260219-fix-plan-bug20-22.md +0 -114
- package/docs/20260219-plan-llm-routing.md +0 -116
- package/docs/20260219-review-bug20-22-fixes.md +0 -135
- package/docs/20260219-routing-baseline-keyword.md +0 -63
- package/docs/20260220-plan-structured-logging-p1.md +0 -80
- package/docs/20260220-plan-structured-logging-p2.md +0 -37
- package/docs/20260220-review-llm-routing.md +0 -180
- package/docs/20260220-review-post-fix-llm-routing.md +0 -70
- package/docs/20260221-fix-plan-relevantfiles-split.md +0 -101
- package/docs/20260221-fix-plan-routing-mode.md +0 -125
- package/docs/20260221-review-v0.9-implementation.md +0 -379
- package/docs/20260222-fix-plan-v091-routing-isolation.md +0 -197
- package/docs/20260223-fix-plan-prompt-audit.md +0 -62
- package/docs/20260224-nax-roadmap-phases.md +0 -189
- package/docs/20260225-phase2-llm-service-layer.md +0 -401
- package/docs/20260225-review-v0.10.1.md +0 -187
- package/docs/20260303-v010-implementation-plan.md +0 -165
- package/docs/20260304-review-nax.md +0 -492
- package/docs/CLAUDE.md.bak +0 -191
- package/docs/ROADMAP.md +0 -390
- package/docs/SPEC-rectification.md +0 -0
- package/docs/SPEC.md +0 -324
- package/docs/US-001-plugin-loading-verification.md +0 -152
- package/docs/adr/ADR-005-implementation-plan.md +0 -655
- package/docs/adr/ADR-005-pipeline-re-architecture.md +0 -464
- package/docs/architecture-analysis.md +0 -1076
- package/docs/bugs/BUG-21-escalation-null-attempts.md +0 -48
- package/docs/bugs-from-dogfood-run-c.md +0 -243
- package/docs/code-review-20260228.md +0 -612
- package/docs/code-review-v0.15.0.md +0 -629
- package/docs/hook-lifecycle-test-plan.md +0 -149
- package/docs/releases/v0.11.0-and-earlier.md +0 -20
- package/docs/releases/v0.12.0.md +0 -15
- package/docs/releases/v0.13.0.md +0 -14
- package/docs/releases/v0.14.0.md +0 -20
- package/docs/releases/v0.14.1.md +0 -36
- package/docs/releases/v0.14.2.md +0 -51
- package/docs/releases/v0.14.3.md +0 -174
- package/docs/releases/v0.14.4.md +0 -94
- package/docs/releases/v0.15.0.md +0 -502
- package/docs/releases/v0.15.1.md +0 -170
- package/docs/releases/v0.15.3.md +0 -193
- package/docs/specs/bug-039-orphan-processes.md +0 -131
- package/docs/specs/bug-040-review-rectification.md +0 -82
- package/docs/specs/bug-041-cross-story-test-isolation.md +0 -88
- package/docs/specs/bug-042-verifier-failure-capture.md +0 -117
- package/docs/specs/bun-pty-migration.md +0 -171
- package/docs/specs/central-run-registry.md +0 -116
- package/docs/specs/feat-010-smart-runner-git-history.md +0 -96
- package/docs/specs/feat-011-file-context-strategy.md +0 -73
- package/docs/specs/feat-012-tdd-writer-tier.md +0 -79
- package/docs/specs/feat-013-test-after-review.md +0 -89
- package/docs/specs/feat-014-heartbeat-observability.md +0 -127
- package/docs/specs/status-file-consolidation.md +0 -93
- package/docs/specs/status-file-v0.10.1.md +0 -812
- package/docs/specs/trigger-completion.md +0 -145
- package/docs/specs/verification-architecture-v2.md +0 -343
- package/docs/tdd/strategies.md +0 -97
- package/docs/v0.10-global-config.md +0 -206
- package/docs/v0.10-plugin-system.md +0 -415
- package/docs/v0.10-prompt-optimizer.md +0 -234
- package/docs/v0.3-spec.md +0 -244
- package/docs/v0.4-spec.md +0 -140
- package/docs/v0.5-spec.md +0 -237
- package/docs/v0.6-spec.md +0 -371
- package/docs/v0.7-spec.md +0 -177
- package/docs/v0.8-llm-routing.md +0 -206
- package/docs/v0.8-structured-logging.md +0 -132
- package/docs/v0.9.3-prompt-audit.md +0 -112
- package/examples/plugins/console-reporter/index.test.ts +0 -207
- package/examples/plugins/console-reporter/index.ts +0 -110
- package/memory/topic/feat-010-baseref.md +0 -28
- package/memory/topic/feat-013-test-after-deprecation.md +0 -22
- package/nax/config.json +0 -154
- package/nax/features/bug-039-medium/prd.json +0 -45
- package/nax/features/bugfix-v0171/prd.json +0 -52
- package/nax/features/central-run-registry/prd.json +0 -105
- package/nax/features/config-management/prd.json +0 -108
- package/nax/features/config-management/progress.txt +0 -5
- package/nax/features/diagnose/acceptance.test.ts +0 -414
- package/nax/features/diagnose/prd.json +0 -41
- package/nax/features/nax-compliance/prd.json +0 -52
- package/nax/features/nax-compliance/progress.txt +0 -1
- package/nax/features/orchestration-fixes/prd.json +0 -89
- package/nax/features/orchestration-fixes/progress.txt +0 -1
- package/nax/features/plugin-integration/US-007-VERIFICATION.md +0 -259
- package/nax/features/plugin-integration/prd.json +0 -208
- package/nax/features/plugin-integration/progress.txt +0 -5
- package/nax/features/post-rearch-bugfix/prd.json +0 -137
- package/nax/features/precheck/prd.json +0 -205
- package/nax/features/precheck/progress.txt +0 -15
- package/nax/features/prompt-builder/prd.json +0 -152
- package/nax/features/prompt-builder/progress.txt +0 -3
- package/nax/features/review-quality/prd.json +0 -55
- package/nax/features/routing-persistence/prd.json +0 -104
- package/nax/features/routing-persistence/progress.txt +0 -1
- package/nax/features/smart-test-runner/plan.md +0 -7
- package/nax/features/smart-test-runner/prd.json +0 -203
- package/nax/features/smart-test-runner/progress.txt +0 -13
- package/nax/features/smart-test-runner/spec.md +0 -7
- package/nax/features/smart-test-runner/tasks.md +0 -8
- package/nax/features/status-file-consolidation/prd.json +0 -106
- package/nax/features/structured-logging/prd.json +0 -199
- package/nax/features/trigger-completion/prd.json +0 -150
- package/nax/features/trigger-completion/progress.txt +0 -7
- package/nax/features/unlock/prd.json +0 -36
- package/nax/features/v0.18.3-execution-reliability/prd.json +0 -80
- package/nax/features/v0.18.3-execution-reliability/progress.txt +0 -3
- package/nax/features/v0.19.0-hardening/plan.md +0 -7
- package/nax/features/v0.19.0-hardening/prd.json +0 -84
- package/nax/features/v0.19.0-hardening/progress.txt +0 -7
- package/nax/features/v0.19.0-hardening/spec.md +0 -18
- package/nax/features/v0.19.0-hardening/tasks.md +0 -8
- package/nax/features/verify-v2/prd.json +0 -79
- package/nax/features/verify-v2/progress.txt +0 -3
- package/nax/status.json +0 -36
- package/src/prompts/templates/implementer.ts +0 -6
- package/src/prompts/templates/single-session.ts +0 -6
- package/src/prompts/templates/test-writer.ts +0 -6
- package/src/prompts/templates/verifier.ts +0 -6
- package/test/COVERAGE-GAPS.md +0 -333
- package/test/e2e/cm-003-default-view.test.ts +0 -195
- package/test/e2e/plan-analyze-run.test.ts +0 -902
- package/test/helpers/helpers.test.ts +0 -295
- package/test/helpers/timeout.ts +0 -42
- package/test/integration/US-002-TEST-SUMMARY.md +0 -107
- package/test/integration/US-003-TEST-SUMMARY.md +0 -149
- package/test/integration/US-004-TEST-SUMMARY.md +0 -106
- package/test/integration/US-005-TEST-SUMMARY.md +0 -138
- package/test/integration/US-007-TEST-SUMMARY.md +0 -100
- package/test/integration/cli/agent-validation.test.ts +0 -439
- package/test/integration/cli/cli-config-default-edge-cases.test.ts +0 -223
- package/test/integration/cli/cli-config-default-view.test.ts +0 -230
- package/test/integration/cli/cli-config-diff.test.ts +0 -461
- package/test/integration/cli/cli-config-prompts-explain.test.ts +0 -74
- package/test/integration/cli/cli-config.test.ts +0 -737
- package/test/integration/cli/cli-diagnose.test.ts +0 -595
- package/test/integration/cli/cli-logs.test.ts +0 -346
- package/test/integration/cli/cli-plugins.test.ts +0 -679
- package/test/integration/cli/cli-precheck.test.ts +0 -372
- package/test/integration/cli/cli-run-headless.test.ts +0 -174
- package/test/integration/cli/cli.test.ts +0 -76
- package/test/integration/cli/precheck-integration.test.ts +0 -476
- package/test/integration/cli/precheck-orchestrator.test.ts +0 -247
- package/test/integration/cli/precheck.test.ts +0 -806
- package/test/integration/config/config-loader.test.ts +0 -266
- package/test/integration/config/config.test.ts +0 -444
- package/test/integration/config/merger.test.ts +0 -466
- package/test/integration/config/paths.test.ts +0 -52
- package/test/integration/config/security-loader.test.ts +0 -83
- package/test/integration/context/context-integration.test.ts +0 -703
- package/test/integration/context/context-path-security.test.ts +0 -173
- package/test/integration/context/context-provider-injection.test.ts +0 -507
- package/test/integration/context/context-verification-integration.test.ts +0 -296
- package/test/integration/context/s5-greenfield-fallback.test.ts +0 -298
- package/test/integration/execution/execution-isolation.test.ts +0 -143
- package/test/integration/execution/execution.test.ts +0 -634
- package/test/integration/execution/feature-status-write.test.ts +0 -302
- package/test/integration/execution/parallel.test.ts +0 -251
- package/test/integration/execution/prd-pause.test.ts +0 -205
- package/test/integration/execution/prd-resolvers.test.ts +0 -186
- package/test/integration/execution/progress.test.ts +0 -34
- package/test/integration/execution/runner-batching.test.ts +0 -682
- package/test/integration/execution/runner-config-plugins.test.ts +0 -462
- package/test/integration/execution/runner-escalation.test.ts +0 -561
- package/test/integration/execution/runner-fixes.test.ts +0 -400
- package/test/integration/execution/runner-plugin-integration.test.ts +0 -544
- package/test/integration/execution/runner-queue-and-attempts.test.ts +0 -476
- package/test/integration/execution/status-file-integration.test.ts +0 -289
- package/test/integration/execution/status-file.test.ts +0 -380
- package/test/integration/execution/status-writer.test.ts +0 -447
- package/test/integration/execution/story-id-in-events.test.ts +0 -274
- package/test/integration/interaction/interaction-chain-pipeline.test.ts +0 -476
- package/test/integration/pipeline/hooks.test.ts +0 -363
- package/test/integration/pipeline/pipeline-acceptance.test.ts +0 -303
- package/test/integration/pipeline/pipeline-events.test.ts +0 -476
- package/test/integration/pipeline/pipeline.test.ts +0 -660
- package/test/integration/pipeline/reporter-lifecycle.test.ts +0 -862
- package/test/integration/pipeline/verify-stage.test.ts +0 -286
- package/test/integration/plan/analyze-integration.test.ts +0 -262
- package/test/integration/plan/analyze-scanner.test.ts +0 -132
- package/test/integration/plan/logger.test.ts +0 -461
- package/test/integration/plan/plan.test.ts +0 -157
- package/test/integration/plugins/config-integration.test.ts +0 -173
- package/test/integration/plugins/config-resolution.test.ts +0 -523
- package/test/integration/plugins/loader.test.ts +0 -644
- package/test/integration/plugins/plugins-registry.test.ts +0 -747
- package/test/integration/plugins/validator.test.ts +0 -564
- package/test/integration/prompts/pb-004-migration.test.ts +0 -523
- package/test/integration/review/review-config-commands.test.ts +0 -320
- package/test/integration/review/review-config-schema.test.ts +0 -117
- package/test/integration/review/review-plugin-integration.test.ts +0 -729
- package/test/integration/review/review.test.ts +0 -150
- package/test/integration/routing/plugin-routing-advanced.test.ts +0 -461
- package/test/integration/routing/plugin-routing-core.test.ts +0 -527
- package/test/integration/routing/routing-stage-bug-021.test.ts +0 -275
- package/test/integration/routing/routing-stage-greenfield.test.ts +0 -287
- package/test/integration/tdd/tdd-cleanup.test.ts +0 -246
- package/test/integration/tdd/tdd-orchestrator-core.test.ts +0 -565
- package/test/integration/tdd/tdd-orchestrator-failureCategory.test.ts +0 -355
- package/test/integration/tdd/tdd-orchestrator-fallback.test.ts +0 -311
- package/test/integration/tdd/tdd-orchestrator-lite.test.ts +0 -289
- package/test/integration/tdd/tdd-orchestrator-prompts.test.ts +0 -260
- package/test/integration/tdd/tdd-orchestrator-verdict.test.ts +0 -536
- package/test/integration/tmp/headless-test/test.jsonl +0 -30
- package/test/integration/verification/test-scanner.test.ts +0 -403
- package/test/integration/verification/verification-asset-check.test.ts +0 -143
- package/test/integration/worktree/manager.test.ts +0 -218
- package/test/integration/worktree/worktree-merge.test.ts +0 -341
- package/test/manual/logging-formatter-demo.ts +0 -158
- package/test/ui/tui-agent-panel.test.tsx +0 -99
- package/test/ui/tui-pty-integration.test.tsx +0 -146
- package/test/unit/acceptance.test.ts +0 -187
- package/test/unit/agent-stderr-capture.test.ts +0 -147
- package/test/unit/agents/claude.test.ts +0 -107
- package/test/unit/analyze-classifier.test.ts +0 -216
- package/test/unit/analyze.test.ts +0 -224
- package/test/unit/auto-detect.test.ts +0 -250
- package/test/unit/cli-status-project-level.test.ts +0 -283
- package/test/unit/cli-status.test.ts +0 -418
- package/test/unit/commands/common.test.ts +0 -321
- package/test/unit/commands/logs.test.ts +0 -458
- package/test/unit/commands/runs.test.ts +0 -303
- package/test/unit/commands/unlock.test.ts +0 -320
- package/test/unit/config/defaults.test.ts +0 -70
- package/test/unit/config/quality-commands-schema.test.ts +0 -72
- package/test/unit/config/regression-gate-schema.test.ts +0 -160
- package/test/unit/config/smart-runner-flag.test.ts +0 -250
- package/test/unit/constitution-generators.test.ts +0 -161
- package/test/unit/constitution.test.ts +0 -210
- package/test/unit/context/context-autodetect.test.ts +0 -297
- package/test/unit/context/context-build.test.ts +0 -575
- package/test/unit/context/context-coverage.test.ts +0 -236
- package/test/unit/context/context-error.test.ts +0 -93
- package/test/unit/context/context-estimate-tokens.test.ts +0 -201
- package/test/unit/context/context-format.test.ts +0 -302
- package/test/unit/context/context-isolation.test.ts +0 -267
- package/test/unit/context/context-sort.test.ts +0 -93
- package/test/unit/context/context-story.test.ts +0 -108
- package/test/unit/context/prior-failures.test.ts +0 -463
- package/test/unit/context.test.ts +0 -1726
- package/test/unit/cost.test.ts +0 -231
- package/test/unit/crash-recovery.test.ts +0 -309
- package/test/unit/escalation.test.ts +0 -127
- package/test/unit/execution/lifecycle/run-completion.test.ts +0 -240
- package/test/unit/execution/lifecycle/run-regression.test.ts +0 -420
- package/test/unit/execution/pid-registry.test.ts +0 -241
- package/test/unit/execution/sequential-executor.test.ts +0 -235
- package/test/unit/execution/sfc-004-dead-code-cleanup.test.ts +0 -89
- package/test/unit/execution/structured-failure.test.ts +0 -415
- package/test/unit/execution-logging-stderr.test.ts +0 -157
- package/test/unit/execution-stage.test.ts +0 -123
- package/test/unit/fix-generator.test.ts +0 -276
- package/test/unit/formatters.test.ts +0 -468
- package/test/unit/greenfield.test.ts +0 -180
- package/test/unit/hooks/shell-security.test.ts +0 -40
- package/test/unit/interaction/auto-plugin.test.ts +0 -162
- package/test/unit/interaction/human-review-trigger.test.ts +0 -165
- package/test/unit/interaction-network-failures.test.ts +0 -390
- package/test/unit/interaction-plugins.test.ts +0 -472
- package/test/unit/logging/formatter.test.ts +0 -456
- package/test/unit/merge.test.ts +0 -269
- package/test/unit/metrics/aggregator.test.ts +0 -164
- package/test/unit/metrics/tracker.test.ts +0 -186
- package/test/unit/metrics.test.ts +0 -276
- package/test/unit/optimizer/noop.optimizer.test.ts +0 -125
- package/test/unit/optimizer/rule-based.optimizer.test.ts +0 -358
- package/test/unit/pipeline/event-bus.test.ts +0 -105
- package/test/unit/pipeline/routing-partial-override.test.ts +0 -121
- package/test/unit/pipeline/runner-retry.test.ts +0 -89
- package/test/unit/pipeline/stages/autofix.test.ts +0 -97
- package/test/unit/pipeline/stages/completion-review-gate.test.ts +0 -218
- package/test/unit/pipeline/stages/execution-ambiguity.test.ts +0 -311
- package/test/unit/pipeline/stages/execution-merge-conflict.test.ts +0 -218
- package/test/unit/pipeline/stages/rectify.test.ts +0 -101
- package/test/unit/pipeline/stages/regression-stage.test.ts +0 -69
- package/test/unit/pipeline/stages/review.test.ts +0 -201
- package/test/unit/pipeline/stages/routing-idempotence.test.ts +0 -139
- package/test/unit/pipeline/stages/routing-initial-complexity.test.ts +0 -321
- package/test/unit/pipeline/stages/routing-persistence.test.ts +0 -380
- package/test/unit/pipeline/stages/verify.test.ts +0 -267
- package/test/unit/pipeline/subscribers/events-writer.test.ts +0 -227
- package/test/unit/pipeline/subscribers/hooks.test.ts +0 -84
- package/test/unit/pipeline/subscribers/interaction.test.ts +0 -313
- package/test/unit/pipeline/subscribers/registry.test.ts +0 -149
- package/test/unit/pipeline/subscribers/reporters.test.ts +0 -90
- package/test/unit/pipeline/verify-smart-runner.test.ts +0 -345
- package/test/unit/prd-auto-default.test.ts +0 -291
- package/test/unit/prd-failure-category.test.ts +0 -177
- package/test/unit/prd-get-next-story.test.ts +0 -215
- package/test/unit/precheck/checks-warnings.test.ts +0 -114
- package/test/unit/precheck-checks.test.ts +0 -841
- package/test/unit/precheck-story-size-gate.test.ts +0 -288
- package/test/unit/precheck-types.test.ts +0 -143
- package/test/unit/prompts/builder.test.ts +0 -258
- package/test/unit/prompts/loader.test.ts +0 -355
- package/test/unit/prompts/sections/conventions.test.ts +0 -30
- package/test/unit/prompts/sections/isolation.test.ts +0 -35
- package/test/unit/prompts/sections/role-task.test.ts +0 -40
- package/test/unit/prompts/sections/sections.test.ts +0 -238
- package/test/unit/prompts/sections/story.test.ts +0 -45
- package/test/unit/prompts/sections/verdict.test.ts +0 -58
- package/test/unit/prompts.test.ts +0 -476
- package/test/unit/queue.test.ts +0 -237
- package/test/unit/rectification.test.ts +0 -285
- package/test/unit/registry.test.ts +0 -288
- package/test/unit/review/runner.test.ts +0 -117
- package/test/unit/routing/content-hash.test.ts +0 -99
- package/test/unit/routing/routing-stability.test.ts +0 -208
- package/test/unit/routing/strategies/llm.test.ts +0 -306
- package/test/unit/routing-advanced.test.ts +0 -313
- package/test/unit/routing-core.test.ts +0 -341
- package/test/unit/routing-strategies.test.ts +0 -440
- package/test/unit/storyid-events.test.ts +0 -213
- package/test/unit/tdd-verdict.test.ts +0 -492
- package/test/unit/test-output-parser.test.ts +0 -377
- package/test/unit/ui/tui-controls.test.ts +0 -335
- package/test/unit/ui/tui-cost-and-pty.test.ts +0 -190
- package/test/unit/ui/tui-layout.test.ts +0 -379
- package/test/unit/ui/tui-stories.test.ts +0 -333
- package/test/unit/unit-isolation.test.ts +0 -135
- package/test/unit/utils/git.test.ts +0 -50
- package/test/unit/utils/path-security.test.ts +0 -47
- package/test/unit/utils-helpers.test.ts +0 -318
- package/test/unit/verdict.test.ts +0 -325
- package/test/unit/verification/orchestrator-types.test.ts +0 -54
- package/test/unit/verification/orchestrator.test.ts +0 -66
- package/test/unit/verification/smart-runner-config.test.ts +0 -163
- package/test/unit/verification/smart-runner-discovery.test.ts +0 -354
- package/test/unit/verification/smart-runner.test.ts +0 -262
- package/test/unit/verification/strategies/acceptance.test.ts +0 -33
- package/test/unit/verification/strategies/regression.test.ts +0 -87
- package/test/unit/verification/strategies/scoped.test.ts +0 -100
- package/test/unit/worktree-manager.test.ts +0 -159
- package/tsconfig.json +0 -27
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
// RE-ARCH: keep
|
|
2
|
-
/**
|
|
3
|
-
* Tests for src/precheck/story-size-gate.ts
|
|
4
|
-
*
|
|
5
|
-
* Tests story size gate detection logic including heuristic signals
|
|
6
|
-
* (AC count, description length, bullet points).
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { describe, expect, test } from "bun:test";
|
|
10
|
-
import type { NaxConfig } from "../../src/config";
|
|
11
|
-
import type { PRD, UserStory } from "../../src/prd/types";
|
|
12
|
-
import { checkStorySizeGate } from "../../src/precheck/story-size-gate";
|
|
13
|
-
|
|
14
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
15
|
-
// Test fixtures
|
|
16
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
17
|
-
|
|
18
|
-
const createMockConfig = (
|
|
19
|
-
storySizeGateConfig?: NaxConfig["precheck"],
|
|
20
|
-
): NaxConfig =>
|
|
21
|
-
({
|
|
22
|
-
precheck: storySizeGateConfig,
|
|
23
|
-
version: 1,
|
|
24
|
-
models: {
|
|
25
|
-
fast: "haiku",
|
|
26
|
-
balanced: "sonnet",
|
|
27
|
-
powerful: "opus",
|
|
28
|
-
},
|
|
29
|
-
autoMode: {
|
|
30
|
-
enabled: false,
|
|
31
|
-
defaultAgent: "test",
|
|
32
|
-
fallbackOrder: [],
|
|
33
|
-
complexityRouting: { simple: "fast", medium: "balanced", complex: "powerful", expert: "powerful" },
|
|
34
|
-
escalation: { enabled: false, tierOrder: [] },
|
|
35
|
-
},
|
|
36
|
-
routing: { strategy: "keyword" },
|
|
37
|
-
execution: {
|
|
38
|
-
maxIterations: 10,
|
|
39
|
-
iterationDelayMs: 1000,
|
|
40
|
-
costLimit: 10,
|
|
41
|
-
sessionTimeoutSeconds: 600,
|
|
42
|
-
verificationTimeoutSeconds: 300,
|
|
43
|
-
maxStoriesPerFeature: 100,
|
|
44
|
-
rectification: {
|
|
45
|
-
enabled: false,
|
|
46
|
-
maxRetries: 0,
|
|
47
|
-
fullSuiteTimeoutSeconds: 120,
|
|
48
|
-
maxFailureSummaryChars: 2000,
|
|
49
|
-
abortOnIncreasingFailures: true,
|
|
50
|
-
},
|
|
51
|
-
regressionGate: { enabled: false, timeoutSeconds: 120 },
|
|
52
|
-
contextProviderTokenBudget: 2000,
|
|
53
|
-
},
|
|
54
|
-
quality: {
|
|
55
|
-
requireTypecheck: false,
|
|
56
|
-
requireLint: false,
|
|
57
|
-
requireTests: false,
|
|
58
|
-
commands: {},
|
|
59
|
-
forceExit: false,
|
|
60
|
-
detectOpenHandles: false,
|
|
61
|
-
detectOpenHandlesRetries: 1,
|
|
62
|
-
gracePeriodMs: 5000,
|
|
63
|
-
drainTimeoutMs: 2000,
|
|
64
|
-
shell: "/bin/sh",
|
|
65
|
-
stripEnvVars: [],
|
|
66
|
-
environmentalEscalationDivisor: 2,
|
|
67
|
-
},
|
|
68
|
-
tdd: {
|
|
69
|
-
maxRetries: 0,
|
|
70
|
-
autoVerifyIsolation: false,
|
|
71
|
-
autoApproveVerifier: false,
|
|
72
|
-
strategy: "off",
|
|
73
|
-
},
|
|
74
|
-
constitution: { enabled: false, path: "", maxTokens: 2000 },
|
|
75
|
-
analyze: { llmEnhanced: false, model: "fast", fallbackToKeywords: true, maxCodebaseSummaryTokens: 5000 },
|
|
76
|
-
review: { enabled: false, checks: [], commands: {} },
|
|
77
|
-
plan: { model: "balanced", outputPath: "" },
|
|
78
|
-
acceptance: { enabled: false, maxRetries: 0, generateTests: false, testPath: "" },
|
|
79
|
-
context: {
|
|
80
|
-
testCoverage: {
|
|
81
|
-
enabled: false,
|
|
82
|
-
detail: "names-only",
|
|
83
|
-
maxTokens: 500,
|
|
84
|
-
testPattern: "**/*.test.ts",
|
|
85
|
-
scopeToStory: false,
|
|
86
|
-
},
|
|
87
|
-
autoDetect: { enabled: false, maxFiles: 5, traceImports: false },
|
|
88
|
-
},
|
|
89
|
-
}) as NaxConfig;
|
|
90
|
-
|
|
91
|
-
const createMockStory = (overrides: Partial<UserStory> = {}): UserStory => ({
|
|
92
|
-
id: "US-001",
|
|
93
|
-
title: "Test story",
|
|
94
|
-
description: "Test description",
|
|
95
|
-
acceptanceCriteria: ["AC1"],
|
|
96
|
-
tags: [],
|
|
97
|
-
dependencies: [],
|
|
98
|
-
status: "pending",
|
|
99
|
-
passes: false,
|
|
100
|
-
escalations: [],
|
|
101
|
-
attempts: 0,
|
|
102
|
-
...overrides,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
const createMockPRD = (stories: UserStory[] = []): PRD => ({
|
|
106
|
-
project: "test-project",
|
|
107
|
-
feature: "test-feature",
|
|
108
|
-
branchName: "test-branch",
|
|
109
|
-
userStories: stories,
|
|
110
|
-
createdAt: new Date().toISOString(),
|
|
111
|
-
updatedAt: new Date().toISOString(),
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
115
|
-
// Tests
|
|
116
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
117
|
-
|
|
118
|
-
describe("checkStorySizeGate", () => {
|
|
119
|
-
test("passes when gate is disabled", async () => {
|
|
120
|
-
const config = createMockConfig({ storySizeGate: { enabled: false, maxAcCount: 6, maxDescriptionLength: 2000, maxBulletPoints: 8 } });
|
|
121
|
-
const story = createMockStory({ acceptanceCriteria: Array(10).fill("AC") });
|
|
122
|
-
const prd = createMockPRD([story]);
|
|
123
|
-
|
|
124
|
-
const result = await checkStorySizeGate(config, prd);
|
|
125
|
-
|
|
126
|
-
expect(result.check.passed).toBe(true);
|
|
127
|
-
expect(result.check.tier).toBe("warning");
|
|
128
|
-
expect(result.check.message).toContain("disabled");
|
|
129
|
-
expect(result.flaggedStories).toHaveLength(0);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
test("passes when no stories exceed thresholds", async () => {
|
|
133
|
-
const config = createMockConfig({ storySizeGate: { enabled: true, maxAcCount: 6, maxDescriptionLength: 2000, maxBulletPoints: 8 } });
|
|
134
|
-
const story = createMockStory({
|
|
135
|
-
acceptanceCriteria: ["AC1", "AC2", "AC3"],
|
|
136
|
-
description: "Short description",
|
|
137
|
-
});
|
|
138
|
-
const prd = createMockPRD([story]);
|
|
139
|
-
|
|
140
|
-
const result = await checkStorySizeGate(config, prd);
|
|
141
|
-
|
|
142
|
-
expect(result.check.passed).toBe(true);
|
|
143
|
-
expect(result.check.tier).toBe("warning");
|
|
144
|
-
expect(result.flaggedStories).toHaveLength(0);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
test("flags story when AC count exceeds threshold", async () => {
|
|
148
|
-
const config = createMockConfig({ storySizeGate: { enabled: true, maxAcCount: 6, maxDescriptionLength: 2000, maxBulletPoints: 8 } });
|
|
149
|
-
const story = createMockStory({
|
|
150
|
-
id: "US-001",
|
|
151
|
-
acceptanceCriteria: Array(8).fill("AC"),
|
|
152
|
-
description: "Short description",
|
|
153
|
-
});
|
|
154
|
-
const prd = createMockPRD([story]);
|
|
155
|
-
|
|
156
|
-
const result = await checkStorySizeGate(config, prd);
|
|
157
|
-
|
|
158
|
-
expect(result.check.passed).toBe(false);
|
|
159
|
-
expect(result.check.tier).toBe("warning");
|
|
160
|
-
expect(result.check.message).toContain("US-001");
|
|
161
|
-
expect(result.flaggedStories).toHaveLength(1);
|
|
162
|
-
expect(result.flaggedStories[0].storyId).toBe("US-001");
|
|
163
|
-
expect(result.flaggedStories[0].signals.acCount.flagged).toBe(true);
|
|
164
|
-
expect(result.flaggedStories[0].signals.acCount.value).toBe(8);
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
test("flags story when description length exceeds threshold", async () => {
|
|
168
|
-
const config = createMockConfig({ storySizeGate: { enabled: true, maxAcCount: 6, maxDescriptionLength: 100, maxBulletPoints: 8 } });
|
|
169
|
-
const longDescription = "a".repeat(150);
|
|
170
|
-
const story = createMockStory({
|
|
171
|
-
id: "US-002",
|
|
172
|
-
acceptanceCriteria: ["AC1"],
|
|
173
|
-
description: longDescription,
|
|
174
|
-
});
|
|
175
|
-
const prd = createMockPRD([story]);
|
|
176
|
-
|
|
177
|
-
const result = await checkStorySizeGate(config, prd);
|
|
178
|
-
|
|
179
|
-
expect(result.check.passed).toBe(false);
|
|
180
|
-
expect(result.flaggedStories).toHaveLength(1);
|
|
181
|
-
expect(result.flaggedStories[0].signals.descriptionLength.flagged).toBe(true);
|
|
182
|
-
expect(result.flaggedStories[0].signals.descriptionLength.value).toBe(150);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
test("flags story when bullet point count exceeds threshold", async () => {
|
|
186
|
-
const config = createMockConfig({ storySizeGate: { enabled: true, maxAcCount: 6, maxDescriptionLength: 2000, maxBulletPoints: 5 } });
|
|
187
|
-
const description = `
|
|
188
|
-
Requirements:
|
|
189
|
-
- Item 1
|
|
190
|
-
- Item 2
|
|
191
|
-
- Item 3
|
|
192
|
-
- Item 4
|
|
193
|
-
- Item 5
|
|
194
|
-
- Item 6
|
|
195
|
-
- Item 7
|
|
196
|
-
`;
|
|
197
|
-
const story = createMockStory({
|
|
198
|
-
id: "US-003",
|
|
199
|
-
acceptanceCriteria: ["AC1"],
|
|
200
|
-
description,
|
|
201
|
-
});
|
|
202
|
-
const prd = createMockPRD([story]);
|
|
203
|
-
|
|
204
|
-
const result = await checkStorySizeGate(config, prd);
|
|
205
|
-
|
|
206
|
-
expect(result.check.passed).toBe(false);
|
|
207
|
-
expect(result.flaggedStories).toHaveLength(1);
|
|
208
|
-
expect(result.flaggedStories[0].signals.bulletPoints.flagged).toBe(true);
|
|
209
|
-
expect(result.flaggedStories[0].signals.bulletPoints.value).toBeGreaterThan(5);
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
test("flags multiple stories when multiple exceed thresholds", async () => {
|
|
213
|
-
const config = createMockConfig({ storySizeGate: { enabled: true, maxAcCount: 3, maxDescriptionLength: 50, maxBulletPoints: 5 } });
|
|
214
|
-
const story1 = createMockStory({
|
|
215
|
-
id: "US-001",
|
|
216
|
-
acceptanceCriteria: Array(5).fill("AC"),
|
|
217
|
-
});
|
|
218
|
-
const story2 = createMockStory({
|
|
219
|
-
id: "US-002",
|
|
220
|
-
description: "a".repeat(100),
|
|
221
|
-
});
|
|
222
|
-
const prd = createMockPRD([story1, story2]);
|
|
223
|
-
|
|
224
|
-
const result = await checkStorySizeGate(config, prd);
|
|
225
|
-
|
|
226
|
-
expect(result.check.passed).toBe(false);
|
|
227
|
-
expect(result.flaggedStories).toHaveLength(2);
|
|
228
|
-
expect(result.flaggedStories[0].storyId).toBe("US-001");
|
|
229
|
-
expect(result.flaggedStories[1].storyId).toBe("US-002");
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
test("only checks pending stories, ignores completed/failed/skipped", async () => {
|
|
233
|
-
const config = createMockConfig({ storySizeGate: { enabled: true, maxAcCount: 3, maxDescriptionLength: 2000, maxBulletPoints: 8 } });
|
|
234
|
-
const pendingStory = createMockStory({
|
|
235
|
-
id: "US-001",
|
|
236
|
-
status: "pending",
|
|
237
|
-
acceptanceCriteria: Array(5).fill("AC"),
|
|
238
|
-
});
|
|
239
|
-
const passedStory = createMockStory({
|
|
240
|
-
id: "US-002",
|
|
241
|
-
status: "passed",
|
|
242
|
-
acceptanceCriteria: Array(5).fill("AC"),
|
|
243
|
-
});
|
|
244
|
-
const failedStory = createMockStory({
|
|
245
|
-
id: "US-003",
|
|
246
|
-
status: "failed",
|
|
247
|
-
acceptanceCriteria: Array(5).fill("AC"),
|
|
248
|
-
});
|
|
249
|
-
const prd = createMockPRD([pendingStory, passedStory, failedStory]);
|
|
250
|
-
|
|
251
|
-
const result = await checkStorySizeGate(config, prd);
|
|
252
|
-
|
|
253
|
-
expect(result.check.passed).toBe(false);
|
|
254
|
-
expect(result.flaggedStories).toHaveLength(1);
|
|
255
|
-
expect(result.flaggedStories[0].storyId).toBe("US-001");
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
test("uses default thresholds when config is not provided", async () => {
|
|
259
|
-
const config = createMockConfig(undefined);
|
|
260
|
-
const story = createMockStory({
|
|
261
|
-
id: "US-001",
|
|
262
|
-
acceptanceCriteria: Array(10).fill("AC"),
|
|
263
|
-
});
|
|
264
|
-
const prd = createMockPRD([story]);
|
|
265
|
-
|
|
266
|
-
const result = await checkStorySizeGate(config, prd);
|
|
267
|
-
|
|
268
|
-
// Default threshold is 6, so 10 AC should be flagged
|
|
269
|
-
expect(result.check.passed).toBe(false);
|
|
270
|
-
expect(result.flaggedStories).toHaveLength(1);
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
test("includes recommendation message in flagged story", async () => {
|
|
274
|
-
const config = createMockConfig({ storySizeGate: { enabled: true, maxAcCount: 3, maxDescriptionLength: 2000, maxBulletPoints: 8 } });
|
|
275
|
-
const story = createMockStory({
|
|
276
|
-
id: "US-001",
|
|
277
|
-
acceptanceCriteria: Array(5).fill("AC"),
|
|
278
|
-
});
|
|
279
|
-
const prd = createMockPRD([story]);
|
|
280
|
-
|
|
281
|
-
const result = await checkStorySizeGate(config, prd);
|
|
282
|
-
|
|
283
|
-
expect(result.flaggedStories[0].recommendation).toContain("US-001");
|
|
284
|
-
expect(result.flaggedStories[0].recommendation).toContain("too large");
|
|
285
|
-
expect(result.flaggedStories[0].recommendation).toContain("5 AC");
|
|
286
|
-
expect(result.flaggedStories[0].recommendation).toContain("max 3");
|
|
287
|
-
});
|
|
288
|
-
});
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
// RE-ARCH: keep
|
|
2
|
-
/**
|
|
3
|
-
* Tests for src/precheck/types.ts
|
|
4
|
-
*
|
|
5
|
-
* Tests the precheck type definitions including PrecheckResult, CheckStatus, and CheckTier.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { describe, expect, test } from "bun:test";
|
|
9
|
-
import type { Check, CheckStatus, CheckTier, PrecheckResult } from "../../src/precheck/types";
|
|
10
|
-
|
|
11
|
-
describe("PrecheckResult type structure", () => {
|
|
12
|
-
test("PrecheckResult has blockers array", () => {
|
|
13
|
-
const result: PrecheckResult = {
|
|
14
|
-
blockers: [],
|
|
15
|
-
warnings: [],
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
expect(result.blockers).toBeDefined();
|
|
19
|
-
expect(Array.isArray(result.blockers)).toBe(true);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
test("PrecheckResult has warnings array", () => {
|
|
23
|
-
const result: PrecheckResult = {
|
|
24
|
-
blockers: [],
|
|
25
|
-
warnings: [],
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
expect(result.warnings).toBeDefined();
|
|
29
|
-
expect(Array.isArray(result.warnings)).toBe(true);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test("PrecheckResult can contain Check objects in blockers", () => {
|
|
33
|
-
const check: Check = {
|
|
34
|
-
name: "git-repo-exists",
|
|
35
|
-
tier: "blocker",
|
|
36
|
-
passed: false,
|
|
37
|
-
message: "Not a git repository",
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const result: PrecheckResult = {
|
|
41
|
-
blockers: [check],
|
|
42
|
-
warnings: [],
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
expect(result.blockers).toHaveLength(1);
|
|
46
|
-
expect(result.blockers[0].name).toBe("git-repo-exists");
|
|
47
|
-
expect(result.blockers[0].tier).toBe("blocker");
|
|
48
|
-
expect(result.blockers[0].passed).toBe(false);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test("PrecheckResult can contain Check objects in warnings", () => {
|
|
52
|
-
const check: Check = {
|
|
53
|
-
name: "claude-md-exists",
|
|
54
|
-
tier: "warning",
|
|
55
|
-
passed: false,
|
|
56
|
-
message: "CLAUDE.md not found",
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const result: PrecheckResult = {
|
|
60
|
-
blockers: [],
|
|
61
|
-
warnings: [check],
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
expect(result.warnings).toHaveLength(1);
|
|
65
|
-
expect(result.warnings[0].name).toBe("claude-md-exists");
|
|
66
|
-
expect(result.warnings[0].tier).toBe("warning");
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
describe("Check type structure", () => {
|
|
71
|
-
test("Check has required name field", () => {
|
|
72
|
-
const check: Check = {
|
|
73
|
-
name: "test-check",
|
|
74
|
-
tier: "blocker",
|
|
75
|
-
passed: true,
|
|
76
|
-
message: "Check passed",
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
expect(check.name).toBe("test-check");
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
test("Check has required tier field", () => {
|
|
83
|
-
const check: Check = {
|
|
84
|
-
name: "test-check",
|
|
85
|
-
tier: "blocker",
|
|
86
|
-
passed: true,
|
|
87
|
-
message: "Check passed",
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
expect(check.tier).toBe("blocker");
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
test("Check has required passed field", () => {
|
|
94
|
-
const check: Check = {
|
|
95
|
-
name: "test-check",
|
|
96
|
-
tier: "blocker",
|
|
97
|
-
passed: false,
|
|
98
|
-
message: "Check failed",
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
expect(check.passed).toBe(false);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
test("Check has required message field", () => {
|
|
105
|
-
const check: Check = {
|
|
106
|
-
name: "test-check",
|
|
107
|
-
tier: "blocker",
|
|
108
|
-
passed: true,
|
|
109
|
-
message: "All good",
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
expect(check.message).toBe("All good");
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
describe("CheckTier type values", () => {
|
|
117
|
-
test("CheckTier accepts blocker value", () => {
|
|
118
|
-
const tier: CheckTier = "blocker";
|
|
119
|
-
expect(tier).toBe("blocker");
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
test("CheckTier accepts warning value", () => {
|
|
123
|
-
const tier: CheckTier = "warning";
|
|
124
|
-
expect(tier).toBe("warning");
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
describe("CheckStatus type values", () => {
|
|
129
|
-
test("CheckStatus accepts passed value", () => {
|
|
130
|
-
const status: CheckStatus = "passed";
|
|
131
|
-
expect(status).toBe("passed");
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
test("CheckStatus accepts failed value", () => {
|
|
135
|
-
const status: CheckStatus = "failed";
|
|
136
|
-
expect(status).toBe("failed");
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
test("CheckStatus accepts skipped value", () => {
|
|
140
|
-
const status: CheckStatus = "skipped";
|
|
141
|
-
expect(status).toBe("skipped");
|
|
142
|
-
});
|
|
143
|
-
});
|
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PromptBuilder unit tests — PB-001
|
|
3
|
-
*
|
|
4
|
-
* Tests verify section ordering, non-overridable sections, and override fallthrough.
|
|
5
|
-
* All tests are expected to FAIL until PromptBuilder is implemented.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { describe, expect, test } from "bun:test";
|
|
9
|
-
import { mkdtempSync, writeFileSync } from "node:fs";
|
|
10
|
-
import { tmpdir } from "node:os";
|
|
11
|
-
import { join } from "node:path";
|
|
12
|
-
import type { UserStory } from "../../../src/prd";
|
|
13
|
-
import { PromptBuilder } from "../../../src/prompts/builder";
|
|
14
|
-
import type { PromptRole } from "../../../src/prompts/types";
|
|
15
|
-
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
// Fixtures
|
|
18
|
-
// ---------------------------------------------------------------------------
|
|
19
|
-
|
|
20
|
-
function makeStory(overrides: Partial<UserStory> = {}): UserStory {
|
|
21
|
-
return {
|
|
22
|
-
id: "US-001",
|
|
23
|
-
title: "Example story",
|
|
24
|
-
description: "Do the thing",
|
|
25
|
-
acceptanceCriteria: ["Criterion 1", "Criterion 2"],
|
|
26
|
-
tags: [],
|
|
27
|
-
dependencies: [],
|
|
28
|
-
status: "pending",
|
|
29
|
-
passes: false,
|
|
30
|
-
escalations: [],
|
|
31
|
-
...overrides,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const ROLES: PromptRole[] = ["test-writer", "implementer", "verifier", "single-session"];
|
|
36
|
-
|
|
37
|
-
// ---------------------------------------------------------------------------
|
|
38
|
-
// 1. Fluent API — builder returns itself for chaining
|
|
39
|
-
// ---------------------------------------------------------------------------
|
|
40
|
-
|
|
41
|
-
describe("PromptBuilder fluent API", () => {
|
|
42
|
-
test("PromptBuilder.for() returns a PromptBuilder instance", () => {
|
|
43
|
-
const builder = PromptBuilder.for("test-writer");
|
|
44
|
-
expect(builder).toBeInstanceOf(PromptBuilder);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test(".story() is chainable", () => {
|
|
48
|
-
const builder = PromptBuilder.for("implementer").story(makeStory());
|
|
49
|
-
expect(builder).toBeInstanceOf(PromptBuilder);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test(".context() is chainable", () => {
|
|
53
|
-
const builder = PromptBuilder.for("verifier").story(makeStory()).context("# Context");
|
|
54
|
-
expect(builder).toBeInstanceOf(PromptBuilder);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test(".constitution() is chainable", () => {
|
|
58
|
-
const builder = PromptBuilder.for("single-session").story(makeStory()).constitution("Be helpful.");
|
|
59
|
-
expect(builder).toBeInstanceOf(PromptBuilder);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test(".override() is chainable", () => {
|
|
63
|
-
const builder = PromptBuilder.for("test-writer").story(makeStory()).override("/tmp/override.md");
|
|
64
|
-
expect(builder).toBeInstanceOf(PromptBuilder);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test(".build() returns a Promise<string>", async () => {
|
|
68
|
-
const result = PromptBuilder.for("test-writer").story(makeStory()).build();
|
|
69
|
-
expect(result).toBeInstanceOf(Promise);
|
|
70
|
-
const text = await result;
|
|
71
|
-
expect(typeof text).toBe("string");
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// ---------------------------------------------------------------------------
|
|
76
|
-
// 2. Section ordering
|
|
77
|
-
// ---------------------------------------------------------------------------
|
|
78
|
-
|
|
79
|
-
describe("PromptBuilder section order", () => {
|
|
80
|
-
test("constitution appears before role task", async () => {
|
|
81
|
-
const prompt = await PromptBuilder.for("test-writer")
|
|
82
|
-
.story(makeStory())
|
|
83
|
-
.constitution("CONSTITUTION_MARKER")
|
|
84
|
-
.build();
|
|
85
|
-
|
|
86
|
-
const constitutionIdx = prompt.indexOf("CONSTITUTION_MARKER");
|
|
87
|
-
const roleTaskIdx = prompt.indexOf("YOUR TASK") !== -1 ? prompt.indexOf("YOUR TASK") : prompt.indexOf("Your role");
|
|
88
|
-
|
|
89
|
-
expect(constitutionIdx).toBeGreaterThanOrEqual(0);
|
|
90
|
-
expect(roleTaskIdx).toBeGreaterThanOrEqual(0);
|
|
91
|
-
expect(constitutionIdx).toBeLessThan(roleTaskIdx);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test("story context appears before conventions footer", async () => {
|
|
95
|
-
const story = makeStory({ title: "STORY_TITLE_MARKER" });
|
|
96
|
-
const prompt = await PromptBuilder.for("implementer").story(story).build();
|
|
97
|
-
|
|
98
|
-
const storyIdx = prompt.indexOf("STORY_TITLE_MARKER");
|
|
99
|
-
// Conventions footer is always last — it contains "conventions" or appears after story
|
|
100
|
-
const footerIdx = prompt.lastIndexOf("conventions") !== -1 ? prompt.lastIndexOf("conventions") : prompt.length - 1;
|
|
101
|
-
|
|
102
|
-
expect(storyIdx).toBeGreaterThanOrEqual(0);
|
|
103
|
-
expect(storyIdx).toBeLessThan(footerIdx);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test("isolation rules appear after role task body", async () => {
|
|
107
|
-
const prompt = await PromptBuilder.for("test-writer").story(makeStory()).build();
|
|
108
|
-
|
|
109
|
-
// Isolation rules section — comes after the main role task body
|
|
110
|
-
const isolationIdx = prompt.indexOf("isolation") !== -1 ? prompt.indexOf("isolation") : prompt.indexOf("ISOLATION");
|
|
111
|
-
|
|
112
|
-
expect(isolationIdx).toBeGreaterThanOrEqual(0);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test("context markdown appears before conventions footer", async () => {
|
|
116
|
-
const ctxMarker = "CONTEXT_MARKDOWN_MARKER";
|
|
117
|
-
const prompt = await PromptBuilder.for("verifier").story(makeStory()).context(ctxMarker).build();
|
|
118
|
-
|
|
119
|
-
const ctxIdx = prompt.indexOf(ctxMarker);
|
|
120
|
-
const footerIdx = prompt.lastIndexOf("conventions") !== -1 ? prompt.lastIndexOf("conventions") : prompt.length;
|
|
121
|
-
|
|
122
|
-
expect(ctxIdx).toBeGreaterThanOrEqual(0);
|
|
123
|
-
expect(ctxIdx).toBeLessThan(footerIdx);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
describe("section order for each role", () => {
|
|
127
|
-
for (const role of ROLES) {
|
|
128
|
-
test(`role ${role}: constitution → role task → story context → isolation rules → context md → conventions footer`, async () => {
|
|
129
|
-
const story = makeStory({ title: `STORY_${role.toUpperCase()}` });
|
|
130
|
-
const ctxMd = `CTXMD_${role.toUpperCase()}`;
|
|
131
|
-
const prompt = await PromptBuilder.for(role)
|
|
132
|
-
.story(story)
|
|
133
|
-
.constitution("CONSTITUTION_BLOCK")
|
|
134
|
-
.context(ctxMd)
|
|
135
|
-
.build();
|
|
136
|
-
|
|
137
|
-
const constitutionIdx = prompt.indexOf("CONSTITUTION_BLOCK");
|
|
138
|
-
const storyIdx = prompt.indexOf(`STORY_${role.toUpperCase()}`);
|
|
139
|
-
const ctxIdx = prompt.indexOf(ctxMd);
|
|
140
|
-
|
|
141
|
-
// All markers present
|
|
142
|
-
expect(constitutionIdx).toBeGreaterThanOrEqual(0);
|
|
143
|
-
expect(storyIdx).toBeGreaterThanOrEqual(0);
|
|
144
|
-
expect(ctxIdx).toBeGreaterThanOrEqual(0);
|
|
145
|
-
|
|
146
|
-
// Ordering: constitution < story < ctx
|
|
147
|
-
expect(constitutionIdx).toBeLessThan(storyIdx);
|
|
148
|
-
expect(storyIdx).toBeLessThan(ctxIdx);
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
// ---------------------------------------------------------------------------
|
|
155
|
-
// 3. Non-overridable sections always present
|
|
156
|
-
// ---------------------------------------------------------------------------
|
|
157
|
-
|
|
158
|
-
describe("PromptBuilder non-overridable sections", () => {
|
|
159
|
-
test("story context always included even when override is set", async () => {
|
|
160
|
-
const tmpDir = mkdtempSync(join(tmpdir(), "nax-pb-test-"));
|
|
161
|
-
const overridePath = join(tmpDir, "override.md");
|
|
162
|
-
writeFileSync(overridePath, "# Custom override body\nThis replaces the template.");
|
|
163
|
-
|
|
164
|
-
const story = makeStory({ title: "NON_OVERRIDABLE_STORY" });
|
|
165
|
-
const prompt = await PromptBuilder.for("test-writer").story(story).override(overridePath).build();
|
|
166
|
-
|
|
167
|
-
expect(prompt).toContain("NON_OVERRIDABLE_STORY");
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
test("conventions footer always last even when override is set", async () => {
|
|
171
|
-
const tmpDir = mkdtempSync(join(tmpdir(), "nax-pb-test-"));
|
|
172
|
-
const overridePath = join(tmpDir, "override.md");
|
|
173
|
-
writeFileSync(overridePath, "# Custom override body");
|
|
174
|
-
|
|
175
|
-
const prompt = await PromptBuilder.for("implementer").story(makeStory()).override(overridePath).build();
|
|
176
|
-
|
|
177
|
-
// Conventions footer must exist and be after the override content
|
|
178
|
-
const overrideIdx = prompt.indexOf("Custom override body");
|
|
179
|
-
const conventionsIdx = prompt.lastIndexOf("conventions");
|
|
180
|
-
expect(conventionsIdx).toBeGreaterThan(overrideIdx);
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
test("isolation rules always present even when override is set", async () => {
|
|
184
|
-
const tmpDir = mkdtempSync(join(tmpdir(), "nax-pb-test-"));
|
|
185
|
-
const overridePath = join(tmpDir, "override.md");
|
|
186
|
-
writeFileSync(overridePath, "# My custom template");
|
|
187
|
-
|
|
188
|
-
const prompt = await PromptBuilder.for("test-writer").story(makeStory()).override(overridePath).build();
|
|
189
|
-
|
|
190
|
-
// Isolation rules must appear somewhere in the final prompt
|
|
191
|
-
const lowerPrompt = prompt.toLowerCase();
|
|
192
|
-
const hasIsolation = lowerPrompt.includes("isolation") || lowerPrompt.includes("isolat");
|
|
193
|
-
expect(hasIsolation).toBe(true);
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
test("story context not removable via override for each role", async () => {
|
|
197
|
-
const tmpDir = mkdtempSync(join(tmpdir(), "nax-pb-test-"));
|
|
198
|
-
const overridePath = join(tmpDir, "override.md");
|
|
199
|
-
writeFileSync(overridePath, "Override that attempts to hide story context.");
|
|
200
|
-
|
|
201
|
-
for (const role of ROLES) {
|
|
202
|
-
const story = makeStory({ title: `ROLE_${role}_TITLE` });
|
|
203
|
-
const prompt = await PromptBuilder.for(role).story(story).override(overridePath).build();
|
|
204
|
-
expect(prompt).toContain(`ROLE_${role}_TITLE`);
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
// ---------------------------------------------------------------------------
|
|
210
|
-
// 4. Override fallthrough to default template
|
|
211
|
-
// ---------------------------------------------------------------------------
|
|
212
|
-
|
|
213
|
-
describe("PromptBuilder override fallthrough", () => {
|
|
214
|
-
test("missing override file falls through to default template", async () => {
|
|
215
|
-
const prompt = await PromptBuilder.for("test-writer")
|
|
216
|
-
.story(makeStory({ title: "FALLTHROUGH_STORY" }))
|
|
217
|
-
.override("/nonexistent/path/override.md")
|
|
218
|
-
.build();
|
|
219
|
-
|
|
220
|
-
// Should still contain story context (non-overridable)
|
|
221
|
-
expect(prompt).toContain("FALLTHROUGH_STORY");
|
|
222
|
-
// Should contain default role task content (not crash)
|
|
223
|
-
expect(typeof prompt).toBe("string");
|
|
224
|
-
expect(prompt.length).toBeGreaterThan(0);
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
test("no override set uses default template body", async () => {
|
|
228
|
-
const promptWithout = await PromptBuilder.for("test-writer")
|
|
229
|
-
.story(makeStory({ title: "DEFAULT_TEMPLATE_STORY" }))
|
|
230
|
-
.build();
|
|
231
|
-
|
|
232
|
-
expect(promptWithout).toContain("DEFAULT_TEMPLATE_STORY");
|
|
233
|
-
expect(promptWithout.length).toBeGreaterThan(0);
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
test("valid override file replaces default template body", async () => {
|
|
237
|
-
const tmpDir = mkdtempSync(join(tmpdir(), "nax-pb-test-"));
|
|
238
|
-
const overridePath = join(tmpDir, "override.md");
|
|
239
|
-
const overrideBody = "UNIQUE_OVERRIDE_BODY_CONTENT";
|
|
240
|
-
writeFileSync(overridePath, overrideBody);
|
|
241
|
-
|
|
242
|
-
const prompt = await PromptBuilder.for("implementer").story(makeStory()).override(overridePath).build();
|
|
243
|
-
|
|
244
|
-
expect(prompt).toContain(overrideBody);
|
|
245
|
-
});
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
// ---------------------------------------------------------------------------
|
|
249
|
-
// 5. Types exported correctly
|
|
250
|
-
// ---------------------------------------------------------------------------
|
|
251
|
-
|
|
252
|
-
describe("src/prompts/types exports", () => {
|
|
253
|
-
test("PromptRole values are correct literals", () => {
|
|
254
|
-
// This is a compile-time check — if types.ts exports correctly, import works
|
|
255
|
-
const roles: PromptRole[] = ["test-writer", "implementer", "verifier", "single-session"];
|
|
256
|
-
expect(roles).toHaveLength(4);
|
|
257
|
-
});
|
|
258
|
-
});
|