@vgai/sdk 0.5.13 → 0.5.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@vgai/sdk",
|
|
3
3
|
"author": "Volter AI, Inc.",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
|
-
"version": "0.5.
|
|
5
|
+
"version": "0.5.14",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
33
|
-
"@vgai/engine": "0.5.
|
|
33
|
+
"@vgai/engine": "0.5.14",
|
|
34
34
|
"playwright": "^1.58.2",
|
|
35
35
|
"zod": "^4.3.6"
|
|
36
36
|
}
|
|
@@ -31,7 +31,7 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
31
31
|
import { isAbsolute, join } from 'node:path';
|
|
32
32
|
import { z } from 'zod';
|
|
33
33
|
import { ToolError } from '../errors.js';
|
|
34
|
-
import { listProjectFiles } from '../project/shared.js';
|
|
34
|
+
import { isTheatreProjectPath, listProjectFiles } from '../project/shared.js';
|
|
35
35
|
import { defineTool, type ToolErrorDefinition, type ToolRegistry } from '../registry.js';
|
|
36
36
|
import type { ToolContext } from '../types.js';
|
|
37
37
|
|
|
@@ -153,7 +153,7 @@ export const cinematicProjectList = defineTool({
|
|
|
153
153
|
permission: { risk: 'read', summary: 'Walks a file tree; no writes.' },
|
|
154
154
|
async impl(input, ctx) {
|
|
155
155
|
const root = resolveRoot(input.root, ctx);
|
|
156
|
-
const theatreProjectFiles = listProjectFiles(root,
|
|
156
|
+
const theatreProjectFiles = listProjectFiles(root, isTheatreProjectPath);
|
|
157
157
|
return { root, theatreProjectFiles };
|
|
158
158
|
},
|
|
159
159
|
});
|
package/src/mcp/mcp-server.ts
CHANGED
|
@@ -159,7 +159,7 @@ export function createMcpServer(options: CreateMcpServerOptions = {}): VgaiMcpSe
|
|
|
159
159
|
request.params.name === 'discover-project'
|
|
160
160
|
? 'Call project.discover, project.status, and project.manifest.read. Summarize each adapter root and then call editor.session.list. Do not write files.'
|
|
161
161
|
: request.params.name === 'bring-existing-game'
|
|
162
|
-
? 'Call project.inspect before writing anything. Use its detected technologies, entry candidates, and blockers to identify Three.js/R3F, PixiJS, or React by renderer;
|
|
162
|
+
? 'Call project.inspect before writing anything. Use its detected technologies, entry candidates, and blockers to identify Three.js/R3F, PixiJS, or React by renderer; name any capability the adapter has not yet reached and obtain consent before metadata or source writes.'
|
|
163
163
|
: `Implement only this requested outcome: ${task}. Discover the project first, preserve unrelated work, use dryRun for file mutations when available, then verify through the exact matching editor with Play, status/logs, and a legible capture.`;
|
|
164
164
|
return {
|
|
165
165
|
description: requested.description,
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* - Stories (CSF) are ordinary `.tsx`/`.ts` modules (§5.2/C3) — VGAI stores
|
|
10
10
|
* no duplicate story registry, so there is nothing to mutate here; listing
|
|
11
11
|
* `*.stories.tsx`/`*.stories.ts` is the whole B2 surface.
|
|
12
|
-
* - Theatre project state (`*.theatre-project.json`)
|
|
12
|
+
* - Theatre project state (`theatre-project.json` or `*.theatre-project.json`)
|
|
13
|
+
* is a real, versioned,
|
|
13
14
|
* proprietary Theatre.js format this repo does not own (§3.2/§5.3 — "the
|
|
14
15
|
* committed Theatre project state is authoritative authored data"). B2
|
|
15
16
|
* validates only the OUTER shape (`sheetsById`/`definitionVersion`/
|
|
@@ -29,6 +30,7 @@ import { z } from 'zod';
|
|
|
29
30
|
import { ToolError } from '../errors.js';
|
|
30
31
|
import { defineTool, type ToolRegistry } from '../registry.js';
|
|
31
32
|
import {
|
|
33
|
+
isTheatreProjectPath,
|
|
32
34
|
listProjectFiles,
|
|
33
35
|
NO_PROJECT_ROOT_ERROR,
|
|
34
36
|
PATH_OUTSIDE_PROJECT_ERROR,
|
|
@@ -71,7 +73,7 @@ export const projectStoryDiscover = defineTool({
|
|
|
71
73
|
export const projectTheatreDiscover = defineTool({
|
|
72
74
|
name: 'project.theatre.discover',
|
|
73
75
|
summary:
|
|
74
|
-
'List every committed Theatre project-state file (*.theatre-project.json) in the project.',
|
|
76
|
+
'List every committed Theatre project-state file (theatre-project.json or *.theatre-project.json) in the project.',
|
|
75
77
|
description:
|
|
76
78
|
'List-only (§3.2/§5.3: the committed Theatre project state is authoritative authored data VGAI does not own the internal format of).',
|
|
77
79
|
input: z.object({}),
|
|
@@ -86,9 +88,7 @@ export const projectTheatreDiscover = defineTool({
|
|
|
86
88
|
permission: { risk: 'read', summary: 'Walks the project file tree; no writes.' },
|
|
87
89
|
async impl(_input, ctx) {
|
|
88
90
|
const projectRoot = requireProjectRoot(ctx);
|
|
89
|
-
const theatreProjectFiles = listProjectFiles(projectRoot,
|
|
90
|
-
p.endsWith('.theatre-project.json'),
|
|
91
|
-
);
|
|
91
|
+
const theatreProjectFiles = listProjectFiles(projectRoot, isTheatreProjectPath);
|
|
92
92
|
return { theatreProjectFiles };
|
|
93
93
|
},
|
|
94
94
|
});
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
checkNotStale,
|
|
23
23
|
DryRunField,
|
|
24
24
|
FILE_NOT_FOUND_ERROR,
|
|
25
|
+
isTheatreProjectPath,
|
|
25
26
|
listProjectFiles,
|
|
26
27
|
mutationResultSchema,
|
|
27
28
|
NO_PROJECT_ROOT_ERROR,
|
|
@@ -65,7 +66,7 @@ const ProjectDiscoverResult = z
|
|
|
65
66
|
.describe('Every *.stories.tsx / *.stories.ts found under the project.'),
|
|
66
67
|
theatreProjectFiles: z
|
|
67
68
|
.array(z.string())
|
|
68
|
-
.describe('Every *.theatre-project.json found under the project.'),
|
|
69
|
+
.describe('Every theatre-project.json / *.theatre-project.json found under the project.'),
|
|
69
70
|
})
|
|
70
71
|
.describe('A one-call survey of the project at ctx.projectRoot.');
|
|
71
72
|
|
|
@@ -115,9 +116,7 @@ export const projectDiscover = defineTool({
|
|
|
115
116
|
projectRoot,
|
|
116
117
|
(p) => p.endsWith('.stories.tsx') || p.endsWith('.stories.ts'),
|
|
117
118
|
),
|
|
118
|
-
theatreProjectFiles: listProjectFiles(projectRoot,
|
|
119
|
-
p.endsWith('.theatre-project.json'),
|
|
120
|
-
),
|
|
119
|
+
theatreProjectFiles: listProjectFiles(projectRoot, isTheatreProjectPath),
|
|
121
120
|
};
|
|
122
121
|
},
|
|
123
122
|
});
|
|
@@ -235,16 +235,78 @@ export type SessionJournalEvent =
|
|
|
235
235
|
/** Two epochs beating under one tabId — "Duplicate Tab" copied sessionStorage. */
|
|
236
236
|
| { readonly kind: 'tab-duplicated'; readonly tabId8: string }
|
|
237
237
|
/**
|
|
238
|
-
* The tab is present
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
238
|
+
* The tab is present but its PAGE never came up this page-load. Presence
|
|
239
|
+
* proves the tab exists, not that the document works — a main thread that
|
|
240
|
+
* died after the inline bootstrap keeps beating and holding its control
|
|
241
|
+
* connection, and can run nothing. Such a tab is passed over for blessing
|
|
242
|
+
* and named in the refusal.
|
|
243
|
+
*
|
|
244
|
+
* `reason` says which stage it is stuck at: `'no-channel'` (the page never
|
|
245
|
+
* opened a control connection at all) or `'no-command-listener'` (it did,
|
|
246
|
+
* and the module graph behind it never produced a listener).
|
|
243
247
|
*/
|
|
244
248
|
| {
|
|
245
249
|
readonly kind: 'tab-unresponsive';
|
|
246
250
|
readonly tabId8: string;
|
|
247
|
-
readonly
|
|
251
|
+
readonly reason: 'no-channel' | 'no-command-listener';
|
|
252
|
+
readonly unresponsiveForMs: number;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* An uncaught error or unhandled rejection in a tab's PAGE, captured by
|
|
256
|
+
* `index.html`'s inline bootstrap — before the module graph, so it is
|
|
257
|
+
* recorded even when the boot that would have reported it is the thing that
|
|
258
|
+
* died. This is the line that says WHY a `tab-unresponsive` tab is
|
|
259
|
+
* unresponsive.
|
|
260
|
+
*/
|
|
261
|
+
| {
|
|
262
|
+
readonly kind: 'page-error';
|
|
263
|
+
readonly tabId8: string;
|
|
264
|
+
readonly message: string;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* One batch of occurrences of ONE console error/warning condition, as the
|
|
268
|
+
* server's unresolved-console ledger recorded it
|
|
269
|
+
* (`packages/editor/server/console-ledger.ts`).
|
|
270
|
+
*
|
|
271
|
+
* This is the DURABLE half of the loudness convention, and the reason it is
|
|
272
|
+
* a row per observation rather than a row per distinct message: `count` is
|
|
273
|
+
* the running total after this batch, so the file answers "how many times
|
|
274
|
+
* did this actually fire, and when did it stop" long after the ledger (and
|
|
275
|
+
* the tab, and the server) are gone. A repeat is never filtered out here —
|
|
276
|
+
* deduping repeats to silence is precisely the failure that made a session's
|
|
277
|
+
* eleven errors read as one line and then nothing.
|
|
278
|
+
*/
|
|
279
|
+
| {
|
|
280
|
+
readonly kind: 'console-entry';
|
|
281
|
+
readonly id: string;
|
|
282
|
+
readonly severity: 'error' | 'warn';
|
|
283
|
+
readonly source: string | null;
|
|
284
|
+
/** Occurrences in THIS batch. */
|
|
285
|
+
readonly added: number;
|
|
286
|
+
/** Running total for this condition, across every page-load. */
|
|
287
|
+
readonly count: number;
|
|
288
|
+
readonly message: string;
|
|
289
|
+
}
|
|
290
|
+
/** A condition cleared by the honest re-test: the page reloaded and it did
|
|
291
|
+
* not recur. `count` is what it reached before it stopped. */
|
|
292
|
+
| {
|
|
293
|
+
readonly kind: 'console-retired';
|
|
294
|
+
readonly id: string;
|
|
295
|
+
readonly severity: 'error' | 'warn';
|
|
296
|
+
readonly count: number;
|
|
297
|
+
readonly message: string;
|
|
298
|
+
}
|
|
299
|
+
/** A condition waved through BY NAME (`vgai console ack`). The audit row is
|
|
300
|
+
* the whole point: an acknowledgment records who and why, and never erases
|
|
301
|
+
* what was acknowledged. */
|
|
302
|
+
| {
|
|
303
|
+
readonly kind: 'console-ack';
|
|
304
|
+
readonly id: string;
|
|
305
|
+
readonly severity: 'error' | 'warn';
|
|
306
|
+
readonly count: number;
|
|
307
|
+
readonly by: string;
|
|
308
|
+
readonly reason: string;
|
|
309
|
+
readonly message: string;
|
|
248
310
|
};
|
|
249
311
|
|
|
250
312
|
/** A parsed journal line: the event plus when it was appended. */
|
|
@@ -449,9 +511,22 @@ export function formatJournalLine(line: SessionJournalLine): string {
|
|
|
449
511
|
case 'tab-duplicated':
|
|
450
512
|
return `journal: ${at} tab-duplicated ${line.tabId8}`;
|
|
451
513
|
case 'tab-unresponsive':
|
|
452
|
-
return `journal: ${at} tab-unresponsive ${line.tabId8}
|
|
514
|
+
return `journal: ${at} tab-unresponsive ${line.tabId8} ${line.reason} for ${Math.round(line.unresponsiveForMs / 1000)}s`;
|
|
515
|
+
case 'page-error':
|
|
516
|
+
return `journal: ${at} page-error ${line.tabId8} ${line.message}`;
|
|
453
517
|
case 'tab-death-profile':
|
|
454
518
|
return `journal: ${at} tab-death-profile ${line.tabId8} code ${line.code} — ${tabDeathProfileBody(line)}`;
|
|
519
|
+
// The CONSOLE arm. `count` is the running total for that condition, so a
|
|
520
|
+
// reader scanning the column sees a repeat climbing rather than the same
|
|
521
|
+
// line over and over with nothing to distinguish the fiftieth from the
|
|
522
|
+
// first. Every line leads with the ack id, because that is what a reader
|
|
523
|
+
// types next.
|
|
524
|
+
case 'console-entry':
|
|
525
|
+
return `journal: ${at} console-${line.severity} ${line.id} +${line.added} (total ${line.count}) ${line.source === null ? '' : `[${line.source}] `}${line.message.split('\n')[0]}`;
|
|
526
|
+
case 'console-retired':
|
|
527
|
+
return `journal: ${at} console-retired ${line.id} after ${line.count} — did not recur after reload`;
|
|
528
|
+
case 'console-ack':
|
|
529
|
+
return `journal: ${at} console-ack ${line.id} (×${line.count}) by ${line.by}: ${line.reason}`;
|
|
455
530
|
}
|
|
456
531
|
}
|
|
457
532
|
|
package/src/project/shared.ts
CHANGED
|
@@ -44,6 +44,12 @@ import { ToolError } from '../errors.js';
|
|
|
44
44
|
import type { ToolErrorDefinition } from '../registry.js';
|
|
45
45
|
import type { ToolContext } from '../types.js';
|
|
46
46
|
|
|
47
|
+
/** Both Theatre project-state names already established in shipped projects. */
|
|
48
|
+
export function isTheatreProjectPath(path: string): boolean {
|
|
49
|
+
const filename = path.slice(Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\')) + 1);
|
|
50
|
+
return filename === 'theatre-project.json' || filename.endsWith('.theatre-project.json');
|
|
51
|
+
}
|
|
52
|
+
|
|
47
53
|
// ---------------------------------------------------------------------------
|
|
48
54
|
// Project-root resolution
|
|
49
55
|
// ---------------------------------------------------------------------------
|