@nodetool-ai/cli 0.7.0-rc.23 → 0.8.2
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 +82 -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 +45 -0
- package/dist/affected/affected.d.ts.map +1 -0
- package/dist/affected/affected.js +160 -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 +29 -0
- package/dist/app-debug/harness.d.ts.map +1 -0
- package/dist/app-debug/harness.js +116 -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 +980 -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 +93 -0
- package/dist/chat-codeact.d.ts.map +1 -0
- package/dist/chat-codeact.js +179 -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 +32 -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-completeness.test.d.ts +2 -0
- package/dist/commands/__tests__/timeline-render-completeness.test.d.ts.map +1 -0
- package/dist/commands/__tests__/timeline-render-completeness.test.js +117 -0
- package/dist/commands/__tests__/timeline-render-completeness.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/__tests__/timeline-score.test.d.ts +2 -0
- package/dist/commands/__tests__/timeline-score.test.d.ts.map +1 -0
- package/dist/commands/__tests__/timeline-score.test.js +100 -0
- package/dist/commands/__tests__/timeline-score.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 +328 -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 +405 -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-summary-output.d.ts +22 -0
- package/dist/commands/debug-summary-output.d.ts.map +1 -0
- package/dist/commands/debug-summary-output.js +28 -0
- package/dist/commands/debug-summary-output.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/errors.d.ts +11 -0
- package/dist/commands/errors.d.ts.map +1 -0
- package/dist/commands/errors.js +177 -0
- package/dist/commands/errors.js.map +1 -0
- package/dist/commands/eval.d.ts +152 -0
- package/dist/commands/eval.d.ts.map +1 -0
- package/dist/commands/eval.js +690 -0
- package/dist/commands/eval.js.map +1 -0
- package/dist/commands/extension.d.ts +12 -0
- package/dist/commands/extension.d.ts.map +1 -0
- package/dist/commands/extension.js +30 -0
- package/dist/commands/extension.js.map +1 -0
- package/dist/commands/game-benchmark.d.ts +34 -0
- package/dist/commands/game-benchmark.d.ts.map +1 -0
- package/dist/commands/game-benchmark.js +95 -0
- package/dist/commands/game-benchmark.js.map +1 -0
- package/dist/commands/game-smoke.d.ts +3 -0
- package/dist/commands/game-smoke.d.ts.map +1 -0
- package/dist/commands/game-smoke.js +23 -0
- package/dist/commands/game-smoke.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 +624 -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 +69 -0
- package/dist/commands/harness.d.ts.map +1 -0
- package/dist/commands/harness.js +575 -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 +211 -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/mcp.d.ts +21 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +164 -0
- package/dist/commands/mcp.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.d.ts.map +1 -1
- package/dist/commands/package.js +14 -14
- 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/runs.d.ts +7 -0
- package/dist/commands/runs.d.ts.map +1 -0
- package/dist/commands/runs.js +302 -0
- package/dist/commands/runs.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 +101 -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 +85 -0
- package/dist/commands/timeline-render.d.ts.map +1 -0
- package/dist/commands/timeline-render.js +474 -0
- package/dist/commands/timeline-render.js.map +1 -0
- package/dist/commands/timeline-score.d.ts +16 -0
- package/dist/commands/timeline-score.d.ts.map +1 -0
- package/dist/commands/timeline-score.js +89 -0
- package/dist/commands/timeline-score.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 +105 -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 +24 -0
- package/dist/debug/server-runner.d.ts.map +1 -0
- package/dist/debug/server-runner.js +197 -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 +3844 -0
- package/dist/harness/capability-table.js.map +1 -0
- package/dist/harness/changed-files.d.ts +20 -0
- package/dist/harness/changed-files.d.ts.map +1 -0
- package/dist/harness/changed-files.js +90 -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 +190 -0
- package/dist/harness/registry.d.ts.map +1 -0
- package/dist/harness/registry.js +2034 -0
- package/dist/harness/registry.js.map +1 -0
- package/dist/index.js +122 -131
- package/dist/index.js.map +1 -1
- package/dist/interaction-script.d.ts +40 -0
- package/dist/interaction-script.d.ts.map +1 -0
- package/dist/interaction-script.js +96 -0
- package/dist/interaction-script.js.map +1 -0
- package/dist/js-script-debug/harness.d.ts +124 -0
- package/dist/js-script-debug/harness.d.ts.map +1 -0
- package/dist/js-script-debug/harness.js +230 -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 +41 -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 +27 -0
- package/dist/node-registry.d.ts.map +1 -0
- package/dist/node-registry.js +33 -0
- package/dist/node-registry.js.map +1 -0
- package/dist/nodetool-main.d.ts +15 -0
- package/dist/nodetool-main.d.ts.map +1 -0
- package/dist/nodetool-main.js +1368 -0
- package/dist/nodetool-main.js.map +1 -0
- package/dist/nodetool.d.ts +0 -13
- package/dist/nodetool.d.ts.map +1 -1
- package/dist/nodetool.js +17 -1147
- 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 +339 -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 +29 -0
- package/dist/run-dsl.d.ts.map +1 -1
- package/dist/run-dsl.js +44 -10
- 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 +24 -0
- package/dist/sandbox-catalog.d.ts.map +1 -0
- package/dist/sandbox-catalog.js +78 -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 +145 -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 +160 -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 +122 -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 +65 -31
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { isDeepStrictEqual } from "node:util";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { gameEvent, gameInputFrame } from "@nodetool-ai/protocol/game.js";
|
|
6
|
+
import { gameEvent3D, gameInputFrame3D } from "@nodetool-ai/protocol";
|
|
7
|
+
import { createScriptedGameSession, createGameSession3D, decodePreparedGameCollider3D, hashGameSnapshot3D, validateGame, validateAnyGame } from "@nodetool-ai/game-runtime";
|
|
8
|
+
import { benchmarkNativeGame } from "./game-benchmark.js";
|
|
9
|
+
import { printCommandError } from "../command-errors.js";
|
|
10
|
+
import { registerGameSmokeCommand } from "./game-smoke.js";
|
|
11
|
+
const strictGameEvent = z.union(gameEvent.options.map((variant) => variant.strict()));
|
|
12
|
+
const jsonFields = z.record(z.string(), z.unknown());
|
|
13
|
+
const tickAssertion = z.strictObject({
|
|
14
|
+
tick: z.number().int().nonnegative(),
|
|
15
|
+
sceneId: z.string().min(1).optional(),
|
|
16
|
+
entities: z.array(z.strictObject({
|
|
17
|
+
id: z.string().min(1),
|
|
18
|
+
x: z.number().finite().optional(),
|
|
19
|
+
y: z.number().finite().optional(),
|
|
20
|
+
active: z.boolean().optional()
|
|
21
|
+
})).optional(),
|
|
22
|
+
events: z.array(strictGameEvent).optional()
|
|
23
|
+
});
|
|
24
|
+
const gameAssertions = z.strictObject({
|
|
25
|
+
tolerance: z.number().finite().nonnegative().default(1e-9),
|
|
26
|
+
ticks: z.array(tickAssertion)
|
|
27
|
+
});
|
|
28
|
+
const MEDIA_TYPES = {
|
|
29
|
+
png: "image/png",
|
|
30
|
+
jpg: "image/jpeg",
|
|
31
|
+
webp: "image/webp",
|
|
32
|
+
wav: "audio/wav",
|
|
33
|
+
ogg: "audio/ogg",
|
|
34
|
+
mp3: "audio/mpeg",
|
|
35
|
+
ttf: "font/ttf",
|
|
36
|
+
otf: "font/otf",
|
|
37
|
+
glb: "model/gltf-binary",
|
|
38
|
+
json: "application/json"
|
|
39
|
+
};
|
|
40
|
+
async function readBuildAsset(directory, sourceAssetId) {
|
|
41
|
+
if (sourceAssetId.startsWith("builtin:"))
|
|
42
|
+
return null;
|
|
43
|
+
if (!directory)
|
|
44
|
+
return null;
|
|
45
|
+
if (!/^[a-f0-9]{32}$/.test(sourceAssetId)) {
|
|
46
|
+
throw new Error(`Asset ID must be a full 32-character resource ID: ${sourceAssetId}`);
|
|
47
|
+
}
|
|
48
|
+
for (const [extension, mimeType] of Object.entries(MEDIA_TYPES)) {
|
|
49
|
+
try {
|
|
50
|
+
return { bytes: await readFile(join(directory, `${sourceAssetId}.${extension}`)), mimeType };
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (error.code !== "ENOENT")
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
function nonnegativeInteger(value, name) {
|
|
60
|
+
const parsed = Number(value);
|
|
61
|
+
if (!Number.isSafeInteger(parsed) || parsed < 0) {
|
|
62
|
+
throw new Error(`${name} must be a nonnegative integer`);
|
|
63
|
+
}
|
|
64
|
+
return parsed;
|
|
65
|
+
}
|
|
66
|
+
async function readDocument(path) {
|
|
67
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
68
|
+
}
|
|
69
|
+
async function readInputs(path, schema) {
|
|
70
|
+
if (!path)
|
|
71
|
+
return [];
|
|
72
|
+
const raw = await readDocument(path);
|
|
73
|
+
if (!Array.isArray(raw)) {
|
|
74
|
+
throw new Error("Input recording must be an array of tick input frames");
|
|
75
|
+
}
|
|
76
|
+
return raw.map((input, index) => {
|
|
77
|
+
const parsed = schema.safeParse(input);
|
|
78
|
+
if (!parsed.success) {
|
|
79
|
+
throw new Error(`Invalid input at tick ${index}: ${parsed.error.message}`);
|
|
80
|
+
}
|
|
81
|
+
return parsed.data;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
async function readAssertions(path, ticks) {
|
|
85
|
+
if (!path) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
const parsed = gameAssertions.safeParse(await readDocument(path));
|
|
89
|
+
if (!parsed.success) {
|
|
90
|
+
throw new Error(`Invalid game assertions: ${parsed.error.message}`);
|
|
91
|
+
}
|
|
92
|
+
const byTick = new Map();
|
|
93
|
+
for (const assertion of parsed.data.ticks) {
|
|
94
|
+
if (assertion.tick > ticks) {
|
|
95
|
+
throw new Error(`Assertion tick ${assertion.tick} exceeds requested ${ticks} ticks`);
|
|
96
|
+
}
|
|
97
|
+
if (byTick.has(assertion.tick)) {
|
|
98
|
+
throw new Error(`Duplicate assertion for tick ${assertion.tick}`);
|
|
99
|
+
}
|
|
100
|
+
byTick.set(assertion.tick, assertion);
|
|
101
|
+
}
|
|
102
|
+
return { byTick, tolerance: parsed.data.tolerance };
|
|
103
|
+
}
|
|
104
|
+
function firstDifference(expected, actual, path) {
|
|
105
|
+
if (isDeepStrictEqual(expected, actual)) {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
if (Array.isArray(expected) && Array.isArray(actual)) {
|
|
109
|
+
if (expected.length !== actual.length) {
|
|
110
|
+
return { path: `${path}.length`, expected: expected.length, actual: actual.length };
|
|
111
|
+
}
|
|
112
|
+
for (let index = 0; index < expected.length; index += 1) {
|
|
113
|
+
const difference = firstDifference(expected[index], actual[index], `${path}[${index}]`);
|
|
114
|
+
if (difference) {
|
|
115
|
+
return difference;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const expectedObject = jsonFields.safeParse(expected);
|
|
120
|
+
const actualObject = jsonFields.safeParse(actual);
|
|
121
|
+
if (expectedObject.success && actualObject.success) {
|
|
122
|
+
const expectedFields = expectedObject.data;
|
|
123
|
+
const actualFields = actualObject.data;
|
|
124
|
+
for (const key of new Set([...Object.keys(expectedFields), ...Object.keys(actualFields)])) {
|
|
125
|
+
const difference = firstDifference(expectedFields[key], actualFields[key], `${path}.${key}`);
|
|
126
|
+
if (difference) {
|
|
127
|
+
return difference;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return { path, expected: expected ?? null, actual: actual ?? null };
|
|
132
|
+
}
|
|
133
|
+
function checkTick(assertion, snapshot, events, tolerance) {
|
|
134
|
+
if (!assertion) {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
const failures = [];
|
|
138
|
+
const check = (path, expected, actual) => {
|
|
139
|
+
if (!isDeepStrictEqual(expected, actual)) {
|
|
140
|
+
failures.push({ tick: assertion.tick, path, expected, actual: actual ?? null });
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
if (assertion.sceneId !== undefined) {
|
|
144
|
+
check("sceneId", assertion.sceneId, snapshot.sceneId);
|
|
145
|
+
}
|
|
146
|
+
for (const entityAssertion of assertion.entities ?? []) {
|
|
147
|
+
const entity = snapshot.entities.find((candidate) => candidate.id === entityAssertion.id);
|
|
148
|
+
if (!entity) {
|
|
149
|
+
failures.push({ tick: assertion.tick, path: `entities.${entityAssertion.id}`, expected: "present", actual: "missing" });
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
for (const coordinate of ["x", "y"]) {
|
|
153
|
+
const expected = entityAssertion[coordinate];
|
|
154
|
+
if (expected !== undefined && Math.abs(entity[coordinate] - expected) > tolerance) {
|
|
155
|
+
failures.push({ tick: assertion.tick, path: `entities.${entity.id}.${coordinate}`, expected, actual: entity[coordinate] });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (entityAssertion.active !== undefined) {
|
|
159
|
+
check(`entities.${entity.id}.active`, entityAssertion.active, entity.active);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (assertion.events !== undefined) {
|
|
163
|
+
const difference = firstDifference(assertion.events, events, "events");
|
|
164
|
+
if (difference) {
|
|
165
|
+
failures.push({ tick: assertion.tick, ...difference });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return failures;
|
|
169
|
+
}
|
|
170
|
+
function validateCliDocument(value) {
|
|
171
|
+
const legacyVersion = z.object({ schemaVersion: z.union([z.literal(1), z.literal(2)]) }).safeParse(value);
|
|
172
|
+
if (legacyVersion.success) {
|
|
173
|
+
return validateGame(value);
|
|
174
|
+
}
|
|
175
|
+
const result = validateAnyGame(value);
|
|
176
|
+
return { valid: result.valid, document: result.valid ? result.document : undefined, issues: result.diagnostics,
|
|
177
|
+
diagnostics: result.diagnostics, errors: result.diagnostics.map((issue) => `${issue.path.join(".")}: ${issue.message}`) };
|
|
178
|
+
}
|
|
179
|
+
/** Register native game validation and deterministic simulation commands. */
|
|
180
|
+
export function registerGameCommands(program) {
|
|
181
|
+
const game = program.command("game").description("Validate and playtest native games");
|
|
182
|
+
registerGameSmokeCommand(game);
|
|
183
|
+
game
|
|
184
|
+
.command("validate <game_file>")
|
|
185
|
+
.description("Validate a native game document and its references")
|
|
186
|
+
.option("--json", "Print a machine-readable report")
|
|
187
|
+
.action(async (path, options) => {
|
|
188
|
+
try {
|
|
189
|
+
const report = validateCliDocument(await readDocument(path));
|
|
190
|
+
if (options.json) {
|
|
191
|
+
process.stdout.write(`${JSON.stringify(report)}\n`);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
process.stdout.write(report.valid
|
|
195
|
+
? "Game document is valid\n"
|
|
196
|
+
: `${report.errors.join("\n")}\n`);
|
|
197
|
+
}
|
|
198
|
+
if (!report.valid)
|
|
199
|
+
process.exitCode = 1;
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
printCommandError(error, options.json);
|
|
203
|
+
process.exitCode = 1;
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
game.command("bench <game_file>")
|
|
207
|
+
.description("Measure headless native game tick, script and sampled allocation costs")
|
|
208
|
+
.option("--ticks <count>", "Measured ticks", "1200")
|
|
209
|
+
.option("--warmup <count>", "Warmup ticks", "300")
|
|
210
|
+
.option("--seed <integer>", "Random seed", "1")
|
|
211
|
+
.option("--json", "Print a machine-readable report")
|
|
212
|
+
.action(async (path, options) => {
|
|
213
|
+
try {
|
|
214
|
+
const validated = validateCliDocument(await readDocument(path));
|
|
215
|
+
if (!validated.valid || !validated.document) {
|
|
216
|
+
throw new Error(validated.errors.join("\n"));
|
|
217
|
+
}
|
|
218
|
+
const report = await benchmarkNativeGame(validated.document, Number(options.ticks), Number(options.warmup), Number(options.seed));
|
|
219
|
+
process.stdout.write(`${JSON.stringify(report, null, options.json ? undefined : 2)}\n`);
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
printCommandError(error, options.json);
|
|
223
|
+
process.exitCode = 1;
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
game
|
|
227
|
+
.command("simulate <game_file>")
|
|
228
|
+
.description("Run a fixed number of game ticks without a renderer")
|
|
229
|
+
.requiredOption("--ticks <count>", "Number of ticks to run")
|
|
230
|
+
.option("--seed <integer>", "Random seed", "1")
|
|
231
|
+
.option("--inputs <file>", "JSON array of tick-indexed input frames")
|
|
232
|
+
.option("--assets-dir <directory>", "Prepared 3D collider files named <full-asset-id>.json")
|
|
233
|
+
.option("--expect-score <score>", "Fail if the final score differs")
|
|
234
|
+
.option("--expect-win", "Fail unless the win condition is reached")
|
|
235
|
+
.option("--assertions <file>", "JSON assertions for scene, entities, and ordered events at selected ticks")
|
|
236
|
+
.option("--verify-replay", "Resume at the midpoint and compare snapshots and events tick by tick")
|
|
237
|
+
.option("--json", "Print a machine-readable report")
|
|
238
|
+
.action(async (path, options) => {
|
|
239
|
+
try {
|
|
240
|
+
const validated = validateCliDocument(await readDocument(path));
|
|
241
|
+
if (!validated.valid || !validated.document) {
|
|
242
|
+
throw new Error(validated.errors.join("\n"));
|
|
243
|
+
}
|
|
244
|
+
const document = validated.document;
|
|
245
|
+
if (document.schemaVersion === 3) {
|
|
246
|
+
await simulateGame3D(document, options);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const ticks = nonnegativeInteger(options.ticks, "ticks");
|
|
250
|
+
const seed = nonnegativeInteger(options.seed, "seed");
|
|
251
|
+
const expectedScore = options.expectScore === undefined
|
|
252
|
+
? undefined
|
|
253
|
+
: nonnegativeInteger(options.expectScore, "expect-score");
|
|
254
|
+
const inputs = await readInputs(options.inputs, gameInputFrame);
|
|
255
|
+
const contract = await readAssertions(options.assertions, ticks);
|
|
256
|
+
const session = await createScriptedGameSession(document, seed);
|
|
257
|
+
let resumed;
|
|
258
|
+
try {
|
|
259
|
+
const events = [];
|
|
260
|
+
const initialAssertion = contract?.byTick.get(0);
|
|
261
|
+
const failures = initialAssertion
|
|
262
|
+
? checkTick(initialAssertion, session.snapshot(), [], contract?.tolerance ?? 1e-9)
|
|
263
|
+
: [];
|
|
264
|
+
const resumeTick = Math.floor(ticks / 2);
|
|
265
|
+
let replayDivergence;
|
|
266
|
+
const startReplay = async (saved) => {
|
|
267
|
+
resumed = await createScriptedGameSession(document, seed, saved);
|
|
268
|
+
const difference = firstDifference(saved, resumed.snapshot(), "snapshot");
|
|
269
|
+
if (difference) {
|
|
270
|
+
replayDivergence = { tick: saved.tick, ...difference };
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
if (options.verifyReplay && resumeTick === 0) {
|
|
274
|
+
await startReplay(session.snapshot());
|
|
275
|
+
}
|
|
276
|
+
for (let tick = 0; tick < ticks; tick += 1) {
|
|
277
|
+
const input = inputs[tick] ?? EMPTY_INPUT;
|
|
278
|
+
const result = session.step(input);
|
|
279
|
+
events.push(...result.events);
|
|
280
|
+
const assertion = contract?.byTick.get(result.tick);
|
|
281
|
+
const snapshot = assertion || (options.verifyReplay && result.tick >= resumeTick)
|
|
282
|
+
? session.snapshot()
|
|
283
|
+
: undefined;
|
|
284
|
+
if (assertion && snapshot) {
|
|
285
|
+
failures.push(...checkTick(assertion, snapshot, result.events, contract?.tolerance ?? 1e-9));
|
|
286
|
+
}
|
|
287
|
+
if (snapshot && options.verifyReplay && result.tick === resumeTick) {
|
|
288
|
+
await startReplay(snapshot);
|
|
289
|
+
}
|
|
290
|
+
if (resumed && snapshot && !replayDivergence && result.tick > resumeTick) {
|
|
291
|
+
const replayStep = resumed.step(input);
|
|
292
|
+
const difference = firstDifference(result.events, replayStep.events, "events")
|
|
293
|
+
?? firstDifference(snapshot, resumed.snapshot(), "snapshot");
|
|
294
|
+
if (difference) {
|
|
295
|
+
replayDivergence = { tick: result.tick, ...difference };
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const snapshot = session.snapshot();
|
|
300
|
+
const assertions = {
|
|
301
|
+
score: expectedScore === undefined || snapshot.score === expectedScore,
|
|
302
|
+
win: options.expectWin !== true || snapshot.won,
|
|
303
|
+
ticks: failures.length === 0,
|
|
304
|
+
replay: !replayDivergence
|
|
305
|
+
};
|
|
306
|
+
const replay = options.verifyReplay
|
|
307
|
+
? { resumeTick, verified: !replayDivergence, divergence: replayDivergence }
|
|
308
|
+
: undefined;
|
|
309
|
+
const report = {
|
|
310
|
+
ticks, seed, snapshot, events, assertions, failures,
|
|
311
|
+
replay,
|
|
312
|
+
ok: Object.values(assertions).every(Boolean)
|
|
313
|
+
};
|
|
314
|
+
if (options.json) {
|
|
315
|
+
process.stdout.write(`${JSON.stringify(report)}\n`);
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
process.stdout.write(`Tick ${snapshot.tick}: score ${snapshot.score}, won ${snapshot.won}\n`);
|
|
319
|
+
for (const failure of failures) {
|
|
320
|
+
process.stdout.write(`Tick ${failure.tick} ${failure.path}: expected ${JSON.stringify(failure.expected)}, got ${JSON.stringify(failure.actual)}\n`);
|
|
321
|
+
}
|
|
322
|
+
if (replayDivergence) {
|
|
323
|
+
process.stdout.write(`Replay diverged at tick ${replayDivergence.tick} ${replayDivergence.path}: expected ${JSON.stringify(replayDivergence.expected)}, got ${JSON.stringify(replayDivergence.actual)}\n`);
|
|
324
|
+
}
|
|
325
|
+
if (!assertions.score || !assertions.win) {
|
|
326
|
+
process.stdout.write("Game assertions failed\n");
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (!report.ok) {
|
|
330
|
+
process.exitCode = 1;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
finally {
|
|
334
|
+
resumed?.dispose();
|
|
335
|
+
session.dispose();
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
printCommandError(error, options.json);
|
|
340
|
+
process.exitCode = 1;
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
game
|
|
344
|
+
.command("capture <game_file>")
|
|
345
|
+
.description("Capture one headless game frame as PNG")
|
|
346
|
+
.requiredOption("--ticks <count>", "Tick to capture")
|
|
347
|
+
.requiredOption("--out <file>", "PNG output path")
|
|
348
|
+
.option("--seed <integer>", "Random seed", "1")
|
|
349
|
+
.option("--inputs <file>", "JSON array of tick-indexed input frames")
|
|
350
|
+
.option("--scale <factor>", "Output scale", "1")
|
|
351
|
+
.option("--backend <canvas2d|webgpu|webgl2>", "Capture backend. Defaults to WebGL2 for 3D", "canvas2d")
|
|
352
|
+
.option("--assets-dir <directory>", "Local media files named <full-asset-id>.<extension>")
|
|
353
|
+
.option("--json", "Print a machine-readable report")
|
|
354
|
+
.action(async (path, options, command) => {
|
|
355
|
+
try {
|
|
356
|
+
const validated = validateCliDocument(await readDocument(path));
|
|
357
|
+
if (!validated.valid || !validated.document) {
|
|
358
|
+
throw new Error(validated.errors.join("\n"));
|
|
359
|
+
}
|
|
360
|
+
if (validated.document.schemaVersion === 3) {
|
|
361
|
+
const backend = command.getOptionValueSource("backend") === "default" ? "webgl2" : options.backend;
|
|
362
|
+
await captureGame3D(validated.document, { ...options, backend });
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const ticks = nonnegativeInteger(options.ticks, "ticks");
|
|
366
|
+
if (ticks === 0)
|
|
367
|
+
throw new Error("ticks must be at least 1 for capture");
|
|
368
|
+
const seed = nonnegativeInteger(options.seed, "seed");
|
|
369
|
+
const scale = Number(options.scale);
|
|
370
|
+
if (!Number.isFinite(scale) || scale <= 0) {
|
|
371
|
+
throw new Error("scale must be a positive number");
|
|
372
|
+
}
|
|
373
|
+
if (options.backend !== "canvas2d" && options.backend !== "webgpu") {
|
|
374
|
+
throw new Error("backend must be canvas2d or webgpu");
|
|
375
|
+
}
|
|
376
|
+
const inputs = await readInputs(options.inputs, gameInputFrame);
|
|
377
|
+
const session = await createScriptedGameSession(validated.document, seed);
|
|
378
|
+
try {
|
|
379
|
+
let frame;
|
|
380
|
+
for (let tick = 0; tick < ticks; tick += 1) {
|
|
381
|
+
frame = session.step(inputs[tick] ?? EMPTY_INPUT).frame;
|
|
382
|
+
}
|
|
383
|
+
if (!frame)
|
|
384
|
+
throw new Error("Game produced no render frame");
|
|
385
|
+
const { captureGameFrame } = await import("@nodetool-ai/game-renderer/node");
|
|
386
|
+
const diagnostics = [];
|
|
387
|
+
const png = await captureGameFrame(frame, {
|
|
388
|
+
scale,
|
|
389
|
+
backend: options.backend,
|
|
390
|
+
effects: validated.document.renderEffects,
|
|
391
|
+
hudEffectOrder: validated.document.hudEffectOrder,
|
|
392
|
+
onDiagnostic: (message) => diagnostics.push(message),
|
|
393
|
+
resolveAsset: async (key) => {
|
|
394
|
+
const sourceId = validated.document?.assets[key]?.assetId;
|
|
395
|
+
if (!sourceId)
|
|
396
|
+
return null;
|
|
397
|
+
return (await readBuildAsset(options.assetsDir, sourceId))?.bytes ?? null;
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
await writeFile(options.out, png);
|
|
401
|
+
const report = { path: options.out, tick: frame.tick, bytes: png.byteLength, diagnostics };
|
|
402
|
+
process.stdout.write(options.json ? `${JSON.stringify(report)}\n` : `Captured tick ${report.tick} to ${report.path}\n${diagnostics.map((message) => `${message}\n`).join("")}`);
|
|
403
|
+
}
|
|
404
|
+
finally {
|
|
405
|
+
session.dispose();
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
catch (error) {
|
|
409
|
+
printCommandError(error, options.json);
|
|
410
|
+
process.exitCode = 1;
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
game
|
|
414
|
+
.command("build <game_file>")
|
|
415
|
+
.description("Build a standalone web player with local, content-addressed assets")
|
|
416
|
+
.requiredOption("--out <directory>", "Build output directory")
|
|
417
|
+
.option("--assets-dir <directory>", "Local media files named <full-asset-id>.<extension>")
|
|
418
|
+
.option("--json", "Print a machine-readable report")
|
|
419
|
+
.action(async (path, options) => {
|
|
420
|
+
try {
|
|
421
|
+
const validated = validateCliDocument(await readDocument(path));
|
|
422
|
+
if (!validated.valid || !validated.document) {
|
|
423
|
+
throw new Error(validated.errors.join("\n"));
|
|
424
|
+
}
|
|
425
|
+
const result = validated.document.schemaVersion === 3 ? await (await import("@nodetool-ai/game-renderer/build3d")).buildStandaloneGame3D({
|
|
426
|
+
document: validated.document, outputDir: resolve(options.out), resolveAsset: (assetId) => readBuildAsset(options.assetsDir, assetId)
|
|
427
|
+
}) : await (await import("@nodetool-ai/game-renderer/build")).buildStandaloneGame({
|
|
428
|
+
document: validated.document, outputDir: options.out, resolveAsset: (assetId) => readBuildAsset(options.assetsDir, assetId)
|
|
429
|
+
});
|
|
430
|
+
process.stdout.write(options.json ? `${JSON.stringify(result)}\n` : `Built game in ${result.outputDir}\n`);
|
|
431
|
+
}
|
|
432
|
+
catch (error) {
|
|
433
|
+
printCommandError(error, options.json);
|
|
434
|
+
process.exitCode = 1;
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
const EMPTY_INPUT = { pressed: [], justPressed: [] };
|
|
439
|
+
const tickAssertion3D = z.strictObject({
|
|
440
|
+
tick: z.number().int().nonnegative(), sceneId: z.string().min(1).optional(),
|
|
441
|
+
entities: z.array(z.strictObject({ id: z.string().min(1), x: z.number().finite().optional(), y: z.number().finite().optional(),
|
|
442
|
+
z: z.number().finite().optional(), active: z.boolean().optional(), grounded: z.boolean().optional() })).optional(),
|
|
443
|
+
events: z.array(z.union(gameEvent3D.options.map((variant) => variant.strict()))).optional()
|
|
444
|
+
});
|
|
445
|
+
async function readAssertions3D(path, ticks) {
|
|
446
|
+
if (!path) {
|
|
447
|
+
return undefined;
|
|
448
|
+
}
|
|
449
|
+
const parsed = gameAssertions.extend({ ticks: z.array(tickAssertion3D) }).safeParse(await readDocument(path));
|
|
450
|
+
if (!parsed.success) {
|
|
451
|
+
throw new Error(`Invalid 3D game assertions: ${parsed.error.message}`);
|
|
452
|
+
}
|
|
453
|
+
const byTick = new Map();
|
|
454
|
+
for (const assertion of parsed.data.ticks) {
|
|
455
|
+
if (assertion.tick > ticks) {
|
|
456
|
+
throw new Error(`Assertion tick ${assertion.tick} exceeds requested ${ticks} ticks`);
|
|
457
|
+
}
|
|
458
|
+
if (byTick.has(assertion.tick)) {
|
|
459
|
+
throw new Error(`Duplicate assertion for tick ${assertion.tick}`);
|
|
460
|
+
}
|
|
461
|
+
byTick.set(assertion.tick, assertion);
|
|
462
|
+
}
|
|
463
|
+
return { byTick, tolerance: parsed.data.tolerance };
|
|
464
|
+
}
|
|
465
|
+
function checkTick3D(assertion, snapshot, events, tolerance) {
|
|
466
|
+
const failures = [];
|
|
467
|
+
const check = (path, expected, actual) => {
|
|
468
|
+
if (!isDeepStrictEqual(expected, actual)) {
|
|
469
|
+
failures.push({ tick: assertion.tick, path, expected, actual: actual ?? null });
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
if (assertion.sceneId !== undefined) {
|
|
473
|
+
check("sceneId", assertion.sceneId, snapshot.sceneId);
|
|
474
|
+
}
|
|
475
|
+
for (const expected of assertion.entities ?? []) {
|
|
476
|
+
const entity = snapshot.entities.find((candidate) => candidate.id === expected.id);
|
|
477
|
+
if (!entity) {
|
|
478
|
+
check(`entities.${expected.id}`, "present", "missing");
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
for (const axis of ["x", "y", "z"]) {
|
|
482
|
+
if (expected[axis] !== undefined && Math.abs(entity.transform.position[axis] - expected[axis]) > tolerance) {
|
|
483
|
+
check(`entities.${entity.id}.${axis}`, expected[axis], entity.transform.position[axis]);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
if (expected.active !== undefined) {
|
|
487
|
+
check(`entities.${entity.id}.active`, expected.active, entity.active);
|
|
488
|
+
}
|
|
489
|
+
if (expected.grounded !== undefined) {
|
|
490
|
+
check(`entities.${entity.id}.grounded`, expected.grounded, entity.grounded);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
if (assertion.events !== undefined) {
|
|
494
|
+
const difference = firstDifference(assertion.events, events, "events");
|
|
495
|
+
if (difference) {
|
|
496
|
+
failures.push({ tick: assertion.tick, ...difference });
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return failures;
|
|
500
|
+
}
|
|
501
|
+
function sessionAssetOptions3D(directory) {
|
|
502
|
+
return { resolveCollider: async (binding) => {
|
|
503
|
+
const asset = await readBuildAsset(directory, binding.assetId);
|
|
504
|
+
if (!asset) {
|
|
505
|
+
throw new Error(`Prepared collider ${binding.assetId} is unavailable. Pass --assets-dir.`);
|
|
506
|
+
}
|
|
507
|
+
return decodePreparedGameCollider3D(asset.bytes, binding);
|
|
508
|
+
} };
|
|
509
|
+
}
|
|
510
|
+
async function simulateGame3D(document, options) {
|
|
511
|
+
const ticks = nonnegativeInteger(options.ticks, "ticks");
|
|
512
|
+
const seed = nonnegativeInteger(options.seed, "seed");
|
|
513
|
+
const expectedScore = options.expectScore === undefined ? undefined : nonnegativeInteger(options.expectScore, "expect-score");
|
|
514
|
+
const inputs = await readInputs(options.inputs, gameInputFrame3D);
|
|
515
|
+
const contract = await readAssertions3D(options.assertions, ticks);
|
|
516
|
+
const sessionOptions = sessionAssetOptions3D(options.assetsDir);
|
|
517
|
+
const session = await createGameSession3D(document, seed, undefined, sessionOptions);
|
|
518
|
+
let resumed;
|
|
519
|
+
try {
|
|
520
|
+
const events = [];
|
|
521
|
+
const initialAssertion = contract?.byTick.get(0);
|
|
522
|
+
const failures = initialAssertion ? checkTick3D(initialAssertion, session.snapshot(), [], contract?.tolerance ?? 1e-9) : [];
|
|
523
|
+
const resumeTick = Math.floor(ticks / 2);
|
|
524
|
+
let replayDivergence;
|
|
525
|
+
const startReplay = async (snapshot) => {
|
|
526
|
+
resumed = await createGameSession3D(document, seed, snapshot, sessionOptions);
|
|
527
|
+
const difference = firstDifference(snapshot, resumed.snapshot(), "snapshot");
|
|
528
|
+
if (difference) {
|
|
529
|
+
replayDivergence = { tick: snapshot.tick, ...difference };
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
if (options.verifyReplay && resumeTick === 0) {
|
|
533
|
+
await startReplay(session.snapshot());
|
|
534
|
+
}
|
|
535
|
+
for (let tick = 0; tick < ticks; tick++) {
|
|
536
|
+
if (tick % 240 === 0) {
|
|
537
|
+
await new Promise((resolveTick) => setTimeout(resolveTick, 0));
|
|
538
|
+
}
|
|
539
|
+
const input = inputs[tick] ?? gameInputFrame3D.parse({ pressed: [] });
|
|
540
|
+
const result = session.step(input);
|
|
541
|
+
events.push(...result.events);
|
|
542
|
+
const assertion = contract?.byTick.get(result.tick);
|
|
543
|
+
const snapshot = assertion || options.verifyReplay && result.tick >= resumeTick ? session.snapshot() : undefined;
|
|
544
|
+
if (assertion && snapshot) {
|
|
545
|
+
failures.push(...checkTick3D(assertion, snapshot, result.events, contract?.tolerance ?? 1e-9));
|
|
546
|
+
}
|
|
547
|
+
if (snapshot && options.verifyReplay && result.tick === resumeTick) {
|
|
548
|
+
await startReplay(snapshot);
|
|
549
|
+
}
|
|
550
|
+
if (snapshot && resumed && !replayDivergence && result.tick > resumeTick) {
|
|
551
|
+
const replayStep = resumed.step(input);
|
|
552
|
+
const difference = firstDifference(result.events, replayStep.events, "events") ?? firstDifference(snapshot, resumed.snapshot(), "snapshot");
|
|
553
|
+
if (difference) {
|
|
554
|
+
replayDivergence = { tick: result.tick, ...difference };
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
const snapshot = session.snapshot();
|
|
559
|
+
const assertions = { score: expectedScore === undefined || snapshot.score === expectedScore, win: options.expectWin !== true || snapshot.won,
|
|
560
|
+
ticks: failures.length === 0, replay: !replayDivergence };
|
|
561
|
+
const report = { dimension: "3d", ticks, seed, snapshot, state_hash: await hashGameSnapshot3D(snapshot), events, assertions, failures,
|
|
562
|
+
replay: options.verifyReplay ? { resumeTick, verified: !replayDivergence, divergence: replayDivergence } : undefined,
|
|
563
|
+
ok: Object.values(assertions).every(Boolean) };
|
|
564
|
+
if (options.json) {
|
|
565
|
+
process.stdout.write(`${JSON.stringify(report)}\n`);
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
process.stdout.write(`Tick ${snapshot.tick}: score ${snapshot.score}, won ${snapshot.won}\n`);
|
|
569
|
+
for (const failure of failures) {
|
|
570
|
+
process.stdout.write(`Tick ${failure.tick} ${failure.path}: expected ${JSON.stringify(failure.expected)}, got ${JSON.stringify(failure.actual)}\n`);
|
|
571
|
+
}
|
|
572
|
+
if (replayDivergence) {
|
|
573
|
+
process.stdout.write(`Replay diverged at tick ${replayDivergence.tick} ${replayDivergence.path}\n`);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
if (!report.ok) {
|
|
577
|
+
process.exitCode = 1;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
finally {
|
|
581
|
+
resumed?.dispose();
|
|
582
|
+
session.dispose();
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
async function captureGame3D(document, options) {
|
|
586
|
+
const ticks = nonnegativeInteger(options.ticks, "ticks");
|
|
587
|
+
if (ticks === 0) {
|
|
588
|
+
throw new Error("ticks must be at least 1 for capture");
|
|
589
|
+
}
|
|
590
|
+
const seed = nonnegativeInteger(options.seed, "seed");
|
|
591
|
+
const scale = Number(options.scale);
|
|
592
|
+
if (!Number.isFinite(scale) || scale <= 0 || scale > 4) {
|
|
593
|
+
throw new Error("3D capture scale must be greater than 0 and at most 4");
|
|
594
|
+
}
|
|
595
|
+
if (options.backend !== "webgl2") {
|
|
596
|
+
throw new Error("3D capture backend must be webgl2");
|
|
597
|
+
}
|
|
598
|
+
const inputs = await readInputs(options.inputs, gameInputFrame3D);
|
|
599
|
+
const session = await createGameSession3D(document, seed, undefined, sessionAssetOptions3D(options.assetsDir));
|
|
600
|
+
try {
|
|
601
|
+
for (let tick = 0; tick < ticks; tick++) {
|
|
602
|
+
session.step(inputs[tick] ?? gameInputFrame3D.parse({ pressed: [] }));
|
|
603
|
+
}
|
|
604
|
+
const frame = session.frame();
|
|
605
|
+
const stateHash = await hashGameSnapshot3D(session.snapshot());
|
|
606
|
+
const { captureGameFrame3D } = await import("@nodetool-ai/game-renderer/node3d");
|
|
607
|
+
const captured = await captureGameFrame3D(frame, { stateHash, interpolation: 1,
|
|
608
|
+
width: Math.round(document.presentation.hudWidth * scale), height: Math.round(document.presentation.hudHeight * scale),
|
|
609
|
+
resolveAsset: async (slot) => {
|
|
610
|
+
const binding = document.assets[slot];
|
|
611
|
+
const asset = binding ? await readBuildAsset(options.assetsDir, binding.assetId) : null;
|
|
612
|
+
return asset ? { bytes: asset.bytes, digest: binding.digest } : null;
|
|
613
|
+
} });
|
|
614
|
+
const path = resolve(options.out);
|
|
615
|
+
await writeFile(path, captured.png);
|
|
616
|
+
const report = { dimension: "3d", path, tick: frame.tick, bytes: captured.png.byteLength, state_hash: stateHash,
|
|
617
|
+
capabilities: captured.capabilities, stats: captured.stats, projected_bounds: captured.projectedBounds, diagnostics: [] };
|
|
618
|
+
process.stdout.write(options.json ? `${JSON.stringify(report)}\n` : `Captured tick ${report.tick} to ${report.path}\n`);
|
|
619
|
+
}
|
|
620
|
+
finally {
|
|
621
|
+
session.dispose();
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
//# sourceMappingURL=game.js.map
|