aiwcli 0.15.4 → 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,37 @@
1
+ /**
2
+ * Inference utility for AI-powered text processing.
3
+ * Unified interface for Claude API calls using the claude CLI.
4
+ * See SPEC.md §6
5
+ */
6
+ import type { InferenceResult } from "../types.js";
7
+ /**
8
+ * Run inference using the claude CLI.
9
+ * See SPEC.md §6.1
10
+ */
11
+ export declare function inference(systemPrompt: string, userPrompt: string, level?: string, timeout?: number, options?: {
12
+ model?: string;
13
+ }): InferenceResult;
14
+ /**
15
+ * Generate a keyword summary of a user prompt.
16
+ * Uses Sonnet (standard tier). Returns null if inference fails.
17
+ * See SPEC.md §6.2
18
+ */
19
+ export declare function generateSemanticSummary(prompt: string, timeout?: number): string | null;
20
+ /**
21
+ * Generate a 5-12 word context ID slug from a user prompt.
22
+ * Uses Codex Spark first, then falls back to current fast tier for resilience.
23
+ * See SPEC.md §6.3
24
+ */
25
+ export declare function generateContextIdSlug(prompt: string, timeout?: number): string | null;
26
+ /**
27
+ * Async version of inference() that does NOT block the event loop.
28
+ * Use for parallel AI calls (e.g., Stage 3 parallel summarizers).
29
+ * Uses execFileAsync and getInternalSubprocessEnv for proper subprocess isolation.
30
+ */
31
+ export declare function inferenceAsync(systemPrompt: string, userPrompt: string, level?: string, timeout?: number, options?: {
32
+ model?: string;
33
+ }): Promise<InferenceResult>;
34
+ export declare function codexInferAsync(prompt: string, model: string, options?: {
35
+ sandbox?: string;
36
+ timeout?: number;
37
+ }): Promise<InferenceResult>;
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Inference utility for AI-powered text processing.
3
+ * Unified interface for Claude API calls using the claude CLI.
4
+ * See SPEC.md §6
5
+ */
6
+ import { execFileSync } from "node:child_process";
7
+ import { logDebug, logWarn } from "./logger.js";
8
+ import { STOP_WORDS } from "./stop-words.js";
9
+ import { buildCliInvocation, inferenceSpec, isModelTier, resolveModel, getTierTimeout, TIER_TIMEOUTS, } from "./cli-args.js";
10
+ import { CODEX_MODELS } from "./models.js";
11
+ import { execFileAsync } from "./subprocess-utils.js";
12
+ const CONTEXT_ID_PRIMARY_MODEL = CODEX_MODELS.spark;
13
+ /**
14
+ * Run inference using the claude CLI.
15
+ * See SPEC.md §6.1
16
+ */
17
+ export function inference(systemPrompt, userPrompt, level = "fast", timeout, options) {
18
+ const startTime = Date.now();
19
+ const modelInput = options?.model ?? level;
20
+ const timeoutSec = timeout ?? (isModelTier(modelInput) ? getTierTimeout(modelInput) : TIER_TIMEOUTS.fast);
21
+ const fullPrompt = `${systemPrompt}\n\n${userPrompt}`;
22
+ const invocation = buildCliInvocation(inferenceSpec(modelInput));
23
+ const isWin = invocation.needsShell;
24
+ // Prompt arg needs Windows quoting when using shell mode
25
+ let promptArg = fullPrompt;
26
+ if (isWin) {
27
+ promptArg = '"' + fullPrompt.replaceAll(/\r?\n/g, " ").replaceAll('"', '""') + '"';
28
+ }
29
+ try {
30
+ const stdout = execFileSync(invocation.cliName, [...invocation.args, promptArg], {
31
+ timeout: timeoutSec * 1000,
32
+ env: invocation.env,
33
+ encoding: "utf8",
34
+ stdio: ["pipe", "pipe", "pipe"],
35
+ shell: isWin,
36
+ });
37
+ const latencyMs = Date.now() - startTime;
38
+ return {
39
+ success: true,
40
+ output: stdout.trim(),
41
+ latency_ms: latencyMs,
42
+ };
43
+ }
44
+ catch (error) {
45
+ const latencyMs = Date.now() - startTime;
46
+ const execError = error;
47
+ if (execError.code === "ETIMEDOUT" || execError.killed) {
48
+ return {
49
+ success: false,
50
+ output: "",
51
+ error: `Timeout after ${timeoutSec}s`,
52
+ latency_ms: latencyMs,
53
+ };
54
+ }
55
+ if (execError.code === "ENOENT") {
56
+ return {
57
+ success: false,
58
+ output: "",
59
+ error: "claude CLI not found",
60
+ latency_ms: latencyMs,
61
+ };
62
+ }
63
+ // Non-zero exit code
64
+ if (execError.status !== undefined && execError.status !== 0) {
65
+ return {
66
+ success: false,
67
+ output: String(execError.stdout ?? "").trim(),
68
+ error: String(execError.stderr ?? "").trim() || `Exit code: ${execError.status}`,
69
+ latency_ms: latencyMs,
70
+ };
71
+ }
72
+ return {
73
+ success: false,
74
+ output: "",
75
+ error: String(error),
76
+ latency_ms: latencyMs,
77
+ };
78
+ }
79
+ }
80
+ // §6.2 — System prompt for keyword extraction
81
+ const CONTEXT_ID_SYSTEM_PROMPT = `Extract 6-12 keywords from what the user wants to do.
82
+
83
+ Rules:
84
+ - Output 6-12 keywords only
85
+ - Keywords: nouns, verbs, adjectives, technical terms, proper names
86
+ - NO function words: the, to, with, for, in, a, an, of, on, is, it, and, or, that, this, be, as, at, by, from
87
+ - Most important/specific words preferred
88
+ - No punctuation, no quotes
89
+
90
+ Output ONLY the keywords separated by spaces, nothing else.`;
91
+ /**
92
+ * Generate a keyword summary of a user prompt.
93
+ * Uses Sonnet (standard tier). Returns null if inference fails.
94
+ * See SPEC.md §6.2
95
+ */
96
+ export function generateSemanticSummary(prompt, timeout = 15) {
97
+ const result = inference(CONTEXT_ID_SYSTEM_PROMPT, prompt, "standard", timeout);
98
+ if (!result.success || !result.output)
99
+ return null;
100
+ let summary = result.output.trim();
101
+ summary = summary.replaceAll(/^["']+|["']+$/g, "");
102
+ summary = summary.replace(/[.!?]+$/, "");
103
+ // Filter stop words
104
+ summary = filterStopWords(summary);
105
+ const words = summary.split(/\s+/);
106
+ if (words.length < 6 || words.length > 12)
107
+ return null;
108
+ return summary;
109
+ }
110
+ // §6.3 — System prompt for context ID slug generation
111
+ const CONTEXT_ID_SLUG_PROMPT = `You generate short title phrases for work sessions. These become folder names like \`260206-1959-fix-auth-middleware-redirect-loop-session-timeout\`.
112
+
113
+ Users scan 100+ such names to find past sessions. Your title must make THIS session instantly recognizable.
114
+
115
+ Rules:
116
+ - Exactly 8-12 lowercase words
117
+ - First word is an action verb (fix, add, implement, refactor, update, create, remove, optimize, debug, migrate, integrate, configure, deploy, scaffold, restructure)
118
+ - Coherent phrase, not disjointed keywords — reads like a short task description
119
+ - Prefer specific technical terms over generic words
120
+ - No articles (the, a, an), no pronouns, no filler words, no punctuation, no quotes
121
+ - Input may come from speech-to-text with filler words (uh, um, like, you know, basically, so) — ignore them entirely
122
+
123
+ Examples:
124
+
125
+ Input: "um so basically I need to like fix the auth bug in the login page"
126
+ {"slug": "fix authentication bug login page redirect session handling flow"}
127
+
128
+ Input: "hey uh can we add dark mode to the settings page"
129
+ {"slug": "add dark mode toggle settings page user preference storage"}
130
+
131
+ Input: "the context ids are bad can we change how we generate them towards a summary"
132
+ {"slug": "improve context id generation use prompt summary slugs"}
133
+
134
+ Input: "I want to refactor the database connection pooling for PostgreSQL"
135
+ {"slug": "refactor postgresql database connection pooling optimize query performance"}
136
+
137
+ Input: "so like you know the webhook retry logic is broken and stuff"
138
+ {"slug": "fix webhook retry logic broken error handling recovery mechanism"}
139
+
140
+ Input: "update the CI pipeline to cache node modules between runs"
141
+ {"slug": "update ci pipeline cache node modules between workflow runs"}
142
+
143
+ Respond with ONLY a JSON object: {"slug": "your 8-12 word phrase here"}`;
144
+ /**
145
+ * Generate a 5-12 word context ID slug from a user prompt.
146
+ * Uses Codex Spark first, then falls back to current fast tier for resilience.
147
+ * See SPEC.md §6.3
148
+ */
149
+ export function generateContextIdSlug(prompt, timeout = 3) {
150
+ const truncated = prompt.slice(0, 500);
151
+ const sparkResult = inference(CONTEXT_ID_SLUG_PROMPT, truncated, "fast", timeout, { model: CONTEXT_ID_PRIMARY_MODEL });
152
+ if (!sparkResult.success || !sparkResult.output) {
153
+ logWarn("inference", `Context ID slug Spark (${CONTEXT_ID_PRIMARY_MODEL}) failed or returned empty output. Falling back to ${resolveModel("fast")}`);
154
+ }
155
+ const result = sparkResult.success && sparkResult.output ? sparkResult : inference(CONTEXT_ID_SLUG_PROMPT, truncated, "fast", timeout);
156
+ if (!result.success || !result.output) {
157
+ logWarn("inference", `Context ID slug inference failed: ${result.error}`);
158
+ return null;
159
+ }
160
+ const raw = result.output.trim();
161
+ // Parse JSON response, fall back to raw text
162
+ let slug = null;
163
+ try {
164
+ const parsed = JSON.parse(raw);
165
+ if (parsed && typeof parsed === "object" && "slug" in parsed) {
166
+ slug = parsed.slug;
167
+ }
168
+ }
169
+ catch {
170
+ // Fall through to raw text
171
+ }
172
+ if (!slug)
173
+ slug = raw;
174
+ // Clean up
175
+ slug = slug.replaceAll(/^["'`]+|["'`]+$/g, "");
176
+ slug = slug.replace(/[.!?]+$/, "");
177
+ slug = slug.replaceAll('-', " ");
178
+ slug = slug.replaceAll(/[^a-zA-Z0-9 ]/g, "");
179
+ slug = slug.replaceAll(/\s+/g, " ").trim();
180
+ const words = slug.split(" ");
181
+ if (words.length > 12)
182
+ words.length = 12;
183
+ if (words.length < 5) {
184
+ logDebug("inference", `Context ID slug too short (${words.length} words): '${slug}'`);
185
+ return null;
186
+ }
187
+ const resultSlug = words.join(" ");
188
+ logDebug("inference", `Generated context ID slug: '${resultSlug}' (${result.latency_ms}ms)`);
189
+ return resultSlug;
190
+ }
191
+ /**
192
+ * Async version of inference() that does NOT block the event loop.
193
+ * Use for parallel AI calls (e.g., Stage 3 parallel summarizers).
194
+ * Uses execFileAsync and getInternalSubprocessEnv for proper subprocess isolation.
195
+ */
196
+ export async function inferenceAsync(systemPrompt, userPrompt, level = "fast", timeout, options) {
197
+ const startTime = Date.now();
198
+ const modelInput = options?.model ?? level;
199
+ const timeoutSec = timeout ?? (isModelTier(modelInput) ? getTierTimeout(modelInput) : TIER_TIMEOUTS.fast);
200
+ const timeoutMs = timeoutSec * 1000;
201
+ const fullPrompt = `${systemPrompt}\n\n${userPrompt}`;
202
+ const invocation = buildCliInvocation(inferenceSpec(modelInput));
203
+ const isWin = invocation.needsShell;
204
+ // Prompt arg needs Windows quoting when using shell mode
205
+ const promptArg = isWin
206
+ ? ('"' + fullPrompt.replaceAll(/\r?\n/g, " ").replaceAll('"', '""') + '"')
207
+ : fullPrompt;
208
+ const result = await execFileAsync(invocation.cliName, [...invocation.args, promptArg], { timeout: timeoutMs, env: invocation.env, shell: isWin });
209
+ const latencyMs = Date.now() - startTime;
210
+ if (result.killed) {
211
+ return { success: false, output: "", error: `Timeout after ${timeoutSec}s`, latency_ms: latencyMs };
212
+ }
213
+ if (result.exitCode !== 0) {
214
+ return {
215
+ success: false,
216
+ output: result.stdout.trim(),
217
+ error: result.stderr.trim() || `Exit code: ${result.exitCode}`,
218
+ latency_ms: latencyMs,
219
+ };
220
+ }
221
+ return { success: true, output: result.stdout.trim(), latency_ms: latencyMs };
222
+ }
223
+ export async function codexInferAsync(prompt, model, options) {
224
+ const startTime = Date.now();
225
+ const args = ["exec", "--model", model, "--json"];
226
+ if (options?.sandbox) {
227
+ args.push("--sandbox", options.sandbox);
228
+ }
229
+ const result = await execFileAsync("codex", args, {
230
+ env: process.env,
231
+ input: prompt,
232
+ timeout: (options?.timeout ?? 30) * 1000,
233
+ });
234
+ const latencyMs = Date.now() - startTime;
235
+ if (result.killed) {
236
+ return { success: false, output: "", error: `Timeout after ${options?.timeout ?? 30}s`, latency_ms: latencyMs };
237
+ }
238
+ if (result.exitCode !== 0) {
239
+ return {
240
+ success: false,
241
+ output: result.stdout.trim(),
242
+ error: result.stderr.trim() || `Exit code: ${result.exitCode}`,
243
+ latency_ms: latencyMs,
244
+ };
245
+ }
246
+ return {
247
+ success: true,
248
+ output: result.stdout.trim(),
249
+ latency_ms: latencyMs,
250
+ };
251
+ }
252
+ /**
253
+ * Filter stop words from text.
254
+ * See SPEC.md §6.4
255
+ */
256
+ function filterStopWords(text) {
257
+ return text
258
+ .toLowerCase()
259
+ .split(/\s+/)
260
+ .filter((w) => !STOP_WORDS.has(w) && w.length > 1)
261
+ .join(" ");
262
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Linter dispatch table and runner for PostToolUse lint-after-edit hook.
3
+ * Maps file extensions to linter configs, runs linters, parses output.
4
+ * See root CLAUDE.md for template sync targets.
5
+ */
6
+ export interface LinterConfig {
7
+ name: string;
8
+ extensions: string[];
9
+ source: "bundled" | "system";
10
+ binaryName: string;
11
+ buildArgs: (filePath: string) => string[];
12
+ parseOutput: (stdout: string, stderr: string, exitCode: number) => LintError[];
13
+ /** Exit codes that mean "lint errors found" (parse output). Other non-zero = crash (skip). */
14
+ lintExitCodes: number[];
15
+ }
16
+ export interface LintError {
17
+ line: number;
18
+ column?: number;
19
+ severity: "error" | "warning";
20
+ message: string;
21
+ rule?: string;
22
+ }
23
+ /**
24
+ * Look up the linter config for a file by extension.
25
+ * Returns null if no linter is configured for this file type.
26
+ */
27
+ export declare function getLinterForFile(filePath: string): LinterConfig | null;
28
+ /**
29
+ * Run a linter on a file.
30
+ * Returns null if the linter binary is not found.
31
+ * Returns { errors: [] } if the file passes lint.
32
+ */
33
+ export declare function runLinter(config: LinterConfig, filePath: string, projectRoot: string): {
34
+ errors: LintError[];
35
+ } | null;
36
+ /**
37
+ * Format lint errors for Claude's context injection.
38
+ * Returns a human-readable string suitable for emitContext().
39
+ */
40
+ export declare function formatLintErrors(filePath: string, linterName: string, errors: LintError[], maxShown?: number): string;
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Linter dispatch table and runner for PostToolUse lint-after-edit hook.
3
+ * Maps file extensions to linter configs, runs linters, parses output.
4
+ * See root CLAUDE.md for template sync targets.
5
+ */
6
+ import { spawnSync } from 'node:child_process';
7
+ import * as fs from "node:fs";
8
+ import path from "node:path";
9
+ import { logDebug, logWarn } from "./logger.js";
10
+ import { findExecutable } from "./subprocess-utils.js";
11
+ // ─── Output Parsers ─────────────────────────────────────────────────────────
12
+ function parseBiomeOutput(stdout, _stderr, _exitCode) {
13
+ try {
14
+ const data = JSON.parse(stdout);
15
+ const diagnostics = data.diagnostics ?? [];
16
+ return diagnostics.map((d) => ({
17
+ line: d.location?.span?.start?.line ?? d.location?.sourceCode?.lineIndex ?? 0,
18
+ column: d.location?.span?.start?.character ?? undefined,
19
+ severity: d.severity === "error" || d.severity === "fatal" ? "error" : "warning",
20
+ message: typeof d.description === "string" ? d.description : (d.message ?? "Unknown issue"),
21
+ ...(d.category ? { rule: d.category } : {}),
22
+ }));
23
+ }
24
+ catch {
25
+ return [];
26
+ }
27
+ }
28
+ function parseRuffOutput(stdout, _stderr, _exitCode) {
29
+ try {
30
+ const items = JSON.parse(stdout);
31
+ return items.map((item) => ({
32
+ line: item.location?.row ?? 0,
33
+ column: item.location?.column ?? undefined,
34
+ severity: "error",
35
+ message: item.message ?? "Unknown issue",
36
+ ...(item.code ? { rule: item.code } : {}),
37
+ }));
38
+ }
39
+ catch {
40
+ return [];
41
+ }
42
+ }
43
+ function parseShellcheckOutput(stdout, _stderr, _exitCode) {
44
+ try {
45
+ const data = JSON.parse(stdout);
46
+ const comments = data.comments ?? [];
47
+ return comments.map((c) => ({
48
+ line: c.line ?? 0,
49
+ column: c.column ?? undefined,
50
+ severity: c.level === "error" ? "error" : "warning",
51
+ message: c.message ?? "Unknown issue",
52
+ ...(c.code ? { rule: `SC${c.code}` } : {}),
53
+ }));
54
+ }
55
+ catch {
56
+ return [];
57
+ }
58
+ }
59
+ function parseRubocopOutput(stdout, _stderr, _exitCode) {
60
+ try {
61
+ const data = JSON.parse(stdout);
62
+ const offenses = data.files?.[0]?.offenses ?? [];
63
+ return offenses.map((o) => ({
64
+ line: o.location?.line ?? 0,
65
+ column: o.location?.column ?? undefined,
66
+ severity: o.severity === "error" || o.severity === "fatal" ? "error" : "warning",
67
+ message: o.message ?? "Unknown issue",
68
+ ...(o.cop_name ? { rule: o.cop_name } : {}),
69
+ }));
70
+ }
71
+ catch {
72
+ return [];
73
+ }
74
+ }
75
+ const CPPCHECK_RE = /^(.+):(\d+):(\d+): (\w+): (.+) \[(.+)\]$/;
76
+ function parseCppcheckOutput(_stdout, stderr, _exitCode) {
77
+ const errors = [];
78
+ for (const line of stderr.split("\n")) {
79
+ const m = CPPCHECK_RE.exec(line.trim());
80
+ if (m) {
81
+ errors.push({
82
+ line: parseInt(m[2], 10),
83
+ column: parseInt(m[3], 10),
84
+ severity: m[4] === "error" ? "error" : "warning",
85
+ message: m[5],
86
+ ...(m[6] ? { rule: m[6] } : {}),
87
+ });
88
+ }
89
+ }
90
+ return errors;
91
+ }
92
+ function parseEslintOutput(stdout, _stderr, _exitCode) {
93
+ try {
94
+ const files = JSON.parse(stdout);
95
+ const messages = files[0]?.messages ?? [];
96
+ return messages.map((m) => ({
97
+ line: m.line ?? 0,
98
+ column: m.column ?? undefined,
99
+ severity: m.severity === 2 ? "error" : "warning",
100
+ message: m.message ?? "Unknown issue",
101
+ ...(m.ruleId ? { rule: m.ruleId } : {}),
102
+ }));
103
+ }
104
+ catch {
105
+ return [];
106
+ }
107
+ }
108
+ const RUSTFMT_DIFF_RE = /^Diff in (.+) at line (\d+)/;
109
+ function parseRustfmtOutput(stdout, _stderr, _exitCode) {
110
+ const errors = [];
111
+ for (const line of stdout.split("\n")) {
112
+ const m = RUSTFMT_DIFF_RE.exec(line.trim());
113
+ if (m) {
114
+ errors.push({
115
+ line: parseInt(m[2], 10),
116
+ severity: "warning",
117
+ message: "Formatting differs from rustfmt style",
118
+ rule: "rustfmt",
119
+ });
120
+ }
121
+ }
122
+ return errors;
123
+ }
124
+ // ─── Dispatch Table ─────────────────────────────────────────────────────────
125
+ const LINTERS = [
126
+ {
127
+ name: "biome",
128
+ extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".json", ".jsonc", ".css"],
129
+ source: "bundled",
130
+ binaryName: "biome",
131
+ buildArgs: (filePath) => ["lint", "--reporter=json", "--max-diagnostics=20", filePath],
132
+ parseOutput: parseBiomeOutput,
133
+ lintExitCodes: [1],
134
+ },
135
+ {
136
+ name: "ruff",
137
+ extensions: [".py", ".pyi"],
138
+ source: "system",
139
+ binaryName: "ruff",
140
+ buildArgs: (filePath) => ["check", "--no-fix", "--output-format=json", filePath],
141
+ parseOutput: parseRuffOutput,
142
+ lintExitCodes: [1],
143
+ },
144
+ {
145
+ name: "shellcheck",
146
+ extensions: [".sh", ".bash"],
147
+ source: "system",
148
+ binaryName: "shellcheck",
149
+ buildArgs: (filePath) => ["-f", "json1", filePath],
150
+ parseOutput: parseShellcheckOutput,
151
+ lintExitCodes: [1],
152
+ },
153
+ {
154
+ name: "rubocop",
155
+ extensions: [".rb"],
156
+ source: "system",
157
+ binaryName: "rubocop",
158
+ buildArgs: (filePath) => ["--format", "json", "--no-autocorrect", filePath],
159
+ parseOutput: parseRubocopOutput,
160
+ lintExitCodes: [1, 2],
161
+ },
162
+ {
163
+ name: "cppcheck",
164
+ extensions: [".c", ".cpp", ".h", ".hpp"],
165
+ source: "system",
166
+ binaryName: "cppcheck",
167
+ buildArgs: (filePath) => ["--enable=warning,style", "--template=gcc", filePath],
168
+ parseOutput: parseCppcheckOutput,
169
+ lintExitCodes: [1],
170
+ },
171
+ {
172
+ name: "eslint",
173
+ extensions: [".svelte"],
174
+ source: "system",
175
+ binaryName: "eslint",
176
+ buildArgs: (filePath) => ["--format", "json", "--no-fix", filePath],
177
+ parseOutput: parseEslintOutput,
178
+ lintExitCodes: [1],
179
+ },
180
+ {
181
+ name: "rustfmt",
182
+ extensions: [".rs"],
183
+ source: "system",
184
+ binaryName: "rustfmt",
185
+ buildArgs: (filePath) => ["--check", filePath],
186
+ parseOutput: parseRustfmtOutput,
187
+ lintExitCodes: [1],
188
+ },
189
+ ];
190
+ /** Extension → LinterConfig lookup map (built once). */
191
+ const EXT_MAP = new Map();
192
+ for (const linter of LINTERS) {
193
+ for (const ext of linter.extensions) {
194
+ EXT_MAP.set(ext, linter);
195
+ }
196
+ }
197
+ // ─── Public API ─────────────────────────────────────────────────────────────
198
+ /**
199
+ * Look up the linter config for a file by extension.
200
+ * Returns null if no linter is configured for this file type.
201
+ */
202
+ export function getLinterForFile(filePath) {
203
+ const ext = path.extname(filePath).toLowerCase();
204
+ return EXT_MAP.get(ext) ?? null;
205
+ }
206
+ /**
207
+ * Resolve the binary path for a linter.
208
+ * Bundled linters: check project node_modules/.bin first, then PATH.
209
+ * System linters: check PATH only.
210
+ * Returns null if binary not found.
211
+ */
212
+ function resolveBinary(config, projectRoot) {
213
+ if (config.source === "bundled") {
214
+ // 1. Project-local node_modules
215
+ const localBin = path.join(projectRoot, "node_modules", ".bin", config.binaryName);
216
+ if (fs.existsSync(localBin))
217
+ return localBin;
218
+ // 2. PATH (covers global npm install of aiwcli)
219
+ return findExecutable(config.binaryName);
220
+ }
221
+ // System linters: PATH only
222
+ return findExecutable(config.binaryName);
223
+ }
224
+ /**
225
+ * Run a linter on a file.
226
+ * Returns null if the linter binary is not found.
227
+ * Returns { errors: [] } if the file passes lint.
228
+ */
229
+ export function runLinter(config, filePath, projectRoot) {
230
+ const binary = resolveBinary(config, projectRoot);
231
+ if (!binary) {
232
+ logDebug("lint-dispatch", `${config.name} binary not found, skipping`);
233
+ return null;
234
+ }
235
+ const args = config.buildArgs(filePath);
236
+ try {
237
+ const result = spawnSync(binary, args, {
238
+ cwd: projectRoot,
239
+ timeout: 8000, // 8s soft limit (10s hook timeout is the hard kill)
240
+ stdio: 'pipe',
241
+ encoding: 'utf8',
242
+ });
243
+ const exitCode = result.status ?? 1;
244
+ const stdout = result.stdout ?? "";
245
+ const stderr = result.stderr ?? "";
246
+ // Exit 0 = clean
247
+ if (exitCode === 0)
248
+ return { errors: [] };
249
+ // Known lint-error exit codes → parse output
250
+ if (config.lintExitCodes.includes(exitCode)) {
251
+ const errors = config.parseOutput(stdout, stderr, exitCode);
252
+ return { errors };
253
+ }
254
+ // Unknown exit code = crash/timeout → skip
255
+ logWarn("lint-dispatch", `${config.name} exited with unexpected code ${exitCode} on ${filePath}`);
256
+ return { errors: [] };
257
+ }
258
+ catch (error) {
259
+ logWarn("lint-dispatch", `${config.name} execution failed: ${error}`);
260
+ return { errors: [] };
261
+ }
262
+ }
263
+ /**
264
+ * Format lint errors for Claude's context injection.
265
+ * Returns a human-readable string suitable for emitContext().
266
+ */
267
+ export function formatLintErrors(filePath, linterName, errors, maxShown = 15) {
268
+ const shown = errors.slice(0, maxShown);
269
+ const lines = [
270
+ `Lint: ${errors.length} issue(s) in \`${filePath}\` (${linterName})`,
271
+ "",
272
+ ];
273
+ for (const err of shown) {
274
+ const loc = err.column ? `L${err.line}:${err.column}` : `L${err.line}`;
275
+ const sev = err.severity === "error" ? "error" : "warn";
276
+ const rule = err.rule ? ` [${err.rule}]` : "";
277
+ lines.push(`- **${sev}** ${loc}: ${err.message}${rule}`);
278
+ }
279
+ if (errors.length > maxShown) {
280
+ lines.push(`- ... and ${errors.length - maxShown} more`);
281
+ }
282
+ lines.push("");
283
+ lines.push("Fix these lint errors in the file you just edited.");
284
+ return lines.join("\n");
285
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Unified logging for all hooks and libraries.
3
+ *
4
+ * Log format: JSONL (one JSON object per line)
5
+ * Log location: _output/hook-log.jsonl (global, all sessions)
6
+ * Filter by session using the "sid" field.
7
+ *
8
+ * stderr is OPT-IN: convenience functions (logDebug, logInfo, logWarn, logError)
9
+ * write to file only by default. To also write to stderr (visible to Claude Code
10
+ * as "hook error"), pass { stderr: true } or use logBlocking().
11
+ * logHookError() always writes to stderr (unhandled errors must be visible).
12
+ *
13
+ * Environment variables:
14
+ * - HOOK_LOG_DISABLE=1: Disable all file logging
15
+ * - HOOK_LOG_LEVEL=warn: Minimum level to log (default: debug)
16
+ * - HOOK_ERROR_LOG_DISABLE=1: Legacy alias for HOOK_LOG_DISABLE
17
+ *
18
+ * Never throws. No buffering. Stdlib only.
19
+ * See SPEC.md §3
20
+ */
21
+ /**
22
+ * Set the session ID for this process. All subsequent log calls include it.
23
+ */
24
+ export declare function setSessionId(sessionId: string | null): void;
25
+ /**
26
+ * Set the context path for this process. Kept for external callers.
27
+ */
28
+ export declare function setContextPath(contextPath: string | null): void;
29
+ export declare function getContextPath(): string | null;
30
+ /**
31
+ * Write a structured log entry to the global hook log.
32
+ *
33
+ * All entries go to _output/hook-log.jsonl. Use the "sid" field
34
+ * (set via setSessionId) to filter by session.
35
+ */
36
+ export declare function hookLog(level: string, hookName: string, message: string, opts?: {
37
+ component?: string;
38
+ data?: unknown;
39
+ traceback_str?: string;
40
+ stderr?: boolean;
41
+ }): void;
42
+ export declare function logDebug(hookName: string, message: string, opts?: Record<string, unknown>): void;
43
+ export declare function logInfo(hookName: string, message: string, opts?: Record<string, unknown>): void;
44
+ export declare function logWarn(hookName: string, message: string, opts?: Record<string, unknown>): void;
45
+ export declare function logError(hookName: string, message: string, opts?: Record<string, unknown>): void;
46
+ /**
47
+ * Log an error that SHOULD be visible to user/model via stderr.
48
+ * Use for real problems needing attention, not routine diagnostics.
49
+ */
50
+ export declare function logBlocking(hookName: string, message: string, opts?: Record<string, unknown>): void;
51
+ /**
52
+ * Log a structured diagnostic entry at a hook decision point.
53
+ * See SPEC.md §3.8
54
+ */
55
+ export declare function logDiagnostic(hookName: string, phase: string, summary: string, opts?: {
56
+ inputs?: unknown;
57
+ decision?: unknown;
58
+ reasoning?: unknown;
59
+ component?: string;
60
+ data?: unknown;
61
+ }): void;
62
+ /**
63
+ * Backward-compatible wrapper matching old hook_utils.log_hook_error signature.
64
+ * See SPEC.md §3.6
65
+ */
66
+ export declare function logHookError(hookName: string, error: Error | string, hookEvent?: string, tracebackStr?: string): void;