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.
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +2 -6
- package/dist/resources/extensions/gsd/commands-cmux.js +1 -30
- package/dist/resources/extensions/gsd/workflow-mcp.js +6 -53
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
- package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/daemon/src/orchestrator.ts +84 -9
- package/packages/mcp-server/README.md +3 -25
- package/packages/mcp-server/dist/cli.d.ts +1 -0
- package/packages/mcp-server/dist/cli.d.ts.map +1 -1
- package/packages/mcp-server/dist/cli.js +2 -4
- package/packages/mcp-server/dist/cli.js.map +1 -1
- package/packages/mcp-server/dist/server.d.ts +1 -32
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +1 -118
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +0 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +2 -274
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/cli.ts +3 -5
- package/packages/mcp-server/src/mcp-server.test.ts +1 -85
- package/packages/mcp-server/src/server.ts +1 -188
- package/packages/mcp-server/src/workflow-tools.test.ts +25 -32
- package/packages/mcp-server/src/workflow-tools.ts +2 -365
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +23 -1
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/anthropic.d.ts +17 -0
- package/packages/pi-ai/dist/utils/oauth/anthropic.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/anthropic.js +106 -0
- package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/index.d.ts +2 -3
- package/packages/pi-ai/dist/utils/oauth/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/index.js +5 -3
- package/packages/pi-ai/dist/utils/oauth/index.js.map +1 -1
- package/packages/pi-ai/src/providers/anthropic.ts +31 -1
- package/packages/pi-ai/src/utils/oauth/anthropic.ts +140 -0
- package/packages/pi-ai/src/utils/oauth/index.ts +5 -3
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +5 -9
- package/src/resources/extensions/gsd/commands-cmux.ts +1 -32
- package/src/resources/extensions/gsd/tests/cmux.test.ts +1 -67
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +2 -6
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +7 -23
- package/src/resources/extensions/gsd/workflow-mcp.ts +5 -59
- package/packages/mcp-server/dist/tool-credentials.d.ts +0 -6
- package/packages/mcp-server/dist/tool-credentials.d.ts.map +0 -1
- package/packages/mcp-server/dist/tool-credentials.js +0 -90
- package/packages/mcp-server/dist/tool-credentials.js.map +0 -1
- package/packages/mcp-server/src/tool-credentials.test.ts +0 -95
- package/packages/mcp-server/src/tool-credentials.ts +0 -97
- /package/dist/web/standalone/.next/static/{CHeIRZw-E97oO51g7zDvv → PYwFks7YuKWnl48wsvjo4}/_buildManifest.js +0 -0
- /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
|
|
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
|
|
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
|
|
202
|
+
env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath),
|
|
257
203
|
};
|
|
258
204
|
}
|
|
259
205
|
|
|
@@ -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
|
-
}
|
|
File without changes
|
|
File without changes
|