gsd-pi 2.69.0-dev.232905b → 2.69.0-dev.87298d1

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 (85) hide show
  1. package/dist/resources/extensions/gsd/bootstrap/system-context.js +2 -6
  2. package/dist/resources/extensions/gsd/commands-cmux.js +1 -30
  3. package/dist/resources/extensions/gsd/workflow-mcp.js +6 -53
  4. package/dist/web/standalone/.next/BUILD_ID +1 -1
  5. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  6. package/dist/web/standalone/.next/build-manifest.json +2 -2
  7. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  8. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  9. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  10. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  12. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  13. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  14. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  15. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  17. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  18. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  20. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  21. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  22. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  23. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  25. package/dist/web/standalone/.next/server/app/index.html +1 -1
  26. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  32. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  33. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  34. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  35. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  36. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  37. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  38. package/package.json +1 -1
  39. package/packages/daemon/src/orchestrator.ts +84 -9
  40. package/packages/mcp-server/README.md +3 -25
  41. package/packages/mcp-server/dist/cli.d.ts +1 -0
  42. package/packages/mcp-server/dist/cli.d.ts.map +1 -1
  43. package/packages/mcp-server/dist/cli.js +2 -4
  44. package/packages/mcp-server/dist/cli.js.map +1 -1
  45. package/packages/mcp-server/dist/server.d.ts +1 -32
  46. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  47. package/packages/mcp-server/dist/server.js +1 -118
  48. package/packages/mcp-server/dist/server.js.map +1 -1
  49. package/packages/mcp-server/dist/workflow-tools.d.ts +0 -1
  50. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  51. package/packages/mcp-server/dist/workflow-tools.js +2 -274
  52. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  53. package/packages/mcp-server/src/cli.ts +3 -5
  54. package/packages/mcp-server/src/mcp-server.test.ts +1 -85
  55. package/packages/mcp-server/src/server.ts +1 -188
  56. package/packages/mcp-server/src/workflow-tools.test.ts +25 -32
  57. package/packages/mcp-server/src/workflow-tools.ts +2 -365
  58. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  59. package/packages/pi-ai/dist/providers/anthropic.js +23 -1
  60. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  61. package/packages/pi-ai/dist/utils/oauth/anthropic.d.ts +17 -0
  62. package/packages/pi-ai/dist/utils/oauth/anthropic.d.ts.map +1 -0
  63. package/packages/pi-ai/dist/utils/oauth/anthropic.js +106 -0
  64. package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -0
  65. package/packages/pi-ai/dist/utils/oauth/index.d.ts +2 -3
  66. package/packages/pi-ai/dist/utils/oauth/index.d.ts.map +1 -1
  67. package/packages/pi-ai/dist/utils/oauth/index.js +5 -3
  68. package/packages/pi-ai/dist/utils/oauth/index.js.map +1 -1
  69. package/packages/pi-ai/src/providers/anthropic.ts +31 -1
  70. package/packages/pi-ai/src/utils/oauth/anthropic.ts +140 -0
  71. package/packages/pi-ai/src/utils/oauth/index.ts +5 -3
  72. package/src/resources/extensions/gsd/bootstrap/system-context.ts +5 -9
  73. package/src/resources/extensions/gsd/commands-cmux.ts +1 -32
  74. package/src/resources/extensions/gsd/tests/cmux.test.ts +1 -67
  75. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +2 -6
  76. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +7 -23
  77. package/src/resources/extensions/gsd/workflow-mcp.ts +5 -59
  78. package/packages/mcp-server/dist/tool-credentials.d.ts +0 -6
  79. package/packages/mcp-server/dist/tool-credentials.d.ts.map +0 -1
  80. package/packages/mcp-server/dist/tool-credentials.js +0 -90
  81. package/packages/mcp-server/dist/tool-credentials.js.map +0 -1
  82. package/packages/mcp-server/src/tool-credentials.test.ts +0 -95
  83. package/packages/mcp-server/src/tool-credentials.ts +0 -97
  84. /package/dist/web/standalone/.next/static/{CHeIRZw-E97oO51g7zDvv → PYwFks7YuKWnl48wsvjo4}/_buildManifest.js +0 -0
  85. /package/dist/web/standalone/.next/static/{CHeIRZw-E97oO51g7zDvv → PYwFks7YuKWnl48wsvjo4}/_ssgManifest.js +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/utils/oauth/anthropic.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAGzC,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACtC,MAAM,SAAS,GAAG,MAAM,CAAC,kDAAkD,CAAC,CAAC;AAC7E,MAAM,aAAa,GAAG,mCAAmC,CAAC;AAC1D,MAAM,SAAS,GAAG,4CAA4C,CAAC;AAC/D,MAAM,YAAY,GAAG,iDAAiD,CAAC;AACvE,MAAM,MAAM,GAAG,gDAAgD,CAAC;AAEhE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CACnC,SAAgC,EAChC,YAAmC;IAEnC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;IAErD,0BAA0B;IAC1B,MAAM,UAAU,GAAG,IAAI,eAAe,CAAC;QACtC,IAAI,EAAE,MAAM;QACZ,SAAS,EAAE,SAAS;QACpB,aAAa,EAAE,MAAM;QACrB,YAAY,EAAE,YAAY;QAC1B,KAAK,EAAE,MAAM;QACb,cAAc,EAAE,SAAS;QACzB,qBAAqB,EAAE,MAAM;QAC7B,KAAK,EAAE,QAAQ;KACf,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,GAAG,aAAa,IAAI,UAAU,CAAC,QAAQ,EAAE,EAAE,CAAC;IAE5D,iCAAiC;IACjC,SAAS,CAAC,OAAO,CAAC,CAAC;IAEnB,iEAAiE;IACjE,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACvB,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAExB,2BAA2B;IAC3B,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE;QAC5C,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACR,cAAc,EAAE,kBAAkB;SAClC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACpB,UAAU,EAAE,oBAAoB;YAChC,SAAS,EAAE,SAAS;YACpB,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,KAAK;YACZ,YAAY,EAAE,YAAY;YAC1B,aAAa,EAAE,QAAQ;SACvB,CAAC;QACF,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;KACnC,CAAC,CAAC;IAEH,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,0BAA0B,KAAK,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,SAAS,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,CAI5C,CAAC;IAEF,2EAA2E;IAC3E,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,UAAU,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IAE3E,mBAAmB;IACnB,OAAO;QACN,OAAO,EAAE,SAAS,CAAC,aAAa;QAChC,MAAM,EAAE,SAAS,CAAC,YAAY;QAC9B,OAAO,EAAE,SAAS;KAClB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,YAAoB;IAC/D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE;QACvC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACpB,UAAU,EAAE,eAAe;YAC3B,SAAS,EAAE,SAAS;YACpB,aAAa,EAAE,YAAY;SAC3B,CAAC;QACF,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;KACnC,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QAClB,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,mCAAmC,KAAK,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAIlC,CAAC;IAEF,OAAO;QACN,OAAO,EAAE,IAAI,CAAC,aAAa;QAC3B,MAAM,EAAE,IAAI,CAAC,YAAY;QACzB,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI;KAC5D,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,sBAAsB,GAA2B;IAC7D,EAAE,EAAE,WAAW;IACf,IAAI,EAAE,4BAA4B;IAElC,KAAK,CAAC,KAAK,CAAC,SAA8B;QACzC,OAAO,cAAc,CACpB,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAClC,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC,CACtE,CAAC;IACH,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,WAA6B;QAC/C,OAAO,qBAAqB,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACnD,CAAC;IAED,SAAS,CAAC,WAA6B;QACtC,OAAO,WAAW,CAAC,MAAM,CAAC;IAC3B,CAAC;CACD,CAAC","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"]}
@@ -3,13 +3,12 @@
3
3
  *
4
4
  * This module handles login, token refresh, and credential storage
5
5
  * for OAuth-based providers:
6
+ * - Anthropic (Claude Pro/Max)
6
7
  * - GitHub Copilot
7
8
  * - Google Cloud Code Assist (Gemini CLI)
8
9
  * - Antigravity (Gemini 3, Claude, GPT-OSS via Google Cloud)
9
- *
10
- * Note: Anthropic OAuth was removed per TOS compliance (see docs/user-docs/claude-code-auth-compliance.md).
11
- * Use API keys or the local Claude Code CLI for Anthropic access.
12
10
  */
11
+ export { anthropicOAuthProvider, loginAnthropic, refreshAnthropicToken } from "./anthropic.js";
13
12
  export { getGitHubCopilotBaseUrl, githubCopilotOAuthProvider, loginGitHubCopilot, normalizeDomain, refreshGitHubCopilotToken, } from "./github-copilot.js";
14
13
  export { antigravityOAuthProvider, loginAntigravity, refreshAntigravityToken } from "./google-antigravity.js";
15
14
  export { geminiCliOAuthProvider, loginGeminiCli, refreshGoogleCloudToken } from "./google-gemini-cli.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EACN,uBAAuB,EACvB,0BAA0B,EAC1B,kBAAkB,EAClB,eAAe,EACf,yBAAyB,GACzB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAE9G,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEzG,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAExG,cAAc,YAAY,CAAC;AAU3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAa5F;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,eAAe,GAAG,sBAAsB,GAAG,SAAS,CAExF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,IAAI,CAE5E;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAOxD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAK1C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,sBAAsB,EAAE,CAE5D;AAMD;;;;;;GAMG;AACH,wBAAsB,cAAc,CACnC,UAAU,EAAE,eAAe,EAC3B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAC3C,OAAO,CAAC;IAAE,cAAc,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAsBtE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE/F,OAAO,EACN,uBAAuB,EACvB,0BAA0B,EAC1B,kBAAkB,EAClB,eAAe,EACf,yBAAyB,GACzB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAE9G,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEzG,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAExG,cAAc,YAAY,CAAC;AAW3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAc5F;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,eAAe,GAAG,sBAAsB,GAAG,SAAS,CAExF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,IAAI,CAE5E;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAOxD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAK1C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,sBAAsB,EAAE,CAE5D;AAMD;;;;;;GAMG;AACH,wBAAsB,cAAc,CACnC,UAAU,EAAE,eAAe,EAC3B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAC3C,OAAO,CAAC;IAAE,cAAc,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAsBtE"}
@@ -3,13 +3,13 @@
3
3
  *
4
4
  * This module handles login, token refresh, and credential storage
5
5
  * for OAuth-based providers:
6
+ * - Anthropic (Claude Pro/Max)
6
7
  * - GitHub Copilot
7
8
  * - Google Cloud Code Assist (Gemini CLI)
8
9
  * - Antigravity (Gemini 3, Claude, GPT-OSS via Google Cloud)
9
- *
10
- * Note: Anthropic OAuth was removed per TOS compliance (see docs/user-docs/claude-code-auth-compliance.md).
11
- * Use API keys or the local Claude Code CLI for Anthropic access.
12
10
  */
11
+ // Anthropic
12
+ export { anthropicOAuthProvider, loginAnthropic, refreshAnthropicToken } from "./anthropic.js";
13
13
  // GitHub Copilot
14
14
  export { getGitHubCopilotBaseUrl, githubCopilotOAuthProvider, loginGitHubCopilot, normalizeDomain, refreshGitHubCopilotToken, } from "./github-copilot.js";
15
15
  // Google Antigravity
@@ -22,11 +22,13 @@ export * from "./types.js";
22
22
  // ============================================================================
23
23
  // Provider Registry
24
24
  // ============================================================================
25
+ import { anthropicOAuthProvider } from "./anthropic.js";
25
26
  import { githubCopilotOAuthProvider } from "./github-copilot.js";
26
27
  import { antigravityOAuthProvider } from "./google-antigravity.js";
27
28
  import { geminiCliOAuthProvider } from "./google-gemini-cli.js";
28
29
  import { openaiCodexOAuthProvider } from "./openai-codex.js";
29
30
  const BUILT_IN_OAUTH_PROVIDERS = [
31
+ anthropicOAuthProvider,
30
32
  githubCopilotOAuthProvider,
31
33
  geminiCliOAuthProvider,
32
34
  antigravityOAuthProvider,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/oauth/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * OAuth credential management for AI providers.\n *\n * This module handles login, token refresh, and credential storage\n * for OAuth-based providers:\n * - GitHub Copilot\n * - Google Cloud Code Assist (Gemini CLI)\n * - Antigravity (Gemini 3, Claude, GPT-OSS via Google Cloud)\n *\n * Note: Anthropic OAuth was removed per TOS compliance (see docs/user-docs/claude-code-auth-compliance.md).\n * Use API keys or the local Claude Code CLI for Anthropic access.\n */\n\n// GitHub Copilot\nexport {\n\tgetGitHubCopilotBaseUrl,\n\tgithubCopilotOAuthProvider,\n\tloginGitHubCopilot,\n\tnormalizeDomain,\n\trefreshGitHubCopilotToken,\n} from \"./github-copilot.js\";\n// Google Antigravity\nexport { antigravityOAuthProvider, loginAntigravity, refreshAntigravityToken } from \"./google-antigravity.js\";\n// Google Gemini CLI\nexport { geminiCliOAuthProvider, loginGeminiCli, refreshGoogleCloudToken } from \"./google-gemini-cli.js\";\n// OpenAI Codex (ChatGPT OAuth)\nexport { loginOpenAICodex, openaiCodexOAuthProvider, refreshOpenAICodexToken } from \"./openai-codex.js\";\n\nexport * from \"./types.js\";\n\n// ============================================================================\n// Provider Registry\n// ============================================================================\n\nimport { githubCopilotOAuthProvider } from \"./github-copilot.js\";\nimport { antigravityOAuthProvider } from \"./google-antigravity.js\";\nimport { geminiCliOAuthProvider } from \"./google-gemini-cli.js\";\nimport { openaiCodexOAuthProvider } from \"./openai-codex.js\";\nimport type { OAuthCredentials, OAuthProviderId, OAuthProviderInterface } from \"./types.js\";\n\nconst BUILT_IN_OAUTH_PROVIDERS: OAuthProviderInterface[] = [\n\tgithubCopilotOAuthProvider,\n\tgeminiCliOAuthProvider,\n\tantigravityOAuthProvider,\n\topenaiCodexOAuthProvider,\n];\n\nconst oauthProviderRegistry = new Map<string, OAuthProviderInterface>(\n\tBUILT_IN_OAUTH_PROVIDERS.map((provider) => [provider.id, provider]),\n);\n\n/**\n * Get an OAuth provider by ID\n */\nexport function getOAuthProvider(id: OAuthProviderId): OAuthProviderInterface | undefined {\n\treturn oauthProviderRegistry.get(id);\n}\n\n/**\n * Register a custom OAuth provider\n */\nexport function registerOAuthProvider(provider: OAuthProviderInterface): void {\n\toauthProviderRegistry.set(provider.id, provider);\n}\n\n/**\n * Unregister an OAuth provider.\n *\n * If the provider is built-in, restores the built-in implementation.\n * Custom providers are removed completely.\n */\nexport function unregisterOAuthProvider(id: string): void {\n\tconst builtInProvider = BUILT_IN_OAUTH_PROVIDERS.find((provider) => provider.id === id);\n\tif (builtInProvider) {\n\t\toauthProviderRegistry.set(id, builtInProvider);\n\t\treturn;\n\t}\n\toauthProviderRegistry.delete(id);\n}\n\n/**\n * Reset OAuth providers to built-ins.\n */\nexport function resetOAuthProviders(): void {\n\toauthProviderRegistry.clear();\n\tfor (const provider of BUILT_IN_OAUTH_PROVIDERS) {\n\t\toauthProviderRegistry.set(provider.id, provider);\n\t}\n}\n\n/**\n * Get all registered OAuth providers\n */\nexport function getOAuthProviders(): OAuthProviderInterface[] {\n\treturn Array.from(oauthProviderRegistry.values());\n}\n\n// ============================================================================\n// High-level API (uses provider registry)\n// ============================================================================\n\n/**\n * Get API key for a provider from OAuth credentials.\n * Automatically refreshes expired tokens.\n *\n * @returns API key string and updated credentials, or null if no credentials\n * @throws Error if refresh fails\n */\nexport async function getOAuthApiKey(\n\tproviderId: OAuthProviderId,\n\tcredentials: Record<string, OAuthCredentials>,\n): Promise<{ newCredentials: OAuthCredentials; apiKey: string } | null> {\n\tconst provider = getOAuthProvider(providerId);\n\tif (!provider) {\n\t\tthrow new Error(`Unknown OAuth provider: ${providerId}`);\n\t}\n\n\tlet creds = credentials[providerId];\n\tif (!creds) {\n\t\treturn null;\n\t}\n\n\t// Refresh if expired\n\tif (Date.now() >= creds.expires) {\n\t\ttry {\n\t\t\tcreds = await provider.refreshToken(creds);\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Failed to refresh OAuth token for ${providerId}`, { cause: error });\n\t\t}\n\t}\n\n\tconst apiKey = provider.getApiKey(creds);\n\treturn { newCredentials: creds, apiKey };\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/oauth/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * OAuth credential management for AI providers.\n *\n * This module handles login, token refresh, and credential storage\n * for OAuth-based providers:\n * - Anthropic (Claude Pro/Max)\n * - GitHub Copilot\n * - Google Cloud Code Assist (Gemini CLI)\n * - Antigravity (Gemini 3, Claude, GPT-OSS via Google Cloud)\n */\n\n// Anthropic\nexport { anthropicOAuthProvider, loginAnthropic, refreshAnthropicToken } from \"./anthropic.js\";\n// GitHub Copilot\nexport {\n\tgetGitHubCopilotBaseUrl,\n\tgithubCopilotOAuthProvider,\n\tloginGitHubCopilot,\n\tnormalizeDomain,\n\trefreshGitHubCopilotToken,\n} from \"./github-copilot.js\";\n// Google Antigravity\nexport { antigravityOAuthProvider, loginAntigravity, refreshAntigravityToken } from \"./google-antigravity.js\";\n// Google Gemini CLI\nexport { geminiCliOAuthProvider, loginGeminiCli, refreshGoogleCloudToken } from \"./google-gemini-cli.js\";\n// OpenAI Codex (ChatGPT OAuth)\nexport { loginOpenAICodex, openaiCodexOAuthProvider, refreshOpenAICodexToken } from \"./openai-codex.js\";\n\nexport * from \"./types.js\";\n\n// ============================================================================\n// Provider Registry\n// ============================================================================\n\nimport { anthropicOAuthProvider } from \"./anthropic.js\";\nimport { githubCopilotOAuthProvider } from \"./github-copilot.js\";\nimport { antigravityOAuthProvider } from \"./google-antigravity.js\";\nimport { geminiCliOAuthProvider } from \"./google-gemini-cli.js\";\nimport { openaiCodexOAuthProvider } from \"./openai-codex.js\";\nimport type { OAuthCredentials, OAuthProviderId, OAuthProviderInterface } from \"./types.js\";\n\nconst BUILT_IN_OAUTH_PROVIDERS: OAuthProviderInterface[] = [\n\tanthropicOAuthProvider,\n\tgithubCopilotOAuthProvider,\n\tgeminiCliOAuthProvider,\n\tantigravityOAuthProvider,\n\topenaiCodexOAuthProvider,\n];\n\nconst oauthProviderRegistry = new Map<string, OAuthProviderInterface>(\n\tBUILT_IN_OAUTH_PROVIDERS.map((provider) => [provider.id, provider]),\n);\n\n/**\n * Get an OAuth provider by ID\n */\nexport function getOAuthProvider(id: OAuthProviderId): OAuthProviderInterface | undefined {\n\treturn oauthProviderRegistry.get(id);\n}\n\n/**\n * Register a custom OAuth provider\n */\nexport function registerOAuthProvider(provider: OAuthProviderInterface): void {\n\toauthProviderRegistry.set(provider.id, provider);\n}\n\n/**\n * Unregister an OAuth provider.\n *\n * If the provider is built-in, restores the built-in implementation.\n * Custom providers are removed completely.\n */\nexport function unregisterOAuthProvider(id: string): void {\n\tconst builtInProvider = BUILT_IN_OAUTH_PROVIDERS.find((provider) => provider.id === id);\n\tif (builtInProvider) {\n\t\toauthProviderRegistry.set(id, builtInProvider);\n\t\treturn;\n\t}\n\toauthProviderRegistry.delete(id);\n}\n\n/**\n * Reset OAuth providers to built-ins.\n */\nexport function resetOAuthProviders(): void {\n\toauthProviderRegistry.clear();\n\tfor (const provider of BUILT_IN_OAUTH_PROVIDERS) {\n\t\toauthProviderRegistry.set(provider.id, provider);\n\t}\n}\n\n/**\n * Get all registered OAuth providers\n */\nexport function getOAuthProviders(): OAuthProviderInterface[] {\n\treturn Array.from(oauthProviderRegistry.values());\n}\n\n// ============================================================================\n// High-level API (uses provider registry)\n// ============================================================================\n\n/**\n * Get API key for a provider from OAuth credentials.\n * Automatically refreshes expired tokens.\n *\n * @returns API key string and updated credentials, or null if no credentials\n * @throws Error if refresh fails\n */\nexport async function getOAuthApiKey(\n\tproviderId: OAuthProviderId,\n\tcredentials: Record<string, OAuthCredentials>,\n): Promise<{ newCredentials: OAuthCredentials; apiKey: string } | null> {\n\tconst provider = getOAuthProvider(providerId);\n\tif (!provider) {\n\t\tthrow new Error(`Unknown OAuth provider: ${providerId}`);\n\t}\n\n\tlet creds = credentials[providerId];\n\tif (!creds) {\n\t\treturn null;\n\t}\n\n\t// Refresh if expired\n\tif (Date.now() >= creds.expires) {\n\t\ttry {\n\t\t\tcreds = await provider.refreshToken(creds);\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Failed to refresh OAuth token for ${providerId}`, { cause: error });\n\t\t}\n\t}\n\n\tconst apiKey = provider.getApiKey(creds);\n\treturn { newCredentials: creds, apiKey };\n}\n"]}
@@ -34,6 +34,9 @@ async function getAnthropicClass(): Promise<typeof Anthropic> {
34
34
  return _AnthropicClass;
35
35
  }
36
36
 
37
+ // Stealth mode: Mimic Claude Code's tool naming exactly
38
+ const claudeCodeVersion = "2.1.62";
39
+
37
40
  function mergeHeaders(...headerSources: (Record<string, string> | undefined)[]): Record<string, string> {
38
41
  const merged: Record<string, string> = {};
39
42
  for (const headers of headerSources) {
@@ -44,6 +47,10 @@ function mergeHeaders(...headerSources: (Record<string, string> | undefined)[]):
44
47
  return merged;
45
48
  }
46
49
 
50
+ function isOAuthToken(apiKey: string): boolean {
51
+ return apiKey.includes("sk-ant-oat");
52
+ }
53
+
47
54
  async function createClient(
48
55
  model: Model<"anthropic-messages">,
49
56
  apiKey: string,
@@ -90,7 +97,30 @@ async function createClient(
90
97
  betaFeatures.push("interleaved-thinking-2025-05-14");
91
98
  }
92
99
 
93
- // API key auth (Anthropic OAuth removed per TOS compliance — use API keys or Claude CLI)
100
+ // OAuth: Bearer auth, Claude Code identity headers
101
+ if (isOAuthToken(apiKey)) {
102
+ const client = new AnthropicClass({
103
+ apiKey: null,
104
+ authToken: apiKey,
105
+ baseURL: model.baseUrl,
106
+ dangerouslyAllowBrowser: true,
107
+ defaultHeaders: mergeHeaders(
108
+ {
109
+ accept: "application/json",
110
+ "anthropic-dangerous-direct-browser-access": "true",
111
+ ...(betaFeatures.length > 0 ? { "anthropic-beta": `claude-code-20250219,oauth-2025-04-20,${betaFeatures.join(",")}` } : {}),
112
+ "user-agent": `claude-cli/${claudeCodeVersion}`,
113
+ "x-app": "cli",
114
+ },
115
+ model.headers,
116
+ optionsHeaders,
117
+ ),
118
+ });
119
+
120
+ return { client, isOAuthToken: true };
121
+ }
122
+
123
+ // API key auth
94
124
  // Alibaba Coding Plan uses Bearer token auth instead of x-api-key
95
125
  const isAlibabaProvider = model.provider === "alibaba-coding-plan";
96
126
  const client = new AnthropicClass({
@@ -0,0 +1,140 @@
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
+ };
@@ -3,14 +3,14 @@
3
3
  *
4
4
  * This module handles login, token refresh, and credential storage
5
5
  * for OAuth-based providers:
6
+ * - Anthropic (Claude Pro/Max)
6
7
  * - GitHub Copilot
7
8
  * - Google Cloud Code Assist (Gemini CLI)
8
9
  * - Antigravity (Gemini 3, Claude, GPT-OSS via Google Cloud)
9
- *
10
- * Note: Anthropic OAuth was removed per TOS compliance (see docs/user-docs/claude-code-auth-compliance.md).
11
- * Use API keys or the local Claude Code CLI for Anthropic access.
12
10
  */
13
11
 
12
+ // Anthropic
13
+ export { anthropicOAuthProvider, loginAnthropic, refreshAnthropicToken } from "./anthropic.js";
14
14
  // GitHub Copilot
15
15
  export {
16
16
  getGitHubCopilotBaseUrl,
@@ -32,6 +32,7 @@ export * from "./types.js";
32
32
  // Provider Registry
33
33
  // ============================================================================
34
34
 
35
+ import { anthropicOAuthProvider } from "./anthropic.js";
35
36
  import { githubCopilotOAuthProvider } from "./github-copilot.js";
36
37
  import { antigravityOAuthProvider } from "./google-antigravity.js";
37
38
  import { geminiCliOAuthProvider } from "./google-gemini-cli.js";
@@ -39,6 +40,7 @@ import { openaiCodexOAuthProvider } from "./openai-codex.js";
39
40
  import type { OAuthCredentials, OAuthProviderId, OAuthProviderInterface } from "./types.js";
40
41
 
41
42
  const BUILT_IN_OAUTH_PROVIDERS: OAuthProviderInterface[] = [
43
+ anthropicOAuthProvider,
42
44
  githubCopilotOAuthProvider,
43
45
  geminiCliOAuthProvider,
44
46
  antigravityOAuthProvider,
@@ -19,7 +19,6 @@ import { deriveState } from "../state.js";
19
19
  import { formatOverridesSection, formatShortcut, loadActiveOverrides, loadFile, parseContinue, parseSummary } from "../files.js";
20
20
  import { toPosixPath } from "../../shared/mod.js";
21
21
  import { markCmuxPromptShown, shouldPromptToEnableCmux } from "../../cmux/index.js";
22
- import { autoEnableCmuxPreferences } from "../commands-cmux.js";
23
22
 
24
23
  const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
25
24
 
@@ -77,16 +76,13 @@ export async function buildBeforeAgentStartResult(
77
76
  shortcutDashboard: formatShortcut("Ctrl+Alt+G"),
78
77
  shortcutShell: formatShortcut("Ctrl+Alt+B"),
79
78
  });
80
- let loadedPreferences = loadEffectiveGSDPreferences();
79
+ const loadedPreferences = loadEffectiveGSDPreferences();
81
80
  if (shouldPromptToEnableCmux(loadedPreferences?.preferences)) {
82
81
  markCmuxPromptShown();
83
- if (autoEnableCmuxPreferences()) {
84
- loadedPreferences = loadEffectiveGSDPreferences();
85
- ctx.ui.notify(
86
- "cmux detected — auto-enabled. Run /gsd cmux off to disable.",
87
- "info",
88
- );
89
- }
82
+ ctx.ui.notify(
83
+ "cmux detected. Run /gsd cmux on to enable sidebar metadata, notifications, and visual subagent splits for this project.",
84
+ "info",
85
+ );
90
86
  }
91
87
 
92
88
  let preferenceBlock = "";
@@ -1,5 +1,5 @@
1
1
  import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
2
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { existsSync, readFileSync } from "node:fs";
3
3
  import { clearCmuxSidebar, CmuxClient, detectCmuxEnvironment, resolveCmuxConfig } from "../cmux/index.js";
4
4
  import { saveFile } from "./files.js";
5
5
  import {
@@ -9,37 +9,6 @@ import {
9
9
  } from "./preferences.js";
10
10
  import { ensurePreferencesFile, serializePreferencesToFrontmatter } from "./commands-prefs-wizard.js";
11
11
 
12
- /**
13
- * Auto-enable cmux in project preferences when detected but never configured.
14
- * Called at boot (before agent start) — no ExtensionCommandContext needed.
15
- * Returns true if preferences were written, false if skipped.
16
- */
17
- export function autoEnableCmuxPreferences(): boolean {
18
- const path = getProjectGSDPreferencesPath();
19
- if (!existsSync(path)) return false;
20
-
21
- const existing = loadProjectGSDPreferences();
22
- const prefs: Record<string, unknown> = existing?.preferences ? { ...existing.preferences } : { version: 1 };
23
- prefs.cmux = {
24
- enabled: true,
25
- notifications: true,
26
- sidebar: true,
27
- splits: false,
28
- browser: false,
29
- ...((prefs.cmux as Record<string, unknown> | undefined) ?? {}),
30
- };
31
- (prefs.cmux as Record<string, unknown>).enabled = true;
32
- prefs.version = prefs.version || 1;
33
-
34
- const frontmatter = serializePreferencesToFrontmatter(prefs);
35
- let body = "\n# GSD Skill Preferences\n\nSee `~/.gsd/agent/extensions/gsd/docs/preferences-reference.md` for full field documentation and examples.\n";
36
- const preserved = extractBodyAfterFrontmatter(readFileSync(path, "utf-8"));
37
- if (preserved) body = preserved;
38
-
39
- writeFileSync(path, `---\n${frontmatter}---${body}`, "utf-8");
40
- return true;
41
- }
42
-
43
12
  function extractBodyAfterFrontmatter(content: string): string | null {
44
13
  const start = content.startsWith("---\n") ? 4 : content.startsWith("---\r\n") ? 5 : -1;
45
14
  if (start === -1) return null;
@@ -1,8 +1,7 @@
1
- import test, { describe, beforeEach, afterEach } from "node:test";
1
+ import test, { describe } from "node:test";
2
2
  import assert from "node:assert/strict";
3
3
  import * as fs from "node:fs";
4
4
  import * as path from "node:path";
5
- import { tmpdir } from "node:os";
6
5
  import { fileURLToPath } from "node:url";
7
6
  import {
8
7
  buildCmuxProgress,
@@ -13,7 +12,6 @@ import {
13
12
  resolveCmuxConfig,
14
13
  shouldPromptToEnableCmux,
15
14
  } from "../../cmux/index.ts";
16
- import { autoEnableCmuxPreferences } from "../commands-cmux.ts";
17
15
  import type { GSDState } from "../types.ts";
18
16
 
19
17
  test("detectCmuxEnvironment requires workspace, surface, and socket", () => {
@@ -81,70 +79,6 @@ test("shouldPromptToEnableCmux only prompts once per session", () => {
81
79
  resetCmuxPromptState();
82
80
  });
83
81
 
84
- describe("autoEnableCmuxPreferences", () => {
85
- let tmp: string;
86
- let originalCwd: string;
87
-
88
- beforeEach(() => {
89
- originalCwd = process.cwd();
90
- tmp = fs.mkdtempSync(path.join(tmpdir(), "cmux-auto-test-"));
91
- fs.mkdirSync(path.join(tmp, ".gsd"), { recursive: true });
92
- process.chdir(tmp);
93
- });
94
-
95
- afterEach(() => {
96
- process.chdir(originalCwd);
97
- fs.rmSync(tmp, { recursive: true, force: true });
98
- });
99
-
100
- test("writes cmux.enabled true when preferences file exists with no cmux config", () => {
101
- const prefsPath = path.join(tmp, ".gsd", "preferences.md");
102
- fs.writeFileSync(prefsPath, [
103
- "---",
104
- "version: 1",
105
- "---",
106
- "",
107
- "# GSD Skill Preferences",
108
- ].join("\n"));
109
-
110
- const result = autoEnableCmuxPreferences();
111
- assert.equal(result, true);
112
-
113
- const content = fs.readFileSync(prefsPath, "utf-8");
114
- assert.ok(content.includes("enabled: true"), "should write enabled: true");
115
- assert.ok(content.includes("notifications: true"), "should default notifications on");
116
- assert.ok(content.includes("sidebar: true"), "should default sidebar on");
117
- assert.ok(content.includes("splits: false"), "should default splits off");
118
- });
119
-
120
- test("returns false when preferences file does not exist", () => {
121
- const result = autoEnableCmuxPreferences();
122
- assert.equal(result, false);
123
- });
124
-
125
- test("preserves existing cmux sub-preferences when auto-enabling", () => {
126
- const prefsPath = path.join(tmp, ".gsd", "preferences.md");
127
- fs.writeFileSync(prefsPath, [
128
- "---",
129
- "version: 1",
130
- "cmux:",
131
- " splits: true",
132
- " browser: true",
133
- "---",
134
- "",
135
- "# GSD Skill Preferences",
136
- ].join("\n"));
137
-
138
- const result = autoEnableCmuxPreferences();
139
- assert.equal(result, true);
140
-
141
- const content = fs.readFileSync(prefsPath, "utf-8");
142
- assert.ok(content.includes("enabled: true"), "should set enabled: true");
143
- assert.ok(content.includes("splits: true"), "should preserve existing splits: true");
144
- assert.ok(content.includes("browser: true"), "should preserve existing browser: true");
145
- });
146
- });
147
-
148
82
  test("buildCmuxStatusLabel and progress prefer deepest active unit", () => {
149
83
  const state: GSDState = {
150
84
  activeMilestone: { id: "M001", title: "Milestone" },
@@ -26,12 +26,8 @@ test("ensureProjectWorkflowMcpConfig creates .mcp.json with the workflow server"
26
26
  assert.equal(typeof server?.command, "string");
27
27
  assert.equal(Array.isArray(server?.args), true);
28
28
  assert.equal(server?.env?.GSD_WORKFLOW_PROJECT_ROOT, projectRoot);
29
- assert.match(server?.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "", /workflow-tool-executors\.(js|ts)$/);
30
- assert.match(server?.env?.GSD_WORKFLOW_WRITE_GATE_MODULE ?? "", /write-gate\.(js|ts)$/);
31
- if ((server?.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "").endsWith(".ts")) {
32
- assert.match(server?.env?.NODE_OPTIONS ?? "", /--experimental-strip-types/);
33
- assert.match(server?.env?.NODE_OPTIONS ?? "", /resolve-ts\.mjs/);
34
- }
29
+ assert.match(server?.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "", /workflow-tool-executors\.js$/);
30
+ assert.match(server?.env?.GSD_WORKFLOW_WRITE_GATE_MODULE ?? "", /write-gate\.js$/);
35
31
  } finally {
36
32
  rmSync(projectRoot, { recursive: true, force: true });
37
33
  }
@@ -141,11 +141,7 @@ test("detectWorkflowMcpLaunchConfig resolves the bundled server relative to the
141
141
  assert.match(launch?.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "", /workflow-tool-executors\.(js|ts)$/);
142
142
  assert.match(launch?.env?.GSD_WORKFLOW_WRITE_GATE_MODULE ?? "", /write-gate\.(js|ts)$/);
143
143
  assert.equal(typeof launch?.args?.[0], "string");
144
- assert.match(launch?.args?.[0] ?? "", /packages[\/\\]mcp-server[\/\\](dist[\/\\]cli\.js|src[\/\\]cli\.ts)$/);
145
- if ((launch?.args?.[0] ?? "").endsWith(".ts")) {
146
- assert.match(launch?.env?.NODE_OPTIONS ?? "", /--experimental-strip-types/);
147
- assert.match(launch?.env?.NODE_OPTIONS ?? "", /resolve-ts\.mjs/);
148
- }
144
+ assert.match(launch?.args?.[0] ?? "", /packages[\/\\]mcp-server[\/\\]dist[\/\\]cli\.js$/);
149
145
  });
150
146
 
151
147
  test("detectWorkflowMcpLaunchConfig resolves the bundled server relative to the package without env hints", () => {
@@ -158,11 +154,7 @@ test("detectWorkflowMcpLaunchConfig resolves the bundled server relative to the
158
154
  assert.match(launch?.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "", /workflow-tool-executors\.(js|ts)$/);
159
155
  assert.match(launch?.env?.GSD_WORKFLOW_WRITE_GATE_MODULE ?? "", /write-gate\.(js|ts)$/);
160
156
  assert.equal(typeof launch?.args?.[0], "string");
161
- assert.match(launch?.args?.[0] ?? "", /packages[\/\\]mcp-server[\/\\](dist[\/\\]cli\.js|src[\/\\]cli\.ts)$/);
162
- if ((launch?.args?.[0] ?? "").endsWith(".ts")) {
163
- assert.match(launch?.env?.NODE_OPTIONS ?? "", /--experimental-strip-types/);
164
- assert.match(launch?.env?.NODE_OPTIONS ?? "", /resolve-ts\.mjs/);
165
- }
157
+ assert.match(launch?.args?.[0] ?? "", /packages[\/\\]mcp-server[\/\\]dist[\/\\]cli\.js$/);
166
158
  });
167
159
 
168
160
  test("workflow MCP launch config reaches mutation tools over stdio", async () => {
@@ -173,16 +165,12 @@ test("workflow MCP launch config reaches mutation tools over stdio", async () =>
173
165
  assert.ok(launch, "expected a workflow MCP launch config");
174
166
  assert.match(
175
167
  launch.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "",
176
- /(dist[\/\\]resources[\/\\]extensions[\/\\]gsd[\/\\]tools[\/\\]workflow-tool-executors\.js|src[\/\\]resources[\/\\]extensions[\/\\]gsd[\/\\]tools[\/\\]workflow-tool-executors\.(js|ts))$/,
168
+ /dist[\/\\]resources[\/\\]extensions[\/\\]gsd[\/\\]tools[\/\\]workflow-tool-executors\.js$/,
177
169
  );
178
170
  assert.match(
179
171
  launch.env?.GSD_WORKFLOW_WRITE_GATE_MODULE ?? "",
180
- /(dist[\/\\]resources[\/\\]extensions[\/\\]gsd[\/\\]bootstrap[\/\\]write-gate\.js|src[\/\\]resources[\/\\]extensions[\/\\]gsd[\/\\]bootstrap[\/\\]write-gate\.(js|ts))$/,
172
+ /dist[\/\\]resources[\/\\]extensions[\/\\]gsd[\/\\]bootstrap[\/\\]write-gate\.js$/,
181
173
  );
182
- if ((launch.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "").endsWith(".ts")) {
183
- assert.match(launch.env?.NODE_OPTIONS ?? "", /--experimental-strip-types/);
184
- assert.match(launch.env?.NODE_OPTIONS ?? "", /resolve-ts\.mjs/);
185
- }
186
174
 
187
175
  const client = new Client({ name: "workflow-mcp-transport-test", version: "1.0.0" });
188
176
  const transport = new StdioClientTransport({
@@ -201,10 +189,6 @@ test("workflow MCP launch config reaches mutation tools over stdio", async () =>
201
189
  (tools.tools ?? []).some((tool) => tool.name === "gsd_plan_slice"),
202
190
  "expected workflow MCP surface to expose gsd_plan_slice",
203
191
  );
204
- assert.ok(
205
- (tools.tools ?? []).some((tool) => tool.name === "ask_user_questions"),
206
- "expected workflow MCP surface to expose ask_user_questions",
207
- );
208
192
 
209
193
  const milestoneResult = await client.callTool(
210
194
  {
@@ -481,18 +465,18 @@ test("transport compatibility now allows replan-slice over workflow MCP surface"
481
465
  test("transport compatibility still blocks units whose MCP tools are not exposed", () => {
482
466
  const error = getWorkflowTransportSupportError(
483
467
  "claude-code",
484
- ["secure_env_collect"],
468
+ ["gsd_skip_slice"],
485
469
  {
486
470
  projectRoot: "/tmp/project",
487
471
  env: { GSD_WORKFLOW_MCP_COMMAND: "node" },
488
472
  surface: "auto-mode",
489
- unitType: "guided-discussion",
473
+ unitType: "skip-slice",
490
474
  authMode: "externalCli",
491
475
  baseUrl: "local://claude-code",
492
476
  },
493
477
  );
494
478
 
495
- assert.match(error ?? "", /requires secure_env_collect/);
479
+ assert.match(error ?? "", /requires gsd_skip_slice/);
496
480
  assert.match(error ?? "", /currently exposes only/);
497
481
  });
498
482