aiwcli 0.15.7 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/README.md +106 -1125
  2. package/bin/run.js +0 -4
  3. package/dist/capabilities/installation/control-plane/clear-command.d.ts +2 -0
  4. package/dist/capabilities/installation/control-plane/clear-command.js +32 -3
  5. package/dist/capabilities/installation/control-plane/init-command.js +2 -2
  6. package/dist/capabilities/launch/contracts.d.ts +39 -4
  7. package/dist/capabilities/launch/control-plane/execute-launch.js +158 -119
  8. package/dist/capabilities/launch/runtime-core/launch-decisions.d.ts +82 -0
  9. package/dist/capabilities/launch/runtime-core/launch-decisions.js +202 -0
  10. package/dist/commands/branch.d.ts +1 -1
  11. package/dist/commands/branch.js +1 -1
  12. package/dist/commands/launch.d.ts +0 -5
  13. package/dist/commands/launch.js +2 -37
  14. package/dist/lib/config.js +1 -2
  15. package/dist/lib/context/context-store.js +28 -2
  16. package/dist/lib/core-installer.d.ts +1 -1
  17. package/dist/lib/core-installer.js +6 -27
  18. package/dist/lib/debug.d.ts +0 -10
  19. package/dist/lib/debug.js +0 -10
  20. package/dist/lib/env-sanitizer.d.ts +25 -0
  21. package/dist/lib/env-sanitizer.js +46 -0
  22. package/dist/lib/errors.d.ts +0 -13
  23. package/dist/lib/errors.js +0 -15
  24. package/dist/lib/git-exclude-manager.js +1 -1
  25. package/dist/lib/hooks/context-monitor-logic.d.ts +6 -0
  26. package/dist/lib/hooks/context-monitor-logic.js +25 -0
  27. package/dist/lib/hooks/hook-utils.js +11 -0
  28. package/dist/lib/hooks/prompt-binding-logic.d.ts +7 -0
  29. package/dist/lib/hooks/prompt-binding-logic.js +50 -0
  30. package/dist/lib/hooks/session-end-logic.js +2 -14
  31. package/dist/lib/install-state.js +6 -13
  32. package/dist/lib/json-io.d.ts +12 -0
  33. package/dist/lib/json-io.js +30 -0
  34. package/dist/lib/multiplexer.d.ts +43 -35
  35. package/dist/lib/multiplexer.js +21 -2
  36. package/dist/lib/multiplexers/psmux.d.ts +14 -34
  37. package/dist/lib/multiplexers/psmux.js +70 -130
  38. package/dist/lib/multiplexers/tmux.d.ts +11 -19
  39. package/dist/lib/multiplexers/tmux.js +79 -120
  40. package/dist/lib/multiplexers/wezterm.d.ts +38 -0
  41. package/dist/lib/multiplexers/wezterm.js +225 -0
  42. package/dist/lib/mux-utils.d.ts +4 -3
  43. package/dist/lib/mux-utils.js +7 -13
  44. package/dist/lib/prompt-file-manager.d.ts +23 -0
  45. package/dist/lib/prompt-file-manager.js +41 -0
  46. package/dist/lib/runtime/agent-launcher.d.ts +67 -0
  47. package/dist/lib/runtime/agent-launcher.js +262 -0
  48. package/dist/lib/runtime/aiw-cli.d.ts +2 -0
  49. package/dist/lib/runtime/aiw-cli.js +3 -1
  50. package/dist/lib/runtime/cli-args.d.ts +5 -2
  51. package/dist/lib/runtime/cli-args.js +18 -3
  52. package/dist/lib/runtime/inference.js +3 -14
  53. package/dist/lib/runtime/models.d.ts +6 -0
  54. package/dist/lib/runtime/models.js +6 -0
  55. package/dist/lib/runtime/state-io.d.ts +2 -1
  56. package/dist/lib/runtime/state-io.js +9 -4
  57. package/dist/lib/runtime/utils.d.ts +8 -0
  58. package/dist/lib/runtime/utils.js +31 -1
  59. package/dist/lib/schemas.d.ts +250 -0
  60. package/dist/lib/schemas.js +216 -0
  61. package/dist/lib/sentinel-manager.d.ts +32 -0
  62. package/dist/lib/sentinel-manager.js +62 -0
  63. package/dist/lib/sentinel-wrapper.d.ts +1 -0
  64. package/dist/lib/sentinel-wrapper.js +12 -3
  65. package/dist/lib/settings-hierarchy.js +3 -20
  66. package/dist/lib/shell-adapters/bash-adapter.d.ts +18 -0
  67. package/dist/lib/shell-adapters/bash-adapter.js +69 -0
  68. package/dist/lib/shell-adapters/index.d.ts +5 -0
  69. package/dist/lib/shell-adapters/index.js +7 -0
  70. package/dist/lib/shell-adapters/powershell-adapter.d.ts +18 -0
  71. package/dist/lib/shell-adapters/powershell-adapter.js +62 -0
  72. package/dist/lib/shell-adapters/shell-adapter.d.ts +45 -0
  73. package/dist/lib/shell-adapters/shell-adapter.js +5 -0
  74. package/dist/lib/spawn-errors.d.ts +3 -0
  75. package/dist/lib/spawn-errors.js +15 -1
  76. package/dist/lib/spinner.d.ts +0 -5
  77. package/dist/lib/spinner.js +0 -16
  78. package/dist/lib/template-installer.d.ts +10 -0
  79. package/dist/lib/template-installer.js +4 -4
  80. package/dist/lib/terminal-strategy.d.ts +1 -0
  81. package/dist/lib/terminal-strategy.js +12 -6
  82. package/dist/lib/terminal.d.ts +7 -5
  83. package/dist/lib/terminal.js +42 -19
  84. package/dist/lib/tmux-primitives.d.ts +0 -2
  85. package/dist/lib/tmux-primitives.js +0 -4
  86. package/dist/lib/tmux-session.js +2 -1
  87. package/dist/lib/windsurf-hooks-hierarchy.js +6 -23
  88. package/dist/platform/launch.d.ts +2 -1
  89. package/dist/platform/launch.js +1 -0
  90. package/dist/templates/CLAUDE.md +0 -1
  91. package/dist/templates/cc-native/.claude/settings.json +0 -10
  92. package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +11 -4
  93. package/dist/templates/cc-native/_cc-native/cc-native.config.json +3 -7
  94. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +26 -47
  95. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +7 -9
  96. package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_write.ts +2 -3
  97. package/dist/templates/cc-native/_cc-native/hooks/mark_questions_asked.ts +2 -2
  98. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +0 -25
  99. package/dist/templates/cc-native/_cc-native/hooks/validate_task_prompt.ts +4 -4
  100. package/dist/templates/cc-native/_cc-native/lib-ts/.mocharc.json +9 -0
  101. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/aggregate-agents.test.ts +118 -0
  102. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/artifacts.test.ts +234 -0
  103. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/cc-native-state.test.ts +170 -0
  104. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/cli-output-parser.test.ts +73 -0
  105. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/config.test.ts +64 -0
  106. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/constants.test.ts +40 -0
  107. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/debug.test.ts +42 -0
  108. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/exports.test.ts +58 -0
  109. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/helpers.ts +107 -0
  110. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/hooks/add-plan-context.hook.test.ts +97 -0
  111. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/hooks/plan-questions.hook.test.ts +81 -0
  112. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/hooks/plan-review.hook.test.ts +71 -0
  113. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/json-parser.test.ts +99 -0
  114. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/orchestrator-agent.test.ts +288 -0
  115. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/orchestrator.test.ts +48 -0
  116. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/reviewers.test.ts +32 -0
  117. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/state.test.ts +124 -0
  118. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/verdict.test.ts +93 -0
  119. package/dist/templates/cc-native/_cc-native/lib-ts/agent-selection.ts +163 -0
  120. package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +6 -14
  121. package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/format.ts +597 -599
  122. package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/index.ts +26 -26
  123. package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/tracker.ts +106 -107
  124. package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/write.ts +118 -119
  125. package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +21 -0
  126. package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +16 -15
  127. package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +132 -10
  128. package/dist/templates/cc-native/_cc-native/lib-ts/constants.ts +6 -6
  129. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/corroboration.ts +119 -119
  130. package/dist/templates/cc-native/_cc-native/lib-ts/debug.ts +1 -2
  131. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/graduation.ts +132 -132
  132. package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +88 -86
  133. package/dist/templates/cc-native/_cc-native/lib-ts/json-parser.ts +5 -6
  134. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/orchestrator.ts +70 -70
  135. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/output-builder.ts +130 -121
  136. package/dist/templates/cc-native/_cc-native/lib-ts/package-lock.json +1679 -0
  137. package/dist/templates/cc-native/_cc-native/lib-ts/package.json +24 -0
  138. package/dist/templates/cc-native/_cc-native/lib-ts/plan-discovery.ts +4 -4
  139. package/dist/templates/cc-native/_cc-native/lib-ts/plan-enhancement.ts +1 -6
  140. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/plan-questions.ts +101 -101
  141. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/review-pipeline.ts +511 -543
  142. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/__tests__/agent-providers.test.ts +262 -0
  143. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/agent.ts +71 -85
  144. package/dist/templates/{core/lib-ts/agent-exec → cc-native/_cc-native/lib-ts/reviewers/base}/base-agent.ts +138 -152
  145. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/index.ts +12 -12
  146. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/claude-agent.ts +66 -57
  147. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/codex-agent.ts +185 -200
  148. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/gemini-agent.ts +39 -40
  149. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/orchestrator-claude-agent.ts +196 -224
  150. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/schemas.ts +201 -201
  151. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/types.ts +21 -23
  152. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/__tests__/hyde.test.ts +365 -0
  153. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/__tests__/ollama-client.test.ts +223 -0
  154. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/embedding-indexer.ts +12 -16
  155. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/hyde.ts +3 -2
  156. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/index.ts +31 -31
  157. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/logger.ts +6 -7
  158. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/ollama-client.ts +7 -9
  159. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/retrieval-pipeline.ts +14 -17
  160. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-indexer.ts +37 -41
  161. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-loader.ts +33 -43
  162. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-searcher.ts +20 -20
  163. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/types.ts +8 -9
  164. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/vector-store.ts +3 -4
  165. package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +50 -126
  166. package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +19 -21
  167. package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +13 -88
  168. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/verdict.ts +72 -72
  169. package/dist/templates/cc-native/_cc-native/plan-review/CLAUDE.md +35 -0
  170. package/dist/templates/cc-native/_cc-native/plan-review/lib/agent-selection.ts +1 -1
  171. package/dist/templates/cc-native/_cc-native/scripts/council_debate.ts +242 -0
  172. package/dist/templates/cc-native/_cc-native/scripts/council_debate_simple.ts +294 -0
  173. package/dist/templates/cc-native/_cc-native/{plan-review/workflows → workflows}/specdev.md +9 -9
  174. package/dist/templates/core/.claude/skills/codex/SKILL.md +25 -0
  175. package/dist/templates/core/.claude/skills/devin/SKILL.md +25 -0
  176. package/dist/templates/core/.claude/skills/handoff/SKILL.md +11 -0
  177. package/dist/templates/core/.claude/skills/handoff-resume/SKILL.md +11 -0
  178. package/dist/templates/core/.claude/skills/meta-plan/SKILL.md +13 -0
  179. package/dist/templates/core/.codex/skills/codex/SKILL.md +13 -0
  180. package/dist/templates/core/.codex/skills/devin/SKILL.md +19 -0
  181. package/dist/templates/core/.codex/skills/handoff/SKILL.md +11 -0
  182. package/dist/templates/core/.codex/skills/handoff-resume/SKILL.md +11 -0
  183. package/dist/templates/core/.codex/{workflows/meta-plan.md → skills/meta-plan/SKILL.md} +6 -0
  184. package/dist/templates/core/{.cognition → .devin}/AGENTS.md +2 -2
  185. package/dist/templates/core/.devin/skills/codex/SKILL.md +19 -0
  186. package/dist/templates/core/.devin/skills/devin/SKILL.md +13 -0
  187. package/dist/templates/core/.devin/skills/handoff/SKILL.md +11 -0
  188. package/dist/templates/core/.devin/skills/handoff-resume/SKILL.md +11 -0
  189. package/dist/templates/core/.devin/skills/meta-plan/SKILL.md +13 -0
  190. package/dist/templates/core/.windsurf/workflows/handoff-resume.md +9 -0
  191. package/dist/templates/core/hooks-ts/archive_plan.ts +1 -21
  192. package/dist/templates/core/hooks-ts/file-suggestion.ts +1 -19
  193. package/dist/templates/core/hooks-ts/pre_compact.ts +5 -18
  194. package/dist/templates/core/lib-ts/context/context-store.ts +29 -2
  195. package/dist/templates/core/lib-ts/hooks/hook-utils.ts +11 -0
  196. package/dist/templates/core/lib-ts/hooks/session-end-logic.ts +2 -13
  197. package/dist/templates/core/lib-ts/runtime/agent-launcher.ts +74 -0
  198. package/dist/templates/core/lib-ts/runtime/aiw-cli.ts +4 -2
  199. package/dist/templates/core/lib-ts/runtime/cli-args.ts +18 -4
  200. package/dist/templates/core/lib-ts/runtime/inference.ts +3 -15
  201. package/dist/templates/core/lib-ts/runtime/models.ts +7 -0
  202. package/dist/templates/core/lib-ts/runtime/state-io.ts +9 -4
  203. package/dist/templates/core/lib-ts/runtime/utils.ts +30 -1
  204. package/dist/templates/core/lib-ts/schemas.ts +233 -0
  205. package/dist/templates/core/scripts/resolve-run.ts +34 -2
  206. package/dist/templates/core/scripts/status_line.ts +1 -1
  207. package/dist/templates/core/skills/codex/CLAUDE.md +9 -4
  208. package/dist/templates/core/skills/codex/SKILL.md +6 -0
  209. package/dist/templates/core/skills/codex/lib/codex-watcher.ts +3 -10
  210. package/dist/templates/core/skills/codex/scripts/launch-codex.ts +26 -26
  211. package/dist/templates/core/skills/devin/CLAUDE.md +63 -6
  212. package/dist/templates/core/skills/devin/lib/devin-watcher.ts +116 -96
  213. package/dist/templates/core/skills/devin/scripts/launch-devin.ts +22 -21
  214. package/dist/templates/core/skills/handoff-system/CLAUDE.md +1 -1
  215. package/oclif.manifest.json +4 -4
  216. package/package.json +4 -4
  217. package/dist/lib/base-command.d.ts +0 -1
  218. package/dist/lib/base-command.js +0 -1
  219. package/dist/lib/env-compat.d.ts +0 -18
  220. package/dist/lib/env-compat.js +0 -23
  221. package/dist/lib/launch-options.d.ts +0 -1
  222. package/dist/lib/launch-options.js +0 -1
  223. package/dist/lib/stdin.d.ts +0 -48
  224. package/dist/lib/stdin.js +0 -60
  225. package/dist/templates/cc-native/_cc-native/CLAUDE.md +0 -73
  226. package/dist/templates/cc-native/_cc-native/artifacts/CLAUDE.md +0 -64
  227. package/dist/templates/cc-native/_cc-native/lib-ts/CLAUDE.md +0 -70
  228. package/dist/templates/cc-native/_cc-native/plan-review/CODING-STANDARDS-CHECKLIST.md +0 -75
  229. package/dist/templates/cc-native/_cc-native/plan-review/agents/CLAUDE.md +0 -143
  230. package/dist/templates/cc-native/_cc-native/plan-review/agents/PLAN-ORCHESTRATOR.md +0 -213
  231. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-questions/PLAN-QUESTIONER.md +0 -70
  232. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-EVOLUTION.md +0 -62
  233. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-PATTERNS.md +0 -61
  234. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-STRUCTURE.md +0 -62
  235. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ASSUMPTION-TRACER.md +0 -56
  236. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/CLARITY-AUDITOR.md +0 -53
  237. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-FEASIBILITY.md +0 -66
  238. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-GAPS.md +0 -70
  239. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-ORDERING.md +0 -62
  240. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/CONSTRAINT-VALIDATOR.md +0 -72
  241. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DESIGN-ADR-VALIDATOR.md +0 -61
  242. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DESIGN-SCALE-MATCHER.md +0 -64
  243. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DEVILS-ADVOCATE.md +0 -56
  244. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DOCUMENTATION-PHILOSOPHY.md +0 -86
  245. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/HANDOFF-READINESS.md +0 -59
  246. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/HIDDEN-COMPLEXITY.md +0 -58
  247. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/INCREMENTAL-DELIVERY.md +0 -66
  248. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-DEPENDENCY.md +0 -62
  249. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-FMEA.md +0 -66
  250. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-PREMORTEM.md +0 -71
  251. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-REVERSIBILITY.md +0 -74
  252. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SCOPE-BOUNDARY.md +0 -77
  253. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SIMPLICITY-GUARDIAN.md +0 -62
  254. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SKEPTIC.md +0 -68
  255. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-BEHAVIOR-AUDITOR.md +0 -61
  256. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-CHARACTERIZATION.md +0 -71
  257. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-FIRST-VALIDATOR.md +0 -61
  258. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-PYRAMID-ANALYZER.md +0 -61
  259. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TRADEOFF-COSTS.md +0 -67
  260. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TRADEOFF-STAKEHOLDERS.md +0 -65
  261. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/VERIFY-COVERAGE.md +0 -74
  262. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/VERIFY-STRENGTH.md +0 -69
  263. package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/base/base-agent.ts +0 -7
  264. package/dist/templates/core/.codex/workflows/codex.md +0 -17
  265. package/dist/templates/core/.codex/workflows/handoff.md +0 -5
  266. package/dist/templates/core/lib-ts/agent-exec/backends/headless.ts +0 -34
  267. package/dist/templates/core/lib-ts/agent-exec/backends/index.ts +0 -6
  268. package/dist/templates/core/lib-ts/agent-exec/backends/tmux.ts +0 -148
  269. package/dist/templates/core/lib-ts/agent-exec/execution-backend.ts +0 -50
  270. package/dist/templates/core/lib-ts/agent-exec/index.ts +0 -6
  271. package/dist/templates/core/lib-ts/agent-exec/structured-output.ts +0 -165
  272. /package/dist/templates/core/{.cognition → .devin}/config.json +0 -0
package/bin/run.js CHANGED
@@ -1,9 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // Load environment variable compatibility layer first
4
- const {loadEnvWithCompatibility} = await import('../dist/lib/env-compat.js')
5
- loadEnvWithCompatibility()
6
-
7
3
  import {execute} from '@oclif/core'
8
4
 
9
5
  // Handle default command: inject 'launch' when no command is specified
@@ -1,4 +1,5 @@
1
1
  import BaseCommand from '../../../cli/base-command.js';
2
+ export declare const PROTECTED_OUTPUT_DIRS: Set<string>;
2
3
  /**
3
4
  * Clear method runtime folders, output folders, IDE method folders, and update configurations.
4
5
  */
@@ -139,6 +140,7 @@ export default class ClearCommand extends BaseCommand {
139
140
  * @param cleanup.removedAiwcliContainer - Whether .aiwcli dir was removed
140
141
  * @param cleanup.removedClaudeDir - Whether .claude dir was removed
141
142
  * @param cleanup.removedCodexDir - Whether .codex dir was removed
143
+ * @param cleanup.removedDevinDir - Whether .devin dir was removed
142
144
  * @param cleanup.removedWindsurfDir - Whether .windsurf dir was removed
143
145
  * @param cleanup.removedCoreIdeFiles - Number of core IDE files removed
144
146
  * @param cleanup.updatedClaudeSettings - Whether Claude settings were updated
@@ -22,6 +22,7 @@ const OUTPUT_FOLDER_NAME = '_output';
22
22
  const CORE_TEMPLATE_NAME = 'core';
23
23
  const SETTINGS_FILES_TO_SKIP = new Set(['hooks.json', 'settings.json']);
24
24
  const CORE_RUNTIME_FOLDERS = ['_core'];
25
+ export const PROTECTED_OUTPUT_DIRS = new Set(['contexts', 'cache', '_archive']);
25
26
  /**
26
27
  * IDE configuration folder names and settings file locations.
27
28
  * Method subfolders are discovered dynamically via disk scanning.
@@ -34,6 +35,9 @@ const IDE_FOLDERS = {
34
35
  codex: {
35
36
  root: '.codex',
36
37
  },
38
+ devin: {
39
+ root: '.devin',
40
+ },
37
41
  windsurf: {
38
42
  root: '.windsurf',
39
43
  settingsFile: 'hooks.json',
@@ -441,6 +445,22 @@ export default class ClearCommand extends BaseCommand {
441
445
  }
442
446
  // Execute deletion and cleanup
443
447
  const deleteCounts = await this.executeFolderDeletion(methodRuntimeFolders, outputMethodFolders, ideMethodFolders, coreRuntimeFolders);
448
+ // Audit log for aiw clear operations (only if _output/ will survive — don't create orphan files)
449
+ try {
450
+ const outputDir = join(targetDir, OUTPUT_FOLDER_NAME);
451
+ if (await pathExists(outputDir) && !await isDirectoryEmpty(outputDir)) {
452
+ const hookLogPath = join(outputDir, 'hook-log.jsonl');
453
+ const logEntry = JSON.stringify({
454
+ ts: new Date().toISOString(),
455
+ level: 'warn',
456
+ hook: 'aiw_clear',
457
+ msg: `aiw clear: deleted ${deleteCounts.deletedMethodRuntime + deleteCounts.deletedOutput + deleteCounts.deletedIde + deleteCounts.deletedCoreRuntime} folder(s)`,
458
+ data: { methodRuntime: deleteCounts.deletedMethodRuntime, output: deleteCounts.deletedOutput, ide: deleteCounts.deletedIde, coreRuntime: deleteCounts.deletedCoreRuntime }
459
+ });
460
+ await fs.appendFile(hookLogPath, logEntry + '\n');
461
+ }
462
+ }
463
+ catch { /* non-critical */ }
444
464
  const cleanupResult = await this.performPostDeleteCleanup(targetDir, methodsToRemove, !isTemplateScoped);
445
465
  this.reportClearResults(deleteCounts, cleanupResult);
446
466
  }
@@ -753,9 +773,10 @@ export default class ClearCommand extends BaseCommand {
753
773
  this.log('');
754
774
  }
755
775
  // Check if IDE folders might be removed after clearing
756
- const [willClaudeFolderBeEmpty, willCodexFolderBeEmpty, willWindsurfFolderBeEmpty] = await Promise.all([
776
+ const [willClaudeFolderBeEmpty, willCodexFolderBeEmpty, willDevinFolderBeEmpty, willWindsurfFolderBeEmpty] = await Promise.all([
757
777
  checkIdeRemovalEligibility(targetDir, IDE_FOLDERS.claude, ideMethodFolders),
758
778
  checkIdeRemovalEligibility(targetDir, IDE_FOLDERS.codex, ideMethodFolders),
779
+ checkIdeRemovalEligibility(targetDir, IDE_FOLDERS.devin, ideMethodFolders),
759
780
  checkIdeRemovalEligibility(targetDir, IDE_FOLDERS.windsurf, ideMethodFolders),
760
781
  ]);
761
782
  if (willClaudeFolderBeEmpty) {
@@ -766,6 +787,10 @@ export default class ClearCommand extends BaseCommand {
766
787
  this.logInfo(`${IDE_FOLDERS.codex.root}/ folder will be removed (will be empty)`);
767
788
  this.log('');
768
789
  }
790
+ if (willDevinFolderBeEmpty) {
791
+ this.logInfo(`${IDE_FOLDERS.devin.root}/ folder will be removed (will be empty)`);
792
+ this.log('');
793
+ }
769
794
  if (willWindsurfFolderBeEmpty) {
770
795
  this.logInfo(`${IDE_FOLDERS.windsurf.root}/ folder will be removed (will be empty)`);
771
796
  this.log('');
@@ -958,7 +983,7 @@ export default class ClearCommand extends BaseCommand {
958
983
  try {
959
984
  const entries = await fs.readdir(outputDir, { withFileTypes: true });
960
985
  for (const entry of entries) {
961
- if (entry.isDirectory()) {
986
+ if (entry.isDirectory() && !PROTECTED_OUTPUT_DIRS.has(entry.name)) {
962
987
  foundFolders.push(join(outputDir, entry.name));
963
988
  }
964
989
  }
@@ -1024,6 +1049,7 @@ export default class ClearCommand extends BaseCommand {
1024
1049
  if (removedClaudeDir)
1025
1050
  updatedClaudeSettings = false;
1026
1051
  const removedCodexDir = await this.tryRemoveIdeFolder(targetDir, IDE_FOLDERS.codex);
1052
+ const removedDevinDir = await this.tryRemoveIdeFolder(targetDir, IDE_FOLDERS.devin);
1027
1053
  const removedWindsurfDir = await this.tryRemoveIdeFolder(targetDir, IDE_FOLDERS.windsurf);
1028
1054
  if (removedWindsurfDir)
1029
1055
  updatedWindsurfSettings = false;
@@ -1031,7 +1057,7 @@ export default class ClearCommand extends BaseCommand {
1031
1057
  const gitExcludeUpdated = await this.cleanupGitExclude(targetDir, isFullClear);
1032
1058
  return {
1033
1059
  removedCoreIdeFiles,
1034
- removedOutputDir, removedAiwcliContainer, removedClaudeDir, removedCodexDir, removedWindsurfDir,
1060
+ removedOutputDir, removedAiwcliContainer, removedClaudeDir, removedCodexDir, removedDevinDir, removedWindsurfDir,
1035
1061
  updatedClaudeSettings, updatedWindsurfSettings, gitExcludeUpdated,
1036
1062
  };
1037
1063
  }
@@ -1109,6 +1135,7 @@ export default class ClearCommand extends BaseCommand {
1109
1135
  * @param cleanup.removedAiwcliContainer - Whether .aiwcli dir was removed
1110
1136
  * @param cleanup.removedClaudeDir - Whether .claude dir was removed
1111
1137
  * @param cleanup.removedCodexDir - Whether .codex dir was removed
1138
+ * @param cleanup.removedDevinDir - Whether .devin dir was removed
1112
1139
  * @param cleanup.removedWindsurfDir - Whether .windsurf dir was removed
1113
1140
  * @param cleanup.removedCoreIdeFiles - Number of core IDE files removed
1114
1141
  * @param cleanup.updatedClaudeSettings - Whether Claude settings were updated
@@ -1135,6 +1162,8 @@ export default class ClearCommand extends BaseCommand {
1135
1162
  parts.push(`${IDE_FOLDERS.claude.root}/ folder`);
1136
1163
  if (cleanup.removedCodexDir)
1137
1164
  parts.push(`${IDE_FOLDERS.codex.root}/ folder`);
1165
+ if (cleanup.removedDevinDir)
1166
+ parts.push(`${IDE_FOLDERS.devin.root}/ folder`);
1138
1167
  if (cleanup.removedWindsurfDir)
1139
1168
  parts.push(`${IDE_FOLDERS.windsurf.root}/ folder`);
1140
1169
  this.logSuccess(`Cleared: ${parts.join(', ')}.`);
@@ -21,7 +21,7 @@ import { EXIT_CODES } from '../../../types/exit-codes.js';
21
21
  const KNOWN_IDES = [
22
22
  { value: 'claude', name: 'Claude Code', description: 'Anthropic Claude Code CLI' },
23
23
  { value: 'codex', name: 'Codex CLI', description: 'OpenAI Codex CLI skills' },
24
- { value: 'cognition', name: 'Cognition', description: 'Cognition (Devin) IDE' },
24
+ { value: 'devin', name: 'Devin', description: 'Devin CLI' },
25
25
  { value: 'windsurf', name: 'Windsurf', description: 'Codeium Windsurf IDE' },
26
26
  ];
27
27
  // detectGitRepository replaced by resolveGitDir from git-exclude-manager
@@ -237,7 +237,7 @@ export default class Init extends BaseCommand {
237
237
  */
238
238
  async installGlobalResolver() {
239
239
  try {
240
- const resolverSrc = getCoreResolverSourcePath();
240
+ const resolverSrc = await getCoreResolverSourcePath();
241
241
  const globalBinDir = join(homedir(), '.aiwcli', 'bin');
242
242
  const resolverDest = join(globalBinDir, 'resolve-run.ts');
243
243
  await fs.mkdir(globalBinDir, { recursive: true });
@@ -1,4 +1,37 @@
1
- import type { SplitPaneResult } from '../../platform/launch.js';
1
+ export type ToolMode = 'claude' | 'codex' | 'devin';
2
+ export interface ToolConfig {
3
+ cliCommand: string;
4
+ cliArgs: string[];
5
+ launchFlag: string;
6
+ toolMode: ToolMode;
7
+ retryOnQuickExit: boolean;
8
+ needsLspPatch: boolean;
9
+ skipVersionCheck: boolean;
10
+ }
11
+ export interface InlineFallbackContext {
12
+ disableMux: boolean;
13
+ hasMux: boolean;
14
+ interactiveTty: boolean;
15
+ platform: NodeJS.Platform;
16
+ resolvedReason?: string;
17
+ }
18
+ export interface SplitRequestParams {
19
+ toolArgs: string[];
20
+ splitPromptPath: string | undefined;
21
+ env: Record<string, string>;
22
+ cwd: string;
23
+ mode: 'repl';
24
+ split: 'auto' | 'horizontal' | 'vertical';
25
+ sentinelPath: string;
26
+ holdPane: boolean;
27
+ retryOnQuickExit: boolean;
28
+ }
29
+ export interface SessionRequestParams {
30
+ sessionName: string;
31
+ reattach: boolean;
32
+ toolArgs: string[];
33
+ promptText: string | undefined;
34
+ }
2
35
  export interface LaunchFlags {
3
36
  codex: boolean;
4
37
  devin: boolean;
@@ -10,7 +43,7 @@ export interface LaunchFlags {
10
43
  'prompt-file'?: string | undefined;
11
44
  'prompt-path'?: string | undefined;
12
45
  'spawned-window': boolean;
13
- split?: 'auto' | 'h' | 'v' | undefined;
46
+ split?: 'auto' | 'horizontal' | 'vertical' | undefined;
14
47
  'tmux-session'?: string | undefined;
15
48
  wait: boolean;
16
49
  }
@@ -40,12 +73,14 @@ export interface LaunchDependencies {
40
73
  pid: number;
41
74
  tempDir: string;
42
75
  writePromptFile(filePath: string, content: string): void;
76
+ isCalledFromRepl?: () => boolean;
77
+ clearNestingVars?: () => void;
43
78
  }
44
79
  export interface JsonLaunchResult {
45
- backend: SplitPaneResult['backend'];
80
+ backend: string;
46
81
  exitCode: null | number;
82
+ handle: null | string;
47
83
  launched: boolean;
48
- paneId: null | string;
49
84
  reason: null | string;
50
85
  sentinelPath: null | string;
51
86
  }
@@ -1,40 +1,46 @@
1
1
  import path from 'node:path';
2
- import { checkVersionCompatibility, configureTmuxSession, detectMultiplexer, ensureLspPatch, findExecutable, findToolPath, getClaudeCodeVersion, launchTerminal, ProcessSpawnError, quoteForSh, readSentinelExitCode, spawnProcess, waitForSentinelFile, } from '../../../platform/launch.js';
2
+ import { checkVersionCompatibility, detectMultiplexer, ensureLspPatch, findExecutable, findToolPath, getClaudeCodeVersion, launchTerminal, ProcessSpawnError, quoteForSh, spawnProcess, } from '../../../platform/launch.js';
3
3
  import { EXIT_CODES } from '../../../types/index.js';
4
- import { buildSpawnedWindowArgs, buildUniqueSessionName, parseExtraEnv, resolvePromptText, sanitizeSessionName, } from '../runtime-core/launch-options.js';
5
- function buildCodexArgs(platform) {
6
- if (platform !== 'win32')
7
- return ['--yolo'];
8
- return ['-c', 'shell_type="bash"', '--yolo'];
9
- }
10
- function buildDevinArgs() {
11
- return ['--permission-mode', 'dangerous'];
12
- }
13
- function toJsonLaunchResult(result, exitCode) {
14
- return {
15
- launched: result.launched,
16
- backend: result.backend,
17
- paneId: result.paneId ?? null,
18
- sentinelPath: result.sentinelPath ?? null,
19
- exitCode,
20
- reason: result.reason ?? null,
21
- };
4
+ import { clearProcessNestingVars, isCalledFromRepl } from '../../../lib/env-sanitizer.js';
5
+ import { PromptFileManager } from '../../../lib/prompt-file-manager.js';
6
+ import { SentinelManager } from '../../../lib/sentinel-manager.js';
7
+ import { formatPathWarning } from '../../../lib/spawn-errors.js';
8
+ import { buildSpawnedWindowArgs, parseExtraEnv, resolvePromptText, } from '../runtime-core/launch-options.js';
9
+ import { buildInlineArgs, buildSessionRequest, buildSplitRequest, formatSessionLaunchMessage, formatSplitSuccessMessage, formatVersionCheckMessages, QUICK_EXIT_THRESHOLD_MS, resolveInlineFallbackMessage, resolveSessionFallbackWarning, resolveToolConfig, resolveToolModeDebugMessage, shouldRetry, toJsonLaunchResult, } from '../runtime-core/launch-decisions.js';
10
+ async function runPreflightWarmup(command, host) {
11
+ try {
12
+ const result = await spawnProcess(command, ['--version'], { stdio: 'pipe' });
13
+ host.debug(`${command} preflight: exit=${result}`);
14
+ }
15
+ catch {
16
+ host.debug(`${command} preflight failed (non-fatal)`);
17
+ }
22
18
  }
23
- async function resolveWaitExitCode(result, wait) {
24
- if (!wait || !result.launched || !result.sentinelPath) {
25
- return result.exitCode ?? null;
19
+ async function spawnInlineWithRetry(command, args, retryOnQuickExit, host) {
20
+ if (retryOnQuickExit) {
21
+ await runPreflightWarmup(command, host);
26
22
  }
27
- const finished = await waitForSentinelFile(result.sentinelPath, 14_400_000);
28
- return finished ? readSentinelExitCode(result.sentinelPath, 1) : -1;
23
+ const start = Date.now();
24
+ let exitCode = await spawnProcess(command, args);
25
+ if (retryOnQuickExit && shouldRetry(Date.now() - start)) {
26
+ host.debug(`${command} exited in <${QUICK_EXIT_THRESHOLD_MS}ms — retrying (first-run init behavior)`);
27
+ exitCode = await spawnProcess(command, args);
28
+ }
29
+ return exitCode;
29
30
  }
30
31
  export async function executeLaunch(request, dependencies) {
31
32
  const { cwd, flags, interactiveTty, platform, readPromptFile } = request;
32
33
  const { host, now, pid, tempDir, writePromptFile } = dependencies;
33
- delete process.env['CLAUDECODE'];
34
- delete process.env['CLAUDE_CODE_ENTRYPOINT'];
35
- const useCodex = flags.codex;
36
- const useDevin = flags.devin;
37
- if (platform === 'win32' && !useCodex && !useDevin) {
34
+ // 1. Capture REPL context BEFORE clearing env vars (injectable for testing)
35
+ const calledFromRepl = (dependencies.isCalledFromRepl ?? isCalledFromRepl)();
36
+ (dependencies.clearNestingVars ?? clearProcessNestingVars)();
37
+ // Pure decision: resolve tool config
38
+ const toolConfig = resolveToolConfig(flags, platform);
39
+ const { cliCommand, cliArgs, launchFlag, toolMode } = toolConfig;
40
+ const disableMux = flags['no-tmux'];
41
+ const wantJson = flags.json;
42
+ const wantWait = flags.wait;
43
+ if (toolConfig.needsLspPatch) {
38
44
  await ensureLspPatch({
39
45
  debugLog: (message) => host.debug(message),
40
46
  warn(message) {
@@ -42,12 +48,6 @@ export async function executeLaunch(request, dependencies) {
42
48
  },
43
49
  });
44
50
  }
45
- const cliCommand = useDevin ? 'devin' : useCodex ? 'codex' : 'claude';
46
- const cliArgs = useDevin ? buildDevinArgs() : useCodex ? buildCodexArgs(platform) : ['--dangerously-skip-permissions'];
47
- const launchFlag = useDevin ? '--devin' : useCodex ? '--codex' : '';
48
- const disableTmux = flags['no-tmux'];
49
- const wantJson = flags.json;
50
- const wantWait = flags.wait;
51
51
  let extraEnv = {};
52
52
  try {
53
53
  extraEnv = parseExtraEnv(flags.env);
@@ -59,6 +59,7 @@ export async function executeLaunch(request, dependencies) {
59
59
  }
60
60
  const promptPath = flags['prompt-path']?.trim() || undefined;
61
61
  const promptText = resolvePromptText(flags.prompt, flags['prompt-file'], readPromptFile);
62
+ // 2. Handle --new (terminal window)
62
63
  if (flags.new) {
63
64
  host.debug(`Launching new terminal in: ${cwd}`);
64
65
  let promptFilePath;
@@ -67,9 +68,9 @@ export async function executeLaunch(request, dependencies) {
67
68
  writePromptFile(promptFilePath, promptText);
68
69
  }
69
70
  const launchArgs = buildSpawnedWindowArgs({
70
- useCodex,
71
- useDevin,
72
- disableTmux,
71
+ useCodex: flags.codex,
72
+ useDevin: flags.devin,
73
+ disableTmux: disableMux,
73
74
  ...(promptPath ? { promptPath } : {}),
74
75
  ...(promptFilePath ? { promptFilePath } : {}),
75
76
  ...(flags.env ? { rawEnvJson: flags.env } : {}),
@@ -88,127 +89,159 @@ export async function executeLaunch(request, dependencies) {
88
89
  host.log(`New terminal launched with aiw launch${launchFlag ? ` ${launchFlag}` : ''}`);
89
90
  return;
90
91
  }
91
- if (useCodex) {
92
- host.debug('Launching Codex with --yolo flag');
93
- }
94
- else if (useDevin) {
95
- host.debug('Launching Devin with --permission-mode dangerous');
96
- }
92
+ const toolDebugMsg = resolveToolModeDebugMessage(toolMode);
93
+ if (toolDebugMsg)
94
+ host.debug(toolDebugMsg);
95
+ // 3. Detect multiplexer + version check
97
96
  const [versionCheck, mux] = await Promise.all([
98
- useCodex || useDevin
97
+ toolConfig.skipVersionCheck
99
98
  ? null
100
99
  : getClaudeCodeVersion().then((v) => checkVersionCompatibility(v)),
101
- disableTmux ? null : detectMultiplexer(platform),
100
+ disableMux ? null : detectMultiplexer(platform),
102
101
  ]);
103
102
  if (versionCheck) {
104
- host.debug(`Claude Code version: ${versionCheck.version ?? 'unknown'}`);
105
- host.debug(`Compatibility status: ${versionCheck.compatible ? 'compatible' : 'incompatible'}`);
106
- if (versionCheck.warning) {
107
- host.warn(versionCheck.warning);
103
+ const msgs = formatVersionCheckMessages(versionCheck);
104
+ for (const line of msgs.debugLines)
105
+ host.debug(line);
106
+ if (msgs.warning)
107
+ host.warn(msgs.warning);
108
+ }
109
+ // 4. Resolve strategy — backend decides
110
+ const resolved = mux?.resolveStrategy({ calledFromRepl, platform, disableMux })
111
+ ?? { strategy: 'inline', reason: 'No multiplexer available' };
112
+ if (!mux || resolved.strategy === 'inline' || resolved.strategy === 'unavailable') {
113
+ // Pure decision: resolve fallback message
114
+ host.logInfo(resolveInlineFallbackMessage({
115
+ disableMux,
116
+ hasMux: Boolean(mux),
117
+ interactiveTty,
118
+ platform,
119
+ resolvedReason: resolved.reason,
120
+ }));
121
+ try {
122
+ // Pure decision: build inline args
123
+ const inlineArgs = buildInlineArgs(cliArgs, toolMode, promptText, promptPath);
124
+ const exitCode = await spawnInlineWithRetry(cliCommand, inlineArgs, toolConfig.retryOnQuickExit, host);
125
+ host.exit(exitCode);
126
+ }
127
+ catch (error) {
128
+ if (error instanceof ProcessSpawnError) {
129
+ host.error(error.message, { exit: EXIT_CODES.ENVIRONMENT_ERROR });
130
+ }
131
+ host.error('Unexpected launch failure.', { exit: EXIT_CODES.GENERAL_ERROR });
108
132
  }
133
+ return;
109
134
  }
135
+ // Lifecycle managers
136
+ const sentinelMgr = new SentinelManager();
137
+ const promptMgr = new PromptFileManager({ tempDir, now, pid });
138
+ // When --json is used without --wait, sentinel ownership transfers to the
139
+ // JSON caller (e.g. skill scripts). The CLI must NOT clean up the sentinel
140
+ // directory because the caller polls for sentinel.txt to detect pane close.
141
+ let sentinelOwnershipTransferred = false;
110
142
  let exitCode = 0;
111
143
  try {
112
- if (!mux) {
113
- if (disableTmux) {
114
- host.logInfo('Multiplexer disabled via --no-tmux — launching inline');
115
- }
116
- else if (!interactiveTty) {
117
- host.logInfo('Non-interactive terminal — launching inline');
118
- }
119
- else if (platform === 'win32') {
120
- host.logInfo('No multiplexer found — launching inline. Install psmux for session management: winget install psmux');
121
- }
122
- else {
123
- host.logInfo('No multiplexer found — launching inline. Install tmux for session management.');
124
- }
125
- exitCode = await spawnProcess(cliCommand, promptText ? [...cliArgs, promptText] : cliArgs);
126
- }
127
- else if (mux.isInsideSession()) {
144
+ const strategy = resolved.strategy;
145
+ if (strategy === 'split') {
146
+ // 5a. Split pane
128
147
  host.logInfo(`Inside ${mux.backend} session — splitting new pane`);
129
- if (mux.backend === 'tmux') {
130
- configureTmuxSession();
131
- }
148
+ const sentinelPath = sentinelMgr.create(cliCommand);
132
149
  let effectivePromptPath = promptPath;
133
150
  if (!effectivePromptPath && promptText) {
134
- effectivePromptPath = path.join(tempDir, `aiwcli-prompt-${now()}-${pid}.txt`);
135
- writePromptFile(effectivePromptPath, promptText);
151
+ effectivePromptPath = promptMgr.materialize(promptText);
136
152
  }
137
- const splitResult = await mux.splitPane({
138
- toolName: cliCommand,
139
- args: cliArgs,
140
- env: extraEnv,
153
+ // Pure decision: build split request (fixes cliArgs mutation bug)
154
+ const splitParams = buildSplitRequest({
155
+ cliArgs,
156
+ toolMode,
157
+ effectivePromptPath,
158
+ extraEnv,
141
159
  cwd,
142
160
  split: flags.split ?? 'auto',
143
- promptPath: effectivePromptPath,
144
- sentinel: wantWait || wantJson,
161
+ sentinelPath,
162
+ retryOnQuickExit: toolConfig.retryOnQuickExit,
163
+ });
164
+ const splitResult = await mux.split({
165
+ toolName: cliCommand,
166
+ args: splitParams.toolArgs,
167
+ env: splitParams.env,
168
+ cwd: splitParams.cwd,
169
+ mode: splitParams.mode,
170
+ split: splitParams.split,
171
+ promptPath: splitParams.splitPromptPath,
172
+ sentinelPath: splitParams.sentinelPath,
173
+ holdPane: splitParams.holdPane,
174
+ retryOnQuickExit: splitParams.retryOnQuickExit,
145
175
  });
146
176
  if (wantJson) {
147
- const jsonExitCode = await resolveWaitExitCode(splitResult, wantWait);
177
+ const jsonExitCode = wantWait && splitResult.launched && splitResult.sentinelPath
178
+ ? await sentinelMgr.waitForExit(splitResult.sentinelPath)
179
+ : splitResult.exitCode ?? null;
180
+ // When returning sentinel path to caller without waiting, transfer
181
+ // ownership so the finally block does not delete the directory.
182
+ if (!wantWait && splitResult.launched && splitResult.sentinelPath) {
183
+ sentinelOwnershipTransferred = true;
184
+ }
148
185
  host.log(JSON.stringify(toJsonLaunchResult(splitResult, jsonExitCode)));
149
186
  host.exit(jsonExitCode ?? 0);
150
187
  }
151
188
  if (splitResult.launched) {
152
- if (splitResult.paneId) {
153
- host.logInfo(`Launched in ${mux.backend} pane: ${splitResult.paneId}`);
154
- }
155
- else {
156
- host.logInfo(`Launched in ${mux.backend}`);
157
- }
189
+ host.logInfo(formatSplitSuccessMessage(mux.backend, splitResult.handle));
158
190
  if (wantWait && splitResult.sentinelPath) {
159
- const waitedExitCode = await resolveWaitExitCode(splitResult, true);
191
+ const waitedExitCode = await sentinelMgr.waitForExit(splitResult.sentinelPath);
160
192
  host.exit(waitedExitCode ?? 1);
161
193
  }
162
194
  return;
163
195
  }
164
196
  host.logWarning(`Pane split failed (${splitResult.reason}), launching directly`);
165
- exitCode = await spawnProcess(cliCommand, promptText ? [...cliArgs, promptText] : cliArgs);
197
+ // Pure decision: build inline args for fallback
198
+ const fallbackArgs = buildInlineArgs(cliArgs, toolMode, promptText, promptPath);
199
+ exitCode = await spawnInlineWithRetry(cliCommand, fallbackArgs, toolConfig.retryOnQuickExit, host);
166
200
  }
167
201
  else {
168
- const resolvedPath = mux.backend === 'psmux' ? findExecutable(cliCommand) : findToolPath(cliCommand);
202
+ // 5b. Create session
203
+ const resolvedPath = findToolPath(cliCommand) ?? findExecutable(cliCommand);
169
204
  if (resolvedPath) {
170
- const sessionFromFlag = flags['tmux-session']?.trim();
171
- const reattach = Boolean(sessionFromFlag && sessionFromFlag.length > 0);
172
- const sessionName = reattach
173
- ? sanitizeSessionName(sessionFromFlag)
174
- : buildUniqueSessionName(`aiw-${path.basename(cwd)}`, now(), pid);
175
- if (reattach) {
176
- host.logInfo(`Launching in ${mux.backend} session: ${sessionName} (reuse/attach)`);
177
- }
178
- else {
179
- host.logInfo(`Launching in new ${mux.backend} session: ${sessionName}`);
180
- }
205
+ // Pure decision: build session request
206
+ const sessionParams = buildSessionRequest({
207
+ cliArgs,
208
+ toolMode,
209
+ promptPath,
210
+ promptText,
211
+ tmuxSessionFlag: flags['tmux-session'],
212
+ cwd,
213
+ now: now(),
214
+ pid,
215
+ });
216
+ host.logInfo(formatSessionLaunchMessage(mux.backend, sessionParams.sessionName, sessionParams.reattach));
181
217
  const result = await mux.createSession({
182
- sessionName,
183
- reattach,
218
+ sessionName: sessionParams.sessionName,
219
+ reattach: sessionParams.reattach,
184
220
  toolPath: resolvedPath,
185
- toolArgs: cliArgs,
186
- promptText,
221
+ toolArgs: sessionParams.toolArgs,
222
+ cwd,
223
+ promptText: sessionParams.promptText,
187
224
  });
188
- if (result.usedMux) {
189
- exitCode = result.exitCode;
225
+ if (result.launched) {
226
+ exitCode = result.exitCode ?? 0;
227
+ if (wantJson) {
228
+ host.log(JSON.stringify(toJsonLaunchResult(result, exitCode)));
229
+ host.exit(exitCode);
230
+ }
190
231
  }
191
232
  else {
233
+ // Pure decision: resolve fallback warning
192
234
  if (result.reason) {
193
- if (result.reason.includes('not found') || result.reason.includes('unavailable')) {
194
- host.logWarning(`${mux.backend} unavailable — launching inline. ${mux.backend === 'psmux' ? 'Install with: winget install psmux' : ''}`);
195
- }
196
- else if (result.reason.includes('too old')) {
197
- host.logWarning(`${result.reason} — launching inline. ${mux.backend === 'psmux' ? 'Update with: winget upgrade psmux' : ''}`);
198
- }
199
- else if (mux.backend === 'psmux' && result.reason.includes('attach failed')) {
200
- host.logWarning(`${result.reason} — launching inline. Recovery: run "psmux kill-server" and relaunch if this persists.`);
201
- }
202
- else {
203
- host.logWarning(`${result.reason} — launching inline`);
204
- }
235
+ host.logWarning(resolveSessionFallbackWarning(mux.backend, result.reason));
205
236
  }
206
- exitCode = await spawnProcess(cliCommand, promptText ? [...cliArgs, promptText] : cliArgs);
237
+ const fallbackArgs = buildInlineArgs(cliArgs, toolMode, promptText, promptPath);
238
+ exitCode = await spawnInlineWithRetry(cliCommand, fallbackArgs, toolConfig.retryOnQuickExit, host);
207
239
  }
208
240
  }
209
241
  else {
210
- host.logWarning(`${cliCommand} not found on PATH (install from https://claude.ai/download)`);
211
- exitCode = await spawnProcess(cliCommand, promptText ? [...cliArgs, promptText] : cliArgs);
242
+ host.logWarning(formatPathWarning(cliCommand));
243
+ const fallbackArgs = buildInlineArgs(cliArgs, toolMode, promptText, promptPath);
244
+ exitCode = await spawnInlineWithRetry(cliCommand, fallbackArgs, toolConfig.retryOnQuickExit, host);
212
245
  }
213
246
  }
214
247
  }
@@ -218,5 +251,11 @@ export async function executeLaunch(request, dependencies) {
218
251
  }
219
252
  host.error('Unexpected launch failure.', { exit: EXIT_CODES.GENERAL_ERROR });
220
253
  }
254
+ finally {
255
+ if (!sentinelOwnershipTransferred) {
256
+ sentinelMgr.cleanupAll();
257
+ }
258
+ promptMgr.cleanup();
259
+ }
221
260
  host.exit(exitCode);
222
261
  }