@cantinasecurity/apex-cli 0.1.4 → 0.1.6

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.
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "cantina-tools",
3
+ "owner": {
4
+ "name": "Cantina",
5
+ "email": "support@cantina.xyz"
6
+ },
7
+ "metadata": {
8
+ "description": "Cantina agent plugins for security review workflows.",
9
+ "version": "0.1.6"
10
+ },
11
+ "plugins": [
12
+ {
13
+ "name": "apex-cli",
14
+ "source": {
15
+ "source": "npm",
16
+ "package": "@cantinasecurity/apex-cli",
17
+ "version": "0.1.6"
18
+ },
19
+ "description": "Run Apex security scans and review findings from Claude Code.",
20
+ "version": "0.1.6",
21
+ "author": {
22
+ "name": "Cantina",
23
+ "email": "support@cantina.xyz"
24
+ },
25
+ "homepage": "https://cantina.xyz",
26
+ "keywords": [
27
+ "apex",
28
+ "cantina",
29
+ "security",
30
+ "mcp",
31
+ "code-review",
32
+ "findings"
33
+ ],
34
+ "category": "Developer Tools",
35
+ "tags": [
36
+ "security",
37
+ "mcp",
38
+ "code-review"
39
+ ]
40
+ }
41
+ ]
42
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "apex-cli",
3
+ "version": "0.1.6",
4
+ "description": "Run Apex security scans and review findings from Claude Code.",
5
+ "author": {
6
+ "name": "Cantina",
7
+ "email": "support@cantina.xyz",
8
+ "url": "https://cantina.xyz"
9
+ },
10
+ "homepage": "https://cantina.xyz",
11
+ "keywords": [
12
+ "apex",
13
+ "cantina",
14
+ "security",
15
+ "mcp",
16
+ "code-review",
17
+ "findings"
18
+ ],
19
+ "skills": "./.claude/skills/",
20
+ "mcpServers": "./.mcp.claude.json"
21
+ }
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "apex-cli",
3
+ "version": "0.1.6",
4
+ "description": "Run Apex security scans and review findings from Codex.",
5
+ "author": {
6
+ "name": "Cantina",
7
+ "email": "support@cantina.xyz",
8
+ "url": "https://cantina.xyz"
9
+ },
10
+ "homepage": "https://cantina.xyz",
11
+ "keywords": [
12
+ "apex",
13
+ "cantina",
14
+ "security",
15
+ "mcp",
16
+ "code-review",
17
+ "findings"
18
+ ],
19
+ "skills": "./skills/",
20
+ "mcpServers": "./.mcp.codex.json",
21
+ "interface": {
22
+ "displayName": "Apex CLI",
23
+ "shortDescription": "Start Apex scans and review findings from Codex.",
24
+ "longDescription": "Adds Apex MCP tools and skills for authentication, workspace binding, scans, finding export, finding comments, valid/invalid feedback, and fix review scans.",
25
+ "developerName": "Cantina",
26
+ "category": "Developer Tools",
27
+ "capabilities": [
28
+ "Read",
29
+ "Write"
30
+ ],
31
+ "websiteURL": "https://cantina.xyz",
32
+ "privacyPolicyURL": "https://cantina.xyz/privacy-policy",
33
+ "termsOfServiceURL": "https://cantina.xyz/terms/general",
34
+ "defaultPrompt": [
35
+ "Use Apex to scan this repository.",
36
+ "Use Apex to review findings for the latest scan.",
37
+ "Use Apex to start a PR scan for this pull request."
38
+ ]
39
+ }
40
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "mcpServers": {
3
+ "apex": {
4
+ "command": "npx",
5
+ "args": [
6
+ "-y",
7
+ "-p",
8
+ "@cantinasecurity/apex-cli@0.1.6",
9
+ "apex-mcp"
10
+ ]
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "apex": {
3
+ "command": "npx",
4
+ "args": [
5
+ "-y",
6
+ "-p",
7
+ "@cantinasecurity/apex-cli@0.1.6",
8
+ "apex-mcp"
9
+ ]
10
+ }
11
+ }
package/MARKETPLACE.md ADDED
@@ -0,0 +1,71 @@
1
+ # Apex CLI Marketplace Publishing
2
+
3
+ This package is prepared as both a Claude Code plugin and a Codex plugin. The published npm package includes:
4
+
5
+ - `.claude-plugin/plugin.json`
6
+ - `.claude-plugin/marketplace.json`
7
+ - `.codex-plugin/plugin.json`
8
+ - `.mcp.claude.json`
9
+ - `.mcp.codex.json`
10
+ - `skills/apex-cli/SKILL.md`
11
+ - `.claude/skills/apex-cli/SKILL.md`
12
+
13
+ The plugin MCP configs launch the pinned npm CLI package with:
14
+
15
+ ```bash
16
+ npx -y -p @cantinasecurity/apex-cli@0.1.6 apex-mcp
17
+ ```
18
+
19
+ That keeps marketplace installs independent of a user's global `apex` install.
20
+
21
+ ## Local Validation
22
+
23
+ Validate the Claude plugin and marketplace from the repo root:
24
+
25
+ ```bash
26
+ claude plugin validate .
27
+ claude plugin marketplace add ./ --scope local
28
+ claude plugin install apex-cli@cantina-tools --scope local
29
+ ```
30
+
31
+ Validate the Codex plugin through the repo marketplace:
32
+
33
+ ```bash
34
+ codex plugin marketplace add ./
35
+ ```
36
+
37
+ Then open the Codex plugin directory and install `apex-cli` from `Cantina Tools`.
38
+
39
+ ## Official Claude Plugin Directory
40
+
41
+ For the Claude Code / Cowork plugin directory:
42
+
43
+ 1. Run `claude plugin validate .`.
44
+ 2. Submit either a public GitHub repository or a zip archive that contains this plugin package.
45
+ 3. Use the Claude plugin submission form.
46
+ 4. Attach the approved listing URL to APEX-161.
47
+
48
+ The current repository is private. If Anthropic requires source inspection through a public GitHub URL, publish either this repo or a dedicated public plugin package repo before submission.
49
+
50
+ ## Anthropic Connectors Directory
51
+
52
+ The Anthropic Connectors Directory is for remote MCP servers, desktop extensions, and MCP Apps. This package currently ships a local stdio MCP server. A Connectors Directory submission still needs a hosted remote MCP endpoint with:
53
+
54
+ - HTTPS transport
55
+ - OAuth 2.0 authentication for authenticated use
56
+ - tool annotations, including titles and read/write hints
57
+ - public docs, privacy policy, support contact, and reviewer test account
58
+ - security, data handling, and launch-readiness checklist answers
59
+
60
+ Do not submit the local `apex-mcp` stdio server as a remote connector until that hosted endpoint exists.
61
+
62
+ ## OpenAI / Codex Public Distribution
63
+
64
+ The package includes a Codex plugin manifest and local marketplace catalog for development and testing. OpenAI's self-serve Codex Plugin Directory publishing is not generally available yet. Public OpenAI distribution currently requires the Apps SDK review path for an app/remote MCP integration, which needs:
65
+
66
+ - a hosted app or remote MCP server
67
+ - MCP Inspector and ChatGPT Developer Mode testing
68
+ - org owner or admin submission
69
+ - app icon, category, legal entity, privacy policy, terms, support contact, and risk profile
70
+
71
+ Attach the OpenAI submission or approved listing URL to APEX-161 when that review path is complete.
package/README.md CHANGED
@@ -292,6 +292,34 @@ For Codex-style clients, the packaged skill can be installed with `apex setup co
292
292
 
293
293
  For Claude Code, the packaged project skill can be installed into the current repository with `apex setup claude`. The repo-local source lives at `.claude/skills/apex-cli/SKILL.md`. Anthropic documents project skills as filesystem directories under `.claude/skills/<name>/SKILL.md`, and the Claude Agent SDK uses the same location when the `Skill` tool is enabled.
294
294
 
295
+ ## Plugin And Marketplace Packaging
296
+
297
+ The npm package also includes marketplace-ready plugin artifacts:
298
+
299
+ - `.codex-plugin/plugin.json` and `.mcp.codex.json` for Codex plugin installs
300
+ - `.claude-plugin/plugin.json` and `.mcp.claude.json` for Claude Code plugin installs
301
+ - `.claude-plugin/marketplace.json` for a Claude marketplace entry backed by the public npm package
302
+
303
+ These plugin installs launch the pinned npm package with `npx -y -p @cantinasecurity/apex-cli@0.1.6 apex-mcp`, so users do not need to install `apex` globally before enabling the plugin.
304
+
305
+ The repository also includes `.agents/plugins/marketplace.json` for local Codex marketplace testing from a checkout.
306
+
307
+ For local Claude validation:
308
+
309
+ ```bash
310
+ claude plugin validate .
311
+ claude plugin marketplace add ./ --scope local
312
+ claude plugin install apex-cli@cantina-tools --scope local
313
+ ```
314
+
315
+ For local Codex validation, add this repo as a local marketplace, then install `apex-cli` from the `Cantina Tools` marketplace in the Codex plugin directory:
316
+
317
+ ```bash
318
+ codex plugin marketplace add ./
319
+ ```
320
+
321
+ See `MARKETPLACE.md` for the official Claude, Anthropic Connectors Directory, and OpenAI/Codex submission checklist. The local stdio MCP server is plugin-ready, but remote marketplace submissions still require the external review steps documented there.
322
+
295
323
  ## Development Notes
296
324
 
297
325
  The CLI uses the Apex `/api/cli/v2/**` local-source routes for scan planning and snapshot uploads, with legacy `/api/cli/v1/**` routes still used for provider-backed flows such as audit scans. Local state is stored under:
package/dist/args.js CHANGED
@@ -41,6 +41,12 @@ export function isJsonMode(flags) {
41
41
  export function isNonInteractive(flags) {
42
42
  return flags["non-interactive"] === true;
43
43
  }
44
+ export function canPromptInteractively(flags) {
45
+ return (!isJsonMode(flags) &&
46
+ !isNonInteractive(flags) &&
47
+ process.stdin.isTTY === true &&
48
+ process.stdout.isTTY === true);
49
+ }
44
50
  export function getFlagString(flags, key) {
45
51
  const value = flags[key];
46
52
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
package/dist/commands.js CHANGED
@@ -1,4 +1,4 @@
1
- import { getFlagList, getFlagString, isJsonMode, isNonInteractive } from "./args.js";
1
+ import { canPromptInteractively, getFlagList, getFlagString, isJsonMode, } from "./args.js";
2
2
  import { logout } from "./auth.js";
3
3
  import { ApiError } from "./api-client.js";
4
4
  import { openInBrowser } from "./browser.js";
@@ -341,7 +341,7 @@ async function maybePersistFindingSelectionBinding(params) {
341
341
  return nextBinding;
342
342
  }
343
343
  function canPromptForConfirmation(flags) {
344
- return !isNonInteractive(flags) && process.stdin.isTTY && process.stdout.isTTY;
344
+ return canPromptInteractively(flags);
345
345
  }
346
346
  async function findFallbackActiveScan(client, binding) {
347
347
  if (!binding?.lastScanId) {
@@ -572,7 +572,7 @@ export async function commandScan(client, cwd, flags) {
572
572
  throw new Error("Workspace resolution did not return a workspaceId.");
573
573
  }
574
574
  if (legacyResolve.missing.length > 0) {
575
- if (isNonInteractive(flags)) {
575
+ if (!canPromptInteractively(flags)) {
576
576
  throw new Error(`PR scans require connected provider access for ${formatMissingProviderConnections(legacyResolve.missing)}. Re-run interactively or pre-connect providers.`);
577
577
  }
578
578
  await remediateMissingConnections(legacyResolve.missing, flags);
package/dist/session.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import path from "node:path";
2
- import { getFlagList, getFlagString, isJsonMode, isNonInteractive } from "./args.js";
2
+ import { canPromptInteractively, getFlagList, getFlagString, isJsonMode, } from "./args.js";
3
3
  import { login } from "./auth.js";
4
4
  import { ApiError } from "./api-client.js";
5
5
  import { openInBrowser } from "./browser.js";
@@ -37,10 +37,13 @@ export async function chooseCompany(me, flags, binding) {
37
37
  throw new Error(`Unknown company: ${requested}`);
38
38
  }
39
39
  }
40
+ if (me.companies.length === 0) {
41
+ throw new Error("No Apex companies are available for this account.");
42
+ }
40
43
  if (me.companies.length === 1) {
41
44
  return me.companies[0];
42
45
  }
43
- if (isNonInteractive(flags)) {
46
+ if (!canPromptInteractively(flags)) {
44
47
  throw new Error("Multiple companies available. Re-run with --company <id-or-handle>.");
45
48
  }
46
49
  const selected = await chooseOne("Select the Apex company to use for this directory:", me.companies.map((company) => ({
@@ -60,12 +63,21 @@ async function chooseWorkspaceName(cwd, flags, binding) {
60
63
  return binding.workspaceName;
61
64
  }
62
65
  const suggested = path.basename(cwd);
63
- if (isNonInteractive(flags)) {
66
+ if (!canPromptInteractively(flags)) {
64
67
  return suggested;
65
68
  }
66
69
  const chosen = await promptText("Workspace name to use in Apex for this directory (press Enter to use the current folder name)", suggested);
67
70
  return chosen.trim().length > 0 ? chosen.trim() : suggested;
68
71
  }
72
+ function selectBindingForWorkspaceName(flags, binding, workspaceName) {
73
+ const explicit = getFlagString(flags, "workspace-name");
74
+ if (!explicit || !binding) {
75
+ return binding;
76
+ }
77
+ return binding.workspaceName.trim().toLowerCase() === workspaceName.trim().toLowerCase()
78
+ ? binding
79
+ : null;
80
+ }
69
81
  function getSourceMode(flags) {
70
82
  const value = getFlagString(flags, "source-mode");
71
83
  return value === "remote" || value === "local" ? value : "auto";
@@ -127,9 +139,10 @@ export async function resolveWorkspace(client, cwd, me, flags) {
127
139
  return resolveWorkspaceSelection(client, selection);
128
140
  }
129
141
  export async function selectWorkspaceTarget(cwd, me, flags) {
130
- const binding = await loadWorkspaceBinding(cwd);
131
- const company = await chooseCompany(me, flags, binding);
132
- const workspaceName = await chooseWorkspaceName(cwd, flags, binding);
142
+ const loadedBinding = await loadWorkspaceBinding(cwd);
143
+ const company = await chooseCompany(me, flags, loadedBinding);
144
+ const workspaceName = await chooseWorkspaceName(cwd, flags, loadedBinding);
145
+ const binding = selectBindingForWorkspaceName(flags, loadedBinding, workspaceName);
133
146
  const sourceSelection = getFlagList(flags, "repo");
134
147
  const discovered = await discoverSources(cwd, sourceSelection);
135
148
  if (discovered.sources.length === 0) {
@@ -218,7 +231,7 @@ export async function remediateMissingConnections(missing, flags) {
218
231
  if (missing.length === 0) {
219
232
  return;
220
233
  }
221
- if (isNonInteractive(flags)) {
234
+ if (!canPromptInteractively(flags)) {
222
235
  throw new Error("Missing provider connections. Re-run interactively or pre-connect providers.");
223
236
  }
224
237
  for (const item of missing) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cantinasecurity/apex-cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Standalone CLI and MCP server for Apex.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -12,10 +12,15 @@
12
12
  "apex-mcp": "./pkg-bin/apex-mcp.js"
13
13
  },
14
14
  "files": [
15
+ ".claude-plugin",
16
+ ".codex-plugin",
17
+ ".mcp.claude.json",
18
+ ".mcp.codex.json",
15
19
  "dist",
16
20
  "pkg-bin",
17
21
  "skills",
18
22
  ".claude/skills",
23
+ "MARKETPLACE.md",
19
24
  "README.md"
20
25
  ],
21
26
  "engines": {