@wrongstack/core 0.68.0 → 0.77.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 (59) hide show
  1. package/dist/{agent-bridge-D-j6OOBT.d.ts → agent-bridge-EWdqs8v6.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-DRZ9-NnR.d.ts → agent-subagent-runner-D8qW8OSC.d.ts} +13 -5
  3. package/dist/{config--86aHSln.d.ts → config-Dy0CK_o6.d.ts} +44 -1
  4. package/dist/coordination/index.d.ts +10 -10
  5. package/dist/coordination/index.js +74 -10
  6. package/dist/coordination/index.js.map +1 -1
  7. package/dist/defaults/index.d.ts +17 -17
  8. package/dist/defaults/index.js +160 -67
  9. package/dist/defaults/index.js.map +1 -1
  10. package/dist/{events-CIplI98R.d.ts → events-CYaoLN5_.d.ts} +45 -0
  11. package/dist/execution/index.d.ts +9 -9
  12. package/dist/execution/index.js +4 -4
  13. package/dist/execution/index.js.map +1 -1
  14. package/dist/extension/index.d.ts +5 -5
  15. package/dist/{index-b5uhfTSl.d.ts → index-DIxjTOga.d.ts} +6 -6
  16. package/dist/{index-DKUvyTvV.d.ts → index-Dsda0uCn.d.ts} +4 -4
  17. package/dist/index.d.ts +108 -33
  18. package/dist/index.js +388 -58
  19. package/dist/index.js.map +1 -1
  20. package/dist/infrastructure/index.d.ts +5 -5
  21. package/dist/infrastructure/index.js +16 -2
  22. package/dist/infrastructure/index.js.map +1 -1
  23. package/dist/kernel/index.d.ts +7 -7
  24. package/dist/kernel/index.js.map +1 -1
  25. package/dist/{logger-bOzkF5LL.d.ts → logger-BppKxDqZ.d.ts} +9 -0
  26. package/dist/{mcp-servers-DwoNBf6r.d.ts → mcp-servers-T0O6UN_w.d.ts} +1 -1
  27. package/dist/{mode-CV077NjV.d.ts → mode-BO4SEUIv.d.ts} +7 -0
  28. package/dist/models/index.d.ts +1 -1
  29. package/dist/models/index.js +18 -9
  30. package/dist/models/index.js.map +1 -1
  31. package/dist/{multi-agent-coordinator-CWnH-CiX.d.ts → multi-agent-coordinator-DpbG3wiy.d.ts} +1 -1
  32. package/dist/{null-fleet-bus-CuN0ObJr.d.ts → null-fleet-bus-u5ys3lW_.d.ts} +28 -9
  33. package/dist/observability/index.d.ts +1 -1
  34. package/dist/{parallel-eternal-engine-0UwotoSx.d.ts → parallel-eternal-engine-Dn0P8Pbj.d.ts} +3 -3
  35. package/dist/{path-resolver-DVkEcIw8.d.ts → path-resolver-B32v2JIq.d.ts} +1 -1
  36. package/dist/{permission-C1A5whY5.d.ts → permission-V5BLOrY6.d.ts} +0 -4
  37. package/dist/{permission-policy-B2dK-T5N.d.ts → permission-policy-CBVx-d-8.d.ts} +1 -5
  38. package/dist/{plan-templates-Bprrzhbu.d.ts → plan-templates-BcUwLlMQ.d.ts} +8 -3
  39. package/dist/{provider-runner-mXvXGSIw.d.ts → provider-runner-CSi_7l0h.d.ts} +1 -1
  40. package/dist/sdd/index.d.ts +6 -6
  41. package/dist/sdd/index.js +3 -3
  42. package/dist/sdd/index.js.map +1 -1
  43. package/dist/security/index.d.ts +2 -2
  44. package/dist/security/index.js +0 -8
  45. package/dist/security/index.js.map +1 -1
  46. package/dist/skills/index.js +1 -0
  47. package/dist/skills/index.js.map +1 -1
  48. package/dist/storage/index.d.ts +4 -4
  49. package/dist/storage/index.js +48 -8
  50. package/dist/storage/index.js.map +1 -1
  51. package/dist/{system-prompt-b61lOd49.d.ts → system-prompt-CA11g6Jo.d.ts} +1 -1
  52. package/dist/types/index.d.ts +14 -14
  53. package/dist/types/index.js +35 -12
  54. package/dist/types/index.js.map +1 -1
  55. package/dist/utils/index.d.ts +2 -2
  56. package/dist/utils/index.js +14 -3
  57. package/dist/utils/index.js.map +1 -1
  58. package/dist/{wstack-paths-eMXnY1_X.d.ts → wstack-paths-D7evAFWM.d.ts} +8 -1
  59. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  import * as crypto2 from 'crypto';
2
2
  import { randomBytes, randomUUID, createCipheriv, createDecipheriv, createHash } from 'crypto';
3
3
  import * as fsp from 'fs/promises';
4
- import * as path16 from 'path';
4
+ import * as path3 from 'path';
5
5
  import { isAbsolute, resolve } from 'path';
6
6
  import * as fs5 from 'fs';
7
7
  import * as os from 'os';
@@ -32,9 +32,9 @@ __export(atomic_write_exports, {
32
32
  ensureDir: () => ensureDir
33
33
  });
34
34
  async function atomicWrite(targetPath, content, opts = {}) {
35
- const dir = path16.dirname(targetPath);
35
+ const dir = path3.dirname(targetPath);
36
36
  await fsp.mkdir(dir, { recursive: true });
37
- const tmp = path16.join(dir, `.${path16.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
37
+ const tmp = path3.join(dir, `.${path3.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
38
38
  try {
39
39
  if (typeof content === "string") {
40
40
  await fsp.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
@@ -162,14 +162,16 @@ var DefaultLogger = class _DefaultLogger {
162
162
  file;
163
163
  bindings;
164
164
  pretty;
165
+ stderr;
165
166
  constructor(opts = {}) {
166
167
  this.level = opts.level ?? process.env.WRONGSTACK_LOG_LEVEL ?? "info";
167
168
  this.file = opts.file;
168
169
  this.bindings = opts.bindings ?? {};
169
170
  this.pretty = opts.pretty ?? true;
171
+ this.stderr = opts.stderr !== false;
170
172
  if (this.file) {
171
173
  try {
172
- fs5.mkdirSync(path16.dirname(this.file), { recursive: true });
174
+ fs5.mkdirSync(path3.dirname(this.file), { recursive: true });
173
175
  } catch {
174
176
  }
175
177
  }
@@ -194,6 +196,7 @@ var DefaultLogger = class _DefaultLogger {
194
196
  level: this.level,
195
197
  file: this.file,
196
198
  pretty: this.pretty,
199
+ stderr: this.stderr,
197
200
  bindings: { ...this.bindings, ...bindings }
198
201
  });
199
202
  }
@@ -213,6 +216,7 @@ var DefaultLogger = class _DefaultLogger {
213
216
  } catch {
214
217
  }
215
218
  }
219
+ if (!this.stderr) return;
216
220
  if (r <= LEVEL_RANK.warn || this.level === "debug" || this.level === "trace") {
217
221
  const head = `${color.dim(ts)} ${COLORS[level](level.toUpperCase().padEnd(5))} ${msg}`;
218
222
  if (ctx !== void 0) {
@@ -331,6 +335,16 @@ function isEmptyMessage(msg) {
331
335
  }
332
336
 
333
337
  // src/storage/session-store.ts
338
+ function sanitizeModel(model) {
339
+ return model.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
340
+ }
341
+ function generateSessionId(startedAt, model) {
342
+ const date = startedAt.slice(0, 10);
343
+ const time = startedAt.slice(11, 19).replace(/:/g, "-");
344
+ const suffix = randomBytes(2).toString("hex");
345
+ const modelPart = model ? `_${sanitizeModel(model)}` : "";
346
+ return `${date}/${time}Z${modelPart}_${suffix}`;
347
+ }
334
348
  var DefaultSessionStore = class {
335
349
  dir;
336
350
  events;
@@ -342,17 +356,23 @@ var DefaultSessionStore = class {
342
356
  }
343
357
  /** Join session ID to its absolute path within the store directory. */
344
358
  sessionPath(id, ext) {
345
- return path16.join(this.dir, `${id}${ext}`);
359
+ return path3.join(this.dir, `${id}${ext}`);
346
360
  }
347
- async ensureShardDir(_id) {
348
- await ensureDir(this.dir);
349
- return this.dir;
361
+ /**
362
+ * Ensure the directory implied by the session ID exists. When the ID
363
+ * contains a date prefix like `2026-06-06/...`, this creates the date
364
+ * subdirectory so sessions group naturally by day.
365
+ */
366
+ async ensureShardDir(id) {
367
+ const dirPath = path3.dirname(path3.join(this.dir, id));
368
+ await ensureDir(dirPath);
369
+ return dirPath;
350
370
  }
351
371
  async create(meta) {
352
372
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
353
- const id = meta.id ?? `${startedAt.replace(/[:.]/g, "-")}-${randomBytes(2).toString("hex")}`;
373
+ const id = meta.id && meta.id.length > 0 ? meta.id : generateSessionId(startedAt, meta.model ?? meta.provider);
354
374
  const shardDir = await this.ensureShardDir(id);
355
- const file = path16.join(shardDir, `${id}.jsonl`);
375
+ const file = path3.join(shardDir, `${path3.basename(id)}.jsonl`);
356
376
  let handle;
357
377
  try {
358
378
  handle = await fsp.open(file, "a", 384);
@@ -445,7 +465,7 @@ var DefaultSessionStore = class {
445
465
  const ids = [];
446
466
  const entries = await fsp.readdir(dir, { withFileTypes: true });
447
467
  for (const entry of entries) {
448
- const full = path16.join(dir, entry.name);
468
+ const full = path3.join(dir, entry.name);
449
469
  if (entry.isDirectory()) {
450
470
  ids.push(...await this.collectSessionIds(full));
451
471
  } else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
@@ -601,7 +621,7 @@ var FileSessionWriter = class {
601
621
  this.meta = meta;
602
622
  this.events = events;
603
623
  this.resumed = opts.resumed ?? false;
604
- this.manifestFile = opts.dir ? path16.join(opts.dir, `${id}.summary.json`) : "";
624
+ this.manifestFile = opts.dir ? path3.join(opts.dir, `${id}.summary.json`) : "";
605
625
  this.filePath = opts.filePath ?? "";
606
626
  this.secretScrubber = opts.secretScrubber;
607
627
  this.summary = {
@@ -883,7 +903,7 @@ init_atomic_write();
883
903
  var QueueStore = class {
884
904
  file;
885
905
  constructor(opts) {
886
- this.file = path16.join(opts.dir, "queue.json");
906
+ this.file = path3.join(opts.dir, "queue.json");
887
907
  }
888
908
  async write(items) {
889
909
  if (items.length === 0) {
@@ -953,7 +973,7 @@ var DefaultAttachmentStore = class {
953
973
  let data = input.data;
954
974
  if (this.spoolDir && bytes >= this.spoolThreshold) {
955
975
  await fsp.mkdir(this.spoolDir, { recursive: true });
956
- spooledPath = path16.join(this.spoolDir, `${id}.bin`);
976
+ spooledPath = path3.join(this.spoolDir, `${id}.bin`);
957
977
  await atomicWrite(spooledPath, input.data, {
958
978
  encoding: input.kind === "image" ? "base64" : "utf8"
959
979
  });
@@ -1141,7 +1161,7 @@ ${body.trim()}`);
1141
1161
  async remember(text, scope = "project-memory") {
1142
1162
  return this.runSerialized(scope, async () => {
1143
1163
  const file = this.files[scope];
1144
- await ensureDir(path16.dirname(file));
1164
+ await ensureDir(path3.dirname(file));
1145
1165
  let existing = "";
1146
1166
  try {
1147
1167
  existing = await fsp.readFile(file, "utf8");
@@ -1479,8 +1499,17 @@ var BEHAVIOR_DEFAULTS = {
1479
1499
  modelsRegistry: true,
1480
1500
  skills: true
1481
1501
  },
1502
+ indexing: {
1503
+ onSessionStart: true,
1504
+ onEdit: true,
1505
+ watchExternal: true,
1506
+ debounceMs: 400
1507
+ },
1482
1508
  session: { ...DEFAULT_SESSION_LOGGING_CONFIG }
1483
1509
  };
1510
+ function envBool(v) {
1511
+ return !/^(0|false|no|off)$/i.test(v.trim());
1512
+ }
1484
1513
  var ENV_MAP = {
1485
1514
  WRONGSTACK_PROVIDER: (c, v) => {
1486
1515
  c.provider = v;
@@ -1505,8 +1534,23 @@ var ENV_MAP = {
1505
1534
  WRONGSTACK_LOG_LEVEL: (c, v) => {
1506
1535
  if (!c.log) c.log = { level: "info" };
1507
1536
  c.log.level = v;
1537
+ },
1538
+ WRONGSTACK_INDEX_ON_START: (c, v) => {
1539
+ c.indexing = { ...defaultIndexing, ...c.indexing, onSessionStart: envBool(v) };
1540
+ },
1541
+ WRONGSTACK_INDEX_ON_EDIT: (c, v) => {
1542
+ c.indexing = { ...defaultIndexing, ...c.indexing, onEdit: envBool(v) };
1543
+ },
1544
+ WRONGSTACK_INDEX_WATCH: (c, v) => {
1545
+ c.indexing = { ...defaultIndexing, ...c.indexing, watchExternal: envBool(v) };
1508
1546
  }
1509
1547
  };
1548
+ var defaultIndexing = {
1549
+ onSessionStart: true,
1550
+ onEdit: true,
1551
+ watchExternal: true,
1552
+ debounceMs: 400
1553
+ };
1510
1554
  function isPrimitiveArray(a) {
1511
1555
  return a.every((v) => v === null || typeof v !== "object");
1512
1556
  }
@@ -1765,7 +1809,7 @@ var RecoveryLock = class {
1765
1809
  sessionStore;
1766
1810
  probe;
1767
1811
  constructor(opts) {
1768
- this.file = path16.join(opts.dir, LOCK_FILE);
1812
+ this.file = path3.join(opts.dir, LOCK_FILE);
1769
1813
  this.pid = opts.pid ?? process.pid;
1770
1814
  this.hostname = opts.hostname ?? os.hostname();
1771
1815
  this.maxAgeMs = opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
@@ -1823,7 +1867,7 @@ var RecoveryLock = class {
1823
1867
  * null return before calling this.
1824
1868
  */
1825
1869
  async write(sessionId) {
1826
- await ensureDir(path16.dirname(this.file));
1870
+ await ensureDir(path3.dirname(this.file));
1827
1871
  const lock = {
1828
1872
  v: 1,
1829
1873
  sessionId,
@@ -2407,7 +2451,7 @@ async function loadTodosCheckpoint(filePath) {
2407
2451
  const parsed = JSON.parse(raw);
2408
2452
  if (parsed?.version !== 1 || !Array.isArray(parsed.todos)) return null;
2409
2453
  return parsed.todos.filter(
2410
- (t) => !!t && typeof t.id === "string" && typeof t.content === "string" && typeof t.status === "string"
2454
+ (t) => !!t && typeof t.id === "string" && typeof t.content === "string" && typeof t.status === "string" && (t.activeForm === void 0 || typeof t.activeForm === "string")
2411
2455
  );
2412
2456
  } catch {
2413
2457
  return null;
@@ -3050,7 +3094,7 @@ var DefaultSecretVault = class {
3050
3094
  } catch (err) {
3051
3095
  if (err.code !== "ENOENT") throw err;
3052
3096
  }
3053
- fs5.mkdirSync(path16.dirname(this.keyFile), { recursive: true });
3097
+ fs5.mkdirSync(path3.dirname(this.keyFile), { recursive: true });
3054
3098
  const key = randomBytes(KEY_BYTES);
3055
3099
  try {
3056
3100
  fs5.writeFileSync(this.keyFile, key, { mode: 384, flag: "wx" });
@@ -3119,7 +3163,7 @@ async function rewriteConfigEncrypted(configPath, vault, patch) {
3119
3163
  }
3120
3164
  const merged = deepMerge2(current, patch ?? {});
3121
3165
  const encrypted = encryptConfigSecrets(merged, vault);
3122
- await fsp.mkdir(path16.dirname(configPath), { recursive: true });
3166
+ await fsp.mkdir(path3.dirname(configPath), { recursive: true });
3123
3167
  await atomicWrite(configPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
3124
3168
  await restrictFilePermissions(configPath);
3125
3169
  }
@@ -3343,9 +3387,9 @@ function getInputString(input, key) {
3343
3387
  function pathLooksInsideProject(rawPath, projectRoot) {
3344
3388
  if (!projectRoot) return false;
3345
3389
  if (rawPath === "~" || rawPath.startsWith("~/") || rawPath.startsWith("~\\")) return false;
3346
- const resolved = path16.resolve(projectRoot, rawPath);
3347
- const relative2 = path16.relative(projectRoot, resolved);
3348
- return !!relative2 && !relative2.startsWith("..") && !path16.isAbsolute(relative2);
3390
+ const resolved = path3.resolve(projectRoot, rawPath);
3391
+ const relative2 = path3.relative(projectRoot, resolved);
3392
+ return !!relative2 && !relative2.startsWith("..") && !path3.isAbsolute(relative2);
3349
3393
  }
3350
3394
  function tokenizeShell(command) {
3351
3395
  return command.match(/"[^"]*"|'[^']*'|\S+/g)?.map((token) => token.replace(/^['"]|['"]$/g, "")) ?? [];
@@ -3355,7 +3399,7 @@ function pathTokenIsOutsideProject(token, projectRoot) {
3355
3399
  if (token === "/" || token === "~" || token === "." || token === "..") return token !== ".";
3356
3400
  if (token.includes("*")) return true;
3357
3401
  if (token.startsWith("..") || token.includes("../") || token.includes("..\\")) return true;
3358
- if (path16.isAbsolute(token) || token.startsWith("~/")) return !pathLooksInsideProject(token, projectRoot);
3402
+ if (path3.isAbsolute(token) || token.startsWith("~/")) return !pathLooksInsideProject(token, projectRoot);
3359
3403
  return false;
3360
3404
  }
3361
3405
  function hasDangerousDeleteTarget(tokens, start, projectRoot) {
@@ -3481,14 +3525,6 @@ var DefaultPermissionPolicy = class {
3481
3525
  getConfirmDestructive() {
3482
3526
  return this.confirmDestructive;
3483
3527
  }
3484
- /** @deprecated Use `setYoloDestructive`. */
3485
- setForceAllYolo(enabled) {
3486
- this.setYoloDestructive(enabled);
3487
- }
3488
- /** @deprecated Use `getYoloDestructive`. */
3489
- getForceAllYolo() {
3490
- return this.getYoloDestructive();
3491
- }
3492
3528
  async reload() {
3493
3529
  try {
3494
3530
  const raw = await fsp.readFile(this.trustFile, "utf8");
@@ -4019,7 +4055,7 @@ var DefaultSkillLoader = class {
4019
4055
  const entries = await fsp.readdir(dir, { withFileTypes: true });
4020
4056
  for (const e of entries) {
4021
4057
  if (!e.isDirectory()) continue;
4022
- const skillFile = path16.join(dir, e.name, "SKILL.md");
4058
+ const skillFile = path3.join(dir, e.name, "SKILL.md");
4023
4059
  try {
4024
4060
  const raw = await fsp.readFile(skillFile, "utf8");
4025
4061
  const meta = parseFrontmatter(raw);
@@ -5832,7 +5868,7 @@ ${errorDetails}`,
5832
5868
  const decision = await this.opts.permissionPolicy.evaluate(tool, use.input, ctx);
5833
5869
  let effectivePermission = decision.permission;
5834
5870
  const policy = this.opts.permissionPolicy;
5835
- const yolo = policy.getYolo?.() === true || policy.getYoloDestructive?.() === true || policy.getForceAllYolo?.() === true;
5871
+ const yolo = policy.getYolo?.() === true || policy.getYoloDestructive?.() === true;
5836
5872
  if (toolDangerousCaps.length > 0 && effectivePermission === "auto" && !yolo) {
5837
5873
  effectivePermission = "confirm";
5838
5874
  }
@@ -6311,8 +6347,8 @@ var AutonomousRunner = class {
6311
6347
  init_atomic_write();
6312
6348
  var MAX_JOURNAL_ENTRIES = 500;
6313
6349
  function goalFilePath(projectRoot) {
6314
- const hash = createHash("sha256").update(path16.resolve(projectRoot)).digest("hex").slice(0, 12);
6315
- return path16.join(os.homedir(), ".wrongstack", "projects", hash, "goal.json");
6350
+ const hash = createHash("sha256").update(path3.resolve(projectRoot)).digest("hex").slice(0, 12);
6351
+ return path3.join(os.homedir(), ".wrongstack", "projects", hash, "goal.json");
6316
6352
  }
6317
6353
  async function loadGoal(filePath) {
6318
6354
  let raw;
@@ -10312,7 +10348,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
10312
10348
  }
10313
10349
  async spawn(subagent) {
10314
10350
  const id = subagent.id || randomUUID();
10315
- subagent = this.withNickname(subagent, id);
10351
+ const cfg = this.withNickname(subagent, id);
10316
10352
  if (this.subagents.has(id)) {
10317
10353
  throw new Error(`Subagent id "${id}" already exists \u2014 refusing to overwrite`);
10318
10354
  }
@@ -10327,12 +10363,12 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
10327
10363
  maxConcurrent: this.config.maxConcurrent ?? 16
10328
10364
  };
10329
10365
  this.subagents.set(id, {
10330
- config: { ...subagent, id },
10366
+ config: { ...cfg, id },
10331
10367
  context,
10332
10368
  status: "idle",
10333
10369
  abortController: new AbortController()
10334
10370
  });
10335
- this.emit("subagent.started", { subagent: { ...subagent, id } });
10371
+ this.emit("subagent.started", { subagent: { ...cfg, id } });
10336
10372
  this.fleetBus?.emit({
10337
10373
  subagentId: id,
10338
10374
  ts: Date.now(),
@@ -11562,7 +11598,8 @@ function isGlob(p) {
11562
11598
  return false;
11563
11599
  }
11564
11600
  function globToRegex(pat) {
11565
- let i = 0, re = "^";
11601
+ let i = 0;
11602
+ let re = "^";
11566
11603
  while (i < pat.length) {
11567
11604
  const c = pat[i];
11568
11605
  if (c === "*") {
@@ -12281,6 +12318,10 @@ A scratchpad shared with the rest of the fleet is mounted at \`${parts.sharedScr
12281
12318
  - Use stable filenames (one file per concern); overwrite instead of appending so the Director sees the latest state.`
12282
12319
  );
12283
12320
  }
12321
+ if (parts.skills && parts.skills.trim().length > 0) {
12322
+ sections.push(`Domain knowledge:
12323
+ ${parts.skills.trim()}`);
12324
+ }
12284
12325
  if (parts.override && parts.override.trim().length > 0) {
12285
12326
  sections.push(parts.override.trim());
12286
12327
  }
@@ -13821,7 +13862,7 @@ var Director = class _Director {
13821
13862
  })),
13822
13863
  usage: this.usage.snapshot()
13823
13864
  };
13824
- await fsp.mkdir(path16.dirname(this.manifestPath), { recursive: true });
13865
+ await fsp.mkdir(path3.dirname(this.manifestPath), { recursive: true });
13825
13866
  await atomicWrite(this.manifestPath, JSON.stringify(manifest, null, 2), { mode: 384 });
13826
13867
  return this.manifestPath;
13827
13868
  }
@@ -14027,7 +14068,7 @@ var Director = class _Director {
14027
14068
  */
14028
14069
  async readSession(subagentId, tail) {
14029
14070
  if (!this.sessionsRoot) return null;
14030
- const filePath = path16.join(this.sessionsRoot, this.directorRunId, `${subagentId}.jsonl`);
14071
+ const filePath = path3.join(this.sessionsRoot, this.directorRunId, `${subagentId}.jsonl`);
14031
14072
  let raw;
14032
14073
  try {
14033
14074
  raw = await fsp.readFile(filePath, "utf8");
@@ -14113,6 +14154,7 @@ var Director = class _Director {
14113
14154
  role: config.prompt,
14114
14155
  task: taskBrief,
14115
14156
  sharedScratchpad: this.sharedScratchpadPath ?? void 0,
14157
+ skills: config.skillContent,
14116
14158
  override: config.systemPromptOverride
14117
14159
  });
14118
14160
  }
@@ -14262,6 +14304,7 @@ function createDelegateTool(opts) {
14262
14304
  if (typeof i.task !== "string" || !i.task.trim()) {
14263
14305
  return { ok: false, error: "`task` is required." };
14264
14306
  }
14307
+ const target = i.role ?? i.name ?? "subagent";
14265
14308
  try {
14266
14309
  let director = await opts.host.ensureDirector();
14267
14310
  if (!director) {
@@ -14322,6 +14365,7 @@ function createDelegateTool(opts) {
14322
14365
  if (!cfg.timeoutMs) {
14323
14366
  cfg.timeoutMs = Math.max(3e4, timeoutMs - SUBAGENT_TIMEOUT_BUFFER_MS);
14324
14367
  }
14368
+ opts.events?.emit("delegate.started", { target, task: i.task });
14325
14369
  const subagentId = await director.spawn(cfg);
14326
14370
  const taskId = await director.assign({
14327
14371
  id: `${randomUUID()}`,
@@ -14356,6 +14400,17 @@ function createDelegateTool(opts) {
14356
14400
  });
14357
14401
  if ("__timeout" in result) {
14358
14402
  const partial2 = await readSubagentPartial(opts, subagentId);
14403
+ opts.events?.emit("delegate.completed", {
14404
+ target,
14405
+ task: i.task,
14406
+ ok: false,
14407
+ status: "host_timeout",
14408
+ summary: `[${target}] timed out \u2014 no result within ${Math.round(timeoutMs / 1e3)}s`,
14409
+ durationMs: timeoutMs,
14410
+ iterations: partial2?.events ?? 0,
14411
+ toolCalls: partial2?.toolUsesObserved ?? 0,
14412
+ subagentId
14413
+ });
14359
14414
  return {
14360
14415
  ok: false,
14361
14416
  stopReason: "host_timeout",
@@ -14372,6 +14427,24 @@ function createDelegateTool(opts) {
14372
14427
  const retryable = result.error?.retryable;
14373
14428
  const backoffMs = result.error?.backoffMs;
14374
14429
  const summary = buildDelegateSummary(i.role, result);
14430
+ let costUsd;
14431
+ try {
14432
+ costUsd = dir.snapshot().perSubagent[result.subagentId]?.cost;
14433
+ } catch {
14434
+ costUsd = void 0;
14435
+ }
14436
+ opts.events?.emit("delegate.completed", {
14437
+ target,
14438
+ task: i.task,
14439
+ ok: result.status === "success",
14440
+ status: result.status,
14441
+ summary,
14442
+ durationMs: result.durationMs,
14443
+ iterations: result.iterations,
14444
+ toolCalls: result.toolCalls,
14445
+ costUsd,
14446
+ subagentId: result.subagentId
14447
+ });
14375
14448
  return {
14376
14449
  ok: result.status === "success",
14377
14450
  status: result.status,
@@ -14393,10 +14466,21 @@ function createDelegateTool(opts) {
14393
14466
  summary
14394
14467
  };
14395
14468
  } catch (err) {
14469
+ const message = err instanceof Error ? err.message : String(err);
14470
+ opts.events?.emit("delegate.completed", {
14471
+ target,
14472
+ task: i.task,
14473
+ ok: false,
14474
+ status: "error",
14475
+ summary: `[${target}] failed \u2014 ${message}`,
14476
+ durationMs: 0,
14477
+ iterations: 0,
14478
+ toolCalls: 0
14479
+ });
14396
14480
  return {
14397
14481
  ok: false,
14398
14482
  stopReason: "error",
14399
- error: err instanceof Error ? err.message : String(err)
14483
+ error: message
14400
14484
  };
14401
14485
  }
14402
14486
  }
@@ -14483,13 +14567,13 @@ async function readSubagentPartial(opts, subagentId) {
14483
14567
  if (!opts.sessionsRoot) return void 0;
14484
14568
  const candidates = [];
14485
14569
  if (opts.directorRunId) {
14486
- candidates.push(path16.join(opts.sessionsRoot, opts.directorRunId, `${subagentId}.jsonl`));
14570
+ candidates.push(path3.join(opts.sessionsRoot, opts.directorRunId, `${subagentId}.jsonl`));
14487
14571
  } else {
14488
14572
  try {
14489
14573
  const entries = await fsp.readdir(opts.sessionsRoot, { withFileTypes: true });
14490
14574
  for (const entry of entries) {
14491
14575
  if (entry.isDirectory()) {
14492
- candidates.push(path16.join(opts.sessionsRoot, entry.name, `${subagentId}.jsonl`));
14576
+ candidates.push(path3.join(opts.sessionsRoot, entry.name, `${subagentId}.jsonl`));
14493
14577
  }
14494
14578
  }
14495
14579
  } catch {
@@ -14536,9 +14620,9 @@ function makeDirectorSessionFactory(opts) {
14536
14620
  let dir;
14537
14621
  if (opts.store) {
14538
14622
  store = opts.store;
14539
- dir = opts.sessionsRoot ? path16.join(opts.sessionsRoot, runId) : "(caller-managed)";
14623
+ dir = opts.sessionsRoot ? path3.join(opts.sessionsRoot, runId) : "(caller-managed)";
14540
14624
  } else if (opts.sessionsRoot) {
14541
- dir = path16.join(opts.sessionsRoot, runId);
14625
+ dir = path3.join(opts.sessionsRoot, runId);
14542
14626
  store = new DefaultSessionStore({ dir });
14543
14627
  } else {
14544
14628
  throw new Error("makeDirectorSessionFactory requires either `store` or `sessionsRoot`");
@@ -14742,7 +14826,7 @@ var DefaultModelsRegistry = class {
14742
14826
  this.overlay = opts.overlay;
14743
14827
  this.overlayUrl = opts.overlayUrl;
14744
14828
  this.overlayFile = opts.overlayFile;
14745
- this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ? path16.join(path16.dirname(opts.cacheFile), "models-overlay-cache.json") : void 0);
14829
+ this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ? path3.join(path3.dirname(opts.cacheFile), "models-overlay-cache.json") : void 0);
14746
14830
  }
14747
14831
  async load(opts = {}) {
14748
14832
  if (this.payload && !opts.force) return this.payload;
@@ -14955,7 +15039,7 @@ var DefaultModelsRegistry = class {
14955
15039
  }
14956
15040
  /** Used by `wstack models refresh` to expose where the cache lives. */
14957
15041
  cacheLocation() {
14958
- return path16.resolve(this.cacheFile);
15042
+ return path3.resolve(this.cacheFile);
14959
15043
  }
14960
15044
  };
14961
15045
  function hasEntries(payload) {
@@ -14989,7 +15073,8 @@ When reviewing code:
14989
15073
  - Verify test coverage for critical paths
14990
15074
  - Ensure naming conventions are followed`,
14991
15075
  tags: ["review", "quality", "security"],
14992
- toolPreferences: ["read", "grep", "git", "diff", "test"]
15076
+ toolPreferences: ["read", "grep", "git", "diff", "test"],
15077
+ suggestedSkills: ["bug-hunter", "security-scanner", "typescript-strict", "testing"]
14993
15078
  },
14994
15079
  {
14995
15080
  id: "code-auditor",
@@ -15006,7 +15091,8 @@ When auditing code for security:
15006
15091
  - Assess input validation and output encoding
15007
15092
  - Look for timing attacks and information leakage`,
15008
15093
  tags: ["security", "audit", "compliance"],
15009
- toolPreferences: ["grep", "read", "audit", "bash"]
15094
+ toolPreferences: ["grep", "read", "audit", "bash"],
15095
+ suggestedSkills: ["security-scanner", "bug-hunter", "audit-log"]
15010
15096
  },
15011
15097
  {
15012
15098
  id: "architect",
@@ -15024,7 +15110,8 @@ When designing or reviewing architecture:
15024
15110
  - Assess API design and contract stability
15025
15111
  - Consider operational aspects (monitoring, logging, deployment)`,
15026
15112
  tags: ["architecture", "design", "scalability"],
15027
- toolPreferences: ["read", "glob", "tree", "diff"]
15113
+ toolPreferences: ["read", "glob", "tree", "diff"],
15114
+ suggestedSkills: ["api-design", "refactor-planner", "node-modern", "docker-deploy"]
15028
15115
  },
15029
15116
  {
15030
15117
  id: "debugger",
@@ -15042,7 +15129,8 @@ When investigating bugs:
15042
15129
  - Use binary search to isolate the root cause
15043
15130
  - Verify fixes with tests before considering done`,
15044
15131
  tags: ["debug", "investigation", "error-resolution"],
15045
- toolPreferences: ["read", "grep", "bash", "logs", "test"]
15132
+ toolPreferences: ["read", "grep", "bash", "logs", "test"],
15133
+ suggestedSkills: ["bug-hunter", "audit-log", "observability"]
15046
15134
  },
15047
15135
  {
15048
15136
  id: "tester",
@@ -15060,7 +15148,8 @@ When testing or writing tests:
15060
15148
  - Check for integration test gaps
15061
15149
  - Verify test isolation and cleanup`,
15062
15150
  tags: ["testing", "qa", "quality"],
15063
- toolPreferences: ["read", "grep", "test", "bash"]
15151
+ toolPreferences: ["read", "grep", "test", "bash"],
15152
+ suggestedSkills: ["testing", "bug-hunter", "typescript-strict"]
15064
15153
  },
15065
15154
  {
15066
15155
  id: "devops",
@@ -15078,7 +15167,8 @@ When working on infrastructure:
15078
15167
  - Assess secrets management
15079
15168
  - Check for resource limits and quotas`,
15080
15169
  tags: ["devops", "infrastructure", "operations"],
15081
- toolPreferences: ["read", "bash", "grep", "logs", "git"]
15170
+ toolPreferences: ["read", "bash", "grep", "logs", "git"],
15171
+ suggestedSkills: ["docker-deploy", "observability", "security-scanner"]
15082
15172
  },
15083
15173
  {
15084
15174
  id: "refactorer",
@@ -15096,7 +15186,8 @@ When refactoring code:
15096
15186
  - Don't mix formatting changes with logic changes
15097
15187
  - Keep performance in mind \u2014 don't regress`,
15098
15188
  tags: ["refactor", "modernization", "improvement"],
15099
- toolPreferences: ["read", "edit", "test", "git", "grep"]
15189
+ toolPreferences: ["read", "edit", "test", "git", "grep"],
15190
+ suggestedSkills: ["refactor-planner", "typescript-strict", "node-modern", "testing"]
15100
15191
  },
15101
15192
  {
15102
15193
  id: "brief",
@@ -15126,7 +15217,8 @@ Get to the point \u2014 read files, run commands, make changes.
15126
15217
  - One-liner sufficient? One liner.
15127
15218
  - Max 3 sentences per paragraph.`,
15128
15219
  tags: ["fast", "concise", "direct"],
15129
- toolPreferences: ["read", "edit", "bash"]
15220
+ toolPreferences: ["read", "edit", "bash"],
15221
+ suggestedSkills: []
15130
15222
  },
15131
15223
  {
15132
15224
  id: "teach",
@@ -15191,7 +15283,8 @@ You follow these principles, but always with explanation:
15191
15283
 
15192
15284
  Remember: your job is to make the user a better developer, not just to complete tasks faster.`,
15193
15285
  tags: ["teaching", "mentor", "learning"],
15194
- toolPreferences: ["read", "edit", "explain"]
15286
+ toolPreferences: ["read", "edit", "explain"],
15287
+ suggestedSkills: ["prompt-engineering", "skill-creator", "node-modern", "typescript-strict"]
15195
15288
  }
15196
15289
  ];
15197
15290
 
@@ -15242,7 +15335,7 @@ var DefaultModeStore = class {
15242
15335
  }
15243
15336
  async loadActiveMode() {
15244
15337
  try {
15245
- const configPath = path16.join(this.configDir, "mode.json");
15338
+ const configPath = path3.join(this.configDir, "mode.json");
15246
15339
  const content = await fsp.readFile(configPath, "utf8");
15247
15340
  const data = JSON.parse(content);
15248
15341
  this.activeModeId = data.activeMode ?? null;
@@ -15253,7 +15346,7 @@ var DefaultModeStore = class {
15253
15346
  async saveActiveMode() {
15254
15347
  try {
15255
15348
  await fsp.mkdir(this.configDir, { recursive: true });
15256
- const configPath = path16.join(this.configDir, "mode.json");
15349
+ const configPath = path3.join(this.configDir, "mode.json");
15257
15350
  await atomicWrite(
15258
15351
  configPath,
15259
15352
  JSON.stringify({ activeMode: this.activeModeId }, null, 2)
@@ -15268,11 +15361,11 @@ async function loadProjectModes(modesDir) {
15268
15361
  const entries = await fsp.readdir(modesDir);
15269
15362
  for (const entry of entries) {
15270
15363
  if (!entry.endsWith(".md") && !entry.endsWith(".txt")) continue;
15271
- const filePath = path16.join(modesDir, entry);
15364
+ const filePath = path3.join(modesDir, entry);
15272
15365
  const stat5 = await fsp.stat(filePath);
15273
15366
  if (!stat5.isFile()) continue;
15274
15367
  const content = await fsp.readFile(filePath, "utf8");
15275
- const id = path16.basename(entry, path16.extname(entry));
15368
+ const id = path3.basename(entry, path3.extname(entry));
15276
15369
  modes.push({
15277
15370
  id,
15278
15371
  name: id.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
@@ -15288,7 +15381,7 @@ async function loadProjectModes(modesDir) {
15288
15381
  async function loadUserModes(modesDir) {
15289
15382
  const modes = [];
15290
15383
  try {
15291
- const manifestPath = path16.join(modesDir, "modes.json");
15384
+ const manifestPath = path3.join(modesDir, "modes.json");
15292
15385
  const content = await fsp.readFile(manifestPath, "utf8");
15293
15386
  const manifest = JSON.parse(content);
15294
15387
  for (const mode of manifest.modes) {
@@ -16205,7 +16298,7 @@ var SpecStore = class {
16205
16298
  indexPath;
16206
16299
  constructor(opts) {
16207
16300
  this.baseDir = opts.baseDir;
16208
- this.indexPath = path16.join(this.baseDir, "_index.json");
16301
+ this.indexPath = path3.join(this.baseDir, "_index.json");
16209
16302
  }
16210
16303
  async save(spec) {
16211
16304
  await ensureDir(this.baseDir);
@@ -16274,7 +16367,7 @@ var SpecStore = class {
16274
16367
  return updated;
16275
16368
  }
16276
16369
  filePath(id) {
16277
- return path16.join(this.baseDir, `${id}.json`);
16370
+ return path3.join(this.baseDir, `${id}.json`);
16278
16371
  }
16279
16372
  async readIndex() {
16280
16373
  try {
@@ -16331,7 +16424,7 @@ var TaskGraphStore = class {
16331
16424
  indexPath;
16332
16425
  constructor(opts) {
16333
16426
  this.baseDir = opts.baseDir;
16334
- this.indexPath = path16.join(this.baseDir, "_index.json");
16427
+ this.indexPath = path3.join(this.baseDir, "_index.json");
16335
16428
  }
16336
16429
  async save(graph) {
16337
16430
  await ensureDir(this.baseDir);
@@ -16369,7 +16462,7 @@ var TaskGraphStore = class {
16369
16462
  }
16370
16463
  }
16371
16464
  filePath(id) {
16372
- return path16.join(this.baseDir, `${id}.json`);
16465
+ return path3.join(this.baseDir, `${id}.json`);
16373
16466
  }
16374
16467
  async readIndex() {
16375
16468
  try {