magus-cli 0.0.0-placeholder → 7.0.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/README.md +309 -0
- package/bin/magus.js +170 -0
- package/package.json +67 -3
- package/scripts/build-binaries.ts +113 -0
- package/scripts/capture-builtin.ts +412 -0
- package/scripts/check-optional-deps.ts +49 -0
- package/scripts/test-isolated.ts +49 -0
- package/scripts/verify-binary.ts +95 -0
- package/scripts/verify-community-registry.ts +272 -0
- package/src/__tests__/active-closure.test.ts +184 -0
- package/src/__tests__/alias-adopt.test.ts +365 -0
- package/src/__tests__/alias-parser.test.ts +417 -0
- package/src/__tests__/alias-shell-writer.test.ts +681 -0
- package/src/__tests__/alias-store.test.ts +163 -0
- package/src/__tests__/binary-signing.test.ts +120 -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__/cache-provenance.test.ts +84 -0
- package/src/__tests__/capture-builtin.test.ts +92 -0
- package/src/__tests__/catalog-cache-store.test.ts +309 -0
- package/src/__tests__/catalog-notice.test.ts +155 -0
- package/src/__tests__/cli-ansi.test.ts +297 -0
- package/src/__tests__/cli-apply-seams.test.ts +288 -0
- package/src/__tests__/cli-live.test.ts +391 -0
- package/src/__tests__/cli-router.test.ts +240 -0
- package/src/__tests__/cli-tool-commands.test.ts +239 -0
- package/src/__tests__/cli-tools-adapter.test.ts +294 -0
- package/src/__tests__/cli-update-view.test.ts +445 -0
- package/src/__tests__/community-fetch.test.ts +545 -0
- package/src/__tests__/community-registry.test.ts +269 -0
- package/src/__tests__/community-staleness.test.ts +720 -0
- package/src/__tests__/component-badge.test.ts +98 -0
- package/src/__tests__/component-icons.test.ts +94 -0
- package/src/__tests__/content-drift.test.ts +353 -0
- package/src/__tests__/conventions-integration.test.ts +830 -0
- package/src/__tests__/conventions-manager.test.ts +1236 -0
- package/src/__tests__/doctor-bins.test.ts +43 -0
- package/src/__tests__/doctor.test.ts +463 -0
- package/src/__tests__/dotenv.test.ts +195 -0
- package/src/__tests__/enabled-not-installed.test.ts +94 -0
- package/src/__tests__/file-locking.test.ts +208 -0
- 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__/footer-hints.test.ts +40 -0
- package/src/__tests__/format-command.test.ts +78 -0
- package/src/__tests__/git-worktree.test.ts +108 -0
- package/src/__tests__/github-budget.test.ts +206 -0
- package/src/__tests__/gitignore-check.test.ts +71 -0
- package/src/__tests__/gitignore-detector.test.ts +176 -0
- package/src/__tests__/gitignore-fixer.test.ts +317 -0
- package/src/__tests__/gitignore-resolver.test.ts +193 -0
- package/src/__tests__/gitignore-service.test.ts +137 -0
- package/src/__tests__/go-module.test.ts +43 -0
- package/src/__tests__/hook-import-policy.test.ts +90 -0
- package/src/__tests__/hook-process.test.ts +256 -0
- package/src/__tests__/hook-registration.test.ts +224 -0
- package/src/__tests__/install-command.test.ts +81 -0
- package/src/__tests__/install-plan.test.ts +104 -0
- package/src/__tests__/launcher-signal.test.ts +308 -0
- package/src/__tests__/local-marketplace-scan.test.ts +174 -0
- package/src/__tests__/manifest.test.ts +281 -0
- package/src/__tests__/markdown-renderer.test.ts +142 -0
- package/src/__tests__/marketplace-badge.test.ts +140 -0
- package/src/__tests__/marketplace-refresh.test.ts +335 -0
- package/src/__tests__/marketplace-version.test.ts +84 -0
- package/src/__tests__/marketplaces.test.ts +128 -0
- package/src/__tests__/mate-availability.test.ts +156 -0
- package/src/__tests__/mate-catalog.test.ts +295 -0
- package/src/__tests__/mcp-registry.test.ts +158 -0
- package/src/__tests__/model-visuals.test.tsx +2466 -0
- package/src/__tests__/models-adapter.test.ts +332 -0
- package/src/__tests__/models-cli.test.ts +273 -0
- package/src/__tests__/models-core.test.ts +802 -0
- package/src/__tests__/models-manager.test.ts +500 -0
- package/src/__tests__/models-presets-marketplace.test.ts +168 -0
- package/src/__tests__/models-screen-state.test.ts +315 -0
- package/src/__tests__/moved-marketplace.test.ts +86 -0
- package/src/__tests__/open-file.test.ts +59 -0
- package/src/__tests__/owned-marketplaces.test.ts +93 -0
- package/src/__tests__/plugin-checkout.test.ts +66 -0
- package/src/__tests__/plugin-cli-argv.test.ts +109 -0
- package/src/__tests__/plugin-contents.test.ts +371 -0
- package/src/__tests__/plugin-manager-fallback.test.ts +320 -0
- package/src/__tests__/plugin-releases.test.ts +98 -0
- package/src/__tests__/plugin-requires.test.ts +187 -0
- package/src/__tests__/plugin-row-text.test.ts +336 -0
- package/src/__tests__/plugin-setup.test.ts +1016 -0
- package/src/__tests__/profile-adopt.test.ts +177 -0
- package/src/__tests__/profile-command.test.ts +110 -0
- package/src/__tests__/profile-materializer.test.ts +238 -0
- package/src/__tests__/profile-sync.test.ts +154 -0
- package/src/__tests__/registry-version-resolution.test.ts +88 -0
- package/src/__tests__/resolve-executable.test.ts +42 -0
- package/src/__tests__/resolver.test.ts +351 -0
- package/src/__tests__/scope-action.test.ts +134 -0
- package/src/__tests__/scope-squares.test.tsx +164 -0
- package/src/__tests__/selection-scope.test.ts +100 -0
- package/src/__tests__/settings-file.test.ts +179 -0
- package/src/__tests__/shell-script-callers.test.ts +92 -0
- package/src/__tests__/skill-install-files.test.ts +136 -0
- package/src/__tests__/skills-catalog-client.test.ts +48 -0
- package/src/__tests__/style-wrap.test.ts +220 -0
- package/src/__tests__/styles-manager.test.ts +1098 -0
- package/src/__tests__/styles-origins.test.ts +414 -0
- package/src/__tests__/styles-screen-state.test.ts +457 -0
- package/src/__tests__/styles-status-line.test.ts +72 -0
- package/src/__tests__/styles-sync.test.ts +452 -0
- package/src/__tests__/symlink-manager.test.ts +180 -0
- package/src/__tests__/tabbar-layout.test.ts +100 -0
- package/src/__tests__/terminology-filler.test.ts +214 -0
- package/src/__tests__/theme-adaptive-colors.test.ts +354 -0
- package/src/__tests__/theme-env.test.ts +281 -0
- package/src/__tests__/theme-resolve.test.ts +380 -0
- package/src/__tests__/tool-probe.test.ts +1400 -0
- package/src/__tests__/toolchain.test.ts +232 -0
- package/src/__tests__/ui-version-writers.test.ts +88 -0
- package/src/__tests__/update-apply.test.ts +637 -0
- package/src/__tests__/update-plan.test.ts +1373 -0
- package/src/__tests__/uppercase-keybindings.test.ts +101 -0
- package/src/__tests__/useGitignoreModal.test.ts +79 -0
- package/src/__tests__/version-check-refresh.test.ts +45 -0
- package/src/__tests__/version-snapshot.test.ts +212 -0
- package/src/__tests__/version-unknown-state.test.ts +388 -0
- package/src/__tests__/worktree-registry-resolution.test.ts +107 -0
- package/src/cli/ansi.ts +520 -0
- package/src/cli/bootstrap.ts +134 -0
- package/src/cli/doctor.ts +218 -0
- package/src/cli/hook.ts +129 -0
- package/src/cli/install.ts +382 -0
- package/src/cli/live.ts +374 -0
- package/src/cli/models.ts +297 -0
- package/src/cli/profile.ts +197 -0
- package/src/cli/prompt.ts +32 -0
- package/src/cli/router.ts +207 -0
- package/src/cli/update-view.ts +526 -0
- package/src/cli/update.ts +613 -0
- package/src/cli/upgrade.ts +97 -0
- package/src/data/alias-flags.ts +301 -0
- package/src/data/cli-tools.ts +146 -0
- package/src/data/community-styles.ts +531 -0
- package/src/data/gitignore-defaults.ts +33 -0
- package/src/data/gitignore-reasons.ts +93 -0
- package/src/data/gitignore-templates.ts +25 -0
- package/src/data/marketplaces.ts +278 -0
- package/src/data/mcp-servers.ts +51 -0
- package/src/data/models-presets.ts +329 -0
- package/src/data/predefined-profiles.ts +252 -0
- package/src/data/settings-catalog.ts +714 -0
- package/src/data/skill-repos.ts +91 -0
- package/src/data/styles/asd-ste100.md +38 -0
- package/src/data/styles/calibrated.md +24 -0
- package/src/data/styles/direct.md +23 -0
- package/src/data/styles/evidence-first.md +22 -0
- package/src/data/styles/explanatory.md +23 -0
- package/src/data/styles/index.ts +57 -0
- package/src/data/styles/no-slop.md +32 -0
- package/src/data/styles/plain-language.md +23 -0
- package/src/data/styles/structured.md +30 -0
- package/src/data/styles/terminology.md +28 -0
- package/src/data/styles/terse.md +20 -0
- package/src/main.tsx +110 -0
- package/src/markdown.d.ts +13 -0
- package/src/opentui.d.ts +203 -0
- package/src/services/active-closure.ts +117 -0
- package/src/services/alias-settings.ts +60 -0
- package/src/services/alias-shell-writer.ts +1244 -0
- package/src/services/alias-store.ts +172 -0
- package/src/services/binary-signing.ts +78 -0
- package/src/services/catalog-cache-store.ts +316 -0
- package/src/services/claude-cli.ts +304 -0
- package/src/services/claude-runner.ts +31 -0
- package/src/services/claude-settings.ts +1589 -0
- package/src/services/cli-tool-commands.ts +133 -0
- package/src/services/community-fetcher.ts +90 -0
- package/src/services/community-styles.ts +1194 -0
- package/src/services/content-drift.ts +208 -0
- package/src/services/conventions-manager.ts +945 -0
- package/src/services/doctor-bins.ts +63 -0
- package/src/services/doctor.ts +570 -0
- package/src/services/dotenv.ts +181 -0
- package/src/services/git-worktree.ts +129 -0
- package/src/services/github-budget.ts +274 -0
- package/src/services/gitignore-check.ts +63 -0
- package/src/services/gitignore-detector.ts +167 -0
- package/src/services/gitignore-fixer.ts +280 -0
- package/src/services/gitignore-resolver.ts +208 -0
- package/src/services/gitignore-service.ts +167 -0
- package/src/services/hook-registration.ts +218 -0
- package/src/services/install-plan.ts +107 -0
- package/src/services/local-marketplace.ts +587 -0
- package/src/services/manifest.ts +250 -0
- package/src/services/marketplace-catalog-git.ts +173 -0
- package/src/services/marketplace-catalog.ts +129 -0
- package/src/services/marketplace-fetcher.ts +400 -0
- package/src/services/marketplace-refresh.ts +253 -0
- package/src/services/marketplace-sync.ts +145 -0
- package/src/services/mate-availability.ts +133 -0
- package/src/services/mate-catalog.ts +265 -0
- package/src/services/mcp-registry.ts +171 -0
- package/src/services/models-core.ts +969 -0
- package/src/services/models-manager.ts +606 -0
- package/src/services/plugin-checkout.ts +186 -0
- package/src/services/plugin-manager.ts +878 -0
- package/src/services/plugin-mcp-config.ts +242 -0
- package/src/services/plugin-releases.ts +47 -0
- package/src/services/plugin-requires.ts +227 -0
- package/src/services/plugin-setup.ts +965 -0
- package/src/services/profile-adopt.ts +206 -0
- package/src/services/profile-materializer.ts +133 -0
- package/src/services/profile-sync.ts +158 -0
- package/src/services/profiles.ts +225 -0
- package/src/services/resolver.ts +344 -0
- package/src/services/settings-file.ts +69 -0
- package/src/services/settings-manager.ts +307 -0
- package/src/services/skills-manager.ts +1111 -0
- package/src/services/skillsmp-client.ts +193 -0
- package/src/services/styles-manager.ts +1294 -0
- package/src/services/symlink-manager.ts +189 -0
- package/src/services/terminology-filler.ts +266 -0
- package/src/services/tool-probe.ts +1637 -0
- package/src/services/toolchain.ts +431 -0
- package/src/services/update-engine.ts +691 -0
- package/src/services/update-plan.ts +863 -0
- package/src/services/version-check.ts +127 -0
- package/src/services/version-snapshot.ts +189 -0
- package/src/tui.tsx +112 -0
- package/src/types/bun.d.ts +27 -0
- package/src/types/gitignore.ts +68 -0
- package/src/types/index.ts +447 -0
- package/src/ui/App.tsx +538 -0
- package/src/ui/adapters/catalogNotice.ts +122 -0
- package/src/ui/adapters/cliToolsAdapter.ts +176 -0
- package/src/ui/adapters/modelsAdapter.ts +213 -0
- package/src/ui/adapters/pluginsAdapter.ts +413 -0
- package/src/ui/adapters/settingsAdapter.ts +168 -0
- package/src/ui/adapters/skillsAdapter.ts +229 -0
- package/src/ui/adapters/stylesAdapter.ts +403 -0
- package/src/ui/components/CategoryHeader.tsx +64 -0
- package/src/ui/components/EmptyFilterState.tsx +32 -0
- package/src/ui/components/FlagDetailEditor.tsx +0 -0
- package/src/ui/components/ScopeIndicator.tsx +63 -0
- package/src/ui/components/ScrollableList.tsx +95 -0
- package/src/ui/components/SearchInput.tsx +57 -0
- package/src/ui/components/StyledText.tsx +75 -0
- package/src/ui/components/TabBar.tsx +101 -0
- package/src/ui/components/layout/FooterHints.tsx +78 -0
- package/src/ui/components/layout/Panel.tsx +63 -0
- package/src/ui/components/layout/ProgressBar.tsx +44 -0
- package/src/ui/components/layout/ScopeTabs.tsx +54 -0
- package/src/ui/components/layout/ScreenLayout.tsx +321 -0
- package/src/ui/components/layout/index.ts +9 -0
- package/src/ui/components/modals/ConfirmModal.tsx +62 -0
- package/src/ui/components/modals/InputModal.tsx +75 -0
- package/src/ui/components/modals/LoadingModal.tsx +51 -0
- package/src/ui/components/modals/MessageModal.tsx +66 -0
- package/src/ui/components/modals/ModalContainer.tsx +159 -0
- package/src/ui/components/modals/SelectModal.tsx +90 -0
- package/src/ui/components/modals/index.ts +6 -0
- package/src/ui/components/primitives/ActionHints.tsx +44 -0
- package/src/ui/components/primitives/DetailSection.tsx +23 -0
- package/src/ui/components/primitives/KeyValueLine.tsx +26 -0
- package/src/ui/components/primitives/ListCategoryRow.tsx +45 -0
- package/src/ui/components/primitives/MetaText.tsx +40 -0
- package/src/ui/components/primitives/ScopeDetail.tsx +67 -0
- package/src/ui/components/primitives/ScopeSquares.tsx +58 -0
- package/src/ui/components/primitives/SelectableRow.tsx +30 -0
- package/src/ui/components/primitives/index.ts +9 -0
- package/src/ui/hooks/index.ts +2 -0
- package/src/ui/hooks/useGitignoreModal.ts +95 -0
- package/src/ui/hooks/useKeyboard.ts +24 -0
- package/src/ui/hooks/useKeyboardHandler.ts +63 -0
- package/src/ui/registry.ts +33 -0
- package/src/ui/renderers/cliToolRenderers.tsx +326 -0
- package/src/ui/renderers/gitignoreRenderers.tsx +80 -0
- package/src/ui/renderers/markdownRenderer.tsx +302 -0
- package/src/ui/renderers/mcpRenderers.tsx +149 -0
- package/src/ui/renderers/modelRenderers.tsx +1309 -0
- package/src/ui/renderers/modelVisuals.tsx +1402 -0
- package/src/ui/renderers/pluginRenderers.tsx +1089 -0
- package/src/ui/renderers/pluginRowText.ts +70 -0
- package/src/ui/renderers/pluginStatusText.ts +56 -0
- package/src/ui/renderers/profileRenderers.tsx +406 -0
- package/src/ui/renderers/settingsRenderers.tsx +218 -0
- package/src/ui/renderers/skillRenderers.tsx +479 -0
- package/src/ui/renderers/styleRenderers.tsx +813 -0
- package/src/ui/screens/AliasScreen.tsx +1558 -0
- package/src/ui/screens/CliToolsScreen.tsx +367 -0
- package/src/ui/screens/EnvVarsScreen.tsx +221 -0
- package/src/ui/screens/GitignoreScreen.tsx +562 -0
- package/src/ui/screens/McpRegistryScreen.tsx +366 -0
- package/src/ui/screens/McpScreen.tsx +256 -0
- package/src/ui/screens/ModelsScreen.tsx +542 -0
- package/src/ui/screens/PluginsScreen.tsx +1464 -0
- package/src/ui/screens/ProfilesScreen.tsx +438 -0
- package/src/ui/screens/SkillsScreen.tsx +853 -0
- package/src/ui/screens/StylesScreen.tsx +1064 -0
- package/src/ui/screens/index.ts +11 -0
- package/src/ui/state/AppContext.tsx +233 -0
- package/src/ui/state/DimensionsContext.tsx +154 -0
- package/src/ui/state/reducer.ts +810 -0
- package/src/ui/state/types.ts +503 -0
- package/src/ui/theme-mode.ts +352 -0
- package/src/ui/theme-resolve.ts +147 -0
- package/src/ui/theme.ts +175 -0
- package/src/utils/clipboard.ts +58 -0
- package/src/utils/command-utils.ts +144 -0
- package/src/utils/config-dir.ts +45 -0
- package/src/utils/file-locking.ts +146 -0
- package/src/utils/fuzzy-search.ts +138 -0
- package/src/utils/go-module.ts +36 -0
- package/src/utils/open-file.ts +84 -0
- package/src/utils/run.ts +67 -0
- package/src/utils/string-utils.ts +88 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The three commands the CLI-tools screen can run against a catalogue entry:
|
|
3
|
+
* install, update, uninstall.
|
|
4
|
+
*
|
|
5
|
+
* A module rather than helpers inside the screen, for two reasons:
|
|
6
|
+
*
|
|
7
|
+
* - **The duplicate.** Uninstall existed twice — once in `CliToolsScreen.tsx`
|
|
8
|
+
* and once in `cliToolRenderers.tsx` (as `getUninstallHint`) — because the
|
|
9
|
+
* renderer needs to SHOW it and the screen needs to RUN it. The two copies
|
|
10
|
+
* had already drifted: one emitted `pip uninstall`, the other
|
|
11
|
+
* `pip uninstall -y`. Both were wrong in the same way, which is the point —
|
|
12
|
+
* a bug in a duplicated builder has to be found twice.
|
|
13
|
+
* - **Testability.** As `.tsx` helpers these were unreachable from a suite that
|
|
14
|
+
* cannot render React. As pure functions over data they are pinned by
|
|
15
|
+
* `cli-tool-commands.test.ts`, which is what proves no arm emits a bare
|
|
16
|
+
* `pip` — the defect that shipped.
|
|
17
|
+
*
|
|
18
|
+
* Import direction stays acyclic: renderer → service, screen → service +
|
|
19
|
+
* renderer.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { CliTool } from "../data/cli-tools.js";
|
|
23
|
+
import type { Command } from "../utils/command-utils.js";
|
|
24
|
+
import {
|
|
25
|
+
binInstallCommand,
|
|
26
|
+
binUninstallCommand,
|
|
27
|
+
binUpgradeCommand,
|
|
28
|
+
} from "./toolchain.js";
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* How a tool turned out to be installed, as detected from its path on disk.
|
|
32
|
+
*
|
|
33
|
+
* NOT the same question as `CliTool.packageManager`, and deliberately not the
|
|
34
|
+
* same type. `packageManager` is how magus WOULD install the tool; this is
|
|
35
|
+
* how it IS installed — which may be neither, since a user can `pnpm add -g` or
|
|
36
|
+
* `yarn global add` something the catalogue calls an npm package. Updating has
|
|
37
|
+
* to follow what is actually on the machine, or it installs a second copy
|
|
38
|
+
* beside the first and the screen then reports a conflict it created itself.
|
|
39
|
+
*
|
|
40
|
+
* `pnpm`, `yarn` and `unknown` have no `BinInstaller` counterpart, which is why
|
|
41
|
+
* the two unions stay separate rather than one being widened into the other.
|
|
42
|
+
*/
|
|
43
|
+
export type InstallMethod =
|
|
44
|
+
| "npm"
|
|
45
|
+
| "bun"
|
|
46
|
+
| "pnpm"
|
|
47
|
+
| "yarn"
|
|
48
|
+
| "brew"
|
|
49
|
+
| "pip"
|
|
50
|
+
| "unknown";
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Install a catalogue tool, derived from the entry's own fields.
|
|
54
|
+
*
|
|
55
|
+
* Entries used to carry a literal `installCommand` string beside the
|
|
56
|
+
* `packageManager` and `packageName` that describe the same thing, so the two
|
|
57
|
+
* could disagree — and did. `aider` declared `packageName: "aider-chat"` and
|
|
58
|
+
* `checkCommand: "aider --version"`, and its `installCommand` installed
|
|
59
|
+
* `aider-install`: a bootstrapper whose version nothing in this screen ever
|
|
60
|
+
* looked at, while the version check queried `aider-chat`. Deriving makes that
|
|
61
|
+
* disagreement unrepresentable rather than merely fixed.
|
|
62
|
+
*/
|
|
63
|
+
export function cliToolInstall(tool: CliTool): Command {
|
|
64
|
+
return binInstallCommand({
|
|
65
|
+
name: tool.name,
|
|
66
|
+
via: tool.packageManager,
|
|
67
|
+
package: tool.packageName,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Update a tool, following the method it was ACTUALLY installed with.
|
|
73
|
+
*
|
|
74
|
+
* Returns null when there is nothing sound to run — an `unknown` method means
|
|
75
|
+
* the detector could not attribute the binary on PATH to any package manager,
|
|
76
|
+
* and guessing there would install a second copy alongside the one already
|
|
77
|
+
* there. Callers fall back to installing.
|
|
78
|
+
*/
|
|
79
|
+
export function cliToolUpdate(
|
|
80
|
+
tool: CliTool,
|
|
81
|
+
method: InstallMethod,
|
|
82
|
+
brewFormula?: string,
|
|
83
|
+
): Command | null {
|
|
84
|
+
switch (method) {
|
|
85
|
+
// The three the resolver does not model. `pnpm`/`yarn` are not
|
|
86
|
+
// BinInstallers because magus never chooses them — it only finds them.
|
|
87
|
+
case "pnpm":
|
|
88
|
+
return { cmd: "pnpm", args: ["install", "-g", tool.packageName] };
|
|
89
|
+
case "yarn":
|
|
90
|
+
return { cmd: "yarn", args: ["global", "add", tool.packageName] };
|
|
91
|
+
case "unknown":
|
|
92
|
+
return null;
|
|
93
|
+
default:
|
|
94
|
+
// TS has narrowed to "npm" | "bun" | "brew" | "pip" here, which is
|
|
95
|
+
// assignable to BinInstaller — so the four real installers delegate,
|
|
96
|
+
// and `pip` in particular gets the uv/pipx/python3 resolution instead
|
|
97
|
+
// of the bare `pip` this switch used to fall through to.
|
|
98
|
+
return binUpgradeCommand({
|
|
99
|
+
name: tool.name,
|
|
100
|
+
via: method,
|
|
101
|
+
package: tool.packageName,
|
|
102
|
+
formula: brewFormula,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Remove a tool, following the method it was actually installed with.
|
|
109
|
+
*
|
|
110
|
+
* Null means "no command to offer": `unknown` for the reason above, and `go`
|
|
111
|
+
* because a `go install` binary has no uninstaller to call.
|
|
112
|
+
*/
|
|
113
|
+
export function cliToolUninstall(
|
|
114
|
+
tool: CliTool,
|
|
115
|
+
method: InstallMethod,
|
|
116
|
+
brewFormula?: string,
|
|
117
|
+
): Command | null {
|
|
118
|
+
switch (method) {
|
|
119
|
+
case "pnpm":
|
|
120
|
+
return { cmd: "pnpm", args: ["remove", "-g", tool.packageName] };
|
|
121
|
+
case "yarn":
|
|
122
|
+
return { cmd: "yarn", args: ["global", "remove", tool.packageName] };
|
|
123
|
+
case "unknown":
|
|
124
|
+
return null;
|
|
125
|
+
default:
|
|
126
|
+
return binUninstallCommand({
|
|
127
|
+
name: tool.name,
|
|
128
|
+
via: method,
|
|
129
|
+
package: tool.packageName,
|
|
130
|
+
formula: brewFormula,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* community-fetcher.ts — the one thing in the community-styles feature that
|
|
3
|
+
* knows `fetch` exists.
|
|
4
|
+
*
|
|
5
|
+
* ## Why a port at all
|
|
6
|
+
*
|
|
7
|
+
* Exactly one boundary gets an interface: the network. The domain here is thin,
|
|
8
|
+
* and an interface-per-class reflex would be waste — so there is no Strategy
|
|
9
|
+
* registry, no adapter factory, and nothing else in the feature is abstracted.
|
|
10
|
+
* The gain is the one the constraints demand: no test can reach GitHub, because
|
|
11
|
+
* every exported function in `community-styles.ts` takes a `StyleFetcher` as a
|
|
12
|
+
* REQUIRED argument. Omitting it is a type error, not a forgotten mock.
|
|
13
|
+
*
|
|
14
|
+
* ## Why it does not speak `Response`
|
|
15
|
+
*
|
|
16
|
+
* The classic way a port leaks its adapter. A `Response` drags in streaming
|
|
17
|
+
* semantics, a body that can only be read once, and a `fetch`-shaped mental
|
|
18
|
+
* model into every test fake. `{ status, body, etag }` is what the caller
|
|
19
|
+
* actually uses.
|
|
20
|
+
*
|
|
21
|
+
* `headers` is the one deliberate exception. `github-budget.ts` parses
|
|
22
|
+
* `retry-after` / `x-ratelimit-reset` / `x-ratelimit-remaining` itself, and it
|
|
23
|
+
* is the module that knows the two hosts differ in what they report. Re-deriving
|
|
24
|
+
* that here would fork the rate-limit logic, which is precisely what §5.3 of the
|
|
25
|
+
* design forbids. A fake supplies `new Headers({...})`, which is a standard
|
|
26
|
+
* built-in, not a fetch import.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** What the application needs from an HTTP response. Never a `Response`. */
|
|
30
|
+
export interface StyleFetchResponse {
|
|
31
|
+
status: number;
|
|
32
|
+
/** Empty for a 304 and for any status with no body. */
|
|
33
|
+
body: string;
|
|
34
|
+
etag: string | null;
|
|
35
|
+
contentType: string | null;
|
|
36
|
+
/** Handed to `github-budget` unchanged — see the header note. */
|
|
37
|
+
headers: Headers;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type StyleFetcher = (
|
|
41
|
+
url: string,
|
|
42
|
+
opts?: { etag?: string | null; timeoutMs?: number; accept?: string },
|
|
43
|
+
) => Promise<StyleFetchResponse>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 10s, matching `marketplace-fetcher.ts`. A style is a few kilobytes over a CDN
|
|
47
|
+
* — measured at ~340ms — so anything past ten seconds is a broken route rather
|
|
48
|
+
* than a slow one, and the user is waiting on a keypress they just made.
|
|
49
|
+
*/
|
|
50
|
+
export const FETCH_TIMEOUT_MS = 10_000;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The real adapter. Wraps global `fetch` and nothing more: no retry, no
|
|
54
|
+
* classification, no budget check. Those are policy and belong in the service,
|
|
55
|
+
* where they can be tested without a network.
|
|
56
|
+
*
|
|
57
|
+
* Sends `GITHUB_TOKEN` / `GITHUB_PERSONAL_ACCESS_TOKEN` to `api.github.com`
|
|
58
|
+
* ONLY — exactly as `skills-manager.ts` already does. The token raises that
|
|
59
|
+
* host's 60/hr unauthenticated budget to 5000/hr and is the documented escape
|
|
60
|
+
* hatch when the advisory says the budget is spent. It is never sent to
|
|
61
|
+
* `raw.githubusercontent.com`, which needs no auth and would receive a
|
|
62
|
+
* credential it has no business seeing.
|
|
63
|
+
*/
|
|
64
|
+
export const githubFetcher: StyleFetcher = async (url, opts = {}) => {
|
|
65
|
+
const headers: Record<string, string> = {
|
|
66
|
+
accept: opts.accept ?? "text/plain, */*",
|
|
67
|
+
"user-agent": "magus",
|
|
68
|
+
};
|
|
69
|
+
if (opts.etag) headers["if-none-match"] = opts.etag;
|
|
70
|
+
|
|
71
|
+
if (new URL(url).hostname === "api.github.com") {
|
|
72
|
+
const token =
|
|
73
|
+
process.env.GITHUB_TOKEN || process.env.GITHUB_PERSONAL_ACCESS_TOKEN;
|
|
74
|
+
if (token) headers.authorization = `Bearer ${token}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const response = await fetch(url, {
|
|
78
|
+
headers,
|
|
79
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? FETCH_TIMEOUT_MS),
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
status: response.status,
|
|
84
|
+
// 304 carries no body; reading it is still safe and yields "".
|
|
85
|
+
body: response.status === 304 ? "" : await response.text(),
|
|
86
|
+
etag: response.headers.get("etag"),
|
|
87
|
+
contentType: response.headers.get("content-type"),
|
|
88
|
+
headers: response.headers,
|
|
89
|
+
};
|
|
90
|
+
};
|