gsd-pi 2.73.1-dev.6f61020 → 2.73.1-dev.a2eb797
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-web-branch.d.ts +4 -3
- package/dist/cli-web-branch.js +10 -7
- package/dist/cli.js +99 -206
- package/dist/logo.d.ts +1 -1
- package/dist/logo.js +1 -1
- package/dist/onboarding.js +59 -53
- package/dist/resource-loader.js +2 -2
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +59 -1
- package/dist/resources/extensions/gsd/auto/phases.js +15 -9
- package/dist/resources/extensions/gsd/auto-dispatch.js +11 -3
- package/dist/resources/extensions/gsd/auto-post-unit.js +41 -1
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +13 -0
- package/dist/resources/extensions/gsd/auto-verification.js +88 -3
- package/dist/resources/extensions/gsd/auto.js +21 -8
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/notification-widget.js +2 -2
- package/dist/resources/extensions/gsd/state.js +61 -14
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
- 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 +1 -1
- 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 +14 -14
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -2
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +138 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.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 +8 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts +2 -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 +9 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +52 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -0
- 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 +21 -4
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +5 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +157 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +73 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +9 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +21 -4
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +5 -1
- package/packages/pi-tui/dist/__tests__/tui.test.js +30 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts +1 -0
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +22 -3
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/__tests__/tui.test.ts +38 -0
- package/packages/pi-tui/src/tui.ts +20 -3
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +95 -1
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +88 -0
- package/src/resources/extensions/gsd/auto/phases.ts +22 -9
- package/src/resources/extensions/gsd/auto-dispatch.ts +10 -4
- package/src/resources/extensions/gsd/auto-post-unit.ts +47 -1
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +17 -0
- package/src/resources/extensions/gsd/auto-verification.ts +98 -3
- package/src/resources/extensions/gsd/auto.ts +26 -14
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/notification-widget.ts +2 -2
- package/src/resources/extensions/gsd/state.ts +71 -15
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +68 -8
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +179 -0
- /package/dist/web/standalone/.next/static/{xEc_9MXTYTFRfqJP-SGqp → rCeJUc4hHW3VT0ARiIinf}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{xEc_9MXTYTFRfqJP-SGqp → rCeJUc4hHW3VT0ARiIinf}/_ssgManifest.js +0 -0
package/dist/cli-web-branch.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { launchWebMode, stopWebMode, type WebModeLaunchStatus, type WebModeStopOptions, type WebModeStopResult } from './web-mode.js';
|
|
2
2
|
export interface CliFlags {
|
|
3
|
-
mode?: 'text' | 'json' | 'rpc';
|
|
3
|
+
mode?: 'text' | 'json' | 'rpc' | 'mcp';
|
|
4
4
|
print?: boolean;
|
|
5
5
|
continue?: boolean;
|
|
6
6
|
noSession?: boolean;
|
|
7
|
+
worktree?: boolean | string;
|
|
7
8
|
model?: string;
|
|
8
9
|
listModels?: string | true;
|
|
9
10
|
extensions: string[];
|
|
@@ -19,8 +20,8 @@ export interface CliFlags {
|
|
|
19
20
|
webPort?: number;
|
|
20
21
|
/** Additional allowed origins for CORS: `--allowed-origins http://192.168.1.10:8080` */
|
|
21
22
|
webAllowedOrigins?: string[];
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
/** Set by `gsd sessions` when the user picks a specific session to resume */
|
|
24
|
+
_selectedSessionPath?: string;
|
|
24
25
|
}
|
|
25
26
|
type WritableLike = Pick<typeof process.stderr, 'write'>;
|
|
26
27
|
export interface RunWebCliBranchDeps {
|
package/dist/cli-web-branch.js
CHANGED
|
@@ -10,7 +10,7 @@ export function parseCliArgs(argv) {
|
|
|
10
10
|
const arg = args[i];
|
|
11
11
|
if (arg === '--mode' && i + 1 < args.length) {
|
|
12
12
|
const mode = args[++i];
|
|
13
|
-
if (mode === 'text' || mode === 'json' || mode === 'rpc')
|
|
13
|
+
if (mode === 'text' || mode === 'json' || mode === 'rpc' || mode === 'mcp')
|
|
14
14
|
flags.mode = mode;
|
|
15
15
|
}
|
|
16
16
|
else if (arg === '--print' || arg === '-p') {
|
|
@@ -22,6 +22,15 @@ export function parseCliArgs(argv) {
|
|
|
22
22
|
else if (arg === '--no-session') {
|
|
23
23
|
flags.noSession = true;
|
|
24
24
|
}
|
|
25
|
+
else if (arg === '--worktree' || arg === '-w') {
|
|
26
|
+
// -w with no value → auto-generate name; -w <name> → use that name
|
|
27
|
+
if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
|
28
|
+
flags.worktree = args[++i];
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
flags.worktree = true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
25
34
|
else if (arg === '--web') {
|
|
26
35
|
flags.web = true;
|
|
27
36
|
// Peek at next arg — if it looks like a path (not another flag), capture it
|
|
@@ -58,12 +67,6 @@ export function parseCliArgs(argv) {
|
|
|
58
67
|
else if (arg === '--list-models') {
|
|
59
68
|
flags.listModels = (i + 1 < args.length && !args[i + 1].startsWith('-')) ? args[++i] : true;
|
|
60
69
|
}
|
|
61
|
-
else if (arg === '--version' || arg === '-v') {
|
|
62
|
-
flags.version = true;
|
|
63
|
-
}
|
|
64
|
-
else if (arg === '--help' || arg === '-h') {
|
|
65
|
-
flags.help = true;
|
|
66
|
-
}
|
|
67
70
|
else if (!arg.startsWith('--') && !arg.startsWith('-')) {
|
|
68
71
|
flags.messages.push(arg);
|
|
69
72
|
}
|
package/dist/cli.js
CHANGED
|
@@ -5,13 +5,14 @@ import { agentDir, sessionsDir, authFilePath } from './app-paths.js';
|
|
|
5
5
|
import { initResources, buildResourceLoader, getNewerManagedResourceVersion } from './resource-loader.js';
|
|
6
6
|
import { ensureManagedTools } from './tool-bootstrap.js';
|
|
7
7
|
import { loadStoredEnvKeys } from './wizard.js';
|
|
8
|
-
import { migratePiCredentials
|
|
8
|
+
import { migratePiCredentials } from './pi-migration.js';
|
|
9
9
|
import { shouldRunOnboarding, runOnboarding } from './onboarding.js';
|
|
10
10
|
import chalk from 'chalk';
|
|
11
11
|
import { checkForUpdates } from './update-check.js';
|
|
12
12
|
import { printHelp, printSubcommandHelp } from './help-text.js';
|
|
13
13
|
import { applySecurityOverrides } from './security-overrides.js';
|
|
14
|
-
import {
|
|
14
|
+
import { validateConfiguredModel } from './startup-model-validation.js';
|
|
15
|
+
import { parseCliArgs, runWebCliBranch, migrateLegacyFlatSessions, } from './cli-web-branch.js';
|
|
15
16
|
import { stopWebMode } from './web-mode.js';
|
|
16
17
|
import { getProjectSessionsDir } from './project-sessions.js';
|
|
17
18
|
import { markStartup, printStartupTimings } from './startup-timings.js';
|
|
@@ -36,112 +37,85 @@ function exitIfManagedResourcesAreNewer(currentAgentDir) {
|
|
|
36
37
|
`[gsd] Run ${chalk.bold('npm install -g gsd-pi@latest')} or ${chalk.bold('gsd update')}, then try again.\n`);
|
|
37
38
|
process.exit(1);
|
|
38
39
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
flags.noSession = true;
|
|
57
|
-
}
|
|
58
|
-
else if (arg === '--model' && i + 1 < args.length) {
|
|
59
|
-
flags.model = args[++i];
|
|
60
|
-
}
|
|
61
|
-
else if (arg === '--extension' && i + 1 < args.length) {
|
|
62
|
-
flags.extensions.push(args[++i]);
|
|
63
|
-
}
|
|
64
|
-
else if (arg === '--append-system-prompt' && i + 1 < args.length) {
|
|
65
|
-
flags.appendSystemPrompt = args[++i];
|
|
66
|
-
}
|
|
67
|
-
else if (arg === '--tools' && i + 1 < args.length) {
|
|
68
|
-
flags.tools = args[++i].split(',');
|
|
69
|
-
}
|
|
70
|
-
else if (arg === '--list-models') {
|
|
71
|
-
flags.listModels = (i + 1 < args.length && !args[i + 1].startsWith('-')) ? args[++i] : true;
|
|
72
|
-
}
|
|
73
|
-
else if (arg === '--version' || arg === '-v') {
|
|
74
|
-
process.stdout.write((process.env.GSD_VERSION || '0.0.0') + '\n');
|
|
75
|
-
process.exit(0);
|
|
76
|
-
}
|
|
77
|
-
else if (arg === '--worktree' || arg === '-w') {
|
|
78
|
-
// -w with no value → auto-generate name; -w <name> → use that name
|
|
79
|
-
if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
|
80
|
-
flags.worktree = args[++i];
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
flags.worktree = true;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
else if (arg === '--help' || arg === '-h') {
|
|
87
|
-
printHelp(process.env.GSD_VERSION || '0.0.0');
|
|
88
|
-
process.exit(0);
|
|
89
|
-
}
|
|
90
|
-
else if (arg === '--web') {
|
|
91
|
-
flags.web = true;
|
|
92
|
-
// Capture optional project path after --web (not a flag)
|
|
93
|
-
if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
|
94
|
-
flags.webPath = args[++i];
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
else if (!arg.startsWith('--') && !arg.startsWith('-')) {
|
|
98
|
-
flags.messages.push(arg);
|
|
99
|
-
}
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Shared helpers used by both the print and interactive code paths
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
/**
|
|
44
|
+
* Print the non-interactive-mode error and exit. Called both from the early
|
|
45
|
+
* TTY gate (before heavy init) and from the interactive-mode TTY gate right
|
|
46
|
+
* before `InteractiveMode.run()`. The `includeWebHint` variant also lists
|
|
47
|
+
* `--web` and `headless` as alternatives.
|
|
48
|
+
*/
|
|
49
|
+
function printNonTtyErrorAndExit(missing, includeWebHint) {
|
|
50
|
+
const suffix = missing ? ` but ${missing} not a TTY` : '';
|
|
51
|
+
process.stderr.write(`[gsd] Error: Interactive mode requires a terminal (TTY)${suffix}.\n`);
|
|
52
|
+
process.stderr.write('[gsd] Non-interactive alternatives:\n');
|
|
53
|
+
process.stderr.write('[gsd] gsd auto Auto-mode (pipeable, no TUI)\n');
|
|
54
|
+
process.stderr.write('[gsd] gsd --print "your message" Single-shot prompt\n');
|
|
55
|
+
if (includeWebHint) {
|
|
56
|
+
process.stderr.write('[gsd] gsd --web [path] Browser-only web mode\n');
|
|
100
57
|
}
|
|
101
|
-
|
|
58
|
+
process.stderr.write('[gsd] gsd --mode rpc JSON-RPC over stdin/stdout\n');
|
|
59
|
+
process.stderr.write('[gsd] gsd --mode mcp MCP server over stdin/stdout\n');
|
|
60
|
+
process.stderr.write('[gsd] gsd --mode text "message" Text output mode\n');
|
|
61
|
+
if (includeWebHint) {
|
|
62
|
+
process.stderr.write('[gsd] gsd headless Auto-mode without TUI\n');
|
|
63
|
+
}
|
|
64
|
+
process.exit(1);
|
|
102
65
|
}
|
|
103
66
|
/**
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
* providers so that extension models (e.g. pi-claude-cli) are visible.
|
|
67
|
+
* Print extension load/conflict errors from an extensions result. Downgrades
|
|
68
|
+
* conflicts with built-in tools to warnings (#1347).
|
|
107
69
|
*/
|
|
108
|
-
function
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
70
|
+
function printExtensionErrors(errors) {
|
|
71
|
+
for (const err of errors) {
|
|
72
|
+
const isConflict = err.error.includes('supersedes') || err.error.includes('conflicts with');
|
|
73
|
+
const prefix = isConflict ? 'Extension conflict' : 'Extension load error';
|
|
74
|
+
process.stderr.write(`[gsd] ${prefix}: ${err.error}\n`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Re-apply the validated model to the session when `createAgentSession()`
|
|
79
|
+
* reports that it had to use a fallback. Prevents silently overriding the
|
|
80
|
+
* persisted model of resumed conversations (#3534).
|
|
81
|
+
*/
|
|
82
|
+
async function reapplyValidatedModelOnFallback(session, modelRegistry, settingsManager, fallbackMessage) {
|
|
83
|
+
if (!fallbackMessage)
|
|
84
|
+
return;
|
|
85
|
+
const validatedProvider = settingsManager.getDefaultProvider();
|
|
86
|
+
const validatedModelId = settingsManager.getDefaultModel();
|
|
87
|
+
if (!validatedProvider || !validatedModelId)
|
|
88
|
+
return;
|
|
89
|
+
const correctModel = modelRegistry.getAvailable()
|
|
90
|
+
.find((m) => m.provider === validatedProvider && m.id === validatedModelId);
|
|
91
|
+
if (!correctModel)
|
|
92
|
+
return;
|
|
93
|
+
try {
|
|
94
|
+
await session.setModel(correctModel);
|
|
133
95
|
}
|
|
134
|
-
|
|
135
|
-
|
|
96
|
+
catch {
|
|
97
|
+
// Provider not ready — leave session on its current model
|
|
136
98
|
}
|
|
137
99
|
}
|
|
138
100
|
const cliFlags = parseCliArgs(process.argv);
|
|
139
101
|
const isPrintMode = cliFlags.print || cliFlags.mode !== undefined;
|
|
140
|
-
//
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
102
|
+
// `gsd [subcommand] --help` / `-h` — print help before any subcommand runs.
|
|
103
|
+
// loader.ts only catches --help/-h as the *first* arg; here we handle the
|
|
104
|
+
// case where it appears later (e.g. `gsd update --help`, `gsd --foo --help`).
|
|
105
|
+
// Prefer subcommand-specific help when the first positional is a known
|
|
106
|
+
// subcommand, otherwise fall back to general help.
|
|
107
|
+
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
108
|
+
const helpSubcommand = cliFlags.messages[0];
|
|
109
|
+
const version = process.env.GSD_VERSION || '0.0.0';
|
|
110
|
+
if (!helpSubcommand || !printSubcommandHelp(helpSubcommand, version)) {
|
|
111
|
+
printHelp(version);
|
|
112
|
+
}
|
|
113
|
+
process.exit(0);
|
|
114
|
+
}
|
|
115
|
+
// RTK bootstrap — runs once per process, memoized via a module-level promise
|
|
116
|
+
// so concurrent callers await the same initialization.
|
|
117
|
+
let rtkBootstrapPromise;
|
|
118
|
+
async function doRtkBootstrap() {
|
|
145
119
|
// RTK is opt-in via experimental.rtk preference. Default: disabled.
|
|
146
120
|
// Honor GSD_RTK_DISABLED if already explicitly set in the environment
|
|
147
121
|
// (env var takes precedence over preferences for manual override).
|
|
@@ -149,16 +123,18 @@ async function ensureRtkBootstrap() {
|
|
|
149
123
|
const prefs = loadEffectiveGSDPreferences();
|
|
150
124
|
const rtkEnabled = prefs?.preferences.experimental?.rtk === true;
|
|
151
125
|
if (!rtkEnabled) {
|
|
152
|
-
process.env[GSD_RTK_DISABLED_ENV] =
|
|
126
|
+
process.env[GSD_RTK_DISABLED_ENV] = '1';
|
|
153
127
|
}
|
|
154
128
|
}
|
|
155
129
|
const rtkStatus = await bootstrapRtk();
|
|
156
|
-
ensureRtkBootstrap._done = true;
|
|
157
130
|
markStartup('bootstrapRtk');
|
|
158
131
|
if (!rtkStatus.available && rtkStatus.supported && rtkStatus.enabled && rtkStatus.reason) {
|
|
159
132
|
process.stderr.write(`[gsd] Warning: RTK unavailable — continuing without shell-command compression (${rtkStatus.reason}).\n`);
|
|
160
133
|
}
|
|
161
134
|
}
|
|
135
|
+
function ensureRtkBootstrap() {
|
|
136
|
+
return (rtkBootstrapPromise ??= doRtkBootstrap());
|
|
137
|
+
}
|
|
162
138
|
// `gsd update` — update to the latest version via npm
|
|
163
139
|
if (cliFlags.messages[0] === 'update') {
|
|
164
140
|
const { runUpdate } = await import('./update-cmd.js');
|
|
@@ -170,21 +146,7 @@ exitIfManagedResourcesAreNewer(agentDir);
|
|
|
170
146
|
// handles that prevent process.exit() from completing promptly.
|
|
171
147
|
const hasSubcommand = cliFlags.messages.length > 0;
|
|
172
148
|
if (!process.stdin.isTTY && !isPrintMode && !hasSubcommand && !cliFlags.listModels && !cliFlags.web) {
|
|
173
|
-
|
|
174
|
-
process.stderr.write('[gsd] Non-interactive alternatives:\n');
|
|
175
|
-
process.stderr.write('[gsd] gsd auto Auto-mode (pipeable, no TUI)\n');
|
|
176
|
-
process.stderr.write('[gsd] gsd --print "your message" Single-shot prompt\n');
|
|
177
|
-
process.stderr.write('[gsd] gsd --mode rpc JSON-RPC over stdin/stdout\n');
|
|
178
|
-
process.stderr.write('[gsd] gsd --mode mcp MCP server over stdin/stdout\n');
|
|
179
|
-
process.stderr.write('[gsd] gsd --mode text "message" Text output mode\n');
|
|
180
|
-
process.exit(1);
|
|
181
|
-
}
|
|
182
|
-
// `gsd <subcommand> --help` — show subcommand-specific help
|
|
183
|
-
const subcommand = cliFlags.messages[0];
|
|
184
|
-
if (subcommand && process.argv.includes('--help')) {
|
|
185
|
-
if (printSubcommandHelp(subcommand, process.env.GSD_VERSION || '0.0.0')) {
|
|
186
|
-
process.exit(0);
|
|
187
|
-
}
|
|
149
|
+
printNonTtyErrorAndExit(undefined, false);
|
|
188
150
|
}
|
|
189
151
|
const packageCommand = await runPackageCommand({
|
|
190
152
|
appName: 'gsd',
|
|
@@ -207,8 +169,7 @@ if (cliFlags.messages[0] === 'config') {
|
|
|
207
169
|
}
|
|
208
170
|
// `gsd web stop [path|all]` — stop web server before anything else
|
|
209
171
|
if (cliFlags.messages[0] === 'web' && cliFlags.messages[1] === 'stop') {
|
|
210
|
-
const
|
|
211
|
-
const webBranch = await runWebCliBranch(webFlags, {
|
|
172
|
+
const webBranch = await runWebCliBranch(cliFlags, {
|
|
212
173
|
stopWebMode,
|
|
213
174
|
stderr: process.stderr,
|
|
214
175
|
baseSessionsDir: sessionsDir,
|
|
@@ -221,8 +182,7 @@ if (cliFlags.messages[0] === 'web' && cliFlags.messages[1] === 'stop') {
|
|
|
221
182
|
// `gsd --web [path]` or `gsd web [start] [path]` — launch browser-only web mode
|
|
222
183
|
if (cliFlags.web || (cliFlags.messages[0] === 'web' && cliFlags.messages[1] !== 'stop')) {
|
|
223
184
|
await ensureRtkBootstrap();
|
|
224
|
-
const
|
|
225
|
-
const webBranch = await runWebCliBranch(webFlags, {
|
|
185
|
+
const webBranch = await runWebCliBranch(cliFlags, {
|
|
226
186
|
stderr: process.stderr,
|
|
227
187
|
baseSessionsDir: sessionsDir,
|
|
228
188
|
agentDir,
|
|
@@ -297,21 +257,23 @@ if (cliFlags.messages[0] === 'headless') {
|
|
|
297
257
|
await runHeadless(parseHeadlessArgs(process.argv));
|
|
298
258
|
process.exit(0);
|
|
299
259
|
}
|
|
260
|
+
/**
|
|
261
|
+
* Run a headless command by invoking the headless entrypoint with a synthetic
|
|
262
|
+
* argv. Shared by the `auto` shorthand (#2732) and the auto-piped-stdout
|
|
263
|
+
* redirect so they use the same bootstrap + dynamic-import dance.
|
|
264
|
+
*/
|
|
265
|
+
async function runHeadlessFromAuto(headlessArgs) {
|
|
266
|
+
await ensureRtkBootstrap();
|
|
267
|
+
const { runHeadless, parseHeadlessArgs } = await import('./headless.js');
|
|
268
|
+
const argv = [process.argv[0], process.argv[1], 'headless', ...headlessArgs];
|
|
269
|
+
await runHeadless(parseHeadlessArgs(argv));
|
|
270
|
+
process.exit(0);
|
|
271
|
+
}
|
|
300
272
|
// `gsd auto [args...]` — shorthand for `gsd headless auto [args...]` (#2732)
|
|
301
273
|
// Without this, `gsd auto` falls through to the interactive TUI which hangs
|
|
302
274
|
// when stdin/stdout are piped (non-TTY environments).
|
|
303
275
|
if (cliFlags.messages[0] === 'auto') {
|
|
304
|
-
await
|
|
305
|
-
const { runHeadless, parseHeadlessArgs } = await import('./headless.js');
|
|
306
|
-
// Rewrite argv so parseHeadlessArgs sees: [node, gsd, headless, auto, ...rest]
|
|
307
|
-
const rewrittenArgv = [
|
|
308
|
-
process.argv[0],
|
|
309
|
-
process.argv[1],
|
|
310
|
-
'headless',
|
|
311
|
-
...cliFlags.messages, // ['auto', ...extra args]
|
|
312
|
-
];
|
|
313
|
-
await runHeadless(parseHeadlessArgs(rewrittenArgv));
|
|
314
|
-
process.exit(0);
|
|
276
|
+
await runHeadlessFromAuto(cliFlags.messages);
|
|
315
277
|
}
|
|
316
278
|
// Pi's tool bootstrap can mis-detect already-installed fd/rg on some systems
|
|
317
279
|
// because spawnSync(..., ["--version"]) returns EPERM despite a zero exit code.
|
|
@@ -458,37 +420,8 @@ if (isPrintMode) {
|
|
|
458
420
|
// Before this, extension-provided models (e.g. claude-code/*) were not yet in the
|
|
459
421
|
// registry, causing the user's valid choice to be silently overwritten.
|
|
460
422
|
validateConfiguredModel(modelRegistry, settingsManager);
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
// overriding the persisted model of resumed conversations (#3534).
|
|
464
|
-
if (modelFallbackMessage) {
|
|
465
|
-
const validatedProvider = settingsManager.getDefaultProvider();
|
|
466
|
-
const validatedModelId = settingsManager.getDefaultModel();
|
|
467
|
-
if (validatedProvider && validatedModelId) {
|
|
468
|
-
const correctModel = modelRegistry.getAvailable()
|
|
469
|
-
.find((m) => m.provider === validatedProvider && m.id === validatedModelId);
|
|
470
|
-
if (correctModel) {
|
|
471
|
-
try {
|
|
472
|
-
await session.setModel(correctModel);
|
|
473
|
-
}
|
|
474
|
-
catch {
|
|
475
|
-
// Provider not ready — leave session on its current model
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
if (extensionsResult.errors.length > 0) {
|
|
481
|
-
for (const err of extensionsResult.errors) {
|
|
482
|
-
// Downgrade conflicts with built-in tools to warnings (#1347)
|
|
483
|
-
const isConflict = err.error.includes("supersedes") || err.error.includes("conflicts with");
|
|
484
|
-
const prefix = isConflict ? "Extension conflict" : "Extension load error";
|
|
485
|
-
process.stderr.write(`[gsd] ${prefix}: ${err.error}\n`);
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
// Validate configured model now that extension providers are registered.
|
|
489
|
-
// Must run after createAgentSession() which flushes pendingProviderRegistrations
|
|
490
|
-
// so extension models (e.g. pi-claude-cli) are visible in the registry.
|
|
491
|
-
validateConfiguredModel(modelRegistry, settingsManager);
|
|
423
|
+
await reapplyValidatedModelOnFallback(session, modelRegistry, settingsManager, modelFallbackMessage);
|
|
424
|
+
printExtensionErrors(extensionsResult.errors);
|
|
492
425
|
// Apply --model override if specified
|
|
493
426
|
if (cliFlags.model) {
|
|
494
427
|
const available = modelRegistry.getAvailable();
|
|
@@ -579,11 +512,8 @@ if (!cliFlags.worktree && !isPrintMode) {
|
|
|
579
512
|
// which handles non-interactive output gracefully.
|
|
580
513
|
// ---------------------------------------------------------------------------
|
|
581
514
|
if (cliFlags.messages[0] === 'auto' && !process.stdout.isTTY) {
|
|
582
|
-
await ensureRtkBootstrap();
|
|
583
|
-
const { runHeadless, parseHeadlessArgs } = await import('./headless.js');
|
|
584
515
|
process.stderr.write('[gsd] stdout is not a terminal — running auto-mode in headless mode.\n');
|
|
585
|
-
await
|
|
586
|
-
process.exit(0);
|
|
516
|
+
await runHeadlessFromAuto(cliFlags.messages.slice(1));
|
|
587
517
|
}
|
|
588
518
|
// ---------------------------------------------------------------------------
|
|
589
519
|
// Interactive mode — normal TTY session
|
|
@@ -627,36 +557,8 @@ markStartup('createAgentSession');
|
|
|
627
557
|
// Before this, extension-provided models (e.g. claude-code/*) were not yet in the
|
|
628
558
|
// registry, causing the user's valid choice to be silently overwritten.
|
|
629
559
|
validateConfiguredModel(modelRegistry, settingsManager);
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
// overriding the persisted model of resumed conversations (#3534).
|
|
633
|
-
if (interactiveFallbackMsg) {
|
|
634
|
-
const validatedProvider = settingsManager.getDefaultProvider();
|
|
635
|
-
const validatedModelId = settingsManager.getDefaultModel();
|
|
636
|
-
if (validatedProvider && validatedModelId) {
|
|
637
|
-
const correctModel = modelRegistry.getAvailable()
|
|
638
|
-
.find((m) => m.provider === validatedProvider && m.id === validatedModelId);
|
|
639
|
-
if (correctModel) {
|
|
640
|
-
try {
|
|
641
|
-
await session.setModel(correctModel);
|
|
642
|
-
}
|
|
643
|
-
catch {
|
|
644
|
-
// Provider not ready — leave session on its current model
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
if (extensionsResult.errors.length > 0) {
|
|
650
|
-
for (const err of extensionsResult.errors) {
|
|
651
|
-
const isConflict = err.error.includes("supersedes") || err.error.includes("conflicts with");
|
|
652
|
-
const prefix = isConflict ? "Extension conflict" : "Extension load error";
|
|
653
|
-
process.stderr.write(`[gsd] ${prefix}: ${err.error}\n`);
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
// Validate configured model now that extension providers are registered.
|
|
657
|
-
// Must run after createAgentSession() which flushes pendingProviderRegistrations
|
|
658
|
-
// so extension models (e.g. pi-claude-cli) are visible in the registry.
|
|
659
|
-
validateConfiguredModel(modelRegistry, settingsManager);
|
|
560
|
+
await reapplyValidatedModelOnFallback(session, modelRegistry, settingsManager, interactiveFallbackMsg);
|
|
561
|
+
printExtensionErrors(extensionsResult.errors);
|
|
660
562
|
// Restore scoped models from settings on startup.
|
|
661
563
|
// The upstream InteractiveMode reads enabledModels from settings when /scoped-models is opened,
|
|
662
564
|
// but doesn't apply them to the session at startup — so Ctrl+P cycles all models instead of
|
|
@@ -704,16 +606,7 @@ if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
|
704
606
|
: !process.stdin.isTTY
|
|
705
607
|
? 'stdin is'
|
|
706
608
|
: 'stdout is';
|
|
707
|
-
|
|
708
|
-
process.stderr.write('[gsd] Non-interactive alternatives:\n');
|
|
709
|
-
process.stderr.write('[gsd] gsd auto Auto-mode (pipeable, no TUI)\n');
|
|
710
|
-
process.stderr.write('[gsd] gsd --print "your message" Single-shot prompt\n');
|
|
711
|
-
process.stderr.write('[gsd] gsd --web [path] Browser-only web mode\n');
|
|
712
|
-
process.stderr.write('[gsd] gsd --mode rpc JSON-RPC over stdin/stdout\n');
|
|
713
|
-
process.stderr.write('[gsd] gsd --mode mcp MCP server over stdin/stdout\n');
|
|
714
|
-
process.stderr.write('[gsd] gsd --mode text "message" Text output mode\n');
|
|
715
|
-
process.stderr.write('[gsd] gsd headless Auto-mode without TUI\n');
|
|
716
|
-
process.exit(1);
|
|
609
|
+
printNonTtyErrorAndExit(missing, true);
|
|
717
610
|
}
|
|
718
611
|
// Welcome screen — shown on every fresh interactive session before TUI takes over.
|
|
719
612
|
// Skip when the first-run banner was already printed in loader.ts (prevents double banner).
|
package/dist/logo.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export declare const GSD_LOGO: readonly string[];
|
|
|
10
10
|
/**
|
|
11
11
|
* Render the logo block with a color function applied to each line.
|
|
12
12
|
*
|
|
13
|
-
* @param color — e.g. `(s) => `\x1b[36m${s}\x1b[0m`` or
|
|
13
|
+
* @param color — e.g. `(s) => `\x1b[36m${s}\x1b[0m`` or chalk.cyan
|
|
14
14
|
* @returns Ready-to-write string with leading/trailing newlines.
|
|
15
15
|
*/
|
|
16
16
|
export declare function renderLogo(color: (s: string) => string): string;
|
package/dist/logo.js
CHANGED
|
@@ -17,7 +17,7 @@ export const GSD_LOGO = [
|
|
|
17
17
|
/**
|
|
18
18
|
* Render the logo block with a color function applied to each line.
|
|
19
19
|
*
|
|
20
|
-
* @param color — e.g. `(s) => `\x1b[36m${s}\x1b[0m`` or
|
|
20
|
+
* @param color — e.g. `(s) => `\x1b[36m${s}\x1b[0m`` or chalk.cyan
|
|
21
21
|
* @returns Ready-to-write string with leading/trailing newlines.
|
|
22
22
|
*/
|
|
23
23
|
export function renderLogo(color) {
|
package/dist/onboarding.js
CHANGED
|
@@ -71,8 +71,8 @@ const OTHER_PROVIDERS = [
|
|
|
71
71
|
];
|
|
72
72
|
// ─── Dynamic imports ──────────────────────────────────────────────────────────
|
|
73
73
|
/**
|
|
74
|
-
* Dynamically import @clack/prompts
|
|
75
|
-
* Dynamic import with fallback so the module doesn't crash if
|
|
74
|
+
* Dynamically import @clack/prompts.
|
|
75
|
+
* Dynamic import with fallback so the module doesn't crash if it's missing.
|
|
76
76
|
*/
|
|
77
77
|
async function loadClack() {
|
|
78
78
|
try {
|
|
@@ -82,10 +82,23 @@ async function loadClack() {
|
|
|
82
82
|
throw new Error('[gsd] @clack/prompts not found — onboarding wizard requires this dependency');
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Build the PicoModule color surface from chalk. Chalk is already a
|
|
87
|
+
* dependency of the CLI; this adapter keeps the onboarding call sites stable
|
|
88
|
+
* while removing the redundant picocolors dep.
|
|
89
|
+
*/
|
|
85
90
|
async function loadPico() {
|
|
86
91
|
try {
|
|
87
|
-
const
|
|
88
|
-
return
|
|
92
|
+
const { default: chalk } = await import('chalk');
|
|
93
|
+
return {
|
|
94
|
+
cyan: (s) => chalk.cyan(s),
|
|
95
|
+
green: (s) => chalk.green(s),
|
|
96
|
+
yellow: (s) => chalk.yellow(s),
|
|
97
|
+
dim: (s) => chalk.dim(s),
|
|
98
|
+
bold: (s) => chalk.bold(s),
|
|
99
|
+
red: (s) => chalk.red(s),
|
|
100
|
+
reset: (s) => chalk.reset(s),
|
|
101
|
+
};
|
|
89
102
|
}
|
|
90
103
|
catch {
|
|
91
104
|
// Fallback: return identity functions
|
|
@@ -105,9 +118,29 @@ function openBrowser(url) {
|
|
|
105
118
|
execFile(cmd, [url], () => { });
|
|
106
119
|
}
|
|
107
120
|
}
|
|
108
|
-
/**
|
|
109
|
-
|
|
110
|
-
|
|
121
|
+
/** Sentinel returned by runStep when the user cancels — tells the caller
|
|
122
|
+
* to abort the entire wizard. */
|
|
123
|
+
const STEP_CANCELLED = Symbol('step-cancelled');
|
|
124
|
+
/**
|
|
125
|
+
* Run a single onboarding step with shared error handling:
|
|
126
|
+
* - user cancel (Ctrl+C) → p.cancel(cancelMessage), returns STEP_CANCELLED
|
|
127
|
+
* - other error → p.log.warn + optional info follow-up, returns null
|
|
128
|
+
* - success → the step's return value
|
|
129
|
+
*/
|
|
130
|
+
async function runStep(p, warnLabel, fn, opts = {}) {
|
|
131
|
+
try {
|
|
132
|
+
return await fn();
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
if (p.isCancel(err)) {
|
|
136
|
+
p.cancel(opts.cancelMessage ?? 'Setup cancelled.');
|
|
137
|
+
return STEP_CANCELLED;
|
|
138
|
+
}
|
|
139
|
+
p.log.warn(`${warnLabel}: ${err instanceof Error ? err.message : String(err)}`);
|
|
140
|
+
if (opts.errorInfo)
|
|
141
|
+
p.log.info(opts.errorInfo);
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
111
144
|
}
|
|
112
145
|
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
113
146
|
/**
|
|
@@ -160,55 +193,28 @@ export async function runOnboarding(authStorage) {
|
|
|
160
193
|
process.stderr.write(renderLogo(pc.cyan));
|
|
161
194
|
p.intro(pc.bold('Welcome to GSD — let\'s get you set up'));
|
|
162
195
|
// ── LLM Provider Selection ────────────────────────────────────────────────
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
p.cancel('Setup cancelled — you can run /login inside GSD later.');
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
p.log.warn(`LLM setup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
174
|
-
p.log.info('You can configure your LLM provider later with /login inside GSD.');
|
|
175
|
-
}
|
|
196
|
+
const llmResult = await runStep(p, 'LLM setup failed', () => runLlmStep(p, pc, authStorage), {
|
|
197
|
+
cancelMessage: 'Setup cancelled — you can run /login inside GSD later.',
|
|
198
|
+
errorInfo: 'You can configure your LLM provider later with /login inside GSD.',
|
|
199
|
+
});
|
|
200
|
+
if (llmResult === STEP_CANCELLED)
|
|
201
|
+
return;
|
|
202
|
+
const llmConfigured = llmResult ?? false;
|
|
176
203
|
// ── Web Search Provider ──────────────────────────────────────────────────
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
catch (err) {
|
|
182
|
-
if (isCancelError(p, err)) {
|
|
183
|
-
p.cancel('Setup cancelled.');
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
p.log.warn(`Web search setup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
187
|
-
}
|
|
204
|
+
const searchResult = await runStep(p, 'Web search setup failed', () => runWebSearchStep(p, pc, authStorage, llmConfigured));
|
|
205
|
+
if (searchResult === STEP_CANCELLED)
|
|
206
|
+
return;
|
|
207
|
+
const searchConfigured = searchResult;
|
|
188
208
|
// ── Remote Questions ─────────────────────────────────────────────────────
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
catch (err) {
|
|
194
|
-
if (isCancelError(p, err)) {
|
|
195
|
-
p.cancel('Setup cancelled.');
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
p.log.warn(`Remote questions setup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
199
|
-
}
|
|
209
|
+
const remoteResult = await runStep(p, 'Remote questions setup failed', () => runRemoteQuestionsStep(p, pc, authStorage));
|
|
210
|
+
if (remoteResult === STEP_CANCELLED)
|
|
211
|
+
return;
|
|
212
|
+
const remoteConfigured = remoteResult;
|
|
200
213
|
// ── Tool API Keys ─────────────────────────────────────────────────────────
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
catch (err) {
|
|
206
|
-
if (isCancelError(p, err)) {
|
|
207
|
-
p.cancel('Setup cancelled.');
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
p.log.warn(`Tool key setup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
211
|
-
}
|
|
214
|
+
const toolResult = await runStep(p, 'Tool key setup failed', () => runToolKeysStep(p, pc, authStorage));
|
|
215
|
+
if (toolResult === STEP_CANCELLED)
|
|
216
|
+
return;
|
|
217
|
+
const toolKeyCount = toolResult ?? 0;
|
|
212
218
|
// ── Summary ───────────────────────────────────────────────────────────────
|
|
213
219
|
const summaryLines = [];
|
|
214
220
|
if (llmConfigured) {
|