gsd-pi 2.39.0 → 2.40.0-dev.4a93031
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/resource-loader.js +66 -2
- package/dist/resources/extensions/async-jobs/index.js +10 -0
- package/dist/resources/extensions/get-secrets-from-user.js +1 -1
- package/dist/resources/extensions/gsd/auto-dashboard.js +7 -0
- package/dist/resources/extensions/gsd/auto-loop.js +761 -673
- package/dist/resources/extensions/gsd/auto-post-unit.js +10 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +3 -3
- package/dist/resources/extensions/gsd/auto-start.js +6 -1
- package/dist/resources/extensions/gsd/auto.js +6 -4
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +126 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +233 -0
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +59 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +38 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +156 -0
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +46 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +300 -0
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +38 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +278 -0
- package/dist/resources/extensions/gsd/commands/context.js +84 -0
- package/dist/resources/extensions/gsd/commands/dispatcher.js +21 -0
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +72 -0
- package/dist/resources/extensions/gsd/commands/handlers/core.js +246 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +166 -0
- package/dist/resources/extensions/gsd/commands/handlers/parallel.js +94 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +102 -0
- package/dist/resources/extensions/gsd/commands/index.js +11 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
- package/dist/resources/extensions/gsd/commands.js +8 -1190
- package/dist/resources/extensions/gsd/dashboard-overlay.js +9 -0
- package/dist/resources/extensions/gsd/doctor-proactive.js +80 -10
- package/dist/resources/extensions/gsd/doctor.js +32 -2
- package/dist/resources/extensions/gsd/export-html.js +46 -0
- package/dist/resources/extensions/gsd/files.js +1 -1
- package/dist/resources/extensions/gsd/health-widget.js +1 -1
- package/dist/resources/extensions/gsd/index.js +4 -1115
- package/dist/resources/extensions/gsd/progress-score.js +20 -1
- package/dist/resources/extensions/gsd/prompts/forensics.md +121 -46
- package/dist/resources/extensions/gsd/visualizer-data.js +26 -1
- package/dist/resources/extensions/gsd/visualizer-views.js +52 -0
- package/dist/welcome-screen.d.ts +3 -2
- package/dist/welcome-screen.js +66 -22
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +12 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +107 -24
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skill-tool.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js +70 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +2 -1
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +244 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +58 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +54 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js +63 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +38 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +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 +15 -457
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +122 -23
- package/packages/pi-coding-agent/src/core/skill-tool.test.ts +89 -0
- package/packages/pi-coding-agent/src/core/skills.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +302 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +59 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +68 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/model-controller.ts +71 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +37 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +18 -510
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/index.ts +11 -0
- package/src/resources/extensions/get-secrets-from-user.ts +1 -1
- package/src/resources/extensions/gsd/auto-dashboard.ts +10 -0
- package/src/resources/extensions/gsd/auto-loop.ts +1075 -921
- package/src/resources/extensions/gsd/auto-post-unit.ts +10 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +3 -3
- package/src/resources/extensions/gsd/auto-start.ts +6 -1
- package/src/resources/extensions/gsd/auto.ts +13 -10
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +142 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +238 -0
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +90 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +46 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +167 -0
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +55 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +340 -0
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +51 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +301 -0
- package/src/resources/extensions/gsd/commands/context.ts +101 -0
- package/src/resources/extensions/gsd/commands/dispatcher.ts +32 -0
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +74 -0
- package/src/resources/extensions/gsd/commands/handlers/core.ts +274 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +169 -0
- package/src/resources/extensions/gsd/commands/handlers/parallel.ts +118 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +109 -0
- package/src/resources/extensions/gsd/commands/index.ts +14 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
- package/src/resources/extensions/gsd/commands.ts +10 -1329
- package/src/resources/extensions/gsd/dashboard-overlay.ts +10 -0
- package/src/resources/extensions/gsd/doctor-proactive.ts +106 -10
- package/src/resources/extensions/gsd/doctor.ts +47 -3
- package/src/resources/extensions/gsd/export-html.ts +51 -0
- package/src/resources/extensions/gsd/files.ts +1 -1
- package/src/resources/extensions/gsd/health-widget.ts +2 -1
- package/src/resources/extensions/gsd/index.ts +12 -1314
- package/src/resources/extensions/gsd/progress-score.ts +23 -0
- package/src/resources/extensions/gsd/prompts/forensics.md +121 -46
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +13 -9
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +16 -16
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +10 -10
- package/src/resources/extensions/gsd/visualizer-data.ts +51 -1
- package/src/resources/extensions/gsd/visualizer-views.ts +58 -0
- /package/dist/resources/extensions/{env-utils.js → gsd/env-utils.js} +0 -0
- /package/src/resources/extensions/{env-utils.ts → gsd/env-utils.ts} +0 -0
|
@@ -282,6 +282,15 @@ export class GSDDashboardOverlay {
|
|
|
282
282
|
: progressScore.level === "yellow" ? th.fg("warning", "●")
|
|
283
283
|
: th.fg("error", "●");
|
|
284
284
|
lines.push(row(`${progressIcon} ${th.fg("text", progressScore.summary)}`));
|
|
285
|
+
// Show signal details when degraded — real-time visibility into what doctor found
|
|
286
|
+
if (progressScore.level !== "green" && progressScore.signals.length > 0) {
|
|
287
|
+
for (const signal of progressScore.signals) {
|
|
288
|
+
const prefix = signal.kind === "positive" ? th.fg("success", " ✓")
|
|
289
|
+
: signal.kind === "negative" ? th.fg("error", " ✗")
|
|
290
|
+
: th.fg("dim", " ·");
|
|
291
|
+
lines.push(row(`${prefix} ${th.fg("dim", signal.label)}`));
|
|
292
|
+
}
|
|
293
|
+
}
|
|
285
294
|
}
|
|
286
295
|
lines.push(blank());
|
|
287
296
|
if (this.dashData.currentUnit) {
|
|
@@ -28,11 +28,23 @@ let healthHistory = [];
|
|
|
28
28
|
let consecutiveErrorUnits = 0;
|
|
29
29
|
/** Unit index counter for health tracking. */
|
|
30
30
|
let healthUnitIndex = 0;
|
|
31
|
+
/** Previous progress level for state transition detection. */
|
|
32
|
+
let previousProgressLevel = "green";
|
|
33
|
+
/** Callback for state transition notifications. Set by auto-mode. */
|
|
34
|
+
let onLevelChange = null;
|
|
35
|
+
/**
|
|
36
|
+
* Register a callback for progress level transitions (green→yellow, yellow→red, etc.).
|
|
37
|
+
* Called once when auto-mode starts. Pass null to unregister.
|
|
38
|
+
*/
|
|
39
|
+
export function setLevelChangeCallback(cb) {
|
|
40
|
+
onLevelChange = cb;
|
|
41
|
+
previousProgressLevel = "green";
|
|
42
|
+
}
|
|
31
43
|
/**
|
|
32
44
|
* Record a health snapshot after a doctor run.
|
|
33
|
-
* Called from the post-unit hook in auto.ts.
|
|
45
|
+
* Called from the post-unit hook in auto-post-unit.ts.
|
|
34
46
|
*/
|
|
35
|
-
export function recordHealthSnapshot(errors, warnings, fixesApplied) {
|
|
47
|
+
export function recordHealthSnapshot(errors, warnings, fixesApplied, issues, fixes, scope) {
|
|
36
48
|
healthUnitIndex++;
|
|
37
49
|
healthHistory.push({
|
|
38
50
|
timestamp: Date.now(),
|
|
@@ -40,6 +52,9 @@ export function recordHealthSnapshot(errors, warnings, fixesApplied) {
|
|
|
40
52
|
warnings,
|
|
41
53
|
fixesApplied,
|
|
42
54
|
unitIndex: healthUnitIndex,
|
|
55
|
+
issues: issues ?? [],
|
|
56
|
+
fixes: fixes ?? [],
|
|
57
|
+
scope,
|
|
43
58
|
});
|
|
44
59
|
// Keep only the last 50 snapshots to bound memory
|
|
45
60
|
if (healthHistory.length > 50) {
|
|
@@ -51,6 +66,18 @@ export function recordHealthSnapshot(errors, warnings, fixesApplied) {
|
|
|
51
66
|
else {
|
|
52
67
|
consecutiveErrorUnits = 0;
|
|
53
68
|
}
|
|
69
|
+
// Detect progress level transitions and notify
|
|
70
|
+
if (onLevelChange) {
|
|
71
|
+
const newLevel = consecutiveErrorUnits >= 3 ? "red"
|
|
72
|
+
: consecutiveErrorUnits >= 1 || getHealthTrend() === "degrading" ? "yellow"
|
|
73
|
+
: "green";
|
|
74
|
+
if (newLevel !== previousProgressLevel) {
|
|
75
|
+
const topIssue = (issues ?? []).find(i => i.severity === "error") ?? (issues ?? [])[0];
|
|
76
|
+
const detail = topIssue ? `: ${topIssue.message}` : "";
|
|
77
|
+
onLevelChange(previousProgressLevel, newLevel, `Health ${previousProgressLevel} → ${newLevel}${detail}`);
|
|
78
|
+
previousProgressLevel = newLevel;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
54
81
|
}
|
|
55
82
|
/**
|
|
56
83
|
* Get the current health trend.
|
|
@@ -84,6 +111,27 @@ export function getConsecutiveErrorUnits() {
|
|
|
84
111
|
export function getHealthHistory() {
|
|
85
112
|
return healthHistory;
|
|
86
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Get the latest health issues from the most recent snapshot.
|
|
116
|
+
* Returns issues from the last snapshot that had any, for real-time visibility.
|
|
117
|
+
*/
|
|
118
|
+
export function getLatestHealthIssues() {
|
|
119
|
+
for (let i = healthHistory.length - 1; i >= 0; i--) {
|
|
120
|
+
if (healthHistory[i].issues.length > 0)
|
|
121
|
+
return healthHistory[i].issues;
|
|
122
|
+
}
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get the latest fixes applied from the most recent snapshot.
|
|
127
|
+
*/
|
|
128
|
+
export function getLatestHealthFixes() {
|
|
129
|
+
for (let i = healthHistory.length - 1; i >= 0; i--) {
|
|
130
|
+
if (healthHistory[i].fixes.length > 0)
|
|
131
|
+
return healthHistory[i].fixes;
|
|
132
|
+
}
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
87
135
|
/**
|
|
88
136
|
* Reset health tracking state. Called on auto-mode start/stop.
|
|
89
137
|
*/
|
|
@@ -91,6 +139,7 @@ export function resetHealthTracking() {
|
|
|
91
139
|
healthHistory = [];
|
|
92
140
|
consecutiveErrorUnits = 0;
|
|
93
141
|
healthUnitIndex = 0;
|
|
142
|
+
previousProgressLevel = "green";
|
|
94
143
|
}
|
|
95
144
|
/**
|
|
96
145
|
* Lightweight pre-dispatch health check. Runs fast checks that should
|
|
@@ -234,23 +283,44 @@ export function resetEscalation() {
|
|
|
234
283
|
}
|
|
235
284
|
/**
|
|
236
285
|
* Format a health summary for display in the auto-mode dashboard.
|
|
286
|
+
* Human-readable with full words, not abbreviations.
|
|
237
287
|
*/
|
|
238
288
|
export function formatHealthSummary() {
|
|
239
289
|
if (healthHistory.length === 0)
|
|
240
290
|
return "No health data yet.";
|
|
241
291
|
const latest = healthHistory[healthHistory.length - 1];
|
|
242
292
|
const trend = getHealthTrend();
|
|
243
|
-
const
|
|
293
|
+
const trendLabel = trend === "improving" ? "improving"
|
|
294
|
+
: trend === "degrading" ? "degrading"
|
|
295
|
+
: trend === "stable" ? "stable"
|
|
296
|
+
: "unknown";
|
|
244
297
|
const totalFixes = healthHistory.reduce((sum, s) => sum + s.fixesApplied, 0);
|
|
245
|
-
const parts = [
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
298
|
+
const parts = [];
|
|
299
|
+
// Error/warning summary
|
|
300
|
+
if (latest.errors === 0 && latest.warnings === 0) {
|
|
301
|
+
parts.push("No issues");
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
const counts = [];
|
|
305
|
+
if (latest.errors > 0)
|
|
306
|
+
counts.push(`${latest.errors} error${latest.errors > 1 ? "s" : ""}`);
|
|
307
|
+
if (latest.warnings > 0)
|
|
308
|
+
counts.push(`${latest.warnings} warning${latest.warnings > 1 ? "s" : ""}`);
|
|
309
|
+
parts.push(counts.join(", "));
|
|
310
|
+
}
|
|
311
|
+
parts.push(`trend ${trendLabel}`);
|
|
312
|
+
if (totalFixes > 0) {
|
|
313
|
+
parts.push(`${totalFixes} fix${totalFixes > 1 ? "es" : ""} applied`);
|
|
314
|
+
}
|
|
250
315
|
if (consecutiveErrorUnits > 0) {
|
|
251
|
-
parts.push(
|
|
316
|
+
parts.push(`${consecutiveErrorUnits} of ${ESCALATION_THRESHOLD} consecutive errors before escalation`);
|
|
317
|
+
}
|
|
318
|
+
// Include top issue from latest snapshot
|
|
319
|
+
if (latest.issues.length > 0) {
|
|
320
|
+
const topIssue = latest.issues.find(i => i.severity === "error") ?? latest.issues[0];
|
|
321
|
+
parts.push(`latest: ${topIssue.message}`);
|
|
252
322
|
}
|
|
253
|
-
return parts.join("
|
|
323
|
+
return parts.join(" · ");
|
|
254
324
|
}
|
|
255
325
|
/**
|
|
256
326
|
* Reset all proactive healing state. Called on auto-mode start/stop.
|
|
@@ -368,13 +368,43 @@ function detectCircularDependencies(slices) {
|
|
|
368
368
|
async function appendDoctorHistory(basePath, report) {
|
|
369
369
|
try {
|
|
370
370
|
const historyPath = join(gsdRoot(basePath), "doctor-history.jsonl");
|
|
371
|
+
const errorCount = report.issues.filter(i => i.severity === "error").length;
|
|
372
|
+
const warningCount = report.issues.filter(i => i.severity === "warning").length;
|
|
373
|
+
const issueDetails = report.issues
|
|
374
|
+
.filter(i => i.severity === "error" || i.severity === "warning")
|
|
375
|
+
.slice(0, 10) // cap to keep JSONL lines bounded
|
|
376
|
+
.map(i => ({ severity: i.severity, code: i.code, message: i.message, unitId: i.unitId }));
|
|
377
|
+
// Human-readable one-line summary
|
|
378
|
+
const summaryParts = [];
|
|
379
|
+
if (report.ok) {
|
|
380
|
+
summaryParts.push("Clean");
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
const counts = [];
|
|
384
|
+
if (errorCount > 0)
|
|
385
|
+
counts.push(`${errorCount} error${errorCount > 1 ? "s" : ""}`);
|
|
386
|
+
if (warningCount > 0)
|
|
387
|
+
counts.push(`${warningCount} warning${warningCount > 1 ? "s" : ""}`);
|
|
388
|
+
summaryParts.push(counts.join(", "));
|
|
389
|
+
}
|
|
390
|
+
if (report.fixesApplied.length > 0) {
|
|
391
|
+
summaryParts.push(`${report.fixesApplied.length} fixed`);
|
|
392
|
+
}
|
|
393
|
+
if (issueDetails.length > 0) {
|
|
394
|
+
const topIssue = issueDetails.find(i => i.severity === "error") ?? issueDetails[0];
|
|
395
|
+
summaryParts.push(topIssue.message);
|
|
396
|
+
}
|
|
371
397
|
const entry = JSON.stringify({
|
|
372
398
|
ts: new Date().toISOString(),
|
|
373
399
|
ok: report.ok,
|
|
374
|
-
errors:
|
|
375
|
-
warnings:
|
|
400
|
+
errors: errorCount,
|
|
401
|
+
warnings: warningCount,
|
|
376
402
|
fixes: report.fixesApplied.length,
|
|
377
403
|
codes: [...new Set(report.issues.map(i => i.code))],
|
|
404
|
+
issues: issueDetails.length > 0 ? issueDetails : undefined,
|
|
405
|
+
fixDescriptions: report.fixesApplied.length > 0 ? report.fixesApplied : undefined,
|
|
406
|
+
scope: report.scope,
|
|
407
|
+
summary: summaryParts.join(" · "),
|
|
378
408
|
});
|
|
379
409
|
const existing = existsSync(historyPath) ? readFileSync(historyPath, "utf-8") : "";
|
|
380
410
|
await saveFile(historyPath, existing + entry + "\n");
|
|
@@ -236,9 +236,55 @@ function buildHealthSection(data) {
|
|
|
236
236
|
<td>${formatTokenCount(tb.tokens.total)}</td></tr>`).join('')}
|
|
237
237
|
</tbody>
|
|
238
238
|
</table>` : '';
|
|
239
|
+
// Progress score section
|
|
240
|
+
let progressHtml = '';
|
|
241
|
+
if (h.progressScore) {
|
|
242
|
+
const ps = h.progressScore;
|
|
243
|
+
const scoreColor = ps.level === 'green' ? '#22c55e' : ps.level === 'yellow' ? '#eab308' : '#ef4444';
|
|
244
|
+
const signalRows = ps.signals.map(s => {
|
|
245
|
+
const icon = s.kind === 'positive' ? '✓' : s.kind === 'negative' ? '✗' : '·';
|
|
246
|
+
const color = s.kind === 'positive' ? '#22c55e' : s.kind === 'negative' ? '#ef4444' : '#888';
|
|
247
|
+
return `<div style="margin-left:1em;color:${color}">${icon} ${esc(s.label)}</div>`;
|
|
248
|
+
}).join('');
|
|
249
|
+
progressHtml = `
|
|
250
|
+
<h3>Progress Score</h3>
|
|
251
|
+
<div style="font-size:1.1em;font-weight:bold;color:${scoreColor}">● ${esc(ps.summary)}</div>
|
|
252
|
+
${signalRows}`;
|
|
253
|
+
}
|
|
254
|
+
// Doctor history section
|
|
255
|
+
let historyHtml = '';
|
|
256
|
+
const doctorHistory = h.doctorHistory ?? [];
|
|
257
|
+
if (doctorHistory.length > 0) {
|
|
258
|
+
const historyRows = doctorHistory.slice(0, 20).map(entry => {
|
|
259
|
+
const statusIcon = entry.ok ? '✓' : '✗';
|
|
260
|
+
const statusColor = entry.ok ? '#22c55e' : '#ef4444';
|
|
261
|
+
const ts = entry.ts.replace('T', ' ').slice(0, 19);
|
|
262
|
+
const scopeTag = entry.scope ? `<span class="mono" style="color:#888"> [${esc(entry.scope)}]</span>` : '';
|
|
263
|
+
const summaryText = entry.summary ? esc(entry.summary) : `${entry.errors} errors, ${entry.warnings} warnings, ${entry.fixes} fixes`;
|
|
264
|
+
const issueDetails = (entry.issues ?? []).slice(0, 3).map(i => {
|
|
265
|
+
const iColor = i.severity === 'error' ? '#ef4444' : '#eab308';
|
|
266
|
+
return `<div style="margin-left:2em;color:${iColor};font-size:0.85em">${i.severity === 'error' ? '✗' : '⚠'} ${esc(i.message)} <span class="mono" style="color:#888">${esc(i.unitId)}</span></div>`;
|
|
267
|
+
}).join('');
|
|
268
|
+
const fixDetails = (entry.fixDescriptions ?? []).slice(0, 2).map(f => `<div style="margin-left:2em;color:#22c55e;font-size:0.85em">↳ ${esc(f)}</div>`).join('');
|
|
269
|
+
return `<tr style="color:${statusColor}">
|
|
270
|
+
<td class="mono">${statusIcon}</td>
|
|
271
|
+
<td class="mono">${esc(ts)}${scopeTag}</td>
|
|
272
|
+
<td>${summaryText}</td>
|
|
273
|
+
</tr>
|
|
274
|
+
${issueDetails || fixDetails ? `<tr><td colspan="3">${issueDetails}${fixDetails}</td></tr>` : ''}`;
|
|
275
|
+
}).join('');
|
|
276
|
+
historyHtml = `
|
|
277
|
+
<h3>Doctor Run History</h3>
|
|
278
|
+
<table class="tbl">
|
|
279
|
+
<thead><tr><th></th><th>Time</th><th>Summary</th></tr></thead>
|
|
280
|
+
<tbody>${historyRows}</tbody>
|
|
281
|
+
</table>`;
|
|
282
|
+
}
|
|
239
283
|
return section('health', 'Health', `
|
|
240
284
|
<table class="tbl tbl-kv"><tbody>${rows.join('')}</tbody></table>
|
|
241
285
|
${tierRows}
|
|
286
|
+
${progressHtml}
|
|
287
|
+
${historyHtml}
|
|
242
288
|
`);
|
|
243
289
|
}
|
|
244
290
|
// ─── Section: Progress ────────────────────────────────────────────────────────
|
|
@@ -7,7 +7,7 @@ import { resolve } from 'node:path';
|
|
|
7
7
|
import { atomicWriteAsync } from './atomic-write.js';
|
|
8
8
|
import { resolveMilestoneFile, relMilestoneFile, resolveGsdRootFile } from './paths.js';
|
|
9
9
|
import { findMilestoneIds } from './milestone-ids.js';
|
|
10
|
-
import { checkExistingEnvKeys } from '
|
|
10
|
+
import { checkExistingEnvKeys } from './env-utils.js';
|
|
11
11
|
import { parseRoadmapSlices } from './roadmap-slices.js';
|
|
12
12
|
import { nativeParseRoadmap, nativeExtractSection, nativeParsePlanFile, nativeParseSummaryFile, NATIVE_UNAVAILABLE } from './native-parser-bridge.js';
|
|
13
13
|
import { debugTime, debugCount } from './debug-logger.js';
|
|
@@ -11,7 +11,7 @@ import { runProviderChecks, summariseProviderIssues } from "./doctor-providers.j
|
|
|
11
11
|
import { runEnvironmentChecks } from "./doctor-environment.js";
|
|
12
12
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
13
13
|
import { loadLedgerFromDisk, getProjectTotals } from "./metrics.js";
|
|
14
|
-
import { projectRoot } from "./commands.js";
|
|
14
|
+
import { projectRoot } from "./commands/context.js";
|
|
15
15
|
import { buildHealthLines, detectHealthWidgetProjectState, } from "./health-widget-core.js";
|
|
16
16
|
// ── Data loader ────────────────────────────────────────────────────────────────
|
|
17
17
|
function loadHealthWidgetData(basePath) {
|