ubume 0.1.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 (182) hide show
  1. package/README.md +88 -0
  2. package/bin/codexa-local-harness-bridge.js +3 -0
  3. package/bin/codexa.js +28 -0
  4. package/bin/ubume-local-harness-bridge.js +325 -0
  5. package/bin/ubume.js +398 -0
  6. package/package.json +66 -0
  7. package/src/app.tsx +5759 -0
  8. package/src/commands/handler.ts +889 -0
  9. package/src/config/appVersion.ts +69 -0
  10. package/src/config/buildInfo.ts +3 -0
  11. package/src/config/launchArgs.ts +196 -0
  12. package/src/config/layeredConfig.ts +853 -0
  13. package/src/config/legacyEnv.ts +16 -0
  14. package/src/config/persistence.ts +377 -0
  15. package/src/config/runtimeConfig.ts +558 -0
  16. package/src/config/settings.ts +405 -0
  17. package/src/config/toml-serialize.ts +109 -0
  18. package/src/config/trustStore.ts +84 -0
  19. package/src/config/updateCheckCache.ts +85 -0
  20. package/src/core/README.md +55 -0
  21. package/src/core/agent/loop.ts +464 -0
  22. package/src/core/agent/protocol.ts +345 -0
  23. package/src/core/agent/tools.ts +423 -0
  24. package/src/core/auth/codexAuth.ts +359 -0
  25. package/src/core/codex/codexExecArgs.ts +166 -0
  26. package/src/core/codex/codexLaunch.ts +163 -0
  27. package/src/core/codex/codexPrompt.ts +429 -0
  28. package/src/core/debug/inputDebug.ts +51 -0
  29. package/src/core/debug/localStreamDebug.ts +50 -0
  30. package/src/core/debug/modelStateDebug.ts +35 -0
  31. package/src/core/executables/antigravityExecutable.ts +48 -0
  32. package/src/core/executables/claudeExecutable.ts +63 -0
  33. package/src/core/executables/codexExecutable.ts +160 -0
  34. package/src/core/executables/executableResolver.ts +164 -0
  35. package/src/core/executables/geminiExecutable.ts +78 -0
  36. package/src/core/models/codexCapabilities.ts +97 -0
  37. package/src/core/models/codexModelCapabilities.ts +624 -0
  38. package/src/core/models/codexModelsCacheSeed.ts +153 -0
  39. package/src/core/models/modelSpecs.ts +303 -0
  40. package/src/core/models/providerModelCache.ts +94 -0
  41. package/src/core/perf/profiler.ts +125 -0
  42. package/src/core/perf/renderDebug.ts +398 -0
  43. package/src/core/process/CommandRunner.ts +280 -0
  44. package/src/core/process/processValidation.ts +111 -0
  45. package/src/core/providerLauncher/launcher.ts +220 -0
  46. package/src/core/providerLauncher/registry.ts +354 -0
  47. package/src/core/providerLauncher/types.ts +95 -0
  48. package/src/core/providerLauncher/workspaceConfig.ts +487 -0
  49. package/src/core/providerRuntime/anthropic.ts +580 -0
  50. package/src/core/providerRuntime/antigravity.ts +500 -0
  51. package/src/core/providerRuntime/capabilityProfile.ts +383 -0
  52. package/src/core/providerRuntime/claudeCodeDiscovery.ts +724 -0
  53. package/src/core/providerRuntime/claudeCodeDiscoveryDebug.ts +55 -0
  54. package/src/core/providerRuntime/codexaCupy.ts +97 -0
  55. package/src/core/providerRuntime/codexaNative.ts +425 -0
  56. package/src/core/providerRuntime/contextMetadata.ts +397 -0
  57. package/src/core/providerRuntime/gemini.ts +789 -0
  58. package/src/core/providerRuntime/lmstudio.ts +118 -0
  59. package/src/core/providerRuntime/local.ts +770 -0
  60. package/src/core/providerRuntime/localHarness/runtime.ts +1090 -0
  61. package/src/core/providerRuntime/localOutputBudget.ts +17 -0
  62. package/src/core/providerRuntime/mistralVibe.ts +667 -0
  63. package/src/core/providerRuntime/models.ts +175 -0
  64. package/src/core/providerRuntime/reasoning.ts +20 -0
  65. package/src/core/providerRuntime/registry.ts +286 -0
  66. package/src/core/providerRuntime/types.ts +142 -0
  67. package/src/core/providerRuntime/unsloth.ts +216 -0
  68. package/src/core/providers/codexJsonStream.ts +305 -0
  69. package/src/core/providers/codexSubprocess.ts +378 -0
  70. package/src/core/providers/codexTranscript.ts +695 -0
  71. package/src/core/providers/openaiNative.ts +13 -0
  72. package/src/core/providers/registry.ts +21 -0
  73. package/src/core/providers/types.ts +91 -0
  74. package/src/core/shared/attachments.ts +101 -0
  75. package/src/core/shared/cleanupFastFail.ts +67 -0
  76. package/src/core/shared/clipboard.ts +24 -0
  77. package/src/core/shared/clipboardImage.ts +111 -0
  78. package/src/core/shared/githubDiagnostics.ts +222 -0
  79. package/src/core/shared/hollowResponseFormat.ts +39 -0
  80. package/src/core/terminal/clearFrameBoundary.ts +852 -0
  81. package/src/core/terminal/frameLock.ts +110 -0
  82. package/src/core/terminal/inkRenderReset.ts +123 -0
  83. package/src/core/terminal/startupClear.ts +20 -0
  84. package/src/core/terminal/terminalCapabilities.ts +100 -0
  85. package/src/core/terminal/terminalControl.ts +169 -0
  86. package/src/core/terminal/terminalSanitize.ts +147 -0
  87. package/src/core/terminal/terminalTitle.ts +400 -0
  88. package/src/core/version/channel.ts +27 -0
  89. package/src/core/version/packageManager.ts +119 -0
  90. package/src/core/version/updateCheck.ts +203 -0
  91. package/src/core/workspace/appData.ts +107 -0
  92. package/src/core/workspace/conversationStore.ts +335 -0
  93. package/src/core/workspace/launchContext.ts +259 -0
  94. package/src/core/workspace/planStorage.ts +135 -0
  95. package/src/core/workspace/projectInstructions.ts +54 -0
  96. package/src/core/workspace/scratchDir.ts +64 -0
  97. package/src/core/workspace/workspaceActivity.ts +384 -0
  98. package/src/core/workspace/workspaceGuard.ts +377 -0
  99. package/src/core/workspace/workspaceRoot.ts +47 -0
  100. package/src/exec.ts +73 -0
  101. package/src/headless/execArgs.ts +296 -0
  102. package/src/headless/execRunner.ts +304 -0
  103. package/src/index.tsx +270 -0
  104. package/src/legacyEnvBootstrap.ts +5 -0
  105. package/src/session/appSession.ts +771 -0
  106. package/src/session/chatLifecycle.ts +994 -0
  107. package/src/session/conversation.ts +107 -0
  108. package/src/session/liveRenderScheduler.ts +214 -0
  109. package/src/session/persistedResponse.ts +93 -0
  110. package/src/session/planFlow.ts +159 -0
  111. package/src/session/planTranscript.ts +19 -0
  112. package/src/session/promptRunSchedule.ts +26 -0
  113. package/src/session/types.ts +234 -0
  114. package/src/test/runtimeTestUtils.ts +14 -0
  115. package/src/types/react-dom.d.ts +3 -0
  116. package/src/ui/chrome/ActivityBars.tsx +68 -0
  117. package/src/ui/chrome/ActivityIndicator.tsx +58 -0
  118. package/src/ui/chrome/AnimatedStatusText.tsx +69 -0
  119. package/src/ui/chrome/AppShell.tsx +474 -0
  120. package/src/ui/chrome/BottomComposer.tsx +1135 -0
  121. package/src/ui/chrome/DashCard.tsx +82 -0
  122. package/src/ui/chrome/RunFooter.tsx +65 -0
  123. package/src/ui/chrome/RuntimeStatusBar.tsx +108 -0
  124. package/src/ui/chrome/Spinner.tsx +25 -0
  125. package/src/ui/chrome/TopHeader.tsx +439 -0
  126. package/src/ui/chrome/UpdateAvailableCard.tsx +42 -0
  127. package/src/ui/chrome/busyStatusAnimation.ts +11 -0
  128. package/src/ui/input/commandNormalize.ts +66 -0
  129. package/src/ui/input/focus.ts +73 -0
  130. package/src/ui/input/imageAttachments.ts +18 -0
  131. package/src/ui/input/inputBuffer.ts +203 -0
  132. package/src/ui/input/pastedContent.ts +75 -0
  133. package/src/ui/input/rawArrowKeys.ts +28 -0
  134. package/src/ui/input/slashCommands.ts +43 -0
  135. package/src/ui/input/useStdinRawModeLease.ts +23 -0
  136. package/src/ui/layout.ts +560 -0
  137. package/src/ui/panels/AttachmentImportPanel.tsx +131 -0
  138. package/src/ui/panels/AuthPanel.tsx +149 -0
  139. package/src/ui/panels/BackendPicker.tsx +28 -0
  140. package/src/ui/panels/ModePicker.tsx +31 -0
  141. package/src/ui/panels/ModelPicker.tsx +31 -0
  142. package/src/ui/panels/ModelPickerScreen.tsx +761 -0
  143. package/src/ui/panels/ModelReasoningPicker.tsx +458 -0
  144. package/src/ui/panels/Panel.tsx +51 -0
  145. package/src/ui/panels/PermissionsPanel.tsx +78 -0
  146. package/src/ui/panels/PlanActionPicker.tsx +187 -0
  147. package/src/ui/panels/ProviderPicker.tsx +753 -0
  148. package/src/ui/panels/ProviderSetupPrompt.tsx +52 -0
  149. package/src/ui/panels/ReasoningPicker.tsx +46 -0
  150. package/src/ui/panels/ResumePicker.tsx +90 -0
  151. package/src/ui/panels/SelectionPanel.tsx +138 -0
  152. package/src/ui/panels/SettingsPanel.tsx +156 -0
  153. package/src/ui/panels/TextEntryPanel.tsx +139 -0
  154. package/src/ui/panels/ThemePicker.tsx +32 -0
  155. package/src/ui/panels/ToolApprovalPanel.tsx +46 -0
  156. package/src/ui/panels/UpdatePromptPanel.tsx +236 -0
  157. package/src/ui/panels/responsivePickerViewport.ts +64 -0
  158. package/src/ui/render/Markdown.tsx +331 -0
  159. package/src/ui/render/diffRenderer.ts +116 -0
  160. package/src/ui/render/logoVariants.ts +113 -0
  161. package/src/ui/render/modeDisplay.ts +52 -0
  162. package/src/ui/render/outputPipeline.ts +64 -0
  163. package/src/ui/render/runtimeDisplay.ts +128 -0
  164. package/src/ui/render/terminalAnswerFormat.ts +128 -0
  165. package/src/ui/render/textLayout.ts +392 -0
  166. package/src/ui/theme.tsx +274 -0
  167. package/src/ui/themeFlow.ts +41 -0
  168. package/src/ui/timeline/ActionRequiredBlock.tsx +38 -0
  169. package/src/ui/timeline/AgentBlock.tsx +130 -0
  170. package/src/ui/timeline/StaticIntroItem.tsx +54 -0
  171. package/src/ui/timeline/ThinkingBlock.tsx +100 -0
  172. package/src/ui/timeline/Timeline.tsx +1410 -0
  173. package/src/ui/timeline/TranscriptShell.tsx +302 -0
  174. package/src/ui/timeline/TurnGroup.tsx +673 -0
  175. package/src/ui/timeline/layoutListWindow.ts +145 -0
  176. package/src/ui/timeline/liveViewportWindow.ts +68 -0
  177. package/src/ui/timeline/progressEntries.ts +156 -0
  178. package/src/ui/timeline/runActivityView.ts +37 -0
  179. package/src/ui/timeline/staticTranscriptCache.ts +174 -0
  180. package/src/ui/timeline/streamCoalesce.ts +53 -0
  181. package/src/ui/timeline/timelineMeasure.ts +3273 -0
  182. package/src/ui/useThrottledValue.ts +31 -0
@@ -0,0 +1,187 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from "react";
2
+ import { Box, Text, useFocus, useFocusManager, useInput, useStdin } from "ink";
3
+ import { FOCUS_IDS } from "../input/focus.js";
4
+ import { getArrowDirection, type ArrowDirection } from "../input/rawArrowKeys.js";
5
+ import { useTheme } from "../theme.js";
6
+
7
+ export type PlanActionValue = "implement" | "revise" | "cancel";
8
+
9
+ const ACTION_ROWS: Array<{ key: string; label: string; value: PlanActionValue }> = [
10
+ { key: "I", label: "Implement changes", value: "implement" },
11
+ { key: "U", label: "Update plan", value: "revise" },
12
+ ];
13
+ const VERTICAL_LAYOUT_BREAKPOINT = 56;
14
+ /**
15
+ * Ink flushes a lone ESC as a bare escape 20ms after it arrives. An arrow key
16
+ * split across two stdin reads therefore looks like "cancel review" followed by
17
+ * stray text, so hold a cancel briefly to see whether the sequence completes.
18
+ */
19
+ const ESCAPE_SETTLE_MS = 60;
20
+ const RAW_BUFFER_IDLE_MS = 120;
21
+
22
+ interface PlanActionPickerProps {
23
+ cols?: number;
24
+ onSelect: (value: PlanActionValue) => void;
25
+ onCancel: () => void;
26
+ }
27
+
28
+ export function measurePlanActionPickerRows(cols = 80): number {
29
+ return cols < VERTICAL_LAYOUT_BREAKPOINT ? 3 : 1;
30
+ }
31
+
32
+ export function PlanActionPicker({
33
+ cols = 80,
34
+ onSelect,
35
+ onCancel,
36
+ }: PlanActionPickerProps) {
37
+ const theme = useTheme();
38
+ const { isFocused } = useFocus({ id: FOCUS_IDS.composer, autoFocus: true });
39
+ const { focus } = useFocusManager();
40
+ const [selectedIndex, setSelectedIndex] = useState(0);
41
+ const { stdin } = useStdin();
42
+ const mouseEventTickRef = useRef(false);
43
+ const mouseEventTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
44
+ const rawBufferRef = useRef("");
45
+ const rawBufferTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
46
+ const pendingEscapeRef = useRef(false);
47
+ const escapeTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
48
+ const onCancelRef = useRef(onCancel);
49
+ onCancelRef.current = onCancel;
50
+ const vertical = cols < VERTICAL_LAYOUT_BREAKPOINT;
51
+
52
+ const moveSelection = useCallback((direction: ArrowDirection) => {
53
+ const step = direction === "left" || direction === "up" ? ACTION_ROWS.length - 1 : 1;
54
+ setSelectedIndex((current) => (current + step) % ACTION_ROWS.length);
55
+ }, []);
56
+
57
+ const clearPendingEscape = useCallback(() => {
58
+ pendingEscapeRef.current = false;
59
+ if (escapeTimeoutRef.current) {
60
+ clearTimeout(escapeTimeoutRef.current);
61
+ escapeTimeoutRef.current = null;
62
+ }
63
+ }, []);
64
+
65
+ // Ink blurs every focusable when it flushes a bare ESC. This picker is only
66
+ // mounted while the plan prompt is up, so any blur here is spurious — without
67
+ // this the prompt silently stops responding to keys.
68
+ useEffect(() => {
69
+ if (!isFocused) focus(FOCUS_IDS.composer);
70
+ }, [focus, isFocused]);
71
+
72
+ useEffect(() => {
73
+ const handleRawInput = (chunk: Buffer | string) => {
74
+ const raw = typeof chunk === "string" ? chunk : chunk.toString();
75
+ if (/\u001b\[<\d+;\d+;\d+[Mm]/.test(raw) || /\u001b\[M/.test(raw)) {
76
+ rawBufferRef.current = "";
77
+ mouseEventTickRef.current = true;
78
+ if (mouseEventTimeoutRef.current) clearTimeout(mouseEventTimeoutRef.current);
79
+ mouseEventTimeoutRef.current = setTimeout(() => {
80
+ mouseEventTickRef.current = false;
81
+ }, 32);
82
+ return;
83
+ }
84
+
85
+ rawBufferRef.current = `${rawBufferRef.current}${raw}`.slice(-16);
86
+ if (rawBufferTimeoutRef.current) clearTimeout(rawBufferTimeoutRef.current);
87
+ rawBufferTimeoutRef.current = setTimeout(() => {
88
+ rawBufferRef.current = "";
89
+ }, RAW_BUFFER_IDLE_MS);
90
+
91
+ const direction = getArrowDirection(rawBufferRef.current);
92
+ if (!direction) return;
93
+ rawBufferRef.current = "";
94
+ // Ink already delivered the leading ESC as a cancel-in-waiting, so it will
95
+ // never surface this chunk as an arrow key — apply the movement here.
96
+ if (pendingEscapeRef.current) {
97
+ clearPendingEscape();
98
+ moveSelection(direction);
99
+ }
100
+ };
101
+ stdin.on("data", handleRawInput);
102
+ return () => {
103
+ stdin.off("data", handleRawInput);
104
+ if (mouseEventTimeoutRef.current) clearTimeout(mouseEventTimeoutRef.current);
105
+ if (rawBufferTimeoutRef.current) clearTimeout(rawBufferTimeoutRef.current);
106
+ if (escapeTimeoutRef.current) clearTimeout(escapeTimeoutRef.current);
107
+ };
108
+ }, [clearPendingEscape, moveSelection, stdin]);
109
+
110
+ useInput((input, key) => {
111
+ if (mouseEventTickRef.current) return;
112
+
113
+ if (key.escape) {
114
+ pendingEscapeRef.current = true;
115
+ if (escapeTimeoutRef.current) clearTimeout(escapeTimeoutRef.current);
116
+ escapeTimeoutRef.current = setTimeout(() => {
117
+ escapeTimeoutRef.current = null;
118
+ if (!pendingEscapeRef.current) return;
119
+ pendingEscapeRef.current = false;
120
+ onCancelRef.current();
121
+ }, ESCAPE_SETTLE_MS);
122
+ return;
123
+ }
124
+
125
+ // Tail of an escape sequence Ink could not reassemble; the raw listener owns it.
126
+ if (input.startsWith("[") || input.startsWith("O")) return;
127
+
128
+ clearPendingEscape();
129
+
130
+ if (key.return) {
131
+ onSelect(ACTION_ROWS[selectedIndex]?.value ?? "implement");
132
+ return;
133
+ }
134
+
135
+ if (key.upArrow || key.leftArrow || (key.shift && key.tab)) {
136
+ moveSelection("left");
137
+ return;
138
+ }
139
+
140
+ if (key.downArrow || key.rightArrow || key.tab) {
141
+ moveSelection("right");
142
+ return;
143
+ }
144
+
145
+ if (input.length === 1 && !key.meta) {
146
+ const lower = input.toLowerCase();
147
+ if (lower === "i") { onSelect("implement"); return; }
148
+ if (lower === "u") { onSelect("revise"); return; }
149
+ }
150
+ }, { isActive: isFocused });
151
+
152
+ const renderAction = (row: (typeof ACTION_ROWS)[number], index: number) => {
153
+ const selected = index === selectedIndex;
154
+ return (
155
+ <Text key={row.value}>
156
+ <Text color={selected ? theme.accent : theme.textDim}>
157
+ {selected ? "› " : vertical ? " " : ""}
158
+ </Text>
159
+ <Text color={selected ? theme.text : theme.textMuted}>
160
+ {`[${row.key}] ${row.label}`}
161
+ </Text>
162
+ </Text>
163
+ );
164
+ };
165
+
166
+ if (vertical) {
167
+ return (
168
+ <Box flexDirection="column">
169
+ <Text color={isFocused ? theme.text : theme.textMuted} bold={isFocused}>Plan ready</Text>
170
+ {ACTION_ROWS.map(renderAction)}
171
+ </Box>
172
+ );
173
+ }
174
+
175
+ return (
176
+ <Text>
177
+ <Text color={isFocused ? theme.text : theme.textMuted} bold={isFocused}>Plan ready</Text>
178
+ <Text color={theme.textDim}>{" "}</Text>
179
+ {ACTION_ROWS.map((row, index) => (
180
+ <React.Fragment key={row.value}>
181
+ {renderAction(row, index)}
182
+ {index < ACTION_ROWS.length - 1 && <Text color={theme.textDim}>{" "}</Text>}
183
+ </React.Fragment>
184
+ ))}
185
+ </Text>
186
+ );
187
+ }