vibeview 0.32.0 → 0.34.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-ZZK7YQSP.js → chunk-4D2E2PE4.js} +13 -3
- package/dist/{chunk-T6H5XTBX.js → chunk-TPZG7NCU.js} +352 -21
- package/dist/cli.js +85 -20
- package/dist/{server-FJSBWEHZ.js → server-RDGEVJD4.js} +314 -76
- package/dist/{upload-app-2LVG4LMB.js → upload-app-AKD73742.js} +1 -1
- package/package.json +1 -1
- package/skills/vibeview-agent/SKILL.md +34 -12
package/dist/cli.js
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
readDevStateFile,
|
|
25
25
|
readMetroState,
|
|
26
26
|
runAgentVerb
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-TPZG7NCU.js";
|
|
28
28
|
import {
|
|
29
29
|
ApiClient,
|
|
30
30
|
ApiStatusError,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
resolveAuth,
|
|
46
46
|
saveConfig,
|
|
47
47
|
uploadApp
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-4D2E2PE4.js";
|
|
49
49
|
|
|
50
50
|
// src/cli.ts
|
|
51
51
|
import { createRequire } from "module";
|
|
@@ -60,10 +60,25 @@ import chalk2 from "chalk";
|
|
|
60
60
|
// src/lib/formatters/human.ts
|
|
61
61
|
import chalk from "chalk";
|
|
62
62
|
|
|
63
|
+
// src/lib/formatters/not-checked.ts
|
|
64
|
+
function notCheckedSteps(steps) {
|
|
65
|
+
return (steps ?? []).filter((s) => s.status === "not_checked");
|
|
66
|
+
}
|
|
67
|
+
function runStepsNotChecked(result) {
|
|
68
|
+
if (typeof result.steps_not_checked === "number") return result.steps_not_checked;
|
|
69
|
+
return notCheckedSteps(result.steps).length;
|
|
70
|
+
}
|
|
71
|
+
function stepsNotCheckedLabel(n) {
|
|
72
|
+
return `${n} step${n === 1 ? "" : "s"} not checked`;
|
|
73
|
+
}
|
|
74
|
+
function notCheckedSuffix(status, n) {
|
|
75
|
+
return status === "passed" && n && n > 0 ? ` (${stepsNotCheckedLabel(n)})` : "";
|
|
76
|
+
}
|
|
77
|
+
|
|
63
78
|
// src/lib/formatters/cases.ts
|
|
64
79
|
function resultCases(result) {
|
|
65
80
|
if (Array.isArray(result.test_runs)) return result.test_runs;
|
|
66
|
-
const failedStep = result.steps?.find((s) => s.status
|
|
81
|
+
const failedStep = result.steps?.find((s) => s.status === "failed" || s.status === "error");
|
|
67
82
|
return [
|
|
68
83
|
{
|
|
69
84
|
case_name: result.case_name || result.run_id,
|
|
@@ -73,7 +88,12 @@ function resultCases(result) {
|
|
|
73
88
|
error_kind: failedStep?.error_kind ?? null,
|
|
74
89
|
error_kind_description: failedStep?.error_kind_description ?? null,
|
|
75
90
|
screenshot_signed_url: failedStep?.screenshot_signed_url ?? null,
|
|
76
|
-
url: result.url
|
|
91
|
+
url: result.url,
|
|
92
|
+
steps_not_checked: runStepsNotChecked(result),
|
|
93
|
+
not_checked_steps: notCheckedSteps(result.steps).map((s) => ({
|
|
94
|
+
step: s.step,
|
|
95
|
+
note: s.note ?? null
|
|
96
|
+
}))
|
|
77
97
|
}
|
|
78
98
|
];
|
|
79
99
|
}
|
|
@@ -100,11 +120,16 @@ function formatHuman(result, verbose) {
|
|
|
100
120
|
const duration = result.duration_ms ? `${(result.duration_ms / 1e3).toFixed(1)}s` : "-";
|
|
101
121
|
lines.push("");
|
|
102
122
|
const title = result.suite_name || result.case_name || result.run_id;
|
|
103
|
-
lines.push(` ${icon} ${chalk.bold(title)} ${chalk.dim(duration)}`);
|
|
104
123
|
const cases = resultCases(result);
|
|
124
|
+
const notChecked = cases.reduce((n, t) => n + (t.steps_not_checked ?? 0), 0);
|
|
125
|
+
const runSuffix = notCheckedSuffix(result.status, notChecked);
|
|
126
|
+
lines.push(
|
|
127
|
+
` ${icon}${runSuffix ? chalk.yellow(runSuffix) : ""} ${chalk.bold(title)} ${chalk.dim(duration)}`
|
|
128
|
+
);
|
|
105
129
|
const passed = cases.filter((t) => t.status === "passed").length;
|
|
106
130
|
const total = cases.length;
|
|
107
|
-
|
|
131
|
+
const notCheckedNote = notChecked > 0 ? `, ${stepsNotCheckedLabel(notChecked)}` : "";
|
|
132
|
+
lines.push(` ${chalk.dim(`${passed}/${total} cases passed${notCheckedNote}`)}`);
|
|
108
133
|
if (result.url) {
|
|
109
134
|
lines.push(` ${chalk.dim(result.url)}`);
|
|
110
135
|
}
|
|
@@ -114,7 +139,10 @@ function formatHuman(result, verbose) {
|
|
|
114
139
|
for (const tr of suiteCases) {
|
|
115
140
|
const caseIcon = tr.status === "passed" ? chalk.green(" PASS") : tr.status === "cancelled" || tr.status === "pending" || tr.status === "running" ? chalk.yellow(" SKIP") : chalk.red(" FAIL");
|
|
116
141
|
const caseDuration = tr.duration_ms ? `${(tr.duration_ms / 1e3).toFixed(1)}s` : "-";
|
|
117
|
-
|
|
142
|
+
const caseSuffix = notCheckedSuffix(tr.status, tr.steps_not_checked);
|
|
143
|
+
lines.push(
|
|
144
|
+
` ${caseIcon}${caseSuffix ? chalk.yellow(caseSuffix) : ""} ${tr.case_name} ${chalk.dim(caseDuration)}`
|
|
145
|
+
);
|
|
118
146
|
if (tr.url) {
|
|
119
147
|
lines.push(` ${chalk.dim(tr.url)}`);
|
|
120
148
|
}
|
|
@@ -129,7 +157,7 @@ function formatHuman(result, verbose) {
|
|
|
129
157
|
lines.push(` ${chalk.bold(result.case_name)}`);
|
|
130
158
|
}
|
|
131
159
|
for (const step of result.steps) {
|
|
132
|
-
const stepIcon = step.status === "passed" ? chalk.green(" PASS") : chalk.red(" FAIL");
|
|
160
|
+
const stepIcon = step.status === "passed" ? chalk.green(" PASS") : step.status === "not_checked" ? chalk.yellow(" NOT CHECKED") : chalk.red(" FAIL");
|
|
133
161
|
const stepDuration = step.duration_ms ? `${(step.duration_ms / 1e3).toFixed(1)}s` : "-";
|
|
134
162
|
lines.push(` ${stepIcon} ${step.step} ${chalk.dim(stepDuration)}`);
|
|
135
163
|
if (verbose && step.actions && step.actions.length > 0) {
|
|
@@ -137,7 +165,9 @@ function formatHuman(result, verbose) {
|
|
|
137
165
|
lines.push(` ${chalk.dim(formatAction(action))}`);
|
|
138
166
|
}
|
|
139
167
|
}
|
|
140
|
-
if (step.status
|
|
168
|
+
if (step.status === "not_checked") {
|
|
169
|
+
if (step.note) lines.push(` ${chalk.dim(step.note)}`);
|
|
170
|
+
} else if (step.status !== "passed") {
|
|
141
171
|
lines.push(...failureLines(step));
|
|
142
172
|
}
|
|
143
173
|
}
|
|
@@ -156,13 +186,33 @@ function formatHuman(result, verbose) {
|
|
|
156
186
|
|
|
157
187
|
// src/lib/formatters/json.ts
|
|
158
188
|
function formatJson(result) {
|
|
159
|
-
|
|
189
|
+
const doc = Array.isArray(result.test_runs) ? result : { ...result, steps_not_checked: runStepsNotChecked(result) };
|
|
190
|
+
return JSON.stringify(doc, null, 2);
|
|
160
191
|
}
|
|
161
192
|
|
|
162
193
|
// src/lib/formatters/junit.ts
|
|
163
194
|
function escapeXml(s) {
|
|
164
195
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
165
196
|
}
|
|
197
|
+
function caseDetailLines(c) {
|
|
198
|
+
const n = c.status === "passed" ? c.steps_not_checked ?? 0 : 0;
|
|
199
|
+
const lines = [];
|
|
200
|
+
if (n > 0) {
|
|
201
|
+
lines.push(" <properties>");
|
|
202
|
+
lines.push(` <property name="steps_not_checked" value="${n}" />`);
|
|
203
|
+
lines.push(" </properties>");
|
|
204
|
+
}
|
|
205
|
+
const out = [];
|
|
206
|
+
if (c.url) out.push(c.url);
|
|
207
|
+
if (n > 0) {
|
|
208
|
+
out.push(`${stepsNotCheckedLabel(n)}:`);
|
|
209
|
+
for (const s of c.not_checked_steps ?? []) {
|
|
210
|
+
out.push(`- ${s.step}${s.note ? ` (${s.note})` : ""}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (out.length) lines.push(` <system-out>${escapeXml(out.join("\n"))}</system-out>`);
|
|
214
|
+
return lines;
|
|
215
|
+
}
|
|
166
216
|
function formatJunit(result) {
|
|
167
217
|
const suiteName = escapeXml(result.suite_name || result.case_name || result.run_id);
|
|
168
218
|
const cases = resultCases(result);
|
|
@@ -194,8 +244,8 @@ function formatJunit(result) {
|
|
|
194
244
|
for (const tr of cases) {
|
|
195
245
|
const caseName = escapeXml(tr.case_name);
|
|
196
246
|
const caseTime = tr.duration_ms ? (tr.duration_ms / 1e3).toFixed(1) : "0";
|
|
197
|
-
const
|
|
198
|
-
if (tr.status === "passed" &&
|
|
247
|
+
const detail = caseDetailLines(tr);
|
|
248
|
+
if (tr.status === "passed" && detail.length === 0) {
|
|
199
249
|
lines.push(` <testcase name="${caseName}" classname="${suiteName}" time="${caseTime}" />`);
|
|
200
250
|
continue;
|
|
201
251
|
}
|
|
@@ -207,7 +257,7 @@ function formatJunit(result) {
|
|
|
207
257
|
const msg = escapeXml(tr.error_message || "Infrastructure error");
|
|
208
258
|
lines.push(` <error message="${msg}" type="InfraError">${msg}</error>`);
|
|
209
259
|
}
|
|
210
|
-
|
|
260
|
+
lines.push(...detail);
|
|
211
261
|
lines.push(" </testcase>");
|
|
212
262
|
}
|
|
213
263
|
lines.push(" </testsuite>");
|
|
@@ -240,8 +290,12 @@ var MULTI_TERMINAL = /* @__PURE__ */ new Set(["passed", "failed", "error", "canc
|
|
|
240
290
|
function caseLines(c, classname) {
|
|
241
291
|
const name = escapeXml(c.name);
|
|
242
292
|
const head = ` <testcase name="${name}" classname="${classname}" time="${c.time}"`;
|
|
243
|
-
const
|
|
244
|
-
|
|
293
|
+
const detail = caseDetailLines({
|
|
294
|
+
status: c.verdict,
|
|
295
|
+
url: c.url,
|
|
296
|
+
steps_not_checked: c.steps_not_checked
|
|
297
|
+
});
|
|
298
|
+
if (c.verdict === "passed" && detail.length === 0) return [`${head} />`];
|
|
245
299
|
const lines = [`${head}>`];
|
|
246
300
|
const msg = escapeXml(c.message ?? "");
|
|
247
301
|
if (c.verdict === "failure") {
|
|
@@ -251,7 +305,7 @@ function caseLines(c, classname) {
|
|
|
251
305
|
} else if (c.verdict === "skipped") {
|
|
252
306
|
lines.push(` <skipped message="${msg}" />`);
|
|
253
307
|
}
|
|
254
|
-
|
|
308
|
+
lines.push(...detail);
|
|
255
309
|
lines.push(" </testcase>");
|
|
256
310
|
return lines;
|
|
257
311
|
}
|
|
@@ -263,7 +317,12 @@ function formatMultiSuiteJunit(result, opts = {}) {
|
|
|
263
317
|
const cases = (sr.case_runs ?? []).map((c) => {
|
|
264
318
|
const name = c.case_name || c.run_id;
|
|
265
319
|
const time = c.duration_ms ? (c.duration_ms / 1e3).toFixed(1) : "0";
|
|
266
|
-
const base = {
|
|
320
|
+
const base = {
|
|
321
|
+
name,
|
|
322
|
+
time,
|
|
323
|
+
url: c.url || void 0,
|
|
324
|
+
steps_not_checked: c.steps_not_checked
|
|
325
|
+
};
|
|
267
326
|
switch (c.status) {
|
|
268
327
|
case "passed":
|
|
269
328
|
return { ...base, verdict: "passed" };
|
|
@@ -1039,8 +1098,13 @@ ${chalk5.dim("Matched:")} ${totalMatched} suite(s)${matchedNames.length ? " \u20
|
|
|
1039
1098
|
} else if (opts.output === "junit") {
|
|
1040
1099
|
process.stdout.write(formatMultiSuiteJunit(last) + "\n");
|
|
1041
1100
|
} else {
|
|
1101
|
+
const totalNotChecked = last.suite_runs.reduce(
|
|
1102
|
+
(n, sr) => n + (sr.case_runs ?? []).reduce((m, cr) => m + (cr.steps_not_checked ?? 0), 0),
|
|
1103
|
+
0
|
|
1104
|
+
);
|
|
1105
|
+
const aggregateNote = totalNotChecked > 0 ? chalk5.yellow(` (${stepsNotCheckedLabel(totalNotChecked)})`) : "";
|
|
1042
1106
|
process.stdout.write(`
|
|
1043
|
-
Aggregate: ${last.status}
|
|
1107
|
+
Aggregate: ${last.status}${aggregateNote}
|
|
1044
1108
|
`);
|
|
1045
1109
|
for (const sr of last.suite_runs) {
|
|
1046
1110
|
const mark = sr.status === "passed" ? chalk5.green("\u2713") : chalk5.red("\u2717");
|
|
@@ -1056,8 +1120,9 @@ Aggregate: ${last.status}
|
|
|
1056
1120
|
for (const cr of sr.case_runs ?? []) {
|
|
1057
1121
|
const caseMark = cr.status === "passed" ? chalk5.green("\u2713") : cr.status === "cancelled" || cr.status === "pending" || cr.status === "running" ? chalk5.yellow("-") : chalk5.red("\u2717");
|
|
1058
1122
|
const dur = cr.duration_ms ? chalk5.dim(` (${(cr.duration_ms / 1e3).toFixed(1)}s)`) : "";
|
|
1123
|
+
const unchecked = notCheckedSuffix(cr.status, cr.steps_not_checked);
|
|
1059
1124
|
process.stdout.write(
|
|
1060
|
-
` ${caseMark} ${cr.case_name ?? "Case"} ${cr.status ?? "?"}${dur} ${chalk5.dim(cr.url)}
|
|
1125
|
+
` ${caseMark} ${cr.case_name ?? "Case"} ${cr.status ?? "?"}${unchecked ? chalk5.yellow(unchecked) : ""}${dur} ${chalk5.dim(cr.url)}
|
|
1061
1126
|
`
|
|
1062
1127
|
);
|
|
1063
1128
|
if (cr.error_message && cr.status !== "passed") {
|
|
@@ -4079,7 +4144,7 @@ program.command("dev-reload").description(
|
|
|
4079
4144
|
program.command("mcp").description(
|
|
4080
4145
|
"Run an MCP stdio server exposing the agent verbs (tap, swipe, type, ...) plus dev_start/dev_stop/dev_reload as tools"
|
|
4081
4146
|
).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").action(async (opts) => {
|
|
4082
|
-
const { runMcpServer } = await import("./server-
|
|
4147
|
+
const { runMcpServer } = await import("./server-RDGEVJD4.js");
|
|
4083
4148
|
await runMcpServer({ ...opts, version: pkg.version });
|
|
4084
4149
|
});
|
|
4085
4150
|
program.command("agent-setup").description(
|