@moxxy/cli 0.12.3 → 0.12.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/dist/bin.js +549 -217
- package/dist/bin.js.map +1 -1
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -195,6 +195,22 @@ var init_log = __esm({
|
|
|
195
195
|
listeners = /* @__PURE__ */ new Set();
|
|
196
196
|
clearListeners = /* @__PURE__ */ new Set();
|
|
197
197
|
now;
|
|
198
|
+
/**
|
|
199
|
+
* Lazy secondary indexes so `ofType`/`byTurn` are O(matches) instead of an
|
|
200
|
+
* O(n) full-array `filter` per call (these back hot paths: token-accounting's
|
|
201
|
+
* `ofType('provider_response')`, lazy-tool gating's
|
|
202
|
+
* `ofType('tool_call_requested')`, and remote-session's per-turn
|
|
203
|
+
* `byTurn(turnId)` priming). Built lazily on first query so a cold/seeded log
|
|
204
|
+
* pays the one-time O(n) build only if anything ever queries it, then kept
|
|
205
|
+
* O(1) per append/ingest. Reset to `null` (rebuild-on-next-query) by
|
|
206
|
+
* `clear`/`rebase`, which mutate `events` wholesale.
|
|
207
|
+
*
|
|
208
|
+
* Each index holds the SAME event object references in their original
|
|
209
|
+
* append order — so a query returns an array deep-equal to the old
|
|
210
|
+
* `events.filter(...)` for every input.
|
|
211
|
+
*/
|
|
212
|
+
byType = null;
|
|
213
|
+
byTurnId = null;
|
|
198
214
|
/**
|
|
199
215
|
* Seq of the FIRST event this log holds. 0 for an authoring log; a mirror
|
|
200
216
|
* primed by a partial attach replay (runner protocol v6 `replay.start`)
|
|
@@ -224,11 +240,53 @@ var init_log = __esm({
|
|
|
224
240
|
slice(from = 0, to = this.base + this.events.length) {
|
|
225
241
|
return this.events.slice(Math.max(0, from - this.base), Math.max(0, to - this.base));
|
|
226
242
|
}
|
|
243
|
+
/** Build both secondary indexes from the current `events` array, preserving
|
|
244
|
+
* append order. Bucket arrays hold the original event references. */
|
|
245
|
+
buildIndexes() {
|
|
246
|
+
const byType = /* @__PURE__ */ new Map();
|
|
247
|
+
const byTurnId = /* @__PURE__ */ new Map();
|
|
248
|
+
for (const e3 of this.events) {
|
|
249
|
+
let typeBucket = byType.get(e3.type);
|
|
250
|
+
if (!typeBucket)
|
|
251
|
+
byType.set(e3.type, typeBucket = []);
|
|
252
|
+
typeBucket.push(e3);
|
|
253
|
+
let turnBucket = byTurnId.get(e3.turnId);
|
|
254
|
+
if (!turnBucket)
|
|
255
|
+
byTurnId.set(e3.turnId, turnBucket = []);
|
|
256
|
+
turnBucket.push(e3);
|
|
257
|
+
}
|
|
258
|
+
this.byType = byType;
|
|
259
|
+
this.byTurnId = byTurnId;
|
|
260
|
+
}
|
|
261
|
+
/** Append one event to the live indexes (no-op while they're cold). Called
|
|
262
|
+
* after the event is pushed to `events`, so order is preserved. */
|
|
263
|
+
indexEvent(e3) {
|
|
264
|
+
if (this.byType) {
|
|
265
|
+
const bucket = this.byType.get(e3.type);
|
|
266
|
+
if (bucket)
|
|
267
|
+
bucket.push(e3);
|
|
268
|
+
else
|
|
269
|
+
this.byType.set(e3.type, [e3]);
|
|
270
|
+
}
|
|
271
|
+
if (this.byTurnId) {
|
|
272
|
+
const bucket = this.byTurnId.get(e3.turnId);
|
|
273
|
+
if (bucket)
|
|
274
|
+
bucket.push(e3);
|
|
275
|
+
else
|
|
276
|
+
this.byTurnId.set(e3.turnId, [e3]);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
227
279
|
ofType(type) {
|
|
228
|
-
|
|
280
|
+
if (!this.byType)
|
|
281
|
+
this.buildIndexes();
|
|
282
|
+
const bucket = this.byType.get(type);
|
|
283
|
+
return bucket ? [...bucket] : [];
|
|
229
284
|
}
|
|
230
285
|
byTurn(turnId) {
|
|
231
|
-
|
|
286
|
+
if (!this.byTurnId)
|
|
287
|
+
this.buildIndexes();
|
|
288
|
+
const bucket = this.byTurnId.get(turnId);
|
|
289
|
+
return bucket ? [...bucket] : [];
|
|
232
290
|
}
|
|
233
291
|
toJSON() {
|
|
234
292
|
return [...this.events];
|
|
@@ -236,6 +294,7 @@ var init_log = __esm({
|
|
|
236
294
|
async append(partial) {
|
|
237
295
|
const event = materializeEvent(partial, this.base + this.events.length, this.now);
|
|
238
296
|
this.events.push(event);
|
|
297
|
+
this.indexEvent(event);
|
|
239
298
|
const snapshot = [...this.listeners];
|
|
240
299
|
for (const fn of snapshot) {
|
|
241
300
|
try {
|
|
@@ -262,6 +321,7 @@ var init_log = __esm({
|
|
|
262
321
|
if (event.seq !== this.base + this.events.length)
|
|
263
322
|
return;
|
|
264
323
|
this.events.push(event);
|
|
324
|
+
this.indexEvent(event);
|
|
265
325
|
const snapshot = [...this.listeners];
|
|
266
326
|
for (const fn of snapshot) {
|
|
267
327
|
try {
|
|
@@ -300,9 +360,13 @@ var init_log = __esm({
|
|
|
300
360
|
throw new Error(`EventLog.rebase(${seq}): seq must be a non-negative integer`);
|
|
301
361
|
}
|
|
302
362
|
this.base = seq;
|
|
363
|
+
this.byType = null;
|
|
364
|
+
this.byTurnId = null;
|
|
303
365
|
}
|
|
304
366
|
clear() {
|
|
305
367
|
this.events.length = 0;
|
|
368
|
+
this.byType = null;
|
|
369
|
+
this.byTurnId = null;
|
|
306
370
|
this.base = 0;
|
|
307
371
|
const snapshot = [...this.clearListeners];
|
|
308
372
|
for (const fn of snapshot) {
|
|
@@ -2224,6 +2288,18 @@ var init_host2 = __esm({
|
|
|
2224
2288
|
dataListeners = /* @__PURE__ */ new Set();
|
|
2225
2289
|
/** In-flight opens, so concurrent `open(kind)` calls share one instance. */
|
|
2226
2290
|
opening = /* @__PURE__ */ new Map();
|
|
2291
|
+
/**
|
|
2292
|
+
* Viewer attach count per kind. A surface is SHARED (the agent's tool + every
|
|
2293
|
+
* attached viewer drive the same PTY/page), so `open` retains and `close`
|
|
2294
|
+
* releases; the instance is only torn down when the last viewer detaches.
|
|
2295
|
+
* Without this, a single viewer's `close` would destroy the resource out from
|
|
2296
|
+
* under the others — and React StrictMode (dev) makes that routine: it
|
|
2297
|
+
* mounts → unmounts → remounts, so the first mount's late-resolving `open`
|
|
2298
|
+
* closes the very instance the remount just attached to, leaving `input`/
|
|
2299
|
+
* `resize` to hit a now-missing instance (output still flows from the
|
|
2300
|
+
* snapshot, but keystrokes/navigation silently vanish).
|
|
2301
|
+
*/
|
|
2302
|
+
refs = /* @__PURE__ */ new Map();
|
|
2227
2303
|
constructor(registry, ctx, logger) {
|
|
2228
2304
|
this.registry = registry;
|
|
2229
2305
|
this.ctx = ctx;
|
|
@@ -2256,28 +2332,25 @@ var init_host2 = __esm({
|
|
|
2256
2332
|
async open(kind3) {
|
|
2257
2333
|
const existing = this.instances.get(kind3);
|
|
2258
2334
|
if (existing) {
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
kind: existing.kind,
|
|
2262
|
-
...existing.snapshot ? { snapshot: existing.snapshot() } : {}
|
|
2263
|
-
};
|
|
2335
|
+
this.retain(kind3);
|
|
2336
|
+
return this.describe(existing);
|
|
2264
2337
|
}
|
|
2265
2338
|
const pending2 = this.opening.get(kind3);
|
|
2266
|
-
if (pending2)
|
|
2267
|
-
|
|
2339
|
+
if (pending2) {
|
|
2340
|
+
const res = await pending2;
|
|
2341
|
+
this.retain(kind3);
|
|
2342
|
+
return res;
|
|
2343
|
+
}
|
|
2268
2344
|
const def = this.registry.get(kind3);
|
|
2269
2345
|
if (!def)
|
|
2270
2346
|
throw new Error(`No surface registered for kind: ${kind3}`);
|
|
2271
2347
|
const promise = (async () => {
|
|
2272
2348
|
const instance = await def.open(this.ctx);
|
|
2273
2349
|
this.instances.set(kind3, instance);
|
|
2350
|
+
this.refs.set(kind3, 1);
|
|
2274
2351
|
const unsub = instance.onData((payload) => this.emit({ surfaceId: instance.id, kind: instance.kind, payload }));
|
|
2275
2352
|
this.unsubs.set(instance.id, unsub);
|
|
2276
|
-
return
|
|
2277
|
-
surfaceId: instance.id,
|
|
2278
|
-
kind: instance.kind,
|
|
2279
|
-
...instance.snapshot ? { snapshot: instance.snapshot() } : {}
|
|
2280
|
-
};
|
|
2353
|
+
return this.describe(instance);
|
|
2281
2354
|
})();
|
|
2282
2355
|
this.opening.set(kind3, promise);
|
|
2283
2356
|
try {
|
|
@@ -2302,9 +2375,16 @@ var init_host2 = __esm({
|
|
|
2302
2375
|
const instance = this.byId(surfaceId);
|
|
2303
2376
|
if (!instance)
|
|
2304
2377
|
return;
|
|
2378
|
+
const kind3 = instance.kind;
|
|
2379
|
+
const remaining = (this.refs.get(kind3) ?? 1) - 1;
|
|
2380
|
+
if (remaining > 0) {
|
|
2381
|
+
this.refs.set(kind3, remaining);
|
|
2382
|
+
return;
|
|
2383
|
+
}
|
|
2384
|
+
this.refs.delete(kind3);
|
|
2305
2385
|
this.unsubs.get(surfaceId)?.();
|
|
2306
2386
|
this.unsubs.delete(surfaceId);
|
|
2307
|
-
this.instances.delete(
|
|
2387
|
+
this.instances.delete(kind3);
|
|
2308
2388
|
try {
|
|
2309
2389
|
await instance.close();
|
|
2310
2390
|
} catch (err) {
|
|
@@ -2314,11 +2394,24 @@ var init_host2 = __esm({
|
|
|
2314
2394
|
});
|
|
2315
2395
|
}
|
|
2316
2396
|
}
|
|
2397
|
+
/** Bump the viewer attach count for an already-open kind. */
|
|
2398
|
+
retain(kind3) {
|
|
2399
|
+
this.refs.set(kind3, (this.refs.get(kind3) ?? 0) + 1);
|
|
2400
|
+
}
|
|
2401
|
+
describe(instance) {
|
|
2402
|
+
return {
|
|
2403
|
+
surfaceId: instance.id,
|
|
2404
|
+
kind: instance.kind,
|
|
2405
|
+
...instance.snapshot ? { snapshot: instance.snapshot() } : {}
|
|
2406
|
+
};
|
|
2407
|
+
}
|
|
2317
2408
|
onData(cb) {
|
|
2318
2409
|
this.dataListeners.add(cb);
|
|
2319
2410
|
return () => this.dataListeners.delete(cb);
|
|
2320
2411
|
}
|
|
2321
2412
|
async closeAll() {
|
|
2413
|
+
for (const kind3 of [...this.instances.keys()])
|
|
2414
|
+
this.refs.set(kind3, 1);
|
|
2322
2415
|
const ids = [...this.unsubs.keys()];
|
|
2323
2416
|
for (const id of ids)
|
|
2324
2417
|
await this.close(id);
|
|
@@ -3960,6 +4053,14 @@ var init_persistence = __esm({
|
|
|
3960
4053
|
* can flush.
|
|
3961
4054
|
*/
|
|
3962
4055
|
writeQueue = createMutex();
|
|
4056
|
+
/**
|
|
4057
|
+
* Memoized one-time setup: `mkdir -p` the sessions dir and create the empty
|
|
4058
|
+
* `.jsonl` (so resume lists the session before any event). Awaited by both
|
|
4059
|
+
* `attach` and `writeIndex` so an early debounced index flush can't race the
|
|
4060
|
+
* initial creation — but it runs the open+close syscalls ONCE, not on every
|
|
4061
|
+
* 250ms flush as before.
|
|
4062
|
+
*/
|
|
4063
|
+
ready = null;
|
|
3963
4064
|
closed = false;
|
|
3964
4065
|
logger;
|
|
3965
4066
|
/**
|
|
@@ -3997,7 +4098,7 @@ var init_persistence = __esm({
|
|
|
3997
4098
|
* reuses the same Session object.
|
|
3998
4099
|
*/
|
|
3999
4100
|
attach(log) {
|
|
4000
|
-
void this.
|
|
4101
|
+
void this.ensureReady().then(() => this.scheduleIndexWrite()).catch(() => void 0);
|
|
4001
4102
|
const unsub = log.subscribe((event) => {
|
|
4002
4103
|
if (this.closed)
|
|
4003
4104
|
return;
|
|
@@ -4112,19 +4213,27 @@ var init_persistence = __esm({
|
|
|
4112
4213
|
async writeIndex() {
|
|
4113
4214
|
try {
|
|
4114
4215
|
if (!this.closed) {
|
|
4115
|
-
await this.
|
|
4116
|
-
await this.ensureLogFile();
|
|
4216
|
+
await this.ensureReady();
|
|
4117
4217
|
}
|
|
4118
4218
|
await writeJsonAtomic(metaPath(this.dir, this.meta.id), this.meta);
|
|
4119
4219
|
} catch {
|
|
4120
4220
|
}
|
|
4121
4221
|
}
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4222
|
+
/** One-time, memoized: `mkdir -p` the dir + create the empty `.jsonl`. On
|
|
4223
|
+
* failure the latch is cleared so a later flush retries (matching the old
|
|
4224
|
+
* per-write ensureDir/ensureLogFile recoverability). */
|
|
4225
|
+
ensureReady() {
|
|
4226
|
+
if (!this.ready) {
|
|
4227
|
+
this.ready = (async () => {
|
|
4228
|
+
await promises.mkdir(this.dir, { recursive: true });
|
|
4229
|
+
const handle2 = await promises.open(this.logPath, "a");
|
|
4230
|
+
await handle2.close();
|
|
4231
|
+
})().catch((err) => {
|
|
4232
|
+
this.ready = null;
|
|
4233
|
+
throw err;
|
|
4234
|
+
});
|
|
4235
|
+
}
|
|
4236
|
+
return this.ready;
|
|
4128
4237
|
}
|
|
4129
4238
|
};
|
|
4130
4239
|
}
|
|
@@ -85197,35 +85306,40 @@ function handleSubagentEvent(e3, subagents, root, groupRef) {
|
|
|
85197
85306
|
return;
|
|
85198
85307
|
}
|
|
85199
85308
|
}
|
|
85200
|
-
function
|
|
85201
|
-
|
|
85202
|
-
|
|
85203
|
-
|
|
85204
|
-
|
|
85205
|
-
|
|
85206
|
-
|
|
85207
|
-
|
|
85208
|
-
|
|
85209
|
-
|
|
85309
|
+
function createFoldState(compactByName = EMPTY_COMPACT_MAP) {
|
|
85310
|
+
return {
|
|
85311
|
+
root: [],
|
|
85312
|
+
compactByName,
|
|
85313
|
+
callTargets: /* @__PURE__ */ new Map(),
|
|
85314
|
+
suppressedCallIds: /* @__PURE__ */ new Set(),
|
|
85315
|
+
pendingLoadSkillCallId: null,
|
|
85316
|
+
openScope: null,
|
|
85317
|
+
continuationSkillEvent: null,
|
|
85318
|
+
openLive: null,
|
|
85319
|
+
subagents: /* @__PURE__ */ new Map(),
|
|
85320
|
+
subagentGroup: { current: null }
|
|
85321
|
+
};
|
|
85322
|
+
}
|
|
85323
|
+
function stepFold(s2, e3) {
|
|
85210
85324
|
const pushBlock = (block) => {
|
|
85211
|
-
subagentGroup.current = null;
|
|
85212
|
-
if (openScope) {
|
|
85213
|
-
openScope.children.push(block);
|
|
85325
|
+
s2.subagentGroup.current = null;
|
|
85326
|
+
if (s2.openScope) {
|
|
85327
|
+
s2.openScope.children.push(block);
|
|
85214
85328
|
} else {
|
|
85215
|
-
root.push(block);
|
|
85329
|
+
s2.root.push(block);
|
|
85216
85330
|
}
|
|
85217
85331
|
};
|
|
85218
85332
|
const closeOpenLive = () => {
|
|
85219
|
-
if (openLive) {
|
|
85220
|
-
openLive.closed = true;
|
|
85221
|
-
openLive = null;
|
|
85333
|
+
if (s2.openLive) {
|
|
85334
|
+
s2.openLive.closed = true;
|
|
85335
|
+
s2.openLive = null;
|
|
85222
85336
|
}
|
|
85223
85337
|
};
|
|
85224
85338
|
const closeOpenScope = () => {
|
|
85225
85339
|
closeOpenLive();
|
|
85226
|
-
if (openScope) {
|
|
85227
|
-
openScope.closed = true;
|
|
85228
|
-
openScope = null;
|
|
85340
|
+
if (s2.openScope) {
|
|
85341
|
+
s2.openScope.closed = true;
|
|
85342
|
+
s2.openScope = null;
|
|
85229
85343
|
}
|
|
85230
85344
|
};
|
|
85231
85345
|
const removeBlockByCallId = (callId) => {
|
|
@@ -85237,12 +85351,12 @@ function pairToolEvents(events, compactByName = EMPTY_COMPACT_MAP) {
|
|
|
85237
85351
|
}
|
|
85238
85352
|
return false;
|
|
85239
85353
|
};
|
|
85240
|
-
if (openScope && removeFrom(openScope.children))
|
|
85354
|
+
if (s2.openScope && removeFrom(s2.openScope.children))
|
|
85241
85355
|
return;
|
|
85242
|
-
removeFrom(root);
|
|
85356
|
+
removeFrom(s2.root);
|
|
85243
85357
|
};
|
|
85244
85358
|
const markOrphansAtTurnBoundary = () => {
|
|
85245
|
-
for (const target of callTargets.values()) {
|
|
85359
|
+
for (const target of s2.callTargets.values()) {
|
|
85246
85360
|
if (target.outcome === null) {
|
|
85247
85361
|
target.outcome = {
|
|
85248
85362
|
type: "denied",
|
|
@@ -85250,116 +85364,119 @@ function pairToolEvents(events, compactByName = EMPTY_COMPACT_MAP) {
|
|
|
85250
85364
|
};
|
|
85251
85365
|
}
|
|
85252
85366
|
}
|
|
85253
|
-
callTargets.clear();
|
|
85367
|
+
s2.callTargets.clear();
|
|
85254
85368
|
};
|
|
85255
|
-
|
|
85256
|
-
|
|
85257
|
-
|
|
85258
|
-
|
|
85259
|
-
|
|
85260
|
-
|
|
85261
|
-
|
|
85262
|
-
|
|
85263
|
-
|
|
85264
|
-
|
|
85369
|
+
if (e3.type === "user_prompt") {
|
|
85370
|
+
closeOpenScope();
|
|
85371
|
+
markOrphansAtTurnBoundary();
|
|
85372
|
+
s2.pendingLoadSkillCallId = null;
|
|
85373
|
+
s2.continuationSkillEvent = null;
|
|
85374
|
+
s2.suppressedCallIds.clear();
|
|
85375
|
+
s2.subagentGroup.current = null;
|
|
85376
|
+
s2.root.push({ kind: "event", id: e3.id, event: e3 });
|
|
85377
|
+
return;
|
|
85378
|
+
}
|
|
85379
|
+
if (e3.type === "skill_invoked") {
|
|
85380
|
+
closeOpenScope();
|
|
85381
|
+
s2.continuationSkillEvent = null;
|
|
85382
|
+
if (s2.pendingLoadSkillCallId) {
|
|
85383
|
+
s2.suppressedCallIds.add(s2.pendingLoadSkillCallId);
|
|
85384
|
+
removeBlockByCallId(s2.pendingLoadSkillCallId);
|
|
85385
|
+
s2.pendingLoadSkillCallId = null;
|
|
85386
|
+
}
|
|
85387
|
+
s2.subagentGroup.current = null;
|
|
85388
|
+
s2.openScope = {
|
|
85389
|
+
kind: "skill-scope",
|
|
85390
|
+
id: e3.id,
|
|
85391
|
+
skillEvent: e3,
|
|
85392
|
+
children: [],
|
|
85393
|
+
closed: false
|
|
85394
|
+
};
|
|
85395
|
+
s2.root.push(s2.openScope);
|
|
85396
|
+
return;
|
|
85397
|
+
}
|
|
85398
|
+
if (e3.type === "tool_call_requested") {
|
|
85399
|
+
if (e3.name === "load_skill") {
|
|
85400
|
+
s2.pendingLoadSkillCallId = e3.callId;
|
|
85265
85401
|
}
|
|
85266
|
-
if (
|
|
85267
|
-
|
|
85268
|
-
continuationSkillEvent = null;
|
|
85269
|
-
if (pendingLoadSkillCallId) {
|
|
85270
|
-
suppressedCallIds.add(pendingLoadSkillCallId);
|
|
85271
|
-
removeBlockByCallId(pendingLoadSkillCallId);
|
|
85272
|
-
pendingLoadSkillCallId = null;
|
|
85273
|
-
}
|
|
85274
|
-
subagentGroup.current = null;
|
|
85275
|
-
openScope = {
|
|
85402
|
+
if (!s2.openScope && s2.continuationSkillEvent) {
|
|
85403
|
+
s2.openScope = {
|
|
85276
85404
|
kind: "skill-scope",
|
|
85277
|
-
id: e3.id
|
|
85278
|
-
skillEvent:
|
|
85405
|
+
id: `${s2.continuationSkillEvent.id}:cont:${e3.id}`,
|
|
85406
|
+
skillEvent: s2.continuationSkillEvent,
|
|
85279
85407
|
children: [],
|
|
85280
85408
|
closed: false
|
|
85281
85409
|
};
|
|
85282
|
-
root.push(openScope);
|
|
85283
|
-
|
|
85284
|
-
}
|
|
85285
|
-
|
|
85286
|
-
|
|
85287
|
-
|
|
85288
|
-
|
|
85289
|
-
|
|
85290
|
-
|
|
85291
|
-
|
|
85292
|
-
|
|
85293
|
-
|
|
85294
|
-
|
|
85295
|
-
closed: false
|
|
85296
|
-
};
|
|
85297
|
-
root.push(openScope);
|
|
85298
|
-
continuationSkillEvent = null;
|
|
85299
|
-
}
|
|
85300
|
-
const compact = FILE_DIFF_TOOL_NAMES.has(e3.name) ? void 0 : compactByName.get(e3.name);
|
|
85301
|
-
if (compact) {
|
|
85302
|
-
if (!openLive) {
|
|
85303
|
-
openLive = { kind: "live-tools", id: e3.id, calls: [], closed: false };
|
|
85304
|
-
pushBlock(openLive);
|
|
85305
|
-
}
|
|
85306
|
-
const call = { id: e3.id, request: e3, compact, outcome: null };
|
|
85307
|
-
openLive.calls.push(call);
|
|
85308
|
-
callTargets.set(e3.callId, call);
|
|
85309
|
-
continue;
|
|
85310
|
-
}
|
|
85311
|
-
closeOpenLive();
|
|
85312
|
-
const block = {
|
|
85313
|
-
kind: "tool-call",
|
|
85314
|
-
id: e3.id,
|
|
85315
|
-
request: e3,
|
|
85316
|
-
outcome: null
|
|
85317
|
-
};
|
|
85318
|
-
callTargets.set(e3.callId, block);
|
|
85319
|
-
pushBlock(block);
|
|
85320
|
-
continue;
|
|
85321
|
-
}
|
|
85322
|
-
if (e3.type === "tool_result") {
|
|
85323
|
-
if (suppressedCallIds.has(e3.callId))
|
|
85324
|
-
continue;
|
|
85325
|
-
const target = callTargets.get(e3.callId);
|
|
85326
|
-
if (target) {
|
|
85327
|
-
target.outcome = e3;
|
|
85328
|
-
continue;
|
|
85329
|
-
}
|
|
85330
|
-
}
|
|
85331
|
-
if (e3.type === "tool_call_denied") {
|
|
85332
|
-
if (suppressedCallIds.has(e3.callId))
|
|
85333
|
-
continue;
|
|
85334
|
-
const target = callTargets.get(e3.callId);
|
|
85335
|
-
if (target) {
|
|
85336
|
-
target.outcome = { type: "denied", reason: e3.reason };
|
|
85337
|
-
continue;
|
|
85338
|
-
}
|
|
85410
|
+
s2.root.push(s2.openScope);
|
|
85411
|
+
s2.continuationSkillEvent = null;
|
|
85412
|
+
}
|
|
85413
|
+
const compact = FILE_DIFF_TOOL_NAMES.has(e3.name) ? void 0 : s2.compactByName.get(e3.name);
|
|
85414
|
+
if (compact) {
|
|
85415
|
+
if (!s2.openLive) {
|
|
85416
|
+
s2.openLive = { kind: "live-tools", id: e3.id, calls: [], closed: false };
|
|
85417
|
+
pushBlock(s2.openLive);
|
|
85418
|
+
}
|
|
85419
|
+
const call = { id: e3.id, request: e3, compact, outcome: null };
|
|
85420
|
+
s2.openLive.calls.push(call);
|
|
85421
|
+
s2.callTargets.set(e3.callId, call);
|
|
85422
|
+
return;
|
|
85339
85423
|
}
|
|
85340
|
-
|
|
85341
|
-
|
|
85424
|
+
closeOpenLive();
|
|
85425
|
+
const block = {
|
|
85426
|
+
kind: "tool-call",
|
|
85427
|
+
id: e3.id,
|
|
85428
|
+
request: e3,
|
|
85429
|
+
outcome: null
|
|
85430
|
+
};
|
|
85431
|
+
s2.callTargets.set(e3.callId, block);
|
|
85432
|
+
pushBlock(block);
|
|
85433
|
+
return;
|
|
85434
|
+
}
|
|
85435
|
+
if (e3.type === "tool_result") {
|
|
85436
|
+
if (s2.suppressedCallIds.has(e3.callId))
|
|
85437
|
+
return;
|
|
85438
|
+
const target = s2.callTargets.get(e3.callId);
|
|
85439
|
+
if (target) {
|
|
85440
|
+
target.outcome = e3;
|
|
85441
|
+
return;
|
|
85342
85442
|
}
|
|
85343
|
-
|
|
85344
|
-
|
|
85345
|
-
|
|
85346
|
-
|
|
85347
|
-
|
|
85348
|
-
|
|
85349
|
-
|
|
85350
|
-
|
|
85351
|
-
}
|
|
85352
|
-
subagentGroup.current = null;
|
|
85353
|
-
root.push({ kind: "event", id: e3.id, event: e3 });
|
|
85354
|
-
continue;
|
|
85443
|
+
}
|
|
85444
|
+
if (e3.type === "tool_call_denied") {
|
|
85445
|
+
if (s2.suppressedCallIds.has(e3.callId))
|
|
85446
|
+
return;
|
|
85447
|
+
const target = s2.callTargets.get(e3.callId);
|
|
85448
|
+
if (target) {
|
|
85449
|
+
target.outcome = { type: "denied", reason: e3.reason };
|
|
85450
|
+
return;
|
|
85355
85451
|
}
|
|
85356
|
-
|
|
85357
|
-
|
|
85358
|
-
|
|
85452
|
+
}
|
|
85453
|
+
if (e3.type === "tool_call_approved") {
|
|
85454
|
+
return;
|
|
85455
|
+
}
|
|
85456
|
+
if (e3.type === "assistant_message") {
|
|
85457
|
+
closeOpenLive();
|
|
85458
|
+
if (s2.openScope) {
|
|
85459
|
+
s2.continuationSkillEvent = s2.openScope.skillEvent;
|
|
85460
|
+
s2.openScope.closed = true;
|
|
85461
|
+
s2.openScope = null;
|
|
85462
|
+
} else {
|
|
85463
|
+
s2.continuationSkillEvent = null;
|
|
85359
85464
|
}
|
|
85360
|
-
|
|
85465
|
+
s2.subagentGroup.current = null;
|
|
85466
|
+
s2.root.push({ kind: "event", id: e3.id, event: e3 });
|
|
85467
|
+
return;
|
|
85361
85468
|
}
|
|
85362
|
-
|
|
85469
|
+
if (e3.type === "plugin_event" && e3.pluginId === SUBAGENT_PLUGIN_ID2) {
|
|
85470
|
+
handleSubagentEvent(e3, s2.subagents, s2.root, s2.subagentGroup);
|
|
85471
|
+
return;
|
|
85472
|
+
}
|
|
85473
|
+
pushBlock({ kind: "event", id: e3.id, event: e3 });
|
|
85474
|
+
}
|
|
85475
|
+
function pairToolEvents(events, compactByName = EMPTY_COMPACT_MAP) {
|
|
85476
|
+
const state = createFoldState(compactByName);
|
|
85477
|
+
for (const e3 of events)
|
|
85478
|
+
stepFold(state, e3);
|
|
85479
|
+
return state.root;
|
|
85363
85480
|
}
|
|
85364
85481
|
function isSettled(block) {
|
|
85365
85482
|
if (block.kind === "event")
|
|
@@ -85445,13 +85562,97 @@ function countToolCalls(blocks) {
|
|
|
85445
85562
|
}
|
|
85446
85563
|
return n2;
|
|
85447
85564
|
}
|
|
85448
|
-
var SUBAGENT_PLUGIN_ID2, FILE_DIFF_TOOL_NAMES, EMPTY_COMPACT_MAP;
|
|
85565
|
+
var SUBAGENT_PLUGIN_ID2, FILE_DIFF_TOOL_NAMES, EMPTY_COMPACT_MAP, IncrementalFold;
|
|
85449
85566
|
var init_pair_events = __esm({
|
|
85450
85567
|
"../chat-model/dist/pair-events.js"() {
|
|
85451
85568
|
init_format();
|
|
85452
85569
|
SUBAGENT_PLUGIN_ID2 = "@moxxy/subagents";
|
|
85453
85570
|
FILE_DIFF_TOOL_NAMES = /* @__PURE__ */ new Set(["Write", "Edit"]);
|
|
85454
85571
|
EMPTY_COMPACT_MAP = /* @__PURE__ */ new Map();
|
|
85572
|
+
IncrementalFold = class {
|
|
85573
|
+
state;
|
|
85574
|
+
prefixLength = 0;
|
|
85575
|
+
rev = 0;
|
|
85576
|
+
/** `id` of the first / last event folded so far — used to detect when the
|
|
85577
|
+
* source array's prefix has shifted (a scroll-up prepend) or been replaced
|
|
85578
|
+
* (/clear, a fresh session), in which case the carried fold state is no
|
|
85579
|
+
* longer valid and we must rebuild from scratch. */
|
|
85580
|
+
headId = null;
|
|
85581
|
+
tailId = null;
|
|
85582
|
+
constructor(compactByName = EMPTY_COMPACT_MAP) {
|
|
85583
|
+
this.state = createFoldState(compactByName);
|
|
85584
|
+
}
|
|
85585
|
+
/** Number of events folded so far (the high-water mark). */
|
|
85586
|
+
get length() {
|
|
85587
|
+
return this.prefixLength;
|
|
85588
|
+
}
|
|
85589
|
+
/** Bumps whenever the folded tree may have changed (every `push`). Use as
|
|
85590
|
+
* a memo key instead of the (stable) `tree()` reference. */
|
|
85591
|
+
get version() {
|
|
85592
|
+
return this.rev;
|
|
85593
|
+
}
|
|
85594
|
+
/** Fold one freshly-committed event onto the existing tree. */
|
|
85595
|
+
push(event) {
|
|
85596
|
+
stepFold(this.state, event);
|
|
85597
|
+
if (this.prefixLength === 0)
|
|
85598
|
+
this.headId = event.id;
|
|
85599
|
+
this.tailId = event.id;
|
|
85600
|
+
this.prefixLength += 1;
|
|
85601
|
+
this.rev += 1;
|
|
85602
|
+
}
|
|
85603
|
+
/** Fold a batch of newly-committed events (e.g. a replayed page). */
|
|
85604
|
+
pushMany(events) {
|
|
85605
|
+
for (const e3 of events)
|
|
85606
|
+
this.push(e3);
|
|
85607
|
+
}
|
|
85608
|
+
/**
|
|
85609
|
+
* Re-sync to `events` when the source array is the authoritative log. Folds
|
|
85610
|
+
* only the tail past the current high-water mark when `events` extends the
|
|
85611
|
+
* already-folded prefix unchanged (the common live-append case), and
|
|
85612
|
+
* rebuilds from scratch only when that prefix shifted or was replaced (a
|
|
85613
|
+
* scroll-up prepend, /clear, a fresh session). Returns the (stable) root.
|
|
85614
|
+
*
|
|
85615
|
+
* Prefix-unchanged is detected by event `id`: the log never rewrites a
|
|
85616
|
+
* settled event in place (only its tool outcome, which the fold owns), so
|
|
85617
|
+
* matching head+tail ids over an unshrunk length proves the leading
|
|
85618
|
+
* `prefixLength` events are exactly the ones already folded.
|
|
85619
|
+
*/
|
|
85620
|
+
syncTo(events) {
|
|
85621
|
+
if (this.canExtend(events)) {
|
|
85622
|
+
for (let i2 = this.prefixLength; i2 < events.length; i2 += 1)
|
|
85623
|
+
this.push(events[i2]);
|
|
85624
|
+
return this.state.root;
|
|
85625
|
+
}
|
|
85626
|
+
this.reset();
|
|
85627
|
+
this.pushMany(events);
|
|
85628
|
+
return this.state.root;
|
|
85629
|
+
}
|
|
85630
|
+
/** Discard all state — folds again from empty. */
|
|
85631
|
+
reset() {
|
|
85632
|
+
this.state = createFoldState(this.state.compactByName);
|
|
85633
|
+
this.prefixLength = 0;
|
|
85634
|
+
this.headId = null;
|
|
85635
|
+
this.tailId = null;
|
|
85636
|
+
this.rev += 1;
|
|
85637
|
+
}
|
|
85638
|
+
/** The folded block tree (stable reference, mutated in place). */
|
|
85639
|
+
tree() {
|
|
85640
|
+
return this.state.root;
|
|
85641
|
+
}
|
|
85642
|
+
/** True when `events` is the already-folded prefix plus zero or more new
|
|
85643
|
+
* tail events — i.e. a pure append. Requires the head id to still match
|
|
85644
|
+
* (no prepend) and the event at `prefixLength-1` to be the last one we
|
|
85645
|
+
* folded (no in-place rewrite or replacement of the prefix). */
|
|
85646
|
+
canExtend(events) {
|
|
85647
|
+
if (this.prefixLength === 0)
|
|
85648
|
+
return true;
|
|
85649
|
+
if (events.length < this.prefixLength)
|
|
85650
|
+
return false;
|
|
85651
|
+
if (events[0].id !== this.headId)
|
|
85652
|
+
return false;
|
|
85653
|
+
return events[this.prefixLength - 1].id === this.tailId;
|
|
85654
|
+
}
|
|
85655
|
+
};
|
|
85455
85656
|
}
|
|
85456
85657
|
});
|
|
85457
85658
|
|
|
@@ -86090,6 +86291,31 @@ var init_BlockLine = __esm({
|
|
|
86090
86291
|
});
|
|
86091
86292
|
|
|
86092
86293
|
// ../plugin-cli/dist/components/chat/StreamingPreview.js
|
|
86294
|
+
function lastNonEmptyLineShown(content, innerCols) {
|
|
86295
|
+
let end = content.length;
|
|
86296
|
+
let chosenStart = -1;
|
|
86297
|
+
let chosenEnd = -1;
|
|
86298
|
+
while (end > 0) {
|
|
86299
|
+
const nl = content.lastIndexOf("\n", end - 1);
|
|
86300
|
+
const start = nl + 1;
|
|
86301
|
+
if (content.slice(start, end).trim()) {
|
|
86302
|
+
chosenStart = start;
|
|
86303
|
+
chosenEnd = end;
|
|
86304
|
+
break;
|
|
86305
|
+
}
|
|
86306
|
+
if (start === 0)
|
|
86307
|
+
break;
|
|
86308
|
+
end = nl;
|
|
86309
|
+
}
|
|
86310
|
+
let line;
|
|
86311
|
+
if (chosenStart >= 0) {
|
|
86312
|
+
line = content.slice(chosenStart, chosenEnd);
|
|
86313
|
+
} else {
|
|
86314
|
+
const lastNl = content.lastIndexOf("\n");
|
|
86315
|
+
line = lastNl < 0 ? content : content.slice(lastNl + 1);
|
|
86316
|
+
}
|
|
86317
|
+
return line.length > innerCols ? `\u2026${line.slice(line.length - (innerCols - 1))}` : line;
|
|
86318
|
+
}
|
|
86093
86319
|
function tailForViewport(content) {
|
|
86094
86320
|
return content;
|
|
86095
86321
|
}
|
|
@@ -86103,17 +86329,7 @@ var init_StreamingPreview = __esm({
|
|
|
86103
86329
|
StreamingPreview = (0, import_react40.memo)(function StreamingPreview2({ content, dim: dim3 }) {
|
|
86104
86330
|
const cols = process.stdout.columns ?? 80;
|
|
86105
86331
|
const innerCols = Math.max(20, cols - 4);
|
|
86106
|
-
const
|
|
86107
|
-
let line = "";
|
|
86108
|
-
for (let i2 = lines.length - 1; i2 >= 0; i2 -= 1) {
|
|
86109
|
-
if (lines[i2].trim()) {
|
|
86110
|
-
line = lines[i2];
|
|
86111
|
-
break;
|
|
86112
|
-
}
|
|
86113
|
-
}
|
|
86114
|
-
if (!line)
|
|
86115
|
-
line = lines[lines.length - 1] ?? "";
|
|
86116
|
-
const shown = line.length > innerCols ? `\u2026${line.slice(line.length - (innerCols - 1))}` : line;
|
|
86332
|
+
const shown = lastNonEmptyLineShown(content, innerCols);
|
|
86117
86333
|
return (0, import_jsx_runtime19.jsxs)(Box_default, { flexDirection: "row", marginTop: 1, children: [(0, import_jsx_runtime19.jsx)(Box_default, { marginRight: 1, children: (0, import_jsx_runtime19.jsx)(Text, { dimColor: true, children: Glyphs.filled }) }), (0, import_jsx_runtime19.jsx)(Text, { dimColor: dim3, children: shown || " " })] });
|
|
86118
86334
|
});
|
|
86119
86335
|
}
|
|
@@ -86130,16 +86346,26 @@ var init_ChatView = __esm({
|
|
|
86130
86346
|
init_dist8();
|
|
86131
86347
|
await init_StreamingPreview();
|
|
86132
86348
|
ChatView = ({ events, streamingDelta, reasoningDelta, expandToolOutputs, compactTools, hideLive }) => {
|
|
86133
|
-
const
|
|
86349
|
+
const foldRef = (0, import_react41.useRef)(null);
|
|
86350
|
+
const compactRef = (0, import_react41.useRef)(void 0);
|
|
86351
|
+
const blocks = (0, import_react41.useMemo)(() => {
|
|
86352
|
+
if (typeof IncrementalFold !== "function")
|
|
86353
|
+
return pairToolEvents(events, compactTools);
|
|
86354
|
+
if (!foldRef.current || compactRef.current !== compactTools) {
|
|
86355
|
+
foldRef.current = new IncrementalFold(compactTools);
|
|
86356
|
+
compactRef.current = compactTools;
|
|
86357
|
+
}
|
|
86358
|
+
return foldRef.current.syncTo(events).slice();
|
|
86359
|
+
}, [events, compactTools]);
|
|
86134
86360
|
const settledRef = (0, import_react41.useRef)([]);
|
|
86135
86361
|
const clearGenerationRef = (0, import_react41.useRef)(0);
|
|
86136
86362
|
if (blocks.length < settledRef.current.length) {
|
|
86137
86363
|
settledRef.current = [];
|
|
86138
86364
|
clearGenerationRef.current += 1;
|
|
86139
86365
|
}
|
|
86140
|
-
let settledCount =
|
|
86141
|
-
for (
|
|
86142
|
-
if (isSettled(
|
|
86366
|
+
let settledCount = settledRef.current.length;
|
|
86367
|
+
for (let i2 = settledRef.current.length; i2 < blocks.length; i2 += 1) {
|
|
86368
|
+
if (isSettled(blocks[i2]))
|
|
86143
86369
|
settledCount += 1;
|
|
86144
86370
|
else
|
|
86145
86371
|
break;
|
|
@@ -88213,6 +88439,13 @@ function modelBreakdownRows(file, liveByModel) {
|
|
|
88213
88439
|
output: m3.outputTokens
|
|
88214
88440
|
})).sort((a2, b3) => b3.prompt - a2.prompt);
|
|
88215
88441
|
}
|
|
88442
|
+
function peak(series, seed = 0) {
|
|
88443
|
+
let m3 = seed;
|
|
88444
|
+
for (const v3 of series)
|
|
88445
|
+
if (v3 > m3)
|
|
88446
|
+
m3 = v3;
|
|
88447
|
+
return m3;
|
|
88448
|
+
}
|
|
88216
88449
|
function perCallPrompt(events) {
|
|
88217
88450
|
const out = [];
|
|
88218
88451
|
for (const e3 of events) {
|
|
@@ -88297,7 +88530,7 @@ var init_UsagePanel = __esm({
|
|
|
88297
88530
|
const subtitle = hasSession ? `${s2.calls} calls \xB7 ${fmt(s2.totalPrompt)} prompt \xB7 ${fmt(s2.totalOutput)} output` : "saved across sessions";
|
|
88298
88531
|
const showSession = hasSession && (!tabs || activeTab === "session");
|
|
88299
88532
|
const showLifetime = hasModels && (!tabs || activeTab === "lifetime");
|
|
88300
|
-
return (0, import_jsx_runtime28.jsxs)(Modal, { title: "Usage", subtitle, ...tabs ? { tabs, activeTabId: activeTab, onTabChange: (id) => setActiveTab(id) } : {}, ...onClose ? { onClose } : {}, children: [showSession ? (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [(0, import_jsx_runtime28.jsx)(Text, { bold: true, children: "Prompt composition" }), (0, import_jsx_runtime28.jsx)(CompRow, { label: "cache read", frac: readFrac, value: s2.totalCacheRead, color: Colors.active }), (0, import_jsx_runtime28.jsx)(CompRow, { label: "fresh input", frac: freshFrac, value: s2.totalInput }), (0, import_jsx_runtime28.jsx)(CompRow, { label: "cache write", frac: writeFrac, value: s2.totalCacheCreation, color: Colors.busy }), (0, import_jsx_runtime28.jsxs)(Box_default, { marginTop: 1, flexDirection: "column", children: [(0, import_jsx_runtime28.jsx)(MetricRow, { label: "Cache hit", frac: s2.cacheHitRate, color: s2.cacheHitRate >= 0.5 ? Colors.active : Colors.busy }), ctxFrac != null ? (0, import_jsx_runtime28.jsx)(MetricRow, { label: "Context fill", frac: ctxFrac, color: ctxColor, suffix: `${fmt(contextTokens ?? 0)} / ${fmt(contextWindow ?? 0)}` }) : null] }), (0, import_jsx_runtime28.jsxs)(Box_default, { marginTop: 1, children: [(0, import_jsx_runtime28.jsx)(Box_default, { width: LABEL_COL, children: (0, import_jsx_runtime28.jsx)(Text, { bold: true, children: "Input cost" }) }), (0, import_jsx_runtime28.jsxs)(Text, { children: [fmt(s2.billedInputEq), " billed-eq"] }), saved > 5e-3 ? (0, import_jsx_runtime28.jsx)(Text, { color: Colors.active, bold: true, children: ` saved ${pct(saved)}` }) : (0, import_jsx_runtime28.jsx)(Text, { dimColor: true, children: " no cache savings yet" })] }), (0, import_jsx_runtime28.jsxs)(Box_default, { marginTop: 1, flexDirection: "column", children: [(0, import_jsx_runtime28.jsxs)(Box_default, { children: [(0, import_jsx_runtime28.jsx)(Text, { bold: true, children: "Per-call prompt " }), (0, import_jsx_runtime28.jsx)(Text, { dimColor: true, children: `peak ${fmt(
|
|
88533
|
+
return (0, import_jsx_runtime28.jsxs)(Modal, { title: "Usage", subtitle, ...tabs ? { tabs, activeTabId: activeTab, onTabChange: (id) => setActiveTab(id) } : {}, ...onClose ? { onClose } : {}, children: [showSession ? (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [(0, import_jsx_runtime28.jsx)(Text, { bold: true, children: "Prompt composition" }), (0, import_jsx_runtime28.jsx)(CompRow, { label: "cache read", frac: readFrac, value: s2.totalCacheRead, color: Colors.active }), (0, import_jsx_runtime28.jsx)(CompRow, { label: "fresh input", frac: freshFrac, value: s2.totalInput }), (0, import_jsx_runtime28.jsx)(CompRow, { label: "cache write", frac: writeFrac, value: s2.totalCacheCreation, color: Colors.busy }), (0, import_jsx_runtime28.jsxs)(Box_default, { marginTop: 1, flexDirection: "column", children: [(0, import_jsx_runtime28.jsx)(MetricRow, { label: "Cache hit", frac: s2.cacheHitRate, color: s2.cacheHitRate >= 0.5 ? Colors.active : Colors.busy }), ctxFrac != null ? (0, import_jsx_runtime28.jsx)(MetricRow, { label: "Context fill", frac: ctxFrac, color: ctxColor, suffix: `${fmt(contextTokens ?? 0)} / ${fmt(contextWindow ?? 0)}` }) : null] }), (0, import_jsx_runtime28.jsxs)(Box_default, { marginTop: 1, children: [(0, import_jsx_runtime28.jsx)(Box_default, { width: LABEL_COL, children: (0, import_jsx_runtime28.jsx)(Text, { bold: true, children: "Input cost" }) }), (0, import_jsx_runtime28.jsxs)(Text, { children: [fmt(s2.billedInputEq), " billed-eq"] }), saved > 5e-3 ? (0, import_jsx_runtime28.jsx)(Text, { color: Colors.active, bold: true, children: ` saved ${pct(saved)}` }) : (0, import_jsx_runtime28.jsx)(Text, { dimColor: true, children: " no cache savings yet" })] }), (0, import_jsx_runtime28.jsxs)(Box_default, { marginTop: 1, flexDirection: "column", children: [(0, import_jsx_runtime28.jsxs)(Box_default, { children: [(0, import_jsx_runtime28.jsx)(Text, { bold: true, children: "Per-call prompt " }), (0, import_jsx_runtime28.jsx)(Text, { dimColor: true, children: `peak ${fmt(peak(series))}` })] }), (0, import_jsx_runtime28.jsxs)(Box_default, { children: [(0, import_jsx_runtime28.jsx)(Text, { children: sparkline(series) }), trend ? (0, import_jsx_runtime28.jsx)(Text, { color: trend === "growing" ? Colors.busy : Colors.active, children: trend === "growing" ? " \u2191 growing" : " \u2248 bounded" }) : null] })] }), !s2.cacheEffective ? (0, import_jsx_runtime28.jsx)(Box_default, { marginTop: 1, children: (0, import_jsx_runtime28.jsx)(Text, { color: Colors.danger, children: "\u26A0 cache ineffective \u2014 writing cache but not reading it back (prefix likely unstable)" }) }) : null] }) : null, showLifetime ? (0, import_jsx_runtime28.jsxs)(Box_default, { marginTop: showSession ? 1 : 0, flexDirection: "column", children: [(0, import_jsx_runtime28.jsxs)(Box_default, { children: [(0, import_jsx_runtime28.jsx)(Text, { bold: true, children: "By model " }), (0, import_jsx_runtime28.jsx)(Text, { dimColor: true, children: `(saved + this session \xB7 ${lifeRows.length} model${lifeRows.length === 1 ? "" : "s"})` })] }), lifeRows.slice(0, 8).map((r2) => (0, import_jsx_runtime28.jsx)(ModelRow, { name: r2.name, calls: r2.calls, prompt: r2.prompt, output: r2.output }, r2.name)), lifeRows.length > 1 ? (0, import_jsx_runtime28.jsx)(ModelRow, { name: "total", calls: lifeTotal.calls, prompt: lifeTotal.prompt, output: lifeTotal.output, dim: true }) : null, (0, import_jsx_runtime28.jsx)(Text, { dimColor: true, children: " /usage clear resets saved history" })] }) : null] });
|
|
88301
88534
|
};
|
|
88302
88535
|
}
|
|
88303
88536
|
});
|
|
@@ -129343,6 +129576,15 @@ async function* walk(root, regex2, cursor, signal, visited) {
|
|
|
129343
129576
|
}
|
|
129344
129577
|
}
|
|
129345
129578
|
}
|
|
129579
|
+
var MAX_FILE_BYTES = 10 * 1024 * 1024;
|
|
129580
|
+
function looksBinary(content) {
|
|
129581
|
+
const limit2 = Math.min(content.length, 8192);
|
|
129582
|
+
for (let i2 = 0; i2 < limit2; i2 += 1) {
|
|
129583
|
+
if (content.charCodeAt(i2) === 0)
|
|
129584
|
+
return true;
|
|
129585
|
+
}
|
|
129586
|
+
return false;
|
|
129587
|
+
}
|
|
129346
129588
|
var grepTool = defineTool({
|
|
129347
129589
|
name: "Grep",
|
|
129348
129590
|
description: "Recursively search files for a regex pattern. Returns lines as `path:line:text`.",
|
|
@@ -129406,12 +129648,21 @@ async function walk2(root, cursor, re2, fileRe, matches, max, signal) {
|
|
|
129406
129648
|
continue;
|
|
129407
129649
|
if (fileRe && !fileRe.test(entry.name))
|
|
129408
129650
|
continue;
|
|
129651
|
+
try {
|
|
129652
|
+
const st3 = await promises.stat(full);
|
|
129653
|
+
if (st3.size > MAX_FILE_BYTES)
|
|
129654
|
+
continue;
|
|
129655
|
+
} catch {
|
|
129656
|
+
continue;
|
|
129657
|
+
}
|
|
129409
129658
|
let content;
|
|
129410
129659
|
try {
|
|
129411
129660
|
content = await promises.readFile(full, "utf8");
|
|
129412
129661
|
} catch {
|
|
129413
129662
|
continue;
|
|
129414
129663
|
}
|
|
129664
|
+
if (looksBinary(content))
|
|
129665
|
+
continue;
|
|
129415
129666
|
const lines = content.split("\n");
|
|
129416
129667
|
for (let i2 = 0; i2 < lines.length; i2++) {
|
|
129417
129668
|
if (re2.test(lines[i2])) {
|
|
@@ -135706,9 +135957,38 @@ var workflowResumeParamsSchema = z.object({
|
|
|
135706
135957
|
var surfaceOpenParamsSchema = z.object({
|
|
135707
135958
|
kind: z.string().min(1).max(64)
|
|
135708
135959
|
});
|
|
135960
|
+
var MAX_SURFACE_INPUT_BYTES = 1e6;
|
|
135961
|
+
function surfaceInputWithinCap(m3) {
|
|
135962
|
+
let upper = 2;
|
|
135963
|
+
let primitiveOnly = true;
|
|
135964
|
+
for (const key in m3) {
|
|
135965
|
+
if (!Object.prototype.hasOwnProperty.call(m3, key))
|
|
135966
|
+
continue;
|
|
135967
|
+
const v3 = m3[key];
|
|
135968
|
+
const t2 = typeof v3;
|
|
135969
|
+
if (v3 === void 0 || t2 === "function")
|
|
135970
|
+
continue;
|
|
135971
|
+
upper += key.length * 6 + 2 + 1 + 1;
|
|
135972
|
+
if (t2 === "string") {
|
|
135973
|
+
upper += v3.length * 6 + 2;
|
|
135974
|
+
} else if (t2 === "number") {
|
|
135975
|
+
upper += 25;
|
|
135976
|
+
} else if (t2 === "boolean" || v3 === null) {
|
|
135977
|
+
upper += 5;
|
|
135978
|
+
} else {
|
|
135979
|
+
primitiveOnly = false;
|
|
135980
|
+
break;
|
|
135981
|
+
}
|
|
135982
|
+
if (upper > MAX_SURFACE_INPUT_BYTES)
|
|
135983
|
+
break;
|
|
135984
|
+
}
|
|
135985
|
+
if (primitiveOnly && upper <= MAX_SURFACE_INPUT_BYTES)
|
|
135986
|
+
return true;
|
|
135987
|
+
return JSON.stringify(m3).length <= MAX_SURFACE_INPUT_BYTES;
|
|
135988
|
+
}
|
|
135709
135989
|
var surfaceInputParamsSchema = z.object({
|
|
135710
135990
|
surfaceId: z.string().min(1).max(120),
|
|
135711
|
-
message: z.object({ type: z.string().min(1).max(64) }).passthrough().refine((m3) =>
|
|
135991
|
+
message: z.object({ type: z.string().min(1).max(64) }).passthrough().refine((m3) => surfaceInputWithinCap(m3), {
|
|
135712
135992
|
message: "surface input message too large"
|
|
135713
135993
|
})
|
|
135714
135994
|
});
|
|
@@ -138600,6 +138880,8 @@ function defaultShell() {
|
|
|
138600
138880
|
return process.env["COMSPEC"] ?? "powershell.exe";
|
|
138601
138881
|
return process.env["SHELL"] ?? "/bin/bash";
|
|
138602
138882
|
}
|
|
138883
|
+
var MAX_SCROLLBACK = 2e5;
|
|
138884
|
+
var SCROLLBACK_SLACK = 1e5;
|
|
138603
138885
|
var TerminalProcessImpl = class {
|
|
138604
138886
|
backend;
|
|
138605
138887
|
pty;
|
|
@@ -138623,7 +138905,10 @@ var TerminalProcessImpl = class {
|
|
|
138623
138905
|
}
|
|
138624
138906
|
}
|
|
138625
138907
|
emitData(d2) {
|
|
138626
|
-
this.buffer
|
|
138908
|
+
this.buffer += d2;
|
|
138909
|
+
if (this.buffer.length > MAX_SCROLLBACK + SCROLLBACK_SLACK) {
|
|
138910
|
+
this.buffer = this.buffer.slice(-MAX_SCROLLBACK);
|
|
138911
|
+
}
|
|
138627
138912
|
for (const cb of this.dataListeners) {
|
|
138628
138913
|
try {
|
|
138629
138914
|
cb(d2);
|
|
@@ -138651,7 +138936,7 @@ var TerminalProcessImpl = class {
|
|
|
138651
138936
|
return () => this.exitListeners.delete(cb);
|
|
138652
138937
|
}
|
|
138653
138938
|
scrollback() {
|
|
138654
|
-
return this.buffer;
|
|
138939
|
+
return this.buffer.length > MAX_SCROLLBACK ? this.buffer.slice(-MAX_SCROLLBACK) : this.buffer;
|
|
138655
138940
|
}
|
|
138656
138941
|
write(data) {
|
|
138657
138942
|
if (!this.alive)
|
|
@@ -138798,11 +139083,17 @@ function runCommand(proc, command, marker, timeoutMs) {
|
|
|
138798
139083
|
clearTimeout(timer);
|
|
138799
139084
|
resolve13({ output: cleanOutput(acc, command, marker), exitCode, timedOut });
|
|
138800
139085
|
};
|
|
139086
|
+
const sentinel2 = new RegExp(`${marker} (\\d+)`);
|
|
139087
|
+
const carry = marker.length + 32;
|
|
139088
|
+
let scanFrom = 0;
|
|
138801
139089
|
const unsub = proc.onData((d2) => {
|
|
139090
|
+
const from = Math.max(scanFrom, acc.length - carry, 0);
|
|
138802
139091
|
acc += d2;
|
|
138803
|
-
|
|
139092
|
+
sentinel2.lastIndex = 0;
|
|
139093
|
+
const m3 = sentinel2.exec(from > 0 ? acc.slice(from) : acc);
|
|
138804
139094
|
if (m3)
|
|
138805
139095
|
finish(Number(m3[1]), false);
|
|
139096
|
+
scanFrom = Math.max(0, acc.length - carry);
|
|
138806
139097
|
});
|
|
138807
139098
|
const timer = setTimeout(() => finish(null, true), timeoutMs);
|
|
138808
139099
|
proc.write(`${command}
|
|
@@ -139859,7 +140150,7 @@ var IS_DARWIN = process.platform === "darwin";
|
|
|
139859
140150
|
function runProcess(cmd, args, opts = {}) {
|
|
139860
140151
|
return new Promise((resolve13, reject) => {
|
|
139861
140152
|
const child = spawn(cmd, [...args], { stdio: ["pipe", "pipe", "pipe"] });
|
|
139862
|
-
|
|
140153
|
+
const stdoutChunks = [];
|
|
139863
140154
|
let stderr = "";
|
|
139864
140155
|
let settled = false;
|
|
139865
140156
|
const onAbort = () => {
|
|
@@ -139880,7 +140171,7 @@ function runProcess(cmd, args, opts = {}) {
|
|
|
139880
140171
|
}
|
|
139881
140172
|
}, opts.timeoutMs) : null;
|
|
139882
140173
|
child.stdout.on("data", (chunk) => {
|
|
139883
|
-
|
|
140174
|
+
stdoutChunks.push(chunk);
|
|
139884
140175
|
});
|
|
139885
140176
|
child.stderr.on("data", (chunk) => {
|
|
139886
140177
|
stderr += chunk.toString("utf8");
|
|
@@ -139903,7 +140194,7 @@ function runProcess(cmd, args, opts = {}) {
|
|
|
139903
140194
|
opts.signal?.removeEventListener("abort", onAbort);
|
|
139904
140195
|
resolve13({
|
|
139905
140196
|
exitCode: code ?? -1,
|
|
139906
|
-
stdout:
|
|
140197
|
+
stdout: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
139907
140198
|
stderr
|
|
139908
140199
|
});
|
|
139909
140200
|
});
|
|
@@ -140552,43 +140843,7 @@ async function syncSkillSchedules(registry, store) {
|
|
|
140552
140843
|
if (draft)
|
|
140553
140844
|
wanted.set(skill.frontmatter.name, draft);
|
|
140554
140845
|
}
|
|
140555
|
-
|
|
140556
|
-
const existingSkill = /* @__PURE__ */ new Map();
|
|
140557
|
-
for (const e3 of existing) {
|
|
140558
|
-
if (e3.source === "skill" && e3.skillName)
|
|
140559
|
-
existingSkill.set(e3.skillName, e3);
|
|
140560
|
-
}
|
|
140561
|
-
let added = 0;
|
|
140562
|
-
let removed = 0;
|
|
140563
|
-
let updated = 0;
|
|
140564
|
-
for (const [skillName2, entry] of existingSkill) {
|
|
140565
|
-
if (!wanted.has(skillName2)) {
|
|
140566
|
-
const ok = await store.delete(entry.id);
|
|
140567
|
-
if (ok)
|
|
140568
|
-
removed += 1;
|
|
140569
|
-
}
|
|
140570
|
-
}
|
|
140571
|
-
for (const [skillName2, draft] of wanted) {
|
|
140572
|
-
const current = existingSkill.get(skillName2);
|
|
140573
|
-
if (!current) {
|
|
140574
|
-
await store.create(draft);
|
|
140575
|
-
added += 1;
|
|
140576
|
-
continue;
|
|
140577
|
-
}
|
|
140578
|
-
const changed = current.prompt !== draft.prompt || current.cron !== draft.cron || current.runAt !== draft.runAt || current.timeZone !== draft.timeZone || current.channel !== draft.channel || current.enabled !== draft.enabled;
|
|
140579
|
-
if (changed) {
|
|
140580
|
-
await store.update(current.id, {
|
|
140581
|
-
prompt: draft.prompt,
|
|
140582
|
-
...draft.cron ? { cron: draft.cron } : { cron: void 0 },
|
|
140583
|
-
...draft.runAt !== void 0 ? { runAt: draft.runAt } : { runAt: void 0 },
|
|
140584
|
-
...draft.timeZone ? { timeZone: draft.timeZone } : { timeZone: void 0 },
|
|
140585
|
-
...draft.channel ? { channel: draft.channel } : { channel: void 0 },
|
|
140586
|
-
enabled: draft.enabled
|
|
140587
|
-
});
|
|
140588
|
-
updated += 1;
|
|
140589
|
-
}
|
|
140590
|
-
}
|
|
140591
|
-
return { added, removed, updated };
|
|
140846
|
+
return store.reconcileSkillSchedules(wanted);
|
|
140592
140847
|
}
|
|
140593
140848
|
|
|
140594
140849
|
// ../plugin-scheduler/dist/poller.js
|
|
@@ -140820,6 +141075,79 @@ var ScheduleStore = class {
|
|
|
140820
141075
|
});
|
|
140821
141076
|
return removed;
|
|
140822
141077
|
}
|
|
141078
|
+
/**
|
|
141079
|
+
* Batch-reconcile every `source='skill'` row against `wanted` (skillName →
|
|
141080
|
+
* desired draft) in a SINGLE atomic write, instead of one whole-file
|
|
141081
|
+
* serialization + fsync per changed row. The diff (and the resulting array)
|
|
141082
|
+
* is byte-identical to running the equivalent sequence of
|
|
141083
|
+
* create/update/delete calls:
|
|
141084
|
+
* - skill rows whose skillName is absent from `wanted` are removed;
|
|
141085
|
+
* - present skillNames with no existing row are created (fresh id +
|
|
141086
|
+
* createdAt), appended in `wanted` iteration order;
|
|
141087
|
+
* - present skillNames with an existing row are updated IN PLACE (id,
|
|
141088
|
+
* createdAt, position preserved) only when a field actually changed.
|
|
141089
|
+
* Returns the add/remove/update counts so the caller's telemetry is
|
|
141090
|
+
* unchanged. Manual/workflow rows are never touched.
|
|
141091
|
+
*/
|
|
141092
|
+
async reconcileSkillSchedules(wanted) {
|
|
141093
|
+
let added = 0;
|
|
141094
|
+
let removed = 0;
|
|
141095
|
+
let updated = 0;
|
|
141096
|
+
await this.store.mutate((schedules) => {
|
|
141097
|
+
const existingByName = /* @__PURE__ */ new Map();
|
|
141098
|
+
for (let i2 = 0; i2 < schedules.length; i2 += 1) {
|
|
141099
|
+
const s2 = schedules[i2];
|
|
141100
|
+
if (s2.source === "skill" && s2.skillName && !existingByName.has(s2.skillName)) {
|
|
141101
|
+
existingByName.set(s2.skillName, i2);
|
|
141102
|
+
}
|
|
141103
|
+
}
|
|
141104
|
+
const next = [];
|
|
141105
|
+
for (const s2 of schedules) {
|
|
141106
|
+
if (s2.source === "skill" && s2.skillName && !wanted.has(s2.skillName)) {
|
|
141107
|
+
removed += 1;
|
|
141108
|
+
continue;
|
|
141109
|
+
}
|
|
141110
|
+
next.push(s2);
|
|
141111
|
+
}
|
|
141112
|
+
const posInNext = /* @__PURE__ */ new Map();
|
|
141113
|
+
for (let i2 = 0; i2 < next.length; i2 += 1) {
|
|
141114
|
+
const s2 = next[i2];
|
|
141115
|
+
if (s2.source === "skill" && s2.skillName && !posInNext.has(s2.skillName)) {
|
|
141116
|
+
posInNext.set(s2.skillName, i2);
|
|
141117
|
+
}
|
|
141118
|
+
}
|
|
141119
|
+
for (const [skillName2, draft] of wanted) {
|
|
141120
|
+
const idx = posInNext.get(skillName2);
|
|
141121
|
+
if (idx === void 0) {
|
|
141122
|
+
next.push(scheduleEntrySchema.parse({
|
|
141123
|
+
...draft,
|
|
141124
|
+
id: ulid(),
|
|
141125
|
+
createdAt: Date.now(),
|
|
141126
|
+
enabled: draft.enabled ?? true,
|
|
141127
|
+
source: draft.source ?? "skill"
|
|
141128
|
+
}));
|
|
141129
|
+
added += 1;
|
|
141130
|
+
continue;
|
|
141131
|
+
}
|
|
141132
|
+
const current = next[idx];
|
|
141133
|
+
const patch = {
|
|
141134
|
+
prompt: draft.prompt,
|
|
141135
|
+
...draft.cron ? { cron: draft.cron } : { cron: void 0 },
|
|
141136
|
+
...draft.runAt !== void 0 ? { runAt: draft.runAt } : { runAt: void 0 },
|
|
141137
|
+
...draft.timeZone ? { timeZone: draft.timeZone } : { timeZone: void 0 },
|
|
141138
|
+
...draft.channel ? { channel: draft.channel } : { channel: void 0 },
|
|
141139
|
+
enabled: draft.enabled ?? true
|
|
141140
|
+
};
|
|
141141
|
+
const changed = current.prompt !== patch.prompt || current.cron !== patch.cron || current.runAt !== patch.runAt || current.timeZone !== patch.timeZone || current.channel !== patch.channel || current.enabled !== patch.enabled;
|
|
141142
|
+
if (changed) {
|
|
141143
|
+
next[idx] = scheduleEntrySchema.parse({ ...current, ...patch });
|
|
141144
|
+
updated += 1;
|
|
141145
|
+
}
|
|
141146
|
+
}
|
|
141147
|
+
return next;
|
|
141148
|
+
});
|
|
141149
|
+
return { added, removed, updated };
|
|
141150
|
+
}
|
|
140823
141151
|
/**
|
|
140824
141152
|
* Replace every `source='skill'` schedule for the given `skillName`
|
|
140825
141153
|
* with the supplied entry, OR remove all of them if `entry` is null.
|
|
@@ -141259,14 +141587,17 @@ function readHeader(headers, name) {
|
|
|
141259
141587
|
return v3[0] ?? null;
|
|
141260
141588
|
return v3 ?? null;
|
|
141261
141589
|
}
|
|
141262
|
-
function
|
|
141263
|
-
let parsed;
|
|
141590
|
+
function parseBody(body) {
|
|
141264
141591
|
try {
|
|
141265
|
-
|
|
141592
|
+
return { ok: true, value: JSON.parse(body.toString("utf8")) };
|
|
141266
141593
|
} catch {
|
|
141267
|
-
return null;
|
|
141594
|
+
return { ok: false, value: null };
|
|
141268
141595
|
}
|
|
141269
|
-
|
|
141596
|
+
}
|
|
141597
|
+
function readJsonPath(parsed, path60) {
|
|
141598
|
+
if (!parsed.ok)
|
|
141599
|
+
return null;
|
|
141600
|
+
let cur = parsed.value;
|
|
141270
141601
|
for (const seg of path60.split(".")) {
|
|
141271
141602
|
if (cur === null || cur === void 0 || typeof cur !== "object")
|
|
141272
141603
|
return null;
|
|
@@ -141274,8 +141605,8 @@ function readJsonPath(body, path60) {
|
|
|
141274
141605
|
}
|
|
141275
141606
|
return asString2(cur);
|
|
141276
141607
|
}
|
|
141277
|
-
function ruleMatches(rule, input) {
|
|
141278
|
-
const value = rule.source === "header" ? readHeader(input.headers, rule.name) : readJsonPath(
|
|
141608
|
+
function ruleMatches(rule, input, parsed) {
|
|
141609
|
+
const value = rule.source === "header" ? readHeader(input.headers, rule.name) : readJsonPath(parsed, rule.path);
|
|
141279
141610
|
if (value === null)
|
|
141280
141611
|
return false;
|
|
141281
141612
|
if (rule.equals && rule.equals.includes(value))
|
|
@@ -141291,11 +141622,12 @@ function ruleMatches(rule, input) {
|
|
|
141291
141622
|
return false;
|
|
141292
141623
|
}
|
|
141293
141624
|
function shouldFire(filter, input) {
|
|
141294
|
-
|
|
141625
|
+
const parsed = parseBody(input.body);
|
|
141626
|
+
if (filter.exclude.some((r2) => ruleMatches(r2, input, parsed)))
|
|
141295
141627
|
return false;
|
|
141296
141628
|
if (filter.include.length === 0)
|
|
141297
141629
|
return true;
|
|
141298
|
-
return filter.include.some((r2) => ruleMatches(r2, input));
|
|
141630
|
+
return filter.include.some((r2) => ruleMatches(r2, input, parsed));
|
|
141299
141631
|
}
|
|
141300
141632
|
|
|
141301
141633
|
// ../plugin-webhooks/dist/template.js
|
|
@@ -145461,7 +145793,7 @@ function buildSubagentSpecWithDeps(step, scope, deps, opts) {
|
|
|
145461
145793
|
}
|
|
145462
145794
|
var dagExecutor = defineWorkflowExecutor({
|
|
145463
145795
|
name: DAG_EXECUTOR_NAME,
|
|
145464
|
-
description: "
|
|
145796
|
+
description: "DAG runner: steps with settled dependencies are scheduled in waves of up to `concurrency` ready steps, then executed sequentially within each wave (no overlap yet \u2014 `concurrency` caps the batch size, not wall-clock latency).",
|
|
145465
145797
|
run: runExecutor
|
|
145466
145798
|
});
|
|
145467
145799
|
|