@kw-yeh/vibeflow 4.11.2 → 4.11.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/vibeflow.mjs +350 -127
- package/dist/web/404/index.html +1 -1
- package/dist/web/404.html +1 -1
- package/dist/web/_next/static/{o3y3NZBsG2M3Apv0aNLTX → GIFAj2f7vnl7CH-w2t2Zn}/_buildManifest.js +1 -1
- package/dist/web/_next/static/chunks/pages/{_app-da81e08b87346d10.js → _app-33cd991a71572ffc.js} +1 -1
- package/dist/web/_next/static/chunks/pages/home-f3c28e54c88c90c9.js +13 -0
- package/dist/web/_next/static/css/28418f147c3162be.css +2 -0
- package/dist/web/home/index.html +1 -1
- package/package.json +1 -1
- package/dist/web/_next/static/chunks/pages/home-d6a12e7acc308e8a.js +0 -12
- package/dist/web/_next/static/css/64c0d78419ed2e17.css +0 -2
- /package/dist/web/_next/static/{o3y3NZBsG2M3Apv0aNLTX → GIFAj2f7vnl7CH-w2t2Zn}/_ssgManifest.js +0 -0
package/dist/vibeflow.mjs
CHANGED
|
@@ -257,6 +257,9 @@ var init_pty = __esm({
|
|
|
257
257
|
scrollback(key) {
|
|
258
258
|
return this.scrollbacks.get(key) ?? null;
|
|
259
259
|
}
|
|
260
|
+
discardScrollback(key) {
|
|
261
|
+
this.scrollbacks.delete(key);
|
|
262
|
+
}
|
|
260
263
|
async isScrolledBack() {
|
|
261
264
|
return false;
|
|
262
265
|
}
|
|
@@ -650,7 +653,8 @@ function buildAgentCommand(task, systemPrompt, opts, workspacePath) {
|
|
|
650
653
|
const customPrompt = resolveSystemPrompt(systemPrompt);
|
|
651
654
|
const sys = [builtInPrompt, libraryPrompt, customPrompt].filter(Boolean).join("\n\n");
|
|
652
655
|
const includeTaskPrompt = opts?.includeTaskPrompt !== false;
|
|
653
|
-
const prompt = includeTaskPrompt && !opts?.resume ? buildPrompt(task)
|
|
656
|
+
const prompt = includeTaskPrompt && !opts?.resume ? [buildPrompt(task), opts?.preflightPlan ? `\u524D\u7F6E\u898F\u5283\uFF08\u4F9B\u53C3\u8003\uFF0C\u8ACB\u5148\u6838\u5C0D\u7A0B\u5F0F\u78BC\u518D\u57F7\u884C\uFF09\uFF1A
|
|
657
|
+
${opts.preflightPlan}` : ""].filter(Boolean).join("\n\n") : "";
|
|
654
658
|
const sessionId = agent === "claude" && includeTaskPrompt ? executorSessionId(task.id, task.runId) : void 0;
|
|
655
659
|
return boardEnvPrefix(task, opts) + assembleCommand(
|
|
656
660
|
agent,
|
|
@@ -1099,9 +1103,9 @@ var init_progress = __esm({
|
|
|
1099
1103
|
|
|
1100
1104
|
// packages/tui/src/task-form.ts
|
|
1101
1105
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
1102
|
-
import
|
|
1106
|
+
import fs24 from "fs";
|
|
1103
1107
|
import os9 from "os";
|
|
1104
|
-
import
|
|
1108
|
+
import path28 from "path";
|
|
1105
1109
|
import React, { useEffect, useRef, useState } from "react";
|
|
1106
1110
|
import { Box, Text, render as render2, useApp, useInput } from "ink";
|
|
1107
1111
|
function newFormState(defaultAutoMode, agents) {
|
|
@@ -1227,17 +1231,17 @@ function editorCommand(env, platform) {
|
|
|
1227
1231
|
return env.VISUAL?.trim() || env.EDITOR?.trim() || (platform === "win32" ? "notepad" : "vi");
|
|
1228
1232
|
}
|
|
1229
1233
|
function editInEditor(text) {
|
|
1230
|
-
const dir =
|
|
1231
|
-
const file =
|
|
1234
|
+
const dir = fs24.mkdtempSync(path28.join(os9.tmpdir(), "vibeflow-"));
|
|
1235
|
+
const file = path28.join(dir, "description.md");
|
|
1232
1236
|
try {
|
|
1233
|
-
|
|
1237
|
+
fs24.writeFileSync(file, text);
|
|
1234
1238
|
const cmd = editorCommand(process.env, process.platform);
|
|
1235
1239
|
const r = spawnSync2(`${cmd} "${file}"`, { stdio: "inherit", shell: true });
|
|
1236
1240
|
if (r.error) return { error: `\u7121\u6CD5\u555F\u52D5\u7DE8\u8F2F\u5668\uFF08${cmd}\uFF09\uFF1A${r.error.message}` };
|
|
1237
1241
|
if (r.status !== 0) return { error: `\u7DE8\u8F2F\u5668\uFF08${cmd}\uFF09\u7D50\u675F\u78BC ${r.status}\uFF0C\u63CF\u8FF0\u672A\u8B8A\u66F4` };
|
|
1238
|
-
return { text:
|
|
1242
|
+
return { text: fs24.readFileSync(file, "utf8").replace(/\r?\n$/, "") };
|
|
1239
1243
|
} finally {
|
|
1240
|
-
|
|
1244
|
+
fs24.rmSync(dir, { recursive: true, force: true });
|
|
1241
1245
|
}
|
|
1242
1246
|
}
|
|
1243
1247
|
function cycle(list, current, step) {
|
|
@@ -1308,10 +1312,10 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
1308
1312
|
if (editing === "title") setS((prev) => ({ ...prev, title: draft }));
|
|
1309
1313
|
else if (editing === "branch") setS((prev) => ({ ...prev, branch: value2 }));
|
|
1310
1314
|
else if (editing === "project") {
|
|
1311
|
-
if (value2) setProject(
|
|
1315
|
+
if (value2) setProject(path28.resolve(value2.replace(/^~(?=$|\/)/, os9.homedir())));
|
|
1312
1316
|
} else if (editing === "attachments" && value2) {
|
|
1313
|
-
const file =
|
|
1314
|
-
if (!
|
|
1317
|
+
const file = path28.resolve(value2.replace(/^~(?=$|\/)/, os9.homedir()));
|
|
1318
|
+
if (!fs24.existsSync(file) || !fs24.statSync(file).isFile()) {
|
|
1315
1319
|
setMessage(`\u627E\u4E0D\u5230\u6A94\u6848\uFF1A${file}`);
|
|
1316
1320
|
return;
|
|
1317
1321
|
}
|
|
@@ -1394,7 +1398,7 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
1394
1398
|
case "branch":
|
|
1395
1399
|
return s.branch || "\uFF08\u7559\u7A7A\u5247\u81EA\u52D5\u547D\u540D\uFF0C\u4F8B\u5982 feature/login-fix\uFF09";
|
|
1396
1400
|
case "attachments":
|
|
1397
|
-
return s.attachments.length ? s.attachments.map((a) =>
|
|
1401
|
+
return s.attachments.length ? s.attachments.map((a) => path28.basename(a)).join("\u3001") : "\uFF08Enter \u8F38\u5165\u6A94\u6848\u8DEF\u5F91\u52A0\u5165\uFF09";
|
|
1398
1402
|
case "description": {
|
|
1399
1403
|
if (!s.description) return "\uFF08Enter \u7528\u7DE8\u8F2F\u5668\u64B0\u5BEB\uFF09";
|
|
1400
1404
|
const lines = s.description.split("\n");
|
|
@@ -1430,7 +1434,7 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
1430
1434
|
if (info && !info.isRepo) return "\u9019\u500B\u8CC7\u6599\u593E\u4E0D\u662F Git repository\u3002\u8ACB\u6539\u9078\u4E00\u500B Git \u5C08\u6848\uFF0C\u6216\u5728\u4E0B\u65B9\u521D\u59CB\u5316\u3002";
|
|
1431
1435
|
if (s.mode === "edit" && projectChanged(s)) return "\u5206\u652F\u6703\u5728\u65B0\u5C08\u6848\u3001\u5361\u7247\u958B\u59CB\u57F7\u884C\u6642\u624D\u5EFA\u7ACB\u3002";
|
|
1432
1436
|
if (info?.isRepo && !info.hasRemote) return `\u6B64 repository \u6C92\u6709 remote\uFF0C\u5C07\u4EE5\u76EE\u524D\u5206\u652F (${info.currentBranch ?? "HEAD"}) \u70BA\u57FA\u6E96\u5EFA\u7ACB\u672C\u5730 worktree\u3002`;
|
|
1433
|
-
if (info?.isRepo && s.projectPath) return `worktree \u6703\u5EFA\u5728 ${ctx.workstationPath || "~/Desktop"}/${
|
|
1437
|
+
if (info?.isRepo && s.projectPath) return `worktree \u6703\u5EFA\u5728 ${ctx.workstationPath || "~/Desktop"}/${path28.basename(s.projectPath)}`;
|
|
1434
1438
|
}
|
|
1435
1439
|
if (field === "branch") {
|
|
1436
1440
|
const when = info?.hasRemote ? "\u958B\u59CB\u57F7\u884C\u6642\u6703\u5EFA\u7ACB\u540C\u540D\u5206\u652F\u4E26\u63A8\u5230 origin\uFF1B\u82E5 remote \u5DF2\u6709\u9019\u500B\u5206\u652F\uFF0C\u5247\u76F4\u63A5\u53D6\u56DE\u4E26\u63A5\u7E8C\u4E0A\u9762\u7684\u5DE5\u4F5C\u3002" : "\u958B\u59CB\u57F7\u884C\u6642\u6703\u5EFA\u7ACB\u540C\u540D\u5206\u652F\u3002";
|
|
@@ -1558,7 +1562,7 @@ __export(src_exports, {
|
|
|
1558
1562
|
showDiff: () => showDiff
|
|
1559
1563
|
});
|
|
1560
1564
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
1561
|
-
import
|
|
1565
|
+
import path29 from "path";
|
|
1562
1566
|
import React2, { useEffect as useEffect2, useState as useState2 } from "react";
|
|
1563
1567
|
import { Box as Box2, Text as Text2, render as render3, useApp as useApp2, useInput as useInput2, useStdout } from "ink";
|
|
1564
1568
|
function findDetachKey(text) {
|
|
@@ -1854,7 +1858,7 @@ function showDiff(task) {
|
|
|
1854
1858
|
});
|
|
1855
1859
|
}
|
|
1856
1860
|
function tmuxAttach(opts, sessionName) {
|
|
1857
|
-
const conf =
|
|
1861
|
+
const conf = path29.join(opts.userDataDir, "tmux.conf");
|
|
1858
1862
|
const inOurServer = (process.env.TMUX ?? "").split(",")[0].endsWith(`/${TMUX_SOCKET}`);
|
|
1859
1863
|
const args = inOurServer ? ["-L", TMUX_SOCKET, "-f", conf, "switch-client", "-t", `=${sessionName}`] : ["-L", TMUX_SOCKET, "-f", conf, "attach-session", "-t", `=${sessionName}`];
|
|
1860
1864
|
spawnSync3("tmux", args, { stdio: "inherit", env: { ...process.env, TMUX: inOurServer ? process.env.TMUX : "" } });
|
|
@@ -1985,8 +1989,8 @@ var init_src = __esm({
|
|
|
1985
1989
|
});
|
|
1986
1990
|
|
|
1987
1991
|
// packages/cli/src/main.ts
|
|
1988
|
-
import
|
|
1989
|
-
import
|
|
1992
|
+
import fs25 from "fs";
|
|
1993
|
+
import path30 from "path";
|
|
1990
1994
|
import { fileURLToPath } from "url";
|
|
1991
1995
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
1992
1996
|
|
|
@@ -2460,6 +2464,9 @@ function createBridge(t) {
|
|
|
2460
2464
|
},
|
|
2461
2465
|
setBoard: (board) => t.invoke("vibeflow:setBoard", board),
|
|
2462
2466
|
setSettings: (patch) => t.invoke("vibeflow:setSettings", patch),
|
|
2467
|
+
getJevKeyStatus: () => t.invoke("settings:jevKeyStatus"),
|
|
2468
|
+
saveJevApiKey: (apiKey) => t.invoke("settings:saveJevApiKey", { apiKey }),
|
|
2469
|
+
removeJevApiKey: () => t.invoke("settings:removeJevApiKey"),
|
|
2463
2470
|
getGithubAuthStatus: () => t.invoke("settings:githubAuthStatus"),
|
|
2464
2471
|
startGithubAuthLogin: () => t.invoke("settings:startGithubAuthLogin"),
|
|
2465
2472
|
cancelGithubAuthLogin: () => t.invoke("settings:cancelGithubAuthLogin"),
|
|
@@ -2576,6 +2583,7 @@ function createBridge(t) {
|
|
|
2576
2583
|
* `sessionKey` defaults to `taskId`.
|
|
2577
2584
|
*/
|
|
2578
2585
|
start: (payload) => t.invoke("pty:start", payload),
|
|
2586
|
+
startStandalone: (payload) => t.invoke("terminal:start", payload),
|
|
2579
2587
|
/** Join a running session without restarting it. */
|
|
2580
2588
|
peek: (sessionKey) => t.invoke("pty:peek", sessionKey),
|
|
2581
2589
|
/** Which session backend runs terminals, and the sessions it has running. */
|
|
@@ -4634,8 +4642,8 @@ async function taskCommand(argv) {
|
|
|
4634
4642
|
}
|
|
4635
4643
|
|
|
4636
4644
|
// packages/cli/src/host.ts
|
|
4637
|
-
import
|
|
4638
|
-
import
|
|
4645
|
+
import fs22 from "fs";
|
|
4646
|
+
import path26 from "path";
|
|
4639
4647
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
4640
4648
|
|
|
4641
4649
|
// packages/core/src/events.ts
|
|
@@ -5173,10 +5181,10 @@ async function syncBuiltinsAtStartup() {
|
|
|
5173
5181
|
}
|
|
5174
5182
|
|
|
5175
5183
|
// packages/core/src/service.ts
|
|
5176
|
-
import
|
|
5184
|
+
import fs19 from "fs";
|
|
5177
5185
|
import os8 from "os";
|
|
5178
|
-
import
|
|
5179
|
-
import { randomUUID as
|
|
5186
|
+
import path23 from "path";
|
|
5187
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
5180
5188
|
|
|
5181
5189
|
// packages/core/src/agent-models.ts
|
|
5182
5190
|
import fs13 from "fs";
|
|
@@ -5529,6 +5537,170 @@ function createModelCatalog(opts) {
|
|
|
5529
5537
|
};
|
|
5530
5538
|
}
|
|
5531
5539
|
|
|
5540
|
+
// packages/core/src/jev-router.ts
|
|
5541
|
+
init_launch();
|
|
5542
|
+
var API_URL = "https://api.typesafe.ai/v1/systemone";
|
|
5543
|
+
var MAX_TASK_CHARS = 12e3;
|
|
5544
|
+
var MAX_PLAN_CHARS = 8e3;
|
|
5545
|
+
function tier(model, agent) {
|
|
5546
|
+
const name = `${model.id} ${model.label}`.toLowerCase();
|
|
5547
|
+
if (/haiku|mini|nano|luna|flash/.test(name)) return 0;
|
|
5548
|
+
if (/opus|astra|pro\b/.test(name)) return 2;
|
|
5549
|
+
if (agent === "codex" && /gpt-5\.5|gpt-5\.4(?!-mini)/.test(name)) return 2;
|
|
5550
|
+
return 1;
|
|
5551
|
+
}
|
|
5552
|
+
function routeCandidates(agent, models) {
|
|
5553
|
+
const valid = models.filter((m) => /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(m.id));
|
|
5554
|
+
const byTier = /* @__PURE__ */ new Map();
|
|
5555
|
+
for (const model of valid) {
|
|
5556
|
+
const rank = tier(model, agent);
|
|
5557
|
+
if (!byTier.has(rank)) byTier.set(rank, model);
|
|
5558
|
+
}
|
|
5559
|
+
return [...byTier.entries()].sort(([a], [b]) => a - b).map(([, model]) => model);
|
|
5560
|
+
}
|
|
5561
|
+
function isChoice(value) {
|
|
5562
|
+
return !!value && typeof value === "object" && value.type === "choice" && typeof value.choice === "string";
|
|
5563
|
+
}
|
|
5564
|
+
function createJevRouter(opts = {}) {
|
|
5565
|
+
const getApiKey = opts.getApiKey ?? (() => opts.apiKey ?? process.env.TYPESAFE_API_KEY?.trim());
|
|
5566
|
+
const fetcher = opts.fetcher ?? fetch;
|
|
5567
|
+
const planner = opts.planner ?? (async (agent, model, prompt, cwd) => {
|
|
5568
|
+
const args = agent === "claude" ? ["-p", "--model", model, "--permission-mode", "plan"] : ["exec", "--model", model, "--sandbox", "read-only", "--skip-git-repo-check", "-"];
|
|
5569
|
+
return (opts.printAgent ?? runAgentPrint)(agent, args, prompt, { cwd, timeout: 12e4, maxBuffer: 128 * 1024 });
|
|
5570
|
+
});
|
|
5571
|
+
async function ask(state, questions) {
|
|
5572
|
+
const apiKey = getApiKey();
|
|
5573
|
+
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");
|
|
5574
|
+
const response = await fetcher(API_URL, {
|
|
5575
|
+
method: "POST",
|
|
5576
|
+
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
5577
|
+
body: JSON.stringify({ model: "jev-latest", state, questions }),
|
|
5578
|
+
signal: AbortSignal.timeout(15e3)
|
|
5579
|
+
});
|
|
5580
|
+
if (!response.ok) throw new Error(`Jev API \u56DE\u61C9 ${response.status}`);
|
|
5581
|
+
const body = await response.json();
|
|
5582
|
+
if (!body.answers) throw new Error("Jev API \u6C92\u6709\u56DE\u50B3\u5224\u65B7");
|
|
5583
|
+
return body.answers;
|
|
5584
|
+
}
|
|
5585
|
+
return {
|
|
5586
|
+
get enabled() {
|
|
5587
|
+
return Boolean(getApiKey());
|
|
5588
|
+
},
|
|
5589
|
+
async route(task, catalog) {
|
|
5590
|
+
const agent = task.agentCli === "codex" ? "codex" : "claude";
|
|
5591
|
+
const candidates = routeCandidates(agent, catalog);
|
|
5592
|
+
if (candidates.length === 0) return { status: "fallback", reason: "\u6A21\u578B\u6E05\u55AE\u6C92\u6709\u53EF\u7528\u7684\u6A21\u578B" };
|
|
5593
|
+
const expensive = candidates[candidates.length - 1];
|
|
5594
|
+
const taskText = buildPrompt(task).slice(0, MAX_TASK_CHARS);
|
|
5595
|
+
try {
|
|
5596
|
+
const first = await ask({ task: taskText, agent }, {
|
|
5597
|
+
complexity: {
|
|
5598
|
+
type: "choice",
|
|
5599
|
+
instructions: "How difficult is this software task to implement correctly?",
|
|
5600
|
+
criteria: {
|
|
5601
|
+
simple: "Small, well scoped and routine",
|
|
5602
|
+
moderate: "Some design choices or multiple files",
|
|
5603
|
+
complex: "Architecture, ambiguous requirements, high risk, or many interacting parts"
|
|
5604
|
+
}
|
|
5605
|
+
},
|
|
5606
|
+
preparation: {
|
|
5607
|
+
type: "choice",
|
|
5608
|
+
instructions: "Would a separate read-only planning pass materially improve the implementation?",
|
|
5609
|
+
criteria: {
|
|
5610
|
+
direct: "The request is clear enough to start implementation directly",
|
|
5611
|
+
plan: "The request is unclear, broad or complex enough to benefit from a plan first"
|
|
5612
|
+
}
|
|
5613
|
+
}
|
|
5614
|
+
});
|
|
5615
|
+
if (!isChoice(first.complexity) || !isChoice(first.preparation) || !["simple", "moderate", "complex"].includes(first.complexity.choice) || !["direct", "plan"].includes(first.preparation.choice)) throw new Error("Jev \u56DE\u50B3\u4E0D\u53D7\u652F\u63F4\u7684\u5224\u65B7");
|
|
5616
|
+
let plan;
|
|
5617
|
+
if (first.preparation.choice === "plan") {
|
|
5618
|
+
if (!task.worktreePath) throw new Error("\u898F\u5283\u6642\u627E\u4E0D\u5230 worktree");
|
|
5619
|
+
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.
|
|
5620
|
+
|
|
5621
|
+
${taskText}`;
|
|
5622
|
+
plan = (await planner(agent, expensive.id, instruction, task.worktreePath)).trim().slice(0, MAX_PLAN_CHARS);
|
|
5623
|
+
if (!plan) throw new Error("\u898F\u5283\u6A21\u578B\u6C92\u6709\u56DE\u50B3\u8A08\u756B");
|
|
5624
|
+
}
|
|
5625
|
+
const options = Object.fromEntries(candidates.map((m) => [
|
|
5626
|
+
m.id,
|
|
5627
|
+
`${m.label}; relative cost tier ${tier(m, agent) + 1}/3 (${tier(m, agent) === 2 ? "highest capability" : tier(m, agent) === 0 ? "lowest cost" : "balanced"})`
|
|
5628
|
+
]));
|
|
5629
|
+
const second = await ask({ task: taskText, complexity: first.complexity.choice, plan }, {
|
|
5630
|
+
model: {
|
|
5631
|
+
type: "choice",
|
|
5632
|
+
instructions: "Choose the lowest-cost available model likely to implement this task correctly. Prefer more capable models as complexity or uncertainty rises.",
|
|
5633
|
+
criteria: options
|
|
5634
|
+
}
|
|
5635
|
+
});
|
|
5636
|
+
if (!isChoice(second.model) || !candidates.some((m) => m.id === second.model.choice)) {
|
|
5637
|
+
throw new Error("Jev \u9078\u4E86\u4E0D\u5728\u6A21\u578B\u6E05\u55AE\u4E2D\u7684\u6A21\u578B");
|
|
5638
|
+
}
|
|
5639
|
+
return {
|
|
5640
|
+
status: "routed",
|
|
5641
|
+
model: second.model.choice,
|
|
5642
|
+
...plan ? { plannerModel: expensive.id, plan } : {}
|
|
5643
|
+
};
|
|
5644
|
+
} catch (err) {
|
|
5645
|
+
return { status: "fallback", reason: err instanceof Error ? err.message : String(err) };
|
|
5646
|
+
}
|
|
5647
|
+
}
|
|
5648
|
+
};
|
|
5649
|
+
}
|
|
5650
|
+
|
|
5651
|
+
// packages/core/src/jev-credentials.ts
|
|
5652
|
+
import fs14 from "fs";
|
|
5653
|
+
import path18 from "path";
|
|
5654
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
5655
|
+
function keyPath(dir) {
|
|
5656
|
+
return path18.join(dir, "jev-api-key");
|
|
5657
|
+
}
|
|
5658
|
+
function dataDir() {
|
|
5659
|
+
return getPlatform().userDataDir();
|
|
5660
|
+
}
|
|
5661
|
+
function readJevApiKey(dir = dataDir()) {
|
|
5662
|
+
try {
|
|
5663
|
+
const file = keyPath(dir);
|
|
5664
|
+
if (fs14.lstatSync(file).isSymbolicLink()) throw new Error("Jev key file must not be a symlink");
|
|
5665
|
+
const saved = fs14.readFileSync(file, "utf8").trim();
|
|
5666
|
+
if (saved) return saved;
|
|
5667
|
+
} catch (err) {
|
|
5668
|
+
if (err.code !== "ENOENT") throw err;
|
|
5669
|
+
}
|
|
5670
|
+
return process.env.TYPESAFE_API_KEY?.trim() || void 0;
|
|
5671
|
+
}
|
|
5672
|
+
function jevKeyStatus(dir = dataDir()) {
|
|
5673
|
+
try {
|
|
5674
|
+
const file = keyPath(dir);
|
|
5675
|
+
if (fs14.lstatSync(file).isSymbolicLink()) throw new Error("Jev key file must not be a symlink");
|
|
5676
|
+
if (fs14.readFileSync(file, "utf8").trim()) return { configured: true, source: "saved" };
|
|
5677
|
+
} catch (err) {
|
|
5678
|
+
if (err.code !== "ENOENT") throw err;
|
|
5679
|
+
}
|
|
5680
|
+
return process.env.TYPESAFE_API_KEY?.trim() ? { configured: true, source: "environment" } : { configured: false, source: "none" };
|
|
5681
|
+
}
|
|
5682
|
+
function saveJevApiKey(value, dir = dataDir()) {
|
|
5683
|
+
const key = value.trim();
|
|
5684
|
+
if (!key || key.length > 4096 || !/^[\x21-\x7e]+$/.test(key)) {
|
|
5685
|
+
throw new Error("Jev API key \u683C\u5F0F\u7121\u6548");
|
|
5686
|
+
}
|
|
5687
|
+
fs14.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
5688
|
+
const file = keyPath(dir);
|
|
5689
|
+
const tmp = `${file}.${randomUUID3()}.tmp`;
|
|
5690
|
+
try {
|
|
5691
|
+
fs14.writeFileSync(tmp, key, { mode: 384, flag: "wx" });
|
|
5692
|
+
fs14.renameSync(tmp, file);
|
|
5693
|
+
if (process.platform !== "win32") fs14.chmodSync(file, 384);
|
|
5694
|
+
} finally {
|
|
5695
|
+
fs14.rmSync(tmp, { force: true });
|
|
5696
|
+
}
|
|
5697
|
+
return { configured: true, source: "saved" };
|
|
5698
|
+
}
|
|
5699
|
+
function removeJevApiKey(dir = dataDir()) {
|
|
5700
|
+
fs14.rmSync(keyPath(dir), { force: true });
|
|
5701
|
+
return jevKeyStatus(dir);
|
|
5702
|
+
}
|
|
5703
|
+
|
|
5532
5704
|
// packages/core/src/service.ts
|
|
5533
5705
|
init_effort();
|
|
5534
5706
|
|
|
@@ -6031,45 +6203,45 @@ function createJiraService(options) {
|
|
|
6031
6203
|
}
|
|
6032
6204
|
|
|
6033
6205
|
// packages/core/src/board-cli.ts
|
|
6034
|
-
import
|
|
6035
|
-
import
|
|
6206
|
+
import fs15 from "fs";
|
|
6207
|
+
import path19 from "path";
|
|
6036
6208
|
import { pathToFileURL } from "url";
|
|
6037
6209
|
async function boardCliLaunchInfo() {
|
|
6038
|
-
const storeDir =
|
|
6210
|
+
const storeDir = path19.dirname(getStorePath());
|
|
6039
6211
|
const entry = getPlatform().cliEntry?.();
|
|
6040
|
-
if (entry &&
|
|
6212
|
+
if (entry && fs15.existsSync(entry)) return { storeDir, cliPath: entry };
|
|
6041
6213
|
const root = getPlatform().sourceRoot();
|
|
6042
6214
|
if (!root) return { storeDir };
|
|
6043
|
-
const cliPath =
|
|
6044
|
-
const loaderPath =
|
|
6045
|
-
if (!
|
|
6215
|
+
const cliPath = path19.join(root, "scripts", "vibeflow.mjs");
|
|
6216
|
+
const loaderPath = path19.join(root, "test", "support", "register.mjs");
|
|
6217
|
+
if (!fs15.existsSync(cliPath) || !fs15.existsSync(loaderPath)) return { storeDir };
|
|
6046
6218
|
return { storeDir, cliPath, loaderPath: pathToFileURL(loaderPath).href };
|
|
6047
6219
|
}
|
|
6048
6220
|
|
|
6049
6221
|
// packages/core/src/decisions.ts
|
|
6050
|
-
import
|
|
6051
|
-
import
|
|
6222
|
+
import fs16 from "fs";
|
|
6223
|
+
import path20 from "path";
|
|
6052
6224
|
var DECISIONS_FILE_SUFFIX = ".DECISIONS.md";
|
|
6053
6225
|
function decisionsKey(worktreePath, branch) {
|
|
6054
|
-
return worktreePath ?
|
|
6226
|
+
return worktreePath ? path20.basename(worktreePath) : branch.replace(/\//g, "-");
|
|
6055
6227
|
}
|
|
6056
6228
|
function decisionsPath(workspacePath, key) {
|
|
6057
|
-
return
|
|
6229
|
+
return path20.join(workspacePath, `${key}${DECISIONS_FILE_SUFFIX}`);
|
|
6058
6230
|
}
|
|
6059
6231
|
function deleteDecisions(workspacePath, key) {
|
|
6060
6232
|
try {
|
|
6061
|
-
|
|
6233
|
+
fs16.rmSync(decisionsPath(workspacePath, key), { force: true });
|
|
6062
6234
|
} catch {
|
|
6063
6235
|
}
|
|
6064
6236
|
}
|
|
6065
6237
|
|
|
6066
6238
|
// packages/core/src/specs.ts
|
|
6067
|
-
import
|
|
6068
|
-
import
|
|
6239
|
+
import fs17 from "fs";
|
|
6240
|
+
import path21 from "path";
|
|
6069
6241
|
var SPEC_FILE_NAME = "spec.md";
|
|
6070
6242
|
var MAX_SPEC_BYTES = 256 * 1024;
|
|
6071
6243
|
function isSpecPath(p) {
|
|
6072
|
-
return
|
|
6244
|
+
return path21.posix.basename(p) === SPEC_FILE_NAME;
|
|
6073
6245
|
}
|
|
6074
6246
|
function clip2(buf) {
|
|
6075
6247
|
return {
|
|
@@ -6084,10 +6256,10 @@ async function readWorktreeSpecs(worktreePath, baseBranch) {
|
|
|
6084
6256
|
for (const entry of entries) {
|
|
6085
6257
|
if (entry.status === "D" || !isSpecPath(entry.path)) continue;
|
|
6086
6258
|
try {
|
|
6087
|
-
const full =
|
|
6088
|
-
const stat =
|
|
6259
|
+
const full = path21.join(worktreePath, entry.path);
|
|
6260
|
+
const stat = fs17.statSync(full);
|
|
6089
6261
|
if (!stat.isFile()) continue;
|
|
6090
|
-
specs.push({ path: entry.path, ...clip2(
|
|
6262
|
+
specs.push({ path: entry.path, ...clip2(fs17.readFileSync(full)), updatedAt: stat.mtimeMs });
|
|
6091
6263
|
} catch {
|
|
6092
6264
|
}
|
|
6093
6265
|
}
|
|
@@ -6153,7 +6325,7 @@ async function readSpecsAt(cwd, ref, paths) {
|
|
|
6153
6325
|
init_env();
|
|
6154
6326
|
init_git_bash();
|
|
6155
6327
|
import { spawn as spawn7 } from "child_process";
|
|
6156
|
-
import { randomUUID as
|
|
6328
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
6157
6329
|
|
|
6158
6330
|
// packages/core/src/chat-store.ts
|
|
6159
6331
|
var _chatStore = null;
|
|
@@ -6283,7 +6455,7 @@ function sendChatMessage(opts, sender) {
|
|
|
6283
6455
|
const fullText = attachmentLines.length ? `${text}
|
|
6284
6456
|
|
|
6285
6457
|
${attachmentLines.join("\n")}` : text;
|
|
6286
|
-
const userMsgId =
|
|
6458
|
+
const userMsgId = randomUUID4().slice(0, 8);
|
|
6287
6459
|
appendMessage(taskId, {
|
|
6288
6460
|
id: userMsgId,
|
|
6289
6461
|
role: "user",
|
|
@@ -6402,7 +6574,7 @@ ${attachmentLines.join("\n")}` : text;
|
|
|
6402
6574
|
proc.on("close", (code2) => {
|
|
6403
6575
|
const assistantText = accumulated || "\uFF08\u7121\u56DE\u61C9\uFF09";
|
|
6404
6576
|
appendMessage(taskId, {
|
|
6405
|
-
id:
|
|
6577
|
+
id: randomUUID4().slice(0, 8),
|
|
6406
6578
|
role: "assistant",
|
|
6407
6579
|
text: assistantText,
|
|
6408
6580
|
ts: Date.now()
|
|
@@ -6439,17 +6611,17 @@ init_launch();
|
|
|
6439
6611
|
// packages/core/src/progress-tracker.ts
|
|
6440
6612
|
init_progress();
|
|
6441
6613
|
init_launch();
|
|
6442
|
-
import
|
|
6614
|
+
import fs18 from "fs";
|
|
6443
6615
|
import os7 from "os";
|
|
6444
|
-
import
|
|
6616
|
+
import path22 from "path";
|
|
6445
6617
|
var SINCE_SLACK_MS = 5e3;
|
|
6446
6618
|
function claudeProjectDir(home, cwd) {
|
|
6447
|
-
return
|
|
6619
|
+
return path22.join(home, ".claude", "projects", cwd.replace(/[^a-zA-Z0-9]/g, "-"));
|
|
6448
6620
|
}
|
|
6449
6621
|
function pathAliases(p) {
|
|
6450
|
-
const resolved =
|
|
6622
|
+
const resolved = path22.resolve(p);
|
|
6451
6623
|
try {
|
|
6452
|
-
const real =
|
|
6624
|
+
const real = fs18.realpathSync(resolved);
|
|
6453
6625
|
return real === resolved ? [resolved] : [resolved, real];
|
|
6454
6626
|
} catch {
|
|
6455
6627
|
return [resolved];
|
|
@@ -6465,7 +6637,7 @@ function samePath(a, b) {
|
|
|
6465
6637
|
}
|
|
6466
6638
|
function listFiles(dir, test) {
|
|
6467
6639
|
try {
|
|
6468
|
-
return
|
|
6640
|
+
return fs18.readdirSync(dir).filter(test).map((name) => path22.join(dir, name));
|
|
6469
6641
|
} catch {
|
|
6470
6642
|
return [];
|
|
6471
6643
|
}
|
|
@@ -6473,22 +6645,22 @@ function listFiles(dir, test) {
|
|
|
6473
6645
|
function firstLine(file) {
|
|
6474
6646
|
let fd;
|
|
6475
6647
|
try {
|
|
6476
|
-
fd =
|
|
6648
|
+
fd = fs18.openSync(file, "r");
|
|
6477
6649
|
const buf = Buffer.alloc(64 * 1024);
|
|
6478
|
-
const n =
|
|
6650
|
+
const n = fs18.readSync(fd, buf, 0, buf.length, 0);
|
|
6479
6651
|
const text = buf.subarray(0, n).toString("utf8");
|
|
6480
6652
|
const nl = text.indexOf("\n");
|
|
6481
6653
|
return nl === -1 ? null : text.slice(0, nl);
|
|
6482
6654
|
} catch {
|
|
6483
6655
|
return null;
|
|
6484
6656
|
} finally {
|
|
6485
|
-
if (fd !== void 0)
|
|
6657
|
+
if (fd !== void 0) fs18.closeSync(fd);
|
|
6486
6658
|
}
|
|
6487
6659
|
}
|
|
6488
6660
|
function advance(file, cursor, reduce, initial) {
|
|
6489
6661
|
let size;
|
|
6490
6662
|
try {
|
|
6491
|
-
size =
|
|
6663
|
+
size = fs18.statSync(file).size;
|
|
6492
6664
|
} catch {
|
|
6493
6665
|
return;
|
|
6494
6666
|
}
|
|
@@ -6500,9 +6672,9 @@ function advance(file, cursor, reduce, initial) {
|
|
|
6500
6672
|
if (size === cursor.offset) return;
|
|
6501
6673
|
let fd;
|
|
6502
6674
|
try {
|
|
6503
|
-
fd =
|
|
6675
|
+
fd = fs18.openSync(file, "r");
|
|
6504
6676
|
const chunk = Buffer.alloc(size - cursor.offset);
|
|
6505
|
-
const n =
|
|
6677
|
+
const n = fs18.readSync(fd, chunk, 0, chunk.length, cursor.offset);
|
|
6506
6678
|
cursor.offset += n;
|
|
6507
6679
|
const data = Buffer.concat([cursor.rest, chunk.subarray(0, n)]);
|
|
6508
6680
|
const nl = data.lastIndexOf(10);
|
|
@@ -6516,7 +6688,7 @@ function advance(file, cursor, reduce, initial) {
|
|
|
6516
6688
|
}
|
|
6517
6689
|
} catch {
|
|
6518
6690
|
} finally {
|
|
6519
|
-
if (fd !== void 0)
|
|
6691
|
+
if (fd !== void 0) fs18.closeSync(fd);
|
|
6520
6692
|
}
|
|
6521
6693
|
}
|
|
6522
6694
|
function newCursor(state) {
|
|
@@ -6535,14 +6707,14 @@ function codexDayDirs(sessionsRoot, since) {
|
|
|
6535
6707
|
const cur = new Date(start.getFullYear(), start.getMonth(), start.getDate());
|
|
6536
6708
|
while (cur <= end) {
|
|
6537
6709
|
const pad = (n) => String(n).padStart(2, "0");
|
|
6538
|
-
days.push(
|
|
6710
|
+
days.push(path22.join(sessionsRoot, String(cur.getFullYear()), pad(cur.getMonth() + 1), pad(cur.getDate())));
|
|
6539
6711
|
cur.setDate(cur.getDate() + 1);
|
|
6540
6712
|
}
|
|
6541
6713
|
return days;
|
|
6542
6714
|
}
|
|
6543
6715
|
function createProgressTracker(opts) {
|
|
6544
6716
|
const home = opts.homeDir ?? os7.homedir();
|
|
6545
|
-
const codexHomes = opts.codexHomes ?? (() => [
|
|
6717
|
+
const codexHomes = opts.codexHomes ?? (() => [path22.join(home, ".codex")]);
|
|
6546
6718
|
const pollMs = opts.pollMs ?? 2e3;
|
|
6547
6719
|
const entries = /* @__PURE__ */ new Map();
|
|
6548
6720
|
const belongsToRun = (target, startedAt) => target.since == null || startedAt != null && startedAt >= target.since - SINCE_SLACK_MS;
|
|
@@ -6551,7 +6723,7 @@ function createProgressTracker(opts) {
|
|
|
6551
6723
|
const dirs = pathAliases(target.worktreePath).map((p) => claudeProjectDir(home, p));
|
|
6552
6724
|
for (const file of dirs.flatMap((dir) => listFiles(dir, (n) => n.endsWith(".jsonl")))) {
|
|
6553
6725
|
if (entry.claude.has(file) || entry.rejected.has(file)) continue;
|
|
6554
|
-
const session =
|
|
6726
|
+
const session = path22.basename(file, ".jsonl");
|
|
6555
6727
|
if (session !== target.sessionId) {
|
|
6556
6728
|
const head = firstLine(file);
|
|
6557
6729
|
if (head == null) continue;
|
|
@@ -6564,8 +6736,8 @@ function createProgressTracker(opts) {
|
|
|
6564
6736
|
entry.claude.set(file, newCursor(initialClaudeState()));
|
|
6565
6737
|
}
|
|
6566
6738
|
for (const file of Array.from(entry.claude.keys())) {
|
|
6567
|
-
if (file.includes(`${
|
|
6568
|
-
const sub =
|
|
6739
|
+
if (file.includes(`${path22.sep}subagents${path22.sep}`)) continue;
|
|
6740
|
+
const sub = path22.join(file.slice(0, -".jsonl".length), "subagents");
|
|
6569
6741
|
for (const f of listFiles(sub, (n) => n.endsWith(".jsonl"))) {
|
|
6570
6742
|
if (!entry.claude.has(f)) entry.claude.set(f, newCursor(initialClaudeState()));
|
|
6571
6743
|
}
|
|
@@ -6574,7 +6746,7 @@ function createProgressTracker(opts) {
|
|
|
6574
6746
|
function discoverCodex(entry) {
|
|
6575
6747
|
const { target } = entry;
|
|
6576
6748
|
for (const codexHome of codexHomes()) {
|
|
6577
|
-
for (const day of codexDayDirs(
|
|
6749
|
+
for (const day of codexDayDirs(path22.join(codexHome, "sessions"), target.since)) {
|
|
6578
6750
|
for (const file of listFiles(day, (n) => n.startsWith("rollout-") && n.endsWith(".jsonl"))) {
|
|
6579
6751
|
if (entry.codex.has(file) || entry.rejected.has(file)) continue;
|
|
6580
6752
|
const head = firstLine(file);
|
|
@@ -6591,11 +6763,11 @@ function createProgressTracker(opts) {
|
|
|
6591
6763
|
}
|
|
6592
6764
|
}
|
|
6593
6765
|
function drainHooks(entry) {
|
|
6594
|
-
const dir =
|
|
6766
|
+
const dir = path22.join(entry.target.worktreePath, PROGRESS_EVENTS_DIR);
|
|
6595
6767
|
for (const file of listFiles(dir, (n) => n.endsWith(".json")).sort()) {
|
|
6596
6768
|
try {
|
|
6597
|
-
const at =
|
|
6598
|
-
const event = JSON.parse(
|
|
6769
|
+
const at = fs18.statSync(file).mtimeMs;
|
|
6770
|
+
const event = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
6599
6771
|
const foreign = entry.target.sessionId && typeof event.session_id === "string" && event.session_id !== entry.target.sessionId;
|
|
6600
6772
|
const activity = foreign ? null : activityFromHook(event, at);
|
|
6601
6773
|
if (activity) entry.hookActivity = latestActivity(entry.hookActivity ?? activity, activity);
|
|
@@ -6603,7 +6775,7 @@ function createProgressTracker(opts) {
|
|
|
6603
6775
|
continue;
|
|
6604
6776
|
}
|
|
6605
6777
|
try {
|
|
6606
|
-
|
|
6778
|
+
fs18.unlinkSync(file);
|
|
6607
6779
|
} catch {
|
|
6608
6780
|
}
|
|
6609
6781
|
}
|
|
@@ -6615,8 +6787,8 @@ function createProgressTracker(opts) {
|
|
|
6615
6787
|
if (target.agent === "claude") {
|
|
6616
6788
|
for (const [file, cursor] of entry.claude) {
|
|
6617
6789
|
runUsage = addUsage(runUsage, claudeUsageTotal(cursor.state));
|
|
6618
|
-
if (file.includes(`${
|
|
6619
|
-
const isExecutor =
|
|
6790
|
+
if (file.includes(`${path22.sep}subagents${path22.sep}`)) continue;
|
|
6791
|
+
const isExecutor = path22.basename(file, ".jsonl") === target.sessionId;
|
|
6620
6792
|
const s = cursor.state;
|
|
6621
6793
|
if (isExecutor || !target.sessionId && (!primary || (s.startedAt ?? 0) > (primary.startedAt ?? 0))) {
|
|
6622
6794
|
primary = { todos: s.todos, contextTokens: s.contextTokens, activity: s.activity, startedAt: s.startedAt };
|
|
@@ -6695,10 +6867,10 @@ function createProgressTracker(opts) {
|
|
|
6695
6867
|
};
|
|
6696
6868
|
entry.timer.unref?.();
|
|
6697
6869
|
entries.set(target.taskId, entry);
|
|
6698
|
-
const eventsDir =
|
|
6870
|
+
const eventsDir = path22.join(target.worktreePath, PROGRESS_EVENTS_DIR);
|
|
6699
6871
|
try {
|
|
6700
|
-
|
|
6701
|
-
entry.watcher =
|
|
6872
|
+
fs18.mkdirSync(eventsDir, { recursive: true });
|
|
6873
|
+
entry.watcher = fs18.watch(eventsDir, () => {
|
|
6702
6874
|
if (entry.pending) return;
|
|
6703
6875
|
entry.pending = setTimeout(() => {
|
|
6704
6876
|
entry.pending = null;
|
|
@@ -6783,9 +6955,12 @@ function validBoard(value) {
|
|
|
6783
6955
|
}
|
|
6784
6956
|
return next;
|
|
6785
6957
|
}
|
|
6786
|
-
function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatus, acliRunner, jiraAuthStatus, modelCatalog }) {
|
|
6958
|
+
function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatus, acliRunner, jiraAuthStatus, modelCatalog, jevRouter }) {
|
|
6787
6959
|
const sink = bus.sink();
|
|
6788
6960
|
const models = modelCatalog ?? createModelCatalog({ version });
|
|
6961
|
+
const router = jevRouter ?? createJevRouter({ getApiKey: readJevApiKey });
|
|
6962
|
+
const routing = /* @__PURE__ */ new Map();
|
|
6963
|
+
const standaloneTerminals = /* @__PURE__ */ new Map();
|
|
6789
6964
|
let libraryCodexHome = null;
|
|
6790
6965
|
void libraryRoot().then((root) => {
|
|
6791
6966
|
libraryCodexHome = libraryPaths(root).codexHome;
|
|
@@ -6794,7 +6969,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6794
6969
|
const home = homeDir ?? os8.homedir();
|
|
6795
6970
|
const progress = createProgressTracker({
|
|
6796
6971
|
homeDir: home,
|
|
6797
|
-
codexHomes: () => [
|
|
6972
|
+
codexHomes: () => [path23.join(home, ".codex"), ...libraryCodexHome ? [libraryCodexHome] : []],
|
|
6798
6973
|
onUpdate: (taskId, value) => bus.emit("progress:update", { taskId, progress: value }),
|
|
6799
6974
|
onNotify: (taskId, list) => {
|
|
6800
6975
|
const prefs = resolveNotificationSettings(getSettings());
|
|
@@ -6840,7 +7015,10 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6840
7015
|
} catch {
|
|
6841
7016
|
}
|
|
6842
7017
|
async function teardownSession(key) {
|
|
7018
|
+
const standalone = standaloneTerminals.has(key);
|
|
6843
7019
|
await sessions.kill(key);
|
|
7020
|
+
if (standalone) sessions.discardScrollback?.(key);
|
|
7021
|
+
standaloneTerminals.delete(key);
|
|
6844
7022
|
unwatchSubAgents(key);
|
|
6845
7023
|
}
|
|
6846
7024
|
async function teardownTask(taskId) {
|
|
@@ -6855,39 +7033,57 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6855
7033
|
}
|
|
6856
7034
|
function requireSessionKey(sessionKey) {
|
|
6857
7035
|
const key = str(sessionKey, "sessionKey");
|
|
7036
|
+
if (standaloneTerminals.has(key)) return key;
|
|
6858
7037
|
requireTask(key.split(":")[0]);
|
|
6859
7038
|
return key;
|
|
6860
7039
|
}
|
|
6861
|
-
function launchEffort(task) {
|
|
6862
|
-
const model = models.findModel(taskAgent(task),
|
|
7040
|
+
function launchEffort(task, selectedModel = taskModel(task)) {
|
|
7041
|
+
const model = models.findModel(taskAgent(task), selectedModel);
|
|
6863
7042
|
return model?.efforts ? clampEffort(task.effort, model.efforts) : task.effort;
|
|
6864
7043
|
}
|
|
6865
7044
|
async function launchCommand(task, intent) {
|
|
6866
7045
|
const settings = getSettings();
|
|
6867
7046
|
const library = await libraryLaunchInfo(task.worktreePath);
|
|
6868
7047
|
const boardCli = await boardCliLaunchInfo();
|
|
7048
|
+
let route = task.model?.trim() ? void 0 : task.jevRoute;
|
|
7049
|
+
if (!task.model?.trim() && !intent.resume && intent.includeTaskPrompt !== false) {
|
|
7050
|
+
let pending = routing.get(task.id);
|
|
7051
|
+
if (!pending) {
|
|
7052
|
+
pending = (async () => {
|
|
7053
|
+
const candidateModels = (await (router.enabled === false ? models.get(taskAgent(task)) : models.refresh(taskAgent(task)))).models;
|
|
7054
|
+
const selected = await router.route(task, candidateModels);
|
|
7055
|
+
updateTask(task.id, { jevRoute: selected });
|
|
7056
|
+
bus.emit("state:changed", getState());
|
|
7057
|
+
return selected;
|
|
7058
|
+
})().finally(() => routing.delete(task.id));
|
|
7059
|
+
routing.set(task.id, pending);
|
|
7060
|
+
}
|
|
7061
|
+
route = await pending;
|
|
7062
|
+
}
|
|
7063
|
+
const selectedModel = task.model?.trim() ? taskModel(task) : route?.model;
|
|
6869
7064
|
return buildAgentCommand(
|
|
6870
|
-
{ ...task, effort: launchEffort(task) },
|
|
7065
|
+
{ ...task, model: selectedModel, effort: launchEffort(task, selectedModel) },
|
|
6871
7066
|
settings.systemPrompt ?? "",
|
|
6872
7067
|
{
|
|
6873
7068
|
resume: intent.resume === true,
|
|
6874
7069
|
includeTaskPrompt: intent.includeTaskPrompt !== false,
|
|
6875
7070
|
library: library ?? void 0,
|
|
6876
7071
|
boardCli,
|
|
6877
|
-
autoMode: task.autoMode ?? settings.autoMode
|
|
7072
|
+
autoMode: task.autoMode ?? settings.autoMode,
|
|
7073
|
+
preflightPlan: !intent.resume ? route?.plan : void 0
|
|
6878
7074
|
},
|
|
6879
7075
|
task.workspacePath
|
|
6880
7076
|
);
|
|
6881
7077
|
}
|
|
6882
7078
|
function claudeSessionFile(cwd, sessionId) {
|
|
6883
7079
|
const munged = cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
6884
|
-
return
|
|
7080
|
+
return path23.join(os8.homedir(), ".claude", "projects", munged, `${sessionId}.jsonl`);
|
|
6885
7081
|
}
|
|
6886
7082
|
async function removeTaskWorktree(task) {
|
|
6887
7083
|
if (!task.projectPath || !task.worktreePath) return;
|
|
6888
7084
|
const branch = task.branch || fallbackBranchName(task.id);
|
|
6889
7085
|
await removeWorktree(task.projectPath, task.worktreePath);
|
|
6890
|
-
deleteArtifacts(task.workspacePath ??
|
|
7086
|
+
deleteArtifacts(task.workspacePath ?? path23.dirname(task.worktreePath), task.worktreePath);
|
|
6891
7087
|
await deleteBranch(task.projectPath, branch);
|
|
6892
7088
|
}
|
|
6893
7089
|
function columnOf(taskId) {
|
|
@@ -6968,6 +7164,12 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6968
7164
|
setSettings(value);
|
|
6969
7165
|
return getState();
|
|
6970
7166
|
},
|
|
7167
|
+
"settings:jevKeyStatus": () => jevKeyStatus(),
|
|
7168
|
+
"settings:saveJevApiKey": (payload) => {
|
|
7169
|
+
const p = obj(payload, "payload");
|
|
7170
|
+
return saveJevApiKey(str(p.apiKey, "apiKey"));
|
|
7171
|
+
},
|
|
7172
|
+
"settings:removeJevApiKey": () => removeJevApiKey(),
|
|
6971
7173
|
"settings:githubAuthStatus": () => getGitHubCliAuthStatus(),
|
|
6972
7174
|
"settings:startGithubAuthLogin": () => {
|
|
6973
7175
|
startGitHubCliLogin((payload) => bus.emit("github-auth:event", payload));
|
|
@@ -7023,8 +7225,8 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7023
7225
|
"projects:listRecent": () => listRecentProjects(getStore()),
|
|
7024
7226
|
// `vibeflow open <path>` while a host runs: only the host writes the store.
|
|
7025
7227
|
"projects:record": (projectPath) => {
|
|
7026
|
-
const p =
|
|
7027
|
-
if (!
|
|
7228
|
+
const p = path23.resolve(str(projectPath, "projectPath"));
|
|
7229
|
+
if (!fs19.existsSync(p) || !fs19.statSync(p).isDirectory()) invalid(`not a directory: ${p}`);
|
|
7028
7230
|
recordRecentProject(getStore(), p);
|
|
7029
7231
|
return listRecentProjects(getStore());
|
|
7030
7232
|
},
|
|
@@ -7069,7 +7271,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7069
7271
|
if (!task.worktreePath) {
|
|
7070
7272
|
await teardownTask(task.id);
|
|
7071
7273
|
progress.untrack(task.id);
|
|
7072
|
-
updateTask(task.id, { launchedAt: Date.now(), runId:
|
|
7274
|
+
updateTask(task.id, { launchedAt: Date.now(), runId: randomUUID5(), jevRoute: void 0 });
|
|
7073
7275
|
const reset2 = findTask(task.id);
|
|
7074
7276
|
if (!reset2) throw new Error("\u627E\u4E0D\u5230\u8981\u91CD\u7F6E\u7684\u4EFB\u52D9");
|
|
7075
7277
|
return { state: getState(), task: reset2 };
|
|
@@ -7077,13 +7279,13 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7077
7279
|
if (!task.baseBranch) throw new Error("\u4EFB\u52D9\u6C92\u6709\u8A18\u9304 base branch\uFF0C\u7121\u6CD5\u9084\u539F worktree");
|
|
7078
7280
|
await teardownTask(task.id);
|
|
7079
7281
|
await resetWorktreeToBase(task.worktreePath, task.baseBranch);
|
|
7080
|
-
const workspacePath = task.workspacePath ??
|
|
7282
|
+
const workspacePath = task.workspacePath ?? path23.dirname(task.worktreePath);
|
|
7081
7283
|
deleteArtifacts(workspacePath, task.worktreePath);
|
|
7082
7284
|
deleteDecisions(workspacePath, decisionsKey(task.worktreePath, task.branch));
|
|
7083
7285
|
resetSubAgents(task.worktreePath);
|
|
7084
7286
|
const usage = usageThroughCurrentRun(task);
|
|
7085
7287
|
progress.untrack(task.id);
|
|
7086
|
-
updateTask(task.id, { launchedAt: Date.now(), runId:
|
|
7288
|
+
updateTask(task.id, { launchedAt: Date.now(), runId: randomUUID5(), jevRoute: void 0, ...usage ? { usage } : {} });
|
|
7087
7289
|
const reset = findTask(task.id);
|
|
7088
7290
|
if (!reset) throw new Error("\u627E\u4E0D\u5230\u8981\u91CD\u7F6E\u7684\u4EFB\u52D9");
|
|
7089
7291
|
bus.emit("subagents:update", { taskId: task.id, subAgents: [] });
|
|
@@ -7121,7 +7323,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7121
7323
|
}
|
|
7122
7324
|
const info = await getGitInfo(nextProject);
|
|
7123
7325
|
if (!info.isRepo) throw new Error("\u76EE\u6A19\u8CC7\u6599\u593E\u4E0D\u662F git repository");
|
|
7124
|
-
const projectName =
|
|
7326
|
+
const projectName = path23.basename(nextProject);
|
|
7125
7327
|
const workspacePath = projectWorkstationPath(resolveWorkstationPath(getSettings()), projectName);
|
|
7126
7328
|
await teardownTask(existing.id);
|
|
7127
7329
|
await removeTaskWorktree(existing);
|
|
@@ -7145,6 +7347,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7145
7347
|
description: p.description?.trim() || void 0,
|
|
7146
7348
|
agentCli: p.agentCli,
|
|
7147
7349
|
model: p.model || void 0,
|
|
7350
|
+
jevRoute: void 0,
|
|
7148
7351
|
effort: p.effort,
|
|
7149
7352
|
autoMode: p.autoMode,
|
|
7150
7353
|
...gitPatch
|
|
@@ -7190,6 +7393,26 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7190
7393
|
}
|
|
7191
7394
|
return result;
|
|
7192
7395
|
},
|
|
7396
|
+
"terminal:start": async (payload) => {
|
|
7397
|
+
const p = obj(payload, "payload");
|
|
7398
|
+
const key = str(p.sessionKey, "sessionKey");
|
|
7399
|
+
if (!/^terminal_[0-9a-f-]{36}$/.test(key)) invalid("invalid standalone terminal key");
|
|
7400
|
+
if (Boolean(p.taskId) === Boolean(p.projectPath)) invalid("provide taskId or projectPath");
|
|
7401
|
+
const cwd = str(p.taskId ? requireTask(p.taskId).projectPath : p.projectPath, "projectPath");
|
|
7402
|
+
if (!path23.isAbsolute(cwd) || !fs19.existsSync(cwd) || !fs19.statSync(cwd).isDirectory()) {
|
|
7403
|
+
invalid("projectPath must be an existing absolute directory");
|
|
7404
|
+
}
|
|
7405
|
+
const previous = standaloneTerminals.get(key);
|
|
7406
|
+
if (previous && previous !== cwd) invalid("terminal key already belongs to another directory");
|
|
7407
|
+
const result = await sessions.start(key, {
|
|
7408
|
+
cwd,
|
|
7409
|
+
cols: typeof p.cols === "number" ? p.cols : void 0,
|
|
7410
|
+
rows: typeof p.rows === "number" ? p.rows : void 0
|
|
7411
|
+
});
|
|
7412
|
+
standaloneTerminals.set(key, cwd);
|
|
7413
|
+
if (!p.taskId) recordRecentProject(getStore(), cwd);
|
|
7414
|
+
return result;
|
|
7415
|
+
},
|
|
7193
7416
|
// Join a session as it is: no restart, for a frontend that attaches
|
|
7194
7417
|
// after it started (the TUI's terminal view).
|
|
7195
7418
|
"pty:peek": async (sessionKey) => {
|
|
@@ -7215,7 +7438,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7215
7438
|
"claude:sessionExists": (taskId) => {
|
|
7216
7439
|
const task = requireTask(taskId);
|
|
7217
7440
|
if (!task.worktreePath) return false;
|
|
7218
|
-
return
|
|
7441
|
+
return fs19.existsSync(claudeSessionFile(task.worktreePath, executorSessionId(task.id, task.runId)));
|
|
7219
7442
|
},
|
|
7220
7443
|
"sessions:list": async () => {
|
|
7221
7444
|
const keys = await sessions.list();
|
|
@@ -7234,9 +7457,9 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7234
7457
|
"git:getDiffEntries": (taskId, opts) => {
|
|
7235
7458
|
const task = requireTask(taskId);
|
|
7236
7459
|
if (!task.worktreePath) return [];
|
|
7237
|
-
const
|
|
7460
|
+
const fetch2 = opts && typeof opts === "object" ? opts.fetch : void 0;
|
|
7238
7461
|
return getWorktreeDiffEntries(task.worktreePath, task.baseBranch ?? "HEAD", {
|
|
7239
|
-
fetch: typeof
|
|
7462
|
+
fetch: typeof fetch2 === "boolean" ? fetch2 : void 0
|
|
7240
7463
|
});
|
|
7241
7464
|
},
|
|
7242
7465
|
"git:getDiffFile": (taskId, filePath) => {
|
|
@@ -7262,7 +7485,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7262
7485
|
const task = requireTask(taskId);
|
|
7263
7486
|
if (!task.worktreePath || !task.workspacePath) return "task has no worktree";
|
|
7264
7487
|
const dir = agentArtifactsPath(task.workspacePath, task.worktreePath);
|
|
7265
|
-
if (!
|
|
7488
|
+
if (!fs19.existsSync(dir)) return "artifacts directory does not exist yet";
|
|
7266
7489
|
return getPlatform().openPath(dir);
|
|
7267
7490
|
},
|
|
7268
7491
|
"task:getSpecs": async (taskId) => {
|
|
@@ -7396,7 +7619,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7396
7619
|
}
|
|
7397
7620
|
await removeTaskWorktree(task);
|
|
7398
7621
|
if (task.workspacePath) {
|
|
7399
|
-
|
|
7622
|
+
fs19.rmSync(taskAttachmentStagingPath(task.workspacePath, task.id), { recursive: true, force: true });
|
|
7400
7623
|
}
|
|
7401
7624
|
clearConversation(task.id);
|
|
7402
7625
|
removeTask(task.id);
|
|
@@ -7436,7 +7659,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7436
7659
|
);
|
|
7437
7660
|
},
|
|
7438
7661
|
"chat:compact": (taskId) => {
|
|
7439
|
-
const newSessionId =
|
|
7662
|
+
const newSessionId = randomUUID5();
|
|
7440
7663
|
clearMessages(requireTask(taskId).id, newSessionId);
|
|
7441
7664
|
return { newSessionId };
|
|
7442
7665
|
}
|
|
@@ -7449,9 +7672,9 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7449
7672
|
// Watch the containing directory, not the file: JsonStore renames a temp
|
|
7450
7673
|
// file over the target and so replaces the inode on every save.
|
|
7451
7674
|
watchStore() {
|
|
7452
|
-
const file =
|
|
7675
|
+
const file = path23.basename(getStorePath());
|
|
7453
7676
|
let debounce = null;
|
|
7454
|
-
storeWatcher =
|
|
7677
|
+
storeWatcher = fs19.watch(path23.dirname(getStorePath()), (_event, filename) => {
|
|
7455
7678
|
if (filename !== file) return;
|
|
7456
7679
|
if (debounce) clearTimeout(debounce);
|
|
7457
7680
|
debounce = setTimeout(() => {
|
|
@@ -7488,9 +7711,9 @@ function createSessionBackend(sink, choice) {
|
|
|
7488
7711
|
}
|
|
7489
7712
|
|
|
7490
7713
|
// packages/core/src/web-server.ts
|
|
7491
|
-
import
|
|
7714
|
+
import fs20 from "fs";
|
|
7492
7715
|
import http from "http";
|
|
7493
|
-
import
|
|
7716
|
+
import path24 from "path";
|
|
7494
7717
|
import { timingSafeEqual } from "crypto";
|
|
7495
7718
|
import { WebSocketServer } from "ws";
|
|
7496
7719
|
var TOKEN_COOKIE = "vf_token";
|
|
@@ -7543,14 +7766,14 @@ function resolveStatic(root, urlPath) {
|
|
|
7543
7766
|
return null;
|
|
7544
7767
|
}
|
|
7545
7768
|
if (decoded.includes("\0")) return null;
|
|
7546
|
-
const rel =
|
|
7547
|
-
const base2 =
|
|
7548
|
-
const candidates = [rel,
|
|
7769
|
+
const rel = path24.posix.normalize(decoded).replace(/^\/+/, "");
|
|
7770
|
+
const base2 = path24.resolve(root);
|
|
7771
|
+
const candidates = [rel, path24.posix.join(rel, "index.html"), `${rel}.html`];
|
|
7549
7772
|
for (const c of candidates) {
|
|
7550
|
-
const full =
|
|
7551
|
-
if (full !== base2 && !full.startsWith(base2 +
|
|
7773
|
+
const full = path24.resolve(base2, c);
|
|
7774
|
+
if (full !== base2 && !full.startsWith(base2 + path24.sep)) return null;
|
|
7552
7775
|
try {
|
|
7553
|
-
if (
|
|
7776
|
+
if (fs20.statSync(full).isFile()) return full;
|
|
7554
7777
|
} catch {
|
|
7555
7778
|
}
|
|
7556
7779
|
}
|
|
@@ -7611,7 +7834,7 @@ async function startWebServer(options) {
|
|
|
7611
7834
|
send(res, 404, "Not found");
|
|
7612
7835
|
return;
|
|
7613
7836
|
}
|
|
7614
|
-
const ext =
|
|
7837
|
+
const ext = path24.extname(file).toLowerCase();
|
|
7615
7838
|
const immutable = url.pathname.startsWith("/_next/static/");
|
|
7616
7839
|
res.writeHead(200, {
|
|
7617
7840
|
"Content-Type": CONTENT_TYPES[ext] ?? "application/octet-stream",
|
|
@@ -7624,7 +7847,7 @@ async function startWebServer(options) {
|
|
|
7624
7847
|
res.end();
|
|
7625
7848
|
return;
|
|
7626
7849
|
}
|
|
7627
|
-
|
|
7850
|
+
fs20.createReadStream(file).pipe(res);
|
|
7628
7851
|
}
|
|
7629
7852
|
const wss = new WebSocketServer({ noServer: true, maxPayload: MAX_PAYLOAD });
|
|
7630
7853
|
function reject(socket, status, reason) {
|
|
@@ -7723,8 +7946,8 @@ Content-Length: 0\r
|
|
|
7723
7946
|
}
|
|
7724
7947
|
|
|
7725
7948
|
// packages/cli/src/update-command.ts
|
|
7726
|
-
import
|
|
7727
|
-
import
|
|
7949
|
+
import fs21 from "node:fs";
|
|
7950
|
+
import path25 from "node:path";
|
|
7728
7951
|
import { spawnSync } from "node:child_process";
|
|
7729
7952
|
function npmRunner(args, inherit) {
|
|
7730
7953
|
const windows = process.platform === "win32";
|
|
@@ -7737,7 +7960,7 @@ function npmRunner(args, inherit) {
|
|
|
7737
7960
|
}
|
|
7738
7961
|
function packageName(packageRoot) {
|
|
7739
7962
|
try {
|
|
7740
|
-
const pkg = JSON.parse(
|
|
7963
|
+
const pkg = JSON.parse(fs21.readFileSync(path25.join(packageRoot, "package.json"), "utf8"));
|
|
7741
7964
|
if (typeof pkg.name !== "string") return null;
|
|
7742
7965
|
return /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/i.test(pkg.name) ? pkg.name : null;
|
|
7743
7966
|
} catch {
|
|
@@ -7752,7 +7975,7 @@ function runUpdate(options) {
|
|
|
7752
7975
|
error("vibeflow update \u53EA\u9069\u7528\u65BC\u5168\u57DF npm \u5B89\u88DD\uFF1B\u76EE\u524D\u662F\u539F\u59CB\u78BC\u7248\u672C\u3002");
|
|
7753
7976
|
return 1;
|
|
7754
7977
|
}
|
|
7755
|
-
const packageRoot =
|
|
7978
|
+
const packageRoot = path25.dirname(path25.dirname(options.cliEntry));
|
|
7756
7979
|
const name = packageName(packageRoot);
|
|
7757
7980
|
if (!name) {
|
|
7758
7981
|
error("\u7121\u6CD5\u8FA8\u8B58\u76EE\u524D VibeFlow \u7684 npm \u5957\u4EF6\u540D\u7A31\uFF0C\u5DF2\u53D6\u6D88\u66F4\u65B0\u3002");
|
|
@@ -7764,8 +7987,8 @@ function runUpdate(options) {
|
|
|
7764
7987
|
return 1;
|
|
7765
7988
|
}
|
|
7766
7989
|
try {
|
|
7767
|
-
const globalPackage =
|
|
7768
|
-
if (
|
|
7990
|
+
const globalPackage = path25.join(String(root.stdout).trim(), ...name.split("/"));
|
|
7991
|
+
if (fs21.lstatSync(globalPackage).isSymbolicLink() || fs21.realpathSync(globalPackage) !== fs21.realpathSync(packageRoot)) {
|
|
7769
7992
|
error("vibeflow update \u53EA\u9069\u7528\u65BC\u5168\u57DF npm \u5B89\u88DD\uFF1B\u76EE\u524D\u57F7\u884C\u7684\u5957\u4EF6\u4F86\u81EA\u5176\u4ED6\u4F4D\u7F6E\u3002");
|
|
7770
7993
|
return 1;
|
|
7771
7994
|
}
|
|
@@ -7861,7 +8084,7 @@ async function startHost(options) {
|
|
|
7861
8084
|
let availableUpdate = null;
|
|
7862
8085
|
let updateTimer = null;
|
|
7863
8086
|
let stopped = false;
|
|
7864
|
-
const installedPackage = options.sourceRoot || !options.cliEntry ? null : packageName(
|
|
8087
|
+
const installedPackage = options.sourceRoot || !options.cliEntry ? null : packageName(path26.dirname(path26.dirname(options.cliEntry)));
|
|
7865
8088
|
const checkUpdates = async () => {
|
|
7866
8089
|
if (!installedPackage) return;
|
|
7867
8090
|
try {
|
|
@@ -7923,7 +8146,7 @@ function loginUrl(lock, pathname = "/home/") {
|
|
|
7923
8146
|
return `http://127.0.0.1:${lock.port}${pathname}?token=${encodeURIComponent(lock.token)}`;
|
|
7924
8147
|
}
|
|
7925
8148
|
function isWebDir(dir) {
|
|
7926
|
-
return
|
|
8149
|
+
return fs22.existsSync(path26.join(dir, "home", "index.html"));
|
|
7927
8150
|
}
|
|
7928
8151
|
|
|
7929
8152
|
// packages/cli/src/remote.ts
|
|
@@ -8040,8 +8263,8 @@ function connectToHost(lock) {
|
|
|
8040
8263
|
}
|
|
8041
8264
|
|
|
8042
8265
|
// packages/cli/src/doctor.ts
|
|
8043
|
-
import
|
|
8044
|
-
import
|
|
8266
|
+
import fs23 from "fs";
|
|
8267
|
+
import path27 from "path";
|
|
8045
8268
|
import { execFile as execFile10 } from "child_process";
|
|
8046
8269
|
import { promisify as promisify7 } from "util";
|
|
8047
8270
|
init_env();
|
|
@@ -8181,10 +8404,10 @@ async function runDoctor(options) {
|
|
|
8181
8404
|
});
|
|
8182
8405
|
}
|
|
8183
8406
|
try {
|
|
8184
|
-
|
|
8185
|
-
const probe =
|
|
8186
|
-
|
|
8187
|
-
|
|
8407
|
+
fs23.mkdirSync(options.userDataDir, { recursive: true });
|
|
8408
|
+
const probe = path27.join(options.userDataDir, `.doctor-${process.pid}`);
|
|
8409
|
+
fs23.writeFileSync(probe, "");
|
|
8410
|
+
fs23.rmSync(probe);
|
|
8188
8411
|
checks.push({ id: "data", name: "\u8CC7\u6599\u76EE\u9304", level: "ok", detail: options.userDataDir });
|
|
8189
8412
|
} catch (err) {
|
|
8190
8413
|
checks.push({
|
|
@@ -8239,24 +8462,24 @@ Options:
|
|
|
8239
8462
|
`.trim();
|
|
8240
8463
|
function detectLayout() {
|
|
8241
8464
|
const file = fileURLToPath(import.meta.url);
|
|
8242
|
-
const here =
|
|
8243
|
-
const bundledWeb =
|
|
8244
|
-
if (isWebDir(bundledWeb) ||
|
|
8465
|
+
const here = path30.dirname(file);
|
|
8466
|
+
const bundledWeb = path30.join(here, "web");
|
|
8467
|
+
if (isWebDir(bundledWeb) || path30.basename(here) === "dist") {
|
|
8245
8468
|
return {
|
|
8246
|
-
version: readVersion(
|
|
8469
|
+
version: readVersion(path30.join(here, "..", "package.json")),
|
|
8247
8470
|
webDir: isWebDir(bundledWeb) ? bundledWeb : null,
|
|
8248
8471
|
sourceRoot: null,
|
|
8249
8472
|
cliEntry: file
|
|
8250
8473
|
};
|
|
8251
8474
|
}
|
|
8252
|
-
const root =
|
|
8475
|
+
const root = path30.resolve(here, "..", "..", "..");
|
|
8253
8476
|
const override = process.env.VIBEFLOW_WEB_DIR;
|
|
8254
|
-
const webDir = override && isWebDir(override) ? override : isWebDir(
|
|
8255
|
-
return { version: readVersion(
|
|
8477
|
+
const webDir = override && isWebDir(override) ? override : isWebDir(path30.join(root, "app")) ? path30.join(root, "app") : null;
|
|
8478
|
+
return { version: readVersion(path30.join(root, "package.json")), webDir, sourceRoot: root, cliEntry: null };
|
|
8256
8479
|
}
|
|
8257
8480
|
function readVersion(pkgPath) {
|
|
8258
8481
|
try {
|
|
8259
|
-
return JSON.parse(
|
|
8482
|
+
return JSON.parse(fs25.readFileSync(pkgPath, "utf8")).version;
|
|
8260
8483
|
} catch {
|
|
8261
8484
|
return "0.0.0";
|
|
8262
8485
|
}
|
|
@@ -8462,8 +8685,8 @@ async function cmdOpen(values, target, layout, userDataDir) {
|
|
|
8462
8685
|
console.error("\u7528\u6CD5\uFF1Avibeflow open <path>");
|
|
8463
8686
|
return 1;
|
|
8464
8687
|
}
|
|
8465
|
-
const dir =
|
|
8466
|
-
if (!
|
|
8688
|
+
const dir = path30.resolve(target);
|
|
8689
|
+
if (!fs25.existsSync(dir) || !fs25.statSync(dir).isDirectory()) {
|
|
8467
8690
|
console.error(`\u4E0D\u662F\u8CC7\u6599\u593E\uFF1A${dir}`);
|
|
8468
8691
|
return 1;
|
|
8469
8692
|
}
|