@volter/live 0.5.212 → 0.5.213

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 (45) hide show
  1. package/BUNDLED_NOTICES +4 -4
  2. package/README.md +4 -1
  3. package/dist/asset-library.d.ts +98 -0
  4. package/dist/asset-library.js +7 -0
  5. package/dist/asset-library.js.map +7 -0
  6. package/dist/chunk-B2HUWFTT.js +25 -0
  7. package/dist/chunk-B2HUWFTT.js.map +7 -0
  8. package/dist/{chunk-7SZ3C4CC.js → chunk-IZJOOON2.js} +45 -8
  9. package/dist/chunk-IZJOOON2.js.map +7 -0
  10. package/dist/{chunk-Y5W77HYT.js → chunk-JDOIPALX.js} +38 -3
  11. package/dist/chunk-JDOIPALX.js.map +7 -0
  12. package/dist/{chunk-YPAOTPIF.js → chunk-JFAHP5CC.js} +19 -3
  13. package/dist/chunk-JFAHP5CC.js.map +7 -0
  14. package/dist/{chunk-SDIWRX5X.js → chunk-PC56TDHV.js} +5 -5
  15. package/dist/chunk-PC56TDHV.js.map +7 -0
  16. package/dist/{chunk-USXOIBVX.js → chunk-WIAH4XZE.js} +5 -4
  17. package/dist/chunk-WIAH4XZE.js.map +7 -0
  18. package/dist/client.d.ts +10 -4
  19. package/dist/client.js +2 -1
  20. package/dist/discovery.js +2 -2
  21. package/dist/editor.d.ts +11 -2
  22. package/dist/index.d.ts +2 -1
  23. package/dist/index.js +18 -51
  24. package/dist/index.js.map +3 -3
  25. package/dist/product-locator.d.ts +2 -2
  26. package/dist/product-locator.js +2 -2
  27. package/dist/registry-format.d.ts +31 -3
  28. package/dist/registry-format.js +13 -3
  29. package/dist/session.d.ts +4 -15
  30. package/dist/volter-manifest.js +1 -1
  31. package/dist/workbench-locator.js +2 -2
  32. package/package.json +7 -3
  33. package/src/asset-library.ts +104 -0
  34. package/src/client.ts +48 -7
  35. package/src/discovery.ts +2 -2
  36. package/src/editor.ts +11 -3
  37. package/src/index.ts +2 -1
  38. package/src/product-locator.ts +2 -2
  39. package/src/registry-format.ts +68 -5
  40. package/src/session.ts +6 -86
  41. package/dist/chunk-7SZ3C4CC.js.map +0 -7
  42. package/dist/chunk-SDIWRX5X.js.map +0 -7
  43. package/dist/chunk-USXOIBVX.js.map +0 -7
  44. package/dist/chunk-Y5W77HYT.js.map +0 -7
  45. package/dist/chunk-YPAOTPIF.js.map +0 -7
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/editor-document.ts", "../src/editor.ts", "../src/lazy-proxy.ts", "../src/session.ts", "../../project/src/manifest/locate.ts", "../../project/src/manifest/filename.ts", "../src/singleton.ts", "../src/member-hints.ts", "../src/index.ts"],
4
- "sourcesContent": ["/** Session binding for reading and driving the editor's named surfaces.\n * Each verb accepts a document-probe scope: document, header, shelf, rail,\n * outliner, utility or area. Targets outside that scope are refused. Chrome\n * scopes remain available without an open document. The eval member listing\n * groups these verbs under editor.document. */\n\nimport type {\n DocumentProbeResult,\n DocumentProbeScope,\n DocumentProbeStep,\n} from '@volter/sdk';\nimport type { EditorClient } from './client.js';\n\n/** Which named surface a verb runs against; `document` when omitted. */\nexport interface DocumentScopeOption {\n scope?: DocumentProbeScope;\n}\n\n/** Modifier/targeting options shared by the gesture verbs. */\nexport interface DocumentGestureOptions extends DocumentScopeOption {\n /** Which match to drive when the selector matches several (default 0). */\n index?: number;\n}\n\nexport interface DocumentKeyOptions extends DocumentGestureOptions {\n /** Target one element instead of whatever inside the scope has focus. */\n selector?: string;\n code?: string;\n ctrlKey?: boolean;\n metaKey?: boolean;\n shiftKey?: boolean;\n altKey?: boolean;\n /** Hold the key this long before releasing it (a person holding W).\n * Finite, nonnegative, and at most 120,000 ms. */\n holdMs?: number;\n}\n\nexport interface DocumentPasteOptions extends DocumentGestureOptions {\n selector?: string;\n}\n\nexport interface DocumentTypeOptions extends DocumentGestureOptions {\n /** The field; omitted types into whatever inside the scope has focus. */\n selector?: string;\n /** Replace what the field holds first (default true). */\n replace?: boolean;\n /** Press Enter after the text (default true). */\n enter?: boolean;\n}\n\nexport class LiveEditorDocument {\n readonly #client: EditorClient;\n\n constructor(client: EditorClient) {\n this.#client = client;\n }\n\n /**\n * Read matching elements inside the active document: tag, text, attributes,\n * value/checked/disabled and rect. `matched` is the total before `limit`.\n *\n * `styles` additionally resolves named properties per match \u2014 and resolving\n * is the point, because a theme token is an expression until an element\n * paints it. Ask for the standard property to learn the colour a person\n * sees; ask for a `--volter-\u2026` custom property to learn what a rule WOULD\n * paint, which is the only way to measure a `:hover` colour (`:hover` is a\n * browser state no synthetic event can enter, so there is deliberately no\n * hover verb on this door).\n *\n * await editor.document.query('.volter-tree-row', {\n * styles: ['backgroundColor', '--volter-widget-regular-hover'],\n * });\n */\n async query(\n selector: string,\n options?: DocumentScopeOption & { limit?: number; styles?: readonly string[] },\n ): Promise<DocumentProbeResult> {\n return this.#probe({\n action: 'query',\n selector,\n ...(options?.scope === undefined ? {} : { scope: options.scope }),\n ...(options?.limit === undefined ? {} : { limit: options.limit }),\n ...(options?.styles === undefined ? {} : { styles: [...options.styles] }),\n });\n }\n\n /** A REAL pointer gesture (pointerdown/mousedown/focus/pointerup/mouseup/click)\n * \u2014 not `element.click()`, which a `pointerdown` listener never sees. */\n async click(\n selector: string,\n options?: DocumentGestureOptions & {\n clicks?: number;\n at?: [number, number];\n altKey?: boolean;\n ctrlKey?: boolean;\n metaKey?: boolean;\n shiftKey?: boolean;\n },\n ): Promise<DocumentProbeResult> {\n // Refuse unknown options before dispatching the gesture.\n const known = ['scope', 'index', 'clicks', 'at', 'altKey', 'ctrlKey', 'metaKey', 'shiftKey'];\n const unknown = Object.keys(options ?? {}).filter((key) => !known.includes(key));\n if (unknown.length > 0) throw new Error(`click has no option ${unknown.map((key) => `\\`${key}\\``).join(', ')}; its options are scope, index, clicks, at ([x, y] fractions of the element's box) and the modifier keys altKey, ctrlKey, metaKey and shiftKey.`);\n return this.#probe({\n action: 'click',\n selector,\n ...(options?.scope === undefined ? {} : { scope: options.scope }),\n ...(options?.index === undefined ? {} : { index: options.index }),\n ...(options?.clicks === undefined ? {} : { clicks: options.clicks }),\n ...(options?.at === undefined ? {} : { at: options.at }),\n ...(options?.altKey ? { altKey: true } : {}),\n ...(options?.ctrlKey ? { ctrlKey: true } : {}),\n ...(options?.metaKey ? { metaKey: true } : {}),\n ...(options?.shiftKey ? { shiftKey: true } : {}),\n });\n }\n\n /**\n * TYPE into a field and commit with Enter, the way a person does \u2014 one\n * character at a time through the prototype's value setter, between real\n * `keydown`/`keyup`.\n *\n * `paste` is not a substitute: an untrusted `ClipboardEvent` performs no\n * default action, so a plain `<input>` with no paste handler keeps its old\n * value. Omit `selector` to type into whatever inside the scope has focus \u2014\n * which is what a rename field is, one gesture after\n * `click(row, { clicks: 2 })`.\n */\n async type(text: string, options?: DocumentTypeOptions): Promise<DocumentProbeResult> {\n return this.#probe({ action: 'type', text, ...(options ?? {}) });\n }\n\n /**\n * A real pointer DRAG across one matched element \u2014 press at `from`, move,\n * release at `to`. A zero-length drag presses and releases at one fraction.\n *\n * `from`, `to` and every point in `via` are `[x, y]` FRACTIONS OF THE\n * MATCHED ELEMENT'S BOX, 0..1 from its top-left \u2014 NEVER pixels and never\n * page coordinates. `[0.5, 0.5]` is its center, `[1, 0]` its top-right.\n * Compute a pixel target by measuring the element first: `query` answers\n * its `rect`, and `(px - rect.x) / rect.width` is the fraction to pass.\n */\n async drag(\n selector: string,\n options: DocumentGestureOptions & {\n from: [number, number];\n to: [number, number];\n via?: [number, number][];\n steps?: number;\n altKey?: boolean;\n ctrlKey?: boolean;\n metaKey?: boolean;\n shiftKey?: boolean;\n /** 0 primary (default), 1 middle, 2 secondary. */\n button?: 0 | 1 | 2;\n /** `via`/`to` may leave the element's box after the press (a handle drag). */\n leave?: boolean;\n /** Keep the button down at `to`, for readings taken mid-gesture; {@link release} lets go. */\n hold?: boolean;\n },\n ): Promise<DocumentProbeResult> {\n return this.#probe({\n action: 'drag',\n selector,\n ...(options.scope === undefined ? {} : { scope: options.scope }),\n from: options.from,\n to: options.to,\n ...(options.via === undefined ? {} : { via: options.via }),\n ...(options.steps === undefined ? {} : { steps: options.steps }),\n ...(options.index === undefined ? {} : { index: options.index }),\n ...(options.altKey === undefined ? {} : { altKey: options.altKey }),\n ...(options.ctrlKey === undefined ? {} : { ctrlKey: options.ctrlKey }),\n ...(options.metaKey === undefined ? {} : { metaKey: options.metaKey }),\n ...(options.shiftKey === undefined ? {} : { shiftKey: options.shiftKey }),\n ...(options.button === undefined ? {} : { button: options.button }),\n ...(options.leave === undefined ? {} : { leave: options.leave }),\n ...(options.hold === undefined ? {} : { hold: options.hold }),\n });\n }\n\n /** Lets go of the drag `hold: true` left pressed, where it was left. */\n async release(options?: DocumentGestureOptions): Promise<DocumentProbeResult> {\n return this.#probe({ action: 'release', ...(options?.scope === undefined ? {} : { scope: options.scope }) });\n }\n\n /** A real keydown/keyup on the target, or on whatever inside the document has focus. */\n async key(key: string, options?: DocumentKeyOptions): Promise<DocumentProbeResult> {\n return this.#probe({ action: 'key', key, ...(options ?? {}) });\n }\n\n /** A real `ClipboardEvent` carrying `text/plain` \u2014 the gesture nothing else\n * in the product can produce. */\n async paste(text: string, options?: DocumentPasteOptions): Promise<DocumentProbeResult> {\n return this.#probe({ action: 'paste', text, ...(options ?? {}) });\n }\n\n /**\n * Choose `value` on a `<select>` \u2014 a native dropdown's options are drawn by\n * the OS, so `click` has nothing in the document to resolve, and a plain\n * `element.value =` is invisible to React. Set through the prototype's own\n * value setter plus `input`/`change`; `value` is the option's `value`, not\n * its label. An unknown value is refused with the options it does offer.\n */\n async select(\n selector: string,\n value: string,\n options?: DocumentGestureOptions,\n ): Promise<DocumentProbeResult> {\n return this.#probe({\n action: 'select',\n selector,\n value,\n ...(options?.scope === undefined ? {} : { scope: options.scope }),\n ...(options?.index === undefined ? {} : { index: options.index }),\n });\n }\n\n /**\n * Run `step` in the editor page against the active document's published\n * context, with its document id in `info`. The document owns the context's\n * API. The step's source is serialized, so inline every value it needs and\n * return plain data.\n */\n async run<T = unknown>(\n step: (ctx: unknown, info: { documentId: string }) => T | Promise<T>,\n ): Promise<T> {\n return this.#client.documentScript<T>(step.toString());\n }\n\n #probe(step: DocumentProbeStep): Promise<DocumentProbeResult> {\n return this.#client.documentProbe(step);\n }\n}\n", "/** Editor and document automation over the shared session command wire.\n * Modeling executes in the editor tab; this client owns no model state. */\n\nimport type {\n ActiveDocumentCapture,\n AssetKind,\n AssetPreviewCapture,\n AssetPreviewOptions,\n AssetPreviewShotSetDefinition,\n AssetPreviewSource,\n CaptureDimensions,\n DocumentLookOutcome,\n StageFrameCostReading,\n EditorChromeCapture,\n EditorChromeCaptureOptions,\n EditorState,\n EditorView,\n EditorWorkspaceName,\n InspectedFieldWrite,\n InspectedHierarchy,\n InspectedInspection,\n LabeledShotSetCapture,\n PresentedEditorView,\n ShadingMode,\n StructureOp,\n StructureOpOptions,\n StructureOpResult,\n ViewPreset,\n ViewportCapture,\n} from '@volter/sdk';\nimport type { EditorClient, HistoryStep, OpenedDocument } from './client.js';\nimport { LiveEditorDocument } from './editor-document.js';\n\n/** A panel `showPanel` can focus: the console, the build surface, or any key\n * the editor's own static-panel registry holds (`hierarchy`, `asset-library`,\n * `inspector`, `history`, \u2026) \u2014 which is why this is open: the registry, not\n * this union, is the vocabulary. */\nexport type PanelName =\n | 'console'\n // Keeps the literals above in autocomplete while admitting every key the\n // editor's registry holds \u2014 the registry answers, this union only hints.\n | (string & {});\n\nconst EXTENSION_KIND: Record<string, AssetKind> = {\n '.glb': 'model',\n '.gltf': 'model',\n '.png': 'image',\n '.jpg': 'image',\n '.jpeg': 'image',\n '.webp': 'image',\n '.gif': 'image',\n '.svg': 'image',\n '.hdr': 'image',\n '.exr': 'image',\n '.mp4': 'video',\n '.webm': 'video',\n '.mp3': 'audio',\n '.ogg': 'audio',\n '.wav': 'audio',\n '.flac': 'audio',\n '.glsl': 'source',\n '.vert': 'source',\n '.frag': 'source',\n // Source kinds select SourceAssetViewer, which routes project scripts by content to\n // LiveModuleDocument. Keep these extensions aligned with its isProjectScriptPath predicate.\n '.ts': 'source',\n '.tsx': 'source',\n '.mts': 'source',\n '.cts': 'source',\n '.js': 'source',\n '.jsx': 'source',\n '.mjs': 'source',\n '.cjs': 'source',\n};\n\n/**\n * Lightweight extension-based `AssetKind` guess for `openAsset`'s optional\n * `kind` argument. Callers with an unusual extension can always pass `kind`\n * explicitly.\n */\nexport function inferAssetKind(path: string): AssetKind {\n // `'prefab'` is an `@volter/sdk` AssetKind that view links name.\n if (path.endsWith('.prefab.json')) return 'prefab';\n const dot = path.lastIndexOf('.');\n const ext = dot >= 0 ? path.slice(dot).toLowerCase() : '';\n return EXTENSION_KIND[ext] ?? 'json';\n}\n\nexport class LiveEditor {\n /** `#`-private, not `private`: `<command> eval --list` enumerates this object's\n * real runtime members, and TypeScript's erased `private` would leave the\n * raw `EditorClient` advertised beside them. */\n readonly #client: EditorClient;\n\n /** Read and drive DOM within a named scope: the active document by default, or editor chrome\n * such as header, shelf, rail, outliner, utility and area. Targets outside the scope are refused.\n * See `@volter/sdk`'s editor-document-probe for scope and gesture contracts. */\n readonly document: LiveEditorDocument;\n\n constructor(client: EditorClient) {\n this.#client = client;\n this.document = new LiveEditorDocument(client);\n }\n\n /** A verb a composed package contributes (`<package>-<verb>`), waited on for its own row's budget. */\n async contributedVerb<T extends object = Record<string, unknown>>(\n type: string,\n fields: Record<string, unknown> = {},\n ): Promise<T> {\n return this.#client.contributedVerb<T>(type, fields);\n }\n\n /**\n * The active authoring adapter's persistence destination \u2014 where a save would\n * land (`status().savePath`). A read only: a stage root has no scene document\n * to open, and its root is activated instead.\n */\n async scene(): Promise<string | null> {\n const state = await this.#client.getState();\n return state.savePath;\n }\n\n /**\n * Make the connected human editor show the same subject/view as the agent.\n * The returned URL is a compact, shareable projection \u2014 not a serialized\n * workspace or document payload.\n */\n async present(view: EditorView): Promise<PresentedEditorView> {\n return this.#client.present(view);\n }\n\n /** The human editor's actual active document, selection, camera and utility. */\n async currentView(): Promise<EditorView> {\n return this.#client.currentView();\n }\n\n /** Capture the active document's render without viewport navigation gizmos or readouts.\n * A number requests a square; `{width, height}` requests a shaped frame, bounded by\n * `CaptureDimensions`. Supply a view to present and capture it in one request.\n * Use `captureEditorChrome({ region: 'document' })` to include viewport chrome. */\n async captureActiveDocument(\n size?: CaptureDimensions,\n view?: EditorView,\n ): Promise<ActiveDocumentCapture> {\n return this.#client.captureActiveDocument(size, view);\n }\n\n /**\n * Photograph the editor PAGE \u2014 every panel, tab strip and viewport as the\n * person sees it. the editor's `screenshot editor` command is this verb from the shell. The\n * one door for judging chrome sighted: a skin, a workspace arrangement or a\n * contributed panel is looked at through this, never guessed at from DOM\n * probes. The page at its own layout, `scale` output pixels per CSS pixel\n * (default `devicePixelRatio`) \u2014 a 1 px border or a glyph stroke is only\n * judgeable at the scale the reference it is compared against was captured\n * at, and the result reports its own `size` and `scale`.\n */\n async captureEditorChrome(options?: EditorChromeCaptureOptions): Promise<EditorChromeCapture> {\n return this.#client.captureEditorChrome(options);\n }\n\n /** `'all'` -> `EditorClient.selectAll()` (mirrors `volter select --all`); otherwise `EditorClient.select(id)` (mirrors `volter select <entityId>`). */\n async select(id: string | 'all'): Promise<void> {\n if (id === 'all') {\n await this.#client.selectAll();\n return;\n }\n await this.#client.select(id);\n }\n\n /** Mirrors `volter deselect`. */\n async deselect(): Promise<void> {\n await this.#client.select(null);\n }\n\n /** No `id` -> focus the current selection (mirrors bare `volter focus`); `id` given -> focus that entity. */\n async focus(id?: string): Promise<void> {\n if (id !== undefined) {\n await this.#client.focusEntity(id);\n return;\n }\n await this.#client.focusSelection();\n }\n\n /**\n * Frame the edit viewport camera on one entity. Same framing as\n * `focus(id)`, but an entity id the scene does not know THROWS, naming the\n * id \u2014 where `focus` quietly does nothing. Reach for this whenever the next\n * step reads the viewport (`screenshot()`, an\n * `assetPreview(..., { stage: 'scene' })`): a framing that silently missed\n * would otherwise be indistinguishable from one that worked.\n */\n async frame(entityId: string): Promise<void>;\n /**\n * Bare `frame()` frames the OPEN asset document's subject instead \u2014 its\n * selection if it has one, else the whole model: the toolbar's own Frame\n * button, reachable from a script. `fit` scales the fitted distance (1 is\n * that button's tight fit, 1.5 stands back a little for a shot).\n */\n async frame(options?: { readonly fit?: number }): Promise<void>;\n async frame(target?: string | { readonly fit?: number }): Promise<void> {\n if (typeof target === 'string') {\n await this.#client.frameEntity(target);\n return;\n }\n await this.#client.frameDocument(target?.fit);\n }\n\n /**\n * WATCH THE AGENT LOOK AROUND THE MODEL.\n *\n * Swings the open asset document's camera \u2014 the camera the human's tab is\n * showing \u2014 around the framed subject by `azimuth`/`elevation` RADIANS,\n * animated over `duration` seconds (default 0.6), and resolves when the move\n * ends. This is deliberately not a jump cut: the point of the verb is that a\n * person watching sees the agent walk around the thing it is working on.\n *\n * `await editor.orbit({ azimuth: Math.PI / 2 })` \u2014 a quarter turn to the right.\n *\n * There is ONE camera, and the human owns it: a drag during the move cancels\n * it exactly where it is, and the resolved outcome says `cancelledBy:\n * 'human'` rather than throwing. A second look verb supersedes the first.\n * The move is drawn by the document's own frame loop, so a document that\n * isn't being drawn (background tab, inactive panel) doesn't orbit.\n */\n async orbit(options: {\n /** RADIANS, relative to where the camera is now. `Math.PI / 2` is a\n * quarter turn; degrees are not accepted and `90` is fourteen turns. */\n readonly azimuth?: number;\n /** RADIANS, relative to where the camera is now. */\n readonly elevation?: number;\n /** SECONDS the move takes (default 0.6). */\n readonly duration?: number;\n }): Promise<DocumentLookOutcome> {\n // Refuse unknown keys by name and include the supported keys and units.\n const known = ['azimuth', 'elevation', 'duration'];\n const unknown = Object.keys(options ?? {}).filter((key) => !known.includes(key));\n if (unknown.length > 0)\n throw new Error(\n `editor.orbit: ${unknown.join(', ')} ${unknown.length === 1 ? 'is not a key' : 'are not keys'} ` +\n 'this verb takes. It takes azimuth and elevation in RADIANS (relative to where the ' +\n 'camera is now) and duration in SECONDS.',\n );\n return this.#client.orbitDocument(options);\n }\n\n /**\n * A slow full revolution of the open document's subject \u2014 {@link orbit} with\n * the turns spelled out and a constant angular rate. Resolves at the end of\n * the last revolution.\n */\n async turntable(options?: {\n readonly seconds?: number;\n readonly revolutions?: number;\n }): Promise<DocumentLookOutcome> {\n return this.#client.turntableDocument(options);\n }\n\n /**\n * What a frame of the open 3D document's stage costs when nothing caps it: `frames` of the\n * stage's own frame back to back, each waited out on the GPU (median, p95, min ms), the canvas\n * with its device pixel ratio, what was drawn after culling against what the scene holds, and\n * the draw mode. `stage` names another stage by its id (a split's second area,\n * `<documentId>#area-2`).\n */\n async frameCost(options?: { readonly frames?: number; readonly stage?: string; readonly quality?: 'full' | 'navigation' }): Promise<StageFrameCostReading> {\n return this.#client.frameCostDocument(options);\n }\n\n async view(preset: ViewPreset): Promise<void> {\n await this.#client.viewPreset(preset);\n }\n\n\n async workspace(id: EditorWorkspaceName): Promise<void> {\n await this.#client.setWorkspace(id);\n }\n\n /**\n * Apply a STYLE BUNDLE by id \u2014 the chrome's palette, material and icon set in\n * one gesture, the session door beside\n * `View \u2192 <Style> Style`. A bundle the open project does not offer refuses\n * and names the vocabulary; `currentView().style` reports the one worn.\n */\n async style(id: string): Promise<void> {\n await this.#client.setStyle(id);\n }\n\n /**\n * A document stage's viewport PRESENTATION \u2014 its draw mode, lighting, backdrop and overlays\n * (`@volter/sdk/viewport-presentation`) \u2014 resolved. With `layer`, that choice is\n * recorded for the view first, as a person's toolbar change would be, e.g.\n * `presentation('model:src/models/cube.blend', { all: { lighting: { studioPreset: 'kit' } } })`.\n */\n async presentation(\n documentId: string,\n layer?: Parameters<EditorClient['viewportPresentation']>[1],\n ): ReturnType<EditorClient['viewportPresentation']> {\n return this.#client.viewportPresentation(documentId, layer);\n }\n\n /** Focus an editor panel: the console, the build surface, or\n * any key the editor's static-panel registry holds \u2014 an unknown key refuses\n * naming the ones it does. */\n async showPanel(name: PanelName): Promise<void> {\n switch (name) {\n case 'console':\n await this.#client.toggleConsole();\n return;\n default:\n // Every other name is the EDITOR's to resolve, against its live panel\n // registry. A list kept here could only ever be a copy going stale.\n await this.#client.showPanel(name);\n return;\n }\n }\n\n /** `kind` inferred from `path`'s extension when omitted (`inferAssetKind`) \u2014 pass it explicitly to override. */\n async openAsset(path: string, kind?: AssetKind): Promise<void> {\n // Finder-listed documents use their document opener rather than asset-kind inference.\n const document = (await this.#client.documentTable()).entries.find((entry) => entry.source?.path === path);\n if (document)\n throw new Error(`${path} is a ${document.kind} document, not an asset: open it with editor.open(\"${document.id}\").`);\n await this.#client.openAsset(path, kind ?? inferAssetKind(path));\n }\n\n /**\n * SELECT a project asset \u2014 the browser's single click, which fills the\n * Inspector without opening a document. `openAsset` is the double click.\n * Selecting a path nothing matches is not an error \u2014 the Inspector shows\n * what it has, exactly as it does for a human.\n */\n async selectAsset(path: string): Promise<void> {\n await this.#client.selectAsset(path);\n }\n\n /**\n * Captures the editor's native four-view preview. A bare string is a\n * project-relative asset path (the common case); an explicit source object\n * targets a path, a LIVE SCENE ENTITY (`assetPreview({ entityId }, \u2026)`) \u2014\n * which is what makes `options.stage: 'scene'`, the entity photographed\n * where it stands under the scene's own lighting, reachable from here \u2014 or\n * RAW GLB BYTES (`assetPreview({ glbBase64 }, \u2026)`), for a model that exists\n * only in the calling Node process's memory and has never been written to\n * disk. `stage` defaults to `'lab'`, the neutral Asset Lab staging, and the\n * bytes form is lab-only.\n */\n async assetPreview(\n source: string | AssetPreviewSource,\n options?: AssetPreviewOptions,\n ): Promise<AssetPreviewCapture> {\n return this.#client.captureAssetPreview(\n typeof source === 'string' ? { assetPath: source } : source,\n options,\n );\n }\n\n /**\n * The same subject photographed as a LABELED SHOT SET instead of the four\n * views \u2014 a caller-supplied definition of turntable yaws and bone-anchored\n * crops, rendered against the asset's own skeleton, with a contact sheet.\n * Every source {@link assetPreview} takes works here, GLB bytes included:\n * a shot set stages its own subject, so it needs no place to stand.\n */\n async assetPreviewShots(\n source: string | AssetPreviewSource,\n definition: AssetPreviewShotSetDefinition,\n options?: AssetPreviewOptions,\n ): Promise<LabeledShotSetCapture> {\n return this.#client.captureShotSetPreview(\n typeof source === 'string' ? { assetPath: source } : source,\n definition,\n options,\n );\n }\n\n async grid(on: boolean): Promise<void> {\n await this.#client.setGrid(on);\n }\n\n async helpers(on: boolean): Promise<void> {\n await this.#client.setHelpers(on);\n }\n\n async stats(on: boolean): Promise<void> {\n await this.#client.setStats(on);\n }\n\n async shading(mode: ShadingMode): Promise<void> {\n await this.#client.setShadingMode(mode);\n }\n\n\n async inspect(): Promise<InspectedInspection> {\n return this.#client.inspect();\n }\n\n /** Run one verb listed by `inspect().quickActions`, through the same action\n * the human Inspector button invokes. */\n async runAction(actionId: string): Promise<InspectedInspection> {\n return this.#client.runInspectionAction(actionId);\n }\n\n /**\n * Run a command by id. Under the native frame this uses ICommandService and\n * can invoke editor or VS Code commands. Standalone sessions resolve registered\n * view verbs of the form `volter.<view>.<verb>` and refuse other ids.\n *\n * Returns the command\u2019s result, or `null` when it returns nothing.\n */\n async command(commandId: string, args?: unknown): Promise<unknown> {\n return this.#client.runCommand(commandId, args);\n }\n\n /**\n * RESTRUCTURE the authored tree \u2014 the hierarchy context menu's own verbs.\n *\n * `create`, `delete`, `duplicate`, `reparent`, `reorder`, `wrap`, `unwrap`,\n * `group`, `ungroup`, `copy`, `cut`, `paste`; `extractComponent` and\n * `forkComponent` are the two that write whole new files and have their own\n * doors below. All of them run the SAME `authoring/consumer-actions.ts`\n * helpers the menu items call, so there is one implementation of each op and\n * not a second that can disagree with what a human gets.\n *\n * `id`/`ids` default to the current selection. The answer carries the same\n * per-edit `write` ack `setField` does, so `write.persisted` tells a saved\n * restructure from a live-only one. An op the active adapter does not provide\n * REJECTS by name \u2014 never a silent no-op.\n */\n async structure(op: StructureOp, options?: StructureOpOptions): Promise<StructureOpResult> {\n return this.#client.structureOp(op, options ?? {});\n }\n\n /**\n * \"Extract Component\u2026\" \u2014 lift the selected native subtree into its own\n * component file (plus a story) and replace the callsite with it.\n *\n * Answers the action's own sentence, which NAMES both new files, because\n * undo owns the callsite edit and will not remove them.\n */\n async extractComponent(options?: { id?: string; name?: string }): Promise<string> {\n return (await this.#client.extractComponent(options ?? {})).hint;\n }\n\n /**\n * \"Fork Component\u2026\" \u2014 copy the selected instance's component definition to a\n * new file and retarget THIS CALLSITE at it.\n *\n * One callsite is the unit of the edit; when that callsite sits inside a\n * component rendered many times, every one of those renders now renders the\n * fork.\n */\n async forkComponent(options?: { id?: string }): Promise<string> {\n return (await this.#client.forkComponent(options ?? {})).hint;\n }\n\n /**\n * READ the hierarchy panel, as data \u2014 the rows a human is looking at right\n * now, nested exactly as the panel nests them.\n *\n * The companion to {@link inspect}: that one answers \"what IS the selected\n * thing\", this one answers \"what does the tree LOOK LIKE\". It is the panel's\n * own projection of component marks, document promotion, child caps,\n * collapse state, search and selection scope onto the adapter tree.\n *\n * Prefer this over `status().entities`, which is deliberately a different\n * question \u2014 the RAW adapter tree, unprojected. A panel that renders the\n * wrong rows looks perfectly healthy in that facet.\n *\n * Each row reports the projected child count and whether the panel draws a disclosure control.\n *\n * Rejects, naming the panel, when no hierarchy panel is mounted \u2014 an empty\n * tree would be a fabricated answer about a surface nobody is being shown.\n */\n async hierarchy(): Promise<InspectedHierarchy> {\n return this.#client.hierarchy();\n }\n\n /** Expand every branch through the Hierarchy panel's own action. */\n async expandHierarchyAll(): Promise<void> {\n await this.#client.expandHierarchyAll();\n }\n\n /** Collapse every branch through the same panel action. Expanding is\n * persisted per project, so without this the tree's REST STATE \u2014 what a\n * person sees on opening the project \u2014 is unreachable once any reader has\n * expanded it. */\n async collapseHierarchyAll(): Promise<void> {\n await this.#client.collapseHierarchyAll();\n }\n\n /**\n * Write one editable field from `inspect()` by its stable path, through the\n * same Inspector IO and persistence boundary the human control uses.\n *\n * The answer is `{ subject, write }`, and `write` is the half worth reading\n * first: a write with no persistence route open still succeeds \u2014 it lands on\n * the live object and journals live-only \u2014 so `write.persisted` is how you\n * tell a saved edit from one that will not survive the session, without\n * diffing the tree. `write.destination` is the adapter's own words for where\n * it went (\"live-only (not saved)\" is a destination, never silence).\n */\n async setField(path: string, value: unknown): Promise<InspectedFieldWrite> {\n return this.#client.setInspectionField(path, value);\n }\n\n /**\n * REMOVE one field's authored override \u2014 the revert arrow, as a command.\n *\n * Reach for this instead of `setField` whenever you are UNDOING an edit that\n * added a property the source did not carry: `setField` can only write a\n * value, so setting the default back leaves `position={[0, 0, 0]}` in the\n * file where there was nothing before. Only this door restores the bytes.\n *\n * The answer is the same `{ subject, write }` shape, awaited past the bytes.\n * It rejects with `code: 'REMOVAL_UNAVAILABLE'` when the field is not\n * declared removable or the lane has no removal door \u2014 which is a missing\n * seam to report, not a removal that failed.\n */\n async removeField(path: string): Promise<InspectedFieldWrite> {\n return this.#client.removeInspectionField(path);\n }\n\n /** Open a document by its adapter-declared id, through its registered owner. */\n async open(id: string): Promise<OpenedDocument> {\n return this.#client.open(id);\n }\n\n /** Undo / redo one project transaction, through the session's own history\n * queue \u2014 the same one the keyboard shortcut drives. */\n async undo(): Promise<HistoryStep> {\n return this.#client.undo();\n }\n\n async redo(): Promise<HistoryStep> {\n return this.#client.redo();\n }\n\n /** Reload the editor's page and resolve once the new document answers. */\n async reloadPage(): Promise<void> {\n await this.#client.reloadPage();\n }\n\n /** Mirrors the editor's `status` command \u2014 the full live editor state as JSON. */\n async status(): Promise<EditorState> {\n return this.#client.getState();\n }\n\n /** A live viewport PNG (`EditorClient.captureViewport`) \u2014 no direct CLI verb exists; this is the closest wire read. */\n async screenshot(size?: number): Promise<ViewportCapture> {\n return this.#client.captureViewport(size);\n }\n}\n", "/**\n * `lazyChainProxy` \u2014 turns an async \"resolve the real object\" function into\n * a synchronously-importable stand-in that supports the SAME call shape as\n * the real thing, including nested member access\n * (`editor.document.query(...)`), by recording the property-access PATH and only\n * resolving + walking it down at the point of an actual function CALL.\n *\n * This is what makes `index.ts`'s top-level `export const editor = ...` work\n * as a plain value a script can `import { editor } from '@volter/live'` and\n * call immediately \u2014 each call transparently awaits the memoized `connect()`\n * first.\n *\n * Limitation (by design, documented on `index.ts`'s exports too): only\n * FUNCTION-shaped access resolves through this proxy \u2014 `editor.document.query(s)`\n * works, but reading a plain data property would return another inert proxy,\n * not the real value, since there is no function CALL to trigger resolution.\n * Every documented `editor` member is a method, so this never bites the\n * documented surface.\n */\n\ntype AnyFn = (...args: unknown[]) => unknown;\n\nfunction isFunction(value: unknown): value is AnyFn {\n return typeof value === 'function';\n}\n\nfunction walk(root: unknown, path: PropertyKey[]): { thisArg: unknown; fn: unknown } {\n if (path.length === 0) return { thisArg: undefined, fn: root };\n let obj: Record<PropertyKey, unknown> = root as Record<PropertyKey, unknown>;\n for (let i = 0; i < path.length - 1; i++) {\n const key = path[i] as PropertyKey;\n obj = obj[key] as Record<PropertyKey, unknown>;\n }\n const lastKey = path[path.length - 1] as PropertyKey;\n return { thisArg: obj, fn: obj[lastKey] };\n}\n\n/**\n * `resolveRoot` is called (and its result awaited) on every terminal\n * function call reached through the returned proxy \u2014 callers typically wire\n * it to a memoized `connect()` (see `index.ts`), so repeated calls across\n * many proxy invocations still resolve only once.\n *\n * `hint` names where a member the root does NOT have lives instead\n * (`member-hints.ts`): consulted for the FIRST step of the path only, because\n * that is the member the caller named on the fa\u00E7ade \u2014 `editor.camera.set(\u2026)`\n * fails at `camera`, not at `set`.\n */\nexport function lazyChainProxy<T>(\n resolveRoot: () => Promise<unknown>,\n path: PropertyKey[] = [],\n hint?: (member: PropertyKey) => string | undefined,\n): T {\n const callableTarget = (() => {}) as unknown as object;\n return new Proxy(callableTarget, {\n get(_target, prop) {\n // Never look thenable \u2014 `await`ing a proxy (accidentally, or via a\n // generic helper checking `typeof x.then`) must not trigger resolution\n // or hang; there is no promise here, only a call-shaped stand-in.\n if (prop === 'then' || prop === 'catch' || prop === 'finally') return undefined;\n return lazyChainProxy(resolveRoot, [...path, prop], hint);\n },\n apply(_target, _thisArg, args) {\n return resolveRoot().then((root) => {\n const first = path[0];\n const pointer = first !== undefined && hint !== undefined && !(first in (root as object)) ? hint(first) : undefined;\n if (pointer !== undefined) throw new TypeError(`@volter/live: editor.${String(first)} does not exist. ${pointer}`);\n const { thisArg, fn } = walk(root, path);\n if (!isFunction(fn)) {\n const label = path.length > 0 ? path.map(String).join('.') : '(the connected value)';\n throw new TypeError(`@volter/live: ${label} is not a function on the connected session.`);\n }\n return fn.apply(thisArg, args);\n });\n },\n }) as T;\n}\n", "/** Resolve an existing session for exactly one project.\n * Prefer the project's hint, verify it against the served canonical path,\n * then consult the shared registry. Never fall back to another project. */\n\nimport { existsSync, readFileSync, realpathSync, statSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { resolveManifestPath } from '@volter/project/manifest/locate';\nimport { resolveProductForProject } from './product-locator.js';\nimport {\n EDITOR_SESSION_DISCOVERY_TIMEOUT_MS,\n type EditorSessionInfo,\n type SessionListingTransport as SessionDiscoveryTransport,\n HttpSessionDiscovery,\n servedProjectAnswer,\n withTimeout,\n} from './discovery.js';\n\n/** Nearest ancestor containing the project's canonical manifest. */\nexport function findProjectRootFrom(dir: string): string | null {\n let cur = resolve(dir);\n for (;;) {\n if (existsSync(resolveManifestPath(cur))) return cur;\n const parent = dirname(cur);\n if (parent === cur) return null;\n cur = parent;\n }\n}\n\n/** The minimal slice of `EditorTransport` `resolveSession` actually needs \u2014 narrower than the full interface so a test double only has to implement one method. */\nexport type SessionListingTransport = SessionDiscoveryTransport;\n\nexport interface ResolvedSession {\n /** Editor dev-server port the resolved session is listening on. */\n port: number;\n /** Absolute project root \u2014 the nearest ancestor of the requested directory containing `volter.project.json`. */\n projectRoot: string;\n}\n\nexport interface SessionResolutionDeps {\n /** Session listing + liveness verification \u2014 defaults to a real `HttpSessionDiscovery`. Overridable for tests. */\n transport?: SessionListingTransport;\n /** Project-root discovery \u2014 defaults to the real fs walk (`findProjectRootFrom` above). Overridable for tests. */\n findProjectRootFrom?: (dir: string) => string | null;\n /** Project-local session hint reader. Defaults to `.volter/session.json`. */\n readProjectSession?: (projectRoot: string) => ProjectSessionHint | null;\n /** Exact-session verifier. Defaults to GET /__editor/project + canonical project matching. */\n verifyProjectSession?: (hint: ProjectSessionHint, projectRoot: string) => Promise<boolean>;\n}\n\nexport interface ProjectSessionHint {\n port: number;\n pid: number;\n url: string;\n startedAt: string;\n}\n\nfunction canonicalPath(path: string): string {\n try {\n return realpathSync(path);\n } catch {\n return resolve(path);\n }\n}\n\n/** Whether two paths are the same folder on disk, which `canonicalPath` alone misses on Windows\n * (it keeps the letter case typed, and short names and `subst` drives unexpanded). */\nfunction sameDirectory(a: string, b: string): boolean {\n try {\n const x = statSync(a, { bigint: true });\n const y = statSync(b, { bigint: true });\n return x.dev === y.dev && x.ino === y.ino;\n } catch {\n return false;\n }\n}\n\n/** The code a refusal carries when the registry was read and no session opens the project: the\n * one state in which \"no editor is open here\" is a fact, which `close` answers as done. */\nexport const NO_SESSION_FOR_PROJECT = 'VOLTER_NO_SESSION_FOR_PROJECT';\n/** The `code` of the refusal for this project's session whose manifest does not load; it carries `session`. */\nexport const SESSION_MANIFEST_UNREADABLE = 'VOLTER_SESSION_MANIFEST_UNREADABLE';\n\nfunction readProjectSession(projectRoot: string): ProjectSessionHint | null {\n try {\n const value: unknown = JSON.parse(\n readFileSync(join(projectRoot, '.volter', 'session.json'), 'utf8'),\n );\n if (typeof value !== 'object' || value === null) return null;\n const hint = value as Record<string, unknown>;\n if (\n typeof hint['port'] !== 'number' ||\n !Number.isInteger(hint['port']) ||\n hint['port'] <= 0 ||\n typeof hint['pid'] !== 'number' ||\n typeof hint['url'] !== 'string' ||\n typeof hint['startedAt'] !== 'string'\n ) {\n return null;\n }\n return hint as unknown as ProjectSessionHint;\n } catch {\n return null;\n }\n}\n\n/**\n * Read project identity and manifest failure in one `/__editor/project` probe.\n * A serving path identifies the project even when its manifest is unreadable;\n * `project: null` without that path denotes no described project. Return\n * `undefined` when the server does not answer successfully.\n */\nasync function probeServedProject(\n port: number,\n): Promise<{ path: string | null; manifestError: string | null } | undefined> {\n try {\n const response = await fetch(`http://127.0.0.1:${port}/__editor/project`, {\n signal: AbortSignal.timeout(EDITOR_SESSION_DISCOVERY_TIMEOUT_MS),\n });\n if (!response.ok) return undefined;\n return servedProjectAnswer(await response.json());\n } catch {\n return undefined;\n }\n}\n\n/**\n * The refusal for a session that IS this project's and cannot be driven,\n * because the project's manifest does not load.\n *\n * A refusal, not an attach: with no readable manifest the editor page itself\n * renders its startup-error screen, so there is no editor behind this door to\n * bind `{ editor, session }` to. It names the failing file and key, so an\n * operator fixes the manifest rather than starting a second editor.\n */\nfunction manifestRefusal(projectRoot: string, manifestError: string, port: number): Error {\n return Object.assign(\n new Error(\n `@volter/live: the editor session for ${projectRoot} is live, but its volter.project.json does ` +\n 'not load, so there is no editor or project to drive \u2014 the editor page is showing this same ' +\n `error. Fix the manifest and retry; the session recovers on save, no restart needed.\\n${manifestError}`,\n ),\n // The session is still this project's, so a caller that only needs to END it (`close`) can.\n { code: SESSION_MANIFEST_UNREADABLE, session: { port, projectRoot } },\n );\n}\n\n/**\n * Distinguish failed discovery, a readable empty registry and sessions serving\n * other canonical paths. Include the requested and listed paths for a path\n * mismatch; only a confirmed absence carries `NO_SESSION_FOR_PROJECT`.\n */\nfunction noMatchingSessionRefusal(\n projectRoot: string,\n canon: string,\n sessions: readonly EditorSessionInfo[],\n discoveryFailure: string | null,\n): Error {\n if (discoveryFailure !== null) {\n return new Error(\n `@volter/live: could not complete editor session discovery while looking for ${projectRoot} \u2014 ` +\n `${discoveryFailure}. This is not the answer \"no editor is running\": the question went ` +\n 'unanswered, so nothing is known about what is live. The step named above is the one that ' +\n 'did not answer: that session\\'s server holds its port but did not reply to the request. ' +\n 'Its own log (logs/editor-<port>.log in the project it serves) says how far its start got; ' +\n `${sessionsCommandFor(projectRoot)} asks the same question directly.`,\n );\n }\n if (sessions.length === 0) {\n return Object.assign(new Error(\n `@volter/live: the editor session registry is readable and lists NO live sessions, so none ` +\n `covers ${projectRoot}. @volter/live only attaches to an already-running session \u2014 it ` +\n `never starts one \u2014 so run ${editCommandFor(projectRoot)} in that project first, then retry.`,\n ), { code: NO_SESSION_FOR_PROJECT });\n }\n const listed = sessions\n .map((s) => ` port ${s.port} \u2192 ${s.project === null ? '(no project)' : s.project}`)\n .join('\\n');\n // A listed session that is this same folder under another spelling is not \"nothing open here\":\n // it keeps the refusal, so `close` does not report done while that editor runs on.\n const thisFolderElsewhere = sessions.some((s) => s.project !== null && sameDirectory(s.project, projectRoot));\n return Object.assign(new Error(\n `@volter/live: ${sessions.length} live editor session(s) are running, but none of them opens ` +\n `${projectRoot}. @volter/live never silently attaches to a different project.\\n` +\n ` looking for (resolved): ${canon}\\n` +\n ` live sessions:\\n${listed}\\n` +\n ' If one of those is meant to be this project, the two paths differ after resolution \u2014 ' +\n 'the usual cause is a git worktree or a symlink, where the session was opened through a ' +\n `different path to the same files. Run ${editCommandFor(projectRoot)} from THIS path, or use the path the ` +\n 'session lists.',\n ), thisFolderElsewhere ? {} : { code: NO_SESSION_FOR_PROJECT });\n}\n\n/**\n * Resolve `projectDir` (default `process.cwd()`) to its already-running editor\n * session. Verify the project hint, then consult the shared registry, with\n * each discovery probe bounded by `EDITOR_SESSION_DISCOVERY_TIMEOUT_MS`.\n * Throw when no project manifest or matching live session is found.\n */\nexport async function resolveSession(\n projectDir: string = process.cwd(),\n deps: SessionResolutionDeps = {},\n): Promise<ResolvedSession> {\n const findRoot = deps.findProjectRootFrom ?? findProjectRootFrom;\n const transport = deps.transport ?? new HttpSessionDiscovery();\n\n const projectRoot = findRoot(projectDir);\n if (projectRoot === null) {\n throw new Error(\n `@volter/live: no volter.project.json found in ${projectDir} or any parent directory \u2014 is this a project?`,\n );\n }\n\n // The editor writes this exact-project hint at boot and removes it on\n // shutdown. Prefer it over a global all-session scan: it is both faster and\n // immune to an unrelated slow/dead registry entry consuming the discovery\n // deadline. The live probe remains authoritative, so a stale file cannot\n // attach us to the wrong project or port.\n const localHint = (deps.readProjectSession ?? readProjectSession)(projectRoot);\n if (localHint) {\n // `deps.verifyProjectSession` is the test-only override and keeps its\n // boolean meaning: \"this hint is this project's session, and healthy\".\n // With no override we read the probe ourselves, because the same response\n // carries WHY a served project cannot be described.\n if (deps.verifyProjectSession) {\n if (await deps.verifyProjectSession(localHint, projectRoot)) {\n return { port: localHint.port, projectRoot };\n }\n } else {\n const served = await probeServedProject(localHint.port);\n if (served?.path != null && canonicalPath(served.path) === canonicalPath(projectRoot)) {\n if (served.manifestError !== null) throw manifestRefusal(projectRoot, served.manifestError, localHint.port);\n return { port: localHint.port, projectRoot };\n }\n }\n }\n\n let sessions: EditorSessionInfo[];\n // Retain discovery failures separately from an empty session list so the\n // refusal names an unanswered probe rather than claiming no session exists.\n let discoveryFailure: string | null = null;\n try {\n sessions = await withTimeout(\n transport.listSessions(EDITOR_SESSION_DISCOVERY_TIMEOUT_MS),\n EDITOR_SESSION_DISCOVERY_TIMEOUT_MS,\n 'editor session discovery',\n );\n } catch (err) {\n sessions = [];\n discoveryFailure = err instanceof Error ? err.message : String(err);\n }\n\n const canon = canonicalPath(projectRoot);\n const match = sessions.find((s) => s.project !== null && canonicalPath(s.project) === canon);\n if (!match) throw noMatchingSessionRefusal(projectRoot, canon, sessions, discoveryFailure);\n\n if (match.manifestError != null) throw manifestRefusal(projectRoot, match.manifestError, match.port);\n\n return { port: match.port, projectRoot };\n}\n\n/** `` `<product> edit` `` for the product this project declares, or a generic\n * phrase when it declares none \u2014 this package serves every product and\n * names only the one the project installed. */\nfunction editCommandFor(projectRoot: string): string {\n return verbFor(projectRoot, 'edit');\n}\n\nfunction sessionsCommandFor(projectRoot: string): string {\n return verbFor(projectRoot, 'sessions');\n}\n\nfunction verbFor(projectRoot: string, verb: string): string {\n try {\n return `\\`${resolveProductForProject(projectRoot).command} ${verb}\\``;\n } catch {\n return `its product's \\`${verb}\\` command`;\n }\n}\n", "// Finding the project manifest ON DISK. There is ONE filename (`./filename.ts`).\n//\n// Deliberately dependency-light \u2014 `node:fs` + `node:path` + `./filename` and\n// NOTHING else (no Zod, no `./load`). Several callers are explicitly\n// schema-free by design (`packages/editor-core/server/project-root-surface.ts`,\n// `packages/editor-react/serving/ui-oid-plugin.ts`) and must be able to locate a\n// manifest without dragging the validator in.\n\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { MANIFEST_FILENAME } from './filename';\n\n/**\n * The manifest path inside `dir`: always `volter.project.json`, so a \"not\n * found\" message names the filename a project must be using.\n *\n * This is the drop-in replacement for a hand-written `join(dir, \u2026)` everywhere\n * a manifest is READ. Writers want {@link manifestWritePath}.\n */\nexport function resolveManifestPath(dir: string): string {\n return join(dir, MANIFEST_FILENAME);\n}\n\n/** True when `dir` holds a manifest. */\nexport function hasManifest(dir: string): boolean {\n return existsSync(join(dir, MANIFEST_FILENAME));\n}\n\n/** Where a manifest gets WRITTEN in `dir`. There is one answer. */\nexport function manifestWritePath(dir: string): string {\n return join(dir, MANIFEST_FILENAME);\n}\n", "// The project manifest's FILENAME. There is exactly ONE, and this module is the one place it is\n// spelled out. It is dependency-free (no `node:fs`) so browser bundles can import it; the\n// filesystem side lives in `./locate` (`resolveManifestPath`, `hasManifest`).\n\n/** The manifest filename. Every reader reads it; every writer writes it. */\nexport const MANIFEST_FILENAME = 'volter.project.json';\n", "/** Memoized async connection. Concurrent ensure calls share the same in-flight promise. */\nexport interface LazySession<T> {\n /** Returns the memoized promise, creating it via `factory()` on first call. */\n ensure(): Promise<T>;\n}\n\nexport function createLazySession<T>(factory: () => Promise<T>): LazySession<T> {\n let promise: Promise<T> | null = null;\n return {\n ensure(): Promise<T> {\n promise ??= factory();\n return promise;\n },\n };\n}\n", "/**\n * NAMES AN AGENT REACHES FOR THAT THE FA\u00C7ADE DOES NOT HAVE, and where the\n * thing it wanted actually lives.\n *\n * A call to `editor.setCamera(...)` would otherwise fail with the engine's bare\n * \"editor.setCamera is not a function\", though the camera is reachable through\n * `editor.present`'s `viewport.camera`. The refusal is the one moment the\n * caller is certainly reading, so that is where the pointer goes.\n *\n * TARGETED, NOT A CATCH-ALL. Only the names below are intercepted, each with\n * the door it was looking for. Every other missing member keeps JavaScript's\n * own behaviour (`undefined`, then the engine's TypeError), so this table can\n * never turn a typo into a wrong suggestion \u2014 it only ever adds what is known.\n */\n\nconst CAMERA_HINT =\n 'The viewport camera is posed through a presented view: ' +\n 'await editor.present({ version: 1, viewport: { camera: { position: { x, y, z }, target: { x, y, z }, fov } } }) ' +\n '(stage space: metres, Y up), ' +\n 'and read back with (await editor.currentView()).viewport.camera. ' +\n 'editor.frame() and editor.orbit() frame or swing around the subject instead.';\n\n/** Missing `editor` member \u2192 what to use instead. */\nconst EDITOR_MEMBER_HINTS: Readonly<Record<string, string>> = {\n camera: CAMERA_HINT,\n setCamera: CAMERA_HINT,\n getCamera: CAMERA_HINT,\n cameraPose: CAMERA_HINT,\n setCameraPose: CAMERA_HINT,\n moveCamera: CAMERA_HINT,\n poseCamera: CAMERA_HINT,\n lookAt: CAMERA_HINT,\n};\n\n/** The pointer for a member `editor` does not have, or undefined when there is none to give. */\nexport function editorMemberHint(member: PropertyKey): string | undefined {\n return typeof member === 'string' && Object.hasOwn(EDITOR_MEMBER_HINTS, member) ? EDITOR_MEMBER_HINTS[member] : undefined;\n}\n\n/**\n * `editor` as `eval` binds it: the same object, except that reading one of the\n * hinted names it does NOT have throws the hint, naming `editor.member`.\n * Thrown on READ, not on call, so `editor.camera.position` is caught as well as\n * `editor.setCamera(...)`.\n *\n * Methods come back bound to the real object: `LiveEditor` keeps its client in\n * a `#`-private field, which a call whose `this` is the proxy cannot read.\n */\nexport function withEditorMemberHints<T extends object>(target: T): T {\n return new Proxy(target, {\n get(object, key) {\n if (!(key in object)) {\n const hint = editorMemberHint(key);\n if (hint !== undefined) throw new TypeError(`editor.${String(key)} does not exist. ${hint}`);\n }\n const value: unknown = Reflect.get(object, key, object);\n return typeof value === 'function' ? (value as (...args: unknown[]) => unknown).bind(object) : value;\n },\n });\n}\n", "/** Attach to an existing editor session; this package never launches one. */\nimport { EditorClient } from './client.js';\nimport { LiveEditor } from './editor.js';\nimport { lazyChainProxy } from './lazy-proxy.js';\nimport { resolveSession, type ResolvedSession, type SessionResolutionDeps } from './session.js';\nimport { createLazySession } from './singleton.js';\nimport { editorMemberHint } from './member-hints.js';\n\nexport { LiveEditor, inferAssetKind, type PanelName } from './editor.js';\nexport { LiveEditorDocument } from './editor-document.js';\nexport type { DocumentGestureOptions, DocumentKeyOptions, DocumentPasteOptions } from './editor-document.js';\nexport { editorMemberHint, withEditorMemberHints } from './member-hints.js';\nexport { resolveSession, findProjectRootFrom, NO_SESSION_FOR_PROJECT, SESSION_MANIFEST_UNREADABLE } from './session.js';\nexport type { ResolvedSession, SessionResolutionDeps, SessionListingTransport, ProjectSessionHint } from './session.js';\nexport type { ActiveDocumentCapture, EditorView, PresentedEditorView } from '@volter/sdk';\n\nexport interface LiveBindings {\n editor: LiveEditor;\n}\nexport interface LiveSession extends LiveBindings {\n session: ResolvedSession;\n}\nfunction bindTo(port: number): LiveBindings {\n const client = new EditorClient({ url: `http://127.0.0.1:${port}` });\n return { editor: new LiveEditor(client) };\n}\n/** Inspect the callable surface without connecting; calls fail on port zero. */\nexport function unconnectedBindings(): LiveBindings { return bindTo(0); }\n\n/** Attach only to the session serving the requested project's canonical path. */\nexport async function connect(projectDir?: string, deps?: SessionResolutionDeps): Promise<LiveSession> {\n const session = await resolveSession(projectDir, deps);\n return { ...bindTo(session.port), session };\n}\nconst lazySession = createLazySession(() => connect());\nexport const editor: LiveEditor = lazyChainProxy<LiveEditor>(() => lazySession.ensure().then(s => s.editor), [], editorMemberHint);\n"],
5
- "mappings": "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",
6
- "names": ["join", "join"]
4
+ "sourcesContent": ["/** Session binding for reading and driving the editor's named surfaces.\n * Each verb accepts a document-probe scope: document, header, shelf, rail,\n * outliner, utility or area. Targets outside that scope are refused. Chrome\n * scopes remain available without an open document. The eval member listing\n * groups these verbs under editor.document. */\n\nimport type {\n DocumentProbeResult,\n DocumentProbeScope,\n DocumentProbeStep,\n} from '@volter/sdk';\nimport type { EditorClient } from './client.js';\n\n/** Which named surface a verb runs against; `document` when omitted. */\nexport interface DocumentScopeOption {\n scope?: DocumentProbeScope;\n}\n\n/** Modifier/targeting options shared by the gesture verbs. */\nexport interface DocumentGestureOptions extends DocumentScopeOption {\n /** Which match to drive when the selector matches several (default 0). */\n index?: number;\n}\n\nexport interface DocumentKeyOptions extends DocumentGestureOptions {\n /** Target one element instead of whatever inside the scope has focus. */\n selector?: string;\n code?: string;\n ctrlKey?: boolean;\n metaKey?: boolean;\n shiftKey?: boolean;\n altKey?: boolean;\n /** Hold the key this long before releasing it (a person holding W).\n * Finite, nonnegative, and at most 120,000 ms. */\n holdMs?: number;\n}\n\nexport interface DocumentPasteOptions extends DocumentGestureOptions {\n selector?: string;\n}\n\nexport interface DocumentTypeOptions extends DocumentGestureOptions {\n /** The field; omitted types into whatever inside the scope has focus. */\n selector?: string;\n /** Replace what the field holds first (default true). */\n replace?: boolean;\n /** Press Enter after the text (default true). */\n enter?: boolean;\n}\n\nexport class LiveEditorDocument {\n readonly #client: EditorClient;\n\n constructor(client: EditorClient) {\n this.#client = client;\n }\n\n /**\n * Read matching elements inside the active document: tag, text, attributes,\n * value/checked/disabled and rect. `matched` is the total before `limit`.\n *\n * `styles` additionally resolves named properties per match \u2014 and resolving\n * is the point, because a theme token is an expression until an element\n * paints it. Ask for the standard property to learn the colour a person\n * sees; ask for a `--volter-\u2026` custom property to learn what a rule WOULD\n * paint, which is the only way to measure a `:hover` colour (`:hover` is a\n * browser state no synthetic event can enter, so there is deliberately no\n * hover verb on this door).\n *\n * await editor.document.query('.volter-tree-row', {\n * styles: ['backgroundColor', '--volter-widget-regular-hover'],\n * });\n */\n async query(\n selector: string,\n options?: DocumentScopeOption & { limit?: number; styles?: readonly string[] },\n ): Promise<DocumentProbeResult> {\n return this.#probe({\n action: 'query',\n selector,\n ...(options?.scope === undefined ? {} : { scope: options.scope }),\n ...(options?.limit === undefined ? {} : { limit: options.limit }),\n ...(options?.styles === undefined ? {} : { styles: [...options.styles] }),\n });\n }\n\n /** A REAL pointer gesture (pointerdown/mousedown/focus/pointerup/mouseup/click)\n * \u2014 not `element.click()`, which a `pointerdown` listener never sees. */\n async click(\n selector: string,\n options?: DocumentGestureOptions & {\n clicks?: number;\n at?: [number, number];\n altKey?: boolean;\n ctrlKey?: boolean;\n metaKey?: boolean;\n shiftKey?: boolean;\n },\n ): Promise<DocumentProbeResult> {\n // Refuse unknown options before dispatching the gesture.\n const known = ['scope', 'index', 'clicks', 'at', 'altKey', 'ctrlKey', 'metaKey', 'shiftKey'];\n const unknown = Object.keys(options ?? {}).filter((key) => !known.includes(key));\n if (unknown.length > 0) throw new Error(`click has no option ${unknown.map((key) => `\\`${key}\\``).join(', ')}; its options are scope, index, clicks, at ([x, y] fractions of the element's box) and the modifier keys altKey, ctrlKey, metaKey and shiftKey.`);\n return this.#probe({\n action: 'click',\n selector,\n ...(options?.scope === undefined ? {} : { scope: options.scope }),\n ...(options?.index === undefined ? {} : { index: options.index }),\n ...(options?.clicks === undefined ? {} : { clicks: options.clicks }),\n ...(options?.at === undefined ? {} : { at: options.at }),\n ...(options?.altKey ? { altKey: true } : {}),\n ...(options?.ctrlKey ? { ctrlKey: true } : {}),\n ...(options?.metaKey ? { metaKey: true } : {}),\n ...(options?.shiftKey ? { shiftKey: true } : {}),\n });\n }\n\n /**\n * TYPE into a field and commit with Enter, the way a person does \u2014 one\n * character at a time through the prototype's value setter, between real\n * `keydown`/`keyup`.\n *\n * `paste` is not a substitute: an untrusted `ClipboardEvent` performs no\n * default action, so a plain `<input>` with no paste handler keeps its old\n * value. Omit `selector` to type into whatever inside the scope has focus \u2014\n * which is what a rename field is, one gesture after\n * `click(row, { clicks: 2 })`.\n */\n async type(text: string, options?: DocumentTypeOptions): Promise<DocumentProbeResult> {\n return this.#probe({ action: 'type', text, ...(options ?? {}) });\n }\n\n /**\n * A real pointer DRAG across one matched element \u2014 press at `from`, move,\n * release at `to`. A zero-length drag presses and releases at one fraction.\n *\n * `from`, `to` and every point in `via` are `[x, y]` FRACTIONS OF THE\n * MATCHED ELEMENT'S BOX, 0..1 from its top-left \u2014 NEVER pixels and never\n * page coordinates. `[0.5, 0.5]` is its center, `[1, 0]` its top-right.\n * Compute a pixel target by measuring the element first: `query` answers\n * its `rect`, and `(px - rect.x) / rect.width` is the fraction to pass.\n */\n async drag(\n selector: string,\n options: DocumentGestureOptions & {\n from: [number, number];\n to: [number, number];\n via?: [number, number][];\n steps?: number;\n altKey?: boolean;\n ctrlKey?: boolean;\n metaKey?: boolean;\n shiftKey?: boolean;\n /** 0 primary (default), 1 middle, 2 secondary. */\n button?: 0 | 1 | 2;\n /** `via`/`to` may leave the element's box after the press (a handle drag). */\n leave?: boolean;\n /** Keep the button down at `to`, for readings taken mid-gesture; {@link release} lets go. */\n hold?: boolean;\n },\n ): Promise<DocumentProbeResult> {\n return this.#probe({\n action: 'drag',\n selector,\n ...(options.scope === undefined ? {} : { scope: options.scope }),\n from: options.from,\n to: options.to,\n ...(options.via === undefined ? {} : { via: options.via }),\n ...(options.steps === undefined ? {} : { steps: options.steps }),\n ...(options.index === undefined ? {} : { index: options.index }),\n ...(options.altKey === undefined ? {} : { altKey: options.altKey }),\n ...(options.ctrlKey === undefined ? {} : { ctrlKey: options.ctrlKey }),\n ...(options.metaKey === undefined ? {} : { metaKey: options.metaKey }),\n ...(options.shiftKey === undefined ? {} : { shiftKey: options.shiftKey }),\n ...(options.button === undefined ? {} : { button: options.button }),\n ...(options.leave === undefined ? {} : { leave: options.leave }),\n ...(options.hold === undefined ? {} : { hold: options.hold }),\n });\n }\n\n /** Lets go of the drag `hold: true` left pressed, where it was left. */\n async release(options?: DocumentGestureOptions): Promise<DocumentProbeResult> {\n return this.#probe({ action: 'release', ...(options?.scope === undefined ? {} : { scope: options.scope }) });\n }\n\n /** A real keydown/keyup on the target, or on whatever inside the document has focus. */\n async key(key: string, options?: DocumentKeyOptions): Promise<DocumentProbeResult> {\n return this.#probe({ action: 'key', key, ...(options ?? {}) });\n }\n\n /** A real `ClipboardEvent` carrying `text/plain` \u2014 the gesture nothing else\n * in the product can produce. */\n async paste(text: string, options?: DocumentPasteOptions): Promise<DocumentProbeResult> {\n return this.#probe({ action: 'paste', text, ...(options ?? {}) });\n }\n\n /**\n * Choose `value` on a `<select>` \u2014 a native dropdown's options are drawn by\n * the OS, so `click` has nothing in the document to resolve, and a plain\n * `element.value =` is invisible to React. Set through the prototype's own\n * value setter plus `input`/`change`; `value` is the option's `value`, not\n * its label. An unknown value is refused with the options it does offer.\n */\n async select(\n selector: string,\n value: string,\n options?: DocumentGestureOptions,\n ): Promise<DocumentProbeResult> {\n return this.#probe({\n action: 'select',\n selector,\n value,\n ...(options?.scope === undefined ? {} : { scope: options.scope }),\n ...(options?.index === undefined ? {} : { index: options.index }),\n });\n }\n\n /**\n * Run `step` in the editor page against the active document's published\n * context, with its document id in `info`. The document owns the context's\n * API. The step's source is serialized, so inline every value it needs and\n * return plain data.\n */\n async run<T = unknown>(\n step: (ctx: unknown, info: { documentId: string }) => T | Promise<T>,\n ): Promise<T> {\n return this.#client.documentScript<T>(step.toString());\n }\n\n #probe(step: DocumentProbeStep): Promise<DocumentProbeResult> {\n return this.#client.documentProbe(step);\n }\n}\n", "/** Editor and document automation over the shared session command wire.\n * Modeling executes in the editor tab; this client owns no model state. */\n\nimport type {\n ActiveDocumentCapture,\n AssetKind,\n AssetPreviewCapture,\n AssetPreviewOptions,\n AssetPreviewShotSetDefinition,\n AssetPreviewSource,\n CaptureDimensions,\n DocumentLookOutcome,\n StageFrameCostReading,\n EditorChromeCapture,\n EditorChromeCaptureOptions,\n EditorState,\n EditorView,\n EditorWorkspaceName,\n InspectedFieldWrite,\n InspectedHierarchy,\n InspectedInspection,\n LabeledShotSetCapture,\n PresentedEditorView,\n ShadingMode,\n StructureOp,\n StructureOpOptions,\n StructureOpResult,\n ViewPreset,\n ViewportCapture,\n} from '@volter/sdk';\nimport type { EditorClient, HistoryStep, OpenedDocument } from './client.js';\nimport { LiveAssetLibrary } from './asset-library.js';\nimport { LiveEditorDocument } from './editor-document.js';\n\n/** A panel `showPanel` can focus: the console, the build surface, or any key\n * the editor's own static-panel registry holds (`hierarchy`, `asset-library`,\n * `inspector`, `history`, \u2026) \u2014 which is why this is open: the registry, not\n * this union, is the vocabulary. */\nexport type PanelName =\n | 'console'\n // Keeps the literals above in autocomplete while admitting every key the\n // editor's registry holds \u2014 the registry answers, this union only hints.\n | (string & {});\n\nconst EXTENSION_KIND: Record<string, AssetKind> = {\n '.glb': 'model',\n '.gltf': 'model',\n '.png': 'image',\n '.jpg': 'image',\n '.jpeg': 'image',\n '.webp': 'image',\n '.gif': 'image',\n '.svg': 'image',\n '.hdr': 'image',\n '.exr': 'image',\n '.mp4': 'video',\n '.webm': 'video',\n '.mp3': 'audio',\n '.ogg': 'audio',\n '.wav': 'audio',\n '.flac': 'audio',\n '.glsl': 'source',\n '.vert': 'source',\n '.frag': 'source',\n // Source kinds select SourceAssetViewer, which routes project scripts by content to\n // LiveModuleDocument. Keep these extensions aligned with its isProjectScriptPath predicate.\n '.ts': 'source',\n '.tsx': 'source',\n '.mts': 'source',\n '.cts': 'source',\n '.js': 'source',\n '.jsx': 'source',\n '.mjs': 'source',\n '.cjs': 'source',\n};\n\n/**\n * Lightweight extension-based `AssetKind` guess for `openAsset`'s optional\n * `kind` argument. Callers with an unusual extension can always pass `kind`\n * explicitly.\n */\nexport function inferAssetKind(path: string): AssetKind {\n // `'prefab'` is an `@volter/sdk` AssetKind that view links name.\n if (path.endsWith('.prefab.json')) return 'prefab';\n const dot = path.lastIndexOf('.');\n const ext = dot >= 0 ? path.slice(dot).toLowerCase() : '';\n return EXTENSION_KIND[ext] ?? 'json';\n}\n\nexport class LiveEditor {\n /** `#`-private, not `private`: `<command> eval --list` enumerates this object's\n * real runtime members, and TypeScript's erased `private` would leave the\n * raw `EditorClient` advertised beside them. */\n readonly #client: EditorClient;\n\n /** Read and drive DOM within a named scope: the active document by default, or editor chrome\n * such as header, shelf, rail, outliner, utility and area. Targets outside the scope are refused.\n * See `@volter/sdk`'s editor-document-probe for scope and gesture contracts. */\n readonly document: LiveEditorDocument;\n\n /** The asset library: search a source, list an asset's files, download one into the project with its license\n * recorded (`asset-library.ts`). */\n readonly assetLibrary: LiveAssetLibrary;\n\n constructor(client: EditorClient) {\n this.#client = client;\n this.document = new LiveEditorDocument(client);\n this.assetLibrary = new LiveAssetLibrary(client);\n }\n\n /** A verb a composed package contributes (`<package>-<verb>`), waited on for its own row's budget. */\n async contributedVerb<T extends object = Record<string, unknown>>(\n type: string,\n fields: Record<string, unknown> = {},\n ): Promise<T> {\n return this.#client.contributedVerb<T>(type, fields);\n }\n\n /**\n * The active authoring adapter's persistence destination \u2014 where a save would\n * land (`status().savePath`). A read only: a stage root has no scene document\n * to open, and its root is activated instead.\n */\n async scene(): Promise<string | null> {\n const state = await this.#client.getState();\n return state.savePath;\n }\n\n /**\n * Make the connected human editor show the same subject/view as the agent.\n * The returned URL is a compact, shareable projection \u2014 not a serialized\n * workspace or document payload.\n */\n async present(view: EditorView): Promise<PresentedEditorView> {\n return this.#client.present(view);\n }\n\n /** The human editor's actual active document, selection, camera and utility. */\n async currentView(): Promise<EditorView> {\n return this.#client.currentView();\n }\n\n /** Capture the active document's render without viewport navigation gizmos or readouts.\n * A number requests a square; `{width, height}` requests a shaped frame, bounded by\n * `CaptureDimensions`. Supply a view to present and capture it in one request.\n * Use `captureEditorChrome({ region: 'document' })` to include viewport chrome. */\n async captureActiveDocument(\n size?: CaptureDimensions,\n view?: EditorView,\n ): Promise<ActiveDocumentCapture> {\n return this.#client.captureActiveDocument(size, view);\n }\n\n /**\n * Photograph the editor PAGE \u2014 every panel, tab strip and viewport as the\n * person sees it. the editor's `screenshot editor` command is this verb from the shell. The\n * one door for judging chrome sighted: a skin, a workspace arrangement or a\n * contributed panel is looked at through this, never guessed at from DOM\n * probes. The page at its own layout, `scale` output pixels per CSS pixel\n * (default `devicePixelRatio`) \u2014 a 1 px border or a glyph stroke is only\n * judgeable at the scale the reference it is compared against was captured\n * at, and the result reports its own `size` and `scale`.\n */\n async captureEditorChrome(options?: EditorChromeCaptureOptions): Promise<EditorChromeCapture> {\n return this.#client.captureEditorChrome(options);\n }\n\n /** `'all'` -> `EditorClient.selectAll()` (mirrors `volter select --all`); otherwise `EditorClient.select(id)` (mirrors `volter select <entityId>`). */\n async select(id: string | 'all'): Promise<void> {\n if (id === 'all') {\n await this.#client.selectAll();\n return;\n }\n await this.#client.select(id);\n }\n\n /** Mirrors `volter deselect`. */\n async deselect(): Promise<void> {\n await this.#client.select(null);\n }\n\n /** No `id` -> focus the current selection (mirrors bare `volter focus`); `id` given -> focus that entity. */\n async focus(id?: string): Promise<void> {\n if (id !== undefined) {\n await this.#client.focusEntity(id);\n return;\n }\n await this.#client.focusSelection();\n }\n\n /**\n * Frame the edit viewport camera on one entity. Same framing as\n * `focus(id)`, but an entity id the scene does not know THROWS, naming the\n * id \u2014 where `focus` quietly does nothing. Reach for this whenever the next\n * step reads the viewport (`screenshot()`, an\n * `assetPreview(..., { stage: 'scene' })`): a framing that silently missed\n * would otherwise be indistinguishable from one that worked.\n */\n async frame(entityId: string): Promise<void>;\n /**\n * Bare `frame()` frames the OPEN asset document's subject instead \u2014 its\n * selection if it has one, else the whole model: the toolbar's own Frame\n * button, reachable from a script. `fit` scales the fitted distance (1 is\n * that button's tight fit, 1.5 stands back a little for a shot).\n */\n async frame(options?: { readonly fit?: number }): Promise<void>;\n async frame(target?: string | { readonly fit?: number }): Promise<void> {\n if (typeof target === 'string') {\n await this.#client.frameEntity(target);\n return;\n }\n await this.#client.frameDocument(target?.fit);\n }\n\n /**\n * WATCH THE AGENT LOOK AROUND THE MODEL.\n *\n * Swings the open asset document's camera \u2014 the camera the human's tab is\n * showing \u2014 around the framed subject by `azimuth`/`elevation` RADIANS,\n * animated over `duration` seconds (default 0.6), and resolves when the move\n * ends. This is deliberately not a jump cut: the point of the verb is that a\n * person watching sees the agent walk around the thing it is working on.\n *\n * `await editor.orbit({ azimuth: Math.PI / 2 })` \u2014 a quarter turn to the right.\n *\n * There is ONE camera, and the human owns it: a drag during the move cancels\n * it exactly where it is, and the resolved outcome says `cancelledBy:\n * 'human'` rather than throwing. A second look verb supersedes the first.\n * The move is drawn by the document's own frame loop, so a document that\n * isn't being drawn (background tab, inactive panel) doesn't orbit.\n */\n async orbit(options: {\n /** RADIANS, relative to where the camera is now. `Math.PI / 2` is a\n * quarter turn; degrees are not accepted and `90` is fourteen turns. */\n readonly azimuth?: number;\n /** RADIANS, relative to where the camera is now. */\n readonly elevation?: number;\n /** SECONDS the move takes (default 0.6). */\n readonly duration?: number;\n }): Promise<DocumentLookOutcome> {\n // Refuse unknown keys by name and include the supported keys and units.\n const known = ['azimuth', 'elevation', 'duration'];\n const unknown = Object.keys(options ?? {}).filter((key) => !known.includes(key));\n if (unknown.length > 0)\n throw new Error(\n `editor.orbit: ${unknown.join(', ')} ${unknown.length === 1 ? 'is not a key' : 'are not keys'} ` +\n 'this verb takes. It takes azimuth and elevation in RADIANS (relative to where the ' +\n 'camera is now) and duration in SECONDS.',\n );\n return this.#client.orbitDocument(options);\n }\n\n /**\n * A slow full revolution of the open document's subject \u2014 {@link orbit} with\n * the turns spelled out and a constant angular rate. Resolves at the end of\n * the last revolution.\n */\n async turntable(options?: {\n readonly seconds?: number;\n readonly revolutions?: number;\n }): Promise<DocumentLookOutcome> {\n return this.#client.turntableDocument(options);\n }\n\n /**\n * What a frame of the open 3D document's stage costs when nothing caps it: `frames` of the\n * stage's own frame back to back, each waited out on the GPU (median, p95, min ms), the canvas\n * with its device pixel ratio, what was drawn after culling against what the scene holds, and\n * the draw mode. `stage` names another stage by its id (a split's second area,\n * `<documentId>#area-2`).\n */\n async frameCost(options?: { readonly frames?: number; readonly stage?: string; readonly quality?: 'full' | 'navigation' }): Promise<StageFrameCostReading> {\n return this.#client.frameCostDocument(options);\n }\n\n async view(preset: ViewPreset): Promise<void> {\n await this.#client.viewPreset(preset);\n }\n\n\n async workspace(id: EditorWorkspaceName): Promise<{ readonly workspace: EditorWorkspaceName; readonly applied: boolean }> {\n return this.#client.setWorkspace(id);\n }\n\n /**\n * Apply a STYLE BUNDLE by id \u2014 the chrome's palette, material and icon set in\n * one gesture, the session door beside\n * `View \u2192 <Style> Style`. A bundle the open project does not offer refuses\n * and names the vocabulary; `currentView().style` reports the one worn.\n */\n async style(id: string): Promise<void> {\n await this.#client.setStyle(id);\n }\n\n /**\n * A document stage's viewport PRESENTATION \u2014 its draw mode, lighting, backdrop and overlays\n * (`@volter/sdk/viewport-presentation`) \u2014 resolved. With `layer`, that choice is\n * recorded for the view first, as a person's toolbar change would be, e.g.\n * `presentation('model:src/models/cube.blend', { all: { lighting: { studioPreset: 'kit' } } })`.\n */\n async presentation(\n documentId: string,\n layer?: Parameters<EditorClient['viewportPresentation']>[1],\n ): ReturnType<EditorClient['viewportPresentation']> {\n return this.#client.viewportPresentation(documentId, layer);\n }\n\n /** Focus an editor panel: the console, the build surface, or\n * any key the editor's static-panel registry holds \u2014 an unknown key refuses\n * naming the ones it does. */\n async showPanel(name: PanelName): Promise<void> {\n switch (name) {\n case 'console':\n await this.#client.toggleConsole();\n return;\n default:\n // Every other name is the EDITOR's to resolve, against its live panel\n // registry. A list kept here could only ever be a copy going stale.\n await this.#client.showPanel(name);\n return;\n }\n }\n\n /** `kind` inferred from `path`'s extension when omitted (`inferAssetKind`) \u2014 pass it explicitly to override. */\n async openAsset(path: string, kind?: AssetKind): Promise<void> {\n // Finder-listed documents use their document opener rather than asset-kind inference.\n const document = (await this.#client.documentTable()).entries.find((entry) => entry.source?.path === path);\n if (document)\n throw new Error(`${path} is a ${document.kind} document, not an asset: open it with editor.open(\"${document.id}\").`);\n await this.#client.openAsset(path, kind ?? inferAssetKind(path));\n }\n\n /**\n * SELECT a project asset \u2014 the browser's single click, which fills the\n * Inspector without opening a document. `openAsset` is the double click.\n * Selecting a path nothing matches is not an error \u2014 the Inspector shows\n * what it has, exactly as it does for a human.\n */\n async selectAsset(path: string): Promise<void> {\n await this.#client.selectAsset(path);\n }\n\n /**\n * Captures the editor's native four-view preview. A bare string is a\n * project-relative asset path (the common case); an explicit source object\n * targets a path, a LIVE SCENE ENTITY (`assetPreview({ entityId }, \u2026)`) \u2014\n * which is what makes `options.stage: 'scene'`, the entity photographed\n * where it stands under the scene's own lighting, reachable from here \u2014 or\n * RAW GLB BYTES (`assetPreview({ glbBase64 }, \u2026)`), for a model that exists\n * only in the calling Node process's memory and has never been written to\n * disk. `stage` defaults to `'lab'`, the neutral Asset Lab staging, and the\n * bytes form is lab-only.\n */\n async assetPreview(\n source: string | AssetPreviewSource,\n options?: AssetPreviewOptions,\n ): Promise<AssetPreviewCapture> {\n return this.#client.captureAssetPreview(\n typeof source === 'string' ? { assetPath: source } : source,\n options,\n );\n }\n\n /**\n * The same subject photographed as a LABELED SHOT SET instead of the four\n * views \u2014 a caller-supplied definition of turntable yaws and bone-anchored\n * crops, rendered against the asset's own skeleton, with a contact sheet.\n * Every source {@link assetPreview} takes works here, GLB bytes included:\n * a shot set stages its own subject, so it needs no place to stand.\n */\n async assetPreviewShots(\n source: string | AssetPreviewSource,\n definition: AssetPreviewShotSetDefinition,\n options?: AssetPreviewOptions,\n ): Promise<LabeledShotSetCapture> {\n return this.#client.captureShotSetPreview(\n typeof source === 'string' ? { assetPath: source } : source,\n definition,\n options,\n );\n }\n\n async grid(on: boolean): Promise<void> {\n await this.#client.setGrid(on);\n }\n\n async helpers(on: boolean): Promise<void> {\n await this.#client.setHelpers(on);\n }\n\n async stats(on: boolean): Promise<void> {\n await this.#client.setStats(on);\n }\n\n async shading(mode: ShadingMode): Promise<void> {\n await this.#client.setShadingMode(mode);\n }\n\n\n async inspect(): Promise<InspectedInspection> {\n return this.#client.inspect();\n }\n\n /** Run one verb listed by `inspect().quickActions`, through the same action\n * the human Inspector button invokes. */\n async runAction(actionId: string): Promise<InspectedInspection> {\n return this.#client.runInspectionAction(actionId);\n }\n\n /**\n * Run a command by id. Under the native frame this uses ICommandService and\n * can invoke editor or VS Code commands. Standalone sessions resolve registered\n * view verbs of the form `volter.<view>.<verb>` and refuse other ids.\n *\n * Returns the command\u2019s result, or `null` when it returns nothing.\n */\n async command(commandId: string, args?: unknown): Promise<unknown> {\n return this.#client.runCommand(commandId, args);\n }\n\n /**\n * RESTRUCTURE the authored tree \u2014 the hierarchy context menu's own verbs.\n *\n * `create`, `delete`, `duplicate`, `reparent`, `reorder`, `wrap`, `unwrap`,\n * `group`, `ungroup`, `copy`, `cut`, `paste`; `extractComponent` and\n * `forkComponent` are the two that write whole new files and have their own\n * doors below. All of them run the SAME `authoring/consumer-actions.ts`\n * helpers the menu items call, so there is one implementation of each op and\n * not a second that can disagree with what a human gets.\n *\n * `id`/`ids` default to the current selection. The answer carries the same\n * per-edit `write` ack `setField` does, so `write.persisted` tells a saved\n * restructure from a live-only one. An op the active adapter does not provide\n * REJECTS by name \u2014 never a silent no-op.\n */\n async structure(op: StructureOp, options?: StructureOpOptions): Promise<StructureOpResult> {\n return this.#client.structureOp(op, options ?? {});\n }\n\n /**\n * \"Extract Component\u2026\" \u2014 lift the selected native subtree into its own\n * component file (plus a story) and replace the callsite with it.\n *\n * Answers the action's own sentence, which NAMES both new files, because\n * undo owns the callsite edit and will not remove them.\n */\n async extractComponent(options?: { id?: string; name?: string }): Promise<string> {\n return (await this.#client.extractComponent(options ?? {})).hint;\n }\n\n /**\n * \"Fork Component\u2026\" \u2014 copy the selected instance's component definition to a\n * new file and retarget THIS CALLSITE at it.\n *\n * One callsite is the unit of the edit; when that callsite sits inside a\n * component rendered many times, every one of those renders now renders the\n * fork.\n */\n async forkComponent(options?: { id?: string }): Promise<string> {\n return (await this.#client.forkComponent(options ?? {})).hint;\n }\n\n /**\n * READ the hierarchy panel, as data \u2014 the rows a human is looking at right\n * now, nested exactly as the panel nests them.\n *\n * The companion to {@link inspect}: that one answers \"what IS the selected\n * thing\", this one answers \"what does the tree LOOK LIKE\". It is the panel's\n * own projection of component marks, document promotion, child caps,\n * collapse state, search and selection scope onto the adapter tree.\n *\n * Prefer this over `status().entities`, which is deliberately a different\n * question \u2014 the RAW adapter tree, unprojected. A panel that renders the\n * wrong rows looks perfectly healthy in that facet.\n *\n * Each row reports the projected child count and whether the panel draws a disclosure control.\n *\n * Rejects, naming the panel, when no hierarchy panel is mounted \u2014 an empty\n * tree would be a fabricated answer about a surface nobody is being shown.\n */\n async hierarchy(): Promise<InspectedHierarchy> {\n return this.#client.hierarchy();\n }\n\n /** Expand every branch through the Hierarchy panel's own action. */\n async expandHierarchyAll(): Promise<void> {\n await this.#client.expandHierarchyAll();\n }\n\n /** Collapse every branch through the same panel action. Expanding is\n * persisted per project, so without this the tree's REST STATE \u2014 what a\n * person sees on opening the project \u2014 is unreachable once any reader has\n * expanded it. */\n async collapseHierarchyAll(): Promise<void> {\n await this.#client.collapseHierarchyAll();\n }\n\n /**\n * Write one editable field from `inspect()` by its stable path, through the\n * same Inspector IO and persistence boundary the human control uses.\n *\n * The answer is `{ subject, write }`, and `write` is the half worth reading\n * first: a write with no persistence route open still succeeds \u2014 it lands on\n * the live object and journals live-only \u2014 so `write.persisted` is how you\n * tell a saved edit from one that will not survive the session, without\n * diffing the tree. `write.destination` is the adapter's own words for where\n * it went (\"live-only (not saved)\" is a destination, never silence).\n */\n async setField(path: string, value: unknown): Promise<InspectedFieldWrite> {\n return this.#client.setInspectionField(path, value);\n }\n\n /**\n * REMOVE one field's authored override \u2014 the revert arrow, as a command.\n *\n * Reach for this instead of `setField` whenever you are UNDOING an edit that\n * added a property the source did not carry: `setField` can only write a\n * value, so setting the default back leaves `position={[0, 0, 0]}` in the\n * file where there was nothing before. Only this door restores the bytes.\n *\n * The answer is the same `{ subject, write }` shape, awaited past the bytes.\n * It rejects with `code: 'REMOVAL_UNAVAILABLE'` when the field is not\n * declared removable or the lane has no removal door \u2014 which is a missing\n * seam to report, not a removal that failed.\n */\n async removeField(path: string): Promise<InspectedFieldWrite> {\n return this.#client.removeInspectionField(path);\n }\n\n /** Open a document by its adapter-declared id, through its registered owner. An id the adapter would list for a\n * file not written yet (a new model, `model:prefabs/coin/coin.blend`) opens as that new document, written by its\n * first save. */\n async open(id: string): Promise<OpenedDocument> {\n return this.#client.open(id);\n }\n\n /** Undo / redo one project transaction, through the session's own history\n * queue \u2014 the same one the keyboard shortcut drives. */\n async undo(): Promise<HistoryStep> {\n return this.#client.undo();\n }\n\n async redo(): Promise<HistoryStep> {\n return this.#client.redo();\n }\n\n /** Reload the editor's page and resolve once the new document answers. */\n async reloadPage(): Promise<void> {\n await this.#client.reloadPage();\n }\n\n /** Mirrors the editor's `status` command \u2014 the full live editor state as JSON. */\n async status(): Promise<EditorState> {\n return this.#client.getState();\n }\n\n /** A live viewport PNG (`EditorClient.captureViewport`) \u2014 no direct CLI verb exists; this is the closest wire read. */\n async screenshot(size?: number): Promise<ViewportCapture> {\n return this.#client.captureViewport(size);\n }\n}\n", "/**\n * `lazyChainProxy` \u2014 turns an async \"resolve the real object\" function into\n * a synchronously-importable stand-in that supports the SAME call shape as\n * the real thing, including nested member access\n * (`editor.document.query(...)`), by recording the property-access PATH and only\n * resolving + walking it down at the point of an actual function CALL.\n *\n * This is what makes `index.ts`'s top-level `export const editor = ...` work\n * as a plain value a script can `import { editor } from '@volter/live'` and\n * call immediately \u2014 each call transparently awaits the memoized `connect()`\n * first.\n *\n * Limitation (by design, documented on `index.ts`'s exports too): only\n * FUNCTION-shaped access resolves through this proxy \u2014 `editor.document.query(s)`\n * works, but reading a plain data property would return another inert proxy,\n * not the real value, since there is no function CALL to trigger resolution.\n * Every documented `editor` member is a method, so this never bites the\n * documented surface.\n */\n\ntype AnyFn = (...args: unknown[]) => unknown;\n\nfunction isFunction(value: unknown): value is AnyFn {\n return typeof value === 'function';\n}\n\nfunction walk(root: unknown, path: PropertyKey[]): { thisArg: unknown; fn: unknown } {\n if (path.length === 0) return { thisArg: undefined, fn: root };\n let obj: Record<PropertyKey, unknown> = root as Record<PropertyKey, unknown>;\n for (let i = 0; i < path.length - 1; i++) {\n const key = path[i] as PropertyKey;\n obj = obj[key] as Record<PropertyKey, unknown>;\n }\n const lastKey = path[path.length - 1] as PropertyKey;\n return { thisArg: obj, fn: obj[lastKey] };\n}\n\n/**\n * `resolveRoot` is called (and its result awaited) on every terminal\n * function call reached through the returned proxy \u2014 callers typically wire\n * it to a memoized `connect()` (see `index.ts`), so repeated calls across\n * many proxy invocations still resolve only once.\n *\n * `hint` names where a member the root does NOT have lives instead\n * (`member-hints.ts`): consulted for the FIRST step of the path only, because\n * that is the member the caller named on the fa\u00E7ade \u2014 `editor.camera.set(\u2026)`\n * fails at `camera`, not at `set`.\n */\nexport function lazyChainProxy<T>(\n resolveRoot: () => Promise<unknown>,\n path: PropertyKey[] = [],\n hint?: (member: PropertyKey) => string | undefined,\n): T {\n const callableTarget = (() => {}) as unknown as object;\n return new Proxy(callableTarget, {\n get(_target, prop) {\n // Never look thenable \u2014 `await`ing a proxy (accidentally, or via a\n // generic helper checking `typeof x.then`) must not trigger resolution\n // or hang; there is no promise here, only a call-shaped stand-in.\n if (prop === 'then' || prop === 'catch' || prop === 'finally') return undefined;\n return lazyChainProxy(resolveRoot, [...path, prop], hint);\n },\n apply(_target, _thisArg, args) {\n return resolveRoot().then((root) => {\n const first = path[0];\n const pointer = first !== undefined && hint !== undefined && !(first in (root as object)) ? hint(first) : undefined;\n if (pointer !== undefined) throw new TypeError(`@volter/live: editor.${String(first)} does not exist. ${pointer}`);\n const { thisArg, fn } = walk(root, path);\n if (!isFunction(fn)) {\n const label = path.length > 0 ? path.map(String).join('.') : '(the connected value)';\n throw new TypeError(`@volter/live: ${label} is not a function on the connected session.`);\n }\n return fn.apply(thisArg, args);\n });\n },\n }) as T;\n}\n", "/** Resolve an existing session for exactly one project, from the shared registry.\n * Never fall back to another project. */\n\nimport { existsSync, realpathSync, statSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { resolveManifestPath } from '@volter/project/manifest/locate';\nimport { resolveProductForProject } from './product-locator.js';\nimport {\n EDITOR_SESSION_DISCOVERY_TIMEOUT_MS,\n type EditorSessionInfo,\n type SessionListingTransport as SessionDiscoveryTransport,\n HttpSessionDiscovery,\n withTimeout,\n} from './discovery.js';\n\n/** Nearest ancestor containing the project's canonical manifest. */\nexport function findProjectRootFrom(dir: string): string | null {\n let cur = resolve(dir);\n for (;;) {\n if (existsSync(resolveManifestPath(cur))) return cur;\n const parent = dirname(cur);\n if (parent === cur) return null;\n cur = parent;\n }\n}\n\n/** The minimal slice of `EditorTransport` `resolveSession` actually needs \u2014 narrower than the full interface so a test double only has to implement one method. */\nexport type SessionListingTransport = SessionDiscoveryTransport;\n\nexport interface ResolvedSession {\n /** Editor dev-server port the resolved session is listening on. */\n port: number;\n /** Absolute project root \u2014 the nearest ancestor of the requested directory containing `volter.project.json`. */\n projectRoot: string;\n}\n\nexport interface SessionResolutionDeps {\n /** Session listing + liveness verification \u2014 defaults to a real `HttpSessionDiscovery`. Overridable for tests. */\n transport?: SessionListingTransport;\n /** Project-root discovery \u2014 defaults to the real fs walk (`findProjectRootFrom` above). Overridable for tests. */\n findProjectRootFrom?: (dir: string) => string | null;\n}\n\nfunction canonicalPath(path: string): string {\n try {\n return realpathSync(path);\n } catch {\n return resolve(path);\n }\n}\n\n/** Whether two paths are the same folder on disk, which `canonicalPath` alone misses on Windows\n * (it keeps the letter case typed, and short names and `subst` drives unexpanded). */\nfunction sameDirectory(a: string, b: string): boolean {\n try {\n const x = statSync(a, { bigint: true });\n const y = statSync(b, { bigint: true });\n return x.dev === y.dev && x.ino === y.ino;\n } catch {\n return false;\n }\n}\n\n/** The code a refusal carries when the registry was read and no session opens the project: the\n * one state in which \"no editor is open here\" is a fact, which `close` answers as done. */\nexport const NO_SESSION_FOR_PROJECT = 'VOLTER_NO_SESSION_FOR_PROJECT';\n/** The `code` of the refusal for this project's session whose manifest does not load; it carries `session`. */\nexport const SESSION_MANIFEST_UNREADABLE = 'VOLTER_SESSION_MANIFEST_UNREADABLE';\n\n/**\n * The refusal for a session that IS this project's and cannot be driven,\n * because the project's manifest does not load.\n *\n * A refusal, not an attach: with no readable manifest the editor page itself\n * renders its startup-error screen, so there is no editor behind this door to\n * bind `{ editor, session }` to. It names the failing file and key, so an\n * operator fixes the manifest rather than starting a second editor.\n */\nfunction manifestRefusal(projectRoot: string, manifestError: string, port: number): Error {\n return Object.assign(\n new Error(\n `@volter/live: the editor session for ${projectRoot} is live, but its volter.project.json does ` +\n 'not load, so there is no editor or project to drive \u2014 the editor page is showing this same ' +\n `error. Fix the manifest and retry; the session recovers on save, no restart needed.\\n${manifestError}`,\n ),\n // The session is still this project's, so a caller that only needs to END it (`close`) can.\n { code: SESSION_MANIFEST_UNREADABLE, session: { port, projectRoot } },\n );\n}\n\n/**\n * Distinguish failed discovery, a readable empty registry and sessions serving\n * other canonical paths. Include the requested and listed paths for a path\n * mismatch; only a confirmed absence carries `NO_SESSION_FOR_PROJECT`.\n */\nfunction noMatchingSessionRefusal(\n projectRoot: string,\n canon: string,\n sessions: readonly EditorSessionInfo[],\n discoveryFailure: string | null,\n): Error {\n if (discoveryFailure !== null) {\n return new Error(\n `@volter/live: could not complete editor session discovery while looking for ${projectRoot} \u2014 ` +\n `${discoveryFailure}. This is not the answer \"no editor is running\": the question went ` +\n 'unanswered, so nothing is known about what is live. The step named above is the one that ' +\n 'did not answer: that session\\'s server holds its port but did not reply to the request. ' +\n 'Its own log (logs/editor-<port>.log in the project it serves) says how far its start got; ' +\n `${sessionsCommandFor(projectRoot)} asks the same question directly.`,\n );\n }\n if (sessions.length === 0) {\n return Object.assign(new Error(\n `@volter/live: the editor session registry is readable and lists NO live sessions, so none ` +\n `covers ${projectRoot}. @volter/live only attaches to an already-running session \u2014 it ` +\n `never starts one \u2014 so run ${editCommandFor(projectRoot)} in that project first, then retry.`,\n ), { code: NO_SESSION_FOR_PROJECT });\n }\n const listed = sessions\n .map((s) => ` port ${s.port} \u2192 ${s.project === null ? '(no project)' : s.project}`)\n .join('\\n');\n // A listed session that is this same folder under another spelling is not \"nothing open here\":\n // it keeps the refusal, so `close` does not report done while that editor runs on.\n const thisFolderElsewhere = sessions.some((s) => s.project !== null && sameDirectory(s.project, projectRoot));\n return Object.assign(new Error(\n `@volter/live: ${sessions.length} live editor session(s) are running, but none of them opens ` +\n `${projectRoot}. @volter/live never silently attaches to a different project.\\n` +\n ` looking for (resolved): ${canon}\\n` +\n ` live sessions:\\n${listed}\\n` +\n ' If one of those is meant to be this project, the two paths differ after resolution \u2014 ' +\n 'the usual cause is a git worktree or a symlink, where the session was opened through a ' +\n `different path to the same files. Run ${editCommandFor(projectRoot)} from THIS path, or use the path the ` +\n 'session lists.',\n ), thisFolderElsewhere ? {} : { code: NO_SESSION_FOR_PROJECT });\n}\n\n/**\n * Resolve `projectDir` (default `process.cwd()`) to its already-running editor\n * session from the shared registry, with each discovery probe bounded by\n * `EDITOR_SESSION_DISCOVERY_TIMEOUT_MS`.\n * Throw when no project manifest or matching live session is found.\n */\nexport async function resolveSession(\n projectDir: string = process.cwd(),\n deps: SessionResolutionDeps = {},\n): Promise<ResolvedSession> {\n const findRoot = deps.findProjectRootFrom ?? findProjectRootFrom;\n const transport = deps.transport ?? new HttpSessionDiscovery();\n\n const projectRoot = findRoot(projectDir);\n if (projectRoot === null) {\n throw new Error(\n `@volter/live: no volter.project.json found in ${projectDir} or any parent directory \u2014 is this a project?`,\n );\n }\n\n let sessions: EditorSessionInfo[];\n // Retain discovery failures separately from an empty session list so the\n // refusal names an unanswered probe rather than claiming no session exists.\n let discoveryFailure: string | null = null;\n try {\n sessions = await withTimeout(\n transport.listSessions(EDITOR_SESSION_DISCOVERY_TIMEOUT_MS),\n EDITOR_SESSION_DISCOVERY_TIMEOUT_MS,\n 'editor session discovery',\n );\n } catch (err) {\n sessions = [];\n discoveryFailure = err instanceof Error ? err.message : String(err);\n }\n\n const canon = canonicalPath(projectRoot);\n const match = sessions.find((s) => s.project !== null && canonicalPath(s.project) === canon);\n if (!match) throw noMatchingSessionRefusal(projectRoot, canon, sessions, discoveryFailure);\n\n if (match.manifestError != null) throw manifestRefusal(projectRoot, match.manifestError, match.port);\n\n return { port: match.port, projectRoot };\n}\n\n/** `` `<product> edit` `` for the product this project declares, or a generic\n * phrase when it declares none \u2014 this package serves every product and\n * names only the one the project installed. */\nfunction editCommandFor(projectRoot: string): string {\n return verbFor(projectRoot, 'edit');\n}\n\nfunction sessionsCommandFor(projectRoot: string): string {\n return verbFor(projectRoot, 'sessions');\n}\n\nfunction verbFor(projectRoot: string, verb: string): string {\n try {\n return `\\`${resolveProductForProject(projectRoot).command} ${verb}\\``;\n } catch {\n return `its product's \\`${verb}\\` command`;\n }\n}\n", "// Finding the project manifest ON DISK. There is ONE filename (`./filename.ts`).\n//\n// Deliberately dependency-light \u2014 `node:fs` + `node:path` + `./filename` and\n// NOTHING else (no Zod, no `./load`). Its callers (the editor's server, the\n// live session and a product's CLI) locate a manifest without dragging the\n// validator in.\n\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { MANIFEST_FILENAME } from './filename';\n\n/**\n * The manifest path inside `dir`: always `volter.project.json`, so a \"not\n * found\" message names the filename a project must be using.\n *\n * This is the drop-in replacement for a hand-written `join(dir, \u2026)` everywhere\n * a manifest is READ. Writers want {@link manifestWritePath}.\n */\nexport function resolveManifestPath(dir: string): string {\n return join(dir, MANIFEST_FILENAME);\n}\n\n/** True when `dir` holds a manifest. */\nexport function hasManifest(dir: string): boolean {\n return existsSync(join(dir, MANIFEST_FILENAME));\n}\n\n/** Where a manifest gets WRITTEN in `dir`. There is one answer. */\nexport function manifestWritePath(dir: string): string {\n return join(dir, MANIFEST_FILENAME);\n}\n", "// The project manifest's FILENAME. There is exactly ONE, and this module is the one place it is\n// spelled out. It is dependency-free (no `node:fs`) so browser bundles can import it; the\n// filesystem side lives in `./locate` (`resolveManifestPath`, `hasManifest`).\n\n/** The manifest filename. Every reader reads it; every writer writes it. */\nexport const MANIFEST_FILENAME = 'volter.project.json';\n", "/** Memoized async connection. Concurrent ensure calls share the same in-flight promise. */\nexport interface LazySession<T> {\n /** Returns the memoized promise, creating it via `factory()` on first call. */\n ensure(): Promise<T>;\n}\n\nexport function createLazySession<T>(factory: () => Promise<T>): LazySession<T> {\n let promise: Promise<T> | null = null;\n return {\n ensure(): Promise<T> {\n promise ??= factory();\n return promise;\n },\n };\n}\n", "/**\n * NAMES AN AGENT REACHES FOR THAT THE FA\u00C7ADE DOES NOT HAVE, and where the\n * thing it wanted actually lives.\n *\n * A call to `editor.setCamera(...)` would otherwise fail with the engine's bare\n * \"editor.setCamera is not a function\", though the camera is reachable through\n * `editor.present`'s `viewport.camera`. The refusal is the one moment the\n * caller is certainly reading, so that is where the pointer goes.\n *\n * TARGETED, NOT A CATCH-ALL. Only the names below are intercepted, each with\n * the door it was looking for. Every other missing member keeps JavaScript's\n * own behaviour (`undefined`, then the engine's TypeError), so this table can\n * never turn a typo into a wrong suggestion \u2014 it only ever adds what is known.\n */\n\nconst CAMERA_HINT =\n 'The viewport camera is posed through a presented view: ' +\n 'await editor.present({ version: 1, viewport: { camera: { position: { x, y, z }, target: { x, y, z }, fov } } }) ' +\n '(stage space: metres, Y up), ' +\n 'and read back with (await editor.currentView()).viewport.camera. ' +\n 'editor.frame() and editor.orbit() frame or swing around the subject instead.';\n\n/** Missing `editor` member \u2192 what to use instead. */\nconst EDITOR_MEMBER_HINTS: Readonly<Record<string, string>> = {\n camera: CAMERA_HINT,\n setCamera: CAMERA_HINT,\n getCamera: CAMERA_HINT,\n cameraPose: CAMERA_HINT,\n setCameraPose: CAMERA_HINT,\n moveCamera: CAMERA_HINT,\n poseCamera: CAMERA_HINT,\n lookAt: CAMERA_HINT,\n};\n\n/** The pointer for a member `editor` does not have, or undefined when there is none to give. */\nexport function editorMemberHint(member: PropertyKey): string | undefined {\n return typeof member === 'string' && Object.hasOwn(EDITOR_MEMBER_HINTS, member) ? EDITOR_MEMBER_HINTS[member] : undefined;\n}\n\n/**\n * `editor` as `eval` binds it: the same object, except that reading one of the\n * hinted names it does NOT have throws the hint, naming `editor.member`.\n * Thrown on READ, not on call, so `editor.camera.position` is caught as well as\n * `editor.setCamera(...)`.\n *\n * Methods come back bound to the real object: `LiveEditor` keeps its client in\n * a `#`-private field, which a call whose `this` is the proxy cannot read.\n */\nexport function withEditorMemberHints<T extends object>(target: T): T {\n return new Proxy(target, {\n get(object, key) {\n if (!(key in object)) {\n const hint = editorMemberHint(key);\n if (hint !== undefined) throw new TypeError(`editor.${String(key)} does not exist. ${hint}`);\n }\n const value: unknown = Reflect.get(object, key, object);\n return typeof value === 'function' ? (value as (...args: unknown[]) => unknown).bind(object) : value;\n },\n });\n}\n", "/** Attach to an existing editor session; this package never launches one. */\nimport { EditorClient } from './client.js';\nimport { LiveEditor } from './editor.js';\nimport { lazyChainProxy } from './lazy-proxy.js';\nimport { resolveSession, type ResolvedSession, type SessionResolutionDeps } from './session.js';\nimport { createLazySession } from './singleton.js';\nimport { editorMemberHint } from './member-hints.js';\n\nexport { LiveEditor, inferAssetKind, type PanelName } from './editor.js';\nexport { LiveEditorDocument } from './editor-document.js';\nexport type { AssetDownloadRequest, AssetDownloadResult, AssetFileOption, AssetSearchQuery, OnlineAsset } from './asset-library.js';\nexport type { DocumentGestureOptions, DocumentKeyOptions, DocumentPasteOptions } from './editor-document.js';\nexport { editorMemberHint, withEditorMemberHints } from './member-hints.js';\nexport { resolveSession, findProjectRootFrom, NO_SESSION_FOR_PROJECT, SESSION_MANIFEST_UNREADABLE } from './session.js';\nexport type { ResolvedSession, SessionResolutionDeps, SessionListingTransport } from './session.js';\nexport type { ActiveDocumentCapture, EditorView, PresentedEditorView } from '@volter/sdk';\n\nexport interface LiveBindings {\n editor: LiveEditor;\n}\nexport interface LiveSession extends LiveBindings {\n session: ResolvedSession;\n}\nfunction bindTo(port: number): LiveBindings {\n const client = new EditorClient({ url: `http://127.0.0.1:${port}` });\n return { editor: new LiveEditor(client) };\n}\n/** Inspect the callable surface without connecting; calls fail on port zero. */\nexport function unconnectedBindings(): LiveBindings { return bindTo(0); }\n\n/** Attach only to the session serving the requested project's canonical path. */\nexport async function connect(projectDir?: string, deps?: SessionResolutionDeps): Promise<LiveSession> {\n const session = await resolveSession(projectDir, deps);\n return { ...bindTo(session.port), session };\n}\nconst lazySession = createLazySession(() => connect());\nexport const editor: LiveEditor = lazyChainProxy<LiveEditor>(() => lazySession.ensure().then(s => s.editor), [], editorMemberHint);\n"],
5
+ "mappings": "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",
6
+ "names": []
7
7
  }
@@ -41,8 +41,8 @@ export interface ProductIdentity {
41
41
  readonly entry: string;
42
42
  /**
43
43
  * The packages this product mounts, in order — `contributes.volter.product.composes`. The ONE statement of
44
- * the composition: the build serves it to the entry as `volter:composition`, and the session
45
- * reads it here for the catalog and the serving doors.
44
+ * the composition: the session reads it here for the packages it installs and serves, the catalog and the
45
+ * serving doors.
46
46
  */
47
47
  readonly composes: readonly string[];
48
48
  readonly colorTheme: ProductColorTheme;
@@ -8,9 +8,9 @@ import {
8
8
  readProductManifest,
9
9
  resolveProductForProject,
10
10
  workbenchProductId
11
- } from "./chunk-SDIWRX5X.js";
11
+ } from "./chunk-PC56TDHV.js";
12
+ import "./chunk-JFAHP5CC.js";
12
13
  import "./chunk-7WKVJGHZ.js";
13
- import "./chunk-YPAOTPIF.js";
14
14
  export {
15
15
  PRODUCT_DECLARATION_HINT,
16
16
  PRODUCT_DECLARATION_KEY,
@@ -2,6 +2,11 @@
2
2
  * Shared editor-session registry format: entry shape, guards, path,
3
3
  * liveness-filtered reads, served-project parsing and pending launches.
4
4
  * The server’s session-registry module owns writes to this format.
5
+ *
6
+ * The registry is also the CREDENTIAL FILE for the owner's own processes: each entry carries its session's
7
+ * connection token, and `sessionFetch` is how a process on this machine reaches a session with it, as a Code-OSS
8
+ * client reads its server's `--connection-token-file` (`src/vs/server/node/serverConnectionToken.ts:62-79` in the
9
+ * `volter-ai/code-oss` fork). The file is the user's alone (0600, written by the session).
5
10
  */
6
11
  /** One registry entry, exactly as the server's write half records it. */
7
12
  export interface EditorSessionEntry {
@@ -13,9 +18,9 @@ export interface EditorSessionEntry {
13
18
  /** ISO timestamp of server start. */
14
19
  startedAt: string;
15
20
  sessionId: string | null;
16
- /** Private loopback control credential — never returned by an editor HTTP
17
- * route; exists only in this user-private registry. */
18
- controlSecret?: string | null;
21
+ /** The session's connection token, which every request to it carries (`sessionFetch`). Never returned by a
22
+ * session route; it is in this user-private file and in the page's cookie. */
23
+ connectionToken?: string | null;
19
24
  repositoryId: string | null;
20
25
  worktreeId: string | null;
21
26
  worktreeRoot: string | null;
@@ -31,6 +36,29 @@ export declare function normalizeEditorSessionEntry(session: EditorSessionEntry)
31
36
  export declare function pidAlive(pid: number): boolean;
32
37
  /** The registry's live entries — shape-validated and PID-liveness-filtered. */
33
38
  export declare function readLiveRegisteredSessions(): EditorSessionEntry[];
39
+ /**
40
+ * The cookie the session reads its connection token from: Code-OSS's own (`connectionTokenCookieName`,
41
+ * `src/vs/base/common/network.ts:187`). The page's Code-OSS server sets it on the page's host from the address's
42
+ * `?tkn=` (`src/vs/server/node/webClientServer.ts:313-336`), and the session's routes share that host through its
43
+ * proxy and the token through the project's token file, so one cookie carries both.
44
+ */
45
+ export declare const CONNECTION_TOKEN_COOKIE = "vscode-tkn";
46
+ /** The connection token of the live session listening on `port` of this machine, from its entry; null when no live
47
+ * session there registered one. */
48
+ export declare function registeredConnectionToken(port: number): string | null;
49
+ /** `init` with the connection token of the session `url` names, as the cookie the session reads. Only a loopback
50
+ * address gets one, and only a registered session's: the token never leaves this machine. */
51
+ export declare function withSessionToken(url: string | URL, init?: RequestInit): RequestInit;
52
+ /**
53
+ * Say why a session on this machine refused (403) a request this process could send it no token with: its registry
54
+ * entry, the one place the owner's processes read the token from, is missing or carries none. Throws that; returns
55
+ * when the refusal is something else (a token was sent, or the address is not a local session's).
56
+ */
57
+ export declare function refuseWithoutRegisteredToken(url: string | URL, status: number): void;
58
+ /** `fetch` to a session on this machine, carrying its connection token (`withSessionToken`). Every request a process
59
+ * of the owner's makes to a session goes through here or through `EditorClient`, which does the same, and a refusal
60
+ * for want of the token says so (`refuseWithoutRegisteredToken`). */
61
+ export declare function sessionFetch(url: string | URL, init?: RequestInit): Promise<Response>;
34
62
  /** Announce a launch before the server can register. Each launcher owns its file. */
35
63
  export declare function announceEditorLaunch(project: string): () => void;
36
64
  /** Wait only for an observed live launcher, never for a missing editor. */
@@ -1,21 +1,31 @@
1
1
  import {
2
+ CONNECTION_TOKEN_COOKIE,
2
3
  EDITOR_SESSIONS_REGISTRY_FILE,
3
4
  announceEditorLaunch,
4
5
  isEditorSessionEntry,
5
6
  normalizeEditorSessionEntry,
6
7
  pidAlive,
7
8
  readLiveRegisteredSessions,
9
+ refuseWithoutRegisteredToken,
10
+ registeredConnectionToken,
8
11
  servedProjectAnswer,
9
- waitForPendingEditorLaunch
10
- } from "./chunk-Y5W77HYT.js";
12
+ sessionFetch,
13
+ waitForPendingEditorLaunch,
14
+ withSessionToken
15
+ } from "./chunk-JDOIPALX.js";
11
16
  export {
17
+ CONNECTION_TOKEN_COOKIE,
12
18
  EDITOR_SESSIONS_REGISTRY_FILE,
13
19
  announceEditorLaunch,
14
20
  isEditorSessionEntry,
15
21
  normalizeEditorSessionEntry,
16
22
  pidAlive,
17
23
  readLiveRegisteredSessions,
24
+ refuseWithoutRegisteredToken,
25
+ registeredConnectionToken,
18
26
  servedProjectAnswer,
19
- waitForPendingEditorLaunch
27
+ sessionFetch,
28
+ waitForPendingEditorLaunch,
29
+ withSessionToken
20
30
  };
21
31
  //# sourceMappingURL=registry-format.js.map
package/dist/session.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- /** Resolve an existing session for exactly one project.
2
- * Prefer the project's hint, verify it against the served canonical path,
3
- * then consult the shared registry. Never fall back to another project. */
1
+ /** Resolve an existing session for exactly one project, from the shared registry.
2
+ * Never fall back to another project. */
4
3
  import { type SessionListingTransport as SessionDiscoveryTransport } from './discovery.js';
5
4
  /** Nearest ancestor containing the project's canonical manifest. */
6
5
  export declare function findProjectRootFrom(dir: string): string | null;
@@ -17,16 +16,6 @@ export interface SessionResolutionDeps {
17
16
  transport?: SessionListingTransport;
18
17
  /** Project-root discovery — defaults to the real fs walk (`findProjectRootFrom` above). Overridable for tests. */
19
18
  findProjectRootFrom?: (dir: string) => string | null;
20
- /** Project-local session hint reader. Defaults to `.volter/session.json`. */
21
- readProjectSession?: (projectRoot: string) => ProjectSessionHint | null;
22
- /** Exact-session verifier. Defaults to GET /__editor/project + canonical project matching. */
23
- verifyProjectSession?: (hint: ProjectSessionHint, projectRoot: string) => Promise<boolean>;
24
- }
25
- export interface ProjectSessionHint {
26
- port: number;
27
- pid: number;
28
- url: string;
29
- startedAt: string;
30
19
  }
31
20
  /** The code a refusal carries when the registry was read and no session opens the project: the
32
21
  * one state in which "no editor is open here" is a fact, which `close` answers as done. */
@@ -35,8 +24,8 @@ export declare const NO_SESSION_FOR_PROJECT = "VOLTER_NO_SESSION_FOR_PROJECT";
35
24
  export declare const SESSION_MANIFEST_UNREADABLE = "VOLTER_SESSION_MANIFEST_UNREADABLE";
36
25
  /**
37
26
  * Resolve `projectDir` (default `process.cwd()`) to its already-running editor
38
- * session. Verify the project hint, then consult the shared registry, with
39
- * each discovery probe bounded by `EDITOR_SESSION_DISCOVERY_TIMEOUT_MS`.
27
+ * session from the shared registry, with each discovery probe bounded by
28
+ * `EDITOR_SESSION_DISCOVERY_TIMEOUT_MS`.
40
29
  * Throw when no project manifest or matching live session is found.
41
30
  */
42
31
  export declare function resolveSession(projectDir?: string, deps?: SessionResolutionDeps): Promise<ResolvedSession>;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  declaredContributions,
3
3
  readVolterManifest
4
- } from "./chunk-YPAOTPIF.js";
4
+ } from "./chunk-JFAHP5CC.js";
5
5
  export {
6
6
  declaredContributions,
7
7
  readVolterManifest
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  PRODUCT_DECLARATION_KEY,
3
3
  workbenchProductId
4
- } from "./chunk-SDIWRX5X.js";
4
+ } from "./chunk-PC56TDHV.js";
5
+ import "./chunk-JFAHP5CC.js";
5
6
  import "./chunk-7WKVJGHZ.js";
6
- import "./chunk-YPAOTPIF.js";
7
7
 
8
8
  // src/workbench-locator.ts
9
9
  import { execFileSync } from "node:child_process";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@volter/live",
3
3
  "author": "Volter AI, Inc.",
4
- "version": "0.5.212",
4
+ "version": "0.5.213",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -29,6 +29,10 @@
29
29
  "types": "./dist/client.d.ts",
30
30
  "default": "./dist/client.js"
31
31
  },
32
+ "./asset-library": {
33
+ "types": "./dist/asset-library.d.ts",
34
+ "default": "./dist/asset-library.js"
35
+ },
32
36
  "./registry-format": {
33
37
  "types": "./dist/registry-format.d.ts",
34
38
  "default": "./dist/registry-format.js"
@@ -62,8 +66,8 @@
62
66
  "node": ">=22"
63
67
  },
64
68
  "dependencies": {
65
- "@volter/sdk": "0.5.212",
66
- "@volter/project": "0.5.212",
69
+ "@volter/sdk": "0.5.213",
70
+ "@volter/project": "0.5.213",
67
71
  "undici": "^7.28.0"
68
72
  },
69
73
  "devDependencies": {