@curdx/flow 3.3.0 → 3.3.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 +13 -0
- package/dist/index.mjs +245 -178
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
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
|
+
## 3.3.2 — 2026-04-27
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **CLAUDE.md sync no longer skipped on the "nothing selected" path** — when a user upgraded flow with all tools already installed and ran `install`, the multiselect would show nothing pre-checked; pressing enter without a selection caused the flow to early-return before reaching the sync step, so the managed block was never added to CLAUDE.md. Each of `install` / `update` / `uninstall` now wraps its body in `try / finally` and runs the sync at the end of any non-cancelled exit (including "nothing to do" paths). User-cancelled flows (Ctrl+C, multiselect cancel, uninstall confirm "no") still skip the sync to respect intent.
|
|
10
|
+
|
|
11
|
+
## 3.3.1 — 2026-04-27
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **Silent stalls between phases** — added spinners to the previously-silent windows where flow shells out to `claude plugin list --json` and `claude mcp list` (the latter performs an MCP server health check and can take 5-15 seconds). Affected sites: `install` (state-derivation between marketplace refresh and the multiselect), `update` and `uninstall` (state-derivation at flow entry), and the post-flow CLAUDE.md sync (after install/update/uninstall busts the cache, sync re-queries state). Each now shows `Checking installed state… (claude plugin list / mcp list)` with a result line so the run no longer feels frozen.
|
|
16
|
+
- **CLAUDE.md sync feedback** — replaced the post-hoc `p.log.info` line with a live spinner that converts to a final status line on completion, matching the marketplace-refresh and per-item install UX.
|
|
17
|
+
|
|
5
18
|
## 3.3.0 — 2026-04-27
|
|
6
19
|
|
|
7
20
|
### Added
|
package/dist/index.mjs
CHANGED
|
@@ -67,6 +67,9 @@ var messages = {
|
|
|
67
67
|
"chrome.prereqChrome": "\u9700\u8981\u672C\u673A\u5DF2\u5B89\u88C5 Chrome\uFF08chrome-devtools-mcp \u4F1A\u8C03\u7528\u672C\u5730\u6D4F\u89C8\u5668\uFF09",
|
|
68
68
|
"reinstall.uninstalling": "\u5148\u5378\u8F7D\u65E7\u7248\u672C\u2026",
|
|
69
69
|
"reinstall.installing": "\u5B89\u88C5\u65B0\u7248\u672C\u2026",
|
|
70
|
+
"state.checking": "\u68C0\u67E5\u5DF2\u5B89\u88C5\u72B6\u6001\u2026\uFF08claude plugin list / mcp list\uFF09",
|
|
71
|
+
"state.checked": "\u5DF2\u68C0\u67E5 {count} \u9879",
|
|
72
|
+
"claudeMd.syncing": "\u540C\u6B65 ~/.claude/CLAUDE.md \u2026",
|
|
70
73
|
"claudeMd.synced": "CLAUDE.md \u5DF2\u66F4\u65B0\uFF08{path}\uFF09",
|
|
71
74
|
"claudeMd.unchanged": "CLAUDE.md \u5DF2\u662F\u6700\u65B0",
|
|
72
75
|
"claudeMd.removed": "\u5DF2\u4ECE CLAUDE.md \u79FB\u9664 @curdx/flow \u533A\u5757",
|
|
@@ -135,6 +138,9 @@ var messages2 = {
|
|
|
135
138
|
"chrome.prereqChrome": "Requires Chrome installed locally (chrome-devtools-mcp drives the local browser)",
|
|
136
139
|
"reinstall.uninstalling": "Uninstalling old version\u2026",
|
|
137
140
|
"reinstall.installing": "Installing new version\u2026",
|
|
141
|
+
"state.checking": "Checking installed state\u2026 (claude plugin list / mcp list)",
|
|
142
|
+
"state.checked": "Checked {count} item(s)",
|
|
143
|
+
"claudeMd.syncing": "Syncing ~/.claude/CLAUDE.md\u2026",
|
|
138
144
|
"claudeMd.synced": "CLAUDE.md updated ({path})",
|
|
139
145
|
"claudeMd.unchanged": "CLAUDE.md already up to date",
|
|
140
146
|
"claudeMd.removed": "Removed @curdx/flow block from CLAUDE.md",
|
|
@@ -769,23 +775,29 @@ async function syncClaudeMd(opts) {
|
|
|
769
775
|
}
|
|
770
776
|
}
|
|
771
777
|
async function syncFromState(opts) {
|
|
772
|
-
|
|
778
|
+
if (opts?.skip) {
|
|
779
|
+
p3.log.info(t("claudeMd.skipped"));
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
const sp = p3.spinner();
|
|
783
|
+
sp.start(t("claudeMd.syncing"));
|
|
784
|
+
const r = await syncClaudeMd();
|
|
773
785
|
switch (r.status) {
|
|
774
786
|
case "skipped":
|
|
775
|
-
|
|
787
|
+
sp.stop(t("claudeMd.skipped"));
|
|
776
788
|
return;
|
|
777
789
|
case "unchanged":
|
|
778
|
-
|
|
790
|
+
sp.stop(t("claudeMd.unchanged"));
|
|
779
791
|
return;
|
|
780
792
|
case "created":
|
|
781
793
|
case "updated":
|
|
782
|
-
|
|
794
|
+
sp.stop(t("claudeMd.synced", { path: r.path }));
|
|
783
795
|
return;
|
|
784
796
|
case "removed":
|
|
785
|
-
|
|
797
|
+
sp.stop(t("claudeMd.removed"));
|
|
786
798
|
return;
|
|
787
799
|
case "failed":
|
|
788
|
-
|
|
800
|
+
sp.stop(t("claudeMd.failed", { error: r.error ?? "unknown" }));
|
|
789
801
|
return;
|
|
790
802
|
}
|
|
791
803
|
}
|
|
@@ -940,41 +952,55 @@ async function maybeRefreshMarketplaces(opts) {
|
|
|
940
952
|
);
|
|
941
953
|
}
|
|
942
954
|
async function installFlow(opts = {}) {
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
const stateMap = /* @__PURE__ */ new Map();
|
|
951
|
-
await Promise.all(
|
|
952
|
-
candidates.map(async (pkg) => {
|
|
953
|
-
stateMap.set(pkg.id, await deriveState(pkg));
|
|
954
|
-
})
|
|
955
|
-
);
|
|
956
|
-
let targets;
|
|
957
|
-
if (explicit) {
|
|
958
|
-
targets = candidates;
|
|
959
|
-
} else {
|
|
960
|
-
const picked = await selectInteractive(stateMap);
|
|
961
|
-
if (picked === null) {
|
|
962
|
-
p4.cancel(t("app.cancelled"));
|
|
955
|
+
let userCancelled = false;
|
|
956
|
+
try {
|
|
957
|
+
await maybeRefreshMarketplaces(opts);
|
|
958
|
+
const explicit = opts.all || opts.ids && opts.ids.length > 0;
|
|
959
|
+
const candidates = explicit ? selectFromIds(opts) : [...PKGS];
|
|
960
|
+
if (candidates.length === 0) {
|
|
961
|
+
p4.log.info(t("install.nothingSelected"));
|
|
963
962
|
return;
|
|
964
963
|
}
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
964
|
+
const stateMap = /* @__PURE__ */ new Map();
|
|
965
|
+
const sp = p4.spinner();
|
|
966
|
+
sp.start(t("state.checking"));
|
|
967
|
+
try {
|
|
968
|
+
await Promise.all([listPlugins(), listMcp()]);
|
|
969
|
+
await Promise.all(
|
|
970
|
+
candidates.map(async (pkg) => {
|
|
971
|
+
stateMap.set(pkg.id, await deriveState(pkg));
|
|
972
|
+
})
|
|
973
|
+
);
|
|
974
|
+
} finally {
|
|
975
|
+
sp.stop(t("state.checked", { count: candidates.length }));
|
|
976
|
+
}
|
|
977
|
+
let targets;
|
|
978
|
+
if (explicit) {
|
|
979
|
+
targets = candidates;
|
|
980
|
+
} else {
|
|
981
|
+
const picked = await selectInteractive(stateMap);
|
|
982
|
+
if (picked === null) {
|
|
983
|
+
userCancelled = true;
|
|
984
|
+
p4.cancel(t("app.cancelled"));
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
targets = picked;
|
|
988
|
+
}
|
|
989
|
+
if (targets.length === 0) {
|
|
990
|
+
p4.log.info(t("install.nothingSelected"));
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
const results = [];
|
|
994
|
+
for (const pkg of targets) {
|
|
995
|
+
const state = stateMap.get(pkg.id) ?? { kind: "not_installed" };
|
|
996
|
+
results.push(await runOne(pkg, state, opts));
|
|
997
|
+
}
|
|
998
|
+
summarize(results);
|
|
999
|
+
} finally {
|
|
1000
|
+
if (!userCancelled) {
|
|
1001
|
+
await syncFromState({ skip: opts.noClaudeMd });
|
|
1002
|
+
}
|
|
975
1003
|
}
|
|
976
|
-
summarize(results);
|
|
977
|
-
await syncFromState({ skip: opts.noClaudeMd });
|
|
978
1004
|
}
|
|
979
1005
|
|
|
980
1006
|
// src/flows/uninstall.ts
|
|
@@ -984,81 +1010,102 @@ async function getInstalled() {
|
|
|
984
1010
|
const states = await Promise.all(PKGS.map(async (pkg) => ({ pkg, installed: await pkg.isInstalled() })));
|
|
985
1011
|
return states.filter((s) => s.installed).map((s) => s.pkg);
|
|
986
1012
|
}
|
|
1013
|
+
async function probeInstalled() {
|
|
1014
|
+
const sp = p5.spinner();
|
|
1015
|
+
sp.start(t("state.checking"));
|
|
1016
|
+
try {
|
|
1017
|
+
await Promise.all([listPlugins(), listMcp()]);
|
|
1018
|
+
const installed = await getInstalled();
|
|
1019
|
+
sp.stop(t("state.checked", { count: installed.length }));
|
|
1020
|
+
return installed;
|
|
1021
|
+
} catch (err) {
|
|
1022
|
+
sp.stop(t("state.checked", { count: 0 }));
|
|
1023
|
+
throw err;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
987
1026
|
async function uninstallFlow(opts = {}) {
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
targets
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1027
|
+
let userCancelled = false;
|
|
1028
|
+
try {
|
|
1029
|
+
const installed = await probeInstalled();
|
|
1030
|
+
let targets;
|
|
1031
|
+
if (opts.ids && opts.ids.length > 0) {
|
|
1032
|
+
targets = [];
|
|
1033
|
+
for (const id of opts.ids) {
|
|
1034
|
+
const pkg = findPkg(id);
|
|
1035
|
+
if (!pkg) {
|
|
1036
|
+
p5.log.warn(`Unknown id: ${id}`);
|
|
1037
|
+
continue;
|
|
1038
|
+
}
|
|
1039
|
+
if (!installed.some((x2) => x2.id === pkg.id)) {
|
|
1040
|
+
p5.log.warn(`${pkg.name}: ${t("pkg.notInstalled")}`);
|
|
1041
|
+
continue;
|
|
1042
|
+
}
|
|
1043
|
+
targets.push(pkg);
|
|
997
1044
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1045
|
+
} else {
|
|
1046
|
+
if (installed.length === 0) {
|
|
1047
|
+
p5.log.info(t("uninstall.noneInstalled"));
|
|
1048
|
+
return;
|
|
1001
1049
|
}
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1050
|
+
const picked = await p5.multiselect({
|
|
1051
|
+
message: t("uninstall.selectPrompt"),
|
|
1052
|
+
options: installed.map((pkg) => ({
|
|
1053
|
+
value: pkg.id,
|
|
1054
|
+
label: `${pkg.name} ${pc2.dim(`(${pkg.type})`)}`,
|
|
1055
|
+
hint: pkg.description
|
|
1056
|
+
})),
|
|
1057
|
+
required: false
|
|
1058
|
+
});
|
|
1059
|
+
if (p5.isCancel(picked)) {
|
|
1060
|
+
userCancelled = true;
|
|
1061
|
+
p5.cancel(t("app.cancelled"));
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
targets = picked.map((id) => findPkg(id)).filter((x2) => Boolean(x2));
|
|
1008
1065
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
options: installed.map((pkg) => ({
|
|
1012
|
-
value: pkg.id,
|
|
1013
|
-
label: `${pkg.name} ${pc2.dim(`(${pkg.type})`)}`,
|
|
1014
|
-
hint: pkg.description
|
|
1015
|
-
})),
|
|
1016
|
-
required: false
|
|
1017
|
-
});
|
|
1018
|
-
if (p5.isCancel(picked)) {
|
|
1019
|
-
p5.cancel(t("app.cancelled"));
|
|
1066
|
+
if (targets.length === 0) {
|
|
1067
|
+
p5.log.info(t("install.nothingSelected"));
|
|
1020
1068
|
return;
|
|
1021
1069
|
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
});
|
|
1033
|
-
if (p5.isCancel(ok2) || ok2 === false) {
|
|
1034
|
-
p5.cancel(t("app.cancelled"));
|
|
1035
|
-
return;
|
|
1070
|
+
if (!opts.yes) {
|
|
1071
|
+
const ok2 = await p5.confirm({
|
|
1072
|
+
message: t("uninstall.confirm", { count: targets.length }),
|
|
1073
|
+
initialValue: false
|
|
1074
|
+
});
|
|
1075
|
+
if (p5.isCancel(ok2) || ok2 === false) {
|
|
1076
|
+
userCancelled = true;
|
|
1077
|
+
p5.cancel(t("app.cancelled"));
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1036
1080
|
}
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
log5.error(`${t("uninstall.failed", { name: pkg.name })}
|
|
1081
|
+
const results = [];
|
|
1082
|
+
for (const pkg of targets) {
|
|
1083
|
+
const log5 = p5.taskLog({ title: t("uninstall.starting", { name: pkg.name }) });
|
|
1084
|
+
try {
|
|
1085
|
+
await pkg.uninstall({ log: log5, config: {}, t });
|
|
1086
|
+
log5.success(t("uninstall.success", { name: pkg.name }));
|
|
1087
|
+
results.push({ id: pkg.id, status: "ok" });
|
|
1088
|
+
} catch (err) {
|
|
1089
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1090
|
+
log5.error(`${t("uninstall.failed", { name: pkg.name })}
|
|
1048
1091
|
${msg}`);
|
|
1049
|
-
|
|
1092
|
+
results.push({ id: pkg.id, status: "fail", message: msg });
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
const ok = results.filter((r) => r.status === "ok").length;
|
|
1096
|
+
const fail = results.filter((r) => r.status === "fail").length;
|
|
1097
|
+
p5.note(
|
|
1098
|
+
[
|
|
1099
|
+
pc2.green(t("install.summaryOk", { count: ok })),
|
|
1100
|
+
pc2.red(t("install.summaryFail", { count: fail }))
|
|
1101
|
+
].join("\n"),
|
|
1102
|
+
t("install.summaryTitle")
|
|
1103
|
+
);
|
|
1104
|
+
} finally {
|
|
1105
|
+
if (!userCancelled) {
|
|
1106
|
+
await syncFromState({ skip: opts.noClaudeMd });
|
|
1050
1107
|
}
|
|
1051
1108
|
}
|
|
1052
|
-
const ok = results.filter((r) => r.status === "ok").length;
|
|
1053
|
-
const fail = results.filter((r) => r.status === "fail").length;
|
|
1054
|
-
p5.note(
|
|
1055
|
-
[
|
|
1056
|
-
pc2.green(t("install.summaryOk", { count: ok })),
|
|
1057
|
-
pc2.red(t("install.summaryFail", { count: fail }))
|
|
1058
|
-
].join("\n"),
|
|
1059
|
-
t("install.summaryTitle")
|
|
1060
|
-
);
|
|
1061
|
-
await syncFromState({ skip: opts.noClaudeMd });
|
|
1062
1109
|
}
|
|
1063
1110
|
|
|
1064
1111
|
// src/flows/update.ts
|
|
@@ -1068,90 +1115,110 @@ async function getInstalled2() {
|
|
|
1068
1115
|
const states = await Promise.all(PKGS.map(async (pkg) => ({ pkg, installed: await pkg.isInstalled() })));
|
|
1069
1116
|
return states.filter((s) => s.installed).map((s) => s.pkg);
|
|
1070
1117
|
}
|
|
1071
|
-
async function
|
|
1072
|
-
const
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1118
|
+
async function probeInstalled2() {
|
|
1119
|
+
const sp = p6.spinner();
|
|
1120
|
+
sp.start(t("state.checking"));
|
|
1121
|
+
try {
|
|
1122
|
+
await Promise.all([listPlugins(), listMcp()]);
|
|
1123
|
+
const installed = await getInstalled2();
|
|
1124
|
+
sp.stop(t("state.checked", { count: installed.length }));
|
|
1125
|
+
return installed;
|
|
1126
|
+
} catch (err) {
|
|
1127
|
+
sp.stop(t("state.checked", { count: 0 }));
|
|
1128
|
+
throw err;
|
|
1076
1129
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1130
|
+
}
|
|
1131
|
+
async function updateFlow(opts = {}) {
|
|
1132
|
+
let userCancelled = false;
|
|
1133
|
+
try {
|
|
1134
|
+
const installed = await probeInstalled2();
|
|
1135
|
+
if (installed.length === 0) {
|
|
1136
|
+
p6.log.info(t("update.noneInstalled"));
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
let targets;
|
|
1140
|
+
if (opts.all) {
|
|
1141
|
+
targets = installed;
|
|
1142
|
+
} else if (opts.ids && opts.ids.length > 0) {
|
|
1143
|
+
targets = [];
|
|
1144
|
+
for (const id of opts.ids) {
|
|
1145
|
+
const pkg = findPkg(id);
|
|
1146
|
+
if (!pkg) {
|
|
1147
|
+
p6.log.warn(`Unknown id: ${id}`);
|
|
1148
|
+
continue;
|
|
1149
|
+
}
|
|
1150
|
+
if (!installed.some((x2) => x2.id === pkg.id)) {
|
|
1151
|
+
p6.log.warn(`${pkg.name}: ${t("pkg.notInstalled")}`);
|
|
1152
|
+
continue;
|
|
1153
|
+
}
|
|
1154
|
+
targets.push(pkg);
|
|
1087
1155
|
}
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1156
|
+
} else {
|
|
1157
|
+
const picked = await p6.multiselect({
|
|
1158
|
+
message: t("update.selectPrompt"),
|
|
1159
|
+
options: installed.map((pkg) => ({
|
|
1160
|
+
value: pkg.id,
|
|
1161
|
+
label: `${pkg.name} ${pc3.dim(`(${pkg.type})`)}`,
|
|
1162
|
+
hint: pkg.description
|
|
1163
|
+
})),
|
|
1164
|
+
required: false
|
|
1165
|
+
});
|
|
1166
|
+
if (p6.isCancel(picked)) {
|
|
1167
|
+
userCancelled = true;
|
|
1168
|
+
p6.cancel(t("app.cancelled"));
|
|
1169
|
+
return;
|
|
1091
1170
|
}
|
|
1092
|
-
targets.
|
|
1171
|
+
targets = picked.map((id) => findPkg(id)).filter((x2) => Boolean(x2));
|
|
1093
1172
|
}
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
message: t("update.selectPrompt"),
|
|
1097
|
-
options: installed.map((pkg) => ({
|
|
1098
|
-
value: pkg.id,
|
|
1099
|
-
label: `${pkg.name} ${pc3.dim(`(${pkg.type})`)}`,
|
|
1100
|
-
hint: pkg.description
|
|
1101
|
-
})),
|
|
1102
|
-
required: false
|
|
1103
|
-
});
|
|
1104
|
-
if (p6.isCancel(picked)) {
|
|
1105
|
-
p6.cancel(t("app.cancelled"));
|
|
1173
|
+
if (targets.length === 0) {
|
|
1174
|
+
p6.log.info(t("install.nothingSelected"));
|
|
1106
1175
|
return;
|
|
1107
1176
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
const results = [];
|
|
1115
|
-
for (const pkg of targets) {
|
|
1116
|
-
if (pkg.id === "sequential-thinking") {
|
|
1117
|
-
p6.log.info(t("update.mcpAutoNote", { name: pkg.name }));
|
|
1118
|
-
results.push({ id: pkg.id, status: "noop" });
|
|
1119
|
-
continue;
|
|
1120
|
-
}
|
|
1121
|
-
if (pkg.id === "context7") {
|
|
1122
|
-
p6.log.info(t("update.context7Note"));
|
|
1123
|
-
results.push({ id: pkg.id, status: "noop" });
|
|
1124
|
-
continue;
|
|
1125
|
-
}
|
|
1126
|
-
const log5 = p6.taskLog({ title: t("update.starting", { name: pkg.name }) });
|
|
1127
|
-
try {
|
|
1128
|
-
if (pkg.update) {
|
|
1129
|
-
await pkg.update({ log: log5, config: {}, t });
|
|
1130
|
-
} else {
|
|
1131
|
-
await pkg.uninstall({ log: log5, config: {}, t });
|
|
1132
|
-
await pkg.install({ log: log5, config: {}, t });
|
|
1177
|
+
const results = [];
|
|
1178
|
+
for (const pkg of targets) {
|
|
1179
|
+
if (pkg.id === "sequential-thinking") {
|
|
1180
|
+
p6.log.info(t("update.mcpAutoNote", { name: pkg.name }));
|
|
1181
|
+
results.push({ id: pkg.id, status: "noop" });
|
|
1182
|
+
continue;
|
|
1133
1183
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1184
|
+
if (pkg.id === "context7") {
|
|
1185
|
+
p6.log.info(t("update.context7Note"));
|
|
1186
|
+
results.push({ id: pkg.id, status: "noop" });
|
|
1187
|
+
continue;
|
|
1188
|
+
}
|
|
1189
|
+
const log5 = p6.taskLog({ title: t("update.starting", { name: pkg.name }) });
|
|
1190
|
+
try {
|
|
1191
|
+
if (pkg.update) {
|
|
1192
|
+
await pkg.update({ log: log5, config: {}, t });
|
|
1193
|
+
} else {
|
|
1194
|
+
await pkg.uninstall({ log: log5, config: {}, t });
|
|
1195
|
+
await pkg.install({ log: log5, config: {}, t });
|
|
1196
|
+
}
|
|
1197
|
+
log5.success(t("update.success", { name: pkg.name }));
|
|
1198
|
+
results.push({ id: pkg.id, status: "ok" });
|
|
1199
|
+
} catch (err) {
|
|
1200
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1201
|
+
log5.error(`${t("update.failed", { name: pkg.name })}
|
|
1139
1202
|
${msg}`);
|
|
1140
|
-
|
|
1203
|
+
results.push({ id: pkg.id, status: "fail", message: msg });
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
const ok = results.filter((r) => r.status === "ok").length;
|
|
1207
|
+
const fail = results.filter((r) => r.status === "fail").length;
|
|
1208
|
+
const noop = results.filter((r) => r.status === "noop").length;
|
|
1209
|
+
p6.note(
|
|
1210
|
+
[
|
|
1211
|
+
pc3.green(t("install.summaryOk", { count: ok })),
|
|
1212
|
+
pc3.red(t("install.summaryFail", { count: fail })),
|
|
1213
|
+
pc3.dim(`noop: ${noop}`)
|
|
1214
|
+
].join("\n"),
|
|
1215
|
+
t("install.summaryTitle")
|
|
1216
|
+
);
|
|
1217
|
+
} finally {
|
|
1218
|
+
if (!userCancelled) {
|
|
1219
|
+
await syncFromState({ skip: opts.noClaudeMd });
|
|
1141
1220
|
}
|
|
1142
1221
|
}
|
|
1143
|
-
const ok = results.filter((r) => r.status === "ok").length;
|
|
1144
|
-
const fail = results.filter((r) => r.status === "fail").length;
|
|
1145
|
-
const noop = results.filter((r) => r.status === "noop").length;
|
|
1146
|
-
p6.note(
|
|
1147
|
-
[
|
|
1148
|
-
pc3.green(t("install.summaryOk", { count: ok })),
|
|
1149
|
-
pc3.red(t("install.summaryFail", { count: fail })),
|
|
1150
|
-
pc3.dim(`noop: ${noop}`)
|
|
1151
|
-
].join("\n"),
|
|
1152
|
-
t("install.summaryTitle")
|
|
1153
|
-
);
|
|
1154
|
-
await syncFromState({ skip: opts.noClaudeMd });
|
|
1155
1222
|
}
|
|
1156
1223
|
|
|
1157
1224
|
// src/flows/status.ts
|
|
@@ -1316,7 +1383,7 @@ var SUBCOMMANDS = /* @__PURE__ */ new Set(["install", "uninstall", "update", "st
|
|
|
1316
1383
|
var root = defineCommand({
|
|
1317
1384
|
meta: {
|
|
1318
1385
|
name: "@curdx/flow",
|
|
1319
|
-
version: "3.3.
|
|
1386
|
+
version: "3.3.2",
|
|
1320
1387
|
description: "Interactive installer for Claude Code plugins and MCP servers"
|
|
1321
1388
|
},
|
|
1322
1389
|
args: sharedArgs,
|