okstra 0.36.0 → 0.36.1
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/run.py +7 -1
- package/runtime/python/okstra_ctl/session.py +65 -7
- 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
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: okstra-time-summary
|
|
3
|
-
description: Use when the user asks how long an okstra task took, time spent per task type, per-worker elapsed time, or for a duration/runtime breakdown of a specific task-id. Trigger words include "작업 시간", "소요 시간", "time summary", "duration", "elapsed", "얼마나 걸렸", "시간 분석".
|
|
4
|
-
user-invocable: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# OKSTRA Time Summary
|
|
8
|
-
|
|
9
|
-
Aggregate elapsed work time for a given task, grouped by **task type** and broken down by **worker** (lead, claude, codex, gemini, report-writer).
|
|
10
|
-
|
|
11
|
-
## When to Use
|
|
12
|
-
|
|
13
|
-
- The user provides a `task-id` (or `task-key`) and asks how long the task took.
|
|
14
|
-
- The user wants to see time spent per phase / task type for a single task.
|
|
15
|
-
- The user wants a per-worker time breakdown for a task's runs.
|
|
16
|
-
|
|
17
|
-
## Data Sources
|
|
18
|
-
|
|
19
|
-
Two sources, both already collected by `okstra`:
|
|
20
|
-
|
|
21
|
-
1. `.project-docs/okstra/tasks/<task-group>/<task-id>/history/timeline.json`
|
|
22
|
-
— lists every run with `runTimestamp`, `taskType`, `status`, `teamStatePath`, and `taskRootPath`. Both path fields may be either project-root-relative or task-root-relative depending on which version of `render.py` wrote the manifest.
|
|
23
|
-
2. Each run's `.../runs/<task-type>/state/team-state-<suffix>.json`
|
|
24
|
-
— populated by `scripts/okstra-token-usage.py` at Phase 7. Contains:
|
|
25
|
-
- `leadUsage.{startedAt, endedAt, durationMs}`
|
|
26
|
-
- `workers[].{workerId, agent, usage.{startedAt, endedAt, durationMs}}`
|
|
27
|
-
|
|
28
|
-
If a run never reached Phase 7, its `team-state` will not have `durationMs` filled in. Mark such runs as `unavailable` rather than guessing.
|
|
29
|
-
|
|
30
|
-
## Step 0: Verify okstra runtime + project setup
|
|
31
|
-
|
|
32
|
-
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.
|
|
33
|
-
|
|
34
|
-
1. `okstra ensure-installed`
|
|
35
|
-
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.
|
|
36
|
-
|
|
37
|
-
2. `okstra check-project --json`
|
|
38
|
-
Reads the project from the current working directory. Parse the JSON from stdout. The shape is `{ok, projectRoot, projectJsonPath, projectId}`.
|
|
39
|
-
|
|
40
|
-
- `ok: false` → tell the user: "this project has no okstra setup. Run `/okstra-setup` first." Then stop.
|
|
41
|
-
- `ok: true` → carry `projectRoot` as a literal string and use it to locate `.project-docs/okstra/discovery/task-catalog.json`.
|
|
42
|
-
|
|
43
|
-
Subsequent `okstra <subcmd>` calls self-bootstrap their Python path, so this skill never needs `okstra paths --shell` / `export PYTHONPATH=...`.
|
|
44
|
-
|
|
45
|
-
## Step 1: Resolve task-id → timeline path
|
|
46
|
-
|
|
47
|
-
1. If the user gave a full `task-key` (`<project-id>:<task-group>:<task-id>`), use it directly.
|
|
48
|
-
2. Otherwise read `.project-docs/okstra/discovery/task-catalog.json` and find the entry whose `taskId` matches.
|
|
49
|
-
3. If multiple entries match, list candidates (`taskKey`, `taskType`, `updatedAt`) and ask the user to pick.
|
|
50
|
-
4. From the chosen entry, read `historyTimelinePath`.
|
|
51
|
-
|
|
52
|
-
If `task-catalog.json` is missing, respond: "No okstra history found. Run `scripts/okstra.sh` first."
|
|
53
|
-
|
|
54
|
-
## Step 2: Walk runs and collect durations
|
|
55
|
-
|
|
56
|
-
For each entry in `timeline.json`'s `runs` array:
|
|
57
|
-
|
|
58
|
-
1. Resolve the `team-state` file using a two-step lookup:
|
|
59
|
-
a. First try `<projectRoot>/<teamStatePath>`.
|
|
60
|
-
b. If that file does not exist, fall back to `<projectRoot>/<taskRootPath>/<teamStatePath>` (the manifest's `taskRootPath` field is the task-root relative to project root; `teamStatePath` written by `render.py` is task-root-relative in many runs).
|
|
61
|
-
Either path satisfies the lookup. If neither resolves to an existing file, treat the run as `unavailable`.
|
|
62
|
-
2. Extract:
|
|
63
|
-
- `taskType` from the timeline entry (authoritative).
|
|
64
|
-
- `leadUsage.durationMs` and `leadUsage.{startedAt,endedAt}`.
|
|
65
|
-
- For each `worker` in `workers[]`: `workerId`, `agent`, `usage.durationMs`.
|
|
66
|
-
Read defensively. `usage` (and `leadUsage`) may be:
|
|
67
|
-
- a normal `usage_block` with `durationMs >= 0`,
|
|
68
|
-
- a `na_block` with `{"source": "unavailable", "durationMs": 0, "note": ...}` when Phase 7 collection failed,
|
|
69
|
-
- missing entirely (older team-state files), or `None`.
|
|
70
|
-
Always normalize via `(block or {}).get("durationMs", 0) or 0`, and treat a `source == "unavailable"` block as zero contribution.
|
|
71
|
-
3. If the team-state file is missing, or every `durationMs` for the run is `0`/absent (i.e. `leadUsage` and every `workers[].usage` are zero or unavailable), record the run under `unavailable` with its `runTimestamp` and `taskType`.
|
|
72
|
-
|
|
73
|
-
## Step 3: Aggregate
|
|
74
|
-
|
|
75
|
-
Build two tables:
|
|
76
|
-
|
|
77
|
-
### A. Per task-type summary
|
|
78
|
-
|
|
79
|
-
For each distinct `taskType` across runs:
|
|
80
|
-
|
|
81
|
-
| Column | Computation |
|
|
82
|
-
|--------|-------------|
|
|
83
|
-
| `Runs` | count of runs of that task type that contributed any duration |
|
|
84
|
-
| `CPU sum` | sum of (lead + all workers) across those runs — see note below |
|
|
85
|
-
| `Lead` | sum of `leadUsage.durationMs` |
|
|
86
|
-
| `Workers` | sum of all `workers[].usage.durationMs` |
|
|
87
|
-
|
|
88
|
-
Add a final `Grand total` row.
|
|
89
|
-
|
|
90
|
-
**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 therefore an additive CPU-style sum, not the wall-clock elapsed time the user actually waited.
|
|
91
|
-
|
|
92
|
-
Worked example for one run with three concurrent workers:
|
|
93
|
-
|
|
94
|
-
```
|
|
95
|
-
lead [================================] durationMs = 1800000 (30:00)
|
|
96
|
-
claude [============] durationMs = 720000 (12:00)
|
|
97
|
-
codex [==============] durationMs = 840000 (14:00)
|
|
98
|
-
gemini [========] durationMs = 480000 (08:00)
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
- `CPU sum` for the run = `1800000 + 720000 + 840000 + 480000` = `3840000` (`01:04:00`)
|
|
102
|
-
- Wall-clock for the run = `max(endedAt) − min(startedAt)` ≈ `30:00`
|
|
103
|
-
|
|
104
|
-
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 it for `CPU sum`.
|
|
105
|
-
|
|
106
|
-
### B. Per worker breakdown (per task type)
|
|
107
|
-
|
|
108
|
-
For each task type, list one row per `workerId` actually present, plus `lead`. Aggregate `durationMs` across all runs of that task type.
|
|
109
|
-
|
|
110
|
-
| Worker | Runs | Total | Avg/run |
|
|
111
|
-
|--------|------|-------|---------|
|
|
112
|
-
|
|
113
|
-
- `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.
|
|
114
|
-
- If `Runs == 0` for a worker, **omit the row entirely** rather than dividing by zero.
|
|
115
|
-
- `Avg/run = Total / Runs` (integer ms, then format to `HH:MM:SS`).
|
|
116
|
-
|
|
117
|
-
Use the `workerId` from team-state. The valid worker enum is `lead, claude, codex, gemini, report-writer`.
|
|
118
|
-
|
|
119
|
-
Display rule for `workerId` vs `agent`:
|
|
120
|
-
- If every run of this task type used `agent == workerId` for this row, display the bare `workerId` (e.g. `claude`).
|
|
121
|
-
- If `agent` differs from `workerId` (e.g. a `claude` worker slot ran with `agent == "sonnet-eval"`), display `workerId (agent)` — and if multiple distinct agents were used across runs, comma-join them: `claude (sonnet-eval, opus-eval)`.
|
|
122
|
-
|
|
123
|
-
Never write `claude (claude)` — the parenthesized agent is shown only when it adds information.
|
|
124
|
-
|
|
125
|
-
### Timestamp parsing
|
|
126
|
-
|
|
127
|
-
When you need `startedAt` / `endedAt` (e.g. for wall-clock or chronological sort within a task type), normalize the ISO-8601 string before comparing: replace a trailing `Z` with `+00:00`, accept explicit offsets as-is, and 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 as raw strings.
|
|
128
|
-
|
|
129
|
-
## Step 4: Format output
|
|
130
|
-
|
|
131
|
-
- Convert `durationMs` to `HH:MM:SS` (zero-pad). Example: `7384000ms` → `02:03:04`.
|
|
132
|
-
- Sort task types by their order of first appearance in the timeline (chronological, not alphabetical).
|
|
133
|
-
- If any runs were `unavailable`, append a final note listing them with reason (`team-state missing`, `Phase 7 not reached`, etc.).
|
|
134
|
-
|
|
135
|
-
### Output template
|
|
136
|
-
|
|
137
|
-
```markdown
|
|
138
|
-
## Time summary — <task-key>
|
|
139
|
-
|
|
140
|
-
### By task type
|
|
141
|
-
|
|
142
|
-
| Task type | Runs | CPU sum | Lead | Workers |
|
|
143
|
-
|------------------------|------|-----------|----------|----------|
|
|
144
|
-
| requirements-discovery | 2 | 00:33:12 | 00:12:08 | 00:21:04 |
|
|
145
|
-
| error-analysis | 1 | 00:18:45 | 00:08:11 | 00:10:34 |
|
|
146
|
-
| implementation | 3 | 02:11:09 | 00:45:30 | 01:25:39 |
|
|
147
|
-
| **Grand total** | 6 | **03:03:06** | 01:05:49 | 01:57:17 |
|
|
148
|
-
|
|
149
|
-
`CPU sum` adds the lead window to each worker window even though they overlap; it is not a wall-clock total.
|
|
150
|
-
|
|
151
|
-
### Per worker — requirements-discovery
|
|
152
|
-
|
|
153
|
-
| Worker | Runs | Total | Avg/run |
|
|
154
|
-
|----------------|------|----------|----------|
|
|
155
|
-
| lead | 2 | 00:12:08 | 00:06:04 |
|
|
156
|
-
| claude | 2 | 00:09:12 | 00:04:36 |
|
|
157
|
-
| codex | 2 | 00:07:40 | 00:03:50 |
|
|
158
|
-
| gemini | 2 | 00:03:12 | 00:01:36 |
|
|
159
|
-
| report-writer | 2 | 00:01:00 | 00:00:30 |
|
|
160
|
-
|
|
161
|
-
### Per worker — error-analysis
|
|
162
|
-
...
|
|
163
|
-
|
|
164
|
-
> Unavailable: 1 run (implementation / 2026-04-30_03-03-48) — team-state has no durationMs (Phase 7 not reached)
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
## Output Rules
|
|
168
|
-
|
|
169
|
-
- Always render durations as `HH:MM:SS`; never raw milliseconds.
|
|
170
|
-
- Never invent or estimate `durationMs`. Missing → `--`.
|
|
171
|
-
- Never sum across `unavailable` runs into the totals — those are reported only in the trailing note.
|
|
172
|
-
- Show the resolved `<task-key>` in the heading so the user can confirm disambiguation.
|