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
package/bin/ufoo.js CHANGED
@@ -1,11 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  /* eslint-disable no-console */
3
- const { runCli } = require("../src/cli");
4
- const { runDaemonCli } = require("../src/daemon/run");
5
- const { runChat } = require("../src/chat");
6
- const { runInternalRunner } = require("../src/agent/internalRunner");
7
- const { runPtyRunner } = require("../src/agent/ptyRunner");
8
- const { resolveGlobalControllerProjectRoot } = require("../src/projects");
3
+ const { runCli } = require("../src/app/cli/run");
4
+ const { runDaemonCli } = require("../src/runtime/daemon/run");
5
+ const { runChat } = require("../src/app/chat");
6
+ const { runInternalRunner } = require("../src/agents/internal/internalRunner");
7
+ const { resolveGlobalControllerProjectRoot } = require("../src/runtime/projects");
9
8
 
10
9
  const rawArgv = process.argv.slice(2);
11
10
 
@@ -33,23 +32,6 @@ async function main() {
33
32
  await runInternalRunner({ projectRoot: process.cwd(), agentType, extraArgs });
34
33
  return;
35
34
  }
36
- if (cmd === "agent-pty-runner") {
37
- const agentType = argv[1] || "codex";
38
- const extraArgs = argv.slice(2);
39
- try {
40
- await runPtyRunner({ projectRoot: process.cwd(), agentType, extraArgs });
41
- } catch (err) {
42
- const normalized = String(agentType || "").trim().toLowerCase();
43
- if (normalized === "ufoo" || normalized === "ucode" || normalized === "ufoo-code") {
44
- throw err;
45
- }
46
- // Fallback to headless runner if PTY is unavailable
47
- // eslint-disable-next-line no-console
48
- console.error(`[pty-runner] ${err.message || err}. Falling back to headless internal runner.`);
49
- await runInternalRunner({ projectRoot: process.cwd(), agentType, extraArgs });
50
- }
51
- return;
52
- }
53
35
  if (cmd === "chat") {
54
36
  await runChat(chatProjectRoot, { globalMode });
55
37
  return;
@@ -3,6 +3,6 @@
3
3
 
4
4
  > **Default: do not write a decision.** Record one only for important, plan-level knowledge that should constrain future work: architectural choices, trade-off analysis, cross-agent coordination, or precedent-setting integration contracts. NOT for routine findings, simple fixes, or because the user asked for a plan/evaluation/recommendation. Durable project facts belong in shared memory, not decisions. → `ufoo ctx decisions new "Title"` BEFORE acting only when that high bar is met.
5
5
  > **Read shared memory before writing it.** Durable facts live in `.ufoo/memory/`; use `ufoo memory list/show`, `recall`, `search_memory`, or redacted `search_history` evidence before `remember` / `edit_memory`.
6
- > **Auto-execute bus messages.** On `ubus`: execute tasks immediately, reply to sender, then `ufoo bus ack`. Never ask the user.
6
+ > **Auto-execute bus messages.** On `ubus`: execute tasks immediately, then `ufoo bus ack`. Never ask the user.
7
7
  > **Full protocol**: `/ufoo` skill (auto-loaded on session start). Docs: `.ufoo/docs/`
8
8
  <!-- /ufoo -->
@@ -120,7 +120,7 @@ ufoo bus ack "$SUBSCRIBER"
120
120
 
121
121
  **This is critical** - if you don't ack, the daemon will keep injecting `/ubus` commands.
122
122
 
123
- If there's nothing to do (no actionable task), just ack immediately without sending a reply.
123
+ **Default behavior is ack-only, no reply.** If there's nothing to do (no actionable task, no question to answer, no follow-up the sender genuinely needs), just ack and stop. Silence is a valid response — see "Handling Received Messages" below for when a reply IS warranted.
124
124
 
125
125
  ### 6. Routing Override
126
126
 
@@ -164,15 +164,40 @@ ufoo bus nick <subscriber-id> "new-nickname"
164
164
 
165
165
  ## Handling Received Messages
166
166
 
167
- When receiving targeted messages:
168
-
169
- 1. **Understand request** - Read message content
170
- 2. **Execute task** - If task delegation, execute it
171
- 3. **Reply to sender** - Send response after completion
172
-
173
- ```bash
174
- ufoo bus send "<sender-id>" "<reply-content>"
175
- ```
167
+ When receiving targeted messages, the default flow is **execute → ack → stop**.
168
+ Replies are the exception, not the default.
169
+
170
+ 1. **Understand request** Read message content.
171
+ 2. **Execute task** If the message delegates a task, do it.
172
+ 3. **`ufoo bus ack "$SUBSCRIBER"`** — Always ack, even when not replying.
173
+ 4. **Reply ONLY when substantive.** Send `ufoo bus send` to the sender only if at least one of the following is true:
174
+ - The sender asked a question → reply with the answer.
175
+ - The sender delegated a task → reply with the result / artifact / status.
176
+ - You discovered something the sender needs to proceed → reply with that fact.
177
+
178
+ ```bash
179
+ # Use this only when the criteria above are met.
180
+ ufoo bus send "<sender-id>" "<substantive-reply>"
181
+ ```
182
+
183
+ ### Anti-pattern: greet / ack loops
184
+
185
+ If the inbound message is itself just a greeting, an acknowledgment, or a
186
+ pleasantry, **do not reply**. Acking is enough. A bare-acknowledgment reply
187
+ will be auto-injected on the other side, triggering them to reply in kind,
188
+ and the two of you will ping-pong forever.
189
+
190
+ | Inbound | Reply? |
191
+ |---|---|
192
+ | `👋` / `hi` / `hello` / `你好` | ❌ ack only |
193
+ | `👍` / `ok` / `收到` / `thanks` / `noted` | ❌ ack only |
194
+ | `已完成 / done / finished` (without a result the sender asked for) | ❌ ack only |
195
+ | `请把 src/foo.ts 改成 ...` (task) | ✅ reply with result |
196
+ | `这个 bug 的根因是什么?` (question) | ✅ reply with answer |
197
+ | `我帮你找到了 X,需要你做 Y` (request) | ✅ reply with status |
198
+
199
+ When in doubt: ack and wait. If the sender genuinely needs something
200
+ from you, they will follow up with a concrete question or task.
176
201
 
177
202
  ## Sending Messages
178
203
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "u-foo",
3
- "version": "2.3.32",
3
+ "version": "2.4.0",
4
4
  "description": "Multi-Agent Workspace Protocol. Just add u. claude → uclaude, codex → ucodex.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "homepage": "https://ufoo.dev",
@@ -19,6 +19,7 @@
19
19
  "ufoo": "bin/ufoo.js",
20
20
  "uclaude": "bin/uclaude.js",
21
21
  "ucodex": "bin/ucodex.js",
22
+ "uagy": "bin/uagy.js",
22
23
  "ucode": "bin/ucode.js",
23
24
  "ucode-core": "bin/ucode-core.js"
24
25
  },
@@ -49,16 +50,15 @@
49
50
  "dependencies": {
50
51
  "@anthropic-ai/claude-agent-sdk": "^0.2.138",
51
52
  "@openai/codex-sdk": "^0.130.0",
52
- "blessed": "^0.1.81",
53
+ "@xterm/addon-serialize": "^0.14.0",
54
+ "@xterm/headless": "^6.0.0",
53
55
  "chalk": "^4.1.2",
54
56
  "commander": "^13.1.0",
55
57
  "gray-matter": "^4.0.3",
56
58
  "ink": "^5.2.1",
57
59
  "node-pty": "^1.1.0",
58
60
  "react": "^18.3.1",
59
- "ws": "^8.19.0",
60
- "xterm-addon-serialize": "^0.11.0",
61
- "xterm-headless": "^5.3.0"
61
+ "ws": "^8.19.0"
62
62
  },
63
63
  "devDependencies": {
64
64
  "jest": "^30.2.0"
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  const { runInk } = require("../src/ui/runInk");
10
- const { createChatApp } = require("../src/ui/components/ChatApp");
10
+ const { createChatApp } = require("../src/ui/ink/ChatApp");
11
11
 
12
12
  (async () => {
13
13
  const props = {
@@ -3,11 +3,11 @@
3
3
  const fs = require("fs");
4
4
  const path = require("path");
5
5
  const { spawn, spawnSync } = require("child_process");
6
- const UfooInit = require("../src/init");
7
- const { socketPath, isRunning } = require("../src/daemon");
8
- const { connectWithRetry } = require("../src/chat/transport");
9
- const { createDaemonTransport } = require("../src/chat/daemonTransport");
10
- const { createDaemonCoordinator } = require("../src/chat/daemonCoordinator");
6
+ const UfooInit = require("../src/app/cli/features/init");
7
+ const { socketPath, isRunning } = require("../src/runtime/daemon");
8
+ const { connectWithRetry } = require("../src/app/chat/transport");
9
+ const { createDaemonTransport } = require("../src/app/chat/daemonTransport");
10
+ const { createDaemonCoordinator } = require("../src/app/chat/daemonCoordinator");
11
11
 
12
12
  function sleep(ms) {
13
13
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -9,7 +9,7 @@
9
9
  */
10
10
 
11
11
  const { runInk } = require("../src/ui/runInk");
12
- const { createInkDemo } = require("../src/ui/components/InkDemo");
12
+ const { createInkDemo } = require("../src/ui/ink/InkDemo");
13
13
 
14
14
  (async () => {
15
15
  const handle = await runInk((React, ink) => {
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  const { runInk } = require("../src/ui/runInk");
10
- const { createInkDemo } = require("../src/ui/components/InkDemo");
10
+ const { createInkDemo } = require("../src/ui/ink/InkDemo");
11
11
 
12
12
  (async () => {
13
13
  const handle = await runInk((React, ink) => {
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  const { runInk } = require("../src/ui/runInk");
10
- const { createUcodeApp } = require("../src/ui/components/UcodeApp");
10
+ const { createUcodeApp } = require("../src/ui/ink/UcodeApp");
11
11
 
12
12
  (async () => {
13
13
  const props = {
@@ -10,7 +10,7 @@
10
10
  * BLOCKED ----+
11
11
  */
12
12
 
13
- const { isTranscriptActive } = require("./claudeSessionFiles");
13
+ const { isTranscriptActive } = require("../providers/claudeSessionFiles");
14
14
 
15
15
  const ACTIVITY_STATES = {
16
16
  starting: "starting",
@@ -46,6 +46,27 @@ const INPUT_PATTERNS = {
46
46
  /\[Y\/n\]/, // Bracket-style prompt
47
47
  /\by\/n\b/i, // y/n prompt (common in confirmation dialogs)
48
48
  ],
49
+ // agy (Antigravity CLI) shows ink-style menus and y/n approvals.
50
+ agy: [
51
+ /Use arrow keys to navigate, Enter to select/, // Any agy menu selector
52
+ /Select login method:/, // Initial OAuth login picker
53
+ /Yes, and run (?:in|without) sandbox/i, // Terminal command approval (sandbox toggle)
54
+ /\bn\b\s*-\s*Don't run/i, // y/n/edit confirmation
55
+ ],
56
+ };
57
+
58
+ // Agent-specific FATAL patterns that immediately move the agent into BLOCKED
59
+ // state (no quiet-window/timeout waiting). Reserved for hard backend errors
60
+ // the user can't resolve by waiting — e.g. agy's account-eligibility / region
61
+ // check failure, which returns 400 from the backend and the conversation
62
+ // never advances.
63
+ const FATAL_PATTERNS = {
64
+ agy: [
65
+ /Eligibility check failed/, // 18+/region not allowed
66
+ /User location is not supported/, // Geo restriction
67
+ /Account ineligible/, // Generic account-state failure
68
+ /FAILED_PRECONDITION/, // gRPC backend precondition reject
69
+ ],
49
70
  };
50
71
 
51
72
  const COMMON_PATTERNS = [
@@ -80,7 +101,7 @@ class ActivityDetector {
80
101
  /**
81
102
  * @param {string} agentType - e.g. "claude-code", "codex"
82
103
  * @param {object} [options]
83
- * @param {string} [options.mode] - launch mode ("internal-pty"/"terminal"/"tmux"/"iterm2")
104
+ * @param {string} [options.mode] - launch mode ("terminal"/"tmux"/"iterm2"/"pty-runner")
84
105
  * @param {number} [options.bufferSize=4000] - rolling buffer size in chars
85
106
  * @param {number} [options.tailLines=10] - number of tail lines used for quiet-time prompt detection
86
107
  * @param {boolean} [options.startOnOutput=false] - allow STARTING -> WORKING on first output
@@ -259,6 +280,22 @@ class ActivityDetector {
259
280
 
260
281
  const tailBuffer = this._tailWindow();
261
282
 
283
+ // Fatal-pattern check first: these go straight to BLOCKED with no
284
+ // recovery timer. Used for backend errors the user can't wait out.
285
+ const fatalPatterns = FATAL_PATTERNS[this.agentType] || [];
286
+ for (const pattern of fatalPatterns) {
287
+ const match = pattern.exec(tailBuffer);
288
+ if (!match) continue;
289
+ const matchedText = String(match[0] || "");
290
+ const matchIndex = Number.isFinite(match.index)
291
+ ? match.index
292
+ : Math.max(0, tailBuffer.length - matchedText.length);
293
+ if (this._hasDeniedContext(tailBuffer, matchIndex, matchedText.length)) continue;
294
+ this._clearBlockedTimer();
295
+ this._setState(ACTIVITY_STATES.blocked, `fatal:${pattern.source}`);
296
+ return;
297
+ }
298
+
262
299
  // Check agent-specific patterns only after output has stabilized.
263
300
  const agentPatterns = INPUT_PATTERNS[this.agentType] || [];
264
301
  const allPatterns = [...agentPatterns, ...COMMON_PATTERNS];
@@ -5,7 +5,7 @@ const { writeActivityState } = require("./activityStateWriter");
5
5
  /**
6
6
  * Unified activity state publisher.
7
7
  * Encapsulates the "write to disk + broadcast event" pattern used by
8
- * ptyRunner, launcher, notifier, and internalRunner.
8
+ * launcher, notifier, and internalRunner.
9
9
  *
10
10
  * Dedupe key is `state|detail` so that within the same canonical state
11
11
  * (e.g. `working`) callers can publish detail transitions like
@@ -1,6 +1,6 @@
1
1
  const fs = require("fs");
2
- const { readJSON, writeJSON } = require("../bus/utils");
3
- const { appendAgentRegistryDiagnostic } = require("../ufoo/agentRegistryDiagnostics");
2
+ const { readJSON, writeJSON } = require("../../coordination/bus/utils");
3
+ const { appendAgentRegistryDiagnostic } = require("../../coordination/state/agentRegistryDiagnostics");
4
4
 
5
5
  /**
6
6
  * Centralized helper for writing activity_state to all-agents.json.
@@ -7,7 +7,7 @@
7
7
  * canonical activity model (`starting`/`ready`/`working`/`idle`/`waiting_input`/`blocked`)
8
8
  * plus a short detail string (e.g. `thinking`, `tool bash`). Publishes through
9
9
  * an injected publisher so the same tracker can be reused by internal,
10
- * internal-pty, or future runner shapes.
10
+ * internal, or future runner shapes.
11
11
  *
12
12
  * Design contract:
13
13
  * - The tracker never reads PTY text or guesses state from prose. All state
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ ...require("./activityDetector"),
5
+ ...require("./activityStatePublisher"),
6
+ ...require("./activityStateWriter"),
7
+ ...require("./activityTracker"),
8
+ };
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
 
3
- const EventBus = require("../bus");
4
- const { getToolDefinition, CALLER_TIERS } = require("../tools");
5
- const { dispatchMessageHandler } = require("../tools/handlers/dispatchMessage");
6
- const { ackBusHandler } = require("../tools/handlers/ackBus");
3
+ const EventBus = require("../../coordination/bus");
4
+ const { getToolDefinition, CALLER_TIERS } = require("../../tools");
5
+ const { dispatchMessageHandler } = require("../../tools/handlers/dispatchMessage");
6
+ const { ackBusHandler } = require("../../tools/handlers/ackBus");
7
7
 
8
8
  function normalizeObjectArgs(value) {
9
9
  if (!value) return {};
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ ...require("./controllerToolExecutor"),
5
+ ...require("./loopObservability"),
6
+ ...require("./loopRuntime"),
7
+ ...require("./ufooAgent"),
8
+ };
@@ -2,8 +2,8 @@
2
2
 
3
3
  const fs = require("fs");
4
4
  const path = require("path");
5
- const { getUfooPaths } = require("../ufoo/paths");
6
- const { redactSecrets } = require("../providerapi/redactor");
5
+ const { getUfooPaths } = require("../../coordination/state/paths");
6
+ const { redactSecrets } = require("../../runtime/privacy/redactor");
7
7
 
8
8
  const LOOP_EVENT_SCHEMA_VERSION = 1;
9
9
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  const { executeControllerTool } = require("./controllerToolExecutor");
4
4
  const { createLoopObserver } = require("./loopObservability");
5
- const { finalizeRouterPayload } = require("../controller/routerFinalize");
5
+ const { finalizeRouterPayload } = require("../../orchestration/controller/routerFinalize");
6
6
 
7
7
  const DEFAULT_LOOP_OPTIONS = {
8
8
  enabled: false,
@@ -1,17 +1,17 @@
1
1
  const fs = require("fs");
2
2
  const path = require("path");
3
- const { buildStatus } = require("../daemon/status");
4
- const { getUfooPaths } = require("../ufoo/paths");
5
- const { normalizeGateRouterResult } = require("../controller/gateRouter");
6
- const { normalizeProvider, sendUpstreamPrompt } = require("./upstreamTransport");
7
- const { normalizeAgentTypeAlias } = require("../bus/utils");
8
- const { buildCachedMemoryPrefix } = require("../memory");
9
- const { listProjectRuntimes, isGlobalControllerProjectRoot } = require("../projects");
10
- const { assignMissingLaunchNicknames } = require("../controller/launchRouting");
3
+ const { buildStatus } = require("../../runtime/daemon/status");
4
+ const { getUfooPaths } = require("../../coordination/state/paths");
5
+ const { normalizeGateRouterResult } = require("../../orchestration/controller/gateRouter");
6
+ const { normalizeProvider, sendUpstreamPrompt } = require("../providers/upstreamTransport");
7
+ const { normalizeAgentTypeAlias } = require("../../coordination/bus/utils");
8
+ const { buildCachedMemoryPrefix } = require("../../coordination/memory");
9
+ const { listProjectRuntimes, isGlobalControllerProjectRoot } = require("../../runtime/projects");
10
+ const { assignMissingLaunchNicknames } = require("../../orchestration/controller/launchRouting");
11
11
  const {
12
12
  CONTROLLER_MODES,
13
13
  resolveControllerMode,
14
- } = require("../controller/flags");
14
+ } = require("../../orchestration/controller/flags");
15
15
 
16
16
  function loadSessionState(projectRoot) {
17
17
  const dir = getUfooPaths(projectRoot).agentDir;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ ...require("./activity"),
5
+ ...require("./controller"),
6
+ ...require("./internal"),
7
+ ...require("./launch"),
8
+ ...require("./prompts"),
9
+ ...require("./providers"),
10
+ };
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+
3
+ module.exports = require("./internalRunner");
@@ -1,25 +1,26 @@
1
1
  const fs = require("fs");
2
2
  const path = require("path");
3
- const { getUfooPaths } = require("../ufoo/paths");
3
+ const { getUfooPaths } = require("../../coordination/state/paths");
4
4
  const { spawnSync } = require("child_process");
5
- const EventBus = require("../bus");
6
- const { readJSON, writeJSON } = require("../bus/utils");
7
- const { createActivityStatePublisher } = require("./activityStatePublisher");
8
- const { createActivityTracker } = require("./activityTracker");
9
- const { loadConfig, normalizeCodexInternalThreadMode } = require("../config");
10
- const { createCodexThreadProvider } = require("./codexThreadProvider");
11
- const { createClaudeThreadProvider } = require("./claudeThreadProvider");
12
- const { resolveClaudeUpstreamCredentials } = require("./credentials/claude");
13
- const { buildUpstreamAuthFromCredential } = require("./credentials");
14
- const { listToolsForCallerTier, CALLER_TIERS } = require("../tools");
15
- const { redactToolCallPayload, redactSecrets } = require("../providerapi/redactor");
16
- const { buildCachedMemoryPrefix } = require("../memory");
17
- const { shouldForwardStreamToPublisher } = require("./publisherRouting");
18
- const { appendAgentRegistryDiagnostic } = require("../ufoo/agentRegistryDiagnostics");
5
+ const EventBus = require("../../coordination/bus");
6
+ const { readJSON, writeJSON } = require("../../coordination/bus/utils");
7
+ const { createActivityStatePublisher } = require("../activity/activityStatePublisher");
8
+ const { createActivityTracker } = require("../activity/activityTracker");
9
+ const { loadConfig, normalizeCodexInternalThreadMode } = require("../../config");
10
+ const { createCodexThreadProvider } = require("../providers/codexThreadProvider");
11
+ const { createClaudeThreadProvider } = require("../providers/claudeThreadProvider");
12
+ const { resolveClaudeUpstreamCredentials } = require("../providers/credentials/claude");
13
+ const { buildUpstreamAuthFromCredential } = require("../providers/credentials");
14
+ const { listToolsForCallerTier, CALLER_TIERS } = require("../../tools");
15
+ const { redactToolCallPayload, redactSecrets } = require("../../runtime/privacy/redactor");
16
+ const { buildCachedMemoryPrefix } = require("../../coordination/memory");
17
+ const { normalizePublisher, shouldForwardStreamToPublisher } = require("../launch/publisherRouting");
18
+ const { appendAgentRegistryDiagnostic } = require("../../coordination/state/agentRegistryDiagnostics");
19
19
  const {
20
20
  buildDefaultStartupBootstrapPrompt,
21
21
  isValueForCodexOption,
22
- } = require("./defaultBootstrap");
22
+ } = require("../prompts/defaultBootstrap");
23
+ const { buildPromptInjectionText } = require("../../coordination/bus/promptEnvelope");
23
24
 
24
25
  function sleep(ms) {
25
26
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -161,6 +162,21 @@ function buildMemoryPrefix(projectRoot, limit = 50) {
161
162
  }
162
163
  }
163
164
 
165
+ function readAgentsMap(projectRoot) {
166
+ try {
167
+ const data = readJSON(getUfooPaths(projectRoot).agentsFile, null);
168
+ return data && data.agents && typeof data.agents === "object" ? data.agents : {};
169
+ } catch {
170
+ return {};
171
+ }
172
+ }
173
+
174
+ function buildInternalPromptMessage(projectRoot, subscriber, evt = {}) {
175
+ const message = String((evt.data && evt.data.message) || "");
176
+ if (evt.__agentViewRaw) return message;
177
+ return buildPromptInjectionText(evt, subscriber, readAgentsMap(projectRoot));
178
+ }
179
+
164
180
  function createBusSender(projectRoot, subscriber) {
165
181
  const eventBus = new EventBus(projectRoot);
166
182
  let sendQueue = Promise.resolve();
@@ -187,11 +203,20 @@ function createBusSender(projectRoot, subscriber) {
187
203
 
188
204
  function isChatUiSource(source = "") {
189
205
  const value = String(source || "").trim();
190
- return value === "chat-direct" || value === "chat-internal-agent-view";
206
+ return value === "chat-direct"
207
+ || value === "chat-agent-view"
208
+ || value === "chat-internal-agent-view";
209
+ }
210
+
211
+ function isUfooAgentDispatchSource(source = "") {
212
+ const value = String(source || "").trim();
213
+ return value === "ufoo-agent" || value === "ufoo-agent-gate-router";
191
214
  }
192
215
 
193
216
  function shouldStreamReplyToPublisher(projectRoot, publisher, evt = {}) {
194
- if (isChatUiSource(evt && evt.data ? evt.data.source : "")) return true;
217
+ const source = evt && evt.data ? evt.data.source : "";
218
+ if (isChatUiSource(source)) return true;
219
+ if (normalizePublisher(publisher) === "ufoo-agent" && isUfooAgentDispatchSource(source)) return true;
195
220
  return shouldForwardStreamToPublisher(projectRoot, publisher);
196
221
  }
197
222
 
@@ -311,7 +336,8 @@ async function handleEvent(
311
336
  ) {
312
337
  if (!evt || !evt.data || !evt.data.message) return;
313
338
  const memoryPrefix = buildMemoryPrefix(projectRoot);
314
- const prompt = [bootstrapText, memoryPrefix, evt.data.message]
339
+ const promptMessage = buildInternalPromptMessage(projectRoot, subscriber, evt);
340
+ const prompt = [bootstrapText, memoryPrefix, promptMessage]
315
341
  .map((item) => String(item || "").trim())
316
342
  .filter(Boolean)
317
343
  .join("\n\n");
@@ -732,9 +758,6 @@ async function runInternalRunner({ projectRoot, agentType = "codex", extraArgs =
732
758
  const queueDir = path.join(getUfooPaths(projectRoot).busQueuesDir, safeSubscriber(subscriber));
733
759
  const queueFile = path.join(queueDir, "pending.jsonl");
734
760
  const normalizedAgentType = String(agentType || "").trim().toLowerCase();
735
- if (normalizedAgentType === "ufoo" || normalizedAgentType === "ucode" || normalizedAgentType === "ufoo-code") {
736
- throw new Error("ufoo core is not supported by headless internal runner; use internal-pty");
737
- }
738
761
  const provider = normalizedAgentType === "codex" ? "codex-cli" : "claude-cli";
739
762
  const model = process.env.UFOO_AGENT_MODEL || "";
740
763
  const bootstrap = resolveInternalBootstrap({