u-foo 2.3.30 → 2.3.32

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 (38) hide show
  1. package/package.json +5 -1
  2. package/scripts/chat-app-smoke.js +30 -0
  3. package/scripts/ink-demo.js +23 -0
  4. package/scripts/ink-smoke.js +30 -0
  5. package/scripts/ucode-app-smoke.js +36 -0
  6. package/src/chat/commandExecutor.js +6 -2
  7. package/src/chat/daemonMessageRouter.js +9 -1
  8. package/src/chat/daemonTransport.js +2 -1
  9. package/src/chat/dashboardKeyController.js +0 -40
  10. package/src/chat/dashboardView.js +0 -20
  11. package/src/chat/index.js +9 -1
  12. package/src/chat/inputSubmitHandler.js +34 -0
  13. package/src/chat/projectCloseController.js +1 -1
  14. package/src/chat/shellCommand.js +42 -0
  15. package/src/chat/transport.js +16 -3
  16. package/src/cli.js +4 -3
  17. package/src/code/agent.js +4 -0
  18. package/src/code/nativeRunner.js +74 -0
  19. package/src/code/taskDecomposer.js +5 -4
  20. package/src/code/tui.js +73 -561
  21. package/src/daemon/index.js +169 -27
  22. package/src/daemon/ipcServer.js +23 -1
  23. package/src/daemon/promptRequest.js +6 -1
  24. package/src/daemon/run.js +11 -4
  25. package/src/projects/runtimes.js +1 -1
  26. package/src/ufoo/agentRegistryDiagnostics.js +43 -0
  27. package/src/ui/MIGRATION.md +382 -0
  28. package/src/ui/components/ChatApp.js +2950 -0
  29. package/src/ui/components/DashboardBar.js +417 -0
  30. package/src/ui/components/InkDemo.js +96 -0
  31. package/src/ui/components/MultilineInput.js +387 -0
  32. package/src/ui/components/UcodeApp.js +813 -0
  33. package/src/ui/components/agentMirror.js +725 -0
  34. package/src/ui/components/chatReducer.js +337 -0
  35. package/src/ui/format/index.js +997 -0
  36. package/src/ui/index.js +9 -0
  37. package/src/ui/runInk.js +57 -0
  38. package/src/utils/nodeExecutable.js +26 -0
@@ -512,12 +512,23 @@ function runCoreTool({ tool = "", args = {}, workspaceRoot = process.cwd(), onTo
512
512
  return result;
513
513
  }
514
514
 
515
+ function emitPhase(callback, event = {}) {
516
+ if (typeof callback !== "function") return;
517
+ try {
518
+ callback(event);
519
+ } catch {
520
+ // ignore phase callback failures
521
+ }
522
+ }
523
+
515
524
  async function runOpenAiLikeTurn({
516
525
  url = "",
517
526
  apiKey = "",
518
527
  model = "",
519
528
  messages = [],
520
529
  onTextDelta = null,
530
+ onThinkingDelta = null,
531
+ onPhase = null,
521
532
  signal = null,
522
533
  timeoutMs = 300000,
523
534
  } = {}) {
@@ -540,6 +551,8 @@ async function runOpenAiLikeTurn({
540
551
 
541
552
  const request = createRequestController({ signal, timeoutMs });
542
553
 
554
+ emitPhase(onPhase, { type: "request_start" });
555
+
543
556
  try {
544
557
  const response = await fetch(url, {
545
558
  method: "POST",
@@ -574,6 +587,7 @@ async function runOpenAiLikeTurn({
574
587
  const toolCallMap = new Map();
575
588
  let rawBuffer = "";
576
589
  let responseText = "";
590
+ const announcedToolNames = new Set();
577
591
 
578
592
  while (true) {
579
593
  const { done, value } = await reader.read();
@@ -599,8 +613,19 @@ async function runOpenAiLikeTurn({
599
613
 
600
614
  const delta = choice.delta && typeof choice.delta === "object" ? choice.delta : {};
601
615
 
616
+ const reasoningChunk = typeof delta.reasoning_content === "string"
617
+ ? delta.reasoning_content
618
+ : (typeof delta.reasoning === "string" ? delta.reasoning : "");
619
+ if (reasoningChunk) {
620
+ emitPhase(onPhase, { type: "thinking_delta", text: reasoningChunk });
621
+ if (typeof onThinkingDelta === "function") {
622
+ onThinkingDelta(reasoningChunk);
623
+ }
624
+ }
625
+
602
626
  if (typeof delta.content === "string" && delta.content) {
603
627
  responseText += delta.content;
628
+ emitPhase(onPhase, { type: "text_delta", text: delta.content });
604
629
  if (typeof onTextDelta === "function") {
605
630
  onTextDelta(delta.content);
606
631
  }
@@ -629,6 +654,13 @@ async function runOpenAiLikeTurn({
629
654
  }
630
655
 
631
656
  toolCallMap.set(index, previous);
657
+
658
+ const toolName = previous.function.name;
659
+ const announceKey = `${index}:${toolName}`;
660
+ if (toolName && !announcedToolNames.has(announceKey)) {
661
+ announcedToolNames.add(announceKey);
662
+ emitPhase(onPhase, { type: "tool_request", name: toolName });
663
+ }
632
664
  }
633
665
  }
634
666
  }
@@ -716,6 +748,8 @@ async function runAnthropicTurn({
716
748
  systemPrompt = "",
717
749
  messages = [],
718
750
  onTextDelta = null,
751
+ onThinkingDelta = null,
752
+ onPhase = null,
719
753
  signal = null,
720
754
  timeoutMs = 300000,
721
755
  } = {}) {
@@ -741,6 +775,8 @@ async function runAnthropicTurn({
741
775
 
742
776
  const request = createRequestController({ signal, timeoutMs });
743
777
 
778
+ emitPhase(onPhase, { type: "request_start" });
779
+
744
780
  try {
745
781
  const response = await fetch(url, {
746
782
  method: "POST",
@@ -811,6 +847,12 @@ async function runAnthropicTurn({
811
847
  type: "text",
812
848
  text: String(contentBlock.text || ""),
813
849
  });
850
+ } else if (contentBlock.type === "thinking") {
851
+ blockMap.set(index, {
852
+ order: index,
853
+ type: "thinking",
854
+ text: String(contentBlock.thinking || ""),
855
+ });
814
856
  } else if (contentBlock.type === "tool_use") {
815
857
  blockMap.set(index, {
816
858
  order: index,
@@ -822,6 +864,10 @@ async function runAnthropicTurn({
822
864
  : {},
823
865
  inputJson: "",
824
866
  });
867
+ const toolName = String(contentBlock.name || "");
868
+ if (toolName) {
869
+ emitPhase(onPhase, { type: "tool_request", name: toolName });
870
+ }
825
871
  }
826
872
  continue;
827
873
  }
@@ -840,6 +886,7 @@ async function runAnthropicTurn({
840
886
  blockMap.set(index, current);
841
887
  if (deltaText) {
842
888
  responseText += deltaText;
889
+ emitPhase(onPhase, { type: "text_delta", text: deltaText });
843
890
  if (typeof onTextDelta === "function") {
844
891
  onTextDelta(deltaText);
845
892
  }
@@ -847,6 +894,20 @@ async function runAnthropicTurn({
847
894
  continue;
848
895
  }
849
896
 
897
+ if (delta.type === "thinking_delta") {
898
+ const deltaText = String(delta.thinking || "");
899
+ current.type = "thinking";
900
+ current.text = `${String(current.text || "")}${deltaText}`;
901
+ blockMap.set(index, current);
902
+ if (deltaText) {
903
+ emitPhase(onPhase, { type: "thinking_delta", text: deltaText });
904
+ if (typeof onThinkingDelta === "function") {
905
+ onThinkingDelta(deltaText);
906
+ }
907
+ }
908
+ continue;
909
+ }
910
+
850
911
  if (delta.type === "input_json_delta") {
851
912
  current.type = "tool_use";
852
913
  current.inputJson = `${String(current.inputJson || "")}${String(delta.partial_json || "")}`;
@@ -859,6 +920,7 @@ async function runAnthropicTurn({
859
920
 
860
921
  const assistantContent = Array.from(blockMap.values())
861
922
  .sort((a, b) => a.order - b.order)
923
+ .filter((item) => item.type !== "thinking")
862
924
  .map((item) => {
863
925
  if (item.type === "text") {
864
926
  return {
@@ -919,6 +981,8 @@ async function runNativeLoopOpenAi({
919
981
  apiKey = "",
920
982
  timeoutMs = 300000,
921
983
  onStreamDelta = null,
984
+ onThinkingDelta = null,
985
+ onPhase = null,
922
986
  onToolEvent = null,
923
987
  signal = null,
924
988
  guards,
@@ -957,6 +1021,8 @@ async function runNativeLoopOpenAi({
957
1021
  messages,
958
1022
  signal,
959
1023
  timeoutMs,
1024
+ onPhase,
1025
+ onThinkingDelta,
960
1026
  onTextDelta: (chunk) => {
961
1027
  const text = String(chunk || "");
962
1028
  if (!text) return;
@@ -1061,6 +1127,8 @@ async function runNativeLoopAnthropic({
1061
1127
  apiKey = "",
1062
1128
  timeoutMs = 300000,
1063
1129
  onStreamDelta = null,
1130
+ onThinkingDelta = null,
1131
+ onPhase = null,
1064
1132
  onToolEvent = null,
1065
1133
  signal = null,
1066
1134
  guards,
@@ -1098,6 +1166,8 @@ async function runNativeLoopAnthropic({
1098
1166
  messages,
1099
1167
  signal,
1100
1168
  timeoutMs,
1169
+ onPhase,
1170
+ onThinkingDelta,
1101
1171
  onTextDelta: (chunk) => {
1102
1172
  const text = String(chunk || "");
1103
1173
  if (!text) return;
@@ -1198,6 +1268,8 @@ async function runNativeAgentTask({
1198
1268
  sessionId = "",
1199
1269
  timeoutMs = 300000,
1200
1270
  onStreamDelta = null,
1271
+ onThinkingDelta = null,
1272
+ onPhase = null,
1201
1273
  onToolEvent = null,
1202
1274
  signal = null,
1203
1275
  } = {}) {
@@ -1238,6 +1310,8 @@ async function runNativeAgentTask({
1238
1310
  apiKey: runtime.apiKey,
1239
1311
  timeoutMs,
1240
1312
  onStreamDelta,
1313
+ onThinkingDelta,
1314
+ onPhase,
1241
1315
  onToolEvent,
1242
1316
  signal,
1243
1317
  guards,
@@ -10,6 +10,7 @@ const { runNativeAgentTask } = require("./nativeRunner");
10
10
  */
11
11
  function decomposeBugFixTask(task) {
12
12
  const steps = [];
13
+ const taskContext = String(task || "");
13
14
 
14
15
  // Analyze task to determine if it's a bug fix
15
16
  const isBugFix = /fix|bug|issue|problem|error|broken|doesn't work|not work/i.test(task);
@@ -18,7 +19,7 @@ function decomposeBugFixTask(task) {
18
19
  steps.push({
19
20
  id: "identify",
20
21
  name: "Identifying the issue",
21
- prompt: `Identify the specific problem: ${task}\n\nBe concise. Focus only on:\n1. What is broken\n2. What file/function is likely involved\n3. What the expected behavior should be\n\nDo NOT analyze entire codebases. Find the specific issue quickly.`,
22
+ prompt: `Task context:\n${taskContext}\n\nIdentify the specific problem.\n\nBe concise. Focus only on:\n1. What is broken\n2. What file/function is likely involved\n3. What the expected behavior should be\n\nDo NOT analyze entire codebases. Find the specific issue quickly.`,
22
23
  timeoutMs: 30000, // 30 seconds
23
24
  earlyExit: true,
24
25
  });
@@ -26,7 +27,7 @@ function decomposeBugFixTask(task) {
26
27
  steps.push({
27
28
  id: "locate",
28
29
  name: "Locating relevant code",
29
- prompt: `Based on the identified issue, find the exact location of the bug.\n\nSearch for and read ONLY the relevant function/file. Stop as soon as you find the problematic code.`,
30
+ prompt: `Task context:\n${taskContext}\n\nBased on the identified issue, find the exact location of the bug.\n\nSearch for and read ONLY the relevant function/file. Stop as soon as you find the problematic code.`,
30
31
  timeoutMs: 30000,
31
32
  earlyExit: true,
32
33
  });
@@ -34,7 +35,7 @@ function decomposeBugFixTask(task) {
34
35
  steps.push({
35
36
  id: "fix",
36
37
  name: "Applying the fix",
37
- prompt: `Apply the minimal fix needed. Do NOT refactor or improve unrelated code. Just fix the specific issue.`,
38
+ prompt: `Task context:\n${taskContext}\n\nApply the minimal fix needed. Do NOT refactor or improve unrelated code. Just fix the specific issue.`,
38
39
  timeoutMs: 60000,
39
40
  earlyExit: false,
40
41
  });
@@ -42,7 +43,7 @@ function decomposeBugFixTask(task) {
42
43
  steps.push({
43
44
  id: "verify",
44
45
  name: "Verifying the fix",
45
- prompt: `Verify the fix resolves the issue. Check that:\n1. The specific problem is fixed\n2. No new issues were introduced\n\nBe brief.`,
46
+ prompt: `Task context:\n${taskContext}\n\nVerify the fix resolves the issue. Check that:\n1. The specific problem is fixed\n2. No new issues were introduced\n\nBe brief.`,
46
47
  timeoutMs: 20000,
47
48
  earlyExit: false,
48
49
  });