gsd-pi 2.58.0-dev.778d6ac → 2.58.0-dev.e002a57
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/cli.js +11 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +11 -8
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +9 -16
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +22 -1
- package/dist/resources/extensions/gsd/codebase-generator.js +279 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +10 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
- package/dist/resources/extensions/gsd/commands-codebase.js +115 -0
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +41 -4
- package/dist/resources/extensions/gsd/complexity-classifier.js +8 -6
- package/dist/resources/extensions/gsd/doctor-git-checks.js +48 -1
- package/dist/resources/extensions/gsd/doctor-proactive.js +34 -1
- package/dist/resources/extensions/gsd/error-classifier.js +3 -4
- package/dist/resources/extensions/gsd/git-service.js +82 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +22 -0
- package/dist/resources/extensions/gsd/paths.js +2 -0
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/watch/header-renderer.js +241 -0
- package/dist/resources/extensions/search-the-web/url-utils.js +17 -0
- package/dist/security-overrides.d.ts +11 -0
- package/dist/security-overrides.js +41 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +16 -16
- 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 +16 -16
- 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/dist/welcome-screen.d.ts +1 -0
- package/dist/welcome-screen.js +32 -6
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/resolve-config-value.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.js +23 -2
- package/packages/pi-coding-agent/dist/core/resolve-config-value.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +89 -2
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager-security.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/settings-manager-security.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/settings-manager-security.test.js +83 -0
- package/packages/pi-coding-agent/dist/core/settings-manager-security.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +14 -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 +36 -3
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -0
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/armin.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/armin.js +9 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/armin.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +0 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bordered-loader.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/config-selector.js +5 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/countdown-timer.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/countdown-timer.js +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/countdown-timer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/custom-message.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/daxnuts.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/daxnuts.js +4 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/daxnuts.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +8 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.js +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-selector.js +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +26 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/oauth-selector.js +4 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +46 -14
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js +2 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.js +4 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.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 +8 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message-selector.js +3 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +15 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +16 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +1 -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 +27 -4
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +111 -1
- package/packages/pi-coding-agent/src/core/resolve-config-value.ts +26 -2
- package/packages/pi-coding-agent/src/core/settings-manager-security.test.ts +102 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +44 -3
- package/packages/pi-coding-agent/src/index.ts +5 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/armin.ts +9 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +0 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +3 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/bordered-loader.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/branch-summary-message.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/compaction-summary-message.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/config-selector.ts +7 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/countdown-timer.ts +3 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/custom-message.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/daxnuts.ts +4 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +2 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +3 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/extension-input.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/extension-selector.ts +4 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +27 -13
- package/packages/pi-coding-agent/src/modes/interactive/components/oauth-selector.ts +4 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +45 -14
- package/packages/pi-coding-agent/src/modes/interactive/components/scoped-models-selector.ts +2 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/session-selector.ts +4 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +2 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +8 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message-selector.ts +3 -2
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +17 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +14 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +35 -3
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +7 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/src/resources/extensions/gsd/auto-worktree.ts +10 -7
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +10 -16
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +22 -1
- package/src/resources/extensions/gsd/codebase-generator.ts +351 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +10 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
- package/src/resources/extensions/gsd/commands-codebase.ts +164 -0
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +46 -4
- package/src/resources/extensions/gsd/complexity-classifier.ts +8 -6
- package/src/resources/extensions/gsd/doctor-git-checks.ts +49 -1
- package/src/resources/extensions/gsd/doctor-proactive.ts +35 -1
- package/src/resources/extensions/gsd/doctor-types.ts +2 -0
- package/src/resources/extensions/gsd/error-classifier.ts +3 -4
- package/src/resources/extensions/gsd/git-service.ts +93 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +24 -0
- package/src/resources/extensions/gsd/paths.ts +2 -0
- package/src/resources/extensions/gsd/preferences-types.ts +8 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +488 -0
- package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +72 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +44 -0
- package/src/resources/extensions/gsd/watch/header-renderer.ts +275 -0
- package/src/resources/extensions/search-the-web/url-utils.ts +19 -0
- /package/dist/web/standalone/.next/static/{R0D4xaIPl5kg93edN7Oo0 → nUA6d2OJrDSVq9RNb-c8b}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{R0D4xaIPl5kg93edN7Oo0 → nUA6d2OJrDSVq9RNb-c8b}/_ssgManifest.js +0 -0
|
@@ -46,7 +46,12 @@ export function setupEditorSubmitHandler(host: InteractiveModeStateHost & {
|
|
|
46
46
|
if (host.isExtensionCommand(text)) {
|
|
47
47
|
host.editor.addToHistory?.(text);
|
|
48
48
|
host.editor.setText("");
|
|
49
|
-
|
|
49
|
+
try {
|
|
50
|
+
await host.session.prompt(text);
|
|
51
|
+
} catch (error: unknown) {
|
|
52
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
53
|
+
host.showError(errorMessage);
|
|
54
|
+
}
|
|
50
55
|
} else {
|
|
51
56
|
host.queueCompactionMessage(text, "steer");
|
|
52
57
|
}
|
|
@@ -82,5 +87,13 @@ export function setupEditorSubmitHandler(host: InteractiveModeStateHost & {
|
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
host.editor.addToHistory?.(text);
|
|
90
|
+
// submitPromptsDirectly is false — still dispatch via session.prompt so user input
|
|
91
|
+
// is not silently discarded.
|
|
92
|
+
try {
|
|
93
|
+
await host.session.prompt(text);
|
|
94
|
+
} catch (error: unknown) {
|
|
95
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
96
|
+
host.showError(errorMessage);
|
|
97
|
+
}
|
|
85
98
|
};
|
|
86
99
|
}
|
|
@@ -107,6 +107,7 @@ import {
|
|
|
107
107
|
getThemeByName,
|
|
108
108
|
initTheme,
|
|
109
109
|
onThemeChange,
|
|
110
|
+
stopThemeWatcher,
|
|
110
111
|
setRegisteredThemes,
|
|
111
112
|
setTheme,
|
|
112
113
|
setThemeInstance,
|
|
@@ -202,6 +203,9 @@ export class InteractiveMode {
|
|
|
202
203
|
// Agent subscription unsubscribe function
|
|
203
204
|
private unsubscribe?: () => void;
|
|
204
205
|
|
|
206
|
+
// Branch change listener unsubscribe function
|
|
207
|
+
private _branchChangeUnsub?: () => void;
|
|
208
|
+
|
|
205
209
|
// Track if editor is in bash mode (text starts with !)
|
|
206
210
|
private isBashMode = false;
|
|
207
211
|
|
|
@@ -511,7 +515,7 @@ export class InteractiveMode {
|
|
|
511
515
|
});
|
|
512
516
|
|
|
513
517
|
// Set up git branch watcher (uses provider instead of footer)
|
|
514
|
-
this.footerDataProvider.onBranchChange(() => {
|
|
518
|
+
this._branchChangeUnsub = this.footerDataProvider.onBranchChange(() => {
|
|
515
519
|
this.ui.requestRender();
|
|
516
520
|
});
|
|
517
521
|
|
|
@@ -1998,8 +2002,9 @@ export class InteractiveMode {
|
|
|
1998
2002
|
}
|
|
1999
2003
|
|
|
2000
2004
|
private subscribeToAgent(): void {
|
|
2001
|
-
|
|
2002
|
-
|
|
2005
|
+
let eventQueue: Promise<void> = Promise.resolve();
|
|
2006
|
+
this.unsubscribe = this.session.subscribe((event) => {
|
|
2007
|
+
eventQueue = eventQueue.then(() => this.handleEvent(event)).catch(() => {});
|
|
2003
2008
|
});
|
|
2004
2009
|
}
|
|
2005
2010
|
|
|
@@ -3805,6 +3810,33 @@ export class InteractiveMode {
|
|
|
3805
3810
|
this.loadingAnimation = undefined;
|
|
3806
3811
|
}
|
|
3807
3812
|
this.clearExtensionTerminalInputListeners();
|
|
3813
|
+
|
|
3814
|
+
// Clean up branch change listener (Fix 1)
|
|
3815
|
+
this._branchChangeUnsub?.();
|
|
3816
|
+
this._branchChangeUnsub = undefined;
|
|
3817
|
+
|
|
3818
|
+
// Clean up theme change listener and watcher (Fix 2)
|
|
3819
|
+
onThemeChange(() => {});
|
|
3820
|
+
stopThemeWatcher();
|
|
3821
|
+
|
|
3822
|
+
// Resolve any pending getUserInput promise so the run() loop can exit (Fix 3)
|
|
3823
|
+
if (this.onInputCallback) {
|
|
3824
|
+
this.onInputCallback("");
|
|
3825
|
+
this.onInputCallback = undefined;
|
|
3826
|
+
}
|
|
3827
|
+
|
|
3828
|
+
// Dispose extension widgets, custom footer, and custom header (Fix 4)
|
|
3829
|
+
this.clearExtensionWidgets();
|
|
3830
|
+
if (this.customFooter?.dispose) {
|
|
3831
|
+
this.customFooter.dispose();
|
|
3832
|
+
}
|
|
3833
|
+
this.customFooter = undefined;
|
|
3834
|
+
if (this.customHeader?.dispose) {
|
|
3835
|
+
this.customHeader.dispose();
|
|
3836
|
+
}
|
|
3837
|
+
this.customHeader = undefined;
|
|
3838
|
+
this.autocompleteProvider = undefined;
|
|
3839
|
+
|
|
3808
3840
|
this.footer.dispose();
|
|
3809
3841
|
this.footerDataProvider.dispose();
|
|
3810
3842
|
if (this.unsubscribe) {
|
|
@@ -236,6 +236,13 @@ export async function dispatchSlashCommand(
|
|
|
236
236
|
return true;
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
+
// If input starts with "/" but no command matched, show unknown command feedback
|
|
240
|
+
if (text.startsWith("/")) {
|
|
241
|
+
const command = text.split(/\s/)[0];
|
|
242
|
+
ctx.showError(`Unknown command: ${command}. Type /help for available commands.`);
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
|
|
239
246
|
return false;
|
|
240
247
|
}
|
|
241
248
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"themes.js","sourceRoot":"","sources":["../../../../src/modes/interactive/theme/themes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Built-in theme definitions.\n *\n * Each theme is a self-contained record of color values. Variable references\n * (e.g. \"accent\") are resolved against the `vars` map at load time by the\n * theme engine in theme.ts.\n *\n * To add a new built-in theme, add an entry to `builtinThemes` below.\n */\n\n// Re-use the ThemeJson type from the schema defined in theme.ts.\n// We import only the type to avoid circular runtime dependencies.\nimport type { ThemeJson } from \"./theme.js\";\n\n// ---------------------------------------------------------------------------\n// Dark theme\n// ---------------------------------------------------------------------------\n\nconst dark: ThemeJson = {\n\tname: \"dark\",\n\tvars: {\n\t\tcyan: \"#00d7ff\",\n\t\tblue: \"#5f87ff\",\n\t\tgreen: \"#b5bd68\",\n\t\tred: \"#cc6666\",\n\t\tyellow: \"#
|
|
1
|
+
{"version":3,"file":"themes.js","sourceRoot":"","sources":["../../../../src/modes/interactive/theme/themes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Built-in theme definitions.\n *\n * Each theme is a self-contained record of color values. Variable references\n * (e.g. \"accent\") are resolved against the `vars` map at load time by the\n * theme engine in theme.ts.\n *\n * To add a new built-in theme, add an entry to `builtinThemes` below.\n */\n\n// Re-use the ThemeJson type from the schema defined in theme.ts.\n// We import only the type to avoid circular runtime dependencies.\nimport type { ThemeJson } from \"./theme.js\";\n\n// ---------------------------------------------------------------------------\n// Dark theme\n// ---------------------------------------------------------------------------\n\nconst dark: ThemeJson = {\n\tname: \"dark\",\n\tvars: {\n\t\tcyan: \"#00d7ff\",\n\t\tblue: \"#5f87ff\",\n\t\tgreen: \"#b5bd68\",\n\t\tred: \"#cc6666\",\n\t\tyellow: \"#e6b800\",\n\t\tgray: \"#808080\",\n\t\tdimGray: \"#666666\",\n\t\tdarkGray: \"#505050\",\n\t\taccent: \"#8abeb7\",\n\t\tselectedBg: \"#3a3a4a\",\n\t\tuserMsgBg: \"#343541\",\n\t\ttoolPendingBg: \"#282832\",\n\t\ttoolSuccessBg: \"#283228\",\n\t\ttoolErrorBg: \"#3c2828\",\n\t\tcustomMsgBg: \"#2d2838\",\n\t},\n\tcolors: {\n\t\taccent: \"accent\",\n\t\tborder: \"blue\",\n\t\tborderAccent: \"cyan\",\n\t\tborderMuted: \"darkGray\",\n\t\tsuccess: \"green\",\n\t\terror: \"red\",\n\t\twarning: \"yellow\",\n\t\tmuted: \"gray\",\n\t\tdim: \"dimGray\",\n\t\ttext: \"\",\n\t\tthinkingText: \"gray\",\n\n\t\tselectedBg: \"selectedBg\",\n\t\tuserMessageBg: \"userMsgBg\",\n\t\tuserMessageText: \"\",\n\t\tcustomMessageBg: \"customMsgBg\",\n\t\tcustomMessageText: \"\",\n\t\tcustomMessageLabel: \"#9575cd\",\n\t\ttoolPendingBg: \"toolPendingBg\",\n\t\ttoolSuccessBg: \"toolSuccessBg\",\n\t\ttoolErrorBg: \"toolErrorBg\",\n\t\ttoolTitle: \"\",\n\t\ttoolOutput: \"gray\",\n\n\t\tmdHeading: \"#f0c674\",\n\t\tmdLink: \"#81a2be\",\n\t\tmdLinkUrl: \"dimGray\",\n\t\tmdCode: \"accent\",\n\t\tmdCodeBlock: \"green\",\n\t\tmdCodeBlockBorder: \"gray\",\n\t\tmdQuote: \"gray\",\n\t\tmdQuoteBorder: \"gray\",\n\t\tmdHr: \"gray\",\n\t\tmdListBullet: \"accent\",\n\n\t\ttoolDiffAdded: \"green\",\n\t\ttoolDiffRemoved: \"red\",\n\t\ttoolDiffContext: \"gray\",\n\n\t\tsyntaxComment: \"#6A9955\",\n\t\tsyntaxKeyword: \"#569CD6\",\n\t\tsyntaxFunction: \"#DCDCAA\",\n\t\tsyntaxVariable: \"#9CDCFE\",\n\t\tsyntaxString: \"#CE9178\",\n\t\tsyntaxNumber: \"#B5CEA8\",\n\t\tsyntaxType: \"#4EC9B0\",\n\t\tsyntaxOperator: \"#D4D4D4\",\n\t\tsyntaxPunctuation: \"#D4D4D4\",\n\n\t\tthinkingOff: \"darkGray\",\n\t\tthinkingMinimal: \"#6e6e6e\",\n\t\tthinkingLow: \"#5f87af\",\n\t\tthinkingMedium: \"#81a2be\",\n\t\tthinkingHigh: \"#b294bb\",\n\t\tthinkingXhigh: \"#d183e8\",\n\n\t\tbashMode: \"green\",\n\t},\n\texport: {\n\t\tpageBg: \"#18181e\",\n\t\tcardBg: \"#1e1e24\",\n\t\tinfoBg: \"#3c3728\",\n\t},\n};\n\n// ---------------------------------------------------------------------------\n// Light theme\n// ---------------------------------------------------------------------------\n\nconst light: ThemeJson = {\n\tname: \"light\",\n\tvars: {\n\t\tteal: \"#5a8080\",\n\t\tblue: \"#547da7\",\n\t\tgreen: \"#588458\",\n\t\tred: \"#aa5555\",\n\t\tyellow: \"#9a7326\",\n\t\twarning: \"#7a5a00\",\n\t\tmediumGray: \"#6c6c6c\",\n\t\tdimGray: \"#767676\",\n\t\tlightGray: \"#b0b0b0\",\n\t\tselectedBg: \"#d0d0e0\",\n\t\tuserMsgBg: \"#e8e8e8\",\n\t\ttoolPendingBg: \"#e8e8f0\",\n\t\ttoolSuccessBg: \"#e8f0e8\",\n\t\ttoolErrorBg: \"#f0e8e8\",\n\t\tcustomMsgBg: \"#ede7f6\",\n\t},\n\tcolors: {\n\t\taccent: \"teal\",\n\t\tborder: \"blue\",\n\t\tborderAccent: \"teal\",\n\t\tborderMuted: \"lightGray\",\n\t\tsuccess: \"green\",\n\t\terror: \"red\",\n\t\twarning: \"warning\",\n\t\tmuted: \"mediumGray\",\n\t\tdim: \"dimGray\",\n\t\ttext: \"\",\n\t\tthinkingText: \"mediumGray\",\n\n\t\tselectedBg: \"selectedBg\",\n\t\tuserMessageBg: \"userMsgBg\",\n\t\tuserMessageText: \"\",\n\t\tcustomMessageBg: \"customMsgBg\",\n\t\tcustomMessageText: \"\",\n\t\tcustomMessageLabel: \"#7e57c2\",\n\t\ttoolPendingBg: \"toolPendingBg\",\n\t\ttoolSuccessBg: \"toolSuccessBg\",\n\t\ttoolErrorBg: \"toolErrorBg\",\n\t\ttoolTitle: \"\",\n\t\ttoolOutput: \"mediumGray\",\n\n\t\tmdHeading: \"yellow\",\n\t\tmdLink: \"blue\",\n\t\tmdLinkUrl: \"dimGray\",\n\t\tmdCode: \"teal\",\n\t\tmdCodeBlock: \"green\",\n\t\tmdCodeBlockBorder: \"mediumGray\",\n\t\tmdQuote: \"mediumGray\",\n\t\tmdQuoteBorder: \"mediumGray\",\n\t\tmdHr: \"mediumGray\",\n\t\tmdListBullet: \"green\",\n\n\t\ttoolDiffAdded: \"green\",\n\t\ttoolDiffRemoved: \"red\",\n\t\ttoolDiffContext: \"mediumGray\",\n\n\t\tsyntaxComment: \"#008000\",\n\t\tsyntaxKeyword: \"#0000FF\",\n\t\tsyntaxFunction: \"#795E26\",\n\t\tsyntaxVariable: \"#001080\",\n\t\tsyntaxString: \"#A31515\",\n\t\tsyntaxNumber: \"#098658\",\n\t\tsyntaxType: \"#267F99\",\n\t\tsyntaxOperator: \"#000000\",\n\t\tsyntaxPunctuation: \"#000000\",\n\n\t\tthinkingOff: \"lightGray\",\n\t\tthinkingMinimal: \"#767676\",\n\t\tthinkingLow: \"blue\",\n\t\tthinkingMedium: \"teal\",\n\t\tthinkingHigh: \"#875f87\",\n\t\tthinkingXhigh: \"#8b008b\",\n\n\t\tbashMode: \"green\",\n\t},\n\texport: {\n\t\tpageBg: \"#f8f8f8\",\n\t\tcardBg: \"#ffffff\",\n\t\tinfoBg: \"#fffae6\",\n\t},\n};\n\n// ---------------------------------------------------------------------------\n// Export\n// ---------------------------------------------------------------------------\n\nexport const builtinThemes: Record<string, ThemeJson> = { dark, light };\n"]}
|
|
@@ -1566,14 +1566,17 @@ export function mergeMilestoneToMain(
|
|
|
1566
1566
|
// Non-fatal — proceed with merge; untracked files may block it
|
|
1567
1567
|
}
|
|
1568
1568
|
|
|
1569
|
-
//
|
|
1570
|
-
//
|
|
1571
|
-
//
|
|
1572
|
-
//
|
|
1569
|
+
// 7b. Clean up stale merge state before attempting squash merge (#2912).
|
|
1570
|
+
// A leftover MERGE_HEAD (from a previous failed merge, libgit2 native path,
|
|
1571
|
+
// or interrupted operation) causes `git merge --squash` to refuse with
|
|
1572
|
+
// "fatal: You have not concluded your merge (MERGE_HEAD exists)".
|
|
1573
|
+
// Defensively remove merge artifacts before starting.
|
|
1573
1574
|
try {
|
|
1574
|
-
const
|
|
1575
|
-
const
|
|
1576
|
-
|
|
1575
|
+
const gitDir_ = resolveGitDir(originalBasePath_);
|
|
1576
|
+
for (const f of ["SQUASH_MSG", "MERGE_MSG", "MERGE_HEAD"]) {
|
|
1577
|
+
const p = join(gitDir_, f);
|
|
1578
|
+
if (existsSync(p)) unlinkSync(p);
|
|
1579
|
+
}
|
|
1577
1580
|
} catch { /* best-effort */ }
|
|
1578
1581
|
|
|
1579
1582
|
// 8. Squash merge — auto-resolve .gsd/ state file conflicts (#530)
|
|
@@ -48,26 +48,20 @@ export function registerHooks(pi: ExtensionAPI): void {
|
|
|
48
48
|
const { dirname } = await import("node:path");
|
|
49
49
|
const { printWelcomeScreen } = await import(
|
|
50
50
|
join(dirname(gsdBinPath), "welcome-screen.js")
|
|
51
|
-
) as { printWelcomeScreen: (opts: { version: string; modelName?: string; provider?: string }) => void };
|
|
52
|
-
|
|
51
|
+
) as { printWelcomeScreen: (opts: { version: string; modelName?: string; provider?: string; remoteChannel?: string }) => void };
|
|
52
|
+
|
|
53
|
+
let remoteChannel: string | undefined;
|
|
54
|
+
try {
|
|
55
|
+
const { resolveRemoteConfig } = await import("../../remote-questions/config.js");
|
|
56
|
+
const rc = resolveRemoteConfig();
|
|
57
|
+
if (rc) remoteChannel = rc.channel;
|
|
58
|
+
} catch { /* non-fatal */ }
|
|
59
|
+
|
|
60
|
+
printWelcomeScreen({ version: process.env.GSD_VERSION || "0.0.0", remoteChannel });
|
|
53
61
|
}
|
|
54
62
|
} catch { /* non-fatal */ }
|
|
55
63
|
}
|
|
56
64
|
loadToolApiKeys();
|
|
57
|
-
try {
|
|
58
|
-
const [{ getRemoteConfigStatus }, { getLatestPromptSummary }] = await Promise.all([
|
|
59
|
-
import("../../remote-questions/config.js"),
|
|
60
|
-
import("../../remote-questions/status.js"),
|
|
61
|
-
]);
|
|
62
|
-
const status = getRemoteConfigStatus();
|
|
63
|
-
const latest = getLatestPromptSummary();
|
|
64
|
-
if (!status.includes("not configured")) {
|
|
65
|
-
const suffix = latest ? `\nLast remote prompt: ${latest.id} (${latest.status})` : "";
|
|
66
|
-
ctx.ui.notify(`${status}${suffix}`, status.includes("disabled") ? "warning" : "info");
|
|
67
|
-
}
|
|
68
|
-
} catch {
|
|
69
|
-
// ignore
|
|
70
|
-
}
|
|
71
65
|
});
|
|
72
66
|
|
|
73
67
|
pi.on("session_switch", async (_event, ctx) => {
|
|
@@ -95,6 +95,27 @@ export async function buildBeforeAgentStartResult(
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
let codebaseBlock = "";
|
|
99
|
+
const codebasePath = resolveGsdRootFile(process.cwd(), "CODEBASE");
|
|
100
|
+
if (existsSync(codebasePath)) {
|
|
101
|
+
try {
|
|
102
|
+
const rawContent = readFileSync(codebasePath, "utf-8").trim();
|
|
103
|
+
if (rawContent) {
|
|
104
|
+
// Cap injection size to ~2 000 tokens to avoid bloating every request.
|
|
105
|
+
// Full map is always available at .gsd/CODEBASE.md.
|
|
106
|
+
const MAX_CODEBASE_CHARS = 8_000;
|
|
107
|
+
const generatedMatch = rawContent.match(/Generated: (\S+)/);
|
|
108
|
+
const generatedAt = generatedMatch?.[1] ?? "unknown";
|
|
109
|
+
const content = rawContent.length > MAX_CODEBASE_CHARS
|
|
110
|
+
? rawContent.slice(0, MAX_CODEBASE_CHARS) + "\n\n*(truncated — see .gsd/CODEBASE.md for full map)*"
|
|
111
|
+
: rawContent;
|
|
112
|
+
codebaseBlock = `\n\n[PROJECT CODEBASE — File structure and descriptions (generated ${generatedAt}, may be stale — run /gsd codebase update to refresh)]\n\n${content}`;
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
// skip
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
98
119
|
warnDeprecatedAgentInstructions();
|
|
99
120
|
|
|
100
121
|
const injection = await buildGuidedExecuteContextInjection(event.prompt, process.cwd());
|
|
@@ -103,7 +124,7 @@ export async function buildBeforeAgentStartResult(
|
|
|
103
124
|
const forensicsInjection = !injection ? buildForensicsContextInjection(process.cwd()) : null;
|
|
104
125
|
|
|
105
126
|
const worktreeBlock = buildWorktreeContextBlock();
|
|
106
|
-
const fullSystem = `${event.systemPrompt}\n\n[SYSTEM CONTEXT — GSD]\n\n${systemContent}${preferenceBlock}${knowledgeBlock}${memoryBlock}${newSkillsBlock}${worktreeBlock}`;
|
|
127
|
+
const fullSystem = `${event.systemPrompt}\n\n[SYSTEM CONTEXT — GSD]\n\n${systemContent}${preferenceBlock}${knowledgeBlock}${codebaseBlock}${memoryBlock}${newSkillsBlock}${worktreeBlock}`;
|
|
107
128
|
|
|
108
129
|
stopContextTimer({
|
|
109
130
|
systemPromptSize: fullSystem.length,
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GSD Codebase Map Generator
|
|
3
|
+
*
|
|
4
|
+
* Produces .gsd/CODEBASE.md — a structural table of contents for the project.
|
|
5
|
+
* Gives fresh agent contexts instant orientation without filesystem exploration.
|
|
6
|
+
*
|
|
7
|
+
* Generation: walk `git ls-files`, group by directory, output with descriptions.
|
|
8
|
+
* Maintenance: agent updates descriptions as it works; incremental update preserves them.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
12
|
+
import { join, dirname, extname } from "node:path";
|
|
13
|
+
|
|
14
|
+
import { execSync } from "node:child_process";
|
|
15
|
+
import { gsdRoot } from "./paths.js";
|
|
16
|
+
|
|
17
|
+
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
export interface CodebaseMapOptions {
|
|
20
|
+
excludePatterns?: string[];
|
|
21
|
+
maxFiles?: number;
|
|
22
|
+
collapseThreshold?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface FileEntry {
|
|
26
|
+
path: string;
|
|
27
|
+
description: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface DirectoryGroup {
|
|
31
|
+
path: string;
|
|
32
|
+
files: FileEntry[];
|
|
33
|
+
collapsed: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ─── Defaults ────────────────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
const DEFAULT_EXCLUDES = [
|
|
39
|
+
".gsd/",
|
|
40
|
+
".planning/",
|
|
41
|
+
".git/",
|
|
42
|
+
"node_modules/",
|
|
43
|
+
"dist/",
|
|
44
|
+
"build/",
|
|
45
|
+
".next/",
|
|
46
|
+
"coverage/",
|
|
47
|
+
"__pycache__/",
|
|
48
|
+
".venv/",
|
|
49
|
+
"vendor/",
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
const DEFAULT_MAX_FILES = 500;
|
|
53
|
+
const DEFAULT_COLLAPSE_THRESHOLD = 20;
|
|
54
|
+
|
|
55
|
+
// ─── Parsing ─────────────────────────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Parse an existing CODEBASE.md to extract file → description mappings.
|
|
59
|
+
* Also scans <!-- gsd:collapsed-descriptions --> comment blocks to preserve
|
|
60
|
+
* descriptions for files in collapsed directories across incremental updates.
|
|
61
|
+
*/
|
|
62
|
+
export function parseCodebaseMap(content: string): Map<string, string> {
|
|
63
|
+
const descriptions = new Map<string, string>();
|
|
64
|
+
let inCollapsedBlock = false;
|
|
65
|
+
|
|
66
|
+
for (const line of content.split("\n")) {
|
|
67
|
+
// Track collapsed-description comment blocks
|
|
68
|
+
if (line.trimStart().startsWith("<!-- gsd:collapsed-descriptions")) {
|
|
69
|
+
inCollapsedBlock = true;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (inCollapsedBlock && line.trimStart().startsWith("-->")) {
|
|
73
|
+
inCollapsedBlock = false;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Match: - `path/to/file.ts` — Description here
|
|
78
|
+
const match = line.match(/^- `(.+?)` — (.+)$/);
|
|
79
|
+
if (match) {
|
|
80
|
+
descriptions.set(match[1], match[2]);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Match: - `path/to/file.ts` (no description) — only outside collapsed blocks
|
|
85
|
+
if (!inCollapsedBlock) {
|
|
86
|
+
const bareMatch = line.match(/^- `(.+?)`\s*$/);
|
|
87
|
+
if (bareMatch) {
|
|
88
|
+
descriptions.set(bareMatch[1], "");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return descriptions;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ─── File Enumeration ────────────────────────────────────────────────────────
|
|
96
|
+
|
|
97
|
+
function shouldExclude(filePath: string, excludes: string[]): boolean {
|
|
98
|
+
for (const pattern of excludes) {
|
|
99
|
+
if (pattern.endsWith("/")) {
|
|
100
|
+
if (filePath.startsWith(pattern) || filePath.includes(`/${pattern}`)) return true;
|
|
101
|
+
} else if (filePath === pattern || filePath.endsWith(`/${pattern}`)) {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Skip binary/lock files
|
|
106
|
+
const ext = extname(filePath).toLowerCase();
|
|
107
|
+
if ([".lock", ".png", ".jpg", ".jpeg", ".gif", ".ico", ".woff", ".woff2", ".ttf", ".eot", ".svg"].includes(ext)) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function lsFiles(basePath: string): string[] {
|
|
114
|
+
try {
|
|
115
|
+
const result = execSync("git ls-files", { cwd: basePath, encoding: "utf-8", timeout: 10000 });
|
|
116
|
+
return result.split("\n").filter(Boolean);
|
|
117
|
+
} catch {
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Enumerate tracked files, applying exclusions and the maxFiles cap.
|
|
124
|
+
* Returns both the file list and whether truncation occurred.
|
|
125
|
+
*/
|
|
126
|
+
function enumerateFiles(basePath: string, excludes: string[], maxFiles: number): { files: string[]; truncated: boolean } {
|
|
127
|
+
const allFiles = lsFiles(basePath);
|
|
128
|
+
const filtered = allFiles.filter((f) => !shouldExclude(f, excludes));
|
|
129
|
+
const truncated = filtered.length > maxFiles;
|
|
130
|
+
return { files: truncated ? filtered.slice(0, maxFiles) : filtered, truncated };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ─── Grouping ────────────────────────────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
function groupByDirectory(
|
|
136
|
+
files: string[],
|
|
137
|
+
descriptions: Map<string, string>,
|
|
138
|
+
collapseThreshold: number,
|
|
139
|
+
): DirectoryGroup[] {
|
|
140
|
+
const dirMap = new Map<string, FileEntry[]>();
|
|
141
|
+
|
|
142
|
+
for (const file of files) {
|
|
143
|
+
const dir = dirname(file);
|
|
144
|
+
const dirKey = dir === "." ? "" : dir;
|
|
145
|
+
if (!dirMap.has(dirKey)) {
|
|
146
|
+
dirMap.set(dirKey, []);
|
|
147
|
+
}
|
|
148
|
+
dirMap.get(dirKey)!.push({
|
|
149
|
+
path: file,
|
|
150
|
+
description: descriptions.get(file) ?? "",
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const groups: DirectoryGroup[] = [];
|
|
155
|
+
const sortedDirs = [...dirMap.keys()].sort();
|
|
156
|
+
|
|
157
|
+
for (const dir of sortedDirs) {
|
|
158
|
+
const dirFiles = dirMap.get(dir)!;
|
|
159
|
+
dirFiles.sort((a, b) => a.path.localeCompare(b.path));
|
|
160
|
+
|
|
161
|
+
groups.push({
|
|
162
|
+
path: dir,
|
|
163
|
+
files: dirFiles,
|
|
164
|
+
collapsed: dirFiles.length > collapseThreshold,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return groups;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ─── Rendering ───────────────────────────────────────────────────────────────
|
|
172
|
+
|
|
173
|
+
function renderCodebaseMap(groups: DirectoryGroup[], totalFiles: number, truncated: boolean): string {
|
|
174
|
+
const lines: string[] = [];
|
|
175
|
+
const now = new Date().toISOString().split(".")[0] + "Z";
|
|
176
|
+
const described = groups.reduce((sum, g) => sum + g.files.filter((f) => f.description).length, 0);
|
|
177
|
+
|
|
178
|
+
lines.push("# Codebase Map");
|
|
179
|
+
lines.push("");
|
|
180
|
+
lines.push(`Generated: ${now} | Files: ${totalFiles} | Described: ${described}/${totalFiles}`);
|
|
181
|
+
if (truncated) {
|
|
182
|
+
lines.push(`Note: Truncated to first ${totalFiles} files. Run with higher --max-files to include all.`);
|
|
183
|
+
}
|
|
184
|
+
lines.push("");
|
|
185
|
+
|
|
186
|
+
for (const group of groups) {
|
|
187
|
+
const heading = group.path || "(root)";
|
|
188
|
+
lines.push(`### ${heading}/`);
|
|
189
|
+
|
|
190
|
+
if (group.collapsed) {
|
|
191
|
+
// Summarize collapsed directories
|
|
192
|
+
const extensions = new Map<string, number>();
|
|
193
|
+
for (const f of group.files) {
|
|
194
|
+
const ext = extname(f.path) || "(no ext)";
|
|
195
|
+
extensions.set(ext, (extensions.get(ext) ?? 0) + 1);
|
|
196
|
+
}
|
|
197
|
+
const extSummary = [...extensions.entries()]
|
|
198
|
+
.sort((a, b) => b[1] - a[1])
|
|
199
|
+
.map(([ext, count]) => `${count} ${ext}`)
|
|
200
|
+
.join(", ");
|
|
201
|
+
lines.push(`- *(${group.files.length} files: ${extSummary})*`);
|
|
202
|
+
|
|
203
|
+
// Preserve any existing descriptions in a hidden comment block so
|
|
204
|
+
// incremental updates can recover them via parseCodebaseMap.
|
|
205
|
+
const descLines = group.files
|
|
206
|
+
.filter((f) => f.description)
|
|
207
|
+
.map((f) => `- \`${f.path}\` — ${f.description}`);
|
|
208
|
+
if (descLines.length > 0) {
|
|
209
|
+
lines.push("<!-- gsd:collapsed-descriptions");
|
|
210
|
+
lines.push(...descLines);
|
|
211
|
+
lines.push("-->");
|
|
212
|
+
}
|
|
213
|
+
} else {
|
|
214
|
+
for (const file of group.files) {
|
|
215
|
+
if (file.description) {
|
|
216
|
+
lines.push(`- \`${file.path}\` — ${file.description}`);
|
|
217
|
+
} else {
|
|
218
|
+
lines.push(`- \`${file.path}\``);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
lines.push("");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return lines.join("\n");
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ─── Public API ──────────────────────────────────────────────────────────────
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Generate a fresh CODEBASE.md from scratch.
|
|
232
|
+
* Preserves existing descriptions if `existingDescriptions` is provided.
|
|
233
|
+
*/
|
|
234
|
+
export function generateCodebaseMap(
|
|
235
|
+
basePath: string,
|
|
236
|
+
options?: CodebaseMapOptions,
|
|
237
|
+
existingDescriptions?: Map<string, string>,
|
|
238
|
+
): { content: string; fileCount: number; truncated: boolean; files: string[] } {
|
|
239
|
+
const excludes = [...DEFAULT_EXCLUDES, ...(options?.excludePatterns ?? [])];
|
|
240
|
+
const maxFiles = options?.maxFiles ?? DEFAULT_MAX_FILES;
|
|
241
|
+
const collapseThreshold = options?.collapseThreshold ?? DEFAULT_COLLAPSE_THRESHOLD;
|
|
242
|
+
|
|
243
|
+
const { files, truncated } = enumerateFiles(basePath, excludes, maxFiles);
|
|
244
|
+
const descriptions = existingDescriptions ?? new Map<string, string>();
|
|
245
|
+
const groups = groupByDirectory(files, descriptions, collapseThreshold);
|
|
246
|
+
const content = renderCodebaseMap(groups, files.length, truncated);
|
|
247
|
+
|
|
248
|
+
return { content, fileCount: files.length, truncated, files };
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Incremental update: re-scan files, preserve existing descriptions,
|
|
253
|
+
* add new files, remove deleted files.
|
|
254
|
+
*/
|
|
255
|
+
export function updateCodebaseMap(
|
|
256
|
+
basePath: string,
|
|
257
|
+
options?: CodebaseMapOptions,
|
|
258
|
+
): { content: string; added: number; removed: number; unchanged: number; fileCount: number; truncated: boolean } {
|
|
259
|
+
const codebasePath = join(gsdRoot(basePath), "CODEBASE.md");
|
|
260
|
+
|
|
261
|
+
// Load existing descriptions
|
|
262
|
+
let existingDescriptions = new Map<string, string>();
|
|
263
|
+
if (existsSync(codebasePath)) {
|
|
264
|
+
const existing = readFileSync(codebasePath, "utf-8");
|
|
265
|
+
existingDescriptions = parseCodebaseMap(existing);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const existingFiles = new Set(existingDescriptions.keys());
|
|
269
|
+
|
|
270
|
+
// Generate new map preserving descriptions — reuse the returned file list
|
|
271
|
+
// to avoid a second enumeration (prevents race between content and stats).
|
|
272
|
+
const result = generateCodebaseMap(basePath, options, existingDescriptions);
|
|
273
|
+
const currentSet = new Set(result.files);
|
|
274
|
+
|
|
275
|
+
// Count changes
|
|
276
|
+
let added = 0;
|
|
277
|
+
let removed = 0;
|
|
278
|
+
|
|
279
|
+
for (const f of result.files) {
|
|
280
|
+
if (!existingFiles.has(f)) added++;
|
|
281
|
+
}
|
|
282
|
+
for (const f of existingFiles) {
|
|
283
|
+
if (!currentSet.has(f)) removed++;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return {
|
|
287
|
+
content: result.content,
|
|
288
|
+
added,
|
|
289
|
+
removed,
|
|
290
|
+
unchanged: result.files.length - added,
|
|
291
|
+
fileCount: result.fileCount,
|
|
292
|
+
truncated: result.truncated,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Write CODEBASE.md to .gsd/ directory.
|
|
298
|
+
*/
|
|
299
|
+
export function writeCodebaseMap(basePath: string, content: string): string {
|
|
300
|
+
const root = gsdRoot(basePath);
|
|
301
|
+
mkdirSync(root, { recursive: true });
|
|
302
|
+
const outPath = join(root, "CODEBASE.md");
|
|
303
|
+
writeFileSync(outPath, content, "utf-8");
|
|
304
|
+
return outPath;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Read existing CODEBASE.md, or return null if it doesn't exist.
|
|
309
|
+
*/
|
|
310
|
+
export function readCodebaseMap(basePath: string): string | null {
|
|
311
|
+
const codebasePath = join(gsdRoot(basePath), "CODEBASE.md");
|
|
312
|
+
if (!existsSync(codebasePath)) return null;
|
|
313
|
+
try {
|
|
314
|
+
return readFileSync(codebasePath, "utf-8");
|
|
315
|
+
} catch {
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Get stats about the codebase map.
|
|
322
|
+
*/
|
|
323
|
+
export function getCodebaseMapStats(basePath: string): {
|
|
324
|
+
exists: boolean;
|
|
325
|
+
fileCount: number;
|
|
326
|
+
describedCount: number;
|
|
327
|
+
undescribedCount: number;
|
|
328
|
+
generatedAt: string | null;
|
|
329
|
+
} {
|
|
330
|
+
const content = readCodebaseMap(basePath);
|
|
331
|
+
if (!content) {
|
|
332
|
+
return { exists: false, fileCount: 0, describedCount: 0, undescribedCount: 0, generatedAt: null };
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Parse total file count from the header line (accurate even for collapsed dirs)
|
|
336
|
+
const fileCountMatch = content.match(/Files:\s*(\d+)/);
|
|
337
|
+
const totalFiles = fileCountMatch ? parseInt(fileCountMatch[1], 10) : 0;
|
|
338
|
+
|
|
339
|
+
// Use parseCodebaseMap to count described files (includes collapsed-description blocks)
|
|
340
|
+
const descriptions = parseCodebaseMap(content);
|
|
341
|
+
const described = [...descriptions.values()].filter((d) => d.length > 0).length;
|
|
342
|
+
const dateMatch = content.match(/Generated: (\S+)/);
|
|
343
|
+
|
|
344
|
+
return {
|
|
345
|
+
exists: true,
|
|
346
|
+
fileCount: totalFiles,
|
|
347
|
+
describedCount: described,
|
|
348
|
+
undescribedCount: totalFiles - described,
|
|
349
|
+
generatedAt: dateMatch?.[1] ?? null,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
@@ -15,7 +15,7 @@ export interface GsdCommandDefinition {
|
|
|
15
15
|
type CompletionMap = Record<string, readonly GsdCommandDefinition[]>;
|
|
16
16
|
|
|
17
17
|
export const GSD_COMMAND_DESCRIPTION =
|
|
18
|
-
"GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|cmux|park|unpark|init|setup|inspect|extensions|update|fast|mcp|rethink";
|
|
18
|
+
"GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|cmux|park|unpark|init|setup|inspect|extensions|update|fast|mcp|rethink|codebase";
|
|
19
19
|
|
|
20
20
|
export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
|
|
21
21
|
{ cmd: "help", desc: "Categorized command reference with descriptions" },
|
|
@@ -71,6 +71,7 @@ export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
|
|
|
71
71
|
{ cmd: "mcp", desc: "MCP server status and connectivity check (status, check <server>)" },
|
|
72
72
|
{ cmd: "rethink", desc: "Conversational project reorganization — reorder, park, discard, add milestones" },
|
|
73
73
|
{ cmd: "workflow", desc: "Custom workflow lifecycle (new, run, list, validate, pause, resume)" },
|
|
74
|
+
{ cmd: "codebase", desc: "Generate and manage codebase map (.gsd/CODEBASE.md)" },
|
|
74
75
|
];
|
|
75
76
|
|
|
76
77
|
const NESTED_COMPLETIONS: CompletionMap = {
|
|
@@ -225,6 +226,14 @@ const NESTED_COMPLETIONS: CompletionMap = {
|
|
|
225
226
|
{ cmd: "pause", desc: "Pause custom workflow auto-mode" },
|
|
226
227
|
{ cmd: "resume", desc: "Resume paused custom workflow auto-mode" },
|
|
227
228
|
],
|
|
229
|
+
codebase: [
|
|
230
|
+
{ cmd: "generate", desc: "Generate or regenerate CODEBASE.md" },
|
|
231
|
+
{ cmd: "generate --max-files", desc: "Generate with custom file limit (default: 500)" },
|
|
232
|
+
{ cmd: "update", desc: "Incremental update (preserves descriptions)" },
|
|
233
|
+
{ cmd: "update --max-files", desc: "Update with custom file limit" },
|
|
234
|
+
{ cmd: "stats", desc: "Show file count, description coverage, and generation time" },
|
|
235
|
+
{ cmd: "help", desc: "Show usage and available subcommands" },
|
|
236
|
+
],
|
|
228
237
|
};
|
|
229
238
|
|
|
230
239
|
function filterOptions(
|