@kw-yeh/vibeflow 4.11.13 → 4.11.16
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 +212 -300
- package/dist/web/404/index.html +1 -1
- package/dist/web/404.html +1 -1
- package/dist/web/_next/static/{JAs_fpQU_6i75zb8sj3G4 → TTJDd4vO-NmQBjEis26sl}/_buildManifest.js +1 -1
- package/dist/web/_next/static/chunks/pages/{_app-8cf225b59c19ec6a.js → _app-0c60752b4c05d52e.js} +1 -1
- package/dist/web/_next/static/chunks/pages/home-a17a5a665f0aa6bd.js +13 -0
- package/dist/web/_next/static/css/3cafb8bddc730b60.css +2 -0
- package/dist/web/home/index.html +1 -1
- package/package.json +1 -1
- package/dist/web/_next/static/chunks/pages/home-273ce6c00cea0e89.js +0 -13
- package/dist/web/_next/static/css/60e89d492b3b3ef3.css +0 -2
- /package/dist/web/_next/static/{JAs_fpQU_6i75zb8sj3G4 → TTJDd4vO-NmQBjEis26sl}/_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
|
+
openUpdateTerminal: () => t.invoke("host:openUpdateTerminal"),
|
|
2473
2461
|
onUpdateAvailable: (callback) => t.on("update:available", (payload) => callback(payload)),
|
|
2474
2462
|
/**
|
|
2475
2463
|
* Fired when an external write (e.g. CLI) changes the store backing file.
|
|
@@ -3336,6 +3324,30 @@ var SNIFF_BYTES = 8 * 1024;
|
|
|
3336
3324
|
function agentArtifactsPath(baseDir, worktreePath) {
|
|
3337
3325
|
return path11.join(baseDir, `${path11.basename(worktreePath)}${ARTIFACTS_DIR_SUFFIX2}`);
|
|
3338
3326
|
}
|
|
3327
|
+
function ensureTaskArtifactDirs(task) {
|
|
3328
|
+
if (!task.worktreePath) throw new Error("\u4EFB\u52D9\u5C1A\u672A\u5EFA\u7ACB worktree");
|
|
3329
|
+
const dir = task.workspacePath ? agentArtifactsPath(task.workspacePath, task.worktreePath) : path11.join(task.worktreePath, ARTIFACTS_FALLBACK_DIR2);
|
|
3330
|
+
fs7.mkdirSync(path11.join(dir, SCRATCH_DIR_NAME2), { recursive: true });
|
|
3331
|
+
return dir;
|
|
3332
|
+
}
|
|
3333
|
+
function addTaskArtifact(task, filePath) {
|
|
3334
|
+
const source = path11.resolve(filePath);
|
|
3335
|
+
const stat = fs7.lstatSync(source);
|
|
3336
|
+
if (!stat.isFile()) throw new Error("Artifact \u4F86\u6E90\u5FC5\u9808\u662F\u4E00\u822C\u6A94\u6848");
|
|
3337
|
+
const dir = ensureTaskArtifactDirs(task);
|
|
3338
|
+
if (path11.dirname(source) === dir) return source;
|
|
3339
|
+
const { name, ext } = path11.parse(source);
|
|
3340
|
+
for (let index = 0; index < 1e3; index += 1) {
|
|
3341
|
+
const destination = path11.join(dir, index === 0 ? `${name}${ext}` : `${name}-${index}${ext}`);
|
|
3342
|
+
try {
|
|
3343
|
+
fs7.copyFileSync(source, destination, fs7.constants.COPYFILE_EXCL);
|
|
3344
|
+
return destination;
|
|
3345
|
+
} catch (error) {
|
|
3346
|
+
if (error.code !== "EEXIST") throw error;
|
|
3347
|
+
}
|
|
3348
|
+
}
|
|
3349
|
+
throw new Error("Artifact \u8CC7\u6599\u593E\u6709\u592A\u591A\u540C\u540D\u6A94\u6848");
|
|
3350
|
+
}
|
|
3339
3351
|
function mediaKind(filePath, size) {
|
|
3340
3352
|
const extension = path11.extname(filePath).toLowerCase();
|
|
3341
3353
|
const imageMime = IMAGE_MIME[extension];
|
|
@@ -4271,7 +4283,7 @@ init_effort();
|
|
|
4271
4283
|
import { execFile as execFile6 } from "child_process";
|
|
4272
4284
|
import { promisify as promisify3 } from "util";
|
|
4273
4285
|
var pexec3 = promisify3(execFile6);
|
|
4274
|
-
var DEFAULT_TASK_EFFORT = "
|
|
4286
|
+
var DEFAULT_TASK_EFFORT = "auto";
|
|
4275
4287
|
var AGENT_CLIS = [
|
|
4276
4288
|
{
|
|
4277
4289
|
id: "claude",
|
|
@@ -4462,7 +4474,7 @@ function updateTaskFromInput(input) {
|
|
|
4462
4474
|
init_attachments();
|
|
4463
4475
|
var AGENT_IDS = AGENT_CLIS.map((agent) => agent.id);
|
|
4464
4476
|
var STATUSES = ["backlog", "in_progress", "done"];
|
|
4465
|
-
var SUBCOMMANDS = ["create", "update"];
|
|
4477
|
+
var SUBCOMMANDS = ["create", "update", "artifact"];
|
|
4466
4478
|
var MODES = ["existing", "new"];
|
|
4467
4479
|
var AUTO_MODES = ["on", "off"];
|
|
4468
4480
|
var TASK_USAGE = `
|
|
@@ -4471,6 +4483,7 @@ VibeFlow task commands
|
|
|
4471
4483
|
Usage:
|
|
4472
4484
|
vibeflow task create [options]
|
|
4473
4485
|
vibeflow task update [options]
|
|
4486
|
+
vibeflow task artifact add --file <path> [options]
|
|
4474
4487
|
|
|
4475
4488
|
task create options:
|
|
4476
4489
|
--project <path> Target project directory (required)
|
|
@@ -4484,7 +4497,7 @@ task create options:
|
|
|
4484
4497
|
--mode <mode> ${MODES.join(" | ")} (default: existing; "new" runs git init first)
|
|
4485
4498
|
--agent <id> Task agent: ${AGENT_IDS.join(" | ")} (default: claude)
|
|
4486
4499
|
--model <id> Task model (default: the agent's own default)
|
|
4487
|
-
--effort <level> ${AGENT_EFFORTS.join(" | ")} (default:
|
|
4500
|
+
--effort <level> ${AGENT_EFFORTS.join(" | ")} (default: auto, same as the UI)
|
|
4488
4501
|
--auto-mode <on|off> Let the agent act without asking for approval
|
|
4489
4502
|
(default: the board-wide setting, same as the UI)
|
|
4490
4503
|
--attach <path> Attach a file; repeat the flag for several files
|
|
@@ -4503,6 +4516,12 @@ task update options:
|
|
|
4503
4516
|
At least one of --title / --prompt / --status is required. Branch, worktree
|
|
4504
4517
|
and project path are provisioned on disk and cannot be changed here.
|
|
4505
4518
|
|
|
4519
|
+
task artifact add options:
|
|
4520
|
+
--file <path> Copy a file into the card's user-facing Artifacts folder
|
|
4521
|
+
--task <id> Card ID (defaults to VIBEFLOW_TASK_ID in a task shell)
|
|
4522
|
+
--store-path <dir> Store directory (defaults to VIBEFLOW_STORE_DIR in a task shell)
|
|
4523
|
+
--profile <name> dev | prod \u2014 when no store path is given
|
|
4524
|
+
|
|
4506
4525
|
Notes:
|
|
4507
4526
|
A card created with --status in_progress does NOT start running by itself.
|
|
4508
4527
|
Every launch is started by hand from the app.
|
|
@@ -4570,6 +4589,7 @@ async function taskCommand(argv) {
|
|
|
4570
4589
|
effort: { type: "string" },
|
|
4571
4590
|
"auto-mode": { type: "string" },
|
|
4572
4591
|
attach: { type: "string", multiple: true },
|
|
4592
|
+
file: { type: "string" },
|
|
4573
4593
|
"store-path": { type: "string" },
|
|
4574
4594
|
profile: { type: "string" },
|
|
4575
4595
|
help: { type: "boolean", short: "h" }
|
|
@@ -4581,13 +4601,24 @@ async function taskCommand(argv) {
|
|
|
4581
4601
|
fail("INVALID_ARGUMENT", err.message);
|
|
4582
4602
|
}
|
|
4583
4603
|
const { values, positionals } = parsed;
|
|
4584
|
-
const [sub] = positionals;
|
|
4604
|
+
const [sub, action] = positionals;
|
|
4585
4605
|
if (values.help || !sub) return null;
|
|
4586
|
-
const storePath = resolveStorePath(
|
|
4606
|
+
const storePath = resolveStorePath(
|
|
4607
|
+
values["store-path"] ?? (sub === "artifact" ? process.env.VIBEFLOW_STORE_DIR : void 0),
|
|
4608
|
+
values.profile
|
|
4609
|
+
);
|
|
4587
4610
|
setPlatform(createNodePlatform({ userDataDir: storePath }));
|
|
4588
4611
|
if (!SUBCOMMANDS.includes(sub)) {
|
|
4589
4612
|
fail("UNKNOWN_COMMAND", `Unknown command: "task ${sub}". Use: ${SUBCOMMANDS.map((s) => `task ${s}`).join(" | ")}`);
|
|
4590
4613
|
}
|
|
4614
|
+
if (sub === "artifact") {
|
|
4615
|
+
if (action !== "add") fail("UNKNOWN_COMMAND", "Use: task artifact add --file <path>");
|
|
4616
|
+
const taskId = values.task ?? process.env.VIBEFLOW_TASK_ID;
|
|
4617
|
+
if (!taskId || !values.file) fail("MISSING_ARGUMENT", "task artifact add needs --file and --task (or VIBEFLOW_TASK_ID)");
|
|
4618
|
+
const task2 = findTask(taskId);
|
|
4619
|
+
if (!task2) fail("TASK_NOT_FOUND", `Task not found: ${taskId}`);
|
|
4620
|
+
return { taskId, path: addTaskArtifact(task2, values.file) };
|
|
4621
|
+
}
|
|
4591
4622
|
if (sub === "update") {
|
|
4592
4623
|
if (!values.task) fail("MISSING_ARGUMENT", "Missing required arguments: --task");
|
|
4593
4624
|
requireOneOf("--status", values.status, STATUSES);
|
|
@@ -4695,7 +4726,6 @@ import path15 from "path";
|
|
|
4695
4726
|
// packages/core/src/library.ts
|
|
4696
4727
|
import { createHash } from "crypto";
|
|
4697
4728
|
import fs10 from "fs";
|
|
4698
|
-
import os3 from "os";
|
|
4699
4729
|
import path14 from "path";
|
|
4700
4730
|
var LIBRARY_DIR = "library";
|
|
4701
4731
|
var LIBRARY_KINDS = ["skill", "prompt", "script"];
|
|
@@ -4712,7 +4742,6 @@ function libraryPaths(root) {
|
|
|
4712
4742
|
skills: path14.join(root, KIND_DIR.skill),
|
|
4713
4743
|
prompts: path14.join(root, KIND_DIR.prompt),
|
|
4714
4744
|
scripts: path14.join(root, KIND_DIR.script),
|
|
4715
|
-
plugin: path14.join(root, "plugin"),
|
|
4716
4745
|
codexHome: path14.join(root, "codex-home")
|
|
4717
4746
|
};
|
|
4718
4747
|
}
|
|
@@ -4960,9 +4989,6 @@ function requireEntry(root, kind, name) {
|
|
|
4960
4989
|
if (!found2) throw new Error(`\u9805\u76EE\u5BEB\u5165\u5F8C\u8B80\u4E0D\u56DE\u4F86\uFF1A${kind}/${name}`);
|
|
4961
4990
|
return found2;
|
|
4962
4991
|
}
|
|
4963
|
-
function projectSkillsDir(worktreePath) {
|
|
4964
|
-
return path14.join(worktreePath, ".claude", "skills");
|
|
4965
|
-
}
|
|
4966
4992
|
function skillNamesIn(dir) {
|
|
4967
4993
|
try {
|
|
4968
4994
|
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();
|
|
@@ -4970,132 +4996,6 @@ function skillNamesIn(dir) {
|
|
|
4970
4996
|
return [];
|
|
4971
4997
|
}
|
|
4972
4998
|
}
|
|
4973
|
-
var PLUGIN_MANIFEST_DIR = ".claude-plugin";
|
|
4974
|
-
function buildPluginDir(root) {
|
|
4975
|
-
const paths = libraryPaths(root);
|
|
4976
|
-
const enabled = listLibrary(root).filter((e) => e.kind === "skill" && e.enabled);
|
|
4977
|
-
fs10.rmSync(path14.join(paths.plugin, "skills"), { recursive: true, force: true });
|
|
4978
|
-
fs10.mkdirSync(path14.join(paths.plugin, PLUGIN_MANIFEST_DIR), { recursive: true });
|
|
4979
|
-
fs10.mkdirSync(path14.join(paths.plugin, "skills"), { recursive: true });
|
|
4980
|
-
fs10.writeFileSync(
|
|
4981
|
-
path14.join(paths.plugin, PLUGIN_MANIFEST_DIR, "plugin.json"),
|
|
4982
|
-
`${JSON.stringify(
|
|
4983
|
-
{
|
|
4984
|
-
name: "vibeflow-library",
|
|
4985
|
-
version: "1.0.0",
|
|
4986
|
-
description: "Skills delivered by VibeFlow for this task."
|
|
4987
|
-
},
|
|
4988
|
-
null,
|
|
4989
|
-
2
|
|
4990
|
-
)}
|
|
4991
|
-
`
|
|
4992
|
-
);
|
|
4993
|
-
for (const entry of enabled) {
|
|
4994
|
-
fs10.cpSync(entry.path, path14.join(paths.plugin, "skills", entry.name), {
|
|
4995
|
-
recursive: true,
|
|
4996
|
-
dereference: true
|
|
4997
|
-
});
|
|
4998
|
-
}
|
|
4999
|
-
return { pluginDir: paths.plugin, skills: enabled.map((e) => e.name) };
|
|
5000
|
-
}
|
|
5001
|
-
function linkOrSkip(target, linkPath) {
|
|
5002
|
-
if (!fs10.existsSync(target)) return false;
|
|
5003
|
-
const source = path14.resolve(target);
|
|
5004
|
-
const attempts = fs10.statSync(source).isDirectory() ? [
|
|
5005
|
-
() => fs10.symlinkSync(source, linkPath, "junction"),
|
|
5006
|
-
() => fs10.cpSync(source, linkPath, { recursive: true, dereference: true })
|
|
5007
|
-
] : [
|
|
5008
|
-
() => fs10.symlinkSync(source, linkPath),
|
|
5009
|
-
() => fs10.linkSync(source, linkPath),
|
|
5010
|
-
() => fs10.copyFileSync(source, linkPath)
|
|
5011
|
-
];
|
|
5012
|
-
for (const attempt of attempts) {
|
|
5013
|
-
try {
|
|
5014
|
-
fs10.rmSync(linkPath, { recursive: true, force: true });
|
|
5015
|
-
attempt();
|
|
5016
|
-
return true;
|
|
5017
|
-
} catch {
|
|
5018
|
-
}
|
|
5019
|
-
}
|
|
5020
|
-
return false;
|
|
5021
|
-
}
|
|
5022
|
-
function buildCodexHome(root, worktreePath, userCodexHome = path14.join(os3.homedir(), ".codex")) {
|
|
5023
|
-
const paths = libraryPaths(root);
|
|
5024
|
-
const skillsDir = path14.join(paths.codexHome, "skills");
|
|
5025
|
-
fs10.rmSync(skillsDir, { recursive: true, force: true });
|
|
5026
|
-
fs10.mkdirSync(skillsDir, { recursive: true });
|
|
5027
|
-
for (const file of ["auth.json", "config.toml"]) {
|
|
5028
|
-
linkOrSkip(path14.join(userCodexHome, file), path14.join(paths.codexHome, file));
|
|
5029
|
-
}
|
|
5030
|
-
const result = {
|
|
5031
|
-
codexHome: paths.codexHome,
|
|
5032
|
-
project: [],
|
|
5033
|
-
user: [],
|
|
5034
|
-
library: [],
|
|
5035
|
-
shadowed: []
|
|
5036
|
-
};
|
|
5037
|
-
const claimed = /* @__PURE__ */ new Map();
|
|
5038
|
-
const projectDir = worktreePath ? projectSkillsDir(worktreePath) : void 0;
|
|
5039
|
-
if (projectDir) {
|
|
5040
|
-
for (const name of skillNamesIn(projectDir)) {
|
|
5041
|
-
if (linkOrSkip(path14.join(projectDir, name), path14.join(skillsDir, name))) {
|
|
5042
|
-
result.project.push(name);
|
|
5043
|
-
claimed.set(name, "project");
|
|
5044
|
-
}
|
|
5045
|
-
}
|
|
5046
|
-
}
|
|
5047
|
-
const userDir = path14.join(userCodexHome, "skills");
|
|
5048
|
-
for (const name of skillNamesIn(userDir)) {
|
|
5049
|
-
const owner = claimed.get(name);
|
|
5050
|
-
if (owner) {
|
|
5051
|
-
result.shadowed.push({ name, keptFrom: owner, dropped: "user" });
|
|
5052
|
-
continue;
|
|
5053
|
-
}
|
|
5054
|
-
if (linkOrSkip(path14.join(userDir, name), path14.join(skillsDir, name))) {
|
|
5055
|
-
result.user.push(name);
|
|
5056
|
-
claimed.set(name, "user");
|
|
5057
|
-
}
|
|
5058
|
-
}
|
|
5059
|
-
for (const entry of listLibrary(root)) {
|
|
5060
|
-
if (entry.kind !== "skill" || !entry.enabled) continue;
|
|
5061
|
-
const owner = claimed.get(entry.name);
|
|
5062
|
-
if (owner) {
|
|
5063
|
-
result.shadowed.push({ name: entry.name, keptFrom: owner, dropped: "library" });
|
|
5064
|
-
continue;
|
|
5065
|
-
}
|
|
5066
|
-
fs10.cpSync(entry.path, path14.join(skillsDir, entry.name), {
|
|
5067
|
-
recursive: true,
|
|
5068
|
-
dereference: true
|
|
5069
|
-
});
|
|
5070
|
-
result.library.push(entry.name);
|
|
5071
|
-
}
|
|
5072
|
-
return result;
|
|
5073
|
-
}
|
|
5074
|
-
function libraryLaunchInfoAt(root, worktreePath, userCodexHome) {
|
|
5075
|
-
const entries = listLibrary(root).filter((e) => e.enabled);
|
|
5076
|
-
if (entries.length === 0) return null;
|
|
5077
|
-
const { pluginDir } = buildPluginDir(root);
|
|
5078
|
-
const { codexHome } = buildCodexHome(root, worktreePath, userCodexHome);
|
|
5079
|
-
const scripts = entries.filter((e) => e.kind === "script").map((e) => ({ name: e.name, path: e.path, description: e.description }));
|
|
5080
|
-
const promptBodies = entries.filter((e) => e.kind === "prompt").map((e) => readEntryContent(root, "prompt", e.name).trim()).filter(Boolean);
|
|
5081
|
-
const lines = [...promptBodies];
|
|
5082
|
-
if (scripts.length > 0) {
|
|
5083
|
-
lines.push(
|
|
5084
|
-
"\u53EF\u7528\u7684\u5DE5\u5177\u8173\u672C\uFF08\u9700\u8981\u6642\u81EA\u884C\u57F7\u884C\uFF0C\u4E0D\u9700\u8981\u5C31\u5225\u8DD1\uFF09\uFF1A",
|
|
5085
|
-
...scripts.map((s) => `- ${s.path}${s.description ? ` \u2014 ${s.description}` : ""}`)
|
|
5086
|
-
);
|
|
5087
|
-
}
|
|
5088
|
-
return {
|
|
5089
|
-
pluginDir,
|
|
5090
|
-
codexHome,
|
|
5091
|
-
libraryDir: root,
|
|
5092
|
-
scripts,
|
|
5093
|
-
promptText: lines.join("\n\n")
|
|
5094
|
-
};
|
|
5095
|
-
}
|
|
5096
|
-
async function libraryLaunchInfo(worktreePath) {
|
|
5097
|
-
return libraryLaunchInfoAt(await libraryRoot(), worktreePath);
|
|
5098
|
-
}
|
|
5099
4999
|
|
|
5100
5000
|
// packages/core/src/library-builtins.ts
|
|
5101
5001
|
function builtinSkillsDir() {
|
|
@@ -5201,19 +5101,19 @@ async function syncBuiltinsAtStartup() {
|
|
|
5201
5101
|
|
|
5202
5102
|
// packages/core/src/service.ts
|
|
5203
5103
|
import fs19 from "fs";
|
|
5204
|
-
import
|
|
5104
|
+
import os7 from "os";
|
|
5205
5105
|
import path23 from "path";
|
|
5206
5106
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
5207
5107
|
|
|
5208
5108
|
// packages/core/src/agent-models.ts
|
|
5209
5109
|
import fs13 from "fs";
|
|
5210
|
-
import
|
|
5110
|
+
import os5 from "os";
|
|
5211
5111
|
import path17 from "path";
|
|
5212
5112
|
|
|
5213
5113
|
// packages/core/src/claude-models.ts
|
|
5214
5114
|
init_effort();
|
|
5215
5115
|
import fs12 from "fs";
|
|
5216
|
-
import
|
|
5116
|
+
import os3 from "os";
|
|
5217
5117
|
import path16 from "path";
|
|
5218
5118
|
|
|
5219
5119
|
// packages/core/src/json-lines-process.ts
|
|
@@ -5318,7 +5218,7 @@ var CLAUDE_MODELS_TIMEOUT_MS = 15e3;
|
|
|
5318
5218
|
var REQUEST_ID = "vibeflow-models";
|
|
5319
5219
|
var CLAUDE_ARGS = ["-p", "--input-format", "stream-json", "--output-format", "stream-json", "--verbose"];
|
|
5320
5220
|
function openClaude() {
|
|
5321
|
-
const cwd = fs12.mkdtempSync(path16.join(
|
|
5221
|
+
const cwd = fs12.mkdtempSync(path16.join(os3.tmpdir(), "vf-claude-models-"));
|
|
5322
5222
|
return spawnJsonLines("claude", CLAUDE_ARGS, {
|
|
5323
5223
|
cwd,
|
|
5324
5224
|
timeoutMs: CLAUDE_MODELS_TIMEOUT_MS,
|
|
@@ -5348,7 +5248,7 @@ function parseClaudeInitialize(message) {
|
|
|
5348
5248
|
seen.add(id);
|
|
5349
5249
|
const label = typeof entry.displayName === "string" && entry.displayName.trim() ? entry.displayName.trim() : id;
|
|
5350
5250
|
const description = typeof entry.description === "string" && entry.description.trim() ? entry.description.trim() : void 0;
|
|
5351
|
-
const levels = entry.supportsEffort === true && Array.isArray(entry.supportedEffortLevels) ? entry.supportedEffortLevels.filter(
|
|
5251
|
+
const levels = entry.supportsEffort === true && Array.isArray(entry.supportedEffortLevels) ? entry.supportedEffortLevels.filter(isManualEffort) : [];
|
|
5352
5252
|
const isDefault = !defaultMarked && defaultResolved !== void 0 && entry.resolvedModel === defaultResolved;
|
|
5353
5253
|
if (isDefault) defaultMarked = true;
|
|
5354
5254
|
models.push({ id, label, ...description ? { description } : {}, efforts: levels, ...isDefault ? { isDefault } : {} });
|
|
@@ -5369,7 +5269,7 @@ async function fetchClaudeModels(open = openClaude) {
|
|
|
5369
5269
|
// packages/core/src/codex-models.ts
|
|
5370
5270
|
init_effort();
|
|
5371
5271
|
init_env();
|
|
5372
|
-
import
|
|
5272
|
+
import os4 from "os";
|
|
5373
5273
|
var CODEX_MODELS_TIMEOUT_MS = 2e4;
|
|
5374
5274
|
var MAX_PAGES = 20;
|
|
5375
5275
|
var CodexLoginRequiredError = class extends Error {
|
|
@@ -5382,7 +5282,7 @@ function codexAppServerCommand() {
|
|
|
5382
5282
|
return {
|
|
5383
5283
|
bin: "codex",
|
|
5384
5284
|
args: ["app-server", "--listen", "stdio://"],
|
|
5385
|
-
cwd:
|
|
5285
|
+
cwd: os4.homedir(),
|
|
5386
5286
|
env: execEnv()
|
|
5387
5287
|
};
|
|
5388
5288
|
}
|
|
@@ -5411,7 +5311,7 @@ function parseCodexModelPage(result) {
|
|
|
5411
5311
|
const id = entry.id.trim();
|
|
5412
5312
|
const label = typeof entry.displayName === "string" && entry.displayName.trim() ? entry.displayName.trim() : id;
|
|
5413
5313
|
const description = typeof entry.description === "string" && entry.description.trim() ? entry.description.trim() : void 0;
|
|
5414
|
-
const efforts = Array.isArray(entry.supportedReasoningEfforts) ? entry.supportedReasoningEfforts.map((e) => isRecord2(e) ? e.reasoningEffort : void 0).filter(
|
|
5314
|
+
const efforts = Array.isArray(entry.supportedReasoningEfforts) ? entry.supportedReasoningEfforts.map((e) => isRecord2(e) ? e.reasoningEffort : void 0).filter(isManualEffort) : void 0;
|
|
5415
5315
|
models.push({
|
|
5416
5316
|
id,
|
|
5417
5317
|
label,
|
|
@@ -5471,7 +5371,7 @@ function builtinModels(id) {
|
|
|
5471
5371
|
}
|
|
5472
5372
|
function defaultCodexHome() {
|
|
5473
5373
|
const configured = process.env.CODEX_HOME?.trim();
|
|
5474
|
-
return configured ? configured : path17.join(
|
|
5374
|
+
return configured ? configured : path17.join(os5.homedir(), ".codex");
|
|
5475
5375
|
}
|
|
5476
5376
|
function parseCodexCatalog(raw) {
|
|
5477
5377
|
const body = JSON.parse(raw);
|
|
@@ -5557,118 +5457,68 @@ function createModelCatalog(opts) {
|
|
|
5557
5457
|
}
|
|
5558
5458
|
|
|
5559
5459
|
// packages/core/src/jev-router.ts
|
|
5460
|
+
init_effort();
|
|
5560
5461
|
init_launch();
|
|
5561
5462
|
var API_URL = "https://api.typesafe.ai/v1/systemone";
|
|
5562
5463
|
var MAX_TASK_CHARS = 12e3;
|
|
5563
|
-
var MAX_PLAN_CHARS = 8e3;
|
|
5564
|
-
function tier(model, agent) {
|
|
5565
|
-
const name = `${model.id} ${model.label}`.toLowerCase();
|
|
5566
|
-
if (/haiku|mini|nano|luna|flash/.test(name)) return 0;
|
|
5567
|
-
if (/opus|astra|pro\b/.test(name)) return 2;
|
|
5568
|
-
if (agent === "codex" && /gpt-5\.5|gpt-5\.4(?!-mini)/.test(name)) return 2;
|
|
5569
|
-
return 1;
|
|
5570
|
-
}
|
|
5571
|
-
function routeCandidates(agent, models) {
|
|
5572
|
-
const valid = models.filter((m) => /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(m.id));
|
|
5573
|
-
const byTier = /* @__PURE__ */ new Map();
|
|
5574
|
-
for (const model of valid) {
|
|
5575
|
-
const rank = tier(model, agent);
|
|
5576
|
-
if (!byTier.has(rank)) byTier.set(rank, model);
|
|
5577
|
-
}
|
|
5578
|
-
return [...byTier.entries()].sort(([a], [b]) => a - b).map(([, model]) => model);
|
|
5579
|
-
}
|
|
5580
|
-
function isChoice(value) {
|
|
5581
|
-
return !!value && typeof value === "object" && value.type === "choice" && typeof value.choice === "string";
|
|
5582
|
-
}
|
|
5583
5464
|
function createJevRouter(opts = {}) {
|
|
5584
5465
|
const getApiKey = opts.getApiKey ?? (() => opts.apiKey ?? process.env.TYPESAFE_API_KEY?.trim());
|
|
5585
5466
|
const fetcher = opts.fetcher ?? fetch;
|
|
5586
|
-
const planner = opts.planner ?? (async (agent, model, prompt, cwd) => {
|
|
5587
|
-
const args = agent === "claude" ? ["-p", "--model", model, "--permission-mode", "plan"] : ["exec", "--model", model, "--sandbox", "read-only", "--skip-git-repo-check", "-"];
|
|
5588
|
-
return (opts.printAgent ?? runAgentPrint)(agent, args, prompt, { cwd, timeout: 12e4, maxBuffer: 128 * 1024 });
|
|
5589
|
-
});
|
|
5590
|
-
async function ask(state, questions) {
|
|
5591
|
-
const apiKey = getApiKey();
|
|
5592
|
-
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");
|
|
5593
|
-
const response = await fetcher(API_URL, {
|
|
5594
|
-
method: "POST",
|
|
5595
|
-
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
5596
|
-
body: JSON.stringify({ model: "jev-latest", state, questions }),
|
|
5597
|
-
signal: AbortSignal.timeout(15e3)
|
|
5598
|
-
});
|
|
5599
|
-
if (!response.ok) throw new Error(`Jev API \u56DE\u61C9 ${response.status}`);
|
|
5600
|
-
const body = await response.json();
|
|
5601
|
-
if (!body.answers) throw new Error("Jev API \u6C92\u6709\u56DE\u50B3\u5224\u65B7");
|
|
5602
|
-
return body.answers;
|
|
5603
|
-
}
|
|
5604
5467
|
return {
|
|
5605
5468
|
get enabled() {
|
|
5606
5469
|
return Boolean(getApiKey());
|
|
5607
5470
|
},
|
|
5608
|
-
async route(task, catalog
|
|
5609
|
-
const
|
|
5610
|
-
const
|
|
5611
|
-
if (
|
|
5612
|
-
const expensive = candidates[candidates.length - 1];
|
|
5613
|
-
const taskText = buildPrompt(task).slice(0, MAX_TASK_CHARS);
|
|
5471
|
+
async route(task, catalog) {
|
|
5472
|
+
const model = modelFor(catalog, taskModel(task));
|
|
5473
|
+
const levels = selectableEfforts(model);
|
|
5474
|
+
if (levels.length === 0) return { status: "fallback", reason: "\u76EE\u524D\u6A21\u578B\u4E0D\u652F\u63F4\u8ABF\u6574 effort" };
|
|
5614
5475
|
try {
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5476
|
+
const apiKey = getApiKey();
|
|
5477
|
+
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");
|
|
5478
|
+
const response = await fetcher(API_URL, {
|
|
5479
|
+
method: "POST",
|
|
5480
|
+
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
5481
|
+
body: JSON.stringify({
|
|
5482
|
+
model: "jev-latest",
|
|
5483
|
+
state: {
|
|
5484
|
+
task: buildPrompt(task).slice(0, MAX_TASK_CHARS),
|
|
5485
|
+
agent: task.agentCli === "codex" ? "codex" : "claude",
|
|
5486
|
+
currentModel: model?.id ?? taskModel(task) ?? "CLI default (catalog unavailable)"
|
|
5487
|
+
},
|
|
5488
|
+
questions: {
|
|
5489
|
+
effort: {
|
|
5490
|
+
type: "choice",
|
|
5491
|
+
instructions: "Choose the lowest reasoning effort likely to complete this software task correctly on the current model. Increase effort for complexity, ambiguity, or risk.",
|
|
5492
|
+
criteria: Object.fromEntries(levels.map((level) => [level, effortDescription(level)]))
|
|
5493
|
+
}
|
|
5632
5494
|
}
|
|
5633
|
-
}
|
|
5495
|
+
}),
|
|
5496
|
+
signal: AbortSignal.timeout(15e3)
|
|
5634
5497
|
});
|
|
5635
|
-
if (!
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
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.
|
|
5641
|
-
|
|
5642
|
-
${taskText}`;
|
|
5643
|
-
plan = (await planner(agent, expensive.id, instruction, task.worktreePath)).trim().slice(0, MAX_PLAN_CHARS);
|
|
5644
|
-
if (!plan) throw new Error("\u898F\u5283\u6A21\u578B\u6C92\u6709\u56DE\u50B3\u8A08\u756B");
|
|
5498
|
+
if (!response.ok) throw new Error(`Jev API \u56DE\u61C9 ${response.status}`);
|
|
5499
|
+
const body = await response.json();
|
|
5500
|
+
const choice = body.answers?.effort;
|
|
5501
|
+
if (choice?.type !== "choice" || !levels.includes(choice.choice)) {
|
|
5502
|
+
throw new Error("Jev \u9078\u4E86\u76EE\u524D\u6A21\u578B\u4E0D\u652F\u63F4\u7684 effort");
|
|
5645
5503
|
}
|
|
5646
|
-
|
|
5647
|
-
const options = Object.fromEntries(candidates.map((m) => [
|
|
5648
|
-
m.id,
|
|
5649
|
-
`${m.label}; relative cost tier ${tier(m, agent) + 1}/3 (${tier(m, agent) === 2 ? "highest capability" : tier(m, agent) === 0 ? "lowest cost" : "balanced"})`
|
|
5650
|
-
]));
|
|
5651
|
-
const second = await ask({ task: taskText, complexity: first.complexity.choice, plan }, {
|
|
5652
|
-
model: {
|
|
5653
|
-
type: "choice",
|
|
5654
|
-
instructions: "Choose the lowest-cost available model likely to implement this task correctly. Prefer more capable models as complexity or uncertainty rises.",
|
|
5655
|
-
criteria: options
|
|
5656
|
-
}
|
|
5657
|
-
});
|
|
5658
|
-
if (!isChoice(second.model) || !candidates.some((m) => m.id === second.model.choice)) {
|
|
5659
|
-
throw new Error("Jev \u9078\u4E86\u4E0D\u5728\u6A21\u578B\u6E05\u55AE\u4E2D\u7684\u6A21\u578B");
|
|
5660
|
-
}
|
|
5661
|
-
return {
|
|
5662
|
-
status: "routed",
|
|
5663
|
-
model: second.model.choice,
|
|
5664
|
-
...plan ? { plannerModel: expensive.id, plan } : {}
|
|
5665
|
-
};
|
|
5504
|
+
return { status: "routed", effort: choice.choice };
|
|
5666
5505
|
} catch (err) {
|
|
5667
5506
|
return { status: "fallback", reason: err instanceof Error ? err.message : String(err) };
|
|
5668
5507
|
}
|
|
5669
5508
|
}
|
|
5670
5509
|
};
|
|
5671
5510
|
}
|
|
5511
|
+
function effortDescription(level) {
|
|
5512
|
+
const descriptions = {
|
|
5513
|
+
low: "Routine, small and well scoped work",
|
|
5514
|
+
medium: "Typical development with limited uncertainty",
|
|
5515
|
+
high: "Complex debugging or several interacting files",
|
|
5516
|
+
xhigh: "Difficult design or extensive reasoning",
|
|
5517
|
+
max: "The hardest, highest risk tasks",
|
|
5518
|
+
ultra: "Deepest reasoning with automatic delegation"
|
|
5519
|
+
};
|
|
5520
|
+
return descriptions[level];
|
|
5521
|
+
}
|
|
5672
5522
|
|
|
5673
5523
|
// packages/core/src/jev-credentials.ts
|
|
5674
5524
|
import fs14 from "fs";
|
|
@@ -6634,7 +6484,7 @@ init_launch();
|
|
|
6634
6484
|
init_progress();
|
|
6635
6485
|
init_launch();
|
|
6636
6486
|
import fs18 from "fs";
|
|
6637
|
-
import
|
|
6487
|
+
import os6 from "os";
|
|
6638
6488
|
import path22 from "path";
|
|
6639
6489
|
var SINCE_SLACK_MS = 5e3;
|
|
6640
6490
|
function claudeProjectDir(home, cwd) {
|
|
@@ -6735,7 +6585,7 @@ function codexDayDirs(sessionsRoot, since) {
|
|
|
6735
6585
|
return days;
|
|
6736
6586
|
}
|
|
6737
6587
|
function createProgressTracker(opts) {
|
|
6738
|
-
const home = opts.homeDir ??
|
|
6588
|
+
const home = opts.homeDir ?? os6.homedir();
|
|
6739
6589
|
const codexHomes = opts.codexHomes ?? (() => [path22.join(home, ".codex")]);
|
|
6740
6590
|
const pollMs = opts.pollMs ?? 2e3;
|
|
6741
6591
|
const entries = /* @__PURE__ */ new Map();
|
|
@@ -6989,7 +6839,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6989
6839
|
libraryCodexHome = libraryPaths(root).codexHome;
|
|
6990
6840
|
}).catch(() => {
|
|
6991
6841
|
});
|
|
6992
|
-
const home = homeDir ??
|
|
6842
|
+
const home = homeDir ?? os7.homedir();
|
|
6993
6843
|
const progress = createProgressTracker({
|
|
6994
6844
|
homeDir: home,
|
|
6995
6845
|
codexHomes: () => [path23.join(home, ".codex"), ...libraryCodexHome ? [libraryCodexHome] : []],
|
|
@@ -7066,16 +6916,16 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7066
6916
|
requireTask(key.split(":")[0]);
|
|
7067
6917
|
return key;
|
|
7068
6918
|
}
|
|
7069
|
-
function launchEffort(task,
|
|
7070
|
-
const
|
|
7071
|
-
|
|
6919
|
+
function launchEffort(task, route) {
|
|
6920
|
+
const effort = task.effort === "auto" ? route?.effort : task.effort;
|
|
6921
|
+
const model = models.findModel(taskAgent(task), taskModel(task));
|
|
6922
|
+
return model?.efforts ? clampEffort(effort, model.efforts) : effort;
|
|
7072
6923
|
}
|
|
7073
6924
|
async function launchCommand(task, intent) {
|
|
7074
6925
|
const settings = getSettings();
|
|
7075
|
-
const library = await libraryLaunchInfo(task.worktreePath);
|
|
7076
6926
|
const boardCli = await boardCliLaunchInfo();
|
|
7077
|
-
let route = task.
|
|
7078
|
-
if (
|
|
6927
|
+
let route = task.jevRoute?.status === "routing" ? void 0 : task.jevRoute;
|
|
6928
|
+
if (task.effort === "auto" && !intent.resume && intent.includeTaskPrompt !== false) {
|
|
7079
6929
|
let pending = routing.get(task.id);
|
|
7080
6930
|
if (!pending) {
|
|
7081
6931
|
const setRoute = (jevRoute) => {
|
|
@@ -7083,9 +6933,9 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7083
6933
|
bus.emit("state:changed", getState());
|
|
7084
6934
|
};
|
|
7085
6935
|
pending = (async () => {
|
|
7086
|
-
setRoute({ status: "routing"
|
|
6936
|
+
setRoute({ status: "routing" });
|
|
7087
6937
|
const candidateModels = (await (router.enabled === false ? models.get(taskAgent(task)) : models.refresh(taskAgent(task)))).models;
|
|
7088
|
-
const selected = await router.route(task, candidateModels
|
|
6938
|
+
const selected = await router.route(task, candidateModels);
|
|
7089
6939
|
setRoute(selected);
|
|
7090
6940
|
return selected;
|
|
7091
6941
|
})().catch((err) => {
|
|
@@ -7096,24 +6946,21 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7096
6946
|
}
|
|
7097
6947
|
route = await pending;
|
|
7098
6948
|
}
|
|
7099
|
-
const selectedModel = task.model?.trim() ? taskModel(task) : route?.model;
|
|
7100
6949
|
return buildAgentCommand(
|
|
7101
|
-
{ ...task, model:
|
|
6950
|
+
{ ...task, model: taskModel(task), effort: launchEffort(task, route) },
|
|
7102
6951
|
settings.systemPrompt ?? "",
|
|
7103
6952
|
{
|
|
7104
6953
|
resume: intent.resume === true,
|
|
7105
6954
|
includeTaskPrompt: intent.includeTaskPrompt !== false,
|
|
7106
|
-
library: library ?? void 0,
|
|
7107
6955
|
boardCli,
|
|
7108
|
-
autoMode: task.autoMode ?? settings.autoMode
|
|
7109
|
-
preflightPlan: !intent.resume ? route?.plan : void 0
|
|
6956
|
+
autoMode: task.autoMode ?? settings.autoMode
|
|
7110
6957
|
},
|
|
7111
6958
|
task.workspacePath
|
|
7112
6959
|
);
|
|
7113
6960
|
}
|
|
7114
6961
|
function claudeSessionFile(cwd, sessionId) {
|
|
7115
6962
|
const munged = cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
7116
|
-
return path23.join(
|
|
6963
|
+
return path23.join(os7.homedir(), ".claude", "projects", munged, `${sessionId}.jsonl`);
|
|
7117
6964
|
}
|
|
7118
6965
|
async function removeTaskWorktree(task) {
|
|
7119
6966
|
if (!task.projectPath || !task.worktreePath) return;
|
|
@@ -7411,6 +7258,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7411
7258
|
command = (await launchCommand(task, intent)).replace(/\r$/, "");
|
|
7412
7259
|
}
|
|
7413
7260
|
}
|
|
7261
|
+
if (p.launch) ensureTaskArtifactDirs(task);
|
|
7414
7262
|
const result = await sessions.start(key, {
|
|
7415
7263
|
cwd,
|
|
7416
7264
|
command,
|
|
@@ -8106,6 +7954,66 @@ async function checkForUpdate(packageName2, currentVersion, query = async (name)
|
|
|
8106
7954
|
return { currentVersion, latestVersion: latest };
|
|
8107
7955
|
}
|
|
8108
7956
|
|
|
7957
|
+
// packages/cli/src/update-terminal.ts
|
|
7958
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
7959
|
+
function updateTerminalCommands(platform) {
|
|
7960
|
+
if (platform === "win32") {
|
|
7961
|
+
return [{ cmd: "powershell.exe", args: ["-NoProfile", "-Command", "Start-Process cmd.exe -ArgumentList '/k vibeflow update'"], waitForExit: true }];
|
|
7962
|
+
}
|
|
7963
|
+
if (platform === "darwin") {
|
|
7964
|
+
return [{ cmd: "osascript", args: [
|
|
7965
|
+
"-e",
|
|
7966
|
+
'tell application "Terminal" to activate',
|
|
7967
|
+
"-e",
|
|
7968
|
+
'tell application "Terminal" to do script "sudo vibeflow update"'
|
|
7969
|
+
], waitForExit: true }];
|
|
7970
|
+
}
|
|
7971
|
+
const command = "sudo vibeflow update; exec sh";
|
|
7972
|
+
return [
|
|
7973
|
+
{ cmd: "gnome-terminal", args: ["--", "sh", "-c", command] },
|
|
7974
|
+
{ cmd: "x-terminal-emulator", args: ["-e", "sh", "-c", command] },
|
|
7975
|
+
{ cmd: "konsole", args: ["-e", "sh", "-c", command] },
|
|
7976
|
+
{ cmd: "xfce4-terminal", args: ["--command", `sh -c '${command}'`] },
|
|
7977
|
+
{ cmd: "xterm", args: ["-e", "sh", "-c", command] }
|
|
7978
|
+
];
|
|
7979
|
+
}
|
|
7980
|
+
function launch(command) {
|
|
7981
|
+
return new Promise((resolve, reject) => {
|
|
7982
|
+
const child = spawn8(command.cmd, command.args, {
|
|
7983
|
+
detached: !command.waitForExit,
|
|
7984
|
+
stdio: command.waitForExit ? ["ignore", "ignore", "pipe"] : "ignore",
|
|
7985
|
+
windowsHide: false
|
|
7986
|
+
});
|
|
7987
|
+
child.once("error", reject);
|
|
7988
|
+
if (command.waitForExit) {
|
|
7989
|
+
let stderr = "";
|
|
7990
|
+
child.stderr?.on("data", (chunk) => {
|
|
7991
|
+
stderr += String(chunk);
|
|
7992
|
+
});
|
|
7993
|
+
child.once("close", (code2) => code2 === 0 ? resolve() : reject(new Error(stderr.trim() || `\u7121\u6CD5\u958B\u555F\u7D42\u7AEF\u6A5F\uFF08\u7D50\u675F\u78BC ${code2 ?? "unknown"}\uFF09`)));
|
|
7994
|
+
} else {
|
|
7995
|
+
child.once("spawn", () => {
|
|
7996
|
+
child.unref();
|
|
7997
|
+
resolve();
|
|
7998
|
+
});
|
|
7999
|
+
}
|
|
8000
|
+
});
|
|
8001
|
+
}
|
|
8002
|
+
async function openUpdateTerminal(platform = process.platform, run3 = launch) {
|
|
8003
|
+
if (platform === "linux" && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) {
|
|
8004
|
+
throw new Error("\u627E\u4E0D\u5230\u5716\u5F62\u684C\u9762\uFF0C\u7121\u6CD5\u958B\u555F\u66F4\u65B0\u7D42\u7AEF\u6A5F\u3002");
|
|
8005
|
+
}
|
|
8006
|
+
for (const command of updateTerminalCommands(platform)) {
|
|
8007
|
+
try {
|
|
8008
|
+
await run3(command);
|
|
8009
|
+
return;
|
|
8010
|
+
} catch (err) {
|
|
8011
|
+
if (err.code !== "ENOENT") throw err;
|
|
8012
|
+
}
|
|
8013
|
+
}
|
|
8014
|
+
throw new Error("\u627E\u4E0D\u5230\u53EF\u7528\u7684\u7D42\u7AEF\u6A5F\uFF0C\u8ACB\u624B\u52D5\u57F7\u884C\u66F4\u65B0\u6307\u4EE4\u3002");
|
|
8015
|
+
}
|
|
8016
|
+
|
|
8109
8017
|
// packages/cli/src/host.ts
|
|
8110
8018
|
var DEFAULT_HOST_PORT = 47820;
|
|
8111
8019
|
async function waitForPort(userDataDir, timeoutMs = 1e4) {
|
|
@@ -8176,7 +8084,11 @@ async function startHost(options) {
|
|
|
8176
8084
|
backend: sessions.kind,
|
|
8177
8085
|
startedAt: lock.startedAt
|
|
8178
8086
|
}),
|
|
8179
|
-
"host:updateStatus": () => availableUpdate
|
|
8087
|
+
"host:updateStatus": () => availableUpdate,
|
|
8088
|
+
"host:openUpdateTerminal": () => {
|
|
8089
|
+
if (!installedPackage || !availableUpdate) throw new Error("\u76EE\u524D\u6C92\u6709\u53EF\u5F9E\u5168\u57DF npm \u5B89\u88DD\u66F4\u65B0\u7684\u7248\u672C\u3002");
|
|
8090
|
+
return openUpdateTerminal();
|
|
8091
|
+
}
|
|
8180
8092
|
};
|
|
8181
8093
|
const server = await startWebServer({
|
|
8182
8094
|
handlers,
|
|
@@ -8514,7 +8426,7 @@ Usage:
|
|
|
8514
8426
|
vibeflow doctor Check Node, git, tmux, node-pty and the agent CLIs
|
|
8515
8427
|
(--skip agents,web,\u2026 leaves checks out, e.g. on CI)
|
|
8516
8428
|
vibeflow update Install the latest global npm release (restart the host afterward)
|
|
8517
|
-
vibeflow task \u2026 Create / update cards (vibeflow task --help)
|
|
8429
|
+
vibeflow task \u2026 Create / update cards; add artifacts (vibeflow task --help)
|
|
8518
8430
|
|
|
8519
8431
|
Options:
|
|
8520
8432
|
--profile dev|prod Store profile (dev = the "(development)" store npm run dev uses)
|