claudeup 0.3.0 → 0.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.
Files changed (68) hide show
  1. package/package.json +23 -12
  2. package/dist/data/cli-tools.d.ts +0 -13
  3. package/dist/data/cli-tools.d.ts.map +0 -1
  4. package/dist/data/cli-tools.js +0 -113
  5. package/dist/data/cli-tools.js.map +0 -1
  6. package/dist/data/marketplaces.d.ts +0 -4
  7. package/dist/data/marketplaces.d.ts.map +0 -1
  8. package/dist/data/marketplaces.js +0 -26
  9. package/dist/data/marketplaces.js.map +0 -1
  10. package/dist/data/mcp-servers.d.ts +0 -8
  11. package/dist/data/mcp-servers.d.ts.map +0 -1
  12. package/dist/data/mcp-servers.js +0 -421
  13. package/dist/data/mcp-servers.js.map +0 -1
  14. package/dist/data/statuslines.d.ts +0 -10
  15. package/dist/data/statuslines.d.ts.map +0 -1
  16. package/dist/data/statuslines.js +0 -160
  17. package/dist/data/statuslines.js.map +0 -1
  18. package/dist/index.d.ts +0 -3
  19. package/dist/index.d.ts.map +0 -1
  20. package/dist/index.js.map +0 -1
  21. package/dist/services/claude-settings.d.ts +0 -46
  22. package/dist/services/claude-settings.d.ts.map +0 -1
  23. package/dist/services/claude-settings.js +0 -248
  24. package/dist/services/claude-settings.js.map +0 -1
  25. package/dist/services/mcp-registry.d.ts +0 -10
  26. package/dist/services/mcp-registry.d.ts.map +0 -1
  27. package/dist/services/mcp-registry.js +0 -88
  28. package/dist/services/mcp-registry.js.map +0 -1
  29. package/dist/services/plugin-manager.d.ts +0 -23
  30. package/dist/services/plugin-manager.d.ts.map +0 -1
  31. package/dist/services/plugin-manager.js +0 -151
  32. package/dist/services/plugin-manager.js.map +0 -1
  33. package/dist/types/index.d.ts +0 -83
  34. package/dist/types/index.d.ts.map +0 -1
  35. package/dist/types/index.js +0 -2
  36. package/dist/types/index.js.map +0 -1
  37. package/dist/ui/app.d.ts +0 -38
  38. package/dist/ui/app.d.ts.map +0 -1
  39. package/dist/ui/app.js +0 -553
  40. package/dist/ui/app.js.map +0 -1
  41. package/dist/ui/screens/cli-tools.d.ts +0 -4
  42. package/dist/ui/screens/cli-tools.d.ts.map +0 -1
  43. package/dist/ui/screens/cli-tools.js +0 -331
  44. package/dist/ui/screens/cli-tools.js.map +0 -1
  45. package/dist/ui/screens/main-menu.d.ts +0 -3
  46. package/dist/ui/screens/main-menu.d.ts.map +0 -1
  47. package/dist/ui/screens/main-menu.js +0 -110
  48. package/dist/ui/screens/main-menu.js.map +0 -1
  49. package/dist/ui/screens/marketplace.d.ts +0 -3
  50. package/dist/ui/screens/marketplace.d.ts.map +0 -1
  51. package/dist/ui/screens/marketplace.js +0 -132
  52. package/dist/ui/screens/marketplace.js.map +0 -1
  53. package/dist/ui/screens/mcp-registry.d.ts +0 -10
  54. package/dist/ui/screens/mcp-registry.d.ts.map +0 -1
  55. package/dist/ui/screens/mcp-registry.js +0 -310
  56. package/dist/ui/screens/mcp-registry.js.map +0 -1
  57. package/dist/ui/screens/mcp-setup.d.ts +0 -4
  58. package/dist/ui/screens/mcp-setup.d.ts.map +0 -1
  59. package/dist/ui/screens/mcp-setup.js +0 -673
  60. package/dist/ui/screens/mcp-setup.js.map +0 -1
  61. package/dist/ui/screens/plugins.d.ts +0 -3
  62. package/dist/ui/screens/plugins.d.ts.map +0 -1
  63. package/dist/ui/screens/plugins.js +0 -449
  64. package/dist/ui/screens/plugins.js.map +0 -1
  65. package/dist/ui/screens/statusline.d.ts +0 -5
  66. package/dist/ui/screens/statusline.d.ts.map +0 -1
  67. package/dist/ui/screens/statusline.js +0 -235
  68. package/dist/ui/screens/statusline.js.map +0 -1
@@ -1,83 +0,0 @@
1
- export interface McpServer {
2
- name: string;
3
- description: string;
4
- command?: string;
5
- args?: string[];
6
- env?: Record<string, string>;
7
- type?: 'http';
8
- url?: string;
9
- category: 'browser' | 'ai' | 'design' | 'dev-tools' | 'cloud' | 'database' | 'productivity';
10
- requiresConfig?: boolean;
11
- configFields?: ConfigField[];
12
- }
13
- export interface ConfigField {
14
- name: string;
15
- label: string;
16
- type: 'string' | 'path' | 'url' | 'boolean';
17
- required: boolean;
18
- default?: string;
19
- envVar?: string;
20
- }
21
- export interface Marketplace {
22
- name: string;
23
- displayName: string;
24
- source: {
25
- source: 'github';
26
- repo: string;
27
- };
28
- description: string;
29
- official?: boolean;
30
- }
31
- export interface Plugin {
32
- name: string;
33
- version: string;
34
- description: string;
35
- marketplace: string;
36
- installed: boolean;
37
- availableVersion?: string;
38
- hasUpdate?: boolean;
39
- }
40
- export interface StatusLineConfig {
41
- name: string;
42
- description: string;
43
- template: string;
44
- }
45
- export interface MarketplaceSource {
46
- source: {
47
- source: 'github';
48
- repo: string;
49
- };
50
- }
51
- export interface ClaudeSettings {
52
- enabledMcpServers?: Record<string, boolean>;
53
- mcpServers?: Record<string, McpServerConfig>;
54
- enabledPlugins?: Record<string, boolean>;
55
- extraKnownMarketplaces?: Record<string, MarketplaceSource>;
56
- installedPluginVersions?: Record<string, string>;
57
- statusLine?: string;
58
- }
59
- export interface McpServerConfig {
60
- command?: string;
61
- args?: string[];
62
- env?: Record<string, string>;
63
- type?: 'http';
64
- url?: string;
65
- }
66
- export interface ClaudeLocalSettings extends ClaudeSettings {
67
- allowMcp?: boolean;
68
- }
69
- export type Screen = 'main' | 'mcp' | 'mcp-registry' | 'plugins' | 'statusline' | 'cli-tools';
70
- export interface McpRegistryServer {
71
- name: string;
72
- url: string;
73
- short_description: string;
74
- version?: string;
75
- source_code_url?: string;
76
- package_registry?: string;
77
- published_at?: string;
78
- }
79
- export interface McpRegistryResponse {
80
- servers: McpRegistryServer[];
81
- next_cursor?: string;
82
- }
83
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,QAAQ,EAAE,SAAS,GAAG,IAAI,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,cAAc,CAAC;IAC5F,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;IAC5C,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE;QACN,MAAM,EAAE,QAAQ,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE;QACN,MAAM,EAAE,QAAQ,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC7C,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC3D,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAE9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,mBAAoB,SAAQ,cAAc;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,cAAc,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,CAAC;AAG9F,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
package/dist/ui/app.d.ts DELETED
@@ -1,38 +0,0 @@
1
- import blessed from 'neo-blessed';
2
- import type { Screen } from '../types/index.js';
3
- export declare const VERSION = "0.3.0";
4
- export interface AppState {
5
- screen: blessed.Screen;
6
- currentScreen: Screen;
7
- projectPath: string;
8
- isSearching: boolean;
9
- }
10
- export declare const colors: {
11
- primary: string;
12
- secondary: string;
13
- success: string;
14
- warning: string;
15
- error: string;
16
- muted: string;
17
- bg: string;
18
- fg: string;
19
- };
20
- export declare function createApp(): AppState;
21
- export declare function navigateTo(state: AppState, screen: Screen): Promise<void>;
22
- export declare function showHelp(state: AppState): void;
23
- export declare function showLoading(state: AppState, message: string): {
24
- stop: () => void;
25
- };
26
- export declare function showMessage(state: AppState, title: string, message: string, type?: 'info' | 'success' | 'error'): Promise<void>;
27
- export declare function showConfirm(state: AppState, title: string, message: string): Promise<boolean>;
28
- export declare function showInput(state: AppState, title: string, label: string, defaultValue?: string): Promise<string | null>;
29
- export interface SelectOption {
30
- label: string;
31
- value: string;
32
- description?: string;
33
- }
34
- export declare function showSelect(state: AppState, title: string, message: string, options: SelectOption[]): Promise<string | null>;
35
- export declare function createBackground(state: AppState): blessed.BoxElement;
36
- export declare function createHeader(state: AppState, _title: string): blessed.BoxElement;
37
- export declare function createFooter(state: AppState, hints: string): blessed.BoxElement;
38
- //# sourceMappingURL=app.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/ui/app.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAOhD,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;CACtB;AAGD,eAAO,MAAM,MAAM;;;;;;;;;CASlB,CAAC;AAEF,wBAAgB,SAAS,IAAI,QAAQ,CAoDpC;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6D/E;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CA8C9C;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,MAAM,GACd;IAAE,IAAI,EAAE,MAAM,IAAI,CAAA;CAAE,CAyCtB;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,MAAM,GAAG,SAAS,GAAG,OAAgB,GAC1C,OAAO,CAAC,IAAI,CAAC,CA4Cf;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,CAoClB;AAED,wBAAgB,SAAS,CACvB,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkHxB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY,EAAE,GACtB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA8GxB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAWpE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAkChF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAU/E"}
package/dist/ui/app.js DELETED
@@ -1,553 +0,0 @@
1
- import blessed from 'neo-blessed';
2
- import { createMainMenu } from './screens/main-menu.js';
3
- import { createMcpScreen } from './screens/mcp-setup.js';
4
- import { createPluginsScreen } from './screens/plugins.js';
5
- import { createStatusLineScreen } from './screens/statusline.js';
6
- // Version from package.json
7
- export const VERSION = '0.3.0';
8
- // Claude Code color palette
9
- export const colors = {
10
- primary: 'cyan',
11
- secondary: 'magenta',
12
- success: 'green',
13
- warning: 'yellow',
14
- error: 'red',
15
- muted: 'gray',
16
- bg: 'black',
17
- fg: 'white',
18
- };
19
- export function createApp() {
20
- const screen = blessed.screen({
21
- smartCSR: true,
22
- title: 'claudeup',
23
- fullUnicode: true,
24
- });
25
- const state = {
26
- screen,
27
- currentScreen: 'plugins', // Default to plugins screen
28
- projectPath: process.cwd(),
29
- isSearching: false,
30
- };
31
- // Global key bindings - check isSearching to prevent conflicts
32
- screen.key(['escape', 'q', 'C-c'], () => {
33
- if (state.isSearching)
34
- return; // Let search handler handle escape
35
- if (state.currentScreen === 'plugins') {
36
- process.exit(0);
37
- }
38
- else {
39
- navigateTo(state, 'plugins');
40
- }
41
- });
42
- screen.key(['?'], () => {
43
- if (state.isSearching)
44
- return;
45
- showHelp(state);
46
- });
47
- // Quick navigation keys - disabled during search or in sub-screens
48
- const isTopLevelScreen = (screen) => {
49
- return ['plugins', 'mcp', 'statusline', 'cli-tools'].includes(screen);
50
- };
51
- screen.key(['1'], () => {
52
- if (state.isSearching || !isTopLevelScreen(state.currentScreen))
53
- return;
54
- navigateTo(state, 'plugins');
55
- });
56
- screen.key(['2'], () => {
57
- if (state.isSearching || !isTopLevelScreen(state.currentScreen))
58
- return;
59
- navigateTo(state, 'mcp');
60
- });
61
- screen.key(['3'], () => {
62
- if (state.isSearching || !isTopLevelScreen(state.currentScreen))
63
- return;
64
- navigateTo(state, 'statusline');
65
- });
66
- screen.key(['4'], () => {
67
- if (state.isSearching || !isTopLevelScreen(state.currentScreen))
68
- return;
69
- navigateTo(state, 'cli-tools');
70
- });
71
- return state;
72
- }
73
- export async function navigateTo(state, screen) {
74
- // Clear current screen content - destroy all children
75
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
76
- const children = [...state.screen.children];
77
- for (const child of children) {
78
- if (child.type !== 'screen') {
79
- child.detach();
80
- child.destroy();
81
- }
82
- }
83
- // Remove all global screen key bindings to prevent cross-screen contamination
84
- // This removes keys like 'r' for refresh that were set by plugins screen
85
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
86
- const scr = state.screen;
87
- if (scr.unkey && typeof scr.unkey === 'function') {
88
- // Remove common global keys that might have been set
89
- try {
90
- scr.unkey(['r']);
91
- scr.unkey(['u']);
92
- scr.unkey(['d']);
93
- scr.unkey(['a']);
94
- }
95
- catch (e) {
96
- // Ignore errors if keys weren't bound
97
- }
98
- }
99
- // Force clear and redraw the screen
100
- if (scr.clearRegion) {
101
- scr.clearRegion(0, scr.width, 0, scr.height);
102
- }
103
- if (scr.realloc) {
104
- scr.realloc();
105
- }
106
- state.currentScreen = screen;
107
- switch (screen) {
108
- case 'main':
109
- createMainMenu(state);
110
- break;
111
- case 'mcp':
112
- await createMcpScreen(state);
113
- break;
114
- case 'mcp-registry':
115
- const { createMcpRegistryScreen } = await import('./screens/mcp-registry.js');
116
- await createMcpRegistryScreen(state);
117
- break;
118
- case 'plugins':
119
- await createPluginsScreen(state);
120
- break;
121
- case 'statusline':
122
- await createStatusLineScreen(state);
123
- break;
124
- case 'cli-tools':
125
- const { createCliToolsScreen } = await import('./screens/cli-tools.js');
126
- await createCliToolsScreen(state);
127
- break;
128
- }
129
- state.screen.render();
130
- }
131
- export function showHelp(state) {
132
- const helpBox = blessed.box({
133
- parent: state.screen,
134
- top: 'center',
135
- left: 'center',
136
- width: 60,
137
- height: 20,
138
- content: `
139
- {center}{bold}{cyan-fg}claudeup{/cyan-fg} Help{/bold}{/center}
140
-
141
- {bold}Navigation{/bold}
142
- {cyan-fg}↑/↓{/cyan-fg} {gray-fg}or{/gray-fg} {cyan-fg}j/k{/cyan-fg} Move selection
143
- {cyan-fg}Enter{/cyan-fg} Select / Toggle
144
- {cyan-fg}Escape{/cyan-fg} {gray-fg}or{/gray-fg} {cyan-fg}q{/cyan-fg} Back / Quit
145
- {cyan-fg}?{/cyan-fg} This help
146
-
147
- {bold}Quick Navigation{/bold}
148
- {cyan-fg}1{/cyan-fg} Plugins {cyan-fg}3{/cyan-fg} Status Line
149
- {cyan-fg}2{/cyan-fg} MCP Servers {cyan-fg}4{/cyan-fg} CLI Tools
150
-
151
- {bold}Plugin Actions{/bold}
152
- {cyan-fg}u{/cyan-fg} Update {cyan-fg}d{/cyan-fg} Uninstall
153
- {cyan-fg}a{/cyan-fg} Update All {cyan-fg}r{/cyan-fg} Refresh
154
-
155
- {bold}MCP Servers{/bold}
156
- {cyan-fg}/{/cyan-fg} Search local + remote
157
- {cyan-fg}r{/cyan-fg} Browse MCP registry
158
- `.trim(),
159
- tags: true,
160
- border: {
161
- type: 'line',
162
- },
163
- style: {
164
- border: {
165
- fg: 'cyan',
166
- },
167
- },
168
- });
169
- helpBox.key(['escape', 'q', 'enter', '?'], () => {
170
- helpBox.destroy();
171
- state.screen.render();
172
- });
173
- helpBox.focus();
174
- state.screen.render();
175
- }
176
- export function showLoading(state, message) {
177
- const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
178
- let frameIndex = 0;
179
- let stopped = false;
180
- const loadingBox = blessed.box({
181
- parent: state.screen,
182
- top: 'center',
183
- left: 'center',
184
- width: 'shrink',
185
- height: 'shrink',
186
- padding: { left: 2, right: 2, top: 1, bottom: 1 },
187
- content: `{cyan-fg}${spinnerFrames[0]}{/cyan-fg} ${message}`,
188
- tags: true,
189
- border: {
190
- type: 'line',
191
- },
192
- style: {
193
- border: {
194
- fg: 'cyan',
195
- },
196
- },
197
- });
198
- state.screen.render();
199
- const interval = setInterval(() => {
200
- if (stopped)
201
- return;
202
- frameIndex = (frameIndex + 1) % spinnerFrames.length;
203
- loadingBox.setContent(`{cyan-fg}${spinnerFrames[frameIndex]}{/cyan-fg} ${message}`);
204
- state.screen.render();
205
- }, 80);
206
- return {
207
- stop: () => {
208
- stopped = true;
209
- clearInterval(interval);
210
- loadingBox.destroy();
211
- state.screen.render();
212
- },
213
- };
214
- }
215
- export function showMessage(state, title, message, type = 'info') {
216
- return new Promise((resolve) => {
217
- const borderColors = {
218
- info: 'cyan',
219
- success: 'green',
220
- error: 'red',
221
- };
222
- const icons = {
223
- info: 'ℹ',
224
- success: '✓',
225
- error: '✗',
226
- };
227
- const msgBox = blessed.box({
228
- parent: state.screen,
229
- top: 'center',
230
- left: 'center',
231
- width: 'shrink',
232
- height: 'shrink',
233
- padding: { left: 2, right: 2, top: 1, bottom: 1 },
234
- content: `{center}{bold}${icons[type]} ${title}{/bold}{/center}\n\n${message}\n\n{center}{gray-fg}Press any key to continue{/gray-fg}{/center}`,
235
- tags: true,
236
- border: {
237
- type: 'line',
238
- },
239
- style: {
240
- border: {
241
- fg: borderColors[type],
242
- },
243
- },
244
- });
245
- // Accept any key to dismiss
246
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
247
- msgBox.on('keypress', () => {
248
- msgBox.destroy();
249
- state.screen.render();
250
- resolve();
251
- });
252
- msgBox.focus();
253
- state.screen.render();
254
- });
255
- }
256
- export function showConfirm(state, title, message) {
257
- return new Promise((resolve) => {
258
- const confirmBox = blessed.box({
259
- parent: state.screen,
260
- top: 'center',
261
- left: 'center',
262
- width: 'shrink',
263
- height: 'shrink',
264
- padding: { left: 2, right: 2, top: 1, bottom: 1 },
265
- content: `{center}{bold}${title}{/bold}{/center}\n\n${message}\n\n{center}{green-fg}[Y]{/green-fg}es {red-fg}[N]{/red-fg}o{/center}`,
266
- tags: true,
267
- border: {
268
- type: 'line',
269
- },
270
- style: {
271
- border: {
272
- fg: 'yellow',
273
- },
274
- },
275
- });
276
- confirmBox.key(['y', 'Y'], () => {
277
- confirmBox.destroy();
278
- state.screen.render();
279
- resolve(true);
280
- });
281
- confirmBox.key(['n', 'N', 'escape', 'q'], () => {
282
- confirmBox.destroy();
283
- state.screen.render();
284
- resolve(false);
285
- });
286
- confirmBox.focus();
287
- state.screen.render();
288
- });
289
- }
290
- export function showInput(state, title, label, defaultValue) {
291
- return new Promise((resolve) => {
292
- let value = defaultValue || '';
293
- let resolved = false;
294
- // Block global key handlers while input is active
295
- state.isSearching = true;
296
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
297
- const form = blessed.box({
298
- parent: state.screen,
299
- top: 'center',
300
- left: 'center',
301
- width: 60,
302
- height: 10,
303
- keys: true,
304
- inputOnFocus: true,
305
- border: {
306
- type: 'line',
307
- },
308
- style: {
309
- border: {
310
- fg: 'cyan',
311
- },
312
- },
313
- });
314
- blessed.text({
315
- parent: form,
316
- top: 0,
317
- left: 1,
318
- content: `{bold}${title}{/bold}`,
319
- tags: true,
320
- });
321
- blessed.text({
322
- parent: form,
323
- top: 2,
324
- left: 1,
325
- content: label,
326
- });
327
- const inputBox = blessed.box({
328
- parent: form,
329
- top: 3,
330
- left: 1,
331
- width: 56,
332
- height: 3,
333
- border: {
334
- type: 'line',
335
- },
336
- style: {
337
- border: {
338
- fg: 'green',
339
- },
340
- },
341
- });
342
- const inputText = blessed.box({
343
- parent: inputBox,
344
- top: 0,
345
- left: 0,
346
- width: '100%-2',
347
- height: 1,
348
- content: value + '{inverse} {/inverse}',
349
- tags: true,
350
- });
351
- blessed.text({
352
- parent: form,
353
- top: 7,
354
- left: 1,
355
- content: '{gray-fg}Enter to confirm • Escape to cancel{/gray-fg}',
356
- tags: true,
357
- });
358
- const updateInput = () => {
359
- inputText.setContent(value + '{inverse} {/inverse}');
360
- state.screen.render();
361
- };
362
- const cleanup = () => {
363
- state.isSearching = false;
364
- form.destroy();
365
- state.screen.render();
366
- };
367
- // Handle keyboard input on the form element directly
368
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
369
- const formAny = form;
370
- formAny.on('keypress', (ch, key) => {
371
- if (resolved)
372
- return;
373
- if (key.name === 'escape') {
374
- resolved = true;
375
- cleanup();
376
- resolve(null);
377
- }
378
- else if (key.name === 'enter' || key.name === 'return') {
379
- resolved = true;
380
- cleanup();
381
- resolve(value);
382
- }
383
- else if (key.name === 'backspace') {
384
- value = value.slice(0, -1);
385
- updateInput();
386
- }
387
- else if (ch && ch.length === 1 && !key.full.startsWith('C-')) {
388
- value += ch;
389
- updateInput();
390
- }
391
- });
392
- form.focus();
393
- state.screen.render();
394
- });
395
- }
396
- export function showSelect(state, title, message, options) {
397
- return new Promise((resolve) => {
398
- let selectedIndex = 0;
399
- let resolved = false;
400
- state.isSearching = true;
401
- const boxHeight = Math.min(options.length + 8, 20);
402
- const selectBox = blessed.box({
403
- parent: state.screen,
404
- top: 'center',
405
- left: 'center',
406
- width: 60,
407
- height: boxHeight,
408
- border: {
409
- type: 'line',
410
- },
411
- style: {
412
- border: {
413
- fg: 'cyan',
414
- },
415
- },
416
- });
417
- blessed.text({
418
- parent: selectBox,
419
- top: 0,
420
- left: 1,
421
- content: `{bold}${title}{/bold}`,
422
- tags: true,
423
- });
424
- blessed.text({
425
- parent: selectBox,
426
- top: 2,
427
- left: 1,
428
- content: message,
429
- tags: true,
430
- });
431
- const listBox = blessed.box({
432
- parent: selectBox,
433
- top: 4,
434
- left: 1,
435
- width: 56,
436
- height: options.length + 2,
437
- border: {
438
- type: 'line',
439
- },
440
- style: {
441
- border: {
442
- fg: 'gray',
443
- },
444
- },
445
- });
446
- const updateList = () => {
447
- const content = options
448
- .map((opt, idx) => {
449
- const prefix = idx === selectedIndex ? '{cyan-fg}>{/cyan-fg}' : ' ';
450
- const highlight = idx === selectedIndex ? '{bold}' : '';
451
- const endHighlight = idx === selectedIndex ? '{/bold}' : '';
452
- return `${prefix} ${highlight}${opt.label}${endHighlight}`;
453
- })
454
- .join('\n');
455
- listBox.setContent(content);
456
- state.screen.render();
457
- };
458
- blessed.text({
459
- parent: selectBox,
460
- top: boxHeight - 2,
461
- left: 1,
462
- content: '{gray-fg}↑↓ Select • Enter Confirm • Esc Cancel{/gray-fg}',
463
- tags: true,
464
- });
465
- updateList();
466
- const cleanup = () => {
467
- state.isSearching = false;
468
- selectBox.destroy();
469
- state.screen.render();
470
- };
471
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
472
- selectBox.on('keypress', (_ch, key) => {
473
- if (resolved)
474
- return;
475
- if (key.name === 'escape' || key.name === 'q') {
476
- resolved = true;
477
- cleanup();
478
- resolve(null);
479
- }
480
- else if (key.name === 'enter' || key.name === 'return') {
481
- resolved = true;
482
- cleanup();
483
- resolve(options[selectedIndex].value);
484
- }
485
- else if (key.name === 'up' || key.name === 'k') {
486
- selectedIndex = Math.max(0, selectedIndex - 1);
487
- updateList();
488
- }
489
- else if (key.name === 'down' || key.name === 'j') {
490
- selectedIndex = Math.min(options.length - 1, selectedIndex + 1);
491
- updateList();
492
- }
493
- });
494
- selectBox.focus();
495
- state.screen.render();
496
- });
497
- }
498
- export function createBackground(state) {
499
- return blessed.box({
500
- parent: state.screen,
501
- top: 0,
502
- left: 0,
503
- width: '100%',
504
- height: '100%',
505
- style: {
506
- bg: 'black',
507
- },
508
- });
509
- }
510
- export function createHeader(state, _title) {
511
- // Always create background first to clear the screen
512
- createBackground(state);
513
- // Navigation tabs
514
- const tabs = [
515
- { key: '1', label: 'Plugins', screen: 'plugins' },
516
- { key: '2', label: 'MCP', screen: 'mcp' },
517
- { key: '3', label: 'Status', screen: 'statusline' },
518
- { key: '4', label: 'Tools', screen: 'cli-tools' },
519
- ];
520
- const tabContent = tabs
521
- .map((tab) => {
522
- const isActive = state.currentScreen === tab.screen;
523
- if (isActive) {
524
- return `{cyan-fg}{bold}[${tab.key}] ${tab.label}{/bold}{/cyan-fg}`;
525
- }
526
- return `{gray-fg}[${tab.key}] ${tab.label}{/gray-fg}`;
527
- })
528
- .join(' ');
529
- return blessed.box({
530
- parent: state.screen,
531
- top: 0,
532
- left: 0,
533
- width: '100%',
534
- height: 3,
535
- content: `{bold}{cyan-fg}◆ claudeup{/cyan-fg}{/bold} {gray-fg}v${VERSION}{/gray-fg} ${tabContent}\n{gray-fg}${'─'.repeat(80)}{/gray-fg}`,
536
- tags: true,
537
- style: {
538
- fg: 'white',
539
- },
540
- });
541
- }
542
- export function createFooter(state, hints) {
543
- return blessed.box({
544
- parent: state.screen,
545
- bottom: 0,
546
- left: 0,
547
- width: '100%',
548
- height: 1,
549
- content: `{gray-fg}${hints}{/gray-fg}`,
550
- tags: true,
551
- });
552
- }
553
- //# sourceMappingURL=app.js.map