gpteam 0.1.15 → 0.1.17

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/README.md CHANGED
@@ -12,9 +12,9 @@ When a selected client is missing, the interactive CLI shows the exact install c
12
12
 
13
13
  Recommendation order is deterministic: success rate first, then an experience score. The score weighs first SSE event time, total completion time, p90 completion tail latency, and health-check time, so a node with one very slow probe is not recommended just because its median result looks good. The result table also marks the fastest full completion separately from the balanced recommendation, because deep or long-output model runs may care more about full completion time than first-token responsiveness. Model prompts use "configurable context" wording because the value is written to the client-side Codex `model_context_window`; it must not be confused with a public marketing total-window label.
14
14
 
15
- Client config writing follows the same safety pattern as cc-switch: keep Codex top-level fields separate from provider tables, preserve unrelated sections such as MCP servers, merge OpenCode/OpenClaw providers additively, and stop before writing when an existing JSON/JSON5 config cannot be parsed. GPTeam keeps three proxy-specific extensions on top of that baseline: Codex explicitly disables WebSocket prewarm, Codex writes the `gpteam_image` MCP server so Image 2 can be called from chat, and Claude Code writes the reasoning-effort header through `ANTHROPIC_CUSTOM_HEADERS`.
15
+ Client config writing follows the same safety pattern as cc-switch: keep Codex top-level fields separate from provider tables, preserve unrelated sections such as MCP servers, merge OpenCode/OpenClaw providers additively, and stop before writing when an existing JSON/JSON5 config cannot be parsed. GPTeam keeps three proxy-specific extensions on top of that baseline: Codex explicitly disables WebSocket prewarm, Codex/OpenCode/Claude Code write the `gpteam_image` MCP server so Image 2 can be called from chat, and Claude Code writes the reasoning-effort header through `ANTHROPIC_CUSTOM_HEADERS`.
16
16
 
17
- For Codex, the Image MCP config uses the cc-switch-style MCP env block. On macOS/Linux it writes `command = "npx"` with `args = ["-y", "-p", "gpteam", "gpteam-image-mcp"]`; on Windows it writes a `cmd /c npx -y -p gpteam gpteam-image-mcp` wrapper. The MCP receives `GPTEAM_API_KEY` and `GPTEAM_BASE_URL` from `[mcp_servers.gpteam_image.env]`, so it does not depend on Codex `auth.json`.
17
+ The Image MCP config uses cc-switch-style per-client env blocks. Codex writes `[mcp_servers.gpteam_image.env]`, OpenCode writes `mcp.gpteam_image.environment`, and Claude Code writes `mcpServers.gpteam_image.env` in `~/.claude.json`. The MCP receives `GPTEAM_API_KEY` and `GPTEAM_BASE_URL` from that MCP config, so it does not depend on Codex `auth.json` or inherited `OPENAI_API_KEY`.
18
18
 
19
19
  Claude Code is written to `~/.claude/settings.json` under the `env` section, using the GPTeam `/anthropic` base URL. OpenClaw writes `models.providers.gpteam` and also selects `gpteam/<model>` under `agents.defaults.model`, so the chosen model is active without an extra manual step.
20
20
 
@@ -89,7 +89,7 @@ export function resolveSpawnInvocation(command, args, platform = process.platfor
89
89
  if (platform === 'win32' && command === 'npm') {
90
90
  return {
91
91
  command: 'cmd.exe',
92
- args: ['/d', '/s', '/c', windowsCommandLine('npm.cmd', args)]
92
+ args: ['/d', '/c', windowsCommandLine('npm.cmd', args)]
93
93
  };
94
94
  }
95
95
  return { command, args };
@@ -123,7 +123,9 @@ function windowsCommandLine(command, args) {
123
123
  }
124
124
 
125
125
  function windowsQuoteArg(value) {
126
- return `"${String(value).replace(/"/g, '\\"')}"`;
126
+ const text = String(value);
127
+ if (!/[\s&()^|<>"]/.test(text)) return text;
128
+ return `"${text.replace(/"/g, '\\"')}"`;
127
129
  }
128
130
 
129
131
  function shellQuote(value) {
package/lib/config.js CHANGED
@@ -109,6 +109,8 @@ export function writeOpenCodeConfig(settings) {
109
109
  }
110
110
  }
111
111
  };
112
+ config.mcp = config.mcp && typeof config.mcp === 'object' ? config.mcp : {};
113
+ config.mcp[IMAGE_MCP_ID] = openCodeImageMCPConfig(settings);
112
114
  writeJSON(filePath, config);
113
115
  return [filePath];
114
116
  }
@@ -117,7 +119,9 @@ export function writeClaudeCodeConfig(settings) {
117
119
  const dir = path.join(homeDir(), '.claude');
118
120
  fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
119
121
  const filePath = claudeSettingsPath(dir);
122
+ const mcpPath = path.join(homeDir(), '.claude.json');
120
123
  backupIfExists(filePath);
124
+ backupIfExists(mcpPath);
121
125
  const config = readJSON(filePath, {});
122
126
  config.env = config.env && typeof config.env === 'object' ? config.env : {};
123
127
  Object.assign(config.env, {
@@ -130,7 +134,13 @@ export function writeClaudeCodeConfig(settings) {
130
134
  ANTHROPIC_CUSTOM_HEADERS: `X-Codex-Reasoning-Effort: ${settings.effort}`
131
135
  });
132
136
  writeJSON(filePath, config);
133
- return [filePath];
137
+ const mcpConfig = readJSON(mcpPath, {});
138
+ mcpConfig.mcpServers = mcpConfig.mcpServers && typeof mcpConfig.mcpServers === 'object'
139
+ ? mcpConfig.mcpServers
140
+ : {};
141
+ mcpConfig.mcpServers[IMAGE_MCP_ID] = imageMCPServer(settings);
142
+ writeJSON(mcpPath, mcpConfig);
143
+ return [filePath, mcpPath];
134
144
  }
135
145
 
136
146
  export const writeClaudeCodeEnv = writeClaudeCodeConfig;
@@ -211,6 +221,32 @@ function codexImageMCPCommand() {
211
221
  };
212
222
  }
213
223
 
224
+ function imageMCPServer(settings) {
225
+ const mcpCommand = codexImageMCPCommand();
226
+ return {
227
+ command: mcpCommand.command,
228
+ args: mcpCommand.args,
229
+ env: imageMCPEnv(settings)
230
+ };
231
+ }
232
+
233
+ function imageMCPEnv(settings) {
234
+ return {
235
+ GPTEAM_API_KEY: String(settings.apiKey || ''),
236
+ GPTEAM_BASE_URL: String(settings.node && settings.node.baseUrl ? settings.node.baseUrl : '')
237
+ };
238
+ }
239
+
240
+ function openCodeImageMCPConfig(settings) {
241
+ const server = imageMCPServer(settings);
242
+ return {
243
+ type: 'local',
244
+ command: [server.command, ...server.args],
245
+ environment: server.env,
246
+ enabled: true
247
+ };
248
+ }
249
+
214
250
  function stripCodexManagedConfig(raw) {
215
251
  const rootLines = [];
216
252
  const rest = [];
package/lib/help.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export const PACKAGE_NAME = 'gpteam';
2
- export const PACKAGE_VERSION = '0.1.15';
2
+ export const PACKAGE_VERSION = '0.1.17';
3
3
 
4
4
  export function getHelpText() {
5
5
  return [
@@ -22,6 +22,6 @@ export function getHelpText() {
22
22
  ' --help 显示帮助',
23
23
  ' --version 显示版本',
24
24
  '',
25
- '说明:输入 key 后会先请求 /v1/models 校验,通过后才继续。选好客户端后会检测本机命令是否可用,缺失时提示安装;Windows 暂不支持自动配置 OpenClaw。测速会请求 GET /api/health 和流式 POST /v1/responses。入口之间并行测速,写新配置前会先备份旧配置。Codex 配置会同时写入 GPTeam Image MCP,生图工具从 MCP env 读取 key。'
25
+ '说明:输入 key 后会先请求 /v1/models 校验,通过后才继续。选好客户端后会检测本机命令是否可用,缺失时提示安装。Windows 暂不支持自动配置 OpenClaw。测速会请求 GET /api/health 和流式 POST /v1/responses。入口之间并行测速,写新配置前会先备份旧配置。Codex、OpenCode、Claude Code 会写入 GPTeam Image MCP,生图工具从 MCP env 读取 key。'
26
26
  ].join('\n');
27
27
  }
@@ -1,6 +1,7 @@
1
1
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
3
  import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
4
+ import fs from 'node:fs';
4
5
  import { generateImage, toolResultContent } from './image.js';
5
6
 
6
7
  const GENERATE_IMAGE_TOOL = {
@@ -42,7 +43,7 @@ const GENERATE_IMAGE_TOOL = {
42
43
  export function createServer(deps = {}) {
43
44
  const server = new Server({
44
45
  name: 'gpteam-image-mcp',
45
- version: '0.1.0'
46
+ version: resolvePackageVersion(deps)
46
47
  }, {
47
48
  capabilities: {
48
49
  tools: {}
@@ -72,3 +73,13 @@ export async function runServer() {
72
73
  const transport = new StdioServerTransport();
73
74
  await server.connect(transport);
74
75
  }
76
+
77
+ export function resolvePackageVersion(deps = {}) {
78
+ const readFile = deps.readFile || ((filePath) => fs.readFileSync(filePath, 'utf8'));
79
+ try {
80
+ const pkg = JSON.parse(readFile(new URL('../../package.json', import.meta.url)));
81
+ return String(pkg.version || '0.0.0');
82
+ } catch {
83
+ return '0.0.0';
84
+ }
85
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gpteam",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "GPTeam API interactive client configurator and ingress benchmark CLI.",
5
5
  "type": "module",
6
6
  "bin": {