okstra 0.34.1 → 0.36.1
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 +27 -19
- package/README.md +27 -19
- package/docs/kr/architecture.md +59 -45
- package/docs/kr/cli.md +61 -18
- package/docs/pr-template-usage.md +65 -0
- package/docs/project-structure-overview.md +353 -354
- package/docs/superpowers/plans/2026-05-12-ticket-id-in-reports.md +1 -1
- package/docs/superpowers/plans/2026-05-14-convergence-queue-pruning.md +1 -1
- package/docs/superpowers/plans/2026-05-17-dual-format-final-report.md +1 -1
- package/docs/superpowers/plans/2026-05-20-final-report-language.md +1501 -0
- package/docs/superpowers/plans/2026-05-20-implementation-planning-multi-stage.md +1267 -0
- package/docs/superpowers/plans/2026-05-20-okstra-run-prompt-sot-b1.md +1007 -0
- package/docs/superpowers/plans/2026-05-20-wizard-messages-json-sot.md +720 -0
- package/docs/superpowers/plans/2026-05-20-wizard-prompt-json-sot-a1.md +681 -0
- package/docs/superpowers/plans/2026-05-21-improvement-discovery-task-type.md +1691 -0
- package/docs/superpowers/plans/2026-05-24-implementation-lead-context-slimming.md +1700 -0
- package/docs/superpowers/specs/2026-05-20-final-report-language-design.md +383 -0
- package/docs/superpowers/specs/2026-05-20-implementation-planning-multi-stage-design.md +320 -0
- package/docs/superpowers/specs/2026-05-20-okstra-run-prompt-sot-design.md +299 -0
- package/docs/superpowers/specs/2026-05-21-improvement-discovery-task-type-design.md +335 -0
- package/docs/task-process/README.md +74 -0
- package/docs/task-process/common-flow.md +166 -0
- package/docs/task-process/error-analysis.md +101 -0
- package/docs/task-process/final-verification.md +167 -0
- package/docs/task-process/implementation-planning.md +128 -0
- package/docs/task-process/implementation.md +149 -0
- package/docs/task-process/release-handoff.md +206 -0
- package/docs/task-process/requirements-discovery.md +115 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/SKILL.md +30 -7
- package/runtime/agents/workers/claude-worker.md +31 -6
- package/runtime/agents/workers/codex-worker.md +37 -10
- package/runtime/agents/workers/gemini-worker.md +34 -7
- package/runtime/agents/workers/report-writer-worker.md +19 -10
- package/runtime/bin/okstra-central.sh +6 -6
- package/runtime/bin/okstra-codex-exec.sh +49 -28
- package/runtime/bin/okstra-gemini-exec.sh +39 -21
- package/runtime/bin/okstra-render-final-report.py +13 -2
- package/runtime/bin/okstra-wrapper-status.py +155 -0
- package/runtime/bin/okstra.sh +2 -2
- package/runtime/prompts/launch.template.md +1 -0
- package/runtime/prompts/profiles/_common-contract.md +11 -6
- package/runtime/prompts/profiles/_implementation-deliverable.md +53 -0
- package/runtime/prompts/profiles/_implementation-executor.md +60 -0
- package/runtime/prompts/profiles/_implementation-verifier.md +76 -0
- package/runtime/prompts/profiles/error-analysis.md +3 -7
- package/runtime/prompts/profiles/implementation-planning.md +22 -21
- package/runtime/prompts/profiles/implementation.md +28 -118
- package/runtime/prompts/profiles/improvement-discovery.md +42 -0
- package/runtime/prompts/profiles/release-handoff.md +1 -1
- package/runtime/prompts/profiles/requirements-discovery.md +8 -12
- package/runtime/prompts/wizard/prompts.ko.json +230 -0
- package/runtime/python/lib/okstra/cli.sh +2 -49
- package/runtime/python/lib/okstra/globals.sh +21 -21
- package/runtime/python/lib/okstra/interactive.sh +7 -7
- package/runtime/python/okstra_ctl/clarification_items.py +3 -9
- package/runtime/python/okstra_ctl/consumers.py +53 -0
- package/runtime/python/okstra_ctl/final_report_schema.py +0 -7
- package/runtime/python/okstra_ctl/i18n.py +73 -0
- package/runtime/python/okstra_ctl/improvement_lenses.py +44 -0
- package/runtime/python/okstra_ctl/index.py +1 -1
- package/runtime/python/okstra_ctl/paths.py +26 -20
- package/runtime/python/okstra_ctl/render.py +166 -207
- package/runtime/python/okstra_ctl/render_final_report.py +53 -10
- package/runtime/python/okstra_ctl/run.py +299 -108
- package/runtime/python/okstra_ctl/run_context.py +22 -0
- package/runtime/python/okstra_ctl/seeding.py +186 -0
- package/runtime/python/okstra_ctl/session.py +65 -7
- package/runtime/python/okstra_ctl/wizard.py +348 -127
- package/runtime/python/okstra_ctl/workflow.py +21 -2
- package/runtime/python/okstra_ctl/worktree.py +54 -1
- package/runtime/python/okstra_project/resolver.py +4 -3
- package/runtime/python/okstra_token_usage/report.py +2 -2
- package/runtime/schemas/final-report-v1.0.schema.json +22 -16
- package/runtime/skills/okstra-brief/SKILL.md +102 -218
- package/runtime/skills/okstra-convergence/SKILL.md +2 -3
- package/runtime/skills/okstra-inspect/SKILL.md +581 -0
- package/runtime/skills/okstra-report-writer/SKILL.md +35 -15
- package/runtime/skills/okstra-run/SKILL.md +8 -7
- package/runtime/skills/okstra-schedule/SKILL.md +14 -157
- package/runtime/skills/okstra-setup/SKILL.md +28 -1
- package/runtime/skills/okstra-team-contract/SKILL.md +16 -107
- package/runtime/templates/okstra.CLAUDE.md +104 -0
- package/runtime/templates/reports/brief.template.md +204 -0
- package/runtime/templates/reports/final-report.template.md +93 -98
- package/runtime/templates/reports/i18n/en.json +135 -0
- package/runtime/templates/reports/i18n/ko.json +135 -0
- package/runtime/templates/reports/implementation-planning-input.template.md +18 -0
- package/runtime/templates/reports/improvement-discovery-input.template.md +78 -0
- package/runtime/templates/reports/schedule.template.md +12 -3
- package/runtime/templates/reports/task-brief.template.md +2 -2
- package/runtime/templates/worker-prompt-preamble.md +108 -0
- package/runtime/validators/lib/fixtures.sh +30 -0
- package/runtime/validators/lib/runners.sh +1 -1
- package/runtime/validators/validate-implementation-plan-stages.py +211 -0
- package/runtime/validators/validate-run.py +121 -26
- package/runtime/validators/validate-workflow.sh +2 -2
- package/runtime/validators/validate_improvement_report.py +275 -0
- package/src/config.mjs +18 -0
- package/src/install.mjs +41 -14
- package/src/setup.mjs +133 -1
- package/src/uninstall.mjs +27 -3
- package/runtime/skills/okstra-history/SKILL.md +0 -165
- package/runtime/skills/okstra-logs/SKILL.md +0 -173
- package/runtime/skills/okstra-report-finder/SKILL.md +0 -111
- package/runtime/skills/okstra-status/SKILL.md +0 -246
- package/runtime/skills/okstra-time-summary/SKILL.md +0 -172
|
@@ -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
|
|
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
|
|
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 ``
|
|
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
|
|
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
|
|
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 ``
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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()}")
|