@nodetool-ai/cli 0.7.0-rc.23 → 0.8.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 (488) hide show
  1. package/README.md +79 -0
  2. package/dist/.nodetool-build-stamp +1 -0
  3. package/dist/ExecutionTree.d.ts +2 -1
  4. package/dist/ExecutionTree.d.ts.map +1 -1
  5. package/dist/ExecutionTree.js +1 -1
  6. package/dist/ExecutionTree.js.map +1 -1
  7. package/dist/affected/affected.d.ts +50 -0
  8. package/dist/affected/affected.d.ts.map +1 -0
  9. package/dist/affected/affected.js +118 -0
  10. package/dist/affected/affected.js.map +1 -0
  11. package/dist/agent-toolbelt.d.ts +15 -0
  12. package/dist/agent-toolbelt.d.ts.map +1 -0
  13. package/dist/agent-toolbelt.js +28 -0
  14. package/dist/agent-toolbelt.js.map +1 -0
  15. package/dist/api-client.d.ts +12 -0
  16. package/dist/api-client.d.ts.map +1 -0
  17. package/dist/api-client.js +21 -0
  18. package/dist/api-client.js.map +1 -0
  19. package/dist/app-build/bundle.d.ts +15 -0
  20. package/dist/app-build/bundle.d.ts.map +1 -0
  21. package/dist/app-build/bundle.js +45 -0
  22. package/dist/app-build/bundle.js.map +1 -0
  23. package/dist/app-build/watch.d.ts +13 -0
  24. package/dist/app-build/watch.d.ts.map +1 -0
  25. package/dist/app-build/watch.js +25 -0
  26. package/dist/app-build/watch.js.map +1 -0
  27. package/dist/app-debug/app-target.d.ts +14 -0
  28. package/dist/app-debug/app-target.d.ts.map +1 -0
  29. package/dist/app-debug/app-target.js +120 -0
  30. package/dist/app-debug/app-target.js.map +1 -0
  31. package/dist/app-debug/harness.d.ts +27 -0
  32. package/dist/app-debug/harness.d.ts.map +1 -0
  33. package/dist/app-debug/harness.js +93 -0
  34. package/dist/app-debug/harness.js.map +1 -0
  35. package/dist/app-debug/index.d.ts +12 -0
  36. package/dist/app-debug/index.d.ts.map +1 -0
  37. package/dist/app-debug/index.js +9 -0
  38. package/dist/app-debug/index.js.map +1 -0
  39. package/dist/app.d.ts +38 -48
  40. package/dist/app.d.ts.map +1 -1
  41. package/dist/app.js +979 -677
  42. package/dist/app.js.map +1 -1
  43. package/dist/bash-tool.d.ts +13 -0
  44. package/dist/bash-tool.d.ts.map +1 -0
  45. package/dist/bash-tool.js +85 -0
  46. package/dist/bash-tool.js.map +1 -0
  47. package/dist/chat-codeact.d.ts +85 -0
  48. package/dist/chat-codeact.d.ts.map +1 -0
  49. package/dist/chat-codeact.js +141 -0
  50. package/dist/chat-codeact.js.map +1 -0
  51. package/dist/chat-context.d.ts +18 -0
  52. package/dist/chat-context.d.ts.map +1 -0
  53. package/dist/chat-context.js +27 -0
  54. package/dist/chat-context.js.map +1 -0
  55. package/dist/chat-media.d.ts +3 -0
  56. package/dist/chat-media.d.ts.map +1 -0
  57. package/dist/chat-media.js +46 -0
  58. package/dist/chat-media.js.map +1 -0
  59. package/dist/chat-prompts.d.ts +20 -0
  60. package/dist/chat-prompts.d.ts.map +1 -0
  61. package/dist/chat-prompts.js +42 -0
  62. package/dist/chat-prompts.js.map +1 -0
  63. package/dist/chat-sessions.d.ts +25 -0
  64. package/dist/chat-sessions.d.ts.map +1 -0
  65. package/dist/chat-sessions.js +153 -0
  66. package/dist/chat-sessions.js.map +1 -0
  67. package/dist/command-errors.d.ts +10 -0
  68. package/dist/command-errors.d.ts.map +1 -0
  69. package/dist/command-errors.js +15 -0
  70. package/dist/command-errors.js.map +1 -0
  71. package/dist/commands/__tests__/jtbd.test.d.ts +2 -0
  72. package/dist/commands/__tests__/jtbd.test.d.ts.map +1 -0
  73. package/dist/commands/__tests__/jtbd.test.js +120 -0
  74. package/dist/commands/__tests__/jtbd.test.js.map +1 -0
  75. package/dist/commands/__tests__/timeline-render-audio.test.d.ts +2 -0
  76. package/dist/commands/__tests__/timeline-render-audio.test.d.ts.map +1 -0
  77. package/dist/commands/__tests__/timeline-render-audio.test.js +53 -0
  78. package/dist/commands/__tests__/timeline-render-audio.test.js.map +1 -0
  79. package/dist/commands/__tests__/timeline-render.test.d.ts +2 -0
  80. package/dist/commands/__tests__/timeline-render.test.d.ts.map +1 -0
  81. package/dist/commands/__tests__/timeline-render.test.js +115 -0
  82. package/dist/commands/__tests__/timeline-render.test.js.map +1 -0
  83. package/dist/commands/affected.d.ts +9 -0
  84. package/dist/commands/affected.d.ts.map +1 -0
  85. package/dist/commands/affected.js +122 -0
  86. package/dist/commands/affected.js.map +1 -0
  87. package/dist/commands/agent.d.ts +26 -4
  88. package/dist/commands/agent.d.ts.map +1 -1
  89. package/dist/commands/agent.js +327 -306
  90. package/dist/commands/agent.js.map +1 -1
  91. package/dist/commands/app.d.ts +3 -0
  92. package/dist/commands/app.d.ts.map +1 -0
  93. package/dist/commands/app.js +381 -0
  94. package/dist/commands/app.js.map +1 -0
  95. package/dist/commands/apps.d.ts +15 -0
  96. package/dist/commands/apps.d.ts.map +1 -0
  97. package/dist/commands/apps.js +180 -0
  98. package/dist/commands/apps.js.map +1 -0
  99. package/dist/commands/auth.d.ts +12 -0
  100. package/dist/commands/auth.d.ts.map +1 -0
  101. package/dist/commands/auth.js +154 -0
  102. package/dist/commands/auth.js.map +1 -0
  103. package/dist/commands/collections.d.ts +10 -0
  104. package/dist/commands/collections.d.ts.map +1 -0
  105. package/dist/commands/collections.js +257 -0
  106. package/dist/commands/collections.js.map +1 -0
  107. package/dist/commands/costs.d.ts +15 -0
  108. package/dist/commands/costs.d.ts.map +1 -0
  109. package/dist/commands/costs.js +201 -0
  110. package/dist/commands/costs.js.map +1 -0
  111. package/dist/commands/db.d.ts +3 -0
  112. package/dist/commands/db.d.ts.map +1 -0
  113. package/dist/commands/db.js +176 -0
  114. package/dist/commands/db.js.map +1 -0
  115. package/dist/commands/debug.d.ts +13 -0
  116. package/dist/commands/debug.d.ts.map +1 -0
  117. package/dist/commands/debug.js +138 -0
  118. package/dist/commands/debug.js.map +1 -0
  119. package/dist/commands/deploy-helpers.d.ts +49 -18
  120. package/dist/commands/deploy-helpers.d.ts.map +1 -1
  121. package/dist/commands/deploy-helpers.js +10 -276
  122. package/dist/commands/deploy-helpers.js.map +1 -1
  123. package/dist/commands/deploy.d.ts +0 -1
  124. package/dist/commands/deploy.d.ts.map +1 -1
  125. package/dist/commands/deploy.js +21 -217
  126. package/dist/commands/deploy.js.map +1 -1
  127. package/dist/commands/eval.d.ts +152 -0
  128. package/dist/commands/eval.d.ts.map +1 -0
  129. package/dist/commands/eval.js +688 -0
  130. package/dist/commands/eval.js.map +1 -0
  131. package/dist/commands/game.d.ts +4 -0
  132. package/dist/commands/game.d.ts.map +1 -0
  133. package/dist/commands/game.js +395 -0
  134. package/dist/commands/game.js.map +1 -0
  135. package/dist/commands/generate.d.ts +17 -0
  136. package/dist/commands/generate.d.ts.map +1 -0
  137. package/dist/commands/generate.js +324 -0
  138. package/dist/commands/generate.js.map +1 -0
  139. package/dist/commands/generations.d.ts +17 -0
  140. package/dist/commands/generations.d.ts.map +1 -0
  141. package/dist/commands/generations.js +408 -0
  142. package/dist/commands/generations.js.map +1 -0
  143. package/dist/commands/harness.d.ts +19 -0
  144. package/dist/commands/harness.d.ts.map +1 -0
  145. package/dist/commands/harness.js +361 -0
  146. package/dist/commands/harness.js.map +1 -0
  147. package/dist/commands/js-script-validation-output.d.ts +7 -0
  148. package/dist/commands/js-script-validation-output.d.ts.map +1 -0
  149. package/dist/commands/js-script-validation-output.js +5 -0
  150. package/dist/commands/js-script-validation-output.js.map +1 -0
  151. package/dist/commands/js-script-versions.d.ts +53 -0
  152. package/dist/commands/js-script-versions.d.ts.map +1 -0
  153. package/dist/commands/js-script-versions.js +89 -0
  154. package/dist/commands/js-script-versions.js.map +1 -0
  155. package/dist/commands/js-script.d.ts +29 -0
  156. package/dist/commands/js-script.d.ts.map +1 -0
  157. package/dist/commands/js-script.js +227 -0
  158. package/dist/commands/js-script.js.map +1 -0
  159. package/dist/commands/jtbd.d.ts +38 -0
  160. package/dist/commands/jtbd.d.ts.map +1 -0
  161. package/dist/commands/jtbd.js +261 -0
  162. package/dist/commands/jtbd.js.map +1 -0
  163. package/dist/commands/local-db.d.ts +16 -0
  164. package/dist/commands/local-db.d.ts.map +1 -0
  165. package/dist/commands/local-db.js +33 -0
  166. package/dist/commands/local-db.js.map +1 -0
  167. package/dist/commands/migrate-code-inputs.d.ts +24 -0
  168. package/dist/commands/migrate-code-inputs.d.ts.map +1 -0
  169. package/dist/commands/migrate-code-inputs.js +120 -0
  170. package/dist/commands/migrate-code-inputs.js.map +1 -0
  171. package/dist/commands/models-hf.js +4 -4
  172. package/dist/commands/models-hf.js.map +1 -1
  173. package/dist/commands/models-recommended.d.ts.map +1 -1
  174. package/dist/commands/models-recommended.js +16 -24
  175. package/dist/commands/models-recommended.js.map +1 -1
  176. package/dist/commands/node.d.ts +10 -0
  177. package/dist/commands/node.d.ts.map +1 -0
  178. package/dist/commands/node.js +72 -0
  179. package/dist/commands/node.js.map +1 -0
  180. package/dist/commands/output.d.ts +24 -0
  181. package/dist/commands/output.d.ts.map +1 -0
  182. package/dist/commands/output.js +132 -0
  183. package/dist/commands/output.js.map +1 -0
  184. package/dist/commands/package-helpers.d.ts +1 -7
  185. package/dist/commands/package-helpers.d.ts.map +1 -1
  186. package/dist/commands/package-helpers.js +3 -26
  187. package/dist/commands/package-helpers.js.map +1 -1
  188. package/dist/commands/package.js +2 -2
  189. package/dist/commands/package.js.map +1 -1
  190. package/dist/commands/packs.d.ts +13 -0
  191. package/dist/commands/packs.d.ts.map +1 -0
  192. package/dist/commands/packs.js +60 -0
  193. package/dist/commands/packs.js.map +1 -0
  194. package/dist/commands/reliability.d.ts +14 -0
  195. package/dist/commands/reliability.d.ts.map +1 -0
  196. package/dist/commands/reliability.js +80 -0
  197. package/dist/commands/reliability.js.map +1 -0
  198. package/dist/commands/resource-read.d.ts +28 -0
  199. package/dist/commands/resource-read.d.ts.map +1 -0
  200. package/dist/commands/resource-read.js +316 -0
  201. package/dist/commands/resource-read.js.map +1 -0
  202. package/dist/commands/sketch-validation-output.d.ts +7 -0
  203. package/dist/commands/sketch-validation-output.d.ts.map +1 -0
  204. package/dist/commands/sketch-validation-output.js +5 -0
  205. package/dist/commands/sketch-validation-output.js.map +1 -0
  206. package/dist/commands/sketch-versions.d.ts +66 -0
  207. package/dist/commands/sketch-versions.d.ts.map +1 -0
  208. package/dist/commands/sketch-versions.js +108 -0
  209. package/dist/commands/sketch-versions.js.map +1 -0
  210. package/dist/commands/sketch.d.ts +21 -0
  211. package/dist/commands/sketch.d.ts.map +1 -0
  212. package/dist/commands/sketch.js +117 -0
  213. package/dist/commands/sketch.js.map +1 -0
  214. package/dist/commands/storage.d.ts +24 -0
  215. package/dist/commands/storage.d.ts.map +1 -0
  216. package/dist/commands/storage.js +112 -0
  217. package/dist/commands/storage.js.map +1 -0
  218. package/dist/commands/telegram.d.ts +11 -0
  219. package/dist/commands/telegram.d.ts.map +1 -0
  220. package/dist/commands/telegram.js +66 -0
  221. package/dist/commands/telegram.js.map +1 -0
  222. package/dist/commands/timeline-render.d.ts +80 -0
  223. package/dist/commands/timeline-render.d.ts.map +1 -0
  224. package/dist/commands/timeline-render.js +465 -0
  225. package/dist/commands/timeline-render.js.map +1 -0
  226. package/dist/commands/timeline-validation-output.d.ts +7 -0
  227. package/dist/commands/timeline-validation-output.d.ts.map +1 -0
  228. package/dist/commands/timeline-validation-output.js +9 -0
  229. package/dist/commands/timeline-validation-output.js.map +1 -0
  230. package/dist/commands/timeline-versions.d.ts +72 -0
  231. package/dist/commands/timeline-versions.d.ts.map +1 -0
  232. package/dist/commands/timeline-versions.js +108 -0
  233. package/dist/commands/timeline-versions.js.map +1 -0
  234. package/dist/commands/timeline.d.ts +22 -0
  235. package/dist/commands/timeline.d.ts.map +1 -0
  236. package/dist/commands/timeline.js +119 -0
  237. package/dist/commands/timeline.js.map +1 -0
  238. package/dist/commands/validate.d.ts +22 -0
  239. package/dist/commands/validate.d.ts.map +1 -0
  240. package/dist/commands/validate.js +127 -0
  241. package/dist/commands/validate.js.map +1 -0
  242. package/dist/commands/validation-output.d.ts +25 -0
  243. package/dist/commands/validation-output.d.ts.map +1 -0
  244. package/dist/commands/validation-output.js +29 -0
  245. package/dist/commands/validation-output.js.map +1 -0
  246. package/dist/commands/version-commands.d.ts +94 -0
  247. package/dist/commands/version-commands.d.ts.map +1 -0
  248. package/dist/commands/version-commands.js +227 -0
  249. package/dist/commands/version-commands.js.map +1 -0
  250. package/dist/commands/worker-models.d.ts +13 -0
  251. package/dist/commands/worker-models.d.ts.map +1 -0
  252. package/dist/commands/worker-models.js +207 -0
  253. package/dist/commands/worker-models.js.map +1 -0
  254. package/dist/commands/worker.d.ts +23 -0
  255. package/dist/commands/worker.d.ts.map +1 -0
  256. package/dist/commands/worker.js +374 -0
  257. package/dist/commands/worker.js.map +1 -0
  258. package/dist/debug/browser-runner.d.ts +21 -0
  259. package/dist/debug/browser-runner.d.ts.map +1 -0
  260. package/dist/debug/browser-runner.js +196 -0
  261. package/dist/debug/browser-runner.js.map +1 -0
  262. package/dist/debug/collector.d.ts +9 -0
  263. package/dist/debug/collector.d.ts.map +1 -0
  264. package/dist/debug/collector.js +9 -0
  265. package/dist/debug/collector.js.map +1 -0
  266. package/dist/debug/diff.d.ts +48 -0
  267. package/dist/debug/diff.d.ts.map +1 -0
  268. package/dist/debug/diff.js +68 -0
  269. package/dist/debug/diff.js.map +1 -0
  270. package/dist/debug/harness.d.ts +11 -0
  271. package/dist/debug/harness.d.ts.map +1 -0
  272. package/dist/debug/harness.js +103 -0
  273. package/dist/debug/harness.js.map +1 -0
  274. package/dist/debug/index.d.ts +17 -0
  275. package/dist/debug/index.d.ts.map +1 -0
  276. package/dist/debug/index.js +16 -0
  277. package/dist/debug/index.js.map +1 -0
  278. package/dist/debug/markdown.d.ts +3 -0
  279. package/dist/debug/markdown.d.ts.map +1 -0
  280. package/dist/debug/markdown.js +127 -0
  281. package/dist/debug/markdown.js.map +1 -0
  282. package/dist/debug/server-runner.d.ts +22 -0
  283. package/dist/debug/server-runner.d.ts.map +1 -0
  284. package/dist/debug/server-runner.js +164 -0
  285. package/dist/debug/server-runner.js.map +1 -0
  286. package/dist/debug/target.d.ts +34 -0
  287. package/dist/debug/target.d.ts.map +1 -0
  288. package/dist/debug/target.js +104 -0
  289. package/dist/debug/target.js.map +1 -0
  290. package/dist/debug/trace.d.ts +30 -0
  291. package/dist/debug/trace.d.ts.map +1 -0
  292. package/dist/debug/trace.js +87 -0
  293. package/dist/debug/trace.js.map +1 -0
  294. package/dist/debug/types.d.ts +82 -0
  295. package/dist/debug/types.d.ts.map +1 -0
  296. package/dist/debug/types.js +13 -0
  297. package/dist/debug/types.js.map +1 -0
  298. package/dist/debug/verdict.d.ts +3 -0
  299. package/dist/debug/verdict.d.ts.map +1 -0
  300. package/dist/debug/verdict.js +78 -0
  301. package/dist/debug/verdict.js.map +1 -0
  302. package/dist/debug/watch.d.ts +23 -0
  303. package/dist/debug/watch.d.ts.map +1 -0
  304. package/dist/debug/watch.js +68 -0
  305. package/dist/debug/watch.js.map +1 -0
  306. package/dist/diagnose.d.ts +139 -0
  307. package/dist/diagnose.d.ts.map +1 -0
  308. package/dist/diagnose.js +418 -0
  309. package/dist/diagnose.js.map +1 -0
  310. package/dist/evals/graph-runner.d.ts +8 -0
  311. package/dist/evals/graph-runner.d.ts.map +1 -0
  312. package/dist/evals/graph-runner.js +136 -0
  313. package/dist/evals/graph-runner.js.map +1 -0
  314. package/dist/harness/capability-coverage.d.ts +161 -0
  315. package/dist/harness/capability-coverage.d.ts.map +1 -0
  316. package/dist/harness/capability-coverage.js +266 -0
  317. package/dist/harness/capability-coverage.js.map +1 -0
  318. package/dist/harness/capability-table.d.ts +17 -0
  319. package/dist/harness/capability-table.d.ts.map +1 -0
  320. package/dist/harness/capability-table.js +3576 -0
  321. package/dist/harness/capability-table.js.map +1 -0
  322. package/dist/harness/changed-files.d.ts +18 -0
  323. package/dist/harness/changed-files.d.ts.map +1 -0
  324. package/dist/harness/changed-files.js +76 -0
  325. package/dist/harness/changed-files.js.map +1 -0
  326. package/dist/harness/declared-capabilities.d.ts +12 -0
  327. package/dist/harness/declared-capabilities.d.ts.map +1 -0
  328. package/dist/harness/declared-capabilities.js +21 -0
  329. package/dist/harness/declared-capabilities.js.map +1 -0
  330. package/dist/harness/registry.d.ts +162 -0
  331. package/dist/harness/registry.d.ts.map +1 -0
  332. package/dist/harness/registry.js +1738 -0
  333. package/dist/harness/registry.js.map +1 -0
  334. package/dist/index.js +121 -130
  335. package/dist/index.js.map +1 -1
  336. package/dist/interaction-script.d.ts +17 -0
  337. package/dist/interaction-script.d.ts.map +1 -0
  338. package/dist/interaction-script.js +47 -0
  339. package/dist/interaction-script.js.map +1 -0
  340. package/dist/js-script-debug/harness.d.ts +114 -0
  341. package/dist/js-script-debug/harness.d.ts.map +1 -0
  342. package/dist/js-script-debug/harness.js +252 -0
  343. package/dist/js-script-debug/harness.js.map +1 -0
  344. package/dist/js-script-debug/index.d.ts +9 -0
  345. package/dist/js-script-debug/index.d.ts.map +1 -0
  346. package/dist/js-script-debug/index.js +9 -0
  347. package/dist/js-script-debug/index.js.map +1 -0
  348. package/dist/js-script-debug/interactions.d.ts +19 -0
  349. package/dist/js-script-debug/interactions.d.ts.map +1 -0
  350. package/dist/js-script-debug/interactions.js +17 -0
  351. package/dist/js-script-debug/interactions.js.map +1 -0
  352. package/dist/js-script-debug/target.d.ts +20 -0
  353. package/dist/js-script-debug/target.d.ts.map +1 -0
  354. package/dist/js-script-debug/target.js +78 -0
  355. package/dist/js-script-debug/target.js.map +1 -0
  356. package/dist/local-model-interfaces.d.ts +20 -0
  357. package/dist/local-model-interfaces.d.ts.map +1 -0
  358. package/dist/local-model-interfaces.js +64 -0
  359. package/dist/local-model-interfaces.js.map +1 -0
  360. package/dist/local-secrets.d.ts +3 -0
  361. package/dist/local-secrets.d.ts.map +1 -0
  362. package/dist/local-secrets.js +16 -0
  363. package/dist/local-secrets.js.map +1 -0
  364. package/dist/markdown.d.ts.map +1 -1
  365. package/dist/markdown.js +7 -2
  366. package/dist/markdown.js.map +1 -1
  367. package/dist/node/run-node.d.ts +28 -0
  368. package/dist/node/run-node.d.ts.map +1 -0
  369. package/dist/node/run-node.js +76 -0
  370. package/dist/node/run-node.js.map +1 -0
  371. package/dist/node-registry.d.ts +13 -0
  372. package/dist/node-registry.d.ts.map +1 -0
  373. package/dist/node-registry.js +36 -0
  374. package/dist/node-registry.js.map +1 -0
  375. package/dist/nodetool.js +845 -309
  376. package/dist/nodetool.js.map +1 -1
  377. package/dist/numeric-options.d.ts +22 -0
  378. package/dist/numeric-options.d.ts.map +1 -0
  379. package/dist/numeric-options.js +45 -0
  380. package/dist/numeric-options.js.map +1 -0
  381. package/dist/permission-gate.d.ts +55 -0
  382. package/dist/permission-gate.d.ts.map +1 -0
  383. package/dist/permission-gate.js +118 -0
  384. package/dist/permission-gate.js.map +1 -0
  385. package/dist/predicates.d.ts +6 -0
  386. package/dist/predicates.d.ts.map +1 -0
  387. package/dist/predicates.js +6 -0
  388. package/dist/predicates.js.map +1 -0
  389. package/dist/providers.d.ts +73 -10
  390. package/dist/providers.d.ts.map +1 -1
  391. package/dist/providers.js +329 -97
  392. package/dist/providers.js.map +1 -1
  393. package/dist/readline-input.d.ts +13 -19
  394. package/dist/readline-input.d.ts.map +1 -1
  395. package/dist/readline-input.js +201 -190
  396. package/dist/readline-input.js.map +1 -1
  397. package/dist/run-budget.d.ts +40 -0
  398. package/dist/run-budget.d.ts.map +1 -0
  399. package/dist/run-budget.js +119 -0
  400. package/dist/run-budget.js.map +1 -0
  401. package/dist/run-dsl-supervised.d.ts +11 -0
  402. package/dist/run-dsl-supervised.d.ts.map +1 -0
  403. package/dist/run-dsl-supervised.js +82 -0
  404. package/dist/run-dsl-supervised.js.map +1 -0
  405. package/dist/run-dsl.d.ts +23 -0
  406. package/dist/run-dsl.d.ts.map +1 -1
  407. package/dist/run-dsl.js +40 -9
  408. package/dist/run-dsl.js.map +1 -1
  409. package/dist/run-json.d.ts +24 -0
  410. package/dist/run-json.d.ts.map +1 -0
  411. package/dist/run-json.js +132 -0
  412. package/dist/run-json.js.map +1 -0
  413. package/dist/sandbox-catalog.d.ts +12 -0
  414. package/dist/sandbox-catalog.d.ts.map +1 -0
  415. package/dist/sandbox-catalog.js +27 -0
  416. package/dist/sandbox-catalog.js.map +1 -0
  417. package/dist/settings.d.ts +11 -10
  418. package/dist/settings.d.ts.map +1 -1
  419. package/dist/settings.js +71 -13
  420. package/dist/settings.js.map +1 -1
  421. package/dist/sketch-debug/harness.d.ts +87 -0
  422. package/dist/sketch-debug/harness.d.ts.map +1 -0
  423. package/dist/sketch-debug/harness.js +178 -0
  424. package/dist/sketch-debug/harness.js.map +1 -0
  425. package/dist/sketch-debug/index.d.ts +9 -0
  426. package/dist/sketch-debug/index.d.ts.map +1 -0
  427. package/dist/sketch-debug/index.js +9 -0
  428. package/dist/sketch-debug/index.js.map +1 -0
  429. package/dist/sketch-debug/interactions.d.ts +19 -0
  430. package/dist/sketch-debug/interactions.d.ts.map +1 -0
  431. package/dist/sketch-debug/interactions.js +17 -0
  432. package/dist/sketch-debug/interactions.js.map +1 -0
  433. package/dist/sketch-debug/target.d.ts +48 -0
  434. package/dist/sketch-debug/target.d.ts.map +1 -0
  435. package/dist/sketch-debug/target.js +138 -0
  436. package/dist/sketch-debug/target.js.map +1 -0
  437. package/dist/stdin.d.ts +18 -19
  438. package/dist/stdin.d.ts.map +1 -1
  439. package/dist/stdin.js +159 -157
  440. package/dist/stdin.js.map +1 -1
  441. package/dist/supervisor.d.ts +97 -0
  442. package/dist/supervisor.d.ts.map +1 -0
  443. package/dist/supervisor.js +194 -0
  444. package/dist/supervisor.js.map +1 -0
  445. package/dist/terminal-clipboard.d.ts +3 -0
  446. package/dist/terminal-clipboard.d.ts.map +1 -0
  447. package/dist/terminal-clipboard.js +24 -0
  448. package/dist/terminal-clipboard.js.map +1 -0
  449. package/dist/terminal-mouse.d.ts +24 -0
  450. package/dist/terminal-mouse.d.ts.map +1 -0
  451. package/dist/terminal-mouse.js +84 -0
  452. package/dist/terminal-mouse.js.map +1 -0
  453. package/dist/terminal-screen.d.ts +41 -0
  454. package/dist/terminal-screen.d.ts.map +1 -0
  455. package/dist/terminal-screen.js +228 -0
  456. package/dist/terminal-screen.js.map +1 -0
  457. package/dist/timeline-debug/harness.d.ts +79 -0
  458. package/dist/timeline-debug/harness.d.ts.map +1 -0
  459. package/dist/timeline-debug/harness.js +155 -0
  460. package/dist/timeline-debug/harness.js.map +1 -0
  461. package/dist/timeline-debug/index.d.ts +9 -0
  462. package/dist/timeline-debug/index.d.ts.map +1 -0
  463. package/dist/timeline-debug/index.js +9 -0
  464. package/dist/timeline-debug/index.js.map +1 -0
  465. package/dist/timeline-debug/interactions.d.ts +19 -0
  466. package/dist/timeline-debug/interactions.d.ts.map +1 -0
  467. package/dist/timeline-debug/interactions.js +17 -0
  468. package/dist/timeline-debug/interactions.js.map +1 -0
  469. package/dist/timeline-debug/target.d.ts +34 -0
  470. package/dist/timeline-debug/target.d.ts.map +1 -0
  471. package/dist/timeline-debug/target.js +132 -0
  472. package/dist/timeline-debug/target.js.map +1 -0
  473. package/dist/tool-format.d.ts +54 -0
  474. package/dist/tool-format.d.ts.map +1 -0
  475. package/dist/tool-format.js +360 -0
  476. package/dist/tool-format.js.map +1 -0
  477. package/dist/useExecutionState.d.ts.map +1 -1
  478. package/dist/useExecutionState.js +8 -4
  479. package/dist/useExecutionState.js.map +1 -1
  480. package/dist/validate/index.d.ts +28 -0
  481. package/dist/validate/index.d.ts.map +1 -0
  482. package/dist/validate/index.js +51 -0
  483. package/dist/validate/index.js.map +1 -0
  484. package/dist/websocket-client.d.ts +78 -15
  485. package/dist/websocket-client.d.ts.map +1 -1
  486. package/dist/websocket-client.js +497 -171
  487. package/dist/websocket-client.js.map +1 -1
  488. package/package.json +62 -31
package/dist/nodetool.js CHANGED
@@ -13,49 +13,107 @@
13
13
  * nodetool settings show
14
14
  */
15
15
  import { program } from "commander";
16
+ import { createRequire } from "node:module";
16
17
  import { fileURLToPath } from "node:url";
17
18
  import { dirname, resolve } from "node:path";
18
19
  import { spawnSync } from "node:child_process";
19
20
  import { createInterface } from "node:readline";
20
- import { createTRPCClient, httpBatchLink } from "@trpc/client";
21
- import superjson from "superjson";
22
21
  import { workflowToDsl } from "@nodetool-ai/dsl";
23
- import { initDb, Workflow, Secret, getSecret } from "@nodetool-ai/models";
24
- import { getDefaultDbPath } from "@nodetool-ai/config";
25
- import { WorkflowRunner } from "@nodetool-ai/kernel";
26
- import { NodeRegistry } from "@nodetool-ai/node-sdk";
22
+ import { initDb, Workflow, Asset, Secret, getSecret } from "@nodetool-ai/models";
23
+ import { readCachedHfModels, searchCachedHfModels } from "@nodetool-ai/huggingface";
24
+ import { initMasterKey } from "@nodetool-ai/security";
25
+ import { installLocalModelInterfaces } from "./local-model-interfaces.js";
26
+ import { getDefaultDbPath, getDefaultAssetsPath } from "@nodetool-ai/config";
27
+ import { ExecutionSession, isExecutionPreflightError } from "@nodetool-ai/execution";
28
+ import { NodeRegistry, createGraphNodeTypeResolver } from "@nodetool-ai/node-sdk";
27
29
  import { registerBaseNodes } from "@nodetool-ai/base-nodes";
28
30
  import { registerElevenLabsNodes } from "@nodetool-ai/elevenlabs-nodes";
31
+ import { registerMinimaxNodes } from "@nodetool-ai/minimax-nodes";
29
32
  import { registerTransformersJsNodes } from "@nodetool-ai/transformers-js-nodes";
30
33
  import { registerFalNodes } from "@nodetool-ai/fal-nodes";
31
34
  import { registerReplicateNodes } from "@nodetool-ai/replicate-nodes";
32
- import { ProcessingContext, initTelemetry } from "@nodetool-ai/runtime";
35
+ import { registerReveNodes } from "@nodetool-ai/reve-nodes";
36
+ import { registerHuggingFaceNodes } from "@nodetool-ai/huggingface-nodes";
37
+ import { ProcessingContext, createLocalWorkspace, initTelemetry, onPythonBridgeCreated } from "@nodetool-ai/runtime";
38
+ import { FileStorageAdapter } from "@nodetool-ai/storage";
39
+ import { mkdirSync } from "node:fs";
40
+ import { addSupervisorOptions, createSupervisorHandle, parseSupervisorFlags, printSupervisedSummary, recordSupervisorCost, streamInterventionLines } from "./supervisor.js";
33
41
  import { registerPackageCommands } from "./commands/package.js";
34
- import { registerDeployCommands, registerListGcpOptions } from "./commands/deploy.js";
42
+ import { registerPackCommands } from "./commands/packs.js";
43
+ import { registerDeployCommands } from "./commands/deploy.js";
35
44
  import { registerHfCommands } from "./commands/models-hf.js";
45
+ import { registerWorkerCommands } from "./commands/worker.js";
46
+ import { installWorkerActivityHeartbeat } from "@nodetool-ai/compute";
36
47
  import { registerRecommendedCommand } from "./commands/models-recommended.js";
37
48
  import { registerAgentCommands } from "./commands/agent.js";
49
+ import { registerDbCommands } from "./commands/db.js";
50
+ import { registerDebugCommands } from "./commands/debug.js";
51
+ import { registerAppCommands } from "./commands/app.js";
52
+ import { registerAppsCommands } from "./commands/apps.js";
53
+ import { registerValidateCommand } from "./commands/validate.js";
54
+ import { registerTimelineCommands } from "./commands/timeline.js";
55
+ import { registerSketchCommands } from "./commands/sketch.js";
56
+ import { registerJsScriptCommands } from "./commands/js-script.js";
57
+ import { registerReliabilityCommands } from "./commands/reliability.js";
58
+ import { registerNodeCommands } from "./commands/node.js";
59
+ import { registerGenerateCommand } from "./commands/generate.js";
60
+ import { registerEvalCommand } from "./commands/eval.js";
61
+ import { registerJtbdCommand } from "./commands/jtbd.js";
62
+ import { registerAffectedCommand } from "./commands/affected.js";
63
+ import { registerHarnessCommands } from "./commands/harness.js";
64
+ import { registerCollectionCommands } from "./commands/collections.js";
65
+ import { registerCostsCommands } from "./commands/costs.js";
66
+ import { registerGenerationsCommands } from "./commands/generations.js";
67
+ import { registerGameCommands } from "./commands/game.js";
68
+ import { registerAuthCommands } from "./commands/auth.js";
69
+ import { registerTelegramCommands } from "./commands/telegram.js";
70
+ import { registerResourceReadCommands } from "./commands/resource-read.js";
71
+ import { createApiClient } from "./api-client.js";
72
+ import { listAllModels, listConfiguredProviderInfo, listOllamaModels, listProviderModels } from "./providers.js";
73
+ import { isString } from "./predicates.js";
74
+ import { printTable, asJson } from "./commands/output.js";
75
+ import { printCommandError } from "./command-errors.js";
38
76
  const __filename = fileURLToPath(import.meta.url);
39
77
  const __dirname = dirname(__filename);
78
+ /**
79
+ * The CLI's own version, read from its package.json rather than repeated here.
80
+ * A literal drifts silently: it sat at "0.1.0" across every 0.7.0-rc release,
81
+ * so `nodetool --version` told users nothing about what they had installed.
82
+ */
83
+ const CLI_VERSION = createRequire(import.meta.url)("../package.json").version;
40
84
  // ---------------------------------------------------------------------------
41
85
  // DB setup (for secrets commands)
42
86
  // ---------------------------------------------------------------------------
43
- async function setupDb() {
87
+ // The local single-user id every direct-DB command runs as, matching the
88
+ // `workflows run` / `secrets` commands and the stdio MCP server.
89
+ import { resolveLocalSecret } from "./local-secrets.js";
90
+ const LOCAL_USER_ID = "1";
91
+ // Open the local SQLite database for a read-only command. Unlike setupDb() this
92
+ // skips master-key unlocking (no secret decryption needed to list/read rows),
93
+ // so it never emits a keychain warning. Idempotent — initDb() is a no-op once
94
+ // a connection is open.
95
+ function ensureDb() {
44
96
  initDb(getDefaultDbPath());
45
97
  }
98
+ async function setupDb() {
99
+ ensureDb();
100
+ // Resolve the master encryption key from keychain / env / AWS so that
101
+ // both encryption (Secret.upsert) and decryption (Secret.getDecryptedValue)
102
+ // use the same persistent key. Without this, a fresh process would
103
+ // auto-generate a one-shot key inside `getMasterKey()`, encrypt with it,
104
+ // then lose it on exit — and the next launch could not decrypt.
105
+ try {
106
+ await initMasterKey();
107
+ }
108
+ catch (err) {
109
+ const msg = err instanceof Error ? err.message : String(err);
110
+ process.stderr.write(`Could not unlock the secret store: ${msg}\n` +
111
+ `Tip: set SECRETS_MASTER_KEY or grant keychain access.\n`);
112
+ }
113
+ }
46
114
  // ---------------------------------------------------------------------------
47
115
  // API clients
48
116
  // ---------------------------------------------------------------------------
49
- function createApiClient(apiUrl) {
50
- return createTRPCClient({
51
- links: [
52
- httpBatchLink({
53
- url: `${apiUrl}/trpc`,
54
- transformer: superjson
55
- })
56
- ]
57
- });
58
- }
59
117
  // REST GET (text) — used for the DSL export endpoint which stays REST
60
118
  // because it returns a TypeScript source string rather than JSON.
61
119
  async function apiGetText(apiUrl, path) {
@@ -64,28 +122,105 @@ async function apiGetText(apiUrl, path) {
64
122
  throw new Error(`HTTP ${res.status}: ${await res.text()}`);
65
123
  return res.text();
66
124
  }
67
- // ---------------------------------------------------------------------------
68
- // Table printer
69
- // ---------------------------------------------------------------------------
70
- function printTable(rows, columns) {
71
- if (rows.length === 0) {
72
- console.log("(no results)");
73
- return;
125
+ // This CLI's package version, stamped into exported bundle manifests.
126
+ function cliVersion() {
127
+ try {
128
+ const req = createRequire(import.meta.url);
129
+ return req("../package.json").version;
74
130
  }
75
- const cols = columns ?? Object.keys(rows[0]);
76
- const widths = cols.map((c) => Math.max(c.length, ...rows.map((r) => String(r[c] ?? "").length)));
77
- const sep = widths.map((w) => "─".repeat(w + 2)).join("┼");
78
- const header = cols.map((c, i) => ` ${c.padEnd(widths[i])} `).join("│");
79
- console.log(header);
80
- console.log(sep);
81
- for (const row of rows) {
82
- console.log(cols
83
- .map((c, i) => ` ${String(row[c] ?? "").padEnd(widths[i])} `)
84
- .join("│"));
131
+ catch {
132
+ // Version is best-effort metadata; omit it if the file can't be read.
133
+ return undefined;
85
134
  }
86
135
  }
87
- function asJson(data) {
88
- console.log(JSON.stringify(data, null, 2));
136
+ // Download asset bytes from a running server, used by the export commands to
137
+ // resolve `asset://` / `/api/storage/` (and optionally http) refs into bytes.
138
+ function makeAssetFetcher(apiUrl) {
139
+ return async (ref) => {
140
+ let url = null;
141
+ if (ref.startsWith("asset://")) {
142
+ const id = ref.slice("asset://".length);
143
+ const bareId = id.replace(/\.[^.]+$/, "");
144
+ try {
145
+ const meta = await fetch(`${apiUrl}/api/assets/${encodeURIComponent(bareId)}`);
146
+ if (meta.ok) {
147
+ const j = (await meta.json());
148
+ if (j.get_url) {
149
+ url = j.get_url.startsWith("/")
150
+ ? `${apiUrl}${j.get_url}`
151
+ : j.get_url;
152
+ }
153
+ }
154
+ }
155
+ catch {
156
+ // Metadata lookup failed — fall back to the storage route below.
157
+ }
158
+ url ??= `${apiUrl}/api/storage/${encodeURIComponent(id)}`;
159
+ }
160
+ else if (ref.includes("/api/storage/")) {
161
+ url = /^https?:\/\//.test(ref)
162
+ ? ref
163
+ : `${apiUrl}${ref.startsWith("/") ? ref : `/${ref}`}`;
164
+ }
165
+ else if (/^https?:\/\//.test(ref)) {
166
+ url = ref;
167
+ }
168
+ if (!url)
169
+ return null;
170
+ const res = await fetch(url);
171
+ if (!res.ok)
172
+ return null;
173
+ return new Uint8Array(await res.arrayBuffer());
174
+ };
175
+ }
176
+ // Resolve asset bytes from the local assets directory, so the export commands
177
+ // work by id without a running server. `asset://<key>` is tried verbatim as a
178
+ // storage key first (that's how import-bundle writes refs), then via the DB
179
+ // record to derive `<id>.<ext>` from the content type. Remote http(s) refs
180
+ // still fetch over the network.
181
+ async function makeLocalAssetFetcher() {
182
+ const { getAssetFileName } = await import("@nodetool-ai/websocket");
183
+ const storage = new FileStorageAdapter(getDefaultAssetsPath());
184
+ return async (ref) => {
185
+ if (ref.startsWith("asset://")) {
186
+ const raw = ref.slice("asset://".length);
187
+ const direct = await storage.retrieve(`/api/storage/${raw}`);
188
+ if (direct)
189
+ return direct;
190
+ const bareId = raw.replace(/\.[^.]+$/, "");
191
+ const asset = await Asset.find(LOCAL_USER_ID, bareId);
192
+ if (!asset)
193
+ return null;
194
+ const key = getAssetFileName(asset.id, asset.content_type);
195
+ return storage.retrieve(`/api/storage/${key}`);
196
+ }
197
+ if (ref.includes("/api/storage/")) {
198
+ const local = await storage.retrieve(ref);
199
+ if (local)
200
+ return local;
201
+ }
202
+ if (/^https?:\/\//.test(ref)) {
203
+ const res = await fetch(ref);
204
+ if (!res.ok)
205
+ return null;
206
+ return new Uint8Array(await res.arrayBuffer());
207
+ }
208
+ return null;
209
+ };
210
+ }
211
+ // Asset and timeline persistence for every context any command builds, here
212
+ // rather than per-entrance: `debug` wired none while `workflows run` wired
213
+ // four, so one workflow saved an image under one command and threw under the
214
+ // other. The interfaces touch the database only when a node calls them, so
215
+ // installing them before `setupDb()` is safe.
216
+ await installLocalModelInterfaces();
217
+ /**
218
+ * What to print when a run command fails. A preflight refusal already reads as
219
+ * a complete explanation — printing the error class in front of it only buries
220
+ * the secret name the user has to go set.
221
+ */
222
+ function describeRunFailure(error) {
223
+ return isExecutionPreflightError(error) ? error.message : String(error);
89
224
  }
90
225
  // ---------------------------------------------------------------------------
91
226
  // info
@@ -93,11 +228,18 @@ function asJson(data) {
93
228
  program
94
229
  .name("nodetool")
95
230
  .description("NodeTool CLI")
96
- .version("0.1.0")
231
+ .version(CLI_VERSION)
97
232
  .option("--trace-file <path>", "Append every LLM/agent/workflow span as JSONL to <path>")
98
233
  .option("--trace-stdout [format]", "Stream spans to stdout: 'pretty' (default) or 'json' (JSONL)")
99
234
  .option("--no-trace-stdout", "Disable stdout span output (overrides NODETOOL_TRACE_STDOUT)")
100
- .hook("preAction", async (thisCommand) => {
235
+ .hook("preAction", async (thisCommand, actionCommand) => {
236
+ // With `--trace`, the `debug` command owns telemetry: it routes spans into
237
+ // its bundle's trace.jsonl via its own initTelemetry call. Initializing here
238
+ // first would win the one-shot init and drop that file sink, so skip it.
239
+ // Without `--trace`, fall through so the global --trace-file/--trace-stdout
240
+ // flags still work for a debug run.
241
+ if (actionCommand?.name() === "debug" && actionCommand.opts()["trace"])
242
+ return;
101
243
  const opts = thisCommand.opts();
102
244
  await initTelemetry({
103
245
  ...(opts.traceFile && { traceFile: opts.traceFile }),
@@ -111,7 +253,7 @@ function parseTraceStdout(v) {
111
253
  return false;
112
254
  if (v === true)
113
255
  return "pretty";
114
- if (typeof v === "string") {
256
+ if (isString(v)) {
115
257
  const lower = v.toLowerCase();
116
258
  if (lower === "false" || lower === "0" || lower === "no")
117
259
  return false;
@@ -125,33 +267,49 @@ function parseTraceStdout(v) {
125
267
  // ---------------------------------------------------------------------------
126
268
  // run — execute a TypeScript/JavaScript DSL workflow file
127
269
  // ---------------------------------------------------------------------------
128
- program
270
+ addSupervisorOptions(program
129
271
  .command("run <dsl-file>")
130
272
  .description("Run a TypeScript/JavaScript DSL workflow file")
131
- .option("--json", "Output results as JSON (default: pretty-print)")
132
- .action(async (dslFile, opts) => {
273
+ .option("--json", "Output results as JSON (default: pretty-print)")).action(async (dslFile, opts) => {
133
274
  try {
134
275
  const { resolve } = await import("node:path");
135
276
  const { runDslFile } = await import("./run-dsl.js");
136
277
  const { registerBaseNodes } = await import("@nodetool-ai/base-nodes");
137
278
  const { NodeRegistry } = await import("@nodetool-ai/node-sdk");
138
279
  registerBaseNodes(NodeRegistry.global);
280
+ const supervisorConfig = parseSupervisorFlags(opts);
139
281
  const absolutePath = resolve(dslFile);
140
- const results = await runDslFile(absolutePath);
282
+ let results;
283
+ let interventions = [];
284
+ if (supervisorConfig) {
285
+ // The supervisor's provider key comes from the secret store, and its
286
+ // spend is written to the local ledger — both need the DB.
287
+ await setupDb();
288
+ const { runDslFileSupervised } = await import("./run-dsl-supervised.js");
289
+ const run = await runDslFileSupervised(absolutePath, supervisorConfig, opts.json === true);
290
+ results = run.results;
291
+ interventions = run.interventions;
292
+ }
293
+ else {
294
+ results = await runDslFile(absolutePath);
295
+ }
296
+ const { printRunJson, previewJson } = await import("./run-json.js");
141
297
  if (opts.json) {
142
- console.log(JSON.stringify(results, null, 2));
298
+ // A supervised run reports what the supervisor did alongside the
299
+ // outputs; an unsupervised one keeps the bare results shape.
300
+ await printRunJson(supervisorConfig ? { results, interventions } : results);
143
301
  }
144
302
  else {
145
303
  for (const [workflowName, outputs] of Object.entries(results)) {
146
304
  console.log(`\n${workflowName}:`);
147
305
  for (const [key, value] of Object.entries(outputs)) {
148
- console.log(` ${key}: ${JSON.stringify(value)}`);
306
+ console.log(` ${key}: ${previewJson(value)}`);
149
307
  }
150
308
  }
151
309
  }
152
310
  }
153
311
  catch (e) {
154
- console.error(String(e));
312
+ console.error(describeRunFailure(e));
155
313
  process.exit(1);
156
314
  }
157
315
  });
@@ -171,7 +329,7 @@ program
171
329
  "HF_TOKEN"
172
330
  ];
173
331
  const data = {
174
- version: "0.1.0",
332
+ version: CLI_VERSION,
175
333
  node_version: process.version,
176
334
  platform: process.platform,
177
335
  arch: process.arch,
@@ -224,7 +382,8 @@ program
224
382
  // ---------------------------------------------------------------------------
225
383
  program
226
384
  .command("chat")
227
- .description("Start interactive chat (TUI)")
385
+ .description("Start fullscreen chat")
386
+ .helpOption(false)
228
387
  .option("-p, --provider <provider>", "LLM provider")
229
388
  .option("-m, --model <model>", "Model ID")
230
389
  .option("-a, --agent", "Agent mode")
@@ -233,17 +392,17 @@ program
233
392
  .option("--tools <tools>", "Comma-separated enabled tools")
234
393
  .allowUnknownOption()
235
394
  .action((_opts, cmd) => {
236
- const chatPath = resolve(__dirname, "index.js");
395
+ const chatPath = resolve(__dirname, import.meta.url.endsWith(".ts") ? "index.ts" : "index.js");
237
396
  const args = cmd.args;
238
397
  const rawArgs = process.argv;
239
398
  // Re-run with the chat entry point, forwarding all flags after "chat"
240
399
  const chatIdx = rawArgs.indexOf("chat");
241
400
  const forwarded = chatIdx >= 0 ? rawArgs.slice(chatIdx + 1) : args;
242
- const result = spawnSync("node", [chatPath, ...forwarded], {
401
+ const result = spawnSync(process.execPath, [...process.execArgv, chatPath, ...forwarded], {
243
402
  stdio: "inherit",
244
403
  env: { ...process.env }
245
404
  });
246
- process.exit(result.status ?? 0);
405
+ process.exit(result.status ?? 1);
247
406
  });
248
407
  // ---------------------------------------------------------------------------
249
408
  // workflows
@@ -251,86 +410,56 @@ program
251
410
  const workflows = program
252
411
  .command("workflows")
253
412
  .description("Workflow management");
254
- workflows
255
- .command("list")
256
- .description("List workflows")
257
- .option("--api-url <url>", "API base URL", process.env["NODETOOL_API_URL"] ?? "http://localhost:7777")
258
- .option("--limit <n>", "Max results", "100")
259
- .option("--json", "Output as JSON")
260
- .action(async (opts) => {
261
- try {
262
- const client = createApiClient(opts.apiUrl);
263
- const data = await client.workflows.list.query({
264
- limit: Number.parseInt(opts.limit, 10)
265
- });
266
- const rows = data.workflows;
267
- if (opts.json) {
268
- asJson(rows);
269
- return;
270
- }
271
- printTable(rows.map((r) => ({
272
- id: r["id"],
273
- name: r["name"],
274
- updated_at: r["updated_at"]
275
- })));
276
- }
277
- catch (e) {
278
- console.error(String(e));
279
- process.exit(1);
280
- }
281
- });
282
- workflows
283
- .command("get <workflow_id>")
284
- .description("Get a workflow by ID")
285
- .option("--api-url <url>", "API base URL", process.env["NODETOOL_API_URL"] ?? "http://localhost:7777")
286
- .option("--json", "Output as JSON")
287
- .action(async (workflowId, opts) => {
288
- try {
289
- const client = createApiClient(opts.apiUrl);
290
- const data = await client.workflows.get.query({ id: workflowId });
291
- if (opts.json) {
292
- asJson(data);
293
- return;
294
- }
295
- const w = data;
296
- printTable([
297
- {
298
- id: w["id"],
299
- name: w["name"],
300
- description: w["description"],
301
- updated_at: w["updated_at"]
302
- }
303
- ]);
304
- }
305
- catch (e) {
306
- console.error(String(e));
307
- process.exit(1);
308
- }
309
- });
310
- workflows
413
+ addSupervisorOptions(workflows
311
414
  .command("run <workflow_id_or_file>")
312
415
  .description("Run a workflow by ID, JSON file, or TypeScript DSL file")
313
416
  .option("--params <json>", "JSON params string")
314
417
  .option("--json", "Output as JSON")
315
- .action(async (idOrFile, opts) => {
418
+ .option("--asset-output-mode <mode>", "How media outputs are materialized: native | raw | data_uri | workspace | storage_url | temp_url", "native")
419
+ .option("--workspace <dir>", "Workspace directory for workspace-mode asset output (default: ./nodetool-output)")
420
+ .option("--trigger-event <json>", 'Wake a trigger node as the scheduler/webhook adapter would: \'{"node_id":"watch","payload":{"path":"/tmp/a.csv","event":"created"}}\'. ' +
421
+ "Without it a webhook, file-watch or manual trigger has no event to " +
422
+ "emit and the run stalls until its timeout — so this is the only way " +
423
+ "to exercise a trigger-driven workflow from the CLI.")).action(async (idOrFile, opts) => {
316
424
  try {
425
+ const supervisorConfig = parseSupervisorFlags(opts);
317
426
  await setupDb();
318
427
  let graph;
319
428
  let workflowId = null;
320
429
  const params = opts.params
321
430
  ? JSON.parse(opts.params)
322
431
  : {};
432
+ // A trigger node emits from `emitTriggerEvent`, not `genProcess`, and
433
+ // only when the run carries an event addressed to it. The kernel has
434
+ // always accepted one (`RunJobRequest.trigger_event`); nothing on the
435
+ // CLI could supply it, so a webhook or file-watch workflow could be
436
+ // validated but never executed. `input_id` defaults because every
437
+ // caller would otherwise invent the same throwaway id.
438
+ const triggerEvent = opts.triggerEvent
439
+ ? (() => {
440
+ const parsed = JSON.parse(opts.triggerEvent);
441
+ if (!parsed.node_id) {
442
+ throw new Error('--trigger-event needs a "node_id" naming the trigger node to wake.');
443
+ }
444
+ return {
445
+ node_id: parsed.node_id,
446
+ payload: parsed.payload ?? {},
447
+ input_id: parsed.input_id ?? `cli-${Date.now()}`
448
+ };
449
+ })()
450
+ : null;
323
451
  // Determine if argument is a file path or workflow ID
324
452
  if (idOrFile.endsWith(".json") ||
325
453
  idOrFile.endsWith(".ts") ||
326
454
  idOrFile.endsWith(".tsx") ||
327
455
  idOrFile.includes("/") ||
328
456
  idOrFile.includes("\\")) {
457
+ /** A DSL/JSON workflow file: the graph, optionally wrapped. */
329
458
  let raw;
330
459
  if (idOrFile.endsWith(".ts") || idOrFile.endsWith(".tsx")) {
331
460
  // Execute DSL file via tsx and capture JSON output
332
- const { execSync } = await import("node:child_process");
333
- const output = execSync(`npx tsx "${resolve(idOrFile)}"`, {
461
+ const { execFileSync } = await import("node:child_process");
462
+ const output = execFileSync("npx", ["tsx", resolve(idOrFile)], {
334
463
  encoding: "utf8",
335
464
  cwd: dirname(resolve(idOrFile)),
336
465
  timeout: 30000
@@ -347,7 +476,6 @@ workflows
347
476
  Object.assign(params, raw.params);
348
477
  }
349
478
  else {
350
- // Load from database
351
479
  const wf = await Workflow.get(idOrFile);
352
480
  if (!wf)
353
481
  throw new Error(`Workflow not found: ${idOrFile}`);
@@ -357,42 +485,132 @@ workflows
357
485
  if (!graph?.nodes || !graph?.edges) {
358
486
  throw new Error("Invalid workflow: missing nodes or edges");
359
487
  }
360
- // Normalize graph: convert node.data → node.properties (kernel format)
361
- graph.nodes = graph.nodes.map((n) => {
362
- if (n.properties === undefined && n.data !== undefined) {
363
- const { data, ...rest } = n;
364
- return { ...rest, properties: data };
365
- }
366
- return n;
367
- });
368
- // Set up node registry
488
+ // Editor-only nodes (Comment, Group, Reroute) and the data→properties
489
+ // rename are handled by `ExecutionSession.create` below, which runs
490
+ // the graph through `normalizeGraph` (@nodetool-ai/execution) — no
491
+ // need to duplicate that here.
369
492
  const registry = new NodeRegistry();
370
493
  registerBaseNodes(registry);
371
494
  registerElevenLabsNodes(registry);
495
+ registerMinimaxNodes(registry);
372
496
  registerTransformersJsNodes(registry);
373
497
  registerFalNodes(registry);
374
498
  registerReplicateNodes(registry);
375
- // Create processing context with secret resolver
499
+ registerReveNodes(registry);
500
+ registerHuggingFaceNodes(registry);
376
501
  const jobId = `job-${Date.now()}`;
502
+ // Resolve asset URIs (e.g. /api/storage/<key>) against the local
503
+ // assets directory, so workflows referencing stored assets run the
504
+ // same decode path the server does.
505
+ // Apply the workflow's assigned workspace (if any) so file ops and
506
+ // workspace-driving nodes land in the same directory as a server run.
507
+ const { resolveWorkflowWorkspace } = await import("@nodetool-ai/websocket");
508
+ const assignedWorkspace = workflowId
509
+ ? await resolveWorkflowWorkspace(workflowId, "1")
510
+ : null;
511
+ const ASSET_OUTPUT_MODES = [
512
+ "native",
513
+ "raw",
514
+ "data_uri",
515
+ "workspace",
516
+ "storage_url",
517
+ "temp_url"
518
+ ];
519
+ const assetOutputMode = (opts.assetOutputMode ??
520
+ "native");
521
+ if (!ASSET_OUTPUT_MODES.includes(assetOutputMode)) {
522
+ throw new Error(`Unknown --asset-output-mode "${assetOutputMode}". ` +
523
+ `Expected one of: ${ASSET_OUTPUT_MODES.join(", ")}`);
524
+ }
525
+ // `--workspace <dir>` wins, then whatever the workflow is assigned.
526
+ // `workspace` asset mode writes each output into <workspace>/assets, so
527
+ // it needs somewhere to write even when the run has no saved workflow (a
528
+ // JSON or DSL file target). Fall back to ./nodetool-output so a bare
529
+ // `workflows run file.json --asset-output-mode workspace` produces files
530
+ // in the current directory rather than failing.
531
+ const overrideWorkspaceDir = opts.workspace ??
532
+ (assignedWorkspace
533
+ ? null
534
+ : assetOutputMode === "workspace"
535
+ ? resolve(process.cwd(), "nodetool-output")
536
+ : null);
537
+ if (overrideWorkspaceDir) {
538
+ mkdirSync(overrideWorkspaceDir, { recursive: true });
539
+ }
540
+ const runWorkspace = overrideWorkspaceDir
541
+ ? createLocalWorkspace(overrideWorkspaceDir)
542
+ : assignedWorkspace;
543
+ const assetStorage = new FileStorageAdapter(getDefaultAssetsPath());
377
544
  const context = new ProcessingContext({
378
545
  jobId,
379
546
  workflowId,
380
547
  userId: "1",
381
- secretResolver: getSecret
382
- });
383
- // Run workflow
384
- const runner = new WorkflowRunner(jobId, {
385
- resolveExecutor: (node) => {
386
- if (!registry.has(node.type))
387
- throw new Error(`Unknown node type: ${node.type}`);
388
- return registry.resolve(node);
389
- },
390
- executionContext: context
548
+ secretResolver: resolveLocalSecret,
549
+ storage: assetStorage,
550
+ assetOutputMode,
551
+ workspace: runWorkspace
391
552
  });
392
- console.error(`Running workflow${workflowId ? ` ${workflowId}` : ""}...`);
393
- const result = await runner.run({ job_id: jobId, workflow_id: workflowId ?? undefined, params }, graph);
553
+ const supervisor = supervisorConfig
554
+ ? await createSupervisorHandle({
555
+ config: supervisorConfig,
556
+ context
557
+ })
558
+ : null;
559
+ console.error(`Running workflow${workflowId ? ` ${workflowId}` : ""}` +
560
+ (supervisor
561
+ ? ` supervised by ${supervisor.providerId}/${supervisor.model}`
562
+ : "") +
563
+ "...");
564
+ // ExecutionSession owns graph hydration, Python-bridge connection
565
+ // (NODETOOL_WORKER_URL/NODETOOL_WORKER_TOKEN → remote worker; unset →
566
+ // local stdio worker; pure-TS graphs get none), and executor
567
+ // resolution (registry → Python bridge → throw).
568
+ const sessionOptions = {
569
+ graph,
570
+ registry,
571
+ // Registry alone hydrates node flags but not `propertyTypes`, and
572
+ // correlation analysis reads list-ness only from that map — so a
573
+ // saved workflow (which never carries it) had every list handle
574
+ // read as non-list, and legal fan-in into one was rejected before
575
+ // any node ran. The resolver fills it from node metadata.
576
+ resolveNodeType: createGraphNodeTypeResolver(registry).resolveNodeType,
577
+ jobId,
578
+ workflowId,
579
+ params,
580
+ context
581
+ };
582
+ if (triggerEvent) {
583
+ sessionOptions.triggerEvent = triggerEvent;
584
+ }
585
+ // Message capture is retention, so it stays off unless a supervised
586
+ // run needs the stream to print its `⛨` lines as they happen.
587
+ if (supervisor) {
588
+ sessionOptions.supervisor = supervisor.handle;
589
+ sessionOptions.captureMessages = true;
590
+ }
591
+ const session = await ExecutionSession.create(sessionOptions);
592
+ const interventionLines = supervisor
593
+ ? streamInterventionLines(session.messages)
594
+ : Promise.resolve();
595
+ const result = await session.result;
596
+ await interventionLines;
597
+ supervisor?.handle.close();
598
+ const interventions = result.interventions ?? [];
599
+ if (supervisor && interventions.length > 0) {
600
+ await recordSupervisorCost({
601
+ interventions,
602
+ jobId,
603
+ workflowId,
604
+ userId: "1",
605
+ providerId: supervisor.providerId,
606
+ model: supervisor.model
607
+ });
608
+ }
609
+ const { printRunJson, previewJson } = await import("./run-json.js");
394
610
  if (opts.json) {
395
- console.log(JSON.stringify(result, null, 2));
611
+ await printRunJson(result, {
612
+ outputDir: resolve(process.cwd(), "nodetool-output", jobId)
613
+ });
396
614
  }
397
615
  else {
398
616
  console.log(`Status: ${result.status}`);
@@ -402,22 +620,23 @@ workflows
402
620
  if (Array.isArray(outputs) && outputs.length > 0) {
403
621
  console.log(`\nNode ${nodeId}:`);
404
622
  for (const out of outputs) {
405
- console.log(` ${JSON.stringify(out).slice(0, 200)}`);
623
+ console.log(` ${previewJson(out, 200)}`);
406
624
  }
407
625
  }
408
626
  }
627
+ printSupervisedSummary(interventions);
409
628
  }
410
629
  process.exit(result.status === "completed" ? 0 : 1);
411
630
  }
412
631
  catch (e) {
413
- console.error(String(e));
632
+ console.error(describeRunFailure(e));
414
633
  process.exit(1);
415
634
  }
416
635
  });
417
636
  workflows
418
637
  .command("export-dsl <workflow_id_or_file>")
419
- .description("Export a workflow as TypeScript DSL code")
420
- .option("--api-url <url>", "API base URL", process.env["NODETOOL_API_URL"] ?? "http://localhost:7777")
638
+ .description("Export a workflow as TypeScript DSL code (local DB by id; --api-url for remote)")
639
+ .option("--api-url <url>", "Fetch the workflow from a remote server instead of the local database", process.env["NODETOOL_API_URL"])
421
640
  .option("-o, --output <file>", "Write the exported DSL to a file")
422
641
  .action(async (idOrFile, opts) => {
423
642
  try {
@@ -429,12 +648,22 @@ workflows
429
648
  const raw = JSON.parse(readFileSync(idOrFile, "utf8"));
430
649
  const graph = (raw.graph ?? raw);
431
650
  source = workflowToDsl(graph, {
432
- workflowName: typeof raw.name === "string" ? raw.name : null
651
+ workflowName: isString(raw.name) ? raw.name : null
433
652
  });
434
653
  }
435
- else {
654
+ else if (opts.apiUrl) {
436
655
  source = await apiGetText(opts.apiUrl, `/api/workflows/${idOrFile}/dsl-export`);
437
656
  }
657
+ else {
658
+ ensureDb();
659
+ const wf = await Workflow.find(LOCAL_USER_ID, idOrFile);
660
+ if (!wf)
661
+ throw new Error(`Workflow not found: ${idOrFile}`);
662
+ const graph = wf.getGraph();
663
+ source = workflowToDsl(graph, {
664
+ workflowName: isString(wf.name) ? wf.name : null
665
+ });
666
+ }
438
667
  if (opts.output) {
439
668
  const { writeFile } = await import("node:fs/promises");
440
669
  await writeFile(opts.output, source, "utf8");
@@ -444,157 +673,275 @@ workflows
444
673
  console.log(source);
445
674
  }
446
675
  catch (e) {
447
- console.error(String(e));
676
+ printCommandError(e);
448
677
  process.exit(1);
449
678
  }
450
679
  });
451
- // ---------------------------------------------------------------------------
452
- // jobs
453
- // ---------------------------------------------------------------------------
454
- const jobs = program.command("jobs").description("Job management");
455
- jobs
456
- .command("list")
457
- .description("List jobs")
458
- .option("--api-url <url>", "API base URL", process.env["NODETOOL_API_URL"] ?? "http://localhost:7777")
459
- .option("--workflow-id <id>", "Filter by workflow ID")
460
- .option("--limit <n>", "Max results", "100")
461
- .option("--json", "Output as JSON")
462
- .action(async (opts) => {
680
+ workflows
681
+ .command("export-example <workflow_id_or_file>")
682
+ .description("Export a workflow as a shipped template: materialize its assets into the " +
683
+ "package's constant asset dir (package:// refs) and write the example JSON")
684
+ .option("--api-url <url>", "Fetch the workflow and asset bytes from a remote server instead of the local DB/assets", process.env["NODETOOL_API_URL"])
685
+ .option("--package <name>", "Owning package", "nodetool-base")
686
+ .option("--assets-dir <dir>", "Root holding <package>/<file> constant assets (defaults to the monorepo base-nodes assets dir)")
687
+ .option("--examples-dir <dir>", "Directory the example JSON is written under, as <dir>/<package>/<name>.json")
688
+ .option("-o, --output <file>", "Write the example JSON to this exact path")
689
+ .option("--include-remote", "Also materialize http(s) and local-file refs (off by default)")
690
+ .action(async (idOrFile, opts) => {
463
691
  try {
464
- const client = createApiClient(opts.apiUrl);
465
- const data = await client.jobs.list.query({
466
- limit: Number.parseInt(opts.limit, 10),
467
- ...(opts.workflowId ? { workflow_id: opts.workflowId } : {})
468
- });
469
- const rows = data.jobs;
470
- if (opts.json) {
471
- asJson(rows);
472
- return;
692
+ const { readFileSync } = await import("node:fs");
693
+ const { mkdir, writeFile } = await import("node:fs/promises");
694
+ const { join } = await import("node:path");
695
+ const { materializeWorkflowConstantAssets } = await import("@nodetool-ai/websocket");
696
+ let name = "";
697
+ let description = "";
698
+ let tags = [];
699
+ let graph;
700
+ const isFile = idOrFile.endsWith(".json") ||
701
+ idOrFile.includes("/") ||
702
+ idOrFile.includes("\\");
703
+ if (isFile) {
704
+ const raw = JSON.parse(readFileSync(idOrFile, "utf8"));
705
+ name = isString(raw.name) ? raw.name : "workflow";
706
+ description =
707
+ isString(raw.description) ? raw.description : "";
708
+ tags = Array.isArray(raw.tags)
709
+ ? raw.tags.filter((t) => typeof t === "string")
710
+ : [];
711
+ graph = (raw.graph ?? raw);
473
712
  }
474
- printTable(rows.map((r) => ({
475
- id: r["id"],
476
- status: r["status"],
477
- workflow_id: r["workflow_id"],
478
- started_at: r["started_at"]
479
- })));
480
- }
481
- catch (e) {
482
- console.error(String(e));
483
- process.exit(1);
484
- }
485
- });
486
- jobs
487
- .command("get <job_id>")
488
- .description("Get a job by ID")
489
- .option("--api-url <url>", "API base URL", process.env["NODETOOL_API_URL"] ?? "http://localhost:7777")
490
- .option("--json", "Output as JSON")
491
- .action(async (jobId, opts) => {
492
- try {
493
- const client = createApiClient(opts.apiUrl);
494
- const data = await client.jobs.get.query({ id: jobId });
495
- if (opts.json) {
496
- asJson(data);
497
- return;
713
+ else if (opts.apiUrl) {
714
+ const client = createApiClient(opts.apiUrl);
715
+ const wf = (await client.workflows.get.query({
716
+ id: idOrFile
717
+ }));
718
+ name = isString(wf.name) ? wf.name : "workflow";
719
+ description =
720
+ isString(wf.description) ? wf.description : "";
721
+ tags = Array.isArray(wf.tags)
722
+ ? wf.tags.filter((t) => typeof t === "string")
723
+ : [];
724
+ graph = wf.graph;
498
725
  }
499
- const j = data;
500
- printTable([
501
- {
502
- id: j["id"],
503
- status: j["status"],
504
- workflow_id: j["workflow_id"],
505
- error: j["error"] ?? ""
506
- }
507
- ]);
726
+ else {
727
+ ensureDb();
728
+ const wf = await Workflow.find(LOCAL_USER_ID, idOrFile);
729
+ if (!wf)
730
+ throw new Error(`Workflow not found: ${idOrFile}`);
731
+ name = isString(wf.name) ? wf.name : "workflow";
732
+ description =
733
+ isString(wf.description) ? wf.description : "";
734
+ tags = Array.isArray(wf.tags)
735
+ ? wf.tags.filter((t) => typeof t === "string")
736
+ : [];
737
+ graph = wf.getGraph();
738
+ }
739
+ if (!graph?.nodes) {
740
+ throw new Error("Workflow has no graph to export");
741
+ }
742
+ const repoRoot = resolve(__dirname, "..", "..", "..");
743
+ const baseNodesDir = join(repoRoot, "packages", "base-nodes", "nodetool");
744
+ const assetsRoot = opts.assetsDir ?? join(baseNodesDir, "assets");
745
+ const examplesDir = opts.examplesDir ?? join(baseNodesDir, "examples");
746
+ const fetchAssetBytes = opts.apiUrl
747
+ ? makeAssetFetcher(opts.apiUrl.replace(/\/+$/, ""))
748
+ : await makeLocalAssetFetcher();
749
+ const materializeOptions = {
750
+ packageName: opts.package,
751
+ assetsRoot,
752
+ fetchAssetBytes
753
+ };
754
+ if (opts.includeRemote) {
755
+ materializeOptions.includeRemote = true;
756
+ }
757
+ const result = await materializeWorkflowConstantAssets(graph, materializeOptions);
758
+ const slug = name
759
+ .toLowerCase()
760
+ .replace(/[^a-z0-9]+/g, "-")
761
+ .replace(/^-+|-+$/g, "");
762
+ const example = {
763
+ id: slug || "workflow",
764
+ access: "public",
765
+ name,
766
+ description,
767
+ tags,
768
+ package_name: opts.package,
769
+ graph: result.graph
770
+ };
771
+ // Sanitize the on-disk filename separately from the display name so
772
+ // names with path separators can't escape the examples directory.
773
+ const safeFileName = name.replace(/[^A-Za-z0-9._-]+/g, "_").replace(/^[._]+/, "") ||
774
+ "workflow";
775
+ const outPath = opts.output ??
776
+ join(examplesDir, opts.package, `${safeFileName}.json`);
777
+ await mkdir(dirname(outPath), { recursive: true });
778
+ await writeFile(outPath, JSON.stringify(example, null, 2) + "\n", "utf8");
779
+ for (const a of result.exported) {
780
+ console.error(` asset ${a.source} → ${a.packageUri} (${a.byteLength} bytes)`);
781
+ }
782
+ for (const s of result.skipped) {
783
+ console.error(` warning: could not resolve asset ${s} (left as-is)`);
784
+ }
785
+ console.log(outPath);
508
786
  }
509
787
  catch (e) {
510
- console.error(String(e));
788
+ printCommandError(e);
511
789
  process.exit(1);
512
790
  }
513
791
  });
514
- // ---------------------------------------------------------------------------
515
- // assets
516
- // ---------------------------------------------------------------------------
517
- const assets = program.command("assets").description("Asset management");
518
- assets
519
- .command("list")
520
- .description("List assets")
521
- .option("--api-url <url>", "API base URL", process.env["NODETOOL_API_URL"] ?? "http://localhost:7777")
522
- .option("--query <q>", "Search query")
523
- .option("--content-type <type>", "Filter by content type")
524
- .option("--limit <n>", "Max results", "100")
525
- .option("--json", "Output as JSON")
526
- .action(async (opts) => {
792
+ workflows
793
+ .command("export-bundle <workflow_id_or_file...>")
794
+ .description("Export one or more workflows as a portable .nodetool bundle (zip): the " +
795
+ "graphs plus the bytes of every asset they reference, in a single file")
796
+ .option("--api-url <url>", "Fetch the workflow and asset bytes from a remote server instead of the local DB/assets", process.env["NODETOOL_API_URL"])
797
+ .option("-o, --output <file>", "Output path (default: <name>.nodetool)")
798
+ .option("--include-remote", "Also embed http(s) and local-file refs (off by default)")
799
+ .action(async (idsOrFiles, opts) => {
527
800
  try {
528
- const client = createApiClient(opts.apiUrl);
529
- const data = await client.assets.list.query({
530
- page_size: Number.parseInt(opts.limit, 10),
531
- ...(opts.contentType ? { content_type: opts.contentType } : {})
801
+ const { readFileSync } = await import("node:fs");
802
+ const { writeFile } = await import("node:fs/promises");
803
+ const { packWorkflowsBundle } = await import("@nodetool-ai/websocket");
804
+ const toBundleWf = (raw) => ({
805
+ name: isString(raw.name) ? raw.name : "workflow",
806
+ description: isString(raw.description) ? raw.description : "",
807
+ tags: Array.isArray(raw.tags)
808
+ ? raw.tags.filter((t) => typeof t === "string")
809
+ : [],
810
+ run_mode: raw.run_mode ?? null,
811
+ settings: raw.settings ?? null,
812
+ graph: (raw.graph ?? raw)
532
813
  });
533
- // Note: --query isn't forwarded because assets.list has no server-side
534
- // search; keep local filtering until the tRPC schema exposes one.
535
- let rows = data.assets;
536
- if (opts.query) {
537
- const q = String(opts.query).toLowerCase();
538
- rows = rows.filter((r) => String(r["name"] ?? "").toLowerCase().includes(q));
814
+ const useServer = Boolean(opts.apiUrl);
815
+ const apiUrl = opts.apiUrl?.replace(/\/+$/, "") ?? "";
816
+ if (!useServer)
817
+ ensureDb();
818
+ const workflowsToPack = [];
819
+ for (const idOrFile of idsOrFiles) {
820
+ const isFile = idOrFile.endsWith(".json") ||
821
+ idOrFile.includes("/") ||
822
+ idOrFile.includes("\\");
823
+ let raw;
824
+ if (isFile) {
825
+ raw = JSON.parse(readFileSync(idOrFile, "utf8"));
826
+ }
827
+ else if (useServer) {
828
+ raw = (await createApiClient(apiUrl).workflows.get.query({
829
+ id: idOrFile
830
+ }));
831
+ }
832
+ else {
833
+ const found = await Workflow.find(LOCAL_USER_ID, idOrFile);
834
+ if (!found)
835
+ throw new Error(`Workflow not found: ${idOrFile}`);
836
+ raw = { ...found, graph: found.getGraph() };
837
+ }
838
+ const wf = toBundleWf(raw);
839
+ if (!wf.graph?.nodes) {
840
+ throw new Error(`Workflow '${idOrFile}' has no graph to export`);
841
+ }
842
+ workflowsToPack.push(wf);
539
843
  }
540
- if (opts.json) {
541
- asJson(rows);
542
- return;
844
+ const packOptions = {
845
+ workflows: workflowsToPack,
846
+ fetchAssetBytes: useServer
847
+ ? makeAssetFetcher(apiUrl)
848
+ : await makeLocalAssetFetcher(),
849
+ nodetoolVersion: cliVersion()
850
+ };
851
+ if (opts.includeRemote) {
852
+ packOptions.includeRemote = true;
543
853
  }
544
- printTable(rows.map((r) => ({
545
- id: r["id"],
546
- name: r["name"],
547
- content_type: r["content_type"],
548
- size: r["size"]
549
- })));
854
+ const { bytes, manifest, skipped } = await packWorkflowsBundle(packOptions);
855
+ const defaultBase = workflowsToPack.length === 1
856
+ ? workflowsToPack[0].name.replace(/[^A-Za-z0-9._-]+/g, "_")
857
+ : `${workflowsToPack.length}-workflows`;
858
+ const outPath = opts.output ?? `${defaultBase}.nodetool`;
859
+ await writeFile(outPath, bytes);
860
+ for (const a of manifest.assets) {
861
+ console.error(` embedded ${a.file} (${a.bytes} bytes)`);
862
+ }
863
+ for (const s of skipped) {
864
+ console.error(` warning: could not resolve asset ${s} (left as-is)`);
865
+ }
866
+ console.error(` bundled ${manifest.workflows.length} workflow(s), ${manifest.assets.length} asset(s)`);
867
+ console.log(outPath);
550
868
  }
551
869
  catch (e) {
552
- console.error(String(e));
870
+ printCommandError(e);
553
871
  process.exit(1);
554
872
  }
555
873
  });
556
- assets
557
- .command("get <asset_id>")
558
- .description("Get an asset by ID")
559
- .option("--api-url <url>", "API base URL", process.env["NODETOOL_API_URL"] ?? "http://localhost:7777")
560
- .option("--json", "Output as JSON")
561
- .action(async (assetId, opts) => {
874
+ workflows
875
+ .command("import-bundle <bundle_file>")
876
+ .description("Import a .nodetool bundle into the local library: store its assets and " +
877
+ "create the workflows with refs rewritten to the imported assets")
878
+ .option("--json", "Output the created workflows as JSON")
879
+ .action(async (bundleFile, opts) => {
562
880
  try {
563
- const client = createApiClient(opts.apiUrl);
564
- const data = await client.assets.get.query({ id: assetId });
881
+ const { readFileSync } = await import("node:fs");
882
+ const { randomUUID } = await import("node:crypto");
883
+ const { extname } = await import("node:path");
884
+ const { importWorkflowBundle } = await import("@nodetool-ai/websocket");
885
+ await setupDb();
886
+ const storage = new FileStorageAdapter(getDefaultAssetsPath());
887
+ const zip = new Uint8Array(readFileSync(bundleFile));
888
+ const result = await importWorkflowBundle(zip, {
889
+ storeAsset: async ({ bytes, fileName, contentType }) => {
890
+ const id = randomUUID();
891
+ const key = `${id}${extname(fileName)}`;
892
+ await storage.store(key, bytes, contentType);
893
+ return { uri: `asset://${key}`, assetId: id };
894
+ }
895
+ });
896
+ const created = [];
897
+ for (const wf of result.workflows) {
898
+ created.push(await Workflow.create({
899
+ user_id: "1",
900
+ name: wf.name,
901
+ description: wf.description ?? "",
902
+ tags: wf.tags ?? [],
903
+ access: "private",
904
+ graph: wf.graph,
905
+ run_mode: wf.run_mode ?? "workflow",
906
+ settings: wf.settings ?? null
907
+ }));
908
+ }
909
+ for (const s of result.missing) {
910
+ console.error(` warning: bundle asset ${s} was missing from the archive`);
911
+ }
912
+ for (const m of result.checksumMismatches) {
913
+ console.error(` warning: ${m}`);
914
+ }
915
+ console.error(` imported ${created.length} workflow(s) and ${result.imported.length} asset(s) into local storage`);
565
916
  if (opts.json) {
566
- asJson(data);
567
- return;
917
+ asJson(created);
568
918
  }
569
- const a = data;
570
- printTable([
571
- {
572
- id: a["id"],
573
- name: a["name"],
574
- content_type: a["content_type"],
575
- size: a["size"],
576
- url: a["url"]
919
+ else {
920
+ for (const c of created) {
921
+ console.log(String(c.id));
577
922
  }
578
- ]);
923
+ }
579
924
  }
580
925
  catch (e) {
581
- console.error(String(e));
926
+ printCommandError(e, opts.json);
582
927
  process.exit(1);
583
928
  }
584
929
  });
585
930
  // ---------------------------------------------------------------------------
586
- // models
931
+ // jobs / assets — the read commands are registered from commands/resource-read.ts
587
932
  // ---------------------------------------------------------------------------
933
+ const jobs = program.command("jobs").description("Job management");
934
+ const assets = program.command("assets").description("Asset management");
935
+ registerResourceReadCommands({ workflows, jobs, assets }, { ensureDb, localUserId: LOCAL_USER_ID });
588
936
  const models = program.command("models").description("Model management");
589
- const modelKinds = ["llm", "image", "tts", "asr", "video", "embedding"];
590
- const byProviderRoute = {
591
- llm: "llmByProvider",
592
- image: "imageByProvider",
593
- tts: "ttsByProvider",
594
- asr: "asrByProvider",
595
- video: "videoByProvider",
596
- embedding: "embeddingByProvider"
597
- };
937
+ const modelKinds = [
938
+ "llm",
939
+ "image",
940
+ "tts",
941
+ "asr",
942
+ "video",
943
+ "embedding"
944
+ ];
598
945
  function modelRow(m) {
599
946
  return {
600
947
  id: m["id"],
@@ -606,14 +953,20 @@ function modelRow(m) {
606
953
  }
607
954
  models
608
955
  .command("list")
609
- .description("List all models (recommended + provider + HF cached)")
610
- .option("--api-url <url>", "API base URL", process.env["NODETOOL_API_URL"] ?? "http://localhost:7777")
956
+ .description("List all models (recommended + provider + HF cached); local by default, --api-url for remote")
957
+ .option("--api-url <url>", "Query a remote server instead of local providers/cache", process.env["NODETOOL_API_URL"])
611
958
  .option("--json", "Output as JSON")
612
959
  .action(async (opts) => {
613
960
  try {
614
- const client = createApiClient(opts.apiUrl);
615
- const data = await client.models.all.query();
616
- const rows = data;
961
+ let rows;
962
+ if (opts.apiUrl) {
963
+ const client = createApiClient(opts.apiUrl);
964
+ rows = await client.models.all.query();
965
+ }
966
+ else {
967
+ await setupDb();
968
+ rows = await listAllModels();
969
+ }
617
970
  if (opts.json) {
618
971
  asJson(rows);
619
972
  return;
@@ -621,19 +974,18 @@ models
621
974
  printTable(rows.map(modelRow));
622
975
  }
623
976
  catch (e) {
624
- console.error(String(e));
977
+ printCommandError(e, opts.json);
625
978
  process.exit(1);
626
979
  }
627
980
  });
628
981
  models
629
982
  .command("providers")
630
983
  .description("List configured providers and their capabilities")
631
- .option("--api-url <url>", "API base URL", process.env["NODETOOL_API_URL"] ?? "http://localhost:7777")
632
984
  .option("--json", "Output as JSON")
633
985
  .action(async (opts) => {
986
+ await setupDb();
634
987
  try {
635
- const client = createApiClient(opts.apiUrl);
636
- const data = await client.models.providers.query();
988
+ const data = await listConfiguredProviderInfo();
637
989
  if (opts.json) {
638
990
  asJson(data);
639
991
  return;
@@ -644,7 +996,7 @@ models
644
996
  })));
645
997
  }
646
998
  catch (e) {
647
- console.error(String(e));
999
+ printCommandError(e, opts.json);
648
1000
  process.exit(1);
649
1001
  }
650
1002
  });
@@ -652,42 +1004,67 @@ registerRecommendedCommand(models);
652
1004
  registerHfCommands(models);
653
1005
  models
654
1006
  .command("ollama")
655
- .description("List Ollama models")
656
- .option("--api-url <url>", "API base URL", process.env["NODETOOL_API_URL"] ?? "http://localhost:7777")
1007
+ .description("List Ollama models (queries the local daemon; --api-url for remote)")
1008
+ .option("--api-url <url>", "Query a remote server instead of the local Ollama daemon", process.env["NODETOOL_API_URL"])
657
1009
  .option("--json", "Output as JSON")
658
1010
  .action(async (opts) => {
659
1011
  try {
660
- const client = createApiClient(opts.apiUrl);
661
- const data = await client.models.ollama.query();
662
- const rows = data;
1012
+ let rows;
1013
+ if (opts.apiUrl) {
1014
+ const client = createApiClient(opts.apiUrl);
1015
+ rows = await client.models.ollama.query();
1016
+ }
1017
+ else {
1018
+ await setupDb();
1019
+ rows = await listOllamaModels();
1020
+ }
663
1021
  if (opts.json) {
664
1022
  asJson(rows);
665
1023
  return;
666
1024
  }
667
- printTable(rows);
1025
+ printTable(rows.map(modelRow));
668
1026
  }
669
1027
  catch (e) {
670
- console.error(String(e));
1028
+ printCommandError(e, opts.json);
671
1029
  process.exit(1);
672
1030
  }
673
1031
  });
674
1032
  models
675
1033
  .command("huggingface")
676
- .description("List HuggingFace cached models")
677
- .option("--api-url <url>", "API base URL", process.env["NODETOOL_API_URL"] ?? "http://localhost:7777")
1034
+ .description("List HuggingFace cached models (scans the local cache; --api-url for remote)")
1035
+ .option("--api-url <url>", "Query a remote server instead of the local HuggingFace cache", process.env["NODETOOL_API_URL"])
678
1036
  .option("--query <q>", "Search query")
679
1037
  .option("--type <t>", "Filter by HF model type")
680
1038
  .option("--json", "Output as JSON")
681
1039
  .action(async (opts) => {
682
1040
  try {
683
- const client = createApiClient(opts.apiUrl);
684
- const data = opts.query || opts.type
685
- ? await client.models.huggingfaceSearch.query({
686
- ...(opts.query ? { query: String(opts.query) } : {}),
687
- ...(opts.type ? { type: String(opts.type) } : {})
688
- })
689
- : await client.models.huggingfaceList.query();
690
- const rows = data;
1041
+ let rows;
1042
+ if (opts.apiUrl) {
1043
+ const client = createApiClient(opts.apiUrl);
1044
+ if (opts.query || opts.type) {
1045
+ const search = {};
1046
+ if (opts.query) {
1047
+ search.query = String(opts.query);
1048
+ }
1049
+ if (opts.type) {
1050
+ search.type = String(opts.type);
1051
+ }
1052
+ rows = await client.models.huggingfaceSearch.query(search);
1053
+ }
1054
+ else {
1055
+ rows = await client.models.huggingfaceList.query();
1056
+ }
1057
+ }
1058
+ else if (opts.query || opts.type) {
1059
+ // Wrap a bare query in wildcards so it matches as a substring, the same
1060
+ // normalization the server's huggingfaceSearch applies.
1061
+ const rawQuery = opts.query ? String(opts.query) : undefined;
1062
+ const query = rawQuery && !rawQuery.includes("*") ? `*${rawQuery}*` : rawQuery;
1063
+ rows = await searchCachedHfModels(query ? [query] : undefined, opts.type ? [String(opts.type)] : undefined);
1064
+ }
1065
+ else {
1066
+ rows = await readCachedHfModels();
1067
+ }
691
1068
  if (opts.json) {
692
1069
  asJson(rows);
693
1070
  return;
@@ -695,14 +1072,13 @@ models
695
1072
  printTable(rows.map(modelRow));
696
1073
  }
697
1074
  catch (e) {
698
- console.error(String(e));
1075
+ printCommandError(e, opts.json);
699
1076
  process.exit(1);
700
1077
  }
701
1078
  });
702
1079
  models
703
1080
  .command("by-provider <provider>")
704
1081
  .description(`List models for a provider. --kind one of: ${modelKinds.join(", ")}`)
705
- .option("--api-url <url>", "API base URL", process.env["NODETOOL_API_URL"] ?? "http://localhost:7777")
706
1082
  .option("--kind <kind>", "Model kind", "llm")
707
1083
  .option("--json", "Output as JSON")
708
1084
  .action(async (provider, opts) => {
@@ -711,11 +1087,9 @@ models
711
1087
  console.error(`Invalid --kind '${opts.kind}'. Must be one of: ${modelKinds.join(", ")}`);
712
1088
  process.exit(1);
713
1089
  }
1090
+ await setupDb();
714
1091
  try {
715
- const client = createApiClient(opts.apiUrl);
716
- const route = byProviderRoute[kind];
717
- const data = await client.models[route].query({ provider });
718
- const rows = data;
1092
+ const rows = await listProviderModels(provider, kind);
719
1093
  if (opts.json) {
720
1094
  asJson(rows);
721
1095
  return;
@@ -723,7 +1097,75 @@ models
723
1097
  printTable(rows.map(modelRow));
724
1098
  }
725
1099
  catch (e) {
726
- console.error(String(e));
1100
+ printCommandError(e, opts.json);
1101
+ process.exit(1);
1102
+ }
1103
+ });
1104
+ // ---------------------------------------------------------------------------
1105
+ // storage
1106
+ // ---------------------------------------------------------------------------
1107
+ const storage = program
1108
+ .command("storage")
1109
+ .description("Maintain the asset storage backend");
1110
+ storage
1111
+ .command("migrate-keys")
1112
+ .description("Move asset objects under their owner's prefix (<userId>/<assetId>.<ext>)")
1113
+ .option("--dry-run", "Report what would move without writing anything")
1114
+ .option("--user-id <id>", "Migrate only this user's objects")
1115
+ .option("--json", "Output the report as JSON")
1116
+ .action(async (opts) => {
1117
+ await setupDb();
1118
+ const { migrateStorageKeys, formatMigrateKeysReport } = await import("./commands/storage.js");
1119
+ try {
1120
+ const migrateOptions = {
1121
+ dryRun: Boolean(opts.dryRun)
1122
+ };
1123
+ if (opts.userId) {
1124
+ migrateOptions.userId = opts.userId;
1125
+ }
1126
+ const report = await migrateStorageKeys(migrateOptions);
1127
+ if (opts.json) {
1128
+ console.log(JSON.stringify(report, null, 2));
1129
+ }
1130
+ else {
1131
+ console.log(formatMigrateKeysReport(report, Boolean(opts.dryRun)));
1132
+ }
1133
+ if (report.failed > 0)
1134
+ process.exit(1);
1135
+ }
1136
+ catch (e) {
1137
+ printCommandError(e, opts.json);
1138
+ process.exit(1);
1139
+ }
1140
+ });
1141
+ workflows
1142
+ .command("migrate-code-inputs")
1143
+ .description("Rewrite saved Code node bodies to read declared inputs off `inputs`")
1144
+ .option("--dry-run", "Report what would change without writing anything")
1145
+ .option("--user-id <id>", "Migrate only this user's workflows")
1146
+ .option("--json", "Output the report as JSON")
1147
+ .action(async (opts) => {
1148
+ await setupDb();
1149
+ const { migrateCodeInputs, formatMigrateCodeInputsReport } = await import("./commands/migrate-code-inputs.js");
1150
+ try {
1151
+ const migrateOptions = {
1152
+ dryRun: Boolean(opts.dryRun)
1153
+ };
1154
+ if (opts.userId) {
1155
+ migrateOptions.userId = opts.userId;
1156
+ }
1157
+ const report = await migrateCodeInputs(migrateOptions);
1158
+ if (opts.json) {
1159
+ console.log(JSON.stringify(report, null, 2));
1160
+ }
1161
+ else {
1162
+ console.log(formatMigrateCodeInputsReport(report, Boolean(opts.dryRun)));
1163
+ }
1164
+ if (report.failed > 0)
1165
+ process.exit(1);
1166
+ }
1167
+ catch (e) {
1168
+ printCommandError(e, opts.json);
727
1169
  process.exit(1);
728
1170
  }
729
1171
  });
@@ -748,7 +1190,7 @@ secrets
748
1190
  printTable(items.map((s) => ({ key: s.key, updated_at: s.updated_at ?? "" })));
749
1191
  }
750
1192
  catch (e) {
751
- console.error(String(e));
1193
+ printCommandError(e);
752
1194
  process.exit(1);
753
1195
  }
754
1196
  });
@@ -780,7 +1222,7 @@ secrets
780
1222
  console.log(`Secret '${key}' stored.`);
781
1223
  }
782
1224
  catch (e) {
783
- console.error(String(e));
1225
+ printCommandError(e);
784
1226
  process.exit(1);
785
1227
  }
786
1228
  });
@@ -799,7 +1241,7 @@ secrets
799
1241
  console.log(value);
800
1242
  }
801
1243
  catch (e) {
802
- console.error(String(e));
1244
+ printCommandError(e);
803
1245
  process.exit(1);
804
1246
  }
805
1247
  });
@@ -888,7 +1330,10 @@ mcp
888
1330
  projects[home] = globalProject;
889
1331
  config["projects"] = projects;
890
1332
  writeFileSync(claudeConfigPath, JSON.stringify(config, null, 2) + "\n");
891
- results.push({ target: "Claude Code", status: `Installed → ${claudeConfigPath}` });
1333
+ results.push({
1334
+ target: "Claude Code",
1335
+ status: `Installed → ${claudeConfigPath}`
1336
+ });
892
1337
  }
893
1338
  catch (e) {
894
1339
  results.push({ target: "Claude Code", status: `Error: ${e}` });
@@ -927,7 +1372,10 @@ mcp
927
1372
  content = mcpBlock + "\n";
928
1373
  }
929
1374
  writeFileSync(codexConfigPath, content);
930
- results.push({ target: "Codex", status: `Installed → ${codexConfigPath}` });
1375
+ results.push({
1376
+ target: "Codex",
1377
+ status: `Installed → ${codexConfigPath}`
1378
+ });
931
1379
  }
932
1380
  catch (e) {
933
1381
  results.push({ target: "Codex", status: `Error: ${e}` });
@@ -950,7 +1398,10 @@ mcp
950
1398
  };
951
1399
  config["mcp"] = mcpConfig;
952
1400
  writeFileSync(opencodeConfigPath, JSON.stringify(config, null, 2) + "\n");
953
- results.push({ target: "OpenCode", status: `Installed → ${opencodeConfigPath}` });
1401
+ results.push({
1402
+ target: "OpenCode",
1403
+ status: `Installed → ${opencodeConfigPath}`
1404
+ });
954
1405
  }
955
1406
  catch (e) {
956
1407
  results.push({ target: "OpenCode", status: `Error: ${e}` });
@@ -1078,7 +1529,11 @@ mcp
1078
1529
  });
1079
1530
  }
1080
1531
  else {
1081
- results.push({ target: "Claude Code", status: "Not installed", url: "" });
1532
+ results.push({
1533
+ target: "Claude Code",
1534
+ status: "Not installed",
1535
+ url: ""
1536
+ });
1082
1537
  }
1083
1538
  }
1084
1539
  else {
@@ -1086,7 +1541,11 @@ mcp
1086
1541
  }
1087
1542
  }
1088
1543
  catch {
1089
- results.push({ target: "Claude Code", status: "Error reading config", url: "" });
1544
+ results.push({
1545
+ target: "Claude Code",
1546
+ status: "Error reading config",
1547
+ url: ""
1548
+ });
1090
1549
  }
1091
1550
  // Codex
1092
1551
  try {
@@ -1110,7 +1569,11 @@ mcp
1110
1569
  }
1111
1570
  }
1112
1571
  catch {
1113
- results.push({ target: "Codex", status: "Error reading config", url: "" });
1572
+ results.push({
1573
+ target: "Codex",
1574
+ status: "Error reading config",
1575
+ url: ""
1576
+ });
1114
1577
  }
1115
1578
  // OpenCode
1116
1579
  try {
@@ -1125,7 +1588,11 @@ mcp
1125
1588
  });
1126
1589
  }
1127
1590
  else {
1128
- results.push({ target: "OpenCode", status: "Not installed", url: "" });
1591
+ results.push({
1592
+ target: "OpenCode",
1593
+ status: "Not installed",
1594
+ url: ""
1595
+ });
1129
1596
  }
1130
1597
  }
1131
1598
  else {
@@ -1133,22 +1600,91 @@ mcp
1133
1600
  }
1134
1601
  }
1135
1602
  catch {
1136
- results.push({ target: "OpenCode", status: "Error reading config", url: "" });
1603
+ results.push({
1604
+ target: "OpenCode",
1605
+ status: "Error reading config",
1606
+ url: ""
1607
+ });
1137
1608
  }
1138
1609
  console.log("\nNodeTool MCP Integration Status\n");
1139
1610
  printTable(results);
1140
1611
  console.log();
1141
1612
  });
1613
+ mcp
1614
+ .command("serve")
1615
+ .description("Run the NodeTool MCP server over stdio for an external agent " +
1616
+ "(Claude Code, Codex, …). All logging goes to stderr; stdout is the " +
1617
+ "MCP protocol channel.")
1618
+ .action(async () => {
1619
+ try {
1620
+ const { createMcpServer, createMcpStdioTransport, forwardMcpStdioToLocalServer } = await import("@nodetool-ai/websocket");
1621
+ if (await forwardMcpStdioToLocalServer()) {
1622
+ process.stderr.write("NodeTool MCP forwarding to the local API server.\n");
1623
+ return;
1624
+ }
1625
+ await setupDb();
1626
+ // A local TS-node registry powers list_nodes / search_nodes /
1627
+ // validate_workflow without spinning up a Python worker.
1628
+ const registry = new NodeRegistry();
1629
+ registerBaseNodes(registry);
1630
+ registerElevenLabsNodes(registry);
1631
+ registerMinimaxNodes(registry);
1632
+ registerTransformersJsNodes(registry);
1633
+ registerFalNodes(registry);
1634
+ registerReplicateNodes(registry);
1635
+ registerReveNodes(registry);
1636
+ registerHuggingFaceNodes(registry);
1637
+ // stdio serves exactly one local user; "1" is the local single-user id.
1638
+ const server = createMcpServer({
1639
+ registry,
1640
+ agentToolsScope: { userId: "1", source: "stdio-local" }
1641
+ });
1642
+ const transport = createMcpStdioTransport();
1643
+ await server.connect(transport);
1644
+ process.stderr.write("NodeTool MCP server ready on stdio.\n");
1645
+ // The stdio transport keeps the event loop alive until the client
1646
+ // closes the connection.
1647
+ }
1648
+ catch (e) {
1649
+ printCommandError(e);
1650
+ process.exit(1);
1651
+ }
1652
+ });
1142
1653
  // ---------------------------------------------------------------------------
1143
1654
  // package
1144
1655
  // ---------------------------------------------------------------------------
1145
1656
  registerPackageCommands(program);
1657
+ registerPackCommands(program);
1658
+ registerWorkerCommands(program);
1659
+ // Any command that opens a remote Python bridge keeps the attached worker's
1660
+ // idle clock fresh, so the reaper doesn't pause a GPU that is mid-job.
1661
+ installWorkerActivityHeartbeat(onPythonBridgeCreated);
1146
1662
  // ---------------------------------------------------------------------------
1147
- // deploy / list-gcp-options — registered from commands/deploy.ts
1663
+ // deploy — registered from commands/deploy.ts
1148
1664
  // ---------------------------------------------------------------------------
1149
1665
  registerDeployCommands(program);
1150
- registerListGcpOptions(program);
1151
1666
  registerAgentCommands(program);
1667
+ registerDbCommands(program);
1668
+ registerDebugCommands(program);
1669
+ registerAppCommands(program);
1670
+ registerAppsCommands(program);
1671
+ registerValidateCommand(program);
1672
+ registerTimelineCommands(program);
1673
+ registerSketchCommands(program);
1674
+ registerGameCommands(program);
1675
+ registerJsScriptCommands(program);
1676
+ registerReliabilityCommands(program);
1677
+ registerNodeCommands(program);
1678
+ registerGenerateCommand(program);
1679
+ registerEvalCommand(program);
1680
+ registerJtbdCommand(program, setupDb);
1681
+ registerAffectedCommand(program);
1682
+ registerHarnessCommands(program);
1683
+ registerCollectionCommands(program);
1684
+ registerCostsCommands(program);
1685
+ registerGenerationsCommands(program);
1686
+ registerAuthCommands(program);
1687
+ registerTelegramCommands(program);
1152
1688
  // ---------------------------------------------------------------------------
1153
1689
  program.parse();
1154
1690
  //# sourceMappingURL=nodetool.js.map