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 +115 -0
- package/README.md +1 -1
- package/dist/cli.js +46 -29
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
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.
|
|
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 :
|
|
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
|
-
|
|
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
|
|
2225
|
+
const mcpServers = config[mapKey] ?? {};
|
|
2207
2226
|
if (mcpServers === null || typeof mcpServers !== "object" || Array.isArray(mcpServers)) {
|
|
2208
|
-
throw new Error(
|
|
2227
|
+
throw new Error(`${mapKey} is not an object: ${configPath}`);
|
|
2209
2228
|
}
|
|
2210
2229
|
mcpServers[serverName] = entry;
|
|
2211
|
-
config
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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("
|
|
2569
|
+
lines.push("\u2502 " + parts.join(" \u2502 ") + " \u2502");
|
|
2551
2570
|
}
|
|
2552
2571
|
return lines;
|
|
2553
2572
|
};
|
|
2554
|
-
const output = [
|
|
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
|
-
|
|
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
|
-
|
|
2981
|
-
);
|
|
2997
|
+
streams.stdout.write(`${enable ? "Enabled" : "Disabled"} ${target.id}.
|
|
2998
|
+
`);
|
|
2982
2999
|
return 0;
|
|
2983
3000
|
}
|
|
2984
3001
|
function runApiKeyCommand(key, options) {
|