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
@@ -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, pathToFileURL } from "node:url";
4
+ import { fileURLToPath } from "node:url";
5
5
 
6
6
  export interface WorkflowMcpLaunchConfig {
7
7
  name: string;
@@ -21,35 +21,22 @@ export interface WorkflowCapabilityOptions {
21
21
  }
22
22
 
23
23
  const MCP_WORKFLOW_TOOL_SURFACE = new Set([
24
- "ask_user_questions",
25
- "gsd_decision_save",
26
24
  "gsd_complete_milestone",
27
25
  "gsd_complete_task",
28
26
  "gsd_complete_slice",
29
- "gsd_generate_milestone_id",
30
- "gsd_journal_query",
31
27
  "gsd_milestone_complete",
32
- "gsd_milestone_generate_id",
33
28
  "gsd_milestone_status",
34
29
  "gsd_milestone_validate",
35
- "gsd_plan_task",
36
30
  "gsd_plan_milestone",
37
31
  "gsd_plan_slice",
38
32
  "gsd_replan_slice",
39
33
  "gsd_reassess_roadmap",
40
- "gsd_requirement_save",
41
- "gsd_requirement_update",
42
34
  "gsd_roadmap_reassess",
43
- "gsd_save_decision",
44
35
  "gsd_save_gate_result",
45
- "gsd_save_requirement",
46
- "gsd_skip_slice",
47
36
  "gsd_slice_replan",
48
37
  "gsd_slice_complete",
49
38
  "gsd_summary_save",
50
- "gsd_task_plan",
51
39
  "gsd_task_complete",
52
- "gsd_update_requirement",
53
40
  "gsd_validate_milestone",
54
41
  ]);
55
42
 
@@ -108,8 +95,6 @@ function getBundledWorkflowMcpCliPath(env: NodeJS.ProcessEnv): string | null {
108
95
  }
109
96
 
110
97
  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))),
113
98
  resolve(fileURLToPath(new URL("../../../../packages/mcp-server/dist/cli.js", import.meta.url))),
114
99
  resolve(fileURLToPath(new URL("../../../../../packages/mcp-server/dist/cli.js", import.meta.url))),
115
100
  ];
@@ -123,9 +108,9 @@ function getBundledWorkflowMcpCliPath(env: NodeJS.ProcessEnv): string | null {
123
108
 
124
109
  function getBundledWorkflowExecutorModulePath(): string | null {
125
110
  const candidates = [
111
+ resolve(fileURLToPath(new URL("../../../../dist/resources/extensions/gsd/tools/workflow-tool-executors.js", import.meta.url))),
126
112
  resolve(fileURLToPath(new URL("./tools/workflow-tool-executors.js", import.meta.url))),
127
113
  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))),
129
114
  ];
130
115
 
131
116
  for (const candidate of candidates) {
@@ -137,9 +122,9 @@ function getBundledWorkflowExecutorModulePath(): string | null {
137
122
 
138
123
  function getBundledWorkflowWriteGateModulePath(): string | null {
139
124
  const candidates = [
125
+ resolve(fileURLToPath(new URL("../../../../dist/resources/extensions/gsd/bootstrap/write-gate.js", import.meta.url))),
140
126
  resolve(fileURLToPath(new URL("./bootstrap/write-gate.js", import.meta.url))),
141
127
  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
128
  ];
144
129
 
145
130
  for (const candidate of candidates) {
@@ -149,58 +134,19 @@ function getBundledWorkflowWriteGateModulePath(): string | null {
149
134
  return null;
150
135
  }
151
136
 
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))),
156
- ];
157
-
158
- for (const candidate of candidates) {
159
- if (existsSync(candidate)) return candidate;
160
- }
161
-
162
- return null;
163
- }
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
-
175
137
  function buildWorkflowLaunchEnv(
176
138
  projectRoot: string,
177
139
  gsdCliPath: string | undefined,
178
140
  explicitEnv?: Record<string, string>,
179
- workflowCliPath?: string,
180
141
  ): Record<string, string> {
181
142
  const executorModulePath = getBundledWorkflowExecutorModulePath();
182
143
  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;
197
144
 
198
145
  return {
199
146
  ...(explicitEnv ?? {}),
200
147
  ...(gsdCliPath ? { GSD_CLI_PATH: gsdCliPath } : {}),
201
148
  ...(executorModulePath ? { GSD_WORKFLOW_EXECUTORS_MODULE: executorModulePath } : {}),
202
149
  ...(writeGateModulePath ? { GSD_WORKFLOW_WRITE_GATE_MODULE: writeGateModulePath } : {}),
203
- ...(nodeOptions ? { NODE_OPTIONS: nodeOptions } : {}),
204
150
  GSD_PERSIST_WRITE_GATE_STATE: "1",
205
151
  GSD_WORKFLOW_PROJECT_ROOT: projectRoot,
206
152
  };
@@ -242,7 +188,7 @@ export function detectWorkflowMcpLaunchConfig(
242
188
  command: process.execPath,
243
189
  args: [distCli],
244
190
  cwd: resolvedWorkflowProjectRoot,
245
- env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath, undefined, distCli),
191
+ env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath),
246
192
  };
247
193
  }
248
194
 
@@ -253,7 +199,7 @@ export function detectWorkflowMcpLaunchConfig(
253
199
  command: process.execPath,
254
200
  args: [bundledCli],
255
201
  cwd: resolvedWorkflowProjectRoot,
256
- env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath, undefined, bundledCli),
202
+ env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath),
257
203
  };
258
204
  }
259
205
 
@@ -1,6 +0,0 @@
1
- export declare function resolveAuthPath(env?: NodeJS.ProcessEnv): string;
2
- export declare function loadStoredCredentialEnvKeys(options?: {
3
- env?: NodeJS.ProcessEnv;
4
- authPath?: string;
5
- }): string[];
6
- //# sourceMappingURL=tool-credentials.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-credentials.d.ts","sourceRoot":"","sources":["../src/tool-credentials.ts"],"names":[],"mappings":"AA8DA,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAI5E;AAED,wBAAgB,2BAA2B,CAAC,OAAO,GAAE;IACnD,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,MAAM,EAAE,CAyBhB"}
@@ -1,90 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { homedir } from "node:os";
3
- import { join } from "node:path";
4
- const AUTH_ENV_KEYS = [
5
- ["anthropic", "ANTHROPIC_API_KEY"],
6
- ["openai", "OPENAI_API_KEY"],
7
- ["github-copilot", "GITHUB_TOKEN"],
8
- ["google", "GEMINI_API_KEY"],
9
- ["groq", "GROQ_API_KEY"],
10
- ["xai", "XAI_API_KEY"],
11
- ["openrouter", "OPENROUTER_API_KEY"],
12
- ["mistral", "MISTRAL_API_KEY"],
13
- ["ollama-cloud", "OLLAMA_API_KEY"],
14
- ["custom-openai", "CUSTOM_OPENAI_API_KEY"],
15
- ["cerebras", "CEREBRAS_API_KEY"],
16
- ["azure-openai-responses", "AZURE_OPENAI_API_KEY"],
17
- ["vercel-ai-gateway", "AI_GATEWAY_API_KEY"],
18
- ["zai", "ZAI_API_KEY"],
19
- ["minimax", "MINIMAX_API_KEY"],
20
- ["minimax-cn", "MINIMAX_CN_API_KEY"],
21
- ["huggingface", "HF_TOKEN"],
22
- ["opencode", "OPENCODE_API_KEY"],
23
- ["opencode-go", "OPENCODE_API_KEY"],
24
- ["kimi-coding", "KIMI_API_KEY"],
25
- ["alibaba-coding-plan", "ALIBABA_API_KEY"],
26
- ["brave", "BRAVE_API_KEY"],
27
- ["brave_answers", "BRAVE_ANSWERS_KEY"],
28
- ["context7", "CONTEXT7_API_KEY"],
29
- ["jina", "JINA_API_KEY"],
30
- ["tavily", "TAVILY_API_KEY"],
31
- ["slack_bot", "SLACK_BOT_TOKEN"],
32
- ["discord_bot", "DISCORD_BOT_TOKEN"],
33
- ["telegram_bot", "TELEGRAM_BOT_TOKEN"],
34
- ];
35
- function expandHome(pathValue) {
36
- if (pathValue === "~")
37
- return homedir();
38
- if (pathValue.startsWith("~/"))
39
- return join(homedir(), pathValue.slice(2));
40
- return pathValue;
41
- }
42
- function getStoredApiKey(data, providerId) {
43
- const raw = data[providerId];
44
- const credentials = Array.isArray(raw) ? raw : raw ? [raw] : [];
45
- for (const credential of credentials) {
46
- if (credential?.type !== "api_key")
47
- continue;
48
- if (typeof credential.key !== "string")
49
- continue;
50
- if (credential.key.trim().length === 0)
51
- continue;
52
- return credential.key;
53
- }
54
- return undefined;
55
- }
56
- export function resolveAuthPath(env = process.env) {
57
- const agentDir = env.GSD_CODING_AGENT_DIR?.trim();
58
- if (agentDir)
59
- return join(expandHome(agentDir), "auth.json");
60
- return join(homedir(), ".gsd", "agent", "auth.json");
61
- }
62
- export function loadStoredCredentialEnvKeys(options = {}) {
63
- const env = options.env ?? process.env;
64
- const authPath = options.authPath ?? resolveAuthPath(env);
65
- if (!existsSync(authPath))
66
- return [];
67
- let parsed;
68
- try {
69
- const raw = readFileSync(authPath, "utf-8");
70
- const data = JSON.parse(raw);
71
- if (!data || typeof data !== "object" || Array.isArray(data))
72
- return [];
73
- parsed = data;
74
- }
75
- catch {
76
- return [];
77
- }
78
- const loaded = [];
79
- for (const [providerId, envVar] of AUTH_ENV_KEYS) {
80
- if (env[envVar])
81
- continue;
82
- const key = getStoredApiKey(parsed, providerId);
83
- if (!key)
84
- continue;
85
- env[envVar] = key;
86
- loaded.push(envVar);
87
- }
88
- return loaded;
89
- }
90
- //# sourceMappingURL=tool-credentials.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-credentials.js","sourceRoot":"","sources":["../src/tool-credentials.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\ntype AuthCredential =\n | { type?: unknown; key?: unknown }\n | Array<{ type?: unknown; key?: unknown }>;\n\ntype AuthStorageData = Record<string, AuthCredential>;\n\nconst AUTH_ENV_KEYS = [\n [\"anthropic\", \"ANTHROPIC_API_KEY\"],\n [\"openai\", \"OPENAI_API_KEY\"],\n [\"github-copilot\", \"GITHUB_TOKEN\"],\n [\"google\", \"GEMINI_API_KEY\"],\n [\"groq\", \"GROQ_API_KEY\"],\n [\"xai\", \"XAI_API_KEY\"],\n [\"openrouter\", \"OPENROUTER_API_KEY\"],\n [\"mistral\", \"MISTRAL_API_KEY\"],\n [\"ollama-cloud\", \"OLLAMA_API_KEY\"],\n [\"custom-openai\", \"CUSTOM_OPENAI_API_KEY\"],\n [\"cerebras\", \"CEREBRAS_API_KEY\"],\n [\"azure-openai-responses\", \"AZURE_OPENAI_API_KEY\"],\n [\"vercel-ai-gateway\", \"AI_GATEWAY_API_KEY\"],\n [\"zai\", \"ZAI_API_KEY\"],\n [\"minimax\", \"MINIMAX_API_KEY\"],\n [\"minimax-cn\", \"MINIMAX_CN_API_KEY\"],\n [\"huggingface\", \"HF_TOKEN\"],\n [\"opencode\", \"OPENCODE_API_KEY\"],\n [\"opencode-go\", \"OPENCODE_API_KEY\"],\n [\"kimi-coding\", \"KIMI_API_KEY\"],\n [\"alibaba-coding-plan\", \"ALIBABA_API_KEY\"],\n [\"brave\", \"BRAVE_API_KEY\"],\n [\"brave_answers\", \"BRAVE_ANSWERS_KEY\"],\n [\"context7\", \"CONTEXT7_API_KEY\"],\n [\"jina\", \"JINA_API_KEY\"],\n [\"tavily\", \"TAVILY_API_KEY\"],\n [\"slack_bot\", \"SLACK_BOT_TOKEN\"],\n [\"discord_bot\", \"DISCORD_BOT_TOKEN\"],\n [\"telegram_bot\", \"TELEGRAM_BOT_TOKEN\"],\n] as const;\n\nfunction expandHome(pathValue: string): string {\n if (pathValue === \"~\") return homedir();\n if (pathValue.startsWith(\"~/\")) return join(homedir(), pathValue.slice(2));\n return pathValue;\n}\n\nfunction getStoredApiKey(data: AuthStorageData, providerId: string): string | undefined {\n const raw = data[providerId];\n const credentials = Array.isArray(raw) ? raw : raw ? [raw] : [];\n\n for (const credential of credentials) {\n if (credential?.type !== \"api_key\") continue;\n if (typeof credential.key !== \"string\") continue;\n if (credential.key.trim().length === 0) continue;\n return credential.key;\n }\n\n return undefined;\n}\n\nexport function resolveAuthPath(env: NodeJS.ProcessEnv = process.env): string {\n const agentDir = env.GSD_CODING_AGENT_DIR?.trim();\n if (agentDir) return join(expandHome(agentDir), \"auth.json\");\n return join(homedir(), \".gsd\", \"agent\", \"auth.json\");\n}\n\nexport function loadStoredCredentialEnvKeys(options: {\n env?: NodeJS.ProcessEnv;\n authPath?: string;\n} = {}): string[] {\n const env = options.env ?? process.env;\n const authPath = options.authPath ?? resolveAuthPath(env);\n if (!existsSync(authPath)) return [];\n\n let parsed: AuthStorageData;\n try {\n const raw = readFileSync(authPath, \"utf-8\");\n const data = JSON.parse(raw) as unknown;\n if (!data || typeof data !== \"object\" || Array.isArray(data)) return [];\n parsed = data as AuthStorageData;\n } catch {\n return [];\n }\n\n const loaded: string[] = [];\n for (const [providerId, envVar] of AUTH_ENV_KEYS) {\n if (env[envVar]) continue;\n const key = getStoredApiKey(parsed, providerId);\n if (!key) continue;\n env[envVar] = key;\n loaded.push(envVar);\n }\n\n return loaded;\n}\n"]}
@@ -1,95 +0,0 @@
1
- import { describe, it } from "node:test";
2
- import assert from "node:assert/strict";
3
- import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
4
- import { tmpdir } from "node:os";
5
- import { join } from "node:path";
6
-
7
- import { loadStoredCredentialEnvKeys, resolveAuthPath } from "./tool-credentials.js";
8
-
9
- describe("tool credentials", () => {
10
- it("hydrates supported model and tool keys from auth.json", () => {
11
- const tempRoot = mkdtempSync(join(tmpdir(), "gsd-mcp-auth-"));
12
- const authPath = join(tempRoot, "auth.json");
13
- const env: NodeJS.ProcessEnv = {};
14
-
15
- try {
16
- writeFileSync(authPath, JSON.stringify({
17
- anthropic: { type: "api_key", key: "sk-ant-secret" },
18
- openai: { type: "api_key", key: "sk-openai-secret" },
19
- tavily: { type: "api_key", key: "tvly-secret" },
20
- context7: [{ type: "api_key", key: "ctx7-secret" }],
21
- }));
22
-
23
- const loaded = loadStoredCredentialEnvKeys({ authPath, env });
24
- assert.deepEqual(loaded.sort(), [
25
- "ANTHROPIC_API_KEY",
26
- "CONTEXT7_API_KEY",
27
- "OPENAI_API_KEY",
28
- "TAVILY_API_KEY",
29
- ]);
30
- assert.equal(env.ANTHROPIC_API_KEY, "sk-ant-secret");
31
- assert.equal(env.OPENAI_API_KEY, "sk-openai-secret");
32
- assert.equal(env.TAVILY_API_KEY, "tvly-secret");
33
- assert.equal(env.CONTEXT7_API_KEY, "ctx7-secret");
34
- } finally {
35
- rmSync(tempRoot, { recursive: true, force: true });
36
- }
37
- });
38
-
39
- it("does not overwrite explicit environment variables", () => {
40
- const tempRoot = mkdtempSync(join(tmpdir(), "gsd-mcp-auth-"));
41
- const authPath = join(tempRoot, "auth.json");
42
- const env: NodeJS.ProcessEnv = {
43
- BRAVE_API_KEY: "already-set",
44
- };
45
-
46
- try {
47
- writeFileSync(authPath, JSON.stringify({
48
- brave: { type: "api_key", key: "from-auth-json" },
49
- anthropic: { type: "api_key", key: "sk-ant-from-auth-json" },
50
- }));
51
-
52
- const loaded = loadStoredCredentialEnvKeys({ authPath, env });
53
- assert.deepEqual(loaded, ["ANTHROPIC_API_KEY"]);
54
- assert.equal(env.BRAVE_API_KEY, "already-set");
55
- assert.equal(env.ANTHROPIC_API_KEY, "sk-ant-from-auth-json");
56
- } finally {
57
- rmSync(tempRoot, { recursive: true, force: true });
58
- }
59
- });
60
-
61
- it("ignores oauth credentials because they are resolved through auth storage, not env hydration", () => {
62
- const tempRoot = mkdtempSync(join(tmpdir(), "gsd-mcp-auth-"));
63
- const authPath = join(tempRoot, "auth.json");
64
- const env: NodeJS.ProcessEnv = {};
65
-
66
- try {
67
- writeFileSync(authPath, JSON.stringify({
68
- openai: { type: "oauth", access: "oauth-access-token" },
69
- "google-gemini-cli": { type: "oauth", token: "ya29.oauth-token" },
70
- }));
71
-
72
- const loaded = loadStoredCredentialEnvKeys({ authPath, env });
73
- assert.deepEqual(loaded, []);
74
- assert.equal(env.OPENAI_API_KEY, undefined);
75
- assert.equal(env.GEMINI_API_KEY, undefined);
76
- } finally {
77
- rmSync(tempRoot, { recursive: true, force: true });
78
- }
79
- });
80
-
81
- it("resolves auth.json from GSD_CODING_AGENT_DIR", () => {
82
- const tempRoot = mkdtempSync(join(tmpdir(), "gsd-mcp-agent-dir-"));
83
- const agentDir = join(tempRoot, "agent");
84
- mkdirSync(agentDir, { recursive: true });
85
-
86
- try {
87
- assert.equal(
88
- resolveAuthPath({ GSD_CODING_AGENT_DIR: agentDir }),
89
- join(agentDir, "auth.json"),
90
- );
91
- } finally {
92
- rmSync(tempRoot, { recursive: true, force: true });
93
- }
94
- });
95
- });
@@ -1,97 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { homedir } from "node:os";
3
- import { join } from "node:path";
4
-
5
- type AuthCredential =
6
- | { type?: unknown; key?: unknown }
7
- | Array<{ type?: unknown; key?: unknown }>;
8
-
9
- type AuthStorageData = Record<string, AuthCredential>;
10
-
11
- const AUTH_ENV_KEYS = [
12
- ["anthropic", "ANTHROPIC_API_KEY"],
13
- ["openai", "OPENAI_API_KEY"],
14
- ["github-copilot", "GITHUB_TOKEN"],
15
- ["google", "GEMINI_API_KEY"],
16
- ["groq", "GROQ_API_KEY"],
17
- ["xai", "XAI_API_KEY"],
18
- ["openrouter", "OPENROUTER_API_KEY"],
19
- ["mistral", "MISTRAL_API_KEY"],
20
- ["ollama-cloud", "OLLAMA_API_KEY"],
21
- ["custom-openai", "CUSTOM_OPENAI_API_KEY"],
22
- ["cerebras", "CEREBRAS_API_KEY"],
23
- ["azure-openai-responses", "AZURE_OPENAI_API_KEY"],
24
- ["vercel-ai-gateway", "AI_GATEWAY_API_KEY"],
25
- ["zai", "ZAI_API_KEY"],
26
- ["minimax", "MINIMAX_API_KEY"],
27
- ["minimax-cn", "MINIMAX_CN_API_KEY"],
28
- ["huggingface", "HF_TOKEN"],
29
- ["opencode", "OPENCODE_API_KEY"],
30
- ["opencode-go", "OPENCODE_API_KEY"],
31
- ["kimi-coding", "KIMI_API_KEY"],
32
- ["alibaba-coding-plan", "ALIBABA_API_KEY"],
33
- ["brave", "BRAVE_API_KEY"],
34
- ["brave_answers", "BRAVE_ANSWERS_KEY"],
35
- ["context7", "CONTEXT7_API_KEY"],
36
- ["jina", "JINA_API_KEY"],
37
- ["tavily", "TAVILY_API_KEY"],
38
- ["slack_bot", "SLACK_BOT_TOKEN"],
39
- ["discord_bot", "DISCORD_BOT_TOKEN"],
40
- ["telegram_bot", "TELEGRAM_BOT_TOKEN"],
41
- ] as const;
42
-
43
- function expandHome(pathValue: string): string {
44
- if (pathValue === "~") return homedir();
45
- if (pathValue.startsWith("~/")) return join(homedir(), pathValue.slice(2));
46
- return pathValue;
47
- }
48
-
49
- function getStoredApiKey(data: AuthStorageData, providerId: string): string | undefined {
50
- const raw = data[providerId];
51
- const credentials = Array.isArray(raw) ? raw : raw ? [raw] : [];
52
-
53
- for (const credential of credentials) {
54
- if (credential?.type !== "api_key") continue;
55
- if (typeof credential.key !== "string") continue;
56
- if (credential.key.trim().length === 0) continue;
57
- return credential.key;
58
- }
59
-
60
- return undefined;
61
- }
62
-
63
- export function resolveAuthPath(env: NodeJS.ProcessEnv = process.env): string {
64
- const agentDir = env.GSD_CODING_AGENT_DIR?.trim();
65
- if (agentDir) return join(expandHome(agentDir), "auth.json");
66
- return join(homedir(), ".gsd", "agent", "auth.json");
67
- }
68
-
69
- export function loadStoredCredentialEnvKeys(options: {
70
- env?: NodeJS.ProcessEnv;
71
- authPath?: string;
72
- } = {}): string[] {
73
- const env = options.env ?? process.env;
74
- const authPath = options.authPath ?? resolveAuthPath(env);
75
- if (!existsSync(authPath)) return [];
76
-
77
- let parsed: AuthStorageData;
78
- try {
79
- const raw = readFileSync(authPath, "utf-8");
80
- const data = JSON.parse(raw) as unknown;
81
- if (!data || typeof data !== "object" || Array.isArray(data)) return [];
82
- parsed = data as AuthStorageData;
83
- } catch {
84
- return [];
85
- }
86
-
87
- const loaded: string[] = [];
88
- for (const [providerId, envVar] of AUTH_ENV_KEYS) {
89
- if (env[envVar]) continue;
90
- const key = getStoredApiKey(parsed, providerId);
91
- if (!key) continue;
92
- env[envVar] = key;
93
- loaded.push(envVar);
94
- }
95
-
96
- return loaded;
97
- }