vibeview 0.31.0 → 0.32.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.
|
@@ -461,6 +461,10 @@ function writeDevState(cwd, state) {
|
|
|
461
461
|
ensureGitignored(cwd);
|
|
462
462
|
}
|
|
463
463
|
function readDevState(cwd) {
|
|
464
|
+
const found = readDevStateFile(cwd);
|
|
465
|
+
return found && found.alive ? found.state : null;
|
|
466
|
+
}
|
|
467
|
+
function readDevStateFile(cwd) {
|
|
464
468
|
let raw;
|
|
465
469
|
try {
|
|
466
470
|
raw = readFileSync2(statePath(cwd), "utf-8");
|
|
@@ -473,10 +477,10 @@ function readDevState(cwd) {
|
|
|
473
477
|
} catch {
|
|
474
478
|
return null;
|
|
475
479
|
}
|
|
476
|
-
if (typeof parsed.pid !== "number" ||
|
|
480
|
+
if (!parsed || typeof parsed.pid !== "number" || typeof parsed.session_id !== "string") {
|
|
477
481
|
return null;
|
|
478
482
|
}
|
|
479
|
-
return parsed;
|
|
483
|
+
return { state: parsed, alive: isPidAlive(parsed.pid) };
|
|
480
484
|
}
|
|
481
485
|
function clearDevState(cwd) {
|
|
482
486
|
const path = statePath(cwd);
|
|
@@ -2575,7 +2579,7 @@ async function pollUntilActive(api, sessionId, timeoutMs, intervalMs = 2e3, onIn
|
|
|
2575
2579
|
}
|
|
2576
2580
|
function sessionLivenessVerdict(info) {
|
|
2577
2581
|
if (info && (info.status === "stopped" || info.status === "failed")) {
|
|
2578
|
-
return { end: true, message: `session ${info.status} \u2014 ending the
|
|
2582
|
+
return { end: true, message: `session ${info.status} \u2014 ending the dev session` };
|
|
2579
2583
|
}
|
|
2580
2584
|
return { end: false };
|
|
2581
2585
|
}
|
|
@@ -3197,6 +3201,8 @@ async function runDevInProcess(opts) {
|
|
|
3197
3201
|
process.stdin.pause();
|
|
3198
3202
|
});
|
|
3199
3203
|
}
|
|
3204
|
+
}
|
|
3205
|
+
if (rokuBuild || standalone) {
|
|
3200
3206
|
const sessionId = handle.sessionId;
|
|
3201
3207
|
const reportedWarnings = handle.reportedWarnings;
|
|
3202
3208
|
let keepAlive;
|
|
@@ -4221,6 +4227,7 @@ export {
|
|
|
4221
4227
|
formatBuildRowsHuman,
|
|
4222
4228
|
listBuilds,
|
|
4223
4229
|
readDevState,
|
|
4230
|
+
readDevStateFile,
|
|
4224
4231
|
clearDevState,
|
|
4225
4232
|
readMetroState,
|
|
4226
4233
|
killOwnedMetro,
|
package/dist/cli.js
CHANGED
|
@@ -21,9 +21,10 @@ import {
|
|
|
21
21
|
printOutcomeLine,
|
|
22
22
|
printTransition,
|
|
23
23
|
readDevState,
|
|
24
|
+
readDevStateFile,
|
|
24
25
|
readMetroState,
|
|
25
26
|
runAgentVerb
|
|
26
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-T6H5XTBX.js";
|
|
27
28
|
import {
|
|
28
29
|
ApiClient,
|
|
29
30
|
ApiStatusError,
|
|
@@ -543,15 +544,20 @@ function formatAction(action) {
|
|
|
543
544
|
function formatToolCall(tc) {
|
|
544
545
|
return formatAction({ tool: tc.name, args: tc.args });
|
|
545
546
|
}
|
|
547
|
+
function runStartedLine(evt) {
|
|
548
|
+
const steps = `${evt.total_steps} step(s)`;
|
|
549
|
+
const model = chalk2.bold(evt.model || "default");
|
|
550
|
+
if (evt.mode === "replay") return `${chalk2.cyan("\u25B6")} Replay started \u2014 ${steps} (no AI)`;
|
|
551
|
+
if (evt.mode === "hybrid") {
|
|
552
|
+
return `${chalk2.cyan("\u25B6")} Hybrid test started \u2014 ${steps}, replaying the recording, AI fallback model: ${model}`;
|
|
553
|
+
}
|
|
554
|
+
return `${chalk2.cyan("\u25B6")} AI test started \u2014 ${steps}, model: ${model}`;
|
|
555
|
+
}
|
|
546
556
|
function displayProgressEvent(evt, ctx) {
|
|
547
557
|
const { spinner } = ctx;
|
|
548
558
|
switch (evt.event) {
|
|
549
559
|
case "run_started":
|
|
550
|
-
printBelowSpinner(
|
|
551
|
-
spinner,
|
|
552
|
-
`${chalk2.cyan("\u25B6")} AI test started \u2014 ${evt.total_steps} step(s), model: ${chalk2.bold(evt.model || "default")}`,
|
|
553
|
-
" Starting test..."
|
|
554
|
-
);
|
|
560
|
+
printBelowSpinner(spinner, runStartedLine(evt), " Starting test...");
|
|
555
561
|
ctx.totalSteps = evt.total_steps ?? ctx.totalSteps;
|
|
556
562
|
break;
|
|
557
563
|
case "step_started": {
|
|
@@ -1348,6 +1354,9 @@ async function resolveSteps(options) {
|
|
|
1348
1354
|
}
|
|
1349
1355
|
throw new Error("No steps provided. Use --steps, --steps-file, or pipe JSON to stdin.");
|
|
1350
1356
|
}
|
|
1357
|
+
function testCaseUrl(baseUrl, publicId) {
|
|
1358
|
+
return `${baseUrl}/tests/cases/${encodeURIComponent(publicId)}`;
|
|
1359
|
+
}
|
|
1351
1360
|
function assertHasSteps(steps) {
|
|
1352
1361
|
if (!Array.isArray(steps)) {
|
|
1353
1362
|
throw new Error(
|
|
@@ -1407,7 +1416,7 @@ async function createTest(options) {
|
|
|
1407
1416
|
name: result.name,
|
|
1408
1417
|
app_id: appPublicId || null,
|
|
1409
1418
|
outcome: result.outcome ?? null,
|
|
1410
|
-
url:
|
|
1419
|
+
url: testCaseUrl(baseUrl, result.public_id)
|
|
1411
1420
|
},
|
|
1412
1421
|
null,
|
|
1413
1422
|
2
|
|
@@ -1423,7 +1432,7 @@ async function createTest(options) {
|
|
|
1423
1432
|
console.log(` ${chalk10.dim(`Platform: ${result.platform}`)}`);
|
|
1424
1433
|
}
|
|
1425
1434
|
console.log(` ${chalk10.dim(`Steps: ${steps.length}`)}`);
|
|
1426
|
-
console.log(chalk10.dim(` ${baseUrl}
|
|
1435
|
+
console.log(chalk10.dim(` ${testCaseUrl(baseUrl, result.public_id)}
|
|
1427
1436
|
`));
|
|
1428
1437
|
}
|
|
1429
1438
|
} catch (err) {
|
|
@@ -1519,8 +1528,8 @@ function buildLine(info) {
|
|
|
1519
1528
|
return `${info.app_build_id}${version}`;
|
|
1520
1529
|
}
|
|
1521
1530
|
async function devStatus(opts) {
|
|
1522
|
-
const
|
|
1523
|
-
if (!
|
|
1531
|
+
const found = readDevStateFile(process.cwd());
|
|
1532
|
+
if (!found) {
|
|
1524
1533
|
if (opts.json) {
|
|
1525
1534
|
console.log(JSON.stringify({ running: false }));
|
|
1526
1535
|
} else {
|
|
@@ -1531,6 +1540,11 @@ async function devStatus(opts) {
|
|
|
1531
1540
|
}
|
|
1532
1541
|
const { token, baseUrl } = resolveAuth(opts);
|
|
1533
1542
|
const api = new ApiClient(baseUrl, token);
|
|
1543
|
+
if (!found.alive) {
|
|
1544
|
+
await reportOrphan(api, found.state, opts);
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
const state = found.state;
|
|
1534
1548
|
let sessionStatus;
|
|
1535
1549
|
let info;
|
|
1536
1550
|
try {
|
|
@@ -1571,11 +1585,46 @@ async function devStatus(opts) {
|
|
|
1571
1585
|
if (metro) console.error(chalk11.dim(`Metro: pid ${metro.pid} on :${metro.port} (CLI-owned)`));
|
|
1572
1586
|
process.exit(0);
|
|
1573
1587
|
}
|
|
1588
|
+
var LIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "queued", "starting", "active"]);
|
|
1589
|
+
async function reportOrphan(api, state, opts) {
|
|
1590
|
+
let status;
|
|
1591
|
+
try {
|
|
1592
|
+
status = (await api.getSession(state.session_id)).status;
|
|
1593
|
+
} catch {
|
|
1594
|
+
status = void 0;
|
|
1595
|
+
}
|
|
1596
|
+
const live = status !== void 0 && LIVE_STATUSES.has(status);
|
|
1597
|
+
if (!live && status !== void 0) clearDevState(process.cwd());
|
|
1598
|
+
if (opts.json) {
|
|
1599
|
+
console.log(
|
|
1600
|
+
JSON.stringify({
|
|
1601
|
+
running: false,
|
|
1602
|
+
pid: state.pid,
|
|
1603
|
+
session_id: state.session_id,
|
|
1604
|
+
session_status: status ?? null,
|
|
1605
|
+
orphaned: live
|
|
1606
|
+
})
|
|
1607
|
+
);
|
|
1608
|
+
} else if (live) {
|
|
1609
|
+
console.error(
|
|
1610
|
+
chalk11.yellow(
|
|
1611
|
+
`\u26A0 The dev process (pid ${state.pid}) has exited, but session ${state.session_id} is still ${status}.`
|
|
1612
|
+
)
|
|
1613
|
+
);
|
|
1614
|
+
console.error(` End it: vibeview stop ${state.session_id}`);
|
|
1615
|
+
} else {
|
|
1616
|
+
console.error(
|
|
1617
|
+
`No dev session running \u2014 the dev process (pid ${state.pid}) has exited` + (status ? ` and session ${state.session_id} is ${status}.` : ".")
|
|
1618
|
+
);
|
|
1619
|
+
}
|
|
1620
|
+
process.exit(1);
|
|
1621
|
+
}
|
|
1574
1622
|
|
|
1575
1623
|
// src/commands/dev-stop.ts
|
|
1576
1624
|
async function devStop(opts) {
|
|
1577
|
-
const
|
|
1578
|
-
|
|
1625
|
+
const found = readDevStateFile(process.cwd());
|
|
1626
|
+
const state = found?.state;
|
|
1627
|
+
if (!found || !state) {
|
|
1579
1628
|
if (opts.json) {
|
|
1580
1629
|
console.log(JSON.stringify({ stopped: false, reason: "no_dev_session" }));
|
|
1581
1630
|
} else {
|
|
@@ -1588,10 +1637,12 @@ async function devStop(opts) {
|
|
|
1588
1637
|
const api = new ApiClient(baseUrl, token);
|
|
1589
1638
|
await api.stopSession(state.session_id).catch(() => {
|
|
1590
1639
|
});
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1640
|
+
if (found.alive) {
|
|
1641
|
+
try {
|
|
1642
|
+
process.kill(state.pid, "SIGTERM");
|
|
1643
|
+
} catch (err) {
|
|
1644
|
+
if (err.code !== "ESRCH") throw err;
|
|
1645
|
+
}
|
|
1595
1646
|
}
|
|
1596
1647
|
clearDevState(process.cwd());
|
|
1597
1648
|
killOwnedMetro(process.cwd());
|
|
@@ -4028,7 +4079,7 @@ program.command("dev-reload").description(
|
|
|
4028
4079
|
program.command("mcp").description(
|
|
4029
4080
|
"Run an MCP stdio server exposing the agent verbs (tap, swipe, type, ...) plus dev_start/dev_stop/dev_reload as tools"
|
|
4030
4081
|
).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").action(async (opts) => {
|
|
4031
|
-
const { runMcpServer } = await import("./server-
|
|
4082
|
+
const { runMcpServer } = await import("./server-FJSBWEHZ.js");
|
|
4032
4083
|
await runMcpServer({ ...opts, version: pkg.version });
|
|
4033
4084
|
});
|
|
4034
4085
|
program.command("agent-setup").description(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeview",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "VibeView CLI -- run your app on cloud iOS simulators, Android emulators, Apple TV, Android TV and Roku (beta) devices: a React Native dev loop, device control for you or your coding agent (CLI or MCP), and tests from CI",
|
|
5
5
|
"mcpName": "io.github.vibeview/vibeview",
|
|
6
6
|
"type": "module",
|