@quenty/studio-bridge 0.21.1 → 0.22.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/CHANGELOG.md +10 -0
- package/README.md +109 -17
- package/build-scripts/transform-add-session-attribute.lua +1 -0
- package/deploy.nevermore.json +10 -0
- package/dist/src/bridge/bridge-connection.d.ts +26 -2
- package/dist/src/bridge/bridge-connection.d.ts.map +1 -1
- package/dist/src/bridge/bridge-connection.js +159 -14
- package/dist/src/bridge/bridge-connection.js.map +1 -1
- package/dist/src/bridge/bridge-connection.test.js +81 -0
- package/dist/src/bridge/bridge-connection.test.js.map +1 -1
- package/dist/src/bridge/bridge-session.d.ts +35 -2
- package/dist/src/bridge/bridge-session.d.ts.map +1 -1
- package/dist/src/bridge/bridge-session.js +185 -28
- package/dist/src/bridge/bridge-session.js.map +1 -1
- package/dist/src/bridge/bridge-session.test.js +6 -4
- package/dist/src/bridge/bridge-session.test.js.map +1 -1
- package/dist/src/bridge/index.d.ts +1 -1
- package/dist/src/bridge/index.d.ts.map +1 -1
- package/dist/src/bridge/index.js.map +1 -1
- package/dist/src/bridge/internal/bridge-client.d.ts +4 -0
- package/dist/src/bridge/internal/bridge-client.d.ts.map +1 -1
- package/dist/src/bridge/internal/bridge-client.js +20 -7
- package/dist/src/bridge/internal/bridge-client.js.map +1 -1
- package/dist/src/bridge/internal/bridge-client.test.js +18 -0
- package/dist/src/bridge/internal/bridge-client.test.js.map +1 -1
- package/dist/src/bridge/internal/bridge-host.d.ts +13 -1
- package/dist/src/bridge/internal/bridge-host.d.ts.map +1 -1
- package/dist/src/bridge/internal/bridge-host.js +35 -0
- package/dist/src/bridge/internal/bridge-host.js.map +1 -1
- package/dist/src/bridge/internal/bridge-host.test.js +31 -0
- package/dist/src/bridge/internal/bridge-host.test.js.map +1 -1
- package/dist/src/bridge/internal/hand-off.d.ts.map +1 -1
- package/dist/src/bridge/internal/hand-off.js +4 -1
- package/dist/src/bridge/internal/hand-off.js.map +1 -1
- package/dist/src/bridge/internal/host-protocol.d.ts +8 -0
- package/dist/src/bridge/internal/host-protocol.d.ts.map +1 -1
- package/dist/src/bridge/internal/host-protocol.js +120 -13
- package/dist/src/bridge/internal/host-protocol.js.map +1 -1
- package/dist/src/bridge/internal/host-protocol.test.js +13 -0
- package/dist/src/bridge/internal/host-protocol.test.js.map +1 -1
- package/dist/src/bridge/internal/instance-state.d.ts +9 -0
- package/dist/src/bridge/internal/instance-state.d.ts.map +1 -0
- package/dist/src/bridge/internal/instance-state.js +28 -0
- package/dist/src/bridge/internal/instance-state.js.map +1 -0
- package/dist/src/bridge/internal/transport-client.d.ts.map +1 -1
- package/dist/src/bridge/internal/transport-client.js +2 -1
- package/dist/src/bridge/internal/transport-client.js.map +1 -1
- package/dist/src/bridge/internal/transport-server.d.ts.map +1 -1
- package/dist/src/bridge/internal/transport-server.js +5 -1
- package/dist/src/bridge/internal/transport-server.js.map +1 -1
- package/dist/src/bridge/types.d.ts +43 -4
- package/dist/src/bridge/types.d.ts.map +1 -1
- package/dist/src/bridge/types.js.map +1 -1
- package/dist/src/cli/adapters/cli-command-adapter-handler.test.js +24 -0
- package/dist/src/cli/adapters/cli-command-adapter-handler.test.js.map +1 -1
- package/dist/src/cli/adapters/cli-command-adapter.d.ts +6 -0
- package/dist/src/cli/adapters/cli-command-adapter.d.ts.map +1 -1
- package/dist/src/cli/adapters/cli-command-adapter.js +107 -11
- package/dist/src/cli/adapters/cli-command-adapter.js.map +1 -1
- package/dist/src/cli/adapters/group-builder.d.ts +3 -0
- package/dist/src/cli/adapters/group-builder.d.ts.map +1 -1
- package/dist/src/cli/adapters/group-builder.js +34 -15
- package/dist/src/cli/adapters/group-builder.js.map +1 -1
- package/dist/src/cli/adapters/group-builder.test.js +26 -2
- package/dist/src/cli/adapters/group-builder.test.js.map +1 -1
- package/dist/src/cli/adapters/help-formatter.d.ts.map +1 -1
- package/dist/src/cli/adapters/help-formatter.js +4 -3
- package/dist/src/cli/adapters/help-formatter.js.map +1 -1
- package/dist/src/cli/adapters/help-formatter.test.js +1 -1
- package/dist/src/cli/adapters/help-formatter.test.js.map +1 -1
- package/dist/src/cli/adapters/playtest-edit-guard.test.d.ts +2 -0
- package/dist/src/cli/adapters/playtest-edit-guard.test.d.ts.map +1 -0
- package/dist/src/cli/adapters/playtest-edit-guard.test.js +28 -0
- package/dist/src/cli/adapters/playtest-edit-guard.test.js.map +1 -0
- package/dist/src/cli/args/global-args.d.ts +1 -1
- package/dist/src/cli/args/global-args.d.ts.map +1 -1
- package/dist/src/cli/cli-output-context.d.ts +14 -0
- package/dist/src/cli/cli-output-context.d.ts.map +1 -0
- package/dist/src/cli/cli-output-context.js +39 -0
- package/dist/src/cli/cli-output-context.js.map +1 -0
- package/dist/src/cli/cli-output-context.test.d.ts +2 -0
- package/dist/src/cli/cli-output-context.test.d.ts.map +1 -0
- package/dist/src/cli/cli-output-context.test.js +38 -0
- package/dist/src/cli/cli-output-context.test.js.map +1 -0
- package/dist/src/cli/cli.js +40 -17
- package/dist/src/cli/cli.js.map +1 -1
- package/dist/src/cli/managed-studio-run.d.ts +21 -0
- package/dist/src/cli/managed-studio-run.d.ts.map +1 -0
- package/dist/src/cli/managed-studio-run.js +75 -0
- package/dist/src/cli/managed-studio-run.js.map +1 -0
- package/dist/src/cli/managed-studio-run.test.d.ts +2 -0
- package/dist/src/cli/managed-studio-run.test.d.ts.map +1 -0
- package/dist/src/cli/managed-studio-run.test.js +52 -0
- package/dist/src/cli/managed-studio-run.test.js.map +1 -0
- package/dist/src/cli/resolve-session.js +1 -1
- package/dist/src/cli/resolve-session.js.map +1 -1
- package/dist/src/cli/resolve-session.test.js +1 -1
- package/dist/src/cli/resolve-session.test.js.map +1 -1
- package/dist/src/cli/script-executor.d.ts +13 -1
- package/dist/src/cli/script-executor.d.ts.map +1 -1
- package/dist/src/cli/script-executor.js +77 -47
- package/dist/src/cli/script-executor.js.map +1 -1
- package/dist/src/commands/console/exec/exec.d.ts +17 -0
- package/dist/src/commands/console/exec/exec.d.ts.map +1 -1
- package/dist/src/commands/console/exec/exec.js +39 -7
- package/dist/src/commands/console/exec/exec.js.map +1 -1
- package/dist/src/commands/console/exec/exec.test.js +62 -3
- package/dist/src/commands/console/exec/exec.test.js.map +1 -1
- package/dist/src/commands/console/logs/logs.d.ts +30 -2
- package/dist/src/commands/console/logs/logs.d.ts.map +1 -1
- package/dist/src/commands/console/logs/logs.js +82 -7
- package/dist/src/commands/console/logs/logs.js.map +1 -1
- package/dist/src/commands/console/logs/logs.test.js +63 -4
- package/dist/src/commands/console/logs/logs.test.js.map +1 -1
- package/dist/src/commands/explorer/export/export.d.ts +19 -0
- package/dist/src/commands/explorer/export/export.d.ts.map +1 -0
- package/dist/src/commands/explorer/export/export.js +37 -0
- package/dist/src/commands/explorer/export/export.js.map +1 -0
- package/dist/src/commands/explorer/export/export.test.d.ts +2 -0
- package/dist/src/commands/explorer/export/export.test.d.ts.map +1 -0
- package/dist/src/commands/explorer/export/export.test.js +25 -0
- package/dist/src/commands/explorer/export/export.test.js.map +1 -0
- package/dist/src/commands/explorer/find/find.d.ts +28 -0
- package/dist/src/commands/explorer/find/find.d.ts.map +1 -0
- package/dist/src/commands/explorer/find/find.js +75 -0
- package/dist/src/commands/explorer/find/find.js.map +1 -0
- package/dist/src/commands/explorer/find/find.test.d.ts +2 -0
- package/dist/src/commands/explorer/find/find.test.d.ts.map +1 -0
- package/dist/src/commands/explorer/find/find.test.js +44 -0
- package/dist/src/commands/explorer/find/find.test.js.map +1 -0
- package/dist/src/commands/explorer/grep/grep.d.ts +24 -0
- package/dist/src/commands/explorer/grep/grep.d.ts.map +1 -0
- package/dist/src/commands/explorer/grep/grep.js +63 -0
- package/dist/src/commands/explorer/grep/grep.js.map +1 -0
- package/dist/src/commands/explorer/grep/grep.test.d.ts +2 -0
- package/dist/src/commands/explorer/grep/grep.test.d.ts.map +1 -0
- package/dist/src/commands/explorer/grep/grep.test.js +42 -0
- package/dist/src/commands/explorer/grep/grep.test.js.map +1 -0
- package/dist/src/commands/explorer/import/import.d.ts +21 -0
- package/dist/src/commands/explorer/import/import.d.ts.map +1 -0
- package/dist/src/commands/explorer/import/import.js +37 -0
- package/dist/src/commands/explorer/import/import.js.map +1 -0
- package/dist/src/commands/explorer/import/import.test.d.ts +2 -0
- package/dist/src/commands/explorer/import/import.test.d.ts.map +1 -0
- package/dist/src/commands/explorer/import/import.test.js +45 -0
- package/dist/src/commands/explorer/import/import.test.js.map +1 -0
- package/dist/src/commands/formatters.test.js +7 -1
- package/dist/src/commands/formatters.test.js.map +1 -1
- package/dist/src/commands/framework/action-loader.d.ts +5 -1
- package/dist/src/commands/framework/action-loader.d.ts.map +1 -1
- package/dist/src/commands/framework/action-loader.js +9 -2
- package/dist/src/commands/framework/action-loader.js.map +1 -1
- package/dist/src/commands/framework/action-loader.test.js +23 -0
- package/dist/src/commands/framework/action-loader.test.js.map +1 -1
- package/dist/src/commands/framework/arg-builder.d.ts +15 -2
- package/dist/src/commands/framework/arg-builder.d.ts.map +1 -1
- package/dist/src/commands/framework/arg-builder.js +22 -2
- package/dist/src/commands/framework/arg-builder.js.map +1 -1
- package/dist/src/commands/framework/define-command.d.ts +19 -3
- package/dist/src/commands/framework/define-command.d.ts.map +1 -1
- package/dist/src/commands/framework/define-command.js.map +1 -1
- package/dist/src/commands/framework/index.d.ts +1 -1
- package/dist/src/commands/framework/index.d.ts.map +1 -1
- package/dist/src/commands/framework/index.js.map +1 -1
- package/dist/src/commands/index.d.ts +11 -0
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/index.js +11 -0
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/commands/linux/inject-credentials/inject-credentials.d.ts.map +1 -1
- package/dist/src/commands/linux/inject-credentials/inject-credentials.js +1 -3
- package/dist/src/commands/linux/inject-credentials/inject-credentials.js.map +1 -1
- package/dist/src/commands/linux/setup/setup.d.ts.map +1 -1
- package/dist/src/commands/linux/setup/setup.js +1 -3
- package/dist/src/commands/linux/setup/setup.js.map +1 -1
- package/dist/src/commands/linux/status/status.d.ts +9 -1
- package/dist/src/commands/linux/status/status.d.ts.map +1 -1
- package/dist/src/commands/linux/status/status.js +66 -86
- package/dist/src/commands/linux/status/status.js.map +1 -1
- package/dist/src/commands/playtest/player/add/add.d.ts +17 -0
- package/dist/src/commands/playtest/player/add/add.d.ts.map +1 -0
- package/dist/src/commands/playtest/player/add/add.js +45 -0
- package/dist/src/commands/playtest/player/add/add.js.map +1 -0
- package/dist/src/commands/playtest/player/list/list.d.ts +13 -0
- package/dist/src/commands/playtest/player/list/list.d.ts.map +1 -0
- package/dist/src/commands/playtest/player/list/list.js +33 -0
- package/dist/src/commands/playtest/player/list/list.js.map +1 -0
- package/dist/src/commands/playtest/player/playtest-players.d.ts +36 -0
- package/dist/src/commands/playtest/player/playtest-players.d.ts.map +1 -0
- package/dist/src/commands/playtest/player/playtest-players.js +187 -0
- package/dist/src/commands/playtest/player/playtest-players.js.map +1 -0
- package/dist/src/commands/playtest/player/playtest-players.test.d.ts +2 -0
- package/dist/src/commands/playtest/player/playtest-players.test.d.ts.map +1 -0
- package/dist/src/commands/playtest/player/playtest-players.test.js +89 -0
- package/dist/src/commands/playtest/player/playtest-players.test.js.map +1 -0
- package/dist/src/commands/playtest/player/remove/remove.d.ts +17 -0
- package/dist/src/commands/playtest/player/remove/remove.d.ts.map +1 -0
- package/dist/src/commands/playtest/player/remove/remove.js +42 -0
- package/dist/src/commands/playtest/player/remove/remove.js.map +1 -0
- package/dist/src/commands/playtest/playtest-sessions.d.ts +49 -0
- package/dist/src/commands/playtest/playtest-sessions.d.ts.map +1 -0
- package/dist/src/commands/playtest/playtest-sessions.js +283 -0
- package/dist/src/commands/playtest/playtest-sessions.js.map +1 -0
- package/dist/src/commands/playtest/playtest-sessions.test.d.ts +2 -0
- package/dist/src/commands/playtest/playtest-sessions.test.d.ts.map +1 -0
- package/dist/src/commands/playtest/playtest-sessions.test.js +87 -0
- package/dist/src/commands/playtest/playtest-sessions.test.js.map +1 -0
- package/dist/src/commands/playtest/restart/restart.d.ts +23 -0
- package/dist/src/commands/playtest/restart/restart.d.ts.map +1 -0
- package/dist/src/commands/playtest/restart/restart.js +105 -0
- package/dist/src/commands/playtest/restart/restart.js.map +1 -0
- package/dist/src/commands/playtest/run/run.d.ts +47 -0
- package/dist/src/commands/playtest/run/run.d.ts.map +1 -0
- package/dist/src/commands/playtest/run/run.js +137 -0
- package/dist/src/commands/playtest/run/run.js.map +1 -0
- package/dist/src/commands/playtest/start/start.d.ts +42 -0
- package/dist/src/commands/playtest/start/start.d.ts.map +1 -0
- package/dist/src/commands/playtest/start/start.js +70 -0
- package/dist/src/commands/playtest/start/start.js.map +1 -0
- package/dist/src/commands/playtest/stop/stop.d.ts +15 -0
- package/dist/src/commands/playtest/stop/stop.d.ts.map +1 -0
- package/dist/src/commands/playtest/stop/stop.js +24 -0
- package/dist/src/commands/playtest/stop/stop.js.map +1 -0
- package/dist/src/commands/process/close/close.d.ts +19 -10
- package/dist/src/commands/process/close/close.d.ts.map +1 -1
- package/dist/src/commands/process/close/close.js +118 -15
- package/dist/src/commands/process/close/close.js.map +1 -1
- package/dist/src/commands/process/close/close.test.d.ts +2 -0
- package/dist/src/commands/process/close/close.test.d.ts.map +1 -0
- package/dist/src/commands/process/close/close.test.js +190 -0
- package/dist/src/commands/process/close/close.test.js.map +1 -0
- package/dist/src/commands/process/info/info.d.ts +45 -5
- package/dist/src/commands/process/info/info.d.ts.map +1 -1
- package/dist/src/commands/process/info/info.js +117 -13
- package/dist/src/commands/process/info/info.js.map +1 -1
- package/dist/src/commands/process/info/info.test.js +140 -38
- package/dist/src/commands/process/info/info.test.js.map +1 -1
- package/dist/src/commands/process/launch/launch.d.ts +11 -1
- package/dist/src/commands/process/launch/launch.d.ts.map +1 -1
- package/dist/src/commands/process/launch/launch.js +37 -7
- package/dist/src/commands/process/launch/launch.js.map +1 -1
- package/dist/src/commands/process/launch/launch.test.js +99 -20
- package/dist/src/commands/process/launch/launch.test.js.map +1 -1
- package/dist/src/commands/process/list/list.d.ts +2 -1
- package/dist/src/commands/process/list/list.d.ts.map +1 -1
- package/dist/src/commands/process/list/list.js +9 -6
- package/dist/src/commands/process/list/list.js.map +1 -1
- package/dist/src/commands/process/list/list.test.js +1 -0
- package/dist/src/commands/process/list/list.test.js.map +1 -1
- package/dist/src/commands/process/run/run.d.ts +9 -0
- package/dist/src/commands/process/run/run.d.ts.map +1 -1
- package/dist/src/commands/process/run/run.js +15 -5
- package/dist/src/commands/process/run/run.js.map +1 -1
- package/dist/src/commands/serve/serve.d.ts +2 -0
- package/dist/src/commands/serve/serve.d.ts.map +1 -1
- package/dist/src/commands/serve/serve.js +17 -4
- package/dist/src/commands/serve/serve.js.map +1 -1
- package/dist/src/commands/serve/serve.test.js +9 -2
- package/dist/src/commands/serve/serve.test.js.map +1 -1
- package/dist/src/commands/viewport/screenshot/screenshot.d.ts.map +1 -1
- package/dist/src/commands/viewport/screenshot/screenshot.js +4 -1
- package/dist/src/commands/viewport/screenshot/screenshot.js.map +1 -1
- package/dist/src/commands/viewport/screenshot/screenshot.test.js +5 -9
- package/dist/src/commands/viewport/screenshot/screenshot.test.js.map +1 -1
- package/dist/src/deploy/deploy-places.d.ts +39 -0
- package/dist/src/deploy/deploy-places.d.ts.map +1 -0
- package/dist/src/deploy/deploy-places.js +162 -0
- package/dist/src/deploy/deploy-places.js.map +1 -0
- package/dist/src/deploy/deploy-places.test.d.ts +2 -0
- package/dist/src/deploy/deploy-places.test.d.ts.map +1 -0
- package/dist/src/deploy/deploy-places.test.js +96 -0
- package/dist/src/deploy/deploy-places.test.js.map +1 -0
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/plugin/persistent-plugin-installer.d.ts.map +1 -1
- package/dist/src/plugin/persistent-plugin-installer.js +2 -1
- package/dist/src/plugin/persistent-plugin-installer.js.map +1 -1
- package/dist/src/plugin/persistent-plugin-installer.test.js +3 -0
- package/dist/src/plugin/persistent-plugin-installer.test.js.map +1 -1
- package/dist/src/plugin/plugin-build-version.d.ts +7 -0
- package/dist/src/plugin/plugin-build-version.d.ts.map +1 -0
- package/dist/src/plugin/plugin-build-version.js +42 -0
- package/dist/src/plugin/plugin-build-version.js.map +1 -0
- package/dist/src/plugin/plugin-build-version.test.d.ts +2 -0
- package/dist/src/plugin/plugin-build-version.test.d.ts.map +1 -0
- package/dist/src/plugin/plugin-build-version.test.js +41 -0
- package/dist/src/plugin/plugin-build-version.test.js.map +1 -0
- package/dist/src/plugin/plugin-injector.d.ts.map +1 -1
- package/dist/src/plugin/plugin-injector.js +7 -1
- package/dist/src/plugin/plugin-injector.js.map +1 -1
- package/dist/src/process/studio-process-closer.d.ts +35 -0
- package/dist/src/process/studio-process-closer.d.ts.map +1 -0
- package/dist/src/process/studio-process-closer.js +129 -0
- package/dist/src/process/studio-process-closer.js.map +1 -0
- package/dist/src/process/studio-process-closer.test.d.ts +2 -0
- package/dist/src/process/studio-process-closer.test.d.ts.map +1 -0
- package/dist/src/process/studio-process-closer.test.js +80 -0
- package/dist/src/process/studio-process-closer.test.js.map +1 -0
- package/dist/src/process/studio-settings.d.ts +14 -0
- package/dist/src/process/studio-settings.d.ts.map +1 -0
- package/dist/src/process/studio-settings.js +50 -0
- package/dist/src/process/studio-settings.js.map +1 -0
- package/dist/src/process/studio-settings.test.d.ts +2 -0
- package/dist/src/process/studio-settings.test.d.ts.map +1 -0
- package/dist/src/process/studio-settings.test.js +16 -0
- package/dist/src/process/studio-settings.test.js.map +1 -0
- package/dist/src/process/studio-window-state.d.ts +13 -0
- package/dist/src/process/studio-window-state.d.ts.map +1 -0
- package/dist/src/process/studio-window-state.js +48 -0
- package/dist/src/process/studio-window-state.js.map +1 -0
- package/dist/src/server/studio-bridge-server.d.ts +3 -1
- package/dist/src/server/studio-bridge-server.d.ts.map +1 -1
- package/dist/src/server/studio-bridge-server.js +12 -4
- package/dist/src/server/studio-bridge-server.js.map +1 -1
- package/dist/src/server/web-socket-protocol.d.ts +173 -6
- package/dist/src/server/web-socket-protocol.d.ts.map +1 -1
- package/dist/src/server/web-socket-protocol.js +244 -1
- package/dist/src/server/web-socket-protocol.js.map +1 -1
- package/dist/src/server/web-socket-protocol.test.js +48 -0
- package/dist/src/server/web-socket-protocol.test.js.map +1 -1
- package/dist/src/test/e2e/persistent-session.test.js +121 -0
- package/dist/src/test/e2e/persistent-session.test.js.map +1 -1
- package/dist/src/test/e2e/split-server.test.d.ts +3 -5
- package/dist/src/test/e2e/split-server.test.d.ts.map +1 -1
- package/dist/src/test/e2e/split-server.test.js +3 -5
- package/dist/src/test/e2e/split-server.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docker/Dockerfile +3 -0
- package/package.json +8 -6
- package/src/bridge/bridge-connection.test.ts +126 -0
- package/src/bridge/bridge-connection.ts +217 -22
- package/src/bridge/bridge-session.test.ts +6 -4
- package/src/bridge/bridge-session.ts +273 -28
- package/src/bridge/index.ts +3 -0
- package/src/bridge/internal/bridge-client.test.ts +23 -0
- package/src/bridge/internal/bridge-client.ts +25 -7
- package/src/bridge/internal/bridge-host.test.ts +38 -0
- package/src/bridge/internal/bridge-host.ts +47 -0
- package/src/bridge/internal/hand-off.ts +4 -1
- package/src/bridge/internal/host-protocol.test.ts +15 -0
- package/src/bridge/internal/host-protocol.ts +148 -37
- package/src/bridge/internal/instance-state.ts +34 -0
- package/src/bridge/internal/transport-client.ts +2 -1
- package/src/bridge/internal/transport-server.ts +5 -1
- package/src/bridge/types.ts +47 -2
- package/src/cli/adapters/cli-command-adapter-handler.test.ts +28 -0
- package/src/cli/adapters/cli-command-adapter.ts +150 -18
- package/src/cli/adapters/group-builder.test.ts +34 -2
- package/src/cli/adapters/group-builder.ts +52 -20
- package/src/cli/adapters/help-formatter.test.ts +1 -1
- package/src/cli/adapters/help-formatter.ts +4 -3
- package/src/cli/adapters/playtest-edit-guard.test.ts +54 -0
- package/src/cli/args/global-args.ts +1 -1
- package/src/cli/cli-output-context.test.ts +55 -0
- package/src/cli/cli-output-context.ts +50 -0
- package/src/cli/cli.ts +49 -17
- package/src/cli/managed-studio-run.test.ts +71 -0
- package/src/cli/managed-studio-run.ts +135 -0
- package/src/cli/resolve-session.test.ts +1 -1
- package/src/cli/resolve-session.ts +1 -1
- package/src/cli/script-executor.ts +99 -51
- package/src/commands/console/exec/exec.test.ts +96 -3
- package/src/commands/console/exec/exec.ts +59 -6
- package/src/commands/console/exec/execute.lua +356 -240
- package/src/commands/console/exec/execute.spec.lua +286 -0
- package/src/commands/console/logs/logs.test.ts +76 -4
- package/src/commands/console/logs/logs.ts +132 -17
- package/src/commands/console/logs/query-logs.lua +85 -52
- package/src/commands/console/logs/query-logs.spec.lua +132 -0
- package/src/commands/explorer/export/export-instances.lua +108 -0
- package/src/commands/explorer/export/export-instances.spec.lua +87 -0
- package/src/commands/explorer/export/export.test.ts +27 -0
- package/src/commands/explorer/export/export.ts +60 -0
- package/src/commands/explorer/find/find-instances.lua +174 -0
- package/src/commands/explorer/find/find-instances.spec.lua +122 -0
- package/src/commands/explorer/find/find.test.ts +53 -0
- package/src/commands/explorer/find/find.ts +113 -0
- package/src/commands/explorer/grep/grep-scripts.lua +214 -0
- package/src/commands/explorer/grep/grep-scripts.spec.lua +130 -0
- package/src/commands/explorer/grep/grep.test.ts +45 -0
- package/src/commands/explorer/grep/grep.ts +93 -0
- package/src/commands/explorer/import/import-instances.lua +106 -0
- package/src/commands/explorer/import/import-instances.spec.lua +84 -0
- package/src/commands/explorer/import/import.test.ts +60 -0
- package/src/commands/explorer/import/import.ts +66 -0
- package/src/commands/explorer/query/query-data-model.lua +124 -152
- package/src/commands/explorer/query/query-data-model.spec.lua +150 -0
- package/src/commands/formatters.test.ts +7 -1
- package/src/commands/framework/action-loader.test.ts +28 -0
- package/src/commands/framework/action-loader.ts +10 -2
- package/src/commands/framework/arg-builder.ts +26 -3
- package/src/commands/framework/define-command.ts +32 -3
- package/src/commands/framework/index.ts +1 -0
- package/src/commands/index.ts +50 -0
- package/src/commands/linux/inject-credentials/inject-credentials.ts +1 -3
- package/src/commands/linux/setup/setup.ts +1 -3
- package/src/commands/linux/status/status.ts +105 -98
- package/src/commands/playtest/player/add/add.ts +85 -0
- package/src/commands/playtest/player/list/list.ts +57 -0
- package/src/commands/playtest/player/playtest-players.test.ts +146 -0
- package/src/commands/playtest/player/playtest-players.ts +270 -0
- package/src/commands/playtest/player/remove/remove.ts +78 -0
- package/src/commands/playtest/playtest-sessions.test.ts +143 -0
- package/src/commands/playtest/playtest-sessions.ts +417 -0
- package/src/commands/playtest/restart/restart.ts +199 -0
- package/src/commands/playtest/run/playtest-runner.luau +264 -0
- package/src/commands/playtest/run/playtest-runner.spec.lua +71 -0
- package/src/commands/playtest/run/run-playtest-script.lua +139 -0
- package/src/commands/playtest/run/run-playtest-script.spec.lua +43 -0
- package/src/commands/playtest/run/run.ts +239 -0
- package/src/commands/playtest/start/start-playtest.lua +108 -0
- package/src/commands/playtest/start/start.ts +138 -0
- package/src/commands/playtest/stop/end-playtest.lua +47 -0
- package/src/commands/playtest/stop/stop.ts +51 -0
- package/src/commands/process/close/close.test.ts +250 -0
- package/src/commands/process/close/close.ts +183 -17
- package/src/commands/process/info/info.test.ts +198 -44
- package/src/commands/process/info/info.ts +204 -15
- package/src/commands/process/info/query-state.lua +42 -29
- package/src/commands/process/info/query-state.spec.lua +39 -0
- package/src/commands/process/launch/launch.test.ts +138 -21
- package/src/commands/process/launch/launch.ts +69 -9
- package/src/commands/process/list/list.test.ts +1 -0
- package/src/commands/process/list/list.ts +14 -6
- package/src/commands/process/run/run.ts +26 -5
- package/src/commands/serve/serve.test.ts +17 -2
- package/src/commands/serve/serve.ts +25 -6
- package/src/commands/viewport/screenshot/capture-screenshot.lua +175 -182
- package/src/commands/viewport/screenshot/capture-screenshot.spec.lua +129 -0
- package/src/commands/viewport/screenshot/screenshot.test.ts +7 -10
- package/src/commands/viewport/screenshot/screenshot.ts +6 -1
- package/src/deploy/deploy-places.test.ts +127 -0
- package/src/deploy/deploy-places.ts +229 -0
- package/src/index.ts +11 -0
- package/src/plugin/persistent-plugin-installer.test.ts +4 -0
- package/src/plugin/persistent-plugin-installer.ts +2 -1
- package/src/plugin/plugin-build-version.test.ts +55 -0
- package/src/plugin/plugin-build-version.ts +53 -0
- package/src/plugin/plugin-injector.ts +7 -1
- package/src/process/studio-process-closer.test.ts +107 -0
- package/src/process/studio-process-closer.ts +187 -0
- package/src/process/studio-settings.test.ts +18 -0
- package/src/process/studio-settings.ts +61 -0
- package/src/process/studio-window-state.ts +65 -0
- package/src/server/studio-bridge-server.ts +15 -4
- package/src/server/web-socket-protocol.test.ts +55 -0
- package/src/server/web-socket-protocol.ts +468 -8
- package/src/test/e2e/persistent-session.test.ts +137 -0
- package/src/test/e2e/split-server.test.ts +3 -5
- package/templates/studio-bridge-plugin/default.project.json +3 -0
- package/templates/studio-bridge-plugin/src/Shared/ActionRouter.lua +208 -159
- package/templates/studio-bridge-plugin/src/Shared/ActionRouter.spec.lua +418 -0
- package/templates/studio-bridge-plugin/src/Shared/BuiltInActions.lua +94 -0
- package/templates/studio-bridge-plugin/src/Shared/BuiltInActions.spec.lua +166 -0
- package/templates/studio-bridge-plugin/src/Shared/DiscoveryStateMachine.lua +118 -137
- package/templates/studio-bridge-plugin/src/Shared/DiscoveryStateMachine.spec.lua +228 -0
- package/templates/studio-bridge-plugin/src/Shared/MessageBuffer.lua +80 -109
- package/templates/studio-bridge-plugin/src/Shared/MessageBuffer.spec.lua +116 -0
- package/templates/studio-bridge-plugin/src/Shared/StudioBridgeConnection.lua +233 -0
- package/templates/studio-bridge-plugin/src/Shared/StudioBridgeConnection.spec.lua +239 -0
- package/templates/studio-bridge-plugin/src/Shared/StudioBridgeLogUtils.lua +53 -0
- package/templates/studio-bridge-plugin/src/Shared/StudioBridgeLogUtils.spec.lua +27 -0
- package/templates/studio-bridge-plugin/src/Shared/StudioBridgeSessionUtils.lua +164 -0
- package/templates/studio-bridge-plugin/src/Shared/StudioBridgeSessionUtils.spec.lua +159 -0
- package/templates/studio-bridge-plugin/src/StudioBridgePlugin.server.lua +266 -368
- package/templates/studio-bridge-plugin/src/Vendor/png.lua +8 -2
- package/test/default.project.json +41 -0
- package/test/jest.config.lua +3 -0
- package/test/scripts/Server/ServerMain.server.lua +10 -0
- package/tsconfig.json +1 -0
- package/templates/studio-bridge-plugin/src/Shared/Protocol.lua +0 -132
- package/templates/studio-bridge-plugin-test/test/actions.test.lua +0 -580
- package/templates/studio-bridge-plugin-test/test/discovery.test.lua +0 -622
- package/templates/studio-bridge-plugin-test/test/execute-handler.test.lua +0 -517
- package/templates/studio-bridge-plugin-test/test/hash-lifecycle.test.lua +0 -814
- package/templates/studio-bridge-plugin-test/test/integration.test.lua +0 -1020
- package/templates/studio-bridge-plugin-test/test/new-actions.test.lua +0 -339
- package/templates/studio-bridge-plugin-test/test/plugin-entry.test.lua +0 -493
- package/templates/studio-bridge-plugin-test/test/protocol.test.lua +0 -506
- package/templates/studio-bridge-plugin-test/test/roblox-mocks.lua +0 -108
- package/templates/studio-bridge-plugin-test/test/test-runner.lua +0 -112
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* - Honors `--output` (file write), `--open`, `--watch`, `--interval`
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import * as path from 'path';
|
|
12
13
|
import type { Argv, CommandModule } from 'yargs';
|
|
13
14
|
import { OutputHelper } from '@quenty/cli-output-helpers';
|
|
14
15
|
import {
|
|
@@ -16,10 +17,20 @@ import {
|
|
|
16
17
|
type ResultReporter,
|
|
17
18
|
formatJson,
|
|
18
19
|
} from '@quenty/cli-output-helpers/reporting';
|
|
19
|
-
import { BridgeConnection } from '../../bridge/index.js';
|
|
20
|
-
import type { SessionContext } from '../../bridge/index.js';
|
|
21
|
-
import type {
|
|
20
|
+
import { BridgeConnection, SessionNotFoundError } from '../../bridge/index.js';
|
|
21
|
+
import type { BridgeSession, SessionContext } from '../../bridge/index.js';
|
|
22
|
+
import type {
|
|
23
|
+
CommandDefinition,
|
|
24
|
+
SessionTargeting,
|
|
25
|
+
} from '../../commands/framework/define-command.js';
|
|
22
26
|
import { toYargsOptions } from '../../commands/framework/arg-builder.js';
|
|
27
|
+
import { explainMissingPlaytestContextAsync } from '../../commands/playtest/playtest-sessions.js';
|
|
28
|
+
import { tryFindFolderInstanceAsync } from '../../deploy/deploy-places.js';
|
|
29
|
+
import {
|
|
30
|
+
addWarning,
|
|
31
|
+
getWarnings,
|
|
32
|
+
warnIfPluginStaleAsync,
|
|
33
|
+
} from '../cli-output-context.js';
|
|
23
34
|
|
|
24
35
|
/** Args injected by the adapter (not defined on CommandDefinition). */
|
|
25
36
|
export interface AdapterArgs {
|
|
@@ -51,8 +62,12 @@ function extractCommandArgs(
|
|
|
51
62
|
def: CommandDefinition
|
|
52
63
|
): Record<string, unknown> {
|
|
53
64
|
const commandArgs: Record<string, unknown> = {};
|
|
54
|
-
for (const name of Object.
|
|
55
|
-
if (
|
|
65
|
+
for (const [name, argDef] of Object.entries(def.args)) {
|
|
66
|
+
if (argDef.kind === 'passthrough') {
|
|
67
|
+
commandArgs[name] = ((argv['--'] as unknown[] | undefined) ?? []).map(
|
|
68
|
+
String
|
|
69
|
+
);
|
|
70
|
+
} else if (name in argv) {
|
|
56
71
|
commandArgs[name] = argv[name];
|
|
57
72
|
}
|
|
58
73
|
}
|
|
@@ -81,15 +96,33 @@ async function executeCommandAsync(
|
|
|
81
96
|
waitForSessions: def.scope === 'connection',
|
|
82
97
|
}));
|
|
83
98
|
|
|
99
|
+
const targeting: SessionTargeting = {
|
|
100
|
+
target: argv.target as string | undefined,
|
|
101
|
+
context: argv.context as SessionContext | undefined,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Connection commands start once Studios have connected, so this can look now
|
|
105
|
+
if (def.scope === 'connection' && !def.coversAllSessions) {
|
|
106
|
+
await tryTargetFolderInstanceAsync(connection, targeting);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (connection.isHostOutdated) {
|
|
110
|
+
addWarning(
|
|
111
|
+
`The bridge host on port ${connection.port} runs an older studio-bridge, which may drop newer options. Restart it (e.g. stop 'studio-bridge serve') to use this version.`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
84
115
|
try {
|
|
85
116
|
if (def.scope === 'session') {
|
|
86
|
-
const session = await connection
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
117
|
+
const session = await resolveTargetSessionAsync(connection, targeting);
|
|
118
|
+
if (def.changesDataModel && !argv.allowEdit) {
|
|
119
|
+
assertNotEditingDuringPlaytest(connection, session);
|
|
120
|
+
}
|
|
121
|
+
await warnIfPluginStaleAsync([session.info]);
|
|
122
|
+
return await (def.handler as any)(session, commandArgs, connection);
|
|
91
123
|
}
|
|
92
|
-
|
|
124
|
+
await warnIfPluginStaleAsync(connection.listSessions());
|
|
125
|
+
return await (def.handler as any)(connection, commandArgs, targeting);
|
|
93
126
|
} finally {
|
|
94
127
|
if (!existingConnection) {
|
|
95
128
|
await connection.disconnectAsync();
|
|
@@ -97,12 +130,85 @@ async function executeCommandAsync(
|
|
|
97
130
|
}
|
|
98
131
|
}
|
|
99
132
|
|
|
133
|
+
/**
|
|
134
|
+
* The session `targeting` names. When it names none and several Studios are
|
|
135
|
+
* connected, the one with the current folder's deploy.nevermore.json place open.
|
|
136
|
+
*/
|
|
137
|
+
async function resolveTargetSessionAsync(
|
|
138
|
+
connection: BridgeConnection,
|
|
139
|
+
targeting: SessionTargeting
|
|
140
|
+
): Promise<BridgeSession> {
|
|
141
|
+
try {
|
|
142
|
+
return await connection.resolveSessionAsync(
|
|
143
|
+
targeting.target,
|
|
144
|
+
targeting.context
|
|
145
|
+
);
|
|
146
|
+
} catch (err) {
|
|
147
|
+
if (
|
|
148
|
+
err instanceof SessionNotFoundError &&
|
|
149
|
+
(await tryTargetFolderInstanceAsync(connection, targeting))
|
|
150
|
+
) {
|
|
151
|
+
return connection
|
|
152
|
+
.resolveSessionAsync(targeting.target, targeting.context)
|
|
153
|
+
.catch(async (retryErr: unknown) => {
|
|
154
|
+
throw await explainMissingPlaytestContextAsync(connection, retryErr);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
throw await explainMissingPlaytestContextAsync(connection, err);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Without a --target, targets the one connected Studio that has the current
|
|
163
|
+
* folder's deploy.nevermore.json place open, and says so.
|
|
164
|
+
*/
|
|
165
|
+
async function tryTargetFolderInstanceAsync(
|
|
166
|
+
connection: BridgeConnection,
|
|
167
|
+
targeting: SessionTargeting
|
|
168
|
+
): Promise<boolean> {
|
|
169
|
+
if (targeting.target) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
const folder = await tryFindFolderInstanceAsync(connection, process.cwd());
|
|
173
|
+
if (!folder) {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
targeting.target = folder.instanceId;
|
|
178
|
+
OutputHelper.hint(
|
|
179
|
+
`Using ${folder.instanceId}, which has '${
|
|
180
|
+
folder.deployPlace.selector
|
|
181
|
+
}' of ${path.relative(process.cwd(), folder.deployPlace.configPath)} open`
|
|
182
|
+
);
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Refuses to change an edit DataModel while a playtest of it runs: the
|
|
188
|
+
* playtest runs a copy, so the change would not show up there.
|
|
189
|
+
*/
|
|
190
|
+
export function assertNotEditingDuringPlaytest(
|
|
191
|
+
connection: BridgeConnection,
|
|
192
|
+
session: BridgeSession
|
|
193
|
+
): void {
|
|
194
|
+
if (session.context !== 'edit') return;
|
|
195
|
+
|
|
196
|
+
const playtest = connection
|
|
197
|
+
.listSessions()
|
|
198
|
+
.find(
|
|
199
|
+
(s) => s.instanceId === session.info.instanceId && s.context === 'server'
|
|
200
|
+
);
|
|
201
|
+
if (playtest) {
|
|
202
|
+
throw new Error(
|
|
203
|
+
`A playtest of '${session.info.placeName}' is running, so this would change Edit, not the playtest. Target the playtest with --context server (or client), or pass --allow-edit to change Edit anyway.`
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
100
208
|
/** Inject version/diagnostic warnings into JSON result objects. */
|
|
101
209
|
function injectWarnings(result: unknown): unknown {
|
|
102
|
-
const warnings = (
|
|
103
|
-
|
|
104
|
-
| undefined;
|
|
105
|
-
if (!warnings || warnings.length === 0) return result;
|
|
210
|
+
const warnings = getWarnings();
|
|
211
|
+
if (warnings.length === 0) return result;
|
|
106
212
|
if (typeof result === 'object' && result !== null && !Array.isArray(result)) {
|
|
107
213
|
return { ...result, _warnings: warnings };
|
|
108
214
|
}
|
|
@@ -162,7 +268,10 @@ export function buildYargsCommand(
|
|
|
162
268
|
const { positionals, options: yargsOptions } = toYargsOptions(def.args);
|
|
163
269
|
|
|
164
270
|
const positionalSuffix = positionals
|
|
165
|
-
.map((p) =>
|
|
271
|
+
.map((p) => {
|
|
272
|
+
const name = p.options.array ? `${p.name}..` : p.name;
|
|
273
|
+
return p.options.demandOption ? `<${name}>` : `[${name}]`;
|
|
274
|
+
})
|
|
166
275
|
.join(' ');
|
|
167
276
|
|
|
168
277
|
const command = positionalSuffix
|
|
@@ -177,6 +286,12 @@ export function buildYargsCommand(
|
|
|
177
286
|
yargs.positional(pos.name, pos.options as any);
|
|
178
287
|
}
|
|
179
288
|
|
|
289
|
+
for (const argDef of Object.values(def.args)) {
|
|
290
|
+
if (argDef.kind === 'passthrough') {
|
|
291
|
+
yargs.epilogue(`-- <args..> ${argDef.description}`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
180
295
|
for (const [name, opt] of Object.entries(yargsOptions)) {
|
|
181
296
|
yargs.option(name, opt as any);
|
|
182
297
|
}
|
|
@@ -185,7 +300,7 @@ export function buildYargsCommand(
|
|
|
185
300
|
yargs.option('target', {
|
|
186
301
|
alias: 't',
|
|
187
302
|
type: 'string',
|
|
188
|
-
describe: 'Target session
|
|
303
|
+
describe: 'Target session or instance ID',
|
|
189
304
|
});
|
|
190
305
|
yargs.option('context', {
|
|
191
306
|
type: 'string',
|
|
@@ -194,6 +309,14 @@ export function buildYargsCommand(
|
|
|
194
309
|
});
|
|
195
310
|
}
|
|
196
311
|
|
|
312
|
+
if (def.changesDataModel && def.scope === 'session') {
|
|
313
|
+
yargs.option('allow-edit', {
|
|
314
|
+
type: 'boolean',
|
|
315
|
+
default: false,
|
|
316
|
+
describe: 'Allow changing Edit while a playtest of it runs',
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
197
320
|
yargs.option('format', {
|
|
198
321
|
type: 'string',
|
|
199
322
|
choices: ['text', 'json'],
|
|
@@ -248,7 +371,16 @@ export function buildYargsCommand(
|
|
|
248
371
|
await runOnceAsync(def, commandArgs, argv, reporter, connect);
|
|
249
372
|
}
|
|
250
373
|
} catch (err) {
|
|
251
|
-
|
|
374
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
375
|
+
if (explicitFormat === 'json') {
|
|
376
|
+
console.log(
|
|
377
|
+
formatJson(injectWarnings({ success: false, error: message }), {
|
|
378
|
+
pretty: process.stdout.isTTY,
|
|
379
|
+
})
|
|
380
|
+
);
|
|
381
|
+
} else {
|
|
382
|
+
OutputHelper.error(message);
|
|
383
|
+
}
|
|
252
384
|
process.exit(1);
|
|
253
385
|
}
|
|
254
386
|
},
|
|
@@ -112,14 +112,14 @@ describe('buildGroupCommands', () => {
|
|
|
112
112
|
expect(consoleMod!.command).toBe('console <command>');
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
-
it('group commands have descriptions', () => {
|
|
115
|
+
it('group commands have descriptions that name their subcommands', () => {
|
|
116
116
|
const registry = makeRegistry();
|
|
117
117
|
const result = buildGroupCommands(registry);
|
|
118
118
|
|
|
119
119
|
const consoleMod = result.groups.find((g) =>
|
|
120
120
|
(g.command as string).startsWith('console')
|
|
121
121
|
);
|
|
122
|
-
expect(consoleMod!.describe).toBe('Execute code and view logs');
|
|
122
|
+
expect(consoleMod!.describe).toBe('Execute code and view logs: exec, logs');
|
|
123
123
|
});
|
|
124
124
|
|
|
125
125
|
it('group builder registers subcommands', () => {
|
|
@@ -136,6 +136,38 @@ describe('buildGroupCommands', () => {
|
|
|
136
136
|
expect(yargs.commands).toHaveLength(2);
|
|
137
137
|
});
|
|
138
138
|
|
|
139
|
+
it('nests a group with a space under its first word', () => {
|
|
140
|
+
const registry = makeRegistry();
|
|
141
|
+
registry.register(
|
|
142
|
+
defineCommand({
|
|
143
|
+
group: 'console player',
|
|
144
|
+
name: 'list',
|
|
145
|
+
description: 'List players',
|
|
146
|
+
category: 'execution',
|
|
147
|
+
safety: 'read',
|
|
148
|
+
scope: 'connection',
|
|
149
|
+
args: {},
|
|
150
|
+
handler: async () => ({}),
|
|
151
|
+
})
|
|
152
|
+
);
|
|
153
|
+
const result = buildGroupCommands(registry);
|
|
154
|
+
|
|
155
|
+
const consoleMods = result.groups.filter((g) =>
|
|
156
|
+
(g.command as string).startsWith('console')
|
|
157
|
+
);
|
|
158
|
+
expect(consoleMods).toHaveLength(1);
|
|
159
|
+
|
|
160
|
+
const yargs = createMockYargs();
|
|
161
|
+
(consoleMods[0].builder as any)(yargs);
|
|
162
|
+
expect(yargs.commands).toHaveLength(3);
|
|
163
|
+
|
|
164
|
+
const playerMod = yargs.commands[2];
|
|
165
|
+
expect(playerMod.command).toBe('player <command>');
|
|
166
|
+
const playerYargs = createMockYargs();
|
|
167
|
+
playerMod.builder(playerYargs);
|
|
168
|
+
expect(playerYargs.commands.map((c: any) => c.command)).toEqual(['list']);
|
|
169
|
+
});
|
|
170
|
+
|
|
139
171
|
it('returns empty arrays for empty registry', () => {
|
|
140
172
|
const registry = new CommandRegistry();
|
|
141
173
|
const result = buildGroupCommands(registry);
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
* Grouped commands become parent commands with subcommands:
|
|
6
6
|
* `console exec <code>` → `console` parent, `exec` subcommand
|
|
7
7
|
*
|
|
8
|
+
* A group name with a space nests under its first word:
|
|
9
|
+
* `playtest player list` → `player` subcommand group of `playtest`
|
|
10
|
+
*
|
|
8
11
|
* Top-level commands (group = null) are returned as standalone modules:
|
|
9
12
|
* `serve`, `mcp`, `terminal`
|
|
10
13
|
*/
|
|
@@ -21,7 +24,8 @@ const GROUP_DESCRIPTIONS: Record<string, string> = {
|
|
|
21
24
|
viewport: 'Screenshots and camera control',
|
|
22
25
|
data: 'Load and save serialized data',
|
|
23
26
|
playtest: 'Control play test sessions',
|
|
24
|
-
|
|
27
|
+
'playtest player': 'List, add and remove the players of a multiplayer test',
|
|
28
|
+
process: 'Open and manage Studio',
|
|
25
29
|
plugin: 'Manage the bridge plugin',
|
|
26
30
|
action: 'Invoke a Studio action',
|
|
27
31
|
linux: 'Linux/Wine environment management',
|
|
@@ -50,26 +54,12 @@ export function buildGroupCommands(
|
|
|
50
54
|
const groups: CommandModule[] = [];
|
|
51
55
|
const topLevel: CommandModule[] = [];
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const commands = registry.getByGroup(groupName);
|
|
56
|
-
const description =
|
|
57
|
-
GROUP_DESCRIPTIONS[groupName] ?? `${groupName} commands`;
|
|
57
|
+
const allGroups = registry.getGroups();
|
|
58
|
+
const topGroups = [...new Set(allGroups.map((name) => name.split(' ')[0]))];
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
builder: (yargs) => {
|
|
63
|
-
for (const cmd of commands) {
|
|
64
|
-
yargs.command(buildYargsCommand(cmd, options) as any);
|
|
65
|
-
}
|
|
66
|
-
return yargs.demandCommand(
|
|
67
|
-
1,
|
|
68
|
-
`Run 'studio-bridge ${groupName} --help' for available commands`
|
|
69
|
-
);
|
|
70
|
-
},
|
|
71
|
-
handler: () => {},
|
|
72
|
-
});
|
|
60
|
+
// Grouped commands → parent module with subcommands
|
|
61
|
+
for (const groupName of topGroups) {
|
|
62
|
+
groups.push(buildGroupModule(registry, allGroups, groupName, options));
|
|
73
63
|
}
|
|
74
64
|
|
|
75
65
|
// Top-level commands (group = null) → standalone modules
|
|
@@ -79,3 +69,45 @@ export function buildGroupCommands(
|
|
|
79
69
|
|
|
80
70
|
return { groups, topLevel };
|
|
81
71
|
}
|
|
72
|
+
|
|
73
|
+
function buildGroupModule(
|
|
74
|
+
registry: CommandRegistry,
|
|
75
|
+
allGroups: string[],
|
|
76
|
+
groupName: string,
|
|
77
|
+
options: GroupBuilderOptions
|
|
78
|
+
): CommandModule {
|
|
79
|
+
const commands = registry.getByGroup(groupName);
|
|
80
|
+
const subgroups = allGroups.filter(
|
|
81
|
+
(name) =>
|
|
82
|
+
name.startsWith(`${groupName} `) &&
|
|
83
|
+
!name.slice(groupName.length + 1).includes(' ')
|
|
84
|
+
);
|
|
85
|
+
// Naming the subcommands lets a reader find e.g. `process launch` from the top-level help
|
|
86
|
+
const names = [
|
|
87
|
+
...commands.map((cmd) => cmd.name),
|
|
88
|
+
...subgroups.map((subgroup) => subgroup.split(' ').pop()),
|
|
89
|
+
];
|
|
90
|
+
const description = `${
|
|
91
|
+
GROUP_DESCRIPTIONS[groupName] ?? `${groupName} commands`
|
|
92
|
+
}: ${names.join(', ')}`;
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
command: `${groupName.split(' ').pop()} <command>`,
|
|
96
|
+
describe: description,
|
|
97
|
+
builder: (yargs) => {
|
|
98
|
+
for (const cmd of commands) {
|
|
99
|
+
yargs.command(buildYargsCommand(cmd, options) as any);
|
|
100
|
+
}
|
|
101
|
+
for (const subgroup of subgroups) {
|
|
102
|
+
yargs.command(
|
|
103
|
+
buildGroupModule(registry, allGroups, subgroup, options) as any
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
return yargs.demandCommand(
|
|
107
|
+
1,
|
|
108
|
+
`Run 'studio-bridge ${groupName} --help' for available commands`
|
|
109
|
+
);
|
|
110
|
+
},
|
|
111
|
+
handler: () => {},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
@@ -85,7 +85,7 @@ describe('formatGroupedHelp', () => {
|
|
|
85
85
|
it('includes group descriptions', () => {
|
|
86
86
|
const help = formatGroupedHelp(makeRegistry());
|
|
87
87
|
expect(help).toContain('Execute code and view logs');
|
|
88
|
-
expect(help).toContain('
|
|
88
|
+
expect(help).toContain('Open and manage Studio');
|
|
89
89
|
});
|
|
90
90
|
|
|
91
91
|
it('returns empty for empty registry', () => {
|
|
@@ -12,7 +12,7 @@ const GROUP_DESCRIPTIONS: Record<string, string> = {
|
|
|
12
12
|
viewport: 'Screenshots and camera control',
|
|
13
13
|
data: 'Load and save serialized data',
|
|
14
14
|
playtest: 'Control play test sessions',
|
|
15
|
-
process: '
|
|
15
|
+
process: 'Open and manage Studio',
|
|
16
16
|
plugin: 'Manage the bridge plugin',
|
|
17
17
|
action: 'Invoke a Studio action',
|
|
18
18
|
};
|
|
@@ -36,10 +36,11 @@ export function formatGroupedHelp(registry: CommandRegistry): string {
|
|
|
36
36
|
|
|
37
37
|
for (const cmd of registry.getAll()) {
|
|
38
38
|
if (cmd.group !== null) {
|
|
39
|
+
const topGroup = cmd.group.split(' ')[0];
|
|
39
40
|
if (cmd.category === 'execution') {
|
|
40
|
-
executionGroups.add(
|
|
41
|
+
executionGroups.add(topGroup);
|
|
41
42
|
} else {
|
|
42
|
-
infrastructureGroups.add(
|
|
43
|
+
infrastructureGroups.add(topGroup);
|
|
43
44
|
}
|
|
44
45
|
} else {
|
|
45
46
|
const entry = { name: cmd.name, description: cmd.description };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { assertNotEditingDuringPlaytest } from './cli-command-adapter.js';
|
|
3
|
+
|
|
4
|
+
function createSession(context: string, instanceId = 'test-place-3f9a') {
|
|
5
|
+
return {
|
|
6
|
+
context,
|
|
7
|
+
info: { instanceId, placeName: 'test-place.rbxl', context },
|
|
8
|
+
} as any;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function createConnection(contexts: string[]) {
|
|
12
|
+
return {
|
|
13
|
+
listSessions: () =>
|
|
14
|
+
contexts.map((context) => ({ instanceId: 'test-place-3f9a', context })),
|
|
15
|
+
} as any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe('assertNotEditingDuringPlaytest', () => {
|
|
19
|
+
it('refuses to change Edit while its playtest runs', () => {
|
|
20
|
+
expect(() =>
|
|
21
|
+
assertNotEditingDuringPlaytest(
|
|
22
|
+
createConnection(['edit', 'server', 'client']),
|
|
23
|
+
createSession('edit')
|
|
24
|
+
)
|
|
25
|
+
).toThrow(/playtest of 'test-place.rbxl' is running/);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('allows changing Edit with no playtest running', () => {
|
|
29
|
+
expect(() =>
|
|
30
|
+
assertNotEditingDuringPlaytest(
|
|
31
|
+
createConnection(['edit']),
|
|
32
|
+
createSession('edit')
|
|
33
|
+
)
|
|
34
|
+
).not.toThrow();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('allows changing the playtest itself', () => {
|
|
38
|
+
expect(() =>
|
|
39
|
+
assertNotEditingDuringPlaytest(
|
|
40
|
+
createConnection(['edit', 'server']),
|
|
41
|
+
createSession('server')
|
|
42
|
+
)
|
|
43
|
+
).not.toThrow();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('ignores playtests of other Studios', () => {
|
|
47
|
+
expect(() =>
|
|
48
|
+
assertNotEditingDuringPlaytest(
|
|
49
|
+
createConnection(['edit', 'server']),
|
|
50
|
+
createSession('edit', 'other-place-1111')
|
|
51
|
+
)
|
|
52
|
+
).not.toThrow();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
vi.mock('../plugin/plugin-build-version.js', () => ({
|
|
4
|
+
getPluginBuildVersionAsync: async () => 'current',
|
|
5
|
+
}));
|
|
6
|
+
|
|
7
|
+
import { OutputHelper } from '@quenty/cli-output-helpers';
|
|
8
|
+
import {
|
|
9
|
+
addWarning,
|
|
10
|
+
clearWarnings,
|
|
11
|
+
getWarnings,
|
|
12
|
+
setJsonOutput,
|
|
13
|
+
warnIfPluginStaleAsync,
|
|
14
|
+
} from './cli-output-context.js';
|
|
15
|
+
|
|
16
|
+
describe('cli-output-context', () => {
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
clearWarnings();
|
|
19
|
+
setJsonOutput(false);
|
|
20
|
+
vi.restoreAllMocks();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('prints warnings right away in text mode', () => {
|
|
24
|
+
const warn = vi.spyOn(OutputHelper, 'warn').mockImplementation(() => {});
|
|
25
|
+
|
|
26
|
+
addWarning('careful');
|
|
27
|
+
|
|
28
|
+
expect(warn).toHaveBeenCalledWith('careful');
|
|
29
|
+
expect(getWarnings()).toEqual(['careful']);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('only collects warnings in JSON mode', () => {
|
|
33
|
+
const warn = vi.spyOn(OutputHelper, 'warn').mockImplementation(() => {});
|
|
34
|
+
setJsonOutput(true);
|
|
35
|
+
|
|
36
|
+
addWarning('careful');
|
|
37
|
+
addWarning('careful');
|
|
38
|
+
|
|
39
|
+
expect(warn).not.toHaveBeenCalled();
|
|
40
|
+
expect(getWarnings()).toEqual(['careful']);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('warns about plugins built from a different template', async () => {
|
|
44
|
+
setJsonOutput(true);
|
|
45
|
+
|
|
46
|
+
await warnIfPluginStaleAsync([
|
|
47
|
+
{ sessionId: 'a-edit', placeName: 'A', pluginVersion: 'current' },
|
|
48
|
+
{ sessionId: 'b-edit', placeName: 'B', pluginVersion: 'old' },
|
|
49
|
+
] as any);
|
|
50
|
+
|
|
51
|
+
expect(getWarnings()).toEqual([
|
|
52
|
+
expect.stringContaining("'B' (b-edit) is out of date"),
|
|
53
|
+
]);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-wide output state: whether stdout carries JSON, and warnings about
|
|
3
|
+
* the CLI's own setup (outdated CLI, stale Studio plugin). Text output prints
|
|
4
|
+
* warnings to stderr as they come up. JSON output carries them in the
|
|
5
|
+
* result's `_warnings` field instead, so they are not lost.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { OutputHelper } from '@quenty/cli-output-helpers';
|
|
9
|
+
import type { SessionInfo } from '../bridge/index.js';
|
|
10
|
+
import { getPluginBuildVersionAsync } from '../plugin/plugin-build-version.js';
|
|
11
|
+
|
|
12
|
+
let isJsonOutput = false;
|
|
13
|
+
const warnings: string[] = [];
|
|
14
|
+
|
|
15
|
+
export function setJsonOutput(json: boolean): void {
|
|
16
|
+
isJsonOutput = json;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function isJsonOutputEnabled(): boolean {
|
|
20
|
+
return isJsonOutput;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function addWarning(message: string): void {
|
|
24
|
+
if (warnings.includes(message)) return;
|
|
25
|
+
warnings.push(message);
|
|
26
|
+
if (!isJsonOutput) {
|
|
27
|
+
OutputHelper.warn(message);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function getWarnings(): readonly string[] {
|
|
32
|
+
return warnings;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function clearWarnings(): void {
|
|
36
|
+
warnings.length = 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function warnIfPluginStaleAsync(
|
|
40
|
+
sessions: SessionInfo[]
|
|
41
|
+
): Promise<void> {
|
|
42
|
+
const expected = await getPluginBuildVersionAsync();
|
|
43
|
+
for (const session of sessions) {
|
|
44
|
+
if (session.pluginVersion !== expected) {
|
|
45
|
+
addWarning(
|
|
46
|
+
`The studio-bridge plugin in '${session.placeName}' (${session.sessionId}) is out of date. Run 'studio-bridge plugin install' to update it.`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|