@kw-yeh/vibeflow 4.11.14 → 4.11.17
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 +2 -2
- package/dist/vibeflow.mjs +183 -320
- package/dist/web/404/index.html +1 -1
- package/dist/web/404.html +1 -1
- package/dist/web/_next/static/chunks/pages/{_app-0c60752b4c05d52e.js → _app-83dfa6752c321c56.js} +1 -1
- package/dist/web/_next/static/chunks/pages/home-61c688b1d20e56ff.js +13 -0
- package/dist/web/_next/static/css/3cafb8bddc730b60.css +2 -0
- package/dist/web/_next/static/{1gu-Md_jBIHwDpsGMC8AV → xoex8UtSV4DX9eSoX3lTZ}/_buildManifest.js +1 -1
- package/dist/web/home/index.html +1 -1
- package/package.json +1 -1
- package/dist/web/_next/static/chunks/pages/home-029b95a2ac77e4bc.js +0 -13
- package/dist/web/_next/static/css/60e89d492b3b3ef3.css +0 -2
- /package/dist/web/_next/static/{1gu-Md_jBIHwDpsGMC8AV → xoex8UtSV4DX9eSoX3lTZ}/_ssgManifest.js +0 -0
package/dist/vibeflow.mjs
CHANGED
|
@@ -514,16 +514,6 @@ function agentArtifactsDir(worktreePath, workspacePath) {
|
|
|
514
514
|
const ws = pathBasename(worktreePath);
|
|
515
515
|
return `${dir}/${ws}${ARTIFACTS_DIR_SUFFIX}`;
|
|
516
516
|
}
|
|
517
|
-
function buildArtifactPrompt(artifactsDir = ARTIFACTS_FALLBACK_DIR) {
|
|
518
|
-
return [
|
|
519
|
-
"Artifact \u8A2D\u5B9A\uFF08\u672C\u6B21 session \u5168\u7A0B\u9069\u7528\uFF09\uFF1A",
|
|
520
|
-
`1. \u672C\u4EFB\u52D9\u7684 Artifact \u8CC7\u6599\u593E\u662F ${artifactsDir}/\uFF1B\u9700\u8981\u4FDD\u5B58\u7D66\u4F7F\u7528\u8005\u7684\u9A57\u8B49\u8B49\u64DA\u6216\u5831\u544A\u6642\uFF0C\u8ACB\u5BEB\u5165\u6B64\u8CC7\u6599\u593E\uFF08\u4E0D\u5B58\u5728\u8ACB\u5EFA\u7ACB\uFF09\u3002`,
|
|
521
|
-
`2. \u4F7F\u7528\u8005\u6703\u5728 VibeFlow \u7684 Artifacts \u5206\u9801\u6AA2\u8996\u6839\u76EE\u9304\u5167\u5BB9\uFF1B\u53EA\u653E\u4F60\u6703\u4E3B\u52D5\u8ACB\u4F7F\u7528\u8005\u904E\u76EE\u7684\u6A94\u6848\u3002`,
|
|
522
|
-
`3. \u4F60\u81EA\u5DF1\u7684\u5DE5\u4F5C\u66AB\u5B58\uFF08\u4E00\u6B21\u6027 script\u3001log\u3001\u4E2D\u9593\u8F38\u51FA\u3001debug \u6A94\uFF09\u653E\u5728 ${artifactsDir}/${SCRATCH_DIR_NAME}/\u3002`,
|
|
523
|
-
`4. \u82E5\u5DE5\u5177\u5148\u8F38\u51FA\u5230 /tmp\u3001/private/tmp\u3001$TMPDIR \u6216 ~/Downloads\uFF0C\u8ACB\u628A\u6700\u7D42\u8981\u5448\u73FE\u7684\u6A94\u6848\u8907\u88FD\u5230 ${artifactsDir}/ \u4E26\u78BA\u8A8D\u5B58\u5728\u3002`,
|
|
524
|
-
"5. Artifact \u8CC7\u6599\u593E\u4F4D\u65BC worktree \u4E4B\u5916\uFF1B\u4E0D\u8981\u628A\u5176\u4E2D\u5167\u5BB9\u52A0\u5165 git commit\uFF0C\u4E5F\u4E0D\u8981\u628A\u6700\u7D42\u4EA4\u4ED8\u7269\u53EA\u7559\u5728\u9019\u88E1\u3002"
|
|
525
|
-
].join("\n");
|
|
526
|
-
}
|
|
527
517
|
function claudePermissionFlag(autoMode) {
|
|
528
518
|
return autoMode ? ` --permission-mode ${AUTO_PERMISSION_MODE}` : "";
|
|
529
519
|
}
|
|
@@ -533,8 +523,9 @@ function shellQuote(s) {
|
|
|
533
523
|
function toShellPath(p) {
|
|
534
524
|
return p.replace(/\\/g, "/");
|
|
535
525
|
}
|
|
536
|
-
function boardEnvPrefix(task, opts) {
|
|
526
|
+
function boardEnvPrefix(task, opts, workspacePath) {
|
|
537
527
|
const board = opts?.boardCli;
|
|
528
|
+
const artifactsDir = agentArtifactsDir(task.worktreePath, workspacePath) ?? (task.worktreePath ? `${toShellPath(task.worktreePath)}/${ARTIFACTS_FALLBACK_DIR}` : void 0);
|
|
538
529
|
if (!board) return "";
|
|
539
530
|
const entries = [
|
|
540
531
|
["VIBEFLOW_TASK_ID", task.id],
|
|
@@ -544,7 +535,9 @@ function boardEnvPrefix(task, opts) {
|
|
|
544
535
|
["VIBEFLOW_STORE_DIR", board?.storeDir],
|
|
545
536
|
["VIBEFLOW_CLI", board?.cliPath],
|
|
546
537
|
["VIBEFLOW_CLI_LOADER", board?.loaderPath],
|
|
547
|
-
["VIBEFLOW_AUTO_MODE", opts?.autoMode ? "1" : "0"]
|
|
538
|
+
["VIBEFLOW_AUTO_MODE", opts?.autoMode ? "1" : "0"],
|
|
539
|
+
["VIBEFLOW_ARTIFACTS_DIR", artifactsDir],
|
|
540
|
+
["VIBEFLOW_SCRATCH_DIR", artifactsDir ? `${artifactsDir}/${SCRATCH_DIR_NAME}` : void 0]
|
|
548
541
|
];
|
|
549
542
|
const exports = entries.filter((entry) => Boolean(entry[1])).map(([key, value]) => `${key}=${shellQuote(toShellPath(value))}`);
|
|
550
543
|
return exports.length ? `export ${exports.join(" ")}; ` : "";
|
|
@@ -612,25 +605,22 @@ function assembleCommand(agent, systemPrompt, prompt, model, effort, opts, workt
|
|
|
612
605
|
const settings = ` --settings ${shellQuote(buildClaudeSettings(worktreePath))}`;
|
|
613
606
|
const addDir = workspacePath ? ` --add-dir ${shellQuote(toShellPath(workspacePath))}` : "";
|
|
614
607
|
const modelFlag = model ? ` --model ${model}` : "";
|
|
615
|
-
const effortFlag = effort ? ` --effort ${effort}` : "";
|
|
616
|
-
const
|
|
617
|
-
const libraryFlags = library ? ` --plugin-dir ${shellQuote(toShellPath(library.pluginDir))} --add-dir ${shellQuote(toShellPath(library.libraryDir))}` : "";
|
|
618
|
-
const flags = `--chrome${claudePermissionFlag(opts?.autoMode)}${modelFlag}${effortFlag}${settings}${addDir}${libraryFlags}`;
|
|
608
|
+
const effortFlag = effort && effort !== "auto" ? ` --effort ${effort}` : "";
|
|
609
|
+
const flags = `--chrome${claudePermissionFlag(opts?.autoMode)}${modelFlag}${effortFlag}${settings}${addDir}`;
|
|
619
610
|
const sysFlag = systemPrompt ? ` --append-system-prompt ${shellQuote(systemPrompt)}` : "";
|
|
620
611
|
const promptArg = prompt ? ` ${shellQuote(prompt)}` : "";
|
|
621
612
|
const tail = `${flags}${sysFlag}${promptArg}`;
|
|
622
613
|
cmd = sessionId && opts?.resume ? claudeResumeOrFresh(sessionId, worktreePath, tail) : `claude ${sessionId ? `--session-id ${sessionId} ` : opts?.resume ? "--continue " : ""}${tail}\r`;
|
|
623
614
|
} else {
|
|
624
615
|
const combined = [systemPrompt, prompt].filter(Boolean).join("\n\n");
|
|
625
|
-
const codexEffortFlag = effort ? `-c ${shellQuote(`model_reasoning_effort="${effort}"`)} ` : "";
|
|
626
|
-
const codexHome = opts?.library ? `CODEX_HOME=${shellQuote(toShellPath(opts.library.codexHome))} ` : "";
|
|
616
|
+
const codexEffortFlag = effort && effort !== "auto" ? `-c ${shellQuote(`model_reasoning_effort="${effort}"`)} ` : "";
|
|
627
617
|
const args = [
|
|
628
618
|
codexAutoFlag(opts?.autoMode).trim(),
|
|
629
619
|
codexEffortFlag.trim(),
|
|
630
620
|
model ? `--model ${model}` : "",
|
|
631
621
|
combined ? shellQuote(combined) : ""
|
|
632
622
|
].filter(Boolean);
|
|
633
|
-
cmd = `${
|
|
623
|
+
cmd = `${["codex", ...args].join(" ")}\r`;
|
|
634
624
|
}
|
|
635
625
|
if (cmd.length > 2e5) console.warn(`[VibeFlow] launch command is ${cmd.length} bytes \u2014 approaching ARG_MAX`);
|
|
636
626
|
return cmd;
|
|
@@ -647,16 +637,11 @@ function taskModel(task) {
|
|
|
647
637
|
function buildAgentCommand(task, systemPrompt, opts, workspacePath) {
|
|
648
638
|
const agent = taskAgent(task);
|
|
649
639
|
const model = taskModel(task);
|
|
650
|
-
const
|
|
651
|
-
const builtInPrompt = buildArtifactPrompt(artifactsDir);
|
|
652
|
-
const libraryPrompt = opts?.library?.promptText?.trim();
|
|
653
|
-
const customPrompt = resolveSystemPrompt(systemPrompt);
|
|
654
|
-
const sys = [builtInPrompt, libraryPrompt, customPrompt].filter(Boolean).join("\n\n");
|
|
640
|
+
const sys = resolveSystemPrompt(systemPrompt);
|
|
655
641
|
const includeTaskPrompt = opts?.includeTaskPrompt !== false;
|
|
656
|
-
const prompt = includeTaskPrompt && !opts?.resume ?
|
|
657
|
-
${opts.preflightPlan}` : ""].filter(Boolean).join("\n\n") : "";
|
|
642
|
+
const prompt = includeTaskPrompt && !opts?.resume ? buildPrompt(task) : "";
|
|
658
643
|
const sessionId = agent === "claude" && includeTaskPrompt ? executorSessionId(task.id, task.runId) : void 0;
|
|
659
|
-
return boardEnvPrefix(task, opts) + assembleCommand(
|
|
644
|
+
return boardEnvPrefix(task, opts, workspacePath) + assembleCommand(
|
|
660
645
|
agent,
|
|
661
646
|
sys,
|
|
662
647
|
prompt,
|
|
@@ -793,8 +778,8 @@ var init_attachments = __esm({
|
|
|
793
778
|
function modelFor(models, modelId) {
|
|
794
779
|
return modelId ? models?.find((m) => m.id === modelId) : models?.find((m) => m.isDefault);
|
|
795
780
|
}
|
|
796
|
-
function
|
|
797
|
-
return typeof value === "string" &&
|
|
781
|
+
function isManualEffort(value) {
|
|
782
|
+
return typeof value === "string" && MANUAL_EFFORTS.includes(value);
|
|
798
783
|
}
|
|
799
784
|
function allowedEfforts(model) {
|
|
800
785
|
return model?.efforts ?? null;
|
|
@@ -804,17 +789,19 @@ function selectableEfforts(model) {
|
|
|
804
789
|
}
|
|
805
790
|
function clampEffort(effort, allowed) {
|
|
806
791
|
if (allowed.length === 0) return void 0;
|
|
807
|
-
if (effort === void 0 ||
|
|
808
|
-
|
|
809
|
-
const
|
|
810
|
-
const
|
|
792
|
+
if (effort === void 0 || effort === "auto") return void 0;
|
|
793
|
+
if (allowed.includes(effort)) return effort;
|
|
794
|
+
const rank = MANUAL_EFFORTS.indexOf(effort);
|
|
795
|
+
const ordered = MANUAL_EFFORTS.filter((level) => allowed.includes(level));
|
|
796
|
+
const notDeeper = ordered.filter((level) => MANUAL_EFFORTS.indexOf(level) <= rank);
|
|
811
797
|
return notDeeper.length > 0 ? notDeeper[notDeeper.length - 1] : ordered[0];
|
|
812
798
|
}
|
|
813
|
-
var AGENT_EFFORTS, UNKNOWN_MODEL_EFFORTS;
|
|
799
|
+
var MANUAL_EFFORTS, AGENT_EFFORTS, UNKNOWN_MODEL_EFFORTS;
|
|
814
800
|
var init_effort = __esm({
|
|
815
801
|
"packages/core/src/effort.ts"() {
|
|
816
802
|
"use strict";
|
|
817
|
-
|
|
803
|
+
MANUAL_EFFORTS = ["low", "medium", "high", "xhigh", "max", "ultra"];
|
|
804
|
+
AGENT_EFFORTS = ["auto", ...MANUAL_EFFORTS];
|
|
818
805
|
UNKNOWN_MODEL_EFFORTS = ["low", "medium", "high", "xhigh"];
|
|
819
806
|
}
|
|
820
807
|
});
|
|
@@ -1104,7 +1091,7 @@ var init_progress = __esm({
|
|
|
1104
1091
|
// packages/tui/src/task-form.ts
|
|
1105
1092
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
1106
1093
|
import fs24 from "fs";
|
|
1107
|
-
import
|
|
1094
|
+
import os8 from "os";
|
|
1108
1095
|
import path28 from "path";
|
|
1109
1096
|
import React, { useEffect, useRef, useState } from "react";
|
|
1110
1097
|
import { Box, Text, render as render2, useApp, useInput } from "ink";
|
|
@@ -1177,10 +1164,10 @@ function modelOptions(ctx, agentCli, current) {
|
|
|
1177
1164
|
return options;
|
|
1178
1165
|
}
|
|
1179
1166
|
function effortOptions(ctx, agentCli, model) {
|
|
1180
|
-
return selectableEfforts(modelFor(ctx.models[agentCli], taskModel({ agentCli, model })));
|
|
1167
|
+
return ["auto", ...selectableEfforts(modelFor(ctx.models[agentCli], taskModel({ agentCli, model })))];
|
|
1181
1168
|
}
|
|
1182
1169
|
function fitEffort(ctx, s) {
|
|
1183
|
-
const effort = clampEffort(s.effort, effortOptions(ctx, s.agentCli, s.model)) ?? s.effort;
|
|
1170
|
+
const effort = s.effort === "auto" ? "auto" : clampEffort(s.effort, effortOptions(ctx, s.agentCli, s.model).filter(isManualEffort)) ?? s.effort;
|
|
1184
1171
|
return effort === s.effort ? s : { ...s, effort };
|
|
1185
1172
|
}
|
|
1186
1173
|
function blockReason(s, ctx, loadingGit) {
|
|
@@ -1231,7 +1218,7 @@ function editorCommand(env, platform) {
|
|
|
1231
1218
|
return env.VISUAL?.trim() || env.EDITOR?.trim() || (platform === "win32" ? "notepad" : "vi");
|
|
1232
1219
|
}
|
|
1233
1220
|
function editInEditor(text) {
|
|
1234
|
-
const dir = fs24.mkdtempSync(path28.join(
|
|
1221
|
+
const dir = fs24.mkdtempSync(path28.join(os8.tmpdir(), "vibeflow-"));
|
|
1235
1222
|
const file = path28.join(dir, "description.md");
|
|
1236
1223
|
try {
|
|
1237
1224
|
fs24.writeFileSync(file, text);
|
|
@@ -1312,9 +1299,9 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
1312
1299
|
if (editing === "title") setS((prev) => ({ ...prev, title: draft }));
|
|
1313
1300
|
else if (editing === "branch") setS((prev) => ({ ...prev, branch: value2 }));
|
|
1314
1301
|
else if (editing === "project") {
|
|
1315
|
-
if (value2) setProject(path28.resolve(value2.replace(/^~(?=$|\/)/,
|
|
1302
|
+
if (value2) setProject(path28.resolve(value2.replace(/^~(?=$|\/)/, os8.homedir())));
|
|
1316
1303
|
} else if (editing === "attachments" && value2) {
|
|
1317
|
-
const file = path28.resolve(value2.replace(/^~(?=$|\/)/,
|
|
1304
|
+
const file = path28.resolve(value2.replace(/^~(?=$|\/)/, os8.homedir()));
|
|
1318
1305
|
if (!fs24.existsSync(file) || !fs24.statSync(file).isFile()) {
|
|
1319
1306
|
setMessage(`\u627E\u4E0D\u5230\u6A94\u6848\uFF1A${file}`);
|
|
1320
1307
|
return;
|
|
@@ -1405,7 +1392,6 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
1405
1392
|
return lines.length > 1 ? `${lines[0]} \u2026\uFF08\u5171 ${lines.length} \u884C\uFF09` : lines[0];
|
|
1406
1393
|
}
|
|
1407
1394
|
case "effort": {
|
|
1408
|
-
if (effortOptions(ctx, s.agentCli, s.model).length === 0) return "\u4E0D\u9069\u7528";
|
|
1409
1395
|
const e = EFFORTS.find((x) => x.value === s.effort) ?? EFFORTS[0];
|
|
1410
1396
|
return `\u2039 ${e.label} \xB7 ${e.value} \u203A`;
|
|
1411
1397
|
}
|
|
@@ -1441,7 +1427,7 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
1441
1427
|
return s.mode === "edit" && s.worktreePath ? `${when} \u9019\u5F35\u5361\u5DF2\u6709 worktree\uFF1A\u66F4\u6539\u5206\u652F\u3001\u5C08\u6848\u6216\u57FA\u6E96\u5206\u652F\u6703\u79FB\u9664\u5B83\uFF08\u6709\u672A\u5B8C\u6210\u8B8A\u66F4\u6642\u7121\u6CD5\u5132\u5B58\uFF09\u3002` : when;
|
|
1442
1428
|
}
|
|
1443
1429
|
if (field === "effort") {
|
|
1444
|
-
if (effortOptions(ctx, s.agentCli, s.model).length ===
|
|
1430
|
+
if (effortOptions(ctx, s.agentCli, s.model).length === 1) return "\u9019\u500B model \u4E0D\u652F\u63F4\u8ABF\u6574\u63A8\u7406\u5F37\u5EA6\uFF0C\u555F\u52D5\u6642\u4F7F\u7528\u6A21\u578B\u9810\u8A2D\u503C\u3002";
|
|
1445
1431
|
const e = EFFORTS.find((x) => x.value === s.effort) ?? EFFORTS[0];
|
|
1446
1432
|
return `${e.description} Claude Code \u8207 Codex \u6703\u5728\u555F\u52D5\u6B64\u4EFB\u52D9\u6642\u5957\u7528\uFF1B\u53EF\u9078\u7684\u7D1A\u8DDD\u4F9D model \u800C\u5B9A\u3002`;
|
|
1447
1433
|
}
|
|
@@ -1521,6 +1507,7 @@ var init_task_form = __esm({
|
|
|
1521
1507
|
init_attachments();
|
|
1522
1508
|
h = React.createElement;
|
|
1523
1509
|
EFFORTS = [
|
|
1510
|
+
{ value: "auto", label: "\u81EA\u52D5", description: "Jev \u4F9D\u4EFB\u52D9\u8207\u76EE\u524D\u6A21\u578B\u9078\u64C7\u63A8\u7406\u5F37\u5EA6\u3002" },
|
|
1524
1511
|
{ value: "low", label: "\u5FEB\u901F", description: "\u9069\u5408\u7BC4\u570D\u660E\u78BA\u3001\u4F4E\u98A8\u96AA\u7684\u5C0F\u4EFB\u52D9\u3002" },
|
|
1525
1512
|
{ value: "medium", label: "\u6A19\u6E96", description: "\u517C\u9867\u901F\u5EA6\u8207\u63A8\u7406\u6DF1\u5EA6\uFF0C\u9069\u5408\u4E00\u822C\u958B\u767C\u4EFB\u52D9\u3002" },
|
|
1526
1513
|
{ value: "high", label: "\u6DF1\u5165", description: "\u9069\u5408\u8DE8\u6A94\u6848\u3001\u9664\u932F\u6216\u9700\u8981\u8F03\u591A\u5224\u65B7\u7684\u4EFB\u52D9\u3002" },
|
|
@@ -1528,7 +1515,7 @@ var init_task_form = __esm({
|
|
|
1528
1515
|
{ value: "max", label: "\u6700\u5927", description: "\u6700\u6DF1\u7684\u63A8\u7406\uFF0C\u9069\u5408\u6700\u56F0\u96E3\u7684\u554F\u984C\u3002" },
|
|
1529
1516
|
{ value: "ultra", label: "\u59D4\u6D3E", description: "\u6700\u6DF1\u63A8\u7406\u4E26\u81EA\u52D5\u59D4\u6D3E\u5B50\u4EFB\u52D9\uFF0C\u8017\u6642\u8207\u7528\u91CF\u53EF\u80FD\u660E\u986F\u589E\u52A0\u3002" }
|
|
1530
1517
|
];
|
|
1531
|
-
DEFAULT_EFFORT = "
|
|
1518
|
+
DEFAULT_EFFORT = "auto";
|
|
1532
1519
|
LABELS = {
|
|
1533
1520
|
title: "\u4EFB\u52D9\u6A19\u984C",
|
|
1534
1521
|
project: "\u5C08\u6848\u8CC7\u6599\u593E",
|
|
@@ -2470,6 +2457,7 @@ function createBridge(t) {
|
|
|
2470
2457
|
/** Running app version (package.json version baked into the build). */
|
|
2471
2458
|
getVersion: () => t.invoke("app:getVersion"),
|
|
2472
2459
|
getUpdateStatus: () => t.invoke("host:updateStatus"),
|
|
2460
|
+
checkForUpdate: () => t.invoke("host:checkUpdate"),
|
|
2473
2461
|
openUpdateTerminal: () => t.invoke("host:openUpdateTerminal"),
|
|
2474
2462
|
onUpdateAvailable: (callback) => t.on("update:available", (payload) => callback(payload)),
|
|
2475
2463
|
/**
|
|
@@ -3337,6 +3325,30 @@ var SNIFF_BYTES = 8 * 1024;
|
|
|
3337
3325
|
function agentArtifactsPath(baseDir, worktreePath) {
|
|
3338
3326
|
return path11.join(baseDir, `${path11.basename(worktreePath)}${ARTIFACTS_DIR_SUFFIX2}`);
|
|
3339
3327
|
}
|
|
3328
|
+
function ensureTaskArtifactDirs(task) {
|
|
3329
|
+
if (!task.worktreePath) throw new Error("\u4EFB\u52D9\u5C1A\u672A\u5EFA\u7ACB worktree");
|
|
3330
|
+
const dir = task.workspacePath ? agentArtifactsPath(task.workspacePath, task.worktreePath) : path11.join(task.worktreePath, ARTIFACTS_FALLBACK_DIR2);
|
|
3331
|
+
fs7.mkdirSync(path11.join(dir, SCRATCH_DIR_NAME2), { recursive: true });
|
|
3332
|
+
return dir;
|
|
3333
|
+
}
|
|
3334
|
+
function addTaskArtifact(task, filePath) {
|
|
3335
|
+
const source = path11.resolve(filePath);
|
|
3336
|
+
const stat = fs7.lstatSync(source);
|
|
3337
|
+
if (!stat.isFile()) throw new Error("Artifact \u4F86\u6E90\u5FC5\u9808\u662F\u4E00\u822C\u6A94\u6848");
|
|
3338
|
+
const dir = ensureTaskArtifactDirs(task);
|
|
3339
|
+
if (path11.dirname(source) === dir) return source;
|
|
3340
|
+
const { name, ext } = path11.parse(source);
|
|
3341
|
+
for (let index = 0; index < 1e3; index += 1) {
|
|
3342
|
+
const destination = path11.join(dir, index === 0 ? `${name}${ext}` : `${name}-${index}${ext}`);
|
|
3343
|
+
try {
|
|
3344
|
+
fs7.copyFileSync(source, destination, fs7.constants.COPYFILE_EXCL);
|
|
3345
|
+
return destination;
|
|
3346
|
+
} catch (error) {
|
|
3347
|
+
if (error.code !== "EEXIST") throw error;
|
|
3348
|
+
}
|
|
3349
|
+
}
|
|
3350
|
+
throw new Error("Artifact \u8CC7\u6599\u593E\u6709\u592A\u591A\u540C\u540D\u6A94\u6848");
|
|
3351
|
+
}
|
|
3340
3352
|
function mediaKind(filePath, size) {
|
|
3341
3353
|
const extension = path11.extname(filePath).toLowerCase();
|
|
3342
3354
|
const imageMime = IMAGE_MIME[extension];
|
|
@@ -4272,7 +4284,7 @@ init_effort();
|
|
|
4272
4284
|
import { execFile as execFile6 } from "child_process";
|
|
4273
4285
|
import { promisify as promisify3 } from "util";
|
|
4274
4286
|
var pexec3 = promisify3(execFile6);
|
|
4275
|
-
var DEFAULT_TASK_EFFORT = "
|
|
4287
|
+
var DEFAULT_TASK_EFFORT = "auto";
|
|
4276
4288
|
var AGENT_CLIS = [
|
|
4277
4289
|
{
|
|
4278
4290
|
id: "claude",
|
|
@@ -4463,7 +4475,7 @@ function updateTaskFromInput(input) {
|
|
|
4463
4475
|
init_attachments();
|
|
4464
4476
|
var AGENT_IDS = AGENT_CLIS.map((agent) => agent.id);
|
|
4465
4477
|
var STATUSES = ["backlog", "in_progress", "done"];
|
|
4466
|
-
var SUBCOMMANDS = ["create", "update"];
|
|
4478
|
+
var SUBCOMMANDS = ["create", "update", "artifact"];
|
|
4467
4479
|
var MODES = ["existing", "new"];
|
|
4468
4480
|
var AUTO_MODES = ["on", "off"];
|
|
4469
4481
|
var TASK_USAGE = `
|
|
@@ -4472,6 +4484,7 @@ VibeFlow task commands
|
|
|
4472
4484
|
Usage:
|
|
4473
4485
|
vibeflow task create [options]
|
|
4474
4486
|
vibeflow task update [options]
|
|
4487
|
+
vibeflow task artifact add --file <path> [options]
|
|
4475
4488
|
|
|
4476
4489
|
task create options:
|
|
4477
4490
|
--project <path> Target project directory (required)
|
|
@@ -4485,7 +4498,7 @@ task create options:
|
|
|
4485
4498
|
--mode <mode> ${MODES.join(" | ")} (default: existing; "new" runs git init first)
|
|
4486
4499
|
--agent <id> Task agent: ${AGENT_IDS.join(" | ")} (default: claude)
|
|
4487
4500
|
--model <id> Task model (default: the agent's own default)
|
|
4488
|
-
--effort <level> ${AGENT_EFFORTS.join(" | ")} (default:
|
|
4501
|
+
--effort <level> ${AGENT_EFFORTS.join(" | ")} (default: auto, same as the UI)
|
|
4489
4502
|
--auto-mode <on|off> Let the agent act without asking for approval
|
|
4490
4503
|
(default: the board-wide setting, same as the UI)
|
|
4491
4504
|
--attach <path> Attach a file; repeat the flag for several files
|
|
@@ -4504,6 +4517,12 @@ task update options:
|
|
|
4504
4517
|
At least one of --title / --prompt / --status is required. Branch, worktree
|
|
4505
4518
|
and project path are provisioned on disk and cannot be changed here.
|
|
4506
4519
|
|
|
4520
|
+
task artifact add options:
|
|
4521
|
+
--file <path> Copy a file into the card's user-facing Artifacts folder
|
|
4522
|
+
--task <id> Card ID (defaults to VIBEFLOW_TASK_ID in a task shell)
|
|
4523
|
+
--store-path <dir> Store directory (defaults to VIBEFLOW_STORE_DIR in a task shell)
|
|
4524
|
+
--profile <name> dev | prod \u2014 when no store path is given
|
|
4525
|
+
|
|
4507
4526
|
Notes:
|
|
4508
4527
|
A card created with --status in_progress does NOT start running by itself.
|
|
4509
4528
|
Every launch is started by hand from the app.
|
|
@@ -4571,6 +4590,7 @@ async function taskCommand(argv) {
|
|
|
4571
4590
|
effort: { type: "string" },
|
|
4572
4591
|
"auto-mode": { type: "string" },
|
|
4573
4592
|
attach: { type: "string", multiple: true },
|
|
4593
|
+
file: { type: "string" },
|
|
4574
4594
|
"store-path": { type: "string" },
|
|
4575
4595
|
profile: { type: "string" },
|
|
4576
4596
|
help: { type: "boolean", short: "h" }
|
|
@@ -4582,13 +4602,24 @@ async function taskCommand(argv) {
|
|
|
4582
4602
|
fail("INVALID_ARGUMENT", err.message);
|
|
4583
4603
|
}
|
|
4584
4604
|
const { values, positionals } = parsed;
|
|
4585
|
-
const [sub] = positionals;
|
|
4605
|
+
const [sub, action] = positionals;
|
|
4586
4606
|
if (values.help || !sub) return null;
|
|
4587
|
-
const storePath = resolveStorePath(
|
|
4607
|
+
const storePath = resolveStorePath(
|
|
4608
|
+
values["store-path"] ?? (sub === "artifact" ? process.env.VIBEFLOW_STORE_DIR : void 0),
|
|
4609
|
+
values.profile
|
|
4610
|
+
);
|
|
4588
4611
|
setPlatform(createNodePlatform({ userDataDir: storePath }));
|
|
4589
4612
|
if (!SUBCOMMANDS.includes(sub)) {
|
|
4590
4613
|
fail("UNKNOWN_COMMAND", `Unknown command: "task ${sub}". Use: ${SUBCOMMANDS.map((s) => `task ${s}`).join(" | ")}`);
|
|
4591
4614
|
}
|
|
4615
|
+
if (sub === "artifact") {
|
|
4616
|
+
if (action !== "add") fail("UNKNOWN_COMMAND", "Use: task artifact add --file <path>");
|
|
4617
|
+
const taskId = values.task ?? process.env.VIBEFLOW_TASK_ID;
|
|
4618
|
+
if (!taskId || !values.file) fail("MISSING_ARGUMENT", "task artifact add needs --file and --task (or VIBEFLOW_TASK_ID)");
|
|
4619
|
+
const task2 = findTask(taskId);
|
|
4620
|
+
if (!task2) fail("TASK_NOT_FOUND", `Task not found: ${taskId}`);
|
|
4621
|
+
return { taskId, path: addTaskArtifact(task2, values.file) };
|
|
4622
|
+
}
|
|
4592
4623
|
if (sub === "update") {
|
|
4593
4624
|
if (!values.task) fail("MISSING_ARGUMENT", "Missing required arguments: --task");
|
|
4594
4625
|
requireOneOf("--status", values.status, STATUSES);
|
|
@@ -4696,7 +4727,6 @@ import path15 from "path";
|
|
|
4696
4727
|
// packages/core/src/library.ts
|
|
4697
4728
|
import { createHash } from "crypto";
|
|
4698
4729
|
import fs10 from "fs";
|
|
4699
|
-
import os3 from "os";
|
|
4700
4730
|
import path14 from "path";
|
|
4701
4731
|
var LIBRARY_DIR = "library";
|
|
4702
4732
|
var LIBRARY_KINDS = ["skill", "prompt", "script"];
|
|
@@ -4713,7 +4743,6 @@ function libraryPaths(root) {
|
|
|
4713
4743
|
skills: path14.join(root, KIND_DIR.skill),
|
|
4714
4744
|
prompts: path14.join(root, KIND_DIR.prompt),
|
|
4715
4745
|
scripts: path14.join(root, KIND_DIR.script),
|
|
4716
|
-
plugin: path14.join(root, "plugin"),
|
|
4717
4746
|
codexHome: path14.join(root, "codex-home")
|
|
4718
4747
|
};
|
|
4719
4748
|
}
|
|
@@ -4961,9 +4990,6 @@ function requireEntry(root, kind, name) {
|
|
|
4961
4990
|
if (!found2) throw new Error(`\u9805\u76EE\u5BEB\u5165\u5F8C\u8B80\u4E0D\u56DE\u4F86\uFF1A${kind}/${name}`);
|
|
4962
4991
|
return found2;
|
|
4963
4992
|
}
|
|
4964
|
-
function projectSkillsDir(worktreePath) {
|
|
4965
|
-
return path14.join(worktreePath, ".claude", "skills");
|
|
4966
|
-
}
|
|
4967
4993
|
function skillNamesIn(dir) {
|
|
4968
4994
|
try {
|
|
4969
4995
|
return fs10.readdirSync(dir, { withFileTypes: true }).filter((d) => !d.name.startsWith(".")).map((d) => d.name).filter((name) => fs10.existsSync(path14.join(dir, name, "SKILL.md"))).sort();
|
|
@@ -4971,132 +4997,6 @@ function skillNamesIn(dir) {
|
|
|
4971
4997
|
return [];
|
|
4972
4998
|
}
|
|
4973
4999
|
}
|
|
4974
|
-
var PLUGIN_MANIFEST_DIR = ".claude-plugin";
|
|
4975
|
-
function buildPluginDir(root) {
|
|
4976
|
-
const paths = libraryPaths(root);
|
|
4977
|
-
const enabled = listLibrary(root).filter((e) => e.kind === "skill" && e.enabled);
|
|
4978
|
-
fs10.rmSync(path14.join(paths.plugin, "skills"), { recursive: true, force: true });
|
|
4979
|
-
fs10.mkdirSync(path14.join(paths.plugin, PLUGIN_MANIFEST_DIR), { recursive: true });
|
|
4980
|
-
fs10.mkdirSync(path14.join(paths.plugin, "skills"), { recursive: true });
|
|
4981
|
-
fs10.writeFileSync(
|
|
4982
|
-
path14.join(paths.plugin, PLUGIN_MANIFEST_DIR, "plugin.json"),
|
|
4983
|
-
`${JSON.stringify(
|
|
4984
|
-
{
|
|
4985
|
-
name: "vibeflow-library",
|
|
4986
|
-
version: "1.0.0",
|
|
4987
|
-
description: "Skills delivered by VibeFlow for this task."
|
|
4988
|
-
},
|
|
4989
|
-
null,
|
|
4990
|
-
2
|
|
4991
|
-
)}
|
|
4992
|
-
`
|
|
4993
|
-
);
|
|
4994
|
-
for (const entry of enabled) {
|
|
4995
|
-
fs10.cpSync(entry.path, path14.join(paths.plugin, "skills", entry.name), {
|
|
4996
|
-
recursive: true,
|
|
4997
|
-
dereference: true
|
|
4998
|
-
});
|
|
4999
|
-
}
|
|
5000
|
-
return { pluginDir: paths.plugin, skills: enabled.map((e) => e.name) };
|
|
5001
|
-
}
|
|
5002
|
-
function linkOrSkip(target, linkPath) {
|
|
5003
|
-
if (!fs10.existsSync(target)) return false;
|
|
5004
|
-
const source = path14.resolve(target);
|
|
5005
|
-
const attempts = fs10.statSync(source).isDirectory() ? [
|
|
5006
|
-
() => fs10.symlinkSync(source, linkPath, "junction"),
|
|
5007
|
-
() => fs10.cpSync(source, linkPath, { recursive: true, dereference: true })
|
|
5008
|
-
] : [
|
|
5009
|
-
() => fs10.symlinkSync(source, linkPath),
|
|
5010
|
-
() => fs10.linkSync(source, linkPath),
|
|
5011
|
-
() => fs10.copyFileSync(source, linkPath)
|
|
5012
|
-
];
|
|
5013
|
-
for (const attempt of attempts) {
|
|
5014
|
-
try {
|
|
5015
|
-
fs10.rmSync(linkPath, { recursive: true, force: true });
|
|
5016
|
-
attempt();
|
|
5017
|
-
return true;
|
|
5018
|
-
} catch {
|
|
5019
|
-
}
|
|
5020
|
-
}
|
|
5021
|
-
return false;
|
|
5022
|
-
}
|
|
5023
|
-
function buildCodexHome(root, worktreePath, userCodexHome = path14.join(os3.homedir(), ".codex")) {
|
|
5024
|
-
const paths = libraryPaths(root);
|
|
5025
|
-
const skillsDir = path14.join(paths.codexHome, "skills");
|
|
5026
|
-
fs10.rmSync(skillsDir, { recursive: true, force: true });
|
|
5027
|
-
fs10.mkdirSync(skillsDir, { recursive: true });
|
|
5028
|
-
for (const file of ["auth.json", "config.toml"]) {
|
|
5029
|
-
linkOrSkip(path14.join(userCodexHome, file), path14.join(paths.codexHome, file));
|
|
5030
|
-
}
|
|
5031
|
-
const result = {
|
|
5032
|
-
codexHome: paths.codexHome,
|
|
5033
|
-
project: [],
|
|
5034
|
-
user: [],
|
|
5035
|
-
library: [],
|
|
5036
|
-
shadowed: []
|
|
5037
|
-
};
|
|
5038
|
-
const claimed = /* @__PURE__ */ new Map();
|
|
5039
|
-
const projectDir = worktreePath ? projectSkillsDir(worktreePath) : void 0;
|
|
5040
|
-
if (projectDir) {
|
|
5041
|
-
for (const name of skillNamesIn(projectDir)) {
|
|
5042
|
-
if (linkOrSkip(path14.join(projectDir, name), path14.join(skillsDir, name))) {
|
|
5043
|
-
result.project.push(name);
|
|
5044
|
-
claimed.set(name, "project");
|
|
5045
|
-
}
|
|
5046
|
-
}
|
|
5047
|
-
}
|
|
5048
|
-
const userDir = path14.join(userCodexHome, "skills");
|
|
5049
|
-
for (const name of skillNamesIn(userDir)) {
|
|
5050
|
-
const owner = claimed.get(name);
|
|
5051
|
-
if (owner) {
|
|
5052
|
-
result.shadowed.push({ name, keptFrom: owner, dropped: "user" });
|
|
5053
|
-
continue;
|
|
5054
|
-
}
|
|
5055
|
-
if (linkOrSkip(path14.join(userDir, name), path14.join(skillsDir, name))) {
|
|
5056
|
-
result.user.push(name);
|
|
5057
|
-
claimed.set(name, "user");
|
|
5058
|
-
}
|
|
5059
|
-
}
|
|
5060
|
-
for (const entry of listLibrary(root)) {
|
|
5061
|
-
if (entry.kind !== "skill" || !entry.enabled) continue;
|
|
5062
|
-
const owner = claimed.get(entry.name);
|
|
5063
|
-
if (owner) {
|
|
5064
|
-
result.shadowed.push({ name: entry.name, keptFrom: owner, dropped: "library" });
|
|
5065
|
-
continue;
|
|
5066
|
-
}
|
|
5067
|
-
fs10.cpSync(entry.path, path14.join(skillsDir, entry.name), {
|
|
5068
|
-
recursive: true,
|
|
5069
|
-
dereference: true
|
|
5070
|
-
});
|
|
5071
|
-
result.library.push(entry.name);
|
|
5072
|
-
}
|
|
5073
|
-
return result;
|
|
5074
|
-
}
|
|
5075
|
-
function libraryLaunchInfoAt(root, worktreePath, userCodexHome) {
|
|
5076
|
-
const entries = listLibrary(root).filter((e) => e.enabled);
|
|
5077
|
-
if (entries.length === 0) return null;
|
|
5078
|
-
const { pluginDir } = buildPluginDir(root);
|
|
5079
|
-
const { codexHome } = buildCodexHome(root, worktreePath, userCodexHome);
|
|
5080
|
-
const scripts = entries.filter((e) => e.kind === "script").map((e) => ({ name: e.name, path: e.path, description: e.description }));
|
|
5081
|
-
const promptBodies = entries.filter((e) => e.kind === "prompt").map((e) => readEntryContent(root, "prompt", e.name).trim()).filter(Boolean);
|
|
5082
|
-
const lines = [...promptBodies];
|
|
5083
|
-
if (scripts.length > 0) {
|
|
5084
|
-
lines.push(
|
|
5085
|
-
"\u53EF\u7528\u7684\u5DE5\u5177\u8173\u672C\uFF08\u9700\u8981\u6642\u81EA\u884C\u57F7\u884C\uFF0C\u4E0D\u9700\u8981\u5C31\u5225\u8DD1\uFF09\uFF1A",
|
|
5086
|
-
...scripts.map((s) => `- ${s.path}${s.description ? ` \u2014 ${s.description}` : ""}`)
|
|
5087
|
-
);
|
|
5088
|
-
}
|
|
5089
|
-
return {
|
|
5090
|
-
pluginDir,
|
|
5091
|
-
codexHome,
|
|
5092
|
-
libraryDir: root,
|
|
5093
|
-
scripts,
|
|
5094
|
-
promptText: lines.join("\n\n")
|
|
5095
|
-
};
|
|
5096
|
-
}
|
|
5097
|
-
async function libraryLaunchInfo(worktreePath) {
|
|
5098
|
-
return libraryLaunchInfoAt(await libraryRoot(), worktreePath);
|
|
5099
|
-
}
|
|
5100
5000
|
|
|
5101
5001
|
// packages/core/src/library-builtins.ts
|
|
5102
5002
|
function builtinSkillsDir() {
|
|
@@ -5202,19 +5102,19 @@ async function syncBuiltinsAtStartup() {
|
|
|
5202
5102
|
|
|
5203
5103
|
// packages/core/src/service.ts
|
|
5204
5104
|
import fs19 from "fs";
|
|
5205
|
-
import
|
|
5105
|
+
import os7 from "os";
|
|
5206
5106
|
import path23 from "path";
|
|
5207
5107
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
5208
5108
|
|
|
5209
5109
|
// packages/core/src/agent-models.ts
|
|
5210
5110
|
import fs13 from "fs";
|
|
5211
|
-
import
|
|
5111
|
+
import os5 from "os";
|
|
5212
5112
|
import path17 from "path";
|
|
5213
5113
|
|
|
5214
5114
|
// packages/core/src/claude-models.ts
|
|
5215
5115
|
init_effort();
|
|
5216
5116
|
import fs12 from "fs";
|
|
5217
|
-
import
|
|
5117
|
+
import os3 from "os";
|
|
5218
5118
|
import path16 from "path";
|
|
5219
5119
|
|
|
5220
5120
|
// packages/core/src/json-lines-process.ts
|
|
@@ -5319,7 +5219,7 @@ var CLAUDE_MODELS_TIMEOUT_MS = 15e3;
|
|
|
5319
5219
|
var REQUEST_ID = "vibeflow-models";
|
|
5320
5220
|
var CLAUDE_ARGS = ["-p", "--input-format", "stream-json", "--output-format", "stream-json", "--verbose"];
|
|
5321
5221
|
function openClaude() {
|
|
5322
|
-
const cwd = fs12.mkdtempSync(path16.join(
|
|
5222
|
+
const cwd = fs12.mkdtempSync(path16.join(os3.tmpdir(), "vf-claude-models-"));
|
|
5323
5223
|
return spawnJsonLines("claude", CLAUDE_ARGS, {
|
|
5324
5224
|
cwd,
|
|
5325
5225
|
timeoutMs: CLAUDE_MODELS_TIMEOUT_MS,
|
|
@@ -5349,7 +5249,7 @@ function parseClaudeInitialize(message) {
|
|
|
5349
5249
|
seen.add(id);
|
|
5350
5250
|
const label = typeof entry.displayName === "string" && entry.displayName.trim() ? entry.displayName.trim() : id;
|
|
5351
5251
|
const description = typeof entry.description === "string" && entry.description.trim() ? entry.description.trim() : void 0;
|
|
5352
|
-
const levels = entry.supportsEffort === true && Array.isArray(entry.supportedEffortLevels) ? entry.supportedEffortLevels.filter(
|
|
5252
|
+
const levels = entry.supportsEffort === true && Array.isArray(entry.supportedEffortLevels) ? entry.supportedEffortLevels.filter(isManualEffort) : [];
|
|
5353
5253
|
const isDefault = !defaultMarked && defaultResolved !== void 0 && entry.resolvedModel === defaultResolved;
|
|
5354
5254
|
if (isDefault) defaultMarked = true;
|
|
5355
5255
|
models.push({ id, label, ...description ? { description } : {}, efforts: levels, ...isDefault ? { isDefault } : {} });
|
|
@@ -5370,7 +5270,7 @@ async function fetchClaudeModels(open = openClaude) {
|
|
|
5370
5270
|
// packages/core/src/codex-models.ts
|
|
5371
5271
|
init_effort();
|
|
5372
5272
|
init_env();
|
|
5373
|
-
import
|
|
5273
|
+
import os4 from "os";
|
|
5374
5274
|
var CODEX_MODELS_TIMEOUT_MS = 2e4;
|
|
5375
5275
|
var MAX_PAGES = 20;
|
|
5376
5276
|
var CodexLoginRequiredError = class extends Error {
|
|
@@ -5383,7 +5283,7 @@ function codexAppServerCommand() {
|
|
|
5383
5283
|
return {
|
|
5384
5284
|
bin: "codex",
|
|
5385
5285
|
args: ["app-server", "--listen", "stdio://"],
|
|
5386
|
-
cwd:
|
|
5286
|
+
cwd: os4.homedir(),
|
|
5387
5287
|
env: execEnv()
|
|
5388
5288
|
};
|
|
5389
5289
|
}
|
|
@@ -5412,7 +5312,7 @@ function parseCodexModelPage(result) {
|
|
|
5412
5312
|
const id = entry.id.trim();
|
|
5413
5313
|
const label = typeof entry.displayName === "string" && entry.displayName.trim() ? entry.displayName.trim() : id;
|
|
5414
5314
|
const description = typeof entry.description === "string" && entry.description.trim() ? entry.description.trim() : void 0;
|
|
5415
|
-
const efforts = Array.isArray(entry.supportedReasoningEfforts) ? entry.supportedReasoningEfforts.map((e) => isRecord2(e) ? e.reasoningEffort : void 0).filter(
|
|
5315
|
+
const efforts = Array.isArray(entry.supportedReasoningEfforts) ? entry.supportedReasoningEfforts.map((e) => isRecord2(e) ? e.reasoningEffort : void 0).filter(isManualEffort) : void 0;
|
|
5416
5316
|
models.push({
|
|
5417
5317
|
id,
|
|
5418
5318
|
label,
|
|
@@ -5472,7 +5372,7 @@ function builtinModels(id) {
|
|
|
5472
5372
|
}
|
|
5473
5373
|
function defaultCodexHome() {
|
|
5474
5374
|
const configured = process.env.CODEX_HOME?.trim();
|
|
5475
|
-
return configured ? configured : path17.join(
|
|
5375
|
+
return configured ? configured : path17.join(os5.homedir(), ".codex");
|
|
5476
5376
|
}
|
|
5477
5377
|
function parseCodexCatalog(raw) {
|
|
5478
5378
|
const body = JSON.parse(raw);
|
|
@@ -5558,118 +5458,68 @@ function createModelCatalog(opts) {
|
|
|
5558
5458
|
}
|
|
5559
5459
|
|
|
5560
5460
|
// packages/core/src/jev-router.ts
|
|
5461
|
+
init_effort();
|
|
5561
5462
|
init_launch();
|
|
5562
5463
|
var API_URL = "https://api.typesafe.ai/v1/systemone";
|
|
5563
5464
|
var MAX_TASK_CHARS = 12e3;
|
|
5564
|
-
var MAX_PLAN_CHARS = 8e3;
|
|
5565
|
-
function tier(model, agent) {
|
|
5566
|
-
const name = `${model.id} ${model.label}`.toLowerCase();
|
|
5567
|
-
if (/haiku|mini|nano|luna|flash/.test(name)) return 0;
|
|
5568
|
-
if (/opus|astra|pro\b/.test(name)) return 2;
|
|
5569
|
-
if (agent === "codex" && /gpt-5\.5|gpt-5\.4(?!-mini)/.test(name)) return 2;
|
|
5570
|
-
return 1;
|
|
5571
|
-
}
|
|
5572
|
-
function routeCandidates(agent, models) {
|
|
5573
|
-
const valid = models.filter((m) => /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(m.id));
|
|
5574
|
-
const byTier = /* @__PURE__ */ new Map();
|
|
5575
|
-
for (const model of valid) {
|
|
5576
|
-
const rank = tier(model, agent);
|
|
5577
|
-
if (!byTier.has(rank)) byTier.set(rank, model);
|
|
5578
|
-
}
|
|
5579
|
-
return [...byTier.entries()].sort(([a], [b]) => a - b).map(([, model]) => model);
|
|
5580
|
-
}
|
|
5581
|
-
function isChoice(value) {
|
|
5582
|
-
return !!value && typeof value === "object" && value.type === "choice" && typeof value.choice === "string";
|
|
5583
|
-
}
|
|
5584
5465
|
function createJevRouter(opts = {}) {
|
|
5585
5466
|
const getApiKey = opts.getApiKey ?? (() => opts.apiKey ?? process.env.TYPESAFE_API_KEY?.trim());
|
|
5586
5467
|
const fetcher = opts.fetcher ?? fetch;
|
|
5587
|
-
const planner = opts.planner ?? (async (agent, model, prompt, cwd) => {
|
|
5588
|
-
const args = agent === "claude" ? ["-p", "--model", model, "--permission-mode", "plan"] : ["exec", "--model", model, "--sandbox", "read-only", "--skip-git-repo-check", "-"];
|
|
5589
|
-
return (opts.printAgent ?? runAgentPrint)(agent, args, prompt, { cwd, timeout: 12e4, maxBuffer: 128 * 1024 });
|
|
5590
|
-
});
|
|
5591
|
-
async function ask(state, questions) {
|
|
5592
|
-
const apiKey = getApiKey();
|
|
5593
|
-
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");
|
|
5594
|
-
const response = await fetcher(API_URL, {
|
|
5595
|
-
method: "POST",
|
|
5596
|
-
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
5597
|
-
body: JSON.stringify({ model: "jev-latest", state, questions }),
|
|
5598
|
-
signal: AbortSignal.timeout(15e3)
|
|
5599
|
-
});
|
|
5600
|
-
if (!response.ok) throw new Error(`Jev API \u56DE\u61C9 ${response.status}`);
|
|
5601
|
-
const body = await response.json();
|
|
5602
|
-
if (!body.answers) throw new Error("Jev API \u6C92\u6709\u56DE\u50B3\u5224\u65B7");
|
|
5603
|
-
return body.answers;
|
|
5604
|
-
}
|
|
5605
5468
|
return {
|
|
5606
5469
|
get enabled() {
|
|
5607
5470
|
return Boolean(getApiKey());
|
|
5608
5471
|
},
|
|
5609
|
-
async route(task, catalog
|
|
5610
|
-
const
|
|
5611
|
-
const
|
|
5612
|
-
if (
|
|
5613
|
-
const expensive = candidates[candidates.length - 1];
|
|
5614
|
-
const taskText = buildPrompt(task).slice(0, MAX_TASK_CHARS);
|
|
5472
|
+
async route(task, catalog) {
|
|
5473
|
+
const model = modelFor(catalog, taskModel(task));
|
|
5474
|
+
const levels = selectableEfforts(model);
|
|
5475
|
+
if (levels.length === 0) return { status: "fallback", reason: "\u76EE\u524D\u6A21\u578B\u4E0D\u652F\u63F4\u8ABF\u6574 effort" };
|
|
5615
5476
|
try {
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5477
|
+
const apiKey = getApiKey();
|
|
5478
|
+
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");
|
|
5479
|
+
const response = await fetcher(API_URL, {
|
|
5480
|
+
method: "POST",
|
|
5481
|
+
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
5482
|
+
body: JSON.stringify({
|
|
5483
|
+
model: "jev-latest",
|
|
5484
|
+
state: {
|
|
5485
|
+
task: buildPrompt(task).slice(0, MAX_TASK_CHARS),
|
|
5486
|
+
agent: task.agentCli === "codex" ? "codex" : "claude",
|
|
5487
|
+
currentModel: model?.id ?? taskModel(task) ?? "CLI default (catalog unavailable)"
|
|
5488
|
+
},
|
|
5489
|
+
questions: {
|
|
5490
|
+
effort: {
|
|
5491
|
+
type: "choice",
|
|
5492
|
+
instructions: "Choose the lowest reasoning effort likely to complete this software task correctly on the current model. Increase effort for complexity, ambiguity, or risk.",
|
|
5493
|
+
criteria: Object.fromEntries(levels.map((level) => [level, effortDescription(level)]))
|
|
5494
|
+
}
|
|
5633
5495
|
}
|
|
5634
|
-
}
|
|
5496
|
+
}),
|
|
5497
|
+
signal: AbortSignal.timeout(15e3)
|
|
5635
5498
|
});
|
|
5636
|
-
if (!
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
const instruction = `Read the repository and make a concise implementation plan for the following task. Do not edit files. Identify unclear requirements, affected areas, and verification. Return only the plan.
|
|
5642
|
-
|
|
5643
|
-
${taskText}`;
|
|
5644
|
-
plan = (await planner(agent, expensive.id, instruction, task.worktreePath)).trim().slice(0, MAX_PLAN_CHARS);
|
|
5645
|
-
if (!plan) throw new Error("\u898F\u5283\u6A21\u578B\u6C92\u6709\u56DE\u50B3\u8A08\u756B");
|
|
5499
|
+
if (!response.ok) throw new Error(`Jev API \u56DE\u61C9 ${response.status}`);
|
|
5500
|
+
const body = await response.json();
|
|
5501
|
+
const choice = body.answers?.effort;
|
|
5502
|
+
if (choice?.type !== "choice" || !levels.includes(choice.choice)) {
|
|
5503
|
+
throw new Error("Jev \u9078\u4E86\u76EE\u524D\u6A21\u578B\u4E0D\u652F\u63F4\u7684 effort");
|
|
5646
5504
|
}
|
|
5647
|
-
|
|
5648
|
-
const options = Object.fromEntries(candidates.map((m) => [
|
|
5649
|
-
m.id,
|
|
5650
|
-
`${m.label}; relative cost tier ${tier(m, agent) + 1}/3 (${tier(m, agent) === 2 ? "highest capability" : tier(m, agent) === 0 ? "lowest cost" : "balanced"})`
|
|
5651
|
-
]));
|
|
5652
|
-
const second = await ask({ task: taskText, complexity: first.complexity.choice, plan }, {
|
|
5653
|
-
model: {
|
|
5654
|
-
type: "choice",
|
|
5655
|
-
instructions: "Choose the lowest-cost available model likely to implement this task correctly. Prefer more capable models as complexity or uncertainty rises.",
|
|
5656
|
-
criteria: options
|
|
5657
|
-
}
|
|
5658
|
-
});
|
|
5659
|
-
if (!isChoice(second.model) || !candidates.some((m) => m.id === second.model.choice)) {
|
|
5660
|
-
throw new Error("Jev \u9078\u4E86\u4E0D\u5728\u6A21\u578B\u6E05\u55AE\u4E2D\u7684\u6A21\u578B");
|
|
5661
|
-
}
|
|
5662
|
-
return {
|
|
5663
|
-
status: "routed",
|
|
5664
|
-
model: second.model.choice,
|
|
5665
|
-
...plan ? { plannerModel: expensive.id, plan } : {}
|
|
5666
|
-
};
|
|
5505
|
+
return { status: "routed", effort: choice.choice };
|
|
5667
5506
|
} catch (err) {
|
|
5668
5507
|
return { status: "fallback", reason: err instanceof Error ? err.message : String(err) };
|
|
5669
5508
|
}
|
|
5670
5509
|
}
|
|
5671
5510
|
};
|
|
5672
5511
|
}
|
|
5512
|
+
function effortDescription(level) {
|
|
5513
|
+
const descriptions = {
|
|
5514
|
+
low: "Routine, small and well scoped work",
|
|
5515
|
+
medium: "Typical development with limited uncertainty",
|
|
5516
|
+
high: "Complex debugging or several interacting files",
|
|
5517
|
+
xhigh: "Difficult design or extensive reasoning",
|
|
5518
|
+
max: "The hardest, highest risk tasks",
|
|
5519
|
+
ultra: "Deepest reasoning with automatic delegation"
|
|
5520
|
+
};
|
|
5521
|
+
return descriptions[level];
|
|
5522
|
+
}
|
|
5673
5523
|
|
|
5674
5524
|
// packages/core/src/jev-credentials.ts
|
|
5675
5525
|
import fs14 from "fs";
|
|
@@ -6635,7 +6485,7 @@ init_launch();
|
|
|
6635
6485
|
init_progress();
|
|
6636
6486
|
init_launch();
|
|
6637
6487
|
import fs18 from "fs";
|
|
6638
|
-
import
|
|
6488
|
+
import os6 from "os";
|
|
6639
6489
|
import path22 from "path";
|
|
6640
6490
|
var SINCE_SLACK_MS = 5e3;
|
|
6641
6491
|
function claudeProjectDir(home, cwd) {
|
|
@@ -6736,7 +6586,7 @@ function codexDayDirs(sessionsRoot, since) {
|
|
|
6736
6586
|
return days;
|
|
6737
6587
|
}
|
|
6738
6588
|
function createProgressTracker(opts) {
|
|
6739
|
-
const home = opts.homeDir ??
|
|
6589
|
+
const home = opts.homeDir ?? os6.homedir();
|
|
6740
6590
|
const codexHomes = opts.codexHomes ?? (() => [path22.join(home, ".codex")]);
|
|
6741
6591
|
const pollMs = opts.pollMs ?? 2e3;
|
|
6742
6592
|
const entries = /* @__PURE__ */ new Map();
|
|
@@ -6990,7 +6840,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6990
6840
|
libraryCodexHome = libraryPaths(root).codexHome;
|
|
6991
6841
|
}).catch(() => {
|
|
6992
6842
|
});
|
|
6993
|
-
const home = homeDir ??
|
|
6843
|
+
const home = homeDir ?? os7.homedir();
|
|
6994
6844
|
const progress = createProgressTracker({
|
|
6995
6845
|
homeDir: home,
|
|
6996
6846
|
codexHomes: () => [path23.join(home, ".codex"), ...libraryCodexHome ? [libraryCodexHome] : []],
|
|
@@ -7067,16 +6917,16 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7067
6917
|
requireTask(key.split(":")[0]);
|
|
7068
6918
|
return key;
|
|
7069
6919
|
}
|
|
7070
|
-
function launchEffort(task,
|
|
7071
|
-
const
|
|
7072
|
-
|
|
6920
|
+
function launchEffort(task, route) {
|
|
6921
|
+
const effort = task.effort === "auto" ? route?.effort : task.effort;
|
|
6922
|
+
const model = models.findModel(taskAgent(task), taskModel(task));
|
|
6923
|
+
return model?.efforts ? clampEffort(effort, model.efforts) : effort;
|
|
7073
6924
|
}
|
|
7074
6925
|
async function launchCommand(task, intent) {
|
|
7075
6926
|
const settings = getSettings();
|
|
7076
|
-
const library = await libraryLaunchInfo(task.worktreePath);
|
|
7077
6927
|
const boardCli = await boardCliLaunchInfo();
|
|
7078
|
-
let route = task.
|
|
7079
|
-
if (
|
|
6928
|
+
let route = task.jevRoute?.status === "routing" ? void 0 : task.jevRoute;
|
|
6929
|
+
if (task.effort === "auto" && !intent.resume && intent.includeTaskPrompt !== false) {
|
|
7080
6930
|
let pending = routing.get(task.id);
|
|
7081
6931
|
if (!pending) {
|
|
7082
6932
|
const setRoute = (jevRoute) => {
|
|
@@ -7084,9 +6934,9 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7084
6934
|
bus.emit("state:changed", getState());
|
|
7085
6935
|
};
|
|
7086
6936
|
pending = (async () => {
|
|
7087
|
-
setRoute({ status: "routing"
|
|
6937
|
+
setRoute({ status: "routing" });
|
|
7088
6938
|
const candidateModels = (await (router.enabled === false ? models.get(taskAgent(task)) : models.refresh(taskAgent(task)))).models;
|
|
7089
|
-
const selected = await router.route(task, candidateModels
|
|
6939
|
+
const selected = await router.route(task, candidateModels);
|
|
7090
6940
|
setRoute(selected);
|
|
7091
6941
|
return selected;
|
|
7092
6942
|
})().catch((err) => {
|
|
@@ -7097,24 +6947,21 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7097
6947
|
}
|
|
7098
6948
|
route = await pending;
|
|
7099
6949
|
}
|
|
7100
|
-
const selectedModel = task.model?.trim() ? taskModel(task) : route?.model;
|
|
7101
6950
|
return buildAgentCommand(
|
|
7102
|
-
{ ...task, model:
|
|
6951
|
+
{ ...task, model: taskModel(task), effort: launchEffort(task, route) },
|
|
7103
6952
|
settings.systemPrompt ?? "",
|
|
7104
6953
|
{
|
|
7105
6954
|
resume: intent.resume === true,
|
|
7106
6955
|
includeTaskPrompt: intent.includeTaskPrompt !== false,
|
|
7107
|
-
library: library ?? void 0,
|
|
7108
6956
|
boardCli,
|
|
7109
|
-
autoMode: task.autoMode ?? settings.autoMode
|
|
7110
|
-
preflightPlan: !intent.resume ? route?.plan : void 0
|
|
6957
|
+
autoMode: task.autoMode ?? settings.autoMode
|
|
7111
6958
|
},
|
|
7112
6959
|
task.workspacePath
|
|
7113
6960
|
);
|
|
7114
6961
|
}
|
|
7115
6962
|
function claudeSessionFile(cwd, sessionId) {
|
|
7116
6963
|
const munged = cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
7117
|
-
return path23.join(
|
|
6964
|
+
return path23.join(os7.homedir(), ".claude", "projects", munged, `${sessionId}.jsonl`);
|
|
7118
6965
|
}
|
|
7119
6966
|
async function removeTaskWorktree(task) {
|
|
7120
6967
|
if (!task.projectPath || !task.worktreePath) return;
|
|
@@ -7412,6 +7259,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7412
7259
|
command = (await launchCommand(task, intent)).replace(/\r$/, "");
|
|
7413
7260
|
}
|
|
7414
7261
|
}
|
|
7262
|
+
if (p.launch) ensureTaskArtifactDirs(task);
|
|
7415
7263
|
const result = await sessions.start(key, {
|
|
7416
7264
|
cwd,
|
|
7417
7265
|
command,
|
|
@@ -8106,6 +7954,28 @@ async function checkForUpdate(packageName2, currentVersion, query = async (name)
|
|
|
8106
7954
|
if (typeof latest !== "string" || !isNewerVersion(latest, currentVersion)) return null;
|
|
8107
7955
|
return { currentVersion, latestVersion: latest };
|
|
8108
7956
|
}
|
|
7957
|
+
function createUpdateMonitor(options) {
|
|
7958
|
+
const check = options.check ?? ((name, version) => checkForUpdate(name, version));
|
|
7959
|
+
let available = null;
|
|
7960
|
+
let stopped = false;
|
|
7961
|
+
return {
|
|
7962
|
+
supported: options.packageName !== null,
|
|
7963
|
+
status: () => available,
|
|
7964
|
+
/** Rejects when the registry cannot be reached; the last answer is kept. */
|
|
7965
|
+
async refresh() {
|
|
7966
|
+
if (!options.packageName) return { status: "unsupported", currentVersion: options.currentVersion };
|
|
7967
|
+
const next = await check(options.packageName, options.currentVersion);
|
|
7968
|
+
if (!stopped && next?.latestVersion !== available?.latestVersion) {
|
|
7969
|
+
available = next;
|
|
7970
|
+
options.onChange(next);
|
|
7971
|
+
}
|
|
7972
|
+
return next ? { status: "available", ...next } : { status: "current", currentVersion: options.currentVersion };
|
|
7973
|
+
},
|
|
7974
|
+
stop() {
|
|
7975
|
+
stopped = true;
|
|
7976
|
+
}
|
|
7977
|
+
};
|
|
7978
|
+
}
|
|
8109
7979
|
|
|
8110
7980
|
// packages/cli/src/update-terminal.ts
|
|
8111
7981
|
import { spawn as spawn8 } from "node:child_process";
|
|
@@ -8208,22 +8078,14 @@ async function startHost(options) {
|
|
|
8208
8078
|
stateDir: options.userDataDir
|
|
8209
8079
|
});
|
|
8210
8080
|
const core = createCore({ sessions, bus, version: options.version });
|
|
8211
|
-
let availableUpdate = null;
|
|
8212
8081
|
let updateTimer = null;
|
|
8213
|
-
|
|
8214
|
-
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
if (next?.latestVersion !== availableUpdate?.latestVersion) {
|
|
8221
|
-
availableUpdate = next;
|
|
8222
|
-
bus.emit("update:available", next);
|
|
8223
|
-
}
|
|
8224
|
-
} catch {
|
|
8225
|
-
}
|
|
8226
|
-
};
|
|
8082
|
+
const updates = createUpdateMonitor({
|
|
8083
|
+
packageName: options.sourceRoot || !options.cliEntry ? null : packageName(path26.dirname(path26.dirname(options.cliEntry))),
|
|
8084
|
+
currentVersion: options.version,
|
|
8085
|
+
onChange: (update) => bus.emit("update:available", update)
|
|
8086
|
+
});
|
|
8087
|
+
const checkUpdates = () => void updates.refresh().catch(() => {
|
|
8088
|
+
});
|
|
8227
8089
|
let stopping = null;
|
|
8228
8090
|
const handlers = {
|
|
8229
8091
|
...core.handlers,
|
|
@@ -8237,9 +8099,10 @@ async function startHost(options) {
|
|
|
8237
8099
|
backend: sessions.kind,
|
|
8238
8100
|
startedAt: lock.startedAt
|
|
8239
8101
|
}),
|
|
8240
|
-
"host:updateStatus": () =>
|
|
8102
|
+
"host:updateStatus": () => updates.status(),
|
|
8103
|
+
"host:checkUpdate": () => updates.refresh(),
|
|
8241
8104
|
"host:openUpdateTerminal": () => {
|
|
8242
|
-
if (!
|
|
8105
|
+
if (!updates.status()) throw new Error("\u76EE\u524D\u6C92\u6709\u53EF\u5F9E\u5168\u57DF npm \u5B89\u88DD\u66F4\u65B0\u7684\u7248\u672C\u3002");
|
|
8243
8106
|
return openUpdateTerminal();
|
|
8244
8107
|
}
|
|
8245
8108
|
};
|
|
@@ -8255,12 +8118,12 @@ async function startHost(options) {
|
|
|
8255
8118
|
updateLock(options.userDataDir, lock);
|
|
8256
8119
|
const stopWatch = core.watchStore();
|
|
8257
8120
|
core.warmModelCatalog();
|
|
8258
|
-
if (
|
|
8259
|
-
|
|
8260
|
-
updateTimer = setInterval(
|
|
8121
|
+
if (updates.supported) {
|
|
8122
|
+
checkUpdates();
|
|
8123
|
+
updateTimer = setInterval(checkUpdates, UPDATE_CHECK_INTERVAL_MS);
|
|
8261
8124
|
}
|
|
8262
8125
|
const stop = () => stopping ??= (async () => {
|
|
8263
|
-
|
|
8126
|
+
updates.stop();
|
|
8264
8127
|
if (updateTimer) clearInterval(updateTimer);
|
|
8265
8128
|
stopWatch();
|
|
8266
8129
|
core.shutdown();
|
|
@@ -8579,7 +8442,7 @@ Usage:
|
|
|
8579
8442
|
vibeflow doctor Check Node, git, tmux, node-pty and the agent CLIs
|
|
8580
8443
|
(--skip agents,web,\u2026 leaves checks out, e.g. on CI)
|
|
8581
8444
|
vibeflow update Install the latest global npm release (restart the host afterward)
|
|
8582
|
-
vibeflow task \u2026 Create / update cards (vibeflow task --help)
|
|
8445
|
+
vibeflow task \u2026 Create / update cards; add artifacts (vibeflow task --help)
|
|
8583
8446
|
|
|
8584
8447
|
Options:
|
|
8585
8448
|
--profile dev|prod Store profile (dev = the "(development)" store npm run dev uses)
|