@wrongstack/core 0.77.0 → 0.82.6
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/{agent-bridge-EWdqs8v6.d.ts → agent-bridge-C9P_HPez.d.ts} +2 -2
- package/dist/{agent-subagent-runner-D8qW8OSC.d.ts → agent-subagent-runner-2Aq0jOSj.d.ts} +107 -102
- package/dist/{compactor-D_ExJajC.d.ts → compactor-CJq7LQev.d.ts} +3 -3
- package/dist/{config-Dy0CK_o6.d.ts → config-_DZ7dN-T.d.ts} +77 -75
- package/dist/{context-y87Jc5ei.d.ts → context-ToHAp4-U.d.ts} +119 -90
- package/dist/coordination/index.d.ts +16 -16
- package/dist/coordination/index.js +318 -37
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +31 -31
- package/dist/defaults/index.js +419 -67
- package/dist/defaults/index.js.map +1 -1
- package/dist/{director-state-BmYi3DGA.d.ts → director-state-CgIc30qi.d.ts} +19 -19
- package/dist/{events-CYaoLN5_.d.ts → events-DnRqXaZ3.d.ts} +43 -42
- package/dist/execution/index.d.ts +53 -53
- package/dist/execution/index.js +67 -23
- package/dist/execution/index.js.map +1 -1
- package/dist/extension/index.d.ts +9 -9
- package/dist/extension/index.js +8 -1
- package/dist/extension/index.js.map +1 -1
- package/dist/{goal-store-C7jcumEh.d.ts → goal-store-DvWLNu52.d.ts} +4 -4
- package/dist/{index-DIxjTOga.d.ts → index-BNOLadHw.d.ts} +28 -28
- package/dist/{index-Dsda0uCn.d.ts → index-N0_c4bHQ.d.ts} +45 -45
- package/dist/index.d.ts +165 -165
- package/dist/index.js +593 -137
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +9 -9
- package/dist/infrastructure/index.js +13 -5
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +14 -14
- package/dist/kernel/index.js +7 -0
- package/dist/kernel/index.js.map +1 -1
- package/dist/logger-B72yyPc6.d.ts +12 -0
- package/dist/{logger-BppKxDqZ.d.ts → logger-C_27pj9i.d.ts} +6 -7
- package/dist/{mcp-servers-T0O6UN_w.d.ts → mcp-servers-Dck3T85_.d.ts} +20 -20
- package/dist/{mode-BO4SEUIv.d.ts → mode-CHo2XtHs.d.ts} +4 -4
- package/dist/models/index.d.ts +10 -10
- package/dist/models/index.js +8 -2
- package/dist/models/index.js.map +1 -1
- package/dist/{models-registry-BcYJDKLm.d.ts → models-registry-Be3osGt5.d.ts} +28 -28
- package/dist/{models-registry-Cuq1C8V9.d.ts → models-registry-Boz639EI.d.ts} +12 -12
- package/dist/{multi-agent-coordinator-DpbG3wiy.d.ts → multi-agent-coordinator-DllpCVkF.d.ts} +12 -12
- package/dist/{null-fleet-bus-u5ys3lW_.d.ts → null-fleet-bus-BY0AN-sr.d.ts} +121 -121
- package/dist/observability/index.d.ts +41 -41
- package/dist/observability/index.js.map +1 -1
- package/dist/{observability-BhnVLBLS.d.ts → observability-CoSNZdhX.d.ts} +4 -4
- package/dist/{parallel-eternal-engine-Dn0P8Pbj.d.ts → parallel-eternal-engine-D402RASp.d.ts} +49 -49
- package/dist/{path-resolver-B32v2JIq.d.ts → path-resolver-UPFTsDyD.d.ts} +6 -6
- package/dist/{permission-V5BLOrY6.d.ts → permission-14CChMmO.d.ts} +10 -8
- package/dist/{permission-policy-CBVx-d-8.d.ts → permission-policy-gW5htOo1.d.ts} +7 -7
- package/dist/{plan-templates-BcUwLlMQ.d.ts → plan-templates-DRvPgkfZ.d.ts} +65 -32
- package/dist/{provider-runner-CSi_7l0h.d.ts → provider-runner-COAJM8tC.d.ts} +6 -6
- package/dist/{retry-policy-CG3qvH_e.d.ts → retry-policy-DSu6O6rD.d.ts} +4 -4
- package/dist/sdd/index.d.ts +47 -47
- package/dist/sdd/index.js +47 -22
- package/dist/sdd/index.js.map +1 -1
- package/dist/security/index.d.ts +6 -6
- package/dist/security/index.js +7 -1
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-RvBR_YRW.d.ts → selector-11-fm95U.d.ts} +2 -2
- package/dist/{session-event-bridge-CDHxcmQU.d.ts → session-event-bridge-D0u-x576.d.ts} +7 -7
- package/dist/{session-reader-BIpwM60D.d.ts → session-reader-BQU-toaN.d.ts} +23 -23
- package/dist/{skill-CxuWrsKK.d.ts → skill-BJeF2DwY.d.ts} +1 -1
- package/dist/skills/index.d.ts +9 -9
- package/dist/skills/index.js +15 -3
- package/dist/skills/index.js.map +1 -1
- package/dist/storage/index.d.ts +15 -15
- package/dist/storage/index.js +378 -76
- package/dist/storage/index.js.map +1 -1
- package/dist/{system-prompt-CA11g6Jo.d.ts → system-prompt-C0rLCeyn.d.ts} +16 -11
- package/dist/{task-graph-D1YQbpxF.d.ts → task-graph-CikNdRTG.d.ts} +22 -22
- package/dist/types/index.d.ts +25 -25
- package/dist/types/index.js +45 -10
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +46 -45
- package/dist/utils/index.js +53 -12
- package/dist/utils/index.js.map +1 -1
- package/dist/{wstack-paths-D7evAFWM.d.ts → wstack-paths-BQMvEllz.d.ts} +2 -2
- package/package.json +1 -1
- package/dist/logger-DDd5C--Z.d.ts +0 -12
package/dist/defaults/index.js
CHANGED
|
@@ -108,8 +108,10 @@ function isStdoutTTY() {
|
|
|
108
108
|
}
|
|
109
109
|
function writeTo(s, stream) {
|
|
110
110
|
if (!stream || typeof stream.write !== "function") return false;
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
{
|
|
112
|
+
stream.write(s);
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
113
115
|
}
|
|
114
116
|
function writeErr(s, stream = process.stderr) {
|
|
115
117
|
return writeTo(s, stream);
|
|
@@ -243,6 +245,12 @@ function formatCtx(ctx) {
|
|
|
243
245
|
init_atomic_write();
|
|
244
246
|
|
|
245
247
|
// src/utils/message-invariants.ts
|
|
248
|
+
function expectDefined(value) {
|
|
249
|
+
if (value === null || value === void 0) {
|
|
250
|
+
throw new Error("Expected value to be defined");
|
|
251
|
+
}
|
|
252
|
+
return value;
|
|
253
|
+
}
|
|
246
254
|
function repairToolUseAdjacency(messages) {
|
|
247
255
|
const removedToolUses = [];
|
|
248
256
|
const removedToolResults = [];
|
|
@@ -250,7 +258,7 @@ function repairToolUseAdjacency(messages) {
|
|
|
250
258
|
let changed = false;
|
|
251
259
|
const out = [];
|
|
252
260
|
for (let i = 0; i < messages.length; i++) {
|
|
253
|
-
const original = messages[i];
|
|
261
|
+
const original = expectDefined(messages[i]);
|
|
254
262
|
let msg = original;
|
|
255
263
|
if (hasToolUse(msg)) {
|
|
256
264
|
const nextIds = toolResultIds(messages[i + 1]);
|
|
@@ -335,6 +343,12 @@ function isEmptyMessage(msg) {
|
|
|
335
343
|
}
|
|
336
344
|
|
|
337
345
|
// src/storage/session-store.ts
|
|
346
|
+
function expectDefined2(value) {
|
|
347
|
+
if (value === null || value === void 0) {
|
|
348
|
+
throw new Error("Expected value to be defined");
|
|
349
|
+
}
|
|
350
|
+
return value;
|
|
351
|
+
}
|
|
338
352
|
function sanitizeModel(model) {
|
|
339
353
|
return model.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
340
354
|
}
|
|
@@ -345,7 +359,7 @@ function generateSessionId(startedAt, model) {
|
|
|
345
359
|
const modelPart = model ? `_${sanitizeModel(model)}` : "";
|
|
346
360
|
return `${date}/${time}Z${modelPart}_${suffix}`;
|
|
347
361
|
}
|
|
348
|
-
var DefaultSessionStore = class {
|
|
362
|
+
var DefaultSessionStore = class _DefaultSessionStore {
|
|
349
363
|
dir;
|
|
350
364
|
events;
|
|
351
365
|
secretScrubber;
|
|
@@ -354,6 +368,10 @@ var DefaultSessionStore = class {
|
|
|
354
368
|
this.events = opts.events;
|
|
355
369
|
this.secretScrubber = opts.secretScrubber;
|
|
356
370
|
}
|
|
371
|
+
/** Absolute path to the session index file. */
|
|
372
|
+
get indexFile() {
|
|
373
|
+
return path3.join(this.dir, "_index.jsonl");
|
|
374
|
+
}
|
|
357
375
|
/** Join session ID to its absolute path within the store directory. */
|
|
358
376
|
sessionPath(id, ext) {
|
|
359
377
|
return path3.join(this.dir, `${id}${ext}`);
|
|
@@ -386,7 +404,8 @@ var DefaultSessionStore = class {
|
|
|
386
404
|
return new FileSessionWriter(id, handle, startedAt, meta, this.events, {
|
|
387
405
|
dir: shardDir,
|
|
388
406
|
filePath: file,
|
|
389
|
-
secretScrubber: this.secretScrubber
|
|
407
|
+
secretScrubber: this.secretScrubber,
|
|
408
|
+
onClose: (s) => this.appendToIndex(s)
|
|
390
409
|
});
|
|
391
410
|
} catch (err) {
|
|
392
411
|
await handle.close().catch(() => {
|
|
@@ -417,7 +436,7 @@ var DefaultSessionStore = class {
|
|
|
417
436
|
provider: data.metadata.provider
|
|
418
437
|
},
|
|
419
438
|
this.events,
|
|
420
|
-
{ resumed: true, dir: this.dir, filePath: file, secretScrubber: this.secretScrubber }
|
|
439
|
+
{ resumed: true, dir: this.dir, filePath: file, secretScrubber: this.secretScrubber, onClose: (s) => this.appendToIndex(s) }
|
|
421
440
|
);
|
|
422
441
|
return { writer, data };
|
|
423
442
|
} catch (err) {
|
|
@@ -447,6 +466,15 @@ var DefaultSessionStore = class {
|
|
|
447
466
|
async list(limit = 20) {
|
|
448
467
|
try {
|
|
449
468
|
await ensureDir(this.dir);
|
|
469
|
+
const indexed = await this.readIndex();
|
|
470
|
+
if (indexed.length > 0) {
|
|
471
|
+
indexed.sort((a, b) => {
|
|
472
|
+
if (a.startedAt < b.startedAt) return 1;
|
|
473
|
+
if (a.startedAt > b.startedAt) return -1;
|
|
474
|
+
return a.id.localeCompare(b.id);
|
|
475
|
+
});
|
|
476
|
+
return indexed.slice(0, limit);
|
|
477
|
+
}
|
|
450
478
|
const ids = await this.collectSessionIds(this.dir);
|
|
451
479
|
const sessions = await Promise.all(ids.map((id) => this.summaryFor(id).catch(() => null)));
|
|
452
480
|
const out = sessions.filter((s) => s !== null);
|
|
@@ -460,16 +488,121 @@ var DefaultSessionStore = class {
|
|
|
460
488
|
return [];
|
|
461
489
|
}
|
|
462
490
|
}
|
|
463
|
-
|
|
464
|
-
|
|
491
|
+
// ── Session index (_index.jsonl) ─────────────────────────────────────────
|
|
492
|
+
//
|
|
493
|
+
// One JSON line per closed session, appended atomically on close().
|
|
494
|
+
// When a session is deleted, a tombstone {action:"delete",id:"..."} is
|
|
495
|
+
// appended. On read, tombstones filter out matching session entries.
|
|
496
|
+
// This keeps listing O(lines-in-index) instead of O(files-on-disk).
|
|
497
|
+
//
|
|
498
|
+
// The index auto-compacts every N appends to prevent unbounded growth
|
|
499
|
+
// from tombstones and duplicate entries (resume cycles).
|
|
500
|
+
indexAppendCount = 0;
|
|
501
|
+
static COMPACT_EVERY = 30;
|
|
502
|
+
/** Append a session summary to the index. */
|
|
503
|
+
async appendToIndex(summary) {
|
|
504
|
+
try {
|
|
505
|
+
await ensureDir(this.dir);
|
|
506
|
+
const line = JSON.stringify(summary) + "\n";
|
|
507
|
+
await fsp.appendFile(this.indexFile, line, "utf8");
|
|
508
|
+
this.indexAppendCount++;
|
|
509
|
+
if (this.indexAppendCount >= _DefaultSessionStore.COMPACT_EVERY) {
|
|
510
|
+
await this.compactIndex();
|
|
511
|
+
this.indexAppendCount = 0;
|
|
512
|
+
}
|
|
513
|
+
} catch {
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
/** Append a tombstone entry for a deleted session. */
|
|
517
|
+
async writeTombstone(id) {
|
|
518
|
+
try {
|
|
519
|
+
await ensureDir(this.dir);
|
|
520
|
+
const line = JSON.stringify({ action: "delete", id }) + "\n";
|
|
521
|
+
await fsp.appendFile(this.indexFile, line, "utf8");
|
|
522
|
+
this.indexAppendCount++;
|
|
523
|
+
} catch {
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Compact the index: read all entries, drop tombstones, deduplicate
|
|
528
|
+
* (keep latest per session), and rewrite. Atomic via temp+rename.
|
|
529
|
+
*/
|
|
530
|
+
async compactIndex() {
|
|
531
|
+
const entries = await this.readIndex();
|
|
532
|
+
if (entries.length === 0) return;
|
|
533
|
+
const tmp = `${this.indexFile}.compact.tmp`;
|
|
534
|
+
const lines = entries.map((s) => JSON.stringify(s)).join("\n") + "\n";
|
|
535
|
+
await fsp.writeFile(tmp, lines, "utf8");
|
|
536
|
+
await fsp.rename(tmp, this.indexFile);
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Read the index file and return deduplicated session summaries.
|
|
540
|
+
* Entries with a matching tombstone are filtered out.
|
|
541
|
+
* Returns empty array when the index doesn't exist or is corrupt.
|
|
542
|
+
*/
|
|
543
|
+
async readIndex() {
|
|
544
|
+
let raw;
|
|
545
|
+
try {
|
|
546
|
+
raw = await fsp.readFile(this.indexFile, "utf8");
|
|
547
|
+
} catch {
|
|
548
|
+
return [];
|
|
549
|
+
}
|
|
550
|
+
const deleted = /* @__PURE__ */ new Set();
|
|
551
|
+
const seen = /* @__PURE__ */ new Map();
|
|
552
|
+
for (const line of raw.split("\n")) {
|
|
553
|
+
if (!line.trim()) continue;
|
|
554
|
+
try {
|
|
555
|
+
const entry = JSON.parse(line);
|
|
556
|
+
if (entry.action === "delete" && entry.id) {
|
|
557
|
+
deleted.add(entry.id);
|
|
558
|
+
seen.delete(entry.id);
|
|
559
|
+
continue;
|
|
560
|
+
}
|
|
561
|
+
if (entry.id && !deleted.has(entry.id)) {
|
|
562
|
+
seen.set(entry.id, entry);
|
|
563
|
+
}
|
|
564
|
+
} catch {
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return Array.from(seen.values());
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Rebuild the index from disk by scanning all sessions and writing a
|
|
571
|
+
* fresh _index.jsonl. Useful after manual cleanup or index corruption.
|
|
572
|
+
*/
|
|
573
|
+
async rebuildIndex() {
|
|
574
|
+
const ids = await this.collectSessionIds(this.dir);
|
|
575
|
+
const summaries = await Promise.all(ids.map((id) => this.summaryFor(id).catch(() => null)));
|
|
576
|
+
const valid = summaries.filter((s) => s !== null);
|
|
577
|
+
const tmp = `${this.indexFile}.tmp`;
|
|
578
|
+
const lines = valid.map((s) => JSON.stringify(s)).join("\n") + "\n";
|
|
579
|
+
await fsp.writeFile(tmp, lines, "utf8");
|
|
580
|
+
await fsp.rename(tmp, this.indexFile);
|
|
581
|
+
return valid.length;
|
|
582
|
+
}
|
|
583
|
+
/** Recursively collect session IDs from date-shard subdirectories.
|
|
584
|
+
* IDs include the date-prefix path (e.g. "2026-06-06/17-46-57Z_…").
|
|
585
|
+
* Skips `.jsonl`/`.summary.json` root files, dot-files, and
|
|
586
|
+
* sub-directories that belong to fleet/subagent sessions. */
|
|
587
|
+
async collectSessionIds(dir, prefix = "", depth = 0) {
|
|
465
588
|
const ids = [];
|
|
466
|
-
|
|
589
|
+
let entries;
|
|
590
|
+
try {
|
|
591
|
+
entries = await fsp.readdir(dir, { withFileTypes: true });
|
|
592
|
+
} catch {
|
|
593
|
+
return ids;
|
|
594
|
+
}
|
|
467
595
|
for (const entry of entries) {
|
|
468
|
-
|
|
596
|
+
if (entry.name.startsWith(".") && entry.name !== ".wrongstack") continue;
|
|
597
|
+
if (entry.name === "shared" || entry.name === "subagents" || entry.name === "attachments")
|
|
598
|
+
continue;
|
|
469
599
|
if (entry.isDirectory()) {
|
|
470
|
-
|
|
600
|
+
const childPrefix = depth === 0 ? entry.name : `${prefix}/${entry.name}`;
|
|
601
|
+
ids.push(...await this.collectSessionIds(path3.join(dir, entry.name), childPrefix, depth + 1));
|
|
471
602
|
} else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
472
|
-
|
|
603
|
+
if (entry.name === "_index.jsonl") continue;
|
|
604
|
+
const base = entry.name.replace(/\.jsonl$/, "");
|
|
605
|
+
ids.push(prefix ? `${prefix}/${base}` : base);
|
|
473
606
|
}
|
|
474
607
|
}
|
|
475
608
|
return ids;
|
|
@@ -492,9 +625,70 @@ var DefaultSessionStore = class {
|
|
|
492
625
|
return summary;
|
|
493
626
|
}
|
|
494
627
|
}
|
|
495
|
-
|
|
496
|
-
|
|
628
|
+
/**
|
|
629
|
+
* Delete a session and all associated files: JSONL, summary, plan/todos
|
|
630
|
+
* sidecars, and the session directory (fleet.json, shared/, subagents/).
|
|
631
|
+
*/
|
|
632
|
+
async deleteSession(id) {
|
|
633
|
+
await fsp.unlink(this.sessionPath(id, ".jsonl")).catch(() => void 0);
|
|
497
634
|
await fsp.unlink(this.sessionPath(id, ".summary.json")).catch(() => void 0);
|
|
635
|
+
const shardDir = path3.dirname(path3.join(this.dir, id));
|
|
636
|
+
const base = path3.basename(id);
|
|
637
|
+
for (const ext of [".plan.json", ".todos.json"]) {
|
|
638
|
+
await fsp.unlink(path3.join(shardDir, `${base}${ext}`)).catch(() => void 0);
|
|
639
|
+
}
|
|
640
|
+
const sessDir = path3.join(shardDir, base);
|
|
641
|
+
await fsp.rm(sessDir, { recursive: true, force: true }).catch(() => void 0);
|
|
642
|
+
await this.writeTombstone(id);
|
|
643
|
+
}
|
|
644
|
+
async delete(id) {
|
|
645
|
+
await this.deleteSession(id);
|
|
646
|
+
}
|
|
647
|
+
async prune(maxAgeDays = 30) {
|
|
648
|
+
const cutoff = Date.now() - maxAgeDays * 864e5;
|
|
649
|
+
let deleted = 0;
|
|
650
|
+
let activeSessionId = null;
|
|
651
|
+
try {
|
|
652
|
+
const raw = await fsp.readFile(path3.join(this.dir, "active.json"), "utf8");
|
|
653
|
+
const active = JSON.parse(raw);
|
|
654
|
+
activeSessionId = active.sessionId ?? null;
|
|
655
|
+
} catch {
|
|
656
|
+
}
|
|
657
|
+
const entries = await fsp.readdir(this.dir, { withFileTypes: true }).catch(() => []);
|
|
658
|
+
for (const entry of entries) {
|
|
659
|
+
if (!entry.isDirectory()) continue;
|
|
660
|
+
const dateDir = path3.join(this.dir, entry.name);
|
|
661
|
+
const files = await fsp.readdir(dateDir, { withFileTypes: true }).catch(() => []);
|
|
662
|
+
for (const file of files) {
|
|
663
|
+
if (!file.isFile() || !file.name.endsWith(".jsonl")) continue;
|
|
664
|
+
const jsonlPath = path3.join(dateDir, file.name);
|
|
665
|
+
try {
|
|
666
|
+
const stat5 = await fsp.stat(jsonlPath);
|
|
667
|
+
if (stat5.mtimeMs >= cutoff) continue;
|
|
668
|
+
} catch {
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
const id = `${entry.name}/${file.name.replace(/\.jsonl$/, "")}`;
|
|
672
|
+
if (activeSessionId && id === activeSessionId) continue;
|
|
673
|
+
await this.deleteSession(id);
|
|
674
|
+
deleted++;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
if (deleted > 0) {
|
|
678
|
+
await this.compactIndex().catch(() => void 0);
|
|
679
|
+
}
|
|
680
|
+
for (const entry of entries) {
|
|
681
|
+
if (!entry.isDirectory()) continue;
|
|
682
|
+
const dateDir = path3.join(this.dir, entry.name);
|
|
683
|
+
try {
|
|
684
|
+
const remaining = await fsp.readdir(dateDir);
|
|
685
|
+
if (remaining.length === 0) {
|
|
686
|
+
await fsp.rmdir(dateDir).catch(() => void 0);
|
|
687
|
+
}
|
|
688
|
+
} catch {
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
return deleted;
|
|
498
692
|
}
|
|
499
693
|
async clearHistory(id) {
|
|
500
694
|
await this.ensureShardDir(id);
|
|
@@ -516,13 +710,42 @@ var DefaultSessionStore = class {
|
|
|
516
710
|
const data = await this.load(id);
|
|
517
711
|
const firstUser = data.events.find((e) => e.type === "user_input");
|
|
518
712
|
const title = firstUser && firstUser.type === "user_input" ? userInputTitle(firstUser.content) : "(empty session)";
|
|
713
|
+
let iterationCount = 0;
|
|
714
|
+
let toolCallCount = 0;
|
|
715
|
+
let toolErrorCount = 0;
|
|
716
|
+
let fileChangeCount = 0;
|
|
717
|
+
const toolBreakdown = {};
|
|
718
|
+
let outcome = void 0;
|
|
719
|
+
const lastEvent = data.events[data.events.length - 1];
|
|
720
|
+
for (const e of data.events) {
|
|
721
|
+
if (e.type === "in_flight_start") iterationCount++;
|
|
722
|
+
else if (e.type === "tool_call_start") {
|
|
723
|
+
toolCallCount++;
|
|
724
|
+
toolBreakdown[e.name] = (toolBreakdown[e.name] ?? 0) + 1;
|
|
725
|
+
} else if (e.type === "tool_result" && e.isError) toolErrorCount++;
|
|
726
|
+
else if (e.type === "file_snapshot") fileChangeCount += e.files.length;
|
|
727
|
+
}
|
|
728
|
+
if (lastEvent?.type === "session_end") {
|
|
729
|
+
outcome = "completed";
|
|
730
|
+
} else if (lastEvent?.type === "in_flight_start") {
|
|
731
|
+
outcome = "aborted";
|
|
732
|
+
} else if (data.events.some((e) => e.type === "error")) {
|
|
733
|
+
outcome = "error";
|
|
734
|
+
}
|
|
519
735
|
return {
|
|
520
736
|
id,
|
|
521
737
|
title,
|
|
522
738
|
startedAt: data.metadata.startedAt,
|
|
739
|
+
endedAt: data.metadata.endedAt,
|
|
523
740
|
model: data.metadata.model ?? "unknown",
|
|
524
741
|
provider: data.metadata.provider ?? "unknown",
|
|
525
|
-
tokenTotal: data.usage.input + data.usage.output
|
|
742
|
+
tokenTotal: data.usage.input + data.usage.output,
|
|
743
|
+
iterationCount: iterationCount > 0 ? iterationCount : void 0,
|
|
744
|
+
toolCallCount: toolCallCount > 0 ? toolCallCount : void 0,
|
|
745
|
+
toolErrorCount: toolErrorCount > 0 ? toolErrorCount : void 0,
|
|
746
|
+
fileChangeCount: fileChangeCount > 0 ? fileChangeCount : void 0,
|
|
747
|
+
toolBreakdown: Object.keys(toolBreakdown).length > 0 ? toolBreakdown : {},
|
|
748
|
+
outcome
|
|
526
749
|
};
|
|
527
750
|
} catch {
|
|
528
751
|
return {
|
|
@@ -621,9 +844,10 @@ var FileSessionWriter = class {
|
|
|
621
844
|
this.meta = meta;
|
|
622
845
|
this.events = events;
|
|
623
846
|
this.resumed = opts.resumed ?? false;
|
|
624
|
-
this.manifestFile = opts.dir ? path3.join(opts.dir, `${id}.summary.json`) : "";
|
|
847
|
+
this.manifestFile = opts.dir ? path3.join(opts.dir, `${path3.basename(id)}.summary.json`) : "";
|
|
625
848
|
this.filePath = opts.filePath ?? "";
|
|
626
849
|
this.secretScrubber = opts.secretScrubber;
|
|
850
|
+
this.onCloseCb = opts.onClose;
|
|
627
851
|
this.summary = {
|
|
628
852
|
id,
|
|
629
853
|
title: "(empty session)",
|
|
@@ -653,6 +877,15 @@ var FileSessionWriter = class {
|
|
|
653
877
|
appendFailCount = 0;
|
|
654
878
|
lastAppendWarnAt = 0;
|
|
655
879
|
secretScrubber;
|
|
880
|
+
onCloseCb;
|
|
881
|
+
// ── Enriched summary tracking ──────────────────────────────────────────
|
|
882
|
+
iterationCount = 0;
|
|
883
|
+
toolCallCount = 0;
|
|
884
|
+
toolErrorCount = 0;
|
|
885
|
+
toolBreakdown = {};
|
|
886
|
+
fileChangeCount = 0;
|
|
887
|
+
compactionCount = 0;
|
|
888
|
+
outcome = void 0;
|
|
656
889
|
/**
|
|
657
890
|
* Scrub secrets out of conversation-turn events before they are observed
|
|
658
891
|
* for the summary, written to the JSONL log, or surfaced on resume. Only
|
|
@@ -730,8 +963,22 @@ var FileSessionWriter = class {
|
|
|
730
963
|
observeForSummary(event) {
|
|
731
964
|
if (event.type === "tool_use") {
|
|
732
965
|
this.openToolUses.add(event.id);
|
|
966
|
+
} else if (event.type === "tool_call_start") {
|
|
967
|
+
this.toolCallCount++;
|
|
968
|
+
this.toolBreakdown[event.name] = (this.toolBreakdown[event.name] ?? 0) + 1;
|
|
733
969
|
} else if (event.type === "tool_result") {
|
|
734
970
|
this.openToolUses.delete(event.id);
|
|
971
|
+
if (event.isError) {
|
|
972
|
+
this.toolErrorCount++;
|
|
973
|
+
this.outcome = "error";
|
|
974
|
+
}
|
|
975
|
+
} else if (event.type === "file_snapshot") {
|
|
976
|
+
this.fileChangeCount += event.files.length;
|
|
977
|
+
} else if (event.type === "compaction") {
|
|
978
|
+
this.compactionCount++;
|
|
979
|
+
}
|
|
980
|
+
if (event.type === "error" || event.type === "provider_error") {
|
|
981
|
+
this.outcome = "error";
|
|
735
982
|
}
|
|
736
983
|
if (event.type === "user_input" && this.summary.title === "(empty session)") {
|
|
737
984
|
this.summary = { ...this.summary, title: userInputTitle(event.content) };
|
|
@@ -742,18 +989,35 @@ var FileSessionWriter = class {
|
|
|
742
989
|
} else if (event.type === "session_end") {
|
|
743
990
|
const total = event.usage.input + event.usage.output;
|
|
744
991
|
if (total > 0) this.summary = { ...this.summary, tokenTotal: total };
|
|
992
|
+
} else if (event.type === "in_flight_start") {
|
|
993
|
+
this.iterationCount++;
|
|
745
994
|
}
|
|
746
995
|
}
|
|
747
996
|
async close() {
|
|
748
997
|
if (this.closing) return;
|
|
749
998
|
this.closing = true;
|
|
750
999
|
this.closed = true;
|
|
1000
|
+
this.summary = {
|
|
1001
|
+
...this.summary,
|
|
1002
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1003
|
+
iterationCount: this.iterationCount,
|
|
1004
|
+
toolCallCount: this.toolCallCount,
|
|
1005
|
+
toolErrorCount: this.toolErrorCount,
|
|
1006
|
+
fileChangeCount: this.fileChangeCount,
|
|
1007
|
+
compactionCount: this.compactionCount > 0 ? this.compactionCount : void 0,
|
|
1008
|
+
toolBreakdown: { ...this.toolBreakdown },
|
|
1009
|
+
outcome: this.outcome ?? "completed"
|
|
1010
|
+
};
|
|
751
1011
|
if (this.manifestFile) {
|
|
752
1012
|
try {
|
|
753
1013
|
await atomicWrite(this.manifestFile, JSON.stringify(this.summary), { mode: 384 });
|
|
754
1014
|
} catch {
|
|
755
1015
|
}
|
|
756
1016
|
}
|
|
1017
|
+
try {
|
|
1018
|
+
await this.onCloseCb?.(this.summary);
|
|
1019
|
+
} catch {
|
|
1020
|
+
}
|
|
757
1021
|
try {
|
|
758
1022
|
await this.handle.close();
|
|
759
1023
|
} catch {
|
|
@@ -795,7 +1059,7 @@ var FileSessionWriter = class {
|
|
|
795
1059
|
let targetCheckpointLine = -1;
|
|
796
1060
|
let afterTarget = false;
|
|
797
1061
|
for (let i = 0; i < lines.length; i++) {
|
|
798
|
-
const line = lines[i];
|
|
1062
|
+
const line = expectDefined2(lines[i]);
|
|
799
1063
|
if (!line.trim()) continue;
|
|
800
1064
|
let event;
|
|
801
1065
|
try {
|
|
@@ -1971,6 +2235,12 @@ function compileUserRegex(pattern, flags) {
|
|
|
1971
2235
|
}
|
|
1972
2236
|
|
|
1973
2237
|
// src/storage/session-reader.ts
|
|
2238
|
+
function expectDefined3(value) {
|
|
2239
|
+
if (value === null || value === void 0) {
|
|
2240
|
+
throw new Error("Expected value to be defined");
|
|
2241
|
+
}
|
|
2242
|
+
return value;
|
|
2243
|
+
}
|
|
1974
2244
|
var DefaultSessionReader = class {
|
|
1975
2245
|
store;
|
|
1976
2246
|
constructor(opts) {
|
|
@@ -2032,7 +2302,7 @@ var DefaultSessionReader = class {
|
|
|
2032
2302
|
continue;
|
|
2033
2303
|
}
|
|
2034
2304
|
for (let i = 0; i < data.events.length; i++) {
|
|
2035
|
-
const ev = data.events[i];
|
|
2305
|
+
const ev = expectDefined3(data.events[i]);
|
|
2036
2306
|
if (allowedTypes && !allowedTypes.has(ev.type)) continue;
|
|
2037
2307
|
const text = eventText(ev);
|
|
2038
2308
|
if (text === null) continue;
|
|
@@ -2337,8 +2607,11 @@ var SessionAnalyzer = class {
|
|
|
2337
2607
|
}
|
|
2338
2608
|
calcDuration(events) {
|
|
2339
2609
|
if (events.length < 2) return 0;
|
|
2340
|
-
const
|
|
2341
|
-
const
|
|
2610
|
+
const firstEvent = events[0];
|
|
2611
|
+
const lastEvent = events[events.length - 1];
|
|
2612
|
+
if (!firstEvent || !lastEvent) return 0;
|
|
2613
|
+
const first = new Date(firstEvent.ts).getTime();
|
|
2614
|
+
const last = new Date(lastEvent.ts).getTime();
|
|
2342
2615
|
return last - first;
|
|
2343
2616
|
}
|
|
2344
2617
|
};
|
|
@@ -3291,6 +3564,12 @@ function getDangerousCapabilities(toolOrCaps) {
|
|
|
3291
3564
|
init_atomic_write();
|
|
3292
3565
|
|
|
3293
3566
|
// src/utils/glob-match.ts
|
|
3567
|
+
function expectDefined4(value) {
|
|
3568
|
+
if (value === null || value === void 0) {
|
|
3569
|
+
throw new Error("Expected value to be defined");
|
|
3570
|
+
}
|
|
3571
|
+
return value;
|
|
3572
|
+
}
|
|
3294
3573
|
function escapeRegex(s) {
|
|
3295
3574
|
return s.replace(/[.+^${}()|\\]/g, "\\$&");
|
|
3296
3575
|
}
|
|
@@ -3302,7 +3581,7 @@ function getCachedGlob(pattern) {
|
|
|
3302
3581
|
if (COMPILED_GLOB_CACHE.size >= CACHE_MAX_SIZE) {
|
|
3303
3582
|
const keys = [...COMPILED_GLOB_CACHE.keys()];
|
|
3304
3583
|
for (let i = 0; i < Math.floor(CACHE_MAX_SIZE / 4); i++) {
|
|
3305
|
-
COMPILED_GLOB_CACHE.delete(keys[i]);
|
|
3584
|
+
COMPILED_GLOB_CACHE.delete(expectDefined4(keys[i]));
|
|
3306
3585
|
}
|
|
3307
3586
|
}
|
|
3308
3587
|
const re = compileGlob(pattern);
|
|
@@ -4160,13 +4439,19 @@ function parseDescription(raw) {
|
|
|
4160
4439
|
const scope = [];
|
|
4161
4440
|
const coversMatch = /(?:covers|for|including)\s+([^.]+)/i.exec(desc);
|
|
4162
4441
|
if (coversMatch) {
|
|
4163
|
-
const items = coversMatch[1].replace(/[·•]/g, ",").split(",").map((s) => s.trim()).filter(Boolean);
|
|
4442
|
+
const items = coversMatch[1] ?? "".replace(/[·•]/g, ",").split(",").map((s) => s.trim()).filter(Boolean);
|
|
4164
4443
|
scope.push(...items);
|
|
4165
4444
|
}
|
|
4166
4445
|
return { trigger, scope };
|
|
4167
4446
|
}
|
|
4168
4447
|
|
|
4169
4448
|
// src/utils/json-repair.ts
|
|
4449
|
+
function expectDefined5(value) {
|
|
4450
|
+
if (value === null || value === void 0) {
|
|
4451
|
+
throw new Error("Expected value to be defined");
|
|
4452
|
+
}
|
|
4453
|
+
return value;
|
|
4454
|
+
}
|
|
4170
4455
|
function completePartialObject(s) {
|
|
4171
4456
|
if (!s.trim().startsWith("{")) return s;
|
|
4172
4457
|
if (tryParse(s).ok) return s;
|
|
@@ -4178,7 +4463,7 @@ function completePartialObject(s) {
|
|
|
4178
4463
|
let contentEnd = 0;
|
|
4179
4464
|
let stringBraceDepth = 0;
|
|
4180
4465
|
for (let i = 0; i < s.length; i++) {
|
|
4181
|
-
const ch = s[i];
|
|
4466
|
+
const ch = expectDefined5(s[i]);
|
|
4182
4467
|
if (inString) {
|
|
4183
4468
|
contentEnd = i + 1;
|
|
4184
4469
|
if (escaped) {
|
|
@@ -4563,6 +4848,12 @@ var DefaultProviderRunner = class {
|
|
|
4563
4848
|
};
|
|
4564
4849
|
|
|
4565
4850
|
// src/utils/token-estimate.ts
|
|
4851
|
+
function expectDefined6(value) {
|
|
4852
|
+
if (value === null || value === void 0) {
|
|
4853
|
+
throw new Error("Expected value to be defined");
|
|
4854
|
+
}
|
|
4855
|
+
return value;
|
|
4856
|
+
}
|
|
4566
4857
|
var RoughTokenEstimate = (text, charsPerToken = 3.5) => Math.max(1, Math.ceil(text.length / charsPerToken));
|
|
4567
4858
|
var ESTIMATE_CACHE = /* @__PURE__ */ new Map();
|
|
4568
4859
|
var ESTIMATE_CACHE_MAX_SIZE = 1e4;
|
|
@@ -4572,7 +4863,7 @@ function getCachedEstimate(key, compute) {
|
|
|
4572
4863
|
if (ESTIMATE_CACHE.size >= ESTIMATE_CACHE_MAX_SIZE) {
|
|
4573
4864
|
const keys = [...ESTIMATE_CACHE.keys()];
|
|
4574
4865
|
for (let i = 0; i < Math.floor(ESTIMATE_CACHE_MAX_SIZE / 4); i++) {
|
|
4575
|
-
ESTIMATE_CACHE.delete(keys[i]);
|
|
4866
|
+
ESTIMATE_CACHE.delete(expectDefined6(keys[i]));
|
|
4576
4867
|
}
|
|
4577
4868
|
}
|
|
4578
4869
|
const estimate = compute();
|
|
@@ -4962,7 +5253,7 @@ var IntelligentCompactor = class {
|
|
|
4962
5253
|
maxTokens: 1024
|
|
4963
5254
|
};
|
|
4964
5255
|
const ac = ctx.signal ? void 0 : new AbortController();
|
|
4965
|
-
const signal = ctx.signal ?? ac
|
|
5256
|
+
const signal = ctx.signal ?? ac?.signal;
|
|
4966
5257
|
const res = await this.provider.complete(req, { signal });
|
|
4967
5258
|
const textBlocks = res.content.filter(isTextBlock);
|
|
4968
5259
|
return textBlocks.map((b) => b.text).join("\n").trim() || "(empty summary)";
|
|
@@ -5065,6 +5356,12 @@ var IntelligentCompactor = class {
|
|
|
5065
5356
|
};
|
|
5066
5357
|
|
|
5067
5358
|
// src/models/llm-selector.ts
|
|
5359
|
+
function expectDefined7(value) {
|
|
5360
|
+
if (value === null || value === void 0) {
|
|
5361
|
+
throw new Error("Expected value to be defined");
|
|
5362
|
+
}
|
|
5363
|
+
return value;
|
|
5364
|
+
}
|
|
5068
5365
|
var DEFAULT_SYSTEM_PROMPT = `You are a context pruning assistant. Given a conversation history and a token budget, decide which message ranges are worth keeping verbatim and which should be collapsed into summaries.
|
|
5069
5366
|
|
|
5070
5367
|
Output a JSON object with this structure:
|
|
@@ -5105,7 +5402,7 @@ function formatMessages(messages, maxChars = 8e3) {
|
|
|
5105
5402
|
const lines = [];
|
|
5106
5403
|
let used = 0;
|
|
5107
5404
|
for (let i = 0; i < messages.length; i++) {
|
|
5108
|
-
const m = messages[i];
|
|
5405
|
+
const m = expectDefined7(messages[i]);
|
|
5109
5406
|
const role = m.role.padEnd(10, " ");
|
|
5110
5407
|
let text;
|
|
5111
5408
|
if (typeof m.content === "string") {
|
|
@@ -5170,7 +5467,7 @@ IMPORTANT: Total conversation (${totalTokens} tokens) exceeds budget (${effectiv
|
|
|
5170
5467
|
let tokenCount = 0;
|
|
5171
5468
|
let startIdx = 0;
|
|
5172
5469
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
5173
|
-
const m = messages[i];
|
|
5470
|
+
const m = expectDefined7(messages[i]);
|
|
5174
5471
|
const cost = typeof m.content === "string" ? Math.ceil(m.content.length / 4) : m.content.reduce(
|
|
5175
5472
|
(acc, b) => acc + (b.type === "text" ? Math.ceil(b.text.length / 4) : Math.ceil(JSON.stringify(b).length / 4)),
|
|
5176
5473
|
0
|
|
@@ -5381,6 +5678,7 @@ Summarize the following message range:`;
|
|
|
5381
5678
|
let boundary = preserveIdx;
|
|
5382
5679
|
for (let i = preserveIdx; i < messages.length && i < preserveIdx + 6; i++) {
|
|
5383
5680
|
const m = messages[i];
|
|
5681
|
+
if (!m) continue;
|
|
5384
5682
|
if (m.role === "user" && this.hasTextContent(m)) {
|
|
5385
5683
|
boundary = i;
|
|
5386
5684
|
break;
|
|
@@ -5776,6 +6074,12 @@ function createToolOutputSerializer(opts = {}) {
|
|
|
5776
6074
|
}
|
|
5777
6075
|
|
|
5778
6076
|
// src/execution/tool-executor.ts
|
|
6077
|
+
function expectDefined8(value) {
|
|
6078
|
+
if (value === null || value === void 0) {
|
|
6079
|
+
throw new Error("Expected value to be defined");
|
|
6080
|
+
}
|
|
6081
|
+
return value;
|
|
6082
|
+
}
|
|
5779
6083
|
var ToolExecutor = class {
|
|
5780
6084
|
constructor(registry, opts) {
|
|
5781
6085
|
this.registry = registry;
|
|
@@ -6064,6 +6368,9 @@ ${post.additionalContext}` };
|
|
|
6064
6368
|
async runStreamedTool(tool, input, ctx, signal, toolUseId) {
|
|
6065
6369
|
let finalOutput;
|
|
6066
6370
|
let sawFinal = false;
|
|
6371
|
+
if (!tool.executeStream) {
|
|
6372
|
+
throw new Error(`Tool "${tool.name}" does not support streaming execution`);
|
|
6373
|
+
}
|
|
6067
6374
|
const stream = tool.executeStream(input, ctx, { signal });
|
|
6068
6375
|
for await (const ev of stream) {
|
|
6069
6376
|
if (ev.type === "final") {
|
|
@@ -6168,7 +6475,7 @@ function hasMalformedArguments(input) {
|
|
|
6168
6475
|
function extractMalformedRaw(input) {
|
|
6169
6476
|
if (!hasMalformedArguments(input)) return void 0;
|
|
6170
6477
|
const obj = input;
|
|
6171
|
-
const value = obj[Object.keys(obj)[0]];
|
|
6478
|
+
const value = obj[expectDefined8(Object.keys(obj)[0])];
|
|
6172
6479
|
if (value === void 0 || value === null) return void 0;
|
|
6173
6480
|
if (typeof value === "string") return value;
|
|
6174
6481
|
try {
|
|
@@ -7129,16 +7436,16 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
7129
7436
|
}
|
|
7130
7437
|
if (exceeded.length === 0) return [];
|
|
7131
7438
|
if (!this._onThreshold) {
|
|
7132
|
-
const first2 = exceeded[0];
|
|
7439
|
+
const first2 = exceeded[0] ?? { kind: "iterations", limit: 0, used: 0 };
|
|
7133
7440
|
throw new BudgetExceededError(first2.kind, first2.limit, first2.used);
|
|
7134
7441
|
}
|
|
7135
7442
|
if (this._mode === "sync") {
|
|
7136
|
-
const first2 = exceeded[0];
|
|
7443
|
+
const first2 = exceeded[0] ?? { kind: "iterations", limit: 0, used: 0 };
|
|
7137
7444
|
throw new BudgetExceededError(first2.kind, first2.limit, first2.used);
|
|
7138
7445
|
}
|
|
7139
7446
|
const bus = this._events;
|
|
7140
7447
|
if (!bus || !bus.hasListenerFor("budget.threshold_reached")) {
|
|
7141
|
-
const first2 = exceeded[0];
|
|
7448
|
+
const first2 = exceeded[0] ?? { kind: "iterations", limit: 0, used: 0 };
|
|
7142
7449
|
throw new BudgetExceededError(first2.kind, first2.limit, first2.used);
|
|
7143
7450
|
}
|
|
7144
7451
|
for (const entry of exceeded) {
|
|
@@ -7146,8 +7453,9 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
7146
7453
|
const decision2 = this._negotiateExtension(entry.kind, exceeded);
|
|
7147
7454
|
this._pendingNegotiations.set(entry.kind, decision2);
|
|
7148
7455
|
}
|
|
7149
|
-
const first = exceeded[0];
|
|
7456
|
+
const first = exceeded[0] ?? { kind: "iterations", limit: 0, used: 0 };
|
|
7150
7457
|
const decision = this._pendingNegotiations.get(first.kind);
|
|
7458
|
+
if (!decision) throw new Error(`No pending negotiation for ${first.kind}`);
|
|
7151
7459
|
throw new BudgetThresholdSignal(first.kind, first.limit, first.used, decision);
|
|
7152
7460
|
}
|
|
7153
7461
|
/**
|
|
@@ -7169,8 +7477,11 @@ var SubagentBudget = class _SubagentBudget {
|
|
|
7169
7477
|
* a fresh signal.
|
|
7170
7478
|
*/
|
|
7171
7479
|
async _negotiateExtension(kind, exceeded) {
|
|
7480
|
+
if (!this._onThreshold) {
|
|
7481
|
+
return "stop";
|
|
7482
|
+
}
|
|
7172
7483
|
try {
|
|
7173
|
-
const first = exceeded[0];
|
|
7484
|
+
const first = exceeded[0] ?? { kind: "iterations", limit: 0, used: 0 };
|
|
7174
7485
|
const result = this._onThreshold({
|
|
7175
7486
|
kind: first.kind,
|
|
7176
7487
|
used: first.used,
|
|
@@ -9653,6 +9964,11 @@ function getAgentDefinition(role) {
|
|
|
9653
9964
|
|
|
9654
9965
|
// src/coordination/dispatcher.ts
|
|
9655
9966
|
var DEFAULT_DISPATCH_ROLE = "executor";
|
|
9967
|
+
var FALLBACK_DEFINITION = {
|
|
9968
|
+
config: { role: "unknown", name: "Unknown Agent" },
|
|
9969
|
+
budget: {},
|
|
9970
|
+
capability: { phase: "meta", summary: "", keywords: [] }
|
|
9971
|
+
};
|
|
9656
9972
|
function normalize(text) {
|
|
9657
9973
|
return ` ${text.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim()} `;
|
|
9658
9974
|
}
|
|
@@ -9680,7 +9996,7 @@ function scoreAgents(task, catalog = AGENT_CATALOG) {
|
|
|
9680
9996
|
}
|
|
9681
9997
|
function heuristicConfidence(candidates) {
|
|
9682
9998
|
if (candidates.length === 0) return 0;
|
|
9683
|
-
const top = candidates[0]
|
|
9999
|
+
const top = candidates[0]?.score ?? 0;
|
|
9684
10000
|
const second = candidates[1]?.score ?? 0;
|
|
9685
10001
|
const strength = Math.min(1, top / 3);
|
|
9686
10002
|
const margin = (top - second + 1) / (top + 1);
|
|
@@ -9696,7 +10012,7 @@ async function dispatchAgent(task, opts = {}) {
|
|
|
9696
10012
|
if (top && confidence >= threshold) {
|
|
9697
10013
|
return {
|
|
9698
10014
|
role: top.role,
|
|
9699
|
-
definition: catalog[top.role],
|
|
10015
|
+
definition: catalog[top.role] ?? FALLBACK_DEFINITION,
|
|
9700
10016
|
confidence,
|
|
9701
10017
|
method: "heuristic",
|
|
9702
10018
|
reason: `Matched keywords: ${top.matched.slice(0, 4).join(", ")}`,
|
|
@@ -9704,7 +10020,7 @@ async function dispatchAgent(task, opts = {}) {
|
|
|
9704
10020
|
};
|
|
9705
10021
|
}
|
|
9706
10022
|
if (opts.classifier) {
|
|
9707
|
-
const pool = (candidates.length > 0 ? candidates.slice(0, maxCandidates).map((c) => catalog[c.role]) : ALL_AGENT_DEFINITIONS).map((d) => ({
|
|
10023
|
+
const pool = (candidates.length > 0 ? candidates.slice(0, maxCandidates).map((c) => catalog[c.role] ?? FALLBACK_DEFINITION) : ALL_AGENT_DEFINITIONS).map((d) => ({
|
|
9708
10024
|
role: d.config.role,
|
|
9709
10025
|
name: d.config.name,
|
|
9710
10026
|
summary: d.capability.summary
|
|
@@ -9714,7 +10030,7 @@ async function dispatchAgent(task, opts = {}) {
|
|
|
9714
10030
|
if (choice && catalog[choice.role]) {
|
|
9715
10031
|
return {
|
|
9716
10032
|
role: choice.role,
|
|
9717
|
-
definition: catalog[choice.role],
|
|
10033
|
+
definition: catalog[choice.role] ?? FALLBACK_DEFINITION,
|
|
9718
10034
|
confidence: 1,
|
|
9719
10035
|
method: "llm",
|
|
9720
10036
|
reason: choice.reason ?? "Selected by LLM classifier",
|
|
@@ -9727,17 +10043,17 @@ async function dispatchAgent(task, opts = {}) {
|
|
|
9727
10043
|
if (top) {
|
|
9728
10044
|
return {
|
|
9729
10045
|
role: top.role,
|
|
9730
|
-
definition: catalog[top.role],
|
|
10046
|
+
definition: catalog[top.role] ?? FALLBACK_DEFINITION,
|
|
9731
10047
|
confidence,
|
|
9732
10048
|
method: "heuristic",
|
|
9733
10049
|
reason: `Weak match (${top.matched.slice(0, 3).join(", ") || "low signal"})`,
|
|
9734
10050
|
alternatives: candidates.slice(1, maxCandidates)
|
|
9735
10051
|
};
|
|
9736
10052
|
}
|
|
9737
|
-
const fallbackRole = catalog[DEFAULT_DISPATCH_ROLE] ? DEFAULT_DISPATCH_ROLE : Object.keys(catalog)[0];
|
|
10053
|
+
const fallbackRole = catalog[DEFAULT_DISPATCH_ROLE] ? DEFAULT_DISPATCH_ROLE : Object.keys(catalog)[0] ?? DEFAULT_DISPATCH_ROLE;
|
|
9738
10054
|
return {
|
|
9739
10055
|
role: fallbackRole,
|
|
9740
|
-
definition: catalog[fallbackRole],
|
|
10056
|
+
definition: catalog[fallbackRole] ?? FALLBACK_DEFINITION,
|
|
9741
10057
|
confidence: 0,
|
|
9742
10058
|
method: "fallback",
|
|
9743
10059
|
reason: "No keyword signal; defaulting to the generalist Executor",
|
|
@@ -10550,6 +10866,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
10550
10866
|
takeNextDispatchableTask() {
|
|
10551
10867
|
for (let i = 0; i < this.pendingTasks.length; i++) {
|
|
10552
10868
|
const task = this.pendingTasks[i];
|
|
10869
|
+
if (!task) continue;
|
|
10553
10870
|
const subagentId = task.subagentId ? this.isIdleSubagent(task.subagentId) ? task.subagentId : null : this.findIdleSubagent();
|
|
10554
10871
|
if (!subagentId) continue;
|
|
10555
10872
|
this.pendingTasks.splice(i, 1);
|
|
@@ -10741,14 +11058,14 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
10741
11058
|
const idleExceeded = idleLimit !== void 0 && budget.idleMs() >= idleLimit;
|
|
10742
11059
|
if (idleExceeded && !wallExceeded) {
|
|
10743
11060
|
this.subagents.get(ctx.subagentId)?.abortController.abort();
|
|
10744
|
-
reject(new BudgetExceededError("timeout", idleLimit, budget.idleMs()));
|
|
11061
|
+
reject(new BudgetExceededError("timeout", idleLimit ?? 0, budget.idleMs()));
|
|
10745
11062
|
return;
|
|
10746
11063
|
}
|
|
10747
11064
|
if (!wallExceeded) {
|
|
10748
11065
|
scheduleNext();
|
|
10749
11066
|
return;
|
|
10750
11067
|
}
|
|
10751
|
-
const limit = wallLimit;
|
|
11068
|
+
const limit = wallLimit ?? 0;
|
|
10752
11069
|
if (!budget.onThreshold) {
|
|
10753
11070
|
this.subagents.get(ctx.subagentId)?.abortController.abort();
|
|
10754
11071
|
reject(new BudgetExceededError("timeout", limit, elapsed));
|
|
@@ -10907,6 +11224,12 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
|
|
|
10907
11224
|
};
|
|
10908
11225
|
|
|
10909
11226
|
// src/execution/parallel-eternal-engine.ts
|
|
11227
|
+
function expectDefined9(value) {
|
|
11228
|
+
if (value === null || value === void 0) {
|
|
11229
|
+
throw new Error("Expected value to be defined");
|
|
11230
|
+
}
|
|
11231
|
+
return value;
|
|
11232
|
+
}
|
|
10910
11233
|
function sleep2(ms) {
|
|
10911
11234
|
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
10912
11235
|
}
|
|
@@ -11065,7 +11388,7 @@ var ParallelEternalEngine = class {
|
|
|
11065
11388
|
// Fan-out
|
|
11066
11389
|
// -------------------------------------------------------------------------
|
|
11067
11390
|
async fanOut(goal, tasks) {
|
|
11068
|
-
const coordinator = this.coordinator;
|
|
11391
|
+
const coordinator = expectDefined9(this.coordinator);
|
|
11069
11392
|
const slotCount = Math.min(this.slots, tasks.length);
|
|
11070
11393
|
const routes = this.dispatchEnabled ? await Promise.all(
|
|
11071
11394
|
tasks.slice(0, slotCount).map(
|
|
@@ -11097,7 +11420,7 @@ ${recentJournal}` : "No prior iterations.",
|
|
|
11097
11420
|
const routeInfo = [];
|
|
11098
11421
|
const spawnPromises = [];
|
|
11099
11422
|
for (let i = 0; i < slotCount; i++) {
|
|
11100
|
-
const task = tasks[i];
|
|
11423
|
+
const task = expectDefined9(tasks[i]);
|
|
11101
11424
|
const route = routes[i] ?? null;
|
|
11102
11425
|
const subagentId = `parallel-${this.iterations}-${i}`;
|
|
11103
11426
|
const taskId = randomUUID();
|
|
@@ -11470,7 +11793,7 @@ var InMemoryBridgeTransport = class {
|
|
|
11470
11793
|
}
|
|
11471
11794
|
subscribe(agentId, handler) {
|
|
11472
11795
|
if (!this.subs.has(agentId)) this.subs.set(agentId, /* @__PURE__ */ new Set());
|
|
11473
|
-
this.subs.get(agentId)
|
|
11796
|
+
this.subs.get(agentId)?.add(handler);
|
|
11474
11797
|
return () => this.subs.get(agentId)?.delete(handler);
|
|
11475
11798
|
}
|
|
11476
11799
|
close(agentId) {
|
|
@@ -11588,6 +11911,12 @@ function createMessage(type, from, payload, to) {
|
|
|
11588
11911
|
priority: "normal"
|
|
11589
11912
|
};
|
|
11590
11913
|
}
|
|
11914
|
+
function expectDefined10(value) {
|
|
11915
|
+
if (value === null || value === void 0) {
|
|
11916
|
+
throw new Error("Expected value to be defined");
|
|
11917
|
+
}
|
|
11918
|
+
return value;
|
|
11919
|
+
}
|
|
11591
11920
|
var GLOB_CHARS = /* @__PURE__ */ new Set(["*", "?", "["]);
|
|
11592
11921
|
var IS_WINDOWS = process.platform === "win32";
|
|
11593
11922
|
var SEP = IS_WINDOWS ? "\\" : "/";
|
|
@@ -11601,7 +11930,7 @@ function globToRegex(pat) {
|
|
|
11601
11930
|
let i = 0;
|
|
11602
11931
|
let re = "^";
|
|
11603
11932
|
while (i < pat.length) {
|
|
11604
|
-
const c = pat[i];
|
|
11933
|
+
const c = expectDefined10(pat[i]);
|
|
11605
11934
|
if (c === "*") {
|
|
11606
11935
|
if (pat[i + 1] === "*") {
|
|
11607
11936
|
re += ".*";
|
|
@@ -11640,7 +11969,7 @@ function globToRegex(pat) {
|
|
|
11640
11969
|
}
|
|
11641
11970
|
function baseDir(pat) {
|
|
11642
11971
|
let i = pat.length - 1;
|
|
11643
|
-
while (i >= 0 && !GLOB_CHARS.has(pat[i]) && pat[i] !== SEP && pat[i] !== "/") i--;
|
|
11972
|
+
while (i >= 0 && !GLOB_CHARS.has(expectDefined10(pat[i])) && pat[i] !== SEP && pat[i] !== "/") i--;
|
|
11644
11973
|
const cut = i >= 0 ? pat.lastIndexOf(SEP, i) : pat.lastIndexOf("/", i);
|
|
11645
11974
|
return cut < 0 ? "." : pat.slice(0, cut);
|
|
11646
11975
|
}
|
|
@@ -11865,7 +12194,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
11865
12194
|
this.emit("session.error", error);
|
|
11866
12195
|
throw error;
|
|
11867
12196
|
}
|
|
11868
|
-
for (const result of results
|
|
12197
|
+
for (const result of results?.flat() ?? []) {
|
|
11869
12198
|
await this.parseAndEmit(result);
|
|
11870
12199
|
}
|
|
11871
12200
|
const report = this.assembleReport();
|
|
@@ -11926,7 +12255,7 @@ var CollabSession = class extends EventEmitter {
|
|
|
11926
12255
|
}
|
|
11927
12256
|
budgetForRole(role) {
|
|
11928
12257
|
if (this.options.budgetOverrides?.[role]) {
|
|
11929
|
-
return this.options.budgetOverrides[role];
|
|
12258
|
+
return this.options.budgetOverrides[role] ?? { maxIterations: 0, maxToolCalls: 0, timeoutMs: 0 };
|
|
11930
12259
|
}
|
|
11931
12260
|
const defaults = {
|
|
11932
12261
|
"bug-hunter": { maxIterations: 2e3, maxToolCalls: 5e3, timeoutMs: 10 * 60 * 1e3 },
|
|
@@ -12379,7 +12708,7 @@ function makeSpawnTool(director, roster) {
|
|
|
12379
12708
|
});
|
|
12380
12709
|
const dispatchRole = dispatchResult.role;
|
|
12381
12710
|
if (roster?.[dispatchRole]) {
|
|
12382
|
-
cfg = instantiateRosterConfig(dispatchRole, roster[dispatchRole]);
|
|
12711
|
+
cfg = instantiateRosterConfig(dispatchRole, roster[dispatchRole] ?? {});
|
|
12383
12712
|
} else {
|
|
12384
12713
|
const def = dispatchResult.definition;
|
|
12385
12714
|
cfg = {
|
|
@@ -14676,7 +15005,10 @@ function attachAutoExtend(events, policy = {}) {
|
|
|
14676
15005
|
if (kind === "timeout" || kind === "idle_timeout") {
|
|
14677
15006
|
if (progress > lastTimeoutProgress) {
|
|
14678
15007
|
lastTimeoutProgress = progress;
|
|
14679
|
-
const next2 = Math.min(
|
|
15008
|
+
const next2 = Math.min(
|
|
15009
|
+
Math.ceil(limit * (1 + factor)),
|
|
15010
|
+
ceiling.timeoutMs ?? DEFAULT_CEILING.timeoutMs
|
|
15011
|
+
);
|
|
14680
15012
|
extend({ timeoutMs: next2 });
|
|
14681
15013
|
} else {
|
|
14682
15014
|
deny();
|
|
@@ -14690,7 +15022,7 @@ function attachAutoExtend(events, policy = {}) {
|
|
|
14690
15022
|
}
|
|
14691
15023
|
extendCounts.set(kind, count + 1);
|
|
14692
15024
|
const field = FIELD_BY_KIND[kind];
|
|
14693
|
-
const cap = ceiling[field];
|
|
15025
|
+
const cap = ceiling[field] ?? DEFAULT_CEILING[field];
|
|
14694
15026
|
const next = Math.min(Math.ceil(limit * (1 + factor)), cap);
|
|
14695
15027
|
extend({ [field]: next });
|
|
14696
15028
|
})
|
|
@@ -15989,7 +16321,7 @@ var TaskTracker = class {
|
|
|
15989
16321
|
if (filter.type?.length && !filter.type.includes(n.type)) return false;
|
|
15990
16322
|
if (filter.assignee?.length && n.assignee && !filter.assignee.includes(n.assignee))
|
|
15991
16323
|
return false;
|
|
15992
|
-
if (filter.tags?.length && n.tags && !n.tags.some((t) => filter.tags
|
|
16324
|
+
if (filter.tags?.length && n.tags && !n.tags.some((t) => filter.tags?.includes(t)))
|
|
15993
16325
|
return false;
|
|
15994
16326
|
if (filter.specRequirementId && n.specRequirementId !== filter.specRequirementId)
|
|
15995
16327
|
return false;
|
|
@@ -16503,6 +16835,12 @@ var TaskGraphStore = class {
|
|
|
16503
16835
|
};
|
|
16504
16836
|
|
|
16505
16837
|
// src/sdd/spec-builder.ts
|
|
16838
|
+
function expectDefined11(value) {
|
|
16839
|
+
if (value === null || value === void 0) {
|
|
16840
|
+
throw new Error("Expected value to be defined");
|
|
16841
|
+
}
|
|
16842
|
+
return value;
|
|
16843
|
+
}
|
|
16506
16844
|
function buildQuestioningPrompt(session, min, max) {
|
|
16507
16845
|
const answered = session.answers.length;
|
|
16508
16846
|
const remaining = Math.max(0, min - answered);
|
|
@@ -16548,7 +16886,7 @@ function buildQuestioningPrompt(session, min, max) {
|
|
|
16548
16886
|
if (answered > 0) {
|
|
16549
16887
|
lines.push("", "**Conversation so far:**");
|
|
16550
16888
|
for (let i = 0; i < answered; i++) {
|
|
16551
|
-
const a = session.answers[i];
|
|
16889
|
+
const a = expectDefined11(session.answers[i]);
|
|
16552
16890
|
lines.push(``, `Q${i + 1}: ${a.question}`, `A${i + 1}: ${a.answer}`);
|
|
16553
16891
|
}
|
|
16554
16892
|
}
|
|
@@ -17290,6 +17628,12 @@ function truncate2(str, maxLen) {
|
|
|
17290
17628
|
}
|
|
17291
17629
|
|
|
17292
17630
|
// src/sdd/critical-path.ts
|
|
17631
|
+
function expectDefined12(value) {
|
|
17632
|
+
if (value === null || value === void 0) {
|
|
17633
|
+
throw new Error("Expected value to be defined");
|
|
17634
|
+
}
|
|
17635
|
+
return value;
|
|
17636
|
+
}
|
|
17293
17637
|
function analyzeCriticalPath(graph) {
|
|
17294
17638
|
const nodes = Array.from(graph.nodes.values());
|
|
17295
17639
|
const topoOrder = topologicalSort(graph);
|
|
@@ -17298,9 +17642,9 @@ function analyzeCriticalPath(graph) {
|
|
|
17298
17642
|
for (const edge of graph.edges) {
|
|
17299
17643
|
if (edge.type === "depends_on") {
|
|
17300
17644
|
if (!blockedByMap.has(edge.from)) blockedByMap.set(edge.from, /* @__PURE__ */ new Set());
|
|
17301
|
-
blockedByMap.get(edge.from)
|
|
17645
|
+
blockedByMap.get(edge.from)?.add(edge.to);
|
|
17302
17646
|
if (!blocksMap.has(edge.to)) blocksMap.set(edge.to, /* @__PURE__ */ new Set());
|
|
17303
|
-
blocksMap.get(edge.to)
|
|
17647
|
+
blocksMap.get(edge.to)?.add(edge.from);
|
|
17304
17648
|
}
|
|
17305
17649
|
}
|
|
17306
17650
|
const readyTasks = [];
|
|
@@ -17365,7 +17709,7 @@ function getTransitiveBlocked(_graph, taskId, blocksMap) {
|
|
|
17365
17709
|
const visited = /* @__PURE__ */ new Set();
|
|
17366
17710
|
const queue = [taskId];
|
|
17367
17711
|
while (queue.length > 0) {
|
|
17368
|
-
const current = queue.shift();
|
|
17712
|
+
const current = expectDefined12(queue.shift());
|
|
17369
17713
|
const blocked = blocksMap.get(current);
|
|
17370
17714
|
if (!blocked) continue;
|
|
17371
17715
|
for (const id of blocked) {
|
|
@@ -17390,7 +17734,7 @@ function computeCriticalPath(graph, _topoOrder, blockedByMap) {
|
|
|
17390
17734
|
for (const [taskId, blockers] of blockedByMap) {
|
|
17391
17735
|
for (const blockerId of blockers) {
|
|
17392
17736
|
if (!blocksMap.has(blockerId)) blocksMap.set(blockerId, /* @__PURE__ */ new Set());
|
|
17393
|
-
blocksMap.get(blockerId)
|
|
17737
|
+
blocksMap.get(blockerId)?.add(taskId);
|
|
17394
17738
|
}
|
|
17395
17739
|
}
|
|
17396
17740
|
const n = allIds.length;
|
|
@@ -17411,7 +17755,7 @@ function computeCriticalPath(graph, _topoOrder, blockedByMap) {
|
|
|
17411
17755
|
if (!changed) break;
|
|
17412
17756
|
}
|
|
17413
17757
|
let maxDist = 0;
|
|
17414
|
-
let maxId = allIds[0];
|
|
17758
|
+
let maxId = expectDefined12(allIds[0]);
|
|
17415
17759
|
for (const id of allIds) {
|
|
17416
17760
|
const d = dist.get(id) ?? 0;
|
|
17417
17761
|
if (d > maxDist) {
|
|
@@ -17880,6 +18224,12 @@ var SddTaskDecomposer = class {
|
|
|
17880
18224
|
return nodes.some((n) => n.status === "blocked");
|
|
17881
18225
|
}
|
|
17882
18226
|
};
|
|
18227
|
+
function expectDefined13(value) {
|
|
18228
|
+
if (value === null || value === void 0) {
|
|
18229
|
+
throw new Error("Expected value to be defined");
|
|
18230
|
+
}
|
|
18231
|
+
return value;
|
|
18232
|
+
}
|
|
17883
18233
|
var SddParallelRun = class {
|
|
17884
18234
|
constructor(opts) {
|
|
17885
18235
|
this.opts = opts;
|
|
@@ -17980,8 +18330,10 @@ var SddParallelRun = class {
|
|
|
17980
18330
|
"\u2022 Do not ask before routine in-project tool use; if a permission gate appears, wait for that flow.",
|
|
17981
18331
|
"\u2022 Keep output concise \u2014 summarize changes, do not transcribe files."
|
|
17982
18332
|
].join("\n");
|
|
18333
|
+
if (!this.coordinator) throw new Error("SDD parallel runner requires a coordinator");
|
|
18334
|
+
const coordinator = this.coordinator;
|
|
17983
18335
|
const spawns = subagentIds.map(
|
|
17984
|
-
(subagentId) =>
|
|
18336
|
+
(subagentId) => coordinator.spawn({
|
|
17985
18337
|
id: subagentId,
|
|
17986
18338
|
name: subagentId,
|
|
17987
18339
|
role: "executor",
|
|
@@ -17989,12 +18341,12 @@ var SddParallelRun = class {
|
|
|
17989
18341
|
})
|
|
17990
18342
|
);
|
|
17991
18343
|
const spawnResults = await Promise.all(spawns);
|
|
17992
|
-
if (!spawnResults.every((r) => r.subagentId)) {
|
|
18344
|
+
if (!spawnResults.every((r) => Boolean(r.subagentId))) {
|
|
17993
18345
|
throw new Error("One or more subagent spawns failed");
|
|
17994
18346
|
}
|
|
17995
18347
|
const assignPromises = tasks.map((task, i) => {
|
|
17996
18348
|
const spec = {
|
|
17997
|
-
id: taskIds[i],
|
|
18349
|
+
id: taskIds[i] ?? task.id,
|
|
17998
18350
|
description: [
|
|
17999
18351
|
directivePreamble,
|
|
18000
18352
|
"",
|
|
@@ -18003,15 +18355,15 @@ var SddParallelRun = class {
|
|
|
18003
18355
|
"",
|
|
18004
18356
|
task.description
|
|
18005
18357
|
].join("\n"),
|
|
18006
|
-
subagentId: subagentIds[i],
|
|
18358
|
+
subagentId: subagentIds[i] ?? spawnResults[i]?.subagentId ?? task.id,
|
|
18007
18359
|
timeoutMs: this.timeoutMs
|
|
18008
18360
|
};
|
|
18009
|
-
return this.coordinator
|
|
18361
|
+
return this.coordinator?.assign(spec);
|
|
18010
18362
|
});
|
|
18011
18363
|
await Promise.all(assignPromises);
|
|
18012
18364
|
let results;
|
|
18013
18365
|
try {
|
|
18014
|
-
results = await
|
|
18366
|
+
results = await coordinator.awaitTasks(taskIds);
|
|
18015
18367
|
} catch (err) {
|
|
18016
18368
|
results = taskIds.map((id) => ({
|
|
18017
18369
|
subagentId: "",
|
|
@@ -18026,8 +18378,8 @@ var SddParallelRun = class {
|
|
|
18026
18378
|
const successCount = results.filter((r) => r.status === "success").length;
|
|
18027
18379
|
const failCount = results.length - successCount;
|
|
18028
18380
|
for (let i = 0; i < results.length; i++) {
|
|
18029
|
-
const result = results[i];
|
|
18030
|
-
const taskId = taskIds[i];
|
|
18381
|
+
const result = expectDefined13(results[i]);
|
|
18382
|
+
const taskId = expectDefined13(taskIds[i]);
|
|
18031
18383
|
if (result.status === "success") {
|
|
18032
18384
|
this.opts.tracker.updateNodeStatus(taskId, "completed");
|
|
18033
18385
|
} else {
|