throughline 0.4.6 → 0.4.8
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 +29 -0
- package/README.ja.md +38 -30
- package/README.md +47 -32
- package/bin/throughline.mjs +15 -2
- package/docs/PUBLIC_RELEASE_PLAN.md +5 -3
- package/docs/THROUGHLINE_CLEAR_AUTO_HANDOFF_PLAN.md +1 -1
- package/docs/THROUGHLINE_CODEX_FIRST_ROADMAP.md +4 -3
- package/docs/THROUGHLINE_CODEX_MONITOR_IMPLEMENTATION_PLAN.md +19 -0
- package/docs/THROUGHLINE_CODEX_TRIM_IMPLEMENTATION_PLAN.md +2 -2
- package/docs/THROUGHLINE_CODEX_TRIM_ROLLBACK_FIX_PLAN.md +7 -2
- package/docs/throughline-rollback-context-trim-insight.md +1 -1
- package/package.json +1 -1
- package/src/cli/codex-hook.mjs +258 -29
- package/src/cli/codex-hook.test.mjs +169 -2
- package/src/cli/doctor.mjs +59 -5
- package/src/cli/doctor.test.mjs +34 -2
- package/src/cli/help.test.mjs +2 -0
- package/src/cli/install.mjs +82 -12
- package/src/cli/install.test.mjs +100 -16
- package/src/codex-auto-refresh.mjs +1 -1
- package/src/codex-auto-refresh.test.mjs +4 -4
- package/src/token-monitor.mjs +97 -11
- package/src/token-monitor.test.mjs +84 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { test } from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
-
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
6
|
|
|
@@ -22,6 +22,8 @@ const {
|
|
|
22
22
|
setMeasuredColumns,
|
|
23
23
|
withLiveActivity,
|
|
24
24
|
resolveMonitorUsage,
|
|
25
|
+
discoverCodexSessionStates,
|
|
26
|
+
mergeCodexDiscoveredStates,
|
|
25
27
|
} = _internal;
|
|
26
28
|
|
|
27
29
|
// state-file は projectPath を resolve + lowercase 正規化する。
|
|
@@ -244,6 +246,73 @@ test('resolveMonitorUsage: live Codex rollout overrides stale Stop snapshot', ()
|
|
|
244
246
|
}
|
|
245
247
|
});
|
|
246
248
|
|
|
249
|
+
test('discoverCodexSessionStates: finds Codex rollout without a monitor state file', () => {
|
|
250
|
+
const home = mkdtempSync(join(tmpdir(), 'tl-monitor-codex-home-'));
|
|
251
|
+
const project = mkdtempSync(join(tmpdir(), 'tl-monitor-codex-project-'));
|
|
252
|
+
const oldHome = process.env.CODEX_HOME;
|
|
253
|
+
try {
|
|
254
|
+
process.env.CODEX_HOME = home;
|
|
255
|
+
const threadId = '019e085c-d3b9-7b43-8445-0efe32416e3d';
|
|
256
|
+
const dir = join(home, 'sessions', '2026', '05', '09');
|
|
257
|
+
mkdirSync(dir, { recursive: true });
|
|
258
|
+
const rollout = join(dir, `rollout-2026-05-09T01-12-41-${threadId}.jsonl`);
|
|
259
|
+
writeFileSync(
|
|
260
|
+
rollout,
|
|
261
|
+
JSON.stringify({
|
|
262
|
+
type: 'session_meta',
|
|
263
|
+
payload: {
|
|
264
|
+
id: threadId,
|
|
265
|
+
cwd: project,
|
|
266
|
+
source: 'vscode',
|
|
267
|
+
cli_version: '0.129.0-alpha.15',
|
|
268
|
+
},
|
|
269
|
+
}) + '\n',
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
const states = discoverCodexSessionStates({ all: false, session: null }, project);
|
|
273
|
+
|
|
274
|
+
assert.equal(states.length, 1);
|
|
275
|
+
assert.equal(states[0].sessionId, `codex:${threadId}`);
|
|
276
|
+
assert.equal(states[0].host, 'codex');
|
|
277
|
+
assert.equal(states[0].projectPath, normalizeProjectPath(project));
|
|
278
|
+
assert.equal(states[0].rolloutPath, rollout);
|
|
279
|
+
assert.equal(states[0].discoveredFrom, 'codex-rollout-discovery');
|
|
280
|
+
} finally {
|
|
281
|
+
if (oldHome === undefined) delete process.env.CODEX_HOME;
|
|
282
|
+
else process.env.CODEX_HOME = oldHome;
|
|
283
|
+
rmSync(home, { recursive: true, force: true });
|
|
284
|
+
rmSync(project, { recursive: true, force: true });
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test('mergeCodexDiscoveredStates: discovered rollout updates an existing Codex state entry', () => {
|
|
289
|
+
const existing = {
|
|
290
|
+
sessionId: 'codex:thread-a',
|
|
291
|
+
host: 'codex',
|
|
292
|
+
projectPath: CWD_FOO,
|
|
293
|
+
transcriptPath: null,
|
|
294
|
+
rolloutPath: '/old/rollout.jsonl',
|
|
295
|
+
updatedAt: 100,
|
|
296
|
+
usage: { tokens: 1 },
|
|
297
|
+
};
|
|
298
|
+
const discovered = {
|
|
299
|
+
sessionId: 'codex:thread-a',
|
|
300
|
+
host: 'codex',
|
|
301
|
+
projectPath: CWD_FOO,
|
|
302
|
+
transcriptPath: null,
|
|
303
|
+
rolloutPath: '/new/rollout.jsonl',
|
|
304
|
+
updatedAt: 200,
|
|
305
|
+
discoveredFrom: 'codex-rollout-discovery',
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const states = mergeCodexDiscoveredStates([existing], [discovered]);
|
|
309
|
+
|
|
310
|
+
assert.equal(states.length, 1);
|
|
311
|
+
assert.equal(states[0].rolloutPath, '/new/rollout.jsonl');
|
|
312
|
+
assert.equal(states[0].updatedAt, 200);
|
|
313
|
+
assert.deepEqual(states[0].usage, { tokens: 1 });
|
|
314
|
+
});
|
|
315
|
+
|
|
247
316
|
// ─── cellWidth ─────────────────────────────────────────────────────
|
|
248
317
|
|
|
249
318
|
test('cellWidth: ASCII は 1 セル', () => {
|
|
@@ -451,7 +520,18 @@ test('formatLine: Codex estimated usage は host と est marker を表示する'
|
|
|
451
520
|
assert.ok(out.includes('codex est win?'));
|
|
452
521
|
});
|
|
453
522
|
|
|
454
|
-
test('formatLine: Codex
|
|
523
|
+
test('formatLine: Codex session id は host prefix を外して 8 桁表示する', () => {
|
|
524
|
+
const args = makeLineArgs(0.5);
|
|
525
|
+
args.state.host = 'codex';
|
|
526
|
+
args.state.sessionId = 'codex:019e085c-d3b9-7b43-8445-0efe32416e3d';
|
|
527
|
+
|
|
528
|
+
const out = stripColors(formatLine(args));
|
|
529
|
+
|
|
530
|
+
assert.ok(out.includes('019e085c'), `expected raw Codex short id in output: ${out}`);
|
|
531
|
+
assert.ok(!out.includes('codex:01'), `did not expect prefixed short id in output: ${out}`);
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
test('formatLine: Codex live turn usage は transient output marker を表示しない', () => {
|
|
455
535
|
const args = makeLineArgs(0.5);
|
|
456
536
|
args.state.host = 'codex';
|
|
457
537
|
args.usage = {
|
|
@@ -469,7 +549,8 @@ test('formatLine: Codex live turn usage は transient output marker を表示す
|
|
|
469
549
|
const out = stripColors(formatLine(args));
|
|
470
550
|
assert.ok(out.includes('Codex'));
|
|
471
551
|
assert.ok(out.includes('101.2k / 200.0k'));
|
|
472
|
-
assert.ok(out.includes('gpt-5.5
|
|
552
|
+
assert.ok(out.includes('gpt-5.5'));
|
|
553
|
+
assert.ok(!out.includes('live+'));
|
|
473
554
|
});
|
|
474
555
|
|
|
475
556
|
test('formatLine: 70% 以上で "!" マーカーと弱めの文言', () => {
|