magus-cli 7.3.0 → 7.4.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.
Files changed (130) hide show
  1. package/package.json +4 -4
  2. package/scripts/build-binaries.ts +4 -2
  3. package/src/__tests__/blind/c1-npm-package.test.ts +206 -0
  4. package/src/__tests__/blind/c10-colour-roles.test.ts +265 -0
  5. package/src/__tests__/blind/c11-cli-parse-refusal.test.ts +454 -0
  6. package/src/__tests__/blind/c12-skill-frontmatter.test.ts +323 -0
  7. package/src/__tests__/blind/c13-wrong-shape.test.ts +603 -0
  8. package/src/__tests__/blind/c14-cli-row-label.test.ts +259 -0
  9. package/src/__tests__/blind/c15-probe-ownership.test.ts +533 -0
  10. package/src/__tests__/blind/c16-nested-wrong-shape.test.ts +297 -0
  11. package/src/__tests__/blind/c17-enter-label.test.ts +625 -0
  12. package/src/__tests__/blind/c18-hook-shape.test.ts +354 -0
  13. package/src/__tests__/blind/c2-settings-parse.test.ts +350 -0
  14. package/src/__tests__/blind/c4-key-dispatch.test.ts +397 -0
  15. package/src/__tests__/blind/c5-keymap.test.ts +461 -0
  16. package/src/__tests__/blind/c6-request-gate.test.ts +133 -0
  17. package/src/__tests__/blind/c7-tab-tiers.test.ts +320 -0
  18. package/src/__tests__/blind/c8-text-width.test.ts +137 -0
  19. package/src/__tests__/blind/c9-cli-tool-version.test.ts +239 -0
  20. package/src/__tests__/blind/child-run.ts +114 -0
  21. package/src/__tests__/cli-tools-adapter.test.ts +5 -2
  22. package/src/__tests__/component-badge.test.ts +20 -36
  23. package/src/__tests__/footer-hints.test.ts +1 -1
  24. package/src/__tests__/manifest.test.ts +25 -17
  25. package/src/__tests__/marketplace-badge.test.ts +4 -4
  26. package/src/__tests__/models-screen-state.test.ts +36 -13
  27. package/src/__tests__/npm-package-name-api.test.ts +111 -0
  28. package/src/__tests__/npm-package-name.test.ts +280 -0
  29. package/src/__tests__/scope-squares.test.tsx +28 -114
  30. package/src/__tests__/shutdown.test.ts +578 -0
  31. package/src/__tests__/styles-manager.test.ts +4 -4
  32. package/src/__tests__/styles-screen-state.test.ts +26 -12
  33. package/src/__tests__/tabbar-layout.test.ts +44 -32
  34. package/src/__tests__/theme-adaptive-colors.test.ts +6 -59
  35. package/src/__tests__/tool-probe.test.ts +47 -22
  36. package/src/__tests__/upgrade-spawn.test.ts +355 -0
  37. package/src/__tests__/uppercase-keybindings.test.ts +25 -12
  38. package/src/cli/ansi.ts +2 -2
  39. package/src/cli/bootstrap.ts +33 -2
  40. package/src/cli/doctor.ts +105 -14
  41. package/src/cli/install.ts +8 -2
  42. package/src/cli/profile.ts +18 -1
  43. package/src/cli/router.ts +31 -18
  44. package/src/cli/update-view.ts +1 -1
  45. package/src/cli/upgrade.ts +37 -9
  46. package/src/data/cli-tools.ts +13 -2
  47. package/src/data/npm-package.ts +15 -0
  48. package/src/services/claude-settings.ts +151 -73
  49. package/src/services/cli-tool-commands.ts +15 -5
  50. package/src/services/cli-tool-version.ts +101 -0
  51. package/src/services/hook-registration.ts +23 -6
  52. package/src/services/manifest.ts +117 -52
  53. package/src/services/plugin-manager.ts +19 -5
  54. package/src/services/profile-adopt.ts +7 -2
  55. package/src/services/profile-startup.ts +87 -7
  56. package/src/services/profiles.ts +36 -23
  57. package/src/services/settings-file.ts +158 -4
  58. package/src/services/settings-manager.ts +19 -5
  59. package/src/services/skills-manager.ts +46 -0
  60. package/src/services/tool-probe.ts +272 -45
  61. package/src/services/toolchain.ts +39 -0
  62. package/src/services/update-engine.ts +5 -0
  63. package/src/services/update-plan.ts +9 -0
  64. package/src/services/version-check.ts +20 -10
  65. package/src/tui.tsx +48 -21
  66. package/src/ui/App.tsx +58 -197
  67. package/src/ui/adapters/cliToolsAdapter.ts +141 -12
  68. package/src/ui/adapters/pluginsAdapter.ts +10 -7
  69. package/src/ui/adapters/settingsAdapter.ts +0 -21
  70. package/src/ui/adapters/skillsAdapter.ts +27 -8
  71. package/src/ui/adapters/stylesAdapter.ts +15 -11
  72. package/src/ui/components/CategoryHeader.tsx +7 -1
  73. package/src/ui/components/EmptyFilterState.tsx +2 -2
  74. package/src/ui/components/FlagDetailEditor.tsx +0 -0
  75. package/src/ui/components/ScreenErrorBoundary.tsx +105 -0
  76. package/src/ui/components/TabBar.tsx +93 -21
  77. package/src/ui/components/layout/FooterHints.tsx +6 -27
  78. package/src/ui/components/layout/ScreenLayout.tsx +68 -42
  79. package/src/ui/components/layout/index.ts +1 -5
  80. package/src/ui/components/modals/ConfirmModal.tsx +2 -19
  81. package/src/ui/components/modals/HelpOverlay.tsx +186 -0
  82. package/src/ui/components/modals/MessageModal.tsx +3 -15
  83. package/src/ui/components/modals/ModalContainer.tsx +99 -60
  84. package/src/ui/components/primitives/ErrorNotice.tsx +38 -0
  85. package/src/ui/components/primitives/ListCategoryRow.tsx +18 -7
  86. package/src/ui/components/primitives/MetaText.tsx +1 -1
  87. package/src/ui/components/primitives/ScopeDetail.tsx +31 -26
  88. package/src/ui/components/primitives/ScopeSquares.tsx +23 -28
  89. package/src/ui/components/primitives/SelectableRow.tsx +24 -1
  90. package/src/ui/components/primitives/index.ts +4 -3
  91. package/src/ui/hooks/useProfileStartupModal.ts +15 -3
  92. package/src/ui/input/KeyRouter.tsx +180 -0
  93. package/src/ui/input/key-dispatch.ts +149 -0
  94. package/src/ui/keymap.ts +898 -0
  95. package/src/ui/renderers/cliToolRenderers.tsx +128 -66
  96. package/src/ui/renderers/gitignoreRenderers.tsx +41 -43
  97. package/src/ui/renderers/markdownRenderer.tsx +2 -2
  98. package/src/ui/renderers/mcpRenderers.tsx +28 -14
  99. package/src/ui/renderers/modelRenderers.tsx +12 -13
  100. package/src/ui/renderers/modelVisuals.tsx +0 -2
  101. package/src/ui/renderers/pluginRenderers.tsx +47 -54
  102. package/src/ui/renderers/profileRenderers.tsx +32 -37
  103. package/src/ui/renderers/settingsRenderers.tsx +84 -55
  104. package/src/ui/renderers/skillRenderers.tsx +237 -190
  105. package/src/ui/renderers/styleRenderers.tsx +13 -2
  106. package/src/ui/runtime/shutdown.ts +268 -0
  107. package/src/ui/screens/AliasScreen.tsx +118 -100
  108. package/src/ui/screens/CliToolsScreen.tsx +98 -87
  109. package/src/ui/screens/EnvVarsScreen.tsx +44 -42
  110. package/src/ui/screens/GitignoreScreen.tsx +50 -55
  111. package/src/ui/screens/McpRegistryScreen.tsx +52 -86
  112. package/src/ui/screens/McpScreen.tsx +47 -33
  113. package/src/ui/screens/ModelsScreen.tsx +59 -104
  114. package/src/ui/screens/PluginsScreen.tsx +123 -127
  115. package/src/ui/screens/ProfilesScreen.tsx +49 -46
  116. package/src/ui/screens/SkillsScreen.tsx +184 -204
  117. package/src/ui/screens/StylesScreen.tsx +104 -157
  118. package/src/ui/state/AppContext.tsx +6 -0
  119. package/src/ui/state/DimensionsContext.tsx +1 -10
  120. package/src/ui/state/reducer.ts +5 -8
  121. package/src/ui/state/types.ts +11 -9
  122. package/src/ui/text-width.ts +341 -0
  123. package/src/ui/theme-mode.ts +34 -71
  124. package/src/ui/theme.ts +50 -28
  125. package/src/utils/request-gate.ts +37 -0
  126. package/src/ui/components/ScopeIndicator.tsx +0 -63
  127. package/src/ui/components/SearchInput.tsx +0 -57
  128. package/src/ui/hooks/index.ts +0 -2
  129. package/src/ui/hooks/useKeyboard.ts +0 -24
  130. package/src/ui/hooks/useKeyboardHandler.ts +0 -63
@@ -1,63 +0,0 @@
1
- import React from "react";
2
- import { type UiColor, theme } from "../theme.js";
3
-
4
- /**
5
- * Scope indicator for list items.
6
- * Shows colored letter badges when installed, empty space when not.
7
- *
8
- * Installed in user+project: u p
9
- * Installed in project only: p
10
- * Not installed: (3 spaces)
11
- *
12
- * Colors match the detail panel: cyan=user, green=project, yellow=local
13
- */
14
-
15
- export function scopeIndicatorText(
16
- user?: boolean,
17
- project?: boolean,
18
- local?: boolean,
19
- ): {
20
- text: string;
21
- segments: Array<{ char: string; bg: UiColor; fg: UiColor }>;
22
- } {
23
- const segments: Array<{ char: string; bg: UiColor; fg: UiColor }> = [
24
- user
25
- ? { char: "u", bg: theme.colors.info, fg: theme.hints.fg }
26
- : { char: " ", bg: "", fg: "" },
27
- project
28
- ? { char: "p", bg: theme.colors.success, fg: theme.hints.fg }
29
- : { char: " ", bg: "", fg: "" },
30
- local
31
- ? { char: "l", bg: theme.colors.warning, fg: theme.hints.fg }
32
- : { char: " ", bg: "", fg: "" },
33
- ];
34
-
35
- const text = segments.map((s) => s.char).join("");
36
- return { text, segments };
37
- }
38
-
39
- interface ScopeIndicatorProps {
40
- user?: boolean;
41
- project?: boolean;
42
- local?: boolean;
43
- }
44
-
45
- export function ScopeIndicator({ user, project, local }: ScopeIndicatorProps) {
46
- const { segments } = scopeIndicatorText(user, project, local);
47
-
48
- return (
49
- <text fg={theme.colors.text}>
50
- {segments.map((s, i) =>
51
- s.bg ? (
52
- // biome-ignore lint/suspicious/noArrayIndexKey: segments are fixed-position scope squares (user/project/local); the slot is the identity and the list never reorders
53
- <span key={i} bg={s.bg} fg={s.fg}>
54
- {s.char}
55
- </span>
56
- ) : (
57
- // biome-ignore lint/suspicious/noArrayIndexKey: same fixed-slot list as above
58
- <span key={i}> </span>
59
- ),
60
- )}
61
- </text>
62
- );
63
- }
@@ -1,57 +0,0 @@
1
- import React from "react";
2
- import { useKeyboardHandler } from "../hooks/useKeyboardHandler.js";
3
- import { theme } from "../theme.js";
4
-
5
- interface SearchInputProps {
6
- /** Current search value */
7
- value: string;
8
- /** Called when value changes */
9
- onChange: (value: string) => void;
10
- /** Placeholder text when empty */
11
- placeholder?: string;
12
- /** Whether the input is focused/active */
13
- isActive: boolean;
14
- /** Called when user presses escape to exit search */
15
- onExit?: () => void;
16
- /** Called when user presses enter */
17
- onSubmit?: () => void;
18
- }
19
-
20
- export function SearchInput({
21
- value,
22
- onChange,
23
- placeholder = "Search...",
24
- isActive,
25
- onExit,
26
- onSubmit,
27
- }: SearchInputProps) {
28
- // Handle keyboard shortcuts when active
29
- useKeyboardHandler((_input, key) => {
30
- if (!isActive) return;
31
-
32
- if (key.escape) {
33
- onExit?.();
34
- return;
35
- }
36
-
37
- if (key.return) {
38
- onSubmit?.();
39
- return;
40
- }
41
- });
42
-
43
- return (
44
- <box flexDirection="row">
45
- <text fg={theme.colors.info}>❯ </text>
46
- <input
47
- value={value}
48
- onChange={onChange}
49
- placeholder={placeholder}
50
- focused={isActive}
51
- width={40}
52
- />
53
- </box>
54
- );
55
- }
56
-
57
- export default SearchInput;
@@ -1,2 +0,0 @@
1
- export { useKeyboardHandler } from "./useKeyboardHandler.js";
2
- export { useKeyboard } from "./useKeyboard.js";
@@ -1,24 +0,0 @@
1
- import { useKeyboard as useOpenTUIKeyboard } from "@opentui/react";
2
-
3
- /**
4
- * OpenTUI keyboard event type
5
- */
6
- export interface KeyEvent {
7
- name: string;
8
- ctrl?: boolean;
9
- shift?: boolean;
10
- meta?: boolean;
11
- }
12
-
13
- /**
14
- * Simple re-export of OpenTUI's useKeyboard hook
15
- * Used by modals for direct keyboard event handling
16
- *
17
- * Key names in OpenTUI:
18
- * - Single characters: "a", "1", etc.
19
- * - Arrow keys: "up", "down", "left", "right"
20
- * - Special: "enter", "escape", "tab", "backspace", "delete"
21
- */
22
- export function useKeyboard(handler: (event: KeyEvent) => void): void {
23
- useOpenTUIKeyboard(handler);
24
- }
@@ -1,63 +0,0 @@
1
- import { useKeyboard as useOpenTUIKeyboard } from "@opentui/react";
2
-
3
- /**
4
- * Wrapper hook for OpenTUI's useKeyboard that provides an Ink-like API
5
- * Maps Ink key names to OpenTUI key names for easier migration
6
- */
7
-
8
- export interface InkLikeKey {
9
- name: string;
10
- ctrl: boolean;
11
- shift: boolean;
12
- meta: boolean;
13
- return?: boolean;
14
- upArrow?: boolean;
15
- downArrow?: boolean;
16
- leftArrow?: boolean;
17
- rightArrow?: boolean;
18
- escape?: boolean;
19
- tab?: boolean;
20
- }
21
-
22
- type KeyHandler = (input: string, key: InkLikeKey) => void;
23
-
24
- /**
25
- * useKeyboardHandler hook
26
- * Provides Ink-like API for keyboard events
27
- *
28
- * @param handler - Callback function with Ink-compatible signature
29
- *
30
- * @example
31
- * ```tsx
32
- * useKeyboardHandler((input, key) => {
33
- * if (key.return) handleEnter();
34
- * if (key.upArrow) handleUp();
35
- * if (key.escape) handleEscape();
36
- * if (input === 'q') handleQuit();
37
- * });
38
- * ```
39
- */
40
- export function useKeyboardHandler(handler: KeyHandler): void {
41
- useOpenTUIKeyboard((event) => {
42
- // Map OpenTUI key names to Ink-like key names
43
- const key: InkLikeKey = {
44
- name: event.name,
45
- ctrl: event.ctrl || false,
46
- shift: event.shift || false,
47
- meta: event.meta || false,
48
- return: event.name === "enter" || event.name === "return",
49
- upArrow: event.name === "up",
50
- downArrow: event.name === "down",
51
- leftArrow: event.name === "left",
52
- rightArrow: event.name === "right",
53
- escape: event.name === "escape",
54
- tab: event.name === "tab",
55
- };
56
-
57
- // For printable characters, pass the character as input
58
- // For special keys, pass empty string
59
- const input = event.name.length === 1 ? event.name : "";
60
-
61
- handler(input, key);
62
- });
63
- }