gsd-pi 2.24.0 → 2.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -3
- package/dist/headless.js +24 -4
- package/dist/models-resolver.d.ts +0 -11
- package/dist/models-resolver.js +0 -15
- package/dist/resource-loader.d.ts +0 -1
- package/dist/resource-loader.js +0 -9
- package/dist/resources/GSD-WORKFLOW.md +12 -9
- package/dist/resources/extensions/async-jobs/index.ts +9 -1
- package/dist/resources/extensions/bg-shell/index.ts +3 -2
- package/dist/resources/extensions/bg-shell/overlay.ts +18 -17
- package/dist/resources/extensions/get-secrets-from-user.ts +5 -23
- package/dist/resources/extensions/gsd/activity-log.ts +5 -3
- package/dist/resources/extensions/gsd/auto-prompts.ts +14 -0
- package/dist/resources/extensions/gsd/auto-recovery.ts +7 -4
- package/dist/resources/extensions/gsd/auto-worktree.ts +132 -3
- package/dist/resources/extensions/gsd/auto.ts +265 -48
- package/dist/resources/extensions/gsd/cache.ts +3 -1
- package/dist/resources/extensions/gsd/doctor-proactive.ts +7 -6
- package/dist/resources/extensions/gsd/doctor.ts +26 -1
- package/dist/resources/extensions/gsd/files.ts +13 -2
- package/dist/resources/extensions/gsd/git-service.ts +74 -14
- package/dist/resources/extensions/gsd/gsd-db.ts +78 -1
- package/dist/resources/extensions/gsd/guided-flow.ts +54 -22
- package/dist/resources/extensions/gsd/index.ts +62 -8
- package/dist/resources/extensions/gsd/memory-extractor.ts +352 -0
- package/dist/resources/extensions/gsd/memory-store.ts +441 -0
- package/dist/resources/extensions/gsd/migrate/command.ts +2 -2
- package/dist/resources/extensions/gsd/migrate/writer.ts +39 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.ts +122 -4
- package/dist/resources/extensions/gsd/preferences.ts +2 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +4 -4
- package/dist/resources/extensions/gsd/prompts/discuss.md +5 -5
- package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +3 -3
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/dist/resources/extensions/gsd/roadmap-slices.ts +45 -1
- package/dist/resources/extensions/gsd/state.ts +17 -6
- package/dist/resources/extensions/gsd/tests/auto-recovery.test.ts +54 -0
- package/dist/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
- package/dist/resources/extensions/gsd/tests/derive-state.test.ts +70 -0
- package/dist/resources/extensions/gsd/tests/doctor-proactive.test.ts +23 -3
- package/dist/resources/extensions/gsd/tests/git-service.test.ts +70 -4
- package/dist/resources/extensions/gsd/tests/gsd-db.test.ts +2 -2
- package/dist/resources/extensions/gsd/tests/md-importer.test.ts +2 -3
- package/dist/resources/extensions/gsd/tests/memory-extractor.test.ts +180 -0
- package/dist/resources/extensions/gsd/tests/memory-store.test.ts +345 -0
- package/dist/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +13 -7
- package/dist/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +171 -0
- package/dist/resources/extensions/gsd/tests/smart-entry-draft.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/validate-milestone.test.ts +8 -4
- package/dist/resources/extensions/gsd/tests/visualizer-data.test.ts +147 -2
- package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +88 -10
- package/dist/resources/extensions/gsd/tests/visualizer-views.test.ts +314 -87
- package/dist/resources/extensions/gsd/triage-ui.ts +1 -1
- package/dist/resources/extensions/gsd/types.ts +2 -0
- package/dist/resources/extensions/gsd/visualizer-data.ts +291 -10
- package/dist/resources/extensions/gsd/visualizer-overlay.ts +237 -28
- package/dist/resources/extensions/gsd/visualizer-views.ts +462 -48
- package/dist/resources/extensions/gsd/worktree.ts +9 -2
- package/dist/resources/extensions/search-the-web/native-search.ts +19 -5
- package/dist/resources/extensions/shared/path-display.ts +19 -0
- package/package.json +1 -6
- package/packages/pi-agent-core/dist/agent-loop.js +2 -0
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.ts +2 -0
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +64 -0
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/mistral.js +3 -0
- package/packages/pi-ai/dist/providers/mistral.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +23 -1
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/src/providers/anthropic.ts +65 -1
- package/packages/pi-ai/src/providers/mistral.ts +3 -0
- package/packages/pi-ai/src/types.ts +19 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +7 -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 +32 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.js +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js +12 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.js +7 -0
- package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +8 -3
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
- package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +2 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +5 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +41 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +301 -62
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-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 +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +5 -0
- 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 +135 -30
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/path-display.test.d.ts +8 -0
- package/packages/pi-coding-agent/dist/tests/path-display.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/path-display.test.js +60 -0
- package/packages/pi-coding-agent/dist/tests/path-display.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/utils/clipboard-image.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/utils/clipboard-image.js +32 -6
- package/packages/pi-coding-agent/dist/utils/clipboard-image.js.map +1 -1
- package/packages/pi-coding-agent/dist/utils/path-display.d.ts +34 -0
- package/packages/pi-coding-agent/dist/utils/path-display.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/utils/path-display.js +36 -0
- package/packages/pi-coding-agent/dist/utils/path-display.js.map +1 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +36 -0
- package/packages/pi-coding-agent/src/core/keybindings.ts +1 -1
- package/packages/pi-coding-agent/src/core/lsp/client.ts +11 -1
- package/packages/pi-coding-agent/src/core/lsp/index.ts +7 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +17 -1
- package/packages/pi-coding-agent/src/core/settings-manager.ts +11 -0
- package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +2 -1
- package/packages/pi-coding-agent/src/index.ts +15 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +347 -62
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +18 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +124 -4
- package/packages/pi-coding-agent/src/tests/path-display.test.ts +85 -0
- package/packages/pi-coding-agent/src/utils/clipboard-image.ts +33 -6
- package/packages/pi-coding-agent/src/utils/path-display.ts +36 -0
- package/src/resources/GSD-WORKFLOW.md +12 -9
- package/src/resources/extensions/async-jobs/index.ts +9 -1
- package/src/resources/extensions/bg-shell/index.ts +3 -2
- package/src/resources/extensions/bg-shell/overlay.ts +18 -17
- package/src/resources/extensions/get-secrets-from-user.ts +5 -23
- package/src/resources/extensions/gsd/activity-log.ts +5 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +14 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +7 -4
- package/src/resources/extensions/gsd/auto-worktree.ts +132 -3
- package/src/resources/extensions/gsd/auto.ts +265 -48
- package/src/resources/extensions/gsd/cache.ts +3 -1
- package/src/resources/extensions/gsd/doctor-proactive.ts +7 -6
- package/src/resources/extensions/gsd/doctor.ts +26 -1
- package/src/resources/extensions/gsd/files.ts +13 -2
- package/src/resources/extensions/gsd/git-service.ts +74 -14
- package/src/resources/extensions/gsd/gsd-db.ts +78 -1
- package/src/resources/extensions/gsd/guided-flow.ts +54 -22
- package/src/resources/extensions/gsd/index.ts +62 -8
- package/src/resources/extensions/gsd/memory-extractor.ts +352 -0
- package/src/resources/extensions/gsd/memory-store.ts +441 -0
- package/src/resources/extensions/gsd/migrate/command.ts +2 -2
- package/src/resources/extensions/gsd/migrate/writer.ts +39 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +122 -4
- package/src/resources/extensions/gsd/preferences.ts +2 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +4 -4
- package/src/resources/extensions/gsd/prompts/discuss.md +5 -5
- package/src/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/queue.md +3 -3
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +45 -1
- package/src/resources/extensions/gsd/state.ts +17 -6
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +23 -3
- package/src/resources/extensions/gsd/tests/git-service.test.ts +70 -4
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +2 -3
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +180 -0
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +345 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +13 -7
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +171 -0
- package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +147 -2
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +88 -10
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +314 -87
- package/src/resources/extensions/gsd/triage-ui.ts +1 -1
- package/src/resources/extensions/gsd/types.ts +2 -0
- package/src/resources/extensions/gsd/visualizer-data.ts +291 -10
- package/src/resources/extensions/gsd/visualizer-overlay.ts +237 -28
- package/src/resources/extensions/gsd/visualizer-views.ts +462 -48
- package/src/resources/extensions/gsd/worktree.ts +9 -2
- package/src/resources/extensions/search-the-web/native-search.ts +19 -5
- package/src/resources/extensions/shared/path-display.ts +19 -0
|
@@ -9,11 +9,14 @@ import {
|
|
|
9
9
|
renderAgentView,
|
|
10
10
|
renderChangelogView,
|
|
11
11
|
renderExportView,
|
|
12
|
+
renderKnowledgeView,
|
|
13
|
+
renderCapturesView,
|
|
14
|
+
renderHealthView,
|
|
12
15
|
type ProgressFilter,
|
|
13
16
|
} from "./visualizer-views.js";
|
|
14
17
|
import { writeExportFile } from "./export.js";
|
|
15
18
|
|
|
16
|
-
const TAB_COUNT =
|
|
19
|
+
const TAB_COUNT = 10;
|
|
17
20
|
const TAB_LABELS = [
|
|
18
21
|
"1 Progress",
|
|
19
22
|
"2 Deps",
|
|
@@ -22,8 +25,15 @@ const TAB_LABELS = [
|
|
|
22
25
|
"5 Agent",
|
|
23
26
|
"6 Changes",
|
|
24
27
|
"7 Export",
|
|
28
|
+
"8 Knowledge",
|
|
29
|
+
"9 Captures",
|
|
30
|
+
"0 Health",
|
|
25
31
|
];
|
|
26
32
|
|
|
33
|
+
function stripAnsi(s: string): string {
|
|
34
|
+
return s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
export class GSDVisualizerOverlay {
|
|
28
38
|
private tui: { requestRender: () => void };
|
|
29
39
|
private theme: Theme;
|
|
@@ -39,7 +49,7 @@ export class GSDVisualizerOverlay {
|
|
|
39
49
|
data: VisualizerData | null = null;
|
|
40
50
|
basePath: string;
|
|
41
51
|
|
|
42
|
-
// Filter state
|
|
52
|
+
// Filter state
|
|
43
53
|
filterMode = false;
|
|
44
54
|
filterText = "";
|
|
45
55
|
filterField: "all" | "status" | "risk" | "keyword" = "all";
|
|
@@ -48,6 +58,11 @@ export class GSDVisualizerOverlay {
|
|
|
48
58
|
lastExportPath?: string;
|
|
49
59
|
exportStatus?: string;
|
|
50
60
|
|
|
61
|
+
// New state
|
|
62
|
+
private lastVisibleRows = 20;
|
|
63
|
+
collapsedMilestones = new Set<string>();
|
|
64
|
+
showHelp = false;
|
|
65
|
+
|
|
51
66
|
constructor(
|
|
52
67
|
tui: { requestRender: () => void },
|
|
53
68
|
theme: Theme,
|
|
@@ -58,6 +73,9 @@ export class GSDVisualizerOverlay {
|
|
|
58
73
|
this.onClose = onClose;
|
|
59
74
|
this.basePath = process.cwd();
|
|
60
75
|
|
|
76
|
+
// Enable SGR mouse tracking
|
|
77
|
+
process.stdout.write("\x1b[?1003h\x1b[?1006h");
|
|
78
|
+
|
|
61
79
|
loadVisualizerData(this.basePath).then((d) => {
|
|
62
80
|
this.data = d;
|
|
63
81
|
this.loading = false;
|
|
@@ -74,6 +92,17 @@ export class GSDVisualizerOverlay {
|
|
|
74
92
|
}, 2000);
|
|
75
93
|
}
|
|
76
94
|
|
|
95
|
+
private parseSGRMouse(data: string): { button: number; x: number; y: number; press: boolean } | null {
|
|
96
|
+
const match = data.match(/^\x1b\[<(\d+);(\d+);(\d+)([Mm])$/);
|
|
97
|
+
if (!match) return null;
|
|
98
|
+
return {
|
|
99
|
+
button: parseInt(match[1], 10),
|
|
100
|
+
x: parseInt(match[2], 10),
|
|
101
|
+
y: parseInt(match[3], 10),
|
|
102
|
+
press: match[4] === "M",
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
77
106
|
handleInput(data: string): void {
|
|
78
107
|
// Filter mode input routing
|
|
79
108
|
if (this.filterMode) {
|
|
@@ -106,6 +135,53 @@ export class GSDVisualizerOverlay {
|
|
|
106
135
|
return;
|
|
107
136
|
}
|
|
108
137
|
|
|
138
|
+
// Help overlay dismissal
|
|
139
|
+
if (this.showHelp) {
|
|
140
|
+
if (matchesKey(data, Key.escape) || data === "?") {
|
|
141
|
+
this.showHelp = false;
|
|
142
|
+
this.invalidate();
|
|
143
|
+
this.tui.requestRender();
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Mouse handling (before keyboard checks)
|
|
150
|
+
const mouse = this.parseSGRMouse(data);
|
|
151
|
+
if (mouse) {
|
|
152
|
+
if (mouse.button === 64) {
|
|
153
|
+
// Wheel up
|
|
154
|
+
this.scrollOffsets[this.activeTab] = Math.max(0, this.scrollOffsets[this.activeTab] - 3);
|
|
155
|
+
this.invalidate();
|
|
156
|
+
this.tui.requestRender();
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (mouse.button === 65) {
|
|
160
|
+
// Wheel down
|
|
161
|
+
this.scrollOffsets[this.activeTab] += 3;
|
|
162
|
+
this.invalidate();
|
|
163
|
+
this.tui.requestRender();
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (mouse.button === 0 && mouse.press) {
|
|
167
|
+
// Left click — check if on tab bar row
|
|
168
|
+
if (mouse.y === 2) {
|
|
169
|
+
let xPos = 3;
|
|
170
|
+
for (let i = 0; i < TAB_LABELS.length; i++) {
|
|
171
|
+
const tabWidth = TAB_LABELS[i].length + 2;
|
|
172
|
+
if (mouse.x >= xPos && mouse.x < xPos + tabWidth) {
|
|
173
|
+
this.activeTab = i;
|
|
174
|
+
this.invalidate();
|
|
175
|
+
this.tui.requestRender();
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
xPos += tabWidth + 1;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
109
185
|
if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c"))) {
|
|
110
186
|
this.dispose();
|
|
111
187
|
this.onClose();
|
|
@@ -126,15 +202,16 @@ export class GSDVisualizerOverlay {
|
|
|
126
202
|
return;
|
|
127
203
|
}
|
|
128
204
|
|
|
129
|
-
if ("
|
|
130
|
-
|
|
205
|
+
if ("1234567890".includes(data) && data.length === 1) {
|
|
206
|
+
const idx = data === "0" ? 9 : parseInt(data, 10) - 1;
|
|
207
|
+
this.activeTab = idx;
|
|
131
208
|
this.invalidate();
|
|
132
209
|
this.tui.requestRender();
|
|
133
210
|
return;
|
|
134
211
|
}
|
|
135
212
|
|
|
136
|
-
// "/" enters filter mode on
|
|
137
|
-
if (data === "/"
|
|
213
|
+
// "/" enters filter mode on any tab
|
|
214
|
+
if (data === "/") {
|
|
138
215
|
this.filterMode = true;
|
|
139
216
|
this.filterText = "";
|
|
140
217
|
this.invalidate();
|
|
@@ -142,16 +219,48 @@ export class GSDVisualizerOverlay {
|
|
|
142
219
|
return;
|
|
143
220
|
}
|
|
144
221
|
|
|
145
|
-
// "f" cycles filter field
|
|
146
|
-
if (data === "f"
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
222
|
+
// "f" cycles filter field (limit to all/keyword on non-Progress tabs)
|
|
223
|
+
if (data === "f") {
|
|
224
|
+
if (this.activeTab === 0) {
|
|
225
|
+
const fields: Array<"all" | "status" | "risk" | "keyword"> = ["all", "status", "risk", "keyword"];
|
|
226
|
+
const idx = fields.indexOf(this.filterField);
|
|
227
|
+
this.filterField = fields[(idx + 1) % fields.length];
|
|
228
|
+
} else {
|
|
229
|
+
this.filterField = this.filterField === "all" ? "keyword" : "all";
|
|
230
|
+
}
|
|
150
231
|
this.invalidate();
|
|
151
232
|
this.tui.requestRender();
|
|
152
233
|
return;
|
|
153
234
|
}
|
|
154
235
|
|
|
236
|
+
// "?" toggles help overlay
|
|
237
|
+
if (data === "?") {
|
|
238
|
+
this.showHelp = true;
|
|
239
|
+
this.invalidate();
|
|
240
|
+
this.tui.requestRender();
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Enter/Space toggles collapse on Progress tab
|
|
245
|
+
if ((matchesKey(data, Key.enter) || data === " ") && this.activeTab === 0 && this.data) {
|
|
246
|
+
const viewLines = this.renderTabContent(0, 80);
|
|
247
|
+
const offset = this.scrollOffsets[0];
|
|
248
|
+
for (const ms of this.data.milestones) {
|
|
249
|
+
const lineIdx = viewLines.findIndex(l => stripAnsi(l).includes(`${ms.id}:`));
|
|
250
|
+
if (lineIdx >= offset && lineIdx < offset + this.lastVisibleRows) {
|
|
251
|
+
if (this.collapsedMilestones.has(ms.id)) {
|
|
252
|
+
this.collapsedMilestones.delete(ms.id);
|
|
253
|
+
} else {
|
|
254
|
+
this.collapsedMilestones.add(ms.id);
|
|
255
|
+
}
|
|
256
|
+
this.invalidate();
|
|
257
|
+
this.tui.requestRender();
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
155
264
|
// Export tab key handling
|
|
156
265
|
if (this.activeTab === 6 && this.data) {
|
|
157
266
|
if (data === "m" || data === "j" || data === "s") {
|
|
@@ -160,6 +269,40 @@ export class GSDVisualizerOverlay {
|
|
|
160
269
|
}
|
|
161
270
|
}
|
|
162
271
|
|
|
272
|
+
// Page Up/Down
|
|
273
|
+
if (matchesKey(data, Key.pageUp)) {
|
|
274
|
+
const amount = Math.max(1, this.lastVisibleRows - 2);
|
|
275
|
+
this.scrollOffsets[this.activeTab] = Math.max(0, this.scrollOffsets[this.activeTab] - amount);
|
|
276
|
+
this.invalidate();
|
|
277
|
+
this.tui.requestRender();
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (matchesKey(data, Key.pageDown)) {
|
|
282
|
+
const amount = Math.max(1, this.lastVisibleRows - 2);
|
|
283
|
+
this.scrollOffsets[this.activeTab] += amount;
|
|
284
|
+
this.invalidate();
|
|
285
|
+
this.tui.requestRender();
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Half-page scroll: Ctrl+U / Ctrl+D
|
|
290
|
+
if (matchesKey(data, Key.ctrl("u"))) {
|
|
291
|
+
const amount = Math.max(1, Math.floor(this.lastVisibleRows / 2));
|
|
292
|
+
this.scrollOffsets[this.activeTab] = Math.max(0, this.scrollOffsets[this.activeTab] - amount);
|
|
293
|
+
this.invalidate();
|
|
294
|
+
this.tui.requestRender();
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (matchesKey(data, Key.ctrl("d"))) {
|
|
299
|
+
const amount = Math.max(1, Math.floor(this.lastVisibleRows / 2));
|
|
300
|
+
this.scrollOffsets[this.activeTab] += amount;
|
|
301
|
+
this.invalidate();
|
|
302
|
+
this.tui.requestRender();
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
|
|
163
306
|
if (matchesKey(data, Key.down) || matchesKey(data, "j")) {
|
|
164
307
|
this.scrollOffsets[this.activeTab]++;
|
|
165
308
|
this.invalidate();
|
|
@@ -226,7 +369,7 @@ export class GSDVisualizerOverlay {
|
|
|
226
369
|
case 0: {
|
|
227
370
|
const filter: ProgressFilter | undefined =
|
|
228
371
|
this.filterText ? { text: this.filterText, field: this.filterField } : undefined;
|
|
229
|
-
return renderProgressView(this.data, th, width, filter);
|
|
372
|
+
return renderProgressView(this.data, th, width, filter, this.collapsedMilestones);
|
|
230
373
|
}
|
|
231
374
|
case 1:
|
|
232
375
|
return renderDepsView(this.data, th, width);
|
|
@@ -240,11 +383,46 @@ export class GSDVisualizerOverlay {
|
|
|
240
383
|
return renderChangelogView(this.data, th, width);
|
|
241
384
|
case 6:
|
|
242
385
|
return renderExportView(this.data, th, width, this.lastExportPath);
|
|
386
|
+
case 7:
|
|
387
|
+
return renderKnowledgeView(this.data, th, width);
|
|
388
|
+
case 8:
|
|
389
|
+
return renderCapturesView(this.data, th, width);
|
|
390
|
+
case 9:
|
|
391
|
+
return renderHealthView(this.data, th, width);
|
|
243
392
|
default:
|
|
244
393
|
return [];
|
|
245
394
|
}
|
|
246
395
|
}
|
|
247
396
|
|
|
397
|
+
private renderHelpContent(width: number): string[] {
|
|
398
|
+
const th = this.theme;
|
|
399
|
+
const lines: string[] = [];
|
|
400
|
+
lines.push(th.fg("accent", th.bold("Keyboard Shortcuts")));
|
|
401
|
+
lines.push("");
|
|
402
|
+
const bindings: [string, string][] = [
|
|
403
|
+
["Tab/Shift+Tab", "Next/Previous tab"],
|
|
404
|
+
["1-9, 0", "Jump to tab"],
|
|
405
|
+
["j/k, Up/Down", "Scroll line"],
|
|
406
|
+
["PgUp/PgDn", "Scroll page"],
|
|
407
|
+
["Ctrl+U/Ctrl+D", "Scroll half-page"],
|
|
408
|
+
["g/G", "Top/Bottom"],
|
|
409
|
+
["/", "Search/filter"],
|
|
410
|
+
["f", "Cycle filter field"],
|
|
411
|
+
["Enter/Space", "Toggle collapse (Progress)"],
|
|
412
|
+
["Mouse wheel", "Scroll"],
|
|
413
|
+
["Click tab", "Switch tab"],
|
|
414
|
+
["?", "Toggle help"],
|
|
415
|
+
["Esc", "Close"],
|
|
416
|
+
];
|
|
417
|
+
for (const [key, desc] of bindings) {
|
|
418
|
+
const keyStr = th.fg("accent", key.padEnd(20));
|
|
419
|
+
lines.push(` ${keyStr} ${desc}`);
|
|
420
|
+
}
|
|
421
|
+
lines.push("");
|
|
422
|
+
lines.push(th.fg("dim", "Press ? or Esc to dismiss"));
|
|
423
|
+
return lines;
|
|
424
|
+
}
|
|
425
|
+
|
|
248
426
|
render(width: number): string[] {
|
|
249
427
|
if (this.cachedLines && this.cachedWidth === width) {
|
|
250
428
|
return this.cachedLines;
|
|
@@ -257,9 +435,13 @@ export class GSDVisualizerOverlay {
|
|
|
257
435
|
// Tab bar
|
|
258
436
|
const tabs = TAB_LABELS.map((label, i) => {
|
|
259
437
|
let displayLabel = label;
|
|
260
|
-
// Show filter indicator on
|
|
261
|
-
if (i ===
|
|
262
|
-
displayLabel += "
|
|
438
|
+
// Show filter indicator on active tab with filter
|
|
439
|
+
if (i === this.activeTab && this.filterText) {
|
|
440
|
+
displayLabel += " \u2731";
|
|
441
|
+
}
|
|
442
|
+
// Show captures badge
|
|
443
|
+
if (i === 8 && this.data?.captures?.pendingCount) {
|
|
444
|
+
displayLabel += ` (${this.data.captures.pendingCount})`;
|
|
263
445
|
}
|
|
264
446
|
if (i === this.activeTab) {
|
|
265
447
|
return th.fg("accent", `[${displayLabel}]`);
|
|
@@ -269,21 +451,23 @@ export class GSDVisualizerOverlay {
|
|
|
269
451
|
content.push(" " + tabs.join(" "));
|
|
270
452
|
content.push("");
|
|
271
453
|
|
|
272
|
-
// Filter bar (when in filter mode)
|
|
273
|
-
if (this.filterMode
|
|
454
|
+
// Filter bar (when in filter mode on any tab)
|
|
455
|
+
if (this.filterMode) {
|
|
274
456
|
content.push(
|
|
275
|
-
th.fg("accent", `Filter (${this.filterField}): ${this.filterText}
|
|
457
|
+
th.fg("accent", `Filter (${this.filterField}): ${this.filterText}\u2588`),
|
|
276
458
|
);
|
|
277
459
|
content.push("");
|
|
278
460
|
}
|
|
279
461
|
|
|
280
|
-
if (this.
|
|
281
|
-
|
|
462
|
+
if (this.showHelp) {
|
|
463
|
+
content.push(...this.renderHelpContent(innerWidth));
|
|
464
|
+
} else if (this.loading) {
|
|
465
|
+
const loadingText = "Loading\u2026";
|
|
282
466
|
const vis = visibleWidth(loadingText);
|
|
283
467
|
const leftPad = Math.max(0, Math.floor((innerWidth - vis) / 2));
|
|
284
468
|
content.push(" ".repeat(leftPad) + loadingText);
|
|
285
469
|
} else if (this.data) {
|
|
286
|
-
|
|
470
|
+
let viewLines = this.renderTabContent(this.activeTab, innerWidth);
|
|
287
471
|
|
|
288
472
|
// Show export status message if present
|
|
289
473
|
if (this.exportStatus && this.activeTab === 6) {
|
|
@@ -292,6 +476,12 @@ export class GSDVisualizerOverlay {
|
|
|
292
476
|
this.exportStatus = undefined;
|
|
293
477
|
}
|
|
294
478
|
|
|
479
|
+
// Apply cross-tab filter for non-Progress tabs
|
|
480
|
+
if (this.filterText && this.activeTab !== 0) {
|
|
481
|
+
const lowerFilter = this.filterText.toLowerCase();
|
|
482
|
+
viewLines = viewLines.filter(line => stripAnsi(line).toLowerCase().includes(lowerFilter));
|
|
483
|
+
}
|
|
484
|
+
|
|
295
485
|
content.push(...viewLines);
|
|
296
486
|
}
|
|
297
487
|
|
|
@@ -299,15 +489,17 @@ export class GSDVisualizerOverlay {
|
|
|
299
489
|
const viewportHeight = Math.max(5, process.stdout.rows ? process.stdout.rows - 8 : 24);
|
|
300
490
|
const chromeHeight = 2;
|
|
301
491
|
const visibleContentRows = Math.max(1, viewportHeight - chromeHeight);
|
|
492
|
+
this.lastVisibleRows = visibleContentRows;
|
|
493
|
+
const totalLines = content.length;
|
|
302
494
|
const maxScroll = Math.max(0, content.length - visibleContentRows);
|
|
303
495
|
this.scrollOffsets[this.activeTab] = Math.min(this.scrollOffsets[this.activeTab], maxScroll);
|
|
304
496
|
const offset = this.scrollOffsets[this.activeTab];
|
|
305
497
|
const visibleContent = content.slice(offset, offset + visibleContentRows);
|
|
306
498
|
|
|
307
|
-
const lines = this.wrapInBox(visibleContent, width);
|
|
499
|
+
const lines = this.wrapInBox(visibleContent, width, offset, visibleContentRows, totalLines);
|
|
308
500
|
|
|
309
501
|
// Footer hint
|
|
310
|
-
const hint = th.fg("dim", "Tab/Shift+Tab/1-
|
|
502
|
+
const hint = th.fg("dim", "Tab/Shift+Tab/1-9,0 switch \u00b7 / filter \u00b7 PgUp/PgDn scroll \u00b7 ? help \u00b7 esc close");
|
|
311
503
|
const hintVis = visibleWidth(hint);
|
|
312
504
|
const hintPad = Math.max(0, Math.floor((width - hintVis) / 2));
|
|
313
505
|
lines.push(" ".repeat(hintPad) + hint);
|
|
@@ -317,18 +509,33 @@ export class GSDVisualizerOverlay {
|
|
|
317
509
|
return lines;
|
|
318
510
|
}
|
|
319
511
|
|
|
320
|
-
private wrapInBox(inner: string[], width: number): string[] {
|
|
512
|
+
private wrapInBox(inner: string[], width: number, offset?: number, visibleRows?: number, totalLines?: number): string[] {
|
|
321
513
|
const th = this.theme;
|
|
322
514
|
const border = (s: string) => th.fg("borderAccent", s);
|
|
323
515
|
const innerWidth = width - 4;
|
|
324
516
|
const lines: string[] = [];
|
|
325
|
-
lines.push(border("
|
|
326
|
-
|
|
517
|
+
lines.push(border("\u256d" + "\u2500".repeat(width - 2) + "\u256e"));
|
|
518
|
+
|
|
519
|
+
// Compute scroll indicator positions
|
|
520
|
+
const scrollable = totalLines !== undefined && visibleRows !== undefined && totalLines > visibleRows;
|
|
521
|
+
let thumbStart = -1;
|
|
522
|
+
let thumbLen = 0;
|
|
523
|
+
const innerRows = inner.length;
|
|
524
|
+
if (scrollable && innerRows > 0 && totalLines! > 0) {
|
|
525
|
+
thumbStart = Math.round(((offset ?? 0) / totalLines!) * innerRows);
|
|
526
|
+
thumbLen = Math.max(1, Math.round((visibleRows! / totalLines!) * innerRows));
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
for (let i = 0; i < inner.length; i++) {
|
|
530
|
+
const line = inner[i];
|
|
327
531
|
const truncated = truncateToWidth(line, innerWidth);
|
|
328
532
|
const padWidth = Math.max(0, innerWidth - visibleWidth(truncated));
|
|
329
|
-
|
|
533
|
+
const rightBorder = scrollable && i >= thumbStart && i < thumbStart + thumbLen
|
|
534
|
+
? border("\u2503")
|
|
535
|
+
: border("\u2502");
|
|
536
|
+
lines.push(border("\u2502") + " " + truncated + " ".repeat(padWidth) + " " + rightBorder);
|
|
330
537
|
}
|
|
331
|
-
lines.push(border("
|
|
538
|
+
lines.push(border("\u2570" + "\u2500".repeat(width - 2) + "\u256f"));
|
|
332
539
|
return lines;
|
|
333
540
|
}
|
|
334
541
|
|
|
@@ -340,5 +547,7 @@ export class GSDVisualizerOverlay {
|
|
|
340
547
|
dispose(): void {
|
|
341
548
|
this.disposed = true;
|
|
342
549
|
clearInterval(this.refreshTimer);
|
|
550
|
+
// Disable SGR mouse tracking
|
|
551
|
+
process.stdout.write("\x1b[?1003l\x1b[?1006l");
|
|
343
552
|
}
|
|
344
553
|
}
|