@levr-one/cli 0.9.29 → 0.10.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 CHANGED
@@ -142,16 +142,15 @@ levr push ./results.xml --source "backend-unit-tests" --run-name "nightly"
142
142
 
143
143
  **Flags:**
144
144
 
145
- | Flag | Alias | Description |
146
- | --------------------------- | ----- | ------------------------------------------------------------------------------------------ |
147
- | `--team-id <uuid>` | `-t` | Team ID (optional; server resolves default if omitted. Or set `LEVR_TEAM_ID`) |
148
- | `--source <name>` | `-s` | Automation source name — groups recurring imports and remembers team (auto-detected in CI) |
149
- | `--run-name <name>` | `-r` | Name for the test run |
150
- | `--format <type>` | `-f` | File format: `junit`, `gherkin`, `cucumber-json`, `ctrf-json` (auto-detected if omitted) |
151
- | `--parent-folder-id <uuid>` | | Destination folder ID |
152
- | `--create-run` | | Force run creation for structure-only imports |
153
- | `--update-mode <mode>` | | `update` (default) or `create_new` |
154
- | `--verbose` | `-v` | Show detailed output |
145
+ | Flag | Alias | Description |
146
+ | ---------------------------- | ----- | ------------------------------------------------------------------------------------------------------------ |
147
+ | `--workspace-id <uuid>` | `-w` | Workspace ID (required for multi-workspace JWT auth) |
148
+ | `--team-id <uuid>` | `-t` | Team ID (optional; server resolves default if omitted. Or set `LEVR_TEAM_ID`) |
149
+ | `--source <name>` | `-s` | Automation source name — groups recurring imports and remembers team (auto-detected in CI). Required unless `--automation-source` is set |
150
+ | `--automation-source <uuid>` | `-a` | UUID of an existing automation source (never creates one). Used instead of `--source`. Or set `LEVR_AUTOMATION_SOURCE_ID` |
151
+ | `--run-name <name>` | `-r` | Name for the test run |
152
+ | `--format <type>` | `-f` | File format: `junit`, `gherkin`, `cucumber-json`, `ctrf-json` (auto-detected if omitted) |
153
+ | `--verbose` | `-v` | Show detailed output |
155
154
 
156
155
  ### Automation sources
157
156
 
@@ -352,6 +351,7 @@ All configuration is via environment variables. Flags take precedence.
352
351
  | `LEVR_MCP_URL` | MCP server URL written by `levr mcp add` (derived from the API URL when unset) | derived |
353
352
  | `LEVR_TEAM_ID` | Default team ID (optional; server resolves from automation source or workspace default) | |
354
353
  | `LEVR_SOURCE` | Automation source name override (groups imports, remembers team) | |
354
+ | `LEVR_AUTOMATION_SOURCE_ID` | UUID of an existing automation source; used instead of the source name (same as `--automation-source`) | |
355
355
 
356
356
  ## Troubleshooting
357
357
 
@@ -2,9 +2,9 @@ import { getApiUrl } from "./env-CHeKHu5S.js";
2
2
  import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
3
3
  import { basename, delimiter, dirname, join, resolve } from "node:path";
4
4
  import { homedir } from "node:os";
5
+ import { execFileSync } from "node:child_process";
5
6
  import { applyEdits, modify, parse, printParseErrorCode } from "jsonc-parser";
6
7
  import { TomlError, parse as parse$1 } from "smol-toml";
7
- import { execFileSync } from "node:child_process";
8
8
 
9
9
  //#region ../mcp-harnesses/dist/format/toml-render.js
10
10
  /**
package/dist/cli.js CHANGED
@@ -175,7 +175,7 @@ Examples:
175
175
  aliases: { y: "yes" }
176
176
  },
177
177
  loader: async () => {
178
- const { mcpAddHandler } = await import("./addHandler-D6OI7Mx7.js");
178
+ const { mcpAddHandler } = await import("./addHandler-uD4hQvb7.js");
179
179
  return mcpAddHandler;
180
180
  }
181
181
  });
@@ -213,7 +213,7 @@ Examples:
213
213
  aliases: { d: "device-code" }
214
214
  },
215
215
  loader: async () => {
216
- const { loginHandler } = await import("./loginHandler-C2Ax94AS.js");
216
+ const { loginHandler } = await import("./loginHandler-CX2L4fjs.js");
217
217
  return loginHandler;
218
218
  }
219
219
  });
@@ -252,7 +252,7 @@ Examples:
252
252
  },
253
253
  parameters: {},
254
254
  loader: async () => {
255
- const { statusHandler } = await import("./statusHandler-BuAkYg-T.js");
255
+ const { statusHandler } = await import("./statusHandler-BvK4zSEf.js");
256
256
  return statusHandler;
257
257
  }
258
258
  });
@@ -339,19 +339,6 @@ Examples:
339
339
  brief: "File format (auto-detected if omitted)",
340
340
  optional: true
341
341
  },
342
- "parent-folder-id": {
343
- kind: "parsed",
344
- parse: String,
345
- brief: "Destination folder ID",
346
- placeholder: "uuid",
347
- optional: true
348
- },
349
- "update-mode": {
350
- kind: "enum",
351
- values: ["update", "create_new"],
352
- default: "update",
353
- brief: "How to handle existing tests"
354
- },
355
342
  verbose: {
356
343
  kind: "boolean",
357
344
  default: false,
@@ -369,7 +356,7 @@ Examples:
369
356
  }
370
357
  },
371
358
  loader: async () => {
372
- const { pushHandler } = await import("./pushHandler-DEuoXQXJ.js");
359
+ const { pushHandler } = await import("./pushHandler-Ck7lMC39.js");
373
360
  return pushHandler;
374
361
  }
375
362
  });
@@ -489,7 +476,7 @@ Examples:
489
476
  }
490
477
  },
491
478
  loader: async () => {
492
- const { importHandler } = await import("./importHandler-B42PBtOB.js");
479
+ const { importHandler } = await import("./importHandler-TVAFta_i.js");
493
480
  return importHandler;
494
481
  }
495
482
  });
@@ -510,7 +497,7 @@ Examples:
510
497
  },
511
498
  parameters: {},
512
499
  loader: async () => {
513
- const { listHandler } = await import("./listHandler-DmG_OvBC.js");
500
+ const { listHandler } = await import("./listHandler-AYN1KpE-.js");
514
501
  return listHandler;
515
502
  }
516
503
  });
@@ -543,7 +530,7 @@ Examples:
543
530
  flags: {}
544
531
  },
545
532
  loader: async () => {
546
- const { selectHandler } = await import("./selectHandler-DmpxYqaN.js");
533
+ const { selectHandler } = await import("./selectHandler-CzolM41G.js");
547
534
  return selectHandler;
548
535
  }
549
536
  });
@@ -560,14 +547,83 @@ Examples:
560
547
  },
561
548
  parameters: {},
562
549
  loader: async () => {
563
- const { currentHandler } = await import("./currentHandler-CHydiFui.js");
550
+ const { currentHandler } = await import("./currentHandler-BBHqC26D.js");
564
551
  return currentHandler;
565
552
  }
566
553
  });
567
554
 
555
+ //#endregion
556
+ //#region src/commands/gates/run.ts
557
+ const gatesRunCommand = buildCommand({
558
+ docs: {
559
+ brief: "Run a deliverable's gate commands and report the raw results",
560
+ fullDescription: `Verify a deliverable's gates, run every local command EXACTLY as the
561
+ server returned it (/bin/bash -c, from the current directory — run it from the
562
+ repo root), and report the raw exit code and output tails so the server can
563
+ derive each verdict.
564
+
565
+ Each command is printed before it runs; use --dry-run to read them first. The
566
+ server validates every local command before handing it out: a command that
567
+ fails its check comes back as a verification error, never as a command to run.
568
+
569
+ Guided gates are listed, not run: perform them and report what you observed
570
+ with report_gate_results step_results[].
571
+
572
+ Exit code 0 when every gate passes after the report, 1 otherwise.
573
+
574
+ Examples:
575
+ levr gates run ENG-50
576
+ levr gates run ENG-50 --dry-run # list the commands; run and report nothing
577
+ levr gates run <issue-uuid> --json`
578
+ },
579
+ parameters: {
580
+ positional: {
581
+ kind: "tuple",
582
+ parameters: [{
583
+ parse: String,
584
+ brief: "Deliverable issue identifier (ENG-50) or UUID",
585
+ placeholder: "issue",
586
+ optional: false
587
+ }]
588
+ },
589
+ flags: {
590
+ "workspace-id": {
591
+ kind: "parsed",
592
+ parse: String,
593
+ brief: "Workspace ID (required for multi-workspace JWT auth)",
594
+ placeholder: "uuid",
595
+ optional: true
596
+ },
597
+ "dry-run": {
598
+ kind: "boolean",
599
+ default: false,
600
+ brief: "List the commands and the report entries they would produce; run nothing"
601
+ },
602
+ json: {
603
+ kind: "boolean",
604
+ default: false,
605
+ brief: "Print machine-readable JSON"
606
+ },
607
+ verbose: {
608
+ kind: "boolean",
609
+ default: false,
610
+ brief: "Show detailed output"
611
+ }
612
+ },
613
+ aliases: {
614
+ w: "workspace-id",
615
+ v: "verbose"
616
+ }
617
+ },
618
+ loader: async () => {
619
+ const { gatesRunHandler } = await import("./runHandler-COp3W6GN.js");
620
+ return gatesRunHandler;
621
+ }
622
+ });
623
+
568
624
  //#endregion
569
625
  //#region package.json
570
- var version = "0.9.29";
626
+ var version = "0.10.0";
571
627
 
572
628
  //#endregion
573
629
  //#region src/app.ts
@@ -587,6 +643,10 @@ const workspaceRoutes = buildRouteMap({
587
643
  },
588
644
  docs: { brief: "Manage workspace selection" }
589
645
  });
646
+ const gatesRoutes = buildRouteMap({
647
+ routes: { run: gatesRunCommand },
648
+ docs: { brief: "Run a deliverable's gates and report the raw results" }
649
+ });
590
650
  const routes = buildRouteMap({
591
651
  routes: {
592
652
  mcp: buildRouteMap({
@@ -595,6 +655,7 @@ const routes = buildRouteMap({
595
655
  }),
596
656
  auth: authRoutes,
597
657
  workspace: workspaceRoutes,
658
+ gates: gatesRoutes,
598
659
  push: pushCommand,
599
660
  import: importCommand,
600
661
  completion: completionCommand
@@ -1,7 +1,7 @@
1
1
  import { getApiUrl, getTeamId } from "./env-CHeKHu5S.js";
2
- import { authGetProfileV1, configureClient, teamFindAllV1, testCaseImportCommitV1, testCaseImportPreviewV1 } from "./sdk-client-CQa-x1zl.js";
2
+ import { authGetProfileV1, configureClient, teamFindAllV1, testCaseImportCommitV1, testCaseImportPreviewV1 } from "./sdk-client-DHD7tgY0.js";
3
3
  import "./workspace-store-DDOxnut1.js";
4
- import { resolveWorkspace } from "./resolve-workspace-DmqApDw5.js";
4
+ import { resolveWorkspace } from "./resolve-workspace-Ba9NuCRq.js";
5
5
  import "./token-refresh-Cu5RpkLJ.js";
6
6
  import { resolveToken } from "./resolve-token-DbQsmn03.js";
7
7
  import chalk from "chalk";
@@ -1,5 +1,5 @@
1
1
  import "./env-CHeKHu5S.js";
2
- import { authGetSitesV1, configureClient } from "./sdk-client-CQa-x1zl.js";
2
+ import { authGetSitesV1, configureClient } from "./sdk-client-DHD7tgY0.js";
3
3
  import { loadWorkspace } from "./workspace-store-DDOxnut1.js";
4
4
  import "./token-refresh-Cu5RpkLJ.js";
5
5
  import { resolveToken } from "./resolve-token-DbQsmn03.js";
@@ -1,7 +1,7 @@
1
1
  import { CLI_CLIENT_ID, getApiUrl, getAuthUrl, setSessionApiUrl, writeCredentials } from "./env-CHeKHu5S.js";
2
- import { configureClient } from "./sdk-client-CQa-x1zl.js";
2
+ import { configureClient } from "./sdk-client-DHD7tgY0.js";
3
3
  import "./workspace-store-DDOxnut1.js";
4
- import { autoSelectWorkspace } from "./resolve-workspace-DmqApDw5.js";
4
+ import { autoSelectWorkspace } from "./resolve-workspace-Ba9NuCRq.js";
5
5
  import chalk from "chalk";
6
6
  import { createHash, randomBytes } from "node:crypto";
7
7
  import { createServer } from "node:http";
@@ -1,13 +1,13 @@
1
1
  import { getApiUrl, getAutomationSourceIdOverride, getSourceOverride, getTeamId } from "./env-CHeKHu5S.js";
2
- import { client, configureClient, uploadImport } from "./sdk-client-CQa-x1zl.js";
2
+ import { client, configureClient, uploadImport } from "./sdk-client-DHD7tgY0.js";
3
3
  import "./workspace-store-DDOxnut1.js";
4
- import { resolveWorkspace } from "./resolve-workspace-DmqApDw5.js";
4
+ import { resolveWorkspace } from "./resolve-workspace-Ba9NuCRq.js";
5
5
  import "./token-refresh-Cu5RpkLJ.js";
6
6
  import { resolveToken } from "./resolve-token-DbQsmn03.js";
7
7
  import { readFileSync, statSync } from "node:fs";
8
8
  import { basename } from "node:path";
9
- import ora from "ora";
10
9
  import { execSync } from "node:child_process";
10
+ import ora from "ora";
11
11
 
12
12
  //#region ../ci-env/dist/providers/github.js
13
13
  const MAX_EVENT_PAYLOAD_BYTES = 5 * 1024 * 1024;
@@ -429,7 +429,6 @@ async function pushHandler(flags, file) {
429
429
  this.logger.debug(`Team: ${uploadTeamId ?? (automationSourceId ? "(automation source's team)" : "(server default)")}`);
430
430
  this.logger.debug(`File: ${file} (${formatBytes(fileStat.size)})`);
431
431
  if (flags.format) this.logger.debug(`Format: ${flags.format}`);
432
- if (flags["update-mode"]) this.logger.debug(`Update mode: ${flags["update-mode"]}`);
433
432
  if (automationSourceId) this.logger.debug(`Automation source: ${automationSourceId} (${automationSourceOrigin})`);
434
433
  else if (sourceName) this.logger.debug(`Source: ${sourceName} (${sourceOrigin})`);
435
434
  if (ciMeta) {
@@ -452,9 +451,7 @@ async function pushHandler(flags, file) {
452
451
  file: new File([fileBuffer], fileName),
453
452
  fileName,
454
453
  format: flags.format,
455
- parentFolderId: flags["parent-folder-id"],
456
454
  runName: flags["run-name"],
457
- updateMode: flags["update-mode"],
458
455
  ...automationSourceId ? { automationSourceId } : { automationSource: sourceName },
459
456
  importMetadata: ciMeta
460
457
  });
@@ -1,4 +1,4 @@
1
- import { authGetSitesV1 } from "./sdk-client-CQa-x1zl.js";
1
+ import { authGetSitesV1 } from "./sdk-client-DHD7tgY0.js";
2
2
  import { clearWorkspace, loadWorkspace, saveWorkspace } from "./workspace-store-DDOxnut1.js";
3
3
 
4
4
  //#region src/workspace/resolve-workspace.ts
@@ -0,0 +1,320 @@
1
+ import "./env-CHeKHu5S.js";
2
+ import { client, configureClient, issueFindAllV1, issueGateVerificationReportGateResultsV1, issueGateVerificationVerifyGatesV1 } from "./sdk-client-DHD7tgY0.js";
3
+ import "./workspace-store-DDOxnut1.js";
4
+ import { resolveWorkspace } from "./resolve-workspace-Ba9NuCRq.js";
5
+ import "./token-refresh-Cu5RpkLJ.js";
6
+ import { resolveToken } from "./resolve-token-DbQsmn03.js";
7
+ import { existsSync } from "node:fs";
8
+ import { spawnSync } from "node:child_process";
9
+
10
+ //#region src/commands/gates/gate-runner.ts
11
+ /**
12
+ * ENG-5967 F — run a deliverable's gate `local_commands` and build the
13
+ * `report_gate_results` payload from RAW facts.
14
+ *
15
+ * The contract with the server (`POST /v1/issue/:id/gate-results`, the same
16
+ * one the `report_gate_results` MCP tool takes):
17
+ *
18
+ * - each `local_commands[]` entry is run EXACTLY as returned, through
19
+ * `/bin/bash -c` (the shell the qinetic-mcp executor uses — see
20
+ * `chooseShell`), from the current directory — no rewriting and no
21
+ * splitting. The server decided what to run; this reports what happened.
22
+ * `levr gates run` prints each command first; there is no local
23
+ * allowlist — the server validates every command it hands out
24
+ * (`validateGateCommand`, review R3-01) and returns one that fails as a
25
+ * verification error;
26
+ * - one result per command, carrying its `link_id`, `gate_type`, `step_id`
27
+ * and `rule_hash`, and ONE raw step: the command, its exit code and the
28
+ * last `GATE_STEP_TAIL_LIMIT` chars of stdout and stderr. A compound
29
+ * command (`cd <ws> && yarn test:unit …`) stays one step: the server
30
+ * judges it per top-level command (review R2-01), so reporting it whole
31
+ * is as strict as the MCP executor's split;
32
+ * - `status` is only the exit code's opinion. The server re-derives every
33
+ * verdict from the steps (a test runner by its exit code and output, an
34
+ * L4 judge by the verdict it stated), which is why the output must be the
35
+ * command's own — a terminal proxy that rewrites it (RTK's `PASS (8)
36
+ * FAIL (0)`) hides the signals the server reads. Spawning the commands
37
+ * from this process means no proxy ever sees them.
38
+ *
39
+ * Why not the qinetic-mcp executor: it splits `&&` chains and rewrites paths
40
+ * for the Levr monorepo — the opposite of "exactly as returned". The CLI
41
+ * shares its wire contract, not its code, and imports
42
+ * no `@levr/*` value module (so the published bundle's inlined set is
43
+ * unchanged). The documented no-install helper
44
+ * (`packages/help-content/docs/gates/running-gates.mdx`) implements this same
45
+ * contract; `gate-runner.helper.test.ts` holds the two to identical output.
46
+ */
47
+ /** The server's `GATE_STEP_TAIL_LIMIT` (`@levr/shared`), in chars. */
48
+ const GATE_STEP_TAIL_LIMIT = 4e3;
49
+ /** How long one command may run before it is killed (15 min). */
50
+ const GATE_COMMAND_TIMEOUT_MS = 900 * 1e3;
51
+ /** Keep the END of a stream — where runner summaries and verdicts are. */
52
+ function tail(value, limit = GATE_STEP_TAIL_LIMIT) {
53
+ const s = value ?? "";
54
+ return s.length <= limit ? s : s.slice(-limit);
55
+ }
56
+ /**
57
+ * No POSIX shell to run gate commands in — ENG-5967 F-020. Thrown by
58
+ * `chooseShell`; `levr gates run` turns it into a refusal before anything
59
+ * runs or is reported.
60
+ */
61
+ var NoPosixShellError = class extends Error {
62
+ constructor(platform) {
63
+ super(platform === "win32" ? "Gate commands are bash, and no `bash` or `sh` was found on PATH. Install Git for Windows (Git Bash — https://git-scm.com/download/win) or run levr inside WSL, then re-run. Nothing was run or reported." : "Gate commands are bash, and neither /bin/bash nor /bin/sh exists on this machine. Install bash, then re-run. Nothing was run or reported.");
64
+ this.name = "NoPosixShellError";
65
+ }
66
+ };
67
+ /**
68
+ * The shell a gate command runs in — ENG-5967 F-020.
69
+ *
70
+ * Gate commands are written for, and run by the qinetic-mcp executor with,
71
+ * `/bin/bash` (`execSync(…, { shell: '/bin/bash' })`), and some use bash-only
72
+ * syntax (`${#v}`, arrays, `shopt`, `[[ ]]`). So:
73
+ *
74
+ * - POSIX (`process.platform !== 'win32'`): `/bin/bash -c` when it exists,
75
+ * else `/bin/sh -c` (a minimal image without bash; a bash-only command
76
+ * then fails loudly with a syntax error, never silently passes);
77
+ * - Windows: `bash -c` from PATH (Git Bash, WSL), else `sh -c` from PATH.
78
+ *
79
+ * With NEITHER, `NoPosixShellError` — never `cmd.exe`. cmd has no POSIX
80
+ * semantics at all (`&&` aside, quoting, `$(…)`, `test`, pipes into `grep`
81
+ * all differ), so a gate "run" there reports failures that say nothing about
82
+ * the code; refusing, and naming what to install, is the honest answer.
83
+ *
84
+ * `has` answers whether a shell is available — an absolute path is checked
85
+ * on disk, a bare name by trying to run it. Injectable for tests.
86
+ */
87
+ function chooseShell(platform = process.platform, has = shellExists) {
88
+ const file = (platform === "win32" ? ["bash", "sh"] : ["/bin/bash", "/bin/sh"]).find((c) => has(c));
89
+ if (!file) throw new NoPosixShellError(platform);
90
+ return {
91
+ file,
92
+ args: (c) => ["-c", c]
93
+ };
94
+ }
95
+ function shellExists(shell) {
96
+ if (shell.startsWith("/")) return existsSync(shell);
97
+ return spawnSync(shell, ["-c", "exit 0"], { stdio: "ignore" }).status === 0;
98
+ }
99
+ /**
100
+ * Run one command with the chosen shell (`chooseShell`), synchronously, in
101
+ * the current directory. A command killed by a signal or a timeout reports
102
+ * exit code 1 and says why on stderr — never 0.
103
+ */
104
+ const runInShell = (command) => {
105
+ const shell = chooseShell();
106
+ const r = spawnSync(shell.file, shell.args(command), {
107
+ encoding: "utf8",
108
+ maxBuffer: 64 * 1024 * 1024,
109
+ timeout: GATE_COMMAND_TIMEOUT_MS
110
+ });
111
+ const stderr = (r.stderr ?? "") + (r.error ? `\n[runner] ${r.error.message}` : "") + (r.signal ? `\n[runner] killed by ${r.signal}` : "");
112
+ return {
113
+ exitCode: typeof r.status === "number" ? r.status : 1,
114
+ stdout: r.stdout ?? "",
115
+ stderr
116
+ };
117
+ };
118
+ /** The report entry for one command and what running it produced. */
119
+ function toReportResult(command, outcome) {
120
+ const step = {
121
+ command: command.command,
122
+ exit_code: outcome.exitCode,
123
+ stdout_tail: tail(outcome.stdout),
124
+ stderr_tail: tail(outcome.stderr),
125
+ ...command.step_id ? { step_id: command.step_id } : {}
126
+ };
127
+ return {
128
+ gate_type: command.gate_type,
129
+ link_id: command.link_id,
130
+ status: outcome.exitCode === 0 ? "pass" : "fail",
131
+ output: tail(`${outcome.stdout}${outcome.stderr}`),
132
+ ...command.expected !== void 0 ? { expected: command.expected } : {},
133
+ ...command.step_id ? { step_id: command.step_id } : {},
134
+ ...command.rule_hash ? { rule_hash: command.rule_hash } : {},
135
+ steps: [step]
136
+ };
137
+ }
138
+ /**
139
+ * Run every command, in order, and build the `results[]` payload.
140
+ * `onBefore` is called BEFORE each command runs (to print it), `onEach`
141
+ * after, with its result.
142
+ */
143
+ function runLocalCommands(commands, run = runInShell, onEach, onBefore) {
144
+ return commands.map((command, index) => {
145
+ onBefore?.(command, index);
146
+ const result = toReportResult(command, run(command.command));
147
+ onEach?.(command, result);
148
+ return result;
149
+ });
150
+ }
151
+
152
+ //#endregion
153
+ //#region src/commands/gates/runHandler.ts
154
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
155
+ /**
156
+ * Seams for tests: the shell runner (production: `chooseShell`'s bash), and
157
+ * the shell resolution checked BEFORE anything runs (F-020).
158
+ */
159
+ const gatesRunDeps = {
160
+ run: runInShell,
161
+ resolveShell: () => chooseShell()
162
+ };
163
+ /**
164
+ * `levr gates run <issue>` — ENG-5967 F. Verify the deliverable's gates, run
165
+ * each `local_commands` entry exactly as returned, report the raw facts, and
166
+ * list any guided gates (which a person or agent performs and reports with
167
+ * `report_gate_results` step_results — this command never reports them).
168
+ *
169
+ * ENG-5967 F-008 — the commands come from the server, so nothing runs unseen:
170
+ * - every command is printed BEFORE it runs (to stderr under `--json`, so
171
+ * the JSON on stdout stays parseable);
172
+ * - `--dry-run` lists the commands and the report entries they would
173
+ * produce, and runs NOTHING.
174
+ * There is no local allowlist (user decision 2026-09-25, review R3-01): the
175
+ * SERVER validates every local command it renders (`validateGateCommand`)
176
+ * and returns one that fails as a verification error, never as a command.
177
+ *
178
+ * Exit code: 0 when the server's summary after the report is `all_pass`
179
+ * (or, with nothing to run, already all_pass); 1 otherwise, so a CI step can
180
+ * gate on it.
181
+ */
182
+ async function gatesRunHandler(flags, issue) {
183
+ if (flags.verbose) this.logger.setVerbose(true);
184
+ const out = (s) => this.process.stdout.write(`${s}\n`);
185
+ let auth;
186
+ try {
187
+ auth = await resolveToken();
188
+ } catch (err) {
189
+ this.logger.error(err instanceof Error ? err.message : "Authentication failed.");
190
+ this.process.exitCode = 1;
191
+ return;
192
+ }
193
+ configureClient(auth);
194
+ if (auth.type === "jwt") try {
195
+ const ws = await resolveWorkspace(flags["workspace-id"]);
196
+ client.setConfig({
197
+ ...client.getConfig(),
198
+ workspaceId: ws.workspaceId
199
+ });
200
+ } catch (err) {
201
+ this.logger.error(err instanceof Error ? err.message : "Workspace resolution failed.");
202
+ this.process.exitCode = 1;
203
+ return;
204
+ }
205
+ let issueId = issue;
206
+ if (!UUID_RE.test(issue)) {
207
+ const found = await issueFindAllV1({ query: {
208
+ "filter.identifier": [`$eq:${issue}`],
209
+ limit: 1
210
+ } });
211
+ const row = found.data?.data?.[0];
212
+ if (found.error || !row) {
213
+ this.logger.error(`Issue ${issue} not found in this workspace.`);
214
+ this.process.exitCode = 1;
215
+ return;
216
+ }
217
+ issueId = row.id;
218
+ }
219
+ const verified = await issueGateVerificationVerifyGatesV1({ path: { id: issueId } });
220
+ if (verified.error) {
221
+ this.logger.error(`verify-gates failed (${String(verified.response?.status ?? "unknown")}): ${JSON.stringify(verified.error)}`);
222
+ this.process.exitCode = 1;
223
+ return;
224
+ }
225
+ const summary = verified.data;
226
+ const commands = summary.local_commands ?? [];
227
+ const tasks = summary.manual_tasks ?? [];
228
+ const label = summary.deliverable ?? issue;
229
+ if (commands.length === 0) {
230
+ if (!flags.json) {
231
+ out(`${label}: no local commands to run (status ${summary.status ?? "unknown"}, ${summary.gates_passing ?? 0}/${summary.gates_total ?? 0} gates passing).`);
232
+ printManualTasks(out, tasks);
233
+ } else out(JSON.stringify({ verify: summary }, null, 2));
234
+ this.process.exitCode = summary.status === "all_pass" ? 0 : 1;
235
+ return;
236
+ }
237
+ if (flags["dry-run"]) {
238
+ out(JSON.stringify({
239
+ dry_run: true,
240
+ deliverable: label,
241
+ commands: commands.map((c) => ({
242
+ test_name: c.test_name ?? c.gate_type,
243
+ gate_type: c.gate_type,
244
+ link_id: c.link_id,
245
+ command: c.command,
246
+ ...c.expected !== void 0 ? { expected: c.expected } : {},
247
+ ...c.step_id ? { step_id: c.step_id } : {},
248
+ ...c.rule_hash ? { rule_hash: c.rule_hash } : {}
249
+ })),
250
+ report_entry_shape: {
251
+ gate_type: "<gate_type>",
252
+ link_id: "<link_id>",
253
+ status: "pass | fail (exit code 0 or not)",
254
+ output: "<last 4000 chars of stdout+stderr>",
255
+ step_id: "<step_id>",
256
+ rule_hash: "<rule_hash>",
257
+ steps: [{
258
+ command: "<command, exactly as above>",
259
+ exit_code: "<n>",
260
+ stdout_tail: "<last 4000 chars>",
261
+ stderr_tail: "<last 4000 chars>"
262
+ }]
263
+ }
264
+ }, null, 2));
265
+ if (!flags.json) printManualTasks(out, tasks);
266
+ return;
267
+ }
268
+ try {
269
+ gatesRunDeps.resolveShell();
270
+ } catch (error) {
271
+ if (!(error instanceof NoPosixShellError)) throw error;
272
+ this.logger.error(error.message);
273
+ this.process.exitCode = 1;
274
+ return;
275
+ }
276
+ const announce = (s) => flags.json ? this.process.stderr.write(`${s}\n`) : out(s);
277
+ const results = runLocalCommands(commands, gatesRunDeps.run, (_command, result) => {
278
+ if (flags.json) return;
279
+ out(` [exit ${result.steps[0].exit_code}]`);
280
+ }, (command, index) => {
281
+ announce(`[${index + 1}/${commands.length}] ${command.test_name ?? command.gate_type}: ${command.command}`);
282
+ });
283
+ const reported = await issueGateVerificationReportGateResultsV1({
284
+ path: { id: issueId },
285
+ body: { results }
286
+ });
287
+ if (reported.error) {
288
+ this.logger.error(`gate-results failed (${String(reported.response?.status ?? "unknown")}): ${JSON.stringify(reported.error)}`);
289
+ this.process.exitCode = 1;
290
+ return;
291
+ }
292
+ const after = reported.data;
293
+ if (flags.json) out(JSON.stringify({
294
+ results,
295
+ report: after
296
+ }, null, 2));
297
+ else {
298
+ out("");
299
+ out(`${after.deliverable ?? label}: ${after.status ?? "unknown"} — ${after.gates_passing ?? 0}/${after.gates_total ?? 0} gates passing`);
300
+ for (const g of after.gates ?? []) {
301
+ if (g.status === "pass") continue;
302
+ out(` ${String(g.status).toUpperCase()} ${g.test_name ?? g.gate_type}: ${String(g.actual ?? "").slice(0, 300)}`);
303
+ }
304
+ for (const r of after.receipts ?? []) if (!r.accepted) out(` REJECTED ${r.link_id}: ${r.reason ?? ""}`);
305
+ printManualTasks(out, tasks);
306
+ }
307
+ this.process.exitCode = after.status === "all_pass" ? 0 : 1;
308
+ }
309
+ function printManualTasks(out, tasks) {
310
+ if (tasks.length === 0) return;
311
+ out("");
312
+ out(`${tasks.length} guided gate(s) — perform each and report what you OBSERVED with report_gate_results step_results[] (not run by this command):`);
313
+ for (const t of tasks) {
314
+ out(` - [${t.link_id}] ${t.test_name ?? t.gate_type}: ${t.instruction}`);
315
+ if (t.expected) out(` expected: ${t.expected}`);
316
+ }
317
+ }
318
+
319
+ //#endregion
320
+ export { gatesRunHandler };
@@ -103,11 +103,11 @@ const zResponseLabelDto = z.object({
103
103
  archived_by: z.string().nullable().describe("")
104
104
  });
105
105
  const zUpdateProfileDto = z.object({
106
- profileName: z.string().optional(),
106
+ profileName: z.string().max(250).optional(),
107
107
  providerType: z.number().optional(),
108
- apiKey: z.string().optional(),
109
- baseUrl: z.string().nullable().optional(),
110
- modelName: z.string().optional(),
108
+ apiKey: z.string().max(1024).optional(),
109
+ baseUrl: z.string().max(1024).nullable().optional(),
110
+ modelName: z.string().max(1024).optional(),
111
111
  temperature: z.number().nullable().optional()
112
112
  });
113
113
  const zSuccessResponseDto = z.object({ success: z.boolean() });
@@ -554,8 +554,8 @@ const zA2aMessageBulkOperationV1Data = z.object({
554
554
  //#endregion
555
555
  //#region ../sdk/dist/gen/admin-member-profile/zod.js
556
556
  const zUpdateMemberProfileDto = z.object({
557
- name: z.string().nullable().optional(),
558
- username: z.string().nullable().optional()
557
+ name: z.string().max(256).nullable().optional(),
558
+ username: z.string().max(39).nullable().optional()
559
559
  });
560
560
  const zAdminMemberProfileUpdateMemberProfileV1Data = z.object({
561
561
  body: zUpdateMemberProfileDto,
@@ -2640,7 +2640,7 @@ const zSitesResponseDto = z.object({
2640
2640
  current_workspace_id: z.string().describe("")
2641
2641
  });
2642
2642
  const zSwitchWorkspaceDto = z.object({ workspace_id: z.string() });
2643
- const zCreateWorkspaceDto = z.object({ name: z.string() });
2643
+ const zCreateWorkspaceDto = z.object({ name: z.string().max(100) });
2644
2644
  const zAuthLoginV1Data = z.object({
2645
2645
  body: zLoginDto,
2646
2646
  url: z.literal("/v1/auth/login")
@@ -2664,8 +2664,8 @@ const zAuthCreateAdditionalWorkspaceV1Data = z.object({
2664
2664
  //#endregion
2665
2665
  //#region ../sdk/dist/gen/autocomplete/zod.js
2666
2666
  const zAutocompleteRequestDto = z.object({
2667
- prefix: z.string(),
2668
- suffix: z.string().optional(),
2667
+ prefix: z.string().max(1e4),
2668
+ suffix: z.string().max(1e4).optional(),
2669
2669
  context: z.object({
2670
2670
  files: z.array(z.string()).optional(),
2671
2671
  threadId: z.string().optional(),
@@ -5612,14 +5612,14 @@ const zChatRestoreV1Data = z.object({
5612
5612
  //#region ../sdk/dist/gen/ci-build-event/zod.js
5613
5613
  const zCIBuildEventDto = z.object({
5614
5614
  workspace_id: z.string(),
5615
- event_type: z.string(),
5616
- status: z.string(),
5617
- branch: z.string().optional(),
5618
- commit_sha: z.string().optional(),
5615
+ event_type: z.string().max(30),
5616
+ status: z.string().max(20),
5617
+ branch: z.string().max(100).optional(),
5618
+ commit_sha: z.string().max(40).optional(),
5619
5619
  error_count: z.number().optional(),
5620
5620
  duration_ms: z.number().optional(),
5621
- output: z.string().optional(),
5622
- triggered_by: z.string().optional(),
5621
+ output: z.string().max(1e4).optional(),
5622
+ triggered_by: z.string().max(50).optional(),
5623
5623
  project_id: z.string().optional()
5624
5624
  });
5625
5625
  const zCIBuildEventResponseDto = z.object({
@@ -6527,7 +6527,7 @@ const zClaudeFileChangeBulkOperationV1Data = z.object({
6527
6527
  //#endregion
6528
6528
  //#region ../sdk/dist/gen/claude-hooks/zod.js
6529
6529
  const zCaptureDto = z.object({
6530
- session_id: z.string(),
6530
+ session_id: z.string().max(100),
6531
6531
  hook_type: z.enum([
6532
6532
  "UserPromptSubmit",
6533
6533
  "PreToolUse",
@@ -6536,7 +6536,7 @@ const zCaptureDto = z.object({
6536
6536
  ]),
6537
6537
  prompt: z.string().optional(),
6538
6538
  response: z.string().optional(),
6539
- tool_name: z.string().optional(),
6539
+ tool_name: z.string().max(100).optional(),
6540
6540
  tool_input: z.record(z.string(), z.unknown()).optional(),
6541
6541
  tool_output: z.string().optional(),
6542
6542
  input_tokens: z.number().optional(),
@@ -6544,19 +6544,19 @@ const zCaptureDto = z.object({
6544
6544
  cache_creation_tokens: z.number().optional(),
6545
6545
  cache_read_tokens: z.number().optional(),
6546
6546
  raw_payload: z.record(z.string(), z.unknown()).optional(),
6547
- redirect_type: z.string().optional(),
6548
- error_type: z.string().optional()
6547
+ redirect_type: z.string().max(50).optional(),
6548
+ error_type: z.string().max(50).optional()
6549
6549
  });
6550
6550
  const zCheckToolDto = z.object({
6551
- session_id: z.string(),
6552
- tool_name: z.string()
6551
+ session_id: z.string().max(100),
6552
+ tool_name: z.string().max(100)
6553
6553
  });
6554
6554
  const zResolveCheckpointDto = z.object({
6555
- session_id: z.string(),
6556
- checkpoint_id: z.string()
6555
+ session_id: z.string().max(100),
6556
+ checkpoint_id: z.string().max(200)
6557
6557
  });
6558
6558
  const zCreateHookInjectionDto = z.object({
6559
- session_id: z.string().optional(),
6559
+ session_id: z.string().max(100).optional(),
6560
6560
  content: z.string(),
6561
6561
  mode: z.enum([
6562
6562
  "one_time",
@@ -6569,7 +6569,7 @@ const zCreateHookInjectionDto = z.object({
6569
6569
  });
6570
6570
  const zMarkUsedDto = z.object({ id: z.number() });
6571
6571
  const zRespondDto = z.object({
6572
- session_id: z.string(),
6572
+ session_id: z.string().max(100),
6573
6573
  content: z.string(),
6574
6574
  priority: z.number().optional()
6575
6575
  });
@@ -11073,28 +11073,28 @@ const zEnvironmentNodeDto = z.object({
11073
11073
  epoch: z.number().describe("")
11074
11074
  });
11075
11075
  const zCreateEnvironmentDto = z.object({
11076
- name: z.string(),
11077
- description: z.string().optional(),
11078
- location: z.string().optional(),
11076
+ name: z.string().max(250),
11077
+ description: z.string().max(65535).optional(),
11078
+ location: z.string().max(250).optional(),
11079
11079
  all_projects: z.boolean().optional(),
11080
11080
  resources: z.array(z.object({
11081
- resource: z.string().describe(""),
11082
- value: z.string().describe("")
11081
+ resource: z.string().max(250).describe(""),
11082
+ value: z.string().max(4096).describe("")
11083
11083
  })).optional(),
11084
11084
  exploration_ids: z.array(z.string()).optional()
11085
11085
  });
11086
11086
  const zUpdateEnvironmentDto = z.object({
11087
- name: z.string().optional(),
11088
- description: z.string().nullable(),
11089
- location: z.string().nullable(),
11087
+ name: z.string().max(250).optional(),
11088
+ description: z.string().max(65535).nullable(),
11089
+ location: z.string().max(250).nullable(),
11090
11090
  all_projects: z.boolean().optional(),
11091
11091
  add_resources: z.array(z.object({
11092
- resource: z.string().describe(""),
11093
- value: z.string().describe("")
11092
+ resource: z.string().max(250).describe(""),
11093
+ value: z.string().max(4096).describe("")
11094
11094
  })).optional(),
11095
11095
  remove_resources: z.array(z.object({
11096
- resource: z.string().describe(""),
11097
- value: z.string().describe("")
11096
+ resource: z.string().max(250).describe(""),
11097
+ value: z.string().max(4096).describe("")
11098
11098
  })).optional(),
11099
11099
  add_exploration_ids: z.array(z.string()).optional(),
11100
11100
  remove_exploration_ids: z.array(z.string()).optional()
@@ -11258,7 +11258,7 @@ const zExplorationNodeDto = z.object({
11258
11258
  }).optional()
11259
11259
  });
11260
11260
  const zCreateExplorationDto = z.object({
11261
- name: z.string(),
11261
+ name: z.string().max(250),
11262
11262
  mission: z.string().nullable(),
11263
11263
  status_id: z.string().nullable(),
11264
11264
  team_id: z.string().nullable(),
@@ -11266,7 +11266,7 @@ const zCreateExplorationDto = z.object({
11266
11266
  virtual: z.unknown().optional()
11267
11267
  });
11268
11268
  const zUpdateExplorationDto = z.object({
11269
- name: z.string().optional(),
11269
+ name: z.string().max(250).optional(),
11270
11270
  mission: z.string().nullable(),
11271
11271
  status_id: z.string().nullable(),
11272
11272
  is_complete: z.boolean().optional(),
@@ -11393,7 +11393,7 @@ const zCreateExplorationItemDto = z.object({
11393
11393
  exploration_id: z.string().optional(),
11394
11394
  result: z.string().nullable(),
11395
11395
  body_md: z.string().nullable(),
11396
- note_type: z.string().nullable(),
11396
+ note_type: z.string().max(50).nullable(),
11397
11397
  severity: z.number().nullable(),
11398
11398
  elapsed: z.number().nullable(),
11399
11399
  status_id: z.string().nullable(),
@@ -11403,7 +11403,7 @@ const zCreateExplorationItemDto = z.object({
11403
11403
  const zUpdateExplorationItemDto = z.object({
11404
11404
  result: z.string().nullable(),
11405
11405
  body_md: z.string().nullable(),
11406
- note_type: z.string().nullable(),
11406
+ note_type: z.string().max(50).nullable(),
11407
11407
  severity: z.number().nullable(),
11408
11408
  elapsed: z.number().nullable(),
11409
11409
  status_id: z.string().nullable(),
@@ -11436,7 +11436,7 @@ const zGenerateIssueDraftResponseDto = z.object({
11436
11436
  priority: z.number()
11437
11437
  });
11438
11438
  const zPromoteItemToTestDto = z.object({
11439
- name: z.string().optional().describe(""),
11439
+ name: z.string().max(500).optional().describe(""),
11440
11440
  automation_type: z.enum([
11441
11441
  "manual",
11442
11442
  "check",
@@ -11452,7 +11452,7 @@ const zPromoteItemToTestDto = z.object({
11452
11452
  })).optional().describe("")
11453
11453
  });
11454
11454
  const zPromoteItemToIssueDto = z.object({
11455
- title: z.string().optional().describe(""),
11455
+ title: z.string().max(500).optional().describe(""),
11456
11456
  description: z.string().optional().describe(""),
11457
11457
  priority: z.number().optional().describe(""),
11458
11458
  severity: z.number().optional().describe(""),
@@ -13178,25 +13178,25 @@ const zBulkFolderOperationDto = z.object({
13178
13178
  ]).describe(""),
13179
13179
  id: z.string().optional().describe(""),
13180
13180
  data: z.union([z.object({
13181
- name: z.string(),
13181
+ name: z.string().max(250),
13182
13182
  description: z.string().optional(),
13183
13183
  virtual: z.unknown().optional(),
13184
13184
  assignee_id: z.string().optional(),
13185
13185
  parent_id: z.string().nullable().optional(),
13186
13186
  sequence: z.string().optional(),
13187
- labels: z.array(z.string()).optional(),
13187
+ labels: z.array(z.string().max(80)).optional(),
13188
13188
  origin: z.enum(["authored", "automation"]).optional(),
13189
13189
  entity_type: z.enum(["test", "run"]).optional(),
13190
13190
  is_root: z.unknown().optional().describe("")
13191
13191
  }), z.object({
13192
- name: z.string().optional(),
13192
+ name: z.string().max(250).optional(),
13193
13193
  description: z.string().optional(),
13194
13194
  virtual: z.unknown().optional(),
13195
13195
  assignee_id: z.string().optional(),
13196
13196
  parent_id: z.string().nullable().optional(),
13197
13197
  sequence: z.string().optional(),
13198
- add_labels: z.array(z.string()).optional(),
13199
- remove_labels: z.array(z.string()).optional(),
13198
+ add_labels: z.array(z.string().max(80)).optional(),
13199
+ remove_labels: z.array(z.string().max(80)).optional(),
13200
13200
  is_root: z.unknown().optional().describe("")
13201
13201
  })]).optional().describe(""),
13202
13202
  tx_id: z.string().describe("")
@@ -13233,26 +13233,26 @@ const zBulkFolderResponseDto = z.object({
13233
13233
  })
13234
13234
  });
13235
13235
  const zCreateFolderDto = z.object({
13236
- name: z.string(),
13236
+ name: z.string().max(250),
13237
13237
  description: z.string().optional(),
13238
13238
  virtual: z.unknown().optional(),
13239
13239
  assignee_id: z.string().optional(),
13240
13240
  parent_id: z.string().nullable().optional(),
13241
13241
  sequence: z.string().optional(),
13242
- labels: z.array(z.string()).optional(),
13242
+ labels: z.array(z.string().max(80)).optional(),
13243
13243
  origin: z.enum(["authored", "automation"]).optional(),
13244
13244
  entity_type: z.enum(["test", "run"]).optional(),
13245
13245
  is_root: z.unknown().optional().describe("")
13246
13246
  });
13247
13247
  const zUpdateFolderDto = z.object({
13248
- name: z.string().optional(),
13248
+ name: z.string().max(250).optional(),
13249
13249
  description: z.string().optional(),
13250
13250
  virtual: z.unknown().optional(),
13251
13251
  assignee_id: z.string().optional(),
13252
13252
  parent_id: z.string().nullable().optional(),
13253
13253
  sequence: z.string().optional(),
13254
- add_labels: z.array(z.string()).optional(),
13255
- remove_labels: z.array(z.string()).optional(),
13254
+ add_labels: z.array(z.string().max(80)).optional(),
13255
+ remove_labels: z.array(z.string().max(80)).optional(),
13256
13256
  is_root: z.unknown().optional().describe("")
13257
13257
  });
13258
13258
  const zFolderFindAllV1Data = z.object({
@@ -15060,9 +15060,9 @@ const zHealthMemoryDiagnosticsData = z.object({ url: z.literal("/health/memory")
15060
15060
  //#region ../sdk/dist/gen/help/zod.js
15061
15061
  const zHelpSearchV1Data = z.object({
15062
15062
  query: z.object({
15063
- "q": z.string(),
15063
+ "q": z.string().max(200),
15064
15064
  "limit": z.number().optional(),
15065
- "category": z.string().optional(),
15065
+ "category": z.string().max(100).optional(),
15066
15066
  "mode": z.enum([
15067
15067
  "hybrid",
15068
15068
  "semantic",
@@ -15124,10 +15124,8 @@ const zImportCreateV1Body = z.object({
15124
15124
  "cucumber-json",
15125
15125
  "ctrf-json"
15126
15126
  ]).optional().describe(""),
15127
- parent_folder_id: z.string().optional().describe(""),
15128
- run_name: z.string().optional().describe(""),
15129
- update_mode: z.enum(["update", "create_new"]).optional().describe(""),
15130
- automation_source: z.string().optional().describe(""),
15127
+ run_name: z.string().max(250).optional().describe(""),
15128
+ automation_source: z.string().max(100).optional().describe(""),
15131
15129
  automation_source_id: z.string().optional().describe(""),
15132
15130
  import_metadata: z.string().optional().describe("")
15133
15131
  });
@@ -15630,6 +15628,22 @@ const zIntegrationTokenDisconnectGithubV1Data = z.object({ url: z.literal("/v1/i
15630
15628
  const zIntegrationTokenDisconnectGithubUserV1Data = z.object({ url: z.literal("/v1/integrations/github/disconnect_user") });
15631
15629
  const zIntegrationTokenIssueConnectIntentV1Data = z.object({ url: z.literal("/v1/integrations/github/connect-intent") });
15632
15630
 
15631
+ //#endregion
15632
+ //#region ../sdk/dist/gen/issue/functions.js
15633
+ /**
15634
+ * Retrieve a paginated list of issues with optional filtering, sorting, and searching capabilities.
15635
+ */
15636
+ const issueFindAllV1 = (options) => {
15637
+ return (options?.client ?? client).get({
15638
+ security: [{
15639
+ scheme: "bearer",
15640
+ type: "http"
15641
+ }],
15642
+ url: "/v1/issue",
15643
+ ...options
15644
+ });
15645
+ };
15646
+
15633
15647
  //#endregion
15634
15648
  //#region ../sdk/dist/gen/issue/zod.js
15635
15649
  const zCreateIssueDto = z.object({
@@ -16169,7 +16183,7 @@ const zIssueAutomationTestEvidenceBulkOperationV1Data = z.object({
16169
16183
  //#endregion
16170
16184
  //#region ../sdk/dist/gen/issue-deduplicate/zod.js
16171
16185
  const zMergeIntoDto = z.object({ patch: z.object({
16172
- title: z.string().optional(),
16186
+ title: z.string().max(500).optional(),
16173
16187
  description: z.string().nullable().optional(),
16174
16188
  priority: z.number().optional(),
16175
16189
  due_date: z.string().nullable().optional(),
@@ -16210,6 +16224,35 @@ const zIssueDeduplicateDuplicateVerdictV1Data = z.object({
16210
16224
  //#region ../sdk/dist/gen/issue-export/zod.js
16211
16225
  const zIssueExportExportIssueV1Data = z.object({ url: z.literal("/v1/issue/export") });
16212
16226
 
16227
+ //#endregion
16228
+ //#region ../sdk/dist/gen/issue-gate-verification/functions.js
16229
+ /**
16230
+ * Split execution model: API gates run server-side, shell gates are returned as local_commands for the caller to execute locally and report back via POST /v1/issue/:id/gate-results.
16231
+ */
16232
+ const issueGateVerificationVerifyGatesV1 = (options) => {
16233
+ return (options?.client ?? client).post({
16234
+ security: [{
16235
+ scheme: "bearer",
16236
+ type: "http"
16237
+ }],
16238
+ url: "/v1/issue/{id}/verify-gates",
16239
+ ...options
16240
+ });
16241
+ };
16242
+ /**
16243
+ * After executing local_commands from verify-gates, report results here. Updates gate_instance records, creates gate_result audit trail, and posts verification summary comment to the issue. Report RAW per-step facts in `steps` (exit code, stdout/stderr tails); the server derives the verdict from them. `levr gates run <issue>` does verify → run → report for you.
16244
+ */
16245
+ const issueGateVerificationReportGateResultsV1 = (options) => {
16246
+ return (options?.client ?? client).post({
16247
+ security: [{
16248
+ scheme: "bearer",
16249
+ type: "http"
16250
+ }],
16251
+ url: "/v1/issue/{id}/gate-results",
16252
+ ...options
16253
+ });
16254
+ };
16255
+
16213
16256
  //#endregion
16214
16257
  //#region ../sdk/dist/gen/issue-gate-verification/zod.js
16215
16258
  const zIssueGateVerificationBatchVerifyGatesV1Body = z.object({
@@ -16249,7 +16292,7 @@ const zIssueGateVerificationDeployGatesV1Body = z.object({
16249
16292
  tests_by_deliverable: z.record(z.string(), z.array(z.object({
16250
16293
  name: z.string(),
16251
16294
  required: z.boolean().optional().describe(""),
16252
- advisory_reason: z.string().optional().describe(""),
16295
+ advisory_reason: z.string().max(2e3).optional().describe(""),
16253
16296
  data: z.record(z.string(), z.unknown()).optional()
16254
16297
  }))).describe(""),
16255
16298
  link_template: z.record(z.string(), z.string()),
@@ -16257,7 +16300,8 @@ const zIssueGateVerificationDeployGatesV1Body = z.object({
16257
16300
  replace_existing: z.boolean().optional(),
16258
16301
  rename_reused: z.boolean().optional(),
16259
16302
  test_origin: z.string().optional(),
16260
- validate: z.boolean().optional()
16303
+ validate: z.boolean().optional(),
16304
+ change_reason: z.string().max(2e3).optional().describe("")
16261
16305
  });
16262
16306
  const zIssueGateVerificationGateStatusV1Data = z.object({
16263
16307
  path: z.object({ "id": z.string() }),
@@ -17214,7 +17258,7 @@ const zTransitionIssueDto = z.object({
17214
17258
  verification_override: z.array(z.object({
17215
17259
  link_id: z.string(),
17216
17260
  kind: z.enum(["override", "not_applicable"]),
17217
- reason: z.string()
17261
+ reason: z.string().max(2e3)
17218
17262
  })).optional().describe(""),
17219
17263
  batch_scope: z.array(z.string()).optional().describe("")
17220
17264
  });
@@ -17661,7 +17705,7 @@ const zJiraRefreshProjectsV1Data = z.object({
17661
17705
  const zJiraSearchCatalogueV1Data = z.object({
17662
17706
  path: z.object({ "id": z.string() }),
17663
17707
  query: z.object({
17664
- "query": z.string().optional(),
17708
+ "query": z.string().max(250).optional(),
17665
17709
  "page": z.number().optional(),
17666
17710
  "limit": z.number().optional()
17667
17711
  }).optional(),
@@ -19419,7 +19463,7 @@ const zLabelAssignedTestBulkOperationV1Data = z.object({
19419
19463
  //#endregion
19420
19464
  //#region ../sdk/dist/gen/layer0/zod.js
19421
19465
  const zStartLayer0RunDto = z.object({ topic_id: z.string().describe("") });
19422
- const zPlanTopicDto = z.object({ questions: z.array(z.string()).describe("") });
19466
+ const zPlanTopicDto = z.object({ questions: z.array(z.string().max(2e3)).describe("") });
19423
19467
  const zQueryCorpusDto = z.object({
19424
19468
  query: z.string().describe(""),
19425
19469
  query_type: z.enum([
@@ -19495,7 +19539,7 @@ const zRecordCaptureDto = z.object({
19495
19539
  confidence_source: z.number().optional().describe(""),
19496
19540
  recency: z.string().optional().describe(""),
19497
19541
  provenance_chain: z.string().optional().describe(""),
19498
- title: z.string().optional().describe("")
19542
+ title: z.string().max(500).optional().describe("")
19499
19543
  });
19500
19544
  const zAcknowledgeDimensionDto = z.object({
19501
19545
  capture_ids: z.array(z.string()).optional().describe(""),
@@ -20619,7 +20663,7 @@ const zPasswordResetCompleteResetV1Data = z.object({
20619
20663
  //#endregion
20620
20664
  //#region ../sdk/dist/gen/pat/zod.js
20621
20665
  const zCreatePatDto = z.object({
20622
- name: z.string(),
20666
+ name: z.string().max(250),
20623
20667
  expires_in_days: z.number().optional().describe("")
20624
20668
  });
20625
20669
  const zPatCreatedResponseDto = z.object({
@@ -21432,11 +21476,11 @@ const zProductPlanFindOneV1Data = z.object({
21432
21476
  //#endregion
21433
21477
  //#region ../sdk/dist/gen/profile/zod.js
21434
21478
  const zCreateProfileDto = z.object({
21435
- profileName: z.string(),
21479
+ profileName: z.string().max(250),
21436
21480
  providerType: z.number(),
21437
- apiKey: z.string(),
21438
- baseUrl: z.string().optional(),
21439
- modelName: z.string(),
21481
+ apiKey: z.string().max(1024),
21482
+ baseUrl: z.string().max(1024).optional(),
21483
+ modelName: z.string().max(1024),
21440
21484
  temperature: z.number().optional()
21441
21485
  });
21442
21486
  const zCreateProfileResponseDto = z.object({
@@ -22926,19 +22970,19 @@ const zInternalRcaConfigBulkOperationV1Data = z.object({
22926
22970
  //#region ../sdk/dist/gen/qinetic-signal/zod.js
22927
22971
  const zQSignalDto = z.object({
22928
22972
  workspace_id: z.string(),
22929
- signal_type: z.string(),
22973
+ signal_type: z.string().max(50),
22930
22974
  severity: z.enum([
22931
22975
  "critical",
22932
22976
  "high",
22933
22977
  "medium",
22934
22978
  "low"
22935
22979
  ]),
22936
- source: z.string(),
22937
- message: z.string(),
22980
+ source: z.string().max(100),
22981
+ message: z.string().max(1e3),
22938
22982
  context: z.record(z.string(), z.unknown()).optional(),
22939
- fingerprint: z.string().optional(),
22940
- commit_sha: z.string().optional(),
22941
- branch: z.string().optional(),
22983
+ fingerprint: z.string().max(64).optional(),
22984
+ commit_sha: z.string().max(40).optional(),
22985
+ branch: z.string().max(100).optional(),
22942
22986
  project_id: z.string().optional()
22943
22987
  });
22944
22988
  const zQSignalResponseDto = z.object({
@@ -24514,14 +24558,14 @@ const zCreateRunDto = z.object({
24514
24558
  test_scope_id: z.string().nullable(),
24515
24559
  cycle_id: z.string().nullable(),
24516
24560
  auto_add_tests_to_team: z.boolean().optional(),
24517
- name: z.string().optional(),
24561
+ name: z.string().max(250).optional(),
24518
24562
  triggered_by: z.enum([
24519
24563
  "user",
24520
24564
  "ci",
24521
24565
  "schedule",
24522
24566
  "pr"
24523
24567
  ]).optional(),
24524
- host_name: z.string().nullable(),
24568
+ host_name: z.string().max(250).nullable(),
24525
24569
  environment_ids: z.array(z.string()).optional(),
24526
24570
  test_inclusions: z.array(z.object({
24527
24571
  test_id: z.string(),
@@ -24529,19 +24573,19 @@ const zCreateRunDto = z.object({
24529
24573
  required: z.boolean().optional()
24530
24574
  })).optional(),
24531
24575
  folder_id: z.string().nullable(),
24532
- sequence: z.string().optional(),
24576
+ sequence: z.string().max(255).optional(),
24533
24577
  required: z.enum(["all", "none"]).optional(),
24534
24578
  required_test_ids: z.array(z.string()).optional(),
24535
24579
  not_required_test_ids: z.array(z.string()).optional()
24536
24580
  });
24537
24581
  const zUpdateRunDto = z.object({
24538
- name: z.string().optional(),
24539
- host_name: z.string().nullable(),
24582
+ name: z.string().max(250).optional(),
24583
+ host_name: z.string().max(250).nullable(),
24540
24584
  is_complete: z.boolean().optional(),
24541
24585
  project_id: z.string().nullable(),
24542
24586
  cycle_id: z.string().nullable(),
24543
24587
  folder_id: z.string().nullable().optional(),
24544
- sequence: z.string().optional(),
24588
+ sequence: z.string().max(255).optional(),
24545
24589
  parent_run_id: z.unknown().optional()
24546
24590
  });
24547
24591
  const zRunWithContentDto = z.object({
@@ -24794,8 +24838,8 @@ const zRefreshFolderResultDto = z.object({
24794
24838
  unchanged: z.number()
24795
24839
  });
24796
24840
  const zCloneRunDto = z.object({
24797
- name: z.string(),
24798
- note: z.string().optional(),
24841
+ name: z.string().max(250),
24842
+ note: z.string().max(250).optional(),
24799
24843
  scope_mode: z.enum(["snapshot", "rescope"])
24800
24844
  });
24801
24845
  const zBulkRunOperationDto = z.object({
@@ -25758,7 +25802,7 @@ const zSchemaBrowserClearErdPositionsV1Data = z.object({
25758
25802
  //#endregion
25759
25803
  //#region ../sdk/dist/gen/search/zod.js
25760
25804
  const zSemanticSearchDto = z.object({
25761
- query: z.string(),
25805
+ query: z.string().max(2e3),
25762
25806
  workspace_id: z.string(),
25763
25807
  entity_type: z.enum([
25764
25808
  "issue",
@@ -25796,7 +25840,7 @@ const zSearchSemanticSearchV1Data = z.object({
25796
25840
  });
25797
25841
  const zSearchFindUserV1Data = z.object({
25798
25842
  query: z.object({
25799
- "query": z.string(),
25843
+ "query": z.string().max(200),
25800
25844
  "team_id": z.string().optional(),
25801
25845
  "include_inactive": z.boolean().optional()
25802
25846
  }).optional(),
@@ -27739,11 +27783,8 @@ const zOmittedHandleQueryV1Data = z.object({ url: z.literal("/v1/cde/steward/que
27739
27783
  const zOpenStreamingRunDto = z.object({
27740
27784
  id: z.string().optional().describe(""),
27741
27785
  team_id: z.string().optional().describe(""),
27742
- automation_source: z.string().describe(""),
27743
- run_name: z.string().optional().describe(""),
27744
- parent_folder_id: z.string().optional().describe(""),
27745
- parent_folder_name: z.string().optional().describe(""),
27746
- update_mode: z.enum(["update", "create_new"]).optional().describe(""),
27786
+ automation_source: z.string().max(100).describe(""),
27787
+ run_name: z.string().max(250).optional().describe(""),
27747
27788
  metadata: z.record(z.string(), z.unknown()).optional().describe("")
27748
27789
  });
27749
27790
  const zStreamingRunResponseDto = z.object({
@@ -28369,7 +28410,7 @@ const zCreateTestDto = z.object({
28369
28410
  labels: z.array(z.string()).optional()
28370
28411
  });
28371
28412
  const zUpdateTestDto = z.object({
28372
- name: z.string().optional(),
28413
+ name: z.string().max(250).optional(),
28373
28414
  automation_status: z.enum([
28374
28415
  "not_automated",
28375
28416
  "to_automate",
@@ -28449,8 +28490,8 @@ const zUpdateTestDto = z.object({
28449
28490
  link_to_id: z.string().optional(),
28450
28491
  unlink: z.boolean().optional()
28451
28492
  }).optional(),
28452
- add_labels: z.array(z.string()).optional(),
28453
- remove_labels: z.array(z.string()).optional()
28493
+ add_labels: z.array(z.string().max(80)).optional(),
28494
+ remove_labels: z.array(z.string().max(80)).optional()
28454
28495
  });
28455
28496
  const zTestBulkOperationDto = z.object({
28456
28497
  op: z.enum([
@@ -28773,9 +28814,9 @@ const zPreviewImportResponseDto = z.object({
28773
28814
  "boolean",
28774
28815
  "unknown"
28775
28816
  ]).optional(),
28776
- labelPrefix: z.string().optional().describe(""),
28777
- descriptionHeading: z.string().optional().describe(""),
28778
- teamQualifier: z.string().optional().describe(""),
28817
+ labelPrefix: z.string().max(60).optional().describe(""),
28818
+ descriptionHeading: z.string().max(80).optional().describe(""),
28819
+ teamQualifier: z.string().max(80).optional().describe(""),
28779
28820
  team_id: z.string().optional().describe("")
28780
28821
  })),
28781
28822
  missing_required: z.array(z.string()),
@@ -28890,9 +28931,9 @@ const zCommitImportDto = z.object({
28890
28931
  "boolean",
28891
28932
  "unknown"
28892
28933
  ]).optional(),
28893
- labelPrefix: z.string().optional().describe(""),
28894
- descriptionHeading: z.string().optional().describe(""),
28895
- teamQualifier: z.string().optional().describe(""),
28934
+ labelPrefix: z.string().max(60).optional().describe(""),
28935
+ descriptionHeading: z.string().max(80).optional().describe(""),
28936
+ teamQualifier: z.string().max(80).optional().describe(""),
28896
28937
  team_id: z.string().optional().describe("")
28897
28938
  })).optional().describe(""),
28898
28939
  assignee_plan: z.object({
@@ -29775,12 +29816,12 @@ const zCaptureEventDto = z.object({
29775
29816
  }).optional().describe(""),
29776
29817
  raw_payload: z.record(z.string(), z.unknown()).optional().describe(""),
29777
29818
  duration_ms: z.number().optional().describe(""),
29778
- agent_key: z.string().optional().describe(""),
29779
- agent_id: z.string().optional().describe(""),
29780
- parent_session_id: z.string().optional().describe(""),
29819
+ agent_key: z.string().max(100).optional().describe(""),
29820
+ agent_id: z.string().max(100).optional().describe(""),
29821
+ parent_session_id: z.string().max(100).optional().describe(""),
29781
29822
  is_sub_agent: z.boolean().optional().describe(""),
29782
- model_name: z.string().optional().describe(""),
29783
- issue_identifier: z.string().optional().describe("")
29823
+ model_name: z.string().max(100).optional().describe(""),
29824
+ issue_identifier: z.string().max(50).optional().describe("")
29784
29825
  });
29785
29826
  const zCaptureResultDto = z.object({
29786
29827
  capture_id: z.string().describe(""),
@@ -30666,14 +30707,14 @@ const zUserPreferenceRestoreV1Data = z.object({
30666
30707
  //#endregion
30667
30708
  //#region ../sdk/dist/gen/verify/zod.js
30668
30709
  const zVerifyDigestRequestDto = z.object({
30669
- entity: z.string().describe(""),
30710
+ entity: z.string().max(100).describe(""),
30670
30711
  level: z.union([z.number(), z.number()]).optional().describe(""),
30671
30712
  due_reason: z.enum([
30672
30713
  "interval",
30673
30714
  "dirty",
30674
30715
  "never_stamped"
30675
30716
  ]).optional().describe(""),
30676
- pass_id: z.string().optional().describe("")
30717
+ pass_id: z.string().max(64).optional().describe("")
30677
30718
  });
30678
30719
  const zFoldedDigestDto = z.object({
30679
30720
  n: z.number().describe(""),
@@ -30695,9 +30736,9 @@ const zVerifyDigestResponseDto = z.object({
30695
30736
  cached: z.boolean().describe("")
30696
30737
  });
30697
30738
  const zVerifyBucketRowsRequestDto = z.object({
30698
- entity: z.string().describe(""),
30739
+ entity: z.string().max(100).describe(""),
30699
30740
  buckets: z.array(z.string()).describe(""),
30700
- after: z.string().optional().describe(""),
30741
+ after: z.string().max(64).optional().describe(""),
30701
30742
  limit: z.number().optional().describe("")
30702
30743
  });
30703
30744
  const zRowRefDto = z.object({
@@ -30709,7 +30750,7 @@ const zVerifyBucketRowsResponseDto = z.object({
30709
30750
  next: z.string().nullable().describe("")
30710
30751
  });
30711
30752
  const zVerifyRowsRequestDto = z.object({
30712
- entity: z.string().describe(""),
30753
+ entity: z.string().max(100).describe(""),
30713
30754
  ids: z.array(z.string()).describe("")
30714
30755
  });
30715
30756
  const zVerifyRowsResponseDto = z.object({
@@ -31550,9 +31591,9 @@ const zWorkspaceDataGetDataV1Data = z.object({ url: z.literal("/v1/workspace-dat
31550
31591
  //#endregion
31551
31592
  //#region ../sdk/dist/gen/workspace-description/zod.js
31552
31593
  const zSuggestDescriptionRequestDto = z.object({
31553
- workspace_name: z.string(),
31554
- company_name: z.string().optional(),
31555
- company_url: z.string().optional(),
31594
+ workspace_name: z.string().max(250),
31595
+ company_name: z.string().max(250).optional(),
31596
+ company_url: z.string().max(250).optional(),
31556
31597
  existing_descriptions: z.array(z.string()).optional()
31557
31598
  });
31558
31599
  const zSuggestDescriptionResponseDto = z.object({ suggestion: z.string().nullable() });
@@ -31989,9 +32030,7 @@ async function uploadImport(options) {
31989
32030
  file: options.file,
31990
32031
  team_id: options.teamId,
31991
32032
  format: options.format,
31992
- parent_folder_id: options.parentFolderId,
31993
32033
  run_name: options.runName,
31994
- update_mode: options.updateMode,
31995
32034
  automation_source: options.automationSource,
31996
32035
  automation_source_id: options.automationSourceId,
31997
32036
  import_metadata: options.importMetadata ? JSON.stringify(options.importMetadata) : void 0
@@ -32019,4 +32058,4 @@ function tryReadMessage(err) {
32019
32058
  }
32020
32059
 
32021
32060
  //#endregion
32022
- export { authGetProfileV1, authGetSitesV1, client, configureClient, teamFindAllV1, testCaseImportCommitV1, testCaseImportPreviewV1, uploadImport };
32061
+ export { authGetProfileV1, authGetSitesV1, client, configureClient, issueFindAllV1, issueGateVerificationReportGateResultsV1, issueGateVerificationVerifyGatesV1, teamFindAllV1, testCaseImportCommitV1, testCaseImportPreviewV1, uploadImport };
@@ -1,5 +1,5 @@
1
1
  import "./env-CHeKHu5S.js";
2
- import { authGetSitesV1, configureClient } from "./sdk-client-CQa-x1zl.js";
2
+ import { authGetSitesV1, configureClient } from "./sdk-client-DHD7tgY0.js";
3
3
  import { saveWorkspace } from "./workspace-store-DDOxnut1.js";
4
4
  import "./token-refresh-Cu5RpkLJ.js";
5
5
  import { resolveToken } from "./resolve-token-DbQsmn03.js";
@@ -1,5 +1,5 @@
1
1
  import { getApiUrl, getPatToken, readCredentials } from "./env-CHeKHu5S.js";
2
- import { authGetProfileV1, configureClient } from "./sdk-client-CQa-x1zl.js";
2
+ import { authGetProfileV1, configureClient } from "./sdk-client-DHD7tgY0.js";
3
3
  import { isTokenExpired } from "./token-refresh-Cu5RpkLJ.js";
4
4
  import chalk from "chalk";
5
5
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@levr-one/cli",
3
- "version": "0.9.29",
3
+ "version": "0.10.0",
4
4
  "description": "The command-line interface for Levr",
5
5
  "type": "module",
6
6
  "license": "MIT",