@test-lab-ai/cli 0.2.18 → 0.2.20

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.
Files changed (2) hide show
  1. package/bin/testlab.mjs +73 -1
  2. package/package.json +1 -1
package/bin/testlab.mjs CHANGED
@@ -43,10 +43,17 @@ Usage:
43
43
  testlab plans update <id> [-f patch.json] [--prompt P] [--name N]
44
44
  Update an existing plan; only the
45
45
  fields you pass change
46
+ testlab plans delete <id> Soft-delete a plan (reversible; kept
47
+ in run history + the audit log)
46
48
  testlab projects list List your projects
47
49
  testlab credentials set <key> --value <value> Set a credential ({{credentials.<key>}})
48
50
  testlab credentials list List credential keys (values never shown)
49
51
  testlab labels list List your labels
52
+ testlab preferences get Show account testing preferences
53
+ testlab preferences set <pref> <value> Set a preference:
54
+ auto-upgrade <on|off>
55
+ script-retry <0-5>
56
+ auto-fix-flaky <on|off>
50
57
  testlab data list List data fixtures + built-in file fixtures
51
58
  testlab data create -f fixture.json Create a data fixture ({{data.<fixture>.<field>}})
52
59
  testlab scripts upload <file> --plan <id> Upload a local Playwright script for a plan
@@ -247,6 +254,19 @@ async function cmdPlansUpdate(flags, args) {
247
254
  log(`✓ Updated plan #${r.json.testPlan.id}: ${r.json.testPlan.name}`)
248
255
  }
249
256
 
257
+ async function cmdPlansDelete(flags, args) {
258
+ const { apiKey, apiUrl } = requireAuth(flags)
259
+ const planId = parsePlanIdArg(args[2] ?? flags.plan)
260
+ if (!Number.isInteger(planId)) {
261
+ errExit("usage: testlab plans delete <id> (numeric plan id; see `testlab plans list`)")
262
+ }
263
+ // Soft delete server-side (reversible; run history kept). Recorded in the
264
+ // account's audit log.
265
+ const r = await apiFetch(apiUrl, apiKey, "DELETE", `/api/v1/test-plans/${planId}`)
266
+ if (!r.ok) errExit(`${r.status}: ${r.json?.error || ""}`)
267
+ log(`✓ Deleted plan #${planId}`)
268
+ }
269
+
250
270
  async function cmdCredentialsSet(flags, args) {
251
271
  const { apiKey, apiUrl } = requireAuth(flags)
252
272
  const key = args[2]
@@ -288,6 +308,52 @@ async function cmdLabelsList(flags) {
288
308
  log(`\n${labels.length} label(s)`)
289
309
  }
290
310
 
311
+ function parseOnOff(v, label) {
312
+ const s = String(v).toLowerCase()
313
+ if (["on", "true", "1", "enable", "enabled", "yes"].includes(s)) return true
314
+ if (["off", "false", "0", "disable", "disabled", "no"].includes(s)) return false
315
+ errExit(`${label} must be on or off (got "${v}")`)
316
+ }
317
+
318
+ async function cmdPreferencesGet(flags) {
319
+ const { apiKey, apiUrl } = requireAuth(flags)
320
+ const r = await apiFetch(apiUrl, apiKey, "GET", "/api/v1/preferences")
321
+ if (!r.ok) errExit(`${r.status}: ${r.json?.error || ""}`)
322
+ const p = r.json || {}
323
+ log(` auto-upgrade: ${p.autoUpgradeEnabled ? "on" : "off"}`)
324
+ log(` script-retry: ${p.scriptRetryOnFailure ?? 0}`)
325
+ log(` auto-fix-flaky: ${p.autoFixFlaky ? "on" : "off"}`)
326
+ }
327
+
328
+ async function cmdPreferencesSet(flags, args) {
329
+ const { apiKey, apiUrl } = requireAuth(flags)
330
+ const key = args[2]
331
+ const value = args[3] ?? flags.value
332
+ if (!key || value === undefined) {
333
+ errExit("usage: testlab preferences set <auto-upgrade|script-retry|auto-fix-flaky> <on|off|0-5>")
334
+ }
335
+ let patch
336
+ switch (key) {
337
+ case "auto-upgrade":
338
+ patch = { autoUpgradeEnabled: parseOnOff(value, "auto-upgrade") }
339
+ break
340
+ case "auto-fix-flaky":
341
+ patch = { autoFixFlaky: parseOnOff(value, "auto-fix-flaky") }
342
+ break
343
+ case "script-retry": {
344
+ const n = parseInt(value, 10)
345
+ if (!Number.isInteger(n) || n < 0 || n > 5) errExit("script-retry must be an integer 0-5")
346
+ patch = { scriptRetryOnFailure: n }
347
+ break
348
+ }
349
+ default:
350
+ errExit(`unknown preference "${key}". Use auto-upgrade, script-retry, or auto-fix-flaky.`)
351
+ }
352
+ const r = await apiFetch(apiUrl, apiKey, "PATCH", "/api/v1/preferences", patch)
353
+ if (!r.ok) errExit(`${r.status}: ${r.json?.error || ""}`)
354
+ log(`✓ Updated ${key}`)
355
+ }
356
+
291
357
  // Resolve which project imported plans go into.
292
358
  // --project none -> null (account-level, no project)
293
359
  // --project <id|name> -> that project
@@ -671,7 +737,8 @@ async function main() {
671
737
  if (args[1] === "list") return cmdPlansList(flags)
672
738
  if (args[1] === "create") return cmdPlansCreate(flags)
673
739
  if (args[1] === "update") return cmdPlansUpdate(flags, args)
674
- return errExit("usage: testlab plans <list|create|update>")
740
+ if (args[1] === "delete") return cmdPlansDelete(flags, args)
741
+ return errExit("usage: testlab plans <list|create|update|delete>")
675
742
  case "projects":
676
743
  if (args[1] === "list") return cmdProjectsList(flags)
677
744
  return errExit("usage: testlab projects list")
@@ -682,6 +749,11 @@ async function main() {
682
749
  case "labels":
683
750
  if (args[1] === "list") return cmdLabelsList(flags)
684
751
  return errExit("usage: testlab labels list")
752
+ case "preferences":
753
+ case "prefs":
754
+ if (args[1] === "get") return cmdPreferencesGet(flags)
755
+ if (args[1] === "set") return cmdPreferencesSet(flags, args)
756
+ return errExit("usage: testlab preferences <get | set <auto-upgrade|script-retry|auto-fix-flaky> <on|off|0-5>>")
685
757
  case "data":
686
758
  if (args[1] === "list") return cmdDataList(flags)
687
759
  if (args[1] === "create") return cmdDataCreate(flags)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@test-lab-ai/cli",
3
- "version": "0.2.18",
3
+ "version": "0.2.20",
4
4
  "description": "Import existing test plans into test-lab.ai from the command line (or an AI agent).",
5
5
  "type": "module",
6
6
  "bin": {