@wrongstack/core 0.9.19 → 0.9.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/{agent-bridge-DMVOX0cF.d.ts → agent-bridge-Dti3KXGk.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-C4qt9e5Y.d.ts → agent-subagent-runner-U-rs7kk7.d.ts} +3 -4
  3. package/dist/compactor-D7X96RLZ.d.ts +41 -0
  4. package/dist/{config-CWva0qoL.d.ts → config-CLXMDOSs.d.ts} +1 -1
  5. package/dist/{context-BRNbHmRM.d.ts → context-zkZeILpr.d.ts} +46 -0
  6. package/dist/coordination/index.d.ts +13 -13
  7. package/dist/coordination/index.js +660 -146
  8. package/dist/coordination/index.js.map +1 -1
  9. package/dist/defaults/index.d.ts +20 -20
  10. package/dist/defaults/index.js +918 -350
  11. package/dist/defaults/index.js.map +1 -1
  12. package/dist/{events-CiG9qUM_.d.ts → events-DH-9r-_C.d.ts} +42 -1
  13. package/dist/execution/index.d.ts +41 -30
  14. package/dist/execution/index.js +358 -112
  15. package/dist/execution/index.js.map +1 -1
  16. package/dist/extension/index.d.ts +6 -6
  17. package/dist/extension/index.js.map +1 -1
  18. package/dist/{index-aizK8olO.d.ts → index-BIHJ4uII.d.ts} +11 -8
  19. package/dist/{index-p95HQ22A.d.ts → index-CFO9QmJo.d.ts} +8 -8
  20. package/dist/index.d.ts +311 -35
  21. package/dist/index.js +1933 -512
  22. package/dist/index.js.map +1 -1
  23. package/dist/infrastructure/index.d.ts +6 -6
  24. package/dist/infrastructure/index.js +36 -0
  25. package/dist/infrastructure/index.js.map +1 -1
  26. package/dist/kernel/index.d.ts +9 -9
  27. package/dist/kernel/index.js.map +1 -1
  28. package/dist/{mcp-servers-BkVEqkRe.d.ts → mcp-servers-DkESgh0G.d.ts} +25 -3
  29. package/dist/models/index.d.ts +2 -2
  30. package/dist/models/index.js +1 -1
  31. package/dist/models/index.js.map +1 -1
  32. package/dist/{multi-agent-3ZnTB1aT.d.ts → multi-agent-DNp6lAzg.d.ts} +35 -23
  33. package/dist/{multi-agent-coordinator-bRaI_aD1.d.ts → multi-agent-coordinator-CAhsegPz.d.ts} +20 -2
  34. package/dist/{null-fleet-bus-DKM3Iy9d.d.ts → null-fleet-bus-Dnl19vmf.d.ts} +411 -110
  35. package/dist/observability/index.d.ts +2 -2
  36. package/dist/{path-resolver-TcJfc29Y.d.ts → path-resolver-CHiBL0DD.d.ts} +2 -2
  37. package/dist/{permission-bPuzAy4x.d.ts → permission-H35s9Evv.d.ts} +1 -1
  38. package/dist/{permission-policy-BUQSutpl.d.ts → permission-policy-CT-nRmTn.d.ts} +2 -2
  39. package/dist/{plan-templates-fkQTyz3U.d.ts → plan-templates-Bs8iRwi6.d.ts} +4 -4
  40. package/dist/{provider-runner-BEpikbbN.d.ts → provider-runner-BZdDrWrS.d.ts} +3 -3
  41. package/dist/{retry-policy-BYkq0ugs.d.ts → retry-policy-J9N_PM40.d.ts} +1 -1
  42. package/dist/sdd/index.d.ts +9 -10
  43. package/dist/sdd/index.js +224 -68
  44. package/dist/sdd/index.js.map +1 -1
  45. package/dist/security/index.d.ts +3 -3
  46. package/dist/{selector-pox8abg0.d.ts → selector-CFTh3Z6p.d.ts} +1 -1
  47. package/dist/{session-reader-CSWcb5Ga.d.ts → session-reader-C7JJlxOw.d.ts} +2 -2
  48. package/dist/skills/index.d.ts +1 -1
  49. package/dist/skills/index.js +1 -1
  50. package/dist/skills/index.js.map +1 -1
  51. package/dist/storage/index.d.ts +390 -6
  52. package/dist/storage/index.js +672 -35
  53. package/dist/storage/index.js.map +1 -1
  54. package/dist/{system-prompt-Bs-Wliab.d.ts → system-prompt-CneIxVip.d.ts} +1 -1
  55. package/dist/{tool-executor-Boo3dekH.d.ts → tool-executor-flTuxsqO.d.ts} +9 -4
  56. package/dist/types/index.d.ts +14 -14
  57. package/dist/types/index.js +60 -0
  58. package/dist/types/index.js.map +1 -1
  59. package/dist/utils/index.d.ts +18 -6
  60. package/dist/utils/index.js +61 -56
  61. package/dist/utils/index.js.map +1 -1
  62. package/package.json +1 -1
  63. package/dist/compactor-DVTKL7XD.d.ts +0 -23
@@ -1,6 +1,6 @@
1
1
  import { randomBytes, randomUUID, createHash } from 'crypto';
2
2
  import * as fsp from 'fs/promises';
3
- import * as path7 from 'path';
3
+ import * as path11 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 = path7.dirname(targetPath);
13
+ const dir = path11.dirname(targetPath);
14
14
  await fsp.mkdir(dir, { recursive: true });
15
- const tmp = path7.join(dir, `.${path7.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
15
+ const tmp = path11.join(dir, `.${path11.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" });
@@ -178,7 +178,7 @@ var DefaultSessionStore = class {
178
178
  }
179
179
  /** Join session ID to its absolute path within the store directory. */
180
180
  sessionPath(id, ext) {
181
- return path7.join(this.dir, `${id}${ext}`);
181
+ return path11.join(this.dir, `${id}${ext}`);
182
182
  }
183
183
  async ensureShardDir(_id) {
184
184
  await ensureDir(this.dir);
@@ -188,7 +188,7 @@ var DefaultSessionStore = class {
188
188
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
189
189
  const id = meta.id ?? `${startedAt.replace(/[:.]/g, "-")}-${randomBytes(2).toString("hex")}`;
190
190
  const shardDir = await this.ensureShardDir(id);
191
- const file = path7.join(shardDir, `${id}.jsonl`);
191
+ const file = path11.join(shardDir, `${id}.jsonl`);
192
192
  let handle;
193
193
  try {
194
194
  handle = await fsp.open(file, "a", 384);
@@ -281,7 +281,7 @@ var DefaultSessionStore = class {
281
281
  const ids = [];
282
282
  const entries = await fsp.readdir(dir, { withFileTypes: true });
283
283
  for (const entry of entries) {
284
- const full = path7.join(dir, entry.name);
284
+ const full = path11.join(dir, entry.name);
285
285
  if (entry.isDirectory()) {
286
286
  ids.push(...await this.collectSessionIds(full));
287
287
  } else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
@@ -437,7 +437,7 @@ var FileSessionWriter = class {
437
437
  this.meta = meta;
438
438
  this.events = events;
439
439
  this.resumed = opts.resumed ?? false;
440
- this.manifestFile = opts.dir ? path7.join(opts.dir, `${id}.summary.json`) : "";
440
+ this.manifestFile = opts.dir ? path11.join(opts.dir, `${id}.summary.json`) : "";
441
441
  this.filePath = opts.filePath ?? "";
442
442
  this.secretScrubber = opts.secretScrubber;
443
443
  this.summary = {
@@ -491,7 +491,6 @@ var FileSessionWriter = class {
491
491
  }
492
492
  return event;
493
493
  }
494
- promptIndex = 0;
495
494
  pendingFileSnapshots = [];
496
495
  /** Tracks open tool_use IDs during the current run to serialize on close for resume. */
497
496
  openToolUses = /* @__PURE__ */ new Set();
@@ -582,7 +581,6 @@ var FileSessionWriter = class {
582
581
  await this.writeFileSnapshot(promptIndex, [...this.pendingFileSnapshots]);
583
582
  this.pendingFileSnapshots = [];
584
583
  }
585
- this.promptIndex = promptIndex + 1;
586
584
  await this.append({
587
585
  type: "checkpoint",
588
586
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -678,6 +676,38 @@ var FileSessionWriter = class {
678
676
  `;
679
677
  await fsp.writeFile(this.filePath, record, "utf8");
680
678
  }
679
+ /**
680
+ * Idea #1 — write an in-flight marker. The agent loop should call
681
+ * this at the start of each long-running operation; a matching
682
+ * `clearInFlightMarker` follows on clean exit. A stale marker
683
+ * (no end) is what `SessionRecovery.detectStale` looks for.
684
+ */
685
+ async writeInFlightMarker(context) {
686
+ if (!context || context.length > 500) {
687
+ throw new Error("In-flight context must be 1..500 chars");
688
+ }
689
+ await this.append({
690
+ type: "in_flight_start",
691
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
692
+ context
693
+ });
694
+ this.events?.emit("in_flight.started", { context, ts: (/* @__PURE__ */ new Date()).toISOString() });
695
+ }
696
+ /**
697
+ * Idea #1 — close the in-flight marker. Idempotent in spirit
698
+ * (you can call it after a successful iteration even if you
699
+ * didn't open one this round) — but the session log records
700
+ * every call so postmortem tooling can see "the agent finished
701
+ * cleanly X times, then died without finishing Y".
702
+ */
703
+ async clearInFlightMarker(reason) {
704
+ await this.append({
705
+ type: "in_flight_end",
706
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
707
+ reason
708
+ });
709
+ this.events?.emit("in_flight.ended", { reason, ts: (/* @__PURE__ */ new Date()).toISOString() });
710
+ }
681
711
  };
682
712
  function userInputTitle(content) {
683
713
  const text = typeof content === "string" ? content : content.filter((b) => b.type === "text").map((b) => b.text).join(" ");
@@ -686,7 +716,7 @@ function userInputTitle(content) {
686
716
  var QueueStore = class {
687
717
  file;
688
718
  constructor(opts) {
689
- this.file = path7.join(opts.dir, "queue.json");
719
+ this.file = path11.join(opts.dir, "queue.json");
690
720
  }
691
721
  async write(items) {
692
722
  if (items.length === 0) {
@@ -753,7 +783,7 @@ var DefaultAttachmentStore = class {
753
783
  let data = input.data;
754
784
  if (this.spoolDir && bytes >= this.spoolThreshold) {
755
785
  await fsp.mkdir(this.spoolDir, { recursive: true });
756
- spooledPath = path7.join(this.spoolDir, `${id}.bin`);
786
+ spooledPath = path11.join(this.spoolDir, `${id}.bin`);
757
787
  await atomicWrite(spooledPath, input.data, {
758
788
  encoding: input.kind === "image" ? "base64" : "utf8"
759
789
  });
@@ -923,7 +953,7 @@ ${body.trim()}`);
923
953
  async remember(text, scope = "project-memory") {
924
954
  return this.runSerialized(scope, async () => {
925
955
  const file = this.files[scope];
926
- await ensureDir(path7.dirname(file));
956
+ await ensureDir(path11.dirname(file));
927
957
  let existing = "";
928
958
  try {
929
959
  existing = await fsp.readFile(file, "utf8");
@@ -1529,7 +1559,7 @@ var RecoveryLock = class {
1529
1559
  sessionStore;
1530
1560
  probe;
1531
1561
  constructor(opts) {
1532
- this.file = path7.join(opts.dir, LOCK_FILE);
1562
+ this.file = path11.join(opts.dir, LOCK_FILE);
1533
1563
  this.pid = opts.pid ?? process.pid;
1534
1564
  this.hostname = opts.hostname ?? os.hostname();
1535
1565
  this.maxAgeMs = opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
@@ -1587,7 +1617,7 @@ var RecoveryLock = class {
1587
1617
  * null return before calling this.
1588
1618
  */
1589
1619
  async write(sessionId) {
1590
- await ensureDir(path7.dirname(this.file));
1620
+ await ensureDir(path11.dirname(this.file));
1591
1621
  const lock = {
1592
1622
  v: 1,
1593
1623
  sessionId,
@@ -1949,6 +1979,613 @@ function renderPlainText(meta, events) {
1949
1979
  }
1950
1980
  return lines.join("\n");
1951
1981
  }
1982
+ var FILE_VERSION = 1;
1983
+ var MAX_TEXT_LENGTH = 2e3;
1984
+ var MAX_ANNOTATIONS = 1e3;
1985
+ var AnnotationsStore = class {
1986
+ dir;
1987
+ /** Per-session write queue. Created lazily on first add. */
1988
+ writeChains = /* @__PURE__ */ new Map();
1989
+ constructor(opts) {
1990
+ this.dir = opts.dir;
1991
+ }
1992
+ // ── Reads ──────────────────────────────────────────────────────────────
1993
+ /**
1994
+ * Return all annotations for `sessionId` in insertion order
1995
+ * (oldest first). Returns an empty array when no file exists
1996
+ * yet (the normal case for a fresh session).
1997
+ */
1998
+ async list(sessionId) {
1999
+ const file = await this.readFile(sessionId);
2000
+ return file ? file.annotations : [];
2001
+ }
2002
+ /**
2003
+ * Convenience: only unresolved annotations, newest first — the
2004
+ * common UI rendering for "what still needs attention?".
2005
+ */
2006
+ async listOpen(sessionId) {
2007
+ const all = await this.list(sessionId);
2008
+ return all.filter((a) => !a.resolved).reverse();
2009
+ }
2010
+ // ── Writes ─────────────────────────────────────────────────────────────
2011
+ /**
2012
+ * Add a new annotation. Returns the persisted record (with id
2013
+ * and timestamps filled in). Throws when `text` is empty or
2014
+ * exceeds `MAX_TEXT_LENGTH`.
2015
+ */
2016
+ async add(input) {
2017
+ const text = input.text.trim();
2018
+ if (text.length === 0) {
2019
+ throw new Error("Annotation text must be non-empty");
2020
+ }
2021
+ if (text.length > MAX_TEXT_LENGTH) {
2022
+ throw new Error(
2023
+ `Annotation text exceeds ${MAX_TEXT_LENGTH} chars (got ${text.length})`
2024
+ );
2025
+ }
2026
+ if (!Number.isInteger(input.atEventIndex) || input.atEventIndex < 0) {
2027
+ throw new Error("atEventIndex must be a non-negative integer");
2028
+ }
2029
+ const annotation = {
2030
+ id: randomUUID(),
2031
+ sessionId: input.sessionId,
2032
+ atEventIndex: input.atEventIndex,
2033
+ authorId: input.authorId,
2034
+ authorRole: "annotator",
2035
+ text,
2036
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2037
+ resolved: false
2038
+ };
2039
+ await this.enqueue(input.sessionId, async () => {
2040
+ const all = await this.list(input.sessionId);
2041
+ all.push(annotation);
2042
+ if (all.length > MAX_ANNOTATIONS) {
2043
+ const sorted = all.map((a, i) => ({ a, i })).sort((x, y) => {
2044
+ if (x.a.resolved !== y.a.resolved) return x.a.resolved ? 1 : -1;
2045
+ return x.a.createdAt.localeCompare(y.a.createdAt);
2046
+ });
2047
+ const evictCount = all.length - MAX_ANNOTATIONS;
2048
+ const toEvict = new Set(sorted.slice(0, evictCount).map((s) => s.a.id));
2049
+ const kept = all.filter((a) => !toEvict.has(a.id));
2050
+ await this.writeFile(input.sessionId, { version: FILE_VERSION, annotations: kept });
2051
+ } else {
2052
+ await this.writeFile(input.sessionId, { version: FILE_VERSION, annotations: all });
2053
+ }
2054
+ });
2055
+ return annotation;
2056
+ }
2057
+ /**
2058
+ * Mark an annotation as resolved. Returns the updated record, or
2059
+ * `null` if no annotation with that id exists in this session.
2060
+ * Idempotent: resolving an already-resolved annotation refreshes
2061
+ * `resolvedAt` / `resolvedBy` to the latest call.
2062
+ */
2063
+ async resolve(input) {
2064
+ let updated = null;
2065
+ await this.enqueue(input.sessionId, async () => {
2066
+ const all = await this.list(input.sessionId);
2067
+ const idx = all.findIndex((a) => a.id === input.annotationId);
2068
+ if (idx === -1) {
2069
+ updated = null;
2070
+ return;
2071
+ }
2072
+ const next = {
2073
+ ...all[idx],
2074
+ resolved: true,
2075
+ resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
2076
+ resolvedBy: input.resolvedBy
2077
+ };
2078
+ all[idx] = next;
2079
+ await this.writeFile(input.sessionId, { version: FILE_VERSION, annotations: all });
2080
+ updated = next;
2081
+ });
2082
+ return updated;
2083
+ }
2084
+ // ── Internals ──────────────────────────────────────────────────────────
2085
+ filePath(sessionId) {
2086
+ if (!sessionId || sessionId.includes("/") || sessionId.includes("\\") || sessionId.includes("..")) {
2087
+ throw new Error(`Invalid sessionId: ${sessionId}`);
2088
+ }
2089
+ return path11.join(this.dir, `${sessionId}.annotations.json`);
2090
+ }
2091
+ async readFile(sessionId) {
2092
+ const fp = this.filePath(sessionId);
2093
+ try {
2094
+ const raw = await fsp.readFile(fp, "utf8");
2095
+ const parsed = JSON.parse(raw);
2096
+ if (parsed.version !== FILE_VERSION) {
2097
+ return { version: FILE_VERSION, annotations: [] };
2098
+ }
2099
+ return parsed;
2100
+ } catch (err) {
2101
+ if (err.code === "ENOENT") return null;
2102
+ return { version: FILE_VERSION, annotations: [] };
2103
+ }
2104
+ }
2105
+ async writeFile(sessionId, file) {
2106
+ const fp = this.filePath(sessionId);
2107
+ await atomicWrite(fp, JSON.stringify(file, null, 2));
2108
+ }
2109
+ /**
2110
+ * Serialize writes per-sessionId. We chain promises instead of
2111
+ * using a Mutex class so the contract is obvious from the
2112
+ * call-site: `enqueue(sid, fn)` runs `fn` after every prior
2113
+ * enqueue for `sid` has settled.
2114
+ */
2115
+ enqueue(sessionId, fn) {
2116
+ const prev = this.writeChains.get(sessionId) ?? Promise.resolve();
2117
+ const next = prev.then(fn, fn);
2118
+ this.writeChains.set(
2119
+ sessionId,
2120
+ next.catch(() => void 0)
2121
+ );
2122
+ return next;
2123
+ }
2124
+ };
2125
+ function stableStringify(value) {
2126
+ return JSON.stringify(sortKeys(value));
2127
+ }
2128
+ function sortKeys(value) {
2129
+ if (Array.isArray(value)) return value.map(sortKeys);
2130
+ if (value && typeof value === "object") {
2131
+ const obj = value;
2132
+ const sorted = {};
2133
+ for (const key of Object.keys(obj).sort()) {
2134
+ sorted[key] = sortKeys(obj[key]);
2135
+ }
2136
+ return sorted;
2137
+ }
2138
+ return value;
2139
+ }
2140
+ function hashRequest(request) {
2141
+ const payload = {
2142
+ model: request.model,
2143
+ system: request.system,
2144
+ messages: request.messages,
2145
+ tools: request.tools,
2146
+ maxTokens: request.maxTokens,
2147
+ temperature: request.temperature,
2148
+ topP: request.topP,
2149
+ stopSequences: request.stopSequences,
2150
+ toolChoice: request.toolChoice
2151
+ };
2152
+ const json = stableStringify(payload);
2153
+ const digest = createHash("sha256").update(json, "utf8").digest("hex");
2154
+ return `sha256:${digest}`;
2155
+ }
2156
+ var DEFAULT_MAX_ENTRIES = 1e3;
2157
+ var ReplayLogStore = class {
2158
+ dir;
2159
+ writeChains = /* @__PURE__ */ new Map();
2160
+ /** Per-session hash → entry index, kept in memory after the first load. */
2161
+ cache = /* @__PURE__ */ new Map();
2162
+ maxEntries;
2163
+ constructor(opts) {
2164
+ this.dir = opts.dir;
2165
+ this.maxEntries = opts.maxEntries ?? DEFAULT_MAX_ENTRIES;
2166
+ }
2167
+ // ── Writes ──────────────────────────────────────────────────────────────
2168
+ /**
2169
+ * Record a request/response pair. Idempotent on hash: a second
2170
+ * `record` for the same hash is a no-op (the existing entry wins).
2171
+ * Returns the hash.
2172
+ */
2173
+ async record(input) {
2174
+ const hash = hashRequest(input.request);
2175
+ await this.enqueue(input.sessionId, async () => {
2176
+ const cache = await this.ensureCache(input.sessionId);
2177
+ if (cache.has(hash)) return;
2178
+ const entry = {
2179
+ hash,
2180
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
2181
+ request: input.request,
2182
+ response: input.response
2183
+ };
2184
+ let all = [...cache.values(), entry];
2185
+ if (all.length > this.maxEntries) {
2186
+ const evictCount = all.length - this.maxEntries;
2187
+ all = all.slice(evictCount);
2188
+ }
2189
+ await this.writeAll(input.sessionId, all);
2190
+ cache.clear();
2191
+ for (const e of all) cache.set(e.hash, e);
2192
+ });
2193
+ return hash;
2194
+ }
2195
+ // ── Reads ───────────────────────────────────────────────────────────────
2196
+ /**
2197
+ * Look up an entry by hash. Returns `null` when the request has
2198
+ * not been recorded for this session. O(1) after the first call
2199
+ * per session (in-memory cache).
2200
+ */
2201
+ async lookup(sessionId, hash) {
2202
+ const cache = await this.ensureCache(sessionId);
2203
+ return cache.get(hash) ?? null;
2204
+ }
2205
+ /** All recorded entries for a session, in insertion order. */
2206
+ async load(sessionId) {
2207
+ const cache = await this.ensureCache(sessionId);
2208
+ return [...cache.values()];
2209
+ }
2210
+ /**
2211
+ * List every session id that has a replay log in the store dir.
2212
+ * Returns an array of `{ sessionId, entryCount, path }` sorted
2213
+ * by sessionId for stable output. Used by `wstack replay --list`.
2214
+ */
2215
+ async list() {
2216
+ let entries;
2217
+ try {
2218
+ entries = await fsp.readdir(this.dir);
2219
+ } catch (err) {
2220
+ if (err.code === "ENOENT") return [];
2221
+ return [];
2222
+ }
2223
+ const out = [];
2224
+ for (const name of entries) {
2225
+ if (!name.endsWith(".replay.jsonl")) continue;
2226
+ const sessionId = name.slice(0, -".replay.jsonl".length);
2227
+ const all = await this.load(sessionId);
2228
+ out.push({
2229
+ sessionId,
2230
+ entryCount: all.length,
2231
+ path: path11.join(this.dir, name)
2232
+ });
2233
+ }
2234
+ return out.sort((a, b) => a.sessionId.localeCompare(b.sessionId));
2235
+ }
2236
+ // ── Internals ───────────────────────────────────────────────────────────
2237
+ filePath(sessionId) {
2238
+ if (!sessionId || sessionId.includes("/") || sessionId.includes("\\") || sessionId.includes("..")) {
2239
+ throw new Error(`Invalid sessionId: ${sessionId}`);
2240
+ }
2241
+ return path11.join(this.dir, `${sessionId}.replay.jsonl`);
2242
+ }
2243
+ async readAll(sessionId) {
2244
+ const fp = this.filePath(sessionId);
2245
+ try {
2246
+ const raw = await fsp.readFile(fp, "utf8");
2247
+ const out = [];
2248
+ for (const line of raw.split("\n")) {
2249
+ if (!line.trim()) continue;
2250
+ try {
2251
+ const parsed = JSON.parse(line);
2252
+ if ("entry" in parsed && parsed.entry) {
2253
+ out.push(parsed.entry);
2254
+ } else {
2255
+ out.push(parsed);
2256
+ }
2257
+ } catch {
2258
+ }
2259
+ }
2260
+ return out;
2261
+ } catch (err) {
2262
+ if (err.code === "ENOENT") return [];
2263
+ return [];
2264
+ }
2265
+ }
2266
+ async writeAll(sessionId, entries) {
2267
+ const fp = this.filePath(sessionId);
2268
+ const body = entries.map((e) => JSON.stringify(e)).join("\n") + (entries.length ? "\n" : "");
2269
+ await atomicWrite(fp, body);
2270
+ }
2271
+ async ensureCache(sessionId) {
2272
+ let cache = this.cache.get(sessionId);
2273
+ if (cache) return cache;
2274
+ const all = await this.readAll(sessionId);
2275
+ cache = /* @__PURE__ */ new Map();
2276
+ for (const e of all) cache.set(e.hash, e);
2277
+ this.cache.set(sessionId, cache);
2278
+ return cache;
2279
+ }
2280
+ enqueue(sessionId, fn) {
2281
+ const prev = this.writeChains.get(sessionId) ?? Promise.resolve();
2282
+ const next = prev.then(fn, fn);
2283
+ this.writeChains.set(
2284
+ sessionId,
2285
+ next.catch(() => void 0)
2286
+ );
2287
+ return next;
2288
+ }
2289
+ };
2290
+ var SessionRecovery = class {
2291
+ constructor(dir) {
2292
+ this.dir = dir;
2293
+ }
2294
+ dir;
2295
+ /**
2296
+ * Scan a session log and return a `StaleSession` if and only
2297
+ * if the last event is an `in_flight_start` without a matching
2298
+ * `in_flight_end`. Returns `null` when:
2299
+ * - the log does not exist;
2300
+ * - the log is empty;
2301
+ * - the last event is `in_flight_end` (clean shutdown);
2302
+ * - the last event is something else (e.g. an unannotated
2303
+ * legacy log without in-flight markers).
2304
+ */
2305
+ async detectStale(sessionId) {
2306
+ const fp = this.filePath(sessionId);
2307
+ let raw;
2308
+ try {
2309
+ raw = await fsp.readFile(fp, "utf8");
2310
+ } catch (err) {
2311
+ if (err.code === "ENOENT") return null;
2312
+ return null;
2313
+ }
2314
+ return this.parseForStale(sessionId, fp, raw);
2315
+ }
2316
+ /**
2317
+ * Generate a recovery plan for a session. The plan describes
2318
+ * "what would be re-executed" if the user chose to resume —
2319
+ * everything after the last `checkpoint` event, plus the
2320
+ * dangling in-flight marker if present.
2321
+ *
2322
+ * Returns a non-null plan for ANY session that has at least
2323
+ * one event after a checkpoint (or, for legacy sessions, at
2324
+ * least one event). Pure read; no mutation.
2325
+ */
2326
+ async recover(sessionId) {
2327
+ const fp = this.filePath(sessionId);
2328
+ let raw;
2329
+ try {
2330
+ raw = await fsp.readFile(fp, "utf8");
2331
+ } catch (err) {
2332
+ if (err.code === "ENOENT") return null;
2333
+ return null;
2334
+ }
2335
+ const events = [];
2336
+ for (const line of raw.split("\n")) {
2337
+ if (!line.trim()) continue;
2338
+ try {
2339
+ events.push(JSON.parse(line));
2340
+ } catch {
2341
+ }
2342
+ }
2343
+ if (events.length === 0) return null;
2344
+ let lastCheckpoint = null;
2345
+ let lastCheckpointIdx = -1;
2346
+ for (let i = 0; i < events.length; i++) {
2347
+ if (events[i].type === "checkpoint") {
2348
+ lastCheckpoint = events[i];
2349
+ lastCheckpointIdx = i;
2350
+ }
2351
+ }
2352
+ const pendingEvents = lastCheckpointIdx >= 0 ? events.slice(lastCheckpointIdx + 1) : events;
2353
+ const lastEv = events[events.length - 1];
2354
+ const inFlightStart = lastEv.type === "in_flight_start" ? lastEv : null;
2355
+ const context = inFlightStart && inFlightStart.type === "in_flight_start" ? inFlightStart.context : null;
2356
+ return {
2357
+ sessionId,
2358
+ stale: inFlightStart !== null,
2359
+ lastCheckpoint,
2360
+ pendingEvents,
2361
+ inFlightStart,
2362
+ context
2363
+ };
2364
+ }
2365
+ /**
2366
+ * List every stale session in a directory. Returns an array
2367
+ * (possibly empty) sorted by `lastEventTs` descending — most
2368
+ * recent crash first.
2369
+ */
2370
+ async listResumable() {
2371
+ let entries;
2372
+ try {
2373
+ entries = await fsp.readdir(this.dir);
2374
+ } catch (err) {
2375
+ if (err.code === "ENOENT") return [];
2376
+ return [];
2377
+ }
2378
+ const out = [];
2379
+ for (const name of entries) {
2380
+ if (!name.endsWith(".jsonl")) continue;
2381
+ const sessionId = name.slice(0, -".jsonl".length);
2382
+ if (sessionId.includes(".replay") || sessionId.includes(".annotations")) continue;
2383
+ const stale = await this.detectStale(sessionId);
2384
+ if (stale) out.push(stale);
2385
+ }
2386
+ return out.sort((a, b) => b.lastEventTs.localeCompare(a.lastEventTs));
2387
+ }
2388
+ // ── Internals ──────────────────────────────────────────────────────────
2389
+ filePath(sessionId) {
2390
+ if (!sessionId || sessionId.includes("/") || sessionId.includes("\\") || sessionId.includes("..")) {
2391
+ throw new Error(`Invalid sessionId: ${sessionId}`);
2392
+ }
2393
+ return path11.join(this.dir, `${sessionId}.jsonl`);
2394
+ }
2395
+ /**
2396
+ * Stream-parse the last few lines of a JSONL log. We do NOT load
2397
+ * the whole file into memory — for long-running sessions the log
2398
+ * can be megabytes. Instead we read tail-ward and find the last
2399
+ * `in_flight_start` / `in_flight_end` pair.
2400
+ */
2401
+ async parseForStale(sessionId, fp, raw) {
2402
+ const lines = raw.split("\n");
2403
+ let lastEvent = null;
2404
+ let eventCount = 0;
2405
+ for (const line of lines) {
2406
+ if (!line.trim()) continue;
2407
+ try {
2408
+ const ev = JSON.parse(line);
2409
+ lastEvent = ev;
2410
+ eventCount++;
2411
+ } catch {
2412
+ }
2413
+ }
2414
+ if (!lastEvent) return null;
2415
+ if (lastEvent.type === "in_flight_start") {
2416
+ return {
2417
+ sessionId,
2418
+ path: fp,
2419
+ lastEventTs: lastEvent.ts,
2420
+ context: lastEvent.context,
2421
+ eventCount
2422
+ };
2423
+ }
2424
+ return null;
2425
+ }
2426
+ };
2427
+ var GENESIS_PREV = "0".repeat(64);
2428
+ var ToolAuditLog = class {
2429
+ dir;
2430
+ /** In-memory cache of the last entry's hash (per session), to compute chains efficiently. */
2431
+ tailHash = /* @__PURE__ */ new Map();
2432
+ writeChains = /* @__PURE__ */ new Map();
2433
+ constructor(opts) {
2434
+ this.dir = opts.dir;
2435
+ }
2436
+ /**
2437
+ * Append a tool call/result pair to the chain. Returns the
2438
+ * resulting entry. Idempotency is not guaranteed — if you
2439
+ * record the same tool_use twice you get two entries. That's
2440
+ * intentional: the audit log is a record, not a cache.
2441
+ */
2442
+ async record(input) {
2443
+ let entry = null;
2444
+ await this.enqueue(input.sessionId, async () => {
2445
+ const prevHash = this.tailHash.get(input.sessionId) ?? GENESIS_PREV;
2446
+ const id = randomUUID();
2447
+ const ts = (/* @__PURE__ */ new Date()).toISOString();
2448
+ const content = {
2449
+ id,
2450
+ ts,
2451
+ prevHash,
2452
+ toolName: input.toolName,
2453
+ toolUseId: input.toolUseId,
2454
+ input: input.input,
2455
+ output: input.output,
2456
+ isError: input.isError
2457
+ };
2458
+ const hash = createHash("sha256").update(stableStringify2(content), "utf8").digest("hex");
2459
+ entry = {
2460
+ index: this.tailHash.has(input.sessionId) ? -1 : 0,
2461
+ // placeholder; recomputed below
2462
+ id,
2463
+ ts,
2464
+ prevHash,
2465
+ hash,
2466
+ toolName: input.toolName,
2467
+ toolUseId: input.toolUseId,
2468
+ input: input.input,
2469
+ output: input.output,
2470
+ isError: input.isError
2471
+ };
2472
+ const existing = await this.readAll(input.sessionId);
2473
+ const index = existing.length;
2474
+ const finalContent = { ...content, index };
2475
+ const finalHash = createHash("sha256").update(stableStringify2(finalContent), "utf8").digest("hex");
2476
+ entry = { ...entry, index, hash: finalHash };
2477
+ await this.appendLine(input.sessionId, entry);
2478
+ this.tailHash.set(input.sessionId, finalHash);
2479
+ });
2480
+ return entry;
2481
+ }
2482
+ /**
2483
+ * Walk the chain and verify every entry's hash and prevHash.
2484
+ * Returns a structured verdict — never throws.
2485
+ */
2486
+ async verify(sessionId) {
2487
+ const entries = await this.readAll(sessionId);
2488
+ if (entries.length === 0) return { ok: true, entries: 0 };
2489
+ if (entries[0].prevHash !== GENESIS_PREV) {
2490
+ return {
2491
+ ok: false,
2492
+ brokenAt: 0,
2493
+ reason: "first entry is not the genesis (prevHash != 0\u20260)"
2494
+ };
2495
+ }
2496
+ let prevHash = GENESIS_PREV;
2497
+ for (let i = 0; i < entries.length; i++) {
2498
+ const e = entries[i];
2499
+ if (e.prevHash !== prevHash) {
2500
+ return {
2501
+ ok: false,
2502
+ brokenAt: i,
2503
+ reason: `prevHash mismatch at entry ${i} (expected ${prevHash.slice(0, 8)}\u2026, got ${e.prevHash.slice(0, 8)}\u2026)`
2504
+ };
2505
+ }
2506
+ const content = {
2507
+ id: e.id,
2508
+ ts: e.ts,
2509
+ prevHash: e.prevHash,
2510
+ toolName: e.toolName,
2511
+ toolUseId: e.toolUseId,
2512
+ input: e.input,
2513
+ output: e.output,
2514
+ isError: e.isError,
2515
+ index: e.index
2516
+ };
2517
+ const expectedHash = createHash("sha256").update(stableStringify2(content), "utf8").digest("hex");
2518
+ if (expectedHash !== e.hash) {
2519
+ return {
2520
+ ok: false,
2521
+ brokenAt: i,
2522
+ reason: `hash mismatch at entry ${i} (entry content was modified)`
2523
+ };
2524
+ }
2525
+ prevHash = e.hash;
2526
+ }
2527
+ return { ok: true, entries: entries.length };
2528
+ }
2529
+ /** All entries for a session, in insertion order. */
2530
+ async load(sessionId) {
2531
+ return this.readAll(sessionId);
2532
+ }
2533
+ // ── Internals ────────────────────────────────────────────────────────────
2534
+ filePath(sessionId) {
2535
+ if (!sessionId || sessionId.includes("/") || sessionId.includes("\\") || sessionId.includes("..")) {
2536
+ throw new Error(`Invalid sessionId: ${sessionId}`);
2537
+ }
2538
+ return path11.join(this.dir, `${sessionId}.audit.jsonl`);
2539
+ }
2540
+ async readAll(sessionId) {
2541
+ const fp = this.filePath(sessionId);
2542
+ try {
2543
+ const raw = await fsp.readFile(fp, "utf8");
2544
+ const out = [];
2545
+ for (const line of raw.split("\n")) {
2546
+ if (!line.trim()) continue;
2547
+ try {
2548
+ out.push(JSON.parse(line));
2549
+ } catch {
2550
+ }
2551
+ }
2552
+ return out;
2553
+ } catch (err) {
2554
+ if (err.code === "ENOENT") return [];
2555
+ return [];
2556
+ }
2557
+ }
2558
+ async appendLine(sessionId, entry) {
2559
+ const fp = this.filePath(sessionId);
2560
+ const existing = await this.readAll(sessionId);
2561
+ const all = [...existing, entry];
2562
+ await atomicWrite(fp, all.map((e) => JSON.stringify(e)).join("\n") + (all.length ? "\n" : ""));
2563
+ }
2564
+ enqueue(sessionId, fn) {
2565
+ const prev = this.writeChains.get(sessionId) ?? Promise.resolve();
2566
+ const next = prev.then(fn, fn);
2567
+ this.writeChains.set(
2568
+ sessionId,
2569
+ next.catch(() => void 0)
2570
+ );
2571
+ return next;
2572
+ }
2573
+ };
2574
+ function stableStringify2(value) {
2575
+ return JSON.stringify(sortKeys2(value));
2576
+ }
2577
+ function sortKeys2(value) {
2578
+ if (Array.isArray(value)) return value.map(sortKeys2);
2579
+ if (value && typeof value === "object") {
2580
+ const obj = value;
2581
+ const sorted = {};
2582
+ for (const key of Object.keys(obj).sort()) {
2583
+ sorted[key] = sortKeys2(obj[key]);
2584
+ }
2585
+ return sorted;
2586
+ }
2587
+ return value;
2588
+ }
1952
2589
 
1953
2590
  // src/storage/session-analyzer.ts
1954
2591
  var SessionAnalyzer = class {
@@ -2054,7 +2691,7 @@ var DefaultSessionRewinder = class {
2054
2691
  sessionsDir;
2055
2692
  projectRoot;
2056
2693
  async listCheckpoints(sessionId) {
2057
- const file = path7.join(this.sessionsDir, `${sessionId}.jsonl`);
2694
+ const file = path11.join(this.sessionsDir, `${sessionId}.jsonl`);
2058
2695
  const raw = await fsp.readFile(file, "utf8");
2059
2696
  const events = parseEvents(raw);
2060
2697
  const fileCountMap = /* @__PURE__ */ new Map();
@@ -2079,7 +2716,7 @@ var DefaultSessionRewinder = class {
2079
2716
  return checkpoints;
2080
2717
  }
2081
2718
  async rewindToCheckpoint(sessionId, checkpointIndex) {
2082
- const file = path7.join(this.sessionsDir, `${sessionId}.jsonl`);
2719
+ const file = path11.join(this.sessionsDir, `${sessionId}.jsonl`);
2083
2720
  const raw = await fsp.readFile(file, "utf8");
2084
2721
  const events = parseEvents(raw);
2085
2722
  let targetIdx = -1;
@@ -2114,7 +2751,7 @@ var DefaultSessionRewinder = class {
2114
2751
  return { ...result, toPromptIndex: checkpointIndex, removedEvents };
2115
2752
  }
2116
2753
  async rewindLastN(sessionId, n) {
2117
- const file = path7.join(this.sessionsDir, `${sessionId}.jsonl`);
2754
+ const file = path11.join(this.sessionsDir, `${sessionId}.jsonl`);
2118
2755
  const raw = await fsp.readFile(file, "utf8");
2119
2756
  const events = parseEvents(raw);
2120
2757
  const checkpoints = [];
@@ -2143,7 +2780,7 @@ var DefaultSessionRewinder = class {
2143
2780
  return { ...result, toPromptIndex: targetIndex, removedEvents: snapshotsToRevert.length };
2144
2781
  }
2145
2782
  async rewindToStart(sessionId) {
2146
- const file = path7.join(this.sessionsDir, `${sessionId}.jsonl`);
2783
+ const file = path11.join(this.sessionsDir, `${sessionId}.jsonl`);
2147
2784
  const raw = await fsp.readFile(file, "utf8");
2148
2785
  const events = parseEvents(raw);
2149
2786
  const allSnapshots = [];
@@ -2179,10 +2816,10 @@ async function revertSnapshots(snapshots, projectRoot) {
2179
2816
  for (const snapshot of snapshots) {
2180
2817
  for (const file of snapshot.files) {
2181
2818
  try {
2182
- const absPath = path7.resolve(file.path);
2183
- const root = path7.resolve(projectRoot);
2184
- const rel = path7.relative(root, absPath);
2185
- if (rel.startsWith("..") || path7.isAbsolute(rel)) {
2819
+ const absPath = path11.resolve(file.path);
2820
+ const root = path11.resolve(projectRoot);
2821
+ const rel = path11.relative(root, absPath);
2822
+ if (rel.startsWith("..") || path11.isAbsolute(rel)) {
2186
2823
  errors.push(`${file.path}: path resolves outside project root \u2014 skipping`);
2187
2824
  continue;
2188
2825
  }
@@ -2741,8 +3378,8 @@ var FsError = class extends WrongStackError {
2741
3378
  // src/storage/goal-store.ts
2742
3379
  var MAX_JOURNAL_ENTRIES = 500;
2743
3380
  function goalFilePath(projectRoot) {
2744
- const hash = createHash("sha256").update(path7.resolve(projectRoot)).digest("hex").slice(0, 12);
2745
- return path7.join(os.homedir(), ".wrongstack", "projects", hash, "goal.json");
3381
+ const hash = createHash("sha256").update(path11.resolve(projectRoot)).digest("hex").slice(0, 12);
3382
+ return path11.join(os.homedir(), ".wrongstack", "projects", hash, "goal.json");
2746
3383
  }
2747
3384
  async function loadGoal(filePath) {
2748
3385
  let raw;
@@ -2850,14 +3487,14 @@ var DefaultPromptStore = class {
2850
3487
  }
2851
3488
  async list() {
2852
3489
  await ensureDir(this.dir);
2853
- let entries = [];
3490
+ const entries = [];
2854
3491
  try {
2855
3492
  const files = await fsp.readdir(this.dir);
2856
3493
  for (const file of files) {
2857
3494
  if (!file.endsWith(".json")) continue;
2858
3495
  try {
2859
3496
  const raw = JSON.parse(
2860
- await fsp.readFile(path7.join(this.dir, file), "utf8")
3497
+ await fsp.readFile(path11.join(this.dir, file), "utf8")
2861
3498
  );
2862
3499
  entries.push(raw.entry);
2863
3500
  } catch {
@@ -2870,7 +3507,7 @@ var DefaultPromptStore = class {
2870
3507
  );
2871
3508
  }
2872
3509
  async get(id) {
2873
- const file = path7.join(this.dir, `${id}.json`);
3510
+ const file = path11.join(this.dir, `${id}.json`);
2874
3511
  try {
2875
3512
  const raw = JSON.parse(await fsp.readFile(file, "utf8"));
2876
3513
  return raw.entry;
@@ -2880,12 +3517,12 @@ var DefaultPromptStore = class {
2880
3517
  }
2881
3518
  async save(entry) {
2882
3519
  await ensureDir(this.dir);
2883
- const file = path7.join(this.dir, `${entry.id}.json`);
3520
+ const file = path11.join(this.dir, `${entry.id}.json`);
2884
3521
  const raw = { version: 1, entry };
2885
3522
  await atomicWrite(file, JSON.stringify(raw, null, 2));
2886
3523
  }
2887
3524
  async delete(id) {
2888
- const file = path7.join(this.dir, `${id}.json`);
3525
+ const file = path11.join(this.dir, `${id}.json`);
2889
3526
  try {
2890
3527
  await fsp.unlink(file);
2891
3528
  return true;
@@ -2919,7 +3556,7 @@ var CloudSync = class {
2919
3556
  this.paths = paths;
2920
3557
  this.getConfig = getConfig;
2921
3558
  this.setConfig = setConfig;
2922
- this.statePath = path7.join(paths.globalRoot, "sync-state.json");
3559
+ this.statePath = path11.join(paths.globalRoot, "sync-state.json");
2923
3560
  }
2924
3561
  paths;
2925
3562
  getConfig;
@@ -3024,9 +3661,9 @@ var CloudSync = class {
3024
3661
  const localPath = this.categoryToPath(cat);
3025
3662
  if (!localPath) continue;
3026
3663
  const rel = segments.slice(2).join("/");
3027
- const destPath = rel ? path7.join(localPath, rel) : localPath;
3664
+ const destPath = rel ? path11.join(localPath, rel) : localPath;
3028
3665
  const blobData = await this.getBlob(token, owner, repoName, entry.sha);
3029
- await fsp.mkdir(path7.dirname(destPath), { recursive: true });
3666
+ await fsp.mkdir(path11.dirname(destPath), { recursive: true });
3030
3667
  await fsp.writeFile(destPath, Buffer.from(blobData, "base64"));
3031
3668
  }
3032
3669
  const localRev = await this.hashLocalCategories(cfg.categories);
@@ -3131,7 +3768,7 @@ var CloudSync = class {
3131
3768
  const files = await this.walkDir(localPath, localPath);
3132
3769
  for (const file of files) {
3133
3770
  const content = await fsp.readFile(file, "utf8");
3134
- const rel = path7.relative(localPath, file).replace(/\\/g, "/");
3771
+ const rel = path11.relative(localPath, file).replace(/\\/g, "/");
3135
3772
  entries.push({ path: `data/${cat}/${rel}`, content, mode: "100644" });
3136
3773
  hashes.push(content);
3137
3774
  }
@@ -3188,7 +3825,7 @@ var CloudSync = class {
3188
3825
  const results = [];
3189
3826
  const entries = await fsp.readdir(dir, { withFileTypes: true });
3190
3827
  for (const entry of entries) {
3191
- const full = path7.join(dir, entry.name);
3828
+ const full = path11.join(dir, entry.name);
3192
3829
  if (entry.isDirectory()) {
3193
3830
  results.push(...await this.walkDir(full, base));
3194
3831
  } else {
@@ -3209,6 +3846,6 @@ function timeAgo(iso) {
3209
3846
  return `${days}d ago`;
3210
3847
  }
3211
3848
 
3212
- export { ALL_SYNC_CATEGORIES, CloudSync, ConfigMigrationError, DEFAULT_CONFIG_MIGRATIONS, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultMemoryStore, DefaultPromptStore, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DirectorStateCheckpoint, MAX_JOURNAL_ENTRIES, QueueStore, RecoveryLock, SessionAnalyzer, addPlanItem, appendJournal, attachPlanCheckpoint, attachTodosCheckpoint, clearPlan, deriveTodosFromPlanItem, emptyGoal, emptyPlan, formatGoal, formatPlan, formatPlanTemplates, getPlanTemplate, goalFilePath, listPlanTemplates, loadDirectorState, loadGoal, loadPlan, loadTodosCheckpoint, removePlanItem, runConfigMigrations, saveGoal, savePlan, saveTodosCheckpoint, setPlanItemStatus, summarizeUsage };
3849
+ export { ALL_SYNC_CATEGORIES, AnnotationsStore, CloudSync, ConfigMigrationError, DEFAULT_CONFIG_MIGRATIONS, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultMemoryStore, DefaultPromptStore, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DirectorStateCheckpoint, MAX_JOURNAL_ENTRIES, QueueStore, RecoveryLock, ReplayLogStore, SessionAnalyzer, SessionRecovery, ToolAuditLog, addPlanItem, appendJournal, attachPlanCheckpoint, attachTodosCheckpoint, clearPlan, deriveTodosFromPlanItem, emptyGoal, emptyPlan, formatGoal, formatPlan, formatPlanTemplates, getPlanTemplate, goalFilePath, listPlanTemplates, loadDirectorState, loadGoal, loadPlan, loadTodosCheckpoint, removePlanItem, runConfigMigrations, saveGoal, savePlan, saveTodosCheckpoint, setPlanItemStatus, summarizeUsage };
3213
3850
  //# sourceMappingURL=index.js.map
3214
3851
  //# sourceMappingURL=index.js.map