@cubis/foundry 0.3.54 → 0.3.56

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/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
+ ## [0.3.56] - 2026-03-05
6
+
7
+ ### Fixed
8
+
9
+ - Improved `cbx remove all` cleanup coverage:
10
+ - removes CBX-managed skills from all configured profile path candidates (not just a single preferred path)
11
+ - includes legacy Codex skill path cleanup (`~/.codex/skills`) for managed artifacts
12
+ - removes empty global CBX roots (`~/.cbx`, `~/.agents`) after cleanup when eligible.
13
+ - Ensured global remove flow clears CBX-managed profile/config artifacts consistently (`~/.cbx/cbx_config.json`, `~/.cbx/state.json`, `~/.cbx/credentials.env` when present).
14
+
15
+ ## [0.3.55] - 2026-03-05
16
+
17
+ ### Added
18
+
19
+ - Added Postman workspace selection step to `cbx init` wizard:
20
+ - interactive workspace list from Postman API when key is available
21
+ - manual workspace ID fallback prompt when listing is unavailable.
22
+ - Added non-interactive workspace flag for wizard:
23
+ - `cbx init --postman-workspace-id <id|null>`
24
+
25
+ ### Changed
26
+
27
+ - Updated wizard execution mapping so selected Postman workspace is persisted through install flow.
28
+ - Updated init wizard docs and TTY smoke test to validate the new workspace selection step.
29
+
5
30
  ## [0.3.54] - 2026-03-05
6
31
 
7
32
  ### Added
package/README.md CHANGED
@@ -72,7 +72,7 @@ Wizard flow:
72
72
  - MCP selection (`Cubis Foundry`, `Postman`, `Stitch`)
73
73
  - Separate scope selection for Skills and MCP (`project` or `global`)
74
74
  - MCP runtime selection (`cbx mcp serve` local, Docker pull, Docker local build) when Postman/Stitch is enabled
75
- - Conditional Postman mode/key and Stitch key prompts
75
+ - Conditional Postman mode/key/workspace and Stitch key prompts
76
76
  - Final summary + confirmation
77
77
 
78
78
  Non-interactive default mode:
@@ -95,6 +95,7 @@ cbx init \
95
95
  --mcps cubis-foundry,postman,stitch \
96
96
  --mcp-scope global \
97
97
  --postman-mode minimal \
98
+ --postman-workspace-id null \
98
99
  --mcp-runtime local
99
100
  ```
100
101
 
@@ -21,6 +21,7 @@ export function registerCommands(deps) {
21
21
  .option("--mcp-scope <scope>", "scope for MCP config: global|project")
22
22
  .option("--mcps <items>", "comma-separated MCP selections: cubis-foundry,postman,stitch")
23
23
  .option("--postman-mode <mode>", "Postman mode: full|minimal")
24
+ .option("--postman-workspace-id <id|null>", "optional: set default Postman workspace ID (use 'null' for no default)")
24
25
  .option("--mcp-runtime <runtime>", "MCP runtime: docker|local")
25
26
  .option("--mcp-build-local", "when MCP runtime is docker, build image locally instead of pulling")
26
27
  .option("--no-banner", "skip init welcome banner")
@@ -1 +1 @@
1
- {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/cli/commands/register.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/cli/commands/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AA4B7D,MAAM,UAAU,gBAAgB,CAAC,IAAyB;IACxD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC9B,OAAO;SACJ,IAAI,CAAC,KAAK,CAAC;SACX,WAAW,CAAC,4DAA4D,CAAC;SACzE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAE5B,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,uCAAuC,CAAC;SACpD,MAAM,CAAC,WAAW,EAAE,gDAAgD,CAAC;SACrE,MAAM,CAAC,WAAW,EAAE,gDAAgD,CAAC;SACrE,MAAM,CAAC,iBAAiB,EAAE,sCAAsC,CAAC;SACjE,MAAM,CAAC,qBAAqB,EAAE,oBAAoB,CAAC;SACnD,MAAM,CACL,qBAAqB,EACrB,sDAAsD,CACvD;SACA,MAAM,CACL,2BAA2B,EAC3B,uCAAuC,CACxC;SACA,MAAM,CACL,wBAAwB,EACxB,0CAA0C,CAC3C;SACA,MAAM,CAAC,qBAAqB,EAAE,sCAAsC,CAAC;SACrE,MAAM,CACL,gBAAgB,EAChB,8DAA8D,CAC/D;SACA,MAAM,CAAC,uBAAuB,EAAE,4BAA4B,CAAC;SAC7D,MAAM,CACL,kCAAkC,EAClC,wEAAwE,CACzE;SACA,MAAM,CAAC,yBAAyB,EAAE,2BAA2B,CAAC;SAC9D,MAAM,CACL,mBAAmB,EACnB,oEAAoE,CACrE;SACA,MAAM,CAAC,aAAa,EAAE,0BAA0B,CAAC;SACjD,MAAM,CAAC,QAAQ,EAAE,sCAAsC,CAAC;SACxD,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAE9B,wBAAwB,CAAC,OAAO,EAAE;QAChC,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;QAC3C,uBAAuB,EAAE,IAAI,CAAC,uBAAuB;QACrD,6BAA6B,EAAE,IAAI,CAAC,6BAA6B;QACjE,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;QAC3C,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;QACzC,oBAAoB,EAAE,IAAI,CAAC,oBAAoB;QAC/C,sBAAsB,EAAE,IAAI,CAAC,sBAAsB;QACnD,oBAAoB,EAAE,IAAI,CAAC,oBAAoB;QAC/C,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;QACzC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;QACzC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;KAC9C,CAAC,CAAC;IAEH,mBAAmB,CAAC,OAAO,EAAE;QAC3B,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;QAC7C,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;QACzC,6BAA6B,EAAE,IAAI,CAAC,6BAA6B;KAClE,CAAC,CAAC;IAEH,qBAAqB,CAAC,OAAO,EAAE;QAC7B,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,cAAc,EAAE,IAAI,CAAC,cAAc;KACpC,CAAC,CAAC;IAEH,MAAM,aAAa,GAAG,OAAO;SAC1B,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,0BAA0B,CAAC,CAAC;IAE3C,MAAM,aAAa,GAAG,OAAO;SAC1B,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,yCAAyC,CAAC,CAAC;IAC1D,aAAa;SACV,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CACV,uFAAuF,CACxF;SACA,MAAM,CACL,2BAA2B,EAC3B,4CAA4C,EAC5C,KAAK,CACN;SACA,MAAM,CACL,iBAAiB,EACjB,iDAAiD,EACjD,KAAK,CACN;SACA,MAAM,CACL,iBAAiB,EACjB,8DAA8D,CAC/D;SACA,MAAM,CACL,uBAAuB,EACvB,+DAA+D,CAChE;SACA,MAAM,CAAC,WAAW,EAAE,iDAAiD,CAAC;SACtE,MAAM,CAAC,WAAW,EAAE,+BAA+B,CAAC;SACpD,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACrC,aAAa,CAAC,MAAM,CAAC,GAAG,EAAE;QACxB,aAAa,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,aAAa;SACV,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,mCAAmC,CAAC;SAChD,MAAM,CAAC,GAAG,EAAE;QACX,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;QAC7D,OAAO,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEL,aAAa,CAAC,MAAM,CAAC,GAAG,EAAE;QACxB,aAAa,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACjB,CAAC"}
package/dist/cli/core.js CHANGED
@@ -2246,6 +2246,45 @@ async function resolveProfilePaths(profileId, scope, cwd = process.cwd()) {
2246
2246
  ruleFilesByPriority: cfg.ruleFilesByPriority.map((filePath) => expandPath(filePath, cwd)),
2247
2247
  };
2248
2248
  }
2249
+ function expandUniquePaths(pathList, cwd = process.cwd()) {
2250
+ const seen = new Set();
2251
+ const output = [];
2252
+ for (const value of pathList || []) {
2253
+ const normalized = String(value || "").trim();
2254
+ if (!normalized)
2255
+ continue;
2256
+ const expanded = expandPath(normalized, cwd);
2257
+ const key = path.resolve(expanded);
2258
+ if (seen.has(key))
2259
+ continue;
2260
+ seen.add(key);
2261
+ output.push(expanded);
2262
+ }
2263
+ return output;
2264
+ }
2265
+ function resolveProfilePathCandidates(profileId, scope, cwd = process.cwd()) {
2266
+ const profile = WORKFLOW_PROFILES[profileId];
2267
+ if (!profile)
2268
+ throw new Error(`Unknown platform '${profileId}'.`);
2269
+ const cfg = profile[scope];
2270
+ return {
2271
+ workflowsDirs: expandUniquePaths(cfg.workflowDirs, cwd),
2272
+ agentsDirs: expandUniquePaths(cfg.agentDirs, cwd),
2273
+ skillsDirs: expandUniquePaths(cfg.skillDirs, cwd),
2274
+ commandsDirs: expandUniquePaths(cfg.commandDirs, cwd),
2275
+ promptsDirs: expandUniquePaths(cfg.promptDirs, cwd),
2276
+ ruleFilesByPriority: expandUniquePaths(cfg.ruleFilesByPriority, cwd),
2277
+ };
2278
+ }
2279
+ function resolveLegacySkillDirsForCleanup(platform, scope, cwd = process.cwd()) {
2280
+ if (platform !== "codex")
2281
+ return [];
2282
+ if (scope === "global") {
2283
+ return [path.join(os.homedir(), ".codex", "skills")];
2284
+ }
2285
+ const workspaceRoot = findWorkspaceRoot(cwd);
2286
+ return [path.join(workspaceRoot, ".codex", "skills")];
2287
+ }
2249
2288
  async function resolveArtifactProfilePaths(profileId, scope, cwd = process.cwd()) {
2250
2289
  const scopedPaths = await resolveProfilePaths(profileId, scope, cwd);
2251
2290
  if (scope !== "global")
@@ -3808,6 +3847,69 @@ async function fetchPostmanWorkspaces({ apiKey, apiBaseUrl = POSTMAN_API_BASE_UR
3808
3847
  clearTimeout(timeout);
3809
3848
  }
3810
3849
  }
3850
+ async function promptPostmanWorkspaceSelection({ apiKey, defaultWorkspaceId = null, }) {
3851
+ let selectedWorkspaceId = normalizePostmanWorkspaceId(defaultWorkspaceId);
3852
+ let usedWorkspaceSelector = false;
3853
+ const warnings = [];
3854
+ const selectableApiKey = normalizePostmanApiKey(apiKey);
3855
+ if (selectableApiKey) {
3856
+ try {
3857
+ const fetchedWorkspaces = await fetchPostmanWorkspaces({
3858
+ apiKey: selectableApiKey,
3859
+ });
3860
+ if (fetchedWorkspaces.length > 0) {
3861
+ usedWorkspaceSelector = true;
3862
+ const sortedWorkspaces = [...fetchedWorkspaces].sort((a, b) => a.name.localeCompare(b.name));
3863
+ const workspaceChoice = await select({
3864
+ message: "Choose default Postman workspace for this install:",
3865
+ choices: [
3866
+ { name: "No default workspace (null)", value: null },
3867
+ ...sortedWorkspaces.map((workspace) => {
3868
+ const details = [workspace.type, workspace.visibility]
3869
+ .filter(Boolean)
3870
+ .join(", ");
3871
+ const suffix = details ? ` - ${details}` : "";
3872
+ return {
3873
+ name: `${workspace.name} (${workspace.id})${suffix}`,
3874
+ value: workspace.id,
3875
+ };
3876
+ }),
3877
+ {
3878
+ name: "Enter workspace ID manually",
3879
+ value: POSTMAN_WORKSPACE_MANUAL_CHOICE,
3880
+ },
3881
+ ],
3882
+ default: selectedWorkspaceId,
3883
+ });
3884
+ if (workspaceChoice === POSTMAN_WORKSPACE_MANUAL_CHOICE) {
3885
+ const promptedWorkspaceId = await input({
3886
+ message: "Default Postman workspace ID (optional, leave blank for null):",
3887
+ default: selectedWorkspaceId || "",
3888
+ });
3889
+ selectedWorkspaceId =
3890
+ normalizePostmanWorkspaceId(promptedWorkspaceId);
3891
+ }
3892
+ else {
3893
+ selectedWorkspaceId = normalizePostmanWorkspaceId(workspaceChoice);
3894
+ }
3895
+ }
3896
+ }
3897
+ catch (error) {
3898
+ warnings.push(`Could not load Postman workspaces for selection: ${error.message}`);
3899
+ }
3900
+ }
3901
+ if (!usedWorkspaceSelector) {
3902
+ const promptedWorkspaceId = await input({
3903
+ message: "Default Postman workspace ID (optional, leave blank for null):",
3904
+ default: selectedWorkspaceId || "",
3905
+ });
3906
+ selectedWorkspaceId = normalizePostmanWorkspaceId(promptedWorkspaceId);
3907
+ }
3908
+ return {
3909
+ workspaceId: selectedWorkspaceId,
3910
+ warnings,
3911
+ };
3912
+ }
3811
3913
  function parseJsonLenient(raw) {
3812
3914
  try {
3813
3915
  return {
@@ -4203,63 +4305,12 @@ async function resolvePostmanInstallSelection({ platform, scope, options, cwd =
4203
4305
  const foundryMcpEnabled = options.foundryMcp !== false;
4204
4306
  const canPrompt = !options.yes && process.stdin.isTTY;
4205
4307
  if (postmanRequested && canPrompt && !hasWorkspaceOption) {
4206
- const selectableApiKey = normalizePostmanApiKey(envApiKey);
4207
- let usedWorkspaceSelector = false;
4208
- let selectedWorkspaceId = defaultWorkspaceId;
4209
- if (selectableApiKey) {
4210
- try {
4211
- const fetchedWorkspaces = await fetchPostmanWorkspaces({
4212
- apiKey: selectableApiKey,
4213
- });
4214
- if (fetchedWorkspaces.length > 0) {
4215
- usedWorkspaceSelector = true;
4216
- const sortedWorkspaces = [...fetchedWorkspaces].sort((a, b) => a.name.localeCompare(b.name));
4217
- const workspaceChoice = await select({
4218
- message: "Choose default Postman workspace for this install:",
4219
- choices: [
4220
- { name: "No default workspace (null)", value: null },
4221
- ...sortedWorkspaces.map((workspace) => {
4222
- const details = [workspace.type, workspace.visibility]
4223
- .filter(Boolean)
4224
- .join(", ");
4225
- const suffix = details ? ` - ${details}` : "";
4226
- return {
4227
- name: `${workspace.name} (${workspace.id})${suffix}`,
4228
- value: workspace.id,
4229
- };
4230
- }),
4231
- {
4232
- name: "Enter workspace ID manually",
4233
- value: POSTMAN_WORKSPACE_MANUAL_CHOICE,
4234
- },
4235
- ],
4236
- default: null,
4237
- });
4238
- if (workspaceChoice === POSTMAN_WORKSPACE_MANUAL_CHOICE) {
4239
- const promptedWorkspaceId = await input({
4240
- message: "Default Postman workspace ID (optional, leave blank for null):",
4241
- default: "",
4242
- });
4243
- selectedWorkspaceId =
4244
- normalizePostmanWorkspaceId(promptedWorkspaceId);
4245
- }
4246
- else {
4247
- selectedWorkspaceId = normalizePostmanWorkspaceId(workspaceChoice);
4248
- }
4249
- }
4250
- }
4251
- catch (error) {
4252
- warnings.push(`Could not load Postman workspaces for selection: ${error.message}`);
4253
- }
4254
- }
4255
- if (!usedWorkspaceSelector) {
4256
- const promptedWorkspaceId = await input({
4257
- message: "Default Postman workspace ID (optional, leave blank for null):",
4258
- default: "",
4259
- });
4260
- selectedWorkspaceId = normalizePostmanWorkspaceId(promptedWorkspaceId);
4261
- }
4262
- defaultWorkspaceId = selectedWorkspaceId;
4308
+ const workspaceSelection = await promptPostmanWorkspaceSelection({
4309
+ apiKey: envApiKey,
4310
+ defaultWorkspaceId,
4311
+ });
4312
+ defaultWorkspaceId = workspaceSelection.workspaceId;
4313
+ warnings.push(...workspaceSelection.warnings);
4263
4314
  workspaceSelectionSource = "interactive";
4264
4315
  }
4265
4316
  if (canPrompt && !requestedMcpScope) {
@@ -6468,6 +6519,35 @@ async function removePathRecord({ targetPath, category, dryRun = false, records,
6468
6519
  });
6469
6520
  }
6470
6521
  }
6522
+ async function removeEmptyDirectoryRecord({ dirPath, category, dryRun = false, records, }) {
6523
+ if (!dirPath)
6524
+ return;
6525
+ if (!(await pathExists(dirPath)))
6526
+ return;
6527
+ let entries = [];
6528
+ try {
6529
+ entries = await readdir(dirPath);
6530
+ }
6531
+ catch {
6532
+ return;
6533
+ }
6534
+ if (entries.length > 0)
6535
+ return;
6536
+ if (dryRun) {
6537
+ records.push({
6538
+ path: dirPath,
6539
+ category,
6540
+ action: "would-remove",
6541
+ });
6542
+ return;
6543
+ }
6544
+ await rm(dirPath, { recursive: true, force: true });
6545
+ records.push({
6546
+ path: dirPath,
6547
+ category,
6548
+ action: "removed",
6549
+ });
6550
+ }
6471
6551
  async function removeMcpRuntimeEntriesJson({ filePath, keyName, serverIds, dryRun = false, }) {
6472
6552
  if (!(await pathExists(filePath))) {
6473
6553
  return { path: filePath, action: "missing", warnings: [] };
@@ -6605,6 +6685,7 @@ async function runWorkflowRemoveAll(options) {
6605
6685
  const scopes = resolveRemoveAllScopes(opts.scope);
6606
6686
  const platforms = resolveRemoveAllPlatforms(opts.platform);
6607
6687
  const bundleIds = await listBundleIds();
6688
+ const knownTopLevelSkillIds = await listTopLevelSkillIdsFromRoot(workflowSkillsRoot());
6608
6689
  if (!dryRun && !opts.yes && process.stdin.isTTY) {
6609
6690
  const proceed = await confirm({
6610
6691
  message: `Remove ALL CBX-managed artifacts for platforms [${platforms.join(", ")}] and scopes [${scopes.join(", ")}]?`,
@@ -6621,7 +6702,20 @@ async function runWorkflowRemoveAll(options) {
6621
6702
  const warnings = [];
6622
6703
  for (const scope of scopes) {
6623
6704
  for (const platform of platforms) {
6624
- const artifactProfilePaths = await resolveArtifactProfilePaths(platform, scope, cwd);
6705
+ const artifactProfilePaths = await resolveProfilePaths(platform, scope, cwd);
6706
+ const profileCandidates = resolveProfilePathCandidates(platform, scope, cwd);
6707
+ const legacySkillDirs = resolveLegacySkillDirsForCleanup(platform, scope, cwd);
6708
+ const allSkillDirs = expandUniquePaths([...profileCandidates.skillsDirs, ...legacySkillDirs], cwd);
6709
+ const isPrimaryDir = (candidateDir, primaryDir) => {
6710
+ if (!candidateDir || !primaryDir)
6711
+ return false;
6712
+ return path.resolve(candidateDir) === path.resolve(primaryDir);
6713
+ };
6714
+ const alternateWorkflowsDirs = profileCandidates.workflowsDirs.filter((dirPath) => !isPrimaryDir(dirPath, artifactProfilePaths.workflowsDir));
6715
+ const alternateAgentsDirs = profileCandidates.agentsDirs.filter((dirPath) => !isPrimaryDir(dirPath, artifactProfilePaths.agentsDir));
6716
+ const alternateCommandsDirs = profileCandidates.commandsDirs.filter((dirPath) => !isPrimaryDir(dirPath, artifactProfilePaths.commandsDir));
6717
+ const alternatePromptsDirs = profileCandidates.promptsDirs.filter((dirPath) => !isPrimaryDir(dirPath, artifactProfilePaths.promptsDir));
6718
+ const alternateSkillsDirs = allSkillDirs.filter((dirPath) => !isPrimaryDir(dirPath, artifactProfilePaths.skillsDir));
6625
6719
  for (const bundleId of bundleIds) {
6626
6720
  const manifest = await readBundleManifest(bundleId);
6627
6721
  const removedBundle = await removeBundleArtifacts({
@@ -6640,19 +6734,91 @@ async function runWorkflowRemoveAll(options) {
6640
6734
  action: dryRun ? "would-remove" : "removed",
6641
6735
  });
6642
6736
  }
6643
- }
6644
- const extraSkillPaths = [
6645
- path.join(artifactProfilePaths.skillsDir || "", POSTMAN_SKILL_ID),
6646
- path.join(artifactProfilePaths.skillsDir || "", STITCH_SKILL_ID),
6647
- path.join(artifactProfilePaths.skillsDir || "", "skills_index.json"),
6648
- ];
6649
- for (const extraPath of extraSkillPaths) {
6650
- await removePathRecord({
6651
- targetPath: extraPath,
6652
- category: `${platform}/${scope}/extra-skill`,
6653
- dryRun,
6654
- records: removedRecords,
6737
+ const platformSpec = manifest.platforms?.[platform];
6738
+ if (!platformSpec)
6739
+ continue;
6740
+ const workflowFiles = (platformSpec.workflows || []).map((entry) => path.basename(entry));
6741
+ const agentFiles = (platformSpec.agents || []).map((entry) => path.basename(entry));
6742
+ const commandFiles = (platformSpec.commands || []).map((entry) => path.basename(entry));
6743
+ const promptFiles = (platformSpec.prompts || []).map((entry) => path.basename(entry));
6744
+ const skillIds = await resolveInstallSkillIds({
6745
+ platformSpec,
6746
+ extraSkillIds: [],
6655
6747
  });
6748
+ const wrapperSkillIds = platform === "codex" ? buildCodexWrapperSkillIds(platformSpec) : [];
6749
+ const bundleSkillIds = [...new Set([...skillIds, ...wrapperSkillIds])];
6750
+ for (const workflowsDir of alternateWorkflowsDirs) {
6751
+ for (const workflowFile of workflowFiles) {
6752
+ await removePathRecord({
6753
+ targetPath: path.join(workflowsDir, workflowFile),
6754
+ category: `${platform}/${scope}/bundle-alt`,
6755
+ dryRun,
6756
+ records: removedRecords,
6757
+ });
6758
+ }
6759
+ }
6760
+ for (const agentsDir of alternateAgentsDirs) {
6761
+ for (const agentFile of agentFiles) {
6762
+ await removePathRecord({
6763
+ targetPath: path.join(agentsDir, agentFile),
6764
+ category: `${platform}/${scope}/bundle-alt`,
6765
+ dryRun,
6766
+ records: removedRecords,
6767
+ });
6768
+ }
6769
+ }
6770
+ for (const commandsDir of alternateCommandsDirs) {
6771
+ for (const commandFile of commandFiles) {
6772
+ await removePathRecord({
6773
+ targetPath: path.join(commandsDir, commandFile),
6774
+ category: `${platform}/${scope}/bundle-alt`,
6775
+ dryRun,
6776
+ records: removedRecords,
6777
+ });
6778
+ }
6779
+ }
6780
+ for (const promptsDir of alternatePromptsDirs) {
6781
+ for (const promptFile of promptFiles) {
6782
+ await removePathRecord({
6783
+ targetPath: path.join(promptsDir, promptFile),
6784
+ category: `${platform}/${scope}/bundle-alt`,
6785
+ dryRun,
6786
+ records: removedRecords,
6787
+ });
6788
+ }
6789
+ }
6790
+ for (const skillsDir of alternateSkillsDirs) {
6791
+ for (const skillId of bundleSkillIds) {
6792
+ await removePathRecord({
6793
+ targetPath: path.join(skillsDir, skillId),
6794
+ category: `${platform}/${scope}/bundle-alt`,
6795
+ dryRun,
6796
+ records: removedRecords,
6797
+ });
6798
+ }
6799
+ }
6800
+ }
6801
+ for (const skillsDir of allSkillDirs) {
6802
+ for (const entry of [
6803
+ POSTMAN_SKILL_ID,
6804
+ STITCH_SKILL_ID,
6805
+ "skills_index.json",
6806
+ ]) {
6807
+ await removePathRecord({
6808
+ targetPath: path.join(skillsDir, entry),
6809
+ category: `${platform}/${scope}/extra-skill`,
6810
+ dryRun,
6811
+ records: removedRecords,
6812
+ });
6813
+ }
6814
+ for (const skillId of knownTopLevelSkillIds) {
6815
+ await removePathRecord({
6816
+ targetPath: path.join(skillsDir, skillId),
6817
+ category: `${platform}/${scope}/known-skill`,
6818
+ dryRun,
6819
+ records: removedRecords,
6820
+ });
6821
+ }
6656
6822
  }
6657
6823
  if (platform === "antigravity") {
6658
6824
  const terminalCleanup = await cleanupAntigravityTerminalIntegration({
@@ -6698,6 +6864,21 @@ async function runWorkflowRemoveAll(options) {
6698
6864
  warnings.push(...runtimeResult.warnings);
6699
6865
  }
6700
6866
  }
6867
+ for (const managedDir of expandUniquePaths([
6868
+ ...profileCandidates.skillsDirs,
6869
+ ...profileCandidates.agentsDirs,
6870
+ ...profileCandidates.workflowsDirs,
6871
+ ...profileCandidates.commandsDirs,
6872
+ ...profileCandidates.promptsDirs,
6873
+ ...legacySkillDirs,
6874
+ ], cwd)) {
6875
+ await removeEmptyDirectoryRecord({
6876
+ dirPath: managedDir,
6877
+ category: `${platform}/${scope}/managed-dir-empty`,
6878
+ dryRun,
6879
+ records: removedRecords,
6880
+ });
6881
+ }
6701
6882
  const scopedProfilePaths = await resolveProfilePaths(platform, scope, cwd);
6702
6883
  const ruleCandidates = [...scopedProfilePaths.ruleFilesByPriority];
6703
6884
  if (scope === "global") {
@@ -6760,7 +6941,7 @@ async function runWorkflowRemoveAll(options) {
6760
6941
  records: removedRecords,
6761
6942
  });
6762
6943
  }
6763
- else if (includeCredentials) {
6944
+ else if (scope === "global" || includeCredentials) {
6764
6945
  await removePathRecord({
6765
6946
  targetPath: resolveManagedCredentialsEnvPath(),
6766
6947
  category: "global/credentials",
@@ -6768,6 +6949,19 @@ async function runWorkflowRemoveAll(options) {
6768
6949
  records: removedRecords,
6769
6950
  });
6770
6951
  }
6952
+ if (scope === "global") {
6953
+ for (const globalRootDir of [
6954
+ path.join(os.homedir(), ".cbx"),
6955
+ path.join(os.homedir(), ".agents"),
6956
+ ]) {
6957
+ await removeEmptyDirectoryRecord({
6958
+ dirPath: globalRootDir,
6959
+ category: "global/root-dir-empty",
6960
+ dryRun,
6961
+ records: removedRecords,
6962
+ });
6963
+ }
6964
+ }
6771
6965
  }
6772
6966
  if (await checkDockerAvailable({ cwd })) {
6773
6967
  const containerName = DEFAULT_MCP_DOCKER_CONTAINER_NAME;
@@ -8886,6 +9080,9 @@ async function runInitWizard(options) {
8886
9080
  const defaultMcpScope = normalizeMcpScope(options.mcpScope, defaultSkillsScope) === "global"
8887
9081
  ? "global"
8888
9082
  : "project";
9083
+ const defaultPostmanWorkspaceId = options.postmanWorkspaceId !== undefined
9084
+ ? normalizePostmanWorkspaceId(options.postmanWorkspaceId)
9085
+ : null;
8889
9086
  const defaultMcpSelections = normalizeInitMcpSelections(options.mcps);
8890
9087
  const defaultPlatforms = normalizeInitPlatforms(options.platforms);
8891
9088
  const defaultMcpRuntime = normalizeMcpRuntime(options.mcpRuntime, defaultMcpSelections.some((item) => item === "postman" || item === "stitch")
@@ -8928,9 +9125,11 @@ async function runInitWizard(options) {
8928
9125
  postmanMode: options.postmanMode && normalizePostmanMode(options.postmanMode)
8929
9126
  ? normalizePostmanMode(options.postmanMode)
8930
9127
  : "full",
9128
+ postmanWorkspaceId: defaultPostmanWorkspaceId,
8931
9129
  postmanApiKey: null,
8932
9130
  stitchApiKey: null,
8933
9131
  };
9132
+ const initWarnings = [];
8934
9133
  if (selections.platforms.length === 0) {
8935
9134
  throw new Error("No platforms selected.");
8936
9135
  }
@@ -8951,6 +9150,15 @@ async function runInitWizard(options) {
8951
9150
  if (selections.selectedMcps.includes("postman") && isInteractive) {
8952
9151
  selections.postmanMode = await promptInitPostmanMode(selections.postmanMode);
8953
9152
  selections.postmanApiKey = await promptOptionalSecret("Postman API key (optional, leave blank to keep existing env/profile state):");
9153
+ const postmanLookupApiKey = normalizePostmanApiKey(selections.postmanApiKey) ||
9154
+ normalizePostmanApiKey(process.env[profileEnvVarAlias("postman", DEFAULT_CREDENTIAL_PROFILE_NAME)]) ||
9155
+ normalizePostmanApiKey(process.env[POSTMAN_API_KEY_ENV_VAR]);
9156
+ const postmanWorkspaceSelection = await promptPostmanWorkspaceSelection({
9157
+ apiKey: postmanLookupApiKey,
9158
+ defaultWorkspaceId: selections.postmanWorkspaceId,
9159
+ });
9160
+ selections.postmanWorkspaceId = postmanWorkspaceSelection.workspaceId;
9161
+ initWarnings.push(...postmanWorkspaceSelection.warnings);
8954
9162
  }
8955
9163
  if (selections.selectedMcps.includes("stitch") && isInteractive) {
8956
9164
  selections.stitchApiKey = await promptOptionalSecret("Stitch API key (optional, leave blank to keep existing env/profile state):");
@@ -8969,6 +9177,12 @@ async function runInitWizard(options) {
8969
9177
  target: options.target,
8970
9178
  });
8971
9179
  const initSummary = formatInitSummary(selections);
9180
+ if (initWarnings.length > 0) {
9181
+ console.log("\nInit warnings:");
9182
+ for (const warning of initWarnings) {
9183
+ console.log(`- ${warning}`);
9184
+ }
9185
+ }
8972
9186
  if (!options.yes && isInteractive) {
8973
9187
  const proceed = await promptInitApplyConfirmation(initSummary);
8974
9188
  if (!proceed) {