okstra 0.75.0 → 0.76.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okstra",
3
- "version": "0.75.0",
3
+ "version": "0.76.0",
4
4
  "description": "Multi-agent cross-verification orchestrator runtime + Claude Code skills.",
5
5
  "license": "MIT",
6
6
  "author": "devonshin",
@@ -1,5 +1,5 @@
1
1
  {
2
- "package": "0.75.0",
3
- "builtAt": "2026-06-11T19:32:02.652Z",
2
+ "package": "0.76.0",
3
+ "builtAt": "2026-06-11T20:04:51.254Z",
4
4
  "repoRoot": "/home/runner/work/okstra/okstra"
5
5
  }
@@ -135,7 +135,7 @@ This wrapper does NOT invoke MCP tools directly. MCP availability inside the Cod
135
135
  - Treat the prompt-history path as the canonical worker prompt history artifact for the current run, resolved to absolute against `Project Root` if given as relative.
136
136
  - The assigned model execution value is canonical for CLI execution. Do not substitute a different Codex model unless the task bundle explicitly changes it.
137
137
  - Pass the prompt received from Lead directly to codex after persisting the exact prompt to the assigned path.
138
- - **Executor preflight forwarding check (implementation runs only).** When the lead prompt assigns this dispatch the `Executor` role for an `implementation` run, the persisted prompt body MUST contain the literal heading `Coding-conventions preflight` (transcribed by the lead from `prompts/profiles/_implementation-executor.md` → "Pre-implementation context exploration") — the Codex CLI does not share the lead's context, so an untranscribed gate never reaches the process that writes the code. If the heading is absent, return `CODEX_PREFLIGHT_MISSING: executor dispatch prompt lacks the coding-conventions preflight block` instead of invoking the CLI; the lead is responsible for re-dispatching with the block included. This check does NOT apply to verifier or analysis dispatches.
138
+ - **Executor preflight forwarding check (implementation runs only).** When the lead prompt assigns this dispatch the `Executor` role for an `implementation` run, the persisted prompt body MUST contain the literal heading `Coding-conventions preflight` (the lead appends the body of `prompts/profiles/_coding-conventions-preflight.md` into the dispatch prompt — see `prompts/profiles/_implementation-executor.md` → "Pre-implementation context exploration") — the Codex CLI does not share the lead's context, so an unforwarded gate never reaches the process that writes the code. If the heading is absent, return `CODEX_PREFLIGHT_MISSING: executor dispatch prompt lacks the coding-conventions preflight block` instead of invoking the CLI; the lead is responsible for re-dispatching with the block included. This check does NOT apply to verifier or analysis dispatches.
139
139
  - Include context (code, diff, file paths) if provided.
140
140
  - For long prompts, dispatch through the wrapper with literal absolute paths (plus the worktree path for implementation phase):
141
141
  ```bash
@@ -135,7 +135,7 @@ This wrapper does NOT invoke MCP tools directly. MCP availability inside the Gem
135
135
  - Treat the prompt-history path as the canonical worker prompt history artifact for the current run, resolved to absolute against `Project Root` if given as relative.
136
136
  - The assigned model execution value is canonical for CLI execution. Do not substitute a different Gemini model unless the task bundle explicitly changes it.
137
137
  - Pass the prompt received from Lead directly to gemini after persisting the exact prompt to the assigned path.
138
- - **Executor preflight forwarding check (implementation runs only).** When the lead prompt assigns this dispatch the `Executor` role for an `implementation` run, the persisted prompt body MUST contain the literal heading `Coding-conventions preflight` (transcribed by the lead from `prompts/profiles/_implementation-executor.md` → "Pre-implementation context exploration") — the Gemini CLI does not share the lead's context, so an untranscribed gate never reaches the process that writes the code. If the heading is absent, return `GEMINI_PREFLIGHT_MISSING: executor dispatch prompt lacks the coding-conventions preflight block` instead of invoking the CLI; the lead is responsible for re-dispatching with the block included. This check does NOT apply to verifier or analysis dispatches.
138
+ - **Executor preflight forwarding check (implementation runs only).** When the lead prompt assigns this dispatch the `Executor` role for an `implementation` run, the persisted prompt body MUST contain the literal heading `Coding-conventions preflight` (the lead appends the body of `prompts/profiles/_coding-conventions-preflight.md` into the dispatch prompt — see `prompts/profiles/_implementation-executor.md` → "Pre-implementation context exploration") — the Gemini CLI does not share the lead's context, so an unforwarded gate never reaches the process that writes the code. If the heading is absent, return `GEMINI_PREFLIGHT_MISSING: executor dispatch prompt lacks the coding-conventions preflight block` instead of invoking the CLI; the lead is responsible for re-dispatching with the block included. This check does NOT apply to verifier or analysis dispatches.
139
139
  - Include context (code, diff, file paths) if provided.
140
140
  - For long prompts, dispatch through the wrapper with literal absolute paths (plus the worktree path for implementation phase):
141
141
  ```bash
@@ -0,0 +1,21 @@
1
+ <!--
2
+ Single source for the executor's Coding-conventions preflight gate. Two delivery
3
+ paths converge here (see _implementation-executor.md "Pre-implementation context
4
+ exploration"):
5
+ - Claude executor reads this file directly before its first Edit / Write.
6
+ - codex / gemini executor cannot read this path (it sits outside the CLI
7
+ sandbox and the CLI only sees its stdin prompt), so the lead appends this
8
+ file's body into the persisted executor prompt at dispatch time.
9
+ The `Coding-conventions preflight` heading below is the literal string the CLI
10
+ wrapper's "Executor preflight forwarding check" greps for in the persisted
11
+ prompt (agents/workers/_cli-wrapper-template.md → Prompt Composition).
12
+ -->
13
+
14
+ # Coding-conventions preflight (BLOCKING — runs before the first `Edit` / `Write`, and binds the TDD loop)
15
+
16
+ Load the applicable coding conventions for every language the diff will touch, then state in ONE line which conventions apply (e.g. `Applying TS + hexagonal overlay; domain at src/domains/*/domain/`). Lint/test green is necessary but NOT sufficient — self-mocked tests, interaction-only assertions, and untruthful names all pass a green pipeline; this gate is what keeps them out of the diff.
17
+
18
+ - **Language-specific rules load per situation — never inline them here.** Detect each touched file's language (extension / project manifest) and load the matching reference by reading okstra's installed coding-conventions files directly at `~/.claude/skills/okstra-coding-preflight/` (placed there by `okstra install`): read `languages/<lang>.md` (mock/spy API, idioms, test framework) + `clean-code.md` + any `architecture/*` overlay via the Read tool by absolute path. The skill is `user-invocable: false`, so do NOT rely on Skill-tool auto-invocation — read the files directly. For a ports-and-adapters / NestJS-hex layout (`domain/` + `ports/` + `adapters/`, `*.port.*`), load the hexagonal overlay too. This per-language split is the skill's job — the executor does not carry a multi-language block in context.
19
+ - **Project review rule packs:** also look for project-local review skills in `<PROJECT_ROOT>/skills/*review*`, `<PROJECT_ROOT>/.claude/skills/*review*`, and up to two parent directories' `skills/*review*/SKILL.md`. Read the relevant `SKILL.md` plus referenced `references/*.md` files and apply their rules during implementation. This is a prevention pass, not a PR-comment generation workflow: do not dispatch reviewer subagents from the executor. For Fonts Ninja-style PR review packs, the executor must avoid newly introduced duplicate helper stacks, tautological tests that merely re-call the delegated helper, self-mocking, domain rules in adapters/ports, domain objects outside `domain/`, dead APIs, weak public names, and functions that fail the plain-English read.
20
+ - **Language-agnostic principles that ALWAYS bind (the TDD loop MUST satisfy them):** (1) no self-mocking of the SUT — stub/spy only injected collaborators, never the subject's own methods; (2) behavioral assertions on outcomes (return value, state, persisted rows, events, boundary calls) — never `toHaveBeenCalled*` on an internal helper as the only/primary assertion; (3) truthful names — a `get*` / `find*` that writes/inserts, or a name encoding the caller's use-case (`*ForInit`) or hiding a domain rule (`findValid*`), is a defect; (4) single-purpose functions ≤50 effective lines, plain-English readability.
21
+ - **Graceful degradation (codex / gemini executor runtimes, or any runtime where the `~/.claude/skills/okstra-coding-preflight/` files are absent or unreadable):** do NOT skip the gate — apply the agnostic principles above plus the project's own `CLAUDE.md` / `CONTRIBUTING` / formatter+lint config, and record `coding-conventions: skill-unavailable → applied <project rules + agnostic principles>` in the final report. Never claim a skill read that did not happen.
@@ -19,12 +19,9 @@ until Phase 5 ends, then drop from active context for Phase 6/7.
19
19
 
20
20
  ## Pre-implementation context exploration (executor before first edit)
21
21
 
22
- - **Coding-conventions preflight (BLOCKING — runs before the first `Edit` / `Write`, and binds the TDD loop below):** load the applicable coding conventions for every language the diff will touch, then state in ONE line which conventions apply (e.g. `Applying TS + hexagonal overlay; domain at src/domains/*/domain/`). Lint/test green is necessary but NOT sufficient — self-mocked tests, interaction-only assertions, and untruthful names all pass a green pipeline; this gate is what keeps them out of the diff.
23
- - **Language-specific rules load per situation — never inline them here.** Detect each touched file's language (extension / project manifest) and load the matching reference by reading okstra's installed coding-conventions files directly at `~/.claude/skills/okstra-coding-preflight/` (placed there by `okstra install`): read `languages/<lang>.md` (mock/spy API, idioms, test framework) + `clean-code.md` + any `architecture/*` overlay via the Read tool by absolute path. The skill is `user-invocable: false`, so do NOT rely on Skill-tool auto-invocation read the files directly. For a ports-and-adapters / NestJS-hex layout (`domain/` + `ports/` + `adapters/`, `*.port.*`), load the hexagonal overlay too. This per-language split is the skill's job — the executor does not carry a multi-language block in context.
24
- - **Project review rule packs:** also look for project-local review skills in `<PROJECT_ROOT>/skills/*review*`, `<PROJECT_ROOT>/.claude/skills/*review*`, and up to two parent directories' `skills/*review*/SKILL.md`. Read the relevant `SKILL.md` plus referenced `references/*.md` files and apply their rules during implementation. This is a prevention pass, not a PR-comment generation workflow: do not dispatch reviewer subagents from the executor. For Fonts Ninja-style PR review packs, the executor must avoid newly introduced duplicate helper stacks, tautological tests that merely re-call the delegated helper, self-mocking, domain rules in adapters/ports, domain objects outside `domain/`, dead APIs, weak public names, and functions that fail the plain-English read.
25
- - **Language-agnostic principles that ALWAYS bind (the TDD loop below MUST satisfy them):** (1) no self-mocking of the SUT — stub/spy only injected collaborators, never the subject's own methods; (2) behavioral assertions on outcomes (return value, state, persisted rows, events, boundary calls) — never `toHaveBeenCalled*` on an internal helper as the only/primary assertion; (3) truthful names — a `get*` / `find*` that writes/inserts, or a name encoding the caller's use-case (`*ForInit`) or hiding a domain rule (`findValid*`), is a defect; (4) single-purpose functions ≤50 effective lines, plain-English readability.
26
- - **Graceful degradation (codex / gemini executor runtimes, or any runtime where the `~/.claude/skills/okstra-coding-preflight/` files are absent or unreadable):** do NOT skip the gate — apply the agnostic principles above plus the project's own `CLAUDE.md` / `CONTRIBUTING` / formatter+lint config, and record `coding-conventions: skill-unavailable → applied <project rules + agnostic principles>` in the final report. Never claim a skill read that did not happen.
27
- - **CLI executor transcription (BLOCKING when the executor provider is `codex` or `gemini`):** the executor CLI process does NOT share the lead's context — a gate that stays in lead memory never reaches it. The lead MUST copy this entire "Coding-conventions preflight" bullet tree (file-read instructions, project review rule packs, agnostic principles, graceful degradation) verbatim into the dispatched executor prompt body. Enforcement: the CLI wrapper agents refuse an implementation-Executor dispatch whose persisted prompt lacks the literal heading `Coding-conventions preflight`, returning `<SENTINEL_PREFIX>_PREFLIGHT_MISSING` (see `agents/workers/_cli-wrapper-template.md` → Prompt Composition).
22
+ - **Coding-conventions preflight (BLOCKING — runs before the first `Edit` / `Write`, and binds the TDD loop below).** The gate body is a single source at `prompts/profiles/_coding-conventions-preflight.md` (sibling of this sidecar): skill-file pointers (`~/.claude/skills/okstra-coding-preflight/`), project review rule packs, the always-binding language-agnostic principles, and graceful degradation. Do NOT re-type that content from memory deliver it by file so it cannot drift or be dropped:
23
+ - **Claude executor:** Read `_coding-conventions-preflight.md` end-to-end before the first `Edit` / `Write`, then state in ONE line which conventions apply (e.g. `Applying TS + hexagonal overlay; domain at src/domains/*/domain/`).
24
+ - **CLI executor (BLOCKING when the executor provider is `codex` or `gemini`):** the executor CLI process does NOT share the lead's context, and it cannot Read this sidecar's directory that path sits outside the CLI sandbox and the CLI only sees its stdin prompt, so a file reference never reaches it. The lead MUST physically append the **body** of `_coding-conventions-preflight.md` into the persisted executor prompt at dispatch time: Read the file from the same absolute directory you read this sidecar from, then `Write`/`cat` its body into the persisted prompt. Never hand-retype it. Enforcement: the CLI wrapper agents refuse an implementation-Executor dispatch whose persisted prompt lacks the literal heading `Coding-conventions preflight`, returning `<SENTINEL_PREFIX>_PREFLIGHT_MISSING` (see `agents/workers/_cli-wrapper-template.md` → Prompt Composition).
28
25
  - **Stage discipline transcription (when a preceding stage is `done`):** the lead MUST transcribe the `Stage discipline` rule (from this run's rendered profile — the INCLUDEd `_stage-discipline.md` body) verbatim into the dispatched CLI executor prompt, so a codex/gemini executor honors the prior-stage behavior-freeze. Declaration-level — no wrapper sentinel.
29
26
  - **Non-interactive auto-execution (BLOCKING when the executor provider is `codex` or `gemini`).** A CLI executor runs head-less (`codex exec` / gemini equivalent) — there is no human at the keyboard. Skills loaded during the run (tdd, coding-preflight, and others) contain "get user approval", "state your plan to the user and wait", or "ask before proceeding" gates written for interactive sessions; in this run those gates are **already satisfied** by the upstream `implementation-planning` approval (the plan this stage executes was human-approved). The executor MUST NOT stop to request approval, MUST NOT end its turn after only producing a plan, and MUST carry the stage through end-to-end — RED → GREEN → refactor → per-step commits → `### Stage Carry Evidence`. The ONLY skill step to skip is the interactive user-approval prompt itself; every other skill rule (TDD discipline, conventions, real-IO isolation) still binds. The lead MUST transcribe this bullet verbatim into the dispatched CLI executor prompt (same reason as the preflight transcription rule above — the CLI process does not share lead context). Stopping early for approval in a head-less run is the observed empty-exit failure (exit 0, no diff): treat it as `contract-violated`.
30
27
  - **Mandatory TDD loop**: BEFORE the first `Edit` or `Write` call, the executor MUST apply a red-green-refactor loop for every code change in this run. This is required; skipping it is a `contract-violated` outcome. This governs HOW each step is executed (failing test first → minimal implementation → refactor); it does not override the approved plan's WHAT/file scope.
@@ -196,6 +196,7 @@
196
196
  },
197
197
  "approved_plan_pick": {
198
198
  "label": "approved final-report 경로 (기본: {default})",
199
+ "label_final_verification": "검증 기준이 될 승인된 plan(approved final-report) 을 선택하세요 (기본: {default})",
199
200
  "echo_template": "approved-plan(pick): {value}",
200
201
  "options": {
201
202
  "__use_default__": "기본 경로 사용: {default}",
@@ -216,12 +217,17 @@
216
217
  "echo_template": "approved-plan: {value}"
217
218
  },
218
219
  "approve_plan_confirm": {
219
- "label": "이 플랜으로 진행할까요?\n {path}\n· 예 — 진행합니다. 플랜이 아직 승인 전이면 지금 data.json(정본) + 리포트를 함께 approved 로 처리한 뒤 진행합니다. (markdown 만 손으로 고치면 일관성 검증에서 거부되므로 이 경로로 승인하세요.)\n· 아니오 — 진행하지 않습니다.",
220
+ "label": "이 플랜으로 구현을 진행할까요?\n {path}\n· 예 — plan 대로 구현을 실행합니다. 플랜이 아직 승인 전이면 지금 data.json(정본) + 리포트를 함께 approved 로 처리한 뒤 진행합니다. (markdown 만 손으로 고치면 일관성 검증에서 거부되므로 이 경로로 승인하세요.)\n· 아니오 — 진행하지 않습니다.",
221
+ "label_final_verification": "이 plan 을 검증 기준으로 삼아 진행할까요?\n {path}\n· 예 — 선택한 stage 의 구현 결과를 위 plan 기준으로 검증합니다. (plan 이 아직 승인 전이면 data.json(정본) + 리포트를 함께 approved 로 처리한 뒤 검증합니다.)\n· 아니오 — 진행하지 않습니다.",
220
222
  "html_approval_note": "\nHTML 승인 기록 발견: {sidecar}\n 선택 옵션: {option}\n· 예(기록 적용) — 승인과 함께 위 옵션을 frontmatter 에 기록합니다.",
221
223
  "html_approval_note_default_option": "(추천 옵션 그대로)",
222
224
  "echo_template": "approve-plan: {value}",
223
225
  "options": {
224
- "yes": "예 — 승인하고 진행",
226
+ "yes": "예 — 승인하고 구현 진행",
227
+ "no": "아니오 — 진행하지 않음"
228
+ },
229
+ "options_final_verification": {
230
+ "yes": "예 — 이 plan 기준으로 검증 진행",
225
231
  "no": "아니오 — 진행하지 않음"
226
232
  },
227
233
  "options_html_approval": {
@@ -230,8 +236,10 @@
230
236
  "no": "아니오 — 진행하지 않음"
231
237
  },
232
238
  "echo_variants": {
233
- "selected": "plan 선택: {path} — 다음 단계에서 승인·진행 여부를 확인합니다",
234
- "approved": "approved-plan: {path} (승인·진행 확인됨)",
239
+ "selected": "plan 선택: {path} — 다음 단계에서 승인·구현 진행 여부를 확인합니다",
240
+ "selected_final_verification": "검증 기준 plan 선택: {path} 다음 단계에서 검증 진행 여부를 확인합니다",
241
+ "approved": "approved-plan: {path} (승인·구현 진행 확인됨)",
242
+ "approved_final_verification": "검증 기준 plan 확정: {path} (검증 진행 확인됨)",
235
243
  "approved_with_option": "approved-plan: {path} (승인 + 옵션 `{option}` 적용됨)"
236
244
  },
237
245
  "errors": {
@@ -635,7 +635,12 @@ def _stage_plan_for_confirmation(
635
635
  state.html_approval_sidecar = str(sidecar_path)
636
636
  state.html_approval_option = record.implementation_option
637
637
  t = _p(state.workspace_root, "approve_plan_confirm", path=str(p))
638
- msg = t["echo_variants"]["selected"].format(path=p)
638
+ variants = t["echo_variants"]
639
+ key = ("selected_final_verification"
640
+ if state.task_type == "final-verification"
641
+ and variants.get("selected_final_verification")
642
+ else "selected")
643
+ msg = variants[key].format(path=p)
639
644
  return f"{msg} {suffix}".rstrip() if suffix else msg
640
645
 
641
646
 
@@ -770,8 +775,10 @@ def _p(workspace_root: str, step_id: str, **vars: str) -> dict:
770
775
  if raw is None:
771
776
  raise WizardError(f"unknown wizard step_id: {step_id!r}")
772
777
  label_template = raw.get("label", "")
778
+ fv_label_template = raw.get("label_final_verification", "")
773
779
  try:
774
780
  label = label_template.format(**vars)
781
+ label_final_verification = fv_label_template.format(**vars)
775
782
  except KeyError as exc:
776
783
  missing = exc.args[0] if exc.args else "<unknown>"
777
784
  raise WizardError(
@@ -779,8 +786,10 @@ def _p(workspace_root: str, step_id: str, **vars: str) -> dict:
779
786
  ) from exc
780
787
  return {
781
788
  "label": label,
789
+ "label_final_verification": label_final_verification,
782
790
  "echo_template": raw.get("echo_template", ""),
783
791
  "options": raw.get("options", {}),
792
+ "options_final_verification": raw.get("options_final_verification", {}),
784
793
  "options_html_approval": raw.get("options_html_approval", {}),
785
794
  "html_approval_note": raw.get("html_approval_note", ""),
786
795
  "html_approval_note_default_option": raw.get(
@@ -1626,6 +1635,8 @@ def _build_approved_plan_pick(state: WizardState) -> Prompt:
1626
1635
  default = reports[0] if reports else None
1627
1636
  t = _p(state.workspace_root, "approved_plan_pick",
1628
1637
  default=str(default) if default is not None else "")
1638
+ is_fv = state.task_type == "final-verification"
1639
+ label = (t["label_final_verification"] or t["label"]) if is_fv else t["label"]
1629
1640
  other_report_label = t["labels"]["other_report"]
1630
1641
  options: list[Option] = []
1631
1642
  if default is not None:
@@ -1637,7 +1648,7 @@ def _build_approved_plan_pick(state: WizardState) -> Prompt:
1637
1648
  options.append(_opt(PICK_OTHER, t["options"][PICK_OTHER]))
1638
1649
  return Prompt(
1639
1650
  step=S_APPROVED_PLAN_PICK, kind="pick",
1640
- label=t["label"], options=options,
1651
+ label=label, options=options,
1641
1652
  echo_template=t["echo_template"],
1642
1653
  )
1643
1654
 
@@ -1679,8 +1690,9 @@ def _submit_approved_plan(state: WizardState, value: str) -> Optional[str]:
1679
1690
  def _build_approve_plan_confirm(state: WizardState) -> Prompt:
1680
1691
  t = _p(state.workspace_root, "approve_plan_confirm",
1681
1692
  path=state.approve_plan_candidate)
1682
- label = t["label"]
1683
- options_map = t["options"]
1693
+ is_fv = state.task_type == "final-verification"
1694
+ label = (t["label_final_verification"] or t["label"]) if is_fv else t["label"]
1695
+ options_map = (t["options_final_verification"] or t["options"]) if is_fv else t["options"]
1684
1696
  if state.html_approval_sidecar:
1685
1697
  label += t["html_approval_note"].format(
1686
1698
  sidecar=state.html_approval_sidecar,
@@ -1728,7 +1740,12 @@ def _submit_approve_plan_confirm(state: WizardState, value: str) -> Optional[str
1728
1740
  if not fully_approved:
1729
1741
  raise WizardError(
1730
1742
  t["errors"]["still_unapproved"].format(path=resolved))
1731
- echo = t["echo_variants"]["approved"].format(path=resolved)
1743
+ variants = t["echo_variants"]
1744
+ approved_key = ("approved_final_verification"
1745
+ if state.task_type == "final-verification"
1746
+ and variants.get("approved_final_verification")
1747
+ else "approved")
1748
+ echo = variants[approved_key].format(path=resolved)
1732
1749
  if apply_option:
1733
1750
  _apply_cli_implementation_option(
1734
1751
  str(resolved), state.html_approval_option)
@@ -1748,10 +1765,7 @@ def _build_stage_pick(state: WizardState) -> Prompt:
1748
1765
  t = _p(state.workspace_root, "stage_pick")
1749
1766
  stages = _parse_stage_objects(state)
1750
1767
  is_fv = state.task_type == "final-verification"
1751
- label = (
1752
- t.get("label_final_verification", t["label"])
1753
- if is_fv else t["label"]
1754
- )
1768
+ label = (t["label_final_verification"] or t["label"]) if is_fv else t["label"]
1755
1769
  done = _done_stage_numbers(state) if is_fv else set()
1756
1770
  options = []
1757
1771
  if _stage_auto_allowed(state):