aiwcli 0.15.5 → 0.15.7

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 (299) hide show
  1. package/README.md +6 -3
  2. package/dist/capabilities/branch/adapters.d.ts +2 -0
  3. package/dist/capabilities/branch/adapters.js +21 -0
  4. package/dist/capabilities/branch/contracts.d.ts +57 -0
  5. package/dist/capabilities/branch/contracts.js +1 -0
  6. package/dist/capabilities/branch/control-plane.d.ts +2 -0
  7. package/dist/capabilities/branch/control-plane.js +343 -0
  8. package/dist/capabilities/branch/runtime-core.d.ts +5 -0
  9. package/dist/capabilities/branch/runtime-core.js +36 -0
  10. package/dist/capabilities/installation/control-plane/clean-command.d.ts +41 -0
  11. package/dist/capabilities/installation/control-plane/clean-command.js +196 -0
  12. package/dist/capabilities/installation/control-plane/clear-command.d.ts +160 -0
  13. package/dist/capabilities/installation/control-plane/clear-command.js +1220 -0
  14. package/dist/capabilities/installation/control-plane/init-command.d.ts +81 -0
  15. package/dist/capabilities/installation/control-plane/init-command.js +449 -0
  16. package/dist/capabilities/launch/contracts.d.ts +51 -0
  17. package/dist/capabilities/launch/contracts.js +1 -0
  18. package/dist/capabilities/launch/control-plane/execute-launch.d.ts +2 -0
  19. package/dist/capabilities/launch/control-plane/execute-launch.js +222 -0
  20. package/dist/capabilities/launch/runtime-core/launch-options.d.ts +14 -0
  21. package/dist/capabilities/launch/runtime-core/launch-options.js +69 -0
  22. package/dist/cli/base-command.d.ts +18 -0
  23. package/dist/cli/base-command.js +55 -0
  24. package/dist/commands/branch.d.ts +0 -20
  25. package/dist/commands/branch.js +24 -416
  26. package/dist/commands/clean.d.ts +1 -41
  27. package/dist/commands/clean.js +1 -196
  28. package/dist/commands/clear.d.ts +1 -161
  29. package/dist/commands/clear.js +1 -1121
  30. package/dist/commands/init/index.d.ts +1 -98
  31. package/dist/commands/init/index.js +4 -478
  32. package/dist/commands/launch.d.ts +36 -11
  33. package/dist/commands/launch.js +135 -159
  34. package/dist/lib/base-command.d.ts +1 -114
  35. package/dist/lib/base-command.js +1 -153
  36. package/dist/lib/claude-settings-types.d.ts +31 -19
  37. package/dist/lib/context/context-formatter.d.ts +74 -0
  38. package/dist/lib/context/context-formatter.js +493 -0
  39. package/dist/lib/context/context-selector.d.ts +42 -0
  40. package/dist/lib/context/context-selector.js +451 -0
  41. package/dist/lib/context/context-store.d.ts +100 -0
  42. package/dist/lib/context/context-store.js +618 -0
  43. package/dist/lib/context/plan-manager.d.ts +54 -0
  44. package/dist/lib/context/plan-manager.js +282 -0
  45. package/dist/lib/context/task-tracker.d.ts +44 -0
  46. package/dist/lib/context/task-tracker.js +146 -0
  47. package/dist/lib/core-ide-base.d.ts +4 -0
  48. package/dist/lib/core-ide-base.js +77 -0
  49. package/dist/lib/core-installer.d.ts +5 -0
  50. package/dist/lib/core-installer.js +54 -0
  51. package/dist/lib/git-exclude-manager.d.ts +2 -2
  52. package/dist/lib/git-exclude-manager.js +3 -3
  53. package/dist/lib/hooks/hook-utils.d.ts +143 -0
  54. package/dist/lib/hooks/hook-utils.js +609 -0
  55. package/dist/lib/hooks/session-end-logic.d.ts +5 -0
  56. package/dist/lib/hooks/session-end-logic.js +63 -0
  57. package/dist/lib/hooks-merger.js +25 -19
  58. package/dist/lib/ide-path-resolver.d.ts +19 -7
  59. package/dist/lib/ide-path-resolver.js +25 -9
  60. package/dist/lib/install-state.d.ts +34 -0
  61. package/dist/lib/install-state.js +161 -0
  62. package/dist/lib/launch-options.d.ts +1 -0
  63. package/dist/lib/launch-options.js +1 -0
  64. package/dist/lib/lsp-patch.d.ts +12 -0
  65. package/dist/lib/lsp-patch.js +156 -0
  66. package/dist/lib/multiplexer.d.ts +57 -0
  67. package/dist/lib/multiplexer.js +19 -0
  68. package/dist/lib/multiplexers/psmux.d.ts +75 -0
  69. package/dist/lib/multiplexers/psmux.js +384 -0
  70. package/dist/lib/multiplexers/tmux.d.ts +44 -0
  71. package/dist/lib/multiplexers/tmux.js +262 -0
  72. package/dist/lib/mux-utils.d.ts +5 -0
  73. package/dist/lib/mux-utils.js +42 -0
  74. package/dist/lib/paths.d.ts +2 -2
  75. package/dist/lib/paths.js +2 -2
  76. package/dist/lib/platform-commands.d.ts +27 -0
  77. package/dist/lib/platform-commands.js +49 -0
  78. package/dist/lib/runtime/aiw-cli.d.ts +37 -0
  79. package/dist/lib/runtime/aiw-cli.js +74 -0
  80. package/dist/lib/runtime/atomic-write.d.ts +19 -0
  81. package/dist/lib/runtime/atomic-write.js +121 -0
  82. package/dist/lib/runtime/cli-args.d.ts +55 -0
  83. package/dist/lib/runtime/cli-args.js +185 -0
  84. package/dist/lib/runtime/constants.d.ts +56 -0
  85. package/dist/lib/runtime/constants.js +230 -0
  86. package/dist/lib/runtime/executable-policy.d.ts +16 -0
  87. package/dist/lib/runtime/executable-policy.js +57 -0
  88. package/dist/lib/runtime/git-state.d.ts +9 -0
  89. package/dist/lib/runtime/git-state.js +59 -0
  90. package/dist/lib/runtime/inference.d.ts +37 -0
  91. package/dist/lib/runtime/inference.js +262 -0
  92. package/dist/lib/runtime/lint-dispatch.d.ts +40 -0
  93. package/dist/lib/runtime/lint-dispatch.js +285 -0
  94. package/dist/lib/runtime/logger.d.ts +66 -0
  95. package/dist/lib/runtime/logger.js +201 -0
  96. package/dist/lib/runtime/models.d.ts +14 -0
  97. package/dist/lib/runtime/models.js +14 -0
  98. package/dist/lib/runtime/platform-adapter.d.ts +7 -0
  99. package/dist/lib/runtime/platform-adapter.js +21 -0
  100. package/dist/lib/runtime/preflight.d.ts +24 -0
  101. package/dist/lib/runtime/preflight.js +65 -0
  102. package/dist/lib/runtime/sentinel-ipc.d.ts +14 -0
  103. package/dist/lib/runtime/sentinel-ipc.js +67 -0
  104. package/dist/lib/runtime/state-io.d.ts +30 -0
  105. package/dist/lib/runtime/state-io.js +174 -0
  106. package/dist/lib/runtime/stop-words.d.ts +20 -0
  107. package/dist/lib/runtime/stop-words.js +150 -0
  108. package/dist/lib/runtime/subprocess-utils.d.ts +29 -0
  109. package/dist/lib/runtime/subprocess-utils.js +96 -0
  110. package/dist/lib/runtime/tmux-preflight.d.ts +13 -0
  111. package/dist/lib/runtime/tmux-preflight.js +78 -0
  112. package/dist/lib/runtime/utils.d.ts +54 -0
  113. package/dist/lib/runtime/utils.js +162 -0
  114. package/dist/lib/sentinel-wrapper.d.ts +9 -0
  115. package/dist/lib/sentinel-wrapper.js +20 -0
  116. package/dist/lib/shell-quoting.d.ts +5 -0
  117. package/dist/lib/shell-quoting.js +17 -0
  118. package/dist/lib/spawn-errors.d.ts +6 -0
  119. package/dist/lib/spawn-errors.js +15 -0
  120. package/dist/lib/spawn.js +5 -11
  121. package/dist/lib/template-installer.d.ts +4 -5
  122. package/dist/lib/template-installer.js +36 -34
  123. package/dist/lib/template-resolver.d.ts +6 -7
  124. package/dist/lib/template-resolver.js +26 -21
  125. package/dist/lib/template-settings-reconstructor.d.ts +7 -2
  126. package/dist/lib/template-settings-reconstructor.js +76 -45
  127. package/dist/lib/terminal-strategy.d.ts +11 -0
  128. package/dist/lib/terminal-strategy.js +49 -0
  129. package/dist/lib/terminal.d.ts +28 -0
  130. package/dist/lib/terminal.js +162 -112
  131. package/dist/lib/tmux-pane-placement.d.ts +17 -0
  132. package/dist/lib/tmux-pane-placement.js +58 -0
  133. package/dist/lib/tmux-primitives.d.ts +5 -0
  134. package/dist/lib/tmux-primitives.js +15 -0
  135. package/dist/lib/tmux-session.d.ts +32 -0
  136. package/dist/lib/tmux-session.js +86 -0
  137. package/dist/lib/tty-detection.js +1 -1
  138. package/dist/lib/types.d.ts +168 -0
  139. package/dist/lib/types.js +6 -0
  140. package/dist/lib/version.d.ts +1 -1
  141. package/dist/lib/version.js +1 -1
  142. package/dist/platform/launch.d.ts +10 -0
  143. package/dist/platform/launch.js +10 -0
  144. package/dist/templates/CLAUDE.md +31 -40
  145. package/dist/templates/cc-native/.claude/settings.json +27 -27
  146. package/dist/templates/cc-native/CC-NATIVE-README.md +1 -1
  147. package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +10 -9
  148. package/dist/templates/cc-native/_cc-native/CLAUDE.md +18 -18
  149. package/dist/templates/cc-native/_cc-native/artifacts/CLAUDE.md +3 -3
  150. package/dist/templates/cc-native/_cc-native/artifacts/lib/format.ts +14 -14
  151. package/dist/templates/cc-native/_cc-native/artifacts/lib/tracker.ts +1 -1
  152. package/dist/templates/cc-native/_cc-native/artifacts/lib/write.ts +3 -3
  153. package/dist/templates/cc-native/_cc-native/cc-native.config.json +3 -3
  154. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +16 -15
  155. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +3 -3
  156. package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_subagent.ts +2 -2
  157. package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_write.ts +2 -2
  158. package/dist/templates/cc-native/_cc-native/hooks/mark_questions_asked.ts +3 -3
  159. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +2 -2
  160. package/dist/templates/cc-native/_cc-native/hooks/validate_task_prompt.ts +3 -3
  161. package/dist/templates/cc-native/_cc-native/lib-ts/CLAUDE.md +8 -8
  162. package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +1 -1
  163. package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +4 -4
  164. package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +1 -1
  165. package/dist/templates/cc-native/_cc-native/lib-ts/config.ts +1 -1
  166. package/dist/templates/cc-native/_cc-native/lib-ts/debug.ts +1 -1
  167. package/dist/templates/cc-native/_cc-native/lib-ts/json-parser.ts +1 -1
  168. package/dist/templates/cc-native/_cc-native/lib-ts/plan-discovery.ts +2 -2
  169. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/logger.ts +1 -1
  170. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/retrieval-pipeline.ts +2 -2
  171. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/types.ts +1 -1
  172. package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +8 -8
  173. package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +3 -3
  174. package/dist/templates/cc-native/_cc-native/lib-ts/tsconfig.json +2 -2
  175. package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +3 -3
  176. package/dist/templates/cc-native/_cc-native/plan-review/CLAUDE.md +3 -1
  177. package/dist/templates/cc-native/_cc-native/plan-review/lib/__tests__/agent-selection.test.ts +345 -0
  178. package/dist/templates/cc-native/_cc-native/plan-review/lib/__tests__/preflight.test.ts +344 -0
  179. package/dist/templates/cc-native/_cc-native/plan-review/lib/agent-selection.ts +37 -15
  180. package/dist/templates/cc-native/_cc-native/plan-review/lib/corroboration.ts +16 -69
  181. package/dist/templates/cc-native/_cc-native/plan-review/lib/orchestrator.ts +1 -1
  182. package/dist/templates/cc-native/_cc-native/plan-review/lib/output-builder.ts +1 -1
  183. package/dist/templates/cc-native/_cc-native/plan-review/lib/plan-questions.ts +2 -2
  184. package/dist/templates/cc-native/_cc-native/plan-review/lib/preflight.ts +56 -26
  185. package/dist/templates/cc-native/_cc-native/plan-review/lib/review-pipeline.ts +7 -7
  186. package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/agent.ts +4 -4
  187. package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/base/base-agent.ts +3 -3
  188. package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/index.ts +1 -1
  189. package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/providers/claude-agent.ts +2 -2
  190. package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/providers/codex-agent.ts +4 -4
  191. package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/providers/gemini-agent.ts +1 -1
  192. package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/providers/orchestrator-claude-agent.ts +5 -6
  193. package/dist/templates/core/.codex/workflows/codex.md +17 -0
  194. package/dist/templates/core/.codex/workflows/handoff.md +5 -0
  195. package/dist/templates/core/.codex/workflows/meta-plan.md +7 -0
  196. package/dist/templates/core/.cognition/AGENTS.md +5 -0
  197. package/dist/templates/core/.cognition/config.json +12 -0
  198. package/dist/templates/{_shared → core}/.windsurf/workflows/handoff.md +1 -1
  199. package/dist/templates/{_shared → core}/.windsurf/workflows/meta-plan.md +1 -1
  200. package/dist/templates/core/hooks-ts/_utils/git-state.ts +2 -0
  201. package/dist/templates/{_shared → core}/hooks-ts/archive_plan.ts +14 -23
  202. package/dist/templates/core/hooks-ts/codex_explorer.ts +160 -0
  203. package/dist/templates/{_shared → core}/hooks-ts/context_monitor.ts +23 -55
  204. package/dist/templates/{_shared → core}/hooks-ts/file-suggestion.ts +4 -3
  205. package/dist/templates/{_shared → core}/hooks-ts/lint_after_edit.ts +7 -9
  206. package/dist/templates/{_shared → core}/hooks-ts/pre_compact.ts +5 -5
  207. package/dist/templates/{_shared → core}/hooks-ts/session_end.ts +38 -78
  208. package/dist/templates/{_shared → core}/hooks-ts/session_start.ts +5 -5
  209. package/dist/templates/core/hooks-ts/task_create_capture.ts +32 -0
  210. package/dist/templates/{_shared → core}/hooks-ts/task_update_capture.ts +9 -24
  211. package/dist/templates/core/hooks-ts/user_prompt_submit.ts +46 -0
  212. package/dist/templates/{_shared → core}/lib-ts/CLAUDE.md +27 -16
  213. package/dist/templates/{_shared → core}/lib-ts/agent-exec/backends/headless.ts +3 -2
  214. package/dist/templates/{_shared → core}/lib-ts/agent-exec/backends/tmux.ts +44 -15
  215. package/dist/templates/{_shared → core}/lib-ts/agent-exec/base-agent.ts +6 -4
  216. package/dist/templates/{_shared → core}/lib-ts/agent-exec/execution-backend.ts +1 -1
  217. package/dist/templates/{_shared → core}/lib-ts/agent-exec/index.ts +2 -2
  218. package/dist/templates/{_shared → core}/lib-ts/agent-exec/structured-output.ts +4 -5
  219. package/dist/templates/{_shared → core}/lib-ts/context/CLAUDE.md +9 -6
  220. package/dist/templates/{_shared → core}/lib-ts/context/context-formatter.ts +16 -21
  221. package/dist/templates/{_shared → core}/lib-ts/context/context-selector.ts +8 -6
  222. package/dist/templates/{_shared → core}/lib-ts/context/context-store.ts +32 -20
  223. package/dist/templates/{_shared → core}/lib-ts/context/plan-manager.ts +19 -15
  224. package/dist/templates/{_shared → core}/lib-ts/context/task-tracker.ts +3 -3
  225. package/dist/templates/core/lib-ts/hooks/context-monitor-logic.ts +32 -0
  226. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/hooks}/hook-utils.ts +168 -41
  227. package/dist/templates/core/lib-ts/hooks/prompt-binding-logic.ts +80 -0
  228. package/dist/templates/core/lib-ts/hooks/session-end-logic.ts +93 -0
  229. package/dist/templates/core/lib-ts/package.json +19 -0
  230. package/dist/templates/core/lib-ts/runtime/agent-launcher.ts +295 -0
  231. package/dist/templates/core/lib-ts/runtime/aiw-cli.ts +106 -0
  232. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/atomic-write.ts +12 -7
  233. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/cli-args.ts +8 -6
  234. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/constants.ts +326 -324
  235. package/dist/templates/core/lib-ts/runtime/executable-policy.ts +89 -0
  236. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/git-state.ts +6 -4
  237. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/inference.ts +59 -10
  238. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/lint-dispatch.ts +25 -23
  239. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/logger.ts +32 -29
  240. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/models.ts +2 -2
  241. package/dist/templates/core/lib-ts/runtime/platform-adapter.ts +33 -0
  242. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/preflight.ts +4 -3
  243. package/dist/templates/core/lib-ts/runtime/sentinel-ipc.ts +91 -0
  244. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/state-io.ts +11 -7
  245. package/dist/templates/core/lib-ts/runtime/stop-words.ts +185 -0
  246. package/dist/templates/core/lib-ts/runtime/subprocess-utils.ts +147 -0
  247. package/dist/templates/core/lib-ts/runtime/tmux-preflight.ts +93 -0
  248. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/utils.ts +4 -3
  249. package/dist/templates/{_shared → core}/lib-ts/templates/formatters.ts +7 -5
  250. package/dist/templates/{_shared → core}/lib-ts/templates/plan-context.ts +2 -1
  251. package/dist/templates/{_shared → core}/lib-ts/tsconfig.json +3 -1
  252. package/dist/templates/{_shared → core}/lib-ts/types.ts +78 -77
  253. package/dist/templates/core/scripts/resolve-run.ts +61 -0
  254. package/dist/templates/{_shared → core}/scripts/resolve_context.ts +3 -3
  255. package/dist/templates/{_shared → core}/scripts/status_line.ts +25 -20
  256. package/dist/templates/core/skills/codex/CLAUDE.md +78 -0
  257. package/dist/templates/{_shared → core}/skills/codex/SKILL.md +21 -18
  258. package/dist/templates/{_shared → core}/skills/codex/lib/codex-watcher.ts +76 -103
  259. package/dist/templates/{_shared → core}/skills/codex/scripts/launch-codex.ts +119 -133
  260. package/dist/templates/{_shared → core}/skills/codex/scripts/watch-codex.ts +6 -4
  261. package/dist/templates/core/skills/devin/CLAUDE.md +65 -0
  262. package/dist/templates/core/skills/devin/SKILL.md +73 -0
  263. package/dist/templates/core/skills/devin/lib/devin-watcher.ts +280 -0
  264. package/dist/templates/core/skills/devin/scripts/launch-devin.ts +257 -0
  265. package/dist/templates/{_shared → core}/skills/handoff-system/CLAUDE.md +436 -433
  266. package/dist/templates/{_shared → core}/skills/handoff-system/lib/document-generator.ts +9 -7
  267. package/dist/templates/{_shared → core}/skills/handoff-system/lib/handoff-reader.ts +6 -4
  268. package/dist/templates/{_shared → core}/skills/handoff-system/scripts/resume_handoff.ts +10 -8
  269. package/dist/templates/{_shared → core}/skills/handoff-system/scripts/save_handoff.ts +12 -10
  270. package/dist/templates/{_shared → core}/skills/handoff-system/workflows/handoff-resume.md +2 -2
  271. package/dist/templates/{_shared → core}/skills/handoff-system/workflows/handoff.md +6 -5
  272. package/dist/templates/{_shared → core}/skills/meta-plan/CLAUDE.md +2 -1
  273. package/dist/templates/{_shared → core}/skills/meta-plan/workflows/meta-plan.md +8 -7
  274. package/oclif.manifest.json +89 -13
  275. package/package.json +13 -12
  276. package/dist/templates/_shared/.claude/settings.json +0 -120
  277. package/dist/templates/_shared/.claude/skills/codex/SKILL.md +0 -35
  278. package/dist/templates/_shared/.claude/skills/handoff/SKILL.md +0 -13
  279. package/dist/templates/_shared/.claude/skills/handoff-resume/SKILL.md +0 -13
  280. package/dist/templates/_shared/.claude/skills/meta-plan/SKILL.md +0 -43
  281. package/dist/templates/_shared/.codex/workflows/codex.md +0 -11
  282. package/dist/templates/_shared/.codex/workflows/handoff.md +0 -226
  283. package/dist/templates/_shared/.codex/workflows/meta-plan.md +0 -347
  284. package/dist/templates/_shared/hooks-ts/_utils/git-state.ts +0 -2
  285. package/dist/templates/_shared/hooks-ts/task_create_capture.ts +0 -48
  286. package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +0 -93
  287. package/dist/templates/_shared/lib-ts/base/launchers/tmux-launcher.ts +0 -173
  288. package/dist/templates/_shared/lib-ts/base/launchers/window-launcher.ts +0 -93
  289. package/dist/templates/_shared/lib-ts/base/launchers/wt-launcher.ts +0 -64
  290. package/dist/templates/_shared/lib-ts/base/pane-launcher.ts +0 -55
  291. package/dist/templates/_shared/lib-ts/base/sentinel-ipc.ts +0 -87
  292. package/dist/templates/_shared/lib-ts/base/stop-words.ts +0 -184
  293. package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +0 -249
  294. package/dist/templates/_shared/lib-ts/base/tmux-driver.ts +0 -341
  295. package/dist/templates/_shared/lib-ts/base/tmux-pane-placement.ts +0 -78
  296. package/dist/templates/_shared/lib-ts/package.json +0 -20
  297. package/dist/templates/_shared/scripts/resolve-run.ts +0 -62
  298. package/dist/templates/_shared/skills/codex/CLAUDE.md +0 -70
  299. /package/dist/templates/{_shared → core}/lib-ts/agent-exec/backends/index.ts +0 -0
package/dist/lib/spawn.js CHANGED
@@ -41,6 +41,7 @@
41
41
  import { execSync, spawn as nodeSpawn } from 'node:child_process';
42
42
  import { debug, debugSpawn } from './debug.js';
43
43
  import { ProcessSpawnError } from './errors.js';
44
+ import { classifySpawnError, resolveWindowsSpawnArgs } from './spawn-errors.js';
44
45
  /**
45
46
  * Spawn an external process and return its exit code.
46
47
  *
@@ -94,9 +95,10 @@ export async function spawnProcess(command, args = [], options = {}) {
94
95
  catch (error) {
95
96
  // If command not found and .cmd file exists, use cmd.exe wrapper
96
97
  // This avoids DEP0190 deprecation warning while supporting npm-installed commands
97
- if (error instanceof ProcessSpawnError && error.code === 'ENOENT' && commandExistsInPath(`${command}.cmd`)) {
98
+ const windowsSpawnArgs = resolveWindowsSpawnArgs(command, args, commandExistsInPath);
99
+ if (error instanceof ProcessSpawnError && error.code === 'ENOENT' && windowsSpawnArgs) {
98
100
  // Use cmd.exe /c to execute .cmd file without shell mode or deprecation warning
99
- return attemptSpawn('cmd.exe', ['/c', command, ...args], { cwd, stdio, detached, shell: false });
101
+ return attemptSpawn(windowsSpawnArgs.command, windowsSpawnArgs.args, { cwd, stdio, detached, shell: false });
100
102
  }
101
103
  throw error;
102
104
  }
@@ -126,15 +128,7 @@ function attemptSpawn(command, args, spawnOptions) {
126
128
  const childProcess = nodeSpawn(command, args, spawnOptions);
127
129
  // Handle spawn errors (ENOENT, EACCES, etc.)
128
130
  childProcess.on('error', (error) => {
129
- if (error.code === 'ENOENT') {
130
- reject(new ProcessSpawnError(`Command not found: ${command}. Install Claude Code from https://claude.ai/download.`, 'ENOENT'));
131
- }
132
- else if (error.code === 'EACCES') {
133
- reject(new ProcessSpawnError(`Permission denied: ${command}. Check file permissions.`, 'EACCES'));
134
- }
135
- else {
136
- reject(new ProcessSpawnError(`Failed to spawn ${command}: ${error.message}. Check that the command exists and is executable.`, error.code));
137
- }
131
+ reject(classifySpawnError(command, error));
138
132
  });
139
133
  // Capture exit code on process close
140
134
  childProcess.on('close', (code, signal) => {
@@ -34,10 +34,10 @@ interface TemplateInstallationStatus {
34
34
  existing: TemplateItemStatus[];
35
35
  /** Items that are missing from target directory */
36
36
  missing: TemplateItemStatus[];
37
- /** The method-specific workflow folder name (e.g., '_gsd', '_bmad') */
38
- workflowFolder: null | string;
39
- /** Whether the workflow folder exists */
40
- workflowFolderExists: boolean;
37
+ /** The method-specific runtime folder name (e.g., '_gsd', '_bmad') */
38
+ runtimeFolder: null | string;
39
+ /** Whether the runtime folder exists */
40
+ runtimeFolderExists: boolean;
41
41
  }
42
42
  /**
43
43
  * Result of template installation
@@ -79,7 +79,6 @@ export declare function copyDir(src: string, dest: string, excludeIdeFolders?: b
79
79
  *
80
80
  * Template structure:
81
81
  * - Non-dot folders (e.g., _bmad/, GSR/) → .aiwcli/ (always overwritten)
82
- * - _shared/ → .aiwcli/_shared/ (always overwritten)
83
82
  * - IDE dot folders (e.g., .claude/) → decomposed into method-owned subdirs
84
83
  *
85
84
  * Settings reconstruction is handled separately by the caller via reconstructIdeSettings().
@@ -1,5 +1,5 @@
1
1
  import { promises as fs } from 'node:fs';
2
- import { dirname, join } from 'node:path';
2
+ import { join } from 'node:path';
3
3
  import { IdePathResolver } from './ide-path-resolver.js';
4
4
  import { pathExists } from './paths.js';
5
5
  /**
@@ -17,11 +17,11 @@ export async function checkTemplateStatus(templatePath, targetDir, ides, templat
17
17
  const missing = [];
18
18
  // Scan template directory
19
19
  const entries = await fs.readdir(templatePath, { withFileTypes: true });
20
- // Identify workflow folder based on template name
20
+ // Identify method runtime folder based on template name
21
21
  // Convention: _templatename (e.g., _gsd, _bmad)
22
- const workflowFolderName = `_${templateName}`;
23
- let workflowFolder = null;
24
- let workflowFolderExists = false;
22
+ const runtimeFolderName = `_${templateName}`;
23
+ let runtimeFolder = null;
24
+ let runtimeFolderExists = false;
25
25
  // Filter entries to only include relevant items (skip non-selected IDE folders and excluded patterns)
26
26
  const relevantEntries = entries.filter((entry) => {
27
27
  // Skip excluded patterns (test files, cache, etc.)
@@ -58,17 +58,17 @@ export async function checkTemplateStatus(templatePath, targetDir, ides, templat
58
58
  else {
59
59
  missing.push(status);
60
60
  }
61
- // Track workflow folder
62
- if (status.name === workflowFolderName) {
63
- workflowFolder = workflowFolderName;
64
- workflowFolderExists = status.exists;
61
+ // Track method runtime folder
62
+ if (status.name === runtimeFolderName) {
63
+ runtimeFolder = runtimeFolderName;
64
+ runtimeFolderExists = status.exists;
65
65
  }
66
66
  }
67
67
  return {
68
68
  existing,
69
69
  missing,
70
- workflowFolder,
71
- workflowFolderExists,
70
+ runtimeFolder,
71
+ runtimeFolderExists,
72
72
  };
73
73
  }
74
74
  /**
@@ -101,7 +101,7 @@ export async function copyDir(src, dest, excludeIdeFolders = false) {
101
101
  if (shouldExclude(entry.name)) {
102
102
  return false;
103
103
  }
104
- // Exclude IDE config folders if requested (used for _shared folder)
104
+ // Exclude IDE config folders if requested (used for core folder)
105
105
  // These folders are used for settings merging, not direct installation
106
106
  if (excludeIdeFolders && entry.isDirectory() && entry.name.startsWith('.')) {
107
107
  return false;
@@ -150,7 +150,6 @@ async function mergeDirectory(src, dest) {
150
150
  *
151
151
  * Template structure:
152
152
  * - Non-dot folders (e.g., _bmad/, GSR/) → .aiwcli/ (always overwritten)
153
- * - _shared/ → .aiwcli/_shared/ (always overwritten)
154
153
  * - IDE dot folders (e.g., .claude/) → decomposed into method-owned subdirs
155
154
  *
156
155
  * Settings reconstruction is handled separately by the caller via reconstructIdeSettings().
@@ -205,27 +204,6 @@ export async function installTemplate(config) {
205
204
  });
206
205
  const nonDotResults = await Promise.all(nonDotInstalls);
207
206
  installedFolders.push(...nonDotResults);
208
- // Install root-level _shared directory (shared across all templates)
209
- // Exclude IDE config folders (.claude, .windsurf) - they are used for settings merging only
210
- const templatesRoot = dirname(templatePath);
211
- const rootSharedSrc = join(templatesRoot, '_shared');
212
- const rootSharedDest = join(containerDir, '_shared');
213
- if (await pathExists(rootSharedSrc)) {
214
- await copyDir(rootSharedSrc, rootSharedDest, true); // excludeIdeFolders = true
215
- installedFolders.push('_shared');
216
- // Copy shared IDE content (e.g., _shared/.claude/commands/handoff.md)
217
- // These are non-method-owned files that live in IDE folders
218
- const sharedIdeInstalls = ides.map(async (ide) => {
219
- const sharedIdeFolder = join(rootSharedSrc, `.${ide}`);
220
- if (await pathExists(sharedIdeFolder)) {
221
- const destIdeFolder = resolver.getIdeDir(ide);
222
- await fs.mkdir(destIdeFolder, { recursive: true });
223
- // Merge shared IDE content, skipping files that already exist
224
- await mergeDirectory(sharedIdeFolder, destIdeFolder);
225
- }
226
- });
227
- await Promise.all(sharedIdeInstalls);
228
- }
229
207
  // Install method-owned IDE content (decomposed approach)
230
208
  // Instead of copying entire .claude/ from template, only copy method-namespaced subdirectories
231
209
  const ideInstalls = ides.map(async (ide) => {
@@ -260,9 +238,33 @@ export async function installTemplate(config) {
260
238
  const ideResults = (await Promise.all(ideInstalls)).filter((result) => result !== null);
261
239
  installedFolders.push(...ideResults);
262
240
  // Settings reconstruction is handled by the caller via reconstructIdeSettings()
241
+ // Write resolved CLI binary path so template scripts can shell out to `aiw`
242
+ await writeAiwBinPath(containerDir);
263
243
  return {
264
244
  installedFolders,
265
245
  sharedSettingsMerged: false,
266
246
  templatePath,
267
247
  };
268
248
  }
249
+ /**
250
+ * Write the resolved `aiw` binary path to `.aiwcli/.aiw-bin-path`.
251
+ * Template scripts read this file to find the CLI binary for `aiw launch`.
252
+ */
253
+ async function writeAiwBinPath(containerDir) {
254
+ try {
255
+ // process.argv[1] is the main script entry point (e.g., /path/to/aiw/bin/run.js)
256
+ // Resolve to the bin directory to find the actual `aiw` executable
257
+ const { execSync } = await import('node:child_process');
258
+ const cmd = process.platform === 'win32' ? 'where aiw' : 'which aiw';
259
+ const resolved = execSync(cmd, { encoding: 'utf8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'] })
260
+ .trim()
261
+ .split(/\r?\n/)[0]
262
+ ?.trim();
263
+ if (resolved) {
264
+ await fs.writeFile(join(containerDir, '.aiw-bin-path'), resolved, 'utf8');
265
+ }
266
+ }
267
+ catch {
268
+ // Best-effort — aiw will still be found on PATH at runtime
269
+ }
270
+ }
@@ -12,15 +12,14 @@
12
12
  */
13
13
  export declare function getTemplatePath(templateName: string): Promise<string>;
14
14
  /**
15
- * Get list of available template names by scanning the templates directory.
15
+ * Get list of available method template names by scanning the templates directory.
16
16
  *
17
- * @returns Array of template names (e.g., ['bmad', 'gsr'])
17
+ * @returns Array of method template names (e.g., ['bmad', 'cc-native'])
18
18
  * @throws Error if templates directory cannot be read (indicates corrupted installation)
19
19
  */
20
+ export declare function getAvailableTemplates(): Promise<string[]>;
20
21
  /**
21
- * Get the absolute path to the _shared template directory.
22
- *
23
- * @returns Absolute path to the _shared template
22
+ * Discover IDE names available in a template path by scanning top-level dot-folders.
23
+ * Example: .claude, .codex -> ['claude', 'codex']
24
24
  */
25
- export declare function getSharedTemplatePath(): string;
26
- export declare function getAvailableTemplates(): Promise<string[]>;
25
+ export declare function getTemplateIdeNamesByPath(templatePath: string): Promise<string[]>;
@@ -1,6 +1,12 @@
1
1
  import { promises as fs } from 'node:fs';
2
2
  import { dirname, join } from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
+ function getTemplatesRootDir() {
5
+ const currentFileUrl = import.meta.url;
6
+ const currentFilePath = fileURLToPath(currentFileUrl);
7
+ const currentDir = dirname(currentFilePath);
8
+ return join(currentDir, '..', 'templates');
9
+ }
4
10
  /**
5
11
  * Resolve the absolute path to a bundled template root.
6
12
  * Works in both development (src/) and production (dist/) contexts.
@@ -21,13 +27,10 @@ export async function getTemplatePath(templateName) {
21
27
  // Get the directory of this file
22
28
  // In dev: .../aiwcli/src/lib/
23
29
  // In prod: .../aiwcli/dist/lib/
24
- const currentFileUrl = import.meta.url;
25
- const currentFilePath = fileURLToPath(currentFileUrl);
26
- const currentDir = dirname(currentFilePath);
27
30
  // Go up one level and into templates/<templateName>
28
31
  // src/lib/ → src/templates/<templateName>/
29
32
  // dist/lib/ → dist/templates/<templateName>/
30
- const templatePath = join(currentDir, '..', 'templates', templateName);
33
+ const templatePath = join(getTemplatesRootDir(), templateName);
31
34
  // Validate template exists
32
35
  try {
33
36
  await fs.access(templatePath);
@@ -38,29 +41,18 @@ export async function getTemplatePath(templateName) {
38
41
  return templatePath;
39
42
  }
40
43
  /**
41
- * Get list of available template names by scanning the templates directory.
44
+ * Get list of available method template names by scanning the templates directory.
42
45
  *
43
- * @returns Array of template names (e.g., ['bmad', 'gsr'])
46
+ * @returns Array of method template names (e.g., ['bmad', 'cc-native'])
44
47
  * @throws Error if templates directory cannot be read (indicates corrupted installation)
45
48
  */
46
- /**
47
- * Get the absolute path to the _shared template directory.
48
- *
49
- * @returns Absolute path to the _shared template
50
- */
51
- export function getSharedTemplatePath() {
52
- const currentFilePath = fileURLToPath(import.meta.url);
53
- const currentDir = dirname(currentFilePath);
54
- return join(currentDir, '..', 'templates', '_shared');
55
- }
56
49
  export async function getAvailableTemplates() {
57
- const currentFileUrl = import.meta.url;
58
- const currentFilePath = fileURLToPath(currentFileUrl);
59
- const currentDir = dirname(currentFilePath);
60
- const templatesDir = join(currentDir, '..', 'templates');
50
+ const templatesDir = getTemplatesRootDir();
61
51
  try {
62
52
  const entries = await fs.readdir(templatesDir, { withFileTypes: true });
63
- return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
53
+ return entries
54
+ .filter((entry) => entry.isDirectory() && !entry.name.startsWith('_') && !RESERVED_TEMPLATE_NAMES.has(entry.name))
55
+ .map((entry) => entry.name);
64
56
  }
65
57
  catch (error) {
66
58
  const err = error;
@@ -68,3 +60,16 @@ export async function getAvailableTemplates() {
68
60
  `This indicates a corrupted installation. Please reinstall aiwcli.`);
69
61
  }
70
62
  }
63
+ /**
64
+ * Discover IDE names available in a template path by scanning top-level dot-folders.
65
+ * Example: .claude, .codex -> ['claude', 'codex']
66
+ */
67
+ export async function getTemplateIdeNamesByPath(templatePath) {
68
+ const entries = await fs.readdir(templatePath, { withFileTypes: true });
69
+ return entries
70
+ .filter((entry) => entry.isDirectory() && entry.name.startsWith('.'))
71
+ .map((entry) => entry.name.slice(1))
72
+ .filter((name) => name.length > 0)
73
+ .sort((a, b) => a.localeCompare(b));
74
+ }
75
+ const RESERVED_TEMPLATE_NAMES = new Set(['core']);
@@ -13,13 +13,17 @@
13
13
  *
14
14
  * @module lib/template-settings-reconstructor
15
15
  */
16
+ import type { ClaudeSettings } from './claude-settings-types.js';
16
17
  /**
17
18
  * Reconstruct .claude/settings.json and .windsurf/hooks.json from the union
18
19
  * of all specified templates.
19
20
  *
21
+ * Note: Codex content is file-based today (`.codex/skills/*`) and does not
22
+ * have a merged settings artifact, so it is intentionally ignored here.
23
+ *
20
24
  * The function:
21
25
  * 1. Starts with empty settings
22
- * 2. Merges _shared template settings (when active templates exist)
26
+ * 2. Merges core template settings (when active templates exist)
23
27
  * 3. For each active template, merges its template-source settings
24
28
  * 4. Writes the result to the IDE settings file
25
29
  *
@@ -30,6 +34,7 @@
30
34
  *
31
35
  * @param targetDir - Project root directory
32
36
  * @param activeTemplates - Template names to include (e.g., ['cc-native', 'bmad'])
33
- * @param ides - IDEs to reconstruct for (e.g., ['claude', 'windsurf'])
37
+ * @param ides - IDEs to reconstruct for (currently claude/windsurf)
34
38
  */
35
39
  export declare function reconstructIdeSettings(targetDir: string, activeTemplates: string[], ides: string[]): Promise<void>;
40
+ export declare function normalizeTemplateSettingsPaths(settings: ClaudeSettings): ClaudeSettings;
@@ -14,19 +14,24 @@
14
14
  * @module lib/template-settings-reconstructor
15
15
  */
16
16
  import { join } from 'node:path';
17
+ import { getCoreClaudeSettingsBase, getCoreWindsurfHooksBase } from './core-ide-base.js';
17
18
  import { mergeClaudeSettings } from './hooks-merger.js';
18
19
  import { IdePathResolver } from './ide-path-resolver.js';
20
+ import { adaptHookCommand, validateCommandsForPlatform } from './platform-commands.js';
19
21
  import { readClaudeSettings, writeClaudeSettings } from './settings-hierarchy.js';
20
- import { getSharedTemplatePath, getTemplatePath } from './template-resolver.js';
22
+ import { getTemplatePath } from './template-resolver.js';
21
23
  import { getTargetHooksFile, readWindsurfHooks, writeWindsurfHooks } from './windsurf-hooks-hierarchy.js';
22
24
  import { mergeWindsurfHooks } from './windsurf-hooks-merger.js';
23
25
  /**
24
26
  * Reconstruct .claude/settings.json and .windsurf/hooks.json from the union
25
27
  * of all specified templates.
26
28
  *
29
+ * Note: Codex content is file-based today (`.codex/skills/*`) and does not
30
+ * have a merged settings artifact, so it is intentionally ignored here.
31
+ *
27
32
  * The function:
28
33
  * 1. Starts with empty settings
29
- * 2. Merges _shared template settings (when active templates exist)
34
+ * 2. Merges core template settings (when active templates exist)
30
35
  * 3. For each active template, merges its template-source settings
31
36
  * 4. Writes the result to the IDE settings file
32
37
  *
@@ -37,87 +42,113 @@ import { mergeWindsurfHooks } from './windsurf-hooks-merger.js';
37
42
  *
38
43
  * @param targetDir - Project root directory
39
44
  * @param activeTemplates - Template names to include (e.g., ['cc-native', 'bmad'])
40
- * @param ides - IDEs to reconstruct for (e.g., ['claude', 'windsurf'])
45
+ * @param ides - IDEs to reconstruct for (currently claude/windsurf)
41
46
  */
42
47
  export async function reconstructIdeSettings(targetDir, activeTemplates, ides) {
43
- const sharedTemplatePath = getSharedTemplatePath();
44
48
  if (ides.includes('claude')) {
45
- await reconstructClaudeSettings(targetDir, activeTemplates, sharedTemplatePath);
49
+ await reconstructClaudeSettings(targetDir, activeTemplates);
46
50
  }
47
51
  if (ides.includes('windsurf')) {
48
- await reconstructWindsurfHooks(targetDir, activeTemplates, sharedTemplatePath);
52
+ await reconstructWindsurfHooks(targetDir, activeTemplates);
49
53
  }
50
54
  }
51
55
  /**
52
56
  * Reconstruct .claude/settings.json from scratch using template sources.
53
57
  */
54
- async function reconstructClaudeSettings(targetDir, activeTemplates, sharedTemplatePath) {
58
+ async function reconstructClaudeSettings(targetDir, activeTemplates) {
55
59
  const resolver = new IdePathResolver(targetDir);
56
60
  const settingsPath = resolver.getClaudeSettings();
57
- // Read existing settings to preserve non-template fields (methods tracking, etc.)
58
- const existingSettings = await readClaudeSettings(settingsPath);
59
- // Preserve the methods tracking from existing settings
60
- const methodsTracking = existingSettings?.methods;
61
- // Start from empty and merge all template settings
62
- let reconstructed = {};
63
- // 1. Merge _shared template settings (only when active templates exist that need them)
64
- if (activeTemplates.length > 0) {
65
- const sharedSettingsPath = join(sharedTemplatePath, '.claude', 'settings.json');
66
- const sharedSettings = await readClaudeSettings(sharedSettingsPath);
67
- if (sharedSettings) {
68
- reconstructed = mergeClaudeSettings(reconstructed, sharedSettings);
69
- }
70
- }
71
- // 2. Merge each active template's settings (sequential for deterministic merge order)
61
+ // Start from core-owned base settings, then merge method templates.
62
+ let reconstructed = getCoreClaudeSettingsBase();
63
+ // Merge each active template's settings (sequential for deterministic merge order)
72
64
  for (const template of activeTemplates) {
65
+ let templateSettingsPath = `<unresolved:${template}>/.claude/settings.json`;
73
66
  try {
74
67
  const templatePath = await getTemplatePath(template); // eslint-disable-line no-await-in-loop
75
- const templateSettingsPath = join(templatePath, '.claude', 'settings.json');
68
+ templateSettingsPath = join(templatePath, '.claude', 'settings.json');
76
69
  const templateSettings = await readClaudeSettings(templateSettingsPath); // eslint-disable-line no-await-in-loop
77
70
  if (templateSettings) {
78
- reconstructed = mergeClaudeSettings(reconstructed, templateSettings);
71
+ reconstructed = mergeClaudeSettings(reconstructed, normalizeTemplateSettingsPaths(templateSettings));
79
72
  }
80
73
  }
81
- catch {
82
- // Template not found — skip
74
+ catch (error) {
75
+ reportTemplateMergeFailure('claude', template, templateSettingsPath, error);
83
76
  }
84
77
  }
85
- // 3. Restore methods tracking
86
- if (methodsTracking && Object.keys(methodsTracking).length > 0) {
87
- reconstructed.methods = methodsTracking;
88
- }
78
+ // 3. Platform-adapt hook commands (Windows cmd.exe compatibility)
79
+ reconstructed = adaptSettingsForPlatform(reconstructed);
89
80
  // 4. Write reconstructed settings
90
81
  await writeClaudeSettings(settingsPath, reconstructed);
91
82
  }
92
83
  /**
93
84
  * Reconstruct .windsurf/hooks.json from scratch using template sources.
94
85
  */
95
- async function reconstructWindsurfHooks(targetDir, activeTemplates, sharedTemplatePath) {
86
+ async function reconstructWindsurfHooks(targetDir, activeTemplates) {
96
87
  const hooksPath = getTargetHooksFile(targetDir);
97
- // Start from empty
98
- let reconstructed = { hooks: {} };
99
- // 1. Merge _shared template hooks (only when active templates exist that need them)
100
- if (activeTemplates.length > 0) {
101
- const sharedHooksPath = join(sharedTemplatePath, '.windsurf', 'hooks.json');
102
- const sharedHooks = await readWindsurfHooks(sharedHooksPath);
103
- if (sharedHooks) {
104
- reconstructed = mergeWindsurfHooks(reconstructed, sharedHooks);
105
- }
106
- }
107
- // 2. Merge each active template's hooks (sequential for deterministic merge order)
88
+ // Start from core-owned base hooks.
89
+ let reconstructed = getCoreWindsurfHooksBase();
90
+ // Merge each active template's hooks (sequential for deterministic merge order)
108
91
  for (const template of activeTemplates) {
92
+ let templateHooksPath = `<unresolved:${template}>/.windsurf/hooks.json`;
109
93
  try {
110
94
  const templatePath = await getTemplatePath(template); // eslint-disable-line no-await-in-loop
111
- const templateHooksPath = join(templatePath, '.windsurf', 'hooks.json');
95
+ templateHooksPath = join(templatePath, '.windsurf', 'hooks.json');
112
96
  const templateHooks = await readWindsurfHooks(templateHooksPath); // eslint-disable-line no-await-in-loop
113
97
  if (templateHooks) {
114
98
  reconstructed = mergeWindsurfHooks(reconstructed, templateHooks);
115
99
  }
116
100
  }
117
- catch {
118
- // Template not found — skip
101
+ catch (error) {
102
+ reportTemplateMergeFailure('windsurf', template, templateHooksPath, error);
119
103
  }
120
104
  }
121
105
  // 3. Write reconstructed hooks
122
106
  await writeWindsurfHooks(hooksPath, reconstructed);
123
107
  }
108
+ /**
109
+ * Adapt all command strings in settings for the current platform.
110
+ * On Windows: rewrites commands for cmd.exe compatibility.
111
+ * Validates adapted commands and fails fast if unknown remain non-portable.
112
+ */
113
+ function adaptSettingsForPlatform(settings) {
114
+ const result = { ...settings };
115
+ const allCommands = [];
116
+ // Adapt top-level command configs
117
+ if (result.statusLine && 'command' in result.statusLine) {
118
+ result.statusLine = { ...result.statusLine, command: adaptHookCommand(result.statusLine.command) };
119
+ allCommands.push(result.statusLine.command);
120
+ }
121
+ if (result.fileSuggestion && 'command' in result.fileSuggestion) {
122
+ result.fileSuggestion = { ...result.fileSuggestion, command: adaptHookCommand(result.fileSuggestion.command) };
123
+ allCommands.push(result.fileSuggestion.command);
124
+ }
125
+ // Adapt all hook commands
126
+ if (result.hooks) {
127
+ const adapted = {};
128
+ for (const [event, matchers] of Object.entries(result.hooks)) {
129
+ if (!matchers)
130
+ continue;
131
+ adapted[event] = matchers.map((matcher) => ({
132
+ ...matcher,
133
+ hooks: matcher.hooks.map((hook) => {
134
+ if (hook.type !== 'command')
135
+ return hook;
136
+ const adaptedCmd = adaptHookCommand(hook.command);
137
+ allCommands.push(adaptedCmd);
138
+ return { ...hook, command: adaptedCmd };
139
+ }),
140
+ }));
141
+ }
142
+ result.hooks = adapted;
143
+ }
144
+ // Validate: fail fast if unknown command still contains bash-only syntax on Windows
145
+ validateCommandsForPlatform(allCommands);
146
+ return result;
147
+ }
148
+ function reportTemplateMergeFailure(ide, template, settingsPath, error) {
149
+ const reason = error instanceof Error ? error.message : String(error);
150
+ process.stderr.write(`[warn] Failed to merge ${ide} template "${template}" from ${settingsPath}: ${reason}\n`);
151
+ }
152
+ export function normalizeTemplateSettingsPaths(settings) {
153
+ return structuredClone(settings);
154
+ }
@@ -0,0 +1,11 @@
1
+ export interface TerminalConfig {
2
+ cmd: string;
3
+ getArgs: (command: string) => string[];
4
+ }
5
+ export type WindowsShellPreference = 'default' | 'git-bash' | 'mintty';
6
+ export type WindowsTerminalStrategy = 'git-bash-in-wt' | 'mintty' | 'powershell-fallback' | 'windows-terminal';
7
+ export declare const LINUX_TERMINALS: TerminalConfig[];
8
+ export declare function resolveWindowsTerminalStrategy(preference: WindowsShellPreference, gitBashPath: null | string, minttyExists: boolean, powershellCmd: string): WindowsTerminalStrategy[];
9
+ export declare function detectPowerShell(isAvailable: (command: string) => boolean): string;
10
+ export declare function isWSL(env?: NodeJS.ProcessEnv): boolean;
11
+ export declare function findAvailableLinuxTerminal(isAvailable: (command: string, platform?: NodeJS.Platform) => boolean): null | TerminalConfig;
@@ -0,0 +1,49 @@
1
+ export const LINUX_TERMINALS = [
2
+ { cmd: 'gnome-terminal', getArgs: (command) => ['--', 'bash', '-c', `${command}; exec bash`] },
3
+ { cmd: 'konsole', getArgs: (command) => ['-e', `bash -c "${command}; exec bash"`] },
4
+ { cmd: 'xterm', getArgs: (command) => ['-e', `bash -c "${command}; exec bash"`] },
5
+ { cmd: 'x-terminal-emulator', getArgs: (command) => ['-e', `bash -c "${command}; exec bash"`] },
6
+ ];
7
+ export function resolveWindowsTerminalStrategy(preference, gitBashPath, minttyExists, powershellCmd) {
8
+ const strategies = [];
9
+ if (preference === 'mintty') {
10
+ if (minttyExists && gitBashPath) {
11
+ strategies.push('mintty');
12
+ }
13
+ if (gitBashPath) {
14
+ strategies.push('git-bash-in-wt');
15
+ }
16
+ else {
17
+ strategies.push('windows-terminal');
18
+ }
19
+ }
20
+ else if (preference === 'git-bash') {
21
+ if (gitBashPath) {
22
+ strategies.push('git-bash-in-wt');
23
+ }
24
+ else {
25
+ strategies.push('windows-terminal');
26
+ }
27
+ }
28
+ else {
29
+ strategies.push('windows-terminal');
30
+ }
31
+ if (powershellCmd) {
32
+ strategies.push('powershell-fallback');
33
+ }
34
+ return [...new Set(strategies)];
35
+ }
36
+ export function detectPowerShell(isAvailable) {
37
+ return isAvailable('pwsh') ? 'pwsh' : 'powershell';
38
+ }
39
+ export function isWSL(env = process.env) {
40
+ return Boolean(env['WSL_DISTRO_NAME']);
41
+ }
42
+ export function findAvailableLinuxTerminal(isAvailable) {
43
+ for (const terminal of LINUX_TERMINALS) {
44
+ if (isAvailable(terminal.cmd, 'linux')) {
45
+ return terminal;
46
+ }
47
+ }
48
+ return null;
49
+ }
@@ -27,6 +27,27 @@
27
27
  *
28
28
  * @module lib/terminal
29
29
  */
30
+ import { type WindowsShellPreference } from './terminal-strategy.js';
31
+ /** @internal */
32
+ export interface SpawnArgs {
33
+ args: string[];
34
+ command: string;
35
+ }
36
+ /** @internal */
37
+ export declare function resolveTerminalPlatform(platform: NodeJS.Platform, isWSLResult: boolean): 'darwin' | 'linux' | 'windows' | 'wsl';
38
+ /** @internal */
39
+ export declare function buildMacTerminalSpawnArgs(cwd: string, command: string): SpawnArgs;
40
+ /** @internal */
41
+ export declare function buildWindowsTerminalSpawnArgs(cwd: string, command: string, powershellCmd: string): SpawnArgs;
42
+ /** @internal */
43
+ export declare function buildPowerShellFallbackSpawnArgs(cwd: string, command: string, powershellCmd: string): SpawnArgs;
44
+ /** @internal */
45
+ export declare function buildLinuxTerminalSpawnArgs(cwd: string, command: string, terminalInfo: {
46
+ cmd: string;
47
+ getArgs: (cmd: string) => string[];
48
+ }): SpawnArgs;
49
+ /** @internal */
50
+ export declare function buildWSLTerminalSpawnArgs(cwd: string, command: string): SpawnArgs;
30
51
  /**
31
52
  * Options for launching a new terminal window.
32
53
  */
@@ -44,6 +65,13 @@ interface TerminalLaunchOptions {
44
65
  * If provided, debug messages will be passed to this function.
45
66
  */
46
67
  debugLog?: (message: string) => void;
68
+ /**
69
+ * Preferred shell when launching on Windows.
70
+ * - default: Existing behavior (PowerShell in wt or fallback)
71
+ * - mintty: Prefer mintty + Git Bash, fallback to git-bash in wt, then PowerShell
72
+ * - git-bash: Prefer Git Bash in wt, fallback to PowerShell if unavailable
73
+ */
74
+ windowsShellPreference?: WindowsShellPreference;
47
75
  }
48
76
  /**
49
77
  * Result of a terminal launch operation.