u-foo 3.0.0 → 3.0.1

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.
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Structural / explicit decomposition upgrade decisions (R7).
5
+ * Not a language-specific bug-keyword classifier.
6
+ */
7
+
8
+ function shouldUpgradeToDecomposition(task = "", options = {}) {
9
+ const text = String(task || "").trim();
10
+ const reasons = [];
11
+
12
+ if (options.forceDirect === true || options.disableDecomposition === true) {
13
+ return {
14
+ upgrade: false,
15
+ reason: "forced_direct",
16
+ reasons: ["forced_direct"],
17
+ };
18
+ }
19
+ if (options.forceDecomposition === true || options.forceDecompose === true) {
20
+ return {
21
+ upgrade: true,
22
+ reason: "forced_decomposition",
23
+ reasons: ["forced_decomposition"],
24
+ };
25
+ }
26
+ if (!text) {
27
+ return { upgrade: false, reason: "empty", reasons: ["empty"] };
28
+ }
29
+
30
+ // Explicit user/model requests (EN + ZH).
31
+ if (/(?:\bdecompos(?:e|ition)\b|\bbreak\s+(?:this|it)\s+down\b|\bmulti[- ]?step\s+plan\b|拆解|分步|分解任务|制定计划)/i.test(text)) {
32
+ reasons.push("explicit_decompose_request");
33
+ }
34
+
35
+ // Multiple independently verifiable goals (numbered / bulleted / conjunctions).
36
+ const numbered = (text.match(/(?:^|\n)\s*(?:\d+[\).]|[-*•])\s+\S+/g) || []).length;
37
+ if (numbered >= 2) reasons.push("multiple_listed_goals");
38
+
39
+ const multiClause = /(?:^|[;;。\n])\s*(?:and\s+also|also|然后|并且|同时|另外|以及)\b/i.test(text)
40
+ || (text.split(/[;;]/).map((s) => s.trim()).filter((s) => s.length > 12).length >= 3);
41
+ if (multiClause) reasons.push("multi_clause_objectives");
42
+
43
+ // High-risk / multi-file structural cues (not "fix" alone).
44
+ if (/\b(?:across\s+(?:files?|modules?|packages?)|multiple\s+files?|refactor\s+the\s+\w+|迁移|跨文件|多文件)\b/i.test(text)) {
45
+ reasons.push("multi_file_or_refactor_scope");
46
+ }
47
+ if (/\b(?:checkpoint|rollback|migration|schema\s+change|生产环境|回滚)\b/i.test(text)) {
48
+ reasons.push("high_risk_change");
49
+ }
50
+
51
+ // Runtime budget / prior failures may request upgrade.
52
+ if (Number(options.failureCount || 0) >= 2) {
53
+ reasons.push("repeated_failures");
54
+ }
55
+ if (options.modelRequestedUpgrade === true) {
56
+ reasons.push("model_route_decision");
57
+ }
58
+ if (options.hasPlanGraph === true) {
59
+ // Already structured — keep direct loop unless other reasons fire.
60
+ // (graph exists is not itself a decompose trigger)
61
+ }
62
+
63
+ const upgrade = reasons.length > 0;
64
+ return {
65
+ upgrade,
66
+ reason: upgrade ? reasons[0] : "direct_default",
67
+ reasons,
68
+ };
69
+ }
70
+
71
+ module.exports = {
72
+ shouldUpgradeToDecomposition,
73
+ };
@@ -950,18 +950,8 @@ function createUcodeApp({ React, ink, props, interactive = true }) {
950
950
 
951
951
  // Pending approval/choice/chat takes priority over nudge / new NL.
952
952
  try {
953
- const {
954
- hasPendingUserInteraction,
955
- parseUserInteractionInput,
956
- getPendingUserInteraction,
957
- } = require("../../code/context/userInteraction");
953
+ const { hasPendingUserInteraction } = require("../../code/context/userInteraction");
958
954
  if (props.state && props.state.executionState && hasPendingUserInteraction(props.state.executionState)) {
959
- const pending = getPendingUserInteraction(props.state.executionState);
960
- const parsed = parseUserInteractionInput(pending, trimmed);
961
- if (!parsed.ok) {
962
- appendLogText(parsed.error || "Invalid reply", "error");
963
- return;
964
- }
965
955
  appendLogText(`› ${trimmed}`, "user");
966
956
  const startedAt = Date.now();
967
957
  setStatus({
@@ -972,14 +962,14 @@ function createUcodeApp({ React, ink, props, interactive = true }) {
972
962
  });
973
963
  runChainRef.current = runChainRef.current
974
964
  .then(async () => {
975
- const resume = typeof props.resumeAfterUserInteraction === "function"
976
- ? props.resumeAfterUserInteraction
977
- : require("../../code/agent").resumeAfterUserInteraction;
965
+ const submit = typeof props.submitUserInteractionAnswer === "function"
966
+ ? props.submitUserInteractionAnswer
967
+ : require("../../code/protocol").submitUserInteractionAnswer;
978
968
  let streamBuf = "";
979
969
  let sawStreamText = false;
980
970
  let streamStarted = false;
981
971
  let dropLeadingStreamBlank = false;
982
- const result = await resume(trimmed, props.state, {
972
+ const result = await submit(trimmed, props.state, {
983
973
  onDelta: (delta) => {
984
974
  const text = String(delta || "");
985
975
  if (!text) return;
@@ -1006,19 +996,12 @@ function createUcodeApp({ React, ink, props, interactive = true }) {
1006
996
  }
1007
997
  flushTableBuffer();
1008
998
  refreshPlanUi();
1009
- if (result && result.waitingUserInteraction) {
1010
- appendLogText("Still waiting for your reply.", "system");
1011
- setStatus({ message: "", type: "thinking", showTimer: false, startedAt: 0 });
1012
- return;
1013
- }
1014
999
  if (!result || result.ok === false) {
1015
1000
  appendLogText(`Error: ${(result && result.error) || "resume failed"}`, "error");
1016
- } else {
1017
- // Skip summary echo when deltas were already rendered (mirrors NL path).
1018
- const shouldSkipSummary = Boolean(result.streamed && result.ok && sawStreamText);
1019
- if (result.summary && !shouldSkipSummary) {
1020
- appendLogText(result.summary);
1021
- }
1001
+ } else if (result.shouldEchoSummary) {
1002
+ appendLogText(result.echoSummaryText || result.summary || "", result.waitingUserInteraction ? "system" : "assistant");
1003
+ } else if (result.waitingUserInteraction) {
1004
+ appendLogText("Still waiting for your reply.", "system");
1022
1005
  }
1023
1006
  setStatus({ message: "", type: "thinking", showTimer: false, startedAt: 0 });
1024
1007
  })
@@ -1067,7 +1050,7 @@ function createUcodeApp({ React, ink, props, interactive = true }) {
1067
1050
  flushActiveMerge,
1068
1051
  flushTableBuffer,
1069
1052
  props.state,
1070
- props.resumeAfterUserInteraction,
1053
+ props.submitUserInteractionAnswer,
1071
1054
  refreshPlanUi,
1072
1055
  ]);
1073
1056