@curdx/flow 7.1.0 → 7.1.2
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 +16 -1
- package/dist/index.mjs +218 -112
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@curdx/flow` are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/) and the project follows [Semantic Versioning](https://semver.org/).
|
|
4
4
|
|
|
5
|
-
## 7.1.
|
|
5
|
+
## 7.1.2 — 2026-05-04
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Auto-detect-and-install Bun when installing `claude-mem`.** The `claude-mem` plugin's runtime hooks shell out to `node scripts/bun-runner.js` which requires Bun on `PATH` or `~/.bun/bin/bun(.exe)` — Windows users without Bun previously hit `Error: Bun not found` at every Claude Code session start. The installer now runs `ensureBun()` as a `prereqCheck` before installing `claude-mem`: detects Bun via `which`/`where` plus the standard fallback paths (mirrors `bun-runner.js`'s discovery order), and if missing prompts `Auto-install Bun now? (default: No)`. On accept, runs the official installer (`curl -fsSL https://bun.sh/install | bash` on macOS/Linux, `powershell -c "irm bun.sh/install.ps1 | iex"` on Windows). On decline, the installer surfaces a `skip` row for `claude-mem` and continues with the rest of the bundle — other packages are unaffected. Existing users with Bun already installed (e.g. all macOS users who manually ran the installer earlier) see zero behavior change.
|
|
10
|
+
- New module: `src/runner/ensureBun.ts` (~75 LoC) — exports `findBun()` and `ensureBun(t)`.
|
|
11
|
+
- `src/registry/plugins/claude-mem.ts` declares `prereqCheck: (t) => ensureBun(t)` (one-line wire-in via the existing `Pkg.prereqCheck` contract that `chrome-devtools-mcp` already uses).
|
|
12
|
+
- i18n: 9 new `bun.*` keys in `src/i18n/{zh,en}.ts`.
|
|
13
|
+
|
|
14
|
+
## 7.1.1 — 2026-05-04
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- **Windows Chrome detection in the installer's `chrome-devtools-mcp` pre-req check.** `src/registry/plugins/chrome-devtools-mcp.ts`'s `checkChrome()` previously ran `test -x /Applications/...` plus `which google-chrome` / `which chromium` on every platform — none of which work on Windows (`test` is a Unix builtin, `which` isn't on `cmd`/PowerShell PATH by default, and the macOS app-bundle path doesn't exist). Result: the installer rejected Windows machines with Chrome installed, reporting "需要本机已安装 Chrome / Requires Chrome installed locally". Detection is now per-platform, mirroring `GoogleChrome/chrome-launcher`'s `chrome-finder` strategy: on `win32`, scan `LOCALAPPDATA` / `PROGRAMFILES` / `PROGRAMFILES(X86)` for `Google\Chrome\Application\chrome.exe` and `Google\Chrome SxS\Application\chrome.exe` (Canary) via `fs.existsSync`; on `darwin`, check the canonical app-bundle path; on Linux, the existing `which` lookup. A `CHROME_PATH` env var now overrides on all platforms (matches chrome-launcher / Lighthouse convention).
|
|
19
|
+
|
|
20
|
+
|
|
6
21
|
|
|
7
22
|
### Added
|
|
8
23
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import * as
|
|
4
|
+
import * as p10 from "@clack/prompts";
|
|
5
5
|
import { defineCommand, runMain } from "citty";
|
|
6
6
|
|
|
7
7
|
// src/ui/language.ts
|
|
@@ -66,6 +66,15 @@ var messages = {
|
|
|
66
66
|
"context7.dashboardHint": "\u53EF\u5728 https://context7.com/dashboard \u521B\u5EFA API Key",
|
|
67
67
|
"chrome.prereqNode": "\u9700\u8981 Node.js >= 20.19\uFF0C\u5F53\u524D\u7248\u672C {current}",
|
|
68
68
|
"chrome.prereqChrome": "\u9700\u8981\u672C\u673A\u5DF2\u5B89\u88C5 Chrome\uFF08chrome-devtools-mcp \u4F1A\u8C03\u7528\u672C\u5730\u6D4F\u89C8\u5668\uFF09",
|
|
69
|
+
"bun.missing": "\u672A\u68C0\u6D4B\u5230 Bun\uFF0Cclaude-mem \u7684\u540E\u53F0 worker \u4F9D\u8D56 Bun \u8FD0\u884C\u3002",
|
|
70
|
+
"bun.installerSource": "Bun \u5B89\u88C5\u811A\u672C\u6765\u6E90\uFF1Ahttps://bun.sh\uFF08macOS/Linux \u7528 curl\uFF0CWindows \u7528 powershell irm\uFF09\u3002",
|
|
71
|
+
"bun.confirmInstall": "\u662F\u5426\u73B0\u5728\u81EA\u52A8\u5B89\u88C5 Bun\uFF1F\uFF08\u9ED8\u8BA4\u5426\u2014\u2014\u9009\u5426\u5C06\u8DF3\u8FC7 claude-mem\uFF0C\u5176\u4ED6\u63D2\u4EF6\u7EE7\u7EED\u5B89\u88C5\uFF09",
|
|
72
|
+
"bun.declined": "\u5DF2\u8DF3\u8FC7 Bun \u5B89\u88C5\uFF1Bclaude-mem \u9700\u8981 Bun\uFF0C\u672C\u6B21\u4E0D\u5B89\u88C5\u3002\u624B\u52A8\u88C5\u597D Bun \u540E\u53EF\u91CD\u8DD1 install\u3002",
|
|
73
|
+
"bun.installing": "\u6B63\u5728\u4E0B\u8F7D\u5E76\u5B89\u88C5 Bun\uFF08\u9996\u6B21\u7EA6 60MB\uFF09\u2026",
|
|
74
|
+
"bun.installed": "Bun \u5B89\u88C5\u5B8C\u6210\u3002",
|
|
75
|
+
"bun.installFailedTitle": "Bun \u5B89\u88C5\u5931\u8D25",
|
|
76
|
+
"bun.installFailedReason": "Bun \u5B89\u88C5\u5931\u8D25\uFF1A{error}",
|
|
77
|
+
"bun.installedButNotFound": "Bun \u5B89\u88C5\u811A\u672C\u58F0\u660E\u6210\u529F\uFF0C\u4F46\u672A\u5728\u5DF2\u77E5\u8DEF\u5F84\u627E\u5230 bun \u53EF\u6267\u884C\u6587\u4EF6\u2014\u2014\u8BF7\u624B\u52A8\u786E\u8BA4\u540E\u91CD\u8DD1\u3002",
|
|
69
78
|
"reinstall.uninstalling": "\u5148\u5378\u8F7D\u65E7\u7248\u672C\u2026",
|
|
70
79
|
"reinstall.installing": "\u5B89\u88C5\u65B0\u7248\u672C\u2026",
|
|
71
80
|
"state.checking": "\u68C0\u67E5\u5DF2\u5B89\u88C5\u72B6\u6001\u2026\uFF08claude plugin list / mcp list\uFF09",
|
|
@@ -138,6 +147,15 @@ var messages2 = {
|
|
|
138
147
|
"context7.dashboardHint": "Get a key at https://context7.com/dashboard",
|
|
139
148
|
"chrome.prereqNode": "Requires Node.js >= 20.19 (current: {current})",
|
|
140
149
|
"chrome.prereqChrome": "Requires Chrome installed locally (chrome-devtools-mcp drives the local browser)",
|
|
150
|
+
"bun.missing": "Bun runtime not found \u2014 claude-mem's background worker requires Bun.",
|
|
151
|
+
"bun.installerSource": "Bun installer source: https://bun.sh (curl on macOS/Linux, PowerShell irm on Windows).",
|
|
152
|
+
"bun.confirmInstall": "Auto-install Bun now? (default: No \u2014 declining will skip claude-mem; other packages continue)",
|
|
153
|
+
"bun.declined": "Bun install declined; claude-mem requires Bun and will be skipped this run. Install Bun manually and re-run install.",
|
|
154
|
+
"bun.installing": "Downloading and installing Bun (~60 MB on first run)\u2026",
|
|
155
|
+
"bun.installed": "Bun installed.",
|
|
156
|
+
"bun.installFailedTitle": "Bun install failed",
|
|
157
|
+
"bun.installFailedReason": "Bun install failed: {error}",
|
|
158
|
+
"bun.installedButNotFound": "Bun installer reported success but bun was not found at any known path \u2014 verify manually and re-run.",
|
|
141
159
|
"reinstall.uninstalling": "Uninstalling old version\u2026",
|
|
142
160
|
"reinstall.installing": "Installing new version\u2026",
|
|
143
161
|
"state.checking": "Checking installed state\u2026 (claude plugin list / mcp list)",
|
|
@@ -196,10 +214,10 @@ async function initLanguage(override) {
|
|
|
196
214
|
}
|
|
197
215
|
|
|
198
216
|
// src/ui/menu.ts
|
|
199
|
-
import * as
|
|
217
|
+
import * as p9 from "@clack/prompts";
|
|
200
218
|
|
|
201
219
|
// src/flows/install.ts
|
|
202
|
-
import * as
|
|
220
|
+
import * as p5 from "@clack/prompts";
|
|
203
221
|
import pc from "picocolors";
|
|
204
222
|
|
|
205
223
|
// src/runner/state.ts
|
|
@@ -218,15 +236,15 @@ async function run(cmd, args) {
|
|
|
218
236
|
stderr: result.stderr
|
|
219
237
|
};
|
|
220
238
|
}
|
|
221
|
-
async function runStreaming(cmd, args,
|
|
222
|
-
|
|
239
|
+
async function runStreaming(cmd, args, log6) {
|
|
240
|
+
log6.message(`$ ${cmd} ${args.join(" ")}`);
|
|
223
241
|
const proc = x(cmd, args, { throwOnError: false });
|
|
224
242
|
let stdout = "";
|
|
225
243
|
for await (const line of proc) {
|
|
226
244
|
const trimmed = line.replace(/\r?\n$/, "");
|
|
227
245
|
if (trimmed.length > 0) {
|
|
228
246
|
stdout += trimmed + "\n";
|
|
229
|
-
|
|
247
|
+
log6.message(trimmed);
|
|
230
248
|
}
|
|
231
249
|
}
|
|
232
250
|
const finished = await proc;
|
|
@@ -269,15 +287,15 @@ async function listPlugins(force = false) {
|
|
|
269
287
|
}
|
|
270
288
|
try {
|
|
271
289
|
const arr = JSON.parse(res.stdout);
|
|
272
|
-
pluginCache = arr.map((
|
|
273
|
-
const [name =
|
|
290
|
+
pluginCache = arr.map((p11) => {
|
|
291
|
+
const [name = p11.id, marketplace = ""] = p11.id.split("@");
|
|
274
292
|
return {
|
|
275
|
-
id:
|
|
293
|
+
id: p11.id,
|
|
276
294
|
name,
|
|
277
295
|
marketplace,
|
|
278
|
-
version:
|
|
279
|
-
scope:
|
|
280
|
-
enabled:
|
|
296
|
+
version: p11.version,
|
|
297
|
+
scope: p11.scope,
|
|
298
|
+
enabled: p11.enabled
|
|
281
299
|
};
|
|
282
300
|
});
|
|
283
301
|
} catch {
|
|
@@ -323,7 +341,7 @@ async function listMcp(force = false) {
|
|
|
323
341
|
}
|
|
324
342
|
async function isPluginInstalled(id) {
|
|
325
343
|
const list = await listPlugins();
|
|
326
|
-
return list.some((
|
|
344
|
+
return list.some((p11) => p11.id === id);
|
|
327
345
|
}
|
|
328
346
|
async function isMarketplaceAdded(name) {
|
|
329
347
|
const list = await listMarketplaces();
|
|
@@ -335,7 +353,7 @@ async function isMcpInstalled(name) {
|
|
|
335
353
|
}
|
|
336
354
|
async function findPlugin(id) {
|
|
337
355
|
const list = await listPlugins();
|
|
338
|
-
return list.find((
|
|
356
|
+
return list.find((p11) => p11.id === id);
|
|
339
357
|
}
|
|
340
358
|
var marketplaceJsonCache = /* @__PURE__ */ new Map();
|
|
341
359
|
function marketplaceDir(name) {
|
|
@@ -357,7 +375,7 @@ async function readMarketplaceJson(name) {
|
|
|
357
375
|
async function getMarketplacePluginVersion(marketplaceName, pluginName) {
|
|
358
376
|
const m = await readMarketplaceJson(marketplaceName);
|
|
359
377
|
if (!m?.plugins) return null;
|
|
360
|
-
const entry = m.plugins.find((
|
|
378
|
+
const entry = m.plugins.find((p11) => p11.name === pluginName);
|
|
361
379
|
return entry?.version ?? null;
|
|
362
380
|
}
|
|
363
381
|
var REFRESH_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -478,8 +496,8 @@ var pua = {
|
|
|
478
496
|
marketplaces: () => [MARKETPLACE_NAME],
|
|
479
497
|
isInstalled: () => isPluginInstalled(PLUGIN_ID),
|
|
480
498
|
installedVersion: async () => {
|
|
481
|
-
const
|
|
482
|
-
const v =
|
|
499
|
+
const p11 = await findPlugin(PLUGIN_ID);
|
|
500
|
+
const v = p11?.version;
|
|
483
501
|
return v && v !== "unknown" ? v : null;
|
|
484
502
|
},
|
|
485
503
|
latestVersion: () => getMarketplacePluginVersion(MARKETPLACE_NAME, PLUGIN_NAME),
|
|
@@ -492,6 +510,72 @@ var pua = {
|
|
|
492
510
|
};
|
|
493
511
|
var pua_default = pua;
|
|
494
512
|
|
|
513
|
+
// src/runner/ensureBun.ts
|
|
514
|
+
import { existsSync } from "fs";
|
|
515
|
+
import { homedir } from "os";
|
|
516
|
+
import path2 from "path";
|
|
517
|
+
import * as p2 from "@clack/prompts";
|
|
518
|
+
var IS_WINDOWS = process.platform === "win32";
|
|
519
|
+
function fallbackPaths() {
|
|
520
|
+
const home = homedir();
|
|
521
|
+
if (IS_WINDOWS) return [path2.join(home, ".bun", "bin", "bun.exe")];
|
|
522
|
+
return [
|
|
523
|
+
path2.join(home, ".bun", "bin", "bun"),
|
|
524
|
+
"/usr/local/bin/bun",
|
|
525
|
+
"/opt/homebrew/bin/bun",
|
|
526
|
+
"/home/linuxbrew/.linuxbrew/bin/bun"
|
|
527
|
+
];
|
|
528
|
+
}
|
|
529
|
+
async function findBun() {
|
|
530
|
+
const probe = IS_WINDOWS ? await run("where", ["bun"]) : await run("which", ["bun"]);
|
|
531
|
+
if (probe.exitCode === 0 && probe.stdout.trim()) {
|
|
532
|
+
const lines = probe.stdout.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
533
|
+
if (IS_WINDOWS) {
|
|
534
|
+
const cmd = lines.find((l) => l.toLowerCase().endsWith("bun.cmd") || l.toLowerCase().endsWith("bun.exe"));
|
|
535
|
+
if (cmd) return cmd;
|
|
536
|
+
}
|
|
537
|
+
if (lines[0]) return lines[0];
|
|
538
|
+
}
|
|
539
|
+
for (const candidate of fallbackPaths()) {
|
|
540
|
+
if (existsSync(candidate)) return candidate;
|
|
541
|
+
}
|
|
542
|
+
return null;
|
|
543
|
+
}
|
|
544
|
+
async function runInstaller() {
|
|
545
|
+
const result = IS_WINDOWS ? await run("powershell", ["-NoProfile", "-Command", "irm bun.sh/install.ps1 | iex"]) : await run("bash", ["-lc", "curl -fsSL https://bun.sh/install | bash"]);
|
|
546
|
+
if (result.exitCode !== 0) {
|
|
547
|
+
const detail = (result.stderr || result.stdout || "").trim().slice(0, 500);
|
|
548
|
+
return { ok: false, error: detail || `exit ${result.exitCode}` };
|
|
549
|
+
}
|
|
550
|
+
return { ok: true };
|
|
551
|
+
}
|
|
552
|
+
async function ensureBun(t2) {
|
|
553
|
+
const found = await findBun();
|
|
554
|
+
if (found) return { ok: true };
|
|
555
|
+
p2.log.warn(t2("bun.missing"));
|
|
556
|
+
p2.log.info(t2("bun.installerSource"));
|
|
557
|
+
const ans = await p2.confirm({
|
|
558
|
+
message: t2("bun.confirmInstall"),
|
|
559
|
+
initialValue: false
|
|
560
|
+
});
|
|
561
|
+
if (p2.isCancel(ans) || ans === false) {
|
|
562
|
+
return { ok: false, reason: t2("bun.declined") };
|
|
563
|
+
}
|
|
564
|
+
const sp = p2.spinner();
|
|
565
|
+
sp.start(t2("bun.installing"));
|
|
566
|
+
const result = await runInstaller();
|
|
567
|
+
if (!result.ok) {
|
|
568
|
+
sp.stop(t2("bun.installFailedTitle"));
|
|
569
|
+
return { ok: false, reason: t2("bun.installFailedReason", { error: result.error }) };
|
|
570
|
+
}
|
|
571
|
+
sp.stop(t2("bun.installed"));
|
|
572
|
+
const reFound = await findBun();
|
|
573
|
+
if (!reFound) {
|
|
574
|
+
return { ok: false, reason: t2("bun.installedButNotFound") };
|
|
575
|
+
}
|
|
576
|
+
return { ok: true };
|
|
577
|
+
}
|
|
578
|
+
|
|
495
579
|
// src/registry/plugins/claude-mem.ts
|
|
496
580
|
var PLUGIN_ID2 = "claude-mem@thedotmack";
|
|
497
581
|
var PLUGIN_NAME2 = "claude-mem";
|
|
@@ -505,10 +589,11 @@ var claudeMem = {
|
|
|
505
589
|
slashNamespace: "/claude-mem:*",
|
|
506
590
|
whenToUse: 'for cross-session memory search ("did we solve this before?"), phased planning (`make-plan`), or phased execution (`do`).',
|
|
507
591
|
marketplaces: () => [MARKETPLACE_NAME2],
|
|
592
|
+
prereqCheck: (t2) => ensureBun(t2),
|
|
508
593
|
isInstalled: () => isPluginInstalled(PLUGIN_ID2),
|
|
509
594
|
installedVersion: async () => {
|
|
510
|
-
const
|
|
511
|
-
const v =
|
|
595
|
+
const p11 = await findPlugin(PLUGIN_ID2);
|
|
596
|
+
const v = p11?.version;
|
|
512
597
|
return v && v !== "unknown" ? v : null;
|
|
513
598
|
},
|
|
514
599
|
latestVersion: () => getMarketplacePluginVersion(MARKETPLACE_NAME2, PLUGIN_NAME2),
|
|
@@ -522,17 +607,38 @@ var claudeMem = {
|
|
|
522
607
|
var claude_mem_default = claudeMem;
|
|
523
608
|
|
|
524
609
|
// src/registry/plugins/chrome-devtools-mcp.ts
|
|
610
|
+
import { existsSync as existsSync2 } from "fs";
|
|
611
|
+
import path3 from "path";
|
|
525
612
|
var PLUGIN_ID3 = "chrome-devtools-mcp@chrome-devtools-plugins";
|
|
526
613
|
var MARKETPLACE_NAME3 = "chrome-devtools-plugins";
|
|
527
614
|
var MARKETPLACE_SOURCE3 = "ChromeDevTools/chrome-devtools-mcp";
|
|
528
615
|
async function checkChrome() {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
616
|
+
if (process.env.CHROME_PATH && existsSync2(process.env.CHROME_PATH)) return true;
|
|
617
|
+
if (process.platform === "win32") {
|
|
618
|
+
const suffixes = [
|
|
619
|
+
path3.join("Google", "Chrome SxS", "Application", "chrome.exe"),
|
|
620
|
+
path3.join("Google", "Chrome", "Application", "chrome.exe")
|
|
621
|
+
];
|
|
622
|
+
const prefixes = [
|
|
623
|
+
process.env.LOCALAPPDATA,
|
|
624
|
+
process.env.PROGRAMFILES,
|
|
625
|
+
process.env["PROGRAMFILES(X86)"]
|
|
626
|
+
].filter((p11) => Boolean(p11));
|
|
627
|
+
for (const prefix of prefixes) {
|
|
628
|
+
for (const suffix of suffixes) {
|
|
629
|
+
if (existsSync2(path3.join(prefix, suffix))) return true;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
if (process.platform === "darwin") {
|
|
635
|
+
return existsSync2("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome");
|
|
636
|
+
}
|
|
637
|
+
const [viaPath, viaPathChromium] = await Promise.all([
|
|
532
638
|
run("which", ["google-chrome"]),
|
|
533
639
|
run("which", ["chromium"])
|
|
534
640
|
]);
|
|
535
|
-
return
|
|
641
|
+
return viaPath.exitCode === 0 || viaPathChromium.exitCode === 0;
|
|
536
642
|
}
|
|
537
643
|
var chromeDevtoolsMcp = {
|
|
538
644
|
id: "chrome-devtools-mcp",
|
|
@@ -592,8 +698,8 @@ var curdxFlow = {
|
|
|
592
698
|
marketplaces: () => [MARKETPLACE_NAME4],
|
|
593
699
|
isInstalled: () => isPluginInstalled(PLUGIN_ID5),
|
|
594
700
|
installedVersion: async () => {
|
|
595
|
-
const
|
|
596
|
-
const v =
|
|
701
|
+
const p11 = await findPlugin(PLUGIN_ID5);
|
|
702
|
+
const v = p11?.version;
|
|
597
703
|
return v && v !== "unknown" ? v : null;
|
|
598
704
|
},
|
|
599
705
|
latestVersion: () => getMarketplacePluginVersion(MARKETPLACE_NAME4, PLUGIN_NAME3),
|
|
@@ -646,7 +752,7 @@ var sequentialThinking = {
|
|
|
646
752
|
var sequential_thinking_default = sequentialThinking;
|
|
647
753
|
|
|
648
754
|
// src/registry/mcps/context7.ts
|
|
649
|
-
import * as
|
|
755
|
+
import * as p3 from "@clack/prompts";
|
|
650
756
|
var MCP_NAME2 = "context7";
|
|
651
757
|
var URL = "https://mcp.context7.com/mcp";
|
|
652
758
|
var context7 = {
|
|
@@ -657,14 +763,14 @@ var context7 = {
|
|
|
657
763
|
whenToUse: "for any library / SDK / framework / API / Claude Code docs lookup. Use instead of web search.",
|
|
658
764
|
isInstalled: () => isMcpInstalled(MCP_NAME2),
|
|
659
765
|
configPrompts: async ({ t: t2 }) => {
|
|
660
|
-
|
|
766
|
+
p3.note(`${t2("context7.dashboardHint")}
|
|
661
767
|
${t2("context7.keyWarning")}`, "context7");
|
|
662
|
-
const key = await
|
|
768
|
+
const key = await p3.text({
|
|
663
769
|
message: t2("context7.askKey"),
|
|
664
770
|
placeholder: t2("context7.keyPlaceholder"),
|
|
665
771
|
defaultValue: ""
|
|
666
772
|
});
|
|
667
|
-
if (
|
|
773
|
+
if (p3.isCancel(key)) return null;
|
|
668
774
|
const trimmed = String(key ?? "").trim();
|
|
669
775
|
const out = {};
|
|
670
776
|
if (trimmed) out["CONTEXT7_API_KEY"] = trimmed;
|
|
@@ -708,19 +814,19 @@ var PKGS = [
|
|
|
708
814
|
context7_default
|
|
709
815
|
];
|
|
710
816
|
function findPkg(id) {
|
|
711
|
-
return PKGS.find((
|
|
817
|
+
return PKGS.find((p11) => p11.id === id);
|
|
712
818
|
}
|
|
713
819
|
|
|
714
820
|
// src/runner/claudeMd.ts
|
|
715
821
|
import { promises as fs2 } from "fs";
|
|
716
|
-
import
|
|
822
|
+
import path4 from "path";
|
|
717
823
|
import os2 from "os";
|
|
718
|
-
import * as
|
|
824
|
+
import * as p4 from "@clack/prompts";
|
|
719
825
|
var BEGIN_MARKER = "<!-- BEGIN @curdx/flow v1 -->";
|
|
720
826
|
var END_MARKER = "<!-- END @curdx/flow v1 -->";
|
|
721
827
|
var BLOCK_RE = /<!-- BEGIN @curdx\/flow v\d+[^>]*-->[\s\S]*?<!-- END @curdx\/flow v\d+ -->/;
|
|
722
828
|
function claudeMdPath() {
|
|
723
|
-
return
|
|
829
|
+
return path4.join(os2.homedir(), ".claude", "CLAUDE.md");
|
|
724
830
|
}
|
|
725
831
|
function buildCombinationPatterns(ids) {
|
|
726
832
|
const has = (k) => ids.has(k);
|
|
@@ -896,7 +1002,7 @@ async function syncClaudeMd(opts) {
|
|
|
896
1002
|
if (next === existing) {
|
|
897
1003
|
return { status: "unchanged", path: file };
|
|
898
1004
|
}
|
|
899
|
-
await fs2.mkdir(
|
|
1005
|
+
await fs2.mkdir(path4.dirname(file), { recursive: true });
|
|
900
1006
|
const tmp = `${file}.tmp.${process.pid}`;
|
|
901
1007
|
await fs2.writeFile(tmp, next, "utf8");
|
|
902
1008
|
await fs2.rename(tmp, file);
|
|
@@ -910,10 +1016,10 @@ async function syncClaudeMd(opts) {
|
|
|
910
1016
|
}
|
|
911
1017
|
async function syncFromState(opts) {
|
|
912
1018
|
if (opts?.skip) {
|
|
913
|
-
|
|
1019
|
+
p4.log.info(t("claudeMd.skipped"));
|
|
914
1020
|
return;
|
|
915
1021
|
}
|
|
916
|
-
const sp =
|
|
1022
|
+
const sp = p4.spinner();
|
|
917
1023
|
sp.start(t("claudeMd.syncing"));
|
|
918
1024
|
const r = await syncClaudeMd();
|
|
919
1025
|
switch (r.status) {
|
|
@@ -968,7 +1074,7 @@ async function selectInteractive(states) {
|
|
|
968
1074
|
const optionalPkgs = PKGS.filter((pkg) => !pkg.required);
|
|
969
1075
|
if (requiredPkgs.length > 0) {
|
|
970
1076
|
const lines = requiredPkgs.map((pkg) => ` ${stateLabel(pkg, states.get(pkg.id))}`);
|
|
971
|
-
|
|
1077
|
+
p5.note(lines.join("\n"), t("install.requiredHeader"));
|
|
972
1078
|
}
|
|
973
1079
|
const options = optionalPkgs.map((pkg) => {
|
|
974
1080
|
const s = states.get(pkg.id);
|
|
@@ -978,13 +1084,13 @@ async function selectInteractive(states) {
|
|
|
978
1084
|
const s = states.get(pkg.id);
|
|
979
1085
|
return s.kind === "not_installed" || s.kind === "update_available";
|
|
980
1086
|
}).map((pkg) => pkg.id);
|
|
981
|
-
const picked = await
|
|
1087
|
+
const picked = await p5.multiselect({
|
|
982
1088
|
message: t("install.selectPrompt"),
|
|
983
1089
|
options,
|
|
984
1090
|
initialValues,
|
|
985
1091
|
required: false
|
|
986
1092
|
});
|
|
987
|
-
if (
|
|
1093
|
+
if (p5.isCancel(picked)) return null;
|
|
988
1094
|
const userPicked = picked.map((id) => findPkg(id)).filter((x2) => Boolean(x2));
|
|
989
1095
|
const requiredAuto = requiredPkgs.filter((pkg) => states.get(pkg.id)?.kind !== "up_to_date");
|
|
990
1096
|
return [...requiredAuto, ...userPicked];
|
|
@@ -996,7 +1102,7 @@ function selectFromIds(opts) {
|
|
|
996
1102
|
for (const id of opts.ids) {
|
|
997
1103
|
const pkg = findPkg(id);
|
|
998
1104
|
if (pkg) found.push(pkg);
|
|
999
|
-
else
|
|
1105
|
+
else p5.log.warn(`Unknown id: ${id}`);
|
|
1000
1106
|
}
|
|
1001
1107
|
return found;
|
|
1002
1108
|
}
|
|
@@ -1008,11 +1114,11 @@ async function runOne(pkg, state, opts) {
|
|
|
1008
1114
|
mode = "update";
|
|
1009
1115
|
} else {
|
|
1010
1116
|
if (!opts.yes) {
|
|
1011
|
-
const ans = await
|
|
1117
|
+
const ans = await p5.confirm({
|
|
1012
1118
|
message: t("install.confirmReinstall", { name: pkg.name }),
|
|
1013
1119
|
initialValue: false
|
|
1014
1120
|
});
|
|
1015
|
-
if (
|
|
1121
|
+
if (p5.isCancel(ans) || ans === false) {
|
|
1016
1122
|
return { id: pkg.id, status: "skip", message: t("install.skippedReinstall", { name: pkg.name }) };
|
|
1017
1123
|
}
|
|
1018
1124
|
}
|
|
@@ -1021,7 +1127,7 @@ async function runOne(pkg, state, opts) {
|
|
|
1021
1127
|
if (pkg.prereqCheck) {
|
|
1022
1128
|
const r = await pkg.prereqCheck(t);
|
|
1023
1129
|
if (!r.ok) {
|
|
1024
|
-
|
|
1130
|
+
p5.log.warn(t("install.prereqFail", { name: pkg.name, reason: r.reason }));
|
|
1025
1131
|
return { id: pkg.id, status: "skip", message: r.reason };
|
|
1026
1132
|
}
|
|
1027
1133
|
}
|
|
@@ -1036,30 +1142,30 @@ async function runOne(pkg, state, opts) {
|
|
|
1036
1142
|
if (mode === "update" && state.kind === "update_available") {
|
|
1037
1143
|
titleVars["version"] = state.latest;
|
|
1038
1144
|
}
|
|
1039
|
-
const
|
|
1145
|
+
const log6 = p5.taskLog({ title: t(titleKey, titleVars) });
|
|
1040
1146
|
try {
|
|
1041
1147
|
if (mode === "reinstall") {
|
|
1042
|
-
|
|
1043
|
-
await pkg.uninstall({ log:
|
|
1044
|
-
|
|
1045
|
-
await pkg.install({ log:
|
|
1148
|
+
log6.message(t("reinstall.uninstalling"));
|
|
1149
|
+
await pkg.uninstall({ log: log6, config, t });
|
|
1150
|
+
log6.message(t("reinstall.installing"));
|
|
1151
|
+
await pkg.install({ log: log6, config, t });
|
|
1046
1152
|
} else if (mode === "update") {
|
|
1047
1153
|
if (pkg.update) {
|
|
1048
|
-
await pkg.update({ log:
|
|
1154
|
+
await pkg.update({ log: log6, config, t });
|
|
1049
1155
|
} else {
|
|
1050
|
-
|
|
1051
|
-
await pkg.uninstall({ log:
|
|
1052
|
-
|
|
1053
|
-
await pkg.install({ log:
|
|
1156
|
+
log6.message(t("reinstall.uninstalling"));
|
|
1157
|
+
await pkg.uninstall({ log: log6, config, t });
|
|
1158
|
+
log6.message(t("reinstall.installing"));
|
|
1159
|
+
await pkg.install({ log: log6, config, t });
|
|
1054
1160
|
}
|
|
1055
1161
|
} else {
|
|
1056
|
-
await pkg.install({ log:
|
|
1162
|
+
await pkg.install({ log: log6, config, t });
|
|
1057
1163
|
}
|
|
1058
|
-
|
|
1164
|
+
log6.success(t("install.success", { name: pkg.name }));
|
|
1059
1165
|
return { id: pkg.id, status: "ok" };
|
|
1060
1166
|
} catch (err) {
|
|
1061
1167
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1062
|
-
|
|
1168
|
+
log6.error(`${t("install.failed", { name: pkg.name })}
|
|
1063
1169
|
${msg}`);
|
|
1064
1170
|
return { id: pkg.id, status: "fail", message: msg };
|
|
1065
1171
|
}
|
|
@@ -1077,7 +1183,7 @@ function summarize(results) {
|
|
|
1077
1183
|
...skip.map((r) => ` ${pc.yellow("-")} ${r.id}${r.message ? pc.dim(` (${r.message})`) : ""}`),
|
|
1078
1184
|
...fail.map((r) => ` ${pc.red("\u2717")} ${r.id}${r.message ? pc.dim(` (${r.message.split("\n")[0]})`) : ""}`)
|
|
1079
1185
|
];
|
|
1080
|
-
|
|
1186
|
+
p5.note(lines.join("\n"), t("install.summaryTitle"));
|
|
1081
1187
|
}
|
|
1082
1188
|
async function maybeRefreshMarketplaces(opts) {
|
|
1083
1189
|
if (opts.noRefresh) return;
|
|
@@ -1086,7 +1192,7 @@ async function maybeRefreshMarketplaces(opts) {
|
|
|
1086
1192
|
if (pkg.marketplaces) for (const n of pkg.marketplaces()) names.add(n);
|
|
1087
1193
|
}
|
|
1088
1194
|
if (names.size === 0) return;
|
|
1089
|
-
const sp =
|
|
1195
|
+
const sp = p5.spinner();
|
|
1090
1196
|
sp.start(t("marketplace.refreshing"));
|
|
1091
1197
|
const refreshed = await refreshMarketplaces([...names]);
|
|
1092
1198
|
sp.stop(
|
|
@@ -1100,7 +1206,7 @@ async function installFlow(opts = {}) {
|
|
|
1100
1206
|
const explicit = opts.all || opts.ids && opts.ids.length > 0;
|
|
1101
1207
|
const candidates = explicit ? selectFromIds(opts) : [...PKGS];
|
|
1102
1208
|
if (candidates.length === 0) {
|
|
1103
|
-
|
|
1209
|
+
p5.log.info(t("install.nothingSelected"));
|
|
1104
1210
|
return;
|
|
1105
1211
|
}
|
|
1106
1212
|
if (opts.ids && opts.ids.length > 0) {
|
|
@@ -1111,7 +1217,7 @@ async function installFlow(opts = {}) {
|
|
|
1111
1217
|
}
|
|
1112
1218
|
}
|
|
1113
1219
|
const stateMap = /* @__PURE__ */ new Map();
|
|
1114
|
-
const sp =
|
|
1220
|
+
const sp = p5.spinner();
|
|
1115
1221
|
sp.start(t("state.checking"));
|
|
1116
1222
|
try {
|
|
1117
1223
|
await Promise.all([listPlugins(), listMcp()]);
|
|
@@ -1139,13 +1245,13 @@ async function installFlow(opts = {}) {
|
|
|
1139
1245
|
const picked = await selectInteractive(stateMap);
|
|
1140
1246
|
if (picked === null) {
|
|
1141
1247
|
userCancelled = true;
|
|
1142
|
-
|
|
1248
|
+
p5.cancel(t("app.cancelled"));
|
|
1143
1249
|
return;
|
|
1144
1250
|
}
|
|
1145
1251
|
targets = picked;
|
|
1146
1252
|
}
|
|
1147
1253
|
if (targets.length === 0) {
|
|
1148
|
-
|
|
1254
|
+
p5.log.info(t("install.nothingSelected"));
|
|
1149
1255
|
return;
|
|
1150
1256
|
}
|
|
1151
1257
|
const results = [];
|
|
@@ -1162,14 +1268,14 @@ async function installFlow(opts = {}) {
|
|
|
1162
1268
|
}
|
|
1163
1269
|
|
|
1164
1270
|
// src/flows/uninstall.ts
|
|
1165
|
-
import * as
|
|
1271
|
+
import * as p6 from "@clack/prompts";
|
|
1166
1272
|
import pc2 from "picocolors";
|
|
1167
1273
|
async function getInstalled() {
|
|
1168
1274
|
const states = await Promise.all(PKGS.map(async (pkg) => ({ pkg, installed: await pkg.isInstalled() })));
|
|
1169
1275
|
return states.filter((s) => s.installed).map((s) => s.pkg);
|
|
1170
1276
|
}
|
|
1171
1277
|
async function probeInstalled() {
|
|
1172
|
-
const sp =
|
|
1278
|
+
const sp = p6.spinner();
|
|
1173
1279
|
sp.start(t("state.checking"));
|
|
1174
1280
|
try {
|
|
1175
1281
|
await Promise.all([listPlugins(), listMcp()]);
|
|
@@ -1191,21 +1297,21 @@ async function uninstallFlow(opts = {}) {
|
|
|
1191
1297
|
for (const id of opts.ids) {
|
|
1192
1298
|
const pkg = findPkg(id);
|
|
1193
1299
|
if (!pkg) {
|
|
1194
|
-
|
|
1300
|
+
p6.log.warn(`Unknown id: ${id}`);
|
|
1195
1301
|
continue;
|
|
1196
1302
|
}
|
|
1197
1303
|
if (!installed.some((x2) => x2.id === pkg.id)) {
|
|
1198
|
-
|
|
1304
|
+
p6.log.warn(`${pkg.name}: ${t("pkg.notInstalled")}`);
|
|
1199
1305
|
continue;
|
|
1200
1306
|
}
|
|
1201
1307
|
targets.push(pkg);
|
|
1202
1308
|
}
|
|
1203
1309
|
} else {
|
|
1204
1310
|
if (installed.length === 0) {
|
|
1205
|
-
|
|
1311
|
+
p6.log.info(t("uninstall.noneInstalled"));
|
|
1206
1312
|
return;
|
|
1207
1313
|
}
|
|
1208
|
-
const picked = await
|
|
1314
|
+
const picked = await p6.multiselect({
|
|
1209
1315
|
message: t("uninstall.selectPrompt"),
|
|
1210
1316
|
options: installed.map((pkg) => ({
|
|
1211
1317
|
value: pkg.id,
|
|
@@ -1214,45 +1320,45 @@ async function uninstallFlow(opts = {}) {
|
|
|
1214
1320
|
})),
|
|
1215
1321
|
required: false
|
|
1216
1322
|
});
|
|
1217
|
-
if (
|
|
1323
|
+
if (p6.isCancel(picked)) {
|
|
1218
1324
|
userCancelled = true;
|
|
1219
|
-
|
|
1325
|
+
p6.cancel(t("app.cancelled"));
|
|
1220
1326
|
return;
|
|
1221
1327
|
}
|
|
1222
1328
|
targets = picked.map((id) => findPkg(id)).filter((x2) => Boolean(x2));
|
|
1223
1329
|
}
|
|
1224
1330
|
if (targets.length === 0) {
|
|
1225
|
-
|
|
1331
|
+
p6.log.info(t("install.nothingSelected"));
|
|
1226
1332
|
return;
|
|
1227
1333
|
}
|
|
1228
1334
|
if (!opts.yes) {
|
|
1229
|
-
const ok2 = await
|
|
1335
|
+
const ok2 = await p6.confirm({
|
|
1230
1336
|
message: t("uninstall.confirm", { count: targets.length }),
|
|
1231
1337
|
initialValue: false
|
|
1232
1338
|
});
|
|
1233
|
-
if (
|
|
1339
|
+
if (p6.isCancel(ok2) || ok2 === false) {
|
|
1234
1340
|
userCancelled = true;
|
|
1235
|
-
|
|
1341
|
+
p6.cancel(t("app.cancelled"));
|
|
1236
1342
|
return;
|
|
1237
1343
|
}
|
|
1238
1344
|
}
|
|
1239
1345
|
const results = [];
|
|
1240
1346
|
for (const pkg of targets) {
|
|
1241
|
-
const
|
|
1347
|
+
const log6 = p6.taskLog({ title: t("uninstall.starting", { name: pkg.name }) });
|
|
1242
1348
|
try {
|
|
1243
|
-
await pkg.uninstall({ log:
|
|
1244
|
-
|
|
1349
|
+
await pkg.uninstall({ log: log6, config: {}, t });
|
|
1350
|
+
log6.success(t("uninstall.success", { name: pkg.name }));
|
|
1245
1351
|
results.push({ id: pkg.id, status: "ok" });
|
|
1246
1352
|
} catch (err) {
|
|
1247
1353
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1248
|
-
|
|
1354
|
+
log6.error(`${t("uninstall.failed", { name: pkg.name })}
|
|
1249
1355
|
${msg}`);
|
|
1250
1356
|
results.push({ id: pkg.id, status: "fail", message: msg });
|
|
1251
1357
|
}
|
|
1252
1358
|
}
|
|
1253
1359
|
const ok = results.filter((r) => r.status === "ok").length;
|
|
1254
1360
|
const fail = results.filter((r) => r.status === "fail").length;
|
|
1255
|
-
|
|
1361
|
+
p6.note(
|
|
1256
1362
|
[
|
|
1257
1363
|
pc2.green(t("install.summaryOk", { count: ok })),
|
|
1258
1364
|
pc2.red(t("install.summaryFail", { count: fail }))
|
|
@@ -1267,14 +1373,14 @@ ${msg}`);
|
|
|
1267
1373
|
}
|
|
1268
1374
|
|
|
1269
1375
|
// src/flows/update.ts
|
|
1270
|
-
import * as
|
|
1376
|
+
import * as p7 from "@clack/prompts";
|
|
1271
1377
|
import pc3 from "picocolors";
|
|
1272
1378
|
async function getInstalled2() {
|
|
1273
1379
|
const states = await Promise.all(PKGS.map(async (pkg) => ({ pkg, installed: await pkg.isInstalled() })));
|
|
1274
1380
|
return states.filter((s) => s.installed).map((s) => s.pkg);
|
|
1275
1381
|
}
|
|
1276
1382
|
async function probeInstalled2() {
|
|
1277
|
-
const sp =
|
|
1383
|
+
const sp = p7.spinner();
|
|
1278
1384
|
sp.start(t("state.checking"));
|
|
1279
1385
|
try {
|
|
1280
1386
|
await Promise.all([listPlugins(), listMcp()]);
|
|
@@ -1291,7 +1397,7 @@ async function updateFlow(opts = {}) {
|
|
|
1291
1397
|
try {
|
|
1292
1398
|
const installed = await probeInstalled2();
|
|
1293
1399
|
if (installed.length === 0) {
|
|
1294
|
-
|
|
1400
|
+
p7.log.info(t("update.noneInstalled"));
|
|
1295
1401
|
return;
|
|
1296
1402
|
}
|
|
1297
1403
|
let targets;
|
|
@@ -1302,17 +1408,17 @@ async function updateFlow(opts = {}) {
|
|
|
1302
1408
|
for (const id of opts.ids) {
|
|
1303
1409
|
const pkg = findPkg(id);
|
|
1304
1410
|
if (!pkg) {
|
|
1305
|
-
|
|
1411
|
+
p7.log.warn(`Unknown id: ${id}`);
|
|
1306
1412
|
continue;
|
|
1307
1413
|
}
|
|
1308
1414
|
if (!installed.some((x2) => x2.id === pkg.id)) {
|
|
1309
|
-
|
|
1415
|
+
p7.log.warn(`${pkg.name}: ${t("pkg.notInstalled")}`);
|
|
1310
1416
|
continue;
|
|
1311
1417
|
}
|
|
1312
1418
|
targets.push(pkg);
|
|
1313
1419
|
}
|
|
1314
1420
|
} else {
|
|
1315
|
-
const picked = await
|
|
1421
|
+
const picked = await p7.multiselect({
|
|
1316
1422
|
message: t("update.selectPrompt"),
|
|
1317
1423
|
options: installed.map((pkg) => ({
|
|
1318
1424
|
value: pkg.id,
|
|
@@ -1321,42 +1427,42 @@ async function updateFlow(opts = {}) {
|
|
|
1321
1427
|
})),
|
|
1322
1428
|
required: false
|
|
1323
1429
|
});
|
|
1324
|
-
if (
|
|
1430
|
+
if (p7.isCancel(picked)) {
|
|
1325
1431
|
userCancelled = true;
|
|
1326
|
-
|
|
1432
|
+
p7.cancel(t("app.cancelled"));
|
|
1327
1433
|
return;
|
|
1328
1434
|
}
|
|
1329
1435
|
targets = picked.map((id) => findPkg(id)).filter((x2) => Boolean(x2));
|
|
1330
1436
|
}
|
|
1331
1437
|
if (targets.length === 0) {
|
|
1332
|
-
|
|
1438
|
+
p7.log.info(t("install.nothingSelected"));
|
|
1333
1439
|
return;
|
|
1334
1440
|
}
|
|
1335
1441
|
const results = [];
|
|
1336
1442
|
for (const pkg of targets) {
|
|
1337
1443
|
if (pkg.id === "sequential-thinking") {
|
|
1338
|
-
|
|
1444
|
+
p7.log.info(t("update.mcpAutoNote", { name: pkg.name }));
|
|
1339
1445
|
results.push({ id: pkg.id, status: "noop" });
|
|
1340
1446
|
continue;
|
|
1341
1447
|
}
|
|
1342
1448
|
if (pkg.id === "context7") {
|
|
1343
|
-
|
|
1449
|
+
p7.log.info(t("update.context7Note"));
|
|
1344
1450
|
results.push({ id: pkg.id, status: "noop" });
|
|
1345
1451
|
continue;
|
|
1346
1452
|
}
|
|
1347
|
-
const
|
|
1453
|
+
const log6 = p7.taskLog({ title: t("update.starting", { name: pkg.name }) });
|
|
1348
1454
|
try {
|
|
1349
1455
|
if (pkg.update) {
|
|
1350
|
-
await pkg.update({ log:
|
|
1456
|
+
await pkg.update({ log: log6, config: {}, t });
|
|
1351
1457
|
} else {
|
|
1352
|
-
await pkg.uninstall({ log:
|
|
1353
|
-
await pkg.install({ log:
|
|
1458
|
+
await pkg.uninstall({ log: log6, config: {}, t });
|
|
1459
|
+
await pkg.install({ log: log6, config: {}, t });
|
|
1354
1460
|
}
|
|
1355
|
-
|
|
1461
|
+
log6.success(t("update.success", { name: pkg.name }));
|
|
1356
1462
|
results.push({ id: pkg.id, status: "ok" });
|
|
1357
1463
|
} catch (err) {
|
|
1358
1464
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1359
|
-
|
|
1465
|
+
log6.error(`${t("update.failed", { name: pkg.name })}
|
|
1360
1466
|
${msg}`);
|
|
1361
1467
|
results.push({ id: pkg.id, status: "fail", message: msg });
|
|
1362
1468
|
}
|
|
@@ -1364,7 +1470,7 @@ ${msg}`);
|
|
|
1364
1470
|
const ok = results.filter((r) => r.status === "ok").length;
|
|
1365
1471
|
const fail = results.filter((r) => r.status === "fail").length;
|
|
1366
1472
|
const noop = results.filter((r) => r.status === "noop").length;
|
|
1367
|
-
|
|
1473
|
+
p7.note(
|
|
1368
1474
|
[
|
|
1369
1475
|
pc3.green(t("install.summaryOk", { count: ok })),
|
|
1370
1476
|
pc3.red(t("install.summaryFail", { count: fail })),
|
|
@@ -1380,7 +1486,7 @@ ${msg}`);
|
|
|
1380
1486
|
}
|
|
1381
1487
|
|
|
1382
1488
|
// src/flows/status.ts
|
|
1383
|
-
import * as
|
|
1489
|
+
import * as p8 from "@clack/prompts";
|
|
1384
1490
|
import pc4 from "picocolors";
|
|
1385
1491
|
async function statusFlow(opts = {}) {
|
|
1386
1492
|
const states = await Promise.all(
|
|
@@ -1413,12 +1519,12 @@ async function statusFlow(opts = {}) {
|
|
|
1413
1519
|
const rows = states.map(
|
|
1414
1520
|
(s) => `${s.name.padEnd(nameW)} ${s.type.padEnd(typeW)} ${s.installed ? pc4.green(`\u2713 ${t("pkg.installed")}`) : pc4.yellow(`\u2717 ${t("pkg.notInstalled")}`)}`
|
|
1415
1521
|
);
|
|
1416
|
-
|
|
1522
|
+
p8.note([header, sep, ...rows].join("\n"), t("status.title"));
|
|
1417
1523
|
}
|
|
1418
1524
|
|
|
1419
1525
|
// src/ui/menu.ts
|
|
1420
1526
|
async function mainMenu() {
|
|
1421
|
-
const action = await
|
|
1527
|
+
const action = await p9.select({
|
|
1422
1528
|
message: t("menu.title"),
|
|
1423
1529
|
options: [
|
|
1424
1530
|
{ value: "install", label: t("menu.install") },
|
|
@@ -1428,8 +1534,8 @@ async function mainMenu() {
|
|
|
1428
1534
|
{ value: "exit", label: t("menu.exit") }
|
|
1429
1535
|
]
|
|
1430
1536
|
});
|
|
1431
|
-
if (
|
|
1432
|
-
|
|
1537
|
+
if (p9.isCancel(action) || action === "exit") {
|
|
1538
|
+
p9.cancel(t("app.cancelled"));
|
|
1433
1539
|
return;
|
|
1434
1540
|
}
|
|
1435
1541
|
switch (action) {
|
|
@@ -1474,7 +1580,7 @@ var installCmd = defineCommand({
|
|
|
1474
1580
|
},
|
|
1475
1581
|
async run({ args }) {
|
|
1476
1582
|
await initLanguage(parseLang(args.lang));
|
|
1477
|
-
|
|
1583
|
+
p10.intro(t("app.intro"));
|
|
1478
1584
|
const ids = collectPositional(args);
|
|
1479
1585
|
await installFlow({
|
|
1480
1586
|
ids,
|
|
@@ -1483,7 +1589,7 @@ var installCmd = defineCommand({
|
|
|
1483
1589
|
noRefresh: Boolean(args["no-refresh"]),
|
|
1484
1590
|
noClaudeMd: noClaudeMdFromArgs(args)
|
|
1485
1591
|
});
|
|
1486
|
-
|
|
1592
|
+
p10.outro(t("app.outro"));
|
|
1487
1593
|
}
|
|
1488
1594
|
});
|
|
1489
1595
|
var uninstallCmd = defineCommand({
|
|
@@ -1495,14 +1601,14 @@ var uninstallCmd = defineCommand({
|
|
|
1495
1601
|
},
|
|
1496
1602
|
async run({ args }) {
|
|
1497
1603
|
await initLanguage(parseLang(args.lang));
|
|
1498
|
-
|
|
1604
|
+
p10.intro(t("app.intro"));
|
|
1499
1605
|
const ids = collectPositional(args);
|
|
1500
1606
|
await uninstallFlow({
|
|
1501
1607
|
ids,
|
|
1502
1608
|
yes: Boolean(args.yes),
|
|
1503
1609
|
noClaudeMd: noClaudeMdFromArgs(args)
|
|
1504
1610
|
});
|
|
1505
|
-
|
|
1611
|
+
p10.outro(t("app.outro"));
|
|
1506
1612
|
}
|
|
1507
1613
|
});
|
|
1508
1614
|
var updateCmd = defineCommand({
|
|
@@ -1514,14 +1620,14 @@ var updateCmd = defineCommand({
|
|
|
1514
1620
|
},
|
|
1515
1621
|
async run({ args }) {
|
|
1516
1622
|
await initLanguage(parseLang(args.lang));
|
|
1517
|
-
|
|
1623
|
+
p10.intro(t("app.intro"));
|
|
1518
1624
|
const ids = collectPositional(args);
|
|
1519
1625
|
await updateFlow({
|
|
1520
1626
|
ids,
|
|
1521
1627
|
all: Boolean(args.all),
|
|
1522
1628
|
noClaudeMd: noClaudeMdFromArgs(args)
|
|
1523
1629
|
});
|
|
1524
|
-
|
|
1630
|
+
p10.outro(t("app.outro"));
|
|
1525
1631
|
}
|
|
1526
1632
|
});
|
|
1527
1633
|
var statusCmd = defineCommand({
|
|
@@ -1532,9 +1638,9 @@ var statusCmd = defineCommand({
|
|
|
1532
1638
|
},
|
|
1533
1639
|
async run({ args }) {
|
|
1534
1640
|
await initLanguage(parseLang(args.lang));
|
|
1535
|
-
if (!args.json)
|
|
1641
|
+
if (!args.json) p10.intro(t("app.intro"));
|
|
1536
1642
|
await statusFlow({ json: Boolean(args.json) });
|
|
1537
|
-
if (!args.json)
|
|
1643
|
+
if (!args.json) p10.outro(t("app.outro"));
|
|
1538
1644
|
}
|
|
1539
1645
|
});
|
|
1540
1646
|
var SUBCOMMANDS = /* @__PURE__ */ new Set(["install", "uninstall", "update", "status"]);
|
|
@@ -1576,9 +1682,9 @@ async function runInteractive(argv2) {
|
|
|
1576
1682
|
else if (argv2[i]?.startsWith("--lang=")) lang = parseLang(argv2[i].slice("--lang=".length));
|
|
1577
1683
|
}
|
|
1578
1684
|
await initLanguage(lang);
|
|
1579
|
-
|
|
1685
|
+
p10.intro(t("app.intro"));
|
|
1580
1686
|
await mainMenu();
|
|
1581
|
-
|
|
1687
|
+
p10.outro(t("app.outro"));
|
|
1582
1688
|
}
|
|
1583
1689
|
var argv = process.argv.slice(2);
|
|
1584
1690
|
var first = firstNonFlag(argv);
|