okstra 0.102.2 → 0.102.4

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 (167) hide show
  1. package/README.kr.md +5 -5
  2. package/README.md +5 -5
  3. package/docs/kr/architecture/storage-model.md +8 -3
  4. package/docs/kr/architecture.md +12 -13
  5. package/docs/kr/cli.md +4 -4
  6. package/docs/kr/container.md +1 -1
  7. package/docs/kr/performance-improvement-plan-v2.md +2 -2
  8. package/docs/project-structure-overview.md +2 -2
  9. package/package.json +7 -2
  10. package/runtime/BUILD.json +2 -2
  11. package/runtime/bin/lib/okstra/interactive.sh +12 -0
  12. package/runtime/bin/okstra-antigravity-exec.sh +1 -2
  13. package/runtime/bin/okstra-codex-exec.sh +1 -2
  14. package/runtime/bin/okstra-render-final-report.py +2 -9
  15. package/runtime/bin/okstra-spawn-followups.py +4 -6
  16. package/runtime/bin/okstra-trace-cleanup.sh +24 -4
  17. package/runtime/prompts/lead/okstra-lead-contract.md +2 -2
  18. package/runtime/prompts/lead/report-writer.md +1 -1
  19. package/runtime/prompts/profiles/_common-contract.md +9 -11
  20. package/runtime/python/okstra_ctl/codex_dispatch.py +6 -13
  21. package/runtime/python/okstra_ctl/consumers.py +35 -0
  22. package/runtime/python/okstra_ctl/container.py +4 -6
  23. package/runtime/python/okstra_ctl/dispatch_core.py +8 -13
  24. package/runtime/python/okstra_ctl/final_report_paths.py +24 -0
  25. package/runtime/python/okstra_ctl/handoff.py +2 -1
  26. package/runtime/python/okstra_ctl/implementation_outcome.py +271 -0
  27. package/runtime/python/okstra_ctl/implementation_stage.py +7 -11
  28. package/runtime/python/okstra_ctl/path_hints.py +665 -0
  29. package/runtime/python/okstra_ctl/render.py +4 -3
  30. package/runtime/python/okstra_ctl/report_view_artifacts.py +14 -0
  31. package/runtime/python/okstra_ctl/report_views.py +7 -4
  32. package/runtime/python/okstra_ctl/run.py +3 -10
  33. package/runtime/python/okstra_ctl/run_context.py +4 -2
  34. package/runtime/python/okstra_ctl/stage_targets.py +18 -0
  35. package/runtime/python/okstra_ctl/wizard.py +37 -26
  36. package/runtime/python/okstra_ctl/wizard_stage_intent.py +54 -0
  37. package/runtime/python/okstra_project/state.py +40 -2
  38. package/runtime/python/okstra_token_usage/report.py +2 -5
  39. package/runtime/validators/validate-report-views.py +2 -1
  40. package/runtime/validators/validate-run.py +1 -11
  41. package/src/commands/lifecycle/install.mjs +5 -5
  42. package/src/commands/lifecycle/uninstall.mjs +4 -4
  43. package/docs/superpowers/plans/2026-05-12-ticket-id-in-reports.md +0 -638
  44. package/docs/superpowers/plans/2026-05-14-convergence-queue-pruning.md +0 -1568
  45. package/docs/superpowers/plans/2026-05-17-dual-format-final-report.md +0 -167
  46. package/docs/superpowers/plans/2026-05-20-final-report-language.md +0 -1501
  47. package/docs/superpowers/plans/2026-05-20-implementation-planning-multi-stage.md +0 -1267
  48. package/docs/superpowers/plans/2026-05-20-okstra-run-prompt-sot-b1.md +0 -1007
  49. package/docs/superpowers/plans/2026-05-20-wizard-messages-json-sot.md +0 -720
  50. package/docs/superpowers/plans/2026-05-20-wizard-prompt-json-sot-a1.md +0 -681
  51. package/docs/superpowers/plans/2026-05-21-improvement-discovery-task-type.md +0 -1691
  52. package/docs/superpowers/plans/2026-05-24-implementation-lead-context-slimming.md +0 -1700
  53. package/docs/superpowers/plans/2026-05-25-okstra-project-root-rename.md +0 -158
  54. package/docs/superpowers/plans/2026-05-26-wizard-3-option-picker.md +0 -860
  55. package/docs/superpowers/plans/2026-06-02-final-verification-protocol-hardening.md +0 -326
  56. package/docs/superpowers/plans/2026-06-02-okstra-run-branch-confirm-step.md +0 -337
  57. package/docs/superpowers/plans/2026-06-02-okstra-run-phase-pane-cleanup.md +0 -410
  58. package/docs/superpowers/plans/2026-06-02-requirements-discovery-fanout.md +0 -728
  59. package/docs/superpowers/plans/2026-06-04-adversarial-implementation-planning.md +0 -294
  60. package/docs/superpowers/plans/2026-06-04-adversarial-verification.md +0 -570
  61. package/docs/superpowers/plans/2026-06-04-coverage-critic.md +0 -516
  62. package/docs/superpowers/plans/2026-06-04-stage-cohesion-planner.md +0 -351
  63. package/docs/superpowers/plans/2026-06-04-stage-run-batching.md +0 -457
  64. package/docs/superpowers/plans/2026-06-05-acceptance-critic.md +0 -251
  65. package/docs/superpowers/plans/2026-06-05-compact-markdown-report-tables.md +0 -323
  66. package/docs/superpowers/plans/2026-06-05-wizard-batch-prompts.md +0 -559
  67. package/docs/superpowers/plans/2026-06-06-final-verification-whole-task-gate.md +0 -993
  68. package/docs/superpowers/plans/2026-06-06-stage-parallel-and-pending-fixes.md +0 -93
  69. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p1.md +0 -447
  70. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p2.md +0 -289
  71. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p3.md +0 -774
  72. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p4.md +0 -303
  73. package/docs/superpowers/plans/2026-06-06-stage-worktree-isolation-p5-multidep-base.md +0 -387
  74. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase2.md +0 -275
  75. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase3.md +0 -282
  76. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4a.md +0 -147
  77. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4b.md +0 -262
  78. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4c.md +0 -184
  79. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4d.md +0 -88
  80. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa-phase4e.md +0 -250
  81. package/docs/superpowers/plans/2026-06-07-stage-conformance-qa.md +0 -409
  82. package/docs/superpowers/plans/2026-06-09-implementation-run-artifact-stage-isolation.md +0 -320
  83. package/docs/superpowers/plans/2026-06-10-concurrent-run-team-guard.md +0 -456
  84. package/docs/superpowers/plans/2026-06-10-git-reconcile-stale-sha-recovery.md +0 -1408
  85. package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling-PROBE.md +0 -42
  86. package/docs/superpowers/plans/2026-06-10-lead-worker-completion-polling.md +0 -337
  87. package/docs/superpowers/plans/2026-06-10-p6-token-usage-incremental.md +0 -1029
  88. package/docs/superpowers/plans/2026-06-10-stage-group-handoff.md +0 -1572
  89. package/docs/superpowers/plans/2026-06-11-fix-cycle.md +0 -1290
  90. package/docs/superpowers/plans/2026-06-11-wizard-whole-task-final-verification.md +0 -526
  91. package/docs/superpowers/plans/2026-06-12-html-plan-approval.md +0 -1000
  92. package/docs/superpowers/plans/2026-06-13-repo-risk-hardening.md +0 -493
  93. package/docs/superpowers/plans/2026-06-14-host-runtime-auto-execution.md +0 -1775
  94. package/docs/superpowers/plans/2026-06-15-coding-preflight-pack-dispatch-path.md +0 -504
  95. package/docs/superpowers/plans/2026-06-15-internal-skill-migration-final-fixups.md +0 -342
  96. package/docs/superpowers/plans/2026-06-15-internal-skill-migration-fixups.md +0 -258
  97. package/docs/superpowers/plans/2026-06-15-internal-skill-migration-remaining-fixups.md +0 -387
  98. package/docs/superpowers/plans/2026-06-15-internal-skill-resource-migration.md +0 -749
  99. package/docs/superpowers/plans/2026-06-15-worker-prompt-anchor-final-fixups.md +0 -828
  100. package/docs/superpowers/plans/2026-06-15-worker-prompt-header-error-contract.md +0 -490
  101. package/docs/superpowers/plans/2026-06-17-okstra-error-report.md +0 -724
  102. package/docs/superpowers/plans/2026-06-18-subagent-pane-reclaim.md +0 -483
  103. package/docs/superpowers/plans/2026-06-19-agent-operating-standard.md +0 -476
  104. package/docs/superpowers/plans/2026-06-19-okstra-inspect-recap-facet.md +0 -647
  105. package/docs/superpowers/plans/2026-06-20-error-feedback-loop.md +0 -1019
  106. package/docs/superpowers/plans/2026-06-20-run-index-row-normalization.md +0 -583
  107. package/docs/superpowers/plans/2026-06-20-stage-auto-integrate-teardown.md +0 -819
  108. package/docs/superpowers/plans/2026-06-21-okstra-container-local-user-test.md +0 -714
  109. package/docs/superpowers/plans/2026-06-21-release-handoff-local-checkout.md +0 -348
  110. package/docs/superpowers/plans/2026-06-23-implementation-stage-multiselect-chain.md +0 -630
  111. package/docs/superpowers/plans/2026-06-23-implementation-step-commit-granularity.md +0 -274
  112. package/docs/superpowers/plans/2026-06-23-phase-batch-cleanup-enforcement.md +0 -409
  113. package/docs/superpowers/plans/2026-06-24-cross-project-precondition.md +0 -542
  114. package/docs/superpowers/plans/2026-06-24-decision-drafts-render-gap.md +0 -568
  115. package/docs/superpowers/plans/2026-06-24-manual-user-test-section.md +0 -203
  116. package/docs/superpowers/plans/2026-06-24-okstra-container-build-rename.md +0 -525
  117. package/docs/superpowers/specs/2026-05-12-ticket-id-in-reports-design.md +0 -131
  118. package/docs/superpowers/specs/2026-05-15-implementation-plan-verification-design.md +0 -254
  119. package/docs/superpowers/specs/2026-05-20-final-report-language-design.md +0 -383
  120. package/docs/superpowers/specs/2026-05-20-implementation-planning-multi-stage-design.md +0 -322
  121. package/docs/superpowers/specs/2026-05-20-okstra-run-prompt-sot-design.md +0 -299
  122. package/docs/superpowers/specs/2026-05-21-improvement-discovery-task-type-design.md +0 -335
  123. package/docs/superpowers/specs/2026-06-02-okstra-run-branch-confirm-step-design.md +0 -113
  124. package/docs/superpowers/specs/2026-06-02-okstra-run-phase-pane-cleanup-design.md +0 -173
  125. package/docs/superpowers/specs/2026-06-02-requirements-discovery-fanout-design.md +0 -154
  126. package/docs/superpowers/specs/2026-06-04-adversarial-implementation-planning-design.md +0 -90
  127. package/docs/superpowers/specs/2026-06-04-adversarial-verification-design.md +0 -176
  128. package/docs/superpowers/specs/2026-06-04-coverage-critic-design.md +0 -99
  129. package/docs/superpowers/specs/2026-06-04-stage-splitting-cost-aware-design.md +0 -98
  130. package/docs/superpowers/specs/2026-06-05-acceptance-critic-design.md +0 -90
  131. package/docs/superpowers/specs/2026-06-05-compact-markdown-report-tables-design.md +0 -87
  132. package/docs/superpowers/specs/2026-06-05-wizard-batch-prompts-design.md +0 -121
  133. package/docs/superpowers/specs/2026-06-06-final-verification-whole-task-gate-design.md +0 -126
  134. package/docs/superpowers/specs/2026-06-06-stage-worktree-isolation-design.md +0 -180
  135. package/docs/superpowers/specs/2026-06-06-vertical-slice-tdd-planning-design.md +0 -179
  136. package/docs/superpowers/specs/2026-06-07-stage-conformance-qa-design.md +0 -169
  137. package/docs/superpowers/specs/2026-06-09-executor-model-custom-id-cascade-design.md +0 -66
  138. package/docs/superpowers/specs/2026-06-09-implementation-run-artifact-stage-isolation-design.md +0 -87
  139. package/docs/superpowers/specs/2026-06-10-blocking-contract-posthoc-conformance-design.md +0 -168
  140. package/docs/superpowers/specs/2026-06-10-concurrent-run-team-guard-design.md +0 -107
  141. package/docs/superpowers/specs/2026-06-10-git-reconcile-stale-sha-recovery-design.md +0 -105
  142. package/docs/superpowers/specs/2026-06-10-lead-worker-completion-polling-design.md +0 -113
  143. package/docs/superpowers/specs/2026-06-10-stage-group-handoff-design.md +0 -156
  144. package/docs/superpowers/specs/2026-06-11-brief-entry-only-handoff-stage-entry-design.md +0 -158
  145. package/docs/superpowers/specs/2026-06-11-fix-cycle-design.md +0 -94
  146. package/docs/superpowers/specs/2026-06-11-wizard-whole-task-final-verification-design.md +0 -89
  147. package/docs/superpowers/specs/2026-06-12-codex-lead-adapter-design.md +0 -358
  148. package/docs/superpowers/specs/2026-06-12-html-plan-approval-design.md +0 -85
  149. package/docs/superpowers/specs/2026-06-12-stage-discipline-rule-design.md +0 -108
  150. package/docs/superpowers/specs/2026-06-13-forbidden-actions-ssot-design.md +0 -134
  151. package/docs/superpowers/specs/2026-06-13-neutral-tmux-lead-adapter-design.md +0 -284
  152. package/docs/superpowers/specs/2026-06-14-host-runtime-auto-execution-design.md +0 -404
  153. package/docs/superpowers/specs/2026-06-17-okstra-error-report-design.md +0 -123
  154. package/docs/superpowers/specs/2026-06-18-subagent-pane-reclaim-design.md +0 -150
  155. package/docs/superpowers/specs/2026-06-19-agent-operating-standard-design.md +0 -120
  156. package/docs/superpowers/specs/2026-06-19-okstra-inspect-recap-facet-design.md +0 -96
  157. package/docs/superpowers/specs/2026-06-20-error-feedback-loop-design.md +0 -171
  158. package/docs/superpowers/specs/2026-06-20-run-index-row-normalization-design.md +0 -112
  159. package/docs/superpowers/specs/2026-06-20-stage-auto-integrate-teardown-design.md +0 -145
  160. package/docs/superpowers/specs/2026-06-21-okstra-container-local-user-test-design.md +0 -125
  161. package/docs/superpowers/specs/2026-06-21-release-handoff-local-checkout-design.md +0 -113
  162. package/docs/superpowers/specs/2026-06-23-implementation-stage-multiselect-chain-design.md +0 -138
  163. package/docs/superpowers/specs/2026-06-23-implementation-step-commit-granularity-design.md +0 -120
  164. package/docs/superpowers/specs/2026-06-24-cross-project-precondition-design.md +0 -129
  165. package/docs/superpowers/specs/2026-06-24-decision-drafts-render-gap-design.md +0 -185
  166. package/docs/superpowers/specs/2026-06-24-manual-user-test-section-design.md +0 -121
  167. package/docs/superpowers/specs/2026-06-24-okstra-container-build-rename-design.md +0 -110
@@ -1,483 +0,0 @@
1
- # Worker pane 완료-즉시 회수 + 내성 fallback 구현 계획
2
-
3
- > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
-
5
- **Goal:** 외부 CLI worker(codex/antigravity)의 trace pane 을 완료 즉시 회수하고, pane 생성 실패 시 in-process 대체로 run 이 멈추지 않게 하여 tmux pane 한도 초과를 방지한다.
6
-
7
- **Architecture:** wrapper 가 trace pane 에 자기 status 파일 경로를 태그(`@okstra_status`)로 단다 → `SubagentStop`/`TaskCompleted` 훅이 `active.jsonl` 의 활성 run 을 순회하며 `okstra-trace-cleanup.sh --reclaim-completed` 를 호출 → 그 모드는 status 가 `exited`(완료)인 trace pane 만 닫고 진행 중은 보존한다. 하니스가 만드는 teammate pane 은 okstra 가 태그할 수 없어 회수 대상에서 제외하고, lead 계약의 내성 fallback 으로 다룬다.
8
-
9
- **Tech Stack:** Bash(wrapper/cleanup/hook 엔트리), Python(`okstra_ctl` — 완료 판정은 기존 `wrapper_status.read_wrapper_status` 재사용), tmux user-options(`@okstra_*`), Claude Code hooks.
10
-
11
- ## Global Constraints
12
-
13
- - `runtime/` 는 빌드 산출물 — 직접 수정 금지. 소스는 `scripts/`, `templates/` 에 두고 `npm run build` 로 동기화([CLAUDE.md](../../../CLAUDE.md)).
14
- - 사용자 영향 수정은 seed/template 에 — 훅은 [templates/reports/settings.template.json](../../../templates/reports/settings.template.json) 에 배선(개인 `.claude/` 아님).
15
- - Bash 는 thin 엔트리/어댑터. 판정 로직은 Python 모듈 재사용 — Bash 에 비즈니스 로직 복제 금지.
16
- - 새/대폭 수정 함수는 유효 50줄 이내.
17
- - pre-1.0 — 하위호환 shim 없음.
18
- - 문서/주석 한국어(코드 식별자·경로·CLI 인자는 영어).
19
- - 완료 판정 SSOT: `wrapper_status.WrapperStatus.is_terminal`(`stage == "exited"`) — 새 판정 로직 만들지 말 것.
20
- - "worktree" 용어는 실제 git worktree 에만 — stage 폴더 상위는 "상위 디렉터리".
21
-
22
- ---
23
-
24
- ## Task 0: 실측 게이트 — teammate pane title 확인 (코드 작성 전 1회)
25
-
26
- 설계의 단 하나 미검증 가정: **하니스가 teammate(subagent) pane title 을 `*-worker` 로 다는가.** 이 결과가 회수 범위를 정한다(trace pane 만 vs teammate pane 도). tmux 안에서 실측한다.
27
-
28
- **Files:** 없음(조사).
29
-
30
- - [ ] **Step 1: tmux 세션 안에서 okstra worker 1개를 띄운 직후 pane title 덤프**
31
-
32
- tmux 안에서 `/okstra-run` 또는 직접 dispatch 로 worker 1개를 띄운 뒤:
33
-
34
- Run: `tmux list-panes -a -F '#{pane_id}\t#{pane_title}\t#{@okstra_trace_run}\t#{@okstra_worker_run}'`
35
-
36
- - [ ] **Step 2: 판정 기록**
37
-
38
- - teammate pane title 이 `claude-worker` / `codex-worker` / `antigravity-worker` / `report-writer-worker` 중 하나와 `*<title>*` 매칭되면 → **회수 가능**. 이 plan 의 Task 2 끝 "조건부 확장" 을 적용한다.
39
- - 매칭 안 되거나(빈 title, 하니스 고유 라벨) 같은 title 이 여러 worker 에 중복돼 진행중/완료 구분이 불가하면 → **trace pane 만 회수**. teammate 누적은 Task 5 내성에 의존(설계대로). 이 경우 Task 2 "조건부 확장" 은 건너뛴다.
40
- - 결과를 이 파일 Task 0 아래 한 줄로 적어 후속 task 가 참조하게 한다.
41
-
42
- > 실측 불가 환경(현재 세션이 tmux 밖)이면: trace pane 만 회수하는 경로로 진행하고, teammate 회수는 미적용으로 둔다. 이는 안전한 기본값이다(없는 기능을 가정해 진행 중 pane 을 죽이는 것보다 낫다).
43
-
44
- ---
45
-
46
- ## Task 1: wrapper 가 trace pane 에 `@okstra_status` 태그 추가
47
-
48
- trace pane 을 그 worker 의 status 파일과 연결한다. cleanup 이 이 태그로 완료 여부를 읽는다.
49
-
50
- **Files:**
51
- - Modify: `scripts/okstra-codex-exec.sh` (trace pane 태그 블록, 현재 `@okstra_trace_run` 설정부 근처 ~272-281)
52
- - Modify: `scripts/okstra-antigravity-exec.sh` (동일 블록 ~214-220)
53
-
54
- **Interfaces:**
55
- - Consumes: 각 wrapper 가 이미 보유한 `$status_path`(`${prompt_path%.md}.status.json`, codex:182 / antigravity:138)와 `$trace_pane`(split 결과 pane id).
56
- - Produces: trace pane 의 tmux user-option `@okstra_status=<status_path 절대경로>`.
57
-
58
- - [ ] **Step 1: codex wrapper — `@okstra_trace_run` 설정 직후 status 태그 추가**
59
-
60
- `scripts/okstra-codex-exec.sh` 의 `tmux set-option -p -t "$trace_pane" @okstra_trace_run "$run_dir"` 줄 **직후**에 추가:
61
-
62
- ```bash
63
- [[ -n "$status_path" ]] && tmux set-option -p -t "$trace_pane" @okstra_status "$status_path" 2>/dev/null || true
64
- ```
65
-
66
- - [ ] **Step 2: antigravity wrapper — 동일 추가**
67
-
68
- `scripts/okstra-antigravity-exec.sh` 의 동일한 `@okstra_trace_run` 설정 줄 직후에 같은 한 줄을 추가(변수명 `$status_path` / `$trace_pane` 동일).
69
-
70
- - [ ] **Step 3: 태그 라인이 두 파일에 들어갔는지 확인**
71
-
72
- Run: `grep -n '@okstra_status' scripts/okstra-codex-exec.sh scripts/okstra-antigravity-exec.sh`
73
- Expected: 두 파일 각각 1줄.
74
-
75
- - [ ] **Step 4: 커밋**
76
-
77
- ```bash
78
- git add scripts/okstra-codex-exec.sh scripts/okstra-antigravity-exec.sh
79
- git commit -m "feat(wrapper): trace pane 에 @okstra_status 태그를 달아 완료 회수 연결"
80
- ```
81
-
82
- ---
83
-
84
- ## Task 2: `okstra-trace-cleanup.sh --reclaim-completed` 모드
85
-
86
- 완료된(`stage == "exited"`) worker 의 trace pane 만 닫고 진행 중은 보존하는 모드. 완료 판정은 Python SSOT 를 호출한다.
87
-
88
- **Files:**
89
- - Create: `scripts/okstra_ctl/pane_reclaim.py` (완료 판정 wrapper — 테스트 대상)
90
- - Modify: `scripts/okstra-trace-cleanup.sh` (인자 파싱 + collect 에 완료 필터)
91
- - Test: `tests/test_pane_reclaim.py`
92
-
93
- **Interfaces:**
94
- - Consumes: trace pane 의 `@okstra_status` 태그(Task 1), `@okstra_trace_run` 태그(기존).
95
- - Produces: `pane_reclaim.is_completed_status(status_path: str) -> bool` (CLI: `python3 -m okstra_ctl.pane_reclaim <status_path>` → exit 0 완료 / 1 미완료·부재). `okstra-trace-cleanup.sh --reclaim-completed --run-dir <RUN_DIR>`.
96
-
97
- - [ ] **Step 1: 완료 판정 테스트 작성 (실패)**
98
-
99
- `tests/test_pane_reclaim.py`:
100
-
101
- ```python
102
- from pathlib import Path
103
- from okstra_ctl.pane_reclaim import is_completed_status
104
-
105
-
106
- def _write(p: Path, stage: str) -> Path:
107
- p.write_text('{"stage": "%s", "exit_code": 0}' % stage, encoding="utf-8")
108
- return p
109
-
110
-
111
- def test_exited_status_is_completed(tmp_path):
112
- assert is_completed_status(str(_write(tmp_path / "w.status.json", "exited"))) is True
113
-
114
-
115
- def test_started_status_is_not_completed(tmp_path):
116
- assert is_completed_status(str(_write(tmp_path / "w.status.json", "started"))) is False
117
-
118
-
119
- def test_missing_status_is_not_completed(tmp_path):
120
- assert is_completed_status(str(tmp_path / "absent.status.json")) is False
121
- ```
122
-
123
- - [ ] **Step 2: 테스트 실패 확인**
124
-
125
- Run: `python3 -m pytest tests/test_pane_reclaim.py -v`
126
- Expected: FAIL — `ModuleNotFoundError: okstra_ctl.pane_reclaim`
127
-
128
- - [ ] **Step 3: `pane_reclaim.py` 구현 (기존 SSOT 재사용)**
129
-
130
- `scripts/okstra_ctl/pane_reclaim.py`:
131
-
132
- ```python
133
- """완료(terminal) worker 판정 — pane 회수용. 판정 SSOT 는
134
- wrapper_status.read_wrapper_status 이며 여기서 재사용한다."""
135
- from __future__ import annotations
136
-
137
- import sys
138
- from pathlib import Path
139
-
140
- from .wrapper_status import read_wrapper_status
141
-
142
-
143
- def is_completed_status(status_path: str) -> bool:
144
- status = read_wrapper_status(Path(status_path))
145
- return status is not None and status.is_terminal
146
-
147
-
148
- def main(argv: list[str]) -> int:
149
- if len(argv) != 1:
150
- return 1
151
- return 0 if is_completed_status(argv[0]) else 1
152
-
153
-
154
- if __name__ == "__main__":
155
- raise SystemExit(main(sys.argv[1:]))
156
- ```
157
-
158
- - [ ] **Step 4: 테스트 통과 확인**
159
-
160
- Run: `python3 -m pytest tests/test_pane_reclaim.py -v`
161
- Expected: PASS (3 passed)
162
-
163
- - [ ] **Step 5: `okstra-trace-cleanup.sh` 에 `--reclaim-completed` 인자 추가**
164
-
165
- 옵션 파싱(`while` 루프 `case`)에 추가:
166
-
167
- ```bash
168
- --reclaim-completed) MODE="reclaim" ;;
169
- ```
170
-
171
- `MODE` 초기값 주석에 `reclaim` 추가. `--reclaim-completed` 는 `--run-dir` 필수(기존 검증 재사용).
172
-
173
- - [ ] **Step 6: collect 에 완료 필터 적용**
174
-
175
- `collect_okstra_panes` 의 (1) 태그 스캔 루프에서, `MODE == "reclaim"` 일 때 trace pane 은 `@okstra_status` 가 완료일 때만 포함하도록 분기. tmux 수집 포맷에 `@okstra_status` 컬럼을 추가하고 판정을 끼운다:
176
-
177
- ```bash
178
- while IFS=$'\t' read -r pid trace_tag worker_tag status_tag; do
179
- [[ -n "$pid" ]] || continue
180
- [[ "$pid" == "$lead_pane" ]] && continue
181
- if _tag_in_scope "$trace_tag" || _tag_in_scope "$worker_tag"; then
182
- if [[ "$MODE" == "reclaim" ]]; then
183
- # reclaim 모드: 완료(stage=exited)된 worker 의 pane 만. status 태그가
184
- # 없거나(teammate/비-wrapper pane) 미완료면 보존.
185
- [[ -n "$status_tag" ]] || continue
186
- python3 -m okstra_ctl.pane_reclaim "$status_tag" || continue
187
- fi
188
- panes+=("$pid")
189
- fi
190
- done < <(tmux list-panes -a \
191
- -F '#{pane_id}'$'\t''#{@okstra_trace_run}'$'\t''#{@okstra_worker_run}'$'\t''#{@okstra_status}' \
192
- 2>/dev/null || true)
193
- ```
194
-
195
- `MODE == "reclaim"` 에서는 (2) title-allowlist teammate 스캔을 **건너뛴다**(Task 0 미통과 기본값 — teammate pane 보존). `MODE` 가 `kill`/`list` 일 때는 기존 동작 유지. `kill` 분기는 `MODE in (kill, reclaim)` 가 동일 kill 경로를 타도록 마지막 실행부 조건을 `[[ "$MODE" != "list" ]]` 로 둔다.
196
-
197
- > **Task 0 통과 시에만** — teammate pane 도 회수하려면, reclaim 모드에서 (2) title 스캔을 살리되 각 teammate pane 의 완료 판정을 추가해야 한다. 단 teammate pane 엔 `@okstra_status` 태그가 없으므로(okstra 가 못 닮) 완료를 디스크에서 역매핑할 수단이 필요하다. Task 0 결과가 "회수 가능"이면 그 매핑(title→worker→status_path)을 별도 스텝으로 설계해 추가하고, 아니면 이 박스는 무시한다.
198
-
199
- - [ ] **Step 7: PYTHONPATH 확인 — cleanup 이 `okstra_ctl` 를 import 할 수 있는지**
200
-
201
- `okstra-trace-cleanup.sh` 가 `python3 -m okstra_ctl.pane_reclaim` 를 호출하려면 `scripts/` 가 `sys.path` 에 있어야 한다. 스크립트 상단(기존 `_clean_script_dir` 도출 직후)에 추가:
202
-
203
- ```bash
204
- export PYTHONPATH="$_clean_script_dir${PYTHONPATH:+:$PYTHONPATH}"
205
- ```
206
-
207
- 설치 레이아웃에서 `pane_reclaim.py`/`wrapper_status.py` 가 `$_clean_script_dir` 기준 어디에 놓이는지 [src/install.mjs](../../../src/install.mjs) 의 python 페이로드 경로와 대조해 PYTHONPATH 를 맞춘다(repo 는 `scripts/`, 설치본은 `~/.okstra/lib/python/`).
208
-
209
- - [ ] **Step 8: e2e 시나리오 — 완료 pane 회수 / 진행 중 보존**
210
-
211
- `tests-e2e/scenario-<id>-pane-reclaim.sh`: `mktemp -d` OKSTRA_HOME, tmux 가용할 때만 실행(없으면 skip). 모의 run-dir 에 두 worker prompt+status(`exited` 1개, `started` 1개)와 태그된 모의 pane 2개를 만들고, `--reclaim-completed --list` 가 `exited` pane 만 출력하는지 검증. `trap` 으로 OKSTRA_HOME 정리.
212
-
213
- - [ ] **Step 9: 단위 테스트 통과 + 커밋**
214
-
215
- Run: `python3 -m pytest tests/test_pane_reclaim.py -v && bash -n scripts/okstra-trace-cleanup.sh`
216
- Expected: PASS + 문법 오류 없음
217
-
218
- ```bash
219
- git add scripts/okstra_ctl/pane_reclaim.py scripts/okstra-trace-cleanup.sh tests/test_pane_reclaim.py tests-e2e/scenario-*-pane-reclaim.sh
220
- git commit -m "feat(cleanup): --reclaim-completed 모드 — 완료된 trace pane 만 회수"
221
- ```
222
-
223
- ---
224
-
225
- ## Task 3: 훅 진입점 `okstra-subagent-reclaim.sh` — 활성 run 순회
226
-
227
- `SubagentStop`/`TaskCompleted` 가 주는 stdin 은 run-dir 을 직접 주지 않고 `cwd` 도 run-dir 보장이 없다. session_id 매핑 대신 `active.jsonl` 의 활성 run 을 모두 순회한다 — 완료 판정(Task 2)이 cross-run 안전을 보장하므로 다른 run 의 진행 중 pane 을 건드리지 않는다.
228
-
229
- **Files:**
230
- - Create: `scripts/okstra-subagent-reclaim.sh`
231
- - Test: `tests/test_subagent_reclaim_targets.py` (run-dir 추출 로직을 Python helper 로 분리해 테스트)
232
-
233
- **Interfaces:**
234
- - Consumes: stdin JSON(무시 가능 — 어느 worker 가 끝났든 활성 run 전체를 reclaim), `~/.okstra/active.jsonl`(`runDirRel`/`projectRoot`/`status`).
235
- - Produces: `pane_reclaim.active_run_dirs(home: Path) -> list[Path]` (status 가 종료 상태가 아닌 run 들의 절대 run-dir).
236
-
237
- - [ ] **Step 1: active run-dir 추출 테스트 작성 (실패)**
238
-
239
- `tests/test_subagent_reclaim_targets.py`:
240
-
241
- ```python
242
- import json
243
- from pathlib import Path
244
- from okstra_ctl.pane_reclaim import active_run_dirs
245
-
246
-
247
- def test_active_run_dirs_resolves_absolute(tmp_path):
248
- home = tmp_path
249
- (home / "active.jsonl").write_text(
250
- json.dumps({"status": "running", "runDirRel": "tasks/g/t/runs/x", "projectRoot": "/proj"}) + "\n",
251
- encoding="utf-8",
252
- )
253
- dirs = active_run_dirs(home)
254
- assert dirs == [home / "tasks/g/t/runs/x"]
255
-
256
-
257
- def test_finished_runs_excluded(tmp_path):
258
- home = tmp_path
259
- (home / "active.jsonl").write_text(
260
- json.dumps({"status": "done", "runDirRel": "tasks/g/t/runs/x", "projectRoot": "/proj"}) + "\n",
261
- encoding="utf-8",
262
- )
263
- assert active_run_dirs(home) == []
264
- ```
265
-
266
- > **구현 전 확인:** `runDirRel` 의 base 가 `home` 인지 `projectRoot` 인지 [index.py](../../../scripts/okstra_ctl/index.py) `reserve_active` 호출부에서 확정하고, 위 테스트의 기대 경로를 그에 맞춘다. `status` 의 "활성" 집합(`reserving`/`running`/...)도 같은 파일에서 확인해 제외 조건을 맞춘다.
267
-
268
- - [ ] **Step 2: 테스트 실패 확인**
269
-
270
- Run: `python3 -m pytest tests/test_subagent_reclaim_targets.py -v`
271
- Expected: FAIL — `active_run_dirs` 없음
272
-
273
- - [ ] **Step 3: `active_run_dirs` 를 `pane_reclaim.py` 에 추가**
274
-
275
- ```python
276
- import json
277
-
278
- _FINISHED = {"done", "complete", "error", "aborted"} # index.py 의 종료 status 와 대조해 확정
279
-
280
-
281
- def active_run_dirs(home: Path) -> list[Path]:
282
- path = home / "active.jsonl"
283
- if not path.is_file():
284
- return []
285
- dirs: list[Path] = []
286
- for line in path.read_text(encoding="utf-8").splitlines():
287
- line = line.strip()
288
- if not line:
289
- continue
290
- try:
291
- row = json.loads(line)
292
- except json.JSONDecodeError:
293
- continue
294
- rel = row.get("runDirRel")
295
- if not rel or row.get("status") in _FINISHED:
296
- continue
297
- dirs.append(home / rel)
298
- return dirs
299
- ```
300
-
301
- - [ ] **Step 4: 테스트 통과 확인**
302
-
303
- Run: `python3 -m pytest tests/test_subagent_reclaim_targets.py -v`
304
- Expected: PASS
305
-
306
- - [ ] **Step 5: 훅 엔트리 스크립트 작성**
307
-
308
- `scripts/okstra-subagent-reclaim.sh`:
309
-
310
- ```bash
311
- #!/usr/bin/env bash
312
- #
313
- # okstra-subagent-reclaim.sh — SubagentStop / TaskCompleted 훅 엔트리.
314
- # stdin(JSON)은 읽고 버린다(어느 worker 가 끝났든 활성 run 전체의 완료 pane 만
315
- # 회수하므로). active.jsonl 의 각 활성 run 에 대해 cleanup --reclaim-completed.
316
- # 모든 실패는 조용히 삼킨다 — 훅은 세션 진행을 절대 막지 않는다.
317
- set -u
318
- cat >/dev/null 2>&1 || true # drain stdin
319
-
320
- _dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
321
- home="${OKSTRA_HOME:-$HOME/.okstra}"
322
- export PYTHONPATH="$_dir${PYTHONPATH:+:$PYTHONPATH}"
323
-
324
- while IFS= read -r run_dir; do
325
- [[ -n "$run_dir" ]] || continue
326
- "$_dir/okstra-trace-cleanup.sh" --reclaim-completed --run-dir "$run_dir" 2>/dev/null || true
327
- done < <(python3 -m okstra_ctl.pane_reclaim --active-dirs "$home" 2>/dev/null || true)
328
-
329
- exit 0
330
- ```
331
-
332
- `pane_reclaim.main` 에 `--active-dirs <home>` 서브커맨드를 추가해 `active_run_dirs` 결과를 한 줄씩 출력하게 한다(기존 단일 status_path 판정과 분기).
333
-
334
- - [ ] **Step 6: `pane_reclaim.main` 에 `--active-dirs` 분기 추가**
335
-
336
- ```python
337
- def main(argv: list[str]) -> int:
338
- if len(argv) == 2 and argv[0] == "--active-dirs":
339
- for d in active_run_dirs(Path(argv[1])):
340
- print(d)
341
- return 0
342
- if len(argv) == 1:
343
- return 0 if is_completed_status(argv[0]) else 1
344
- return 1
345
- ```
346
-
347
- - [ ] **Step 7: 실행권한 + 문법 + 테스트**
348
-
349
- Run: `chmod +x scripts/okstra-subagent-reclaim.sh && bash -n scripts/okstra-subagent-reclaim.sh && python3 -m pytest tests/test_subagent_reclaim_targets.py tests/test_pane_reclaim.py -v`
350
- Expected: PASS
351
-
352
- - [ ] **Step 8: 커밋**
353
-
354
- ```bash
355
- git add scripts/okstra-subagent-reclaim.sh scripts/okstra_ctl/pane_reclaim.py tests/test_subagent_reclaim_targets.py
356
- git commit -m "feat(hook): okstra-subagent-reclaim.sh — 활성 run 의 완료 pane 회수 엔트리"
357
- ```
358
-
359
- ---
360
-
361
- ## Task 4: 훅 배선 — `settings.template.json`
362
-
363
- 완료 이벤트에 reclaim 엔트리를 배선한다. no-team(Agent) 경로는 `SubagentStop`, Teams 경로는 `TaskCompleted`.
364
-
365
- **Files:**
366
- - Modify: `templates/reports/settings.template.json` (`hooks` 객체)
367
-
368
- - [ ] **Step 1: 두 이벤트 훅 추가**
369
-
370
- `hooks` 객체에 추가(기존 `PreToolUse`, `SessionEnd` 유지):
371
-
372
- ```json
373
- "SubagentStop": [
374
- {
375
- "hooks": [
376
- {
377
- "type": "command",
378
- "command": "$HOME/.okstra/bin/okstra-subagent-reclaim.sh"
379
- }
380
- ]
381
- }
382
- ],
383
- "TaskCompleted": [
384
- {
385
- "hooks": [
386
- {
387
- "type": "command",
388
- "command": "$HOME/.okstra/bin/okstra-subagent-reclaim.sh"
389
- }
390
- ]
391
- }
392
- ]
393
- ```
394
-
395
- - [ ] **Step 2: JSON 유효성 확인**
396
-
397
- Run: `python3 -c "import json; json.load(open('templates/reports/settings.template.json'))"`
398
- Expected: 오류 없음
399
-
400
- - [ ] **Step 3: 설치 payload 에 새 스크립트가 포함되는지 확인**
401
-
402
- [src/install.mjs](../../../src/install.mjs) 가 `scripts/okstra-*.sh` 를 `~/.okstra/bin/` 으로 복사하는 규칙에 `okstra-subagent-reclaim.sh` 가 자동 포함되는지(glob/명시 목록) 확인. 명시 목록이면 추가한다.
403
-
404
- Run: `grep -n 'okstra-trace-cleanup\|okstra-.*\.sh\|bin/' src/install.mjs | head`
405
-
406
- - [ ] **Step 4: 커밋**
407
-
408
- ```bash
409
- git add templates/reports/settings.template.json src/install.mjs
410
- git commit -m "feat(hook): SubagentStop/TaskCompleted 에 pane reclaim 배선"
411
- ```
412
-
413
- ---
414
-
415
- ## Task 5: 내성 계약 — `_common-contract.md`
416
-
417
- 하니스 teammate pane 생성 실패는 okstra Python 이 못 보므로 코드 강제 불가. lead 행동 계약에 명시한다(declaration, prompt 지시임을 분명히).
418
-
419
- **Files:**
420
- - Modify: `prompts/profiles/_common-contract.md` (dispatch/convergence 절)
421
-
422
- - [ ] **Step 1: pane-실패 fallback 문단 추가**
423
-
424
- 기존 dispatch 관련 절에 추가(한국어/영어는 그 파일의 기존 언어 관행에 맞춤):
425
-
426
- > **Pane-budget fallback (tolerance).** worker dispatch 가 `no room for another tmux split`(또는 동등한 teammate pane 생성 실패)로 거부되면, 그 worker 를 `run_in_background` 없이 in-process 로 재시도하거나, 외부 CLI worker 였다면 in-process claude 분석으로 **대체**하고 그 사실(provider 불가)을 run 기록·convergence 노트에 남긴다. 완료된 외부 CLI worker 의 trace pane 은 `SubagentStop` 훅이 자동 회수하지만, 하니스가 만든 teammate pane 누적은 okstra 가 직접 회수할 수 없으므로 이 fallback 이 최후 방어선이다. (이는 코드 강제가 아닌 prompt 지시다.)
427
-
428
- - [ ] **Step 2: declaration ≠ enforcement 규칙 준수 확인**
429
-
430
- 이 문단이 "MUST/BLOCKING" 같은 강제 용어를 enforcement 없이 쓰지 않는지 확인(글로벌 5.5). "최후 방어선"·"대체한다" 수준의 행동 지시로 유지하고, 코드 강제가 아님을 명시한 현재 문구를 지킨다.
431
-
432
- - [ ] **Step 3: 커밋**
433
-
434
- ```bash
435
- git add prompts/profiles/_common-contract.md
436
- git commit -m "docs(contract): pane-budget fallback — pane 실패 시 in-process 대체"
437
- ```
438
-
439
- ---
440
-
441
- ## Task 6: 빌드 동기화 + 전체 검증
442
-
443
- **Files:** 없음(빌드/검증).
444
-
445
- - [ ] **Step 1: 빌드**
446
-
447
- Run: `npm run build`
448
- Expected: `done. NN/NN sources synced.`
449
-
450
- - [ ] **Step 2: 전체 단위 + 워크플로 검증**
451
-
452
- Run: `python3 -m pytest tests/ -q && bash validators/validate-workflow.sh`
453
- Expected: 모두 통과
454
-
455
- - [ ] **Step 3: CLI 스모크 + doctor**
456
-
457
- Run: `node bin/okstra --version && node bin/okstra doctor`
458
- Expected: 정상
459
-
460
- - [ ] **Step 4: CHANGES.md 항목 추가 (사용자 영향)**
461
-
462
- `CHANGES.md` 최상단 날짜 섹션에 항목 추가 — trace pane 완료-즉시 회수 + 내성 fallback 이 pane 한도 초과를 완화한다는 `사용자 영향:` 줄 포함. 한국어.
463
-
464
- - [ ] **Step 5: 커밋**
465
-
466
- ```bash
467
- git add CHANGES.md
468
- git commit -m "docs(changes): worker trace pane 완료-회수 + 내성 fallback"
469
- ```
470
-
471
- ---
472
-
473
- ## 완료 기준
474
-
475
- - 외부 CLI worker 완료 시 그 trace pane 이 `SubagentStop`/`TaskCompleted` 훅으로 자동 회수되고, 진행 중 worker 의 pane 은 보존된다(e2e 시나리오로 입증).
476
- - pane 생성 실패 시 lead 가 in-process 대체로 진행하도록 계약에 명시된다.
477
- - 전체 pytest + validate-workflow 통과, 빌드 동기화 완료.
478
- - teammate pane 회수는 Task 0 실측 결과에 따라 적용/미적용이 명확히 기록된다.
479
-
480
- ## 알려진 한계 (spec §9 와 일치)
481
-
482
- - 하니스 teammate pane 은 okstra 가 태그·식별을 보장할 수 없어, Task 0 미통과 시 회수 대상이 아니다 — 그 누적은 Task 5 내성에 의존하며, 내성은 코드 강제가 불가능한 prompt 계약이다.
483
- - 한 세션 다중 동시 run 시 active.jsonl 순회가 모든 run 을 reclaim 하지만, 완료 판정이 진행 중 pane 을 보호하므로 안전하다.