@cjhyy/code-shell-core 0.9.6 → 0.9.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/automation/scheduler.d.ts +3 -0
- package/dist/automation/scheduler.js +21 -0
- package/dist/context/manager.d.ts +8 -2
- package/dist/context/manager.js +20 -4
- package/dist/context/notes.d.ts +39 -0
- package/dist/context/notes.js +314 -0
- package/dist/engine/engine.d.ts +5 -4
- package/dist/engine/engine.js +79 -11
- package/dist/engine/run-tooling.d.ts +3 -0
- package/dist/engine/run-tooling.js +25 -23
- package/dist/engine/run-types.d.ts +4 -0
- package/dist/engine/subagent-spawner.d.ts +3 -0
- package/dist/engine/subagent-spawner.js +48 -17
- package/dist/engine/turn-loop.d.ts +10 -0
- package/dist/engine/turn-loop.js +91 -19
- package/dist/engine/types.d.ts +19 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/prompt/section-loader.js +1 -0
- package/dist/prompt/sections/browser.md +4 -2
- package/dist/prompt/sections/context-notes.md +9 -0
- package/dist/protocol/server.d.ts +1 -0
- package/dist/protocol/server.js +207 -19
- package/dist/protocol/types.d.ts +2 -0
- package/dist/session/session-manager.js +8 -7
- package/dist/session/transcript.d.ts +17 -0
- package/dist/session/transcript.js +271 -16
- package/dist/settings/schema.d.ts +9 -0
- package/dist/settings/schema.js +4 -0
- package/dist/themes/paths.js +20 -1
- package/dist/tool-system/browser-bridge.d.ts +3 -1
- package/dist/tool-system/browser-discovery.d.ts +6 -0
- package/dist/tool-system/browser-discovery.js +17 -0
- package/dist/tool-system/builtin/browser-tools.js +12 -8
- package/dist/tool-system/builtin/context-notes.d.ts +12 -0
- package/dist/tool-system/builtin/context-notes.js +188 -0
- package/dist/tool-system/builtin/index.js +47 -0
- package/dist/tool-system/builtin/mcp-tools.d.ts +5 -3
- package/dist/tool-system/builtin/mcp-tools.js +10 -10
- package/dist/tool-system/builtin/tool-search.js +15 -3
- package/dist/tool-system/context.d.ts +9 -0
- package/dist/tool-system/executor.js +5 -3
- package/dist/tool-system/mcp-compat.d.ts +3 -0
- package/dist/tool-system/mcp-compat.js +51 -0
- package/dist/tool-system/mcp-manager.d.ts +27 -26
- package/dist/tool-system/mcp-manager.js +273 -111
- package/dist/tool-system/mcp-workspace.d.ts +18 -0
- package/dist/tool-system/mcp-workspace.js +56 -0
- package/dist/tool-system/permission.d.ts +6 -0
- package/dist/tool-system/permission.js +45 -9
- package/dist/tool-system/plan-mode-allowlist.js +5 -0
- package/dist/tool-system/sandbox/seatbelt.js +71 -2
- package/dist/tool-system/session-tool-host.js +9 -1
- package/dist/types.d.ts +4 -2
- package/package.json +1 -1
|
@@ -100,7 +100,10 @@ export declare class InteractiveApprovalBackend implements ApprovalBackend {
|
|
|
100
100
|
private promptFn;
|
|
101
101
|
private legacyPromptTurn;
|
|
102
102
|
private legacyContext;
|
|
103
|
+
private requestGuard?;
|
|
103
104
|
constructor(approvalRouter?: ApprovalRouter);
|
|
105
|
+
/** Host lifecycle checks apply even to cached grants and queued prompts. */
|
|
106
|
+
setRequestGuard(guard: (request: ApprovalRequest) => ApprovalResult | undefined): void;
|
|
104
107
|
setPromptFn(fn: (request: ApprovalRequest) => Promise<ApprovalResult>): void;
|
|
105
108
|
clearPromptFn(): void;
|
|
106
109
|
/**
|
|
@@ -220,6 +223,9 @@ export declare class PermissionClassifier {
|
|
|
220
223
|
handleAsk(toolName: string, args: Record<string, unknown>, reason?: string, opts?: {
|
|
221
224
|
sessionId?: string;
|
|
222
225
|
}): Promise<boolean>;
|
|
226
|
+
handleAskResult(toolName: string, args: Record<string, unknown>, reason?: string, opts?: {
|
|
227
|
+
sessionId?: string;
|
|
228
|
+
}): Promise<ApprovalResult>;
|
|
223
229
|
/** Get denial warning message if the model keeps getting denied. */
|
|
224
230
|
getDenialWarning(toolName: string): string | undefined;
|
|
225
231
|
private matchesRule;
|
|
@@ -106,12 +106,16 @@ export class HeadlessApprovalBackend {
|
|
|
106
106
|
case "approve-all":
|
|
107
107
|
return { approved: true };
|
|
108
108
|
case "deny-all":
|
|
109
|
-
return { approved: false, reason: "headless deny-all mode" };
|
|
109
|
+
return { approved: false, failure: "policy_denied", reason: "headless deny-all mode" };
|
|
110
110
|
case "approve-read-only": {
|
|
111
111
|
if (READ_ONLY_TOOLS.has(req.toolName)) {
|
|
112
112
|
return { approved: true };
|
|
113
113
|
}
|
|
114
|
-
return {
|
|
114
|
+
return {
|
|
115
|
+
approved: false,
|
|
116
|
+
failure: "policy_denied",
|
|
117
|
+
reason: "read-only mode: write operations denied",
|
|
118
|
+
};
|
|
115
119
|
}
|
|
116
120
|
}
|
|
117
121
|
}
|
|
@@ -140,6 +144,7 @@ export class AutoApprovalBackend {
|
|
|
140
144
|
}
|
|
141
145
|
return {
|
|
142
146
|
approved: false,
|
|
147
|
+
failure: "unavailable",
|
|
143
148
|
reason: "auto mode: high-risk operation denied (no interactive approval available)",
|
|
144
149
|
};
|
|
145
150
|
}
|
|
@@ -157,6 +162,7 @@ export class AutoApprovalBackend {
|
|
|
157
162
|
}
|
|
158
163
|
return {
|
|
159
164
|
approved: false,
|
|
165
|
+
failure: "unavailable",
|
|
160
166
|
reason: "auto mode: medium-risk operation denied (no interactive approval available)",
|
|
161
167
|
};
|
|
162
168
|
}
|
|
@@ -223,9 +229,14 @@ export class InteractiveApprovalBackend {
|
|
|
223
229
|
savedProjectRules: [],
|
|
224
230
|
onProjectRules: null,
|
|
225
231
|
};
|
|
232
|
+
requestGuard;
|
|
226
233
|
constructor(approvalRouter = new ApprovalRouter()) {
|
|
227
234
|
this.approvalRouter = approvalRouter;
|
|
228
235
|
}
|
|
236
|
+
/** Host lifecycle checks apply even to cached grants and queued prompts. */
|
|
237
|
+
setRequestGuard(guard) {
|
|
238
|
+
this.requestGuard = guard;
|
|
239
|
+
}
|
|
229
240
|
setPromptFn(fn) {
|
|
230
241
|
this.promptFn = fn;
|
|
231
242
|
}
|
|
@@ -313,13 +324,20 @@ export class InteractiveApprovalBackend {
|
|
|
313
324
|
this.sessionStateById.get(sessionId) === state);
|
|
314
325
|
}
|
|
315
326
|
async requestApproval(req) {
|
|
327
|
+
const unavailable = this.requestGuard?.(req);
|
|
328
|
+
if (unavailable)
|
|
329
|
+
return unavailable;
|
|
316
330
|
const state = this.getSessionState(req.sessionId, true);
|
|
317
331
|
// Fast path: the operation may already be covered by a session rule.
|
|
318
332
|
const cached = state ? this.checkSessionRules(req, state) : null;
|
|
319
333
|
if (cached)
|
|
320
334
|
return cached;
|
|
321
335
|
if (!this.promptFn && !this.approvalRouter.hasConnections()) {
|
|
322
|
-
return {
|
|
336
|
+
return {
|
|
337
|
+
approved: false,
|
|
338
|
+
failure: "unavailable",
|
|
339
|
+
reason: "interactive approval backend has no prompt function",
|
|
340
|
+
};
|
|
323
341
|
}
|
|
324
342
|
// Serialize prompts and re-check rules when our turn comes (see promptTurn
|
|
325
343
|
// field doc): a burst of parallel tool calls all passes the fast path
|
|
@@ -336,6 +354,9 @@ export class InteractiveApprovalBackend {
|
|
|
336
354
|
}
|
|
337
355
|
try {
|
|
338
356
|
await prevTurn;
|
|
357
|
+
const unavailable = this.requestGuard?.(req);
|
|
358
|
+
if (unavailable)
|
|
359
|
+
return unavailable;
|
|
339
360
|
const activeState = this.isActiveSessionState(req.sessionId, state) ? state : null;
|
|
340
361
|
const nowCached = activeState ? this.checkSessionRules(req, activeState) : null;
|
|
341
362
|
if (nowCached)
|
|
@@ -374,12 +395,20 @@ export class InteractiveApprovalBackend {
|
|
|
374
395
|
? await fallback
|
|
375
396
|
: {
|
|
376
397
|
approved: false,
|
|
398
|
+
failure: "owner_lost",
|
|
377
399
|
reason: `no approval connection owns session ${req.sessionId}`,
|
|
378
400
|
};
|
|
379
401
|
}
|
|
380
402
|
else {
|
|
381
|
-
return {
|
|
403
|
+
return {
|
|
404
|
+
approved: false,
|
|
405
|
+
failure: "unavailable",
|
|
406
|
+
reason: "interactive approval backend has no prompt function",
|
|
407
|
+
};
|
|
382
408
|
}
|
|
409
|
+
const unavailable = this.requestGuard?.(req);
|
|
410
|
+
if (unavailable)
|
|
411
|
+
return unavailable;
|
|
383
412
|
const scope = result.scope ?? (result.always ? "session" : "once");
|
|
384
413
|
const activeState = this.isActiveSessionState(req.sessionId, state) ? state : null;
|
|
385
414
|
const context = activeState ?? (!req.sessionId ? this.legacyContext : null);
|
|
@@ -1322,13 +1351,20 @@ export class PermissionClassifier {
|
|
|
1322
1351
|
}
|
|
1323
1352
|
}
|
|
1324
1353
|
async handleAsk(toolName, args, reason, opts) {
|
|
1354
|
+
return (await this.handleAskResult(toolName, args, reason, opts)).approved;
|
|
1355
|
+
}
|
|
1356
|
+
async handleAskResult(toolName, args, reason, opts) {
|
|
1325
1357
|
if (this.defaultMode === "dontAsk") {
|
|
1326
1358
|
this.log.info("permission.auto_deny", {
|
|
1327
1359
|
cat: "permission",
|
|
1328
1360
|
tool: toolName,
|
|
1329
1361
|
reason: "dontAsk_mode",
|
|
1330
1362
|
});
|
|
1331
|
-
return
|
|
1363
|
+
return {
|
|
1364
|
+
approved: false,
|
|
1365
|
+
failure: "policy_denied",
|
|
1366
|
+
reason: "permission policy does not allow prompting",
|
|
1367
|
+
};
|
|
1332
1368
|
}
|
|
1333
1369
|
if (this.defaultMode === "bypassPermissions") {
|
|
1334
1370
|
this.log.info("permission.auto_allow", {
|
|
@@ -1336,7 +1372,7 @@ export class PermissionClassifier {
|
|
|
1336
1372
|
tool: toolName,
|
|
1337
1373
|
reason: "bypassPermissions_mode",
|
|
1338
1374
|
});
|
|
1339
|
-
return true;
|
|
1375
|
+
return { approved: true };
|
|
1340
1376
|
}
|
|
1341
1377
|
// Check denial tracker — if too many denials, auto-deny
|
|
1342
1378
|
if (this.denialTracker.shouldWarn(toolName)) {
|
|
@@ -1345,7 +1381,7 @@ export class PermissionClassifier {
|
|
|
1345
1381
|
tool: toolName,
|
|
1346
1382
|
reason: "denial_tracker_threshold",
|
|
1347
1383
|
});
|
|
1348
|
-
return false;
|
|
1384
|
+
return { approved: false, failure: "policy_denied", reason: "repeated user denials" };
|
|
1349
1385
|
}
|
|
1350
1386
|
const riskLevel = this.assessRisk(toolName, args);
|
|
1351
1387
|
const span = this.log.span("permission.ask", {
|
|
@@ -1385,7 +1421,7 @@ export class PermissionClassifier {
|
|
|
1385
1421
|
if (result.approved) {
|
|
1386
1422
|
this.denialTracker.recordSuccess(toolName);
|
|
1387
1423
|
}
|
|
1388
|
-
else {
|
|
1424
|
+
else if (!result.failure || result.failure === "denied") {
|
|
1389
1425
|
this.denialTracker.record(toolName);
|
|
1390
1426
|
}
|
|
1391
1427
|
this.emitApprovalEvent({
|
|
@@ -1403,7 +1439,7 @@ export class PermissionClassifier {
|
|
|
1403
1439
|
scope: result.scope,
|
|
1404
1440
|
reason: !result.approved ? result.reason : undefined,
|
|
1405
1441
|
});
|
|
1406
|
-
return result
|
|
1442
|
+
return result;
|
|
1407
1443
|
}
|
|
1408
1444
|
/** Get denial warning message if the model keeps getting denied. */
|
|
1409
1445
|
getDenialWarning(toolName) {
|
|
@@ -35,6 +35,7 @@ export const READ_ONLY_TOOLS = new Set([
|
|
|
35
35
|
"WebSearch",
|
|
36
36
|
"WebFetch",
|
|
37
37
|
"ToolSearch",
|
|
38
|
+
"SearchHistory",
|
|
38
39
|
]);
|
|
39
40
|
export const PLAN_MODE_ALLOWED_TOOLS = new Set([
|
|
40
41
|
// Plan lifecycle
|
|
@@ -60,6 +61,10 @@ export const PLAN_MODE_ALLOWED_TOOLS = new Set([
|
|
|
60
61
|
"TaskUpdate",
|
|
61
62
|
"TaskList",
|
|
62
63
|
"TaskGet",
|
|
64
|
+
// Session-local working state remains available across planning contexts.
|
|
65
|
+
"SaveContextNote",
|
|
66
|
+
"NewContext",
|
|
67
|
+
"SearchHistory",
|
|
63
68
|
// Bash: visible to the model; executor gates it to read-only commands.
|
|
64
69
|
"Bash",
|
|
65
70
|
]);
|
|
@@ -14,9 +14,43 @@
|
|
|
14
14
|
* sandbox-exec is technically deprecated by Apple but remains the only
|
|
15
15
|
* working OS-level sandbox on macOS and is what Codex CLI / Cursor use today.
|
|
16
16
|
*/
|
|
17
|
-
import {
|
|
17
|
+
import { execFileSync } from "node:child_process";
|
|
18
|
+
import { mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
18
19
|
import { tmpdir } from "node:os";
|
|
19
20
|
import { join } from "node:path";
|
|
21
|
+
/**
|
|
22
|
+
* Per-user MDS (Module Directory Service) scratch directory.
|
|
23
|
+
*
|
|
24
|
+
* Security.framework opens the keychain through MDS, which needs to write a
|
|
25
|
+
* lock file under the per-user Darwin cache dir. Without it *any* keychain
|
|
26
|
+
* read fails — see the `(allow file-write* …/mds)` clause in buildProfile()
|
|
27
|
+
* for why that matters and how it presents.
|
|
28
|
+
*
|
|
29
|
+
* `getconf DARWIN_USER_CACHE_DIR` reports the `/var/folders/…` form, but
|
|
30
|
+
* Seatbelt matches subpaths canonically (`/private/var/folders/…`), so the
|
|
31
|
+
* result is realpath'd — the same footgun expandConfig() handles for
|
|
32
|
+
* writableRoots. Resolved once per process; the value is stable for a user.
|
|
33
|
+
*/
|
|
34
|
+
let mdsCacheDir;
|
|
35
|
+
function resolveMdsCacheDir() {
|
|
36
|
+
if (mdsCacheDir !== undefined)
|
|
37
|
+
return mdsCacheDir;
|
|
38
|
+
try {
|
|
39
|
+
const cacheDir = execFileSync("/usr/bin/getconf", ["DARWIN_USER_CACHE_DIR"], {
|
|
40
|
+
encoding: "utf-8",
|
|
41
|
+
timeout: 5_000,
|
|
42
|
+
}).trim();
|
|
43
|
+
// Bail rather than emit a bogus rule if getconf returns something odd.
|
|
44
|
+
mdsCacheDir = cacheDir ? realpathSync(join(cacheDir, "mds")) : null;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// getconf missing/failed, or no mds dir yet on this host. Keychain reads
|
|
48
|
+
// stay broken, but that's strictly the pre-existing behavior — never fail
|
|
49
|
+
// the whole sandbox over it.
|
|
50
|
+
mdsCacheDir = null;
|
|
51
|
+
}
|
|
52
|
+
return mdsCacheDir;
|
|
53
|
+
}
|
|
20
54
|
export function createSeatbeltBackend(config) {
|
|
21
55
|
return {
|
|
22
56
|
name: "seatbelt",
|
|
@@ -44,6 +78,20 @@ export function createSeatbeltBackend(config) {
|
|
|
44
78
|
};
|
|
45
79
|
},
|
|
46
80
|
hintForBlockedOutput(stderr) {
|
|
81
|
+
// Keychain denials never say "sandbox" or "Operation not permitted" —
|
|
82
|
+
// they surface as an MDS error, or as a downstream tool blaming its own
|
|
83
|
+
// credentials ("token invalid") after silently falling back off the
|
|
84
|
+
// keyring. Match the MDS string specifically so the model stops
|
|
85
|
+
// recommending a re-login for what is a sandbox problem. This is a
|
|
86
|
+
// deterministic error string from Security.framework, not prose.
|
|
87
|
+
if (/Module Directory Service error/.test(stderr)) {
|
|
88
|
+
return ("\n[sandbox:seatbelt] A keychain read failed inside the sandbox " +
|
|
89
|
+
"(Security.framework/MDS). Any 'invalid token' / 'not logged in' " +
|
|
90
|
+
"message above is likely bogus — the credential is in the macOS " +
|
|
91
|
+
"keychain and was unreadable, NOT wrong. Do not re-run `auth login`. " +
|
|
92
|
+
"If this host has an unusual DARWIN_USER_CACHE_DIR, ask the user to " +
|
|
93
|
+
"add its `mds` dir to sandbox.writableRoots in settings.json.");
|
|
94
|
+
}
|
|
47
95
|
if (/Operation not permitted|sandbox/.test(stderr)) {
|
|
48
96
|
return ("\n[sandbox:seatbelt] A syscall was blocked by the sandbox. " +
|
|
49
97
|
"If this path should be writable or this network call legitimate, " +
|
|
@@ -57,6 +105,27 @@ function buildProfile(config) {
|
|
|
57
105
|
const writeAllows = config.writableRoots.map((p) => ` (subpath ${quote(p)})`).join("\n");
|
|
58
106
|
const readDenies = config.deniedReads.map((p) => ` (subpath ${quote(p)})`).join("\n");
|
|
59
107
|
const networkClause = config.network === "deny" ? "(deny network-outbound)" : "(allow network*)";
|
|
108
|
+
// Keychain access. Tools that store credentials in the macOS keychain
|
|
109
|
+
// (`gh`, `az`, `docker login`, anything calling /usr/bin/security) shell
|
|
110
|
+
// out to Security.framework, which reaches the keychain via MDS — and MDS
|
|
111
|
+
// needs to write a lock file under the per-user Darwin cache dir. That dir
|
|
112
|
+
// is outside the workspace, so a write-restricted profile blocks it.
|
|
113
|
+
//
|
|
114
|
+
// The failure is worth spelling out because it does NOT look like a
|
|
115
|
+
// sandbox denial: `security` exits 44 with "A Module Directory Service
|
|
116
|
+
// error has occurred", and callers treat that as "no keychain" and fall
|
|
117
|
+
// back to their plaintext config. `gh` then reports "The token in default
|
|
118
|
+
// is invalid" — pointing at the token, which is fine, instead of at the
|
|
119
|
+
// sandbox. Users burn a lot of time re-running `gh auth login` here.
|
|
120
|
+
//
|
|
121
|
+
// Verified empirically: this single clause is the minimal delta that makes
|
|
122
|
+
// `gh auth status` report `(keyring)` instead of `(default)` under an
|
|
123
|
+
// otherwise unchanged profile. Reads of ~/.ssh and writes outside the
|
|
124
|
+
// workspace stay denied — the grant is one scratch dir, not a hole.
|
|
125
|
+
const mdsDir = resolveMdsCacheDir();
|
|
126
|
+
const keychainClause = mdsDir
|
|
127
|
+
? `\n;; Keychain (Security.framework/MDS scratch)\n(allow file-write* (subpath ${quote(mdsDir)}))\n`
|
|
128
|
+
: "";
|
|
60
129
|
// SBPL evaluation note: when a broad `(allow file-read*)` and a specific
|
|
61
130
|
// `(deny file-read* (subpath …))` both match, the more specific subpath
|
|
62
131
|
// rule wins — order between the two clauses does not matter. We tested
|
|
@@ -88,7 +157,7 @@ ${writeAllows})
|
|
|
88
157
|
(literal "/dev/random")
|
|
89
158
|
(literal "/dev/urandom")
|
|
90
159
|
(literal "/dev/dtracehelper"))
|
|
91
|
-
|
|
160
|
+
${keychainClause}
|
|
92
161
|
;; IPC & system services common tools need
|
|
93
162
|
(allow mach-lookup)
|
|
94
163
|
(allow ipc-posix-shm)
|
|
@@ -87,9 +87,17 @@ export function createSessionToolHost(options) {
|
|
|
87
87
|
...options.contextOverrides,
|
|
88
88
|
sessionId: options.businessSessionId,
|
|
89
89
|
externalRuntime: true,
|
|
90
|
+
// This bridge owns tool calls, not a native model loop that can apply a
|
|
91
|
+
// context rollover. Never expose native working-memory controls here.
|
|
92
|
+
contextStrategy: undefined,
|
|
93
|
+
contextNotes: undefined,
|
|
90
94
|
planMode: options.planMode,
|
|
91
95
|
permissionMode: options.permissionMode,
|
|
92
|
-
toolVisibility: buildToolVisibility(
|
|
96
|
+
toolVisibility: buildToolVisibility({
|
|
97
|
+
...options.visibility,
|
|
98
|
+
contextStrategy: undefined,
|
|
99
|
+
hasBrowserAutomation: options.contextOverrides?.browser !== undefined,
|
|
100
|
+
}),
|
|
93
101
|
// Belt and braces with the exposure check in execute(): the executor
|
|
94
102
|
// enforces this too, so a future refactor that loses one still fails closed.
|
|
95
103
|
allowedToolNames: new Set(exposure.toolNames),
|
package/dist/types.d.ts
CHANGED
|
@@ -145,7 +145,7 @@ export interface RegisteredTool {
|
|
|
145
145
|
*/
|
|
146
146
|
timeoutMs?: number;
|
|
147
147
|
}
|
|
148
|
-
export type TranscriptEventType = "message" | "tool_use" | "tool_result" | "summary" | "context_transfer" | "range_archive" | "content_replace" | "file_history" | "plan_operation" | "session_meta" | "subagent" | "external_file_changes" | "turn_boundary" | "run_result" | "goal_progress" | "turn_stopped" | "error";
|
|
148
|
+
export type TranscriptEventType = "message" | "tool_use" | "tool_result" | "summary" | "context_transfer" | "context_note" | "context_checkpoint" | "range_archive" | "content_replace" | "file_history" | "plan_operation" | "session_meta" | "subagent" | "external_file_changes" | "turn_boundary" | "run_result" | "goal_progress" | "turn_stopped" | "error";
|
|
149
149
|
export interface TranscriptEvent {
|
|
150
150
|
id: string;
|
|
151
151
|
type: TranscriptEventType;
|
|
@@ -423,6 +423,8 @@ export type ApprovalResult = {
|
|
|
423
423
|
} | {
|
|
424
424
|
approved: false;
|
|
425
425
|
reason?: string;
|
|
426
|
+
/** A host/policy failure is distinct from an explicit user denial. */
|
|
427
|
+
failure?: "denied" | "cancelled" | "session_closed" | "owner_lost" | "timed_out" | "unavailable" | "policy_denied";
|
|
426
428
|
always?: boolean;
|
|
427
429
|
scope?: ApprovalScope;
|
|
428
430
|
};
|
|
@@ -586,7 +588,7 @@ export type StreamEvent = {
|
|
|
586
588
|
agentId?: string;
|
|
587
589
|
} | {
|
|
588
590
|
type: "context_compact";
|
|
589
|
-
strategy: "micro" | "summary" | "window" | "snip" | "emergency" | "compacted" | "range";
|
|
591
|
+
strategy: "micro" | "summary" | "window" | "snip" | "emergency" | "compacted" | "range" | "notes";
|
|
590
592
|
before: number;
|
|
591
593
|
after: number;
|
|
592
594
|
agentId?: string;
|
package/package.json
CHANGED