okstra 0.72.0 → 0.74.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.
Files changed (44) hide show
  1. package/docs/kr/architecture.md +2 -1
  2. package/docs/kr/cli.md +1 -1
  3. package/docs/kr/performance-improvement-plan-v2.md +27 -7
  4. package/docs/project-structure-overview.md +1 -0
  5. package/docs/superpowers/plans/2026-06-12-html-plan-approval.md +1000 -0
  6. package/docs/superpowers/specs/2026-06-12-html-plan-approval-design.md +85 -0
  7. package/package.json +1 -1
  8. package/runtime/BUILD.json +2 -2
  9. package/runtime/agents/SKILL.md +3 -3
  10. package/runtime/agents/workers/codex-worker.md +5 -5
  11. package/runtime/agents/workers/gemini-worker.md +5 -5
  12. package/runtime/prompts/profiles/_implementation-executor.md +1 -0
  13. package/runtime/prompts/profiles/_implementation-verifier.md +1 -0
  14. package/runtime/prompts/profiles/error-analysis.md +1 -1
  15. package/runtime/prompts/profiles/final-verification.md +1 -1
  16. package/runtime/prompts/profiles/implementation-planning.md +1 -1
  17. package/runtime/prompts/profiles/requirements-discovery.md +1 -1
  18. package/runtime/prompts/wizard/prompts.ko.json +11 -2
  19. package/runtime/python/okstra_ctl/clarification_items.py +32 -22
  20. package/runtime/python/okstra_ctl/context_cost.py +32 -5
  21. package/runtime/python/okstra_ctl/md_table.py +56 -0
  22. package/runtime/python/okstra_ctl/render_final_report.py +8 -1
  23. package/runtime/python/okstra_ctl/report_views.py +218 -26
  24. package/runtime/python/okstra_ctl/run.py +4 -4
  25. package/runtime/python/okstra_ctl/user_response.py +55 -0
  26. package/runtime/python/okstra_ctl/wizard.py +116 -11
  27. package/runtime/python/okstra_token_usage/claude.py +22 -0
  28. package/runtime/python/okstra_token_usage/collect.py +51 -3
  29. package/runtime/python/okstra_token_usage/cursor.py +3 -1
  30. package/runtime/schemas/final-report-v1.0.schema.json +2 -1
  31. package/runtime/skills/okstra-convergence/SKILL.md +8 -4
  32. package/runtime/skills/okstra-inspect/SKILL.md +20 -0
  33. package/runtime/skills/okstra-report-writer/SKILL.md +4 -3
  34. package/runtime/skills/okstra-run/SKILL.md +1 -1
  35. package/runtime/skills/okstra-team-contract/SKILL.md +1 -1
  36. package/runtime/templates/reports/final-report.template.md +57 -52
  37. package/runtime/templates/reports/report.css +21 -7
  38. package/runtime/templates/reports/report.js +56 -8
  39. package/runtime/templates/reports/user-response.template.md +15 -0
  40. package/runtime/validators/validate-implementation-plan-stages.py +9 -2
  41. package/runtime/validators/validate-report-views.py +2 -1
  42. package/runtime/validators/validate-run.py +6 -17
  43. package/runtime/validators/validate-schedule.py +9 -2
  44. package/runtime/validators/validate_improvement_report.py +2 -1
@@ -17,6 +17,13 @@ import re
17
17
  import sys
18
18
  from pathlib import Path
19
19
 
20
+ # scripts/ is not a package; insert it so okstra_ctl is importable directly.
21
+ _SCRIPTS_DIR = Path(__file__).resolve().parent.parent / "scripts"
22
+ if str(_SCRIPTS_DIR) not in sys.path:
23
+ sys.path.insert(0, str(_SCRIPTS_DIR))
24
+
25
+ from okstra_ctl.md_table import split_pipe_row # noqa: E402
26
+
20
27
  REQUIRED_SECTIONS_IN_ORDER: list[str] = [
21
28
  "## At a Glance",
22
29
  "## Executive Summary",
@@ -298,7 +305,7 @@ def validate(path: Path) -> list[str]:
298
305
  for row in re.finditer(
299
306
  r"^\|\s*\d+\s*\|.*$", body, re.MULTILINE
300
307
  ):
301
- cells = [c.strip() for c in row.group(0).strip().strip("|").split("|")]
308
+ cells = split_pipe_row(row.group(0))
302
309
  # header: # | Task ID | Title | Category | Priority | Effort | Days | taskType | Risk | Phase
303
310
  if len(cells) < 10:
304
311
  continue
@@ -508,7 +515,7 @@ def _extract_task_id_whitelist(text: str, section_positions: dict[str, int],
508
515
  next_h = re.search(r"^##\s", rest, re.MULTILINE)
509
516
  body = rest[: next_h.start()] if next_h else rest
510
517
  for row in re.finditer(r"^\|\s*\d+\s*\|.*$", body, re.MULTILINE):
511
- cells = [c.strip() for c in row.group(0).strip().strip("|").split("|")]
518
+ cells = split_pipe_row(row.group(0))
512
519
  if len(cells) >= 2 and re.fullmatch(r"[A-Z][A-Z0-9_-]*", cells[1]):
513
520
  whitelist.add(cells[1])
514
521
  return whitelist
@@ -23,6 +23,7 @@ from okstra_ctl.improvement_lenses import (
23
23
  ABSOLUTE_CANDIDATE_CAP,
24
24
  SOURCE_WORKERS,
25
25
  )
26
+ from okstra_ctl.md_table import split_pipe_row
26
27
 
27
28
 
28
29
  _VERDICT_TOKENS = ("candidates-ready", "no-candidates", "blocked")
@@ -57,7 +58,7 @@ def _read_section_table(body: str, heading: str) -> list[list[str]]:
57
58
  s = line.strip()
58
59
  if not s.startswith("|") or not s.endswith("|"):
59
60
  continue
60
- cells = [_CELL_ANCHOR_RE.sub("", c).strip() for c in s.strip("|").split("|")]
61
+ cells = [_CELL_ANCHOR_RE.sub("", c).strip() for c in split_pipe_row(s)]
61
62
  if all(set(c) <= set("-: ") for c in cells):
62
63
  continue
63
64
  rows.append(cells)