gsd-pi 2.22.0 → 2.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -1
- package/dist/cli.js +74 -7
- package/dist/headless.d.ts +25 -0
- package/dist/headless.js +454 -0
- package/dist/help-text.js +47 -0
- package/dist/mcp-server.d.ts +20 -3
- package/dist/mcp-server.js +21 -1
- package/dist/models-resolver.d.ts +32 -0
- package/dist/models-resolver.js +50 -0
- package/dist/resource-loader.js +64 -9
- package/dist/resources/extensions/bg-shell/output-formatter.ts +36 -16
- package/dist/resources/extensions/bg-shell/process-manager.ts +6 -4
- package/dist/resources/extensions/bg-shell/types.ts +33 -1
- package/dist/resources/extensions/browser-tools/capture.ts +18 -16
- package/dist/resources/extensions/browser-tools/index.ts +20 -0
- package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +25 -0
- package/dist/resources/extensions/browser-tools/tools/action-cache.ts +216 -0
- package/dist/resources/extensions/browser-tools/tools/codegen.ts +274 -0
- package/dist/resources/extensions/browser-tools/tools/device.ts +183 -0
- package/dist/resources/extensions/browser-tools/tools/extract.ts +229 -0
- package/dist/resources/extensions/browser-tools/tools/injection-detect.ts +221 -0
- package/dist/resources/extensions/browser-tools/tools/network-mock.ts +244 -0
- package/dist/resources/extensions/browser-tools/tools/pdf.ts +92 -0
- package/dist/resources/extensions/browser-tools/tools/state-persistence.ts +202 -0
- package/dist/resources/extensions/browser-tools/tools/visual-diff.ts +209 -0
- package/dist/resources/extensions/browser-tools/tools/zoom.ts +104 -0
- package/dist/resources/extensions/gsd/auto-dashboard.ts +2 -0
- package/dist/resources/extensions/gsd/auto-dispatch.ts +51 -2
- package/dist/resources/extensions/gsd/auto-prompts.ts +73 -0
- package/dist/resources/extensions/gsd/auto-recovery.ts +51 -2
- package/dist/resources/extensions/gsd/auto-worktree.ts +15 -3
- package/dist/resources/extensions/gsd/auto.ts +560 -52
- package/dist/resources/extensions/gsd/captures.ts +49 -0
- package/dist/resources/extensions/gsd/commands.ts +194 -11
- package/dist/resources/extensions/gsd/complexity.ts +1 -0
- package/dist/resources/extensions/gsd/dashboard-overlay.ts +54 -2
- package/dist/resources/extensions/gsd/diff-context.ts +73 -80
- package/dist/resources/extensions/gsd/doctor.ts +76 -12
- package/dist/resources/extensions/gsd/exit-command.ts +2 -2
- package/dist/resources/extensions/gsd/forensics.ts +95 -52
- package/dist/resources/extensions/gsd/gitignore.ts +1 -0
- package/dist/resources/extensions/gsd/guided-flow.ts +85 -5
- package/dist/resources/extensions/gsd/index.ts +34 -1
- package/dist/resources/extensions/gsd/mcp-server.ts +33 -12
- package/dist/resources/extensions/gsd/parallel-eligibility.ts +233 -0
- package/dist/resources/extensions/gsd/parallel-merge.ts +156 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.ts +496 -0
- package/dist/resources/extensions/gsd/post-unit-hooks.ts +2 -1
- package/dist/resources/extensions/gsd/preferences.ts +65 -1
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +86 -0
- package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +104 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -0
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/system.md +2 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +70 -0
- package/dist/resources/extensions/gsd/provider-error-pause.ts +29 -2
- package/dist/resources/extensions/gsd/roadmap-slices.ts +41 -1
- package/dist/resources/extensions/gsd/session-forensics.ts +36 -2
- package/dist/resources/extensions/gsd/session-status-io.ts +197 -0
- package/dist/resources/extensions/gsd/state.ts +72 -30
- package/dist/resources/extensions/gsd/templates/milestone-validation.md +62 -0
- package/dist/resources/extensions/gsd/tests/agent-end-provider-error.test.ts +81 -0
- package/dist/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +20 -3
- package/dist/resources/extensions/gsd/tests/auto-lock-creation.test.ts +186 -0
- package/dist/resources/extensions/gsd/tests/auto-preflight.test.ts +1 -0
- package/dist/resources/extensions/gsd/tests/auto-recovery.test.ts +264 -0
- package/dist/resources/extensions/gsd/tests/auto-skip-loop.test.ts +123 -0
- package/dist/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +34 -0
- package/dist/resources/extensions/gsd/tests/complete-milestone.test.ts +8 -1
- package/dist/resources/extensions/gsd/tests/derive-state-db.test.ts +9 -15
- package/dist/resources/extensions/gsd/tests/derive-state-deps.test.ts +9 -0
- package/dist/resources/extensions/gsd/tests/derive-state-draft.test.ts +8 -0
- package/dist/resources/extensions/gsd/tests/derive-state.test.ts +14 -0
- package/dist/resources/extensions/gsd/tests/doctor.test.ts +58 -0
- package/dist/resources/extensions/gsd/tests/in-flight-tool-tracking.test.ts +17 -6
- package/dist/resources/extensions/gsd/tests/integration/headless-command.ts +534 -0
- package/dist/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +8 -0
- package/dist/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +5 -5
- package/dist/resources/extensions/gsd/tests/parallel-orchestration.test.ts +656 -0
- package/dist/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +354 -0
- package/dist/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +1 -0
- package/dist/resources/extensions/gsd/tests/roadmap-slices.test.ts +43 -1
- package/dist/resources/extensions/gsd/tests/triage-dispatch.test.ts +120 -0
- package/dist/resources/extensions/gsd/tests/triage-resolution.test.ts +203 -2
- package/dist/resources/extensions/gsd/tests/validate-milestone.test.ts +316 -0
- package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +8 -3
- package/dist/resources/extensions/gsd/tests/worker-registry.test.ts +148 -0
- package/dist/resources/extensions/gsd/triage-resolution.ts +83 -0
- package/dist/resources/extensions/gsd/types.ts +15 -1
- package/dist/resources/extensions/gsd/visualizer-overlay.ts +8 -1
- package/dist/resources/extensions/gsd/workspace-index.ts +34 -6
- package/dist/resources/extensions/subagent/index.ts +5 -0
- package/dist/resources/extensions/subagent/worker-registry.ts +99 -0
- package/dist/update-check.d.ts +9 -0
- package/dist/update-check.js +97 -0
- package/package.json +6 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +16 -7
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.js +12 -4
- package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-vertex.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-vertex.js +21 -9
- package/packages/pi-ai/dist/providers/google-vertex.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +12 -4
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js +12 -4
- package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/packages/pi-ai/src/providers/anthropic.ts +21 -8
- package/packages/pi-ai/src/providers/azure-openai-responses.ts +16 -4
- package/packages/pi-ai/src/providers/google-vertex.ts +32 -17
- package/packages/pi-ai/src/providers/openai-completions.ts +16 -4
- package/packages/pi-ai/src/providers/openai-responses.ts +16 -4
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash-background.test.d.ts +10 -0
- package/packages/pi-coding-agent/dist/core/tools/bash-background.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/bash-background.test.js +79 -0
- package/packages/pi-coding-agent/dist/core/tools/bash-background.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +18 -0
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js +77 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.js +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
- package/packages/pi-coding-agent/src/core/settings-manager.ts +2 -2
- package/packages/pi-coding-agent/src/core/tools/bash-background.test.ts +91 -0
- package/packages/pi-coding-agent/src/core/tools/bash.ts +83 -1
- package/packages/pi-coding-agent/src/core/tools/index.ts +1 -0
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/scripts/postinstall.js +7 -109
- package/src/resources/extensions/bg-shell/output-formatter.ts +36 -16
- package/src/resources/extensions/bg-shell/process-manager.ts +6 -4
- package/src/resources/extensions/bg-shell/types.ts +33 -1
- package/src/resources/extensions/browser-tools/capture.ts +18 -16
- package/src/resources/extensions/browser-tools/index.ts +20 -0
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +25 -0
- package/src/resources/extensions/browser-tools/tools/action-cache.ts +216 -0
- package/src/resources/extensions/browser-tools/tools/codegen.ts +274 -0
- package/src/resources/extensions/browser-tools/tools/device.ts +183 -0
- package/src/resources/extensions/browser-tools/tools/extract.ts +229 -0
- package/src/resources/extensions/browser-tools/tools/injection-detect.ts +221 -0
- package/src/resources/extensions/browser-tools/tools/network-mock.ts +244 -0
- package/src/resources/extensions/browser-tools/tools/pdf.ts +92 -0
- package/src/resources/extensions/browser-tools/tools/state-persistence.ts +202 -0
- package/src/resources/extensions/browser-tools/tools/visual-diff.ts +209 -0
- package/src/resources/extensions/browser-tools/tools/zoom.ts +104 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +2 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +51 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +73 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +51 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +15 -3
- package/src/resources/extensions/gsd/auto.ts +560 -52
- package/src/resources/extensions/gsd/captures.ts +49 -0
- package/src/resources/extensions/gsd/commands.ts +194 -11
- package/src/resources/extensions/gsd/complexity.ts +1 -0
- package/src/resources/extensions/gsd/dashboard-overlay.ts +54 -2
- package/src/resources/extensions/gsd/diff-context.ts +73 -80
- package/src/resources/extensions/gsd/doctor.ts +76 -12
- package/src/resources/extensions/gsd/exit-command.ts +2 -2
- package/src/resources/extensions/gsd/forensics.ts +95 -52
- package/src/resources/extensions/gsd/gitignore.ts +1 -0
- package/src/resources/extensions/gsd/guided-flow.ts +85 -5
- package/src/resources/extensions/gsd/index.ts +34 -1
- package/src/resources/extensions/gsd/mcp-server.ts +33 -12
- package/src/resources/extensions/gsd/parallel-eligibility.ts +233 -0
- package/src/resources/extensions/gsd/parallel-merge.ts +156 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +496 -0
- package/src/resources/extensions/gsd/post-unit-hooks.ts +2 -1
- package/src/resources/extensions/gsd/preferences.ts +65 -1
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +86 -0
- package/src/resources/extensions/gsd/prompts/execute-task.md +5 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +104 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -0
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/system.md +2 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +70 -0
- package/src/resources/extensions/gsd/provider-error-pause.ts +29 -2
- package/src/resources/extensions/gsd/roadmap-slices.ts +41 -1
- package/src/resources/extensions/gsd/session-forensics.ts +36 -2
- package/src/resources/extensions/gsd/session-status-io.ts +197 -0
- package/src/resources/extensions/gsd/state.ts +72 -30
- package/src/resources/extensions/gsd/templates/milestone-validation.md +62 -0
- package/src/resources/extensions/gsd/tests/agent-end-provider-error.test.ts +81 -0
- package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +20 -3
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +264 -0
- package/src/resources/extensions/gsd/tests/auto-skip-loop.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +9 -15
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/derive-state-draft.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/doctor.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/in-flight-tool-tracking.test.ts +17 -6
- package/src/resources/extensions/gsd/tests/integration/headless-command.ts +534 -0
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +656 -0
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +354 -0
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +43 -1
- package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +203 -2
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +316 -0
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +8 -3
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +148 -0
- package/src/resources/extensions/gsd/triage-resolution.ts +83 -0
- package/src/resources/extensions/gsd/types.ts +15 -1
- package/src/resources/extensions/gsd/visualizer-overlay.ts +8 -1
- package/src/resources/extensions/gsd/workspace-index.ts +34 -6
- package/src/resources/extensions/subagent/index.ts +5 -0
- package/src/resources/extensions/subagent/worker-registry.ts +99 -0
package/dist/help-text.js
CHANGED
|
@@ -17,6 +17,51 @@ const SUBCOMMAND_HELP = {
|
|
|
17
17
|
'',
|
|
18
18
|
'Equivalent to: npm install -g gsd-pi@latest',
|
|
19
19
|
].join('\n'),
|
|
20
|
+
sessions: [
|
|
21
|
+
'Usage: gsd sessions',
|
|
22
|
+
'',
|
|
23
|
+
'List all saved sessions for the current directory and interactively',
|
|
24
|
+
'pick one to resume. Shows date, message count, and a preview of the',
|
|
25
|
+
'first message for each session.',
|
|
26
|
+
'',
|
|
27
|
+
'Sessions are stored per-directory, so you only see sessions that were',
|
|
28
|
+
'started from the current working directory.',
|
|
29
|
+
'',
|
|
30
|
+
'Compare with --continue (-c) which always resumes the most recent session.',
|
|
31
|
+
].join('\n'),
|
|
32
|
+
headless: [
|
|
33
|
+
'Usage: gsd headless [flags] [command] [args...]',
|
|
34
|
+
'',
|
|
35
|
+
'Run /gsd commands without the TUI. Default command: auto',
|
|
36
|
+
'',
|
|
37
|
+
'Flags:',
|
|
38
|
+
' --timeout N Overall timeout in ms (default: 300000)',
|
|
39
|
+
' --json JSONL event stream to stdout',
|
|
40
|
+
' --model ID Override model',
|
|
41
|
+
'',
|
|
42
|
+
'Commands:',
|
|
43
|
+
' auto Run all queued units continuously (default)',
|
|
44
|
+
' next Run one unit',
|
|
45
|
+
' status Show progress dashboard',
|
|
46
|
+
' new-milestone Create a milestone from a specification document',
|
|
47
|
+
'',
|
|
48
|
+
'new-milestone flags:',
|
|
49
|
+
' --context <path> Path to spec/PRD file (use \'-\' for stdin)',
|
|
50
|
+
' --context-text <txt> Inline specification text',
|
|
51
|
+
' --auto Start auto-mode after milestone creation',
|
|
52
|
+
' --verbose Show tool calls in progress output',
|
|
53
|
+
'',
|
|
54
|
+
'Examples:',
|
|
55
|
+
' gsd headless Run /gsd auto',
|
|
56
|
+
' gsd headless next Run one unit',
|
|
57
|
+
' gsd headless --json status Machine-readable status',
|
|
58
|
+
' gsd headless --timeout 60000 With 1-minute timeout',
|
|
59
|
+
' gsd headless new-milestone --context spec.md Create milestone from file',
|
|
60
|
+
' cat spec.md | gsd headless new-milestone --context - From stdin',
|
|
61
|
+
' gsd headless new-milestone --context spec.md --auto Create + auto-execute',
|
|
62
|
+
'',
|
|
63
|
+
'Exit codes: 0 = complete, 1 = error/timeout, 2 = blocked',
|
|
64
|
+
].join('\n'),
|
|
20
65
|
};
|
|
21
66
|
export function printHelp(version) {
|
|
22
67
|
process.stdout.write(`GSD v${version} — Get Shit Done\n\n`);
|
|
@@ -35,6 +80,8 @@ export function printHelp(version) {
|
|
|
35
80
|
process.stdout.write('\nSubcommands:\n');
|
|
36
81
|
process.stdout.write(' config Re-run the setup wizard\n');
|
|
37
82
|
process.stdout.write(' update Update GSD to the latest version\n');
|
|
83
|
+
process.stdout.write(' sessions List and resume a past session\n');
|
|
84
|
+
process.stdout.write(' headless [cmd] [args] Run /gsd commands without TUI (default: auto)\n');
|
|
38
85
|
process.stdout.write('\nRun gsd <subcommand> --help for subcommand-specific help.\n');
|
|
39
86
|
}
|
|
40
87
|
export function printSubcommandHelp(subcommand, version) {
|
package/dist/mcp-server.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Minimal tool interface matching GSD's AgentTool shape.
|
|
3
|
+
* Avoids a direct dependency on @gsd/pi-agent-core from this compiled module.
|
|
4
|
+
*/
|
|
5
|
+
export interface McpToolDef {
|
|
2
6
|
name: string;
|
|
3
7
|
description: string;
|
|
4
8
|
parameters: Record<string, unknown>;
|
|
@@ -11,8 +15,21 @@ interface McpTool {
|
|
|
11
15
|
}>;
|
|
12
16
|
}>;
|
|
13
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Starts a native MCP (Model Context Protocol) server over stdin/stdout.
|
|
20
|
+
*
|
|
21
|
+
* This enables GSD's tools (read, write, edit, bash, grep, glob, ls, etc.)
|
|
22
|
+
* to be used by external AI clients such as Claude Desktop, VS Code Copilot,
|
|
23
|
+
* and any MCP-compatible host.
|
|
24
|
+
*
|
|
25
|
+
* The server registers all tools from the agent session's tool registry and
|
|
26
|
+
* maps MCP tools/list and tools/call requests to GSD tool definitions and
|
|
27
|
+
* execution, respectively.
|
|
28
|
+
*
|
|
29
|
+
* All MCP SDK imports are dynamic to avoid subpath export resolution issues
|
|
30
|
+
* with TypeScript's NodeNext module resolution.
|
|
31
|
+
*/
|
|
14
32
|
export declare function startMcpServer(options: {
|
|
15
|
-
tools:
|
|
33
|
+
tools: McpToolDef[];
|
|
16
34
|
version?: string;
|
|
17
35
|
}): Promise<void>;
|
|
18
|
-
export {};
|
package/dist/mcp-server.js
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
// at runtime but TypeScript cannot statically type-check. We construct the
|
|
3
3
|
// specifiers dynamically so tsc treats them as `any`.
|
|
4
4
|
const MCP_PKG = '@modelcontextprotocol/sdk';
|
|
5
|
+
/**
|
|
6
|
+
* Starts a native MCP (Model Context Protocol) server over stdin/stdout.
|
|
7
|
+
*
|
|
8
|
+
* This enables GSD's tools (read, write, edit, bash, grep, glob, ls, etc.)
|
|
9
|
+
* to be used by external AI clients such as Claude Desktop, VS Code Copilot,
|
|
10
|
+
* and any MCP-compatible host.
|
|
11
|
+
*
|
|
12
|
+
* The server registers all tools from the agent session's tool registry and
|
|
13
|
+
* maps MCP tools/list and tools/call requests to GSD tool definitions and
|
|
14
|
+
* execution, respectively.
|
|
15
|
+
*
|
|
16
|
+
* All MCP SDK imports are dynamic to avoid subpath export resolution issues
|
|
17
|
+
* with TypeScript's NodeNext module resolution.
|
|
18
|
+
*/
|
|
5
19
|
export async function startMcpServer(options) {
|
|
6
20
|
const { tools, version = '0.0.0' } = options;
|
|
7
21
|
const serverMod = await import(`${MCP_PKG}/server`);
|
|
@@ -10,11 +24,13 @@ export async function startMcpServer(options) {
|
|
|
10
24
|
const Server = serverMod.Server;
|
|
11
25
|
const StdioServerTransport = stdioMod.StdioServerTransport;
|
|
12
26
|
const { ListToolsRequestSchema, CallToolRequestSchema } = typesMod;
|
|
27
|
+
// Build a lookup map for fast tool resolution on calls
|
|
13
28
|
const toolMap = new Map();
|
|
14
29
|
for (const tool of tools) {
|
|
15
30
|
toolMap.set(tool.name, tool);
|
|
16
31
|
}
|
|
17
32
|
const server = new Server({ name: 'gsd', version }, { capabilities: { tools: {} } });
|
|
33
|
+
// tools/list — return every registered GSD tool with its JSON Schema parameters
|
|
18
34
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
19
35
|
tools: tools.map((t) => ({
|
|
20
36
|
name: t.name,
|
|
@@ -22,6 +38,7 @@ export async function startMcpServer(options) {
|
|
|
22
38
|
inputSchema: t.parameters,
|
|
23
39
|
})),
|
|
24
40
|
}));
|
|
41
|
+
// tools/call — execute the requested tool and return content blocks
|
|
25
42
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
26
43
|
const { name, arguments: args } = request.params;
|
|
27
44
|
const tool = toolMap.get(name);
|
|
@@ -32,7 +49,9 @@ export async function startMcpServer(options) {
|
|
|
32
49
|
};
|
|
33
50
|
}
|
|
34
51
|
try {
|
|
35
|
-
const result = await tool.execute(`mcp-${Date.now()}`, args ?? {}, undefined,
|
|
52
|
+
const result = await tool.execute(`mcp-${Date.now()}`, args ?? {}, undefined, // no AbortSignal
|
|
53
|
+
undefined);
|
|
54
|
+
// Convert AgentToolResult content blocks to MCP content format
|
|
36
55
|
const content = result.content.map((block) => {
|
|
37
56
|
if (block.type === 'text')
|
|
38
57
|
return { type: 'text', text: block.text ?? '' };
|
|
@@ -47,6 +66,7 @@ export async function startMcpServer(options) {
|
|
|
47
66
|
return { isError: true, content: [{ type: 'text', text: message }] };
|
|
48
67
|
}
|
|
49
68
|
});
|
|
69
|
+
// Connect to stdin/stdout transport
|
|
50
70
|
const transport = new StdioServerTransport();
|
|
51
71
|
await server.connect(transport);
|
|
52
72
|
process.stderr.write(`[gsd] MCP server started (v${version})\n`);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Models.json resolution with fallback to ~/.pi/agent/models.json
|
|
3
|
+
*
|
|
4
|
+
* GSD uses ~/.gsd/agent/models.json, but for a smooth migration/development
|
|
5
|
+
* experience, this module provides resolution logic that:
|
|
6
|
+
*
|
|
7
|
+
* 1. Reads ~/.gsd/agent/models.json if it exists
|
|
8
|
+
* 2. Falls back to ~/.pi/agent/models.json if GSD file doesn't exist
|
|
9
|
+
* 3. Merges both files if both exist (GSD takes precedence)
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Resolve the path to models.json with fallback logic.
|
|
13
|
+
*
|
|
14
|
+
* Priority:
|
|
15
|
+
* 1. ~/.gsd/agent/models.json (exists) → return this path
|
|
16
|
+
* 2. ~/.pi/agent/models.json (exists) → return this path (fallback)
|
|
17
|
+
* 3. Neither exists → return GSD path (will be created)
|
|
18
|
+
*
|
|
19
|
+
* @returns The path to use for models.json
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveModelsJsonPath(): string;
|
|
22
|
+
/**
|
|
23
|
+
* Check if both GSD and PI models.json files exist.
|
|
24
|
+
*/
|
|
25
|
+
export declare function hasBothModelsFiles(): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Get the paths to both models.json files.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getModelsPaths(): {
|
|
30
|
+
gsd: string;
|
|
31
|
+
pi: string;
|
|
32
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Models.json resolution with fallback to ~/.pi/agent/models.json
|
|
3
|
+
*
|
|
4
|
+
* GSD uses ~/.gsd/agent/models.json, but for a smooth migration/development
|
|
5
|
+
* experience, this module provides resolution logic that:
|
|
6
|
+
*
|
|
7
|
+
* 1. Reads ~/.gsd/agent/models.json if it exists
|
|
8
|
+
* 2. Falls back to ~/.pi/agent/models.json if GSD file doesn't exist
|
|
9
|
+
* 3. Merges both files if both exist (GSD takes precedence)
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync } from 'node:fs';
|
|
12
|
+
import { homedir } from 'node:os';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { agentDir } from './app-paths.js';
|
|
15
|
+
const GSD_MODELS_PATH = join(agentDir, 'models.json');
|
|
16
|
+
const PI_MODELS_PATH = join(homedir(), '.pi', 'agent', 'models.json');
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the path to models.json with fallback logic.
|
|
19
|
+
*
|
|
20
|
+
* Priority:
|
|
21
|
+
* 1. ~/.gsd/agent/models.json (exists) → return this path
|
|
22
|
+
* 2. ~/.pi/agent/models.json (exists) → return this path (fallback)
|
|
23
|
+
* 3. Neither exists → return GSD path (will be created)
|
|
24
|
+
*
|
|
25
|
+
* @returns The path to use for models.json
|
|
26
|
+
*/
|
|
27
|
+
export function resolveModelsJsonPath() {
|
|
28
|
+
if (existsSync(GSD_MODELS_PATH)) {
|
|
29
|
+
return GSD_MODELS_PATH;
|
|
30
|
+
}
|
|
31
|
+
if (existsSync(PI_MODELS_PATH)) {
|
|
32
|
+
return PI_MODELS_PATH;
|
|
33
|
+
}
|
|
34
|
+
return GSD_MODELS_PATH;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Check if both GSD and PI models.json files exist.
|
|
38
|
+
*/
|
|
39
|
+
export function hasBothModelsFiles() {
|
|
40
|
+
return existsSync(GSD_MODELS_PATH) && existsSync(PI_MODELS_PATH);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get the paths to both models.json files.
|
|
44
|
+
*/
|
|
45
|
+
export function getModelsPaths() {
|
|
46
|
+
return {
|
|
47
|
+
gsd: GSD_MODELS_PATH,
|
|
48
|
+
pi: PI_MODELS_PATH,
|
|
49
|
+
};
|
|
50
|
+
}
|
package/dist/resource-loader.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DefaultResourceLoader } from '@gsd/pi-coding-agent';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
|
-
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { chmodSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { compareSemver } from './update-check.js';
|
|
@@ -113,6 +113,38 @@ export function getNewerManagedResourceVersion(agentDir, currentVersion) {
|
|
|
113
113
|
}
|
|
114
114
|
return compareSemver(managedVersion, currentVersion) > 0 ? managedVersion : null;
|
|
115
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Recursively makes all files and directories under dirPath owner-writable.
|
|
118
|
+
*
|
|
119
|
+
* Files copied from the Nix store inherit read-only modes (0444/0555).
|
|
120
|
+
* Calling this before cpSync prevents overwrite failures on subsequent upgrades,
|
|
121
|
+
* and calling it after ensures the next run can overwrite the copies too.
|
|
122
|
+
*
|
|
123
|
+
* Preserves existing permission bits (including executability) and only adds
|
|
124
|
+
* owner-write (and for directories, owner-exec) without widening group/other
|
|
125
|
+
* permissions.
|
|
126
|
+
*/
|
|
127
|
+
function makeTreeWritable(dirPath) {
|
|
128
|
+
if (!existsSync(dirPath))
|
|
129
|
+
return;
|
|
130
|
+
const stats = statSync(dirPath);
|
|
131
|
+
const isDir = stats.isDirectory();
|
|
132
|
+
const currentMode = stats.mode & 0o777;
|
|
133
|
+
// Ensure owner-write; for directories also ensure owner-exec so they remain traversable.
|
|
134
|
+
let newMode = currentMode | 0o200;
|
|
135
|
+
if (isDir) {
|
|
136
|
+
newMode |= 0o100;
|
|
137
|
+
}
|
|
138
|
+
if (newMode !== currentMode) {
|
|
139
|
+
chmodSync(dirPath, newMode);
|
|
140
|
+
}
|
|
141
|
+
if (isDir) {
|
|
142
|
+
for (const entry of readdirSync(dirPath, { withFileTypes: true })) {
|
|
143
|
+
const entryPath = join(dirPath, entry.name);
|
|
144
|
+
makeTreeWritable(entryPath);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
116
148
|
/**
|
|
117
149
|
* Syncs all bundled resources to agentDir (~/.gsd/agent/) on every launch.
|
|
118
150
|
*
|
|
@@ -130,26 +162,49 @@ export function getNewerManagedResourceVersion(agentDir, currentVersion) {
|
|
|
130
162
|
*/
|
|
131
163
|
export function initResources(agentDir) {
|
|
132
164
|
mkdirSync(agentDir, { recursive: true });
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if (managedVersion && managedVersion === currentVersion) {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
// Sync extensions — overwrite so updates land on next launch
|
|
165
|
+
// Sync extensions — clean bundled subdirs first to remove stale leftover files,
|
|
166
|
+
// then overwrite so updates land on next launch. Only bundled subdirs are removed;
|
|
167
|
+
// user-created extension directories are preserved.
|
|
140
168
|
const destExtensions = join(agentDir, 'extensions');
|
|
169
|
+
makeTreeWritable(destExtensions);
|
|
170
|
+
for (const entry of readdirSync(bundledExtensionsDir, { withFileTypes: true })) {
|
|
171
|
+
if (entry.isDirectory()) {
|
|
172
|
+
const target = join(destExtensions, entry.name);
|
|
173
|
+
if (existsSync(target))
|
|
174
|
+
rmSync(target, { recursive: true, force: true });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
141
177
|
cpSync(bundledExtensionsDir, destExtensions, { recursive: true, force: true });
|
|
178
|
+
makeTreeWritable(destExtensions);
|
|
142
179
|
// Sync agents
|
|
143
180
|
const destAgents = join(agentDir, 'agents');
|
|
144
181
|
const srcAgents = join(resourcesDir, 'agents');
|
|
145
182
|
if (existsSync(srcAgents)) {
|
|
183
|
+
makeTreeWritable(destAgents);
|
|
184
|
+
for (const entry of readdirSync(srcAgents, { withFileTypes: true })) {
|
|
185
|
+
if (entry.isDirectory()) {
|
|
186
|
+
const target = join(destAgents, entry.name);
|
|
187
|
+
if (existsSync(target))
|
|
188
|
+
rmSync(target, { recursive: true, force: true });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
146
191
|
cpSync(srcAgents, destAgents, { recursive: true, force: true });
|
|
192
|
+
makeTreeWritable(destAgents);
|
|
147
193
|
}
|
|
148
|
-
// Sync skills
|
|
194
|
+
// Sync skills
|
|
149
195
|
const destSkills = join(agentDir, 'skills');
|
|
150
196
|
const srcSkills = join(resourcesDir, 'skills');
|
|
151
197
|
if (existsSync(srcSkills)) {
|
|
198
|
+
makeTreeWritable(destSkills);
|
|
199
|
+
for (const entry of readdirSync(srcSkills, { withFileTypes: true })) {
|
|
200
|
+
if (entry.isDirectory()) {
|
|
201
|
+
const target = join(destSkills, entry.name);
|
|
202
|
+
if (existsSync(target))
|
|
203
|
+
rmSync(target, { recursive: true, force: true });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
152
206
|
cpSync(srcSkills, destSkills, { recursive: true, force: true });
|
|
207
|
+
makeTreeWritable(destSkills);
|
|
153
208
|
}
|
|
154
209
|
writeManagedResourceManifest(agentDir);
|
|
155
210
|
}
|
|
@@ -10,12 +10,19 @@ import {
|
|
|
10
10
|
import type { BgProcess, OutputDigest, OutputLine, GetOutputOptions } from "./types.js";
|
|
11
11
|
import {
|
|
12
12
|
ERROR_PATTERNS,
|
|
13
|
+
ERROR_PATTERN_UNION,
|
|
14
|
+
WARNING_PATTERN_UNION,
|
|
15
|
+
READINESS_PATTERN_UNION,
|
|
16
|
+
BUILD_COMPLETE_PATTERN_UNION,
|
|
17
|
+
TEST_RESULT_PATTERN_UNION,
|
|
13
18
|
WARNING_PATTERNS,
|
|
14
19
|
URL_PATTERN,
|
|
15
20
|
PORT_PATTERN,
|
|
21
|
+
PORT_PATTERN_SOURCE,
|
|
16
22
|
READINESS_PATTERNS,
|
|
17
23
|
BUILD_COMPLETE_PATTERNS,
|
|
18
24
|
TEST_RESULT_PATTERNS,
|
|
25
|
+
LINE_DEDUP_MAX,
|
|
19
26
|
} from "./types.js";
|
|
20
27
|
import { addEvent, pushAlert } from "./process-manager.js";
|
|
21
28
|
import { transitionToReady } from "./readiness-detector.js";
|
|
@@ -24,8 +31,8 @@ import { formatUptime, formatTimeAgo } from "./utilities.js";
|
|
|
24
31
|
// ── Output Analysis ────────────────────────────────────────────────────────
|
|
25
32
|
|
|
26
33
|
export function analyzeLine(bg: BgProcess, line: string, stream: "stdout" | "stderr"): void {
|
|
27
|
-
// Error detection
|
|
28
|
-
if (
|
|
34
|
+
// Error detection — single union regex instead of .some(p => p.test(line))
|
|
35
|
+
if (ERROR_PATTERN_UNION.test(line)) {
|
|
29
36
|
bg.recentErrors.push(line.trim().slice(0, 200)); // Cap line length
|
|
30
37
|
if (bg.recentErrors.length > 50) bg.recentErrors.splice(0, bg.recentErrors.length - 50);
|
|
31
38
|
|
|
@@ -40,8 +47,8 @@ export function analyzeLine(bg: BgProcess, line: string, stream: "stdout" | "std
|
|
|
40
47
|
}
|
|
41
48
|
}
|
|
42
49
|
|
|
43
|
-
// Warning detection
|
|
44
|
-
if (
|
|
50
|
+
// Warning detection — single union regex
|
|
51
|
+
if (WARNING_PATTERN_UNION.test(line)) {
|
|
45
52
|
bg.recentWarnings.push(line.trim().slice(0, 200));
|
|
46
53
|
if (bg.recentWarnings.length > 50) bg.recentWarnings.splice(0, bg.recentWarnings.length - 50);
|
|
47
54
|
}
|
|
@@ -56,9 +63,10 @@ export function analyzeLine(bg: BgProcess, line: string, stream: "stdout" | "std
|
|
|
56
63
|
}
|
|
57
64
|
}
|
|
58
65
|
|
|
59
|
-
// Port extraction
|
|
66
|
+
// Port extraction — PORT_PATTERN has /g flag so must be re-created per call
|
|
67
|
+
// Use PORT_PATTERN_SOURCE (string) to avoid re-parsing the literal each time
|
|
68
|
+
const portRe = new RegExp(PORT_PATTERN_SOURCE, "gi");
|
|
60
69
|
let portMatch: RegExpExecArray | null;
|
|
61
|
-
const portRe = new RegExp(PORT_PATTERN.source, PORT_PATTERN.flags);
|
|
62
70
|
while ((portMatch = portRe.exec(line)) !== null) {
|
|
63
71
|
const port = parseInt(portMatch[1], 10);
|
|
64
72
|
if (port > 0 && port <= 65535 && !bg.ports.includes(port)) {
|
|
@@ -71,7 +79,7 @@ export function analyzeLine(bg: BgProcess, line: string, stream: "stdout" | "std
|
|
|
71
79
|
}
|
|
72
80
|
}
|
|
73
81
|
|
|
74
|
-
// Readiness detection
|
|
82
|
+
// Readiness detection — single union regex
|
|
75
83
|
if (bg.status === "starting") {
|
|
76
84
|
// Check custom ready pattern first
|
|
77
85
|
if (bg.readyPattern) {
|
|
@@ -83,14 +91,14 @@ export function analyzeLine(bg: BgProcess, line: string, stream: "stdout" | "std
|
|
|
83
91
|
}
|
|
84
92
|
|
|
85
93
|
// Check built-in readiness patterns
|
|
86
|
-
if (bg.status === "starting" &&
|
|
94
|
+
if (bg.status === "starting" && READINESS_PATTERN_UNION.test(line)) {
|
|
87
95
|
transitionToReady(bg, `Readiness pattern matched: ${line.trim().slice(0, 100)}`);
|
|
88
96
|
}
|
|
89
97
|
}
|
|
90
98
|
|
|
91
99
|
// Recovery detection: if we were in error and see a success pattern
|
|
92
100
|
if (bg.status === "error") {
|
|
93
|
-
if (
|
|
101
|
+
if (READINESS_PATTERN_UNION.test(line) || BUILD_COMPLETE_PATTERN_UNION.test(line)) {
|
|
94
102
|
bg.status = "ready";
|
|
95
103
|
bg.recentErrors = [];
|
|
96
104
|
addEvent(bg, { type: "recovered", detail: "Process recovered from error state" });
|
|
@@ -98,10 +106,22 @@ export function analyzeLine(bg: BgProcess, line: string, stream: "stdout" | "std
|
|
|
98
106
|
}
|
|
99
107
|
}
|
|
100
108
|
|
|
101
|
-
// Dedup tracking
|
|
109
|
+
// Dedup tracking — evict oldest entry when map exceeds LINE_DEDUP_MAX (LRU via Map insertion order)
|
|
102
110
|
bg.totalRawLines++;
|
|
103
111
|
const lineHash = line.trim().slice(0, 100);
|
|
104
|
-
|
|
112
|
+
const existing = bg.lineDedup.get(lineHash);
|
|
113
|
+
if (existing !== undefined) {
|
|
114
|
+
// Re-insert to update insertion order (move to tail = most recent)
|
|
115
|
+
bg.lineDedup.delete(lineHash);
|
|
116
|
+
bg.lineDedup.set(lineHash, existing + 1);
|
|
117
|
+
} else {
|
|
118
|
+
if (bg.lineDedup.size >= LINE_DEDUP_MAX) {
|
|
119
|
+
// Evict oldest entry (Map iteration order = insertion order = LRU at head)
|
|
120
|
+
const oldest = bg.lineDedup.keys().next().value;
|
|
121
|
+
if (oldest !== undefined) bg.lineDedup.delete(oldest);
|
|
122
|
+
}
|
|
123
|
+
bg.lineDedup.set(lineHash, 1);
|
|
124
|
+
}
|
|
105
125
|
}
|
|
106
126
|
|
|
107
127
|
// ── Digest Generation ──────────────────────────────────────────────────────
|
|
@@ -154,12 +174,12 @@ export function getHighlights(bg: BgProcess, maxLines: number = 15): string[] {
|
|
|
154
174
|
for (let i = 0; i < bg.output.length; i++) {
|
|
155
175
|
const entry = bg.output[i];
|
|
156
176
|
let score = 0;
|
|
157
|
-
if (
|
|
158
|
-
if (
|
|
177
|
+
if (ERROR_PATTERN_UNION.test(entry.line)) score += 10;
|
|
178
|
+
if (WARNING_PATTERN_UNION.test(entry.line)) score += 5;
|
|
159
179
|
if (URL_PATTERN.test(entry.line)) score += 3;
|
|
160
|
-
if (
|
|
161
|
-
if (
|
|
162
|
-
if (
|
|
180
|
+
if (READINESS_PATTERN_UNION.test(entry.line)) score += 8;
|
|
181
|
+
if (TEST_RESULT_PATTERN_UNION.test(entry.line)) score += 7;
|
|
182
|
+
if (BUILD_COMPLETE_PATTERN_UNION.test(entry.line)) score += 6;
|
|
163
183
|
// Boost recent lines so highlights favor fresh output over stale
|
|
164
184
|
if (i >= bg.output.length - 50) score += 2;
|
|
165
185
|
if (score > 0) {
|
|
@@ -39,6 +39,8 @@ export function setPendingAlerts(alerts: string[]): void {
|
|
|
39
39
|
|
|
40
40
|
export function addOutputLine(bg: BgProcess, stream: "stdout" | "stderr", line: string): void {
|
|
41
41
|
bg.output.push({ stream, line, ts: Date.now() });
|
|
42
|
+
if (stream === "stdout") bg.stdoutLineCount++;
|
|
43
|
+
else bg.stderrLineCount++;
|
|
42
44
|
if (bg.output.length > MAX_BUFFER_LINES) {
|
|
43
45
|
const excess = bg.output.length - MAX_BUFFER_LINES;
|
|
44
46
|
bg.output.splice(0, excess);
|
|
@@ -60,8 +62,6 @@ export function pushAlert(bg: BgProcess, message: string): void {
|
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
export function getInfo(p: BgProcess): BgProcessInfo {
|
|
63
|
-
const stdoutLines = p.output.filter(l => l.stream === "stdout").length;
|
|
64
|
-
const stderrLines = p.output.filter(l => l.stream === "stderr").length;
|
|
65
65
|
return {
|
|
66
66
|
id: p.id,
|
|
67
67
|
label: p.label,
|
|
@@ -72,8 +72,8 @@ export function getInfo(p: BgProcess): BgProcessInfo {
|
|
|
72
72
|
exitCode: p.exitCode,
|
|
73
73
|
signal: p.signal,
|
|
74
74
|
outputLines: p.output.length,
|
|
75
|
-
stdoutLines,
|
|
76
|
-
stderrLines,
|
|
75
|
+
stdoutLines: p.stdoutLineCount,
|
|
76
|
+
stderrLines: p.stderrLineCount,
|
|
77
77
|
status: p.status,
|
|
78
78
|
processType: p.processType,
|
|
79
79
|
ports: p.ports,
|
|
@@ -161,6 +161,8 @@ export function startProcess(opts: StartOptions): BgProcess {
|
|
|
161
161
|
commandHistory: [],
|
|
162
162
|
lineDedup: new Map(),
|
|
163
163
|
totalRawLines: 0,
|
|
164
|
+
stdoutLineCount: 0,
|
|
165
|
+
stderrLineCount: 0,
|
|
164
166
|
envKeys: Object.keys(opts.env || {}),
|
|
165
167
|
restartCount: 0,
|
|
166
168
|
startConfig: {
|
|
@@ -90,10 +90,14 @@ export interface BgProcess {
|
|
|
90
90
|
lastWarningCount: number;
|
|
91
91
|
/** Command history for shell-type sessions */
|
|
92
92
|
commandHistory: string[];
|
|
93
|
-
/** Dedup tracker: hash → count of repeated lines */
|
|
93
|
+
/** Dedup tracker: hash → count of repeated lines (capped at LINE_DEDUP_MAX entries) */
|
|
94
94
|
lineDedup: Map<string, number>;
|
|
95
95
|
/** Total raw lines (before dedup) for token savings calc */
|
|
96
96
|
totalRawLines: number;
|
|
97
|
+
/** Tracked stdout line count (incremented in addOutputLine, avoids O(n) filter) */
|
|
98
|
+
stdoutLineCount: number;
|
|
99
|
+
/** Tracked stderr line count (incremented in addOutputLine, avoids O(n) filter) */
|
|
100
|
+
stderrLineCount: number;
|
|
97
101
|
/** Env snapshot (keys only, no values for security) */
|
|
98
102
|
envKeys: string[];
|
|
99
103
|
/** Restart count */
|
|
@@ -163,6 +167,8 @@ export interface ProcessManifest {
|
|
|
163
167
|
export const MAX_BUFFER_LINES = 5000;
|
|
164
168
|
export const MAX_EVENTS = 200;
|
|
165
169
|
export const DEAD_PROCESS_TTL = 10 * 60 * 1000;
|
|
170
|
+
/** Maximum unique entries in the per-process lineDedup Map before LRU eviction. */
|
|
171
|
+
export const LINE_DEDUP_MAX = 500;
|
|
166
172
|
export const PORT_PROBE_TIMEOUT = 500;
|
|
167
173
|
export const READY_POLL_INTERVAL = 250;
|
|
168
174
|
export const DEFAULT_READY_TIMEOUT = 30000;
|
|
@@ -249,3 +255,29 @@ export const BUILD_COMPLETE_PATTERNS: RegExp[] = [
|
|
|
249
255
|
/webpack\s+\d+\.\d+/i,
|
|
250
256
|
/bundle\s+(?:is\s+)?ready/i,
|
|
251
257
|
];
|
|
258
|
+
|
|
259
|
+
// ── Compiled union regexes (single-pass alternatives to .some(p => p.test(line))) ──
|
|
260
|
+
// Built once at module load — eliminates per-line RegExp construction overhead.
|
|
261
|
+
|
|
262
|
+
export const ERROR_PATTERN_UNION = new RegExp(
|
|
263
|
+
ERROR_PATTERNS.map(p => p.source).join("|"),
|
|
264
|
+
"i",
|
|
265
|
+
);
|
|
266
|
+
export const WARNING_PATTERN_UNION = new RegExp(
|
|
267
|
+
WARNING_PATTERNS.map(p => p.source).join("|"),
|
|
268
|
+
"i",
|
|
269
|
+
);
|
|
270
|
+
export const READINESS_PATTERN_UNION = new RegExp(
|
|
271
|
+
READINESS_PATTERNS.map(p => p.source).join("|"),
|
|
272
|
+
"i",
|
|
273
|
+
);
|
|
274
|
+
export const BUILD_COMPLETE_PATTERN_UNION = new RegExp(
|
|
275
|
+
BUILD_COMPLETE_PATTERNS.map(p => p.source).join("|"),
|
|
276
|
+
"i",
|
|
277
|
+
);
|
|
278
|
+
export const TEST_RESULT_PATTERN_UNION = new RegExp(
|
|
279
|
+
TEST_RESULT_PATTERNS.map(p => p.source).join("|"),
|
|
280
|
+
"i",
|
|
281
|
+
);
|
|
282
|
+
/** PORT_PATTERN compiled once for reuse in analyzeLine (needs exec, so must be re-created per call with /g) */
|
|
283
|
+
export const PORT_PATTERN_SOURCE = PORT_PATTERN.source;
|
|
@@ -10,9 +10,11 @@ import sharp from "sharp";
|
|
|
10
10
|
import type { CompactPageState, CompactSelectorState } from "./state.js";
|
|
11
11
|
import { formatCompactStateSummary } from "./utils.js";
|
|
12
12
|
|
|
13
|
-
// Anthropic
|
|
14
|
-
//
|
|
15
|
-
|
|
13
|
+
// Anthropic vision: 1568px is the recommended optimal width. Height is capped
|
|
14
|
+
// generously at 8000px so tall full-page screenshots remain readable rather
|
|
15
|
+
// than being squished into a square constraint.
|
|
16
|
+
const MAX_SCREENSHOT_WIDTH = 1568;
|
|
17
|
+
const MAX_SCREENSHOT_HEIGHT = 8000;
|
|
16
18
|
|
|
17
19
|
// ---------------------------------------------------------------------------
|
|
18
20
|
// Compact page state capture
|
|
@@ -120,9 +122,10 @@ export async function postActionSummary(p: Page, target?: Page | Frame): Promise
|
|
|
120
122
|
// ---------------------------------------------------------------------------
|
|
121
123
|
|
|
122
124
|
/**
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
125
|
+
* Constrain screenshot dimensions for the Anthropic vision API.
|
|
126
|
+
* Width is capped at 1568px (optimal) and height at 8000px, each
|
|
127
|
+
* independently, using `fit: "inside"` so aspect ratio is preserved.
|
|
128
|
+
* Small images are never upscaled.
|
|
126
129
|
*
|
|
127
130
|
* `page` parameter is retained for ToolDeps signature stability (D008)
|
|
128
131
|
* but is no longer used — all processing is server-side via sharp.
|
|
@@ -133,18 +136,17 @@ export async function constrainScreenshot(
|
|
|
133
136
|
mimeType: string,
|
|
134
137
|
quality: number,
|
|
135
138
|
): Promise<Buffer> {
|
|
136
|
-
const
|
|
139
|
+
const meta = await sharp(buffer).metadata();
|
|
140
|
+
const width = meta.width;
|
|
141
|
+
const height = meta.height;
|
|
137
142
|
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
height !== undefined &&
|
|
141
|
-
width <= MAX_SCREENSHOT_DIM &&
|
|
142
|
-
height <= MAX_SCREENSHOT_DIM
|
|
143
|
-
) {
|
|
144
|
-
return buffer;
|
|
145
|
-
}
|
|
143
|
+
if (width === undefined || height === undefined) return buffer;
|
|
144
|
+
if (width <= MAX_SCREENSHOT_WIDTH && height <= MAX_SCREENSHOT_HEIGHT) return buffer;
|
|
146
145
|
|
|
147
|
-
const resizer = sharp(buffer).resize(
|
|
146
|
+
const resizer = sharp(buffer).resize(MAX_SCREENSHOT_WIDTH, MAX_SCREENSHOT_HEIGHT, {
|
|
147
|
+
fit: "inside",
|
|
148
|
+
withoutEnlargement: true,
|
|
149
|
+
});
|
|
148
150
|
|
|
149
151
|
if (mimeType === "image/png") {
|
|
150
152
|
return Buffer.from(await resizer.png().toBuffer());
|
|
@@ -17,6 +17,16 @@ import { registerWaitTools } from "./tools/wait.js";
|
|
|
17
17
|
import { registerPageTools } from "./tools/pages.js";
|
|
18
18
|
import { registerFormTools } from "./tools/forms.js";
|
|
19
19
|
import { registerIntentTools } from "./tools/intent.js";
|
|
20
|
+
import { registerPdfTools } from "./tools/pdf.js";
|
|
21
|
+
import { registerStatePersistenceTools } from "./tools/state-persistence.js";
|
|
22
|
+
import { registerNetworkMockTools } from "./tools/network-mock.js";
|
|
23
|
+
import { registerDeviceTools } from "./tools/device.js";
|
|
24
|
+
import { registerExtractTools } from "./tools/extract.js";
|
|
25
|
+
import { registerVisualDiffTools } from "./tools/visual-diff.js";
|
|
26
|
+
import { registerZoomTools } from "./tools/zoom.js";
|
|
27
|
+
import { registerCodegenTools } from "./tools/codegen.js";
|
|
28
|
+
import { registerActionCacheTools } from "./tools/action-cache.js";
|
|
29
|
+
import { registerInjectionDetectionTools } from "./tools/injection-detect.js";
|
|
20
30
|
|
|
21
31
|
export default function (pi: ExtensionAPI) {
|
|
22
32
|
pi.on("session_shutdown", async () => { await closeBrowser(); });
|
|
@@ -48,4 +58,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
48
58
|
registerPageTools(pi, deps);
|
|
49
59
|
registerFormTools(pi, deps);
|
|
50
60
|
registerIntentTools(pi, deps);
|
|
61
|
+
registerPdfTools(pi, deps);
|
|
62
|
+
registerStatePersistenceTools(pi, deps);
|
|
63
|
+
registerNetworkMockTools(pi, deps);
|
|
64
|
+
registerDeviceTools(pi, deps);
|
|
65
|
+
registerExtractTools(pi, deps);
|
|
66
|
+
registerVisualDiffTools(pi, deps);
|
|
67
|
+
registerZoomTools(pi, deps);
|
|
68
|
+
registerCodegenTools(pi, deps);
|
|
69
|
+
registerActionCacheTools(pi, deps);
|
|
70
|
+
registerInjectionDetectionTools(pi, deps);
|
|
51
71
|
}
|