instar 1.3.123 → 1.3.124

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.
@@ -25,7 +25,29 @@ export declare function findRolloutFile(threadId: string, codexHome?: string): P
25
25
  * Claude agent) returns null fast — `readdirSync` throws and is caught.
26
26
  */
27
27
  export declare function findRolloutFileSync(threadId: string, codexHome?: string): string | null;
28
- /** List all rollout files under $CODEX_HOME/sessions, newest first. */
28
+ /**
29
+ * List rollout files under $CODEX_HOME/sessions, newest first (by mtime).
30
+ *
31
+ * Codex partitions rollouts by date: `sessions/YYYY/MM/DD/rollout-*.jsonl`. A
32
+ * busy account accumulates tens of thousands of these over time (one real
33
+ * machine: 14k files / 1.4 GB). The previous implementation walked AND
34
+ * `stat`ed EVERY file on every call before slicing to `limit`, which made
35
+ * callers like `GET /codex/usage` and the TokenLedger scan take tens of
36
+ * seconds (the route timed out) on a large history.
37
+ *
38
+ * This walks the date-partition directories in DESCENDING date order and
39
+ * `stat`s only the rollout files in the newest partitions, stopping once it has
40
+ * `limit` candidates (after covering >= MIN_PARTITIONS_SCANNED non-empty
41
+ * partitions, so a day is never cut mid-way and the cross-midnight boundary is
42
+ * covered). Work is bounded to the most-recent partitions instead of the entire
43
+ * history. Trade-off: "newest by mtime" becomes "newest among the most-recent
44
+ * date partitions, then by mtime" — for the rate-limit reader this is exact
45
+ * (the account-wide windows are identical across any recently-active session),
46
+ * and for the resume/token-ledger callers a session older than the scanned
47
+ * partitions yet still the single most-recently-touched file is the only miss,
48
+ * which is vanishingly rare in practice. A non-date-partitioned layout falls
49
+ * back to the original full walk (correctness over speed).
50
+ */
29
51
  export declare function listAllRollouts(codexHome?: string, limit?: number): Promise<ReadonlyArray<{
30
52
  path: string;
31
53
  mtime: number;
@@ -1 +1 @@
1
- {"version":3,"file":"sessionPaths.d.ts","sourceRoot":"","sources":["../../../../../src/providers/adapters/openai-codex/observability/sessionPaths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,wBAAgB,mBAAmB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,4EAA4E;AAC5E,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIvF;AAoDD,uEAAuE;AACvE,wBAAsB,eAAe,CACnC,SAAS,CAAC,EAAE,MAAM,EAClB,KAAK,SAAM,GACV,OAAO,CAAC,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAMzD"}
1
+ {"version":3,"file":"sessionPaths.d.ts","sourceRoot":"","sources":["../../../../../src/providers/adapters/openai-codex/observability/sessionPaths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,wBAAgB,mBAAmB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,4EAA4E;AAC5E,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIvF;AAyDD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,eAAe,CACnC,SAAS,CAAC,EAAE,MAAM,EAClB,KAAK,SAAM,GACV,OAAO,CAAC,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CA0CzD"}
@@ -96,13 +96,110 @@ async function walkForUuid(root, uuid) {
96
96
  }
97
97
  return null;
98
98
  }
99
- /** List all rollout files under $CODEX_HOME/sessions, newest first. */
99
+ // Always cover at least this many newest non-empty day-partitions before an
100
+ // early break, so the cross-midnight boundary (and a session that started
101
+ // "yesterday" but is still the most recently active) is not missed.
102
+ const MIN_PARTITIONS_SCANNED = 2;
103
+ /**
104
+ * List rollout files under $CODEX_HOME/sessions, newest first (by mtime).
105
+ *
106
+ * Codex partitions rollouts by date: `sessions/YYYY/MM/DD/rollout-*.jsonl`. A
107
+ * busy account accumulates tens of thousands of these over time (one real
108
+ * machine: 14k files / 1.4 GB). The previous implementation walked AND
109
+ * `stat`ed EVERY file on every call before slicing to `limit`, which made
110
+ * callers like `GET /codex/usage` and the TokenLedger scan take tens of
111
+ * seconds (the route timed out) on a large history.
112
+ *
113
+ * This walks the date-partition directories in DESCENDING date order and
114
+ * `stat`s only the rollout files in the newest partitions, stopping once it has
115
+ * `limit` candidates (after covering >= MIN_PARTITIONS_SCANNED non-empty
116
+ * partitions, so a day is never cut mid-way and the cross-midnight boundary is
117
+ * covered). Work is bounded to the most-recent partitions instead of the entire
118
+ * history. Trade-off: "newest by mtime" becomes "newest among the most-recent
119
+ * date partitions, then by mtime" — for the rate-limit reader this is exact
120
+ * (the account-wide windows are identical across any recently-active session),
121
+ * and for the resume/token-ledger callers a session older than the scanned
122
+ * partitions yet still the single most-recently-touched file is the only miss,
123
+ * which is vanishingly rare in practice. A non-date-partitioned layout falls
124
+ * back to the original full walk (correctness over speed).
125
+ */
100
126
  export async function listAllRollouts(codexHome, limit = 100) {
101
127
  const root = path.join(codexHomeFromConfig(codexHome), 'sessions');
102
- const all = [];
103
- await walkCollect(root, all);
104
- all.sort((a, b) => b.mtime - a.mtime);
105
- return all.slice(0, limit);
128
+ const dayDirs = await listDayPartitionsDescending(root);
129
+ if (dayDirs === null) {
130
+ // Unexpected/flat layout — fall back to the full walk so we never silently
131
+ // miss files just because the date partitions weren't where we expected.
132
+ const all = [];
133
+ await walkCollect(root, all);
134
+ all.sort((a, b) => b.mtime - a.mtime);
135
+ return all.slice(0, limit);
136
+ }
137
+ const out = [];
138
+ let partitionsWithFiles = 0;
139
+ for (const dir of dayDirs) {
140
+ let entries;
141
+ try {
142
+ entries = await fs.readdir(dir);
143
+ }
144
+ catch {
145
+ continue;
146
+ }
147
+ let had = false;
148
+ for (const entry of entries) {
149
+ if (!entry.startsWith('rollout-') || !entry.endsWith('.jsonl'))
150
+ continue;
151
+ const full = path.join(dir, entry);
152
+ let stat;
153
+ try {
154
+ stat = await fs.stat(full);
155
+ }
156
+ catch {
157
+ continue;
158
+ }
159
+ if (stat.isFile()) {
160
+ out.push({ path: full, mtime: stat.mtimeMs });
161
+ had = true;
162
+ }
163
+ }
164
+ if (had)
165
+ partitionsWithFiles++;
166
+ if (out.length >= limit && partitionsWithFiles >= MIN_PARTITIONS_SCANNED)
167
+ break;
168
+ }
169
+ out.sort((a, b) => b.mtime - a.mtime);
170
+ return out.slice(0, limit);
171
+ }
172
+ /**
173
+ * Enumerate the `sessions/YYYY/MM/DD` day-partition directories in descending
174
+ * date order WITHOUT statting their contents. Returns null when no
175
+ * date-partitioned structure is present (so the caller can fall back to a full
176
+ * walk). Numeric-name sort (zero-padded YYYY/MM/DD) is lexicographic-correct.
177
+ */
178
+ async function listDayPartitionsDescending(root) {
179
+ const dirs = [];
180
+ const years = await readNamesDesc(root, /^\d{4}$/);
181
+ for (const y of years) {
182
+ const yPath = path.join(root, y);
183
+ const months = await readNamesDesc(yPath, /^\d{2}$/);
184
+ for (const m of months) {
185
+ const mPath = path.join(yPath, m);
186
+ const days = await readNamesDesc(mPath, /^\d{2}$/);
187
+ for (const d of days)
188
+ dirs.push(path.join(mPath, d));
189
+ }
190
+ }
191
+ return dirs.length > 0 ? dirs : null;
192
+ }
193
+ /** readdir + filter by name pattern + descending sort. [] on any read error. */
194
+ async function readNamesDesc(dir, pattern) {
195
+ let entries;
196
+ try {
197
+ entries = await fs.readdir(dir);
198
+ }
199
+ catch {
200
+ return [];
201
+ }
202
+ return entries.filter((e) => pattern.test(e)).sort().reverse();
106
203
  }
107
204
  async function walkCollect(dir, out) {
108
205
  let entries;
@@ -1 +1 @@
1
- {"version":3,"file":"sessionPaths.js","sourceRoot":"","sources":["../../../../../src/providers/adapters/openai-codex/observability/sessionPaths.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sessionPaths.js","sourceRoot":"","sources":["../../../../../src/providers/adapters/openai-codex/observability/sessionPaths.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.123",
3
+ "version": "1.3.124",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-05-30T20:55:40.867Z",
5
- "instarVersion": "1.3.123",
4
+ "generatedAt": "2026-05-30T21:48:31.075Z",
5
+ "instarVersion": "1.3.124",
6
6
  "entryCount": 193,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -0,0 +1,53 @@
1
+ # Instar Upgrade Guide — vNEXT
2
+
3
+ <!-- bump: patch -->
4
+
5
+ ## What Changed
6
+
7
+ **Fixed: `GET /codex/usage` (and the codex TokenLedger / resume scans) timed out
8
+ on a large codex history.** The shared helper `listAllRollouts` walked the ENTIRE
9
+ `$CODEX_HOME/sessions` tree and `stat`-ed every rollout file before slicing to
10
+ the newest few. On a real account that history is large — one machine measured
11
+ 14,277 files / 1.4 GB — so the full walk plus ~14k sequential `stat`s, under
12
+ live server load, made `GET /codex/usage` (shipped in v1.3.123) return a
13
+ connection timeout. It now walks the date-partition directories
14
+ (`sessions/YYYY/MM/DD/`) newest-first and `stat`s only the newest partitions
15
+ (at least two, until it has `limit` candidates), with a full-walk fallback for
16
+ any non-date-partitioned layout. The returned newest-N is unchanged; only the
17
+ scan is bounded. This one change fixes all four callers of the helper (the
18
+ codex-usage reader, the TokenLedger codex scan, the session-resume index, and
19
+ the layout canary).
20
+
21
+ ## Summary of New Capabilities
22
+
23
+ - No new capability — a performance fix. `listAllRollouts` is now bounded to the
24
+ most-recent date partitions (helpers `listDayPartitionsDescending` +
25
+ `readNamesDesc`), so codex usage/ledger/resume reads stay fast regardless of
26
+ how much rollout history has accumulated.
27
+
28
+ ## What to Tell Your User
29
+
30
+ The codex usage check now answers instantly even on a heavy account. Before this
31
+ fix, on an account with a very large codex history, asking how much codex usage
32
+ was left could hang and time out, because the check was reading through the
33
+ entire history to find the most recent record. It now looks only at the most
34
+ recent day or two of records, so it returns right away. Nothing else changes.
35
+
36
+ ## Evidence
37
+
38
+ **Reproduction.** On a real codex account with 14,277 rollout files (1.4 GB)
39
+ under `~/.codex/sessions`, hitting `GET /codex/usage` on the running server
40
+ returned a connection timeout — curl reported status 000 after a 30-second
41
+ `--max-time`, while `GET /health` on the same server responded normally. Root
42
+ cause confirmed by reading the code: `listAllRollouts` recursively walked the
43
+ whole tree and awaited an `fs.stat` on every one of the 14k files before
44
+ sorting and slicing.
45
+
46
+ **Before / after.** The old full-walk timed out at 30 s+ under load. The fixed
47
+ date-partition walk, run against the same live 14,277-file tree, completed in
48
+ **59 ms** (it scanned the two newest day-partitions, found the newest rollout,
49
+ and stopped) — returning the same newest record. A unit test with 206 fixture
50
+ files across 42 partitions uses an `fs.stat` spy to assert fewer than 20 stats
51
+ occur (only the newest partitions), versus 206 before. All three test tiers for
52
+ the codex-usage feature plus the TokenLedger / resume / canary suites stay
53
+ green.
@@ -0,0 +1,64 @@
1
+ # Side-Effects Review — bound the codex rollout scan to the newest partitions
2
+
3
+ **Version / slug:** `codex-rollout-scan-perf`
4
+ **Date:** 2026-05-30
5
+ **Author:** Echo (instar-dev agent)
6
+ **Second-pass reviewer:** not required (pure read-path perf optimization; no block/allow/lifecycle/decision surface)
7
+
8
+ ## Summary of the change
9
+
10
+ `listAllRollouts` (`src/providers/adapters/openai-codex/observability/sessionPaths.ts`)
11
+ no longer walks + `stat`s the ENTIRE `$CODEX_HOME/sessions` tree to return the
12
+ newest-N rollouts. It now walks date-partition dirs newest-first and stats only
13
+ the newest partitions (>= 2, until `limit` candidates), with a full-walk
14
+ fallback for non-date-partitioned layouts. Fixes the `GET /codex/usage` timeout
15
+ (and the shared TokenLedger / resume-index cost) on a large codex history
16
+ (measured 14,277 files / 1.4 GB → route timed out at 30 s; now 59 ms).
17
+
18
+ ## Decision-point inventory
19
+
20
+ - No decision point. `listAllRollouts` returns data (a list of file paths +
21
+ mtimes). The change is purely the disk-scan strategy used to produce that
22
+ list; the returned newest-N is unchanged for the common case.
23
+
24
+ ---
25
+
26
+ ## 1. Over-block
27
+ No block/allow surface — not applicable. It returns a file list; it rejects
28
+ nothing.
29
+
30
+ ## 2. Under-block
31
+ Not applicable. The closest "miss" is the documented trade-off: a session OLDER
32
+ than the scanned partitions yet still the single most-recently-touched file on
33
+ disk would not be in the candidate set. For the rate-limit reader this changes
34
+ nothing (account-wide windows are identical across any recently-active session);
35
+ for the resume/token-ledger callers it is a vanishingly rare miss (sessions are
36
+ not active for days) and `MIN_PARTITIONS_SCANNED = 2` covers the common
37
+ cross-midnight case.
38
+
39
+ ## 3. Level-of-abstraction fit
40
+ Correct layer — the fix is in the shared helper, so all four callers
41
+ (codex-usage reader, TokenLedger scan, resume index, layout canary) get the
42
+ speedup from one change rather than each re-implementing a bounded scan.
43
+
44
+ ## 4. Signal vs authority compliance
45
+ Compliant — no authority at all. A read helper that returns data; it gates,
46
+ blocks, and decides nothing (`docs/signal-vs-authority.md` n/a beyond "this is
47
+ not a decision point").
48
+
49
+ ## 5. Interactions
50
+ - **Shared helper:** all callers benefit; none depend on the *full* unbounded
51
+ list (every caller passes a `limit` and wants newest-N). Verified the four
52
+ call sites pass a finite limit.
53
+ - **No races / no writes:** read-only; opens + closes its own dir/file handles.
54
+ - **Canary:** `codexSessionLayoutCanary` uses date-partitioned fixtures → hits
55
+ the fast path → stays green (verified).
56
+
57
+ ## 6. External surfaces
58
+ - Makes `GET /codex/usage` actually responsive on a heavy account (it returns
59
+ fast instead of timing out). No change to the response shape or semantics.
60
+ - No new route, no message, no change visible to other agents.
61
+
62
+ ## 7. Rollback cost
63
+ Trivial. Revert the `listAllRollouts` rewrite + the two private helpers + the new
64
+ test. No data, no migration, no behavior to repair — only the scan strategy.