@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.
- package/README.md +79 -0
- package/dist/.nodetool-build-stamp +1 -0
- package/dist/ExecutionTree.d.ts +2 -1
- package/dist/ExecutionTree.d.ts.map +1 -1
- package/dist/ExecutionTree.js +1 -1
- package/dist/ExecutionTree.js.map +1 -1
- package/dist/affected/affected.d.ts +50 -0
- package/dist/affected/affected.d.ts.map +1 -0
- package/dist/affected/affected.js +118 -0
- package/dist/affected/affected.js.map +1 -0
- package/dist/agent-toolbelt.d.ts +15 -0
- package/dist/agent-toolbelt.d.ts.map +1 -0
- package/dist/agent-toolbelt.js +28 -0
- package/dist/agent-toolbelt.js.map +1 -0
- package/dist/api-client.d.ts +12 -0
- package/dist/api-client.d.ts.map +1 -0
- package/dist/api-client.js +21 -0
- package/dist/api-client.js.map +1 -0
- package/dist/app-build/bundle.d.ts +15 -0
- package/dist/app-build/bundle.d.ts.map +1 -0
- package/dist/app-build/bundle.js +45 -0
- package/dist/app-build/bundle.js.map +1 -0
- package/dist/app-build/watch.d.ts +13 -0
- package/dist/app-build/watch.d.ts.map +1 -0
- package/dist/app-build/watch.js +25 -0
- package/dist/app-build/watch.js.map +1 -0
- package/dist/app-debug/app-target.d.ts +14 -0
- package/dist/app-debug/app-target.d.ts.map +1 -0
- package/dist/app-debug/app-target.js +120 -0
- package/dist/app-debug/app-target.js.map +1 -0
- package/dist/app-debug/harness.d.ts +27 -0
- package/dist/app-debug/harness.d.ts.map +1 -0
- package/dist/app-debug/harness.js +93 -0
- package/dist/app-debug/harness.js.map +1 -0
- package/dist/app-debug/index.d.ts +12 -0
- package/dist/app-debug/index.d.ts.map +1 -0
- package/dist/app-debug/index.js +9 -0
- package/dist/app-debug/index.js.map +1 -0
- package/dist/app.d.ts +38 -48
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +979 -677
- package/dist/app.js.map +1 -1
- package/dist/bash-tool.d.ts +13 -0
- package/dist/bash-tool.d.ts.map +1 -0
- package/dist/bash-tool.js +85 -0
- package/dist/bash-tool.js.map +1 -0
- package/dist/chat-codeact.d.ts +85 -0
- package/dist/chat-codeact.d.ts.map +1 -0
- package/dist/chat-codeact.js +141 -0
- package/dist/chat-codeact.js.map +1 -0
- package/dist/chat-context.d.ts +18 -0
- package/dist/chat-context.d.ts.map +1 -0
- package/dist/chat-context.js +27 -0
- package/dist/chat-context.js.map +1 -0
- package/dist/chat-media.d.ts +3 -0
- package/dist/chat-media.d.ts.map +1 -0
- package/dist/chat-media.js +46 -0
- package/dist/chat-media.js.map +1 -0
- package/dist/chat-prompts.d.ts +20 -0
- package/dist/chat-prompts.d.ts.map +1 -0
- package/dist/chat-prompts.js +42 -0
- package/dist/chat-prompts.js.map +1 -0
- package/dist/chat-sessions.d.ts +25 -0
- package/dist/chat-sessions.d.ts.map +1 -0
- package/dist/chat-sessions.js +153 -0
- package/dist/chat-sessions.js.map +1 -0
- package/dist/command-errors.d.ts +10 -0
- package/dist/command-errors.d.ts.map +1 -0
- package/dist/command-errors.js +15 -0
- package/dist/command-errors.js.map +1 -0
- package/dist/commands/__tests__/jtbd.test.d.ts +2 -0
- package/dist/commands/__tests__/jtbd.test.d.ts.map +1 -0
- package/dist/commands/__tests__/jtbd.test.js +120 -0
- package/dist/commands/__tests__/jtbd.test.js.map +1 -0
- package/dist/commands/__tests__/timeline-render-audio.test.d.ts +2 -0
- package/dist/commands/__tests__/timeline-render-audio.test.d.ts.map +1 -0
- package/dist/commands/__tests__/timeline-render-audio.test.js +53 -0
- package/dist/commands/__tests__/timeline-render-audio.test.js.map +1 -0
- package/dist/commands/__tests__/timeline-render.test.d.ts +2 -0
- package/dist/commands/__tests__/timeline-render.test.d.ts.map +1 -0
- package/dist/commands/__tests__/timeline-render.test.js +115 -0
- package/dist/commands/__tests__/timeline-render.test.js.map +1 -0
- package/dist/commands/affected.d.ts +9 -0
- package/dist/commands/affected.d.ts.map +1 -0
- package/dist/commands/affected.js +122 -0
- package/dist/commands/affected.js.map +1 -0
- package/dist/commands/agent.d.ts +26 -4
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +327 -306
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/app.d.ts +3 -0
- package/dist/commands/app.d.ts.map +1 -0
- package/dist/commands/app.js +381 -0
- package/dist/commands/app.js.map +1 -0
- package/dist/commands/apps.d.ts +15 -0
- package/dist/commands/apps.d.ts.map +1 -0
- package/dist/commands/apps.js +180 -0
- package/dist/commands/apps.js.map +1 -0
- package/dist/commands/auth.d.ts +12 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +154 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/collections.d.ts +10 -0
- package/dist/commands/collections.d.ts.map +1 -0
- package/dist/commands/collections.js +257 -0
- package/dist/commands/collections.js.map +1 -0
- package/dist/commands/costs.d.ts +15 -0
- package/dist/commands/costs.d.ts.map +1 -0
- package/dist/commands/costs.js +201 -0
- package/dist/commands/costs.js.map +1 -0
- package/dist/commands/db.d.ts +3 -0
- package/dist/commands/db.d.ts.map +1 -0
- package/dist/commands/db.js +176 -0
- package/dist/commands/db.js.map +1 -0
- package/dist/commands/debug.d.ts +13 -0
- package/dist/commands/debug.d.ts.map +1 -0
- package/dist/commands/debug.js +138 -0
- package/dist/commands/debug.js.map +1 -0
- package/dist/commands/deploy-helpers.d.ts +49 -18
- package/dist/commands/deploy-helpers.d.ts.map +1 -1
- package/dist/commands/deploy-helpers.js +10 -276
- package/dist/commands/deploy-helpers.js.map +1 -1
- package/dist/commands/deploy.d.ts +0 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +21 -217
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/eval.d.ts +152 -0
- package/dist/commands/eval.d.ts.map +1 -0
- package/dist/commands/eval.js +688 -0
- package/dist/commands/eval.js.map +1 -0
- package/dist/commands/game.d.ts +4 -0
- package/dist/commands/game.d.ts.map +1 -0
- package/dist/commands/game.js +395 -0
- package/dist/commands/game.js.map +1 -0
- package/dist/commands/generate.d.ts +17 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +324 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/generations.d.ts +17 -0
- package/dist/commands/generations.d.ts.map +1 -0
- package/dist/commands/generations.js +408 -0
- package/dist/commands/generations.js.map +1 -0
- package/dist/commands/harness.d.ts +19 -0
- package/dist/commands/harness.d.ts.map +1 -0
- package/dist/commands/harness.js +361 -0
- package/dist/commands/harness.js.map +1 -0
- package/dist/commands/js-script-validation-output.d.ts +7 -0
- package/dist/commands/js-script-validation-output.d.ts.map +1 -0
- package/dist/commands/js-script-validation-output.js +5 -0
- package/dist/commands/js-script-validation-output.js.map +1 -0
- package/dist/commands/js-script-versions.d.ts +53 -0
- package/dist/commands/js-script-versions.d.ts.map +1 -0
- package/dist/commands/js-script-versions.js +89 -0
- package/dist/commands/js-script-versions.js.map +1 -0
- package/dist/commands/js-script.d.ts +29 -0
- package/dist/commands/js-script.d.ts.map +1 -0
- package/dist/commands/js-script.js +227 -0
- package/dist/commands/js-script.js.map +1 -0
- package/dist/commands/jtbd.d.ts +38 -0
- package/dist/commands/jtbd.d.ts.map +1 -0
- package/dist/commands/jtbd.js +261 -0
- package/dist/commands/jtbd.js.map +1 -0
- package/dist/commands/local-db.d.ts +16 -0
- package/dist/commands/local-db.d.ts.map +1 -0
- package/dist/commands/local-db.js +33 -0
- package/dist/commands/local-db.js.map +1 -0
- package/dist/commands/migrate-code-inputs.d.ts +24 -0
- package/dist/commands/migrate-code-inputs.d.ts.map +1 -0
- package/dist/commands/migrate-code-inputs.js +120 -0
- package/dist/commands/migrate-code-inputs.js.map +1 -0
- package/dist/commands/models-hf.js +4 -4
- package/dist/commands/models-hf.js.map +1 -1
- package/dist/commands/models-recommended.d.ts.map +1 -1
- package/dist/commands/models-recommended.js +16 -24
- package/dist/commands/models-recommended.js.map +1 -1
- package/dist/commands/node.d.ts +10 -0
- package/dist/commands/node.d.ts.map +1 -0
- package/dist/commands/node.js +72 -0
- package/dist/commands/node.js.map +1 -0
- package/dist/commands/output.d.ts +24 -0
- package/dist/commands/output.d.ts.map +1 -0
- package/dist/commands/output.js +132 -0
- package/dist/commands/output.js.map +1 -0
- package/dist/commands/package-helpers.d.ts +1 -7
- package/dist/commands/package-helpers.d.ts.map +1 -1
- package/dist/commands/package-helpers.js +3 -26
- package/dist/commands/package-helpers.js.map +1 -1
- package/dist/commands/package.js +2 -2
- package/dist/commands/package.js.map +1 -1
- package/dist/commands/packs.d.ts +13 -0
- package/dist/commands/packs.d.ts.map +1 -0
- package/dist/commands/packs.js +60 -0
- package/dist/commands/packs.js.map +1 -0
- package/dist/commands/reliability.d.ts +14 -0
- package/dist/commands/reliability.d.ts.map +1 -0
- package/dist/commands/reliability.js +80 -0
- package/dist/commands/reliability.js.map +1 -0
- package/dist/commands/resource-read.d.ts +28 -0
- package/dist/commands/resource-read.d.ts.map +1 -0
- package/dist/commands/resource-read.js +316 -0
- package/dist/commands/resource-read.js.map +1 -0
- package/dist/commands/sketch-validation-output.d.ts +7 -0
- package/dist/commands/sketch-validation-output.d.ts.map +1 -0
- package/dist/commands/sketch-validation-output.js +5 -0
- package/dist/commands/sketch-validation-output.js.map +1 -0
- package/dist/commands/sketch-versions.d.ts +66 -0
- package/dist/commands/sketch-versions.d.ts.map +1 -0
- package/dist/commands/sketch-versions.js +108 -0
- package/dist/commands/sketch-versions.js.map +1 -0
- package/dist/commands/sketch.d.ts +21 -0
- package/dist/commands/sketch.d.ts.map +1 -0
- package/dist/commands/sketch.js +117 -0
- package/dist/commands/sketch.js.map +1 -0
- package/dist/commands/storage.d.ts +24 -0
- package/dist/commands/storage.d.ts.map +1 -0
- package/dist/commands/storage.js +112 -0
- package/dist/commands/storage.js.map +1 -0
- package/dist/commands/telegram.d.ts +11 -0
- package/dist/commands/telegram.d.ts.map +1 -0
- package/dist/commands/telegram.js +66 -0
- package/dist/commands/telegram.js.map +1 -0
- package/dist/commands/timeline-render.d.ts +80 -0
- package/dist/commands/timeline-render.d.ts.map +1 -0
- package/dist/commands/timeline-render.js +465 -0
- package/dist/commands/timeline-render.js.map +1 -0
- package/dist/commands/timeline-validation-output.d.ts +7 -0
- package/dist/commands/timeline-validation-output.d.ts.map +1 -0
- package/dist/commands/timeline-validation-output.js +9 -0
- package/dist/commands/timeline-validation-output.js.map +1 -0
- package/dist/commands/timeline-versions.d.ts +72 -0
- package/dist/commands/timeline-versions.d.ts.map +1 -0
- package/dist/commands/timeline-versions.js +108 -0
- package/dist/commands/timeline-versions.js.map +1 -0
- package/dist/commands/timeline.d.ts +22 -0
- package/dist/commands/timeline.d.ts.map +1 -0
- package/dist/commands/timeline.js +119 -0
- package/dist/commands/timeline.js.map +1 -0
- package/dist/commands/validate.d.ts +22 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +127 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/commands/validation-output.d.ts +25 -0
- package/dist/commands/validation-output.d.ts.map +1 -0
- package/dist/commands/validation-output.js +29 -0
- package/dist/commands/validation-output.js.map +1 -0
- package/dist/commands/version-commands.d.ts +94 -0
- package/dist/commands/version-commands.d.ts.map +1 -0
- package/dist/commands/version-commands.js +227 -0
- package/dist/commands/version-commands.js.map +1 -0
- package/dist/commands/worker-models.d.ts +13 -0
- package/dist/commands/worker-models.d.ts.map +1 -0
- package/dist/commands/worker-models.js +207 -0
- package/dist/commands/worker-models.js.map +1 -0
- package/dist/commands/worker.d.ts +23 -0
- package/dist/commands/worker.d.ts.map +1 -0
- package/dist/commands/worker.js +374 -0
- package/dist/commands/worker.js.map +1 -0
- package/dist/debug/browser-runner.d.ts +21 -0
- package/dist/debug/browser-runner.d.ts.map +1 -0
- package/dist/debug/browser-runner.js +196 -0
- package/dist/debug/browser-runner.js.map +1 -0
- package/dist/debug/collector.d.ts +9 -0
- package/dist/debug/collector.d.ts.map +1 -0
- package/dist/debug/collector.js +9 -0
- package/dist/debug/collector.js.map +1 -0
- package/dist/debug/diff.d.ts +48 -0
- package/dist/debug/diff.d.ts.map +1 -0
- package/dist/debug/diff.js +68 -0
- package/dist/debug/diff.js.map +1 -0
- package/dist/debug/harness.d.ts +11 -0
- package/dist/debug/harness.d.ts.map +1 -0
- package/dist/debug/harness.js +103 -0
- package/dist/debug/harness.js.map +1 -0
- package/dist/debug/index.d.ts +17 -0
- package/dist/debug/index.d.ts.map +1 -0
- package/dist/debug/index.js +16 -0
- package/dist/debug/index.js.map +1 -0
- package/dist/debug/markdown.d.ts +3 -0
- package/dist/debug/markdown.d.ts.map +1 -0
- package/dist/debug/markdown.js +127 -0
- package/dist/debug/markdown.js.map +1 -0
- package/dist/debug/server-runner.d.ts +22 -0
- package/dist/debug/server-runner.d.ts.map +1 -0
- package/dist/debug/server-runner.js +164 -0
- package/dist/debug/server-runner.js.map +1 -0
- package/dist/debug/target.d.ts +34 -0
- package/dist/debug/target.d.ts.map +1 -0
- package/dist/debug/target.js +104 -0
- package/dist/debug/target.js.map +1 -0
- package/dist/debug/trace.d.ts +30 -0
- package/dist/debug/trace.d.ts.map +1 -0
- package/dist/debug/trace.js +87 -0
- package/dist/debug/trace.js.map +1 -0
- package/dist/debug/types.d.ts +82 -0
- package/dist/debug/types.d.ts.map +1 -0
- package/dist/debug/types.js +13 -0
- package/dist/debug/types.js.map +1 -0
- package/dist/debug/verdict.d.ts +3 -0
- package/dist/debug/verdict.d.ts.map +1 -0
- package/dist/debug/verdict.js +78 -0
- package/dist/debug/verdict.js.map +1 -0
- package/dist/debug/watch.d.ts +23 -0
- package/dist/debug/watch.d.ts.map +1 -0
- package/dist/debug/watch.js +68 -0
- package/dist/debug/watch.js.map +1 -0
- package/dist/diagnose.d.ts +139 -0
- package/dist/diagnose.d.ts.map +1 -0
- package/dist/diagnose.js +418 -0
- package/dist/diagnose.js.map +1 -0
- package/dist/evals/graph-runner.d.ts +8 -0
- package/dist/evals/graph-runner.d.ts.map +1 -0
- package/dist/evals/graph-runner.js +136 -0
- package/dist/evals/graph-runner.js.map +1 -0
- package/dist/harness/capability-coverage.d.ts +161 -0
- package/dist/harness/capability-coverage.d.ts.map +1 -0
- package/dist/harness/capability-coverage.js +266 -0
- package/dist/harness/capability-coverage.js.map +1 -0
- package/dist/harness/capability-table.d.ts +17 -0
- package/dist/harness/capability-table.d.ts.map +1 -0
- package/dist/harness/capability-table.js +3576 -0
- package/dist/harness/capability-table.js.map +1 -0
- package/dist/harness/changed-files.d.ts +18 -0
- package/dist/harness/changed-files.d.ts.map +1 -0
- package/dist/harness/changed-files.js +76 -0
- package/dist/harness/changed-files.js.map +1 -0
- package/dist/harness/declared-capabilities.d.ts +12 -0
- package/dist/harness/declared-capabilities.d.ts.map +1 -0
- package/dist/harness/declared-capabilities.js +21 -0
- package/dist/harness/declared-capabilities.js.map +1 -0
- package/dist/harness/registry.d.ts +162 -0
- package/dist/harness/registry.d.ts.map +1 -0
- package/dist/harness/registry.js +1738 -0
- package/dist/harness/registry.js.map +1 -0
- package/dist/index.js +121 -130
- package/dist/index.js.map +1 -1
- package/dist/interaction-script.d.ts +17 -0
- package/dist/interaction-script.d.ts.map +1 -0
- package/dist/interaction-script.js +47 -0
- package/dist/interaction-script.js.map +1 -0
- package/dist/js-script-debug/harness.d.ts +114 -0
- package/dist/js-script-debug/harness.d.ts.map +1 -0
- package/dist/js-script-debug/harness.js +252 -0
- package/dist/js-script-debug/harness.js.map +1 -0
- package/dist/js-script-debug/index.d.ts +9 -0
- package/dist/js-script-debug/index.d.ts.map +1 -0
- package/dist/js-script-debug/index.js +9 -0
- package/dist/js-script-debug/index.js.map +1 -0
- package/dist/js-script-debug/interactions.d.ts +19 -0
- package/dist/js-script-debug/interactions.d.ts.map +1 -0
- package/dist/js-script-debug/interactions.js +17 -0
- package/dist/js-script-debug/interactions.js.map +1 -0
- package/dist/js-script-debug/target.d.ts +20 -0
- package/dist/js-script-debug/target.d.ts.map +1 -0
- package/dist/js-script-debug/target.js +78 -0
- package/dist/js-script-debug/target.js.map +1 -0
- package/dist/local-model-interfaces.d.ts +20 -0
- package/dist/local-model-interfaces.d.ts.map +1 -0
- package/dist/local-model-interfaces.js +64 -0
- package/dist/local-model-interfaces.js.map +1 -0
- package/dist/local-secrets.d.ts +3 -0
- package/dist/local-secrets.d.ts.map +1 -0
- package/dist/local-secrets.js +16 -0
- package/dist/local-secrets.js.map +1 -0
- package/dist/markdown.d.ts.map +1 -1
- package/dist/markdown.js +7 -2
- package/dist/markdown.js.map +1 -1
- package/dist/node/run-node.d.ts +28 -0
- package/dist/node/run-node.d.ts.map +1 -0
- package/dist/node/run-node.js +76 -0
- package/dist/node/run-node.js.map +1 -0
- package/dist/node-registry.d.ts +13 -0
- package/dist/node-registry.d.ts.map +1 -0
- package/dist/node-registry.js +36 -0
- package/dist/node-registry.js.map +1 -0
- package/dist/nodetool.js +845 -309
- package/dist/nodetool.js.map +1 -1
- package/dist/numeric-options.d.ts +22 -0
- package/dist/numeric-options.d.ts.map +1 -0
- package/dist/numeric-options.js +45 -0
- package/dist/numeric-options.js.map +1 -0
- package/dist/permission-gate.d.ts +55 -0
- package/dist/permission-gate.d.ts.map +1 -0
- package/dist/permission-gate.js +118 -0
- package/dist/permission-gate.js.map +1 -0
- package/dist/predicates.d.ts +6 -0
- package/dist/predicates.d.ts.map +1 -0
- package/dist/predicates.js +6 -0
- package/dist/predicates.js.map +1 -0
- package/dist/providers.d.ts +73 -10
- package/dist/providers.d.ts.map +1 -1
- package/dist/providers.js +329 -97
- package/dist/providers.js.map +1 -1
- package/dist/readline-input.d.ts +13 -19
- package/dist/readline-input.d.ts.map +1 -1
- package/dist/readline-input.js +201 -190
- package/dist/readline-input.js.map +1 -1
- package/dist/run-budget.d.ts +40 -0
- package/dist/run-budget.d.ts.map +1 -0
- package/dist/run-budget.js +119 -0
- package/dist/run-budget.js.map +1 -0
- package/dist/run-dsl-supervised.d.ts +11 -0
- package/dist/run-dsl-supervised.d.ts.map +1 -0
- package/dist/run-dsl-supervised.js +82 -0
- package/dist/run-dsl-supervised.js.map +1 -0
- package/dist/run-dsl.d.ts +23 -0
- package/dist/run-dsl.d.ts.map +1 -1
- package/dist/run-dsl.js +40 -9
- package/dist/run-dsl.js.map +1 -1
- package/dist/run-json.d.ts +24 -0
- package/dist/run-json.d.ts.map +1 -0
- package/dist/run-json.js +132 -0
- package/dist/run-json.js.map +1 -0
- package/dist/sandbox-catalog.d.ts +12 -0
- package/dist/sandbox-catalog.d.ts.map +1 -0
- package/dist/sandbox-catalog.js +27 -0
- package/dist/sandbox-catalog.js.map +1 -0
- package/dist/settings.d.ts +11 -10
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +71 -13
- package/dist/settings.js.map +1 -1
- package/dist/sketch-debug/harness.d.ts +87 -0
- package/dist/sketch-debug/harness.d.ts.map +1 -0
- package/dist/sketch-debug/harness.js +178 -0
- package/dist/sketch-debug/harness.js.map +1 -0
- package/dist/sketch-debug/index.d.ts +9 -0
- package/dist/sketch-debug/index.d.ts.map +1 -0
- package/dist/sketch-debug/index.js +9 -0
- package/dist/sketch-debug/index.js.map +1 -0
- package/dist/sketch-debug/interactions.d.ts +19 -0
- package/dist/sketch-debug/interactions.d.ts.map +1 -0
- package/dist/sketch-debug/interactions.js +17 -0
- package/dist/sketch-debug/interactions.js.map +1 -0
- package/dist/sketch-debug/target.d.ts +48 -0
- package/dist/sketch-debug/target.d.ts.map +1 -0
- package/dist/sketch-debug/target.js +138 -0
- package/dist/sketch-debug/target.js.map +1 -0
- package/dist/stdin.d.ts +18 -19
- package/dist/stdin.d.ts.map +1 -1
- package/dist/stdin.js +159 -157
- package/dist/stdin.js.map +1 -1
- package/dist/supervisor.d.ts +97 -0
- package/dist/supervisor.d.ts.map +1 -0
- package/dist/supervisor.js +194 -0
- package/dist/supervisor.js.map +1 -0
- package/dist/terminal-clipboard.d.ts +3 -0
- package/dist/terminal-clipboard.d.ts.map +1 -0
- package/dist/terminal-clipboard.js +24 -0
- package/dist/terminal-clipboard.js.map +1 -0
- package/dist/terminal-mouse.d.ts +24 -0
- package/dist/terminal-mouse.d.ts.map +1 -0
- package/dist/terminal-mouse.js +84 -0
- package/dist/terminal-mouse.js.map +1 -0
- package/dist/terminal-screen.d.ts +41 -0
- package/dist/terminal-screen.d.ts.map +1 -0
- package/dist/terminal-screen.js +228 -0
- package/dist/terminal-screen.js.map +1 -0
- package/dist/timeline-debug/harness.d.ts +79 -0
- package/dist/timeline-debug/harness.d.ts.map +1 -0
- package/dist/timeline-debug/harness.js +155 -0
- package/dist/timeline-debug/harness.js.map +1 -0
- package/dist/timeline-debug/index.d.ts +9 -0
- package/dist/timeline-debug/index.d.ts.map +1 -0
- package/dist/timeline-debug/index.js +9 -0
- package/dist/timeline-debug/index.js.map +1 -0
- package/dist/timeline-debug/interactions.d.ts +19 -0
- package/dist/timeline-debug/interactions.d.ts.map +1 -0
- package/dist/timeline-debug/interactions.js +17 -0
- package/dist/timeline-debug/interactions.js.map +1 -0
- package/dist/timeline-debug/target.d.ts +34 -0
- package/dist/timeline-debug/target.d.ts.map +1 -0
- package/dist/timeline-debug/target.js +132 -0
- package/dist/timeline-debug/target.js.map +1 -0
- package/dist/tool-format.d.ts +54 -0
- package/dist/tool-format.d.ts.map +1 -0
- package/dist/tool-format.js +360 -0
- package/dist/tool-format.js.map +1 -0
- package/dist/useExecutionState.d.ts.map +1 -1
- package/dist/useExecutionState.js +8 -4
- package/dist/useExecutionState.js.map +1 -1
- package/dist/validate/index.d.ts +28 -0
- package/dist/validate/index.d.ts.map +1 -0
- package/dist/validate/index.js +51 -0
- package/dist/validate/index.js.map +1 -0
- package/dist/websocket-client.d.ts +78 -15
- package/dist/websocket-client.d.ts.map +1 -1
- package/dist/websocket-client.js +497 -171
- package/dist/websocket-client.js.map +1 -1
- 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 {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
88
|
-
|
|
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(
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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}: ${
|
|
306
|
+
console.log(` ${key}: ${previewJson(value)}`);
|
|
149
307
|
}
|
|
150
308
|
}
|
|
151
309
|
}
|
|
152
310
|
}
|
|
153
311
|
catch (e) {
|
|
154
|
-
console.error(
|
|
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:
|
|
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
|
|
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(
|
|
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 ??
|
|
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
|
-
.
|
|
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 {
|
|
333
|
-
const output =
|
|
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
|
-
//
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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
|
-
|
|
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:
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
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
|
-
|
|
393
|
-
|
|
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
|
-
|
|
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(` ${
|
|
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(
|
|
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>", "
|
|
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:
|
|
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
|
-
|
|
676
|
+
printCommandError(e);
|
|
448
677
|
process.exit(1);
|
|
449
678
|
}
|
|
450
679
|
});
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
.
|
|
457
|
-
.
|
|
458
|
-
.option("--
|
|
459
|
-
.option("
|
|
460
|
-
.option("--
|
|
461
|
-
.
|
|
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
|
|
465
|
-
const
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
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
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
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
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
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
|
-
|
|
788
|
+
printCommandError(e);
|
|
511
789
|
process.exit(1);
|
|
512
790
|
}
|
|
513
791
|
});
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
assets
|
|
519
|
-
.
|
|
520
|
-
.
|
|
521
|
-
.
|
|
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
|
|
529
|
-
const
|
|
530
|
-
|
|
531
|
-
|
|
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
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
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
|
-
|
|
541
|
-
|
|
542
|
-
|
|
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
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
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
|
-
|
|
870
|
+
printCommandError(e);
|
|
553
871
|
process.exit(1);
|
|
554
872
|
}
|
|
555
873
|
});
|
|
556
|
-
|
|
557
|
-
.command("
|
|
558
|
-
.description("
|
|
559
|
-
|
|
560
|
-
.option("--json", "Output as JSON")
|
|
561
|
-
.action(async (
|
|
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
|
|
564
|
-
const
|
|
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(
|
|
567
|
-
return;
|
|
917
|
+
asJson(created);
|
|
568
918
|
}
|
|
569
|
-
|
|
570
|
-
|
|
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
|
-
|
|
926
|
+
printCommandError(e, opts.json);
|
|
582
927
|
process.exit(1);
|
|
583
928
|
}
|
|
584
929
|
});
|
|
585
930
|
// ---------------------------------------------------------------------------
|
|
586
|
-
//
|
|
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 = [
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
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>", "
|
|
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
|
-
|
|
615
|
-
|
|
616
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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>", "
|
|
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
|
-
|
|
661
|
-
|
|
662
|
-
|
|
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
|
-
|
|
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>", "
|
|
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
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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
|
|
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
|