@wrongstack/core 0.260.0 → 0.264.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 (80) hide show
  1. package/dist/{agent-bridge-BbskZ7HH.d.ts → agent-bridge-D8sa1vtv.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-BNIGZx18.d.ts → agent-subagent-runner-c9DLkaas.d.ts} +11 -9
  3. package/dist/{brain-C2yDd7Lw.d.ts → brain-O1IdKPaK.d.ts} +2 -2
  4. package/dist/{compactor-t0R_AIt_.d.ts → compactor-BBy0rCtB.d.ts} +1 -1
  5. package/dist/{config-FG6As4H5.d.ts → config-Dz2F3H2K.d.ts} +7 -1
  6. package/dist/{context-JFOVvu6z.d.ts → context-BGSpZNSE.d.ts} +11 -0
  7. package/dist/coordination/index.d.ts +1681 -15
  8. package/dist/coordination/index.js +2648 -388
  9. package/dist/coordination/index.js.map +1 -1
  10. package/dist/defaults/index.d.ts +25 -25
  11. package/dist/defaults/index.js +1414 -1387
  12. package/dist/defaults/index.js.map +1 -1
  13. package/dist/dispatcher-types.d-BBeXBQgS.d.ts +66 -0
  14. package/dist/execution/index.d.ts +15 -15
  15. package/dist/execution/index.js +410 -388
  16. package/dist/execution/index.js.map +1 -1
  17. package/dist/execution/prompt-enhancer.d.ts +2 -2
  18. package/dist/execution/prompt-enhancer.js +7 -1
  19. package/dist/execution/prompt-enhancer.js.map +1 -1
  20. package/dist/extension/index.d.ts +6 -6
  21. package/dist/extension/index.js.map +1 -1
  22. package/dist/{goal-preamble-B1IXJtLX.d.ts → goal-preamble-DzjFuN3p.d.ts} +21 -9
  23. package/dist/{goal-store-CPXz6Mml.d.ts → goal-store-CxWmCGbH.d.ts} +1 -1
  24. package/dist/{index-CebbJB94.d.ts → index-CYIQrXVF.d.ts} +8 -8
  25. package/dist/{index-BPcg4N3M.d.ts → index-CbLSI66_.d.ts} +5 -5
  26. package/dist/index.d.ts +45 -91
  27. package/dist/index.js +14976 -12551
  28. package/dist/index.js.map +1 -1
  29. package/dist/infrastructure/index.d.ts +6 -6
  30. package/dist/kernel/index.d.ts +9 -9
  31. package/dist/kernel/index.js +6 -1
  32. package/dist/kernel/index.js.map +1 -1
  33. package/dist/{llm-selector-DXxI2tlu.d.ts → llm-selector-DzxuZnNz.d.ts} +2 -2
  34. package/dist/{mcp-servers-OwNHo43-.d.ts → mcp-servers-DC4QRPUI.d.ts} +3 -3
  35. package/dist/models/index.d.ts +5 -5
  36. package/dist/models/index.js +6 -1
  37. package/dist/models/index.js.map +1 -1
  38. package/dist/{models-registry-Djlmq4uB.d.ts → models-registry-B_siPxqN.d.ts} +1 -1
  39. package/dist/{multi-agent-coordinator-CEmrSCMJ.d.ts → multi-agent-coordinator-CK5Jdj9K.d.ts} +2 -2
  40. package/dist/{null-fleet-bus-DT92xqgJ.d.ts → null-fleet-bus-DgvD4SCO.d.ts} +6 -6
  41. package/dist/observability/index.d.ts +2 -2
  42. package/dist/observability/index.js +8 -3
  43. package/dist/observability/index.js.map +1 -1
  44. package/dist/{parallel-eternal-engine-0SItuq5r.d.ts → parallel-eternal-engine-bK0JQBR_.d.ts} +9 -9
  45. package/dist/{path-resolver-DKBh6Jlo.d.ts → path-resolver-BPEDlN38.d.ts} +3 -3
  46. package/dist/{permission-BJ7eO9Vl.d.ts → permission-4yvGmMRB.d.ts} +1 -1
  47. package/dist/{permission-policy-DEXOfnpm.d.ts → permission-policy-C6XpsBOy.d.ts} +2 -2
  48. package/dist/{pipeline-zflkI2dp.d.ts → pipeline-CXCeMz8J.d.ts} +58 -3
  49. package/dist/{plan-templates-BFXyRkEK.d.ts → plan-templates-BvzRBkJc.d.ts} +5 -5
  50. package/dist/{provider-runner-BC-uywtT.d.ts → provider-runner-C5aQpDWE.d.ts} +3 -3
  51. package/dist/{retry-policy-Cavrzmtk.d.ts → retry-policy-CFhdtRzz.d.ts} +1 -1
  52. package/dist/sdd/index.d.ts +8 -8
  53. package/dist/sdd/index.js +39 -29
  54. package/dist/sdd/index.js.map +1 -1
  55. package/dist/{secret-vault-CDvDYXWX.d.ts → secret-vault-CxiVLbt1.d.ts} +1 -1
  56. package/dist/security/index.d.ts +4 -4
  57. package/dist/security/index.js +208 -203
  58. package/dist/security/index.js.map +1 -1
  59. package/dist/{selector-B7AivHsu.d.ts → selector-gIuhRTkN.d.ts} +1 -1
  60. package/dist/{session-event-bridge-BmIDxdJd.d.ts → session-event-bridge-DkvvrpDt.d.ts} +8 -2
  61. package/dist/{session-reader-DtofsB-2.d.ts → session-reader-KdfVwkKP.d.ts} +1 -1
  62. package/dist/skills/index.js +67 -64
  63. package/dist/skills/index.js.map +1 -1
  64. package/dist/storage/index.d.ts +31 -12
  65. package/dist/storage/index.js +441 -360
  66. package/dist/storage/index.js.map +1 -1
  67. package/dist/tools/index.d.ts +57 -0
  68. package/dist/tools/index.js +411 -0
  69. package/dist/tools/index.js.map +1 -0
  70. package/dist/types/index.d.ts +19 -19
  71. package/dist/types/index.js +703 -694
  72. package/dist/types/index.js.map +1 -1
  73. package/dist/utils/error.d.ts +7 -0
  74. package/dist/utils/error.js +8 -0
  75. package/dist/utils/error.js.map +1 -0
  76. package/dist/utils/index.d.ts +7 -67
  77. package/dist/utils/index.js +17 -5
  78. package/dist/utils/index.js.map +1 -1
  79. package/package.json +5 -1
  80. package/dist/package-outdated-watcher-C70ag2G9.d.ts +0 -581
@@ -1,9 +1,9 @@
1
- import { execFile } from 'child_process';
2
- import { promisify } from 'util';
3
- import * as fs from 'fs/promises';
4
1
  import { randomUUID, randomBytes, createHash } from 'crypto';
2
+ import * as fs from 'fs/promises';
5
3
  import * as path2 from 'path';
6
4
  import * as os from 'os';
5
+ import { execFile } from 'child_process';
6
+ import { promisify } from 'util';
7
7
  import { EventEmitter } from 'events';
8
8
 
9
9
  // src/utils/token-estimate.ts
@@ -1250,6 +1250,323 @@ function readPolicy(ctx) {
1250
1250
  if (typeof candidate.preserveK !== "number" || !candidate.thresholds) return null;
1251
1251
  return candidate;
1252
1252
  }
1253
+ async function atomicWrite(targetPath, content, opts = {}) {
1254
+ const dir = path2.dirname(targetPath);
1255
+ await fs.mkdir(dir, { recursive: true });
1256
+ const tmp = path2.join(dir, `.${path2.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
1257
+ try {
1258
+ if (typeof content === "string") {
1259
+ await fs.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
1260
+ } else {
1261
+ await fs.writeFile(tmp, content, { flag: "wx" });
1262
+ }
1263
+ try {
1264
+ const fh = await fs.open(tmp, "r+");
1265
+ try {
1266
+ await fh.sync();
1267
+ } finally {
1268
+ await fh.close();
1269
+ }
1270
+ } catch {
1271
+ }
1272
+ let mode;
1273
+ try {
1274
+ const stat2 = await fs.stat(targetPath);
1275
+ mode = stat2.mode & 511;
1276
+ } catch {
1277
+ mode = opts.mode;
1278
+ }
1279
+ if (mode !== void 0) {
1280
+ await fs.chmod(tmp, mode);
1281
+ }
1282
+ await renameWithRetry(tmp, targetPath);
1283
+ } catch (err) {
1284
+ try {
1285
+ await fs.unlink(tmp);
1286
+ } catch {
1287
+ }
1288
+ throw err;
1289
+ }
1290
+ }
1291
+ var TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
1292
+ async function renameWithRetry(from, to) {
1293
+ if (process.platform !== "win32") {
1294
+ await fs.rename(from, to);
1295
+ return;
1296
+ }
1297
+ const delays = [10, 25, 60, 120, 250];
1298
+ let lastErr;
1299
+ for (let i = 0; i <= delays.length; i++) {
1300
+ try {
1301
+ await fs.rename(from, to);
1302
+ return;
1303
+ } catch (err) {
1304
+ lastErr = err;
1305
+ const code = err?.code;
1306
+ if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
1307
+ throw err;
1308
+ }
1309
+ await new Promise((resolve2) => setTimeout(resolve2, delays[i]));
1310
+ }
1311
+ }
1312
+ throw lastErr;
1313
+ }
1314
+
1315
+ // src/utils/error.ts
1316
+ function toErrorMessage(err) {
1317
+ return err instanceof Error ? err.message : String(err);
1318
+ }
1319
+
1320
+ // src/utils/string.ts
1321
+ function truncate(s, max) {
1322
+ return s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;
1323
+ }
1324
+ function projectHash(absRoot) {
1325
+ return createHash("sha256").update(path2.resolve(absRoot)).digest("hex").slice(0, 12);
1326
+ }
1327
+ function projectSlug(absRoot) {
1328
+ const base = slugify(path2.basename(absRoot));
1329
+ const hash = createHash("sha256").update(path2.resolve(absRoot)).digest("hex").slice(0, 6);
1330
+ return `${base}-${hash}`;
1331
+ }
1332
+ function slugify(name) {
1333
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "project";
1334
+ }
1335
+ function wstackGlobalRoot() {
1336
+ const fromEnv = process.env["WRONGSTACK_HOME"];
1337
+ if (fromEnv && fromEnv.trim().length > 0) return path2.resolve(fromEnv);
1338
+ return path2.join(os.homedir(), ".wrongstack");
1339
+ }
1340
+ function resolveWstackPaths(opts) {
1341
+ const globalRoot = opts.globalRoot ?? (opts.userHome ? path2.join(opts.userHome, ".wrongstack") : wstackGlobalRoot());
1342
+ const hash = projectHash(opts.projectRoot);
1343
+ const slug = projectSlug(opts.projectRoot);
1344
+ const projectDir = path2.join(globalRoot, "projects", slug);
1345
+ return {
1346
+ globalRoot,
1347
+ configDir: globalRoot,
1348
+ globalConfig: path2.join(globalRoot, "config.json"),
1349
+ secretsKey: path2.join(globalRoot, ".key"),
1350
+ globalMemory: path2.join(globalRoot, "memory.md"),
1351
+ globalSkills: path2.join(globalRoot, "skills"),
1352
+ globalPrompts: path2.join(globalRoot, "prompts"),
1353
+ cacheDir: path2.join(globalRoot, "cache"),
1354
+ modelsCache: path2.join(globalRoot, "cache", "models.dev.json"),
1355
+ modelsOverlayCache: path2.join(globalRoot, "cache", "models-overlay.json"),
1356
+ historyFile: path2.join(globalRoot, "history"),
1357
+ logFile: path2.join(globalRoot, "logs", "wrongstack.log"),
1358
+ projectDir,
1359
+ projectCodebaseIndex: path2.join(projectDir, "codebase-index"),
1360
+ projectMemory: path2.join(projectDir, "memory.md"),
1361
+ projectSessions: path2.join(projectDir, "sessions"),
1362
+ projectTrust: path2.join(projectDir, "trust.json"),
1363
+ projectMeta: path2.join(projectDir, "meta.json"),
1364
+ projectLocalConfig: path2.join(projectDir, "config.local.json"),
1365
+ inProjectConfig: path2.join(opts.projectRoot, ".wrongstack", "config.json"),
1366
+ inProjectAgentsFile: path2.join(opts.projectRoot, ".wrongstack", "AGENTS.md"),
1367
+ inProjectSkills: path2.join(opts.projectRoot, ".wrongstack", "skills"),
1368
+ inProjectWorktrees: path2.join(opts.projectRoot, ".wrongstack", "worktrees"),
1369
+ projectHash: hash,
1370
+ projectSlug: slug,
1371
+ projectGoal: path2.join(projectDir, "goal.json"),
1372
+ projectSpecs: path2.join(projectDir, "specs"),
1373
+ projectTaskGraphs: path2.join(projectDir, "task-graphs"),
1374
+ projectSddSession: path2.join(projectDir, "sdd-session.json"),
1375
+ projectPlan: path2.join(projectDir, "plan.json"),
1376
+ projectAutophase: path2.join(projectDir, "autophase"),
1377
+ syncConfig: path2.join(globalRoot, "sync.json")
1378
+ };
1379
+ }
1380
+
1381
+ // src/utils/sleep.ts
1382
+ function sleep(ms) {
1383
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
1384
+ }
1385
+
1386
+ // src/utils/assert-never.ts
1387
+ function assertNever(x, message) {
1388
+ const err = new Error(
1389
+ `Unhandled case: ${JSON.stringify(x)}`
1390
+ );
1391
+ err.name = "AssertNeverError";
1392
+ throw err;
1393
+ }
1394
+
1395
+ // src/utils/tool-output-serializer.ts
1396
+ function createToolOutputSerializer(opts = {}) {
1397
+ const capBytes = opts.perIterationOutputCapBytes ?? 1e5;
1398
+ function serialize(value) {
1399
+ if (typeof value === "string") return value;
1400
+ if (value === null || value === void 0) return "";
1401
+ if (typeof value === "object") {
1402
+ if (Array.isArray(value)) return value.map(serialize).join("\n");
1403
+ if ("text" in value) {
1404
+ const t = value.text;
1405
+ return typeof t === "string" ? t : JSON.stringify(value, null, 2);
1406
+ }
1407
+ try {
1408
+ return JSON.stringify(value, null, 2);
1409
+ } catch {
1410
+ return String(value);
1411
+ }
1412
+ }
1413
+ return String(value);
1414
+ }
1415
+ function enforceCap(text, remainingBudget) {
1416
+ if (remainingBudget <= 0) {
1417
+ return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
1418
+ }
1419
+ const textBytes = Buffer.byteLength(text, "utf8");
1420
+ if (textBytes <= remainingBudget) {
1421
+ return { text, newBudget: remainingBudget - textBytes };
1422
+ }
1423
+ const marker = `
1424
+ \u2026[truncated ${textBytes - remainingBudget} bytes]\u2026
1425
+ `;
1426
+ const markerBytes = Buffer.byteLength(marker, "utf8");
1427
+ const available = remainingBudget - markerBytes;
1428
+ if (available <= 0) {
1429
+ return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
1430
+ }
1431
+ const half = Math.floor(available / 2);
1432
+ const first = text.slice(0, half);
1433
+ const second = text.slice(text.length - half);
1434
+ return { text: `${first}${marker}${second}`, newBudget: 0 };
1435
+ }
1436
+ return { serialize, enforceCap, capBytes };
1437
+ }
1438
+
1439
+ // src/utils/json-schema-validate.ts
1440
+ function validateAgainstSchema(value, schema) {
1441
+ const errors = [];
1442
+ walk(value, schema, "", errors);
1443
+ return { ok: errors.length === 0, errors };
1444
+ }
1445
+ function walk(value, schema, path4, errors) {
1446
+ if (schema.enum !== void 0) {
1447
+ if (!schema.enum.some((e) => deepEqual(e, value))) {
1448
+ errors.push({
1449
+ path: path4 || "<root>",
1450
+ message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
1451
+ });
1452
+ return;
1453
+ }
1454
+ }
1455
+ if (typeof schema.type === "string") {
1456
+ if (!checkType(value, schema.type)) {
1457
+ errors.push({
1458
+ path: path4 || "<root>",
1459
+ message: `expected ${schema.type}, got ${describeType(value)}`
1460
+ });
1461
+ return;
1462
+ }
1463
+ }
1464
+ if (schema.type === "object" && isPlainObject(value)) {
1465
+ const obj = value;
1466
+ for (const req of schema.required ?? []) {
1467
+ if (!(req in obj)) {
1468
+ errors.push({ path: joinPath(path4, req), message: "required property missing" });
1469
+ }
1470
+ }
1471
+ if (schema.properties) {
1472
+ for (const [key, subSchema] of Object.entries(schema.properties)) {
1473
+ if (key in obj) {
1474
+ walk(obj[key], subSchema, joinPath(path4, key), errors);
1475
+ }
1476
+ }
1477
+ }
1478
+ }
1479
+ if (schema.type === "array" && Array.isArray(value) && schema.items) {
1480
+ for (let i = 0; i < value.length; i++) {
1481
+ walk(value[i], schema.items, `${path4}[${i}]`, errors);
1482
+ }
1483
+ }
1484
+ }
1485
+ function checkType(value, type) {
1486
+ switch (type) {
1487
+ case "string":
1488
+ return typeof value === "string";
1489
+ case "number":
1490
+ return typeof value === "number" && !Number.isNaN(value);
1491
+ case "integer":
1492
+ return typeof value === "number" && Number.isInteger(value);
1493
+ case "boolean":
1494
+ return typeof value === "boolean";
1495
+ case "null":
1496
+ return value === null;
1497
+ case "array":
1498
+ return Array.isArray(value);
1499
+ case "object":
1500
+ return isPlainObject(value);
1501
+ default:
1502
+ return true;
1503
+ }
1504
+ }
1505
+ function isPlainObject(v) {
1506
+ return typeof v === "object" && v !== null && !Array.isArray(v);
1507
+ }
1508
+ function describeType(v) {
1509
+ if (v === null) return "null";
1510
+ if (Array.isArray(v)) return "array";
1511
+ return typeof v;
1512
+ }
1513
+ function joinPath(parent, key) {
1514
+ if (!parent) return key;
1515
+ return `${parent}.${key}`;
1516
+ }
1517
+ function deepEqual(a, b) {
1518
+ if (a === b) return true;
1519
+ if (typeof a !== typeof b) return false;
1520
+ if (a === null || b === null) return a === b;
1521
+ if (Array.isArray(a) && Array.isArray(b)) {
1522
+ return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
1523
+ }
1524
+ if (typeof a === "object" && typeof b === "object") {
1525
+ const ak = Object.keys(a);
1526
+ const bk = Object.keys(b);
1527
+ if (ak.length !== bk.length) return false;
1528
+ return ak.every(
1529
+ (k) => deepEqual(a[k], b[k])
1530
+ );
1531
+ }
1532
+ return false;
1533
+ }
1534
+
1535
+ // src/utils/regex-guard.ts
1536
+ var MAX_PATTERN_LEN = 512;
1537
+ var DANGEROUS_PATTERNS = [
1538
+ /(\([^)]*[+*][^)]*\))[+*]/,
1539
+ // (a+)+, (.*)+, etc
1540
+ /(\(\?:[^)]*[+*][^)]*\))[+*]/
1541
+ // same, with non-capturing group
1542
+ ];
1543
+ function compileUserRegex(pattern, flags) {
1544
+ if (typeof pattern !== "string") {
1545
+ return { ok: false, reason: "pattern must be a string" };
1546
+ }
1547
+ if (pattern.length === 0) {
1548
+ return { ok: false, reason: "pattern is empty" };
1549
+ }
1550
+ if (pattern.length > MAX_PATTERN_LEN) {
1551
+ return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };
1552
+ }
1553
+ for (const rx of DANGEROUS_PATTERNS) {
1554
+ if (rx.test(pattern)) {
1555
+ return {
1556
+ ok: false,
1557
+ reason: "pattern looks vulnerable to catastrophic backtracking \u2014 rewrite without nested quantifiers"
1558
+ };
1559
+ }
1560
+ }
1561
+ try {
1562
+ return { ok: true, regex: new RegExp(pattern, flags) };
1563
+ } catch (err) {
1564
+ return {
1565
+ ok: false,
1566
+ reason: err instanceof Error ? err.message : "invalid regex"
1567
+ };
1568
+ }
1569
+ }
1253
1570
 
1254
1571
  // src/types/errors.ts
1255
1572
  var ERROR_CODES = {
@@ -1312,7 +1629,7 @@ var AgentError = class extends WrongStackError {
1312
1629
  };
1313
1630
  function toWrongStackError(err, code = ERROR_CODES.AGENT_RUN_FAILED) {
1314
1631
  if (err instanceof WrongStackError) return err;
1315
- const message = err instanceof Error ? err.message : String(err);
1632
+ const message = toErrorMessage(err);
1316
1633
  return new AgentError({
1317
1634
  message,
1318
1635
  code: code === "UNKNOWN" ? ERROR_CODES.AGENT_RUN_FAILED : code,
@@ -1353,6 +1670,12 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
1353
1670
  hardThreshold;
1354
1671
  /** Writable so model-switch can update the denominator without re-registering the middleware. */
1355
1672
  _maxContext;
1673
+ /**
1674
+ * Runtime on/off gate. The middleware is always installed in the pipeline so
1675
+ * auto-compaction can be toggled live from the TUI `/settings` picker; when
1676
+ * disabled the handler is a pass-through. Defaults to enabled.
1677
+ */
1678
+ _enabled = true;
1356
1679
  aggressiveOn;
1357
1680
  events;
1358
1681
  failureMode;
@@ -1410,8 +1733,19 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
1410
1733
  setMaxContext(maxContext) {
1411
1734
  this._maxContext = maxContext;
1412
1735
  }
1736
+ /** Whether auto-compaction is currently active. */
1737
+ get enabled() {
1738
+ return this._enabled;
1739
+ }
1740
+ /** Toggle auto-compaction on a live session (TUI `/settings`). When disabled
1741
+ * the middleware passes every iteration straight through without estimating
1742
+ * tokens or compacting. */
1743
+ setEnabled(enabled) {
1744
+ this._enabled = enabled;
1745
+ }
1413
1746
  handler() {
1414
1747
  return async (ctx, next) => {
1748
+ if (!this._enabled) return next(ctx);
1415
1749
  const msgCount = ctx.messages.length;
1416
1750
  const toolCount = (ctx.tools ?? []).length;
1417
1751
  let tokens;
@@ -1532,207 +1866,69 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
1532
1866
  aggressive,
1533
1867
  level: pressure.level,
1534
1868
  tokens: pressure.tokens,
1535
- maxContext: this._maxContext,
1536
- load: pressure.load,
1537
- fatal
1538
- });
1539
- if (fatal) {
1540
- throw new AgentError({
1541
- message: `Auto-compaction failed at ${pressure.level} threshold`,
1542
- code: ERROR_CODES.AGENT_CONTEXT_OVERFLOW,
1543
- recoverable: true,
1544
- context: {
1545
- level: pressure.level,
1546
- tokens: pressure.tokens,
1547
- maxContext: this._maxContext
1548
- },
1549
- cause: err
1550
- });
1551
- }
1552
- }
1553
- }
1554
- };
1555
-
1556
- // src/security/capabilities.ts
1557
- var ToolCapabilities = {
1558
- /** Can execute arbitrary commands in the user's shell (the `bash` tool). */
1559
- SHELL_ARBITRARY: "shell.arbitrary",
1560
- /** Can execute a restricted set of commands (the `exec` tool). */
1561
- SHELL_RESTRICTED: "shell.restricted",
1562
- /** Can write / modify / delete files inside the project. */
1563
- FS_WRITE: "fs.write",
1564
- /** Can write files outside the current project root (very high risk). */
1565
- FS_WRITE_OUTSIDE_PROJECT: "fs.write.outside-project",
1566
- /** Proxies tools from external MCP servers (unknown capability). */
1567
- MCP_PROXY: "mcp.proxy",
1568
- /** Can spawn or manage subagents / multi-agent tasks. */
1569
- SUBAGENT_SPAWN: "subagent.spawn",
1570
- /** Can mutate global or session configuration / trust state. */
1571
- CONFIG_MUTATE: "config.mutate",
1572
- /** Can install packages or run package managers with side effects. */
1573
- PACKAGE_INSTALL: "package.install"
1574
- };
1575
- var DANGEROUS_FOR_SUBAGENTS = [
1576
- ToolCapabilities.SHELL_ARBITRARY,
1577
- ToolCapabilities.SHELL_RESTRICTED,
1578
- ToolCapabilities.FS_WRITE,
1579
- ToolCapabilities.FS_WRITE_OUTSIDE_PROJECT,
1580
- ToolCapabilities.MCP_PROXY,
1581
- ToolCapabilities.SUBAGENT_SPAWN,
1582
- ToolCapabilities.CONFIG_MUTATE,
1583
- ToolCapabilities.PACKAGE_INSTALL
1584
- ];
1585
- function hasDangerousCapabilityForSubagents(toolOrCaps) {
1586
- if (!toolOrCaps) return false;
1587
- const input = toolOrCaps;
1588
- const caps = Array.isArray(toolOrCaps) ? toolOrCaps : input.capabilities ?? [];
1589
- return caps.some((c) => DANGEROUS_FOR_SUBAGENTS.includes(c));
1590
- }
1591
- function getDangerousCapabilities(toolOrCaps) {
1592
- if (!toolOrCaps) return [];
1593
- const input = toolOrCaps;
1594
- const caps = Array.isArray(toolOrCaps) ? toolOrCaps : input.capabilities ?? [];
1595
- return caps.filter(
1596
- (c) => DANGEROUS_FOR_SUBAGENTS.includes(c)
1597
- );
1598
- }
1599
-
1600
- // src/utils/json-schema-validate.ts
1601
- function validateAgainstSchema(value, schema) {
1602
- const errors = [];
1603
- walk(value, schema, "", errors);
1604
- return { ok: errors.length === 0, errors };
1605
- }
1606
- function walk(value, schema, path4, errors) {
1607
- if (schema.enum !== void 0) {
1608
- if (!schema.enum.some((e) => deepEqual(e, value))) {
1609
- errors.push({
1610
- path: path4 || "<root>",
1611
- message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
1612
- });
1613
- return;
1614
- }
1615
- }
1616
- if (typeof schema.type === "string") {
1617
- if (!checkType(value, schema.type)) {
1618
- errors.push({
1619
- path: path4 || "<root>",
1620
- message: `expected ${schema.type}, got ${describeType(value)}`
1621
- });
1622
- return;
1623
- }
1624
- }
1625
- if (schema.type === "object" && isPlainObject(value)) {
1626
- const obj = value;
1627
- for (const req of schema.required ?? []) {
1628
- if (!(req in obj)) {
1629
- errors.push({ path: joinPath(path4, req), message: "required property missing" });
1630
- }
1631
- }
1632
- if (schema.properties) {
1633
- for (const [key, subSchema] of Object.entries(schema.properties)) {
1634
- if (key in obj) {
1635
- walk(obj[key], subSchema, joinPath(path4, key), errors);
1636
- }
1637
- }
1638
- }
1639
- }
1640
- if (schema.type === "array" && Array.isArray(value) && schema.items) {
1641
- value.forEach((item, i) => walk(item, schema.items, `${path4}[${i}]`, errors));
1642
- }
1643
- }
1644
- function checkType(value, type) {
1645
- switch (type) {
1646
- case "string":
1647
- return typeof value === "string";
1648
- case "number":
1649
- return typeof value === "number" && !Number.isNaN(value);
1650
- case "integer":
1651
- return typeof value === "number" && Number.isInteger(value);
1652
- case "boolean":
1653
- return typeof value === "boolean";
1654
- case "null":
1655
- return value === null;
1656
- case "array":
1657
- return Array.isArray(value);
1658
- case "object":
1659
- return isPlainObject(value);
1660
- default:
1661
- return true;
1662
- }
1663
- }
1664
- function isPlainObject(v) {
1665
- return typeof v === "object" && v !== null && !Array.isArray(v);
1666
- }
1667
- function describeType(v) {
1668
- if (v === null) return "null";
1669
- if (Array.isArray(v)) return "array";
1670
- return typeof v;
1671
- }
1672
- function joinPath(parent, key) {
1673
- if (!parent) return key;
1674
- return `${parent}.${key}`;
1675
- }
1676
- function deepEqual(a, b) {
1677
- if (a === b) return true;
1678
- if (typeof a !== typeof b) return false;
1679
- if (a === null || b === null) return a === b;
1680
- if (Array.isArray(a) && Array.isArray(b)) {
1681
- return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
1682
- }
1683
- if (typeof a === "object" && typeof b === "object") {
1684
- const ak = Object.keys(a);
1685
- const bk = Object.keys(b);
1686
- if (ak.length !== bk.length) return false;
1687
- return ak.every(
1688
- (k) => deepEqual(a[k], b[k])
1689
- );
1690
- }
1691
- return false;
1692
- }
1693
-
1694
- // src/utils/tool-output-serializer.ts
1695
- function createToolOutputSerializer(opts = {}) {
1696
- const capBytes = opts.perIterationOutputCapBytes ?? 1e5;
1697
- function serialize(value) {
1698
- if (typeof value === "string") return value;
1699
- if (value === null || value === void 0) return "";
1700
- if (typeof value === "object") {
1701
- if (Array.isArray(value)) return value.map(serialize).join("\n");
1702
- if ("text" in value) {
1703
- const t = value.text;
1704
- return typeof t === "string" ? t : JSON.stringify(value, null, 2);
1705
- }
1706
- try {
1707
- return JSON.stringify(value, null, 2);
1708
- } catch {
1709
- return String(value);
1869
+ maxContext: this._maxContext,
1870
+ load: pressure.load,
1871
+ fatal
1872
+ });
1873
+ if (fatal) {
1874
+ throw new AgentError({
1875
+ message: `Auto-compaction failed at ${pressure.level} threshold`,
1876
+ code: ERROR_CODES.AGENT_CONTEXT_OVERFLOW,
1877
+ recoverable: true,
1878
+ context: {
1879
+ level: pressure.level,
1880
+ tokens: pressure.tokens,
1881
+ maxContext: this._maxContext
1882
+ },
1883
+ cause: err
1884
+ });
1710
1885
  }
1711
1886
  }
1712
- return String(value);
1713
- }
1714
- function enforceCap(text, remainingBudget) {
1715
- if (remainingBudget <= 0) {
1716
- return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
1717
- }
1718
- const textBytes = Buffer.byteLength(text, "utf8");
1719
- if (textBytes <= remainingBudget) {
1720
- return { text, newBudget: remainingBudget - textBytes };
1721
- }
1722
- const marker = `
1723
- \u2026[truncated ${textBytes - remainingBudget} bytes]\u2026
1724
- `;
1725
- const markerBytes = Buffer.byteLength(marker, "utf8");
1726
- const available = remainingBudget - markerBytes;
1727
- if (available <= 0) {
1728
- return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
1729
- }
1730
- const half = Math.floor(available / 2);
1731
- const first = text.slice(0, half);
1732
- const second = text.slice(text.length - half);
1733
- return { text: `${first}${marker}${second}`, newBudget: 0 };
1734
1887
  }
1735
- return { serialize, enforceCap, capBytes };
1888
+ };
1889
+
1890
+ // src/security/capabilities.ts
1891
+ var ToolCapabilities = {
1892
+ /** Can execute arbitrary commands in the user's shell (the `bash` tool). */
1893
+ SHELL_ARBITRARY: "shell.arbitrary",
1894
+ /** Can execute a restricted set of commands (the `exec` tool). */
1895
+ SHELL_RESTRICTED: "shell.restricted",
1896
+ /** Can write / modify / delete files inside the project. */
1897
+ FS_WRITE: "fs.write",
1898
+ /** Can write files outside the current project root (very high risk). */
1899
+ FS_WRITE_OUTSIDE_PROJECT: "fs.write.outside-project",
1900
+ /** Proxies tools from external MCP servers (unknown capability). */
1901
+ MCP_PROXY: "mcp.proxy",
1902
+ /** Can spawn or manage subagents / multi-agent tasks. */
1903
+ SUBAGENT_SPAWN: "subagent.spawn",
1904
+ /** Can mutate global or session configuration / trust state. */
1905
+ CONFIG_MUTATE: "config.mutate",
1906
+ /** Can install packages or run package managers with side effects. */
1907
+ PACKAGE_INSTALL: "package.install"
1908
+ };
1909
+ var DANGEROUS_FOR_SUBAGENTS = [
1910
+ ToolCapabilities.SHELL_ARBITRARY,
1911
+ ToolCapabilities.SHELL_RESTRICTED,
1912
+ ToolCapabilities.FS_WRITE,
1913
+ ToolCapabilities.FS_WRITE_OUTSIDE_PROJECT,
1914
+ ToolCapabilities.MCP_PROXY,
1915
+ ToolCapabilities.SUBAGENT_SPAWN,
1916
+ ToolCapabilities.CONFIG_MUTATE,
1917
+ ToolCapabilities.PACKAGE_INSTALL
1918
+ ];
1919
+ function hasDangerousCapabilityForSubagents(toolOrCaps) {
1920
+ if (!toolOrCaps) return false;
1921
+ const input = toolOrCaps;
1922
+ const caps = Array.isArray(toolOrCaps) ? toolOrCaps : input.capabilities ?? [];
1923
+ return caps.some((c) => DANGEROUS_FOR_SUBAGENTS.includes(c));
1924
+ }
1925
+ function getDangerousCapabilities(toolOrCaps) {
1926
+ if (!toolOrCaps) return [];
1927
+ const input = toolOrCaps;
1928
+ const caps = Array.isArray(toolOrCaps) ? toolOrCaps : input.capabilities ?? [];
1929
+ return caps.filter(
1930
+ (c) => DANGEROUS_FOR_SUBAGENTS.includes(c)
1931
+ );
1736
1932
  }
1737
1933
 
1738
1934
  // src/execution/tool-executor.ts
@@ -1898,7 +2094,7 @@ ${post.additionalContext}`;
1898
2094
  );
1899
2095
  return { result, tool, durationMs: Date.now() - start };
1900
2096
  } catch (err) {
1901
- const msg = err instanceof Error ? err.message : String(err);
2097
+ const msg = toErrorMessage(err);
1902
2098
  const scrubbed = this.opts.secretScrubber.scrub(msg);
1903
2099
  this.opts.renderer?.writeToolResult(tool.name, scrubbed, true);
1904
2100
  const result = {
@@ -1919,7 +2115,7 @@ ${post.additionalContext}`;
1919
2115
  try {
1920
2116
  return await runOne(use);
1921
2117
  } catch (err) {
1922
- const msg = err instanceof Error ? err.message : String(err);
2118
+ const msg = toErrorMessage(err);
1923
2119
  const scrubbed = this.opts.secretScrubber.scrub(msg);
1924
2120
  const result = {
1925
2121
  type: "tool_result",
@@ -2202,51 +2398,6 @@ function extractMalformedRaw(input) {
2202
2398
  }
2203
2399
  }
2204
2400
 
2205
- // src/utils/assert-never.ts
2206
- function assertNever(x, message) {
2207
- const err = new Error(
2208
- `Unhandled case: ${JSON.stringify(x)}`
2209
- );
2210
- err.name = "AssertNeverError";
2211
- throw err;
2212
- }
2213
-
2214
- // src/utils/regex-guard.ts
2215
- var MAX_PATTERN_LEN = 512;
2216
- var DANGEROUS_PATTERNS = [
2217
- /(\([^)]*[+*][^)]*\))[+*]/,
2218
- // (a+)+, (.*)+, etc
2219
- /(\(\?:[^)]*[+*][^)]*\))[+*]/
2220
- // same, with non-capturing group
2221
- ];
2222
- function compileUserRegex(pattern, flags) {
2223
- if (typeof pattern !== "string") {
2224
- return { ok: false, reason: "pattern must be a string" };
2225
- }
2226
- if (pattern.length === 0) {
2227
- return { ok: false, reason: "pattern is empty" };
2228
- }
2229
- if (pattern.length > MAX_PATTERN_LEN) {
2230
- return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };
2231
- }
2232
- for (const rx of DANGEROUS_PATTERNS) {
2233
- if (rx.test(pattern)) {
2234
- return {
2235
- ok: false,
2236
- reason: "pattern looks vulnerable to catastrophic backtracking \u2014 rewrite without nested quantifiers"
2237
- };
2238
- }
2239
- }
2240
- try {
2241
- return { ok: true, regex: new RegExp(pattern, flags) };
2242
- } catch (err) {
2243
- return {
2244
- ok: false,
2245
- reason: err instanceof Error ? err.message : "invalid regex"
2246
- };
2247
- }
2248
- }
2249
-
2250
2401
  // src/execution/autonomous-runner.ts
2251
2402
  var DoneConditionChecker = class {
2252
2403
  constructor(condition) {
@@ -2423,125 +2574,6 @@ var AutonomousRunner = class {
2423
2574
  this.stopped = true;
2424
2575
  }
2425
2576
  };
2426
- async function atomicWrite(targetPath, content, opts = {}) {
2427
- const dir = path2.dirname(targetPath);
2428
- await fs.mkdir(dir, { recursive: true });
2429
- const tmp = path2.join(dir, `.${path2.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
2430
- try {
2431
- if (typeof content === "string") {
2432
- await fs.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
2433
- } else {
2434
- await fs.writeFile(tmp, content, { flag: "wx" });
2435
- }
2436
- try {
2437
- const fh = await fs.open(tmp, "r+");
2438
- try {
2439
- await fh.sync();
2440
- } finally {
2441
- await fh.close();
2442
- }
2443
- } catch {
2444
- }
2445
- let mode;
2446
- try {
2447
- const stat2 = await fs.stat(targetPath);
2448
- mode = stat2.mode & 511;
2449
- } catch {
2450
- mode = opts.mode;
2451
- }
2452
- if (mode !== void 0) {
2453
- await fs.chmod(tmp, mode);
2454
- }
2455
- await renameWithRetry(tmp, targetPath);
2456
- } catch (err) {
2457
- try {
2458
- await fs.unlink(tmp);
2459
- } catch {
2460
- }
2461
- throw err;
2462
- }
2463
- }
2464
- var TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
2465
- async function renameWithRetry(from, to) {
2466
- if (process.platform !== "win32") {
2467
- await fs.rename(from, to);
2468
- return;
2469
- }
2470
- const delays = [10, 25, 60, 120, 250];
2471
- let lastErr;
2472
- for (let i = 0; i <= delays.length; i++) {
2473
- try {
2474
- await fs.rename(from, to);
2475
- return;
2476
- } catch (err) {
2477
- lastErr = err;
2478
- const code = err?.code;
2479
- if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
2480
- throw err;
2481
- }
2482
- await new Promise((resolve2) => setTimeout(resolve2, delays[i]));
2483
- }
2484
- }
2485
- throw lastErr;
2486
- }
2487
- function projectHash(absRoot) {
2488
- return createHash("sha256").update(path2.resolve(absRoot)).digest("hex").slice(0, 12);
2489
- }
2490
- function projectSlug(absRoot) {
2491
- const base = slugify(path2.basename(absRoot));
2492
- const hash = createHash("sha256").update(path2.resolve(absRoot)).digest("hex").slice(0, 6);
2493
- return `${base}-${hash}`;
2494
- }
2495
- function slugify(name) {
2496
- return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "project";
2497
- }
2498
- function wstackGlobalRoot() {
2499
- const fromEnv = process.env["WRONGSTACK_HOME"];
2500
- if (fromEnv && fromEnv.trim().length > 0) return path2.resolve(fromEnv);
2501
- return path2.join(os.homedir(), ".wrongstack");
2502
- }
2503
- function resolveWstackPaths(opts) {
2504
- const globalRoot = opts.globalRoot ?? (opts.userHome ? path2.join(opts.userHome, ".wrongstack") : wstackGlobalRoot());
2505
- const hash = projectHash(opts.projectRoot);
2506
- const slug = projectSlug(opts.projectRoot);
2507
- const projectDir = path2.join(globalRoot, "projects", slug);
2508
- return {
2509
- globalRoot,
2510
- configDir: globalRoot,
2511
- globalConfig: path2.join(globalRoot, "config.json"),
2512
- secretsKey: path2.join(globalRoot, ".key"),
2513
- globalMemory: path2.join(globalRoot, "memory.md"),
2514
- globalSkills: path2.join(globalRoot, "skills"),
2515
- globalPrompts: path2.join(globalRoot, "prompts"),
2516
- cacheDir: path2.join(globalRoot, "cache"),
2517
- modelsCache: path2.join(globalRoot, "cache", "models.dev.json"),
2518
- modelsOverlayCache: path2.join(globalRoot, "cache", "models-overlay.json"),
2519
- historyFile: path2.join(globalRoot, "history"),
2520
- logFile: path2.join(globalRoot, "logs", "wrongstack.log"),
2521
- projectDir,
2522
- projectCodebaseIndex: path2.join(projectDir, "codebase-index"),
2523
- projectMemory: path2.join(projectDir, "memory.md"),
2524
- projectSessions: path2.join(projectDir, "sessions"),
2525
- projectTrust: path2.join(projectDir, "trust.json"),
2526
- projectMeta: path2.join(projectDir, "meta.json"),
2527
- projectLocalConfig: path2.join(projectDir, "config.local.json"),
2528
- inProjectConfig: path2.join(opts.projectRoot, ".wrongstack", "config.json"),
2529
- inProjectAgentsFile: path2.join(opts.projectRoot, ".wrongstack", "AGENTS.md"),
2530
- inProjectSkills: path2.join(opts.projectRoot, ".wrongstack", "skills"),
2531
- inProjectWorktrees: path2.join(opts.projectRoot, ".wrongstack", "worktrees"),
2532
- projectHash: hash,
2533
- projectSlug: slug,
2534
- projectGoal: path2.join(projectDir, "goal.json"),
2535
- projectSpecs: path2.join(projectDir, "specs"),
2536
- projectTaskGraphs: path2.join(projectDir, "task-graphs"),
2537
- projectSddSession: path2.join(projectDir, "sdd-session.json"),
2538
- projectPlan: path2.join(projectDir, "plan.json"),
2539
- projectAutophase: path2.join(projectDir, "autophase"),
2540
- syncConfig: path2.join(globalRoot, "sync.json")
2541
- };
2542
- }
2543
-
2544
- // src/storage/goal-store.ts
2545
2577
  var MAX_JOURNAL_ENTRIES = 500;
2546
2578
  function goalFilePath(projectRoot) {
2547
2579
  return resolveWstackPaths({ projectRoot }).projectGoal;
@@ -2569,7 +2601,7 @@ async function loadGoal(filePath, events) {
2569
2601
  store: "goal",
2570
2602
  filePath,
2571
2603
  operation: "load",
2572
- error: err instanceof Error ? err.message : String(err),
2604
+ error: toErrorMessage(err),
2573
2605
  recoverable: false
2574
2606
  });
2575
2607
  throw err;
@@ -2642,11 +2674,11 @@ async function saveGoal(filePath, goal, events) {
2642
2674
  store: "goal",
2643
2675
  filePath,
2644
2676
  operation: "save",
2645
- error: err instanceof Error ? err.message : String(err),
2677
+ error: toErrorMessage(err),
2646
2678
  recoverable: false
2647
2679
  });
2648
2680
  throw new FsError({
2649
- message: err instanceof Error ? err.message : String(err),
2681
+ message: toErrorMessage(err),
2650
2682
  code: ERROR_CODES.FS_ATOMIC_WRITE_FAILED,
2651
2683
  path: filePath,
2652
2684
  cause: err
@@ -2700,11 +2732,6 @@ function computeTrend(history) {
2700
2732
  return "steady";
2701
2733
  }
2702
2734
 
2703
- // src/utils/sleep.ts
2704
- function sleep(ms) {
2705
- return new Promise((resolve2) => setTimeout(resolve2, ms));
2706
- }
2707
-
2708
2735
  // src/execution/autonomy-brain.ts
2709
2736
  var RISK_LEVELS = {
2710
2737
  low: 0,
@@ -2941,7 +2968,7 @@ var EternalAutonomyEngine = class {
2941
2968
  console.error(JSON.stringify({
2942
2969
  level: "error",
2943
2970
  event: "engine.persist_state_failed",
2944
- message: err instanceof Error ? err.message : String(err),
2971
+ message: toErrorMessage(err),
2945
2972
  context: { expectedState: "stopped" },
2946
2973
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
2947
2974
  }));
@@ -2974,7 +3001,7 @@ var EternalAutonomyEngine = class {
2974
3001
  } catch (err) {
2975
3002
  this.consecutiveFailures++;
2976
3003
  this.opts.onError?.(err instanceof Error ? err : new Error(String(err)), this.consecutiveFailures);
2977
- await this.appendFailure("engine error", err instanceof Error ? err.message : String(err));
3004
+ await this.appendFailure("engine error", toErrorMessage(err));
2978
3005
  }
2979
3006
  if (iterationOk) {
2980
3007
  this.consecutiveFailures = 0;
@@ -3075,7 +3102,7 @@ var EternalAutonomyEngine = class {
3075
3102
  } catch (err) {
3076
3103
  const isAbort = err instanceof Error && (err.name === "AbortError" || err.message.includes("abort"));
3077
3104
  status = isAbort ? "aborted" : "failure";
3078
- note = err instanceof Error ? err.message : String(err);
3105
+ note = toErrorMessage(err);
3079
3106
  if (!isAbort && typeof err?.recoverable === "boolean") {
3080
3107
  isTransientFailure = err.recoverable;
3081
3108
  }
@@ -6819,11 +6846,6 @@ async function dispatchAgent(task, opts = {}) {
6819
6846
  };
6820
6847
  }
6821
6848
 
6822
- // src/utils/string.ts
6823
- function truncate(s, max) {
6824
- return s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;
6825
- }
6826
-
6827
6849
  // src/types/provider.ts
6828
6850
  var ProviderError = class extends WrongStackError {
6829
6851
  status;
@@ -6903,7 +6925,7 @@ function classifySubagentError(err, hints = {}) {
6903
6925
  const baseMessage2 = err.describe();
6904
6926
  return providerErrorToSubagentError(err, baseMessage2, cause);
6905
6927
  }
6906
- const baseMessage = err instanceof Error ? err.message : String(err);
6928
+ const baseMessage = toErrorMessage(err);
6907
6929
  if (err instanceof BudgetExceededError) {
6908
6930
  const map = {
6909
6931
  iterations: "budget_iterations",
@@ -7883,7 +7905,7 @@ var ParallelEternalEngine = class {
7883
7905
  console.error(JSON.stringify({
7884
7906
  level: "error",
7885
7907
  event: "engine.persist_state_failed",
7886
- message: err instanceof Error ? err.message : String(err),
7908
+ message: toErrorMessage(err),
7887
7909
  context: { expectedState: "stopped" },
7888
7910
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
7889
7911
  }));
@@ -7919,7 +7941,7 @@ var ParallelEternalEngine = class {
7919
7941
  );
7920
7942
  await this.appendFailure(
7921
7943
  "engine error",
7922
- err instanceof Error ? err.message : String(err)
7944
+ toErrorMessage(err)
7923
7945
  );
7924
7946
  }
7925
7947
  if (this.stopRequested) break;
@@ -8711,7 +8733,7 @@ function parseDescription(raw) {
8711
8733
  const scope = [];
8712
8734
  const coversMatch = /(?:covers|for|including)\s+([^.]+)/i.exec(desc);
8713
8735
  if (coversMatch) {
8714
- const items = coversMatch[1] ?? "".replace(/[·•]/g, ",").split(",").map((s) => s.trim()).filter(Boolean);
8736
+ const items = (coversMatch[1] ?? "").replace(/[·•]/g, ",").split(",").map((s) => s.trim()).filter(Boolean);
8715
8737
  scope.push(...items);
8716
8738
  }
8717
8739
  return { trigger, scope };