@cantinasecurity/apex-cli 0.1.15 → 0.1.17

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.
@@ -25,26 +25,28 @@ Recommended workflow:
25
25
  4. Call `apex-doctor` before starting a scan if workspace binding or source planning might be unclear.
26
26
  5. If the directory is not bound to the right workspace, call `apex-workspaces` and `apex-workspace-use`.
27
27
  6. Use `apex-scan`, `apex-status`, `apex-scans`, `apex-findings`, and `apex-export-findings` for the scan lifecycle.
28
- 7. For PR scans, call `apex-scan` with `mode: "pr"` and `pullRequests`.
29
- 8. Use `apex-finding-comment` and `apex-finding-feedback` when the user wants to leave review notes or valid/invalid feedback on a finding.
30
- 9. For fix reviews, call `apex-finding-fix-review`. Pass `fixPrUrls` for a PR-based review, or omit them to review the current repository state when Bedrock has original scan repository context.
28
+ 7. For Lite scans, call `apex-scan` with `mode: "lite"` only when the company has Lite Scan beta access and the sources are provider-backed.
29
+ 8. For PR scans, call `apex-scan` with `mode: "pr"` and `pullRequests`.
30
+ 9. Use `apex-finding-comment` and `apex-finding-feedback` when the user wants to leave review notes or valid/invalid feedback on a finding.
31
+ 10. For fix reviews, call `apex-finding-fix-review`. Pass `fixPrUrls` for a PR-based review, or omit them to review the current repository state when Bedrock has original scan repository context.
31
32
 
32
33
  If the Apex MCP server is not configured, fall back to the local CLI:
33
34
 
34
35
  - Prefer scripted commands over the interactive shell.
35
36
  - Service-key management has no MCP tools. Never ask a user to paste a service key into a prompt, and never place one in an MCP call, tool result, source file, or log.
36
- - If a user explicitly needs a new service key, tell them to run `apex login` if needed, then run `apex service-key create --company <company> --name <name> --scope <scope[,scope]>` directly in their own terminal. Use only the required scopes: `scans:create` to trigger, `scans:read` to poll status, and `findings:read` to retrieve findings. A P1-only adapter can use `--scope scans:read,findings:read`; omitting `--scope` grants all three. Service-key commands never initiate login; the secret is shown once. `list` and `revoke` also require an explicit `--company`.
37
+ - If a user explicitly needs a new service key, tell them to run `apex login` if needed, then run `apex service-key create --name <name> --scope <scope[,scope]>` directly in their own terminal. Use only the required scopes: `scans:create` to trigger, `scans:read` to poll status, and `findings:read` to retrieve findings. A P1-only adapter can use `--scope scans:read,findings:read`; omitting `--scope` grants all three. The CLI automatically selects the company when only one is available and prompts when there are several; use `--company <id-or-handle>` to skip that prompt or resolve a non-interactive command. Service-key commands never initiate login, and the secret is shown once.
37
38
  - For a headless HTTP adapter, read the service key from a secret-backed environment variable, send it as a bearer token to `/api/apex/v1`, and redact it from errors and logs. Do not shell out to `apex` or launch MCP from the adapter.
38
39
  - Hosted API v1 requires the GitHub repository to be linked to an active Apex workspace. It never creates or mutates workspaces; use optional `workspaceId` to disambiguate matches and treat zero or ambiguous matches as HTTP `409` setup errors.
39
40
  - Hosted scan triggers require `Idempotency-Key`. Reuse one stable key only for an identical transport/timeout/5xx retry. After correcting a definitive 4xx response, or for any new intended scan, use a new key.
40
41
  - Use `--non-interactive` and `--no-open` for automation-friendly CLI calls.
41
42
  - Use `--json` whenever structured output is helpful.
42
- - `apex credits` reports standard credits plus audit and fix review scan entitlements when Bedrock returns those balances.
43
+ - `apex credits` reports standard credits plus audit, fix review, and Lite scan entitlements when Bedrock returns those balances.
43
44
  - Work from the target repository directory so Apex can resolve `.apex/workspace.json`.
44
45
  - `apex scan` scans the current working directory by default; pass `--repo` only when the user asks to scan explicit alternate roots.
45
46
  - `apex-doctor` reports whether Apex will use remote materialization or a local snapshot upload for each selected source.
46
47
  - Plain local directories and dirty git worktrees can scan through local snapshot uploads without provider access.
47
48
  - Audit scans use `--mode audit` in user-facing CLI calls and request payloads. The legacy `ultra` mode remains accepted as an alias, but audit scans still require provider-backed GitHub or GitLab sources.
49
+ - Lite scans use `--mode lite` in CLI calls or `mode: "lite"` in MCP, require Lite Scan beta access, and require provider-backed GitHub or GitLab sources without local snapshot fallback.
48
50
  - PR scans use `--mode pr --pr <number>` in CLI calls, or `mode: "pr"` with `pullRequests` in MCP. They require one provider-backed GitHub repository.
49
51
  - `apex-workspace-use` accepts a workspace name, prefix, or ID.
50
52
  - Use `sourceMode: "remote"` only when the user explicitly wants to forbid local snapshot fallbacks.
@@ -59,6 +61,7 @@ If the Apex MCP server is not configured, fall back to the local CLI:
59
61
  ## Examples
60
62
 
61
63
  - Start a scan for the current repository or directory: run `apex-doctor`, bind a workspace if needed, then call `apex-scan`.
64
+ - Start a Lite scan: call `apex-scan` with `mode: "lite"` after confirming beta access and provider-backed sources.
62
65
  - Start a PR scan: call `apex-scan` with `mode: "pr"` and `pullRequests`.
63
66
  - Check an active scan: call `apex-status`, passing `scanId` when the scan is not the latest binding, then `apex-findings` when the scan completes.
64
67
  - Export findings for review: call `apex-export-findings` with `format` set to `markdown`, `json`, or `gitlab-sast`.
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Cantina agent plugins for security review workflows.",
9
- "version": "0.1.15"
9
+ "version": "0.1.17"
10
10
  },
11
11
  "plugins": [
12
12
  {
@@ -14,10 +14,10 @@
14
14
  "source": {
15
15
  "source": "npm",
16
16
  "package": "@cantinasecurity/apex-cli",
17
- "version": "0.1.15"
17
+ "version": "0.1.17"
18
18
  },
19
19
  "description": "Run Apex security scans and review findings from Claude Code.",
20
- "version": "0.1.15",
20
+ "version": "0.1.17",
21
21
  "author": {
22
22
  "name": "Cantina",
23
23
  "email": "support@cantina.xyz"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apex-cli",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "Run Apex security scans and review findings from Claude Code.",
5
5
  "author": {
6
6
  "name": "Cantina",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apex-cli",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "Run Apex security scans and review findings from Codex.",
5
5
  "author": {
6
6
  "name": "Cantina",
package/.mcp.claude.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "args": [
6
6
  "-y",
7
7
  "-p",
8
- "@cantinasecurity/apex-cli@0.1.15",
8
+ "@cantinasecurity/apex-cli@0.1.17",
9
9
  "apex-mcp"
10
10
  ],
11
11
  "env": {
package/.mcp.codex.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "args": [
5
5
  "-y",
6
6
  "-p",
7
- "@cantinasecurity/apex-cli@0.1.15",
7
+ "@cantinasecurity/apex-cli@0.1.17",
8
8
  "apex-mcp"
9
9
  ],
10
10
  "env": {
package/MARKETPLACE.md CHANGED
@@ -13,7 +13,7 @@ This package is prepared as both a Claude Code plugin and a Codex plugin. The pu
13
13
  The plugin MCP configs launch the pinned npm CLI package with:
14
14
 
15
15
  ```bash
16
- npx -y -p @cantinasecurity/apex-cli@0.1.15 apex-mcp
16
+ npx -y -p @cantinasecurity/apex-cli@0.1.17 apex-mcp
17
17
  ```
18
18
 
19
19
  That keeps marketplace installs independent of a user's global `apex` install.
package/README.md CHANGED
@@ -103,7 +103,7 @@ If Apex asks for a workspace name, that is the Apex workspace name for the curre
103
103
  Supported shell commands:
104
104
 
105
105
  - `/credits`
106
- - `/scan [standard|audit]`
106
+ - `/scan [standard|audit|lite]`
107
107
  - `/scan pr <pr-number>`
108
108
  - `/scans`
109
109
  - `/findings [scan-id]`
@@ -136,6 +136,7 @@ Supported shell commands:
136
136
 
137
137
  - `apex credits`
138
138
  - `apex scan`
139
+ - `apex scan --mode lite`
139
140
  - `apex scan --mode pr --pr <number> [--pr <number>] [--pr-path <path>]`
140
141
  - `apex scans`
141
142
  - `apex findings [--scan <scan-id>]`
@@ -151,9 +152,9 @@ Supported shell commands:
151
152
  - `apex doctor`
152
153
  - `apex login`
153
154
  - `apex logout`
154
- - `apex service-key create --company <id-or-handle> --name <name> [--scope <scope[,scope]>] [--expires-at <ISO-8601>] [--json]`
155
- - `apex service-key list --company <id-or-handle> [--json]`
156
- - `apex service-key revoke <key-id> --company <id-or-handle> [--json]`
155
+ - `apex service-key create --name <name> [--company <id-or-handle>] [--scope <scope[,scope]>] [--expires-at <ISO-8601>] [--json]`
156
+ - `apex service-key list [--company <id-or-handle>] [--json]`
157
+ - `apex service-key revoke <key-id> [--company <id-or-handle>] [--json]`
157
158
  - `apex setup [all|codex|claude|copilot]`
158
159
  - `apex telemetry [status|enable|disable]`
159
160
  - `apex update`
@@ -165,7 +166,7 @@ Helpful workspace flags:
165
166
  - `--company <id-or-handle>` to choose the Apex company when more than one is available
166
167
  - `--workspace-name <name>` to set the Apex workspace name for this directory
167
168
 
168
- `apex credits` shows standard scan credits plus audit and fix review scan entitlements when the server returns them.
169
+ `apex credits` shows standard, audit, fix review, and Lite scan entitlements when the server returns them.
169
170
 
170
171
  ## Service Keys And The Hosted API
171
172
 
@@ -175,12 +176,13 @@ An organization manager can create a service key with an existing Apex device-lo
175
176
 
176
177
  ```bash
177
178
  apex service-key create \
178
- --company acme \
179
179
  --name internal-audit-hub \
180
180
  --scope scans:create,scans:read,findings:read \
181
181
  --expires-at 2027-01-01T00:00:00Z
182
182
  ```
183
183
 
184
+ The CLI automatically uses your company when only one is available. If you belong to multiple companies, it prompts you to choose one. Pass `--company <id-or-handle>` to skip that prompt, or when a non-interactive or `--json` command cannot prompt.
185
+
184
186
  The secret is returned only by `create` and cannot be retrieved later. Store it directly in a secret manager and do not put it in source control, prompts, chat messages, or logs. `--json` also includes the shown-once secret so it can be captured programmatically; handle that output as a credential.
185
187
 
186
188
  Service keys are organization-level credentials. Grant only the scopes the integration needs: `scans:create` triggers scans, `scans:read` polls status, and `findings:read` retrieves findings. Omit `--scope` to grant all three scopes. For a P1-only adapter that reads manually started scans, create a read-only key with `--scope scans:read,findings:read`.
@@ -190,8 +192,8 @@ A key with `findings:read` can retrieve unpublished draft findings for scans in
190
192
  List metadata or revoke a key without exposing its secret:
191
193
 
192
194
  ```bash
193
- apex service-key list --company acme
194
- apex service-key revoke <key-id> --company acme
195
+ apex service-key list
196
+ apex service-key revoke <key-id>
195
197
  ```
196
198
 
197
199
  Service-key management is intentionally available only through the scripted CLI. It is not exposed as an MCP tool or interactive-shell command, which keeps raw secrets out of model tool results and transcripts. The CLI requires an existing device-login bearer session, never initiates login from these commands, and never stores a created service key locally.
@@ -277,7 +279,7 @@ Useful flags:
277
279
 
278
280
  - `--repo <path>` to scan one or more explicit local roots instead of the current directory
279
281
  - `--source-mode auto|remote|local` to control remote-first fallback behavior
280
- - `--mode standard|audit|pr` to choose the scan mode
282
+ - `--mode standard|audit|lite|pr` to choose the scan mode
281
283
  - `--pr <number>` to select one or more GitHub pull requests for `--mode pr`
282
284
  - `--pr <number:path,path>` or `--pr-path <path>` to limit a PR scan to changed paths
283
285
 
@@ -285,6 +287,8 @@ Useful flags:
285
287
 
286
288
  Audit scans use `audit` as the scan mode and still require provider-backed GitHub or GitLab repositories that Apex can materialize remotely without a local snapshot fallback. `ultra` remains accepted as a backwards-compatible alias.
287
289
 
290
+ Lite scans use `lite` as the scan mode and require the Lite Scan beta feature plus provider-backed GitHub or GitLab repositories that Apex can materialize remotely. Local snapshot uploads are not supported for Lite scans.
291
+
288
292
  PR scans require exactly one provider-backed GitHub repository. If the current directory resolves to multiple sources, pass `--repo <path>` to select the one that contains the pull request.
289
293
 
290
294
  ## LLM / MCP Usage
@@ -381,6 +385,7 @@ The MCP server exposes Apex-specific tools for:
381
385
  - doctor, credits, and provider connection URLs
382
386
  - workspace inspection and workspace binding
383
387
  - scan start, status, cancellation, findings, and findings export
388
+ - Lite scan start by calling `apex-scan` with `mode: "lite"`
384
389
  - PR scan start by calling `apex-scan` with `mode: "pr"` and `pullRequests`
385
390
  - finding comments and valid/invalid feedback with `apex-finding-comment` and `apex-finding-feedback`
386
391
  - Fix PR and current-repository fix review scans with `apex-finding-fix-review`, optionally after `apex-finding-feedback`
@@ -424,7 +429,7 @@ Telemetry event posts do not include bearer tokens. The telemetry endpoint is `P
424
429
  {
425
430
  "schemaVersion": 1,
426
431
  "event": "apex.invocation.completed",
427
- "cliVersion": "0.1.15",
432
+ "cliVersion": "0.1.17",
428
433
  "invocation": {
429
434
  "surface": "mcp",
430
435
  "command": "apex-scan",
@@ -455,7 +460,7 @@ The npm package also includes marketplace-ready plugin artifacts:
455
460
  - `.claude-plugin/plugin.json` and `.mcp.claude.json` for Claude Code plugin installs
456
461
  - `.claude-plugin/marketplace.json` for a Claude marketplace entry backed by the public npm package
457
462
 
458
- These plugin installs launch the pinned npm package with `npx -y -p @cantinasecurity/apex-cli@0.1.15 apex-mcp`, so users do not need to install `apex` globally before enabling the plugin.
463
+ These plugin installs launch the pinned npm package with `npx -y -p @cantinasecurity/apex-cli@0.1.17 apex-mcp`, so users do not need to install `apex` globally before enabling the plugin.
459
464
 
460
465
  The repository also includes `.agents/plugins/marketplace.json` for local Codex marketplace testing from a checkout.
461
466
 
package/dist/apex.js CHANGED
@@ -52,7 +52,7 @@ async function dispatch(parsed) {
52
52
  await commandServiceKeyRevoke(client, parsed.flags, parsed.args[0] ?? "");
53
53
  return;
54
54
  }
55
- throw new Error("Usage: apex service-key <create|list|revoke> [key-id] --company <id-or-handle>");
55
+ throw new Error("Usage: apex service-key <create|list|revoke> [key-id] [--company <id-or-handle>]");
56
56
  case "update":
57
57
  await commandUpdate(parsed.flags);
58
58
  return;
package/dist/commands.js CHANGED
@@ -42,9 +42,10 @@ const FIX_REVIEW_TARGETS = [
42
42
  "pull_request",
43
43
  "repository_current",
44
44
  ];
45
- const SERVICE_KEY_CREATE_USAGE = "Usage: apex service-key create --company <id-or-handle> --name <name> [--scope <scope[,scope]>] [--expires-at <ISO-8601>] [--json]";
46
- const SERVICE_KEY_LIST_USAGE = "Usage: apex service-key list --company <id-or-handle> [--json]";
47
- const SERVICE_KEY_REVOKE_USAGE = "Usage: apex service-key revoke <key-id> --company <id-or-handle> [--json]";
45
+ const SERVICE_KEY_CREATE_USAGE = "Usage: apex service-key create --name <name> [--company <id-or-handle>] [--scope <scope[,scope]>] [--expires-at <ISO-8601>] [--json]";
46
+ const SERVICE_KEY_LIST_USAGE = "Usage: apex service-key list [--company <id-or-handle>] [--json]";
47
+ const SERVICE_KEY_REVOKE_USAGE = "Usage: apex service-key revoke <key-id> [--company <id-or-handle>] [--json]";
48
+ const SERVICE_KEY_COMPANY_PROMPT = "Select the Apex company whose service keys you want to manage:";
48
49
  const SERVICE_KEY_EXPIRATION_SCHEMA = z.string().datetime({ offset: true });
49
50
  const SERVICE_KEY_NAME_CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f-\u009f]/;
50
51
  const SERVICE_KEY_NAME_SCHEMA = z
@@ -65,11 +66,6 @@ async function saveCompanyDefault(companyId) {
65
66
  function formatCommandArgument(value) {
66
67
  return /\s/.test(value) ? `"${value}"` : value;
67
68
  }
68
- function requireExplicitServiceKeyCompany(flags, usage) {
69
- if (!getFlagString(flags, "company")) {
70
- throw new Error(`${usage}\nService-key commands require an explicit --company.`);
71
- }
72
- }
73
69
  async function requireExistingServiceKeySession(client) {
74
70
  const me = await getMe(client);
75
71
  if (!me) {
@@ -188,6 +184,28 @@ function formatFixReviewScanBalance(scanBalance) {
188
184
  }
189
185
  return `Fix review scans: ${detailParts.join(", ")}`;
190
186
  }
187
+ function formatLiteScanBalance(scanBalance) {
188
+ const purchased = getOptionalCount(scanBalance.litePurchased);
189
+ const used = getOptionalCount(scanBalance.liteUsed);
190
+ const remaining = getOptionalCount(scanBalance.liteRemaining);
191
+ const available = remaining ??
192
+ (purchased !== null && used !== null ? Math.max(0, purchased - used) : null);
193
+ if (purchased === null && used === null && available === null) {
194
+ return null;
195
+ }
196
+ const detailParts = [];
197
+ if (purchased !== null) {
198
+ detailParts.push(`${purchased} purchased`);
199
+ }
200
+ if (used !== null) {
201
+ detailParts.push(`${used} used`);
202
+ }
203
+ if (available !== null) {
204
+ const detailSuffix = detailParts.length ? ` (${detailParts.join(", ")})` : "";
205
+ return `Lite scan credits: ${available} available${detailSuffix}`;
206
+ }
207
+ return `Lite scan credits: ${detailParts.join(", ")}`;
208
+ }
191
209
  function normalizeRequestedScanMode(value) {
192
210
  if (value === "ultra" || value === "audit") {
193
211
  return "audit";
@@ -195,6 +213,9 @@ function normalizeRequestedScanMode(value) {
195
213
  if (value === "pr") {
196
214
  return "pr";
197
215
  }
216
+ if (value === "lite") {
217
+ return "lite";
218
+ }
198
219
  return "standard";
199
220
  }
200
221
  function getFlagValues(flags, key) {
@@ -578,6 +599,10 @@ export async function commandCredits(client, cwd, flags) {
578
599
  if (redeemableFixReviewScans && redeemableFixReviewScans > 0) {
579
600
  logLine(`Redeemable fix review scans from standard credits: ${redeemableFixReviewScans}`, flags);
580
601
  }
602
+ const liteBalance = formatLiteScanBalance(payload.scanBalance);
603
+ if (liteBalance) {
604
+ logLine(liteBalance, flags);
605
+ }
581
606
  logLine(`Scans enabled: ${payload.scansEnabled ? "yes" : "no"}`, flags);
582
607
  return payload;
583
608
  }
@@ -588,12 +613,14 @@ export async function commandLogout(client, flags) {
588
613
  }
589
614
  }
590
615
  export async function commandServiceKeyCreate(client, flags) {
591
- requireExplicitServiceKeyCompany(flags, SERVICE_KEY_CREATE_USAGE);
592
616
  const name = normalizeServiceKeyName(getFlagString(flags, "name"));
593
617
  const scopes = normalizeServiceKeyScopes(flags);
594
618
  const expiresAt = normalizeServiceKeyExpiration(getFlagString(flags, "expires-at"));
595
619
  const me = await requireExistingServiceKeySession(client);
596
- const company = await chooseCompany(me, flags, null);
620
+ const company = await chooseCompany(me, flags, null, {
621
+ prompt: SERVICE_KEY_COMPANY_PROMPT,
622
+ useSavedDefault: false,
623
+ });
597
624
  const response = await withLoadingIndicator("Creating service key...", flags, () => createServiceApiKey(client, company.id, {
598
625
  name,
599
626
  expiresAt,
@@ -623,9 +650,11 @@ export async function commandServiceKeyCreate(client, flags) {
623
650
  return payload;
624
651
  }
625
652
  export async function commandServiceKeyList(client, flags) {
626
- requireExplicitServiceKeyCompany(flags, SERVICE_KEY_LIST_USAGE);
627
653
  const me = await requireExistingServiceKeySession(client);
628
- const company = await chooseCompany(me, flags, null);
654
+ const company = await chooseCompany(me, flags, null, {
655
+ prompt: SERVICE_KEY_COMPANY_PROMPT,
656
+ useSavedDefault: false,
657
+ });
629
658
  const response = await withLoadingIndicator("Loading service keys...", flags, () => listServiceApiKeys(client, company.id));
630
659
  const payload = {
631
660
  company,
@@ -653,13 +682,15 @@ export async function commandServiceKeyList(client, flags) {
653
682
  return payload;
654
683
  }
655
684
  export async function commandServiceKeyRevoke(client, flags, requestedKeyId) {
656
- requireExplicitServiceKeyCompany(flags, SERVICE_KEY_REVOKE_USAGE);
657
685
  const keyId = requestedKeyId.trim();
658
686
  if (!keyId) {
659
687
  throw new Error(SERVICE_KEY_REVOKE_USAGE);
660
688
  }
661
689
  const me = await requireExistingServiceKeySession(client);
662
- const company = await chooseCompany(me, flags, null);
690
+ const company = await chooseCompany(me, flags, null, {
691
+ prompt: SERVICE_KEY_COMPANY_PROMPT,
692
+ useSavedDefault: false,
693
+ });
663
694
  await withLoadingIndicator("Revoking service key...", flags, () => revokeServiceApiKey(client, company.id, keyId));
664
695
  const payload = {
665
696
  company,
@@ -853,16 +884,17 @@ export async function commandScan(client, cwd, flags) {
853
884
  },
854
885
  }));
855
886
  }
856
- else if (requestedMode === "audit") {
887
+ else if (requestedMode === "audit" || requestedMode === "lite") {
888
+ const modeLabel = requestedMode === "audit" ? "Audit" : "Lite";
857
889
  if (!supportsLegacyRemoteFlow(result.resolve.plannedSources)) {
858
- throw new Error("Audit scans currently require provider-backed GitHub or GitLab repositories without local snapshot fallbacks.");
890
+ throw new Error(`${modeLabel} scans currently require provider-backed GitHub or GitLab repositories without local snapshot fallbacks.`);
859
891
  }
860
- const legacyResolve = await withLoadingIndicator("Preparing audit scan...", flags, () => resolveWorkspaceSelectionLegacy(client, selection, resolvedWorkspaceId));
892
+ const legacyResolve = await withLoadingIndicator(`Preparing ${modeLabel.toLowerCase()} scan...`, flags, () => resolveWorkspaceSelectionLegacy(client, selection, resolvedWorkspaceId));
861
893
  if (!legacyResolve.workspaceId) {
862
894
  throw new Error("Workspace resolution did not return a workspaceId.");
863
895
  }
864
896
  workspaceId = legacyResolve.workspaceId;
865
- scan = await withLoadingIndicator("Starting audit scan...", flags, () => client.request(`/api/cli/v1/local-workspaces/${encodeURIComponent(workspaceId)}/scan`, {
897
+ scan = await withLoadingIndicator(`Starting ${modeLabel.toLowerCase()} scan...`, flags, () => client.request(`/api/cli/v1/local-workspaces/${encodeURIComponent(workspaceId)}/scan`, {
866
898
  method: "POST",
867
899
  json: {
868
900
  mode: requestedMode,
package/dist/help.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export const CLI_HELP_TEXT = `Usage:
2
2
  apex Open the interactive Apex shell
3
- apex credits Show scan credits plus audit and fix review scan entitlements for the active company
3
+ apex credits Show standard, audit, fix review, and Lite scan entitlements for the active company
4
4
  apex scan Create or resolve a workspace for this directory and start a scan
5
5
  apex scans List scans for the current workspace binding
6
6
  apex findings List findings for the latest or selected scan
@@ -33,7 +33,7 @@ export const CLI_HELP_TEXT = `Usage:
33
33
  apex connect gitlab Open the GitLab connection flow
34
34
 
35
35
  Flags:
36
- --company <id-or-handle> Choose the Apex company to use
36
+ --company <id-or-handle> Override the automatically selected Apex company
37
37
  --name <name> Name a new service key
38
38
  --scope <scope[,scope]> Limit a service key to scans:create, scans:read, and/or findings:read
39
39
  --expires-at <ISO-8601> Set an optional service-key expiration time
@@ -55,7 +55,7 @@ Flags:
55
55
  Choose the export format for findings
56
56
  --output <path> Write exported findings to this file path
57
57
  --limit <count> Limit the number of findings returned
58
- --mode standard|audit|pr Choose the scan mode
58
+ --mode standard|audit|lite|pr Choose the scan mode
59
59
  --pr <number[:path,path]> Select a GitHub pull request for --mode pr
60
60
  --pr-path <path> Limit a single-PR scan to a changed file path
61
61
  --source-mode auto|remote|local Control remote-vs-local source materialization
@@ -71,9 +71,11 @@ Tips:
71
71
  apex scan uses the current directory as the default source root unless you pass --repo.
72
72
  PR scans require --mode pr and at least one --pr selection for a GitHub repository.
73
73
  audit is the current scan mode for audit scans; ultra remains accepted as a legacy alias.
74
+ Lite scans use --mode lite and require beta access plus provider-backed GitHub or GitLab sources.
74
75
  apex workspace use accepts a workspace name, prefix, or ID.
75
76
  Finding comments, feedback, and fix review scans use the same Apex login credentials as other CLI commands.
76
- Service-key commands require an existing login and --company; run apex login first when needed.
77
+ Service-key commands require an existing login; run apex login first when needed.
78
+ Apex automatically selects your company when only one is available. With multiple companies, choose one interactively or pass --company.
77
79
  Service-key creation also requires --name and reveals the secret only once; omit --scope to grant all hosted API scopes.
78
80
  Service-key management is available only in the scripted CLI, not the interactive shell or MCP server.
79
81
  Invalid finding feedback requires --dismissal-reason.
@@ -86,8 +88,9 @@ Tips:
86
88
  export const SHELL_HELP_TEXT = `Press Tab to autocomplete commands and common arguments.
87
89
 
88
90
  Commands:
89
- /credits Show scan credits plus audit and fix review scan entitlements for the active company
90
- /scan [standard|audit] Start a new Apex scan for this workspace
91
+ /credits Show standard, audit, fix review, and Lite scan entitlements for the active company
92
+ /scan [standard|audit|lite]
93
+ Start a new Apex scan for this workspace
91
94
  /scan pr <pr-number> Start a PR scan for this workspace
92
95
  /scans List scans for this workspace
93
96
  /findings [scan-id] List findings for the latest or selected scan
@@ -120,11 +123,22 @@ Commands:
120
123
  /help Show this help
121
124
  /exit Exit Apex
122
125
 
126
+ Scripted-only commands (run outside the interactive shell):
127
+ apex service-key create --name <name> [--company <id-or-handle>] [--scope <scope[,scope]>]
128
+ Create an organization service key (shown once)
129
+ apex service-key list [--company <id-or-handle>]
130
+ List service-key metadata
131
+ apex service-key revoke <key-id> [--company <id-or-handle>]
132
+ Revoke a service key
133
+
123
134
  Tips:
124
135
  PR scans require a GitHub PR number and provider-backed repository access.
125
136
  audit is the current scan mode for audit scans; ultra remains accepted as a legacy alias.
137
+ Lite scans require beta access plus provider-backed GitHub or GitLab sources.
126
138
  /workspace use accepts a workspace name, prefix, or ID.
127
139
  /findings comment, /findings feedback, and /findings fix-review use the current Apex login.
140
+ Service-key commands automatically use your company when only one is available. With multiple companies, choose one interactively or pass --company.
141
+ Service-key secrets are shown once. Run these commands in your terminal, not in the interactive shell or through MCP.
128
142
  Invalid finding feedback requires a dismissal reason.
129
143
  Fix review scans use saved Fix PR URLs when present; otherwise they review the current repository when Bedrock has original scan repository context. Use scripted CLI or MCP to supply Fix PR URLs directly.
130
144
  Use scripted CLI flags for advanced feedback options such as suggested severity or dismissal reason.
package/dist/mcp.js CHANGED
@@ -26,7 +26,7 @@ Notes:
26
26
  - Finding write tools use the same Apex device-login credentials as read tools.
27
27
  - Organization service-key creation, listing, and revocation are intentionally scripted-CLI-only and are not exposed as MCP tools. Never ask a user to paste a service key into an MCP prompt or tool call.
28
28
  - HTTP-only serverless and cron integrations should use the hosted API documented at https://ai.cantina.xyz/docs/apex-api instead of launching this stdio server.
29
- - Use mode "audit" for audit scans; "ultra" remains accepted as a legacy alias. Use mode "pr" for GitHub pull request scans.
29
+ - Use mode "audit" for audit scans; "ultra" remains accepted as a legacy alias. Use mode "lite" only for beta-enabled provider-backed Lite scans, and mode "pr" for GitHub pull request scans.
30
30
  - Doctor reports whether Apex will use remote materialization or a local snapshot upload for each source.`;
31
31
  const WORKSPACE_BINDING_ERROR = "This directory is not bound to an Apex workspace yet. Run `apex workspaces` to list workspace names, prefixes, and IDs, then bind one with `apex workspace use \"<workspace name>\"`, or run `apex scan` to create or resolve one automatically.";
32
32
  const MISSING_PROVIDER_CONNECTIONS_ERROR = "Missing provider connections. Re-run interactively or pre-connect providers.";
@@ -292,7 +292,7 @@ function registerTools(server) {
292
292
  }));
293
293
  server.registerTool("apex-credits", {
294
294
  title: "Get Apex Credits",
295
- description: "Show scan credits plus audit and fix review scan entitlements for the active or selected company.",
295
+ description: "Show scan credits plus audit, fix review, and Lite scan entitlements for the active or selected company.",
296
296
  inputSchema: {
297
297
  cwd: z.string().optional(),
298
298
  company: z.string().optional(),
@@ -376,13 +376,13 @@ function registerTools(server) {
376
376
  }));
377
377
  server.registerTool("apex-scan", {
378
378
  title: "Start Apex Scan",
379
- description: "Start a new Apex scan for the provided cwd by default. Pass repoPaths only to scan explicit alternate local roots. Use mode audit for audit scans and mode pr for GitHub pull request scans.",
379
+ description: "Start a new Apex scan for the provided cwd by default. Pass repoPaths only to scan explicit alternate local roots. Use mode audit for audit scans, mode lite for beta-gated provider-backed Lite scans, and mode pr for GitHub pull request scans.",
380
380
  inputSchema: {
381
381
  cwd: z.string().optional(),
382
382
  company: z.string().optional(),
383
383
  workspaceName: z.string().optional(),
384
384
  repoPaths: z.array(z.string()).optional(),
385
- mode: z.enum(["standard", "audit", "ultra", "pr"]).optional(),
385
+ mode: z.enum(["standard", "audit", "ultra", "lite", "pr"]).optional(),
386
386
  pullRequests: z
387
387
  .array(z.object({
388
388
  number: z.number().int().positive(),
package/dist/session.js CHANGED
@@ -23,10 +23,13 @@ export function createWorkspaceBinding(result, currentBinding) {
23
23
  lastScanUrl: preservedBinding?.lastScanUrl ?? null,
24
24
  };
25
25
  }
26
- export async function chooseCompany(me, flags, binding) {
26
+ export async function chooseCompany(me, flags, binding, options = {}) {
27
27
  const requested = getFlagString(flags, "company");
28
28
  const config = await loadConfig();
29
- const defaultRef = requested ?? binding?.companyId ?? config.defaultCompanyId ?? null;
29
+ const defaultRef = requested ??
30
+ (options.useSavedDefault === false
31
+ ? null
32
+ : (binding?.companyId ?? config.defaultCompanyId ?? null));
30
33
  if (defaultRef) {
31
34
  const matched = me.companies.find((company) => company.id === defaultRef ||
32
35
  (company.handle ?? "").toLowerCase() === defaultRef.toLowerCase());
@@ -46,7 +49,7 @@ export async function chooseCompany(me, flags, binding) {
46
49
  if (!canPromptInteractively(flags)) {
47
50
  throw new Error("Multiple companies available. Re-run with --company <id-or-handle>.");
48
51
  }
49
- const selected = await chooseOne("Select the Apex company to use for this directory:", me.companies.map((company) => ({
52
+ const selected = await chooseOne(options.prompt ?? "Select the Apex company to use for this directory:", me.companies.map((company) => ({
50
53
  label: company.handle
51
54
  ? `${company.name ?? company.id} (${company.handle})`
52
55
  : (company.name ?? company.id),
package/dist/shell.js CHANGED
@@ -7,7 +7,7 @@ import { formatApiError } from "./api-client.js";
7
7
  import { createShellTelemetryInvocation, emitInvocationCompleted, emitInvocationStarted, withTelemetryContext, } from "./telemetry.js";
8
8
  const SHELL_COMPLETIONS = [
9
9
  { command: "credits" },
10
- { command: "scan", args: ["standard", "audit", "ultra", "pr"] },
10
+ { command: "scan", args: ["standard", "audit", "ultra", "lite", "pr"] },
11
11
  { command: "scans" },
12
12
  { command: "findings", args: ["comment", "feedback", "fix-review"] },
13
13
  { command: "export" },
@@ -195,8 +195,8 @@ async function runShellCommand(client, cwd, parsed, shellFlags, session) {
195
195
  return {};
196
196
  case "scan": {
197
197
  const mode = parsed.args[0];
198
- if (mode && !["standard", "audit", "ultra", "pr"].includes(mode)) {
199
- process.stderr.write("Usage: /scan [standard|audit|ultra|pr] [pr-number]\n");
198
+ if (mode && !["standard", "audit", "ultra", "lite", "pr"].includes(mode)) {
199
+ process.stderr.write("Usage: /scan [standard|audit|ultra|lite|pr] [pr-number]\n");
200
200
  return {};
201
201
  }
202
202
  const prNumber = mode === "pr" ? parsed.args[1] : null;
package/dist/telemetry.js CHANGED
@@ -184,7 +184,13 @@ function sanitizeCliFlags(flags) {
184
184
  contentProvided: stringFlag(flags, "content") !== null,
185
185
  commentProvided: stringFlag(flags, "comment") !== null,
186
186
  parentCommentProvided: stringFlag(flags, "parent-comment") !== null,
187
- mode: safeEnum(stringFlag(flags, "mode"), ["standard", "audit", "ultra", "pr"]),
187
+ mode: safeEnum(stringFlag(flags, "mode"), [
188
+ "standard",
189
+ "audit",
190
+ "ultra",
191
+ "lite",
192
+ "pr",
193
+ ]),
188
194
  sourceMode: safeEnum(stringFlag(flags, "source-mode"), ["auto", "remote", "local"]),
189
195
  format: safeEnum(stringFlag(flags, "format"), ["markdown", "json", "gitlab-sast"]),
190
196
  feedbackStatus: safeEnum(stringFlag(flags, "status"), ["valid", "invalid"]),
@@ -351,6 +357,7 @@ export function sanitizeMcpInput(input = {}) {
351
357
  "standard",
352
358
  "audit",
353
359
  "ultra",
360
+ "lite",
354
361
  "pr",
355
362
  ]),
356
363
  sourceMode: safeEnum(typeof input.sourceMode === "string" ? input.sourceMode : null, [
@@ -538,7 +545,13 @@ export function createCliTelemetryInvocation(parsed) {
538
545
  }
539
546
  export function createShellTelemetryInvocation(parsed, flags) {
540
547
  const shellMode = parsed.command === "scan"
541
- ? safeEnum(parsed.args[0] ?? "default", ["standard", "audit", "ultra", "pr"]) ??
548
+ ? safeEnum(parsed.args[0] ?? "default", [
549
+ "standard",
550
+ "audit",
551
+ "ultra",
552
+ "lite",
553
+ "pr",
554
+ ]) ??
542
555
  (parsed.args[0] ? "other" : "default")
543
556
  : null;
544
557
  return createInvocation({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cantinasecurity/apex-cli",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "Standalone CLI and MCP server for Apex.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -23,23 +23,25 @@ Workflow:
23
23
  4. Call `apex-doctor` before starting a scan if workspace binding or source planning might be unclear.
24
24
  5. If the directory is not bound to the right workspace, call `apex-workspaces` and `apex-workspace-use`.
25
25
  6. Use `apex-scan`, `apex-status`, `apex-scans`, `apex-findings`, and `apex-export-findings` for the scan lifecycle.
26
- 7. For PR scans, call `apex-scan` with `mode: "pr"` and `pullRequests`.
27
- 8. Use `apex-finding-comment` and `apex-finding-feedback` when the user wants to leave review notes or valid/invalid feedback on a finding.
28
- 9. For fix reviews, call `apex-finding-fix-review`. Pass `fixPrUrls` for a PR-based review, or omit them to review the current repository state when Bedrock has original scan repository context.
26
+ 7. For Lite scans, call `apex-scan` with `mode: "lite"` only when the company has Lite Scan beta access and the sources are provider-backed.
27
+ 8. For PR scans, call `apex-scan` with `mode: "pr"` and `pullRequests`.
28
+ 9. Use `apex-finding-comment` and `apex-finding-feedback` when the user wants to leave review notes or valid/invalid feedback on a finding.
29
+ 10. For fix reviews, call `apex-finding-fix-review`. Pass `fixPrUrls` for a PR-based review, or omit them to review the current repository state when Bedrock has original scan repository context.
29
30
 
30
31
  Guidelines:
31
32
 
32
33
  - Do not rely on interactive CLI prompts. The MCP tools are intentionally non-interactive.
33
34
  - Service-key management has no MCP tools. Never ask a user to paste a service key into a prompt, and never place one in an MCP call, tool result, source file, or log.
34
- - If a user explicitly needs a new service key, tell them to run `apex login` if needed, then run `apex service-key create --company <company> --name <name> --scope <scope[,scope]>` directly in their own terminal. Use only the required scopes: `scans:create` to trigger, `scans:read` to poll status, and `findings:read` to retrieve findings. A P1-only adapter can use `--scope scans:read,findings:read`; omitting `--scope` grants all three. Service-key commands never initiate login; the secret is shown once. `list` and `revoke` also require an explicit `--company`.
35
+ - If a user explicitly needs a new service key, tell them to run `apex login` if needed, then run `apex service-key create --name <name> --scope <scope[,scope]>` directly in their own terminal. Use only the required scopes: `scans:create` to trigger, `scans:read` to poll status, and `findings:read` to retrieve findings. A P1-only adapter can use `--scope scans:read,findings:read`; omitting `--scope` grants all three. The CLI automatically selects the company when only one is available and prompts when there are several; use `--company <id-or-handle>` to skip that prompt or resolve a non-interactive command. Service-key commands never initiate login, and the secret is shown once.
35
36
  - For a headless HTTP adapter, read the service key from a secret-backed environment variable, send it as a bearer token to `/api/apex/v1`, and redact it from errors and logs. Do not shell out to `apex` or launch MCP from the adapter.
36
37
  - Hosted API v1 requires the GitHub repository to be linked to an active Apex workspace. It never creates or mutates workspaces; use optional `workspaceId` to disambiguate matches and treat zero or ambiguous matches as HTTP `409` setup errors.
37
38
  - Hosted scan triggers require `Idempotency-Key`. Reuse one stable key only for an identical transport/timeout/5xx retry. After correcting a definitive 4xx response, or for any new intended scan, use a new key.
38
- - `apex-credits` reports standard credits plus audit and fix review scan entitlements when Bedrock returns those balances.
39
+ - `apex-credits` reports standard credits plus audit, fix review, and Lite scan entitlements when Bedrock returns those balances.
39
40
  - `apex-scan` scans the provided `cwd` by default; pass `repoPaths` only when the user asks to scan explicit alternate roots.
40
41
  - `apex-doctor` reports whether Apex will use remote materialization or a local snapshot upload for each selected source.
41
42
  - Apex can scan plain local directories and dirty git worktrees without provider connections by using local snapshot uploads.
42
43
  - Audit scans use `mode: "audit"` in user-facing instructions and request payloads. The legacy `ultra` mode remains accepted as an alias, but audit scans still require provider-backed GitHub or GitLab sources.
44
+ - Lite scans use `mode: "lite"`, require Lite Scan beta access, and require provider-backed GitHub or GitLab sources without local snapshot fallback.
43
45
  - PR scans use `mode: "pr"` and require one provider-backed GitHub repository plus one or more `pullRequests`.
44
46
  - `apex-workspace-use` accepts a workspace name, prefix, or ID.
45
47
  - Use `sourceMode: "remote"` only when the user explicitly wants to forbid local snapshot fallbacks.