gsd-pi 2.44.0-dev.62b5d6c → 2.44.0-dev.848dd4c
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/README.md +30 -12
- package/dist/resources/extensions/gsd/auto-start.js +10 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -18
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
- package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
- package/src/resources/extensions/gsd/auto-start.ts +14 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
- package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
- package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
- package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
- package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +38 -59
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
- package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
- package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +390 -420
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +152 -183
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
- package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
- package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
- package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
- package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
- package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
- package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
- package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
- package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
- package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
- package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
- package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
- package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
- package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
- package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
- package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
- package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
- package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
- package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
- package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
- package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
- package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
- package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
- package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
- package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
- package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +9 -11
- package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
- package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
- package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
- /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → -zps1Q9mQmioAKLcQiCr8}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → -zps1Q9mQmioAKLcQiCr8}/_ssgManifest.js +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { describe, test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
1
3
|
// ensureDbOpen — Tests that the lazy DB opener creates + migrates the database
|
|
2
4
|
// when .gsd/ exists with Markdown content but no gsd.db file.
|
|
3
5
|
//
|
|
@@ -5,14 +7,11 @@
|
|
|
5
7
|
// "GSD database is not available" because ensureDbOpen only opened
|
|
6
8
|
// existing DB files but never created them.
|
|
7
9
|
|
|
8
|
-
import { createTestContext } from './test-helpers.ts';
|
|
9
10
|
import * as path from 'node:path';
|
|
10
11
|
import * as os from 'node:os';
|
|
11
12
|
import * as fs from 'node:fs';
|
|
12
13
|
import { closeDatabase, isDbAvailable, getDecisionById } from '../gsd-db.ts';
|
|
13
14
|
|
|
14
|
-
const { assertEq, assertTrue, report } = createTestContext();
|
|
15
|
-
|
|
16
15
|
function makeTmpDir(): string {
|
|
17
16
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-ensure-db-'));
|
|
18
17
|
return dir;
|
|
@@ -28,141 +27,134 @@ function cleanupDir(dir: string): void {
|
|
|
28
27
|
// ensureDbOpen creates DB + migrates when .gsd/ has Markdown
|
|
29
28
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
30
|
+
describe('ensure-db-open', () => {
|
|
31
|
+
test('ensureDbOpen: creates DB from Markdown', async () => {
|
|
32
|
+
const tmpDir = makeTmpDir();
|
|
33
|
+
const gsdDir = path.join(tmpDir, '.gsd');
|
|
34
|
+
fs.mkdirSync(gsdDir, { recursive: true });
|
|
35
|
+
|
|
36
|
+
// Write a minimal DECISIONS.md so migration has content
|
|
37
|
+
const decisionsContent = `# Decisions
|
|
38
|
+
|
|
39
|
+
| # | When | Scope | Decision | Choice | Rationale | Revisable |
|
|
40
|
+
|---|------|-------|----------|--------|-----------|-----------|
|
|
41
|
+
| D001 | M001 | architecture | Use SQLite | SQLite | Sync API | Yes |
|
|
42
|
+
`;
|
|
43
|
+
fs.writeFileSync(path.join(gsdDir, 'DECISIONS.md'), decisionsContent);
|
|
44
|
+
|
|
45
|
+
// Verify no DB file exists yet
|
|
46
|
+
const dbPath = path.join(gsdDir, 'gsd.db');
|
|
47
|
+
assert.ok(!fs.existsSync(dbPath), 'DB file should not exist before ensureDbOpen');
|
|
48
|
+
|
|
49
|
+
// Close any previously open DB
|
|
50
|
+
try { closeDatabase(); } catch { /* ok */ }
|
|
51
|
+
|
|
52
|
+
// Override process.cwd to point at tmpDir for ensureDbOpen
|
|
53
|
+
const origCwd = process.cwd;
|
|
54
|
+
process.cwd = () => tmpDir;
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
// Dynamic import to get the freshest version
|
|
58
|
+
const { ensureDbOpen } = await import('../bootstrap/dynamic-tools.ts');
|
|
59
|
+
|
|
60
|
+
const result = await ensureDbOpen();
|
|
61
|
+
|
|
62
|
+
assert.ok(result === true, 'ensureDbOpen should return true when .gsd/ has Markdown');
|
|
63
|
+
assert.ok(fs.existsSync(dbPath), 'DB file should be created after ensureDbOpen');
|
|
64
|
+
assert.ok(isDbAvailable(), 'DB should be available after ensureDbOpen');
|
|
65
|
+
|
|
66
|
+
// Verify that Markdown migration actually ran
|
|
67
|
+
const decision = getDecisionById('D001');
|
|
68
|
+
assert.ok(decision !== null, 'D001 should be migrated from DECISIONS.md');
|
|
69
|
+
if (decision) {
|
|
70
|
+
assert.deepStrictEqual(decision.scope, 'architecture', 'Migrated decision scope should match');
|
|
71
|
+
assert.deepStrictEqual(decision.choice, 'SQLite', 'Migrated decision choice should match');
|
|
72
|
+
}
|
|
73
|
+
} finally {
|
|
74
|
+
process.cwd = origCwd;
|
|
75
|
+
closeDatabase();
|
|
76
|
+
cleanupDir(tmpDir);
|
|
74
77
|
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
assertTrue(result === false, 'ensureDbOpen should return false when no .gsd/ exists');
|
|
100
|
-
assertTrue(!isDbAvailable(), 'DB should not be available');
|
|
101
|
-
} finally {
|
|
102
|
-
process.cwd = origCwd;
|
|
103
|
-
cleanupDir(tmpDir);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
108
|
-
// ensureDbOpen opens existing DB without re-migration
|
|
109
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
110
|
-
|
|
111
|
-
console.log('\n── ensureDbOpen: opens existing DB ──');
|
|
112
|
-
|
|
113
|
-
{
|
|
114
|
-
const tmpDir = makeTmpDir();
|
|
115
|
-
const gsdDir = path.join(tmpDir, '.gsd');
|
|
116
|
-
fs.mkdirSync(gsdDir, { recursive: true });
|
|
117
|
-
|
|
118
|
-
// Create a DB file first
|
|
119
|
-
const dbPath = path.join(gsdDir, 'gsd.db');
|
|
120
|
-
const { openDatabase } = await import('../gsd-db.ts');
|
|
121
|
-
openDatabase(dbPath);
|
|
122
|
-
closeDatabase();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
81
|
+
// ensureDbOpen returns false when no .gsd/ exists
|
|
82
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
83
|
+
|
|
84
|
+
test('ensureDbOpen: no .gsd/ returns false', async () => {
|
|
85
|
+
const tmpDir = makeTmpDir();
|
|
86
|
+
// No .gsd/ directory at all
|
|
87
|
+
|
|
88
|
+
try { closeDatabase(); } catch { /* ok */ }
|
|
89
|
+
const origCwd = process.cwd;
|
|
90
|
+
process.cwd = () => tmpDir;
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const { ensureDbOpen } = await import('../bootstrap/dynamic-tools.ts');
|
|
94
|
+
const result = await ensureDbOpen();
|
|
95
|
+
assert.ok(result === false, 'ensureDbOpen should return false when no .gsd/ exists');
|
|
96
|
+
assert.ok(!isDbAvailable(), 'DB should not be available');
|
|
97
|
+
} finally {
|
|
98
|
+
process.cwd = origCwd;
|
|
99
|
+
cleanupDir(tmpDir);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
123
102
|
|
|
124
|
-
|
|
103
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
104
|
+
// ensureDbOpen opens existing DB without re-migration
|
|
105
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
125
106
|
|
|
126
|
-
|
|
127
|
-
|
|
107
|
+
test('ensureDbOpen: opens existing DB', async () => {
|
|
108
|
+
const tmpDir = makeTmpDir();
|
|
109
|
+
const gsdDir = path.join(tmpDir, '.gsd');
|
|
110
|
+
fs.mkdirSync(gsdDir, { recursive: true });
|
|
128
111
|
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
assertTrue(isDbAvailable(), 'DB should be available');
|
|
134
|
-
} finally {
|
|
135
|
-
process.cwd = origCwd;
|
|
112
|
+
// Create a DB file first
|
|
113
|
+
const dbPath = path.join(gsdDir, 'gsd.db');
|
|
114
|
+
const { openDatabase } = await import('../gsd-db.ts');
|
|
115
|
+
openDatabase(dbPath);
|
|
136
116
|
closeDatabase();
|
|
137
|
-
cleanupDir(tmpDir);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
142
|
-
// ensureDbOpen returns false for empty .gsd/ (no Markdown, no DB)
|
|
143
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
144
|
-
|
|
145
|
-
console.log('\n── ensureDbOpen: empty .gsd/ returns false ──');
|
|
146
117
|
|
|
147
|
-
|
|
148
|
-
const tmpDir = makeTmpDir();
|
|
149
|
-
fs.mkdirSync(path.join(tmpDir, '.gsd'), { recursive: true });
|
|
150
|
-
// .gsd/ exists but no DECISIONS.md, REQUIREMENTS.md, or milestones/
|
|
118
|
+
assert.ok(fs.existsSync(dbPath), 'DB file should exist from manual create');
|
|
151
119
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
process.cwd = () => tmpDir;
|
|
120
|
+
const origCwd = process.cwd;
|
|
121
|
+
process.cwd = () => tmpDir;
|
|
155
122
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
123
|
+
try {
|
|
124
|
+
const { ensureDbOpen } = await import('../bootstrap/dynamic-tools.ts');
|
|
125
|
+
const result = await ensureDbOpen();
|
|
126
|
+
assert.ok(result === true, 'ensureDbOpen should open existing DB');
|
|
127
|
+
assert.ok(isDbAvailable(), 'DB should be available');
|
|
128
|
+
} finally {
|
|
129
|
+
process.cwd = origCwd;
|
|
130
|
+
closeDatabase();
|
|
131
|
+
cleanupDir(tmpDir);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
136
|
+
// ensureDbOpen returns false for empty .gsd/ (no Markdown, no DB)
|
|
137
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
138
|
+
|
|
139
|
+
test('ensureDbOpen: empty .gsd/ returns false', async () => {
|
|
140
|
+
const tmpDir = makeTmpDir();
|
|
141
|
+
fs.mkdirSync(path.join(tmpDir, '.gsd'), { recursive: true });
|
|
142
|
+
// .gsd/ exists but no DECISIONS.md, REQUIREMENTS.md, or milestones/
|
|
143
|
+
|
|
144
|
+
try { closeDatabase(); } catch { /* ok */ }
|
|
145
|
+
const origCwd = process.cwd;
|
|
146
|
+
process.cwd = () => tmpDir;
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
const { ensureDbOpen } = await import('../bootstrap/dynamic-tools.ts');
|
|
150
|
+
const result = await ensureDbOpen();
|
|
151
|
+
assert.ok(result === false, 'ensureDbOpen should return false for empty .gsd/');
|
|
152
|
+
} finally {
|
|
153
|
+
process.cwd = origCwd;
|
|
154
|
+
cleanupDir(tmpDir);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
165
157
|
|
|
166
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
158
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
167
159
|
|
|
168
|
-
|
|
160
|
+
});
|
|
@@ -3,7 +3,7 @@ import assert from "node:assert/strict";
|
|
|
3
3
|
|
|
4
4
|
import { registerExitCommand } from "../exit-command.ts";
|
|
5
5
|
|
|
6
|
-
test("/exit requests graceful shutdown instead of process.exit", async () => {
|
|
6
|
+
test("/exit requests graceful shutdown instead of process.exit", async (t) => {
|
|
7
7
|
const commands = new Map<
|
|
8
8
|
string,
|
|
9
9
|
{
|
|
@@ -35,15 +35,13 @@ test("/exit requests graceful shutdown instead of process.exit", async () => {
|
|
|
35
35
|
throw new Error(`process.exit should not be called: ${code ?? "undefined"}`);
|
|
36
36
|
}) as typeof process.exit;
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
process.exit = originalExit;
|
|
46
|
-
}
|
|
38
|
+
t.after(() => { process.exit = originalExit; });
|
|
39
|
+
|
|
40
|
+
await exit.handler("", {
|
|
41
|
+
async shutdown() {
|
|
42
|
+
shutdownCalls += 1;
|
|
43
|
+
},
|
|
44
|
+
});
|
|
47
45
|
|
|
48
46
|
assert.equal(stopAutoCalls, 1, "handler should stop auto-mode exactly once before shutdown");
|
|
49
47
|
assert.equal(shutdownCalls, 1, "handler should request graceful shutdown exactly once");
|
|
@@ -51,7 +49,7 @@ test("/exit requests graceful shutdown instead of process.exit", async () => {
|
|
|
51
49
|
|
|
52
50
|
// ─── #1839 regression: ESM cache mismatch must not crash exit ────────────────
|
|
53
51
|
|
|
54
|
-
test("/exit still shuts down gracefully when stopAuto throws (ESM module cache mismatch)", async () => {
|
|
52
|
+
test("/exit still shuts down gracefully when stopAuto throws (ESM module cache mismatch)", async (t) => {
|
|
55
53
|
const commands = new Map<string, { description?: string; handler: (args: string, ctx: any) => Promise<void> }>();
|
|
56
54
|
|
|
57
55
|
const pi = {
|
|
@@ -80,20 +78,18 @@ test("/exit still shuts down gracefully when stopAuto throws (ESM module cache m
|
|
|
80
78
|
throw new Error(`process.exit should not be called: ${code ?? "undefined"}`);
|
|
81
79
|
}) as typeof process.exit;
|
|
82
80
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
81
|
+
t.after(() => { process.exit = originalExit; });
|
|
82
|
+
|
|
83
|
+
await exit.handler("", {
|
|
84
|
+
async shutdown() {
|
|
85
|
+
shutdownCalls += 1;
|
|
86
|
+
},
|
|
87
|
+
ui: {
|
|
88
|
+
notify(msg: string, level: string) {
|
|
89
|
+
notifications.push({ msg, level });
|
|
92
90
|
},
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
process.exit = originalExit;
|
|
96
|
-
}
|
|
91
|
+
},
|
|
92
|
+
});
|
|
97
93
|
|
|
98
94
|
assert.equal(shutdownCalls, 1, "shutdown must still be called even when stopAuto throws");
|
|
99
95
|
assert.equal(notifications.length, 1, "should emit exactly one warning notification");
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { describe, test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
1
3
|
/**
|
|
2
4
|
* feature-branch-lifecycle.test.ts — Integration tests for the feature-branch workflow.
|
|
3
5
|
*
|
|
@@ -29,10 +31,6 @@ import { captureIntegrationBranch, getSliceBranchName } from "../worktree.ts";
|
|
|
29
31
|
import { writeIntegrationBranch, readIntegrationBranch } from "../git-service.ts";
|
|
30
32
|
import { nextMilestoneId, generateMilestoneSuffix } from "../guided-flow.ts";
|
|
31
33
|
|
|
32
|
-
import { createTestContext } from "./test-helpers.ts";
|
|
33
|
-
|
|
34
|
-
const { assertEq, assertTrue, assertMatch, report } = createTestContext();
|
|
35
|
-
|
|
36
34
|
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
37
35
|
|
|
38
36
|
function run(cmd: string, cwd: string): string {
|
|
@@ -137,7 +135,7 @@ function addSliceToMilestone(
|
|
|
137
135
|
|
|
138
136
|
// ─── Tests ──────────────────────────────────────────────────────────────────
|
|
139
137
|
|
|
140
|
-
async
|
|
138
|
+
describe('feature-branch-lifecycle-integration', async () => {
|
|
141
139
|
const savedCwd = process.cwd();
|
|
142
140
|
const tempDirs: string[] = [];
|
|
143
141
|
|
|
@@ -154,14 +152,13 @@ async function main(): Promise<void> {
|
|
|
154
152
|
// Start on f-new-shiny-thing with uncommitted changes, create
|
|
155
153
|
// worktree, add slices, merge back. Assert main is untouched.
|
|
156
154
|
// ================================================================
|
|
157
|
-
|
|
158
|
-
{
|
|
155
|
+
test('Feature-branch lifecycle with unique milestone IDs', () => {
|
|
159
156
|
const featureBranch = "f-new-shiny-thing";
|
|
160
157
|
const repo = fresh(featureBranch);
|
|
161
158
|
|
|
162
159
|
// Generate a unique milestone ID (M001-xxxxxx format)
|
|
163
160
|
const milestoneId = nextMilestoneId([], true);
|
|
164
|
-
|
|
161
|
+
assert.match(milestoneId, /^M001-[a-z0-9]{6}$/, "unique milestone ID format");
|
|
165
162
|
|
|
166
163
|
// Snapshot main before anything happens
|
|
167
164
|
const mainShaBefore = headSha(repo, "main");
|
|
@@ -174,8 +171,8 @@ async function main(): Promise<void> {
|
|
|
174
171
|
|
|
175
172
|
// Verify files are uncommitted
|
|
176
173
|
const statusBefore = run("git status --short", repo);
|
|
177
|
-
|
|
178
|
-
|
|
174
|
+
assert.ok(statusBefore.includes("wip-config.ts"), "wip-config.ts is uncommitted");
|
|
175
|
+
assert.ok(statusBefore.includes("wip-types.ts"), "wip-types.ts is uncommitted");
|
|
179
176
|
|
|
180
177
|
// ── Simulate what startAuto does: commit dirty state, capture integration branch ──
|
|
181
178
|
// startAuto bootstraps .gsd/ which commits .gsd/ files. It also calls
|
|
@@ -198,7 +195,7 @@ async function main(): Promise<void> {
|
|
|
198
195
|
|
|
199
196
|
// Verify integration branch recorded
|
|
200
197
|
const recorded = readIntegrationBranch(repo, milestoneId);
|
|
201
|
-
|
|
198
|
+
assert.deepStrictEqual(recorded, featureBranch, "integration branch recorded as feature branch");
|
|
202
199
|
|
|
203
200
|
// Snapshot feature branch SHA after metadata commit (HEAD may have advanced)
|
|
204
201
|
const featureShaBeforeWorktree = headSha(repo, featureBranch);
|
|
@@ -206,28 +203,28 @@ async function main(): Promise<void> {
|
|
|
206
203
|
// ── Create the auto-worktree ──
|
|
207
204
|
const wtPath = createAutoWorktree(repo, milestoneId);
|
|
208
205
|
tempDirs.push(wtPath);
|
|
209
|
-
|
|
206
|
+
assert.ok(existsSync(wtPath), "worktree directory created");
|
|
210
207
|
|
|
211
208
|
// Worktree should be on milestone/<unique-id> branch
|
|
212
209
|
const wtBranch = run("git branch --show-current", wtPath);
|
|
213
|
-
|
|
210
|
+
assert.deepStrictEqual(wtBranch, `milestone/${milestoneId}`, "worktree is on milestone branch");
|
|
214
211
|
|
|
215
212
|
// Milestone branch should be rooted at the feature branch, not main
|
|
216
213
|
const milestoneBranchBase = headSha(repo, `milestone/${milestoneId}`);
|
|
217
|
-
|
|
214
|
+
assert.deepStrictEqual(
|
|
218
215
|
milestoneBranchBase,
|
|
219
216
|
featureShaBeforeWorktree,
|
|
220
217
|
"milestone branch starts from feature branch HEAD",
|
|
221
218
|
);
|
|
222
219
|
|
|
223
220
|
// Feature-branch-only file should be in the worktree
|
|
224
|
-
|
|
221
|
+
assert.ok(
|
|
225
222
|
existsSync(join(wtPath, "feature-setup.ts")),
|
|
226
223
|
"feature branch file (feature-setup.ts) exists in worktree",
|
|
227
224
|
);
|
|
228
225
|
|
|
229
226
|
// Main should be completely untouched at this point
|
|
230
|
-
|
|
227
|
+
assert.deepStrictEqual(headSha(repo, "main"), mainShaBefore, "main SHA unchanged after worktree creation");
|
|
231
228
|
|
|
232
229
|
// ── Do work in slices ──
|
|
233
230
|
addSliceToMilestone(wtPath, milestoneId, "S01", "Auth module", [
|
|
@@ -250,62 +247,62 @@ async function main(): Promise<void> {
|
|
|
250
247
|
|
|
251
248
|
// ── Assert: feature branch received the merge ──
|
|
252
249
|
const currentBranch = run("git branch --show-current", repo);
|
|
253
|
-
|
|
250
|
+
assert.deepStrictEqual(currentBranch, featureBranch, "repo is on feature branch after merge");
|
|
254
251
|
|
|
255
252
|
// Exactly one new commit on feature branch (the squash merge)
|
|
256
253
|
const featureLog = run(`git log --oneline ${featureBranch}`, repo);
|
|
257
|
-
|
|
254
|
+
assert.ok(
|
|
258
255
|
featureLog.includes(`feat(${milestoneId})`),
|
|
259
256
|
"feature branch has milestone merge commit",
|
|
260
257
|
);
|
|
261
258
|
|
|
262
259
|
// Slice files are on the feature branch
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
260
|
+
assert.ok(existsSync(join(repo, "auth.ts")), "auth.ts on feature branch");
|
|
261
|
+
assert.ok(existsSync(join(repo, "dashboard.ts")), "dashboard.ts on feature branch");
|
|
262
|
+
assert.ok(existsSync(join(repo, "auth-utils.ts")), "auth-utils.ts on feature branch");
|
|
266
263
|
|
|
267
264
|
// Original feature branch file still present
|
|
268
|
-
|
|
265
|
+
assert.ok(existsSync(join(repo, "feature-setup.ts")), "feature-setup.ts still on feature branch");
|
|
269
266
|
|
|
270
267
|
// Commit message is well-formed
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
268
|
+
assert.ok(result.commitMessage.includes("New shiny feature"), "commit message has milestone title");
|
|
269
|
+
assert.ok(result.commitMessage.includes("S01: Auth module"), "commit message lists S01");
|
|
270
|
+
assert.ok(result.commitMessage.includes("S02: Dashboard"), "commit message lists S02");
|
|
271
|
+
assert.ok(
|
|
275
272
|
result.commitMessage.includes(`milestone/${milestoneId}`),
|
|
276
273
|
"commit message references milestone branch with unique ID",
|
|
277
274
|
);
|
|
278
275
|
|
|
279
276
|
// ── Assert: main is COMPLETELY untouched ──
|
|
280
|
-
|
|
281
|
-
|
|
277
|
+
assert.deepStrictEqual(headSha(repo, "main"), mainShaBefore, "main SHA unchanged after merge");
|
|
278
|
+
assert.deepStrictEqual(commitCount(repo, "main"), mainCommitsBefore, "main commit count unchanged");
|
|
282
279
|
|
|
283
280
|
// Main should NOT have any of the milestone files
|
|
284
281
|
run("git checkout main", repo);
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
282
|
+
assert.ok(!existsSync(join(repo, "auth.ts")), "auth.ts NOT on main");
|
|
283
|
+
assert.ok(!existsSync(join(repo, "dashboard.ts")), "dashboard.ts NOT on main");
|
|
284
|
+
assert.ok(!existsSync(join(repo, "feature-setup.ts")), "feature-setup.ts NOT on main");
|
|
288
285
|
run(`git checkout ${featureBranch}`, repo);
|
|
289
286
|
|
|
290
287
|
// ── Assert: worktree cleaned up ──
|
|
291
288
|
const worktreeDir = join(repo, ".gsd", "worktrees", milestoneId);
|
|
292
|
-
|
|
289
|
+
assert.ok(!existsSync(worktreeDir), "worktree directory removed");
|
|
293
290
|
|
|
294
291
|
// Milestone branch deleted
|
|
295
|
-
|
|
292
|
+
assert.ok(
|
|
296
293
|
!branchExists(repo, `milestone/${milestoneId}`),
|
|
297
294
|
"milestone branch deleted after merge",
|
|
298
295
|
);
|
|
299
296
|
|
|
300
297
|
// Only expected branches remain
|
|
301
298
|
const branches = allBranches(repo);
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
299
|
+
assert.ok(branches.includes("main"), "main branch exists");
|
|
300
|
+
assert.ok(branches.includes(featureBranch), "feature branch exists");
|
|
301
|
+
assert.ok(
|
|
305
302
|
!branches.some(b => b.startsWith("milestone/")),
|
|
306
303
|
"no milestone branches remain",
|
|
307
304
|
);
|
|
308
|
-
}
|
|
305
|
+
});
|
|
309
306
|
|
|
310
307
|
// ================================================================
|
|
311
308
|
// Test 2: Uncommitted .gsd/ planning files are available in worktree
|
|
@@ -314,8 +311,7 @@ async function main(): Promise<void> {
|
|
|
314
311
|
// Planning artifacts should be carried into the worktree even if
|
|
315
312
|
// they weren't committed on the feature branch.
|
|
316
313
|
// ================================================================
|
|
317
|
-
|
|
318
|
-
{
|
|
314
|
+
test('Untracked planning files copied to worktree', () => {
|
|
319
315
|
const featureBranch = "f-planning-test";
|
|
320
316
|
const repo = fresh(featureBranch);
|
|
321
317
|
const milestoneId = nextMilestoneId([], true);
|
|
@@ -334,7 +330,7 @@ async function main(): Promise<void> {
|
|
|
334
330
|
writeFileSync(join(repo, ".gsd", "DECISIONS.md"), "# Decisions\n\n## D001\nTest decision.\n");
|
|
335
331
|
|
|
336
332
|
// These files are untracked
|
|
337
|
-
|
|
333
|
+
assert.ok(run("git status --short", repo).length > 0, "repo has untracked files");
|
|
338
334
|
|
|
339
335
|
// Record integration branch and create worktree
|
|
340
336
|
writeIntegrationBranch(repo, milestoneId, featureBranch);
|
|
@@ -344,11 +340,11 @@ async function main(): Promise<void> {
|
|
|
344
340
|
// With external state, worktree .gsd is a symlink to shared state.
|
|
345
341
|
// Verify symlink was created (planning files are shared, not copied).
|
|
346
342
|
const wtGsd = join(wtPath, ".gsd");
|
|
347
|
-
|
|
343
|
+
assert.ok(existsSync(wtGsd), "worktree .gsd exists (symlink or dir)");
|
|
348
344
|
|
|
349
345
|
// Clean up: chdir back before teardown
|
|
350
346
|
process.chdir(savedCwd);
|
|
351
|
-
}
|
|
347
|
+
});
|
|
352
348
|
|
|
353
349
|
// ================================================================
|
|
354
350
|
// Test 3: Multiple milestones on the same feature branch
|
|
@@ -356,8 +352,7 @@ async function main(): Promise<void> {
|
|
|
356
352
|
// Proves that unique IDs prevent collision when running successive
|
|
357
353
|
// milestones, and each merge lands on the feature branch.
|
|
358
354
|
// ================================================================
|
|
359
|
-
|
|
360
|
-
{
|
|
355
|
+
test('Multiple unique milestones on same feature branch', () => {
|
|
361
356
|
const featureBranch = "f-multi-milestone";
|
|
362
357
|
const repo = fresh(featureBranch);
|
|
363
358
|
|
|
@@ -377,12 +372,12 @@ async function main(): Promise<void> {
|
|
|
377
372
|
mergeMilestoneToMain(repo, mid1, makeRoadmap(mid1, "First", [{ id: "S01", title: "First milestone work" }]));
|
|
378
373
|
process.chdir(savedCwd);
|
|
379
374
|
|
|
380
|
-
|
|
375
|
+
assert.ok(existsSync(join(repo, "m1-feature.ts")), "m1 file on feature branch");
|
|
381
376
|
|
|
382
377
|
// Second milestone — different unique ID
|
|
383
378
|
const mid2 = nextMilestoneId([mid1], true);
|
|
384
|
-
|
|
385
|
-
|
|
379
|
+
assert.ok(mid1 !== mid2, "second milestone has different ID");
|
|
380
|
+
assert.match(mid2, /^M002-[a-z0-9]{6}$/, "second milestone is M002-xxxxxx");
|
|
386
381
|
|
|
387
382
|
mkdirSync(join(repo, ".gsd", "milestones", mid2), { recursive: true });
|
|
388
383
|
writeIntegrationBranch(repo, mid2, featureBranch);
|
|
@@ -397,19 +392,19 @@ async function main(): Promise<void> {
|
|
|
397
392
|
process.chdir(savedCwd);
|
|
398
393
|
|
|
399
394
|
// Both milestone files on feature branch
|
|
400
|
-
|
|
401
|
-
|
|
395
|
+
assert.ok(existsSync(join(repo, "m1-feature.ts")), "m1 file still on feature branch");
|
|
396
|
+
assert.ok(existsSync(join(repo, "m2-feature.ts")), "m2 file on feature branch");
|
|
402
397
|
|
|
403
398
|
// Main completely untouched
|
|
404
|
-
|
|
399
|
+
assert.deepStrictEqual(headSha(repo, "main"), mainShaBefore, "main unchanged after two milestones");
|
|
405
400
|
|
|
406
401
|
// No milestone branches remain
|
|
407
402
|
const branches = allBranches(repo);
|
|
408
|
-
|
|
403
|
+
assert.ok(
|
|
409
404
|
!branches.some(b => b.startsWith("milestone/")),
|
|
410
405
|
"no milestone branches remain after two milestones",
|
|
411
406
|
);
|
|
412
|
-
}
|
|
407
|
+
});
|
|
413
408
|
|
|
414
409
|
} finally {
|
|
415
410
|
process.chdir(savedCwd);
|
|
@@ -417,8 +412,4 @@ async function main(): Promise<void> {
|
|
|
417
412
|
try { rmSync(d, { recursive: true, force: true }); } catch { /* ignore */ }
|
|
418
413
|
}
|
|
419
414
|
}
|
|
420
|
-
|
|
421
|
-
report();
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
main();
|
|
415
|
+
});
|