gsd-pi 2.44.0-dev.73f2fd5 → 2.44.0-dev.8894d5b
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/dist/resources/extensions/gsd/auto/infra-errors.js +0 -3
- package/dist/resources/extensions/gsd/auto/phases.js +36 -36
- package/dist/resources/extensions/gsd/auto-prompts.js +1 -24
- package/dist/resources/extensions/gsd/auto-timers.js +3 -57
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +0 -4
- package/dist/resources/extensions/gsd/auto-worktree.js +6 -9
- package/dist/resources/extensions/gsd/auto.js +3 -30
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +0 -136
- package/dist/resources/extensions/gsd/commands/catalog.js +1 -6
- package/dist/resources/extensions/gsd/commands/handlers/core.js +0 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +0 -5
- package/dist/resources/extensions/gsd/db-writer.js +16 -34
- package/dist/resources/extensions/gsd/doctor.js +0 -8
- package/dist/resources/extensions/gsd/git-service.js +3 -8
- package/dist/resources/extensions/gsd/gsd-db.js +1 -12
- package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +4 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +14 -3
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +37 -7
- package/dist/resources/extensions/gsd/provider-error-pause.js +0 -7
- package/dist/resources/extensions/gsd/tools/plan-slice.js +0 -1
- package/dist/resources/extensions/gsd/tools/plan-task.js +0 -1
- package/dist/resources/extensions/gsd/tools/replan-slice.js +0 -2
- package/dist/resources/extensions/gsd/worktree-resolver.js +0 -6
- package/dist/resources/extensions/mcp-client/index.js +0 -14
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +20 -20
- 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 +20 -20
- 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.d.ts +1 -3
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +1 -15
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +0 -11
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +1 -20
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +0 -3
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +0 -6
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +0 -17
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +1 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +1 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +0 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +0 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +1 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +2 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +2 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +8 -17
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -7
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.ts +1 -15
- package/packages/pi-coding-agent/src/core/model-registry.ts +1 -21
- package/packages/pi-coding-agent/src/core/settings-manager.ts +0 -9
- package/packages/pi-coding-agent/src/main.ts +0 -19
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +0 -10
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +0 -15
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +1 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +3 -18
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +7 -16
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +1 -8
- package/src/resources/extensions/gsd/auto/infra-errors.ts +0 -3
- package/src/resources/extensions/gsd/auto/phases.ts +48 -45
- package/src/resources/extensions/gsd/auto-prompts.ts +1 -24
- package/src/resources/extensions/gsd/auto-timers.ts +3 -64
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +0 -5
- package/src/resources/extensions/gsd/auto-worktree.ts +6 -9
- package/src/resources/extensions/gsd/auto.ts +3 -37
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +0 -129
- package/src/resources/extensions/gsd/commands/catalog.ts +1 -6
- package/src/resources/extensions/gsd/commands/handlers/core.ts +0 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +0 -5
- package/src/resources/extensions/gsd/db-writer.ts +17 -39
- package/src/resources/extensions/gsd/doctor.ts +1 -7
- package/src/resources/extensions/gsd/git-service.ts +2 -6
- package/src/resources/extensions/gsd/gsd-db.ts +1 -16
- package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +4 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/src/resources/extensions/gsd/prompts/replan-slice.md +14 -3
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +37 -7
- package/src/resources/extensions/gsd/provider-error-pause.ts +0 -9
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +0 -79
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -20
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +7 -11
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +1 -2
- package/src/resources/extensions/gsd/tools/plan-slice.ts +0 -2
- package/src/resources/extensions/gsd/tools/plan-task.ts +0 -2
- package/src/resources/extensions/gsd/tools/replan-slice.ts +0 -3
- package/src/resources/extensions/gsd/worktree-resolver.ts +0 -7
- package/src/resources/extensions/mcp-client/index.ts +0 -20
- package/dist/resources/extensions/gsd/commands-mcp-status.js +0 -187
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +0 -88
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +0 -15
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/local-model-check.js +0 -41
- package/packages/pi-coding-agent/dist/core/local-model-check.js.map +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +0 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +0 -32
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +0 -15
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +0 -40
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +0 -1
- package/packages/pi-coding-agent/src/core/local-model-check.ts +0 -45
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +0 -38
- package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +0 -48
- package/src/resources/extensions/gsd/commands-mcp-status.ts +0 -247
- package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +0 -88
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +0 -114
- package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +0 -120
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +0 -103
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +0 -66
- package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +0 -67
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +0 -49
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +0 -127
- /package/dist/web/standalone/.next/static/{kxxAA66bah_yhPYqLBHE2 → oZMtyM-zfu6Inx-S59cOl}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{kxxAA66bah_yhPYqLBHE2 → oZMtyM-zfu6Inx-S59cOl}/_ssgManifest.js +0 -0
|
@@ -16,8 +16,6 @@ All relevant context has been preloaded below — the roadmap, all slice summari
|
|
|
16
16
|
|
|
17
17
|
{{inlinedContext}}
|
|
18
18
|
|
|
19
|
-
{{skillActivation}}
|
|
20
|
-
|
|
21
19
|
## Validation Steps
|
|
22
20
|
|
|
23
21
|
1. For each **success criterion** in `{{roadmapPath}}`, check whether slice summaries and UAT results provide evidence that it was met. Record pass/fail per criterion.
|
|
@@ -27,15 +25,47 @@ All relevant context has been preloaded below — the roadmap, all slice summari
|
|
|
27
25
|
5. Determine a verdict:
|
|
28
26
|
- `pass` — all criteria met, all slices delivered, no gaps
|
|
29
27
|
- `needs-attention` — minor gaps that do not block completion (document them)
|
|
30
|
-
- `needs-remediation` — material gaps found; remediation slices
|
|
28
|
+
- `needs-remediation` — material gaps found; add remediation slices to the roadmap
|
|
29
|
+
|
|
30
|
+
## Output
|
|
31
|
+
|
|
32
|
+
Write `{{validationPath}}` with this structure:
|
|
33
|
+
|
|
34
|
+
```markdown
|
|
35
|
+
---
|
|
36
|
+
verdict: <pass|needs-attention|needs-remediation>
|
|
37
|
+
remediation_round: {{remediationRound}}
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
# Milestone Validation: {{milestoneId}}
|
|
31
41
|
|
|
32
|
-
##
|
|
42
|
+
## Success Criteria Checklist
|
|
43
|
+
- [x] Criterion 1 — evidence: ...
|
|
44
|
+
- [ ] Criterion 2 — gap: ...
|
|
33
45
|
|
|
34
|
-
|
|
46
|
+
## Slice Delivery Audit
|
|
47
|
+
| Slice | Claimed | Delivered | Status |
|
|
48
|
+
|-------|---------|-----------|--------|
|
|
49
|
+
| S01 | ... | ... | pass |
|
|
50
|
+
|
|
51
|
+
## Cross-Slice Integration
|
|
52
|
+
(any boundary mismatches)
|
|
53
|
+
|
|
54
|
+
## Requirement Coverage
|
|
55
|
+
(any unaddressed requirements)
|
|
56
|
+
|
|
57
|
+
## Verdict Rationale
|
|
58
|
+
(why this verdict was chosen)
|
|
59
|
+
|
|
60
|
+
## Remediation Plan
|
|
61
|
+
(only if verdict is needs-remediation — list new slices to add to the roadmap)
|
|
62
|
+
```
|
|
35
63
|
|
|
36
64
|
If verdict is `needs-remediation`:
|
|
37
|
-
-
|
|
38
|
-
- These
|
|
65
|
+
- Add new slices to `{{roadmapPath}}` with unchecked `[ ]` status
|
|
66
|
+
- These slices will be planned and executed before validation re-runs
|
|
67
|
+
|
|
68
|
+
**You MUST write `{{validationPath}}` before finishing.**
|
|
39
69
|
|
|
40
70
|
**File system safety:** When scanning milestone directories for evidence, use `ls` or `find` to list directory contents first — never pass a directory path (e.g. `tasks/`, `slices/`) directly to the `read` tool. The `read` tool only accepts file paths, not directories.
|
|
41
71
|
|
|
@@ -19,11 +19,6 @@ export function classifyProviderError(errorMsg: string): {
|
|
|
19
19
|
const isRateLimit = /rate.?limit|too many requests|429/i.test(errorMsg);
|
|
20
20
|
const isServerError = /internal server error|500|502|503|overloaded|server_error|api_error|service.?unavailable/i.test(errorMsg);
|
|
21
21
|
|
|
22
|
-
// Connection/process errors — transient, auto-resume after brief backoff (#2309).
|
|
23
|
-
// These indicate the process was killed, the connection was reset, or a network
|
|
24
|
-
// blip occurred. They are NOT permanent failures.
|
|
25
|
-
const isConnectionError = /terminated|connection.?reset|connection.?refused|other side closed|fetch failed|network.?(?:is\s+)?unavailable|ECONNREFUSED|ECONNRESET|EPIPE/i.test(errorMsg);
|
|
26
|
-
|
|
27
22
|
// Permanent errors — never auto-resume
|
|
28
23
|
const isPermanent = /auth|unauthorized|forbidden|invalid.*key|invalid.*api|billing|quota exceeded|account/i.test(errorMsg);
|
|
29
24
|
|
|
@@ -42,10 +37,6 @@ export function classifyProviderError(errorMsg: string): {
|
|
|
42
37
|
return { isTransient: true, isRateLimit: false, suggestedDelayMs: 30_000 }; // 30s for server errors
|
|
43
38
|
}
|
|
44
39
|
|
|
45
|
-
if (isConnectionError) {
|
|
46
|
-
return { isTransient: true, isRateLimit: false, suggestedDelayMs: 15_000 }; // 15s for connection errors
|
|
47
|
-
}
|
|
48
|
-
|
|
49
40
|
// Unknown error — treat as permanent (user reviews)
|
|
50
41
|
return { isTransient: false, isRateLimit: false, suggestedDelayMs: 0 };
|
|
51
42
|
}
|
|
@@ -483,85 +483,6 @@ describe('db-writer', () => {
|
|
|
483
483
|
}
|
|
484
484
|
});
|
|
485
485
|
|
|
486
|
-
test('saveArtifactToDb — shrinkage guard preserves larger existing file', async () => {
|
|
487
|
-
const tmpDir = makeTmpDir();
|
|
488
|
-
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
489
|
-
openDatabase(dbPath);
|
|
490
|
-
|
|
491
|
-
try {
|
|
492
|
-
const fullContent = '# Full Research\n\n' + 'x'.repeat(20000) + '\n';
|
|
493
|
-
const abbreviatedContent = '# Summary\n\nShort version.\n';
|
|
494
|
-
|
|
495
|
-
// Pre-create the file with full content (simulating a prior `write` tool call)
|
|
496
|
-
const relPath = 'milestones/M001/M001-RESEARCH.md';
|
|
497
|
-
const filePath = path.join(tmpDir, '.gsd', relPath);
|
|
498
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
499
|
-
fs.writeFileSync(filePath, fullContent);
|
|
500
|
-
|
|
501
|
-
// Call saveArtifactToDb with abbreviated content — should trigger shrinkage guard
|
|
502
|
-
await saveArtifactToDb({
|
|
503
|
-
path: relPath,
|
|
504
|
-
artifact_type: 'RESEARCH',
|
|
505
|
-
content: abbreviatedContent,
|
|
506
|
-
milestone_id: 'M001',
|
|
507
|
-
}, tmpDir);
|
|
508
|
-
|
|
509
|
-
// Disk file should be preserved (not overwritten)
|
|
510
|
-
assert.deepStrictEqual(
|
|
511
|
-
fs.readFileSync(filePath, 'utf-8'),
|
|
512
|
-
fullContent,
|
|
513
|
-
'disk file preserved — shrinkage guard prevented overwrite',
|
|
514
|
-
);
|
|
515
|
-
|
|
516
|
-
// DB should contain the full disk content, not the abbreviated content
|
|
517
|
-
const adapter = _getAdapter();
|
|
518
|
-
const row = adapter!
|
|
519
|
-
.prepare('SELECT full_content FROM artifacts WHERE path = ?')
|
|
520
|
-
.get(relPath);
|
|
521
|
-
assert.deepStrictEqual(
|
|
522
|
-
row!['full_content'],
|
|
523
|
-
fullContent,
|
|
524
|
-
'DB stores the richer disk content instead of abbreviated content',
|
|
525
|
-
);
|
|
526
|
-
} finally {
|
|
527
|
-
closeDatabase();
|
|
528
|
-
cleanupDir(tmpDir);
|
|
529
|
-
}
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
test('saveArtifactToDb — allows overwrite when new content is similar size', async () => {
|
|
533
|
-
const tmpDir = makeTmpDir();
|
|
534
|
-
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
535
|
-
openDatabase(dbPath);
|
|
536
|
-
|
|
537
|
-
try {
|
|
538
|
-
const oldContent = '# Summary v1\n\nOriginal content here.\n';
|
|
539
|
-
const newContent = '# Summary v2\n\nUpdated content here with more details.\n';
|
|
540
|
-
|
|
541
|
-
const relPath = 'milestones/M001/M001-SUMMARY.md';
|
|
542
|
-
const filePath = path.join(tmpDir, '.gsd', relPath);
|
|
543
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
544
|
-
fs.writeFileSync(filePath, oldContent);
|
|
545
|
-
|
|
546
|
-
await saveArtifactToDb({
|
|
547
|
-
path: relPath,
|
|
548
|
-
artifact_type: 'SUMMARY',
|
|
549
|
-
content: newContent,
|
|
550
|
-
milestone_id: 'M001',
|
|
551
|
-
}, tmpDir);
|
|
552
|
-
|
|
553
|
-
// Disk file should be updated (new content is >=50% of old size)
|
|
554
|
-
assert.deepStrictEqual(
|
|
555
|
-
fs.readFileSync(filePath, 'utf-8'),
|
|
556
|
-
newContent,
|
|
557
|
-
'disk file updated when new content is similar size',
|
|
558
|
-
);
|
|
559
|
-
} finally {
|
|
560
|
-
closeDatabase();
|
|
561
|
-
cleanupDir(tmpDir);
|
|
562
|
-
}
|
|
563
|
-
});
|
|
564
|
-
|
|
565
486
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
566
487
|
// Full Round-Trip: DB → Markdown → Parse → Compare
|
|
567
488
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -7,13 +7,10 @@ import { isInfrastructureError, INFRA_ERROR_CODES } from "../auto/infra-errors.j
|
|
|
7
7
|
// ── INFRA_ERROR_CODES constant ───────────────────────────────────────────────
|
|
8
8
|
|
|
9
9
|
test("INFRA_ERROR_CODES contains the expected codes", () => {
|
|
10
|
-
for (const code of [
|
|
11
|
-
"ENOSPC", "ENOMEM", "EROFS", "EDQUOT", "EMFILE", "ENFILE",
|
|
12
|
-
"ECONNREFUSED", "ENOTFOUND", "ENETUNREACH",
|
|
13
|
-
]) {
|
|
10
|
+
for (const code of ["ENOSPC", "ENOMEM", "EROFS", "EDQUOT", "EMFILE", "ENFILE"]) {
|
|
14
11
|
assert.ok(INFRA_ERROR_CODES.has(code), `missing ${code}`);
|
|
15
12
|
}
|
|
16
|
-
assert.equal(INFRA_ERROR_CODES.size,
|
|
13
|
+
assert.equal(INFRA_ERROR_CODES.size, 6, "unexpected extra codes");
|
|
17
14
|
});
|
|
18
15
|
|
|
19
16
|
// ── isInfrastructureError: code property detection ───────────────────────────
|
|
@@ -48,21 +45,6 @@ test("detects ENFILE via code property", () => {
|
|
|
48
45
|
assert.equal(isInfrastructureError(err), "ENFILE");
|
|
49
46
|
});
|
|
50
47
|
|
|
51
|
-
test("detects ECONNREFUSED via code property", () => {
|
|
52
|
-
const err = Object.assign(new Error("connect ECONNREFUSED 127.0.0.1:3000"), { code: "ECONNREFUSED" });
|
|
53
|
-
assert.equal(isInfrastructureError(err), "ECONNREFUSED");
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
test("detects ENOTFOUND via code property", () => {
|
|
57
|
-
const err = Object.assign(new Error("getaddrinfo ENOTFOUND api.example.com"), { code: "ENOTFOUND" });
|
|
58
|
-
assert.equal(isInfrastructureError(err), "ENOTFOUND");
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test("detects ENETUNREACH via code property", () => {
|
|
62
|
-
const err = Object.assign(new Error("connect ENETUNREACH 2607:f8b0:4004::"), { code: "ENETUNREACH" });
|
|
63
|
-
assert.equal(isInfrastructureError(err), "ENETUNREACH");
|
|
64
|
-
});
|
|
65
|
-
|
|
66
48
|
// ── isInfrastructureError: message fallback ──────────────────────────────────
|
|
67
49
|
|
|
68
50
|
test("falls back to message scanning when no code property", () => {
|
|
@@ -147,12 +147,12 @@ test("plan-slice prompt no longer frames direct PLAN writes as the source of tru
|
|
|
147
147
|
assert.match(prompt, /Do \*\*not\*\* rely on direct `PLAN\.md` writes as the source of truth/i);
|
|
148
148
|
});
|
|
149
149
|
|
|
150
|
-
test("plan-slice prompt explicitly names gsd_plan_slice as DB-backed planning
|
|
150
|
+
test("plan-slice prompt explicitly names gsd_plan_slice and gsd_plan_task as DB-backed planning tools", () => {
|
|
151
151
|
const prompt = readPrompt("plan-slice");
|
|
152
152
|
assert.match(prompt, /gsd_plan_slice/);
|
|
153
153
|
assert.match(prompt, /gsd_plan_task/);
|
|
154
|
-
// The prompt should describe
|
|
155
|
-
assert.match(prompt, /DB-backed
|
|
154
|
+
// The prompt should describe these as the canonical write path
|
|
155
|
+
assert.match(prompt, /DB-backed tools are the canonical write path/i);
|
|
156
156
|
});
|
|
157
157
|
|
|
158
158
|
test("plan-slice prompt does not instruct direct file writes as a primary step", () => {
|
|
@@ -161,18 +161,14 @@ test("plan-slice prompt does not instruct direct file writes as a primary step",
|
|
|
161
161
|
assert.doesNotMatch(prompt, /^\d+\.\s+Write `?\{\{outputPath\}\}`?\s*$/m);
|
|
162
162
|
});
|
|
163
163
|
|
|
164
|
-
test("plan-slice prompt
|
|
164
|
+
test("plan-slice prompt instructs calling gsd_plan_task for each task", () => {
|
|
165
165
|
const prompt = readPrompt("plan-slice");
|
|
166
|
-
|
|
167
|
-
assert.match(prompt, /gsd_plan_task/);
|
|
168
|
-
assert.match(prompt, /gsd_plan_slice` handles task persistence/i);
|
|
166
|
+
assert.match(prompt, /call `gsd_plan_task` for each task/i);
|
|
169
167
|
});
|
|
170
168
|
|
|
171
|
-
test("replan-slice prompt
|
|
169
|
+
test("replan-slice prompt requires DB-backed planning state when available", () => {
|
|
172
170
|
const prompt = readPrompt("replan-slice");
|
|
173
|
-
assert.match(prompt, /
|
|
174
|
-
// Degraded fallback (direct file writes) was removed — DB tools are always available
|
|
175
|
-
assert.doesNotMatch(prompt, /Degraded fallback/i);
|
|
171
|
+
assert.match(prompt, /DB-backed planning tool exists for this phase, use it as the source of truth/i);
|
|
176
172
|
});
|
|
177
173
|
|
|
178
174
|
test("reassess-roadmap prompt references gsd_reassess_roadmap tool", () => {
|
|
@@ -34,7 +34,6 @@ const RENAME_MAP: Array<{ canonical: string; alias: string }> = [
|
|
|
34
34
|
{ canonical: "gsd_replan_slice", alias: "gsd_slice_replan" },
|
|
35
35
|
{ canonical: "gsd_reassess_roadmap", alias: "gsd_roadmap_reassess" },
|
|
36
36
|
{ canonical: "gsd_complete_milestone", alias: "gsd_milestone_complete" },
|
|
37
|
-
{ canonical: "gsd_validate_milestone", alias: "gsd_milestone_validate" },
|
|
38
37
|
];
|
|
39
38
|
|
|
40
39
|
// ─── Registration count ──────────────────────────────────────────────────────
|
|
@@ -44,7 +43,7 @@ console.log('\n── Tool naming: registration count ──');
|
|
|
44
43
|
const pi = makeMockPi();
|
|
45
44
|
registerDbTools(pi);
|
|
46
45
|
|
|
47
|
-
assert.deepStrictEqual(pi.tools.length,
|
|
46
|
+
assert.deepStrictEqual(pi.tools.length, 24, 'Should register exactly 24 tools (12 canonical + 12 aliases)');
|
|
48
47
|
|
|
49
48
|
// ─── Both names exist for each pair ──────────────────────────────────────────
|
|
50
49
|
|
|
@@ -20,7 +20,6 @@ export interface PlanSliceTaskInput {
|
|
|
20
20
|
inputs: string[];
|
|
21
21
|
expectedOutput: string[];
|
|
22
22
|
observabilityImpact?: string;
|
|
23
|
-
fullPlanMd?: string;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
export interface PlanSliceParams {
|
|
@@ -168,7 +167,6 @@ export async function handlePlanSlice(
|
|
|
168
167
|
inputs: task.inputs,
|
|
169
168
|
expectedOutput: task.expectedOutput,
|
|
170
169
|
observabilityImpact: task.observabilityImpact ?? "",
|
|
171
|
-
fullPlanMd: task.fullPlanMd,
|
|
172
170
|
});
|
|
173
171
|
}
|
|
174
172
|
});
|
|
@@ -15,7 +15,6 @@ export interface PlanTaskParams {
|
|
|
15
15
|
inputs: string[];
|
|
16
16
|
expectedOutput: string[];
|
|
17
17
|
observabilityImpact?: string;
|
|
18
|
-
fullPlanMd?: string;
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
export interface PlanTaskResult {
|
|
@@ -95,7 +94,6 @@ export async function handlePlanTask(
|
|
|
95
94
|
inputs: params.inputs,
|
|
96
95
|
expectedOutput: params.expectedOutput,
|
|
97
96
|
observabilityImpact: params.observabilityImpact ?? "",
|
|
98
|
-
fullPlanMd: params.fullPlanMd,
|
|
99
97
|
});
|
|
100
98
|
});
|
|
101
99
|
} catch (err) {
|
|
@@ -21,7 +21,6 @@ export interface ReplanSliceTaskInput {
|
|
|
21
21
|
verify: string;
|
|
22
22
|
inputs: string[];
|
|
23
23
|
expectedOutput: string[];
|
|
24
|
-
fullPlanMd?: string;
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
export interface ReplanSliceParams {
|
|
@@ -137,7 +136,6 @@ export async function handleReplanSlice(
|
|
|
137
136
|
verify: updatedTask.verify || "",
|
|
138
137
|
inputs: updatedTask.inputs || [],
|
|
139
138
|
expectedOutput: updatedTask.expectedOutput || [],
|
|
140
|
-
fullPlanMd: updatedTask.fullPlanMd,
|
|
141
139
|
});
|
|
142
140
|
} else {
|
|
143
141
|
// Insert new task then set planning fields
|
|
@@ -156,7 +154,6 @@ export async function handleReplanSlice(
|
|
|
156
154
|
verify: updatedTask.verify || "",
|
|
157
155
|
inputs: updatedTask.inputs || [],
|
|
158
156
|
expectedOutput: updatedTask.expectedOutput || [],
|
|
159
|
-
fullPlanMd: updatedTask.fullPlanMd,
|
|
160
157
|
});
|
|
161
158
|
}
|
|
162
159
|
}
|
|
@@ -17,7 +17,6 @@ import { existsSync, unlinkSync } from "node:fs";
|
|
|
17
17
|
import { join } from "node:path";
|
|
18
18
|
import type { AutoSession } from "./auto/session.js";
|
|
19
19
|
import { debugLog } from "./debug-logger.js";
|
|
20
|
-
import { MergeConflictError } from "./git-service.js";
|
|
21
20
|
|
|
22
21
|
// ─── Dependency Interface ──────────────────────────────────────────────────
|
|
23
22
|
|
|
@@ -434,12 +433,6 @@ export class WorktreeResolver {
|
|
|
434
433
|
/* best-effort */
|
|
435
434
|
}
|
|
436
435
|
}
|
|
437
|
-
|
|
438
|
-
// Re-throw MergeConflictError so the auto loop can detect real code
|
|
439
|
-
// conflicts and stop instead of retrying forever (#2330).
|
|
440
|
-
if (err instanceof MergeConflictError) {
|
|
441
|
-
throw err;
|
|
442
|
-
}
|
|
443
436
|
}
|
|
444
437
|
|
|
445
438
|
// Always restore basePath and rebuild — whether merge succeeded or failed
|
|
@@ -213,26 +213,6 @@ function formatToolList(serverName: string, tools: McpToolSchema[]): string {
|
|
|
213
213
|
return lines.join("\n");
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
// ─── Status helper (consumed by /gsd mcp) ─────────────────────────────────────
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Return the live connection status for a named MCP server.
|
|
220
|
-
* Safe to call even when the server has never been connected.
|
|
221
|
-
*/
|
|
222
|
-
export function getConnectionStatus(name: string): {
|
|
223
|
-
connected: boolean;
|
|
224
|
-
tools: string[];
|
|
225
|
-
error?: string;
|
|
226
|
-
} {
|
|
227
|
-
const conn = connections.get(name);
|
|
228
|
-
const cached = toolCache.get(name);
|
|
229
|
-
return {
|
|
230
|
-
connected: !!conn,
|
|
231
|
-
tools: cached ? cached.map((t) => t.name) : [],
|
|
232
|
-
error: undefined,
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
|
|
236
216
|
// ─── Extension ────────────────────────────────────────────────────────────────
|
|
237
217
|
|
|
238
218
|
export default function (pi: ExtensionAPI) {
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP Status — `/gsd mcp` command handler.
|
|
3
|
-
*
|
|
4
|
-
* Shows configured MCP servers, their connection status, and available tools.
|
|
5
|
-
*
|
|
6
|
-
* Subcommands:
|
|
7
|
-
* /gsd mcp — Overview of all servers (alias: /gsd mcp status)
|
|
8
|
-
* /gsd mcp status — Same as bare /gsd mcp
|
|
9
|
-
* /gsd mcp check <srv> — Detailed status for a specific server
|
|
10
|
-
*/
|
|
11
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
12
|
-
import { join } from "node:path";
|
|
13
|
-
function readMcpConfigs() {
|
|
14
|
-
const servers = [];
|
|
15
|
-
const seen = new Set();
|
|
16
|
-
const configPaths = [
|
|
17
|
-
join(process.cwd(), ".mcp.json"),
|
|
18
|
-
join(process.cwd(), ".gsd", "mcp.json"),
|
|
19
|
-
];
|
|
20
|
-
for (const configPath of configPaths) {
|
|
21
|
-
try {
|
|
22
|
-
if (!existsSync(configPath))
|
|
23
|
-
continue;
|
|
24
|
-
const raw = readFileSync(configPath, "utf-8");
|
|
25
|
-
const data = JSON.parse(raw);
|
|
26
|
-
const mcpServers = (data.mcpServers ?? data.servers);
|
|
27
|
-
if (!mcpServers || typeof mcpServers !== "object")
|
|
28
|
-
continue;
|
|
29
|
-
for (const [name, config] of Object.entries(mcpServers)) {
|
|
30
|
-
if (seen.has(name))
|
|
31
|
-
continue;
|
|
32
|
-
seen.add(name);
|
|
33
|
-
const hasCommand = typeof config.command === "string";
|
|
34
|
-
const hasUrl = typeof config.url === "string";
|
|
35
|
-
const transport = hasCommand
|
|
36
|
-
? "stdio"
|
|
37
|
-
: hasUrl
|
|
38
|
-
? "http"
|
|
39
|
-
: "unknown";
|
|
40
|
-
servers.push({
|
|
41
|
-
name,
|
|
42
|
-
transport,
|
|
43
|
-
...(hasCommand && {
|
|
44
|
-
command: config.command,
|
|
45
|
-
args: Array.isArray(config.args) ? config.args : undefined,
|
|
46
|
-
}),
|
|
47
|
-
...(hasUrl && { url: config.url }),
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
// Non-fatal — config file may not exist or be malformed
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return servers;
|
|
56
|
-
}
|
|
57
|
-
// ─── Formatters (exported for testing) ──────────────────────────────────────
|
|
58
|
-
export function formatMcpStatusReport(servers) {
|
|
59
|
-
if (servers.length === 0) {
|
|
60
|
-
return [
|
|
61
|
-
"No MCP servers configured.",
|
|
62
|
-
"",
|
|
63
|
-
"Add servers to .mcp.json or .gsd/mcp.json to enable MCP integrations.",
|
|
64
|
-
"See: https://modelcontextprotocol.io/quickstart",
|
|
65
|
-
].join("\n");
|
|
66
|
-
}
|
|
67
|
-
const lines = [`MCP Server Status — ${servers.length} server(s)\n`];
|
|
68
|
-
for (const s of servers) {
|
|
69
|
-
const icon = s.error ? "✗" : s.connected ? "✓" : "○";
|
|
70
|
-
const status = s.error
|
|
71
|
-
? `error: ${s.error}`
|
|
72
|
-
: s.connected
|
|
73
|
-
? `connected — ${s.toolCount} tools`
|
|
74
|
-
: "disconnected";
|
|
75
|
-
lines.push(` ${icon} ${s.name} (${s.transport}) — ${status}`);
|
|
76
|
-
}
|
|
77
|
-
lines.push("");
|
|
78
|
-
lines.push("Use /gsd mcp check <server> for details on a specific server.");
|
|
79
|
-
lines.push("Use mcp_discover to connect and list tools for a server.");
|
|
80
|
-
return lines.join("\n");
|
|
81
|
-
}
|
|
82
|
-
export function formatMcpServerDetail(server) {
|
|
83
|
-
const lines = [`MCP Server: ${server.name}\n`];
|
|
84
|
-
lines.push(` Transport: ${server.transport}`);
|
|
85
|
-
if (server.error) {
|
|
86
|
-
lines.push(` Status: error`);
|
|
87
|
-
lines.push(` Error: ${server.error}`);
|
|
88
|
-
}
|
|
89
|
-
else if (server.connected) {
|
|
90
|
-
lines.push(` Status: connected`);
|
|
91
|
-
lines.push(` Tools: ${server.toolCount}`);
|
|
92
|
-
if (server.tools.length > 0) {
|
|
93
|
-
lines.push("");
|
|
94
|
-
lines.push(" Available tools:");
|
|
95
|
-
for (const tool of server.tools) {
|
|
96
|
-
lines.push(` - ${tool}`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
lines.push(` Status: disconnected`);
|
|
102
|
-
lines.push("");
|
|
103
|
-
lines.push(` Run mcp_discover("${server.name}") to connect and list tools.`);
|
|
104
|
-
}
|
|
105
|
-
return lines.join("\n");
|
|
106
|
-
}
|
|
107
|
-
// ─── Command handler ────────────────────────────────────────────────────────
|
|
108
|
-
/**
|
|
109
|
-
* Handle `/gsd mcp [status|check <server>]`.
|
|
110
|
-
*/
|
|
111
|
-
export async function handleMcpStatus(args, ctx) {
|
|
112
|
-
const trimmed = args.trim().toLowerCase();
|
|
113
|
-
const configs = readMcpConfigs();
|
|
114
|
-
// /gsd mcp check <server>
|
|
115
|
-
if (trimmed.startsWith("check ")) {
|
|
116
|
-
const serverName = args.trim().slice("check ".length).trim();
|
|
117
|
-
const config = configs.find((c) => c.name === serverName);
|
|
118
|
-
if (!config) {
|
|
119
|
-
const available = configs.map((c) => c.name).join(", ") || "(none)";
|
|
120
|
-
ctx.ui.notify(`Unknown MCP server: "${serverName}"\n\nAvailable: ${available}`, "warning");
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
// Try to get connection/tool info from the mcp-client module if available
|
|
124
|
-
let connected = false;
|
|
125
|
-
let toolNames = [];
|
|
126
|
-
let error;
|
|
127
|
-
try {
|
|
128
|
-
const mcpClient = await import("../mcp-client/index.js");
|
|
129
|
-
// Access the module's connection state if exported; fall back gracefully
|
|
130
|
-
const mod = mcpClient;
|
|
131
|
-
if (typeof mod.getConnectionStatus === "function") {
|
|
132
|
-
const status = mod.getConnectionStatus(serverName);
|
|
133
|
-
connected = status.connected;
|
|
134
|
-
toolNames = status.tools;
|
|
135
|
-
error = status.error;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
catch {
|
|
139
|
-
// mcp-client may not expose status helpers — that's fine
|
|
140
|
-
}
|
|
141
|
-
ctx.ui.notify(formatMcpServerDetail({
|
|
142
|
-
name: config.name,
|
|
143
|
-
transport: config.transport,
|
|
144
|
-
connected,
|
|
145
|
-
toolCount: toolNames.length,
|
|
146
|
-
tools: toolNames,
|
|
147
|
-
error,
|
|
148
|
-
}), "info");
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
// /gsd mcp or /gsd mcp status
|
|
152
|
-
if (!trimmed || trimmed === "status") {
|
|
153
|
-
// Build status for each server
|
|
154
|
-
const statuses = [];
|
|
155
|
-
for (const config of configs) {
|
|
156
|
-
let connected = false;
|
|
157
|
-
let toolCount = 0;
|
|
158
|
-
let error;
|
|
159
|
-
try {
|
|
160
|
-
const mcpClient = await import("../mcp-client/index.js");
|
|
161
|
-
const mod = mcpClient;
|
|
162
|
-
if (typeof mod.getConnectionStatus === "function") {
|
|
163
|
-
const status = mod.getConnectionStatus(config.name);
|
|
164
|
-
connected = status.connected;
|
|
165
|
-
toolCount = status.tools.length;
|
|
166
|
-
error = status.error;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
catch {
|
|
170
|
-
// Fall back to unknown state
|
|
171
|
-
}
|
|
172
|
-
statuses.push({
|
|
173
|
-
name: config.name,
|
|
174
|
-
transport: config.transport,
|
|
175
|
-
connected,
|
|
176
|
-
toolCount,
|
|
177
|
-
error,
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
ctx.ui.notify(formatMcpStatusReport(statuses), "info");
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
// Unknown subcommand
|
|
184
|
-
ctx.ui.notify("Usage: /gsd mcp [status|check <server>]\n\n" +
|
|
185
|
-
" status Show all MCP server statuses (default)\n" +
|
|
186
|
-
" check <server> Detailed status for a specific server", "warning");
|
|
187
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* validate-milestone handler — the core operation behind gsd_validate_milestone.
|
|
3
|
-
*
|
|
4
|
-
* Persists milestone validation results to the assessments table,
|
|
5
|
-
* renders VALIDATION.md to disk, and invalidates caches.
|
|
6
|
-
*/
|
|
7
|
-
import { join } from "node:path";
|
|
8
|
-
import { transaction, _getAdapter, } from "../gsd-db.js";
|
|
9
|
-
import { resolveMilestonePath, clearPathCache } from "../paths.js";
|
|
10
|
-
import { saveFile, clearParseCache } from "../files.js";
|
|
11
|
-
import { invalidateStateCache } from "../state.js";
|
|
12
|
-
function renderValidationMarkdown(params) {
|
|
13
|
-
let md = `---
|
|
14
|
-
verdict: ${params.verdict}
|
|
15
|
-
remediation_round: ${params.remediationRound}
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
# Milestone Validation: ${params.milestoneId}
|
|
19
|
-
|
|
20
|
-
## Success Criteria Checklist
|
|
21
|
-
${params.successCriteriaChecklist}
|
|
22
|
-
|
|
23
|
-
## Slice Delivery Audit
|
|
24
|
-
${params.sliceDeliveryAudit}
|
|
25
|
-
|
|
26
|
-
## Cross-Slice Integration
|
|
27
|
-
${params.crossSliceIntegration}
|
|
28
|
-
|
|
29
|
-
## Requirement Coverage
|
|
30
|
-
${params.requirementCoverage}
|
|
31
|
-
|
|
32
|
-
## Verdict Rationale
|
|
33
|
-
${params.verdictRationale}
|
|
34
|
-
`;
|
|
35
|
-
if (params.verdict === "needs-remediation" && params.remediationPlan) {
|
|
36
|
-
md += `\n## Remediation Plan\n${params.remediationPlan}\n`;
|
|
37
|
-
}
|
|
38
|
-
return md;
|
|
39
|
-
}
|
|
40
|
-
export async function handleValidateMilestone(params, basePath) {
|
|
41
|
-
if (!params.milestoneId || typeof params.milestoneId !== "string" || params.milestoneId.trim() === "") {
|
|
42
|
-
return { error: "milestoneId is required and must be a non-empty string" };
|
|
43
|
-
}
|
|
44
|
-
const validVerdicts = ["pass", "needs-attention", "needs-remediation"];
|
|
45
|
-
if (!validVerdicts.includes(params.verdict)) {
|
|
46
|
-
return { error: `verdict must be one of: ${validVerdicts.join(", ")}` };
|
|
47
|
-
}
|
|
48
|
-
// ── Filesystem render ──────────────────────────────────────────────────
|
|
49
|
-
const validationMd = renderValidationMarkdown(params);
|
|
50
|
-
let validationPath;
|
|
51
|
-
const milestoneDir = resolveMilestonePath(basePath, params.milestoneId);
|
|
52
|
-
if (milestoneDir) {
|
|
53
|
-
validationPath = join(milestoneDir, `${params.milestoneId}-VALIDATION.md`);
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
const gsdDir = join(basePath, ".gsd");
|
|
57
|
-
const manualDir = join(gsdDir, "milestones", params.milestoneId);
|
|
58
|
-
validationPath = join(manualDir, `${params.milestoneId}-VALIDATION.md`);
|
|
59
|
-
}
|
|
60
|
-
try {
|
|
61
|
-
await saveFile(validationPath, validationMd);
|
|
62
|
-
}
|
|
63
|
-
catch (renderErr) {
|
|
64
|
-
process.stderr.write(`gsd-db: validate_milestone — disk render failed: ${renderErr.message}\n`);
|
|
65
|
-
return { error: `disk render failed: ${renderErr.message}` };
|
|
66
|
-
}
|
|
67
|
-
// ── DB write — store in assessments table ──────────────────────────────
|
|
68
|
-
const validatedAt = new Date().toISOString();
|
|
69
|
-
transaction(() => {
|
|
70
|
-
const adapter = _getAdapter();
|
|
71
|
-
adapter.prepare(`INSERT OR REPLACE INTO assessments (path, milestone_id, slice_id, task_id, status, scope, full_content, created_at)
|
|
72
|
-
VALUES (:path, :mid, NULL, NULL, :verdict, 'milestone-validation', :content, :created_at)`).run({
|
|
73
|
-
":path": validationPath,
|
|
74
|
-
":mid": params.milestoneId,
|
|
75
|
-
":verdict": params.verdict,
|
|
76
|
-
":content": validationMd,
|
|
77
|
-
":created_at": validatedAt,
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
invalidateStateCache();
|
|
81
|
-
clearPathCache();
|
|
82
|
-
clearParseCache();
|
|
83
|
-
return {
|
|
84
|
-
milestoneId: params.milestoneId,
|
|
85
|
-
verdict: params.verdict,
|
|
86
|
-
validationPath,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* local-model-check.ts — Utility to detect if a model baseUrl is local.
|
|
3
|
-
*
|
|
4
|
-
* Leaf module with zero transitive dependencies on TypeScript parameter properties.
|
|
5
|
-
* Used by ModelRegistry and tests.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Check if a model's baseUrl points to a local endpoint.
|
|
9
|
-
* Returns true for localhost, 127.0.0.1, 0.0.0.0, ::1, or unix socket paths.
|
|
10
|
-
* Returns false if baseUrl is empty (cloud provider) or points to a remote host.
|
|
11
|
-
*/
|
|
12
|
-
export declare function isLocalModel(model: {
|
|
13
|
-
baseUrl: string;
|
|
14
|
-
}): boolean;
|
|
15
|
-
//# sourceMappingURL=local-model-check.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"local-model-check.d.ts","sourceRoot":"","sources":["../../src/core/local-model-check.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAgChE"}
|