claudeup 6.5.1 → 6.6.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/package.json +4 -4
- package/src/__tests__/active-closure.test.ts +184 -0
- package/src/__tests__/blackbox-active-closure.test.ts +119 -0
- package/src/__tests__/blackbox-convergence.test.ts +334 -0
- package/src/__tests__/blackbox-parity.test.ts +684 -0
- package/src/__tests__/blackbox-plugin-state.test.ts +523 -0
- package/src/__tests__/blackbox-tool-state.test.ts +669 -0
- package/src/__tests__/cli-apply-seams.test.ts +2 -0
- package/src/__tests__/cli-tool-commands.test.ts +1 -1
- package/src/__tests__/cli-tools-adapter.test.ts +294 -0
- package/src/__tests__/cli-update-view.test.ts +142 -2
- package/src/__tests__/content-drift.test.ts +60 -0
- package/src/__tests__/enabled-not-installed.test.ts +1 -2
- package/src/__tests__/fixtures/tool-probe/brew-list-versions-tmux.txt +2 -0
- package/src/__tests__/fixtures/tool-probe/brew-outdated-behind-homebrew-spec.txt +29 -0
- package/src/__tests__/fixtures/tool-probe/brew-outdated-tmux-current.txt +7 -0
- package/src/__tests__/fixtures/tool-probe/brew-outdated-unknown-formula.txt +6 -0
- package/src/__tests__/fixtures/tool-probe/go-version-m-tmux-mcp.txt +27 -0
- package/src/__tests__/fixtures/tool-probe/npm-dist-tags-missing-scoped.txt +4 -0
- package/src/__tests__/fixtures/tool-probe/npm-dist-tags-openai-codex.txt +4 -0
- package/src/__tests__/fixtures/tool-probe/pypi-cowsay.txt +3 -0
- package/src/__tests__/fixtures/tool-probe/uv-receipt-browser-use.toml +10 -0
- package/src/__tests__/fixtures/tool-probe/uv-receipt-cowsay-git.toml +8 -0
- package/src/__tests__/fixtures/tool-probe/uv-receipt-cowsay-pinned.toml +8 -0
- package/src/__tests__/fixtures/tool-probe/uv-receipt-graphifyy.toml +7 -0
- package/src/__tests__/fixtures/tool-probe/uv-receipt-mcp.toml +6 -0
- package/src/__tests__/fixtures/tool-probe/uv-receipt-serena-agent.toml +9 -0
- package/src/__tests__/fixtures/tool-probe/uv-tool-list-outdated-pinned.txt +5 -0
- package/src/__tests__/fixtures/tool-probe/uv-tool-list-outdated.txt +11 -0
- package/src/__tests__/fixtures/tool-probe/uv-tool-list.txt +22 -0
- package/src/__tests__/{gitignore-prerun.test.ts → gitignore-check.test.ts} +8 -6
- package/src/__tests__/plugin-cli-argv.test.ts +1 -1
- package/src/__tests__/plugin-row-text.test.ts +336 -0
- package/src/__tests__/scope-action.test.ts +69 -19
- package/src/__tests__/shell-script-callers.test.ts +8 -8
- package/src/__tests__/tool-probe.test.ts +1400 -0
- package/src/__tests__/update-apply.test.ts +283 -1
- package/src/__tests__/update-plan.test.ts +773 -31
- package/src/__tests__/version-unknown-state.test.ts +388 -0
- package/src/cli/router.ts +0 -5
- package/src/cli/update-view.ts +92 -12
- package/src/cli/update.ts +114 -38
- package/src/services/active-closure.ts +117 -0
- package/src/services/catalog-cache-store.ts +6 -2
- package/src/services/claude-settings.ts +1 -173
- package/src/services/{gitignore-prerun.ts → gitignore-check.ts} +14 -10
- package/src/services/gitignore-fixer.ts +1 -1
- package/src/services/marketplace-refresh.ts +30 -0
- package/src/services/plugin-manager.ts +200 -283
- package/src/services/resolver.ts +7 -2
- package/src/services/tool-probe.ts +1637 -0
- package/src/services/toolchain.ts +97 -0
- package/src/services/update-engine.ts +220 -32
- package/src/services/update-plan.ts +640 -160
- package/src/services/version-snapshot.ts +1 -1
- package/src/types/bun.d.ts +6 -0
- package/src/ui/App.tsx +2 -27
- package/src/ui/adapters/cliToolsAdapter.ts +176 -0
- package/src/ui/adapters/pluginsAdapter.ts +57 -0
- package/src/ui/components/modals/ModalContainer.tsx +0 -26
- package/src/ui/hooks/index.ts +0 -1
- package/src/ui/hooks/useGitignoreModal.ts +2 -3
- package/src/ui/renderers/cliToolRenderers.tsx +108 -67
- package/src/ui/renderers/pluginRenderers.tsx +157 -98
- package/src/ui/renderers/pluginRowText.ts +70 -0
- package/src/ui/renderers/pluginStatusText.ts +56 -0
- package/src/ui/screens/CliToolsScreen.tsx +154 -280
- package/src/ui/screens/PluginsScreen.tsx +156 -140
- package/src/ui/state/types.ts +0 -7
- package/src/__tests__/dual-write-prevention.test.ts +0 -380
- package/src/__tests__/gap-fill-versions.test.ts +0 -389
- package/src/__tests__/plugin-version-check.test.ts +0 -762
- package/src/cli/claude.ts +0 -21
- package/src/prerunner/index.ts +0 -500
- package/src/services/plugin-version-check.ts +0 -360
- package/src/services/update-cache.ts +0 -78
- package/src/ui/components/modals/VersionMismatchModal.tsx +0 -138
- package/src/ui/hooks/useMismatchModal.ts +0 -89
|
@@ -2,12 +2,17 @@ import type React from "react";
|
|
|
2
2
|
import type { CliTool } from "../../data/cli-tools.js";
|
|
3
3
|
import {
|
|
4
4
|
type InstallMethod,
|
|
5
|
-
cliToolInstall,
|
|
6
5
|
cliToolUninstall,
|
|
7
6
|
} from "../../services/cli-tool-commands.js";
|
|
8
|
-
import type { Command } from "../../utils/command-utils.js";
|
|
9
7
|
import { formatCommand } from "../../utils/command-utils.js";
|
|
8
|
+
import {
|
|
9
|
+
type CliToolRow,
|
|
10
|
+
cliToolStatusText,
|
|
11
|
+
displayVersion,
|
|
12
|
+
isInstalled,
|
|
13
|
+
} from "../adapters/cliToolsAdapter.js";
|
|
10
14
|
import { type UiColor, theme } from "../theme.js";
|
|
15
|
+
import type { StatusTone } from "./pluginStatusText.js";
|
|
11
16
|
|
|
12
17
|
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
13
18
|
|
|
@@ -32,52 +37,58 @@ function uninstallHint(
|
|
|
32
37
|
return cmd ? formatCommand(cmd) : "";
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
function toneColor(tone: StatusTone): UiColor {
|
|
41
|
+
switch (tone) {
|
|
42
|
+
case "warning":
|
|
43
|
+
return theme.colors.warning;
|
|
44
|
+
case "danger":
|
|
45
|
+
return theme.colors.danger;
|
|
46
|
+
case "success":
|
|
47
|
+
return theme.colors.success;
|
|
48
|
+
case "info":
|
|
49
|
+
return theme.colors.info;
|
|
50
|
+
case "muted":
|
|
51
|
+
return theme.colors.muted;
|
|
52
|
+
}
|
|
48
53
|
}
|
|
49
54
|
|
|
50
55
|
// ─── Row renderer ──────────────────────────────────────────────────────────────
|
|
51
56
|
|
|
52
57
|
export function renderCliToolRow(
|
|
53
|
-
|
|
58
|
+
row: CliToolRow,
|
|
54
59
|
_index: number,
|
|
55
60
|
isSelected: boolean,
|
|
56
61
|
): React.ReactNode {
|
|
57
|
-
const { tool,
|
|
58
|
-
|
|
59
|
-
const
|
|
62
|
+
const { tool, status, install } = row;
|
|
63
|
+
const installed = isInstalled(status);
|
|
64
|
+
const allMethods = install?.all ?? [];
|
|
65
|
+
const hasConflict = allMethods.length > 1;
|
|
60
66
|
|
|
61
67
|
let icon: string;
|
|
62
68
|
let iconColor: UiColor;
|
|
63
|
-
|
|
64
69
|
if (!installed) {
|
|
65
70
|
icon = "○";
|
|
66
71
|
iconColor = theme.colors.muted;
|
|
67
72
|
} else if (hasConflict) {
|
|
68
73
|
icon = "!";
|
|
69
74
|
iconColor = theme.colors.danger;
|
|
70
|
-
} else if (
|
|
75
|
+
} else if (status?.state === "upgrade") {
|
|
71
76
|
icon = "*";
|
|
72
77
|
iconColor = theme.colors.warning;
|
|
78
|
+
} else if (status?.state === "unknown") {
|
|
79
|
+
icon = "?";
|
|
80
|
+
iconColor = theme.colors.warning;
|
|
73
81
|
} else {
|
|
74
82
|
icon = "●";
|
|
75
83
|
iconColor = theme.colors.success;
|
|
76
84
|
}
|
|
77
85
|
|
|
78
|
-
const versionText =
|
|
86
|
+
const versionText = status?.installed
|
|
87
|
+
? ` ${displayVersion(status.installed)}`
|
|
88
|
+
: "";
|
|
79
89
|
const methodTag =
|
|
80
|
-
installed && allMethods
|
|
90
|
+
installed && allMethods.length ? ` ${allMethods.join("+")}` : "";
|
|
91
|
+
const { suffix, tone } = cliToolStatusText(row);
|
|
81
92
|
|
|
82
93
|
if (isSelected) {
|
|
83
94
|
return (
|
|
@@ -86,7 +97,7 @@ export function renderCliToolRow(
|
|
|
86
97
|
{icon} {tool.displayName}
|
|
87
98
|
{versionText}
|
|
88
99
|
{methodTag}
|
|
89
|
-
{
|
|
100
|
+
{suffix}{" "}
|
|
90
101
|
</text>
|
|
91
102
|
);
|
|
92
103
|
}
|
|
@@ -103,7 +114,7 @@ export function renderCliToolRow(
|
|
|
103
114
|
{methodTag}
|
|
104
115
|
</span>
|
|
105
116
|
) : null}
|
|
106
|
-
{
|
|
117
|
+
{suffix ? <span fg={toneColor(tone)}>{suffix}</span> : null}
|
|
107
118
|
</text>
|
|
108
119
|
);
|
|
109
120
|
}
|
|
@@ -111,9 +122,9 @@ export function renderCliToolRow(
|
|
|
111
122
|
// ─── Detail renderer ───────────────────────────────────────────────────────────
|
|
112
123
|
|
|
113
124
|
export function renderCliToolDetail(
|
|
114
|
-
|
|
125
|
+
row: CliToolRow | undefined,
|
|
115
126
|
): React.ReactNode {
|
|
116
|
-
if (!
|
|
127
|
+
if (!row) {
|
|
117
128
|
return (
|
|
118
129
|
<box
|
|
119
130
|
flexDirection="column"
|
|
@@ -126,20 +137,13 @@ export function renderCliToolDetail(
|
|
|
126
137
|
);
|
|
127
138
|
}
|
|
128
139
|
|
|
129
|
-
const {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
installMethod,
|
|
137
|
-
allMethods,
|
|
138
|
-
updateCommand,
|
|
139
|
-
brewFormula,
|
|
140
|
-
} = status;
|
|
141
|
-
|
|
142
|
-
const hasConflict = allMethods && allMethods.length > 1;
|
|
140
|
+
const { tool, status, checking, install, updateCommand, installCommand } =
|
|
141
|
+
row;
|
|
142
|
+
const installed = isInstalled(status);
|
|
143
|
+
const allMethods = install?.all ?? [];
|
|
144
|
+
const brewFormula = install?.brewFormula;
|
|
145
|
+
const hasConflict = allMethods.length > 1;
|
|
146
|
+
const state = status?.state;
|
|
143
147
|
|
|
144
148
|
return (
|
|
145
149
|
<box flexDirection="column">
|
|
@@ -150,7 +154,7 @@ export function renderCliToolDetail(
|
|
|
150
154
|
{tool.displayName}
|
|
151
155
|
</strong>
|
|
152
156
|
</text>
|
|
153
|
-
{
|
|
157
|
+
{state === "upgrade" ? <text fg={theme.colors.warning}> ⬆</text> : null}
|
|
154
158
|
{hasConflict ? <text fg={theme.colors.danger}> !</text> : null}
|
|
155
159
|
</box>
|
|
156
160
|
|
|
@@ -159,30 +163,56 @@ export function renderCliToolDetail(
|
|
|
159
163
|
<box marginTop={1} flexDirection="column">
|
|
160
164
|
<box>
|
|
161
165
|
<text fg={theme.colors.muted}>{"Status "}</text>
|
|
162
|
-
{!
|
|
166
|
+
{checking || !status ? (
|
|
167
|
+
<text fg={theme.colors.muted}>{"● Checking..."}</text>
|
|
168
|
+
) : state === "install" ? (
|
|
163
169
|
<text fg={theme.colors.muted}>{"○ Not installed"}</text>
|
|
164
|
-
) :
|
|
165
|
-
<text fg={theme.colors.success}>{"● Checking..."}</text>
|
|
166
|
-
) : hasUpdate ? (
|
|
170
|
+
) : state === "upgrade" ? (
|
|
167
171
|
<text fg={theme.colors.warning}>{"● Update available"}</text>
|
|
172
|
+
) : state === "unknown" ? (
|
|
173
|
+
<text fg={theme.colors.warning}>{"? Unverified"}</text>
|
|
168
174
|
) : (
|
|
169
175
|
<text fg={theme.colors.success}>{"● Up to date"}</text>
|
|
170
176
|
)}
|
|
171
177
|
</box>
|
|
172
|
-
{
|
|
178
|
+
{state === "unknown" && status?.note ? (
|
|
179
|
+
<box>
|
|
180
|
+
<text fg={theme.colors.muted}>{"Why "}</text>
|
|
181
|
+
<text fg={theme.colors.warning}>{status.note}</text>
|
|
182
|
+
</box>
|
|
183
|
+
) : null}
|
|
184
|
+
{/* An upgrade that also takes the tool over from another installer. */}
|
|
185
|
+
{status?.adopted ? (
|
|
186
|
+
<box>
|
|
187
|
+
<text fg={theme.colors.muted}>{"Note "}</text>
|
|
188
|
+
<text fg={theme.colors.warning}>{status.adopted}</text>
|
|
189
|
+
</box>
|
|
190
|
+
) : null}
|
|
191
|
+
{status?.installed ? (
|
|
173
192
|
<box>
|
|
174
193
|
<text fg={theme.colors.muted}>{"Version "}</text>
|
|
175
194
|
<text fg={theme.colors.text}>
|
|
176
|
-
<span fg={theme.colors.success}>
|
|
177
|
-
|
|
178
|
-
|
|
195
|
+
<span fg={theme.colors.success}>
|
|
196
|
+
{displayVersion(status.installed)}
|
|
197
|
+
</span>
|
|
198
|
+
{state === "upgrade" && status.target ? (
|
|
199
|
+
<span fg={theme.colors.warning}>
|
|
200
|
+
{" "}
|
|
201
|
+
→ {displayVersion(status.target)}
|
|
202
|
+
</span>
|
|
179
203
|
) : null}
|
|
180
204
|
</text>
|
|
181
205
|
</box>
|
|
182
|
-
) :
|
|
206
|
+
) : status?.latest ? (
|
|
183
207
|
<box>
|
|
184
208
|
<text fg={theme.colors.muted}>{"Latest "}</text>
|
|
185
|
-
<text fg={theme.colors.text}>
|
|
209
|
+
<text fg={theme.colors.text}>{displayVersion(status.latest)}</text>
|
|
210
|
+
</box>
|
|
211
|
+
) : null}
|
|
212
|
+
{status?.pin ? (
|
|
213
|
+
<box>
|
|
214
|
+
<text fg={theme.colors.muted}>{"Pinned "}</text>
|
|
215
|
+
<text fg={theme.colors.text}>{displayVersion(status.pin)}</text>
|
|
186
216
|
</box>
|
|
187
217
|
) : null}
|
|
188
218
|
{installed && updateCommand ? (
|
|
@@ -190,11 +220,11 @@ export function renderCliToolDetail(
|
|
|
190
220
|
<text fg={theme.colors.muted}>{"Update "}</text>
|
|
191
221
|
<text fg={theme.colors.accent}>{formatCommand(updateCommand)}</text>
|
|
192
222
|
</box>
|
|
193
|
-
) : !installed ? (
|
|
223
|
+
) : !installed && !checking ? (
|
|
194
224
|
<box>
|
|
195
225
|
<text fg={theme.colors.muted}>{"Install "}</text>
|
|
196
226
|
<text fg={theme.colors.accent}>
|
|
197
|
-
{formatCommand(
|
|
227
|
+
{formatCommand(installCommand)}
|
|
198
228
|
</text>
|
|
199
229
|
</box>
|
|
200
230
|
) : null}
|
|
@@ -250,33 +280,44 @@ export function renderCliToolDetail(
|
|
|
250
280
|
|
|
251
281
|
{/* Actions */}
|
|
252
282
|
<box marginTop={2} flexDirection="column">
|
|
253
|
-
{!installed ? (
|
|
283
|
+
{checking || !status ? null : !installed ? (
|
|
254
284
|
<box>
|
|
255
285
|
<text bg={theme.colors.success} fg={theme.hints.fg}>
|
|
256
286
|
{" "}
|
|
257
287
|
Enter{" "}
|
|
258
288
|
</text>
|
|
259
289
|
<text fg={theme.colors.muted}> Install</text>
|
|
260
|
-
<text fg={theme.colors.dim}>
|
|
261
|
-
{" "}
|
|
262
|
-
{formatCommand(cliToolInstall(tool))}
|
|
263
|
-
</text>
|
|
290
|
+
<text fg={theme.colors.dim}> {formatCommand(installCommand)}</text>
|
|
264
291
|
</box>
|
|
265
|
-
) :
|
|
292
|
+
) : state === "upgrade" ? (
|
|
266
293
|
<box>
|
|
267
294
|
<text bg={theme.colors.warning} fg={theme.hints.fg}>
|
|
268
295
|
{" "}
|
|
269
296
|
Enter{" "}
|
|
270
297
|
</text>
|
|
271
|
-
<text fg={theme.colors.muted}>
|
|
272
|
-
</box>
|
|
273
|
-
) : (
|
|
274
|
-
<box>
|
|
275
|
-
<text bg={theme.colors.muted} fg={theme.hints.fg}>
|
|
298
|
+
<text fg={theme.colors.muted}>
|
|
276
299
|
{" "}
|
|
277
|
-
|
|
300
|
+
Update
|
|
301
|
+
{status.target ? ` to ${displayVersion(status.target)}` : ""}
|
|
278
302
|
</text>
|
|
279
|
-
|
|
303
|
+
</box>
|
|
304
|
+
) : (
|
|
305
|
+
<box flexDirection="column">
|
|
306
|
+
<box>
|
|
307
|
+
<text bg={theme.colors.muted} fg={theme.hints.fg}>
|
|
308
|
+
{" "}
|
|
309
|
+
Enter{" "}
|
|
310
|
+
</text>
|
|
311
|
+
<text fg={theme.colors.muted}>
|
|
312
|
+
{state === "unknown" ? " Update anyway" : " Reinstall"}
|
|
313
|
+
</text>
|
|
314
|
+
</box>
|
|
315
|
+
{/* The status warns that this command may not replace the
|
|
316
|
+
running binary; the menu still offers it, as an explicit
|
|
317
|
+
user action, and says so beside it. */}
|
|
318
|
+
{status.reason === "not-managed" && status.note ? (
|
|
319
|
+
<text fg={theme.colors.warning}>{` ${status.note}`}</text>
|
|
320
|
+
) : null}
|
|
280
321
|
</box>
|
|
281
322
|
)}
|
|
282
323
|
</box>
|