cueline 0.1.5 → 0.1.7

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 (175) hide show
  1. package/.claude-plugin/plugin.json +2 -2
  2. package/.codex-plugin/plugin.json +2 -2
  3. package/CHANGELOG.md +49 -0
  4. package/README.ja.md +51 -15
  5. package/README.ko.md +51 -15
  6. package/README.md +109 -17
  7. package/README.zh-CN.md +53 -15
  8. package/README.zh-TW.md +70 -17
  9. package/config/routing.default.json +1 -0
  10. package/config/routing.schema.json +3 -0
  11. package/dist/src/api-caller-work.d.ts +18 -0
  12. package/dist/src/api-caller-work.js +441 -0
  13. package/dist/src/api-caller-work.js.map +1 -0
  14. package/dist/src/api-contracts.d.ts +86 -0
  15. package/dist/src/api-controller-handoff.d.ts +2 -2
  16. package/dist/src/api-controller-handoff.js +108 -41
  17. package/dist/src/api-controller-handoff.js.map +1 -1
  18. package/dist/src/api-run-verification.d.ts +3 -0
  19. package/dist/src/api-run-verification.js +174 -0
  20. package/dist/src/api-run-verification.js.map +1 -0
  21. package/dist/src/api-runtime-lifecycle.d.ts +6 -1
  22. package/dist/src/api-runtime-lifecycle.js +103 -9
  23. package/dist/src/api-runtime-lifecycle.js.map +1 -1
  24. package/dist/src/api.d.ts +19 -3
  25. package/dist/src/api.js +132 -36
  26. package/dist/src/api.js.map +1 -1
  27. package/dist/src/browser/browser-adapter.d.ts +15 -0
  28. package/dist/src/browser/codex-iab/bootstrap.d.ts +20 -0
  29. package/dist/src/browser/codex-iab/bootstrap.js +207 -9
  30. package/dist/src/browser/codex-iab/bootstrap.js.map +1 -1
  31. package/dist/src/browser/codex-iab/chatgpt-client.d.ts +3 -0
  32. package/dist/src/browser/codex-iab/chatgpt-client.js +115 -57
  33. package/dist/src/browser/codex-iab/chatgpt-client.js.map +1 -1
  34. package/dist/src/browser/codex-iab/probe.d.ts +36 -0
  35. package/dist/src/browser/codex-iab/probe.js +217 -0
  36. package/dist/src/browser/codex-iab/probe.js.map +1 -0
  37. package/dist/src/browser/codex-iab/recovery-evidence.d.ts +1 -1
  38. package/dist/src/browser/codex-iab/recovery-evidence.js +7 -10
  39. package/dist/src/browser/codex-iab/recovery-evidence.js.map +1 -1
  40. package/dist/src/browser/codex-iab/selectors.d.ts +1 -0
  41. package/dist/src/browser/codex-iab/selectors.js +1 -0
  42. package/dist/src/browser/codex-iab/selectors.js.map +1 -1
  43. package/dist/src/browser/codex-iab/send-button.d.ts +5 -0
  44. package/dist/src/browser/codex-iab/send-button.js +62 -0
  45. package/dist/src/browser/codex-iab/send-button.js.map +1 -0
  46. package/dist/src/browser/codex-iab/submission-url.js +6 -15
  47. package/dist/src/browser/codex-iab/submission-url.js.map +1 -1
  48. package/dist/src/browser/codex-iab/tab-discovery.js +45 -12
  49. package/dist/src/browser/codex-iab/tab-discovery.js.map +1 -1
  50. package/dist/src/browser/codex-iab/timing-options.d.ts +1 -0
  51. package/dist/src/browser/codex-iab/timing-options.js +5 -0
  52. package/dist/src/browser/codex-iab/timing-options.js.map +1 -0
  53. package/dist/src/cli/health-commands.d.ts +2 -0
  54. package/dist/src/cli/health-commands.js +191 -0
  55. package/dist/src/cli/health-commands.js.map +1 -0
  56. package/dist/src/cli/io.d.ts +4 -0
  57. package/dist/src/cli/io.js +2 -0
  58. package/dist/src/cli/io.js.map +1 -0
  59. package/dist/src/cli/main.d.ts +1 -5
  60. package/dist/src/cli/main.js +170 -77
  61. package/dist/src/cli/main.js.map +1 -1
  62. package/dist/src/cli/observation-commands.d.ts +2 -0
  63. package/dist/src/cli/observation-commands.js +239 -0
  64. package/dist/src/cli/observation-commands.js.map +1 -0
  65. package/dist/src/cli/run-status-view.d.ts +79 -0
  66. package/dist/src/cli/run-status-view.js +112 -0
  67. package/dist/src/cli/run-status-view.js.map +1 -0
  68. package/dist/src/core/controller-command-execution.d.ts +2 -2
  69. package/dist/src/core/controller-command-execution.js +108 -18
  70. package/dist/src/core/controller-command-execution.js.map +1 -1
  71. package/dist/src/core/controller-conversation-archive.d.ts +11 -0
  72. package/dist/src/core/controller-conversation-archive.js +109 -0
  73. package/dist/src/core/controller-conversation-archive.js.map +1 -0
  74. package/dist/src/core/controller-loop.d.ts +7 -1
  75. package/dist/src/core/controller-loop.js +173 -37
  76. package/dist/src/core/controller-loop.js.map +1 -1
  77. package/dist/src/core/controller-turn.d.ts +14 -2
  78. package/dist/src/core/controller-turn.js +114 -40
  79. package/dist/src/core/controller-turn.js.map +1 -1
  80. package/dist/src/core/controller-types.d.ts +5 -1
  81. package/dist/src/core/conversation-url.d.ts +3 -0
  82. package/dist/src/core/conversation-url.js +34 -0
  83. package/dist/src/core/conversation-url.js.map +1 -0
  84. package/dist/src/core/ids.d.ts +1 -0
  85. package/dist/src/core/ids.js +3 -0
  86. package/dist/src/core/ids.js.map +1 -1
  87. package/dist/src/core/run-status.d.ts +37 -3
  88. package/dist/src/core/run-status.js +147 -6
  89. package/dist/src/core/run-status.js.map +1 -1
  90. package/dist/src/core/state-machine.d.ts +49 -1
  91. package/dist/src/core/state-machine.js +335 -13
  92. package/dist/src/core/state-machine.js.map +1 -1
  93. package/dist/src/core/timing.d.ts +9 -0
  94. package/dist/src/core/timing.js +22 -0
  95. package/dist/src/core/timing.js.map +1 -0
  96. package/dist/src/diagnostics/run-doctor.d.ts +22 -0
  97. package/dist/src/diagnostics/run-doctor.js +197 -0
  98. package/dist/src/diagnostics/run-doctor.js.map +1 -0
  99. package/dist/src/jobs/status.d.ts +10 -2
  100. package/dist/src/jobs/status.js +172 -12
  101. package/dist/src/jobs/status.js.map +1 -1
  102. package/dist/src/jobs/supervisor.js +81 -6
  103. package/dist/src/jobs/supervisor.js.map +1 -1
  104. package/dist/src/observation/run-handoff.d.ts +86 -0
  105. package/dist/src/observation/run-handoff.js +309 -0
  106. package/dist/src/observation/run-handoff.js.map +1 -0
  107. package/dist/src/observation/run-timeline.d.ts +32 -0
  108. package/dist/src/observation/run-timeline.js +278 -0
  109. package/dist/src/observation/run-timeline.js.map +1 -0
  110. package/dist/src/observation/run-watch.d.ts +15 -0
  111. package/dist/src/observation/run-watch.js +82 -0
  112. package/dist/src/observation/run-watch.js.map +1 -0
  113. package/dist/src/protocol/limits.d.ts +3 -0
  114. package/dist/src/protocol/limits.js +4 -0
  115. package/dist/src/protocol/limits.js.map +1 -0
  116. package/dist/src/protocol/lint-command.d.ts +24 -0
  117. package/dist/src/protocol/lint-command.js +210 -0
  118. package/dist/src/protocol/lint-command.js.map +1 -0
  119. package/dist/src/protocol/parse-command.js +4 -0
  120. package/dist/src/protocol/parse-command.js.map +1 -1
  121. package/dist/src/protocol/types.d.ts +12 -0
  122. package/dist/src/protocol/validate-command.js +76 -3
  123. package/dist/src/protocol/validate-command.js.map +1 -1
  124. package/dist/src/router/config-loader.js +23 -2
  125. package/dist/src/router/config-loader.js.map +1 -1
  126. package/dist/src/router/materialize.js +1 -0
  127. package/dist/src/router/materialize.js.map +1 -1
  128. package/dist/src/router/resolver.js +8 -3
  129. package/dist/src/router/resolver.js.map +1 -1
  130. package/dist/src/runners/process-runner.js +108 -11
  131. package/dist/src/runners/process-runner.js.map +1 -1
  132. package/dist/src/runners/runner-adapter.d.ts +11 -0
  133. package/dist/src/runners/runner-adapter.js.map +1 -1
  134. package/dist/src/state/atomic-write.d.ts +6 -0
  135. package/dist/src/state/atomic-write.js +43 -2
  136. package/dist/src/state/atomic-write.js.map +1 -1
  137. package/dist/src/state/cancellation.js +38 -4
  138. package/dist/src/state/cancellation.js.map +1 -1
  139. package/dist/src/state/event-log.js +5 -4
  140. package/dist/src/state/event-log.js.map +1 -1
  141. package/dist/src/state/private-directory.d.ts +5 -0
  142. package/dist/src/state/private-directory.js +37 -0
  143. package/dist/src/state/private-directory.js.map +1 -0
  144. package/dist/src/state/runtime-lease.js +19 -39
  145. package/dist/src/state/runtime-lease.js.map +1 -1
  146. package/dist/src/state/runtime-record-validation.d.ts +6 -0
  147. package/dist/src/state/runtime-record-validation.js +44 -0
  148. package/dist/src/state/runtime-record-validation.js.map +1 -0
  149. package/dist/src/state/runtime-retirement.js +58 -18
  150. package/dist/src/state/runtime-retirement.js.map +1 -1
  151. package/dist/src/state/runtime-takeover-intent.js +2 -2
  152. package/dist/src/state/runtime-takeover-intent.js.map +1 -1
  153. package/dist/src/state/store.d.ts +1 -0
  154. package/dist/src/state/store.js +12 -6
  155. package/dist/src/state/store.js.map +1 -1
  156. package/dist/src/version.d.ts +1 -1
  157. package/dist/src/version.js +1 -1
  158. package/docs/architecture.md +10 -9
  159. package/docs/assets/cueline-loop-en.svg +1 -1
  160. package/docs/assets/cueline-loop-ja.svg +1 -1
  161. package/docs/assets/cueline-loop-ko.svg +1 -1
  162. package/docs/assets/cueline-loop-zh-CN.svg +1 -1
  163. package/docs/assets/cueline-loop-zh-TW.svg +1 -1
  164. package/docs/compatibility.md +8 -8
  165. package/docs/controller-protocol.md +39 -8
  166. package/docs/experiments/protocol-lint.md +40 -0
  167. package/docs/experiments/run-doctor.md +39 -0
  168. package/docs/experiments/run-handoff.md +39 -0
  169. package/docs/experiments/run-timeline.md +35 -0
  170. package/docs/experiments/run-watch.md +31 -0
  171. package/docs/runner-contract.md +22 -8
  172. package/docs/state-and-recovery.md +24 -9
  173. package/package.json +2 -2
  174. package/schemas/controller-command.schema.json +89 -4
  175. package/skills/cueline/SKILL.md +58 -12
package/README.md CHANGED
@@ -13,21 +13,34 @@
13
13
 
14
14
  **CueLine hands the wheel to an open ChatGPT web conversation: it plans the run and calls each next step, while CueLine checks every text command and the current Codex does the permitted local work.**
15
15
 
16
- The web page never touches your machine and has no local tools. It only emits one text command per round. CueLine decides whether that command is well-formed and belongs to this run. By default, it persists `advise` jobs for the current Codex to execute and submit; an explicitly selected process executor can instead run registered local workers. CueLine keeps bounded controller evidence and the full local record.
16
+ The web page never touches your machine and has no local tools. It only emits one text command per round. CueLine decides whether that command is well-formed and belongs to this run. By default, it persists caller jobs for the current Codex: `advise` is a coordination-only handoff, while `work` requires a durable claim and start before any mutation. An explicitly double-authorized process executor can instead run registered local workers. CueLine keeps bounded controller evidence and the full local record.
17
17
 
18
18
  CueLine is a standalone implementation with **no runtime npm dependencies**. It is not a wrapper around Omnilane or GPT Relay.
19
19
 
20
+ ## Latest release: 0.1.7
21
+
22
+ - Added safe run inventory, doctor, watch, timeline, handoff, verification, protocol lint, browser diagnostics, and deterministic inspected-evidence pagination.
23
+ - Hardened browser tab/control evidence, command/routing bounds, atomic job status, private durable state, workdir identity, runtime/cancellation records, and redacted CLI output.
24
+ - Added opt-in exact-conversation archiving after durable `complete`, with a one-click write-ahead fence, Pro-active/navigation checks, and no retry after ambiguity.
25
+ - Verified 454/454 tests and a disposable real ChatGPT Web Pro run that completed and archived exactly once without interrupting Pro or touching the existing user conversation.
26
+
27
+ Read the complete [changelog](CHANGELOG.md#017---2026-07-16) or the immutable [v0.1.7 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.1.7).
28
+
20
29
  ## How a run actually goes
21
30
 
22
31
  <img alt="A caller-first CueLine run: ChatGPT emits text commands, the current Codex performs local advice, and CueLine returns bounded evidence until complete." src="docs/assets/cueline-loop-en.svg" width="100%">
23
32
 
24
33
  Each round: CueLine writes down what it is about to ask, sends one observation into the conversation, and later reads back exactly one `<CueLineControl>` envelope. The controller picks one of five actions — `dispatch`, `wait`, `inspect`, `complete`, `blocked` — and nothing outside that envelope is ever executed. A command that names the wrong run, the wrong round, or a malformed job is sent back for a bounded repair attempt rather than guessed at. The loop pauses at `awaiting_controller` after one durable send, at a caller handoff, or stops at `complete`, `blocked`, or the round limit (12 by default).
25
34
 
35
+ Controller commands also have fail-closed resource bounds: 131,072 characters
36
+ per envelope, 64 jobs per dispatch, and 256 explicit job IDs per wait or
37
+ inspect. These checks happen before job registration or process execution.
38
+
26
39
  A non-default `maxRounds` is fixed when the run is created and counts total controller rounds across every ownerless pause. Later continuations normally omit it and reuse the durable value; supplying a different value is rejected rather than silently resetting or widening the budget.
27
40
 
28
- `caller` is the default executor for both `startCueLineRun` and `runCueLine`. With the built-in browser, CueLine submits once, captures the exact conversation URL, returns `awaiting_controller`, and releases the runtime lease instead of holding one tool call open while Pro thinks. A later `continueCueLineRun` performs one read-only observation: unfinished work returns `awaiting_controller` again without resending. A dispatch then produces durable pending `advise` jobs and returns `awaiting_caller`; the current Codex executes each exact task with its local tools, calls `submitCueLineCallerJobResult`, and continues the same run. ChatGPT planned the work—it did not perform the inspection. Caller advice has no execution claim, so coordinate one session: two sessions may both perform it, while only the first terminal evidence submitted wins. Caller-mode `work` is rejected until CueLine can issue a duplicate-safe execution claim.
41
+ `caller` is the default executor for both `startCueLineRun` and `runCueLine`. With the built-in browser, CueLine submits once, captures the exact conversation URL, returns `awaiting_controller`, and releases the runtime lease instead of holding one tool call open while Pro thinks. A later `continueCueLineRun` performs one read-only observation: unfinished work returns `awaiting_controller` again without resending. A dispatch produces durable pending jobs. `advise` returns `awaiting_caller`; it has no side-effect claim, so coordinate one session. `work` returns `awaiting_caller_work` and remains unstarted until the current Codex calls `claimCueLineCallerJob` and `startCueLineCallerJob`. The claim is bound to run, job, task hash, absolute workdir, canonical directory identity, caller identity, and a fencing token; callers execute only in its returned `resolvedWorkdir`. Started work is never automatically retried; an expired started claim becomes `ambiguous`. ChatGPT proposed and reviewed the work—it did not use local tools or perform the work itself.
29
42
 
30
- For explicit `executor: "process"`, the controller chooses *what should happen* and the local side chooses *whether and how it may happen*: the lane must be enabled, the candidate must be available **before** anything spawns, and `argv[0]` must already be registered by your routing config. Nothing is passed through a shell. Independent advice defaults to two concurrent jobs globally and per lane; a batch containing `work` is serial. Once a worker starts, there is no silent fallback to a second candidate.
43
+ Process execution requires both `executor: "process"` and `allowProcessExecution: true`; a non-terminal continuation must pass the second authorization again. The bundled route also uses `--ignore-user-config`, preventing hidden workers from loading user-configured MCP servers or their command arguments. The controller chooses *what should happen* and the local side chooses *whether and how it may happen*: the lane must be enabled, the candidate must be available **before** anything spawns, and `argv[0]` must already be registered by your routing config. Nothing is passed through a shell. A process `workdir` must be absolute; when omitted, CueLine binds the accepted job to the runtime's resolved absolute workspace so recovery cannot silently move it to another checkout. Independent advice defaults to two concurrent jobs globally and per lane; a batch containing `work` is serial. Once a worker starts, there is no silent fallback to a second candidate. Status exposes the resolved runner, PID, phase, last progress time, and safely observed model/provider metadata.
31
44
 
32
45
  The controller protocol keeps routing levels explicit: `lane` names the lane (`default`), while `codex-default` is a candidate runner inside that lane, not a lane. CueLine validates the entire `dispatch` before registering any job; an invalid lane or runner rejects the whole dispatch for repair, so no valid-looking subset starts early.
33
46
 
@@ -48,15 +61,15 @@ You need Node.js 22+, Codex with its built-in Browser, and — for the bundled d
48
61
  Install from the npm registry:
49
62
 
50
63
  ```bash
51
- npm install -g cueline@0.1.5
64
+ npm install -g cueline@0.1.7
52
65
  cueline install
53
66
  cueline doctor
54
67
  ```
55
68
 
56
- As a fallback, install the packaged tarball from the [v0.1.5 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.1.5), which also carries its `.sha256` checksum:
69
+ As a fallback, install the packaged tarball from the [v0.1.7 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.1.7), which also carries its `.sha256` checksum:
57
70
 
58
71
  ```bash
59
- npm install -g https://github.com/Seraphim0916/cueline/releases/download/v0.1.5/cueline-0.1.5.tgz
72
+ npm install -g https://github.com/Seraphim0916/cueline/releases/download/v0.1.7/cueline-0.1.7.tgz
60
73
  cueline install
61
74
  cueline doctor
62
75
  ```
@@ -79,7 +92,7 @@ cueline doctor
79
92
  Then, in Codex:
80
93
 
81
94
  1. Open `https://chatgpt.com` in Codex's built-in Browser and sign in.
82
- 2. Leave the conversation you want to be in charge selected — that page is the controller. Its composer must be on a `Pro` model; CueLine selects `Pro` for you if it is not, and refuses to send otherwise.
95
+ 2. Leave the conversation you want to be in charge selected — that page is the controller. If no selected tab is available and several matching ChatGPT tabs exist, CueLine returns `IAB_CHATGPT_TAB_AMBIGUOUS` instead of choosing the first one. Its composer must be on a `Pro` model; CueLine selects `Pro` for you if it is not, and refuses to send otherwise.
83
96
  3. Ask Codex to use CueLine for the task: *"Use CueLine and let the open ChatGPT Pro conversation direct this task."*
84
97
  4. Keep the returned `runId`. It is how an interrupted run is resumed.
85
98
 
@@ -89,23 +102,27 @@ The bundled `cueline` skill drives the package from Codex's own Node runtime, wh
89
102
 
90
103
  ```js
91
104
  import {
105
+ claimCueLineCallerJob,
92
106
  continueCueLineRun,
93
107
  createCodexIabAdapter,
108
+ heartbeatCueLineCallerJob,
94
109
  runCueLine,
110
+ startCueLineCallerJob,
95
111
  submitCueLineCallerJobResult,
96
112
  } from "cueline";
97
113
 
98
114
  let result = await runCueLine({
99
115
  request: "Inspect the repository, delegate an implementation plan, and report the evidence.",
100
- browser: createCodexIabAdapter(),
116
+ browser: createCodexIabAdapter({ browser: globalThis.browser }),
117
+ // Optional opt-in: archiveControllerConversationOnComplete: true,
101
118
  // Optional: conversationUrl, routingConfig / routingConfigPath, home, cwd,
102
119
  // runTimeoutMs, signal, and per-job/default limits.
103
120
  }); // defaults to executor: "caller"
104
121
 
105
- while (result.status === "awaiting_controller" || result.status === "awaiting_caller") {
122
+ while (["awaiting_controller", "awaiting_caller", "awaiting_caller_work"].includes(result.status)) {
106
123
  if (result.status === "awaiting_controller") {
107
124
  await waitBeforeNextObservation(); // bounded backoff; never resend
108
- } else {
125
+ } else if (result.status === "awaiting_caller") {
109
126
  for (const job of result.pendingJobs ?? []) {
110
127
  const stdout = await executeExactLocalAdvice(job.spec.task);
111
128
  await submitCueLineCallerJobResult(result.runId, job.jobId, {
@@ -113,6 +130,28 @@ while (result.status === "awaiting_controller" || result.status === "awaiting_ca
113
130
  stdout,
114
131
  });
115
132
  }
133
+ } else {
134
+ for (const job of result.pendingJobs ?? []) {
135
+ if (job.spec.mode !== "work") continue;
136
+ const claim = await claimCueLineCallerJob(result.runId, job.jobId, {
137
+ callerId: "stable-codex-task-identity",
138
+ });
139
+ const proof = {
140
+ claimId: claim.claimId,
141
+ callerId: claim.callerId,
142
+ fencingToken: claim.fencingToken,
143
+ };
144
+ await startCueLineCallerJob(result.runId, job.jobId, proof);
145
+ const stdout = await executeExactLocalWork(job.spec.task, claim.resolvedWorkdir, {
146
+ heartbeat: () => heartbeatCueLineCallerJob(result.runId, job.jobId, proof),
147
+ });
148
+ await submitCueLineCallerJobResult(
149
+ result.runId,
150
+ job.jobId,
151
+ { status: "succeeded", stdout },
152
+ { claim: proof },
153
+ );
154
+ }
116
155
  }
117
156
  result = await continueCueLineRun({ runId: result.runId });
118
157
  }
@@ -122,20 +161,26 @@ if (result.status === "complete") {
122
161
  }
123
162
  ```
124
163
 
125
- `startCueLineRun` creates the durable run and returns `ready` without driving the browser. `runCueLine` creates and advances it to a durable controller-observation pause, caller handoff, or terminal state. `continueCueLineRun({ runId })` advances the same conversation and reuses its stored URL. `loadCueLineRunState(runId)` is read-only. A terminal run is returned as-is. Before continuation, run `cueline run status <run-id> --json`: ownerless `controller_response_pending` with exactly one normally submitted turn and `safeNextAction: observe` means Pro's response has not yet been observed; wait briefly and continue it without resend. `phase: prompt_not_sent` with `safeNextAction: retry` is used only when the exact request has built-in write-ahead evidence or request-correlated `definitely_not_sent` evidence. `safeNextAction: reconcile` is reserved for ambiguous, manually submitted, or multiple pending turns. Ownerless `caller_jobs_pending` is a healthy local handoff; an accepted response plus `jobs_running` means an explicit process executor is active.
164
+ `archiveControllerConversationOnComplete` defaults to `false` and is fixed when the run is created. When enabled, CueLine first persists `complete`, then archives only the exact bound conversation while Pro is idle. A proven failure before the durable click checkpoint can be retried; after that checkpoint, any timeout, restart, navigation race, or missing proof becomes `ambiguous` and CueLine never clicks Archive again. `blocked` and `cancelled` runs are left open.
165
+
166
+ `startCueLineRun` creates the durable run and returns `ready` without driving the browser. `runCueLine` creates and advances it to a durable controller-observation pause, caller handoff, or terminal state. `continueCueLineRun({ runId })` advances the same conversation and reuses its stored URL. `loadCueLineRunState(runId)` is read-only. A terminal run is returned as-is. Before continuation, run `cueline run status <run-id> --json`: `controller_response_pending` with exactly one normally submitted turn and `safeNextAction: observe` means Pro's response has not yet been observed; wait briefly and continue it without resend. That exact read-only observer can be safely fenced even after its lease becomes stale, but ambiguous/manual submissions, jobs, pending commands, cancellation, or a missing/mismatched URL still require explicit recovery. `phase: prompt_not_sent` with `safeNextAction: retry` is used only with write-ahead or request-correlated `definitely_not_sent` evidence. Caller work phases report `claim_caller_work`, `start_caller_work`, or `continue_caller_work`; a dispatch alone is not local execution. An accepted response plus `jobs_running` means a double-authorized process executor is active. CLI status output is an explicit metadata allowlist: it omits task bodies, caller identities, task hashes, workdirs, and runtime owner IDs. The formal caller claim API returns the exact task and workdir to the authorized caller; the detailed read-only API remains available for trusted local diagnostics.
167
+
168
+ `listCueLineRuns()` is a read-only, sanitized inventory for discovering persisted run IDs. It omits controller text, conversation URLs, job tasks, and worker output.
169
+
170
+ `verifyCueLineRun(runId)` is a read-only integrity check for the creation marker, event replay and authority fences, optional snapshot, runtime lease, and job status evidence. It returns stable findings without returning durable run content.
126
171
 
127
172
  Inside Codex's runtime, import the absolute module that `cueline api path` prints — that is the built API of the package you installed.
128
173
 
129
174
  ## The CLI
130
175
 
131
- The CLI does not drive the browser. `doctor`, `routing`, `jobs`, `run status`, `api path`, and `config path` are read-only. `install`/`uninstall` change the package-owned skill link. `run reconcile`, `run takeover`, `run reconcile-runtime`, `run cancel`/`run stop`, and `job cancel` append evidence or change durable local run/job state. Run `cueline help` for every positional argument and option before using a state-changing command.
176
+ The CLI does not drive the browser. `doctor`, `routing`, `jobs`, `runs`, `run status`, `run verify`, `api path`, and `config path` are read-only. `install`/`uninstall` change the package-owned skill link. `run reconcile`, `run takeover`, `run reconcile-runtime`, `run cancel`/`run stop`, and `job cancel` append evidence or change durable local run/job state. Run `cueline help` for every positional argument and option before using a state-changing command.
132
177
 
133
178
  ```console
134
179
  $ cueline install
135
180
  CueLine skill installed: /Users/you/.codex/skills/cueline
136
181
 
137
182
  $ cueline doctor
138
- CueLine 0.1.5
183
+ CueLine 0.1.7
139
184
  status ok
140
185
  node 22.14.0 ok
141
186
  config /usr/local/lib/node_modules/cueline/config/routing.default.json valid
@@ -144,18 +189,45 @@ caller_ready yes
144
189
  caller_lanes 1
145
190
  process_available_lanes 1
146
191
 
192
+ $ cueline doctor --json
193
+ {"version":"0.1.7","status":"ok","node":{"version":"22.14.0","ok":true,"requirement":">=22"},...}
194
+
147
195
  $ cueline api path
148
196
  /usr/local/lib/node_modules/cueline/dist/src/api.js
149
197
 
150
198
  $ cueline routing
151
199
  default codex-default available
152
200
 
201
+ $ cueline routing --json
202
+ {"version":"0.1.7","availableLanes":1,"lanes":[{"name":"default","status":"available","selectedRunnerId":"codex-default"}],...}
203
+
153
204
  $ cueline jobs
154
205
  No jobs.
155
206
 
207
+ $ cueline protocol lint response.txt --run-id run_... --round 3 --request-id msg_... --json
208
+ {"valid":false,"issues":[{"code":"LEGACY_RUNNER_ID_FIELD",...}]}
209
+
210
+ $ cueline runs
211
+ No runs.
212
+
156
213
  $ cueline run status run_... --json
157
214
  {"status":"running","executor":"caller","phase":"caller_jobs_pending","runtime":{"ownership":"missing"},...}
158
215
 
216
+ $ cueline run doctor run_... --json
217
+ {"outcome":"action_required","phase":"caller_jobs_pending","nextAction":"execute_caller_jobs",...}
218
+
219
+ $ cueline run watch run_... --after 42 --timeout-ms 5000 --json
220
+ {"outcome":"changed","previousSequence":42,"currentSequence":43,...}
221
+
222
+ $ cueline run handoff run_... --json
223
+ {"schema":"cueline-handoff/0.1","run":{"runId":"run_...","safeNextAction":"execute_caller_jobs"},...}
224
+
225
+ $ cueline run timeline run_... --after 40 --limit 20 --json
226
+ {"schema":"cueline-timeline/0.1","entries":[{"sequence":41,"type":"job_status",...}],...}
227
+
228
+ $ cueline run verify run_... --json
229
+ {"runId":"run_...","outcome":"verified","marker":"valid",...}
230
+
159
231
  $ cueline run takeover stale_run_... --json
160
232
  {"runId":"stale_run_...","outcome":"taken_over","next":"continue",...}
161
233
 
@@ -174,13 +246,33 @@ CueLine skill removed: /Users/you/.codex/skills/cueline
174
246
 
175
247
  `cueline doctor` exits non-zero when Node is too old or no enabled caller lane exists. `process_available_lanes` may be zero without degrading caller mode; use `cueline routing` to inspect process availability before explicitly selecting that executor. `cueline api path` is what the skill imports, so a packaged install needs no repository checkout. `cueline help` lists every command's exact syntax, including `--json` and the manual-reconcile confirmation flags.
176
248
 
249
+ The experimental `run doctor` command converts a run snapshot into stable
250
+ finding codes, bounded evidence, and a safe next action without writing state.
251
+ See [`docs/experiments/run-doctor.md`](docs/experiments/run-doctor.md).
252
+
253
+ The experimental `run watch` command performs a bounded, lease-free observation
254
+ using the durable event sequence as its cursor. See
255
+ [`docs/experiments/run-watch.md`](docs/experiments/run-watch.md).
256
+
257
+ The experimental `protocol lint` command validates a Pro envelope offline and
258
+ reports all known contract corrections in one pass. See
259
+ [`docs/experiments/protocol-lint.md`](docs/experiments/protocol-lint.md).
260
+
261
+ The experimental `run handoff` command produces a safe restart packet with
262
+ exact identities and absolute paths. See
263
+ [`docs/experiments/run-handoff.md`](docs/experiments/run-handoff.md).
264
+
265
+ The experimental `run timeline` command exposes a sanitized, cursor-paginated
266
+ audit view without raw event payloads. See
267
+ [`docs/experiments/run-timeline.md`](docs/experiments/run-timeline.md).
268
+
177
269
  Use `run takeover` only when `run status` reports an exact stale owner. It refuses a fresh active heartbeat and returns `next: continue` or `next: reconcile_runtime`; follow that value instead of guessing.
178
270
 
179
271
  ## Configuration
180
272
 
181
273
  `CUELINE_CONFIG` selects a routing file; `CUELINE_HOME` moves local state (default `~/.cueline`).
182
274
 
183
- Caller execution needs no spawned route. When `executor: "process"` is explicitly selected, the bundled `default` lane holds one candidate, `codex-default`: `codex exec` with the task on stdin, `read-only` for `advise`, and `workspace-write` for `work`. To register a different process worker, copy [`config/routing.default.json`](config/routing.default.json), add your candidate, and point `CUELINE_CONFIG` at it.
275
+ Caller execution needs no spawned route. When `executor: "process"` and `allowProcessExecution: true` are both selected, the bundled `default` lane holds one candidate, `codex-default`: isolated `codex exec --ignore-user-config` with the task on stdin, `read-only` for `advise`, and `workspace-write` for `work`. To register a different process worker, copy [`config/routing.default.json`](config/routing.default.json), add your candidate, and point `CUELINE_CONFIG` at it.
184
276
 
185
277
  State lives under `CUELINE_HOME`:
186
278
 
@@ -196,11 +288,11 @@ jobs/<job-id>.json per-job execution evidence
196
288
 
197
289
  The event log is the record: the controller turn is written before it is sent, and a job is registered before its process starts, so an interruption between intent and side effect leaves a trace. A corrupt snapshot is ignored and rebuilt from event 1 rather than trusted.
198
290
 
199
- Recovery reattaches only to the exact recorded conversation URL. CueLine recognizes long prompts that ChatGPT automatically converts into attachment chips and makes at most one send attempt. Contenteditable block newlines are normalized before readiness comparison. An ambiguous click is `possibly_sent` and is never clicked again. If an operator manually sends that attachment after ChatGPT creates the first `/c/...` URL, `cueline run reconcile ... --manual-send-confirmed --conversation-url URL` atomically binds the exact URL and records an append-only confirmation; CueLine then requires exact conversation, Pro model, and protocol/run/round/request identity before importing the response without resend or duplicate dispatch.
291
+ Recovery reattaches only to the exact recorded conversation URL. CueLine recognizes long prompts that ChatGPT automatically converts into attachment chips and makes at most one send attempt. Contenteditable block newlines are normalized before readiness comparison. An ambiguous click is `possibly_sent` and is never clicked again. A response is considered in progress only while a visible, enabled, actionable Stop control exists; hidden residual buttons do not suppress a completed Pro response. If an operator manually sends an attachment after ChatGPT creates the first `/c/...` URL, `cueline run reconcile ... --manual-send-confirmed --conversation-url URL` atomically binds the exact URL and records an append-only confirmation; CueLine then requires exact conversation, Pro model, and protocol/run/round/request identity before importing the response without resend or duplicate dispatch.
200
292
 
201
293
  Never interrupt Pro or use `Answer now`, `Respond now`, `Stop`, or an equivalent acceleration control while it is answering. Pro has no local tools and no default knowledge of repository layout or local paths. Caller evidence must include exact code/error identifiers, relevant code excerpts, and absolute local paths, then explicitly ask whether Pro needs more local evidence.
202
294
 
203
- Controller observations prefer successful non-empty stdout, retain full stdout/stderr in local job status, and share one 12,000-character evidence budget with an explicit truncation marker.
295
+ Controller observations prefer successful non-empty stdout, retain full stdout/stderr in local job status, and share one 12,000-character evidence budget with an explicit truncation marker. Every preferred output/error field includes a raw-character `evidence_window` and SHA-256 `content_hash`. When `next_offset` is non-null, Pro can inspect exactly one job by copying it as `evidence_offset` and the hash as `evidence_hash`; CueLine returns the next bounded window without rerunning the job. Changed evidence invalidates the cursor instead of mixing versions. An accepted `inspect(job_ids)` reserves that budget for the named jobs before unrelated evidence, so the next Pro turn receives the requested output instead of only its terminal status. `wait` and `inspect` targets must be exact job IDs from the current observation; one unknown target rejects the entire command for repair before any partial wait or inspection. Controller commands are exact per action: unknown top-level fields, fields belonging to another action, empty/duplicate/malformed `job_ids`, `prompt` in place of `task`, and `runner_id` in place of `runner` are rejected with a repair error instead of silently ignored.
204
296
 
205
297
  ## Verify
206
298
 
@@ -217,7 +309,7 @@ npm pack --dry-run
217
309
 
218
310
  ## Limits in 0.1
219
311
 
220
- Text commands only. One conversation per run. Selecting `Pro` is the only model switch CueLine makes. Automatic long-text-to-attachment conversion is supported, but deliberate file upload, images, Deep Research, Projects, and Apps are not. Caller mode is `advise` only; process `work` must be explicit. No automatic retry or fallback starts a worker twice. macOS is the primary desktop target and Linux is the CI target; Windows is unverified. The adapter depends on the current ChatGPT web UI, so a UI change surfaces explicitly, never as a fabricated answer.
312
+ Text commands only. One conversation per run. Selecting `Pro` is the only model switch CueLine makes. Automatic long-text-to-attachment conversion is supported, but deliberate file upload, images, Deep Research, Projects, and Apps are not. Caller `work` requires an explicit durable claim/start and a heartbeat for long work; process execution requires two explicit authorization fields. No automatic retry or fallback starts work twice. macOS is the primary desktop target and Linux is the CI target; Windows is unverified. The adapter depends on the current ChatGPT web UI, so a UI change surfaces explicitly, never as a fabricated answer.
221
313
 
222
314
  See [compatibility](docs/compatibility.md) for the full matrix.
223
315
 
package/README.zh-CN.md CHANGED
@@ -13,10 +13,19 @@
13
13
 
14
14
  **CueLine 把方向盘交给一个已经打开的 ChatGPT 网页会话:由它规划运行、发出每一步文本指令;CueLine 负责校验,当前 Codex 才在本机执行获准的工作。**
15
15
 
16
- 那个网页碰不到你的机器,也没有本地工具。CueLine 默认把 `advise` 作业持久化并交回当前 Codex 执行;只有显式选择 `process` executor,才会启动已注册的本地 worker。
16
+ 那个网页碰不到你的机器,也没有本地工具。CueLine 默认把 caller 作业持久化:`advise` 是协调式交接;`work` 必须先获得持久 claim 并正式 start。只有双重显式授权 `process` executor,才会启动已注册的本地 worker。
17
17
 
18
18
  CueLine 是独立实现,**没有任何运行时 npm 依赖**,也不是 Omnilane 或 GPT Relay 的包装层。
19
19
 
20
+ ## 最新版本:0.1.7
21
+
22
+ - 新增安全的 run 清单、doctor、watch、timeline、handoff、完整性验证、协议 lint、浏览器诊断与 inspect 证据分页。
23
+ - 强化标签页/按钮证据、命令与路由上限、原子 job 状态、私有持久数据、workdir 身份、runtime/取消记录和 CLI 脱敏。
24
+ - 新增可选的 `complete` 后精确会话归档:点击前有持久 fence,Pro 再次回答或页面切换时拒绝,进入模糊状态后绝不重复点击。
25
+ - 完成 454/454 测试和一次可丢弃的真实 ChatGPT Web Pro 验收;控制器自然完成、只归档一次,原有用户会话未被触碰。
26
+
27
+ 完整内容请查看 [changelog](CHANGELOG.md#017---2026-07-16) 或不可变的 [v0.1.7 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.1.7)。
28
+
20
29
  ## 一次运行实际是怎么走的
21
30
 
22
31
  <img alt="Caller-first CueLine 运行:ChatGPT 发出文本命令,当前 Codex 执行本地只读检查,CueLine 回传有界证据直至 complete。" src="docs/assets/cueline-loop-zh-CN.svg" width="100%">
@@ -25,9 +34,9 @@ CueLine 是独立实现,**没有任何运行时 npm 依赖**,也不是 Omnil
25
34
 
26
35
  非默认的 `maxRounds` 会在创建 run 时固定,并跨所有无 owner 的暂停累计控制器总轮次。后续继续通常省略它并复用持久值;传入不同数值会被拒绝,不会暗中重置或放宽预算。
27
36
 
28
- `startCueLineRun` 与 `runCueLine` 都默认使用 `caller`。使用内置浏览器时,CueLine 只发送一次、保存精确会话 URL,然后返回 `awaiting_controller` 并释放 runtime lease,不会让单次工具调用一直等待 Pro。之后的 `continueCueLineRun` 只做一次只读观测;若尚未完成,会再次返回 `awaiting_controller`,绝不重发。`dispatch` 才返回 `awaiting_caller`;当前 Codex 执行各个 `advise` 任务、调用 `submitCueLineCallerJobResult`,再继续同一 run。Pro 控制器只下文本命令,不能使用本地工具。Caller advice 没有 execution claim,请协调由单一 session 执行;两个 session 可能都做同一项检查,但只有第一份提交的终态证据生效。Caller 模式明确拒绝 `work`。
37
+ `startCueLineRun` 与 `runCueLine` 都默认使用 `caller`。CueLine 发送一次后返回 `awaiting_controller` 并释放 lease;继续只做一次只读观测,绝不重发。`advise` 返回 `awaiting_caller`,没有副作用 claim;`work` 返回 `awaiting_caller_work`,必须由当前 Codex 调用 `claimCueLineCallerJob` `startCueLineCallerJob` 后才能修改。claim 绑定 run、job、task hash、绝对 workdir、caller identity fencing token;已开始的工作不会自动重试,过期后成为 `ambiguous`。Pro 只提出和审查文本指令,不会使用本地工具。
29
38
 
30
- 控制器决定*应该发生什么*;本地这一侧决定*是否允许发生、以何种方式发生*:通道(lane)必须启用、候选必须在任何进程启动**之前**确认可用、`argv[0]` 必须早已由你的路由配置注册。没有任何内容会经过 shell。worker 一旦启动,就不会悄悄退回到第二个候选——失败以证据的形式返回,而不是自动重试。
39
+ Process 模式必须同时指定 `executor: "process"` 与 `allowProcessExecution: true`,非终态继续也要再次传入第二道授权。内置 route 还使用 `--ignore-user-config`,不会让隐藏 worker 加载用户配置的 MCP server 或其命令参数。通道必须启用、候选必须在任何进程启动**之前**确认可用、`argv[0]` 必须已注册。没有内容经过 shell,也不会在启动后自动换候选。
31
40
 
32
41
  控制器协议有意区分路由层级:`lane` 填的是通道名称 `default`;`codex-default` 是该通道内的候选执行器,不是通道。CueLine 会在注册任何作业之前先验证整份 `dispatch`;只要包含无效通道或执行器,整份派工就会被退回修复,不会先执行其中一部分。
33
42
 
@@ -48,15 +57,15 @@ ChatGPT Pro 订阅套餐与“选定的 Pro 模型”是两回事。账号或个
48
57
  从 npm registry 安装:
49
58
 
50
59
  ```bash
51
- npm install -g cueline@0.1.5
60
+ npm install -g cueline@0.1.7
52
61
  cueline install
53
62
  cueline doctor
54
63
  ```
55
64
 
56
- 作为后备,也可以安装 [v0.1.5 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.1.5) 上的打包 tarball,该 release 同时附带它的 `.sha256` 校验值:
65
+ 作为后备,也可以安装 [v0.1.7 release](https://github.com/Seraphim0916/cueline/releases/tag/v0.1.7) 上的打包 tarball,该 release 同时附带它的 `.sha256` 校验值:
57
66
 
58
67
  ```bash
59
- npm install -g https://github.com/Seraphim0916/cueline/releases/download/v0.1.5/cueline-0.1.5.tgz
68
+ npm install -g https://github.com/Seraphim0916/cueline/releases/download/v0.1.7/cueline-0.1.7.tgz
60
69
  cueline install
61
70
  cueline doctor
62
71
  ```
@@ -89,23 +98,27 @@ cueline doctor
89
98
 
90
99
  ```js
91
100
  import {
101
+ claimCueLineCallerJob,
92
102
  continueCueLineRun,
93
103
  createCodexIabAdapter,
104
+ heartbeatCueLineCallerJob,
94
105
  runCueLine,
106
+ startCueLineCallerJob,
95
107
  submitCueLineCallerJobResult,
96
108
  } from "cueline";
97
109
 
98
110
  let result = await runCueLine({
99
111
  request: "Inspect the repository, delegate an implementation plan, and report the evidence.",
100
- browser: createCodexIabAdapter(),
112
+ browser: createCodexIabAdapter({ browser: globalThis.browser }),
113
+ // 可选并显式启用:archiveControllerConversationOnComplete: true,
101
114
  // 可选:conversationUrl、routingConfig / routingConfigPath、home、cwd、
102
115
  // runTimeoutMs、signal,以及作业/默认期限。
103
116
  }); // 默认 executor: "caller"
104
117
 
105
- while (result.status === "awaiting_controller" || result.status === "awaiting_caller") {
118
+ while (["awaiting_controller", "awaiting_caller", "awaiting_caller_work"].includes(result.status)) {
106
119
  if (result.status === "awaiting_controller") {
107
120
  await waitBeforeNextObservation(); // 有界退避;绝不重发
108
- } else {
121
+ } else if (result.status === "awaiting_caller") {
109
122
  for (const job of result.pendingJobs ?? []) {
110
123
  const stdout = await executeExactLocalAdvice(job.spec.task);
111
124
  await submitCueLineCallerJobResult(result.runId, job.jobId, {
@@ -113,6 +126,19 @@ while (result.status === "awaiting_controller" || result.status === "awaiting_ca
113
126
  stdout,
114
127
  });
115
128
  }
129
+ } else {
130
+ for (const job of result.pendingJobs ?? []) {
131
+ if (job.spec.mode !== "work") continue;
132
+ const claim = await claimCueLineCallerJob(result.runId, job.jobId, {
133
+ callerId: "stable-codex-task-identity",
134
+ });
135
+ const proof = { claimId: claim.claimId, callerId: claim.callerId, fencingToken: claim.fencingToken };
136
+ await startCueLineCallerJob(result.runId, job.jobId, proof);
137
+ const stdout = await executeExactLocalWork(job.spec.task, claim.resolvedWorkdir, {
138
+ heartbeat: () => heartbeatCueLineCallerJob(result.runId, job.jobId, proof),
139
+ });
140
+ await submitCueLineCallerJobResult(result.runId, job.jobId, { status: "succeeded", stdout }, { claim: proof });
141
+ }
116
142
  }
117
143
  result = await continueCueLineRun({ runId: result.runId });
118
144
  }
@@ -122,22 +148,22 @@ if (result.status === "complete") {
122
148
  }
123
149
  ```
124
150
 
125
- 若返回 `awaiting_controller`,表示同一个精确 request 已发送、但 Pro 回复尚未被观测;稍后继续只会执行只读观测,不会重发。若返回 `awaiting_caller`,由当前 Codex 执行 `result.pendingJobs` 中的每个 `advise`,用 `submitCueLineCallerJobResult` 提交真实结果,再调用 `continueCueLineRun`。这不是 Pro 网页直接使用本地工具。
151
+ `awaiting_controller` 只读观测且不重发;`awaiting_caller` 交接 `advise`;`awaiting_caller_work` 必须依次 claim、start、执行、heartbeat 并带 claim proof 提交。Pro 网页从不直接使用本地工具。
126
152
 
127
153
  在 Codex 的 runtime 里,import `cueline api path` 打印出的那个绝对路径模块——那就是你安装的那份包构建出来的 API。
128
154
 
129
- `startCueLineRun` 只创建持久 run 并返回 `ready`;`runCueLine` 创建并推进到持久 controller 观测暂停、caller 交接或终态。缺少 owner 的 `controller_response_pending` 若只有一个正常发送的回合且显示 `safeNextAction: observe`,表示同一个 Pro 回复仍待只读观测;稍后继续即可且不得重发。`safeNextAction: reconcile` 只用于模糊、人工发送或多个待对账回合。缺少 owner 的 `caller_jobs_pending` 是正常本地交接,并非 orphan,也不是仍在等 ChatGPT。
155
+ `startCueLineRun` 只创建持久 run 并返回 `ready`;`runCueLine` 创建并推进到持久 controller 观测暂停、caller 交接或终态。缺少 owner 的 `controller_response_pending` 若只有一个正常发送的回合且显示 `safeNextAction: observe`,表示同一个 Pro 回复仍待只读观测;稍后继续即可且不得重发。`safeNextAction: reconcile` 只用于模糊、人工发送或多个待对账回合。缺少 owner 的 `caller_jobs_pending` 是正常本地交接,并非 orphan,也不是仍在等 ChatGPT。CLI 的 `run status` 只输出交接所需元数据,不包含 task 正文、caller 身份、task hash、workdir 或 runtime owner ID;正式 claim 后,API 才把精确 task 与 workdir 交给获授权的 caller。
130
156
 
131
157
  ## CLI
132
158
 
133
- CLI 不驱动浏览器。`doctor`、`routing`、`jobs`、`run status`、`api path`、`config path` 都是只读;`install`/`uninstall` 只修改包所拥有的 skill 链接;`run reconcile`、`run takeover`、`run reconcile-runtime`、`run cancel`/`run stop`、`job cancel` 会追加审计证据或修改持久 run/job 状态。执行写入状态的命令前,先用 `cueline help` 核对完整参数。
159
+ CLI 不驱动浏览器。`doctor`、`routing`、`jobs`、`runs`、`run status`、`run verify`、`api path`、`config path` 都是只读;`install`/`uninstall` 只修改包所拥有的 skill 链接;`run reconcile`、`run takeover`、`run reconcile-runtime`、`run cancel`/`run stop`、`job cancel` 会追加审计证据或修改持久 run/job 状态。执行写入状态的命令前,先用 `cueline help` 核对完整参数。
134
160
 
135
161
  ```console
136
162
  $ cueline install
137
163
  CueLine skill installed: /Users/you/.codex/skills/cueline
138
164
 
139
165
  $ cueline doctor
140
- CueLine 0.1.5
166
+ CueLine 0.1.7
141
167
  status ok
142
168
  node 22.14.0 ok
143
169
  config /usr/local/lib/node_modules/cueline/config/routing.default.json valid
@@ -146,18 +172,30 @@ caller_ready yes
146
172
  caller_lanes 1
147
173
  process_available_lanes 1
148
174
 
175
+ $ cueline doctor --json
176
+ {"version":"0.1.7","status":"ok","node":{"version":"22.14.0","ok":true,"requirement":">=22"},...}
177
+
149
178
  $ cueline api path
150
179
  /usr/local/lib/node_modules/cueline/dist/src/api.js
151
180
 
152
181
  $ cueline routing
153
182
  default codex-default available
154
183
 
184
+ $ cueline routing --json
185
+ {"version":"0.1.7","availableLanes":1,"lanes":[{"name":"default","status":"available","selectedRunnerId":"codex-default"}],...}
186
+
155
187
  $ cueline jobs
156
188
  No jobs.
157
189
 
190
+ $ cueline runs
191
+ No runs.
192
+
158
193
  $ cueline run status run_... --json
159
194
  {"status":"running","executor":"caller","phase":"caller_jobs_pending","runtime":{"ownership":"missing"},...}
160
195
 
196
+ $ cueline run verify run_... --json
197
+ {"runId":"run_...","outcome":"verified","marker":"valid",...}
198
+
161
199
  $ cueline run takeover stale_run_... --json
162
200
  {"runId":"stale_run_...","outcome":"taken_over","next":"continue",...}
163
201
 
@@ -179,7 +217,7 @@ CueLine skill removed: /Users/you/.codex/skills/cueline
179
217
 
180
218
  `CUELINE_CONFIG` 用于指定路由配置文件;`CUELINE_HOME` 用于迁移本地状态(默认 `~/.cueline`)。
181
219
 
182
- Caller 模式不会启动路由进程。只有显式选择 `process` executor 时,内置 `default` 通道才以 `codex-default` 运行 `codex exec`;独立 `advise` 默认全局/每 lane 并发上限均为 2,包含 `work` 的批次保持串行。
220
+ Caller 模式不会启动路由进程。只有同时选择 `executor: "process"` `allowProcessExecution: true` 时,内置 `default` 通道才以 `codex-default` 运行隔离的 `codex exec --ignore-user-config`;独立 `advise` 默认全局/每 lane 并发上限均为 2,包含 `work` 的批次保持串行。
183
221
 
184
222
  状态位于 `CUELINE_HOME` 之下:
185
223
 
@@ -212,7 +250,7 @@ npm pack --dry-run
212
250
 
213
251
  ## 0.1 的限制
214
252
 
215
- 仅支持文本控制命令。一次运行只对应一个会话。支持 ChatGPT 自动将长文本转为附件,但不支持主动文件上传、图片、Deep Research、Projects 或 Apps。Caller 模式只允许 `advise`;`work` 必须显式选择 process executor。模糊发送和已启动工作都不会被自动重试。
253
+ 仅支持文本控制命令。一次运行只对应一个会话。支持 ChatGPT 自动将长文本转为附件,但不支持主动文件上传、图片、Deep Research、Projects 或 Apps。Caller `work` 必须显式 claim/start;process 执行必须双重授权。模糊发送和已启动工作都不会被自动重试。
216
254
 
217
255
  完整矩阵见 [compatibility](docs/compatibility.md)。
218
256