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/cli.js CHANGED
@@ -24,7 +24,7 @@ import {
24
24
  readDevStateFile,
25
25
  readMetroState,
26
26
  runAgentVerb
27
- } from "./chunk-T6H5XTBX.js";
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-ZZK7YQSP.js";
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 !== "passed");
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
- lines.push(` ${chalk.dim(`${passed}/${total} cases passed`)}`);
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
- lines.push(` ${caseIcon} ${tr.case_name} ${chalk.dim(caseDuration)}`);
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 !== "passed") {
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
- return JSON.stringify(result, null, 2);
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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
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 out = tr.url ? ` <system-out>${escapeXml(tr.url)}</system-out>` : null;
198
- if (tr.status === "passed" && !out) {
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
- if (out) lines.push(out);
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 out = c.url ? ` <system-out>${escapeXml(c.url)}</system-out>` : null;
244
- if (c.verdict === "passed" && !out) return [`${head} />`];
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
- if (out) lines.push(out);
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 = { name, time, url: c.url || void 0 };
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-FJSBWEHZ.js");
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(