gsd-pi 2.60.0-dev.d9052f5 → 2.61.0-dev.7aed0bf
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/ask-user-questions.js +7 -4
- package/dist/resources/extensions/gsd/auto/phases.js +15 -7
- package/dist/resources/extensions/gsd/auto-dashboard.js +21 -8
- package/dist/resources/extensions/gsd/auto-dispatch.js +6 -3
- package/dist/resources/extensions/gsd/auto-model-selection.js +58 -9
- package/dist/resources/extensions/gsd/auto-post-unit.js +3 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +36 -20
- package/dist/resources/extensions/gsd/auto-recovery.js +37 -18
- package/dist/resources/extensions/gsd/auto-start.js +9 -5
- package/dist/resources/extensions/gsd/auto-timers.js +11 -5
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +5 -3
- package/dist/resources/extensions/gsd/auto-verification.js +3 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +120 -55
- package/dist/resources/extensions/gsd/auto.js +39 -17
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +6 -3
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +2 -2
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +4 -10
- package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +2 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +11 -10
- package/dist/resources/extensions/gsd/commands/catalog.js +2 -0
- package/dist/resources/extensions/gsd/commands-codebase.js +48 -21
- package/dist/resources/extensions/gsd/commands-inspect.js +2 -1
- package/dist/resources/extensions/gsd/commands-maintenance.js +32 -19
- package/dist/resources/extensions/gsd/complexity-classifier.js +8 -4
- package/dist/resources/extensions/gsd/custom-verification.js +3 -2
- package/dist/resources/extensions/gsd/gsd-db.js +33 -13
- package/dist/resources/extensions/gsd/guided-flow.js +19 -9
- package/dist/resources/extensions/gsd/init-wizard.js +12 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +11 -9
- package/dist/resources/extensions/gsd/md-importer.js +5 -4
- package/dist/resources/extensions/gsd/milestone-actions.js +3 -2
- package/dist/resources/extensions/gsd/milestone-ids.js +2 -1
- package/dist/resources/extensions/gsd/model-router.js +156 -121
- package/dist/resources/extensions/gsd/parallel-merge.js +5 -3
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +26 -14
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +45 -0
- package/dist/resources/extensions/gsd/preferences.js +15 -3
- package/dist/resources/extensions/gsd/prompt-loader.js +3 -2
- package/dist/resources/extensions/gsd/prompts/rethink.md +1 -1
- package/dist/resources/extensions/gsd/rule-registry.js +7 -6
- package/dist/resources/extensions/gsd/safe-fs.js +6 -8
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +3 -2
- package/dist/resources/extensions/gsd/tools/complete-task.js +3 -2
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +3 -2
- package/dist/resources/extensions/gsd/tools/plan-slice.js +3 -2
- package/dist/resources/extensions/gsd/tools/plan-task.js +2 -1
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +4 -4
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +2 -1
- package/dist/resources/extensions/gsd/tools/reopen-task.js +2 -1
- package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -1
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +2 -1
- package/dist/resources/extensions/gsd/triage-resolution.js +11 -4
- package/dist/resources/extensions/gsd/workflow-events.js +2 -1
- package/dist/resources/extensions/gsd/workflow-logger.js +37 -4
- package/dist/resources/extensions/gsd/workflow-migration.js +14 -12
- package/dist/resources/extensions/gsd/workflow-projections.js +2 -2
- package/dist/resources/extensions/gsd/workflow-reconcile.js +2 -2
- package/dist/resources/extensions/gsd/worktree-manager.js +26 -14
- package/dist/resources/extensions/shared/interview-ui.js +3 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +19 -19
- 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 +19 -19
- 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/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +5 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +16 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +26 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/config.js +6 -1
- package/packages/pi-coding-agent/dist/core/lsp/config.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/defaults.json +2 -2
- package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.js +47 -0
- package/packages/pi-coding-agent/dist/core/lsp/lsp-legacy-alias.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +6 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +19 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +26 -0
- package/packages/pi-coding-agent/src/core/lsp/config.ts +7 -1
- package/packages/pi-coding-agent/src/core/lsp/defaults.json +2 -2
- package/packages/pi-coding-agent/src/core/lsp/lsp-legacy-alias.test.ts +70 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/ask-user-questions.ts +7 -3
- package/src/resources/extensions/gsd/auto/phases.ts +17 -7
- package/src/resources/extensions/gsd/auto-dashboard.ts +22 -8
- package/src/resources/extensions/gsd/auto-dispatch.ts +7 -3
- package/src/resources/extensions/gsd/auto-model-selection.ts +77 -15
- package/src/resources/extensions/gsd/auto-post-unit.ts +4 -4
- package/src/resources/extensions/gsd/auto-prompts.ts +37 -20
- package/src/resources/extensions/gsd/auto-recovery.ts +38 -18
- package/src/resources/extensions/gsd/auto-start.ts +10 -9
- package/src/resources/extensions/gsd/auto-timers.ts +12 -5
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +6 -2
- package/src/resources/extensions/gsd/auto-verification.ts +3 -6
- package/src/resources/extensions/gsd/auto-worktree.ts +121 -55
- package/src/resources/extensions/gsd/auto.ts +40 -17
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +4 -3
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +2 -2
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +4 -16
- package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +2 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +8 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -10
- package/src/resources/extensions/gsd/commands/catalog.ts +2 -0
- package/src/resources/extensions/gsd/commands-codebase.ts +52 -20
- package/src/resources/extensions/gsd/commands-inspect.ts +2 -1
- package/src/resources/extensions/gsd/commands-maintenance.ts +28 -19
- package/src/resources/extensions/gsd/complexity-classifier.ts +9 -4
- package/src/resources/extensions/gsd/custom-verification.ts +3 -2
- package/src/resources/extensions/gsd/gsd-db.ts +12 -14
- package/src/resources/extensions/gsd/guided-flow.ts +9 -8
- package/src/resources/extensions/gsd/init-wizard.ts +12 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +11 -17
- package/src/resources/extensions/gsd/md-importer.ts +5 -4
- package/src/resources/extensions/gsd/milestone-actions.ts +3 -2
- package/src/resources/extensions/gsd/milestone-ids.ts +2 -1
- package/src/resources/extensions/gsd/model-router.ts +199 -173
- package/src/resources/extensions/gsd/parallel-merge.ts +5 -3
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +18 -14
- package/src/resources/extensions/gsd/preferences-types.ts +13 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +45 -0
- package/src/resources/extensions/gsd/preferences.ts +16 -3
- package/src/resources/extensions/gsd/prompt-loader.ts +3 -2
- package/src/resources/extensions/gsd/prompts/rethink.md +1 -1
- package/src/resources/extensions/gsd/rule-registry.ts +7 -6
- package/src/resources/extensions/gsd/safe-fs.ts +6 -5
- package/src/resources/extensions/gsd/tests/capability-router.test.ts +347 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +27 -2
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +1188 -0
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +841 -0
- package/src/resources/extensions/gsd/tests/model-router.test.ts +403 -3
- package/src/resources/extensions/gsd/tests/preferences.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +284 -0
- package/src/resources/extensions/gsd/tests/workflow-logger-audit.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +6 -6
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -6
- package/src/resources/extensions/gsd/tools/complete-slice.ts +3 -6
- package/src/resources/extensions/gsd/tools/complete-task.ts +3 -6
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +3 -6
- package/src/resources/extensions/gsd/tools/plan-slice.ts +3 -6
- package/src/resources/extensions/gsd/tools/plan-task.ts +2 -3
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +4 -6
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +2 -3
- package/src/resources/extensions/gsd/tools/reopen-task.ts +2 -3
- package/src/resources/extensions/gsd/tools/replan-slice.ts +2 -3
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +2 -3
- package/src/resources/extensions/gsd/triage-resolution.ts +11 -4
- package/src/resources/extensions/gsd/types.ts +1 -0
- package/src/resources/extensions/gsd/workflow-events.ts +2 -1
- package/src/resources/extensions/gsd/workflow-logger.ts +52 -5
- package/src/resources/extensions/gsd/workflow-migration.ts +14 -12
- package/src/resources/extensions/gsd/workflow-projections.ts +2 -2
- package/src/resources/extensions/gsd/workflow-reconcile.ts +2 -2
- package/src/resources/extensions/gsd/worktree-manager.ts +16 -14
- package/src/resources/extensions/shared/interview-ui.ts +3 -1
- package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +144 -0
- /package/dist/web/standalone/.next/static/{JVkoVYumy0cDhOQISEYdG → b7FOoMHaUb3FPoLNbxar4}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{JVkoVYumy0cDhOQISEYdG → b7FOoMHaUb3FPoLNbxar4}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify that catch blocks across GSD source files use the centralized
|
|
3
|
+
* workflow-logger (logWarning/logError) instead of raw process.stderr.write,
|
|
4
|
+
* console.error, or being completely empty (#3348, #3345).
|
|
5
|
+
*
|
|
6
|
+
* Two tests:
|
|
7
|
+
* 1. Auto-mode files must have zero empty catch blocks (fully migrated).
|
|
8
|
+
* 2. All GSD files must not use raw stderr/console in catch blocks.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, test } from "node:test";
|
|
12
|
+
import assert from "node:assert/strict";
|
|
13
|
+
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
14
|
+
import { join, dirname, relative } from "node:path";
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
|
|
17
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
const gsdDir = join(__dirname, "..");
|
|
19
|
+
|
|
20
|
+
/** Files exempt from the raw-stderr/console check */
|
|
21
|
+
const EXEMPT_FILES = new Set([
|
|
22
|
+
"workflow-logger.ts", // The logger itself
|
|
23
|
+
"debug-logger.ts", // Separate opt-in debug system
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Files that have been fully migrated to workflow-logger and must not
|
|
28
|
+
* regress to empty catch blocks. Covers auto-mode, tools, bootstrap,
|
|
29
|
+
* and core infrastructure files.
|
|
30
|
+
*/
|
|
31
|
+
const MIGRATED_FILES = new Set([
|
|
32
|
+
// auto-mode (detected dynamically below)
|
|
33
|
+
// tools/
|
|
34
|
+
"tools/complete-task.ts",
|
|
35
|
+
"tools/complete-slice.ts",
|
|
36
|
+
"tools/complete-milestone.ts",
|
|
37
|
+
"tools/plan-milestone.ts",
|
|
38
|
+
"tools/plan-slice.ts",
|
|
39
|
+
"tools/plan-task.ts",
|
|
40
|
+
"tools/reassess-roadmap.ts",
|
|
41
|
+
"tools/reopen-task.ts",
|
|
42
|
+
"tools/reopen-slice.ts",
|
|
43
|
+
"tools/replan-slice.ts",
|
|
44
|
+
"tools/validate-milestone.ts",
|
|
45
|
+
// bootstrap/
|
|
46
|
+
"bootstrap/agent-end-recovery.ts",
|
|
47
|
+
"bootstrap/system-context.ts",
|
|
48
|
+
"bootstrap/db-tools.ts",
|
|
49
|
+
"bootstrap/dynamic-tools.ts",
|
|
50
|
+
"bootstrap/journal-tools.ts",
|
|
51
|
+
// core infrastructure
|
|
52
|
+
"gsd-db.ts",
|
|
53
|
+
"workflow-logger.ts",
|
|
54
|
+
"workflow-reconcile.ts",
|
|
55
|
+
"workflow-migration.ts",
|
|
56
|
+
"workflow-projections.ts",
|
|
57
|
+
"workflow-events.ts",
|
|
58
|
+
"worktree-manager.ts",
|
|
59
|
+
"parallel-orchestrator.ts",
|
|
60
|
+
"parallel-merge.ts",
|
|
61
|
+
"guided-flow.ts",
|
|
62
|
+
"preferences.ts",
|
|
63
|
+
"commands-maintenance.ts",
|
|
64
|
+
"commands-inspect.ts",
|
|
65
|
+
"safe-fs.ts",
|
|
66
|
+
"markdown-renderer.ts",
|
|
67
|
+
"md-importer.ts",
|
|
68
|
+
"milestone-actions.ts",
|
|
69
|
+
"milestone-ids.ts",
|
|
70
|
+
"rule-registry.ts",
|
|
71
|
+
"custom-verification.ts",
|
|
72
|
+
"prompt-loader.ts",
|
|
73
|
+
"auto-verification.ts",
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
/** Patterns that indicate a catch block already uses workflow-logger */
|
|
77
|
+
const LOGGER_PATTERNS = [
|
|
78
|
+
/logWarning\s*\(/,
|
|
79
|
+
/logError\s*\(/,
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
function getAutoModeFiles(): string[] {
|
|
83
|
+
const files: string[] = [];
|
|
84
|
+
|
|
85
|
+
// Top-level auto*.ts files
|
|
86
|
+
for (const f of readdirSync(gsdDir)) {
|
|
87
|
+
if (f.startsWith("auto") && f.endsWith(".ts") && !f.endsWith(".test.ts")) {
|
|
88
|
+
files.push(join(gsdDir, f));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// auto/ subdirectory
|
|
93
|
+
const autoSubDir = join(gsdDir, "auto");
|
|
94
|
+
for (const f of readdirSync(autoSubDir)) {
|
|
95
|
+
if (f.endsWith(".ts") && !f.endsWith(".test.ts")) {
|
|
96
|
+
files.push(join(autoSubDir, f));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return files;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function getGsdSourceFiles(): string[] {
|
|
104
|
+
const files: string[] = [];
|
|
105
|
+
|
|
106
|
+
function walk(dir: string): void {
|
|
107
|
+
for (const entry of readdirSync(dir)) {
|
|
108
|
+
const full = join(dir, entry);
|
|
109
|
+
if (entry === "tests" || entry === "node_modules") continue;
|
|
110
|
+
try {
|
|
111
|
+
const st = statSync(full);
|
|
112
|
+
if (st.isDirectory()) {
|
|
113
|
+
walk(full);
|
|
114
|
+
} else if (entry.endsWith(".ts") && !entry.endsWith(".test.ts") && !entry.endsWith(".d.ts")) {
|
|
115
|
+
files.push(full);
|
|
116
|
+
}
|
|
117
|
+
} catch {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
walk(gsdDir);
|
|
124
|
+
return files;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Scan a file for empty catch blocks — catches whose body contains
|
|
129
|
+
* only whitespace and/or comments but no executable statements.
|
|
130
|
+
*/
|
|
131
|
+
function findEmptyCatches(filePath: string): Array<{ line: number; text: string }> {
|
|
132
|
+
const content = readFileSync(filePath, "utf-8");
|
|
133
|
+
const lines = content.split("\n");
|
|
134
|
+
const results: Array<{ line: number; text: string }> = [];
|
|
135
|
+
|
|
136
|
+
for (let i = 0; i < lines.length; i++) {
|
|
137
|
+
const line = lines[i];
|
|
138
|
+
|
|
139
|
+
// Match catch block opening
|
|
140
|
+
if (!/\}\s*catch\s*(\([^)]*\))?\s*\{/.test(line)) continue;
|
|
141
|
+
|
|
142
|
+
// Inline single-line catch: } catch { ... }
|
|
143
|
+
const inlineMatch = line.match(/\}\s*catch\s*(\([^)]*\))?\s*\{(.*)\}\s*;?\s*$/);
|
|
144
|
+
if (inlineMatch) {
|
|
145
|
+
const body = inlineMatch[2].trim();
|
|
146
|
+
const stripped = body.replace(/\/\*.*?\*\//g, "").replace(/\/\/.*/g, "").trim();
|
|
147
|
+
if (!stripped) {
|
|
148
|
+
results.push({ line: i + 1, text: line.trim() });
|
|
149
|
+
}
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Multi-line catch — scan until matching }
|
|
154
|
+
let j = i + 1;
|
|
155
|
+
let depth = 1;
|
|
156
|
+
const bodyLines: string[] = [];
|
|
157
|
+
while (j < lines.length && depth > 0) {
|
|
158
|
+
for (const ch of lines[j]) {
|
|
159
|
+
if (ch === "{") depth++;
|
|
160
|
+
else if (ch === "}") depth--;
|
|
161
|
+
}
|
|
162
|
+
bodyLines.push(lines[j].trim());
|
|
163
|
+
j++;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const meaningful = bodyLines.slice(0, -1).filter(
|
|
167
|
+
(l) => l && !l.startsWith("//") && !l.startsWith("/*") && !l.startsWith("*") && l !== "}",
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
if (meaningful.length === 0) {
|
|
171
|
+
results.push({ line: i + 1, text: line.trim() });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return results;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Scan a file for catch blocks that use raw process.stderr.write or
|
|
180
|
+
* console.error/warn instead of workflow-logger.
|
|
181
|
+
*/
|
|
182
|
+
function findRawStderrCatches(filePath: string): Array<{ line: number; text: string }> {
|
|
183
|
+
const content = readFileSync(filePath, "utf-8");
|
|
184
|
+
const lines = content.split("\n");
|
|
185
|
+
const results: Array<{ line: number; text: string }> = [];
|
|
186
|
+
|
|
187
|
+
for (let i = 0; i < lines.length; i++) {
|
|
188
|
+
const line = lines[i];
|
|
189
|
+
if (!/\}\s*catch\s*(\([^)]*\))?\s*\{/.test(line)) continue;
|
|
190
|
+
|
|
191
|
+
// Inline single-line catch
|
|
192
|
+
const inlineMatch = line.match(/\}\s*catch\s*(\([^)]*\))?\s*\{(.*)\}\s*;?\s*$/);
|
|
193
|
+
if (inlineMatch) {
|
|
194
|
+
const body = inlineMatch[2];
|
|
195
|
+
if (!LOGGER_PATTERNS.some((p) => p.test(body))) {
|
|
196
|
+
if (/process\.stderr\.write/.test(body) || /console\.(error|warn)/.test(body)) {
|
|
197
|
+
results.push({ line: i + 1, text: line.trim() });
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Multi-line catch
|
|
204
|
+
let j = i + 1;
|
|
205
|
+
let depth = 1;
|
|
206
|
+
const bodyLines: string[] = [];
|
|
207
|
+
while (j < lines.length && depth > 0) {
|
|
208
|
+
for (const ch of lines[j]) {
|
|
209
|
+
if (ch === "{") depth++;
|
|
210
|
+
else if (ch === "}") depth--;
|
|
211
|
+
}
|
|
212
|
+
bodyLines.push(lines[j]);
|
|
213
|
+
j++;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const bodyText = bodyLines.slice(0, -1).join("\n");
|
|
217
|
+
if (!LOGGER_PATTERNS.some((p) => p.test(bodyText))) {
|
|
218
|
+
if (/process\.stderr\.write/.test(bodyText) || /console\.(error|warn)/.test(bodyText)) {
|
|
219
|
+
results.push({ line: i + 1, text: line.trim() });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return results;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
describe("workflow-logger coverage (#3348)", () => {
|
|
228
|
+
test("no empty catch blocks remain in migrated files", () => {
|
|
229
|
+
// Combine auto-mode files + explicitly migrated files
|
|
230
|
+
const autoFiles = getAutoModeFiles();
|
|
231
|
+
const allFiles = getGsdSourceFiles();
|
|
232
|
+
const migratedPaths = new Set(autoFiles);
|
|
233
|
+
for (const file of allFiles) {
|
|
234
|
+
const rel = relative(gsdDir, file);
|
|
235
|
+
if (MIGRATED_FILES.has(rel)) {
|
|
236
|
+
migratedPaths.add(file);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
assert.ok(migratedPaths.size > 0, "should find migrated source files");
|
|
241
|
+
|
|
242
|
+
const violations: string[] = [];
|
|
243
|
+
for (const file of migratedPaths) {
|
|
244
|
+
const rel = relative(gsdDir, file);
|
|
245
|
+
const basename = rel.split("/").pop()!;
|
|
246
|
+
// gsd-db.ts has intentionally silent provider probes
|
|
247
|
+
if (basename === "gsd-db.ts" || basename === "session-lock.ts") continue;
|
|
248
|
+
|
|
249
|
+
const empties = findEmptyCatches(file);
|
|
250
|
+
for (const empty of empties) {
|
|
251
|
+
violations.push(`${rel}:${empty.line} — ${empty.text}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
assert.equal(
|
|
256
|
+
violations.length,
|
|
257
|
+
0,
|
|
258
|
+
`Found ${violations.length} empty catch block(s) in migrated files:\n${violations.join("\n")}`,
|
|
259
|
+
);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
test("catch blocks use workflow-logger instead of raw stderr/console", () => {
|
|
263
|
+
const files = getGsdSourceFiles();
|
|
264
|
+
assert.ok(files.length > 0, "should find GSD source files");
|
|
265
|
+
|
|
266
|
+
const violations: string[] = [];
|
|
267
|
+
for (const file of files) {
|
|
268
|
+
const rel = relative(gsdDir, file);
|
|
269
|
+
const basename = rel.split("/").pop()!;
|
|
270
|
+
if (EXEMPT_FILES.has(basename)) continue;
|
|
271
|
+
|
|
272
|
+
const issues = findRawStderrCatches(file);
|
|
273
|
+
for (const issue of issues) {
|
|
274
|
+
violations.push(`${rel}:${issue.line} — ${issue.text}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
assert.equal(
|
|
279
|
+
violations.length,
|
|
280
|
+
0,
|
|
281
|
+
`Found ${violations.length} catch block(s) using raw stderr/console instead of workflow-logger:\n${violations.join("\n")}`,
|
|
282
|
+
);
|
|
283
|
+
});
|
|
284
|
+
});
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// GSD Extension — Workflow Logger Audit Persistence Tests
|
|
2
|
+
// Validates error-only persistence, sanitization, and warning ephemeral behavior.
|
|
3
|
+
|
|
4
|
+
import { describe, test, beforeEach, afterEach } from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
import { mkdtempSync, mkdirSync, readFileSync, existsSync, rmSync } from "node:fs";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
logWarning,
|
|
12
|
+
logError,
|
|
13
|
+
setLogBasePath,
|
|
14
|
+
_resetLogs,
|
|
15
|
+
peekLogs,
|
|
16
|
+
drainLogs,
|
|
17
|
+
} from "../workflow-logger.ts";
|
|
18
|
+
|
|
19
|
+
function createTempProject(): string {
|
|
20
|
+
const tmp = mkdtempSync(join(tmpdir(), "gsd-wflog-test-"));
|
|
21
|
+
mkdirSync(join(tmp, ".gsd"), { recursive: true });
|
|
22
|
+
return tmp;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function readAuditLines(basePath: string): Record<string, unknown>[] {
|
|
26
|
+
const auditPath = join(basePath, ".gsd", "audit-log.jsonl");
|
|
27
|
+
if (!existsSync(auditPath)) return [];
|
|
28
|
+
const content = readFileSync(auditPath, "utf-8").trim();
|
|
29
|
+
if (!content) return [];
|
|
30
|
+
return content.split("\n").map((line) => JSON.parse(line));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe("workflow-logger audit persistence", () => {
|
|
34
|
+
let tmp: string;
|
|
35
|
+
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
tmp = createTempProject();
|
|
38
|
+
_resetLogs();
|
|
39
|
+
setLogBasePath(tmp);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterEach(() => {
|
|
43
|
+
_resetLogs();
|
|
44
|
+
setLogBasePath(null as unknown as string);
|
|
45
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("logError persists to audit-log.jsonl", () => {
|
|
49
|
+
logError("engine", "something broke");
|
|
50
|
+
const lines = readAuditLines(tmp);
|
|
51
|
+
assert.equal(lines.length, 1);
|
|
52
|
+
assert.equal(lines[0].severity, "error");
|
|
53
|
+
assert.equal(lines[0].component, "engine");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("logWarning does NOT persist to audit-log.jsonl", () => {
|
|
57
|
+
logWarning("engine", "something fishy");
|
|
58
|
+
const lines = readAuditLines(tmp);
|
|
59
|
+
assert.equal(lines.length, 0, "warnings must not be persisted to audit log");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("logWarning still appears in in-memory buffer", () => {
|
|
63
|
+
logWarning("recovery", "probe miss");
|
|
64
|
+
const entries = peekLogs();
|
|
65
|
+
assert.equal(entries.length, 1);
|
|
66
|
+
assert.equal(entries[0].severity, "warn");
|
|
67
|
+
assert.equal(entries[0].component, "recovery");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("persisted error messages are truncated at 200 chars", () => {
|
|
71
|
+
const longMessage = "x".repeat(300);
|
|
72
|
+
logError("engine", longMessage);
|
|
73
|
+
const lines = readAuditLines(tmp);
|
|
74
|
+
assert.equal(lines.length, 1);
|
|
75
|
+
const msg = lines[0].message as string;
|
|
76
|
+
assert.ok(msg.length <= 215, `message should be truncated, got ${msg.length} chars`);
|
|
77
|
+
assert.ok(msg.endsWith("…[truncated]"));
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("persisted errors have context filtered to safe allowlist", () => {
|
|
81
|
+
logError("tool", "tool failed", {
|
|
82
|
+
fn: "saveDecisionToDb",
|
|
83
|
+
tool: "gsd_decision_save",
|
|
84
|
+
error: "SQLITE_BUSY: database is locked",
|
|
85
|
+
file: "/home/user/project/gsd.db",
|
|
86
|
+
});
|
|
87
|
+
const lines = readAuditLines(tmp);
|
|
88
|
+
assert.equal(lines.length, 1);
|
|
89
|
+
const ctx = lines[0].context as Record<string, string>;
|
|
90
|
+
assert.ok(ctx, "context should exist");
|
|
91
|
+
assert.equal(ctx.fn, "saveDecisionToDb");
|
|
92
|
+
assert.equal(ctx.tool, "gsd_decision_save");
|
|
93
|
+
assert.equal(ctx.error, undefined, "error key must be stripped from persisted context");
|
|
94
|
+
assert.equal(ctx.file, undefined, "file key must be stripped from persisted context");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("persisted errors omit context when no safe keys present", () => {
|
|
98
|
+
logError("bootstrap", "ensureDbOpen failed", {
|
|
99
|
+
error: "ENOENT",
|
|
100
|
+
cwd: "/home/user/project",
|
|
101
|
+
});
|
|
102
|
+
const lines = readAuditLines(tmp);
|
|
103
|
+
assert.equal(lines.length, 1);
|
|
104
|
+
assert.equal(lines[0].context, undefined, "context should be omitted when no safe keys match");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("mixed warnings and errors only persist errors", () => {
|
|
108
|
+
logWarning("recovery", "main not found");
|
|
109
|
+
logWarning("recovery", "master not found");
|
|
110
|
+
logError("engine", "fatal failure");
|
|
111
|
+
logWarning("prompt", "cache miss");
|
|
112
|
+
|
|
113
|
+
const lines = readAuditLines(tmp);
|
|
114
|
+
assert.equal(lines.length, 1, "only the error should be persisted");
|
|
115
|
+
assert.equal(lines[0].severity, "error");
|
|
116
|
+
|
|
117
|
+
const buffered = drainLogs();
|
|
118
|
+
assert.equal(buffered.length, 4, "all entries should be in the in-memory buffer");
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -240,13 +240,13 @@ describe("workflow-logger", () => {
|
|
|
240
240
|
|
|
241
241
|
test("writes entry to .gsd/audit-log.jsonl after setLogBasePath", () => {
|
|
242
242
|
setLogBasePath(dir);
|
|
243
|
-
|
|
243
|
+
logError("engine", "audit test entry");
|
|
244
244
|
|
|
245
245
|
const auditPath = join(dir, ".gsd", "audit-log.jsonl");
|
|
246
246
|
assert.ok(existsSync(auditPath), "audit-log.jsonl should exist");
|
|
247
247
|
const content = readFileSync(auditPath, "utf-8");
|
|
248
248
|
const entry = JSON.parse(content.trim());
|
|
249
|
-
assert.equal(entry.severity, "
|
|
249
|
+
assert.equal(entry.severity, "error");
|
|
250
250
|
assert.equal(entry.component, "engine");
|
|
251
251
|
assert.equal(entry.message, "audit test entry");
|
|
252
252
|
});
|
|
@@ -254,7 +254,7 @@ describe("workflow-logger", () => {
|
|
|
254
254
|
test("_resetLogs does not clear the audit base path", () => {
|
|
255
255
|
setLogBasePath(dir);
|
|
256
256
|
_resetLogs();
|
|
257
|
-
|
|
257
|
+
logError("engine", "post-reset entry");
|
|
258
258
|
|
|
259
259
|
const auditPath = join(dir, ".gsd", "audit-log.jsonl");
|
|
260
260
|
assert.ok(existsSync(auditPath), "audit-log.jsonl should exist after _resetLogs");
|
|
@@ -293,13 +293,13 @@ describe("workflow-logger", () => {
|
|
|
293
293
|
|
|
294
294
|
test("writes entry to .gsd/audit-log.jsonl after setLogBasePath", () => {
|
|
295
295
|
setLogBasePath(dir);
|
|
296
|
-
|
|
296
|
+
logError("engine", "audit test entry");
|
|
297
297
|
|
|
298
298
|
const auditPath = join(dir, ".gsd", "audit-log.jsonl");
|
|
299
299
|
assert.ok(existsSync(auditPath), "audit-log.jsonl should exist");
|
|
300
300
|
const content = readFileSync(auditPath, "utf-8");
|
|
301
301
|
const entry = JSON.parse(content.trim());
|
|
302
|
-
assert.equal(entry.severity, "
|
|
302
|
+
assert.equal(entry.severity, "error");
|
|
303
303
|
assert.equal(entry.component, "engine");
|
|
304
304
|
assert.equal(entry.message, "audit test entry");
|
|
305
305
|
});
|
|
@@ -307,7 +307,7 @@ describe("workflow-logger", () => {
|
|
|
307
307
|
test("_resetLogs does not clear the audit base path", () => {
|
|
308
308
|
setLogBasePath(dir);
|
|
309
309
|
_resetLogs();
|
|
310
|
-
|
|
310
|
+
logError("engine", "post-reset entry");
|
|
311
311
|
|
|
312
312
|
const auditPath = join(dir, ".gsd", "audit-log.jsonl");
|
|
313
313
|
assert.ok(existsSync(auditPath), "audit-log.jsonl should exist after _resetLogs");
|
|
@@ -23,6 +23,7 @@ import { invalidateStateCache } from "../state.js";
|
|
|
23
23
|
import { renderAllProjections } from "../workflow-projections.js";
|
|
24
24
|
import { writeManifest } from "../workflow-manifest.js";
|
|
25
25
|
import { appendEvent } from "../workflow-events.js";
|
|
26
|
+
import { logWarning } from "../workflow-logger.js";
|
|
26
27
|
|
|
27
28
|
export interface CompleteMilestoneParams {
|
|
28
29
|
milestoneId: string;
|
|
@@ -191,9 +192,7 @@ export async function handleCompleteMilestone(
|
|
|
191
192
|
await saveFile(summaryPath, summaryMd);
|
|
192
193
|
} catch (renderErr) {
|
|
193
194
|
// Disk render failed — roll back DB status so state stays consistent
|
|
194
|
-
|
|
195
|
-
`gsd-db: complete_milestone — disk render failed, rolling back DB status: ${(renderErr as Error).message}\n`,
|
|
196
|
-
);
|
|
195
|
+
logWarning("tool", `complete_milestone — disk render failed, rolling back DB status: ${(renderErr as Error).message}`);
|
|
197
196
|
updateMilestoneStatus(params.milestoneId, 'active', null);
|
|
198
197
|
invalidateStateCache();
|
|
199
198
|
return { error: `disk render failed: ${(renderErr as Error).message}` };
|
|
@@ -217,9 +216,7 @@ export async function handleCompleteMilestone(
|
|
|
217
216
|
trigger_reason: params.triggerReason,
|
|
218
217
|
});
|
|
219
218
|
} catch (hookErr) {
|
|
220
|
-
|
|
221
|
-
`gsd: complete-milestone post-mutation hook warning: ${(hookErr as Error).message}\n`,
|
|
222
|
-
);
|
|
219
|
+
logWarning("tool", `complete-milestone post-mutation hook warning: ${(hookErr as Error).message}`);
|
|
223
220
|
}
|
|
224
221
|
|
|
225
222
|
return {
|
|
@@ -30,6 +30,7 @@ import { renderRoadmapCheckboxes } from "../markdown-renderer.js";
|
|
|
30
30
|
import { renderAllProjections } from "../workflow-projections.js";
|
|
31
31
|
import { writeManifest } from "../workflow-manifest.js";
|
|
32
32
|
import { appendEvent } from "../workflow-events.js";
|
|
33
|
+
import { logWarning } from "../workflow-logger.js";
|
|
33
34
|
|
|
34
35
|
export interface CompleteSliceResult {
|
|
35
36
|
sliceId: string;
|
|
@@ -297,9 +298,7 @@ export async function handleCompleteSlice(
|
|
|
297
298
|
}
|
|
298
299
|
} catch (renderErr) {
|
|
299
300
|
// Disk render failed — roll back DB status so state stays consistent
|
|
300
|
-
|
|
301
|
-
`gsd-db: complete_slice — disk render failed, rolling back DB status: ${(renderErr as Error).message}\n`,
|
|
302
|
-
);
|
|
301
|
+
logWarning("tool", `complete_slice — disk render failed, rolling back DB status: ${(renderErr as Error).message}`);
|
|
303
302
|
updateSliceStatus(params.milestoneId, params.sliceId, 'pending');
|
|
304
303
|
invalidateStateCache();
|
|
305
304
|
return { error: `disk render failed: ${(renderErr as Error).message}` };
|
|
@@ -326,9 +325,7 @@ export async function handleCompleteSlice(
|
|
|
326
325
|
trigger_reason: params.triggerReason,
|
|
327
326
|
});
|
|
328
327
|
} catch (hookErr) {
|
|
329
|
-
|
|
330
|
-
`gsd: complete-slice post-mutation hook warning: ${(hookErr as Error).message}\n`,
|
|
331
|
-
);
|
|
328
|
+
logWarning("tool", `complete-slice post-mutation hook warning: ${(hookErr as Error).message}`);
|
|
332
329
|
}
|
|
333
330
|
|
|
334
331
|
return {
|
|
@@ -33,6 +33,7 @@ import { renderPlanCheckboxes } from "../markdown-renderer.js";
|
|
|
33
33
|
import { renderAllProjections, renderSummaryContent } from "../workflow-projections.js";
|
|
34
34
|
import { writeManifest } from "../workflow-manifest.js";
|
|
35
35
|
import { appendEvent } from "../workflow-events.js";
|
|
36
|
+
import { logWarning } from "../workflow-logger.js";
|
|
36
37
|
|
|
37
38
|
export interface CompleteTaskResult {
|
|
38
39
|
taskId: string;
|
|
@@ -210,9 +211,7 @@ export async function handleCompleteTask(
|
|
|
210
211
|
}
|
|
211
212
|
} catch (renderErr) {
|
|
212
213
|
// Disk render failed — roll back DB status so state stays consistent
|
|
213
|
-
|
|
214
|
-
`gsd-db: complete_task — disk render failed, rolling back DB status: ${(renderErr as Error).message}\n`,
|
|
215
|
-
);
|
|
214
|
+
logWarning("tool", `complete_task — disk render failed, rolling back DB status: ${(renderErr as Error).message}`);
|
|
216
215
|
// Delete orphaned verification_evidence rows first (FK constraint
|
|
217
216
|
// references tasks, so evidence must go before status change).
|
|
218
217
|
// Without this, retries accumulate duplicate evidence rows (#2724).
|
|
@@ -243,9 +242,7 @@ export async function handleCompleteTask(
|
|
|
243
242
|
trigger_reason: params.triggerReason,
|
|
244
243
|
});
|
|
245
244
|
} catch (hookErr) {
|
|
246
|
-
|
|
247
|
-
`gsd: complete-task post-mutation hook warning: ${(hookErr as Error).message}\n`,
|
|
248
|
-
);
|
|
245
|
+
logWarning("tool", `complete-task post-mutation hook warning: ${(hookErr as Error).message}`);
|
|
249
246
|
}
|
|
250
247
|
|
|
251
248
|
return {
|
|
@@ -15,6 +15,7 @@ import { renderRoadmapFromDb } from "../markdown-renderer.js";
|
|
|
15
15
|
import { renderAllProjections } from "../workflow-projections.js";
|
|
16
16
|
import { writeManifest } from "../workflow-manifest.js";
|
|
17
17
|
import { appendEvent } from "../workflow-events.js";
|
|
18
|
+
import { logWarning } from "../workflow-logger.js";
|
|
18
19
|
|
|
19
20
|
export interface PlanMilestoneSliceInput {
|
|
20
21
|
sliceId: string;
|
|
@@ -269,9 +270,7 @@ export async function handlePlanMilestone(
|
|
|
269
270
|
const renderResult = await renderRoadmapFromDb(basePath, params.milestoneId);
|
|
270
271
|
roadmapPath = renderResult.roadmapPath;
|
|
271
272
|
} catch (renderErr) {
|
|
272
|
-
|
|
273
|
-
`gsd-db: plan_milestone — render failed (DB rows preserved for debugging): ${(renderErr as Error).message}\n`,
|
|
274
|
-
);
|
|
273
|
+
logWarning("tool", `plan_milestone — render failed (DB rows preserved for debugging): ${(renderErr as Error).message}`);
|
|
275
274
|
invalidateStateCache();
|
|
276
275
|
return { error: `render failed: ${(renderErr as Error).message}` };
|
|
277
276
|
}
|
|
@@ -292,9 +291,7 @@ export async function handlePlanMilestone(
|
|
|
292
291
|
trigger_reason: params.triggerReason,
|
|
293
292
|
});
|
|
294
293
|
} catch (hookErr) {
|
|
295
|
-
|
|
296
|
-
`gsd: plan-milestone post-mutation hook warning: ${(hookErr as Error).message}\n`,
|
|
297
|
-
);
|
|
294
|
+
logWarning("tool", `plan-milestone post-mutation hook warning: ${(hookErr as Error).message}`);
|
|
298
295
|
}
|
|
299
296
|
|
|
300
297
|
return {
|
|
@@ -16,6 +16,7 @@ import { renderPlanFromDb } from "../markdown-renderer.js";
|
|
|
16
16
|
import { renderAllProjections } from "../workflow-projections.js";
|
|
17
17
|
import { writeManifest } from "../workflow-manifest.js";
|
|
18
18
|
import { appendEvent } from "../workflow-events.js";
|
|
19
|
+
import { logWarning } from "../workflow-logger.js";
|
|
19
20
|
|
|
20
21
|
export interface PlanSliceTaskInput {
|
|
21
22
|
taskId: string;
|
|
@@ -229,9 +230,7 @@ export async function handlePlanSlice(
|
|
|
229
230
|
trigger_reason: params.triggerReason,
|
|
230
231
|
});
|
|
231
232
|
} catch (hookErr) {
|
|
232
|
-
|
|
233
|
-
`gsd: plan-slice post-mutation hook warning: ${(hookErr as Error).message}\n`,
|
|
234
|
-
);
|
|
233
|
+
logWarning("tool", `plan-slice post-mutation hook warning: ${(hookErr as Error).message}`);
|
|
235
234
|
}
|
|
236
235
|
|
|
237
236
|
return {
|
|
@@ -241,9 +240,7 @@ export async function handlePlanSlice(
|
|
|
241
240
|
taskPlanPaths: renderResult.taskPlanPaths,
|
|
242
241
|
};
|
|
243
242
|
} catch (renderErr) {
|
|
244
|
-
|
|
245
|
-
`gsd-db: plan_slice — render failed (DB rows preserved for debugging): ${(renderErr as Error).message}\n`,
|
|
246
|
-
);
|
|
243
|
+
logWarning("tool", `plan_slice — render failed (DB rows preserved for debugging): ${(renderErr as Error).message}`);
|
|
247
244
|
invalidateStateCache();
|
|
248
245
|
return { error: `render failed: ${(renderErr as Error).message}` };
|
|
249
246
|
}
|
|
@@ -7,6 +7,7 @@ import { renderTaskPlanFromDb } from "../markdown-renderer.js";
|
|
|
7
7
|
import { renderAllProjections } from "../workflow-projections.js";
|
|
8
8
|
import { writeManifest } from "../workflow-manifest.js";
|
|
9
9
|
import { appendEvent } from "../workflow-events.js";
|
|
10
|
+
import { logWarning } from "../workflow-logger.js";
|
|
10
11
|
|
|
11
12
|
export interface PlanTaskParams {
|
|
12
13
|
milestoneId: string;
|
|
@@ -135,9 +136,7 @@ export async function handlePlanTask(
|
|
|
135
136
|
trigger_reason: params.triggerReason,
|
|
136
137
|
});
|
|
137
138
|
} catch (hookErr) {
|
|
138
|
-
|
|
139
|
-
`gsd: plan-task post-mutation hook warning: ${(hookErr as Error).message}\n`,
|
|
140
|
-
);
|
|
139
|
+
logWarning("tool", `plan-task post-mutation hook warning: ${(hookErr as Error).message}`);
|
|
141
140
|
}
|
|
142
141
|
|
|
143
142
|
return {
|
|
@@ -19,6 +19,7 @@ import { renderRoadmapFromDb, renderAssessmentFromDb } from "../markdown-rendere
|
|
|
19
19
|
import { renderAllProjections } from "../workflow-projections.js";
|
|
20
20
|
import { writeManifest } from "../workflow-manifest.js";
|
|
21
21
|
import { appendEvent } from "../workflow-events.js";
|
|
22
|
+
import { logWarning } from "../workflow-logger.js";
|
|
22
23
|
|
|
23
24
|
export interface SliceChangeInput {
|
|
24
25
|
sliceId: string;
|
|
@@ -248,9 +249,8 @@ export async function handleReassessRoadmap(
|
|
|
248
249
|
);
|
|
249
250
|
try {
|
|
250
251
|
if (existsSync(validationFile)) unlinkSync(validationFile);
|
|
251
|
-
} catch {
|
|
252
|
-
|
|
253
|
-
// will not see the file-based verdict as authoritative.
|
|
252
|
+
} catch (e) {
|
|
253
|
+
logWarning("tool", `validation file cleanup failed: ${(e as Error).message}`);
|
|
254
254
|
}
|
|
255
255
|
}
|
|
256
256
|
|
|
@@ -271,9 +271,7 @@ export async function handleReassessRoadmap(
|
|
|
271
271
|
trigger_reason: params.triggerReason,
|
|
272
272
|
});
|
|
273
273
|
} catch (hookErr) {
|
|
274
|
-
|
|
275
|
-
`gsd: reassess-roadmap post-mutation hook warning: ${(hookErr as Error).message}\n`,
|
|
276
|
-
);
|
|
274
|
+
logWarning("tool", `reassess-roadmap post-mutation hook warning: ${(hookErr as Error).message}`);
|
|
277
275
|
}
|
|
278
276
|
|
|
279
277
|
return {
|
|
@@ -24,6 +24,7 @@ import { isClosedStatus } from "../status-guards.js";
|
|
|
24
24
|
import { renderAllProjections } from "../workflow-projections.js";
|
|
25
25
|
import { writeManifest } from "../workflow-manifest.js";
|
|
26
26
|
import { appendEvent } from "../workflow-events.js";
|
|
27
|
+
import { logWarning } from "../workflow-logger.js";
|
|
27
28
|
|
|
28
29
|
export interface ReopenSliceParams {
|
|
29
30
|
milestoneId: string;
|
|
@@ -113,9 +114,7 @@ export async function handleReopenSlice(
|
|
|
113
114
|
trigger_reason: params.triggerReason,
|
|
114
115
|
});
|
|
115
116
|
} catch (hookErr) {
|
|
116
|
-
|
|
117
|
-
`gsd: reopen-slice post-mutation hook warning: ${(hookErr as Error).message}\n`,
|
|
118
|
-
);
|
|
117
|
+
logWarning("tool", `reopen-slice post-mutation hook warning: ${(hookErr as Error).message}`);
|
|
119
118
|
}
|
|
120
119
|
|
|
121
120
|
return {
|