mcp-google-api 0.23.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,114 @@
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
+
33
+ ## [0.25.0](https://github.com/Ogekuri/mcp-google-api/compare/v0.24.0..v0.25.0) - 2026-11-08
34
+ ### 🐛 Bug Fixes
35
+ - make doctor spawn tests hermetic with isolated home [useReq] *(cliSpawn)*
36
+ - Root cause of the CI-only failure: the doctor spawn test inherited the
37
+ - host HOME, so it read the developer machine's real
38
+ - ~/.config/mcp-google-api/config.json; locally the real API key made the
39
+ - REQ-070 api-key check pass (exit 0), while the clean CI runner had no
40
+ - settings file, so doctor correctly exited 1 and the gate failed.
41
+ - spawnCli now accepts an injectable HOME override; the doctor success
42
+ - test provisions an isolated home with the DES-018 settings fixture and
43
+ - a valid-format test key, so local runs reproduce the CI runner state
44
+ - exactly and the discrepancy can no longer hide before publication.
45
+ - Add a REQ-070 regression pin: doctor exits 1 on a clean isolated home
46
+ - without a configured API key (the exact CI failure state).
47
+ - Evidence: clean-HOME reproduction exited 1 with api-key fail before the
48
+ - fix; after the fix the suite passes 4/4 both with the real and a clean
49
+ - HOME; full suite 146/146; local pre-release gate green (exit 0).
50
+ - No source changes: doctor clean-env exit-1 behavior is REQ-070-correct.
51
+
52
+ ## [0.24.0](https://github.com/Ogekuri/mcp-google-api/compare/v0.23.0..v0.24.0) - 2026-11-08
53
+ ### ⛰️ Features
54
+ - add pre-release-check.sh release gate [useReq] *(scripts)*
55
+ - Ship scripts/pre-release-check.sh running the release-gating stages
56
+ - in mandatory order: publish-version guard, typecheck, unit tests,
57
+ - production build, aborting at the first failed stage (PKG-058/059).
58
+ - The script exits 0 only when every stage passes, runs from any cwd
59
+ - by resolving the repository root, and never installs dependencies
60
+ - or publishes (PKG-060).
61
+ - Add tests/preReleaseCheck.unit.test.ts (TST-024): static contract on
62
+ - stage order, fail-fast wiring, repository-root cd, and no install/
63
+ - publish commands, plus a sandbox run proving fail-fast exit 1 on an
64
+ - injected failing stage.
65
+ - Runtime verification: full run green (guard 0.23.0 publishable,
66
+ - typecheck clean, 143/143 unit tests, build success, exit 0); real
67
+ - fail-fast observed on a missing-toolchain run (typecheck FAILED ->
68
+ - exit 1, later stages skipped).
69
+
70
+ ### 🐛 Bug Fixes
71
+ - sync package-lock bin path with package.json launcher [useReq] *(packaging)*
72
+ - The committed package-lock.json root bin entry still recorded the
73
+ - superseded dist/cli.js launcher, so every standard bootstrap
74
+ - (npm install) rewrote the tracked lockfile and left a fresh clone dirty.
75
+ - Regenerate the lockfile bin entry to bin/mcp-google-api.mjs, matching
76
+ - the package.json launcher contract (PRJ-020).
77
+ - Add a level-0 regression guard test asserting lockfile/package.json
78
+ - bin-map identity to tests/npmPublishContract.unit.test.ts, closing
79
+ - the TST-021 coverage gap that let the drift go undetected.
80
+ - Evidence: reproducer red on the stale lockfile, green after the fix;
81
+ - full suite 138/138 pass, typecheck clean, static analysis clean.
82
+
83
+ ### 🚜 Changes
84
+ - gate pipeline on pre-release test checks [useReq] *(release)*
85
+ - Add a Pre-release check step to .github/workflows/release-npm.yml
86
+ - running scripts/pre-release-check.sh after npm ci and before every
87
+ - build, pack, publish, and release-creation step, so versions whose
88
+ - tests fail produce no release artifact and are never published
89
+ - (PKG-063).
90
+ - The gate executes the PKG-058 stages (publish-version guard,
91
+ - typecheck, unit tests, build) in fail-fast order (PKG-059) and never
92
+ - installs dependencies or publishes (PKG-060).
93
+ - Update the workflow header and pack-step comments; the release
94
+ - pipeline defines no direct test commands - all test stages live in
95
+ - the gate script.
96
+ - SRS: add PKG-063 and extend TST-020 with the gate contract.
97
+ - Tests: ciContract asserts gate presence, placement, and absence of
98
+ - direct test commands; suite 6/6, full suite 145/145.
99
+ - clean run-created artifacts in pre-release-check [useReq] *(scripts)*
100
+ - scripts/pre-release-check.sh now snapshots the repository state before
101
+ - the stages and removes on exit every artifact directory the run created
102
+ - (e.g. the tsup dist/ tree), on both success and fail-fast paths, so the
103
+ - repository is left as found (PKG-061).
104
+ - Pre-existing artifact directories are preserved untouched (PKG-062).
105
+ - SRS: add PKG-061/PKG-062 and extend TST-024 with the cleanup contract.
106
+ - Tests: shared sandbox helper plus two behavioral proofs - run-created
107
+ - dist removed on the fail-fast path, pre-existing dist sentinel intact.
108
+ - Verification: suite 7/7; full run 145/145 tests with dist removed after
109
+ - the run; pre-existing dist preserved in a second scenario; static
110
+ - analysis clean; git status clean after every run.
111
+
3
112
  ## [0.23.0](https://github.com/Ogekuri/mcp-google-api/compare/v0.22.0..v0.23.0) - 2026-11-07
4
113
  ### ⛰️ Features
5
114
  - add copilot CLI agent support (DES-017, REQ-110/112/113/117) [useReq] *(cli-targets)*
@@ -556,6 +665,9 @@
556
665
  - \[0.21.0\]: https://github.com/Ogekuri/mcp-google-api/releases/tag/v0.21.0
557
666
  - \[0.22.0\]: https://github.com/Ogekuri/mcp-google-api/releases/tag/v0.22.0
558
667
  - \[0.23.0\]: https://github.com/Ogekuri/mcp-google-api/releases/tag/v0.23.0
668
+ - \[0.24.0\]: https://github.com/Ogekuri/mcp-google-api/releases/tag/v0.24.0
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
559
671
 
560
672
  [0.2.0]: https://github.com/Ogekuri/mcp-google-api/releases/tag/v0.2.0
561
673
  [0.3.0]: https://github.com/Ogekuri/mcp-google-api/compare/v0.2.0..v0.3.0
@@ -578,3 +690,6 @@
578
690
  [0.21.0]: https://github.com/Ogekuri/mcp-google-api/compare/v0.20.0..v0.21.0
579
691
  [0.22.0]: https://github.com/Ogekuri/mcp-google-api/compare/v0.21.0..v0.22.0
580
692
  [0.23.0]: https://github.com/Ogekuri/mcp-google-api/compare/v0.22.0..v0.23.0
693
+ [0.24.0]: https://github.com/Ogekuri/mcp-google-api/compare/v0.23.0..v0.24.0
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.23.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) {