@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,218 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
-
import { execSync } from "node:child_process";
|
|
3
|
-
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
import { WorktreeManager } from "../../../src/worktree/manager";
|
|
7
|
-
|
|
8
|
-
describe("WorktreeManager", () => {
|
|
9
|
-
let testDir: string;
|
|
10
|
-
let projectRoot: string;
|
|
11
|
-
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
// Create a temporary directory for each test
|
|
14
|
-
testDir = mkdtempSync(join(tmpdir(), "worktree-test-"));
|
|
15
|
-
projectRoot = join(testDir, "test-project");
|
|
16
|
-
mkdirSync(projectRoot, { recursive: true });
|
|
17
|
-
|
|
18
|
-
// Initialize a git repository
|
|
19
|
-
execSync("git init", { cwd: projectRoot, stdio: "pipe" });
|
|
20
|
-
execSync('git config user.email "test@example.com"', {
|
|
21
|
-
cwd: projectRoot,
|
|
22
|
-
stdio: "pipe",
|
|
23
|
-
});
|
|
24
|
-
execSync('git config user.name "Test User"', {
|
|
25
|
-
cwd: projectRoot,
|
|
26
|
-
stdio: "pipe",
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// Create an initial commit (required for worktree creation)
|
|
30
|
-
writeFileSync(join(projectRoot, "README.md"), "# Test Project");
|
|
31
|
-
execSync("git add README.md", { cwd: projectRoot, stdio: "pipe" });
|
|
32
|
-
execSync('git commit -m "Initial commit"', {
|
|
33
|
-
cwd: projectRoot,
|
|
34
|
-
stdio: "pipe",
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
afterEach(() => {
|
|
39
|
-
// Clean up test directory
|
|
40
|
-
if (existsSync(testDir)) {
|
|
41
|
-
rmSync(testDir, { recursive: true, force: true });
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
describe("create", () => {
|
|
46
|
-
test("creates a git worktree at .nax-wt/<storyId>/ with branch nax/<storyId>", async () => {
|
|
47
|
-
const manager = new WorktreeManager();
|
|
48
|
-
const storyId = "story-123";
|
|
49
|
-
|
|
50
|
-
await manager.create(projectRoot, storyId);
|
|
51
|
-
|
|
52
|
-
const worktreePath = join(projectRoot, ".nax-wt", storyId);
|
|
53
|
-
expect(existsSync(worktreePath)).toBe(true);
|
|
54
|
-
|
|
55
|
-
// Verify branch exists
|
|
56
|
-
const branches = execSync("git branch --list", {
|
|
57
|
-
cwd: projectRoot,
|
|
58
|
-
encoding: "utf-8",
|
|
59
|
-
});
|
|
60
|
-
expect(branches).toContain(`nax/${storyId}`);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test("symlinks node_modules from project root into worktree", async () => {
|
|
64
|
-
const manager = new WorktreeManager();
|
|
65
|
-
const storyId = "story-456";
|
|
66
|
-
|
|
67
|
-
// Create node_modules in project root
|
|
68
|
-
const nodeModulesPath = join(projectRoot, "node_modules");
|
|
69
|
-
mkdirSync(nodeModulesPath, { recursive: true });
|
|
70
|
-
writeFileSync(join(nodeModulesPath, "test.txt"), "test content");
|
|
71
|
-
|
|
72
|
-
await manager.create(projectRoot, storyId);
|
|
73
|
-
|
|
74
|
-
const worktreePath = join(projectRoot, ".nax-wt", storyId);
|
|
75
|
-
const symlinkPath = join(worktreePath, "node_modules");
|
|
76
|
-
|
|
77
|
-
expect(existsSync(symlinkPath)).toBe(true);
|
|
78
|
-
// Check if it's a symlink by reading the link
|
|
79
|
-
const { lstatSync, readlinkSync } = await import("node:fs");
|
|
80
|
-
expect(lstatSync(symlinkPath).isSymbolicLink()).toBe(true);
|
|
81
|
-
expect(readlinkSync(symlinkPath)).toBe(nodeModulesPath);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test("symlinks .env if present", async () => {
|
|
85
|
-
const manager = new WorktreeManager();
|
|
86
|
-
const storyId = "story-789";
|
|
87
|
-
|
|
88
|
-
// Create .env in project root
|
|
89
|
-
const envPath = join(projectRoot, ".env");
|
|
90
|
-
writeFileSync(envPath, "TEST_VAR=value");
|
|
91
|
-
|
|
92
|
-
await manager.create(projectRoot, storyId);
|
|
93
|
-
|
|
94
|
-
const worktreePath = join(projectRoot, ".nax-wt", storyId);
|
|
95
|
-
const symlinkPath = join(worktreePath, ".env");
|
|
96
|
-
|
|
97
|
-
expect(existsSync(symlinkPath)).toBe(true);
|
|
98
|
-
// Check if it's a symlink
|
|
99
|
-
const { lstatSync, readlinkSync } = await import("node:fs");
|
|
100
|
-
expect(lstatSync(symlinkPath).isSymbolicLink()).toBe(true);
|
|
101
|
-
expect(readlinkSync(symlinkPath)).toBe(envPath);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
test("does not fail if .env is not present", async () => {
|
|
105
|
-
const manager = new WorktreeManager();
|
|
106
|
-
const storyId = "story-no-env";
|
|
107
|
-
|
|
108
|
-
await manager.create(projectRoot, storyId);
|
|
109
|
-
|
|
110
|
-
const worktreePath = join(projectRoot, ".nax-wt", storyId);
|
|
111
|
-
expect(existsSync(worktreePath)).toBe(true);
|
|
112
|
-
|
|
113
|
-
const symlinkPath = join(worktreePath, ".env");
|
|
114
|
-
expect(existsSync(symlinkPath)).toBe(false);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
test("throws descriptive error when not in git repo", async () => {
|
|
118
|
-
const manager = new WorktreeManager();
|
|
119
|
-
const nonGitDir = join(testDir, "non-git");
|
|
120
|
-
mkdirSync(nonGitDir, { recursive: true });
|
|
121
|
-
|
|
122
|
-
await expect(manager.create(nonGitDir, "story-fail")).rejects.toThrow(
|
|
123
|
-
/not a git repository|fatal: not a git repository/i,
|
|
124
|
-
);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test("throws descriptive error when worktree already exists", async () => {
|
|
128
|
-
const manager = new WorktreeManager();
|
|
129
|
-
const storyId = "story-duplicate";
|
|
130
|
-
|
|
131
|
-
await manager.create(projectRoot, storyId);
|
|
132
|
-
|
|
133
|
-
// Try to create the same worktree again
|
|
134
|
-
await expect(manager.create(projectRoot, storyId)).rejects.toThrow(/already exists|worktree.*exists/i);
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
describe("remove", () => {
|
|
139
|
-
test("cleans up worktree and branch", async () => {
|
|
140
|
-
const manager = new WorktreeManager();
|
|
141
|
-
const storyId = "story-remove";
|
|
142
|
-
|
|
143
|
-
// Create worktree first
|
|
144
|
-
await manager.create(projectRoot, storyId);
|
|
145
|
-
|
|
146
|
-
const worktreePath = join(projectRoot, ".nax-wt", storyId);
|
|
147
|
-
expect(existsSync(worktreePath)).toBe(true);
|
|
148
|
-
|
|
149
|
-
// Remove it
|
|
150
|
-
await manager.remove(projectRoot, storyId);
|
|
151
|
-
|
|
152
|
-
// Verify worktree is removed
|
|
153
|
-
expect(existsSync(worktreePath)).toBe(false);
|
|
154
|
-
|
|
155
|
-
// Verify branch is deleted
|
|
156
|
-
const branches = execSync("git branch --list", {
|
|
157
|
-
cwd: projectRoot,
|
|
158
|
-
encoding: "utf-8",
|
|
159
|
-
});
|
|
160
|
-
expect(branches).not.toContain(`nax/${storyId}`);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
test("throws descriptive error when worktree does not exist", async () => {
|
|
164
|
-
const manager = new WorktreeManager();
|
|
165
|
-
const storyId = "nonexistent-story";
|
|
166
|
-
|
|
167
|
-
await expect(manager.remove(projectRoot, storyId)).rejects.toThrow(
|
|
168
|
-
/not found|does not exist|no such worktree|worktree not found/i,
|
|
169
|
-
);
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
describe("list", () => {
|
|
174
|
-
test("returns active worktree entries", async () => {
|
|
175
|
-
const manager = new WorktreeManager();
|
|
176
|
-
const storyId1 = "story-list-1";
|
|
177
|
-
const storyId2 = "story-list-2";
|
|
178
|
-
|
|
179
|
-
// Create two worktrees
|
|
180
|
-
await manager.create(projectRoot, storyId1);
|
|
181
|
-
await manager.create(projectRoot, storyId2);
|
|
182
|
-
|
|
183
|
-
const worktrees = await manager.list(projectRoot);
|
|
184
|
-
|
|
185
|
-
// Should have at least our two worktrees (main worktree + 2 created)
|
|
186
|
-
expect(worktrees.length).toBeGreaterThanOrEqual(2);
|
|
187
|
-
|
|
188
|
-
// Check if our worktrees are in the list
|
|
189
|
-
const paths = worktrees.map((wt) => wt.path);
|
|
190
|
-
expect(paths.some((p) => p.includes(join(".nax-wt", storyId1)))).toBe(true);
|
|
191
|
-
expect(paths.some((p) => p.includes(join(".nax-wt", storyId2)))).toBe(true);
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
test("returns empty array when no worktrees exist (except main)", async () => {
|
|
195
|
-
const manager = new WorktreeManager();
|
|
196
|
-
|
|
197
|
-
const worktrees = await manager.list(projectRoot);
|
|
198
|
-
|
|
199
|
-
// Should only have the main worktree
|
|
200
|
-
expect(worktrees.length).toBeGreaterThanOrEqual(0);
|
|
201
|
-
expect(worktrees.every((wt) => !wt.path.includes(".nax-wt"))).toBe(true);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
test("each entry contains path and branch info", async () => {
|
|
205
|
-
const manager = new WorktreeManager();
|
|
206
|
-
const storyId = "story-info";
|
|
207
|
-
|
|
208
|
-
await manager.create(projectRoot, storyId);
|
|
209
|
-
|
|
210
|
-
const worktrees = await manager.list(projectRoot);
|
|
211
|
-
const ourWorktree = worktrees.find((wt) => wt.path.includes(join(".nax-wt", storyId)));
|
|
212
|
-
|
|
213
|
-
expect(ourWorktree).toBeDefined();
|
|
214
|
-
expect(ourWorktree?.path).toBeTruthy();
|
|
215
|
-
expect(ourWorktree?.branch).toBe(`nax/${storyId}`);
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
});
|
|
@@ -1,341 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
-
import { execSync } from "node:child_process";
|
|
3
|
-
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
import { WorktreeManager } from "../../../src/worktree/manager";
|
|
7
|
-
import { MergeEngine } from "../../../src/worktree/merge";
|
|
8
|
-
|
|
9
|
-
describe("MergeEngine", () => {
|
|
10
|
-
let testDir: string;
|
|
11
|
-
let projectRoot: string;
|
|
12
|
-
let manager: WorktreeManager;
|
|
13
|
-
let engine: MergeEngine;
|
|
14
|
-
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
// Create a temporary directory for each test
|
|
17
|
-
testDir = mkdtempSync(join(tmpdir(), "merge-test-"));
|
|
18
|
-
projectRoot = join(testDir, "test-project");
|
|
19
|
-
mkdirSync(projectRoot, { recursive: true });
|
|
20
|
-
|
|
21
|
-
// Initialize a git repository
|
|
22
|
-
execSync("git init", { cwd: projectRoot, stdio: "pipe" });
|
|
23
|
-
execSync('git config user.email "test@example.com"', {
|
|
24
|
-
cwd: projectRoot,
|
|
25
|
-
stdio: "pipe",
|
|
26
|
-
});
|
|
27
|
-
execSync('git config user.name "Test User"', {
|
|
28
|
-
cwd: projectRoot,
|
|
29
|
-
stdio: "pipe",
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
// Create an initial commit (required for worktree creation)
|
|
33
|
-
writeFileSync(join(projectRoot, "README.md"), "# Test Project");
|
|
34
|
-
execSync("git add README.md", { cwd: projectRoot, stdio: "pipe" });
|
|
35
|
-
execSync('git commit -m "Initial commit"', {
|
|
36
|
-
cwd: projectRoot,
|
|
37
|
-
stdio: "pipe",
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
manager = new WorktreeManager();
|
|
41
|
-
engine = new MergeEngine(manager);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
afterEach(() => {
|
|
45
|
-
// Clean up test directory
|
|
46
|
-
if (existsSync(testDir)) {
|
|
47
|
-
rmSync(testDir, { recursive: true, force: true });
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
describe("merge", () => {
|
|
52
|
-
test("performs git merge --no-ff of story branch", async () => {
|
|
53
|
-
const storyId = "story-merge-1";
|
|
54
|
-
|
|
55
|
-
// Create worktree and make a change
|
|
56
|
-
await manager.create(projectRoot, storyId);
|
|
57
|
-
const worktreePath = join(projectRoot, ".nax-wt", storyId);
|
|
58
|
-
writeFileSync(join(worktreePath, "feature.txt"), "feature content");
|
|
59
|
-
execSync("git add feature.txt", {
|
|
60
|
-
cwd: worktreePath,
|
|
61
|
-
stdio: "pipe",
|
|
62
|
-
});
|
|
63
|
-
execSync('git commit -m "Add feature"', {
|
|
64
|
-
cwd: worktreePath,
|
|
65
|
-
stdio: "pipe",
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// Merge the branch
|
|
69
|
-
const result = await engine.merge(projectRoot, storyId);
|
|
70
|
-
|
|
71
|
-
expect(result.success).toBe(true);
|
|
72
|
-
expect(result.conflictFiles).toBeUndefined();
|
|
73
|
-
|
|
74
|
-
// Verify merge commit exists
|
|
75
|
-
const log = execSync("git log --oneline --graph", {
|
|
76
|
-
cwd: projectRoot,
|
|
77
|
-
encoding: "utf-8",
|
|
78
|
-
});
|
|
79
|
-
expect(log).toContain(`Merge branch 'nax/${storyId}'`);
|
|
80
|
-
|
|
81
|
-
// Verify feature file exists in main branch
|
|
82
|
-
expect(existsSync(join(projectRoot, "feature.txt"))).toBe(true);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test("returns { success: true } on clean merge", async () => {
|
|
86
|
-
const storyId = "story-clean";
|
|
87
|
-
|
|
88
|
-
// Create worktree and make a non-conflicting change
|
|
89
|
-
await manager.create(projectRoot, storyId);
|
|
90
|
-
const worktreePath = join(projectRoot, ".nax-wt", storyId);
|
|
91
|
-
writeFileSync(join(worktreePath, "new-file.txt"), "new content");
|
|
92
|
-
execSync("git add new-file.txt", {
|
|
93
|
-
cwd: worktreePath,
|
|
94
|
-
stdio: "pipe",
|
|
95
|
-
});
|
|
96
|
-
execSync('git commit -m "Add new file"', {
|
|
97
|
-
cwd: worktreePath,
|
|
98
|
-
stdio: "pipe",
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
const result = await engine.merge(projectRoot, storyId);
|
|
102
|
-
|
|
103
|
-
expect(result.success).toBe(true);
|
|
104
|
-
expect(result.conflictFiles).toBeUndefined();
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test("returns { success: false, conflictFiles: [...] } on conflict", async () => {
|
|
108
|
-
const storyId = "story-conflict";
|
|
109
|
-
|
|
110
|
-
// Create worktree
|
|
111
|
-
await manager.create(projectRoot, storyId);
|
|
112
|
-
const worktreePath = join(projectRoot, ".nax-wt", storyId);
|
|
113
|
-
|
|
114
|
-
// Make conflicting changes in both branches
|
|
115
|
-
// Change in main branch
|
|
116
|
-
writeFileSync(join(projectRoot, "conflict.txt"), "main content");
|
|
117
|
-
execSync("git add conflict.txt", {
|
|
118
|
-
cwd: projectRoot,
|
|
119
|
-
stdio: "pipe",
|
|
120
|
-
});
|
|
121
|
-
execSync('git commit -m "Add conflict file in main"', {
|
|
122
|
-
cwd: projectRoot,
|
|
123
|
-
stdio: "pipe",
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// Change in story branch (same file, different content)
|
|
127
|
-
writeFileSync(join(worktreePath, "conflict.txt"), "story content");
|
|
128
|
-
execSync("git add conflict.txt", {
|
|
129
|
-
cwd: worktreePath,
|
|
130
|
-
stdio: "pipe",
|
|
131
|
-
});
|
|
132
|
-
execSync('git commit -m "Add conflict file in story"', {
|
|
133
|
-
cwd: worktreePath,
|
|
134
|
-
stdio: "pipe",
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
const result = await engine.merge(projectRoot, storyId);
|
|
138
|
-
|
|
139
|
-
expect(result.success).toBe(false);
|
|
140
|
-
expect(result.conflictFiles).toBeDefined();
|
|
141
|
-
expect(result.conflictFiles?.length).toBeGreaterThan(0);
|
|
142
|
-
expect(result.conflictFiles).toContain("conflict.txt");
|
|
143
|
-
|
|
144
|
-
// Verify merge was aborted (working tree should be clean except for .nax-wt)
|
|
145
|
-
const status = execSync("git status --short", {
|
|
146
|
-
cwd: projectRoot,
|
|
147
|
-
encoding: "utf-8",
|
|
148
|
-
});
|
|
149
|
-
const nonWorktreeStatus = status
|
|
150
|
-
.split("\n")
|
|
151
|
-
.filter((line) => !line.includes(".nax-wt"))
|
|
152
|
-
.join("\n")
|
|
153
|
-
.trim();
|
|
154
|
-
expect(nonWorktreeStatus).toBe(""); // Clean working tree after abort
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
test("cleans up worktree after successful merge", async () => {
|
|
158
|
-
const storyId = "story-cleanup";
|
|
159
|
-
|
|
160
|
-
// Create worktree and make a change
|
|
161
|
-
await manager.create(projectRoot, storyId);
|
|
162
|
-
const worktreePath = join(projectRoot, ".nax-wt", storyId);
|
|
163
|
-
writeFileSync(join(worktreePath, "cleanup.txt"), "cleanup test");
|
|
164
|
-
execSync("git add cleanup.txt", {
|
|
165
|
-
cwd: worktreePath,
|
|
166
|
-
stdio: "pipe",
|
|
167
|
-
});
|
|
168
|
-
execSync('git commit -m "Add cleanup test"', {
|
|
169
|
-
cwd: worktreePath,
|
|
170
|
-
stdio: "pipe",
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
// Merge and verify cleanup
|
|
174
|
-
await engine.merge(projectRoot, storyId);
|
|
175
|
-
|
|
176
|
-
// Worktree should be removed
|
|
177
|
-
expect(existsSync(worktreePath)).toBe(false);
|
|
178
|
-
|
|
179
|
-
// Branch should be deleted
|
|
180
|
-
const branches = execSync("git branch --list", {
|
|
181
|
-
cwd: projectRoot,
|
|
182
|
-
encoding: "utf-8",
|
|
183
|
-
});
|
|
184
|
-
expect(branches).not.toContain(`nax/${storyId}`);
|
|
185
|
-
});
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
describe("mergeAll", () => {
|
|
189
|
-
test("processes stories in topological order", async () => {
|
|
190
|
-
// Create three stories with dependencies: story-1 <- story-2 <- story-3
|
|
191
|
-
const storyIds = ["story-1", "story-2", "story-3"];
|
|
192
|
-
const dependencies = {
|
|
193
|
-
"story-1": [],
|
|
194
|
-
"story-2": ["story-1"],
|
|
195
|
-
"story-3": ["story-2"],
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
// Create worktrees and commits for each story
|
|
199
|
-
for (const storyId of storyIds) {
|
|
200
|
-
await manager.create(projectRoot, storyId);
|
|
201
|
-
const worktreePath = join(projectRoot, ".nax-wt", storyId);
|
|
202
|
-
writeFileSync(join(worktreePath, `${storyId}.txt`), `${storyId} content`);
|
|
203
|
-
execSync(`git add ${storyId}.txt`, {
|
|
204
|
-
cwd: worktreePath,
|
|
205
|
-
stdio: "pipe",
|
|
206
|
-
});
|
|
207
|
-
execSync(`git commit -m "Add ${storyId}"`, {
|
|
208
|
-
cwd: worktreePath,
|
|
209
|
-
stdio: "pipe",
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const results = await engine.mergeAll(projectRoot, storyIds, dependencies);
|
|
214
|
-
|
|
215
|
-
// All should succeed
|
|
216
|
-
expect(results.every((r) => r.success)).toBe(true);
|
|
217
|
-
expect(results.length).toBe(3);
|
|
218
|
-
|
|
219
|
-
// Verify all files exist
|
|
220
|
-
for (const storyId of storyIds) {
|
|
221
|
-
expect(existsSync(join(projectRoot, `${storyId}.txt`))).toBe(true);
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
test("retries once on conflict after rebasing worktree", async () => {
|
|
226
|
-
const storyIds = ["story-base", "story-conflict"];
|
|
227
|
-
const dependencies = {
|
|
228
|
-
"story-base": [],
|
|
229
|
-
"story-conflict": [],
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
// Create base story
|
|
233
|
-
await manager.create(projectRoot, "story-base");
|
|
234
|
-
const basePath = join(projectRoot, ".nax-wt", "story-base");
|
|
235
|
-
writeFileSync(join(basePath, "shared.txt"), "base content");
|
|
236
|
-
execSync("git add shared.txt", { cwd: basePath, stdio: "pipe" });
|
|
237
|
-
execSync('git commit -m "Add shared file"', {
|
|
238
|
-
cwd: basePath,
|
|
239
|
-
stdio: "pipe",
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
// Create conflicting story
|
|
243
|
-
await manager.create(projectRoot, "story-conflict");
|
|
244
|
-
const conflictPath = join(projectRoot, ".nax-wt", "story-conflict");
|
|
245
|
-
writeFileSync(join(conflictPath, "shared.txt"), "conflict content");
|
|
246
|
-
execSync("git add shared.txt", { cwd: conflictPath, stdio: "pipe" });
|
|
247
|
-
execSync('git commit -m "Add conflicting shared file"', {
|
|
248
|
-
cwd: conflictPath,
|
|
249
|
-
stdio: "pipe",
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
// This should handle the conflict scenario
|
|
253
|
-
const results = await engine.mergeAll(projectRoot, storyIds, dependencies);
|
|
254
|
-
|
|
255
|
-
expect(results.length).toBe(2);
|
|
256
|
-
// First story should succeed
|
|
257
|
-
expect(results[0].success).toBe(true);
|
|
258
|
-
expect(results[0].storyId).toBe("story-base");
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
test("marks story as failed on second conflict", async () => {
|
|
262
|
-
const storyIds = ["story-1", "story-2"];
|
|
263
|
-
const dependencies = {
|
|
264
|
-
"story-1": [],
|
|
265
|
-
"story-2": [],
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
// Create first story
|
|
269
|
-
await manager.create(projectRoot, "story-1");
|
|
270
|
-
const path1 = join(projectRoot, ".nax-wt", "story-1");
|
|
271
|
-
writeFileSync(join(path1, "conflict.txt"), "content 1");
|
|
272
|
-
execSync("git add conflict.txt", { cwd: path1, stdio: "pipe" });
|
|
273
|
-
execSync('git commit -m "Story 1"', { cwd: path1, stdio: "pipe" });
|
|
274
|
-
|
|
275
|
-
// Create second story with conflict
|
|
276
|
-
await manager.create(projectRoot, "story-2");
|
|
277
|
-
const path2 = join(projectRoot, ".nax-wt", "story-2");
|
|
278
|
-
writeFileSync(join(path2, "conflict.txt"), "content 2");
|
|
279
|
-
execSync("git add conflict.txt", { cwd: path2, stdio: "pipe" });
|
|
280
|
-
execSync('git commit -m "Story 2"', { cwd: path2, stdio: "pipe" });
|
|
281
|
-
|
|
282
|
-
const results = await engine.mergeAll(projectRoot, storyIds, dependencies);
|
|
283
|
-
|
|
284
|
-
// First should succeed, second should fail
|
|
285
|
-
expect(results.length).toBe(2);
|
|
286
|
-
expect(results[0].success).toBe(true);
|
|
287
|
-
expect(results[1].success).toBe(false);
|
|
288
|
-
expect(results[1].conflictFiles).toBeDefined();
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
test("continues with remaining stories after failure", async () => {
|
|
292
|
-
const storyIds = ["story-base", "story-conflict", "story-3"];
|
|
293
|
-
const dependencies = {
|
|
294
|
-
"story-base": [],
|
|
295
|
-
"story-conflict": [],
|
|
296
|
-
"story-3": [],
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
// Create base story with a file
|
|
300
|
-
await manager.create(projectRoot, "story-base");
|
|
301
|
-
const pathBase = join(projectRoot, ".nax-wt", "story-base");
|
|
302
|
-
writeFileSync(join(pathBase, "shared.txt"), "base content");
|
|
303
|
-
execSync("git add shared.txt", { cwd: pathBase, stdio: "pipe" });
|
|
304
|
-
execSync('git commit -m "Add shared file"', {
|
|
305
|
-
cwd: pathBase,
|
|
306
|
-
stdio: "pipe",
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
// Create conflicting story (modifies same file)
|
|
310
|
-
await manager.create(projectRoot, "story-conflict");
|
|
311
|
-
const pathConflict = join(projectRoot, ".nax-wt", "story-conflict");
|
|
312
|
-
writeFileSync(join(pathConflict, "shared.txt"), "conflict content");
|
|
313
|
-
execSync("git add shared.txt", {
|
|
314
|
-
cwd: pathConflict,
|
|
315
|
-
stdio: "pipe",
|
|
316
|
-
});
|
|
317
|
-
execSync('git commit -m "Modify shared file in story-conflict"', {
|
|
318
|
-
cwd: pathConflict,
|
|
319
|
-
stdio: "pipe",
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
// Create third story (no conflict)
|
|
323
|
-
await manager.create(projectRoot, "story-3");
|
|
324
|
-
const path3 = join(projectRoot, ".nax-wt", "story-3");
|
|
325
|
-
writeFileSync(join(path3, "file3.txt"), "content 3");
|
|
326
|
-
execSync("git add file3.txt", { cwd: path3, stdio: "pipe" });
|
|
327
|
-
execSync('git commit -m "Story 3"', { cwd: path3, stdio: "pipe" });
|
|
328
|
-
|
|
329
|
-
const results = await engine.mergeAll(projectRoot, storyIds, dependencies);
|
|
330
|
-
|
|
331
|
-
// Base should succeed, conflict should fail, story-3 should succeed
|
|
332
|
-
expect(results.length).toBe(3);
|
|
333
|
-
expect(results[0].success).toBe(true);
|
|
334
|
-
expect(results[0].storyId).toBe("story-base");
|
|
335
|
-
expect(results[1].success).toBe(false);
|
|
336
|
-
expect(results[1].storyId).toBe("story-conflict");
|
|
337
|
-
expect(results[2].success).toBe(true);
|
|
338
|
-
expect(results[2].storyId).toBe("story-3");
|
|
339
|
-
});
|
|
340
|
-
});
|
|
341
|
-
});
|