okstra 0.36.0 → 0.36.2
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.kr.md +3 -5
- package/README.md +3 -5
- package/docs/project-structure-overview.md +2 -7
- package/docs/superpowers/plans/2026-05-24-implementation-lead-context-slimming.md +1700 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/SKILL.md +18 -5
- package/runtime/agents/workers/claude-worker.md +5 -6
- package/runtime/agents/workers/codex-worker.md +10 -9
- package/runtime/agents/workers/gemini-worker.md +7 -6
- package/runtime/agents/workers/report-writer-worker.md +13 -11
- package/runtime/prompts/launch.template.md +1 -0
- package/runtime/prompts/profiles/_implementation-deliverable.md +53 -0
- package/runtime/prompts/profiles/_implementation-executor.md +60 -0
- package/runtime/prompts/profiles/_implementation-verifier.md +76 -0
- package/runtime/prompts/profiles/implementation.md +27 -134
- package/runtime/python/okstra_ctl/paths.py +3 -0
- package/runtime/python/okstra_ctl/render.py +19 -5
- package/runtime/python/okstra_ctl/render_final_report.py +4 -1
- package/runtime/python/okstra_ctl/run.py +7 -1
- package/runtime/python/okstra_ctl/session.py +65 -7
- package/runtime/python/okstra_token_usage/report.py +6 -2
- package/runtime/skills/okstra-brief/SKILL.md +2 -211
- package/runtime/skills/okstra-inspect/SKILL.md +581 -0
- package/runtime/skills/okstra-run/SKILL.md +3 -3
- package/runtime/skills/okstra-schedule/SKILL.md +10 -153
- package/runtime/skills/okstra-setup/SKILL.md +1 -1
- package/runtime/skills/okstra-team-contract/SKILL.md +15 -106
- package/runtime/templates/reports/brief.template.md +204 -0
- package/runtime/templates/reports/schedule.template.md +12 -3
- package/runtime/templates/worker-prompt-preamble.md +108 -0
- package/src/uninstall.mjs +7 -3
- package/runtime/prompts/profiles/kr/_common-contract.md +0 -92
- package/runtime/prompts/profiles/kr/error-analysis.md +0 -36
- package/runtime/prompts/profiles/kr/final-verification.md +0 -48
- package/runtime/prompts/profiles/kr/implementation-planning.md +0 -90
- package/runtime/prompts/profiles/kr/implementation.md +0 -144
- package/runtime/prompts/profiles/kr/improvement-discovery.md +0 -42
- package/runtime/prompts/profiles/kr/release-handoff.md +0 -104
- package/runtime/prompts/profiles/kr/requirements-discovery.md +0 -42
- package/runtime/skills/okstra-history/SKILL.md +0 -165
- package/runtime/skills/okstra-logs/SKILL.md +0 -173
- package/runtime/skills/okstra-report-finder/SKILL.md +0 -111
- package/runtime/skills/okstra-status/SKILL.md +0 -246
- package/runtime/skills/okstra-time-summary/SKILL.md +0 -172
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: okstra-inspect
|
|
3
|
+
description: |
|
|
4
|
+
Use for any read-side okstra inspection or status mutation. Single skill dispatches by sub-command to five facets — status, history, report, time, logs. Trigger words include "okstra status", "task status", "current phase", "next phase", "okstra status set", "okstra mark", "<task-id> done|in-progress|진행중|완료", "okstra history", "past runs", "re-run", "resume", "list tasks", "find report", "show report for", "read the okstra report", "continue from report", "작업 시간", "소요 시간", "time summary", "duration", "elapsed", "얼마나 걸렸", "시간 분석", "okstra logs", "로그 현황", "로그 파일", "log files", "log size", "log status", "로그 정리", "log cleanup".
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# OKSTRA Inspect
|
|
8
|
+
|
|
9
|
+
Single read-side entry point for okstra runtime inspection plus the one write-side mutation that belongs here (`workStatus`). Sub-commands:
|
|
10
|
+
|
|
11
|
+
| Sub-command | What it does |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `status` | Task / phase status, blockers, approval state. Also writes `workStatus` on user request. |
|
|
14
|
+
| `history` | List past okstra runs; assemble re-run or resume command. |
|
|
15
|
+
| `report` | Resolve final-report path for a task-key. Optionally read it. |
|
|
16
|
+
| `time` | Per-task-type and per-worker duration breakdown for a task. |
|
|
17
|
+
| `logs` | Inventory codex/gemini wrapper `.log` sidecars; emit cleanup commands. |
|
|
18
|
+
|
|
19
|
+
## Step 0: Verify okstra runtime + project setup (shared)
|
|
20
|
+
|
|
21
|
+
Before any sub-command, run each of the following commands as a **separate Bash tool call**. Each command starts with the literal token `okstra` so the `Bash(okstra:*)` permission match succeeds. Do **not** wrap any of them in `if`, `eval`, `export`, `$(...)`, `VAR=...`, `||`, or `&&`, and do **not** introduce a `$OKSTRA_CMD` variable or an `npx -y okstra@latest` fallback — those leading tokens defeat the permission match and force a confirmation prompt on every call. The LLM (you) inspects each command's output and decides what to do next in natural language — never in shell.
|
|
22
|
+
|
|
23
|
+
1. `okstra ensure-installed`
|
|
24
|
+
If this exits non-zero, tell the user: "okstra not installed — run `npx okstra@latest install` once, then retry this skill." Then stop. Do **not** try to invoke `npx -y okstra@latest ...` as a fallback.
|
|
25
|
+
|
|
26
|
+
2. `okstra check-project --json`
|
|
27
|
+
Reads the project from the current working directory. Parse the JSON from stdout. The shape is `{ok, projectRoot, projectJsonPath, projectId}`.
|
|
28
|
+
|
|
29
|
+
- `ok: false` → tell the user: "this project has no okstra setup. Run `/okstra-setup` first." Then stop.
|
|
30
|
+
- `ok: true` → carry `projectRoot` as a literal string and use it as the base for sub-command steps.
|
|
31
|
+
|
|
32
|
+
Subsequent `okstra <subcmd>` calls self-bootstrap their Python path, so this skill never needs `okstra paths --shell` / `export PYTHONPATH=...`.
|
|
33
|
+
|
|
34
|
+
## Step 1: Dispatch by intent
|
|
35
|
+
|
|
36
|
+
Classify the user's request into one sub-command using the trigger table above. If ambiguous (e.g. "okstra 보여줘"), ask which facet — do not silently default. After routing, the chosen sub-command's section below governs the rest of the response.
|
|
37
|
+
|
|
38
|
+
When the user chains multiple facets in one message (e.g. "status, and then time for DEV-9047"), execute them sequentially — Step 0 runs once, each sub-command section runs once.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## status
|
|
43
|
+
|
|
44
|
+
Trigger phrases: "okstra status", "task status", "current phase", "next phase", "what is pending", "resume point", "okstra status set", "okstra mark", "<task-id> done", "<task-id> in-progress", "<task-id> 진행중", "<task-id> 완료".
|
|
45
|
+
|
|
46
|
+
### status.1 — Overall project status
|
|
47
|
+
|
|
48
|
+
Read `.project-docs/okstra/discovery/task-catalog.json`. The catalog is the authoritative source — every field listed below (including `workStatus`, `workStatusUpdatedAt`, `workStatusNote`) is projected directly from each `task-manifest.json` by `scripts/okstra_ctl/render.py :: render_task_catalog_discovery`. Do NOT re-open individual manifests for the overview.
|
|
49
|
+
|
|
50
|
+
| Field | Description |
|
|
51
|
+
|------|------|
|
|
52
|
+
| `taskKey` | `<project-id>:<task-group>:<task-id>` |
|
|
53
|
+
| `taskType` | latest task type |
|
|
54
|
+
| `workCategory` | bugfix / feature / improvement / refactor / ops-change / unknown. Display `unknown` as-is, but flag with `(unset)` annotation so the reader knows the requirements-discovery classification was skipped or no `--work-category` flag was passed. |
|
|
55
|
+
| `currentStatus` | task-level status |
|
|
56
|
+
| `currentPhase` | lifecycle current phase |
|
|
57
|
+
| `currentPhaseState` | lifecycle phase state |
|
|
58
|
+
| `nextRecommendedPhase` | next recommended phase |
|
|
59
|
+
| `routingStatus` | routing decision status |
|
|
60
|
+
| `awaitingApproval` | approval 대기 여부 |
|
|
61
|
+
| `latestRunStatus` | latest run status |
|
|
62
|
+
| `latestReportPath` | latest report path |
|
|
63
|
+
| `latestResumeCommandPath` | latest resume command |
|
|
64
|
+
| `workStatus` | user-managed work status (todo / in-progress / blocked / done; default in-progress) |
|
|
65
|
+
| `updatedAt` | last update time |
|
|
66
|
+
|
|
67
|
+
Sort by `updatedAt` desc, then `taskKey`.
|
|
68
|
+
|
|
69
|
+
The overview table is intentionally narrow so it renders cleanly in a terminal. Only six columns are shown; for any task that needs a closer look (phase state, routing, approval gate, last run status, resume path, etc.) tell the user to run `okstra status <task-key>` (or `/okstra-inspect status <task-key>`) for the detail view in `status.2`.
|
|
70
|
+
|
|
71
|
+
If `awaitingApproval` is true OR `routingStatus == "pending"`, append a `*` to the `Next` cell and explain the marker once below the table.
|
|
72
|
+
|
|
73
|
+
```markdown
|
|
74
|
+
## okstra Status — <project-id>
|
|
75
|
+
|
|
76
|
+
| # | Task Key | Category | Phase | workStatus | Next |
|
|
77
|
+
|---|----------|----------|-------|------------|------|
|
|
78
|
+
| 1 | proj:group:id | bugfix | error-analysis | in-progress | implementation-planning |
|
|
79
|
+
| 2 | proj:group:id2 | feature | requirements-discovery | done | pending-routing-decision* |
|
|
80
|
+
|
|
81
|
+
`*` = awaiting user approval or pending routing decision. Run `okstra status <task-key>` for details.
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### status.2 — Specific task status
|
|
85
|
+
|
|
86
|
+
Given a specific `task-key` or `task-group + task-id`:
|
|
87
|
+
|
|
88
|
+
1. If possible, quickly look it up in `task-catalog.json`.
|
|
89
|
+
2. If necessary, read `.project-docs/okstra/tasks/<task-group>/<task-id>/task-manifest.json` directly.
|
|
90
|
+
3. If you need the latest run information, read `history/timeline.json` along with the latest run manifest.
|
|
91
|
+
|
|
92
|
+
Required fields: `taskKey`, `taskType`, `workCategory`, `currentStatus`, `latestRunStatus`, `workflow.{currentPhase, currentPhaseState, phaseStates, lastCompletedPhase, nextRecommendedPhase, awaitingApproval, routingStatus, lastSafeCheckpoint}`, `workStatus`, `workStatusUpdatedAt`, `workStatusNote`, `latestReportPath`, `latestResumeCommandPath`, `historyTimelinePath`.
|
|
93
|
+
|
|
94
|
+
```markdown
|
|
95
|
+
## okstra Task Status — <task-key>
|
|
96
|
+
|
|
97
|
+
- Work category: `<category>`
|
|
98
|
+
- Current phase: `<phase>`
|
|
99
|
+
- Current phase state: `<phase-state>`
|
|
100
|
+
- Last completed phase: `<phase-or-->`
|
|
101
|
+
- Next recommended phase: `<phase>`
|
|
102
|
+
- Awaiting approval: `<yes|no>`
|
|
103
|
+
- Routing status: `<routing-status>`
|
|
104
|
+
- Task status: `<task-status>`
|
|
105
|
+
- Latest run status: `<run-status>`
|
|
106
|
+
- Latest report: `<relative-path-or-->`
|
|
107
|
+
- Resume command: `<relative-path-or-->`
|
|
108
|
+
- workStatus: `<todo|in-progress|blocked|done>` (updated `<workStatusUpdatedAt-or-->`)
|
|
109
|
+
- workStatus note: `<workStatusNote-or-->`
|
|
110
|
+
|
|
111
|
+
### Phase States
|
|
112
|
+
|
|
113
|
+
- `requirements-discovery`: `<state>`
|
|
114
|
+
- `error-analysis`: `<state>`
|
|
115
|
+
- `implementation-planning`: `<state>`
|
|
116
|
+
- `implementation`: `<state>`
|
|
117
|
+
- `final-verification`: `<state>`
|
|
118
|
+
- `release-handoff`: `<state>`
|
|
119
|
+
|
|
120
|
+
### Safe Resume Checkpoint
|
|
121
|
+
|
|
122
|
+
- Label: `<checkpoint-label>`
|
|
123
|
+
- Run manifest: `<relative-path-or-->`
|
|
124
|
+
- Team state: `<relative-path-or-->`
|
|
125
|
+
- Report: `<relative-path-or-->`
|
|
126
|
+
- Resume command: `<relative-path-or-->`
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### status.3 — Resume / next-step guidance
|
|
130
|
+
|
|
131
|
+
The status response always includes one of:
|
|
132
|
+
|
|
133
|
+
1. **Resume current run** — if `latestResumeCommandPath` exists, display that path.
|
|
134
|
+
2. **Restart current phase** — task can be re-run with the same `task-key` and current `taskType`.
|
|
135
|
+
3. **Start next phase** — if `workflow.nextRecommendedPhase` is one of `error-analysis`, `implementation-planning`, `implementation`, `final-verification`, `release-handoff`, that phase is proposed. If `nextRecommendedPhase` is `pending-release-handoff`, surface as verdict-gated and propose `release-handoff` only when the cited verdict is `accepted`.
|
|
136
|
+
4. **Need more information** — if `nextRecommendedPhase` is `pending-routing-decision` or `routingStatus` is `pending`.
|
|
137
|
+
5. **Task complete (terminal)** — if `nextRecommendedPhase` is `done-or-follow-up`, the task lifecycle has reached its terminal signal. This is **not** a "next phase" — do not propose a new okstra run. Surface the latest report and ask the user whether any follow-up task should be opened separately.
|
|
138
|
+
|
|
139
|
+
### status.4 — Update workStatus (write)
|
|
140
|
+
|
|
141
|
+
Recognize requests to change a task's `workStatus` and update the corresponding `task-manifest.json`.
|
|
142
|
+
|
|
143
|
+
**Trigger patterns** (recognize both):
|
|
144
|
+
|
|
145
|
+
Natural language: "DEV-6827 done으로 바꿔줘", "PROD-1623을 blocked로 표시", "DEV-9047 진행중", "Mark DEV-6827 as done".
|
|
146
|
+
|
|
147
|
+
Explicit command:
|
|
148
|
+
- `okstra status set <task-id> <status>`
|
|
149
|
+
- `okstra status set <task-group> <task-id> <status>` (disambiguation)
|
|
150
|
+
- `okstra mark <task-id> <status>`
|
|
151
|
+
- `okstra status set <task-id> <status> --note "<note>"`
|
|
152
|
+
|
|
153
|
+
Accepted `<status>` values: `todo`, `in-progress`, `blocked`, `done`.
|
|
154
|
+
|
|
155
|
+
**Procedure:**
|
|
156
|
+
|
|
157
|
+
1. **Validate status value.** If not in the enum, output an error and the allowed values list. Do not modify any file.
|
|
158
|
+
2. **Look up the task** in `.project-docs/okstra/discovery/task-catalog.json` by `task-id` (case-insensitive on both `task-id` and `task-group`).
|
|
159
|
+
- If the user provided `<task-group>` explicitly, scope the lookup to that group (case-insensitive).
|
|
160
|
+
- Single match → proceed. Multiple matches across different groups → list and ask user to retry with explicit form (`okstra status set <task-group> <TASK-ID> <status>`). No match → `<TASK-ID>를 찾을 수 없습니다.` and stop.
|
|
161
|
+
3. **Open the matching `task-manifest.json`** at `.project-docs/okstra/tasks/<task-group-segment>/<task-id-segment>/task-manifest.json`. Assemble the path from the catalog entry's `taskGroupPathSegment` and `taskIdPathSegment` fields (filesystem-safe segments emitted by the renderer) — NOT from the raw user-supplied strings, which may differ in case or contain characters normalized when the manifest was created. Prefer the `taskManifestPath` field directly when present.
|
|
162
|
+
4. **Update fields at the manifest root:**
|
|
163
|
+
- `workStatus` ← new status value
|
|
164
|
+
- `workStatusUpdatedAt` ← current ISO-8601 UTC timestamp (`2026-05-01T10:23:45Z`)
|
|
165
|
+
- `workStatusNote`: if `--note` provided, set to its value; if not provided, leave any existing value untouched (do not delete, do not blank). If the field did not exist before, do not create it.
|
|
166
|
+
|
|
167
|
+
**Manifest preservation (critical):**
|
|
168
|
+
- Use a targeted in-place edit (Edit tool with old_string/new_string anchors).
|
|
169
|
+
- Do NOT round-trip the file through `JSON.parse` + `JSON.stringify` — that reorders keys, drops trailing newlines, normalizes spacing.
|
|
170
|
+
- Preserve existing key order, indentation, and trailing newline exactly.
|
|
171
|
+
|
|
172
|
+
5. **Confirm in Korean:**
|
|
173
|
+
```
|
|
174
|
+
✓ <TASK-ID> workStatus: <previous> → <new>
|
|
175
|
+
✓ task-manifest.json 업데이트됨
|
|
176
|
+
```
|
|
177
|
+
`<previous>` = `(없음)` if the field was absent before.
|
|
178
|
+
|
|
179
|
+
**Default value convention:** if `workStatus` is missing or empty, infer the display value from lifecycle state (DO NOT default to a static `in-progress`):
|
|
180
|
+
|
|
181
|
+
| Manifest state | Inferred display |
|
|
182
|
+
|---|---|
|
|
183
|
+
| `currentStatus == "completed"` AND `workflow.nextRecommendedPhase == "done-or-follow-up"` | `done` (inferred) |
|
|
184
|
+
| `currentStatus == "completed"` AND `workflow.currentPhaseState == "completed"` | `phase-done` (inferred) |
|
|
185
|
+
| `currentStatus == "contract-violated"` OR `workflow.currentPhaseState == "blocked"` | `blocked` (inferred) |
|
|
186
|
+
| anything else | `in-progress` (default) |
|
|
187
|
+
|
|
188
|
+
Annotate inferred values with `(inferred)` or `(default)`. Do not back-fill on read; only write when the user explicitly issues an update.
|
|
189
|
+
|
|
190
|
+
**Catalog sync note:** this sub-command updates `task-manifest.json` only. `discovery/task-catalog.json` may become stale until regenerated. Downstream consumers (e.g. `okstra-schedule`) should re-read each manifest directly.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## history
|
|
195
|
+
|
|
196
|
+
Trigger phrases: "okstra history", "past runs", "run history", "re-run", "list tasks", "다시 실행", "resume", "이어서".
|
|
197
|
+
|
|
198
|
+
**Re-run vs Resume — decide upfront.** Re-run = start a fresh run (new run-seq, new manifest, new report) reusing an old run's parameters → `history.3`. Resume = continue an interrupted Claude session for an existing run, no new run-seq → `history.4`. If the user is ambiguous, ask — defaulting to the wrong one either wastes a fresh run-seq or silently abandons a recoverable session.
|
|
199
|
+
|
|
200
|
+
### history.1 — Read the task catalog
|
|
201
|
+
|
|
202
|
+
1. Read `.project-docs/okstra/discovery/task-catalog.json`.
|
|
203
|
+
2. Apply filters from user input (all optional, AND-combined):
|
|
204
|
+
- `--task-type <type>` → keep entries whose `taskType` matches.
|
|
205
|
+
- `--latest-run-status <status>` → keep entries whose `latestRunStatus` matches (`completed`, `contract-violated`, `error`).
|
|
206
|
+
- `--task-group <group>` → keep entries whose `taskGroup` matches.
|
|
207
|
+
3. Sort by `updatedAt` desc.
|
|
208
|
+
4. Page: default `--limit 20`. If truncated, add `... <N> more (pass --limit <N> to see all)`.
|
|
209
|
+
5. Extract: `taskKey`, `taskType`, `currentStatus`, `latestRunStatus`, `latestRunManifestPath`, `updatedAt`, `latestReportPath`, `latestResumeCommandPath`, `historyTimelinePath`.
|
|
210
|
+
|
|
211
|
+
```markdown
|
|
212
|
+
## okstra Task History — <project-id>
|
|
213
|
+
|
|
214
|
+
| # | Task Key | Type | currentStatus | latestRunStatus | Last Run | Report |
|
|
215
|
+
|---|----------|------|---------------|------------------|----------|--------|
|
|
216
|
+
| 1 | proj:group:id | error-analysis | completed | completed | 2026-04-05 22:59 | .project-docs/.../final-report-*.md |
|
|
217
|
+
| 2 | proj:group:id2 | final-verification | todo | error | 2026-04-04 15:30 | -- |
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Catalog absent — fallback.** Do NOT bail out. Manifests on disk are the source of truth.
|
|
221
|
+
|
|
222
|
+
1. Glob `<projectRoot>/.project-docs/okstra/tasks/*/*/task-manifest.json`.
|
|
223
|
+
2. For each manifest, read the same fields as above.
|
|
224
|
+
3. Apply the same filters/sort/limit and print the same table, prefixed with: `note: task-catalog.json missing; reconstructed from task manifests on disk.`
|
|
225
|
+
4. Only if the glob yields zero manifests: `There is no okstra execution history yet.`
|
|
226
|
+
|
|
227
|
+
### history.2 — Run history by task
|
|
228
|
+
|
|
229
|
+
When a user selects a specific task:
|
|
230
|
+
|
|
231
|
+
1. Retrieve `historyTimelinePath`, read `runs` array.
|
|
232
|
+
2. Extract: `runTimestamp`, `runDateTimeSegment`, `taskType`, `status`, `runManifestPath`, `reportPath`, `resumeCommandPath`, `relatedTasks`.
|
|
233
|
+
|
|
234
|
+
```markdown
|
|
235
|
+
## Runs for <task-key>
|
|
236
|
+
|
|
237
|
+
| # | Timestamp | Type | Status | Report |
|
|
238
|
+
|---|-----------|------|--------|--------|
|
|
239
|
+
| 1 | 2026-04-05 22:59 | error-analysis | completed | .../final-report-*.md |
|
|
240
|
+
| 2 | 2026-04-04 15:30 | error-analysis | error | -- |
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### history.3 — Re-run (NEW run from old parameters)
|
|
244
|
+
|
|
245
|
+
Builds a fresh run — new run-seq, new manifest, new report — using parameters from a previous `run-manifest-*.json`. Does NOT touch old artifacts; use `history.4` to continue an interrupted session.
|
|
246
|
+
|
|
247
|
+
1. Pick the source run-manifest: `runManifestPath` from `history.2`, or task's `latestRunManifestPath` from `history.1`.
|
|
248
|
+
2. Read the manifest and extract required arguments:
|
|
249
|
+
- `projectId` → `--project-id`
|
|
250
|
+
- `taskGroup` → `--task-group`
|
|
251
|
+
- `taskId` → `--task-id`
|
|
252
|
+
- `taskType` → `--task-type`
|
|
253
|
+
- `taskBriefPath` → `--task-brief`
|
|
254
|
+
3. Optional arguments (include only when present in source):
|
|
255
|
+
- `recommendedWorkers` → `--workers` (comma-separated)
|
|
256
|
+
- `relatedTasks` → `--related-tasks`
|
|
257
|
+
- model overrides → `--claude-model`, `--codex-model`, `--gemini-model`
|
|
258
|
+
- for `taskType: implementation`: `teamContract.executor.provider` → `--executor <claude|codex|gemini>` when different from `claude`.
|
|
259
|
+
4. **`taskType: implementation` only — resolve `--base-ref`:** base ref is NOT in the run-manifest; it lives in the worktree registry at `~/.okstra/worktrees/registry.json`. If a worktree is already registered, existing branch & base are reused — omit `--base-ref` unless the user explicitly wants a different starting point. If no worktree is registered (cleaned up), `--base-ref` is mandatory — ask the user before running.
|
|
260
|
+
5. Display the assembled command:
|
|
261
|
+
```bash
|
|
262
|
+
okstra.sh \
|
|
263
|
+
--project-id <project-id> \
|
|
264
|
+
--task-group <task-group> \
|
|
265
|
+
--task-id <task-id> \
|
|
266
|
+
--task-type <task-type> \
|
|
267
|
+
--task-brief <brief-path> \
|
|
268
|
+
--workers <worker-list>
|
|
269
|
+
```
|
|
270
|
+
6. Once the user confirms, execute it.
|
|
271
|
+
|
|
272
|
+
### history.4 — Resume (continue an interrupted run)
|
|
273
|
+
|
|
274
|
+
Continues an existing Claude session for an unfinished run. Does NOT create a new run-seq — for a fresh dispatch use `history.3`.
|
|
275
|
+
|
|
276
|
+
1. Read `latestResumeCommandPath` from `history.1` (or `resumeCommandPath` from a `history.2` timeline entry).
|
|
277
|
+
2. Verify the file exists on disk.
|
|
278
|
+
3. If present: `bash <resume-command-path>`.
|
|
279
|
+
4. If absent: `No resume script available for this run. Use 'history.3' to start a fresh run instead.`
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## report
|
|
284
|
+
|
|
285
|
+
Trigger phrases: "find report", "show report for", "read the okstra report", "continue from report".
|
|
286
|
+
|
|
287
|
+
### report.1 — Resolve report path
|
|
288
|
+
|
|
289
|
+
task-key format: `<project-id>:<task-group>:<task-id>`.
|
|
290
|
+
|
|
291
|
+
**Normalization:** task-key matching is lowercase. Disk segments are slugified (lowercase + non-alphanumeric runs → `-`) per `scripts/lib/okstra/interactive.sh:147`. Catalog lookup is case-insensitive; file path assembly uses slugified segments.
|
|
292
|
+
|
|
293
|
+
Lookup methods (in priority order):
|
|
294
|
+
|
|
295
|
+
A. **`task-catalog.json` (fast):** read `.project-docs/okstra/discovery/task-catalog.json`, match `taskKey` lowercase. `latestReportPath` is task-type-agnostic "most recent report".
|
|
296
|
+
|
|
297
|
+
B. **`task-manifest.json` (direct):** if catalog missing, slugify task-group / task-id, read `.project-docs/okstra/tasks/<group-segment>/<id-segment>/task-manifest.json`, use `latestReportPath` (task-type-agnostic).
|
|
298
|
+
|
|
299
|
+
C. **`timeline.json` (specific run):** for a specific date or run, read `.project-docs/okstra/tasks/<group-segment>/<id-segment>/history/timeline.json`, filter `runs[]` by `runTimestamp` / `status` / `taskType`, use `runs[].reportPath`.
|
|
300
|
+
|
|
301
|
+
D. **Specific task-type (fallback):** `latestReportPath` is task-type-agnostic. For a specific task-type's latest report, look under `.project-docs/okstra/tasks/<group-segment>/<id-segment>/runs/<task-type-segment>/reports/`, filename pattern `final-report-<task-type-segment>-<NNN>.md` per `scripts/okstra_ctl/sequence.py:31`. Highest seq is latest. Cross-verify with `timeline.json`'s `runs[].taskType` filter.
|
|
302
|
+
|
|
303
|
+
### report.2 — Confirm existence
|
|
304
|
+
|
|
305
|
+
1. Verify `latestReportPath` is non-empty AND the file exists on disk. Either signal indicates report presence (tolerant).
|
|
306
|
+
2. If present, display the path and ask the user whether to read it.
|
|
307
|
+
3. If absent, check `task-manifest.json` signals:
|
|
308
|
+
- `latestReportPath` empty/missing AND `currentStatus != completed` AND `workStatus != done` AND `workflow.routingStatus` not completion-like → `이 task는 아직 완료되지 않았습니다 (currentStatus: <currentStatus>, workStatus: <workStatus>).`
|
|
309
|
+
- Any signal indicates completion but the file is missing → `보고서 파일이 존재하지 않습니다: <path>`
|
|
310
|
+
|
|
311
|
+
`workStatus` enum: `todo | in-progress | blocked | done`. `currentStatus`: `completed` / `contract-violated` etc. `"completed"` string does NOT exist in `workStatus` — do not confuse the two.
|
|
312
|
+
|
|
313
|
+
### report.3 — Read + next-step guidance
|
|
314
|
+
|
|
315
|
+
After reading the report, surface follow-up options:
|
|
316
|
+
|
|
317
|
+
1. **구현 진행:** based on the report's "권장 다음 단계" section.
|
|
318
|
+
2. **추가 검증:** new okstra run with the same task-key:
|
|
319
|
+
```bash
|
|
320
|
+
scripts/okstra.sh --task-key <task-key> --task-type <task-type>
|
|
321
|
+
```
|
|
322
|
+
For richer options (base-ref, workers, render-only), use the `history` sub-command.
|
|
323
|
+
3. **관련 task 확인:** if the report references related task-keys, fetch their reports too.
|
|
324
|
+
|
|
325
|
+
### report — Output template
|
|
326
|
+
|
|
327
|
+
```markdown
|
|
328
|
+
## Report for <task-key>
|
|
329
|
+
|
|
330
|
+
| Field | Value |
|
|
331
|
+
| ------------ | -------------------------------------------------- |
|
|
332
|
+
| Status | `<status>` |
|
|
333
|
+
| Task type | `<task-type>` |
|
|
334
|
+
| Run seq | `<NNN>` |
|
|
335
|
+
| Run date | `<runTimestamp ISO-8601>` |
|
|
336
|
+
| Report (rel) | `<relative-path-from-project-root>` |
|
|
337
|
+
| Report (abs) | `<absolute-path>` |
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## time
|
|
343
|
+
|
|
344
|
+
Trigger phrases: "작업 시간", "소요 시간", "time summary", "duration", "elapsed", "얼마나 걸렸", "시간 분석".
|
|
345
|
+
|
|
346
|
+
Aggregate elapsed work time for a given task, grouped by **task type** and broken down by **worker** (lead, claude, codex, gemini, report-writer).
|
|
347
|
+
|
|
348
|
+
**Data sources** (both collected by okstra):
|
|
349
|
+
|
|
350
|
+
1. `.project-docs/okstra/tasks/<task-group>/<task-id>/history/timeline.json` — `runs` array with `runTimestamp`, `taskType`, `status`, `teamStatePath`, `taskRootPath`. Both path fields may be either project-root-relative or task-root-relative depending on which `render.py` version wrote the manifest.
|
|
351
|
+
2. Each run's `.../runs/<task-type>/state/team-state-<suffix>.json` — populated by `scripts/okstra-token-usage.py` at Phase 7. Contains `leadUsage.{startedAt, endedAt, durationMs}` and `workers[].{workerId, agent, usage.{startedAt, endedAt, durationMs}}`.
|
|
352
|
+
|
|
353
|
+
If a run never reached Phase 7, its `team-state` lacks `durationMs`. Mark such runs as `unavailable` rather than guessing.
|
|
354
|
+
|
|
355
|
+
### time.1 — Resolve task-id → timeline path
|
|
356
|
+
|
|
357
|
+
1. If the user gave a full `task-key`, use it directly.
|
|
358
|
+
2. Otherwise read `.project-docs/okstra/discovery/task-catalog.json` and find the entry whose `taskId` matches.
|
|
359
|
+
3. Multiple matches → list candidates (`taskKey`, `taskType`, `updatedAt`) and ask the user to pick.
|
|
360
|
+
4. Read `historyTimelinePath` from the chosen entry.
|
|
361
|
+
|
|
362
|
+
If `task-catalog.json` is missing: `No okstra history found. Run scripts/okstra.sh first.`
|
|
363
|
+
|
|
364
|
+
### time.2 — Walk runs and collect durations
|
|
365
|
+
|
|
366
|
+
For each entry in `timeline.json`'s `runs` array:
|
|
367
|
+
|
|
368
|
+
1. Resolve the `team-state` file via two-step lookup:
|
|
369
|
+
a. First try `<projectRoot>/<teamStatePath>`.
|
|
370
|
+
b. If that file does not exist, fall back to `<projectRoot>/<taskRootPath>/<teamStatePath>` (the manifest's `taskRootPath` is task-root relative to project root; `teamStatePath` written by `render.py` is task-root-relative in many runs).
|
|
371
|
+
If neither resolves, treat the run as `unavailable`.
|
|
372
|
+
2. Extract `taskType` from the timeline entry (authoritative), `leadUsage.durationMs` and `leadUsage.{startedAt,endedAt}`, and for each `worker` in `workers[]`: `workerId`, `agent`, `usage.durationMs`. Read defensively — `usage` (and `leadUsage`) may be:
|
|
373
|
+
- a normal `usage_block` with `durationMs >= 0`,
|
|
374
|
+
- a `na_block` with `{"source": "unavailable", "durationMs": 0, "note": ...}` when Phase 7 collection failed,
|
|
375
|
+
- missing entirely (older team-state files), or `None`.
|
|
376
|
+
Normalize via `(block or {}).get("durationMs", 0) or 0`, and treat `source == "unavailable"` as zero contribution.
|
|
377
|
+
3. If the team-state file is missing, or every `durationMs` for the run is `0`/absent, record the run under `unavailable` with its `runTimestamp` and `taskType`.
|
|
378
|
+
|
|
379
|
+
### time.3 — Aggregate
|
|
380
|
+
|
|
381
|
+
**A. Per task-type summary:**
|
|
382
|
+
|
|
383
|
+
| Column | Computation |
|
|
384
|
+
|--------|-------------|
|
|
385
|
+
| `Runs` | count of runs of that task type that contributed any duration |
|
|
386
|
+
| `CPU sum` | sum of (lead + all workers) across those runs |
|
|
387
|
+
| `Lead` | sum of `leadUsage.durationMs` |
|
|
388
|
+
| `Workers` | sum of all `workers[].usage.durationMs` |
|
|
389
|
+
|
|
390
|
+
Add a final `Grand total` row.
|
|
391
|
+
|
|
392
|
+
**Note on `CPU sum` vs wall-clock:** workers run as children of the lead session, so the lead's `durationMs` window OVERLAPS its workers' windows. `CPU sum = Lead + Workers` is an additive CPU-style sum, not the wall-clock elapsed time the user actually waited.
|
|
393
|
+
|
|
394
|
+
Worked example for one run with three concurrent workers:
|
|
395
|
+
|
|
396
|
+
```
|
|
397
|
+
lead [================================] durationMs = 1800000 (30:00)
|
|
398
|
+
claude [============] durationMs = 720000 (12:00)
|
|
399
|
+
codex [==============] durationMs = 840000 (14:00)
|
|
400
|
+
gemini [========] durationMs = 480000 (08:00)
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
- `CPU sum` for the run = `1800000 + 720000 + 840000 + 480000` = `3840000` (`01:04:00`)
|
|
404
|
+
- Wall-clock for the run = `max(endedAt) − min(startedAt)` ≈ `30:00`
|
|
405
|
+
|
|
406
|
+
Always report `CPU sum` in the by-task-type table. If the user explicitly asks for wall-clock, compute it per run as `max(leadUsage.endedAt, max(workers[].usage.endedAt)) − min(leadUsage.startedAt, min(workers[].usage.startedAt))` and surface it separately — never silently substitute.
|
|
407
|
+
|
|
408
|
+
**B. Per worker breakdown (per task type):**
|
|
409
|
+
|
|
410
|
+
For each task type, list one row per `workerId` actually present, plus `lead`. Aggregate `durationMs` across all runs of that task type.
|
|
411
|
+
|
|
412
|
+
| Worker | Runs | Total | Avg/run |
|
|
413
|
+
|--------|------|-------|---------|
|
|
414
|
+
|
|
415
|
+
- `Runs` denominator = number of runs of this task type in which this worker recorded a **nonzero** `durationMs`. A run where the worker's block was `na_block`, missing, or `0` does NOT count.
|
|
416
|
+
- If `Runs == 0` for a worker, **omit the row entirely** rather than dividing by zero.
|
|
417
|
+
- `Avg/run = Total / Runs` (integer ms, then format to `HH:MM:SS`).
|
|
418
|
+
|
|
419
|
+
Use the `workerId` from team-state. Valid enum: `lead, claude, codex, gemini, report-writer`.
|
|
420
|
+
|
|
421
|
+
Display rule for `workerId` vs `agent`:
|
|
422
|
+
- If every run of this task type used `agent == workerId` for this row, display the bare `workerId`.
|
|
423
|
+
- If `agent` differs (e.g. a `claude` worker slot ran with `agent == "sonnet-eval"`), display `workerId (agent)`. Multiple distinct agents across runs → comma-join: `claude (sonnet-eval, opus-eval)`.
|
|
424
|
+
|
|
425
|
+
Never write `claude (claude)` — the parenthesized agent is shown only when it adds information.
|
|
426
|
+
|
|
427
|
+
**Timestamp parsing:** for `startedAt` / `endedAt`, normalize ISO-8601: replace trailing `Z` with `+00:00`, accept explicit offsets as-is, parse via `datetime.fromisoformat(s.replace("Z", "+00:00"))`. Strings without an offset are assumed UTC. Mixed-form comparisons must be done as `datetime` objects, never raw strings.
|
|
428
|
+
|
|
429
|
+
### time.4 — Format output
|
|
430
|
+
|
|
431
|
+
- Convert `durationMs` to `HH:MM:SS` (zero-pad). Example: `7384000ms` → `02:03:04`.
|
|
432
|
+
- Sort task types by order of first appearance in the timeline (chronological, not alphabetical).
|
|
433
|
+
- If any runs were `unavailable`, append a final note listing them with reason.
|
|
434
|
+
|
|
435
|
+
```markdown
|
|
436
|
+
## Time summary — <task-key>
|
|
437
|
+
|
|
438
|
+
### By task type
|
|
439
|
+
|
|
440
|
+
| Task type | Runs | CPU sum | Lead | Workers |
|
|
441
|
+
|------------------------|------|-----------|----------|----------|
|
|
442
|
+
| requirements-discovery | 2 | 00:33:12 | 00:12:08 | 00:21:04 |
|
|
443
|
+
| error-analysis | 1 | 00:18:45 | 00:08:11 | 00:10:34 |
|
|
444
|
+
| implementation | 3 | 02:11:09 | 00:45:30 | 01:25:39 |
|
|
445
|
+
| **Grand total** | 6 | **03:03:06** | 01:05:49 | 01:57:17 |
|
|
446
|
+
|
|
447
|
+
`CPU sum` adds the lead window to each worker window even though they overlap; it is not a wall-clock total.
|
|
448
|
+
|
|
449
|
+
### Per worker — requirements-discovery
|
|
450
|
+
|
|
451
|
+
| Worker | Runs | Total | Avg/run |
|
|
452
|
+
|----------------|------|----------|----------|
|
|
453
|
+
| lead | 2 | 00:12:08 | 00:06:04 |
|
|
454
|
+
| claude | 2 | 00:09:12 | 00:04:36 |
|
|
455
|
+
| codex | 2 | 00:07:40 | 00:03:50 |
|
|
456
|
+
| gemini | 2 | 00:03:12 | 00:01:36 |
|
|
457
|
+
| report-writer | 2 | 00:01:00 | 00:00:30 |
|
|
458
|
+
|
|
459
|
+
> Unavailable: 1 run (implementation / 2026-04-30_03-03-48) — team-state has no durationMs (Phase 7 not reached)
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
**Rules:**
|
|
463
|
+
- Always render durations as `HH:MM:SS`; never raw milliseconds.
|
|
464
|
+
- Never invent or estimate `durationMs`. Missing → `--`.
|
|
465
|
+
- Never sum across `unavailable` runs into the totals — those are reported only in the trailing note.
|
|
466
|
+
- Show the resolved `<task-key>` in the heading so the user can confirm disambiguation.
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
## logs
|
|
471
|
+
|
|
472
|
+
Trigger phrases: "okstra logs", "로그 현황", "로그 파일", "log files", "log size", "log status", "로그 정리", "log cleanup".
|
|
473
|
+
|
|
474
|
+
Read-only inventory of codex/gemini wrapper 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.
|
|
475
|
+
|
|
476
|
+
**Background:** codex/gemini wrappers (`okstra-codex-exec.sh`, `okstra-gemini-exec.sh`) write a sidecar log next to each prompt history file:
|
|
477
|
+
|
|
478
|
+
```
|
|
479
|
+
.project-docs/okstra/tasks/<task-group>/<task-id>/runs/<phase>/prompts/
|
|
480
|
+
<worker>-prompt-<phase>-<seq>.md <-- prompt (git-tracked)
|
|
481
|
+
<worker>-prompt-<phase>-<seq>.log <-- live stdout+stderr mirror
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
The log is truncated at each dispatch (`: > "$log_path"`) — only the latest run for a given seq is preserved. Different seqs keep separate files. Long-running implementation dispatches can produce multi-MB logs; analysis-phase dispatches are typically smaller.
|
|
485
|
+
|
|
486
|
+
### logs.1 — Inventory
|
|
487
|
+
|
|
488
|
+
Construct the logs root by appending `/.project-docs/okstra/tasks` to the literal `projectRoot` value parsed in Step 0; paste as a literal absolute path in place of `<LOGS_ROOT>` below (no shell variables, no `$(...)`):
|
|
489
|
+
|
|
490
|
+
```bash
|
|
491
|
+
find <LOGS_ROOT> -type f -path '*/runs/*/prompts/*.log' \
|
|
492
|
+
-printf '%s\t%T@\t%p\n' 2>/dev/null \
|
|
493
|
+
| sort -k1,1nr
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
Columns: `size_bytes | mtime_epoch | path`.
|
|
497
|
+
|
|
498
|
+
On macOS, `find -printf` is unavailable. Fall back to `-exec stat`:
|
|
499
|
+
|
|
500
|
+
```bash
|
|
501
|
+
find <LOGS_ROOT> -type f -path '*/runs/*/prompts/*.log' -exec stat -f '%z%t%m%t%N' {} + 2>/dev/null | sort -k1,1nr
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
If empty, report `No wrapper log files found under <projectRoot>` and exit.
|
|
505
|
+
|
|
506
|
+
### logs.2 — Summary tables
|
|
507
|
+
|
|
508
|
+
**Table A — Top 20 largest logs:**
|
|
509
|
+
|
|
510
|
+
| # | Task | Phase | Worker | Seq | Size | Age | Path |
|
|
511
|
+
|---|------|-------|--------|-----|------|-----|------|
|
|
512
|
+
|
|
513
|
+
Parse fields from the path: task-group / task-id from the `tasks/<task-group>/<task-id>/` segment; phase from `runs/<phase>/`; worker from filename prefix before `-prompt-`; seq from filename suffix (last 3-digit segment). Format sizes as KB/MB. Format age as `Nd` (days) or `Nh` (hours) from `mtime` relative to "now".
|
|
514
|
+
|
|
515
|
+
**Table B — Per-task totals:**
|
|
516
|
+
|
|
517
|
+
| Task Key | Files | Total Size | Oldest | Newest |
|
|
518
|
+
|----------|-------|-----------:|--------|--------|
|
|
519
|
+
|
|
520
|
+
Sort by total size desc. "Task Key" = `<project-id>:<task-group>:<task-id>` for consistency with other sub-commands.
|
|
521
|
+
|
|
522
|
+
**Footer:** `Total: N files, X.X MB across M tasks under <PROJECT_ROOT>`.
|
|
523
|
+
|
|
524
|
+
### logs.3 — Suggested cleanup commands
|
|
525
|
+
|
|
526
|
+
Emit a fenced bash block the user can copy-paste. Do NOT execute. Each block pairs a dry-run preview (`-print`) with the destructive (`-delete`) command:
|
|
527
|
+
|
|
528
|
+
```markdown
|
|
529
|
+
## Cleanup options (manual)
|
|
530
|
+
|
|
531
|
+
# 7일 이상 된 로그만 삭제
|
|
532
|
+
find <PROJECT_ROOT>/.project-docs/okstra/tasks \
|
|
533
|
+
-type f -path '*/runs/*/prompts/*.log' -mtime +7 -print # dry-run
|
|
534
|
+
find <PROJECT_ROOT>/.project-docs/okstra/tasks \
|
|
535
|
+
-type f -path '*/runs/*/prompts/*.log' -mtime +7 -delete
|
|
536
|
+
|
|
537
|
+
# 30일 이상 된 로그만 삭제
|
|
538
|
+
find <PROJECT_ROOT>/.project-docs/okstra/tasks \
|
|
539
|
+
-type f -path '*/runs/*/prompts/*.log' -mtime +30 -print # dry-run
|
|
540
|
+
find <PROJECT_ROOT>/.project-docs/okstra/tasks \
|
|
541
|
+
-type f -path '*/runs/*/prompts/*.log' -mtime +30 -delete
|
|
542
|
+
|
|
543
|
+
# 특정 task-group 의 로그 일괄 삭제 (예: dev-9388)
|
|
544
|
+
find <PROJECT_ROOT>/.project-docs/okstra/tasks/dev-9388 \
|
|
545
|
+
-type f -name '*.log' -print # dry-run
|
|
546
|
+
find <PROJECT_ROOT>/.project-docs/okstra/tasks/dev-9388 \
|
|
547
|
+
-type f -name '*.log' -delete
|
|
548
|
+
|
|
549
|
+
# 특정 task-id 의 로그 일괄 삭제 (예: dev-9428)
|
|
550
|
+
find <PROJECT_ROOT>/.project-docs/okstra/tasks/*/dev-9428 \
|
|
551
|
+
-type f -name '*.log' -print # dry-run
|
|
552
|
+
find <PROJECT_ROOT>/.project-docs/okstra/tasks/*/dev-9428 \
|
|
553
|
+
-type f -name '*.log' -delete
|
|
554
|
+
|
|
555
|
+
# 전체 일괄 삭제 (주의)
|
|
556
|
+
find <PROJECT_ROOT>/.project-docs/okstra/tasks \
|
|
557
|
+
-type f -path '*/runs/*/prompts/*.log' -print # dry-run
|
|
558
|
+
find <PROJECT_ROOT>/.project-docs/okstra/tasks \
|
|
559
|
+
-type f -path '*/runs/*/prompts/*.log' -delete
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
Substitute the literal `<PROJECT_ROOT>` with the resolved absolute path so the commands are directly copy-pasteable.
|
|
563
|
+
|
|
564
|
+
### logs.4 — Notes for the user
|
|
565
|
+
|
|
566
|
+
- Logs are truncated on each re-dispatch of the same `seq`, so deleting an in-flight run's log will cause the wrapper to recreate an empty file on the next dispatch — no data loss beyond the current trace.
|
|
567
|
+
- **If a dispatch is currently running, check the `status` sub-command first** and avoid deleting logs for tasks in `in-progress` state — you will lose the live trace for the active run.
|
|
568
|
+
- Prompt history files (`.md`) are separate and are NOT touched by these commands — only `.log` sidecars.
|
|
569
|
+
- This sub-command **does not modify any external files itself**, including `.gitignore`. If the project commits `.project-docs/okstra/`, the user may want to add `.project-docs/okstra/tasks/**/runs/**/prompts/*.log` to `.gitignore` manually to keep large logs out of git.
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
573
|
+
## Output Rules (shared)
|
|
574
|
+
|
|
575
|
+
- Responses should be concise and written in Korean unless the user requests otherwise.
|
|
576
|
+
- Use project-relative paths whenever possible.
|
|
577
|
+
- If there is no recent report, display `--`.
|
|
578
|
+
- If a specific task does not exist, explicitly state that it cannot be found based on `task-catalog.json`.
|
|
579
|
+
- If `awaitingApproval` is true, clearly indicate that the task is awaiting user approval.
|
|
580
|
+
- Display status fields as-is from disk (`completed`, `contract-violated`, `todo`, `error`, empty, ...). Do not normalize or remap.
|
|
581
|
+
- Dates in `YYYY-MM-DD HH:MM` format.
|
|
@@ -18,9 +18,9 @@ Launch an okstra task — gather inputs interactively via the **wizard state mac
|
|
|
18
18
|
|
|
19
19
|
## When NOT to Use
|
|
20
20
|
|
|
21
|
-
- User explicitly asks to spawn a new terminal / new claude — use `okstra-history`
|
|
22
|
-
- User wants status only — use `okstra-status`.
|
|
23
|
-
- User wants past runs — use `okstra-history`.
|
|
21
|
+
- User explicitly asks to spawn a new terminal / new claude — use `okstra-inspect history.4` (resume command) or instruct them to run `okstra` in another terminal.
|
|
22
|
+
- User wants status only — use `okstra-inspect status`.
|
|
23
|
+
- User wants past runs — use `okstra-inspect history`.
|
|
24
24
|
|
|
25
25
|
## How the wizard talks to you
|
|
26
26
|
|