throughline 0.10.1 → 0.10.2
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 +14 -0
- package/README.ja.md +1 -1
- package/README.md +2 -2
- package/docs/16_readonly_handoff_context_plan.md +2 -2
- package/package.json +1 -1
- package/src/auditor-context.mjs +3 -3
- package/src/cli/auditor-context.mjs +2 -1
- package/src/cli/doctor.mjs +7 -6
- package/src/cli/trim.mjs +3 -2
- package/src/codex-auto-refresh.mjs +3 -3
- package/src/codex-sidecar.mjs +2 -1
- package/src/completed-turn-receipts.mjs +5 -5
- package/src/hosts/identity.mjs +1 -1
- package/src/os/app-dirs.mjs +25 -0
- package/src/os/paths.mjs +4 -0
- package/src/runtime-error-store.mjs +6 -7
- package/src/trim-model.mjs +6 -5
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,20 @@ shipped to npm but were not individually tagged on GitHub.
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
+
## [0.10.2] — 2026-08-24
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- 挙動不変のOS/harness層集約リファクタ(harness用語統一campaignの分離規約):
|
|
18
|
+
- LOCALAPPDATA / XDG_CONFIG_HOME / XDG_STATE_HOME のベースディレクトリ組み立てを
|
|
19
|
+
新設`src/os/app-dirs.mjs`へ一本化(runtime-error-store / completed-turn-receipts
|
|
20
|
+
に3重実装されていた)。
|
|
21
|
+
- hostリテラル比較(`'claude'`/`'codex'`)6ファイルを`src/hosts/identity.mjs`の
|
|
22
|
+
定数importへ統一し、「識別の唯一の正本」宣言と実装を一致させた。
|
|
23
|
+
- codex-auto-refreshの独自パス正規化を`src/os/paths.mjs`の
|
|
24
|
+
`foldPathCaseForPlatform`へ、codex-sidecarのwin32判定を同`isWin32Platform`へ委譲。
|
|
25
|
+
- `hosts/identity.mjs`の分類語をvendorからharnessへ更新(用語のみ)。
|
|
26
|
+
|
|
13
27
|
## [0.10.1] — 2026-08-23
|
|
14
28
|
|
|
15
29
|
### Changed
|
package/README.ja.md
CHANGED
|
@@ -390,7 +390,7 @@ throughline handoff-context --session codex:<thread-id> --json
|
|
|
390
390
|
成功時の`throughline.handoff_context.v1`は`schema`、`status`、`sessionId`、`context`だけを返す。
|
|
391
391
|
`context`はSessionStartと同じ予算付き継承文脈で、DB作成・migration・baton消費・session merge・
|
|
392
392
|
latest session推測・`sessions.merged_into`変更・L1/L2/L3 rowの所属変更は行わない。AItermは任意の
|
|
393
|
-
別
|
|
393
|
+
別harness portable forkでこの境界を使う。Observer feedはcompleted-turn projectionであり代替ではない。
|
|
394
394
|
|
|
395
395
|
スラッシュコマンド (Claude Code 内でユーザーが叩く):
|
|
396
396
|
|
package/README.md
CHANGED
|
@@ -834,7 +834,7 @@ local-only contracts.
|
|
|
834
834
|
| `throughline runtime-errors reopen <fingerprint> --json` | Explicitly reopen a resolved aggregate without fabricating a new occurrence |
|
|
835
835
|
| `throughline runtime-errors compact --json` | Remove only acknowledged, resolved aggregates after retention; open or unacknowledged records remain |
|
|
836
836
|
| `throughline handoff-preview --session <id>` | Print a Codex-facing `throughline_handoff` JSON projection |
|
|
837
|
-
| `throughline handoff-context --session <id> --json` | Print the exact SessionStart inheritance context as versioned JSON without moving memory rows or changing `sessions.merged_into`; intended for local launchers that need portable cross-
|
|
837
|
+
| `throughline handoff-context --session <id> --json` | Print the exact SessionStart inheritance context as versioned JSON without moving memory rows or changing `sessions.merged_into`; intended for local launchers that need portable cross-harness context |
|
|
838
838
|
| `throughline grok-continue --session <id>` | Spawn a person-facing Grok seat whose first user text is the handoff-context body. cwd is the source session `project_path`. Does not spawn without ready context. No `--rules`. macOS Terminal only |
|
|
839
839
|
| `throughline codex-capture --codex-thread-id <id>` | Capture active Codex rollout turns into a `codex:<thread_id>` DB session |
|
|
840
840
|
| `throughline codex-summarize --session codex:<id>` | Summarize captured Codex L2 into L1 with the Codex CLI backend |
|
|
@@ -872,7 +872,7 @@ The successful `throughline.handoff_context.v1` object contains only `schema`,
|
|
|
872
872
|
inheritance text used by SessionStart. The command does not create or migrate a
|
|
873
873
|
database, consume a baton, merge sessions, infer a latest session, change
|
|
874
874
|
`sessions.merged_into`, or reassign L1/L2/L3 rows. AIterm uses this boundary for
|
|
875
|
-
its optional cross-
|
|
875
|
+
its optional cross-harness portable fork; the Observer feed is a separate
|
|
876
876
|
completed-turn projection and is not a substitute.
|
|
877
877
|
|
|
878
878
|
Slash commands (invoked by the user in Claude Code):
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
通常 handoff が使う `buildBudgetedResumeContext` の出力を、DB 所有権を変えずにローカルプログラムが
|
|
6
6
|
取得できる read-only CLI として公開する。最初の consumer は AIterm の portable fork だが、I/F は
|
|
7
|
-
特定 consumer や
|
|
7
|
+
特定 consumer や harness に依存させない。
|
|
8
8
|
|
|
9
9
|
実行 ToDo、依存、状態、完了証拠の正本は Lattice plan `readonly-handoff-context` とする。
|
|
10
10
|
|
|
11
11
|
## 完了
|
|
12
12
|
|
|
13
13
|
2026-08-04に`throughline@0.9.0`としてnpm、tag、GitHub Release、global installまで公開した。
|
|
14
|
-
focused契約testと全回帰は729 pass/1 skip/0 fail。AIterm v0.23.0の代表cross-
|
|
14
|
+
focused契約testと全回帰は729 pass/1 skip/0 fail。AIterm v0.23.0の代表cross-harness smokeでは
|
|
15
15
|
Codex source memoryをClaudeへ注入し、前後でsource session、`sessions.merged_into`、L1/L2/L3 row所属が
|
|
16
16
|
完全一致することを確認した。公開後の現行ドキュメント全域監査は、Latticeの終端ToDoを再openして
|
|
17
17
|
README、作業者入口、配布Codex skill、docs索引、計画、CHANGELOGへ同期した。変更Markdownの
|
package/package.json
CHANGED
package/src/auditor-context.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { homedir } from 'node:os';
|
|
|
3
3
|
import { isAbsolute, join, resolve, sep } from 'node:path';
|
|
4
4
|
import { DatabaseSync } from 'node:sqlite';
|
|
5
5
|
import { buildBodyRowsFromActiveTurns } from './codex-capture.mjs';
|
|
6
|
-
import { isCodexSessionId } from './hosts/identity.mjs';
|
|
6
|
+
import { CLAUDE_HOST, CODEX_HOST, isCodexSessionId } from './hosts/identity.mjs';
|
|
7
7
|
import { parseCodexRolloutFile } from './codex-rollout-memory.mjs';
|
|
8
8
|
import { getLogicalTurnGroups } from './transcript-reader.mjs';
|
|
9
9
|
import { hashAuditorBody, normalizeAuditorBody } from './body-digest.mjs';
|
|
@@ -24,7 +24,7 @@ export function defaultAuditorContextDbPath() {
|
|
|
24
24
|
export function deriveAuditorFreshnessExpectation({ host, transcriptPath, sessionId } = {}) {
|
|
25
25
|
assertNonEmptyString(transcriptPath, 'transcriptPath');
|
|
26
26
|
assertNonEmptyString(sessionId, 'sessionId');
|
|
27
|
-
if (host ===
|
|
27
|
+
if (host === CLAUDE_HOST) {
|
|
28
28
|
const latest = getLogicalTurnGroups(transcriptPath).at(-1);
|
|
29
29
|
if (!latest) return null;
|
|
30
30
|
return {
|
|
@@ -34,7 +34,7 @@ export function deriveAuditorFreshnessExpectation({ host, transcriptPath, sessio
|
|
|
34
34
|
expectedAssistantSha256: hashAuditorBody(latest.representative.content),
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
|
-
if (host ===
|
|
37
|
+
if (host === CODEX_HOST) {
|
|
38
38
|
const parsed = parseCodexRolloutFile(transcriptPath, { includeInFlightTurn: false });
|
|
39
39
|
const rows = buildBodyRowsFromActiveTurns(parsed.activeTurns, { sessionId, now: 0 });
|
|
40
40
|
const latestTurnNumber = rows.reduce((max, row) => Math.max(max, row.turnNumber), 0);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CLAUDE_HOST, CODEX_HOST } from '../hosts/identity.mjs';
|
|
1
2
|
import {
|
|
2
3
|
AUDITOR_CONTEXT_SCHEMA,
|
|
3
4
|
deriveAuditorFreshnessExpectation,
|
|
@@ -53,7 +54,7 @@ export function parseArgs(argv = []) {
|
|
|
53
54
|
else if (arg === '--max-body-chars') out.maxBodyChars = parsePositiveInteger(value);
|
|
54
55
|
else if (arg === '--max-total-chars') out.maxTotalChars = parsePositiveInteger(value);
|
|
55
56
|
else if (arg === '--db') out.dbPath = value;
|
|
56
|
-
else if (arg === '--host' && (value ===
|
|
57
|
+
else if (arg === '--host' && (value === CLAUDE_HOST || value === CODEX_HOST)) out.host = value;
|
|
57
58
|
else if (arg === '--transcript') out.transcriptPath = value;
|
|
58
59
|
else throw new TypeError('unknown option');
|
|
59
60
|
}
|
package/src/cli/doctor.mjs
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { existsSync, accessSync, readFileSync, constants, readdirSync, statSync } from 'node:fs';
|
|
17
|
+
import { CODEX_HOST } from '../hosts/identity.mjs';
|
|
17
18
|
import { join, dirname } from 'node:path';
|
|
18
19
|
import { homedir } from 'node:os';
|
|
19
20
|
import { execSync } from 'node:child_process';
|
|
@@ -302,9 +303,9 @@ function runTrimDiagnosis(
|
|
|
302
303
|
) {
|
|
303
304
|
const info = describeTrimHost(host);
|
|
304
305
|
const codexIdentity =
|
|
305
|
-
info.host ===
|
|
306
|
+
info.host === CODEX_HOST ? resolveCodexThreadIdentity({ codexThreadId: null }, env) : null;
|
|
306
307
|
const hostPrimitiveDiagnosis =
|
|
307
|
-
info.host ===
|
|
308
|
+
info.host === CODEX_HOST ? readCodexHostPrimitiveDiagnosis({ env, auditRunner }) : null;
|
|
308
309
|
console.log(`${BOLD}[Trim]${RESET}\n`);
|
|
309
310
|
console.log(` host: ${info.host}`);
|
|
310
311
|
console.log(` default keep-recent: ${DEFAULT_TRIM_KEEP_RECENT}`);
|
|
@@ -330,19 +331,19 @@ function runTrimDiagnosis(
|
|
|
330
331
|
}
|
|
331
332
|
console.log('');
|
|
332
333
|
console.log(' dry-run command:');
|
|
333
|
-
if (info.host ===
|
|
334
|
+
if (info.host === CODEX_HOST && !codexIdentity?.codexThreadId) {
|
|
334
335
|
console.log(' throughline trim --dry-run --host codex --codex-thread-id <id>');
|
|
335
336
|
console.log(' throughline trim --preflight --host codex --codex-thread-id <id>');
|
|
336
|
-
} else if (info.host ===
|
|
337
|
+
} else if (info.host === CODEX_HOST) {
|
|
337
338
|
console.log(' throughline trim --dry-run --host codex');
|
|
338
339
|
console.log(' throughline trim --preflight --host codex');
|
|
339
340
|
} else {
|
|
340
341
|
console.log(` throughline trim --dry-run --host ${info.host}`);
|
|
341
342
|
}
|
|
342
|
-
if (info.host ===
|
|
343
|
+
if (info.host === CODEX_HOST) {
|
|
343
344
|
console.log(' throughline trim --execute --host codex');
|
|
344
345
|
}
|
|
345
|
-
if (info.host ===
|
|
346
|
+
if (info.host === CODEX_HOST) {
|
|
346
347
|
const sessionId = codexIdentity?.codexThreadId
|
|
347
348
|
? `codex:${codexIdentity.codexThreadId}`
|
|
348
349
|
: 'codex:<thread-id>';
|
package/src/cli/trim.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { runCodexTrimExecution, runCodexTrimPreflight } from '../codex-app-server.mjs';
|
|
2
|
+
import { CODEX_HOST } from '../hosts/identity.mjs';
|
|
2
3
|
import {
|
|
3
4
|
buildCodexRolloutTrimSource,
|
|
4
5
|
parseCodexRolloutFile,
|
|
@@ -122,7 +123,7 @@ export async function run(args) {
|
|
|
122
123
|
const inflightMemo = parsed.memoStdin ? await readStdin() : null;
|
|
123
124
|
const db = getDb();
|
|
124
125
|
const trimSource =
|
|
125
|
-
parsed.host ===
|
|
126
|
+
parsed.host === CODEX_HOST && parsed.codexThreadId
|
|
126
127
|
? buildCodexRolloutTrimSource({
|
|
127
128
|
threadId: parsed.codexThreadId,
|
|
128
129
|
projectPath: process.cwd(),
|
|
@@ -376,7 +377,7 @@ async function runPreflight(parsed, plan) {
|
|
|
376
377
|
}
|
|
377
378
|
|
|
378
379
|
function validateCodexAction(parsed, plan, action) {
|
|
379
|
-
if (parsed.host !==
|
|
380
|
+
if (parsed.host !== CODEX_HOST) {
|
|
380
381
|
return {
|
|
381
382
|
status: `${action}-refused`,
|
|
382
383
|
reason: `${action}_requires_codex_host`,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import {
|
|
2
|
+
import { foldPathCaseForPlatform } from './os/paths.mjs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
3
4
|
import { join, resolve } from 'node:path';
|
|
4
5
|
|
|
5
6
|
import { runCodexTrimExecution } from './codex-app-server.mjs';
|
|
@@ -509,8 +510,7 @@ function normalizeProjectPath(value) {
|
|
|
509
510
|
if (typeof value !== 'string' || value.length === 0) return '';
|
|
510
511
|
let result = resolve(value).replace(/\\/g, '/');
|
|
511
512
|
if (result.length > 1 && result.endsWith('/')) result = result.slice(0, -1);
|
|
512
|
-
|
|
513
|
-
return result;
|
|
513
|
+
return foldPathCaseForPlatform(result);
|
|
514
514
|
}
|
|
515
515
|
|
|
516
516
|
function numberOrNull(value) {
|
package/src/codex-sidecar.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawnPortableSync } from './os/portable-spawn-sync.mjs';
|
|
2
|
+
import { isWin32Platform } from './os/paths.mjs';
|
|
2
3
|
|
|
3
4
|
export const CODEX_SIDECAR_WORKFLOWS = Object.freeze([
|
|
4
5
|
'review',
|
|
@@ -23,7 +24,7 @@ function resolveCommand({ command, env }) {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
export function shouldShellWrapSidecarCommand(platform = process.platform) {
|
|
26
|
-
return platform
|
|
27
|
+
return isWin32Platform(platform);
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
export function runCodexSidecarCommand(command, args, options = {}) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { CLAUDE_HOST } from './hosts/identity.mjs';
|
|
2
3
|
import {
|
|
3
4
|
chmodSync,
|
|
4
5
|
lstatSync,
|
|
@@ -8,12 +9,12 @@ import {
|
|
|
8
9
|
rmSync,
|
|
9
10
|
writeFileSync,
|
|
10
11
|
} from 'node:fs';
|
|
11
|
-
import { homedir } from 'node:os';
|
|
12
12
|
import { dirname, join } from 'node:path';
|
|
13
13
|
import { DatabaseSync } from 'node:sqlite';
|
|
14
14
|
import { hashAuditorBody } from './body-digest.mjs';
|
|
15
15
|
import { normalizeProjectPathForCompare } from './project-path.mjs';
|
|
16
16
|
import { applyAndVerifyWindowsAcl, isWindows, verifyWindowsAcl } from './os/windows-acl.mjs';
|
|
17
|
+
import { windowsLocalAppData, xdgStateHome } from './os/app-dirs.mjs';
|
|
17
18
|
|
|
18
19
|
export const COMPLETED_TURN_RECEIPT_STORE_SCHEMA = 'throughline.completed_turn_receipts.v1';
|
|
19
20
|
export const COMPLETED_TURN_RECEIPT_SCHEMA_VERSION = '1.0';
|
|
@@ -24,11 +25,10 @@ const PRIVATE_DIRECTORY_CAPABILITY = Symbol('throughline.completed-turn-receipt-
|
|
|
24
25
|
|
|
25
26
|
export function defaultCompletedTurnReceiptStorePath(projectSha256, env = process.env) {
|
|
26
27
|
if (!isSha256(projectSha256)) throw new TypeError('projectSha256 must be a SHA-256 digest');
|
|
27
|
-
const home = env.HOME || env.USERPROFILE || homedir();
|
|
28
28
|
if (isWindows(env)) {
|
|
29
|
-
return join(env
|
|
29
|
+
return join(windowsLocalAppData(env), 'throughline', 'completed-turn-receipts', `${projectSha256}.json`);
|
|
30
30
|
}
|
|
31
|
-
return join(env
|
|
31
|
+
return join(xdgStateHome(env), 'throughline', 'completed-turn-receipts', `${projectSha256}.json`);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/**
|
|
@@ -273,7 +273,7 @@ function validateReceipt(receipt, nextSequence) {
|
|
|
273
273
|
];
|
|
274
274
|
if (!receipt || typeof receipt !== 'object' || Array.isArray(receipt) ||
|
|
275
275
|
!exactKeys(receipt, keys) || receipt.schema_version !== COMPLETED_TURN_RECEIPT_SCHEMA_VERSION ||
|
|
276
|
-
receipt.host !==
|
|
276
|
+
receipt.host !== CLAUDE_HOST || !isSha256(receipt.project_sha256) ||
|
|
277
277
|
!isIdentity(receipt.target_session_id) || !isIdentity(receipt.origin_session_id) ||
|
|
278
278
|
!isSha256(receipt.user_sha256) || !isSha256(receipt.assistant_sha256) ||
|
|
279
279
|
!Number.isSafeInteger(receipt.completed_at) || receipt.completed_at < 0 ||
|
package/src/hosts/identity.mjs
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* os/app-dirs.mjs — OS別のユーザー設定/状態ベースディレクトリ解決
|
|
3
|
+
*
|
|
4
|
+
* LOCALAPPDATA(Windows)と XDG_CONFIG_HOME / XDG_STATE_HOME(POSIX)の
|
|
5
|
+
* フォールバック組み立てが runtime-error-store と completed-turn-receipts に
|
|
6
|
+
* 別々に書かれていたため、ここへ集約する。最終的なアプリ別 join は呼び出し側が持つ。
|
|
7
|
+
*/
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
|
|
11
|
+
function homeOf(env) {
|
|
12
|
+
return env.HOME || env.USERPROFILE || homedir();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function windowsLocalAppData(env = process.env) {
|
|
16
|
+
return env.LOCALAPPDATA || join(homeOf(env), 'AppData', 'Local');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function xdgConfigHome(env = process.env) {
|
|
20
|
+
return env.XDG_CONFIG_HOME || join(homeOf(env), '.config');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function xdgStateHome(env = process.env) {
|
|
24
|
+
return env.XDG_STATE_HOME || join(homeOf(env), '.local', 'state');
|
|
25
|
+
}
|
package/src/os/paths.mjs
CHANGED
|
@@ -10,3 +10,7 @@ import { platform } from 'node:os';
|
|
|
10
10
|
export function foldPathCaseForPlatform(path, { hostPlatform = platform() } = {}) {
|
|
11
11
|
return hostPlatform === 'win32' ? path.toLowerCase() : path;
|
|
12
12
|
}
|
|
13
|
+
|
|
14
|
+
export function isWin32Platform(hostPlatform = platform()) {
|
|
15
|
+
return hostPlatform === 'win32';
|
|
16
|
+
}
|
|
@@ -10,12 +10,13 @@ import {
|
|
|
10
10
|
writeFileSync,
|
|
11
11
|
} from 'node:fs';
|
|
12
12
|
import childProcess from 'node:child_process';
|
|
13
|
-
import { arch as hostArch,
|
|
13
|
+
import { arch as hostArch, platform as hostPlatform } from 'node:os';
|
|
14
14
|
import { dirname, join } from 'node:path';
|
|
15
15
|
import { createRequire } from 'node:module';
|
|
16
16
|
import { fileURLToPath } from 'node:url';
|
|
17
17
|
import { DatabaseSync } from 'node:sqlite';
|
|
18
18
|
import { applyAndVerifyWindowsAcl, isWindows, verifyWindowsAcl } from './os/windows-acl.mjs';
|
|
19
|
+
import { windowsLocalAppData, xdgConfigHome, xdgStateHome } from './os/app-dirs.mjs';
|
|
19
20
|
|
|
20
21
|
const require = createRequire(import.meta.url);
|
|
21
22
|
const PACKAGE_VERSION = require('../package.json').version;
|
|
@@ -53,19 +54,17 @@ const DEFINITIONS = Object.freeze({
|
|
|
53
54
|
});
|
|
54
55
|
|
|
55
56
|
export function defaultFactoryReporterConfigPath(env = process.env) {
|
|
56
|
-
const home = env.HOME || env.USERPROFILE || homedir();
|
|
57
57
|
if (isWindows(env)) {
|
|
58
|
-
return join(env
|
|
58
|
+
return join(windowsLocalAppData(env), 'dotagents', 'factory-reporter', 'config.json');
|
|
59
59
|
}
|
|
60
|
-
return join(env
|
|
60
|
+
return join(xdgConfigHome(env), 'dotagents', 'factory-reporter.json');
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export function defaultRuntimeErrorStorePath(env = process.env) {
|
|
64
|
-
const home = env.HOME || env.USERPROFILE || homedir();
|
|
65
64
|
if (isWindows(env)) {
|
|
66
|
-
return join(env
|
|
65
|
+
return join(windowsLocalAppData(env), 'throughline', 'runtime-errors.json');
|
|
67
66
|
}
|
|
68
|
-
return join(env
|
|
67
|
+
return join(xdgStateHome(env), 'throughline', 'runtime-errors.json');
|
|
69
68
|
}
|
|
70
69
|
|
|
71
70
|
export function isRuntimeErrorCollectionEnabled({ env = process.env, configPath } = {}) {
|
package/src/trim-model.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { inspectCodexPlannedRollbackRestoreSafety } from './codex-rollout-memory.mjs';
|
|
2
|
+
import { CLAUDE_HOST, CODEX_HOST } from './hosts/identity.mjs';
|
|
2
3
|
import { buildHandoffRecord, N_RECENT_L2 } from './handoff-record.mjs';
|
|
3
4
|
import { sameProjectPath } from './project-path.mjs';
|
|
4
5
|
import { estimateTokens } from './token-estimator.mjs';
|
|
@@ -48,7 +49,7 @@ export function findLatestSessionIdForProject(db, projectPath) {
|
|
|
48
49
|
|
|
49
50
|
function resolveDefaultSessionId({ sessionId, host, codexThreadId, db, projectPath }) {
|
|
50
51
|
if (sessionId) return sessionId;
|
|
51
|
-
if (host ===
|
|
52
|
+
if (host === CODEX_HOST) {
|
|
52
53
|
return codexThreadId ? `codex:${codexThreadId}` : null;
|
|
53
54
|
}
|
|
54
55
|
return findLatestSessionIdForProject(db, projectPath);
|
|
@@ -79,7 +80,7 @@ function countDistinctCapturedTurns(db, sessionId) {
|
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
export function describeTrimHost(host) {
|
|
82
|
-
if (host ===
|
|
83
|
+
if (host === CLAUDE_HOST) {
|
|
83
84
|
return {
|
|
84
85
|
host,
|
|
85
86
|
automaticRollback: false,
|
|
@@ -94,7 +95,7 @@ export function describeTrimHost(host) {
|
|
|
94
95
|
};
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
if (host ===
|
|
98
|
+
if (host === CODEX_HOST) {
|
|
98
99
|
return {
|
|
99
100
|
host,
|
|
100
101
|
automaticRollback: true,
|
|
@@ -123,7 +124,7 @@ export function describeTrimHost(host) {
|
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
function buildSafeContinuation({ host, hostIdentity }) {
|
|
126
|
-
if (host !==
|
|
127
|
+
if (host !== CODEX_HOST) return null;
|
|
127
128
|
|
|
128
129
|
const threadId = hostIdentity?.codexThreadId ?? '<thread-id>';
|
|
129
130
|
const sessionId = threadId === '<thread-id>' ? 'codex:<thread-id>' : `codex:${threadId}`;
|
|
@@ -561,7 +562,7 @@ function buildPlanSession({ resolvedSessionId, session, trimSource, projectPath
|
|
|
561
562
|
}
|
|
562
563
|
|
|
563
564
|
function buildHostIdentity({ host, codexThreadId, codexThreadIdSource = null }) {
|
|
564
|
-
if (host !==
|
|
565
|
+
if (host !== CODEX_HOST) {
|
|
565
566
|
return {
|
|
566
567
|
host,
|
|
567
568
|
codexThreadId: null,
|