@wrongstack/core 0.9.0 → 0.9.1

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 (52) hide show
  1. package/dist/{agent-bridge-Bad3ZGQ7.d.ts → agent-bridge-DMVOX0cF.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-Cc8sRJOF.d.ts → agent-subagent-runner-R0I0Xusn.d.ts} +3 -3
  3. package/dist/{compactor-Mw7-rNyb.d.ts → compactor-DVTKL7XD.d.ts} +1 -1
  4. package/dist/{config-Bi4Q0fnz.d.ts → config-DoUAEvXH.d.ts} +8 -2
  5. package/dist/{context-z2x5gv_V.d.ts → context-BRNbHmRM.d.ts} +6 -0
  6. package/dist/coordination/index.d.ts +12 -12
  7. package/dist/coordination/index.js +58 -37
  8. package/dist/coordination/index.js.map +1 -1
  9. package/dist/{default-config-DvRSTELf.d.ts → default-config-Uzla85H-.d.ts} +5 -1
  10. package/dist/defaults/index.d.ts +22 -22
  11. package/dist/defaults/index.js +102 -72
  12. package/dist/defaults/index.js.map +1 -1
  13. package/dist/{events-yCpJD4wa.d.ts → events-CiG9qUM_.d.ts} +1 -1
  14. package/dist/execution/index.d.ts +13 -13
  15. package/dist/execution/index.js.map +1 -1
  16. package/dist/extension/index.d.ts +6 -6
  17. package/dist/{index-SxpnwRlJ.d.ts → index-bOl8lzFV.d.ts} +5 -5
  18. package/dist/{index-Dl3PaD7f.d.ts → index-u2ROAV0F.d.ts} +8 -8
  19. package/dist/index.d.ts +31 -31
  20. package/dist/index.js +72 -42
  21. package/dist/index.js.map +1 -1
  22. package/dist/infrastructure/index.d.ts +6 -6
  23. package/dist/kernel/index.d.ts +9 -9
  24. package/dist/{mcp-servers-n2L9ohMX.d.ts → mcp-servers-jEoMIBZv.d.ts} +3 -3
  25. package/dist/models/index.d.ts +2 -2
  26. package/dist/{multi-agent-C8uY45AY.d.ts → multi-agent-3ZnTB1aT.d.ts} +2 -2
  27. package/dist/{multi-agent-coordinator-C7YbZUY8.d.ts → multi-agent-coordinator-COwCGIrU.d.ts} +2 -2
  28. package/dist/{null-fleet-bus-Bb2jVLKr.d.ts → null-fleet-bus-C1grTnOF.d.ts} +6 -6
  29. package/dist/observability/index.d.ts +2 -2
  30. package/dist/{path-resolver-DnC1nOjb.d.ts → path-resolver-TcJfc29Y.d.ts} +2 -2
  31. package/dist/{permission-policy-BBa1M1xc.d.ts → permission-policy-BpCGYBud.d.ts} +2 -2
  32. package/dist/{plan-templates-Cc-04Z8o.d.ts → plan-templates-ByT1HcRI.d.ts} +9 -4
  33. package/dist/{provider-runner-C4ouU7--.d.ts → provider-runner-BEpikbbN.d.ts} +3 -3
  34. package/dist/{retry-policy-OwtKNxo8.d.ts → retry-policy-BYkq0ugs.d.ts} +1 -1
  35. package/dist/sdd/index.d.ts +8 -8
  36. package/dist/{secret-scrubber-CyE1-EMG.d.ts → secret-scrubber-DttNiGYA.d.ts} +1 -1
  37. package/dist/{secret-scrubber-C0n1EqrC.d.ts → secret-scrubber-QSeI0ADi.d.ts} +1 -1
  38. package/dist/security/index.d.ts +4 -4
  39. package/dist/security/index.js +5 -2
  40. package/dist/security/index.js.map +1 -1
  41. package/dist/{selector-DkvgYVS4.d.ts → selector-pox8abg0.d.ts} +1 -1
  42. package/dist/{session-reader-DsadjyF9.d.ts → session-reader-CSWcb5Ga.d.ts} +1 -1
  43. package/dist/storage/index.d.ts +5 -5
  44. package/dist/storage/index.js +81 -57
  45. package/dist/storage/index.js.map +1 -1
  46. package/dist/{system-prompt-CWA6ml-d.d.ts → system-prompt-Bs-Wliab.d.ts} +1 -1
  47. package/dist/{tool-executor-Ch25BDwa.d.ts → tool-executor-D7a00JVJ.d.ts} +4 -4
  48. package/dist/types/index.d.ts +16 -16
  49. package/dist/types/index.js +8 -2
  50. package/dist/types/index.js.map +1 -1
  51. package/dist/utils/index.d.ts +1 -1
  52. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import { randomBytes, randomUUID, createHash } from 'crypto';
2
2
  import * as fsp from 'fs/promises';
3
- import * as path2 from 'path';
3
+ import * as path7 from 'path';
4
4
  import * as os from 'os';
5
5
 
6
6
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
@@ -10,9 +10,9 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
10
10
  throw Error('Dynamic require of "' + x + '" is not supported');
11
11
  });
12
12
  async function atomicWrite(targetPath, content, opts = {}) {
13
- const dir = path2.dirname(targetPath);
13
+ const dir = path7.dirname(targetPath);
14
14
  await fsp.mkdir(dir, { recursive: true });
15
- const tmp = path2.join(dir, `.${path2.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
15
+ const tmp = path7.join(dir, `.${path7.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
16
16
  try {
17
17
  if (typeof content === "string") {
18
18
  await fsp.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
@@ -174,24 +174,30 @@ var DefaultSessionStore = class {
174
174
  this.dir = opts.dir;
175
175
  this.events = opts.events;
176
176
  }
177
- async create(meta) {
177
+ /** Join session ID to its absolute path within the store directory. */
178
+ sessionPath(id, ext) {
179
+ return path7.join(this.dir, `${id}${ext}`);
180
+ }
181
+ async ensureShardDir(_id) {
178
182
  await ensureDir(this.dir);
183
+ return this.dir;
184
+ }
185
+ async create(meta) {
179
186
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
180
187
  const id = meta.id ?? `${startedAt.replace(/[:.]/g, "-")}-${randomBytes(2).toString("hex")}`;
181
- const file = path2.join(this.dir, `${id}.jsonl`);
188
+ const shardDir = await this.ensureShardDir(id);
189
+ const file = path7.join(shardDir, `${id}.jsonl`);
182
190
  let handle;
183
191
  try {
184
192
  handle = await fsp.open(file, "a", 384);
185
193
  } catch (err) {
186
194
  throw new Error(
187
195
  `Failed to open session file: ${err instanceof Error ? err.message : String(err)}`,
188
- {
189
- cause: err
190
- }
196
+ { cause: err }
191
197
  );
192
198
  }
193
199
  try {
194
- return new FileSessionWriter(id, handle, startedAt, meta, this.events, { dir: this.dir, filePath: file });
200
+ return new FileSessionWriter(id, handle, startedAt, meta, this.events, { dir: shardDir, filePath: file });
195
201
  } catch (err) {
196
202
  await handle.close().catch(() => {
197
203
  });
@@ -199,15 +205,7 @@ var DefaultSessionStore = class {
199
205
  }
200
206
  }
201
207
  async resume(id) {
202
- const file = path2.join(this.dir, `${id}.jsonl`);
203
- try {
204
- await fsp.access(file, fsp.constants.R_OK);
205
- } catch {
206
- throw new Error(
207
- `Session "${id}" not found \u2014 the session file does not exist or was deleted.`,
208
- { cause: new Error("ENOENT") }
209
- );
210
- }
208
+ const file = this.sessionPath(id, ".jsonl");
211
209
  const data = await this.load(id);
212
210
  let handle;
213
211
  try {
@@ -239,7 +237,7 @@ var DefaultSessionStore = class {
239
237
  }
240
238
  }
241
239
  async load(id) {
242
- const file = path2.join(this.dir, `${id}.jsonl`);
240
+ const file = this.sessionPath(id, ".jsonl");
243
241
  const raw = await fsp.readFile(file, "utf8");
244
242
  const lines = raw.split("\n").filter((l) => l.trim());
245
243
  const events = [];
@@ -259,8 +257,7 @@ var DefaultSessionStore = class {
259
257
  async list(limit = 20) {
260
258
  try {
261
259
  await ensureDir(this.dir);
262
- const files = await fsp.readdir(this.dir);
263
- const ids = files.filter((f) => f.endsWith(".jsonl")).map((f) => f.replace(/\.jsonl$/, ""));
260
+ const ids = await this.collectSessionIds(this.dir);
264
261
  const sessions = await Promise.all(ids.map((id) => this.summaryFor(id).catch(() => null)));
265
262
  const out = sessions.filter((s) => s !== null);
266
263
  out.sort((a, b) => {
@@ -273,13 +270,27 @@ var DefaultSessionStore = class {
273
270
  return [];
274
271
  }
275
272
  }
273
+ /** Recursively collect all session IDs from shard subdirectories. */
274
+ async collectSessionIds(dir) {
275
+ const ids = [];
276
+ const entries = await fsp.readdir(dir, { withFileTypes: true });
277
+ for (const entry of entries) {
278
+ const full = path7.join(dir, entry.name);
279
+ if (entry.isDirectory()) {
280
+ ids.push(...await this.collectSessionIds(full));
281
+ } else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
282
+ ids.push(entry.name.replace(/\.jsonl$/, ""));
283
+ }
284
+ }
285
+ return ids;
286
+ }
276
287
  async summaryFor(id) {
277
- const manifest = path2.join(this.dir, `${id}.summary.json`);
288
+ const manifest = this.sessionPath(id, ".summary.json");
278
289
  try {
279
290
  const raw = await fsp.readFile(manifest, "utf8");
280
291
  return JSON.parse(raw);
281
292
  } catch {
282
- const full = path2.join(this.dir, `${id}.jsonl`);
293
+ const full = this.sessionPath(id, ".jsonl");
283
294
  const stat3 = await fsp.stat(full);
284
295
  const summary = await this.summarize(id, stat3.mtime.toISOString());
285
296
  await atomicWrite(manifest, JSON.stringify(summary), { mode: 384 }).catch((err) => {
@@ -292,12 +303,13 @@ var DefaultSessionStore = class {
292
303
  }
293
304
  }
294
305
  async delete(id) {
295
- await fsp.unlink(path2.join(this.dir, `${id}.jsonl`));
296
- await fsp.unlink(path2.join(this.dir, `${id}.summary.json`)).catch(() => void 0);
306
+ await fsp.unlink(this.sessionPath(id, ".jsonl"));
307
+ await fsp.unlink(this.sessionPath(id, ".summary.json")).catch(() => void 0);
297
308
  }
298
309
  async clearHistory(id) {
299
- const file = path2.join(this.dir, `${id}.jsonl`);
300
- const meta = path2.join(this.dir, `${id}.summary.json`);
310
+ await this.ensureShardDir(id);
311
+ const file = this.sessionPath(id, ".jsonl");
312
+ const meta = this.sessionPath(id, ".summary.json");
301
313
  const record = `${JSON.stringify({
302
314
  type: "session_start",
303
315
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -341,7 +353,8 @@ var DefaultSessionStore = class {
341
353
  startedAt: start?.ts ?? (/* @__PURE__ */ new Date(0)).toISOString(),
342
354
  endedAt: end?.ts,
343
355
  model: start?.model,
344
- provider: start?.provider
356
+ provider: start?.provider,
357
+ pendingToolUses: end?.pendingToolUses
345
358
  };
346
359
  }
347
360
  replay(events, sessionId = "unknown") {
@@ -418,7 +431,7 @@ var FileSessionWriter = class {
418
431
  this.meta = meta;
419
432
  this.events = events;
420
433
  this.resumed = opts.resumed ?? false;
421
- this.manifestFile = opts.dir ? path2.join(opts.dir, `${id}.summary.json`) : "";
434
+ this.manifestFile = opts.dir ? path7.join(opts.dir, `${id}.summary.json`) : "";
422
435
  this.filePath = opts.filePath ?? "";
423
436
  this.summary = {
424
437
  id,
@@ -441,9 +454,6 @@ var FileSessionWriter = class {
441
454
  tokenIn = 0;
442
455
  tokenOut = 0;
443
456
  filePath;
444
- /** Public accessor for the JSONL path — required by SessionWriter so
445
- * observability surfaces (`/fleet log`, FleetPanel) can locate the
446
- * transcript without recomputing the path from session metadata. */
447
457
  get transcriptPath() {
448
458
  return this.filePath || void 0;
449
459
  }
@@ -451,13 +461,16 @@ var FileSessionWriter = class {
451
461
  resumed;
452
462
  appendFailCount = 0;
453
463
  lastAppendWarnAt = 0;
454
- // Rewind support: track pending file changes and prompt index
455
464
  promptIndex = 0;
456
465
  pendingFileSnapshots = [];
457
- // Register a pending file change. Call recordFileChange() from tools.
466
+ /** Tracks open tool_use IDs during the current run to serialize on close for resume. */
467
+ openToolUses = /* @__PURE__ */ new Set();
458
468
  recordFileChange(input) {
459
469
  this.pendingFileSnapshots.push(input);
460
470
  }
471
+ get pendingToolUses() {
472
+ return Array.from(this.openToolUses);
473
+ }
461
474
  async writeSessionStartLazy() {
462
475
  const record = `${JSON.stringify({
463
476
  type: this.resumed ? "session_resumed" : "session_start",
@@ -500,13 +513,12 @@ var FileSessionWriter = class {
500
513
  }
501
514
  }
502
515
  }
503
- /**
504
- * Watch events as they're appended and keep the summary state hot, so
505
- * `close()` can flush a `<id>.summary.json` manifest without re-reading
506
- * the JSONL. `list()` reads only manifests, turning a per-session full
507
- * parse into a single stat+read.
508
- */
509
516
  observeForSummary(event) {
517
+ if (event.type === "tool_use") {
518
+ this.openToolUses.add(event.id);
519
+ } else if (event.type === "tool_result") {
520
+ this.openToolUses.delete(event.id);
521
+ }
510
522
  if (event.type === "user_input" && this.summary.title === "(empty session)") {
511
523
  this.summary = { ...this.summary, title: userInputTitle(event.content) };
512
524
  } else if (event.type === "llm_response") {
@@ -600,7 +612,16 @@ var FileSessionWriter = class {
600
612
  }
601
613
  }
602
614
  const truncated = kept.join("\n");
603
- await fsp.writeFile(this.filePath, truncated + "\n", "utf8");
615
+ const tmpPath = `${this.filePath}.rewind.tmp`;
616
+ await fsp.writeFile(tmpPath, truncated + "\n", "utf8");
617
+ try {
618
+ await this.handle.close();
619
+ await fsp.rename(tmpPath, this.filePath);
620
+ this.handle = await fsp.open(this.filePath, "a", 384);
621
+ } catch (err) {
622
+ await fsp.unlink(tmpPath).catch(() => void 0);
623
+ throw err;
624
+ }
604
625
  await this.append({
605
626
  type: "rewound",
606
627
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -634,7 +655,7 @@ function userInputTitle(content) {
634
655
  var QueueStore = class {
635
656
  file;
636
657
  constructor(opts) {
637
- this.file = path2.join(opts.dir, "queue.json");
658
+ this.file = path7.join(opts.dir, "queue.json");
638
659
  }
639
660
  async write(items) {
640
661
  if (items.length === 0) {
@@ -701,7 +722,7 @@ var DefaultAttachmentStore = class {
701
722
  let data = input.data;
702
723
  if (this.spoolDir && bytes >= this.spoolThreshold) {
703
724
  await fsp.mkdir(this.spoolDir, { recursive: true });
704
- spooledPath = path2.join(this.spoolDir, `${id}.bin`);
725
+ spooledPath = path7.join(this.spoolDir, `${id}.bin`);
705
726
  await atomicWrite(spooledPath, input.data, {
706
727
  encoding: input.kind === "image" ? "base64" : "utf8"
707
728
  });
@@ -871,7 +892,7 @@ ${body.trim()}`);
871
892
  async remember(text, scope = "project-memory") {
872
893
  return this.runSerialized(scope, async () => {
873
894
  const file = this.files[scope];
874
- await ensureDir(path2.dirname(file));
895
+ await ensureDir(path7.dirname(file));
875
896
  let existing = "";
876
897
  try {
877
898
  existing = await fsp.readFile(file, "utf8");
@@ -1364,7 +1385,10 @@ var DefaultConfigLoader = class {
1364
1385
  }
1365
1386
  if (c.mode !== void 0 && !isContextWindowModeId(c.mode)) {
1366
1387
  const known = listContextWindowModes().map((m) => m.id).join(", ");
1367
- throw new Error(`Config: context.mode must be one of: ${known}`);
1388
+ console.warn(
1389
+ `[config] Ignoring unknown context.mode "${c.mode}" (expected one of: ${known}); falling back to "${DEFAULT_CONTEXT_WINDOW_MODE_ID}".`
1390
+ );
1391
+ c.mode = DEFAULT_CONTEXT_WINDOW_MODE_ID;
1368
1392
  }
1369
1393
  }
1370
1394
  validateIdentity(cfg) {
@@ -1440,7 +1464,7 @@ var RecoveryLock = class {
1440
1464
  sessionStore;
1441
1465
  probe;
1442
1466
  constructor(opts) {
1443
- this.file = path2.join(opts.dir, LOCK_FILE);
1467
+ this.file = path7.join(opts.dir, LOCK_FILE);
1444
1468
  this.pid = opts.pid ?? process.pid;
1445
1469
  this.hostname = opts.hostname ?? os.hostname();
1446
1470
  this.maxAgeMs = opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
@@ -1498,7 +1522,7 @@ var RecoveryLock = class {
1498
1522
  * null return before calling this.
1499
1523
  */
1500
1524
  async write(sessionId) {
1501
- await ensureDir(path2.dirname(this.file));
1525
+ await ensureDir(path7.dirname(this.file));
1502
1526
  const lock = {
1503
1527
  v: 1,
1504
1528
  sessionId,
@@ -1965,7 +1989,7 @@ var DefaultSessionRewinder = class {
1965
1989
  sessionsDir;
1966
1990
  projectRoot;
1967
1991
  async listCheckpoints(sessionId) {
1968
- const file = path2.join(this.sessionsDir, `${sessionId}.jsonl`);
1992
+ const file = path7.join(this.sessionsDir, `${sessionId}.jsonl`);
1969
1993
  const raw = await fsp.readFile(file, "utf8");
1970
1994
  const events = parseEvents(raw);
1971
1995
  const fileCountMap = /* @__PURE__ */ new Map();
@@ -1990,7 +2014,7 @@ var DefaultSessionRewinder = class {
1990
2014
  return checkpoints;
1991
2015
  }
1992
2016
  async rewindToCheckpoint(sessionId, checkpointIndex) {
1993
- const file = path2.join(this.sessionsDir, `${sessionId}.jsonl`);
2017
+ const file = path7.join(this.sessionsDir, `${sessionId}.jsonl`);
1994
2018
  const raw = await fsp.readFile(file, "utf8");
1995
2019
  const events = parseEvents(raw);
1996
2020
  let targetIdx = -1;
@@ -2025,7 +2049,7 @@ var DefaultSessionRewinder = class {
2025
2049
  return { ...result, toPromptIndex: checkpointIndex, removedEvents };
2026
2050
  }
2027
2051
  async rewindLastN(sessionId, n) {
2028
- const file = path2.join(this.sessionsDir, `${sessionId}.jsonl`);
2052
+ const file = path7.join(this.sessionsDir, `${sessionId}.jsonl`);
2029
2053
  const raw = await fsp.readFile(file, "utf8");
2030
2054
  const events = parseEvents(raw);
2031
2055
  const checkpoints = [];
@@ -2054,7 +2078,7 @@ var DefaultSessionRewinder = class {
2054
2078
  return { ...result, toPromptIndex: targetIndex, removedEvents: snapshotsToRevert.length };
2055
2079
  }
2056
2080
  async rewindToStart(sessionId) {
2057
- const file = path2.join(this.sessionsDir, `${sessionId}.jsonl`);
2081
+ const file = path7.join(this.sessionsDir, `${sessionId}.jsonl`);
2058
2082
  const raw = await fsp.readFile(file, "utf8");
2059
2083
  const events = parseEvents(raw);
2060
2084
  const allSnapshots = [];
@@ -2090,10 +2114,10 @@ async function revertSnapshots(snapshots, projectRoot) {
2090
2114
  for (const snapshot of snapshots) {
2091
2115
  for (const file of snapshot.files) {
2092
2116
  try {
2093
- const absPath = path2.resolve(file.path);
2094
- const root = path2.resolve(projectRoot);
2095
- const rel = path2.relative(root, absPath);
2096
- if (rel.startsWith("..") || path2.isAbsolute(rel)) {
2117
+ const absPath = path7.resolve(file.path);
2118
+ const root = path7.resolve(projectRoot);
2119
+ const rel = path7.relative(root, absPath);
2120
+ if (rel.startsWith("..") || path7.isAbsolute(rel)) {
2097
2121
  errors.push(`${file.path}: path resolves outside project root \u2014 skipping`);
2098
2122
  continue;
2099
2123
  }
@@ -2652,8 +2676,8 @@ var FsError = class extends WrongStackError {
2652
2676
  // src/storage/goal-store.ts
2653
2677
  var MAX_JOURNAL_ENTRIES = 500;
2654
2678
  function goalFilePath(projectRoot) {
2655
- const hash = createHash("sha256").update(path2.resolve(projectRoot)).digest("hex").slice(0, 12);
2656
- return path2.join(os.homedir(), ".wrongstack", "projects", hash, "goal.json");
2679
+ const hash = createHash("sha256").update(path7.resolve(projectRoot)).digest("hex").slice(0, 12);
2680
+ return path7.join(os.homedir(), ".wrongstack", "projects", hash, "goal.json");
2657
2681
  }
2658
2682
  async function loadGoal(filePath) {
2659
2683
  let raw;