u-foo 2.3.12 → 2.3.14

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.
package/src/daemon/ops.js CHANGED
@@ -14,6 +14,7 @@ const {
14
14
  const {
15
15
  createSession: createHostSession,
16
16
  } = require("../terminal/adapters/hostAdapter");
17
+ const { resolveDefaultManualBootstrap } = require("../agent/defaultBootstrap");
17
18
 
18
19
  function normalizeLaunchAgent(agent = "") {
19
20
  const value = String(agent || "").trim().toLowerCase();
@@ -44,6 +45,43 @@ function toTmuxBinary(agent = "") {
44
45
  return "";
45
46
  }
46
47
 
48
+ function applyDefaultManagedBootstrap(projectRoot, normalizedAgent, args = [], extraEnv = {}) {
49
+ const agentType = toBusAgentType(normalizedAgent);
50
+ if (!agentType || agentType === "ufoo-code") {
51
+ return {
52
+ args: Array.isArray(args) ? args.slice() : [],
53
+ extraEnv: extraEnv && typeof extraEnv === "object" ? { ...extraEnv } : {},
54
+ applied: false,
55
+ };
56
+ }
57
+
58
+ const currentArgs = Array.isArray(args) ? args.slice() : [];
59
+ const currentExtraEnv = extraEnv && typeof extraEnv === "object" ? { ...extraEnv } : {};
60
+ const resolved = resolveDefaultManualBootstrap({
61
+ projectRoot,
62
+ agentType,
63
+ args: currentArgs,
64
+ env: {
65
+ ...process.env,
66
+ ...currentExtraEnv,
67
+ },
68
+ });
69
+
70
+ if (!resolved || resolved.mode === "skip") {
71
+ return { args: currentArgs, extraEnv: currentExtraEnv, applied: false };
72
+ }
73
+
74
+ return {
75
+ args: Array.isArray(resolved.args) ? resolved.args : currentArgs,
76
+ extraEnv: {
77
+ ...currentExtraEnv,
78
+ ...(resolved.env && typeof resolved.env === "object" ? resolved.env : {}),
79
+ UFOO_SKIP_DEFAULT_BOOTSTRAP: "1",
80
+ },
81
+ applied: true,
82
+ };
83
+ }
84
+
47
85
  function resolveUfooRunnerPath() {
48
86
  return path.resolve(__dirname, "../../bin/ufoo.js");
49
87
  }
@@ -116,7 +154,7 @@ function resolveHostLaunchContext(options = {}) {
116
154
 
117
155
  function resolveConfiguredLaunchMode(configuredMode = "", options = {}) {
118
156
  const mode = normalizeOptionalString(configuredMode);
119
- if (mode === "internal" || mode === "tmux" || mode === "terminal" || mode === "host") {
157
+ if (mode === "internal" || mode === "internal-pty" || mode === "tmux" || mode === "terminal" || mode === "host") {
120
158
  return mode;
121
159
  }
122
160
  const hostContext = resolveHostLaunchContext(options);
@@ -518,7 +556,9 @@ async function spawnManagedHostAgent(
518
556
  subscriberId = "";
519
557
  }
520
558
 
521
- const args = Array.isArray(extraArgs) ? extraArgs : [];
559
+ const hostBootstrap = applyDefaultManagedBootstrap(projectRoot, normalizedAgent, extraArgs, extraEnv);
560
+ const args = hostBootstrap.args;
561
+ const hostExtraEnv = hostBootstrap.extraEnv;
522
562
  const argText = args.length > 0 ? ` ${args.map(shellEscape).join(" ")}` : "";
523
563
 
524
564
  const titleCmd = buildTitleCmd(nickname);
@@ -538,8 +578,8 @@ async function spawnManagedHostAgent(
538
578
  env.UFOO_NICKNAME = nickname;
539
579
  }
540
580
  // Parse extraEnv string (e.g., "UFOO_UCODE_BOOTSTRAP_FILE=/path/to/file") and add to env
541
- if (extraEnv && typeof extraEnv === "object") {
542
- for (const [key, value] of Object.entries(extraEnv)) {
581
+ if (hostExtraEnv && typeof hostExtraEnv === "object") {
582
+ for (const [key, value] of Object.entries(hostExtraEnv)) {
543
583
  if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(String(key || ""))) {
544
584
  env[String(key)] = String(value ?? "");
545
585
  }
@@ -645,7 +685,9 @@ async function spawnInternalAgent(
645
685
  ? (count > 1 ? `${nickname}-${i + 1}` : nickname)
646
686
  : "";
647
687
  const providerSessionId = typeof options.providerSessionId === "string" ? options.providerSessionId.trim() : "";
648
- const usePty = process.env.UFOO_INTERNAL_PTY !== "0";
688
+ const usePty = typeof options.usePty === "boolean"
689
+ ? options.usePty
690
+ : process.env.UFOO_INTERNAL_PTY !== "0";
649
691
  const launchMode = usePty ? "internal-pty" : "internal";
650
692
 
651
693
  // 传递 launch_mode 和 parent PID 到 join
@@ -657,8 +699,9 @@ async function spawnInternalAgent(
657
699
  const finalNickname = joinResult.nickname || requestedNickname || "";
658
700
  bus.saveBusData();
659
701
 
702
+ const managedBootstrap = applyDefaultManagedBootstrap(projectRoot, normalizedAgent, extraArgs, extraEnv);
660
703
  const runnerCmd = usePty ? "agent-pty-runner" : "agent-runner";
661
- const args = Array.isArray(extraArgs) ? extraArgs : [];
704
+ const args = managedBootstrap.args;
662
705
  const child = spawn(process.execPath, [runner, runnerCmd, agent, ...args], {
663
706
  // 关键改动:不使用 detached,daemon 作为父进程
664
707
  detached: false,
@@ -666,7 +709,7 @@ async function spawnInternalAgent(
666
709
  cwd: projectRoot,
667
710
  env: {
668
711
  ...process.env,
669
- ...(extraEnv && typeof extraEnv === "object" ? extraEnv : {}),
712
+ ...(managedBootstrap.extraEnv && typeof managedBootstrap.extraEnv === "object" ? managedBootstrap.extraEnv : {}),
670
713
  UFOO_INTERNAL_AGENT: "1",
671
714
  UFOO_INTERNAL_PTY: usePty ? "1" : "0",
672
715
  UFOO_SUBSCRIBER_ID: subscriberId, // 直接传递 subscriber ID
@@ -888,7 +931,8 @@ async function launchAgent(projectRoot, agent, count = 1, nickname = "", process
888
931
  throw new Error(`unsupported agent type: ${agent}`);
889
932
  }
890
933
 
891
- if (mode === "internal") {
934
+ if (mode === "internal" || mode === "internal-pty") {
935
+ const usePty = mode === "internal-pty";
892
936
  const result = await spawnInternalAgent(
893
937
  projectRoot,
894
938
  normalizedAgent,
@@ -896,9 +940,10 @@ async function launchAgent(projectRoot, agent, count = 1, nickname = "", process
896
940
  nickname,
897
941
  processManager,
898
942
  launchEnvObject,
899
- extraArgs
943
+ extraArgs,
944
+ { usePty }
900
945
  );
901
- return { mode: "internal", launchScope, subscriberIds: result.subscriberIds };
946
+ return { mode, launchScope, subscriberIds: result.subscriberIds };
902
947
  }
903
948
  if (mode === "tmux") {
904
949
  // Check if tmux is available
@@ -1129,7 +1174,7 @@ async function resumeAgents(projectRoot, target = "", processManager = null) {
1129
1174
  const args = buildResumeArgs(item.agent, sessionId);
1130
1175
  let reused = false;
1131
1176
  let resumedId = item.id;
1132
- if (mode === "internal") {
1177
+ if (mode === "internal" || mode === "internal-pty") {
1133
1178
  // Internal agents have no terminal/pane to reattach. Start a fresh
1134
1179
  // daemon-managed runner and replace the old recoverable registration.
1135
1180
  // The provider session is still reused via the normal provider args.
@@ -1142,7 +1187,7 @@ async function resumeAgents(projectRoot, target = "", processManager = null) {
1142
1187
  processManager,
1143
1188
  { UFOO_SKIP_SESSION_PROBE: "1" },
1144
1189
  args,
1145
- { replaceAgentId: item.id, providerSessionId: sessionId }
1190
+ { replaceAgentId: item.id, providerSessionId: sessionId, usePty: mode === "internal-pty" }
1146
1191
  );
1147
1192
  resumedId = launchResult.subscriberIds && launchResult.subscriberIds[0]
1148
1193
  ? launchResult.subscriberIds[0]