@cubis/foundry 0.3.23 → 0.3.24

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.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/bin/cubis.js +106 -5
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -59,6 +59,7 @@ cbx workflows install --platform antigravity --dry-run
59
59
  cbx workflows install --platform antigravity --terminal-integration --terminal-verifier codex
60
60
  cbx workflows install --platform codex --postman
61
61
  cbx workflows install --platform codex --postman --postman-workspace-id null
62
+ cbx workflows install --platform codex --postman --postman-workspace-id "<workspace-id>"
62
63
  cbx workflows install --platform codex --postman --postman-api-key "<key>"
63
64
  cbx workflows install --platform codex --postman --mcp-scope global
64
65
  cbx workflows install --platform copilot --postman --mcp-scope project
@@ -83,6 +84,7 @@ Postman + Antigravity Stitch setup behavior:
83
84
  - Env-first auth is supported: when `POSTMAN_API_KEY` is set, generated settings keep `apiKey: null` and MCP config uses `Bearer ${POSTMAN_API_KEY}`.
84
85
  - Inline auth is supported with `--postman-api-key <key>`.
85
86
  - `--postman-workspace-id null` writes JSON `null` for `defaultWorkspaceId`.
87
+ - If `POSTMAN_API_KEY` is available and install is interactive (no `--yes`) without `--postman-workspace-id`, `cbx` fetches your Postman workspaces and prompts you to pick one as default.
86
88
  - Antigravity gets an additional managed file at `.cbx/mcp/antigravity/stitch.json` (or `~/.cbx/mcp/antigravity/stitch.json` in global MCP scope).
87
89
  - 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`.
88
90
  - In project MCP scope, `cbx_config.json` and `.cbx/mcp/` are auto-added to `.gitignore` (no duplicate entries).
package/bin/cubis.js CHANGED
@@ -127,11 +127,13 @@ const TERMINAL_VERIFIER_PROVIDERS = ["codex", "gemini"];
127
127
  const DEFAULT_TERMINAL_VERIFIER = "codex";
128
128
  const POSTMAN_API_KEY_ENV_VAR = "POSTMAN_API_KEY";
129
129
  const POSTMAN_MCP_URL = "https://mcp.postman.com/minimal";
130
+ const POSTMAN_API_BASE_URL = "https://api.getpostman.com";
130
131
  const POSTMAN_SKILL_ID = "postman";
131
132
  const STITCH_MCP_SERVER_ID = "StitchMCP";
132
133
  const STITCH_API_KEY_ENV_VAR = "STITCH_API_KEY";
133
134
  const STITCH_MCP_URL = "https://stitch.googleapis.com/mcp";
134
135
  const STITCH_API_KEY_PLACEHOLDER = "ur stitch key";
136
+ const POSTMAN_WORKSPACE_MANUAL_CHOICE = "__postman_workspace_manual__";
135
137
  const CBX_CONFIG_FILENAME = "cbx_config.json";
136
138
  const POSTMAN_SETTINGS_FILENAME = "postman_setting.json";
137
139
  const POSTMAN_API_KEY_MISSING_WARNING =
@@ -2428,6 +2430,57 @@ function parseStoredPostmanConfig(raw) {
2428
2430
  };
2429
2431
  }
2430
2432
 
2433
+ async function fetchPostmanWorkspaces({
2434
+ apiKey,
2435
+ apiBaseUrl = POSTMAN_API_BASE_URL,
2436
+ timeoutMs = 12000
2437
+ }) {
2438
+ if (!apiKey) return [];
2439
+
2440
+ const controller = new AbortController();
2441
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
2442
+ const endpoint = `${apiBaseUrl.replace(/\/$/, "")}/workspaces`;
2443
+
2444
+ try {
2445
+ const response = await fetch(endpoint, {
2446
+ method: "GET",
2447
+ headers: {
2448
+ "X-Api-Key": apiKey,
2449
+ Accept: "application/json"
2450
+ },
2451
+ signal: controller.signal
2452
+ });
2453
+
2454
+ const payload = await response.json().catch(() => null);
2455
+ if (!response.ok) {
2456
+ const message =
2457
+ payload?.error?.message ||
2458
+ payload?.error?.name ||
2459
+ `Postman API request failed (${response.status} ${response.statusText}).`;
2460
+ throw new Error(message);
2461
+ }
2462
+
2463
+ const workspaces = Array.isArray(payload?.workspaces) ? payload.workspaces : [];
2464
+ return workspaces
2465
+ .map((workspace) => {
2466
+ const id = normalizePostmanWorkspaceId(workspace?.id);
2467
+ if (!id) return null;
2468
+ const name = String(workspace?.name || "").trim() || id;
2469
+ const type = String(workspace?.type || "").trim() || null;
2470
+ const visibility = String(workspace?.visibility || "").trim() || null;
2471
+ return { id, name, type, visibility };
2472
+ })
2473
+ .filter(Boolean);
2474
+ } catch (error) {
2475
+ if (error?.name === "AbortError") {
2476
+ throw new Error("Postman workspace lookup timed out.");
2477
+ }
2478
+ throw error;
2479
+ } finally {
2480
+ clearTimeout(timeout);
2481
+ }
2482
+ }
2483
+
2431
2484
  function parseStoredStitchConfig(raw) {
2432
2485
  if (!raw || typeof raw !== "object") return null;
2433
2486
  const source = raw.stitch && typeof raw.stitch === "object" ? raw.stitch : null;
@@ -2762,11 +2815,59 @@ async function resolvePostmanInstallSelection({
2762
2815
  }
2763
2816
 
2764
2817
  if (canPrompt && !hasWorkspaceOption) {
2765
- const promptedWorkspaceId = await input({
2766
- message: "Default Postman workspace ID (optional, leave blank for null):",
2767
- default: ""
2768
- });
2769
- defaultWorkspaceId = normalizePostmanWorkspaceId(promptedWorkspaceId);
2818
+ const selectableApiKey = normalizePostmanApiKey(apiKey || envApiKey);
2819
+ let usedWorkspaceSelector = false;
2820
+ let selectedWorkspaceId = defaultWorkspaceId;
2821
+
2822
+ if (selectableApiKey) {
2823
+ try {
2824
+ const fetchedWorkspaces = await fetchPostmanWorkspaces({
2825
+ apiKey: selectableApiKey
2826
+ });
2827
+ if (fetchedWorkspaces.length > 0) {
2828
+ usedWorkspaceSelector = true;
2829
+ const sortedWorkspaces = [...fetchedWorkspaces].sort((a, b) => a.name.localeCompare(b.name));
2830
+ const workspaceChoice = await select({
2831
+ message: "Choose default Postman workspace for this install:",
2832
+ choices: [
2833
+ { name: "No default workspace (null)", value: null },
2834
+ ...sortedWorkspaces.map((workspace) => {
2835
+ const details = [workspace.type, workspace.visibility].filter(Boolean).join(", ");
2836
+ const suffix = details ? ` - ${details}` : "";
2837
+ return {
2838
+ name: `${workspace.name} (${workspace.id})${suffix}`,
2839
+ value: workspace.id
2840
+ };
2841
+ }),
2842
+ { name: "Enter workspace ID manually", value: POSTMAN_WORKSPACE_MANUAL_CHOICE }
2843
+ ],
2844
+ default: null
2845
+ });
2846
+
2847
+ if (workspaceChoice === POSTMAN_WORKSPACE_MANUAL_CHOICE) {
2848
+ const promptedWorkspaceId = await input({
2849
+ message: "Default Postman workspace ID (optional, leave blank for null):",
2850
+ default: ""
2851
+ });
2852
+ selectedWorkspaceId = normalizePostmanWorkspaceId(promptedWorkspaceId);
2853
+ } else {
2854
+ selectedWorkspaceId = normalizePostmanWorkspaceId(workspaceChoice);
2855
+ }
2856
+ }
2857
+ } catch (error) {
2858
+ warnings.push(`Could not load Postman workspaces for selection: ${error.message}`);
2859
+ }
2860
+ }
2861
+
2862
+ if (!usedWorkspaceSelector) {
2863
+ const promptedWorkspaceId = await input({
2864
+ message: "Default Postman workspace ID (optional, leave blank for null):",
2865
+ default: ""
2866
+ });
2867
+ selectedWorkspaceId = normalizePostmanWorkspaceId(promptedWorkspaceId);
2868
+ }
2869
+
2870
+ defaultWorkspaceId = selectedWorkspaceId;
2770
2871
  }
2771
2872
 
2772
2873
  if (canPrompt && stitchEnabled && !hasStitchApiKeyOption && !stitchApiKey && !envStitchApiKey) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cubis/foundry",
3
- "version": "0.3.23",
3
+ "version": "0.3.24",
4
4
  "description": "Cubis Foundry CLI for workflow-first AI agent environments",
5
5
  "type": "module",
6
6
  "bin": {