antechamber 1.0.4 → 1.0.5
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/CHANGELOG.md +7 -0
- package/dist/session-store.d.ts +3 -0
- package/dist/session-store.js +40 -2
- package/dist/sessions.js +32 -24
- package/extensions/omo-compat/package.json +1 -1
- package/extensions/omo-dag/package.json +1 -1
- package/extensions/omo-work/package.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,13 @@ and this project uses [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.0.5] - 2026-10-20
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Reduce startup CPU usage and boot delays for large session histories by committing restoration metadata
|
|
15
|
+
in one registry write, while preserving restored costs, child sessions and independent registry writers.
|
|
16
|
+
|
|
10
17
|
## [1.0.4] - 2026-10-20
|
|
11
18
|
|
|
12
19
|
### Fixed
|
package/dist/session-store.d.ts
CHANGED
|
@@ -91,12 +91,15 @@ export declare class SessionStore {
|
|
|
91
91
|
readonly stateDir: string;
|
|
92
92
|
private readonly file;
|
|
93
93
|
private entries;
|
|
94
|
+
private batchState;
|
|
94
95
|
constructor(stateDir?: string);
|
|
95
96
|
private load;
|
|
96
97
|
private readEntries;
|
|
97
98
|
private withRegistryLock;
|
|
98
99
|
private persist;
|
|
99
100
|
private mutate;
|
|
101
|
+
/** Synchronous restoration reads its own changes, then merges them under one short-lived write lock. */
|
|
102
|
+
batch<T>(action: () => T): T;
|
|
100
103
|
get(ocSessionId: string): SessionRegistryEntry | undefined;
|
|
101
104
|
idFor(piSessionId: string): string | undefined;
|
|
102
105
|
childIds(): string[];
|
package/dist/session-store.js
CHANGED
|
@@ -378,12 +378,15 @@ export class SessionStore {
|
|
|
378
378
|
stateDir;
|
|
379
379
|
file;
|
|
380
380
|
entries;
|
|
381
|
+
batchState;
|
|
381
382
|
constructor(stateDir) {
|
|
382
383
|
const dir = stateDir ?? envSetting("STATE_DIR") ?? defaultStateDir();
|
|
383
384
|
this.stateDir = dir;
|
|
384
385
|
this.file = join(dir, "sessions.json");
|
|
385
386
|
}
|
|
386
387
|
load() {
|
|
388
|
+
if (this.batchState !== undefined)
|
|
389
|
+
return this.batchState.entries;
|
|
387
390
|
if (this.entries !== undefined)
|
|
388
391
|
return this.entries;
|
|
389
392
|
this.entries = this.readEntries();
|
|
@@ -452,6 +455,11 @@ export class SessionStore {
|
|
|
452
455
|
renameSync(tmp, this.file);
|
|
453
456
|
}
|
|
454
457
|
mutate(change) {
|
|
458
|
+
if (this.batchState !== undefined) {
|
|
459
|
+
this.batchState.changes.push(change);
|
|
460
|
+
change(this.batchState.entries);
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
455
463
|
this.withRegistryLock(() => {
|
|
456
464
|
const entries = this.readEntries();
|
|
457
465
|
if (change(entries))
|
|
@@ -459,6 +467,31 @@ export class SessionStore {
|
|
|
459
467
|
this.entries = entries;
|
|
460
468
|
});
|
|
461
469
|
}
|
|
470
|
+
/** Synchronous restoration reads its own changes, then merges them under one short-lived write lock. */
|
|
471
|
+
batch(action) {
|
|
472
|
+
if (this.batchState !== undefined)
|
|
473
|
+
return action();
|
|
474
|
+
const changes = [];
|
|
475
|
+
const batch = { entries: structuredClone(this.load()), changes };
|
|
476
|
+
this.batchState = batch;
|
|
477
|
+
try {
|
|
478
|
+
const result = action();
|
|
479
|
+
this.batchState = undefined;
|
|
480
|
+
if (batch.changes.length !== 0) {
|
|
481
|
+
this.mutate((entries) => {
|
|
482
|
+
let changed = false;
|
|
483
|
+
for (const change of batch.changes)
|
|
484
|
+
if (change(entries))
|
|
485
|
+
changed = true;
|
|
486
|
+
return changed;
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
return result;
|
|
490
|
+
}
|
|
491
|
+
finally {
|
|
492
|
+
this.batchState = undefined;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
462
495
|
get(ocSessionId) {
|
|
463
496
|
return this.load().get(ocSessionId);
|
|
464
497
|
}
|
|
@@ -471,18 +504,23 @@ export class SessionStore {
|
|
|
471
504
|
.map(([id]) => id);
|
|
472
505
|
}
|
|
473
506
|
set(ocSessionId, entry) {
|
|
507
|
+
const saved = this.batchState === undefined ? entry : structuredClone(entry);
|
|
474
508
|
this.mutate((entries) => {
|
|
475
|
-
entries.set(ocSessionId,
|
|
509
|
+
entries.set(ocSessionId, this.batchState === undefined ? saved : structuredClone(saved));
|
|
476
510
|
return true;
|
|
477
511
|
});
|
|
478
512
|
}
|
|
479
513
|
/** Merge a partial update (e.g. title override, updated timestamp). */
|
|
480
514
|
update(ocSessionId, patch) {
|
|
515
|
+
const saved = this.batchState === undefined ? patch : structuredClone(patch);
|
|
481
516
|
this.mutate((entries) => {
|
|
482
517
|
const previous = entries.get(ocSessionId);
|
|
483
518
|
if (previous === undefined)
|
|
484
519
|
return false;
|
|
485
|
-
entries.set(ocSessionId, {
|
|
520
|
+
entries.set(ocSessionId, {
|
|
521
|
+
...previous,
|
|
522
|
+
...(this.batchState === undefined ? saved : structuredClone(saved)),
|
|
523
|
+
});
|
|
486
524
|
return true;
|
|
487
525
|
});
|
|
488
526
|
}
|
package/dist/sessions.js
CHANGED
|
@@ -308,14 +308,18 @@ export class SessionManager {
|
|
|
308
308
|
.sort((a, b) => this.lifecycle.lastUsed(b) - this.lifecycle.lastUsed(a));
|
|
309
309
|
}
|
|
310
310
|
list(directory) {
|
|
311
|
-
this.
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
311
|
+
return this.store.batch(() => {
|
|
312
|
+
this.refreshNativeTitles();
|
|
313
|
+
this.subagents.restoreAll();
|
|
314
|
+
if (directory !== undefined) {
|
|
315
|
+
this.ensureScanned(directory);
|
|
316
|
+
return [...this.sessions.values()]
|
|
317
|
+
.filter((s) => s.info.directory === directory)
|
|
318
|
+
.map((s) => this.sessionInfo(s));
|
|
319
|
+
}
|
|
320
|
+
// Unfiltered: keep the old semantics — live sessions only.
|
|
321
|
+
return [...this.sessions.values()].filter((s) => s.restored === undefined).map((s) => this.sessionInfo(s));
|
|
322
|
+
});
|
|
319
323
|
}
|
|
320
324
|
/**
|
|
321
325
|
* Every restorable session on disk (all directories) plus live ones. Backs the
|
|
@@ -323,10 +327,12 @@ export class SessionManager {
|
|
|
323
327
|
* global/recent view; `list(directory)` stays the per-project source of truth.
|
|
324
328
|
*/
|
|
325
329
|
listAll() {
|
|
326
|
-
this.
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
+
return this.store.batch(() => {
|
|
331
|
+
this.refreshNativeTitles();
|
|
332
|
+
this.ensureAllScanned();
|
|
333
|
+
this.subagents.restoreAll();
|
|
334
|
+
return [...this.sessions.values()].map((s) => this.sessionInfo(s));
|
|
335
|
+
});
|
|
330
336
|
}
|
|
331
337
|
sessionInfo(s) {
|
|
332
338
|
if (s.restored !== undefined)
|
|
@@ -334,18 +340,20 @@ export class SessionManager {
|
|
|
334
340
|
return s.info;
|
|
335
341
|
}
|
|
336
342
|
get(sessionId) {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
343
|
+
return this.store.batch(() => {
|
|
344
|
+
if (this.disposed)
|
|
345
|
+
return undefined;
|
|
346
|
+
const live = this.sessions.get(sessionId);
|
|
347
|
+
if (live !== undefined) {
|
|
348
|
+
this.refreshNativeTitles();
|
|
349
|
+
this.sessionInfo(live);
|
|
350
|
+
return live;
|
|
351
|
+
}
|
|
352
|
+
const restored = this.subagents.restore(sessionId) ?? this.resolveRestored(sessionId);
|
|
353
|
+
if (restored !== undefined)
|
|
354
|
+
this.sessionInfo(restored);
|
|
355
|
+
return restored;
|
|
356
|
+
});
|
|
349
357
|
}
|
|
350
358
|
async remove(sessionId) {
|
|
351
359
|
return this.lifecycle.run(() => this.removeLive(sessionId));
|