@kw-yeh/vibeflow 4.7.1 → 4.9.0
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 +702 -350
- package/dist/web/404/index.html +1 -1
- package/dist/web/404.html +1 -1
- package/dist/web/_next/static/chunks/674-f8f6187ae7148f97.js +9 -0
- package/dist/web/_next/static/chunks/pages/home-8775f5b8256ee371.js +12 -0
- package/dist/web/_next/static/css/{d25415d1bec170b4.css → c1491b2feaf90c67.css} +1 -1
- package/dist/web/_next/static/{rD1tZjqo_1oM7qAU7uvic → zd9N4vIppSGgwT--n88P6}/_buildManifest.js +1 -1
- package/dist/web/home/index.html +1 -1
- package/package.json +1 -1
- package/dist/web/_next/static/chunks/7451-e9f74fece50504ed.js +0 -9
- package/dist/web/_next/static/chunks/pages/home-78adf6369b572108.js +0 -12
- /package/dist/web/_next/static/{rD1tZjqo_1oM7qAU7uvic → zd9N4vIppSGgwT--n88P6}/_ssgManifest.js +0 -0
package/dist/vibeflow.mjs
CHANGED
|
@@ -499,6 +499,192 @@ var init_tmux_backend = __esm({
|
|
|
499
499
|
}
|
|
500
500
|
});
|
|
501
501
|
|
|
502
|
+
// packages/core/src/launch.ts
|
|
503
|
+
function pathBasename(p) {
|
|
504
|
+
const norm = p.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
505
|
+
const i = norm.lastIndexOf("/");
|
|
506
|
+
return i >= 0 ? norm.slice(i + 1) : norm;
|
|
507
|
+
}
|
|
508
|
+
function agentArtifactsDir(worktreePath, workspacePath) {
|
|
509
|
+
if (!worktreePath || !workspacePath) return null;
|
|
510
|
+
const dir = toShellPath(workspacePath);
|
|
511
|
+
const ws = pathBasename(worktreePath);
|
|
512
|
+
return `${dir}/${ws}${ARTIFACTS_DIR_SUFFIX}`;
|
|
513
|
+
}
|
|
514
|
+
function buildArtifactPrompt(artifactsDir = ARTIFACTS_FALLBACK_DIR) {
|
|
515
|
+
return [
|
|
516
|
+
"Artifact \u8A2D\u5B9A\uFF08\u672C\u6B21 session \u5168\u7A0B\u9069\u7528\uFF09\uFF1A",
|
|
517
|
+
`1. \u672C\u4EFB\u52D9\u7684 Artifact \u8CC7\u6599\u593E\u662F ${artifactsDir}/\uFF1B\u9700\u8981\u4FDD\u5B58\u7D66\u4F7F\u7528\u8005\u7684\u9A57\u8B49\u8B49\u64DA\u6216\u5831\u544A\u6642\uFF0C\u8ACB\u5BEB\u5165\u6B64\u8CC7\u6599\u593E\uFF08\u4E0D\u5B58\u5728\u8ACB\u5EFA\u7ACB\uFF09\u3002`,
|
|
518
|
+
`2. \u4F7F\u7528\u8005\u6703\u5728 VibeFlow \u7684 Artifacts \u5206\u9801\u6AA2\u8996\u6839\u76EE\u9304\u5167\u5BB9\uFF1B\u53EA\u653E\u4F60\u6703\u4E3B\u52D5\u8ACB\u4F7F\u7528\u8005\u904E\u76EE\u7684\u6A94\u6848\u3002`,
|
|
519
|
+
`3. \u4F60\u81EA\u5DF1\u7684\u5DE5\u4F5C\u66AB\u5B58\uFF08\u4E00\u6B21\u6027 script\u3001log\u3001\u4E2D\u9593\u8F38\u51FA\u3001debug \u6A94\uFF09\u653E\u5728 ${artifactsDir}/${SCRATCH_DIR_NAME}/\u3002`,
|
|
520
|
+
`4. \u82E5\u5DE5\u5177\u5148\u8F38\u51FA\u5230 /tmp\u3001/private/tmp\u3001$TMPDIR \u6216 ~/Downloads\uFF0C\u8ACB\u628A\u6700\u7D42\u8981\u5448\u73FE\u7684\u6A94\u6848\u8907\u88FD\u5230 ${artifactsDir}/ \u4E26\u78BA\u8A8D\u5B58\u5728\u3002`,
|
|
521
|
+
"5. Artifact \u8CC7\u6599\u593E\u4F4D\u65BC worktree \u4E4B\u5916\uFF1B\u4E0D\u8981\u628A\u5176\u4E2D\u5167\u5BB9\u52A0\u5165 git commit\uFF0C\u4E5F\u4E0D\u8981\u628A\u6700\u7D42\u4EA4\u4ED8\u7269\u53EA\u7559\u5728\u9019\u88E1\u3002"
|
|
522
|
+
].join("\n");
|
|
523
|
+
}
|
|
524
|
+
function claudePermissionFlag(autoMode) {
|
|
525
|
+
return autoMode ? ` --permission-mode ${AUTO_PERMISSION_MODE}` : "";
|
|
526
|
+
}
|
|
527
|
+
function shellQuote(s) {
|
|
528
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
529
|
+
}
|
|
530
|
+
function toShellPath(p) {
|
|
531
|
+
return p.replace(/\\/g, "/");
|
|
532
|
+
}
|
|
533
|
+
function boardEnvPrefix(task, opts) {
|
|
534
|
+
const board = opts?.boardCli;
|
|
535
|
+
if (!board) return "";
|
|
536
|
+
const entries = [
|
|
537
|
+
["VIBEFLOW_TASK_ID", task.id],
|
|
538
|
+
["VIBEFLOW_PROJECT_PATH", task.projectPath],
|
|
539
|
+
["VIBEFLOW_BRANCH", task.branch],
|
|
540
|
+
["VIBEFLOW_BASE_BRANCH", task.baseBranch],
|
|
541
|
+
["VIBEFLOW_STORE_DIR", board?.storeDir],
|
|
542
|
+
["VIBEFLOW_CLI", board?.cliPath],
|
|
543
|
+
["VIBEFLOW_CLI_LOADER", board?.loaderPath],
|
|
544
|
+
["VIBEFLOW_AUTO_MODE", opts?.autoMode ? "1" : "0"]
|
|
545
|
+
];
|
|
546
|
+
const exports = entries.filter((entry) => Boolean(entry[1])).map(([key, value]) => `${key}=${shellQuote(toShellPath(value))}`);
|
|
547
|
+
return exports.length ? `export ${exports.join(" ")}; ` : "";
|
|
548
|
+
}
|
|
549
|
+
function codexAutoFlag(autoMode) {
|
|
550
|
+
return autoMode ? "--dangerously-bypass-approvals-and-sandbox " : "";
|
|
551
|
+
}
|
|
552
|
+
function claudeResumeOrFresh(sessionId, worktreePath, tail) {
|
|
553
|
+
if (!worktreePath) return `claude --resume ${sessionId} ${tail}\r`;
|
|
554
|
+
const munged = worktreePath.replace(/[^a-zA-Z0-9]/g, "-");
|
|
555
|
+
const sessionFile = `"$HOME/.claude/projects/${munged}/${sessionId}.jsonl"`;
|
|
556
|
+
return `if [ -f ${sessionFile} ]; then claude --resume ${sessionId} ${tail}; else claude --session-id ${sessionId} ${tail}; fi\r`;
|
|
557
|
+
}
|
|
558
|
+
function buildClaudeSettings(worktreePath) {
|
|
559
|
+
const settings = { theme: "dark" };
|
|
560
|
+
if (worktreePath) {
|
|
561
|
+
const dir = `${toShellPath(worktreePath)}/${SUBAGENTS_DIR2}`;
|
|
562
|
+
const command = `mkdir -p "${dir}" && cat > "${dir}/$(date +%s)-$$-$RANDOM.json"`;
|
|
563
|
+
const taskHook = {
|
|
564
|
+
matcher: "Task",
|
|
565
|
+
hooks: [{ type: "command", command }]
|
|
566
|
+
};
|
|
567
|
+
const eventsDir = `${toShellPath(worktreePath)}/${PROGRESS_EVENTS_DIR}`;
|
|
568
|
+
const progress = {
|
|
569
|
+
hooks: [{ type: "command", command: `mkdir -p "${eventsDir}" && cat > "${eventsDir}/$(date +%s)-$$-$RANDOM.json"; exit 0` }]
|
|
570
|
+
};
|
|
571
|
+
settings.hooks = {
|
|
572
|
+
PreToolUse: [taskHook],
|
|
573
|
+
PostToolUse: [taskHook, { matcher: TODO_TOOLS, ...progress }],
|
|
574
|
+
Stop: [progress],
|
|
575
|
+
Notification: [progress],
|
|
576
|
+
UserPromptSubmit: [progress]
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
return JSON.stringify(settings);
|
|
580
|
+
}
|
|
581
|
+
function resolveSystemPrompt(custom) {
|
|
582
|
+
return custom && custom.trim() ? custom : "";
|
|
583
|
+
}
|
|
584
|
+
function buildPrompt(task) {
|
|
585
|
+
const lines = [`\u4EFB\u52D9\u6A19\u984C\uFF1A${task.title}`];
|
|
586
|
+
const description = task.description?.trim();
|
|
587
|
+
if (description) {
|
|
588
|
+
lines.push("", "\u4EFB\u52D9\u63CF\u8FF0\uFF1A", description);
|
|
589
|
+
}
|
|
590
|
+
return lines.join("\n");
|
|
591
|
+
}
|
|
592
|
+
function executorSessionId(taskId, runId) {
|
|
593
|
+
const source = runId ? `${taskId}:${runId}` : taskId;
|
|
594
|
+
const raw = source.replace(/[^0-9a-f]/gi, "").toLowerCase();
|
|
595
|
+
const hex = runId ? `${raw.slice(0, 24).padEnd(24, "0")}${namespaceHash(`executor:${source}`)}` : raw.padEnd(32, "0").slice(0, 32);
|
|
596
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-4${hex.slice(13, 16)}-8${hex.slice(17, 20)}-${hex.slice(20, 32)}`;
|
|
597
|
+
}
|
|
598
|
+
function namespaceHash(namespace) {
|
|
599
|
+
let hash = 2166136261;
|
|
600
|
+
for (let i = 0; i < namespace.length; i += 1) {
|
|
601
|
+
hash ^= namespace.charCodeAt(i);
|
|
602
|
+
hash = Math.imul(hash, 16777619);
|
|
603
|
+
}
|
|
604
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
605
|
+
}
|
|
606
|
+
function assembleCommand(agent, systemPrompt, prompt, model, effort, opts, worktreePath, sessionId, workspacePath) {
|
|
607
|
+
let cmd;
|
|
608
|
+
if (agent === "claude") {
|
|
609
|
+
const settings = ` --settings ${shellQuote(buildClaudeSettings(worktreePath))}`;
|
|
610
|
+
const addDir = workspacePath ? ` --add-dir ${shellQuote(toShellPath(workspacePath))}` : "";
|
|
611
|
+
const modelFlag = model ? ` --model ${model}` : "";
|
|
612
|
+
const effortFlag = effort ? ` --effort ${effort}` : "";
|
|
613
|
+
const library = opts?.library;
|
|
614
|
+
const libraryFlags = library ? ` --plugin-dir ${shellQuote(toShellPath(library.pluginDir))} --add-dir ${shellQuote(toShellPath(library.libraryDir))}` : "";
|
|
615
|
+
const flags = `--chrome${claudePermissionFlag(opts?.autoMode)}${modelFlag}${effortFlag}${settings}${addDir}${libraryFlags}`;
|
|
616
|
+
const sysFlag = systemPrompt ? ` --append-system-prompt ${shellQuote(systemPrompt)}` : "";
|
|
617
|
+
const promptArg = prompt ? ` ${shellQuote(prompt)}` : "";
|
|
618
|
+
const tail = `${flags}${sysFlag}${promptArg}`;
|
|
619
|
+
cmd = sessionId && opts?.resume ? claudeResumeOrFresh(sessionId, worktreePath, tail) : `claude ${sessionId ? `--session-id ${sessionId} ` : opts?.resume ? "--continue " : ""}${tail}\r`;
|
|
620
|
+
} else {
|
|
621
|
+
const combined = [systemPrompt, prompt].filter(Boolean).join("\n\n");
|
|
622
|
+
const codexEffortFlag = effort ? `-c ${shellQuote(`model_reasoning_effort="${effort}"`)} ` : "";
|
|
623
|
+
const codexHome = opts?.library ? `CODEX_HOME=${shellQuote(toShellPath(opts.library.codexHome))} ` : "";
|
|
624
|
+
const args = [
|
|
625
|
+
codexAutoFlag(opts?.autoMode).trim(),
|
|
626
|
+
codexEffortFlag.trim(),
|
|
627
|
+
model ? `--model ${model}` : "",
|
|
628
|
+
combined ? shellQuote(combined) : ""
|
|
629
|
+
].filter(Boolean);
|
|
630
|
+
cmd = `${codexHome}${["codex", ...args].join(" ")}\r`;
|
|
631
|
+
}
|
|
632
|
+
if (cmd.length > 2e5) console.warn(`[VibeFlow] launch command is ${cmd.length} bytes \u2014 approaching ARG_MAX`);
|
|
633
|
+
return cmd;
|
|
634
|
+
}
|
|
635
|
+
function taskAgent(task) {
|
|
636
|
+
const agent = task.agentCli;
|
|
637
|
+
return agent && agent in AGENT_NAMES ? agent : "claude";
|
|
638
|
+
}
|
|
639
|
+
function taskModel(task) {
|
|
640
|
+
const model = task.model?.trim();
|
|
641
|
+
if (!model || RETIRED_MODELS[taskAgent(task)]?.includes(model)) return void 0;
|
|
642
|
+
return model;
|
|
643
|
+
}
|
|
644
|
+
function buildAgentCommand(task, systemPrompt, opts, workspacePath) {
|
|
645
|
+
const agent = taskAgent(task);
|
|
646
|
+
const model = taskModel(task);
|
|
647
|
+
const artifactsDir = agentArtifactsDir(task.worktreePath, workspacePath) ?? ARTIFACTS_FALLBACK_DIR;
|
|
648
|
+
const builtInPrompt = buildArtifactPrompt(artifactsDir);
|
|
649
|
+
const libraryPrompt = opts?.library?.promptText?.trim();
|
|
650
|
+
const customPrompt = resolveSystemPrompt(systemPrompt);
|
|
651
|
+
const sys = [builtInPrompt, libraryPrompt, customPrompt].filter(Boolean).join("\n\n");
|
|
652
|
+
const includeTaskPrompt = opts?.includeTaskPrompt !== false;
|
|
653
|
+
const prompt = includeTaskPrompt && !opts?.resume ? buildPrompt(task) : "";
|
|
654
|
+
const sessionId = agent === "claude" && includeTaskPrompt ? executorSessionId(task.id, task.runId) : void 0;
|
|
655
|
+
return boardEnvPrefix(task, opts) + assembleCommand(
|
|
656
|
+
agent,
|
|
657
|
+
sys,
|
|
658
|
+
prompt,
|
|
659
|
+
model,
|
|
660
|
+
task.effort,
|
|
661
|
+
opts,
|
|
662
|
+
task.worktreePath,
|
|
663
|
+
sessionId,
|
|
664
|
+
workspacePath
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
var ARTIFACTS_DIR_SUFFIX, SCRATCH_DIR_NAME, ARTIFACTS_FALLBACK_DIR, AUTO_PERMISSION_MODE, SUBAGENTS_DIR2, PROGRESS_EVENTS_DIR, TODO_TOOLS, AGENT_NAMES, RETIRED_MODELS;
|
|
668
|
+
var init_launch = __esm({
|
|
669
|
+
"packages/core/src/launch.ts"() {
|
|
670
|
+
"use strict";
|
|
671
|
+
ARTIFACTS_DIR_SUFFIX = ".artifacts";
|
|
672
|
+
SCRATCH_DIR_NAME = "scratch";
|
|
673
|
+
ARTIFACTS_FALLBACK_DIR = ".vibeflow-artifacts";
|
|
674
|
+
AUTO_PERMISSION_MODE = "auto";
|
|
675
|
+
SUBAGENTS_DIR2 = ".vibeflow-subagents";
|
|
676
|
+
PROGRESS_EVENTS_DIR = ".vibeflow-events";
|
|
677
|
+
TODO_TOOLS = "TodoWrite|TaskCreate|TaskUpdate";
|
|
678
|
+
AGENT_NAMES = {
|
|
679
|
+
claude: "Claude Code",
|
|
680
|
+
codex: "Codex CLI"
|
|
681
|
+
};
|
|
682
|
+
RETIRED_MODELS = {
|
|
683
|
+
codex: ["gpt-5-codex", "gpt-5"]
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
|
|
502
688
|
// packages/core/src/attachments.ts
|
|
503
689
|
import { randomUUID } from "crypto";
|
|
504
690
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
@@ -599,6 +785,36 @@ var init_attachments = __esm({
|
|
|
599
785
|
}
|
|
600
786
|
});
|
|
601
787
|
|
|
788
|
+
// packages/core/src/effort.ts
|
|
789
|
+
function modelFor(models, modelId) {
|
|
790
|
+
return modelId ? models?.find((m) => m.id === modelId) : models?.find((m) => m.isDefault);
|
|
791
|
+
}
|
|
792
|
+
function isAgentEffort(value) {
|
|
793
|
+
return typeof value === "string" && AGENT_EFFORTS.includes(value);
|
|
794
|
+
}
|
|
795
|
+
function allowedEfforts(model) {
|
|
796
|
+
return model?.efforts ?? null;
|
|
797
|
+
}
|
|
798
|
+
function selectableEfforts(model) {
|
|
799
|
+
return allowedEfforts(model) ?? UNKNOWN_MODEL_EFFORTS;
|
|
800
|
+
}
|
|
801
|
+
function clampEffort(effort, allowed) {
|
|
802
|
+
if (allowed.length === 0) return void 0;
|
|
803
|
+
if (effort === void 0 || allowed.includes(effort)) return effort;
|
|
804
|
+
const rank = AGENT_EFFORTS.indexOf(effort);
|
|
805
|
+
const ordered = AGENT_EFFORTS.filter((level) => allowed.includes(level));
|
|
806
|
+
const notDeeper = ordered.filter((level) => AGENT_EFFORTS.indexOf(level) <= rank);
|
|
807
|
+
return notDeeper.length > 0 ? notDeeper[notDeeper.length - 1] : ordered[0];
|
|
808
|
+
}
|
|
809
|
+
var AGENT_EFFORTS, UNKNOWN_MODEL_EFFORTS;
|
|
810
|
+
var init_effort = __esm({
|
|
811
|
+
"packages/core/src/effort.ts"() {
|
|
812
|
+
"use strict";
|
|
813
|
+
AGENT_EFFORTS = ["low", "medium", "high", "xhigh", "max", "ultra"];
|
|
814
|
+
UNKNOWN_MODEL_EFFORTS = ["low", "medium", "high", "xhigh"];
|
|
815
|
+
}
|
|
816
|
+
});
|
|
817
|
+
|
|
602
818
|
// packages/core/src/progress.ts
|
|
603
819
|
function emptyUsage() {
|
|
604
820
|
return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, reasoning: 0 };
|
|
@@ -883,9 +1099,9 @@ var init_progress = __esm({
|
|
|
883
1099
|
|
|
884
1100
|
// packages/tui/src/task-form.ts
|
|
885
1101
|
import { spawnSync } from "child_process";
|
|
886
|
-
import
|
|
887
|
-
import
|
|
888
|
-
import
|
|
1102
|
+
import fs22 from "fs";
|
|
1103
|
+
import os9 from "os";
|
|
1104
|
+
import path26 from "path";
|
|
889
1105
|
import React, { useEffect, useRef, useState } from "react";
|
|
890
1106
|
import { Box, Text, render, useApp, useInput } from "ink";
|
|
891
1107
|
function newFormState(defaultAutoMode, agents) {
|
|
@@ -951,11 +1167,18 @@ function visibleFields(s, ctx) {
|
|
|
951
1167
|
return fields;
|
|
952
1168
|
}
|
|
953
1169
|
function modelOptions(ctx, agentCli, current) {
|
|
954
|
-
const listed = ctx.models[agentCli] ?? [];
|
|
1170
|
+
const listed = (ctx.models[agentCli] ?? []).map((m) => m.id);
|
|
955
1171
|
const options = ["", ...listed];
|
|
956
1172
|
if (current && !listed.includes(current)) options.push(current);
|
|
957
1173
|
return options;
|
|
958
1174
|
}
|
|
1175
|
+
function effortOptions(ctx, agentCli, model) {
|
|
1176
|
+
return selectableEfforts(modelFor(ctx.models[agentCli], taskModel({ agentCli, model })));
|
|
1177
|
+
}
|
|
1178
|
+
function fitEffort(ctx, s) {
|
|
1179
|
+
const effort = clampEffort(s.effort, effortOptions(ctx, s.agentCli, s.model)) ?? s.effort;
|
|
1180
|
+
return effort === s.effort ? s : { ...s, effort };
|
|
1181
|
+
}
|
|
959
1182
|
function blockReason(s, ctx, loadingGit) {
|
|
960
1183
|
if (!s.title.trim()) return "\u8ACB\u8F38\u5165\u4EFB\u52D9\u6A19\u984C";
|
|
961
1184
|
if (loadingGit) return "\u5075\u6E2C Git \u72C0\u614B\u4E2D\u2026";
|
|
@@ -1004,17 +1227,17 @@ function editorCommand(env, platform) {
|
|
|
1004
1227
|
return env.VISUAL?.trim() || env.EDITOR?.trim() || (platform === "win32" ? "notepad" : "vi");
|
|
1005
1228
|
}
|
|
1006
1229
|
function editInEditor(text) {
|
|
1007
|
-
const dir =
|
|
1008
|
-
const file =
|
|
1230
|
+
const dir = fs22.mkdtempSync(path26.join(os9.tmpdir(), "vibeflow-"));
|
|
1231
|
+
const file = path26.join(dir, "description.md");
|
|
1009
1232
|
try {
|
|
1010
|
-
|
|
1233
|
+
fs22.writeFileSync(file, text);
|
|
1011
1234
|
const cmd = editorCommand(process.env, process.platform);
|
|
1012
1235
|
const r = spawnSync(`${cmd} "${file}"`, { stdio: "inherit", shell: true });
|
|
1013
1236
|
if (r.error) return { error: `\u7121\u6CD5\u555F\u52D5\u7DE8\u8F2F\u5668\uFF08${cmd}\uFF09\uFF1A${r.error.message}` };
|
|
1014
1237
|
if (r.status !== 0) return { error: `\u7DE8\u8F2F\u5668\uFF08${cmd}\uFF09\u7D50\u675F\u78BC ${r.status}\uFF0C\u63CF\u8FF0\u672A\u8B8A\u66F4` };
|
|
1015
|
-
return { text:
|
|
1238
|
+
return { text: fs22.readFileSync(file, "utf8").replace(/\r?\n$/, "") };
|
|
1016
1239
|
} finally {
|
|
1017
|
-
|
|
1240
|
+
fs22.rmSync(dir, { recursive: true, force: true });
|
|
1018
1241
|
}
|
|
1019
1242
|
}
|
|
1020
1243
|
function cycle(list, current, step) {
|
|
@@ -1085,10 +1308,10 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
1085
1308
|
if (editing === "title") setS((prev) => ({ ...prev, title: draft }));
|
|
1086
1309
|
else if (editing === "branch") setS((prev) => ({ ...prev, branch: value2 }));
|
|
1087
1310
|
else if (editing === "project") {
|
|
1088
|
-
if (value2) setProject(
|
|
1311
|
+
if (value2) setProject(path26.resolve(value2.replace(/^~(?=$|\/)/, os9.homedir())));
|
|
1089
1312
|
} else if (editing === "attachments" && value2) {
|
|
1090
|
-
const file =
|
|
1091
|
-
if (!
|
|
1313
|
+
const file = path26.resolve(value2.replace(/^~(?=$|\/)/, os9.homedir()));
|
|
1314
|
+
if (!fs22.existsSync(file) || !fs22.statSync(file).isFile()) {
|
|
1092
1315
|
setMessage(`\u627E\u4E0D\u5230\u6A94\u6848\uFF1A${file}`);
|
|
1093
1316
|
return;
|
|
1094
1317
|
}
|
|
@@ -1127,13 +1350,16 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
1127
1350
|
} else if (field === "baseBranch") {
|
|
1128
1351
|
setS((prev) => ({ ...prev, baseBranch: cycle(prev.gitInfo?.branches ?? [], prev.baseBranch, step) }));
|
|
1129
1352
|
} else if (field === "effort") {
|
|
1130
|
-
setS((prev) =>
|
|
1353
|
+
setS((prev) => {
|
|
1354
|
+
const levels = effortOptions(ctx, prev.agentCli, prev.model);
|
|
1355
|
+
return levels.length ? { ...prev, effort: cycle([...levels], prev.effort, step) } : prev;
|
|
1356
|
+
});
|
|
1131
1357
|
} else if (field === "autoMode") {
|
|
1132
1358
|
setS((prev) => ({ ...prev, autoMode: !prev.autoMode }));
|
|
1133
1359
|
} else if (field === "agent" && ctx.agents?.length) {
|
|
1134
|
-
setS((prev) => ({ ...prev, agentCli: cycle(ctx.agents.map((a) => a.id), prev.agentCli, step), model: "" }));
|
|
1360
|
+
setS((prev) => fitEffort(ctx, { ...prev, agentCli: cycle(ctx.agents.map((a) => a.id), prev.agentCli, step), model: "" }));
|
|
1135
1361
|
} else if (field === "model") {
|
|
1136
|
-
setS((prev) => ({ ...prev, model: cycle(modelOptions(ctx, prev.agentCli, prev.model), prev.model, step) }));
|
|
1362
|
+
setS((prev) => fitEffort(ctx, { ...prev, model: cycle(modelOptions(ctx, prev.agentCli, prev.model), prev.model, step) }));
|
|
1137
1363
|
}
|
|
1138
1364
|
return;
|
|
1139
1365
|
}
|
|
@@ -1168,14 +1394,15 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
1168
1394
|
case "branch":
|
|
1169
1395
|
return s.branch || "\uFF08\u7559\u7A7A\u5247\u81EA\u52D5\u547D\u540D\uFF0C\u4F8B\u5982 feature/login-fix\uFF09";
|
|
1170
1396
|
case "attachments":
|
|
1171
|
-
return s.attachments.length ? s.attachments.map((a) =>
|
|
1397
|
+
return s.attachments.length ? s.attachments.map((a) => path26.basename(a)).join("\u3001") : "\uFF08Enter \u8F38\u5165\u6A94\u6848\u8DEF\u5F91\u52A0\u5165\uFF09";
|
|
1172
1398
|
case "description": {
|
|
1173
1399
|
if (!s.description) return "\uFF08Enter \u7528\u7DE8\u8F2F\u5668\u64B0\u5BEB\uFF09";
|
|
1174
1400
|
const lines = s.description.split("\n");
|
|
1175
1401
|
return lines.length > 1 ? `${lines[0]} \u2026\uFF08\u5171 ${lines.length} \u884C\uFF09` : lines[0];
|
|
1176
1402
|
}
|
|
1177
1403
|
case "effort": {
|
|
1178
|
-
|
|
1404
|
+
if (effortOptions(ctx, s.agentCli, s.model).length === 0) return "\u4E0D\u9069\u7528";
|
|
1405
|
+
const e = EFFORTS.find((x) => x.value === s.effort) ?? EFFORTS[0];
|
|
1179
1406
|
return `\u2039 ${e.label} \xB7 ${e.value} \u203A`;
|
|
1180
1407
|
}
|
|
1181
1408
|
case "autoMode":
|
|
@@ -1185,8 +1412,12 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
1185
1412
|
if (ctx.agents.length === 0) return "\u672A\u5075\u6E2C\u5230 Agent CLI\uFF08claude / codex\uFF09";
|
|
1186
1413
|
return `\u2039 ${ctx.agents.find((a) => a.id === s.agentCli)?.name ?? s.agentCli} \u203A`;
|
|
1187
1414
|
}
|
|
1188
|
-
case "model":
|
|
1189
|
-
|
|
1415
|
+
case "model": {
|
|
1416
|
+
if (modelOptions(ctx, s.agentCli, s.model).length <= 1) return "\u7121\u6CD5\u53D6\u5F97 model list\uFF0C\u5C07\u4F7F\u7528\u9810\u8A2D model";
|
|
1417
|
+
const listed = ctx.models[s.agentCli]?.find((m) => m.id === s.model);
|
|
1418
|
+
const fallback = ctx.models[s.agentCli]?.find((m) => m.isDefault)?.label;
|
|
1419
|
+
return `\u2039 ${s.model ? listed?.label ?? s.model : fallback ? `\u4F7F\u7528\u9810\u8A2D model\uFF08${fallback}\uFF09` : "\u4F7F\u7528\u9810\u8A2D model"} \u203A`;
|
|
1420
|
+
}
|
|
1190
1421
|
case "submit":
|
|
1191
1422
|
return busy ?? (s.mode === "new" ? "\uFF3B \u5EFA\u7ACB\u4EFB\u52D9 \uFF3D" : "\uFF3B \u5132\u5B58\u8B8A\u66F4 \uFF3D");
|
|
1192
1423
|
}
|
|
@@ -1199,13 +1430,17 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
1199
1430
|
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";
|
|
1200
1431
|
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";
|
|
1201
1432
|
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`;
|
|
1202
|
-
if (info?.isRepo && s.projectPath) return `worktree \u6703\u5EFA\u5728 ${ctx.workstationPath || "~/Desktop"}/${
|
|
1433
|
+
if (info?.isRepo && s.projectPath) return `worktree \u6703\u5EFA\u5728 ${ctx.workstationPath || "~/Desktop"}/${path26.basename(s.projectPath)}`;
|
|
1203
1434
|
}
|
|
1204
1435
|
if (field === "branch") {
|
|
1205
1436
|
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";
|
|
1206
1437
|
return s.mode === "edit" && s.worktreePath ? `${when} \u9019\u5F35\u5361\u5DF2\u6709 worktree\uFF1A\u66F4\u6539\u5206\u652F\u3001\u5C08\u6848\u6216\u57FA\u6E96\u5206\u652F\u6703\u79FB\u9664\u5B83\uFF08\u6709\u672A\u5B8C\u6210\u8B8A\u66F4\u6642\u7121\u6CD5\u5132\u5B58\uFF09\u3002` : when;
|
|
1207
1438
|
}
|
|
1208
|
-
if (field === "effort")
|
|
1439
|
+
if (field === "effort") {
|
|
1440
|
+
if (effortOptions(ctx, s.agentCli, s.model).length === 0) return "\u9019\u500B model \u4E0D\u652F\u63F4\u8ABF\u6574\u63A8\u7406\u5F37\u5EA6\uFF0C\u555F\u52D5\u6642\u4E0D\u6703\u6307\u5B9A\u4EFB\u52D9\u8907\u96DC\u5EA6\u3002";
|
|
1441
|
+
const e = EFFORTS.find((x) => x.value === s.effort) ?? EFFORTS[0];
|
|
1442
|
+
return `${e.description} Claude Code \u8207 Codex \u6703\u5728\u555F\u52D5\u6B64\u4EFB\u52D9\u6642\u5957\u7528\uFF1B\u53EF\u9078\u7684\u7D1A\u8DDD\u4F9D model \u800C\u5B9A\u3002`;
|
|
1443
|
+
}
|
|
1209
1444
|
if (field === "autoMode") return s.autoMode ? "\u958B\u555F\uFF1AAgent \u6703\u76F4\u63A5\u4FEE\u6539\u6A94\u6848\u3001\u57F7\u884C\u6307\u4EE4\uFF0C\u4E0D\u6703\u9010\u6B21\u5411\u4F60\u78BA\u8A8D\u3002" : "\u95DC\u9589\uFF1AAgent \u6BCF\u6B21\u8981\u52D5\u4F5C\u524D\uFF0C\u90FD\u6703\u5728\u7D42\u7AEF\u6A5F\u88E1\u7B49\u4F60\u5141\u8A31\u3002";
|
|
1210
1445
|
if (field === "submit") return blockReason(s, ctx, loadingGit);
|
|
1211
1446
|
return null;
|
|
@@ -1260,7 +1495,7 @@ async function loadFormContext(api) {
|
|
|
1260
1495
|
const lists = await Promise.all(
|
|
1261
1496
|
(agents ?? []).map(async (a) => {
|
|
1262
1497
|
const list = await api.listAgentModels(a.id).catch(() => null);
|
|
1263
|
-
return [a.id, list ? list.models
|
|
1498
|
+
return [a.id, list ? list.models : []];
|
|
1264
1499
|
})
|
|
1265
1500
|
);
|
|
1266
1501
|
return {
|
|
@@ -1277,13 +1512,17 @@ var h, EFFORTS, DEFAULT_EFFORT, LABELS, TEXT_FIELDS;
|
|
|
1277
1512
|
var init_task_form = __esm({
|
|
1278
1513
|
"packages/tui/src/task-form.ts"() {
|
|
1279
1514
|
"use strict";
|
|
1515
|
+
init_effort();
|
|
1516
|
+
init_launch();
|
|
1280
1517
|
init_attachments();
|
|
1281
1518
|
h = React.createElement;
|
|
1282
1519
|
EFFORTS = [
|
|
1283
1520
|
{ value: "low", label: "\u5FEB\u901F", description: "\u9069\u5408\u7BC4\u570D\u660E\u78BA\u3001\u4F4E\u98A8\u96AA\u7684\u5C0F\u4EFB\u52D9\u3002" },
|
|
1284
1521
|
{ value: "medium", label: "\u6A19\u6E96", description: "\u517C\u9867\u901F\u5EA6\u8207\u63A8\u7406\u6DF1\u5EA6\uFF0C\u9069\u5408\u4E00\u822C\u958B\u767C\u4EFB\u52D9\u3002" },
|
|
1285
1522
|
{ value: "high", label: "\u6DF1\u5165", description: "\u9069\u5408\u8DE8\u6A94\u6848\u3001\u9664\u932F\u6216\u9700\u8981\u8F03\u591A\u5224\u65B7\u7684\u4EFB\u52D9\u3002" },
|
|
1286
|
-
{ value: "xhigh", label: "\u6975\u81F4", description: "\u9069\u5408\u9AD8\u8907\u96DC\u5EA6\u3001\u9577\u93C8\u63A8\u7406\u6216\u9AD8\u98A8\u96AA\u8B8A\u66F4\u3002" }
|
|
1523
|
+
{ value: "xhigh", label: "\u6975\u81F4", description: "\u9069\u5408\u9AD8\u8907\u96DC\u5EA6\u3001\u9577\u93C8\u63A8\u7406\u6216\u9AD8\u98A8\u96AA\u8B8A\u66F4\u3002" },
|
|
1524
|
+
{ value: "max", label: "\u6700\u5927", description: "\u6700\u6DF1\u7684\u63A8\u7406\uFF0C\u9069\u5408\u6700\u56F0\u96E3\u7684\u554F\u984C\u3002" },
|
|
1525
|
+
{ value: "ultra", label: "\u59D4\u6D3E", description: "\u6700\u6DF1\u63A8\u7406\u4E26\u81EA\u52D5\u59D4\u6D3E\u5B50\u4EFB\u52D9\uFF0C\u8017\u6642\u8207\u7528\u91CF\u53EF\u80FD\u660E\u986F\u589E\u52A0\u3002" }
|
|
1287
1526
|
];
|
|
1288
1527
|
DEFAULT_EFFORT = "medium";
|
|
1289
1528
|
LABELS = {
|
|
@@ -1319,7 +1558,7 @@ __export(src_exports, {
|
|
|
1319
1558
|
showDiff: () => showDiff
|
|
1320
1559
|
});
|
|
1321
1560
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
1322
|
-
import
|
|
1561
|
+
import path27 from "path";
|
|
1323
1562
|
import React2, { useEffect as useEffect2, useState as useState2 } from "react";
|
|
1324
1563
|
import { Box as Box2, Text as Text2, render as render2, useApp as useApp2, useInput as useInput2, useStdout } from "ink";
|
|
1325
1564
|
function findDetachKey(text) {
|
|
@@ -1615,7 +1854,7 @@ function showDiff(task) {
|
|
|
1615
1854
|
});
|
|
1616
1855
|
}
|
|
1617
1856
|
function tmuxAttach(opts, sessionName) {
|
|
1618
|
-
const conf =
|
|
1857
|
+
const conf = path27.join(opts.userDataDir, "tmux.conf");
|
|
1619
1858
|
const inOurServer = (process.env.TMUX ?? "").split(",")[0].endsWith(`/${TMUX_SOCKET}`);
|
|
1620
1859
|
const args = inOurServer ? ["-L", TMUX_SOCKET, "-f", conf, "switch-client", "-t", `=${sessionName}`] : ["-L", TMUX_SOCKET, "-f", conf, "attach-session", "-t", `=${sessionName}`];
|
|
1621
1860
|
spawnSync2("tmux", args, { stdio: "inherit", env: { ...process.env, TMUX: inOurServer ? process.env.TMUX : "" } });
|
|
@@ -1746,8 +1985,8 @@ var init_src = __esm({
|
|
|
1746
1985
|
});
|
|
1747
1986
|
|
|
1748
1987
|
// packages/cli/src/main.ts
|
|
1749
|
-
import
|
|
1750
|
-
import
|
|
1988
|
+
import fs23 from "fs";
|
|
1989
|
+
import path28 from "path";
|
|
1751
1990
|
import { fileURLToPath } from "url";
|
|
1752
1991
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
1753
1992
|
|
|
@@ -2699,191 +2938,8 @@ function unwatchAllSubAgents() {
|
|
|
2699
2938
|
}
|
|
2700
2939
|
}
|
|
2701
2940
|
|
|
2702
|
-
// packages/core/src/launch.ts
|
|
2703
|
-
var ARTIFACTS_DIR_SUFFIX = ".artifacts";
|
|
2704
|
-
var SCRATCH_DIR_NAME = "scratch";
|
|
2705
|
-
var ARTIFACTS_FALLBACK_DIR = ".vibeflow-artifacts";
|
|
2706
|
-
function pathBasename(p) {
|
|
2707
|
-
const norm = p.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
2708
|
-
const i = norm.lastIndexOf("/");
|
|
2709
|
-
return i >= 0 ? norm.slice(i + 1) : norm;
|
|
2710
|
-
}
|
|
2711
|
-
function agentArtifactsDir(worktreePath, workspacePath) {
|
|
2712
|
-
if (!worktreePath || !workspacePath) return null;
|
|
2713
|
-
const dir = toShellPath(workspacePath);
|
|
2714
|
-
const ws = pathBasename(worktreePath);
|
|
2715
|
-
return `${dir}/${ws}${ARTIFACTS_DIR_SUFFIX}`;
|
|
2716
|
-
}
|
|
2717
|
-
function buildArtifactPrompt(artifactsDir = ARTIFACTS_FALLBACK_DIR) {
|
|
2718
|
-
return [
|
|
2719
|
-
"Artifact \u8A2D\u5B9A\uFF08\u672C\u6B21 session \u5168\u7A0B\u9069\u7528\uFF09\uFF1A",
|
|
2720
|
-
`1. \u672C\u4EFB\u52D9\u7684 Artifact \u8CC7\u6599\u593E\u662F ${artifactsDir}/\uFF1B\u9700\u8981\u4FDD\u5B58\u7D66\u4F7F\u7528\u8005\u7684\u9A57\u8B49\u8B49\u64DA\u6216\u5831\u544A\u6642\uFF0C\u8ACB\u5BEB\u5165\u6B64\u8CC7\u6599\u593E\uFF08\u4E0D\u5B58\u5728\u8ACB\u5EFA\u7ACB\uFF09\u3002`,
|
|
2721
|
-
`2. \u4F7F\u7528\u8005\u6703\u5728 VibeFlow \u7684 Artifacts \u5206\u9801\u6AA2\u8996\u6839\u76EE\u9304\u5167\u5BB9\uFF1B\u53EA\u653E\u4F60\u6703\u4E3B\u52D5\u8ACB\u4F7F\u7528\u8005\u904E\u76EE\u7684\u6A94\u6848\u3002`,
|
|
2722
|
-
`3. \u4F60\u81EA\u5DF1\u7684\u5DE5\u4F5C\u66AB\u5B58\uFF08\u4E00\u6B21\u6027 script\u3001log\u3001\u4E2D\u9593\u8F38\u51FA\u3001debug \u6A94\uFF09\u653E\u5728 ${artifactsDir}/${SCRATCH_DIR_NAME}/\u3002`,
|
|
2723
|
-
`4. \u82E5\u5DE5\u5177\u5148\u8F38\u51FA\u5230 /tmp\u3001/private/tmp\u3001$TMPDIR \u6216 ~/Downloads\uFF0C\u8ACB\u628A\u6700\u7D42\u8981\u5448\u73FE\u7684\u6A94\u6848\u8907\u88FD\u5230 ${artifactsDir}/ \u4E26\u78BA\u8A8D\u5B58\u5728\u3002`,
|
|
2724
|
-
"5. Artifact \u8CC7\u6599\u593E\u4F4D\u65BC worktree \u4E4B\u5916\uFF1B\u4E0D\u8981\u628A\u5176\u4E2D\u5167\u5BB9\u52A0\u5165 git commit\uFF0C\u4E5F\u4E0D\u8981\u628A\u6700\u7D42\u4EA4\u4ED8\u7269\u53EA\u7559\u5728\u9019\u88E1\u3002"
|
|
2725
|
-
].join("\n");
|
|
2726
|
-
}
|
|
2727
|
-
var AUTO_PERMISSION_MODE = "auto";
|
|
2728
|
-
function claudePermissionFlag(autoMode) {
|
|
2729
|
-
return autoMode ? ` --permission-mode ${AUTO_PERMISSION_MODE}` : "";
|
|
2730
|
-
}
|
|
2731
|
-
function shellQuote(s) {
|
|
2732
|
-
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
2733
|
-
}
|
|
2734
|
-
function toShellPath(p) {
|
|
2735
|
-
return p.replace(/\\/g, "/");
|
|
2736
|
-
}
|
|
2737
|
-
function boardEnvPrefix(task, opts) {
|
|
2738
|
-
const board = opts?.boardCli;
|
|
2739
|
-
if (!board) return "";
|
|
2740
|
-
const entries = [
|
|
2741
|
-
["VIBEFLOW_TASK_ID", task.id],
|
|
2742
|
-
["VIBEFLOW_PROJECT_PATH", task.projectPath],
|
|
2743
|
-
["VIBEFLOW_BRANCH", task.branch],
|
|
2744
|
-
["VIBEFLOW_BASE_BRANCH", task.baseBranch],
|
|
2745
|
-
["VIBEFLOW_STORE_DIR", board?.storeDir],
|
|
2746
|
-
["VIBEFLOW_CLI", board?.cliPath],
|
|
2747
|
-
["VIBEFLOW_CLI_LOADER", board?.loaderPath],
|
|
2748
|
-
["VIBEFLOW_AUTO_MODE", opts?.autoMode ? "1" : "0"]
|
|
2749
|
-
];
|
|
2750
|
-
const exports = entries.filter((entry) => Boolean(entry[1])).map(([key, value]) => `${key}=${shellQuote(toShellPath(value))}`);
|
|
2751
|
-
return exports.length ? `export ${exports.join(" ")}; ` : "";
|
|
2752
|
-
}
|
|
2753
|
-
function codexAutoFlag(autoMode) {
|
|
2754
|
-
return autoMode ? "--dangerously-bypass-approvals-and-sandbox " : "";
|
|
2755
|
-
}
|
|
2756
|
-
function claudeResumeOrFresh(sessionId, worktreePath, tail) {
|
|
2757
|
-
if (!worktreePath) return `claude --resume ${sessionId} ${tail}\r`;
|
|
2758
|
-
const munged = worktreePath.replace(/[^a-zA-Z0-9]/g, "-");
|
|
2759
|
-
const sessionFile = `"$HOME/.claude/projects/${munged}/${sessionId}.jsonl"`;
|
|
2760
|
-
return `if [ -f ${sessionFile} ]; then claude --resume ${sessionId} ${tail}; else claude --session-id ${sessionId} ${tail}; fi\r`;
|
|
2761
|
-
}
|
|
2762
|
-
var SUBAGENTS_DIR2 = ".vibeflow-subagents";
|
|
2763
|
-
var PROGRESS_EVENTS_DIR = ".vibeflow-events";
|
|
2764
|
-
var TODO_TOOLS = "TodoWrite|TaskCreate|TaskUpdate";
|
|
2765
|
-
function buildClaudeSettings(worktreePath) {
|
|
2766
|
-
const settings = { theme: "dark" };
|
|
2767
|
-
if (worktreePath) {
|
|
2768
|
-
const dir = `${toShellPath(worktreePath)}/${SUBAGENTS_DIR2}`;
|
|
2769
|
-
const command = `mkdir -p "${dir}" && cat > "${dir}/$(date +%s)-$$-$RANDOM.json"`;
|
|
2770
|
-
const taskHook = {
|
|
2771
|
-
matcher: "Task",
|
|
2772
|
-
hooks: [{ type: "command", command }]
|
|
2773
|
-
};
|
|
2774
|
-
const eventsDir = `${toShellPath(worktreePath)}/${PROGRESS_EVENTS_DIR}`;
|
|
2775
|
-
const progress = {
|
|
2776
|
-
hooks: [{ type: "command", command: `mkdir -p "${eventsDir}" && cat > "${eventsDir}/$(date +%s)-$$-$RANDOM.json"; exit 0` }]
|
|
2777
|
-
};
|
|
2778
|
-
settings.hooks = {
|
|
2779
|
-
PreToolUse: [taskHook],
|
|
2780
|
-
PostToolUse: [taskHook, { matcher: TODO_TOOLS, ...progress }],
|
|
2781
|
-
Stop: [progress],
|
|
2782
|
-
Notification: [progress],
|
|
2783
|
-
UserPromptSubmit: [progress]
|
|
2784
|
-
};
|
|
2785
|
-
}
|
|
2786
|
-
return JSON.stringify(settings);
|
|
2787
|
-
}
|
|
2788
|
-
function resolveSystemPrompt(custom) {
|
|
2789
|
-
return custom && custom.trim() ? custom : "";
|
|
2790
|
-
}
|
|
2791
|
-
function buildPrompt(task) {
|
|
2792
|
-
const lines = [`\u4EFB\u52D9\u6A19\u984C\uFF1A${task.title}`];
|
|
2793
|
-
const description = task.description?.trim();
|
|
2794
|
-
if (description) {
|
|
2795
|
-
lines.push("", "\u4EFB\u52D9\u63CF\u8FF0\uFF1A", description);
|
|
2796
|
-
}
|
|
2797
|
-
return lines.join("\n");
|
|
2798
|
-
}
|
|
2799
|
-
function executorSessionId(taskId, runId) {
|
|
2800
|
-
const source = runId ? `${taskId}:${runId}` : taskId;
|
|
2801
|
-
const raw = source.replace(/[^0-9a-f]/gi, "").toLowerCase();
|
|
2802
|
-
const hex = runId ? `${raw.slice(0, 24).padEnd(24, "0")}${namespaceHash(`executor:${source}`)}` : raw.padEnd(32, "0").slice(0, 32);
|
|
2803
|
-
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-4${hex.slice(13, 16)}-8${hex.slice(17, 20)}-${hex.slice(20, 32)}`;
|
|
2804
|
-
}
|
|
2805
|
-
function namespaceHash(namespace) {
|
|
2806
|
-
let hash = 2166136261;
|
|
2807
|
-
for (let i = 0; i < namespace.length; i += 1) {
|
|
2808
|
-
hash ^= namespace.charCodeAt(i);
|
|
2809
|
-
hash = Math.imul(hash, 16777619);
|
|
2810
|
-
}
|
|
2811
|
-
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
2812
|
-
}
|
|
2813
|
-
function assembleCommand(agent, systemPrompt, prompt, model, effort, opts, worktreePath, sessionId, workspacePath) {
|
|
2814
|
-
let cmd;
|
|
2815
|
-
if (agent === "claude") {
|
|
2816
|
-
const settings = ` --settings ${shellQuote(buildClaudeSettings(worktreePath))}`;
|
|
2817
|
-
const addDir = workspacePath ? ` --add-dir ${shellQuote(toShellPath(workspacePath))}` : "";
|
|
2818
|
-
const modelFlag = model ? ` --model ${model}` : "";
|
|
2819
|
-
const effortFlag = effort ? ` --effort ${effort}` : "";
|
|
2820
|
-
const library = opts?.library;
|
|
2821
|
-
const libraryFlags = library ? ` --plugin-dir ${shellQuote(toShellPath(library.pluginDir))} --add-dir ${shellQuote(toShellPath(library.libraryDir))}` : "";
|
|
2822
|
-
const flags = `--chrome${claudePermissionFlag(opts?.autoMode)}${modelFlag}${effortFlag}${settings}${addDir}${libraryFlags}`;
|
|
2823
|
-
const sysFlag = systemPrompt ? ` --append-system-prompt ${shellQuote(systemPrompt)}` : "";
|
|
2824
|
-
const promptArg = prompt ? ` ${shellQuote(prompt)}` : "";
|
|
2825
|
-
const tail = `${flags}${sysFlag}${promptArg}`;
|
|
2826
|
-
cmd = sessionId && opts?.resume ? claudeResumeOrFresh(sessionId, worktreePath, tail) : `claude ${sessionId ? `--session-id ${sessionId} ` : opts?.resume ? "--continue " : ""}${tail}\r`;
|
|
2827
|
-
} else {
|
|
2828
|
-
const combined = [systemPrompt, prompt].filter(Boolean).join("\n\n");
|
|
2829
|
-
const codexEffortFlag = effort ? `-c ${shellQuote(`model_reasoning_effort="${effort}"`)} ` : "";
|
|
2830
|
-
const codexHome = opts?.library ? `CODEX_HOME=${shellQuote(toShellPath(opts.library.codexHome))} ` : "";
|
|
2831
|
-
const promptArg = combined ? ` ${shellQuote(combined)}` : "";
|
|
2832
|
-
cmd = `${codexHome}codex ${codexAutoFlag(opts?.autoMode)}${codexEffortFlag}--model ${model}${promptArg}\r`;
|
|
2833
|
-
}
|
|
2834
|
-
if (cmd.length > 2e5) console.warn(`[VibeFlow] launch command is ${cmd.length} bytes \u2014 approaching ARG_MAX`);
|
|
2835
|
-
return cmd;
|
|
2836
|
-
}
|
|
2837
|
-
var AGENT_NAMES = {
|
|
2838
|
-
claude: "Claude Code",
|
|
2839
|
-
codex: "Codex CLI"
|
|
2840
|
-
};
|
|
2841
|
-
var DEFAULT_MODELS = {
|
|
2842
|
-
claude: "sonnet",
|
|
2843
|
-
codex: "gpt-5.5"
|
|
2844
|
-
};
|
|
2845
|
-
var LEGACY_MODEL_FALLBACKS = {
|
|
2846
|
-
codex: {
|
|
2847
|
-
"gpt-5-codex": "gpt-5.5",
|
|
2848
|
-
"gpt-5": "gpt-5.5"
|
|
2849
|
-
}
|
|
2850
|
-
};
|
|
2851
|
-
function normalizeModel(agent, model) {
|
|
2852
|
-
return LEGACY_MODEL_FALLBACKS[agent]?.[model] ?? model;
|
|
2853
|
-
}
|
|
2854
|
-
function taskAgent(task) {
|
|
2855
|
-
const agent = task.agentCli;
|
|
2856
|
-
return agent && agent in AGENT_NAMES ? agent : "claude";
|
|
2857
|
-
}
|
|
2858
|
-
function taskModel(task) {
|
|
2859
|
-
const agent = taskAgent(task);
|
|
2860
|
-
return normalizeModel(agent, task.model || DEFAULT_MODELS[agent]);
|
|
2861
|
-
}
|
|
2862
|
-
function buildAgentCommand(task, systemPrompt, opts, workspacePath) {
|
|
2863
|
-
const agent = taskAgent(task);
|
|
2864
|
-
const model = taskModel(task);
|
|
2865
|
-
const artifactsDir = agentArtifactsDir(task.worktreePath, workspacePath) ?? ARTIFACTS_FALLBACK_DIR;
|
|
2866
|
-
const builtInPrompt = buildArtifactPrompt(artifactsDir);
|
|
2867
|
-
const libraryPrompt = opts?.library?.promptText?.trim();
|
|
2868
|
-
const customPrompt = resolveSystemPrompt(systemPrompt);
|
|
2869
|
-
const sys = [builtInPrompt, libraryPrompt, customPrompt].filter(Boolean).join("\n\n");
|
|
2870
|
-
const includeTaskPrompt = opts?.includeTaskPrompt !== false;
|
|
2871
|
-
const prompt = includeTaskPrompt && !opts?.resume ? buildPrompt(task) : "";
|
|
2872
|
-
const sessionId = agent === "claude" && includeTaskPrompt ? executorSessionId(task.id, task.runId) : void 0;
|
|
2873
|
-
return boardEnvPrefix(task, opts) + assembleCommand(
|
|
2874
|
-
agent,
|
|
2875
|
-
sys,
|
|
2876
|
-
prompt,
|
|
2877
|
-
model,
|
|
2878
|
-
task.effort,
|
|
2879
|
-
opts,
|
|
2880
|
-
task.worktreePath,
|
|
2881
|
-
sessionId,
|
|
2882
|
-
workspacePath
|
|
2883
|
-
);
|
|
2884
|
-
}
|
|
2885
|
-
|
|
2886
2941
|
// packages/core/src/git.ts
|
|
2942
|
+
init_launch();
|
|
2887
2943
|
init_env();
|
|
2888
2944
|
|
|
2889
2945
|
// packages/core/src/github.ts
|
|
@@ -3001,16 +3057,17 @@ async function listPrs(run3, repo, filter) {
|
|
|
3001
3057
|
return rows.map((r) => toPr(r, repo));
|
|
3002
3058
|
}
|
|
3003
3059
|
async function fetchRepoItems(run3, repo) {
|
|
3004
|
-
const [assignedIssues, authoredIssues, assignedPrs, authoredPrs, reviewPrs] = await Promise.all([
|
|
3060
|
+
const [assignedIssues, authoredIssues, assignedPrs, authoredPrs, reviewPrs, reviewedPrs] = await Promise.all([
|
|
3005
3061
|
listIssues(run3, repo, ["--assignee", "@me"]),
|
|
3006
3062
|
listIssues(run3, repo, ["--author", "@me"]),
|
|
3007
3063
|
listPrs(run3, repo, ["--assignee", "@me"]),
|
|
3008
3064
|
listPrs(run3, repo, ["--author", "@me"]),
|
|
3009
|
-
listPrs(run3, repo, ["--search", "review-requested:@me"])
|
|
3065
|
+
listPrs(run3, repo, ["--search", "review-requested:@me"]),
|
|
3066
|
+
listPrs(run3, repo, ["--search", "reviewed-by:@me"])
|
|
3010
3067
|
]);
|
|
3011
3068
|
return {
|
|
3012
3069
|
issues: mergeItems([assignedIssues, authoredIssues]),
|
|
3013
|
-
prs: mergeItems([assignedPrs, authoredPrs, reviewPrs])
|
|
3070
|
+
prs: mergeItems([assignedPrs, authoredPrs, reviewPrs, reviewedPrs])
|
|
3014
3071
|
};
|
|
3015
3072
|
}
|
|
3016
3073
|
async function fetchPrIndex(run3, repo) {
|
|
@@ -4142,10 +4199,10 @@ function taskAttachmentStagingPath(workspacePath, taskId) {
|
|
|
4142
4199
|
|
|
4143
4200
|
// packages/core/src/agents.ts
|
|
4144
4201
|
init_env();
|
|
4202
|
+
init_effort();
|
|
4145
4203
|
import { execFile as execFile6 } from "child_process";
|
|
4146
4204
|
import { promisify as promisify3 } from "util";
|
|
4147
4205
|
var pexec3 = promisify3(execFile6);
|
|
4148
|
-
var AGENT_EFFORTS = ["low", "medium", "high", "xhigh"];
|
|
4149
4206
|
var DEFAULT_TASK_EFFORT = "medium";
|
|
4150
4207
|
var AGENT_CLIS = [
|
|
4151
4208
|
{
|
|
@@ -4153,7 +4210,7 @@ var AGENT_CLIS = [
|
|
|
4153
4210
|
bin: "claude",
|
|
4154
4211
|
name: "Claude Code",
|
|
4155
4212
|
models: [
|
|
4156
|
-
{ id: "sonnet", label: "Sonnet\uFF08\u5E73\u8861\
|
|
4213
|
+
{ id: "sonnet", label: "Sonnet\uFF08\u5E73\u8861\uFF09" },
|
|
4157
4214
|
{ id: "haiku", label: "Haiku\uFF08\u8F15\u91CF\uFF09" },
|
|
4158
4215
|
{ id: "opus", label: "Opus\uFF08\u6700\u5F37\uFF09" }
|
|
4159
4216
|
]
|
|
@@ -4163,7 +4220,7 @@ var AGENT_CLIS = [
|
|
|
4163
4220
|
bin: "codex",
|
|
4164
4221
|
name: "Codex CLI",
|
|
4165
4222
|
models: [
|
|
4166
|
-
{ id: "gpt-5.5", label: "GPT-5.5
|
|
4223
|
+
{ id: "gpt-5.5", label: "GPT-5.5" },
|
|
4167
4224
|
{ id: "gpt-5.4", label: "GPT-5.4" },
|
|
4168
4225
|
{ id: "gpt-5.4-mini", label: "GPT-5.4 Mini" }
|
|
4169
4226
|
]
|
|
@@ -4535,8 +4592,8 @@ async function taskCommand(argv) {
|
|
|
4535
4592
|
}
|
|
4536
4593
|
|
|
4537
4594
|
// packages/cli/src/host.ts
|
|
4538
|
-
import
|
|
4539
|
-
import
|
|
4595
|
+
import fs20 from "fs";
|
|
4596
|
+
import path24 from "path";
|
|
4540
4597
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
4541
4598
|
|
|
4542
4599
|
// packages/core/src/events.ts
|
|
@@ -5074,35 +5131,278 @@ async function syncBuiltinsAtStartup() {
|
|
|
5074
5131
|
}
|
|
5075
5132
|
|
|
5076
5133
|
// packages/core/src/service.ts
|
|
5077
|
-
import
|
|
5078
|
-
import
|
|
5079
|
-
import
|
|
5134
|
+
import fs18 from "fs";
|
|
5135
|
+
import os8 from "os";
|
|
5136
|
+
import path22 from "path";
|
|
5080
5137
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
5081
5138
|
|
|
5082
5139
|
// packages/core/src/agent-models.ts
|
|
5083
|
-
import
|
|
5140
|
+
import fs13 from "fs";
|
|
5141
|
+
import os6 from "os";
|
|
5142
|
+
import path17 from "path";
|
|
5143
|
+
|
|
5144
|
+
// packages/core/src/claude-models.ts
|
|
5145
|
+
init_effort();
|
|
5084
5146
|
import fs12 from "fs";
|
|
5085
5147
|
import os4 from "os";
|
|
5086
5148
|
import path16 from "path";
|
|
5087
|
-
|
|
5149
|
+
|
|
5150
|
+
// packages/core/src/json-lines-process.ts
|
|
5088
5151
|
init_env();
|
|
5089
|
-
|
|
5152
|
+
import { spawn as spawn4 } from "child_process";
|
|
5153
|
+
function spawnJsonLines(bin, args, opts) {
|
|
5154
|
+
const spawnOpts = { cwd: opts.cwd, env: opts.env ?? execEnv(), windowsHide: true };
|
|
5155
|
+
const proc = process.platform === "win32" ? spawn4([bin, ...args].join(" "), { ...spawnOpts, shell: true }) : spawn4(bin, args, spawnOpts);
|
|
5156
|
+
const inbox = [];
|
|
5157
|
+
const waiters = [];
|
|
5158
|
+
let failure = null;
|
|
5159
|
+
let stderr = "";
|
|
5160
|
+
let exited = false;
|
|
5161
|
+
const finished = () => {
|
|
5162
|
+
if (exited) return;
|
|
5163
|
+
exited = true;
|
|
5164
|
+
opts.onExit?.();
|
|
5165
|
+
};
|
|
5166
|
+
const fail2 = (err) => {
|
|
5167
|
+
if (failure) return;
|
|
5168
|
+
failure = err;
|
|
5169
|
+
for (const w of waiters.splice(0)) w.reject(err);
|
|
5170
|
+
};
|
|
5171
|
+
const deliver = (message) => {
|
|
5172
|
+
const i = waiters.findIndex((w) => w.match(message));
|
|
5173
|
+
if (i === -1) inbox.push(message);
|
|
5174
|
+
else waiters.splice(i, 1)[0].resolve(message);
|
|
5175
|
+
};
|
|
5176
|
+
let buffered = "";
|
|
5177
|
+
proc.stdout.setEncoding("utf8");
|
|
5178
|
+
proc.stdout.on("data", (chunk) => {
|
|
5179
|
+
buffered += chunk;
|
|
5180
|
+
let nl;
|
|
5181
|
+
while ((nl = buffered.indexOf("\n")) >= 0) {
|
|
5182
|
+
const line = buffered.slice(0, nl).trim();
|
|
5183
|
+
buffered = buffered.slice(nl + 1);
|
|
5184
|
+
if (!line) continue;
|
|
5185
|
+
let message;
|
|
5186
|
+
try {
|
|
5187
|
+
message = JSON.parse(line);
|
|
5188
|
+
} catch {
|
|
5189
|
+
continue;
|
|
5190
|
+
}
|
|
5191
|
+
deliver(message);
|
|
5192
|
+
}
|
|
5193
|
+
});
|
|
5194
|
+
proc.stderr.setEncoding("utf8");
|
|
5195
|
+
proc.stderr.on("data", (chunk) => {
|
|
5196
|
+
stderr = (stderr + chunk).slice(-2048);
|
|
5197
|
+
});
|
|
5198
|
+
proc.on("error", (err) => {
|
|
5199
|
+
fail2(err);
|
|
5200
|
+
if (proc.pid === void 0) {
|
|
5201
|
+
clearTimeout(timer);
|
|
5202
|
+
finished();
|
|
5203
|
+
}
|
|
5204
|
+
});
|
|
5205
|
+
proc.on("exit", (code2, signal) => {
|
|
5206
|
+
finished();
|
|
5207
|
+
clearTimeout(timer);
|
|
5208
|
+
clearTimeout(graceTimer);
|
|
5209
|
+
const reason = signal ? `was killed (${signal})` : `exited with code ${code2}`;
|
|
5210
|
+
fail2(new Error(`${bin} ${reason}${stderr.trim() ? `: ${stderr.trim()}` : ""}`));
|
|
5211
|
+
});
|
|
5212
|
+
proc.stdin.on("error", () => {
|
|
5213
|
+
});
|
|
5214
|
+
const kill = () => {
|
|
5215
|
+
if (exited) return;
|
|
5216
|
+
if (process.platform === "win32" && proc.pid !== void 0) {
|
|
5217
|
+
spawn4("taskkill", ["/pid", String(proc.pid), "/T", "/F"], { windowsHide: true }).on("error", () => proc.kill());
|
|
5218
|
+
return;
|
|
5219
|
+
}
|
|
5220
|
+
proc.kill();
|
|
5221
|
+
};
|
|
5222
|
+
const timer = setTimeout(() => {
|
|
5223
|
+
fail2(new Error(`${bin} did not answer within ${opts.timeoutMs}ms`));
|
|
5224
|
+
kill();
|
|
5225
|
+
}, opts.timeoutMs);
|
|
5226
|
+
let graceTimer;
|
|
5227
|
+
return {
|
|
5228
|
+
send(message) {
|
|
5229
|
+
if (!failure) proc.stdin.write(`${JSON.stringify(message)}
|
|
5230
|
+
`);
|
|
5231
|
+
},
|
|
5232
|
+
next(match) {
|
|
5233
|
+
const i = inbox.findIndex(match);
|
|
5234
|
+
if (i >= 0) return Promise.resolve(inbox.splice(i, 1)[0]);
|
|
5235
|
+
if (failure) return Promise.reject(failure);
|
|
5236
|
+
return new Promise((resolve, reject) => waiters.push({ match, resolve, reject }));
|
|
5237
|
+
},
|
|
5238
|
+
close() {
|
|
5239
|
+
clearTimeout(timer);
|
|
5240
|
+
fail2(new Error(`${bin} conversation closed`));
|
|
5241
|
+
proc.stdin.end();
|
|
5242
|
+
if (!exited && !graceTimer) graceTimer = setTimeout(kill, opts.exitGraceMs ?? 3e3);
|
|
5243
|
+
}
|
|
5244
|
+
};
|
|
5245
|
+
}
|
|
5246
|
+
|
|
5247
|
+
// packages/core/src/claude-models.ts
|
|
5248
|
+
var CLAUDE_MODELS_TIMEOUT_MS = 15e3;
|
|
5249
|
+
var REQUEST_ID = "vibeflow-models";
|
|
5250
|
+
var CLAUDE_ARGS = ["-p", "--input-format", "stream-json", "--output-format", "stream-json", "--verbose"];
|
|
5251
|
+
function openClaude() {
|
|
5252
|
+
const cwd = fs12.mkdtempSync(path16.join(os4.tmpdir(), "vf-claude-models-"));
|
|
5253
|
+
return spawnJsonLines("claude", CLAUDE_ARGS, {
|
|
5254
|
+
cwd,
|
|
5255
|
+
timeoutMs: CLAUDE_MODELS_TIMEOUT_MS,
|
|
5256
|
+
onExit: () => fs12.rmSync(cwd, { recursive: true, force: true })
|
|
5257
|
+
});
|
|
5258
|
+
}
|
|
5259
|
+
function isRecord(value) {
|
|
5260
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5261
|
+
}
|
|
5262
|
+
function isOurResponse(message) {
|
|
5263
|
+
return isRecord(message) && message.type === "control_response" && isRecord(message.response) && message.response.request_id === REQUEST_ID;
|
|
5264
|
+
}
|
|
5265
|
+
function parseClaudeInitialize(message) {
|
|
5266
|
+
const outer = isRecord(message) && isRecord(message.response) ? message.response : null;
|
|
5267
|
+
if (outer?.subtype === "error") throw new Error(`claude refused the handshake: ${String(outer.error ?? "unknown error")}`);
|
|
5268
|
+
const body = outer && isRecord(outer.response) ? outer.response : null;
|
|
5269
|
+
if (!body || !Array.isArray(body.models)) throw new Error("claude handshake has no models array");
|
|
5270
|
+
const defaultEntry = body.models.find((e) => isRecord(e) && e.value === "default");
|
|
5271
|
+
const defaultResolved = isRecord(defaultEntry) && typeof defaultEntry.resolvedModel === "string" ? defaultEntry.resolvedModel : void 0;
|
|
5272
|
+
let defaultMarked = false;
|
|
5273
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5274
|
+
const models = [];
|
|
5275
|
+
for (const entry of body.models) {
|
|
5276
|
+
if (!isRecord(entry) || typeof entry.value !== "string") continue;
|
|
5277
|
+
const id = entry.value.trim();
|
|
5278
|
+
if (!id || id === "default" || seen.has(id)) continue;
|
|
5279
|
+
seen.add(id);
|
|
5280
|
+
const label = typeof entry.displayName === "string" && entry.displayName.trim() ? entry.displayName.trim() : id;
|
|
5281
|
+
const description = typeof entry.description === "string" && entry.description.trim() ? entry.description.trim() : void 0;
|
|
5282
|
+
const levels = entry.supportsEffort === true && Array.isArray(entry.supportedEffortLevels) ? entry.supportedEffortLevels.filter(isAgentEffort) : [];
|
|
5283
|
+
const isDefault = !defaultMarked && defaultResolved !== void 0 && entry.resolvedModel === defaultResolved;
|
|
5284
|
+
if (isDefault) defaultMarked = true;
|
|
5285
|
+
models.push({ id, label, ...description ? { description } : {}, efforts: levels, ...isDefault ? { isDefault } : {} });
|
|
5286
|
+
}
|
|
5287
|
+
if (models.length === 0) throw new Error("claude handshake lists no selectable models");
|
|
5288
|
+
return models;
|
|
5289
|
+
}
|
|
5290
|
+
async function fetchClaudeModels(open = openClaude) {
|
|
5291
|
+
const channel = open();
|
|
5292
|
+
try {
|
|
5293
|
+
channel.send({ type: "control_request", request_id: REQUEST_ID, request: { subtype: "initialize" } });
|
|
5294
|
+
return parseClaudeInitialize(await channel.next(isOurResponse));
|
|
5295
|
+
} finally {
|
|
5296
|
+
channel.close();
|
|
5297
|
+
}
|
|
5298
|
+
}
|
|
5299
|
+
|
|
5300
|
+
// packages/core/src/codex-models.ts
|
|
5301
|
+
init_effort();
|
|
5302
|
+
init_env();
|
|
5303
|
+
import os5 from "os";
|
|
5090
5304
|
var CODEX_MODELS_TIMEOUT_MS = 2e4;
|
|
5305
|
+
var MAX_PAGES = 20;
|
|
5306
|
+
var CodexLoginRequiredError = class extends Error {
|
|
5307
|
+
constructor() {
|
|
5308
|
+
super("Codex CLI is not signed in; run `codex login`");
|
|
5309
|
+
this.name = "CodexLoginRequiredError";
|
|
5310
|
+
}
|
|
5311
|
+
};
|
|
5312
|
+
function codexAppServerCommand() {
|
|
5313
|
+
return {
|
|
5314
|
+
bin: "codex",
|
|
5315
|
+
args: ["app-server", "--listen", "stdio://"],
|
|
5316
|
+
cwd: os5.homedir(),
|
|
5317
|
+
env: execEnv()
|
|
5318
|
+
};
|
|
5319
|
+
}
|
|
5320
|
+
function openCodex() {
|
|
5321
|
+
const { bin, args, cwd, env } = codexAppServerCommand();
|
|
5322
|
+
return spawnJsonLines(bin, args, { cwd, env, timeoutMs: CODEX_MODELS_TIMEOUT_MS });
|
|
5323
|
+
}
|
|
5324
|
+
function isRecord2(value) {
|
|
5325
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5326
|
+
}
|
|
5327
|
+
var responseTo = (id) => (message) => isRecord2(message) && message.id === id && ("result" in message || "error" in message);
|
|
5328
|
+
function resultOf(message, method) {
|
|
5329
|
+
if (!isRecord2(message)) throw new Error(`codex ${method}: malformed response`);
|
|
5330
|
+
if (isRecord2(message.error)) throw new Error(`codex ${method}: ${String(message.error.message ?? "request failed")}`);
|
|
5331
|
+
if (!isRecord2(message.result)) throw new Error(`codex ${method}: response has no result`);
|
|
5332
|
+
return message.result;
|
|
5333
|
+
}
|
|
5334
|
+
function isCodexSignedIn(result) {
|
|
5335
|
+
return result.account != null || result.requiresOpenaiAuth === false;
|
|
5336
|
+
}
|
|
5337
|
+
function parseCodexModelPage(result) {
|
|
5338
|
+
if (!Array.isArray(result.data)) throw new Error("codex model/list has no data array");
|
|
5339
|
+
const models = [];
|
|
5340
|
+
for (const entry of result.data) {
|
|
5341
|
+
if (!isRecord2(entry) || typeof entry.id !== "string" || !entry.id.trim() || entry.hidden === true) continue;
|
|
5342
|
+
const id = entry.id.trim();
|
|
5343
|
+
const label = typeof entry.displayName === "string" && entry.displayName.trim() ? entry.displayName.trim() : id;
|
|
5344
|
+
const description = typeof entry.description === "string" && entry.description.trim() ? entry.description.trim() : void 0;
|
|
5345
|
+
const efforts = Array.isArray(entry.supportedReasoningEfforts) ? entry.supportedReasoningEfforts.map((e) => isRecord2(e) ? e.reasoningEffort : void 0).filter(isAgentEffort) : void 0;
|
|
5346
|
+
models.push({
|
|
5347
|
+
id,
|
|
5348
|
+
label,
|
|
5349
|
+
...description ? { description } : {},
|
|
5350
|
+
...efforts ? { efforts } : {},
|
|
5351
|
+
...entry.isDefault === true ? { isDefault: true } : {}
|
|
5352
|
+
});
|
|
5353
|
+
}
|
|
5354
|
+
const nextCursor = typeof result.nextCursor === "string" && result.nextCursor ? result.nextCursor : null;
|
|
5355
|
+
return { models, nextCursor };
|
|
5356
|
+
}
|
|
5357
|
+
async function fetchCodexModels(clientVersion, open = openCodex) {
|
|
5358
|
+
const channel = open();
|
|
5359
|
+
try {
|
|
5360
|
+
channel.send({
|
|
5361
|
+
method: "initialize",
|
|
5362
|
+
id: 1,
|
|
5363
|
+
params: { clientInfo: { name: "vibeflow", title: "VibeFlow", version: clientVersion } }
|
|
5364
|
+
});
|
|
5365
|
+
resultOf(await channel.next(responseTo(1)), "initialize");
|
|
5366
|
+
channel.send({ method: "initialized", params: {} });
|
|
5367
|
+
channel.send({ method: "account/read", id: 2, params: { refreshToken: false } });
|
|
5368
|
+
if (!isCodexSignedIn(resultOf(await channel.next(responseTo(2)), "account/read"))) {
|
|
5369
|
+
throw new CodexLoginRequiredError();
|
|
5370
|
+
}
|
|
5371
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5372
|
+
const models = [];
|
|
5373
|
+
let cursor = null;
|
|
5374
|
+
for (let page = 0; page < MAX_PAGES; page++) {
|
|
5375
|
+
const id = 3 + page;
|
|
5376
|
+
channel.send({
|
|
5377
|
+
method: "model/list",
|
|
5378
|
+
id,
|
|
5379
|
+
params: { limit: 100, includeHidden: false, ...cursor ? { cursor } : {} }
|
|
5380
|
+
});
|
|
5381
|
+
const parsed = parseCodexModelPage(resultOf(await channel.next(responseTo(id)), "model/list"));
|
|
5382
|
+
for (const model of parsed.models) {
|
|
5383
|
+
if (seen.has(model.id)) continue;
|
|
5384
|
+
seen.add(model.id);
|
|
5385
|
+
models.push(model);
|
|
5386
|
+
}
|
|
5387
|
+
cursor = parsed.nextCursor;
|
|
5388
|
+
if (!cursor) break;
|
|
5389
|
+
}
|
|
5390
|
+
if (cursor) throw new Error(`codex model/list did not finish within ${MAX_PAGES} pages`);
|
|
5391
|
+
if (models.length === 0) throw new Error("codex model/list lists no selectable models");
|
|
5392
|
+
return models;
|
|
5393
|
+
} finally {
|
|
5394
|
+
channel.close();
|
|
5395
|
+
}
|
|
5396
|
+
}
|
|
5397
|
+
|
|
5398
|
+
// packages/core/src/agent-models.ts
|
|
5399
|
+
init_effort();
|
|
5091
5400
|
function builtinModels(id) {
|
|
5092
5401
|
return (AGENT_CLIS.find((a) => a.id === id) ?? AGENT_CLIS[0]).models;
|
|
5093
5402
|
}
|
|
5094
5403
|
function defaultCodexHome() {
|
|
5095
5404
|
const configured = process.env.CODEX_HOME?.trim();
|
|
5096
|
-
return configured ? configured :
|
|
5097
|
-
}
|
|
5098
|
-
async function defaultRunCodexModels() {
|
|
5099
|
-
const { stdout } = await pexec4("codex", ["debug", "models"], {
|
|
5100
|
-
env: execEnv(),
|
|
5101
|
-
timeout: CODEX_MODELS_TIMEOUT_MS,
|
|
5102
|
-
maxBuffer: 16 * 1024 * 1024,
|
|
5103
|
-
windowsHide: true
|
|
5104
|
-
});
|
|
5105
|
-
return stdout;
|
|
5405
|
+
return configured ? configured : path17.join(os6.homedir(), ".codex");
|
|
5106
5406
|
}
|
|
5107
5407
|
function parseCodexCatalog(raw) {
|
|
5108
5408
|
const body = JSON.parse(raw);
|
|
@@ -5127,36 +5427,75 @@ function parseCodexCatalog(raw) {
|
|
|
5127
5427
|
function errorMessage(err) {
|
|
5128
5428
|
return err instanceof Error ? err.message : String(err);
|
|
5129
5429
|
}
|
|
5130
|
-
async function
|
|
5131
|
-
|
|
5132
|
-
if (opts.refresh) {
|
|
5133
|
-
try {
|
|
5134
|
-
const stdout = await (opts.runCodexModels ?? defaultRunCodexModels)();
|
|
5135
|
-
return { models: parseCodexCatalog(stdout), source: "codex-cli" };
|
|
5136
|
-
} catch (err) {
|
|
5137
|
-
return { models: builtinModels(id), source: "builtin", error: errorMessage(err) };
|
|
5138
|
-
}
|
|
5139
|
-
}
|
|
5140
|
-
const cachePath = path16.join(opts.codexHome ?? defaultCodexHome(), "models_cache.json");
|
|
5430
|
+
async function readCodexCache(codexHome) {
|
|
5431
|
+
const cachePath = path17.join(codexHome, "models_cache.json");
|
|
5141
5432
|
try {
|
|
5142
|
-
const raw = await
|
|
5433
|
+
const raw = await fs13.promises.readFile(cachePath, "utf8");
|
|
5143
5434
|
return { models: parseCodexCatalog(raw), source: "codex-cache" };
|
|
5144
5435
|
} catch (err) {
|
|
5145
5436
|
const missing = err.code === "ENOENT";
|
|
5146
5437
|
return {
|
|
5147
|
-
models: builtinModels(
|
|
5438
|
+
models: builtinModels("codex"),
|
|
5148
5439
|
source: "builtin",
|
|
5149
5440
|
...missing ? {} : { error: errorMessage(err) }
|
|
5150
5441
|
};
|
|
5151
5442
|
}
|
|
5152
5443
|
}
|
|
5444
|
+
function createModelCatalog(opts) {
|
|
5445
|
+
const fetchClaude = opts.fetchClaude ?? (() => fetchClaudeModels());
|
|
5446
|
+
const fetchCodex = opts.fetchCodex ?? (() => fetchCodexModels(opts.version));
|
|
5447
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
5448
|
+
const settled = /* @__PURE__ */ new Map();
|
|
5449
|
+
const fallback = (id) => id === "codex" ? readCodexCache(opts.codexHome ?? defaultCodexHome()) : Promise.resolve({ models: builtinModels(id), source: "builtin" });
|
|
5450
|
+
const ask = async (id) => {
|
|
5451
|
+
try {
|
|
5452
|
+
const models = await (id === "codex" ? fetchCodex() : fetchClaude());
|
|
5453
|
+
return { models, source: id === "codex" ? "codex-app-server" : "claude-cli" };
|
|
5454
|
+
} catch (err) {
|
|
5455
|
+
const list = await fallback(id);
|
|
5456
|
+
return {
|
|
5457
|
+
...list,
|
|
5458
|
+
error: errorMessage(err),
|
|
5459
|
+
...err instanceof CodexLoginRequiredError ? { loginRequired: true } : {}
|
|
5460
|
+
};
|
|
5461
|
+
}
|
|
5462
|
+
};
|
|
5463
|
+
const refresh = (id) => {
|
|
5464
|
+
const running = inFlight.get(id);
|
|
5465
|
+
if (running) return running;
|
|
5466
|
+
const pending = ask(id).then((list) => {
|
|
5467
|
+
settled.set(id, list);
|
|
5468
|
+
return list;
|
|
5469
|
+
}).finally(() => inFlight.delete(id));
|
|
5470
|
+
inFlight.set(id, pending);
|
|
5471
|
+
return pending;
|
|
5472
|
+
};
|
|
5473
|
+
return {
|
|
5474
|
+
async get(id) {
|
|
5475
|
+
const answer = settled.get(id);
|
|
5476
|
+
if (answer) return answer;
|
|
5477
|
+
const list = await fallback(id);
|
|
5478
|
+
return inFlight.has(id) ? { ...list, pending: true } : list;
|
|
5479
|
+
},
|
|
5480
|
+
refresh,
|
|
5481
|
+
warm() {
|
|
5482
|
+
for (const agent of AGENT_CLIS) void refresh(agent.id);
|
|
5483
|
+
},
|
|
5484
|
+
findModel(id, modelId) {
|
|
5485
|
+
return modelFor(settled.get(id)?.models, modelId);
|
|
5486
|
+
}
|
|
5487
|
+
};
|
|
5488
|
+
}
|
|
5489
|
+
|
|
5490
|
+
// packages/core/src/service.ts
|
|
5491
|
+
init_effort();
|
|
5153
5492
|
|
|
5154
5493
|
// packages/core/src/github-auth.ts
|
|
5155
5494
|
init_env();
|
|
5156
|
-
import { execFile as
|
|
5157
|
-
import { promisify as
|
|
5495
|
+
import { execFile as execFile7 } from "child_process";
|
|
5496
|
+
import { promisify as promisify4 } from "util";
|
|
5158
5497
|
import * as nodePty3 from "node-pty";
|
|
5159
|
-
var
|
|
5498
|
+
var pexec4 = promisify4(execFile7);
|
|
5160
5499
|
var GITHUB_HOST = "github.com";
|
|
5161
5500
|
var DEVICE_URL = "https://github.com/login/device";
|
|
5162
5501
|
var activeLogin = null;
|
|
@@ -5191,7 +5530,7 @@ function errorMessage2(err) {
|
|
|
5191
5530
|
}
|
|
5192
5531
|
async function getGitHubCliAuthStatus() {
|
|
5193
5532
|
try {
|
|
5194
|
-
const { stdout } = await
|
|
5533
|
+
const { stdout } = await pexec4(
|
|
5195
5534
|
"gh",
|
|
5196
5535
|
["auth", "status", "--hostname", GITHUB_HOST, "--json", "hosts"],
|
|
5197
5536
|
{
|
|
@@ -5223,7 +5562,7 @@ async function logoutGitHubCli() {
|
|
|
5223
5562
|
const status = await getGitHubCliAuthStatus();
|
|
5224
5563
|
if (!status.installed) throw new Error("\u627E\u4E0D\u5230 GitHub CLI\uFF08gh\uFF09\u3002");
|
|
5225
5564
|
if (!status.login) return status;
|
|
5226
|
-
await
|
|
5565
|
+
await pexec4(
|
|
5227
5566
|
"gh",
|
|
5228
5567
|
["auth", "logout", "--hostname", GITHUB_HOST, "--user", status.login],
|
|
5229
5568
|
{
|
|
@@ -5306,45 +5645,45 @@ function startGitHubCliLogin(onEvent) {
|
|
|
5306
5645
|
}
|
|
5307
5646
|
|
|
5308
5647
|
// packages/core/src/board-cli.ts
|
|
5309
|
-
import
|
|
5310
|
-
import
|
|
5648
|
+
import fs14 from "fs";
|
|
5649
|
+
import path18 from "path";
|
|
5311
5650
|
import { pathToFileURL } from "url";
|
|
5312
5651
|
async function boardCliLaunchInfo() {
|
|
5313
|
-
const storeDir =
|
|
5652
|
+
const storeDir = path18.dirname(getStorePath());
|
|
5314
5653
|
const entry = getPlatform().cliEntry?.();
|
|
5315
|
-
if (entry &&
|
|
5654
|
+
if (entry && fs14.existsSync(entry)) return { storeDir, cliPath: entry };
|
|
5316
5655
|
const root = getPlatform().sourceRoot();
|
|
5317
5656
|
if (!root) return { storeDir };
|
|
5318
|
-
const cliPath =
|
|
5319
|
-
const loaderPath =
|
|
5320
|
-
if (!
|
|
5657
|
+
const cliPath = path18.join(root, "scripts", "vibeflow.mjs");
|
|
5658
|
+
const loaderPath = path18.join(root, "test", "support", "register.mjs");
|
|
5659
|
+
if (!fs14.existsSync(cliPath) || !fs14.existsSync(loaderPath)) return { storeDir };
|
|
5321
5660
|
return { storeDir, cliPath, loaderPath: pathToFileURL(loaderPath).href };
|
|
5322
5661
|
}
|
|
5323
5662
|
|
|
5324
5663
|
// packages/core/src/decisions.ts
|
|
5325
|
-
import
|
|
5326
|
-
import
|
|
5664
|
+
import fs15 from "fs";
|
|
5665
|
+
import path19 from "path";
|
|
5327
5666
|
var DECISIONS_FILE_SUFFIX = ".DECISIONS.md";
|
|
5328
5667
|
function decisionsKey(worktreePath, branch) {
|
|
5329
|
-
return worktreePath ?
|
|
5668
|
+
return worktreePath ? path19.basename(worktreePath) : branch.replace(/\//g, "-");
|
|
5330
5669
|
}
|
|
5331
5670
|
function decisionsPath(workspacePath, key) {
|
|
5332
|
-
return
|
|
5671
|
+
return path19.join(workspacePath, `${key}${DECISIONS_FILE_SUFFIX}`);
|
|
5333
5672
|
}
|
|
5334
5673
|
function deleteDecisions(workspacePath, key) {
|
|
5335
5674
|
try {
|
|
5336
|
-
|
|
5675
|
+
fs15.rmSync(decisionsPath(workspacePath, key), { force: true });
|
|
5337
5676
|
} catch {
|
|
5338
5677
|
}
|
|
5339
5678
|
}
|
|
5340
5679
|
|
|
5341
5680
|
// packages/core/src/specs.ts
|
|
5342
|
-
import
|
|
5343
|
-
import
|
|
5681
|
+
import fs16 from "fs";
|
|
5682
|
+
import path20 from "path";
|
|
5344
5683
|
var SPEC_FILE_NAME = "spec.md";
|
|
5345
5684
|
var MAX_SPEC_BYTES = 256 * 1024;
|
|
5346
5685
|
function isSpecPath(p) {
|
|
5347
|
-
return
|
|
5686
|
+
return path20.posix.basename(p) === SPEC_FILE_NAME;
|
|
5348
5687
|
}
|
|
5349
5688
|
function clip2(buf) {
|
|
5350
5689
|
return {
|
|
@@ -5359,10 +5698,10 @@ async function readWorktreeSpecs(worktreePath, baseBranch) {
|
|
|
5359
5698
|
for (const entry of entries) {
|
|
5360
5699
|
if (entry.status === "D" || !isSpecPath(entry.path)) continue;
|
|
5361
5700
|
try {
|
|
5362
|
-
const full =
|
|
5363
|
-
const stat =
|
|
5701
|
+
const full = path20.join(worktreePath, entry.path);
|
|
5702
|
+
const stat = fs16.statSync(full);
|
|
5364
5703
|
if (!stat.isFile()) continue;
|
|
5365
|
-
specs.push({ path: entry.path, ...clip2(
|
|
5704
|
+
specs.push({ path: entry.path, ...clip2(fs16.readFileSync(full)), updatedAt: stat.mtimeMs });
|
|
5366
5705
|
} catch {
|
|
5367
5706
|
}
|
|
5368
5707
|
}
|
|
@@ -5427,7 +5766,7 @@ async function readSpecsAt(cwd, ref, paths) {
|
|
|
5427
5766
|
// packages/core/src/chat-session.ts
|
|
5428
5767
|
init_env();
|
|
5429
5768
|
init_git_bash();
|
|
5430
|
-
import { spawn as
|
|
5769
|
+
import { spawn as spawn6 } from "child_process";
|
|
5431
5770
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
5432
5771
|
|
|
5433
5772
|
// packages/core/src/chat-store.ts
|
|
@@ -5583,7 +5922,7 @@ ${attachmentLines.join("\n")}` : text;
|
|
|
5583
5922
|
`--append-system-prompt ${quote(systemPrompt)}`,
|
|
5584
5923
|
quote(fullText)
|
|
5585
5924
|
].filter(Boolean).join(" ") : buildRawAgentCommand(agentCli, model, fullText, systemPrompt, worktreePath, quote, workspacePath);
|
|
5586
|
-
const proc =
|
|
5925
|
+
const proc = spawn6(shell.command, shell.args(cmd), {
|
|
5587
5926
|
cwd: worktreePath,
|
|
5588
5927
|
env: execEnv()
|
|
5589
5928
|
});
|
|
@@ -5709,20 +6048,22 @@ function startChatSend(opts, sender) {
|
|
|
5709
6048
|
|
|
5710
6049
|
// packages/core/src/service.ts
|
|
5711
6050
|
init_attachments();
|
|
6051
|
+
init_launch();
|
|
5712
6052
|
|
|
5713
6053
|
// packages/core/src/progress-tracker.ts
|
|
5714
6054
|
init_progress();
|
|
5715
|
-
|
|
5716
|
-
import
|
|
5717
|
-
import
|
|
6055
|
+
init_launch();
|
|
6056
|
+
import fs17 from "fs";
|
|
6057
|
+
import os7 from "os";
|
|
6058
|
+
import path21 from "path";
|
|
5718
6059
|
var SINCE_SLACK_MS = 5e3;
|
|
5719
6060
|
function claudeProjectDir(home, cwd) {
|
|
5720
|
-
return
|
|
6061
|
+
return path21.join(home, ".claude", "projects", cwd.replace(/[^a-zA-Z0-9]/g, "-"));
|
|
5721
6062
|
}
|
|
5722
6063
|
function pathAliases(p) {
|
|
5723
|
-
const resolved =
|
|
6064
|
+
const resolved = path21.resolve(p);
|
|
5724
6065
|
try {
|
|
5725
|
-
const real =
|
|
6066
|
+
const real = fs17.realpathSync(resolved);
|
|
5726
6067
|
return real === resolved ? [resolved] : [resolved, real];
|
|
5727
6068
|
} catch {
|
|
5728
6069
|
return [resolved];
|
|
@@ -5738,7 +6079,7 @@ function samePath(a, b) {
|
|
|
5738
6079
|
}
|
|
5739
6080
|
function listFiles(dir, test) {
|
|
5740
6081
|
try {
|
|
5741
|
-
return
|
|
6082
|
+
return fs17.readdirSync(dir).filter(test).map((name) => path21.join(dir, name));
|
|
5742
6083
|
} catch {
|
|
5743
6084
|
return [];
|
|
5744
6085
|
}
|
|
@@ -5746,22 +6087,22 @@ function listFiles(dir, test) {
|
|
|
5746
6087
|
function firstLine(file) {
|
|
5747
6088
|
let fd;
|
|
5748
6089
|
try {
|
|
5749
|
-
fd =
|
|
6090
|
+
fd = fs17.openSync(file, "r");
|
|
5750
6091
|
const buf = Buffer.alloc(64 * 1024);
|
|
5751
|
-
const n =
|
|
6092
|
+
const n = fs17.readSync(fd, buf, 0, buf.length, 0);
|
|
5752
6093
|
const text = buf.subarray(0, n).toString("utf8");
|
|
5753
6094
|
const nl = text.indexOf("\n");
|
|
5754
6095
|
return nl === -1 ? null : text.slice(0, nl);
|
|
5755
6096
|
} catch {
|
|
5756
6097
|
return null;
|
|
5757
6098
|
} finally {
|
|
5758
|
-
if (fd !== void 0)
|
|
6099
|
+
if (fd !== void 0) fs17.closeSync(fd);
|
|
5759
6100
|
}
|
|
5760
6101
|
}
|
|
5761
6102
|
function advance(file, cursor, reduce, initial) {
|
|
5762
6103
|
let size;
|
|
5763
6104
|
try {
|
|
5764
|
-
size =
|
|
6105
|
+
size = fs17.statSync(file).size;
|
|
5765
6106
|
} catch {
|
|
5766
6107
|
return;
|
|
5767
6108
|
}
|
|
@@ -5773,9 +6114,9 @@ function advance(file, cursor, reduce, initial) {
|
|
|
5773
6114
|
if (size === cursor.offset) return;
|
|
5774
6115
|
let fd;
|
|
5775
6116
|
try {
|
|
5776
|
-
fd =
|
|
6117
|
+
fd = fs17.openSync(file, "r");
|
|
5777
6118
|
const chunk = Buffer.alloc(size - cursor.offset);
|
|
5778
|
-
const n =
|
|
6119
|
+
const n = fs17.readSync(fd, chunk, 0, chunk.length, cursor.offset);
|
|
5779
6120
|
cursor.offset += n;
|
|
5780
6121
|
const data = Buffer.concat([cursor.rest, chunk.subarray(0, n)]);
|
|
5781
6122
|
const nl = data.lastIndexOf(10);
|
|
@@ -5789,7 +6130,7 @@ function advance(file, cursor, reduce, initial) {
|
|
|
5789
6130
|
}
|
|
5790
6131
|
} catch {
|
|
5791
6132
|
} finally {
|
|
5792
|
-
if (fd !== void 0)
|
|
6133
|
+
if (fd !== void 0) fs17.closeSync(fd);
|
|
5793
6134
|
}
|
|
5794
6135
|
}
|
|
5795
6136
|
function newCursor(state) {
|
|
@@ -5808,14 +6149,14 @@ function codexDayDirs(sessionsRoot, since) {
|
|
|
5808
6149
|
const cur = new Date(start.getFullYear(), start.getMonth(), start.getDate());
|
|
5809
6150
|
while (cur <= end) {
|
|
5810
6151
|
const pad = (n) => String(n).padStart(2, "0");
|
|
5811
|
-
days.push(
|
|
6152
|
+
days.push(path21.join(sessionsRoot, String(cur.getFullYear()), pad(cur.getMonth() + 1), pad(cur.getDate())));
|
|
5812
6153
|
cur.setDate(cur.getDate() + 1);
|
|
5813
6154
|
}
|
|
5814
6155
|
return days;
|
|
5815
6156
|
}
|
|
5816
6157
|
function createProgressTracker(opts) {
|
|
5817
|
-
const home = opts.homeDir ??
|
|
5818
|
-
const codexHomes = opts.codexHomes ?? (() => [
|
|
6158
|
+
const home = opts.homeDir ?? os7.homedir();
|
|
6159
|
+
const codexHomes = opts.codexHomes ?? (() => [path21.join(home, ".codex")]);
|
|
5819
6160
|
const pollMs = opts.pollMs ?? 2e3;
|
|
5820
6161
|
const entries = /* @__PURE__ */ new Map();
|
|
5821
6162
|
const belongsToRun = (target, startedAt) => target.since == null || startedAt != null && startedAt >= target.since - SINCE_SLACK_MS;
|
|
@@ -5824,7 +6165,7 @@ function createProgressTracker(opts) {
|
|
|
5824
6165
|
const dirs = pathAliases(target.worktreePath).map((p) => claudeProjectDir(home, p));
|
|
5825
6166
|
for (const file of dirs.flatMap((dir) => listFiles(dir, (n) => n.endsWith(".jsonl")))) {
|
|
5826
6167
|
if (entry.claude.has(file) || entry.rejected.has(file)) continue;
|
|
5827
|
-
const session =
|
|
6168
|
+
const session = path21.basename(file, ".jsonl");
|
|
5828
6169
|
if (session !== target.sessionId) {
|
|
5829
6170
|
const head = firstLine(file);
|
|
5830
6171
|
if (head == null) continue;
|
|
@@ -5837,8 +6178,8 @@ function createProgressTracker(opts) {
|
|
|
5837
6178
|
entry.claude.set(file, newCursor(initialClaudeState()));
|
|
5838
6179
|
}
|
|
5839
6180
|
for (const file of Array.from(entry.claude.keys())) {
|
|
5840
|
-
if (file.includes(`${
|
|
5841
|
-
const sub =
|
|
6181
|
+
if (file.includes(`${path21.sep}subagents${path21.sep}`)) continue;
|
|
6182
|
+
const sub = path21.join(file.slice(0, -".jsonl".length), "subagents");
|
|
5842
6183
|
for (const f of listFiles(sub, (n) => n.endsWith(".jsonl"))) {
|
|
5843
6184
|
if (!entry.claude.has(f)) entry.claude.set(f, newCursor(initialClaudeState()));
|
|
5844
6185
|
}
|
|
@@ -5847,7 +6188,7 @@ function createProgressTracker(opts) {
|
|
|
5847
6188
|
function discoverCodex(entry) {
|
|
5848
6189
|
const { target } = entry;
|
|
5849
6190
|
for (const codexHome of codexHomes()) {
|
|
5850
|
-
for (const day of codexDayDirs(
|
|
6191
|
+
for (const day of codexDayDirs(path21.join(codexHome, "sessions"), target.since)) {
|
|
5851
6192
|
for (const file of listFiles(day, (n) => n.startsWith("rollout-") && n.endsWith(".jsonl"))) {
|
|
5852
6193
|
if (entry.codex.has(file) || entry.rejected.has(file)) continue;
|
|
5853
6194
|
const head = firstLine(file);
|
|
@@ -5864,11 +6205,11 @@ function createProgressTracker(opts) {
|
|
|
5864
6205
|
}
|
|
5865
6206
|
}
|
|
5866
6207
|
function drainHooks(entry) {
|
|
5867
|
-
const dir =
|
|
6208
|
+
const dir = path21.join(entry.target.worktreePath, PROGRESS_EVENTS_DIR);
|
|
5868
6209
|
for (const file of listFiles(dir, (n) => n.endsWith(".json")).sort()) {
|
|
5869
6210
|
try {
|
|
5870
|
-
const at =
|
|
5871
|
-
const event = JSON.parse(
|
|
6211
|
+
const at = fs17.statSync(file).mtimeMs;
|
|
6212
|
+
const event = JSON.parse(fs17.readFileSync(file, "utf8"));
|
|
5872
6213
|
const foreign = entry.target.sessionId && typeof event.session_id === "string" && event.session_id !== entry.target.sessionId;
|
|
5873
6214
|
const activity = foreign ? null : activityFromHook(event, at);
|
|
5874
6215
|
if (activity) entry.hookActivity = latestActivity(entry.hookActivity ?? activity, activity);
|
|
@@ -5876,7 +6217,7 @@ function createProgressTracker(opts) {
|
|
|
5876
6217
|
continue;
|
|
5877
6218
|
}
|
|
5878
6219
|
try {
|
|
5879
|
-
|
|
6220
|
+
fs17.unlinkSync(file);
|
|
5880
6221
|
} catch {
|
|
5881
6222
|
}
|
|
5882
6223
|
}
|
|
@@ -5888,8 +6229,8 @@ function createProgressTracker(opts) {
|
|
|
5888
6229
|
if (target.agent === "claude") {
|
|
5889
6230
|
for (const [file, cursor] of entry.claude) {
|
|
5890
6231
|
runUsage = addUsage(runUsage, claudeUsageTotal(cursor.state));
|
|
5891
|
-
if (file.includes(`${
|
|
5892
|
-
const isExecutor =
|
|
6232
|
+
if (file.includes(`${path21.sep}subagents${path21.sep}`)) continue;
|
|
6233
|
+
const isExecutor = path21.basename(file, ".jsonl") === target.sessionId;
|
|
5893
6234
|
const s = cursor.state;
|
|
5894
6235
|
if (isExecutor || !target.sessionId && (!primary || (s.startedAt ?? 0) > (primary.startedAt ?? 0))) {
|
|
5895
6236
|
primary = { todos: s.todos, contextTokens: s.contextTokens, activity: s.activity, startedAt: s.startedAt };
|
|
@@ -5968,10 +6309,10 @@ function createProgressTracker(opts) {
|
|
|
5968
6309
|
};
|
|
5969
6310
|
entry.timer.unref?.();
|
|
5970
6311
|
entries.set(target.taskId, entry);
|
|
5971
|
-
const eventsDir =
|
|
6312
|
+
const eventsDir = path21.join(target.worktreePath, PROGRESS_EVENTS_DIR);
|
|
5972
6313
|
try {
|
|
5973
|
-
|
|
5974
|
-
entry.watcher =
|
|
6314
|
+
fs17.mkdirSync(eventsDir, { recursive: true });
|
|
6315
|
+
entry.watcher = fs17.watch(eventsDir, () => {
|
|
5975
6316
|
if (entry.pending) return;
|
|
5976
6317
|
entry.pending = setTimeout(() => {
|
|
5977
6318
|
entry.pending = null;
|
|
@@ -6056,17 +6397,18 @@ function validBoard(value) {
|
|
|
6056
6397
|
}
|
|
6057
6398
|
return next;
|
|
6058
6399
|
}
|
|
6059
|
-
function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatus }) {
|
|
6400
|
+
function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatus, modelCatalog }) {
|
|
6060
6401
|
const sink = bus.sink();
|
|
6402
|
+
const models = modelCatalog ?? createModelCatalog({ version });
|
|
6061
6403
|
let libraryCodexHome = null;
|
|
6062
6404
|
void libraryRoot().then((root) => {
|
|
6063
6405
|
libraryCodexHome = libraryPaths(root).codexHome;
|
|
6064
6406
|
}).catch(() => {
|
|
6065
6407
|
});
|
|
6066
|
-
const home = homeDir ??
|
|
6408
|
+
const home = homeDir ?? os8.homedir();
|
|
6067
6409
|
const progress = createProgressTracker({
|
|
6068
6410
|
homeDir: home,
|
|
6069
|
-
codexHomes: () => [
|
|
6411
|
+
codexHomes: () => [path22.join(home, ".codex"), ...libraryCodexHome ? [libraryCodexHome] : []],
|
|
6070
6412
|
onUpdate: (taskId, value) => bus.emit("progress:update", { taskId, progress: value }),
|
|
6071
6413
|
onNotify: (taskId, list) => {
|
|
6072
6414
|
const prefs = resolveNotificationSettings(getSettings());
|
|
@@ -6130,12 +6472,16 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6130
6472
|
requireTask(key.split(":")[0]);
|
|
6131
6473
|
return key;
|
|
6132
6474
|
}
|
|
6475
|
+
function launchEffort(task) {
|
|
6476
|
+
const model = models.findModel(taskAgent(task), taskModel(task));
|
|
6477
|
+
return model?.efforts ? clampEffort(task.effort, model.efforts) : task.effort;
|
|
6478
|
+
}
|
|
6133
6479
|
async function launchCommand(task, intent) {
|
|
6134
6480
|
const settings = getSettings();
|
|
6135
6481
|
const library = await libraryLaunchInfo(task.worktreePath);
|
|
6136
6482
|
const boardCli = await boardCliLaunchInfo();
|
|
6137
6483
|
return buildAgentCommand(
|
|
6138
|
-
task,
|
|
6484
|
+
{ ...task, effort: launchEffort(task) },
|
|
6139
6485
|
settings.systemPrompt ?? "",
|
|
6140
6486
|
{
|
|
6141
6487
|
resume: intent.resume === true,
|
|
@@ -6149,13 +6495,13 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6149
6495
|
}
|
|
6150
6496
|
function claudeSessionFile(cwd, sessionId) {
|
|
6151
6497
|
const munged = cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
6152
|
-
return
|
|
6498
|
+
return path22.join(os8.homedir(), ".claude", "projects", munged, `${sessionId}.jsonl`);
|
|
6153
6499
|
}
|
|
6154
6500
|
async function removeTaskWorktree(task) {
|
|
6155
6501
|
if (!task.projectPath || !task.worktreePath) return;
|
|
6156
6502
|
const branch = task.branch || fallbackBranchName(task.id);
|
|
6157
6503
|
await removeWorktree(task.projectPath, task.worktreePath);
|
|
6158
|
-
deleteArtifacts(task.workspacePath ??
|
|
6504
|
+
deleteArtifacts(task.workspacePath ?? path22.dirname(task.worktreePath), task.worktreePath);
|
|
6159
6505
|
await deleteBranch(task.projectPath, branch);
|
|
6160
6506
|
}
|
|
6161
6507
|
function columnOf(taskId) {
|
|
@@ -6246,7 +6592,8 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6246
6592
|
"env:detectAgents": () => detectAgents(),
|
|
6247
6593
|
"agents:listModels": (payload) => {
|
|
6248
6594
|
const { agentId: rawId, refresh } = obj(payload, "payload");
|
|
6249
|
-
|
|
6595
|
+
const id = agentId(rawId);
|
|
6596
|
+
return refresh === true ? models.refresh(id) : models.get(id);
|
|
6250
6597
|
},
|
|
6251
6598
|
// A task does not exist yet when a project is picked, so these two are the
|
|
6252
6599
|
// ones that must take a path. They only inspect or `git init` it.
|
|
@@ -6260,8 +6607,8 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6260
6607
|
"projects:listRecent": () => listRecentProjects(getStore()),
|
|
6261
6608
|
// `vibeflow open <path>` while a host runs: only the host writes the store.
|
|
6262
6609
|
"projects:record": (projectPath) => {
|
|
6263
|
-
const p =
|
|
6264
|
-
if (!
|
|
6610
|
+
const p = path22.resolve(str(projectPath, "projectPath"));
|
|
6611
|
+
if (!fs18.existsSync(p) || !fs18.statSync(p).isDirectory()) invalid(`not a directory: ${p}`);
|
|
6265
6612
|
recordRecentProject(getStore(), p);
|
|
6266
6613
|
return listRecentProjects(getStore());
|
|
6267
6614
|
},
|
|
@@ -6312,7 +6659,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6312
6659
|
if (!task.baseBranch) throw new Error("\u4EFB\u52D9\u6C92\u6709\u8A18\u9304 base branch\uFF0C\u7121\u6CD5\u9084\u539F worktree");
|
|
6313
6660
|
await teardownTask(task.id);
|
|
6314
6661
|
await resetWorktreeToBase(task.worktreePath, task.baseBranch);
|
|
6315
|
-
const workspacePath = task.workspacePath ??
|
|
6662
|
+
const workspacePath = task.workspacePath ?? path22.dirname(task.worktreePath);
|
|
6316
6663
|
deleteArtifacts(workspacePath, task.worktreePath);
|
|
6317
6664
|
deleteDecisions(workspacePath, decisionsKey(task.worktreePath, task.branch));
|
|
6318
6665
|
resetSubAgents(task.worktreePath);
|
|
@@ -6336,6 +6683,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6336
6683
|
if (columnOf(existing.id) !== "backlog") {
|
|
6337
6684
|
throw new Error("\u53EA\u6709 Backlog \u7684\u4EFB\u52D9\u53EF\u4EE5\u7DE8\u8F2F");
|
|
6338
6685
|
}
|
|
6686
|
+
if (p.effort !== void 0 && !AGENT_EFFORTS.includes(p.effort)) invalid("unknown effort");
|
|
6339
6687
|
let gitPatch = {};
|
|
6340
6688
|
const nextProject = p.projectPath || existing.projectPath;
|
|
6341
6689
|
const nextBranch = p.branch === void 0 ? "" : str(p.branch, "branch").trim();
|
|
@@ -6355,7 +6703,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6355
6703
|
}
|
|
6356
6704
|
const info = await getGitInfo(nextProject);
|
|
6357
6705
|
if (!info.isRepo) throw new Error("\u76EE\u6A19\u8CC7\u6599\u593E\u4E0D\u662F git repository");
|
|
6358
|
-
const projectName =
|
|
6706
|
+
const projectName = path22.basename(nextProject);
|
|
6359
6707
|
const workspacePath = projectWorkstationPath(resolveWorkstationPath(getSettings()), projectName);
|
|
6360
6708
|
await teardownTask(existing.id);
|
|
6361
6709
|
await removeTaskWorktree(existing);
|
|
@@ -6449,7 +6797,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6449
6797
|
"claude:sessionExists": (taskId) => {
|
|
6450
6798
|
const task = requireTask(taskId);
|
|
6451
6799
|
if (!task.worktreePath) return false;
|
|
6452
|
-
return
|
|
6800
|
+
return fs18.existsSync(claudeSessionFile(task.worktreePath, executorSessionId(task.id, task.runId)));
|
|
6453
6801
|
},
|
|
6454
6802
|
"sessions:list": async () => {
|
|
6455
6803
|
const keys = await sessions.list();
|
|
@@ -6496,7 +6844,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6496
6844
|
const task = requireTask(taskId);
|
|
6497
6845
|
if (!task.worktreePath || !task.workspacePath) return "task has no worktree";
|
|
6498
6846
|
const dir = agentArtifactsPath(task.workspacePath, task.worktreePath);
|
|
6499
|
-
if (!
|
|
6847
|
+
if (!fs18.existsSync(dir)) return "artifacts directory does not exist yet";
|
|
6500
6848
|
return getPlatform().openPath(dir);
|
|
6501
6849
|
},
|
|
6502
6850
|
"task:getSpecs": async (taskId) => {
|
|
@@ -6630,7 +6978,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6630
6978
|
}
|
|
6631
6979
|
await removeTaskWorktree(task);
|
|
6632
6980
|
if (task.workspacePath) {
|
|
6633
|
-
|
|
6981
|
+
fs18.rmSync(taskAttachmentStagingPath(task.workspacePath, task.id), { recursive: true, force: true });
|
|
6634
6982
|
}
|
|
6635
6983
|
clearConversation(task.id);
|
|
6636
6984
|
removeTask(task.id);
|
|
@@ -6683,9 +7031,9 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6683
7031
|
// Watch the containing directory, not the file: JsonStore renames a temp
|
|
6684
7032
|
// file over the target and so replaces the inode on every save.
|
|
6685
7033
|
watchStore() {
|
|
6686
|
-
const file =
|
|
7034
|
+
const file = path22.basename(getStorePath());
|
|
6687
7035
|
let debounce = null;
|
|
6688
|
-
storeWatcher =
|
|
7036
|
+
storeWatcher = fs18.watch(path22.dirname(getStorePath()), (_event, filename) => {
|
|
6689
7037
|
if (filename !== file) return;
|
|
6690
7038
|
if (debounce) clearTimeout(debounce);
|
|
6691
7039
|
debounce = setTimeout(() => {
|
|
@@ -6697,6 +7045,9 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6697
7045
|
});
|
|
6698
7046
|
return () => storeWatcher?.close();
|
|
6699
7047
|
},
|
|
7048
|
+
warmModelCatalog() {
|
|
7049
|
+
models.warm();
|
|
7050
|
+
},
|
|
6700
7051
|
shutdown() {
|
|
6701
7052
|
sessions.shutdown();
|
|
6702
7053
|
cancelAllChatSends();
|
|
@@ -6718,9 +7069,9 @@ function createSessionBackend(sink, choice) {
|
|
|
6718
7069
|
}
|
|
6719
7070
|
|
|
6720
7071
|
// packages/core/src/web-server.ts
|
|
6721
|
-
import
|
|
7072
|
+
import fs19 from "fs";
|
|
6722
7073
|
import http from "http";
|
|
6723
|
-
import
|
|
7074
|
+
import path23 from "path";
|
|
6724
7075
|
import { timingSafeEqual } from "crypto";
|
|
6725
7076
|
import { WebSocketServer } from "ws";
|
|
6726
7077
|
var TOKEN_COOKIE = "vf_token";
|
|
@@ -6773,14 +7124,14 @@ function resolveStatic(root, urlPath) {
|
|
|
6773
7124
|
return null;
|
|
6774
7125
|
}
|
|
6775
7126
|
if (decoded.includes("\0")) return null;
|
|
6776
|
-
const rel =
|
|
6777
|
-
const base2 =
|
|
6778
|
-
const candidates = [rel,
|
|
7127
|
+
const rel = path23.posix.normalize(decoded).replace(/^\/+/, "");
|
|
7128
|
+
const base2 = path23.resolve(root);
|
|
7129
|
+
const candidates = [rel, path23.posix.join(rel, "index.html"), `${rel}.html`];
|
|
6779
7130
|
for (const c of candidates) {
|
|
6780
|
-
const full =
|
|
6781
|
-
if (full !== base2 && !full.startsWith(base2 +
|
|
7131
|
+
const full = path23.resolve(base2, c);
|
|
7132
|
+
if (full !== base2 && !full.startsWith(base2 + path23.sep)) return null;
|
|
6782
7133
|
try {
|
|
6783
|
-
if (
|
|
7134
|
+
if (fs19.statSync(full).isFile()) return full;
|
|
6784
7135
|
} catch {
|
|
6785
7136
|
}
|
|
6786
7137
|
}
|
|
@@ -6841,7 +7192,7 @@ async function startWebServer(options) {
|
|
|
6841
7192
|
send(res, 404, "Not found");
|
|
6842
7193
|
return;
|
|
6843
7194
|
}
|
|
6844
|
-
const ext =
|
|
7195
|
+
const ext = path23.extname(file).toLowerCase();
|
|
6845
7196
|
const immutable = url.pathname.startsWith("/_next/static/");
|
|
6846
7197
|
res.writeHead(200, {
|
|
6847
7198
|
"Content-Type": CONTENT_TYPES[ext] ?? "application/octet-stream",
|
|
@@ -6854,7 +7205,7 @@ async function startWebServer(options) {
|
|
|
6854
7205
|
res.end();
|
|
6855
7206
|
return;
|
|
6856
7207
|
}
|
|
6857
|
-
|
|
7208
|
+
fs19.createReadStream(file).pipe(res);
|
|
6858
7209
|
}
|
|
6859
7210
|
const wss = new WebSocketServer({ noServer: true, maxPayload: MAX_PAYLOAD });
|
|
6860
7211
|
function reject(socket, status, reason) {
|
|
@@ -7018,6 +7369,7 @@ async function startHost(options) {
|
|
|
7018
7369
|
lock.port = server.port;
|
|
7019
7370
|
updateLock(options.userDataDir, lock);
|
|
7020
7371
|
const stopWatch = core.watchStore();
|
|
7372
|
+
core.warmModelCatalog();
|
|
7021
7373
|
const stop = () => stopping ??= (async () => {
|
|
7022
7374
|
stopWatch();
|
|
7023
7375
|
core.shutdown();
|
|
@@ -7034,7 +7386,7 @@ function loginUrl(lock, pathname = "/home/") {
|
|
|
7034
7386
|
return `http://127.0.0.1:${lock.port}${pathname}?token=${encodeURIComponent(lock.token)}`;
|
|
7035
7387
|
}
|
|
7036
7388
|
function isWebDir(dir) {
|
|
7037
|
-
return
|
|
7389
|
+
return fs20.existsSync(path24.join(dir, "home", "index.html"));
|
|
7038
7390
|
}
|
|
7039
7391
|
|
|
7040
7392
|
// packages/cli/src/remote.ts
|
|
@@ -7151,14 +7503,14 @@ function connectToHost(lock) {
|
|
|
7151
7503
|
}
|
|
7152
7504
|
|
|
7153
7505
|
// packages/cli/src/doctor.ts
|
|
7154
|
-
import
|
|
7155
|
-
import
|
|
7156
|
-
import { execFile as
|
|
7157
|
-
import { promisify as
|
|
7506
|
+
import fs21 from "fs";
|
|
7507
|
+
import path25 from "path";
|
|
7508
|
+
import { execFile as execFile8 } from "child_process";
|
|
7509
|
+
import { promisify as promisify5 } from "util";
|
|
7158
7510
|
init_env();
|
|
7159
7511
|
init_git_bash();
|
|
7160
7512
|
init_tmux_backend();
|
|
7161
|
-
var
|
|
7513
|
+
var pexec5 = promisify5(execFile8);
|
|
7162
7514
|
function parseVersion(text) {
|
|
7163
7515
|
const m = /(\d+)\.(\d+)(?:\.(\d+))?/.exec(text);
|
|
7164
7516
|
return m ? [Number(m[1]), Number(m[2]), Number(m[3] ?? 0)] : [];
|
|
@@ -7172,7 +7524,7 @@ function versionAtLeast(have, want) {
|
|
|
7172
7524
|
}
|
|
7173
7525
|
async function run2(cmd, args) {
|
|
7174
7526
|
try {
|
|
7175
|
-
const { stdout } = await
|
|
7527
|
+
const { stdout } = await pexec5(cmd, args, { env: execEnv(), timeout: 1e4, windowsHide: true });
|
|
7176
7528
|
return String(stdout).trim();
|
|
7177
7529
|
} catch {
|
|
7178
7530
|
return null;
|
|
@@ -7292,10 +7644,10 @@ async function runDoctor(options) {
|
|
|
7292
7644
|
});
|
|
7293
7645
|
}
|
|
7294
7646
|
try {
|
|
7295
|
-
|
|
7296
|
-
const probe =
|
|
7297
|
-
|
|
7298
|
-
|
|
7647
|
+
fs21.mkdirSync(options.userDataDir, { recursive: true });
|
|
7648
|
+
const probe = path25.join(options.userDataDir, `.doctor-${process.pid}`);
|
|
7649
|
+
fs21.writeFileSync(probe, "");
|
|
7650
|
+
fs21.rmSync(probe);
|
|
7299
7651
|
checks.push({ id: "data", name: "\u8CC7\u6599\u76EE\u9304", level: "ok", detail: options.userDataDir });
|
|
7300
7652
|
} catch (err) {
|
|
7301
7653
|
checks.push({
|
|
@@ -7349,24 +7701,24 @@ Options:
|
|
|
7349
7701
|
`.trim();
|
|
7350
7702
|
function detectLayout() {
|
|
7351
7703
|
const file = fileURLToPath(import.meta.url);
|
|
7352
|
-
const here =
|
|
7353
|
-
const bundledWeb =
|
|
7354
|
-
if (isWebDir(bundledWeb) ||
|
|
7704
|
+
const here = path28.dirname(file);
|
|
7705
|
+
const bundledWeb = path28.join(here, "web");
|
|
7706
|
+
if (isWebDir(bundledWeb) || path28.basename(here) === "dist") {
|
|
7355
7707
|
return {
|
|
7356
|
-
version: readVersion(
|
|
7708
|
+
version: readVersion(path28.join(here, "..", "package.json")),
|
|
7357
7709
|
webDir: isWebDir(bundledWeb) ? bundledWeb : null,
|
|
7358
7710
|
sourceRoot: null,
|
|
7359
7711
|
cliEntry: file
|
|
7360
7712
|
};
|
|
7361
7713
|
}
|
|
7362
|
-
const root =
|
|
7714
|
+
const root = path28.resolve(here, "..", "..", "..");
|
|
7363
7715
|
const override = process.env.VIBEFLOW_WEB_DIR;
|
|
7364
|
-
const webDir = override && isWebDir(override) ? override : isWebDir(
|
|
7365
|
-
return { version: readVersion(
|
|
7716
|
+
const webDir = override && isWebDir(override) ? override : isWebDir(path28.join(root, "app")) ? path28.join(root, "app") : null;
|
|
7717
|
+
return { version: readVersion(path28.join(root, "package.json")), webDir, sourceRoot: root, cliEntry: null };
|
|
7366
7718
|
}
|
|
7367
7719
|
function readVersion(pkgPath) {
|
|
7368
7720
|
try {
|
|
7369
|
-
return JSON.parse(
|
|
7721
|
+
return JSON.parse(fs23.readFileSync(pkgPath, "utf8")).version;
|
|
7370
7722
|
} catch {
|
|
7371
7723
|
return "0.0.0";
|
|
7372
7724
|
}
|
|
@@ -7572,8 +7924,8 @@ async function cmdOpen(values, target, layout, userDataDir) {
|
|
|
7572
7924
|
console.error("\u7528\u6CD5\uFF1Avibeflow open <path>");
|
|
7573
7925
|
return 1;
|
|
7574
7926
|
}
|
|
7575
|
-
const dir =
|
|
7576
|
-
if (!
|
|
7927
|
+
const dir = path28.resolve(target);
|
|
7928
|
+
if (!fs23.existsSync(dir) || !fs23.statSync(dir).isDirectory()) {
|
|
7577
7929
|
console.error(`\u4E0D\u662F\u8CC7\u6599\u593E\uFF1A${dir}`);
|
|
7578
7930
|
return 1;
|
|
7579
7931
|
}
|