@wrongstack/core 0.8.6 → 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.
- package/dist/{agent-bridge-Bad3ZGQ7.d.ts → agent-bridge-DMVOX0cF.d.ts} +1 -1
- package/dist/{agent-subagent-runner-Cc8sRJOF.d.ts → agent-subagent-runner-R0I0Xusn.d.ts} +3 -3
- package/dist/{compactor-Mw7-rNyb.d.ts → compactor-DVTKL7XD.d.ts} +1 -1
- package/dist/{config-Bi4Q0fnz.d.ts → config-DoUAEvXH.d.ts} +8 -2
- package/dist/{context-z2x5gv_V.d.ts → context-BRNbHmRM.d.ts} +6 -0
- package/dist/coordination/index.d.ts +12 -12
- package/dist/coordination/index.js +58 -37
- package/dist/coordination/index.js.map +1 -1
- package/dist/{default-config-DvRSTELf.d.ts → default-config-Uzla85H-.d.ts} +5 -1
- package/dist/defaults/index.d.ts +22 -22
- package/dist/defaults/index.js +119 -76
- package/dist/defaults/index.js.map +1 -1
- package/dist/{events-yCpJD4wa.d.ts → events-CiG9qUM_.d.ts} +1 -1
- package/dist/execution/index.d.ts +13 -13
- package/dist/execution/index.js.map +1 -1
- package/dist/extension/index.d.ts +6 -6
- package/dist/{index-SxpnwRlJ.d.ts → index-bOl8lzFV.d.ts} +5 -5
- package/dist/{index-BvZld4Dr.d.ts → index-u2ROAV0F.d.ts} +17 -8
- package/dist/index.d.ts +31 -31
- package/dist/index.js +182 -95
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +6 -6
- package/dist/kernel/index.d.ts +9 -9
- package/dist/{mcp-servers-n2L9ohMX.d.ts → mcp-servers-jEoMIBZv.d.ts} +3 -3
- package/dist/models/index.d.ts +2 -2
- package/dist/{multi-agent-C8uY45AY.d.ts → multi-agent-3ZnTB1aT.d.ts} +2 -2
- package/dist/{multi-agent-coordinator-C7YbZUY8.d.ts → multi-agent-coordinator-COwCGIrU.d.ts} +2 -2
- package/dist/{null-fleet-bus-Bb2jVLKr.d.ts → null-fleet-bus-C1grTnOF.d.ts} +6 -6
- package/dist/observability/index.d.ts +2 -2
- package/dist/{path-resolver-DnC1nOjb.d.ts → path-resolver-TcJfc29Y.d.ts} +2 -2
- package/dist/{permission-policy-BBa1M1xc.d.ts → permission-policy-BpCGYBud.d.ts} +2 -2
- package/dist/{plan-templates-Cqdy6rtM.d.ts → plan-templates-ByT1HcRI.d.ts} +17 -7
- package/dist/{provider-runner-C4ouU7--.d.ts → provider-runner-BEpikbbN.d.ts} +3 -3
- package/dist/{retry-policy-OwtKNxo8.d.ts → retry-policy-BYkq0ugs.d.ts} +1 -1
- package/dist/sdd/index.d.ts +8 -8
- package/dist/{secret-scrubber-CyE1-EMG.d.ts → secret-scrubber-DttNiGYA.d.ts} +1 -1
- package/dist/{secret-scrubber-C0n1EqrC.d.ts → secret-scrubber-QSeI0ADi.d.ts} +1 -1
- package/dist/security/index.d.ts +4 -4
- package/dist/security/index.js +5 -2
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-DkvgYVS4.d.ts → selector-pox8abg0.d.ts} +1 -1
- package/dist/{session-reader-DsadjyF9.d.ts → session-reader-CSWcb5Ga.d.ts} +1 -1
- package/dist/storage/index.d.ts +9 -6
- package/dist/storage/index.js +109 -63
- package/dist/storage/index.js.map +1 -1
- package/dist/{system-prompt-CWA6ml-d.d.ts → system-prompt-Bs-Wliab.d.ts} +1 -1
- package/dist/{tool-executor-Ch25BDwa.d.ts → tool-executor-D7a00JVJ.d.ts} +4 -4
- package/dist/types/index.d.ts +16 -16
- package/dist/types/index.js +8 -2
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +3 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
package/dist/storage/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomBytes, randomUUID, createHash } from 'crypto';
|
|
2
2
|
import * as fsp from 'fs/promises';
|
|
3
|
-
import * as
|
|
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 =
|
|
13
|
+
const dir = path7.dirname(targetPath);
|
|
14
14
|
await fsp.mkdir(dir, { recursive: true });
|
|
15
|
-
const 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" });
|
|
@@ -68,7 +68,7 @@ async function renameWithRetry(from, to) {
|
|
|
68
68
|
if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
|
|
69
69
|
throw err;
|
|
70
70
|
}
|
|
71
|
-
await new Promise((
|
|
71
|
+
await new Promise((resolve3) => setTimeout(resolve3, delays[i]));
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
throw lastErr;
|
|
@@ -174,24 +174,30 @@ var DefaultSessionStore = class {
|
|
|
174
174
|
this.dir = opts.dir;
|
|
175
175
|
this.events = opts.events;
|
|
176
176
|
}
|
|
177
|
-
|
|
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
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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(
|
|
296
|
-
await fsp.unlink(
|
|
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
|
-
|
|
300
|
-
const
|
|
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 ?
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
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 =
|
|
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;
|
|
@@ -1488,12 +1512,17 @@ var RecoveryLock = class {
|
|
|
1488
1512
|
};
|
|
1489
1513
|
}
|
|
1490
1514
|
/**
|
|
1491
|
-
* Claim the lock for the given session.
|
|
1492
|
-
*
|
|
1493
|
-
* `checkAbandoned`
|
|
1515
|
+
* Claim the lock for the given session. Uses exclusive-create (`O_EXCL`)
|
|
1516
|
+
* to detect whether another process acquired the lock between our
|
|
1517
|
+
* `checkAbandoned()` call and now. If the file already exists, it means
|
|
1518
|
+
* another process won the race and we throw instead of silently
|
|
1519
|
+
* overwriting their recovery record.
|
|
1520
|
+
*
|
|
1521
|
+
* The caller MUST have already called `checkAbandoned()` and handled its
|
|
1522
|
+
* null return before calling this.
|
|
1494
1523
|
*/
|
|
1495
1524
|
async write(sessionId) {
|
|
1496
|
-
await ensureDir(
|
|
1525
|
+
await ensureDir(path7.dirname(this.file));
|
|
1497
1526
|
const lock = {
|
|
1498
1527
|
v: 1,
|
|
1499
1528
|
sessionId,
|
|
@@ -1501,7 +1530,15 @@ var RecoveryLock = class {
|
|
|
1501
1530
|
hostname: this.hostname,
|
|
1502
1531
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1503
1532
|
};
|
|
1504
|
-
|
|
1533
|
+
try {
|
|
1534
|
+
await fsp.writeFile(this.file, JSON.stringify(lock), { flag: "wx", mode: 384 });
|
|
1535
|
+
} catch (err) {
|
|
1536
|
+
const code = err.code;
|
|
1537
|
+
if (code === "EEXIST") {
|
|
1538
|
+
throw new Error(`Recovery lock already held by another process`);
|
|
1539
|
+
}
|
|
1540
|
+
throw err;
|
|
1541
|
+
}
|
|
1505
1542
|
}
|
|
1506
1543
|
/**
|
|
1507
1544
|
* Release the lock. Idempotent — silently succeeds if the file is
|
|
@@ -1945,12 +1982,14 @@ var SessionAnalyzer = class {
|
|
|
1945
1982
|
}
|
|
1946
1983
|
};
|
|
1947
1984
|
var DefaultSessionRewinder = class {
|
|
1948
|
-
constructor(sessionsDir) {
|
|
1985
|
+
constructor(sessionsDir, projectRoot) {
|
|
1949
1986
|
this.sessionsDir = sessionsDir;
|
|
1987
|
+
this.projectRoot = projectRoot;
|
|
1950
1988
|
}
|
|
1951
1989
|
sessionsDir;
|
|
1990
|
+
projectRoot;
|
|
1952
1991
|
async listCheckpoints(sessionId) {
|
|
1953
|
-
const file =
|
|
1992
|
+
const file = path7.join(this.sessionsDir, `${sessionId}.jsonl`);
|
|
1954
1993
|
const raw = await fsp.readFile(file, "utf8");
|
|
1955
1994
|
const events = parseEvents(raw);
|
|
1956
1995
|
const fileCountMap = /* @__PURE__ */ new Map();
|
|
@@ -1975,7 +2014,7 @@ var DefaultSessionRewinder = class {
|
|
|
1975
2014
|
return checkpoints;
|
|
1976
2015
|
}
|
|
1977
2016
|
async rewindToCheckpoint(sessionId, checkpointIndex) {
|
|
1978
|
-
const file =
|
|
2017
|
+
const file = path7.join(this.sessionsDir, `${sessionId}.jsonl`);
|
|
1979
2018
|
const raw = await fsp.readFile(file, "utf8");
|
|
1980
2019
|
const events = parseEvents(raw);
|
|
1981
2020
|
let targetIdx = -1;
|
|
@@ -2005,12 +2044,12 @@ var DefaultSessionRewinder = class {
|
|
|
2005
2044
|
}
|
|
2006
2045
|
}
|
|
2007
2046
|
}
|
|
2008
|
-
const result = await revertSnapshots(snapshotsToRevert);
|
|
2047
|
+
const result = await revertSnapshots(snapshotsToRevert, this.projectRoot);
|
|
2009
2048
|
const removedEvents = events.length - targetIdx - 1;
|
|
2010
2049
|
return { ...result, toPromptIndex: checkpointIndex, removedEvents };
|
|
2011
2050
|
}
|
|
2012
2051
|
async rewindLastN(sessionId, n) {
|
|
2013
|
-
const file =
|
|
2052
|
+
const file = path7.join(this.sessionsDir, `${sessionId}.jsonl`);
|
|
2014
2053
|
const raw = await fsp.readFile(file, "utf8");
|
|
2015
2054
|
const events = parseEvents(raw);
|
|
2016
2055
|
const checkpoints = [];
|
|
@@ -2035,11 +2074,11 @@ var DefaultSessionRewinder = class {
|
|
|
2035
2074
|
snapshotsToRevert.push({ promptIndex: event.promptIndex, files: event.files });
|
|
2036
2075
|
}
|
|
2037
2076
|
}
|
|
2038
|
-
const result = await revertSnapshots(snapshotsToRevert.reverse());
|
|
2077
|
+
const result = await revertSnapshots(snapshotsToRevert.reverse(), this.projectRoot);
|
|
2039
2078
|
return { ...result, toPromptIndex: targetIndex, removedEvents: snapshotsToRevert.length };
|
|
2040
2079
|
}
|
|
2041
2080
|
async rewindToStart(sessionId) {
|
|
2042
|
-
const file =
|
|
2081
|
+
const file = path7.join(this.sessionsDir, `${sessionId}.jsonl`);
|
|
2043
2082
|
const raw = await fsp.readFile(file, "utf8");
|
|
2044
2083
|
const events = parseEvents(raw);
|
|
2045
2084
|
const allSnapshots = [];
|
|
@@ -2051,7 +2090,7 @@ var DefaultSessionRewinder = class {
|
|
|
2051
2090
|
if (allSnapshots.length === 0) {
|
|
2052
2091
|
return { revertedFiles: [], errors: [], toPromptIndex: 0, removedEvents: 0 };
|
|
2053
2092
|
}
|
|
2054
|
-
const result = await revertSnapshots(allSnapshots.reverse());
|
|
2093
|
+
const result = await revertSnapshots(allSnapshots.reverse(), this.projectRoot);
|
|
2055
2094
|
return { ...result, toPromptIndex: 0, removedEvents: allSnapshots.length };
|
|
2056
2095
|
}
|
|
2057
2096
|
};
|
|
@@ -2069,12 +2108,19 @@ function parseEvents(raw) {
|
|
|
2069
2108
|
}
|
|
2070
2109
|
return events;
|
|
2071
2110
|
}
|
|
2072
|
-
async function revertSnapshots(snapshots) {
|
|
2111
|
+
async function revertSnapshots(snapshots, projectRoot) {
|
|
2073
2112
|
const revertedFiles = [];
|
|
2074
2113
|
const errors = [];
|
|
2075
2114
|
for (const snapshot of snapshots) {
|
|
2076
2115
|
for (const file of snapshot.files) {
|
|
2077
2116
|
try {
|
|
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)) {
|
|
2121
|
+
errors.push(`${file.path}: path resolves outside project root \u2014 skipping`);
|
|
2122
|
+
continue;
|
|
2123
|
+
}
|
|
2078
2124
|
if (file.action === "deleted") {
|
|
2079
2125
|
if (file.before !== null) {
|
|
2080
2126
|
await atomicWrite(file.path, file.before, { mode: 420 });
|
|
@@ -2630,8 +2676,8 @@ var FsError = class extends WrongStackError {
|
|
|
2630
2676
|
// src/storage/goal-store.ts
|
|
2631
2677
|
var MAX_JOURNAL_ENTRIES = 500;
|
|
2632
2678
|
function goalFilePath(projectRoot) {
|
|
2633
|
-
const hash = createHash("sha256").update(
|
|
2634
|
-
return
|
|
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");
|
|
2635
2681
|
}
|
|
2636
2682
|
async function loadGoal(filePath) {
|
|
2637
2683
|
let raw;
|