@code-yeongyu/senpi 2026.9.4-3 → 2026.9.5
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 +27 -0
- package/dist/core/agent-session.d.ts +17 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +62 -2
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/model-usability-budget.d.ts +5 -0
- package/dist/core/extensions/builtin/compaction/model-usability-budget.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/model-usability-budget.js +11 -4
- package/dist/core/extensions/builtin/compaction/model-usability-budget.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts +9 -5
- package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js +20 -11
- package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js.map +1 -1
- package/dist/core/extensions/builtin/recommended-models/index.d.ts +1 -1
- package/dist/core/extensions/builtin/recommended-models/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/recommended-models/index.js +1 -0
- package/dist/core/extensions/builtin/recommended-models/index.js.map +1 -1
- package/dist/core/extensions/builtin/service-tier.d.ts.map +1 -1
- package/dist/core/extensions/builtin/service-tier.js +12 -4
- package/dist/core/extensions/builtin/service-tier.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/durable-command.d.ts +31 -0
- package/dist/core/extensions/builtin/terminal/durable-command.d.ts.map +1 -0
- package/dist/core/extensions/builtin/terminal/durable-command.js +96 -0
- package/dist/core/extensions/builtin/terminal/durable-command.js.map +1 -0
- package/dist/core/extensions/builtin/terminal/durable-file.d.ts +42 -0
- package/dist/core/extensions/builtin/terminal/durable-file.d.ts.map +1 -0
- package/dist/core/extensions/builtin/terminal/durable-file.js +102 -0
- package/dist/core/extensions/builtin/terminal/durable-file.js.map +1 -0
- package/dist/core/extensions/builtin/terminal/extension.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/extension.js +58 -13
- package/dist/core/extensions/builtin/terminal/extension.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-notify.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-notify.js +5 -1
- package/dist/core/extensions/builtin/terminal/monitor-notify.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts +29 -0
- package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-registry.js +49 -0
- package/dist/core/extensions/builtin/terminal/monitor-registry.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-status.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-status.js +21 -1
- package/dist/core/extensions/builtin/terminal/monitor-status.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/prompt.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/prompt.js +9 -5
- package/dist/core/extensions/builtin/terminal/prompt.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/restore.d.ts +13 -0
- package/dist/core/extensions/builtin/terminal/restore.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/restore.js +31 -3
- package/dist/core/extensions/builtin/terminal/restore.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/shared.d.ts +25 -0
- package/dist/core/extensions/builtin/terminal/shared.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/shared.js +25 -0
- package/dist/core/extensions/builtin/terminal/shared.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/terminal-manifest-model.d.ts +91 -0
- package/dist/core/extensions/builtin/terminal/terminal-manifest-model.d.ts.map +1 -0
- package/dist/core/extensions/builtin/terminal/terminal-manifest-model.js +14 -0
- package/dist/core/extensions/builtin/terminal/terminal-manifest-model.js.map +1 -0
- package/dist/core/extensions/builtin/terminal/terminal-manifest.d.ts +29 -77
- package/dist/core/extensions/builtin/terminal/terminal-manifest.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/terminal-manifest.js +61 -15
- package/dist/core/extensions/builtin/terminal/terminal-manifest.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/monitor.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/monitor.js +59 -11
- package/dist/core/extensions/builtin/terminal/tools/monitor.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +18 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/retry-fallback/chains.d.ts +1 -13
- package/dist/core/retry-fallback/chains.d.ts.map +1 -1
- package/dist/core/retry-fallback/chains.js +3 -49
- package/dist/core/retry-fallback/chains.js.map +1 -1
- package/dist/core/retry-fallback/controller.d.ts.map +1 -1
- package/dist/core/retry-fallback/controller.js +4 -9
- package/dist/core/retry-fallback/controller.js.map +1 -1
- package/dist/core/retry-fallback/expansion.js +1 -1
- package/dist/core/retry-fallback/expansion.js.map +1 -1
- package/dist/core/retry-fallback/settings.d.ts +2 -4
- package/dist/core/retry-fallback/settings.d.ts.map +1 -1
- package/dist/core/retry-fallback/settings.js +7 -36
- package/dist/core/retry-fallback/settings.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +10 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/settings.md +1 -0
- package/docs/terminal-tools.md +35 -4
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +12 -0
- package/node_modules/@code-yeongyu/senpi-codemode/README.md +2 -2
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/extension/session-manager.ts +8 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/display-image.js +162 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/prelude.ts +2 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-runtime.js +29 -60
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/prelude.py +66 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt.ts +3 -3
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +2 -2
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.d.ts +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +3 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +14 -9
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.d.ts +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +6 -4
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts +30 -0
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +30 -0
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.d.ts +3 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.js +27 -3
- package/node_modules/@earendil-works/pi-ai/dist/models.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/azure-openai-responses.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/github-copilot.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openai-codex.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openai.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/vercel-ai-gateway.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/package.json +1 -1
- package/package.json +7 -7
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
1
2
|
import { StringEnum } from "@earendil-works/pi-ai";
|
|
2
3
|
import { Type } from "typebox";
|
|
3
4
|
import { APPROVED_MONITOR_PARENT } from "../monitor-permission.js";
|
|
4
5
|
import { MonitorRegistry } from "../monitor-registry.js";
|
|
5
|
-
import { DEFAULT_COLS, DEFAULT_ROWS, TERMINAL_MONITOR_TOOL } from "../shared.js";
|
|
6
|
+
import { DEFAULT_COLS, DEFAULT_ROWS, DURABLE_MONITOR_EXPIRY_MS, MAX_DURABLE_MONITORS, TERMINAL_MONITOR_TOOL, } from "../shared.js";
|
|
6
7
|
import { errorResult, resolveTerminalId, textResult, } from "./context.js";
|
|
7
8
|
import { renderMonitorCall } from "./render.js";
|
|
8
9
|
import { spawnCommandSession } from "./spawn.js";
|
|
@@ -28,7 +29,7 @@ export const monitorSchema = Type.Object({
|
|
|
28
29
|
})),
|
|
29
30
|
path: Type.Optional(Type.String({
|
|
30
31
|
minLength: 1,
|
|
31
|
-
description: "Create, file branch (XOR command): one regular file to watch natively, whose parent directory must already exist; takes no filter
|
|
32
|
+
description: "Create, file branch (XOR command): one regular file to watch natively, whose parent directory must already exist; takes no filter.",
|
|
32
33
|
})),
|
|
33
34
|
event: Type.Optional(StringEnum(["create", "modify"], {
|
|
34
35
|
description: "File branch only: which file event fires the watch (defaults to create).",
|
|
@@ -37,9 +38,11 @@ export const monitorSchema = Type.Object({
|
|
|
37
38
|
timeout_ms: Type.Optional(Type.Number({
|
|
38
39
|
minimum: 1,
|
|
39
40
|
maximum: MAX_MONITOR_TIMEOUT_MS,
|
|
40
|
-
description: "Watcher deadline in milliseconds (default 300000; ignored
|
|
41
|
+
description: "Watcher deadline in milliseconds (default 300000; ignored when persistent).",
|
|
42
|
+
})),
|
|
43
|
+
persistent: Type.Optional(Type.Boolean({
|
|
44
|
+
description: "Standing watch: no deadline, and it survives a session restart (command re-run once, file rescanned and any detached change reported). Expires 7 days after creation; max 5 per session; stop one with kill_bash.",
|
|
41
45
|
})),
|
|
42
|
-
persistent: Type.Optional(Type.Boolean({ description: "Keep watching until the command exits or kill_bash stops its bash_id." })),
|
|
43
46
|
bash_id: Type.Optional(Type.String({ description: "Rearm: paused monitor id (mon_ or bash_id) to resume; omit for all paused." })),
|
|
44
47
|
});
|
|
45
48
|
function isFileCreateInput(input) {
|
|
@@ -76,15 +79,27 @@ async function createMonitor(ctx, registry, input, execCtx) {
|
|
|
76
79
|
catch {
|
|
77
80
|
return errorResult(`Invalid monitor filter regex: ${input.filter}`);
|
|
78
81
|
}
|
|
82
|
+
// Durability needs an absolute directory: a restore runs in a different process whose
|
|
83
|
+
// process cwd is unrelated, so the spec must carry the resolved path the spawn used.
|
|
84
|
+
const cwd = resolve(execCtx?.cwd ?? ctx.cwd);
|
|
79
85
|
const { id, runtime } = await spawnCommandSession(ctx, {
|
|
80
86
|
command: input.command,
|
|
81
87
|
cols: resolveDimension(undefined, ctx.defaultCols || DEFAULT_COLS),
|
|
82
88
|
rows: resolveDimension(undefined, ctx.defaultRows || DEFAULT_ROWS),
|
|
83
|
-
cwd
|
|
89
|
+
cwd,
|
|
84
90
|
...(input.persistent ? {} : { timeoutMs: resolveTimeoutMs(input.timeout_ms) }),
|
|
85
91
|
});
|
|
86
92
|
ctx.onMonitorRearmed?.(id);
|
|
87
|
-
const monitorId = registry.register({
|
|
93
|
+
const monitorId = registry.register({
|
|
94
|
+
id,
|
|
95
|
+
description: input.description,
|
|
96
|
+
runtime,
|
|
97
|
+
filter,
|
|
98
|
+
// Only persistent command watches are restartable-command durable: those carry the fire budget.
|
|
99
|
+
durabilityClass: input.persistent === true ? "restartable-command" : "ephemeral",
|
|
100
|
+
// Same deadline the manifest writer persists, so the footer warns off the live record too.
|
|
101
|
+
...(input.persistent === true ? { expiresAt: Date.now() + DURABLE_MONITOR_EXPIRY_MS } : {}),
|
|
102
|
+
});
|
|
88
103
|
ctx.manager.bindMonitorId(monitorId, id);
|
|
89
104
|
// The tool call site is the only place the branch inputs (command, persistent, filter)
|
|
90
105
|
// live; hand the captured spec to the session's manifest writer for durable recording.
|
|
@@ -95,7 +110,7 @@ async function createMonitor(ctx, registry, input, execCtx) {
|
|
|
95
110
|
description: input.description,
|
|
96
111
|
command: input.command,
|
|
97
112
|
filter: input.filter,
|
|
98
|
-
cwd
|
|
113
|
+
cwd,
|
|
99
114
|
persistent: input.persistent === true,
|
|
100
115
|
},
|
|
101
116
|
});
|
|
@@ -121,6 +136,26 @@ function handMonitorSpec(sessionKey, registration) {
|
|
|
121
136
|
const writer = sessionKey === undefined ? undefined : manifestWriters.get(sessionKey);
|
|
122
137
|
void writer?.recordRegister(registration);
|
|
123
138
|
}
|
|
139
|
+
/** Persist a durable file watch's baseline checkpoint through the writer's debounced path. */
|
|
140
|
+
function handFileCheckpoint(sessionKey, monitorId, registry, runtimeId) {
|
|
141
|
+
const writer = sessionKey === undefined ? undefined : manifestWriters.get(sessionKey);
|
|
142
|
+
const checkpoint = registry.fileCheckpoint(runtimeId);
|
|
143
|
+
if (writer && checkpoint)
|
|
144
|
+
writer.scheduleCheckpoint(monitorId, checkpoint);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Admission control for a durable create: refuse once the session already holds
|
|
148
|
+
* MAX_DURABLE_MONITORS restart-surviving monitors. Checked BEFORE any spawn or registry
|
|
149
|
+
* registration so a refused call leaves no PTY and no manifest entry behind. A context
|
|
150
|
+
* with no bound writer persists nothing, so it has no durable population to cap.
|
|
151
|
+
*/
|
|
152
|
+
function durableAdmissionError(ctx) {
|
|
153
|
+
const sessionKey = manifestSessionKey(ctx);
|
|
154
|
+
const writer = sessionKey === undefined ? undefined : manifestWriters.get(sessionKey);
|
|
155
|
+
if (writer === undefined || writer.durableCount() < MAX_DURABLE_MONITORS)
|
|
156
|
+
return undefined;
|
|
157
|
+
return errorResult(`Cannot start another persistent monitor: this session already holds ${MAX_DURABLE_MONITORS} durable monitors (the maximum). Stop one with kill_bash first.`);
|
|
158
|
+
}
|
|
124
159
|
export function createMonitorTool(ctx) {
|
|
125
160
|
let fallbackRegistry;
|
|
126
161
|
const getRegistry = () => {
|
|
@@ -133,7 +168,7 @@ export function createMonitorTool(ctx) {
|
|
|
133
168
|
return {
|
|
134
169
|
name: TERMINAL_MONITOR_TOOL,
|
|
135
170
|
label: "monitor",
|
|
136
|
-
description: "Subscribe to a change instead of polling. Pass command XOR path, never both: command watches a PTY session,
|
|
171
|
+
description: "Subscribe to a change instead of polling. Pass command XOR path, never both: command watches a PTY session, injecting matching newline-terminated output lines (stderr merged) plus an exit summary; path natively watches one file and fires once, where create (the default) fires only when the file appears after registration, so use event modify for an existing file, and filter is rejected. Returns a bash_id immediately; peek with bash_output, stop with kill_bash.",
|
|
137
172
|
promptSnippet: "Subscribe to a command's output or a file's create/modify event as injected events instead of polling",
|
|
138
173
|
promptGuidelines: [
|
|
139
174
|
"Waiting on observable state (CI checks, builds, log patterns, deploys, a file landing) means a monitor, never a foreground sleep/poll loop.",
|
|
@@ -172,9 +207,15 @@ export function createMonitorTool(ctx) {
|
|
|
172
207
|
const commandInput = isCreateInput(input);
|
|
173
208
|
if (fileInput && commandInput)
|
|
174
209
|
return errorResult("monitor accepts either command or path, not both.");
|
|
210
|
+
// Admission runs before either create branch touches a PTY or the registry.
|
|
211
|
+
if (input.persistent === true && (fileInput || commandInput)) {
|
|
212
|
+
const refused = durableAdmissionError(ctx);
|
|
213
|
+
if (refused)
|
|
214
|
+
return refused;
|
|
215
|
+
}
|
|
175
216
|
if (fileInput) {
|
|
176
|
-
if (input.filter !== undefined
|
|
177
|
-
return errorResult("Native file monitors do not support filter
|
|
217
|
+
if (input.filter !== undefined)
|
|
218
|
+
return errorResult("Native file monitors do not support filter.");
|
|
178
219
|
if (!ctx.monitorRegistry)
|
|
179
220
|
return errorResult("Native file monitors require a lifecycle-owned monitor registry.");
|
|
180
221
|
try {
|
|
@@ -186,10 +227,12 @@ export function createMonitorTool(ctx) {
|
|
|
186
227
|
timeoutMs: resolveTimeoutMs(input.timeout_ms),
|
|
187
228
|
cwd: execCtx?.cwd ?? ctx.cwd,
|
|
188
229
|
...(approvedParent !== undefined ? { approvedParent } : {}),
|
|
230
|
+
...(input.persistent === true ? { expiresAt: Date.now() + DURABLE_MONITOR_EXPIRY_MS } : {}),
|
|
189
231
|
});
|
|
190
232
|
ctx.manager.bindMonitorId(monitorId, id);
|
|
191
233
|
// Same spec capture as the command branch: durability inputs live only here.
|
|
192
|
-
|
|
234
|
+
const sessionKey = manifestSessionKey(ctx);
|
|
235
|
+
handMonitorSpec(sessionKey, {
|
|
193
236
|
monitorId,
|
|
194
237
|
spec: {
|
|
195
238
|
kind: "file",
|
|
@@ -198,9 +241,14 @@ export function createMonitorTool(ctx) {
|
|
|
198
241
|
event: input.event ?? "create",
|
|
199
242
|
timeoutMs: resolveTimeoutMs(input.timeout_ms),
|
|
200
243
|
cwd: execCtx?.cwd ?? ctx.cwd,
|
|
244
|
+
persistent: input.persistent === true,
|
|
201
245
|
...(approvedParent !== undefined ? { approvedParent } : {}),
|
|
202
246
|
},
|
|
203
247
|
});
|
|
248
|
+
// A durable watch checkpoints the registry's own identity tuple straight away, so a
|
|
249
|
+
// restart before the first change still has a baseline (digest included) to compare to.
|
|
250
|
+
if (input.persistent === true)
|
|
251
|
+
handFileCheckpoint(sessionKey, monitorId, ctx.monitorRegistry, id);
|
|
204
252
|
return textResult(`Monitor started with ID: ${monitorId}`, {
|
|
205
253
|
details: { monitor_id: monitorId, bash_id: id, monitor: true },
|
|
206
254
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"monitor.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/terminal/tools/monitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAEjF,OAAO,EACN,WAAW,EACX,iBAAiB,EAGjB,UAAU,GACV,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,CAAC,MAAM,0BAA0B,GAAG,OAAO,CAAC;AAClD,MAAM,CAAC,MAAM,sBAAsB,GAAG,SAAS,CAAC;AAEhD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC;IACxC,MAAM,EAAE,IAAI,CAAC,QAAQ,CACpB,UAAU,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAU,EAAE;QACxC,WAAW,EAAE,wEAAwE;KACrF,CAAC,CACF;IACD,WAAW,EAAE,IAAI,CAAC,QAAQ,CACzB,IAAI,CAAC,MAAM,CAAC;QACX,SAAS,EAAE,CAAC;QACZ,SAAS,EAAE,GAAG;QACd,WAAW,EAAE,wFAAwF;KACrG,CAAC,CACF;IACD,OAAO,EAAE,IAAI,CAAC,QAAQ,CACrB,IAAI,CAAC,MAAM,CAAC;QACX,WAAW,EACV,oGAAoG;KACrG,CAAC,CACF;IACD,IAAI,EAAE,IAAI,CAAC,QAAQ,CAClB,IAAI,CAAC,MAAM,CAAC;QACX,SAAS,EAAE,CAAC;QACZ,WAAW,EACV,sJAAsJ;KACvJ,CAAC,CACF;IACD,KAAK,EAAE,IAAI,CAAC,QAAQ,CACnB,UAAU,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAU,EAAE;QACzC,WAAW,EAAE,0EAA0E;KACvF,CAAC,CACF;IACD,MAAM,EAAE,IAAI,CAAC,QAAQ,CACpB,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,kEAAkE,EAAE,CAAC,CAChG;IACD,UAAU,EAAE,IAAI,CAAC,QAAQ,CACxB,IAAI,CAAC,MAAM,CAAC;QACX,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,sBAAsB;QAC/B,WAAW,EAAE,oFAAoF;KACjG,CAAC,CACF;IACD,UAAU,EAAE,IAAI,CAAC,QAAQ,CACxB,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,uEAAuE,EAAE,CAAC,CACtG;IACD,OAAO,EAAE,IAAI,CAAC,QAAQ,CACrB,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,4EAA4E,EAAE,CAAC,CAC1G;CACD,CAAC,CAAC;AAMH,SAAS,iBAAiB,CAAC,KAAmB;IAC7C,OAAO,CACN,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ;QACrC,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC;QAC5B,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;QAC9B,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CACrB,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAmB;IACzC,OAAO,CACN,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ;QACrC,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC;QAC5B,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ;QACjC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CACxB,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAyB,EAAE,QAAgB;IACpE,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IACjF,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAyB;IAClD,MAAM,OAAO,GAAG,KAAK,IAAI,0BAA0B,CAAC;IACpD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAC;AAC3E,CAAC;AAED,SAAS,aAAa,CAAC,MAA0B;IAChD,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC3C,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;AAC3B,CAAC;AAED,KAAK,UAAU,aAAa,CAC3B,GAAwB,EACxB,QAAyB,EACzB,KAAyB,EACzB,OAAqC;IAErC,IAAI,MAA0B,CAAC;IAC/B,IAAI,CAAC;QACJ,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,WAAW,CAAC,iCAAiC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,MAAM,mBAAmB,CAAC,GAAG,EAAE;QACtD,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,IAAI,EAAE,gBAAgB,CAAC,SAAS,EAAE,GAAG,CAAC,WAAW,IAAI,YAAY,CAAC;QAClE,IAAI,EAAE,gBAAgB,CAAC,SAAS,EAAE,GAAG,CAAC,WAAW,IAAI,YAAY,CAAC;QAClE,GAAG,EAAE,OAAO,EAAE,GAAG;QACjB,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,gBAAgB,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;KAC9E,CAAC,CAAC;IACH,GAAG,CAAC,gBAAgB,EAAE,CAAC,EAAE,CAAC,CAAC;IAC3B,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7F,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACzC,uFAAuF;IACvF,uFAAuF;IACvF,eAAe,CAAC,kBAAkB,CAAC,GAAG,CAAC,EAAE;QACxC,SAAS;QACT,IAAI,EAAE;YACL,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,GAAG,EAAE,OAAO,EAAE,GAAG;YACjB,UAAU,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI;SACrC;KACD,CAAC,CAAC;IACH,OAAO,UAAU,CAAC,4BAA4B,SAAS,EAAE,EAAE;QAC1D,OAAO,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;KAC9D,CAAC,CAAC;AACJ,CAAC;AAED,mGAAmG;AACnG,MAAM,eAAe,GAAG,IAAI,GAAG,EAAkC,CAAC;AAElE,4GAA4G;AAC5G,MAAM,UAAU,0BAA0B,CAAC,SAAiB,EAAE,MAA8B;IAC3F,eAAe,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,SAAiB;IAC7D,eAAe,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AACnC,CAAC;AAED,yGAAyG;AACzG,SAAS,kBAAkB,CAAC,GAAwB;IACnD,OAAO,GAAG,CAAC,iBAAiB,EAAE,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,EAAE,CAAC;AACpE,CAAC;AAED,gGAAgG;AAChG,SAAS,eAAe,CAAC,UAA8B,EAAE,YAAiC;IACzF,MAAM,MAAM,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACtF,KAAK,MAAM,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAwB;IACzD,IAAI,gBAA6C,CAAC;IAClD,MAAM,WAAW,GAAG,GAAoB,EAAE;QACzC,MAAM,eAAe,GAAG,GAAG,CAAC,eAAe,CAAC;QAC5C,IAAI,eAAe;YAAE,OAAO,eAAe,CAAC;QAC5C,gBAAgB,KAAK,IAAI,eAAe,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QACjF,OAAO,gBAAgB,CAAC;IACzB,CAAC,CAAC;IACF,OAAO;QACN,IAAI,EAAE,qBAAqB;QAC3B,KAAK,EAAE,SAAS;QAChB,WAAW,EACV,ysBAAysB;QAC1sB,aAAa,EACZ,uGAAuG;QACxG,gBAAgB,EAAE;YACjB,6IAA6I;YAC7I,6XAA6X;YAC7X,uOAAuO;YACvO,0LAA0L;SAC1L;QACD,UAAU,EAAE,aAAa;QACzB,UAAU,EAAE,iBAAiB;QAC7B,KAAK,CAAC,OAAO,CACZ,WAAmB,EACnB,KAAmB,EACnB,OAAqB,EACrB,SAAqB,EACrB,OAA0B;YAE1B,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;YAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;gBAC9B,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC/D,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;oBAClC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO,UAAU,CAAC,+BAA+B,CAAC,CAAC;oBAC7E,GAAG,CAAC,iBAAiB,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;oBAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;oBAC9E,OAAO,UAAU,CAChB,KAAK,GAAG,CAAC;wBACR,CAAC,CAAC,YAAY,OAAO,CAAC,MAAM,uBAAuB,KAAK,gCAAgC;wBACxF,CAAC,CAAC,YAAY,OAAO,CAAC,MAAM,qBAAqB,CAClD,CAAC;gBACH,CAAC;gBACD,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;gBAC7D,MAAM,OAAO,GAAG,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;gBAC9C,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBACvC,IAAI,OAAO,KAAK,WAAW;oBAAE,OAAO,WAAW,CAAC,oCAAoC,MAAM,EAAE,CAAC,CAAC;gBAC9F,IAAI,OAAO,KAAK,YAAY;oBAAE,OAAO,UAAU,CAAC,WAAW,MAAM,kCAAkC,CAAC,CAAC;gBACrG,GAAG,CAAC,gBAAgB,EAAE,CAAC,MAAM,CAAC,CAAC;gBAC/B,OAAO,UAAU,CAChB,OAAO,GAAG,CAAC;oBACV,CAAC,CAAC,WAAW,MAAM,cAAc,OAAO,gCAAgC;oBACxE,CAAC,CAAC,WAAW,MAAM,YAAY,CAChC,CAAC;YACH,CAAC;YACD,MAAM,SAAS,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAC3C,MAAM,YAAY,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;YAC1C,IAAI,SAAS,IAAI,YAAY;gBAAE,OAAO,WAAW,CAAC,mDAAmD,CAAC,CAAC;YACvG,IAAI,SAAS,EAAE,CAAC;gBACf,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,UAAU;oBACjD,OAAO,WAAW,CAAC,2DAA2D,CAAC,CAAC;gBACjF,IAAI,CAAC,GAAG,CAAC,eAAe;oBACvB,OAAO,WAAW,CAAC,kEAAkE,CAAC,CAAC;gBACxF,IAAI,CAAC;oBACJ,MAAM,cAAc,GAAI,KAA0C,CAAC,uBAAuB,CAE9E,CAAC;oBACb,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,MAAM,GAAG,CAAC,eAAe,CAAC,YAAY,CAAC;wBAChE,WAAW,EAAE,KAAK,CAAC,WAAW;wBAC9B,IAAI,EAAE,KAAK,CAAC,IAAI;wBAChB,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,QAAQ;wBAC9B,SAAS,EAAE,gBAAgB,CAAC,KAAK,CAAC,UAAU,CAAC;wBAC7C,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,GAAG,CAAC,GAAG;wBAC5B,GAAG,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;qBAC3D,CAAC,CAAC;oBACH,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;oBACzC,6EAA6E;oBAC7E,eAAe,CAAC,kBAAkB,CAAC,GAAG,CAAC,EAAE;wBACxC,SAAS;wBACT,IAAI,EAAE;4BACL,IAAI,EAAE,MAAM;4BACZ,WAAW,EAAE,KAAK,CAAC,WAAW;4BAC9B,IAAI,EAAE,KAAK,CAAC,IAAI;4BAChB,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,QAAQ;4BAC9B,SAAS,EAAE,gBAAgB,CAAC,KAAK,CAAC,UAAU,CAAC;4BAC7C,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,GAAG,CAAC,GAAG;4BAC5B,GAAG,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;yBAC3D;qBACD,CAAC,CAAC;oBACH,OAAO,UAAU,CAAC,4BAA4B,SAAS,EAAE,EAAE;wBAC1D,OAAO,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;qBAC9D,CAAC,CAAC;gBACJ,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBAChB,OAAO,WAAW,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC5E,CAAC;YACF,CAAC;YACD,IAAI,CAAC,YAAY;gBAAE,OAAO,WAAW,CAAC,sEAAsE,CAAC,CAAC;YAC9G,OAAO,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QACrD,CAAC;KACD,CAAC;AACH,CAAC","sourcesContent":["import { StringEnum } from \"@earendil-works/pi-ai\";\nimport { type Static, Type } from \"typebox\";\nimport { APPROVED_MONITOR_PARENT } from \"../monitor-permission.ts\";\nimport { MonitorRegistry } from \"../monitor-registry.ts\";\nimport { DEFAULT_COLS, DEFAULT_ROWS, TERMINAL_MONITOR_TOOL } from \"../shared.ts\";\nimport type { MonitorRegistration, TerminalManifestWriter } from \"../terminal-manifest.ts\";\nimport {\n\terrorResult,\n\tresolveTerminalId,\n\ttype TerminalToolContext,\n\ttype TerminalToolResult,\n\ttextResult,\n} from \"./context.ts\";\nimport { renderMonitorCall } from \"./render.ts\";\nimport { spawnCommandSession } from \"./spawn.ts\";\n\nexport const DEFAULT_MONITOR_TIMEOUT_MS = 300_000;\nexport const MAX_MONITOR_TIMEOUT_MS = 3_600_000;\n\n/**\n * One flat object schema, no top-level union: several provider payload paths\n * (e.g. Anthropic's legacy input_schema conversion) rebuild tool schemas from\n * top-level `properties` only, so a root anyOf would reach the model as an\n * empty schema. Branch requirements are enforced at runtime in `execute`.\n */\nexport const monitorSchema = Type.Object({\n\taction: Type.Optional(\n\t\tStringEnum([\"create\", \"rearm\"] as const, {\n\t\t\tdescription: \"Defaults to create. rearm resumes a monitor paused by the wake budget.\",\n\t\t}),\n\t),\n\tdescription: Type.Optional(\n\t\tType.String({\n\t\t\tminLength: 1,\n\t\t\tmaxLength: 200,\n\t\t\tdescription: \"Create (required): specific label shown with every event, e.g. 'errors in deploy.log'.\",\n\t\t}),\n\t),\n\tcommand: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Create, command branch (XOR path): shell command to run and watch in a PTY-backed monitor session.\",\n\t\t}),\n\t),\n\tpath: Type.Optional(\n\t\tType.String({\n\t\t\tminLength: 1,\n\t\t\tdescription:\n\t\t\t\t\"Create, file branch (XOR command): one regular file to watch natively, whose parent directory must already exist; takes no filter and no persistent.\",\n\t\t}),\n\t),\n\tevent: Type.Optional(\n\t\tStringEnum([\"create\", \"modify\"] as const, {\n\t\t\tdescription: \"File branch only: which file event fires the watch (defaults to create).\",\n\t\t}),\n\t),\n\tfilter: Type.Optional(\n\t\tType.String({ description: \"Only PTY output lines matching this regex become monitor events.\" }),\n\t),\n\ttimeout_ms: Type.Optional(\n\t\tType.Number({\n\t\t\tminimum: 1,\n\t\t\tmaximum: MAX_MONITOR_TIMEOUT_MS,\n\t\t\tdescription: \"Watcher deadline in milliseconds (default 300000; ignored by persistent monitors).\",\n\t\t}),\n\t),\n\tpersistent: Type.Optional(\n\t\tType.Boolean({ description: \"Keep watching until the command exits or kill_bash stops its bash_id.\" }),\n\t),\n\tbash_id: Type.Optional(\n\t\tType.String({ description: \"Rearm: paused monitor id (mon_ or bash_id) to resume; omit for all paused.\" }),\n\t),\n});\nexport type MonitorInput = Static<typeof monitorSchema>;\n\ntype MonitorCreateInput = MonitorInput & { description: string; command: string };\ntype FileMonitorCreateInput = MonitorInput & { description: string; path: string };\n\nfunction isFileCreateInput(input: MonitorInput): input is FileMonitorCreateInput {\n\treturn (\n\t\ttypeof input.description === \"string\" &&\n\t\tinput.description.length > 0 &&\n\t\ttypeof input.path === \"string\" &&\n\t\tinput.path.length > 0\n\t);\n}\n\nfunction isCreateInput(input: MonitorInput): input is MonitorCreateInput {\n\treturn (\n\t\ttypeof input.description === \"string\" &&\n\t\tinput.description.length > 0 &&\n\t\ttypeof input.command === \"string\" &&\n\t\tinput.command.length > 0\n\t);\n}\n\nfunction resolveDimension(value: number | undefined, fallback: number): number {\n\tif (value === undefined || !Number.isFinite(value) || value < 1) return fallback;\n\treturn Math.trunc(value);\n}\n\nfunction resolveTimeoutMs(value: number | undefined): number {\n\tconst timeout = value ?? DEFAULT_MONITOR_TIMEOUT_MS;\n\treturn Math.min(Math.max(Math.trunc(timeout), 1), MAX_MONITOR_TIMEOUT_MS);\n}\n\nfunction compileFilter(filter: string | undefined): RegExp | undefined {\n\tif (filter === undefined) return undefined;\n\treturn new RegExp(filter);\n}\n\nasync function createMonitor(\n\tctx: TerminalToolContext,\n\tregistry: MonitorRegistry,\n\tinput: MonitorCreateInput,\n\texecCtx: { cwd?: string } | undefined,\n): Promise<TerminalToolResult> {\n\tlet filter: RegExp | undefined;\n\ttry {\n\t\tfilter = compileFilter(input.filter);\n\t} catch {\n\t\treturn errorResult(`Invalid monitor filter regex: ${input.filter}`);\n\t}\n\n\tconst { id, runtime } = await spawnCommandSession(ctx, {\n\t\tcommand: input.command,\n\t\tcols: resolveDimension(undefined, ctx.defaultCols || DEFAULT_COLS),\n\t\trows: resolveDimension(undefined, ctx.defaultRows || DEFAULT_ROWS),\n\t\tcwd: execCtx?.cwd,\n\t\t...(input.persistent ? {} : { timeoutMs: resolveTimeoutMs(input.timeout_ms) }),\n\t});\n\tctx.onMonitorRearmed?.(id);\n\tconst monitorId = registry.register({ id, description: input.description, runtime, filter });\n\tctx.manager.bindMonitorId(monitorId, id);\n\t// The tool call site is the only place the branch inputs (command, persistent, filter)\n\t// live; hand the captured spec to the session's manifest writer for durable recording.\n\thandMonitorSpec(manifestSessionKey(ctx), {\n\t\tmonitorId,\n\t\tspec: {\n\t\t\tkind: \"command\",\n\t\t\tdescription: input.description,\n\t\t\tcommand: input.command,\n\t\t\tfilter: input.filter,\n\t\t\tcwd: execCtx?.cwd,\n\t\t\tpersistent: input.persistent === true,\n\t\t},\n\t});\n\treturn textResult(`Monitor started with ID: ${monitorId}`, {\n\t\tdetails: { monitor_id: monitorId, bash_id: id, monitor: true },\n\t});\n}\n\n/** Build the PTY-backed monitor tool. Monitor handles share TerminalManager's bash_N namespace. */\nconst manifestWriters = new Map<string, TerminalManifestWriter>();\n\n/** Bind the session's manifest writer so monitor tool calls can hand it specs captured at the call site. */\nexport function bindTerminalManifestWriter(sessionId: string, writer: TerminalManifestWriter): void {\n\tmanifestWriters.set(sessionId, writer);\n}\n\nexport function unbindTerminalManifestWriter(sessionId: string): void {\n\tmanifestWriters.delete(sessionId);\n}\n\n/** The durability session key for a tool context: the agent session id, when the context carries one. */\nfunction manifestSessionKey(ctx: TerminalToolContext): string | undefined {\n\treturn ctx.getSessionContext?.()?.sessionManager?.getSessionId?.();\n}\n\n/** Hand a spec captured at the monitor tool call site to the session's bound writer, if any. */\nfunction handMonitorSpec(sessionKey: string | undefined, registration: MonitorRegistration): void {\n\tconst writer = sessionKey === undefined ? undefined : manifestWriters.get(sessionKey);\n\tvoid writer?.recordRegister(registration);\n}\n\nexport function createMonitorTool(ctx: TerminalToolContext) {\n\tlet fallbackRegistry: MonitorRegistry | undefined;\n\tconst getRegistry = (): MonitorRegistry => {\n\t\tconst sessionRegistry = ctx.monitorRegistry;\n\t\tif (sessionRegistry) return sessionRegistry;\n\t\tfallbackRegistry ??= new MonitorRegistry((event) => ctx.onMonitorEvent?.(event));\n\t\treturn fallbackRegistry;\n\t};\n\treturn {\n\t\tname: TERMINAL_MONITOR_TOOL,\n\t\tlabel: \"monitor\",\n\t\tdescription:\n\t\t\t\"Subscribe to a change instead of polling. Pass command XOR path, never both: command watches a PTY session, where newline-terminated output lines (stderr merged) that match filter arrive as injected events while you keep working and command exit always delivers a summary event; path natively watches one file and fires once: create (the default) fires only when the file appears after registration, so watch a file that already exists with event modify. The path branch takes no filter and no persistent. Identical consecutive line-only update batches are deduped, so a watcher reprinting unchanged status does not re-wake the session. Returns a bash_id immediately; peek with bash_output, stop with kill_bash.\",\n\t\tpromptSnippet:\n\t\t\t\"Subscribe to a command's output or a file's create/modify event as injected events instead of polling\",\n\t\tpromptGuidelines: [\n\t\t\t\"Waiting on observable state (CI checks, builds, log patterns, deploys, a file landing) means a monitor, never a foreground sleep/poll loop.\",\n\t\t\t'Waiting for one file to appear or change is the path branch: `monitor({ description, path, event? })` beats wrapping `test -f` in a shell poll loop; a file that already exists needs `event: \"modify\"`, since `create` only fires on appearance, and registration needs the parent directory to exist already — when the run creates that directory too, use the `command` branch instead.',\n\t\t\t\"Shape the command for the events you need: one-shot gate = `until <cond>; do sleep 1; done; printf 'READY\\\\n'` with filter ^READY$; stream = `tail -n 0 -F <log> | grep --line-buffered <pat>` with persistent: true, then kill_bash.\",\n\t\t\t\"Sleep loops belong INSIDE the monitor command, never in your turn: about to sleep, re-poll bash_output, or foreground-block on a long command means register a monitor and keep working.\",\n\t\t],\n\t\tparameters: monitorSchema,\n\t\trenderCall: renderMonitorCall,\n\t\tasync execute(\n\t\t\t_toolCallId: string,\n\t\t\tinput: MonitorInput,\n\t\t\t_signal?: AbortSignal,\n\t\t\t_onUpdate?: undefined,\n\t\t\texecCtx?: { cwd?: string },\n\t\t): Promise<TerminalToolResult> {\n\t\t\tconst registry = getRegistry();\n\t\t\tif (input.action === \"rearm\") {\n\t\t\t\tif (input.bash_id === undefined || input.bash_id.length === 0) {\n\t\t\t\t\tconst resumed = registry.resume();\n\t\t\t\t\tif (resumed.length === 0) return textResult(\"No paused monitors to re-arm.\");\n\t\t\t\t\tctx.onMonitorsResumed?.(resumed.map((monitor) => monitor.id));\n\t\t\t\t\tconst total = resumed.reduce((sum, monitor) => sum + monitor.mutedDropped, 0);\n\t\t\t\t\treturn textResult(\n\t\t\t\t\t\ttotal > 0\n\t\t\t\t\t\t\t? `Re-armed ${resumed.length} paused monitor(s) (${total} line(s) dropped while muted).`\n\t\t\t\t\t\t\t: `Re-armed ${resumed.length} paused monitor(s).`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst bashId = resolveTerminalId(ctx.manager, input.bash_id);\n\t\t\t\tconst dropped = registry.mutedDropped(bashId);\n\t\t\t\tconst outcome = registry.rearm(bashId);\n\t\t\t\tif (outcome === \"not_found\") return errorResult(`No active monitor found with id: ${bashId}`);\n\t\t\t\tif (outcome === \"not_paused\") return textResult(`Monitor ${bashId} is not paused; no action taken.`);\n\t\t\t\tctx.onMonitorRearmed?.(bashId);\n\t\t\t\treturn textResult(\n\t\t\t\t\tdropped > 0\n\t\t\t\t\t\t? `Monitor ${bashId} re-armed (${dropped} line(s) dropped while muted).`\n\t\t\t\t\t\t: `Monitor ${bashId} re-armed.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst fileInput = isFileCreateInput(input);\n\t\t\tconst commandInput = isCreateInput(input);\n\t\t\tif (fileInput && commandInput) return errorResult(\"monitor accepts either command or path, not both.\");\n\t\t\tif (fileInput) {\n\t\t\t\tif (input.filter !== undefined || input.persistent)\n\t\t\t\t\treturn errorResult(\"Native file monitors do not support filter or persistent.\");\n\t\t\t\tif (!ctx.monitorRegistry)\n\t\t\t\t\treturn errorResult(\"Native file monitors require a lifecycle-owned monitor registry.\");\n\t\t\t\ttry {\n\t\t\t\t\tconst approvedParent = (input as Record<string | symbol, unknown>)[APPROVED_MONITOR_PARENT] as\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| undefined;\n\t\t\t\t\tconst { id, monitorId } = await ctx.monitorRegistry.registerFile({\n\t\t\t\t\t\tdescription: input.description,\n\t\t\t\t\t\tpath: input.path,\n\t\t\t\t\t\tevent: input.event ?? \"create\",\n\t\t\t\t\t\ttimeoutMs: resolveTimeoutMs(input.timeout_ms),\n\t\t\t\t\t\tcwd: execCtx?.cwd ?? ctx.cwd,\n\t\t\t\t\t\t...(approvedParent !== undefined ? { approvedParent } : {}),\n\t\t\t\t\t});\n\t\t\t\t\tctx.manager.bindMonitorId(monitorId, id);\n\t\t\t\t\t// Same spec capture as the command branch: durability inputs live only here.\n\t\t\t\t\thandMonitorSpec(manifestSessionKey(ctx), {\n\t\t\t\t\t\tmonitorId,\n\t\t\t\t\t\tspec: {\n\t\t\t\t\t\t\tkind: \"file\",\n\t\t\t\t\t\t\tdescription: input.description,\n\t\t\t\t\t\t\tpath: input.path,\n\t\t\t\t\t\t\tevent: input.event ?? \"create\",\n\t\t\t\t\t\t\ttimeoutMs: resolveTimeoutMs(input.timeout_ms),\n\t\t\t\t\t\t\tcwd: execCtx?.cwd ?? ctx.cwd,\n\t\t\t\t\t\t\t...(approvedParent !== undefined ? { approvedParent } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\treturn textResult(`Monitor started with ID: ${monitorId}`, {\n\t\t\t\t\t\tdetails: { monitor_id: monitorId, bash_id: id, monitor: true },\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn errorResult(error instanceof Error ? error.message : String(error));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!commandInput) return errorResult(\"monitor requires description and command or path to start a watcher.\");\n\t\t\treturn createMonitor(ctx, registry, input, execCtx);\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"monitor.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/terminal/tools/monitor.ts"],"names":[],"mappings":"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","sourcesContent":["import { resolve } from \"node:path\";\nimport { StringEnum } from \"@earendil-works/pi-ai\";\nimport { type Static, Type } from \"typebox\";\nimport { APPROVED_MONITOR_PARENT } from \"../monitor-permission.ts\";\nimport { MonitorRegistry } from \"../monitor-registry.ts\";\nimport {\n\tDEFAULT_COLS,\n\tDEFAULT_ROWS,\n\tDURABLE_MONITOR_EXPIRY_MS,\n\tMAX_DURABLE_MONITORS,\n\tTERMINAL_MONITOR_TOOL,\n} from \"../shared.ts\";\nimport type { MonitorRegistration, TerminalManifestWriter } from \"../terminal-manifest.ts\";\nimport {\n\terrorResult,\n\tresolveTerminalId,\n\ttype TerminalToolContext,\n\ttype TerminalToolResult,\n\ttextResult,\n} from \"./context.ts\";\nimport { renderMonitorCall } from \"./render.ts\";\nimport { spawnCommandSession } from \"./spawn.ts\";\n\nexport const DEFAULT_MONITOR_TIMEOUT_MS = 300_000;\nexport const MAX_MONITOR_TIMEOUT_MS = 3_600_000;\n\n/**\n * One flat object schema, no top-level union: several provider payload paths\n * (e.g. Anthropic's legacy input_schema conversion) rebuild tool schemas from\n * top-level `properties` only, so a root anyOf would reach the model as an\n * empty schema. Branch requirements are enforced at runtime in `execute`.\n */\nexport const monitorSchema = Type.Object({\n\taction: Type.Optional(\n\t\tStringEnum([\"create\", \"rearm\"] as const, {\n\t\t\tdescription: \"Defaults to create. rearm resumes a monitor paused by the wake budget.\",\n\t\t}),\n\t),\n\tdescription: Type.Optional(\n\t\tType.String({\n\t\t\tminLength: 1,\n\t\t\tmaxLength: 200,\n\t\t\tdescription: \"Create (required): specific label shown with every event, e.g. 'errors in deploy.log'.\",\n\t\t}),\n\t),\n\tcommand: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Create, command branch (XOR path): shell command to run and watch in a PTY-backed monitor session.\",\n\t\t}),\n\t),\n\tpath: Type.Optional(\n\t\tType.String({\n\t\t\tminLength: 1,\n\t\t\tdescription:\n\t\t\t\t\"Create, file branch (XOR command): one regular file to watch natively, whose parent directory must already exist; takes no filter.\",\n\t\t}),\n\t),\n\tevent: Type.Optional(\n\t\tStringEnum([\"create\", \"modify\"] as const, {\n\t\t\tdescription: \"File branch only: which file event fires the watch (defaults to create).\",\n\t\t}),\n\t),\n\tfilter: Type.Optional(\n\t\tType.String({ description: \"Only PTY output lines matching this regex become monitor events.\" }),\n\t),\n\ttimeout_ms: Type.Optional(\n\t\tType.Number({\n\t\t\tminimum: 1,\n\t\t\tmaximum: MAX_MONITOR_TIMEOUT_MS,\n\t\t\tdescription: \"Watcher deadline in milliseconds (default 300000; ignored when persistent).\",\n\t\t}),\n\t),\n\tpersistent: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Standing watch: no deadline, and it survives a session restart (command re-run once, file rescanned and any detached change reported). Expires 7 days after creation; max 5 per session; stop one with kill_bash.\",\n\t\t}),\n\t),\n\tbash_id: Type.Optional(\n\t\tType.String({ description: \"Rearm: paused monitor id (mon_ or bash_id) to resume; omit for all paused.\" }),\n\t),\n});\nexport type MonitorInput = Static<typeof monitorSchema>;\n\ntype MonitorCreateInput = MonitorInput & { description: string; command: string };\ntype FileMonitorCreateInput = MonitorInput & { description: string; path: string };\n\nfunction isFileCreateInput(input: MonitorInput): input is FileMonitorCreateInput {\n\treturn (\n\t\ttypeof input.description === \"string\" &&\n\t\tinput.description.length > 0 &&\n\t\ttypeof input.path === \"string\" &&\n\t\tinput.path.length > 0\n\t);\n}\n\nfunction isCreateInput(input: MonitorInput): input is MonitorCreateInput {\n\treturn (\n\t\ttypeof input.description === \"string\" &&\n\t\tinput.description.length > 0 &&\n\t\ttypeof input.command === \"string\" &&\n\t\tinput.command.length > 0\n\t);\n}\n\nfunction resolveDimension(value: number | undefined, fallback: number): number {\n\tif (value === undefined || !Number.isFinite(value) || value < 1) return fallback;\n\treturn Math.trunc(value);\n}\n\nfunction resolveTimeoutMs(value: number | undefined): number {\n\tconst timeout = value ?? DEFAULT_MONITOR_TIMEOUT_MS;\n\treturn Math.min(Math.max(Math.trunc(timeout), 1), MAX_MONITOR_TIMEOUT_MS);\n}\n\nfunction compileFilter(filter: string | undefined): RegExp | undefined {\n\tif (filter === undefined) return undefined;\n\treturn new RegExp(filter);\n}\n\nasync function createMonitor(\n\tctx: TerminalToolContext,\n\tregistry: MonitorRegistry,\n\tinput: MonitorCreateInput,\n\texecCtx: { cwd?: string } | undefined,\n): Promise<TerminalToolResult> {\n\tlet filter: RegExp | undefined;\n\ttry {\n\t\tfilter = compileFilter(input.filter);\n\t} catch {\n\t\treturn errorResult(`Invalid monitor filter regex: ${input.filter}`);\n\t}\n\n\t// Durability needs an absolute directory: a restore runs in a different process whose\n\t// process cwd is unrelated, so the spec must carry the resolved path the spawn used.\n\tconst cwd = resolve(execCtx?.cwd ?? ctx.cwd);\n\tconst { id, runtime } = await spawnCommandSession(ctx, {\n\t\tcommand: input.command,\n\t\tcols: resolveDimension(undefined, ctx.defaultCols || DEFAULT_COLS),\n\t\trows: resolveDimension(undefined, ctx.defaultRows || DEFAULT_ROWS),\n\t\tcwd,\n\t\t...(input.persistent ? {} : { timeoutMs: resolveTimeoutMs(input.timeout_ms) }),\n\t});\n\tctx.onMonitorRearmed?.(id);\n\tconst monitorId = registry.register({\n\t\tid,\n\t\tdescription: input.description,\n\t\truntime,\n\t\tfilter,\n\t\t// Only persistent command watches are restartable-command durable: those carry the fire budget.\n\t\tdurabilityClass: input.persistent === true ? \"restartable-command\" : \"ephemeral\",\n\t\t// Same deadline the manifest writer persists, so the footer warns off the live record too.\n\t\t...(input.persistent === true ? { expiresAt: Date.now() + DURABLE_MONITOR_EXPIRY_MS } : {}),\n\t});\n\tctx.manager.bindMonitorId(monitorId, id);\n\t// The tool call site is the only place the branch inputs (command, persistent, filter)\n\t// live; hand the captured spec to the session's manifest writer for durable recording.\n\thandMonitorSpec(manifestSessionKey(ctx), {\n\t\tmonitorId,\n\t\tspec: {\n\t\t\tkind: \"command\",\n\t\t\tdescription: input.description,\n\t\t\tcommand: input.command,\n\t\t\tfilter: input.filter,\n\t\t\tcwd,\n\t\t\tpersistent: input.persistent === true,\n\t\t},\n\t});\n\treturn textResult(`Monitor started with ID: ${monitorId}`, {\n\t\tdetails: { monitor_id: monitorId, bash_id: id, monitor: true },\n\t});\n}\n\n/** Build the PTY-backed monitor tool. Monitor handles share TerminalManager's bash_N namespace. */\nconst manifestWriters = new Map<string, TerminalManifestWriter>();\n\n/** Bind the session's manifest writer so monitor tool calls can hand it specs captured at the call site. */\nexport function bindTerminalManifestWriter(sessionId: string, writer: TerminalManifestWriter): void {\n\tmanifestWriters.set(sessionId, writer);\n}\n\nexport function unbindTerminalManifestWriter(sessionId: string): void {\n\tmanifestWriters.delete(sessionId);\n}\n\n/** The durability session key for a tool context: the agent session id, when the context carries one. */\nfunction manifestSessionKey(ctx: TerminalToolContext): string | undefined {\n\treturn ctx.getSessionContext?.()?.sessionManager?.getSessionId?.();\n}\n\n/** Hand a spec captured at the monitor tool call site to the session's bound writer, if any. */\nfunction handMonitorSpec(sessionKey: string | undefined, registration: MonitorRegistration): void {\n\tconst writer = sessionKey === undefined ? undefined : manifestWriters.get(sessionKey);\n\tvoid writer?.recordRegister(registration);\n}\n\n/** Persist a durable file watch's baseline checkpoint through the writer's debounced path. */\nfunction handFileCheckpoint(\n\tsessionKey: string | undefined,\n\tmonitorId: string,\n\tregistry: MonitorRegistry,\n\truntimeId: string,\n): void {\n\tconst writer = sessionKey === undefined ? undefined : manifestWriters.get(sessionKey);\n\tconst checkpoint = registry.fileCheckpoint(runtimeId);\n\tif (writer && checkpoint) writer.scheduleCheckpoint(monitorId, checkpoint);\n}\n\n/**\n * Admission control for a durable create: refuse once the session already holds\n * MAX_DURABLE_MONITORS restart-surviving monitors. Checked BEFORE any spawn or registry\n * registration so a refused call leaves no PTY and no manifest entry behind. A context\n * with no bound writer persists nothing, so it has no durable population to cap.\n */\nfunction durableAdmissionError(ctx: TerminalToolContext): TerminalToolResult | undefined {\n\tconst sessionKey = manifestSessionKey(ctx);\n\tconst writer = sessionKey === undefined ? undefined : manifestWriters.get(sessionKey);\n\tif (writer === undefined || writer.durableCount() < MAX_DURABLE_MONITORS) return undefined;\n\treturn errorResult(\n\t\t`Cannot start another persistent monitor: this session already holds ${MAX_DURABLE_MONITORS} durable monitors (the maximum). Stop one with kill_bash first.`,\n\t);\n}\n\nexport function createMonitorTool(ctx: TerminalToolContext) {\n\tlet fallbackRegistry: MonitorRegistry | undefined;\n\tconst getRegistry = (): MonitorRegistry => {\n\t\tconst sessionRegistry = ctx.monitorRegistry;\n\t\tif (sessionRegistry) return sessionRegistry;\n\t\tfallbackRegistry ??= new MonitorRegistry((event) => ctx.onMonitorEvent?.(event));\n\t\treturn fallbackRegistry;\n\t};\n\treturn {\n\t\tname: TERMINAL_MONITOR_TOOL,\n\t\tlabel: \"monitor\",\n\t\tdescription:\n\t\t\t\"Subscribe to a change instead of polling. Pass command XOR path, never both: command watches a PTY session, injecting matching newline-terminated output lines (stderr merged) plus an exit summary; path natively watches one file and fires once, where create (the default) fires only when the file appears after registration, so use event modify for an existing file, and filter is rejected. Returns a bash_id immediately; peek with bash_output, stop with kill_bash.\",\n\t\tpromptSnippet:\n\t\t\t\"Subscribe to a command's output or a file's create/modify event as injected events instead of polling\",\n\t\tpromptGuidelines: [\n\t\t\t\"Waiting on observable state (CI checks, builds, log patterns, deploys, a file landing) means a monitor, never a foreground sleep/poll loop.\",\n\t\t\t'Waiting for one file to appear or change is the path branch: `monitor({ description, path, event? })` beats wrapping `test -f` in a shell poll loop; a file that already exists needs `event: \"modify\"`, since `create` only fires on appearance, and registration needs the parent directory to exist already — when the run creates that directory too, use the `command` branch instead.',\n\t\t\t\"Shape the command for the events you need: one-shot gate = `until <cond>; do sleep 1; done; printf 'READY\\\\n'` with filter ^READY$; stream = `tail -n 0 -F <log> | grep --line-buffered <pat>` with persistent: true, then kill_bash.\",\n\t\t\t\"Sleep loops belong INSIDE the monitor command, never in your turn: about to sleep, re-poll bash_output, or foreground-block on a long command means register a monitor and keep working.\",\n\t\t],\n\t\tparameters: monitorSchema,\n\t\trenderCall: renderMonitorCall,\n\t\tasync execute(\n\t\t\t_toolCallId: string,\n\t\t\tinput: MonitorInput,\n\t\t\t_signal?: AbortSignal,\n\t\t\t_onUpdate?: undefined,\n\t\t\texecCtx?: { cwd?: string },\n\t\t): Promise<TerminalToolResult> {\n\t\t\tconst registry = getRegistry();\n\t\t\tif (input.action === \"rearm\") {\n\t\t\t\tif (input.bash_id === undefined || input.bash_id.length === 0) {\n\t\t\t\t\tconst resumed = registry.resume();\n\t\t\t\t\tif (resumed.length === 0) return textResult(\"No paused monitors to re-arm.\");\n\t\t\t\t\tctx.onMonitorsResumed?.(resumed.map((monitor) => monitor.id));\n\t\t\t\t\tconst total = resumed.reduce((sum, monitor) => sum + monitor.mutedDropped, 0);\n\t\t\t\t\treturn textResult(\n\t\t\t\t\t\ttotal > 0\n\t\t\t\t\t\t\t? `Re-armed ${resumed.length} paused monitor(s) (${total} line(s) dropped while muted).`\n\t\t\t\t\t\t\t: `Re-armed ${resumed.length} paused monitor(s).`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst bashId = resolveTerminalId(ctx.manager, input.bash_id);\n\t\t\t\tconst dropped = registry.mutedDropped(bashId);\n\t\t\t\tconst outcome = registry.rearm(bashId);\n\t\t\t\tif (outcome === \"not_found\") return errorResult(`No active monitor found with id: ${bashId}`);\n\t\t\t\tif (outcome === \"not_paused\") return textResult(`Monitor ${bashId} is not paused; no action taken.`);\n\t\t\t\tctx.onMonitorRearmed?.(bashId);\n\t\t\t\treturn textResult(\n\t\t\t\t\tdropped > 0\n\t\t\t\t\t\t? `Monitor ${bashId} re-armed (${dropped} line(s) dropped while muted).`\n\t\t\t\t\t\t: `Monitor ${bashId} re-armed.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst fileInput = isFileCreateInput(input);\n\t\t\tconst commandInput = isCreateInput(input);\n\t\t\tif (fileInput && commandInput) return errorResult(\"monitor accepts either command or path, not both.\");\n\t\t\t// Admission runs before either create branch touches a PTY or the registry.\n\t\t\tif (input.persistent === true && (fileInput || commandInput)) {\n\t\t\t\tconst refused = durableAdmissionError(ctx);\n\t\t\t\tif (refused) return refused;\n\t\t\t}\n\t\t\tif (fileInput) {\n\t\t\t\tif (input.filter !== undefined) return errorResult(\"Native file monitors do not support filter.\");\n\t\t\t\tif (!ctx.monitorRegistry)\n\t\t\t\t\treturn errorResult(\"Native file monitors require a lifecycle-owned monitor registry.\");\n\t\t\t\ttry {\n\t\t\t\t\tconst approvedParent = (input as Record<string | symbol, unknown>)[APPROVED_MONITOR_PARENT] as\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| undefined;\n\t\t\t\t\tconst { id, monitorId } = await ctx.monitorRegistry.registerFile({\n\t\t\t\t\t\tdescription: input.description,\n\t\t\t\t\t\tpath: input.path,\n\t\t\t\t\t\tevent: input.event ?? \"create\",\n\t\t\t\t\t\ttimeoutMs: resolveTimeoutMs(input.timeout_ms),\n\t\t\t\t\t\tcwd: execCtx?.cwd ?? ctx.cwd,\n\t\t\t\t\t\t...(approvedParent !== undefined ? { approvedParent } : {}),\n\t\t\t\t\t\t...(input.persistent === true ? { expiresAt: Date.now() + DURABLE_MONITOR_EXPIRY_MS } : {}),\n\t\t\t\t\t});\n\t\t\t\t\tctx.manager.bindMonitorId(monitorId, id);\n\t\t\t\t\t// Same spec capture as the command branch: durability inputs live only here.\n\t\t\t\t\tconst sessionKey = manifestSessionKey(ctx);\n\t\t\t\t\thandMonitorSpec(sessionKey, {\n\t\t\t\t\t\tmonitorId,\n\t\t\t\t\t\tspec: {\n\t\t\t\t\t\t\tkind: \"file\",\n\t\t\t\t\t\t\tdescription: input.description,\n\t\t\t\t\t\t\tpath: input.path,\n\t\t\t\t\t\t\tevent: input.event ?? \"create\",\n\t\t\t\t\t\t\ttimeoutMs: resolveTimeoutMs(input.timeout_ms),\n\t\t\t\t\t\t\tcwd: execCtx?.cwd ?? ctx.cwd,\n\t\t\t\t\t\t\tpersistent: input.persistent === true,\n\t\t\t\t\t\t\t...(approvedParent !== undefined ? { approvedParent } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\t// A durable watch checkpoints the registry's own identity tuple straight away, so a\n\t\t\t\t\t// restart before the first change still has a baseline (digest included) to compare to.\n\t\t\t\t\tif (input.persistent === true) handFileCheckpoint(sessionKey, monitorId, ctx.monitorRegistry, id);\n\t\t\t\t\treturn textResult(`Monitor started with ID: ${monitorId}`, {\n\t\t\t\t\t\tdetails: { monitor_id: monitorId, bash_id: id, monitor: true },\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn errorResult(error instanceof Error ? error.message : String(error));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!commandInput) return errorResult(\"monitor requires description and command or path to start a watcher.\");\n\t\t\treturn createMonitor(ctx, registry, input, execCtx);\n\t\t},\n\t};\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"footer-data-provider.d.ts","sourceRoot":"","sources":["../../src/core/footer-data-provider.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,QAAQ,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAgCzD;AA+CD;;;GAGG;AACH,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAO;IAEhD,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,QAAQ,CAA0C;IAC1D,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,qBAAqB,CAA4D;IACzF,OAAO,CAAC,eAAe,CAA0B;IACjD,OAAO,CAAC,yBAAyB,CAA0B;IAC3D,OAAO,CAAC,sBAAsB,CAAuB;IACrD,OAAO,CAAC,qBAAqB,CAAyB;IACtD,OAAO,CAAC,sBAAsB,CAAK;IACnC,OAAO,CAAC,YAAY,CAA8C;IAClE,OAAO,CAAC,oBAAoB,CAA8C;IAC1E,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAS;gBAEb,GAAG,EAAE,MAAM;IAMvB,2EAA2E;IAC3E,YAAY,IAAI,MAAM,GAAG,IAAI;IAO7B,wDAAwD;IACxD,oBAAoB,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;IAInD,qEAAqE;IACrE,cAAc,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAKhD,qCAAqC;IACrC,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAQ/D,yCAAyC;IACzC,sBAAsB,IAAI,IAAI;IAI9B,4EAA4E;IAC5E,yBAAyB,IAAI,MAAM;IAInC,gDAAgD;IAChD,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI9C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAiBzB,wBAAwB;IACxB,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,eAAe;YAYT,qBAAqB;IA0BnC,OAAO,CAAC,oBAAoB;YAcd,qBAAqB;IAgBnC,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,uBAAuB;IAW/B,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,eAAe;
|
|
1
|
+
{"version":3,"file":"footer-data-provider.d.ts","sourceRoot":"","sources":["../../src/core/footer-data-provider.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,QAAQ,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAgCzD;AA+CD;;;GAGG;AACH,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAO;IAEhD,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,QAAQ,CAA0C;IAC1D,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,qBAAqB,CAA4D;IACzF,OAAO,CAAC,eAAe,CAA0B;IACjD,OAAO,CAAC,yBAAyB,CAA0B;IAC3D,OAAO,CAAC,sBAAsB,CAAuB;IACrD,OAAO,CAAC,qBAAqB,CAAyB;IACtD,OAAO,CAAC,sBAAsB,CAAK;IACnC,OAAO,CAAC,YAAY,CAA8C;IAClE,OAAO,CAAC,oBAAoB,CAA8C;IAC1E,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAS;gBAEb,GAAG,EAAE,MAAM;IAMvB,2EAA2E;IAC3E,YAAY,IAAI,MAAM,GAAG,IAAI;IAO7B,wDAAwD;IACxD,oBAAoB,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;IAInD,qEAAqE;IACrE,cAAc,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAKhD,qCAAqC;IACrC,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAQ/D,yCAAyC;IACzC,sBAAsB,IAAI,IAAI;IAI9B,4EAA4E;IAC5E,yBAAyB,IAAI,MAAM;IAInC,gDAAgD;IAChD,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI9C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAiBzB,wBAAwB;IACxB,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,eAAe;YAYT,qBAAqB;IA0BnC,OAAO,CAAC,oBAAoB;YAcd,qBAAqB;IAgBnC,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,uBAAuB;IAW/B,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,eAAe;CAoFvB;AAED,yGAAyG;AACzG,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAC5C,kBAAkB,EAClB,cAAc,GAAG,sBAAsB,GAAG,2BAA2B,GAAG,gBAAgB,CACxF,CAAC"}
|
|
@@ -318,8 +318,25 @@ export class FooterDataProvider {
|
|
|
318
318
|
// when watcher creation just failed. The path is recorded after the
|
|
319
319
|
// attempt because a failure synchronously clears watcher state.
|
|
320
320
|
this.reftableTablesListPath = tablesListPath;
|
|
321
|
+
let previousTablesListContent;
|
|
322
|
+
try {
|
|
323
|
+
previousTablesListContent = readFileSync(tablesListPath, "utf8");
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
// The file may disappear between existsSync and the first poll.
|
|
327
|
+
}
|
|
321
328
|
watchFile(tablesListPath, { interval: 250 }, (current, previous) => {
|
|
322
|
-
|
|
329
|
+
let contentChanged = false;
|
|
330
|
+
try {
|
|
331
|
+
const currentContent = readFileSync(tablesListPath, "utf8");
|
|
332
|
+
contentChanged = previousTablesListContent !== currentContent;
|
|
333
|
+
previousTablesListContent = currentContent;
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
contentChanged = true;
|
|
337
|
+
}
|
|
338
|
+
if (contentChanged ||
|
|
339
|
+
current.mtimeMs !== previous.mtimeMs ||
|
|
323
340
|
current.ctimeMs !== previous.ctimeMs ||
|
|
324
341
|
current.size !== previous.size) {
|
|
325
342
|
this.scheduleRefresh();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"footer-data-provider.js","sourceRoot":"","sources":["../../src/core/footer-data-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { type ExecFileException, execFile, spawnSync } from \"child_process\";\nimport { existsSync, type FSWatcher, readFileSync, type Stats, statSync, unwatchFile, watchFile } from \"fs\";\nimport { dirname, join, resolve } from \"path\";\nimport { closeWatcher, FS_WATCH_RETRY_DELAY_MS, watchWithErrorHandler } from \"../utils/fs-watch.ts\";\n\nexport type GitPaths = {\n\trepoDir: string;\n\tcommonGitDir: string;\n\theadPath: string;\n};\n\n/**\n * Find git metadata paths by walking up from cwd.\n * Handles both regular git repos (.git is a directory) and worktrees (.git is a file).\n */\nexport function findGitPaths(cwd: string): GitPaths | null {\n\tlet dir = cwd;\n\twhile (true) {\n\t\tconst gitPath = join(dir, \".git\");\n\t\tif (existsSync(gitPath)) {\n\t\t\ttry {\n\t\t\t\tconst stat = statSync(gitPath);\n\t\t\t\tif (stat.isFile()) {\n\t\t\t\t\tconst content = readFileSync(gitPath, \"utf8\").trim();\n\t\t\t\t\tif (content.startsWith(\"gitdir: \")) {\n\t\t\t\t\t\tconst gitDir = resolve(dir, content.slice(8).trim());\n\t\t\t\t\t\tconst headPath = join(gitDir, \"HEAD\");\n\t\t\t\t\t\tif (!existsSync(headPath)) return null;\n\t\t\t\t\t\tconst commonDirPath = join(gitDir, \"commondir\");\n\t\t\t\t\t\tconst commonGitDir = existsSync(commonDirPath)\n\t\t\t\t\t\t\t? resolve(gitDir, readFileSync(commonDirPath, \"utf8\").trim())\n\t\t\t\t\t\t\t: gitDir;\n\t\t\t\t\t\treturn { repoDir: dir, commonGitDir, headPath };\n\t\t\t\t\t}\n\t\t\t\t} else if (stat.isDirectory()) {\n\t\t\t\t\tconst headPath = join(gitPath, \"HEAD\");\n\t\t\t\t\tif (!existsSync(headPath)) return null;\n\t\t\t\t\treturn { repoDir: dir, commonGitDir: gitPath, headPath };\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) return null;\n\t\tdir = parent;\n\t}\n}\n\n/** Ask git for the current branch. Returns null on detached HEAD or if git is unavailable. */\nfunction resolveBranchWithGitSync(repoDir: string): string | null {\n\tconst result = spawnSync(\"git\", [\"--no-optional-locks\", \"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"], {\n\t\tcwd: repoDir,\n\t\tencoding: \"utf8\",\n\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t});\n\tconst branch = result.status === 0 ? result.stdout.trim() : \"\";\n\treturn branch || null;\n}\n\n/** Ask git for the current branch asynchronously. Returns null on detached HEAD or if git is unavailable. */\nfunction resolveBranchWithGitAsync(repoDir: string): Promise<string | null> {\n\treturn new Promise((resolvePromise) => {\n\t\texecFile(\n\t\t\t\"git\",\n\t\t\t[\"--no-optional-locks\", \"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"],\n\t\t\t{\n\t\t\t\tcwd: repoDir,\n\t\t\t\tencoding: \"utf8\",\n\t\t\t},\n\t\t\t(error: ExecFileException | null, stdout: string) => {\n\t\t\t\tif (error) {\n\t\t\t\t\tresolvePromise(null);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst branch = stdout.trim();\n\t\t\t\tresolvePromise(branch || null);\n\t\t\t},\n\t\t);\n\t});\n}\n\nfunction isWslEnvironment(): boolean {\n\treturn process.platform === \"linux\" && !!(process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP);\n}\n\nfunction isWindowsMountedRepoPath(repoDir: string): boolean {\n\treturn /^\\/mnt\\/[a-z](?:\\/|$)/i.test(repoDir);\n}\n\nfunction shouldPollGitHead(repoDir: string): boolean {\n\treturn isWslEnvironment() && isWindowsMountedRepoPath(repoDir);\n}\n\n/**\n * Provides git branch and extension statuses - data not otherwise accessible to extensions.\n * Context usage on ctx.getContextUsage(), token stats on ctx.sessionManager.getEntries(), model info on ctx.model.\n */\nexport class FooterDataProvider {\n\tprivate cwd: string;\n\tprivate static readonly WATCH_DEBOUNCE_MS = 500;\n\n\tprivate extensionStatuses = new Map<string, string>();\n\tprivate cachedBranch: string | null | undefined = undefined;\n\tprivate gitPaths: GitPaths | null | undefined = undefined;\n\tprivate headWatcher: FSWatcher | null = null;\n\tprivate headWatchFilePath: string | null = null;\n\tprivate headWatchFileListener: ((current: Stats, previous: Stats) => void) | null = null;\n\tprivate reftableWatcher: FSWatcher | null = null;\n\tprivate reftableTablesListWatcher: FSWatcher | null = null;\n\tprivate reftableTablesListPath: string | null = null;\n\tprivate branchChangeCallbacks = new Set<() => void>();\n\tprivate availableProviderCount = 0;\n\tprivate refreshTimer: ReturnType<typeof setTimeout> | null = null;\n\tprivate gitWatcherRetryTimer: ReturnType<typeof setTimeout> | null = null;\n\tprivate refreshInFlight = false;\n\tprivate refreshPending = false;\n\tprivate disposed = false;\n\n\tconstructor(cwd: string) {\n\t\tthis.cwd = cwd;\n\t\tthis.gitPaths = findGitPaths(cwd);\n\t\tthis.setupGitWatcher();\n\t}\n\n\t/** Current git branch, null if not in repo, \"detached\" if detached HEAD */\n\tgetGitBranch(): string | null {\n\t\tif (this.cachedBranch === undefined) {\n\t\t\tthis.cachedBranch = this.resolveGitBranchSync();\n\t\t}\n\t\treturn this.cachedBranch;\n\t}\n\n\t/** Extension status texts set via ctx.ui.setStatus() */\n\tgetExtensionStatuses(): ReadonlyMap<string, string> {\n\t\treturn this.extensionStatuses;\n\t}\n\n\t/** Subscribe to git branch changes. Returns unsubscribe function. */\n\tonBranchChange(callback: () => void): () => void {\n\t\tthis.branchChangeCallbacks.add(callback);\n\t\treturn () => this.branchChangeCallbacks.delete(callback);\n\t}\n\n\t/** Internal: set extension status */\n\tsetExtensionStatus(key: string, text: string | undefined): void {\n\t\tif (text === undefined) {\n\t\t\tthis.extensionStatuses.delete(key);\n\t\t} else {\n\t\t\tthis.extensionStatuses.set(key, text);\n\t\t}\n\t}\n\n\t/** Internal: clear extension statuses */\n\tclearExtensionStatuses(): void {\n\t\tthis.extensionStatuses.clear();\n\t}\n\n\t/** Number of unique providers with available models (for footer display) */\n\tgetAvailableProviderCount(): number {\n\t\treturn this.availableProviderCount;\n\t}\n\n\t/** Internal: update available provider count */\n\tsetAvailableProviderCount(count: number): void {\n\t\tthis.availableProviderCount = count;\n\t}\n\n\tsetCwd(cwd: string): void {\n\t\tif (this.cwd === cwd) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.cwd = cwd;\n\t\tif (this.refreshTimer) {\n\t\t\tclearTimeout(this.refreshTimer);\n\t\t\tthis.refreshTimer = null;\n\t\t}\n\t\tthis.clearGitWatchers();\n\t\tthis.cachedBranch = undefined;\n\t\tthis.gitPaths = findGitPaths(cwd);\n\t\tthis.setupGitWatcher();\n\t\tthis.notifyBranchChange();\n\t}\n\n\t/** Internal: cleanup */\n\tdispose(): void {\n\t\tthis.disposed = true;\n\t\tif (this.refreshTimer) {\n\t\t\tclearTimeout(this.refreshTimer);\n\t\t\tthis.refreshTimer = null;\n\t\t}\n\t\tthis.clearGitWatchers();\n\t\tthis.branchChangeCallbacks.clear();\n\t}\n\n\tprivate notifyBranchChange(): void {\n\t\tfor (const cb of this.branchChangeCallbacks) cb();\n\t}\n\n\tprivate scheduleRefresh(): void {\n\t\tif (this.disposed || this.refreshTimer) return;\n\t\tif (this.refreshInFlight) {\n\t\t\tthis.refreshPending = true;\n\t\t\treturn;\n\t\t}\n\t\tthis.refreshTimer = setTimeout(() => {\n\t\t\tthis.refreshTimer = null;\n\t\t\tvoid this.refreshGitBranchAsync();\n\t\t}, FooterDataProvider.WATCH_DEBOUNCE_MS);\n\t}\n\n\tprivate async refreshGitBranchAsync(): Promise<void> {\n\t\tif (this.disposed) return;\n\t\tif (this.refreshInFlight) {\n\t\t\tthis.refreshPending = true;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.refreshInFlight = true;\n\t\ttry {\n\t\t\tconst nextBranch = await this.resolveGitBranchAsync();\n\t\t\tif (this.disposed) return;\n\t\t\tif (this.cachedBranch !== undefined && this.cachedBranch !== nextBranch) {\n\t\t\t\tthis.cachedBranch = nextBranch;\n\t\t\t\tthis.notifyBranchChange();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.cachedBranch = nextBranch;\n\t\t} finally {\n\t\t\tthis.refreshInFlight = false;\n\t\t\tif (this.refreshPending && !this.disposed) {\n\t\t\t\tthis.refreshPending = false;\n\t\t\t\tthis.scheduleRefresh();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate resolveGitBranchSync(): string | null {\n\t\ttry {\n\t\t\tif (!this.gitPaths) return null;\n\t\t\tconst content = readFileSync(this.gitPaths.headPath, \"utf8\").trim();\n\t\t\tif (content.startsWith(\"ref: refs/heads/\")) {\n\t\t\t\tconst branch = content.slice(16);\n\t\t\t\treturn branch === \".invalid\" ? (resolveBranchWithGitSync(this.gitPaths.repoDir) ?? \"detached\") : branch;\n\t\t\t}\n\t\t\treturn \"detached\";\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate async resolveGitBranchAsync(): Promise<string | null> {\n\t\ttry {\n\t\t\tif (!this.gitPaths) return null;\n\t\t\tconst content = readFileSync(this.gitPaths.headPath, \"utf8\").trim();\n\t\t\tif (content.startsWith(\"ref: refs/heads/\")) {\n\t\t\t\tconst branch = content.slice(16);\n\t\t\t\treturn branch === \".invalid\"\n\t\t\t\t\t? ((await resolveBranchWithGitAsync(this.gitPaths.repoDir)) ?? \"detached\")\n\t\t\t\t\t: branch;\n\t\t\t}\n\t\t\treturn \"detached\";\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate clearGitWatchers(): void {\n\t\tcloseWatcher(this.headWatcher);\n\t\tthis.headWatcher = null;\n\t\tif (this.headWatchFilePath && this.headWatchFileListener) {\n\t\t\tunwatchFile(this.headWatchFilePath, this.headWatchFileListener);\n\t\t\tthis.headWatchFilePath = null;\n\t\t\tthis.headWatchFileListener = null;\n\t\t}\n\t\tcloseWatcher(this.reftableWatcher);\n\t\tthis.reftableWatcher = null;\n\t\tcloseWatcher(this.reftableTablesListWatcher);\n\t\tthis.reftableTablesListWatcher = null;\n\t\tif (this.reftableTablesListPath) {\n\t\t\tunwatchFile(this.reftableTablesListPath);\n\t\t\tthis.reftableTablesListPath = null;\n\t\t}\n\t\tif (this.gitWatcherRetryTimer) {\n\t\t\tclearTimeout(this.gitWatcherRetryTimer);\n\t\t\tthis.gitWatcherRetryTimer = null;\n\t\t}\n\t}\n\n\tprivate scheduleGitWatcherRetry(): void {\n\t\tif (this.disposed || this.gitWatcherRetryTimer) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.gitWatcherRetryTimer = setTimeout(() => {\n\t\t\tthis.gitWatcherRetryTimer = null;\n\t\t\tthis.setupGitWatcher();\n\t\t}, FS_WATCH_RETRY_DELAY_MS);\n\t}\n\n\tprivate handleGitWatcherError(): void {\n\t\tthis.clearGitWatchers();\n\t\tthis.scheduleGitWatcherRetry();\n\t}\n\n\tprivate setupGitWatcher(): void {\n\t\tthis.clearGitWatchers();\n\t\tif (!this.gitPaths) return;\n\n\t\tconst pollGitHead = shouldPollGitHead(this.gitPaths.repoDir);\n\n\t\t// Watch the directory containing HEAD, not HEAD itself.\n\t\t// Git uses atomic writes (write temp, rename over HEAD), which changes the inode.\n\t\t// fs.watch on a file stops working after the inode changes.\n\t\tthis.headWatcher = watchWithErrorHandler(\n\t\t\tdirname(this.gitPaths.headPath),\n\t\t\t(_eventType, filename) => {\n\t\t\t\tif (!filename || filename === \"HEAD\") {\n\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => this.handleGitWatcherError(),\n\t\t);\n\t\tif (pollGitHead) {\n\t\t\tthis.headWatchFilePath = this.gitPaths.headPath;\n\t\t\tthis.headWatchFileListener = (current, previous) => {\n\t\t\t\tif (\n\t\t\t\t\tcurrent.mtimeMs !== previous.mtimeMs ||\n\t\t\t\t\tcurrent.ctimeMs !== previous.ctimeMs ||\n\t\t\t\t\tcurrent.size !== previous.size\n\t\t\t\t) {\n\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t}\n\t\t\t};\n\t\t\twatchFile(this.headWatchFilePath, { interval: 1000 }, this.headWatchFileListener);\n\t\t}\n\t\t// In reftable repos, branch switches update files in the reftable directory\n\t\t// instead of HEAD. Watch it separately so the footer picks up those changes.\n\t\tconst reftableDir = join(this.gitPaths.commonGitDir, \"reftable\");\n\t\tif (existsSync(reftableDir)) {\n\t\t\tthis.reftableWatcher = watchWithErrorHandler(\n\t\t\t\treftableDir,\n\t\t\t\t() => {\n\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t},\n\t\t\t\t() => this.handleGitWatcherError(),\n\t\t\t);\n\n\t\t\tconst tablesListPath = join(reftableDir, \"tables.list\");\n\t\t\tif (existsSync(tablesListPath)) {\n\t\t\t\tthis.reftableTablesListWatcher = watchWithErrorHandler(\n\t\t\t\t\ttablesListPath,\n\t\t\t\t\t() => {\n\t\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t\t},\n\t\t\t\t\t() => this.handleGitWatcherError(),\n\t\t\t\t);\n\t\t\t\t// Polling is the fallback for environments where fs.watch is unusable\n\t\t\t\t// (descriptor limits, unsupported filesystems), so it must be armed even\n\t\t\t\t// when watcher creation just failed. The path is recorded after the\n\t\t\t\t// attempt because a failure synchronously clears watcher state.\n\t\t\t\tthis.reftableTablesListPath = tablesListPath;\n\t\t\t\twatchFile(tablesListPath, { interval: 250 }, (current, previous) => {\n\t\t\t\t\tif (\n\t\t\t\t\t\tcurrent.mtimeMs !== previous.mtimeMs ||\n\t\t\t\t\t\tcurrent.ctimeMs !== previous.ctimeMs ||\n\t\t\t\t\t\tcurrent.size !== previous.size\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** Read-only view for extensions - excludes setExtensionStatus, setAvailableProviderCount and dispose */\nexport type ReadonlyFooterDataProvider = Pick<\n\tFooterDataProvider,\n\t\"getGitBranch\" | \"getExtensionStatuses\" | \"getAvailableProviderCount\" | \"onBranchChange\"\n>;\n"]}
|
|
1
|
+
{"version":3,"file":"footer-data-provider.js","sourceRoot":"","sources":["../../src/core/footer-data-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { type ExecFileException, execFile, spawnSync } from \"child_process\";\nimport { existsSync, type FSWatcher, readFileSync, type Stats, statSync, unwatchFile, watchFile } from \"fs\";\nimport { dirname, join, resolve } from \"path\";\nimport { closeWatcher, FS_WATCH_RETRY_DELAY_MS, watchWithErrorHandler } from \"../utils/fs-watch.ts\";\n\nexport type GitPaths = {\n\trepoDir: string;\n\tcommonGitDir: string;\n\theadPath: string;\n};\n\n/**\n * Find git metadata paths by walking up from cwd.\n * Handles both regular git repos (.git is a directory) and worktrees (.git is a file).\n */\nexport function findGitPaths(cwd: string): GitPaths | null {\n\tlet dir = cwd;\n\twhile (true) {\n\t\tconst gitPath = join(dir, \".git\");\n\t\tif (existsSync(gitPath)) {\n\t\t\ttry {\n\t\t\t\tconst stat = statSync(gitPath);\n\t\t\t\tif (stat.isFile()) {\n\t\t\t\t\tconst content = readFileSync(gitPath, \"utf8\").trim();\n\t\t\t\t\tif (content.startsWith(\"gitdir: \")) {\n\t\t\t\t\t\tconst gitDir = resolve(dir, content.slice(8).trim());\n\t\t\t\t\t\tconst headPath = join(gitDir, \"HEAD\");\n\t\t\t\t\t\tif (!existsSync(headPath)) return null;\n\t\t\t\t\t\tconst commonDirPath = join(gitDir, \"commondir\");\n\t\t\t\t\t\tconst commonGitDir = existsSync(commonDirPath)\n\t\t\t\t\t\t\t? resolve(gitDir, readFileSync(commonDirPath, \"utf8\").trim())\n\t\t\t\t\t\t\t: gitDir;\n\t\t\t\t\t\treturn { repoDir: dir, commonGitDir, headPath };\n\t\t\t\t\t}\n\t\t\t\t} else if (stat.isDirectory()) {\n\t\t\t\t\tconst headPath = join(gitPath, \"HEAD\");\n\t\t\t\t\tif (!existsSync(headPath)) return null;\n\t\t\t\t\treturn { repoDir: dir, commonGitDir: gitPath, headPath };\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) return null;\n\t\tdir = parent;\n\t}\n}\n\n/** Ask git for the current branch. Returns null on detached HEAD or if git is unavailable. */\nfunction resolveBranchWithGitSync(repoDir: string): string | null {\n\tconst result = spawnSync(\"git\", [\"--no-optional-locks\", \"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"], {\n\t\tcwd: repoDir,\n\t\tencoding: \"utf8\",\n\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t});\n\tconst branch = result.status === 0 ? result.stdout.trim() : \"\";\n\treturn branch || null;\n}\n\n/** Ask git for the current branch asynchronously. Returns null on detached HEAD or if git is unavailable. */\nfunction resolveBranchWithGitAsync(repoDir: string): Promise<string | null> {\n\treturn new Promise((resolvePromise) => {\n\t\texecFile(\n\t\t\t\"git\",\n\t\t\t[\"--no-optional-locks\", \"symbolic-ref\", \"--quiet\", \"--short\", \"HEAD\"],\n\t\t\t{\n\t\t\t\tcwd: repoDir,\n\t\t\t\tencoding: \"utf8\",\n\t\t\t},\n\t\t\t(error: ExecFileException | null, stdout: string) => {\n\t\t\t\tif (error) {\n\t\t\t\t\tresolvePromise(null);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst branch = stdout.trim();\n\t\t\t\tresolvePromise(branch || null);\n\t\t\t},\n\t\t);\n\t});\n}\n\nfunction isWslEnvironment(): boolean {\n\treturn process.platform === \"linux\" && !!(process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP);\n}\n\nfunction isWindowsMountedRepoPath(repoDir: string): boolean {\n\treturn /^\\/mnt\\/[a-z](?:\\/|$)/i.test(repoDir);\n}\n\nfunction shouldPollGitHead(repoDir: string): boolean {\n\treturn isWslEnvironment() && isWindowsMountedRepoPath(repoDir);\n}\n\n/**\n * Provides git branch and extension statuses - data not otherwise accessible to extensions.\n * Context usage on ctx.getContextUsage(), token stats on ctx.sessionManager.getEntries(), model info on ctx.model.\n */\nexport class FooterDataProvider {\n\tprivate cwd: string;\n\tprivate static readonly WATCH_DEBOUNCE_MS = 500;\n\n\tprivate extensionStatuses = new Map<string, string>();\n\tprivate cachedBranch: string | null | undefined = undefined;\n\tprivate gitPaths: GitPaths | null | undefined = undefined;\n\tprivate headWatcher: FSWatcher | null = null;\n\tprivate headWatchFilePath: string | null = null;\n\tprivate headWatchFileListener: ((current: Stats, previous: Stats) => void) | null = null;\n\tprivate reftableWatcher: FSWatcher | null = null;\n\tprivate reftableTablesListWatcher: FSWatcher | null = null;\n\tprivate reftableTablesListPath: string | null = null;\n\tprivate branchChangeCallbacks = new Set<() => void>();\n\tprivate availableProviderCount = 0;\n\tprivate refreshTimer: ReturnType<typeof setTimeout> | null = null;\n\tprivate gitWatcherRetryTimer: ReturnType<typeof setTimeout> | null = null;\n\tprivate refreshInFlight = false;\n\tprivate refreshPending = false;\n\tprivate disposed = false;\n\n\tconstructor(cwd: string) {\n\t\tthis.cwd = cwd;\n\t\tthis.gitPaths = findGitPaths(cwd);\n\t\tthis.setupGitWatcher();\n\t}\n\n\t/** Current git branch, null if not in repo, \"detached\" if detached HEAD */\n\tgetGitBranch(): string | null {\n\t\tif (this.cachedBranch === undefined) {\n\t\t\tthis.cachedBranch = this.resolveGitBranchSync();\n\t\t}\n\t\treturn this.cachedBranch;\n\t}\n\n\t/** Extension status texts set via ctx.ui.setStatus() */\n\tgetExtensionStatuses(): ReadonlyMap<string, string> {\n\t\treturn this.extensionStatuses;\n\t}\n\n\t/** Subscribe to git branch changes. Returns unsubscribe function. */\n\tonBranchChange(callback: () => void): () => void {\n\t\tthis.branchChangeCallbacks.add(callback);\n\t\treturn () => this.branchChangeCallbacks.delete(callback);\n\t}\n\n\t/** Internal: set extension status */\n\tsetExtensionStatus(key: string, text: string | undefined): void {\n\t\tif (text === undefined) {\n\t\t\tthis.extensionStatuses.delete(key);\n\t\t} else {\n\t\t\tthis.extensionStatuses.set(key, text);\n\t\t}\n\t}\n\n\t/** Internal: clear extension statuses */\n\tclearExtensionStatuses(): void {\n\t\tthis.extensionStatuses.clear();\n\t}\n\n\t/** Number of unique providers with available models (for footer display) */\n\tgetAvailableProviderCount(): number {\n\t\treturn this.availableProviderCount;\n\t}\n\n\t/** Internal: update available provider count */\n\tsetAvailableProviderCount(count: number): void {\n\t\tthis.availableProviderCount = count;\n\t}\n\n\tsetCwd(cwd: string): void {\n\t\tif (this.cwd === cwd) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.cwd = cwd;\n\t\tif (this.refreshTimer) {\n\t\t\tclearTimeout(this.refreshTimer);\n\t\t\tthis.refreshTimer = null;\n\t\t}\n\t\tthis.clearGitWatchers();\n\t\tthis.cachedBranch = undefined;\n\t\tthis.gitPaths = findGitPaths(cwd);\n\t\tthis.setupGitWatcher();\n\t\tthis.notifyBranchChange();\n\t}\n\n\t/** Internal: cleanup */\n\tdispose(): void {\n\t\tthis.disposed = true;\n\t\tif (this.refreshTimer) {\n\t\t\tclearTimeout(this.refreshTimer);\n\t\t\tthis.refreshTimer = null;\n\t\t}\n\t\tthis.clearGitWatchers();\n\t\tthis.branchChangeCallbacks.clear();\n\t}\n\n\tprivate notifyBranchChange(): void {\n\t\tfor (const cb of this.branchChangeCallbacks) cb();\n\t}\n\n\tprivate scheduleRefresh(): void {\n\t\tif (this.disposed || this.refreshTimer) return;\n\t\tif (this.refreshInFlight) {\n\t\t\tthis.refreshPending = true;\n\t\t\treturn;\n\t\t}\n\t\tthis.refreshTimer = setTimeout(() => {\n\t\t\tthis.refreshTimer = null;\n\t\t\tvoid this.refreshGitBranchAsync();\n\t\t}, FooterDataProvider.WATCH_DEBOUNCE_MS);\n\t}\n\n\tprivate async refreshGitBranchAsync(): Promise<void> {\n\t\tif (this.disposed) return;\n\t\tif (this.refreshInFlight) {\n\t\t\tthis.refreshPending = true;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.refreshInFlight = true;\n\t\ttry {\n\t\t\tconst nextBranch = await this.resolveGitBranchAsync();\n\t\t\tif (this.disposed) return;\n\t\t\tif (this.cachedBranch !== undefined && this.cachedBranch !== nextBranch) {\n\t\t\t\tthis.cachedBranch = nextBranch;\n\t\t\t\tthis.notifyBranchChange();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.cachedBranch = nextBranch;\n\t\t} finally {\n\t\t\tthis.refreshInFlight = false;\n\t\t\tif (this.refreshPending && !this.disposed) {\n\t\t\t\tthis.refreshPending = false;\n\t\t\t\tthis.scheduleRefresh();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate resolveGitBranchSync(): string | null {\n\t\ttry {\n\t\t\tif (!this.gitPaths) return null;\n\t\t\tconst content = readFileSync(this.gitPaths.headPath, \"utf8\").trim();\n\t\t\tif (content.startsWith(\"ref: refs/heads/\")) {\n\t\t\t\tconst branch = content.slice(16);\n\t\t\t\treturn branch === \".invalid\" ? (resolveBranchWithGitSync(this.gitPaths.repoDir) ?? \"detached\") : branch;\n\t\t\t}\n\t\t\treturn \"detached\";\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate async resolveGitBranchAsync(): Promise<string | null> {\n\t\ttry {\n\t\t\tif (!this.gitPaths) return null;\n\t\t\tconst content = readFileSync(this.gitPaths.headPath, \"utf8\").trim();\n\t\t\tif (content.startsWith(\"ref: refs/heads/\")) {\n\t\t\t\tconst branch = content.slice(16);\n\t\t\t\treturn branch === \".invalid\"\n\t\t\t\t\t? ((await resolveBranchWithGitAsync(this.gitPaths.repoDir)) ?? \"detached\")\n\t\t\t\t\t: branch;\n\t\t\t}\n\t\t\treturn \"detached\";\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate clearGitWatchers(): void {\n\t\tcloseWatcher(this.headWatcher);\n\t\tthis.headWatcher = null;\n\t\tif (this.headWatchFilePath && this.headWatchFileListener) {\n\t\t\tunwatchFile(this.headWatchFilePath, this.headWatchFileListener);\n\t\t\tthis.headWatchFilePath = null;\n\t\t\tthis.headWatchFileListener = null;\n\t\t}\n\t\tcloseWatcher(this.reftableWatcher);\n\t\tthis.reftableWatcher = null;\n\t\tcloseWatcher(this.reftableTablesListWatcher);\n\t\tthis.reftableTablesListWatcher = null;\n\t\tif (this.reftableTablesListPath) {\n\t\t\tunwatchFile(this.reftableTablesListPath);\n\t\t\tthis.reftableTablesListPath = null;\n\t\t}\n\t\tif (this.gitWatcherRetryTimer) {\n\t\t\tclearTimeout(this.gitWatcherRetryTimer);\n\t\t\tthis.gitWatcherRetryTimer = null;\n\t\t}\n\t}\n\n\tprivate scheduleGitWatcherRetry(): void {\n\t\tif (this.disposed || this.gitWatcherRetryTimer) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.gitWatcherRetryTimer = setTimeout(() => {\n\t\t\tthis.gitWatcherRetryTimer = null;\n\t\t\tthis.setupGitWatcher();\n\t\t}, FS_WATCH_RETRY_DELAY_MS);\n\t}\n\n\tprivate handleGitWatcherError(): void {\n\t\tthis.clearGitWatchers();\n\t\tthis.scheduleGitWatcherRetry();\n\t}\n\n\tprivate setupGitWatcher(): void {\n\t\tthis.clearGitWatchers();\n\t\tif (!this.gitPaths) return;\n\n\t\tconst pollGitHead = shouldPollGitHead(this.gitPaths.repoDir);\n\n\t\t// Watch the directory containing HEAD, not HEAD itself.\n\t\t// Git uses atomic writes (write temp, rename over HEAD), which changes the inode.\n\t\t// fs.watch on a file stops working after the inode changes.\n\t\tthis.headWatcher = watchWithErrorHandler(\n\t\t\tdirname(this.gitPaths.headPath),\n\t\t\t(_eventType, filename) => {\n\t\t\t\tif (!filename || filename === \"HEAD\") {\n\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => this.handleGitWatcherError(),\n\t\t);\n\t\tif (pollGitHead) {\n\t\t\tthis.headWatchFilePath = this.gitPaths.headPath;\n\t\t\tthis.headWatchFileListener = (current, previous) => {\n\t\t\t\tif (\n\t\t\t\t\tcurrent.mtimeMs !== previous.mtimeMs ||\n\t\t\t\t\tcurrent.ctimeMs !== previous.ctimeMs ||\n\t\t\t\t\tcurrent.size !== previous.size\n\t\t\t\t) {\n\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t}\n\t\t\t};\n\t\t\twatchFile(this.headWatchFilePath, { interval: 1000 }, this.headWatchFileListener);\n\t\t}\n\t\t// In reftable repos, branch switches update files in the reftable directory\n\t\t// instead of HEAD. Watch it separately so the footer picks up those changes.\n\t\tconst reftableDir = join(this.gitPaths.commonGitDir, \"reftable\");\n\t\tif (existsSync(reftableDir)) {\n\t\t\tthis.reftableWatcher = watchWithErrorHandler(\n\t\t\t\treftableDir,\n\t\t\t\t() => {\n\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t},\n\t\t\t\t() => this.handleGitWatcherError(),\n\t\t\t);\n\n\t\t\tconst tablesListPath = join(reftableDir, \"tables.list\");\n\t\t\tif (existsSync(tablesListPath)) {\n\t\t\t\tthis.reftableTablesListWatcher = watchWithErrorHandler(\n\t\t\t\t\ttablesListPath,\n\t\t\t\t\t() => {\n\t\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t\t},\n\t\t\t\t\t() => this.handleGitWatcherError(),\n\t\t\t\t);\n\t\t\t\t// Polling is the fallback for environments where fs.watch is unusable\n\t\t\t\t// (descriptor limits, unsupported filesystems), so it must be armed even\n\t\t\t\t// when watcher creation just failed. The path is recorded after the\n\t\t\t\t// attempt because a failure synchronously clears watcher state.\n\t\t\t\tthis.reftableTablesListPath = tablesListPath;\n\t\t\t\tlet previousTablesListContent: string | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tpreviousTablesListContent = readFileSync(tablesListPath, \"utf8\");\n\t\t\t\t} catch {\n\t\t\t\t\t// The file may disappear between existsSync and the first poll.\n\t\t\t\t}\n\t\t\t\twatchFile(tablesListPath, { interval: 250 }, (current, previous) => {\n\t\t\t\t\tlet contentChanged = false;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst currentContent = readFileSync(tablesListPath, \"utf8\");\n\t\t\t\t\t\tcontentChanged = previousTablesListContent !== currentContent;\n\t\t\t\t\t\tpreviousTablesListContent = currentContent;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcontentChanged = true;\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\tcontentChanged ||\n\t\t\t\t\t\tcurrent.mtimeMs !== previous.mtimeMs ||\n\t\t\t\t\t\tcurrent.ctimeMs !== previous.ctimeMs ||\n\t\t\t\t\t\tcurrent.size !== previous.size\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis.scheduleRefresh();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** Read-only view for extensions - excludes setExtensionStatus, setAvailableProviderCount and dispose */\nexport type ReadonlyFooterDataProvider = Pick<\n\tFooterDataProvider,\n\t\"getGitBranch\" | \"getExtensionStatuses\" | \"getAvailableProviderCount\" | \"onBranchChange\"\n>;\n"]}
|
|
@@ -40,20 +40,8 @@ export declare function baseSelector(selector: Pick<FallbackSelector, "provider"
|
|
|
40
40
|
* consecutive upstream 500s, zero fallback attempts, terminal error).
|
|
41
41
|
* Users disable it with the `"*": []` tombstone.
|
|
42
42
|
*/
|
|
43
|
-
export declare const WILDCARD_CHAIN_KEY = "*";
|
|
44
|
-
/**
|
|
45
|
-
* Whether the user explicitly switched fallback OFF for this model with the
|
|
46
|
-
* documented `[]` tombstone (exact key, base key, or a bare family key that
|
|
47
|
-
* covers it). The shipped wildcard lane must never resurrect fallback against
|
|
48
|
-
* that instruction, so the wildcard gate consults this first.
|
|
49
|
-
*
|
|
50
|
-
* Bare-family matching is deliberately conservative: an ambiguous match
|
|
51
|
-
* suppresses the wildcard rather than overriding an explicit opt-out, because a
|
|
52
|
-
* surprising extra fallback hop is worse than a missing convenience lane.
|
|
53
|
-
*/
|
|
54
|
-
export declare function hasExplicitFallbackOptOut(chains: FallbackChains, currentModel: Model<Api>, currentThinking: ThinkingLevel | undefined): boolean;
|
|
55
43
|
export declare function canonicalizeFallbackChains(chains: FallbackChains, lookup: FallbackModelLookup): FallbackChains;
|
|
56
|
-
export declare function resolveChainKey(currentModel: Model<Api>, currentThinking: ThinkingLevel | undefined, chains: FallbackChains,
|
|
44
|
+
export declare function resolveChainKey(currentModel: Model<Api>, currentThinking: ThinkingLevel | undefined, chains: FallbackChains, _options?: {
|
|
57
45
|
allowWildcard?: boolean;
|
|
58
46
|
}): string | undefined;
|
|
59
47
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chains.d.ts","sourceRoot":"","sources":["../../../src/core/retry-fallback/chains.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"chains.d.ts","sourceRoot":"","sources":["../../../src/core/retry-fallback/chains.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAKxD,MAAM,WAAW,gBAAgB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;AAEzE,MAAM,MAAM,mBAAmB,GAC5B,SAAS,KAAK,CAAC,GAAG,CAAC,EAAE,GACrB;IACA,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IACvB,YAAY,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;IAC1C,iBAAiB,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;IAC/C,kBAAkB,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;CAC/C,CAAC;AA8BL,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,OAAO,CAEhF;AAeD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,GAAG,gBAAgB,GAAG,SAAS,CAkC5G;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,aAAa,CAAC,EAAE,aAAa,GAAG,MAAM,CAGvF;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,GAAG,IAAI,CAAC,GAAG,MAAM,CAExF;AAED;;;;;;;;GAQG;AACH;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,mBAAmB,GAAG,cAAc,CA4D9G;AAED,wBAAgB,eAAe,CAC9B,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,EACxB,eAAe,EAAE,aAAa,GAAG,SAAS,EAC1C,MAAM,EAAE,cAAc,EACtB,QAAQ,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,GACpC,MAAM,GAAG,SAAS,CAMpB;AAoBD;;;GAGG;AACH,wBAAgB,eAAe,CAC9B,YAAY,EAAE,SAAS,MAAM,EAAE,EAC/B,eAAe,EAAE,gBAAgB,GAAG,MAAM,GACxC,SAAS,MAAM,EAAE,CAQnB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isValidThinkingLevel } from "../../cli/args.js";
|
|
2
2
|
import { findExactModelReferenceMatch, parseModelPattern } from "../model-resolver.js";
|
|
3
|
-
import { MAX_PROVIDERS_PER_FAMILY,
|
|
3
|
+
import { MAX_PROVIDERS_PER_FAMILY, parseBareSelector, rankFamilyModels } from "./expansion.js";
|
|
4
4
|
function availableModels(lookup) {
|
|
5
5
|
return "getAll" in lookup ? lookup.getAll() : [...lookup];
|
|
6
6
|
}
|
|
@@ -99,35 +99,6 @@ export function baseSelector(selector) {
|
|
|
99
99
|
* consecutive upstream 500s, zero fallback attempts, terminal error).
|
|
100
100
|
* Users disable it with the `"*": []` tombstone.
|
|
101
101
|
*/
|
|
102
|
-
export const WILDCARD_CHAIN_KEY = "*";
|
|
103
|
-
/**
|
|
104
|
-
* Whether the user explicitly switched fallback OFF for this model with the
|
|
105
|
-
* documented `[]` tombstone (exact key, base key, or a bare family key that
|
|
106
|
-
* covers it). The shipped wildcard lane must never resurrect fallback against
|
|
107
|
-
* that instruction, so the wildcard gate consults this first.
|
|
108
|
-
*
|
|
109
|
-
* Bare-family matching is deliberately conservative: an ambiguous match
|
|
110
|
-
* suppresses the wildcard rather than overriding an explicit opt-out, because a
|
|
111
|
-
* surprising extra fallback hop is worse than a missing convenience lane.
|
|
112
|
-
*/
|
|
113
|
-
export function hasExplicitFallbackOptOut(chains, currentModel, currentThinking) {
|
|
114
|
-
const base = formatSelector(currentModel).toLowerCase();
|
|
115
|
-
const exact = currentThinking ? `${base}:${currentThinking}`.toLowerCase() : base;
|
|
116
|
-
for (const [key, entries] of Object.entries(chains)) {
|
|
117
|
-
if (!Array.isArray(entries) || !isChainTombstone(entries))
|
|
118
|
-
continue;
|
|
119
|
-
if (key === WILDCARD_CHAIN_KEY)
|
|
120
|
-
continue;
|
|
121
|
-
const normalizedKey = key.trim().toLowerCase();
|
|
122
|
-
const keyBase = normalizedBase(normalizedKey);
|
|
123
|
-
if (keyBase === base || normalizedKey === exact)
|
|
124
|
-
return true;
|
|
125
|
-
// Bare family key (no provider prefix): treat an id match as covering.
|
|
126
|
-
if (!normalizedKey.includes("/") && matchesFamily(currentModel, keyBase))
|
|
127
|
-
return true;
|
|
128
|
-
}
|
|
129
|
-
return false;
|
|
130
|
-
}
|
|
131
102
|
export function canonicalizeFallbackChains(chains, lookup) {
|
|
132
103
|
const models = availableModels(lookup);
|
|
133
104
|
const tiers = authTiers(lookup);
|
|
@@ -186,33 +157,16 @@ export function canonicalizeFallbackChains(chains, lookup) {
|
|
|
186
157
|
if (tombstones.has(normalizedBase(key)))
|
|
187
158
|
delete canonical[key];
|
|
188
159
|
}
|
|
189
|
-
// The wildcard key is not a model selector, so both loops above skip it.
|
|
190
|
-
// Its entries expand exactly like any other chain; a `[]` tombstone removes
|
|
191
|
-
// the lane entirely. Self-selection of the failing model is prevented at
|
|
192
|
-
// candidate time (nextCandidate's "self" skip), not here, because the
|
|
193
|
-
// wildcard has no key selector to filter against.
|
|
194
|
-
const wildcardEntries = chains[WILDCARD_CHAIN_KEY];
|
|
195
|
-
if (Array.isArray(wildcardEntries) && !isChainTombstone(wildcardEntries)) {
|
|
196
|
-
const canonicalEntries = expandEntries(wildcardEntries, WILDCARD_CHAIN_KEY);
|
|
197
|
-
if (canonicalEntries.length > 0)
|
|
198
|
-
canonical[WILDCARD_CHAIN_KEY] = canonicalEntries;
|
|
199
|
-
}
|
|
200
160
|
return canonical;
|
|
201
161
|
}
|
|
202
|
-
export function resolveChainKey(currentModel, currentThinking, chains,
|
|
162
|
+
export function resolveChainKey(currentModel, currentThinking, chains, _options) {
|
|
203
163
|
const base = formatSelector(currentModel);
|
|
204
164
|
const exact = currentThinking ? `${base}:${currentThinking}` : base;
|
|
205
165
|
if (Object.hasOwn(chains, exact))
|
|
206
166
|
return exact;
|
|
207
167
|
if (Object.hasOwn(chains, base))
|
|
208
168
|
return base;
|
|
209
|
-
|
|
210
|
-
// no chain of its own, and it must never hijack a session already walking a
|
|
211
|
-
// configured chain (the last rung of that chain usually has no key either).
|
|
212
|
-
// nextCandidate consults the active episode's chainKey before asking for it.
|
|
213
|
-
if (!options?.allowWildcard)
|
|
214
|
-
return undefined;
|
|
215
|
-
return Object.hasOwn(chains, WILDCARD_CHAIN_KEY) ? WILDCARD_CHAIN_KEY : undefined;
|
|
169
|
+
return undefined;
|
|
216
170
|
}
|
|
217
171
|
function formatParsedSelector(selector) {
|
|
218
172
|
const base = baseSelector(selector);
|