okstra 0.189.4 → 0.190.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/README.md +1 -1
- package/dist/cli-registry.mjs +9 -0
- package/dist/cli-registry.mjs.map +1 -1
- package/dist/commands/chat/chat.mjs +54 -4
- package/dist/commands/chat/chat.mjs.map +1 -1
- package/dist/commands/lifecycle/install.mjs +12 -5
- package/dist/commands/lifecycle/install.mjs.map +1 -1
- package/dist/commands/lifecycle/uninstall.mjs +2 -1
- package/dist/commands/lifecycle/uninstall.mjs.map +1 -1
- package/dist/lib/host-config.d.mts +5 -3
- package/dist/lib/host-config.mjs +89 -31
- package/dist/lib/host-config.mjs.map +1 -1
- package/docs/architecture/storage-model.md +4 -1
- package/docs/architecture.md +2 -2
- package/docs/cli.md +10 -8
- package/docs/for-ai/skills/okstra-brief-gen.md +1 -1
- package/docs/for-ai/skills/okstra-chat.md +3 -3
- package/docs/for-ai/skills/okstra-inspect.md +11 -1
- package/docs/for-ai/skills/okstra-rollup.md +1 -0
- package/docs/for-ai/skills/okstra-run.md +5 -4
- package/docs/for-ai/skills/okstra-user-response.md +1 -1
- package/docs/project-structure-overview.md +17 -5
- package/docs/task-process/README.md +1 -1
- package/docs/task-process/error-analysis.md +2 -2
- package/docs/task-process/final-verification.md +1 -1
- package/docs/task-process/implementation.md +1 -1
- package/docs/task-process/release-handoff.md +8 -6
- package/docs/task-process/requirements-discovery.md +1 -1
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/claude-worker.md +4 -0
- package/runtime/bin/okstra-report-translate.py +10 -4
- package/runtime/prompts/launch.template.md +11 -5
- package/runtime/prompts/lead/adapters/cmux.md +4 -7
- package/runtime/prompts/lead/context-loader.md +2 -0
- package/runtime/prompts/lead/convergence.md +20 -83
- package/runtime/prompts/lead/okstra-lead-contract.md +24 -6
- package/runtime/prompts/lead/plan-body-verification.md +10 -3
- package/runtime/prompts/lead/report-writer.md +7 -4
- package/runtime/prompts/lead/team-contract.md +15 -9
- package/runtime/prompts/profiles/_common-contract.md +1 -0
- package/runtime/prompts/profiles/_implementation-deliverable.md +2 -0
- package/runtime/prompts/profiles/_implementation-diff-review.md +4 -0
- package/runtime/prompts/profiles/_implementation-executor.md +9 -5
- package/runtime/prompts/profiles/_implementation-self-check.md +2 -0
- package/runtime/prompts/profiles/_implementation-verifier.md +3 -4
- package/runtime/prompts/profiles/_stage-discipline.md +12 -5
- package/runtime/prompts/profiles/final-verification.md +1 -1
- package/runtime/prompts/profiles/implementation.md +2 -0
- package/runtime/prompts/profiles/release-handoff.md +4 -3
- package/runtime/prompts/wizard/prompts.ko.json +2 -1
- package/runtime/python/okstra_ctl/adapters/dispatch/cmux.py +6 -0
- package/runtime/python/okstra_ctl/adapters/hosts/antigravity/adapter.py +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/antigravity/relay.md +2 -2
- package/runtime/python/okstra_ctl/adapters/hosts/capability_adapter.py +9 -0
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +3 -3
- package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +17 -3
- package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/external/relay.md +3 -3
- package/runtime/python/okstra_ctl/adapters/hosts/grok/adapter.py +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +2 -2
- package/runtime/python/okstra_ctl/adapters/hosts/kimi/adapter.py +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +2 -2
- package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +3 -3
- package/runtime/python/okstra_ctl/agent/invocation.py +107 -5
- package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +16 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/dynamic_verifier.py +3 -2
- package/runtime/python/okstra_ctl/agent/prompt_cli/jobs.py +87 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +72 -3
- package/runtime/python/okstra_ctl/analysis_packet.py +47 -6
- package/runtime/python/okstra_ctl/cmux.py +34 -13
- package/runtime/python/okstra_ctl/consumers.py +30 -7
- package/runtime/python/okstra_ctl/convergence.py +110 -21
- package/runtime/python/okstra_ctl/convergence_provenance.py +83 -0
- package/runtime/python/okstra_ctl/dispatch_core.py +127 -5
- package/runtime/python/okstra_ctl/dispatch_state.py +17 -9
- package/runtime/python/okstra_ctl/domain/host.py +5 -0
- package/runtime/python/okstra_ctl/domain/wizard/interaction.py +1 -0
- package/runtime/python/okstra_ctl/error_log_write.py +44 -4
- package/runtime/python/okstra_ctl/execution_mutation_audit.py +84 -7
- package/runtime/python/okstra_ctl/fixed_text.py +25 -7
- package/runtime/python/okstra_ctl/group_context.py +475 -10
- package/runtime/python/okstra_ctl/handoff.py +109 -32
- package/runtime/python/okstra_ctl/handoff_verification.py +80 -0
- package/runtime/python/okstra_ctl/initial_prompt_materialization.py +52 -10
- package/runtime/python/okstra_ctl/lead_progress.py +291 -0
- package/runtime/python/okstra_ctl/model_io/renderers.py +60 -1
- package/runtime/python/okstra_ctl/model_io_cli.py +6 -1
- package/runtime/python/okstra_ctl/ports/worker_dispatch.py +4 -0
- package/runtime/python/okstra_ctl/recap.py +179 -17
- package/runtime/python/okstra_ctl/reconcile.py +55 -4
- package/runtime/python/okstra_ctl/render.py +10 -1
- package/runtime/python/okstra_ctl/report_assembly.py +7 -6
- package/runtime/python/okstra_ctl/report_finalize.py +204 -11
- package/runtime/python/okstra_ctl/report_html/render.py +15 -4
- package/runtime/python/okstra_ctl/run.py +48 -14
- package/runtime/python/okstra_ctl/stage_targets.py +66 -0
- package/runtime/python/okstra_ctl/verdict_blocks.py +39 -12
- package/runtime/python/okstra_ctl/wizard/__init__.py +148 -0
- package/runtime/python/okstra_ctl/wizard/__main__.py +13 -0
- package/runtime/python/okstra_ctl/wizard/cli.py +176 -0
- package/runtime/python/okstra_ctl/wizard/confirmation.py +331 -0
- package/runtime/python/okstra_ctl/wizard/engine.py +363 -0
- package/runtime/python/okstra_ctl/wizard/ids.py +411 -0
- package/runtime/python/okstra_ctl/wizard/prompts.py +202 -0
- package/runtime/python/okstra_ctl/wizard/registry.py +836 -0
- package/runtime/python/okstra_ctl/wizard/render.py +189 -0
- package/runtime/python/okstra_ctl/wizard/roles.py +737 -0
- package/runtime/python/okstra_ctl/wizard/sources.py +703 -0
- package/runtime/python/okstra_ctl/wizard/state.py +689 -0
- package/runtime/python/okstra_ctl/wizard/statefile.py +145 -0
- package/runtime/python/okstra_ctl/wizard/steps_analysis.py +558 -0
- package/runtime/python/okstra_ctl/wizard/steps_identity.py +828 -0
- package/runtime/python/okstra_ctl/wizard/steps_options.py +340 -0
- package/runtime/python/okstra_ctl/wizard/steps_plan.py +959 -0
- package/runtime/python/okstra_ctl/wizard/steps_roles.py +672 -0
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +43 -3
- package/runtime/python/okstra_ctl/worker_prompt_headers.py +14 -0
- package/runtime/python/okstra_ctl/workflow.py +2 -2
- package/runtime/python/okstra_ctl/worktree/__init__.py +2 -0
- package/runtime/python/okstra_ctl/worktree/cleanliness.py +7 -4
- package/runtime/python/okstra_ctl/worktree/git_ops.py +7 -0
- package/runtime/python/okstra_ctl/worktree/naming.py +15 -6
- package/runtime/python/okstra_ctl/worktree/provision.py +2 -1
- package/runtime/python/okstra_ctl/worktree_registry.py +27 -0
- package/runtime/python/okstra_ctl/wrapper_status.py +4 -0
- package/runtime/skills/okstra-brief-gen/SKILL.md +22 -3
- package/runtime/skills/okstra-chat/SKILL.md +8 -6
- package/runtime/skills/okstra-inspect/SKILL.md +2 -2
- package/runtime/skills/okstra-inspect/facets/recap.md +52 -4
- package/runtime/skills/okstra-rollup/SKILL.md +1 -1
- package/runtime/skills/okstra-run/SKILL.md +17 -7
- package/runtime/skills/okstra-schedule-gen/SKILL.md +2 -0
- package/runtime/skills/okstra-user-response/SKILL.md +1 -1
- package/runtime/templates/reports/brief.template.md +15 -7
- package/runtime/templates/reports/final-verification-input.template.md +2 -0
- package/runtime/templates/reports/group-context.template.md +7 -0
- package/runtime/templates/reports/html/tasks/release-handoff.template.html +2 -2
- package/runtime/templates/reports/implementation-planning-input.template.md +3 -0
- package/runtime/templates/reports/improvement-discovery-input.template.md +3 -0
- package/runtime/templates/reports/release-handoff-input.template.md +5 -3
- package/runtime/templates/reports/schedule.template.md +13 -4
- package/runtime/templates/reports/task-brief.template.md +1 -1
- package/runtime/templates/reverify-output-contract.md +5 -0
- package/runtime/templates/worker-error-contract.md +2 -0
- package/runtime/templates/worker-prompt-preamble.md +1 -1
- package/runtime/validators/validate-run.py +81 -22
- package/runtime/validators/validate_session_conformance.py +102 -2
- package/runtime/python/okstra_ctl/wizard.py +0 -7168
|
@@ -508,6 +508,42 @@ def _read_scoped_lead_activities(
|
|
|
508
508
|
return activities, events_path, None
|
|
509
509
|
|
|
510
510
|
|
|
511
|
+
# 리드가 `progress` 행을 빠뜨려도 같은 사실이 activity 원장에 남아 있는
|
|
512
|
+
# 체크포인트. 값은 `okstra agent-activity append --kind` 가 받는 것과 같고,
|
|
513
|
+
# 왼쪽이 그 kind, 오른쪽이 그것이 증명하는 PROGRESS phase 다.
|
|
514
|
+
_ACTIVITY_PROGRESS_PHASE = {
|
|
515
|
+
"worker-dispatched": "phase-4-dispatch",
|
|
516
|
+
"worker-completed": "phase-5-collect",
|
|
517
|
+
"verification-round-completed": "phase-5.5-convergence",
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
def _progress_from_activity(event) -> tuple[str, str, str] | None:
|
|
522
|
+
"""activity 한 행이 증명하는 PROGRESS 체크포인트.
|
|
523
|
+
|
|
524
|
+
`PROGRESS:` 는 사용자가 보는 대화 텍스트이고, artifact-only 호스트에서는
|
|
525
|
+
리드가 그것을 `leadEventsPath` 에 손으로 append 해야 검증에 잡힌다. 리드가
|
|
526
|
+
그 행을 빠뜨리면 워커를 실제로 띄우고 거둔 run 도 체크포인트 전건 누락으로
|
|
527
|
+
보고됐다 — 그 사실이 `okstra agent-activity append` 가 쓴 activity 행에
|
|
528
|
+
이미 기록돼 있는데도(실측: dev-10784 error-analysis, advisory 22건 중 9건이
|
|
529
|
+
activity 원장으로 확인 가능한 항목이었다). 원장에 있는 것은 원장에서 읽는다.
|
|
530
|
+
|
|
531
|
+
나머지 체크포인트(intake·prompts·team-create·synthesis·persist)는 대응하는
|
|
532
|
+
activity kind 가 없다. 그것들은 여전히 리드가 남겨야 하고, 없으면 없다고
|
|
533
|
+
보고된다.
|
|
534
|
+
"""
|
|
535
|
+
details = event.details
|
|
536
|
+
phase = _ACTIVITY_PROGRESS_PHASE.get(str(details.get("kind") or ""))
|
|
537
|
+
if phase is None:
|
|
538
|
+
return None
|
|
539
|
+
agent = str(details.get("agent") or "").strip()
|
|
540
|
+
if not agent or agent == "okstra-lead":
|
|
541
|
+
# 리드 자신을 주체로 적은 행은 워커를 지목하지 않는다. 워커별 체크포인트
|
|
542
|
+
# 검사는 이름을 대조하므로, 이름 없는 행으로 그 검사를 만족시키지 않는다.
|
|
543
|
+
return (event.timestamp, phase, f"PROGRESS: {phase}")
|
|
544
|
+
return (event.timestamp, phase, f"PROGRESS: {phase} worker={agent}")
|
|
545
|
+
|
|
546
|
+
|
|
511
547
|
def _progress_line_from_event(event) -> tuple[str, str, str] | None:
|
|
512
548
|
details = event.details
|
|
513
549
|
phase = details.get("phase")
|
|
@@ -568,6 +604,7 @@ def _collect_artifact_lead_evidence(
|
|
|
568
604
|
|
|
569
605
|
run_seq = _run_sequence(run_manifest, suffix)
|
|
570
606
|
evidence = _LeadEvidence(scanned_files=[events_path])
|
|
607
|
+
from_activities: list[tuple[str, str, str]] = []
|
|
571
608
|
for event in events:
|
|
572
609
|
if not _event_matches_run(
|
|
573
610
|
event, team_state, run_manifest, task_type, run_seq
|
|
@@ -575,6 +612,9 @@ def _collect_artifact_lead_evidence(
|
|
|
575
612
|
continue
|
|
576
613
|
if event.event_type == "activity":
|
|
577
614
|
evidence.activities.append(event)
|
|
615
|
+
derived = _progress_from_activity(event)
|
|
616
|
+
if derived is not None:
|
|
617
|
+
from_activities.append(derived)
|
|
578
618
|
elif event.event_type in ("progress", "progress-checkpoint"):
|
|
579
619
|
progress = _progress_line_from_event(event)
|
|
580
620
|
if progress is not None:
|
|
@@ -585,6 +625,12 @@ def _collect_artifact_lead_evidence(
|
|
|
585
625
|
basename, timestamp = read
|
|
586
626
|
evidence.sidecar_reads.setdefault(basename, []).append(timestamp)
|
|
587
627
|
|
|
628
|
+
if not evidence.progress:
|
|
629
|
+
# 리드가 `progress` 행을 하나도 남기지 않은 run 에서만 원장으로 대신
|
|
630
|
+
# 읽는다. 한 줄이라도 남긴 run 에서는 그 줄들이 검사 대상이다 — 거기서
|
|
631
|
+
# 원장을 섞으면 "PROGRESS 라인의 `worker=` 가 로스터 역할과 일치하는가"
|
|
632
|
+
# 라는 서술 정확성 검사가 대조할 것을 잃는다.
|
|
633
|
+
evidence.progress.extend(from_activities)
|
|
588
634
|
evidence.progress.sort()
|
|
589
635
|
for ts_list in evidence.sidecar_reads.values():
|
|
590
636
|
ts_list.sort()
|
|
@@ -1299,6 +1345,7 @@ def _check_activity_contract(
|
|
|
1299
1345
|
def _check_user_confirm_checkpoints(
|
|
1300
1346
|
by_phase: dict[str, list[tuple[str, str]]],
|
|
1301
1347
|
asked_ids: list[str],
|
|
1348
|
+
activities: list,
|
|
1302
1349
|
errors: list[str],
|
|
1303
1350
|
) -> None:
|
|
1304
1351
|
""""물어봤다"는 리포트의 기록에는 물어본 흔적이 세션에 남아 있어야 한다.
|
|
@@ -1313,8 +1360,21 @@ def _check_user_confirm_checkpoints(
|
|
|
1313
1360
|
return
|
|
1314
1361
|
detail = "prompts/lead/okstra-lead-contract.md 'User confirmation before an approval blocker'"
|
|
1315
1362
|
asked_lines = " ".join(line for _ts, line in by_phase.get("user-confirm", []))
|
|
1363
|
+
# 원장이 더 강한 증거다. `okstra agent-activity append --kind
|
|
1364
|
+
# user-decision-required --evidence-ref C-NNN` 이 남긴 행은 리드가 그
|
|
1365
|
+
# 질문을 실제로 냈다는 구조화된 기록이고, 대화에 같은 문장을 냈는지보다
|
|
1366
|
+
# 확실하다. 실측(dev-10784 error-analysis): 리드가 C-001·C-002 를 묻고
|
|
1367
|
+
# 두 행을 정확히 남겼는데, 이 검사가 대화 텍스트만 보아 둘 다 누락으로
|
|
1368
|
+
# 보고했다.
|
|
1369
|
+
asked_in_ledger = {
|
|
1370
|
+
ref
|
|
1371
|
+
for event in activities
|
|
1372
|
+
if event.details.get("kind") == "user-decision-required"
|
|
1373
|
+
for ref in (event.details.get("evidenceRefs") or [])
|
|
1374
|
+
if isinstance(ref, str)
|
|
1375
|
+
}
|
|
1316
1376
|
for row_id in asked_ids:
|
|
1317
|
-
if row_id in asked_lines:
|
|
1377
|
+
if row_id in asked_lines or row_id in asked_in_ledger:
|
|
1318
1378
|
continue
|
|
1319
1379
|
errors.append(
|
|
1320
1380
|
f"PROGRESS checkpoint missing: `user-confirm {row_id}` — the final "
|
|
@@ -1325,6 +1385,38 @@ def _check_user_confirm_checkpoints(
|
|
|
1325
1385
|
)
|
|
1326
1386
|
|
|
1327
1387
|
|
|
1388
|
+
def _check_user_confirm_activities(
|
|
1389
|
+
evidence: _LeadEvidence,
|
|
1390
|
+
report_path: Path,
|
|
1391
|
+
errors: list[str],
|
|
1392
|
+
) -> None:
|
|
1393
|
+
"""artifact-only 호스트에서 "물어봤다"를 확인하는 자리.
|
|
1394
|
+
|
|
1395
|
+
`_check_user_confirm_checkpoints` 와 같은 질문에 답하되, 근거를 대화
|
|
1396
|
+
텍스트가 아니라 activity 원장의 `user-decision-required` 행에서 찾는다.
|
|
1397
|
+
리드는 `okstra agent-activity append --kind user-decision-required
|
|
1398
|
+
--evidence-ref C-NNN` 으로 그 행을 남긴다.
|
|
1399
|
+
"""
|
|
1400
|
+
asked_ids = _ids_reported_as_asked(report_path)
|
|
1401
|
+
if not asked_ids:
|
|
1402
|
+
return
|
|
1403
|
+
required = [
|
|
1404
|
+
event
|
|
1405
|
+
for event in evidence.activities
|
|
1406
|
+
if event.details.get("kind") == "user-decision-required"
|
|
1407
|
+
]
|
|
1408
|
+
for row_id in asked_ids:
|
|
1409
|
+
if any(_activity_references(event, row_id) for event in required):
|
|
1410
|
+
continue
|
|
1411
|
+
errors.append(
|
|
1412
|
+
f"activity contract: the final report records `{row_id}` as an "
|
|
1413
|
+
"approval blocker the user was asked about, but no "
|
|
1414
|
+
"`user-decision-required` activity references it. Ask before "
|
|
1415
|
+
"writing the row, then record it with `okstra agent-activity "
|
|
1416
|
+
f"append --kind user-decision-required --evidence-ref {row_id}`."
|
|
1417
|
+
)
|
|
1418
|
+
|
|
1419
|
+
|
|
1328
1420
|
def _phase_mentions_worker(
|
|
1329
1421
|
lines: list[tuple[str, str]], roles: set[str]
|
|
1330
1422
|
) -> bool:
|
|
@@ -1525,7 +1617,7 @@ def _check_progress_checkpoints(
|
|
|
1525
1617
|
by_phase, _plan_body_rounds_ran(run_dir, suffix), narration
|
|
1526
1618
|
)
|
|
1527
1619
|
_check_user_confirm_checkpoints(
|
|
1528
|
-
by_phase, _ids_reported_as_asked(report_path), errors
|
|
1620
|
+
by_phase, _ids_reported_as_asked(report_path), evidence.activities, errors
|
|
1529
1621
|
)
|
|
1530
1622
|
|
|
1531
1623
|
|
|
@@ -1744,6 +1836,7 @@ def _check_entry_guard_reads(
|
|
|
1744
1836
|
errors: list[str],
|
|
1745
1837
|
instruction_set: Path | None,
|
|
1746
1838
|
task_type: str,
|
|
1839
|
+
evidence_source: str = "claude-jsonl",
|
|
1747
1840
|
) -> None:
|
|
1748
1841
|
"""검사 3 — entry guard. fresh-read 규칙(이전 run 기억으로 갈음 불가)은 run
|
|
1749
1842
|
윈도우 스코핑이 보장한다: 이번 윈도우 안의 Read 만 증거로 인정된다.
|
|
@@ -1751,6 +1844,12 @@ def _check_entry_guard_reads(
|
|
|
1751
1844
|
anchor 가 있는 행은 존재 + 순서를, anchor 가 `None` 인 행은 존재만 본다.
|
|
1752
1845
|
`staged_per_run` 행은 이 run 의 instruction-set 에 실제로 있을 때만,
|
|
1753
1846
|
`required_when` 행은 그 PROGRESS 체크포인트가 이 run 에 있을 때만 요구한다."""
|
|
1847
|
+
if evidence_source == "artifact-only":
|
|
1848
|
+
# `_check_cmux_adapter_read` 와 같은 사유다: artifact-only 호스트의
|
|
1849
|
+
# 리드는 파일을 읽어도 그 사실을 남길 도구 기록이 없다. 그 자리에서
|
|
1850
|
+
# "읽은 흔적이 없다"는 읽지 않았다는 뜻이 아니라 기록 형식이 없다는
|
|
1851
|
+
# 뜻이고, 그 둘을 구분하지 못하는 검사는 판정하지 않는다.
|
|
1852
|
+
return
|
|
1754
1853
|
seen_phases = {phase for _ts, phase, _line in evidence.progress}
|
|
1755
1854
|
anchor_phases = {row.anchor[0] for row in _ENTRY_GUARD_READS if row.anchor}
|
|
1756
1855
|
anchors: dict[str, str] = {}
|
|
@@ -1859,5 +1958,6 @@ def validate_session_conformance(
|
|
|
1859
1958
|
result.errors,
|
|
1860
1959
|
_instruction_set_dir(run_dir, suffix, project_root),
|
|
1861
1960
|
task_type,
|
|
1961
|
+
evidence_source,
|
|
1862
1962
|
)
|
|
1863
1963
|
return result
|