gsd-pi 2.53.0 → 2.54.0-dev.e1efc1a
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/headless-ui.d.ts +2 -2
- package/dist/headless-ui.js +18 -15
- package/dist/headless.d.ts +11 -0
- package/dist/headless.js +178 -38
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +19 -19
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/required-server-files.json +4 -4
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- 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/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- 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/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +19 -19
- package/dist/web/standalone/.next/server/chunks/2229.js +1 -1
- package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- 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/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-b950e4e384cc62b3.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/mcp-server/README.md +6 -6
- package/packages/mcp-server/package.json +14 -4
- package/packages/mcp-server/src/cli.ts +1 -1
- package/packages/mcp-server/src/index.ts +1 -1
- package/packages/mcp-server/src/mcp-server.test.ts +2 -2
- package/packages/mcp-server/src/session-manager.ts +2 -2
- package/packages/mcp-server/src/types.ts +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/rpc-client/README.md +125 -0
- package/packages/rpc-client/examples/basic-usage.ts +13 -0
- package/packages/rpc-client/package.json +17 -3
- package/packages/rpc-client/src/index.ts +10 -0
- package/packages/rpc-client/src/jsonl.ts +64 -0
- package/packages/rpc-client/src/rpc-client.test.ts +568 -0
- package/packages/rpc-client/src/rpc-client.ts +666 -0
- package/packages/rpc-client/src/rpc-types.ts +399 -0
- package/packages/rpc-client/tsconfig.examples.json +17 -0
- package/packages/rpc-client/tsconfig.json +24 -0
- package/pkg/package.json +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-fbecd1237e2d6d1f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- /package/dist/web/standalone/.next/static/{mWBOLPnUoeaTGiD-vhu5O → nISuDzAIpGYC-DVTvs4Po}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{mWBOLPnUoeaTGiD-vhu5O → nISuDzAIpGYC-DVTvs4Po}/_ssgManifest.js +0 -0
package/dist/headless-ui.d.ts
CHANGED
|
@@ -18,6 +18,6 @@ interface ExtensionUIRequest {
|
|
|
18
18
|
[key: string]: unknown;
|
|
19
19
|
}
|
|
20
20
|
export type { ExtensionUIRequest };
|
|
21
|
-
export declare function handleExtensionUIRequest(event: ExtensionUIRequest,
|
|
21
|
+
export declare function handleExtensionUIRequest(event: ExtensionUIRequest, client: RpcClient): void;
|
|
22
22
|
export declare function formatProgress(event: Record<string, unknown>, verbose: boolean): string | null;
|
|
23
|
-
export declare function startSupervisedStdinReader(
|
|
23
|
+
export declare function startSupervisedStdinReader(client: RpcClient, onResponse: (id: string) => void): () => void;
|
package/dist/headless-ui.js
CHANGED
|
@@ -5,13 +5,12 @@
|
|
|
5
5
|
* formats progress events for stderr output, and reads orchestrator
|
|
6
6
|
* commands from stdin in supervised mode.
|
|
7
7
|
*/
|
|
8
|
-
import { attachJsonlLineReader
|
|
8
|
+
import { attachJsonlLineReader } from '@gsd/pi-coding-agent';
|
|
9
9
|
// ---------------------------------------------------------------------------
|
|
10
10
|
// Extension UI Auto-Responder
|
|
11
11
|
// ---------------------------------------------------------------------------
|
|
12
|
-
export function handleExtensionUIRequest(event,
|
|
12
|
+
export function handleExtensionUIRequest(event, client) {
|
|
13
13
|
const { id, method } = event;
|
|
14
|
-
let response;
|
|
15
14
|
switch (method) {
|
|
16
15
|
case 'select': {
|
|
17
16
|
// Lock-guard prompts list "View status" first, but headless needs "Force start"
|
|
@@ -23,31 +22,30 @@ export function handleExtensionUIRequest(event, writeToStdin) {
|
|
|
23
22
|
if (forceOption)
|
|
24
23
|
selected = forceOption;
|
|
25
24
|
}
|
|
26
|
-
|
|
25
|
+
client.sendUIResponse(id, { value: selected });
|
|
27
26
|
break;
|
|
28
27
|
}
|
|
29
28
|
case 'confirm':
|
|
30
|
-
|
|
29
|
+
client.sendUIResponse(id, { confirmed: true });
|
|
31
30
|
break;
|
|
32
31
|
case 'input':
|
|
33
|
-
|
|
32
|
+
client.sendUIResponse(id, { value: '' });
|
|
34
33
|
break;
|
|
35
34
|
case 'editor':
|
|
36
|
-
|
|
35
|
+
client.sendUIResponse(id, { value: event.prefill ?? '' });
|
|
37
36
|
break;
|
|
38
37
|
case 'notify':
|
|
39
38
|
case 'setStatus':
|
|
40
39
|
case 'setWidget':
|
|
41
40
|
case 'setTitle':
|
|
42
41
|
case 'set_editor_text':
|
|
43
|
-
|
|
42
|
+
client.sendUIResponse(id, { value: '' });
|
|
44
43
|
break;
|
|
45
44
|
default:
|
|
46
45
|
process.stderr.write(`[headless] Warning: unknown extension_ui_request method "${method}", cancelling\n`);
|
|
47
|
-
|
|
46
|
+
client.sendUIResponse(id, { cancelled: true });
|
|
48
47
|
break;
|
|
49
48
|
}
|
|
50
|
-
writeToStdin(serializeJsonLine(response));
|
|
51
49
|
}
|
|
52
50
|
// ---------------------------------------------------------------------------
|
|
53
51
|
// Progress Formatter
|
|
@@ -78,7 +76,7 @@ export function formatProgress(event, verbose) {
|
|
|
78
76
|
// ---------------------------------------------------------------------------
|
|
79
77
|
// Supervised Stdin Reader
|
|
80
78
|
// ---------------------------------------------------------------------------
|
|
81
|
-
export function startSupervisedStdinReader(
|
|
79
|
+
export function startSupervisedStdinReader(client, onResponse) {
|
|
82
80
|
return attachJsonlLineReader(process.stdin, (line) => {
|
|
83
81
|
let msg;
|
|
84
82
|
try {
|
|
@@ -90,12 +88,17 @@ export function startSupervisedStdinReader(stdinWriter, client, onResponse) {
|
|
|
90
88
|
}
|
|
91
89
|
const type = String(msg.type ?? '');
|
|
92
90
|
switch (type) {
|
|
93
|
-
case 'extension_ui_response':
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
91
|
+
case 'extension_ui_response': {
|
|
92
|
+
const id = String(msg.id ?? '');
|
|
93
|
+
const value = msg.value !== undefined ? String(msg.value) : undefined;
|
|
94
|
+
const confirmed = typeof msg.confirmed === 'boolean' ? msg.confirmed : undefined;
|
|
95
|
+
const cancelled = typeof msg.cancelled === 'boolean' ? msg.cancelled : undefined;
|
|
96
|
+
client.sendUIResponse(id, { value, confirmed, cancelled });
|
|
97
|
+
if (id) {
|
|
98
|
+
onResponse(id);
|
|
97
99
|
}
|
|
98
100
|
break;
|
|
101
|
+
}
|
|
99
102
|
case 'prompt':
|
|
100
103
|
client.prompt(String(msg.message ?? ''));
|
|
101
104
|
break;
|
package/dist/headless.d.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* 10 — blocked (command reported a blocker)
|
|
12
12
|
* 11 — cancelled (SIGINT/SIGTERM received)
|
|
13
13
|
*/
|
|
14
|
+
import type { SessionInfo } from '@gsd/pi-coding-agent';
|
|
14
15
|
import type { OutputFormat } from './headless-types.js';
|
|
15
16
|
export interface HeadlessOptions {
|
|
16
17
|
timeout: number;
|
|
@@ -31,5 +32,15 @@ export interface HeadlessOptions {
|
|
|
31
32
|
resumeSession?: string;
|
|
32
33
|
bare?: boolean;
|
|
33
34
|
}
|
|
35
|
+
export interface ResumeSessionResult {
|
|
36
|
+
session?: SessionInfo;
|
|
37
|
+
error?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Resolve a session prefix to a single session.
|
|
41
|
+
* Exact id match is preferred over prefix match.
|
|
42
|
+
* Returns `{ session }` on unique match or `{ error }` on 0/ambiguous matches.
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveResumeSession(sessions: SessionInfo[], prefix: string): ResumeSessionResult;
|
|
34
45
|
export declare function parseHeadlessArgs(argv: string[]): HeadlessOptions;
|
|
35
46
|
export declare function runHeadless(options: HeadlessOptions): Promise<void>;
|
package/dist/headless.js
CHANGED
|
@@ -14,12 +14,35 @@
|
|
|
14
14
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
15
15
|
import { join } from 'node:path';
|
|
16
16
|
import { resolve } from 'node:path';
|
|
17
|
-
import { RpcClient } from '@gsd/pi-coding-agent';
|
|
17
|
+
import { RpcClient, SessionManager } from '@gsd/pi-coding-agent';
|
|
18
|
+
import { getProjectSessionsDir } from './project-sessions.js';
|
|
18
19
|
import { loadAndValidateAnswerFile, AnswerInjector } from './headless-answers.js';
|
|
19
|
-
import { isTerminalNotification, isBlockedNotification, isMilestoneReadyNotification, isQuickCommand, FIRE_AND_FORGET_METHODS, IDLE_TIMEOUT_MS, NEW_MILESTONE_IDLE_TIMEOUT_MS, EXIT_SUCCESS, EXIT_ERROR, EXIT_BLOCKED, EXIT_CANCELLED, } from './headless-events.js';
|
|
20
|
+
import { isTerminalNotification, isBlockedNotification, isMilestoneReadyNotification, isQuickCommand, FIRE_AND_FORGET_METHODS, IDLE_TIMEOUT_MS, NEW_MILESTONE_IDLE_TIMEOUT_MS, EXIT_SUCCESS, EXIT_ERROR, EXIT_BLOCKED, EXIT_CANCELLED, mapStatusToExitCode, } from './headless-events.js';
|
|
20
21
|
import { VALID_OUTPUT_FORMATS } from './headless-types.js';
|
|
21
22
|
import { handleExtensionUIRequest, formatProgress, startSupervisedStdinReader, } from './headless-ui.js';
|
|
22
23
|
import { loadContext, bootstrapGsdProject, } from './headless-context.js';
|
|
24
|
+
/**
|
|
25
|
+
* Resolve a session prefix to a single session.
|
|
26
|
+
* Exact id match is preferred over prefix match.
|
|
27
|
+
* Returns `{ session }` on unique match or `{ error }` on 0/ambiguous matches.
|
|
28
|
+
*/
|
|
29
|
+
export function resolveResumeSession(sessions, prefix) {
|
|
30
|
+
// Exact match takes priority
|
|
31
|
+
const exact = sessions.find(s => s.id === prefix);
|
|
32
|
+
if (exact) {
|
|
33
|
+
return { session: exact };
|
|
34
|
+
}
|
|
35
|
+
// Prefix match
|
|
36
|
+
const matches = sessions.filter(s => s.id.startsWith(prefix));
|
|
37
|
+
if (matches.length === 0) {
|
|
38
|
+
return { error: `No session matching '${prefix}' found` };
|
|
39
|
+
}
|
|
40
|
+
if (matches.length > 1) {
|
|
41
|
+
const list = matches.map(s => ` ${s.id}`).join('\n');
|
|
42
|
+
return { error: `Ambiguous session prefix '${prefix}' matches ${matches.length} sessions:\n${list}` };
|
|
43
|
+
}
|
|
44
|
+
return { session: matches[0] };
|
|
45
|
+
}
|
|
23
46
|
// ---------------------------------------------------------------------------
|
|
24
47
|
// CLI Argument Parser
|
|
25
48
|
// ---------------------------------------------------------------------------
|
|
@@ -256,6 +279,39 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
256
279
|
let exitCode = 0;
|
|
257
280
|
let milestoneReady = false; // tracks "Milestone X ready." for auto-chaining
|
|
258
281
|
const recentEvents = [];
|
|
282
|
+
// JSON batch mode: cost aggregation (cumulative-max pattern per K004)
|
|
283
|
+
let cumulativeCostUsd = 0;
|
|
284
|
+
let cumulativeInputTokens = 0;
|
|
285
|
+
let cumulativeOutputTokens = 0;
|
|
286
|
+
let cumulativeCacheReadTokens = 0;
|
|
287
|
+
let cumulativeCacheWriteTokens = 0;
|
|
288
|
+
let lastSessionId;
|
|
289
|
+
// Emit HeadlessJsonResult to stdout for --output-format json batch mode
|
|
290
|
+
function emitBatchJsonResult() {
|
|
291
|
+
if (options.outputFormat !== 'json')
|
|
292
|
+
return;
|
|
293
|
+
const duration = Date.now() - startTime;
|
|
294
|
+
const status = blocked ? 'blocked'
|
|
295
|
+
: exitCode === EXIT_CANCELLED ? 'cancelled'
|
|
296
|
+
: exitCode === EXIT_ERROR ? (totalEvents === 0 ? 'error' : 'timeout')
|
|
297
|
+
: 'success';
|
|
298
|
+
const result = {
|
|
299
|
+
status,
|
|
300
|
+
exitCode,
|
|
301
|
+
sessionId: lastSessionId,
|
|
302
|
+
duration,
|
|
303
|
+
cost: {
|
|
304
|
+
total: cumulativeCostUsd,
|
|
305
|
+
input_tokens: cumulativeInputTokens,
|
|
306
|
+
output_tokens: cumulativeOutputTokens,
|
|
307
|
+
cache_read_tokens: cumulativeCacheReadTokens,
|
|
308
|
+
cache_write_tokens: cumulativeCacheWriteTokens,
|
|
309
|
+
},
|
|
310
|
+
toolCalls: toolCallCount,
|
|
311
|
+
events: totalEvents,
|
|
312
|
+
};
|
|
313
|
+
process.stdout.write(JSON.stringify(result) + '\n');
|
|
314
|
+
}
|
|
259
315
|
function trackEvent(event) {
|
|
260
316
|
totalEvents++;
|
|
261
317
|
const type = String(event.type ?? 'unknown');
|
|
@@ -272,8 +328,11 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
272
328
|
if (recentEvents.length > 20)
|
|
273
329
|
recentEvents.shift();
|
|
274
330
|
}
|
|
275
|
-
//
|
|
276
|
-
let
|
|
331
|
+
// Client started flag — replaces old stdinWriter null-check
|
|
332
|
+
let clientStarted = false;
|
|
333
|
+
// Adapter for AnswerInjector — wraps client.sendUIResponse in a writeToStdin-compatible callback
|
|
334
|
+
// Initialized after client.start(); events won't fire before then
|
|
335
|
+
let injectorStdinAdapter = () => { };
|
|
277
336
|
// Supervised mode state
|
|
278
337
|
const pendingResponseTimers = new Map();
|
|
279
338
|
let supervisedFallback = false;
|
|
@@ -320,21 +379,54 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
320
379
|
resetIdleTimer();
|
|
321
380
|
// Answer injector: observe events for question metadata
|
|
322
381
|
injector?.observeEvent(eventObj);
|
|
323
|
-
// --json
|
|
324
|
-
|
|
382
|
+
// --json / --output-format stream-json: forward events as JSONL to stdout (filtered if --events)
|
|
383
|
+
// --output-format json (batch mode): suppress streaming, track cost for final result
|
|
384
|
+
if (options.json && options.outputFormat === 'stream-json') {
|
|
325
385
|
const eventType = String(eventObj.type ?? '');
|
|
326
386
|
if (!options.eventFilter || options.eventFilter.has(eventType)) {
|
|
327
387
|
process.stdout.write(JSON.stringify(eventObj) + '\n');
|
|
328
388
|
}
|
|
329
389
|
}
|
|
330
|
-
else {
|
|
390
|
+
else if (options.outputFormat === 'json') {
|
|
391
|
+
// Batch mode: silently track cost_update events (cumulative-max per K004)
|
|
392
|
+
const eventType = String(eventObj.type ?? '');
|
|
393
|
+
if (eventType === 'cost_update') {
|
|
394
|
+
const data = eventObj;
|
|
395
|
+
const cumCost = data.cumulativeCost;
|
|
396
|
+
if (cumCost) {
|
|
397
|
+
cumulativeCostUsd = Math.max(cumulativeCostUsd, Number(cumCost.costUsd ?? 0));
|
|
398
|
+
const tokens = data.tokens;
|
|
399
|
+
if (tokens) {
|
|
400
|
+
cumulativeInputTokens = Math.max(cumulativeInputTokens, tokens.input ?? 0);
|
|
401
|
+
cumulativeOutputTokens = Math.max(cumulativeOutputTokens, tokens.output ?? 0);
|
|
402
|
+
cumulativeCacheReadTokens = Math.max(cumulativeCacheReadTokens, tokens.cacheRead ?? 0);
|
|
403
|
+
cumulativeCacheWriteTokens = Math.max(cumulativeCacheWriteTokens, tokens.cacheWrite ?? 0);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
// Track sessionId from init_result
|
|
408
|
+
if (eventType === 'init_result') {
|
|
409
|
+
lastSessionId = String(eventObj.sessionId ?? '');
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
else if (!options.json) {
|
|
331
413
|
// Progress output to stderr
|
|
332
414
|
const line = formatProgress(eventObj, !!options.verbose);
|
|
333
415
|
if (line)
|
|
334
416
|
process.stderr.write(line + '\n');
|
|
335
417
|
}
|
|
418
|
+
// Handle execution_complete (v2 structured completion)
|
|
419
|
+
if (eventObj.type === 'execution_complete' && !completed) {
|
|
420
|
+
completed = true;
|
|
421
|
+
const status = String(eventObj.status ?? 'success');
|
|
422
|
+
exitCode = mapStatusToExitCode(status);
|
|
423
|
+
if (eventObj.status === 'blocked')
|
|
424
|
+
blocked = true;
|
|
425
|
+
resolveCompletion();
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
336
428
|
// Handle extension_ui_request
|
|
337
|
-
if (eventObj.type === 'extension_ui_request' &&
|
|
429
|
+
if (eventObj.type === 'extension_ui_request' && clientStarted) {
|
|
338
430
|
// Check for terminal notification before auto-responding
|
|
339
431
|
if (isBlockedNotification(eventObj)) {
|
|
340
432
|
blocked = true;
|
|
@@ -348,7 +440,7 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
348
440
|
}
|
|
349
441
|
// Answer injection: try to handle with pre-supplied answers before supervised/auto
|
|
350
442
|
if (injector && !FIRE_AND_FORGET_METHODS.has(String(eventObj.method ?? ''))) {
|
|
351
|
-
if (injector.tryHandle(eventObj,
|
|
443
|
+
if (injector.tryHandle(eventObj, injectorStdinAdapter)) {
|
|
352
444
|
if (completed) {
|
|
353
445
|
exitCode = blocked ? EXIT_BLOCKED : EXIT_SUCCESS;
|
|
354
446
|
resolveCompletion();
|
|
@@ -364,13 +456,13 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
364
456
|
const eventId = String(eventObj.id ?? '');
|
|
365
457
|
const timer = setTimeout(() => {
|
|
366
458
|
pendingResponseTimers.delete(eventId);
|
|
367
|
-
handleExtensionUIRequest(eventObj,
|
|
459
|
+
handleExtensionUIRequest(eventObj, client);
|
|
368
460
|
process.stdout.write(JSON.stringify({ type: 'supervised_timeout', id: eventId, method }) + '\n');
|
|
369
461
|
}, responseTimeout);
|
|
370
462
|
pendingResponseTimers.set(eventId, timer);
|
|
371
463
|
}
|
|
372
464
|
else {
|
|
373
|
-
handleExtensionUIRequest(eventObj,
|
|
465
|
+
handleExtensionUIRequest(eventObj, client);
|
|
374
466
|
}
|
|
375
467
|
// If we detected a terminal notification, resolve after responding
|
|
376
468
|
if (completed) {
|
|
@@ -393,13 +485,22 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
393
485
|
process.stderr.write('\n[headless] Interrupted, stopping child process...\n');
|
|
394
486
|
interrupted = true;
|
|
395
487
|
exitCode = EXIT_CANCELLED;
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
}
|
|
488
|
+
// Kill child process — don't await, just fire and exit.
|
|
489
|
+
// The main flow may be awaiting a promise that resolves when the child dies,
|
|
490
|
+
// which would race with this handler. Exit synchronously to ensure correct exit code.
|
|
491
|
+
try {
|
|
492
|
+
client.stop().catch(() => { });
|
|
493
|
+
}
|
|
494
|
+
catch { }
|
|
495
|
+
if (timeoutTimer)
|
|
496
|
+
clearTimeout(timeoutTimer);
|
|
497
|
+
if (idleTimer)
|
|
498
|
+
clearTimeout(idleTimer);
|
|
499
|
+
// Emit batch JSON result if in json mode before exiting
|
|
500
|
+
if (options.outputFormat === 'json') {
|
|
501
|
+
emitBatchJsonResult();
|
|
502
|
+
}
|
|
503
|
+
process.exit(exitCode);
|
|
403
504
|
};
|
|
404
505
|
process.on('SIGINT', signalHandler);
|
|
405
506
|
process.on('SIGTERM', signalHandler);
|
|
@@ -413,21 +514,55 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
413
514
|
clearTimeout(timeoutTimer);
|
|
414
515
|
process.exit(1);
|
|
415
516
|
}
|
|
416
|
-
//
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
if (timeoutTimer)
|
|
422
|
-
clearTimeout(timeoutTimer);
|
|
423
|
-
process.exit(1);
|
|
517
|
+
// v2 protocol negotiation — attempt init for structured completion events
|
|
518
|
+
let v2Enabled = false;
|
|
519
|
+
try {
|
|
520
|
+
await client.init({ clientId: 'gsd-headless' });
|
|
521
|
+
v2Enabled = true;
|
|
424
522
|
}
|
|
425
|
-
|
|
426
|
-
|
|
523
|
+
catch {
|
|
524
|
+
process.stderr.write('[headless] Warning: v2 init failed, falling back to v1 string-matching\n');
|
|
525
|
+
}
|
|
526
|
+
clientStarted = true;
|
|
527
|
+
// --resume: resolve session ID and switch to it
|
|
528
|
+
if (options.resumeSession) {
|
|
529
|
+
const projectSessionsDir = getProjectSessionsDir(process.cwd());
|
|
530
|
+
const sessions = await SessionManager.list(process.cwd(), projectSessionsDir);
|
|
531
|
+
const result = resolveResumeSession(sessions, options.resumeSession);
|
|
532
|
+
if (result.error) {
|
|
533
|
+
process.stderr.write(`[headless] Error: ${result.error}\n`);
|
|
534
|
+
await client.stop();
|
|
535
|
+
if (timeoutTimer)
|
|
536
|
+
clearTimeout(timeoutTimer);
|
|
537
|
+
process.exit(1);
|
|
538
|
+
}
|
|
539
|
+
const matched = result.session;
|
|
540
|
+
const switchResult = await client.switchSession(matched.path);
|
|
541
|
+
if (switchResult.cancelled) {
|
|
542
|
+
process.stderr.write(`[headless] Error: Session switch to '${matched.id}' was cancelled by an extension\n`);
|
|
543
|
+
await client.stop();
|
|
544
|
+
if (timeoutTimer)
|
|
545
|
+
clearTimeout(timeoutTimer);
|
|
546
|
+
process.exit(1);
|
|
547
|
+
}
|
|
548
|
+
process.stderr.write(`[headless] Resuming session ${matched.id}\n`);
|
|
549
|
+
}
|
|
550
|
+
// Build injector adapter — wraps client.sendUIResponse for AnswerInjector's writeToStdin interface
|
|
551
|
+
injectorStdinAdapter = (data) => {
|
|
552
|
+
try {
|
|
553
|
+
const parsed = JSON.parse(data.trim());
|
|
554
|
+
if (parsed.type === 'extension_ui_response' && parsed.id) {
|
|
555
|
+
const { id, value, values, confirmed, cancelled } = parsed;
|
|
556
|
+
client.sendUIResponse(id, { value, values, confirmed, cancelled });
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
catch {
|
|
560
|
+
process.stderr.write('[headless] Warning: injector adapter received unparseable data\n');
|
|
561
|
+
}
|
|
427
562
|
};
|
|
428
563
|
// Start supervised stdin reader for orchestrator commands
|
|
429
564
|
if (options.supervised) {
|
|
430
|
-
stopSupervisedReader = startSupervisedStdinReader(
|
|
565
|
+
stopSupervisedReader = startSupervisedStdinReader(client, (id) => {
|
|
431
566
|
const timer = pendingResponseTimers.get(id);
|
|
432
567
|
if (timer) {
|
|
433
568
|
clearTimeout(timer);
|
|
@@ -437,15 +572,18 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
437
572
|
// Ensure stdin is in flowing mode for JSONL reading
|
|
438
573
|
process.stdin.resume();
|
|
439
574
|
}
|
|
440
|
-
// Detect child process crash
|
|
441
|
-
internalProcess
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
575
|
+
// Detect child process crash (read-only exit event subscription — not stdin access)
|
|
576
|
+
const internalProcess = client.process;
|
|
577
|
+
if (internalProcess) {
|
|
578
|
+
internalProcess.on('exit', (code) => {
|
|
579
|
+
if (!completed) {
|
|
580
|
+
const msg = `[headless] Child process exited unexpectedly with code ${code ?? 'null'}\n`;
|
|
581
|
+
process.stderr.write(msg);
|
|
582
|
+
exitCode = EXIT_ERROR;
|
|
583
|
+
resolveCompletion();
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
}
|
|
449
587
|
if (!options.json) {
|
|
450
588
|
process.stderr.write(`[headless] Running /gsd ${options.command}${options.commandArgs.length > 0 ? ' ' + options.commandArgs.join(' ') : ''}...\n`);
|
|
451
589
|
}
|
|
@@ -530,5 +668,7 @@ async function runHeadlessOnce(options, restartCount) {
|
|
|
530
668
|
}
|
|
531
669
|
}
|
|
532
670
|
}
|
|
671
|
+
// Emit structured JSON result in batch mode
|
|
672
|
+
emitBatchJsonResult();
|
|
533
673
|
return { exitCode, interrupted };
|
|
534
674
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
nISuDzAIpGYC-DVTvs4Po
|
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
{
|
|
2
|
-
"/_not-found/page": "/_not-found",
|
|
3
2
|
"/_global-error/page": "/_global-error",
|
|
3
|
+
"/_not-found/page": "/_not-found",
|
|
4
|
+
"/api/bridge-terminal/input/route": "/api/bridge-terminal/input",
|
|
4
5
|
"/api/bridge-terminal/resize/route": "/api/bridge-terminal/resize",
|
|
5
6
|
"/api/boot/route": "/api/boot",
|
|
6
|
-
"/api/
|
|
7
|
-
"/api/bridge-terminal/stream/route": "/api/bridge-terminal/stream",
|
|
7
|
+
"/api/browse-directories/route": "/api/browse-directories",
|
|
8
8
|
"/api/dev-mode/route": "/api/dev-mode",
|
|
9
|
+
"/api/bridge-terminal/stream/route": "/api/bridge-terminal/stream",
|
|
10
|
+
"/api/captures/route": "/api/captures",
|
|
11
|
+
"/api/export-data/route": "/api/export-data",
|
|
9
12
|
"/api/cleanup/route": "/api/cleanup",
|
|
10
13
|
"/api/doctor/route": "/api/doctor",
|
|
11
|
-
"/api/
|
|
12
|
-
"/api/export-data/route": "/api/export-data",
|
|
14
|
+
"/api/history/route": "/api/history",
|
|
13
15
|
"/api/forensics/route": "/api/forensics",
|
|
14
|
-
"/api/captures/route": "/api/captures",
|
|
15
16
|
"/api/git/route": "/api/git",
|
|
16
|
-
"/api/history/route": "/api/history",
|
|
17
|
-
"/api/hooks/route": "/api/hooks",
|
|
18
17
|
"/api/knowledge/route": "/api/knowledge",
|
|
19
|
-
"/api/
|
|
18
|
+
"/api/hooks/route": "/api/hooks",
|
|
20
19
|
"/api/experimental/route": "/api/experimental",
|
|
21
|
-
"/api/
|
|
20
|
+
"/api/inspect/route": "/api/inspect",
|
|
22
21
|
"/api/preferences/route": "/api/preferences",
|
|
23
|
-
"/api/
|
|
22
|
+
"/api/live-state/route": "/api/live-state",
|
|
24
23
|
"/api/onboarding/route": "/api/onboarding",
|
|
24
|
+
"/api/recovery/route": "/api/recovery",
|
|
25
25
|
"/api/projects/route": "/api/projects",
|
|
26
26
|
"/api/session/browser/route": "/api/session/browser",
|
|
27
27
|
"/api/session/command/route": "/api/session/command",
|
|
28
28
|
"/api/session/events/route": "/api/session/events",
|
|
29
|
-
"/api/session/manage/route": "/api/session/manage",
|
|
30
29
|
"/api/settings-data/route": "/api/settings-data",
|
|
31
|
-
"/api/shutdown/route": "/api/shutdown",
|
|
32
|
-
"/api/skill-health/route": "/api/skill-health",
|
|
33
30
|
"/api/steer/route": "/api/steer",
|
|
31
|
+
"/api/session/manage/route": "/api/session/manage",
|
|
32
|
+
"/api/skill-health/route": "/api/skill-health",
|
|
33
|
+
"/api/shutdown/route": "/api/shutdown",
|
|
34
34
|
"/api/terminal/input/route": "/api/terminal/input",
|
|
35
35
|
"/api/terminal/resize/route": "/api/terminal/resize",
|
|
36
36
|
"/api/switch-root/route": "/api/switch-root",
|
|
37
|
-
"/api/terminal/sessions/route": "/api/terminal/sessions",
|
|
38
37
|
"/api/terminal/stream/route": "/api/terminal/stream",
|
|
39
|
-
"/api/
|
|
40
|
-
"/api/
|
|
38
|
+
"/api/terminal/sessions/route": "/api/terminal/sessions",
|
|
39
|
+
"/api/remote-questions/route": "/api/remote-questions",
|
|
41
40
|
"/api/terminal/upload/route": "/api/terminal/upload",
|
|
42
|
-
"/api/
|
|
41
|
+
"/api/undo/route": "/api/undo",
|
|
43
42
|
"/api/update/route": "/api/update",
|
|
44
|
-
"/api/
|
|
43
|
+
"/api/visualizer/route": "/api/visualizer",
|
|
44
|
+
"/api/files/route": "/api/files",
|
|
45
45
|
"/page": "/"
|
|
46
46
|
}
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
],
|
|
5
5
|
"devFiles": [],
|
|
6
6
|
"lowPriorityFiles": [
|
|
7
|
-
"static/
|
|
8
|
-
"static/
|
|
7
|
+
"static/nISuDzAIpGYC-DVTvs4Po/_buildManifest.js",
|
|
8
|
+
"static/nISuDzAIpGYC-DVTvs4Po/_ssgManifest.js"
|
|
9
9
|
],
|
|
10
10
|
"rootMainFiles": [
|
|
11
11
|
"static/chunks/webpack-bca0e732db0dcec3.js",
|
|
12
12
|
"static/chunks/4bd1b696-e5d7c65570c947b7.js",
|
|
13
13
|
"static/chunks/3794-337d1ca25ad99a89.js",
|
|
14
|
-
"static/chunks/main-app-
|
|
14
|
+
"static/chunks/main-app-fdab67f7802d7832.js"
|
|
15
15
|
],
|
|
16
16
|
"rootMainFilesTree": {},
|
|
17
17
|
"pages": {
|
|
@@ -78,8 +78,8 @@
|
|
|
78
78
|
"dynamicRoutes": {},
|
|
79
79
|
"notFoundRoutes": [],
|
|
80
80
|
"preview": {
|
|
81
|
-
"previewModeId": "
|
|
82
|
-
"previewModeSigningKey": "
|
|
83
|
-
"previewModeEncryptionKey": "
|
|
81
|
+
"previewModeId": "421c8ae4252416128c6285506cccf021",
|
|
82
|
+
"previewModeSigningKey": "55cb8a1dd17e322add989f48f333adbf1322c54b5b786db308294dc5891a464c",
|
|
83
|
+
"previewModeEncryptionKey": "48301e074f6610a318f4af6a7fb298f6ace2a45887285828301e9bba0ace5432"
|
|
84
84
|
}
|
|
85
85
|
}
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
"transform": "lodash/{{member}}"
|
|
101
101
|
}
|
|
102
102
|
},
|
|
103
|
-
"outputFileTracingRoot": "/
|
|
103
|
+
"outputFileTracingRoot": "/__w/gsd-2/gsd-2",
|
|
104
104
|
"cacheComponents": false,
|
|
105
105
|
"cacheLife": {
|
|
106
106
|
"default": {
|
|
@@ -157,7 +157,7 @@
|
|
|
157
157
|
"proxyPrefetch": "flexible",
|
|
158
158
|
"optimisticClientCache": true,
|
|
159
159
|
"manualClientBasePath": false,
|
|
160
|
-
"cpus":
|
|
160
|
+
"cpus": 5,
|
|
161
161
|
"memoryBasedWorkersCount": false,
|
|
162
162
|
"imgOptConcurrency": null,
|
|
163
163
|
"imgOptTimeoutInSeconds": 7,
|
|
@@ -297,11 +297,11 @@
|
|
|
297
297
|
"node-pty"
|
|
298
298
|
],
|
|
299
299
|
"turbopack": {
|
|
300
|
-
"root": "/
|
|
300
|
+
"root": "/__w/gsd-2/gsd-2"
|
|
301
301
|
},
|
|
302
302
|
"distDirRoot": ".next"
|
|
303
303
|
},
|
|
304
|
-
"appDir": "/
|
|
304
|
+
"appDir": "/__w/gsd-2/gsd-2/web",
|
|
305
305
|
"relativeAppDir": "web",
|
|
306
306
|
"files": [
|
|
307
307
|
".next/routes-manifest.json",
|