@cubis/foundry 0.3.20 → 0.3.22
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 +40 -14
- package/bin/cubis.js +759 -108
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,8 +26,9 @@ Compatibility binaries are still shipped for migration:
|
|
|
26
26
|
# 1) Install CLI
|
|
27
27
|
npm install -g @cubis/foundry
|
|
28
28
|
|
|
29
|
-
# 2) Set
|
|
29
|
+
# 2) Set API keys once (recommended: env mode)
|
|
30
30
|
export POSTMAN_API_KEY="<your-postman-api-key>"
|
|
31
|
+
export STITCH_API_KEY="<your-stitch-api-key>" # Antigravity StitchMCP only
|
|
31
32
|
|
|
32
33
|
# 3) Install workflow bundle for your platform
|
|
33
34
|
cbx workflows install --platform codex --bundle agent-environment-setup --postman --yes
|
|
@@ -54,22 +55,50 @@ cbx workflows install --platform antigravity --terminal-integration --terminal-v
|
|
|
54
55
|
cbx workflows install --platform codex --postman
|
|
55
56
|
cbx workflows install --platform codex --postman --postman-workspace-id null
|
|
56
57
|
cbx workflows install --platform codex --postman --postman-api-key "<key>"
|
|
58
|
+
cbx workflows install --platform codex --postman --mcp-scope global
|
|
59
|
+
cbx workflows install --platform copilot --postman --mcp-scope project
|
|
57
60
|
cbx workflows install --platform antigravity --postman
|
|
61
|
+
cbx workflows install --platform antigravity --postman --stitch-api-key "<key>"
|
|
58
62
|
cbx workflows install --platform copilot --postman
|
|
59
63
|
```
|
|
60
64
|
|
|
61
65
|
Install bootstrap behavior:
|
|
62
66
|
- `cbx workflows install` now also bootstraps `ENGINEERING_RULES.md` and `TECH.md` (creates when missing; keeps existing files unless explicitly regenerated).
|
|
63
|
-
- When install scope is `global
|
|
64
|
-
-
|
|
67
|
+
- When install scope is `global` (default), skills/powers install to global paths, while workflows + agents stay in workspace (`project`) paths.
|
|
68
|
+
- Rule sync + engineering artifacts (`AGENTS.md`/`GEMINI.md`/Copilot instructions, `ENGINEERING_RULES.md`, `TECH.md`) are maintained in workspace (`project`) scope.
|
|
69
|
+
- Codex workflow templates are maintained in workspace `.agents/workflows` so workflow-wrapper routing remains discoverable in project rules.
|
|
70
|
+
- Optional `--postman` bootstrap creates `cbx_config.json`, stores managed MCP definitions in `.cbx/mcp/`, and installs/configures Postman MCP for Codex, Antigravity, and Copilot.
|
|
71
|
+
- For Antigravity only, `--postman` also installs a default `StitchMCP` entry (`stitch.googleapis.com/mcp`) using key from `--stitch-api-key` or `STITCH_API_KEY`.
|
|
72
|
+
- Use `--mcp-scope <project|workspace|global|user>` to choose where MCP runtime config is installed (interactive installs prompt for this when not provided).
|
|
65
73
|
- Use `cbx rules init --platform <platform> --overwrite` to force-regenerate both files.
|
|
66
74
|
|
|
67
|
-
Postman setup behavior:
|
|
68
|
-
- `
|
|
75
|
+
Postman + Antigravity Stitch setup behavior:
|
|
76
|
+
- `cbx_config.json` is generated in workspace root (project MCP scope) or `~/.cbx/cbx_config.json` (global MCP scope).
|
|
77
|
+
- Managed MCP definition files are generated under `.cbx/mcp/<platform>/postman.json` (workspace scope) or `~/.cbx/mcp/<platform>/postman.json` (global scope).
|
|
69
78
|
- Env-first auth is supported: when `POSTMAN_API_KEY` is set, generated settings keep `apiKey: null` and MCP config uses `Bearer ${POSTMAN_API_KEY}`.
|
|
70
79
|
- Inline auth is supported with `--postman-api-key <key>`.
|
|
71
80
|
- `--postman-workspace-id null` writes JSON `null` for `defaultWorkspaceId`.
|
|
72
|
-
-
|
|
81
|
+
- Antigravity gets an additional managed file at `.cbx/mcp/antigravity/stitch.json` (or `~/.cbx/mcp/antigravity/stitch.json` in global MCP scope).
|
|
82
|
+
- Stitch key source priority for Antigravity: `--stitch-api-key` then `STITCH_API_KEY`; when unset, generated config keeps placeholder `X-Goog-Api-Key: ur stitch key`.
|
|
83
|
+
- In project MCP scope, `cbx_config.json` and `.cbx/mcp/` are auto-added to `.gitignore` (no duplicate entries).
|
|
84
|
+
|
|
85
|
+
Platform runtime MCP placement:
|
|
86
|
+
- Codex:
|
|
87
|
+
- Global MCP scope: `~/.codex/config.toml` via `codex mcp add`.
|
|
88
|
+
- Workspace MCP scope: `.vscode/mcp.json`.
|
|
89
|
+
- Antigravity (Gemini CLI):
|
|
90
|
+
- Global MCP scope: `~/.gemini/settings.json` (`mcpServers`, includes `postman` + default `StitchMCP`).
|
|
91
|
+
- Workspace MCP scope: `.gemini/settings.json` (`mcpServers`, includes `postman` + default `StitchMCP`).
|
|
92
|
+
- Copilot:
|
|
93
|
+
- Workspace MCP scope: `.vscode/mcp.json`.
|
|
94
|
+
- Global MCP scope: `~/.copilot/mcp-config.json`.
|
|
95
|
+
|
|
96
|
+
API key docs:
|
|
97
|
+
- Google Stitch MCP setup docs: [stitch.withgoogle.com/docs/mcp/setup](https://stitch.withgoogle.com/docs/mcp/setup)
|
|
98
|
+
- Google Stitch settings (create API key): [stitch.withgoogle.com/settings](https://stitch.withgoogle.com/settings)
|
|
99
|
+
- Google Cloud API key guidance: [Authenticate to Google and Google Cloud MCP servers](https://docs.cloud.google.com/mcp/authenticate-mcp)
|
|
100
|
+
- Postman API key creation: [Generate and use Postman API keys](https://learning.postman.com/docs/developer/postman-api/authentication/)
|
|
101
|
+
- Postman MCP setup: [Set up the Postman MCP Server](https://learning.postman.com/docs/developer/postman-api/postman-mcp-server/set-up-postman-mcp-server)
|
|
73
102
|
|
|
74
103
|
`rules` manages strict engineering policy and a generated codebase tech map:
|
|
75
104
|
|
|
@@ -177,11 +206,9 @@ Project scope:
|
|
|
177
206
|
- Terminal integration (optional): `.agent/terminal-integration`
|
|
178
207
|
|
|
179
208
|
Global scope:
|
|
180
|
-
- Workflows: `~/.gemini/antigravity/workflows`
|
|
181
|
-
- Agents: `~/.gemini/antigravity/agents`
|
|
182
209
|
- Skills: `~/.gemini/antigravity/skills`
|
|
183
210
|
- Rules: `~/.gemini/GEMINI.md`
|
|
184
|
-
-
|
|
211
|
+
- Workflows/agents/terminal-integration: default install keeps these in workspace (`.agent/...`) paths.
|
|
185
212
|
|
|
186
213
|
### Antigravity Terminal Integration (Optional)
|
|
187
214
|
|
|
@@ -191,7 +218,7 @@ Install-time options:
|
|
|
191
218
|
|
|
192
219
|
Behavior:
|
|
193
220
|
- Interactive installs prompt whether to enable terminal verification integration.
|
|
194
|
-
- If enabled, cbx writes managed scripts/config under `.agent/terminal-integration
|
|
221
|
+
- If enabled, cbx writes managed scripts/config under `.agent/terminal-integration`.
|
|
195
222
|
- cbx also writes a managed terminal verification block into Antigravity rule files so post-task verification commands are explicit.
|
|
196
223
|
- Removing the bundle cleans the managed terminal integration directory and block.
|
|
197
224
|
|
|
@@ -208,9 +235,9 @@ Project scope:
|
|
|
208
235
|
- Example usage: `$workflow-plan`, `$agent-backend-specialist`
|
|
209
236
|
|
|
210
237
|
Global scope:
|
|
211
|
-
- Workflow templates (reference docs): `~/.agents/workflows`
|
|
212
238
|
- Skills: `~/.agents/skills`
|
|
213
239
|
- Rules: `~/.codex/AGENTS.md`
|
|
240
|
+
- Workflow templates (reference docs): default install keeps these in workspace `.agents/workflows`
|
|
214
241
|
- Agents: not installed for Codex runtime
|
|
215
242
|
|
|
216
243
|
Legacy compatibility note:
|
|
@@ -226,10 +253,9 @@ Project scope:
|
|
|
226
253
|
- Skill schema note: `cbx` normalizes Copilot skill frontmatter by removing unsupported top-level keys like `displayName` and `keywords` during install.
|
|
227
254
|
|
|
228
255
|
Global scope:
|
|
229
|
-
- Workflows: `~/.copilot/workflows`
|
|
230
|
-
- Agents: `~/.copilot/agents`
|
|
231
256
|
- Skills: `~/.copilot/skills`
|
|
232
257
|
- Rules: `~/.copilot/copilot-instructions.md`
|
|
258
|
+
- Workflows/agents: default install keeps these in workspace (`.github/...`) paths.
|
|
233
259
|
|
|
234
260
|
## Rule Auto-Sync
|
|
235
261
|
|
|
@@ -261,7 +287,7 @@ Default scope:
|
|
|
261
287
|
- `cbx install` (legacy alias)
|
|
262
288
|
- `cbx init` (legacy alias)
|
|
263
289
|
- Default scope for these commands is `global`.
|
|
264
|
-
-
|
|
290
|
+
- In this default global mode, only skills/powers install globally. Workflows/agents and rule/engineering files remain workspace-scoped.
|
|
265
291
|
- Other workflow/rules commands default to `project`.
|
|
266
292
|
|
|
267
293
|
Optional:
|
package/bin/cubis.js
CHANGED
|
@@ -13,13 +13,16 @@ import {
|
|
|
13
13
|
writeFile
|
|
14
14
|
} from "node:fs/promises";
|
|
15
15
|
import { createRequire } from "node:module";
|
|
16
|
+
import { execFile as execFileCallback } from "node:child_process";
|
|
16
17
|
import os from "node:os";
|
|
17
18
|
import path from "node:path";
|
|
18
19
|
import process from "node:process";
|
|
20
|
+
import { promisify } from "node:util";
|
|
19
21
|
import { fileURLToPath } from "node:url";
|
|
20
22
|
|
|
21
23
|
const require = createRequire(import.meta.url);
|
|
22
24
|
const { version: CLI_VERSION } = require("../package.json");
|
|
25
|
+
const execFile = promisify(execFileCallback);
|
|
23
26
|
|
|
24
27
|
const MANAGED_BLOCK_START_RE = /<!--\s*cbx:workflows:auto:start[^>]*-->/g;
|
|
25
28
|
const MANAGED_BLOCK_END_RE = /<!--\s*cbx:workflows:auto:end\s*-->/g;
|
|
@@ -125,9 +128,16 @@ const DEFAULT_TERMINAL_VERIFIER = "codex";
|
|
|
125
128
|
const POSTMAN_API_KEY_ENV_VAR = "POSTMAN_API_KEY";
|
|
126
129
|
const POSTMAN_MCP_URL = "https://mcp.postman.com/minimal";
|
|
127
130
|
const POSTMAN_SKILL_ID = "postman";
|
|
131
|
+
const STITCH_MCP_SERVER_ID = "StitchMCP";
|
|
132
|
+
const STITCH_API_KEY_ENV_VAR = "STITCH_API_KEY";
|
|
133
|
+
const STITCH_MCP_URL = "https://stitch.googleapis.com/mcp";
|
|
134
|
+
const STITCH_API_KEY_PLACEHOLDER = "ur stitch key";
|
|
135
|
+
const CBX_CONFIG_FILENAME = "cbx_config.json";
|
|
128
136
|
const POSTMAN_SETTINGS_FILENAME = "postman_setting.json";
|
|
129
137
|
const POSTMAN_API_KEY_MISSING_WARNING =
|
|
130
|
-
`Postman API key is not configured. Set ${POSTMAN_API_KEY_ENV_VAR} or update ${
|
|
138
|
+
`Postman API key is not configured. Set ${POSTMAN_API_KEY_ENV_VAR} or update ${CBX_CONFIG_FILENAME}.`;
|
|
139
|
+
const STITCH_API_KEY_MISSING_WARNING =
|
|
140
|
+
`Google Stitch API key is not configured. Set ${STITCH_API_KEY_ENV_VAR} or update ${CBX_CONFIG_FILENAME}.`;
|
|
131
141
|
const TECH_SCAN_MAX_FILES = 5000;
|
|
132
142
|
const TECH_SCAN_IGNORED_DIRS = new Set([
|
|
133
143
|
".git",
|
|
@@ -279,6 +289,14 @@ function normalizeScope(value) {
|
|
|
279
289
|
throw new Error(`Unknown scope '${value}'. Use --scope project or --scope global.`);
|
|
280
290
|
}
|
|
281
291
|
|
|
292
|
+
function normalizeMcpScope(value, fallback = "project") {
|
|
293
|
+
if (!value) return fallback;
|
|
294
|
+
const normalized = value.trim().toLowerCase();
|
|
295
|
+
if (normalized === "project" || normalized === "workspace") return "project";
|
|
296
|
+
if (normalized === "global" || normalized === "user") return "global";
|
|
297
|
+
throw new Error(`Unknown MCP scope '${value}'. Use project/workspace or global/user.`);
|
|
298
|
+
}
|
|
299
|
+
|
|
282
300
|
function normalizeTerminalVerifier(value) {
|
|
283
301
|
if (!value) return null;
|
|
284
302
|
const normalized = value.trim().toLowerCase();
|
|
@@ -1295,6 +1313,19 @@ async function resolveProfilePaths(profileId, scope, cwd = process.cwd()) {
|
|
|
1295
1313
|
};
|
|
1296
1314
|
}
|
|
1297
1315
|
|
|
1316
|
+
async function resolveArtifactProfilePaths(profileId, scope, cwd = process.cwd()) {
|
|
1317
|
+
const scopedPaths = await resolveProfilePaths(profileId, scope, cwd);
|
|
1318
|
+
if (scope !== "global") return scopedPaths;
|
|
1319
|
+
|
|
1320
|
+
// Global install mode is skills-only. Keep workflows/agents in workspace scope.
|
|
1321
|
+
const workspacePaths = await resolveProfilePaths(profileId, "project", cwd);
|
|
1322
|
+
return {
|
|
1323
|
+
...scopedPaths,
|
|
1324
|
+
workflowsDir: workspacePaths.workflowsDir,
|
|
1325
|
+
agentsDir: workspacePaths.agentsDir
|
|
1326
|
+
};
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1298
1329
|
async function listBundleIds() {
|
|
1299
1330
|
const root = path.join(agentAssetsRoot(), "workflows");
|
|
1300
1331
|
if (!(await pathExists(root))) return [];
|
|
@@ -2241,7 +2272,7 @@ async function writeGeneratedArtifact({ destination, content, dryRun = false })
|
|
|
2241
2272
|
return { action: exists ? "replaced" : "installed", path: destination };
|
|
2242
2273
|
}
|
|
2243
2274
|
|
|
2244
|
-
function
|
|
2275
|
+
function resolveLegacyPostmanSettingsPath({ scope, cwd = process.cwd() }) {
|
|
2245
2276
|
if (scope === "global") {
|
|
2246
2277
|
return path.join(os.homedir(), ".cbx", POSTMAN_SETTINGS_FILENAME);
|
|
2247
2278
|
}
|
|
@@ -2249,20 +2280,116 @@ function resolvePostmanSettingsPath({ scope, cwd = process.cwd() }) {
|
|
|
2249
2280
|
return path.join(workspaceRoot, POSTMAN_SETTINGS_FILENAME);
|
|
2250
2281
|
}
|
|
2251
2282
|
|
|
2252
|
-
function
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2283
|
+
function resolveCbxConfigPath({ scope, cwd = process.cwd() }) {
|
|
2284
|
+
if (scope === "global") {
|
|
2285
|
+
return path.join(os.homedir(), ".cbx", CBX_CONFIG_FILENAME);
|
|
2286
|
+
}
|
|
2287
|
+
const workspaceRoot = findWorkspaceRoot(cwd);
|
|
2288
|
+
return path.join(workspaceRoot, CBX_CONFIG_FILENAME);
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
function resolveMcpRootPath({ scope, cwd = process.cwd() }) {
|
|
2292
|
+
if (scope === "global") {
|
|
2293
|
+
return path.join(os.homedir(), ".cbx", "mcp");
|
|
2294
|
+
}
|
|
2295
|
+
const workspaceRoot = findWorkspaceRoot(cwd);
|
|
2296
|
+
return path.join(workspaceRoot, ".cbx", "mcp");
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
function resolvePostmanMcpDefinitionPath({ platform, scope, cwd = process.cwd() }) {
|
|
2300
|
+
return path.join(resolveMcpRootPath({ scope, cwd }), platform, `${POSTMAN_SKILL_ID}.json`);
|
|
2301
|
+
}
|
|
2302
|
+
|
|
2303
|
+
function resolveStitchMcpDefinitionPath({ scope, cwd = process.cwd() }) {
|
|
2304
|
+
return path.join(resolveMcpRootPath({ scope, cwd }), "antigravity", "stitch.json");
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
function buildPostmanAuthHeader({ apiKey = null, apiKeyEnvVar = POSTMAN_API_KEY_ENV_VAR }) {
|
|
2308
|
+
return apiKey ? `Bearer ${apiKey}` : `Bearer \${${apiKeyEnvVar}}`;
|
|
2309
|
+
}
|
|
2310
|
+
|
|
2311
|
+
function buildStitchApiHeader({ apiKey = null }) {
|
|
2312
|
+
return `X-Goog-Api-Key: ${apiKey || STITCH_API_KEY_PLACEHOLDER}`;
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
function buildPostmanMcpDefinition({
|
|
2316
|
+
apiKey = null,
|
|
2317
|
+
apiKeyEnvVar = POSTMAN_API_KEY_ENV_VAR,
|
|
2318
|
+
mcpUrl = POSTMAN_MCP_URL
|
|
2319
|
+
}) {
|
|
2256
2320
|
return {
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2321
|
+
schemaVersion: 1,
|
|
2322
|
+
server: POSTMAN_SKILL_ID,
|
|
2323
|
+
transport: "http",
|
|
2324
|
+
url: mcpUrl,
|
|
2325
|
+
headers: {
|
|
2326
|
+
Authorization: buildPostmanAuthHeader({ apiKey, apiKeyEnvVar })
|
|
2327
|
+
}
|
|
2328
|
+
};
|
|
2329
|
+
}
|
|
2330
|
+
|
|
2331
|
+
function buildStitchMcpDefinition({
|
|
2332
|
+
apiKey = null,
|
|
2333
|
+
mcpUrl = STITCH_MCP_URL
|
|
2334
|
+
}) {
|
|
2335
|
+
return {
|
|
2336
|
+
schemaVersion: 1,
|
|
2337
|
+
server: STITCH_MCP_SERVER_ID,
|
|
2338
|
+
transport: "command",
|
|
2339
|
+
command: "npx",
|
|
2340
|
+
args: [
|
|
2341
|
+
"-y",
|
|
2342
|
+
"mcp-remote",
|
|
2343
|
+
mcpUrl,
|
|
2344
|
+
"--header",
|
|
2345
|
+
buildStitchApiHeader({ apiKey })
|
|
2346
|
+
],
|
|
2347
|
+
env: {}
|
|
2348
|
+
};
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
function buildVsCodePostmanServer({
|
|
2352
|
+
apiKey = null,
|
|
2353
|
+
apiKeyEnvVar = POSTMAN_API_KEY_ENV_VAR,
|
|
2354
|
+
mcpUrl = POSTMAN_MCP_URL
|
|
2355
|
+
}) {
|
|
2356
|
+
return {
|
|
2357
|
+
type: "sse",
|
|
2358
|
+
url: mcpUrl,
|
|
2359
|
+
headers: {
|
|
2360
|
+
Authorization: buildPostmanAuthHeader({ apiKey, apiKeyEnvVar })
|
|
2361
|
+
}
|
|
2362
|
+
};
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2365
|
+
function buildGeminiPostmanServer({
|
|
2366
|
+
apiKey = null,
|
|
2367
|
+
apiKeyEnvVar = POSTMAN_API_KEY_ENV_VAR,
|
|
2368
|
+
mcpUrl = POSTMAN_MCP_URL
|
|
2369
|
+
}) {
|
|
2370
|
+
return {
|
|
2371
|
+
httpUrl: mcpUrl,
|
|
2372
|
+
headers: {
|
|
2373
|
+
Authorization: buildPostmanAuthHeader({ apiKey, apiKeyEnvVar })
|
|
2374
|
+
}
|
|
2375
|
+
};
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
function buildGeminiStitchServer({
|
|
2379
|
+
apiKey = null,
|
|
2380
|
+
mcpUrl = STITCH_MCP_URL
|
|
2381
|
+
}) {
|
|
2382
|
+
return {
|
|
2383
|
+
$typeName: "exa.cascade_plugins_pb.CascadePluginCommandTemplate",
|
|
2384
|
+
command: "npx",
|
|
2385
|
+
args: [
|
|
2386
|
+
"-y",
|
|
2387
|
+
"mcp-remote",
|
|
2388
|
+
mcpUrl,
|
|
2389
|
+
"--header",
|
|
2390
|
+
buildStitchApiHeader({ apiKey })
|
|
2391
|
+
],
|
|
2392
|
+
env: {}
|
|
2266
2393
|
};
|
|
2267
2394
|
}
|
|
2268
2395
|
|
|
@@ -2272,12 +2399,297 @@ function getPostmanApiKeySource({ apiKey, envApiKey }) {
|
|
|
2272
2399
|
return "unset";
|
|
2273
2400
|
}
|
|
2274
2401
|
|
|
2402
|
+
function getStitchApiKeySource({ apiKey, envApiKey }) {
|
|
2403
|
+
if (apiKey) return "inline";
|
|
2404
|
+
if (envApiKey) return "env";
|
|
2405
|
+
return "unset";
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2275
2408
|
function normalizePostmanApiKey(value) {
|
|
2276
2409
|
if (value === undefined || value === null) return null;
|
|
2277
2410
|
const normalized = String(value).trim();
|
|
2278
2411
|
return normalized || null;
|
|
2279
2412
|
}
|
|
2280
2413
|
|
|
2414
|
+
function parseStoredPostmanConfig(raw) {
|
|
2415
|
+
if (!raw || typeof raw !== "object") return null;
|
|
2416
|
+
const source = raw.postman && typeof raw.postman === "object" ? raw.postman : raw;
|
|
2417
|
+
|
|
2418
|
+
const apiKey = normalizePostmanApiKey(source.apiKey);
|
|
2419
|
+
const apiKeyEnvVar = String(source.apiKeyEnvVar || POSTMAN_API_KEY_ENV_VAR).trim() || POSTMAN_API_KEY_ENV_VAR;
|
|
2420
|
+
const mcpUrl = String(source.mcpUrl || POSTMAN_MCP_URL).trim() || POSTMAN_MCP_URL;
|
|
2421
|
+
const defaultWorkspaceId = normalizePostmanWorkspaceId(source.defaultWorkspaceId);
|
|
2422
|
+
|
|
2423
|
+
return {
|
|
2424
|
+
apiKey,
|
|
2425
|
+
apiKeyEnvVar,
|
|
2426
|
+
mcpUrl,
|
|
2427
|
+
defaultWorkspaceId
|
|
2428
|
+
};
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
function parseStoredStitchConfig(raw) {
|
|
2432
|
+
if (!raw || typeof raw !== "object") return null;
|
|
2433
|
+
const source = raw.stitch && typeof raw.stitch === "object" ? raw.stitch : null;
|
|
2434
|
+
if (!source) return null;
|
|
2435
|
+
|
|
2436
|
+
const apiKey = normalizePostmanApiKey(source.apiKey);
|
|
2437
|
+
const apiKeyEnvVar = String(source.apiKeyEnvVar || STITCH_API_KEY_ENV_VAR).trim() || STITCH_API_KEY_ENV_VAR;
|
|
2438
|
+
const mcpUrl = String(source.mcpUrl || STITCH_MCP_URL).trim() || STITCH_MCP_URL;
|
|
2439
|
+
|
|
2440
|
+
return {
|
|
2441
|
+
apiKey,
|
|
2442
|
+
apiKeyEnvVar,
|
|
2443
|
+
mcpUrl
|
|
2444
|
+
};
|
|
2445
|
+
}
|
|
2446
|
+
|
|
2447
|
+
async function readJsonFileIfExists(filePath) {
|
|
2448
|
+
if (!(await pathExists(filePath))) return { exists: false, value: null };
|
|
2449
|
+
try {
|
|
2450
|
+
const raw = await readFile(filePath, "utf8");
|
|
2451
|
+
return { exists: true, value: JSON.parse(raw) };
|
|
2452
|
+
} catch (error) {
|
|
2453
|
+
return { exists: true, value: null, error };
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
|
|
2457
|
+
async function upsertJsonObjectFile({ targetPath, updater, dryRun = false }) {
|
|
2458
|
+
const exists = await pathExists(targetPath);
|
|
2459
|
+
const warnings = [];
|
|
2460
|
+
let parsed = {};
|
|
2461
|
+
|
|
2462
|
+
if (exists) {
|
|
2463
|
+
try {
|
|
2464
|
+
const raw = await readFile(targetPath, "utf8");
|
|
2465
|
+
const decoded = JSON.parse(raw);
|
|
2466
|
+
if (decoded && typeof decoded === "object" && !Array.isArray(decoded)) {
|
|
2467
|
+
parsed = decoded;
|
|
2468
|
+
} else {
|
|
2469
|
+
warnings.push(`Existing JSON at ${targetPath} was not an object. Resetting structure.`);
|
|
2470
|
+
}
|
|
2471
|
+
} catch {
|
|
2472
|
+
warnings.push(`Existing JSON at ${targetPath} could not be parsed. Resetting structure.`);
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
const nextValue = updater(parsed);
|
|
2477
|
+
const content = `${JSON.stringify(nextValue, null, 2)}\n`;
|
|
2478
|
+
const writeResult = await writeGeneratedArtifact({
|
|
2479
|
+
destination: targetPath,
|
|
2480
|
+
content,
|
|
2481
|
+
dryRun
|
|
2482
|
+
});
|
|
2483
|
+
|
|
2484
|
+
return {
|
|
2485
|
+
action: writeResult.action,
|
|
2486
|
+
filePath: targetPath,
|
|
2487
|
+
warnings
|
|
2488
|
+
};
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
async function removeGeneratedArtifactIfExists({ targetPath, dryRun = false }) {
|
|
2492
|
+
const exists = await pathExists(targetPath);
|
|
2493
|
+
if (!exists) {
|
|
2494
|
+
return {
|
|
2495
|
+
action: "missing",
|
|
2496
|
+
path: targetPath
|
|
2497
|
+
};
|
|
2498
|
+
}
|
|
2499
|
+
|
|
2500
|
+
if (!dryRun) {
|
|
2501
|
+
await rm(targetPath, { recursive: true, force: true });
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
return {
|
|
2505
|
+
action: dryRun ? "would-remove" : "removed",
|
|
2506
|
+
path: targetPath
|
|
2507
|
+
};
|
|
2508
|
+
}
|
|
2509
|
+
|
|
2510
|
+
async function applyPostmanMcpForPlatform({
|
|
2511
|
+
platform,
|
|
2512
|
+
mcpScope,
|
|
2513
|
+
apiKey,
|
|
2514
|
+
apiKeyEnvVar,
|
|
2515
|
+
mcpUrl,
|
|
2516
|
+
stitchApiKey,
|
|
2517
|
+
stitchMcpUrl,
|
|
2518
|
+
includeStitchMcp = false,
|
|
2519
|
+
dryRun = false,
|
|
2520
|
+
cwd = process.cwd()
|
|
2521
|
+
}) {
|
|
2522
|
+
const workspaceRoot = findWorkspaceRoot(cwd);
|
|
2523
|
+
const warnings = [];
|
|
2524
|
+
|
|
2525
|
+
if (platform === "antigravity") {
|
|
2526
|
+
const settingsPath =
|
|
2527
|
+
mcpScope === "global"
|
|
2528
|
+
? path.join(os.homedir(), ".gemini", "settings.json")
|
|
2529
|
+
: path.join(workspaceRoot, ".gemini", "settings.json");
|
|
2530
|
+
const result = await upsertJsonObjectFile({
|
|
2531
|
+
targetPath: settingsPath,
|
|
2532
|
+
updater: (existing) => {
|
|
2533
|
+
const next = { ...existing };
|
|
2534
|
+
const mcpServers =
|
|
2535
|
+
next.mcpServers && typeof next.mcpServers === "object" && !Array.isArray(next.mcpServers)
|
|
2536
|
+
? { ...next.mcpServers }
|
|
2537
|
+
: {};
|
|
2538
|
+
mcpServers[POSTMAN_SKILL_ID] = buildGeminiPostmanServer({
|
|
2539
|
+
apiKey,
|
|
2540
|
+
apiKeyEnvVar,
|
|
2541
|
+
mcpUrl
|
|
2542
|
+
});
|
|
2543
|
+
if (includeStitchMcp) {
|
|
2544
|
+
mcpServers[STITCH_MCP_SERVER_ID] = buildGeminiStitchServer({
|
|
2545
|
+
apiKey: stitchApiKey,
|
|
2546
|
+
mcpUrl: stitchMcpUrl
|
|
2547
|
+
});
|
|
2548
|
+
}
|
|
2549
|
+
next.mcpServers = mcpServers;
|
|
2550
|
+
return next;
|
|
2551
|
+
},
|
|
2552
|
+
dryRun
|
|
2553
|
+
});
|
|
2554
|
+
return {
|
|
2555
|
+
kind: "gemini-settings",
|
|
2556
|
+
scope: mcpScope,
|
|
2557
|
+
path: settingsPath,
|
|
2558
|
+
action: result.action,
|
|
2559
|
+
warnings: [...warnings, ...result.warnings]
|
|
2560
|
+
};
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
if (platform === "copilot") {
|
|
2564
|
+
const configPath =
|
|
2565
|
+
mcpScope === "global"
|
|
2566
|
+
? path.join(os.homedir(), ".copilot", "mcp-config.json")
|
|
2567
|
+
: path.join(workspaceRoot, ".vscode", "mcp.json");
|
|
2568
|
+
const result = await upsertJsonObjectFile({
|
|
2569
|
+
targetPath: configPath,
|
|
2570
|
+
updater: (existing) => {
|
|
2571
|
+
const next = { ...existing };
|
|
2572
|
+
const servers =
|
|
2573
|
+
next.servers && typeof next.servers === "object" && !Array.isArray(next.servers)
|
|
2574
|
+
? { ...next.servers }
|
|
2575
|
+
: {};
|
|
2576
|
+
servers[POSTMAN_SKILL_ID] = buildVsCodePostmanServer({
|
|
2577
|
+
apiKey,
|
|
2578
|
+
apiKeyEnvVar,
|
|
2579
|
+
mcpUrl
|
|
2580
|
+
});
|
|
2581
|
+
next.servers = servers;
|
|
2582
|
+
return next;
|
|
2583
|
+
},
|
|
2584
|
+
dryRun
|
|
2585
|
+
});
|
|
2586
|
+
return {
|
|
2587
|
+
kind: mcpScope === "global" ? "copilot-cli-mcp" : "vscode-mcp",
|
|
2588
|
+
scope: mcpScope,
|
|
2589
|
+
path: configPath,
|
|
2590
|
+
action: result.action,
|
|
2591
|
+
warnings: [...warnings, ...result.warnings]
|
|
2592
|
+
};
|
|
2593
|
+
}
|
|
2594
|
+
|
|
2595
|
+
if (platform === "codex") {
|
|
2596
|
+
if (mcpScope === "project") {
|
|
2597
|
+
const vscodePath = path.join(workspaceRoot, ".vscode", "mcp.json");
|
|
2598
|
+
const result = await upsertJsonObjectFile({
|
|
2599
|
+
targetPath: vscodePath,
|
|
2600
|
+
updater: (existing) => {
|
|
2601
|
+
const next = { ...existing };
|
|
2602
|
+
const servers =
|
|
2603
|
+
next.servers && typeof next.servers === "object" && !Array.isArray(next.servers)
|
|
2604
|
+
? { ...next.servers }
|
|
2605
|
+
: {};
|
|
2606
|
+
servers[POSTMAN_SKILL_ID] = buildVsCodePostmanServer({
|
|
2607
|
+
apiKey,
|
|
2608
|
+
apiKeyEnvVar,
|
|
2609
|
+
mcpUrl
|
|
2610
|
+
});
|
|
2611
|
+
next.servers = servers;
|
|
2612
|
+
return next;
|
|
2613
|
+
},
|
|
2614
|
+
dryRun
|
|
2615
|
+
});
|
|
2616
|
+
return {
|
|
2617
|
+
kind: "vscode-mcp",
|
|
2618
|
+
scope: mcpScope,
|
|
2619
|
+
path: vscodePath,
|
|
2620
|
+
action: result.action,
|
|
2621
|
+
warnings: [...warnings, ...result.warnings]
|
|
2622
|
+
};
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2625
|
+
const codexConfigPath = path.join(os.homedir(), ".codex", "config.toml");
|
|
2626
|
+
if (dryRun) {
|
|
2627
|
+
return {
|
|
2628
|
+
kind: "codex-cli",
|
|
2629
|
+
scope: mcpScope,
|
|
2630
|
+
path: codexConfigPath,
|
|
2631
|
+
action: "would-patch",
|
|
2632
|
+
warnings
|
|
2633
|
+
};
|
|
2634
|
+
}
|
|
2635
|
+
|
|
2636
|
+
try {
|
|
2637
|
+
await execFile("codex", ["mcp", "remove", POSTMAN_SKILL_ID], { cwd });
|
|
2638
|
+
} catch {
|
|
2639
|
+
// Best effort. Add will still run and becomes source of truth.
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2642
|
+
try {
|
|
2643
|
+
await execFile(
|
|
2644
|
+
"codex",
|
|
2645
|
+
[
|
|
2646
|
+
"mcp",
|
|
2647
|
+
"add",
|
|
2648
|
+
POSTMAN_SKILL_ID,
|
|
2649
|
+
"--url",
|
|
2650
|
+
mcpUrl,
|
|
2651
|
+
"--bearer-token-env-var",
|
|
2652
|
+
apiKeyEnvVar || POSTMAN_API_KEY_ENV_VAR
|
|
2653
|
+
],
|
|
2654
|
+
{ cwd }
|
|
2655
|
+
);
|
|
2656
|
+
} catch (error) {
|
|
2657
|
+
warnings.push(
|
|
2658
|
+
`Failed to register Postman MCP via Codex CLI. Ensure 'codex' is installed and rerun. (${error.message})`
|
|
2659
|
+
);
|
|
2660
|
+
return {
|
|
2661
|
+
kind: "codex-cli",
|
|
2662
|
+
scope: mcpScope,
|
|
2663
|
+
path: codexConfigPath,
|
|
2664
|
+
action: "failed",
|
|
2665
|
+
warnings
|
|
2666
|
+
};
|
|
2667
|
+
}
|
|
2668
|
+
|
|
2669
|
+
if (apiKey) {
|
|
2670
|
+
warnings.push(
|
|
2671
|
+
"Codex global MCP uses bearer token env vars. Inline apiKey in cbx_config.json is not directly used by Codex."
|
|
2672
|
+
);
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2675
|
+
return {
|
|
2676
|
+
kind: "codex-cli",
|
|
2677
|
+
scope: mcpScope,
|
|
2678
|
+
path: codexConfigPath,
|
|
2679
|
+
action: "patched",
|
|
2680
|
+
warnings
|
|
2681
|
+
};
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
return {
|
|
2685
|
+
kind: "unknown",
|
|
2686
|
+
scope: mcpScope,
|
|
2687
|
+
path: null,
|
|
2688
|
+
action: "skipped",
|
|
2689
|
+
warnings: [`Unsupported platform '${platform}' for Postman MCP installation.`]
|
|
2690
|
+
};
|
|
2691
|
+
}
|
|
2692
|
+
|
|
2281
2693
|
async function ensureGitIgnoreEntry({
|
|
2282
2694
|
filePath,
|
|
2283
2695
|
entry,
|
|
@@ -2310,13 +2722,15 @@ async function ensureGitIgnoreEntry({
|
|
|
2310
2722
|
}
|
|
2311
2723
|
|
|
2312
2724
|
async function resolvePostmanInstallSelection({
|
|
2725
|
+
platform,
|
|
2313
2726
|
scope,
|
|
2314
2727
|
options,
|
|
2315
2728
|
cwd = process.cwd()
|
|
2316
2729
|
}) {
|
|
2317
2730
|
const hasApiKeyOption = options.postmanApiKey !== undefined;
|
|
2318
2731
|
const hasWorkspaceOption = options.postmanWorkspaceId !== undefined;
|
|
2319
|
-
const
|
|
2732
|
+
const hasStitchApiKeyOption = options.stitchApiKey !== undefined;
|
|
2733
|
+
const enabled = Boolean(options.postman) || hasApiKeyOption || hasWorkspaceOption || hasStitchApiKeyOption;
|
|
2320
2734
|
if (!enabled) return { enabled: false };
|
|
2321
2735
|
|
|
2322
2736
|
const explicitApiKey = hasApiKeyOption ? String(options.postmanApiKey || "").trim() : "";
|
|
@@ -2325,7 +2739,14 @@ async function resolvePostmanInstallSelection({
|
|
|
2325
2739
|
let defaultWorkspaceId = hasWorkspaceOption
|
|
2326
2740
|
? normalizePostmanWorkspaceId(options.postmanWorkspaceId)
|
|
2327
2741
|
: null;
|
|
2742
|
+
const requestedMcpScope = options.mcpScope
|
|
2743
|
+
? normalizeMcpScope(options.mcpScope, normalizeMcpScope(scope, "project"))
|
|
2744
|
+
: null;
|
|
2745
|
+
let mcpScope = requestedMcpScope || normalizeMcpScope(scope, "project");
|
|
2328
2746
|
const warnings = [];
|
|
2747
|
+
const stitchEnabled = platform === "antigravity";
|
|
2748
|
+
let stitchApiKey = hasStitchApiKeyOption ? normalizePostmanApiKey(options.stitchApiKey) : null;
|
|
2749
|
+
const envStitchApiKey = normalizePostmanApiKey(process.env[STITCH_API_KEY_ENV_VAR]);
|
|
2329
2750
|
|
|
2330
2751
|
const canPrompt = !options.yes && process.stdin.isTTY;
|
|
2331
2752
|
if (canPrompt && !hasApiKeyOption && !apiKey && !envApiKey) {
|
|
@@ -2348,34 +2769,91 @@ async function resolvePostmanInstallSelection({
|
|
|
2348
2769
|
defaultWorkspaceId = normalizePostmanWorkspaceId(promptedWorkspaceId);
|
|
2349
2770
|
}
|
|
2350
2771
|
|
|
2772
|
+
if (canPrompt && stitchEnabled && !hasStitchApiKeyOption && !stitchApiKey && !envStitchApiKey) {
|
|
2773
|
+
const promptedStitchApiKey = String(
|
|
2774
|
+
await input({
|
|
2775
|
+
message: `Google Stitch API key (optional, leave blank to keep ${STITCH_API_KEY_ENV_VAR} env mode):`,
|
|
2776
|
+
default: ""
|
|
2777
|
+
})
|
|
2778
|
+
).trim();
|
|
2779
|
+
if (promptedStitchApiKey) {
|
|
2780
|
+
stitchApiKey = promptedStitchApiKey;
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
|
|
2784
|
+
if (canPrompt && !requestedMcpScope) {
|
|
2785
|
+
mcpScope = await select({
|
|
2786
|
+
message: "Install MCP config in workspace or global scope?",
|
|
2787
|
+
choices: [
|
|
2788
|
+
{ name: scope === "global" ? "Global (recommended)" : "Global", value: "global" },
|
|
2789
|
+
{ name: scope === "project" ? "Workspace (recommended)" : "Workspace", value: "project" }
|
|
2790
|
+
],
|
|
2791
|
+
default: mcpScope
|
|
2792
|
+
});
|
|
2793
|
+
}
|
|
2794
|
+
|
|
2351
2795
|
const apiKeySource = getPostmanApiKeySource({ apiKey, envApiKey });
|
|
2352
2796
|
if (apiKeySource === "unset") {
|
|
2353
2797
|
warnings.push(POSTMAN_API_KEY_MISSING_WARNING);
|
|
2354
2798
|
}
|
|
2355
2799
|
|
|
2356
|
-
const
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2800
|
+
const stitchApiKeySource = stitchEnabled
|
|
2801
|
+
? getStitchApiKeySource({ apiKey: stitchApiKey, envApiKey: envStitchApiKey })
|
|
2802
|
+
: null;
|
|
2803
|
+
if (stitchEnabled && stitchApiKeySource === "unset") {
|
|
2804
|
+
warnings.push(STITCH_API_KEY_MISSING_WARNING);
|
|
2805
|
+
}
|
|
2806
|
+
if (!stitchEnabled && hasStitchApiKeyOption) {
|
|
2807
|
+
warnings.push("--stitch-api-key is only used for --platform antigravity.");
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2810
|
+
const cbxConfigPath = resolveCbxConfigPath({ scope: mcpScope, cwd });
|
|
2811
|
+
const legacySettingsPath = resolveLegacyPostmanSettingsPath({ scope: mcpScope, cwd });
|
|
2812
|
+
const cbxConfig = {
|
|
2813
|
+
schemaVersion: 1,
|
|
2363
2814
|
generatedBy: "cbx workflows install --postman",
|
|
2364
|
-
generatedAt: new Date().toISOString()
|
|
2815
|
+
generatedAt: new Date().toISOString(),
|
|
2816
|
+
mcp: {
|
|
2817
|
+
scope: mcpScope,
|
|
2818
|
+
server: POSTMAN_SKILL_ID,
|
|
2819
|
+
platform
|
|
2820
|
+
},
|
|
2821
|
+
postman: {
|
|
2822
|
+
apiKey: apiKey || null,
|
|
2823
|
+
apiKeyEnvVar: POSTMAN_API_KEY_ENV_VAR,
|
|
2824
|
+
apiKeySource,
|
|
2825
|
+
defaultWorkspaceId: defaultWorkspaceId ?? null,
|
|
2826
|
+
mcpUrl: POSTMAN_MCP_URL
|
|
2827
|
+
}
|
|
2365
2828
|
};
|
|
2829
|
+
if (stitchEnabled) {
|
|
2830
|
+
cbxConfig.stitch = {
|
|
2831
|
+
server: STITCH_MCP_SERVER_ID,
|
|
2832
|
+
apiKey: stitchApiKey || null,
|
|
2833
|
+
apiKeyEnvVar: STITCH_API_KEY_ENV_VAR,
|
|
2834
|
+
apiKeySource: stitchApiKeySource,
|
|
2835
|
+
mcpUrl: STITCH_MCP_URL
|
|
2836
|
+
};
|
|
2837
|
+
}
|
|
2366
2838
|
|
|
2367
2839
|
return {
|
|
2368
2840
|
enabled: true,
|
|
2369
2841
|
apiKey,
|
|
2370
2842
|
apiKeySource,
|
|
2843
|
+
stitchEnabled,
|
|
2844
|
+
stitchApiKey,
|
|
2845
|
+
stitchApiKeySource,
|
|
2371
2846
|
defaultWorkspaceId: defaultWorkspaceId ?? null,
|
|
2847
|
+
mcpScope,
|
|
2372
2848
|
warnings,
|
|
2373
|
-
|
|
2374
|
-
|
|
2849
|
+
cbxConfig,
|
|
2850
|
+
cbxConfigPath,
|
|
2851
|
+
legacySettingsPath
|
|
2375
2852
|
};
|
|
2376
2853
|
}
|
|
2377
2854
|
|
|
2378
2855
|
async function configurePostmanInstallArtifacts({
|
|
2856
|
+
platform,
|
|
2379
2857
|
scope,
|
|
2380
2858
|
profilePaths,
|
|
2381
2859
|
postmanSelection,
|
|
@@ -2385,34 +2863,55 @@ async function configurePostmanInstallArtifacts({
|
|
|
2385
2863
|
}) {
|
|
2386
2864
|
if (!postmanSelection?.enabled) return null;
|
|
2387
2865
|
|
|
2388
|
-
let warnings = postmanSelection.warnings.filter(
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2866
|
+
let warnings = postmanSelection.warnings.filter(
|
|
2867
|
+
(warning) => warning !== POSTMAN_API_KEY_MISSING_WARNING && warning !== STITCH_API_KEY_MISSING_WARNING
|
|
2868
|
+
);
|
|
2869
|
+
const cbxConfigContent = `${JSON.stringify(postmanSelection.cbxConfig, null, 2)}\n`;
|
|
2870
|
+
const cbxConfigResult = await writeTextFile({
|
|
2871
|
+
targetPath: postmanSelection.cbxConfigPath,
|
|
2872
|
+
content: cbxConfigContent,
|
|
2393
2873
|
overwrite,
|
|
2394
2874
|
dryRun
|
|
2395
2875
|
});
|
|
2396
2876
|
|
|
2397
|
-
let effectiveApiKey = normalizePostmanApiKey(postmanSelection.
|
|
2877
|
+
let effectiveApiKey = normalizePostmanApiKey(postmanSelection.cbxConfig?.postman?.apiKey);
|
|
2878
|
+
let effectiveApiKeyEnvVar = String(
|
|
2879
|
+
postmanSelection.cbxConfig?.postman?.apiKeyEnvVar || POSTMAN_API_KEY_ENV_VAR
|
|
2880
|
+
).trim();
|
|
2398
2881
|
let effectiveDefaultWorkspaceId = postmanSelection.defaultWorkspaceId ?? null;
|
|
2399
|
-
let effectiveMcpUrl = postmanSelection.
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2882
|
+
let effectiveMcpUrl = postmanSelection.cbxConfig?.postman?.mcpUrl || POSTMAN_MCP_URL;
|
|
2883
|
+
const shouldInstallStitch = Boolean(postmanSelection.stitchEnabled);
|
|
2884
|
+
let effectiveStitchApiKey = shouldInstallStitch
|
|
2885
|
+
? normalizePostmanApiKey(postmanSelection.cbxConfig?.stitch?.apiKey)
|
|
2886
|
+
: null;
|
|
2887
|
+
let effectiveStitchMcpUrl = shouldInstallStitch
|
|
2888
|
+
? postmanSelection.cbxConfig?.stitch?.mcpUrl || STITCH_MCP_URL
|
|
2889
|
+
: STITCH_MCP_URL;
|
|
2890
|
+
|
|
2891
|
+
if (cbxConfigResult.action === "skipped" || cbxConfigResult.action === "would-skip") {
|
|
2892
|
+
const existingCbxConfig = await readJsonFileIfExists(postmanSelection.cbxConfigPath);
|
|
2893
|
+
const existingLegacySettings = await readJsonFileIfExists(postmanSelection.legacySettingsPath);
|
|
2894
|
+
const storedPostmanConfig =
|
|
2895
|
+
parseStoredPostmanConfig(existingCbxConfig.value) || parseStoredPostmanConfig(existingLegacySettings.value);
|
|
2896
|
+
const storedStitchConfig =
|
|
2897
|
+
shouldInstallStitch &&
|
|
2898
|
+
(parseStoredStitchConfig(existingCbxConfig.value) || parseStoredStitchConfig(existingLegacySettings.value));
|
|
2899
|
+
|
|
2900
|
+
if (storedPostmanConfig) {
|
|
2901
|
+
effectiveApiKey = storedPostmanConfig.apiKey;
|
|
2902
|
+
effectiveApiKeyEnvVar = storedPostmanConfig.apiKeyEnvVar || POSTMAN_API_KEY_ENV_VAR;
|
|
2903
|
+
effectiveDefaultWorkspaceId = storedPostmanConfig.defaultWorkspaceId;
|
|
2904
|
+
effectiveMcpUrl = storedPostmanConfig.mcpUrl || POSTMAN_MCP_URL;
|
|
2905
|
+
} else {
|
|
2412
2906
|
warnings.push(
|
|
2413
|
-
`Existing ${POSTMAN_SETTINGS_FILENAME} could not be parsed. Using install-time Postman values for MCP config.`
|
|
2907
|
+
`Existing ${CBX_CONFIG_FILENAME} (or legacy ${POSTMAN_SETTINGS_FILENAME}) could not be parsed. Using install-time Postman values for MCP config.`
|
|
2414
2908
|
);
|
|
2415
2909
|
}
|
|
2910
|
+
|
|
2911
|
+
if (storedStitchConfig) {
|
|
2912
|
+
effectiveStitchApiKey = storedStitchConfig.apiKey;
|
|
2913
|
+
effectiveStitchMcpUrl = storedStitchConfig.mcpUrl || STITCH_MCP_URL;
|
|
2914
|
+
}
|
|
2416
2915
|
}
|
|
2417
2916
|
|
|
2418
2917
|
const envApiKey = normalizePostmanApiKey(process.env[POSTMAN_API_KEY_ENV_VAR]);
|
|
@@ -2423,52 +2922,112 @@ async function configurePostmanInstallArtifacts({
|
|
|
2423
2922
|
if (effectiveApiKeySource === "unset") {
|
|
2424
2923
|
warnings.push(POSTMAN_API_KEY_MISSING_WARNING);
|
|
2425
2924
|
}
|
|
2925
|
+
const envStitchApiKey = normalizePostmanApiKey(process.env[STITCH_API_KEY_ENV_VAR]);
|
|
2926
|
+
const effectiveStitchApiKeySource = shouldInstallStitch
|
|
2927
|
+
? getStitchApiKeySource({
|
|
2928
|
+
apiKey: effectiveStitchApiKey,
|
|
2929
|
+
envApiKey: envStitchApiKey
|
|
2930
|
+
})
|
|
2931
|
+
: null;
|
|
2932
|
+
if (shouldInstallStitch && effectiveStitchApiKeySource === "unset") {
|
|
2933
|
+
warnings.push(STITCH_API_KEY_MISSING_WARNING);
|
|
2934
|
+
}
|
|
2426
2935
|
|
|
2427
|
-
|
|
2428
|
-
if (
|
|
2936
|
+
const gitIgnoreResults = [];
|
|
2937
|
+
if (postmanSelection.mcpScope === "project") {
|
|
2429
2938
|
const workspaceRoot = findWorkspaceRoot(cwd);
|
|
2430
2939
|
const gitIgnorePath = path.join(workspaceRoot, ".gitignore");
|
|
2431
|
-
|
|
2940
|
+
const configIgnore = await ensureGitIgnoreEntry({
|
|
2941
|
+
filePath: gitIgnorePath,
|
|
2942
|
+
entry: CBX_CONFIG_FILENAME,
|
|
2943
|
+
dryRun
|
|
2944
|
+
});
|
|
2945
|
+
gitIgnoreResults.push(configIgnore);
|
|
2946
|
+
|
|
2947
|
+
const mcpIgnore = await ensureGitIgnoreEntry({
|
|
2432
2948
|
filePath: gitIgnorePath,
|
|
2433
|
-
entry:
|
|
2949
|
+
entry: ".cbx/mcp/",
|
|
2434
2950
|
dryRun
|
|
2435
2951
|
});
|
|
2952
|
+
gitIgnoreResults.push(mcpIgnore);
|
|
2436
2953
|
}
|
|
2437
2954
|
|
|
2438
|
-
const
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2955
|
+
const mcpDefinitionPath = resolvePostmanMcpDefinitionPath({
|
|
2956
|
+
platform,
|
|
2957
|
+
scope: postmanSelection.mcpScope,
|
|
2958
|
+
cwd
|
|
2959
|
+
});
|
|
2960
|
+
const mcpDefinitionContent = `${JSON.stringify(
|
|
2961
|
+
buildPostmanMcpDefinition({
|
|
2962
|
+
apiKey: effectiveApiKey,
|
|
2963
|
+
apiKeyEnvVar: effectiveApiKeyEnvVar,
|
|
2964
|
+
mcpUrl: effectiveMcpUrl
|
|
2965
|
+
}),
|
|
2966
|
+
null,
|
|
2967
|
+
2
|
|
2968
|
+
)}\n`;
|
|
2969
|
+
const mcpDefinitionResult = await writeGeneratedArtifact({
|
|
2970
|
+
destination: mcpDefinitionPath,
|
|
2971
|
+
content: mcpDefinitionContent,
|
|
2972
|
+
dryRun
|
|
2973
|
+
});
|
|
2974
|
+
let stitchMcpDefinitionPath = null;
|
|
2975
|
+
let stitchMcpDefinitionResult = null;
|
|
2976
|
+
if (shouldInstallStitch) {
|
|
2977
|
+
stitchMcpDefinitionPath = resolveStitchMcpDefinitionPath({
|
|
2978
|
+
scope: postmanSelection.mcpScope,
|
|
2979
|
+
cwd
|
|
2980
|
+
});
|
|
2981
|
+
const stitchMcpDefinitionContent = `${JSON.stringify(
|
|
2982
|
+
buildStitchMcpDefinition({
|
|
2983
|
+
apiKey: effectiveStitchApiKey,
|
|
2984
|
+
mcpUrl: effectiveStitchMcpUrl
|
|
2452
2985
|
}),
|
|
2453
2986
|
null,
|
|
2454
2987
|
2
|
|
2455
2988
|
)}\n`;
|
|
2456
|
-
|
|
2457
|
-
destination:
|
|
2458
|
-
content:
|
|
2989
|
+
stitchMcpDefinitionResult = await writeGeneratedArtifact({
|
|
2990
|
+
destination: stitchMcpDefinitionPath,
|
|
2991
|
+
content: stitchMcpDefinitionContent,
|
|
2459
2992
|
dryRun
|
|
2460
2993
|
});
|
|
2461
2994
|
}
|
|
2462
2995
|
|
|
2996
|
+
const mcpRuntimeResult = await applyPostmanMcpForPlatform({
|
|
2997
|
+
platform,
|
|
2998
|
+
mcpScope: postmanSelection.mcpScope,
|
|
2999
|
+
apiKey: effectiveApiKey,
|
|
3000
|
+
apiKeyEnvVar: effectiveApiKeyEnvVar,
|
|
3001
|
+
mcpUrl: effectiveMcpUrl,
|
|
3002
|
+
stitchApiKey: effectiveStitchApiKey,
|
|
3003
|
+
stitchMcpUrl: effectiveStitchMcpUrl,
|
|
3004
|
+
includeStitchMcp: shouldInstallStitch,
|
|
3005
|
+
dryRun,
|
|
3006
|
+
cwd
|
|
3007
|
+
});
|
|
3008
|
+
warnings.push(...(mcpRuntimeResult.warnings || []));
|
|
3009
|
+
|
|
3010
|
+
const legacySkillMcpCleanup = await removeGeneratedArtifactIfExists({
|
|
3011
|
+
targetPath: path.join(profilePaths.skillsDir, POSTMAN_SKILL_ID, "mcp.json"),
|
|
3012
|
+
dryRun
|
|
3013
|
+
});
|
|
3014
|
+
|
|
2463
3015
|
return {
|
|
2464
3016
|
enabled: true,
|
|
3017
|
+
mcpScope: postmanSelection.mcpScope,
|
|
2465
3018
|
apiKeySource: effectiveApiKeySource,
|
|
3019
|
+
stitchApiKeySource: effectiveStitchApiKeySource,
|
|
2466
3020
|
defaultWorkspaceId: effectiveDefaultWorkspaceId,
|
|
2467
3021
|
warnings,
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
3022
|
+
cbxConfigPath: postmanSelection.cbxConfigPath,
|
|
3023
|
+
cbxConfigResult,
|
|
3024
|
+
gitIgnoreResults,
|
|
3025
|
+
mcpDefinitionPath,
|
|
3026
|
+
mcpDefinitionResult,
|
|
3027
|
+
stitchMcpDefinitionPath,
|
|
3028
|
+
stitchMcpDefinitionResult,
|
|
3029
|
+
mcpRuntimeResult,
|
|
3030
|
+
legacySkillMcpCleanup
|
|
2472
3031
|
};
|
|
2473
3032
|
}
|
|
2474
3033
|
|
|
@@ -2632,12 +3191,13 @@ async function installBundleArtifacts({
|
|
|
2632
3191
|
platform,
|
|
2633
3192
|
scope,
|
|
2634
3193
|
overwrite,
|
|
3194
|
+
profilePathsOverride = null,
|
|
2635
3195
|
extraSkillIds = [],
|
|
2636
3196
|
terminalVerifierSelection = null,
|
|
2637
3197
|
dryRun = false,
|
|
2638
3198
|
cwd = process.cwd()
|
|
2639
3199
|
}) {
|
|
2640
|
-
const profilePaths = await
|
|
3200
|
+
const profilePaths = profilePathsOverride || (await resolveArtifactProfilePaths(platform, scope, cwd));
|
|
2641
3201
|
const platformSpec = manifest.platforms?.[platform];
|
|
2642
3202
|
|
|
2643
3203
|
if (!platformSpec) {
|
|
@@ -2766,6 +3326,46 @@ async function installBundleArtifacts({
|
|
|
2766
3326
|
};
|
|
2767
3327
|
}
|
|
2768
3328
|
|
|
3329
|
+
async function installCodexProjectWorkflowTemplates({
|
|
3330
|
+
bundleId,
|
|
3331
|
+
manifest,
|
|
3332
|
+
overwrite,
|
|
3333
|
+
dryRun = false,
|
|
3334
|
+
cwd = process.cwd()
|
|
3335
|
+
}) {
|
|
3336
|
+
const platform = "codex";
|
|
3337
|
+
const platformSpec = manifest.platforms?.[platform];
|
|
3338
|
+
if (!platformSpec) return { installed: [], skipped: [] };
|
|
3339
|
+
|
|
3340
|
+
const workflowFiles = Array.isArray(platformSpec.workflows) ? platformSpec.workflows : [];
|
|
3341
|
+
if (workflowFiles.length === 0) return { installed: [], skipped: [] };
|
|
3342
|
+
|
|
3343
|
+
const profilePaths = await resolveProfilePaths(platform, "project", cwd);
|
|
3344
|
+
if (!dryRun) {
|
|
3345
|
+
await mkdir(profilePaths.workflowsDir, { recursive: true });
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
const bundleRoot = path.join(agentAssetsRoot(), "workflows", bundleId);
|
|
3349
|
+
const platformRoot = path.join(bundleRoot, "platforms", platform);
|
|
3350
|
+
const installed = [];
|
|
3351
|
+
const skipped = [];
|
|
3352
|
+
|
|
3353
|
+
for (const workflowFile of workflowFiles) {
|
|
3354
|
+
const source = path.join(platformRoot, "workflows", workflowFile);
|
|
3355
|
+
const destination = path.join(profilePaths.workflowsDir, path.basename(workflowFile));
|
|
3356
|
+
|
|
3357
|
+
if (!(await pathExists(source))) {
|
|
3358
|
+
throw new Error(`Missing workflow source file: ${source}`);
|
|
3359
|
+
}
|
|
3360
|
+
|
|
3361
|
+
const result = await copyArtifact({ source, destination, overwrite, dryRun });
|
|
3362
|
+
if (result.action === "skipped" || result.action === "would-skip") skipped.push(destination);
|
|
3363
|
+
else installed.push(destination);
|
|
3364
|
+
}
|
|
3365
|
+
|
|
3366
|
+
return { installed, skipped };
|
|
3367
|
+
}
|
|
3368
|
+
|
|
2769
3369
|
async function seedRuleFileFromTemplateIfMissing({
|
|
2770
3370
|
bundleId,
|
|
2771
3371
|
manifest,
|
|
@@ -2833,10 +3433,11 @@ async function removeBundleArtifacts({
|
|
|
2833
3433
|
manifest,
|
|
2834
3434
|
platform,
|
|
2835
3435
|
scope,
|
|
3436
|
+
profilePathsOverride = null,
|
|
2836
3437
|
dryRun = false,
|
|
2837
3438
|
cwd = process.cwd()
|
|
2838
3439
|
}) {
|
|
2839
|
-
const profilePaths = await
|
|
3440
|
+
const profilePaths = profilePathsOverride || (await resolveArtifactProfilePaths(platform, scope, cwd));
|
|
2840
3441
|
const platformSpec = manifest.platforms?.[platform];
|
|
2841
3442
|
if (!platformSpec) throw new Error(`Bundle '${bundleId}' does not define platform '${platform}'.`);
|
|
2842
3443
|
|
|
@@ -2886,6 +3487,7 @@ function printPlatforms() {
|
|
|
2886
3487
|
);
|
|
2887
3488
|
console.log(` global skills: ${profile.global.skillDirs[0]}`);
|
|
2888
3489
|
console.log(` global rules: ${profile.global.ruleFilesByPriority.join(" | ")}`);
|
|
3490
|
+
console.log(" default install: workflows/agents -> project, skills -> global");
|
|
2889
3491
|
}
|
|
2890
3492
|
}
|
|
2891
3493
|
|
|
@@ -2995,18 +3597,35 @@ function printPostmanSetupSummary({ postmanSetup }) {
|
|
|
2995
3597
|
if (!postmanSetup?.enabled) return;
|
|
2996
3598
|
|
|
2997
3599
|
console.log("\nPostman setup:");
|
|
2998
|
-
console.log(`-
|
|
2999
|
-
console.log(`-
|
|
3600
|
+
console.log(`- MCP scope: ${postmanSetup.mcpScope}`);
|
|
3601
|
+
console.log(`- Config file: ${postmanSetup.cbxConfigResult.action} (${postmanSetup.cbxConfigPath})`);
|
|
3602
|
+
console.log(`- Postman API key source: ${postmanSetup.apiKeySource}`);
|
|
3603
|
+
if (postmanSetup.stitchApiKeySource) {
|
|
3604
|
+
console.log(`- Stitch API key source: ${postmanSetup.stitchApiKeySource}`);
|
|
3605
|
+
}
|
|
3000
3606
|
console.log(
|
|
3001
3607
|
`- Default workspace ID: ${postmanSetup.defaultWorkspaceId === null ? "null" : postmanSetup.defaultWorkspaceId}`
|
|
3002
3608
|
);
|
|
3003
|
-
|
|
3609
|
+
for (const ignoreResult of postmanSetup.gitIgnoreResults || []) {
|
|
3610
|
+
console.log(`- .gitignore (${ignoreResult.filePath}): ${ignoreResult.action}`);
|
|
3611
|
+
}
|
|
3612
|
+
console.log(
|
|
3613
|
+
`- Managed MCP definition (${postmanSetup.mcpDefinitionPath}): ${postmanSetup.mcpDefinitionResult.action}`
|
|
3614
|
+
);
|
|
3615
|
+
if (postmanSetup.stitchMcpDefinitionPath && postmanSetup.stitchMcpDefinitionResult) {
|
|
3004
3616
|
console.log(
|
|
3005
|
-
`-
|
|
3617
|
+
`- Managed Stitch MCP definition (${postmanSetup.stitchMcpDefinitionPath}): ${postmanSetup.stitchMcpDefinitionResult.action}`
|
|
3006
3618
|
);
|
|
3007
3619
|
}
|
|
3008
|
-
if (postmanSetup.
|
|
3009
|
-
console.log(
|
|
3620
|
+
if (postmanSetup.mcpRuntimeResult) {
|
|
3621
|
+
console.log(
|
|
3622
|
+
`- Platform MCP target (${postmanSetup.mcpRuntimeResult.path || "n/a"}): ${postmanSetup.mcpRuntimeResult.action}`
|
|
3623
|
+
);
|
|
3624
|
+
}
|
|
3625
|
+
if (postmanSetup.legacySkillMcpCleanup) {
|
|
3626
|
+
console.log(
|
|
3627
|
+
`- Legacy skill mcp.json cleanup (${postmanSetup.legacySkillMcpCleanup.path}): ${postmanSetup.legacySkillMcpCleanup.action}`
|
|
3628
|
+
);
|
|
3010
3629
|
}
|
|
3011
3630
|
|
|
3012
3631
|
if (postmanSetup.warnings.length > 0) {
|
|
@@ -3060,21 +3679,22 @@ function printRemoveSummary({
|
|
|
3060
3679
|
async function createDoctorReport({ platform, scope, cwd = process.cwd() }) {
|
|
3061
3680
|
const profile = WORKFLOW_PROFILES[platform];
|
|
3062
3681
|
const profilePaths = await resolveProfilePaths(platform, scope, cwd);
|
|
3682
|
+
const artifactPaths = await resolveArtifactProfilePaths(platform, scope, cwd);
|
|
3063
3683
|
const agentsEnabled = platformInstallsCustomAgents(platform);
|
|
3064
3684
|
|
|
3065
3685
|
const pathStatus = {
|
|
3066
3686
|
workflows: {
|
|
3067
|
-
path:
|
|
3068
|
-
exists: await pathExists(
|
|
3687
|
+
path: artifactPaths.workflowsDir,
|
|
3688
|
+
exists: await pathExists(artifactPaths.workflowsDir)
|
|
3069
3689
|
},
|
|
3070
3690
|
agents: {
|
|
3071
|
-
path:
|
|
3691
|
+
path: artifactPaths.agentsDir,
|
|
3072
3692
|
enabled: agentsEnabled,
|
|
3073
|
-
exists: agentsEnabled ? await pathExists(
|
|
3693
|
+
exists: agentsEnabled ? await pathExists(artifactPaths.agentsDir) : null
|
|
3074
3694
|
},
|
|
3075
3695
|
skills: {
|
|
3076
|
-
path:
|
|
3077
|
-
exists: await pathExists(
|
|
3696
|
+
path: artifactPaths.skillsDir,
|
|
3697
|
+
exists: await pathExists(artifactPaths.skillsDir)
|
|
3078
3698
|
}
|
|
3079
3699
|
};
|
|
3080
3700
|
|
|
@@ -3100,7 +3720,7 @@ async function createDoctorReport({ platform, scope, cwd = process.cwd() }) {
|
|
|
3100
3720
|
|
|
3101
3721
|
let terminalIntegration = null;
|
|
3102
3722
|
if (platform === "antigravity") {
|
|
3103
|
-
const integrationDir = getAntigravityTerminalIntegrationDir(
|
|
3723
|
+
const integrationDir = getAntigravityTerminalIntegrationDir(artifactPaths);
|
|
3104
3724
|
const configPath = path.join(integrationDir, "config.json");
|
|
3105
3725
|
const exists = await pathExists(integrationDir);
|
|
3106
3726
|
const configExists = await pathExists(configPath);
|
|
@@ -3220,7 +3840,7 @@ async function createDoctorReport({ platform, scope, cwd = process.cwd() }) {
|
|
|
3220
3840
|
}
|
|
3221
3841
|
|
|
3222
3842
|
if (platform === "copilot" && pathStatus.skills.exists) {
|
|
3223
|
-
const findings = await validateCopilotSkillsSchema(
|
|
3843
|
+
const findings = await validateCopilotSkillsSchema(artifactPaths.skillsDir);
|
|
3224
3844
|
if (findings.length > 0) {
|
|
3225
3845
|
const preview = findings
|
|
3226
3846
|
.slice(0, 5)
|
|
@@ -3236,7 +3856,7 @@ async function createDoctorReport({ platform, scope, cwd = process.cwd() }) {
|
|
|
3236
3856
|
}
|
|
3237
3857
|
|
|
3238
3858
|
if (platform === "copilot" && pathStatus.agents.exists) {
|
|
3239
|
-
const findings = await validateCopilotAgentsSchema(
|
|
3859
|
+
const findings = await validateCopilotAgentsSchema(artifactPaths.agentsDir);
|
|
3240
3860
|
if (findings.length > 0) {
|
|
3241
3861
|
const preview = findings
|
|
3242
3862
|
.slice(0, 5)
|
|
@@ -3326,16 +3946,24 @@ function withInstallOptions(command) {
|
|
|
3326
3946
|
.option("--overwrite", "overwrite existing files")
|
|
3327
3947
|
.option(
|
|
3328
3948
|
"--postman",
|
|
3329
|
-
"optional: install Postman skill and generate
|
|
3949
|
+
"optional: install Postman skill and generate cbx_config.json"
|
|
3330
3950
|
)
|
|
3331
3951
|
.option(
|
|
3332
3952
|
"--postman-api-key <key>",
|
|
3333
|
-
"optional: set Postman API key inline for generated
|
|
3953
|
+
"optional: set Postman API key inline for generated cbx_config.json and installed Postman MCP config"
|
|
3334
3954
|
)
|
|
3335
3955
|
.option(
|
|
3336
3956
|
"--postman-workspace-id <id|null>",
|
|
3337
3957
|
"optional: set default Postman workspace ID (use 'null' for no default)"
|
|
3338
3958
|
)
|
|
3959
|
+
.option(
|
|
3960
|
+
"--stitch-api-key <key>",
|
|
3961
|
+
"optional: Antigravity only. Set Google Stitch API key inline for StitchMCP config"
|
|
3962
|
+
)
|
|
3963
|
+
.option(
|
|
3964
|
+
"--mcp-scope <scope>",
|
|
3965
|
+
"optional: MCP config scope for --postman (project|workspace|global|user)"
|
|
3966
|
+
)
|
|
3339
3967
|
.option(
|
|
3340
3968
|
"--terminal-integration",
|
|
3341
3969
|
"Antigravity only: enable terminal verification integration (prompts for verifier when interactive)"
|
|
@@ -3447,7 +4075,7 @@ async function cleanupAntigravityTerminalIntegration({
|
|
|
3447
4075
|
cwd,
|
|
3448
4076
|
dryRun = false
|
|
3449
4077
|
}) {
|
|
3450
|
-
const profilePaths = await
|
|
4078
|
+
const profilePaths = await resolveArtifactProfilePaths("antigravity", scope, cwd);
|
|
3451
4079
|
const integrationDir = getAntigravityTerminalIntegrationDir(profilePaths);
|
|
3452
4080
|
const dirRemoved = await safeRemove(integrationDir, dryRun);
|
|
3453
4081
|
|
|
@@ -3475,10 +4103,12 @@ async function cleanupAntigravityTerminalIntegration({
|
|
|
3475
4103
|
|
|
3476
4104
|
async function runWorkflowInstall(options) {
|
|
3477
4105
|
try {
|
|
4106
|
+
const cwd = process.cwd();
|
|
3478
4107
|
const scope = normalizeScope(options.scope);
|
|
3479
4108
|
const ruleScope = scope === "global" ? "project" : scope;
|
|
3480
4109
|
const dryRun = Boolean(options.dryRun);
|
|
3481
|
-
const platform = await resolvePlatform(options.platform, scope,
|
|
4110
|
+
const platform = await resolvePlatform(options.platform, scope, cwd);
|
|
4111
|
+
const artifactProfilePaths = await resolveArtifactProfilePaths(platform, scope, cwd);
|
|
3482
4112
|
const bundleId = await chooseBundle(options.bundle);
|
|
3483
4113
|
const manifest = await readBundleManifest(bundleId);
|
|
3484
4114
|
|
|
@@ -3498,9 +4128,10 @@ async function runWorkflowInstall(options) {
|
|
|
3498
4128
|
options
|
|
3499
4129
|
});
|
|
3500
4130
|
const postmanSelection = await resolvePostmanInstallSelection({
|
|
4131
|
+
platform,
|
|
3501
4132
|
scope,
|
|
3502
4133
|
options,
|
|
3503
|
-
cwd
|
|
4134
|
+
cwd
|
|
3504
4135
|
});
|
|
3505
4136
|
|
|
3506
4137
|
const installResult = await installBundleArtifacts({
|
|
@@ -3509,12 +4140,28 @@ async function runWorkflowInstall(options) {
|
|
|
3509
4140
|
platform,
|
|
3510
4141
|
scope,
|
|
3511
4142
|
overwrite: Boolean(options.overwrite),
|
|
4143
|
+
profilePathsOverride: artifactProfilePaths,
|
|
3512
4144
|
extraSkillIds: postmanSelection.enabled ? [POSTMAN_SKILL_ID] : [],
|
|
3513
4145
|
terminalVerifierSelection,
|
|
3514
4146
|
dryRun,
|
|
3515
|
-
cwd
|
|
4147
|
+
cwd
|
|
3516
4148
|
});
|
|
3517
4149
|
|
|
4150
|
+
if (platform === "codex" && scope === "global") {
|
|
4151
|
+
const codexProjectPaths = await resolveProfilePaths("codex", "project", cwd);
|
|
4152
|
+
if (path.resolve(artifactProfilePaths.workflowsDir) !== path.resolve(codexProjectPaths.workflowsDir)) {
|
|
4153
|
+
const codexProjectWorkflows = await installCodexProjectWorkflowTemplates({
|
|
4154
|
+
bundleId,
|
|
4155
|
+
manifest,
|
|
4156
|
+
overwrite: Boolean(options.overwrite),
|
|
4157
|
+
dryRun,
|
|
4158
|
+
cwd
|
|
4159
|
+
});
|
|
4160
|
+
installResult.installed.push(...codexProjectWorkflows.installed);
|
|
4161
|
+
installResult.skipped.push(...codexProjectWorkflows.skipped);
|
|
4162
|
+
}
|
|
4163
|
+
}
|
|
4164
|
+
|
|
3518
4165
|
await seedRuleFileFromTemplateIfMissing({
|
|
3519
4166
|
bundleId,
|
|
3520
4167
|
manifest,
|
|
@@ -3522,14 +4169,14 @@ async function runWorkflowInstall(options) {
|
|
|
3522
4169
|
scope: ruleScope,
|
|
3523
4170
|
overwrite: Boolean(options.overwrite),
|
|
3524
4171
|
dryRun,
|
|
3525
|
-
cwd
|
|
4172
|
+
cwd
|
|
3526
4173
|
});
|
|
3527
4174
|
|
|
3528
4175
|
const syncResult = await syncRulesForPlatform({
|
|
3529
4176
|
platform,
|
|
3530
4177
|
scope: ruleScope,
|
|
3531
4178
|
dryRun,
|
|
3532
|
-
cwd
|
|
4179
|
+
cwd
|
|
3533
4180
|
});
|
|
3534
4181
|
const engineeringArtifactsResult = await upsertEngineeringArtifacts({
|
|
3535
4182
|
platform,
|
|
@@ -3537,22 +4184,23 @@ async function runWorkflowInstall(options) {
|
|
|
3537
4184
|
overwrite: false,
|
|
3538
4185
|
dryRun,
|
|
3539
4186
|
skipTech: false,
|
|
3540
|
-
cwd
|
|
4187
|
+
cwd
|
|
3541
4188
|
});
|
|
3542
4189
|
const postmanSetupResult = await configurePostmanInstallArtifacts({
|
|
4190
|
+
platform,
|
|
3543
4191
|
scope,
|
|
3544
4192
|
profilePaths: installResult.profilePaths,
|
|
3545
4193
|
postmanSelection,
|
|
3546
4194
|
overwrite: Boolean(options.overwrite),
|
|
3547
4195
|
dryRun,
|
|
3548
|
-
cwd
|
|
4196
|
+
cwd
|
|
3549
4197
|
});
|
|
3550
4198
|
|
|
3551
4199
|
const terminalVerificationRuleResult =
|
|
3552
4200
|
platform === "antigravity" && installResult.terminalIntegration
|
|
3553
4201
|
? await upsertTerminalVerificationForInstall({
|
|
3554
4202
|
scope: ruleScope,
|
|
3555
|
-
cwd
|
|
4203
|
+
cwd,
|
|
3556
4204
|
terminalIntegration: installResult.terminalIntegration,
|
|
3557
4205
|
dryRun
|
|
3558
4206
|
})
|
|
@@ -3565,7 +4213,7 @@ async function runWorkflowInstall(options) {
|
|
|
3565
4213
|
bundleId,
|
|
3566
4214
|
artifacts: installResult.artifacts,
|
|
3567
4215
|
ruleFilePath: syncResult.filePath,
|
|
3568
|
-
cwd
|
|
4216
|
+
cwd
|
|
3569
4217
|
});
|
|
3570
4218
|
}
|
|
3571
4219
|
|
|
@@ -3611,9 +4259,12 @@ async function runWorkflowRemove(target, options) {
|
|
|
3611
4259
|
throw new Error("Missing <bundle-or-workflow>. Usage: cbx workflows remove <bundle-or-workflow>");
|
|
3612
4260
|
}
|
|
3613
4261
|
|
|
4262
|
+
const cwd = process.cwd();
|
|
3614
4263
|
const scope = normalizeScope(options.scope);
|
|
4264
|
+
const ruleScope = scope === "global" ? "project" : scope;
|
|
3615
4265
|
const dryRun = Boolean(options.dryRun);
|
|
3616
|
-
const platform = await resolvePlatform(options.platform, scope,
|
|
4266
|
+
const platform = await resolvePlatform(options.platform, scope, cwd);
|
|
4267
|
+
const artifactProfilePaths = await resolveArtifactProfilePaths(platform, scope, cwd);
|
|
3617
4268
|
const bundleIds = await listBundleIds();
|
|
3618
4269
|
|
|
3619
4270
|
let removed = [];
|
|
@@ -3640,8 +4291,9 @@ async function runWorkflowRemove(target, options) {
|
|
|
3640
4291
|
manifest,
|
|
3641
4292
|
platform,
|
|
3642
4293
|
scope,
|
|
4294
|
+
profilePathsOverride: artifactProfilePaths,
|
|
3643
4295
|
dryRun,
|
|
3644
|
-
cwd
|
|
4296
|
+
cwd
|
|
3645
4297
|
});
|
|
3646
4298
|
|
|
3647
4299
|
removed = removeResult.removed;
|
|
@@ -3649,7 +4301,7 @@ async function runWorkflowRemove(target, options) {
|
|
|
3649
4301
|
if (platform === "antigravity") {
|
|
3650
4302
|
terminalIntegrationCleanup = await cleanupAntigravityTerminalIntegration({
|
|
3651
4303
|
scope,
|
|
3652
|
-
cwd
|
|
4304
|
+
cwd,
|
|
3653
4305
|
dryRun
|
|
3654
4306
|
});
|
|
3655
4307
|
if (terminalIntegrationCleanup.dirRemoved) {
|
|
@@ -3657,8 +4309,7 @@ async function runWorkflowRemove(target, options) {
|
|
|
3657
4309
|
}
|
|
3658
4310
|
}
|
|
3659
4311
|
} else {
|
|
3660
|
-
const
|
|
3661
|
-
const workflowFile = await findWorkflowFileByTarget(profilePaths.workflowsDir, target);
|
|
4312
|
+
const workflowFile = await findWorkflowFileByTarget(artifactProfilePaths.workflowsDir, target);
|
|
3662
4313
|
|
|
3663
4314
|
if (!workflowFile) {
|
|
3664
4315
|
throw new Error(`Could not find workflow or bundle '${target}' in platform '${platform}'.`);
|
|
@@ -3682,9 +4333,9 @@ async function runWorkflowRemove(target, options) {
|
|
|
3682
4333
|
|
|
3683
4334
|
const syncResult = await syncRulesForPlatform({
|
|
3684
4335
|
platform,
|
|
3685
|
-
scope,
|
|
4336
|
+
scope: ruleScope,
|
|
3686
4337
|
dryRun,
|
|
3687
|
-
cwd
|
|
4338
|
+
cwd
|
|
3688
4339
|
});
|
|
3689
4340
|
|
|
3690
4341
|
if (!dryRun && removedType === "bundle") {
|
|
@@ -3693,7 +4344,7 @@ async function runWorkflowRemove(target, options) {
|
|
|
3693
4344
|
platform,
|
|
3694
4345
|
bundleId: target,
|
|
3695
4346
|
ruleFilePath: syncResult.filePath,
|
|
3696
|
-
cwd
|
|
4347
|
+
cwd
|
|
3697
4348
|
});
|
|
3698
4349
|
}
|
|
3699
4350
|
|