@roarpeng/graphflow 1.9.6 → 1.9.12

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 (214) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +190 -113
  3. package/dist/agents/atp-example-producer.d.ts +33 -0
  4. package/dist/agents/atp-example-producer.d.ts.map +1 -0
  5. package/dist/agents/atp-example-producer.js +154 -0
  6. package/dist/agents/atp-example-producer.js.map +1 -0
  7. package/dist/agents/planner.d.ts.map +1 -1
  8. package/dist/agents/planner.js +14 -8
  9. package/dist/agents/planner.js.map +1 -1
  10. package/dist/config/defaults.d.ts.map +1 -1
  11. package/dist/config/defaults.js +5 -3
  12. package/dist/config/defaults.js.map +1 -1
  13. package/dist/config/include-extensions.d.ts +3 -1
  14. package/dist/config/include-extensions.d.ts.map +1 -1
  15. package/dist/config/include-extensions.js +6 -3
  16. package/dist/config/include-extensions.js.map +1 -1
  17. package/dist/config/loader.js +1 -1
  18. package/dist/config/loader.js.map +1 -1
  19. package/dist/core/agent-delegation.d.ts +16 -2
  20. package/dist/core/agent-delegation.d.ts.map +1 -1
  21. package/dist/core/agent-delegation.js +48 -5
  22. package/dist/core/agent-delegation.js.map +1 -1
  23. package/dist/core/merge-agent-insight.d.ts.map +1 -1
  24. package/dist/core/merge-agent-insight.js +10 -0
  25. package/dist/core/merge-agent-insight.js.map +1 -1
  26. package/dist/core/orchestrator-episode.js +1 -1
  27. package/dist/core/orchestrator.js +52 -1
  28. package/dist/core/orchestrator.js.map +1 -1
  29. package/dist/core/submit-agent-insight.d.ts +17 -0
  30. package/dist/core/submit-agent-insight.d.ts.map +1 -1
  31. package/dist/core/submit-agent-insight.js +28 -0
  32. package/dist/core/submit-agent-insight.js.map +1 -1
  33. package/dist/core/types.d.ts +35 -2
  34. package/dist/core/types.d.ts.map +1 -1
  35. package/dist/graph/context-slicer-types.d.ts +4 -0
  36. package/dist/graph/context-slicer-types.d.ts.map +1 -1
  37. package/dist/graph/context-slicer-types.js +3 -0
  38. package/dist/graph/context-slicer-types.js.map +1 -1
  39. package/dist/graph/context-slicer.d.ts.map +1 -1
  40. package/dist/graph/context-slicer.js +154 -6
  41. package/dist/graph/context-slicer.js.map +1 -1
  42. package/dist/graph/document-convert.d.ts +33 -0
  43. package/dist/graph/document-convert.d.ts.map +1 -0
  44. package/dist/graph/document-convert.js +137 -0
  45. package/dist/graph/document-convert.js.map +1 -0
  46. package/dist/graph/document-semantic-bridge.d.ts +23 -0
  47. package/dist/graph/document-semantic-bridge.d.ts.map +1 -0
  48. package/dist/graph/document-semantic-bridge.js +61 -0
  49. package/dist/graph/document-semantic-bridge.js.map +1 -0
  50. package/dist/graph/document-semantic-ingest.d.ts +48 -0
  51. package/dist/graph/document-semantic-ingest.d.ts.map +1 -0
  52. package/dist/graph/document-semantic-ingest.js +229 -0
  53. package/dist/graph/document-semantic-ingest.js.map +1 -0
  54. package/dist/graph/episode-engineering-links.d.ts +29 -0
  55. package/dist/graph/episode-engineering-links.d.ts.map +1 -0
  56. package/dist/graph/episode-engineering-links.js +63 -0
  57. package/dist/graph/episode-engineering-links.js.map +1 -0
  58. package/dist/graph/file-indexer-edges.d.ts +15 -0
  59. package/dist/graph/file-indexer-edges.d.ts.map +1 -1
  60. package/dist/graph/file-indexer-edges.js +60 -5
  61. package/dist/graph/file-indexer-edges.js.map +1 -1
  62. package/dist/graph/file-indexer-walker.d.ts +2 -1
  63. package/dist/graph/file-indexer-walker.d.ts.map +1 -1
  64. package/dist/graph/file-indexer-walker.js +29 -16
  65. package/dist/graph/file-indexer-walker.js.map +1 -1
  66. package/dist/graph/file-indexer.d.ts +5 -0
  67. package/dist/graph/file-indexer.d.ts.map +1 -1
  68. package/dist/graph/file-indexer.js +121 -17
  69. package/dist/graph/file-indexer.js.map +1 -1
  70. package/dist/graph/graph-compression.d.ts.map +1 -1
  71. package/dist/graph/graph-compression.js +17 -2
  72. package/dist/graph/graph-compression.js.map +1 -1
  73. package/dist/graph/language-indexers/c-cpp.d.ts.map +1 -1
  74. package/dist/graph/language-indexers/c-cpp.js +19 -13
  75. package/dist/graph/language-indexers/c-cpp.js.map +1 -1
  76. package/dist/graph/language-indexers/dart.d.ts.map +1 -1
  77. package/dist/graph/language-indexers/dart.js +2 -6
  78. package/dist/graph/language-indexers/dart.js.map +1 -1
  79. package/dist/graph/language-indexers/go.d.ts.map +1 -1
  80. package/dist/graph/language-indexers/go.js +3 -6
  81. package/dist/graph/language-indexers/go.js.map +1 -1
  82. package/dist/graph/language-indexers/java.d.ts.map +1 -1
  83. package/dist/graph/language-indexers/java.js +2 -6
  84. package/dist/graph/language-indexers/java.js.map +1 -1
  85. package/dist/graph/language-indexers/kotlin.d.ts.map +1 -1
  86. package/dist/graph/language-indexers/kotlin.js +2 -6
  87. package/dist/graph/language-indexers/kotlin.js.map +1 -1
  88. package/dist/graph/language-indexers/python.d.ts.map +1 -1
  89. package/dist/graph/language-indexers/python.js +4 -6
  90. package/dist/graph/language-indexers/python.js.map +1 -1
  91. package/dist/graph/language-indexers/ruby.d.ts.map +1 -1
  92. package/dist/graph/language-indexers/ruby.js +2 -6
  93. package/dist/graph/language-indexers/ruby.js.map +1 -1
  94. package/dist/graph/language-indexers/rust.d.ts.map +1 -1
  95. package/dist/graph/language-indexers/rust.js +3 -6
  96. package/dist/graph/language-indexers/rust.js.map +1 -1
  97. package/dist/graph/language-indexers/swift.d.ts.map +1 -1
  98. package/dist/graph/language-indexers/swift.js +2 -6
  99. package/dist/graph/language-indexers/swift.js.map +1 -1
  100. package/dist/graph/language-indexers/tree-sitter-loader.d.ts +20 -0
  101. package/dist/graph/language-indexers/tree-sitter-loader.d.ts.map +1 -1
  102. package/dist/graph/language-indexers/tree-sitter-loader.js +42 -0
  103. package/dist/graph/language-indexers/tree-sitter-loader.js.map +1 -1
  104. package/dist/graph/memory-pack.d.ts +46 -0
  105. package/dist/graph/memory-pack.d.ts.map +1 -0
  106. package/dist/graph/memory-pack.js +204 -0
  107. package/dist/graph/memory-pack.js.map +1 -0
  108. package/dist/graph/snapshot-view.d.ts.map +1 -1
  109. package/dist/graph/snapshot-view.js +26 -1
  110. package/dist/graph/snapshot-view.js.map +1 -1
  111. package/dist/graph/symbol-extract.d.ts +39 -0
  112. package/dist/graph/symbol-extract.d.ts.map +1 -0
  113. package/dist/graph/symbol-extract.js +187 -0
  114. package/dist/graph/symbol-extract.js.map +1 -0
  115. package/dist/hooks/auto-capture.d.ts +3 -2
  116. package/dist/hooks/auto-capture.d.ts.map +1 -1
  117. package/dist/hooks/auto-capture.js +5 -3
  118. package/dist/hooks/auto-capture.js.map +1 -1
  119. package/dist/index.d.ts +7 -2
  120. package/dist/index.d.ts.map +1 -1
  121. package/dist/index.js +21 -2
  122. package/dist/index.js.map +1 -1
  123. package/dist/integrations/agent-mcp-installer.d.ts +87 -5
  124. package/dist/integrations/agent-mcp-installer.d.ts.map +1 -1
  125. package/dist/integrations/agent-mcp-installer.js +418 -60
  126. package/dist/integrations/agent-mcp-installer.js.map +1 -1
  127. package/dist/integrations/agent-profiles/profiles/qoder.d.ts.map +1 -1
  128. package/dist/integrations/agent-profiles/profiles/qoder.js +14 -2
  129. package/dist/integrations/agent-profiles/profiles/qoder.js.map +1 -1
  130. package/dist/integrations/agent-profiles/skills/qoder.js +6 -0
  131. package/dist/integrations/agent-profiles/skills/qoder.js.map +1 -1
  132. package/dist/integrations/claude-code-hooks.d.ts +33 -1
  133. package/dist/integrations/claude-code-hooks.d.ts.map +1 -1
  134. package/dist/integrations/claude-code-hooks.js +99 -13
  135. package/dist/integrations/claude-code-hooks.js.map +1 -1
  136. package/dist/integrations/ensure-anydoc.d.ts +41 -0
  137. package/dist/integrations/ensure-anydoc.d.ts.map +1 -0
  138. package/dist/integrations/ensure-anydoc.js +221 -0
  139. package/dist/integrations/ensure-anydoc.js.map +1 -0
  140. package/dist/integrations/skill-installer.d.ts +26 -3
  141. package/dist/integrations/skill-installer.d.ts.map +1 -1
  142. package/dist/integrations/skill-installer.js +147 -5
  143. package/dist/integrations/skill-installer.js.map +1 -1
  144. package/dist/learning/canary-gate.d.ts +39 -0
  145. package/dist/learning/canary-gate.d.ts.map +1 -0
  146. package/dist/learning/canary-gate.js +57 -0
  147. package/dist/learning/canary-gate.js.map +1 -0
  148. package/dist/learning/skill-consolidate.d.ts +84 -0
  149. package/dist/learning/skill-consolidate.d.ts.map +1 -0
  150. package/dist/learning/skill-consolidate.js +353 -0
  151. package/dist/learning/skill-consolidate.js.map +1 -0
  152. package/dist/learning/skill-flywheel.d.ts +26 -0
  153. package/dist/learning/skill-flywheel.d.ts.map +1 -1
  154. package/dist/learning/skill-flywheel.js +192 -29
  155. package/dist/learning/skill-flywheel.js.map +1 -1
  156. package/dist/learning/skill-opt-lite.d.ts +46 -0
  157. package/dist/learning/skill-opt-lite.d.ts.map +1 -0
  158. package/dist/learning/skill-opt-lite.js +270 -0
  159. package/dist/learning/skill-opt-lite.js.map +1 -0
  160. package/dist/learning/skill-package.d.ts.map +1 -1
  161. package/dist/learning/skill-package.js +80 -6
  162. package/dist/learning/skill-package.js.map +1 -1
  163. package/dist/learning/skill-store.d.ts.map +1 -1
  164. package/dist/learning/skill-store.js +13 -0
  165. package/dist/learning/skill-store.js.map +1 -1
  166. package/dist/learning/skill-types.d.ts +32 -0
  167. package/dist/learning/skill-types.d.ts.map +1 -1
  168. package/dist/learning/skill-types.js +17 -0
  169. package/dist/learning/skill-types.js.map +1 -1
  170. package/dist/skills/index.js +1 -1
  171. package/dist/skills/index.js.map +1 -1
  172. package/dist/surfaces/cli/index.js +46 -5
  173. package/dist/surfaces/cli/index.js.map +1 -1
  174. package/dist/surfaces/cli/init.d.ts +17 -4
  175. package/dist/surfaces/cli/init.d.ts.map +1 -1
  176. package/dist/surfaces/cli/init.js +71 -8
  177. package/dist/surfaces/cli/init.js.map +1 -1
  178. package/dist/surfaces/cli/output.d.ts.map +1 -1
  179. package/dist/surfaces/cli/output.js +4 -2
  180. package/dist/surfaces/cli/output.js.map +1 -1
  181. package/dist/surfaces/cli/runtime/facade.d.ts +2 -1
  182. package/dist/surfaces/cli/runtime/facade.d.ts.map +1 -1
  183. package/dist/surfaces/cli/runtime/facade.js +1 -0
  184. package/dist/surfaces/cli/runtime/facade.js.map +1 -1
  185. package/dist/surfaces/cli/runtime/graph.d.ts +53 -0
  186. package/dist/surfaces/cli/runtime/graph.d.ts.map +1 -1
  187. package/dist/surfaces/cli/runtime/graph.js +116 -5
  188. package/dist/surfaces/cli/runtime/graph.js.map +1 -1
  189. package/dist/surfaces/cli/runtime/learning.d.ts +19 -0
  190. package/dist/surfaces/cli/runtime/learning.d.ts.map +1 -1
  191. package/dist/surfaces/cli/runtime/learning.js +46 -0
  192. package/dist/surfaces/cli/runtime/learning.js.map +1 -1
  193. package/dist/surfaces/cli/runtime/routing.d.ts +6 -3
  194. package/dist/surfaces/cli/runtime/routing.d.ts.map +1 -1
  195. package/dist/surfaces/cli/runtime/routing.js +70 -7
  196. package/dist/surfaces/cli/runtime/routing.js.map +1 -1
  197. package/dist/surfaces/cli/runtime/types.d.ts +54 -0
  198. package/dist/surfaces/cli/runtime/types.d.ts.map +1 -1
  199. package/dist/surfaces/cli/runtime.d.ts +3 -3
  200. package/dist/surfaces/cli/runtime.d.ts.map +1 -1
  201. package/dist/surfaces/cli/runtime.js +6 -2
  202. package/dist/surfaces/cli/runtime.js.map +1 -1
  203. package/dist/surfaces/mcp/server.js +1 -1
  204. package/dist/surfaces/mcp/tool-definitions.d.ts.map +1 -1
  205. package/dist/surfaces/mcp/tool-definitions.js +15 -0
  206. package/dist/surfaces/mcp/tool-definitions.js.map +1 -1
  207. package/dist/surfaces/mcp/tool-handlers.d.ts.map +1 -1
  208. package/dist/surfaces/mcp/tool-handlers.js +24 -3
  209. package/dist/surfaces/mcp/tool-handlers.js.map +1 -1
  210. package/mcp.json +14 -0
  211. package/package.json +19 -1
  212. package/plugin.json +21 -0
  213. package/scripts/safe-postinstall.cjs +36 -1
  214. package/skills/graphflow/SKILL.md +565 -0
@@ -8,11 +8,17 @@ exports.isEphemeralNodePath = isEphemeralNodePath;
8
8
  exports.isIdeBundledNode = isIdeBundledNode;
9
9
  exports.resolveSystemNodeCommand = resolveSystemNodeCommand;
10
10
  exports.resolveMcpNodeLaunch = resolveMcpNodeLaunch;
11
+ exports.toWindowsPathFromWsl = toWindowsPathFromWsl;
12
+ exports.toWslPathFromWindows = toWslPathFromWindows;
11
13
  exports.getWindowsShortPath = getWindowsShortPath;
12
14
  exports.preferSpaceFreeWindowsPath = preferSpaceFreeWindowsPath;
13
15
  exports.sanitizeMcpServerNodeForWindowsClients = sanitizeMcpServerNodeForWindowsClients;
14
16
  exports.mcpNodeNeedsWindowsSpaceRepair = mcpNodeNeedsWindowsSpaceRepair;
15
17
  exports.repairUnsafeWindowsMcpCommands = repairUnsafeWindowsMcpCommands;
18
+ exports.isGraphFlowMcpLauncherPath = isGraphFlowMcpLauncherPath;
19
+ exports.findMissingGraphFlowMcpLauncher = findMissingGraphFlowMcpLauncher;
20
+ exports.repairStaleGraphFlowMcpLaunchers = repairStaleGraphFlowMcpLaunchers;
21
+ exports.resolveWindowsNpxLaunch = resolveWindowsNpxLaunch;
16
22
  exports.buildMcpServerNode = buildMcpServerNode;
17
23
  exports.removeMcpEntry = removeMcpEntry;
18
24
  exports.removeCodexMcpEntry = removeCodexMcpEntry;
@@ -467,7 +473,11 @@ function buildAgentProfiles() {
467
473
  name: "Qoder",
468
474
  markerPaths: [
469
475
  (0, node_path_1.join)(home, ".qoder"),
476
+ (0, node_path_1.join)(home, ".qoder-cn"),
477
+ (0, node_path_1.join)(home, ".config", "Qoder"),
478
+ (0, node_path_1.join)(home, ".config", "QoderCN"),
470
479
  (0, node_path_1.join)(appData, "Qoder"),
480
+ (0, node_path_1.join)(appData, "QoderCN"),
471
481
  (0, node_path_1.join)(localAppData, "Programs", "qoder"),
472
482
  ],
473
483
  userTargets: [
@@ -476,9 +486,17 @@ function buildAgentProfiles() {
476
486
  serversKey: "mcpServers",
477
487
  },
478
488
  {
489
+ // Qoder 实际读取的用户级 MCP 配置(国际版,已实测生效)
479
490
  configPath: isWindows()
480
- ? (0, node_path_1.join)(appData, "Qoder", "User", "mcp.json")
481
- : (0, node_path_1.join)(home, ".config", "Qoder", "User", "mcp.json"),
491
+ ? (0, node_path_1.join)(appData, "Qoder", "SharedClientCache", "mcp.json")
492
+ : (0, node_path_1.join)(home, ".config", "Qoder", "SharedClientCache", "mcp.json"),
493
+ serversKey: "mcpServers",
494
+ },
495
+ {
496
+ // Qoder CN 版实际读取的用户级 MCP 配置(已实测生效)
497
+ configPath: isWindows()
498
+ ? (0, node_path_1.join)(appData, "QoderCN", "SharedClientCache", "mcp.json")
499
+ : (0, node_path_1.join)(home, ".config", "QoderCN", "SharedClientCache", "mcp.json"),
482
500
  serversKey: "mcpServers",
483
501
  },
484
502
  ],
@@ -681,19 +699,54 @@ function resolveMcpNodeLaunch(options) {
681
699
  // 4. Last resort: bare "node" (relies on PATH resolution at MCP launch time)
682
700
  return { command: "node", env: { ...MCP_STDIO_ENV } };
683
701
  }
702
+ /** Convert `/mnt/c/foo` ↔ `C:\foo` for WSL ↔ Windows path bridging. */
703
+ function toWindowsPathFromWsl(pathValue) {
704
+ const normalized = pathValue.replace(/\//g, "\\");
705
+ const mnt = normalized.match(/^\\mnt\\([A-Za-z])\\(.*)$/);
706
+ if (mnt?.[1] && mnt[2] !== undefined) {
707
+ return `${mnt[1].toUpperCase()}:\\${mnt[2]}`;
708
+ }
709
+ return pathValue.includes("/") ? pathValue.replace(/\//g, "\\") : pathValue;
710
+ }
711
+ function toWslPathFromWindows(pathValue) {
712
+ const match = pathValue.replace(/\//g, "\\").match(/^([A-Za-z]):\\(.*)$/);
713
+ if (match?.[1] && match[2] !== undefined) {
714
+ return `/mnt/${match[1].toLowerCase()}/${match[2].replace(/\\/g, "/")}`;
715
+ }
716
+ return pathValue;
717
+ }
718
+ function pathExistsOnWindowsHost(windowsPath) {
719
+ if (isWindows()) {
720
+ return (0, node_fs_1.existsSync)(windowsPath);
721
+ }
722
+ if (isWsl()) {
723
+ return (0, node_fs_1.existsSync)(toWslPathFromWindows(windowsPath));
724
+ }
725
+ return false;
726
+ }
684
727
  /**
685
- * On Windows, convert a long path containing spaces to its 8.3 short form.
686
- * Many MCP clients (e.g., TRAE) spawn the `command` field via cmd.exe without
687
- * quoting, so paths like "C:\Program Files\..." break with "'C:\Program' is not
688
- * recognized". The 8.3 short name (e.g., "C:\PROGRA~1\...") avoids this entirely.
728
+ * On Windows (or via cmd.exe from WSL), convert a long path containing spaces
729
+ * to its 8.3 short form. Many MCP clients (e.g., TRAE / Codex) spawn `command`
730
+ * without reliable quoting, so "C:\Program Files\..." breaks. Short names like
731
+ * "C:\PROGRA~1\..." avoid this. Codex on Windows also needs NODE/NPX_CLI env
732
+ * pointing at these short paths for npx-cli registration to succeed.
689
733
  */
690
734
  function getWindowsShortPath(longPath) {
691
- if (!isWindows() || !longPath || !longPath.includes(" ")) {
735
+ if (!longPath) {
692
736
  return longPath;
693
737
  }
694
- // Try cmd.exe first (faster, available on all Windows)
738
+ const windowsPath = isWsl() && longPath.startsWith("/mnt/")
739
+ ? toWindowsPathFromWsl(longPath)
740
+ : longPath;
741
+ if (!windowsPath.includes(" ")) {
742
+ return windowsPath;
743
+ }
744
+ if (!isWindows() && !isWsl()) {
745
+ return undefined;
746
+ }
747
+ // Try cmd.exe first (works on native Windows and from WSL)
695
748
  try {
696
- const result = (0, node_child_process_1.execSync)(`for %A in ("${longPath}") do @echo %~sA`, {
749
+ const result = (0, node_child_process_1.execSync)(`for %A in ("${windowsPath}") do @echo %~sA`, {
697
750
  encoding: "utf8",
698
751
  stdio: ["ignore", "pipe", "ignore"],
699
752
  timeout: 3000,
@@ -701,34 +754,36 @@ function getWindowsShortPath(longPath) {
701
754
  }).trim();
702
755
  const lines = result.split(/\r?\n/).filter((l) => l.trim());
703
756
  const shortPath = lines[lines.length - 1]?.trim();
704
- if (shortPath && !shortPath.includes(" ") && (0, node_fs_1.existsSync)(shortPath)) {
757
+ if (shortPath && !shortPath.includes(" ") && pathExistsOnWindowsHost(shortPath)) {
705
758
  return shortPath;
706
759
  }
707
760
  }
708
761
  catch {
709
762
  // fall through to PowerShell
710
763
  }
711
- // Fallback: PowerShell with FileSystemObject COM
712
- try {
713
- const escaped = longPath.replace(/'/g, "''");
714
- const result = (0, node_child_process_1.execSync)(`$fso = New-Object -ComObject Scripting.FileSystemObject; if (Test-Path -LiteralPath '${escaped}') { if ((Get-Item -LiteralPath '${escaped}') -is [System.IO.DirectoryInfo]) { $fso.GetFolder('${escaped}').ShortPath } else { $fso.GetFile('${escaped}').ShortPath } }`, {
715
- encoding: "utf8",
716
- stdio: ["ignore", "pipe", "ignore"],
717
- timeout: 5000,
718
- shell: "powershell.exe",
719
- }).trim();
720
- if (result && !result.includes(" ") && (0, node_fs_1.existsSync)(result)) {
721
- return result;
764
+ // Fallback: PowerShell with FileSystemObject COM (native Windows only)
765
+ if (isWindows()) {
766
+ try {
767
+ const escaped = windowsPath.replace(/'/g, "''");
768
+ const result = (0, node_child_process_1.execSync)(`$fso = New-Object -ComObject Scripting.FileSystemObject; if (Test-Path -LiteralPath '${escaped}') { if ((Get-Item -LiteralPath '${escaped}') -is [System.IO.DirectoryInfo]) { $fso.GetFolder('${escaped}').ShortPath } else { $fso.GetFile('${escaped}').ShortPath } }`, {
769
+ encoding: "utf8",
770
+ stdio: ["ignore", "pipe", "ignore"],
771
+ timeout: 5000,
772
+ shell: "powershell.exe",
773
+ }).trim();
774
+ if (result && !result.includes(" ") && (0, node_fs_1.existsSync)(result)) {
775
+ return result;
776
+ }
777
+ }
778
+ catch {
779
+ // 8.3 name generation may be disabled on some volumes
722
780
  }
723
- }
724
- catch {
725
- // 8.3 name generation may be disabled on some volumes
726
781
  }
727
782
  return undefined;
728
783
  }
729
784
  /** Prefer 8.3 short path on Windows when the input contains spaces; otherwise keep as-is. */
730
785
  function preferSpaceFreeWindowsPath(pathValue) {
731
- if (!isWindows() || !pathValue.includes(" ")) {
786
+ if ((!isWindows() && !isWsl()) || !pathValue.includes(" ")) {
732
787
  return pathValue;
733
788
  }
734
789
  return getWindowsShortPath(pathValue) ?? pathValue;
@@ -848,32 +903,270 @@ function repairUnsafeWindowsMcpCommands(serverName = "graphflow", options) {
848
903
  }
849
904
  return results;
850
905
  }
851
- function resolveWindowsNpxLaunch() {
852
- const node = resolveSystemNodeCommand();
906
+ /** True when a path looks like GraphFlow's extension mcp-launcher script. */
907
+ function isGraphFlowMcpLauncherPath(filePath) {
908
+ const normalized = filePath.replace(/\\/g, "/");
909
+ const base = (0, node_path_1.basename)(normalized).toLowerCase();
910
+ return base === "mcp-launcher.cjs" || base === "mcp-launcher.cmd";
911
+ }
912
+ /**
913
+ * Find a missing GraphFlow mcp-launcher path referenced by an MCP server node.
914
+ * Returns the stale path when the node points at a launcher that is not on disk.
915
+ */
916
+ function findMissingGraphFlowMcpLauncher(node) {
917
+ const candidates = [];
918
+ if (typeof node.command === "string" && isGraphFlowMcpLauncherPath(node.command)) {
919
+ candidates.push(node.command);
920
+ }
921
+ if (Array.isArray(node.args)) {
922
+ for (const arg of node.args) {
923
+ if (typeof arg === "string" && isGraphFlowMcpLauncherPath(arg)) {
924
+ candidates.push(arg);
925
+ }
926
+ }
927
+ }
928
+ for (const candidate of candidates) {
929
+ if (!(0, node_fs_1.existsSync)(candidate)) {
930
+ return candidate;
931
+ }
932
+ }
933
+ return undefined;
934
+ }
935
+ /**
936
+ * After VSIX upgrades, user/workspace MCP configs often still point at the previous
937
+ * extension folder (`…/roarpeng.graphflow-1.9.6/mcp-launcher.cjs`). Cursor Agents
938
+ * Window prefers project MCP and fails hard when that file is gone, while the IDE
939
+ * may still work via a newer user-level entry. Rewrite missing launcher refs to the
940
+ * active extension launcher on activate (and when Install MCP runs).
941
+ */
942
+ function repairStaleGraphFlowMcpLaunchers(options) {
943
+ const launcherPath = options.launcherPath?.trim();
944
+ if (!launcherPath || !(0, node_fs_1.existsSync)(launcherPath)) {
945
+ return [];
946
+ }
947
+ const serverName = options.serverName ?? "graphflow";
948
+ const results = [];
949
+ const seen = new Set();
950
+ const targets = options.targets ??
951
+ buildAgentProfiles().flatMap((profile) => {
952
+ const user = profile.userTargets
953
+ .filter((t) => (t.configFormat ?? "json") !== "codex-toml" && (t.configFormat ?? "json") !== "opencode")
954
+ .map((t) => ({
955
+ agentId: profile.id,
956
+ agentName: profile.name,
957
+ configPath: t.configPath,
958
+ serversKey: t.serversKey,
959
+ }));
960
+ const workspace = options.workspaceRoot && profile.workspaceRelativePaths
961
+ ? profile.workspaceRelativePaths
962
+ .filter((t) => (t.configFormat ?? "json") !== "codex-toml" && (t.configFormat ?? "json") !== "opencode")
963
+ .map((t) => ({
964
+ agentId: profile.id,
965
+ agentName: `${profile.name} (workspace)`,
966
+ configPath: (0, node_path_1.join)(options.workspaceRoot, t.relativePath),
967
+ serversKey: t.serversKey,
968
+ }))
969
+ : [];
970
+ return [...user, ...workspace];
971
+ });
972
+ for (const target of targets) {
973
+ const key = `${target.configPath}::${target.serversKey}`;
974
+ if (seen.has(key) || !(0, node_fs_1.existsSync)(target.configPath)) {
975
+ continue;
976
+ }
977
+ seen.add(key);
978
+ try {
979
+ const json = readJsonConfig(target.configPath);
980
+ const servers = json[target.serversKey] ?? {};
981
+ const previous = servers[serverName];
982
+ if (!previous || typeof previous.command !== "string") {
983
+ continue;
984
+ }
985
+ const missingLauncher = findMissingGraphFlowMcpLauncher({
986
+ ...previous,
987
+ args: Array.isArray(previous.args) ? previous.args : [],
988
+ });
989
+ if (!missingLauncher) {
990
+ const existingLauncher = Array.isArray(previous.args)
991
+ ? previous.args.find((a) => typeof a === "string" && isGraphFlowMcpLauncherPath(a))
992
+ : undefined;
993
+ const unrepaired = {
994
+ agentId: target.agentId,
995
+ agentName: target.agentName,
996
+ configPath: target.configPath,
997
+ repaired: false,
998
+ beforeCommand: previous.command,
999
+ afterCommand: previous.command,
1000
+ };
1001
+ if (existingLauncher) {
1002
+ unrepaired.beforeLauncher = existingLauncher;
1003
+ unrepaired.afterLauncher = existingLauncher;
1004
+ }
1005
+ results.push(unrepaired);
1006
+ continue;
1007
+ }
1008
+ const explicitCommand = options.command?.trim();
1009
+ const nextCommand = explicitCommand ||
1010
+ (previous.command && !isGraphFlowMcpLauncherPath(previous.command)
1011
+ ? previous.command
1012
+ : "node");
1013
+ const nextCwd = options.cwd ?? previous.cwd;
1014
+ const next = {
1015
+ command: nextCommand,
1016
+ args: [launcherPath],
1017
+ ...(nextCwd ? { cwd: nextCwd } : {}),
1018
+ ...(previous.env ? { env: { ...previous.env } } : {}),
1019
+ };
1020
+ servers[serverName] = next;
1021
+ json[target.serversKey] = servers;
1022
+ writeJsonConfig(target.configPath, json);
1023
+ results.push({
1024
+ agentId: target.agentId,
1025
+ agentName: target.agentName,
1026
+ configPath: target.configPath,
1027
+ repaired: true,
1028
+ beforeCommand: previous.command,
1029
+ afterCommand: next.command,
1030
+ beforeLauncher: missingLauncher,
1031
+ afterLauncher: launcherPath,
1032
+ });
1033
+ }
1034
+ catch {
1035
+ // Config may be malformed; skip — install path will recreate.
1036
+ }
1037
+ }
1038
+ return results;
1039
+ }
1040
+ function windowsDirname(windowsPath) {
1041
+ const normalized = windowsPath.replace(/\//g, "\\");
1042
+ const idx = normalized.lastIndexOf("\\");
1043
+ return idx >= 0 ? normalized.slice(0, idx) : ".";
1044
+ }
1045
+ function windowsJoin(...parts) {
1046
+ return parts
1047
+ .map((p, i) => {
1048
+ const n = p.replace(/\//g, "\\");
1049
+ if (i === 0) {
1050
+ return n.replace(/\\+$/g, "");
1051
+ }
1052
+ return n.replace(/^\\+|\\+$/g, "");
1053
+ })
1054
+ .filter((p) => p.length > 0)
1055
+ .join("\\");
1056
+ }
1057
+ function resolveWindowsNodeCandidates(options) {
1058
+ const candidates = [];
1059
+ if (options?.windowsNodePath?.trim()) {
1060
+ candidates.push(options.windowsNodePath.trim());
1061
+ }
1062
+ const wantWindows = Boolean(options?.windowsHost) || isWindows();
1063
+ if (!wantWindows) {
1064
+ return candidates;
1065
+ }
1066
+ if (isWindows()) {
1067
+ const system = resolveSystemNodeCommand();
1068
+ if (system) {
1069
+ candidates.push(system);
1070
+ }
1071
+ const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
1072
+ candidates.push(windowsJoin(programFiles, "nodejs", "node.exe"));
1073
+ candidates.push("C:\\PROGRA~1\\nodejs\\node.exe");
1074
+ return candidates;
1075
+ }
1076
+ // WSL → Windows host: resolve via cmd.exe, then common mount points.
1077
+ try {
1078
+ const output = (0, node_child_process_1.execFileSync)("cmd.exe", ["/c", "where node"], {
1079
+ encoding: "utf8",
1080
+ stdio: ["ignore", "pipe", "ignore"],
1081
+ timeout: 3000,
1082
+ }).trim();
1083
+ for (const line of output.split(/\r?\n/).map((l) => l.trim()).filter(Boolean)) {
1084
+ if (/^[A-Za-z]:\\/.test(line) && !isIdeBundledNode(line)) {
1085
+ candidates.push(line);
1086
+ }
1087
+ }
1088
+ }
1089
+ catch {
1090
+ // ignore
1091
+ }
1092
+ candidates.push("C:\\Program Files\\nodejs\\node.exe", "C:\\PROGRA~1\\nodejs\\node.exe", "/mnt/c/Program Files/nodejs/node.exe", "/mnt/c/PROGRA~1/nodejs/node.exe");
1093
+ return candidates;
1094
+ }
1095
+ /**
1096
+ * Resolve `node.exe` + `npx-cli.js` with space-free (8.3) Windows paths and
1097
+ * NODE/NPX_CLI env — required for Codex MCP registration on Windows.
1098
+ */
1099
+ function resolveWindowsNpxLaunch(options) {
1100
+ const wantWindows = Boolean(options?.windowsHost) || isWindows();
1101
+ if (!wantWindows) {
1102
+ return undefined;
1103
+ }
1104
+ const explicitNode = options?.windowsNodePath?.trim();
1105
+ const explicitNpxCli = options?.windowsNpxCliPath?.trim();
1106
+ // Test / forced injection: trust caller paths (already short-form recommended).
1107
+ if (explicitNode && explicitNpxCli) {
1108
+ const node = explicitNode.startsWith("/mnt/")
1109
+ ? toWindowsPathFromWsl(explicitNode)
1110
+ : explicitNode.replace(/\//g, "\\");
1111
+ const npxCli = explicitNpxCli.startsWith("/mnt/")
1112
+ ? toWindowsPathFromWsl(explicitNpxCli)
1113
+ : explicitNpxCli.replace(/\//g, "\\");
1114
+ const shortNode = getWindowsShortPath(node) ?? node;
1115
+ const shortNpxCli = getWindowsShortPath(npxCli) ?? npxCli;
1116
+ if (shortNode.includes(" ") || shortNpxCli.includes(" ")) {
1117
+ return undefined;
1118
+ }
1119
+ return {
1120
+ command: shortNode,
1121
+ args: [shortNpxCli, "-y", "--package=@roarpeng/graphflow", "graphflow-mcp"],
1122
+ env: {
1123
+ NODE: shortNode,
1124
+ NPX_CLI: shortNpxCli,
1125
+ },
1126
+ };
1127
+ }
1128
+ const nodeCandidates = resolveWindowsNodeCandidates(options);
1129
+ let node;
1130
+ for (const candidate of nodeCandidates) {
1131
+ const windowsStyle = candidate.startsWith("/mnt/")
1132
+ ? toWindowsPathFromWsl(candidate)
1133
+ : candidate;
1134
+ if (pathExistsOnWindowsHost(windowsStyle) || pathExistsOnWindowsHost(candidate)) {
1135
+ node = windowsStyle;
1136
+ break;
1137
+ }
1138
+ }
853
1139
  if (!node) {
854
1140
  return undefined;
855
1141
  }
856
- const nodeDir = (0, node_path_1.dirname)(node);
857
- const candidates = [
858
- (0, node_path_1.join)(nodeDir, "node_modules", "npm", "bin", "npx-cli.js"),
859
- (0, node_path_1.join)(nodeDir, "..", "lib", "node_modules", "npm", "bin", "npx-cli.js"),
1142
+ const nodeDir = windowsDirname(node);
1143
+ const npxCandidates = [
1144
+ windowsJoin(nodeDir, "node_modules", "npm", "bin", "npx-cli.js"),
1145
+ // Some installs put npm next to node under Program Files
1146
+ windowsJoin(windowsDirname(nodeDir), "node_modules", "npm", "bin", "npx-cli.js"),
860
1147
  ];
861
- for (const npxCli of candidates) {
862
- if ((0, node_fs_1.existsSync)(npxCli)) {
863
- // If paths contain spaces, try 8.3 short format to avoid quoting issues
864
- // with MCP clients that don't properly quote the command (e.g., TRAE).
865
- const shortNode = getWindowsShortPath(node) ?? node;
866
- const shortNpxCli = getWindowsShortPath(npxCli) ?? npxCli;
867
- if (shortNode.includes(" ") || shortNpxCli.includes(" ")) {
868
- // Can't resolve to a space-free path; fall back to npx.cmd which
869
- // relies on PATH resolution and handles quoting internally.
870
- return undefined;
871
- }
872
- return {
873
- command: shortNode,
874
- args: [shortNpxCli, "-y", "--package=@roarpeng/graphflow", "graphflow-mcp"],
875
- };
1148
+ for (const npxCliRaw of npxCandidates) {
1149
+ const npxCli = npxCliRaw.startsWith("/mnt/")
1150
+ ? toWindowsPathFromWsl(npxCliRaw)
1151
+ : npxCliRaw.replace(/\//g, "\\");
1152
+ if (!pathExistsOnWindowsHost(npxCli) && !pathExistsOnWindowsHost(npxCliRaw)) {
1153
+ continue;
876
1154
  }
1155
+ const shortNode = getWindowsShortPath(node) ?? node;
1156
+ const shortNpxCli = getWindowsShortPath(npxCli) ?? npxCli;
1157
+ if (shortNode.includes(" ") || shortNpxCli.includes(" ")) {
1158
+ // Can't resolve to a space-free path; fall back to npx.cmd which
1159
+ // relies on PATH resolution and handles quoting internally.
1160
+ return undefined;
1161
+ }
1162
+ return {
1163
+ command: shortNode,
1164
+ args: [shortNpxCli, "-y", "--package=@roarpeng/graphflow", "graphflow-mcp"],
1165
+ env: {
1166
+ NODE: shortNode,
1167
+ NPX_CLI: shortNpxCli,
1168
+ },
1169
+ };
877
1170
  }
878
1171
  return undefined;
879
1172
  }
@@ -947,21 +1240,26 @@ function buildMcpServerNodeRaw(options) {
947
1240
  // 写入 Cursor/VS Code 可展开的 ${workspaceFolder},让 MCP 子进程拿到真实项目根。
948
1241
  // 不支持插值的宿主会留下字面量;discover-workspace 会忽略 unresolved placeholder
949
1242
  // 并回退到 WORKSPACE_FOLDER_PATHS / rootDir。
1243
+ // Codex 不支持 ${workspaceFolder},由 omitWorkspaceFolderPlaceholder 跳过。
950
1244
  const npxEnv = {
951
1245
  ...MCP_STDIO_ENV,
952
- GRAPHFLOW_WORKSPACE_ROOT: "${workspaceFolder}",
953
1246
  };
954
- if (isWindows()) {
955
- const winNpx = resolveWindowsNpxLaunch();
956
- if (winNpx) {
957
- return {
958
- command: winNpx.command,
959
- args: winNpx.args,
960
- env: npxEnv,
961
- };
962
- }
1247
+ if (!options.omitWorkspaceFolderPlaceholder) {
1248
+ npxEnv.GRAPHFLOW_WORKSPACE_ROOT = "${workspaceFolder}";
1249
+ }
1250
+ const winNpx = resolveWindowsNpxLaunch({
1251
+ ...(options.windowsHost !== undefined ? { windowsHost: options.windowsHost } : {}),
1252
+ ...(options.windowsNodePath !== undefined ? { windowsNodePath: options.windowsNodePath } : {}),
1253
+ ...(options.windowsNpxCliPath !== undefined ? { windowsNpxCliPath: options.windowsNpxCliPath } : {}),
1254
+ });
1255
+ if (winNpx) {
1256
+ return {
1257
+ command: winNpx.command,
1258
+ args: winNpx.args,
1259
+ env: { ...npxEnv, ...winNpx.env },
1260
+ };
963
1261
  }
964
- const npxCmd = isWindows() ? "npx.cmd" : "npx";
1262
+ const npxCmd = isWindows() || options.windowsHost ? "npx.cmd" : "npx";
965
1263
  return {
966
1264
  command: npxCmd,
967
1265
  args: ["-y", "--package=@roarpeng/graphflow", "graphflow-mcp"],
@@ -1255,9 +1553,22 @@ function installMcpToDetectedAgents(options) {
1255
1553
  for (const target of targets) {
1256
1554
  try {
1257
1555
  const { workspaceRoot, ...restOptions } = options;
1556
+ const windowsHost = Boolean(restOptions.windowsHost) ||
1557
+ isWindows() ||
1558
+ target.agentId.endsWith("-windows");
1559
+ const isCodex = target.configFormat === "codex-toml";
1258
1560
  const node = buildMcpServerNode(target.scope === "workspace" && workspaceRoot
1259
- ? { ...restOptions, workspaceRoot }
1260
- : restOptions);
1561
+ ? {
1562
+ ...restOptions,
1563
+ workspaceRoot,
1564
+ windowsHost,
1565
+ omitWorkspaceFolderPlaceholder: Boolean(restOptions.omitWorkspaceFolderPlaceholder) || isCodex,
1566
+ }
1567
+ : {
1568
+ ...restOptions,
1569
+ windowsHost,
1570
+ omitWorkspaceFolderPlaceholder: Boolean(restOptions.omitWorkspaceFolderPlaceholder) || isCodex,
1571
+ });
1261
1572
  const status = injectIntoAgentConfig(target.configPath, target.serversKey, target.configFormat, serverName, node);
1262
1573
  results.push({
1263
1574
  agentId: target.agentId,
@@ -1280,12 +1591,13 @@ function installMcpToDetectedAgents(options) {
1280
1591
  }
1281
1592
  return results;
1282
1593
  }
1283
- /** 从所有检测到的 agent 中移除 GraphFlow MCP 配置 */
1594
+ /** 从所有检测到的 agent 中移除 GraphFlow MCP 配置(user + optional workspace) */
1284
1595
  function uninstallMcpFromDetectedAgents(options) {
1285
1596
  const profiles = buildAgentProfiles();
1286
1597
  const detectedIds = new Set(detectInstalledAgents().map((agent) => agent.id));
1287
1598
  const serverName = options?.serverName ?? "graphflow";
1288
1599
  const targetAgentId = options?.agentId;
1600
+ const workspaceRoot = options?.workspaceRoot?.trim() || process.cwd();
1289
1601
  const results = [];
1290
1602
  for (const profile of profiles) {
1291
1603
  // 如果指定了 agent,则仅处理该 agent
@@ -1318,6 +1630,7 @@ function uninstallMcpFromDetectedAgents(options) {
1318
1630
  agentName: profile.name,
1319
1631
  configPath: userTarget.configPath,
1320
1632
  removed,
1633
+ scope: "user",
1321
1634
  message: removed ? "已移除" : "未找到配置(可能已移除)",
1322
1635
  });
1323
1636
  }
@@ -1327,10 +1640,54 @@ function uninstallMcpFromDetectedAgents(options) {
1327
1640
  agentName: profile.name,
1328
1641
  configPath: userTarget.configPath,
1329
1642
  removed: false,
1643
+ scope: "user",
1330
1644
  message: error instanceof Error ? error.message : String(error),
1331
1645
  });
1332
1646
  }
1333
1647
  }
1648
+ if (workspaceRoot && profile.workspaceRelativePaths) {
1649
+ for (const workspaceTarget of profile.workspaceRelativePaths) {
1650
+ const configPath = (0, node_path_1.join)(workspaceRoot, workspaceTarget.relativePath);
1651
+ const key = `${configPath}::${workspaceTarget.serversKey}::${workspaceTarget.configFormat ?? "json"}`;
1652
+ if (seen.has(key)) {
1653
+ continue;
1654
+ }
1655
+ seen.add(key);
1656
+ if (!(0, node_fs_1.existsSync)(configPath)) {
1657
+ continue;
1658
+ }
1659
+ try {
1660
+ let removed = false;
1661
+ if (workspaceTarget.configFormat === "codex-toml") {
1662
+ removed = removeCodexMcpEntry(configPath, serverName);
1663
+ }
1664
+ else if (workspaceTarget.configFormat === "opencode") {
1665
+ removed = removeOpencodeMcpEntry(configPath, serverName);
1666
+ }
1667
+ else {
1668
+ removed = removeMcpEntry(configPath, workspaceTarget.serversKey, serverName);
1669
+ }
1670
+ results.push({
1671
+ agentId: profile.id,
1672
+ agentName: `${profile.name} (workspace)`,
1673
+ configPath,
1674
+ removed,
1675
+ scope: "workspace",
1676
+ message: removed ? "已移除" : "未找到配置(可能已移除)",
1677
+ });
1678
+ }
1679
+ catch (error) {
1680
+ results.push({
1681
+ agentId: profile.id,
1682
+ agentName: `${profile.name} (workspace)`,
1683
+ configPath,
1684
+ removed: false,
1685
+ scope: "workspace",
1686
+ message: error instanceof Error ? error.message : String(error),
1687
+ });
1688
+ }
1689
+ }
1690
+ }
1334
1691
  }
1335
1692
  return results;
1336
1693
  }
@@ -1361,6 +1718,7 @@ function formatModelConfigGuide(workspaceRoot) {
1361
1718
  '> "使用 graphflow 预览当前项目的 orchestrator 相关上下文"',
1362
1719
  "",
1363
1720
  "Codex 配置写入 `~/.codex/config.toml` 的 `[mcp_servers.graphflow]`;Trae 写入 `User/mcp.json`。",
1721
+ "Windows 上 Codex 使用 node.exe + npx-cli.js,并写入 NODE / NPX_CLI(优先 8.3 短路径,如 C:\\PROGRA~1\\nodejs\\...)。",
1364
1722
  "",
1365
1723
  "## 6. 验证路由",
1366
1724
  "运行 `GraphFlow: Settings` 保存后,在 Chat 输入 `@graphflow /diagnose` 查看 provider 健康状态。",