vibeview 0.23.0 → 0.25.0
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/README.md +2 -0
- package/dist/{chunk-E2LZSLRF.js → chunk-GEKYHEWU.js} +247 -103
- package/dist/{chunk-PSFXVUHG.js → chunk-RFFCCPGZ.js} +44 -6
- package/dist/cli.js +176 -125
- package/dist/{server-XMSBLIWY.js → server-6EUBLXKE.js} +94 -5
- package/dist/{upload-app-ZAKAOJKE.js → upload-app-E32EZXYQ.js} +3 -1
- package/package.json +1 -1
- package/skills/vibeview-agent/SKILL.md +11 -1
|
@@ -5,22 +5,26 @@ import {
|
|
|
5
5
|
PLATFORM_DEVICE,
|
|
6
6
|
PLATFORM_NEEDS_METRO,
|
|
7
7
|
ROKU_LIVENESS_INTERVAL_MS,
|
|
8
|
+
buildRows,
|
|
8
9
|
buildToolCall,
|
|
10
|
+
checkDevBuild,
|
|
9
11
|
checkMetro,
|
|
10
12
|
createRokuPush,
|
|
11
13
|
decodeScreenshotResult,
|
|
12
14
|
filterDeviceModels,
|
|
15
|
+
formatBuildRowsHuman,
|
|
13
16
|
formatDeviceModelsHuman,
|
|
14
17
|
isDevPlatform,
|
|
15
18
|
loadDevConfig,
|
|
19
|
+
parseBuildId,
|
|
16
20
|
readDevState,
|
|
17
21
|
renderEnvelope,
|
|
18
22
|
startDevSession
|
|
19
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-GEKYHEWU.js";
|
|
20
24
|
import {
|
|
21
25
|
ApiClient,
|
|
22
26
|
resolveAuth
|
|
23
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-RFFCCPGZ.js";
|
|
24
28
|
|
|
25
29
|
// src/mcp/server.ts
|
|
26
30
|
import { writeFileSync } from "fs";
|
|
@@ -84,10 +88,32 @@ var DEV_START_DEF = {
|
|
|
84
88
|
model: {
|
|
85
89
|
type: "string",
|
|
86
90
|
description: 'Run on this exact device model, e.g. "iPhone Duo" for the foldable. Names come from list_device_models. Omit for a default phone (or TV on TV platforms).'
|
|
91
|
+
},
|
|
92
|
+
build_id: {
|
|
93
|
+
type: "number",
|
|
94
|
+
description: 'Run this uploaded build of the app instead of its newest debug build. Must be a debug build (kind "debug" in list_builds) for the platform \u2014 a release build or one with an embedded JS bundle is refused. Not for roku.'
|
|
87
95
|
}
|
|
88
96
|
},
|
|
89
97
|
required: ["platform"]
|
|
90
98
|
};
|
|
99
|
+
var LIST_BUILDS_DEF = {
|
|
100
|
+
name: "list_builds",
|
|
101
|
+
description: "List an app's uploaded builds, newest first: id, version, build number, platform, kind (debug/release/unknown), upload time and note. Pass a debug build's id to dev_start as build_id.",
|
|
102
|
+
mutating: false,
|
|
103
|
+
properties: {
|
|
104
|
+
app: { type: "string", description: "App id (public_id, from upload_app or list-apps)." }
|
|
105
|
+
},
|
|
106
|
+
required: ["app"]
|
|
107
|
+
};
|
|
108
|
+
var STOP_SESSION_DEF = {
|
|
109
|
+
name: "stop_session",
|
|
110
|
+
description: "Stop any session by id \u2014 e.g. one created through the API, the sandbox, or a collaboration link. For the session dev_start started, dev_stop does the same without an id.",
|
|
111
|
+
mutating: true,
|
|
112
|
+
properties: {
|
|
113
|
+
session_id: { type: "string", description: "The session to stop." }
|
|
114
|
+
},
|
|
115
|
+
required: ["session_id"]
|
|
116
|
+
};
|
|
91
117
|
var LIST_DEVICE_MODELS_DEF = {
|
|
92
118
|
name: "list_device_models",
|
|
93
119
|
description: 'List the device models you can start right now (model, OS version, platform, category, and form_factor "foldable" for a device that folds, like the iPhone Duo). Pass a model name to dev_start to run on it.',
|
|
@@ -138,7 +164,9 @@ function buildToolDefinitions() {
|
|
|
138
164
|
DEV_STOP_DEF,
|
|
139
165
|
DEV_RELOAD_DEF,
|
|
140
166
|
UPLOAD_APP_DEF,
|
|
141
|
-
LIST_DEVICE_MODELS_DEF
|
|
167
|
+
LIST_DEVICE_MODELS_DEF,
|
|
168
|
+
LIST_BUILDS_DEF,
|
|
169
|
+
STOP_SESSION_DEF
|
|
142
170
|
];
|
|
143
171
|
}
|
|
144
172
|
function textResult(text, structuredContent, isError = false) {
|
|
@@ -166,6 +194,12 @@ async function handleToolCall(toolName, args, deps) {
|
|
|
166
194
|
if (toolName === "list_device_models") {
|
|
167
195
|
return handleListDeviceModels(args, deps);
|
|
168
196
|
}
|
|
197
|
+
if (toolName === "list_builds") {
|
|
198
|
+
return handleListBuilds(args, deps);
|
|
199
|
+
}
|
|
200
|
+
if (toolName === "stop_session") {
|
|
201
|
+
return handleStopSession(args, deps);
|
|
202
|
+
}
|
|
169
203
|
const cmd = findCommand(toolName);
|
|
170
204
|
if (!cmd) {
|
|
171
205
|
return errorResult(`Unknown tool: ${toolName}`);
|
|
@@ -245,12 +279,23 @@ async function handleDevStart(args, deps) {
|
|
|
245
279
|
`dev_start: platform must be one of ${MCP_DEV_PLATFORMS.join(", ")}, got "${String(platform)}"`
|
|
246
280
|
);
|
|
247
281
|
}
|
|
282
|
+
let buildId;
|
|
283
|
+
if (args.build_id !== void 0 && args.build_id !== null) {
|
|
284
|
+
try {
|
|
285
|
+
buildId = parseBuildId(args.build_id);
|
|
286
|
+
} catch {
|
|
287
|
+
return errorResult(
|
|
288
|
+
`dev_start: build_id must be a positive build id (see list_builds), got "${String(args.build_id)}"`
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
248
292
|
try {
|
|
249
293
|
const result = await deps.devSession.start({
|
|
250
294
|
platform,
|
|
251
295
|
app: typeof args.app === "string" ? args.app : void 0,
|
|
252
296
|
metroPort: typeof args.metro_port === "number" ? args.metro_port : void 0,
|
|
253
|
-
model: typeof args.model === "string" && args.model.trim() ? args.model : void 0
|
|
297
|
+
model: typeof args.model === "string" && args.model.trim() ? args.model : void 0,
|
|
298
|
+
...buildId !== void 0 ? { buildId } : {}
|
|
254
299
|
});
|
|
255
300
|
const payload = { session_id: result.sessionId, page_url: result.pageUrl };
|
|
256
301
|
return textResult(`dev session started: ${payload.session_id}
|
|
@@ -271,6 +316,36 @@ async function handleListDeviceModels(args, deps) {
|
|
|
271
316
|
}
|
|
272
317
|
return textResult(formatDeviceModelsHuman(models).trimEnd(), { models });
|
|
273
318
|
}
|
|
319
|
+
async function handleListBuilds(args, deps) {
|
|
320
|
+
const appId = typeof args.app === "string" ? args.app.trim() : "";
|
|
321
|
+
if (!appId) return errorResult("list_builds: `app` is required \u2014 an app id from list-apps");
|
|
322
|
+
const getApp = deps.getApp ?? ((id) => new ApiClient(deps.auth.baseUrl, deps.auth.token).getApp(id));
|
|
323
|
+
try {
|
|
324
|
+
const app = await getApp(appId);
|
|
325
|
+
const builds = buildRows(app);
|
|
326
|
+
return textResult(formatBuildRowsHuman(app, builds).trimEnd(), {
|
|
327
|
+
app_id: app.public_id,
|
|
328
|
+
builds
|
|
329
|
+
});
|
|
330
|
+
} catch (err) {
|
|
331
|
+
return errorResult(`error: ${err instanceof Error ? err.message : String(err)}`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
async function handleStopSession(args, deps) {
|
|
335
|
+
const sessionId = typeof args.session_id === "string" ? args.session_id.trim() : "";
|
|
336
|
+
if (!sessionId) return errorResult("stop_session: `session_id` is required");
|
|
337
|
+
const stop = deps.stopSession ?? ((id) => new ApiClient(deps.auth.baseUrl, deps.auth.token).stopSession(id));
|
|
338
|
+
try {
|
|
339
|
+
if (deps.devSession.current()?.sessionId === sessionId) {
|
|
340
|
+
await deps.devSession.stop();
|
|
341
|
+
} else {
|
|
342
|
+
await stop(sessionId);
|
|
343
|
+
}
|
|
344
|
+
} catch (err) {
|
|
345
|
+
return errorResult(`error: ${err instanceof Error ? err.message : String(err)}`);
|
|
346
|
+
}
|
|
347
|
+
return textResult(`session stopped: ${sessionId}`, { session_id: sessionId, stopped: true });
|
|
348
|
+
}
|
|
274
349
|
async function handleDevReload(args, deps) {
|
|
275
350
|
const requested = typeof args.session_id === "string" ? args.session_id : void 0;
|
|
276
351
|
try {
|
|
@@ -301,7 +376,7 @@ async function handleUploadApp(args, deps) {
|
|
|
301
376
|
}
|
|
302
377
|
const name = typeof args.name === "string" && args.name ? args.name : void 0;
|
|
303
378
|
const upload = deps.uploadApp ?? (async (f, n) => {
|
|
304
|
-
const { uploadAppBuild } = await import("./upload-app-
|
|
379
|
+
const { uploadAppBuild } = await import("./upload-app-E32EZXYQ.js");
|
|
305
380
|
const { result: result2 } = await uploadAppBuild(f, { ...deps.auth, name: n });
|
|
306
381
|
return result2;
|
|
307
382
|
});
|
|
@@ -319,11 +394,17 @@ async function handleUploadApp(args, deps) {
|
|
|
319
394
|
package_name: result.package_name,
|
|
320
395
|
platform: result.platform,
|
|
321
396
|
is_new: isNew,
|
|
397
|
+
build_id: result.build_id ?? null,
|
|
398
|
+
version: result.version ?? null,
|
|
399
|
+
build_number: result.build_number ?? null,
|
|
322
400
|
warnings
|
|
323
401
|
};
|
|
324
402
|
const lines = [
|
|
325
403
|
`${isNew ? "New app created" : "Build added to existing app"}: ${result.name}`,
|
|
326
404
|
`app_id: ${result.public_id} [${result.platform}] ${result.package_name}`,
|
|
405
|
+
...result.build_id != null ? [
|
|
406
|
+
`build_id: ${result.build_id}${result.version ? ` version ${result.version}${result.build_number ? ` (${result.build_number})` : ""}` : ""}`
|
|
407
|
+
] : [],
|
|
327
408
|
...warnings.map((w) => `warning: ${w}`)
|
|
328
409
|
];
|
|
329
410
|
return textResult(lines.join("\n"), payload);
|
|
@@ -375,6 +456,13 @@ function createDevSessionController(auth, webUrl) {
|
|
|
375
456
|
);
|
|
376
457
|
}
|
|
377
458
|
}
|
|
459
|
+
if (cfg.buildId !== void 0) {
|
|
460
|
+
checkDevBuild(
|
|
461
|
+
await new ApiClient(auth.baseUrl, auth.token).getApp(appId),
|
|
462
|
+
cfg.buildId,
|
|
463
|
+
cfg.platform
|
|
464
|
+
);
|
|
465
|
+
}
|
|
378
466
|
const isTv = PLATFORM_DEVICE[cfg.platform].tv;
|
|
379
467
|
platform = cfg.platform;
|
|
380
468
|
handle = await startDevSession({
|
|
@@ -386,6 +474,7 @@ function createDevSessionController(auth, webUrl) {
|
|
|
386
474
|
deviceCategory: isTv ? "tv" : entry?.deviceCategory ?? "phone",
|
|
387
475
|
// A named model decides the category itself (startDevSession).
|
|
388
476
|
model: cfg.model,
|
|
477
|
+
buildId: cfg.buildId,
|
|
389
478
|
metroPort,
|
|
390
479
|
open: false
|
|
391
480
|
});
|
package/package.json
CHANGED
|
@@ -214,6 +214,11 @@ streaming minutes even when idle:
|
|
|
214
214
|
```bash
|
|
215
215
|
vibeview dev-stop
|
|
216
216
|
```
|
|
217
|
+
A session you did not start with `dev` (one created through the API, the
|
|
218
|
+
sandbox, or a collaboration link) is stopped by id:
|
|
219
|
+
```bash
|
|
220
|
+
vibeview stop <session-id>
|
|
221
|
+
```
|
|
217
222
|
|
|
218
223
|
## 6. Command reference
|
|
219
224
|
|
|
@@ -250,9 +255,12 @@ Dev-loop lifecycle commands (not registry verbs, but needed for every run):
|
|
|
250
255
|
| Command | Purpose |
|
|
251
256
|
|---------|---------|
|
|
252
257
|
| `dev --detach --json` | Start a device + Metro-tunnel session in the background, emitting `session_ready`/`warning`/`error` JSON events on stdout. Add `--model "<name>"` to pick an exact device model. |
|
|
258
|
+
| `dev --build <id>` | Run that uploaded build instead of the app's newest debug build (combine with `--app`, `--platform`, `--model`, `--detach --json`). Only a debug build (kind `debug` in `list-builds`) is accepted; a release build or one with an embedded JS bundle is refused. Not on Roku. |
|
|
259
|
+
| `list-builds <app>` | List an app's uploaded builds, newest first: id, version (build number), platform, kind (`debug`/`release`/`unknown`), upload time, note. `--json` prints an array. |
|
|
253
260
|
| `list-devices --models` | List the device models you can start (the names `--model` takes); foldables are marked `foldable`. |
|
|
254
261
|
| `dev-status` | Check on the current project's detached dev session. |
|
|
255
262
|
| `dev-stop` | End the current project's detached dev session. |
|
|
263
|
+
| `vibeview stop <session-id>` | End any session by id — one created through the API, the sandbox, or a collaboration link. |
|
|
256
264
|
| `dev-reload` | Roku only: re-package, upload and restart the channel in the detached session (the `r` key of the foreground loop). |
|
|
257
265
|
|
|
258
266
|
## 7. If you're calling VibeView over MCP
|
|
@@ -271,9 +279,11 @@ steps the CLI does with plain shell commands:
|
|
|
271
279
|
| MCP tool | Args | Purpose |
|
|
272
280
|
|----------|------|---------|
|
|
273
281
|
| `upload_app` | `file` (required path), `name` | Upload a debug build. The MCP equivalent of `vibeview upload-app`, so step 1 of the loop needs no shell. Returns the `app_id` to pass to `dev_start`. |
|
|
274
|
-
| `dev_start` | `platform` (required: `ios`/`android`/`tvos`/`androidtv`/`roku`), `app`, `metro_port`, `model` | Start a dev-loop session held open by the MCP server. The MCP equivalent of `vibeview dev --detach`; `model` picks an exact device model (e.g. `"iPhone Duo"`). Returns `page_url` — relay it to the developer immediately, same as step 5 of the loop. |
|
|
282
|
+
| `dev_start` | `platform` (required: `ios`/`android`/`tvos`/`androidtv`/`roku`), `app`, `metro_port`, `model`, `build_id` | Start a dev-loop session held open by the MCP server. The MCP equivalent of `vibeview dev --detach`; `model` picks an exact device model (e.g. `"iPhone Duo"`); `build_id` runs that debug build instead of the newest one (see `list_builds`). Returns `page_url` — relay it to the developer immediately, same as step 5 of the loop. |
|
|
275
283
|
| `list_device_models` | `device_type` | List the device models you can start (model, OS, platform, category, `foldable` marker). The MCP equivalent of `vibeview list-devices --models`. |
|
|
284
|
+
| `list_builds` | `app` (required) | List an app's uploaded builds with their kind (`debug`/`release`/`unknown`). The MCP equivalent of `vibeview list-builds`. |
|
|
276
285
|
| `dev_stop` | — | Stop the session `dev_start` started. The MCP equivalent of `vibeview dev-stop`. |
|
|
286
|
+
| `stop_session` | `session_id` (required) | Stop any session by id. The MCP equivalent of `vibeview stop <session-id>`. |
|
|
277
287
|
|
|
278
288
|
**`dev_start` is stateful — it changes the default session for every later
|
|
279
289
|
call.** Once it succeeds, any tool called without an explicit `session_id`
|