@wrongstack/core 0.141.0 → 0.155.0

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.
Files changed (51) hide show
  1. package/dist/{agent-bridge-r9y6gdn4.d.ts → agent-bridge-BbZU5TPN.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-1GeQE_L0.d.ts → agent-subagent-runner-Bsueu0J2.d.ts} +2 -2
  3. package/dist/{brain-Cp_3GIS2.d.ts → brain-CS_B0vIE.d.ts} +2 -0
  4. package/dist/coordination/index.d.ts +7 -7
  5. package/dist/coordination/index.js +147 -10
  6. package/dist/coordination/index.js.map +1 -1
  7. package/dist/defaults/index.d.ts +13 -13
  8. package/dist/defaults/index.js +360 -78
  9. package/dist/defaults/index.js.map +1 -1
  10. package/dist/execution/index.d.ts +6 -6
  11. package/dist/execution/index.js +277 -16
  12. package/dist/execution/index.js.map +1 -1
  13. package/dist/extension/index.d.ts +2 -2
  14. package/dist/{goal-preamble-iuIUTQwk.d.ts → goal-preamble-CbV8pXLD.d.ts} +11 -3
  15. package/dist/{index-CPweVoFM.d.ts → index-B5wz-GXm.d.ts} +1 -1
  16. package/dist/{index-BZdezm3g.d.ts → index-CI1hRfPt.d.ts} +2 -2
  17. package/dist/index.d.ts +23 -23
  18. package/dist/index.js +396 -86
  19. package/dist/index.js.map +1 -1
  20. package/dist/infrastructure/index.d.ts +3 -3
  21. package/dist/infrastructure/index.js +11 -2
  22. package/dist/infrastructure/index.js.map +1 -1
  23. package/dist/kernel/index.d.ts +3 -3
  24. package/dist/kernel/index.js.map +1 -1
  25. package/dist/{mcp-servers-Bl5LTvQg.d.ts → mcp-servers-CPERR2De.d.ts} +8 -1
  26. package/dist/{multi-agent-coordinator-QWEzJDlm.d.ts → multi-agent-coordinator-BSKSFNhv.d.ts} +1 -1
  27. package/dist/{null-fleet-bus-BUyfqh23.d.ts → null-fleet-bus-CGOez8Le.d.ts} +4 -4
  28. package/dist/observability/index.d.ts +1 -1
  29. package/dist/{parallel-eternal-engine-Dj2SYzha.d.ts → parallel-eternal-engine-CYoTKjsz.d.ts} +13 -4
  30. package/dist/{path-resolver-DRjQBkoO.d.ts → path-resolver-DuhlmPil.d.ts} +1 -1
  31. package/dist/{plan-templates-CkKNPU3I.d.ts → plan-templates-DbH7lg-t.d.ts} +2 -2
  32. package/dist/{provider-runner-BNpuIyOL.d.ts → provider-runner-Cocq0O9E.d.ts} +1 -1
  33. package/dist/sdd/index.d.ts +3 -3
  34. package/dist/sdd/index.js +143 -6
  35. package/dist/sdd/index.js.map +1 -1
  36. package/dist/{secret-vault-DoISxaKO.d.ts → secret-vault-BJDY28ev.d.ts} +7 -1
  37. package/dist/{secret-vault-BTcC_T5v.d.ts → secret-vault-w8MbUe2Q.d.ts} +1 -1
  38. package/dist/security/index.d.ts +2 -2
  39. package/dist/security/index.js +60 -23
  40. package/dist/security/index.js.map +1 -1
  41. package/dist/storage/index.d.ts +5 -5
  42. package/dist/storage/index.js +78 -44
  43. package/dist/storage/index.js.map +1 -1
  44. package/dist/types/index.d.ts +11 -11
  45. package/dist/types/index.js +186 -26
  46. package/dist/types/index.js.map +1 -1
  47. package/dist/utils/index.d.ts +65 -1
  48. package/dist/utils/index.js +64 -5
  49. package/dist/utils/index.js.map +1 -1
  50. package/package.json +1 -1
  51. package/skills/tech-stack/SKILL.md +253 -97
@@ -757,7 +757,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
757
757
  let toolErrorCount = 0;
758
758
  let fileChangeCount = 0;
759
759
  const toolBreakdown = {};
760
- let outcome = void 0;
760
+ let outcome;
761
761
  const lastEvent = data.events[data.events.length - 1];
762
762
  for (const e of data.events) {
763
763
  if (e.type === "in_flight_start") iterationCount++;
@@ -1502,7 +1502,7 @@ var FileMemoryBackend = class {
1502
1502
  const line = `
1503
1503
  - [${entry.ts}] ${id}${meta} ${entry.text.replace(/\n/g, " ")}
1504
1504
  `;
1505
- const next = existing.trim() ? existing.replace(/\n+$/, "") + line : `# WrongStack Memory
1505
+ const next = existing.trim() ? existing.replace(/\n+$/, "") + line : `# Agent Memory
1506
1506
  ${line}`;
1507
1507
  await atomicWrite(file, next);
1508
1508
  }
@@ -1988,6 +1988,67 @@ var ENCRYPTED_PREFIX = "enc:v1:";
1988
1988
 
1989
1989
  // src/security/secret-vault.ts
1990
1990
  init_atomic_write();
1991
+
1992
+ // src/utils/deep-merge.ts
1993
+ var FORBIDDEN_PROTO_KEYS = /* @__PURE__ */ new Set([
1994
+ "__proto__",
1995
+ "constructor",
1996
+ "prototype",
1997
+ "__defineGetter__",
1998
+ "__defineSetter__",
1999
+ "__lookupGetter__",
2000
+ "__lookupSetter__"
2001
+ ]);
2002
+ function isPrimitiveArray(a) {
2003
+ return a.every((v) => v === null || typeof v !== "object" && typeof v !== "function");
2004
+ }
2005
+ function deepMerge(base, patch, options = {}) {
2006
+ const {
2007
+ conflictResolution = "prefer-patch",
2008
+ arrayMode = "replace",
2009
+ protectProto = true,
2010
+ onNonPrimitiveArrayReplace
2011
+ } = options;
2012
+ if (typeof base !== "object" || base === null) {
2013
+ return conflictResolution === "prefer-patch" ? patch : base;
2014
+ }
2015
+ if (typeof patch !== "object" || patch === null) {
2016
+ return conflictResolution === "prefer-patch" ? patch : base;
2017
+ }
2018
+ if (Array.isArray(base) && Array.isArray(patch)) {
2019
+ if (arrayMode === "concat-primitives" && isPrimitiveArray(base) && isPrimitiveArray(patch)) {
2020
+ return [.../* @__PURE__ */ new Set([...base, ...patch])];
2021
+ }
2022
+ return conflictResolution === "prefer-patch" ? patch : base;
2023
+ }
2024
+ if (Array.isArray(base) || Array.isArray(patch)) {
2025
+ return conflictResolution === "prefer-patch" ? patch : base;
2026
+ }
2027
+ const baseObj = base;
2028
+ const patchObj = patch;
2029
+ const out = { ...baseObj };
2030
+ for (const [k, v] of Object.entries(patchObj)) {
2031
+ if (protectProto && FORBIDDEN_PROTO_KEYS.has(k)) continue;
2032
+ const existing = out[k];
2033
+ if (v !== null && typeof v === "object" && !Array.isArray(v) && existing !== null && typeof existing === "object" && !Array.isArray(existing)) {
2034
+ out[k] = deepMerge(existing, v, options);
2035
+ } else if (Array.isArray(v) && Array.isArray(existing)) {
2036
+ if (onNonPrimitiveArrayReplace && !isPrimitiveArray(v)) {
2037
+ onNonPrimitiveArrayReplace(k, existing.length, v.length);
2038
+ }
2039
+ out[k] = deepMerge(existing, v, options);
2040
+ } else if (v !== void 0) {
2041
+ if (onNonPrimitiveArrayReplace && Array.isArray(v) && !isPrimitiveArray(v)) {
2042
+ const existingLen = Array.isArray(existing) ? existing.length : 0;
2043
+ onNonPrimitiveArrayReplace(k, existingLen, v.length);
2044
+ }
2045
+ out[k] = v;
2046
+ }
2047
+ }
2048
+ return out;
2049
+ }
2050
+
2051
+ // src/security/secret-vault.ts
1991
2052
  var KEY_BYTES = 32;
1992
2053
  var IV_BYTES = 12;
1993
2054
  var TAG_BYTES = 16;
@@ -2189,28 +2250,6 @@ function walkCount(node, vault, counter) {
2189
2250
  }
2190
2251
  return out;
2191
2252
  }
2192
- var FORBIDDEN_PROTO_KEYS = /* @__PURE__ */ new Set([
2193
- "__proto__",
2194
- "constructor",
2195
- "prototype",
2196
- "__defineGetter__",
2197
- "__defineSetter__",
2198
- "__lookupGetter__",
2199
- "__lookupSetter__"
2200
- ]);
2201
- function deepMerge(a, b) {
2202
- const out = { ...a };
2203
- for (const [k, v] of Object.entries(b)) {
2204
- if (FORBIDDEN_PROTO_KEYS.has(k)) continue;
2205
- const existing = out[k];
2206
- if (v !== null && typeof v === "object" && !Array.isArray(v) && existing !== null && typeof existing === "object" && !Array.isArray(existing)) {
2207
- out[k] = deepMerge(existing, v);
2208
- } else {
2209
- out[k] = v;
2210
- }
2211
- }
2212
- return out;
2213
- }
2214
2253
 
2215
2254
  // src/storage/config-loader.ts
2216
2255
  init_atomic_write();
@@ -2393,43 +2432,16 @@ var defaultIndexing = {
2393
2432
  watchExternal: true,
2394
2433
  debounceMs: 400
2395
2434
  };
2396
- function isPrimitiveArray(a) {
2397
- return a.every((v) => v === null || typeof v !== "object");
2398
- }
2399
- var FORBIDDEN_PROTO_KEYS2 = /* @__PURE__ */ new Set([
2400
- "__proto__",
2401
- "constructor",
2402
- "prototype",
2403
- "__defineGetter__",
2404
- "__defineSetter__",
2405
- "__lookupGetter__",
2406
- "__lookupSetter__"
2407
- ]);
2408
2435
  function deepMerge2(base, patch) {
2409
- if (typeof base !== "object" || base === null) return patch ?? base;
2410
- if (typeof patch !== "object" || patch === null) return base;
2411
- const out = { ...base };
2412
- for (const [k, v] of Object.entries(patch)) {
2413
- if (FORBIDDEN_PROTO_KEYS2.has(k)) continue;
2414
- const existing = out[k];
2415
- if (Array.isArray(v)) {
2416
- if (Array.isArray(existing) && isPrimitiveArray(v) && isPrimitiveArray(existing)) {
2417
- out[k] = [.../* @__PURE__ */ new Set([...existing, ...v])];
2418
- } else {
2419
- out[k] = v;
2420
- if (envBoolOptional(process.env.WRONGSTACK_DEBUG_CONFIG)) {
2421
- console.warn(
2422
- `[config] Non-primitive array for "${k}" replaced (global + local config merge). Global entries: ${existing?.length ?? 0}, local entries: ${v.length}.`
2423
- );
2424
- }
2425
- }
2426
- } else if (typeof v === "object" && v !== null && typeof existing === "object" && existing !== null) {
2427
- out[k] = deepMerge2(existing, v);
2428
- } else if (v !== void 0) {
2429
- out[k] = v;
2430
- }
2436
+ const opts = { arrayMode: "concat-primitives" };
2437
+ if (envBoolOptional(process.env.WRONGSTACK_DEBUG_CONFIG)) {
2438
+ opts.onNonPrimitiveArrayReplace = (key, existingLen, patchLen) => {
2439
+ console.warn(
2440
+ `[config] Non-primitive array for "${key}" replaced (global + local config merge). Global entries: ${existingLen}, local entries: ${patchLen}.`
2441
+ );
2442
+ };
2431
2443
  }
2432
- return out;
2444
+ return deepMerge(base, patch, opts);
2433
2445
  }
2434
2446
  var DefaultConfigLoader = class {
2435
2447
  paths;
@@ -4318,7 +4330,7 @@ var DefaultPermissionPolicy = class {
4318
4330
  subjectFor(toolName, input, subjectKey) {
4319
4331
  if (!input || typeof input !== "object") return void 0;
4320
4332
  const obj = input;
4321
- const globChars = /[*?\[\]]/g;
4333
+ const globChars = /[*?[\]]/g;
4322
4334
  const escapeGlob = (s) => s.replace(globChars, (c) => `\\${c}`);
4323
4335
  const normalizePath = (s) => escapeGlob(s.replace(/\\/g, "/"));
4324
4336
  if (subjectKey) {
@@ -5343,8 +5355,8 @@ function findPreserveStart(messages, preserveK) {
5343
5355
  for (let i = preserveStart; i < messages.length; i++) {
5344
5356
  const m = messages[i];
5345
5357
  if (!m || typeof m.content === "string" || !Array.isArray(m.content)) continue;
5346
- const hasToolUse2 = m.content.some((b) => b.type === "tool_use");
5347
- if (hasToolUse2 && i + 1 < messages.length) {
5358
+ const hasToolUse3 = m.content.some((b) => b.type === "tool_use");
5359
+ if (hasToolUse3 && i + 1 < messages.length) {
5348
5360
  const next = messages[i + 1];
5349
5361
  if (next && next.role === "user" && typeof next.content !== "string" && Array.isArray(next.content) && next.content.some((b) => b.type === "tool_result")) {
5350
5362
  preserveStart = i + 1;
@@ -5408,6 +5420,127 @@ function buildLosslessDigest(messages) {
5408
5420
  }
5409
5421
  return lines.join("\n");
5410
5422
  }
5423
+ function extractText(m) {
5424
+ if (typeof m.content === "string") return m.content;
5425
+ return m.content.filter(isTextBlock).map((b) => b.text).join(" ");
5426
+ }
5427
+ function hasToolUse2(m) {
5428
+ if (typeof m.content === "string") return false;
5429
+ return m.content.some((b) => b.type === "tool_use");
5430
+ }
5431
+ function hasLargeToolResult(m, threshold = 3e3) {
5432
+ if (typeof m.content === "string") return false;
5433
+ return m.content.some(
5434
+ (b) => b.type === "tool_result" && b.content && (typeof b.content === "string" ? b.content.length : JSON.stringify(b.content).length) > threshold
5435
+ );
5436
+ }
5437
+ function scoreMessage(m, context) {
5438
+ const text = extractText(m).toLowerCase();
5439
+ if (text.trim().length === 0 && (hasToolUse2(m) || typeof m.content !== "string")) {
5440
+ const hasResult = typeof m.content !== "string" && m.content.some((b) => b.type === "tool_result");
5441
+ if (hasToolUse2(m) || hasResult) return 0;
5442
+ }
5443
+ if (context?.failureCounts && m.role === "user" && hasToolUse2(m) === false) {
5444
+ const isFailure = /error|fail|exception|timeout|enonet|eacces|eperm|enoent|abort/i.test(text);
5445
+ if (isFailure) {
5446
+ const errKey = /(error|fail|exception|timeout|enonet|eacces|eperm|enoent|abort)/i.exec(text)?.[0]?.toLowerCase() ?? "error";
5447
+ const count = (context.failureCounts.get(errKey) ?? 0) + 1;
5448
+ context.failureCounts.set(errKey, count);
5449
+ if (count >= 5) return 0;
5450
+ if (count >= 3) return 1;
5451
+ }
5452
+ }
5453
+ if (m.role === "user") {
5454
+ if (/\b(wrong|no\b|stop\b|don'?t\b|actually|fix that|undo|revert|forget|ignore|skip)\b/i.test(
5455
+ text
5456
+ )) {
5457
+ return 5;
5458
+ }
5459
+ }
5460
+ if (/\b(error|exception|fatal|critical|crash|panic|abort|segfault|core dump|undefined is not|null pointer|typeerror|referenceerror|syntaxerror)\b/i.test(
5461
+ text
5462
+ )) {
5463
+ return 5;
5464
+ }
5465
+ if (/\b(security|vulnerability|injection|xss|csrf|secret|apikey|api.key|hardcoded|leak|exploit|cve)\b/i.test(
5466
+ text
5467
+ )) {
5468
+ return 5;
5469
+ }
5470
+ if (m.role === "assistant" && /\b(architecture|design|approach|strategy|pattern|refactor|migrate|restructure|decision|trade.?off)\b/i.test(
5471
+ text
5472
+ )) {
5473
+ return 5;
5474
+ }
5475
+ if (hasLargeToolResult(m)) return 1;
5476
+ if (m.role === "user" && !hasToolUse2(m) && /\b(files_with_matches|count|found \d+ match|directory tree|\.\.\. and \d+ more)\b/i.test(text)) {
5477
+ return 1;
5478
+ }
5479
+ return 3;
5480
+ }
5481
+ function buildSmartDigest(messages) {
5482
+ const lines = [];
5483
+ const failureCounts = /* @__PURE__ */ new Map();
5484
+ let noiseCount = 0;
5485
+ for (const m of messages) {
5486
+ const score = scoreMessage(m, { failureCounts });
5487
+ const text = extractText(m);
5488
+ const toolCount = countToolBlocks(m);
5489
+ if (score === 0) {
5490
+ noiseCount++;
5491
+ continue;
5492
+ }
5493
+ const marker = toolCount > 0 ? ` [${toolCount} tool call(s)]` : "";
5494
+ let display;
5495
+ switch (score) {
5496
+ case 5:
5497
+ display = text.trim();
5498
+ break;
5499
+ case 3:
5500
+ display = firstSentence(text);
5501
+ break;
5502
+ case 1:
5503
+ display = oneLineSummary(m, text);
5504
+ break;
5505
+ default:
5506
+ display = firstSentence(text);
5507
+ }
5508
+ if (display.length === 0 && toolCount === 0) continue;
5509
+ lines.push(`[${m.role}]: ${display}${marker}`);
5510
+ }
5511
+ if (noiseCount > 0) {
5512
+ lines.push(`[system]: ${noiseCount} low-importance turn(s) collapsed (repeated failures / pure tool I/O)`);
5513
+ }
5514
+ return lines.join("\n");
5515
+ }
5516
+ function countToolBlocks(m) {
5517
+ if (typeof m.content === "string") return 0;
5518
+ return m.content.filter(
5519
+ (b) => b.type === "tool_use" || b.type === "tool_result"
5520
+ ).length;
5521
+ }
5522
+ function firstSentence(text) {
5523
+ const trimmed = text.trim();
5524
+ if (trimmed.length === 0) return "";
5525
+ const dot = trimmed.indexOf(". ");
5526
+ if (dot === -1) return trimmed.length > 150 ? `${trimmed.slice(0, 147)}\u2026` : trimmed;
5527
+ const sentence = trimmed.slice(0, dot + 1);
5528
+ return sentence.length > 150 ? `${sentence.slice(0, 147)}\u2026` : sentence;
5529
+ }
5530
+ function oneLineSummary(m, text) {
5531
+ const trimmed = text.trim();
5532
+ if (trimmed.length === 0) {
5533
+ if (typeof m.content !== "string") {
5534
+ const results = m.content.filter((b) => b.type === "tool_result");
5535
+ if (results.length > 0) {
5536
+ return `[${results.length} tool result(s) \u2014 see session log]`;
5537
+ }
5538
+ }
5539
+ return "[no text content]";
5540
+ }
5541
+ const firstLine = trimmed.split("\n")[0] ?? "";
5542
+ return firstLine.length > 100 ? `${firstLine.slice(0, 97)}\u2026` : firstLine;
5543
+ }
5411
5544
  function findSafeBoundary(messages, from, to) {
5412
5545
  for (let i = to; i >= from; i--) {
5413
5546
  const m = messages[i];
@@ -5423,8 +5556,8 @@ function findExchangeStart(messages, userIndex) {
5423
5556
  const m = messages[i];
5424
5557
  if (!m) continue;
5425
5558
  if (m.role === "assistant") {
5426
- const hasToolUse2 = Array.isArray(m.content) ? m.content.some((b) => b.type === "tool_use") : false;
5427
- if (!hasToolUse2) return i + 1;
5559
+ const hasToolUse3 = Array.isArray(m.content) ? m.content.some((b) => b.type === "tool_use") : false;
5560
+ if (!hasToolUse3) return i + 1;
5428
5561
  } else if (m.role === "user") {
5429
5562
  return i;
5430
5563
  }
@@ -5436,9 +5569,11 @@ function findExchangeStart(messages, userIndex) {
5436
5569
  var HybridCompactor = class {
5437
5570
  preserveK;
5438
5571
  eliseThreshold;
5572
+ smart;
5439
5573
  constructor(opts = {}) {
5440
5574
  this.preserveK = opts.preserveK ?? 5;
5441
5575
  this.eliseThreshold = opts.eliseThreshold ?? 2e3;
5576
+ this.smart = opts.smart ?? false;
5442
5577
  }
5443
5578
  async compact(ctx, opts = {}) {
5444
5579
  const beforeTokens = estimateMessages(ctx.messages);
@@ -5510,7 +5645,7 @@ var HybridCompactor = class {
5510
5645
  if (boundary <= 0) return { saved: 0 };
5511
5646
  const removed = messages.slice(0, boundary);
5512
5647
  const removedTokens = estimateMessages(removed);
5513
- const digest = buildLosslessDigest(removed) || `${removed.length} earlier turns (no textual content; tool I/O omitted \u2014 see session log)`;
5648
+ const digest = this.smart ? buildSmartDigest(removed) || `${removed.length} earlier turns (no textual content; tool I/O omitted \u2014 see session log)` : buildLosslessDigest(removed) || `${removed.length} earlier turns (no textual content; tool I/O omitted \u2014 see session log)`;
5514
5649
  const summaryMsg = {
5515
5650
  role: "system",
5516
5651
  content: `[prior_turns_digest: ${digest}]`
@@ -6034,7 +6169,8 @@ function createStrategyCompactor(opts = {}) {
6034
6169
  }
6035
6170
  return new HybridCompactor({
6036
6171
  preserveK: opts.preserveK,
6037
- eliseThreshold: opts.eliseThreshold
6172
+ eliseThreshold: opts.eliseThreshold,
6173
+ smart: opts.smart
6038
6174
  });
6039
6175
  }
6040
6176
  var ProviderBackedCompactor = class {
@@ -6766,7 +6902,7 @@ ${excerpt}`;
6766
6902
  subjectFor(toolName, input, subjectKey) {
6767
6903
  if (!input || typeof input !== "object") return void 0;
6768
6904
  const obj = input;
6769
- const globChars = /[*?\[\]]/g;
6905
+ const globChars = /[*?[\]]/g;
6770
6906
  const escapeGlob = (s) => s.replace(globChars, (c) => `\\${c}`);
6771
6907
  const normalizePath = (s) => escapeGlob(s.replace(/\\/g, "/"));
6772
6908
  if (subjectKey) {
@@ -7102,7 +7238,7 @@ function appendJournal(goal, entry) {
7102
7238
  };
7103
7239
  }
7104
7240
  function parseProgressFromText(text) {
7105
- const re = /\[progress:\s*(\d{1,3})%\]\s*(?:[—\-]\s*(.+))?/i;
7241
+ const re = /\[progress:\s*(\d{1,3})%\]\s*(?:[—-]\s*(.+))?/i;
7106
7242
  const m = text.match(re);
7107
7243
  if (!m) return null;
7108
7244
  const progress = Math.min(100, Math.max(0, Number.parseInt(m[1] ?? "0", 10)));
@@ -8153,6 +8289,7 @@ var SubagentBudget = class _SubagentBudget {
8153
8289
  function makeAgentSubagentRunner(opts) {
8154
8290
  const format = opts.formatTaskInput ?? defaultFormatTaskInput;
8155
8291
  return async (task, ctx) => {
8292
+ const taskStartedAt = Date.now();
8156
8293
  const factoryResult = await opts.factory(ctx.config);
8157
8294
  const { agent, events } = factoryResult;
8158
8295
  const detachFleet = opts.fleetBus?.attach(ctx.subagentId, events, task.id);
@@ -8249,7 +8386,7 @@ function makeAgentSubagentRunner(opts) {
8249
8386
  }),
8250
8387
  events.on("provider.text_delta", (e) => {
8251
8388
  ctx.budget.markActivity();
8252
- streamingTextAcc = (streamingTextAcc + e.text).slice(-200);
8389
+ streamingTextAcc = (streamingTextAcc + e.text).slice(-2e3);
8253
8390
  })
8254
8391
  );
8255
8392
  const onParentAbort = () => aborter.abort();
@@ -8257,6 +8394,15 @@ function makeAgentSubagentRunner(opts) {
8257
8394
  let result;
8258
8395
  try {
8259
8396
  result = await agent.run(format(task, ctx.config), { signal: aborter.signal });
8397
+ events.emit("subagent.task_completed", {
8398
+ subagentId: ctx.subagentId,
8399
+ taskId: task.id,
8400
+ status: result.status === "done" ? "success" : "failed",
8401
+ iterations: result.iterations,
8402
+ toolCalls: ctx.budget.usage().toolCalls,
8403
+ durationMs: Date.now() - taskStartedAt,
8404
+ finalText: result.finalText?.trim() || void 0
8405
+ });
8260
8406
  } finally {
8261
8407
  detachFleet?.();
8262
8408
  ctx.signal.removeEventListener("abort", onParentAbort);
@@ -9166,15 +9312,44 @@ Working rules:
9166
9312
  id: "e2e",
9167
9313
  name: "E2E",
9168
9314
  role: "e2e",
9169
- tools: [...TOOLS.build, "fetch"],
9315
+ tools: [
9316
+ ...TOOLS.build,
9317
+ "fetch",
9318
+ "playwright_navigate",
9319
+ "playwright_screenshot",
9320
+ "playwright_click",
9321
+ "playwright_type",
9322
+ "playwright_evaluate",
9323
+ "playwright_select_option",
9324
+ "playwright_hover",
9325
+ "playwright_fill_form",
9326
+ "playwright_wait_for",
9327
+ "playwright_press_key",
9328
+ "playwright_drag"
9329
+ ],
9170
9330
  prompt: `You are the E2E agent. Your job is end-to-end testing: drive the whole
9171
9331
  system the way a user would and verify the full flow works across boundaries.
9172
9332
 
9173
9333
  Scope:
9174
9334
  - Author end-to-end scenarios that exercise real user journeys
9175
9335
  - Drive UI/CLI/API across process and network boundaries
9336
+ - Use Playwright browser tools (navigate, click, type, screenshot, evaluate)
9337
+ to automate web UI flows \u2014 open pages, interact with forms, capture evidence
9176
9338
  - Set up and tear down realistic test state
9177
- - Capture failures with enough detail to reproduce (screenshots, logs)
9339
+ - Capture failures with enough detail to reproduce (screenshots, logs, page HTML)
9340
+
9341
+ Playwright tools available (require the "playwright" MCP server to be enabled):
9342
+ playwright_navigate(url) \u2014 open a page at the given URL
9343
+ playwright_screenshot() \u2014 capture a full-page or viewport screenshot
9344
+ playwright_click(selector) \u2014 click on an element matching a CSS selector
9345
+ playwright_type(selector, text) \u2014 type text into a focused input element
9346
+ playwright_evaluate(script) \u2014 run arbitrary JavaScript in the page context
9347
+ playwright_select_option(selector, value) \u2014 pick a <select> dropdown option
9348
+ playwright_hover(selector) \u2014 hover the mouse over an element
9349
+ playwright_fill_form(fields) \u2014 fill multiple form fields in one call
9350
+ playwright_wait_for(selector) \u2014 block until an element appears on the page
9351
+ playwright_press_key(key) \u2014 press a keyboard key (Enter, Tab, Escape, \u2026)
9352
+ playwright_drag(from, to) \u2014 drag an element from one selector to another
9178
9353
 
9179
9354
  Input format you accept:
9180
9355
  { "task": "scenario | smoke | journey", "flow": "<user journey>", "surface": "ui | cli | api" }
@@ -9188,8 +9363,10 @@ Output: Markdown e2e report:
9188
9363
  Working rules:
9189
9364
  - Test the real flow end to end; don't stub the thing under test
9190
9365
  - Make scenarios deterministic \u2014 control time, randomness, and external state
9191
- - On failure, capture artifacts (logs/screenshots) for reproduction
9192
- - Keep scenarios independent so one failure doesn't cascade`
9366
+ - On failure, capture artifacts (screenshots, page HTML, logs) for reproduction
9367
+ - Keep scenarios independent so one failure doesn't cascade
9368
+ - For browser tests: playwright_navigate first, then interact, then playwright_screenshot as evidence
9369
+ - If playwright tools are unavailable, report it and fall back to API/CLI testing`
9193
9370
  },
9194
9371
  budget: HEAVY_BUDGET,
9195
9372
  capability: {
@@ -9202,10 +9379,106 @@ Working rules:
9202
9379
  "user journey",
9203
9380
  "smoke test",
9204
9381
  "playwright",
9382
+ "browser",
9383
+ "screenshot",
9384
+ "web ui",
9385
+ "headless",
9205
9386
  "cypress",
9206
9387
  "full flow",
9207
9388
  "browser test",
9208
- "acceptance test"
9389
+ "acceptance test",
9390
+ "navigate",
9391
+ "click",
9392
+ "form fill",
9393
+ "dom",
9394
+ "page load"
9395
+ ]
9396
+ }
9397
+ },
9398
+ {
9399
+ config: {
9400
+ id: "browser",
9401
+ name: "Browser",
9402
+ role: "browser",
9403
+ tools: [
9404
+ ...TOOLS.read,
9405
+ "fetch",
9406
+ "playwright_navigate",
9407
+ "playwright_screenshot",
9408
+ "playwright_click",
9409
+ "playwright_type",
9410
+ "playwright_evaluate",
9411
+ "playwright_select_option",
9412
+ "playwright_hover",
9413
+ "playwright_fill_form",
9414
+ "playwright_wait_for",
9415
+ "playwright_press_key",
9416
+ "playwright_drag"
9417
+ ],
9418
+ prompt: `You are the Browser agent. Your job is browser automation: open web pages,
9419
+ interact with them, extract data, capture screenshots, and return structured
9420
+ results. You are a read-focused agent \u2014 you drive the browser, not the filesystem.
9421
+
9422
+ Scope:
9423
+ - Navigate to URLs and wait for pages to load
9424
+ - Take full-page or element screenshots as evidence
9425
+ - Click buttons, fill forms, select options, type text \u2014 full user simulation
9426
+ - Extract page content: text, HTML, element attributes, data tables
9427
+ - Evaluate JavaScript in the page context to extract structured data
9428
+ - Verify visual state (element visibility, text content, attribute values)
9429
+
9430
+ Playwright tools available (require the "playwright" MCP server to be enabled):
9431
+ playwright_navigate(url) \u2014 open a page at the given URL
9432
+ playwright_screenshot() \u2014 capture a full-page or viewport screenshot
9433
+ playwright_click(selector) \u2014 click on an element matching a CSS selector
9434
+ playwright_type(selector, text) \u2014 type text into a focused input element
9435
+ playwright_evaluate(script) \u2014 run arbitrary JavaScript in the page context
9436
+ playwright_select_option(selector, value) \u2014 pick a <select> dropdown option
9437
+ playwright_hover(selector) \u2014 hover the mouse over an element
9438
+ playwright_fill_form(fields) \u2014 fill multiple form fields in one call
9439
+ playwright_wait_for(selector) \u2014 block until an element appears on the page
9440
+ playwright_press_key(key) \u2014 press a keyboard key (Enter, Tab, Escape, \u2026)
9441
+ playwright_drag(from, to) \u2014 drag an element from one selector to another
9442
+
9443
+ Input format you accept:
9444
+ { "task": "navigate | screenshot | extract | interact | verify", "url": "<url>", "steps": ["step1", "step2"] }
9445
+
9446
+ Output: Structured markdown report:
9447
+ - ## Page (URL, title, load status)
9448
+ - ## Actions Taken (step-by-step with timestamps)
9449
+ - ## Results (extracted data, element states, verification results)
9450
+ - ## Screenshots (list attached screenshot references)
9451
+ - ## Errors (any failures with stack traces)
9452
+
9453
+ Working rules:
9454
+ - Always playwright_navigate first before any interaction
9455
+ - Always playwright_wait_for after navigation to ensure the page is ready
9456
+ - playwright_screenshot is your primary evidence \u2014 use it before and after interactions
9457
+ - Use playwright_evaluate for structured data extraction (JSON, text content)
9458
+ - If a selector fails, try alternative selectors before giving up
9459
+ - Report exact CSS selectors used \u2014 they're part of the evidence
9460
+ - If playwright tools are unavailable, report the error immediately \u2014 do not guess`
9461
+ },
9462
+ budget: MEDIUM_BUDGET,
9463
+ capability: {
9464
+ phase: "verify",
9465
+ summary: "Browser automation: opens pages, clicks, types, screenshots, extracts data via Playwright headless Chromium.",
9466
+ keywords: [
9467
+ "browser",
9468
+ "screenshot",
9469
+ "navigate",
9470
+ "web page",
9471
+ "scrape",
9472
+ "crawl",
9473
+ "headless",
9474
+ "chrome",
9475
+ "open url",
9476
+ "capture",
9477
+ "page title",
9478
+ "extract data",
9479
+ "fill form",
9480
+ "click button",
9481
+ "take screenshot"
9209
9482
  ]
9210
9483
  }
9211
9484
  },
@@ -12849,7 +13122,7 @@ async function expandGlob(pattern) {
12849
13122
  } catch {
12850
13123
  return;
12851
13124
  }
12852
- const firstGlob = pat.search(/[*?[\[]/);
13125
+ const firstGlob = pat.search(/[*?[[]/);
12853
13126
  if (firstGlob < 0) {
12854
13127
  const re = globToRegex(pat);
12855
13128
  for (const e of entries) {
@@ -12909,7 +13182,7 @@ var CollabSession = class extends EventEmitter {
12909
13182
  bugs = /* @__PURE__ */ new Map();
12910
13183
  plans = /* @__PURE__ */ new Map();
12911
13184
  evaluations = /* @__PURE__ */ new Map();
12912
- disposers = new Array();
13185
+ disposers = [];
12913
13186
  settled = false;
12914
13187
  timeoutMs;
12915
13188
  cancelled = false;
@@ -14117,7 +14390,7 @@ var FleetUsageAggregator = class {
14117
14390
  metaLookup;
14118
14391
  perSubagent = /* @__PURE__ */ new Map();
14119
14392
  total = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };
14120
- unsub = new Array();
14393
+ unsub = [];
14121
14394
  /**
14122
14395
  * Remove a terminated subagent's data from the aggregator and subtract its
14123
14396
  * contribution from the running totals. Call this when a subagent is removed
@@ -20409,6 +20682,14 @@ var zaiVisionServer = () => ({
20409
20682
  ],
20410
20683
  permission: "auto"
20411
20684
  });
20685
+ var playwrightServer = () => ({
20686
+ name: "playwright",
20687
+ description: "Browser automation \u2014 navigate, screenshot, click, type, evaluate JS (headless Chromium)",
20688
+ transport: "stdio",
20689
+ command: "npx",
20690
+ args: ["-y", "@modelcontextprotocol/server-playwright"],
20691
+ permission: "confirm"
20692
+ });
20412
20693
  var miniMaxVisionServer = () => ({
20413
20694
  name: "minimax-vision",
20414
20695
  description: "MiniMax MCP \u2014 image understanding via understand_image",
@@ -20435,7 +20716,8 @@ var allServers = () => ({
20435
20716
  "google-maps": { ...googleMapsServer(), enabled: false },
20436
20717
  sentinel: { ...sentinelServer(), enabled: false },
20437
20718
  "zai-vision": { ...zaiVisionServer(), enabled: false },
20438
- "minimax-vision": { ...miniMaxVisionServer(), enabled: false }
20719
+ "minimax-vision": { ...miniMaxVisionServer(), enabled: false },
20720
+ playwright: { ...playwrightServer(), enabled: false }
20439
20721
  });
20440
20722
 
20441
20723
  export { AGENTS_BY_PHASE, AGENT_CATALOG, AISpecBuilder, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, ConfigMigrationError, DEFAULT_AUTONOMY_CONFIG, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_CONFIG, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_SUBAGENT_BASELINE, DEFAULT_TOOLS_CONFIG, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPermissionPolicy, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionStore, DefaultSkillLoader, DefaultTaskStore, Director, DirectorStateCheckpoint, DoneConditionChecker, EternalAutonomyEngine, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetSpawnBudgetError, FleetUsageAggregator, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, IntelligentCompactor, LLMSelector, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, ParallelEternalEngine, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, SddParallelRun, SddTaskDecomposer, SelectiveCompactor, SessionAnalyzer, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, ToolExecutor, addPlanItem, allServers, analyzeCriticalPath, applyRosterBudget, attachAutoExtend, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, classifyFamily, clearPlan, composeDirectorPrompt, composeSubagentPrompt, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDelegateTool, createMessage, createSessionEventBridge, createStrategyCompactor, decryptConfigSecrets, deriveTodosFromPlanItem, dispatchAgent, emptyPlan, encryptConfigSecrets, everArtServer, filesystemServer, formatPlan, formatPlanTemplates, getAgentDefinition, getPlanTemplate, getTemplate, githubServer, googleMapsServer, listPlanTemplates, listTemplates, loadDirectorState, loadPlan, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAskTool, makeAssignTool, makeAutonomyPromptContributor, makeAwaitTasksTool, makeCollabDebugTool, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetHealthTool, makeFleetSessionTool, makeFleetStatusTool, makeFleetUsageTool, makeLLMClassifier, makeRollUpTool, makeSpawnTool, makeTerminateTool, migratePlaintextSecrets, miniMaxVisionServer, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, resolveAuditLevel, resolveSessionLoggingConfig, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, savePlan, saveTodosCheckpoint, scoreAgents, sentinelServer, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, templateToMarkdown, wireMetricsToEvents, zaiVisionServer };