vibeview 0.25.0 → 0.27.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/dist/{chunk-GEKYHEWU.js → chunk-46X7UN6Y.js} +272 -199
- package/dist/{chunk-RFFCCPGZ.js → chunk-U7FCGMWG.js} +24 -4
- package/dist/cli.js +83 -60
- package/dist/{server-6EUBLXKE.js → server-XJREB7KU.js} +8 -7
- package/dist/{upload-app-E32EZXYQ.js → upload-app-QUUXKNR2.js} +1 -1
- package/package.json +1 -1
- package/skills/vibeview-agent/SKILL.md +36 -17
|
@@ -42,6 +42,21 @@ import { createWriteStream, mkdirSync as mkdirSync2, renameSync, rmSync } from "
|
|
|
42
42
|
import { basename, join as join2, resolve, sep } from "path";
|
|
43
43
|
import { pipeline } from "stream/promises";
|
|
44
44
|
import { Readable } from "stream";
|
|
45
|
+
var AuthError = class extends Error {
|
|
46
|
+
constructor(message = "Authentication failed. Check your API token.") {
|
|
47
|
+
super(message);
|
|
48
|
+
this.name = "AuthError";
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
function errorExitCode(err, otherwise = 1) {
|
|
52
|
+
return err instanceof AuthError ? 2 : otherwise;
|
|
53
|
+
}
|
|
54
|
+
function reportCommandError(json, err) {
|
|
55
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
56
|
+
if (json) console.log(JSON.stringify({ event: "error", message }));
|
|
57
|
+
process.stderr.write(`error: ${message}
|
|
58
|
+
`);
|
|
59
|
+
}
|
|
45
60
|
var NotFoundError = class extends Error {
|
|
46
61
|
constructor(message) {
|
|
47
62
|
super(message);
|
|
@@ -52,6 +67,8 @@ function extractDetail(text) {
|
|
|
52
67
|
try {
|
|
53
68
|
const parsed = JSON.parse(text);
|
|
54
69
|
if (parsed && typeof parsed.detail === "string") return parsed.detail;
|
|
70
|
+
if (parsed && parsed.detail && typeof parsed.detail.message === "string")
|
|
71
|
+
return parsed.detail.message;
|
|
55
72
|
} catch {
|
|
56
73
|
}
|
|
57
74
|
return void 0;
|
|
@@ -96,7 +113,7 @@ var ApiClient = class {
|
|
|
96
113
|
});
|
|
97
114
|
if (!resp.ok) {
|
|
98
115
|
const text = await resp.text().catch(() => "");
|
|
99
|
-
if (resp.status === 401) throw new
|
|
116
|
+
if (resp.status === 401) throw new AuthError();
|
|
100
117
|
if (resp.status === 404) throw new NotFoundError(`Not found: ${extractDetail(text) ?? path}`);
|
|
101
118
|
throw new Error(extractDetail(text) ?? `API error ${resp.status}: ${text}`);
|
|
102
119
|
}
|
|
@@ -168,7 +185,7 @@ var ApiClient = class {
|
|
|
168
185
|
});
|
|
169
186
|
if (!resp.ok) {
|
|
170
187
|
const text = await resp.text().catch(() => "");
|
|
171
|
-
if (resp.status === 401) throw new
|
|
188
|
+
if (resp.status === 401) throw new AuthError();
|
|
172
189
|
if (resp.status === 404) throw new NotFoundError(`Not found: ${extractDetail(text) ?? path}`);
|
|
173
190
|
throw new Error(extractDetail(text) ?? `API error ${resp.status}: ${text}`);
|
|
174
191
|
}
|
|
@@ -188,7 +205,7 @@ var ApiClient = class {
|
|
|
188
205
|
});
|
|
189
206
|
if (!resp.ok) {
|
|
190
207
|
const text = await resp.text().catch(() => "");
|
|
191
|
-
if (resp.status === 401) throw new
|
|
208
|
+
if (resp.status === 401) throw new AuthError();
|
|
192
209
|
if (resp.status === 404) throw new NotFoundError(`Not found: ${extractDetail(text) ?? path}`);
|
|
193
210
|
throw new Error(extractDetail(text) ?? `API error ${resp.status}: ${text}`);
|
|
194
211
|
}
|
|
@@ -347,7 +364,7 @@ var ApiClient = class {
|
|
|
347
364
|
const resp = await this.fetchOrExplain(url, { method: "GET", headers });
|
|
348
365
|
if (!resp.ok) {
|
|
349
366
|
const text = await resp.text().catch(() => "");
|
|
350
|
-
if (resp.status === 401) throw new
|
|
367
|
+
if (resp.status === 401) throw new AuthError();
|
|
351
368
|
if (resp.status === 404)
|
|
352
369
|
throw new NotFoundError(`Not found: ${extractDetail(text) ?? `/builds/${id}/artifact`}`);
|
|
353
370
|
throw new Error(extractDetail(text) ?? `API error ${resp.status}: ${text}`);
|
|
@@ -729,6 +746,9 @@ export {
|
|
|
729
746
|
loadConfig,
|
|
730
747
|
saveConfig,
|
|
731
748
|
resolveAuth,
|
|
749
|
+
AuthError,
|
|
750
|
+
errorExitCode,
|
|
751
|
+
reportCommandError,
|
|
732
752
|
NotFoundError,
|
|
733
753
|
ApiClient,
|
|
734
754
|
createSpinner,
|
package/dist/cli.js
CHANGED
|
@@ -11,16 +11,19 @@ import {
|
|
|
11
11
|
formatDeviceModelsHuman,
|
|
12
12
|
formatDevicesHuman,
|
|
13
13
|
formatDuration,
|
|
14
|
+
formatUtcTimestamp,
|
|
14
15
|
killOwnedMetro,
|
|
15
16
|
listBuilds,
|
|
16
17
|
loadDevConfig,
|
|
17
18
|
newTransitionState,
|
|
19
|
+
platformWithArticle,
|
|
20
|
+
pressButtonsHelp,
|
|
18
21
|
printOutcomeLine,
|
|
19
22
|
printTransition,
|
|
20
23
|
readDevState,
|
|
21
24
|
readMetroState,
|
|
22
25
|
runAgentVerb
|
|
23
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-46X7UN6Y.js";
|
|
24
27
|
import {
|
|
25
28
|
ApiClient,
|
|
26
29
|
EXIT_INFRA_ERROR,
|
|
@@ -29,15 +32,17 @@ import {
|
|
|
29
32
|
NotFoundError,
|
|
30
33
|
UsageError,
|
|
31
34
|
createSpinner,
|
|
35
|
+
errorExitCode,
|
|
32
36
|
loadConfig,
|
|
37
|
+
reportCommandError,
|
|
33
38
|
resolveAuth,
|
|
34
39
|
saveConfig,
|
|
35
40
|
uploadApp
|
|
36
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-U7FCGMWG.js";
|
|
37
42
|
|
|
38
43
|
// src/cli.ts
|
|
39
44
|
import { createRequire } from "module";
|
|
40
|
-
import { Command } from "commander";
|
|
45
|
+
import { Command, Option } from "commander";
|
|
41
46
|
|
|
42
47
|
// src/commands/run-suite.ts
|
|
43
48
|
import chalk3 from "chalk";
|
|
@@ -833,10 +838,16 @@ import chalk6 from "chalk";
|
|
|
833
838
|
async function listSuites(options) {
|
|
834
839
|
const { token, baseUrl } = resolveAuth(options);
|
|
835
840
|
const client = new ApiClient(baseUrl, token);
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
841
|
+
let suites;
|
|
842
|
+
try {
|
|
843
|
+
suites = await client.listSuites({
|
|
844
|
+
tags: options.tag && options.tag.length > 0 ? options.tag : void 0,
|
|
845
|
+
match: options.match
|
|
846
|
+
});
|
|
847
|
+
} catch (err) {
|
|
848
|
+
reportCommandError(options.output === "json", err);
|
|
849
|
+
process.exit(EXIT_INFRA_ERROR);
|
|
850
|
+
}
|
|
840
851
|
if (options.output === "json") {
|
|
841
852
|
console.log(JSON.stringify(suites, null, 2));
|
|
842
853
|
return;
|
|
@@ -861,7 +872,13 @@ import chalk7 from "chalk";
|
|
|
861
872
|
async function listApps(options) {
|
|
862
873
|
const { token, baseUrl } = resolveAuth(options);
|
|
863
874
|
const client = new ApiClient(baseUrl, token);
|
|
864
|
-
|
|
875
|
+
let apps;
|
|
876
|
+
try {
|
|
877
|
+
apps = await client.listApps();
|
|
878
|
+
} catch (err) {
|
|
879
|
+
reportCommandError(options.output === "json", err);
|
|
880
|
+
process.exit(EXIT_INFRA_ERROR);
|
|
881
|
+
}
|
|
865
882
|
if (options.output === "json") {
|
|
866
883
|
console.log(JSON.stringify(apps, null, 2));
|
|
867
884
|
return;
|
|
@@ -895,7 +912,7 @@ async function stopCommand(sessionId, opts, deps) {
|
|
|
895
912
|
const message = err instanceof Error ? err.message : String(err);
|
|
896
913
|
if (opts.json) console.log(JSON.stringify({ stopped: false, session_id: id, message }));
|
|
897
914
|
console.error(chalk8.red(`error: ${message}`));
|
|
898
|
-
process.exitCode =
|
|
915
|
+
process.exitCode = errorExitCode(err);
|
|
899
916
|
return;
|
|
900
917
|
}
|
|
901
918
|
const state = readDevState(process.cwd());
|
|
@@ -1217,7 +1234,7 @@ async function devReload(opts) {
|
|
|
1217
1234
|
fail(
|
|
1218
1235
|
opts,
|
|
1219
1236
|
"not_roku",
|
|
1220
|
-
`dev-reload is for Roku channels;
|
|
1237
|
+
`dev-reload is for Roku channels; ${platformWithArticle(state.platform)} session hot-reloads through Metro on its own.`,
|
|
1221
1238
|
2
|
|
1222
1239
|
);
|
|
1223
1240
|
}
|
|
@@ -1277,8 +1294,10 @@ import chalk13 from "chalk";
|
|
|
1277
1294
|
// src/lib/formatters/builds.ts
|
|
1278
1295
|
import chalk12 from "chalk";
|
|
1279
1296
|
var HEADERS = ["ID", "PLATFORM", "STATUS", "CREATED", "COST", "APP"];
|
|
1280
|
-
|
|
1281
|
-
|
|
1297
|
+
var UNBILLED_STATUSES = /* @__PURE__ */ new Set(["queued", "running"]);
|
|
1298
|
+
function formatCostCell(costMicro, status) {
|
|
1299
|
+
if (costMicro <= 0 && UNBILLED_STATUSES.has(status)) return "-";
|
|
1300
|
+
return `$${(Math.max(costMicro, 0) / 1e6).toFixed(2)}`;
|
|
1282
1301
|
}
|
|
1283
1302
|
var STATUS_COLOR = {
|
|
1284
1303
|
succeeded: chalk12.green,
|
|
@@ -1297,8 +1316,8 @@ function formatBuildsHuman(builds2) {
|
|
|
1297
1316
|
b.id,
|
|
1298
1317
|
b.platform,
|
|
1299
1318
|
b.status,
|
|
1300
|
-
b.created_at
|
|
1301
|
-
formatCostCell(b.cost_micro),
|
|
1319
|
+
formatUtcTimestamp(b.created_at),
|
|
1320
|
+
formatCostCell(b.cost_micro, b.status),
|
|
1302
1321
|
b.app_public_id ?? ""
|
|
1303
1322
|
]);
|
|
1304
1323
|
const widths = HEADERS.map((h, i) => Math.max(h.length, ...rows.map((r) => r[i].length)));
|
|
@@ -1349,7 +1368,7 @@ async function buildsList(opts, deps) {
|
|
|
1349
1368
|
process.exitCode = 0;
|
|
1350
1369
|
} catch (err) {
|
|
1351
1370
|
printError(opts, err);
|
|
1352
|
-
process.exitCode =
|
|
1371
|
+
process.exitCode = errorExitCode(err);
|
|
1353
1372
|
}
|
|
1354
1373
|
}
|
|
1355
1374
|
async function buildsLogs(id, opts, deps) {
|
|
@@ -1372,7 +1391,7 @@ async function buildsLogs(id, opts, deps) {
|
|
|
1372
1391
|
process.exitCode = final.status === "succeeded" ? 0 : 1;
|
|
1373
1392
|
} catch (err) {
|
|
1374
1393
|
printError(opts, err);
|
|
1375
|
-
process.exitCode =
|
|
1394
|
+
process.exitCode = errorExitCode(err);
|
|
1376
1395
|
}
|
|
1377
1396
|
}
|
|
1378
1397
|
var MAX_CONSECUTIVE_POLL_FAILURES = 5;
|
|
@@ -1465,7 +1484,7 @@ async function buildsDownload(id, opts, deps) {
|
|
|
1465
1484
|
process.exitCode = 0;
|
|
1466
1485
|
} catch (err) {
|
|
1467
1486
|
printError(opts, err);
|
|
1468
|
-
process.exitCode =
|
|
1487
|
+
process.exitCode = errorExitCode(err);
|
|
1469
1488
|
}
|
|
1470
1489
|
}
|
|
1471
1490
|
async function buildsCancel(id, opts, deps) {
|
|
@@ -1482,7 +1501,7 @@ async function buildsCancel(id, opts, deps) {
|
|
|
1482
1501
|
process.exitCode = 0;
|
|
1483
1502
|
} catch (err) {
|
|
1484
1503
|
printError(opts, err);
|
|
1485
|
-
process.exitCode =
|
|
1504
|
+
process.exitCode = errorExitCode(err);
|
|
1486
1505
|
}
|
|
1487
1506
|
}
|
|
1488
1507
|
async function buildsDeleteArtifact(id, opts, deps) {
|
|
@@ -1499,7 +1518,7 @@ async function buildsDeleteArtifact(id, opts, deps) {
|
|
|
1499
1518
|
process.exitCode = 0;
|
|
1500
1519
|
} catch (err) {
|
|
1501
1520
|
printError(opts, err);
|
|
1502
|
-
process.exitCode =
|
|
1521
|
+
process.exitCode = errorExitCode(err);
|
|
1503
1522
|
}
|
|
1504
1523
|
}
|
|
1505
1524
|
function printError(opts, err) {
|
|
@@ -1691,7 +1710,7 @@ async function submitCommand(opts, deps) {
|
|
|
1691
1710
|
process.exitCode = final.status === "succeeded" ? 0 : 1;
|
|
1692
1711
|
} catch (err) {
|
|
1693
1712
|
printError2(opts, err);
|
|
1694
|
-
process.exitCode =
|
|
1713
|
+
process.exitCode = errorExitCode(err);
|
|
1695
1714
|
}
|
|
1696
1715
|
}
|
|
1697
1716
|
async function checkStore(platform, androidFamily, ascKey2, opts, deps) {
|
|
@@ -1722,7 +1741,7 @@ async function checkStore(platform, androidFamily, ascKey2, opts, deps) {
|
|
|
1722
1741
|
process.exitCode = result.ready ? 0 : 1;
|
|
1723
1742
|
} catch (err) {
|
|
1724
1743
|
printError2(opts, err);
|
|
1725
|
-
process.exitCode =
|
|
1744
|
+
process.exitCode = errorExitCode(err);
|
|
1726
1745
|
}
|
|
1727
1746
|
}
|
|
1728
1747
|
async function resolveLatestBuild(platform, deps) {
|
|
@@ -1852,7 +1871,7 @@ async function versionsList(opts, deps) {
|
|
|
1852
1871
|
process.exitCode = 0;
|
|
1853
1872
|
} catch (err) {
|
|
1854
1873
|
printError3(opts, err);
|
|
1855
|
-
process.exitCode =
|
|
1874
|
+
process.exitCode = errorExitCode(err);
|
|
1856
1875
|
}
|
|
1857
1876
|
}
|
|
1858
1877
|
async function versionsSet(buildNumber, opts, deps) {
|
|
@@ -1885,7 +1904,7 @@ async function versionsSet(buildNumber, opts, deps) {
|
|
|
1885
1904
|
process.exitCode = 0;
|
|
1886
1905
|
} catch (err) {
|
|
1887
1906
|
printError3(opts, err);
|
|
1888
|
-
process.exitCode =
|
|
1907
|
+
process.exitCode = errorExitCode(err);
|
|
1889
1908
|
}
|
|
1890
1909
|
}
|
|
1891
1910
|
var HEADERS2 = ["PLATFORM", "BUILD NUMBER", "UPDATED"];
|
|
@@ -1961,7 +1980,7 @@ Create an admin API token in the dashboard and use ${chalk16.bold("--token")} or
|
|
|
1961
1980
|
console.log(JSON.stringify({ event: "error", message }));
|
|
1962
1981
|
}
|
|
1963
1982
|
console.error(chalk16.red(`error: ${message}`));
|
|
1964
|
-
process.exitCode =
|
|
1983
|
+
process.exitCode = errorExitCode(err);
|
|
1965
1984
|
}
|
|
1966
1985
|
}
|
|
1967
1986
|
|
|
@@ -2039,7 +2058,7 @@ async function envList(opts, deps) {
|
|
|
2039
2058
|
process.exitCode = 0;
|
|
2040
2059
|
} catch (err) {
|
|
2041
2060
|
printError4(opts, err);
|
|
2042
|
-
process.exitCode =
|
|
2061
|
+
process.exitCode = errorExitCode(err);
|
|
2043
2062
|
}
|
|
2044
2063
|
}
|
|
2045
2064
|
function formatEnvVarsHuman(variables) {
|
|
@@ -2088,7 +2107,7 @@ async function envSet(name, value, opts, deps) {
|
|
|
2088
2107
|
process.exitCode = 0;
|
|
2089
2108
|
} catch (err) {
|
|
2090
2109
|
printError4(opts, err);
|
|
2091
|
-
process.exitCode =
|
|
2110
|
+
process.exitCode = errorExitCode(err);
|
|
2092
2111
|
}
|
|
2093
2112
|
}
|
|
2094
2113
|
function resolveVisibility(opts) {
|
|
@@ -2121,7 +2140,7 @@ async function envRm(name, opts, deps) {
|
|
|
2121
2140
|
process.exitCode = 0;
|
|
2122
2141
|
} catch (err) {
|
|
2123
2142
|
printError4(opts, err);
|
|
2124
|
-
process.exitCode =
|
|
2143
|
+
process.exitCode = errorExitCode(err);
|
|
2125
2144
|
}
|
|
2126
2145
|
}
|
|
2127
2146
|
async function envPull(opts, deps) {
|
|
@@ -2153,7 +2172,7 @@ async function envPull(opts, deps) {
|
|
|
2153
2172
|
process.exitCode = 0;
|
|
2154
2173
|
} catch (err) {
|
|
2155
2174
|
printError4(opts, err);
|
|
2156
|
-
process.exitCode =
|
|
2175
|
+
process.exitCode = errorExitCode(err);
|
|
2157
2176
|
}
|
|
2158
2177
|
}
|
|
2159
2178
|
function isLossyEnvValue(value) {
|
|
@@ -2346,7 +2365,7 @@ async function credentialsAdd(opts, deps) {
|
|
|
2346
2365
|
process.exitCode = 0;
|
|
2347
2366
|
} catch (err) {
|
|
2348
2367
|
printError5(opts, err);
|
|
2349
|
-
process.exitCode =
|
|
2368
|
+
process.exitCode = errorExitCode(err);
|
|
2350
2369
|
}
|
|
2351
2370
|
}
|
|
2352
2371
|
async function credentialsGenerate(opts, deps) {
|
|
@@ -2420,7 +2439,7 @@ async function credentialsGenerate(opts, deps) {
|
|
|
2420
2439
|
process.exitCode = 0;
|
|
2421
2440
|
} catch (err) {
|
|
2422
2441
|
printError5(opts, err);
|
|
2423
|
-
process.exitCode =
|
|
2442
|
+
process.exitCode = errorExitCode(err);
|
|
2424
2443
|
}
|
|
2425
2444
|
}
|
|
2426
2445
|
async function generateAppleCredential(platform, opts, d) {
|
|
@@ -2456,7 +2475,7 @@ async function generateAppleCredential(platform, opts, d) {
|
|
|
2456
2475
|
process.exitCode = 0;
|
|
2457
2476
|
} catch (err) {
|
|
2458
2477
|
printError5(opts, err);
|
|
2459
|
-
process.exitCode =
|
|
2478
|
+
process.exitCode = errorExitCode(err);
|
|
2460
2479
|
}
|
|
2461
2480
|
}
|
|
2462
2481
|
async function credentialsDownload(name, opts, deps) {
|
|
@@ -2531,7 +2550,7 @@ async function credentialsDownload(name, opts, deps) {
|
|
|
2531
2550
|
process.exitCode = 0;
|
|
2532
2551
|
} catch (err) {
|
|
2533
2552
|
printError5(opts, err);
|
|
2534
|
-
process.exitCode =
|
|
2553
|
+
process.exitCode = errorExitCode(err);
|
|
2535
2554
|
}
|
|
2536
2555
|
}
|
|
2537
2556
|
async function ascKeyAdd(opts, deps) {
|
|
@@ -2571,7 +2590,7 @@ async function ascKeyAdd(opts, deps) {
|
|
|
2571
2590
|
process.exitCode = 0;
|
|
2572
2591
|
} catch (err) {
|
|
2573
2592
|
printError5(opts, err);
|
|
2574
|
-
process.exitCode =
|
|
2593
|
+
process.exitCode = errorExitCode(err);
|
|
2575
2594
|
}
|
|
2576
2595
|
}
|
|
2577
2596
|
async function ascKeyList(opts, deps) {
|
|
@@ -2586,7 +2605,7 @@ async function ascKeyList(opts, deps) {
|
|
|
2586
2605
|
process.exitCode = 0;
|
|
2587
2606
|
} catch (err) {
|
|
2588
2607
|
printError5(opts, err);
|
|
2589
|
-
process.exitCode =
|
|
2608
|
+
process.exitCode = errorExitCode(err);
|
|
2590
2609
|
}
|
|
2591
2610
|
}
|
|
2592
2611
|
function formatAscKeysHuman(keys) {
|
|
@@ -2594,7 +2613,7 @@ function formatAscKeysHuman(keys) {
|
|
|
2594
2613
|
return "No App Store Connect keys found.\n";
|
|
2595
2614
|
}
|
|
2596
2615
|
const HEADERS3 = ["NAME", "KEY ID", "ISSUER ID", "CREATED"];
|
|
2597
|
-
const rows = keys.map((k) => [k.name, k.key_id, k.issuer_id, k.created_at
|
|
2616
|
+
const rows = keys.map((k) => [k.name, k.key_id, k.issuer_id, formatUtcTimestamp(k.created_at)]);
|
|
2598
2617
|
const widths = HEADERS3.map((h, i) => Math.max(h.length, ...rows.map((r) => r[i].length)));
|
|
2599
2618
|
const padCells = (cells) => cells.map((c, i) => c.padEnd(widths[i]));
|
|
2600
2619
|
const join3 = (cells) => cells.join(" ").trimEnd();
|
|
@@ -2614,7 +2633,7 @@ async function ascKeyRm(name, opts, deps) {
|
|
|
2614
2633
|
process.exitCode = 0;
|
|
2615
2634
|
} catch (err) {
|
|
2616
2635
|
printError5(opts, err);
|
|
2617
|
-
process.exitCode =
|
|
2636
|
+
process.exitCode = errorExitCode(err);
|
|
2618
2637
|
}
|
|
2619
2638
|
}
|
|
2620
2639
|
async function playKeyAdd(opts, deps) {
|
|
@@ -2647,7 +2666,7 @@ async function playKeyAdd(opts, deps) {
|
|
|
2647
2666
|
process.exitCode = 0;
|
|
2648
2667
|
} catch (err) {
|
|
2649
2668
|
printError5(opts, err);
|
|
2650
|
-
process.exitCode =
|
|
2669
|
+
process.exitCode = errorExitCode(err);
|
|
2651
2670
|
}
|
|
2652
2671
|
}
|
|
2653
2672
|
async function playKeyList(opts, deps) {
|
|
@@ -2662,7 +2681,7 @@ async function playKeyList(opts, deps) {
|
|
|
2662
2681
|
process.exitCode = 0;
|
|
2663
2682
|
} catch (err) {
|
|
2664
2683
|
printError5(opts, err);
|
|
2665
|
-
process.exitCode =
|
|
2684
|
+
process.exitCode = errorExitCode(err);
|
|
2666
2685
|
}
|
|
2667
2686
|
}
|
|
2668
2687
|
function formatPlayKeysHuman(keys) {
|
|
@@ -2670,7 +2689,7 @@ function formatPlayKeysHuman(keys) {
|
|
|
2670
2689
|
return "No Google Play keys found.\n";
|
|
2671
2690
|
}
|
|
2672
2691
|
const HEADERS3 = ["NAME", "CLIENT EMAIL", "CREATED"];
|
|
2673
|
-
const rows = keys.map((k) => [k.name, k.client_email, k.created_at
|
|
2692
|
+
const rows = keys.map((k) => [k.name, k.client_email, formatUtcTimestamp(k.created_at)]);
|
|
2674
2693
|
const widths = HEADERS3.map((h, i) => Math.max(h.length, ...rows.map((r) => r[i].length)));
|
|
2675
2694
|
const padCells = (cells) => cells.map((c, i) => c.padEnd(widths[i]));
|
|
2676
2695
|
const join3 = (cells) => cells.join(" ").trimEnd();
|
|
@@ -2690,7 +2709,7 @@ async function playKeyRm(name, opts, deps) {
|
|
|
2690
2709
|
process.exitCode = 0;
|
|
2691
2710
|
} catch (err) {
|
|
2692
2711
|
printError5(opts, err);
|
|
2693
|
-
process.exitCode =
|
|
2712
|
+
process.exitCode = errorExitCode(err);
|
|
2694
2713
|
}
|
|
2695
2714
|
}
|
|
2696
2715
|
async function credentialsList(opts, deps) {
|
|
@@ -2711,7 +2730,7 @@ async function credentialsList(opts, deps) {
|
|
|
2711
2730
|
process.exitCode = 0;
|
|
2712
2731
|
} catch (err) {
|
|
2713
2732
|
printError5(opts, err);
|
|
2714
|
-
process.exitCode =
|
|
2733
|
+
process.exitCode = errorExitCode(err);
|
|
2715
2734
|
}
|
|
2716
2735
|
}
|
|
2717
2736
|
function formatIdentity(c) {
|
|
@@ -2730,10 +2749,10 @@ function earliestExpiry(c) {
|
|
|
2730
2749
|
function formatExpires(c) {
|
|
2731
2750
|
const parts = [];
|
|
2732
2751
|
if (c.profile_expires_at) {
|
|
2733
|
-
if (c.expires_at) parts.push(`cert ${c.expires_at}`);
|
|
2734
|
-
parts.push(`profile ${c.profile_expires_at}`);
|
|
2752
|
+
if (c.expires_at) parts.push(`cert ${formatUtcTimestamp(c.expires_at)}`);
|
|
2753
|
+
parts.push(`profile ${formatUtcTimestamp(c.profile_expires_at)}`);
|
|
2735
2754
|
} else if (c.expires_at) {
|
|
2736
|
-
parts.push(c.expires_at);
|
|
2755
|
+
parts.push(formatUtcTimestamp(c.expires_at));
|
|
2737
2756
|
}
|
|
2738
2757
|
if (parts.length === 0) return "";
|
|
2739
2758
|
const cell = parts.join(" \xB7 ");
|
|
@@ -2770,7 +2789,7 @@ async function credentialsRm(name, opts, deps) {
|
|
|
2770
2789
|
process.exitCode = 0;
|
|
2771
2790
|
} catch (err) {
|
|
2772
2791
|
printError5(opts, err);
|
|
2773
|
-
process.exitCode =
|
|
2792
|
+
process.exitCode = errorExitCode(err);
|
|
2774
2793
|
}
|
|
2775
2794
|
}
|
|
2776
2795
|
function printKeystoreWriteFailure(opts, err, result) {
|
|
@@ -2848,14 +2867,14 @@ async function webhooksAdd(opts, deps) {
|
|
|
2848
2867
|
process.exitCode = 0;
|
|
2849
2868
|
} catch (err) {
|
|
2850
2869
|
printError6(opts, err);
|
|
2851
|
-
process.exitCode =
|
|
2870
|
+
process.exitCode = errorExitCode(err);
|
|
2852
2871
|
}
|
|
2853
2872
|
}
|
|
2854
2873
|
function formatLastDelivery(ld) {
|
|
2855
2874
|
if (!ld) return "\u2014";
|
|
2856
2875
|
if (ld.status === "pending") return "pending";
|
|
2857
2876
|
const code = ld.response_code != null ? ` (${ld.response_code})` : "";
|
|
2858
|
-
const at = ld.at != null ? ` ${ld.at}` : "";
|
|
2877
|
+
const at = ld.at != null ? ` ${formatUtcTimestamp(ld.at)}` : "";
|
|
2859
2878
|
return `${ld.status}${code}${at}`;
|
|
2860
2879
|
}
|
|
2861
2880
|
function formatWebhooksHuman(webhooks2) {
|
|
@@ -2868,7 +2887,7 @@ function formatWebhooksHuman(webhooks2) {
|
|
|
2868
2887
|
w.url,
|
|
2869
2888
|
w.active ? "yes" : "no",
|
|
2870
2889
|
formatLastDelivery(w.last_delivery),
|
|
2871
|
-
w.created_at
|
|
2890
|
+
formatUtcTimestamp(w.created_at)
|
|
2872
2891
|
]);
|
|
2873
2892
|
const widths = HEADERS3.map((h, i) => Math.max(h.length, ...rows.map((r) => r[i].length)));
|
|
2874
2893
|
const padCells = (cells) => cells.map((c, i) => c.padEnd(widths[i]));
|
|
@@ -2889,7 +2908,7 @@ async function webhooksList(opts, deps) {
|
|
|
2889
2908
|
process.exitCode = 0;
|
|
2890
2909
|
} catch (err) {
|
|
2891
2910
|
printError6(opts, err);
|
|
2892
|
-
process.exitCode =
|
|
2911
|
+
process.exitCode = errorExitCode(err);
|
|
2893
2912
|
}
|
|
2894
2913
|
}
|
|
2895
2914
|
async function webhooksRm(id, opts, deps) {
|
|
@@ -2904,7 +2923,7 @@ async function webhooksRm(id, opts, deps) {
|
|
|
2904
2923
|
process.exitCode = 0;
|
|
2905
2924
|
} catch (err) {
|
|
2906
2925
|
printError6(opts, err);
|
|
2907
|
-
process.exitCode =
|
|
2926
|
+
process.exitCode = errorExitCode(err);
|
|
2908
2927
|
}
|
|
2909
2928
|
}
|
|
2910
2929
|
function parseUtcTimestamp(iso) {
|
|
@@ -2938,7 +2957,7 @@ async function webhooksTest(id, opts, deps) {
|
|
|
2938
2957
|
} else {
|
|
2939
2958
|
if (!opts.json) {
|
|
2940
2959
|
const code = ld.response_code != null ? `HTTP ${ld.response_code}` : "no response";
|
|
2941
|
-
console.error(chalk19.red(`\u2717 Failed (${code}) at ${ld.at}`));
|
|
2960
|
+
console.error(chalk19.red(`\u2717 Failed (${code}) at ${formatUtcTimestamp(ld.at)}`));
|
|
2942
2961
|
}
|
|
2943
2962
|
process.exitCode = 1;
|
|
2944
2963
|
}
|
|
@@ -2954,7 +2973,7 @@ async function webhooksTest(id, opts, deps) {
|
|
|
2954
2973
|
process.exitCode = 1;
|
|
2955
2974
|
} catch (err) {
|
|
2956
2975
|
printError6(opts, err);
|
|
2957
|
-
process.exitCode =
|
|
2976
|
+
process.exitCode = errorExitCode(err);
|
|
2958
2977
|
}
|
|
2959
2978
|
}
|
|
2960
2979
|
function printError6(opts, err) {
|
|
@@ -2977,8 +2996,7 @@ async function listDevicesCommand(options) {
|
|
|
2977
2996
|
}
|
|
2978
2997
|
process.exit(EXIT_PASS);
|
|
2979
2998
|
} catch (err) {
|
|
2980
|
-
|
|
2981
|
-
`);
|
|
2999
|
+
reportCommandError(options.output === "json", err);
|
|
2982
3000
|
process.exit(EXIT_INFRA_ERROR);
|
|
2983
3001
|
}
|
|
2984
3002
|
return;
|
|
@@ -2996,8 +3014,7 @@ async function listDevicesCommand(options) {
|
|
|
2996
3014
|
}
|
|
2997
3015
|
process.exit(EXIT_PASS);
|
|
2998
3016
|
} catch (err) {
|
|
2999
|
-
|
|
3000
|
-
`);
|
|
3017
|
+
reportCommandError(options.output === "json", err);
|
|
3001
3018
|
process.exit(EXIT_INFRA_ERROR);
|
|
3002
3019
|
}
|
|
3003
3020
|
}
|
|
@@ -3270,7 +3287,11 @@ program.command("list-apps").description("List apps in your organization").optio
|
|
|
3270
3287
|
program.command("list-builds <app>").description(
|
|
3271
3288
|
"List an app's uploaded builds, newest first: id, version, platform, debug/release, upload time and note (the ids `dev --build <id>` and `run-test --build` take)"
|
|
3272
3289
|
).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--json", "Print the builds as a JSON array", false).action((app, opts) => listBuilds(app, opts));
|
|
3273
|
-
program.command("list-devices").description("List devices registered with the platform (filterable by type and category)").option("--token <token>", "API token").option("--output <format>", "Output format: human, json", "human").
|
|
3290
|
+
program.command("list-devices").description("List devices registered with the platform (filterable by type and category)").option("--token <token>", "API token").option("--output <format>", "Output format: human, json", "human").addOption(
|
|
3291
|
+
new Option("--type <type>", "Filter by device type").choices(["ios", "android", "roku"])
|
|
3292
|
+
).addOption(
|
|
3293
|
+
new Option("--category <category>", "Filter by category").choices(["phone", "tablet", "tv"])
|
|
3294
|
+
).addOption(new Option("--status <status>", "Filter by status").choices(["available", "busy"])).option(
|
|
3274
3295
|
"--models",
|
|
3275
3296
|
"List the device models you can start instead (the names `dev --model` takes)",
|
|
3276
3297
|
false
|
|
@@ -3292,7 +3313,7 @@ program.command("dev").description(
|
|
|
3292
3313
|
parseDeviceCategory
|
|
3293
3314
|
).option(
|
|
3294
3315
|
"--model <name>",
|
|
3295
|
-
'Run on this exact device model, e.g. "iPhone Duo" (see `vibeview list-devices --models`)'
|
|
3316
|
+
'Run on this exact device model, e.g. "iPhone Duo" or "Pixel 9 Pro Fold" (see `vibeview list-devices --models`)'
|
|
3296
3317
|
).option("--no-open", "Do not open the browser automatically").option("--debug", "Log raw tunnel lifecycle events (close codes, reconnects) for diagnostics").option("--json", "Emit line-delimited JSON events on stdout instead of human output", false).option(
|
|
3297
3318
|
"--detach",
|
|
3298
3319
|
"Run the dev session in the background; prints session info and exits (see `dev-status`, `dev-stop`, and `dev-reload` for Roku)",
|
|
@@ -3444,8 +3465,8 @@ program.command("dev-reload").description(
|
|
|
3444
3465
|
program.command("mcp").description(
|
|
3445
3466
|
"Run an MCP stdio server exposing the agent verbs (tap, swipe, type, ...) plus dev_start/dev_stop/dev_reload as tools"
|
|
3446
3467
|
).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").action(async (opts) => {
|
|
3447
|
-
const { runMcpServer } = await import("./server-
|
|
3448
|
-
await runMcpServer(opts);
|
|
3468
|
+
const { runMcpServer } = await import("./server-XJREB7KU.js");
|
|
3469
|
+
await runMcpServer({ ...opts, version: pkg.version });
|
|
3449
3470
|
});
|
|
3450
3471
|
program.command("agent-setup").description(
|
|
3451
3472
|
"Make VibeView discoverable to your coding agent: install the vibeview-agent skill (and optionally register the MCP server with Claude Code)"
|
|
@@ -3455,6 +3476,8 @@ for (const cmd of AGENT_COMMANDS) {
|
|
|
3455
3476
|
const flagParams = cmd.params.filter((p) => p.cli !== "positional");
|
|
3456
3477
|
const argSignature = positionalParams.map((p) => p.required ? `<${p.name}>` : `[${p.name}]`).join(" ");
|
|
3457
3478
|
let command = program.command(argSignature ? `${cmd.verb} ${argSignature}` : cmd.verb).description(cmd.summary);
|
|
3479
|
+
if (cmd.verb === "press") command.addHelpText("after", `
|
|
3480
|
+
${pressButtonsHelp()}`);
|
|
3458
3481
|
for (const param of flagParams) {
|
|
3459
3482
|
const flagArg = param.type === "number" ? `${param.cli} <n>` : `${param.cli} <value>`;
|
|
3460
3483
|
command = command.option(flagArg, param.description);
|
|
@@ -17,14 +17,15 @@ import {
|
|
|
17
17
|
isDevPlatform,
|
|
18
18
|
loadDevConfig,
|
|
19
19
|
parseBuildId,
|
|
20
|
+
platformWithArticle,
|
|
20
21
|
readDevState,
|
|
21
22
|
renderEnvelope,
|
|
22
23
|
startDevSession
|
|
23
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-46X7UN6Y.js";
|
|
24
25
|
import {
|
|
25
26
|
ApiClient,
|
|
26
27
|
resolveAuth
|
|
27
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-U7FCGMWG.js";
|
|
28
29
|
|
|
29
30
|
// src/mcp/server.ts
|
|
30
31
|
import { writeFileSync } from "fs";
|
|
@@ -87,7 +88,7 @@ var DEV_START_DEF = {
|
|
|
87
88
|
},
|
|
88
89
|
model: {
|
|
89
90
|
type: "string",
|
|
90
|
-
description: 'Run on this exact device model, e.g. "iPhone Duo" for
|
|
91
|
+
description: 'Run on this exact device model, e.g. "iPhone Duo" or "Pixel 9 Pro Fold" for a foldable (any model list_device_models marks form_factor "foldable"). Names come from list_device_models. Omit for a default phone (or TV on TV platforms).'
|
|
91
92
|
},
|
|
92
93
|
build_id: {
|
|
93
94
|
type: "number",
|
|
@@ -116,7 +117,7 @@ var STOP_SESSION_DEF = {
|
|
|
116
117
|
};
|
|
117
118
|
var LIST_DEVICE_MODELS_DEF = {
|
|
118
119
|
name: "list_device_models",
|
|
119
|
-
description: 'List the device models you can start right now (model, OS version, platform, category, and form_factor "foldable" for
|
|
120
|
+
description: 'List the device models you can start right now (model, OS version, platform, category, and form_factor "foldable" for any device with a hinge \u2014 the iPhone Duo, Android foldables such as the Pixel 9 Pro Fold). Pass a model name to dev_start to run on it.',
|
|
120
121
|
mutating: false,
|
|
121
122
|
properties: {
|
|
122
123
|
device_type: {
|
|
@@ -376,7 +377,7 @@ async function handleUploadApp(args, deps) {
|
|
|
376
377
|
}
|
|
377
378
|
const name = typeof args.name === "string" && args.name ? args.name : void 0;
|
|
378
379
|
const upload = deps.uploadApp ?? (async (f, n) => {
|
|
379
|
-
const { uploadAppBuild } = await import("./upload-app-
|
|
380
|
+
const { uploadAppBuild } = await import("./upload-app-QUUXKNR2.js");
|
|
380
381
|
const { result: result2 } = await uploadAppBuild(f, { ...deps.auth, name: n });
|
|
381
382
|
return result2;
|
|
382
383
|
});
|
|
@@ -535,7 +536,7 @@ function createDevSessionController(auth, webUrl) {
|
|
|
535
536
|
}
|
|
536
537
|
if (target.platform !== "roku") {
|
|
537
538
|
throw new Error(
|
|
538
|
-
`dev_reload is for Roku channels;
|
|
539
|
+
`dev_reload is for Roku channels; ${platformWithArticle(target.platform)} session hot-reloads through Metro on its own`
|
|
539
540
|
);
|
|
540
541
|
}
|
|
541
542
|
if (!target.build) {
|
|
@@ -577,7 +578,7 @@ async function createMcpServer(opts) {
|
|
|
577
578
|
agentTool: client.agentTool.bind(client),
|
|
578
579
|
devSession
|
|
579
580
|
};
|
|
580
|
-
const server = new McpServer({ name: "vibeview", version: "
|
|
581
|
+
const server = new McpServer({ name: "vibeview", version: opts.version ?? "0.0.0" });
|
|
581
582
|
function zodShape(def) {
|
|
582
583
|
const shape = {};
|
|
583
584
|
for (const [key, prop] of Object.entries(def.properties)) {
|