okstra 0.163.2 → 0.165.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/README.md +8 -6
- package/docs/architecture.md +24 -15
- package/docs/cli.md +15 -8
- package/docs/for-ai/README.md +2 -2
- package/docs/for-ai/skills/okstra-inspect.md +2 -2
- package/docs/for-ai/skills/okstra-user-response.md +2 -2
- package/docs/project-structure-overview.md +22 -14
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/antigravity-worker.md +9 -7
- package/runtime/agents/workers/claude-worker.md +1 -0
- package/runtime/agents/workers/codex-worker.md +9 -7
- package/runtime/agents/workers/grok-worker.md +6 -4
- package/runtime/agents/workers/kimi-worker.md +6 -4
- package/runtime/bin/lib/okstra/cli.sh +5 -0
- package/runtime/bin/lib/okstra/globals.sh +2 -0
- package/runtime/bin/lib/okstra/usage.sh +5 -5
- package/runtime/bin/okstra-antigravity-exec.sh +1 -340
- package/runtime/bin/okstra-claude-exec.sh +1 -178
- package/runtime/bin/okstra-codex-exec.sh +1 -467
- package/runtime/bin/okstra-provider-exec.py +165 -190
- package/runtime/bin/okstra-trace-cleanup.sh +14 -7
- package/runtime/bin/okstra-wrapper-status.py +26 -19
- package/runtime/bin/okstra.sh +87 -91
- package/runtime/prompts/lead/adapters/cmux.md +2 -2
- package/runtime/prompts/lead/convergence.md +36 -8
- package/runtime/prompts/lead/okstra-lead-contract.md +24 -1
- package/runtime/prompts/lead/plan-body-verification.md +9 -1
- package/runtime/prompts/lead/report-writer.md +1 -0
- package/runtime/prompts/lead/team-contract.md +3 -3
- package/runtime/prompts/profiles/_common-contract.md +9 -1
- package/runtime/prompts/profiles/_coverage-critic.md +1 -1
- package/runtime/prompts/profiles/_implementation-diff-review.md +3 -1
- package/runtime/prompts/profiles/_implementation-self-check.md +1 -1
- package/runtime/prompts/profiles/_implementation-verifier.md +3 -1
- package/runtime/prompts/profiles/implementation-planning.md +6 -4
- package/runtime/python/okstra_ctl/adapters/accounting/__init__.py +11 -0
- package/runtime/python/okstra_ctl/adapters/accounting/claude_jsonl.py +17 -0
- package/runtime/python/okstra_ctl/adapters/accounting/cli_artifact.py +17 -0
- package/runtime/python/okstra_ctl/adapters/accounting/unavailable.py +19 -0
- package/runtime/python/okstra_ctl/adapters/dispatch/__init__.py +92 -0
- package/runtime/python/okstra_ctl/adapters/dispatch/cli_wrapper.py +54 -0
- package/runtime/python/okstra_ctl/adapters/dispatch/cmux.py +68 -0
- package/runtime/python/okstra_ctl/adapters/dispatch/native_team.py +13 -0
- package/runtime/python/okstra_ctl/adapters/hosts/antigravity/adapter.py +60 -0
- package/runtime/python/okstra_ctl/adapters/hosts/antigravity/manifest.json +1 -0
- package/runtime/{prompts/lead/adapters/antigravity.md → python/okstra_ctl/adapters/hosts/antigravity/relay.md} +52 -0
- package/runtime/python/okstra_ctl/adapters/hosts/capability_adapter.py +292 -0
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +120 -0
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/manifest.json +1 -0
- package/runtime/{prompts/lead/adapters/claude-code.md → python/okstra_ctl/adapters/hosts/claude-code/relay.md} +112 -1
- package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +60 -0
- package/runtime/python/okstra_ctl/adapters/hosts/codex/manifest.json +1 -0
- package/runtime/{prompts/lead/adapters/codex.md → python/okstra_ctl/adapters/hosts/codex/relay.md} +52 -0
- package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +72 -0
- package/runtime/python/okstra_ctl/adapters/hosts/external/manifest.json +1 -0
- package/runtime/{prompts/lead/adapters/external.md → python/okstra_ctl/adapters/hosts/external/relay.md} +53 -1
- package/runtime/python/okstra_ctl/adapters/hosts/grok/adapter.py +63 -0
- package/runtime/python/okstra_ctl/adapters/hosts/grok/manifest.json +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +90 -0
- package/runtime/python/okstra_ctl/adapters/hosts/kimi/adapter.py +63 -0
- package/runtime/python/okstra_ctl/adapters/hosts/kimi/manifest.json +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +90 -0
- package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +183 -0
- package/runtime/python/okstra_ctl/adapters/providers/antigravity/manifest.json +1 -0
- package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +110 -0
- package/runtime/python/okstra_ctl/adapters/providers/claude/manifest.json +1 -0
- package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +84 -0
- package/runtime/python/okstra_ctl/adapters/providers/codex/manifest.json +1 -0
- package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +76 -0
- package/runtime/python/okstra_ctl/adapters/providers/grok/manifest.json +1 -0
- package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +80 -0
- package/runtime/python/okstra_ctl/adapters/providers/kimi/manifest.json +1 -0
- package/runtime/python/okstra_ctl/application/__init__.py +1 -0
- package/runtime/python/okstra_ctl/application/advance_wizard.py +25 -0
- package/runtime/python/okstra_ctl/application/collect_usage.py +15 -0
- package/runtime/python/okstra_ctl/application/dispatch_assignments.py +15 -0
- package/runtime/python/okstra_ctl/application/resolve_assignment.py +93 -0
- package/runtime/python/okstra_ctl/application/resume_run.py +21 -0
- package/runtime/python/okstra_ctl/application/start_run.py +21 -0
- package/runtime/python/okstra_ctl/codex_dispatch.py +49 -826
- package/runtime/python/okstra_ctl/dispatch_core.py +244 -29
- package/runtime/python/okstra_ctl/dispatch_state.py +27 -0
- package/runtime/python/okstra_ctl/domain/__init__.py +34 -0
- package/runtime/python/okstra_ctl/domain/host.py +100 -0
- package/runtime/python/okstra_ctl/domain/provider.py +70 -0
- package/runtime/python/okstra_ctl/domain/wizard/__init__.py +19 -0
- package/runtime/python/okstra_ctl/domain/wizard/interaction.py +140 -0
- package/runtime/python/okstra_ctl/domain/worker_exec.py +102 -0
- package/runtime/python/okstra_ctl/domain/worker_role.py +34 -0
- package/runtime/python/okstra_ctl/domain/worker_stream.py +261 -0
- package/runtime/python/okstra_ctl/entrypoints/__init__.py +1 -0
- package/runtime/python/okstra_ctl/entrypoints/hosts.py +334 -0
- package/runtime/python/okstra_ctl/incremental_scope.py +16 -4
- package/runtime/python/okstra_ctl/models.py +54 -269
- package/runtime/python/okstra_ctl/ports/__init__.py +15 -0
- package/runtime/python/okstra_ctl/ports/host.py +32 -0
- package/runtime/python/okstra_ctl/ports/interaction.py +15 -0
- package/runtime/python/okstra_ctl/ports/lead_session.py +25 -0
- package/runtime/python/okstra_ctl/ports/usage_accounting.py +23 -0
- package/runtime/python/okstra_ctl/ports/worker_dispatch.py +32 -0
- package/runtime/python/okstra_ctl/registry/__init__.py +13 -0
- package/runtime/python/okstra_ctl/registry/factory_loader.py +32 -0
- package/runtime/python/okstra_ctl/registry/host_discovery.py +124 -0
- package/runtime/python/okstra_ctl/registry/host_registry.py +365 -0
- package/runtime/python/okstra_ctl/registry/provider_registry.py +149 -0
- package/runtime/python/okstra_ctl/render.py +145 -47
- package/runtime/python/okstra_ctl/report_html/common.py +71 -25
- package/runtime/python/okstra_ctl/report_html/models.py +5 -0
- package/runtime/python/okstra_ctl/report_html/render.py +1 -1
- package/runtime/python/okstra_ctl/report_html/run_usage.py +19 -0
- package/runtime/python/okstra_ctl/report_html/view_models/implementation_planning.py +14 -0
- package/runtime/python/okstra_ctl/report_views.py +44 -16
- package/runtime/python/okstra_ctl/run.py +80 -58
- package/runtime/python/okstra_ctl/session.py +1 -1
- package/runtime/python/okstra_ctl/stage_citations.py +52 -15
- package/runtime/python/okstra_ctl/team.py +44 -32
- package/runtime/python/okstra_ctl/user_response.py +45 -29
- package/runtime/python/okstra_ctl/wizard.py +175 -73
- package/runtime/python/okstra_ctl/worker_audit_ledger.py +29 -4
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +10 -3
- package/runtime/python/okstra_ctl/worker_request.py +140 -0
- package/runtime/python/okstra_ctl/worker_runner.py +622 -0
- package/runtime/python/okstra_token_usage/collect.py +42 -7
- package/runtime/python/okstra_token_usage/report.py +42 -0
- package/runtime/python/okstra_token_usage/task_totals.py +88 -0
- package/runtime/schemas/final-report-v1.0.schema.json +4040 -1066
- package/runtime/schemas/final-report-v2.0.schema.json +5673 -1412
- package/runtime/skills/okstra-inspect/SKILL.md +1 -2
- package/runtime/skills/okstra-inspect/facets/logs.md +5 -5
- package/runtime/skills/okstra-inspect/facets/run-audit.md +3 -3
- package/runtime/skills/okstra-run/SKILL.md +74 -29
- package/runtime/skills/okstra-user-response/SKILL.md +15 -5
- package/runtime/templates/implementation-worker-preamble.md +1 -1
- package/runtime/templates/report-writer-prompt-preamble.md +1 -0
- package/runtime/templates/reports/final-report.template.md +3 -3
- package/runtime/templates/reports/html/assets/base.css +8 -4
- package/runtime/templates/reports/html/base.template.html +12 -6
- package/runtime/templates/reports/html/i18n/en.json +32 -7
- package/runtime/templates/reports/html/i18n/ko.json +32 -7
- package/runtime/templates/reports/html/macros/forms.html +9 -3
- package/runtime/templates/reports/html/tasks/implementation-planning.template.html +14 -19
- package/runtime/templates/reports/report.js +59 -26
- package/runtime/templates/reports/user-response.template.md +12 -8
- package/runtime/templates/worker-prompt-preamble.md +1 -1
- package/runtime/validators/validate-implementation-plan-stages.py +17 -22
- package/runtime/validators/validate-report-views.py +0 -39
- package/runtime/validators/validate-run.py +96 -14
- package/runtime/validators/validate_session_conformance.py +69 -3
- package/src/cli-registry.mjs +0 -7
- package/src/commands/execute/render-bundle.mjs +4 -4
- package/src/commands/execute/run.mjs +8 -25
- package/src/commands/execute/wizard.mjs +33 -13
- package/src/commands/lifecycle/doctor.mjs +10 -10
- package/src/commands/lifecycle/install.mjs +53 -30
- package/src/commands/lifecycle/preflight.mjs +14 -4
- package/src/lib/host-registry-client.mjs +176 -0
- package/src/lib/runtime-manifest.mjs +6 -8
- package/runtime/bin/okstra-wrapper-agy-stream.py +0 -61
- package/runtime/python/okstra_ctl/error_issue.py +0 -640
- package/runtime/python/okstra_ctl/issue_signals.py +0 -186
- package/runtime/python/okstra_ctl/lead_runtime.py +0 -115
- package/runtime/python/okstra_ctl/runner_resolution.py +0 -103
- package/runtime/skills/okstra-inspect/facets/error-issue.md +0 -77
- package/src/commands/inspect/error-issue.mjs +0 -27
- package/src/lib/runtime-readiness.mjs +0 -90
- package/src/lib/runtime-resolver.mjs +0 -123
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: okstra-inspect
|
|
3
3
|
description: >-
|
|
4
|
-
Use this for everything that happens AFTER a single okstra task has already run — inspecting it or light bookkeeping on it, never launching new work. The tell is usually a named task id (PROD-1623, dev-9184), often dropped without the word "okstra." Reach for it when the user wants one task's: status, current/next phase, blockers, or approval gate; its final report — where it is or whether it passed (verdict / pass); its elapsed time or context/read cost; its run history, re-run, or resume; to mark it done / in-progress / blocked / todo; or a failed run's error logs gathered into a report (error report). Also turns cross-project okstra errors into an anonymized zip (error feedback)
|
|
4
|
+
Use this for everything that happens AFTER a single okstra task has already run — inspecting it or light bookkeeping on it, never launching new work. The tell is usually a named task id (PROD-1623, dev-9184), often dropped without the word "okstra." Reach for it when the user wants one task's: status, current/next phase, blockers, or approval gate; its final report — where it is or whether it passed (verdict / pass); its elapsed time or context/read cost; its run history, re-run, or resume; to mark it done / in-progress / blocked / todo; or a failed run's error logs gathered into a report (error report). Also turns cross-project okstra errors into an anonymized zip (error feedback), and audits run health across tasks (run audit). NOT for starting a run (okstra-run), rollups/schedules (okstra-rollup / okstra-schedule-gen), a brief (okstra-brief-gen), setup (okstra-setup), or cross-project management (okstra-manager).
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# OKSTRA Inspect
|
|
@@ -18,7 +18,6 @@ Single read-side entry point for okstra runtime inspection plus the one status m
|
|
|
18
18
|
| `cost` | `facets/cost.md` | Estimate file/read context cost for a task bundle. |
|
|
19
19
|
| `errors` | `facets/errors.md` | Aggregate okstra-run error logs for a task into a timestamped markdown report; print a summary. |
|
|
20
20
|
| `error-zip` | `facets/error-zip.md` | Collect cross-project okstra error logs into an anonymized zip (report + raw) and summarize clusters. |
|
|
21
|
-
| `error-issue` | `facets/error-issue.md` | Turn cross-project okstra anomalies into GitHub issue candidates; file the approved ones after explicit user approval. |
|
|
22
21
|
| `run-audit` | `facets/run-audit.md` | Check every run's artifacts against progress invariants; report what went wrong without an error ever being logged. |
|
|
23
22
|
| `recap` | `facets/recap.md` | Summarize a task's run-to-run phase transitions, then answer free-form questions over its `.okstra` artifacts. Appends each summary/Q&A to `recap/recap-log.jsonl`, and writes agent-authored notes to `notes/` for feeding into later runs. |
|
|
24
23
|
|
|
@@ -6,17 +6,17 @@ Loaded lazily by the dispatch table in `SKILL.md` (core). Shared rules — Step
|
|
|
6
6
|
|
|
7
7
|
Trigger phrases: "okstra logs", "log status", "log files", "log size", "log cleanup".
|
|
8
8
|
|
|
9
|
-
Read-only inventory of
|
|
9
|
+
Read-only inventory of the worker log files written next to each prompt history file (`<prompt>.log`). Reports sizes, ages, totals, and suggests cleanup commands. **Does not delete** — the user runs whichever `find … -delete` line they like.
|
|
10
10
|
|
|
11
|
-
**Background:**
|
|
11
|
+
**Background:** every CLI-worker dispatch writes a sidecar log next to its prompt history file. All five providers go through the same shared runner (`~/.okstra/lib/python/okstra_ctl/worker_runner.py`), so the file is there whichever provider ran:
|
|
12
12
|
|
|
13
13
|
```
|
|
14
14
|
.okstra/tasks/<task-group>/<task-id>/runs/<phase>/prompts/
|
|
15
15
|
<worker>-worker-prompt-<phase>-<seq>.md <-- prompt (git-tracked)
|
|
16
|
-
<worker>-worker-prompt-<phase>-<seq>.log <--
|
|
16
|
+
<worker>-worker-prompt-<phase>-<seq>.log <-- the run's archive of what the worker did
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
The log is
|
|
19
|
+
The log is rewritten from scratch at each dispatch — only the latest run for a given seq is preserved. Different seqs keep separate files. It holds one row per tool call and per tool result plus the worker's closing text, and drops thinking; a provider that emits plain text instead of an event stream has its progress copy capped at 5000 lines per run, with `[okstra log-cap] N progress line(s) elided` marking what was dropped. Long-running implementation dispatches can still produce multi-MB logs; analysis-phase dispatches are typically smaller.
|
|
20
20
|
|
|
21
21
|
### logs.1 — Inventory
|
|
22
22
|
|
|
@@ -29,7 +29,7 @@ Scans `<projectRoot>/.okstra/tasks/**/runs/*/prompts/*.log` and parses task/phas
|
|
|
29
29
|
- `perTask[]` — `{taskKey, fileCount, totalBytes, oldestEpoch, newestEpoch}`, total-size desc
|
|
30
30
|
- `totals` — `{fileCount, totalBytes, taskCount}`
|
|
31
31
|
|
|
32
|
-
If `totals.fileCount` is 0, report `No
|
|
32
|
+
If `totals.fileCount` is 0, report `No worker log files found under <projectRoot>` and stop.
|
|
33
33
|
|
|
34
34
|
### logs.2 — Summary tables
|
|
35
35
|
|
|
@@ -28,7 +28,7 @@ Under each, list the affected `taskKey` values with their `detail` and `source`.
|
|
|
28
28
|
State plainly which violations are this task's own state versus a repeated okstra defect:
|
|
29
29
|
|
|
30
30
|
- an invariant broken in **one** task → that task's own state; tell the user what to do about that task
|
|
31
|
-
- an invariant broken across **two or more** tasks →
|
|
32
|
-
- `approval-not-forgotten` is the exception
|
|
31
|
+
- an invariant broken across **two or more** tasks → a repeated okstra defect; say so and cite every affected `taskKey` so the user can decide what to do with it
|
|
32
|
+
- `approval-not-forgotten` is the exception no matter how far it spreads. It means a human has not approved yet, not that okstra did something wrong. Report it as a to-do list of tasks awaiting the user's approval instead.
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
This facet reports; it never files anything anywhere.
|
|
@@ -41,28 +41,29 @@ Every non-terminal `next` carries a `progress` object (`done` / `aborted` omit i
|
|
|
41
41
|
|
|
42
42
|
On `ok: false`, re-prompt with the same `current.step` using the error message. The wizard never advances on validation failure; the user retries the same step. **`current` may be `null`** when the current step itself cannot render (e.g. the approved plan's Stage Map is corrupt) — that case is terminal: show `error` and stop, the user must fix the plan file before retrying. Never re-prompt off a `null` `current`.
|
|
43
43
|
|
|
44
|
-
The wizard tells you
|
|
45
|
-
|
|
46
|
-
- `
|
|
47
|
-
- `
|
|
48
|
-
- `
|
|
49
|
-
- `
|
|
50
|
-
- `
|
|
44
|
+
The wizard tells you which relay operation to use via `next.interaction.kind`. Step 1 loads the current registered host's relay contract. Use the matching entry under its `interactions` object exactly; if the entry is absent, stop instead of inventing a host function or falling back silently. The only exception is the explicit `Legacy text relay compatibility` mapping selected in Step 1 when the preflight response has no `relayContract`.
|
|
45
|
+
|
|
46
|
+
- `native-single` → use the current registered host's relay contract for its native single-select function. Pass every option in its original order and submit the selected `options[].value`.
|
|
47
|
+
- `native-multi` → use the relay contract's native multi-select function. Pass every option in its original order and submit the selected values as one CSV answer; submit an empty selection as `--answer ""`.
|
|
48
|
+
- `native-group` → use the relay contract's native grouped-question function once. Preserve every question and option, then submit one JSON object keyed by `questions[].step`; when a grouped question is multi-select, its step value is the selected option values joined as one CSV string, not a JSON array.
|
|
49
|
+
- `numbered-single` → render every option as a 1-based numbered Markdown list and submit the user's next message unchanged.
|
|
50
|
+
- `numbered-multi` → render every option as a 1-based numbered Markdown list and submit the user's comma-separated reply unchanged.
|
|
51
|
+
- `sequential-group` → render every question in order, preserve each complete option list, collect every answer, and submit one JSON object keyed by `questions[].step`.
|
|
52
|
+
- `plain-text` → write `label` as plain text and submit the user's next message unchanged.
|
|
51
53
|
- `kind: "done"` → input collection finished; move to Step 5.
|
|
52
54
|
- `kind: "aborted"` → the user picked abort; the wizard is terminally cancelled. Tell the user on one short line that the run setup was aborted, delete the state file (`rm` with the literal path), and stop this skill — do NOT call `render-args` or `render-bundle` (the wizard rejects `render-args` on an aborted state).
|
|
53
55
|
|
|
56
|
+
Submit the answer shape required by `interaction.answerProtocol`; do not add normalization that the protocol does not request. Invalid, out-of-range, or ambiguous answers return `ok: false` and must re-render the same complete interaction.
|
|
57
|
+
|
|
54
58
|
The final `confirm` step is a normal `pick` step with three options — `Proceed` / `Edit` / `Abort`(abort) — and is rendered the same way (no special handling). `Edit` rewinds to any earlier step (including `base-ref`); `Abort` terminally cancels the wizard. The branch/worktree decision the run will actually use (for `implementation`, the **stage worktree** — not the task-key directory) is folded into the Step 4 confirmation summary block as a `worktree` line, so there is no separate branch-confirm prompt.
|
|
55
59
|
|
|
56
|
-
Never invent additional questions.
|
|
60
|
+
Never invent additional questions. **Never drop, hide, merge, reorder, or truncate** a `pick` / `pick_group` option — relay every `options[]` entry, including entries that carry a `(default)` / `(recommended)` suffix. Do not collapse a multi-option pick into a "recommended + Enter directly / Other" shortlist. The wizard's arrays are the complete authoritative choice sets, regardless of the current host UI's usual option limit. The run-prompt recommendation rule (1–2 recommendations + Enter directly) applies only to prompts this skill authors itself, never to wizard-provided options.
|
|
57
61
|
|
|
58
62
|
## Step 1: Preflight
|
|
59
63
|
|
|
60
|
-
|
|
64
|
+
Use the launcher's `OKSTRA_RUNTIME_HOST` value when it is present. Otherwise use the registered host ID that the current harness declares for this session. This is a harness capability declaration, never a worker-provider choice. Do not infer it from an executable or `PATH`, and do not silently substitute another host.
|
|
61
65
|
|
|
62
|
-
|
|
63
|
-
- Codex host → `codex`
|
|
64
|
-
- Antigravity CLI host → `antigravity`
|
|
65
|
-
- other host → `external`
|
|
66
|
+
Record the semantic functions that the live harness can actually perform. Always include `plain_text_input`. Record `native_single_select`, `native_multi_select`, or `native_question_group` only when the current harness exposes that function. Do not infer functions from the host ID; the effective declaration is computed from the relay contract after preflight.
|
|
66
67
|
|
|
67
68
|
The host-native provider runs as the current lead session when its role is supported. Other selected providers run through their registered CLI wrappers. Claude remains only the model-policy default; it is not the process owner.
|
|
68
69
|
|
|
@@ -72,15 +73,61 @@ Run one Bash tool call (Bash invocation rule from the top of this file applies):
|
|
|
72
73
|
okstra preflight --runtime <host-runtime> --json
|
|
73
74
|
```
|
|
74
75
|
|
|
75
|
-
Parse the stdout JSON. `ok: false` (or `okstra` not on `PATH` at all) → tell the user: "okstra not set up — run `/okstra-setup` first." Then stop. If the call fails with `unknown command: preflight`, the `okstra` binary on PATH predates this skill — tell the user to update it (`npm i -g okstra@latest`), then stop (`/okstra-setup` does not update the binary). Do **not** try to invoke `npx -y okstra@latest ...` as a fallback — `npx` is not on the literal-token allow-list and will force a confirmation prompt on every wizard call afterward. Every subsequent `okstra <subcmd>` call self-bootstraps its Python path, so never `export PYTHONPATH=...`.
|
|
76
|
+
Parse the stdout JSON. If `ok: false` with `stage: runtime_readiness`, show `runtimeReadiness.status` and every readiness check, including each adapter-provided `action`, then stop before Step 2. Do not relabel a host login, license, daemon, trust, or other readiness failure as missing Okstra setup. Any other `ok: false` response (or `okstra` not on `PATH` at all) → tell the user: "okstra not set up — run `/okstra-setup` first." Then stop. If the call fails with `unknown command: preflight`, the `okstra` binary on PATH predates this skill — tell the user to update it (`npm i -g okstra@latest`), then stop (`/okstra-setup` does not update the binary). Do **not** try to invoke `npx -y okstra@latest ...` as a fallback — `npx` is not on the literal-token allow-list and will force a confirmation prompt on every wizard call afterward. Every subsequent `okstra <subcmd>` call self-bootstraps its Python path, so never `export PYTHONPATH=...`.
|
|
77
|
+
|
|
78
|
+
When `runtimeReadiness` is present on an `ok: true` response, require `runtimeReadiness.status: ready` before Step 2. These checks come from the selected host adapter and are independent of worker-provider choices. A `blocked` or `unknown` status is a host readiness failure regardless of check IDs: show the status and checks, then stop before Step 2. Any other readiness status is unrecognized runtime output: show it and stop before Step 2 instead of guessing that the host is ready.
|
|
79
|
+
|
|
80
|
+
For a ready response, read the absolute file path in `runtimeReadiness.relayContract` with the current host's file-read primitive. Do not derive the path from the host ID or search `PATH`. In that file, find the `Wizard interaction relay` JSON block, require `schemaVersion: 1` and `runtime` equal to `runtimeReadiness.runtime`, then take its `semanticFunctions` allowlist and intersect it with the functions the live harness exposes. Pass only that intersection to Step 2; `plain_text_input` must be present. Keep the parsed `interactions` object for Step 3's function/input/response conversion. An unreadable file, malformed block, runtime mismatch, absent `plain_text_input`, or later interaction kind missing from the object is a host relay contract failure: show the problem and stop rather than guessing.
|
|
81
|
+
|
|
82
|
+
If `runtimeReadiness` is absent, preserve compatibility with an older preflight response: carry `projectRoot` and `projectId` into Step 2 and treat it as a response with no `relayContract`. If readiness exists but `relayContract` is absent, also enter the compatibility branch below. In that branch only, declare `plain_text_input` and keep its built-in `interactions` mapping for Step 3; do not assume a native tool from the host ID. The existing `unknown command: preflight` branch remains the authoritative stale-CLI failure.
|
|
76
83
|
|
|
77
|
-
|
|
84
|
+
### Legacy text relay compatibility
|
|
85
|
+
|
|
86
|
+
Use this built-in mapping only when the successful preflight response omitted `relayContract`. It is not a fallback for an unreadable, malformed, mismatched, or incomplete relay contract. If a present relay contract omits the wizard's interaction kind, keep the fail-closed rule above and stop.
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"scope": "preflight-response-without-relayContract-only",
|
|
91
|
+
"semanticFunctions": ["plain_text_input"],
|
|
92
|
+
"interactions": {
|
|
93
|
+
"numbered-single": {
|
|
94
|
+
"function": "host-text",
|
|
95
|
+
"input": {
|
|
96
|
+
"question": "label-with-progress",
|
|
97
|
+
"options": "all-in-original-order-as-numbered-markdown-label-and-description"
|
|
98
|
+
},
|
|
99
|
+
"response": { "source": "next-message", "submit": "raw" }
|
|
100
|
+
},
|
|
101
|
+
"numbered-multi": {
|
|
102
|
+
"function": "host-text",
|
|
103
|
+
"input": {
|
|
104
|
+
"question": "label-with-progress",
|
|
105
|
+
"options": "all-in-original-order-as-numbered-markdown-label-and-description"
|
|
106
|
+
},
|
|
107
|
+
"response": { "source": "next-message", "submit": "raw" }
|
|
108
|
+
},
|
|
109
|
+
"sequential-group": {
|
|
110
|
+
"function": "host-text",
|
|
111
|
+
"input": {
|
|
112
|
+
"questions": "all-one-at-a-time-in-original-order",
|
|
113
|
+
"question": "label-with-progress",
|
|
114
|
+
"options": "all-in-original-order-as-numbered-markdown-label-and-description"
|
|
115
|
+
},
|
|
116
|
+
"response": {
|
|
117
|
+
"source": "next-message-by-question-position",
|
|
118
|
+
"submit": "compact-step-json-raw"
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"plain-text": {
|
|
122
|
+
"function": "host-text",
|
|
123
|
+
"input": { "question": "label-with-progress" },
|
|
124
|
+
"response": { "source": "next-message", "submit": "raw" }
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
78
129
|
|
|
79
|
-
|
|
80
|
-
- On `claude-code`, `status: unavailable` → tell the user that Claude Code workspace trust could not be verified, ask them to open `<projectRoot>` directly in Claude Code and complete any trust prompt, then run `/okstra-run` again. Then stop before Step 2.
|
|
81
|
-
- `status: accepted` or `status: not-applicable` → carry `projectRoot` and `projectId` as literal strings into Step 2.
|
|
82
|
-
- If `runtimeReadiness` is absent, preserve compatibility with an older preflight response: carry `projectRoot` and `projectId` into Step 2. The existing `unknown command: preflight` branch remains the authoritative stale-CLI failure.
|
|
83
|
-
- Any other `workspace-trust` status is unrecognized runtime output: show the status and stop before Step 2 instead of guessing that trust exists.
|
|
130
|
+
For numbered interactions, render every option as a 1-based Markdown item containing its label followed by its description verbatim, in original order. For `sequential-group`, ask every question in order and build one compact JSON object keyed by `questions[].step`. Submit each user message unchanged; the wizard owns numbered and grouped normalization.
|
|
84
131
|
|
|
85
132
|
## Step 2: Initialize the wizard
|
|
86
133
|
|
|
@@ -99,7 +146,10 @@ okstra wizard init \
|
|
|
99
146
|
--state-file /var/folders/.../okstra-wizard.AbCd.json \
|
|
100
147
|
--project-root /abs/path/to/project \
|
|
101
148
|
--project-id my-project-id \
|
|
102
|
-
--host-runtime <host-runtime>
|
|
149
|
+
--host-runtime <host-runtime> \
|
|
150
|
+
--entry-mode current-session \
|
|
151
|
+
--available-function plain_text_input \
|
|
152
|
+
--available-function <each-additional-function-in-the-effective-intersection>
|
|
103
153
|
```
|
|
104
154
|
|
|
105
155
|
Output: the same `{ok, next}` JSON described above. The first `next` is always `step: "task_pick"`.
|
|
@@ -108,12 +158,7 @@ Output: the same `{ok, next}` JSON described above. The first `next` is always `
|
|
|
108
158
|
|
|
109
159
|
Repeat until `next.kind == "done"` (or `"aborted"` — terminal cancel, see "How the wizard talks to you"):
|
|
110
160
|
|
|
111
|
-
1. **Render** the prompt according to `kind`
|
|
112
|
-
- `pick` + `presentation: "numbered-text"` → plain text containing `label`, followed by every option as a numbered Markdown list. Consume the user's next message verbatim as the answer string.
|
|
113
|
-
- `pick` + `multi: false` → `AskUserQuestion` with `multiSelect: false`, `label`, and `options`. The user's chosen option's `value` is the answer string.
|
|
114
|
-
- `pick` + `multi: true` → `AskUserQuestion` with `multiSelect: true`, `label`, and `options`. Join the selected `value`s with `,` into a single literal CSV string (e.g. `"claude,codex,grok,kimi"`) and submit it as one `--answer` value. Empty selection submits `--answer ""` and the wizard re-prompts.
|
|
115
|
-
- `pick_group` → one `AskUserQuestion` with one question per `questions[]` entry (tab). Map each tab's selected `value` back by `questions[].step`, assemble a JSON object, and submit it as a single literal `--answer '<json>'`.
|
|
116
|
-
- `text` → plain text message containing `label`. Consume the user's next reply verbatim as the answer string (empty reply = empty string).
|
|
161
|
+
1. **Render** the prompt according to `next.interaction.kind` using the relay rules above. **Always append the progress marker to the rendered question label**: suffix it with ` (<next.progress.label>)` — render `progress.label` exactly as the wizard sent it, never recompute it. Example: label `Step 8/11 · 3 steps remaining` → `Select a model (Step 8/11 · 3 steps remaining)`. Re-prompts after `ok: false` reuse `current.progress.label` the same way. The progress marker is presentation-only — never send it back to the wizard as part of an answer.
|
|
117
162
|
2. **Submit** the answer — call `okstra wizard step` with the literal state-file path from Step 2 and the literal user answer (no shell variables, no `$(...)`):
|
|
118
163
|
```bash
|
|
119
164
|
okstra wizard step --state-file /var/folders/.../okstra-wizard.AbCd.json --answer preprod
|
|
@@ -138,7 +183,7 @@ That is the entire interactive flow. The wizard handles:
|
|
|
138
183
|
- brief path — **asked only for entry task-types (requirements-discovery / error-analysis / improvement-discovery / project-analysis / feature-analysis / change-impact-analysis)** (same-group `.okstra/briefs/<task-group>/**/*.md` candidates first, sorted by the newer of file-created/modified time and latest task-catalog use; direct input last; `Keep / Change` for existing entry tasks). `project-analysis`, `feature-analysis`, and `change-impact-analysis` are brief entry task types. A downstream lifecycle task-type auto carries in the manifest's brief, and when no registered brief exists a `brief_carry` 3-option prompt appears (recommend switching to entry / Enter directly / Abort). `release-handoff` has no brief step at all — prepare generates the input document that cites the verification report,
|
|
139
184
|
- analysis-input sub-flow — `project-analysis` has no target or evidence step. `feature-analysis` runs `project_evidence_pick` / `project_evidence`, then `analysis_target_pick` / `analysis_target`; the target is required even when the user skips project evidence. `change-impact-analysis` runs `feature_evidence_pick` / `feature_evidence`, then `project_evidence_pick` / `project_evidence`. The evidence steps show accepted compatible reports first and retain direct-path entry; do not invent a different relation or reorder these steps,
|
|
140
185
|
- base-ref pick + git rev-parse validation (skipped when reusing an active worktree),
|
|
141
|
-
- `implementation`-only sub-flow: approved-plan path (frontmatter `approved: true` check) + stage pick (`auto` = the earliest incomplete stage whose dependencies are satisfied, or a specific stage number) + executor pick. When an approved plan is selected and a `##
|
|
186
|
+
- `implementation`-only sub-flow: approved-plan path (frontmatter `approved: true` check) + stage pick (`auto` = the earliest incomplete stage whose dependencies are satisfied, or a specific stage number) + executor pick. When an approved plan is selected and a `## PLAN DECISION` sidecar carrying `Status: approved`, exported from the report — matching the plan on source-report·seq — is detected in that run's sibling `user-responses/`, the approve-confirm step expands to 3 options (`yes_apply` recommended: approve + apply the option as exported / `yes` approve only / `no` abort) — `yes_apply` validates the option against the plan's `optionCandidates` before applying it via the existing approval·option path,
|
|
142
187
|
- `release-handoff`-only sub-flow: after the approved plan auto-resolves, a `handoff_stage_pick` multi-select — choose an eligible stage bundle (stage-group) or the whole task (when an accepted whole-task verification report exists); the result goes out as render-args' `stages` key (csv, empty when whole-task),
|
|
143
188
|
- `Use defaults / Customize` branch with profile-aware worker/model questions,
|
|
144
189
|
- **resume-clarification (in-session equivalent)** — there is no separate mode or flag matching the shell's `okstra.sh --resume-clarification`; two steps of the standard flow carry out its substance. (1) `reuse_previous` (yes/no to reuse the previous run's settings — in `requirements-discovery` / `error-analysis` / `implementation-planning`, only when prior run-inputs exist): YES prefills workers·model·directive·related-tasks at once. (2) `clarification_pick`: if the **task-type's own** previous `final-report` exists it is auto-recommended as the carry-in input (falling back to the newest by mtime across all phases when absent), and the same run's `user-responses/` sidecar (answers the user filled in) is attached alongside. The chosen path is passed to prepare as `--clarification-response` — the user makes the sidecar via the report's `Export user response`, places it in `runs/<task-type>/user-responses/`, and re-runs the same phase,
|
|
@@ -217,7 +262,7 @@ okstra render-bundle \
|
|
|
217
262
|
|
|
218
263
|
The python function underneath is mutex-protected (`~/.okstra/.locks/<task-key>.lock`), writes `run-context-*.json` + `run-inputs-*.json` + all manifests + discovery files, and registers the run in `~/.okstra/recent.jsonl` with status `prepared`.
|
|
219
264
|
|
|
220
|
-
You can delete the literal state-file path after this point — its job is done. Invoke `rm` with the literal path (e.g. `rm /var/folders/.../okstra-wizard.AbCd.json`), not a shell variable.
|
|
265
|
+
You can delete the literal state-file path after this point — its job is done. Invoke `command rm` with the literal path (e.g. `command rm /var/folders/.../okstra-wizard.AbCd.json`), not a shell variable. `command` is what keeps a `rm='rm -i'` alias from turning this into a confirmation prompt nobody is there to answer.
|
|
221
266
|
|
|
222
267
|
<!-- BEGIN FRAGMENT: host-orchestration-implementation -->
|
|
223
268
|
## Host orchestration rules — implementation
|
|
@@ -147,26 +147,36 @@ Once the loop has covered every open item, **before** calling `write`, **echo ba
|
|
|
147
147
|
- If the user changes any item, show the echo-back again with the changed value and re-confirm.
|
|
148
148
|
- Every `value` must be what the user picked or typed, never a wording you settled on for them — this gate guarantees that.
|
|
149
149
|
|
|
150
|
-
## Step 5: (Optional) Record
|
|
150
|
+
## Step 5: (Optional) Record the plan decision
|
|
151
151
|
|
|
152
|
-
Record
|
|
152
|
+
Record a decision alongside the answers only when the user stated one outright. Never infer it from the tone of the conversation.
|
|
153
|
+
|
|
154
|
+
Approval also requires that the report's approval-blocking clarification items are **all filled with an answer**:
|
|
153
155
|
|
|
154
156
|
```
|
|
155
|
-
--
|
|
157
|
+
--plan-decision '{"status":"approved","implementationOption":"<the option the user chose>"}'
|
|
156
158
|
```
|
|
157
159
|
|
|
158
160
|
If any approval-target item is not filled with an answer, or is a reframe/hold, do not approve — tell the user the gate is still open.
|
|
159
161
|
|
|
162
|
+
A user who turns the plan down gets the same treatment, and the reason is mandatory — the next planning run reads it to know what to change:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
--plan-decision '{"status":"rejected","reason":"<the user's own words>"}'
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Use `revision-requested` instead of `rejected` when the user wants the same plan reworked rather than dropped. Either way, quote the user's reason; do not summarise it into your own.
|
|
169
|
+
|
|
160
170
|
## Step 6: Write the sidecar
|
|
161
171
|
|
|
162
172
|
Run only after the user has confirmed the echo-back with "confirmed":
|
|
163
173
|
|
|
164
174
|
```bash
|
|
165
|
-
okstra user-response write --report <reportPath> --answers '<answers-json>' --
|
|
175
|
+
okstra user-response write --report <reportPath> --answers '<answers-json>' --plan-decision '<plan-decision-json>' --task-key <taskKey>
|
|
166
176
|
```
|
|
167
177
|
|
|
168
178
|
- `--answers` = the JSON array of `{id, kind, value, rationale?, disposition}` objects collected in Step 3.
|
|
169
|
-
- `--
|
|
179
|
+
- `--plan-decision` is attached only when recording a decision in Step 5 (otherwise omit it).
|
|
170
180
|
- `--task-key` is the value carried forward from Step 1/2.
|
|
171
181
|
- Report the path from the returned JSON `{sidecar: <path>}` to the user. (`write` merges items when a sidecar already exists — the same `id` is overwritten with the new value.)
|
|
172
182
|
|
|
@@ -31,7 +31,7 @@ When `**Evidence ledger:** required-v1` is present, append one canonical row to
|
|
|
31
31
|
|
|
32
32
|
- Evidence read: `<project-relative path without a line suffix>`
|
|
33
33
|
|
|
34
|
-
Every file citation in the result MUST use backticks
|
|
34
|
+
Every file citation in the result MUST use backticks, a line suffix, and the same project-relative path its ledger row carries — for example `src/config/env.ts:1-22`. A bare filename (`env.ts:1-22`) does not match its row and fails exactly like a file you never opened, however many times you cited the full path earlier. A cited path without a matching ledger row fails Phase 7 in `validators/validate-run.py` `validate_worker_results_audit()`. Do not add a row for a file you did not open.
|
|
35
35
|
|
|
36
36
|
## Anchor headers
|
|
37
37
|
|
|
@@ -25,6 +25,7 @@ Write `- PROGRESS: <stage> <ISO-8601-UTC>` there before reading and at least eve
|
|
|
25
25
|
- Follow the task-type schema excerpt and Phase 6 report-writer contract. Do not perform independent analysis, edit source code, or load implementation coding-preflight resources.
|
|
26
26
|
- Invoke `okstra render-final-report <Result Path>` after writing data.json and verify the markdown sibling exists before returning.
|
|
27
27
|
- Preserve source item IDs, convergence classifications, round history, and unresolved dissent; do not recompute them from intuition.
|
|
28
|
+
- Every `clarificationItems[]` row you leave `status: open` with `blocks: approval` carries `origin` and `userConfirmation`. `origin` is `worker-finding` only when an analyser or verifier reached it on its own evidence — when the lead's dispatch prompt told you to raise it, it is `lead-directed`, whatever the workers then agreed. `userConfirmation` is what the lead reports having done about it (`asked-and-answered` / `asked-awaiting` / `deferred-no-interactive-session`); if the dispatch does not say, write `asked-awaiting` and name the gap in your return message rather than guessing. An open approval blocker stops the whole task, so a row that misreports where it came from costs a re-run. **Enforced:** `validators/validate-run.py` `_validate_open_approval_blocker_provenance`.
|
|
28
29
|
|
|
29
30
|
## Anchor headers
|
|
30
31
|
|
|
@@ -380,10 +380,10 @@ Carried-forward plan items retain their prior verdicts verbatim; each such item
|
|
|
380
380
|
|
|
381
381
|
### Stepwise Execution Order
|
|
382
382
|
|
|
383
|
-
| step | action | files | command | expected |
|
|
384
|
-
|
|
383
|
+
| step | action | files | command | outcome | expected |
|
|
384
|
+
|------|--------|-------|---------|---------|----------|
|
|
385
385
|
{% for row in stage.stepwiseExecution -%}
|
|
386
|
-
| {{ row.step | mdcell }} | {{ row.action | mdcell }} | `{{ row.files | mdcell }}` | `{{ row.command | mdcell }}` | {{ row.
|
|
386
|
+
| {{ row.step | mdcell }} | {{ row.action | mdcell }} | `{{ row.files | mdcell }}` | `{{ row.command | mdcell }}` | {{ row.outcome | mdcell }} | {{ row.expectedDetail | mdcell }} |
|
|
387
387
|
{% endfor %}
|
|
388
388
|
|
|
389
389
|
### Stage Exit Contract
|
|
@@ -77,8 +77,9 @@ th, td { text-align: left; vertical-align: top; border-bottom: 1px solid color-m
|
|
|
77
77
|
.ledger-key { display: flex; flex-wrap: wrap; gap: .6rem; font-weight: 600; }
|
|
78
78
|
.ledger-kind { font-weight: 400; color: GrayText; }
|
|
79
79
|
.ledger-text { max-width: 78ch; }
|
|
80
|
-
.ledger-source { font-size: .9rem; color: GrayText; }
|
|
81
|
-
.ledger-source > span:first-child::after
|
|
80
|
+
.ledger-source, .ledger-confidence { font-size: .9rem; color: GrayText; }
|
|
81
|
+
.ledger-source > span:first-child::after,
|
|
82
|
+
.ledger-confidence > span:first-child::after { content: ":"; }
|
|
82
83
|
.status { display: inline-block; white-space: nowrap; border-radius: 999px; padding: .1rem .5rem; background: color-mix(in srgb, GrayText 15%, Canvas); }
|
|
83
84
|
.status-gap, .status-risk, .status-error, .status-timeout { background: color-mix(in srgb, #d94b4b 18%, Canvas); }
|
|
84
85
|
/* Figures are read by comparing them down the column, which only works when
|
|
@@ -86,13 +87,16 @@ th, td { text-align: left; vertical-align: top; border-bottom: 1px solid color-m
|
|
|
86
87
|
the right edge is the one they share. */
|
|
87
88
|
.run-usage-lede { max-width: 78ch; }
|
|
88
89
|
.figure { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
89
|
-
/*
|
|
90
|
+
/* Five nowrap number columns need almost none of the width, and the default
|
|
90
91
|
even split spent it on them while the agent names wrapped mid-word. */
|
|
91
|
-
[data-report-section="run-usage"] .row-key { width:
|
|
92
|
+
[data-report-section="run-usage"] .row-key { width: 40%; }
|
|
92
93
|
.cli-extra { display: block; color: GrayText; font-size: .85em; }
|
|
93
94
|
tfoot th { font-weight: 600; }
|
|
94
95
|
tfoot tr:first-child > * { border-top: 2px solid color-mix(in srgb, CanvasText 30%, transparent); }
|
|
95
96
|
tfoot .grand-total > * { font-weight: 700; }
|
|
97
|
+
/* The task total counts runs this report is not about, so it is ruled off from
|
|
98
|
+
the run's own figures rather than reading as one more line of them. */
|
|
99
|
+
tfoot .task-cumulative > * { border-top: 1px solid color-mix(in srgb, CanvasText 20%, transparent); color: GrayText; }
|
|
96
100
|
.human-report-footer { width: min(1120px, calc(100% - 2rem)); margin: 0 auto 2rem; display: flex; flex-wrap: wrap; gap: .6rem; }
|
|
97
101
|
.human-report-footer pre { flex-basis: 100%; white-space: pre-wrap; max-height: 14em; overflow: auto; }
|
|
98
102
|
fieldset, label { display: block; margin: .7rem 0; }
|
|
@@ -31,9 +31,11 @@
|
|
|
31
31
|
<ol class="ledger">
|
|
32
32
|
{% for row_id, row in evidenceIndex.items() %}
|
|
33
33
|
<li class="ledger-item" id="id-{{ row_id }}">
|
|
34
|
-
<p class="ledger-key"><span class="ledger-id">{{ row_id }}</span><span class="ledger-kind">{{ row.kind }}</span></p>
|
|
34
|
+
<p class="ledger-key"><span class="ledger-id">{{ row_id }}</span><span class="ledger-kind">{{ row.kind | enum_label('ledgerKind') }}</span></p>
|
|
35
35
|
<p class="ledger-text">{{ row.text | inline_code }}</p>
|
|
36
|
-
<p class="ledger-source"><span>{{ t('base.source
|
|
36
|
+
{% if row.codeEvidence %}<p class="ledger-source"><span>{{ t('base.source') }}</span> {{ row.codeEvidence | code_evidence }}</p>
|
|
37
|
+
{% elif row.source %}<p class="ledger-source"><span>{{ t('base.source') }}</span> {{ row.source | inline_code }}</p>{% endif %}
|
|
38
|
+
{% if row.confidence %}<p class="ledger-confidence"><span>{{ t('base.confidence') }}</span> {{ row.confidence | inline_code }}</p>{% endif %}
|
|
37
39
|
</li>
|
|
38
40
|
{% endfor %}
|
|
39
41
|
</ol>
|
|
@@ -47,6 +49,7 @@
|
|
|
47
49
|
<thead><tr>
|
|
48
50
|
<th scope="col">{{ t('runUsage.agent') }}</th>
|
|
49
51
|
<th scope="col" class="figure">{{ t('runUsage.raw-tokens') }}</th>
|
|
52
|
+
<th scope="col" class="figure">{{ t('runUsage.cache-read-tokens') }}</th>
|
|
50
53
|
<th scope="col" class="figure">{{ t('runUsage.billable-tokens') }}</th>
|
|
51
54
|
<th scope="col" class="figure">{{ t('runUsage.cost') }}</th>
|
|
52
55
|
<th scope="col" class="figure">{{ t('runUsage.duration') }}</th>
|
|
@@ -56,6 +59,7 @@
|
|
|
56
59
|
<tr>
|
|
57
60
|
{{ row_key(pairs=[(t('runUsage.agent'), row.agent), (t('runUsage.role'), row.role), (t('runUsage.model'), row.model)], status_name=t('runUsage.status'), status_raw=row.status, status_text=row.status | enum_label('workerStatus')) }}
|
|
58
61
|
<td class="figure">{{ row.rawTokens }}{% if row.cliTokens %}<span class="cli-extra">{{ t('runUsage.cli') }} {{ row.cliTokens }}</span>{% endif %}</td>
|
|
62
|
+
<td class="figure">{{ row.cacheReadTokens }}</td>
|
|
59
63
|
<td class="figure">{{ row.billableTokens }}</td>
|
|
60
64
|
<td class="figure">{{ row.cost }}{% if row.cliCost %}<span class="cli-extra">+ {{ t('runUsage.cli') }} {{ row.cliCost }}</span>{% endif %}</td>
|
|
61
65
|
<td class="figure">{{ row.duration }}</td>
|
|
@@ -65,6 +69,7 @@
|
|
|
65
69
|
<tr>
|
|
66
70
|
<td class="row-key">{{ t('runUsage.unaccounted') }}</td>
|
|
67
71
|
<td class="figure">{{ runUsage.unaccounted.rawTokens }}</td>
|
|
72
|
+
<td class="figure">{{ runUsage.unaccounted.cacheReadTokens }}</td>
|
|
68
73
|
<td class="figure">{{ runUsage.unaccounted.billableTokens }}</td>
|
|
69
74
|
<td class="figure">{{ runUsage.unaccounted.cost }}</td>
|
|
70
75
|
<td class="figure"></td>
|
|
@@ -72,10 +77,11 @@
|
|
|
72
77
|
{% endif %}
|
|
73
78
|
</tbody>
|
|
74
79
|
<tfoot>
|
|
75
|
-
<tr><th scope="row">{{ t('runUsage.row-lead') }}</th><td class="figure">{{ runUsage.lead.rawTokens }}</td><td class="figure">{{ runUsage.lead.billableTokens }}</td><td class="figure">{{ runUsage.lead.cost }}</td><td class="figure"></td></tr>
|
|
76
|
-
<tr><th scope="row">{{ t('runUsage.row-workers') }}</th><td class="figure">{{ runUsage.worker.rawTokens }}</td><td class="figure">{{ runUsage.worker.billableTokens }}</td><td class="figure">{{ runUsage.worker.cost }}</td><td class="figure"></td></tr>
|
|
77
|
-
<tr class="grand-total"><th scope="row">{{ t('runUsage.row-total') }}</th><td class="figure">{{ runUsage.grand.rawTokens }}</td><td class="figure">{{ runUsage.grand.billableTokens }}</td><td class="figure">{{ runUsage.grand.cost }}</td><td class="figure"></td></tr>
|
|
78
|
-
{% if runUsage.cliCost %}<tr><th scope="row">{{ t('runUsage.row-cli') }}</th><td class="figure"></td><td class="figure"></td><td class="figure">{{ runUsage.cliCost }}</td><td class="figure"></td></tr>{% endif %}
|
|
80
|
+
<tr><th scope="row">{{ t('runUsage.row-lead') }}</th><td class="figure">{{ runUsage.lead.rawTokens }}</td><td class="figure">{{ runUsage.lead.cacheReadTokens }}</td><td class="figure">{{ runUsage.lead.billableTokens }}</td><td class="figure">{{ runUsage.lead.cost }}</td><td class="figure"></td></tr>
|
|
81
|
+
<tr><th scope="row">{{ t('runUsage.row-workers') }}</th><td class="figure">{{ runUsage.worker.rawTokens }}</td><td class="figure">{{ runUsage.worker.cacheReadTokens }}</td><td class="figure">{{ runUsage.worker.billableTokens }}</td><td class="figure">{{ runUsage.worker.cost }}</td><td class="figure"></td></tr>
|
|
82
|
+
<tr class="grand-total"><th scope="row">{{ t('runUsage.row-total') }}</th><td class="figure">{{ runUsage.grand.rawTokens }}</td><td class="figure">{{ runUsage.grand.cacheReadTokens }}</td><td class="figure">{{ runUsage.grand.billableTokens }}</td><td class="figure">{{ runUsage.grand.cost }}</td><td class="figure"></td></tr>
|
|
83
|
+
{% if runUsage.cliCost %}<tr><th scope="row">{{ t('runUsage.row-cli') }}</th><td class="figure"></td><td class="figure"></td><td class="figure"></td><td class="figure">{{ runUsage.cliCost }}</td><td class="figure"></td></tr>{% endif %}
|
|
84
|
+
{% if runUsage.taskCumulative %}<tr class="task-cumulative"><th scope="row">{{ t('runUsage.row-task-cumulative') | replace('{runs}', runUsage.taskCumulative.runCount) }}</th><td class="figure">{{ runUsage.taskCumulative.rawTokens }}</td><td class="figure">{{ runUsage.taskCumulative.cacheReadTokens }}</td><td class="figure">{{ runUsage.taskCumulative.billableTokens }}</td><td class="figure">{{ runUsage.taskCumulative.cost }}</td><td class="figure"></td></tr>{% endif %}
|
|
79
85
|
</tfoot>
|
|
80
86
|
</table>
|
|
81
87
|
</section>
|
|
@@ -67,6 +67,21 @@
|
|
|
67
67
|
"timeout": "Timed out",
|
|
68
68
|
"not-run": "Not run",
|
|
69
69
|
"synthesis-only": "Synthesis only"
|
|
70
|
+
},
|
|
71
|
+
"replanMode": {
|
|
72
|
+
"full": "Replanned in full",
|
|
73
|
+
"incremental": "Partly replanned"
|
|
74
|
+
},
|
|
75
|
+
"ledgerKind": {
|
|
76
|
+
"code-evidence": "Code evidence",
|
|
77
|
+
"hypothesis": "Hypothesis",
|
|
78
|
+
"confirmed-fact": "Confirmed fact",
|
|
79
|
+
"inference": "Inference",
|
|
80
|
+
"unknown": "Unknown",
|
|
81
|
+
"cross-check-consensus": "Agreed across workers",
|
|
82
|
+
"cross-check-dissent": "Workers disagreed",
|
|
83
|
+
"missing-information": "Missing information",
|
|
84
|
+
"follow-up": "Follow-up"
|
|
70
85
|
}
|
|
71
86
|
},
|
|
72
87
|
"enumHint": {
|
|
@@ -85,7 +100,8 @@
|
|
|
85
100
|
"written": "Written",
|
|
86
101
|
"elapsed": "Elapsed",
|
|
87
102
|
"evidence-ledger": "Evidence ledger",
|
|
88
|
-
"source
|
|
103
|
+
"source": "Source",
|
|
104
|
+
"confidence": "Confidence",
|
|
89
105
|
"export-my-answers": "Export my answers",
|
|
90
106
|
"copy": "Copy",
|
|
91
107
|
"dismiss": "Dismiss",
|
|
@@ -95,7 +111,7 @@
|
|
|
95
111
|
},
|
|
96
112
|
"runUsage": {
|
|
97
113
|
"heading": "What this run cost",
|
|
98
|
-
"intro": "
|
|
114
|
+
"intro": "What each agent this run put in, and how long it worked. Agents overlap, so their working times do not add up to the elapsed time in the header. Raw tokens are what the run sent through the model once. Cache re-reads are the context read back on every turn — they are billed at a tenth of the input rate, which is why they sit outside the raw figure but inside the money. Billable tokens restate the whole run in base-input units, and the cost comes from that.",
|
|
99
115
|
"agent": "Agent",
|
|
100
116
|
"role": "Role",
|
|
101
117
|
"model": "Model",
|
|
@@ -109,7 +125,9 @@
|
|
|
109
125
|
"row-lead": "Lead",
|
|
110
126
|
"row-workers": "Workers",
|
|
111
127
|
"row-total": "Total",
|
|
112
|
-
"row-cli": "CLI calls (billed separately)"
|
|
128
|
+
"row-cli": "CLI calls (billed separately)",
|
|
129
|
+
"cache-read-tokens": "Cache re-reads",
|
|
130
|
+
"row-task-cumulative": "This task so far ({runs} runs)"
|
|
113
131
|
},
|
|
114
132
|
"macros": {
|
|
115
133
|
"forms": {
|
|
@@ -122,7 +140,6 @@
|
|
|
122
140
|
"why": "Why",
|
|
123
141
|
"further-evidence": "Further evidence",
|
|
124
142
|
"scope-change-requested": "Scope change requested",
|
|
125
|
-
"approve-this-plan": "Approve this plan",
|
|
126
143
|
"implementation-option": "Implementation option",
|
|
127
144
|
"i-approve-this-plan": "I approve this plan.",
|
|
128
145
|
"approval-is-held": "Approval is held:",
|
|
@@ -136,7 +153,12 @@
|
|
|
136
153
|
"recommended": "Recommended",
|
|
137
154
|
"scope-impact": "Scope",
|
|
138
155
|
"added-work": "Added work",
|
|
139
|
-
"direction-change": "Direction change"
|
|
156
|
+
"direction-change": "Direction change",
|
|
157
|
+
"decide-on-this-plan": "Decide on this plan",
|
|
158
|
+
"request-changes-to-this-plan": "Send it back for changes",
|
|
159
|
+
"reject-this-plan": "Reject this plan",
|
|
160
|
+
"why-required-for-changes-or-rejection": "Why — required when you send it back or reject it",
|
|
161
|
+
"answer-the-blockers-then-regenerate": "Answer {ids}, export your answers, then regenerate the report with the clarification resume command."
|
|
140
162
|
},
|
|
141
163
|
"visualizations": {
|
|
142
164
|
"component": "Component",
|
|
@@ -285,7 +307,8 @@
|
|
|
285
307
|
"statement-overturned": "Statement overturned",
|
|
286
308
|
"replaced-with": "Replaced with",
|
|
287
309
|
"no-answer-overturned-anything": "No answer overturned anything.",
|
|
288
|
-
"scope-restated": "
|
|
310
|
+
"scope-restated": "How much of the plan was rewritten",
|
|
311
|
+
"scope-restated-lede": "This planning run started from an earlier plan. This is how much of it survived your answers.",
|
|
289
312
|
"stages-verified-again": "Stages verified again",
|
|
290
313
|
"stages-carried-over-as-they-were": "Stages carried over as they were",
|
|
291
314
|
"decision-record-draft": "Decision record draft",
|
|
@@ -297,7 +320,9 @@
|
|
|
297
320
|
"topic": "Topic",
|
|
298
321
|
"why": "Why",
|
|
299
322
|
"open-decisions-before-approval": "Open decisions before approval",
|
|
300
|
-
"no-open-decision-is-holding-approval": "No open decision is holding approval."
|
|
323
|
+
"no-open-decision-is-holding-approval": "No open decision is holding approval.",
|
|
324
|
+
"uniform-verifier-label": "Uniform verifier",
|
|
325
|
+
"uniform-verifier-legend": "This verifier answered the same verdict to every item it voted on, so this round's refutation signal came from its peers alone — the gate above reads as a wider cross-check than it was. A unanimous round is a legitimate outcome; confirm from the worker's audit sidecar that it actually opened the cited evidence."
|
|
301
326
|
},
|
|
302
327
|
"implementation": {
|
|
303
328
|
"what-was-delivered": "What was delivered",
|