throughline 0.8.0 → 0.8.1
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 +10 -0
- package/README.ja.md +74 -42
- package/README.md +27 -21
- package/docs/adr/0016-push-pull-recall-injection.md +12 -0
- package/package.json +1 -1
- package/src/cli/factory-diagnostics.test.mjs +10 -1
- package/src/factory-diagnostics.mjs +3 -1
- package/src/factory-diagnostics.test.mjs +17 -0
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,16 @@ shipped to npm but were not individually tagged on GitHub.
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **Native factory diagnostics now report the database compatibility label from
|
|
16
|
+
the canonical schema version.** Throughline schema v9 previously emitted the
|
|
17
|
+
stale `throughline.database.v8` label alongside numeric versions `9`/`9`, so
|
|
18
|
+
exact factory reporters correctly classified the installation as
|
|
19
|
+
incompatible. The label is now derived from the DB migration version and a
|
|
20
|
+
regression test requires the label, actual version, and supported version to
|
|
21
|
+
stay aligned on future schema bumps.
|
|
22
|
+
|
|
13
23
|
## [0.8.0] — 2026-07-18
|
|
14
24
|
|
|
15
25
|
### Changed (breaking behavior)
|
package/README.ja.md
CHANGED
|
@@ -29,10 +29,14 @@ throughline install # hook / Codex skill / VS Code monitor task を登録
|
|
|
29
29
|
<details>
|
|
30
30
|
<summary><b>Codex も併用する場合</b> Codex hooks も登録される — クリックで詳細</summary>
|
|
31
31
|
|
|
32
|
-
Codex
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
global install は Codex の `UserPromptSubmit` / `PostToolUse` / `Stop` hook
|
|
33
|
+
(絶対 node パス登録)と `$throughline` skill も登録する。これらの hook は
|
|
34
|
+
rollout capture と monitor state 書き込みだけを行い、**使用量閾値での
|
|
35
|
+
`$throughline` 自動注入はしない**(token-monitor は表示専用)。bare
|
|
36
|
+
`$throughline` は app-server 経由で新規 Codex thread を開始し、Throughline DB
|
|
37
|
+
の handoff memory を developer item として注入する。current-thread rollback
|
|
38
|
+
診断が要る時だけ明示的に `trim --execute --host codex` を使う。既存の
|
|
39
|
+
非 Throughline Codex hook は保持される。
|
|
36
40
|
|
|
37
41
|
</details>
|
|
38
42
|
|
|
@@ -42,7 +46,7 @@ skill も登録する。75% 自動発火は token-monitor 依存ではなく、
|
|
|
42
46
|
|---|---|---|---|---|
|
|
43
47
|
| **何をする** | ツール I/O を SQLite に退避、本文は残す | ウィンドウを全消去 | ウィンドウ全体を LLM 要約 | 新旧で要約 |
|
|
44
48
|
| **圧縮の軸** | コンテンツの **種類** (テキスト vs ツール I/O) | 無し — 全消去 | **新旧** (一律) | **新旧** (一律) |
|
|
45
|
-
| **境界後に残る記憶** | ✅
|
|
49
|
+
| **境界後に残る記憶** | ✅ 直近ターン本文そのまま (予算内ターン原子詰め) + それ以前は `recall` で pull + L3 オンデマンド | ❌ ゼロ | △ 一個の要約 (情報欠落) | △ 要約 (情報欠落) |
|
|
46
50
|
| **ツール I/O の扱い** | L3 に退避、`/sc-detail HH:MM:SS` で取り戻せる | 消える | 要約に溶けて読めない | 要約に溶ける |
|
|
47
51
|
| **コーディング用途への適合** | 高 — ツール I/O こそ重い 80% | 低 — 文脈が切れる | 中 — ただし不可逆 | 中 |
|
|
48
52
|
| **誤継承リスク** | 低 (typed `/clear` / `/tl` が前任を指名) | n/a | n/a | 高 |
|
|
@@ -73,10 +77,10 @@ Throughline 無し (50 ターン、/clear なし):
|
|
|
73
77
|
≈ 125,000 tok 合計
|
|
74
78
|
|
|
75
79
|
Throughline 有り (50 ターン → /clear → 再開):
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
ツール I/O 0 tok
|
|
79
|
-
≈ 13,000 tok — 90% 軽量
|
|
80
|
+
再開注入 ~3,000 tok ▌ (直近 L2 ターン丸ごと、≤9,500 字)
|
|
81
|
+
それ以前の記憶 0〜10,000 tok (必要な時だけ recall --l2 / --l1 で pull)
|
|
82
|
+
ツール I/O 0 tok (SQLite 退避、detail でオンデマンド取得)
|
|
83
|
+
≈ 最大 13,000 tok — 90% 軽量
|
|
80
84
|
```
|
|
81
85
|
|
|
82
86
|
MemGPT や LangChain の SummaryBufferMemory が **新旧** で圧縮するのに対し、
|
|
@@ -94,7 +98,7 @@ Throughline は加えて、トランスクリプト JSONL から実測 API 使
|
|
|
94
98
|
|
|
95
99
|
---
|
|
96
100
|
|
|
97
|
-
## 3 層メモリーモデル (schema
|
|
101
|
+
## 3 層メモリーモデル (schema v9)
|
|
98
102
|
|
|
99
103
|
```mermaid
|
|
100
104
|
flowchart LR
|
|
@@ -102,10 +106,11 @@ flowchart LR
|
|
|
102
106
|
T --> H["Stop hook"]
|
|
103
107
|
H --> L2[("L2 · bodies<br/>本文そのまま")]
|
|
104
108
|
H --> L3[("L3 · details<br/>ツール I/O · 思考")]
|
|
105
|
-
H -. "非同期<br
|
|
109
|
+
H -. "非同期<br/>要約器" .-> L1[("L1 · skeletons<br/>一行要約")]
|
|
106
110
|
|
|
107
|
-
L2 -- "
|
|
108
|
-
|
|
111
|
+
L2 -- "直近ターン丸ごと<br/>(9,500 字予算)" --> S["次セッション<br/>初回プロンプト注入"]
|
|
112
|
+
L2 -. "窓の残り<br/>throughline recall --l2" .-> S
|
|
113
|
+
L1 -. "それ以前すべて<br/>throughline recall --l1" .-> S
|
|
109
114
|
L3 -. "オンデマンド · throughline detail" .-> S
|
|
110
115
|
|
|
111
116
|
classDef l1 fill:#3aa0ff,stroke:#1a1f2e,color:#fff
|
|
@@ -118,28 +123,35 @@ flowchart LR
|
|
|
118
123
|
|
|
119
124
|
| 層 | 名称 | 保存先 | 内容 | ターンあたりコスト |
|
|
120
125
|
| --- | --- | --- | --- | --- |
|
|
121
|
-
| **L1** | スケルトン |
|
|
122
|
-
| **L2** | ボディ |
|
|
126
|
+
| **L1** | スケルトン | `recall --l1` でオンデマンド pull | ターンの一行要約(既定 backend は Codex CLI `gpt-5.6-luna`、fallback は ADR 0015 参照) | 約 10 トークン |
|
|
127
|
+
| **L2** | ボディ | 予算内は注入、残りは `recall --l2` | ユーザー本文 + アシスタント返答そのまま | 自然なフルサイズ |
|
|
123
128
|
| **L3** | ディテール | SQLite のみ | ツール I/O、システムメッセージ、画像、**拡張思考** (オンデマンド) | 重い、退避済 |
|
|
124
129
|
|
|
125
130
|
3 層は **互いに補完的かつ排他的** で、重複保存はありません。
|
|
126
131
|
拡張思考ブロックは L3 (`kind='thinking'`) に格納されるので、次セッションは
|
|
127
132
|
**前セッションの Claude が中断時に何を考えていたか** を、発話だけでなく
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
-
|
|
133
|
+
内省レベルで参照できます。思考は注入されず、`throughline detail <時刻>` で
|
|
134
|
+
いつでも取得できます。
|
|
135
|
+
|
|
136
|
+
次セッションの **初回ユーザープロンプト** 時(二相ハンドオフ、ADR 0014)、
|
|
137
|
+
Throughline は SQLite からコンテキストを再構築し、プレーンテキストとして
|
|
138
|
+
注入します(push/pull 設計、ADR 0016):
|
|
139
|
+
|
|
140
|
+
- **直近ターン** を L2 (`bodies`) のフル本文として注入 — 新しい順に
|
|
141
|
+
ターン丸ごと(user + assistant 原子)、約 9,500 字の予算に入るだけ
|
|
142
|
+
- **L1 (`skeletons`) の一行要約は注入しません** — 代わりに、そのまま実行
|
|
143
|
+
できる `throughline recall --l2|--l1` コマンド入りの案内セクションを注入し、
|
|
144
|
+
古い記憶は必要になった時だけ pull します
|
|
136
145
|
- L3 は SQLite に残り、`/sc-detail <時刻>` でオンデマンド取得
|
|
137
146
|
|
|
138
147
|
L1 要約は遅延実行で、20 ターン未満で終わるセッションでは外部要約器を呼ばず、
|
|
139
|
-
|
|
140
|
-
`
|
|
141
|
-
Claude
|
|
142
|
-
|
|
148
|
+
短いタスクの要約コストはゼロです。要約は **削減割合**(既定 1/5、
|
|
149
|
+
`THROUGHLINE_L1_RATIO` で変更可。不正値は明示エラー)を目標にします。
|
|
150
|
+
Claude-primary 経路の backend 順は codex-sidecar(`summarize-l1` preset 明示
|
|
151
|
+
設定時)→ **Codex CLI**(既定 `gpt-5.6-luna`@`low`、実測評価で選定 — ADR 0015。
|
|
152
|
+
`THROUGHLINE_L1_MODEL` / `THROUGHLINE_L1_EFFORT` で変更可)→ **Claude Haiku 4.5**
|
|
153
|
+
(`claude -p` サブプロセス、Claude Max のログイン認証流用)で、API キーは
|
|
154
|
+
不要です。各段の失敗理由は記録されます。
|
|
143
155
|
|
|
144
156
|
3 層 (L1/L2/L3) の書き込みパスは schema v5 から動作しています。
|
|
145
157
|
`/sc-detail HH:MM:SS` はユーザー / アシスタント本文 (L2) と、そのターンで
|
|
@@ -158,13 +170,14 @@ flowchart LR
|
|
|
158
170
|
U["ユーザーが入力<br/>/clear または /tl"] -->|UserPromptSubmit| W["writeBaton<br/>(session_id + TTL 1h)"]
|
|
159
171
|
W --> B[("handoff_batons<br/>SQLite")]
|
|
160
172
|
M["VS Code メニュー<br/>clear"] -->|UserPromptSubmit に届かない| X["baton 無し"]
|
|
161
|
-
NS["次の SessionStart"] -->
|
|
173
|
+
NS["次の SessionStart<br/>(intent 登録のみ)"] --> FP["初回ユーザープロンプト<br/>(実セッションの証明)"]
|
|
174
|
+
FP --> C{"baton<br/>あり?"}
|
|
162
175
|
B -.-> C
|
|
163
176
|
X -.-> C
|
|
164
177
|
C -->|あり| P1["baton path<br/>(主経路)<br/>指名された前任を merge"]
|
|
165
|
-
C -->|無し / source='clear'| P2["auto path<br/>(補助)<br
|
|
178
|
+
C -->|無し / source='clear'| P2["auto path<br/>(補助)<br/>前任は SessionStart 時点で凍結"]
|
|
166
179
|
C -->|無し / source!='clear'| P3["新規セッション<br/>merge 無し"]
|
|
167
|
-
P1 --> INJ["
|
|
180
|
+
P1 --> INJ["L2 ターン + recall 案内を注入<br/>(予算 ≤ 9,500 字)"]
|
|
168
181
|
P2 --> INJ
|
|
169
182
|
|
|
170
183
|
classDef primary fill:#7c5cff,stroke:#1a1f2e,color:#fff
|
|
@@ -178,16 +191,26 @@ flowchart LR
|
|
|
178
191
|
### baton path (primary): typed `/clear` または `/tl`
|
|
179
192
|
|
|
180
193
|
ユーザーが prompt に `/clear` または `/tl` を打つと、UserPromptSubmit hook が
|
|
181
|
-
**そのセッションの** `session_id` を `handoff_batons`
|
|
182
|
-
|
|
194
|
+
**そのセッションの** `session_id` を `handoff_batons` に書きます。次の新セッション
|
|
195
|
+
は **初回ユーザープロンプト時** に baton を消費し(適格性: セッション誕生が baton
|
|
196
|
+
書き込みから TTL 1 時間以内)、その前任を確定的に merge します。
|
|
183
197
|
複数ウィンドウで「最新更新セッション」と「今 `/clear` したセッション」が違っても、
|
|
184
198
|
指名された前任だけを引き継ぎます。
|
|
185
199
|
|
|
200
|
+
なぜ SessionStart でなく初回プロンプトか: Claude Code は同一 project に数百 ms の
|
|
201
|
+
間隔で複数の SessionStart を発火させることがあり、その一部は transcript を一切
|
|
202
|
+
作らない**幽霊セッション**になります。SessionStart 時点では実体と幽霊を判別
|
|
203
|
+
できないため、baton を SessionStart で消費すると幽霊が記憶を飲み込み、実セッション
|
|
204
|
+
が空で始まる事故が起きます。幽霊はプロンプトを発火しないので、消費を初回
|
|
205
|
+
プロンプトへ遅延させればこの事故は構造的に起きません(二相ハンドオフ、ADR 0014)。
|
|
206
|
+
|
|
186
207
|
### auto path (fallback): `source='clear'`
|
|
187
208
|
|
|
188
209
|
baton が無く、SessionStart の `source='clear'` が届いた場合だけ、同 project の
|
|
189
|
-
最新 Claude predecessor
|
|
190
|
-
|
|
210
|
+
最新 Claude predecessor を **SessionStart 時点で** 解決・凍結し(transcript の
|
|
211
|
+
無い幽霊は候補から除外)、merge + 注入は初回プロンプト時に行います。これは
|
|
212
|
+
VS Code 拡張メニューなど、typed `/clear` が UserPromptSubmit hook に届かない
|
|
213
|
+
経路のための補助です。
|
|
191
214
|
|
|
192
215
|
`THROUGHLINE_DISABLE_AUTO_HANDOFF=1` はこの fallback path だけを OFF にします。
|
|
193
216
|
typed `/clear` と `/tl` はユーザーの明示意思なので、この env に関係なく baton を
|
|
@@ -201,11 +224,18 @@ fallback: baton 無し + source='clear' → latest predecessor を merge
|
|
|
201
224
|
|
|
202
225
|
### 注入されるもの
|
|
203
226
|
|
|
204
|
-
両経路で同じ curated memory
|
|
227
|
+
両経路で同じ curated memory が注入されます(push/pull 設計、ADR 0016):
|
|
205
228
|
|
|
206
|
-
-
|
|
207
|
-
|
|
208
|
-
-
|
|
229
|
+
- **「現在地」アンカー** (v0.4.12〜) — 最新のユーザー指示と最新の assistant turn を
|
|
230
|
+
ヘッダ直下に再掲(各 600 字で切り詰め)
|
|
231
|
+
- **pull 案内セクション**(無条件表示)— そのまま実行できる `throughline recall`
|
|
232
|
+
コマンド。session id・ISO ms 境界・件数は注入時に焼き込み済み
|
|
233
|
+
- L2 verbatim — 約 9,500 字の注入予算に入るだけ、新しい turn からターン丸ごと
|
|
234
|
+
詰める(典型 7〜8 turn、軽い会話ならもっと多い)。**L1 サマリーは注入しません**
|
|
235
|
+
— 20 turn 窓の残りは `recall --l2` で全文、それより古い全 turn は `recall --l1`
|
|
236
|
+
で取得(要約済みは L1 行、未要約は `throughline detail` への誘導付きで明示)
|
|
237
|
+
- L3 references (`throughline detail <時刻>` で引き出すコマンド、各 L2 行末尾に
|
|
238
|
+
inline 付記。本文は SQLite に残置)
|
|
209
239
|
|
|
210
240
|
注入は **「中断されたタスクの再開」** として再フレーミングされます。L2 verbatim に
|
|
211
241
|
最終 assistant turn (= 次に何をしようとしていたか) が含まれるため、別途 memo /
|
|
@@ -231,14 +261,14 @@ slash command / transcript / baton / resume behavior を置き換えるもので
|
|
|
231
261
|
adapter / projection として追加されます。
|
|
232
262
|
|
|
233
263
|
現時点で core Throughline が外部モデルを呼ぶのは L2→L1 要約だけです。
|
|
234
|
-
|
|
235
|
-
|
|
264
|
+
backend 順は codex-sidecar(`summarize-l1` preset 明示設定時)→ Codex CLI
|
|
265
|
+
(既定 `gpt-5.6-luna`)→ Claude Haiku です(ADR 0015)。
|
|
236
266
|
|
|
237
267
|
Codex 側 trim (= same-thread context trim) は `throughline trim --execute --host codex`
|
|
238
268
|
で発火します。Codex の bare `$throughline` skill もこの scripted rollback + DB
|
|
239
269
|
memory inject を直接実行します。Claude 側は `/clear` での auto path 引継ぎが本線になったため、
|
|
240
270
|
`/tl-trim` slash command は v0.4.0 で廃止されました。current-work framing は
|
|
241
|
-
|
|
271
|
+
再開注入の Reading Contract / Continuation Instruction で同じ意図を
|
|
242
272
|
継承しています。
|
|
243
273
|
|
|
244
274
|
</details>
|
|
@@ -285,6 +315,7 @@ Throughline state をまだ書いていない現在セッションも表示で
|
|
|
285
315
|
| `throughline monitor` | マルチセッション監視を起動 |
|
|
286
316
|
| `throughline monitor --diag` | TTY/columns/env 診断ダンプ (描画バグ切り分け用) |
|
|
287
317
|
| `throughline detail <時刻>` | あるターンの L2 本文と L3 ツール I/O を取得 (Claude が使う) |
|
|
318
|
+
| `throughline recall --l2\|--l1 --session <id> --before <ISO> ...` | 注入の案内セクションが指す古い記憶を pull (read-only、正確なコマンドは注入に焼き込み済み) |
|
|
288
319
|
| `throughline doctor` | Node バージョン、hook 登録状況、DB、PATH をチェック |
|
|
289
320
|
| `throughline doctor --trim --host claude` | trim boundary と手動手順を診断 |
|
|
290
321
|
| `throughline handoff-preview --session <id>` | Codex 向け `throughline_handoff` JSON projection を表示 |
|
|
@@ -313,7 +344,8 @@ Throughline state をまだ書いていない現在セッションも表示で
|
|
|
313
344
|
|
|
314
345
|
- **Node.js 22.5 以上** (組み込み `node:sqlite` モジュール使用、ネイティブビルド不要)
|
|
315
346
|
- **Claude Code** (`SessionStart`, `Stop`, `UserPromptSubmit` hooks 対応版)
|
|
316
|
-
- **
|
|
347
|
+
- **Codex CLI ログイン**(既定の L1 要約 backend、`gpt-5.6-luna`)または
|
|
348
|
+
**Claude Max サブスクリプション**(`claude -p` 経由の Haiku fallback)— どちらも API キー不要
|
|
317
349
|
- 対応 OS: **Windows / macOS / Linux**
|
|
318
350
|
|
|
319
351
|
ランタイム依存 **ゼロ**。npm パッケージは純 `.mjs` ファイルのみで構成されています。
|
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ guarded `trim --execute --host codex` surface.
|
|
|
54
54
|
|---|---|---|---|---|
|
|
55
55
|
| **What it does** | retire tool I/O to SQLite, keep text in-context | wipe the whole window | LLM-summarize the whole window | recency-based summarize |
|
|
56
56
|
| **Compression axis** | content **type** (text vs tool I/O) | none — full wipe | **recency** (uniform) | **recency** (uniform) |
|
|
57
|
-
| **Memory after the boundary** | ✅ recent
|
|
57
|
+
| **Memory after the boundary** | ✅ recent turns verbatim (whole, budget-packed) + everything older via `recall` pull + L3 on demand | ❌ zero | △ lossy single summary | △ lossy summary |
|
|
58
58
|
| **Tool I/O handling** | retired to L3, retrievable by `/sc-detail HH:MM:SS` | gone | folded into summary, unreadable | folded into summary |
|
|
59
59
|
| **Coding-assistant fit** | high — tool I/O is the heavy 80% | low — you lose the thread | medium — but irreversible | medium |
|
|
60
60
|
| **Auto-inheritance risk** | low (typed `/clear` / `/tl` names the predecessor) | n/a | n/a | high |
|
|
@@ -86,10 +86,10 @@ Without Throughline (50 turns, no /clear):
|
|
|
86
86
|
≈ 125,000 tok total
|
|
87
87
|
|
|
88
88
|
With Throughline (50 turns → /clear → resume):
|
|
89
|
-
recent
|
|
90
|
-
older
|
|
91
|
-
tool I/O 0 tok
|
|
92
|
-
≈ 13,000 tok
|
|
89
|
+
resume injection ~3,000 tok ▌ (recent L2 turns, whole, ≤ 9,500 chars)
|
|
90
|
+
older memory 0–10,000 tok (pulled only when needed: recall --l2 / --l1)
|
|
91
|
+
tool I/O 0 tok (retired to SQLite, on-demand via detail)
|
|
92
|
+
≈ 13,000 tok worst case — 90% lighter
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
Throughline separates conversation content by **type, not time**: human-readable
|
|
@@ -117,10 +117,11 @@ flowchart LR
|
|
|
117
117
|
T --> H["Stop hook"]
|
|
118
118
|
H --> L2[("L2 · bodies<br/>verbatim text")]
|
|
119
119
|
H --> L3[("L3 · details<br/>tool I/O · thinking")]
|
|
120
|
-
H -. "async<br/>
|
|
120
|
+
H -. "async<br/>summarizer" .-> L1[("L1 · skeletons<br/>one-liners")]
|
|
121
121
|
|
|
122
|
-
L2 -- "recent
|
|
123
|
-
|
|
122
|
+
L2 -- "recent turns, whole<br/>(9,500-char budget)" --> S["Next session's first prompt<br/>injection"]
|
|
123
|
+
L2 -. "rest of the window<br/>throughline recall --l2" .-> S
|
|
124
|
+
L1 -. "everything older<br/>throughline recall --l1" .-> S
|
|
124
125
|
L3 -. "on demand · throughline detail" .-> S
|
|
125
126
|
|
|
126
127
|
classDef l1 fill:#3aa0ff,stroke:#1a1f2e,color:#fff
|
|
@@ -133,22 +134,25 @@ flowchart LR
|
|
|
133
134
|
|
|
134
135
|
| Layer | Name | Where it lives | Content | Cost per turn |
|
|
135
136
|
| ----- | ---------- | --------------------- | --------------------------------------------------------------------- | ------------- |
|
|
136
|
-
| **L1** | Skeleton |
|
|
137
|
-
| **L2** | Body | injected
|
|
137
|
+
| **L1** | Skeleton | pulled on demand (`recall --l1`) | one-line summary of the turn (default backend: Codex CLI `gpt-5.6-luna`, fallbacks per ADR 0015) | ~10 tok |
|
|
138
|
+
| **L2** | Body | injected while the budget lasts; rest via `recall --l2` | user text + assistant reply, verbatim | full natural |
|
|
138
139
|
| **L3** | Detail | SQLite only | tool I/O, system messages, images, **extended thinking** (on-demand) | heavy, retired |
|
|
139
140
|
|
|
140
141
|
The layers are **complementary and disjoint** — nothing is duplicated across
|
|
141
142
|
them. Extended thinking blocks are stored at L3 (`kind='thinking'`) so the
|
|
142
143
|
next session can see *what the previous Claude was thinking* at the moment it
|
|
143
|
-
was interrupted, not just what it said aloud.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
- The **most recent
|
|
151
|
-
-
|
|
144
|
+
was interrupted, not just what it said aloud. Thinking is never injected —
|
|
145
|
+
it stays retrievable via `throughline detail <time>`.
|
|
146
|
+
|
|
147
|
+
At the **first user prompt** of the next session (two-phase handoff, ADR
|
|
148
|
+
0014), Throughline rebuilds the context from SQLite and injects it as plain
|
|
149
|
+
text (push/pull design, ADR 0016):
|
|
150
|
+
|
|
151
|
+
- The **most recent turns** are injected as full L2 (`bodies`) text — packed
|
|
152
|
+
whole-turn, newest-first, as many as fit the ~9,500-char budget
|
|
153
|
+
- **L1 (`skeletons`) one-liners are not injected** — a guidance section with
|
|
154
|
+
ready-to-run `throughline recall --l2|--l1` commands is injected instead,
|
|
155
|
+
so older memory is pulled only when needed
|
|
152
156
|
- L3 stays in SQLite and is retrieved on demand via `/sc-detail <time>`
|
|
153
157
|
|
|
154
158
|
L1 summaries are generated lazily: for sessions that stay under 20 turns, no
|
|
@@ -189,7 +193,7 @@ flowchart LR
|
|
|
189
193
|
C -->|yes| P1["baton path<br/>(primary)<br/>merge that exact predecessor"]
|
|
190
194
|
C -->|no, source='clear'| P2["auto path<br/>(fallback)<br/>predecessor frozen at SessionStart"]
|
|
191
195
|
C -->|no, source!='clear'| P3["fresh session<br/>no merge"]
|
|
192
|
-
P1 --> INJ["inject
|
|
196
|
+
P1 --> INJ["inject L2 turns + recall guidance<br/>(budgeted ≤ 9,500 chars)"]
|
|
193
197
|
P2 --> INJ
|
|
194
198
|
|
|
195
199
|
classDef primary fill:#7c5cff,stroke:#1a1f2e,color:#fff
|
|
@@ -895,7 +899,9 @@ throughline auditor-context --session claude-session-id --project "$PWD" \
|
|
|
895
899
|
- **Node.js >= 22.13** (for the stable, flag-free built-in `node:sqlite` module — no native build
|
|
896
900
|
required, no `npm install` of SQLite bindings)
|
|
897
901
|
- **Claude Code** with hooks support (`SessionStart`, `Stop`)
|
|
898
|
-
- **
|
|
902
|
+
- **Codex CLI login** (default L1 summarization backend, `gpt-5.6-luna`) or a
|
|
903
|
+
**Claude Max subscription** (Haiku fallback via `claude -p`) — no API key
|
|
904
|
+
either way
|
|
899
905
|
- Works on **Windows, macOS, Linux**
|
|
900
906
|
|
|
901
907
|
Throughline has **zero runtime dependencies**. The published tarball is just
|
|
@@ -73,6 +73,18 @@ assistant 行だけ入り user 行が pull 側に半身で現れ、境界の算
|
|
|
73
73
|
- 焼き込まれた案内コマンドをそのまま実行して、`--l2` が境界ぴったりから 11 ターン
|
|
74
74
|
(33k 字)、`--l1` が全 171 ターン一覧(118k 字、`--last` で部分取得可)を返すことを確認
|
|
75
75
|
|
|
76
|
+
### 実機 E2E(2026-07-18、global 0.8.0 / baton path)
|
|
77
|
+
|
|
78
|
+
- `/tl` → 新セッションの初回プロンプトで新形式注入が発火(47 ターン引き継ぎ)。
|
|
79
|
+
注入は L1 非注入・現在地アンカー・L2 ターン原子詰め(11 ターン全文)・案内セクション
|
|
80
|
+
焼き込みで、設計どおりの形を目視確認
|
|
81
|
+
- 焼き込まれた `recall --l2 --session <id> --before <ISO ms> --last 11` を新セッション側から
|
|
82
|
+
そのまま実行し、境界より古い 11 ターン(11:02:27〜11:38:57)が古い順・全文・L3 suffix
|
|
83
|
+
付きで返り、注入分の最古ターン(11:48:57)と連続・重複欠落なしを確認
|
|
84
|
+
- 焼き込まれた `recall --l1 ... --skip 11` が窓外の全 9 ターンを「全 9 / 要約済み 7」の
|
|
85
|
+
正直表示で返し、未要約 2 件は `throughline detail <時刻>` への誘導付きで明示された
|
|
86
|
+
- これをもって v0.8.0 の残タスク(新注入形式の実機 E2E)は完了
|
|
87
|
+
|
|
76
88
|
### multi-hook 10k 突破の実測(2026-07-18、Claude Code 2.1.211 / 不採用)
|
|
77
89
|
|
|
78
90
|
- 同一 UserPromptSubmit に hook を 3 本登録 → それぞれ独立の `hook_success` attachment
|
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@ import { existsSync, mkdtempSync, rmSync, statSync } from 'node:fs';
|
|
|
5
5
|
import { tmpdir } from 'node:os';
|
|
6
6
|
import { join } from 'node:path';
|
|
7
7
|
|
|
8
|
+
import { CURRENT_VERSION } from '../db.mjs';
|
|
8
9
|
import {
|
|
9
10
|
collectFactoryDiagnostics,
|
|
10
11
|
inspectFactoryDatabase,
|
|
@@ -19,7 +20,12 @@ test('factory-diagnostics CLI: JSON-only contract and schema fixture', () => {
|
|
|
19
20
|
stdout: { write(value) { output.push(value); } },
|
|
20
21
|
version: '0.6.1',
|
|
21
22
|
inspectThread: () => ({ status: 'ready', rolloutAvailable: true }),
|
|
22
|
-
inspectDatabase: () => ({
|
|
23
|
+
inspectDatabase: () => ({
|
|
24
|
+
status: 'ready',
|
|
25
|
+
schemaVersion: CURRENT_VERSION,
|
|
26
|
+
supportedSchemaVersion: CURRENT_VERSION,
|
|
27
|
+
handoffMemory: true,
|
|
28
|
+
}),
|
|
23
29
|
inspectHooks: () => ({
|
|
24
30
|
status: 'ready',
|
|
25
31
|
claudeStatus: 'ready',
|
|
@@ -32,6 +38,9 @@ test('factory-diagnostics CLI: JSON-only contract and schema fixture', () => {
|
|
|
32
38
|
const parsed = JSON.parse(output[0]);
|
|
33
39
|
assert.equal(parsed.schema, 'throughline.native_factory_diagnostics.v1');
|
|
34
40
|
assert.equal(parsed.version, '0.6.1');
|
|
41
|
+
assert.equal(parsed.databaseSchema.schema, `throughline.database.v${CURRENT_VERSION}`);
|
|
42
|
+
assert.equal(parsed.databaseSchema.databaseSchemaVersion, CURRENT_VERSION);
|
|
43
|
+
assert.equal(parsed.databaseSchema.supportedDatabaseSchemaVersion, CURRENT_VERSION);
|
|
35
44
|
assert.equal(parsed.readiness.restore.status, 'ready');
|
|
36
45
|
assert.equal(parsed.evidence.restoreSmoke.status, 'unverified');
|
|
37
46
|
});
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { CURRENT_VERSION } from './db.mjs';
|
|
2
|
+
|
|
1
3
|
export const FACTORY_DIAGNOSTICS_SCHEMA = 'throughline.native_factory_diagnostics.v1';
|
|
2
|
-
export const DATABASE_SCHEMA =
|
|
4
|
+
export const DATABASE_SCHEMA = `throughline.database.v${CURRENT_VERSION}`;
|
|
3
5
|
|
|
4
6
|
const STATUSES = new Set(['ready', 'not_ready', 'not_applicable', 'unverified']);
|
|
5
7
|
|
|
@@ -2,9 +2,26 @@ import { test } from 'node:test';
|
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
|
+
DATABASE_SCHEMA,
|
|
5
6
|
FACTORY_DIAGNOSTICS_SCHEMA,
|
|
6
7
|
buildFactoryDiagnostics,
|
|
7
8
|
} from './factory-diagnostics.mjs';
|
|
9
|
+
import { CURRENT_VERSION } from './db.mjs';
|
|
10
|
+
|
|
11
|
+
test('factory diagnostics: database label は DB 実体・対応 version と一致する', () => {
|
|
12
|
+
const result = buildFactoryDiagnostics({
|
|
13
|
+
database: {
|
|
14
|
+
status: 'ready',
|
|
15
|
+
schemaVersion: CURRENT_VERSION,
|
|
16
|
+
supportedSchemaVersion: CURRENT_VERSION,
|
|
17
|
+
handoffMemory: true,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
assert.equal(DATABASE_SCHEMA, `throughline.database.v${CURRENT_VERSION}`);
|
|
22
|
+
assert.equal(result.databaseSchema.schema, `throughline.database.v${result.databaseSchema.databaseSchemaVersion}`);
|
|
23
|
+
assert.equal(result.databaseSchema.databaseSchemaVersion, result.databaseSchema.supportedDatabaseSchemaVersion);
|
|
24
|
+
});
|
|
8
25
|
|
|
9
26
|
test('factory diagnostics: 未設定の native factory は not_applicable を成功へ丸めない', () => {
|
|
10
27
|
const result = buildFactoryDiagnostics({
|