@glasstrace/sdk 1.10.1 → 1.11.0

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 (39) hide show
  1. package/README.md +43 -5
  2. package/dist/{chunk-WQF7ZQOM.js → chunk-DQFGNX3H.js} +13 -8
  3. package/dist/{chunk-WQF7ZQOM.js.map → chunk-DQFGNX3H.js.map} +1 -1
  4. package/dist/{chunk-UMGZJYC4.js → chunk-FQ4SEG6Y.js} +8 -3
  5. package/dist/chunk-FQ4SEG6Y.js.map +1 -0
  6. package/dist/chunk-KOYZJN6G.js +651 -0
  7. package/dist/chunk-KOYZJN6G.js.map +1 -0
  8. package/dist/{chunk-ZBQQXVHD.js → chunk-YIEXKQYP.js} +2 -67
  9. package/dist/chunk-YIEXKQYP.js.map +1 -0
  10. package/dist/cli/init.cjs +460 -127
  11. package/dist/cli/init.cjs.map +1 -1
  12. package/dist/cli/init.js +29 -16
  13. package/dist/cli/init.js.map +1 -1
  14. package/dist/cli/mcp-add.cjs +346 -98
  15. package/dist/cli/mcp-add.cjs.map +1 -1
  16. package/dist/cli/mcp-add.js +32 -14
  17. package/dist/cli/mcp-add.js.map +1 -1
  18. package/dist/cli/status.cjs +6 -1
  19. package/dist/cli/status.cjs.map +1 -1
  20. package/dist/cli/status.js +7 -2
  21. package/dist/cli/status.js.map +1 -1
  22. package/dist/cli/uninit.cjs +6 -1
  23. package/dist/cli/uninit.cjs.map +1 -1
  24. package/dist/cli/uninit.js +2 -2
  25. package/dist/cli/upgrade-instructions.cjs +390 -113
  26. package/dist/cli/upgrade-instructions.cjs.map +1 -1
  27. package/dist/cli/upgrade-instructions.js +70 -18
  28. package/dist/cli/upgrade-instructions.js.map +1 -1
  29. package/dist/index.cjs +11 -6
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.js +2 -2
  32. package/dist/node-entry.cjs +11 -6
  33. package/dist/node-entry.cjs.map +1 -1
  34. package/dist/node-entry.js +2 -2
  35. package/package.json +1 -1
  36. package/dist/chunk-TJ46YOGJ.js +0 -355
  37. package/dist/chunk-TJ46YOGJ.js.map +0 -1
  38. package/dist/chunk-UMGZJYC4.js.map +0 -1
  39. package/dist/chunk-ZBQQXVHD.js.map +0 -1
@@ -14277,33 +14277,61 @@ var AGENT_RULES = [
14277
14277
  },
14278
14278
  {
14279
14279
  name: "codex",
14280
+ // Codex 2026 default discovery is `AGENTS.override.md` → `AGENTS.md` →
14281
+ // opt-in `project_doc_fallback_filenames`; `codex.md` is NOT in the
14282
+ // default fallback list. Detection requires Codex-specific markers
14283
+ // (`codex.md` legacy, `.codex/` config dir) — `AGENTS.md` is NOT
14284
+ // included as a marker because the SDK now writes `AGENTS.md`
14285
+ // broadly via the multi-target dispatcher's companion writes; if
14286
+ // `AGENTS.md` were a Codex marker, every project with the SDK's
14287
+ // own companion AGENTS.md would re-classify as Codex on subsequent
14288
+ // detect runs and trigger unintended `.codex/config.toml` writes
14289
+ // (Codex P1 + Copilot P1 review of Wave 18 PR #274). The canonical
14290
+ // write destination remains AGENTS.md regardless of which marker
14291
+ // classified the project.
14280
14292
  markers: ["codex.md", ".codex"],
14281
14293
  mcpConfigPath: (dir) => (0, import_node_path.join)(dir, ".codex", "config.toml"),
14282
- infoFilePath: (dir) => (0, import_node_path.join)(dir, "codex.md"),
14294
+ infoFilePath: (dir) => (0, import_node_path.join)(dir, "AGENTS.md"),
14283
14295
  cliBinary: "codex",
14284
14296
  registrationCommand: "npx glasstrace mcp add --agent codex"
14285
14297
  },
14286
14298
  {
14287
14299
  name: "gemini",
14288
- markers: [".gemini"],
14300
+ markers: [".gemini", "GEMINI.md"],
14289
14301
  mcpConfigPath: (dir) => (0, import_node_path.join)(dir, ".gemini", "settings.json"),
14290
- infoFilePath: () => null,
14302
+ infoFilePath: (dir) => (0, import_node_path.join)(dir, "GEMINI.md"),
14291
14303
  cliBinary: "gemini",
14292
14304
  registrationCommand: "npx glasstrace mcp add --agent gemini"
14293
14305
  },
14294
14306
  {
14295
14307
  name: "cursor",
14308
+ // `.cursor/rules/*.mdc` is the current canonical format per Cursor's
14309
+ // 2026 docs. `.cursorrules` (single file) is supported-but-deprecated
14310
+ // and stays as a transitional fallback that the multi-target write
14311
+ // helper writes unconditionally alongside the .mdc canonical.
14296
14312
  markers: [".cursor", ".cursorrules"],
14297
14313
  mcpConfigPath: (dir) => (0, import_node_path.join)(dir, ".cursor", "mcp.json"),
14298
- infoFilePath: (dir) => (0, import_node_path.join)(dir, ".cursorrules"),
14314
+ infoFilePath: (dir) => (0, import_node_path.join)(dir, ".cursor", "rules", "glasstrace.mdc"),
14299
14315
  cliBinary: null,
14300
14316
  registrationCommand: "npx glasstrace mcp add --agent cursor"
14301
14317
  },
14302
14318
  {
14303
14319
  name: "windsurf",
14304
- markers: [".windsurfrules", ".windsurf"],
14320
+ // Windsurf's current canonical workspace-rules format is
14321
+ // `.windsurf/rules/*.md`. AGENTS.md is a parallel cross-tool
14322
+ // mechanism Windsurf also reads BUT is NOT included as a Windsurf
14323
+ // detection marker — the SDK writes `AGENTS.md` broadly via the
14324
+ // multi-target dispatcher's companion writes, so treating
14325
+ // `AGENTS.md` as a Windsurf marker would re-classify every
14326
+ // SDK-managed project as Windsurf and cause `glasstrace uninit`
14327
+ // to mutate the global `~/.codeium/windsurf/mcp_config.json` for
14328
+ // non-Windsurf projects (Codex P1 + Copilot P1 review of Wave 18
14329
+ // PR #274). The single-file `.windsurfrules` is the deprecated
14330
+ // legacy form — recognized as a marker so legacy projects classify
14331
+ // correctly, but the SDK no longer writes to it.
14332
+ markers: [".windsurf", ".windsurfrules"],
14305
14333
  mcpConfigPath: () => (0, import_node_path.join)((0, import_node_os.homedir)(), ".codeium", "windsurf", "mcp_config.json"),
14306
- infoFilePath: (dir) => (0, import_node_path.join)(dir, ".windsurfrules"),
14334
+ infoFilePath: (dir) => (0, import_node_path.join)(dir, ".windsurf", "rules", "glasstrace.md"),
14307
14335
  cliBinary: null,
14308
14336
  registrationCommand: "npx glasstrace mcp add --agent windsurf"
14309
14337
  }
@@ -14390,10 +14418,7 @@ async function detectAgents(projectRoot) {
14390
14418
  continue;
14391
14419
  }
14392
14420
  seenAgents.add(rule.name);
14393
- let infoFilePath = rule.infoFilePath(foundDir);
14394
- if (infoFilePath !== null && !await pathExists(infoFilePath)) {
14395
- infoFilePath = null;
14396
- }
14421
+ const infoFilePath = rule.infoFilePath(foundDir);
14397
14422
  const cliAvailable = rule.cliBinary ? await isCliAvailable(rule.cliBinary) : false;
14398
14423
  detected.push({
14399
14424
  name: rule.name,
@@ -14406,7 +14431,7 @@ async function detectAgents(projectRoot) {
14406
14431
  detected.push({
14407
14432
  name: "generic",
14408
14433
  mcpConfigPath: (0, import_node_path.join)(resolvedRoot, ".glasstrace", "mcp.json"),
14409
- infoFilePath: null,
14434
+ infoFilePath: (0, import_node_path.join)(resolvedRoot, "AGENTS.md"),
14410
14435
  cliAvailable: false,
14411
14436
  registrationCommand: null
14412
14437
  });
@@ -14436,7 +14461,13 @@ function buildAgentInstructionBody() {
14436
14461
  "1. Start with `find_trace_candidates`. Pass whatever route or procedure name is natural \u2014 the server normalizes vocabulary and, on miss, returns close matches and a sample of routes actually present in the window.",
14437
14462
  "2. Take the highest-confidence candidate's `suggestedFollowups` and pass them straight to `get_trace` or `get_root_cause`.",
14438
14463
  "3. For side-effect bugs, read `sideEffectSummary` in the `get_trace` / `get_root_cause` response. The allowlisted fields (`templateKey`, `providerOperation`, `role`, `locale`, `timezone`, `status`, `phase`) are the ones that disambiguate payload bugs.",
14439
- "4. If a tool returns empty, READ the response's `closeMatches`, `recentRoutesSample`, and `recoveryActions` before pivoting to source. Empty results carry `notAbsenceProof: true` \u2014 they are never proof the bug did not occur.",
14464
+ "4. If a tool returns empty, READ the response's empty-result envelope before pivoting to source \u2014 each field disambiguates a different reason for the empty result:",
14465
+ " - `closeMatches` / `recentRoutesSample` \u2014 your filter vocabulary doesn't match server-side names; the server returns the closest known names + a sample of routes actually present.",
14466
+ ' - `windowActivity` \u2014 load-bearing four-way distinguisher. `totalTracesInWindow === 0` AND `totalTracesInTenantEver > 0` means "your time window missed the activity"; `totalTracesInTenantEver === 0` means "this tenant has never produced traces" (SDK not registered, or never hit); `captureConfigBlocksRequest === true` means "the SDK\'s capture config dropped this route"; otherwise the empty result is a vocabulary miss \u2014 see `closeMatches`.',
14467
+ " - `humanReadable` \u2014 prose guidance written for the agent.",
14468
+ " - `recoveryActions` \u2014 concrete next-call shapes.",
14469
+ " - `diagnosticValue` / `recommendedNextStep` \u2014 whether to keep searching or stop.",
14470
+ " Empty results carry `notAbsenceProof: true` \u2014 they are never proof the bug did not occur.",
14440
14471
  "",
14441
14472
  "### Tools",
14442
14473
  "- `find_trace_candidates` \u2014 discovery, vocabulary-tolerant filter",
@@ -14580,34 +14611,75 @@ function generateInfoSection(agent, endpoint, sdkVersion) {
14580
14611
  }
14581
14612
  const content = buildAgentInstructionBody();
14582
14613
  switch (agent.name) {
14583
- case "claude": {
14584
- const m = htmlMarkers(sdkVersion);
14585
- return `${m.start}
14586
- ${content}${m.end}
14587
- `;
14588
- }
14589
- case "codex": {
14614
+ case "claude":
14615
+ case "codex":
14616
+ case "gemini":
14617
+ case "windsurf":
14618
+ case "generic": {
14590
14619
  const m = htmlMarkers(sdkVersion);
14591
14620
  return `${m.start}
14592
14621
  ${content}${m.end}
14593
14622
  `;
14594
14623
  }
14595
14624
  case "cursor": {
14596
- const m = hashMarkers(sdkVersion);
14625
+ const m = htmlMarkers(sdkVersion);
14597
14626
  return `${m.start}
14598
14627
  ${content}${m.end}
14599
14628
  `;
14600
14629
  }
14601
- case "gemini":
14602
- case "windsurf":
14603
- case "generic":
14604
- return "";
14605
14630
  default: {
14606
14631
  const _exhaustive = agent.name;
14607
14632
  throw new Error(`Unknown agent: ${_exhaustive}`);
14608
14633
  }
14609
14634
  }
14610
14635
  }
14636
+ function generateInfoSectionForCursorrulesLegacy(endpoint, sdkVersion) {
14637
+ if (!endpoint || endpoint.trim() === "") {
14638
+ throw new Error("endpoint must not be empty");
14639
+ }
14640
+ if (!sdkVersion || sdkVersion.trim() === "") {
14641
+ throw new Error("sdkVersion must not be empty");
14642
+ }
14643
+ if (!SDK_VERSION_STAMP_PATTERN.test(sdkVersion)) {
14644
+ throw new Error(
14645
+ "sdkVersion must match [A-Za-z0-9.+\\-]+ (semver-shaped, no whitespace, no angle brackets)"
14646
+ );
14647
+ }
14648
+ const content = buildAgentInstructionBody();
14649
+ const m = hashMarkers(sdkVersion);
14650
+ return `${m.start}
14651
+ ${content}${m.end}
14652
+ `;
14653
+ }
14654
+ function generateInfoSectionForCursorMdc(endpoint, sdkVersion) {
14655
+ if (!endpoint || endpoint.trim() === "") {
14656
+ throw new Error("endpoint must not be empty");
14657
+ }
14658
+ if (!sdkVersion || sdkVersion.trim() === "") {
14659
+ throw new Error("sdkVersion must not be empty");
14660
+ }
14661
+ if (!SDK_VERSION_STAMP_PATTERN.test(sdkVersion)) {
14662
+ throw new Error(
14663
+ "sdkVersion must match [A-Za-z0-9.+\\-]+ (semver-shaped, no whitespace, no angle brackets)"
14664
+ );
14665
+ }
14666
+ const content = buildAgentInstructionBody();
14667
+ const m = htmlMarkers(sdkVersion);
14668
+ return [
14669
+ "---",
14670
+ "description: Glasstrace MCP runtime debugging tools \u2014 runtime evidence the agent reads when source alone cannot resolve a bug",
14671
+ "alwaysApply: true",
14672
+ "---",
14673
+ "",
14674
+ `${m.start}
14675
+ ${content}${m.end}
14676
+ `
14677
+ ].join("\n");
14678
+ }
14679
+
14680
+ // src/agent-detection/inject-all-targets.ts
14681
+ var import_promises3 = require("node:fs/promises");
14682
+ var import_node_path3 = require("node:path");
14611
14683
 
14612
14684
  // src/agent-detection/inject.ts
14613
14685
  var import_promises2 = require("node:fs/promises");
@@ -14682,71 +14754,6 @@ function findMarkerBoundaries(lines) {
14682
14754
  }
14683
14755
  return null;
14684
14756
  }
14685
- async function injectInfoSection(agent, content, projectRoot) {
14686
- if (agent.infoFilePath === null) {
14687
- return;
14688
- }
14689
- if (content === "") {
14690
- return;
14691
- }
14692
- const filePath = agent.infoFilePath;
14693
- let existingContent = null;
14694
- try {
14695
- existingContent = await (0, import_promises2.readFile)(filePath, "utf-8");
14696
- } catch (err) {
14697
- const code = err.code;
14698
- if (code !== "ENOENT") {
14699
- if (isPermissionError(err)) {
14700
- process.stderr.write(
14701
- `Warning: cannot read info file ${filePath}: permission denied
14702
- `
14703
- );
14704
- return;
14705
- }
14706
- throw err;
14707
- }
14708
- }
14709
- if (existingContent === null) {
14710
- try {
14711
- await (0, import_promises2.mkdir)((0, import_node_path2.dirname)(filePath), { recursive: true });
14712
- await (0, import_promises2.writeFile)(filePath, content, "utf-8");
14713
- } catch (err) {
14714
- if (isPermissionError(err)) {
14715
- process.stderr.write(
14716
- `Warning: cannot write info file ${filePath}: permission denied
14717
- `
14718
- );
14719
- return;
14720
- }
14721
- throw err;
14722
- }
14723
- return;
14724
- }
14725
- const lines = existingContent.split("\n");
14726
- const boundaries = findMarkerBoundaries(lines);
14727
- let newContent;
14728
- if (boundaries !== null) {
14729
- const before = lines.slice(0, boundaries.startIdx);
14730
- const after = lines.slice(boundaries.endIdx + 1);
14731
- const contentWithoutTrailingNewline = content.endsWith("\n") ? content.slice(0, -1) : content;
14732
- newContent = [...before, contentWithoutTrailingNewline, ...after].join("\n");
14733
- } else {
14734
- const separator = existingContent.endsWith("\n") ? "\n" : "\n\n";
14735
- newContent = existingContent + separator + content;
14736
- }
14737
- try {
14738
- await (0, import_promises2.writeFile)(filePath, newContent, "utf-8");
14739
- } catch (err) {
14740
- if (isPermissionError(err)) {
14741
- process.stderr.write(
14742
- `Warning: cannot write info file ${filePath}: permission denied
14743
- `
14744
- );
14745
- return;
14746
- }
14747
- throw err;
14748
- }
14749
- }
14750
14757
  async function updateGitignore(paths, projectRoot) {
14751
14758
  const gitignorePath = (0, import_node_path2.join)(projectRoot, ".gitignore");
14752
14759
  const relativePaths = paths.filter((p) => !(0, import_node_path2.isAbsolute)(p));
@@ -14794,6 +14801,228 @@ async function updateGitignore(paths, projectRoot) {
14794
14801
  }
14795
14802
  }
14796
14803
 
14804
+ // src/agent-detection/inject-all-targets.ts
14805
+ async function injectAllTargets(agents, endpoint, sdkVersion, projectRoot) {
14806
+ const writtenAgentsMd = /* @__PURE__ */ new Set();
14807
+ for (const agent of agents) {
14808
+ const targets = computeTargets(agent, projectRoot);
14809
+ for (const target of targets) {
14810
+ if (target.isAgentsMdCompanion) {
14811
+ if (writtenAgentsMd.has(target.path)) {
14812
+ continue;
14813
+ }
14814
+ writtenAgentsMd.add(target.path);
14815
+ }
14816
+ let createContent;
14817
+ let managedSectionOnly;
14818
+ if (target.kind === "cursor-mdc") {
14819
+ createContent = generateInfoSectionForCursorMdc(endpoint, sdkVersion);
14820
+ managedSectionOnly = generateInfoSection(agent, endpoint, sdkVersion);
14821
+ } else if (target.kind === "cursorrules-legacy") {
14822
+ createContent = generateInfoSectionForCursorrulesLegacy(
14823
+ endpoint,
14824
+ sdkVersion
14825
+ );
14826
+ managedSectionOnly = createContent;
14827
+ } else {
14828
+ createContent = generateInfoSection(agent, endpoint, sdkVersion);
14829
+ managedSectionOnly = createContent;
14830
+ }
14831
+ if (managedSectionOnly === "") continue;
14832
+ await writeManagedSectionToTarget(
14833
+ target.path,
14834
+ createContent,
14835
+ managedSectionOnly
14836
+ );
14837
+ }
14838
+ }
14839
+ }
14840
+ function foundDirFromAgent(agent) {
14841
+ if (agent.infoFilePath === null) return null;
14842
+ switch (agent.name) {
14843
+ case "claude":
14844
+ case "codex":
14845
+ case "gemini":
14846
+ case "generic":
14847
+ return (0, import_node_path3.dirname)(agent.infoFilePath);
14848
+ case "cursor":
14849
+ return (0, import_node_path3.dirname)((0, import_node_path3.dirname)((0, import_node_path3.dirname)(agent.infoFilePath)));
14850
+ case "windsurf":
14851
+ return (0, import_node_path3.dirname)((0, import_node_path3.dirname)((0, import_node_path3.dirname)(agent.infoFilePath)));
14852
+ }
14853
+ }
14854
+ function computeTargets(agent, projectRoot) {
14855
+ const targets = [];
14856
+ const foundDir = foundDirFromAgent(agent) ?? projectRoot;
14857
+ switch (agent.name) {
14858
+ case "claude": {
14859
+ if (agent.infoFilePath) {
14860
+ targets.push({
14861
+ path: agent.infoFilePath,
14862
+ kind: "primary",
14863
+ isAgentsMdCompanion: false
14864
+ });
14865
+ }
14866
+ targets.push({
14867
+ path: (0, import_node_path3.join)(foundDir, "AGENTS.md"),
14868
+ kind: "agents-md-companion",
14869
+ isAgentsMdCompanion: true
14870
+ });
14871
+ return targets;
14872
+ }
14873
+ case "codex": {
14874
+ if (agent.infoFilePath) {
14875
+ targets.push({
14876
+ path: agent.infoFilePath,
14877
+ kind: "primary",
14878
+ isAgentsMdCompanion: true
14879
+ });
14880
+ }
14881
+ return targets;
14882
+ }
14883
+ case "gemini": {
14884
+ if (agent.infoFilePath) {
14885
+ targets.push({
14886
+ path: agent.infoFilePath,
14887
+ kind: "primary",
14888
+ isAgentsMdCompanion: false
14889
+ });
14890
+ }
14891
+ targets.push({
14892
+ path: (0, import_node_path3.join)(foundDir, "AGENTS.md"),
14893
+ kind: "agents-md-companion",
14894
+ isAgentsMdCompanion: true
14895
+ });
14896
+ return targets;
14897
+ }
14898
+ case "cursor": {
14899
+ if (agent.infoFilePath) {
14900
+ targets.push({
14901
+ path: agent.infoFilePath,
14902
+ kind: "cursor-mdc",
14903
+ isAgentsMdCompanion: false
14904
+ });
14905
+ targets.push({
14906
+ path: (0, import_node_path3.join)(foundDir, ".cursorrules"),
14907
+ kind: "cursorrules-legacy",
14908
+ isAgentsMdCompanion: false
14909
+ });
14910
+ }
14911
+ targets.push({
14912
+ path: (0, import_node_path3.join)(foundDir, "AGENTS.md"),
14913
+ kind: "agents-md-companion",
14914
+ isAgentsMdCompanion: true
14915
+ });
14916
+ return targets;
14917
+ }
14918
+ case "windsurf": {
14919
+ if (agent.infoFilePath) {
14920
+ targets.push({
14921
+ path: agent.infoFilePath,
14922
+ kind: "primary",
14923
+ isAgentsMdCompanion: false
14924
+ });
14925
+ }
14926
+ targets.push({
14927
+ path: (0, import_node_path3.join)(foundDir, "AGENTS.md"),
14928
+ kind: "agents-md-companion",
14929
+ isAgentsMdCompanion: true
14930
+ });
14931
+ return targets;
14932
+ }
14933
+ case "generic": {
14934
+ if (agent.infoFilePath) {
14935
+ targets.push({
14936
+ path: agent.infoFilePath,
14937
+ kind: "primary",
14938
+ isAgentsMdCompanion: true
14939
+ });
14940
+ }
14941
+ return targets;
14942
+ }
14943
+ default: {
14944
+ const _exhaustive = agent.name;
14945
+ throw new Error(`Unknown agent: ${_exhaustive}`);
14946
+ }
14947
+ }
14948
+ }
14949
+ async function writeManagedSectionToTarget(filePath, createContent, managedSectionOnly) {
14950
+ let existingContent = null;
14951
+ try {
14952
+ existingContent = await (0, import_promises3.readFile)(filePath, "utf-8");
14953
+ } catch (err) {
14954
+ const code = err.code;
14955
+ if (code !== "ENOENT") {
14956
+ emitTargetWarning(filePath, "read", err);
14957
+ return;
14958
+ }
14959
+ }
14960
+ if (existingContent === null) {
14961
+ try {
14962
+ await (0, import_promises3.mkdir)((0, import_node_path3.dirname)(filePath), { recursive: true });
14963
+ await (0, import_promises3.writeFile)(filePath, createContent, "utf-8");
14964
+ } catch (err) {
14965
+ emitTargetWarning(filePath, "write", err);
14966
+ return;
14967
+ }
14968
+ return;
14969
+ }
14970
+ const lines = existingContent.split("\n");
14971
+ const boundaries = findMarkerBoundaries(lines);
14972
+ let newContent;
14973
+ if (boundaries !== null) {
14974
+ const before = lines.slice(0, boundaries.startIdx);
14975
+ const after = lines.slice(boundaries.endIdx + 1);
14976
+ const contentWithoutTrailingNewline = managedSectionOnly.endsWith("\n") ? managedSectionOnly.slice(0, -1) : managedSectionOnly;
14977
+ newContent = [...before, contentWithoutTrailingNewline, ...after].join(
14978
+ "\n"
14979
+ );
14980
+ } else {
14981
+ const separator = existingContent.endsWith("\n") ? "\n" : "\n\n";
14982
+ newContent = existingContent + separator + managedSectionOnly;
14983
+ }
14984
+ try {
14985
+ await (0, import_promises3.writeFile)(filePath, newContent, "utf-8");
14986
+ } catch (err) {
14987
+ emitTargetWarning(filePath, "write", err);
14988
+ }
14989
+ }
14990
+ function emitTargetWarning(filePath, op, err) {
14991
+ const code = err.code;
14992
+ let qualifier;
14993
+ switch (code) {
14994
+ case "EACCES":
14995
+ case "EPERM":
14996
+ qualifier = "permission denied";
14997
+ break;
14998
+ case "EROFS":
14999
+ qualifier = "filesystem read-only";
15000
+ break;
15001
+ case "ENOSPC":
15002
+ qualifier = "disk full";
15003
+ break;
15004
+ case "ENAMETOOLONG":
15005
+ qualifier = "path too long";
15006
+ break;
15007
+ case "ENOTDIR":
15008
+ qualifier = "not a directory";
15009
+ break;
15010
+ case "EISDIR":
15011
+ qualifier = "is a directory";
15012
+ break;
15013
+ default:
15014
+ qualifier = "I/O error";
15015
+ break;
15016
+ }
15017
+ try {
15018
+ process.stderr.write(
15019
+ `Warning: cannot ${op} info file ${filePath}: ${qualifier}
15020
+ `
15021
+ );
15022
+ } catch {
15023
+ }
15024
+ }
15025
+
14797
15026
  // src/cli/constants.ts
14798
15027
  function formatAgentName(name) {
14799
15028
  const displayNames = {
@@ -14949,14 +15178,9 @@ async function mcpAdd(options) {
14949
15178
  const bearer = resolved.effective.key;
14950
15179
  for (const agent of targetAgents) {
14951
15180
  const name = formatAgentName(agent.name);
14952
- const sdkVersion = true ? "1.10.1" : "0.0.0-dev";
14953
15181
  if (agent.name !== "generic") {
14954
15182
  const cliSuccess = await registerViaCli(agent, bearer);
14955
15183
  if (cliSuccess) {
14956
- const infoContent = generateInfoSection(agent, MCP_ENDPOINT, sdkVersion);
14957
- if (infoContent !== "") {
14958
- await injectInfoSection(agent, infoContent, projectRoot);
14959
- }
14960
15184
  results.push({
14961
15185
  agent: agent.name,
14962
15186
  success: true,
@@ -14971,10 +15195,6 @@ async function mcpAdd(options) {
14971
15195
  const configContent = generateMcpConfig(agent, MCP_ENDPOINT, bearer);
14972
15196
  await writeMcpConfig(agent, configContent, projectRoot);
14973
15197
  if (fs.existsSync(agent.mcpConfigPath)) {
14974
- const infoContent = generateInfoSection(agent, MCP_ENDPOINT, sdkVersion);
14975
- if (infoContent !== "") {
14976
- await injectInfoSection(agent, infoContent, projectRoot);
14977
- }
14978
15198
  results.push({
14979
15199
  agent: agent.name,
14980
15200
  success: true,
@@ -15007,6 +15227,34 @@ async function mcpAdd(options) {
15007
15227
  message: `${name}: No registration method available`
15008
15228
  });
15009
15229
  }
15230
+ const successfulAgentNames = new Set(
15231
+ results.filter((r) => r.success).map((r) => r.agent)
15232
+ );
15233
+ const agentsWithMcpReady = targetAgents.filter(
15234
+ (a) => successfulAgentNames.has(a.name)
15235
+ );
15236
+ const detectedNonGenericMcpAdd = targetAgents.filter(
15237
+ (a) => a.name !== "generic"
15238
+ );
15239
+ const nonGenericReadyMcpAdd = agentsWithMcpReady.filter(
15240
+ (a) => a.name !== "generic"
15241
+ );
15242
+ const dispatchSetMcpAdd = detectedNonGenericMcpAdd.length === 0 ? agentsWithMcpReady : nonGenericReadyMcpAdd;
15243
+ if (dispatchSetMcpAdd.length > 0) {
15244
+ const sdkVersion = true ? "1.11.0" : "0.0.0-dev";
15245
+ try {
15246
+ await injectAllTargets(
15247
+ dispatchSetMcpAdd,
15248
+ MCP_ENDPOINT,
15249
+ sdkVersion,
15250
+ projectRoot
15251
+ );
15252
+ } catch (injectErr) {
15253
+ messages.push(
15254
+ `Warning: Failed to write some agent-instruction files: ${injectErr instanceof Error ? injectErr.message : String(injectErr)}`
15255
+ );
15256
+ }
15257
+ }
15010
15258
  await updateGitignore(
15011
15259
  [".mcp.json", ".cursor/mcp.json", ".gemini/settings.json", ".codex/config.toml"],
15012
15260
  projectRoot