@kw-yeh/vibeflow 4.11.36 → 4.11.39
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/README.md +1 -1
- package/dist/vibeflow.mjs +264 -112
- package/dist/web/404/index.html +1 -1
- package/dist/web/404.html +1 -1
- package/dist/web/_next/static/{wFlo60T-hKTrS3FBCZ5OJ → 7PoSgDqLcXreA4Amg4KCd}/_buildManifest.js +1 -1
- package/dist/web/_next/static/chunks/{6646-4e91d829d8130f2c.js → 5174-9f90ae432131a522.js} +2 -2
- package/dist/web/_next/static/chunks/pages/home-e9b4955fe2fcbdc3.js +13 -0
- package/dist/web/_next/static/css/07822becd778a410.css +2 -0
- package/dist/web/home/index.html +1 -1
- package/package.json +1 -1
- package/dist/web/_next/static/chunks/pages/home-3cfd14b77313e75b.js +0 -13
- package/dist/web/_next/static/css/1b8cc89c93b78db0.css +0 -2
- /package/dist/web/_next/static/{wFlo60T-hKTrS3FBCZ5OJ → 7PoSgDqLcXreA4Amg4KCd}/_ssgManifest.js +0 -0
package/dist/vibeflow.mjs
CHANGED
|
@@ -168,8 +168,8 @@ function shellArgs(shell, command) {
|
|
|
168
168
|
const isPosixShell = process.platform !== "win32" || shell.toLowerCase().endsWith("bash.exe");
|
|
169
169
|
if (isPosixShell) return command ? ["-lic", command] : ["-l"];
|
|
170
170
|
if (command) {
|
|
171
|
-
const
|
|
172
|
-
return ["-NoProfile", "-NonInteractive", "-Command", `Write-Host '${
|
|
171
|
+
const message2 = GIT_BASH_MISSING_MESSAGE.replace(/'/g, "''");
|
|
172
|
+
return ["-NoProfile", "-NonInteractive", "-Command", `Write-Host '${message2}' -ForegroundColor Yellow; exit 1`];
|
|
173
173
|
}
|
|
174
174
|
return ["-NoProfile"];
|
|
175
175
|
}
|
|
@@ -637,7 +637,8 @@ function masterSystemPrompt(opts) {
|
|
|
637
637
|
"1. \u5224\u65B7\uFF1A\u4E00\u5F35\u5361\u505A\u5F97\u5B8C\u5C31\u53EA\u5EFA\u4E00\u5F35\uFF1B\u6D89\u53CA\u591A\u500B repo \u6216\u53EF\u5E73\u884C\u7684\u7368\u7ACB\u5DE5\u4F5C\u624D\u62C6\u6210\u591A\u5F35\u3002\u6BCF\u5F35\u53EA\u52D5\u4E00\u500B repo\uFF0C\u5404\u81EA\u80FD\u7368\u7ACB\u9A57\u6536\u3002",
|
|
638
638
|
'2. \u6D3E\u5DE5\uFF1AVF task create --store-path "$VIBEFLOW_STORE_DIR" --master "$VIBEFLOW_TASK_ID" --project <repo \u7D55\u5C0D\u8DEF\u5F91> --title <\u6A19\u984C> --prompt <\u5167\u5BB9>',
|
|
639
639
|
" prompt \u5FC5\u9808\u81EA\u5305\u542B\uFF1A\u80CC\u666F\u3001\u7BC4\u570D\u3001\u9A57\u6536\u689D\u4EF6\u3001\u8207\u5176\u4ED6\u5361\u7684\u4ECB\u9762\u7D04\u5B9A\u2014\u2014slave \u770B\u4E0D\u5230\u4F60\u7684\u5C0D\u8A71\u3002",
|
|
640
|
-
" \
|
|
640
|
+
" \u6A19\u984C\u8981\u77ED\u3001\u5F7C\u6B64\u4E00\u773C\u5206\u5F97\u51FA\u4F86\uFF1A\u4EE5\u9019\u5F35\u5361\u8CA0\u8CAC\u7684\u90E8\u5206\u958B\u982D\uFF08\u4F8B\u5982\u300C\u5F8C\u7AEF\uFF1A\u2026\u300D\u300C\u9A57\u6536\uFF1A\u2026\u300D\uFF09\uFF0C\u4E0D\u8981\u8B93\u591A\u5F35\u5361\u5171\u7528\u540C\u4E00\u6BB5\u958B\u982D\u3002",
|
|
641
|
+
" \u9810\u8A2D\u4E0D\u8981\u52A0 --model / --effort\uFF1A\u6C92\u6307\u5B9A\u6642 Jev \u6703\u4F9D\u4EFB\u52D9\u8907\u96DC\u5EA6\u6311\u6A21\u578B\u8207 effort\uFF1B\u53EA\u6709\u4EFB\u52D9\u660E\u78BA\u9700\u8981\u7279\u5B9A\u6A21\u578B\u6216 effort \u6642\u624D\u6307\u5B9A\u3002\u9700\u8981\u6642\u53EF\u52A0 --agent / --base-branch\u3002"
|
|
641
642
|
);
|
|
642
643
|
lines.push(
|
|
643
644
|
opts.autoMode ? '3. \u555F\u52D5\uFF1A\u6C92\u6709\u524D\u7F6E\u4F9D\u8CF4\u7684\u5361\u76F4\u63A5 VF task start --store-path "$VIBEFLOW_STORE_DIR" --task <id>\uFF1B\u6709\u4F9D\u8CF4\u7684\u5148\u7559\u5728 Backlog\uFF0C\u524D\u7F6E\u5361\u5B8C\u6210\u5F8C\u518D\u555F\u52D5\u3002' : "3. \u555F\u52D5\uFF1A\u4E0D\u8981\u81EA\u5DF1\u555F\u52D5\u5361\u7247\u3002\u5217\u51FA\u4F60\u5EFA\u4E86\u54EA\u4E9B\u5361\u3001\u5EFA\u8B70\u7684\u555F\u52D5\u9806\u5E8F\uFF0C\u7B49\u4F7F\u7528\u8005\u5728 VibeFlow \u6309\u958B\u59CB\u3002"
|
|
@@ -649,16 +650,21 @@ function masterSystemPrompt(opts) {
|
|
|
649
650
|
" \u9700\u8981\u7368\u7ACB\u9A57\u6536\u6642\u53E6\u958B\u4E00\u5F35\u9A57\u6536\u5361\u3002\u9A57\u6536\u56DE\u5831\u554F\u984C\u6642\uFF0C\u628A\u5177\u9AD4\u554F\u984C\u8207\u91CD\u73FE\u6B65\u9A5F\u6574\u7406\u597D\u8F49\u7D66\u8CA0\u8CAC\u958B\u767C\u7684\u5361\u4FEE\u6B63\uFF0C\u4FEE\u5B8C\u518D\u8ACB\u9A57\u6536\u5361\u8907\u9A57\uFF0C\u76F4\u5230\u901A\u904E\u3002",
|
|
650
651
|
" task send \u56DE TARGET_BLOCKED \u4EE3\u8868\u5C0D\u65B9\u5361\u5728\u6B0A\u9650\u78BA\u8A8D\uFF0C\u8ACB\u4F7F\u7528\u8005\u5230\u90A3\u5F35\u5361\u8655\u7406\u3002",
|
|
651
652
|
"6. PR\uFF1A\u9A57\u6536\u901A\u904E\u5F8C\uFF0C\u4EA4\u4EE3\u958B\u767C\u5361\u7528 pr skill \u958B PR\uFF08\u74B0\u5883\u88E1\u6C92\u6709\u9019\u500B skill \u5C31\u7528 gh pr create\uFF09\uFF0C\u4E26\u56DE\u5831 PR \u9023\u7D50\u7D66\u4F60\u3002",
|
|
652
|
-
"7. \u4F7F\u7528\u8005\u4E3B\u8981\u53EA\u8DDF\u4F60\u6E9D\u901A\uFF1A\u4E3B\u52D5\u5411\u4F7F\u7528\u8005\u56DE\u5831\u6574\u9AD4\u9032\u5EA6\u8207\u9700\u8981\u4F7F\u7528\u8005\u6C7A\u5B9A\u7684\u4E8B\u3002\u4F60\u4E0D\u6703\u628A\u5361\u7247\u79FB\u5230 Done\u3001\u4E0D\u6703\u5408\u4F75 PR\uFF1B\u5168\u90E8\u5B8C\u6210\u5F8C\u6574\u7406\u6BCF\u5F35\u5361\u7684\u7D50\u679C\u8207 PR \u9023\u7D50\uFF0C\u4EA4\u7D66\u4F7F\u7528\u8005\u505A\u6700\u5F8C\u78BA\u8A8D\u3002"
|
|
653
|
+
"7. \u4F7F\u7528\u8005\u4E3B\u8981\u53EA\u8DDF\u4F60\u6E9D\u901A\uFF1A\u4E3B\u52D5\u5411\u4F7F\u7528\u8005\u56DE\u5831\u6574\u9AD4\u9032\u5EA6\u8207\u9700\u8981\u4F7F\u7528\u8005\u6C7A\u5B9A\u7684\u4E8B\u3002\u4F60\u4E0D\u6703\u628A\u5361\u7247\u79FB\u5230 Done\u3001\u4E0D\u6703\u5408\u4F75 PR\uFF1B\u5168\u90E8\u5B8C\u6210\u5F8C\u6574\u7406\u6BCF\u5F35\u5361\u7684\u7D50\u679C\u8207 PR \u9023\u7D50\uFF0C\u4EA4\u7D66\u4F7F\u7528\u8005\u505A\u6700\u5F8C\u78BA\u8A8D\u3002",
|
|
654
|
+
" \u8DDF\u4F7F\u7528\u8005\u63D0\u5230\u4EFB\u4F55\u4E00\u5F35\u5361\u6642\uFF0C\u4E00\u5F8B\u5BEB\u6210 <id>\u300C<\u6A19\u984C>\u300D\u2014\u2014\u5361\u7247\u4E0A\u770B\u5F97\u5230 id\uFF0C\u4F7F\u7528\u8005\u9760\u5B83\u5C0D\u4E0A\u662F\u54EA\u4E00\u5F35\u3002"
|
|
653
655
|
);
|
|
654
656
|
return lines.join("\n");
|
|
655
657
|
}
|
|
656
|
-
function buildPrompt(task) {
|
|
658
|
+
function buildPrompt(task, preface) {
|
|
657
659
|
const lines = [`\u4EFB\u52D9\u6A19\u984C\uFF1A${task.title}`];
|
|
658
660
|
const description = task.description?.trim();
|
|
659
661
|
if (description) {
|
|
660
662
|
lines.push("", "\u4EFB\u52D9\u63CF\u8FF0\uFF1A", description);
|
|
661
663
|
}
|
|
664
|
+
const context = preface?.context.trim();
|
|
665
|
+
if (preface && context) {
|
|
666
|
+
lines.push("", `\u524D\u7F6E\u5206\u6790\uFF08${preface.model}\uFF0C\u50C5\u4F9B\u53C3\u8003\uFF09\uFF1A`, context);
|
|
667
|
+
}
|
|
662
668
|
return lines.join("\n");
|
|
663
669
|
}
|
|
664
670
|
function executorSessionId(taskId, runId) {
|
|
@@ -716,9 +722,9 @@ function buildAgentCommand(task, systemPrompt, opts, workspacePath) {
|
|
|
716
722
|
const custom = resolveSystemPrompt(systemPrompt);
|
|
717
723
|
const canWrite = Boolean(opts?.boardCli?.cliPath);
|
|
718
724
|
const role = task.role === "master" ? masterSystemPrompt({ canWrite, autoMode: opts?.autoMode === true }) : task.masterId ? slaveSystemPrompt({ canWrite }) : null;
|
|
719
|
-
const sys = role ? [custom, role].filter(Boolean).join("\n\n") : custom;
|
|
725
|
+
const sys = task.masterId && task.role !== "master" ? role ?? "" : role ? [custom, role].filter(Boolean).join("\n\n") : custom;
|
|
720
726
|
const includeTaskPrompt = opts?.includeTaskPrompt !== false;
|
|
721
|
-
const prompt = includeTaskPrompt && !opts?.resume ? buildPrompt(task) : "";
|
|
727
|
+
const prompt = includeTaskPrompt && !opts?.resume ? buildPrompt(task, opts?.preface) : "";
|
|
722
728
|
const sessionId = agent === "claude" && includeTaskPrompt ? executorSessionId(task.id, task.runId) : void 0;
|
|
723
729
|
return boardEnvPrefix(task, opts, workspacePath) + assembleCommand(
|
|
724
730
|
agent,
|
|
@@ -984,13 +990,13 @@ function reduceClaudeLine(state, line) {
|
|
|
984
990
|
if (!entry) return state;
|
|
985
991
|
const at = parseTime(entry.timestamp);
|
|
986
992
|
const next = { ...state, startedAt: state.startedAt ?? at };
|
|
987
|
-
const
|
|
988
|
-
const content = Array.isArray(
|
|
989
|
-
if (entry.type === "assistant" &&
|
|
990
|
-
const usage =
|
|
991
|
-
if (usage && typeof
|
|
993
|
+
const message2 = entry.message;
|
|
994
|
+
const content = Array.isArray(message2?.content) ? message2.content : [];
|
|
995
|
+
if (entry.type === "assistant" && message2) {
|
|
996
|
+
const usage = message2.usage;
|
|
997
|
+
if (usage && typeof message2.id === "string") {
|
|
992
998
|
const u = claudeUsage(usage);
|
|
993
|
-
next.usageById = { ...state.usageById, [
|
|
999
|
+
next.usageById = { ...state.usageById, [message2.id]: u };
|
|
994
1000
|
next.contextTokens = u.input + u.cacheRead + u.cacheWrite;
|
|
995
1001
|
}
|
|
996
1002
|
let tool;
|
|
@@ -1006,11 +1012,11 @@ function reduceClaudeLine(state, line) {
|
|
|
1006
1012
|
}
|
|
1007
1013
|
}
|
|
1008
1014
|
if (tool) next.activity = { state: "working", tool, at };
|
|
1009
|
-
else if (
|
|
1015
|
+
else if (message2.stop_reason === "end_turn") next.activity = { state: "waiting", waitingFor: "input", at };
|
|
1010
1016
|
else next.activity = { state: "working", at };
|
|
1011
1017
|
return next;
|
|
1012
1018
|
}
|
|
1013
|
-
if (entry.type === "user" &&
|
|
1019
|
+
if (entry.type === "user" && message2) {
|
|
1014
1020
|
const result = entry.toolUseResult && typeof entry.toolUseResult === "object" ? entry.toolUseResult : void 0;
|
|
1015
1021
|
let pending = next.pendingTasks;
|
|
1016
1022
|
for (const block of content) {
|
|
@@ -1340,7 +1346,7 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
1340
1346
|
const [focus, setFocus] = useState(initialFocus);
|
|
1341
1347
|
const [editing, setEditing] = useState(null);
|
|
1342
1348
|
const [draft, setDraft] = useState("");
|
|
1343
|
-
const [
|
|
1349
|
+
const [message2, setMessage] = useState(initialMessage ?? "");
|
|
1344
1350
|
const [busy, setBusy] = useState(null);
|
|
1345
1351
|
const [loadingGit, setLoadingGit] = useState(false);
|
|
1346
1352
|
const [confirmLeave, setConfirmLeave] = useState(false);
|
|
@@ -1559,7 +1565,7 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
1559
1565
|
)
|
|
1560
1566
|
),
|
|
1561
1567
|
extra ? h(Text, { dimColor: true }, ` ${extra}`) : null,
|
|
1562
|
-
confirmLeave ? h(Text, { color: "yellow" }, "\u6709\u672A\u5132\u5B58\u7684\u8B8A\u66F4\uFF0C\u78BA\u5B9A\u8981\u96E2\u958B\uFF1F\uFF08y/n\uFF09") :
|
|
1568
|
+
confirmLeave ? h(Text, { color: "yellow" }, "\u6709\u672A\u5132\u5B58\u7684\u8B8A\u66F4\uFF0C\u78BA\u5B9A\u8981\u96E2\u958B\uFF1F\uFF08y/n\uFF09") : message2 ? h(Text, { color: "yellow" }, message2) : h(Text, { dimColor: true }, hint)
|
|
1563
1569
|
);
|
|
1564
1570
|
}
|
|
1565
1571
|
function showForm(api, ctx, initial, pristine, initialFocus = 0, initialMessage) {
|
|
@@ -1700,7 +1706,7 @@ function BoardView({ opts, initial, initialMessage, onAction }) {
|
|
|
1700
1706
|
const [sel, setSel] = useState2(initial);
|
|
1701
1707
|
const [running, setRunning] = useState2(/* @__PURE__ */ new Set());
|
|
1702
1708
|
const [backend, setBackend] = useState2("pty");
|
|
1703
|
-
const [
|
|
1709
|
+
const [message2, setMessage] = useState2(initialMessage ?? "");
|
|
1704
1710
|
const [confirm, setConfirm] = useState2(null);
|
|
1705
1711
|
const [help, setHelp] = useState2(false);
|
|
1706
1712
|
const [progress, setProgress] = useState2({});
|
|
@@ -1911,7 +1917,7 @@ function BoardView({ opts, initial, initialMessage, onAction }) {
|
|
|
1911
1917
|
Box2,
|
|
1912
1918
|
{ flexDirection: "column" },
|
|
1913
1919
|
h2(Box2, { flexDirection: "row" }, ...columns),
|
|
1914
|
-
confirm ? h2(Text2, { color: "yellow" }, confirm.prompt) :
|
|
1920
|
+
confirm ? h2(Text2, { color: "yellow" }, confirm.prompt) : message2 ? h2(Text2, { color: "yellow" }, message2) : h2(
|
|
1915
1921
|
Text2,
|
|
1916
1922
|
{ dimColor: true },
|
|
1917
1923
|
`h/l \u5207\u6B04 \xB7 j/k \u9078\u5361 \xB7 H/L \u79FB\u52D5 \xB7 Enter \u7D42\u7AEF \xB7 n \u65B0\u589E \xB7 e \u7DE8\u8F2F \xB7 d diff \xB7 w Web \xB7 ? \u8AAA\u660E \xB7 q \u96E2\u958B [${backend}]`
|
|
@@ -2035,24 +2041,24 @@ async function runForm(opts, action) {
|
|
|
2035
2041
|
}
|
|
2036
2042
|
async function runTui(opts) {
|
|
2037
2043
|
let sel = { column: 1, index: 0 };
|
|
2038
|
-
let
|
|
2044
|
+
let message2;
|
|
2039
2045
|
for (; ; ) {
|
|
2040
|
-
const result = await showBoard(opts, sel,
|
|
2046
|
+
const result = await showBoard(opts, sel, message2);
|
|
2041
2047
|
sel = result.sel;
|
|
2042
|
-
|
|
2048
|
+
message2 = void 0;
|
|
2043
2049
|
const { action } = result;
|
|
2044
2050
|
if (action.type === "quit") return;
|
|
2045
2051
|
try {
|
|
2046
|
-
if (action.type === "attach")
|
|
2052
|
+
if (action.type === "attach") message2 = await openTerminal(opts, action.task);
|
|
2047
2053
|
else if (action.type === "diff") showDiff(action.task);
|
|
2048
2054
|
else {
|
|
2049
2055
|
process.stdout.write(CLEAR_SCREEN);
|
|
2050
2056
|
const done = await runForm(opts, action);
|
|
2051
|
-
|
|
2057
|
+
message2 = done.message;
|
|
2052
2058
|
if (done.sel) sel = done.sel;
|
|
2053
2059
|
}
|
|
2054
2060
|
} catch (err) {
|
|
2055
|
-
|
|
2061
|
+
message2 = `\u5931\u6557\uFF1A${err.message}`;
|
|
2056
2062
|
}
|
|
2057
2063
|
process.stdout.write(CLEAR_SCREEN);
|
|
2058
2064
|
}
|
|
@@ -2650,7 +2656,7 @@ function createBridge(t) {
|
|
|
2650
2656
|
restoreBuiltinSkill: (payload) => t.invoke("library:restoreBuiltin", payload),
|
|
2651
2657
|
/** Shipped skills the user deleted, offered for restore. */
|
|
2652
2658
|
listRemovedBuiltinSkills: () => t.invoke("library:removedBuiltins"),
|
|
2653
|
-
approve: (taskId,
|
|
2659
|
+
approve: (taskId, message2) => t.invoke("git:approve", { taskId, message: message2 }),
|
|
2654
2660
|
/** Use the task's agent CLI to generate a commit message for branch changes. */
|
|
2655
2661
|
generateCommitMessage: (taskId) => t.invoke("git:generateCommitMessage", taskId),
|
|
2656
2662
|
/** Check whether a PR exists for the task's branch. */
|
|
@@ -4231,11 +4237,11 @@ async function getWorktreeDiff(worktreePath, baseBranch) {
|
|
|
4231
4237
|
}
|
|
4232
4238
|
return files;
|
|
4233
4239
|
}
|
|
4234
|
-
async function commitAndPush(worktreePath,
|
|
4240
|
+
async function commitAndPush(worktreePath, message2) {
|
|
4235
4241
|
await git(worktreePath, ["add", "-A"]);
|
|
4236
4242
|
let committed = false;
|
|
4237
4243
|
try {
|
|
4238
|
-
await git(worktreePath, ["commit", "-m",
|
|
4244
|
+
await git(worktreePath, ["commit", "-m", message2]);
|
|
4239
4245
|
committed = true;
|
|
4240
4246
|
} catch {
|
|
4241
4247
|
committed = false;
|
|
@@ -4247,7 +4253,7 @@ async function commitAndPush(worktreePath, message) {
|
|
|
4247
4253
|
} catch {
|
|
4248
4254
|
pushed = false;
|
|
4249
4255
|
}
|
|
4250
|
-
return { committed, pushed, message };
|
|
4256
|
+
return { committed, pushed, message: message2 };
|
|
4251
4257
|
}
|
|
4252
4258
|
var MAX_OUTCOME_COMMITS = 50;
|
|
4253
4259
|
var OUTCOME_LOG_FORMAT = "%h%x00%s";
|
|
@@ -4451,8 +4457,8 @@ init_attachments();
|
|
|
4451
4457
|
function mastersRoot(storeFile) {
|
|
4452
4458
|
return path13.join(path13.dirname(storeFile), "masters");
|
|
4453
4459
|
}
|
|
4454
|
-
function taskError(
|
|
4455
|
-
return Object.assign(new Error(
|
|
4460
|
+
function taskError(message2, code2) {
|
|
4461
|
+
return Object.assign(new Error(message2), { code: code2 });
|
|
4456
4462
|
}
|
|
4457
4463
|
function assertMasterRef(board, masterId, taskId) {
|
|
4458
4464
|
const master = Object.values(board).flat().find((t) => t.id === masterId);
|
|
@@ -4731,8 +4737,8 @@ function createWsTransport(options) {
|
|
|
4731
4737
|
function dispatch(channel, payload) {
|
|
4732
4738
|
for (const cb of Array.from(listeners.get(channel) ?? [])) cb(payload);
|
|
4733
4739
|
}
|
|
4734
|
-
function post(
|
|
4735
|
-
const data = JSON.stringify(
|
|
4740
|
+
function post(message2) {
|
|
4741
|
+
const data = JSON.stringify(message2);
|
|
4736
4742
|
if (socket && socket.readyState === OPEN) socket.send(data);
|
|
4737
4743
|
else queue.push(data);
|
|
4738
4744
|
}
|
|
@@ -4870,13 +4876,13 @@ Examples:
|
|
|
4870
4876
|
`.trim();
|
|
4871
4877
|
var CliFailure = class extends Error {
|
|
4872
4878
|
code;
|
|
4873
|
-
constructor(code2,
|
|
4874
|
-
super(
|
|
4879
|
+
constructor(code2, message2) {
|
|
4880
|
+
super(message2);
|
|
4875
4881
|
this.code = code2;
|
|
4876
4882
|
}
|
|
4877
4883
|
};
|
|
4878
|
-
function fail(code2,
|
|
4879
|
-
throw new CliFailure(code2,
|
|
4884
|
+
function fail(code2, message2) {
|
|
4885
|
+
throw new CliFailure(code2, message2);
|
|
4880
4886
|
}
|
|
4881
4887
|
function requireOneOf(flag, value, allowed) {
|
|
4882
4888
|
if (value !== void 0 && !allowed.includes(value)) {
|
|
@@ -5615,10 +5621,10 @@ function spawnJsonLines(bin, args, opts) {
|
|
|
5615
5621
|
failure = err;
|
|
5616
5622
|
for (const w of waiters.splice(0)) w.reject(err);
|
|
5617
5623
|
};
|
|
5618
|
-
const deliver = (
|
|
5619
|
-
const i = waiters.findIndex((w) => w.match(
|
|
5620
|
-
if (i === -1) inbox.push(
|
|
5621
|
-
else waiters.splice(i, 1)[0].resolve(
|
|
5624
|
+
const deliver = (message2) => {
|
|
5625
|
+
const i = waiters.findIndex((w) => w.match(message2));
|
|
5626
|
+
if (i === -1) inbox.push(message2);
|
|
5627
|
+
else waiters.splice(i, 1)[0].resolve(message2);
|
|
5622
5628
|
};
|
|
5623
5629
|
let buffered = "";
|
|
5624
5630
|
proc.stdout.setEncoding("utf8");
|
|
@@ -5629,13 +5635,13 @@ function spawnJsonLines(bin, args, opts) {
|
|
|
5629
5635
|
const line = buffered.slice(0, nl).trim();
|
|
5630
5636
|
buffered = buffered.slice(nl + 1);
|
|
5631
5637
|
if (!line) continue;
|
|
5632
|
-
let
|
|
5638
|
+
let message2;
|
|
5633
5639
|
try {
|
|
5634
|
-
|
|
5640
|
+
message2 = JSON.parse(line);
|
|
5635
5641
|
} catch {
|
|
5636
5642
|
continue;
|
|
5637
5643
|
}
|
|
5638
|
-
deliver(
|
|
5644
|
+
deliver(message2);
|
|
5639
5645
|
}
|
|
5640
5646
|
});
|
|
5641
5647
|
proc.stderr.setEncoding("utf8");
|
|
@@ -5672,8 +5678,8 @@ function spawnJsonLines(bin, args, opts) {
|
|
|
5672
5678
|
}, opts.timeoutMs);
|
|
5673
5679
|
let graceTimer;
|
|
5674
5680
|
return {
|
|
5675
|
-
send(
|
|
5676
|
-
if (!failure) proc.stdin.write(`${JSON.stringify(
|
|
5681
|
+
send(message2) {
|
|
5682
|
+
if (!failure) proc.stdin.write(`${JSON.stringify(message2)}
|
|
5677
5683
|
`);
|
|
5678
5684
|
},
|
|
5679
5685
|
next(match) {
|
|
@@ -5706,11 +5712,11 @@ function openClaude() {
|
|
|
5706
5712
|
function isRecord(value) {
|
|
5707
5713
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5708
5714
|
}
|
|
5709
|
-
function isOurResponse(
|
|
5710
|
-
return isRecord(
|
|
5715
|
+
function isOurResponse(message2) {
|
|
5716
|
+
return isRecord(message2) && message2.type === "control_response" && isRecord(message2.response) && message2.response.request_id === REQUEST_ID;
|
|
5711
5717
|
}
|
|
5712
|
-
function parseClaudeInitialize(
|
|
5713
|
-
const outer = isRecord(
|
|
5718
|
+
function parseClaudeInitialize(message2) {
|
|
5719
|
+
const outer = isRecord(message2) && isRecord(message2.response) ? message2.response : null;
|
|
5714
5720
|
if (outer?.subtype === "error") throw new Error(`claude refused the handshake: ${String(outer.error ?? "unknown error")}`);
|
|
5715
5721
|
const body = outer && isRecord(outer.response) ? outer.response : null;
|
|
5716
5722
|
if (!body || !Array.isArray(body.models)) throw new Error("claude handshake has no models array");
|
|
@@ -5771,12 +5777,12 @@ function openCodex() {
|
|
|
5771
5777
|
function isRecord2(value) {
|
|
5772
5778
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5773
5779
|
}
|
|
5774
|
-
var responseTo = (id) => (
|
|
5775
|
-
function resultOf(
|
|
5776
|
-
if (!isRecord2(
|
|
5777
|
-
if (isRecord2(
|
|
5778
|
-
if (!isRecord2(
|
|
5779
|
-
return
|
|
5780
|
+
var responseTo = (id) => (message2) => isRecord2(message2) && message2.id === id && ("result" in message2 || "error" in message2);
|
|
5781
|
+
function resultOf(message2, method) {
|
|
5782
|
+
if (!isRecord2(message2)) throw new Error(`codex ${method}: malformed response`);
|
|
5783
|
+
if (isRecord2(message2.error)) throw new Error(`codex ${method}: ${String(message2.error.message ?? "request failed")}`);
|
|
5784
|
+
if (!isRecord2(message2.result)) throw new Error(`codex ${method}: response has no result`);
|
|
5785
|
+
return message2.result;
|
|
5780
5786
|
}
|
|
5781
5787
|
function isCodexSignedIn(result) {
|
|
5782
5788
|
return result.account != null || result.requiresOpenaiAuth === false;
|
|
@@ -5939,53 +5945,175 @@ init_effort();
|
|
|
5939
5945
|
init_launch();
|
|
5940
5946
|
var API_URL = "https://api.typesafe.ai/v1/systemone";
|
|
5941
5947
|
var MAX_TASK_CHARS = 12e3;
|
|
5948
|
+
var MAX_CONTEXT_CHARS = 8e3;
|
|
5949
|
+
var SCOUT_TIMEOUT_MS = 5 * 6e4;
|
|
5950
|
+
var SAFE_MODEL_ID = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
5951
|
+
function tier(model, agent) {
|
|
5952
|
+
const name = `${model.id} ${model.label}`.toLowerCase();
|
|
5953
|
+
if (/haiku|mini|nano|luna|flash/.test(name)) return 0;
|
|
5954
|
+
if (/opus|fable|astra|pro\b/.test(name)) return 2;
|
|
5955
|
+
if (agent === "codex" && /gpt-5\.5|gpt-5\.4(?!-mini)/.test(name)) return 2;
|
|
5956
|
+
return 1;
|
|
5957
|
+
}
|
|
5958
|
+
var TIER_LABELS = ["lowest cost", "balanced", "highest capability"];
|
|
5959
|
+
function routeCandidates(agent, models) {
|
|
5960
|
+
const byTier = /* @__PURE__ */ new Map();
|
|
5961
|
+
for (const model of models) {
|
|
5962
|
+
if (!SAFE_MODEL_ID.test(model.id) || model.id === "default") continue;
|
|
5963
|
+
const rank = tier(model, agent);
|
|
5964
|
+
if (!byTier.has(rank)) byTier.set(rank, model);
|
|
5965
|
+
}
|
|
5966
|
+
return [...byTier.entries()].sort(([a], [b]) => a - b).map(([, model]) => model);
|
|
5967
|
+
}
|
|
5968
|
+
function isChoice(value) {
|
|
5969
|
+
return !!value && typeof value === "object" && value.type === "choice" && typeof value.choice === "string";
|
|
5970
|
+
}
|
|
5971
|
+
var defaultScout = (agent, model, effort, prompt, cwd) => {
|
|
5972
|
+
const args = agent === "claude" ? ["-p", "--model", model, "--permission-mode", "plan", ...effort ? ["--effort", effort] : []] : [
|
|
5973
|
+
"exec",
|
|
5974
|
+
"--model",
|
|
5975
|
+
model,
|
|
5976
|
+
...effort ? ["-c", `model_reasoning_effort=${effort}`] : [],
|
|
5977
|
+
"--sandbox",
|
|
5978
|
+
"read-only",
|
|
5979
|
+
"--skip-git-repo-check",
|
|
5980
|
+
"-"
|
|
5981
|
+
];
|
|
5982
|
+
return runAgentPrint(agent, args, prompt, { cwd, timeout: SCOUT_TIMEOUT_MS, maxBuffer: 128 * 1024 });
|
|
5983
|
+
};
|
|
5942
5984
|
function createJevRouter(opts = {}) {
|
|
5943
5985
|
const getApiKey = opts.getApiKey ?? (() => opts.apiKey ?? process.env.TYPESAFE_API_KEY?.trim());
|
|
5944
5986
|
const fetcher = opts.fetcher ?? fetch;
|
|
5987
|
+
const scout = opts.scout ?? defaultScout;
|
|
5988
|
+
async function ask(state, questions) {
|
|
5989
|
+
const apiKey = getApiKey();
|
|
5990
|
+
if (!apiKey) throw new Error("\u672A\u8A2D\u5B9A Jev API key\uFF08\u53EF\u5728\u8A2D\u5B9A\u4E2D\u8F38\u5165\u6216\u63D0\u4F9B TYPESAFE_API_KEY\uFF09");
|
|
5991
|
+
const response = await fetcher(API_URL, {
|
|
5992
|
+
method: "POST",
|
|
5993
|
+
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
5994
|
+
body: JSON.stringify({ model: "jev-latest", state, questions }),
|
|
5995
|
+
signal: AbortSignal.timeout(15e3)
|
|
5996
|
+
});
|
|
5997
|
+
if (response.status === 402 || response.status === 429) {
|
|
5998
|
+
throw new Error(`Jev \u984D\u5EA6\u5DF2\u7528\u5B8C\u6216\u8ACB\u6C42\u904E\u591A\uFF08HTTP ${response.status}\uFF09\uFF0C\u6539\u7528 CLI \u76EE\u524D\u7684\u6A21\u578B`);
|
|
5999
|
+
}
|
|
6000
|
+
if (!response.ok) throw new Error(`Jev API \u56DE\u61C9 ${response.status}`);
|
|
6001
|
+
const body = await response.json();
|
|
6002
|
+
if (!body.answers) throw new Error("Jev API \u6C92\u6709\u56DE\u50B3\u5224\u65B7");
|
|
6003
|
+
return body.answers;
|
|
6004
|
+
}
|
|
6005
|
+
async function routeEffort(task, catalog) {
|
|
6006
|
+
const model = modelFor(catalog, taskModel(task));
|
|
6007
|
+
const levels = selectableEfforts(model);
|
|
6008
|
+
if (levels.length === 0) return { status: "fallback", reason: "\u76EE\u524D\u6A21\u578B\u4E0D\u652F\u63F4\u8ABF\u6574 effort" };
|
|
6009
|
+
try {
|
|
6010
|
+
const answers = await ask({
|
|
6011
|
+
task: buildPrompt(task).slice(0, MAX_TASK_CHARS),
|
|
6012
|
+
agent: taskAgent(task),
|
|
6013
|
+
currentModel: model?.id ?? taskModel(task) ?? "CLI default (catalog unavailable)"
|
|
6014
|
+
}, { effort: effortQuestion(levels) });
|
|
6015
|
+
const choice = answers.effort;
|
|
6016
|
+
if (!isChoice(choice) || !levels.includes(choice.choice)) {
|
|
6017
|
+
throw new Error("Jev \u9078\u4E86\u76EE\u524D\u6A21\u578B\u4E0D\u652F\u63F4\u7684 effort");
|
|
6018
|
+
}
|
|
6019
|
+
return { status: "routed", effort: choice.choice };
|
|
6020
|
+
} catch (err) {
|
|
6021
|
+
return { status: "fallback", reason: message(err) };
|
|
6022
|
+
}
|
|
6023
|
+
}
|
|
6024
|
+
async function routeModel(task, catalog, ro) {
|
|
6025
|
+
const agent = taskAgent(task);
|
|
6026
|
+
const candidates = routeCandidates(agent, catalog);
|
|
6027
|
+
if (candidates.length === 0) return { status: "fallback", reason: "\u6A21\u578B\u6E05\u55AE\u6C92\u6709\u53EF\u7528\u7684\u6A21\u578B" };
|
|
6028
|
+
const chooseEffort = task.effort === "auto";
|
|
6029
|
+
const strongest = candidates[candidates.length - 1];
|
|
6030
|
+
const levels = MANUAL_EFFORTS.filter((level) => candidates.some((m) => selectableEfforts(m).includes(level)));
|
|
6031
|
+
const taskText = buildPrompt(task).slice(0, MAX_TASK_CHARS);
|
|
6032
|
+
const modelQuestion = {
|
|
6033
|
+
type: "choice",
|
|
6034
|
+
instructions: "Choose the lowest-cost available model likely to implement this software task correctly. Prefer more capable models as complexity, ambiguity or risk rises.",
|
|
6035
|
+
criteria: Object.fromEntries(candidates.map((m) => [m.id, `${m.label}; ${TIER_LABELS[tier(m, agent)]}`]))
|
|
6036
|
+
};
|
|
6037
|
+
const questions = (withUnclear) => ({
|
|
6038
|
+
complexity: {
|
|
6039
|
+
type: "choice",
|
|
6040
|
+
instructions: "How difficult is this software task to implement correctly?",
|
|
6041
|
+
criteria: {
|
|
6042
|
+
simple: "Small, well scoped and routine",
|
|
6043
|
+
moderate: "Some design choices or multiple files",
|
|
6044
|
+
complex: "Architecture, ambiguous requirements, high risk, or many interacting parts",
|
|
6045
|
+
...withUnclear ? { unclear: "Cannot be judged from the description alone; the repository must be read first" } : {}
|
|
6046
|
+
}
|
|
6047
|
+
},
|
|
6048
|
+
model: modelQuestion,
|
|
6049
|
+
...chooseEffort && levels.length > 0 ? { effort: effortQuestion(levels) } : {}
|
|
6050
|
+
});
|
|
6051
|
+
const decide = (answers, extra) => {
|
|
6052
|
+
const model = candidates.find((m) => isChoice(answers.model) && m.id === answers.model.choice);
|
|
6053
|
+
if (!model) throw new Error("Jev \u9078\u4E86\u4E0D\u5728\u6A21\u578B\u6E05\u55AE\u4E2D\u7684\u6A21\u578B");
|
|
6054
|
+
let effort;
|
|
6055
|
+
if (chooseEffort && levels.length > 0) {
|
|
6056
|
+
const choice = answers.effort;
|
|
6057
|
+
if (!isChoice(choice) || !levels.includes(choice.choice)) throw new Error("Jev \u56DE\u50B3\u4E0D\u53D7\u652F\u63F4\u7684 effort");
|
|
6058
|
+
effort = clampEffort(choice.choice, selectableEfforts(model));
|
|
6059
|
+
}
|
|
6060
|
+
return { status: "routed", model: model.id, ...effort ? { effort } : {}, ...extra };
|
|
6061
|
+
};
|
|
6062
|
+
const conservative = (extra) => {
|
|
6063
|
+
const effort = chooseEffort ? clampEffort("high", selectableEfforts(strongest)) : void 0;
|
|
6064
|
+
return { model: strongest.id, ...effort ? { effort } : {}, ...extra };
|
|
6065
|
+
};
|
|
6066
|
+
let first;
|
|
6067
|
+
let complexity;
|
|
6068
|
+
try {
|
|
6069
|
+
ro.onPhase?.("judging");
|
|
6070
|
+
first = await ask({ task: taskText, agent }, questions(true));
|
|
6071
|
+
const c = first.complexity;
|
|
6072
|
+
if (!isChoice(c) || !["simple", "moderate", "complex", "unclear"].includes(c.choice)) throw new Error("Jev \u56DE\u50B3\u4E0D\u53D7\u652F\u63F4\u7684\u8907\u96DC\u5EA6");
|
|
6073
|
+
complexity = c.choice;
|
|
6074
|
+
if (complexity !== "unclear") return decide(first, { complexity });
|
|
6075
|
+
} catch (err) {
|
|
6076
|
+
return { status: "fallback", reason: message(err) };
|
|
6077
|
+
}
|
|
6078
|
+
if (ro.scout === false) return conservative({ status: "routed", complexity });
|
|
6079
|
+
let context;
|
|
6080
|
+
try {
|
|
6081
|
+
if (!ro.cwd) throw new Error("\u88DC\u5145 context \u6642\u627E\u4E0D\u5230 worktree");
|
|
6082
|
+
ro.onPhase?.("scouting");
|
|
6083
|
+
const scoutEffort = clampEffort("high", selectableEfforts(strongest));
|
|
6084
|
+
const instruction = "Read the repository to prepare the following software task. Do not edit any file. Report concisely: the affected areas and files, requirements that are unclear, the main risks, and how to verify the work. Return only the analysis.\n\n" + taskText;
|
|
6085
|
+
context = (await scout(agent, strongest.id, scoutEffort, instruction, ro.cwd)).trim().slice(0, MAX_CONTEXT_CHARS);
|
|
6086
|
+
if (!context) throw new Error("\u88DC\u5145 context \u7684\u6A21\u578B\u6C92\u6709\u56DE\u50B3\u5206\u6790");
|
|
6087
|
+
} catch (err) {
|
|
6088
|
+
return conservative({ status: "fallback", complexity, reason: message(err) });
|
|
6089
|
+
}
|
|
6090
|
+
try {
|
|
6091
|
+
ro.onPhase?.("selecting");
|
|
6092
|
+
const second = await ask({ task: taskText, agent, context }, questions(false));
|
|
6093
|
+
return decide(second, { complexity, scoutModel: strongest.id, context });
|
|
6094
|
+
} catch (err) {
|
|
6095
|
+
return { status: "fallback", complexity, reason: message(err), scoutModel: strongest.id, context };
|
|
6096
|
+
}
|
|
6097
|
+
}
|
|
5945
6098
|
return {
|
|
5946
6099
|
get enabled() {
|
|
5947
6100
|
return Boolean(getApiKey());
|
|
5948
6101
|
},
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
const levels = selectableEfforts(model);
|
|
5952
|
-
if (levels.length === 0) return { status: "fallback", reason: "\u76EE\u524D\u6A21\u578B\u4E0D\u652F\u63F4\u8ABF\u6574 effort" };
|
|
5953
|
-
try {
|
|
5954
|
-
const apiKey = getApiKey();
|
|
5955
|
-
if (!apiKey) throw new Error("\u672A\u8A2D\u5B9A Jev API key\uFF08\u53EF\u5728\u8A2D\u5B9A\u4E2D\u8F38\u5165\u6216\u63D0\u4F9B TYPESAFE_API_KEY\uFF09");
|
|
5956
|
-
const response = await fetcher(API_URL, {
|
|
5957
|
-
method: "POST",
|
|
5958
|
-
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
5959
|
-
body: JSON.stringify({
|
|
5960
|
-
model: "jev-latest",
|
|
5961
|
-
state: {
|
|
5962
|
-
task: buildPrompt(task).slice(0, MAX_TASK_CHARS),
|
|
5963
|
-
agent: task.agentCli === "codex" ? "codex" : "claude",
|
|
5964
|
-
currentModel: model?.id ?? taskModel(task) ?? "CLI default (catalog unavailable)"
|
|
5965
|
-
},
|
|
5966
|
-
questions: {
|
|
5967
|
-
effort: {
|
|
5968
|
-
type: "choice",
|
|
5969
|
-
instructions: "Choose the lowest reasoning effort likely to complete this software task correctly on the current model. Increase effort for complexity, ambiguity, or risk.",
|
|
5970
|
-
criteria: Object.fromEntries(levels.map((level) => [level, effortDescription(level)]))
|
|
5971
|
-
}
|
|
5972
|
-
}
|
|
5973
|
-
}),
|
|
5974
|
-
signal: AbortSignal.timeout(15e3)
|
|
5975
|
-
});
|
|
5976
|
-
if (!response.ok) throw new Error(`Jev API \u56DE\u61C9 ${response.status}`);
|
|
5977
|
-
const body = await response.json();
|
|
5978
|
-
const choice = body.answers?.effort;
|
|
5979
|
-
if (choice?.type !== "choice" || !levels.includes(choice.choice)) {
|
|
5980
|
-
throw new Error("Jev \u9078\u4E86\u76EE\u524D\u6A21\u578B\u4E0D\u652F\u63F4\u7684 effort");
|
|
5981
|
-
}
|
|
5982
|
-
return { status: "routed", effort: choice.choice };
|
|
5983
|
-
} catch (err) {
|
|
5984
|
-
return { status: "fallback", reason: err instanceof Error ? err.message : String(err) };
|
|
5985
|
-
}
|
|
6102
|
+
route(task, catalog, ro = {}) {
|
|
6103
|
+
return taskModel(task) ? routeEffort(task, catalog) : routeModel(task, catalog, ro);
|
|
5986
6104
|
}
|
|
5987
6105
|
};
|
|
5988
6106
|
}
|
|
6107
|
+
function effortQuestion(levels) {
|
|
6108
|
+
return {
|
|
6109
|
+
type: "choice",
|
|
6110
|
+
instructions: "Choose the lowest reasoning effort likely to complete this software task correctly on the chosen model. Increase effort for complexity, ambiguity, or risk.",
|
|
6111
|
+
criteria: Object.fromEntries(levels.map((level) => [level, effortDescription(level)]))
|
|
6112
|
+
};
|
|
6113
|
+
}
|
|
6114
|
+
function message(err) {
|
|
6115
|
+
return err instanceof Error ? err.message : String(err);
|
|
6116
|
+
}
|
|
5989
6117
|
function effortDescription(level) {
|
|
5990
6118
|
const descriptions = {
|
|
5991
6119
|
low: "Routine, small and well scoped work",
|
|
@@ -6114,11 +6242,11 @@ async function getGitHubCliAuthStatus() {
|
|
|
6114
6242
|
} catch {
|
|
6115
6243
|
}
|
|
6116
6244
|
}
|
|
6117
|
-
const
|
|
6245
|
+
const message2 = errorMessage2(err);
|
|
6118
6246
|
return {
|
|
6119
|
-
installed: !/ENOENT|not found/i.test(
|
|
6247
|
+
installed: !/ENOENT|not found/i.test(message2),
|
|
6120
6248
|
authenticated: false,
|
|
6121
|
-
error:
|
|
6249
|
+
error: message2
|
|
6122
6250
|
};
|
|
6123
6251
|
}
|
|
6124
6252
|
}
|
|
@@ -6704,13 +6832,13 @@ function setConversation(taskId, conversation) {
|
|
|
6704
6832
|
function loadConversation(taskId) {
|
|
6705
6833
|
return getChatStore().get("conversations")[taskId] ?? null;
|
|
6706
6834
|
}
|
|
6707
|
-
function appendMessage(taskId,
|
|
6835
|
+
function appendMessage(taskId, message2) {
|
|
6708
6836
|
const existing = loadConversation(taskId) ?? {
|
|
6709
6837
|
taskId,
|
|
6710
6838
|
messages: [],
|
|
6711
6839
|
updatedAt: 0
|
|
6712
6840
|
};
|
|
6713
|
-
existing.messages.push(
|
|
6841
|
+
existing.messages.push(message2);
|
|
6714
6842
|
existing.updatedAt = Date.now();
|
|
6715
6843
|
setConversation(taskId, existing);
|
|
6716
6844
|
}
|
|
@@ -7265,8 +7393,8 @@ var PASTE_END = "\x1B[201~";
|
|
|
7265
7393
|
var PASTE_GAP_MS = 200;
|
|
7266
7394
|
var DEFAULT_QUIET_MS = 3e3;
|
|
7267
7395
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
7268
|
-
function coded(code2,
|
|
7269
|
-
return Object.assign(new Error(
|
|
7396
|
+
function coded(code2, message2) {
|
|
7397
|
+
return Object.assign(new Error(message2), { code: code2 });
|
|
7270
7398
|
}
|
|
7271
7399
|
function isBlocked(activity) {
|
|
7272
7400
|
return activity?.state === "waiting" && activity.waitingFor === "permission";
|
|
@@ -7451,11 +7579,11 @@ var InvalidRequestError = class extends Error {
|
|
|
7451
7579
|
};
|
|
7452
7580
|
var STANDALONE_KEY = /^terminal_[0-9a-f-]{36}$/;
|
|
7453
7581
|
var MAX_MESSAGE_LENGTH = 2e4;
|
|
7454
|
-
function coded2(code2,
|
|
7455
|
-
return Object.assign(new Error(
|
|
7582
|
+
function coded2(code2, message2) {
|
|
7583
|
+
return Object.assign(new Error(message2), { code: code2 });
|
|
7456
7584
|
}
|
|
7457
|
-
function invalid(
|
|
7458
|
-
throw new InvalidRequestError(
|
|
7585
|
+
function invalid(message2) {
|
|
7586
|
+
throw new InvalidRequestError(message2);
|
|
7459
7587
|
}
|
|
7460
7588
|
function str(value, name) {
|
|
7461
7589
|
if (typeof value !== "string") invalid(`${name} must be a string`);
|
|
@@ -7636,16 +7764,23 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7636
7764
|
const task = requireTask(key.split(":")[0]);
|
|
7637
7765
|
return str(task.worktreePath ?? task.projectPath, "directory");
|
|
7638
7766
|
}
|
|
7767
|
+
function launchModel(task, route) {
|
|
7768
|
+
return taskModel(task) ?? route?.model;
|
|
7769
|
+
}
|
|
7639
7770
|
function launchEffort(task, route) {
|
|
7640
7771
|
const effort = task.effort === "auto" ? route?.effort : task.effort;
|
|
7641
|
-
const model = models.findModel(taskAgent(task),
|
|
7772
|
+
const model = models.findModel(taskAgent(task), launchModel(task, route));
|
|
7642
7773
|
return model?.efforts ? clampEffort(effort, model.efforts) : effort;
|
|
7643
7774
|
}
|
|
7775
|
+
function settledRoute(task) {
|
|
7776
|
+
return task.jevRoute?.status === "routing" ? void 0 : task.jevRoute;
|
|
7777
|
+
}
|
|
7644
7778
|
async function launchCommand(task, intent) {
|
|
7645
7779
|
const settings = getSettings();
|
|
7646
7780
|
const boardCli = await boardCliLaunchInfo();
|
|
7647
|
-
let route = task
|
|
7648
|
-
|
|
7781
|
+
let route = settledRoute(task);
|
|
7782
|
+
const needsRoute = !taskModel(task) || task.effort === "auto";
|
|
7783
|
+
if (needsRoute && !intent.resume && intent.includeTaskPrompt !== false) {
|
|
7649
7784
|
let pending = routing.get(task.id);
|
|
7650
7785
|
if (!pending) {
|
|
7651
7786
|
const setRoute = (jevRoute) => {
|
|
@@ -7655,7 +7790,12 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7655
7790
|
pending = (async () => {
|
|
7656
7791
|
setRoute({ status: "routing" });
|
|
7657
7792
|
const candidateModels = (await (router.enabled === false ? models.get(taskAgent(task)) : models.refresh(taskAgent(task)))).models;
|
|
7658
|
-
const selected = await router.route(task, candidateModels
|
|
7793
|
+
const selected = await router.route(task, candidateModels, {
|
|
7794
|
+
// A master has no repo to read, only its notes folder.
|
|
7795
|
+
scout: !isMasterTask(task),
|
|
7796
|
+
cwd: task.worktreePath,
|
|
7797
|
+
onPhase: (phase) => setRoute({ status: "routing", phase })
|
|
7798
|
+
});
|
|
7659
7799
|
setRoute(selected);
|
|
7660
7800
|
return selected;
|
|
7661
7801
|
})().catch((err) => {
|
|
@@ -7666,14 +7806,16 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7666
7806
|
}
|
|
7667
7807
|
route = await pending;
|
|
7668
7808
|
}
|
|
7809
|
+
const preface = route?.context && route.scoutModel ? { model: route.scoutModel, context: route.context } : void 0;
|
|
7669
7810
|
return buildAgentCommand(
|
|
7670
|
-
{ ...task, model:
|
|
7811
|
+
{ ...task, model: launchModel(task, route), effort: launchEffort(task, route) },
|
|
7671
7812
|
settings.systemPrompt ?? "",
|
|
7672
7813
|
{
|
|
7673
7814
|
resume: intent.resume === true,
|
|
7674
7815
|
includeTaskPrompt: intent.includeTaskPrompt !== false,
|
|
7675
7816
|
boardCli,
|
|
7676
|
-
autoMode: task.autoMode ?? settings.autoMode
|
|
7817
|
+
autoMode: task.autoMode ?? settings.autoMode,
|
|
7818
|
+
preface
|
|
7677
7819
|
},
|
|
7678
7820
|
task.workspacePath
|
|
7679
7821
|
);
|
|
@@ -7782,6 +7924,15 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7782
7924
|
const task = findTask(taskId);
|
|
7783
7925
|
if (task && sessions.isAttached?.(taskId) === false) await startTaskSession(task, taskId, { taskId });
|
|
7784
7926
|
}
|
|
7927
|
+
function launchChoice(task) {
|
|
7928
|
+
const route = settledRoute(task);
|
|
7929
|
+
const model = launchModel(task, route);
|
|
7930
|
+
const effort = launchEffort(task, route);
|
|
7931
|
+
return {
|
|
7932
|
+
...model ? { model } : {},
|
|
7933
|
+
...effort && effort !== "auto" ? { effort } : {}
|
|
7934
|
+
};
|
|
7935
|
+
}
|
|
7785
7936
|
async function summarizeTasks(filter) {
|
|
7786
7937
|
const board = getState().board;
|
|
7787
7938
|
const alive = new Set(await sessions.list());
|
|
@@ -7803,6 +7954,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7803
7954
|
...task.masterId ? { masterId: task.masterId } : {},
|
|
7804
7955
|
...task.projectName ? { projectName: task.projectName } : {},
|
|
7805
7956
|
...task.branch ? { branch: task.branch } : {},
|
|
7957
|
+
...launchChoice(task),
|
|
7806
7958
|
running: alive.has(task.id),
|
|
7807
7959
|
...task.launchedAt ? { launchedAt: task.launchedAt } : {},
|
|
7808
7960
|
...task.launchError ? { launchError: task.launchError } : {},
|
|
@@ -8192,8 +8344,8 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
8192
8344
|
const file = await readTerminalFile(terminalDirectory(p.sessionKey), str(p.path, "path"), true);
|
|
8193
8345
|
if (!file.ok) return { ok: false, message: file.message };
|
|
8194
8346
|
try {
|
|
8195
|
-
const
|
|
8196
|
-
return
|
|
8347
|
+
const message2 = await getPlatform().openPath(file.path);
|
|
8348
|
+
return message2 ? { ok: false, message: message2 } : { ok: true };
|
|
8197
8349
|
} catch (error) {
|
|
8198
8350
|
return { ok: false, message: error instanceof Error ? error.message : "\u7121\u6CD5\u958B\u555F\u6A94\u6848\u3002" };
|
|
8199
8351
|
}
|