@ebowwa/coder 0.7.64 → 0.7.65

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 (101) hide show
  1. package/dist/index.js +36168 -32
  2. package/dist/interfaces/ui/terminal/cli/index.js +34253 -158
  3. package/dist/interfaces/ui/terminal/native/README.md +53 -0
  4. package/dist/interfaces/ui/terminal/native/claude_code_native.darwin-x64.node +0 -0
  5. package/dist/interfaces/ui/terminal/native/claude_code_native.dylib +0 -0
  6. package/dist/interfaces/ui/terminal/native/index.d.ts +0 -0
  7. package/dist/interfaces/ui/terminal/native/index.darwin-arm64.node +0 -0
  8. package/dist/interfaces/ui/terminal/native/index.js +43 -0
  9. package/dist/interfaces/ui/terminal/native/index.node +0 -0
  10. package/dist/interfaces/ui/terminal/native/package.json +34 -0
  11. package/dist/native/README.md +53 -0
  12. package/dist/native/claude_code_native.darwin-x64.node +0 -0
  13. package/dist/native/claude_code_native.dylib +0 -0
  14. package/dist/native/index.d.ts +0 -480
  15. package/dist/native/index.darwin-arm64.node +0 -0
  16. package/dist/native/index.js +43 -1625
  17. package/dist/native/index.node +0 -0
  18. package/dist/native/package.json +34 -0
  19. package/native/index.darwin-arm64.node +0 -0
  20. package/native/index.js +33 -19
  21. package/package.json +3 -2
  22. package/packages/src/core/agent-loop/__tests__/compaction.test.ts +17 -14
  23. package/packages/src/core/agent-loop/compaction.ts +6 -2
  24. package/packages/src/core/agent-loop/index.ts +2 -0
  25. package/packages/src/core/agent-loop/loop-state.ts +1 -1
  26. package/packages/src/core/agent-loop/turn-executor.ts +4 -0
  27. package/packages/src/core/agent-loop/types.ts +4 -0
  28. package/packages/src/core/api-client-impl.ts +283 -173
  29. package/packages/src/core/cognitive-security/hooks.ts +2 -1
  30. package/packages/src/core/config/todo +7 -0
  31. package/packages/src/core/context/__tests__/integration.test.ts +334 -0
  32. package/packages/src/core/context/compaction.ts +170 -0
  33. package/packages/src/core/context/constants.ts +58 -0
  34. package/packages/src/core/context/extraction.ts +85 -0
  35. package/packages/src/core/context/index.ts +66 -0
  36. package/packages/src/core/context/summarization.ts +251 -0
  37. package/packages/src/core/context/token-estimation.ts +98 -0
  38. package/packages/src/core/context/types.ts +59 -0
  39. package/packages/src/core/models.ts +81 -4
  40. package/packages/src/core/normalizers/todo +5 -1
  41. package/packages/src/core/providers/README.md +230 -0
  42. package/packages/src/core/providers/__tests__/providers.test.ts +135 -0
  43. package/packages/src/core/providers/index.ts +419 -0
  44. package/packages/src/core/providers/types.ts +132 -0
  45. package/packages/src/core/retry.ts +10 -0
  46. package/packages/src/ecosystem/tools/index.ts +174 -0
  47. package/packages/src/index.ts +23 -2
  48. package/packages/src/interfaces/ui/index.ts +17 -20
  49. package/packages/src/interfaces/ui/spinner.ts +2 -2
  50. package/packages/src/interfaces/ui/terminal/bridge/index.ts +370 -0
  51. package/packages/src/interfaces/ui/terminal/bridge/ipc.ts +829 -0
  52. package/packages/src/interfaces/ui/terminal/bridge/screen-export.ts +968 -0
  53. package/packages/src/interfaces/ui/terminal/bridge/types.ts +226 -0
  54. package/packages/src/interfaces/ui/terminal/bridge/useBridge.ts +210 -0
  55. package/packages/src/interfaces/ui/terminal/cli/bootstrap.ts +132 -0
  56. package/packages/src/interfaces/ui/terminal/cli/index.ts +200 -13
  57. package/packages/src/interfaces/ui/terminal/cli/interactive/index.ts +110 -0
  58. package/packages/src/interfaces/ui/terminal/cli/interactive/input-handler.ts +393 -0
  59. package/packages/src/interfaces/ui/terminal/cli/interactive/interactive-runner.ts +820 -0
  60. package/packages/src/interfaces/ui/terminal/cli/interactive/message-store.ts +299 -0
  61. package/packages/src/interfaces/ui/terminal/cli/interactive/types.ts +274 -0
  62. package/packages/src/interfaces/ui/terminal/shared/index.ts +13 -0
  63. package/packages/src/interfaces/ui/terminal/shared/query.ts +9 -3
  64. package/packages/src/interfaces/ui/terminal/shared/setup.ts +5 -1
  65. package/packages/src/interfaces/ui/terminal/shared/spinner-frames.ts +73 -0
  66. package/packages/src/interfaces/ui/terminal/shared/status-line.ts +10 -2
  67. package/packages/src/native/index.ts +404 -27
  68. package/packages/src/native/tui_v2_types.ts +39 -0
  69. package/packages/src/teammates/coordination.test.ts +279 -0
  70. package/packages/src/teammates/coordination.ts +646 -0
  71. package/packages/src/teammates/index.ts +95 -25
  72. package/packages/src/teammates/integration.test.ts +272 -0
  73. package/packages/src/teammates/runner.test.ts +235 -0
  74. package/packages/src/teammates/runner.ts +750 -0
  75. package/packages/src/teammates/schemas.ts +673 -0
  76. package/packages/src/types/index.ts +1 -0
  77. package/packages/src/core/context-compaction.ts +0 -578
  78. package/packages/src/interfaces/ui/Screenshot 2026-03-02 at 9.23.10/342/200/257PM.png +0 -0
  79. package/packages/src/interfaces/ui/Screenshot 2026-03-03 at 10.55.11/342/200/257AM.png +0 -0
  80. package/packages/src/interfaces/ui/terminal/tui/HelpPanel.tsx +0 -262
  81. package/packages/src/interfaces/ui/terminal/tui/InputContext.tsx +0 -232
  82. package/packages/src/interfaces/ui/terminal/tui/InputField.tsx +0 -62
  83. package/packages/src/interfaces/ui/terminal/tui/InteractiveTUI.tsx +0 -537
  84. package/packages/src/interfaces/ui/terminal/tui/MessageArea.tsx +0 -107
  85. package/packages/src/interfaces/ui/terminal/tui/MessageStore.tsx +0 -240
  86. package/packages/src/interfaces/ui/terminal/tui/StatusBar.tsx +0 -54
  87. package/packages/src/interfaces/ui/terminal/tui/commands.ts +0 -438
  88. package/packages/src/interfaces/ui/terminal/tui/components/InteractiveElements.tsx +0 -584
  89. package/packages/src/interfaces/ui/terminal/tui/components/MultilineInput.tsx +0 -614
  90. package/packages/src/interfaces/ui/terminal/tui/components/PaneManager.tsx +0 -333
  91. package/packages/src/interfaces/ui/terminal/tui/components/Sidebar.tsx +0 -604
  92. package/packages/src/interfaces/ui/terminal/tui/components/index.ts +0 -118
  93. package/packages/src/interfaces/ui/terminal/tui/console.ts +0 -49
  94. package/packages/src/interfaces/ui/terminal/tui/index.ts +0 -90
  95. package/packages/src/interfaces/ui/terminal/tui/run.tsx +0 -42
  96. package/packages/src/interfaces/ui/terminal/tui/spinner.ts +0 -69
  97. package/packages/src/interfaces/ui/terminal/tui/tui-app.tsx +0 -390
  98. package/packages/src/interfaces/ui/terminal/tui/tui-footer.ts +0 -422
  99. package/packages/src/interfaces/ui/terminal/tui/types.ts +0 -186
  100. package/packages/src/interfaces/ui/terminal/tui/useInputHandler.ts +0 -104
  101. package/packages/src/interfaces/ui/terminal/tui/useNativeInput.ts +0 -239
@@ -1,262 +0,0 @@
1
- /** @jsx React.createElement */
2
- /**
3
- * Help Panel Component
4
- * Displays contextual help with tabbed sections
5
- */
6
-
7
- import React, { useState, useEffect } from "react";
8
- import { Box, Text, useStdout } from "ink";
9
- import chalk from "chalk";
10
-
11
- /**
12
- * Help section definition
13
- */
14
- export interface HelpSection {
15
- id: string;
16
- title: string;
17
- content: string;
18
- }
19
-
20
- /**
21
- * Help panel props
22
- */
23
- export interface HelpPanelProps {
24
- activeSection?: string;
25
- onClose?: () => void;
26
- }
27
-
28
- /**
29
- * General help section - basic usage
30
- */
31
- const GENERAL_HELP: string = `
32
- ${chalk.bold.cyan("Claude understands your codebase, makes edits with your permission,")}
33
- ${chalk.bold.cyan("and executes commands — right from your terminal.")}
34
-
35
- ${chalk.gray("─").repeat(60)}
36
-
37
- ${chalk.yellow("Input Features:")}
38
- ${chalk.green("@")} <path> ${chalk.gray("Reference files or directories")}
39
- ${chalk.green("&")} ${chalk.gray("Run command in background")}
40
- ${chalk.green("#")} <memory> ${chalk.gray("Add to persistent memory")}
41
-
42
- ${chalk.yellow("Keyboard Shortcuts:")}
43
- ${chalk.cyan("ctrl + o")} ${chalk.gray("Toggle verbose output")}
44
- ${chalk.cyan("meta + o")} ${chalk.gray("Toggle fast mode")}
45
- ${chalk.cyan("shift + ⏎")} ${chalk.gray("Insert newline")}
46
- ${chalk.cyan("ctrl + c")} ${chalk.gray("Exit session")}
47
- ${chalk.cyan("ctrl + b")} ${chalk.gray("Background task menu")}
48
-
49
- ${chalk.gray("─").repeat(60)}
50
-
51
- ${chalk.dim("For more help:")} ${chalk.blue.underline("https://code.claude.com/docs/en/overview")}
52
- `;
53
-
54
- /**
55
- * Commands help section
56
- */
57
- const COMMANDS_HELP: string = `
58
- ${chalk.bold.yellow("Session Commands:")}
59
- ${chalk.green("/help")}, ${chalk.green("/?")} Show this help
60
- ${chalk.green("/exit")}, ${chalk.green("/q")} Exit the session
61
- ${chalk.green("/new")} Start a fresh session
62
- ${chalk.green("/clear")} Clear conversation history
63
- ${chalk.green("/status")} Show session status
64
- ${chalk.green("/cost")} Show total cost
65
-
66
- ${chalk.bold.yellow("Model Commands:")}
67
- ${chalk.green("/model")} <name> Switch model
68
- ${chalk.green("/models")} List available models
69
- ${chalk.green("/tools")} List available tools
70
-
71
- ${chalk.bold.yellow("Context Commands:")}
72
- ${chalk.green("/compact")} Force context compaction
73
- ${chalk.green("/export")} [fmt] Export session (json/md/jsonl)
74
-
75
- ${chalk.bold.yellow("Session Management:")}
76
- ${chalk.green("/resume")} [id] Resume session
77
- ${chalk.green("/sessions")} List recent sessions
78
- `;
79
-
80
- /**
81
- * Checkpoint commands help section
82
- */
83
- const CHECKPOINTS_HELP: string = `
84
- ${chalk.bold.magenta("Checkpoint Commands:")}
85
- ${chalk.gray("Save and restore conversation + code state")}
86
-
87
- ${chalk.green("/checkpoint")} <label> Save checkpoint
88
- ${chalk.green("/checkpoints")} List saved checkpoints
89
- ${chalk.green("/restore")} <id> Restore checkpoint
90
- ${chalk.green("/restore-chat")} <id> Restore chat only
91
- ${chalk.green("/undo")} Go back to previous state
92
- ${chalk.green("/redo")} Go forward
93
- ${chalk.green("/cps-status")} Navigation status
94
-
95
- ${chalk.gray("─").repeat(60)}
96
-
97
- ${chalk.dim("Checkpoints capture:")}
98
- ${chalk.gray("• Conversation history")}
99
- ${chalk.gray("• File snapshots")}
100
- ${chalk.gray("• Git state")}
101
- ${chalk.gray("• Cost/tokens used")}
102
- `;
103
-
104
- /**
105
- * Custom commands help section
106
- */
107
- const CUSTOM_HELP: string = `
108
- ${chalk.bold.blue("Custom Commands & Skills:")}
109
- ${chalk.gray("Extend Coder with your own commands")}
110
-
111
- ${chalk.yellow("Skills:")}
112
- ${chalk.green("/commit")} Create a git commit
113
- ${chalk.green("/review-pr")} Review a pull request
114
- ${chalk.green("/git")} Git workflow helper
115
- ${chalk.green("/mcp-builder")} Build MCP servers
116
-
117
- ${chalk.yellow("Configuration:")}
118
- ${chalk.cyan("~/.claude/CLAUDE.md")} ${chalk.gray("Global instructions")}
119
- ${chalk.cyan(".claude/CLAUDE.md")} ${chalk.gray("Project instructions")}
120
- ${chalk.cyan("~/.claude.json")} ${chalk.gray("MCP servers config")}
121
- ${chalk.cyan("~/.claude/settings.json")} ${chalk.gray("Hooks & permissions")}
122
- ${chalk.cyan("~/.claude/keybindings.json")} ${chalk.gray("Custom keybindings")}
123
-
124
- ${chalk.gray("─").repeat(60)}
125
-
126
- ${chalk.dim("Create custom skills in:")} ${chalk.cyan("~/.claude/skills/")}
127
- `;
128
-
129
- /**
130
- * Keybindings help section
131
- */
132
- const KEYBINDINGS_HELP: string = `
133
- ${chalk.bold.green("Keyboard Shortcuts")}
134
-
135
- ${chalk.yellow("Input Editing:")}
136
- ${chalk.cyan("← →")} Move cursor
137
- ${chalk.cyan("Home / End")} Jump to start/end
138
- ${chalk.cyan("ctrl + a")} Jump to start
139
- ${chalk.cyan("ctrl + e")} Jump to end
140
- ${chalk.cyan("ctrl + u")} Clear line
141
- ${chalk.cyan("ctrl + w")} Delete word
142
-
143
- ${chalk.yellow("Navigation:")}
144
- ${chalk.cyan("Page Up / Down")} Scroll messages
145
- ${chalk.cyan("shift + ↑ ↓")} Scroll one line
146
- ${chalk.cyan("tab")} Cycle help sections
147
- ${chalk.cyan("← →")} Cycle sections (in help)
148
-
149
- ${chalk.yellow("Session:")}
150
- ${chalk.cyan("ctrl + c")} Exit session
151
- ${chalk.cyan("ctrl + d")} Exit (alternative)
152
- ${chalk.cyan("ctrl + b")} Background tasks
153
-
154
- ${chalk.gray("─").repeat(60)}
155
-
156
- ${chalk.dim("Customize:")} ${chalk.green("/keybindings")}
157
- `;
158
-
159
- /**
160
- * All help sections
161
- */
162
- const HELP_SECTIONS: HelpSection[] = [
163
- { id: "general", title: "general", content: GENERAL_HELP },
164
- { id: "commands", title: "commands", content: COMMANDS_HELP },
165
- { id: "checkpoints", title: "checkpoints", content: CHECKPOINTS_HELP },
166
- { id: "custom", title: "custom-commands", content: CUSTOM_HELP },
167
- { id: "keybindings", title: "keybindings", content: KEYBINDINGS_HELP },
168
- ];
169
-
170
- /**
171
- * Help Panel Component
172
- */
173
- export function HelpPanel({ activeSection = "general", onClose }: HelpPanelProps) {
174
- const [currentSection, setCurrentSection] = useState(0);
175
- const { stdout } = useStdout();
176
-
177
- // Find initial section index
178
- useEffect(() => {
179
- const index = HELP_SECTIONS.findIndex(s => s.id === activeSection);
180
- if (index >= 0) {
181
- setCurrentSection(index);
182
- }
183
- }, [activeSection]);
184
-
185
- const section = HELP_SECTIONS[currentSection];
186
- if (!section) return null;
187
-
188
- // Build tab bar
189
- const tabBar = HELP_SECTIONS.map((s, i) => {
190
- const isActive = i === currentSection;
191
- const label = s.title;
192
- if (isActive) {
193
- return chalk.bgCyan.black(` ${label} `);
194
- }
195
- return chalk.dim(` ${label} `);
196
- }).join(chalk.gray("│"));
197
-
198
- // Navigation hint
199
- const navHint = chalk.dim("←/→ or tab to cycle");
200
-
201
- return (
202
- <Box flexDirection="column" width={stdout.columns || 80}>
203
- {/* Header */}
204
- <Box>
205
- <Text>
206
- {chalk.gray("─").repeat(3)}
207
- {chalk.bold.cyan(" Coder ")}
208
- {chalk.gray("v0.2.0 ─ ")}
209
- {tabBar}
210
- {chalk.gray(" ─ ")}
211
- {navHint}
212
- {chalk.gray("─".repeat(Math.max(0, (stdout.columns || 80) - 60)))}
213
- </Text>
214
- </Box>
215
-
216
- {/* Content */}
217
- <Box flexDirection="column" paddingX={1}>
218
- <Text>{section.content}</Text>
219
- </Box>
220
-
221
- {/* Footer */}
222
- <Box>
223
- <Text dimColor>
224
- {chalk.gray("─").repeat(Math.min((stdout.columns || 80), 80))}
225
- </Text>
226
- </Box>
227
- </Box>
228
- );
229
- }
230
-
231
- /**
232
- * Get all help sections
233
- */
234
- export function getHelpSections(): HelpSection[] {
235
- return HELP_SECTIONS;
236
- }
237
-
238
- /**
239
- * Get help text for a specific section (for non-interactive display)
240
- */
241
- export function getHelpText(section?: string): string {
242
- if (section) {
243
- const s = HELP_SECTIONS.find(s => s.id === section || s.title === section);
244
- if (s) return s.content;
245
- }
246
-
247
- // Return all sections combined
248
- return HELP_SECTIONS.map(s => s.content).join("\n");
249
- }
250
-
251
- /**
252
- * Get compact help text (single line per command)
253
- */
254
- export function getCompactHelpText(): string {
255
- return `
256
- Commands: /help /exit /new /clear /compact /model /models /tools /cost /status /resume
257
- Checkpoints: /checkpoint /checkpoints /restore /undo /redo /cps-status
258
- Export: /export [json|md|jsonl]
259
- `;
260
- }
261
-
262
- export default HelpPanel;
@@ -1,232 +0,0 @@
1
- /** @jsx React.createElement */
2
- /** @jsxFrag React.Fragment */
3
- /**
4
- * Centralized Input Management System
5
- *
6
- * Single source of truth for keyboard input across all TUI components.
7
- * Solves the problem of multiple components fighting over stdin.
8
- *
9
- * Architecture:
10
- * - InputProvider wraps the entire TUI
11
- * - Components register/unregister as input handlers
12
- * - Focus system ensures only ONE handler receives input
13
- * - Priority system for modals/overlays
14
- */
15
-
16
- import React, { createContext, useContext, useState, useCallback, useRef, useEffect } from "react";
17
- import type { NativeKeyEvent } from "../../../../native/index.js";
18
-
19
- // Re-export NativeKeyEvent for convenience
20
- export type { NativeKeyEvent } from "../../../../native/index.js";
21
-
22
- // ============================================
23
- // TYPES
24
- // ============================================
25
-
26
- export type InputHandler = (event: NativeKeyEvent) => boolean;
27
-
28
- export interface InputHandlerOptions {
29
- /** Unique ID for this handler */
30
- id: string;
31
- /** Priority (higher = receives input first) */
32
- priority?: number;
33
- /** Handler function - return true to consume, false to pass through */
34
- handler: InputHandler;
35
- /** Whether this handler is currently active */
36
- isActive?: boolean;
37
- }
38
-
39
- export interface InputContextValue {
40
- /** Register an input handler */
41
- register: (options: InputHandlerOptions) => () => void;
42
- /** Set focus to a specific handler */
43
- focus: (handlerId: string) => void;
44
- /** Get currently focused handler ID */
45
- focusedId: string | null;
46
- /** Dispatch a key event to handlers */
47
- dispatch: (event: NativeKeyEvent) => boolean;
48
- /** Whether input is currently blocked */
49
- isBlocked: boolean;
50
- /** Block/unblock input (for loading states) */
51
- setBlocked: (blocked: boolean) => void;
52
- }
53
-
54
- // ============================================
55
- // CONTEXT
56
- // ============================================
57
-
58
- const InputContext = createContext<InputContextValue | null>(null);
59
-
60
- export function useInputContext(): InputContextValue {
61
- const ctx = useContext(InputContext);
62
- if (!ctx) {
63
- throw new Error("useInputContext must be used within InputProvider");
64
- }
65
- return ctx;
66
- }
67
-
68
- // ============================================
69
- // PROVIDER
70
- // ============================================
71
-
72
- export interface InputProviderProps {
73
- children: React.ReactNode;
74
- /** Initial blocked state */
75
- initialBlocked?: boolean;
76
- }
77
-
78
- export function InputProvider({ children, initialBlocked = false }: InputProviderProps) {
79
- const handlersRef = useRef<Map<string, InputHandlerOptions>>(new Map());
80
- const [focusedId, setFocusedId] = useState<string | null>(null);
81
- const [isBlocked, setIsBlocked] = useState(initialBlocked);
82
-
83
- const register = useCallback((options: InputHandlerOptions) => {
84
- const { id } = options;
85
- handlersRef.current.set(id, options);
86
-
87
- // If no focus set, focus this handler
88
- if (!focusedId) {
89
- setFocusedId(id);
90
- }
91
-
92
- // Return unregister function
93
- return () => {
94
- handlersRef.current.delete(id);
95
- if (focusedId === id) {
96
- // Focus next available handler (highest priority)
97
- const remaining = Array.from(handlersRef.current.values())
98
- .filter(h => h.isActive !== false)
99
- .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
100
- setFocusedId(remaining[0]?.id ?? null);
101
- }
102
- };
103
- }, [focusedId]);
104
-
105
- const focus = useCallback((handlerId: string) => {
106
- if (handlersRef.current.has(handlerId)) {
107
- setFocusedId(handlerId);
108
- }
109
- }, []);
110
-
111
- const dispatch = useCallback((event: NativeKeyEvent): boolean => {
112
- if (isBlocked) return false;
113
-
114
- // Get all active handlers sorted by priority (highest first)
115
- const activeHandlers = Array.from(handlersRef.current.values())
116
- .filter(h => h.isActive !== false)
117
- .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
118
-
119
- // First, try the focused handler
120
- if (focusedId) {
121
- const focused = handlersRef.current.get(focusedId);
122
- if (focused?.isActive !== false && focused?.handler) {
123
- const consumed = focused.handler(event);
124
- if (consumed) return true;
125
- }
126
- }
127
-
128
- // Then try other handlers by priority
129
- for (const h of activeHandlers) {
130
- if (h.id === focusedId) continue; // Already tried
131
- const consumed = h.handler(event);
132
- if (consumed) return true;
133
- }
134
-
135
- return false;
136
- }, [isBlocked, focusedId]);
137
-
138
- const setBlocked = useCallback((blocked: boolean) => {
139
- setIsBlocked(blocked);
140
- }, []);
141
-
142
- const value: InputContextValue = {
143
- register,
144
- focus,
145
- focusedId,
146
- dispatch,
147
- isBlocked,
148
- setBlocked,
149
- };
150
-
151
- return (
152
- <InputContext.Provider value={value}>
153
- {children}
154
- </InputContext.Provider>
155
- );
156
- }
157
-
158
- // ============================================
159
- // CONVENIENCE HOOKS
160
- // ============================================
161
-
162
- /**
163
- * Hook to register an input handler with the centralized system
164
- * Automatically unregisters on unmount
165
- */
166
- export function useInputRegistration(
167
- id: string,
168
- handler: InputHandler,
169
- options: { priority?: number; isActive?: boolean } = {}
170
- ) {
171
- const { register } = useInputContext();
172
-
173
- useEffect(() => {
174
- return register({
175
- id,
176
- handler,
177
- priority: options.priority,
178
- isActive: options.isActive,
179
- });
180
- }, [id, handler, options.priority, options.isActive, register]);
181
- }
182
-
183
- // Alias for convenience
184
- export const useInputHandler = useInputRegistration;
185
-
186
- /**
187
- * Hook to receive focus for a handler
188
- */
189
- export function useInputFocus(handlerId: string) {
190
- const { focus, focusedId } = useInputContext();
191
- const isFocused = focusedId === handlerId;
192
-
193
- return {
194
- isFocused,
195
- focus: () => focus(handlerId),
196
- };
197
- }
198
-
199
- /**
200
- * Hook for components that need to block input
201
- */
202
- export function useInputBlock() {
203
- const { isBlocked, setBlocked } = useInputContext();
204
- return { isBlocked, setBlocked };
205
- }
206
-
207
- // ============================================
208
- // PRIORITY CONSTANTS
209
- // ============================================
210
-
211
- export const InputPriority = {
212
- /** Normal components */
213
- DEFAULT: 0,
214
- /** Focused input fields */
215
- INPUT: 10,
216
- /** Selectable lists */
217
- LIST: 20,
218
- /** Sidebar */
219
- SIDEBAR: 30,
220
- /** Modal dialogs */
221
- MODAL: 100,
222
- /** Toast notifications (can dismiss) */
223
- TOAST: 110,
224
- /** System-level (Ctrl+C, etc.) */
225
- SYSTEM: 1000,
226
- } as const;
227
-
228
- // ============================================
229
- // EXPORTS
230
- // ============================================
231
-
232
- export default InputContext;
@@ -1,62 +0,0 @@
1
- /** @jsx React.createElement */
2
- /** @jsxFrag React.Fragment */
3
- /**
4
- * Input Field Component - Simple plain text input
5
- */
6
-
7
- import React, { useSyncExternalStore } from "react";
8
- import { Text } from "ink";
9
- import type { InputFieldProps } from "./types.js";
10
-
11
- // Global input display state - bypasses React batching
12
- let globalInputValue = "";
13
- let globalCursorPos = 0;
14
- const listeners = new Set<() => void>();
15
-
16
- export function setGlobalInput(value: string, cursor: number) {
17
- globalInputValue = value;
18
- globalCursorPos = cursor;
19
- listeners.forEach((listener) => listener());
20
- }
21
-
22
- export function getGlobalInput() {
23
- return { value: globalInputValue, cursorPos: globalCursorPos };
24
- }
25
-
26
- function subscribe(callback: () => void) {
27
- listeners.add(callback);
28
- return () => listeners.delete(callback);
29
- }
30
-
31
- function getSnapshot() {
32
- return { value: globalInputValue, cursorPos: globalCursorPos };
33
- }
34
-
35
- /**
36
- * Simple input field - just text, no box
37
- */
38
- export function InputField({ placeholder, isActive }: Omit<InputFieldProps, "value" | "cursorPos">) {
39
- const { value, cursorPos } = useSyncExternalStore(subscribe, getSnapshot);
40
-
41
- const beforeCursor = value.slice(0, cursorPos);
42
- const afterCursor = value.slice(cursorPos);
43
-
44
- return (
45
- <Text>
46
- <Text bold color={isActive ? "cyan" : "gray"}>You: </Text>
47
- {value.length > 0 ? (
48
- <>
49
- {beforeCursor}
50
- <Text backgroundColor="cyan" color="black">
51
- {cursorPos < value.length ? value[cursorPos] : " "}
52
- </Text>
53
- {afterCursor}
54
- </>
55
- ) : (
56
- <Text dimColor>{placeholder}</Text>
57
- )}
58
- </Text>
59
- );
60
- }
61
-
62
- export default InputField;