u-foo 2.3.32 → 2.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 (235) hide show
  1. package/README.md +157 -213
  2. package/README.zh-CN.md +151 -197
  3. package/SKILLS/ufoo/SKILL.md +8 -8
  4. package/bin/uagy.js +69 -0
  5. package/bin/uclaude.js +2 -2
  6. package/bin/ucode.js +4 -4
  7. package/bin/ucodex.js +2 -2
  8. package/bin/ufoo.js +5 -23
  9. package/modules/AGENTS.template.md +1 -1
  10. package/modules/bus/SKILLS/ubus/SKILL.md +35 -10
  11. package/package.json +5 -5
  12. package/scripts/chat-app-smoke.js +1 -1
  13. package/scripts/global-chat-switch-benchmark.js +5 -5
  14. package/scripts/ink-demo.js +1 -1
  15. package/scripts/ink-smoke.js +1 -1
  16. package/scripts/ucode-app-smoke.js +1 -1
  17. package/src/{agent → agents/activity}/activityDetector.js +39 -2
  18. package/src/{agent → agents/activity}/activityStatePublisher.js +1 -1
  19. package/src/{agent → agents/activity}/activityStateWriter.js +2 -2
  20. package/src/{agent → agents/activity}/activityTracker.js +1 -1
  21. package/src/agents/activity/index.js +8 -0
  22. package/src/{agent → agents/controller}/controllerToolExecutor.js +4 -4
  23. package/src/agents/controller/index.js +8 -0
  24. package/src/{agent → agents/controller}/loopObservability.js +2 -2
  25. package/src/{agent → agents/controller}/loopRuntime.js +1 -1
  26. package/src/{agent → agents/controller}/ufooAgent.js +9 -9
  27. package/src/agents/index.js +10 -0
  28. package/src/agents/internal/index.js +3 -0
  29. package/src/{agent → agents/internal}/internalRunner.js +45 -22
  30. package/src/agents/launch/agyConversation.js +159 -0
  31. package/src/agents/launch/index.js +12 -0
  32. package/src/{agent → agents/launch}/launchEnvironment.js +2 -3
  33. package/src/{agent → agents/launch}/launcher.js +64 -21
  34. package/src/{agent → agents/launch}/notifier.js +23 -12
  35. package/src/{agent → agents/launch}/ptyRunner.js +44 -12
  36. package/src/{agent → agents/launch}/ptyWrapper.js +2 -2
  37. package/src/{agent → agents/launch}/publisherRouting.js +1 -1
  38. package/src/{agent → agents/launch}/readyDetector.js +23 -0
  39. package/src/{agent → agents/prompts}/defaultBootstrap.js +63 -4
  40. package/src/{group/bootstrap.js → agents/prompts/groupBootstrap.js} +41 -6
  41. package/src/agents/prompts/index.js +8 -0
  42. package/src/{code/prompts → agents/prompts/native}/index.js +1 -1
  43. package/src/{agent → agents/providers}/claudeThreadProvider.js +1 -1
  44. package/src/{agent → agents/providers}/codexThreadProvider.js +1 -1
  45. package/src/{agent → agents/providers}/directAuthStatus.js +184 -1
  46. package/src/agents/providers/index.js +13 -0
  47. package/src/{agent → agents/providers}/upstreamTransport.js +2 -2
  48. package/src/{chat → app/chat}/agentSockets.js +1 -1
  49. package/src/{chat → app/chat}/commandExecutor.js +50 -26
  50. package/src/{chat → app/chat}/commands.js +119 -5
  51. package/src/{chat → app/chat}/daemonConnection.js +1 -1
  52. package/src/{chat → app/chat}/daemonMessageRouter.js +45 -3
  53. package/src/{chat → app/chat}/dashboardView.js +2 -1
  54. package/src/app/chat/index.js +6 -0
  55. package/src/{chat → app/chat}/inputSubmitHandler.js +4 -13
  56. package/src/{chat → app/chat}/internalAgentLogHistory.js +1 -1
  57. package/src/app/chat/multiWindow/index.js +268 -0
  58. package/src/app/chat/multiWindow/paneLayout.js +84 -0
  59. package/src/app/chat/multiWindow/paneManager.js +299 -0
  60. package/src/app/chat/multiWindow/renderer.js +384 -0
  61. package/src/app/chat/multiWindow/virtualTerminal.js +327 -0
  62. package/src/{chat → app/chat}/transport.js +1 -1
  63. package/src/{cli → app/cli}/ctxCoreCommands.js +3 -3
  64. package/src/{doctor/index.js → app/cli/features/doctor.js} +1 -1
  65. package/src/{init/index.js → app/cli/features/init.js} +14 -32
  66. package/src/{cli → app/cli}/groupCoreCommands.js +2 -2
  67. package/src/app/cli/index.js +9 -0
  68. package/src/{cli → app/cli}/onlineCoreCommands.js +5 -5
  69. package/src/{cli.js → app/cli/run.js} +59 -57
  70. package/src/app/index.js +6 -0
  71. package/src/code/agent.js +10 -9
  72. package/src/code/index.js +2 -0
  73. package/src/code/launcher/index.js +9 -0
  74. package/src/{agent → code/launcher}/ucode.js +7 -8
  75. package/src/{agent → code/launcher}/ucodeBootstrap.js +3 -3
  76. package/src/{agent → code/launcher}/ucodeBuild.js +2 -2
  77. package/src/{agent → code/launcher}/ucodeDoctor.js +2 -2
  78. package/src/{agent → code/launcher}/ucodeRuntimeConfig.js +1 -2
  79. package/src/code/nativeRunner.js +4 -4
  80. package/src/code/tui.js +3 -1454
  81. package/src/config.js +15 -2
  82. package/src/{bus → coordination/bus}/activate.js +2 -2
  83. package/src/{bus → coordination/bus}/daemon.js +15 -5
  84. package/src/coordination/bus/envelope.js +173 -0
  85. package/src/{bus → coordination/bus}/index.js +7 -3
  86. package/src/{bus → coordination/bus}/inject.js +11 -3
  87. package/src/{bus → coordination/bus}/message.js +1 -1
  88. package/src/coordination/bus/messageMeta.js +130 -0
  89. package/src/coordination/bus/promptEnvelope.js +65 -0
  90. package/src/{bus → coordination/bus}/shake.js +1 -1
  91. package/src/{bus → coordination/bus}/store.js +3 -3
  92. package/src/{bus → coordination/bus}/subscriber.js +2 -2
  93. package/src/{bus → coordination/bus}/utils.js +2 -2
  94. package/src/{history → coordination/history}/inputTimeline.js +5 -5
  95. package/src/coordination/index.js +10 -0
  96. package/src/{memory → coordination/memory}/historySearch.js +1 -1
  97. package/src/{memory → coordination/memory}/index.js +3 -3
  98. package/src/{report → coordination/report}/store.js +2 -2
  99. package/src/{status → coordination/status}/index.js +3 -3
  100. package/src/online/bridge.js +2 -2
  101. package/src/{controller → orchestration/controller}/flags.js +1 -1
  102. package/src/{controller → orchestration/controller}/gateRouter.js +1 -1
  103. package/src/orchestration/controller/index.js +10 -0
  104. package/src/{controller → orchestration/controller}/shadowGuard.js +1 -1
  105. package/src/orchestration/groups/bootstrap.js +3 -0
  106. package/src/orchestration/groups/index.js +10 -0
  107. package/src/orchestration/groups/promptProfiles.js +3 -0
  108. package/src/{group → orchestration/groups}/templates.js +1 -1
  109. package/src/{group → orchestration/groups}/validateTemplate.js +1 -1
  110. package/src/orchestration/index.js +7 -0
  111. package/src/orchestration/solo/index.js +3 -0
  112. package/src/{daemon → runtime/daemon}/agentProcessManager.js +1 -1
  113. package/src/{daemon → runtime/daemon}/cronOps.js +3 -2
  114. package/src/{daemon → runtime/daemon}/groupOrchestrator.js +26 -9
  115. package/src/{daemon → runtime/daemon}/index.js +105 -53
  116. package/src/{daemon → runtime/daemon}/ipcServer.js +1 -1
  117. package/src/{daemon → runtime/daemon}/nicknameScope.js +6 -3
  118. package/src/{daemon → runtime/daemon}/ops.js +48 -61
  119. package/src/{daemon → runtime/daemon}/promptLoop.js +1 -1
  120. package/src/{daemon → runtime/daemon}/promptRequest.js +7 -7
  121. package/src/runtime/daemon/providerSessions.js +230 -0
  122. package/src/{daemon → runtime/daemon}/reporting.js +4 -4
  123. package/src/{daemon → runtime/daemon}/run.js +4 -4
  124. package/src/{daemon → runtime/daemon}/soloBootstrap.js +7 -7
  125. package/src/{daemon → runtime/daemon}/status.js +5 -5
  126. package/src/runtime/index.js +10 -0
  127. package/src/{projects → runtime/projects}/registry.js +1 -1
  128. package/src/{terminal → runtime/terminal}/adapterRouter.js +0 -10
  129. package/src/{terminal → runtime/terminal}/adapters/internalAdapter.js +0 -4
  130. package/src/tools/handlers/common.js +1 -1
  131. package/src/tools/handlers/listAgents.js +1 -1
  132. package/src/tools/handlers/memory.js +3 -3
  133. package/src/tools/handlers/readBusSummary.js +1 -1
  134. package/src/tools/handlers/readOpenDecisions.js +1 -1
  135. package/src/tools/handlers/readProjectRegistry.js +1 -1
  136. package/src/tools/handlers/readPromptHistory.js +2 -2
  137. package/src/tools/schemaFixtures.js +1 -1
  138. package/src/ui/MIGRATION.md +42 -88
  139. package/src/ui/format/index.js +5 -28
  140. package/src/ui/index.js +1 -1
  141. package/src/ui/{components → ink}/ChatApp.js +812 -88
  142. package/src/ui/ink/DashboardBar.js +685 -0
  143. package/src/ui/{components → ink}/MultilineInput.js +230 -5
  144. package/src/ui/{components → ink}/UcodeApp.js +16 -7
  145. package/src/ui/{components → ink}/agentMirror.js +24 -19
  146. package/src/ui/{components → ink}/chatReducer.js +29 -7
  147. package/src/bus/messageMeta.js +0 -52
  148. package/src/chat/agentViewController.js +0 -1072
  149. package/src/chat/chatLogController.js +0 -138
  150. package/src/chat/completionController.js +0 -533
  151. package/src/chat/dashboardKeyController.js +0 -533
  152. package/src/chat/index.js +0 -2222
  153. package/src/chat/inputHistoryController.js +0 -135
  154. package/src/chat/inputListenerController.js +0 -470
  155. package/src/chat/layout.js +0 -186
  156. package/src/chat/pasteController.js +0 -81
  157. package/src/chat/statusLineController.js +0 -223
  158. package/src/chat/streamTracker.js +0 -156
  159. package/src/code/config +0 -0
  160. package/src/daemon/providerSessions.js +0 -488
  161. package/src/terminal/adapters/internalPtyAdapter.js +0 -42
  162. package/src/ui/components/DashboardBar.js +0 -417
  163. /package/src/{code/prompts → agents/prompts/native}/actions.js +0 -0
  164. /package/src/{code/prompts → agents/prompts/native}/efficiency.js +0 -0
  165. /package/src/{code/prompts → agents/prompts/native}/environment.js +0 -0
  166. /package/src/{code/prompts → agents/prompts/native}/identity.js +0 -0
  167. /package/src/{code/prompts → agents/prompts/native}/safety.js +0 -0
  168. /package/src/{code/prompts → agents/prompts/native}/sections.js +0 -0
  169. /package/src/{code/prompts → agents/prompts/native}/system.js +0 -0
  170. /package/src/{code/prompts → agents/prompts/native}/tasks.js +0 -0
  171. /package/src/{code/prompts → agents/prompts/native}/toolDescriptions/bash.js +0 -0
  172. /package/src/{code/prompts → agents/prompts/native}/toolDescriptions/edit.js +0 -0
  173. /package/src/{code/prompts → agents/prompts/native}/toolDescriptions/read.js +0 -0
  174. /package/src/{code/prompts → agents/prompts/native}/toolDescriptions/write.js +0 -0
  175. /package/src/{code/prompts → agents/prompts/native}/ufoo.js +0 -0
  176. /package/src/{group → agents/prompts}/promptProfiles.js +0 -0
  177. /package/src/{agent → agents/providers}/claudeEventTranslator.js +0 -0
  178. /package/src/{agent → agents/providers}/claudeOauthTokenReader.js +0 -0
  179. /package/src/{agent → agents/providers}/claudeSessionFiles.js +0 -0
  180. /package/src/{agent → agents/providers}/codexEventTranslator.js +0 -0
  181. /package/src/{agent → agents/providers}/credentials/claude.js +0 -0
  182. /package/src/{agent → agents/providers}/credentials/codex.js +0 -0
  183. /package/src/{agent → agents/providers}/credentials/index.js +0 -0
  184. /package/src/{chat → app/chat}/agentBar.js +0 -0
  185. /package/src/{chat → app/chat}/agentDirectory.js +0 -0
  186. /package/src/{chat → app/chat}/cronScheduler.js +0 -0
  187. /package/src/{chat → app/chat}/daemonCoordinator.js +0 -0
  188. /package/src/{chat → app/chat}/daemonReconnect.js +0 -0
  189. /package/src/{chat → app/chat}/daemonTransport.js +0 -0
  190. /package/src/{chat → app/chat}/daemonTransportDefaults.js +0 -0
  191. /package/src/{chat → app/chat}/inputMath.js +0 -0
  192. /package/src/{chat → app/chat}/projectCloseController.js +0 -0
  193. /package/src/{chat → app/chat}/rawKeyMap.js +0 -0
  194. /package/src/{chat → app/chat}/settingsController.js +0 -0
  195. /package/src/{chat → app/chat}/shellCommand.js +0 -0
  196. /package/src/{chat → app/chat}/text.js +0 -0
  197. /package/src/{chat → app/chat}/transientAgentState.js +0 -0
  198. /package/src/{cli → app/cli}/busCoreCommands.js +0 -0
  199. /package/src/{skills/index.js → app/cli/features/skills.js} +0 -0
  200. /package/src/{bus → coordination/bus}/nickname.js +0 -0
  201. /package/src/{bus → coordination/bus}/queue.js +0 -0
  202. /package/src/{context → coordination/context}/decisions.js +0 -0
  203. /package/src/{context → coordination/context}/doctor.js +0 -0
  204. /package/src/{context → coordination/context}/index.js +0 -0
  205. /package/src/{context → coordination/context}/sync.js +0 -0
  206. /package/src/{ufoo → coordination/state}/agentRegistryDiagnostics.js +0 -0
  207. /package/src/{ufoo → coordination/state}/agentsStore.js +0 -0
  208. /package/src/{ufoo → coordination/state}/paths.js +0 -0
  209. /package/src/{controller → orchestration/controller}/launchRouting.js +0 -0
  210. /package/src/{controller → orchestration/controller}/routerFastPath.js +0 -0
  211. /package/src/{controller → orchestration/controller}/routerFinalize.js +0 -0
  212. /package/src/{group → orchestration/groups}/diagram.js +0 -0
  213. /package/src/{group → orchestration/groups}/templateValidation.js +0 -0
  214. /package/src/{solo → orchestration/solo}/commands.js +0 -0
  215. /package/src/{shared → runtime/contracts}/eventContract.js +0 -0
  216. /package/src/{shared → runtime/contracts}/ptySocketContract.js +0 -0
  217. /package/src/{providerapi → runtime/privacy}/redactor.js +0 -0
  218. /package/src/{providerapi → runtime/privacy}/shadowDiff.js +0 -0
  219. /package/src/{utils → runtime/process}/nodeExecutable.js +0 -0
  220. /package/src/{projects → runtime/projects}/identity.js +0 -0
  221. /package/src/{projects → runtime/projects}/index.js +0 -0
  222. /package/src/{projects → runtime/projects}/projectId.js +0 -0
  223. /package/src/{projects → runtime/projects}/runtimes.js +0 -0
  224. /package/src/{terminal → runtime/terminal}/adapterContract.js +0 -0
  225. /package/src/{terminal → runtime/terminal}/adapters/externalAdapter.js +0 -0
  226. /package/src/{terminal → runtime/terminal}/adapters/hostAdapter.js +0 -0
  227. /package/src/{terminal → runtime/terminal}/adapters/internalQueueAdapter.js +0 -0
  228. /package/src/{terminal → runtime/terminal}/adapters/terminalAdapter.js +0 -0
  229. /package/src/{terminal → runtime/terminal}/adapters/tmuxAdapter.js +0 -0
  230. /package/src/{terminal → runtime/terminal}/detect.js +0 -0
  231. /package/src/{terminal → runtime/terminal}/index.js +0 -0
  232. /package/src/{terminal → runtime/terminal}/iterm2.js +0 -0
  233. /package/src/{utils → ui/format}/banner.js +0 -0
  234. /package/src/{shared → ui/format}/markdownRenderer.js +0 -0
  235. /package/src/ui/{components → ink}/InkDemo.js +0 -0
@@ -1,186 +0,0 @@
1
- function createChatLayout(options = {}) {
2
- const {
3
- blessed,
4
- currentInputHeight = 4,
5
- dashboardHeight = 1,
6
- version = "unknown",
7
- logBorder = false,
8
- logScrollbar = false,
9
- } = options;
10
- const normalizedDashboardHeight = Number.isFinite(dashboardHeight) && dashboardHeight > 0
11
- ? Math.floor(dashboardHeight)
12
- : 1;
13
- const reservedBottomLines = Math.max(2, currentInputHeight + 1);
14
-
15
- const screen = blessed.screen({
16
- smartCSR: true,
17
- title: "ufoo chat",
18
- fullUnicode: true,
19
- // Toggle mouse at runtime to balance copy vs scroll
20
- sendFocus: true,
21
- mouse: false,
22
- // Allow Ctrl+C to exit even when input grabs keys
23
- ignoreLocked: ["C-c"],
24
- });
25
- // Prefer normal buffer for reliable terminal selection/copy
26
- if (screen.program && typeof screen.program.normalBuffer === "function") {
27
- screen.program.normalBuffer();
28
- if (screen.program.put && typeof screen.program.put.keypad_local === "function") {
29
- screen.program.put.keypad_local();
30
- }
31
- if (typeof screen.program.clear === "function") {
32
- screen.program.clear();
33
- screen.program.cup(0, 0);
34
- }
35
- }
36
-
37
- // Log area
38
- const logBox = blessed.log({
39
- parent: screen,
40
- top: 0,
41
- left: 0,
42
- width: "100%",
43
- height: `100%-${reservedBottomLines}`, // Will be adjusted dynamically
44
- border: logBorder ? { type: "line" } : null,
45
- tags: true,
46
- scrollable: true,
47
- alwaysScroll: true,
48
- scrollback: 10000,
49
- scrollbar: logScrollbar
50
- ? {
51
- ch: " ",
52
- track: { bg: "black" },
53
- style: { bg: "gray" },
54
- }
55
- : null,
56
- keys: true,
57
- vi: true,
58
- // Mouse handled globally (toggleable) to keep copy working
59
- mouse: false,
60
- // Ensure proper wrapping and width calculation
61
- wrap: true,
62
- padding: logBorder ? { left: 1, right: 1 } : undefined,
63
- style: logBorder
64
- ? {
65
- border: { fg: "gray" },
66
- scrollbar: { bg: "gray" },
67
- }
68
- : undefined,
69
- });
70
-
71
- // Status line just above input
72
- const statusLine = blessed.box({
73
- parent: screen,
74
- bottom: currentInputHeight,
75
- left: 0,
76
- width: "100%",
77
- height: 1,
78
- style: { fg: "gray" },
79
- tags: true,
80
- content: "",
81
- });
82
- const bannerText = `{bold}UFOO{/bold} · Chat Manager{|}v${version}`;
83
- statusLine.setContent(bannerText);
84
-
85
- // Command completion panel
86
- const completionPanel = blessed.box({
87
- parent: screen,
88
- bottom: currentInputHeight - 1,
89
- left: 0,
90
- width: "100%",
91
- height: 0,
92
- hidden: true,
93
- wrap: false,
94
- border: {
95
- type: "line",
96
- top: true,
97
- left: false,
98
- right: false,
99
- bottom: false,
100
- },
101
- style: {
102
- border: { fg: "yellow" },
103
- fg: "white",
104
- // No bg - uses terminal default background
105
- },
106
- padding: {
107
- left: 0,
108
- right: 0,
109
- top: 0,
110
- bottom: 0,
111
- },
112
- tags: true,
113
- });
114
-
115
- // Dashboard at very bottom
116
- const dashboard = blessed.box({
117
- parent: screen,
118
- bottom: 0,
119
- left: 0,
120
- width: "100%",
121
- height: normalizedDashboardHeight,
122
- style: { fg: "gray" },
123
- tags: true,
124
- });
125
-
126
- // Bottom border line for input area (above dashboard)
127
- const inputBottomLine = blessed.line({
128
- parent: screen,
129
- bottom: normalizedDashboardHeight,
130
- left: 1,
131
- width: "100%-2",
132
- orientation: "horizontal",
133
- style: { fg: "gray" },
134
- });
135
-
136
- // Prompt indicator
137
- const promptBox = blessed.box({
138
- parent: screen,
139
- bottom: normalizedDashboardHeight + 1,
140
- left: 0,
141
- width: 2,
142
- height: Math.max(1, currentInputHeight - normalizedDashboardHeight - 2),
143
- content: ">",
144
- style: { fg: "cyan" },
145
- });
146
-
147
- // Input area without left/right border
148
- const input = blessed.textarea({
149
- parent: screen,
150
- bottom: normalizedDashboardHeight + 1,
151
- left: 2,
152
- width: "100%-2",
153
- height: Math.max(1, currentInputHeight - normalizedDashboardHeight - 2),
154
- inputOnFocus: true,
155
- keys: true,
156
- });
157
- // Avoid textarea's extra wrap margin (causes a phantom empty column)
158
- input.type = "box";
159
-
160
- // Top border line for input area (just above input)
161
- const inputTopLine = blessed.line({
162
- parent: screen,
163
- bottom: currentInputHeight - 1, // 4-1=3: above input(2) + inputHeight(1)
164
- left: 1,
165
- width: "100%-2",
166
- orientation: "horizontal",
167
- style: { fg: "gray" },
168
- });
169
-
170
- return {
171
- screen,
172
- logBox,
173
- statusLine,
174
- bannerText,
175
- completionPanel,
176
- dashboard,
177
- inputBottomLine,
178
- promptBox,
179
- input,
180
- inputTopLine,
181
- };
182
- }
183
-
184
- module.exports = {
185
- createChatLayout,
186
- };
@@ -1,81 +0,0 @@
1
- function createPasteController(options = {}) {
2
- const {
3
- shouldHandle = () => true,
4
- normalizePaste = (text) => text,
5
- insertTextAtCursor = () => {},
6
- setImmediateFn = setImmediate,
7
- clearImmediateFn = clearImmediate,
8
- } = options;
9
-
10
- const PASTE_START = "\x1b[200~";
11
- const PASTE_END = "\x1b[201~";
12
- let pasteActive = false;
13
- let pasteBuffer = "";
14
- let pasteRemainder = "";
15
- let suppressKeypress = false;
16
- let suppressReset = null;
17
-
18
- function keepMarkerPrefixTail(text, marker) {
19
- const max = Math.min(marker.length - 1, text.length);
20
- for (let len = max; len > 0; len -= 1) {
21
- if (text.endsWith(marker.slice(0, len))) {
22
- return text.slice(-len);
23
- }
24
- }
25
- return "";
26
- }
27
-
28
- function scheduleSuppressReset() {
29
- suppressKeypress = true;
30
- if (suppressReset) clearImmediateFn(suppressReset);
31
- suppressReset = setImmediateFn(() => {
32
- if (!pasteActive) suppressKeypress = false;
33
- });
34
- }
35
-
36
- function handleProgramData(data) {
37
- if (!shouldHandle()) return;
38
- let buffer = pasteRemainder + data.toString("utf8");
39
- pasteRemainder = "";
40
- while (buffer.length > 0) {
41
- if (!pasteActive) {
42
- const start = buffer.indexOf(PASTE_START);
43
- if (start === -1) {
44
- pasteRemainder = keepMarkerPrefixTail(buffer, PASTE_START);
45
- return;
46
- }
47
- buffer = buffer.slice(start + PASTE_START.length);
48
- pasteActive = true;
49
- pasteBuffer = "";
50
- scheduleSuppressReset();
51
- continue;
52
- }
53
- const end = buffer.indexOf(PASTE_END);
54
- if (end === -1) {
55
- pasteBuffer += buffer;
56
- scheduleSuppressReset();
57
- return;
58
- }
59
- pasteBuffer += buffer.slice(0, end);
60
- buffer = buffer.slice(end + PASTE_END.length);
61
- pasteActive = false;
62
- scheduleSuppressReset();
63
- const normalized = normalizePaste(pasteBuffer);
64
- pasteBuffer = "";
65
- if (normalized) insertTextAtCursor(normalized);
66
- }
67
- }
68
-
69
- function isSuppressKeypress() {
70
- return suppressKeypress;
71
- }
72
-
73
- return {
74
- handleProgramData,
75
- isSuppressKeypress,
76
- };
77
- }
78
-
79
- module.exports = {
80
- createPasteController,
81
- };
@@ -1,223 +0,0 @@
1
- function createStatusLineController(options = {}) {
2
- const {
3
- statusLine,
4
- bannerText = "",
5
- renderScreen = () => {},
6
- setIntervalFn = setInterval,
7
- clearIntervalFn = clearInterval,
8
- now = () => Date.now(),
9
- } = options;
10
-
11
- if (!statusLine) {
12
- throw new Error("createStatusLineController requires statusLine");
13
- }
14
-
15
- const pendingStatusLines = [];
16
- const busStatusQueue = [];
17
- let primaryStatusText = bannerText;
18
- let primaryStatusPending = false;
19
-
20
- const shimmerStart = now();
21
- let animationTimer = null;
22
- const STATUS_ANIM_FRAME_MS = 50;
23
- const SHIMMER_PADDING = 10;
24
- const SHIMMER_BAND_HALF_WIDTH = 5;
25
- const SHIMMER_SWEEP_MS = 2000;
26
- const SPINNER_PERIOD_MS = 600;
27
-
28
- function formatProcessingText(text) {
29
- if (!text) return text;
30
- if (text.includes("{")) return text;
31
- if (!/processing/i.test(text)) return text;
32
- return text;
33
- }
34
-
35
- function shimmerText(text, nowMs) {
36
- if (!text) return "";
37
- if (text.includes("{")) return text;
38
- const chars = Array.from(text);
39
- const period = chars.length + SHIMMER_PADDING * 2;
40
- const pos = Math.floor(((nowMs - shimmerStart) % SHIMMER_SWEEP_MS) / SHIMMER_SWEEP_MS * period);
41
- let out = "";
42
- for (let i = 0; i < chars.length; i += 1) {
43
- const iPos = i + SHIMMER_PADDING;
44
- const dist = Math.abs(iPos - pos);
45
- let intensity = 0;
46
- if (dist <= SHIMMER_BAND_HALF_WIDTH) {
47
- const x = Math.PI * (dist / SHIMMER_BAND_HALF_WIDTH);
48
- intensity = 0.5 * (1 + Math.cos(x));
49
- }
50
- const ch = chars[i];
51
- if (intensity < 0.2) {
52
- out += `{gray-fg}${ch}{/gray-fg}`;
53
- } else if (intensity < 0.6) {
54
- out += ch;
55
- } else {
56
- out += `{bold}{white-fg}${ch}{/white-fg}{/bold}`;
57
- }
58
- }
59
- return out;
60
- }
61
-
62
- function spinnerFrame(nowMs) {
63
- const on = Math.floor((nowMs - shimmerStart) / SPINNER_PERIOD_MS) % 2 === 0;
64
- return on ? "{gray-fg}•{/gray-fg}" : "{gray-fg}◦{/gray-fg}";
65
- }
66
-
67
- function renderPendingStatus(text, nowMs) {
68
- const spinner = spinnerFrame(nowMs);
69
- const shimmer = shimmerText(text, nowMs);
70
- return shimmer ? `${spinner} ${shimmer}` : spinner;
71
- }
72
-
73
- function renderStatusLine(nowMs = now()) {
74
- let content = primaryStatusText || "";
75
- if (primaryStatusPending) {
76
- content = renderPendingStatus(primaryStatusText, nowMs);
77
- }
78
- if (busStatusQueue.length > 0) {
79
- const extra = busStatusQueue.length > 1
80
- ? ` {gray-fg}(+${busStatusQueue.length - 1}){/gray-fg}`
81
- : "";
82
- const busText = `${busStatusQueue[0].text}${extra}`;
83
- content = content
84
- ? `${content} {gray-fg}·{/gray-fg} ${busText}`
85
- : busText;
86
- }
87
- statusLine.setContent(content);
88
- }
89
-
90
- function updateAnimation() {
91
- if (primaryStatusPending && !animationTimer) {
92
- animationTimer = setIntervalFn(() => {
93
- if (!primaryStatusPending) return;
94
- renderStatusLine(now());
95
- renderScreen();
96
- }, STATUS_ANIM_FRAME_MS);
97
- } else if (!primaryStatusPending && animationTimer) {
98
- clearIntervalFn(animationTimer);
99
- animationTimer = null;
100
- }
101
- }
102
-
103
- function setPrimaryStatus(text, options = {}) {
104
- primaryStatusText = text || "";
105
- primaryStatusPending = Boolean(options.pending);
106
- updateAnimation();
107
- renderStatusLine();
108
- }
109
-
110
- function normalizePendingItem(text, options = {}) {
111
- const key = options && typeof options.key === "string"
112
- ? options.key.trim()
113
- : "";
114
- return {
115
- text: text || "",
116
- key,
117
- };
118
- }
119
-
120
- function headPendingText() {
121
- if (pendingStatusLines.length === 0) return "";
122
- const item = pendingStatusLines[0];
123
- return item && typeof item.text === "string" ? item.text : "";
124
- }
125
-
126
- function queueStatusLine(text, options = {}) {
127
- const item = normalizePendingItem(text, options);
128
- if (item.key) {
129
- const existingIndex = pendingStatusLines.findIndex((entry) => entry.key === item.key);
130
- if (existingIndex >= 0) {
131
- pendingStatusLines[existingIndex] = item;
132
- if (existingIndex === 0) {
133
- setPrimaryStatus(item.text, { pending: true });
134
- renderScreen();
135
- }
136
- return;
137
- }
138
- }
139
-
140
- pendingStatusLines.push(item);
141
- if (pendingStatusLines.length === 1) {
142
- setPrimaryStatus(item.text, { pending: true });
143
- renderScreen();
144
- }
145
- }
146
-
147
- function resolveStatusLine(text, options = {}) {
148
- const key = options && typeof options.key === "string"
149
- ? options.key.trim()
150
- : "";
151
- let removedHead = false;
152
-
153
- if (pendingStatusLines.length > 0) {
154
- if (key) {
155
- const index = pendingStatusLines.findIndex((entry) => entry.key === key);
156
- if (index >= 0) {
157
- pendingStatusLines.splice(index, 1);
158
- removedHead = index === 0;
159
- }
160
- } else {
161
- pendingStatusLines.shift();
162
- removedHead = true;
163
- }
164
- }
165
-
166
- if (pendingStatusLines.length > 0) {
167
- if (removedHead || !primaryStatusPending) {
168
- setPrimaryStatus(headPendingText(), { pending: true });
169
- }
170
- } else {
171
- setPrimaryStatus(text || "", { pending: false });
172
- }
173
- renderScreen();
174
- }
175
-
176
- function enqueueBusStatus(item) {
177
- if (!item || !item.text) return;
178
- const key = item.key || item.text;
179
- const formatted = formatProcessingText(item.text);
180
- const existing = busStatusQueue.find((entry) => entry.key === key);
181
- if (existing) {
182
- existing.text = formatted;
183
- } else {
184
- busStatusQueue.push({ key, text: formatted });
185
- }
186
- renderStatusLine();
187
- }
188
-
189
- function resolveBusStatus(item) {
190
- if (!item) return;
191
- const key = item.key || item.text;
192
- let index = -1;
193
- if (key) {
194
- index = busStatusQueue.findIndex((entry) => entry.key === key);
195
- }
196
- if (index === -1 && item.text) {
197
- index = busStatusQueue.findIndex((entry) => entry.text === item.text);
198
- }
199
- if (index === -1) return;
200
- busStatusQueue.splice(index, 1);
201
- renderStatusLine();
202
- }
203
-
204
- function destroy() {
205
- if (animationTimer) {
206
- clearIntervalFn(animationTimer);
207
- animationTimer = null;
208
- }
209
- }
210
-
211
- return {
212
- queueStatusLine,
213
- resolveStatusLine,
214
- enqueueBusStatus,
215
- resolveBusStatus,
216
- renderStatusLine,
217
- destroy,
218
- };
219
- }
220
-
221
- module.exports = {
222
- createStatusLineController,
223
- };
@@ -1,156 +0,0 @@
1
- const { renderMarkdownLines } = require("../shared/markdownRenderer");
2
-
3
- function createStreamTracker(options = {}) {
4
- const {
5
- logBox,
6
- writeSpacer,
7
- appendHistory,
8
- escapeBlessed,
9
- onStreamStart,
10
- now = () => new Date().toISOString(),
11
- } = options;
12
-
13
- const streamStates = new Map();
14
- const pendingDeliveries = new Map();
15
-
16
- function renderLine(line, mdState) {
17
- const rendered = renderMarkdownLines(line, mdState, escapeBlessed);
18
- return rendered.length > 0 ? rendered[0] : escapeBlessed(line);
19
- }
20
-
21
- function buildStreamDisplayText(fullText, prefix, continuationPrefix) {
22
- const mdState = {};
23
- const lines = String(fullText || "").split("\n");
24
- return lines.map((line, i) => {
25
- const p = i === 0 ? prefix : continuationPrefix;
26
- return `${p}${renderLine(line, mdState)}`;
27
- }).join("\n");
28
- }
29
-
30
- function beginStream(publisher, prefix, continuationPrefix, meta) {
31
- let state = streamStates.get(publisher);
32
- if (state) return state;
33
-
34
- if (typeof writeSpacer === "function") {
35
- writeSpacer();
36
- }
37
- logBox.pushLine(prefix);
38
- state = {
39
- publisher,
40
- prefix,
41
- continuationPrefix,
42
- lineIndex: logBox.getLines().length - 1,
43
- buffer: "",
44
- full: "",
45
- linesEmitted: 0,
46
- meta,
47
- mdState: {},
48
- };
49
- streamStates.set(publisher, state);
50
- if (typeof onStreamStart === "function") {
51
- onStreamStart();
52
- }
53
- return state;
54
- }
55
-
56
- function appendStreamDelta(state, delta) {
57
- if (!delta || !state) return;
58
- state.full += delta;
59
- state.buffer += delta;
60
- const parts = state.buffer.split("\n");
61
- if (parts.length > 1) {
62
- const completed = parts.slice(0, -1);
63
- for (const line of completed) {
64
- const prefix = state.linesEmitted === 0 ? state.prefix : state.continuationPrefix;
65
- logBox.setLine(state.lineIndex, `${prefix}${renderLine(line, state.mdState)}`);
66
- state.linesEmitted += 1;
67
- logBox.pushLine(state.continuationPrefix);
68
- state.lineIndex = logBox.getLines().length - 1;
69
- }
70
- state.buffer = parts[parts.length - 1];
71
- }
72
- const prefix = state.linesEmitted === 0 ? state.prefix : state.continuationPrefix;
73
- // For the current incomplete line, render with a snapshot of mdState
74
- // to avoid mutating state on partial lines
75
- const snapState = { inCodeBlock: state.mdState.inCodeBlock };
76
- logBox.setLine(state.lineIndex, `${prefix}${renderLine(state.buffer, snapState)}`);
77
- }
78
-
79
- function finalizeStream(publisher, meta, reason = "") {
80
- const state = streamStates.get(publisher);
81
- if (!state) return;
82
- const text = buildStreamDisplayText(state.full, state.prefix, state.continuationPrefix);
83
- appendHistory({
84
- ts: now(),
85
- type: "bus",
86
- text,
87
- meta: { ...(meta || {}), stream_done: true, stream_reason: reason },
88
- });
89
- streamStates.delete(publisher);
90
- }
91
-
92
- function hasStream(publisher) {
93
- return streamStates.has(publisher);
94
- }
95
-
96
- function markPendingDelivery(agentId, agentLabel) {
97
- const key = agentId || agentLabel;
98
- if (!key) return;
99
- const existing = pendingDeliveries.get(key);
100
- const state = existing || { count: 0, keys: new Set() };
101
- state.count += 1;
102
- if (agentId) {
103
- pendingDeliveries.set(agentId, state);
104
- state.keys.add(agentId);
105
- }
106
- if (agentLabel && agentLabel !== agentId) {
107
- pendingDeliveries.set(agentLabel, state);
108
- state.keys.add(agentLabel);
109
- }
110
- if (!agentId && !agentLabel) {
111
- pendingDeliveries.set(key, state);
112
- state.keys.add(key);
113
- }
114
- }
115
-
116
- function getPendingState(publisher, displayName) {
117
- if (publisher && pendingDeliveries.has(publisher)) {
118
- return { key: publisher, state: pendingDeliveries.get(publisher) };
119
- }
120
- if (displayName && pendingDeliveries.has(displayName)) {
121
- return { key: displayName, state: pendingDeliveries.get(displayName) };
122
- }
123
- return null;
124
- }
125
-
126
- function consumePendingDelivery(publisher, displayName) {
127
- const hit = getPendingState(publisher, displayName);
128
- if (!hit) return false;
129
- const state = hit.state;
130
- state.count -= 1;
131
- if (state.count <= 0) {
132
- for (const key of state.keys || []) {
133
- pendingDeliveries.delete(key);
134
- }
135
- }
136
- return true;
137
- }
138
-
139
- function discardAll() {
140
- streamStates.clear();
141
- pendingDeliveries.clear();
142
- }
143
-
144
- return {
145
- beginStream,
146
- appendStreamDelta,
147
- finalizeStream,
148
- hasStream,
149
- discardAll,
150
- markPendingDelivery,
151
- getPendingState,
152
- consumePendingDelivery,
153
- };
154
- }
155
-
156
- module.exports = { createStreamTracker };
package/src/code/config DELETED
File without changes