@volter/editor-live 0.5.64 → 0.5.66

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@volter/editor-live",
3
3
  "author": "Volter AI, Inc.",
4
- "version": "0.5.64",
4
+ "version": "0.5.66",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -30,8 +30,8 @@
30
30
  "node": ">=22"
31
31
  },
32
32
  "dependencies": {
33
- "@volter/editor-sdk": "0.5.64",
34
- "@volter/editor-project": "0.5.64",
33
+ "@volter/editor-sdk": "0.5.66",
34
+ "@volter/editor-project": "0.5.66",
35
35
  "undici": "^7.28.0"
36
36
  },
37
37
  "devDependencies": {
@@ -59,6 +59,8 @@ export interface DocumentKeyOptions extends DocumentGestureOptions {
59
59
  metaKey?: boolean;
60
60
  shiftKey?: boolean;
61
61
  altKey?: boolean;
62
+ /** Hold the key this long before releasing it (a person holding W). */
63
+ holdMs?: number;
62
64
  }
63
65
 
64
66
  export interface DocumentPasteOptions extends DocumentGestureOptions {
package/src/editor.ts CHANGED
@@ -99,7 +99,7 @@ export function inferAssetKind(path: string): AssetKind {
99
99
  }
100
100
 
101
101
  export class LiveEditor {
102
- /** `#`-private, not `private`: `volter-editor eval --list` enumerates this object's
102
+ /** `#`-private, not `private`: `volter-model-editor eval --list` enumerates this object's
103
103
  * real runtime members, and TypeScript's erased `private` would leave the
104
104
  * raw `EditorClient` advertised beside them. */
105
105
  readonly #client: EditorClient;
@@ -120,7 +120,7 @@ export class LiveEditor {
120
120
  }
121
121
 
122
122
  /**
123
- * THE BLENDER LANE'S VERBS, from `volter-editor eval`.
123
+ * THE BLENDER LANE'S VERBS, from `volter-model-editor eval`.
124
124
  *
125
125
  * Blender runs headless in the editor tab's worker (ARCHITECTURE-CORE, "THE
126
126
  * BLENDER IN THE TAB IS BLENDER") and answers `blender-start`,
@@ -132,7 +132,7 @@ export class LiveEditor {
132
132
  * per question — the same discovery failure `eval-surface.ts`'s header
133
133
  * records, in a lane that had not noticed it yet.
134
134
  *
135
- * volter-editor eval "await editor.blender('blender-execute', { code: 'import bpy; print(len(bpy.data.objects))' })"
135
+ * volter-model-editor eval "await editor.blender('blender-execute', { code: 'import bpy; print(len(bpy.data.objects))' })"
136
136
  *
137
137
  * `blender-status` is the only verb that creates nothing: it answers whether
138
138
  * this tab already has a session without starting one.
@@ -178,6 +178,9 @@ export class LiveEditor {
178
178
  * `@volter/editor-sdk`'s `CaptureDimensions`.
179
179
  * Supply a view to present and photograph it in one editor request.
180
180
  */
181
+ /** The active document's RENDER alone, at the size asked for: what the document draws,
182
+ * without what the viewport draws over it (its navigation gizmo, its readouts). To see a
183
+ * stage as the person does, use `captureEditorChrome({ region: 'document' })`. */
181
184
  async captureActiveDocument(
182
185
  size?: CaptureDimensions,
183
186
  view?: EditorView,
@@ -325,8 +328,8 @@ export class LiveEditor {
325
328
  }
326
329
 
327
330
  /**
328
- * Apply a STYLE BUNDLE by id — the chrome's palette, material, icon set and
329
- * region defaults in one gesture, the session door beside
331
+ * Apply a STYLE BUNDLE by id — the chrome's palette, material and icon set in
332
+ * one gesture, the session door beside
330
333
  * `View → <Style> Style`. A bundle the open project does not offer refuses
331
334
  * and names the vocabulary; `currentView().style` reports the one worn.
332
335
  */
@@ -334,6 +337,21 @@ export class LiveEditor {
334
337
  await this.#client.setStyle(id);
335
338
  }
336
339
 
340
+ /**
341
+ * A document stage's viewport PRESENTATION — its draw mode, lighting, backdrop and overlays
342
+ * (`@volter/editor-sdk/kit/viewport-presentation`) — resolved. With `layer`, that choice is
343
+ * recorded for the view first, as a person's toolbar change would be, e.g.
344
+ * `presentation('model:src/models/cube.blend', { all: { lighting: { studioPreset: 'kit' } } })`.
345
+ * With a STRING, the named view of that id (`*.view.ts`, e.g. `'godot'`) is put on the view
346
+ * whole; the answer's `viewPresets` lists the ones registered.
347
+ */
348
+ async presentation(
349
+ documentId: string,
350
+ layer?: Parameters<EditorClient['viewportPresentation']>[1],
351
+ ): ReturnType<EditorClient['viewportPresentation']> {
352
+ return this.#client.viewportPresentation(documentId, layer);
353
+ }
354
+
337
355
  /**
338
356
  * Set the MATERIAL apart from the bundle that usually carries it.
339
357
  * Appearance is palette × material, independent axes by ruling, so
@@ -651,6 +669,11 @@ export class LiveEditor {
651
669
  return this.#client.redo();
652
670
  }
653
671
 
672
+ /** Reload the editor's page and resolve once the new document answers. */
673
+ async reloadPage(): Promise<void> {
674
+ await this.#client.reloadPage();
675
+ }
676
+
654
677
  /** Mirrors `vgai status` — the full live editor state as JSON. */
655
678
  async status(): Promise<EditorState> {
656
679
  return this.#client.getState();
package/src/session.ts CHANGED
@@ -6,6 +6,7 @@
6
6
  import { existsSync, readFileSync, realpathSync } from 'node:fs';
7
7
  import { dirname, join, resolve } from 'node:path';
8
8
  import { resolveManifestPath } from '@volter/editor-project/manifest/locate';
9
+ import { resolveProductForProject } from '@volter/editor-sdk/session/product-locator';
9
10
  import {
10
11
  EDITOR_SESSION_DISCOVERY_TIMEOUT_MS,
11
12
  type EditorSessionInfo,
@@ -176,14 +177,14 @@ function noMatchingSessionRefusal(
176
177
  `@volter/editor-live: could not READ the editor session registry while looking for ${projectRoot} — ` +
177
178
  `${discoveryFailure}. This is not the answer "no editor is running": the question went ` +
178
179
  'unanswered, so nothing is known about what is live. Retry (a probe can time out while ' +
179
- 'the box is loaded); if it keeps failing, `vgai sessions` asks the same question directly.',
180
+ `the box is loaded); if it keeps failing, ${sessionsCommandFor(projectRoot)} asks the same question directly.`,
180
181
  );
181
182
  }
182
183
  if (sessions.length === 0) {
183
184
  return new Error(
184
185
  `@volter/editor-live: the editor session registry is readable and lists NO live sessions, so none ` +
185
186
  `covers ${projectRoot}. @volter/editor-live only attaches to an already-running session — it ` +
186
- 'never starts one — so run `volter-editor edit` in that project first, then retry.',
187
+ `never starts one — so run ${editCommandFor(projectRoot)} in that project first, then retry.`,
187
188
  );
188
189
  }
189
190
  const listed = sessions
@@ -196,7 +197,7 @@ function noMatchingSessionRefusal(
196
197
  ` live sessions:\n${listed}\n` +
197
198
  ' If one of those is meant to be this project, the two paths differ after resolution — ' +
198
199
  'the usual cause is a git worktree or a symlink, where the session was opened through a ' +
199
- 'different path to the same files. Run `volter-editor edit` from THIS path, or use the path the ' +
200
+ `different path to the same files. Run ${editCommandFor(projectRoot)} from THIS path, or use the path the ` +
200
201
  'session lists.',
201
202
  );
202
203
  }
@@ -211,7 +212,7 @@ export async function resolveSession(
211
212
  const projectRoot = findRoot(projectDir);
212
213
  if (projectRoot === null) {
213
214
  throw new Error(
214
- `@volter/editor-live: no vgai.project.json found in ${projectDir} or any parent directory — is this a vgai project?`,
215
+ `@volter/editor-live: no vgai.project.json found in ${projectDir} or any parent directory — is this a project?`,
215
216
  );
216
217
  }
217
218
 
@@ -265,3 +266,22 @@ export async function resolveSession(
265
266
 
266
267
  return { port: match.port, projectRoot };
267
268
  }
269
+
270
+ /** `` `<product> edit` `` for the product this project declares, or a generic
271
+ * phrase when it declares none — this package serves every product and
272
+ * names only the one the project installed. */
273
+ function editCommandFor(projectRoot: string): string {
274
+ return verbFor(projectRoot, 'edit');
275
+ }
276
+
277
+ function sessionsCommandFor(projectRoot: string): string {
278
+ return verbFor(projectRoot, 'sessions');
279
+ }
280
+
281
+ function verbFor(projectRoot: string, verb: string): string {
282
+ try {
283
+ return `\`${resolveProductForProject(projectRoot).command} ${verb}\``;
284
+ } catch {
285
+ return `its product's \`${verb}\` command`;
286
+ }
287
+ }