@kw-yeh/vibeflow 4.0.4 → 4.0.6
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/dist/vibeflow.mjs +242 -250
- package/dist/web/404/index.html +1 -1
- package/dist/web/404.html +1 -1
- package/dist/web/_next/static/chunks/{5896-9ec24bfe388d6661.js → 5426-48abe4a8b4f787e5.js} +2 -2
- package/dist/web/_next/static/chunks/pages/{_app-fde992b12936b886.js → _app-2c12a0c9ae85f245.js} +1 -1
- package/dist/web/_next/static/chunks/pages/home-0b1963318ed92bb5.js +11 -0
- package/dist/web/_next/static/css/{5576c1267923e491.css → 37b782400bf48851.css} +1 -1
- package/dist/web/_next/static/{zygbxZW3DHGve5whWS7yR → nFwNZkZhqIks3G972au7C}/_buildManifest.js +1 -1
- package/dist/web/home/index.html +1 -1
- package/package.json +1 -1
- package/dist/web/_next/static/chunks/pages/home-132f9ce2b08bd09d.js +0 -11
- /package/dist/web/_next/static/{zygbxZW3DHGve5whWS7yR → nFwNZkZhqIks3G972au7C}/_ssgManifest.js +0 -0
package/dist/vibeflow.mjs
CHANGED
|
@@ -598,9 +598,9 @@ var init_attachments = __esm({
|
|
|
598
598
|
|
|
599
599
|
// packages/tui/src/task-form.ts
|
|
600
600
|
import { spawnSync } from "child_process";
|
|
601
|
-
import
|
|
602
|
-
import
|
|
603
|
-
import
|
|
601
|
+
import fs18 from "fs";
|
|
602
|
+
import os6 from "os";
|
|
603
|
+
import path22 from "path";
|
|
604
604
|
import React, { useEffect, useRef, useState } from "react";
|
|
605
605
|
import { Box, Text, render, useApp, useInput } from "ink";
|
|
606
606
|
function newFormState(defaultAutoMode, agents) {
|
|
@@ -667,7 +667,7 @@ function visibleFields(s, ctx) {
|
|
|
667
667
|
return fields;
|
|
668
668
|
}
|
|
669
669
|
function modelOptions(ctx, agentCli, current) {
|
|
670
|
-
const listed = ctx.
|
|
670
|
+
const listed = ctx.models[agentCli] ?? [];
|
|
671
671
|
const options = ["", ...listed];
|
|
672
672
|
if (current && !listed.includes(current)) options.push(current);
|
|
673
673
|
return options;
|
|
@@ -719,17 +719,17 @@ function editorCommand(env, platform) {
|
|
|
719
719
|
return env.VISUAL?.trim() || env.EDITOR?.trim() || (platform === "win32" ? "notepad" : "vi");
|
|
720
720
|
}
|
|
721
721
|
function editInEditor(text) {
|
|
722
|
-
const dir =
|
|
723
|
-
const file =
|
|
722
|
+
const dir = fs18.mkdtempSync(path22.join(os6.tmpdir(), "vibeflow-"));
|
|
723
|
+
const file = path22.join(dir, "description.md");
|
|
724
724
|
try {
|
|
725
|
-
|
|
725
|
+
fs18.writeFileSync(file, text);
|
|
726
726
|
const cmd = editorCommand(process.env, process.platform);
|
|
727
727
|
const r = spawnSync(`${cmd} "${file}"`, { stdio: "inherit", shell: true });
|
|
728
728
|
if (r.error) return { error: `\u7121\u6CD5\u555F\u52D5\u7DE8\u8F2F\u5668\uFF08${cmd}\uFF09\uFF1A${r.error.message}` };
|
|
729
729
|
if (r.status !== 0) return { error: `\u7DE8\u8F2F\u5668\uFF08${cmd}\uFF09\u7D50\u675F\u78BC ${r.status}\uFF0C\u63CF\u8FF0\u672A\u8B8A\u66F4` };
|
|
730
|
-
return { text:
|
|
730
|
+
return { text: fs18.readFileSync(file, "utf8").replace(/\r?\n$/, "") };
|
|
731
731
|
} finally {
|
|
732
|
-
|
|
732
|
+
fs18.rmSync(dir, { recursive: true, force: true });
|
|
733
733
|
}
|
|
734
734
|
}
|
|
735
735
|
function cycle(list, current, step) {
|
|
@@ -797,10 +797,10 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
797
797
|
if (editing === "title") setS((prev) => ({ ...prev, title: draft }));
|
|
798
798
|
else if (editing === "branch") setS((prev) => ({ ...prev, branch: value2 }));
|
|
799
799
|
else if (editing === "project") {
|
|
800
|
-
if (value2) setProject(
|
|
800
|
+
if (value2) setProject(path22.resolve(value2.replace(/^~(?=$|\/)/, os6.homedir())));
|
|
801
801
|
} else if (editing === "attachments" && value2) {
|
|
802
|
-
const file =
|
|
803
|
-
if (!
|
|
802
|
+
const file = path22.resolve(value2.replace(/^~(?=$|\/)/, os6.homedir()));
|
|
803
|
+
if (!fs18.existsSync(file) || !fs18.statSync(file).isFile()) {
|
|
804
804
|
setMessage(`\u627E\u4E0D\u5230\u6A94\u6848\uFF1A${file}`);
|
|
805
805
|
return;
|
|
806
806
|
}
|
|
@@ -870,7 +870,7 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
870
870
|
case "title":
|
|
871
871
|
return s.title || "\uFF08\u4F8B\u5982\uFF1A\u5BE6\u4F5C\u767B\u5165\u9801\u9762\uFF09";
|
|
872
872
|
case "project": {
|
|
873
|
-
if (projectLocked) return `${s.projectPath ?
|
|
873
|
+
if (projectLocked) return `${s.projectPath ? path22.basename(s.projectPath) : "\u2014"}\uFF08\u4EFB\u52D9\u5DF2\u958B\u59CB\uFF0C\u9396\u5B9A\uFF09`;
|
|
874
874
|
if (!s.projectPath) return ctx.recent.length ? "\u2190/\u2192 \u9078\u64C7\u4F7F\u7528\u904E\u7684\u5C08\u6848\uFF0C\u6216 Enter \u8F38\u5165\u8DEF\u5F91" : "Enter \u8F38\u5165\u5C08\u6848\u8CC7\u6599\u593E\u7684\u7D55\u5C0D\u8DEF\u5F91";
|
|
875
875
|
return `${s.projectPath}${missing ? "\uFF08\u8DEF\u5F91\u907A\u5931\uFF09" : ""}`;
|
|
876
876
|
}
|
|
@@ -881,7 +881,7 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
881
881
|
case "branch":
|
|
882
882
|
return s.branch || "\uFF08\u7559\u7A7A\u5247\u81EA\u52D5\u547D\u540D\uFF0C\u4F8B\u5982 feature/login-fix\uFF09";
|
|
883
883
|
case "attachments":
|
|
884
|
-
return s.attachments.length ? s.attachments.map((a) =>
|
|
884
|
+
return s.attachments.length ? s.attachments.map((a) => path22.basename(a)).join("\u3001") : "\uFF08Enter \u8F38\u5165\u6A94\u6848\u8DEF\u5F91\u52A0\u5165\uFF09";
|
|
885
885
|
case "description": {
|
|
886
886
|
if (!s.description) return "\uFF08Enter \u7528\u7DE8\u8F2F\u5668\u64B0\u5BEB\uFF09";
|
|
887
887
|
const lines = s.description.split("\n");
|
|
@@ -899,7 +899,7 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
899
899
|
return `\u2039 ${ctx.agents.find((a) => a.id === s.agentCli)?.name ?? s.agentCli} \u203A`;
|
|
900
900
|
}
|
|
901
901
|
case "model":
|
|
902
|
-
return modelOptions(ctx, s.agentCli, s.model).length > 1 ? `\u2039 ${s.model || "\u4F7F\u7528\u9810\u8A2D model"} \u203A` : "\
|
|
902
|
+
return modelOptions(ctx, s.agentCli, s.model).length > 1 ? `\u2039 ${s.model || "\u4F7F\u7528\u9810\u8A2D model"} \u203A` : "\u7121\u6CD5\u53D6\u5F97 model list\uFF0C\u5C07\u4F7F\u7528\u9810\u8A2D model";
|
|
903
903
|
case "submit":
|
|
904
904
|
return busy ?? (s.mode === "new" ? "\uFF3B \u5EFA\u7ACB\u4EFB\u52D9 \uFF3D" : "\uFF3B \u5132\u5B58\u8B8A\u66F4 \uFF3D");
|
|
905
905
|
}
|
|
@@ -912,7 +912,7 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
912
912
|
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";
|
|
913
913
|
if (s.mode === "edit" && projectChanged(s)) return "\u66F4\u63DB\u5C08\u6848\u6703\u5728\u65B0\u5C08\u6848\u91CD\u5EFA worktree\uFF08\u6B64\u4EFB\u52D9\u5C1A\u672A\u958B\u59CB\uFF0C\u7121\u8B8A\u66F4\u6703\u907A\u5931\uFF09\u3002";
|
|
914
914
|
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`;
|
|
915
|
-
if (info?.isRepo && s.projectPath) return `worktree \u6703\u5EFA\u5728 ${ctx.workstationPath || "~/Desktop"}/${
|
|
915
|
+
if (info?.isRepo && s.projectPath) return `worktree \u6703\u5EFA\u5728 ${ctx.workstationPath || "~/Desktop"}/${path22.basename(s.projectPath)}`;
|
|
916
916
|
}
|
|
917
917
|
if (field === "branch") return info?.hasRemote ? "\u586B\u5BEB\u5F8C\u6703\u5EFA\u7ACB\u540C\u540D\u5206\u652F\uFF1B\u82E5 remote \u5DF2\u6709\u9019\u500B\u5206\u652F\uFF0C\u5247\u76F4\u63A5\u53D6\u56DE\u4E26\u63A5\u7E8C\u4E0A\u9762\u7684\u5DE5\u4F5C\u3002" : "\u586B\u5BEB\u5F8C\u6703\u5EFA\u7ACB\u540C\u540D\u5206\u652F\u3002";
|
|
918
918
|
if (field === "effort") return `${EFFORTS.find((x) => x.value === s.effort).description} Claude Code \u8207 Codex \u6703\u5728\u555F\u52D5\u6B64\u4EFB\u52D9\u6642\u5957\u7528\uFF1B\u5BE6\u969B\u53EF\u7528\u7D1A\u8DDD\u4F9D model \u800C\u5B9A\u3002`;
|
|
@@ -967,11 +967,17 @@ async function loadFormContext(api) {
|
|
|
967
967
|
api.listRecentProjects(),
|
|
968
968
|
Promise.race([api.detectAgents(), timeout]).catch(() => null)
|
|
969
969
|
]).finally(() => clearTimeout(timer));
|
|
970
|
+
const lists = await Promise.all(
|
|
971
|
+
(agents ?? []).map(async (a) => {
|
|
972
|
+
const list = await api.listAgentModels(a.id).catch(() => null);
|
|
973
|
+
return [a.id, list ? list.models.map((m) => m.id) : []];
|
|
974
|
+
})
|
|
975
|
+
);
|
|
970
976
|
return {
|
|
971
977
|
ctx: {
|
|
972
978
|
recent,
|
|
973
979
|
agents,
|
|
974
|
-
|
|
980
|
+
models: Object.fromEntries(lists),
|
|
975
981
|
workstationPath: state.settings.workstationPath?.trim() ?? ""
|
|
976
982
|
},
|
|
977
983
|
autoMode: state.settings.autoMode
|
|
@@ -1023,7 +1029,7 @@ __export(src_exports, {
|
|
|
1023
1029
|
showDiff: () => showDiff
|
|
1024
1030
|
});
|
|
1025
1031
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
1026
|
-
import
|
|
1032
|
+
import path23 from "path";
|
|
1027
1033
|
import React2, { useEffect as useEffect2, useState as useState2 } from "react";
|
|
1028
1034
|
import { Box as Box2, Text as Text2, render as render2, useApp as useApp2, useInput as useInput2, useStdout } from "ink";
|
|
1029
1035
|
function findDetachKey(text) {
|
|
@@ -1285,7 +1291,7 @@ function showDiff(task) {
|
|
|
1285
1291
|
});
|
|
1286
1292
|
}
|
|
1287
1293
|
function tmuxAttach(opts, sessionName) {
|
|
1288
|
-
const conf =
|
|
1294
|
+
const conf = path23.join(opts.userDataDir, "tmux.conf");
|
|
1289
1295
|
const inOurServer = (process.env.TMUX ?? "").split(",")[0].endsWith(`/${TMUX_SOCKET}`);
|
|
1290
1296
|
const args = inOurServer ? ["-L", TMUX_SOCKET, "-f", conf, "switch-client", "-t", `=${sessionName}`] : ["-L", TMUX_SOCKET, "-f", conf, "attach-session", "-t", `=${sessionName}`];
|
|
1291
1297
|
spawnSync2("tmux", args, { stdio: "inherit", env: { ...process.env, TMUX: inOurServer ? process.env.TMUX : "" } });
|
|
@@ -1415,8 +1421,8 @@ var init_src = __esm({
|
|
|
1415
1421
|
});
|
|
1416
1422
|
|
|
1417
1423
|
// packages/cli/src/main.ts
|
|
1418
|
-
import
|
|
1419
|
-
import
|
|
1424
|
+
import fs19 from "fs";
|
|
1425
|
+
import path24 from "path";
|
|
1420
1426
|
import { fileURLToPath } from "url";
|
|
1421
1427
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
1422
1428
|
|
|
@@ -1681,6 +1687,11 @@ function migrateStore(store) {
|
|
|
1681
1687
|
if (!store.has("recentProjects")) {
|
|
1682
1688
|
store.set("recentProjects", recentProjectsFromBoard(store.get("board")));
|
|
1683
1689
|
}
|
|
1690
|
+
const settings = store.get("settings");
|
|
1691
|
+
if (settings && "agentConnections" in settings) {
|
|
1692
|
+
const { agentConnections: _dropped, ...rest } = settings;
|
|
1693
|
+
store.set("settings", rest);
|
|
1694
|
+
}
|
|
1684
1695
|
if (persistedVersion < STATE_VERSION) {
|
|
1685
1696
|
store.set("version", STATE_VERSION);
|
|
1686
1697
|
}
|
|
@@ -1760,8 +1771,6 @@ function createBridge(t) {
|
|
|
1760
1771
|
},
|
|
1761
1772
|
setBoard: (board) => t.invoke("vibeflow:setBoard", board),
|
|
1762
1773
|
setSettings: (patch) => t.invoke("vibeflow:setSettings", patch),
|
|
1763
|
-
connectAgent: (agentId2, apiKey) => t.invoke("settings:connectAgent", { agentId: agentId2, apiKey }),
|
|
1764
|
-
refreshAgentModels: (agentId2) => t.invoke("settings:refreshAgentModels", agentId2),
|
|
1765
1774
|
getGithubAuthStatus: () => t.invoke("settings:githubAuthStatus"),
|
|
1766
1775
|
startGithubAuthLogin: () => t.invoke("settings:startGithubAuthLogin"),
|
|
1767
1776
|
cancelGithubAuthLogin: () => t.invoke("settings:cancelGithubAuthLogin"),
|
|
@@ -1776,6 +1785,8 @@ function createBridge(t) {
|
|
|
1776
1785
|
initRepository: (projectPath) => t.invoke("git:initRepository", projectPath),
|
|
1777
1786
|
/** Agent CLIs (claude / codex) actually installed on PATH. */
|
|
1778
1787
|
detectAgents: () => t.invoke("env:detectAgents"),
|
|
1788
|
+
/** Models the agent's own CLI offers; `refresh` asks the CLI instead of its cache. */
|
|
1789
|
+
listAgentModels: (agentId2, refresh = false) => t.invoke("agents:listModels", { agentId: agentId2, refresh }),
|
|
1779
1790
|
createTask: (payload) => t.invoke("vibeflow:createTask", payload),
|
|
1780
1791
|
updateTask: (payload) => t.invoke("vibeflow:updateTask", payload),
|
|
1781
1792
|
/** Clear prior execution state and prepare a fresh run of this task. */
|
|
@@ -3519,8 +3530,8 @@ async function taskCommand(argv) {
|
|
|
3519
3530
|
}
|
|
3520
3531
|
|
|
3521
3532
|
// packages/cli/src/host.ts
|
|
3522
|
-
import
|
|
3523
|
-
import
|
|
3533
|
+
import fs16 from "fs";
|
|
3534
|
+
import path20 from "path";
|
|
3524
3535
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
3525
3536
|
|
|
3526
3537
|
// packages/core/src/events.ts
|
|
@@ -3547,53 +3558,89 @@ var EventBus = class {
|
|
|
3547
3558
|
};
|
|
3548
3559
|
|
|
3549
3560
|
// packages/core/src/service.ts
|
|
3550
|
-
import
|
|
3551
|
-
import
|
|
3552
|
-
import
|
|
3561
|
+
import fs14 from "fs";
|
|
3562
|
+
import os5 from "os";
|
|
3563
|
+
import path18 from "path";
|
|
3553
3564
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
3554
3565
|
|
|
3555
|
-
// packages/core/src/agent-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
}
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
function
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
}
|
|
3578
|
-
}) : await fetch("https://api.openai.com/v1/models", {
|
|
3579
|
-
headers: {
|
|
3580
|
-
Authorization: `Bearer ${key}`
|
|
3581
|
-
}
|
|
3566
|
+
// packages/core/src/agent-models.ts
|
|
3567
|
+
import { execFile as execFile5 } from "child_process";
|
|
3568
|
+
import fs10 from "fs";
|
|
3569
|
+
import os3 from "os";
|
|
3570
|
+
import path14 from "path";
|
|
3571
|
+
import { promisify as promisify3 } from "util";
|
|
3572
|
+
init_env();
|
|
3573
|
+
var pexec3 = promisify3(execFile5);
|
|
3574
|
+
var CODEX_MODELS_TIMEOUT_MS = 2e4;
|
|
3575
|
+
function builtinModels(id) {
|
|
3576
|
+
return (AGENT_CLIS.find((a) => a.id === id) ?? AGENT_CLIS[0]).models;
|
|
3577
|
+
}
|
|
3578
|
+
function defaultCodexHome() {
|
|
3579
|
+
const configured = process.env.CODEX_HOME?.trim();
|
|
3580
|
+
return configured ? configured : path14.join(os3.homedir(), ".codex");
|
|
3581
|
+
}
|
|
3582
|
+
async function defaultRunCodexModels() {
|
|
3583
|
+
const { stdout } = await pexec3("codex", ["debug", "models"], {
|
|
3584
|
+
env: execEnv(),
|
|
3585
|
+
timeout: CODEX_MODELS_TIMEOUT_MS,
|
|
3586
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
3587
|
+
windowsHide: true
|
|
3582
3588
|
});
|
|
3583
|
-
|
|
3584
|
-
|
|
3589
|
+
return stdout;
|
|
3590
|
+
}
|
|
3591
|
+
function parseCodexCatalog(raw) {
|
|
3592
|
+
const body = JSON.parse(raw);
|
|
3593
|
+
if (!Array.isArray(body.models)) throw new Error("Codex model catalog has no models array");
|
|
3594
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3595
|
+
const models = [];
|
|
3596
|
+
for (const entry of body.models) {
|
|
3597
|
+
if (!entry || typeof entry !== "object") continue;
|
|
3598
|
+
const { slug, display_name: displayName, visibility } = entry;
|
|
3599
|
+
if (typeof slug !== "string" || !slug.trim() || visibility === "hide") continue;
|
|
3600
|
+
const id = slug.trim();
|
|
3601
|
+
if (seen.has(id)) continue;
|
|
3602
|
+
seen.add(id);
|
|
3603
|
+
models.push({
|
|
3604
|
+
id,
|
|
3605
|
+
label: typeof displayName === "string" && displayName.trim() ? displayName.trim() : id
|
|
3606
|
+
});
|
|
3607
|
+
}
|
|
3608
|
+
if (models.length === 0) throw new Error("Codex model catalog lists no selectable models");
|
|
3609
|
+
return models;
|
|
3610
|
+
}
|
|
3611
|
+
function errorMessage(err) {
|
|
3612
|
+
return err instanceof Error ? err.message : String(err);
|
|
3613
|
+
}
|
|
3614
|
+
async function listAgentModels(id, opts = {}) {
|
|
3615
|
+
if (id !== "codex") return { models: builtinModels(id), source: "builtin" };
|
|
3616
|
+
if (opts.refresh) {
|
|
3617
|
+
try {
|
|
3618
|
+
const stdout = await (opts.runCodexModels ?? defaultRunCodexModels)();
|
|
3619
|
+
return { models: parseCodexCatalog(stdout), source: "codex-cli" };
|
|
3620
|
+
} catch (err) {
|
|
3621
|
+
return { models: builtinModels(id), source: "builtin", error: errorMessage(err) };
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
const cachePath = path14.join(opts.codexHome ?? defaultCodexHome(), "models_cache.json");
|
|
3625
|
+
try {
|
|
3626
|
+
const raw = await fs10.promises.readFile(cachePath, "utf8");
|
|
3627
|
+
return { models: parseCodexCatalog(raw), source: "codex-cache" };
|
|
3628
|
+
} catch (err) {
|
|
3629
|
+
const missing = err.code === "ENOENT";
|
|
3630
|
+
return {
|
|
3631
|
+
models: builtinModels(id),
|
|
3632
|
+
source: "builtin",
|
|
3633
|
+
...missing ? {} : { error: errorMessage(err) }
|
|
3634
|
+
};
|
|
3585
3635
|
}
|
|
3586
|
-
const body = await response.json();
|
|
3587
|
-
const data = Array.isArray(body.data) ? body.data : [];
|
|
3588
|
-
return sortModels(data.map(modelIdFromUnknown).filter((id) => Boolean(id)));
|
|
3589
3636
|
}
|
|
3590
3637
|
|
|
3591
3638
|
// packages/core/src/github-auth.ts
|
|
3592
3639
|
init_env();
|
|
3593
|
-
import { execFile as
|
|
3594
|
-
import { promisify as
|
|
3640
|
+
import { execFile as execFile6 } from "child_process";
|
|
3641
|
+
import { promisify as promisify4 } from "util";
|
|
3595
3642
|
import * as nodePty3 from "node-pty";
|
|
3596
|
-
var
|
|
3643
|
+
var pexec4 = promisify4(execFile6);
|
|
3597
3644
|
var GITHUB_HOST = "github.com";
|
|
3598
3645
|
var DEVICE_URL = "https://github.com/login/device";
|
|
3599
3646
|
var activeLogin = null;
|
|
@@ -3622,13 +3669,13 @@ function statusFromBody(body) {
|
|
|
3622
3669
|
error: active.error
|
|
3623
3670
|
};
|
|
3624
3671
|
}
|
|
3625
|
-
function
|
|
3672
|
+
function errorMessage2(err) {
|
|
3626
3673
|
if (err instanceof Error) return err.message;
|
|
3627
3674
|
return String(err);
|
|
3628
3675
|
}
|
|
3629
3676
|
async function getGitHubCliAuthStatus() {
|
|
3630
3677
|
try {
|
|
3631
|
-
const { stdout } = await
|
|
3678
|
+
const { stdout } = await pexec4(
|
|
3632
3679
|
"gh",
|
|
3633
3680
|
["auth", "status", "--hostname", GITHUB_HOST, "--json", "hosts"],
|
|
3634
3681
|
{
|
|
@@ -3648,7 +3695,7 @@ async function getGitHubCliAuthStatus() {
|
|
|
3648
3695
|
} catch {
|
|
3649
3696
|
}
|
|
3650
3697
|
}
|
|
3651
|
-
const message =
|
|
3698
|
+
const message = errorMessage2(err);
|
|
3652
3699
|
return {
|
|
3653
3700
|
installed: !/ENOENT|not found/i.test(message),
|
|
3654
3701
|
authenticated: false,
|
|
@@ -3660,7 +3707,7 @@ async function logoutGitHubCli() {
|
|
|
3660
3707
|
const status = await getGitHubCliAuthStatus();
|
|
3661
3708
|
if (!status.installed) throw new Error("\u627E\u4E0D\u5230 GitHub CLI\uFF08gh\uFF09\u3002");
|
|
3662
3709
|
if (!status.login) return status;
|
|
3663
|
-
await
|
|
3710
|
+
await pexec4(
|
|
3664
3711
|
"gh",
|
|
3665
3712
|
["auth", "logout", "--hostname", GITHUB_HOST, "--user", status.login],
|
|
3666
3713
|
{
|
|
@@ -3701,7 +3748,7 @@ function startGitHubCliLogin(onEvent) {
|
|
|
3701
3748
|
}
|
|
3702
3749
|
);
|
|
3703
3750
|
} catch (err) {
|
|
3704
|
-
onEvent({ type: "error", error:
|
|
3751
|
+
onEvent({ type: "error", error: errorMessage2(err) });
|
|
3705
3752
|
return;
|
|
3706
3753
|
}
|
|
3707
3754
|
activeLogin = proc;
|
|
@@ -3743,38 +3790,38 @@ function startGitHubCliLogin(onEvent) {
|
|
|
3743
3790
|
}
|
|
3744
3791
|
|
|
3745
3792
|
// packages/core/src/board-cli.ts
|
|
3746
|
-
import
|
|
3747
|
-
import
|
|
3793
|
+
import fs11 from "fs";
|
|
3794
|
+
import path15 from "path";
|
|
3748
3795
|
import { pathToFileURL } from "url";
|
|
3749
3796
|
async function boardCliLaunchInfo() {
|
|
3750
|
-
const storeDir =
|
|
3797
|
+
const storeDir = path15.dirname(getStorePath());
|
|
3751
3798
|
const entry = getPlatform().cliEntry?.();
|
|
3752
|
-
if (entry &&
|
|
3799
|
+
if (entry && fs11.existsSync(entry)) return { storeDir, cliPath: entry };
|
|
3753
3800
|
const root = getPlatform().sourceRoot();
|
|
3754
3801
|
if (!root) return { storeDir };
|
|
3755
|
-
const cliPath =
|
|
3756
|
-
const loaderPath =
|
|
3757
|
-
if (!
|
|
3802
|
+
const cliPath = path15.join(root, "scripts", "vibeflow.mjs");
|
|
3803
|
+
const loaderPath = path15.join(root, "test", "support", "register.mjs");
|
|
3804
|
+
if (!fs11.existsSync(cliPath) || !fs11.existsSync(loaderPath)) return { storeDir };
|
|
3758
3805
|
return { storeDir, cliPath, loaderPath: pathToFileURL(loaderPath).href };
|
|
3759
3806
|
}
|
|
3760
3807
|
|
|
3761
3808
|
// packages/core/src/decisions.ts
|
|
3762
|
-
import
|
|
3763
|
-
import
|
|
3809
|
+
import fs12 from "fs";
|
|
3810
|
+
import path16 from "path";
|
|
3764
3811
|
var DECISIONS_FILE_SUFFIX = ".DECISIONS.md";
|
|
3765
3812
|
var MAX_DECISION_BYTES = 256 * 1024;
|
|
3766
3813
|
function decisionsKey(worktreePath, branch) {
|
|
3767
|
-
return worktreePath ?
|
|
3814
|
+
return worktreePath ? path16.basename(worktreePath) : branch.replace(/\//g, "-");
|
|
3768
3815
|
}
|
|
3769
3816
|
function decisionsPath(workspacePath, key) {
|
|
3770
|
-
return
|
|
3817
|
+
return path16.join(workspacePath, `${key}${DECISIONS_FILE_SUFFIX}`);
|
|
3771
3818
|
}
|
|
3772
3819
|
function readDecisions(workspacePath, key) {
|
|
3773
3820
|
const target = decisionsPath(workspacePath, key);
|
|
3774
3821
|
try {
|
|
3775
|
-
const stat =
|
|
3822
|
+
const stat = fs12.statSync(target);
|
|
3776
3823
|
if (!stat.isFile()) return { path: target, markdown: null };
|
|
3777
|
-
const buf =
|
|
3824
|
+
const buf = fs12.readFileSync(target);
|
|
3778
3825
|
return {
|
|
3779
3826
|
path: target,
|
|
3780
3827
|
markdown: buf.subarray(0, MAX_DECISION_BYTES).toString("utf8"),
|
|
@@ -3787,7 +3834,7 @@ function readDecisions(workspacePath, key) {
|
|
|
3787
3834
|
}
|
|
3788
3835
|
function deleteDecisions(workspacePath, key) {
|
|
3789
3836
|
try {
|
|
3790
|
-
|
|
3837
|
+
fs12.rmSync(decisionsPath(workspacePath, key), { force: true });
|
|
3791
3838
|
} catch {
|
|
3792
3839
|
}
|
|
3793
3840
|
}
|
|
@@ -4079,9 +4126,9 @@ function startChatSend(opts, sender) {
|
|
|
4079
4126
|
init_attachments();
|
|
4080
4127
|
|
|
4081
4128
|
// packages/core/src/library.ts
|
|
4082
|
-
import
|
|
4083
|
-
import
|
|
4084
|
-
import
|
|
4129
|
+
import fs13 from "fs";
|
|
4130
|
+
import os4 from "os";
|
|
4131
|
+
import path17 from "path";
|
|
4085
4132
|
var LIBRARY_DIR = "library";
|
|
4086
4133
|
var LIBRARY_KINDS = ["skill", "prompt", "script"];
|
|
4087
4134
|
var KIND_DIR = {
|
|
@@ -4094,15 +4141,15 @@ var MAX_NAME_BYTES = 100;
|
|
|
4094
4141
|
function libraryPaths(root) {
|
|
4095
4142
|
return {
|
|
4096
4143
|
root,
|
|
4097
|
-
skills:
|
|
4098
|
-
prompts:
|
|
4099
|
-
scripts:
|
|
4100
|
-
plugin:
|
|
4101
|
-
codexHome:
|
|
4144
|
+
skills: path17.join(root, KIND_DIR.skill),
|
|
4145
|
+
prompts: path17.join(root, KIND_DIR.prompt),
|
|
4146
|
+
scripts: path17.join(root, KIND_DIR.script),
|
|
4147
|
+
plugin: path17.join(root, "plugin"),
|
|
4148
|
+
codexHome: path17.join(root, "codex-home")
|
|
4102
4149
|
};
|
|
4103
4150
|
}
|
|
4104
4151
|
async function libraryRoot() {
|
|
4105
|
-
return
|
|
4152
|
+
return path17.join(getPlatform().userDataDir(), LIBRARY_DIR);
|
|
4106
4153
|
}
|
|
4107
4154
|
function truncateUtf82(value, maxBytes) {
|
|
4108
4155
|
let result = "";
|
|
@@ -4124,11 +4171,11 @@ function entryKey(kind, name) {
|
|
|
4124
4171
|
return `${kind}/${name}`;
|
|
4125
4172
|
}
|
|
4126
4173
|
function indexPath(root) {
|
|
4127
|
-
return
|
|
4174
|
+
return path17.join(root, INDEX_FILE);
|
|
4128
4175
|
}
|
|
4129
4176
|
function readIndex(root) {
|
|
4130
4177
|
try {
|
|
4131
|
-
const parsed = JSON.parse(
|
|
4178
|
+
const parsed = JSON.parse(fs13.readFileSync(indexPath(root), "utf8"));
|
|
4132
4179
|
if (parsed && typeof parsed === "object" && "entries" in parsed) {
|
|
4133
4180
|
const entries = parsed.entries;
|
|
4134
4181
|
if (entries && typeof entries === "object") return { version: 1, entries };
|
|
@@ -4138,21 +4185,21 @@ function readIndex(root) {
|
|
|
4138
4185
|
return { version: 1, entries: {} };
|
|
4139
4186
|
}
|
|
4140
4187
|
function writeIndex(root, index) {
|
|
4141
|
-
|
|
4142
|
-
|
|
4188
|
+
fs13.mkdirSync(root, { recursive: true });
|
|
4189
|
+
fs13.writeFileSync(indexPath(root), `${JSON.stringify(index, null, 2)}
|
|
4143
4190
|
`);
|
|
4144
4191
|
}
|
|
4145
4192
|
function ensureLibrary(root) {
|
|
4146
4193
|
const paths = libraryPaths(root);
|
|
4147
4194
|
for (const kind of LIBRARY_KINDS) {
|
|
4148
|
-
|
|
4195
|
+
fs13.mkdirSync(path17.join(root, KIND_DIR[kind]), { recursive: true });
|
|
4149
4196
|
}
|
|
4150
4197
|
return paths;
|
|
4151
4198
|
}
|
|
4152
4199
|
function readSkillDescription(skillMdPath) {
|
|
4153
4200
|
let content;
|
|
4154
4201
|
try {
|
|
4155
|
-
content =
|
|
4202
|
+
content = fs13.readFileSync(skillMdPath, "utf8");
|
|
4156
4203
|
} catch {
|
|
4157
4204
|
return void 0;
|
|
4158
4205
|
}
|
|
@@ -4167,16 +4214,16 @@ function readSkillDescription(skillMdPath) {
|
|
|
4167
4214
|
return void 0;
|
|
4168
4215
|
}
|
|
4169
4216
|
function entryPath(root, kind, name) {
|
|
4170
|
-
return
|
|
4217
|
+
return path17.join(root, KIND_DIR[kind], name);
|
|
4171
4218
|
}
|
|
4172
4219
|
function listLibrary(root) {
|
|
4173
4220
|
const index = readIndex(root);
|
|
4174
4221
|
const entries = [];
|
|
4175
4222
|
for (const kind of LIBRARY_KINDS) {
|
|
4176
|
-
const dir =
|
|
4223
|
+
const dir = path17.join(root, KIND_DIR[kind]);
|
|
4177
4224
|
let dirents;
|
|
4178
4225
|
try {
|
|
4179
|
-
dirents =
|
|
4226
|
+
dirents = fs13.readdirSync(dir, { withFileTypes: true });
|
|
4180
4227
|
} catch {
|
|
4181
4228
|
continue;
|
|
4182
4229
|
}
|
|
@@ -4185,14 +4232,14 @@ function listLibrary(root) {
|
|
|
4185
4232
|
const wantsDirectory = kind === "skill";
|
|
4186
4233
|
let stat;
|
|
4187
4234
|
try {
|
|
4188
|
-
stat =
|
|
4235
|
+
stat = fs13.statSync(path17.join(dir, dirent.name));
|
|
4189
4236
|
} catch {
|
|
4190
4237
|
continue;
|
|
4191
4238
|
}
|
|
4192
4239
|
if (stat.isDirectory() !== wantsDirectory) continue;
|
|
4193
4240
|
const name = dirent.name;
|
|
4194
|
-
const full =
|
|
4195
|
-
if (wantsDirectory && !
|
|
4241
|
+
const full = path17.join(dir, name);
|
|
4242
|
+
if (wantsDirectory && !fs13.existsSync(path17.join(full, "SKILL.md"))) continue;
|
|
4196
4243
|
const key = entryKey(kind, name);
|
|
4197
4244
|
const record = index.entries[key] ?? {};
|
|
4198
4245
|
entries.push({
|
|
@@ -4200,7 +4247,7 @@ function listLibrary(root) {
|
|
|
4200
4247
|
kind,
|
|
4201
4248
|
name,
|
|
4202
4249
|
path: full,
|
|
4203
|
-
description: wantsDirectory ? readSkillDescription(
|
|
4250
|
+
description: wantsDirectory ? readSkillDescription(path17.join(full, "SKILL.md")) : record.description,
|
|
4204
4251
|
sourcePath: record.sourcePath,
|
|
4205
4252
|
importedAt: record.importedAt,
|
|
4206
4253
|
enabled: record.enabled !== false
|
|
@@ -4216,21 +4263,21 @@ function annotate(root, key, patch) {
|
|
|
4216
4263
|
}
|
|
4217
4264
|
function importEntry(root, kind, sourcePath) {
|
|
4218
4265
|
ensureLibrary(root);
|
|
4219
|
-
const resolved =
|
|
4220
|
-
const stat =
|
|
4266
|
+
const resolved = path17.resolve(sourcePath);
|
|
4267
|
+
const stat = fs13.statSync(resolved);
|
|
4221
4268
|
if (kind === "skill") {
|
|
4222
4269
|
if (!stat.isDirectory()) throw new Error("skill \u5FC5\u9808\u662F\u542B SKILL.md \u7684\u76EE\u9304");
|
|
4223
|
-
if (!
|
|
4270
|
+
if (!fs13.existsSync(path17.join(resolved, "SKILL.md"))) {
|
|
4224
4271
|
throw new Error("\u76EE\u9304\u5167\u627E\u4E0D\u5230 SKILL.md");
|
|
4225
4272
|
}
|
|
4226
4273
|
} else if (!stat.isFile()) {
|
|
4227
4274
|
throw new Error(`${kind} \u5FC5\u9808\u662F\u55AE\u4E00\u6A94\u6848`);
|
|
4228
4275
|
}
|
|
4229
|
-
const name = safeLibraryName(
|
|
4276
|
+
const name = safeLibraryName(path17.basename(resolved));
|
|
4230
4277
|
const target = entryPath(root, kind, name);
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
if (kind === "script")
|
|
4278
|
+
fs13.rmSync(target, { recursive: true, force: true });
|
|
4279
|
+
fs13.cpSync(resolved, target, { recursive: kind === "skill", dereference: true });
|
|
4280
|
+
if (kind === "script") fs13.chmodSync(target, 493);
|
|
4234
4281
|
annotate(root, entryKey(kind, name), {
|
|
4235
4282
|
sourcePath: resolved,
|
|
4236
4283
|
importedAt: Date.now(),
|
|
@@ -4242,13 +4289,13 @@ function createEntry(root, kind, rawName, content, description) {
|
|
|
4242
4289
|
ensureLibrary(root);
|
|
4243
4290
|
const name = safeLibraryName(rawName);
|
|
4244
4291
|
const target = entryPath(root, kind, name);
|
|
4245
|
-
if (
|
|
4292
|
+
if (fs13.existsSync(target)) throw new Error(`\u5DF2\u5B58\u5728\u540C\u540D\u9805\u76EE\uFF1A${name}`);
|
|
4246
4293
|
if (kind === "skill") {
|
|
4247
|
-
|
|
4248
|
-
|
|
4294
|
+
fs13.mkdirSync(target, { recursive: true });
|
|
4295
|
+
fs13.writeFileSync(path17.join(target, "SKILL.md"), content);
|
|
4249
4296
|
} else {
|
|
4250
|
-
|
|
4251
|
-
if (kind === "script")
|
|
4297
|
+
fs13.writeFileSync(target, content);
|
|
4298
|
+
if (kind === "script") fs13.chmodSync(target, 493);
|
|
4252
4299
|
}
|
|
4253
4300
|
annotate(root, entryKey(kind, name), {
|
|
4254
4301
|
importedAt: Date.now(),
|
|
@@ -4262,16 +4309,16 @@ function setEntryDescription(root, kind, name, description) {
|
|
|
4262
4309
|
}
|
|
4263
4310
|
function updateEntry(root, kind, name, content) {
|
|
4264
4311
|
const target = entryPath(root, kind, name);
|
|
4265
|
-
if (!
|
|
4266
|
-
|
|
4312
|
+
if (!fs13.existsSync(target)) throw new Error(`\u627E\u4E0D\u5230\u9805\u76EE\uFF1A${name}`);
|
|
4313
|
+
fs13.writeFileSync(kind === "skill" ? path17.join(target, "SKILL.md") : target, content);
|
|
4267
4314
|
return requireEntry(root, kind, name);
|
|
4268
4315
|
}
|
|
4269
4316
|
function readEntryContent(root, kind, name) {
|
|
4270
4317
|
const target = entryPath(root, kind, name);
|
|
4271
|
-
return
|
|
4318
|
+
return fs13.readFileSync(kind === "skill" ? path17.join(target, "SKILL.md") : target, "utf8");
|
|
4272
4319
|
}
|
|
4273
4320
|
function deleteEntry(root, kind, name) {
|
|
4274
|
-
|
|
4321
|
+
fs13.rmSync(entryPath(root, kind, name), { recursive: true, force: true });
|
|
4275
4322
|
const index = readIndex(root);
|
|
4276
4323
|
delete index.entries[entryKey(kind, name)];
|
|
4277
4324
|
writeIndex(root, index);
|
|
@@ -4285,11 +4332,11 @@ function requireEntry(root, kind, name) {
|
|
|
4285
4332
|
return found2;
|
|
4286
4333
|
}
|
|
4287
4334
|
function projectSkillsDir(worktreePath) {
|
|
4288
|
-
return
|
|
4335
|
+
return path17.join(worktreePath, ".claude", "skills");
|
|
4289
4336
|
}
|
|
4290
4337
|
function skillNamesIn(dir) {
|
|
4291
4338
|
try {
|
|
4292
|
-
return
|
|
4339
|
+
return fs13.readdirSync(dir, { withFileTypes: true }).filter((d) => !d.name.startsWith(".")).map((d) => d.name).filter((name) => fs13.existsSync(path17.join(dir, name, "SKILL.md"))).sort();
|
|
4293
4340
|
} catch {
|
|
4294
4341
|
return [];
|
|
4295
4342
|
}
|
|
@@ -4298,11 +4345,11 @@ var PLUGIN_MANIFEST_DIR = ".claude-plugin";
|
|
|
4298
4345
|
function buildPluginDir(root) {
|
|
4299
4346
|
const paths = libraryPaths(root);
|
|
4300
4347
|
const enabled = listLibrary(root).filter((e) => e.kind === "skill" && e.enabled);
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4348
|
+
fs13.rmSync(path17.join(paths.plugin, "skills"), { recursive: true, force: true });
|
|
4349
|
+
fs13.mkdirSync(path17.join(paths.plugin, PLUGIN_MANIFEST_DIR), { recursive: true });
|
|
4350
|
+
fs13.mkdirSync(path17.join(paths.plugin, "skills"), { recursive: true });
|
|
4351
|
+
fs13.writeFileSync(
|
|
4352
|
+
path17.join(paths.plugin, PLUGIN_MANIFEST_DIR, "plugin.json"),
|
|
4306
4353
|
`${JSON.stringify(
|
|
4307
4354
|
{
|
|
4308
4355
|
name: "vibeflow-library",
|
|
@@ -4315,7 +4362,7 @@ function buildPluginDir(root) {
|
|
|
4315
4362
|
`
|
|
4316
4363
|
);
|
|
4317
4364
|
for (const entry of enabled) {
|
|
4318
|
-
|
|
4365
|
+
fs13.cpSync(entry.path, path17.join(paths.plugin, "skills", entry.name), {
|
|
4319
4366
|
recursive: true,
|
|
4320
4367
|
dereference: true
|
|
4321
4368
|
});
|
|
@@ -4323,19 +4370,19 @@ function buildPluginDir(root) {
|
|
|
4323
4370
|
return { pluginDir: paths.plugin, skills: enabled.map((e) => e.name) };
|
|
4324
4371
|
}
|
|
4325
4372
|
function linkOrSkip(target, linkPath) {
|
|
4326
|
-
if (!
|
|
4327
|
-
const source =
|
|
4328
|
-
const attempts =
|
|
4329
|
-
() =>
|
|
4330
|
-
() =>
|
|
4373
|
+
if (!fs13.existsSync(target)) return false;
|
|
4374
|
+
const source = path17.resolve(target);
|
|
4375
|
+
const attempts = fs13.statSync(source).isDirectory() ? [
|
|
4376
|
+
() => fs13.symlinkSync(source, linkPath, "junction"),
|
|
4377
|
+
() => fs13.cpSync(source, linkPath, { recursive: true, dereference: true })
|
|
4331
4378
|
] : [
|
|
4332
|
-
() =>
|
|
4333
|
-
() =>
|
|
4334
|
-
() =>
|
|
4379
|
+
() => fs13.symlinkSync(source, linkPath),
|
|
4380
|
+
() => fs13.linkSync(source, linkPath),
|
|
4381
|
+
() => fs13.copyFileSync(source, linkPath)
|
|
4335
4382
|
];
|
|
4336
4383
|
for (const attempt of attempts) {
|
|
4337
4384
|
try {
|
|
4338
|
-
|
|
4385
|
+
fs13.rmSync(linkPath, { recursive: true, force: true });
|
|
4339
4386
|
attempt();
|
|
4340
4387
|
return true;
|
|
4341
4388
|
} catch {
|
|
@@ -4343,13 +4390,13 @@ function linkOrSkip(target, linkPath) {
|
|
|
4343
4390
|
}
|
|
4344
4391
|
return false;
|
|
4345
4392
|
}
|
|
4346
|
-
function buildCodexHome(root, worktreePath, userCodexHome =
|
|
4393
|
+
function buildCodexHome(root, worktreePath, userCodexHome = path17.join(os4.homedir(), ".codex")) {
|
|
4347
4394
|
const paths = libraryPaths(root);
|
|
4348
|
-
const skillsDir =
|
|
4349
|
-
|
|
4350
|
-
|
|
4395
|
+
const skillsDir = path17.join(paths.codexHome, "skills");
|
|
4396
|
+
fs13.rmSync(skillsDir, { recursive: true, force: true });
|
|
4397
|
+
fs13.mkdirSync(skillsDir, { recursive: true });
|
|
4351
4398
|
for (const file of ["auth.json", "config.toml"]) {
|
|
4352
|
-
linkOrSkip(
|
|
4399
|
+
linkOrSkip(path17.join(userCodexHome, file), path17.join(paths.codexHome, file));
|
|
4353
4400
|
}
|
|
4354
4401
|
const result = {
|
|
4355
4402
|
codexHome: paths.codexHome,
|
|
@@ -4362,20 +4409,20 @@ function buildCodexHome(root, worktreePath, userCodexHome = path16.join(os3.home
|
|
|
4362
4409
|
const projectDir = worktreePath ? projectSkillsDir(worktreePath) : void 0;
|
|
4363
4410
|
if (projectDir) {
|
|
4364
4411
|
for (const name of skillNamesIn(projectDir)) {
|
|
4365
|
-
if (linkOrSkip(
|
|
4412
|
+
if (linkOrSkip(path17.join(projectDir, name), path17.join(skillsDir, name))) {
|
|
4366
4413
|
result.project.push(name);
|
|
4367
4414
|
claimed.set(name, "project");
|
|
4368
4415
|
}
|
|
4369
4416
|
}
|
|
4370
4417
|
}
|
|
4371
|
-
const userDir =
|
|
4418
|
+
const userDir = path17.join(userCodexHome, "skills");
|
|
4372
4419
|
for (const name of skillNamesIn(userDir)) {
|
|
4373
4420
|
const owner = claimed.get(name);
|
|
4374
4421
|
if (owner) {
|
|
4375
4422
|
result.shadowed.push({ name, keptFrom: owner, dropped: "user" });
|
|
4376
4423
|
continue;
|
|
4377
4424
|
}
|
|
4378
|
-
if (linkOrSkip(
|
|
4425
|
+
if (linkOrSkip(path17.join(userDir, name), path17.join(skillsDir, name))) {
|
|
4379
4426
|
result.user.push(name);
|
|
4380
4427
|
claimed.set(name, "user");
|
|
4381
4428
|
}
|
|
@@ -4387,7 +4434,7 @@ function buildCodexHome(root, worktreePath, userCodexHome = path16.join(os3.home
|
|
|
4387
4434
|
result.shadowed.push({ name: entry.name, keptFrom: owner, dropped: "library" });
|
|
4388
4435
|
continue;
|
|
4389
4436
|
}
|
|
4390
|
-
|
|
4437
|
+
fs13.cpSync(entry.path, path17.join(skillsDir, entry.name), {
|
|
4391
4438
|
recursive: true,
|
|
4392
4439
|
dereference: true
|
|
4393
4440
|
});
|
|
@@ -4703,13 +4750,13 @@ function createCore({ sessions, bus, version }) {
|
|
|
4703
4750
|
}
|
|
4704
4751
|
function claudeSessionFile(cwd, sessionId) {
|
|
4705
4752
|
const munged = cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
4706
|
-
return
|
|
4753
|
+
return path18.join(os5.homedir(), ".claude", "projects", munged, `${sessionId}.jsonl`);
|
|
4707
4754
|
}
|
|
4708
4755
|
async function removeTaskWorktree(task) {
|
|
4709
4756
|
if (!task.projectPath || !task.worktreePath) return;
|
|
4710
4757
|
const branch = task.branch || fallbackBranchName(task.id);
|
|
4711
4758
|
await removeWorktree(task.projectPath, task.worktreePath);
|
|
4712
|
-
deleteArtifacts(task.workspacePath ??
|
|
4759
|
+
deleteArtifacts(task.workspacePath ?? path18.dirname(task.worktreePath), task.worktreePath);
|
|
4713
4760
|
await deleteBranch(task.projectPath, branch);
|
|
4714
4761
|
}
|
|
4715
4762
|
const handlers = {
|
|
@@ -4720,66 +4767,7 @@ function createCore({ sessions, bus, version }) {
|
|
|
4720
4767
|
return getState();
|
|
4721
4768
|
},
|
|
4722
4769
|
"vibeflow:setSettings": (patch) => {
|
|
4723
|
-
|
|
4724
|
-
const { agentConnections: _ignored, ...rest } = p;
|
|
4725
|
-
setSettings(rest);
|
|
4726
|
-
return getState();
|
|
4727
|
-
},
|
|
4728
|
-
"settings:connectAgent": async (payload) => {
|
|
4729
|
-
const { agentId: rawId, apiKey } = obj(payload, "payload");
|
|
4730
|
-
const id = agentId(rawId);
|
|
4731
|
-
const key = str(apiKey, "apiKey");
|
|
4732
|
-
const models = await fetchAgentModels(id, key);
|
|
4733
|
-
const state = getState();
|
|
4734
|
-
setSettings({
|
|
4735
|
-
agentConnections: {
|
|
4736
|
-
...state.settings.agentConnections ?? {},
|
|
4737
|
-
[id]: {
|
|
4738
|
-
connected: true,
|
|
4739
|
-
apiKey: key.trim(),
|
|
4740
|
-
models,
|
|
4741
|
-
error: void 0,
|
|
4742
|
-
updatedAt: Date.now()
|
|
4743
|
-
}
|
|
4744
|
-
}
|
|
4745
|
-
});
|
|
4746
|
-
return getState();
|
|
4747
|
-
},
|
|
4748
|
-
"settings:refreshAgentModels": async (rawId) => {
|
|
4749
|
-
const id = agentId(rawId);
|
|
4750
|
-
const connections = getState().settings.agentConnections ?? {};
|
|
4751
|
-
const existing = connections[id];
|
|
4752
|
-
if (!existing?.apiKey) {
|
|
4753
|
-
setSettings({
|
|
4754
|
-
agentConnections: {
|
|
4755
|
-
...connections,
|
|
4756
|
-
[id]: { connected: false, models: [], error: "\u5C1A\u672A\u7D81\u5B9A API key\u3002", updatedAt: Date.now() }
|
|
4757
|
-
}
|
|
4758
|
-
});
|
|
4759
|
-
return getState();
|
|
4760
|
-
}
|
|
4761
|
-
try {
|
|
4762
|
-
const models = await fetchAgentModels(id, existing.apiKey);
|
|
4763
|
-
setSettings({
|
|
4764
|
-
agentConnections: {
|
|
4765
|
-
...connections,
|
|
4766
|
-
[id]: { ...existing, connected: true, models, error: void 0, updatedAt: Date.now() }
|
|
4767
|
-
}
|
|
4768
|
-
});
|
|
4769
|
-
} catch (err) {
|
|
4770
|
-
setSettings({
|
|
4771
|
-
agentConnections: {
|
|
4772
|
-
...connections,
|
|
4773
|
-
[id]: {
|
|
4774
|
-
...existing,
|
|
4775
|
-
connected: false,
|
|
4776
|
-
models: [],
|
|
4777
|
-
error: err instanceof Error ? err.message : String(err),
|
|
4778
|
-
updatedAt: Date.now()
|
|
4779
|
-
}
|
|
4780
|
-
}
|
|
4781
|
-
});
|
|
4782
|
-
}
|
|
4770
|
+
setSettings(obj(patch, "patch"));
|
|
4783
4771
|
return getState();
|
|
4784
4772
|
},
|
|
4785
4773
|
"settings:githubAuthStatus": () => getGitHubCliAuthStatus(),
|
|
@@ -4791,6 +4779,10 @@ function createCore({ sessions, bus, version }) {
|
|
|
4791
4779
|
},
|
|
4792
4780
|
"settings:logoutGithubAuth": () => logoutGitHubCli(),
|
|
4793
4781
|
"env:detectAgents": () => detectAgents(),
|
|
4782
|
+
"agents:listModels": (payload) => {
|
|
4783
|
+
const { agentId: rawId, refresh } = obj(payload, "payload");
|
|
4784
|
+
return listAgentModels(agentId(rawId), { refresh: refresh === true });
|
|
4785
|
+
},
|
|
4794
4786
|
// A task does not exist yet when a project is picked, so these two are the
|
|
4795
4787
|
// ones that must take a path. They only inspect or `git init` it.
|
|
4796
4788
|
"git:getInfo": (projectPath) => getGitInfo(str(projectPath ?? "", "projectPath")),
|
|
@@ -4803,8 +4795,8 @@ function createCore({ sessions, bus, version }) {
|
|
|
4803
4795
|
"projects:listRecent": () => listRecentProjects(getStore()),
|
|
4804
4796
|
// `vibeflow open <path>` while a host runs: only the host writes the store.
|
|
4805
4797
|
"projects:record": (projectPath) => {
|
|
4806
|
-
const p =
|
|
4807
|
-
if (!
|
|
4798
|
+
const p = path18.resolve(str(projectPath, "projectPath"));
|
|
4799
|
+
if (!fs14.existsSync(p) || !fs14.statSync(p).isDirectory()) invalid(`not a directory: ${p}`);
|
|
4808
4800
|
recordRecentProject(getStore(), p);
|
|
4809
4801
|
return listRecentProjects(getStore());
|
|
4810
4802
|
},
|
|
@@ -4844,7 +4836,7 @@ function createCore({ sessions, bus, version }) {
|
|
|
4844
4836
|
if (!task.baseBranch) throw new Error("\u4EFB\u52D9\u6C92\u6709\u8A18\u9304 base branch\uFF0C\u7121\u6CD5\u9084\u539F worktree");
|
|
4845
4837
|
await teardownTask(task.id);
|
|
4846
4838
|
await resetWorktreeToBase(task.worktreePath, task.baseBranch);
|
|
4847
|
-
const workspacePath = task.workspacePath ??
|
|
4839
|
+
const workspacePath = task.workspacePath ?? path18.dirname(task.worktreePath);
|
|
4848
4840
|
deleteArtifacts(workspacePath, task.worktreePath);
|
|
4849
4841
|
deleteDecisions(workspacePath, decisionsKey(task.worktreePath, task.branch));
|
|
4850
4842
|
resetSubAgents(task.worktreePath);
|
|
@@ -4883,9 +4875,9 @@ function createCore({ sessions, bus, version }) {
|
|
|
4883
4875
|
if (!info.isRepo) throw new Error("\u76EE\u6A19\u8CC7\u6599\u593E\u4E0D\u662F git repository");
|
|
4884
4876
|
await teardownTask(existing.id);
|
|
4885
4877
|
await removeTaskWorktree(existing);
|
|
4886
|
-
const projectName =
|
|
4878
|
+
const projectName = path18.basename(nextProject);
|
|
4887
4879
|
const workspacePath = projectWorkstationPath(resolveWorkstationPath(getSettings()), projectName);
|
|
4888
|
-
await
|
|
4880
|
+
await fs14.promises.mkdir(workspacePath, { recursive: true });
|
|
4889
4881
|
const result = await provisionWorktree(
|
|
4890
4882
|
nextProject,
|
|
4891
4883
|
workspacePath,
|
|
@@ -4973,7 +4965,7 @@ function createCore({ sessions, bus, version }) {
|
|
|
4973
4965
|
"claude:sessionExists": (taskId) => {
|
|
4974
4966
|
const task = requireTask(taskId);
|
|
4975
4967
|
if (!task.worktreePath) return false;
|
|
4976
|
-
return
|
|
4968
|
+
return fs14.existsSync(claudeSessionFile(task.worktreePath, executorSessionId(task.id, task.runId)));
|
|
4977
4969
|
},
|
|
4978
4970
|
"sessions:list": async () => {
|
|
4979
4971
|
const keys = await sessions.list();
|
|
@@ -4992,9 +4984,9 @@ function createCore({ sessions, bus, version }) {
|
|
|
4992
4984
|
"git:getDiffEntries": (taskId, opts) => {
|
|
4993
4985
|
const task = requireTask(taskId);
|
|
4994
4986
|
if (!task.worktreePath) return [];
|
|
4995
|
-
const
|
|
4987
|
+
const fetch = opts && typeof opts === "object" ? opts.fetch : void 0;
|
|
4996
4988
|
return getWorktreeDiffEntries(task.worktreePath, task.baseBranch ?? "HEAD", {
|
|
4997
|
-
fetch: typeof
|
|
4989
|
+
fetch: typeof fetch === "boolean" ? fetch : void 0
|
|
4998
4990
|
});
|
|
4999
4991
|
},
|
|
5000
4992
|
"git:getDiffFile": (taskId, filePath) => {
|
|
@@ -5020,7 +5012,7 @@ function createCore({ sessions, bus, version }) {
|
|
|
5020
5012
|
const task = requireTask(taskId);
|
|
5021
5013
|
if (!task.worktreePath || !task.workspacePath) return "task has no worktree";
|
|
5022
5014
|
const dir = agentArtifactsPath(task.workspacePath, task.worktreePath);
|
|
5023
|
-
if (!
|
|
5015
|
+
if (!fs14.existsSync(dir)) return "artifacts directory does not exist yet";
|
|
5024
5016
|
return getPlatform().openPath(dir);
|
|
5025
5017
|
},
|
|
5026
5018
|
"task:getDecisions": (taskId) => {
|
|
@@ -5173,9 +5165,9 @@ function createCore({ sessions, bus, version }) {
|
|
|
5173
5165
|
// Watch the containing directory, not the file: JsonStore renames a temp
|
|
5174
5166
|
// file over the target and so replaces the inode on every save.
|
|
5175
5167
|
watchStore() {
|
|
5176
|
-
const file =
|
|
5168
|
+
const file = path18.basename(getStorePath());
|
|
5177
5169
|
let debounce = null;
|
|
5178
|
-
storeWatcher =
|
|
5170
|
+
storeWatcher = fs14.watch(path18.dirname(getStorePath()), (_event, filename) => {
|
|
5179
5171
|
if (filename !== file) return;
|
|
5180
5172
|
if (debounce) clearTimeout(debounce);
|
|
5181
5173
|
debounce = setTimeout(() => {
|
|
@@ -5207,9 +5199,9 @@ function createSessionBackend(sink, choice) {
|
|
|
5207
5199
|
}
|
|
5208
5200
|
|
|
5209
5201
|
// packages/core/src/web-server.ts
|
|
5210
|
-
import
|
|
5202
|
+
import fs15 from "fs";
|
|
5211
5203
|
import http from "http";
|
|
5212
|
-
import
|
|
5204
|
+
import path19 from "path";
|
|
5213
5205
|
import { timingSafeEqual } from "crypto";
|
|
5214
5206
|
import { WebSocketServer } from "ws";
|
|
5215
5207
|
var TOKEN_COOKIE = "vf_token";
|
|
@@ -5262,14 +5254,14 @@ function resolveStatic(root, urlPath) {
|
|
|
5262
5254
|
return null;
|
|
5263
5255
|
}
|
|
5264
5256
|
if (decoded.includes("\0")) return null;
|
|
5265
|
-
const rel =
|
|
5266
|
-
const base =
|
|
5267
|
-
const candidates = [rel,
|
|
5257
|
+
const rel = path19.posix.normalize(decoded).replace(/^\/+/, "");
|
|
5258
|
+
const base = path19.resolve(root);
|
|
5259
|
+
const candidates = [rel, path19.posix.join(rel, "index.html"), `${rel}.html`];
|
|
5268
5260
|
for (const c of candidates) {
|
|
5269
|
-
const full =
|
|
5270
|
-
if (full !== base && !full.startsWith(base +
|
|
5261
|
+
const full = path19.resolve(base, c);
|
|
5262
|
+
if (full !== base && !full.startsWith(base + path19.sep)) return null;
|
|
5271
5263
|
try {
|
|
5272
|
-
if (
|
|
5264
|
+
if (fs15.statSync(full).isFile()) return full;
|
|
5273
5265
|
} catch {
|
|
5274
5266
|
}
|
|
5275
5267
|
}
|
|
@@ -5330,7 +5322,7 @@ async function startWebServer(options) {
|
|
|
5330
5322
|
send(res, 404, "Not found");
|
|
5331
5323
|
return;
|
|
5332
5324
|
}
|
|
5333
|
-
const ext =
|
|
5325
|
+
const ext = path19.extname(file).toLowerCase();
|
|
5334
5326
|
const immutable = url.pathname.startsWith("/_next/static/");
|
|
5335
5327
|
res.writeHead(200, {
|
|
5336
5328
|
"Content-Type": CONTENT_TYPES[ext] ?? "application/octet-stream",
|
|
@@ -5343,7 +5335,7 @@ async function startWebServer(options) {
|
|
|
5343
5335
|
res.end();
|
|
5344
5336
|
return;
|
|
5345
5337
|
}
|
|
5346
|
-
|
|
5338
|
+
fs15.createReadStream(file).pipe(res);
|
|
5347
5339
|
}
|
|
5348
5340
|
const wss = new WebSocketServer({ noServer: true, maxPayload: MAX_PAYLOAD });
|
|
5349
5341
|
function reject(socket, status, reason) {
|
|
@@ -5514,7 +5506,7 @@ function loginUrl(lock, pathname = "/home/") {
|
|
|
5514
5506
|
return `http://127.0.0.1:${lock.port}${pathname}?token=${encodeURIComponent(lock.token)}`;
|
|
5515
5507
|
}
|
|
5516
5508
|
function isWebDir(dir) {
|
|
5517
|
-
return
|
|
5509
|
+
return fs16.existsSync(path20.join(dir, "home", "index.html"));
|
|
5518
5510
|
}
|
|
5519
5511
|
|
|
5520
5512
|
// packages/cli/src/remote.ts
|
|
@@ -5631,14 +5623,14 @@ function connectToHost(lock) {
|
|
|
5631
5623
|
}
|
|
5632
5624
|
|
|
5633
5625
|
// packages/cli/src/doctor.ts
|
|
5634
|
-
import
|
|
5635
|
-
import
|
|
5636
|
-
import { execFile as
|
|
5637
|
-
import { promisify as
|
|
5626
|
+
import fs17 from "fs";
|
|
5627
|
+
import path21 from "path";
|
|
5628
|
+
import { execFile as execFile7 } from "child_process";
|
|
5629
|
+
import { promisify as promisify5 } from "util";
|
|
5638
5630
|
init_env();
|
|
5639
5631
|
init_git_bash();
|
|
5640
5632
|
init_tmux_backend();
|
|
5641
|
-
var
|
|
5633
|
+
var pexec5 = promisify5(execFile7);
|
|
5642
5634
|
function parseVersion(text) {
|
|
5643
5635
|
const m = /(\d+)\.(\d+)(?:\.(\d+))?/.exec(text);
|
|
5644
5636
|
return m ? [Number(m[1]), Number(m[2]), Number(m[3] ?? 0)] : [];
|
|
@@ -5652,7 +5644,7 @@ function versionAtLeast(have, want) {
|
|
|
5652
5644
|
}
|
|
5653
5645
|
async function run(cmd, args) {
|
|
5654
5646
|
try {
|
|
5655
|
-
const { stdout } = await
|
|
5647
|
+
const { stdout } = await pexec5(cmd, args, { env: execEnv(), timeout: 1e4, windowsHide: true });
|
|
5656
5648
|
return String(stdout).trim();
|
|
5657
5649
|
} catch {
|
|
5658
5650
|
return null;
|
|
@@ -5772,10 +5764,10 @@ async function runDoctor(options) {
|
|
|
5772
5764
|
});
|
|
5773
5765
|
}
|
|
5774
5766
|
try {
|
|
5775
|
-
|
|
5776
|
-
const probe =
|
|
5777
|
-
|
|
5778
|
-
|
|
5767
|
+
fs17.mkdirSync(options.userDataDir, { recursive: true });
|
|
5768
|
+
const probe = path21.join(options.userDataDir, `.doctor-${process.pid}`);
|
|
5769
|
+
fs17.writeFileSync(probe, "");
|
|
5770
|
+
fs17.rmSync(probe);
|
|
5779
5771
|
checks.push({ id: "data", name: "\u8CC7\u6599\u76EE\u9304", level: "ok", detail: options.userDataDir });
|
|
5780
5772
|
} catch (err) {
|
|
5781
5773
|
checks.push({
|
|
@@ -5829,24 +5821,24 @@ Options:
|
|
|
5829
5821
|
`.trim();
|
|
5830
5822
|
function detectLayout() {
|
|
5831
5823
|
const file = fileURLToPath(import.meta.url);
|
|
5832
|
-
const here =
|
|
5833
|
-
const bundledWeb =
|
|
5834
|
-
if (isWebDir(bundledWeb) ||
|
|
5824
|
+
const here = path24.dirname(file);
|
|
5825
|
+
const bundledWeb = path24.join(here, "web");
|
|
5826
|
+
if (isWebDir(bundledWeb) || path24.basename(here) === "dist") {
|
|
5835
5827
|
return {
|
|
5836
|
-
version: readVersion(
|
|
5828
|
+
version: readVersion(path24.join(here, "..", "package.json")),
|
|
5837
5829
|
webDir: isWebDir(bundledWeb) ? bundledWeb : null,
|
|
5838
5830
|
sourceRoot: null,
|
|
5839
5831
|
cliEntry: file
|
|
5840
5832
|
};
|
|
5841
5833
|
}
|
|
5842
|
-
const root =
|
|
5834
|
+
const root = path24.resolve(here, "..", "..", "..");
|
|
5843
5835
|
const override = process.env.VIBEFLOW_WEB_DIR;
|
|
5844
|
-
const webDir = override && isWebDir(override) ? override : isWebDir(
|
|
5845
|
-
return { version: readVersion(
|
|
5836
|
+
const webDir = override && isWebDir(override) ? override : isWebDir(path24.join(root, "app")) ? path24.join(root, "app") : null;
|
|
5837
|
+
return { version: readVersion(path24.join(root, "package.json")), webDir, sourceRoot: root, cliEntry: null };
|
|
5846
5838
|
}
|
|
5847
5839
|
function readVersion(pkgPath) {
|
|
5848
5840
|
try {
|
|
5849
|
-
return JSON.parse(
|
|
5841
|
+
return JSON.parse(fs19.readFileSync(pkgPath, "utf8")).version;
|
|
5850
5842
|
} catch {
|
|
5851
5843
|
return "0.0.0";
|
|
5852
5844
|
}
|
|
@@ -6052,8 +6044,8 @@ async function cmdOpen(values, target, layout, userDataDir) {
|
|
|
6052
6044
|
console.error("\u7528\u6CD5\uFF1Avibeflow open <path>");
|
|
6053
6045
|
return 1;
|
|
6054
6046
|
}
|
|
6055
|
-
const dir =
|
|
6056
|
-
if (!
|
|
6047
|
+
const dir = path24.resolve(target);
|
|
6048
|
+
if (!fs19.existsSync(dir) || !fs19.statSync(dir).isDirectory()) {
|
|
6057
6049
|
console.error(`\u4E0D\u662F\u8CC7\u6599\u593E\uFF1A${dir}`);
|
|
6058
6050
|
return 1;
|
|
6059
6051
|
}
|