lsd-pi 1.3.2 → 1.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +2 -1
- package/dist/lsd-settings-manager.d.ts +2 -0
- package/dist/lsd-settings-manager.js +5 -0
- package/dist/resource-loader.js +33 -3
- package/dist/resources/extensions/browser-tools/tools/codegen.js +5 -5
- package/dist/resources/extensions/browser-tools/tools/navigation.js +107 -178
- package/dist/resources/extensions/browser-tools/tools/network-mock.js +112 -167
- package/dist/resources/extensions/browser-tools/tools/pages.js +182 -234
- package/dist/resources/extensions/browser-tools/tools/refs.js +202 -461
- package/dist/resources/extensions/browser-tools/tools/session.js +176 -323
- package/dist/resources/extensions/browser-tools/tools/state-persistence.js +91 -154
- package/dist/resources/extensions/browser-tools/utils.js +1 -1
- package/dist/resources/extensions/cache-timer/index.js +3 -2
- package/dist/resources/extensions/slash-commands/extension-manifest.json +2 -2
- package/dist/resources/extensions/slash-commands/fast.js +73 -0
- package/dist/resources/extensions/slash-commands/index.js +2 -0
- package/dist/resources/extensions/slash-commands/plan.js +37 -12
- package/dist/resources/extensions/subagent/background-job-manager.js +13 -0
- package/dist/resources/extensions/subagent/in-process-runner.js +387 -0
- package/dist/resources/extensions/subagent/index.js +278 -626
- package/dist/resources/extensions/subagent/legacy-runner.js +503 -0
- package/dist/resources/extensions/voice/index.js +96 -36
- package/dist/resources/extensions/voice/push-to-talk.js +26 -0
- package/dist/welcome-screen.js +2 -2
- package/package.json +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +19 -0
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +16 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/src/agent.ts +32 -2
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts +34 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +32 -4
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +127 -16
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts +8 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.fast-mode.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/openai-responses.fast-mode.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/openai-responses.fast-mode.test.js +67 -0
- package/packages/pi-ai/dist/providers/openai-responses.fast-mode.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/openai-responses.js +21 -3
- package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +2 -0
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +5 -0
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +143 -20
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +47 -4
- package/packages/pi-ai/src/providers/openai-responses.fast-mode.test.ts +73 -0
- package/packages/pi-ai/src/providers/openai-responses.ts +26 -3
- package/packages/pi-ai/src/providers/simple-options.ts +2 -0
- package/packages/pi-ai/src/types.ts +5 -0
- package/packages/pi-coding-agent/dist/core/keybindings.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.js +2 -0
- package/packages/pi-coding-agent/dist/core/keybindings.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +4 -2
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.collapse-tool-calls.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.collapse-tool-calls.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.collapse-tool-calls.test.js +35 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.collapse-tool-calls.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +12 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.fast-mode.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.fast-mode.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.fast-mode.test.js +35 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.fast-mode.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js +24 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
- package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +6 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tool-priority.d.ts +4 -0
- package/packages/pi-coding-agent/dist/core/tool-priority.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tool-priority.js +18 -0
- package/packages/pi-coding-agent/dist/core/tool-priority.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/tool-priority.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tool-priority.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tool-priority.test.js +27 -0
- package/packages/pi-coding-agent/dist/core/tool-priority.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.js +21 -0
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +16 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.js +34 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-summary-line.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.d.ts +45 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.js +314 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.test.js +122 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/btw-overlay.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +7 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +86 -28
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +23 -10
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +8 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +52 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +19 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +127 -14
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.d.ts +14 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.js +93 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-summary-line.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.js +328 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.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 +123 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +7 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +9 -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 +103 -23
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +41 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +4 -4
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/keybindings.ts +4 -1
- package/packages/pi-coding-agent/src/core/sdk.ts +4 -2
- package/packages/pi-coding-agent/src/core/settings-manager.collapse-tool-calls.test.ts +46 -0
- package/packages/pi-coding-agent/src/core/settings-manager.fast-mode.test.ts +46 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +36 -0
- package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +6 -1
- package/packages/pi-coding-agent/src/core/tool-priority.test.ts +30 -0
- package/packages/pi-coding-agent/src/core/tool-priority.ts +17 -0
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +20 -0
- package/packages/pi-coding-agent/src/core/tools/edit-diff.ts +26 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-summary-line.test.ts +41 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/btw-overlay.test.ts +172 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/btw-overlay.ts +402 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +105 -28
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +21 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +63 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +1262 -1138
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-summary-line.ts +120 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/__tests__/chat-controller.collapsed-tool-summary.test.ts +396 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +530 -398
- package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +7 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +4 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +109 -23
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +60 -1
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +4 -4
- package/packages/pi-tui/dist/components/editor.js +3 -3
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/src/components/editor.ts +3 -3
- package/pkg/dist/modes/interactive/theme/themes.js +4 -4
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/tools/codegen.ts +5 -5
- package/src/resources/extensions/browser-tools/tools/navigation.ts +118 -196
- package/src/resources/extensions/browser-tools/tools/network-mock.ts +114 -205
- package/src/resources/extensions/browser-tools/tools/pages.ts +183 -237
- package/src/resources/extensions/browser-tools/tools/refs.ts +193 -507
- package/src/resources/extensions/browser-tools/tools/session.ts +182 -321
- package/src/resources/extensions/browser-tools/tools/state-persistence.ts +94 -172
- package/src/resources/extensions/browser-tools/utils.ts +1 -1
- package/src/resources/extensions/cache-timer/index.ts +3 -2
- package/src/resources/extensions/slash-commands/extension-manifest.json +2 -2
- package/src/resources/extensions/slash-commands/fast.ts +89 -0
- package/src/resources/extensions/slash-commands/index.ts +2 -0
- package/src/resources/extensions/slash-commands/plan.ts +42 -12
- package/src/resources/extensions/subagent/background-job-manager.ts +28 -0
- package/src/resources/extensions/subagent/in-process-runner.ts +534 -0
- package/src/resources/extensions/subagent/index.ts +489 -799
- package/src/resources/extensions/subagent/legacy-runner.ts +607 -0
- package/src/resources/extensions/voice/index.ts +308 -238
- package/src/resources/extensions/voice/push-to-talk.ts +42 -0
- package/src/resources/extensions/voice/tests/push-to-talk.test.ts +109 -0
|
@@ -1,180 +1,117 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
/**
|
|
3
|
-
* State persistence
|
|
3
|
+
* State persistence — save/restore cookies, localStorage, sessionStorage.
|
|
4
4
|
*/
|
|
5
5
|
const STATE_DIR = ".gsd/browser-state";
|
|
6
6
|
export function registerStatePersistenceTools(pi, deps) {
|
|
7
|
-
// -------------------------------------------------------------------------
|
|
8
|
-
// browser_save_state
|
|
9
|
-
// -------------------------------------------------------------------------
|
|
10
7
|
pi.registerTool({
|
|
11
|
-
name: "
|
|
12
|
-
label: "Browser
|
|
13
|
-
description: "Save cookies, localStorage,
|
|
14
|
-
"State files
|
|
15
|
-
"Never displays secret values in output.",
|
|
8
|
+
name: "browser_state",
|
|
9
|
+
label: "Browser State",
|
|
10
|
+
description: "Save or restore browser state (cookies, localStorage, sessionStorage) to persist sessions across browser restarts. " +
|
|
11
|
+
"State files written to .gsd/browser-state/ (should be gitignored).",
|
|
16
12
|
parameters: Type.Object({
|
|
17
|
-
|
|
13
|
+
action: Type.Union([
|
|
14
|
+
Type.Literal("save"),
|
|
15
|
+
Type.Literal("restore"),
|
|
16
|
+
], { description: "'save' — persist current state, 'restore' — load previously saved state" }),
|
|
17
|
+
name: Type.Optional(Type.String({ description: "State file name (default: 'default'). Used as filename stem." })),
|
|
18
18
|
}),
|
|
19
19
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
20
20
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const { mkdir, writeFile } = await import("node:fs/promises");
|
|
24
|
-
const path = await import("node:path");
|
|
25
|
-
const stateDir = path.resolve(process.cwd(), STATE_DIR);
|
|
26
|
-
await mkdir(stateDir, { recursive: true });
|
|
27
|
-
// 1. Playwright storageState: cookies + localStorage
|
|
28
|
-
const storageState = await ctx.storageState();
|
|
29
|
-
// 2. sessionStorage: must be extracted per-origin via page.evaluate
|
|
30
|
-
const sessionStorageData = {};
|
|
31
|
-
try {
|
|
32
|
-
const origin = new URL(p.url()).origin;
|
|
33
|
-
const ssData = await p.evaluate(() => {
|
|
34
|
-
const data = {};
|
|
35
|
-
for (let i = 0; i < sessionStorage.length; i++) {
|
|
36
|
-
const key = sessionStorage.key(i);
|
|
37
|
-
if (key)
|
|
38
|
-
data[key] = sessionStorage.getItem(key) ?? "";
|
|
39
|
-
}
|
|
40
|
-
return data;
|
|
41
|
-
});
|
|
42
|
-
if (Object.keys(ssData).length > 0) {
|
|
43
|
-
sessionStorageData[origin] = ssData;
|
|
44
|
-
}
|
|
21
|
+
if (params.action === "save") {
|
|
22
|
+
return await saveState(deps, params.name ?? "default");
|
|
45
23
|
}
|
|
46
|
-
|
|
47
|
-
|
|
24
|
+
else {
|
|
25
|
+
return await restoreState(deps, params.name ?? "default");
|
|
48
26
|
}
|
|
49
|
-
const combined = {
|
|
50
|
-
storageState,
|
|
51
|
-
sessionStorage: sessionStorageData,
|
|
52
|
-
savedAt: new Date().toISOString(),
|
|
53
|
-
url: p.url(),
|
|
54
|
-
};
|
|
55
|
-
const filePath = path.join(stateDir, `${name}.json`);
|
|
56
|
-
await writeFile(filePath, JSON.stringify(combined, null, 2));
|
|
57
|
-
// Ensure .gitignore covers the state dir
|
|
58
|
-
const gitignorePath = path.resolve(process.cwd(), STATE_DIR, ".gitignore");
|
|
59
|
-
await writeFile(gitignorePath, "*\n!.gitignore\n").catch(() => { });
|
|
60
|
-
const cookieCount = storageState.cookies?.length ?? 0;
|
|
61
|
-
const localStorageOrigins = storageState.origins?.length ?? 0;
|
|
62
|
-
const sessionStorageOrigins = Object.keys(sessionStorageData).length;
|
|
63
|
-
return {
|
|
64
|
-
content: [{
|
|
65
|
-
type: "text",
|
|
66
|
-
text: `State saved: ${filePath}\nCookies: ${cookieCount}\nlocalStorage origins: ${localStorageOrigins}\nsessionStorage origins: ${sessionStorageOrigins}`,
|
|
67
|
-
}],
|
|
68
|
-
details: {
|
|
69
|
-
path: filePath,
|
|
70
|
-
cookieCount,
|
|
71
|
-
localStorageOrigins,
|
|
72
|
-
sessionStorageOrigins,
|
|
73
|
-
},
|
|
74
|
-
};
|
|
75
27
|
}
|
|
76
28
|
catch (err) {
|
|
77
29
|
return {
|
|
78
|
-
content: [{ type: "text", text: `
|
|
30
|
+
content: [{ type: "text", text: `State '${params.action}' failed: ${err.message}` }],
|
|
79
31
|
details: { error: err.message },
|
|
80
32
|
isError: true,
|
|
81
33
|
};
|
|
82
34
|
}
|
|
83
35
|
},
|
|
84
36
|
});
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const path = await import("node:path");
|
|
103
|
-
const filePath = path.join(process.cwd(), STATE_DIR, `${name}.json`);
|
|
104
|
-
let raw;
|
|
105
|
-
try {
|
|
106
|
-
raw = await readFile(filePath, "utf-8");
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
return {
|
|
110
|
-
content: [{ type: "text", text: `State file not found: ${filePath}` }],
|
|
111
|
-
details: { error: "file_not_found", path: filePath },
|
|
112
|
-
isError: true,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
const combined = JSON.parse(raw);
|
|
116
|
-
const storageState = combined.storageState;
|
|
117
|
-
const sessionStorageData = combined.sessionStorage ?? {};
|
|
118
|
-
// 1. Restore cookies
|
|
119
|
-
let cookieCount = 0;
|
|
120
|
-
if (storageState?.cookies?.length) {
|
|
121
|
-
await ctx.addCookies(storageState.cookies);
|
|
122
|
-
cookieCount = storageState.cookies.length;
|
|
37
|
+
async function saveState(deps, name) {
|
|
38
|
+
const { context: ctx, page: p } = await deps.ensureBrowser();
|
|
39
|
+
name = deps.sanitizeArtifactName(name, "default");
|
|
40
|
+
const { mkdir, writeFile } = await import("node:fs/promises");
|
|
41
|
+
const path = await import("node:path");
|
|
42
|
+
const stateDir = path.resolve(process.cwd(), STATE_DIR);
|
|
43
|
+
await mkdir(stateDir, { recursive: true });
|
|
44
|
+
const storageState = await ctx.storageState();
|
|
45
|
+
const sessionStorageData = {};
|
|
46
|
+
try {
|
|
47
|
+
const origin = new URL(p.url()).origin;
|
|
48
|
+
const ssData = await p.evaluate(() => {
|
|
49
|
+
const data = {};
|
|
50
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
|
51
|
+
const key = sessionStorage.key(i);
|
|
52
|
+
if (key)
|
|
53
|
+
data[key] = sessionStorage.getItem(key) ?? "";
|
|
123
54
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
55
|
+
return data;
|
|
56
|
+
});
|
|
57
|
+
if (Object.keys(ssData).length > 0)
|
|
58
|
+
sessionStorageData[origin] = ssData;
|
|
59
|
+
}
|
|
60
|
+
catch { /* Page may not have a valid origin */ }
|
|
61
|
+
const combined = { storageState, sessionStorage: sessionStorageData, savedAt: new Date().toISOString(), url: p.url() };
|
|
62
|
+
const filePath = path.join(stateDir, `${name}.json`);
|
|
63
|
+
await writeFile(filePath, JSON.stringify(combined, null, 2));
|
|
64
|
+
const gitignorePath = path.resolve(process.cwd(), STATE_DIR, ".gitignore");
|
|
65
|
+
await writeFile(gitignorePath, "*\n!.gitignore\n").catch(() => { });
|
|
66
|
+
return {
|
|
67
|
+
content: [{ type: "text", text: `State saved: ${filePath}\nCookies: ${storageState.cookies?.length ?? 0}\nlocalStorage origins: ${storageState.origins?.length ?? 0}\nsessionStorage origins: ${Object.keys(sessionStorageData).length}` }],
|
|
68
|
+
details: { path: filePath, cookieCount: storageState.cookies?.length ?? 0, localStorageOrigins: storageState.origins?.length ?? 0, sessionStorageOrigins: Object.keys(sessionStorageData).length },
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async function restoreState(deps, name) {
|
|
72
|
+
const { context: ctx, page: p } = await deps.ensureBrowser();
|
|
73
|
+
name = deps.sanitizeArtifactName(name, "default");
|
|
74
|
+
const { readFile } = await import("node:fs/promises");
|
|
75
|
+
const path = await import("node:path");
|
|
76
|
+
const filePath = path.join(process.cwd(), STATE_DIR, `${name}.json`);
|
|
77
|
+
let raw;
|
|
78
|
+
try {
|
|
79
|
+
raw = await readFile(filePath, "utf-8");
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return { content: [{ type: "text", text: `State file not found: ${filePath}` }], details: { error: "file_not_found", path: filePath }, isError: true };
|
|
83
|
+
}
|
|
84
|
+
const combined = JSON.parse(raw);
|
|
85
|
+
const storageState = combined.storageState;
|
|
86
|
+
const sessionStorageData = combined.sessionStorage ?? {};
|
|
87
|
+
let cookieCount = 0;
|
|
88
|
+
if (storageState?.cookies?.length) {
|
|
89
|
+
await ctx.addCookies(storageState.cookies);
|
|
90
|
+
cookieCount = storageState.cookies.length;
|
|
91
|
+
}
|
|
92
|
+
let localStorageOrigins = 0;
|
|
93
|
+
if (storageState?.origins?.length) {
|
|
94
|
+
for (const origin of storageState.origins) {
|
|
95
|
+
try {
|
|
96
|
+
await p.evaluate((items) => { for (const { name, value } of items)
|
|
97
|
+
localStorage.setItem(name, value); }, origin.localStorage ?? []);
|
|
98
|
+
localStorageOrigins++;
|
|
155
99
|
}
|
|
156
|
-
|
|
157
|
-
content: [{
|
|
158
|
-
type: "text",
|
|
159
|
-
text: `State restored from: ${filePath}\nCookies: ${cookieCount}\nlocalStorage origins: ${localStorageOrigins}\nsessionStorage origins: ${sessionStorageOrigins}\nSaved at: ${combined.savedAt ?? "unknown"}`,
|
|
160
|
-
}],
|
|
161
|
-
details: {
|
|
162
|
-
path: filePath,
|
|
163
|
-
cookieCount,
|
|
164
|
-
localStorageOrigins,
|
|
165
|
-
sessionStorageOrigins,
|
|
166
|
-
savedAt: combined.savedAt,
|
|
167
|
-
savedUrl: combined.url,
|
|
168
|
-
},
|
|
169
|
-
};
|
|
100
|
+
catch { /* Origin mismatch */ }
|
|
170
101
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
102
|
+
}
|
|
103
|
+
let sessionStorageOrigins = 0;
|
|
104
|
+
for (const [_origin, data] of Object.entries(sessionStorageData)) {
|
|
105
|
+
try {
|
|
106
|
+
await p.evaluate((items) => { for (const [key, value] of Object.entries(items))
|
|
107
|
+
sessionStorage.setItem(key, value); }, data);
|
|
108
|
+
sessionStorageOrigins++;
|
|
177
109
|
}
|
|
178
|
-
|
|
179
|
-
|
|
110
|
+
catch { /* Origin mismatch */ }
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
content: [{ type: "text", text: `State restored from: ${filePath}\nCookies: ${cookieCount}\nlocalStorage origins: ${localStorageOrigins}\nsessionStorage origins: ${sessionStorageOrigins}` }],
|
|
114
|
+
details: { path: filePath, cookieCount, localStorageOrigins, sessionStorageOrigins, savedAt: combined.savedAt, savedUrl: combined.url },
|
|
115
|
+
};
|
|
116
|
+
}
|
|
180
117
|
}
|
|
@@ -463,7 +463,7 @@ export function formatVersionedRef(version, key) {
|
|
|
463
463
|
return `@v${version}:${key}`;
|
|
464
464
|
}
|
|
465
465
|
export function staleRefGuidance(refDisplay, reason) {
|
|
466
|
-
return `Ref ${refDisplay} could not be resolved (${reason}). The ref is likely stale after DOM/navigation changes. Call
|
|
466
|
+
return `Ref ${refDisplay} could not be resolved (${reason}). The ref is likely stale after DOM/navigation changes. Call browser_ref with action='snapshot' to refresh refs.`;
|
|
467
467
|
}
|
|
468
468
|
// ---------------------------------------------------------------------------
|
|
469
469
|
// Compact state summary formatting
|
|
@@ -18,6 +18,7 @@ const IS_MEMORY_MAINTENANCE_WORKER = process.env.LSD_MEMORY_EXTRACT === "1" || p
|
|
|
18
18
|
const IS_CACHE_TIMER_FORCED_OFF = process.env.LSD_DISABLE_CACHE_TIMER === "1" || process.env.GSD_DISABLE_CACHE_TIMER === "1";
|
|
19
19
|
// ANSI color codes for timer display
|
|
20
20
|
const ANSI_RESET = "\x1b[0m";
|
|
21
|
+
const ANSI_GREEN = "\x1b[32m";
|
|
21
22
|
const ANSI_YELLOW = "\x1b[33m";
|
|
22
23
|
const ANSI_RED = "\x1b[31m";
|
|
23
24
|
function getSettingsPath() {
|
|
@@ -63,8 +64,8 @@ function formatElapsed(ms) {
|
|
|
63
64
|
// 5–10 minutes: yellow
|
|
64
65
|
return `${ANSI_YELLOW}⏱ ${time}${ANSI_RESET}`;
|
|
65
66
|
}
|
|
66
|
-
// Under 5 minutes:
|
|
67
|
-
return
|
|
67
|
+
// Under 5 minutes: green
|
|
68
|
+
return `${ANSI_GREEN}⏱ ${time}${ANSI_RESET}`;
|
|
68
69
|
}
|
|
69
70
|
export default function cacheTimerExtension(pi) {
|
|
70
71
|
if (IS_MEMORY_MAINTENANCE_WORKER || IS_CACHE_TIMER_FORCED_OFF) {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"id": "slash-commands",
|
|
3
3
|
"name": "Slash Commands",
|
|
4
4
|
"version": "1.0.0",
|
|
5
|
-
"description": "Bundled slash commands for context inspection, planning, and lazy tool search",
|
|
5
|
+
"description": "Bundled slash commands for context inspection, planning, fast mode, and lazy tool search",
|
|
6
6
|
"tier": "bundled",
|
|
7
7
|
"requires": { "platform": ">=2.29.0" },
|
|
8
8
|
"provides": {
|
|
9
|
-
"commands": ["audit", "clear", "context", "plan", "execute", "cancel-plan", "tools"],
|
|
9
|
+
"commands": ["audit", "clear", "context", "fast", "plan", "execute", "cancel-plan", "tools"],
|
|
10
10
|
"tools": ["tool_search", "tool_enable"],
|
|
11
11
|
"flags": ["plan"]
|
|
12
12
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { getAgentDir, SettingsManager } from "@gsd/pi-coding-agent";
|
|
2
|
+
function parseFastCommandAction(args) {
|
|
3
|
+
const normalized = args.trim().toLowerCase();
|
|
4
|
+
if (!normalized)
|
|
5
|
+
return "toggle";
|
|
6
|
+
if (normalized === "on")
|
|
7
|
+
return "on";
|
|
8
|
+
if (normalized === "off")
|
|
9
|
+
return "off";
|
|
10
|
+
if (normalized === "status")
|
|
11
|
+
return "status";
|
|
12
|
+
return "invalid";
|
|
13
|
+
}
|
|
14
|
+
function supportsFastMode(model) {
|
|
15
|
+
if (!model)
|
|
16
|
+
return false;
|
|
17
|
+
if (model.api === "openai-codex-responses")
|
|
18
|
+
return true;
|
|
19
|
+
if (model.api !== "openai-responses")
|
|
20
|
+
return false;
|
|
21
|
+
if (model.provider !== "openai")
|
|
22
|
+
return false;
|
|
23
|
+
return model.capabilities?.supportsServiceTier === true;
|
|
24
|
+
}
|
|
25
|
+
function getModelLabel(model) {
|
|
26
|
+
if (!model)
|
|
27
|
+
return "no active model";
|
|
28
|
+
return `${model.provider}/${model.id}`;
|
|
29
|
+
}
|
|
30
|
+
function getSettingsManager() {
|
|
31
|
+
return SettingsManager.create(process.cwd(), getAgentDir());
|
|
32
|
+
}
|
|
33
|
+
export const __testing = {
|
|
34
|
+
parseFastCommandAction,
|
|
35
|
+
supportsFastMode,
|
|
36
|
+
};
|
|
37
|
+
export default function fastCommand(pi) {
|
|
38
|
+
pi.registerCommand("fast", {
|
|
39
|
+
description: "Toggle fast mode for OpenAI/Codex models (service_tier=priority)",
|
|
40
|
+
getArgumentCompletions(prefix) {
|
|
41
|
+
const options = [
|
|
42
|
+
{ value: "on", label: "on", description: "Enable fast mode" },
|
|
43
|
+
{ value: "off", label: "off", description: "Disable fast mode" },
|
|
44
|
+
{ value: "status", label: "status", description: "Show current fast-mode status" },
|
|
45
|
+
];
|
|
46
|
+
const query = prefix.trim().toLowerCase();
|
|
47
|
+
return options.filter((item) => item.value.startsWith(query));
|
|
48
|
+
},
|
|
49
|
+
async handler(args, ctx) {
|
|
50
|
+
const settings = getSettingsManager();
|
|
51
|
+
const current = settings.getFastMode();
|
|
52
|
+
const action = parseFastCommandAction(args);
|
|
53
|
+
const model = ctx.model;
|
|
54
|
+
const supported = supportsFastMode(model);
|
|
55
|
+
const modelLabel = getModelLabel(model);
|
|
56
|
+
if (action === "invalid") {
|
|
57
|
+
ctx.ui.notify("Usage: /fast [on|off|status]", "warning");
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (action === "status") {
|
|
61
|
+
ctx.ui.notify(`Fast mode: ${current ? "ON" : "OFF"} · model ${modelLabel} is ${supported ? "supported" : "unsupported"}`, "info");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const next = action === "toggle" ? !current : action === "on";
|
|
65
|
+
settings.setFastMode(next);
|
|
66
|
+
if (!supported) {
|
|
67
|
+
ctx.ui.notify(`Fast mode: ${next ? "ON" : "OFF"} (saved). Current model ${modelLabel} does not support fast mode.`, "warning");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
ctx.ui.notify(`Fast mode: ${next ? "ON" : "OFF"} (saved). ${next ? "Requests will include service_tier=priority." : "Requests will omit service_tier."}`, "info");
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import auditCommand from "./audit.js";
|
|
2
2
|
import clearCommand from "./clear.js";
|
|
3
3
|
import contextCommand from "./context.js";
|
|
4
|
+
import fastCommand from "./fast.js";
|
|
4
5
|
import initCommand from "./init.js";
|
|
5
6
|
import planCommand from "./plan.js";
|
|
6
7
|
import toolSearchExtension from "./tools.js";
|
|
@@ -8,6 +9,7 @@ export default function slashCommands(pi) {
|
|
|
8
9
|
auditCommand(pi);
|
|
9
10
|
clearCommand(pi);
|
|
10
11
|
contextCommand(pi);
|
|
12
|
+
fastCommand(pi);
|
|
11
13
|
initCommand(pi);
|
|
12
14
|
planCommand(pi);
|
|
13
15
|
toolSearchExtension(pi);
|
|
@@ -28,9 +28,8 @@ const BLOCKED_TOOLS = new Set([
|
|
|
28
28
|
"async_bash",
|
|
29
29
|
"bg_shell",
|
|
30
30
|
"browser_navigate",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"browser_reload",
|
|
31
|
+
"browser_pages",
|
|
32
|
+
"browser_frames",
|
|
34
33
|
"browser_click",
|
|
35
34
|
"browser_drag",
|
|
36
35
|
"browser_type",
|
|
@@ -41,18 +40,13 @@ const BLOCKED_TOOLS = new Set([
|
|
|
41
40
|
"browser_select_option",
|
|
42
41
|
"browser_set_checked",
|
|
43
42
|
"browser_set_viewport",
|
|
44
|
-
"
|
|
45
|
-
"browser_hover_ref",
|
|
46
|
-
"browser_fill_ref",
|
|
43
|
+
"browser_ref",
|
|
47
44
|
"browser_act",
|
|
48
45
|
"browser_batch",
|
|
49
46
|
"browser_fill_form",
|
|
50
|
-
"
|
|
51
|
-
"browser_block_urls",
|
|
52
|
-
"browser_clear_routes",
|
|
47
|
+
"browser_network",
|
|
53
48
|
"browser_emulate_device",
|
|
54
|
-
"
|
|
55
|
-
"browser_restore_state",
|
|
49
|
+
"browser_state",
|
|
56
50
|
"browser_generate_test",
|
|
57
51
|
"browser_verify",
|
|
58
52
|
"write",
|
|
@@ -70,6 +64,7 @@ const REVISE_LABEL = "Revise plan";
|
|
|
70
64
|
const CANCEL_LABEL = "Cancel";
|
|
71
65
|
const DEFAULT_PLAN_REVIEW_AGENT = "generic";
|
|
72
66
|
const DEFAULT_PLAN_CODING_AGENT = "worker";
|
|
67
|
+
const MIN_PLAN_CONFIDENCE = 8;
|
|
73
68
|
const INITIAL_STATE = {
|
|
74
69
|
active: false,
|
|
75
70
|
task: "",
|
|
@@ -366,6 +361,9 @@ function buildPlanModeSystemPrompt() {
|
|
|
366
361
|
"You are currently in plan mode.",
|
|
367
362
|
"Investigate, clarify scope, and produce a persisted execution plan before making source changes.",
|
|
368
363
|
"If requirements are ambiguous or constraints are missing, ask concise clarifying questions before drafting or saving a plan.",
|
|
364
|
+
`Before writing or updating a plan artifact, make sure your confidence is at least ${MIN_PLAN_CONFIDENCE}/10. If confidence is lower, investigate more or ask clarifying questions first.`,
|
|
365
|
+
"Include an explicit confidence line in every saved plan, for example: \"Confidence: 8/10\" or higher.",
|
|
366
|
+
"When adjusting an existing saved plan, prefer the edit tool for targeted changes. Rewrite the whole file only when the structure changes substantially or an exact edit is impractical.",
|
|
369
367
|
"Do not modify source files or run side-effect commands while plan mode is active.",
|
|
370
368
|
"Persist plan artifacts under .lsd/plan/.",
|
|
371
369
|
];
|
|
@@ -400,7 +398,7 @@ function buildApprovalActionInstructions() {
|
|
|
400
398
|
const newSessionLabel = buildNewSessionOptionLabel();
|
|
401
399
|
return [
|
|
402
400
|
"Ask for plan approval now via exactly one ask_user_questions tool call.",
|
|
403
|
-
`Question 1 (single-select) id \"${PLAN_APPROVAL_ACTION_QUESTION_ID}\": ask what to do next with the plan.`,
|
|
401
|
+
`Question 1 (single-select) id \"${PLAN_APPROVAL_ACTION_QUESTION_ID}\": ask what to do next with the plan. In the question text, tell the user that if they choose \"${REVISE_LABEL}\" they should type exact requested changes in the dialog notes field before submitting.`,
|
|
404
402
|
`Question 1 options: ${APPROVE_LABEL}, ${REVIEW_LABEL}, ${REVISE_LABEL}. Put "${APPROVE_LABEL}" first with a "(Recommended)" suffix in the description, not in the label.`,
|
|
405
403
|
`Do not include \"${CANCEL_LABEL}\" as an explicit option — if the user wants to cancel they should choose \"None of the above\" and type \"${CANCEL_LABEL}\" in the note.`,
|
|
406
404
|
`Question 2 (single-select) id \"${PLAN_APPROVAL_PERMISSION_QUESTION_ID}\": ask which execution mode to use.`,
|
|
@@ -454,6 +452,23 @@ function buildReviewSteeringMessage(planPath, planMarkdown) {
|
|
|
454
452
|
details.push("After the subagent responds, summarize its feedback for the user, present the current plan again, and then ask for approval again.", buildApprovalActionInstructions());
|
|
455
453
|
return details.join("\n\n");
|
|
456
454
|
}
|
|
455
|
+
function buildRevisionSteeringMessage(planPath, requestedChanges) {
|
|
456
|
+
const details = [
|
|
457
|
+
`The user selected \"${REVISE_LABEL}\" for ${planPath}.`,
|
|
458
|
+
"Revise the existing saved plan instead of drafting a fresh replacement unless a full rewrite is genuinely necessary.",
|
|
459
|
+
"Prefer the edit tool for targeted adjustments to the current plan artifact. Use write only if the structure changes substantially or an exact edit is impractical.",
|
|
460
|
+
`Before saving the revised plan, make sure confidence is at least ${MIN_PLAN_CONFIDENCE}/10. If lower, investigate more or ask clarifying questions first.`,
|
|
461
|
+
"Keep an explicit confidence line in the plan, for example: \"Confidence: 8/10\" or higher.",
|
|
462
|
+
];
|
|
463
|
+
if (requestedChanges) {
|
|
464
|
+
details.push(`User-requested changes: ${requestedChanges}`);
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
details.push("No concrete revision note was provided yet. Ask one concise clarifying question about what should change before editing the plan.");
|
|
468
|
+
}
|
|
469
|
+
details.push("After revising the saved plan artifact, ask for approval again.");
|
|
470
|
+
return details.join("\n\n");
|
|
471
|
+
}
|
|
457
472
|
function approvalSelectionToExecutionMode(selected) {
|
|
458
473
|
if (!selected)
|
|
459
474
|
return undefined;
|
|
@@ -482,6 +497,12 @@ function getAnswerValues(answer) {
|
|
|
482
497
|
}
|
|
483
498
|
return values;
|
|
484
499
|
}
|
|
500
|
+
function getAnswerNote(answer) {
|
|
501
|
+
if (typeof answer?.notes !== "string")
|
|
502
|
+
return undefined;
|
|
503
|
+
const note = answer.notes.trim();
|
|
504
|
+
return note.length > 0 ? note : undefined;
|
|
505
|
+
}
|
|
485
506
|
function selectionRequestsCancel(selected) {
|
|
486
507
|
return selected.some((value) => {
|
|
487
508
|
if (typeof value !== "string")
|
|
@@ -506,6 +527,8 @@ export const __testing = {
|
|
|
506
527
|
buildApprovalSteeringMessage,
|
|
507
528
|
buildPlanPreviewMessage,
|
|
508
529
|
buildReviewSteeringMessage,
|
|
530
|
+
buildRevisionSteeringMessage,
|
|
531
|
+
buildPlanModeSystemPrompt,
|
|
509
532
|
buildAutoSuggestPlanModeSystemPrompt,
|
|
510
533
|
readAutoSuggestPlanModeSetting,
|
|
511
534
|
PLAN_SUGGEST_QUESTION_ID,
|
|
@@ -696,9 +719,11 @@ export default function planCommand(pi) {
|
|
|
696
719
|
return;
|
|
697
720
|
}
|
|
698
721
|
if (actionSelection.includes(REVISE_LABEL)) {
|
|
722
|
+
const requestedChanges = getAnswerNote(actionAnswer);
|
|
699
723
|
enablePlanMode(pi, ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined, {
|
|
700
724
|
approvalStatus: "revising",
|
|
701
725
|
});
|
|
726
|
+
pi.sendUserMessage(buildRevisionSteeringMessage(state.latestPlanPath ?? "the latest plan", requestedChanges), { deliverAs: "steer" });
|
|
702
727
|
}
|
|
703
728
|
});
|
|
704
729
|
pi.registerCommand("plan", {
|
|
@@ -38,6 +38,19 @@ export class BackgroundJobManager {
|
|
|
38
38
|
adoptRunning(agentName, task, cwd, abortController, resultPromise, metadata) {
|
|
39
39
|
return this.attachJob(agentName, task, cwd, abortController, resultPromise, metadata);
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Adopt an in-process subagent handle into background tracking.
|
|
43
|
+
*/
|
|
44
|
+
adoptHandle(agentName, task, cwd, handle, resultPromise, metadata) {
|
|
45
|
+
const abortController = new AbortController();
|
|
46
|
+
const onAbort = () => handle.abort();
|
|
47
|
+
abortController.signal.addEventListener("abort", onAbort, { once: true });
|
|
48
|
+
const wrapped = resultPromise.finally(() => {
|
|
49
|
+
abortController.signal.removeEventListener("abort", onAbort);
|
|
50
|
+
handle.dispose();
|
|
51
|
+
});
|
|
52
|
+
return this.attachJob(agentName, task, cwd, abortController, wrapped, metadata);
|
|
53
|
+
}
|
|
41
54
|
/**
|
|
42
55
|
* Cancel a running job.
|
|
43
56
|
*/
|