gsd-pi 2.69.0 → 2.70.0-dev.7ebda5e

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 (255) hide show
  1. package/dist/loader.js +4 -0
  2. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +150 -2
  3. package/dist/resources/extensions/gsd/auto-model-selection.js +33 -19
  4. package/dist/resources/extensions/gsd/auto-prompts.js +7 -3
  5. package/dist/resources/extensions/gsd/auto-start.js +25 -1
  6. package/dist/resources/extensions/gsd/auto.js +12 -8
  7. package/dist/resources/extensions/gsd/bootstrap/system-context.js +6 -2
  8. package/dist/resources/extensions/gsd/commands-cmux.js +30 -1
  9. package/dist/resources/extensions/gsd/commands-handlers.js +22 -8
  10. package/dist/resources/extensions/gsd/doctor-engine-checks.js +12 -0
  11. package/dist/resources/extensions/gsd/doctor-format.js +2 -0
  12. package/dist/resources/extensions/gsd/guided-flow.js +21 -10
  13. package/dist/resources/extensions/gsd/pre-execution-checks.js +5 -3
  14. package/dist/resources/extensions/gsd/validate-directory.js +30 -12
  15. package/dist/resources/extensions/gsd/workflow-mcp.js +64 -6
  16. package/dist/resources/extensions/slash-commands/audit.js +2 -1
  17. package/dist/resources/extensions/subagent/isolation.js +4 -2
  18. package/dist/update-check.d.ts +1 -0
  19. package/dist/update-check.js +30 -27
  20. package/dist/update-cmd.js +3 -11
  21. package/dist/web/standalone/.next/BUILD_ID +1 -1
  22. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  23. package/dist/web/standalone/.next/build-manifest.json +3 -3
  24. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  25. package/dist/web/standalone/.next/required-server-files.json +4 -4
  26. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  27. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  28. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  29. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  32. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  37. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  38. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  39. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  40. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  41. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  43. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  47. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  48. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  49. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  50. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  51. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  53. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  59. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  65. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  85. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  95. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  101. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  117. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  121. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/index.html +1 -1
  131. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  132. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  133. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  134. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  136. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/page.js +2 -2
  138. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  140. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  141. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  142. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/middleware.js +2 -2
  144. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  146. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  147. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  148. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  149. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  150. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  151. package/dist/web/standalone/.next/static/chunks/app/page-f1e30ab6bb269149.js +1 -0
  152. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  153. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  154. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  155. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  156. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  157. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  158. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  159. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  160. package/dist/web/standalone/server.js +1 -1
  161. package/dist/web-mode.js +4 -0
  162. package/package.json +11 -11
  163. package/packages/daemon/src/orchestrator.ts +9 -84
  164. package/packages/mcp-server/README.md +25 -3
  165. package/packages/mcp-server/dist/cli.d.ts +0 -1
  166. package/packages/mcp-server/dist/cli.d.ts.map +1 -1
  167. package/packages/mcp-server/dist/cli.js +4 -2
  168. package/packages/mcp-server/dist/cli.js.map +1 -1
  169. package/packages/mcp-server/dist/server.d.ts +32 -1
  170. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  171. package/packages/mcp-server/dist/server.js +118 -1
  172. package/packages/mcp-server/dist/server.js.map +1 -1
  173. package/packages/mcp-server/dist/tool-credentials.d.ts +6 -0
  174. package/packages/mcp-server/dist/tool-credentials.d.ts.map +1 -0
  175. package/packages/mcp-server/dist/tool-credentials.js +90 -0
  176. package/packages/mcp-server/dist/tool-credentials.js.map +1 -0
  177. package/packages/mcp-server/dist/workflow-tools.d.ts +3 -0
  178. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  179. package/packages/mcp-server/dist/workflow-tools.js +308 -4
  180. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  181. package/packages/mcp-server/src/cli.ts +5 -3
  182. package/packages/mcp-server/src/import-candidates.test.ts +48 -0
  183. package/packages/mcp-server/src/mcp-server.test.ts +85 -1
  184. package/packages/mcp-server/src/server.ts +188 -1
  185. package/packages/mcp-server/src/tool-credentials.test.ts +95 -0
  186. package/packages/mcp-server/src/tool-credentials.ts +97 -0
  187. package/packages/mcp-server/src/workflow-tools.test.ts +32 -25
  188. package/packages/mcp-server/src/workflow-tools.ts +398 -2
  189. package/packages/pi-agent-core/dist/agent.d.ts +8 -0
  190. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  191. package/packages/pi-agent-core/dist/agent.js +3 -0
  192. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  193. package/packages/pi-agent-core/src/agent.test.ts +82 -0
  194. package/packages/pi-agent-core/src/agent.ts +12 -0
  195. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  196. package/packages/pi-ai/dist/providers/anthropic.js +1 -23
  197. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  198. package/packages/pi-ai/dist/utils/oauth/index.d.ts +3 -2
  199. package/packages/pi-ai/dist/utils/oauth/index.d.ts.map +1 -1
  200. package/packages/pi-ai/dist/utils/oauth/index.js +3 -5
  201. package/packages/pi-ai/dist/utils/oauth/index.js.map +1 -1
  202. package/packages/pi-ai/src/providers/anthropic.ts +1 -31
  203. package/packages/pi-ai/src/utils/oauth/index.ts +3 -5
  204. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts +1 -0
  205. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -1
  206. package/packages/pi-coding-agent/dist/core/lsp/config.js +38 -15
  207. package/packages/pi-coding-agent/dist/core/lsp/config.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  209. package/packages/pi-coding-agent/dist/core/sdk.js +10 -0
  210. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  211. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
  212. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +3 -1
  213. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
  214. package/packages/pi-coding-agent/package.json +1 -1
  215. package/packages/pi-coding-agent/src/core/lsp/config.ts +43 -17
  216. package/packages/pi-coding-agent/src/core/sdk.ts +8 -0
  217. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +7 -5
  218. package/pkg/package.json +1 -1
  219. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +227 -2
  220. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +172 -0
  221. package/src/resources/extensions/gsd/auto-model-selection.ts +39 -25
  222. package/src/resources/extensions/gsd/auto-prompts.ts +7 -3
  223. package/src/resources/extensions/gsd/auto-start.ts +34 -1
  224. package/src/resources/extensions/gsd/auto.ts +12 -8
  225. package/src/resources/extensions/gsd/bootstrap/system-context.ts +9 -5
  226. package/src/resources/extensions/gsd/commands-cmux.ts +32 -1
  227. package/src/resources/extensions/gsd/commands-handlers.ts +22 -7
  228. package/src/resources/extensions/gsd/doctor-engine-checks.ts +14 -0
  229. package/src/resources/extensions/gsd/doctor-format.ts +1 -0
  230. package/src/resources/extensions/gsd/doctor-types.ts +1 -0
  231. package/src/resources/extensions/gsd/guided-flow.ts +24 -8
  232. package/src/resources/extensions/gsd/pre-execution-checks.ts +6 -3
  233. package/src/resources/extensions/gsd/tests/cmux.test.ts +67 -1
  234. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +43 -0
  235. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +207 -0
  236. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +6 -2
  237. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +48 -1
  238. package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +8 -7
  239. package/src/resources/extensions/gsd/tests/validate-directory.test.ts +33 -1
  240. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +87 -1
  241. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +48 -7
  242. package/src/resources/extensions/gsd/validate-directory.ts +33 -11
  243. package/src/resources/extensions/gsd/workflow-mcp.ts +74 -5
  244. package/src/resources/extensions/slash-commands/audit.ts +2 -1
  245. package/src/resources/extensions/subagent/isolation.ts +4 -3
  246. package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.js +0 -1
  247. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  248. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  249. package/packages/pi-ai/dist/utils/oauth/anthropic.d.ts +0 -17
  250. package/packages/pi-ai/dist/utils/oauth/anthropic.d.ts.map +0 -1
  251. package/packages/pi-ai/dist/utils/oauth/anthropic.js +0 -106
  252. package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +0 -1
  253. package/packages/pi-ai/src/utils/oauth/anthropic.ts +0 -140
  254. /package/dist/web/standalone/.next/static/{DrWdzskk28E5Qz-Wjw1mj → yvFbuOJuph5517lR7HBt2}/_buildManifest.js +0 -0
  255. /package/dist/web/standalone/.next/static/{DrWdzskk28E5Qz-Wjw1mj → yvFbuOJuph5517lR7HBt2}/_ssgManifest.js +0 -0
@@ -61,6 +61,33 @@ const WINDOWS_BLOCKED_PATHS = new Set([
61
61
  "C:\\Program Files (x86)",
62
62
  ]);
63
63
 
64
+ const WINDOWS_BLOCKED_SUFFIXES = new Set([
65
+ "\\",
66
+ "\\windows",
67
+ "\\windows\\system32",
68
+ "\\program files",
69
+ "\\program files (x86)",
70
+ ]);
71
+
72
+ function normalizePathForComparison(dirPath: string): string {
73
+ let normalized = dirPath.replace(/[/\\]+$/, "");
74
+ if (normalized === "") {
75
+ normalized = "/";
76
+ } else if (/^[A-Za-z]:$/.test(normalized)) {
77
+ normalized += "\\";
78
+ }
79
+ return platform() === "win32" ? normalized.toLowerCase() : normalized;
80
+ }
81
+
82
+ function isBlockedWindowsPath(normalized: string): boolean {
83
+ if (!/^[a-z]:\\/.test(normalized)) {
84
+ return false;
85
+ }
86
+
87
+ const suffix = normalized.slice(2);
88
+ return WINDOWS_BLOCKED_SUFFIXES.has(suffix);
89
+ }
90
+
64
91
  // ─── Core Validation ────────────────────────────────────────────────────────────
65
92
 
66
93
  /**
@@ -84,16 +111,11 @@ export function validateDirectory(dirPath: string): DirectoryValidationResult {
84
111
 
85
112
  // Normalize trailing slashes for consistent comparison.
86
113
  // Special cases: "/" → "/" (not ""), "C:\" → "C:\" (not "C:")
87
- let normalized = resolved.replace(/[/\\]+$/, "");
88
- if (normalized === "") {
89
- normalized = "/";
90
- } else if (/^[A-Za-z]:$/.test(normalized)) {
91
- normalized = normalized + "\\";
92
- }
114
+ const normalized = normalizePathForComparison(resolved);
93
115
 
94
116
  // ── Check 1: Blocked system paths ──────────────────────────────────────
95
117
  const blockedPaths = platform() === "win32" ? WINDOWS_BLOCKED_PATHS : UNIX_BLOCKED_PATHS;
96
- if (blockedPaths.has(normalized)) {
118
+ if (platform() === "win32" ? isBlockedWindowsPath(normalized) : blockedPaths.has(normalized)) {
97
119
  return {
98
120
  safe: false,
99
121
  severity: "blocked",
@@ -104,9 +126,9 @@ export function validateDirectory(dirPath: string): DirectoryValidationResult {
104
126
  // ── Check 2: Home directory itself (not subdirs) ───────────────────────
105
127
  let resolvedHome: string;
106
128
  try {
107
- resolvedHome = realpathSync(resolve(homedir())).replace(/[/\\]+$/, "");
129
+ resolvedHome = normalizePathForComparison(realpathSync(resolve(homedir())));
108
130
  } catch {
109
- resolvedHome = resolve(homedir()).replace(/[/\\]+$/, "");
131
+ resolvedHome = normalizePathForComparison(resolve(homedir()));
110
132
  }
111
133
 
112
134
  if (normalized === resolvedHome) {
@@ -120,9 +142,9 @@ export function validateDirectory(dirPath: string): DirectoryValidationResult {
120
142
  // ── Check 3: Temp directory root ───────────────────────────────────────
121
143
  let resolvedTmp: string;
122
144
  try {
123
- resolvedTmp = realpathSync(resolve(tmpdir())).replace(/[/\\]+$/, "");
145
+ resolvedTmp = normalizePathForComparison(realpathSync(resolve(tmpdir())));
124
146
  } catch {
125
- resolvedTmp = resolve(tmpdir()).replace(/[/\\]+$/, "");
147
+ resolvedTmp = normalizePathForComparison(resolve(tmpdir()));
126
148
  }
127
149
 
128
150
  if (normalized === resolvedTmp) {
@@ -1,7 +1,7 @@
1
1
  import { execSync } from "node:child_process";
2
2
  import { existsSync } from "node:fs";
3
3
  import { dirname, resolve } from "node:path";
4
- import { fileURLToPath } from "node:url";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
5
 
6
6
  export interface WorkflowMcpLaunchConfig {
7
7
  name: string;
@@ -21,22 +21,35 @@ export interface WorkflowCapabilityOptions {
21
21
  }
22
22
 
23
23
  const MCP_WORKFLOW_TOOL_SURFACE = new Set([
24
+ "ask_user_questions",
25
+ "gsd_decision_save",
24
26
  "gsd_complete_milestone",
25
27
  "gsd_complete_task",
26
28
  "gsd_complete_slice",
29
+ "gsd_generate_milestone_id",
30
+ "gsd_journal_query",
27
31
  "gsd_milestone_complete",
32
+ "gsd_milestone_generate_id",
28
33
  "gsd_milestone_status",
29
34
  "gsd_milestone_validate",
35
+ "gsd_plan_task",
30
36
  "gsd_plan_milestone",
31
37
  "gsd_plan_slice",
32
38
  "gsd_replan_slice",
33
39
  "gsd_reassess_roadmap",
40
+ "gsd_requirement_save",
41
+ "gsd_requirement_update",
34
42
  "gsd_roadmap_reassess",
43
+ "gsd_save_decision",
35
44
  "gsd_save_gate_result",
45
+ "gsd_save_requirement",
46
+ "gsd_skip_slice",
36
47
  "gsd_slice_replan",
37
48
  "gsd_slice_complete",
38
49
  "gsd_summary_save",
50
+ "gsd_task_plan",
39
51
  "gsd_task_complete",
52
+ "gsd_update_requirement",
40
53
  "gsd_validate_milestone",
41
54
  ]);
42
55
 
@@ -95,6 +108,8 @@ function getBundledWorkflowMcpCliPath(env: NodeJS.ProcessEnv): string | null {
95
108
  }
96
109
 
97
110
  const candidates = [
111
+ resolve(fileURLToPath(new URL("../../../../packages/mcp-server/src/cli.ts", import.meta.url))),
112
+ resolve(fileURLToPath(new URL("../../../../../packages/mcp-server/src/cli.ts", import.meta.url))),
98
113
  resolve(fileURLToPath(new URL("../../../../packages/mcp-server/dist/cli.js", import.meta.url))),
99
114
  resolve(fileURLToPath(new URL("../../../../../packages/mcp-server/dist/cli.js", import.meta.url))),
100
115
  ];
@@ -108,9 +123,9 @@ function getBundledWorkflowMcpCliPath(env: NodeJS.ProcessEnv): string | null {
108
123
 
109
124
  function getBundledWorkflowExecutorModulePath(): string | null {
110
125
  const candidates = [
111
- resolve(fileURLToPath(new URL("../../../../dist/resources/extensions/gsd/tools/workflow-tool-executors.js", import.meta.url))),
112
126
  resolve(fileURLToPath(new URL("./tools/workflow-tool-executors.js", import.meta.url))),
113
127
  resolve(fileURLToPath(new URL("./tools/workflow-tool-executors.ts", import.meta.url))),
128
+ resolve(fileURLToPath(new URL("../../../../dist/resources/extensions/gsd/tools/workflow-tool-executors.js", import.meta.url))),
114
129
  ];
115
130
 
116
131
  for (const candidate of candidates) {
@@ -122,9 +137,22 @@ function getBundledWorkflowExecutorModulePath(): string | null {
122
137
 
123
138
  function getBundledWorkflowWriteGateModulePath(): string | null {
124
139
  const candidates = [
125
- resolve(fileURLToPath(new URL("../../../../dist/resources/extensions/gsd/bootstrap/write-gate.js", import.meta.url))),
126
140
  resolve(fileURLToPath(new URL("./bootstrap/write-gate.js", import.meta.url))),
127
141
  resolve(fileURLToPath(new URL("./bootstrap/write-gate.ts", import.meta.url))),
142
+ resolve(fileURLToPath(new URL("../../../../dist/resources/extensions/gsd/bootstrap/write-gate.js", import.meta.url))),
143
+ ];
144
+
145
+ for (const candidate of candidates) {
146
+ if (existsSync(candidate)) return candidate;
147
+ }
148
+
149
+ return null;
150
+ }
151
+
152
+ function getResolveTsHookPath(): string | null {
153
+ const candidates = [
154
+ resolve(fileURLToPath(new URL("./tests/resolve-ts.mjs", import.meta.url))),
155
+ resolve(fileURLToPath(new URL("../../../../src/resources/extensions/gsd/tests/resolve-ts.mjs", import.meta.url))),
128
156
  ];
129
157
 
130
158
  for (const candidate of candidates) {
@@ -134,19 +162,45 @@ function getBundledWorkflowWriteGateModulePath(): string | null {
134
162
  return null;
135
163
  }
136
164
 
165
+ function mergeNodeOptions(existing: string | undefined, additions: string[]): string | undefined {
166
+ const tokens = (existing ?? "").split(/\s+/).map((value) => value.trim()).filter(Boolean);
167
+ for (const addition of additions) {
168
+ if (!tokens.includes(addition)) {
169
+ tokens.push(addition);
170
+ }
171
+ }
172
+ return tokens.length > 0 ? tokens.join(" ") : undefined;
173
+ }
174
+
137
175
  function buildWorkflowLaunchEnv(
138
176
  projectRoot: string,
139
177
  gsdCliPath: string | undefined,
140
178
  explicitEnv?: Record<string, string>,
179
+ workflowCliPath?: string,
141
180
  ): Record<string, string> {
142
181
  const executorModulePath = getBundledWorkflowExecutorModulePath();
143
182
  const writeGateModulePath = getBundledWorkflowWriteGateModulePath();
183
+ const resolveTsHookPath = getResolveTsHookPath();
184
+ const wantsSourceTs =
185
+ Boolean(resolveTsHookPath) &&
186
+ (
187
+ (workflowCliPath?.endsWith(".ts") ?? false) ||
188
+ (executorModulePath?.endsWith(".ts") ?? false) ||
189
+ (writeGateModulePath?.endsWith(".ts") ?? false)
190
+ );
191
+ const nodeOptions = wantsSourceTs
192
+ ? mergeNodeOptions(explicitEnv?.NODE_OPTIONS, [
193
+ "--experimental-strip-types",
194
+ `--import=${pathToFileURL(resolveTsHookPath!).href}`,
195
+ ])
196
+ : explicitEnv?.NODE_OPTIONS;
144
197
 
145
198
  return {
146
199
  ...(explicitEnv ?? {}),
147
200
  ...(gsdCliPath ? { GSD_CLI_PATH: gsdCliPath } : {}),
148
201
  ...(executorModulePath ? { GSD_WORKFLOW_EXECUTORS_MODULE: executorModulePath } : {}),
149
202
  ...(writeGateModulePath ? { GSD_WORKFLOW_WRITE_GATE_MODULE: writeGateModulePath } : {}),
203
+ ...(nodeOptions ? { NODE_OPTIONS: nodeOptions } : {}),
150
204
  GSD_PERSIST_WRITE_GATE_STATE: "1",
151
205
  GSD_WORKFLOW_PROJECT_ROOT: projectRoot,
152
206
  };
@@ -188,7 +242,7 @@ export function detectWorkflowMcpLaunchConfig(
188
242
  command: process.execPath,
189
243
  args: [distCli],
190
244
  cwd: resolvedWorkflowProjectRoot,
191
- env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath),
245
+ env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath, undefined, distCli),
192
246
  };
193
247
  }
194
248
 
@@ -199,7 +253,7 @@ export function detectWorkflowMcpLaunchConfig(
199
253
  command: process.execPath,
200
254
  args: [bundledCli],
201
255
  cwd: resolvedWorkflowProjectRoot,
202
- env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath),
256
+ env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath, undefined, bundledCli),
203
257
  };
204
258
  }
205
259
 
@@ -294,6 +348,21 @@ export function usesWorkflowMcpTransport(
294
348
  return authMode === "externalCli" && typeof baseUrl === "string" && baseUrl.startsWith("local://");
295
349
  }
296
350
 
351
+ export function supportsStructuredQuestions(
352
+ activeTools: string[],
353
+ options: Pick<WorkflowCapabilityOptions, "authMode" | "baseUrl"> = {},
354
+ ): boolean {
355
+ if (!activeTools.includes("ask_user_questions")) return false;
356
+
357
+ // Workflow MCP currently exposes ask_user_questions via MCP form elicitation.
358
+ // Local external CLI transports such as Claude Code can invoke the tool, but
359
+ // do not reliably complete that elicitation round-trip yet, so guided discuss
360
+ // prompts must fall back to plain-text questioning.
361
+ if (usesWorkflowMcpTransport(options.authMode, options.baseUrl)) return false;
362
+
363
+ return true;
364
+ }
365
+
297
366
  export function getWorkflowTransportSupportError(
298
367
  provider: string | undefined,
299
368
  requiredTools: string[],
@@ -1,4 +1,5 @@
1
1
  import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent";
2
+ import { mkdirSync } from "node:fs";
2
3
 
3
4
  export default function auditCommand(pi: ExtensionAPI) {
4
5
  pi.registerCommand("audit", {
@@ -39,7 +40,7 @@ export default function auditCommand(pi: ExtensionAPI) {
39
40
 
40
41
  // ── Step 3: Ensure the output directory exists ───────────────────────
41
42
 
42
- await pi.exec("mkdir", ["-p", ".gsd/audits"]);
43
+ mkdirSync(".gsd/audits", { recursive: true });
43
44
 
44
45
  // ── Step 4: Send the audit prompt to the agent ───────────────────────
45
46
 
@@ -53,8 +53,10 @@ interface Baseline {
53
53
  // Directory helpers
54
54
  // ============================================================================
55
55
 
56
- function encodeCwd(cwd: string): string {
57
- return cwd.replace(/\//g, "--");
56
+ export function encodeCwd(cwd: string): string {
57
+ // Encode the entire cwd so Windows drive letters, separators, and UNC
58
+ // prefixes cannot leak into the isolation path.
59
+ return Buffer.from(cwd, "utf8").toString("base64url");
58
60
  }
59
61
 
60
62
  const gsdHome = process.env.GSD_HOME || path.join(os.homedir(), ".gsd");
@@ -500,4 +502,3 @@ export function readIsolationMode(): IsolationMode {
500
502
  return "none";
501
503
  }
502
504
  }
503
-
@@ -1 +0,0 @@
1
- (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[8974],{5214:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"workAsyncStorage",{enumerable:!0,get:function(){return r.workAsyncStorageInstance}});let r=n(17828)},15726:(e,t,n)=>{Promise.resolve().then(n.bind(n,66919))},17828:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"workAsyncStorageInstance",{enumerable:!0,get:function(){return r}});let r=(0,n(64054).createAsyncLocalStorage)()},21957:(e,t,n)=>{"use strict";function r({moduleIds:e}){return null}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"PreloadChunks",{enumerable:!0,get:function(){return r}}),n(95155),n(47650),n(5214),n(2451),n(53887)},37206:(e,t,n)=>{"use strict";n.d(t,{default:()=>u.a});var r=n(75707),u=n.n(r)},41112:(e,t,n)=>{"use strict";function r({reason:e,children:t}){return t}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"BailoutToCSR",{enumerable:!0,get:function(){return r}}),n(1980)},64054:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n={bindSnapshot:function(){return s},createAsyncLocalStorage:function(){return a},createSnapshot:function(){return i}};for(var r in n)Object.defineProperty(t,r,{enumerable:!0,get:n[r]});let u=Object.defineProperty(Error("Invariant: AsyncLocalStorage accessed in runtime where it is not available"),"__NEXT_ERROR_CODE",{value:"E504",enumerable:!1,configurable:!0});class l{disable(){throw u}getStore(){}run(){throw u}exit(){throw u}enterWith(){throw u}static bind(e){return e}}let o="u">typeof globalThis&&globalThis.AsyncLocalStorage;function a(){return o?new o:new l}function s(e){return o?o.bind(e):l.bind(e)}function i(){return o?o.snapshot():function(e,...t){return e(...t)}}},66919:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>l});var r=n(95155);let u=(0,n(37206).default)(()=>Promise.all([n.e(1838),n.e(6079),n.e(4986),n.e(2008),n.e(2826)]).then(n.bind(n,62826)).then(e=>e.GSDAppShell),{loadableGenerated:{webpack:()=>[62826]},ssr:!1,loading:()=>(0,r.jsx)("div",{className:"flex h-screen items-center justify-center bg-background text-sm text-muted-foreground",children:"Loading workspace…"})});function l(){return(0,r.jsx)(u,{})}},68635:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return s}});let r=n(95155),u=n(12115),l=n(41112);function o(e){return{default:e&&"default"in e?e.default:e}}n(21957);let a={loader:()=>Promise.resolve(o(()=>null)),loading:null,ssr:!0},s=function(e){let t={...a,...e},n=(0,u.lazy)(()=>t.loader().then(o)),s=t.loading;function i(e){let o=s?(0,r.jsx)(s,{isLoading:!0,pastDelay:!0,error:null}):null,a=!t.ssr||!!t.loading,i=a?u.Suspense:u.Fragment,c=t.ssr?(0,r.jsxs)(r.Fragment,{children:[null,(0,r.jsx)(n,{...e})]}):(0,r.jsx)(l.BailoutToCSR,{reason:"next/dynamic",children:(0,r.jsx)(n,{...e})});return(0,r.jsx)(i,{...a?{fallback:o}:{},children:c})}return i.displayName="LoadableComponent",i}},75707:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return u}});let r=n(73623)._(n(68635));function u(e,t){let n={};"function"==typeof e&&(n.loader=e);let u={...n,...t};return(0,r.default)({...u,modules:u.loadableGenerated?.modules})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)}},e=>{e.O(0,[8441,3794,7358],()=>e(e.s=15726)),_N_E=e.O()}]);
@@ -1 +0,0 @@
1
- (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7358],{2852:(e,s,n)=>{Promise.resolve().then(n.t.bind(n,27123,23)),Promise.resolve().then(n.t.bind(n,61304,23)),Promise.resolve().then(n.t.bind(n,78616,23)),Promise.resolve().then(n.t.bind(n,64777,23)),Promise.resolve().then(n.t.bind(n,57121,23)),Promise.resolve().then(n.t.bind(n,74581,23)),Promise.resolve().then(n.t.bind(n,90484,23)),Promise.resolve().then(n.bind(n,86869))},19393:()=>{}},e=>{var s=s=>e(e.s=s);e.O(0,[8441,3794],()=>(s(83861),s(2852))),_N_E=e.O()}]);
@@ -1 +0,0 @@
1
- (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[9337],{52560:(e,s,_)=>{Promise.resolve().then(_.t.bind(_,27123,23))}},e=>{e.O(0,[8441,3794,7358],()=>e(e.s=52560)),_N_E=e.O()}]);
@@ -1,17 +0,0 @@
1
- /**
2
- * Anthropic OAuth flow (Claude Pro/Max)
3
- */
4
- import type { OAuthCredentials, OAuthProviderInterface } from "./types.js";
5
- /**
6
- * Login with Anthropic OAuth (device code flow)
7
- *
8
- * @param onAuthUrl - Callback to handle the authorization URL (e.g., open browser)
9
- * @param onPromptCode - Callback to prompt user for the authorization code
10
- */
11
- export declare function loginAnthropic(onAuthUrl: (url: string) => void, onPromptCode: () => Promise<string>): Promise<OAuthCredentials>;
12
- /**
13
- * Refresh Anthropic OAuth token
14
- */
15
- export declare function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials>;
16
- export declare const anthropicOAuthProvider: OAuthProviderInterface;
17
- //# sourceMappingURL=anthropic.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/anthropic.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAuB,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAShG;;;;;GAKG;AACH,wBAAsB,cAAc,CACnC,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,EAChC,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GACjC,OAAO,CAAC,gBAAgB,CAAC,CA+D3B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA4B3F;AAED,eAAO,MAAM,sBAAsB,EAAE,sBAkBpC,CAAC"}
@@ -1,106 +0,0 @@
1
- /**
2
- * Anthropic OAuth flow (Claude Pro/Max)
3
- */
4
- import { generatePKCE } from "./pkce.js";
5
- const decode = (s) => atob(s);
6
- const CLIENT_ID = decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
7
- const AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
8
- const TOKEN_URL = "https://platform.claude.com/v1/oauth/token";
9
- const REDIRECT_URI = "https://platform.claude.com/oauth/code/callback";
10
- const SCOPES = "org:create_api_key user:profile user:inference";
11
- /**
12
- * Login with Anthropic OAuth (device code flow)
13
- *
14
- * @param onAuthUrl - Callback to handle the authorization URL (e.g., open browser)
15
- * @param onPromptCode - Callback to prompt user for the authorization code
16
- */
17
- export async function loginAnthropic(onAuthUrl, onPromptCode) {
18
- const { verifier, challenge } = await generatePKCE();
19
- // Build authorization URL
20
- const authParams = new URLSearchParams({
21
- code: "true",
22
- client_id: CLIENT_ID,
23
- response_type: "code",
24
- redirect_uri: REDIRECT_URI,
25
- scope: SCOPES,
26
- code_challenge: challenge,
27
- code_challenge_method: "S256",
28
- state: verifier,
29
- });
30
- const authUrl = `${AUTHORIZE_URL}?${authParams.toString()}`;
31
- // Notify caller with URL to open
32
- onAuthUrl(authUrl);
33
- // Wait for user to paste authorization code (format: code#state)
34
- const authCode = await onPromptCode();
35
- const splits = authCode.split("#");
36
- const code = splits[0];
37
- const state = splits[1];
38
- // Exchange code for tokens
39
- const tokenResponse = await fetch(TOKEN_URL, {
40
- method: "POST",
41
- headers: {
42
- "Content-Type": "application/json",
43
- },
44
- body: JSON.stringify({
45
- grant_type: "authorization_code",
46
- client_id: CLIENT_ID,
47
- code: code,
48
- state: state,
49
- redirect_uri: REDIRECT_URI,
50
- code_verifier: verifier,
51
- }),
52
- signal: AbortSignal.timeout(30_000),
53
- });
54
- if (!tokenResponse.ok) {
55
- const error = await tokenResponse.text();
56
- throw new Error(`Token exchange failed: ${error}`);
57
- }
58
- const tokenData = (await tokenResponse.json());
59
- // Calculate expiry time (current time + expires_in seconds - 5 min buffer)
60
- const expiresAt = Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000;
61
- // Save credentials
62
- return {
63
- refresh: tokenData.refresh_token,
64
- access: tokenData.access_token,
65
- expires: expiresAt,
66
- };
67
- }
68
- /**
69
- * Refresh Anthropic OAuth token
70
- */
71
- export async function refreshAnthropicToken(refreshToken) {
72
- const response = await fetch(TOKEN_URL, {
73
- method: "POST",
74
- headers: { "Content-Type": "application/json" },
75
- body: JSON.stringify({
76
- grant_type: "refresh_token",
77
- client_id: CLIENT_ID,
78
- refresh_token: refreshToken,
79
- }),
80
- signal: AbortSignal.timeout(30_000),
81
- });
82
- if (!response.ok) {
83
- const error = await response.text();
84
- throw new Error(`Anthropic token refresh failed: ${error}`);
85
- }
86
- const data = (await response.json());
87
- return {
88
- refresh: data.refresh_token,
89
- access: data.access_token,
90
- expires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,
91
- };
92
- }
93
- export const anthropicOAuthProvider = {
94
- id: "anthropic",
95
- name: "Anthropic (Claude Pro/Max)",
96
- async login(callbacks) {
97
- return loginAnthropic((url) => callbacks.onAuth({ url }), () => callbacks.onPrompt({ message: "Paste the authorization code:" }));
98
- },
99
- async refreshToken(credentials) {
100
- return refreshAnthropicToken(credentials.refresh);
101
- },
102
- getApiKey(credentials) {
103
- return credentials.access;
104
- },
105
- };
106
- //# sourceMappingURL=anthropic.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/utils/oauth/anthropic.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Anthropic OAuth flow (Claude Pro/Max)\n */\n\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.js\";\n\nconst decode = (s: string) => atob(s);\nconst CLIENT_ID = decode(\"OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl\");\nconst AUTHORIZE_URL = \"https://claude.ai/oauth/authorize\";\nconst TOKEN_URL = \"https://platform.claude.com/v1/oauth/token\";\nconst REDIRECT_URI = \"https://platform.claude.com/oauth/code/callback\";\nconst SCOPES = \"org:create_api_key user:profile user:inference\";\n\n/**\n * Login with Anthropic OAuth (device code flow)\n *\n * @param onAuthUrl - Callback to handle the authorization URL (e.g., open browser)\n * @param onPromptCode - Callback to prompt user for the authorization code\n */\nexport async function loginAnthropic(\n\tonAuthUrl: (url: string) => void,\n\tonPromptCode: () => Promise<string>,\n): Promise<OAuthCredentials> {\n\tconst { verifier, challenge } = await generatePKCE();\n\n\t// Build authorization URL\n\tconst authParams = new URLSearchParams({\n\t\tcode: \"true\",\n\t\tclient_id: CLIENT_ID,\n\t\tresponse_type: \"code\",\n\t\tredirect_uri: REDIRECT_URI,\n\t\tscope: SCOPES,\n\t\tcode_challenge: challenge,\n\t\tcode_challenge_method: \"S256\",\n\t\tstate: verifier,\n\t});\n\n\tconst authUrl = `${AUTHORIZE_URL}?${authParams.toString()}`;\n\n\t// Notify caller with URL to open\n\tonAuthUrl(authUrl);\n\n\t// Wait for user to paste authorization code (format: code#state)\n\tconst authCode = await onPromptCode();\n\tconst splits = authCode.split(\"#\");\n\tconst code = splits[0];\n\tconst state = splits[1];\n\n\t// Exchange code for tokens\n\tconst tokenResponse = await fetch(TOKEN_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tcode: code,\n\t\t\tstate: state,\n\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\tcode_verifier: verifier,\n\t\t}),\n\t\tsignal: AbortSignal.timeout(30_000),\n\t});\n\n\tif (!tokenResponse.ok) {\n\t\tconst error = await tokenResponse.text();\n\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t}\n\n\tconst tokenData = (await tokenResponse.json()) as {\n\t\taccess_token: string;\n\t\trefresh_token: string;\n\t\texpires_in: number;\n\t};\n\n\t// Calculate expiry time (current time + expires_in seconds - 5 min buffer)\n\tconst expiresAt = Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000;\n\n\t// Save credentials\n\treturn {\n\t\trefresh: tokenData.refresh_token,\n\t\taccess: tokenData.access_token,\n\t\texpires: expiresAt,\n\t};\n}\n\n/**\n * Refresh Anthropic OAuth token\n */\nexport async function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials> {\n\tconst response = await fetch(TOKEN_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\tbody: JSON.stringify({\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\trefresh_token: refreshToken,\n\t\t}),\n\t\tsignal: AbortSignal.timeout(30_000),\n\t});\n\n\tif (!response.ok) {\n\t\tconst error = await response.text();\n\t\tthrow new Error(`Anthropic token refresh failed: ${error}`);\n\t}\n\n\tconst data = (await response.json()) as {\n\t\taccess_token: string;\n\t\trefresh_token: string;\n\t\texpires_in: number;\n\t};\n\n\treturn {\n\t\trefresh: data.refresh_token,\n\t\taccess: data.access_token,\n\t\texpires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\nexport const anthropicOAuthProvider: OAuthProviderInterface = {\n\tid: \"anthropic\",\n\tname: \"Anthropic (Claude Pro/Max)\",\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginAnthropic(\n\t\t\t(url) => callbacks.onAuth({ url }),\n\t\t\t() => callbacks.onPrompt({ message: \"Paste the authorization code:\" }),\n\t\t);\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshAnthropicToken(credentials.refresh);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n"]}
@@ -1,140 +0,0 @@
1
- /**
2
- * Anthropic OAuth flow (Claude Pro/Max)
3
- */
4
-
5
- import { generatePKCE } from "./pkce.js";
6
- import type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from "./types.js";
7
-
8
- const decode = (s: string) => atob(s);
9
- const CLIENT_ID = decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
10
- const AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
11
- const TOKEN_URL = "https://platform.claude.com/v1/oauth/token";
12
- const REDIRECT_URI = "https://platform.claude.com/oauth/code/callback";
13
- const SCOPES = "org:create_api_key user:profile user:inference";
14
-
15
- /**
16
- * Login with Anthropic OAuth (device code flow)
17
- *
18
- * @param onAuthUrl - Callback to handle the authorization URL (e.g., open browser)
19
- * @param onPromptCode - Callback to prompt user for the authorization code
20
- */
21
- export async function loginAnthropic(
22
- onAuthUrl: (url: string) => void,
23
- onPromptCode: () => Promise<string>,
24
- ): Promise<OAuthCredentials> {
25
- const { verifier, challenge } = await generatePKCE();
26
-
27
- // Build authorization URL
28
- const authParams = new URLSearchParams({
29
- code: "true",
30
- client_id: CLIENT_ID,
31
- response_type: "code",
32
- redirect_uri: REDIRECT_URI,
33
- scope: SCOPES,
34
- code_challenge: challenge,
35
- code_challenge_method: "S256",
36
- state: verifier,
37
- });
38
-
39
- const authUrl = `${AUTHORIZE_URL}?${authParams.toString()}`;
40
-
41
- // Notify caller with URL to open
42
- onAuthUrl(authUrl);
43
-
44
- // Wait for user to paste authorization code (format: code#state)
45
- const authCode = await onPromptCode();
46
- const splits = authCode.split("#");
47
- const code = splits[0];
48
- const state = splits[1];
49
-
50
- // Exchange code for tokens
51
- const tokenResponse = await fetch(TOKEN_URL, {
52
- method: "POST",
53
- headers: {
54
- "Content-Type": "application/json",
55
- },
56
- body: JSON.stringify({
57
- grant_type: "authorization_code",
58
- client_id: CLIENT_ID,
59
- code: code,
60
- state: state,
61
- redirect_uri: REDIRECT_URI,
62
- code_verifier: verifier,
63
- }),
64
- signal: AbortSignal.timeout(30_000),
65
- });
66
-
67
- if (!tokenResponse.ok) {
68
- const error = await tokenResponse.text();
69
- throw new Error(`Token exchange failed: ${error}`);
70
- }
71
-
72
- const tokenData = (await tokenResponse.json()) as {
73
- access_token: string;
74
- refresh_token: string;
75
- expires_in: number;
76
- };
77
-
78
- // Calculate expiry time (current time + expires_in seconds - 5 min buffer)
79
- const expiresAt = Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000;
80
-
81
- // Save credentials
82
- return {
83
- refresh: tokenData.refresh_token,
84
- access: tokenData.access_token,
85
- expires: expiresAt,
86
- };
87
- }
88
-
89
- /**
90
- * Refresh Anthropic OAuth token
91
- */
92
- export async function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials> {
93
- const response = await fetch(TOKEN_URL, {
94
- method: "POST",
95
- headers: { "Content-Type": "application/json" },
96
- body: JSON.stringify({
97
- grant_type: "refresh_token",
98
- client_id: CLIENT_ID,
99
- refresh_token: refreshToken,
100
- }),
101
- signal: AbortSignal.timeout(30_000),
102
- });
103
-
104
- if (!response.ok) {
105
- const error = await response.text();
106
- throw new Error(`Anthropic token refresh failed: ${error}`);
107
- }
108
-
109
- const data = (await response.json()) as {
110
- access_token: string;
111
- refresh_token: string;
112
- expires_in: number;
113
- };
114
-
115
- return {
116
- refresh: data.refresh_token,
117
- access: data.access_token,
118
- expires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,
119
- };
120
- }
121
-
122
- export const anthropicOAuthProvider: OAuthProviderInterface = {
123
- id: "anthropic",
124
- name: "Anthropic (Claude Pro/Max)",
125
-
126
- async login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {
127
- return loginAnthropic(
128
- (url) => callbacks.onAuth({ url }),
129
- () => callbacks.onPrompt({ message: "Paste the authorization code:" }),
130
- );
131
- },
132
-
133
- async refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {
134
- return refreshAnthropicToken(credentials.refresh);
135
- },
136
-
137
- getApiKey(credentials: OAuthCredentials): string {
138
- return credentials.access;
139
- },
140
- };