@code-yeongyu/senpi 2026.8.29 → 2026.8.30
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/CHANGELOG.md +66 -0
- package/dist/core/agent-session.d.ts +45 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +312 -25
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +155 -37
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/credential-accounts.d.ts.map +1 -1
- package/dist/core/credential-accounts.js +23 -9
- package/dist/core/credential-accounts.js.map +1 -1
- package/dist/core/credential-pool/env-slots.d.ts.map +1 -1
- package/dist/core/credential-pool/env-slots.js +2 -0
- package/dist/core/credential-pool/env-slots.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts +8 -2
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.js +160 -47
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/retained-message-safety.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/retained-message-safety.js +31 -8
- package/dist/core/extensions/builtin/compaction/retained-message-safety.js.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/stream.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/stream.js +8 -28
- package/dist/core/extensions/builtin/cursor-cli-oauth/stream.js.map +1 -1
- package/dist/core/extensions/builtin/permission-system/external-dir.d.ts.map +1 -1
- package/dist/core/extensions/builtin/permission-system/external-dir.js +15 -5
- package/dist/core/extensions/builtin/permission-system/external-dir.js.map +1 -1
- package/dist/core/extensions/builtin/permission-system/parsers.d.ts.map +1 -1
- package/dist/core/extensions/builtin/permission-system/parsers.js +16 -1
- package/dist/core/extensions/builtin/permission-system/parsers.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/manager.d.ts +5 -0
- package/dist/core/extensions/builtin/terminal/manager.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/manager.js +31 -3
- package/dist/core/extensions/builtin/terminal/manager.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-permission.d.ts +8 -0
- package/dist/core/extensions/builtin/terminal/monitor-permission.d.ts.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-permission.js +16 -0
- package/dist/core/extensions/builtin/terminal/monitor-permission.js.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts +13 -0
- package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-registry.js +403 -3
- package/dist/core/extensions/builtin/terminal/monitor-registry.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/session-bundle.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/session-bundle.js +1 -0
- package/dist/core/extensions/builtin/terminal/session-bundle.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/kill-bash.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/kill-bash.js +5 -2
- package/dist/core/extensions/builtin/terminal/tools/kill-bash.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/monitor.d.ts +4 -0
- package/dist/core/extensions/builtin/terminal/tools/monitor.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/monitor.js +40 -2
- package/dist/core/extensions/builtin/terminal/tools/monitor.js.map +1 -1
- package/dist/core/model-resolver.js +2 -2
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +10 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +7 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +6 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +97 -15
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +8 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts +1 -1
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +76 -34
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +7 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +34 -8
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/grok/chrome.d.ts +2 -0
- package/dist/modes/interactive/grok/chrome.d.ts.map +1 -1
- package/dist/modes/interactive/grok/chrome.js.map +1 -1
- package/dist/modes/interactive/interactive-host-runtime.d.ts +51 -1
- package/dist/modes/interactive/interactive-host-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-host-runtime.js +235 -20
- package/dist/modes/interactive/interactive-host-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +7 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +114 -2
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/connection-handler.d.ts +8 -1
- package/dist/modes/rpc/connection-handler.d.ts.map +1 -1
- package/dist/modes/rpc/connection-handler.js +145 -49
- package/dist/modes/rpc/connection-handler.js.map +1 -1
- package/dist/modes/rpc/host-ensure.d.ts +2 -0
- package/dist/modes/rpc/host-ensure.d.ts.map +1 -1
- package/dist/modes/rpc/host-ensure.js +15 -2
- package/dist/modes/rpc/host-ensure.js.map +1 -1
- package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
- package/dist/modes/rpc/host-lifecycle.js +31 -12
- package/dist/modes/rpc/host-lifecycle.js.map +1 -1
- package/dist/modes/rpc/host-watchdog.d.ts +2 -0
- package/dist/modes/rpc/host-watchdog.d.ts.map +1 -1
- package/dist/modes/rpc/host-watchdog.js +23 -12
- package/dist/modes/rpc/host-watchdog.js.map +1 -1
- package/dist/modes/rpc/multi-session-host.js +6 -4
- package/dist/modes/rpc/multi-session-host.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +10 -4
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +45 -10
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-input-validation.d.ts +1 -0
- package/dist/modes/rpc/rpc-input-validation.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-input-validation.js +66 -0
- package/dist/modes/rpc/rpc-input-validation.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +79 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/modes/rpc/session-binding.d.ts +1 -0
- package/dist/modes/rpc/session-binding.d.ts.map +1 -1
- package/dist/modes/rpc/session-binding.js +21 -1
- package/dist/modes/rpc/session-binding.js.map +1 -1
- package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
- package/dist/modes/rpc/session-command-router.js +1 -0
- package/dist/modes/rpc/session-command-router.js.map +1 -1
- package/dist/modes/rpc/session-event-writer.d.ts +2 -0
- package/dist/modes/rpc/session-event-writer.d.ts.map +1 -1
- package/dist/modes/rpc/session-event-writer.js +54 -7
- package/dist/modes/rpc/session-event-writer.js.map +1 -1
- package/dist/modes/rpc/session-extension-ui-requests.d.ts +1 -0
- package/dist/modes/rpc/session-extension-ui-requests.d.ts.map +1 -1
- package/dist/modes/rpc/session-extension-ui-requests.js +5 -0
- package/dist/modes/rpc/session-extension-ui-requests.js.map +1 -1
- package/dist/modes/rpc/session-registry.d.ts +10 -2
- package/dist/modes/rpc/session-registry.d.ts.map +1 -1
- package/dist/modes/rpc/session-registry.js +58 -4
- package/dist/modes/rpc/session-registry.js.map +1 -1
- package/dist/modes/rpc/socket-event-fanout.d.ts +22 -0
- package/dist/modes/rpc/socket-event-fanout.d.ts.map +1 -0
- package/dist/modes/rpc/socket-event-fanout.js +84 -0
- package/dist/modes/rpc/socket-event-fanout.js.map +1 -0
- package/docs/rpc.md +3 -1
- package/docs/settings.md +34 -0
- package/docs/windows.md +2 -0
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +38 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-indirect-eval.js +139 -90
- package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt.ts +4 -4
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/env/nodejs.js +40 -20
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts +3 -3
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/shell-output.d.ts +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/shell-output.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/shell-output.js +28 -9
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/shell-output.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +58 -31
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.d.ts +20 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.js +443 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-workers-ai.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/together.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai-coding-cn.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai.json +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts +7 -0
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +5 -0
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/mux.d.ts +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/mux.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/mux.js +2 -2
- package/node_modules/@earendil-works/pi-tui/dist/mux.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts +1 -0
- package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js +19 -0
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { rm } from "node:fs/promises";
|
|
1
3
|
import { executeBashWithOperations } from "../../core/bash-executor.js";
|
|
2
4
|
import { SessionManager } from "../../core/session-manager.js";
|
|
3
5
|
import { SettingsManager } from "../../core/settings-manager.js";
|
|
@@ -27,6 +29,14 @@ export async function createInteractiveHostRuntime(localRuntime, options) {
|
|
|
27
29
|
thinkingLevel: localRuntime.session.thinkingLevel,
|
|
28
30
|
});
|
|
29
31
|
const remoteSession = createRemoteSessionProxy(localRuntime.session, localRuntime.services.agentDir, client, opened.state, options.onWarning);
|
|
32
|
+
if (opened.state.isBashRunning && !opened.attached) {
|
|
33
|
+
// Only a newly opened session can have an execution orphaned by a
|
|
34
|
+
// previous connection. An attach is an observer of the same live runtime;
|
|
35
|
+
// aborting it would cancel work owned by the surviving attachment.
|
|
36
|
+
await client.abortBash().catch(() => { });
|
|
37
|
+
}
|
|
38
|
+
if (opened.attached)
|
|
39
|
+
await remoteSession.refresh();
|
|
30
40
|
return new RemoteInteractiveRuntime(localRuntime, remoteSession, client);
|
|
31
41
|
}
|
|
32
42
|
catch (cause) {
|
|
@@ -39,7 +49,7 @@ export async function createInteractiveHostRuntime(localRuntime, options) {
|
|
|
39
49
|
return localRuntime;
|
|
40
50
|
}
|
|
41
51
|
}
|
|
42
|
-
class RemoteInteractiveRuntime {
|
|
52
|
+
export class RemoteInteractiveRuntime {
|
|
43
53
|
#local;
|
|
44
54
|
#remoteSession;
|
|
45
55
|
#client;
|
|
@@ -74,10 +84,26 @@ class RemoteInteractiveRuntime {
|
|
|
74
84
|
setRebindSession(callback) {
|
|
75
85
|
this.#rebindSession = callback;
|
|
76
86
|
}
|
|
87
|
+
setHostUiHandler(callback) {
|
|
88
|
+
this.#remoteSession.setHostUiHandler(callback);
|
|
89
|
+
}
|
|
77
90
|
async dispose() {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
91
|
+
const errors = [];
|
|
92
|
+
for (const cleanup of [
|
|
93
|
+
() => this.#remoteSession.abortLocalBash?.(),
|
|
94
|
+
() => this.#client.closeSession(),
|
|
95
|
+
() => this.#client.stop(),
|
|
96
|
+
() => this.#local.dispose(),
|
|
97
|
+
]) {
|
|
98
|
+
try {
|
|
99
|
+
await cleanup();
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
errors.push(error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (errors.length > 0)
|
|
106
|
+
throw errors[0];
|
|
81
107
|
}
|
|
82
108
|
async newSession(options) {
|
|
83
109
|
const result = await this.#client.newSession(options?.parentSession);
|
|
@@ -99,7 +125,7 @@ class RemoteInteractiveRuntime {
|
|
|
99
125
|
return result;
|
|
100
126
|
}
|
|
101
127
|
async switchSession(sessionPath, options) {
|
|
102
|
-
const result = await this.#client.switchSession(sessionPath, options);
|
|
128
|
+
const result = await this.#client.switchSession(sessionPath, options?.cwdOverride === undefined ? undefined : { cwdOverride: options.cwdOverride });
|
|
103
129
|
if (!result.cancelled) {
|
|
104
130
|
this.#beforeSessionInvalidate?.();
|
|
105
131
|
this.#remoteSession.abortLocalBash();
|
|
@@ -150,10 +176,65 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
150
176
|
});
|
|
151
177
|
};
|
|
152
178
|
let state = { ...initialState };
|
|
153
|
-
|
|
179
|
+
const waitForBashCallbacks = async (promises, allowAbandonment) => {
|
|
180
|
+
if (promises.size === 0)
|
|
181
|
+
return true;
|
|
182
|
+
const settled = Promise.allSettled([...promises]).then(() => true);
|
|
183
|
+
let timeout;
|
|
184
|
+
const bounded = new Promise((resolve) => {
|
|
185
|
+
timeout = setTimeout(resolve, allowAbandonment ? 100 : 5_000, false);
|
|
186
|
+
timeout.unref?.();
|
|
187
|
+
});
|
|
188
|
+
try {
|
|
189
|
+
return await Promise.race([settled, bounded]);
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
if (timeout)
|
|
193
|
+
clearTimeout(timeout);
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
const executionNamespace = randomUUID();
|
|
197
|
+
const cleanupRemoteBashOutput = async (path) => {
|
|
198
|
+
let cleanupTimeout;
|
|
199
|
+
try {
|
|
200
|
+
await Promise.race([
|
|
201
|
+
client.cleanupBashOutput(path),
|
|
202
|
+
new Promise((_, reject) => {
|
|
203
|
+
cleanupTimeout = setTimeout(() => reject(new Error("RPC cleanup timed out")), 1_000);
|
|
204
|
+
}),
|
|
205
|
+
]);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
catch (transportError) {
|
|
209
|
+
// Spill paths are shared host filesystem paths. If the RPC transport is
|
|
210
|
+
// already unavailable, remove locally as a bounded best-effort fallback;
|
|
211
|
+
// a later reconnect is not required to prevent this callback failure from
|
|
212
|
+
// permanently leaking the host-owned artifact.
|
|
213
|
+
try {
|
|
214
|
+
await rm(path, { force: true });
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
catch (localError) {
|
|
218
|
+
onWarning?.({
|
|
219
|
+
type: "interactive_host_action_failed",
|
|
220
|
+
message: `Warning: failed to clean up shared bash output spill: ${localError instanceof Error ? localError.message : String(localError)}`,
|
|
221
|
+
cause: new AggregateError([transportError, localError]),
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
finally {
|
|
226
|
+
if (cleanupTimeout)
|
|
227
|
+
clearTimeout(cleanupTimeout);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
let nextBashExecutionId = 0;
|
|
231
|
+
const bashExecutions = new Map();
|
|
232
|
+
let hostUiHandler;
|
|
233
|
+
const pendingUiRequests = [];
|
|
154
234
|
let localBashAbortController;
|
|
155
235
|
let localBashRunning = false;
|
|
156
236
|
let hostBashRunning = initialState.isBashRunning;
|
|
237
|
+
let nextQueuedInputOrder = Math.max(0, ...initialState.ordered.map((item) => item.enqueueOrder));
|
|
157
238
|
let sessionManager = local.sessionManager;
|
|
158
239
|
let settingsManager = SettingsManager.create(initialState.cwd, agentDir, {
|
|
159
240
|
projectTrusted: initialState.projectTrusted,
|
|
@@ -166,6 +247,8 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
166
247
|
if (property === "appendLabelChange") {
|
|
167
248
|
return (entryId, label) => void client.setLabel(entryId, label);
|
|
168
249
|
}
|
|
250
|
+
if (property === "getCwd")
|
|
251
|
+
return () => state.cwd;
|
|
169
252
|
if (property === "getSessionName")
|
|
170
253
|
return () => state.sessionName;
|
|
171
254
|
if (property === "getUsageTotals")
|
|
@@ -178,6 +261,14 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
178
261
|
let mirroredCurrentAssistantUsage = false;
|
|
179
262
|
const listeners = new Set();
|
|
180
263
|
client.onEvent((wireEvent) => {
|
|
264
|
+
if (wireEvent.type === "extension_ui_request") {
|
|
265
|
+
const request = wireEvent;
|
|
266
|
+
if (hostUiHandler)
|
|
267
|
+
void Promise.resolve(hostUiHandler(request)).then((response) => response && client.sendExtensionUIResponse(response));
|
|
268
|
+
else
|
|
269
|
+
pendingUiRequests.push(request);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
181
272
|
if (wireEvent.type === "agent_settled")
|
|
182
273
|
state = { ...state, isStreaming: false, retryAttempt: 0 };
|
|
183
274
|
if (wireEvent.type === "bash_start") {
|
|
@@ -188,8 +279,30 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
188
279
|
hostBashRunning = false;
|
|
189
280
|
updateBashState();
|
|
190
281
|
}
|
|
191
|
-
if (wireEvent.type === "bash_execution_update")
|
|
192
|
-
|
|
282
|
+
if (wireEvent.type === "bash_execution_update" && wireEvent.id) {
|
|
283
|
+
const execution = bashExecutions.get(wireEvent.id);
|
|
284
|
+
if (execution?.chunk && !execution.hasError) {
|
|
285
|
+
try {
|
|
286
|
+
const callbackPromise = Promise.resolve(execution.chunk(wireEvent.delta)).catch((error) => {
|
|
287
|
+
if (!execution.hasError) {
|
|
288
|
+
execution.error = error;
|
|
289
|
+
execution.hasError = true;
|
|
290
|
+
void client.abortBash().catch(() => { });
|
|
291
|
+
}
|
|
292
|
+
throw error;
|
|
293
|
+
});
|
|
294
|
+
execution.promises.add(callbackPromise);
|
|
295
|
+
void callbackPromise.catch(() => { }).finally(() => execution.promises.delete(callbackPromise));
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
if (!execution.hasError) {
|
|
299
|
+
execution.error = error;
|
|
300
|
+
execution.hasError = true;
|
|
301
|
+
void client.abortBash().catch(() => { });
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
193
306
|
if (wireEvent.type === "agent_start")
|
|
194
307
|
state = { ...state, isStreaming: true };
|
|
195
308
|
if (wireEvent.type === "compaction_start")
|
|
@@ -201,6 +314,7 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
201
314
|
if (wireEvent.type === "auto_retry_end")
|
|
202
315
|
state = { ...state, retryAttempt: 0 };
|
|
203
316
|
if (wireEvent.type === "queue_update") {
|
|
317
|
+
nextQueuedInputOrder = Math.max(nextQueuedInputOrder, ...wireEvent.ordered.map((item) => item.enqueueOrder));
|
|
204
318
|
state = {
|
|
205
319
|
...state,
|
|
206
320
|
steering: [...wireEvent.steering],
|
|
@@ -217,6 +331,23 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
217
331
|
if (wireEvent.type === "service_tier_changed") {
|
|
218
332
|
state = { ...state, serviceTier: wireEvent.tier, fastMode: wireEvent.fastMode };
|
|
219
333
|
}
|
|
334
|
+
if (wireEvent.type === "session_settings_changed") {
|
|
335
|
+
state = {
|
|
336
|
+
...state,
|
|
337
|
+
steeringMode: wireEvent.steeringMode,
|
|
338
|
+
followUpMode: wireEvent.followUpMode,
|
|
339
|
+
autoCompactionEnabled: wireEvent.autoCompactionEnabled,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
if (wireEvent.type === "entry_appended") {
|
|
343
|
+
try {
|
|
344
|
+
sessionManager.appendEntry(wireEvent.entry);
|
|
345
|
+
local.agent.state.messages = sessionManager.buildSessionContext().messages;
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
// Non-fatal if the local snapshot cannot accept a concurrent entry.
|
|
349
|
+
}
|
|
350
|
+
}
|
|
220
351
|
if (wireEvent.type === "session_info_changed")
|
|
221
352
|
state = { ...state, sessionName: wireEvent.name };
|
|
222
353
|
if (wireEvent.type === "message_start") {
|
|
@@ -233,8 +364,13 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
233
364
|
if (usage && !mirroredCurrentAssistantUsage) {
|
|
234
365
|
mirroredCurrentAssistantUsage = true;
|
|
235
366
|
const latestPromptTokens = usage.input + usage.cacheRead + usage.cacheWrite;
|
|
367
|
+
const contextWindow = state.model?.contextWindow ?? 0;
|
|
368
|
+
const contextTokens = usage.input + usage.cacheRead + usage.cacheWrite;
|
|
236
369
|
state = {
|
|
237
370
|
...state,
|
|
371
|
+
contextUsage: contextWindow > 0
|
|
372
|
+
? { tokens: contextTokens, contextWindow, percent: (contextTokens / contextWindow) * 100 }
|
|
373
|
+
: undefined,
|
|
238
374
|
usageTotals: {
|
|
239
375
|
...state.usageTotals,
|
|
240
376
|
input: state.usageTotals.input + usage.input,
|
|
@@ -254,7 +390,9 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
254
390
|
}
|
|
255
391
|
if (wireEvent.type === "compaction_end" && wireEvent.accepted && !wireEvent.aborted) {
|
|
256
392
|
try {
|
|
257
|
-
sessionManager.reloadFromDisk?.();
|
|
393
|
+
local.sessionManager.reloadFromDisk?.();
|
|
394
|
+
if (sessionManager !== local.sessionManager)
|
|
395
|
+
sessionManager.reloadFromDisk?.();
|
|
258
396
|
local.agent.state.messages = sessionManager.buildSessionContext().messages;
|
|
259
397
|
}
|
|
260
398
|
catch {
|
|
@@ -268,14 +406,23 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
268
406
|
const refresh = async () => {
|
|
269
407
|
const nextState = await client.getState();
|
|
270
408
|
state = { ...stateFromRpc(nextState) };
|
|
409
|
+
nextQueuedInputOrder = Math.max(0, ...nextState.ordered.map((item) => item.enqueueOrder));
|
|
271
410
|
let messages;
|
|
272
411
|
settingsManager = SettingsManager.create(nextState.cwd, agentDir, {
|
|
273
412
|
projectTrusted: nextState.projectTrusted,
|
|
274
413
|
});
|
|
275
414
|
if (nextState.sessionFile) {
|
|
276
|
-
//
|
|
277
|
-
//
|
|
278
|
-
|
|
415
|
+
// Keep the caller-owned manager identity when refreshing the same session.
|
|
416
|
+
// Navigation and host-side mutations must update every existing mirror, not
|
|
417
|
+
// leave the interactive runtime holding the pre-refresh snapshot.
|
|
418
|
+
if (sessionManager.getSessionFile() === nextState.sessionFile) {
|
|
419
|
+
sessionManager.reloadFromDisk?.();
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
// SessionManager.open retains the explicit path even when the host has
|
|
423
|
+
// deferred creating the file for a setup-only session.
|
|
424
|
+
sessionManager = SessionManager.open(nextState.sessionFile, undefined, nextState.cwd);
|
|
425
|
+
}
|
|
279
426
|
if (nextState.entries?.length && !sessionManager.getEntries().length) {
|
|
280
427
|
for (const entry of nextState.entries)
|
|
281
428
|
sessionManager.appendEntry(entry);
|
|
@@ -295,6 +442,12 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
295
442
|
...(options?.images ? { images: options.images } : {}),
|
|
296
443
|
...(options?.streamingBehavior ? { streamingBehavior: options.streamingBehavior } : {}),
|
|
297
444
|
...(options?.thinkingLevel ? { thinkingLevel: options.thinkingLevel } : {}),
|
|
445
|
+
...(options?.sessionTitlePrompt !== undefined
|
|
446
|
+
? { sessionTitlePrompt: options.sessionTitlePrompt }
|
|
447
|
+
: {}),
|
|
448
|
+
...(options?.expandPromptTemplates !== undefined
|
|
449
|
+
? { expandPromptTemplates: options.expandPromptTemplates }
|
|
450
|
+
: {}),
|
|
298
451
|
...(options?.promptDisposition ? { promptDisposition: options.promptDisposition } : {}),
|
|
299
452
|
...(options?.preflightResult ? { preflightResult: options.preflightResult } : {}),
|
|
300
453
|
});
|
|
@@ -328,13 +481,35 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
328
481
|
return () => client.waitForIdle();
|
|
329
482
|
if (property === "getLastAssistantText")
|
|
330
483
|
return () => target.getLastAssistantText();
|
|
331
|
-
if (property === "setModel")
|
|
484
|
+
if (property === "setModel" || property === "setSessionModel")
|
|
332
485
|
return async (model) => {
|
|
333
486
|
const next = await client.setModel(model.provider, model.id);
|
|
334
487
|
return { systemPromptName: next.systemPromptName, model: next };
|
|
335
488
|
};
|
|
489
|
+
if (property === "setSessionThinkingLevel")
|
|
490
|
+
return (level) => void client
|
|
491
|
+
.setThinkingLevel(level, { scope: "turn" })
|
|
492
|
+
.catch(reportActionFailure("setSessionThinkingLevel"));
|
|
493
|
+
if (property === "setSessionFastMode")
|
|
494
|
+
return (enabled) => void client.setFastMode(enabled).catch(reportActionFailure("setSessionFastMode"));
|
|
495
|
+
if (property === "abortRetry")
|
|
496
|
+
return () => void client.abortRetry().catch(reportActionFailure("abortRetry"));
|
|
497
|
+
if (property === "setAutoRetryEnabled")
|
|
498
|
+
return (enabled) => void client.setAutoRetry(enabled).catch(reportActionFailure("setAutoRetryEnabled"));
|
|
499
|
+
if (property === "reserveQueuedInputOrder")
|
|
500
|
+
return () => ++nextQueuedInputOrder;
|
|
501
|
+
if (property === "setFavoriteModels")
|
|
502
|
+
return (models) => {
|
|
503
|
+
state = { ...state, favoriteModels: [...models] };
|
|
504
|
+
void client.setFavoriteModels(models).catch(reportActionFailure("setFavoriteModels"));
|
|
505
|
+
};
|
|
506
|
+
if (property === "setScopedModels")
|
|
507
|
+
return (models) => {
|
|
508
|
+
state = { ...state, scopedModels: [...models] };
|
|
509
|
+
void client.setScopedModels(models).catch(reportActionFailure("setScopedModels"));
|
|
510
|
+
};
|
|
336
511
|
if (property === "cycleModel")
|
|
337
|
-
return () => client.cycleModel();
|
|
512
|
+
return (direction) => client.cycleModel(direction);
|
|
338
513
|
if (property === "setThinkingLevel")
|
|
339
514
|
return (level) => void client.setThinkingLevel(level).catch(reportActionFailure("setThinkingLevel"));
|
|
340
515
|
if (property === "cycleThinkingLevel")
|
|
@@ -372,15 +547,35 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
372
547
|
updateBashState();
|
|
373
548
|
}
|
|
374
549
|
}
|
|
375
|
-
|
|
550
|
+
const executionId = `bash-${executionNamespace}-${++nextBashExecutionId}`;
|
|
551
|
+
const execution = {
|
|
552
|
+
chunk: onChunk,
|
|
553
|
+
promises: new Set(),
|
|
554
|
+
error: undefined,
|
|
555
|
+
hasError: false,
|
|
556
|
+
};
|
|
557
|
+
bashExecutions.set(executionId, execution);
|
|
376
558
|
try {
|
|
377
|
-
|
|
559
|
+
const result = await client.bash(command, {
|
|
378
560
|
excludeFromContext: options?.excludeFromContext,
|
|
561
|
+
executionId,
|
|
379
562
|
operations: options?.operations,
|
|
380
563
|
});
|
|
564
|
+
const callbacksSettled = await waitForBashCallbacks(execution.promises, false);
|
|
565
|
+
if (!callbacksSettled) {
|
|
566
|
+
if (result.fullOutputPath)
|
|
567
|
+
await cleanupRemoteBashOutput(result.fullOutputPath);
|
|
568
|
+
throw new Error("Bash output callback did not settle within 5000ms");
|
|
569
|
+
}
|
|
570
|
+
if (execution.hasError) {
|
|
571
|
+
if (result.fullOutputPath)
|
|
572
|
+
await cleanupRemoteBashOutput(result.fullOutputPath);
|
|
573
|
+
throw execution.error;
|
|
574
|
+
}
|
|
575
|
+
return result;
|
|
381
576
|
}
|
|
382
577
|
finally {
|
|
383
|
-
|
|
578
|
+
bashExecutions.delete(executionId);
|
|
384
579
|
}
|
|
385
580
|
};
|
|
386
581
|
if (property === "abortBash")
|
|
@@ -390,10 +585,12 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
390
585
|
else
|
|
391
586
|
void client.abortBash().catch(reportActionFailure("abortBash"));
|
|
392
587
|
};
|
|
588
|
+
if (property === "getContextUsage")
|
|
589
|
+
return () => state.contextUsage;
|
|
393
590
|
if (property === "getSessionStats")
|
|
394
591
|
return () => client.getSessionStats();
|
|
395
592
|
if (property === "exportToHtml")
|
|
396
|
-
return (outputPath) => client.exportHtml(outputPath).then((result) => result.path);
|
|
593
|
+
return (outputPath, options) => client.exportHtml(outputPath, options?.themeName).then((result) => result.path);
|
|
397
594
|
if (property === "setSessionName")
|
|
398
595
|
return (name) => client.setSessionName(name).catch(reportActionFailure("setSessionName"));
|
|
399
596
|
if (property === "navigateTree")
|
|
@@ -416,10 +613,10 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
416
613
|
};
|
|
417
614
|
if (property === "isStreaming")
|
|
418
615
|
return state.isStreaming;
|
|
616
|
+
if (property === "isIdle")
|
|
617
|
+
return !state.isStreaming;
|
|
419
618
|
if (property === "isCompacting")
|
|
420
619
|
return state.isCompacting;
|
|
421
|
-
if (property === "isFastModeActive")
|
|
422
|
-
return () => state.fastMode;
|
|
423
620
|
if (property === "pendingMessageCount")
|
|
424
621
|
return state.pendingMessageCount;
|
|
425
622
|
if (property === "getSteeringMessages")
|
|
@@ -475,12 +672,24 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
475
672
|
return state.sessionName;
|
|
476
673
|
if (property === "serviceTier")
|
|
477
674
|
return state.serviceTier;
|
|
675
|
+
if (property === "steeringMode")
|
|
676
|
+
return state.steeringMode;
|
|
677
|
+
if (property === "followUpMode")
|
|
678
|
+
return state.followUpMode;
|
|
679
|
+
if (property === "autoCompactionEnabled")
|
|
680
|
+
return state.autoCompactionEnabled;
|
|
681
|
+
if (property === "isFastModeActive")
|
|
682
|
+
return () => state.fastMode;
|
|
478
683
|
if (property === "sessionManager")
|
|
479
684
|
return remoteSessionManager;
|
|
480
685
|
if (property === "settingsManager")
|
|
481
686
|
return settingsManager;
|
|
482
687
|
if (property === "messages")
|
|
483
688
|
return target.messages;
|
|
689
|
+
if (property === "favoriteModels")
|
|
690
|
+
return state.favoriteModels;
|
|
691
|
+
if (property === "scopedModels")
|
|
692
|
+
return state.scopedModels;
|
|
484
693
|
if (property === "model")
|
|
485
694
|
return state.model ?? target.model;
|
|
486
695
|
if (property === "thinkingLevel")
|
|
@@ -490,6 +699,12 @@ function createRemoteSessionProxy(local, agentDir, client, initialState, onWarni
|
|
|
490
699
|
});
|
|
491
700
|
return {
|
|
492
701
|
session,
|
|
702
|
+
setHostUiHandler: (callback) => {
|
|
703
|
+
hostUiHandler = callback;
|
|
704
|
+
if (callback)
|
|
705
|
+
for (const request of pendingUiRequests.splice(0))
|
|
706
|
+
void Promise.resolve(callback(request)).then((response) => response && client.sendExtensionUIResponse(response));
|
|
707
|
+
},
|
|
493
708
|
refresh,
|
|
494
709
|
abortLocalBash: () => localBashAbortController?.abort(),
|
|
495
710
|
createReplacedSessionContext: () => {
|