@nathapp/nax 0.18.1

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 (459) hide show
  1. package/.gitlab-ci.yml +96 -0
  2. package/BRIEF.md +140 -0
  3. package/CHANGELOG.md +60 -0
  4. package/CLAUDE.md +159 -0
  5. package/README.md +373 -0
  6. package/US-007-IMPLEMENTATION.md +139 -0
  7. package/bin/nax.ts +930 -0
  8. package/biome.json +14 -0
  9. package/bun.lock +168 -0
  10. package/bunfig.toml +11 -0
  11. package/docs/20260216-fix-plan-context-review.md +56 -0
  12. package/docs/20260216-relentless-vs-ngent-comparison.md +208 -0
  13. package/docs/20260216-v02-plan.md +136 -0
  14. package/docs/20260216-v02-review.md +685 -0
  15. package/docs/20260217-dogfood-findings.md +56 -0
  16. package/docs/20260217-p2-plus-plan.md +117 -0
  17. package/docs/20260217-partial-fixes-plan.md +62 -0
  18. package/docs/20260217-plan-analyze-spec.md +117 -0
  19. package/docs/20260217-post-impl-review.md +1137 -0
  20. package/docs/20260217-quick-wins-plan.md +66 -0
  21. package/docs/20260217-split-runner-plan.md +75 -0
  22. package/docs/20260217-v03-impl-plan.md +80 -0
  23. package/docs/20260217-v03-post-impl-review.md +589 -0
  24. package/docs/20260217-v04-impl-plan.md +86 -0
  25. package/docs/20260217-v05-post-impl-review.md +850 -0
  26. package/docs/20260217-v06-post-impl-review.md +817 -0
  27. package/docs/20260218-adr003-port-plan.md +151 -0
  28. package/docs/20260218-review-adr003-verification.md +175 -0
  29. package/docs/20260219-fix-plan-bug16-19.md +79 -0
  30. package/docs/20260219-fix-plan-bug20-22.md +114 -0
  31. package/docs/20260219-plan-llm-routing.md +116 -0
  32. package/docs/20260219-review-bug20-22-fixes.md +135 -0
  33. package/docs/20260219-routing-baseline-keyword.md +63 -0
  34. package/docs/20260220-plan-structured-logging-p1.md +80 -0
  35. package/docs/20260220-plan-structured-logging-p2.md +37 -0
  36. package/docs/20260220-review-llm-routing.md +180 -0
  37. package/docs/20260220-review-post-fix-llm-routing.md +70 -0
  38. package/docs/20260221-fix-plan-relevantfiles-split.md +101 -0
  39. package/docs/20260221-fix-plan-routing-mode.md +125 -0
  40. package/docs/20260221-review-v0.9-implementation.md +379 -0
  41. package/docs/20260222-fix-plan-v091-routing-isolation.md +197 -0
  42. package/docs/20260223-fix-plan-prompt-audit.md +62 -0
  43. package/docs/20260224-nax-roadmap-phases.md +189 -0
  44. package/docs/20260225-phase2-llm-service-layer.md +401 -0
  45. package/docs/20260225-review-v0.10.1.md +187 -0
  46. package/docs/20260303-v010-implementation-plan.md +165 -0
  47. package/docs/CLAUDE.md.bak +191 -0
  48. package/docs/ROADMAP.md +165 -0
  49. package/docs/SPEC-rectification.md +0 -0
  50. package/docs/SPEC.md +324 -0
  51. package/docs/US-001-plugin-loading-verification.md +152 -0
  52. package/docs/architecture-analysis.md +1076 -0
  53. package/docs/bugs/BUG-21-escalation-null-attempts.md +48 -0
  54. package/docs/bugs-from-dogfood-run-c.md +243 -0
  55. package/docs/code-review-20260228.md +612 -0
  56. package/docs/code-review-v0.15.0.md +629 -0
  57. package/docs/hook-lifecycle-test-plan.md +149 -0
  58. package/docs/releases/v0.11.0-and-earlier.md +20 -0
  59. package/docs/releases/v0.12.0.md +15 -0
  60. package/docs/releases/v0.13.0.md +14 -0
  61. package/docs/releases/v0.14.0.md +20 -0
  62. package/docs/releases/v0.14.1.md +36 -0
  63. package/docs/releases/v0.14.2.md +51 -0
  64. package/docs/releases/v0.14.3.md +174 -0
  65. package/docs/releases/v0.14.4.md +94 -0
  66. package/docs/releases/v0.15.0.md +502 -0
  67. package/docs/releases/v0.15.1.md +170 -0
  68. package/docs/releases/v0.15.3.md +193 -0
  69. package/docs/specs/status-file-v0.10.1.md +812 -0
  70. package/docs/v0.10-global-config.md +206 -0
  71. package/docs/v0.10-plugin-system.md +415 -0
  72. package/docs/v0.10-prompt-optimizer.md +234 -0
  73. package/docs/v0.3-spec.md +244 -0
  74. package/docs/v0.4-spec.md +140 -0
  75. package/docs/v0.5-spec.md +237 -0
  76. package/docs/v0.6-spec.md +371 -0
  77. package/docs/v0.7-spec.md +177 -0
  78. package/docs/v0.8-llm-routing.md +206 -0
  79. package/docs/v0.8-structured-logging.md +132 -0
  80. package/docs/v0.9.3-prompt-audit.md +112 -0
  81. package/examples/plugins/console-reporter/index.test.ts +207 -0
  82. package/examples/plugins/console-reporter/index.ts +110 -0
  83. package/nax/config.json +147 -0
  84. package/nax/features/bugfix-v0171/prd.json +52 -0
  85. package/nax/features/config-management/prd.json +108 -0
  86. package/nax/features/config-management/progress.txt +5 -0
  87. package/nax/features/diagnose/acceptance.test.ts +412 -0
  88. package/nax/features/diagnose/prd.json +41 -0
  89. package/nax/features/orchestration-fixes/prd.json +89 -0
  90. package/nax/features/orchestration-fixes/progress.txt +1 -0
  91. package/nax/features/plugin-integration/US-007-VERIFICATION.md +259 -0
  92. package/nax/features/plugin-integration/prd.json +208 -0
  93. package/nax/features/plugin-integration/progress.txt +5 -0
  94. package/nax/features/precheck/prd.json +205 -0
  95. package/nax/features/precheck/progress.txt +15 -0
  96. package/nax/features/structured-logging/prd.json +199 -0
  97. package/nax/features/unlock/prd.json +36 -0
  98. package/package.json +47 -0
  99. package/src/acceptance/fix-generator.ts +348 -0
  100. package/src/acceptance/generator.ts +282 -0
  101. package/src/acceptance/index.ts +30 -0
  102. package/src/acceptance/types.ts +79 -0
  103. package/src/agents/claude-decompose.ts +169 -0
  104. package/src/agents/claude-plan.ts +139 -0
  105. package/src/agents/claude.ts +324 -0
  106. package/src/agents/cost.ts +268 -0
  107. package/src/agents/index.ts +13 -0
  108. package/src/agents/registry.ts +48 -0
  109. package/src/agents/types-extended.ts +133 -0
  110. package/src/agents/types.ts +113 -0
  111. package/src/agents/validation.ts +69 -0
  112. package/src/analyze/classifier.ts +305 -0
  113. package/src/analyze/index.ts +16 -0
  114. package/src/analyze/scanner.ts +175 -0
  115. package/src/analyze/types.ts +51 -0
  116. package/src/cli/accept.ts +108 -0
  117. package/src/cli/analyze-parser.ts +284 -0
  118. package/src/cli/analyze.ts +207 -0
  119. package/src/cli/config.ts +561 -0
  120. package/src/cli/constitution.ts +109 -0
  121. package/src/cli/diagnose-analysis.ts +159 -0
  122. package/src/cli/diagnose-formatter.ts +87 -0
  123. package/src/cli/diagnose.ts +203 -0
  124. package/src/cli/generate.ts +127 -0
  125. package/src/cli/index.ts +37 -0
  126. package/src/cli/init.ts +188 -0
  127. package/src/cli/interact.ts +295 -0
  128. package/src/cli/plan.ts +198 -0
  129. package/src/cli/plugins.ts +111 -0
  130. package/src/cli/prompts.ts +295 -0
  131. package/src/cli/runs.ts +174 -0
  132. package/src/cli/status-cost.ts +151 -0
  133. package/src/cli/status-features.ts +338 -0
  134. package/src/cli/status.ts +13 -0
  135. package/src/commands/common.ts +171 -0
  136. package/src/commands/diagnose.ts +17 -0
  137. package/src/commands/index.ts +8 -0
  138. package/src/commands/logs.ts +384 -0
  139. package/src/commands/precheck.ts +86 -0
  140. package/src/commands/unlock.ts +96 -0
  141. package/src/config/defaults.ts +160 -0
  142. package/src/config/index.ts +22 -0
  143. package/src/config/loader.ts +121 -0
  144. package/src/config/merger.ts +147 -0
  145. package/src/config/path-security.ts +121 -0
  146. package/src/config/paths.ts +27 -0
  147. package/src/config/schema.ts +56 -0
  148. package/src/config/schemas.ts +286 -0
  149. package/src/config/types.ts +423 -0
  150. package/src/config/validate.ts +103 -0
  151. package/src/constitution/generator.ts +191 -0
  152. package/src/constitution/generators/aider.ts +41 -0
  153. package/src/constitution/generators/claude.ts +35 -0
  154. package/src/constitution/generators/cursor.ts +36 -0
  155. package/src/constitution/generators/opencode.ts +38 -0
  156. package/src/constitution/generators/types.ts +33 -0
  157. package/src/constitution/generators/windsurf.ts +36 -0
  158. package/src/constitution/index.ts +10 -0
  159. package/src/constitution/loader.ts +133 -0
  160. package/src/constitution/types.ts +31 -0
  161. package/src/context/auto-detect.ts +227 -0
  162. package/src/context/builder.ts +246 -0
  163. package/src/context/elements.ts +83 -0
  164. package/src/context/formatter.ts +107 -0
  165. package/src/context/generator.ts +129 -0
  166. package/src/context/generators/aider.ts +34 -0
  167. package/src/context/generators/claude.ts +28 -0
  168. package/src/context/generators/cursor.ts +28 -0
  169. package/src/context/generators/opencode.ts +30 -0
  170. package/src/context/generators/windsurf.ts +28 -0
  171. package/src/context/greenfield.ts +114 -0
  172. package/src/context/index.ts +33 -0
  173. package/src/context/injector.ts +279 -0
  174. package/src/context/test-scanner.ts +370 -0
  175. package/src/context/types.ts +98 -0
  176. package/src/errors.ts +67 -0
  177. package/src/execution/batching.ts +157 -0
  178. package/src/execution/crash-recovery.ts +373 -0
  179. package/src/execution/escalation/escalation.ts +44 -0
  180. package/src/execution/escalation/index.ts +13 -0
  181. package/src/execution/escalation/tier-escalation.ts +295 -0
  182. package/src/execution/escalation/tier-outcome.ts +158 -0
  183. package/src/execution/helpers.ts +38 -0
  184. package/src/execution/index.ts +45 -0
  185. package/src/execution/lifecycle/acceptance-loop.ts +272 -0
  186. package/src/execution/lifecycle/headless-formatter.ts +85 -0
  187. package/src/execution/lifecycle/index.ts +12 -0
  188. package/src/execution/lifecycle/parallel-lifecycle.ts +101 -0
  189. package/src/execution/lifecycle/precheck-runner.ts +140 -0
  190. package/src/execution/lifecycle/run-cleanup.ts +81 -0
  191. package/src/execution/lifecycle/run-completion.ts +129 -0
  192. package/src/execution/lifecycle/run-initialization.ts +141 -0
  193. package/src/execution/lifecycle/run-lifecycle.ts +312 -0
  194. package/src/execution/lifecycle/run-setup.ts +204 -0
  195. package/src/execution/lifecycle/story-hooks.ts +38 -0
  196. package/src/execution/lifecycle/story-size-prompts.ts +123 -0
  197. package/src/execution/lock.ts +115 -0
  198. package/src/execution/parallel-executor.ts +216 -0
  199. package/src/execution/parallel.ts +400 -0
  200. package/src/execution/pid-registry.ts +280 -0
  201. package/src/execution/pipeline-result-handler.ts +388 -0
  202. package/src/execution/post-verify-rectification.ts +188 -0
  203. package/src/execution/post-verify.ts +274 -0
  204. package/src/execution/progress.ts +25 -0
  205. package/src/execution/prompts.ts +127 -0
  206. package/src/execution/queue-handler.ts +109 -0
  207. package/src/execution/rectification.ts +13 -0
  208. package/src/execution/runner.ts +377 -0
  209. package/src/execution/sequential-executor.ts +388 -0
  210. package/src/execution/status-file.ts +264 -0
  211. package/src/execution/status-writer.ts +139 -0
  212. package/src/execution/story-context.ts +229 -0
  213. package/src/execution/test-output-parser.ts +14 -0
  214. package/src/execution/verification.ts +72 -0
  215. package/src/hooks/index.ts +2 -0
  216. package/src/hooks/runner.ts +286 -0
  217. package/src/hooks/types.ts +67 -0
  218. package/src/interaction/chain.ts +154 -0
  219. package/src/interaction/index.ts +60 -0
  220. package/src/interaction/init.ts +83 -0
  221. package/src/interaction/plugins/auto.ts +217 -0
  222. package/src/interaction/plugins/cli.ts +300 -0
  223. package/src/interaction/plugins/telegram.ts +384 -0
  224. package/src/interaction/plugins/webhook.ts +258 -0
  225. package/src/interaction/state.ts +171 -0
  226. package/src/interaction/triggers.ts +229 -0
  227. package/src/interaction/types.ts +163 -0
  228. package/src/logger/formatters.ts +84 -0
  229. package/src/logger/index.ts +16 -0
  230. package/src/logger/logger.ts +298 -0
  231. package/src/logger/types.ts +48 -0
  232. package/src/logging/formatter.ts +355 -0
  233. package/src/logging/index.ts +22 -0
  234. package/src/logging/types.ts +93 -0
  235. package/src/metrics/aggregator.ts +190 -0
  236. package/src/metrics/index.ts +14 -0
  237. package/src/metrics/tracker.ts +200 -0
  238. package/src/metrics/types.ts +109 -0
  239. package/src/optimizer/index.ts +62 -0
  240. package/src/optimizer/noop.optimizer.ts +24 -0
  241. package/src/optimizer/rule-based.optimizer.ts +248 -0
  242. package/src/optimizer/types.ts +53 -0
  243. package/src/pipeline/events.ts +130 -0
  244. package/src/pipeline/index.ts +19 -0
  245. package/src/pipeline/runner.ts +161 -0
  246. package/src/pipeline/stages/acceptance.ts +197 -0
  247. package/src/pipeline/stages/completion.ts +99 -0
  248. package/src/pipeline/stages/constitution.ts +63 -0
  249. package/src/pipeline/stages/context.ts +117 -0
  250. package/src/pipeline/stages/execution.ts +194 -0
  251. package/src/pipeline/stages/index.ts +62 -0
  252. package/src/pipeline/stages/optimizer.ts +74 -0
  253. package/src/pipeline/stages/prompt.ts +57 -0
  254. package/src/pipeline/stages/queue-check.ts +103 -0
  255. package/src/pipeline/stages/review.ts +181 -0
  256. package/src/pipeline/stages/routing.ts +81 -0
  257. package/src/pipeline/stages/verify.ts +100 -0
  258. package/src/pipeline/types.ts +167 -0
  259. package/src/plugins/index.ts +31 -0
  260. package/src/plugins/loader.ts +287 -0
  261. package/src/plugins/registry.ts +168 -0
  262. package/src/plugins/types.ts +327 -0
  263. package/src/plugins/validator.ts +352 -0
  264. package/src/prd/index.ts +172 -0
  265. package/src/prd/types.ts +202 -0
  266. package/src/precheck/checks-blockers.ts +391 -0
  267. package/src/precheck/checks-warnings.ts +142 -0
  268. package/src/precheck/checks.ts +30 -0
  269. package/src/precheck/index.ts +247 -0
  270. package/src/precheck/story-size-gate.ts +144 -0
  271. package/src/precheck/types.ts +31 -0
  272. package/src/queue/index.ts +2 -0
  273. package/src/queue/manager.ts +254 -0
  274. package/src/queue/types.ts +54 -0
  275. package/src/review/index.ts +8 -0
  276. package/src/review/runner.ts +172 -0
  277. package/src/review/types.ts +66 -0
  278. package/src/routing/builder.ts +81 -0
  279. package/src/routing/chain.ts +74 -0
  280. package/src/routing/index.ts +16 -0
  281. package/src/routing/loader.ts +58 -0
  282. package/src/routing/router.ts +303 -0
  283. package/src/routing/strategies/adaptive.ts +215 -0
  284. package/src/routing/strategies/index.ts +8 -0
  285. package/src/routing/strategies/keyword.ts +163 -0
  286. package/src/routing/strategies/llm-prompts.ts +209 -0
  287. package/src/routing/strategies/llm.ts +235 -0
  288. package/src/routing/strategies/manual.ts +50 -0
  289. package/src/routing/strategy.ts +99 -0
  290. package/src/tdd/cleanup.ts +111 -0
  291. package/src/tdd/index.ts +23 -0
  292. package/src/tdd/isolation.ts +123 -0
  293. package/src/tdd/orchestrator.ts +383 -0
  294. package/src/tdd/prompts.ts +270 -0
  295. package/src/tdd/rectification-gate.ts +183 -0
  296. package/src/tdd/session-runner.ts +179 -0
  297. package/src/tdd/types.ts +81 -0
  298. package/src/tdd/verdict.ts +271 -0
  299. package/src/tui/App.tsx +265 -0
  300. package/src/tui/components/AgentPanel.tsx +75 -0
  301. package/src/tui/components/CostOverlay.tsx +118 -0
  302. package/src/tui/components/HelpOverlay.tsx +107 -0
  303. package/src/tui/components/StatusBar.tsx +63 -0
  304. package/src/tui/components/StoriesPanel.tsx +177 -0
  305. package/src/tui/hooks/useKeyboard.ts +142 -0
  306. package/src/tui/hooks/useLayout.ts +137 -0
  307. package/src/tui/hooks/usePipelineEvents.ts +183 -0
  308. package/src/tui/hooks/usePty.ts +194 -0
  309. package/src/tui/index.tsx +38 -0
  310. package/src/tui/types.ts +76 -0
  311. package/src/utils/git.ts +83 -0
  312. package/src/utils/queue-writer.ts +54 -0
  313. package/src/verification/executor.ts +235 -0
  314. package/src/verification/gate.ts +207 -0
  315. package/src/verification/index.ts +12 -0
  316. package/src/verification/parser.ts +230 -0
  317. package/src/verification/rectification.ts +108 -0
  318. package/src/verification/types.ts +113 -0
  319. package/src/worktree/dispatcher.ts +65 -0
  320. package/src/worktree/index.ts +2 -0
  321. package/src/worktree/manager.ts +187 -0
  322. package/src/worktree/merge.ts +301 -0
  323. package/src/worktree/types.ts +4 -0
  324. package/test/TEST_COVERAGE_US001.md +217 -0
  325. package/test/TEST_COVERAGE_US003.md +84 -0
  326. package/test/TEST_COVERAGE_US005.md +86 -0
  327. package/test/US-002-orchestrator.test.ts +246 -0
  328. package/test/acceptance/cm-003-default-view.test.ts +194 -0
  329. package/test/execution/pid-registry.test.ts +240 -0
  330. package/test/execution/post-verify.test.ts +224 -0
  331. package/test/helpers/timeout.ts +42 -0
  332. package/test/integration/US-002-TEST-SUMMARY.md +107 -0
  333. package/test/integration/US-003-TEST-SUMMARY.md +149 -0
  334. package/test/integration/US-004-TEST-SUMMARY.md +106 -0
  335. package/test/integration/US-005-TEST-SUMMARY.md +138 -0
  336. package/test/integration/US-007-TEST-SUMMARY.md +100 -0
  337. package/test/integration/agent-validation.test.ts +439 -0
  338. package/test/integration/analyze-integration.test.ts +261 -0
  339. package/test/integration/analyze-scanner.test.ts +131 -0
  340. package/test/integration/cli-config-default-edge-cases.test.ts +222 -0
  341. package/test/integration/cli-config-default-view.test.ts +229 -0
  342. package/test/integration/cli-config-diff.test.ts +460 -0
  343. package/test/integration/cli-config.test.ts +736 -0
  344. package/test/integration/cli-diagnose.test.ts +592 -0
  345. package/test/integration/cli-logs.test.ts +314 -0
  346. package/test/integration/cli-plugins.test.ts +678 -0
  347. package/test/integration/cli-precheck.test.ts +371 -0
  348. package/test/integration/cli-run-headless.test.ts +173 -0
  349. package/test/integration/cli.test.ts +75 -0
  350. package/test/integration/config/merger.test.ts +465 -0
  351. package/test/integration/config/paths.test.ts +51 -0
  352. package/test/integration/config-loader.test.ts +265 -0
  353. package/test/integration/config.test.ts +444 -0
  354. package/test/integration/context-integration.test.ts +702 -0
  355. package/test/integration/context-provider-injection.test.ts +506 -0
  356. package/test/integration/context-verification-integration.test.ts +295 -0
  357. package/test/integration/e2e.test.ts +896 -0
  358. package/test/integration/execution.test.ts +625 -0
  359. package/test/integration/helpers.test.ts +295 -0
  360. package/test/integration/hooks.test.ts +361 -0
  361. package/test/integration/interaction-chain-pipeline.test.ts +464 -0
  362. package/test/integration/isolation.test.ts +143 -0
  363. package/test/integration/logger.test.ts +461 -0
  364. package/test/integration/parallel.test.ts +250 -0
  365. package/test/integration/path-security.test.ts +173 -0
  366. package/test/integration/pipeline-acceptance.test.ts +302 -0
  367. package/test/integration/pipeline-events.test.ts +475 -0
  368. package/test/integration/pipeline.test.ts +658 -0
  369. package/test/integration/plan.test.ts +157 -0
  370. package/test/integration/plugin-routing.test.ts +921 -0
  371. package/test/integration/plugins/config-integration.test.ts +172 -0
  372. package/test/integration/plugins/config-resolution.test.ts +522 -0
  373. package/test/integration/plugins/loader.test.ts +641 -0
  374. package/test/integration/plugins/registry.test.ts +746 -0
  375. package/test/integration/plugins/validator.test.ts +563 -0
  376. package/test/integration/prd-pause.test.ts +205 -0
  377. package/test/integration/prd-resolvers.test.ts +185 -0
  378. package/test/integration/precheck-integration.test.ts +468 -0
  379. package/test/integration/precheck.test.ts +805 -0
  380. package/test/integration/progress.test.ts +34 -0
  381. package/test/integration/rectification-flow.test.ts +512 -0
  382. package/test/integration/reporter-lifecycle.test.ts +860 -0
  383. package/test/integration/review-config-commands.test.ts +319 -0
  384. package/test/integration/review-config-schema.test.ts +116 -0
  385. package/test/integration/review-plugin-integration.test.ts +722 -0
  386. package/test/integration/review.test.ts +149 -0
  387. package/test/integration/routing-stage-bug-021.test.ts +274 -0
  388. package/test/integration/routing-stage-greenfield.test.ts +286 -0
  389. package/test/integration/runner-config-plugins.test.ts +461 -0
  390. package/test/integration/runner-fixes.test.ts +399 -0
  391. package/test/integration/runner-plugin-integration.test.ts +543 -0
  392. package/test/integration/runner.test.ts +1679 -0
  393. package/test/integration/s5-greenfield-fallback.test.ts +297 -0
  394. package/test/integration/status-file-integration.test.ts +325 -0
  395. package/test/integration/status-file.test.ts +379 -0
  396. package/test/integration/status-writer.test.ts +345 -0
  397. package/test/integration/story-id-in-events.test.ts +273 -0
  398. package/test/integration/tdd-cleanup.test.ts +246 -0
  399. package/test/integration/tdd-orchestrator.test.ts +1762 -0
  400. package/test/integration/test-scanner.test.ts +403 -0
  401. package/test/integration/verification-asset-check.test.ts +142 -0
  402. package/test/integration/verify-stage.test.ts +275 -0
  403. package/test/integration/worktree/manager.test.ts +218 -0
  404. package/test/integration/worktree/merge.test.ts +341 -0
  405. package/test/manual/logging-formatter-demo.ts +158 -0
  406. package/test/ui/tui-agent-panel.test.tsx +99 -0
  407. package/test/ui/tui-controls.test.ts +334 -0
  408. package/test/ui/tui-cost-and-pty.test.ts +189 -0
  409. package/test/ui/tui-layout.test.ts +378 -0
  410. package/test/ui/tui-pty-integration.test.tsx +159 -0
  411. package/test/ui/tui-stories.test.ts +332 -0
  412. package/test/unit/acceptance.test.ts +186 -0
  413. package/test/unit/agent-stderr-capture.test.ts +146 -0
  414. package/test/unit/analyze-classifier.test.ts +215 -0
  415. package/test/unit/analyze.test.ts +224 -0
  416. package/test/unit/auto-detect.test.ts +249 -0
  417. package/test/unit/cli-status.test.ts +417 -0
  418. package/test/unit/commands/common.test.ts +320 -0
  419. package/test/unit/commands/logs.test.ts +416 -0
  420. package/test/unit/commands/unlock.test.ts +319 -0
  421. package/test/unit/constitution-generators.test.ts +160 -0
  422. package/test/unit/constitution.test.ts +209 -0
  423. package/test/unit/context.test.ts +1722 -0
  424. package/test/unit/cost.test.ts +231 -0
  425. package/test/unit/crash-recovery.test.ts +308 -0
  426. package/test/unit/escalation.test.ts +126 -0
  427. package/test/unit/execution-logging-stderr.test.ts +156 -0
  428. package/test/unit/execution-stage.test.ts +122 -0
  429. package/test/unit/fix-generator.test.ts +275 -0
  430. package/test/unit/formatters.test.ts +469 -0
  431. package/test/unit/greenfield.test.ts +179 -0
  432. package/test/unit/helpers.test.ts +317 -0
  433. package/test/unit/interaction/human-review-trigger.test.ts +164 -0
  434. package/test/unit/interaction-network-failures.test.ts +389 -0
  435. package/test/unit/interaction-plugins.test.ts +164 -0
  436. package/test/unit/isolation.test.ts +134 -0
  437. package/test/unit/logging/formatter.test.ts +455 -0
  438. package/test/unit/merge.test.ts +268 -0
  439. package/test/unit/metrics.test.ts +276 -0
  440. package/test/unit/optimizer/noop.optimizer.test.ts +125 -0
  441. package/test/unit/optimizer/rule-based.optimizer.test.ts +358 -0
  442. package/test/unit/prd-auto-default.test.ts +290 -0
  443. package/test/unit/prd-failure-category.test.ts +176 -0
  444. package/test/unit/prd-get-next-story.test.ts +186 -0
  445. package/test/unit/precheck-checks.test.ts +840 -0
  446. package/test/unit/precheck-story-size-gate.test.ts +287 -0
  447. package/test/unit/precheck-types.test.ts +142 -0
  448. package/test/unit/prompts.test.ts +475 -0
  449. package/test/unit/queue.test.ts +237 -0
  450. package/test/unit/rectification.test.ts +284 -0
  451. package/test/unit/registry.test.ts +287 -0
  452. package/test/unit/routing.test.ts +937 -0
  453. package/test/unit/run-lifecycle.test.ts +140 -0
  454. package/test/unit/storyid-events.test.ts +224 -0
  455. package/test/unit/tdd-verdict.test.ts +492 -0
  456. package/test/unit/test-output-parser.test.ts +377 -0
  457. package/test/unit/verdict.test.ts +324 -0
  458. package/test/unit/worktree-manager.test.ts +158 -0
  459. package/tsconfig.json +27 -0
@@ -0,0 +1,286 @@
1
+ /**
2
+ * Hook Runner
3
+ *
4
+ * Loads hooks.json and executes hooks at lifecycle events.
5
+ */
6
+
7
+ import { existsSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ import { getLogger } from "../logger";
10
+ import type { HookContext, HookDef, HookEvent, HooksConfig } from "./types";
11
+
12
+ const DEFAULT_TIMEOUT = 5000;
13
+
14
+ /** Extended hooks config that tracks global vs project hooks */
15
+ export interface LoadedHooksConfig extends HooksConfig {
16
+ /** Global hooks (loaded from ~/.nax/hooks.json) */
17
+ _global?: HooksConfig;
18
+ /** Whether global hooks were skipped */
19
+ _skipGlobal?: boolean;
20
+ }
21
+
22
+ /**
23
+ * Load hooks config from global and project paths.
24
+ *
25
+ * Both global and project hooks are preserved independently (not merged).
26
+ * The skipGlobal flag in project config disables global hook loading.
27
+ *
28
+ * @param projectDir - Project nax directory path
29
+ * @param globalDir - Global nax directory path (optional)
30
+ * @returns Merged hooks config with both global and project hooks
31
+ */
32
+ export async function loadHooksConfig(projectDir: string, globalDir?: string): Promise<LoadedHooksConfig> {
33
+ let globalHooks: HooksConfig = { hooks: {} };
34
+ let projectHooks: HooksConfig = { hooks: {} };
35
+ let skipGlobal = false;
36
+
37
+ // Load project hooks first to check skipGlobal flag
38
+ const projectPath = join(projectDir, "hooks.json");
39
+ if (existsSync(projectPath)) {
40
+ try {
41
+ const projectData = await Bun.file(projectPath).json();
42
+ projectHooks = projectData as HooksConfig;
43
+ // Check if project config has skipGlobal flag
44
+ skipGlobal = (projectData as { skipGlobal?: boolean }).skipGlobal ?? false;
45
+ } catch (err) {
46
+ const logger = getLogger();
47
+ logger.warn("hooks", "Failed to parse project hooks.json", { path: projectPath, error: String(err) });
48
+ }
49
+ }
50
+
51
+ // Load global hooks only if not skipped
52
+ if (!skipGlobal && globalDir) {
53
+ const globalPath = join(globalDir, "hooks.json");
54
+ if (existsSync(globalPath)) {
55
+ try {
56
+ const globalData = await Bun.file(globalPath).json();
57
+ globalHooks = globalData as HooksConfig;
58
+ } catch (err) {
59
+ const logger = getLogger();
60
+ logger.warn("hooks", "Failed to parse global hooks.json", { path: globalPath, error: String(err) });
61
+ }
62
+ }
63
+ }
64
+
65
+ // Return project hooks as the main config, with global hooks stored separately
66
+ return {
67
+ ...projectHooks,
68
+ _global: skipGlobal ? undefined : globalHooks,
69
+ _skipGlobal: skipGlobal,
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Escape environment variable values to prevent injection
75
+ * @param value - Raw value to escape
76
+ * @returns Escaped value safe for subprocess environment
77
+ */
78
+ function escapeEnvValue(value: string): string {
79
+ // Remove null bytes and newlines that could cause issues
80
+ return value.replace(/\0/g, "").replace(/\n/g, " ").replace(/\r/g, "");
81
+ }
82
+
83
+ /**
84
+ * Build environment variables from hook context
85
+ * All values are escaped to prevent injection attacks
86
+ */
87
+ function buildEnv(ctx: HookContext): Record<string, string> {
88
+ const env: Record<string, string> = {
89
+ NAX_EVENT: escapeEnvValue(ctx.event),
90
+ NAX_FEATURE: escapeEnvValue(ctx.feature),
91
+ };
92
+
93
+ if (ctx.storyId) env.NAX_STORY_ID = escapeEnvValue(ctx.storyId);
94
+ if (ctx.status) env.NAX_STATUS = escapeEnvValue(ctx.status);
95
+ if (ctx.reason) env.NAX_REASON = escapeEnvValue(ctx.reason);
96
+ if (ctx.cost !== undefined) env.NAX_COST = ctx.cost.toFixed(4);
97
+ if (ctx.model) env.NAX_MODEL = escapeEnvValue(ctx.model);
98
+ if (ctx.agent) env.NAX_AGENT = escapeEnvValue(ctx.agent);
99
+ if (ctx.iteration !== undefined) env.NAX_ITERATION = String(ctx.iteration);
100
+
101
+ return env;
102
+ }
103
+
104
+ /**
105
+ * Detect shell operators that indicate shell interpolation
106
+ * @param command - Command string to check
107
+ * @returns true if shell operators detected
108
+ */
109
+ function hasShellOperators(command: string): boolean {
110
+ // Check for common shell operators that require shell interpretation
111
+ const shellOperators = /[|&;$`<>(){}]/;
112
+ return shellOperators.test(command);
113
+ }
114
+
115
+ /**
116
+ * Validate hook command for injection patterns
117
+ * @param command - Command string to validate
118
+ * @throws Error if obvious injection pattern detected
119
+ */
120
+ function validateHookCommand(command: string): void {
121
+ // Reject commands with obvious injection patterns
122
+ const dangerousPatterns = [
123
+ /\$\(.*\)/, // Command substitution $(...)
124
+ /`.*`/, // Backtick command substitution
125
+ /\|\s*bash/, // Piping to bash
126
+ /\|\s*sh/, // Piping to sh
127
+ /;\s*rm\s+-rf/, // Dangerous deletion
128
+ /&&\s*rm\s+-rf/, // Dangerous deletion after success
129
+ /\beval\s+/, // SEC-3 fix: eval command
130
+ /curl\s+[^|]*\|\s*/, // SEC-3 fix: curl piping
131
+ /python\s+-c/, // SEC-3 fix: python -c execution
132
+ ];
133
+
134
+ for (const pattern of dangerousPatterns) {
135
+ if (pattern.test(command)) {
136
+ throw new Error(`Hook command contains dangerous pattern: ${pattern.source}`);
137
+ }
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Parse command string into argv array
143
+ * Simple space-based splitting (does not handle complex quoting)
144
+ * @param command - Command string
145
+ * @returns Array of command and arguments
146
+ */
147
+ function parseCommandToArgv(command: string): string[] {
148
+ return command.trim().split(/\s+/);
149
+ }
150
+
151
+ /**
152
+ * Execute a single hook
153
+ *
154
+ * SECURITY WARNING: Hook commands are executed as subprocesses.
155
+ * - Commands are parsed into argv arrays to avoid shell injection
156
+ * - Shell operators (|, &&, ;, $, etc.) trigger a security warning
157
+ * - Obvious injection patterns are rejected
158
+ * - Environment variables are escaped
159
+ * - Only configure hooks from trusted sources
160
+ *
161
+ * @param hookDef - Hook definition from config
162
+ * @param ctx - Hook context with environment variables
163
+ * @param workdir - Working directory for command execution
164
+ * @returns Promise with success status and output
165
+ */
166
+ async function executeHook(
167
+ hookDef: HookDef,
168
+ ctx: HookContext,
169
+ workdir: string,
170
+ ): Promise<{ success: boolean; output: string }> {
171
+ if (hookDef.enabled === false) {
172
+ return { success: true, output: "(disabled)" };
173
+ }
174
+
175
+ // Validate command for injection patterns
176
+ try {
177
+ validateHookCommand(hookDef.command);
178
+ } catch (err) {
179
+ return {
180
+ success: false,
181
+ output: `Security validation failed: ${err}`,
182
+ };
183
+ }
184
+
185
+ // Warn if shell operators detected
186
+ const logger = getLogger();
187
+ if (hasShellOperators(hookDef.command)) {
188
+ logger.warn("hooks", "[SECURITY] Hook command contains shell operators", {
189
+ command: hookDef.command,
190
+ warning: "Shell operators may enable injection attacks. Consider using simple commands only.",
191
+ });
192
+ }
193
+
194
+ const timeout = hookDef.timeout ?? DEFAULT_TIMEOUT;
195
+ const env = buildEnv(ctx);
196
+
197
+ // Pass full context as JSON via stdin
198
+ const contextJson = JSON.stringify(ctx);
199
+
200
+ // Parse command to argv array (no shell interpolation)
201
+ const argv = parseCommandToArgv(hookDef.command);
202
+ if (argv.length === 0) {
203
+ return { success: false, output: "Empty command" };
204
+ }
205
+
206
+ const proc = Bun.spawn(argv, {
207
+ cwd: workdir,
208
+ stdin: new Response(contextJson),
209
+ stdout: "pipe",
210
+ stderr: "pipe",
211
+ env: { ...process.env, ...env },
212
+ });
213
+
214
+ // Timeout handling
215
+ const timeoutId = setTimeout(() => {
216
+ proc.kill("SIGTERM");
217
+ }, timeout);
218
+
219
+ const exitCode = await proc.exited;
220
+ clearTimeout(timeoutId);
221
+
222
+ const stdout = await new Response(proc.stdout).text();
223
+ const stderr = await new Response(proc.stderr).text();
224
+
225
+ const output = (stdout + stderr).trim();
226
+
227
+ // Check if process was killed by timeout
228
+ if (exitCode !== 0 && output === "") {
229
+ return {
230
+ success: false,
231
+ output: `Hook timed out after ${timeout}ms`,
232
+ };
233
+ }
234
+
235
+ return {
236
+ success: exitCode === 0,
237
+ output,
238
+ };
239
+ }
240
+
241
+ /**
242
+ * Fire a hook event for both global and project hooks.
243
+ *
244
+ * Both hooks fire independently - global failure doesn't block project hook.
245
+ *
246
+ * @param config - Loaded hooks config (contains both global and project hooks)
247
+ * @param event - Hook event name
248
+ * @param ctx - Hook context
249
+ * @param workdir - Working directory
250
+ */
251
+ export async function fireHook(
252
+ config: LoadedHooksConfig,
253
+ event: HookEvent,
254
+ ctx: HookContext,
255
+ workdir: string,
256
+ ): Promise<void> {
257
+ const logger = getLogger();
258
+
259
+ // Fire global hook first (if present and not skipped)
260
+ if (config._global && !config._skipGlobal) {
261
+ const globalHookDef = config._global.hooks[event];
262
+ if (globalHookDef && globalHookDef.enabled !== false) {
263
+ try {
264
+ const result = await executeHook(globalHookDef, { ...ctx, event }, workdir);
265
+ if (!result.success) {
266
+ logger.warn("hooks", `Global hook ${event} failed`, { event, output: result.output });
267
+ }
268
+ } catch (err) {
269
+ logger.warn("hooks", `Global hook ${event} error`, { event, error: String(err) });
270
+ }
271
+ }
272
+ }
273
+
274
+ // Fire project hook (independent of global hook result)
275
+ const projectHookDef = config.hooks[event];
276
+ if (projectHookDef && projectHookDef.enabled !== false) {
277
+ try {
278
+ const result = await executeHook(projectHookDef, { ...ctx, event }, workdir);
279
+ if (!result.success) {
280
+ logger.warn("hooks", `Project hook ${event} failed`, { event, output: result.output });
281
+ }
282
+ } catch (err) {
283
+ logger.warn("hooks", `Project hook ${event} error`, { event, error: String(err) });
284
+ }
285
+ }
286
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Hook System Types
3
+ *
4
+ * Script-based lifecycle hooks configured via hooks.json.
5
+ */
6
+
7
+ /** All supported hook events */
8
+ export type HookEvent =
9
+ | "on-start"
10
+ | "on-story-start"
11
+ | "on-story-complete"
12
+ | "on-story-fail"
13
+ | "on-pause"
14
+ | "on-resume"
15
+ | "on-session-end"
16
+ | "on-complete"
17
+ | "on-error";
18
+
19
+ /** Single hook definition */
20
+ export interface HookDef {
21
+ /** Command to execute */
22
+ command: string;
23
+ /** Timeout in milliseconds (default: 5000) */
24
+ timeout?: number;
25
+ /** Whether this hook is enabled (default: true) */
26
+ enabled?: boolean;
27
+ /** Interaction prompt (v0.15.0) */
28
+ interaction?: {
29
+ /** Interaction type */
30
+ type: "confirm" | "choose" | "input" | "review" | "notify";
31
+ /** Summary template (supports {{variable}} syntax) */
32
+ summary: string;
33
+ /** Detail template (optional) */
34
+ detail?: string;
35
+ /** Fallback behavior on timeout */
36
+ fallback: "continue" | "skip" | "escalate" | "abort";
37
+ /** Timeout in milliseconds (optional) */
38
+ timeout?: number;
39
+ };
40
+ }
41
+
42
+ /** hooks.json schema */
43
+ export interface HooksConfig {
44
+ hooks: Partial<Record<HookEvent, HookDef>>;
45
+ }
46
+
47
+ /** Context passed to hooks via environment variables */
48
+ export interface HookContext {
49
+ /** Event name */
50
+ event: HookEvent;
51
+ /** Feature name */
52
+ feature: string;
53
+ /** Current story ID */
54
+ storyId?: string;
55
+ /** Status (pass/fail/paused/error) */
56
+ status?: string;
57
+ /** Reason for pause/error */
58
+ reason?: string;
59
+ /** Accumulated cost (USD) */
60
+ cost?: number;
61
+ /** Current model */
62
+ model?: string;
63
+ /** Current agent */
64
+ agent?: string;
65
+ /** Current iteration number */
66
+ iteration?: number;
67
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Interaction Plugin Chain (v0.15.0)
3
+ *
4
+ * Manages plugin priority, fallback cascade, and request routing.
5
+ */
6
+
7
+ import type { InteractionFallback, InteractionPlugin, InteractionRequest, InteractionResponse } from "./types";
8
+
9
+ /** Plugin chain entry */
10
+ interface ChainEntry {
11
+ plugin: InteractionPlugin;
12
+ priority: number;
13
+ }
14
+
15
+ /** Plugin chain configuration */
16
+ export interface ChainConfig {
17
+ /** Default timeout for all requests (ms) */
18
+ defaultTimeout: number;
19
+ /** Default fallback behavior */
20
+ defaultFallback: InteractionFallback;
21
+ }
22
+
23
+ /**
24
+ * Interaction plugin chain with priority and fallback cascade
25
+ */
26
+ export class InteractionChain {
27
+ private plugins: ChainEntry[] = [];
28
+ private config: ChainConfig;
29
+
30
+ constructor(config: ChainConfig) {
31
+ this.config = config;
32
+ }
33
+
34
+ /**
35
+ * Register a plugin with priority (higher = earlier in chain)
36
+ */
37
+ register(plugin: InteractionPlugin, priority = 0): void {
38
+ this.plugins.push({ plugin, priority });
39
+ this.plugins.sort((a, b) => b.priority - a.priority); // descending
40
+ }
41
+
42
+ /**
43
+ * Get primary plugin (highest priority)
44
+ */
45
+ getPrimary(): InteractionPlugin | null {
46
+ return this.plugins[0]?.plugin ?? null;
47
+ }
48
+
49
+ /**
50
+ * Send interaction request through the chain
51
+ */
52
+ async send(request: InteractionRequest): Promise<void> {
53
+ const plugin = this.getPrimary();
54
+ if (!plugin) {
55
+ throw new Error("No interaction plugin registered");
56
+ }
57
+ await plugin.send(request);
58
+ }
59
+
60
+ /**
61
+ * Receive interaction response with timeout and fallback cascade
62
+ */
63
+ async receive(requestId: string, timeout?: number): Promise<InteractionResponse> {
64
+ if (this.plugins.length === 0) {
65
+ throw new Error("No interaction plugin registered");
66
+ }
67
+
68
+ const timeoutMs = timeout ?? this.config.defaultTimeout;
69
+ const errors: Error[] = [];
70
+
71
+ // Try each plugin in priority order (fallback cascade)
72
+ for (const entry of this.plugins) {
73
+ try {
74
+ const response = await entry.plugin.receive(requestId, timeoutMs);
75
+ return response;
76
+ } catch (err) {
77
+ const error = err instanceof Error ? err : new Error(String(err));
78
+ errors.push(error);
79
+ // Continue to next plugin
80
+ }
81
+ }
82
+
83
+ // All plugins failed - throw with all error messages
84
+ const errorMessages = errors.map((e) => e.message).join("; ");
85
+ throw new Error(`All interaction plugins failed: ${errorMessages}`);
86
+ }
87
+
88
+ /**
89
+ * Send and receive in one call (convenience method)
90
+ */
91
+ async prompt(request: InteractionRequest): Promise<InteractionResponse> {
92
+ await this.send(request);
93
+ const response = await this.receive(request.id, request.timeout);
94
+ return response;
95
+ }
96
+
97
+ /**
98
+ * Cancel a pending interaction
99
+ */
100
+ async cancel(requestId: string): Promise<void> {
101
+ const plugin = this.getPrimary();
102
+ if (plugin?.cancel) {
103
+ await plugin.cancel(requestId);
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Initialize all plugins
109
+ */
110
+ async init(pluginConfigs: Record<string, Record<string, unknown>>): Promise<void> {
111
+ for (const entry of this.plugins) {
112
+ if (entry.plugin.init) {
113
+ const config = pluginConfigs[entry.plugin.name] ?? {};
114
+ await entry.plugin.init(config);
115
+ }
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Destroy all plugins
121
+ */
122
+ async destroy(): Promise<void> {
123
+ for (const entry of this.plugins) {
124
+ if (entry.plugin.destroy) {
125
+ await entry.plugin.destroy();
126
+ }
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Apply fallback behavior to get final action
132
+ */
133
+ applyFallback(response: InteractionResponse, fallback: InteractionFallback): InteractionAction {
134
+ // If user responded explicitly, use their action
135
+ if (response.respondedBy !== "timeout" && response.respondedBy !== "system") {
136
+ return response.action;
137
+ }
138
+
139
+ // Otherwise apply fallback
140
+ switch (fallback) {
141
+ case "continue":
142
+ return "approve";
143
+ case "skip":
144
+ return "skip";
145
+ case "escalate":
146
+ return "approve"; // proceed but escalate tier
147
+ case "abort":
148
+ return "abort";
149
+ }
150
+ }
151
+ }
152
+
153
+ /** Convenience type for action */
154
+ type InteractionAction = InteractionResponse["action"];
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Interaction System — Barrel Exports (v0.15.0)
3
+ */
4
+
5
+ // Types
6
+ export type {
7
+ InteractionType,
8
+ InteractionStage,
9
+ InteractionFallback,
10
+ InteractionRequest,
11
+ InteractionAction,
12
+ InteractionResponse,
13
+ InteractionPlugin,
14
+ TriggerName,
15
+ TriggerConfig,
16
+ TriggerSafety,
17
+ TriggerMetadata,
18
+ } from "./types";
19
+ export { TRIGGER_METADATA } from "./types";
20
+
21
+ // Chain
22
+ export { InteractionChain } from "./chain";
23
+ export type { ChainConfig } from "./chain";
24
+
25
+ // State persistence
26
+ export {
27
+ serializeRunState,
28
+ deserializeRunState,
29
+ clearRunState,
30
+ savePendingInteraction,
31
+ loadPendingInteraction,
32
+ deletePendingInteraction,
33
+ listPendingInteractions,
34
+ } from "./state";
35
+ export type { RunState } from "./state";
36
+
37
+ // Plugins
38
+ export { CLIInteractionPlugin } from "./plugins/cli";
39
+ export { TelegramInteractionPlugin } from "./plugins/telegram";
40
+ export { WebhookInteractionPlugin } from "./plugins/webhook";
41
+ export { AutoInteractionPlugin } from "./plugins/auto";
42
+
43
+ // Triggers
44
+ export {
45
+ isTriggerEnabled,
46
+ createTriggerRequest,
47
+ executeTrigger,
48
+ checkSecurityReview,
49
+ checkCostExceeded,
50
+ checkMergeConflict,
51
+ checkCostWarning,
52
+ checkMaxRetries,
53
+ checkPreMerge,
54
+ checkStoryAmbiguity,
55
+ checkReviewGate,
56
+ } from "./triggers";
57
+ export type { TriggerContext } from "./triggers";
58
+
59
+ // Initialization
60
+ export { initInteractionChain } from "./init";
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Interaction Chain Initialization Helper
3
+ *
4
+ * Creates and initializes interaction chain from config.
5
+ */
6
+
7
+ import type { NaxConfig } from "../config";
8
+ import { getSafeLogger } from "../logger";
9
+ import { InteractionChain } from "./chain";
10
+ import { AutoInteractionPlugin } from "./plugins/auto";
11
+ import { CLIInteractionPlugin } from "./plugins/cli";
12
+ import { TelegramInteractionPlugin } from "./plugins/telegram";
13
+ import { WebhookInteractionPlugin } from "./plugins/webhook";
14
+ import type { InteractionPlugin } from "./types";
15
+
16
+ /**
17
+ * Create interaction plugin based on config
18
+ */
19
+ function createInteractionPlugin(pluginName: string): InteractionPlugin {
20
+ switch (pluginName) {
21
+ case "cli":
22
+ return new CLIInteractionPlugin();
23
+ case "telegram":
24
+ return new TelegramInteractionPlugin();
25
+ case "webhook":
26
+ return new WebhookInteractionPlugin();
27
+ case "auto":
28
+ return new AutoInteractionPlugin();
29
+ default:
30
+ throw new Error(`Unknown interaction plugin: ${pluginName}`);
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Initialize interaction chain from config
36
+ *
37
+ * @param config - Nax configuration
38
+ * @param headless - Whether running in headless mode (skip interactions)
39
+ * @returns Initialized interaction chain or null if disabled/headless
40
+ */
41
+ export async function initInteractionChain(config: NaxConfig, headless: boolean): Promise<InteractionChain | null> {
42
+ const logger = getSafeLogger();
43
+
44
+ // If headless mode, skip interaction system
45
+ if (headless) {
46
+ logger?.debug("interaction", "Headless mode - skipping interaction system");
47
+ return null;
48
+ }
49
+
50
+ // If no interaction config, skip
51
+ if (!config.interaction) {
52
+ logger?.debug("interaction", "No interaction config - skipping interaction system");
53
+ return null;
54
+ }
55
+
56
+ // Create chain
57
+ const chain = new InteractionChain({
58
+ defaultTimeout: config.interaction.defaults.timeout,
59
+ defaultFallback: config.interaction.defaults.fallback,
60
+ });
61
+
62
+ // Create and register plugin
63
+ const pluginName = config.interaction.plugin;
64
+ try {
65
+ const plugin = createInteractionPlugin(pluginName);
66
+ chain.register(plugin, 100);
67
+
68
+ // Initialize plugin
69
+ const pluginConfig = config.interaction.config ?? {};
70
+ await chain.init({ [pluginName]: pluginConfig });
71
+
72
+ logger?.info("interaction", `Initialized ${pluginName} interaction plugin`, {
73
+ timeout: config.interaction.defaults.timeout,
74
+ fallback: config.interaction.defaults.fallback,
75
+ });
76
+
77
+ return chain;
78
+ } catch (err) {
79
+ const error = err instanceof Error ? err.message : String(err);
80
+ logger?.error("interaction", `Failed to initialize interaction plugin: ${error}`);
81
+ throw err;
82
+ }
83
+ }