mcp-google-api 0.25.0 → 0.26.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.26.0](https://github.com/Ogekuri/mcp-google-api/compare/v0.25.0..v0.26.0) - 2026-11-08
4
+ ### 🚜 Changes
5
+ - add opencode CLI support and alphabetical CLI listing [useReq] *(cliTargets)*
6
+ - REQ-110/DES-017 updated: opencode joins the supported CLI registry; supported-name listings print alphabetically.
7
+ - REQ-112/REQ-113 updated: opencode MCP config at ~/.config/opencode/opencode.json (JSON mcp map) and skills at ~/.config/opencode/skills.
8
+ - REQ-117 updated: show CLI Configuration table covers all seven CLIs in alphabetical order; CLI_TARGETS registry reordered alphabetically.
9
+ - JSON read-modify-write helpers gained a mapKey parameter (default mcpServers, mcp for opencode) preserving unrelated keys; CliTarget gained jsonMcpMapKey.
10
+ - Unit suite 146/146 green; behavioral proof verified paths, mcp-map install/uninstall round-trip, and alphabetical show rows.
11
+ - rebuild dist binaries on every launcher run [useReq] *(mcp-google-api.sh)*
12
+ - PRJ-019 amended: the dev launcher rebuilds dist from the current sources before every execution and aborts non-zero when the rebuild fails; dependency installs stay explicit (npm ci).
13
+ - PRJ-022 added: every argument is forwarded unchanged to the rebuilt dist/cli.js with exit-code propagation via exec.
14
+ - PKG-019 amended: the helper-script no-implicit-install/build rule now carves out the PRJ-018 development launcher.
15
+ - Build output routes to stderr so the exec'd CLI keeps stdout clean for stdio JSON-RPC framing (CTN-003).
16
+ - No src/ changes; unit suite 146/146 green; live proof verified rebuild, exit propagation, and JSON-pure stdout.
17
+ - render show tables as box-drawing grid [useReq] *(cliShow)*
18
+ - REQ-185 added: the show CLI Configuration and Installation Status tables render as box-drawing grids using the specific border characters.
19
+ - REQ-186 added: data rows emit without inter-row border lines, with exactly one header separator and a closing bottom border.
20
+ - renderAsciiTable now builds borders via a parametric borderLine helper (top/header/body/bottom) and pipe-delimited rows; column sizing, cell wrapping, and alignment are unchanged.
21
+ - WORKFLOW.md TRACE-K and EDGE-06 runtime model updated; REFERENCES.md regenerated; no test files modified.
22
+ - print enable/disable result as human-readable confirmation [useReq] *(cli)*
23
+ - PRJ-008 updated: enable and disable join the human-readable stdout operation-report exceptions.
24
+ - REQ-184 added: enable/disable print a human-readable confirmation naming the resolved CLI and the resulting enabled state, exit 0.
25
+ - runEnableDisableCliCommand now writes plain-text confirmations on both success branches (state change and idempotent no-op); the unsupported-name JSON stderr diagnostic and exit 2 are unchanged (REQ-110).
26
+ - WORKFLOW.md TRACE-K and EDGE-06 runtime model updated; REFERENCES.md regenerated; no test files modified.
27
+ - render GitHub probe failure reason in version report [useReq] *(upgradeManager)*
28
+ - REQ-181 added: --ver/--version now prints 'GitHub latest: unknown (<reason>)' when the GitHub releases probe fails, <reason> carrying the probe diagnostic message.
29
+ - REQ-164 updated to reference the REQ-181 failed-probe diagnostic rendering.
30
+ - probeLatestGitHubVersion embeds the GitHub API error message body field (e.g. HTTP 404 rate limit) via the new tolerant readGitHubErrorDetail helper.
31
+ - WORKFLOW.md TRACE-L and EDGE-06/EDGE-10 runtime model updated; REFERENCES.md regenerated; no test files modified.
32
+
3
33
  ## [0.25.0](https://github.com/Ogekuri/mcp-google-api/compare/v0.24.0..v0.25.0) - 2026-11-08
4
34
  ### 🐛 Bug Fixes
5
35
  - make doctor spawn tests hermetic with isolated home [useReq] *(cliSpawn)*
@@ -637,6 +667,7 @@
637
667
  - \[0.23.0\]: https://github.com/Ogekuri/mcp-google-api/releases/tag/v0.23.0
638
668
  - \[0.24.0\]: https://github.com/Ogekuri/mcp-google-api/releases/tag/v0.24.0
639
669
  - \[0.25.0\]: https://github.com/Ogekuri/mcp-google-api/releases/tag/v0.25.0
670
+ - \[0.26.0\]: https://github.com/Ogekuri/mcp-google-api/releases/tag/v0.26.0
640
671
 
641
672
  [0.2.0]: https://github.com/Ogekuri/mcp-google-api/releases/tag/v0.2.0
642
673
  [0.3.0]: https://github.com/Ogekuri/mcp-google-api/compare/v0.2.0..v0.3.0
@@ -661,3 +692,4 @@
661
692
  [0.23.0]: https://github.com/Ogekuri/mcp-google-api/compare/v0.22.0..v0.23.0
662
693
  [0.24.0]: https://github.com/Ogekuri/mcp-google-api/compare/v0.23.0..v0.24.0
663
694
  [0.25.0]: https://github.com/Ogekuri/mcp-google-api/compare/v0.24.0..v0.25.0
695
+ [0.26.0]: https://github.com/Ogekuri/mcp-google-api/compare/v0.25.0..v0.26.0
package/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
  > * **No Support or Feature Requests:** please **do not** open issues, bug reports, or feature requests. They will not be addressed or accepted at this stage.
11
11
  > * **No Warranty:** this software is provided **"AS IS"**, without warranty of any kind, express or implied. Use it strictly for testing and evaluation purposes at your own sole risk.
12
12
 
13
- # mcp-google-api / MCP Google API server (0.25.0)
13
+ # mcp-google-api / MCP Google API server (0.26.0)
14
14
 
15
15
  <p align="center">
16
16
  <img src="https://img.shields.io/badge/node-%3E%3D24-339933?style=flat-square&logo=nodedotjs&logoColor=white" alt="Node.js >= 24">
package/dist/cli.js CHANGED
@@ -1608,6 +1608,15 @@ var DEFAULT_GITHUB_RELEASES_API_URL = "https://api.github.com/repos/Ogekuri/mcp-
1608
1608
  function stripReleaseTagPrefix(tag) {
1609
1609
  return tag.trim().replace(/^v/i, "");
1610
1610
  }
1611
+ async function readGitHubErrorDetail(response) {
1612
+ try {
1613
+ const payload = await response.json();
1614
+ const detail = typeof payload?.message === "string" ? payload.message.trim() : "";
1615
+ return detail.length > 0 ? detail : void 0;
1616
+ } catch {
1617
+ return void 0;
1618
+ }
1619
+ }
1611
1620
  async function probeLatestGitHubVersion(deps = {}) {
1612
1621
  const releasesUrl = deps.releasesUrl ?? DEFAULT_GITHUB_RELEASES_API_URL;
1613
1622
  const timeoutMs = deps.timeoutMs ?? DEFAULT_UPDATE_CHECK_TIMEOUT_MS;
@@ -1621,9 +1630,11 @@ async function probeLatestGitHubVersion(deps = {}) {
1621
1630
  signal: AbortSignal.timeout(timeoutMs)
1622
1631
  });
1623
1632
  if (!response.ok) {
1633
+ const detail = await readGitHubErrorDetail(response);
1634
+ const cause = detail ? `: ${detail.replace(/\.+$/, "")}` : "";
1624
1635
  return {
1625
1636
  status: "error",
1626
- message: `GitHub releases API responded with HTTP ${response.status}.`
1637
+ message: `GitHub releases API responded with HTTP ${response.status}${cause}.`
1627
1638
  };
1628
1639
  }
1629
1640
  const payload = await response.json();
@@ -1959,7 +1970,7 @@ async function runVersionCommand(options, deps = {}) {
1959
1970
  ]);
1960
1971
  const installedVersion = options.currentVersion || "unknown";
1961
1972
  const npmLatest = resolveProbeLatestVersion(npmProbe);
1962
- const githubLatest = githubProbe.status === "ok" ? githubProbe.version : "unknown";
1973
+ const githubLatest = githubProbe.status === "ok" ? githubProbe.version : `unknown (${githubProbe.message})`;
1963
1974
  const stdout = deps.stdout ?? process.stdout;
1964
1975
  stdout.write(`${installedVersion}
1965
1976
  npmjs latest: ${npmLatest}
@@ -2173,13 +2184,21 @@ var COPILOT_TARGET = {
2173
2184
  mcpConfigPath: (home) => join3(homeRoot(home), ".copilot", "mcp.json"),
2174
2185
  skillsDir: (home) => join3(homeRoot(home), ".copilot", "skills")
2175
2186
  };
2187
+ var OPENCODE_TARGET = {
2188
+ id: "opencode",
2189
+ configFormat: "json",
2190
+ jsonMcpMapKey: "mcp",
2191
+ mcpConfigPath: (home) => join3(homeRoot(home), ".config", "opencode", "opencode.json"),
2192
+ skillsDir: (home) => join3(homeRoot(home), ".config", "opencode", "skills")
2193
+ };
2176
2194
  var CLI_TARGETS = {
2177
- pi: PI_TARGET,
2178
- openclaw: OPENCLAW_TARGET,
2179
- codex: CODEX_TARGET,
2180
2195
  antigravity: ANTIGRAVITY_TARGET,
2181
2196
  claude: CLAUDE_TARGET,
2182
- copilot: COPILOT_TARGET
2197
+ codex: CODEX_TARGET,
2198
+ copilot: COPILOT_TARGET,
2199
+ openclaw: OPENCLAW_TARGET,
2200
+ opencode: OPENCODE_TARGET,
2201
+ pi: PI_TARGET
2183
2202
  };
2184
2203
  function resolveCliTarget(name) {
2185
2204
  return CLI_TARGETS[name.trim().toLowerCase()];
@@ -2201,35 +2220,35 @@ function writeJsonConfig(configPath, value) {
2201
2220
  writeFileSync3(temporary, JSON.stringify(value, null, 2) + "\n", "utf-8");
2202
2221
  renameSync2(temporary, configPath);
2203
2222
  }
2204
- function writeJsonMcpServerEntry(configPath, serverName, entry) {
2223
+ function writeJsonMcpServerEntry(configPath, serverName, entry, mapKey = "mcpServers") {
2205
2224
  const config = readJsonConfig(configPath);
2206
- const mcpServers = config.mcpServers ?? {};
2225
+ const mcpServers = config[mapKey] ?? {};
2207
2226
  if (mcpServers === null || typeof mcpServers !== "object" || Array.isArray(mcpServers)) {
2208
- throw new Error(`mcpServers is not an object: ${configPath}`);
2227
+ throw new Error(`${mapKey} is not an object: ${configPath}`);
2209
2228
  }
2210
2229
  mcpServers[serverName] = entry;
2211
- config.mcpServers = mcpServers;
2230
+ config[mapKey] = mcpServers;
2212
2231
  writeJsonConfig(configPath, config);
2213
2232
  }
2214
- function removeJsonMcpServerEntry(configPath, serverName) {
2233
+ function removeJsonMcpServerEntry(configPath, serverName, mapKey = "mcpServers") {
2215
2234
  if (!existsSync(configPath)) return false;
2216
2235
  const config = readJsonConfig(configPath);
2217
- const mcpServers = config.mcpServers;
2236
+ const mcpServers = config[mapKey];
2218
2237
  if (mcpServers === void 0) return false;
2219
2238
  if (mcpServers === null || typeof mcpServers !== "object" || Array.isArray(mcpServers)) {
2220
- throw new Error(`mcpServers is not an object: ${configPath}`);
2239
+ throw new Error(`${mapKey} is not an object: ${configPath}`);
2221
2240
  }
2222
2241
  const map = mcpServers;
2223
2242
  if (!(serverName in map)) return false;
2224
2243
  delete map[serverName];
2225
- config.mcpServers = map;
2244
+ config[mapKey] = map;
2226
2245
  writeJsonConfig(configPath, config);
2227
2246
  return true;
2228
2247
  }
2229
- function readJsonMcpServerEntry(configPath, serverName) {
2248
+ function readJsonMcpServerEntry(configPath, serverName, mapKey = "mcpServers") {
2230
2249
  try {
2231
2250
  const config = readJsonConfig(configPath);
2232
- const mcpServers = config.mcpServers;
2251
+ const mcpServers = config[mapKey];
2233
2252
  if (mcpServers === null || typeof mcpServers !== "object" || Array.isArray(mcpServers)) {
2234
2253
  return void 0;
2235
2254
  }
@@ -2372,7 +2391,7 @@ function isServerRegistered(target, serverName, home) {
2372
2391
  if (target.configFormat === "toml") {
2373
2392
  return hasTomlMcpServerSection(configPath, serverName);
2374
2393
  }
2375
- return readJsonMcpServerEntry(configPath, serverName) !== void 0;
2394
+ return readJsonMcpServerEntry(configPath, serverName, target.jsonMcpMapKey) !== void 0;
2376
2395
  }
2377
2396
  function applyServerRegistration(target, serverName, entry, home) {
2378
2397
  const configPath = target.mcpConfigPath(home);
@@ -2385,9 +2404,9 @@ function applyServerRegistration(target, serverName, entry, home) {
2385
2404
  return;
2386
2405
  }
2387
2406
  if (entry === void 0) {
2388
- removeJsonMcpServerEntry(configPath, serverName);
2407
+ removeJsonMcpServerEntry(configPath, serverName, target.jsonMcpMapKey);
2389
2408
  } else {
2390
- writeJsonMcpServerEntry(configPath, serverName, entry);
2409
+ writeJsonMcpServerEntry(configPath, serverName, entry, target.jsonMcpMapKey);
2391
2410
  }
2392
2411
  }
2393
2412
 
@@ -2540,22 +2559,22 @@ function renderAsciiTable(headers, rows, maxWidth = MAX_CELL_WIDTH) {
2540
2559
  const lengths = [header.length, ...rows.map((row) => (row[index] ?? "").length)];
2541
2560
  return Math.max(1, Math.min(Math.max(...lengths), Math.max(1, maxWidth)));
2542
2561
  });
2543
- const border = "+" + widths.map((width) => "-".repeat(width + 2)).join("+") + "+";
2562
+ const borderLine = (left, middle, right) => left + widths.map((width) => "\u2500".repeat(width + 2)).join(middle) + right;
2544
2563
  const renderRow = (cells) => {
2545
2564
  const wrapped = cells.map((cell, index) => wrapCell(cell ?? "", widths[index]));
2546
2565
  const height = Math.max(...wrapped.map((part) => part.length));
2547
2566
  const lines = [];
2548
2567
  for (let line = 0; line < height; line += 1) {
2549
2568
  const parts = wrapped.map((part, index) => (part[line] ?? "").padEnd(widths[index]));
2550
- lines.push("| " + parts.join(" | ") + " |");
2569
+ lines.push("\u2502 " + parts.join(" \u2502 ") + " \u2502");
2551
2570
  }
2552
2571
  return lines;
2553
2572
  };
2554
- const output = [border, ...renderRow(headers), border];
2573
+ const output = [borderLine("\u250C", "\u252C", "\u2510"), ...renderRow(headers), borderLine("\u251C", "\u253C", "\u2524")];
2555
2574
  for (const row of rows) {
2556
2575
  output.push(...renderRow(row));
2557
- output.push(border);
2558
2576
  }
2577
+ output.push(borderLine("\u2514", "\u2534", "\u2518"));
2559
2578
  return output.join("\n");
2560
2579
  }
2561
2580
  function buildCliRows(home) {
@@ -2969,16 +2988,14 @@ function runEnableDisableCliCommand(name, enable, options = {}) {
2969
2988
  const settings = loadCliSettings(options.home);
2970
2989
  const already = settings.enabled.includes(target.id);
2971
2990
  if (enable === already) {
2972
- streams.stdout.write(
2973
- JSON.stringify({ cli: target.id, enabled: enable, message: `${target.id} is already ${enable ? "enabled" : "disabled"}.` }, null, 2) + "\n"
2974
- );
2991
+ streams.stdout.write(`${target.id} is already ${enable ? "enabled" : "disabled"}.
2992
+ `);
2975
2993
  return 0;
2976
2994
  }
2977
2995
  settings.enabled = enable ? [...settings.enabled, target.id] : settings.enabled.filter((item) => item !== target.id);
2978
2996
  saveCliSettings(settings, options.home);
2979
- streams.stdout.write(
2980
- JSON.stringify({ cli: target.id, enabled: enable, message: `${enable ? "Enabled" : "Disabled"} ${target.id}.` }, null, 2) + "\n"
2981
- );
2997
+ streams.stdout.write(`${enable ? "Enabled" : "Disabled"} ${target.id}.
2998
+ `);
2982
2999
  return 0;
2983
3000
  }
2984
3001
  function runApiKeyCommand(key, options) {