u-foo 1.9.6 → 1.9.8
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/bin/ufoo.js +5 -3
- package/package.json +1 -1
- package/src/agent/cliRunner.js +6 -0
- package/src/agent/internalRunner.js +17 -3
- package/src/agent/ptyRunner.js +8 -7
- package/src/daemon/index.js +31 -9
package/bin/ufoo.js
CHANGED
|
@@ -29,13 +29,15 @@ async function main() {
|
|
|
29
29
|
}
|
|
30
30
|
if (cmd === "agent-runner") {
|
|
31
31
|
const agentType = argv[1] || "codex";
|
|
32
|
-
|
|
32
|
+
const extraArgs = argv.slice(2);
|
|
33
|
+
await runInternalRunner({ projectRoot: process.cwd(), agentType, extraArgs });
|
|
33
34
|
return;
|
|
34
35
|
}
|
|
35
36
|
if (cmd === "agent-pty-runner") {
|
|
36
37
|
const agentType = argv[1] || "codex";
|
|
38
|
+
const extraArgs = argv.slice(2);
|
|
37
39
|
try {
|
|
38
|
-
await runPtyRunner({ projectRoot: process.cwd(), agentType });
|
|
40
|
+
await runPtyRunner({ projectRoot: process.cwd(), agentType, extraArgs });
|
|
39
41
|
} catch (err) {
|
|
40
42
|
const normalized = String(agentType || "").trim().toLowerCase();
|
|
41
43
|
if (normalized === "ufoo" || normalized === "ucode" || normalized === "ufoo-code") {
|
|
@@ -44,7 +46,7 @@ async function main() {
|
|
|
44
46
|
// Fallback to headless runner if PTY is unavailable
|
|
45
47
|
// eslint-disable-next-line no-console
|
|
46
48
|
console.error(`[pty-runner] ${err.message || err}. Falling back to headless internal runner.`);
|
|
47
|
-
await runInternalRunner({ projectRoot: process.cwd(), agentType });
|
|
49
|
+
await runInternalRunner({ projectRoot: process.cwd(), agentType, extraArgs });
|
|
48
50
|
}
|
|
49
51
|
return;
|
|
50
52
|
}
|
package/package.json
CHANGED
package/src/agent/cliRunner.js
CHANGED
|
@@ -484,6 +484,10 @@ const DEFAULT_CODEX = {
|
|
|
484
484
|
|
|
485
485
|
function buildArgs(backend, prompt, opts) {
|
|
486
486
|
const args = [...(backend.args || [])];
|
|
487
|
+
const extraArgs = Array.isArray(opts.extraArgs) ? opts.extraArgs.filter(Boolean) : [];
|
|
488
|
+
if (extraArgs.length > 0) {
|
|
489
|
+
args.push(...extraArgs);
|
|
490
|
+
}
|
|
487
491
|
if (opts.model && backend.modelArg) {
|
|
488
492
|
args.push(backend.modelArg, opts.model);
|
|
489
493
|
}
|
|
@@ -588,6 +592,7 @@ async function runCliAgent(params) {
|
|
|
588
592
|
sessionId,
|
|
589
593
|
systemPrompt: params.systemPrompt,
|
|
590
594
|
disableSession: params.disableSession,
|
|
595
|
+
extraArgs: params.extraArgs,
|
|
591
596
|
});
|
|
592
597
|
if (backend === DEFAULT_CODEX && params.sandbox) {
|
|
593
598
|
applySandboxOverride(args, params.sandbox);
|
|
@@ -642,6 +647,7 @@ async function runCliAgent(params) {
|
|
|
642
647
|
sessionId,
|
|
643
648
|
systemPrompt: params.systemPrompt,
|
|
644
649
|
disableSession: params.disableSession,
|
|
650
|
+
extraArgs: params.extraArgs,
|
|
645
651
|
},
|
|
646
652
|
);
|
|
647
653
|
retryArgs = retry.args;
|
|
@@ -96,7 +96,18 @@ function drainQueue(queueFile) {
|
|
|
96
96
|
return content.split(/\r?\n/).filter(Boolean);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
async function handleEvent(
|
|
99
|
+
async function handleEvent(
|
|
100
|
+
projectRoot,
|
|
101
|
+
agentType,
|
|
102
|
+
provider,
|
|
103
|
+
model,
|
|
104
|
+
subscriber,
|
|
105
|
+
nickname,
|
|
106
|
+
evt,
|
|
107
|
+
cliSessionState,
|
|
108
|
+
busSender,
|
|
109
|
+
extraArgs = []
|
|
110
|
+
) {
|
|
100
111
|
if (!evt || !evt.data || !evt.data.message) return;
|
|
101
112
|
const prompt = evt.data.message;
|
|
102
113
|
const publisher = evt.publisher || "unknown";
|
|
@@ -118,6 +129,7 @@ async function handleEvent(projectRoot, agentType, provider, model, subscriber,
|
|
|
118
129
|
sessionId: cliSessionState.cliSessionId,
|
|
119
130
|
sandbox,
|
|
120
131
|
cwd: projectRoot,
|
|
132
|
+
extraArgs,
|
|
121
133
|
onStreamDelta: emitStreamDelta,
|
|
122
134
|
});
|
|
123
135
|
|
|
@@ -136,6 +148,7 @@ async function handleEvent(projectRoot, agentType, provider, model, subscriber,
|
|
|
136
148
|
sessionId: null, // Let runCliAgent generate new session
|
|
137
149
|
sandbox,
|
|
138
150
|
cwd: projectRoot,
|
|
151
|
+
extraArgs,
|
|
139
152
|
onStreamDelta: emitStreamDelta,
|
|
140
153
|
});
|
|
141
154
|
}
|
|
@@ -175,7 +188,7 @@ async function handleEvent(projectRoot, agentType, provider, model, subscriber,
|
|
|
175
188
|
await busSender.flush();
|
|
176
189
|
}
|
|
177
190
|
|
|
178
|
-
async function runInternalRunner({ projectRoot, agentType = "codex" }) {
|
|
191
|
+
async function runInternalRunner({ projectRoot, agentType = "codex", extraArgs = [] }) {
|
|
179
192
|
// Internal runner 必须由 daemon 启动,UFOO_SUBSCRIBER_ID 应该已经设置
|
|
180
193
|
const { subscriber, agentType: parsedAgentType, sessionId } = parseSubscriberId();
|
|
181
194
|
const nickname = process.env.UFOO_NICKNAME || "";
|
|
@@ -280,7 +293,8 @@ async function runInternalRunner({ projectRoot, agentType = "codex" }) {
|
|
|
280
293
|
nickname,
|
|
281
294
|
evt,
|
|
282
295
|
cliSessionState,
|
|
283
|
-
busSender
|
|
296
|
+
busSender,
|
|
297
|
+
extraArgs
|
|
284
298
|
);
|
|
285
299
|
}
|
|
286
300
|
|
package/src/agent/ptyRunner.js
CHANGED
|
@@ -113,24 +113,25 @@ function buildPrompt(text, marker) {
|
|
|
113
113
|
return `${text}\n\n请在完成后输出以下标记(单独一行):\n${marker}\n`;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
function resolveCommand(agentType) {
|
|
116
|
+
function resolveCommand(agentType, extraArgs = []) {
|
|
117
117
|
const normalizedAgent = String(agentType || "").trim().toLowerCase();
|
|
118
|
+
const extra = Array.isArray(extraArgs) ? extraArgs : [];
|
|
118
119
|
const rawCmd = String(process.env.UFOO_PTY_CMD || "").trim();
|
|
119
120
|
if (rawCmd) {
|
|
120
121
|
const rawArgs = String(process.env.UFOO_PTY_ARGS || "").trim();
|
|
121
122
|
const args = rawArgs ? rawArgs.split(/\s+/).filter(Boolean) : [];
|
|
122
|
-
return { command: rawCmd, args };
|
|
123
|
+
return { command: rawCmd, args: [...args, ...extra] };
|
|
123
124
|
}
|
|
124
125
|
if (normalizedAgent === "claude" || normalizedAgent === "claude-code") {
|
|
125
|
-
return { command: "claude", args: [] };
|
|
126
|
+
return { command: "claude", args: [...extra] };
|
|
126
127
|
}
|
|
127
128
|
if (normalizedAgent === "ufoo" || normalizedAgent === "ucode" || normalizedAgent === "ufoo-code") {
|
|
128
|
-
return { command: "ucode", args: [] };
|
|
129
|
+
return { command: "ucode", args: [...extra] };
|
|
129
130
|
}
|
|
130
|
-
return { command: "codex", args: ["--no-alt-screen", "--sandbox", "workspace-write"] };
|
|
131
|
+
return { command: "codex", args: ["--no-alt-screen", "--sandbox", "workspace-write", ...extra] };
|
|
131
132
|
}
|
|
132
133
|
|
|
133
|
-
async function runPtyRunner({ projectRoot, agentType = "codex" }) {
|
|
134
|
+
async function runPtyRunner({ projectRoot, agentType = "codex", extraArgs = [] }) {
|
|
134
135
|
let pty;
|
|
135
136
|
try {
|
|
136
137
|
// eslint-disable-next-line global-require
|
|
@@ -156,7 +157,7 @@ async function runPtyRunner({ projectRoot, agentType = "codex" }) {
|
|
|
156
157
|
const logFile = path.join(runDir, "pty-runner.log");
|
|
157
158
|
const injectSockPath = path.join(queueDir, "inject.sock");
|
|
158
159
|
|
|
159
|
-
const { command, args } = resolveCommand(agentType);
|
|
160
|
+
const { command, args } = resolveCommand(agentType, extraArgs);
|
|
160
161
|
const env = {
|
|
161
162
|
...process.env,
|
|
162
163
|
UFOO_LAUNCH_MODE: "internal-pty",
|
package/src/daemon/index.js
CHANGED
|
@@ -1342,8 +1342,11 @@ function startDaemon({ projectRoot, provider, model, resumeMode = "auto" }) {
|
|
|
1342
1342
|
: null,
|
|
1343
1343
|
};
|
|
1344
1344
|
let soloLaunchBootstrap = null;
|
|
1345
|
-
if (requestedProfile && normalizedAgent === "ufoo") {
|
|
1346
|
-
const
|
|
1345
|
+
if (requestedProfile && (normalizedAgent === "ufoo" || normalizedAgent === "claude" || normalizedAgent === "codex")) {
|
|
1346
|
+
const agentTypeMap = { ufoo: "ufoo-code", claude: "claude-code", codex: "codex" };
|
|
1347
|
+
const defaultNickMap = { ufoo: "ucode", claude: "claude", codex: "codex" };
|
|
1348
|
+
const agentTypeForBootstrap = agentTypeMap[normalizedAgent];
|
|
1349
|
+
const soloNickname = explicitNickname || defaultNickMap[normalizedAgent];
|
|
1347
1350
|
const profileResult = resolveSoloPromptProfile(projectRoot, requestedProfile);
|
|
1348
1351
|
if (!profileResult.ok) {
|
|
1349
1352
|
socket.write(
|
|
@@ -1357,17 +1360,36 @@ function startDaemon({ projectRoot, provider, model, resumeMode = "auto" }) {
|
|
|
1357
1360
|
}
|
|
1358
1361
|
const built = buildSoloBootstrap({
|
|
1359
1362
|
nickname: soloNickname,
|
|
1360
|
-
agentType:
|
|
1363
|
+
agentType: agentTypeForBootstrap,
|
|
1361
1364
|
requestedProfile: profileResult.requested_profile,
|
|
1362
1365
|
profile: profileResult.profile,
|
|
1363
1366
|
});
|
|
1364
1367
|
if (built.required) {
|
|
1365
1368
|
try {
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1369
|
+
if (normalizedAgent === "ufoo") {
|
|
1370
|
+
// ucode: bootstrap via env var pointing to file
|
|
1371
|
+
const prepared = prepareSoloUcodeBootstrap(projectRoot, soloNickname, built.promptText);
|
|
1372
|
+
op.extra_env = {
|
|
1373
|
+
...(op.extra_env && typeof op.extra_env === "object" ? op.extra_env : {}),
|
|
1374
|
+
UFOO_UCODE_BOOTSTRAP_FILE: prepared.file,
|
|
1375
|
+
};
|
|
1376
|
+
} else if (normalizedAgent === "claude") {
|
|
1377
|
+
// claude-code: bootstrap via --append-system-prompt file
|
|
1378
|
+
const bootstrapDir = path.join(getUfooPaths(projectRoot).agentDir, "claude-code", "solo");
|
|
1379
|
+
fs.mkdirSync(bootstrapDir, { recursive: true });
|
|
1380
|
+
const bootstrapFile = path.join(bootstrapDir, `${soloNickname}.bootstrap.md`);
|
|
1381
|
+
fs.writeFileSync(bootstrapFile, built.promptText, "utf8");
|
|
1382
|
+
op.extra_args = [
|
|
1383
|
+
...(Array.isArray(op.extra_args) ? op.extra_args : []),
|
|
1384
|
+
"--append-system-prompt", bootstrapFile,
|
|
1385
|
+
];
|
|
1386
|
+
} else if (normalizedAgent === "codex") {
|
|
1387
|
+
// codex: bootstrap via initial prompt argument
|
|
1388
|
+
op.extra_args = [
|
|
1389
|
+
...(Array.isArray(op.extra_args) ? op.extra_args : []),
|
|
1390
|
+
built.promptText,
|
|
1391
|
+
];
|
|
1392
|
+
}
|
|
1371
1393
|
soloLaunchBootstrap = {
|
|
1372
1394
|
requested_profile: profileResult.requested_profile,
|
|
1373
1395
|
resolved_profile: profileResult.profile.id,
|
|
@@ -1377,7 +1399,7 @@ function startDaemon({ projectRoot, provider, model, resumeMode = "auto" }) {
|
|
|
1377
1399
|
socket.write(
|
|
1378
1400
|
`${JSON.stringify({
|
|
1379
1401
|
type: IPC_RESPONSE_TYPES.ERROR,
|
|
1380
|
-
error: err.message || "failed to prepare
|
|
1402
|
+
error: err.message || "failed to prepare solo bootstrap",
|
|
1381
1403
|
})}
|
|
1382
1404
|
`,
|
|
1383
1405
|
);
|