@wrongstack/core 0.54.1 → 0.66.13

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 (63) hide show
  1. package/dist/{agent-bridge-Dnhw4tnM.d.ts → agent-bridge-D-j6OOBT.d.ts} +1 -1
  2. package/dist/agent-subagent-runner-DRZ9-NnR.d.ts +1042 -0
  3. package/dist/{compactor-Duhsf0ge.d.ts → compactor-D_ExJajC.d.ts} +1 -1
  4. package/dist/{config-bht0txXS.d.ts → config--86aHSln.d.ts} +112 -2
  5. package/dist/{context-DtPKqKYV.d.ts → context-y87Jc5ei.d.ts} +8 -8
  6. package/dist/coordination/index.d.ts +12 -12
  7. package/dist/coordination/index.js +87 -69
  8. package/dist/coordination/index.js.map +1 -1
  9. package/dist/defaults/index.d.ts +22 -22
  10. package/dist/defaults/index.js +365 -174
  11. package/dist/defaults/index.js.map +1 -1
  12. package/dist/{events-CbHTS4ZZ.d.ts → events-CIplI98R.d.ts} +20 -1
  13. package/dist/execution/index.d.ts +16 -385
  14. package/dist/execution/index.js +129 -61
  15. package/dist/execution/index.js.map +1 -1
  16. package/dist/extension/index.d.ts +7 -7
  17. package/dist/goal-store-C7jcumEh.d.ts +96 -0
  18. package/dist/index-DKUvyTvV.d.ts +560 -0
  19. package/dist/{index-ge5F2dnc.d.ts → index-b5uhfTSl.d.ts} +10 -8
  20. package/dist/index.d.ts +59 -33
  21. package/dist/index.js +1138 -733
  22. package/dist/index.js.map +1 -1
  23. package/dist/infrastructure/index.d.ts +6 -6
  24. package/dist/infrastructure/index.js +1 -1
  25. package/dist/infrastructure/index.js.map +1 -1
  26. package/dist/kernel/index.d.ts +9 -9
  27. package/dist/kernel/index.js +3 -1
  28. package/dist/kernel/index.js.map +1 -1
  29. package/dist/{mcp-servers-DE6gzBry.d.ts → mcp-servers-DwoNBf6r.d.ts} +3 -3
  30. package/dist/models/index.d.ts +2 -2
  31. package/dist/{multi-agent-coordinator-CjNX4uBD.d.ts → multi-agent-coordinator-CWnH-CiX.d.ts} +10 -2
  32. package/dist/{null-fleet-bus-BNiSlTna.d.ts → null-fleet-bus-VApKRxcp.d.ts} +6 -7
  33. package/dist/observability/index.d.ts +2 -2
  34. package/dist/parallel-eternal-engine-0UwotoSx.d.ts +483 -0
  35. package/dist/{path-resolver-Bax85amb.d.ts → path-resolver-DVkEcIw8.d.ts} +2 -2
  36. package/dist/{permission-Drm7LpPo.d.ts → permission-C1A5whY5.d.ts} +17 -1
  37. package/dist/{permission-policy-CU6sqWxF.d.ts → permission-policy-B2dK-T5N.d.ts} +28 -7
  38. package/dist/{plan-templates-CLRcurWN.d.ts → plan-templates-Bprrzhbu.d.ts} +4 -4
  39. package/dist/{provider-runner-BikCxGCx.d.ts → provider-runner-mXvXGSIw.d.ts} +3 -3
  40. package/dist/{retry-policy-Chtlvr5b.d.ts → retry-policy-CG3qvH_e.d.ts} +1 -1
  41. package/dist/sdd/index.d.ts +9 -9
  42. package/dist/sdd/index.js +59 -52
  43. package/dist/sdd/index.js.map +1 -1
  44. package/dist/security/index.d.ts +3 -3
  45. package/dist/security/index.js +144 -33
  46. package/dist/security/index.js.map +1 -1
  47. package/dist/{selector-BvSPdJj6.d.ts → selector-RvBR_YRW.d.ts} +1 -1
  48. package/dist/session-event-bridge-CDHxcmQU.d.ts +93 -0
  49. package/dist/{session-reader-BGhzMir4.d.ts → session-reader-BIpwM60D.d.ts} +1 -1
  50. package/dist/storage/index.d.ts +7 -6
  51. package/dist/{system-prompt-dtzV_mLm.d.ts → system-prompt-b61lOd49.d.ts} +32 -2
  52. package/dist/types/index.d.ts +23 -14
  53. package/dist/types/index.js +62 -6
  54. package/dist/types/index.js.map +1 -1
  55. package/dist/utils/index.d.ts +2 -2
  56. package/dist/utils/index.js.map +1 -1
  57. package/package.json +1 -1
  58. package/skills/multi-agent/SKILL.md +0 -2
  59. package/dist/agent-subagent-runner-By7jruZ_.d.ts +0 -182
  60. package/dist/goal-store-DwcTDDiX.d.ts +0 -188
  61. package/dist/index-CI271MjL.d.ts +0 -903
  62. package/dist/multi-agent-BmC_xiog.d.ts +0 -554
  63. package/dist/tool-executor-CgU0yWpB.d.ts +0 -110
@@ -1466,8 +1466,9 @@ var ToolExecutor = class {
1466
1466
  */
1467
1467
  async executeBatch(toolUses, ctx, strategy) {
1468
1468
  let budget = this.opts.perIterationOutputCapBytes ?? 1e5;
1469
- const runOne = async (use) => {
1469
+ const runOne = async (use0) => {
1470
1470
  const start = Date.now();
1471
+ let use = use0;
1471
1472
  const tool = this.registry.get(use.name);
1472
1473
  if (!tool) {
1473
1474
  const result = this.unknownToolResult(use, () => this.registry.list().map((t) => t.name));
@@ -1500,10 +1501,36 @@ Please call the tool again with arguments that match its inputSchema. You can us
1500
1501
  budget = this.decrementBudget(result, budget);
1501
1502
  return { result, tool, durationMs: Date.now() - start };
1502
1503
  }
1504
+ if (this.opts.hookRunner?.has("PreToolUse")) {
1505
+ const pre = await this.opts.hookRunner.preToolUse(tool.name, use.input, ctx);
1506
+ if (pre.block) {
1507
+ const result = this.blockedByHookResult(use, pre.reason);
1508
+ budget = this.decrementBudget(result, budget);
1509
+ return { result, tool, durationMs: Date.now() - start };
1510
+ }
1511
+ if (pre.input) {
1512
+ const reval = validateAgainstSchema(pre.input, tool.inputSchema);
1513
+ if (!reval.ok) {
1514
+ const errorDetails = reval.errors.map((e) => ` - ${e.path || "input"}: ${e.message}`).join("\n");
1515
+ const result = {
1516
+ type: "tool_result",
1517
+ tool_use_id: use.id,
1518
+ content: `A PreToolUse hook rewrote the arguments for "${tool.name}" into an invalid shape.
1519
+
1520
+ Validation errors:
1521
+ ${errorDetails}`,
1522
+ is_error: true
1523
+ };
1524
+ budget = this.decrementBudget(result, budget);
1525
+ return { result, tool, durationMs: Date.now() - start };
1526
+ }
1527
+ use = { ...use, input: pre.input };
1528
+ }
1529
+ }
1503
1530
  const decision = await this.opts.permissionPolicy.evaluate(tool, use.input, ctx);
1504
1531
  let effectivePermission = decision.permission;
1505
1532
  const policy = this.opts.permissionPolicy;
1506
- const yolo = policy.getYolo?.() === true || policy.getForceAllYolo?.() === true;
1533
+ const yolo = policy.getYolo?.() === true || policy.getYoloDestructive?.() === true || policy.getForceAllYolo?.() === true;
1507
1534
  if (toolDangerousCaps.length > 0 && effectivePermission === "auto" && !yolo) {
1508
1535
  effectivePermission = "confirm";
1509
1536
  }
@@ -1546,7 +1573,20 @@ Please call the tool again with arguments that match its inputSchema. You can us
1546
1573
  "tool.has_dangerous_capabilities": toolCapsForAudit.length > 0
1547
1574
  });
1548
1575
  try {
1549
- const result = await this.executeTool(tool, use, ctx, budget);
1576
+ let result = await this.executeTool(tool, use, ctx, budget);
1577
+ if (this.opts.hookRunner?.has("PostToolUse")) {
1578
+ const post = await this.opts.hookRunner.postToolUse(
1579
+ tool.name,
1580
+ use.input,
1581
+ { content: String(result.content), isError: !!result.is_error },
1582
+ ctx
1583
+ );
1584
+ if (post.additionalContext) {
1585
+ result = { ...result, content: `${result.content}
1586
+
1587
+ ${post.additionalContext}` };
1588
+ }
1589
+ }
1550
1590
  budget = this.decrementBudget(result, budget);
1551
1591
  span?.setAttribute("tool.is_error", !!result.is_error);
1552
1592
  span?.setAttribute(
@@ -1735,6 +1775,14 @@ ${excerpt}`;
1735
1775
  is_error: true
1736
1776
  };
1737
1777
  }
1778
+ blockedByHookResult(use, reason) {
1779
+ return {
1780
+ type: "tool_result",
1781
+ tool_use_id: use.id,
1782
+ content: `Tool "${use.name}" was blocked by a PreToolUse hook: ${reason ?? "no reason given"}`,
1783
+ is_error: true
1784
+ };
1785
+ }
1738
1786
  decrementBudget(result, budget) {
1739
1787
  const contentBytes = typeof result.content === "string" ? Buffer.byteLength(result.content, "utf8") : Buffer.byteLength(JSON.stringify(result.content), "utf8");
1740
1788
  return Math.max(0, budget - contentBytes);
@@ -2544,7 +2592,8 @@ ${recentJournal}` : "No prior iterations.",
2544
2592
  " \u2022 When this iteration's Task is finished (real artifact / passing",
2545
2593
  " test / applied diff / clean output), emit `[done]` on its own line.",
2546
2594
  " \u2022 Do not stop on the first obstacle \u2014 try at least 3 distinct",
2547
- " approaches before giving up. YOLO is active; no confirmations.",
2595
+ " approaches before giving up. YOLO is active for normal project work;",
2596
+ " destructive-gated confirmations still belong to the permission flow.",
2548
2597
  "",
2549
2598
  "2. UPDATE TODO STATE (when Source is `todo`)",
2550
2599
  " \u2022 Mark this todo `in_progress` via the todos tool before tool work.",
@@ -2965,15 +3014,22 @@ var SubagentBudget = class _SubagentBudget {
2965
3014
  void this.checkLimits();
2966
3015
  }
2967
3016
  /**
2968
- * Wall-clock budget check. Unlike other limits, timeout is always a hard stop
2969
- * wall-clock time cannot be "extended" by the coordinator, so it throws
2970
- * synchronously rather than entering the negotiation flow.
3017
+ * Wall-clock / idle budget check. Delegates to `checkLimits(elapsed)`, so
3018
+ * `timeout` and `idle_timeout` follow the SAME negotiation path as the other
3019
+ * kinds they are NOT a special-cased hard stop. This is deliberate: a
3020
+ * heartbeat-aware policy (see `attachAutoExtend` and `CollabSession`) grants
3021
+ * a timeout extension only while the agent is making progress and denies it
3022
+ * once the agent is genuinely stuck, which is safer than an unconditional
3023
+ * hard kill of a long-but-working agent. The runner translates the resulting
3024
+ * `BudgetThresholdSignal` decision (`extend` → patch limits in place,
3025
+ * `stop` → abort) just like every other kind.
2971
3026
  *
2972
- * Decision table:
2973
- * - no `onThreshold` handler → throw `BudgetExceededError`
2974
- * - `mode === 'sync'` → throw `BudgetExceededError`
2975
- * - `mode === 'auto'` + no listener → throw `BudgetExceededError`
2976
- * - `mode === 'auto'` + listener → throw `BudgetExceededError` (timeout is not extendable)
3027
+ * Decision table (same as `checkLimits`):
3028
+ * - no `onThreshold` handler → throw `BudgetExceededError` (hard stop)
3029
+ * - `mode === 'sync'` → throw `BudgetExceededError` (hard stop)
3030
+ * - `mode === 'auto'` + no listener → throw `BudgetExceededError` (no one to ask)
3031
+ * - `mode === 'auto'` + listener → throw `BudgetThresholdSignal` (negotiated;
3032
+ * a heartbeat-aware policy may extend the timeout)
2977
3033
  */
2978
3034
  checkTimeout() {
2979
3035
  if (this.startTime === null) return;
@@ -5661,7 +5717,10 @@ var NICKNAME_POOL = {
5661
5717
  "lavoisier": { name: "Lavoisier", domain: "chemistry" },
5662
5718
  "mendeleev": { name: "Mendeleev", domain: "chemistry" }
5663
5719
  };
5664
- var ALL_NICKNAMES = Object.values(NICKNAME_POOL);
5720
+ var ALL_NICKNAMES = Object.entries(NICKNAME_POOL);
5721
+ Object.fromEntries(
5722
+ ALL_NICKNAMES.map(([key, entry]) => [entry.name, key])
5723
+ );
5665
5724
  var DOMAIN_PREFERENCES = {
5666
5725
  "security": ["shannon", "turing", "lamarr", "stallman"],
5667
5726
  "bug-hunter": ["darwin", "curie", "feynman", "fermi"],
@@ -5694,17 +5753,16 @@ function assignNickname(role, used) {
5694
5753
  for (const key of preferences) {
5695
5754
  const entry = NICKNAME_POOL[key];
5696
5755
  if (entry && !used.has(key)) {
5697
- return `${entry.name} (${formatRole(role)})`;
5756
+ return { key, display: `${entry.name} (${formatRole(role)})` };
5698
5757
  }
5699
5758
  }
5700
- for (const entry of ALL_NICKNAMES) {
5701
- const key = Object.entries(NICKNAME_POOL).find(([, v]) => v.name === entry.name)?.[0];
5702
- if (key && !used.has(key)) {
5703
- return `${entry.name} (${formatRole(role)})`;
5759
+ for (const [key, entry] of ALL_NICKNAMES) {
5760
+ if (!used.has(key)) {
5761
+ return { key, display: `${entry.name} (${formatRole(role)})` };
5704
5762
  }
5705
5763
  }
5706
5764
  const counter = used.size + 1;
5707
- return `Scientist #${counter} (${formatRole(role)})`;
5765
+ return { key: `scientist-${counter}`, display: `Scientist #${counter} (${formatRole(role)})` };
5708
5766
  }
5709
5767
  function formatRole(role) {
5710
5768
  return role.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
@@ -5791,11 +5849,10 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
5791
5849
  const name = subagent.name?.trim() ?? "";
5792
5850
  const isPlaceholder = name === "" || name.toLowerCase() === role.toLowerCase() || name === "subagent" || name === "adhoc" || name === "generic" || /^slot-/.test(name);
5793
5851
  if (!isPlaceholder) return subagent;
5794
- const nickname = assignNickname(role, this.usedNicknames);
5795
- const baseKey = nickname.split(" ")[0].toLowerCase().replace(/[^a-z0-9-]/g, "-");
5796
- this.usedNicknames.add(baseKey);
5797
- this.subagentNicknames.set(subagentId, baseKey);
5798
- return { ...subagent, name: nickname };
5852
+ const { key, display } = assignNickname(role, this.usedNicknames);
5853
+ this.usedNicknames.add(key);
5854
+ this.subagentNicknames.set(subagentId, key);
5855
+ return { ...subagent, name: display };
5799
5856
  }
5800
5857
  async spawn(subagent) {
5801
5858
  const id = subagent.id || randomUUID();
@@ -6047,23 +6104,32 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
6047
6104
  */
6048
6105
  drainPendingAsAborted(message) {
6049
6106
  const dropped = this.pendingTasks.splice(0, this.pendingTasks.length);
6050
- for (const t of dropped) {
6051
- const synthetic = {
6052
- subagentId: t.subagentId ?? "unassigned",
6053
- taskId: t.id,
6054
- status: "stopped",
6055
- error: {
6056
- kind: "aborted_by_parent",
6057
- message,
6058
- retryable: false
6059
- },
6060
- iterations: 0,
6061
- toolCalls: 0,
6062
- durationMs: 0
6063
- };
6064
- this.completedResults.push(synthetic);
6065
- this.emit("task.completed", { task: t, result: synthetic });
6066
- }
6107
+ for (const t of dropped) this.emitPendingAborted(t, message);
6108
+ }
6109
+ /**
6110
+ * Emit a synthetic `stopped`/`aborted_by_parent` completion for a single
6111
+ * PENDING task — one that was never counted in `inFlight`. This MUST bypass
6112
+ * `recordCompletion`: that path does `inFlight--`, which for a pending task
6113
+ * steals a decrement from a genuinely in-flight task and trips the underflow
6114
+ * guard — suppressing that real task's `task.completed` and hanging its
6115
+ * `awaitTasks()` caller. Pushes the result and fires the event directly.
6116
+ */
6117
+ emitPendingAborted(task, message) {
6118
+ const synthetic = {
6119
+ subagentId: task.subagentId ?? "unassigned",
6120
+ taskId: task.id,
6121
+ status: "stopped",
6122
+ error: {
6123
+ kind: "aborted_by_parent",
6124
+ message,
6125
+ retryable: false
6126
+ },
6127
+ iterations: 0,
6128
+ toolCalls: 0,
6129
+ durationMs: 0
6130
+ };
6131
+ this.completedResults.push(synthetic);
6132
+ this.emit("task.completed", { task, result: synthetic });
6067
6133
  }
6068
6134
  async runDispatched(subagentId, task) {
6069
6135
  const subagent = this.subagents.get(subagentId);
@@ -6324,20 +6390,10 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
6324
6390
  const orphaned = this.pendingTasks.filter((t) => t.subagentId === subagentId);
6325
6391
  this.pendingTasks = this.pendingTasks.filter((t) => t.subagentId !== subagentId);
6326
6392
  for (const t of orphaned) {
6327
- const synthetic = {
6328
- subagentId,
6329
- taskId: t.id,
6330
- status: "stopped",
6331
- error: {
6332
- kind: "aborted_by_parent",
6333
- message: `Subagent "${subagentId}" was removed while task "${t.id}" was pending`,
6334
- retryable: false
6335
- },
6336
- iterations: 0,
6337
- toolCalls: 0,
6338
- durationMs: 0
6339
- };
6340
- this.recordCompletion(synthetic);
6393
+ this.emitPendingAborted(
6394
+ t,
6395
+ `Subagent "${subagentId}" was removed while task "${t.id}" was pending`
6396
+ );
6341
6397
  }
6342
6398
  this.fleetBus?.emit({
6343
6399
  subagentId,
@@ -6634,7 +6690,8 @@ ${recentJournal}` : "No prior iterations.",
6634
6690
  "\u2500\u2500 EXECUTION PROTOCOL \u2500\u2500",
6635
6691
  "\u2022 Execute the assigned task end-to-end using multiple tool calls.",
6636
6692
  "\u2022 Emit `[done]` on its own line when the task is complete.",
6637
- "\u2022 Do not ask for confirmation \u2014 YOLO is active.",
6693
+ "\u2022 Do not ask before routine in-project tool use \u2014 YOLO is active for normal project work.",
6694
+ "\u2022 If a destructive-gated confirmation appears, wait for the permission flow.",
6638
6695
  "\u2022 If the overall Mission is accomplished, emit `[GOAL_COMPLETE]` followed by a verification recipe.",
6639
6696
  "\u2022 Keep output concise \u2014 summarize findings, do not transcribe files."
6640
6697
  ].join("\n");
@@ -6714,6 +6771,7 @@ ${personaLine}Task: ${task}
6714
6771
  } catch {
6715
6772
  results = coordinator.results().slice(-taskIds.length);
6716
6773
  }
6774
+ await Promise.allSettled(subagentIds.map((id) => coordinator.remove(id)));
6717
6775
  const allSuccessful = results.length > 0 && results.every((r) => r.status === "success");
6718
6776
  const goalComplete = results.some(
6719
6777
  (r) => r.status === "success" && typeof r.result === "string" && GOAL_COMPLETE_MARKER2.test(r.result)
@@ -6891,8 +6949,10 @@ ${journalTail.join("\n")}` : "Recent journal: (none \u2014 this is the first ite
6891
6949
  " decide.",
6892
6950
  "",
6893
6951
  "### Operating principles",
6894
- "- YOLO is active. Do NOT ask for confirmation, do NOT propose",
6895
- " options. Pick the best path and execute it.",
6952
+ "- YOLO is active for normal project work. Proceed with routine",
6953
+ " in-project tool use without pre-confirming; pick the best path and execute it.",
6954
+ " If the permission system raises a destructive-gated confirmation, wait",
6955
+ " for that flow instead of trying to bypass it.",
6896
6956
  "- Use tools freely; multiple calls per turn are normal and expected.",
6897
6957
  "- When working on a todo, mark it `in_progress` via the todos tool",
6898
6958
  " before tool work and `completed` (or `cancelled` with a reason)",
@@ -7016,7 +7076,7 @@ var DefaultRetryPolicy = class {
7016
7076
  };
7017
7077
 
7018
7078
  // src/execution/error-handler.ts
7019
- var CONTEXT_OVERFLOW_RE = /context|too long|tokens/i;
7079
+ var CONTEXT_OVERFLOW_RE = /context|too long|tokens|exceeds the context window|context window/i;
7020
7080
  function buildRecoveryStrategies(opts) {
7021
7081
  return [
7022
7082
  {
@@ -7024,7 +7084,7 @@ function buildRecoveryStrategies(opts) {
7024
7084
  compactor: opts?.compactor,
7025
7085
  async attempt(err, ctx) {
7026
7086
  if (!(err instanceof ProviderError)) return null;
7027
- if (err.status !== 413 && !CONTEXT_OVERFLOW_RE.test(err.message)) return null;
7087
+ if (err.status !== 413 && !isContextOverflowError(err)) return null;
7028
7088
  if (this.compactor) {
7029
7089
  try {
7030
7090
  const report = await this.compactor.compact(ctx, { aggressive: true });
@@ -7058,6 +7118,14 @@ function buildRecoveryStrategies(opts) {
7058
7118
  ];
7059
7119
  }
7060
7120
  var DEFAULT_RECOVERY_STRATEGIES = buildRecoveryStrategies();
7121
+ function isContextOverflowError(err) {
7122
+ return CONTEXT_OVERFLOW_RE.test([
7123
+ err.message,
7124
+ err.body?.message,
7125
+ err.body?.type,
7126
+ err.body?.raw
7127
+ ].filter(Boolean).join("\n"));
7128
+ }
7061
7129
  var DefaultErrorHandler = class {
7062
7130
  strategies;
7063
7131
  constructor(strategies = DEFAULT_RECOVERY_STRATEGIES) {
@@ -7074,7 +7142,7 @@ var DefaultErrorHandler = class {
7074
7142
  if (err.status === 429) return { kind: "rate_limit", retryable: true };
7075
7143
  if (err.status === 529) return { kind: "overloaded", retryable: true };
7076
7144
  if (err.status >= 500) return { kind: "server", retryable: true };
7077
- if (err.status === 413 || CONTEXT_OVERFLOW_RE.test(err.message)) {
7145
+ if (err.status === 413 || isContextOverflowError(err)) {
7078
7146
  return { kind: "context_overflow", retryable: false };
7079
7147
  }
7080
7148
  if (err.status >= 400) return { kind: "client", retryable: false };