@glasstrace/sdk 1.10.2 → 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 (38) hide show
  1. package/README.md +43 -5
  2. package/dist/{chunk-QS5RZ2TC.js → chunk-DQFGNX3H.js} +13 -8
  3. package/dist/{chunk-QS5RZ2TC.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-CIKPFJOM.js → chunk-KOYZJN6G.js} +310 -20
  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 +453 -126
  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 +339 -97
  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 +383 -112
  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-CIKPFJOM.js.map +0 -1
  37. package/dist/chunk-UMGZJYC4.js.map +0 -1
  38. package/dist/chunk-ZBQQXVHD.js.map +0 -1
@@ -12,11 +12,11 @@ import {
12
12
  unwrapCJSExport,
13
13
  unwrapExport,
14
14
  writeShutdownMarker
15
- } from "../chunk-UMGZJYC4.js";
15
+ } from "../chunk-FQ4SEG6Y.js";
16
16
  import "../chunk-RL43PU2X.js";
17
17
  import "../chunk-6RKS3DNA.js";
18
18
  import "../chunk-NB7GJE4S.js";
19
- import "../chunk-ZBQQXVHD.js";
19
+ import "../chunk-YIEXKQYP.js";
20
20
  import "../chunk-NSBPE2FW.js";
21
21
  export {
22
22
  findMatchingDelimiter,
@@ -46,33 +46,61 @@ var AGENT_RULES = [
46
46
  },
47
47
  {
48
48
  name: "codex",
49
+ // Codex 2026 default discovery is `AGENTS.override.md` → `AGENTS.md` →
50
+ // opt-in `project_doc_fallback_filenames`; `codex.md` is NOT in the
51
+ // default fallback list. Detection requires Codex-specific markers
52
+ // (`codex.md` legacy, `.codex/` config dir) — `AGENTS.md` is NOT
53
+ // included as a marker because the SDK now writes `AGENTS.md`
54
+ // broadly via the multi-target dispatcher's companion writes; if
55
+ // `AGENTS.md` were a Codex marker, every project with the SDK's
56
+ // own companion AGENTS.md would re-classify as Codex on subsequent
57
+ // detect runs and trigger unintended `.codex/config.toml` writes
58
+ // (Codex P1 + Copilot P1 review of Wave 18 PR #274). The canonical
59
+ // write destination remains AGENTS.md regardless of which marker
60
+ // classified the project.
49
61
  markers: ["codex.md", ".codex"],
50
62
  mcpConfigPath: (dir) => (0, import_node_path.join)(dir, ".codex", "config.toml"),
51
- infoFilePath: (dir) => (0, import_node_path.join)(dir, "codex.md"),
63
+ infoFilePath: (dir) => (0, import_node_path.join)(dir, "AGENTS.md"),
52
64
  cliBinary: "codex",
53
65
  registrationCommand: "npx glasstrace mcp add --agent codex"
54
66
  },
55
67
  {
56
68
  name: "gemini",
57
- markers: [".gemini"],
69
+ markers: [".gemini", "GEMINI.md"],
58
70
  mcpConfigPath: (dir) => (0, import_node_path.join)(dir, ".gemini", "settings.json"),
59
- infoFilePath: () => null,
71
+ infoFilePath: (dir) => (0, import_node_path.join)(dir, "GEMINI.md"),
60
72
  cliBinary: "gemini",
61
73
  registrationCommand: "npx glasstrace mcp add --agent gemini"
62
74
  },
63
75
  {
64
76
  name: "cursor",
77
+ // `.cursor/rules/*.mdc` is the current canonical format per Cursor's
78
+ // 2026 docs. `.cursorrules` (single file) is supported-but-deprecated
79
+ // and stays as a transitional fallback that the multi-target write
80
+ // helper writes unconditionally alongside the .mdc canonical.
65
81
  markers: [".cursor", ".cursorrules"],
66
82
  mcpConfigPath: (dir) => (0, import_node_path.join)(dir, ".cursor", "mcp.json"),
67
- infoFilePath: (dir) => (0, import_node_path.join)(dir, ".cursorrules"),
83
+ infoFilePath: (dir) => (0, import_node_path.join)(dir, ".cursor", "rules", "glasstrace.mdc"),
68
84
  cliBinary: null,
69
85
  registrationCommand: "npx glasstrace mcp add --agent cursor"
70
86
  },
71
87
  {
72
88
  name: "windsurf",
73
- markers: [".windsurfrules", ".windsurf"],
89
+ // Windsurf's current canonical workspace-rules format is
90
+ // `.windsurf/rules/*.md`. AGENTS.md is a parallel cross-tool
91
+ // mechanism Windsurf also reads BUT is NOT included as a Windsurf
92
+ // detection marker — the SDK writes `AGENTS.md` broadly via the
93
+ // multi-target dispatcher's companion writes, so treating
94
+ // `AGENTS.md` as a Windsurf marker would re-classify every
95
+ // SDK-managed project as Windsurf and cause `glasstrace uninit`
96
+ // to mutate the global `~/.codeium/windsurf/mcp_config.json` for
97
+ // non-Windsurf projects (Codex P1 + Copilot P1 review of Wave 18
98
+ // PR #274). The single-file `.windsurfrules` is the deprecated
99
+ // legacy form — recognized as a marker so legacy projects classify
100
+ // correctly, but the SDK no longer writes to it.
101
+ markers: [".windsurf", ".windsurfrules"],
74
102
  mcpConfigPath: () => (0, import_node_path.join)((0, import_node_os.homedir)(), ".codeium", "windsurf", "mcp_config.json"),
75
- infoFilePath: (dir) => (0, import_node_path.join)(dir, ".windsurfrules"),
103
+ infoFilePath: (dir) => (0, import_node_path.join)(dir, ".windsurf", "rules", "glasstrace.md"),
76
104
  cliBinary: null,
77
105
  registrationCommand: "npx glasstrace mcp add --agent windsurf"
78
106
  }
@@ -159,10 +187,7 @@ async function detectAgents(projectRoot) {
159
187
  continue;
160
188
  }
161
189
  seenAgents.add(rule.name);
162
- let infoFilePath = rule.infoFilePath(foundDir);
163
- if (infoFilePath !== null && !await pathExists(infoFilePath)) {
164
- infoFilePath = null;
165
- }
190
+ const infoFilePath = rule.infoFilePath(foundDir);
166
191
  const cliAvailable = rule.cliBinary ? await isCliAvailable(rule.cliBinary) : false;
167
192
  detected.push({
168
193
  name: rule.name,
@@ -175,13 +200,62 @@ async function detectAgents(projectRoot) {
175
200
  detected.push({
176
201
  name: "generic",
177
202
  mcpConfigPath: (0, import_node_path.join)(resolvedRoot, ".glasstrace", "mcp.json"),
178
- infoFilePath: null,
203
+ infoFilePath: (0, import_node_path.join)(resolvedRoot, "AGENTS.md"),
179
204
  cliAvailable: false,
180
205
  registrationCommand: null
181
206
  });
182
207
  return detected;
183
208
  }
184
209
 
210
+ // src/agent-detection/inject.ts
211
+ var import_promises2 = require("node:fs/promises");
212
+ var HTML_START_RE = /^<!--\s*glasstrace:mcp:start(?:\s+v=([^\s>]+))?\s*-->$/;
213
+ var HTML_END = "<!-- glasstrace:mcp:end -->";
214
+ var HASH_START_RE = /^#\s*glasstrace:mcp:start(?:\s+v=(\S+))?$/;
215
+ var HASH_END = "# glasstrace:mcp:end";
216
+ function parseStartMarkerLine(line) {
217
+ const trimmed = line.trim();
218
+ const html = HTML_START_RE.exec(trimmed);
219
+ if (html !== null) {
220
+ return { kind: "html", stamp: html[1] ?? null };
221
+ }
222
+ const hash = HASH_START_RE.exec(trimmed);
223
+ if (hash !== null) {
224
+ return { kind: "hash", stamp: hash[1] ?? null };
225
+ }
226
+ return null;
227
+ }
228
+ function isEndMarker(line) {
229
+ const trimmed = line.trim();
230
+ return trimmed === HTML_END || trimmed === HASH_END;
231
+ }
232
+ function findMarkerBoundaries(lines) {
233
+ let startIdx = -1;
234
+ for (let i = 0; i < lines.length; i++) {
235
+ if (parseStartMarkerLine(lines[i]) !== null) {
236
+ startIdx = i;
237
+ } else if (startIdx !== -1 && isEndMarker(lines[i])) {
238
+ return { startIdx, endIdx: i };
239
+ }
240
+ }
241
+ return null;
242
+ }
243
+ async function hasManagedSection(filePath) {
244
+ let content;
245
+ try {
246
+ content = await (0, import_promises2.readFile)(filePath, "utf-8");
247
+ } catch (err) {
248
+ const code = err.code;
249
+ if (code === "ENOENT") return false;
250
+ throw err;
251
+ }
252
+ return findMarkerBoundaries(content.split("\n")) !== null;
253
+ }
254
+
255
+ // src/agent-detection/inject-all-targets.ts
256
+ var import_promises3 = require("node:fs/promises");
257
+ var import_node_path2 = require("node:path");
258
+
185
259
  // src/agent-detection/agent-instruction-text.ts
186
260
  function buildAgentInstructionBody() {
187
261
  return [
@@ -253,110 +327,235 @@ function generateInfoSection(agent, endpoint, sdkVersion) {
253
327
  }
254
328
  const content = buildAgentInstructionBody();
255
329
  switch (agent.name) {
256
- case "claude": {
257
- const m = htmlMarkers(sdkVersion);
258
- return `${m.start}
259
- ${content}${m.end}
260
- `;
261
- }
262
- case "codex": {
330
+ case "claude":
331
+ case "codex":
332
+ case "gemini":
333
+ case "windsurf":
334
+ case "generic": {
263
335
  const m = htmlMarkers(sdkVersion);
264
336
  return `${m.start}
265
337
  ${content}${m.end}
266
338
  `;
267
339
  }
268
340
  case "cursor": {
269
- const m = hashMarkers(sdkVersion);
341
+ const m = htmlMarkers(sdkVersion);
270
342
  return `${m.start}
271
343
  ${content}${m.end}
272
344
  `;
273
345
  }
274
- case "gemini":
275
- case "windsurf":
276
- case "generic":
277
- return "";
278
346
  default: {
279
347
  const _exhaustive = agent.name;
280
348
  throw new Error(`Unknown agent: ${_exhaustive}`);
281
349
  }
282
350
  }
283
351
  }
284
-
285
- // src/agent-detection/inject.ts
286
- var import_promises2 = require("node:fs/promises");
287
- var import_node_path2 = require("node:path");
288
- var HTML_START_RE = /^<!--\s*glasstrace:mcp:start(?:\s+v=([^\s>]+))?\s*-->$/;
289
- var HTML_END = "<!-- glasstrace:mcp:end -->";
290
- var HASH_START_RE = /^#\s*glasstrace:mcp:start(?:\s+v=(\S+))?$/;
291
- var HASH_END = "# glasstrace:mcp:end";
292
- function parseStartMarkerLine(line) {
293
- const trimmed = line.trim();
294
- const html = HTML_START_RE.exec(trimmed);
295
- if (html !== null) {
296
- return { kind: "html", stamp: html[1] ?? null };
352
+ function generateInfoSectionForCursorrulesLegacy(endpoint, sdkVersion) {
353
+ if (!endpoint || endpoint.trim() === "") {
354
+ throw new Error("endpoint must not be empty");
297
355
  }
298
- const hash = HASH_START_RE.exec(trimmed);
299
- if (hash !== null) {
300
- return { kind: "hash", stamp: hash[1] ?? null };
356
+ if (!sdkVersion || sdkVersion.trim() === "") {
357
+ throw new Error("sdkVersion must not be empty");
301
358
  }
302
- return null;
303
- }
304
- function isEndMarker(line) {
305
- const trimmed = line.trim();
306
- return trimmed === HTML_END || trimmed === HASH_END;
359
+ if (!SDK_VERSION_STAMP_PATTERN.test(sdkVersion)) {
360
+ throw new Error(
361
+ "sdkVersion must match [A-Za-z0-9.+\\-]+ (semver-shaped, no whitespace, no angle brackets)"
362
+ );
363
+ }
364
+ const content = buildAgentInstructionBody();
365
+ const m = hashMarkers(sdkVersion);
366
+ return `${m.start}
367
+ ${content}${m.end}
368
+ `;
307
369
  }
308
- function isPermissionError(err) {
309
- const code = err.code;
310
- return code === "EACCES" || code === "EPERM" || code === "EROFS";
370
+ function generateInfoSectionForCursorMdc(endpoint, sdkVersion) {
371
+ if (!endpoint || endpoint.trim() === "") {
372
+ throw new Error("endpoint must not be empty");
373
+ }
374
+ if (!sdkVersion || sdkVersion.trim() === "") {
375
+ throw new Error("sdkVersion must not be empty");
376
+ }
377
+ if (!SDK_VERSION_STAMP_PATTERN.test(sdkVersion)) {
378
+ throw new Error(
379
+ "sdkVersion must match [A-Za-z0-9.+\\-]+ (semver-shaped, no whitespace, no angle brackets)"
380
+ );
381
+ }
382
+ const content = buildAgentInstructionBody();
383
+ const m = htmlMarkers(sdkVersion);
384
+ return [
385
+ "---",
386
+ "description: Glasstrace MCP runtime debugging tools \u2014 runtime evidence the agent reads when source alone cannot resolve a bug",
387
+ "alwaysApply: true",
388
+ "---",
389
+ "",
390
+ `${m.start}
391
+ ${content}${m.end}
392
+ `
393
+ ].join("\n");
311
394
  }
312
- function findMarkerBoundaries(lines) {
313
- let startIdx = -1;
314
- for (let i = 0; i < lines.length; i++) {
315
- if (parseStartMarkerLine(lines[i]) !== null) {
316
- startIdx = i;
317
- } else if (startIdx !== -1 && isEndMarker(lines[i])) {
318
- return { startIdx, endIdx: i };
395
+
396
+ // src/agent-detection/inject-all-targets.ts
397
+ async function injectAllTargets(agents, endpoint, sdkVersion, projectRoot) {
398
+ const writtenAgentsMd = /* @__PURE__ */ new Set();
399
+ for (const agent of agents) {
400
+ const targets = computeTargets(agent, projectRoot);
401
+ for (const target of targets) {
402
+ if (target.isAgentsMdCompanion) {
403
+ if (writtenAgentsMd.has(target.path)) {
404
+ continue;
405
+ }
406
+ writtenAgentsMd.add(target.path);
407
+ }
408
+ let createContent;
409
+ let managedSectionOnly;
410
+ if (target.kind === "cursor-mdc") {
411
+ createContent = generateInfoSectionForCursorMdc(endpoint, sdkVersion);
412
+ managedSectionOnly = generateInfoSection(agent, endpoint, sdkVersion);
413
+ } else if (target.kind === "cursorrules-legacy") {
414
+ createContent = generateInfoSectionForCursorrulesLegacy(
415
+ endpoint,
416
+ sdkVersion
417
+ );
418
+ managedSectionOnly = createContent;
419
+ } else {
420
+ createContent = generateInfoSection(agent, endpoint, sdkVersion);
421
+ managedSectionOnly = createContent;
422
+ }
423
+ if (managedSectionOnly === "") continue;
424
+ await writeManagedSectionToTarget(
425
+ target.path,
426
+ createContent,
427
+ managedSectionOnly
428
+ );
319
429
  }
320
430
  }
321
- return null;
322
431
  }
323
- async function injectInfoSection(agent, content, projectRoot) {
324
- if (agent.infoFilePath === null) {
325
- return;
432
+ function foundDirFromAgent(agent) {
433
+ if (agent.infoFilePath === null) return null;
434
+ switch (agent.name) {
435
+ case "claude":
436
+ case "codex":
437
+ case "gemini":
438
+ case "generic":
439
+ return (0, import_node_path2.dirname)(agent.infoFilePath);
440
+ case "cursor":
441
+ return (0, import_node_path2.dirname)((0, import_node_path2.dirname)((0, import_node_path2.dirname)(agent.infoFilePath)));
442
+ case "windsurf":
443
+ return (0, import_node_path2.dirname)((0, import_node_path2.dirname)((0, import_node_path2.dirname)(agent.infoFilePath)));
326
444
  }
327
- if (content === "") {
328
- return;
445
+ }
446
+ function computeTargets(agent, projectRoot) {
447
+ const targets = [];
448
+ const foundDir = foundDirFromAgent(agent) ?? projectRoot;
449
+ switch (agent.name) {
450
+ case "claude": {
451
+ if (agent.infoFilePath) {
452
+ targets.push({
453
+ path: agent.infoFilePath,
454
+ kind: "primary",
455
+ isAgentsMdCompanion: false
456
+ });
457
+ }
458
+ targets.push({
459
+ path: (0, import_node_path2.join)(foundDir, "AGENTS.md"),
460
+ kind: "agents-md-companion",
461
+ isAgentsMdCompanion: true
462
+ });
463
+ return targets;
464
+ }
465
+ case "codex": {
466
+ if (agent.infoFilePath) {
467
+ targets.push({
468
+ path: agent.infoFilePath,
469
+ kind: "primary",
470
+ isAgentsMdCompanion: true
471
+ });
472
+ }
473
+ return targets;
474
+ }
475
+ case "gemini": {
476
+ if (agent.infoFilePath) {
477
+ targets.push({
478
+ path: agent.infoFilePath,
479
+ kind: "primary",
480
+ isAgentsMdCompanion: false
481
+ });
482
+ }
483
+ targets.push({
484
+ path: (0, import_node_path2.join)(foundDir, "AGENTS.md"),
485
+ kind: "agents-md-companion",
486
+ isAgentsMdCompanion: true
487
+ });
488
+ return targets;
489
+ }
490
+ case "cursor": {
491
+ if (agent.infoFilePath) {
492
+ targets.push({
493
+ path: agent.infoFilePath,
494
+ kind: "cursor-mdc",
495
+ isAgentsMdCompanion: false
496
+ });
497
+ targets.push({
498
+ path: (0, import_node_path2.join)(foundDir, ".cursorrules"),
499
+ kind: "cursorrules-legacy",
500
+ isAgentsMdCompanion: false
501
+ });
502
+ }
503
+ targets.push({
504
+ path: (0, import_node_path2.join)(foundDir, "AGENTS.md"),
505
+ kind: "agents-md-companion",
506
+ isAgentsMdCompanion: true
507
+ });
508
+ return targets;
509
+ }
510
+ case "windsurf": {
511
+ if (agent.infoFilePath) {
512
+ targets.push({
513
+ path: agent.infoFilePath,
514
+ kind: "primary",
515
+ isAgentsMdCompanion: false
516
+ });
517
+ }
518
+ targets.push({
519
+ path: (0, import_node_path2.join)(foundDir, "AGENTS.md"),
520
+ kind: "agents-md-companion",
521
+ isAgentsMdCompanion: true
522
+ });
523
+ return targets;
524
+ }
525
+ case "generic": {
526
+ if (agent.infoFilePath) {
527
+ targets.push({
528
+ path: agent.infoFilePath,
529
+ kind: "primary",
530
+ isAgentsMdCompanion: true
531
+ });
532
+ }
533
+ return targets;
534
+ }
535
+ default: {
536
+ const _exhaustive = agent.name;
537
+ throw new Error(`Unknown agent: ${_exhaustive}`);
538
+ }
329
539
  }
330
- const filePath = agent.infoFilePath;
540
+ }
541
+ async function writeManagedSectionToTarget(filePath, createContent, managedSectionOnly) {
331
542
  let existingContent = null;
332
543
  try {
333
- existingContent = await (0, import_promises2.readFile)(filePath, "utf-8");
544
+ existingContent = await (0, import_promises3.readFile)(filePath, "utf-8");
334
545
  } catch (err) {
335
546
  const code = err.code;
336
547
  if (code !== "ENOENT") {
337
- if (isPermissionError(err)) {
338
- process.stderr.write(
339
- `Warning: cannot read info file ${filePath}: permission denied
340
- `
341
- );
342
- return;
343
- }
344
- throw err;
548
+ emitTargetWarning(filePath, "read", err);
549
+ return;
345
550
  }
346
551
  }
347
552
  if (existingContent === null) {
348
553
  try {
349
- await (0, import_promises2.mkdir)((0, import_node_path2.dirname)(filePath), { recursive: true });
350
- await (0, import_promises2.writeFile)(filePath, content, "utf-8");
554
+ await (0, import_promises3.mkdir)((0, import_node_path2.dirname)(filePath), { recursive: true });
555
+ await (0, import_promises3.writeFile)(filePath, createContent, "utf-8");
351
556
  } catch (err) {
352
- if (isPermissionError(err)) {
353
- process.stderr.write(
354
- `Warning: cannot write info file ${filePath}: permission denied
355
- `
356
- );
357
- return;
358
- }
359
- throw err;
557
+ emitTargetWarning(filePath, "write", err);
558
+ return;
360
559
  }
361
560
  return;
362
561
  }
@@ -366,38 +565,89 @@ async function injectInfoSection(agent, content, projectRoot) {
366
565
  if (boundaries !== null) {
367
566
  const before = lines.slice(0, boundaries.startIdx);
368
567
  const after = lines.slice(boundaries.endIdx + 1);
369
- const contentWithoutTrailingNewline = content.endsWith("\n") ? content.slice(0, -1) : content;
370
- newContent = [...before, contentWithoutTrailingNewline, ...after].join("\n");
568
+ const contentWithoutTrailingNewline = managedSectionOnly.endsWith("\n") ? managedSectionOnly.slice(0, -1) : managedSectionOnly;
569
+ newContent = [...before, contentWithoutTrailingNewline, ...after].join(
570
+ "\n"
571
+ );
371
572
  } else {
372
573
  const separator = existingContent.endsWith("\n") ? "\n" : "\n\n";
373
- newContent = existingContent + separator + content;
574
+ newContent = existingContent + separator + managedSectionOnly;
374
575
  }
375
576
  try {
376
- await (0, import_promises2.writeFile)(filePath, newContent, "utf-8");
577
+ await (0, import_promises3.writeFile)(filePath, newContent, "utf-8");
377
578
  } catch (err) {
378
- if (isPermissionError(err)) {
379
- process.stderr.write(
380
- `Warning: cannot write info file ${filePath}: permission denied
381
- `
382
- );
383
- return;
384
- }
385
- throw err;
579
+ emitTargetWarning(filePath, "write", err);
386
580
  }
387
581
  }
388
- async function hasManagedSection(filePath) {
389
- let content;
582
+ function emitTargetWarning(filePath, op, err) {
583
+ const code = err.code;
584
+ let qualifier;
585
+ switch (code) {
586
+ case "EACCES":
587
+ case "EPERM":
588
+ qualifier = "permission denied";
589
+ break;
590
+ case "EROFS":
591
+ qualifier = "filesystem read-only";
592
+ break;
593
+ case "ENOSPC":
594
+ qualifier = "disk full";
595
+ break;
596
+ case "ENAMETOOLONG":
597
+ qualifier = "path too long";
598
+ break;
599
+ case "ENOTDIR":
600
+ qualifier = "not a directory";
601
+ break;
602
+ case "EISDIR":
603
+ qualifier = "is a directory";
604
+ break;
605
+ default:
606
+ qualifier = "I/O error";
607
+ break;
608
+ }
390
609
  try {
391
- content = await (0, import_promises2.readFile)(filePath, "utf-8");
392
- } catch (err) {
393
- const code = err.code;
394
- if (code === "ENOENT") return false;
395
- throw err;
610
+ process.stderr.write(
611
+ `Warning: cannot ${op} info file ${filePath}: ${qualifier}
612
+ `
613
+ );
614
+ } catch {
396
615
  }
397
- return findMarkerBoundaries(content.split("\n")) !== null;
398
616
  }
399
617
 
400
618
  // src/cli/upgrade-instructions.ts
619
+ function legacyDestinationsForAgent(agent) {
620
+ if (agent.infoFilePath === null) {
621
+ return [];
622
+ }
623
+ switch (agent.name) {
624
+ case "codex":
625
+ return [(0, import_node_path3.join)((0, import_node_path3.dirname)(agent.infoFilePath), "codex.md")];
626
+ case "cursor":
627
+ return [
628
+ (0, import_node_path3.join)((0, import_node_path3.dirname)((0, import_node_path3.dirname)((0, import_node_path3.dirname)(agent.infoFilePath))), ".cursorrules")
629
+ ];
630
+ case "windsurf":
631
+ return [
632
+ (0, import_node_path3.join)(
633
+ (0, import_node_path3.dirname)((0, import_node_path3.dirname)((0, import_node_path3.dirname)(agent.infoFilePath))),
634
+ ".windsurfrules"
635
+ )
636
+ ];
637
+ case "claude":
638
+ case "gemini":
639
+ case "generic":
640
+ return [];
641
+ }
642
+ }
643
+ async function anyHasManagedSection(paths) {
644
+ for (const p of paths) {
645
+ if (await hasManagedSection(p)) {
646
+ return true;
647
+ }
648
+ }
649
+ return false;
650
+ }
401
651
  function formatPathForOutput(filePath, projectRoot) {
402
652
  const rel = (0, import_node_path3.relative)(projectRoot, filePath);
403
653
  if (rel === "" || rel.startsWith("..") || (0, import_node_path3.isAbsolute)(rel)) {
@@ -419,7 +669,8 @@ async function runUpgradeInstructions(options) {
419
669
  );
420
670
  return { exitCode: 1, refreshed, skipped, warnings, errors };
421
671
  }
422
- const sdkVersion = true ? "1.10.2" : "0.0.0-dev";
672
+ const sdkVersion = true ? "1.11.0" : "0.0.0-dev";
673
+ const optedInAgents = [];
423
674
  for (const agent of agents) {
424
675
  if (agent.infoFilePath === null) {
425
676
  continue;
@@ -428,34 +679,54 @@ async function runUpgradeInstructions(options) {
428
679
  agent.infoFilePath,
429
680
  options.projectRoot
430
681
  );
431
- let containsSection;
682
+ const legacyDestinations = legacyDestinationsForAgent(agent);
683
+ let optedIn;
432
684
  try {
433
- containsSection = await hasManagedSection(agent.infoFilePath);
685
+ optedIn = await anyHasManagedSection([
686
+ agent.infoFilePath,
687
+ ...legacyDestinations
688
+ ]);
434
689
  } catch (err) {
435
690
  warnings.push(
436
691
  `Could not inspect ${displayPath}: ${err instanceof Error ? err.message : String(err)}`
437
692
  );
438
693
  continue;
439
694
  }
440
- if (!containsSection) {
695
+ if (!optedIn) {
441
696
  skipped.push(displayPath);
442
697
  continue;
443
698
  }
444
- const content = generateInfoSection(agent, MCP_ENDPOINT, sdkVersion);
445
- if (content === "") {
446
- continue;
447
- }
699
+ optedInAgents.push(agent);
700
+ }
701
+ if (optedInAgents.length > 0) {
448
702
  try {
449
- await injectInfoSection(agent, content, options.projectRoot);
450
- refreshed.push(displayPath);
703
+ await injectAllTargets(
704
+ optedInAgents,
705
+ MCP_ENDPOINT,
706
+ sdkVersion,
707
+ options.projectRoot
708
+ );
709
+ for (const a of optedInAgents) {
710
+ if (a.infoFilePath !== null) {
711
+ refreshed.push(formatPathForOutput(a.infoFilePath, options.projectRoot));
712
+ }
713
+ }
451
714
  } catch (err) {
452
715
  errors.push(
453
- `Failed to refresh ${displayPath}: ${err instanceof Error ? err.message : String(err)}`
716
+ `Failed to refresh agent-instruction files: ${err instanceof Error ? err.message : String(err)}`
454
717
  );
455
718
  }
456
719
  }
720
+ const refreshedSet = new Set(refreshed);
721
+ const dedupedSkipped = skipped.filter((p) => !refreshedSet.has(p));
457
722
  const exitCode = errors.length === 0 ? 0 : 1;
458
- return { exitCode, refreshed, skipped, warnings, errors };
723
+ return {
724
+ exitCode,
725
+ refreshed,
726
+ skipped: dedupedSkipped,
727
+ warnings,
728
+ errors
729
+ };
459
730
  }
460
731
  // Annotate the CommonJS export names for ESM import in node:
461
732
  0 && (module.exports = {