okstra 0.63.0 → 0.64.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/docs/kr/architecture.md +1 -1
- package/docs/superpowers/plans/2026-06-09-implementation-run-artifact-stage-isolation.md +320 -0
- package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling-PROBE.md +42 -0
- package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling.md +337 -0
- package/docs/superpowers/specs/2026-06-09-executor-model-custom-id-cascade-design.md +66 -0
- package/docs/superpowers/specs/2026-06-09-implementation-run-artifact-stage-isolation-design.md +87 -0
- package/docs/superpowers/specs/2026-06-10-lead-worker-completion-polling-design.md +113 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/SKILL.md +5 -2
- package/runtime/agents/TODO.md +9 -2
- package/runtime/agents/workers/claude-worker.md +1 -1
- package/runtime/bin/lib/okstra-ctl/cmd-rerun.sh +23 -4
- package/runtime/prompts/profiles/implementation-planning.md +1 -1
- package/runtime/prompts/wizard/prompts.ko.json +17 -1
- package/runtime/python/okstra_ctl/backfill.py +23 -4
- package/runtime/python/okstra_ctl/consumers.py +118 -1
- package/runtime/python/okstra_ctl/paths.py +11 -0
- package/runtime/python/okstra_ctl/run.py +147 -67
- package/runtime/python/okstra_ctl/run_context.py +2 -0
- package/runtime/python/okstra_ctl/wizard.py +127 -29
- package/runtime/skills/okstra-convergence/SKILL.md +3 -1
- package/runtime/skills/okstra-report-writer/SKILL.md +2 -0
- package/runtime/skills/okstra-run/SKILL.md +1 -1
- package/runtime/skills/okstra-team-contract/SKILL.md +37 -0
- package/runtime/templates/reports/final-report.template.md +1 -1
- package/runtime/validators/validate-run.py +20 -3
- package/src/install.mjs +21 -0
- package/src/uninstall.mjs +17 -17
|
@@ -151,7 +151,7 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
|
|
|
151
151
|
{%- endif %}
|
|
152
152
|
|
|
153
153
|
{% if header.taskType == 'implementation-planning' %}
|
|
154
|
-
## 5.
|
|
154
|
+
## 5.4 Implementation Plan Deliverables
|
|
155
155
|
|
|
156
156
|
### Option Candidates{% if t("sectionAside.optionCandidates") != "Option Candidates" %} ({{ t("sectionAside.optionCandidates") }}){% endif %}
|
|
157
157
|
|
|
@@ -748,6 +748,20 @@ def _parse_diff_summary_files(content: str) -> list[str]:
|
|
|
748
748
|
return _DIFF_ROW_PATH_RE.findall(section.group(0))
|
|
749
749
|
|
|
750
750
|
|
|
751
|
+
def _task_root_from_run_dir(run_dir: Path) -> Path:
|
|
752
|
+
"""run_dir 에서 `runs` 디렉터리를 앵커로 task_root 를 복원한다.
|
|
753
|
+
|
|
754
|
+
일반 task-type: run_dir = task_root/runs/<task-type> → task_root.
|
|
755
|
+
implementation(stage 격리): run_dir = task_root/runs/implementation/stage-<N>
|
|
756
|
+
→ 같은 task_root. `runs` 를 위로 탐색하므로 stage-<N> 레벨이 추가돼도
|
|
757
|
+
안전하다. `runs` 가 조상에 없으면 기존 동작(두 단계 위)로 폴백한다.
|
|
758
|
+
"""
|
|
759
|
+
for parent in run_dir.parents:
|
|
760
|
+
if parent.name == "runs":
|
|
761
|
+
return parent.parent
|
|
762
|
+
return run_dir.parent.parent
|
|
763
|
+
|
|
764
|
+
|
|
751
765
|
def _validate_conformance(report_path: Path, failures: list[str],
|
|
752
766
|
surface_patterns: object = None) -> None:
|
|
753
767
|
"""Tier 3 conformance 게이트(implementation / final-verification).
|
|
@@ -759,10 +773,13 @@ def _validate_conformance(report_path: Path, failures: list[str],
|
|
|
759
773
|
"""
|
|
760
774
|
# conformance 산출물은 task-level(<task_root>/qa)에 있어 planning/
|
|
761
775
|
# implementation/final-verification 가 공유한다. report_path 는
|
|
762
|
-
# task_root/runs/<task-type>/reports/final-report.md
|
|
763
|
-
#
|
|
776
|
+
# task_root/runs/<task-type>/reports/final-report.md (implementation 은
|
|
777
|
+
# stage 격리로 runs/implementation/stage-<N>/reports/...) 이므로 고정 parent
|
|
778
|
+
# 카운트 대신 `runs` 디렉터리를 앵커로 task_root 를 찾는다 — stage-<N> 레벨이
|
|
779
|
+
# 있어도 task_root/qa 로 정확히 떨어진다.
|
|
764
780
|
run_dir = report_path.parent.parent
|
|
765
|
-
|
|
781
|
+
task_root = _task_root_from_run_dir(run_dir)
|
|
782
|
+
qa_dir = task_root / "qa"
|
|
766
783
|
manifest_path = qa_dir / "conformance-manifest.json"
|
|
767
784
|
if not manifest_path.is_file():
|
|
768
785
|
return
|
package/src/install.mjs
CHANGED
|
@@ -44,6 +44,7 @@ Usage:
|
|
|
44
44
|
|
|
45
45
|
Effect (copy mode):
|
|
46
46
|
${"$HOME"}/.okstra/lib/python <- runtime/python
|
|
47
|
+
${"$HOME"}/.okstra/lib/validators <- runtime/validators (stage/report structure validators)
|
|
47
48
|
${"$HOME"}/.okstra/bin <- runtime/bin
|
|
48
49
|
${"$HOME"}/.okstra/templates <- runtime/templates (report.css / report.js / *.template.md)
|
|
49
50
|
${"$HOME"}/.okstra/templates/settings.local.json <- runtime/templates/reports/settings.template.json
|
|
@@ -577,12 +578,27 @@ export async function runInstall(args) {
|
|
|
577
578
|
join(paths.home, "schemas"),
|
|
578
579
|
{ refresh: opts.refresh, dryRun: opts.dryRun, mode: 0o644 },
|
|
579
580
|
);
|
|
581
|
+
// validators/ tree — validate-implementation-plan-stages.py (+ lib/) is
|
|
582
|
+
// resolved at runtime by run.py / validate-run.py via the installed package's
|
|
583
|
+
// `parents[2]/validators`, i.e. ~/.okstra/lib/validators. Without this step a
|
|
584
|
+
// copy-mode UPGRADE bumps the version stamp but never refreshes the
|
|
585
|
+
// validators, so a stale validator (e.g. a pre-renumber section schema)
|
|
586
|
+
// survives and render-bundle's stage-structure check diverges from the
|
|
587
|
+
// current template (observed: render-bundle demanding `## 4.5 Stage Map`
|
|
588
|
+
// while the report + wizard validator use `## 5.5`). Mode 0o755 preserves the
|
|
589
|
+
// executable .sh helpers in the tree.
|
|
590
|
+
const validatorsResult = await copyTreeIfChanged(
|
|
591
|
+
join(runtimeRoot, "validators"),
|
|
592
|
+
join(paths.home, "lib", "validators"),
|
|
593
|
+
{ refresh: opts.refresh, dryRun: opts.dryRun, mode: 0o755 },
|
|
594
|
+
);
|
|
580
595
|
|
|
581
596
|
if (!opts.quiet) {
|
|
582
597
|
summarise("python", pythonResult, paths.pythonpath);
|
|
583
598
|
summarise("bin", binResult, paths.bin);
|
|
584
599
|
summarise("templates", templatesResult, join(paths.home, "templates"));
|
|
585
600
|
summarise("schemas", schemasResult, join(paths.home, "schemas"));
|
|
601
|
+
summarise("validators", validatorsResult, join(paths.home, "lib", "validators"));
|
|
586
602
|
}
|
|
587
603
|
|
|
588
604
|
if (pythonResult.missingSource && binResult.missingSource) {
|
|
@@ -600,6 +616,11 @@ export async function runInstall(args) {
|
|
|
600
616
|
"warning: runtime/schemas is empty. final-report schema validation + excerpt generation will be unavailable — re-run the build step.\n",
|
|
601
617
|
);
|
|
602
618
|
}
|
|
619
|
+
if (validatorsResult.missingSource) {
|
|
620
|
+
process.stderr.write(
|
|
621
|
+
"warning: runtime/validators is empty. stage-structure / report validation will use stale or missing validators — re-run the build step.\n",
|
|
622
|
+
);
|
|
623
|
+
}
|
|
603
624
|
|
|
604
625
|
const skillResult = await installSkillsCopy(runtimeRoot, opts);
|
|
605
626
|
await writeSkillsManifest(paths.home, skillResult.installed, { dryRun: opts.dryRun });
|
package/src/uninstall.mjs
CHANGED
|
@@ -53,10 +53,10 @@ const AGENTS_MANIFEST_REL = "installed-agents.json";
|
|
|
53
53
|
const USAGE = `okstra uninstall — remove installed runtime from ~/.okstra, ~/.claude/skills, ~/.claude/agents
|
|
54
54
|
|
|
55
55
|
Usage:
|
|
56
|
-
okstra uninstall Remove ~/.okstra/{lib
|
|
56
|
+
okstra uninstall Remove ~/.okstra/{lib (python + validators),
|
|
57
|
+
bin/<known>, schemas, templates, version,
|
|
57
58
|
dev-link, installed-skills.json,
|
|
58
|
-
installed-agents.json
|
|
59
|
-
templates/settings.local.json} AND
|
|
59
|
+
installed-agents.json} AND
|
|
60
60
|
~/.claude/skills/<name> AND
|
|
61
61
|
~/.claude/agents/<worker>.md for every
|
|
62
62
|
entry in the install manifests (fallback:
|
|
@@ -156,6 +156,12 @@ export async function runUninstall(args) {
|
|
|
156
156
|
process.stdout.write(` home: ${paths.home}\n`);
|
|
157
157
|
}
|
|
158
158
|
await removePath(paths.pythonpath, opts);
|
|
159
|
+
// lib/validators — installed wholesale by copy mode (runtime/validators).
|
|
160
|
+
// Without removing it, `lib` stays non-empty so the rmdir below is skipped and
|
|
161
|
+
// a stale validator survives uninstall → reinstall, diverging from the current
|
|
162
|
+
// template's section schema (observed: a pre-renumber `## 4.5 Stage Map`
|
|
163
|
+
// validator outliving every later install).
|
|
164
|
+
await removePath(join(paths.home, "lib", "validators"), opts);
|
|
159
165
|
for (const name of BIN_ENTRYPOINTS) {
|
|
160
166
|
await removePath(join(paths.bin, name), opts);
|
|
161
167
|
}
|
|
@@ -174,6 +180,10 @@ export async function runUninstall(args) {
|
|
|
174
180
|
}
|
|
175
181
|
}
|
|
176
182
|
|
|
183
|
+
// schemas/ tree — installed by copy mode (runtime/schemas). Older uninstall
|
|
184
|
+
// never removed it, leaving a stale final-report schema behind.
|
|
185
|
+
await removePath(join(paths.home, "schemas"), opts);
|
|
186
|
+
|
|
177
187
|
// Remove the skills we own. Manifest is authoritative; fall back to the
|
|
178
188
|
// hard-coded okstra-* names if it is missing (e.g. an install from an old
|
|
179
189
|
// version that did not write the manifest).
|
|
@@ -196,24 +206,14 @@ export async function runUninstall(args) {
|
|
|
196
206
|
}
|
|
197
207
|
await removePath(join(paths.home, AGENTS_MANIFEST_REL), opts);
|
|
198
208
|
|
|
199
|
-
|
|
209
|
+
// templates/ tree — installed wholesale by copy mode (runtime/templates),
|
|
210
|
+
// including the seeded settings.local.json sidecar. Remove the whole tree so
|
|
211
|
+
// an upgrade/reinstall never serves a stale report.css / *.template.md.
|
|
212
|
+
await removePath(join(paths.home, "templates"), opts);
|
|
200
213
|
// Per-project <PROJECT>/.claude/settings.local.json symlinks are NOT removed
|
|
201
214
|
// here — uninstall is machine-level and does not know which projects opted
|
|
202
215
|
// in. They will dangle until the user removes them manually or re-runs
|
|
203
216
|
// okstra install + okstra setup.
|
|
204
|
-
// Remove templates/ if now empty.
|
|
205
|
-
const templatesDir = join(paths.home, "templates");
|
|
206
|
-
if (await pathExists(templatesDir)) {
|
|
207
|
-
try {
|
|
208
|
-
const entries = await fs.readdir(templatesDir);
|
|
209
|
-
if (entries.length === 0) {
|
|
210
|
-
if (!opts.dryRun) await fs.rmdir(templatesDir);
|
|
211
|
-
if (!opts.quiet) process.stdout.write(` removed empty: ${templatesDir}\n`);
|
|
212
|
-
}
|
|
213
|
-
} catch {
|
|
214
|
-
/* ignore */
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
217
|
|
|
218
218
|
await removePath(join(paths.home, "version"), opts);
|
|
219
219
|
await removePath(join(paths.home, "dev-link"), opts);
|