@kw-yeh/vibeflow 4.11.14 → 4.11.16

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