@vgai/live 0.5.32 → 0.5.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/{vgai-live/src/session.js → session.js} +1 -2
- package/package.json +4 -4
- package/src/session.ts +1 -1
- package/dist/vgai-sdk/src/editor/session-registry-format.d.ts +0 -81
- package/dist/vgai-sdk/src/editor/session-registry-format.js +0 -158
- /package/dist/{vgai-live/src/editor-document.d.ts → editor-document.d.ts} +0 -0
- /package/dist/{vgai-live/src/editor-document.js → editor-document.js} +0 -0
- /package/dist/{vgai-live/src/editor.d.ts → editor.d.ts} +0 -0
- /package/dist/{vgai-live/src/editor.js → editor.js} +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/bridge-heartbeat.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/bridge-heartbeat.js +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/bridge-transport.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/bridge-transport.js +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/capture-notes.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/capture-notes.js +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/client.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/client.js +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/errors.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/errors.js +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/events-matcher.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/events-matcher.js +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/failure-block.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/failure-block.js +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/fast-forward.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/fast-forward.js +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/hidden-recovery.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/hidden-recovery.js +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/index.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/index.js +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/perf-sampling.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/perf-sampling.js +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/relay-transport.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/relay-transport.js +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/screenshot-target.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/screenshot-target.js +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/state-cap.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/state-cap.js +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/types.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/types.js +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/wait-for.d.ts +0 -0
- /package/dist/{vgai-live/src/game-client → game-client}/wait-for.js +0 -0
- /package/dist/{vgai-live/src/game.d.ts → game.d.ts} +0 -0
- /package/dist/{vgai-live/src/game.js → game.js} +0 -0
- /package/dist/{vgai-live/src/index.d.ts → index.d.ts} +0 -0
- /package/dist/{vgai-live/src/index.js → index.js} +0 -0
- /package/dist/{vgai-live/src/lazy-proxy.d.ts → lazy-proxy.d.ts} +0 -0
- /package/dist/{vgai-live/src/lazy-proxy.js → lazy-proxy.js} +0 -0
- /package/dist/{vgai-live/src/recording.d.ts → recording.d.ts} +0 -0
- /package/dist/{vgai-live/src/recording.js → recording.js} +0 -0
- /package/dist/{vgai-live/src/session.d.ts → session.d.ts} +0 -0
- /package/dist/{vgai-live/src/singleton.d.ts → singleton.d.ts} +0 -0
- /package/dist/{vgai-live/src/singleton.js → singleton.js} +0 -0
- /package/dist/{vgai-live/src/tools.d.ts → tools.d.ts} +0 -0
- /package/dist/{vgai-live/src/tools.js → tools.js} +0 -0
|
@@ -46,8 +46,7 @@
|
|
|
46
46
|
*/
|
|
47
47
|
import { existsSync, readFileSync, realpathSync } from 'node:fs';
|
|
48
48
|
import { dirname, join, resolve } from 'node:path';
|
|
49
|
-
import { EDITOR_SESSION_DISCOVERY_TIMEOUT_MS, HttpEditorTransport, withTimeout, } from '@vgai/sdk';
|
|
50
|
-
import { servedProjectAnswer } from '../../vgai-sdk/src/editor/session-registry-format';
|
|
49
|
+
import { EDITOR_SESSION_DISCOVERY_TIMEOUT_MS, HttpEditorTransport, servedProjectAnswer, withTimeout, } from '@vgai/sdk';
|
|
51
50
|
/**
|
|
52
51
|
* Lifted verbatim from `packages/vgai-cli/src/project-root.ts` (see this
|
|
53
52
|
* module's doc comment above for why it's duplicated rather than imported).
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@vgai/live",
|
|
3
3
|
"author": "Volter AI, Inc.",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
|
-
"version": "0.5.
|
|
5
|
+
"version": "0.5.35",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
"node": ">=22.0.0"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
|
-
"build": "tsc -p tsconfig.build.json",
|
|
30
|
+
"build": "tsc -p tsconfig.build.json && node ../../scripts/check-live-build-output.mjs",
|
|
31
31
|
"dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput",
|
|
32
32
|
"prepack": "npm run build"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@vgai/editor-sdk": "0.5.
|
|
36
|
-
"@vgai/sdk": "0.5.
|
|
35
|
+
"@vgai/editor-sdk": "0.5.35",
|
|
36
|
+
"@vgai/sdk": "0.5.35"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@playwright/test": ">=1.58.2 <2"
|
package/src/session.ts
CHANGED
|
@@ -52,9 +52,9 @@ import {
|
|
|
52
52
|
type EditorSessionInfo,
|
|
53
53
|
type EditorTransport,
|
|
54
54
|
HttpEditorTransport,
|
|
55
|
+
servedProjectAnswer,
|
|
55
56
|
withTimeout,
|
|
56
57
|
} from '@vgai/sdk';
|
|
57
|
-
import { servedProjectAnswer } from '../../vgai-sdk/src/editor/session-registry-format';
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
60
|
* Lifted verbatim from `packages/vgai-cli/src/project-root.ts` (see this
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `~/.vgai/editor-sessions.json` — the ONE spelling of the editor-session
|
|
3
|
-
* registry contract, and the shared machinery every reader was hand-copying.
|
|
4
|
-
*
|
|
5
|
-
* The registry's WRITE half stays with its owner
|
|
6
|
-
* (`packages/editor/server/session-registry.ts`); this module owns the
|
|
7
|
-
* FORMAT: the entry shape, the shape guards, the file path, the
|
|
8
|
-
* liveness-filtered read, the `/__editor/project` answer parser, and the
|
|
9
|
-
* deterministic session-selection core. It existed as FOUR drifting copies
|
|
10
|
-
* (server registry, the CLI, and both vgai-sdk transports) held together by
|
|
11
|
-
* a "the CLI has no editor dependency" premise that had stopped being true —
|
|
12
|
-
* and the drift was already real: one copy's `/__editor/project` parser
|
|
13
|
-
* dropped `manifestError`, reporting a degraded session as belonging to no
|
|
14
|
-
* project.
|
|
15
|
-
*/
|
|
16
|
-
/** One registry entry, exactly as the server's write half records it. */
|
|
17
|
-
export interface EditorSessionEntry {
|
|
18
|
-
/** Canonical project root currently open, or null when none. */
|
|
19
|
-
project: string | null;
|
|
20
|
-
port: number;
|
|
21
|
-
/** PID of the dev-server process. */
|
|
22
|
-
pid: number;
|
|
23
|
-
/** ISO timestamp of server start. */
|
|
24
|
-
startedAt: string;
|
|
25
|
-
sessionId: string | null;
|
|
26
|
-
/** Private loopback control credential — never returned by an editor HTTP
|
|
27
|
-
* route; exists only in this user-private registry. */
|
|
28
|
-
controlSecret?: string | null;
|
|
29
|
-
repositoryId: string | null;
|
|
30
|
-
worktreeId: string | null;
|
|
31
|
-
worktreeRoot: string | null;
|
|
32
|
-
projectRelativePath: string | null;
|
|
33
|
-
branch: string | null;
|
|
34
|
-
headCommit: string | null;
|
|
35
|
-
baseCommit: string | null;
|
|
36
|
-
}
|
|
37
|
-
export declare const EDITOR_SESSIONS_REGISTRY_FILE: string;
|
|
38
|
-
export declare function isEditorSessionEntry(v: unknown): v is EditorSessionEntry;
|
|
39
|
-
export declare function normalizeEditorSessionEntry(session: EditorSessionEntry): EditorSessionEntry;
|
|
40
|
-
export declare function pidAlive(pid: number): boolean;
|
|
41
|
-
/** The registry's live entries — shape-validated and PID-liveness-filtered. */
|
|
42
|
-
export declare function readLiveRegisteredSessions(): EditorSessionEntry[];
|
|
43
|
-
/**
|
|
44
|
-
* WHICH PROJECT a `/__editor/project` body says its server is serving.
|
|
45
|
-
*
|
|
46
|
-
* `serving` is that server's own statement of "I AM serving this project, I
|
|
47
|
-
* just cannot describe it" (its manifest is unparseable or fails strict
|
|
48
|
-
* validation) — added to the route precisely because a bare
|
|
49
|
-
* `{ project: null }` is indistinguishable from "no project open". Reading
|
|
50
|
-
* only `project.path` collapses the two, and the cost is that every
|
|
51
|
-
* project-matched command loses a live session the moment a save breaks its
|
|
52
|
-
* manifest, reporting it as belonging to no project rather than as this
|
|
53
|
-
* project's degraded session.
|
|
54
|
-
*/
|
|
55
|
-
export declare function servedProjectAnswer(body: unknown): {
|
|
56
|
-
path: string | null;
|
|
57
|
-
manifestError: string | null;
|
|
58
|
-
};
|
|
59
|
-
/**
|
|
60
|
-
* Deterministic session selection — the ONE precedence order every surface
|
|
61
|
-
* follows: explicit `ctx.editorUrl` probe > port match against the listing >
|
|
62
|
-
* `ctx.projectRoot` match > lowest live port > not-running. Generic over the
|
|
63
|
-
* session shape so the editor and play transports (whose probe results
|
|
64
|
-
* differ) share the algorithm rather than a copy of it.
|
|
65
|
-
*/
|
|
66
|
-
export declare function resolveRegisteredSession<T extends {
|
|
67
|
-
port: number;
|
|
68
|
-
project: string | null;
|
|
69
|
-
url?: string;
|
|
70
|
-
}>(ctx: {
|
|
71
|
-
editorUrl?: string | undefined;
|
|
72
|
-
projectRoot?: string | undefined;
|
|
73
|
-
}, transport: {
|
|
74
|
-
listSessions(timeoutMs: number): Promise<T[]>;
|
|
75
|
-
probeSessionUrl?: ((url: string, timeoutMs: number) => Promise<T | null | undefined>) | undefined;
|
|
76
|
-
}, options: {
|
|
77
|
-
probeTimeoutMs: number;
|
|
78
|
-
discoveryTimeoutMs: number;
|
|
79
|
-
withTimeout: <V>(work: Promise<V>, timeoutMs: number, what: string) => Promise<V>;
|
|
80
|
-
notRunning: () => never;
|
|
81
|
-
}): Promise<T>;
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `~/.vgai/editor-sessions.json` — the ONE spelling of the editor-session
|
|
3
|
-
* registry contract, and the shared machinery every reader was hand-copying.
|
|
4
|
-
*
|
|
5
|
-
* The registry's WRITE half stays with its owner
|
|
6
|
-
* (`packages/editor/server/session-registry.ts`); this module owns the
|
|
7
|
-
* FORMAT: the entry shape, the shape guards, the file path, the
|
|
8
|
-
* liveness-filtered read, the `/__editor/project` answer parser, and the
|
|
9
|
-
* deterministic session-selection core. It existed as FOUR drifting copies
|
|
10
|
-
* (server registry, the CLI, and both vgai-sdk transports) held together by
|
|
11
|
-
* a "the CLI has no editor dependency" premise that had stopped being true —
|
|
12
|
-
* and the drift was already real: one copy's `/__editor/project` parser
|
|
13
|
-
* dropped `manifestError`, reporting a degraded session as belonging to no
|
|
14
|
-
* project.
|
|
15
|
-
*/
|
|
16
|
-
import { readFileSync, realpathSync } from 'node:fs';
|
|
17
|
-
import { homedir } from 'node:os';
|
|
18
|
-
import { join, resolve } from 'node:path';
|
|
19
|
-
export const EDITOR_SESSIONS_REGISTRY_FILE = join(homedir(), '.vgai', 'editor-sessions.json');
|
|
20
|
-
export function isEditorSessionEntry(v) {
|
|
21
|
-
if (typeof v !== 'object' || v === null)
|
|
22
|
-
return false;
|
|
23
|
-
const s = v;
|
|
24
|
-
const optionalIdentity = (value) => value === undefined || value === null || typeof value === 'string';
|
|
25
|
-
return ((typeof s['project'] === 'string' || s['project'] === null) &&
|
|
26
|
-
typeof s['port'] === 'number' &&
|
|
27
|
-
typeof s['pid'] === 'number' &&
|
|
28
|
-
typeof s['startedAt'] === 'string' &&
|
|
29
|
-
optionalIdentity(s['sessionId']) &&
|
|
30
|
-
optionalIdentity(s['controlSecret']) &&
|
|
31
|
-
optionalIdentity(s['repositoryId']) &&
|
|
32
|
-
optionalIdentity(s['worktreeId']) &&
|
|
33
|
-
optionalIdentity(s['worktreeRoot']) &&
|
|
34
|
-
optionalIdentity(s['projectRelativePath']) &&
|
|
35
|
-
optionalIdentity(s['branch']) &&
|
|
36
|
-
optionalIdentity(s['headCommit']) &&
|
|
37
|
-
optionalIdentity(s['baseCommit']));
|
|
38
|
-
}
|
|
39
|
-
export function normalizeEditorSessionEntry(session) {
|
|
40
|
-
return {
|
|
41
|
-
...session,
|
|
42
|
-
sessionId: session.sessionId ?? null,
|
|
43
|
-
controlSecret: session.controlSecret ?? null,
|
|
44
|
-
repositoryId: session.repositoryId ?? null,
|
|
45
|
-
worktreeId: session.worktreeId ?? null,
|
|
46
|
-
worktreeRoot: session.worktreeRoot ?? null,
|
|
47
|
-
projectRelativePath: session.projectRelativePath ?? null,
|
|
48
|
-
branch: session.branch ?? null,
|
|
49
|
-
headCommit: session.headCommit ?? null,
|
|
50
|
-
baseCommit: session.baseCommit ?? null,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
export function pidAlive(pid) {
|
|
54
|
-
try {
|
|
55
|
-
process.kill(pid, 0);
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
catch {
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
/** The registry's live entries — shape-validated and PID-liveness-filtered. */
|
|
63
|
-
export function readLiveRegisteredSessions() {
|
|
64
|
-
try {
|
|
65
|
-
const raw = JSON.parse(readFileSync(EDITOR_SESSIONS_REGISTRY_FILE, 'utf8'));
|
|
66
|
-
return Array.isArray(raw)
|
|
67
|
-
? raw
|
|
68
|
-
.filter(isEditorSessionEntry)
|
|
69
|
-
.map(normalizeEditorSessionEntry)
|
|
70
|
-
.filter((s) => pidAlive(s.pid))
|
|
71
|
-
: [];
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
return [];
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* WHICH PROJECT a `/__editor/project` body says its server is serving.
|
|
79
|
-
*
|
|
80
|
-
* `serving` is that server's own statement of "I AM serving this project, I
|
|
81
|
-
* just cannot describe it" (its manifest is unparseable or fails strict
|
|
82
|
-
* validation) — added to the route precisely because a bare
|
|
83
|
-
* `{ project: null }` is indistinguishable from "no project open". Reading
|
|
84
|
-
* only `project.path` collapses the two, and the cost is that every
|
|
85
|
-
* project-matched command loses a live session the moment a save breaks its
|
|
86
|
-
* manifest, reporting it as belonging to no project rather than as this
|
|
87
|
-
* project's degraded session.
|
|
88
|
-
*/
|
|
89
|
-
export function servedProjectAnswer(body) {
|
|
90
|
-
const b = body;
|
|
91
|
-
return {
|
|
92
|
-
path: b.project?.path ?? b.serving?.path ?? null,
|
|
93
|
-
manifestError: b.project ? null : (b.serving?.error ?? null),
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
/** Canonical (realpathed when possible) absolute form of a project path. */
|
|
97
|
-
function canonicalizeProjectPath(p) {
|
|
98
|
-
const absolute = resolve(p);
|
|
99
|
-
try {
|
|
100
|
-
return realpathSync(absolute);
|
|
101
|
-
}
|
|
102
|
-
catch {
|
|
103
|
-
return absolute;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
/** Extract the port from an `http(s)://host:port` URL, or undefined if unparseable. */
|
|
107
|
-
function portOfUrl(url) {
|
|
108
|
-
try {
|
|
109
|
-
const port = new URL(url).port;
|
|
110
|
-
return port ? Number(port) : undefined;
|
|
111
|
-
}
|
|
112
|
-
catch {
|
|
113
|
-
return undefined;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Deterministic session selection — the ONE precedence order every surface
|
|
118
|
-
* follows: explicit `ctx.editorUrl` probe > port match against the listing >
|
|
119
|
-
* `ctx.projectRoot` match > lowest live port > not-running. Generic over the
|
|
120
|
-
* session shape so the editor and play transports (whose probe results
|
|
121
|
-
* differ) share the algorithm rather than a copy of it.
|
|
122
|
-
*/
|
|
123
|
-
export async function resolveRegisteredSession(ctx, transport, options) {
|
|
124
|
-
const editorUrl = ctx.editorUrl;
|
|
125
|
-
if (editorUrl !== undefined && transport.probeSessionUrl) {
|
|
126
|
-
try {
|
|
127
|
-
const session = await options.withTimeout(transport.probeSessionUrl(editorUrl, options.probeTimeoutMs), options.probeTimeoutMs, 'explicit editor URL probe');
|
|
128
|
-
if (session)
|
|
129
|
-
return session;
|
|
130
|
-
}
|
|
131
|
-
catch { }
|
|
132
|
-
return options.notRunning();
|
|
133
|
-
}
|
|
134
|
-
let sessions;
|
|
135
|
-
try {
|
|
136
|
-
sessions = await options.withTimeout(transport.listSessions(options.discoveryTimeoutMs), options.discoveryTimeoutMs, 'editor session discovery');
|
|
137
|
-
}
|
|
138
|
-
catch {
|
|
139
|
-
return options.notRunning();
|
|
140
|
-
}
|
|
141
|
-
if (sessions.length === 0)
|
|
142
|
-
return options.notRunning();
|
|
143
|
-
if (editorUrl !== undefined) {
|
|
144
|
-
const port = portOfUrl(editorUrl);
|
|
145
|
-
const match = sessions.find((s) => s.port === port);
|
|
146
|
-
if (!match)
|
|
147
|
-
return options.notRunning();
|
|
148
|
-
return { ...match, url: editorUrl.replace(/\/+$/, '') };
|
|
149
|
-
}
|
|
150
|
-
if (ctx.projectRoot !== undefined) {
|
|
151
|
-
const canon = canonicalizeProjectPath(ctx.projectRoot);
|
|
152
|
-
const match = sessions.find((s) => s.project !== null && canonicalizeProjectPath(s.project) === canon);
|
|
153
|
-
if (!match)
|
|
154
|
-
return options.notRunning();
|
|
155
|
-
return match;
|
|
156
|
-
}
|
|
157
|
-
return [...sessions].sort((a, b) => a.port - b.port)[0];
|
|
158
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|