@levr-one/cli 0.4.0 → 0.5.1

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 CHANGED
@@ -14,14 +14,45 @@ The command-line interface for [Levr](https://www.levr.one). The binary is
14
14
  ## Install
15
15
 
16
16
  ```bash
17
- npm install -g @levr-one/cli # global install for daily use
18
- # or run once, no install:
19
- npx @levr-one/cli --help
17
+ npm install -g @levr-one/cli # gives you a persistent `levr` command
20
18
  ```
21
19
 
22
20
  The package is self-contained — no peer setup required. A global install
23
21
  replaces the `levr` bin from the deprecated `@levr-one/setup` package.
24
22
 
23
+ ### Or run it without a global install
24
+
25
+ ```bash
26
+ npx @levr-one/cli --help
27
+ ```
28
+
29
+ `npx` is right for one-shot use (`mcp add`, trying a command). Two things to
30
+ expect:
31
+
32
+ - **`levr` will not be on your PATH afterwards.** npx puts the command on PATH
33
+ only for the duration of that one invocation. Shell completion also assumes a
34
+ global install, since the generated script wires up the `levr` command.
35
+ - **It does download the package** — roughly 8 MB into npm's `~/.npm/_npx`
36
+ cache, kept indefinitely. The first run asks `Ok to proceed?`; later runs are
37
+ silent until a new version is published.
38
+
39
+ In scripts and CI, pass `--yes` — **in a terminal the prompt blocks until it is
40
+ answered**, so an unattended run with a TTY hangs rather than failing:
41
+
42
+ ```bash
43
+ npx --yes @levr-one/cli push ./test-results.xml
44
+ ```
45
+
46
+ Two things to get right:
47
+
48
+ - **Always `npx @levr-one/cli`, never `npx levr`.** npx treats the first
49
+ positional as a _package_ name, so `npx levr` would fetch and run whatever
50
+ package is published under the unscoped name `levr` — which is not ours.
51
+ - **npm's flags go before the package name.** `npx @levr-one/cli --yes` passes
52
+ `--yes` to `levr`, not to npm.
53
+
54
+ For reproducible CI, pin `@levr-one/cli` to a version you have validated.
55
+
25
56
  ## Quick start
26
57
 
27
58
  **Using an AI client?** Wire the Levr MCP server into it — no login needed;
@@ -203,7 +234,7 @@ levr import ./cases.csv --team-id <uuid> --map "State=labels:state"
203
234
  env:
204
235
  LEVR_TOKEN: ${{ secrets.LEVR_TOKEN }}
205
236
  # LEVR_TEAM_ID is optional — server resolves from automation source or workspace default
206
- run: npx @levr-one/cli push ./test-results.xml
237
+ run: npx --yes @levr-one/cli push ./test-results.xml
207
238
  ```
208
239
 
209
240
  ### GitLab CI
@@ -211,7 +242,7 @@ levr import ./cases.csv --team-id <uuid> --map "State=labels:state"
211
242
  ```yaml
212
243
  push-results:
213
244
  script:
214
- - npx @levr-one/cli push ./test-results.xml
245
+ - npx --yes @levr-one/cli push ./test-results.xml
215
246
  variables:
216
247
  LEVR_TOKEN: $LEVR_TOKEN
217
248
  ```
@@ -220,7 +251,7 @@ push-results:
220
251
 
221
252
  ```groovy
222
253
  withEnv(["LEVR_TOKEN=${LEVR_TOKEN}"]) {
223
- sh 'npx @levr-one/cli push ./test-results.xml'
254
+ sh 'npx --yes @levr-one/cli push ./test-results.xml'
224
255
  }
225
256
  ```
226
257
 
@@ -272,13 +303,43 @@ levr workspace current # show the active workspace
272
303
 
273
304
  ## Shell completion (optional)
274
305
 
275
- Tab-completion is an explicit opt-in step (it is not installed automatically):
306
+ Completion needs a global install: the generated script wires up the `levr`
307
+ command, so it does nothing if `levr` is not on your PATH (which it is not when
308
+ you run via `npx`).
309
+
310
+ `levr completion` prints a completion script to **stdout**. It never edits your
311
+ shell config — you choose where the script goes:
276
312
 
277
313
  ```bash
278
- levr install # add shell completion for the current shell
279
- levr uninstall # remove it
314
+ # This session only
315
+ eval "$(levr completion bash)"
316
+ eval "$(levr completion zsh)"
317
+
318
+ # Persist it
319
+ levr completion bash >> ~/.bashrc
320
+ levr completion zsh >> ~/.zshrc
321
+
322
+ # Or system-wide (bash)
323
+ levr completion bash > /etc/bash_completion.d/levr
280
324
  ```
281
325
 
326
+ **zsh:** load it _after_ `compinit`, which is what defines `compdef`:
327
+
328
+ ```zsh
329
+ autoload -Uz compinit && compinit
330
+ eval "$(levr completion zsh)"
331
+ ```
332
+
333
+ If `compinit` has not run, the script says so on stderr instead of failing with
334
+ a bare `command not found: compdef`.
335
+
336
+ Supported shells: **bash** and **zsh**. The shell is detected from `$SHELL` when
337
+ you omit the argument — pass it explicitly in scripts, or to generate a script
338
+ for a shell other than the one you are running. An unsupported or undetectable
339
+ shell writes an error to stderr and exits non-zero.
340
+
341
+ Nothing is installed automatically: the package ships no `postinstall` hook.
342
+
282
343
  ## Configuration
283
344
 
284
345
  All configuration is via environment variables. Flags take precedence.
@@ -1,7 +1,7 @@
1
- import { getApiUrl } from "./env-NxtzJJPk.js";
1
+ import { getApiUrl } from "./env-CHeKHu5S.js";
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
- import { homedir } from "node:os";
4
3
  import { delimiter, dirname, join } from "node:path";
4
+ import { homedir } from "node:os";
5
5
  import { applyEdits, modify, parse } from "jsonc-parser";
6
6
 
7
7
  //#region ../mcp-harnesses/dist/catalog.js
@@ -356,17 +356,17 @@ function signalMatches(signal, env) {
356
356
  return existsSync(signal.startsWith("~") ? expandTilde(signal, env.homedir) : signal);
357
357
  }
358
358
  /** Read a text file, or `null` if it doesn't exist / can't be read. */
359
- function readTextOrNull(path$1) {
359
+ function readTextOrNull(path) {
360
360
  try {
361
- return readFileSync(path$1, "utf8");
361
+ return readFileSync(path, "utf8");
362
362
  } catch {
363
363
  return null;
364
364
  }
365
365
  }
366
366
  /** Safe nested lookup over an unknown-typed parsed JSON value. */
367
- function getAtPath(obj, path$1) {
367
+ function getAtPath(obj, path) {
368
368
  let cur = obj;
369
- for (const key of path$1) {
369
+ for (const key of path) {
370
370
  if (cur === null || typeof cur !== "object") return void 0;
371
371
  cur = cur[key];
372
372
  }
@@ -430,8 +430,8 @@ function installHarnessSync(harness, mcpUrl, opts = {}) {
430
430
  alreadyConfigured: false,
431
431
  dryRun
432
432
  };
433
- const path$1 = resolveConfigPath(harness, env);
434
- if (!path$1) return {
433
+ const path = resolveConfigPath(harness, env);
434
+ if (!path) return {
435
435
  ok: false,
436
436
  wrote: false,
437
437
  path: "",
@@ -440,7 +440,7 @@ function installHarnessSync(harness, mcpUrl, opts = {}) {
440
440
  };
441
441
  const entryValue = buildServerEntry(harness, mcpUrl)[SERVER_NAME];
442
442
  const modPath = [harness.serverPropertyName, SERVER_NAME];
443
- const existing = readTextOrNull(path$1);
443
+ const existing = readTextOrNull(path);
444
444
  const baseText = existing && existing.trim() ? existing : "{}";
445
445
  const current = getAtPath(parse(baseText), modPath);
446
446
  const alreadyConfigured = current !== void 0 && sameValue(current, entryValue);
@@ -448,7 +448,7 @@ function installHarnessSync(harness, mcpUrl, opts = {}) {
448
448
  if (alreadyConfigured) return {
449
449
  ok: true,
450
450
  wrote: false,
451
- path: path$1,
451
+ path,
452
452
  alreadyConfigured: true,
453
453
  dryRun,
454
454
  preview: nextText
@@ -456,18 +456,18 @@ function installHarnessSync(harness, mcpUrl, opts = {}) {
456
456
  if (dryRun) return {
457
457
  ok: true,
458
458
  wrote: false,
459
- path: path$1,
459
+ path,
460
460
  alreadyConfigured: false,
461
461
  dryRun: true,
462
462
  preview: nextText
463
463
  };
464
- mkdirSync(dirname(path$1), { recursive: true });
464
+ mkdirSync(dirname(path), { recursive: true });
465
465
  const finalText = nextText.endsWith("\n") ? nextText : `${nextText}\n`;
466
- writeFileSync(path$1, finalText, "utf8");
466
+ writeFileSync(path, finalText, "utf8");
467
467
  return {
468
468
  ok: true,
469
469
  wrote: true,
470
- path: path$1,
470
+ path,
471
471
  alreadyConfigured: false,
472
472
  dryRun: false,
473
473
  preview: finalText
package/dist/cli.js CHANGED
@@ -1,10 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import { COMPLETION_SHELLS } from "./completionHandler-O2G_WZLf.js";
2
3
  import { buildApplication, buildCommand, buildRouteMap, proposeCompletions, run, text_en } from "@stricli/core";
3
- import fs from "node:fs";
4
- import os from "node:os";
5
- import path from "node:path";
6
4
  import chalk from "chalk";
7
- import { buildInstallCommand, buildUninstallCommand } from "@stricli/auto-complete";
8
5
 
9
6
  //#region src/utils/logger.ts
10
7
  var Logger = class {
@@ -41,9 +38,6 @@ var Logger = class {
41
38
  function buildContext(process$1) {
42
39
  return {
43
40
  process: process$1,
44
- os,
45
- fs,
46
- path,
47
41
  logger: new Logger({
48
42
  verbose: false,
49
43
  stdout: process$1.stdout,
@@ -52,6 +46,45 @@ function buildContext(process$1) {
52
46
  };
53
47
  }
54
48
 
49
+ //#endregion
50
+ //#region src/commands/completion.ts
51
+ const completionCommand = buildCommand({
52
+ docs: {
53
+ brief: "Print the shell completion script for bash or zsh",
54
+ fullDescription: `Prints a shell completion script to stdout. You decide where it goes —
55
+ this command never edits your shell config.
56
+
57
+ Load it for the current session:
58
+ eval "$(levr completion bash)"
59
+ eval "$(levr completion zsh)"
60
+
61
+ Or persist it:
62
+ levr completion bash >> ~/.bashrc
63
+ levr completion zsh >> ~/.zshrc
64
+ levr completion bash > /etc/bash_completion.d/levr # system-wide
65
+
66
+ The shell is detected from $SHELL when omitted; pass it explicitly in scripts
67
+ or when generating a script for a shell other than the one you are running.`
68
+ },
69
+ parameters: {
70
+ positional: {
71
+ kind: "tuple",
72
+ parameters: [{
73
+ parse: String,
74
+ proposeCompletions: (partial) => COMPLETION_SHELLS.filter((shell) => shell.startsWith(partial)),
75
+ brief: `Shell to emit (${COMPLETION_SHELLS.join("|")}); detected from $SHELL if omitted`,
76
+ placeholder: "shell",
77
+ optional: true
78
+ }]
79
+ },
80
+ flags: {}
81
+ },
82
+ loader: async () => {
83
+ const { completionHandler } = await import("./completionHandler-DtG_CsK0.js");
84
+ return completionHandler;
85
+ }
86
+ });
87
+
55
88
  //#endregion
56
89
  //#region src/commands/mcp/add.ts
57
90
  const mcpAddCommand = buildCommand({
@@ -109,7 +142,7 @@ Examples:
109
142
  aliases: { y: "yes" }
110
143
  },
111
144
  loader: async () => {
112
- const { mcpAddHandler } = await import("./addHandler-DFtvzTci.js");
145
+ const { mcpAddHandler } = await import("./addHandler-K2a4rVv8.js");
113
146
  return mcpAddHandler;
114
147
  }
115
148
  });
@@ -147,7 +180,7 @@ Examples:
147
180
  aliases: { d: "device-code" }
148
181
  },
149
182
  loader: async () => {
150
- const { loginHandler } = await import("./loginHandler-D9k-tQLX.js");
183
+ const { loginHandler } = await import("./loginHandler-BhvCWTd8.js");
151
184
  return loginHandler;
152
185
  }
153
186
  });
@@ -166,7 +199,7 @@ Examples:
166
199
  },
167
200
  parameters: {},
168
201
  loader: async () => {
169
- const { logoutHandler } = await import("./logoutHandler-BC8laIAB.js");
202
+ const { logoutHandler } = await import("./logoutHandler-BFutKash.js");
170
203
  return logoutHandler;
171
204
  }
172
205
  });
@@ -186,7 +219,7 @@ Examples:
186
219
  },
187
220
  parameters: {},
188
221
  loader: async () => {
189
- const { statusHandler } = await import("./statusHandler-DuVZJMtw.js");
222
+ const { statusHandler } = await import("./statusHandler-B6XRPg4k.js");
190
223
  return statusHandler;
191
224
  }
192
225
  });
@@ -297,7 +330,7 @@ Examples:
297
330
  }
298
331
  },
299
332
  loader: async () => {
300
- const { pushHandler } = await import("./pushHandler-COg5WbGS.js");
333
+ const { pushHandler } = await import("./pushHandler-v4-lHK6A.js");
301
334
  return pushHandler;
302
335
  }
303
336
  });
@@ -409,7 +442,7 @@ Examples:
409
442
  }
410
443
  },
411
444
  loader: async () => {
412
- const { importHandler } = await import("./importHandler-ChywPYeL.js");
445
+ const { importHandler } = await import("./importHandler-D27Xrx73.js");
413
446
  return importHandler;
414
447
  }
415
448
  });
@@ -430,7 +463,7 @@ Examples:
430
463
  },
431
464
  parameters: {},
432
465
  loader: async () => {
433
- const { listHandler } = await import("./listHandler-fK9Mapr3.js");
466
+ const { listHandler } = await import("./listHandler-8uqFClxw.js");
434
467
  return listHandler;
435
468
  }
436
469
  });
@@ -463,7 +496,7 @@ Examples:
463
496
  flags: {}
464
497
  },
465
498
  loader: async () => {
466
- const { selectHandler } = await import("./selectHandler-BzQRF8E7.js");
499
+ const { selectHandler } = await import("./selectHandler-DeEZe6PU.js");
467
500
  return selectHandler;
468
501
  }
469
502
  });
@@ -480,14 +513,14 @@ Examples:
480
513
  },
481
514
  parameters: {},
482
515
  loader: async () => {
483
- const { currentHandler } = await import("./currentHandler-BD-h0j-S.js");
516
+ const { currentHandler } = await import("./currentHandler-CHydiFui.js");
484
517
  return currentHandler;
485
518
  }
486
519
  });
487
520
 
488
521
  //#endregion
489
522
  //#region package.json
490
- var version = "0.4.0";
523
+ var version = "0.5.1";
491
524
 
492
525
  //#endregion
493
526
  //#region src/app.ts
@@ -517,16 +550,9 @@ const routes = buildRouteMap({
517
550
  workspace: workspaceRoutes,
518
551
  push: pushCommand,
519
552
  import: importCommand,
520
- install: buildInstallCommand("levr", { bash: "levr __complete" }),
521
- uninstall: buildUninstallCommand("levr", { bash: true })
553
+ completion: completionCommand
522
554
  },
523
- docs: {
524
- brief: "The command-line interface for Levr",
525
- hideRoute: {
526
- install: true,
527
- uninstall: true
528
- }
529
- }
555
+ docs: { brief: "The command-line interface for Levr" }
530
556
  });
531
557
  const app = buildApplication(routes, {
532
558
  name: "levr",
@@ -545,10 +571,13 @@ const app = buildApplication(routes, {
545
571
  //#region src/completion.ts
546
572
  /**
547
573
  * Compute shell tab-completion suggestions for the hidden `__complete` entrypoint
548
- * (see src/bin/cli.ts). `levr install` registers a bash function that invokes
549
- * `levr __complete <COMP_LINE>` on each TAB, so `rawArgs` (process.argv.slice(2))
550
- * is `['__complete', <targetCommandName>, ...wordsBeingCompleted]`. A COMP_LINE
551
- * ending in a space means the cursor is on a fresh (empty) word to complete.
574
+ * (see src/bin/cli.ts). The scripts emitted by `levr completion bash|zsh`
575
+ * register a shell function that invokes `levr __complete <words…>` on each TAB,
576
+ * so `rawArgs` (process.argv.slice(2)) is
577
+ * `['__complete', <targetCommandName>, ...wordsBeingCompleted]` note the
578
+ * command name is passed through and dropped here, which is why the shell
579
+ * scripts pass their FULL word array. A COMP_LINE ending in a space means the
580
+ * cursor is on a fresh (empty) word to complete.
552
581
  *
553
582
  * Never throws — completion must not surface an error to the user's shell.
554
583
  */
@@ -0,0 +1,3 @@
1
+ import { COMPLETION_SHELLS, completionHandler, completionScript, detectShell, isCompletionShell } from "./completionHandler-O2G_WZLf.js";
2
+
3
+ export { completionHandler };
@@ -0,0 +1,95 @@
1
+ //#region src/commands/completionHandler.ts
2
+ const COMPLETION_SHELLS = ["bash", "zsh"];
3
+ function isCompletionShell(value) {
4
+ return COMPLETION_SHELLS.includes(value);
5
+ }
6
+ /**
7
+ * Best-effort shell detection from `$SHELL`. Matches on the basename so login
8
+ * shells (`-bash`) and non-standard prefixes (`/usr/local/bin/zsh`) still
9
+ * resolve. Returns undefined when the shell is unset or unsupported — the
10
+ * caller must then fail loudly rather than guess.
11
+ */
12
+ function detectShell(shellPath) {
13
+ const name = shellPath?.split("/").pop() ?? "";
14
+ if (name.includes("zsh")) return "zsh";
15
+ if (name.includes("bash")) return "bash";
16
+ }
17
+ const BASH_SCRIPT = `# levr bash completion.
18
+ # Load it from ~/.bashrc: eval "$(levr completion bash)"
19
+ __levr_complete() {
20
+ export COMP_LINE
21
+ local -a words=( "\${COMP_WORDS[@]}" )
22
+ # Drop a trailing empty word. COMP_LINE's trailing space is already the
23
+ # signal that the cursor is on a fresh word; passing the empty word too
24
+ # would make __complete see it twice and match nothing. Harmless when the
25
+ # last word is non-empty, so this is correct however bash populates
26
+ # COMP_WORDS.
27
+ if [[ \${#words[@]} -gt 0 && -z "\${words[\${#words[@]}-1]}" ]]; then
28
+ words=( "\${words[@]:0:\${#words[@]}-1}" )
29
+ fi
30
+ COMPREPLY=( $(levr __complete "\${words[@]}") )
31
+ return 0
32
+ }
33
+ complete -o default -o nospace -F __levr_complete levr
34
+ `;
35
+ const ZSH_SCRIPT = `# levr zsh completion.
36
+ # Load it from ~/.zshrc, AFTER your compinit call:
37
+ # autoload -Uz compinit && compinit
38
+ # eval "$(levr completion zsh)"
39
+ _levr_complete() {
40
+ local -a candidates args
41
+ local raw
42
+ local comp_line="\${(j: :)words}"
43
+
44
+ args=("\${(@)words}")
45
+ if [[ -z "\${args[-1]}" ]]; then
46
+ args=("\${(@)args[1,-2]}")
47
+ fi
48
+
49
+ # Return before splitting when there is nothing to offer, so compadd is
50
+ # never reached with an empty candidate list.
51
+ raw="$(COMP_LINE="$comp_line" levr __complete "\${args[@]}" 2>/dev/null)"
52
+ [[ -n "$raw" ]] || return
53
+
54
+ candidates=(\${(f)raw})
55
+ # -S '' matches bash's \`complete -o nospace\`: no space is appended after a
56
+ # unique match, so subcommands can be chained without deleting one.
57
+ compadd -S '' -- "\${candidates[@]}"
58
+ }
59
+
60
+ # compdef only exists once compinit has run. Without this guard a .zshrc that
61
+ # eval's this before compinit dies with a bare "command not found: compdef" on
62
+ # every new shell; the explicit message says what to actually do.
63
+ if (( $+functions[compdef] )); then
64
+ compdef _levr_complete levr
65
+ else
66
+ print -u2 "levr: completion not registered — run \\\`autoload -Uz compinit && compinit\\\` before loading it."
67
+ fi
68
+ `;
69
+ function completionScript(shell) {
70
+ return shell === "zsh" ? ZSH_SCRIPT : BASH_SCRIPT;
71
+ }
72
+ /**
73
+ * Print the completion script for `shell` (or the detected shell) to stdout.
74
+ *
75
+ * stdout carries the script and NOTHING else, so `eval "$(levr completion zsh)"`
76
+ * is safe; diagnostics go to stderr and set a non-zero exit code. The command
77
+ * never writes to the filesystem — wiring it up is the user's call (ENG-2702).
78
+ */
79
+ function completionHandler(_flags, shell) {
80
+ const requested = shell === void 0 ? detectShell(this.process.env["SHELL"]) : shell;
81
+ if (requested === void 0) {
82
+ this.process.stderr.write(`Could not detect your shell from \$SHELL. Pass one explicitly: levr completion <${COMPLETION_SHELLS.join("|")}>\n`);
83
+ this.process.exitCode = 1;
84
+ return;
85
+ }
86
+ if (!isCompletionShell(requested)) {
87
+ this.process.stderr.write(`Unsupported shell "${requested}". Supported shells: ${COMPLETION_SHELLS.join(", ")}.\n`);
88
+ this.process.exitCode = 1;
89
+ return;
90
+ }
91
+ this.process.stdout.write(completionScript(requested));
92
+ }
93
+
94
+ //#endregion
95
+ export { COMPLETION_SHELLS, completionHandler, completionScript, detectShell, isCompletionShell };
@@ -1,4 +1,4 @@
1
- import { loadWorkspace } from "./workspace-store-4hfvsEHS.js";
1
+ import { loadWorkspace } from "./workspace-store-DDOxnut1.js";
2
2
 
3
3
  //#region src/commands/workspace/currentHandler.ts
4
4
  function currentHandler() {
@@ -1,6 +1,6 @@
1
1
  import { mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
2
- import { homedir } from "node:os";
3
2
  import { dirname, join } from "node:path";
3
+ import { homedir } from "node:os";
4
4
 
5
5
  //#region src/auth/credentials.ts
6
6
  const CREDENTIALS_PATH = join(join(homedir(), ".config", "levr"), "credentials.json");
@@ -1,12 +1,12 @@
1
- import { getApiUrl } from "./env-NxtzJJPk.js";
2
- import { configureClient, testCaseImportCommitV1, testCaseImportPreviewV1 } from "./sdk-client-DyRTezC5.js";
3
- import "./workspace-store-4hfvsEHS.js";
4
- import { resolveWorkspace } from "./resolve-workspace-CO8d3IBz.js";
5
- import "./token-refresh-Cz-FqDtC.js";
6
- import { resolveToken } from "./resolve-token-Dq8cAuiu.js";
1
+ import { getApiUrl } from "./env-CHeKHu5S.js";
2
+ import { configureClient, testCaseImportCommitV1, testCaseImportPreviewV1 } from "./sdk-client-DP7uCfXP.js";
3
+ import "./workspace-store-DDOxnut1.js";
4
+ import { resolveWorkspace } from "./resolve-workspace-BnTDxvYq.js";
5
+ import "./token-refresh-Cu5RpkLJ.js";
6
+ import { resolveToken } from "./resolve-token-DbQsmn03.js";
7
+ import chalk from "chalk";
7
8
  import { createReadStream } from "node:fs";
8
9
  import { basename } from "node:path";
9
- import chalk from "chalk";
10
10
  import { readFile, writeFile } from "node:fs/promises";
11
11
  import { createInterface } from "node:readline/promises";
12
12
  import ora from "ora";
@@ -108,9 +108,9 @@ const MATCH_COLORS = {
108
108
  manual: chalk.green
109
109
  };
110
110
  /** Stream the file into a Blob — no readFileSync, no sync stall. */
111
- async function fileToBlob(path$1) {
111
+ async function fileToBlob(path) {
112
112
  const chunks = [];
113
- for await (const chunk of createReadStream(path$1)) chunks.push(chunk);
113
+ for await (const chunk of createReadStream(path)) chunks.push(chunk);
114
114
  return new Blob(chunks);
115
115
  }
116
116
  function printMapping(logger, mapping) {
@@ -1,8 +1,8 @@
1
- import "./env-NxtzJJPk.js";
2
- import { authGetSitesV1, configureClient } from "./sdk-client-DyRTezC5.js";
3
- import { loadWorkspace } from "./workspace-store-4hfvsEHS.js";
4
- import "./token-refresh-Cz-FqDtC.js";
5
- import { resolveToken } from "./resolve-token-Dq8cAuiu.js";
1
+ import "./env-CHeKHu5S.js";
2
+ import { authGetSitesV1, configureClient } from "./sdk-client-DP7uCfXP.js";
3
+ import { loadWorkspace } from "./workspace-store-DDOxnut1.js";
4
+ import "./token-refresh-Cu5RpkLJ.js";
5
+ import { resolveToken } from "./resolve-token-DbQsmn03.js";
6
6
 
7
7
  //#region src/commands/workspace/listHandler.ts
8
8
  async function listHandler() {
@@ -1,7 +1,7 @@
1
- import { CLI_CLIENT_ID, getApiUrl, getAuthUrl, setSessionApiUrl, writeCredentials } from "./env-NxtzJJPk.js";
2
- import { configureClient } from "./sdk-client-DyRTezC5.js";
3
- import "./workspace-store-4hfvsEHS.js";
4
- import { autoSelectWorkspace } from "./resolve-workspace-CO8d3IBz.js";
1
+ import { CLI_CLIENT_ID, getApiUrl, getAuthUrl, setSessionApiUrl, writeCredentials } from "./env-CHeKHu5S.js";
2
+ import { configureClient } from "./sdk-client-DP7uCfXP.js";
3
+ import "./workspace-store-DDOxnut1.js";
4
+ import { autoSelectWorkspace } from "./resolve-workspace-BnTDxvYq.js";
5
5
  import chalk from "chalk";
6
6
  import { createHash, randomBytes } from "node:crypto";
7
7
  import { createServer } from "node:http";
@@ -1,5 +1,5 @@
1
- import { deleteCredentials, getPatToken } from "./env-NxtzJJPk.js";
2
- import { clearWorkspace } from "./workspace-store-4hfvsEHS.js";
1
+ import { deleteCredentials, getPatToken } from "./env-CHeKHu5S.js";
2
+ import { clearWorkspace } from "./workspace-store-DDOxnut1.js";
3
3
 
4
4
  //#region src/commands/auth/logoutHandler.ts
5
5
  function logoutHandler() {
@@ -1,9 +1,9 @@
1
- import { getApiUrl, getAutomationSourceIdOverride, getSourceOverride, getTeamId } from "./env-NxtzJJPk.js";
2
- import { client, configureClient, uploadAutomationIngest, uploadImport } from "./sdk-client-DyRTezC5.js";
3
- import "./workspace-store-4hfvsEHS.js";
4
- import { resolveWorkspace } from "./resolve-workspace-CO8d3IBz.js";
5
- import "./token-refresh-Cz-FqDtC.js";
6
- import { resolveToken } from "./resolve-token-Dq8cAuiu.js";
1
+ import { getApiUrl, getAutomationSourceIdOverride, getSourceOverride, getTeamId } from "./env-CHeKHu5S.js";
2
+ import { client, configureClient, uploadAutomationIngest, uploadImport } from "./sdk-client-DP7uCfXP.js";
3
+ import "./workspace-store-DDOxnut1.js";
4
+ import { resolveWorkspace } from "./resolve-workspace-BnTDxvYq.js";
5
+ import "./token-refresh-Cu5RpkLJ.js";
6
+ import { resolveToken } from "./resolve-token-DbQsmn03.js";
7
7
  import { readFileSync, statSync } from "node:fs";
8
8
  import { basename } from "node:path";
9
9
  import ora from "ora";
@@ -1,5 +1,5 @@
1
- import { getApiUrl, getPatToken, readCredentials } from "./env-NxtzJJPk.js";
2
- import { isTokenExpired, refreshToken } from "./token-refresh-Cz-FqDtC.js";
1
+ import { getApiUrl, getPatToken, readCredentials } from "./env-CHeKHu5S.js";
2
+ import { isTokenExpired, refreshToken } from "./token-refresh-Cu5RpkLJ.js";
3
3
 
4
4
  //#region src/auth/resolve-token.ts
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { authGetSitesV1 } from "./sdk-client-DyRTezC5.js";
2
- import { clearWorkspace, loadWorkspace, saveWorkspace } from "./workspace-store-4hfvsEHS.js";
1
+ import { authGetSitesV1 } from "./sdk-client-DP7uCfXP.js";
2
+ import { clearWorkspace, loadWorkspace, saveWorkspace } from "./workspace-store-DDOxnut1.js";
3
3
 
4
4
  //#region src/workspace/resolve-workspace.ts
5
5
  async function fetchSites() {
@@ -1,4 +1,4 @@
1
- import { getApiUrl } from "./env-NxtzJJPk.js";
1
+ import { getApiUrl } from "./env-CHeKHu5S.js";
2
2
  import { z } from "zod/v3";
3
3
 
4
4
  //#region ../sdk/dist/gen/_common/zod.js
@@ -2426,18 +2426,81 @@ const zAppGetHelloV1Data = z.object({ url: z.literal("/v1") });
2426
2426
 
2427
2427
  //#endregion
2428
2428
  //#region ../sdk/dist/gen/archive/zod.js
2429
+ const zArchiveListResponseDto = z.object({
2430
+ data: z.array(z.object({
2431
+ id: z.string(),
2432
+ entity_type: z.string(),
2433
+ display_name: z.string(),
2434
+ archived_at: z.string().nullable().optional(),
2435
+ deleted_at: z.string().nullable().optional(),
2436
+ created_at: z.string(),
2437
+ created_by: z.string(),
2438
+ deleted_by: z.string().nullable().optional()
2439
+ })),
2440
+ meta: z.object({
2441
+ itemsPerPage: z.number(),
2442
+ totalItems: z.number(),
2443
+ currentPage: z.number(),
2444
+ totalPages: z.number()
2445
+ })
2446
+ });
2447
+ const zArchiveFacetsResponseDto = z.object({
2448
+ entityTypes: z.array(z.object({
2449
+ value: z.string(),
2450
+ count: z.number()
2451
+ })),
2452
+ owners: z.array(z.object({
2453
+ value: z.string(),
2454
+ count: z.number()
2455
+ })),
2456
+ deleters: z.array(z.object({
2457
+ value: z.string(),
2458
+ count: z.number()
2459
+ }))
2460
+ });
2429
2461
  const zArchiveActionDto = z.object({
2430
2462
  id: z.string(),
2431
2463
  entity_type: z.string()
2432
2464
  });
2465
+ const zArchiveBulkActionDto = z.object({ items: z.array(z.object({
2466
+ id: z.string(),
2467
+ entity_type: z.string()
2468
+ })) });
2469
+ const zArchiveBulkResultDto = z.object({
2470
+ results: z.array(z.object({
2471
+ id: z.string(),
2472
+ entity_type: z.string(),
2473
+ ok: z.boolean(),
2474
+ error: z.string().optional()
2475
+ })),
2476
+ succeeded: z.number(),
2477
+ failed: z.number()
2478
+ });
2433
2479
  const zArchiveFindAllV1Data = z.object({
2434
2480
  query: z.object({
2435
2481
  "mode": z.enum(["archived", "deleted"]),
2436
2482
  "page": z.number().optional(),
2437
- "limit": z.number().optional()
2483
+ "limit": z.number().optional(),
2484
+ "sortBy": z.enum([
2485
+ "entity_type",
2486
+ "display_name",
2487
+ "archived_at",
2488
+ "deleted_at",
2489
+ "created_at",
2490
+ "created_by",
2491
+ "deleted_by"
2492
+ ]).optional(),
2493
+ "sortDir": z.enum(["asc", "desc"]).optional(),
2494
+ "entityType": z.array(z.string()).optional(),
2495
+ "ownerId": z.array(z.string()).optional(),
2496
+ "deletedById": z.array(z.string()).optional()
2438
2497
  }).optional(),
2439
2498
  url: z.literal("/v1/archives")
2440
2499
  });
2500
+ const zArchiveFacetsV1Data = z.object({
2501
+ query: z.object({ "mode": z.enum(["archived", "deleted"]) }).optional(),
2502
+ url: z.literal("/v1/archives/facets")
2503
+ });
2441
2504
  const zArchiveArchiveV1Data = z.object({
2442
2505
  body: zArchiveActionDto,
2443
2506
  url: z.literal("/v1/archives/archive")
@@ -2450,6 +2513,14 @@ const zArchiveUnarchiveV1Data = z.object({
2450
2513
  body: zArchiveActionDto,
2451
2514
  url: z.literal("/v1/archives/unarchive")
2452
2515
  });
2516
+ const zArchiveRestoreBulkV1Data = z.object({
2517
+ body: zArchiveBulkActionDto,
2518
+ url: z.literal("/v1/archives/restore-bulk")
2519
+ });
2520
+ const zArchiveUnarchiveBulkV1Data = z.object({
2521
+ body: zArchiveBulkActionDto,
2522
+ url: z.literal("/v1/archives/unarchive-bulk")
2523
+ });
2453
2524
 
2454
2525
  //#endregion
2455
2526
  //#region ../sdk/dist/gen/artifact-sync/zod.js
@@ -1,8 +1,8 @@
1
- import "./env-NxtzJJPk.js";
2
- import { authGetSitesV1, configureClient } from "./sdk-client-DyRTezC5.js";
3
- import { saveWorkspace } from "./workspace-store-4hfvsEHS.js";
4
- import "./token-refresh-Cz-FqDtC.js";
5
- import { resolveToken } from "./resolve-token-Dq8cAuiu.js";
1
+ import "./env-CHeKHu5S.js";
2
+ import { authGetSitesV1, configureClient } from "./sdk-client-DP7uCfXP.js";
3
+ import { saveWorkspace } from "./workspace-store-DDOxnut1.js";
4
+ import "./token-refresh-Cu5RpkLJ.js";
5
+ import { resolveToken } from "./resolve-token-DbQsmn03.js";
6
6
 
7
7
  //#region src/commands/workspace/selectHandler.ts
8
8
  async function selectHandler(_flags, workspaceId) {
@@ -1,6 +1,6 @@
1
- import { getApiUrl, getPatToken, readCredentials } from "./env-NxtzJJPk.js";
2
- import { authGetProfileV1, configureClient } from "./sdk-client-DyRTezC5.js";
3
- import { isTokenExpired } from "./token-refresh-Cz-FqDtC.js";
1
+ import { getApiUrl, getPatToken, readCredentials } from "./env-CHeKHu5S.js";
2
+ import { authGetProfileV1, configureClient } from "./sdk-client-DP7uCfXP.js";
3
+ import { isTokenExpired } from "./token-refresh-Cu5RpkLJ.js";
4
4
  import chalk from "chalk";
5
5
 
6
6
  //#region src/commands/auth/statusHandler.ts
@@ -1,4 +1,4 @@
1
- import { CLI_CLIENT_ID, deleteCredentials, getApiUrl, writeCredentials } from "./env-NxtzJJPk.js";
1
+ import { CLI_CLIENT_ID, deleteCredentials, getApiUrl, writeCredentials } from "./env-CHeKHu5S.js";
2
2
 
3
3
  //#region src/auth/token-refresh.ts
4
4
  const REFRESH_BUFFER_MS = 300 * 1e3;
@@ -1,6 +1,6 @@
1
1
  import { mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
2
- import { homedir } from "node:os";
3
2
  import { dirname, join } from "node:path";
3
+ import { homedir } from "node:os";
4
4
 
5
5
  //#region src/workspace/workspace-store.ts
6
6
  const WORKSPACE_PATH = join(join(homedir(), ".config", "levr"), "workspace.json");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@levr-one/cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "The command-line interface for Levr",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -14,7 +14,6 @@
14
14
  ],
15
15
  "dependencies": {
16
16
  "@clack/prompts": "^1.7.0",
17
- "@stricli/auto-complete": "^1.2.0",
18
17
  "@stricli/core": "^1.2.0",
19
18
  "chalk": "^5.6.2",
20
19
  "jsonc-parser": "^3.3.1",
@@ -29,7 +28,6 @@
29
28
  "eslint-config-prettier": "^10.0.1",
30
29
  "eslint-plugin-prettier": "^5.2.2",
31
30
  "globals": "^16.0.0",
32
- "npm-run-all": "^4.1.5",
33
31
  "prettier": "^3.4.2",
34
32
  "rimraf": "^6.0.1",
35
33
  "tsdown": "^0.15.6",