@ericrisco/rsc 2.0.11 → 2.0.12
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/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -98,15 +98,18 @@ export function handleLifecycle({ target, event, native = {}, cwd, settings } =
|
|
|
98
98
|
try {
|
|
99
99
|
if (!LOCAL_TARGETS.has(target)) throw new Error(`unsupported memory target: ${target}`);
|
|
100
100
|
if (isRemote(target, native)) return { output: {}, capture: null, remote: true, degraded: false };
|
|
101
|
-
|
|
101
|
+
// Two answers from one path, kept apart on purpose: `project` is where the journal is KEPT (the
|
|
102
|
+
// nearest harness), `here` is where the agent WORKS and therefore who the session is.
|
|
103
|
+
const here = resolve(cwd || native.cwd || process.env.RSC_PROJECT_CWD || process.cwd());
|
|
104
|
+
const project = nearestHarness(here);
|
|
102
105
|
if (!existsSync(project)) throw new Error('project directory unavailable');
|
|
103
106
|
const config = settings || projectSettings(project);
|
|
104
107
|
if (config.enabled === false) return { output: {}, capture: null, remote: false, degraded: false };
|
|
105
108
|
const id = sessionId(native, target);
|
|
106
109
|
const eventName = hookEventName(target, event, native);
|
|
107
110
|
if (event === 'start') {
|
|
108
|
-
const started = capture({ cwd: project, sessionId: id, target, event: 'start', settings: config });
|
|
109
|
-
const resumed = resume({ cwd: project, target, settings: config });
|
|
111
|
+
const started = capture({ cwd: project, worktreeCwd: here, sessionId: id, target, event: 'start', settings: config });
|
|
112
|
+
const resumed = resume({ cwd: project, worktreeCwd: here, target, settings: config });
|
|
110
113
|
return {
|
|
111
114
|
output: nativeOutput(target, eventName, resumed.context),
|
|
112
115
|
capture: started,
|
|
@@ -117,6 +120,7 @@ export function handleLifecycle({ target, event, native = {}, cwd, settings } =
|
|
|
117
120
|
}
|
|
118
121
|
const captureInput = {
|
|
119
122
|
cwd: project,
|
|
123
|
+
worktreeCwd: here,
|
|
120
124
|
sessionId: id,
|
|
121
125
|
target,
|
|
122
126
|
event: event === 'end' ? 'sessionEnd' : event,
|
|
@@ -284,6 +284,12 @@ function readRecords(root) {
|
|
|
284
284
|
|
|
285
285
|
export function capture(input = {}) {
|
|
286
286
|
const cwd = resolve(input.cwd || process.cwd());
|
|
287
|
+
// WHERE the journal lives and WHO the session is are two different questions. `cwd` answers the
|
|
288
|
+
// first — the nearest harness, so a child with no manifest of its own does not scatter journals.
|
|
289
|
+
// The second has to be asked of git from where the agent actually works: asked from the harness,
|
|
290
|
+
// every worktree nested under it came back as the harness itself, and a sibling's record then
|
|
291
|
+
// "matched exactly". See GHSA-8gjp-3r7c-33f4.
|
|
292
|
+
const here = resolve(input.worktreeCwd || cwd);
|
|
287
293
|
const config = settings(input.settings);
|
|
288
294
|
if (!config.enabled) return { record: null, path: null, notice: null, compactionHint: false };
|
|
289
295
|
const store = chooseMemoryRoot(cwd);
|
|
@@ -299,7 +305,7 @@ export function capture(input = {}) {
|
|
|
299
305
|
const recordPath = join(store.root, 'sessions', `${storageId}.json`);
|
|
300
306
|
let anchor = readJson(anchorPath);
|
|
301
307
|
let existing = readJson(recordPath);
|
|
302
|
-
const firstSnapshot = snapshot(
|
|
308
|
+
const firstSnapshot = snapshot(here, null);
|
|
303
309
|
if (!anchor) {
|
|
304
310
|
anchor = {
|
|
305
311
|
sessionId,
|
|
@@ -312,7 +318,7 @@ export function capture(input = {}) {
|
|
|
312
318
|
}
|
|
313
319
|
if (input.event === 'start' && !existing) return { record: null, path: null, notice: null, compactionHint: false };
|
|
314
320
|
|
|
315
|
-
const repo = snapshot(
|
|
321
|
+
const repo = snapshot(here, anchor.baselineHead);
|
|
316
322
|
const editCount = Math.max(0, (existing?.editCount || 0) + (finiteOrNull(input.editDelta, true) || 0));
|
|
317
323
|
const baselineFiles = new Set(anchor.baselineFiles || []);
|
|
318
324
|
const newDirtyPath = repo.files.some((path) => !baselineFiles.has(path));
|
|
@@ -419,13 +425,19 @@ export function resume(input = {}) {
|
|
|
419
425
|
ensureStore(store.root);
|
|
420
426
|
const now = iso(input.now);
|
|
421
427
|
prune(store.root, now, config);
|
|
422
|
-
const
|
|
423
|
-
const
|
|
428
|
+
const here = resolve(input.worktreeCwd || cwd);
|
|
429
|
+
const current = snapshot(here, null);
|
|
430
|
+
const records = readRecords(store.root).filter((record) => validAnchor(here, record))
|
|
424
431
|
.sort((a, b) => b.timestamps.updatedAt.localeCompare(a.timestamps.updatedAt));
|
|
425
432
|
let record = records.find((candidate) => candidate.branch === current.branch && candidate.worktree === current.worktree) || null;
|
|
426
433
|
let match = record ? 'exact' : 'none';
|
|
434
|
+
// Only ever this worktree's own records. The chain used to end in `|| records[0]` — the newest
|
|
435
|
+
// record in the store, whoever wrote it — which a moved or renamed checkout reached every time,
|
|
436
|
+
// because its stale records match nothing. A shared store is a place to KEEP several worktrees'
|
|
437
|
+
// journals, never a reason to hand one of them to another. No continuation is the honest answer
|
|
438
|
+
// when there is nothing of yours to continue.
|
|
427
439
|
if (!record) {
|
|
428
|
-
record = records.find((candidate) => candidate.worktree === current.worktree) ||
|
|
440
|
+
record = records.find((candidate) => candidate.worktree === current.worktree) || null;
|
|
429
441
|
if (record) match = 'nearby';
|
|
430
442
|
}
|
|
431
443
|
const lessons = selectedLessons(store.root, config);
|