vibeview 0.37.1 → 0.38.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 +6 -5
- package/dist/{chunk-NJ2IXB5H.js → chunk-AV674D7T.js} +3 -3
- package/dist/{chunk-QRJAFBH3.js → chunk-MYXUGCR5.js} +41 -5
- package/dist/cli.js +385 -183
- package/dist/{server-DF3CDWL4.js → server-FMU3HQWF.js} +193 -4
- package/dist/{upload-app-BPTGBDQB.js → upload-app-UHJLFQKZ.js} +1 -1
- package/package.json +2 -1
- package/skills/vibeview-agent/SKILL.md +6 -2
package/README.md
CHANGED
|
@@ -141,11 +141,11 @@ Other MCP clients (Cursor, Claude Desktop, VS Code Copilot) run command
|
|
|
141
141
|
# Upload the build under test (zipped simulator .app for iOS, .apk for Android)
|
|
142
142
|
vibeview upload-app ./MyApp.zip
|
|
143
143
|
|
|
144
|
-
# Run a single test or a whole
|
|
144
|
+
# Run a single test or a whole group
|
|
145
145
|
vibeview run-test <test-id> --output json
|
|
146
146
|
vibeview run-suite <suite-id> --output junit
|
|
147
147
|
|
|
148
|
-
# Run several
|
|
148
|
+
# Run several groups with an aggregated exit code
|
|
149
149
|
vibeview run-suites --tag smoke
|
|
150
150
|
```
|
|
151
151
|
|
|
@@ -181,11 +181,12 @@ Output formats: `human`, `json`, and `junit` for any CI system. The exit code re
|
|
|
181
181
|
| `vibeview list-apps` | List your apps |
|
|
182
182
|
| `vibeview list-builds <app>` | List an app's uploaded builds (ids for `dev --build <id>`, `run-test --build`) |
|
|
183
183
|
| `vibeview list-devices` | List available device types |
|
|
184
|
-
| `vibeview list-suites` | List
|
|
184
|
+
| `vibeview list-suites` | List groups (the CLI calls them suites) |
|
|
185
185
|
| `vibeview create-test [name]` | Create a test case |
|
|
186
|
+
| `vibeview import-maestro <path>` | Import Maestro flows (file, `.zip` or folder) as tests; `--dry-run` previews |
|
|
186
187
|
| `vibeview run-test <test-id>` | Run a single test |
|
|
187
|
-
| `vibeview run-suite <suite-id>` | Run a test
|
|
188
|
-
| `vibeview run-suites` | Run multiple
|
|
188
|
+
| `vibeview run-suite <suite-id>` | Run a test group |
|
|
189
|
+
| `vibeview run-suites` | Run multiple groups |
|
|
189
190
|
|
|
190
191
|
Run any command with `--help` for its options.
|
|
191
192
|
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
resolveArtifact,
|
|
14
14
|
resolveAuth,
|
|
15
15
|
uploadAppBuild
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-MYXUGCR5.js";
|
|
17
17
|
|
|
18
18
|
// src/lib/dev-config.ts
|
|
19
19
|
import { readFileSync, renameSync, rmSync, writeFileSync } from "fs";
|
|
@@ -4658,10 +4658,10 @@ var AGENT_COMMANDS = [
|
|
|
4658
4658
|
{
|
|
4659
4659
|
// relaunch_app: {} — terminate the session's app and launch it again the
|
|
4660
4660
|
// way the session launched it (same launch params); its data is kept.
|
|
4661
|
-
// Refused on embed sessions (their watchdog owns launching)
|
|
4661
|
+
// Refused on embed sessions (their watchdog owns launching).
|
|
4662
4662
|
verb: "relaunch-app",
|
|
4663
4663
|
tool: "relaunch_app",
|
|
4664
|
-
summary: "Close the app under test and start it again: a cold start that keeps the app's data, e.g. to check that something persists. Its log keeps streaming across the restart. Not available on
|
|
4664
|
+
summary: "Close the app under test and start it again: a cold start that keeps the app's data, e.g. to check that something persists. Its log keeps streaming across the restart. Not available on embed sessions.",
|
|
4665
4665
|
mutating: true,
|
|
4666
4666
|
params: []
|
|
4667
4667
|
},
|
|
@@ -163,9 +163,16 @@ async function parseJsonBody(resp) {
|
|
|
163
163
|
return withUtcTimestamps(await resp.json());
|
|
164
164
|
}
|
|
165
165
|
var ApiClient = class {
|
|
166
|
-
constructor(baseUrl, token) {
|
|
166
|
+
constructor(baseUrl, token, opts = {}) {
|
|
167
167
|
this.baseUrl = baseUrl;
|
|
168
168
|
this.token = token;
|
|
169
|
+
this.opts = opts;
|
|
170
|
+
}
|
|
171
|
+
extraHeaders() {
|
|
172
|
+
const h = {};
|
|
173
|
+
if (this.opts.client) h["X-VibeView-Client"] = this.opts.client;
|
|
174
|
+
if (process.env.CI) h["X-VibeView-CI"] = "1";
|
|
175
|
+
return h;
|
|
169
176
|
}
|
|
170
177
|
/**
|
|
171
178
|
* fetch() rejects with undici's bare "TypeError: fetch failed" on any
|
|
@@ -189,6 +196,7 @@ var ApiClient = class {
|
|
|
189
196
|
const url = `${this.baseUrl}/api/v1/ci${path}`;
|
|
190
197
|
const headers = {
|
|
191
198
|
Authorization: `Bearer ${this.token}`,
|
|
199
|
+
...this.extraHeaders(),
|
|
192
200
|
"Content-Type": "application/json"
|
|
193
201
|
};
|
|
194
202
|
const resp = await this.fetchOrExplain(url, {
|
|
@@ -231,7 +239,8 @@ var ApiClient = class {
|
|
|
231
239
|
build_id: options?.build,
|
|
232
240
|
metadata: options?.metadata,
|
|
233
241
|
platform: options?.platform,
|
|
234
|
-
app_id: options?.app
|
|
242
|
+
app_id: options?.app,
|
|
243
|
+
retry_failed: options?.retryFailed
|
|
235
244
|
});
|
|
236
245
|
}
|
|
237
246
|
async runTest(testId, options) {
|
|
@@ -246,7 +255,8 @@ var ApiClient = class {
|
|
|
246
255
|
build_id: options?.build,
|
|
247
256
|
metadata: options?.metadata,
|
|
248
257
|
platform: options?.platform,
|
|
249
|
-
app_id: options?.app
|
|
258
|
+
app_id: options?.app,
|
|
259
|
+
retry_failed: options?.retryFailed
|
|
250
260
|
});
|
|
251
261
|
}
|
|
252
262
|
/** Cancel a still-queued CI run by its queue entry id. Idempotent best-effort. */
|
|
@@ -271,6 +281,7 @@ var ApiClient = class {
|
|
|
271
281
|
const url = `${this.baseUrl}/api/v1${path}`;
|
|
272
282
|
const headers = {
|
|
273
283
|
Authorization: `Bearer ${this.token}`,
|
|
284
|
+
...this.extraHeaders(),
|
|
274
285
|
"Content-Type": "application/json"
|
|
275
286
|
};
|
|
276
287
|
const resp = await this.fetchOrExplain(url, {
|
|
@@ -295,7 +306,8 @@ var ApiClient = class {
|
|
|
295
306
|
async requestFormData(method, path, formData) {
|
|
296
307
|
const url = `${this.baseUrl}/api/v1${path}`;
|
|
297
308
|
const headers = {
|
|
298
|
-
Authorization: `Bearer ${this.token}
|
|
309
|
+
Authorization: `Bearer ${this.token}`,
|
|
310
|
+
...this.extraHeaders()
|
|
299
311
|
// Do NOT set Content-Type — let fetch set multipart boundary automatically
|
|
300
312
|
};
|
|
301
313
|
const resp = await this.fetchOrExplain(url, {
|
|
@@ -351,12 +363,35 @@ var ApiClient = class {
|
|
|
351
363
|
}
|
|
352
364
|
return this.requestFormData("POST", `/apps/${appPublicId}/builds`, formData);
|
|
353
365
|
}
|
|
366
|
+
/** POST /api/v1/tests/import/maestro (multipart): preview (`dryRun`) or
|
|
367
|
+
* import Maestro flows as tests of one app. `group` is a group id or name. */
|
|
368
|
+
async importMaestro(upload, opts) {
|
|
369
|
+
const formData = new FormData();
|
|
370
|
+
formData.append("file", new Blob([Buffer.from(upload.bytes)]), upload.name);
|
|
371
|
+
formData.append("app_id", opts.appId);
|
|
372
|
+
if (opts.group) formData.append("group", opts.group);
|
|
373
|
+
formData.append("dry_run", opts.dryRun ? "true" : "false");
|
|
374
|
+
if (opts.skip && opts.skip.length > 0) formData.append("skip", JSON.stringify(opts.skip));
|
|
375
|
+
return this.requestFormData("POST", "/tests/import/maestro", formData);
|
|
376
|
+
}
|
|
354
377
|
async createTest(body) {
|
|
355
378
|
return this.requestRaw("POST", "/tests/cases/", body);
|
|
356
379
|
}
|
|
357
380
|
async runSuites(body) {
|
|
358
381
|
return this.request("POST", "/run-suites", body);
|
|
359
382
|
}
|
|
383
|
+
async startRun(body) {
|
|
384
|
+
return this.requestRaw("POST", "/tests/runs", body);
|
|
385
|
+
}
|
|
386
|
+
async startRunOnSession(sessionId, body) {
|
|
387
|
+
return this.requestRaw("POST", `/sessions/${encodeURIComponent(sessionId)}/runs`, body);
|
|
388
|
+
}
|
|
389
|
+
async getRunBatch(batchId) {
|
|
390
|
+
return this.requestRaw("GET", `/tests/batches/${encodeURIComponent(batchId)}`);
|
|
391
|
+
}
|
|
392
|
+
async resolveRun(runId) {
|
|
393
|
+
return this.requestRaw("GET", `/tests/runs/${encodeURIComponent(runId)}/resolve`);
|
|
394
|
+
}
|
|
360
395
|
async getMultiSuiteRun(aggregateId) {
|
|
361
396
|
return this.request("GET", `/multi-suite-runs/${aggregateId}`);
|
|
362
397
|
}
|
|
@@ -474,7 +509,8 @@ var ApiClient = class {
|
|
|
474
509
|
async downloadCloudBuildArtifact(id, destDir) {
|
|
475
510
|
const url = `${this.baseUrl}/api/v1/builds/${id}/artifact`;
|
|
476
511
|
const headers = {
|
|
477
|
-
Authorization: `Bearer ${this.token}
|
|
512
|
+
Authorization: `Bearer ${this.token}`,
|
|
513
|
+
...this.extraHeaders()
|
|
478
514
|
};
|
|
479
515
|
const resp = await this.fetchOrExplain(url, { method: "GET", headers });
|
|
480
516
|
if (!resp.ok) {
|