cueline 0.1.6 → 0.2.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.
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/CHANGELOG.md +50 -0
- package/README.ja.md +77 -30
- package/README.ko.md +77 -30
- package/README.md +71 -29
- package/README.zh-CN.md +77 -30
- package/README.zh-TW.md +74 -29
- package/config/routing.schema.json +3 -0
- package/dist/src/api-caller-work.js +58 -14
- package/dist/src/api-caller-work.js.map +1 -1
- package/dist/src/api-contracts.d.ts +56 -0
- package/dist/src/api-controller-handoff.d.ts +5 -1
- package/dist/src/api-controller-handoff.js +178 -38
- package/dist/src/api-controller-handoff.js.map +1 -1
- package/dist/src/api-run-verification.d.ts +3 -0
- package/dist/src/api-run-verification.js +174 -0
- package/dist/src/api-run-verification.js.map +1 -0
- package/dist/src/api-runtime-lifecycle.d.ts +6 -1
- package/dist/src/api-runtime-lifecycle.js +97 -8
- package/dist/src/api-runtime-lifecycle.js.map +1 -1
- package/dist/src/api.d.ts +26 -4
- package/dist/src/api.js +111 -40
- package/dist/src/api.js.map +1 -1
- package/dist/src/browser/browser-adapter.d.ts +41 -0
- package/dist/src/browser/codex-iab/bootstrap.d.ts +21 -0
- package/dist/src/browser/codex-iab/bootstrap.js +174 -9
- package/dist/src/browser/codex-iab/bootstrap.js.map +1 -1
- package/dist/src/browser/codex-iab/chatgpt-client.d.ts +3 -0
- package/dist/src/browser/codex-iab/chatgpt-client.js +216 -70
- package/dist/src/browser/codex-iab/chatgpt-client.js.map +1 -1
- package/dist/src/browser/codex-iab/probe.d.ts +36 -0
- package/dist/src/browser/codex-iab/probe.js +217 -0
- package/dist/src/browser/codex-iab/probe.js.map +1 -0
- package/dist/src/browser/codex-iab/recovery-evidence.d.ts +1 -1
- package/dist/src/browser/codex-iab/recovery-evidence.js +7 -10
- package/dist/src/browser/codex-iab/recovery-evidence.js.map +1 -1
- package/dist/src/browser/codex-iab/selectors.d.ts +1 -0
- package/dist/src/browser/codex-iab/selectors.js +1 -0
- package/dist/src/browser/codex-iab/selectors.js.map +1 -1
- package/dist/src/browser/codex-iab/send-button.d.ts +5 -0
- package/dist/src/browser/codex-iab/send-button.js +62 -0
- package/dist/src/browser/codex-iab/send-button.js.map +1 -0
- package/dist/src/browser/codex-iab/submission-url.js +6 -15
- package/dist/src/browser/codex-iab/submission-url.js.map +1 -1
- package/dist/src/browser/codex-iab/tab-discovery.js +45 -12
- package/dist/src/browser/codex-iab/tab-discovery.js.map +1 -1
- package/dist/src/browser/codex-iab/timing-options.d.ts +1 -0
- package/dist/src/browser/codex-iab/timing-options.js +5 -0
- package/dist/src/browser/codex-iab/timing-options.js.map +1 -0
- package/dist/src/cli/health-commands.d.ts +2 -0
- package/dist/src/cli/health-commands.js +265 -0
- package/dist/src/cli/health-commands.js.map +1 -0
- package/dist/src/cli/io.d.ts +4 -0
- package/dist/src/cli/io.js +2 -0
- package/dist/src/cli/io.js.map +1 -0
- package/dist/src/cli/main.d.ts +1 -5
- package/dist/src/cli/main.js +187 -84
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/cli/observation-commands.d.ts +2 -0
- package/dist/src/cli/observation-commands.js +350 -0
- package/dist/src/cli/observation-commands.js.map +1 -0
- package/dist/src/cli/run-status-view.d.ts +87 -0
- package/dist/src/cli/run-status-view.js +121 -0
- package/dist/src/cli/run-status-view.js.map +1 -0
- package/dist/src/core/controller-command-execution.d.ts +2 -2
- package/dist/src/core/controller-command-execution.js +82 -16
- package/dist/src/core/controller-command-execution.js.map +1 -1
- package/dist/src/core/controller-conversation-archive.d.ts +11 -0
- package/dist/src/core/controller-conversation-archive.js +109 -0
- package/dist/src/core/controller-conversation-archive.js.map +1 -0
- package/dist/src/core/controller-loop.d.ts +7 -1
- package/dist/src/core/controller-loop.js +136 -23
- package/dist/src/core/controller-loop.js.map +1 -1
- package/dist/src/core/controller-turn.d.ts +21 -3
- package/dist/src/core/controller-turn.js +182 -41
- package/dist/src/core/controller-turn.js.map +1 -1
- package/dist/src/core/controller-types.d.ts +2 -0
- package/dist/src/core/conversation-url.d.ts +3 -0
- package/dist/src/core/conversation-url.js +34 -0
- package/dist/src/core/conversation-url.js.map +1 -0
- package/dist/src/core/run-status.d.ts +17 -2
- package/dist/src/core/run-status.js +64 -25
- package/dist/src/core/run-status.js.map +1 -1
- package/dist/src/core/state-machine.d.ts +36 -1
- package/dist/src/core/state-machine.js +242 -13
- package/dist/src/core/state-machine.js.map +1 -1
- package/dist/src/core/timing.d.ts +9 -0
- package/dist/src/core/timing.js +22 -0
- package/dist/src/core/timing.js.map +1 -0
- package/dist/src/diagnostics/run-doctor.d.ts +22 -0
- package/dist/src/diagnostics/run-doctor.js +197 -0
- package/dist/src/diagnostics/run-doctor.js.map +1 -0
- package/dist/src/jobs/status.d.ts +5 -2
- package/dist/src/jobs/status.js +172 -12
- package/dist/src/jobs/status.js.map +1 -1
- package/dist/src/jobs/supervisor.js +57 -8
- package/dist/src/jobs/supervisor.js.map +1 -1
- package/dist/src/observation/run-diff.d.ts +39 -0
- package/dist/src/observation/run-diff.js +67 -0
- package/dist/src/observation/run-diff.js.map +1 -0
- package/dist/src/observation/run-graph.d.ts +17 -0
- package/dist/src/observation/run-graph.js +77 -0
- package/dist/src/observation/run-graph.js.map +1 -0
- package/dist/src/observation/run-handoff.d.ts +86 -0
- package/dist/src/observation/run-handoff.js +309 -0
- package/dist/src/observation/run-handoff.js.map +1 -0
- package/dist/src/observation/run-status-at.d.ts +41 -0
- package/dist/src/observation/run-status-at.js +65 -0
- package/dist/src/observation/run-status-at.js.map +1 -0
- package/dist/src/observation/run-timeline.d.ts +32 -0
- package/dist/src/observation/run-timeline.js +279 -0
- package/dist/src/observation/run-timeline.js.map +1 -0
- package/dist/src/observation/run-watch.d.ts +15 -0
- package/dist/src/observation/run-watch.js +82 -0
- package/dist/src/observation/run-watch.js.map +1 -0
- package/dist/src/protocol/limits.d.ts +3 -0
- package/dist/src/protocol/limits.js +4 -0
- package/dist/src/protocol/limits.js.map +1 -0
- package/dist/src/protocol/lint-command.d.ts +24 -0
- package/dist/src/protocol/lint-command.js +210 -0
- package/dist/src/protocol/lint-command.js.map +1 -0
- package/dist/src/protocol/parse-command.js +4 -0
- package/dist/src/protocol/parse-command.js.map +1 -1
- package/dist/src/protocol/types.d.ts +12 -0
- package/dist/src/protocol/validate-command.js +76 -3
- package/dist/src/protocol/validate-command.js.map +1 -1
- package/dist/src/router/config-loader.js +23 -2
- package/dist/src/router/config-loader.js.map +1 -1
- package/dist/src/router/explain.d.ts +28 -0
- package/dist/src/router/explain.js +86 -0
- package/dist/src/router/explain.js.map +1 -0
- package/dist/src/router/resolver.d.ts +2 -1
- package/dist/src/router/resolver.js +11 -6
- package/dist/src/router/resolver.js.map +1 -1
- package/dist/src/runners/process-runner.js +55 -12
- package/dist/src/runners/process-runner.js.map +1 -1
- package/dist/src/runners/runner-adapter.d.ts +2 -0
- package/dist/src/runners/runner-adapter.js.map +1 -1
- package/dist/src/state/atomic-write.d.ts +6 -0
- package/dist/src/state/atomic-write.js +43 -2
- package/dist/src/state/atomic-write.js.map +1 -1
- package/dist/src/state/cancellation.js +38 -4
- package/dist/src/state/cancellation.js.map +1 -1
- package/dist/src/state/event-log.js +5 -4
- package/dist/src/state/event-log.js.map +1 -1
- package/dist/src/state/private-directory.d.ts +5 -0
- package/dist/src/state/private-directory.js +37 -0
- package/dist/src/state/private-directory.js.map +1 -0
- package/dist/src/state/runtime-lease.js +19 -39
- package/dist/src/state/runtime-lease.js.map +1 -1
- package/dist/src/state/runtime-record-validation.d.ts +6 -0
- package/dist/src/state/runtime-record-validation.js +44 -0
- package/dist/src/state/runtime-record-validation.js.map +1 -0
- package/dist/src/state/runtime-retirement.js +58 -18
- package/dist/src/state/runtime-retirement.js.map +1 -1
- package/dist/src/state/runtime-takeover-intent.js +2 -2
- package/dist/src/state/runtime-takeover-intent.js.map +1 -1
- package/dist/src/state/store.d.ts +1 -0
- package/dist/src/state/store.js +12 -6
- package/dist/src/state/store.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/docs/architecture.md +4 -4
- package/docs/assets/README.md +3 -1
- package/docs/assets/cueline-architecture-en.svg +63 -0
- package/docs/assets/cueline-architecture-ja.svg +63 -0
- package/docs/assets/cueline-architecture-ko.svg +63 -0
- package/docs/assets/cueline-architecture-zh-CN.svg +63 -0
- package/docs/assets/cueline-architecture-zh-TW.svg +63 -0
- package/docs/assets/cueline-states-en.svg +50 -0
- package/docs/assets/cueline-states-ja.svg +48 -0
- package/docs/assets/cueline-states-ko.svg +48 -0
- package/docs/assets/cueline-states-zh-CN.svg +48 -0
- package/docs/assets/cueline-states-zh-TW.svg +48 -0
- package/docs/compatibility.md +1 -1
- package/docs/controller-protocol.md +44 -7
- package/docs/experiments/protocol-lint.md +40 -0
- package/docs/experiments/run-doctor.md +39 -0
- package/docs/experiments/run-handoff.md +39 -0
- package/docs/experiments/run-timeline.md +35 -0
- package/docs/experiments/run-watch.md +31 -0
- package/docs/multi-model-routing.md +256 -0
- package/docs/runner-contract.md +4 -3
- package/docs/state-and-recovery.md +45 -5
- package/package.json +1 -1
- package/schemas/controller-command.schema.json +89 -4
- package/skills/cueline/SKILL.md +13 -7
package/docs/runner-contract.md
CHANGED
|
@@ -10,8 +10,8 @@ The ChatGPT web controller only emits a text command. It does not inspect the re
|
|
|
10
10
|
|
|
11
11
|
Caller work requires an absolute workdir and follows one fenced lifecycle:
|
|
12
12
|
|
|
13
|
-
1. `claimCueLineCallerJob` atomically binds `runId + jobId + taskHash + workdir + callerId + fencingToken`. The same caller may recover the same active proof after losing an API response; a different caller is rejected.
|
|
14
|
-
2. Before start, the caller may heartbeat or release the claim. An
|
|
13
|
+
1. `claimCueLineCallerJob` atomically binds `runId + jobId + taskHash + workdir + canonical directory identity + callerId + fencingToken`. The returned `resolvedWorkdir` is the exact canonical path the caller must use. The same caller may recover the same active proof after losing an API response; a different caller is rejected.
|
|
14
|
+
2. Before start, the caller may heartbeat or release the claim. `startCueLineCallerJob` rechecks the canonical path, device, and inode before authorizing mutation, so a replaced directory or retargeted symlink is rejected. An unstarted legacy claim without directory identity is append-only released and reissued to the same caller with a higher fencing token; an expired unstarted claim follows the same fenced reclaim pattern.
|
|
15
15
|
3. `startCueLineCallerJob` must succeed immediately before the first mutation. The exact owner heartbeats long work with `heartbeatCueLineCallerJob`.
|
|
16
16
|
4. `submitCueLineCallerJobResult` requires the exact active proof. Wrong or old proof is rejected; a terminal job cannot be executed or overwritten again.
|
|
17
17
|
5. Once started, release is forbidden. A crash or expiry becomes `ambiguous`, and CueLine never automatically retries that work.
|
|
@@ -54,7 +54,8 @@ interface RunnerSpec {
|
|
|
54
54
|
- `CUELINE_DEPTH=1` is injected into the child.
|
|
55
55
|
- A pre-existing `CUELINE_DEPTH` in the process or job environment rejects nested routing.
|
|
56
56
|
- Standard input is closed unless the route explicitly selects stdin task input; stdout and stderr are captured as UTF-8 text.
|
|
57
|
-
-
|
|
57
|
+
- Each stream keeps up to 512,000 characters. Output within that bound is persisted in full. Larger output preserves its head and tail around an explicit truncation marker, with exact `stdoutTruncatedChars` or `stderrTruncatedChars` metadata, so a noisy worker cannot grow CueLine memory and status JSON without limit.
|
|
58
|
+
- Stdout and stderr are persisted separately. Successful non-empty stdout is the preferred controller evidence; combined output remains diagnostic status only.
|
|
58
59
|
- Exit code 0 is `succeeded`; a non-zero exit or spawn error is `failed`.
|
|
59
60
|
- At timeout CueLine sends `SIGTERM`, then schedules `SIGKILL` after 250 ms if needed; the result is `timed_out`.
|
|
60
61
|
- Cancellation uses the same owned-process termination path. `advise` becomes `cancelled`; started `work` becomes `ambiguous`.
|
|
@@ -23,6 +23,14 @@ ${CUELINE_HOME:-$HOME/.cueline}/
|
|
|
23
23
|
|
|
24
24
|
`CUELINE_HOME` accepts an absolute or relative path. `~` and `~/...` are expanded against `HOME`. Run and job IDs are validated before they are used in filesystem paths.
|
|
25
25
|
|
|
26
|
+
On POSIX hosts, CueLine-owned run, event-segment, runtime, cancellation, and
|
|
27
|
+
job-status directories are created or tightened to mode `0700`; durable JSON
|
|
28
|
+
evidence is written with mode `0600`. A pre-existing permissive CueLine
|
|
29
|
+
directory is tightened on its next state write. State-directory symlinks are
|
|
30
|
+
rejected rather than followed, so permission repair cannot be redirected to an
|
|
31
|
+
unrelated path. Windows does not expose equivalent POSIX mode semantics and is
|
|
32
|
+
unchanged.
|
|
33
|
+
|
|
26
34
|
## Event log
|
|
27
35
|
|
|
28
36
|
The logical event log is append-only and authoritative. A legacy or atomically created first event may live in `events.jsonl`; subsequent events use one immutable file per sequence under `events.jsonl.segments/`. Each event contains a monotonically increasing sequence number, timestamp, type, payload, and an optional runtime owner ID. The writer fully writes and syncs a temporary segment, hard-links it to the sequence name with create-if-absent semantics, then syncs the containing directory before reporting success. A `legacy-fence.json` freezes the accepted byte prefix of an older JSONL writer, so a still-loaded pre-segment process may append a diagnostic suffix without creating duplicate logical sequence numbers. Concurrent or recovered writers that lose a sequence race reread and retry; no global event lock or partial segment becomes authoritative.
|
|
@@ -40,6 +48,8 @@ The controller turn is recorded before sending it through the browser. The built
|
|
|
40
48
|
|
|
41
49
|
The absence of `controller_response_received` proves only that the local runtime did not record a response. It does **not** prove that ChatGPT did not answer. `run_failed` therefore retains the safe error message, stage, exact request ID, submission state, and known conversation URL. CueLine never treats a missing response event as permission to resend an ambiguous prompt.
|
|
42
50
|
|
|
51
|
+
Submission checkpoints also bind the run, round, request ID, prompt hash, exact conversation URL, Pro model evidence, baseline user and assistant message counts, composer state, click-attempt state, and bounded DOM evidence. If the click throws, CueLine records the exception class and message plus any readable post-click DOM evidence before classification.
|
|
52
|
+
|
|
43
53
|
## Snapshot
|
|
44
54
|
|
|
45
55
|
`snapshot.json` is a disposable materialized view of the event stream. CueLine writes a temporary file in the same directory and renames it over the destination. A snapshot records its state protocol, run ID, and last applied physical sequence. Loads replay the authoritative event stream from event 1 instead of trusting a snapshot that a retired owner could have replaced.
|
|
@@ -48,7 +58,7 @@ The snapshot is therefore disposable. Do not edit the event log by hand; invalid
|
|
|
48
58
|
|
|
49
59
|
## Job status
|
|
50
60
|
|
|
51
|
-
The supervisor atomically replaces one JSON status file per job. Status records include run ID, job key, lane, mode, resolved runner, PID, model/provider when safely observed, phase, and last progress time when available. The task remains in the authoritative run's `job_registered` event; `cueline jobs` joins that event metadata with the status file so the task is still visible. Caller jobs are visible as `pending` before the current Codex submits a terminal result. PID is diagnostic evidence only; CueLine never treats a PID alone as authority to kill a process. Foreground process work returns its terminal status directly. Background process work first persists `running`; later `wait` reads the same in-process completion or the last persisted status.
|
|
61
|
+
The supervisor atomically replaces one JSON status file per job. The first terminal result also creates an immutable `<job-id>.terminal` anchor; readers prefer that anchor, and a later `pending`/`running` write is rejected before it can authorize a duplicate spawn. Existing terminal-only JSON files are anchored lazily on the next write, so upgrades preserve legacy evidence. Status records include run ID, job key, lane, mode, resolved runner, PID, model/provider when safely observed, phase, and last progress time when available. The task remains in the authoritative run's `job_registered` event; `cueline jobs` joins that event metadata with the status file so the task is still visible. Caller jobs are visible as `pending` before the current Codex submits a terminal result. PID is diagnostic evidence only; CueLine never treats a PID alone as authority to kill a process. Foreground process work returns its terminal status directly. Background process work first persists `running`; later `wait` reads the same in-process completion or the last persisted status.
|
|
52
62
|
|
|
53
63
|
The run event log still records the controller-visible job transitions. A status file is execution evidence, not a substitute for the run history. `cueline jobs --json` includes run ID, job key, lane, mode, task, and PID when known. For process runs it adds a derived observed status: `running` requires active runtime ownership, `orphaned` means persisted process work says active but no owner is proven, `unverified` covers legacy records without a run ID, and `conflict` means a status file disagrees with authoritative run events. A conflict reports the authoritative `status`, exposes the file's value as `persistedStatus`, and omits the untrusted late result. Pending caller jobs remain pending during their intentional ownerless handoff.
|
|
54
64
|
|
|
@@ -62,17 +72,47 @@ The run event log still records the controller-visible job transitions. A status
|
|
|
62
72
|
- `phase: jobs_running` plus `runtime.ownership: active` means local jobs are executing under the original loop.
|
|
63
73
|
- `executor: caller`, `phase: caller_jobs_pending`, `runtime.ownership: missing`, and `safeNextAction: execute_caller_jobs` is a healthy durable pause. The current Codex should execute the listed `advise` tasks and submit their results; it must not claim that ChatGPT used local tools.
|
|
64
74
|
- Caller handoff has no execution claim. Coordinate one session before doing the local advice; if two sessions execute it, the first terminal evidence submitted wins and the later submission returns `already_terminal`.
|
|
65
|
-
- `caller_work_pending` / `claim_caller_work` means no local mutation has begun. `caller_work_claimed` / `start_caller_work` means the immutable claim exists but still has `started=false`. `caller_work_running` / `continue_caller_work` authorizes only the exact claim owner to continue and heartbeat the started work.
|
|
75
|
+
- `caller_work_pending` / `claim_caller_work` means no local mutation has begun. `caller_work_claimed` / `start_caller_work` means the immutable claim exists but still has `started=false`. `caller_work_running` / `continue_caller_work` authorizes only the exact claim owner to continue and heartbeat the started work. CLI run status is metadata-only: task bodies, caller identities, task hashes, workdirs, runtime owner IDs, claim IDs, and fencing tokens are omitted. The formal claim API returns the exact task and workdir after an atomic claim.
|
|
66
76
|
- One stale caller observer is automatically recoverable only when it owns exactly one normally submitted, non-manual turn with an exact matching ChatGPT URL, no active jobs, no pending command, and no cancellation. Status remains `controller_response_pending` / `observe`; continuation atomically fences the stale owner and performs read-only observation without resend. Every other stale state requires explicit takeover/reconciliation.
|
|
67
77
|
- `runtime_ownership_unknown` means persisted `running` is not proof of a live process. Except for the strict side-effect-free caller observer described above, `runtime_stale` requires explicit `cueline run takeover <run-id>` confirmation before the exact stale heartbeat can be retired. Active-looking process jobs are reported as `orphaned`.
|
|
68
78
|
- `runtime_active` means a live owner is still settling a failed state; another session must observe rather than continue.
|
|
79
|
+
- `controller_archive_pending` / `settle_controller_archive` means the controller run is already durably `complete`, but an explicitly enabled post-completion archive has not reached terminal proof. Only missing/released ownership may settle it. `archived`, `ambiguous`, and `failed` are terminal archive outcomes; never retry an `ambiguous` attempt.
|
|
69
80
|
- `continueAllowed: false` forbids `continueCueLineRun`. A caller-work state may separately authorize only the exact claim/start/continue API action named by `safeNextAction`; it never authorizes a browser resend.
|
|
70
81
|
|
|
82
|
+
## Operator-confirmed not-sent recovery
|
|
83
|
+
|
|
84
|
+
`possibly_sent` remains non-retryable by default. If the operator directly inspects the exact ChatGPT conversation and confirms that the original user message is absent, a separate append-only recovery path can authorize one retry:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
cueline run reconcile RUN_ID \
|
|
88
|
+
--request-id REQUEST_ID \
|
|
89
|
+
--not-sent-confirmed \
|
|
90
|
+
--conversation-url https://chatgpt.com/c/EXACT_CONVERSATION
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The command does not drive the browser or send a message. It requires exactly one pending controller turn and validates the exact run, conversation, round, request ID, persisted prompt hash, and Pro model checkpoint. It also refuses recovery if a matching response or a command for the same or a newer controller round was accepted. Success appends `controller_turn_not_sent_confirmed` and `controller_turn_abandoned` with reason `operator_confirmed_not_sent`; old events remain unchanged.
|
|
94
|
+
|
|
95
|
+
The next continuation creates exactly one new request ID for the same round. The regenerated prompt must match the abandoned checkpoint hash after substituting only the new request ID for the abandoned request ID. Any other content change records `CONTROLLER_NOT_SENT_PROMPT_MISMATCH` and freezes the run for manual review. A crash after the retry request is written resumes the same deterministic retry identity. Repeating the confirmation command is idempotent and never appends another confirmation, abandonment, or send.
|
|
96
|
+
|
|
97
|
+
Status exposes `operatorConfirmation`, `abandonedRequestId`, `retryRequestId`, `promptHash`, and `resendBlockedReason`. Before the retry, `safeNextAction` is `retry`; after submission it is the normal `observe`. If later DOM or response evidence shows that the abandoned request actually appeared, CueLine records `CONTROLLER_NOT_SENT_CONFIRMATION_CONFLICT` or `CONTROLLER_NOT_SENT_RESPONSE_CONFLICT`, changes `safeNextAction` to `manual_review`, and refuses automatic resend or command acceptance.
|
|
98
|
+
|
|
99
|
+
Existing manual-send path is distinct:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
cueline run reconcile RUN_ID \
|
|
103
|
+
--request-id REQUEST_ID \
|
|
104
|
+
--manual-send-confirmed \
|
|
105
|
+
--conversation-url https://chatgpt.com/c/EXACT_CONVERSATION
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`--manual-send-confirmed` says the original request was sent and must be observed under the same identity. `--not-sent-confirmed` says the original request definitely was not sent and must be abandoned. The flags are mutually exclusive.
|
|
109
|
+
|
|
71
110
|
## Continue behavior
|
|
72
111
|
|
|
73
112
|
Always run `cueline run status <run-id> --json` before continuation. `continueCueLineRun` loads the exact `runId`, replays state as needed, and resumes the same persisted run. The public runtime also reuses the stored ChatGPT conversation URL unless an explicit compatible adapter is supplied.
|
|
74
113
|
|
|
75
114
|
- `complete`, `blocked`, and `cancelled` runs are returned as-is; they are not dispatched again.
|
|
115
|
+
- When `archiveControllerConversationOnComplete` was fixed to `true` at creation, `complete` first becomes durable and then the exact bound ChatGPT conversation may be archived while Pro is idle. The built-in browser invokes a durable write-ahead hook immediately before one Archive click. A proven failure before that hook stays pending and may be retried; after it, any interruption or missing URL-change proof becomes `ambiguous` and cannot be retried. `blocked` and `cancelled` never archive.
|
|
76
116
|
- an active owner is rejected with `RUN_ALREADY_ACTIVE`; a stale lease requires dead-owner inspection; missing ownership is healthy only for a pristine or caller-mode run
|
|
77
117
|
- a non-terminal or locally `failed` run with no pending controller turn can be marked resumed and driven for additional rounds
|
|
78
118
|
- `maxRounds` is a durable total-run contract, not a per-continuation allowance; continuation reuses the created value and cannot widen or shrink it
|
|
@@ -97,13 +137,13 @@ Caller advice remains coordination-only; caller work requires its durable claim
|
|
|
97
137
|
|
|
98
138
|
`cueline run cancel <run-id>` and its `run stop` alias write a durable request. `cueline job cancel <run-id> <job-id>` targets one job. An active owner observes the request, sends `SIGTERM` to its owned child, escalates to `SIGKILL` after the grace interval, and persists the terminal transition. Cancelled `advise` is `cancelled`; started `work` is `ambiguous` because partial side effects cannot be disproved.
|
|
99
139
|
|
|
100
|
-
The CLI does not drive the browser. `doctor`, `routing`, `jobs`, `run status`, `api path`, and `config path` are read-only. `install`/`uninstall` change only the package-owned skill link. `run reconcile`, `run takeover`, `run reconcile-runtime`, `run cancel`/`run stop`, and `job cancel` append audit evidence or mutate durable local state; their complete positional syntax and options are listed by `cueline help`.
|
|
140
|
+
The CLI does not drive the browser. `doctor`, `routing`, `jobs`, `runs`, `run status`, `run verify`, `api path`, and `config path` are read-only. `runs` returns sanitized summaries only and reports corrupt run directories without hiding readable runs. `run verify` checks the creation marker, event sequence and authority replay, optional snapshot, runtime lease, and job status consistency without returning durable content. `install`/`uninstall` change only the package-owned skill link. `run reconcile`, `run takeover`, `run reconcile-runtime`, `run cancel`/`run stop`, and `job cancel` append audit evidence or mutate durable local state; their complete positional syntax and options are listed by `cueline help`.
|
|
101
141
|
|
|
102
142
|
When a process run has no verifiable owner, runtime reconciliation checks both the recorded process and its POSIX process group. Surviving processes block settlement. Only dead `advise` work can become failed/cancelled; `work` remains `ambiguous` when partial side effects cannot be disproved. `cueline run reconcile-runtime <run-id>` exposes this transition without treating a stale PID as kill authority.
|
|
103
143
|
|
|
104
144
|
`cueline run takeover <run-id>` is narrower: it atomically replaces only the exact stale owner/heartbeat observed by the command and writes `runtime_stale_owner_takeover_requested` followed by `runtime_stale_owner_takeover_confirmed` while the replacement lease is held. A fresh active heartbeat is refused. Caller runs return `next: continue`. Process runs always return `next: reconcile_runtime`, even when no job is currently recorded, so the advertised next step cannot bypass process-owner loss reconciliation.
|
|
105
145
|
|
|
106
|
-
`runTimeoutMs` is an optional owned-advancement deadline. In explicit process mode it limits that controller-loop invocation and aborts owned jobs before returning `RUN_TIMEOUT`. Caller runs intentionally release ownership at controller/caller pauses, so the value limits each `runCueLine` or `continueCueLineRun` call in which it is supplied; ownerless Pro thinking and local handoff time between calls are not counted. `defaultTimeoutMs` and job `timeout_ms` remain per-job limits. A caller-side or tool-side wait timeout is not a cancellation signal; after one fires, inspect `run status`, then explicitly cancel if required. API callers may pass `signal` for direct cancellation propagation.
|
|
146
|
+
`runTimeoutMs` is an optional owned-advancement deadline. In explicit process mode it limits that controller-loop invocation and aborts owned jobs before returning `RUN_TIMEOUT`. Caller runs intentionally release ownership at controller/caller pauses, so the value limits each `runCueLine` or `continueCueLineRun` call in which it is supplied; ownerless Pro thinking and local handoff time between calls are not counted. `defaultTimeoutMs` and job `timeout_ms` remain per-job limits. Runtime, process, cancellation-poll, and heartbeat timer values must be integer milliseconds from 1 through 2,147,483,647; invalid or overflowing values are rejected before browser, process, or lease side effects because Node otherwise reduces an overflowing timer to a near-immediate delay. A caller-side or tool-side wait timeout is not a cancellation signal; after one fires, inspect `run status`, then explicitly cancel if required. API callers may pass `signal` for direct cancellation propagation.
|
|
107
147
|
|
|
108
148
|
For one unambiguous pending turn, supply the exact conversation URL when it was not captured before the failure:
|
|
109
149
|
|
|
@@ -136,7 +176,7 @@ cueline run reconcile RUN_ID \
|
|
|
136
176
|
--conversation-url https://chatgpt.com/c/EXACT_CONVERSATION
|
|
137
177
|
```
|
|
138
178
|
|
|
139
|
-
The command accepts the first exact ChatGPT conversation URL created by that manual send, binds it in `controller_conversation_bound`, and writes `controller_turn_manual_submission_confirmed` under the same lease. Then continue with that request ID. CueLine accepts the response only if its Pro evidence and full envelope identity match; a mismatch is rejected without resend or dispatch.
|
|
179
|
+
The command accepts the first exact ChatGPT conversation URL created by that manual send, binds it in `controller_conversation_bound`, and writes `controller_turn_manual_submission_confirmed` under the same lease. Then continue with that request ID. Before the public continuation API records the same confirmation, it validates nested-routing safety, runtime limits, executor authorization, conversation identity, routing configuration, and Browser construction. A deterministic preflight failure therefore leaves the pending turn unchanged instead of returning an error after mutating it. CueLine accepts the response only if its Pro evidence and full envelope identity match; a mismatch is rejected without resend or dispatch.
|
|
140
180
|
|
|
141
181
|
Continuation cannot reconstruct an expired ChatGPT login, a deleted conversation, an unavailable registered executable, or an in-memory child process that disappeared with the host process. In those cases CueLine reports the concrete failure; it does not fabricate completion.
|
|
142
182
|
|
package/package.json
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"jobs": {
|
|
14
14
|
"type": "array",
|
|
15
15
|
"minItems": 1,
|
|
16
|
+
"maxItems": 64,
|
|
16
17
|
"items": {
|
|
17
18
|
"type": "object",
|
|
18
19
|
"additionalProperties": false,
|
|
@@ -30,7 +31,22 @@
|
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
},
|
|
33
|
-
"job_ids": {
|
|
34
|
+
"job_ids": {
|
|
35
|
+
"type": "array",
|
|
36
|
+
"minItems": 1,
|
|
37
|
+
"maxItems": 256,
|
|
38
|
+
"uniqueItems": true,
|
|
39
|
+
"items": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]*$" }
|
|
40
|
+
},
|
|
41
|
+
"evidence_offset": {
|
|
42
|
+
"type": "integer",
|
|
43
|
+
"minimum": 0,
|
|
44
|
+
"maximum": 1000000000
|
|
45
|
+
},
|
|
46
|
+
"evidence_hash": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"pattern": "^[0-9a-f]{64}$"
|
|
49
|
+
},
|
|
34
50
|
"wait_ms": { "type": "integer", "minimum": 1, "maximum": 300000 },
|
|
35
51
|
"final_delivery_text": { "type": "string", "minLength": 1 },
|
|
36
52
|
"reason": { "type": "string", "minLength": 1 }
|
|
@@ -38,15 +54,84 @@
|
|
|
38
54
|
"allOf": [
|
|
39
55
|
{
|
|
40
56
|
"if": { "properties": { "action": { "const": "dispatch" } } },
|
|
41
|
-
"then": {
|
|
57
|
+
"then": {
|
|
58
|
+
"required": ["jobs"],
|
|
59
|
+
"not": {
|
|
60
|
+
"anyOf": [
|
|
61
|
+
{ "required": ["job_ids"] },
|
|
62
|
+
{ "required": ["wait_ms"] },
|
|
63
|
+
{ "required": ["final_delivery_text"] },
|
|
64
|
+
{ "required": ["reason"] }
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"if": { "properties": { "action": { "const": "wait" } } },
|
|
71
|
+
"then": {
|
|
72
|
+
"not": {
|
|
73
|
+
"anyOf": [
|
|
74
|
+
{ "required": ["jobs"] },
|
|
75
|
+
{ "required": ["final_delivery_text"] },
|
|
76
|
+
{ "required": ["reason"] }
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"if": { "properties": { "action": { "const": "inspect" } } },
|
|
83
|
+
"then": {
|
|
84
|
+
"not": {
|
|
85
|
+
"anyOf": [
|
|
86
|
+
{ "required": ["jobs"] },
|
|
87
|
+
{ "required": ["wait_ms"] },
|
|
88
|
+
{ "required": ["final_delivery_text"] },
|
|
89
|
+
{ "required": ["reason"] }
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"if": {
|
|
96
|
+
"anyOf": [
|
|
97
|
+
{ "required": ["evidence_offset"] },
|
|
98
|
+
{ "required": ["evidence_hash"] }
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
"then": {
|
|
102
|
+
"properties": {
|
|
103
|
+
"action": { "const": "inspect" },
|
|
104
|
+
"job_ids": { "minItems": 1, "maxItems": 1 }
|
|
105
|
+
},
|
|
106
|
+
"required": ["job_ids", "evidence_offset", "evidence_hash"]
|
|
107
|
+
}
|
|
42
108
|
},
|
|
43
109
|
{
|
|
44
110
|
"if": { "properties": { "action": { "const": "complete" } } },
|
|
45
|
-
"then": {
|
|
111
|
+
"then": {
|
|
112
|
+
"required": ["final_delivery_text"],
|
|
113
|
+
"not": {
|
|
114
|
+
"anyOf": [
|
|
115
|
+
{ "required": ["jobs"] },
|
|
116
|
+
{ "required": ["job_ids"] },
|
|
117
|
+
{ "required": ["wait_ms"] },
|
|
118
|
+
{ "required": ["reason"] }
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
}
|
|
46
122
|
},
|
|
47
123
|
{
|
|
48
124
|
"if": { "properties": { "action": { "const": "blocked" } } },
|
|
49
|
-
"then": {
|
|
125
|
+
"then": {
|
|
126
|
+
"required": ["reason"],
|
|
127
|
+
"not": {
|
|
128
|
+
"anyOf": [
|
|
129
|
+
{ "required": ["jobs"] },
|
|
130
|
+
{ "required": ["job_ids"] },
|
|
131
|
+
{ "required": ["wait_ms"] }
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
}
|
|
50
135
|
}
|
|
51
136
|
],
|
|
52
137
|
"additionalProperties": false
|
package/skills/cueline/SKILL.md
CHANGED
|
@@ -10,8 +10,8 @@ Use CueLine to put the current ChatGPT web conversation in charge of planning an
|
|
|
10
10
|
## Preconditions
|
|
11
11
|
|
|
12
12
|
1. Confirm the current host, operator, and work directory before local work.
|
|
13
|
-
2. Run `cueline version`, then `cueline doctor`, and require the same expected package version, Node.js 22 or newer, and `
|
|
14
|
-
3. Use Codex's persistent Node REPL/runtime together with the built-in in-app Browser (IAB), not a separate plain `node` child, Chrome automation, or GPT Relay. Claim the logged-in `chatgpt.com` tab intended for this run.
|
|
13
|
+
2. Run `cueline version`, then `cueline doctor --json`, and require the same expected package version, Node.js 22 or newer, and `caller.ready: true` (plain `cueline doctor` remains available for humans). Run `cueline api path` and require the returned API module to exist. Do not reuse a module imported before a package update. `process.availableLanes` may be zero for caller mode; a usable process lane and `codex` CLI are required only when explicitly selecting the process executor. Use `cueline routing --json` when automation needs the selected runner ID; its output intentionally omits argv and environment values.
|
|
14
|
+
3. Use Codex's persistent Node REPL/runtime together with the built-in in-app Browser (IAB), not a separate plain `node` child, Chrome automation, or GPT Relay. Claim the logged-in `chatgpt.com` tab intended for this run. If CueLine reports `IAB_CHATGPT_TAB_AMBIGUOUS`, select the exact intended tab and retry; never choose an arbitrary matching tab or resend through another conversation.
|
|
15
15
|
4. CueLine requires the composer model selector to show `Pro` before every controller turn and requires the completed assistant message's `data-message-model-slug` to identify a Pro model. The account label (for example, a profile name ending in `Pro`) is subscription evidence only and never model evidence. Do not bypass `MODEL_SELECTOR_MISSING`, `PRO_MODEL_UNAVAILABLE`, `PRO_MODEL_SELECTION_FAILED`, or `PRO_MODEL_MISMATCH`.
|
|
16
16
|
5. Do not request, read, copy, or print cookies, access tokens, browser session material, or private environment values.
|
|
17
17
|
6. Keep v0.1 controller traffic text-only. ChatGPT may automatically convert a long filled prompt into an attachment; CueLine recognizes that state. Do not deliberately upload files, images, use Deep Research, Projects, or Apps. CueLine may switch the composer from another model to `Pro`; no other model switching is allowed.
|
|
@@ -52,6 +52,8 @@ const browser = createCodexIabAdapter({
|
|
|
52
52
|
let result = await startCueLineRun({
|
|
53
53
|
request: USER_REQUEST,
|
|
54
54
|
// executor defaults to "caller". Select "process" only explicitly.
|
|
55
|
+
// Opt in only when the user wants this exact controller conversation archived
|
|
56
|
+
// after a durable `complete`: archiveControllerConversationOnComplete: true,
|
|
55
57
|
// Optional here: runId, home, environment, now, maxRounds.
|
|
56
58
|
});
|
|
57
59
|
result = await continueCueLineRun({
|
|
@@ -64,6 +66,8 @@ result = await continueCueLineRun({
|
|
|
64
66
|
|
|
65
67
|
`maxRounds` is fixed as a durable total-run limit at creation. Continuations should omit it and reuse the stored value; if supplied, it must exactly match or CueLine rejects the continuation without sending another controller turn.
|
|
66
68
|
|
|
69
|
+
`archiveControllerConversationOnComplete` is also a durable creation-time policy. It defaults to `false`. When explicitly enabled, CueLine first persists `run_completed`, then archives only the exact bound ChatGPT conversation and only while Pro is no longer answering. It never archives a `blocked` or `cancelled` run. The browser must finish a durable write-ahead checkpoint immediately before the Archive click. A proven failure before that checkpoint remains `pending` and may be retried; a timeout or restart after it, a missing checkpoint, or missing completion proof becomes `ambiguous` and is never retried automatically. A later continuation must omit the option or supply the exact stored value.
|
|
70
|
+
|
|
67
71
|
Pass the user's request faithfully. Do not silently widen it, and do not turn an analysis-only request into `work`. Prefer `startCueLineRun` followed by `continueCueLineRun`, so the durable `runId` is known before any browser send. `runCueLine` remains a convenience API and post-creation failures include `details.run_id`. In caller mode, both APIs pause at `awaiting_controller` after one durable send and later at `awaiting_caller` or `awaiting_caller_work`; neither silently spawns a worker.
|
|
68
72
|
|
|
69
73
|
The web controller decides `dispatch`, `wait`, `inspect`, `complete`, or `blocked`. CueLine validates the exact pending identity and persists transitions. Under the default caller executor, a `dispatch` is only a durable work proposal. An `advise` job is handed to the current Codex without a side-effect claim. A `work` job remains unstarted until this exact caller claims and starts it through the public API. Never describe a Pro `dispatch` as local work having begun.
|
|
@@ -76,7 +80,7 @@ When the result is `awaiting_controller`, CueLine has submitted the exact reques
|
|
|
76
80
|
|
|
77
81
|
When the result is `awaiting_caller`, execute every pending `advise` task exactly as written using the current Codex's local tools. Advice has no execution claim: coordinate one session, because two sessions could perform the same inspection and only the first submitted terminal evidence wins.
|
|
78
82
|
|
|
79
|
-
When the result is `awaiting_caller_work`, do not modify anything yet. Read each exact task and absolute `workdir`, then acquire a durable claim with a stable caller identity. A repeated call by that same caller returns the same active claim, which safely recovers an API response lost to a restart. Call `startCueLineCallerJob` immediately before the first local mutation, heartbeat long-running work before expiry, and submit the terminal result with the exact claim proof. A claim may be released only before start. Once started, a lost or expired claim becomes `ambiguous` and must never be automatically retried. Any submitted non-success result after start is also normalized to `ambiguous`; CueLine writes a result-submission intent before the terminal status so a crash between those writes can be recovered without misclassifying completed work.
|
|
83
|
+
When the result is `awaiting_caller_work`, do not modify anything yet. Read each exact task and absolute `workdir`, then acquire a durable claim with a stable caller identity. Execute only in the returned `resolvedWorkdir`: CueLine pins that canonical directory identity and rechecks it at start, so a replaced directory or retargeted symlink cannot redirect authorized work. A repeated call by that same caller returns the same active claim, which safely recovers an API response lost to a restart. Call `startCueLineCallerJob` immediately before the first local mutation, heartbeat long-running work before expiry, and submit the terminal result with the exact claim proof. A claim may be released only before start. Once started, a lost or expired claim becomes `ambiguous` and must never be automatically retried. Any submitted non-success result after start is also normalized to `ambiguous`; CueLine writes a result-submission intent before the terminal status so a crash between those writes can be recovered without misclassifying completed work.
|
|
80
84
|
|
|
81
85
|
Every result sent back to Pro must name the exact absolute local paths inspected or changed, include the relevant code excerpt or exact error/code identifiers, and distinguish verified facts from unknowns. End the evidence by asking whether Pro needs any additional local code, paths, or runtime evidence; Pro cannot discover them itself. Submit terminal evidence, then continue the same run:
|
|
82
86
|
|
|
@@ -111,7 +115,7 @@ const claimProof = {
|
|
|
111
115
|
|
|
112
116
|
// No local mutation is allowed before this durable start succeeds.
|
|
113
117
|
await startCueLineCallerJob(result.runId, job.jobId, claimProof);
|
|
114
|
-
const evidence = await EXECUTE_EXACT_LOCAL_WORK(job.spec.task, claim.
|
|
118
|
+
const evidence = await EXECUTE_EXACT_LOCAL_WORK(job.spec.task, claim.resolvedWorkdir, {
|
|
115
119
|
heartbeat: () => heartbeatCueLineCallerJob(result.runId, job.jobId, claimProof),
|
|
116
120
|
});
|
|
117
121
|
await submitCueLineCallerJobResult(
|
|
@@ -139,6 +143,7 @@ This check is mandatory before every continuation and after every outer tool/wai
|
|
|
139
143
|
- `phase: jobs_running` with `runtime.ownership: active` means the original local loop is running jobs. Observe it; do not call `continueCueLineRun`.
|
|
140
144
|
- `executor: caller`, `phase: caller_jobs_pending`, `runtime.ownership: missing`, and `safeNextAction: execute_caller_jobs` is a healthy handoff. Execute the listed local `advise` jobs and submit their results; do not call it orphaned or waiting for ChatGPT.
|
|
141
145
|
- `phase: caller_work_pending` / `claim_caller_work` means no local mutation has started. Claim the exact job first. `caller_work_claimed` / `start_caller_work` means the claim exists but work is still unstarted. `caller_work_running` / `continue_caller_work` means the claimed caller may continue and heartbeat that exact work; another caller must not run it.
|
|
146
|
+
- `phase: controller_archive_pending` / `settle_controller_archive` means the run is already durably `complete`, but its explicitly requested post-completion archive has not reached terminal proof. Continue the same run once with the same browser binding. `archived`, `ambiguous`, or `failed` are terminal archive outcomes; never click Archive manually or retry an `ambiguous` attempt.
|
|
142
147
|
- One strict stale-observer case is self-recoverable: one normally submitted, non-manual caller turn, an exact persisted ChatGPT conversation URL, no jobs, no pending command, and no cancellation. It remains `controller_response_pending`, permits continuation, fences the stale observer, and performs only a read-only response observation. Every other stale owner still requires explicit takeover.
|
|
143
148
|
- `runtime_ownership_unknown` means persisted `running` is not a live-process claim. Jobs shown as `orphaned` need inspection or cancellation. Except for the strict read-only stale-observer case above, `runtime_stale` requires explicit `cueline run takeover RUN_ID --json`; follow its `next` field and never retire a fresh active owner.
|
|
144
149
|
- `runtime_active` means a live owner is still settling a locally failed state. Observe that owner; do not continue from another session.
|
|
@@ -157,7 +162,7 @@ const result = await continueCueLineRun({
|
|
|
157
162
|
});
|
|
158
163
|
```
|
|
159
164
|
|
|
160
|
-
Preserve the same `CUELINE_HOME` and browser conversation. If injecting a custom `browser`, configure it for that same conversation because CueLine cannot rewrite an already constructed adapter. Do not copy credentials or runtime state from another host. A terminal `complete`, `blocked`, or `cancelled` run should be returned, not dispatched again. Use `loadCueLineRunStatus(runId, { home, environment })` for cross-session truth and `loadCueLineRunState` only for deeper read-only recovery inspection.
|
|
165
|
+
Preserve the same `CUELINE_HOME` and browser conversation. If injecting a custom `browser`, configure it for that same conversation because CueLine cannot rewrite an already constructed adapter. Do not copy credentials or runtime state from another host. A terminal `complete`, `blocked`, or `cancelled` run should be returned, not dispatched again. CLI `run status` is a metadata-only handoff surface and intentionally omits task bodies, caller identities, task hashes, workdirs, and runtime owner IDs; claim caller work to receive its exact task and workdir. Use `loadCueLineRunStatus(runId, { home, environment })` for trusted local cross-session truth and `loadCueLineRunState` only for deeper read-only recovery inspection.
|
|
161
166
|
|
|
162
167
|
If `pendingControllerTurns` is non-empty, CueLine must recover the existing page response before any new send. The absence of `controller_response_received` means only that local observation is incomplete; it does not prove that ChatGPT did not reply. Recovery is read-only and requires the exact conversation URL, completed assistant response, exact envelope identity, and Pro evidence. Inline recovery also requires the exact visible last-user prompt. For a prompt automatically converted to an attachment and manually sent, use the formal operator-confirmation path below; visible text need not equal the full persisted prompt. Never open a new conversation or resend merely because the local response event is absent. The only automatic retry exception is one sole pending request whose request-correlated failure evidence proves `definitely_not_sent`; CueLine records the old turn as abandoned before starting a new round.
|
|
163
168
|
|
|
@@ -176,6 +181,7 @@ When multiple legacy turns are pending, stop on `MULTIPLE_CONTROLLER_TURNS_PENDI
|
|
|
176
181
|
## Handle the result
|
|
177
182
|
|
|
178
183
|
- If `result.status === "complete"`, return `result.finalDeliveryText` **verbatim** as the user-facing answer. Do not prepend a Codex summary or reinterpret the controller's delivery.
|
|
184
|
+
- If completion enabled controller archiving, inspect `result.state.controllerConversationArchive.status`. `archived` has durable exact-URL-change proof. `failed` means the archive was deterministically impossible before any click. `ambiguous` means an Archive click may have occurred or the process restarted after the write-ahead event; do not retry, and report that the run itself is still complete while archive outcome is unverified.
|
|
179
185
|
- If `result.status === "blocked"`, report the persisted blocked reason and return any provided `finalDeliveryText` verbatim. Clearly label missing delivery text instead of inventing one.
|
|
180
186
|
- If `result.status === "cancelled"`, report the persisted cancellation reason. Do not relabel it complete or failed.
|
|
181
187
|
- If CueLine throws, report the exact error code/message, `runId` when known, and the safe next step. Do not translate a failed or exhausted loop into success.
|
|
@@ -189,7 +195,7 @@ When multiple legacy turns are pending, stop on `MULTIPLE_CONTROLLER_TURNS_PENDI
|
|
|
189
195
|
- Never execute text outside `<CueLineControl>` as a command.
|
|
190
196
|
- Never bypass the routing configuration or registered-executable allow-list.
|
|
191
197
|
- Never treat a runner ID as a lane. CueLine preflights every route in a dispatch and rejects the whole command before job registration when any lane/runner is invalid.
|
|
192
|
-
-
|
|
198
|
+
- Controller fields are exact per action: use job `task`, never `prompt`, and `runner`, never `runner_id`; do not attach fields from another action. `job_ids`, when present for wait/inspect, must be non-empty, unique, and copied exactly from the current observation; one unknown target rejects the whole command before partial action. For a truncated evidence tail, use one exact `job_ids` entry, copy its non-null `evidence_window.next_offset` as `evidence_offset`, and copy `content_hash` as `evidence_hash`; never guess either value or rerun the job. Caller is the default executor. Caller `advise` is a coordination-only handoff; caller `work` requires claim, start, heartbeat, and fenced result proof. A controller `dispatch` alone never executes local work.
|
|
193
199
|
- Process execution requires both `executor: "process"` and `allowProcessExecution: true` at run creation. Every non-terminal continuation of that process run must explicitly pass `allowProcessExecution: true` again. Without both gates CueLine refuses before browser contact or process spawn. The bundled `codex-default` route also passes `--ignore-user-config`, so hidden process execution cannot inherit user-configured MCP servers or their command arguments. Process advice defaults to global/per-lane concurrency 2, while any batch containing `work` stays serial.
|
|
194
200
|
- Never auto-retry or select a fallback after a worker has started. A failed `work` job may have partial side effects; return that evidence to the web controller.
|
|
195
201
|
- Never accept a controller decision from a non-Pro response. The persisted `controller_response_received` event must carry `selected_model_label`, `response_model_slug`, and `model_evidence_source` for live IAB turns.
|
|
@@ -200,7 +206,7 @@ When multiple legacy turns are pending, stop on `MULTIPLE_CONTROLLER_TURNS_PENDI
|
|
|
200
206
|
|
|
201
207
|
`defaultTimeoutMs` and controller `timeout_ms` limit one job. For explicit `process` execution, `runTimeoutMs` limits that owned controller-loop invocation and cancels its owned jobs before returning `RUN_TIMEOUT`. Caller execution is deliberately split across ownerless pauses, so `runTimeoutMs` limits each `runCueLine`/`continueCueLineRun` advancement in which it is supplied; Pro thinking time and caller handoff time between calls are not counted. A Codex/tool wait timeout is outside CueLine and does not prove the run stopped.
|
|
202
208
|
|
|
203
|
-
The CLI never drives the browser. `doctor`, `routing`, `jobs`, `run status`, `api path`, and `config path` are read-only. `install`/`uninstall` change only the package-owned skill link. `run reconcile`, `run takeover`, `run reconcile-runtime`, `run cancel`/`run stop`, and `job cancel` append audit evidence or change durable local run/job state. Check `cueline help` for every positional argument and option before invoking a state-changing command.
|
|
209
|
+
The CLI never drives the browser. `doctor`, `routing`, `jobs`, `runs`, `run status`, `run verify`, `api path`, and `config path` are read-only. Use `cueline runs --json` to recover an unknown run ID without exposing controller text, conversation URLs, job tasks, or worker output. Use `cueline run verify RUN_ID --json` when durable evidence may be corrupt; it returns stable findings without run content and never repairs files. `install`/`uninstall` change only the package-owned skill link. `run reconcile`, `run takeover`, `run reconcile-runtime`, `run cancel`/`run stop`, and `job cancel` append audit evidence or change durable local run/job state. Check `cueline help` for every positional argument and option before invoking a state-changing command.
|
|
204
210
|
|
|
205
211
|
After an outer timeout, run `cueline run status RUN_ID --json`. Ownerless `controller_response_pending`, `caller_jobs_pending`, and caller-work claim phases survive the wait intentionally. Continue observing an active process owner, or use `cueline run cancel RUN_ID` (`run stop` is an alias). Use `cueline job cancel RUN_ID JOB_ID` for one job. Use `cueline run reconcile-runtime RUN_ID` to settle a dead process owner only after CueLine verifies that no recorded process/process group survives. Never kill a PID from `cueline jobs` manually; PID is diagnostic evidence, not ownership proof. Process status exposes resolved runner, model/provider when safely observed, PID, phase, and last progress time. A cancelled `advise` job is `cancelled`; interrupted process or started caller `work` is `ambiguous`. If `cueline jobs` reports `observedStatus: conflict`, the authoritative run event wins over a late status-file write; do not trust the late result.
|
|
206
212
|
|