okstra 0.34.0 → 0.36.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 (101) hide show
  1. package/README.kr.md +26 -16
  2. package/README.md +26 -16
  3. package/docs/kr/architecture.md +59 -45
  4. package/docs/kr/cli.md +61 -18
  5. package/docs/pr-template-usage.md +65 -0
  6. package/docs/project-structure-overview.md +358 -354
  7. package/docs/superpowers/plans/2026-05-12-ticket-id-in-reports.md +1 -1
  8. package/docs/superpowers/plans/2026-05-14-convergence-queue-pruning.md +1 -1
  9. package/docs/superpowers/plans/2026-05-17-dual-format-final-report.md +1 -1
  10. package/docs/superpowers/plans/2026-05-20-final-report-language.md +1501 -0
  11. package/docs/superpowers/plans/2026-05-20-implementation-planning-multi-stage.md +1267 -0
  12. package/docs/superpowers/plans/2026-05-20-okstra-run-prompt-sot-b1.md +1007 -0
  13. package/docs/superpowers/plans/2026-05-20-wizard-messages-json-sot.md +720 -0
  14. package/docs/superpowers/plans/2026-05-20-wizard-prompt-json-sot-a1.md +681 -0
  15. package/docs/superpowers/plans/2026-05-21-improvement-discovery-task-type.md +1691 -0
  16. package/docs/superpowers/specs/2026-05-20-final-report-language-design.md +383 -0
  17. package/docs/superpowers/specs/2026-05-20-implementation-planning-multi-stage-design.md +320 -0
  18. package/docs/superpowers/specs/2026-05-20-okstra-run-prompt-sot-design.md +299 -0
  19. package/docs/superpowers/specs/2026-05-21-improvement-discovery-task-type-design.md +335 -0
  20. package/docs/task-process/README.md +74 -0
  21. package/docs/task-process/common-flow.md +166 -0
  22. package/docs/task-process/error-analysis.md +101 -0
  23. package/docs/task-process/final-verification.md +167 -0
  24. package/docs/task-process/implementation-planning.md +128 -0
  25. package/docs/task-process/implementation.md +149 -0
  26. package/docs/task-process/release-handoff.md +206 -0
  27. package/docs/task-process/requirements-discovery.md +115 -0
  28. package/package.json +1 -1
  29. package/runtime/BUILD.json +2 -2
  30. package/runtime/agents/SKILL.md +29 -13
  31. package/runtime/agents/workers/claude-worker.md +26 -0
  32. package/runtime/agents/workers/codex-worker.md +27 -1
  33. package/runtime/agents/workers/gemini-worker.md +27 -1
  34. package/runtime/agents/workers/report-writer-worker.md +8 -1
  35. package/runtime/bin/okstra-central.sh +6 -6
  36. package/runtime/bin/okstra-codex-exec.sh +49 -28
  37. package/runtime/bin/okstra-gemini-exec.sh +39 -21
  38. package/runtime/bin/okstra-render-final-report.py +13 -2
  39. package/runtime/bin/okstra-wrapper-status.py +155 -0
  40. package/runtime/bin/okstra.sh +2 -2
  41. package/runtime/prompts/profiles/_common-contract.md +11 -6
  42. package/runtime/prompts/profiles/error-analysis.md +3 -7
  43. package/runtime/prompts/profiles/implementation-planning.md +22 -21
  44. package/runtime/prompts/profiles/implementation.md +28 -11
  45. package/runtime/prompts/profiles/improvement-discovery.md +42 -0
  46. package/runtime/prompts/profiles/kr/_common-contract.md +92 -0
  47. package/runtime/prompts/profiles/kr/error-analysis.md +36 -0
  48. package/runtime/prompts/profiles/kr/final-verification.md +48 -0
  49. package/runtime/prompts/profiles/kr/implementation-planning.md +90 -0
  50. package/runtime/prompts/profiles/kr/implementation.md +144 -0
  51. package/runtime/prompts/profiles/kr/improvement-discovery.md +42 -0
  52. package/runtime/prompts/profiles/kr/release-handoff.md +104 -0
  53. package/runtime/prompts/profiles/kr/requirements-discovery.md +42 -0
  54. package/runtime/prompts/profiles/release-handoff.md +1 -1
  55. package/runtime/prompts/profiles/requirements-discovery.md +8 -12
  56. package/runtime/prompts/wizard/prompts.ko.json +230 -0
  57. package/runtime/python/lib/okstra/cli.sh +2 -49
  58. package/runtime/python/lib/okstra/globals.sh +21 -21
  59. package/runtime/python/lib/okstra/interactive.sh +7 -7
  60. package/runtime/python/okstra_ctl/clarification_items.py +3 -9
  61. package/runtime/python/okstra_ctl/consumers.py +53 -0
  62. package/runtime/python/okstra_ctl/final_report_schema.py +0 -7
  63. package/runtime/python/okstra_ctl/i18n.py +73 -0
  64. package/runtime/python/okstra_ctl/improvement_lenses.py +44 -0
  65. package/runtime/python/okstra_ctl/index.py +1 -1
  66. package/runtime/python/okstra_ctl/paths.py +23 -20
  67. package/runtime/python/okstra_ctl/render.py +147 -202
  68. package/runtime/python/okstra_ctl/render_final_report.py +53 -10
  69. package/runtime/python/okstra_ctl/run.py +292 -107
  70. package/runtime/python/okstra_ctl/run_context.py +22 -0
  71. package/runtime/python/okstra_ctl/seeding.py +186 -0
  72. package/runtime/python/okstra_ctl/wizard.py +348 -127
  73. package/runtime/python/okstra_ctl/workflow.py +21 -2
  74. package/runtime/python/okstra_ctl/worktree.py +54 -1
  75. package/runtime/python/okstra_project/resolver.py +4 -3
  76. package/runtime/python/okstra_token_usage/report.py +2 -2
  77. package/runtime/schemas/final-report-v1.0.schema.json +22 -16
  78. package/runtime/skills/okstra-brief/SKILL.md +124 -31
  79. package/runtime/skills/okstra-convergence/SKILL.md +2 -3
  80. package/runtime/skills/okstra-report-writer/SKILL.md +35 -15
  81. package/runtime/skills/okstra-run/SKILL.md +5 -4
  82. package/runtime/skills/okstra-schedule/SKILL.md +4 -4
  83. package/runtime/skills/okstra-setup/SKILL.md +27 -0
  84. package/runtime/skills/okstra-team-contract/SKILL.md +1 -1
  85. package/runtime/templates/okstra.CLAUDE.md +104 -0
  86. package/runtime/templates/reports/final-report.template.md +93 -98
  87. package/runtime/templates/reports/i18n/en.json +135 -0
  88. package/runtime/templates/reports/i18n/ko.json +135 -0
  89. package/runtime/templates/reports/implementation-planning-input.template.md +18 -0
  90. package/runtime/templates/reports/improvement-discovery-input.template.md +78 -0
  91. package/runtime/templates/reports/task-brief.template.md +2 -2
  92. package/runtime/validators/lib/fixtures.sh +30 -0
  93. package/runtime/validators/lib/runners.sh +1 -1
  94. package/runtime/validators/validate-implementation-plan-stages.py +211 -0
  95. package/runtime/validators/validate-run.py +121 -26
  96. package/runtime/validators/validate-workflow.sh +2 -2
  97. package/runtime/validators/validate_improvement_report.py +275 -0
  98. package/src/config.mjs +18 -0
  99. package/src/install.mjs +41 -14
  100. package/src/setup.mjs +133 -1
  101. package/src/uninstall.mjs +21 -1
@@ -35,11 +35,13 @@ import okstra_vendor # noqa: F401 — side effect: sys.modules aliases
35
35
  from jinja2 import ChainableUndefined, Environment, FileSystemLoader
36
36
  from jinja2 import select_autoescape # noqa: F401 — kept for future HTML use
37
37
 
38
+ from okstra_ctl.i18n import I18nError, SUPPORTED_LANGS, load_dictionary, make_jinja_global
39
+
38
40
 
39
41
  DEFAULT_TEMPLATE_REL = ("templates", "reports", "final-report.template.md")
40
42
 
41
43
 
42
- class RenderError(RuntimeError):
44
+ class FinalReportRenderError(RuntimeError):
43
45
  """Raised when the data.json cannot be rendered. Wraps jinja2 errors
44
46
  and IO errors with a single user-facing message so the CLI / Phase 6
45
47
  surface one consistent failure shape.
@@ -122,23 +124,59 @@ def _build_environment(template_dir: Path) -> Environment:
122
124
  return env
123
125
 
124
126
 
125
- def render(data: dict, *, template_path: Path) -> str:
127
+ def resolve_report_language(data: dict, *, override: str | None) -> str:
128
+ """우선순위: override > data.meta.reportLanguage > 'en'."""
129
+ if override is not None:
130
+ candidate = override
131
+ else:
132
+ candidate = (data.get("meta") or {}).get("reportLanguage") or "en"
133
+ if candidate == "auto":
134
+ raise FinalReportRenderError(
135
+ "reportLanguage 'auto' must be resolved by the lead before "
136
+ "the renderer runs; the report-writer worker writes the "
137
+ "resolved 'en' or 'ko' into data.json.meta.reportLanguage."
138
+ )
139
+ if candidate not in SUPPORTED_LANGS:
140
+ raise FinalReportRenderError(
141
+ f"reportLanguage must be one of {SUPPORTED_LANGS}, got {candidate!r}"
142
+ )
143
+ return candidate
144
+
145
+
146
+ def render(
147
+ data: dict,
148
+ *,
149
+ template_path: Path,
150
+ report_language: str | None = None,
151
+ ) -> str:
126
152
  """Render ``data`` through the Jinja2 ``template_path`` and return the
127
153
  final markdown as a string. Caller writes it to disk.
128
154
 
129
- Raises ``RenderError`` on any template / IO / data structural failure
155
+ Raises ``FinalReportRenderError`` on any template / IO / data structural failure
130
156
  so the surface is one exception type rather than the broad jinja2
131
157
  hierarchy.
132
158
  """
133
159
  if not template_path.is_file():
134
- raise RenderError(f"template not found: {template_path}")
160
+ raise FinalReportRenderError(f"template not found: {template_path}")
161
+
162
+ lang = resolve_report_language(data, override=report_language)
163
+ try:
164
+ dictionary = load_dictionary(lang)
165
+ except I18nError as exc:
166
+ raise FinalReportRenderError(str(exc)) from exc
135
167
 
136
168
  env = _build_environment(template_path.parent)
169
+ env.globals["t"] = make_jinja_global(dictionary)
170
+
137
171
  try:
138
172
  template = env.get_template(template_path.name)
139
173
  return template.render(**data)
174
+ except I18nError as exc:
175
+ raise FinalReportRenderError(
176
+ f"i18n lookup failed while rendering {template_path.name}: {exc}"
177
+ ) from exc
140
178
  except Exception as exc: # jinja2.TemplateError, KeyError, etc.
141
- raise RenderError(
179
+ raise FinalReportRenderError(
142
180
  f"render failed for template {template_path.name}: {exc}"
143
181
  ) from exc
144
182
 
@@ -152,7 +190,7 @@ def find_default_template(start: Path | None = None) -> Path:
152
190
  Repo root is detected by walking up from this file until a
153
191
  ``templates/reports/final-report.template.md`` exists.
154
192
 
155
- Raises ``RenderError`` if neither path is present.
193
+ Raises ``FinalReportRenderError`` if neither path is present.
156
194
  """
157
195
  okstra_home = os.environ.get("OKSTRA_HOME")
158
196
  if okstra_home:
@@ -166,7 +204,7 @@ def find_default_template(start: Path | None = None) -> Path:
166
204
  if candidate.is_file():
167
205
  return candidate
168
206
 
169
- raise RenderError(
207
+ raise FinalReportRenderError(
170
208
  "could not locate final-report.template.md. Set OKSTRA_HOME or "
171
209
  "run from a checkout that contains templates/reports/."
172
210
  )
@@ -177,6 +215,7 @@ def render_to_file(
177
215
  output_path: Path,
178
216
  *,
179
217
  template_path: Path | None = None,
218
+ report_language: str | None = None,
180
219
  ) -> int:
181
220
  """Read ``data_path`` (JSON), render through Jinja2, write to
182
221
  ``output_path``. Returns the number of bytes written.
@@ -185,14 +224,18 @@ def render_to_file(
185
224
  write never produces a half-corrupt final-report on disk.
186
225
  """
187
226
  if not data_path.is_file():
188
- raise RenderError(f"data file not found: {data_path}")
227
+ raise FinalReportRenderError(f"data file not found: {data_path}")
189
228
  try:
190
229
  data = json.loads(data_path.read_text(encoding="utf-8"))
191
230
  except json.JSONDecodeError as exc:
192
- raise RenderError(f"invalid JSON in {data_path}: {exc}") from exc
231
+ raise FinalReportRenderError(f"invalid JSON in {data_path}: {exc}") from exc
193
232
 
194
233
  resolved_template = template_path or find_default_template(data_path)
195
- rendered = render(data, template_path=resolved_template)
234
+ rendered = render(
235
+ data,
236
+ template_path=resolved_template,
237
+ report_language=report_language,
238
+ )
196
239
 
197
240
  output_path.parent.mkdir(parents=True, exist_ok=True)
198
241
  tmp = output_path.with_suffix(output_path.suffix + f".tmp.{os.getpid()}")