@vgai/live 0.5.2 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/editor.d.ts +78 -55
  3. package/dist/editor.js +129 -76
  4. package/dist/game-client/bridge-heartbeat.d.ts +49 -0
  5. package/dist/game-client/bridge-heartbeat.js +46 -0
  6. package/dist/game-client/bridge-transport.d.ts +75 -0
  7. package/dist/game-client/bridge-transport.js +19 -0
  8. package/dist/game-client/client.d.ts +293 -0
  9. package/dist/game-client/client.js +706 -0
  10. package/dist/game-client/errors.d.ts +57 -0
  11. package/dist/game-client/errors.js +76 -0
  12. package/dist/game-client/events-matcher.d.ts +41 -0
  13. package/dist/game-client/events-matcher.js +68 -0
  14. package/dist/game-client/failure-block.d.ts +93 -0
  15. package/dist/game-client/failure-block.js +97 -0
  16. package/dist/game-client/fast-forward.d.ts +125 -0
  17. package/dist/game-client/fast-forward.js +122 -0
  18. package/dist/game-client/hidden-recovery.d.ts +85 -0
  19. package/dist/game-client/hidden-recovery.js +105 -0
  20. package/dist/game-client/index.d.ts +40 -0
  21. package/dist/game-client/index.js +26 -0
  22. package/dist/game-client/perf-sampling.d.ts +56 -0
  23. package/dist/game-client/perf-sampling.js +85 -0
  24. package/dist/game-client/relay-transport.d.ts +100 -0
  25. package/dist/game-client/relay-transport.js +237 -0
  26. package/dist/game-client/screenshot-target.d.ts +60 -0
  27. package/dist/game-client/screenshot-target.js +68 -0
  28. package/dist/game-client/state-cap.d.ts +7 -0
  29. package/dist/game-client/state-cap.js +21 -0
  30. package/dist/game-client/types.d.ts +128 -0
  31. package/dist/game-client/types.js +15 -0
  32. package/dist/game-client/wait-for.d.ts +155 -0
  33. package/dist/game-client/wait-for.js +229 -0
  34. package/dist/game.d.ts +47 -18
  35. package/dist/game.js +59 -16
  36. package/dist/index.d.ts +46 -21
  37. package/dist/index.js +51 -20
  38. package/dist/session.d.ts +4 -4
  39. package/dist/session.js +7 -7
  40. package/dist/tools.d.ts +12 -3
  41. package/dist/tools.js +15 -6
  42. package/package.json +10 -5
  43. package/src/editor.ts +142 -96
  44. package/src/game-client/bridge-heartbeat.ts +61 -0
  45. package/src/game-client/bridge-transport.ts +73 -0
  46. package/src/game-client/client.ts +836 -0
  47. package/src/game-client/errors.ts +96 -0
  48. package/src/game-client/events-matcher.ts +106 -0
  49. package/src/game-client/failure-block.ts +199 -0
  50. package/src/game-client/fast-forward.ts +175 -0
  51. package/src/game-client/hidden-recovery.ts +149 -0
  52. package/src/game-client/index.ts +98 -0
  53. package/src/game-client/perf-sampling.ts +94 -0
  54. package/src/game-client/relay-transport.ts +311 -0
  55. package/src/game-client/screenshot-target.ts +91 -0
  56. package/src/game-client/state-cap.ts +29 -0
  57. package/src/game-client/types.ts +137 -0
  58. package/src/game-client/wait-for.ts +327 -0
  59. package/src/game.ts +96 -16
  60. package/src/index.ts +68 -31
  61. package/src/session.ts +8 -10
  62. package/src/tools.ts +19 -6
package/dist/index.d.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  /**
2
- * `@vgai/live` — `{ editor, game, page, tools }` over the session wire
3
- * (docs/SHARED-SESSION-SPEC.md, Wave 2). Editor control consolidates HERE
4
- * from the ~19 `vgai` CLI verbs: a plain node/tsx script gets
5
- * `import { editor, game, page } from '@vgai/live'` instead of shelling out
6
- * to the CLI — semantics are discoverable from THIS module's types, not from
7
- * CLI usage text.
2
+ * `@vgai/live` — `{ editor, game, page, tools }` over the session wire.
3
+ * Editor control consolidates HERE from the ~19 `vgai` CLI verbs: a plain
4
+ * node/tsx script gets `import { editor, game, page } from '@vgai/live'`
5
+ * instead of shelling out to the CLI semantics are discoverable from THIS
6
+ * module's types, not from CLI usage text.
8
7
  *
9
8
  * `@vgai/live` never starts or stops a session — the CLI keeps that
10
9
  * (`create`/`edit`/`sessions`/`close`). `connect()` (and the lazy
@@ -30,22 +29,23 @@
30
29
  *
31
30
  * `page(step)` = `GameClient.page(step)` (Wave-2's playwright-shim surface,
32
31
  * PR #166) — write `step` as a literal `async (page) => {...}` and inline
33
- * every value it needs. KNOWN WIRE LIMITATION: under the relay transport
34
- * this binds to (the same one `vgai e2e --in-editor` uses), `step` is
35
- * shipped to the editor dev server as `step.toString()` and reconstructed
36
- * there closures over outer variables do NOT survive that trip. See
37
- * `@vgai/e2e`'s `bridge-transport.ts` (`runPageScript`'s doc comment) and
38
- * `relay-transport.ts` for the full honesty-boundary contract this wraps.
32
+ * every value it needs. KNOWN WIRE LIMITATION: under the relay transport this
33
+ * binds to, `step` is shipped to the editor dev server as `step.toString()`
34
+ * and reconstructed there closures over outer variables do NOT survive that
35
+ * trip. See `game-client/bridge-transport.ts` (`runPageScript`'s doc comment)
36
+ * and `game-client/relay-transport.ts` for the full honesty-boundary contract
37
+ * this wraps.
39
38
  */
40
- import type { GameClient } from '@vgai/e2e';
41
39
  import { LiveEditor } from './editor.js';
40
+ import { type LiveGame } from './game.js';
41
+ import type { GameClient } from './game-client/index.js';
42
42
  import { type ResolvedSession, type SessionResolutionDeps } from './session.js';
43
43
  import { LiveTools } from './tools.js';
44
- export type { GameClient } from '@vgai/e2e';
45
44
  export type { ActiveDocumentCapture, EditorClient, EditorView, EditorViewDocument, PresentedEditorView, } from '@vgai/editor-sdk';
46
- export type { ApplyDiffInput, ApplyDiffResult, PanelName } from './editor.js';
45
+ export type { PanelName } from './editor.js';
47
46
  export { inferAssetKind, LiveEditor } from './editor.js';
48
- export { createGameClient } from './game.js';
47
+ export { createGameClient, createLiveGame, type LiveGame } from './game.js';
48
+ export * from './game-client/index.js';
49
49
  export type { ProjectSessionHint, ResolvedSession, SessionListingTransport, SessionResolutionDeps, } from './session.js';
50
50
  export { findProjectRootFrom, resolveSession } from './session.js';
51
51
  export type { LazySession } from './singleton.js';
@@ -53,16 +53,41 @@ export { createLazySession } from './singleton.js';
53
53
  export { LiveTools } from './tools.js';
54
54
  /** A `game.page(step)`-shaped call — see this module's doc comment for the closure-capture limitation. */
55
55
  export type PageStep = GameClient['page'];
56
- export interface LiveSession {
56
+ export interface LiveSession extends LiveBindings {
57
+ /** The resolved session this is bound to — useful for logging/debugging which port/project a script attached to. */
58
+ session: ResolvedSession;
59
+ }
60
+ /** The callable half of a session: everything `vgai eval` binds except `session` itself. */
61
+ export interface LiveBindings {
57
62
  editor: LiveEditor;
58
- game: GameClient;
63
+ /** The game client, plus `instances()`/`instance(id)` for addressing one of
64
+ * several mounted instances (multiplayer authoring). A bare `game` call
65
+ * targets the sole instance and refuses when several are live. */
66
+ game: LiveGame;
59
67
  /** `GameClient.page` bound to `game` — see this module's own doc comment for the wire limitation. */
60
68
  page: PageStep;
61
69
  /** Registered project callables: enumerate, inspect, and invoke. */
62
70
  tools: LiveTools;
63
- /** The resolved session this is bound to — useful for logging/debugging which port/project a script attached to. */
64
- session: ResolvedSession;
65
71
  }
72
+ /**
73
+ * The SAME `{ editor, game, page, tools }` objects `connect()` returns —
74
+ * real classes, real instance fields — bound to a port nothing listens on.
75
+ *
76
+ * This exists for INTROSPECTION, and specifically for `vgai eval --list`
77
+ * (`packages/vgai-cli/src/eval-surface.ts`), which must answer "what could I
78
+ * call?" before `vgai edit` is running. Reading a CLASS instead is what
79
+ * shipped first, and it silently omitted `game.input` and `game.events`:
80
+ * those are instance fields the constructor assigns, so they exist on no
81
+ * prototype and a class walk cannot see them — an agent reading the listing
82
+ * concluded there was no honest input door. Objects, not classes, is the fix,
83
+ * and going through `bindTo` is what keeps it honest: the probe is assembled
84
+ * by the same function `connect()` uses, so a binding added there is listed
85
+ * here with no second place to remember.
86
+ *
87
+ * Awaiting any method on these objects will fail (connection refused). Use
88
+ * `connect()` for that.
89
+ */
90
+ export declare function unconnectedBindings(): LiveBindings;
66
91
  /**
67
92
  * Resolve `projectDir` (default `process.cwd()`) to its live `vgai edit`
68
93
  * session and bind `{ editor, game, page }` to it. `deps` is an advanced/
@@ -73,6 +98,6 @@ export declare function connect(projectDir?: string, deps?: SessionResolutionDep
73
98
  /** Test-only reset of the lazy top-level singletons' memo — NOT part of the documented public surface (real callers never need to reconnect mid-process). */
74
99
  export declare function __resetLiveSingletonForTests(): void;
75
100
  export declare const editor: LiveEditor;
76
- export declare const game: GameClient;
101
+ export declare const game: LiveGame;
77
102
  export declare const page: PageStep;
78
103
  export declare const tools: LiveTools;
package/dist/index.js CHANGED
@@ -1,10 +1,9 @@
1
1
  /**
2
- * `@vgai/live` — `{ editor, game, page, tools }` over the session wire
3
- * (docs/SHARED-SESSION-SPEC.md, Wave 2). Editor control consolidates HERE
4
- * from the ~19 `vgai` CLI verbs: a plain node/tsx script gets
5
- * `import { editor, game, page } from '@vgai/live'` instead of shelling out
6
- * to the CLI — semantics are discoverable from THIS module's types, not from
7
- * CLI usage text.
2
+ * `@vgai/live` — `{ editor, game, page, tools }` over the session wire.
3
+ * Editor control consolidates HERE from the ~19 `vgai` CLI verbs: a plain
4
+ * node/tsx script gets `import { editor, game, page } from '@vgai/live'`
5
+ * instead of shelling out to the CLI semantics are discoverable from THIS
6
+ * module's types, not from CLI usage text.
8
7
  *
9
8
  * `@vgai/live` never starts or stops a session — the CLI keeps that
10
9
  * (`create`/`edit`/`sessions`/`close`). `connect()` (and the lazy
@@ -30,26 +29,63 @@
30
29
  *
31
30
  * `page(step)` = `GameClient.page(step)` (Wave-2's playwright-shim surface,
32
31
  * PR #166) — write `step` as a literal `async (page) => {...}` and inline
33
- * every value it needs. KNOWN WIRE LIMITATION: under the relay transport
34
- * this binds to (the same one `vgai e2e --in-editor` uses), `step` is
35
- * shipped to the editor dev server as `step.toString()` and reconstructed
36
- * there closures over outer variables do NOT survive that trip. See
37
- * `@vgai/e2e`'s `bridge-transport.ts` (`runPageScript`'s doc comment) and
38
- * `relay-transport.ts` for the full honesty-boundary contract this wraps.
32
+ * every value it needs. KNOWN WIRE LIMITATION: under the relay transport this
33
+ * binds to, `step` is shipped to the editor dev server as `step.toString()`
34
+ * and reconstructed there closures over outer variables do NOT survive that
35
+ * trip. See `game-client/bridge-transport.ts` (`runPageScript`'s doc comment)
36
+ * and `game-client/relay-transport.ts` for the full honesty-boundary contract
37
+ * this wraps.
39
38
  */
40
39
  import { join } from 'node:path';
41
40
  import { EditorClient } from '@vgai/editor-sdk';
42
41
  import { LiveEditor } from './editor.js';
43
- import { createGameClient } from './game.js';
42
+ import { createLiveGame } from './game.js';
44
43
  import { lazyChainProxy } from './lazy-proxy.js';
45
44
  import { resolveSession } from './session.js';
46
45
  import { createLazySession } from './singleton.js';
47
46
  import { LiveTools } from './tools.js';
48
47
  export { inferAssetKind, LiveEditor } from './editor.js';
49
- export { createGameClient } from './game.js';
48
+ export { createGameClient, createLiveGame } from './game.js';
49
+ export * from './game-client/index.js';
50
50
  export { findProjectRootFrom, resolveSession } from './session.js';
51
51
  export { createLazySession } from './singleton.js';
52
52
  export { LiveTools } from './tools.js';
53
+ /**
54
+ * Construct the binding graph for an editor on `port`. Pure — every object
55
+ * here is built from a URL/port and contacts nothing until a method is
56
+ * awaited, which is what lets `unconnectedBindings()` below reuse it.
57
+ */
58
+ function bindTo(port, projectRoot) {
59
+ const client = new EditorClient({ url: `http://127.0.0.1:${port}` });
60
+ const editor = new LiveEditor(client);
61
+ const game = createLiveGame(port, join(projectRoot, '.vgai', 'last-run'));
62
+ const page = (step) => game.page(step);
63
+ const tools = new LiveTools(client);
64
+ return { editor, game, page, tools };
65
+ }
66
+ /**
67
+ * The SAME `{ editor, game, page, tools }` objects `connect()` returns —
68
+ * real classes, real instance fields — bound to a port nothing listens on.
69
+ *
70
+ * This exists for INTROSPECTION, and specifically for `vgai eval --list`
71
+ * (`packages/vgai-cli/src/eval-surface.ts`), which must answer "what could I
72
+ * call?" before `vgai edit` is running. Reading a CLASS instead is what
73
+ * shipped first, and it silently omitted `game.input` and `game.events`:
74
+ * those are instance fields the constructor assigns, so they exist on no
75
+ * prototype and a class walk cannot see them — an agent reading the listing
76
+ * concluded there was no honest input door. Objects, not classes, is the fix,
77
+ * and going through `bindTo` is what keeps it honest: the probe is assembled
78
+ * by the same function `connect()` uses, so a binding added there is listed
79
+ * here with no second place to remember.
80
+ *
81
+ * Awaiting any method on these objects will fail (connection refused). Use
82
+ * `connect()` for that.
83
+ */
84
+ export function unconnectedBindings() {
85
+ return bindTo(UNCONNECTED_PORT, process.cwd());
86
+ }
87
+ /** Port 0 is never a listening editor — an accidental call fails loudly rather than reaching a stranger's server. */
88
+ const UNCONNECTED_PORT = 0;
53
89
  /**
54
90
  * Resolve `projectDir` (default `process.cwd()`) to its live `vgai edit`
55
91
  * session and bind `{ editor, game, page }` to it. `deps` is an advanced/
@@ -58,12 +94,7 @@ export { LiveTools } from './tools.js';
58
94
  */
59
95
  export async function connect(projectDir, deps) {
60
96
  const resolved = await resolveSession(projectDir, deps);
61
- const client = new EditorClient({ url: `http://localhost:${resolved.port}` });
62
- const editor = new LiveEditor(client, resolved.projectRoot);
63
- const game = createGameClient(resolved.port, join(resolved.projectRoot, '.vgai', 'e2e', 'last-run'));
64
- const page = (step) => game.page(step);
65
- const tools = new LiveTools(client);
66
- return { editor, game, page, tools, session: resolved };
97
+ return { ...bindTo(resolved.port, resolved.projectRoot), session: resolved };
67
98
  }
68
99
  // ---------------------------------------------------------------------------
69
100
  // Lazy top-level singletons (usage form B above) — thin proxies over an
package/dist/session.d.ts CHANGED
@@ -23,7 +23,7 @@
23
23
  * 3. Project-root discovery (`findProjectRootFrom` below) — LIFTED (not
24
24
  * imported) from `packages/vgai-cli/src/project-root.ts`. `@vgai/sdk`'s
25
25
  * `resolveEditorSession` takes an already-known `ctx.projectRoot`; it has
26
- * no "walk up from an arbitrary cwd to find the nearest vgai.game.json"
26
+ * no "walk up from an arbitrary cwd to find the nearest vgai.project.json"
27
27
  * step of its own, which `connect(projectDir?)` needs. `@vgai/cli` is
28
28
  * `"private": true` with no `exports` field to import through (and
29
29
  * depending on it from here would invert the intended CLI -> SDK ->
@@ -48,7 +48,7 @@ import { type EditorTransport } from '@vgai/sdk';
48
48
  /**
49
49
  * Lifted verbatim from `packages/vgai-cli/src/project-root.ts` (see this
50
50
  * module's doc comment above for why it's duplicated rather than imported).
51
- * Nearest ancestor of `dir` (inclusive) containing a `vgai.game.json`, or
51
+ * Nearest ancestor of `dir` (inclusive) containing a `vgai.project.json`, or
52
52
  * `null` if none.
53
53
  */
54
54
  export declare function findProjectRootFrom(dir: string): string | null;
@@ -57,7 +57,7 @@ export type SessionListingTransport = Pick<EditorTransport, 'listSessions'>;
57
57
  export interface ResolvedSession {
58
58
  /** Editor dev-server port the resolved session is listening on. */
59
59
  port: number;
60
- /** Absolute project root — the nearest ancestor of the requested directory containing `vgai.game.json`. */
60
+ /** Absolute project root — the nearest ancestor of the requested directory containing `vgai.project.json`. */
61
61
  projectRoot: string;
62
62
  }
63
63
  export interface SessionResolutionDeps {
@@ -81,6 +81,6 @@ export interface ProjectSessionHint {
81
81
  * running `vgai edit` session. Throws a descriptive error (never hangs
82
82
  * indefinitely — bounded by `EDITOR_SESSION_DISCOVERY_TIMEOUT_MS`, and never
83
83
  * silently attaches to an unrelated project's session — see the module doc
84
- * above) when no vgai.game.json is found, or no live session covers it.
84
+ * above) when no vgai.project.json is found, or no live session covers it.
85
85
  */
86
86
  export declare function resolveSession(projectDir?: string, deps?: SessionResolutionDeps): Promise<ResolvedSession>;
package/dist/session.js CHANGED
@@ -23,7 +23,7 @@
23
23
  * 3. Project-root discovery (`findProjectRootFrom` below) — LIFTED (not
24
24
  * imported) from `packages/vgai-cli/src/project-root.ts`. `@vgai/sdk`'s
25
25
  * `resolveEditorSession` takes an already-known `ctx.projectRoot`; it has
26
- * no "walk up from an arbitrary cwd to find the nearest vgai.game.json"
26
+ * no "walk up from an arbitrary cwd to find the nearest vgai.project.json"
27
27
  * step of its own, which `connect(projectDir?)` needs. `@vgai/cli` is
28
28
  * `"private": true` with no `exports` field to import through (and
29
29
  * depending on it from here would invert the intended CLI -> SDK ->
@@ -50,13 +50,13 @@ import { EDITOR_SESSION_DISCOVERY_TIMEOUT_MS, HttpEditorTransport, withTimeout,
50
50
  /**
51
51
  * Lifted verbatim from `packages/vgai-cli/src/project-root.ts` (see this
52
52
  * module's doc comment above for why it's duplicated rather than imported).
53
- * Nearest ancestor of `dir` (inclusive) containing a `vgai.game.json`, or
53
+ * Nearest ancestor of `dir` (inclusive) containing a `vgai.project.json`, or
54
54
  * `null` if none.
55
55
  */
56
56
  export function findProjectRootFrom(dir) {
57
57
  let cur = resolve(dir);
58
58
  for (;;) {
59
- if (existsSync(join(cur, 'vgai.game.json')))
59
+ if (existsSync(join(cur, 'vgai.project.json')))
60
60
  return cur;
61
61
  const parent = dirname(cur);
62
62
  if (parent === cur)
@@ -94,7 +94,7 @@ function readProjectSession(projectRoot) {
94
94
  }
95
95
  async function verifyProjectSession(hint, projectRoot) {
96
96
  try {
97
- const response = await fetch(`http://localhost:${hint.port}/__editor/project`, {
97
+ const response = await fetch(`http://127.0.0.1:${hint.port}/__editor/project`, {
98
98
  signal: AbortSignal.timeout(EDITOR_SESSION_DISCOVERY_TIMEOUT_MS),
99
99
  });
100
100
  if (!response.ok)
@@ -112,14 +112,14 @@ async function verifyProjectSession(hint, projectRoot) {
112
112
  * running `vgai edit` session. Throws a descriptive error (never hangs
113
113
  * indefinitely — bounded by `EDITOR_SESSION_DISCOVERY_TIMEOUT_MS`, and never
114
114
  * silently attaches to an unrelated project's session — see the module doc
115
- * above) when no vgai.game.json is found, or no live session covers it.
115
+ * above) when no vgai.project.json is found, or no live session covers it.
116
116
  */
117
117
  export async function resolveSession(projectDir = process.cwd(), deps = {}) {
118
118
  const findRoot = deps.findProjectRootFrom ?? findProjectRootFrom;
119
119
  const transport = deps.transport ?? new HttpEditorTransport();
120
120
  const projectRoot = findRoot(projectDir);
121
121
  if (projectRoot === null) {
122
- throw new Error(`@vgai/live: no vgai.game.json found in ${projectDir} or any parent directory — is this a vgai project?`);
122
+ throw new Error(`@vgai/live: no vgai.project.json found in ${projectDir} or any parent directory — is this a vgai project?`);
123
123
  }
124
124
  // The editor writes this exact-project hint at boot and removes it on
125
125
  // shutdown. Prefer it over a global all-session scan: it is both faster and
@@ -139,7 +139,7 @@ export async function resolveSession(projectDir = process.cwd(), deps = {}) {
139
139
  sessions = [];
140
140
  }
141
141
  const canon = canonicalPath(projectRoot);
142
- const match = sessions.find((s) => s.kind !== 'e2e' && s.project !== null && canonicalPath(s.project) === canon);
142
+ const match = sessions.find((s) => s.project !== null && canonicalPath(s.project) === canon);
143
143
  if (!match) {
144
144
  const otherCount = sessions.length;
145
145
  throw new Error(`@vgai/live: no live editor session found for ${projectRoot}. @vgai/live only attaches to ` +
package/dist/tools.d.ts CHANGED
@@ -1,14 +1,23 @@
1
1
  /** Registered project tools over the current shared editor session. */
2
2
  import type { EditorClient, ProjectToolCatalog, ProjectToolCatalogEntry, ProjectToolOutcome } from '@vgai/editor-sdk';
3
3
  export declare class LiveTools {
4
- private readonly client;
4
+ #private;
5
5
  constructor(client: EditorClient);
6
6
  /** Enumerate the exact `package.json#vgai.tools` catalog without executing it. */
7
7
  list(): Promise<ProjectToolCatalog>;
8
8
  /** Return one tool's discoverable metadata, or `null` when it is not registered. */
9
9
  describe(name: string): Promise<ProjectToolCatalogEntry | null>;
10
- /** Invoke the same validated callable used by the editor and CLI. */
11
- call(name: string, input?: unknown, options?: {
10
+ /**
11
+ * Invoke the same validated callable used by the editor and CLI.
12
+ *
13
+ * `instance` names WHICH mounted instance the tool should drive when several
14
+ * are live (multiplayer authoring) — it reaches the tool as `ctx.instance`,
15
+ * and a tool that drives the game (e.g. `project.autoplay`) binds
16
+ * `game.instance(ctx.instance)` from it. Omitted is the single-instance case;
17
+ * the tool then targets the sole live instance, exactly as before.
18
+ */
19
+ run(name: string, input?: unknown, options?: {
12
20
  confirm?: boolean;
21
+ instance?: string;
13
22
  }): Promise<ProjectToolOutcome>;
14
23
  }
package/dist/tools.js CHANGED
@@ -1,20 +1,29 @@
1
1
  /** Registered project tools over the current shared editor session. */
2
2
  export class LiveTools {
3
- client;
3
+ /** `#`-private for the same reason `LiveEditor.#client` is. */
4
+ #client;
4
5
  constructor(client) {
5
- this.client = client;
6
+ this.#client = client;
6
7
  }
7
8
  /** Enumerate the exact `package.json#vgai.tools` catalog without executing it. */
8
9
  async list() {
9
- return this.client.listProjectTools();
10
+ return this.#client.listProjectTools();
10
11
  }
11
12
  /** Return one tool's discoverable metadata, or `null` when it is not registered. */
12
13
  async describe(name) {
13
14
  const catalog = await this.list();
14
15
  return catalog.tools.find((tool) => tool.name === name) ?? null;
15
16
  }
16
- /** Invoke the same validated callable used by the editor and CLI. */
17
- async call(name, input = {}, options = {}) {
18
- return this.client.runProjectTool(name, input, options);
17
+ /**
18
+ * Invoke the same validated callable used by the editor and CLI.
19
+ *
20
+ * `instance` names WHICH mounted instance the tool should drive when several
21
+ * are live (multiplayer authoring) — it reaches the tool as `ctx.instance`,
22
+ * and a tool that drives the game (e.g. `project.autoplay`) binds
23
+ * `game.instance(ctx.instance)` from it. Omitted is the single-instance case;
24
+ * the tool then targets the sole live instance, exactly as before.
25
+ */
26
+ async run(name, input = {}, options = {}) {
27
+ return this.#client.runProjectTool(name, input, options);
19
28
  }
20
29
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@vgai/live",
3
3
  "author": "Volter AI, Inc.",
4
4
  "license": "Apache-2.0",
5
- "version": "0.5.2",
5
+ "version": "0.5.4",
6
6
  "type": "module",
7
7
  "repository": {
8
8
  "type": "git",
@@ -30,9 +30,8 @@
30
30
  "build": "tsc -p tsconfig.build.json"
31
31
  },
32
32
  "dependencies": {
33
- "@vgai/editor-sdk": "0.5.2",
34
- "@vgai/e2e": "0.5.2",
35
- "@vgai/sdk": "0.5.2"
33
+ "@vgai/editor-sdk": "0.5.4",
34
+ "@vgai/sdk": "0.5.4"
36
35
  },
37
36
  "peerDependencies": {
38
37
  "@playwright/test": ">=1.58.2 <2"
@@ -41,5 +40,11 @@
41
40
  "@playwright/test": "^1.58.2",
42
41
  "@types/node": "^25.3.0",
43
42
  "typescript": "^5.6.0"
44
- }
43
+ },
44
+ "description": "Live-session client for VGAI projects: { editor, game, page, tools } over the vgai edit session wire.",
45
+ "keywords": [
46
+ "game-engine",
47
+ "ai-agents",
48
+ "game-testing"
49
+ ]
45
50
  }