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
@@ -0,0 +1,89 @@
1
+ import { execSync } from 'node:child_process'
2
+ import type { ExecSyncOptionsWithStringEncoding } from 'node:child_process'
3
+
4
+ import { commandLookupBinary, isWindowsPlatform } from './platform-adapter.js'
5
+
6
+ export type WindowsLookupProfile = 'cmdOrExeFirst' | 'exeThenExtensionlessThenCmd'
7
+
8
+ export function parseLookupLines(stdout: string): string[] {
9
+ return stdout
10
+ .trim()
11
+ .split(/\r?\n/)
12
+ .map((line) => line.trim())
13
+ .filter(Boolean)
14
+ }
15
+
16
+ export function pickWindowsPath(lines: string[], profile: WindowsLookupProfile): null | string {
17
+ if (lines.length === 0) return null
18
+
19
+ if (profile === 'cmdOrExeFirst') {
20
+ return lines.find((line) => /\.(cmd|exe)$/i.test(line)) ?? lines[0] ?? null
21
+ }
22
+
23
+ return lines.find((line) => /\.exe$/i.test(line))
24
+ ?? lines.find((line) => !/\.(cmd|ps1)$/i.test(line))
25
+ ?? lines.find((line) => /\.cmd$/i.test(line))
26
+ ?? lines[0]
27
+ ?? null
28
+ }
29
+
30
+ export function selectLookupPath(
31
+ lines: string[],
32
+ platform: NodeJS.Platform = process.platform,
33
+ windowsProfile: WindowsLookupProfile = 'cmdOrExeFirst',
34
+ ): null | string {
35
+ if (lines.length === 0) return null
36
+ if (!isWindowsPlatform(platform)) return lines[0] ?? null
37
+ return pickWindowsPath(lines, windowsProfile)
38
+ }
39
+
40
+ export function resolveExecutable(
41
+ name: string,
42
+ options?: {
43
+ platform?: NodeJS.Platform | undefined
44
+ timeoutMs?: number | undefined
45
+ windowsHide?: boolean | undefined
46
+ windowsProfile?: undefined | WindowsLookupProfile
47
+ },
48
+ ): null | string {
49
+ const platform = options?.platform ?? process.platform
50
+ const lines = lookupExecutables(name, {
51
+ platform,
52
+ timeoutMs: options?.timeoutMs,
53
+ windowsHide: options?.windowsHide,
54
+ })
55
+ return selectLookupPath(lines, platform, options?.windowsProfile ?? 'cmdOrExeFirst')
56
+ }
57
+
58
+ export function isCommandAvailable(
59
+ name: string,
60
+ platform: NodeJS.Platform = process.platform,
61
+ ): boolean {
62
+ return resolveExecutable(name, { platform }) !== null
63
+ }
64
+
65
+ export function lookupExecutables(
66
+ name: string,
67
+ options?: {
68
+ platform?: NodeJS.Platform | undefined
69
+ timeoutMs?: number | undefined
70
+ windowsHide?: boolean | undefined
71
+ },
72
+ ): string[] {
73
+ const platform = options?.platform ?? process.platform
74
+ const lookupBin = commandLookupBinary(platform)
75
+ const cmd = `${lookupBin} ${name}`
76
+
77
+ try {
78
+ return parseLookupLines(execSync(cmd, {
79
+ encoding: 'utf8',
80
+ stdio: ['pipe', 'pipe', 'pipe'],
81
+ shell: true,
82
+ timeout: options?.timeoutMs ?? 3000,
83
+ windowsHide: options?.windowsHide ?? true,
84
+ } as unknown as ExecSyncOptionsWithStringEncoding))
85
+ } catch {
86
+ return []
87
+ }
88
+ }
89
+
@@ -4,13 +4,13 @@ import { execFileSync } from "node:child_process";
4
4
  * Capture current git state for session snapshots.
5
5
  * All fields are optional — failures are silently ignored.
6
6
  */
7
- export function getGitState(projectRoot: string): Record<string, any> {
8
- const gitState: Record<string, any> = {};
7
+ export function getGitState(projectRoot: string): Record<string, unknown> {
8
+ const gitState: Record<string, unknown> = {};
9
9
  const isWin = process.platform === "win32";
10
10
  const opts = {
11
11
  cwd: projectRoot,
12
12
  timeout: 5000,
13
- encoding: "utf-8" as const,
13
+ encoding: "utf8" as const,
14
14
  stdio: ["pipe", "pipe", "pipe"] as ["pipe", "pipe", "pipe"],
15
15
  shell: isWin,
16
16
  };
@@ -45,7 +45,7 @@ export function getGitState(projectRoot: string): Record<string, any> {
45
45
  export function getGitStatusShort(projectRoot?: string): string {
46
46
  try {
47
47
  const result = execFileSync("git", ["status", "--short"], {
48
- encoding: "utf-8",
48
+ encoding: "utf8",
49
49
  timeout: 5000,
50
50
  stdio: ["pipe", "pipe", "pipe"],
51
51
  ...(projectRoot ? { cwd: projectRoot } : {}),
@@ -56,3 +56,5 @@ export function getGitStatusShort(projectRoot?: string): string {
56
56
  return "(git status unavailable)";
57
57
  }
58
58
  }
59
+
60
+
@@ -9,7 +9,6 @@ import { execFileSync } from "node:child_process";
9
9
  import { logDebug, logWarn } from "./logger.js";
10
10
  import { STOP_WORDS } from "./stop-words.js";
11
11
  import type { InferenceResult } from "../types.js";
12
- import { execFileAsync } from "./subprocess-utils.js";
13
12
  import {
14
13
  buildCliInvocation,
15
14
  inferenceSpec,
@@ -19,6 +18,7 @@ import {
19
18
  TIER_TIMEOUTS,
20
19
  } from "./cli-args.js";
21
20
  import { CODEX_MODELS } from "./models.js";
21
+ import { execFileAsync } from "./subprocess-utils.js";
22
22
 
23
23
  const CONTEXT_ID_PRIMARY_MODEL = CODEX_MODELS.spark;
24
24
 
@@ -35,7 +35,6 @@ export function inference(
35
35
  ): InferenceResult {
36
36
  const startTime = Date.now();
37
37
  const modelInput = options?.model ?? level;
38
- const model = resolveModel(modelInput);
39
38
  const timeoutSec = timeout ?? (isModelTier(modelInput) ? getTierTimeout(modelInput) : TIER_TIMEOUTS.fast);
40
39
  const fullPrompt = `${systemPrompt}\n\n${userPrompt}`;
41
40
 
@@ -55,7 +54,7 @@ export function inference(
55
54
  {
56
55
  timeout: timeoutSec * 1000,
57
56
  env: invocation.env,
58
- encoding: "utf-8",
57
+ encoding: "utf8",
59
58
  stdio: ["pipe", "pipe", "pipe"],
60
59
  shell: isWin,
61
60
  },
@@ -67,10 +66,17 @@ export function inference(
67
66
  output: stdout.trim(),
68
67
  latency_ms: latencyMs,
69
68
  };
70
- } catch (error: any) {
69
+ } catch (error: unknown) {
71
70
  const latencyMs = Date.now() - startTime;
71
+ const execError = error as {
72
+ code?: string;
73
+ killed?: boolean;
74
+ status?: number;
75
+ stderr?: unknown;
76
+ stdout?: unknown;
77
+ };
72
78
 
73
- if (error.code === "ETIMEDOUT" || error.killed) {
79
+ if (execError.code === "ETIMEDOUT" || execError.killed) {
74
80
  return {
75
81
  success: false,
76
82
  output: "",
@@ -79,7 +85,7 @@ export function inference(
79
85
  };
80
86
  }
81
87
 
82
- if (error.code === "ENOENT") {
88
+ if (execError.code === "ENOENT") {
83
89
  return {
84
90
  success: false,
85
91
  output: "",
@@ -89,11 +95,11 @@ export function inference(
89
95
  }
90
96
 
91
97
  // Non-zero exit code
92
- if (error.status !== undefined && error.status !== 0) {
98
+ if (execError.status !== undefined && execError.status !== 0) {
93
99
  return {
94
100
  success: false,
95
- output: (error.stdout ?? "").toString().trim(),
96
- error: (error.stderr ?? "").toString().trim() || `Exit code: ${error.status}`,
101
+ output: String(execError.stdout ?? "").trim(),
102
+ error: String(execError.stderr ?? "").trim() || `Exit code: ${execError.status}`,
97
103
  latency_ms: latencyMs,
98
104
  };
99
105
  }
@@ -182,7 +188,7 @@ Respond with ONLY a JSON object: {"slug": "your 8-12 word phrase here"}`;
182
188
 
183
189
  /**
184
190
  * Generate a 5-12 word context ID slug from a user prompt.
185
- * Uses 5.3 Codex Spark first, then falls back to current fast tier for resilience.
191
+ * Uses Codex Spark first, then falls back to current fast tier for resilience.
186
192
  * See SPEC.md §6.3
187
193
  */
188
194
  export function generateContextIdSlug(
@@ -294,6 +300,47 @@ export async function inferenceAsync(
294
300
  return { success: true, output: result.stdout.trim(), latency_ms: latencyMs };
295
301
  }
296
302
 
303
+ export async function codexInferAsync(
304
+ prompt: string,
305
+ model: string,
306
+ options?: { sandbox?: string; timeout?: number },
307
+ ): Promise<InferenceResult> {
308
+ const startTime = Date.now();
309
+ const args = ["exec", "--model", model, "--json"];
310
+ if (options?.sandbox) {
311
+ args.push("--sandbox", options.sandbox);
312
+ }
313
+
314
+ const result = await execFileAsync(
315
+ "codex",
316
+ args,
317
+ {
318
+ env: process.env,
319
+ input: prompt,
320
+ timeout: (options?.timeout ?? 30) * 1000,
321
+ },
322
+ );
323
+
324
+ const latencyMs = Date.now() - startTime;
325
+ if (result.killed) {
326
+ return { success: false, output: "", error: `Timeout after ${options?.timeout ?? 30}s`, latency_ms: latencyMs };
327
+ }
328
+ if (result.exitCode !== 0) {
329
+ return {
330
+ success: false,
331
+ output: result.stdout.trim(),
332
+ error: result.stderr.trim() || `Exit code: ${result.exitCode}`,
333
+ latency_ms: latencyMs,
334
+ };
335
+ }
336
+
337
+ return {
338
+ success: true,
339
+ output: result.stdout.trim(),
340
+ latency_ms: latencyMs,
341
+ };
342
+ }
343
+
297
344
  /**
298
345
  * Filter stop words from text.
299
346
  * See SPEC.md §6.4
@@ -305,3 +352,5 @@ function filterStopWords(text: string): string {
305
352
  .filter((w) => !STOP_WORDS.has(w) && w.length > 1)
306
353
  .join(" ");
307
354
  }
355
+
356
+
@@ -4,8 +4,9 @@
4
4
  * See root CLAUDE.md for template sync targets.
5
5
  */
6
6
 
7
+ import {spawnSync} from 'node:child_process'
7
8
  import * as fs from "node:fs";
8
- import * as path from "node:path";
9
+ import path from "node:path";
9
10
 
10
11
  import { logDebug, logWarn } from "./logger.js";
11
12
  import { findExecutable } from "./subprocess-utils.js";
@@ -35,14 +36,14 @@ export interface LintError {
35
36
 
36
37
  function parseBiomeOutput(stdout: string, _stderr: string, _exitCode: number): LintError[] {
37
38
  try {
38
- const data = JSON.parse(stdout);
39
- const diagnostics: any[] = data?.diagnostics ?? [];
39
+ const data = JSON.parse(stdout) as { diagnostics?: any[] };
40
+ const diagnostics = data.diagnostics ?? [];
40
41
  return diagnostics.map((d) => ({
41
42
  line: d.location?.span?.start?.line ?? d.location?.sourceCode?.lineIndex ?? 0,
42
43
  column: d.location?.span?.start?.character ?? undefined,
43
44
  severity: d.severity === "error" || d.severity === "fatal" ? "error" as const : "warning" as const,
44
45
  message: typeof d.description === "string" ? d.description : (d.message ?? "Unknown issue"),
45
- rule: d.category ?? undefined,
46
+ ...(d.category ? {rule: d.category} : {}),
46
47
  }));
47
48
  } catch {
48
49
  return [];
@@ -51,13 +52,13 @@ function parseBiomeOutput(stdout: string, _stderr: string, _exitCode: number): L
51
52
 
52
53
  function parseRuffOutput(stdout: string, _stderr: string, _exitCode: number): LintError[] {
53
54
  try {
54
- const items: any[] = JSON.parse(stdout);
55
+ const items = JSON.parse(stdout) as any[];
55
56
  return items.map((item) => ({
56
57
  line: item.location?.row ?? 0,
57
58
  column: item.location?.column ?? undefined,
58
59
  severity: "error" as const,
59
60
  message: item.message ?? "Unknown issue",
60
- rule: item.code ?? undefined,
61
+ ...(item.code ? {rule: item.code} : {}),
61
62
  }));
62
63
  } catch {
63
64
  return [];
@@ -66,14 +67,14 @@ function parseRuffOutput(stdout: string, _stderr: string, _exitCode: number): Li
66
67
 
67
68
  function parseShellcheckOutput(stdout: string, _stderr: string, _exitCode: number): LintError[] {
68
69
  try {
69
- const data = JSON.parse(stdout);
70
- const comments: any[] = data?.comments ?? [];
70
+ const data = JSON.parse(stdout) as { comments?: any[] };
71
+ const comments = data.comments ?? [];
71
72
  return comments.map((c) => ({
72
73
  line: c.line ?? 0,
73
74
  column: c.column ?? undefined,
74
75
  severity: c.level === "error" ? "error" as const : "warning" as const,
75
76
  message: c.message ?? "Unknown issue",
76
- rule: c.code ? `SC${c.code}` : undefined,
77
+ ...(c.code ? {rule: `SC${c.code}`} : {}),
77
78
  }));
78
79
  } catch {
79
80
  return [];
@@ -82,14 +83,14 @@ function parseShellcheckOutput(stdout: string, _stderr: string, _exitCode: numbe
82
83
 
83
84
  function parseRubocopOutput(stdout: string, _stderr: string, _exitCode: number): LintError[] {
84
85
  try {
85
- const data = JSON.parse(stdout);
86
- const offenses: any[] = data?.files?.[0]?.offenses ?? [];
86
+ const data = JSON.parse(stdout) as { files?: Array<{ offenses?: any[] }> };
87
+ const offenses = data.files?.[0]?.offenses ?? [];
87
88
  return offenses.map((o) => ({
88
89
  line: o.location?.line ?? 0,
89
90
  column: o.location?.column ?? undefined,
90
91
  severity: o.severity === "error" || o.severity === "fatal" ? "error" as const : "warning" as const,
91
92
  message: o.message ?? "Unknown issue",
92
- rule: o.cop_name ?? undefined,
93
+ ...(o.cop_name ? {rule: o.cop_name} : {}),
93
94
  }));
94
95
  } catch {
95
96
  return [];
@@ -108,7 +109,7 @@ function parseCppcheckOutput(_stdout: string, stderr: string, _exitCode: number)
108
109
  column: parseInt(m[3]!, 10),
109
110
  severity: m[4] === "error" ? "error" : "warning",
110
111
  message: m[5]!,
111
- rule: m[6],
112
+ ...(m[6] ? {rule: m[6]} : {}),
112
113
  });
113
114
  }
114
115
  }
@@ -117,14 +118,14 @@ function parseCppcheckOutput(_stdout: string, stderr: string, _exitCode: number)
117
118
 
118
119
  function parseEslintOutput(stdout: string, _stderr: string, _exitCode: number): LintError[] {
119
120
  try {
120
- const files: any[] = JSON.parse(stdout);
121
- const messages: any[] = files?.[0]?.messages ?? [];
121
+ const files = JSON.parse(stdout) as Array<{ messages?: any[] }>;
122
+ const messages = files[0]?.messages ?? [];
122
123
  return messages.map((m) => ({
123
124
  line: m.line ?? 0,
124
125
  column: m.column ?? undefined,
125
126
  severity: m.severity === 2 ? "error" as const : "warning" as const,
126
127
  message: m.message ?? "Unknown issue",
127
- rule: m.ruleId ?? undefined,
128
+ ...(m.ruleId ? {rule: m.ruleId} : {}),
128
129
  }));
129
130
  } catch {
130
131
  return [];
@@ -275,17 +276,16 @@ export function runLinter(
275
276
  const args = config.buildArgs(filePath);
276
277
 
277
278
  try {
278
- // eslint-disable-next-line no-undef -- Bun runtime global
279
- const result = (Bun as any).spawnSync([binary, ...args], {
279
+ const result = spawnSync(binary, args, {
280
280
  cwd: projectRoot,
281
281
  timeout: 8000, // 8s soft limit (10s hook timeout is the hard kill)
282
- stdout: "pipe",
283
- stderr: "pipe",
282
+ stdio: 'pipe',
283
+ encoding: 'utf8',
284
284
  });
285
285
 
286
- const {exitCode} = result;
287
- const stdout = result.stdout?.toString() ?? "";
288
- const stderr = result.stderr?.toString() ?? "";
286
+ const exitCode = result.status ?? 1;
287
+ const stdout = result.stdout ?? "";
288
+ const stderr = result.stderr ?? "";
289
289
 
290
290
  // Exit 0 = clean
291
291
  if (exitCode === 0) return { errors: [] };
@@ -337,3 +337,5 @@ export function formatLintErrors(
337
337
 
338
338
  return lines.join("\n");
339
339
  }
340
+
341
+
@@ -20,7 +20,7 @@
20
20
  */
21
21
 
22
22
  import * as fs from "node:fs";
23
- import * as path from "node:path";
23
+ import path from "node:path";
24
24
 
25
25
  const LEVELS: Record<string, number> = {
26
26
  debug: 0,
@@ -29,7 +29,8 @@ const LEVELS: Record<string, number> = {
29
29
  error: 3,
30
30
  };
31
31
 
32
- const MAX_LOG_LINES = 10_000; // Max lines in global log before pruning
32
+ const MAX_LOG_BYTES = 2_000_000; // 2MB threshold before pruning
33
+ let _prunedThisProcess = false;
33
34
 
34
35
  // Module-level session ID cache
35
36
  let _cachedSessionId: string | null = null;
@@ -89,7 +90,7 @@ export function hookLog(
89
90
  message: string,
90
91
  opts?: {
91
92
  component?: string;
92
- data?: any;
93
+ data?: unknown;
93
94
  traceback_str?: string;
94
95
  stderr?: boolean;
95
96
  },
@@ -121,7 +122,7 @@ export function hookLog(
121
122
  // Build JSONL entry
122
123
  const now = new Date();
123
124
  const ts = now.toISOString().replace("Z", "").slice(0, 23);
124
- const entry: Record<string, any> = {
125
+ const entry: Record<string, unknown> = {
125
126
  ts,
126
127
  level: levelLower,
127
128
  hook: hookName,
@@ -148,42 +149,41 @@ export function hookLog(
148
149
  const dir = path.dirname(logPath);
149
150
  fs.mkdirSync(dir, { recursive: true });
150
151
 
151
- // Line-count guard: prune to last MAX_LOG_LINES
152
- try {
153
- if (fs.existsSync(logPath)) {
154
- const content = fs.readFileSync(logPath, "utf-8");
155
- const lines = content.split(/\r?\n/);
156
- if (lines.length > MAX_LOG_LINES) {
157
- fs.writeFileSync(
158
- logPath,
159
- lines.slice(lines.length - MAX_LOG_LINES).join("\n"),
160
- "utf-8",
161
- );
152
+ // Size-based prune: runs at most once per bun process
153
+ if (!_prunedThisProcess) {
154
+ _prunedThisProcess = true;
155
+ try {
156
+ const stat = fs.statSync(logPath);
157
+ if (stat.size > MAX_LOG_BYTES) {
158
+ const content = fs.readFileSync(logPath, "utf8");
159
+ const pruneTarget = Math.floor(content.length * 0.1);
160
+ const keepFrom = content.indexOf("\n", pruneTarget);
161
+ if (keepFrom > 0) {
162
+ fs.writeFileSync(logPath, content.slice(keepFrom + 1), "utf8");
163
+ }
162
164
  }
163
- }
164
- } catch {
165
- // ignore
165
+ } catch { /* file doesn't exist yet — fine */ }
166
166
  }
167
167
 
168
- fs.appendFileSync(logPath, line, "utf-8");
168
+ fs.appendFileSync(logPath, line, "utf8");
169
169
  } catch {
170
170
  // Never crash
171
171
  }
172
172
  }
173
173
 
174
- export function logDebug(hookName: string, message: string, opts?: Record<string, any>): void {
174
+ export function logDebug(hookName: string, message: string, opts?: Record<string, unknown>): void {
175
175
  hookLog("debug", hookName, message, opts);
176
176
  }
177
177
 
178
- export function logInfo(hookName: string, message: string, opts?: Record<string, any>): void {
178
+ export function logInfo(hookName: string, message: string, opts?: Record<string, unknown>): void {
179
179
  hookLog("info", hookName, message, opts);
180
180
  }
181
181
 
182
- export function logWarn(hookName: string, message: string, opts?: Record<string, any>): void {
182
+ export function logWarn(hookName: string, message: string, opts?: Record<string, unknown>): void {
183
183
  hookLog("warn", hookName, message, opts);
184
184
  }
185
185
 
186
- export function logError(hookName: string, message: string, opts?: Record<string, any>): void {
186
+ export function logError(hookName: string, message: string, opts?: Record<string, unknown>): void {
187
187
  hookLog("error", hookName, message, opts);
188
188
  }
189
189
 
@@ -191,7 +191,7 @@ export function logError(hookName: string, message: string, opts?: Record<string
191
191
  * Log an error that SHOULD be visible to user/model via stderr.
192
192
  * Use for real problems needing attention, not routine diagnostics.
193
193
  */
194
- export function logBlocking(hookName: string, message: string, opts?: Record<string, any>): void {
194
+ export function logBlocking(hookName: string, message: string, opts?: Record<string, unknown>): void {
195
195
  hookLog("error", hookName, message, { ...opts, stderr: true });
196
196
  }
197
197
 
@@ -204,14 +204,14 @@ export function logDiagnostic(
204
204
  phase: string,
205
205
  summary: string,
206
206
  opts?: {
207
- inputs?: any;
208
- decision?: any;
209
- reasoning?: any;
207
+ inputs?: unknown;
208
+ decision?: unknown;
209
+ reasoning?: unknown;
210
210
  component?: string;
211
- data?: any;
211
+ data?: unknown;
212
212
  },
213
213
  ): void {
214
- const diagData: Record<string, any> = { phase };
214
+ const diagData: Record<string, unknown> = { phase };
215
215
  if (opts?.inputs !== undefined) diagData.inputs = opts.inputs;
216
216
  if (opts?.decision !== undefined) diagData.decision = opts.decision;
217
217
  if (opts?.reasoning !== undefined) diagData.reasoning = opts.reasoning;
@@ -245,3 +245,6 @@ export function logHookError(
245
245
  stderr: true,
246
246
  });
247
247
  }
248
+
249
+
250
+
@@ -11,6 +11,6 @@ export const CLAUDE_MODELS = {
11
11
 
12
12
  export const CODEX_MODELS = {
13
13
  spark: "gpt-5.3-codex-spark",
14
- codex: "gpt-5.3-codex",
15
- gpt: "gpt-5.2",
14
+ codex: "gpt-5.4",
15
+ gpt: "gpt-5.4",
16
16
  } as const;
@@ -0,0 +1,33 @@
1
+ export type TmuxColorMode = 'c256' | 'truecolor'
2
+
3
+ export function isWindowsPlatform(platform: NodeJS.Platform = process.platform): boolean {
4
+ return platform === 'win32'
5
+ }
6
+
7
+ export function isNonWindowsPlatform(platform: NodeJS.Platform = process.platform): boolean {
8
+ return !isWindowsPlatform(platform)
9
+ }
10
+
11
+ export function commandLookupBinary(platform: NodeJS.Platform = process.platform): 'where.exe' | 'which' {
12
+ return isWindowsPlatform(platform) ? 'where.exe' : 'which'
13
+ }
14
+
15
+ export function shouldUseShell(platform: NodeJS.Platform = process.platform): boolean {
16
+ return isWindowsPlatform(platform)
17
+ }
18
+
19
+ export function resolveTmuxColorModeForPlatform(
20
+ _platform?: NodeJS.Platform,
21
+ ): TmuxColorMode {
22
+ // Always truecolor — Windows now uses psmux (native ConPTY) which supports truecolor natively.
23
+ // The c256 degradation was only needed for tmux-via-MSYS2-bash.
24
+ return 'truecolor'
25
+ }
26
+
27
+ export function applyTmuxLaunchEnv(
28
+ envVars: Record<string, string>,
29
+ _platform?: NodeJS.Platform,
30
+ ): Record<string, string> {
31
+ // Always inject truecolor — psmux on Windows and tmux on Unix both support it.
32
+ return { COLORTERM: 'truecolor', ...envVars }
33
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Shared preflight health check for provider+model availability.
3
- * Extracted from plan-review/lib/preflight.ts for reuse by any hook.
3
+ * Extracted from plan-review/lib/preflight.ts for reuse by unknown hook.
4
4
  *
5
5
  * Validates that a CLI tool + model combo works by running a minimal "ping" request.
6
6
  */
@@ -89,10 +89,11 @@ export async function checkProviderModel(
89
89
 
90
90
  logDebug(hook, `${provider}:${model} passed (${latencyMs}ms)`);
91
91
  return { provider, model, available: true, latencyMs };
92
- } catch (err) {
92
+ } catch (error_) {
93
93
  const latencyMs = Date.now() - start;
94
- const error = err instanceof Error ? err.message : String(err);
94
+ const error = error_ instanceof Error ? error_.message : String(error_);
95
95
  logWarn(hook, `${provider}:${model} exception: ${error}`);
96
96
  return { provider, model, available: false, latencyMs, error };
97
97
  }
98
98
  }
99
+
@@ -0,0 +1,91 @@
1
+ import * as fs from 'node:fs'
2
+ import * as os from 'node:os'
3
+ import path from 'node:path'
4
+
5
+ export interface SentinelIpcPaths {
6
+ tmpDir: string
7
+ inputPath: string
8
+ stdoutPath: string
9
+ stderrPath: string
10
+ sentinelPath: string
11
+ }
12
+
13
+ function sanitizePrefix(prefix: string): string {
14
+ return prefix.replaceAll(/[^a-zA-Z0-9_-]/g, '-')
15
+ }
16
+
17
+ export function createSentinelIpcPaths(prefix: string): SentinelIpcPaths {
18
+ const safePrefix = sanitizePrefix(prefix)
19
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), `${safePrefix}-`))
20
+
21
+ return {
22
+ tmpDir,
23
+ inputPath: path.join(tmpDir, 'input.txt'),
24
+ stdoutPath: path.join(tmpDir, 'stdout.txt'),
25
+ stderrPath: path.join(tmpDir, 'stderr.txt'),
26
+ sentinelPath: path.join(tmpDir, 'sentinel.txt'),
27
+ }
28
+ }
29
+
30
+ export function buildShellCaptureScript(
31
+ command: string,
32
+ paths: Pick<SentinelIpcPaths, 'inputPath' | 'stdoutPath' | 'stderrPath' | 'sentinelPath'>,
33
+ quote: (input: string) => string,
34
+ ): string {
35
+ return [
36
+ command,
37
+ `< ${quote(paths.inputPath)}`,
38
+ `> ${quote(paths.stdoutPath)}`,
39
+ `2> ${quote(paths.stderrPath)}`,
40
+ `; echo $? > ${quote(paths.sentinelPath)}`,
41
+ ].join(' ')
42
+ }
43
+
44
+ export async function waitForSentinelFile(
45
+ sentinelPath: string,
46
+ timeoutMs: number,
47
+ pollIntervalMs = 250,
48
+ ): Promise<boolean> {
49
+ const deadline = Date.now() + timeoutMs
50
+ while (Date.now() < deadline) {
51
+ if (fs.existsSync(sentinelPath)) return true
52
+ await new Promise<void>((resolve) => {
53
+ setTimeout(resolve, pollIntervalMs)
54
+ })
55
+ }
56
+
57
+ return fs.existsSync(sentinelPath)
58
+ }
59
+
60
+ export function readSentinelExitCode(sentinelPath: string, fallback = 1): number {
61
+ if (!fs.existsSync(sentinelPath)) return fallback
62
+
63
+ const raw = fs.readFileSync(sentinelPath, 'utf8').trim()
64
+ const parsed = Number.parseInt(raw, 10)
65
+ return Number.isFinite(parsed) ? parsed : fallback
66
+ }
67
+
68
+ export function readTextIfExists(filePath: string): string {
69
+ if (!filePath || !fs.existsSync(filePath)) return ''
70
+ return fs.readFileSync(filePath, 'utf8')
71
+ }
72
+
73
+ export function cleanupSentinelIpc(paths: Pick<SentinelIpcPaths, 'tmpDir'>): void {
74
+ try {
75
+ fs.rmSync(paths.tmpDir, { recursive: true, force: true })
76
+ } catch {
77
+ // Best-effort cleanup.
78
+ }
79
+ }
80
+
81
+ export function cleanupSentinelPath(sentinelPath: string | undefined): void {
82
+ if (!sentinelPath) return
83
+
84
+ try {
85
+ fs.rmSync(path.dirname(sentinelPath), { recursive: true, force: true })
86
+ } catch {
87
+ // Best-effort cleanup.
88
+ }
89
+ }
90
+
91
+