cueline 0.2.2 → 0.3.0

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.
Files changed (51) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +35 -0
  4. package/README.ja.md +12 -12
  5. package/README.ko.md +12 -12
  6. package/README.md +12 -12
  7. package/README.zh-CN.md +12 -12
  8. package/README.zh-TW.md +12 -12
  9. package/dist/src/api-run-prune.d.ts +41 -0
  10. package/dist/src/api-run-prune.js +218 -0
  11. package/dist/src/api-run-prune.js.map +1 -0
  12. package/dist/src/api.d.ts +3 -0
  13. package/dist/src/api.js +3 -0
  14. package/dist/src/api.js.map +1 -1
  15. package/dist/src/cli/health-commands.js +35 -0
  16. package/dist/src/cli/health-commands.js.map +1 -1
  17. package/dist/src/cli/main.js +95 -3
  18. package/dist/src/cli/main.js.map +1 -1
  19. package/dist/src/cli/observation-commands.js +94 -1
  20. package/dist/src/cli/observation-commands.js.map +1 -1
  21. package/dist/src/diagnostics/offline-self-test.d.ts +23 -0
  22. package/dist/src/diagnostics/offline-self-test.js +163 -0
  23. package/dist/src/diagnostics/offline-self-test.js.map +1 -0
  24. package/dist/src/diagnostics/secret-audit.d.ts +25 -0
  25. package/dist/src/diagnostics/secret-audit.js +114 -0
  26. package/dist/src/diagnostics/secret-audit.js.map +1 -0
  27. package/dist/src/diagnostics/upgrade-preflight.d.ts +41 -0
  28. package/dist/src/diagnostics/upgrade-preflight.js +182 -0
  29. package/dist/src/diagnostics/upgrade-preflight.js.map +1 -0
  30. package/dist/src/observation/run-bundle.d.ts +27 -0
  31. package/dist/src/observation/run-bundle.js +55 -0
  32. package/dist/src/observation/run-bundle.js.map +1 -0
  33. package/dist/src/version.d.ts +1 -1
  34. package/dist/src/version.js +1 -1
  35. package/docs/1.0/ideas/machine-output-contracts.md +47 -0
  36. package/docs/1.0/ideas/node26-contract.md +50 -0
  37. package/docs/1.0/ideas/offline-self-test.md +52 -0
  38. package/docs/1.0/ideas/upgrade-preflight.md +46 -0
  39. package/docs/compatibility.md +5 -5
  40. package/package.json +12 -2
  41. package/schemas/cli-doctor.schema.json +77 -0
  42. package/schemas/cli-routing-explain.schema.json +88 -0
  43. package/schemas/cli-routing.schema.json +65 -0
  44. package/schemas/cli-run-audit-secrets.schema.json +72 -0
  45. package/schemas/cli-run-export.schema.json +410 -0
  46. package/schemas/cli-runs-prune.schema.json +93 -0
  47. package/scripts/artifact-integrity.mjs +114 -0
  48. package/scripts/release-check.mjs +118 -0
  49. package/scripts/validate-cli-contracts.mjs +59 -0
  50. package/scripts/validate-doc-versions.mjs +79 -0
  51. package/scripts/validate-node-support.mjs +118 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cueline",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "Use a ChatGPT web conversation as the text controller for durable local advice or explicitly claimed work executed by the current Codex.",
5
5
  "author": {
6
6
  "name": "CueLine contributors"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cueline",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "Use a ChatGPT web conversation as the text controller for durable local advice or explicitly claimed work executed by the current Codex.",
5
5
  "author": {
6
6
  "name": "CueLine contributors"
package/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0 - 2026-07-17
4
+
5
+ ### Added
6
+
7
+ - Operator tooling: `runs prune` retention sweep over terminal runs (dry-run
8
+ by default, deletion serialized with the runtime lease lock), `run
9
+ audit-secrets` masked scan of durable events for secret-shaped strings, and
10
+ `run export` one-file sanitized support bundles.
11
+ - Release engineering: `self-test` offline controller-loop check, `upgrade
12
+ preflight` read-only migration report, `npm run release:check` release
13
+ gate, reproducible pack artifacts with SHA-256 verification, a
14
+ documentation version guard, and a Node 22/24/26 support contract in CI.
15
+ - Machine-output contracts: versioned strict JSON Schemas for `doctor`,
16
+ `routing`, `routing explain`, `runs prune`, `run audit-secrets`, and
17
+ `run export`; contract tests reject added fields, nested injection, empty
18
+ sections, and contradictory shapes.
19
+
20
+ ### Fixed
21
+
22
+ - Run-scoped commands fail closed for an absent run instead of fabricating a
23
+ healthy view; a sweep pins this for every read and mutating surface.
24
+ - Secret audit reports a secret-shaped object key as a finding and masks it
25
+ in the finding path instead of echoing it verbatim.
26
+ - Prune re-reads runtime ownership inside the lease mutation lock before
27
+ deletion, and only a definite ENOENT counts as a completed removal; any
28
+ other filesystem error keeps the run and records the error.
29
+
30
+ ### Verification
31
+
32
+ - Verified TypeScript typecheck, build, 532/532 unit/integration/smoke tests,
33
+ plugin validation, pack dry-run, release:check, offline self-test, and
34
+ upgrade preflight on the unified candidate, cross-reviewed adversarially by
35
+ two independent lines (AJV negative oracle: seven malicious mutations all
36
+ rejected).
37
+
3
38
  ## 0.2.2 - 2026-07-17
4
39
 
5
40
  ### Fixed
package/README.ja.md CHANGED
@@ -22,15 +22,15 @@
22
22
 
23
23
  CueLine は独立した実装で、**ランタイムの npm 依存はゼロ**です。Omnilane のラッパーではありません。
24
24
 
25
- ## 最新リリース:0.2.2
25
+ ## 最新リリース:0.3.0
26
26
 
27
- - 設定可能で永続的な job 単位のコントローラー証拠上限を追加し(0.2.1)、記録されるすべての job イベントにも適用しました。イベントログとコントローラーへ提供される証拠は常に同じ上限を共有します。
28
- - run で観測された証拠枯渇デッドロックを修正しました。過大なワーカー出力がコントローラーをラウンド上限内に終わらない inspect ページングループへ追い込むことはもうありません。
29
- - 容量警告はコントローラーが実際にページングできる証拠だけを数えます。永続上限を超える真の総量は独立した決定的な通知で開示され、証拠が十分ならコントローラーは早期に判断できます。
30
- - リプレイされた証拠はバイト単位で安定します。検証済みの正規上限マーカーはそのまま保持され、旧形式の切り詰めマーカーは整合性エラーなしに決定的へ再適用されます。
31
- - 490/490 テストに加え、実 process runner で検証しました。真の総量を持つ上限イベントマーカーを 1 つ書き込み、コントローラー 2 ターンで完了しました。
27
+ - 運用ツールを追加:終了済み run を掃除する `runs prune`(デフォルトは dry-run、削除は runtime lease ロックと直列化)、永続イベント中の秘密情報らしき文字列をマスク付きで走査する `run audit-secrets`、サニタイズ済みサポートバンドルを 1 ファイルで出力する `run export`。
28
+ - リリースエンジニアリングを追加:オフラインで制御ループを検査する `self-test`、読み取り専用の移行レポート `upgrade preflight`、リリースゲート `release:check`、SHA-256 検証付きの再現可能なパッケージ成果物、ドキュメントバージョンガード、CI 上で証拠に裏付けられた Node サポート契約。
29
+ - すべての読み取り専用 `--json` 出力にバージョン付きの厳格な JSON 契約を公開。契約テストは余分なフィールド、ネストされた注入、空セクション、矛盾した形状を拒否します。
30
+ - fail-closed 挙動を強化:敵対的プロトコルファズコーパス、全 run コマンドの欠損 run 掃引、ENOENT のみを削除完了と数える prune 記帳。
31
+ - 統一候補で 532/532 テストと全リリースゲートを検証し、独立した 2 系統が相互に敵対的レビューを実施しました。
32
32
 
33
- 詳細は [changelog](CHANGELOG.md#022---2026-07-17) またはバージョン指定の [v0.2.2 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.2.2) を参照してください。
33
+ 詳細は [changelog](CHANGELOG.md#030---2026-07-17) またはバージョン指定の [v0.3.0 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.3.0) を参照してください。
34
34
 
35
35
  ## 1 回の実行は実際にどう進むか
36
36
 
@@ -71,15 +71,15 @@ ChatGPT Pro のサブスクリプションと、選択された Pro モデルは
71
71
  npm レジストリからインストールします。
72
72
 
73
73
  ```bash
74
- npm install -g cueline@0.2.0
74
+ npm install -g cueline@0.3.0
75
75
  cueline install
76
76
  cueline doctor
77
77
  ```
78
78
 
79
- フォールバックとして、[v0.2.0 リリース](https://github.com/Seraphim0916/cueline/releases/tag/v0.2.0) のパッケージ済み tarball をインストールすることもできます。同じリリースに `.sha256` チェックサムも置いてあります。
79
+ フォールバックとして、[v0.3.0 リリース](https://github.com/Seraphim0916/cueline/releases/tag/v0.3.0) のパッケージ済み tarball をインストールすることもできます。同じリリースに `.sha256` チェックサムも置いてあります。
80
80
 
81
81
  ```bash
82
- npm install -g https://github.com/Seraphim0916/cueline/releases/download/v0.2.0/cueline-0.2.0.tgz
82
+ npm install -g https://github.com/Seraphim0916/cueline/releases/download/v0.3.0/cueline-0.3.0.tgz
83
83
  cueline install
84
84
  cueline doctor
85
85
  ```
@@ -186,7 +186,7 @@ CLI はブラウザーを駆動しません。状態を書き込むコマンド
186
186
 
187
187
  ```console
188
188
  $ cueline doctor
189
- CueLine 0.2.0
189
+ CueLine 0.3.0
190
190
  status ok
191
191
  node 22.14.0 ok
192
192
  config /usr/local/lib/node_modules/cueline/config/routing.default.json valid
@@ -292,7 +292,7 @@ npm pack --dry-run
292
292
 
293
293
  ## 開発
294
294
 
295
- TypeScript、ESM、Node の組み込みモジュールのみ。`npm run build` は `dist/` へコンパイルし、テストは `node --test` でコンパイル済みの成果物に対して実行します。CI は Ubuntu と macOS 上の Node 22 / 24 を対象とします。
295
+ TypeScript、ESM、Node の組み込みモジュールのみ。`npm run build` は `dist/` へコンパイルし、テストは `node --test` でコンパイル済みの成果物に対して実行します。CI は Ubuntu と macOS 上の Node 22 / 24 / 26 を対象とします。
296
296
 
297
297
  CueLine は独立したプロジェクトであり、OpenAI やその他いかなる企業とも提携しておらず、推奨・後援も受けていません。[provenance](docs/provenance.md) と [third-party notices](THIRD_PARTY_NOTICES.md) を参照してください。
298
298
 
package/README.ko.md CHANGED
@@ -22,15 +22,15 @@
22
22
 
23
23
  CueLine은 독립적인 구현이며 **런타임 npm 의존성이 전혀 없습니다**. Omnilane을 감싼 래퍼가 아닙니다.
24
24
 
25
- ## 최신 릴리스: 0.2.2
25
+ ## 최신 릴리스: 0.3.0
26
26
 
27
- - 설정 가능한 영속적 job별 컨트롤러 증거 상한을 추가하고(0.2.1), 기록되는 모든 job 이벤트에도 적용했습니다. 이벤트 로그와 컨트롤러에 제공되는 증거는 항상 같은 상한을 공유합니다.
28
- - 실제 run에서 관측된 증거 고갈 교착을 수정했습니다. 과대한 워커 출력이 컨트롤러를 라운드 한도 안에 끝나지 않는 inspect 페이징 루프로 몰아넣는 일은 이상 없습니다.
29
- - 용량 경고는 컨트롤러가 실제로 페이징할 있는 증거만 계산합니다. 영속 상한을 넘는 실제 총량은 별도의 결정적 알림으로 공개되며, 증거가 충분하면 컨트롤러는 조기에 결정할 수 있습니다.
30
- - 재생된 증거는 바이트 단위로 안정적입니다. 검증된 정규 상한 마커는 그대로 유지되고, 구형 절단 마커는 무결성 오류 없이 결정적으로 다시 상한이 적용됩니다.
31
- - 490/490 테스트와 함께 실제 process runner로 검증했습니다. 실제 총량을 담은 상한 이벤트 마커 하나를 기록하고 컨트롤러 2턴 안에 완료했습니다.
27
+ - 운영 도구 추가: 종료된 run을 정리하는 `runs prune`(기본 dry-run, 삭제는 runtime lease 잠금과 직렬화), 영속 이벤트에서 비밀 형태 문자열을 마스킹 방식으로 검사하는 `run audit-secrets`, 정제된 지원 번들을 한 파일로 내보내는 `run export`.
28
+ - 릴리스 엔지니어링 추가: 오프라인 제어 루프 점검 `self-test`, 읽기 전용 마이그레이션 리포트 `upgrade preflight`, 릴리스 게이트 `release:check`, SHA-256 검증이 붙은 재현 가능한 패키지 산출물, 문서 버전 가드, CI에서 증거로 뒷받침되는 Node 지원 계약.
29
+ - 모든 읽기 전용 `--json` 출력에 버전이 붙은 엄격한 JSON 계약을 공개. 계약 테스트는 추가 필드, 중첩 주입, 섹션, 모순된 형태를 거부합니다.
30
+ - fail-closed 동작 강화: 적대적 프로토콜 퍼즈 코퍼스, 전체 run 명령의 누락 run 점검, ENOENT만 삭제 완료로 인정하는 prune 회계.
31
+ - 통합 후보에서 532/532 테스트와 모든 릴리스 게이트를 검증했으며, 독립된 라인이 상호 적대적 검토를 수행했습니다.
32
32
 
33
- 전체 내용은 [changelog](CHANGELOG.md#022---2026-07-17) 또는 버전이 지정된 [v0.2.2 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.2.2)에서 확인할 수 있습니다.
33
+ 전체 내용은 [changelog](CHANGELOG.md#030---2026-07-17) 또는 버전이 지정된 [v0.3.0 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.3.0)에서 확인할 수 있습니다.
34
34
 
35
35
  ## 실행 한 번은 실제로 이렇게 흘러갑니다
36
36
 
@@ -71,15 +71,15 @@ ChatGPT Pro 구독과 선택된 Pro 모델은 서로 다른 것입니다. 계정
71
71
  npm 레지스트리에서 설치합니다:
72
72
 
73
73
  ```bash
74
- npm install -g cueline@0.2.0
74
+ npm install -g cueline@0.3.0
75
75
  cueline install
76
76
  cueline doctor
77
77
  ```
78
78
 
79
- 대안으로, [v0.2.0 릴리스](https://github.com/Seraphim0916/cueline/releases/tag/v0.2.0)의 패키지 tarball을 설치할 수도 있습니다. 같은 릴리스에 `.sha256` 체크섬도 함께 있습니다.
79
+ 대안으로, [v0.3.0 릴리스](https://github.com/Seraphim0916/cueline/releases/tag/v0.3.0)의 패키지 tarball을 설치할 수도 있습니다. 같은 릴리스에 `.sha256` 체크섬도 함께 있습니다.
80
80
 
81
81
  ```bash
82
- npm install -g https://github.com/Seraphim0916/cueline/releases/download/v0.2.0/cueline-0.2.0.tgz
82
+ npm install -g https://github.com/Seraphim0916/cueline/releases/download/v0.3.0/cueline-0.3.0.tgz
83
83
  cueline install
84
84
  cueline doctor
85
85
  ```
@@ -186,7 +186,7 @@ CLI는 브라우저를 구동하지 않습니다. 상태를 쓰는 명령 전에
186
186
 
187
187
  ```console
188
188
  $ cueline doctor
189
- CueLine 0.2.0
189
+ CueLine 0.3.0
190
190
  status ok
191
191
  node 22.14.0 ok
192
192
  config /usr/local/lib/node_modules/cueline/config/routing.default.json valid
@@ -292,7 +292,7 @@ npm pack --dry-run
292
292
 
293
293
  ## 개발
294
294
 
295
- TypeScript, ESM, Node 내장 모듈만 사용합니다. `npm run build`는 `dist/`로 컴파일하고, 테스트는 `node --test`로 컴파일된 결과물을 대상으로 실행합니다. CI는 Ubuntu와 macOS의 Node 22 24 다룹니다.
295
+ TypeScript, ESM, Node 내장 모듈만 사용합니다. `npm run build`는 `dist/`로 컴파일하고, 테스트는 `node --test`로 컴파일된 결과물을 대상으로 실행합니다. CI는 Ubuntu와 macOS의 Node 22, 24, 26을 다룹니다.
296
296
 
297
297
  CueLine은 독립 프로젝트이며 OpenAI를 비롯한 어떤 회사와도 제휴하거나 보증·후원을 받지 않았습니다. [provenance](docs/provenance.md)와 [third-party notices](THIRD_PARTY_NOTICES.md)를 참고하세요.
298
298
 
package/README.md CHANGED
@@ -22,15 +22,15 @@ The web page never touches your machine and has no local tools. It only emits on
22
22
 
23
23
  CueLine is a standalone implementation with **no runtime npm dependencies**. It is not a wrapper around Omnilane.
24
24
 
25
- ## Latest release: 0.2.2
25
+ ## Latest release: 0.3.0
26
26
 
27
- - Added a durable, configurable per-job controller-evidence cap (0.2.1), now applied to every recorded job event so event-log and controller-served evidence always share one cap.
28
- - Fixed the evidence-starvation deadlock observed in a real run: oversized worker output can no longer force the controller into an inspect-pagination treadmill that cannot finish within the round limit.
29
- - Capacity warnings count only evidence the controller can actually page through; true totals beyond the durable cap are reported in a separate deterministic notice, and the controller may decide as soon as evidence is sufficient.
30
- - Replayed evidence stays byte-stable: a validated canonical cap marker is preserved as-is, and legacy truncation markers re-cap deterministically without integrity errors.
31
- - Verified 490/490 tests, plus a real process-runner run that wrote one capped event marker carrying the true total and completed in two controller turns.
27
+ - Added operator tooling: `runs prune` retention sweep over terminal runs (dry-run by default, deletion serialized with the runtime lease lock), `run audit-secrets` masked scan of durable events for secret-shaped strings, and `run export` one-file sanitized support bundles.
28
+ - Added release engineering: `self-test` offline controller-loop check, `upgrade preflight` read-only migration report, `release:check` gate, reproducible pack artifacts with SHA-256 verification, a documentation version guard, and an evidence-backed Node support contract in CI.
29
+ - Published versioned strict JSON contracts for every read-only `--json` surface; contract tests reject added fields, nested injection, empty sections, and contradictory shapes.
30
+ - Hardened fail-closed behavior: an adversarial protocol fuzz corpus, a missing-run sweep across all run-scoped commands, and ENOENT-only prune removal accounting.
31
+ - Verified 532/532 tests plus all release gates on the unified candidate, cross-reviewed adversarially by two independent lines.
32
32
 
33
- Read the complete [changelog](CHANGELOG.md#022---2026-07-17) or the versioned [v0.2.2 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.2.2).
33
+ Read the complete [changelog](CHANGELOG.md#030---2026-07-17) or the versioned [v0.3.0 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.3.0).
34
34
 
35
35
  ## How a run actually goes
36
36
 
@@ -73,15 +73,15 @@ You need Node.js 22+, Codex with its built-in Browser, and — for the bundled d
73
73
  Install from the npm registry:
74
74
 
75
75
  ```bash
76
- npm install -g cueline@0.2.0
76
+ npm install -g cueline@0.3.0
77
77
  cueline install
78
78
  cueline doctor
79
79
  ```
80
80
 
81
- As a fallback, install the packaged tarball from the [v0.2.0 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.2.0), which also carries its `.sha256` checksum:
81
+ As a fallback, install the packaged tarball from the [v0.3.0 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.3.0), which also carries its `.sha256` checksum:
82
82
 
83
83
  ```bash
84
- npm install -g https://github.com/Seraphim0916/cueline/releases/download/v0.2.0/cueline-0.2.0.tgz
84
+ npm install -g https://github.com/Seraphim0916/cueline/releases/download/v0.3.0/cueline-0.3.0.tgz
85
85
  cueline install
86
86
  cueline doctor
87
87
  ```
@@ -197,7 +197,7 @@ The CLI does not drive the browser. Run `cueline help` for every positional argu
197
197
 
198
198
  ```console
199
199
  $ cueline doctor
200
- CueLine 0.2.0
200
+ CueLine 0.3.0
201
201
  status ok
202
202
  node 22.14.0 ok
203
203
  config /usr/local/lib/node_modules/cueline/config/routing.default.json valid
@@ -301,7 +301,7 @@ See [compatibility](docs/compatibility.md) for the full matrix.
301
301
 
302
302
  ## Development
303
303
 
304
- TypeScript, ESM, Node built-ins only. `npm run build` compiles to `dist/`; tests run on the compiled output with `node --test`. CI covers Node 22 and 24 on Ubuntu and macOS.
304
+ TypeScript, ESM, Node built-ins only. `npm run build` compiles to `dist/`; tests run on the compiled output with `node --test`. CI covers Node 22, 24, and 26 on Ubuntu and macOS.
305
305
 
306
306
  CueLine is an independent project and is not affiliated with, endorsed by, or sponsored by OpenAI or any other company. See [provenance](docs/provenance.md) and [third-party notices](THIRD_PARTY_NOTICES.md).
307
307
 
package/README.zh-CN.md CHANGED
@@ -22,15 +22,15 @@
22
22
 
23
23
  CueLine 是独立实现,**没有任何运行时 npm 依赖**,也不是 Omnilane 的包装层。
24
24
 
25
- ## 最新版本:0.2.2
25
+ ## 最新版本:0.3.0
26
26
 
27
- - 新增可配置的持久单 job 控制器证据上限(0.2.1),并应用到每一条写入的 job 事件,事件日志与提供给控制器的证据始终共用同一个上限。
28
- - 修复真实 run 中观察到的证据饥饿死锁:过大的 worker 输出不再能把控制器拖进轮次上限内走不完的 inspect 翻页循环。
29
- - 容量警告只统计控制器实际能翻到的证据;超过持久上限的真实总量改由独立的确定性通知披露,控制器在证据充分时即可提前决策。
30
- - 重放证据字节稳定:通过校验的规范上限标记原样保留,旧版截断标记则确定性地重新套用上限,不产生完整性错误。
31
- - 完成 490/490 测试,并用真实 process runner 验证:单个上限事件标记携带真实总量写入,两个控制器轮次内完成。
27
+ - 新增运维工具:`runs prune` 清理已结束的 run(默认 dry-run,删除与 runtime lease 锁串行化)、`run audit-secrets` 以掩码方式扫描持久事件中的密钥形字符串、`run export` 一键导出脱敏支持包。
28
+ - 新增发布工程:`self-test` 离线控制环检查、`upgrade preflight` 只读升级体检、`release:check` 发布闸门、可复现打包产物与 SHA-256 校验、文档版本守卫、以及 CI 上以证据背书的 Node 支持契约。
29
+ - 为每个只读 `--json` 输出发布带版本的严格 JSON 契约;契约测试拒绝多余字段、嵌套注入、空区段与矛盾形状。
30
+ - 强化 fail-closed 行为:对抗式协议 fuzz 语料、全 run 命令的缺失 run 扫描、prune 仅认 ENOENT 的删除记账。
31
+ - 统一候选完成 532/532 测试与全部发布闸门,并由两条独立线互相对抗式复验。
32
32
 
33
- 完整内容请查看 [changelog](CHANGELOG.md#022---2026-07-17) 或版本化的 [v0.2.2 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.2.2)。
33
+ 完整内容请查看 [changelog](CHANGELOG.md#030---2026-07-17) 或版本化的 [v0.3.0 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.3.0)。
34
34
 
35
35
  ## 一次运行实际是怎么走的
36
36
 
@@ -71,15 +71,15 @@ ChatGPT Pro 订阅套餐与“选定的 Pro 模型”是两回事。账号或个
71
71
  从 npm registry 安装:
72
72
 
73
73
  ```bash
74
- npm install -g cueline@0.2.0
74
+ npm install -g cueline@0.3.0
75
75
  cueline install
76
76
  cueline doctor
77
77
  ```
78
78
 
79
- 作为后备,也可以安装 [v0.2.0 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.2.0) 上的打包 tarball,该 release 同时附带它的 `.sha256` 校验值:
79
+ 作为后备,也可以安装 [v0.3.0 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.3.0) 上的打包 tarball,该 release 同时附带它的 `.sha256` 校验值:
80
80
 
81
81
  ```bash
82
- npm install -g https://github.com/Seraphim0916/cueline/releases/download/v0.2.0/cueline-0.2.0.tgz
82
+ npm install -g https://github.com/Seraphim0916/cueline/releases/download/v0.3.0/cueline-0.3.0.tgz
83
83
  cueline install
84
84
  cueline doctor
85
85
  ```
@@ -188,7 +188,7 @@ CLI 不驱动浏览器。执行写入状态的命令前,先用 `cueline help`
188
188
 
189
189
  ```console
190
190
  $ cueline doctor
191
- CueLine 0.2.0
191
+ CueLine 0.3.0
192
192
  status ok
193
193
  node 22.14.0 ok
194
194
  config /usr/local/lib/node_modules/cueline/config/routing.default.json valid
@@ -294,7 +294,7 @@ npm pack --dry-run
294
294
 
295
295
  ## 开发
296
296
 
297
- TypeScript、ESM,仅使用 Node 内置模块。`npm run build` 编译到 `dist/`;测试以 `node --test` 运行编译产物。CI 覆盖 Ubuntu 与 macOS 上的 Node 2224。
297
+ TypeScript、ESM,仅使用 Node 内置模块。`npm run build` 编译到 `dist/`;测试以 `node --test` 运行编译产物。CI 覆盖 Ubuntu 与 macOS 上的 Node 2224、26
298
298
 
299
299
  CueLine 是独立项目,与 OpenAI 或任何其他公司均无隶属关系,也未获其背书或赞助。见 [provenance](docs/provenance.md) 与 [third-party notices](THIRD_PARTY_NOTICES.md)。
300
300
 
package/README.zh-TW.md CHANGED
@@ -22,15 +22,15 @@
22
22
 
23
23
  CueLine 是獨立實作,**沒有任何 runtime npm 相依套件**,也不是 Omnilane 的包裝層。
24
24
 
25
- ## 最新版本:0.2.2
25
+ ## 最新版本:0.3.0
26
26
 
27
- - 新增可設定的持久單一 job 主控證據上限(0.2.1),並套用到每一筆寫入的 job 事件,事件紀錄與提供給主控的證據永遠共用同一個上限。
28
- - 修復真實 run 觀察到的證據餓死卡死:過大的工人輸出不再能把主控拖進回合上限內走不完的 inspect 翻頁迴圈。
29
- - 容量警告只計算主控實際翻得到的證據;超過持久上限的真實總量改以獨立的決定性通知揭露,主控在證據足夠時即可提前決策。
30
- - 重播證據位元組穩定:通過驗證的正規上限標記原樣保留,舊版截斷標記則決定性地重新套用上限,不產生完整性錯誤。
31
- - 完成 490/490 測試,並以真實 process runner 驗證:單一上限事件標記帶真實總量寫入,兩個主控回合內完成。
27
+ - 新增操作面工具:`runs prune` 清掃已結束的 run(預設 dry-run,刪除與 runtime lease 鎖序列化)、`run audit-secrets` 以遮罩方式掃描持久事件中的密鑰形字串、`run export` 一鍵匯出去敏支援包。
28
+ - 新增發佈工程:`self-test` 離線控制迴圈檢查、`upgrade preflight` 唯讀升級體檢、`release:check` 發佈閘門、可重現打包產物與 SHA-256 驗證、文件版本守衛、以及 CI 上以證據背書的 Node 支援契約。
29
+ - 為每個唯讀 `--json` 面發佈帶版本的嚴格 JSON 契約;契約測試會拒絕多餘欄位、巢狀注入、空區段與矛盾形狀。
30
+ - 強化 fail-closed 行為:對抗式協定 fuzz 火力網、全 run-scoped 指令的缺失 run 掃描、prune 只認 ENOENT 的刪除記帳。
31
+ - 統一候選完成 532/532 測試與全部發佈閘門,並由兩條獨立線互相對抗式複驗。
32
32
 
33
- 完整內容請看 [changelog](CHANGELOG.md#022---2026-07-17) 或版本化的 [v0.2.2 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.2.2)。
33
+ 完整內容請看 [changelog](CHANGELOG.md#030---2026-07-17) 或版本化的 [v0.3.0 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.3.0)。
34
34
 
35
35
  ## 一次執行實際上怎麼跑
36
36
 
@@ -71,15 +71,15 @@ ChatGPT Pro 訂閱方案與「選定的 Pro 模型」是兩回事。帳號或個
71
71
  從 npm registry 安裝:
72
72
 
73
73
  ```bash
74
- npm install -g cueline@0.2.0
74
+ npm install -g cueline@0.3.0
75
75
  cueline install
76
76
  cueline doctor
77
77
  ```
78
78
 
79
- 作為備援,也可以安裝 [v0.2.0 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.2.0) 上的打包 tarball,該 release 同時附上它的 `.sha256` 校驗碼:
79
+ 作為備援,也可以安裝 [v0.3.0 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.3.0) 上的打包 tarball,該 release 同時附上它的 `.sha256` 校驗碼:
80
80
 
81
81
  ```bash
82
- npm install -g https://github.com/Seraphim0916/cueline/releases/download/v0.2.0/cueline-0.2.0.tgz
82
+ npm install -g https://github.com/Seraphim0916/cueline/releases/download/v0.3.0/cueline-0.3.0.tgz
83
83
  cueline install
84
84
  cueline doctor
85
85
  ```
@@ -197,7 +197,7 @@ CLI 不驅動瀏覽器。執行寫入狀態的命令前,先用 `cueline help`
197
197
 
198
198
  ```console
199
199
  $ cueline doctor
200
- CueLine 0.2.0
200
+ CueLine 0.3.0
201
201
  status ok
202
202
  node 22.14.0 ok
203
203
  config /usr/local/lib/node_modules/cueline/config/routing.default.json valid
@@ -303,7 +303,7 @@ npm pack --dry-run
303
303
 
304
304
  ## 開發
305
305
 
306
- TypeScript、ESM,只用 Node 內建模組。`npm run build` 會編譯到 `dist/`;測試以 `node --test` 跑編譯後的產物。CI 涵蓋 Ubuntu 與 macOS 上的 Node 2224。
306
+ TypeScript、ESM,只用 Node 內建模組。`npm run build` 會編譯到 `dist/`;測試以 `node --test` 跑編譯後的產物。CI 涵蓋 Ubuntu 與 macOS 上的 Node 2224、26
307
307
 
308
308
  CueLine 是獨立專案,與 OpenAI 或任何其他公司皆無隸屬關係,亦未獲其背書或贊助。見 [provenance](docs/provenance.md) 與 [third-party notices](THIRD_PARTY_NOTICES.md)。
309
309
 
@@ -0,0 +1,41 @@
1
+ import type { CueLineRuntimeOptions } from "./api-contracts.js";
2
+ export declare const PRUNABLE_RUN_STATES: readonly ["complete", "blocked", "cancelled"];
3
+ export type PrunableRunState = (typeof PRUNABLE_RUN_STATES)[number];
4
+ export type CueLineRunPruneKeptReason = "unreadable" | "non_terminal" | "state_excluded" | "runtime_active" | "active_jobs" | "too_recent" | "delete_failed";
5
+ export interface CueLineRunPruneDecision {
6
+ runId: string;
7
+ decision: "pruned" | "eligible" | "kept";
8
+ reason?: CueLineRunPruneKeptReason;
9
+ status?: string;
10
+ lastEventAt?: string;
11
+ }
12
+ export interface CueLineRunPruneError {
13
+ runId: string;
14
+ message: string;
15
+ }
16
+ export interface CueLineRunPruneResult {
17
+ home: string;
18
+ apply: boolean;
19
+ olderThanMs: number;
20
+ cutoff: string;
21
+ states: PrunableRunState[];
22
+ decisions: CueLineRunPruneDecision[];
23
+ prunedRuns: number;
24
+ eligibleRuns: number;
25
+ keptRuns: number;
26
+ removedJobRecords: number;
27
+ errors: CueLineRunPruneError[];
28
+ }
29
+ export interface CueLineRunPruneOptions extends Pick<CueLineRuntimeOptions, "home" | "environment" | "now"> {
30
+ olderThanMs: number;
31
+ states?: readonly PrunableRunState[];
32
+ apply?: boolean;
33
+ }
34
+ /**
35
+ * Retention sweep over persisted runs. Only terminal runs (complete, blocked,
36
+ * cancelled) whose runtime lease is not active, with zero pending or running
37
+ * jobs, and whose last durable event is older than the cutoff are eligible.
38
+ * Dry-run by default: nothing is deleted unless `apply` is true. Unreadable
39
+ * runs are always kept; deciding about corrupt evidence requires a human.
40
+ */
41
+ export declare function pruneCueLineRuns(options: CueLineRunPruneOptions): Promise<CueLineRunPruneResult>;
@@ -0,0 +1,218 @@
1
+ import { access, readdir, rm } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { listCueLineRuns } from "./api-runtime-lifecycle.js";
4
+ import { CueLineError } from "./core/errors.js";
5
+ import { runtimeEnvironment } from "./core/runtime.js";
6
+ import { JobStatusStore } from "./jobs/status.js";
7
+ import { defaultCueLineHome, runPaths } from "./state/paths.js";
8
+ import { readRuntimeLease, withRuntimeLeaseMutation, } from "./state/runtime-lease.js";
9
+ export const PRUNABLE_RUN_STATES = ["complete", "blocked", "cancelled"];
10
+ function normalizedStates(states) {
11
+ const requested = states === undefined ? PRUNABLE_RUN_STATES : states;
12
+ const unique = [];
13
+ for (const state of requested) {
14
+ if (!PRUNABLE_RUN_STATES.includes(state)) {
15
+ throw new CueLineError("RUN_PRUNE_STATE_INVALID", `Only terminal run states may be pruned; '${state}' is not one of: ${PRUNABLE_RUN_STATES.join(", ")}.`);
16
+ }
17
+ if (!unique.includes(state))
18
+ unique.push(state);
19
+ }
20
+ if (unique.length === 0) {
21
+ throw new CueLineError("RUN_PRUNE_STATE_INVALID", "At least one terminal run state is required.");
22
+ }
23
+ return unique;
24
+ }
25
+ /**
26
+ * Only a definite ENOENT counts as "gone". Any other filesystem error
27
+ * (EACCES, EIO, …) must propagate, otherwise the RUNTIME_MUTATION_FENCED
28
+ * recovery path would misclassify an unverifiable directory as pruned.
29
+ */
30
+ async function definitelyMissing(target) {
31
+ try {
32
+ await access(target);
33
+ return false;
34
+ }
35
+ catch (error) {
36
+ if (error.code === "ENOENT")
37
+ return true;
38
+ throw error;
39
+ }
40
+ }
41
+ async function removeJobRecordsForRuns(home, runIds, errors) {
42
+ if (runIds.size === 0)
43
+ return 0;
44
+ const directory = path.join(home, "jobs");
45
+ let names;
46
+ try {
47
+ names = await readdir(directory);
48
+ }
49
+ catch (error) {
50
+ if (error.code === "ENOENT")
51
+ return 0;
52
+ throw error;
53
+ }
54
+ const jobIds = new Set();
55
+ for (const name of names) {
56
+ if (name.endsWith(".json"))
57
+ jobIds.add(name.slice(0, -".json".length));
58
+ else if (name.endsWith(".terminal"))
59
+ jobIds.add(name.slice(0, -".terminal".length));
60
+ }
61
+ const statusStore = new JobStatusStore(home);
62
+ let removed = 0;
63
+ for (const jobId of [...jobIds].sort()) {
64
+ let runId;
65
+ try {
66
+ runId = (await statusStore.read(jobId))?.runId;
67
+ }
68
+ catch {
69
+ // An unparsable job record never names a run; leave it for `jobs` to surface.
70
+ continue;
71
+ }
72
+ if (runId === undefined || !runIds.has(runId))
73
+ continue;
74
+ try {
75
+ await rm(path.join(directory, `${jobId}.json`), { force: true });
76
+ await rm(path.join(directory, `${jobId}.terminal`), { force: true });
77
+ removed += 1;
78
+ }
79
+ catch (error) {
80
+ errors.push({
81
+ runId,
82
+ message: `job record '${jobId}': ${error instanceof Error ? error.message : String(error)}`,
83
+ });
84
+ }
85
+ }
86
+ return removed;
87
+ }
88
+ /**
89
+ * Retention sweep over persisted runs. Only terminal runs (complete, blocked,
90
+ * cancelled) whose runtime lease is not active, with zero pending or running
91
+ * jobs, and whose last durable event is older than the cutoff are eligible.
92
+ * Dry-run by default: nothing is deleted unless `apply` is true. Unreadable
93
+ * runs are always kept; deciding about corrupt evidence requires a human.
94
+ */
95
+ export async function pruneCueLineRuns(options) {
96
+ if (!Number.isFinite(options.olderThanMs) ||
97
+ options.olderThanMs < 0) {
98
+ throw new CueLineError("RUN_PRUNE_AGE_INVALID", "olderThanMs must be a non-negative finite number of milliseconds.");
99
+ }
100
+ const environment = options.environment ?? runtimeEnvironment();
101
+ const home = options.home ?? defaultCueLineHome(environment);
102
+ const states = normalizedStates(options.states);
103
+ const apply = options.apply === true;
104
+ const now = options.now === undefined ? new Date() : options.now();
105
+ const cutoffMs = now.getTime() - options.olderThanMs;
106
+ const cutoff = new Date(cutoffMs).toISOString();
107
+ const runs = await listCueLineRuns({
108
+ home,
109
+ ...(options.environment === undefined ? {} : { environment: options.environment }),
110
+ ...(options.now === undefined ? {} : { now: options.now }),
111
+ });
112
+ const decisions = [];
113
+ const errors = [];
114
+ const prunedRunIds = new Set();
115
+ let eligibleRuns = 0;
116
+ let keptRuns = 0;
117
+ for (const run of runs) {
118
+ if (!run.readable) {
119
+ decisions.push({ runId: run.runId, decision: "kept", reason: "unreadable" });
120
+ keptRuns += 1;
121
+ continue;
122
+ }
123
+ const base = {
124
+ runId: run.runId,
125
+ status: run.status,
126
+ lastEventAt: run.lastEventAt,
127
+ };
128
+ if (!PRUNABLE_RUN_STATES.includes(run.status)) {
129
+ decisions.push({ ...base, decision: "kept", reason: "non_terminal" });
130
+ keptRuns += 1;
131
+ continue;
132
+ }
133
+ if (!states.includes(run.status)) {
134
+ decisions.push({ ...base, decision: "kept", reason: "state_excluded" });
135
+ keptRuns += 1;
136
+ continue;
137
+ }
138
+ if (run.runtimeOwnership === "active") {
139
+ decisions.push({ ...base, decision: "kept", reason: "runtime_active" });
140
+ keptRuns += 1;
141
+ continue;
142
+ }
143
+ if (run.activeJobs > 0) {
144
+ decisions.push({ ...base, decision: "kept", reason: "active_jobs" });
145
+ keptRuns += 1;
146
+ continue;
147
+ }
148
+ const lastEventMs = Date.parse(run.lastEventAt);
149
+ if (!Number.isFinite(lastEventMs) || lastEventMs >= cutoffMs) {
150
+ decisions.push({ ...base, decision: "kept", reason: "too_recent" });
151
+ keptRuns += 1;
152
+ continue;
153
+ }
154
+ if (!apply) {
155
+ decisions.push({ ...base, decision: "eligible" });
156
+ eligibleRuns += 1;
157
+ continue;
158
+ }
159
+ try {
160
+ // The inventory above is a snapshot; a runtime could claim the lease
161
+ // between listing and deletion. Re-read and delete inside the lease
162
+ // mutation lock so this serializes with RuntimeLease.claim — a plain
163
+ // re-read before rm still leaves a window for a claim to land between
164
+ // the two awaits.
165
+ const deleted = await withRuntimeLeaseMutation(home, run.runId, async () => {
166
+ const recheck = await readRuntimeLease(home, run.runId, {
167
+ ...(options.now === undefined ? {} : { now: options.now }),
168
+ });
169
+ if (recheck.ownership === "active")
170
+ return false;
171
+ await rm(runPaths(home, run.runId).runDir, { recursive: true, force: true });
172
+ return true;
173
+ });
174
+ if (!deleted) {
175
+ decisions.push({ ...base, decision: "kept", reason: "runtime_active" });
176
+ keptRuns += 1;
177
+ continue;
178
+ }
179
+ prunedRunIds.add(run.runId);
180
+ decisions.push({ ...base, decision: "pruned" });
181
+ }
182
+ catch (error) {
183
+ // Deleting the run directory removes its own fence record, so the
184
+ // lock's post-operation fence check reports RUNTIME_MUTATION_FENCED
185
+ // for runs that ever had a runtime generation. Under the mutation lock
186
+ // nobody else can rotate the fence, so if the directory is gone the
187
+ // mismatch is self-inflicted and the deletion succeeded.
188
+ if (error instanceof CueLineError &&
189
+ error.code === "RUNTIME_MUTATION_FENCED" &&
190
+ (await definitelyMissing(runPaths(home, run.runId).runDir).catch(() => false))) {
191
+ prunedRunIds.add(run.runId);
192
+ decisions.push({ ...base, decision: "pruned" });
193
+ continue;
194
+ }
195
+ errors.push({
196
+ runId: run.runId,
197
+ message: error instanceof Error ? error.message : String(error),
198
+ });
199
+ decisions.push({ ...base, decision: "kept", reason: "delete_failed" });
200
+ keptRuns += 1;
201
+ }
202
+ }
203
+ const removedJobRecords = await removeJobRecordsForRuns(home, prunedRunIds, errors);
204
+ return {
205
+ home,
206
+ apply,
207
+ olderThanMs: options.olderThanMs,
208
+ cutoff,
209
+ states,
210
+ decisions,
211
+ prunedRuns: prunedRunIds.size,
212
+ eligibleRuns,
213
+ keptRuns,
214
+ removedJobRecords,
215
+ errors,
216
+ };
217
+ }
218
+ //# sourceMappingURL=api-run-prune.js.map