okstra 0.36.2 → 0.37.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.kr.md +6 -6
- package/README.md +6 -6
- package/bin/okstra +4 -2
- package/docs/kr/architecture.md +29 -29
- package/docs/kr/cli.md +7 -6
- package/docs/pr-template-usage.md +2 -2
- package/docs/project-structure-overview.md +4 -4
- package/docs/superpowers/plans/2026-05-25-okstra-project-root-rename.md +159 -0
- package/docs/superpowers/plans/2026-05-26-wizard-3-option-picker.md +860 -0
- package/docs/task-process/common-flow.md +2 -2
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/SKILL.md +2 -2
- package/runtime/agents/workers/claude-worker.md +1 -1
- package/runtime/prompts/profiles/_common-contract.md +6 -6
- package/runtime/prompts/profiles/_implementation-executor.md +2 -2
- package/runtime/prompts/profiles/_implementation-verifier.md +1 -1
- package/runtime/prompts/profiles/final-verification.md +1 -1
- package/runtime/prompts/profiles/implementation-planning.md +5 -5
- package/runtime/prompts/profiles/release-handoff.md +1 -1
- package/runtime/prompts/profiles/requirements-discovery.md +3 -3
- package/runtime/prompts/wizard/prompts.ko.json +80 -6
- package/runtime/python/lib/okstra/interactive.sh +2 -2
- package/runtime/python/lib/okstra/project-resolver.sh +1 -1
- package/runtime/python/lib/okstra/usage.sh +5 -5
- package/runtime/python/lib/okstra-ctl/cmd-rerun.sh +1 -1
- package/runtime/python/okstra_ctl/backfill.py +5 -3
- package/runtime/python/okstra_ctl/migrate.py +408 -0
- package/runtime/python/okstra_ctl/paths.py +12 -3
- package/runtime/python/okstra_ctl/pr_template.py +4 -2
- package/runtime/python/okstra_ctl/render.py +8 -6
- package/runtime/python/okstra_ctl/run.py +5 -5
- package/runtime/python/okstra_ctl/seeding.py +12 -6
- package/runtime/python/okstra_ctl/sequence.py +3 -1
- package/runtime/python/okstra_ctl/wizard.py +412 -77
- package/runtime/python/okstra_ctl/worktree.py +8 -6
- package/runtime/python/okstra_project/__init__.py +35 -5
- package/runtime/python/okstra_project/dirs.py +67 -0
- package/runtime/python/okstra_project/resolver.py +8 -8
- package/runtime/python/okstra_project/state.py +11 -9
- package/runtime/python/okstra_token_usage/collect.py +3 -1
- package/runtime/skills/okstra-brief/SKILL.md +30 -30
- package/runtime/skills/okstra-context-loader/SKILL.md +7 -7
- package/runtime/skills/okstra-inspect/SKILL.md +25 -25
- package/runtime/skills/okstra-run/templates/pr-body.template.md +1 -1
- package/runtime/skills/okstra-schedule/SKILL.md +7 -7
- package/runtime/skills/okstra-setup/SKILL.md +8 -8
- package/runtime/templates/okstra.CLAUDE.md +4 -4
- package/runtime/templates/reports/brief.template.md +5 -5
- package/runtime/templates/reports/task-brief.template.md +1 -1
- package/runtime/validators/lib/fixtures.sh +2 -2
- package/runtime/validators/lib/paths.sh +9 -3
- package/runtime/validators/validate-brief.py +2 -2
- package/runtime/validators/validate-brief.sh +1 -1
- package/runtime/validators/validate-run.py +3 -1
- package/runtime/validators/validate-workflow.sh +2 -2
- package/src/check-project.mjs +3 -3
- package/src/config.mjs +6 -5
- package/src/install.mjs +5 -5
- package/src/migrate.mjs +163 -0
- package/src/okstra-dirs.mjs +37 -0
- package/src/paths.mjs +17 -0
- package/src/setup.mjs +8 -4
- package/src/uninstall.mjs +3 -3
|
@@ -45,7 +45,7 @@ Trigger phrases: "okstra status", "task status", "current phase", "next phase",
|
|
|
45
45
|
|
|
46
46
|
### status.1 — Overall project status
|
|
47
47
|
|
|
48
|
-
Read `.
|
|
48
|
+
Read `.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
49
|
|
|
50
50
|
| Field | Description |
|
|
51
51
|
|------|------|
|
|
@@ -86,7 +86,7 @@ If `awaitingApproval` is true OR `routingStatus == "pending"`, append a `*` to t
|
|
|
86
86
|
Given a specific `task-key` or `task-group + task-id`:
|
|
87
87
|
|
|
88
88
|
1. If possible, quickly look it up in `task-catalog.json`.
|
|
89
|
-
2. If necessary, read `.
|
|
89
|
+
2. If necessary, read `.okstra/tasks/<task-group>/<task-id>/task-manifest.json` directly.
|
|
90
90
|
3. If you need the latest run information, read `history/timeline.json` along with the latest run manifest.
|
|
91
91
|
|
|
92
92
|
Required fields: `taskKey`, `taskType`, `workCategory`, `currentStatus`, `latestRunStatus`, `workflow.{currentPhase, currentPhaseState, phaseStates, lastCompletedPhase, nextRecommendedPhase, awaitingApproval, routingStatus, lastSafeCheckpoint}`, `workStatus`, `workStatusUpdatedAt`, `workStatusNote`, `latestReportPath`, `latestResumeCommandPath`, `historyTimelinePath`.
|
|
@@ -155,10 +155,10 @@ Accepted `<status>` values: `todo`, `in-progress`, `blocked`, `done`.
|
|
|
155
155
|
**Procedure:**
|
|
156
156
|
|
|
157
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 `.
|
|
158
|
+
2. **Look up the task** in `.okstra/discovery/task-catalog.json` by `task-id` (case-insensitive on both `task-id` and `task-group`).
|
|
159
159
|
- If the user provided `<task-group>` explicitly, scope the lookup to that group (case-insensitive).
|
|
160
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 `.
|
|
161
|
+
3. **Open the matching `task-manifest.json`** at `.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
162
|
4. **Update fields at the manifest root:**
|
|
163
163
|
- `workStatus` ← new status value
|
|
164
164
|
- `workStatusUpdatedAt` ← current ISO-8601 UTC timestamp (`2026-05-01T10:23:45Z`)
|
|
@@ -199,7 +199,7 @@ Trigger phrases: "okstra history", "past runs", "run history", "re-run", "list t
|
|
|
199
199
|
|
|
200
200
|
### history.1 — Read the task catalog
|
|
201
201
|
|
|
202
|
-
1. Read `.
|
|
202
|
+
1. Read `.okstra/discovery/task-catalog.json`.
|
|
203
203
|
2. Apply filters from user input (all optional, AND-combined):
|
|
204
204
|
- `--task-type <type>` → keep entries whose `taskType` matches.
|
|
205
205
|
- `--latest-run-status <status>` → keep entries whose `latestRunStatus` matches (`completed`, `contract-violated`, `error`).
|
|
@@ -219,7 +219,7 @@ Trigger phrases: "okstra history", "past runs", "run history", "re-run", "list t
|
|
|
219
219
|
|
|
220
220
|
**Catalog absent — fallback.** Do NOT bail out. Manifests on disk are the source of truth.
|
|
221
221
|
|
|
222
|
-
1. Glob `<projectRoot>/.
|
|
222
|
+
1. Glob `<projectRoot>/.okstra/tasks/*/*/task-manifest.json`.
|
|
223
223
|
2. For each manifest, read the same fields as above.
|
|
224
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
225
|
4. Only if the glob yields zero manifests: `There is no okstra execution history yet.`
|
|
@@ -292,13 +292,13 @@ task-key format: `<project-id>:<task-group>:<task-id>`.
|
|
|
292
292
|
|
|
293
293
|
Lookup methods (in priority order):
|
|
294
294
|
|
|
295
|
-
A. **`task-catalog.json` (fast):** read `.
|
|
295
|
+
A. **`task-catalog.json` (fast):** read `.okstra/discovery/task-catalog.json`, match `taskKey` lowercase. `latestReportPath` is task-type-agnostic "most recent report".
|
|
296
296
|
|
|
297
|
-
B. **`task-manifest.json` (direct):** if catalog missing, slugify task-group / task-id, read `.
|
|
297
|
+
B. **`task-manifest.json` (direct):** if catalog missing, slugify task-group / task-id, read `.okstra/tasks/<group-segment>/<id-segment>/task-manifest.json`, use `latestReportPath` (task-type-agnostic).
|
|
298
298
|
|
|
299
|
-
C. **`timeline.json` (specific run):** for a specific date or run, read `.
|
|
299
|
+
C. **`timeline.json` (specific run):** for a specific date or run, read `.okstra/tasks/<group-segment>/<id-segment>/history/timeline.json`, filter `runs[]` by `runTimestamp` / `status` / `taskType`, use `runs[].reportPath`.
|
|
300
300
|
|
|
301
|
-
D. **Specific task-type (fallback):** `latestReportPath` is task-type-agnostic. For a specific task-type's latest report, look under `.
|
|
301
|
+
D. **Specific task-type (fallback):** `latestReportPath` is task-type-agnostic. For a specific task-type's latest report, look under `.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
302
|
|
|
303
303
|
### report.2 — Confirm existence
|
|
304
304
|
|
|
@@ -347,7 +347,7 @@ Aggregate elapsed work time for a given task, grouped by **task type** and broke
|
|
|
347
347
|
|
|
348
348
|
**Data sources** (both collected by okstra):
|
|
349
349
|
|
|
350
|
-
1. `.
|
|
350
|
+
1. `.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
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
352
|
|
|
353
353
|
If a run never reached Phase 7, its `team-state` lacks `durationMs`. Mark such runs as `unavailable` rather than guessing.
|
|
@@ -355,7 +355,7 @@ If a run never reached Phase 7, its `team-state` lacks `durationMs`. Mark such r
|
|
|
355
355
|
### time.1 — Resolve task-id → timeline path
|
|
356
356
|
|
|
357
357
|
1. If the user gave a full `task-key`, use it directly.
|
|
358
|
-
2. Otherwise read `.
|
|
358
|
+
2. Otherwise read `.okstra/discovery/task-catalog.json` and find the entry whose `taskId` matches.
|
|
359
359
|
3. Multiple matches → list candidates (`taskKey`, `taskType`, `updatedAt`) and ask the user to pick.
|
|
360
360
|
4. Read `historyTimelinePath` from the chosen entry.
|
|
361
361
|
|
|
@@ -476,7 +476,7 @@ Read-only inventory of codex/gemini wrapper log files written next to each promp
|
|
|
476
476
|
**Background:** codex/gemini wrappers (`okstra-codex-exec.sh`, `okstra-gemini-exec.sh`) write a sidecar log next to each prompt history file:
|
|
477
477
|
|
|
478
478
|
```
|
|
479
|
-
.
|
|
479
|
+
.okstra/tasks/<task-group>/<task-id>/runs/<phase>/prompts/
|
|
480
480
|
<worker>-prompt-<phase>-<seq>.md <-- prompt (git-tracked)
|
|
481
481
|
<worker>-prompt-<phase>-<seq>.log <-- live stdout+stderr mirror
|
|
482
482
|
```
|
|
@@ -485,7 +485,7 @@ The log is truncated at each dispatch (`: > "$log_path"`) — only the latest ru
|
|
|
485
485
|
|
|
486
486
|
### logs.1 — Inventory
|
|
487
487
|
|
|
488
|
-
Construct the logs root by appending `/.
|
|
488
|
+
Construct the logs root by appending `/.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
489
|
|
|
490
490
|
```bash
|
|
491
491
|
find <LOGS_ROOT> -type f -path '*/runs/*/prompts/*.log' \
|
|
@@ -529,33 +529,33 @@ Emit a fenced bash block the user can copy-paste. Do NOT execute. Each block pai
|
|
|
529
529
|
## Cleanup options (manual)
|
|
530
530
|
|
|
531
531
|
# 7일 이상 된 로그만 삭제
|
|
532
|
-
find <PROJECT_ROOT>/.
|
|
532
|
+
find <PROJECT_ROOT>/.okstra/tasks \
|
|
533
533
|
-type f -path '*/runs/*/prompts/*.log' -mtime +7 -print # dry-run
|
|
534
|
-
find <PROJECT_ROOT>/.
|
|
534
|
+
find <PROJECT_ROOT>/.okstra/tasks \
|
|
535
535
|
-type f -path '*/runs/*/prompts/*.log' -mtime +7 -delete
|
|
536
536
|
|
|
537
537
|
# 30일 이상 된 로그만 삭제
|
|
538
|
-
find <PROJECT_ROOT>/.
|
|
538
|
+
find <PROJECT_ROOT>/.okstra/tasks \
|
|
539
539
|
-type f -path '*/runs/*/prompts/*.log' -mtime +30 -print # dry-run
|
|
540
|
-
find <PROJECT_ROOT>/.
|
|
540
|
+
find <PROJECT_ROOT>/.okstra/tasks \
|
|
541
541
|
-type f -path '*/runs/*/prompts/*.log' -mtime +30 -delete
|
|
542
542
|
|
|
543
543
|
# 특정 task-group 의 로그 일괄 삭제 (예: dev-9388)
|
|
544
|
-
find <PROJECT_ROOT>/.
|
|
544
|
+
find <PROJECT_ROOT>/.okstra/tasks/dev-9388 \
|
|
545
545
|
-type f -name '*.log' -print # dry-run
|
|
546
|
-
find <PROJECT_ROOT>/.
|
|
546
|
+
find <PROJECT_ROOT>/.okstra/tasks/dev-9388 \
|
|
547
547
|
-type f -name '*.log' -delete
|
|
548
548
|
|
|
549
549
|
# 특정 task-id 의 로그 일괄 삭제 (예: dev-9428)
|
|
550
|
-
find <PROJECT_ROOT>/.
|
|
550
|
+
find <PROJECT_ROOT>/.okstra/tasks/*/dev-9428 \
|
|
551
551
|
-type f -name '*.log' -print # dry-run
|
|
552
|
-
find <PROJECT_ROOT>/.
|
|
552
|
+
find <PROJECT_ROOT>/.okstra/tasks/*/dev-9428 \
|
|
553
553
|
-type f -name '*.log' -delete
|
|
554
554
|
|
|
555
555
|
# 전체 일괄 삭제 (주의)
|
|
556
|
-
find <PROJECT_ROOT>/.
|
|
556
|
+
find <PROJECT_ROOT>/.okstra/tasks \
|
|
557
557
|
-type f -path '*/runs/*/prompts/*.log' -print # dry-run
|
|
558
|
-
find <PROJECT_ROOT>/.
|
|
558
|
+
find <PROJECT_ROOT>/.okstra/tasks \
|
|
559
559
|
-type f -path '*/runs/*/prompts/*.log' -delete
|
|
560
560
|
```
|
|
561
561
|
|
|
@@ -566,7 +566,7 @@ Substitute the literal `<PROJECT_ROOT>` with the resolved absolute path so the c
|
|
|
566
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
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
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 `.
|
|
569
|
+
- This sub-command **does not modify any external files itself**, including `.gitignore`. If the project commits `.okstra/`, the user may want to add `.okstra/tasks/**/runs/**/prompts/*.log` to `.gitignore` manually to keep large logs out of git.
|
|
570
570
|
|
|
571
571
|
---
|
|
572
572
|
|
|
@@ -3,7 +3,7 @@ okstra release-handoff 기본 PR 본문 템플릿.
|
|
|
3
3
|
|
|
4
4
|
이 파일은 사용자 정의 PR 템플릿이 없을 때 사용됩니다. 우선순위:
|
|
5
5
|
1. okstra-run Step 6 에서 입력한 per-run override 경로
|
|
6
|
-
2. <project-root>/.
|
|
6
|
+
2. <project-root>/.okstra/project.json 의 `prTemplatePath`
|
|
7
7
|
3. ~/.okstra/config.json 의 `prTemplatePath`
|
|
8
8
|
4. 이 디폴트 파일
|
|
9
9
|
|
|
@@ -8,7 +8,7 @@ model: opus
|
|
|
8
8
|
|
|
9
9
|
## Overview
|
|
10
10
|
|
|
11
|
-
Generate a consolidated work schedule for all non-done tasks in a given `task-group`. The skill reads each task's `task-manifest.json` and `latestReport`, classifies tasks into phases by priority and risk, and writes a single Markdown plan file under `.
|
|
11
|
+
Generate a consolidated work schedule for all non-done tasks in a given `task-group`. The skill reads each task's `task-manifest.json` and `latestReport`, classifies tasks into phases by priority and risk, and writes a single Markdown plan file under `.okstra/tasks/<task-group>/schedule/`.
|
|
12
12
|
|
|
13
13
|
The skill runs as a single Claude lead synthesis (lightweight mode). A `--cross-verify` multi-agent variant was previously sketched here but never specified end-to-end; it has been dropped pre-1.0 and is tracked as a follow-up if multi-agent schedule verification is needed later.
|
|
14
14
|
|
|
@@ -16,7 +16,7 @@ The skill runs as a single Claude lead synthesis (lightweight mode). A `--cross-
|
|
|
16
16
|
|
|
17
17
|
- User asks to generate a work schedule / plan / "일정" for an entire `task-group`
|
|
18
18
|
- User wants a single document that summarizes all non-done tasks with effort, risk, and dependencies
|
|
19
|
-
- A `task-group` exists in `.
|
|
19
|
+
- A `task-group` exists in `.okstra/discovery/task-catalog.json` with at least one task whose `workStatus` is not `done`
|
|
20
20
|
|
|
21
21
|
**Do NOT use** for single-task analysis (use `okstra-inspect status` instead) or when the user wants to actually execute one task (use the parent `okstra` skill).
|
|
22
22
|
|
|
@@ -46,7 +46,7 @@ Before anything else in this skill, run each of the following commands as a **se
|
|
|
46
46
|
Reads the project from the current working directory. Parse the JSON from stdout. The shape is `{ok, projectRoot, projectJsonPath, projectId}`.
|
|
47
47
|
|
|
48
48
|
- `ok: false` → tell the user: "this project has no okstra setup. Run `/okstra-setup` first." Then stop.
|
|
49
|
-
- `ok: true` → carry `projectRoot` as a literal string and use it to locate `.
|
|
49
|
+
- `ok: true` → carry `projectRoot` as a literal string and use it to locate `.okstra/discovery/task-catalog.json` and the task-group directory.
|
|
50
50
|
|
|
51
51
|
Subsequent `okstra <subcmd>` calls self-bootstrap their Python path, so this skill never needs `okstra paths --shell` / `export PYTHONPATH=...`.
|
|
52
52
|
|
|
@@ -68,10 +68,10 @@ This skill performs cross-task synthesis (multi-task classification, dependency
|
|
|
68
68
|
|
|
69
69
|
### Step 1: Resolve task-group and collect tasks
|
|
70
70
|
|
|
71
|
-
1. Read `.
|
|
71
|
+
1. Read `.okstra/discovery/task-catalog.json`.
|
|
72
72
|
2. **Normalise the user-supplied `<task-group>` argument:** lowercase it, then strip every character that is not `[a-z0-9]` (drop spaces, hyphens, underscores, dots, etc.). Apply the same transform to each entry's `taskGroupPathSegment`. Match when the two normalised forms are equal. This is the single comparison rule — do NOT also fall back to the raw `taskGroup` field.
|
|
73
73
|
3. If no tasks found, output `해당 task-group을 찾을 수 없습니다.` and stop.
|
|
74
|
-
4. For each matched task, read `.
|
|
74
|
+
4. For each matched task, read `.okstra/tasks/<task-group-segment>/<task-id-segment>/task-manifest.json` directly. Catalog data may be stale; the manifest is authoritative.
|
|
75
75
|
5. **Derive `<project-id>`** for the schedule header: prefer `task-catalog.json`'s top-level `projectId` field if present, otherwise use the first matched manifest's `projectId` field. Do not invent a value.
|
|
76
76
|
|
|
77
77
|
### Step 2: Filter by workStatus
|
|
@@ -157,7 +157,7 @@ When the classification is genuinely ambiguous after applying the table + priori
|
|
|
157
157
|
|
|
158
158
|
Output path:
|
|
159
159
|
```
|
|
160
|
-
.
|
|
160
|
+
.okstra/tasks/<task-group-segment>/schedule/<task-group-segment>-plan-<YYYY-MM-DD_HH-MM-SS>.md
|
|
161
161
|
```
|
|
162
162
|
|
|
163
163
|
- `<task-group-segment>`: from manifest's `taskGroupPathSegment` (lowercase, hyphenated).
|
|
@@ -322,7 +322,7 @@ Before applying the heuristics above, **check the schedule-level directive sourc
|
|
|
322
322
|
**Resolution order (first hit wins):**
|
|
323
323
|
|
|
324
324
|
1. Absolute path passed via the `--directive-file <abs-path>` argument when invoking the skill.
|
|
325
|
-
2. `<PROJECT_ROOT>/.
|
|
325
|
+
2. `<PROJECT_ROOT>/.okstra/tasks/<task-group-segment>/schedule/instruction-set/analysis-material.md` (the canonical schedule-level instruction-set location — okstra writes here when a schedule run is dispatched with `--directive`).
|
|
326
326
|
3. **No directive file** — fall through and apply the default heuristic without any override. This is the normal case; do not warn, do not block.
|
|
327
327
|
|
|
328
328
|
If a directive source is found and contains a `## Directive` section that affects Gantt rendering — e.g. "render a Gantt even with single XL task", "no Gantt needed" — that directive **overrides the heuristic and the skip-reason rule** for the affected section. When following a Directive override that contradicts the default heuristic, append a one-line note inside the rendered (or skipped) section: `> _Per Directive directive: <verbatim short excerpt>._` so the reader can trace why the section appeared/disappeared against the default. The Directive may also pre-supply day allocations, phase weights, or sub-task decompositions — use those verbatim as bar lengths in the Gantt.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: okstra-setup
|
|
3
|
-
description: One-time bootstrap for okstra in a new project or on a new machine — installs the okstra runtime via npx and creates the project's .
|
|
3
|
+
description: One-time bootstrap for okstra in a new project or on a new machine — installs the okstra runtime via npx and creates the project's .okstra/project.json. Trigger words include "okstra setup", "setup okstra", "initialize okstra", "okstra init", "first time okstra setup", "configure okstra here".
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# okstra-setup
|
|
@@ -11,7 +11,7 @@ machine, or when adopting okstra in a new project.
|
|
|
11
11
|
## When to use
|
|
12
12
|
|
|
13
13
|
- `~/.okstra/version` is missing or stale → okstra runtime is not installed yet.
|
|
14
|
-
- The current project has no `.
|
|
14
|
+
- The current project has no `.okstra/project.json` yet.
|
|
15
15
|
- The user says "set up okstra here", "first time", "okstra init", etc.
|
|
16
16
|
|
|
17
17
|
## When NOT to use
|
|
@@ -76,7 +76,7 @@ Parse the JSON from stdout. The shape is `{ok, projectRoot, projectJsonPath, pro
|
|
|
76
76
|
|
|
77
77
|
## Step 4: Inspect or create `project.json`
|
|
78
78
|
|
|
79
|
-
Use the `Read` tool on the literal absolute path `<projectRoot>/.
|
|
79
|
+
Use the `Read` tool on the literal absolute path `<projectRoot>/.okstra/project.json` (substitute the literal `projectRoot` value parsed in Step 3). If `Read` errors with "file does not exist", treat that as the "create" branch below; otherwise the file exists and you can inspect its contents inline.
|
|
80
80
|
|
|
81
81
|
If the file exists, surface its `projectId`/`projectRoot` and ask whether to
|
|
82
82
|
keep or overwrite. Default is to keep — okstra refuses to change `projectId`
|
|
@@ -112,7 +112,7 @@ directories is symlinked from the main checkout into that worktree so
|
|
|
112
112
|
every task sees the shared state. The built-in default is
|
|
113
113
|
`.project-docs`, `.scratch`, `graphify-out`, `.claude`.
|
|
114
114
|
Syncing a directory does not make it okstra memory; okstra-owned context
|
|
115
|
-
and writes still stay under `<PROJECT_ROOT>/.
|
|
115
|
+
and writes still stay under `<PROJECT_ROOT>/.okstra/**`
|
|
116
116
|
unless the task brief explicitly authorizes a non-okstra path.
|
|
117
117
|
|
|
118
118
|
To override per-project, add a `worktreeSyncDirs` array to
|
|
@@ -231,7 +231,7 @@ okstra-run prompt convention):
|
|
|
231
231
|
|
|
232
232
|
- **Question**: `"이 프로젝트에서 release-handoff 가 사용할 PR 본문 템플릿을 등록할까요?"`
|
|
233
233
|
- **Options**:
|
|
234
|
-
1. `이번 프로젝트만 (project scope)` — write to `<PROJECT_ROOT>/.
|
|
234
|
+
1. `이번 프로젝트만 (project scope)` — write to `<PROJECT_ROOT>/.okstra/project.json` `prTemplatePath`.
|
|
235
235
|
2. `전역 (global scope)` — write to `~/.okstra/config.json` `prTemplatePath`.
|
|
236
236
|
3. `나중에` — skip.
|
|
237
237
|
|
|
@@ -292,7 +292,7 @@ the output and let the user decide whether to re-run install or skip.
|
|
|
292
292
|
Inform the user with a short summary:
|
|
293
293
|
|
|
294
294
|
> okstra is ready. Runtime: `~/.okstra` (version stamp). Project metadata:
|
|
295
|
-
> `<PROJECT_ROOT>/.
|
|
295
|
+
> `<PROJECT_ROOT>/.okstra/project.json` (`projectId`). Run
|
|
296
296
|
> `/okstra-run` to start your first task.
|
|
297
297
|
|
|
298
298
|
## Failure modes
|
|
@@ -302,7 +302,7 @@ Inform the user with a short summary:
|
|
|
302
302
|
| `command not found: npx` | Node missing | Install node 18+. |
|
|
303
303
|
| `okstra ensure-installed` keeps reinstalling | `~/.okstra/version` write fails (permissions) | Check `~/.okstra` ownership and writability. |
|
|
304
304
|
| `error: --project-id is required (no existing project.json, not a TTY)` | `okstra setup --yes` invoked without `--project-id`, or with empty answer to Step 4 prompt | Re-ask Step 4 and pass a non-empty id via `--project-id`. |
|
|
305
|
-
| `projectId mismatch` / `projectId 불일치` | `project.json` already exists with a different id | Decide which id is canonical; manually delete `<PROJECT_ROOT>/.
|
|
306
|
-
| `EACCES` writing under `.
|
|
305
|
+
| `projectId mismatch` / `projectId 불일치` | `project.json` already exists with a different id | Decide which id is canonical; manually delete `<PROJECT_ROOT>/.okstra/project.json` to re-register, or re-run with the existing id. |
|
|
306
|
+
| `EACCES` writing under `.okstra/` | directory owned by another user (e.g. created by a previous root-shell run) | `chown -R "$USER" <PROJECT_ROOT>/.project-docs` or delete and let setup recreate. |
|
|
307
307
|
| `warning: failed to provision .claude/settings.local.json symlink` | a non-symlink `.claude/settings.local.json` already exists and the backup-and-replace step failed | Inspect `<PROJECT_ROOT>/.claude/settings.local.json{,.bak.*}`; manually merge project-specific rules, then re-run setup. |
|
|
308
308
|
| `npx okstra@latest install` succeeds but `doctor` shows FAIL | runtime/{python,bin,skills} sync not yet performed (pre-release package) | Use dev install: clone the repo and run `node bin/okstra install --link <repo>`. |
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
This file is shipped by `okstra install` and surfaced into the active project
|
|
4
4
|
through two channels by `okstra setup`:
|
|
5
5
|
|
|
6
|
-
- **Claude Code**: `<PROJECT>/CLAUDE.md` gets an `@.
|
|
6
|
+
- **Claude Code**: `<PROJECT>/CLAUDE.md` gets an `@.okstra/CLAUDE.md`
|
|
7
7
|
import block (per-project symlink to this template). Existing user content
|
|
8
8
|
in `CLAUDE.md` is preserved — the block lives between
|
|
9
9
|
`<!-- okstra:claude-md:begin ... -->` markers.
|
|
@@ -14,7 +14,7 @@ through two channels by `okstra setup`:
|
|
|
14
14
|
It is **owned by the okstra package**: every `okstra install` overwrites
|
|
15
15
|
`~/.okstra/templates/okstra.CLAUDE.md` from the version currently on disk in
|
|
16
16
|
the npm package. Edits made directly to this file (or to the per-project
|
|
17
|
-
`<PROJECT>/.
|
|
17
|
+
`<PROJECT>/.okstra/CLAUDE.md` / `<PROJECT>/AGENTS.md` symlinks)
|
|
18
18
|
will be lost on the next install. Put project-specific overrides outside the
|
|
19
19
|
managed block in `<PROJECT>/CLAUDE.md` instead (or replace `AGENTS.md` with
|
|
20
20
|
your own file — okstra will respect it).
|
|
@@ -30,7 +30,7 @@ through slash commands inside a Claude Code session.
|
|
|
30
30
|
|
|
31
31
|
| Command | When to use |
|
|
32
32
|
| --- | --- |
|
|
33
|
-
| `/okstra-setup` | First-time bootstrap in a new project — writes `.
|
|
33
|
+
| `/okstra-setup` | First-time bootstrap in a new project — writes `.okstra/project.json`, provisions `.claude/settings.local.json` and `.okstra/CLAUDE.md`. |
|
|
34
34
|
| `/okstra-brief` | Turn a requirements doc / ticket / link / conversation into the markdown task brief consumed by `okstra-run`. |
|
|
35
35
|
| `/okstra-run` | Start a cross-verification task in the current session. Drives the interactive wizard. |
|
|
36
36
|
| `/okstra-status` | Inspect overall okstra task status, current phase, blockers, next recommended phase. Also flips a task's workStatus (todo / in-progress / blocked / done). |
|
|
@@ -55,7 +55,7 @@ Type the slash command — do not paraphrase the trigger words into prose.
|
|
|
55
55
|
duplicate those permissions in the user's global `~/.claude/settings.json`.
|
|
56
56
|
- Each okstra run provisions a task-scoped git worktree under
|
|
57
57
|
`~/.okstra/worktrees/`. Files synced from the main checkout are governed by
|
|
58
|
-
`worktreeSyncDirs` in `.
|
|
58
|
+
`worktreeSyncDirs` in `.okstra/project.json` (default:
|
|
59
59
|
`.project-docs`, `.scratch`, `graphify-out`, `.claude`).
|
|
60
60
|
- QA gating is configured via `qaCommands` in the same `project.json`.
|
|
61
61
|
Verifiers reject mutation-style commands (`--fix`, `--write`, `cargo update`,
|
|
@@ -105,14 +105,14 @@ handle it. Free-form rows are allowed only as `general:`.
|
|
|
105
105
|
Allowed signals:
|
|
106
106
|
- `general: <unresolved question the user flagged>`
|
|
107
107
|
- `terminology: <reporter word> — needs canonical resolution against
|
|
108
|
-
<PROJECT_ROOT>/.
|
|
108
|
+
<PROJECT_ROOT>/.okstra/glossary.md`
|
|
109
109
|
- `intent-check: <restated inference> — confirm with reporter`
|
|
110
110
|
(auto-paired with every `intent-inference` augmentation)
|
|
111
111
|
- `conversion-block: <reporter statement> — could not be mapped to project
|
|
112
112
|
vocabulary; reporter query required`
|
|
113
113
|
- `adr-candidate: <topic>` — signal only; `implementation-planning`
|
|
114
114
|
evaluates and, if accepted, drafts a decision file at
|
|
115
|
-
`<PROJECT_ROOT>/.
|
|
115
|
+
`<PROJECT_ROOT>/.okstra/decisions/<NNNN>-<slug>.md`.
|
|
116
116
|
|
|
117
117
|
Use `_(none)_` only if every signal is empty. `intent-check:` and
|
|
118
118
|
`conversion-block:` rows that are answered in Step 6.5 are NOT removed
|
|
@@ -156,17 +156,17 @@ Every entry below must start with one of the four labels:
|
|
|
156
156
|
<!-- author guidance — strip out at fill-in time:
|
|
157
157
|
Observations from Step 3b and the outcome of Step 4.5 (glossary applied
|
|
158
158
|
vs. skipped). The actual glossary edits live in
|
|
159
|
-
`<PROJECT_ROOT>/.
|
|
159
|
+
`<PROJECT_ROOT>/.okstra/glossary.md` when applied; this
|
|
160
160
|
section records what happened. Decision candidates are NOT recorded here —
|
|
161
161
|
they flow through `Open Questions` as `adr-candidate:` rows for
|
|
162
162
|
`implementation-planning` to evaluate (and, if accepted, draft into
|
|
163
|
-
`<PROJECT_ROOT>/.
|
|
163
|
+
`<PROJECT_ROOT>/.okstra/decisions/`).
|
|
164
164
|
|
|
165
165
|
Allowed entry shapes:
|
|
166
166
|
- `terminology-mapping: <reporter word> → <okstra glossary canonical>` —
|
|
167
167
|
routine glossary alignment, paired with `terminology:` in Open Questions
|
|
168
168
|
when unresolved.
|
|
169
|
-
- `terminology-mapping: applied glossary: <term> → <PROJECT_ROOT>/.
|
|
169
|
+
- `terminology-mapping: applied glossary: <term> → <PROJECT_ROOT>/.okstra/glossary.md`
|
|
170
170
|
- `terminology-mapping: skipped glossary: <term> = <definition>` —
|
|
171
171
|
Step 4.5 outcomes.
|
|
172
172
|
Use `_(none)_` if every alignment entry is empty.
|
|
@@ -145,7 +145,7 @@ taskType: "{{FM_TASK_TYPE}}"
|
|
|
145
145
|
|
|
146
146
|
## Available MCP Servers
|
|
147
147
|
|
|
148
|
-
The MCP servers available to this run are declared in `.
|
|
148
|
+
The MCP servers available to this run are declared in `.okstra/project.json`'s `mcpServers` array and rendered into the Claude lead's launch prompt under `## Available MCP Servers`. They may be invoked **as needed** by Claude lead, Claude worker, and Report writer worker. The lead is responsible for forwarding the rendered list verbatim into the worker prompts (Phase 2) so workers know which tools they are allowed to call.
|
|
149
149
|
|
|
150
150
|
To declare servers, add entries shaped `{ "name": "<server>", "description": "...", "tools": ["..."], "notes": "..." }` to that array. If the array is empty or absent, treat MCP as unavailable for this run.
|
|
151
151
|
|
|
@@ -52,11 +52,11 @@ write_validation_brief() {
|
|
|
52
52
|
- Config file: \`.claude/settings.json\`
|
|
53
53
|
- Expected values:
|
|
54
54
|
- installed okstra Claude assets must remain discoverable under \`~/.claude/skills/\` and \`~/.claude/agents/\` (managed by \`okstra install\`)
|
|
55
|
-
- Config file: \`.
|
|
55
|
+
- Config file: \`.okstra/discovery/latest-task.json\`
|
|
56
56
|
- Expected values:
|
|
57
57
|
- latest prepared task pointer must include the current task key
|
|
58
58
|
- task catalog path must be present
|
|
59
|
-
- Config file: \`.
|
|
59
|
+
- Config file: \`.okstra/discovery/task-catalog.json\`
|
|
60
60
|
- Expected values:
|
|
61
61
|
- task catalog must preserve prepared task bundles by task key
|
|
62
62
|
- task catalog must allow task-group and task-id level distinction
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# shellcheck shell=bash
|
|
2
2
|
|
|
3
|
+
# Single source of truth for the okstra-relative directory name in shell code.
|
|
4
|
+
# Python (okstra_project/dirs.py) 와 Node (src/okstra-dirs.mjs) 와 같은 값을
|
|
5
|
+
# 유지해야 한다. 디렉토리 이름을 바꾸려면 세 곳의 한 줄씩만 수정.
|
|
6
|
+
OKSTRA_DIR="${OKSTRA_DIR:-.okstra}"
|
|
7
|
+
LEGACY_OKSTRA_DIR=".project-docs/okstra"
|
|
8
|
+
|
|
3
9
|
validate_project_root_safety() {
|
|
4
10
|
if [[ -z "${PROJECT_ROOT:-}" ]]; then
|
|
5
11
|
fail "PROJECT_ROOT is not defined"
|
|
@@ -26,19 +32,19 @@ task_root() {
|
|
|
26
32
|
local task_group="$1"
|
|
27
33
|
local task_id="$2"
|
|
28
34
|
|
|
29
|
-
printf '%s
|
|
35
|
+
printf '%s/%s/tasks/%s/%s\n' "$PROJECT_ROOT" "$OKSTRA_DIR" "$task_group" "$task_id"
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
task_manifest_relative_path() {
|
|
33
39
|
local task_group="$1"
|
|
34
40
|
local task_id="$2"
|
|
35
41
|
|
|
36
|
-
printf '
|
|
42
|
+
printf '%s/tasks/%s/%s/task-manifest.json\n' "$OKSTRA_DIR" "$task_group" "$task_id"
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
reference_expectations_relative_path() {
|
|
40
46
|
local task_group="$1"
|
|
41
47
|
local task_id="$2"
|
|
42
48
|
|
|
43
|
-
printf '
|
|
49
|
+
printf '%s/tasks/%s/%s/instruction-set/reference-expectations.md\n' "$OKSTRA_DIR" "$task_group" "$task_id"
|
|
44
50
|
}
|
|
@@ -10,7 +10,7 @@ Checks performed per brief file:
|
|
|
10
10
|
4. Every Open Questions row starts with one of the five signal prefixes
|
|
11
11
|
(general | terminology | intent-check | conversion-block | adr-candidate).
|
|
12
12
|
`adr-candidate:` targets okstra-internal
|
|
13
|
-
`<PROJECT_ROOT>/.
|
|
13
|
+
`<PROJECT_ROOT>/.okstra/decisions/`, not external `docs/adr/`.
|
|
14
14
|
5. Every Augmentation entry (inline `> augmented: <label>` blockquotes and
|
|
15
15
|
`Augmentation` section bullets) carries one of the four labels
|
|
16
16
|
(evidence-link | format-conversion | terminology-mapping | intent-inference).
|
|
@@ -342,7 +342,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
342
342
|
default=None,
|
|
343
343
|
help=(
|
|
344
344
|
"Root used for depth computation (defaults to briefs_dir). "
|
|
345
|
-
"Usually `<PROJECT_ROOT>/.
|
|
345
|
+
"Usually `<PROJECT_ROOT>/.okstra/briefs`."
|
|
346
346
|
),
|
|
347
347
|
)
|
|
348
348
|
args = parser.parse_args(argv)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# validators/validate-brief.sh <briefs-dir> [--briefs-root <dir>]
|
|
7
7
|
#
|
|
8
8
|
# Typical invocation (inside a project that has run okstra-setup):
|
|
9
|
-
# validators/validate-brief.sh "$PROJECT_ROOT/.
|
|
9
|
+
# validators/validate-brief.sh "$PROJECT_ROOT/.okstra/briefs"
|
|
10
10
|
#
|
|
11
11
|
# Thin bash entrypoint — delegates to validate-brief.py for content checks.
|
|
12
12
|
|
|
@@ -29,6 +29,8 @@ except ImportError: # pragma: no cover — runtime guarantees this import
|
|
|
29
29
|
load_schema = None # type: ignore[assignment]
|
|
30
30
|
schema_validate = None # type: ignore[assignment]
|
|
31
31
|
|
|
32
|
+
from okstra_project.dirs import tasks_root as _okstra_tasks_root # noqa: E402
|
|
33
|
+
|
|
32
34
|
TERMINAL_STATUSES = {"completed", "timeout", "error", "not-run"}
|
|
33
35
|
ATTEMPTED_STATUSES = {"completed", "timeout", "error"}
|
|
34
36
|
|
|
@@ -1317,7 +1319,7 @@ def _refresh_task_catalog(project_root: Path, task_manifest: dict) -> tuple[bool
|
|
|
1317
1319
|
except Exception as exc: # noqa: BLE001
|
|
1318
1320
|
return False, f"okstra_ctl import failed: {exc}"
|
|
1319
1321
|
|
|
1320
|
-
tasks_root = (project_root
|
|
1322
|
+
tasks_root = _okstra_tasks_root(project_root).resolve()
|
|
1321
1323
|
catalog_path = (project_root / catalog_relative).resolve()
|
|
1322
1324
|
ctx = {
|
|
1323
1325
|
"PROJECT_ROOT": str(project_root),
|
|
@@ -24,13 +24,13 @@ PRIMARY_BRIEF_FILENAME="validation-brief-primary.md"
|
|
|
24
24
|
SECONDARY_TASK_GROUP="discovery"
|
|
25
25
|
SECONDARY_TASK_ID="task-catalog"
|
|
26
26
|
SECONDARY_BRIEF_FILENAME="validation-brief-secondary.md"
|
|
27
|
-
LATEST_TASK_RELATIVE_PATH=".project-docs/okstra/discovery/latest-task.json"
|
|
28
|
-
TASK_CATALOG_RELATIVE_PATH=".project-docs/okstra/discovery/task-catalog.json"
|
|
29
27
|
|
|
30
28
|
# shellcheck source=lib/common.sh
|
|
31
29
|
source "$SCRIPT_DIR/lib/common.sh"
|
|
32
30
|
# shellcheck source=lib/paths.sh
|
|
33
31
|
source "$SCRIPT_DIR/lib/paths.sh"
|
|
32
|
+
LATEST_TASK_RELATIVE_PATH="$OKSTRA_DIR/discovery/latest-task.json"
|
|
33
|
+
TASK_CATALOG_RELATIVE_PATH="$OKSTRA_DIR/discovery/task-catalog.json"
|
|
34
34
|
# shellcheck source=lib/fixtures.sh
|
|
35
35
|
source "$SCRIPT_DIR/lib/fixtures.sh"
|
|
36
36
|
# shellcheck source=lib/runners.sh
|
package/src/check-project.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { promises as fs } from "node:fs";
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { resolvePaths } from "./paths.mjs";
|
|
4
|
+
import { buildPythonpath, resolvePaths } from "./paths.mjs";
|
|
5
5
|
|
|
6
6
|
const USAGE = `okstra check-project — verify that the current project has okstra setup
|
|
7
7
|
|
|
8
8
|
Usage:
|
|
9
9
|
okstra check-project Resolve PROJECT_ROOT from cwd, look for
|
|
10
|
-
.
|
|
10
|
+
.okstra/project.json,
|
|
11
11
|
print JSON status to stdout.
|
|
12
12
|
okstra check-project --cwd <dir> Use <dir> as the search starting point
|
|
13
13
|
instead of process cwd.
|
|
@@ -99,7 +99,7 @@ export async function run(args) {
|
|
|
99
99
|
].join("\n"),
|
|
100
100
|
opts.cwd,
|
|
101
101
|
],
|
|
102
|
-
{ PYTHONPATH: paths
|
|
102
|
+
{ PYTHONPATH: buildPythonpath(paths) },
|
|
103
103
|
);
|
|
104
104
|
|
|
105
105
|
if (probe.code !== 0) {
|
package/src/config.mjs
CHANGED
|
@@ -2,12 +2,13 @@ import { promises as fs } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { dirname, join, resolve, isAbsolute } from "node:path";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
|
-
import { resolvePaths } from "./paths.mjs";
|
|
5
|
+
import { buildPythonpath, resolvePaths } from "./paths.mjs";
|
|
6
|
+
import { OKSTRA_DIR, projectJsonPath } from "./okstra-dirs.mjs";
|
|
6
7
|
|
|
7
8
|
const USAGE = `okstra config — read / write okstra settings (project + global scopes)
|
|
8
9
|
|
|
9
10
|
Settings are persisted as JSON keys in one of two files:
|
|
10
|
-
project: <project-root
|
|
11
|
+
project: <project-root>/${OKSTRA_DIR}/project.json
|
|
11
12
|
global: ~/.okstra/config.json
|
|
12
13
|
|
|
13
14
|
Supported keys (CLI alias -> JSON field):
|
|
@@ -132,7 +133,7 @@ function globalConfigPath() {
|
|
|
132
133
|
}
|
|
133
134
|
|
|
134
135
|
function projectConfigPath(projectRoot) {
|
|
135
|
-
return
|
|
136
|
+
return projectJsonPath(projectRoot);
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
async function fileExists(p) {
|
|
@@ -193,7 +194,7 @@ async function resolveProjectRoot(cwd) {
|
|
|
193
194
|
].join("\n"),
|
|
194
195
|
cwd,
|
|
195
196
|
],
|
|
196
|
-
{ PYTHONPATH: paths
|
|
197
|
+
{ PYTHONPATH: buildPythonpath(paths) },
|
|
197
198
|
);
|
|
198
199
|
if (result.code === 0) return result.stdout.trim();
|
|
199
200
|
return null;
|
|
@@ -229,7 +230,7 @@ async function effectivePrTemplatePath(projectRoot) {
|
|
|
229
230
|
].join("\n"),
|
|
230
231
|
projectRoot ?? process.cwd(),
|
|
231
232
|
],
|
|
232
|
-
{ PYTHONPATH: paths
|
|
233
|
+
{ PYTHONPATH: buildPythonpath(paths) },
|
|
233
234
|
);
|
|
234
235
|
if (result.code !== 0) return null;
|
|
235
236
|
try {
|
package/src/install.mjs
CHANGED
|
@@ -15,8 +15,8 @@ const SETTINGS_TEMPLATE_SRC_REL = ["templates", "reports", "settings.template.js
|
|
|
15
15
|
// Destination under ~/.okstra/. Project-local .claude/settings.local.json symlinks here.
|
|
16
16
|
const SETTINGS_TEMPLATE_DST_REL = ["templates", "settings.local.json"];
|
|
17
17
|
|
|
18
|
-
// okstra-managed CLAUDE.md template. Per-project <PROJECT>/.
|
|
19
|
-
// symlinks here; <PROJECT>/CLAUDE.md gets an `@.
|
|
18
|
+
// okstra-managed CLAUDE.md template. Per-project <PROJECT>/.okstra/CLAUDE.md
|
|
19
|
+
// symlinks here; <PROJECT>/CLAUDE.md gets an `@.okstra/CLAUDE.md` import line.
|
|
20
20
|
const CLAUDE_MD_TEMPLATE_REL = ["templates", "okstra.CLAUDE.md"];
|
|
21
21
|
|
|
22
22
|
const PYTHON_PACKAGES = ["okstra_project", "okstra_ctl", "okstra_token_usage", "okstra_vendor", "lib"];
|
|
@@ -70,8 +70,8 @@ provisions, granting per-project Claude Code permissions for okstra
|
|
|
70
70
|
worker wrapper scripts without modifying the user's global settings.
|
|
71
71
|
|
|
72
72
|
The okstra.CLAUDE.md file is the symlink target referenced by every
|
|
73
|
-
project-local <project>/.
|
|
74
|
-
<project>/CLAUDE.md gets an "@.
|
|
73
|
+
project-local <project>/.okstra/CLAUDE.md that okstra-setup provisions;
|
|
74
|
+
<project>/CLAUDE.md gets an "@.okstra/CLAUDE.md" import block so Claude
|
|
75
75
|
Code automatically picks up the okstra runtime guidance.
|
|
76
76
|
|
|
77
77
|
Worker agent definitions are installed into ${"$HOME"}/.claude/agents/ so
|
|
@@ -579,7 +579,7 @@ export async function runInstall(args) {
|
|
|
579
579
|
);
|
|
580
580
|
// templates/ tree — report.css / report.js / *.template.md / okstra.CLAUDE.md
|
|
581
581
|
// are consumed at runtime by okstra-render-report-views.py, final-report
|
|
582
|
-
// assembly, and the per-project .
|
|
582
|
+
// assembly, and the per-project .okstra/CLAUDE.md symlink provisioned by
|
|
583
583
|
// setup. They are NOT covered by installNamedTemplate (which only handles
|
|
584
584
|
// the renamed settings.local.json sidecar), so without this step copy-mode
|
|
585
585
|
// installs miss every asset other than that single file. See
|