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,348 +0,0 @@
1
- # release-handoff `local checkout` 액션 구현 계획
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:** release-handoff 에 `local checkout` 액션을 추가해, 검증된 task 브랜치를 메인 워크트리로 가져와 로컬 테스트 가능 상태로 만든다.
6
-
7
- **Architecture:** Python 헬퍼 `okstra handoff local-checkout` 가 registry 의 task-key 행에서 okstra 워크트리·브랜치를 해소하고, 메인 워크트리 cwd 에서 `git worktree remove --force`(브랜치 보존) → `release_status`(branch 슬롯 유지) → `git checkout` 을 수행한다. release-handoff 프로필이 확인을 받고 이 명령 하나만 호출한다. base 브랜치는 절대 건드리지 않는다.
8
-
9
- **Tech Stack:** Python 3 (argparse, subprocess), 기존 `okstra_ctl.handoff` / `worktree` / `worktree_registry`, Node CLI shim, markdown 프로필.
10
-
11
- ## Global Constraints
12
-
13
- - 설계 문서: [docs/superpowers/specs/2026-06-21-release-handoff-local-checkout-design.md](../specs/2026-06-21-release-handoff-local-checkout-design.md) — 충돌 시 spec 우선.
14
- - `runtime/` 직접 수정 금지(빌드 산출물). 소스는 `scripts/` `src/` `prompts/`; 변경 후 `npm run build`.
15
- - pre-1.0 — compat shim 불필요. `local only` 액션은 완전 제거.
16
- - 함수 본문 50줄 이하.
17
- - 동시 세션 환경 — git amend 금지, 항상 새 커밋. 내 작업 파일만 스테이징.
18
- - Conventional Commits, 메시지 한국어 prose, AI 트레일러 금지.
19
- - 사용자 영향 있는 변경은 [CHANGES.md](../../../CHANGES.md) 에 `사용자 영향:` 항목 추가(한국어).
20
- - `local checkout` 은 whole-task 모드 전용. base 브랜치 자동 머지는 비목표.
21
-
22
- ## File Structure
23
-
24
- - `scripts/okstra_ctl/handoff.py` — `local_checkout()` 코어 + `local-checkout` 서브커맨드/디스패치 추가.
25
- - `src/commands/execute/handoff.mjs` — USAGE 에 `local-checkout` 노출(동작은 기존 shim 이 그대로 forward).
26
- - `tests/handoff/test_handoff_local_checkout.py` — 신규: 성공/메인 dirty 거부/registry 행 없음 + 브랜치 보존 실증.
27
- - `prompts/profiles/release-handoff.md` — 액션 선택 재편 + 핸들러 + `local only` 잔존 참조 정리 + 보고 deliverable.
28
- - `CHANGES.md` — 사용자 영향 항목.
29
-
30
- ---
31
-
32
- ### Task 1: `local_checkout()` 코어 + CLI 서브커맨드
33
-
34
- **Files:**
35
- - Modify: `scripts/okstra_ctl/handoff.py` (import 확장 + `local_checkout()` 추가 + `main()` argparse/dispatch)
36
- - Modify: `src/commands/execute/handoff.mjs` (USAGE)
37
- - Test: `tests/handoff/test_handoff_local_checkout.py`
38
-
39
- **Interfaces:**
40
- - Consumes: `worktree_registry.lookup(project_id, task_group, task_id) -> Optional[WorktreeEntry]` (`.branch`, `.worktree_path`, `.status`); `worktree_registry.release_status(project_id, task_group, task_id)`; `worktree.main_worktree_path(Path) -> Path`; `worktree.is_dirty_excluding_okstra(cwd) -> bool`; `handoff._run_git(args, cwd, check=True)`.
41
- - Produces: `handoff.local_checkout(*, project_root, project_id, task_group, task_id) -> Dict[str, Any]` — 성공 시 `{"ok": True, "branch": str, "mainWorktreePath": str, "removedWorktree": str, "status": "checked-out"}`; 전제 위반 시 `HandoffError`(→ exit 1). CLI: `okstra handoff local-checkout --project-root <dir> --project-id <id> --task-group <g> --task-id <t>`.
42
-
43
- - [ ] **Step 1: 실패 테스트 작성**
44
-
45
- `tests/handoff/test_handoff_local_checkout.py` 생성:
46
-
47
- ```python
48
- """handoff.local_checkout — okstra 워크트리 제거 + 메인 checkout 의 git 실증."""
49
- import sys
50
- import subprocess
51
- from pathlib import Path
52
- from _paths import REPO_ROOT
53
-
54
- LIB_DIR = REPO_ROOT / "scripts"
55
- if str(LIB_DIR) not in sys.path:
56
- sys.path.insert(0, str(LIB_DIR))
57
-
58
- import pytest
59
-
60
- from okstra_ctl import handoff, worktree_registry
61
-
62
- ARGS = dict(project_id="proj", task_group="grp", task_id="task")
63
- BRANCH = "feature-development-task"
64
-
65
-
66
- def _git(repo, *args):
67
- r = subprocess.run(["git", *args], cwd=str(repo),
68
- capture_output=True, text=True)
69
- assert r.returncode == 0, r.stderr
70
- return r.stdout.strip()
71
-
72
-
73
- def _main_repo(tmp_path):
74
- repo = tmp_path / "main"
75
- repo.mkdir()
76
- _git(repo, "init", "-q", "-b", "main")
77
- _git(repo, "config", "user.email", "t@t")
78
- _git(repo, "config", "user.name", "t")
79
- (repo / "base.txt").write_text("base\n")
80
- _git(repo, "add", ".")
81
- _git(repo, "commit", "-q", "-m", "base")
82
- return repo
83
-
84
-
85
- def _provision_okstra_worktree(repo, tmp_path):
86
- """main repo 에서 task 브랜치를 든 okstra 워크트리를 만들고 registry 에 등록."""
87
- okstra_wt = tmp_path / "okstra-wt"
88
- _git(repo, "worktree", "add", "-b", BRANCH, str(okstra_wt), "main")
89
- (okstra_wt / "work.txt").write_text("task work\n")
90
- _git(okstra_wt, "add", ".")
91
- _git(okstra_wt, "commit", "-q", "-m", "task work")
92
- worktree_registry.reserve(**ARGS, worktree_path=str(okstra_wt),
93
- branch=BRANCH, base_ref="main")
94
- return okstra_wt
95
-
96
-
97
- def test_local_checkout_removes_worktree_and_checks_out_in_main(tmp_path):
98
- repo = _main_repo(tmp_path)
99
- okstra_wt = _provision_okstra_worktree(repo, tmp_path)
100
-
101
- out = handoff.local_checkout(project_root=repo, **ARGS)
102
-
103
- assert out["status"] == "checked-out"
104
- assert out["branch"] == BRANCH
105
- assert not okstra_wt.exists() # okstra 워크트리 제거
106
- assert _git(repo, "rev-parse", "--abbrev-ref", "HEAD") == BRANCH # 메인이 task 브랜치
107
- assert _git(repo, "rev-parse", "--verify", BRANCH) # 브랜치 ref 보존
108
- assert (repo / "work.txt").exists() # task 작업물이 메인에 보임
109
- assert worktree_registry.lookup(**ARGS).status == "released"
110
-
111
-
112
- def test_local_checkout_aborts_when_main_dirty(tmp_path):
113
- repo = _main_repo(tmp_path)
114
- okstra_wt = _provision_okstra_worktree(repo, tmp_path)
115
- (repo / "uncommitted.txt").write_text("dirty\n") # 메인 dirty (.okstra 밖)
116
-
117
- with pytest.raises(handoff.HandoffError, match="미커밋"):
118
- handoff.local_checkout(project_root=repo, **ARGS)
119
-
120
- assert okstra_wt.exists() # 보존
121
- assert worktree_registry.lookup(**ARGS).status == "active" # 미변경
122
-
123
-
124
- def test_local_checkout_errors_when_no_registry_entry(tmp_path):
125
- repo = _main_repo(tmp_path)
126
- with pytest.raises(handoff.HandoffError, match="registry"):
127
- handoff.local_checkout(project_root=repo, **ARGS)
128
- ```
129
-
130
- - [ ] **Step 2: 테스트 실패 확인**
131
-
132
- Run: `python3 -m pytest tests/handoff/test_handoff_local_checkout.py -v`
133
- Expected: FAIL — `AttributeError: module 'okstra_ctl.handoff' has no attribute 'local_checkout'`
134
-
135
- - [ ] **Step 3: import 확장**
136
-
137
- `scripts/okstra_ctl/handoff.py` 의 import 한 줄을 교체:
138
-
139
- ```python
140
- from .worktree import compute_branch_name, compute_worktree_path
141
- ```
142
-
143
- ```python
144
- from .worktree import (compute_branch_name, compute_worktree_path,
145
- main_worktree_path, is_dirty_excluding_okstra)
146
- ```
147
-
148
- - [ ] **Step 4: `local_checkout()` 구현**
149
-
150
- `scripts/okstra_ctl/handoff.py` 에 `assemble(...)` 정의 바로 다음(즉 `record_verified` 앞)에 추가:
151
-
152
- ```python
153
- def local_checkout(*, project_root, project_id, task_group, task_id) -> Dict[str, Any]:
154
- """whole-task: okstra task-key 워크트리를 제거하고 task 브랜치를 메인
155
- 워크트리에 checkout 한다(브랜치 보존). 메인이 dirty 면 거부. base 브랜치는
156
- 건드리지 않는다."""
157
- entry = worktree_registry.lookup(project_id, task_group, task_id)
158
- if not entry or not entry.branch or not entry.worktree_path:
159
- raise HandoffError(
160
- "task-key worktree registry 엔트리가 없습니다 — local checkout 대상 없음")
161
- main_wt = main_worktree_path(Path(project_root))
162
- if is_dirty_excluding_okstra(main_wt):
163
- raise HandoffError(
164
- f"메인 워크트리에 미커밋 변경이 있습니다 ({main_wt}) — "
165
- "커밋/스태시 후 다시 시도하세요")
166
- _run_git(["worktree", "remove", "--force", entry.worktree_path], main_wt)
167
- worktree_registry.release_status(project_id, task_group, task_id)
168
- co = _run_git(["checkout", entry.branch], main_wt, check=False)
169
- if co.returncode != 0:
170
- raise HandoffError(
171
- f"git checkout {entry.branch} 실패: {co.stderr.strip()} — 워크트리는 "
172
- f"제거됨; 메인({main_wt})에서 수동 checkout 으로 복구하세요")
173
- return {"ok": True, "branch": entry.branch, "mainWorktreePath": str(main_wt),
174
- "removedWorktree": entry.worktree_path, "status": "checked-out"}
175
- ```
176
-
177
- - [ ] **Step 5: argparse 서브커맨드 + 디스패치**
178
-
179
- `scripts/okstra_ctl/handoff.py` 의 `main()` 에서 `record-pr` 서브파서 등록 다음에 추가:
180
-
181
- ```python
182
- sp = sub.add_parser("local-checkout")
183
- common(sp, plan=False)
184
- sp.add_argument("--project-root", default=".")
185
- sp.add_argument("--project-id", required=True)
186
- sp.add_argument("--task-group", required=True)
187
- sp.add_argument("--task-id", required=True)
188
- ```
189
-
190
- 디스패치에서 `else:`(record-pr) 바로 앞에 elif 추가:
191
-
192
- ```python
193
- elif a.cmd == "local-checkout":
194
- out = local_checkout(
195
- project_root=Path(a.project_root).resolve(),
196
- project_id=a.project_id, task_group=a.task_group,
197
- task_id=a.task_id)
198
- ```
199
-
200
- - [ ] **Step 6: 테스트 통과 확인**
201
-
202
- Run: `python3 -m pytest tests/handoff/test_handoff_local_checkout.py -v`
203
- Expected: PASS (3 passed)
204
-
205
- - [ ] **Step 7: handoff.mjs USAGE 갱신**
206
-
207
- `src/commands/execute/handoff.mjs` 의 USAGE 에서 `record-pr` 줄 다음에 추가:
208
-
209
- ```
210
- okstra handoff record-pr --plan-run-root <dir> --stages 2,3 \\
211
- --branch <b> --url <u>
212
- okstra handoff local-checkout --project-root <dir> --project-id <id> \\
213
- --task-group <g> --task-id <t>
214
- ```
215
-
216
- - [ ] **Step 8: CLI 스모크**
217
-
218
- Run: `node bin/okstra handoff --help`
219
- Expected: 출력에 `local-checkout` 줄이 보임.
220
-
221
- - [ ] **Step 9: 커밋**
222
-
223
- ```bash
224
- git add scripts/okstra_ctl/handoff.py src/commands/execute/handoff.mjs tests/handoff/test_handoff_local_checkout.py
225
- git commit -m "feat(handoff): okstra handoff local-checkout 서브커맨드 추가"
226
- ```
227
-
228
- ---
229
-
230
- ### Task 2: release-handoff 프로필 — 액션 재편 + `local only` 정리
231
-
232
- **Files:**
233
- - Modify: `prompts/profiles/release-handoff.md`
234
-
235
- **Interfaces:**
236
- - Consumes: Task 1 의 CLI `okstra handoff local-checkout ...`.
237
- - Produces: 프로필 동작 — `local checkout`(첫째)/`push + PR`/`skip` 3지선다, whole-task 게이트, 확인 후 헬퍼 호출, 보고 deliverable.
238
-
239
- - [ ] **Step 1: 액션 선택 블록 교체**
240
-
241
- `prompts/profiles/release-handoff.md` 의 다음 블록(현재 22–26줄)을 교체:
242
-
243
- old:
244
- ```
245
- 1. **Action selection** — present three choices and capture exactly one:
246
- - `local only` — complete the handoff as a local delivery record: record the accepted, already-committed branch and end without push or PR.
247
- - `push + PR` — push the feature branch, then open or reuse a pull request.
248
- - `skip` — cancel delivery actions for now: record that release-handoff was intentionally skipped and end the run without any git command.
249
- If the user picks `skip`, route directly to the final-report self-review pass.
250
- ```
251
- new:
252
- ```
253
- 1. **Action selection** — present three choices and capture exactly one:
254
- - `local checkout` (whole-task mode only) — bring the verified task branch into the MAIN worktree for local testing (no push, no PR). See step 1c. When `HANDOFF_MODE` is `stage-group`, do NOT offer this option — tell the user "`local checkout` is whole-task mode only" and re-ask.
255
- - `push + PR` — push the feature branch, then open or reuse a pull request.
256
- - `skip` — cancel delivery actions for now: record that release-handoff was intentionally skipped and end the run without any git command.
257
- If the user picks `skip`, route directly to the final-report self-review pass.
258
- 1c. **Local checkout execution** (only when the user picked `local checkout`) — confirm with the user that okstra will remove the okstra task worktree and `git checkout <feature branch>` in the MAIN worktree, and that the base branch is never modified. On confirmation run:
259
- `okstra handoff local-checkout --project-root <project root> --project-id <id> --task-group <g> --task-id <t>`
260
- Exit 1 means a precondition failed (MAIN worktree dirty, registry entry missing, or checkout failed): show the error verbatim and re-ask the action selection. On success the okstra task worktree no longer exists — the lead's cwd is gone, so EVERY subsequent step (final-report authoring included) MUST use absolute paths or run from the MAIN worktree. Then route to the final-report self-review pass.
261
- ```
262
-
263
- - [ ] **Step 2: 잔존 `local only` 참조 정리**
264
-
265
- 다음 세 줄을 각각 교체:
266
-
267
- 68줄 old: ` - Q1 action: `local only` | `push + PR` | `skip`.`
268
- 68줄 new: ` - Q1 action: `local checkout` | `push + PR` | `skip`.`
269
-
270
- 75줄 old: ` - `- Not run (user picked local only or skip).``
271
- 75줄 new: ` - `- Not run (user picked local checkout or skip).``
272
-
273
- 79줄 old: ` - `- No PR action requested.` (user picked `local only` or `skip`)`
274
- 79줄 new: ` - `- No PR action requested.` (user picked `local checkout` or `skip`)`
275
-
276
- - [ ] **Step 3: Local Checkout Outcome deliverable 추가**
277
-
278
- `Required deliverable shape` 의 **Pull Request Outcome** 블록(현재 78–82줄) 다음에 새 deliverable 추가:
279
-
280
- old:
281
- ```
282
- - `- PR creation skipped: <reason>` for any user-driven cancellation
283
- - **Stage Group** (stage-group mode only): selected stages, each stage's single-stage verification report path + quoted `Verdict Token` row, collector branch name, merge commit SHAs from assemble, and the dependency-closure verdict (from the assemble output / error).
284
- ```
285
- new:
286
- ```
287
- - `- PR creation skipped: <reason>` for any user-driven cancellation
288
- - **Local Checkout Outcome**: one of
289
- - `- Not run (user picked push + PR or skip).`
290
- - `- Checked out <branch> into <main worktree path>; okstra task worktree <path> removed. Next: 로컬 테스트 후 PR 하려면 okstra-run 으로 release-handoff 재진입 → push + PR.`
291
- - **Stage Group** (stage-group mode only): selected stages, each stage's single-stage verification report path + quoted `Verdict Token` row, collector branch name, merge commit SHAs from assemble, and the dependency-closure verdict (from the assemble output / error).
292
- ```
293
-
294
- - [ ] **Step 4: 잔존 참조 일관성 확인**
295
-
296
- Run: `grep -n "local only" prompts/profiles/release-handoff.md`
297
- Expected: 출력 없음(모든 `local only` 제거됨).
298
-
299
- - [ ] **Step 5: 워크플로 validator**
300
-
301
- Run: `bash validators/validate-workflow.sh`
302
- Expected: PASS(또는 본 변경과 무관한 기존 상태 그대로 — 신규 실패 없음).
303
-
304
- - [ ] **Step 6: 커밋**
305
-
306
- ```bash
307
- git add prompts/profiles/release-handoff.md
308
- git commit -m "feat(handoff): release-handoff 에 local checkout 액션 + local only 제거"
309
- ```
310
-
311
- ---
312
-
313
- ### Task 3: CHANGES.md + 빌드 + 최종 검증
314
-
315
- **Files:**
316
- - Modify: `CHANGES.md`
317
-
318
- - [ ] **Step 1: CHANGES.md 항목 추가**
319
-
320
- `CHANGES.md` 의 `## 2026-06-21` 섹션(없으면 최상단 날짜 섹션 위에 생성)에 추가:
321
-
322
- ```markdown
323
- ### feat(handoff): release-handoff 에 `local checkout` 액션 추가 — 검증된 브랜치를 메인 워크트리로
324
-
325
- - **배경**: okstra task 작업은 격리된 git worktree(`~/.okstra/worktrees/...`)에서 진행돼, 검증이 끝난 뒤 사용자가 결과를 로컬에서 테스트하려면 그 폴더로 직접 `cd` 해야 했다. task 브랜치를 메인 작업 디렉터리로 가져오는 한-스텝 경로가 없었다.
326
- - **해결**: release-handoff 액션 선택을 `local checkout`(신규, 첫째)/`push + PR`/`skip` 으로 재편하고(중복이던 `local only` 제거), 신규 `okstra handoff local-checkout` 헬퍼가 메인 워크트리 dirty 확인 후 okstra task 워크트리를 제거(브랜치 보존)하고 메인에서 `git checkout <task-branch>` 를 수행한다. base 브랜치는 건드리지 않는다(whole-task 모드 전용).
327
- - 사용자 영향: release-handoff 에서 `local checkout` 을 고르면, 검증된 task 브랜치가 메인 작업 디렉터리에 바로 체크아웃돼 별도 `cd` 없이 로컬 테스트할 수 있다. 메인에 미커밋 변경이 있으면 중단·안내한다. 기존 `local only` 액션은 `skip` 과 중복이라 제거됐다. (설치 환경은 `okstra install` 로 런타임 갱신 후 적용.)
328
- ```
329
-
330
- - [ ] **Step 2: 런타임 빌드**
331
-
332
- Run: `npm run build`
333
- Expected: 성공(소스가 `runtime/` 으로 동기화됨).
334
-
335
- - [ ] **Step 3: 최종 검증 스윕**
336
-
337
- Run: `python3 -m pytest tests/handoff/test_handoff_local_checkout.py tests/handoff/test_handoff_assemble.py -q`
338
- Expected: PASS(신규 3 + 기존 회귀 무손상).
339
-
340
- Run: `node bin/okstra handoff --help`
341
- Expected: `local-checkout` 노출.
342
-
343
- - [ ] **Step 4: 커밋**
344
-
345
- ```bash
346
- git add CHANGES.md
347
- git commit -m "docs(handoff): local checkout 액션 CHANGES 기록"
348
- ```