openfox 2.0.113 → 2.0.114

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.
Files changed (94) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/CHANGELOG.md +22 -0
  3. package/dist/agent-defaults/builder.agent.md +1 -0
  4. package/dist/agent-defaults/planner.agent.md +1 -0
  5. package/dist/{backend-P3GHHLHJ.js → backend-LVYHLGQJ.js} +2 -2
  6. package/dist/{chat-handler-PEK5JDHO.js → chat-handler-KWXRSWXZ.js} +31 -25
  7. package/dist/{chunk-HKD4IMOE.js → chunk-2XD65L7M.js} +2 -2
  8. package/dist/{chunk-AZFZE36I.js → chunk-3O77NT4T.js} +17 -7
  9. package/dist/{chunk-HGOTZWON.js → chunk-7GWARYQC.js} +60 -1064
  10. package/dist/{chunk-YHEQTVFV.js → chunk-AZHWLLPP.js} +1 -1
  11. package/dist/{chunk-6UPBZ2ZR.js → chunk-BZVW77PI.js} +4 -4
  12. package/dist/{chunk-YGPPFVLJ.js → chunk-FW4NDUBL.js} +15 -15
  13. package/dist/{chunk-O2YSYW2F.js → chunk-GUHHUDNL.js} +6 -6
  14. package/dist/{chunk-WWTYWLDM.js → chunk-HP5CIB66.js} +2 -2
  15. package/dist/{chunk-ONONXV3N.js → chunk-HV6IALXF.js} +4 -4
  16. package/dist/{chunk-4NMGX5F2.js → chunk-I7FY2LTR.js} +2 -2
  17. package/dist/{chunk-Y64PEWKP.js → chunk-JP7NM545.js} +2 -2
  18. package/dist/{chunk-CP44U7BT.js → chunk-JXLRL5JR.js} +5 -5
  19. package/dist/{chunk-5VYSKVZT.js → chunk-K733B5T2.js} +254 -20
  20. package/dist/{chunk-SNLLOXCM.js → chunk-L63Q4JQJ.js} +3 -3
  21. package/dist/{chunk-43M7QZMX.js → chunk-LXYPMFTH.js} +3 -3
  22. package/dist/{chunk-TCGWZBTS.js → chunk-MUSPWEBB.js} +3 -3
  23. package/dist/chunk-NCZRWCJN.js +7 -0
  24. package/dist/{chunk-JR54MDZI.js → chunk-NLO64UE3.js} +2 -2
  25. package/dist/{chunk-3R43CMLS.js → chunk-NWJLWLKF.js} +8 -8
  26. package/dist/chunk-OSXPQSLW.js +128 -0
  27. package/dist/chunk-OTYAEEX3.js +1081 -0
  28. package/dist/{chunk-V4664YKR.js → chunk-OXSTNSCF.js} +2 -2
  29. package/dist/{chunk-R2MTWC7C.js → chunk-P5UANBBX.js} +6 -4
  30. package/dist/{chunk-PWXBIUEY.js → chunk-PBW3YC3G.js} +85 -1
  31. package/dist/{chunk-TEQEDOWI.js → chunk-QD7MRMCH.js} +245 -289
  32. package/dist/{chunk-BNFGDTEU.js → chunk-SA34STZ6.js} +2 -2
  33. package/dist/{chunk-VGRVPYZ5.js → chunk-SBSUDHL4.js} +2 -2
  34. package/dist/{chunk-XQR76MQ5.js → chunk-SFZGMB2G.js} +2 -2
  35. package/dist/{chunk-EC5T5A6O.js → chunk-TKKP56QK.js} +3 -3
  36. package/dist/{chunk-BYSUSSSC.js → chunk-UPBWEHIL.js} +30 -148
  37. package/dist/{chunk-YB6WYVNY.js → chunk-UTIQ7OO5.js} +2 -2
  38. package/dist/{chunk-EMI3YYLP.js → chunk-VPVLO436.js} +4 -4
  39. package/dist/chunk-W77NBJAZ.js +957 -0
  40. package/dist/{chunk-BKCW3JLL.js → chunk-X25Q6RAV.js} +1 -1
  41. package/dist/{chunk-FF2EKUQO.js → chunk-YGJIK3CG.js} +4 -4
  42. package/dist/cli/dev.js +1 -1
  43. package/dist/cli/index.js +1 -1
  44. package/dist/{client-3LJGD6KY.js → client-EM7ISGUP.js} +6 -6
  45. package/dist/{compactor-ZBNKANHV.js → compactor-V3LR7APW.js} +13 -12
  46. package/dist/{dynamic-context-F2XTQJR5.js → dynamic-context-MVGOF5V2.js} +10 -9
  47. package/dist/{events-224IO5NJ.js → events-PI7IMPHT.js} +8 -7
  48. package/dist/{folding-YTTTVS56.js → folding-FO57K4JM.js} +6 -5
  49. package/dist/http-client-33EZ3BLR.js +11 -0
  50. package/dist/{inspect-proxy-B7LGGTM7.js → inspect-proxy-NHKQQ2CD.js} +4 -4
  51. package/dist/launch-L5ROVNI3.js +52 -0
  52. package/dist/{manager-4QGXI6WZ.js → manager-66YAEO7K.js} +5 -5
  53. package/dist/{model-overrides-OY2YKUNV.js → model-overrides-L53PZNZA.js} +4 -4
  54. package/dist/orchestrator-XK5K3RPL.js +63 -0
  55. package/dist/package.json +3 -3
  56. package/dist/{path-security-PFMZY7IA.js → path-security-RSEI3YKB.js} +12 -11
  57. package/dist/{platform-QNGCKX4L.js → platform-WA4GK5BO.js} +4 -4
  58. package/dist/{processor-NYPJ5PFA.js → processor-WDZSFBVO.js} +30 -24
  59. package/dist/{project-creator-AWP2JUFS.js → project-creator-676WQXVI.js} +3 -3
  60. package/dist/{projects-C4353IQK.js → projects-SSBWIYL4.js} +3 -3
  61. package/dist/{protocol-CBT1d98i.d.ts → protocol-BzHs024-.d.ts} +21 -3
  62. package/dist/{protocol-LZZ7C4VQ.js → protocol-RKSWKNXI.js} +3 -3
  63. package/dist/provider/index.d.ts +4 -4
  64. package/dist/{provider-PIRPN2CC.js → provider-PLIWRBCF.js} +7 -7
  65. package/dist/{provider-manager-GNEPR6UN.js → provider-manager-2QSJTPWS.js} +7 -7
  66. package/dist/{registry-VCKDSVKA.js → registry-ZP4TN2IN.js} +5 -4
  67. package/dist/{serve-6DRHQLCG.js → serve-MZ3BCCWC.js} +35 -32
  68. package/dist/server/index.d.ts +4 -4
  69. package/dist/server/index.js +34 -31
  70. package/dist/server-EPXODFMB.js +55 -0
  71. package/dist/service-54PGIPDQ.js +25 -0
  72. package/dist/{session-overrides-RNKV35MU.js → session-overrides-LXN6W7SA.js} +7 -6
  73. package/dist/{sessions-D5CEPQGU.js → sessions-CHPVUG6H.js} +6 -5
  74. package/dist/{settings-BNRNX6IW.js → settings-NEBM3GQX.js} +3 -3
  75. package/dist/shared/index.d.ts +3 -3
  76. package/dist/shared/index.js +1 -1
  77. package/dist/skill-defaults/workflows/SKILL.md +24 -6
  78. package/dist/tasks-TJXG2V3U.js +217 -0
  79. package/dist/{tools-2B363F7L.js → tools-CIM26IFB.js} +30 -22
  80. package/dist/{types-BAxh20ZL.d.ts → types-CMtHpDWT.d.ts} +74 -1
  81. package/dist/{types-cVfqOj6M.d.ts → types-CbggXFvR.d.ts} +1 -1
  82. package/dist/{update-IQMRYN7J.js → update-UZBBO42X.js} +2 -2
  83. package/dist/web/assets/{index-CjWC6EQ4.css → index-BmILAZrT.css} +1 -1
  84. package/dist/web/assets/index-rZHXkfMq.js +324 -0
  85. package/dist/web/index.html +2 -2
  86. package/dist/web/sw.js +1 -1
  87. package/dist/workflow-defaults/default.workflow.json +5 -3
  88. package/dist/{workspace-YUNHV4WS.js → workspace-2XODU4YJ.js} +4 -4
  89. package/package.json +3 -3
  90. package/dist/chunk-B2PHPBFU.js +0 -7
  91. package/dist/http-client-YC3UA5OZ.js +0 -11
  92. package/dist/orchestrator-JKBY7B3P.js +0 -57
  93. package/dist/server-HUHFJW7U.js +0 -48
  94. package/dist/web/assets/index-DBUtUSHK.js +0 -323
@@ -2,46 +2,37 @@ import {
2
2
  generateSessionNameForSession,
3
3
  getSessionMessageCount,
4
4
  needsNameGeneration
5
- } from "./chunk-3R43CMLS.js";
5
+ } from "./chunk-NWJLWLKF.js";
6
+ import {
7
+ launchWorkflowRun
8
+ } from "./chunk-W77NBJAZ.js";
6
9
  import {
7
- runAgentTurn,
8
10
  runChatTurn
9
- } from "./chunk-YGPPFVLJ.js";
11
+ } from "./chunk-FW4NDUBL.js";
12
+ import {
13
+ devServerManager
14
+ } from "./chunk-K733B5T2.js";
10
15
  import {
11
16
  applyDynamicContext,
12
17
  computeSessionHash,
13
18
  computeUnifiedDiff
14
- } from "./chunk-O2YSYW2F.js";
19
+ } from "./chunk-GUHHUDNL.js";
15
20
  import {
16
21
  appendCompactionPrompt
17
- } from "./chunk-EMI3YYLP.js";
18
- import {
19
- devServerManager,
20
- executeSubAgent,
21
- getToolRegistryForAgent
22
- } from "./chunk-5VYSKVZT.js";
22
+ } from "./chunk-VPVLO436.js";
23
23
  import {
24
- TurnMetrics,
25
- createMessageStartEvent
26
- } from "./chunk-JR54MDZI.js";
24
+ onProcessEvent
25
+ } from "./chunk-TKKP56QK.js";
27
26
  import {
28
- checkAborted,
29
- decodeUtf8,
30
- onProcessEvent,
31
- spawnShellProcess
32
- } from "./chunk-EC5T5A6O.js";
33
- import {
34
- killProcessTree,
35
- terminateProcessTree
27
+ killProcessTree
36
28
  } from "./chunk-I72ACQ6R.js";
37
29
  import {
38
30
  gitSpawnEnv
39
31
  } from "./chunk-J7GAZGZT.js";
40
32
  import {
41
33
  combineEventsWithSnapshot,
42
- getCurrentContextWindowId,
43
34
  getEventStore
44
- } from "./chunk-CP44U7BT.js";
35
+ } from "./chunk-JXLRL5JR.js";
45
36
  import {
46
37
  createChatErrorMessage,
47
38
  createChatMessageMessage,
@@ -56,10 +47,10 @@ import {
56
47
  parseClientMessage,
57
48
  serializeServerMessage,
58
49
  storedEventToServerMessage
59
- } from "./chunk-4NMGX5F2.js";
50
+ } from "./chunk-I7FY2LTR.js";
60
51
  import {
61
52
  getPlatformShell
62
- } from "./chunk-BNFGDTEU.js";
53
+ } from "./chunk-SA34STZ6.js";
63
54
  import {
64
55
  getPendingQuestionsForSession,
65
56
  provideAnswer
@@ -67,35 +58,23 @@ import {
67
58
  import {
68
59
  buildMessagesFromStoredEvents,
69
60
  foldPendingConfirmations
70
- } from "./chunk-YB6WYVNY.js";
61
+ } from "./chunk-UTIQ7OO5.js";
71
62
  import {
72
- deleteItemFromDir,
73
- findAgentById,
74
- getRuntimeConfig,
75
- jsonSerializer,
76
- loadAllAgentsDefault,
77
- resolveDefaultAgentId,
78
- saveItemToDir
79
- } from "./chunk-BYSUSSSC.js";
63
+ getRuntimeConfig
64
+ } from "./chunk-UPBWEHIL.js";
80
65
  import {
81
66
  getMaxVisibleItems
82
- } from "./chunk-WWTYWLDM.js";
67
+ } from "./chunk-HP5CIB66.js";
83
68
  import {
84
69
  logger
85
70
  } from "./chunk-K44MW7JJ.js";
86
- import {
87
- computeSessionStats
88
- } from "./chunk-VUQCQXXJ.js";
89
71
  import {
90
72
  createServerMessage
91
- } from "./chunk-BKCW3JLL.js";
92
- import {
93
- getGlobalConfigDir
94
- } from "./chunk-CQGTEGKL.js";
73
+ } from "./chunk-X25Q6RAV.js";
95
74
 
96
75
  // src/server/ws/server.ts
97
76
  import { WebSocketServer, WebSocket as WebSocket2 } from "ws";
98
- import { spawn as spawn3 } from "child_process";
77
+ import { spawn as spawn2 } from "child_process";
99
78
  import { createHash as createHash2 } from "crypto";
100
79
 
101
80
  // src/server/ws/terminal.ts
@@ -351,943 +330,17 @@ function unsubscribeAllFromTerminal(ws) {
351
330
  }
352
331
  }
353
332
 
354
- // src/server/workflows/registry.ts
355
- import { readdir, readFile, writeFile, mkdir, access, unlink } from "fs/promises";
356
- import { join, dirname } from "path";
357
- import { constants } from "fs";
358
- import { fileURLToPath } from "url";
359
- var __bundleDir = dirname(fileURLToPath(import.meta.url));
360
- var DEFAULTS_DIR = join(__bundleDir, "defaults");
361
- var DEFAULTS_DIR_ALT = join(__bundleDir, "workflow-defaults");
362
- var WORKFLOW_EXTENSION = ".workflow.json";
363
- function normalizeWorkflowScope(value) {
364
- return typeof value === "string" && (value === "builtin" || value === "user" || value === "project" || value === "auto") ? value : "auto";
365
- }
366
- function getWorkflowsDir(configDir) {
367
- return join(configDir, "workflows");
368
- }
369
- function getProjectWorkflowsDir(projectDir) {
370
- return join(projectDir, ".openfox", "workflows");
371
- }
372
- async function pathExists(path) {
373
- try {
374
- await access(path, constants.R_OK);
375
- return true;
376
- } catch {
377
- return false;
378
- }
379
- }
380
- async function loadWorkflowsFromDir(dir) {
381
- if (!await pathExists(dir)) {
382
- return [];
383
- }
384
- let files;
385
- try {
386
- files = (await readdir(dir)).filter((f) => f.endsWith(WORKFLOW_EXTENSION));
387
- } catch {
388
- return [];
389
- }
390
- const workflows = [];
391
- for (const file of files) {
392
- try {
393
- const raw = await readFile(join(dir, file), "utf-8");
394
- const parsed = JSON.parse(raw);
395
- if (parsed.metadata?.id && parsed.steps?.length > 0) {
396
- workflows.push(parsed);
397
- } else {
398
- logger.warn("Skipping invalid workflow file", { file });
399
- }
400
- } catch (err) {
401
- logger.warn("Failed to parse workflow file", { file, error: err instanceof Error ? err.message : String(err) });
402
- }
403
- }
404
- return workflows;
405
- }
406
- async function loadDefaultWorkflows() {
407
- let defaults = await loadWorkflowsFromDir(DEFAULTS_DIR);
408
- if (!defaults.length) {
409
- defaults = await loadWorkflowsFromDir(DEFAULTS_DIR_ALT);
410
- }
411
- return defaults;
412
- }
413
- async function loadUserWorkflows(configDir) {
414
- return loadWorkflowsFromDir(getWorkflowsDir(configDir));
415
- }
416
- async function loadProjectWorkflows(projectDir) {
417
- return loadWorkflowsFromDir(getProjectWorkflowsDir(projectDir));
418
- }
419
- async function loadAllWorkflows(configDir, projectDir) {
420
- const [defaultWorkflows, userWorkflows] = await Promise.all([loadDefaultWorkflows(), loadUserWorkflows(configDir)]);
421
- const workflowMap = /* @__PURE__ */ new Map();
422
- for (const workflow of defaultWorkflows) {
423
- workflowMap.set(workflow.metadata.id, workflow);
424
- }
425
- for (const workflow of userWorkflows) {
426
- workflowMap.set(workflow.metadata.id, workflow);
427
- }
428
- if (projectDir) {
429
- const projectWorkflows = await loadProjectWorkflows(projectDir);
430
- for (const workflow of projectWorkflows) {
431
- workflowMap.set(workflow.metadata.id, workflow);
432
- }
433
- }
434
- return Array.from(workflowMap.values());
435
- }
436
- async function saveWorkflowToProject(projectDir, workflow) {
437
- await saveItemToDir(getProjectWorkflowsDir(projectDir), workflow, WORKFLOW_EXTENSION, jsonSerializer);
438
- }
439
- async function deleteProjectWorkflow(projectDir, workflowId) {
440
- return deleteItemFromDir(getProjectWorkflowsDir(projectDir), workflowId, WORKFLOW_EXTENSION);
441
- }
442
- async function getDefaultWorkflowIds() {
443
- for (const dir of [DEFAULTS_DIR, DEFAULTS_DIR_ALT]) {
444
- try {
445
- const files = (await readdir(dir)).filter((f) => f.endsWith(WORKFLOW_EXTENSION));
446
- return files.map((f) => f.replace(WORKFLOW_EXTENSION, ""));
447
- } catch {
448
- }
449
- }
450
- return [];
451
- }
452
- async function isDefaultWorkflow(workflowId) {
453
- const defaultIds = await getDefaultWorkflowIds();
454
- return defaultIds.includes(workflowId);
455
- }
456
- function findWorkflowById(workflowId, workflows) {
457
- return workflows.find((p) => p.metadata.id === workflowId);
458
- }
459
- async function workflowExists(configDir, workflowId, projectDir) {
460
- if (await pathExists(join(getWorkflowsDir(configDir), `${workflowId}${WORKFLOW_EXTENSION}`))) return true;
461
- if (projectDir && await pathExists(join(getProjectWorkflowsDir(projectDir), `${workflowId}${WORKFLOW_EXTENSION}`)))
462
- return true;
463
- return false;
464
- }
465
- async function saveWorkflow(configDir, workflow) {
466
- const workflowsDir = getWorkflowsDir(configDir);
467
- if (!await pathExists(workflowsDir)) {
468
- await mkdir(workflowsDir, { recursive: true });
469
- }
470
- const filePath = join(workflowsDir, `${workflow.metadata.id}${WORKFLOW_EXTENSION}`);
471
- await writeFile(filePath, JSON.stringify(workflow, null, 2) + "\n", "utf-8");
472
- }
473
- async function deleteWorkflow(configDir, workflowId) {
474
- const isDefault = await isDefaultWorkflow(workflowId);
475
- if (isDefault) {
476
- return { success: false, reason: "Cannot delete built-in defaults" };
477
- }
478
- const filePath = join(getWorkflowsDir(configDir), `${workflowId}${WORKFLOW_EXTENSION}`);
479
- try {
480
- await unlink(filePath);
481
- return { success: true };
482
- } catch {
483
- return { success: false };
484
- }
485
- }
486
-
487
- // src/server/workflows/types.ts
488
- var TERMINAL_DONE = "$done";
489
- var TERMINAL_BLOCKED = "$blocked";
490
-
491
- // src/server/git/diff.ts
492
- import { spawn as spawn2 } from "child_process";
493
- function getGitDiffFiles(cwd) {
494
- return new Promise((resolve) => {
495
- const env = gitSpawnEnv();
496
- const diffProc = spawn2("git", ["diff", "--name-status", "HEAD"], {
497
- cwd,
498
- env,
499
- stdio: ["ignore", "pipe", "pipe"],
500
- windowsHide: true
501
- });
502
- const statusProc = spawn2("git", ["status", "--porcelain"], {
503
- cwd,
504
- env,
505
- stdio: ["ignore", "pipe", "pipe"],
506
- windowsHide: true
507
- });
508
- let diffStdout = "";
509
- let statusStdout = "";
510
- let diffExited = false;
511
- let statusExited = false;
512
- let diffCode = null;
513
- let statusCode = null;
514
- const collect = () => {
515
- if (!diffExited || !statusExited) return;
516
- const files = [];
517
- if (diffCode === 0) {
518
- for (const line of diffStdout.split("\n")) {
519
- if (!line.trim()) continue;
520
- const [statusChar, ...pathParts] = line.split(" ");
521
- const path = pathParts.join(" ") || statusChar || "";
522
- if (!path) continue;
523
- const status = statusChar === "A" ? "added" : statusChar === "D" ? "deleted" : "modified";
524
- files.push({ path, status, additions: 0, deletions: 0 });
525
- }
526
- }
527
- if (statusCode === 0) {
528
- for (const line of statusStdout.split("\n")) {
529
- if (!line.startsWith("?? ")) continue;
530
- const path = line.slice(3).trim();
531
- if (!path) continue;
532
- files.push({ path, status: "added", additions: 0, deletions: 0 });
533
- }
534
- }
535
- resolve(files);
536
- };
537
- diffProc.stdout.on("data", (data) => {
538
- diffStdout += data.toString();
539
- });
540
- statusProc.stdout.on("data", (data) => {
541
- statusStdout += data.toString();
542
- });
543
- diffProc.on("close", (code) => {
544
- diffExited = true;
545
- diffCode = code;
546
- collect();
547
- });
548
- statusProc.on("close", (code) => {
549
- statusExited = true;
550
- statusCode = code;
551
- collect();
552
- });
553
- diffProc.on("error", () => {
554
- diffExited = true;
555
- diffCode = 1;
556
- collect();
557
- });
558
- statusProc.on("error", () => {
559
- statusExited = true;
560
- statusCode = 1;
561
- collect();
562
- });
563
- });
564
- }
565
- async function formatGitDiffFiles(cwd) {
566
- const files = await getGitDiffFiles(cwd);
567
- if (files.length === 0) return "(none)";
568
- return files.map((f) => `- ${f.path} (${f.status})`).join("\n");
569
- }
570
-
571
- // src/server/workflows/shell.ts
572
- function executeShellCommand(command, cwd, timeout, signal) {
573
- return new Promise((resolve, reject) => {
574
- if (checkAborted(signal)) {
575
- reject(new Error("Aborted"));
576
- return;
577
- }
578
- const proc = spawnShellProcess(command, cwd, signal);
579
- const stdoutChunks = [];
580
- const stderrChunks = [];
581
- let killed = false;
582
- const timer = setTimeout(() => {
583
- killed = true;
584
- void terminateProcessTree(proc);
585
- resolve({
586
- exitCode: 1,
587
- stdout: decodeUtf8(stdoutChunks),
588
- stderr: decodeUtf8(stderrChunks) + "\nCommand timed out",
589
- success: false
590
- });
591
- }, timeout);
592
- const onAbort = () => {
593
- if (!killed) {
594
- killed = true;
595
- void terminateProcessTree(proc, { immediate: true });
596
- clearTimeout(timer);
597
- reject(new Error("Aborted"));
598
- }
599
- };
600
- signal?.addEventListener("abort", onAbort);
601
- proc.stdout?.on("data", (data) => {
602
- stdoutChunks.push(data);
603
- });
604
- proc.stderr?.on("data", (data) => {
605
- stderrChunks.push(data);
606
- });
607
- proc.on("close", (code) => {
608
- clearTimeout(timer);
609
- signal?.removeEventListener("abort", onAbort);
610
- if (killed) return;
611
- const exitCode = code ?? 1;
612
- resolve({
613
- exitCode,
614
- stdout: decodeUtf8(stdoutChunks),
615
- stderr: decodeUtf8(stderrChunks),
616
- success: exitCode === 0
617
- });
618
- });
619
- proc.on("error", (err) => {
620
- clearTimeout(timer);
621
- signal?.removeEventListener("abort", onAbort);
622
- if (killed) return;
623
- resolve({ exitCode: 1, stdout: decodeUtf8(stdoutChunks), stderr: err.message, success: false });
624
- });
625
- });
626
- }
627
-
628
- // src/server/workflows/executor.ts
629
- var TEMPLATE_VARIABLES = [
630
- { name: "workdir", description: "Working directory of the session" },
631
- { name: "reason", description: 'Human-readable reason (e.g. "2 criteria remaining")' },
632
- {
633
- name: "stepOutput",
634
- description: "Structured output from the previous step (content, stdout, stderr, exitCode, etc.)"
635
- },
636
- {
637
- name: "verifierFindings",
638
- description: "@deprecated Use stepOutput.content instead. Output from the last sub-agent step"
639
- },
640
- {
641
- name: "previousStepOutput",
642
- description: "@deprecated Use stepOutput.stdout instead. Output from the last shell step"
643
- },
644
- { name: "criteriaCount", description: "Total number of criteria" },
645
- { name: "pendingCount", description: "Number of pending/failed criteria" },
646
- { name: "criteriaList", description: "Formatted list of all criteria with status" },
647
- { name: "modifiedFiles", description: "List of modified files" }
648
- ];
649
- function formatCriteriaList(entries) {
650
- if (entries.length === 0) return "(none)";
651
- return entries.map((e) => {
652
- const status = e.status === "passed" ? "[PASSED]" : e.status === "completed" ? "[NEEDS VERIFICATION]" : e.status === "failed" ? "[FAILED]" : "[NOT COMPLETED]";
653
- return `- **${e.id}** ${status}: ${e.description}`;
654
- }).join("\n");
655
- }
656
- async function formatModifiedFiles(workdir) {
657
- return formatGitDiffFiles(workdir);
658
- }
659
- function resolveTemplate(template, ctx) {
660
- let result = template;
661
- for (const { name } of TEMPLATE_VARIABLES) {
662
- if (name === "stepOutput" || name === "verifierFindings" || name === "previousStepOutput") continue;
663
- const value = String(ctx[name]);
664
- result = result.replace(new RegExp(`\\{\\{${name}\\}\\}`, "g"), value);
665
- }
666
- result = result.replace(/\{\{stepOutput\.(\w+)\}\}/g, (_, key) => ctx.stepOutput[key] ?? "");
667
- result = result.replace(/\{\{verifierFindings\}\}/g, ctx.stepOutput["content"] ?? "");
668
- result = result.replace(/\{\{previousStepOutput\}\}/g, ctx.stepOutput["stdout"] ?? "");
669
- for (const [key, value] of Object.entries(ctx.params)) {
670
- result = result.replaceAll(`{{${key}}}`, value);
671
- }
672
- return result;
673
- }
674
- function evaluateCondition(condition, stepOutcome, metadataEntries) {
675
- switch (condition.type) {
676
- case "step_result":
677
- if (!stepOutcome) return false;
678
- return stepOutcome.result === condition.result;
679
- case "metadata_all_match": {
680
- if (!metadataEntries) return false;
681
- const entries = metadataEntries[condition.key];
682
- if (!entries || entries.length === 0) return true;
683
- return entries.every((e) => e[condition.field] === condition.value);
684
- }
685
- case "metadata_all_in": {
686
- if (!metadataEntries) return false;
687
- const entries = metadataEntries[condition.key];
688
- if (!entries || entries.length === 0) return true;
689
- return entries.every((e) => condition.values.includes(e[condition.field]));
690
- }
691
- case "always":
692
- return true;
693
- }
694
- }
695
- function evaluateTransitions(transitions, stepOutcome, metadataEntries) {
696
- for (const transition of transitions) {
697
- if (evaluateCondition(transition.when, stepOutcome, metadataEntries)) {
698
- return transition.goto;
699
- }
700
- }
701
- return TERMINAL_BLOCKED;
702
- }
703
- var DEFAULT_USER_RESULT = "continue";
704
- var CONTINUE_CHOICE_ID = "continue";
705
- function userStepChoices(step) {
706
- const seen = /* @__PURE__ */ new Set();
707
- const choices = [];
708
- for (const t of step.transitions) {
709
- if (t.when.type === "step_result") {
710
- const id = t.when.result;
711
- if (seen.has(id)) continue;
712
- seen.add(id);
713
- choices.push({ id, label: id, goto: t.goto });
714
- } else if (t.when.type === "always") {
715
- if (seen.has(CONTINUE_CHOICE_ID)) continue;
716
- seen.add(CONTINUE_CHOICE_ID);
717
- choices.push({ id: CONTINUE_CHOICE_ID, label: "Continue", goto: t.goto });
718
- }
719
- }
720
- return choices;
721
- }
722
- function emitWorkflowMessage(eventStore, sessionId, content, windowOptions, onMessage) {
723
- const msgId = crypto.randomUUID();
724
- eventStore.append(
725
- sessionId,
726
- createMessageStartEvent(msgId, "user", content, {
727
- ...windowOptions ?? {},
728
- isSystemGenerated: true,
729
- messageKind: "correction",
730
- metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
731
- })
732
- );
733
- eventStore.append(sessionId, { type: "message.done", data: { messageId: msgId } });
734
- if (onMessage) {
735
- onMessage(
736
- createChatMessageMessage({
737
- id: msgId,
738
- role: "user",
739
- content,
740
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
741
- isSystemGenerated: true,
742
- messageKind: "correction",
743
- metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
744
- })
745
- );
746
- }
747
- return msgId;
748
- }
749
- function injectGenericKickoff(sessionId) {
750
- const eventStore = getEventStore();
751
- const windowOpts = getCurrentWindowMessageOptions(sessionId);
752
- const msgId = crypto.randomUUID();
753
- eventStore.append(
754
- sessionId,
755
- createMessageStartEvent(msgId, "user", "Proceed with the current step.", {
756
- ...windowOpts ?? {},
757
- isSystemGenerated: true,
758
- messageKind: "auto-prompt",
759
- metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
760
- })
761
- );
762
- eventStore.append(sessionId, { type: "message.done", data: { messageId: msgId } });
763
- }
764
- function getCurrentWindowMessageOptions(sessionId) {
765
- const contextWindowId = getCurrentContextWindowId(sessionId);
766
- return contextWindowId ? { contextWindowId } : void 0;
767
- }
768
- function buildReason(metadataEntries) {
769
- const entries = metadataEntries?.["criteria"] ?? [];
770
- const remaining = entries.filter((e) => e.status !== "passed");
771
- return `${remaining.length} criteria remaining`;
772
- }
773
- async function executeWorkflow(workflow, options, subGroup) {
774
- const { sessionManager, sessionId, llmClient, signal, onMessage } = options;
775
- const eventStore = getEventStore();
776
- const startTime = performance.now();
777
- let iterations = 0;
778
- const activeSteps = subGroup ? workflow.steps.filter((s) => s.subGroup === subGroup) : workflow.steps;
779
- const resumeFromStep = options.resumeFromStep;
780
- const isResume = !!resumeFromStep;
781
- let resumeConsumed = false;
782
- let currentStepId = isResume ? resumeFromStep : subGroup ? activeSteps[0]?.id ?? workflow.entryStep : workflow.entryStep;
783
- let lastStepOutput = options.initialStepOutput ?? {};
784
- const firstEntryForStep = /* @__PURE__ */ new Set();
785
- const messagesBeforeWorkflow = sessionManager.requireSession(sessionId).messages.length;
786
- const activeStepIds = new Set(activeSteps.map((s) => s.id));
787
- const stepsById = /* @__PURE__ */ new Map();
788
- for (const step of activeSteps) {
789
- stepsById.set(step.id, step);
790
- }
791
- if (resumeFromStep) {
792
- const targetStep = stepsById.get(resumeFromStep);
793
- if (!targetStep) {
794
- return {
795
- finalAction: {
796
- type: "BLOCKED",
797
- reason: `Resume target step "${resumeFromStep}" not found in workflow "${workflow.metadata.id}"`,
798
- blockedCriteria: []
799
- },
800
- iterations: 0,
801
- totalTime: (performance.now() - startTime) / 1e3
802
- };
803
- }
804
- }
805
- logger.debug("Workflow executor starting", { sessionId, workflow: workflow.metadata.id });
806
- let executionId;
807
- if (isResume) {
808
- const activeExec = sessionManager.getActiveWorkflowExecution(sessionId);
809
- if (activeExec) {
810
- executionId = activeExec.id;
811
- }
812
- }
813
- if (workflow.startCondition && workflow.startCondition.type !== "always") {
814
- const session = sessionManager.requireSession(sessionId);
815
- const conditionMet = evaluateCondition(
816
- workflow.startCondition,
817
- null,
818
- session.metadataEntries
819
- );
820
- if (!conditionMet) {
821
- logger.debug("Workflow start condition not met", { sessionId, condition: workflow.startCondition.type });
822
- return {
823
- finalAction: {
824
- type: "BLOCKED",
825
- reason: `Start condition not met: ${workflow.startCondition.type}`,
826
- blockedCriteria: []
827
- },
828
- iterations: 0,
829
- totalTime: (performance.now() - startTime) / 1e3
830
- };
831
- }
832
- }
833
- if (!isResume) {
834
- const startMsgId = crypto.randomUUID();
835
- const startWindowOpts = getCurrentWindowMessageOptions(sessionId);
836
- eventStore.append(
837
- sessionId,
838
- createMessageStartEvent(
839
- startMsgId,
840
- "user",
841
- JSON.stringify({
842
- workflowName: workflow.metadata.name,
843
- workflowId: workflow.metadata.id,
844
- workflowColor: workflow.metadata.color
845
- }),
846
- { ...startWindowOpts ?? {}, isSystemGenerated: true, messageKind: "workflow-started" }
847
- )
848
- );
849
- eventStore.append(sessionId, { type: "message.done", data: { messageId: startMsgId } });
850
- executionId = crypto.randomUUID();
851
- sessionManager.startWorkflow(
852
- sessionId,
853
- executionId,
854
- workflow.metadata.id,
855
- workflow.metadata.name,
856
- workflow.metadata.color,
857
- options.params ?? {}
858
- );
859
- }
860
- if (options.userMessage) {
861
- sessionManager.addMessage(sessionId, {
862
- role: "user",
863
- content: options.userMessage.content,
864
- ...options.userMessage.attachments ? { attachments: options.userMessage.attachments } : {}
865
- });
866
- }
867
- while (iterations < workflow.settings.maxIterations) {
868
- if (signal?.aborted) {
869
- logger.debug("Workflow executor aborted \u2014 preserving execution", { sessionId, iterations });
870
- return {
871
- finalAction: { type: "RUN_BUILDER", reason: "Aborted" },
872
- iterations,
873
- totalTime: (performance.now() - startTime) / 1e3
874
- };
875
- }
876
- iterations++;
877
- const step = stepsById.get(currentStepId);
878
- if (!step) {
879
- logger.error("Workflow step not found", { sessionId, stepId: currentStepId });
880
- return {
881
- finalAction: { type: "BLOCKED", reason: `Step "${currentStepId}" not found in workflow`, blockedCriteria: [] },
882
- iterations,
883
- totalTime: (performance.now() - startTime) / 1e3
884
- };
885
- }
886
- const session = sessionManager.requireSession(sessionId);
887
- const currentWindowMessageOptions = getCurrentWindowMessageOptions(sessionId);
888
- const criteriaEntries = session.metadataEntries["criteria"] ?? [];
889
- const templateCtx = {
890
- workdir: sessionManager.getEffectiveWorkdir(sessionId),
891
- reason: buildReason(session.metadataEntries),
892
- verifierFindings: lastStepOutput["content"] ?? "",
893
- previousStepOutput: lastStepOutput["stdout"] ?? "",
894
- criteriaCount: criteriaEntries.length,
895
- pendingCount: criteriaEntries.filter((e) => e.status !== "passed").length,
896
- criteriaList: formatCriteriaList(criteriaEntries),
897
- modifiedFiles: await formatModifiedFiles(sessionManager.getEffectiveWorkdir(sessionId)),
898
- stepOutput: lastStepOutput,
899
- params: options.params ?? {}
900
- };
901
- sessionManager.setPhase(sessionId, step.phase);
902
- if (executionId) {
903
- sessionManager.updateWorkflowStep(
904
- sessionId,
905
- executionId,
906
- step.id,
907
- step.name,
908
- workflow.metadata.id,
909
- workflow.metadata.name,
910
- workflow.metadata.color
911
- );
912
- }
913
- if (step.type === "agent") {
914
- const agentStep = step;
915
- sessionManager.setMode(sessionId, agentStep.agentId ?? resolveDefaultAgentId());
916
- }
917
- logger.debug("Workflow step executing", { sessionId, iteration: iterations, stepId: step.id, stepType: step.type });
918
- let stepOutcome = null;
919
- switch (step.type) {
920
- case "agent": {
921
- const agentStep = step;
922
- const STEP_DONE_PROMPT = "\n\nOnce you're done, call step_done()";
923
- const STEP_DONE_NUDGE = "You haven't called step_done(). If you haven't finished the task, continue and when you're finished call step_done()";
924
- let promptContent;
925
- let nudgeContent;
926
- const isResumingCurrentStep = isResume && step.id === resumeFromStep && !resumeConsumed;
927
- if (!firstEntryForStep.has(step.id) && agentStep.prompt && !isResumingCurrentStep) {
928
- const resolvedPrompt = resolveTemplate(agentStep.prompt, templateCtx);
929
- promptContent = resolvedPrompt + STEP_DONE_PROMPT;
930
- const promptMsgId = crypto.randomUUID();
931
- const msgMetadata = { type: "workflow", name: "Workflow", color: "#f59e0b" };
932
- eventStore.append(
933
- sessionId,
934
- createMessageStartEvent(promptMsgId, "user", promptContent, {
935
- ...currentWindowMessageOptions ?? {},
936
- isSystemGenerated: true,
937
- messageKind: "auto-prompt",
938
- metadata: msgMetadata
939
- })
940
- );
941
- eventStore.append(sessionId, { type: "message.done", data: { messageId: promptMsgId } });
942
- if (onMessage) {
943
- onMessage(
944
- createChatMessageMessage({
945
- id: promptMsgId,
946
- role: "user",
947
- content: promptContent,
948
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
949
- isSystemGenerated: true,
950
- messageKind: "auto-prompt",
951
- metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
952
- })
953
- );
954
- }
955
- } else if (firstEntryForStep.has(step.id) && !isResumingCurrentStep) {
956
- const parts = [];
957
- if (agentStep.nudgePrompt) {
958
- const resolvedNudge = resolveTemplate(agentStep.nudgePrompt, templateCtx);
959
- parts.push(resolvedNudge);
960
- }
961
- parts.push(STEP_DONE_NUDGE);
962
- nudgeContent = parts.join("\n\n");
963
- emitWorkflowMessage(eventStore, sessionId, nudgeContent, currentWindowMessageOptions, onMessage);
964
- }
965
- const turnMetrics = new TurnMetrics();
966
- const es = getEventStore();
967
- const append = (event) => es.append(sessionId, event);
968
- let stepDoneCalled = false;
969
- const agentResult = await runAgentTurn(
970
- {
971
- sessionManager,
972
- sessionId,
973
- llmClient,
974
- ...options.statsIdentity ? { statsIdentity: options.statsIdentity } : {},
975
- ...signal ? { signal } : {},
976
- ...onMessage ? { onMessage } : {}
977
- },
978
- turnMetrics,
979
- agentStep.agentId ?? resolveDefaultAgentId(),
980
- append,
981
- {
982
- ...!firstEntryForStep.has(step.id) && !agentStep.prompt && !isResumingCurrentStep ? { injectKickoff: () => injectGenericKickoff(sessionId) } : {},
983
- onToolExecuted: (toolCall, toolResult) => {
984
- if (toolCall.name === "step_done" && toolResult.success) {
985
- stepDoneCalled = true;
986
- }
987
- }
988
- }
989
- );
990
- firstEntryForStep.add(step.id);
991
- resumeConsumed = true;
992
- const agentReturnValue = agentResult.returnValueResult ?? "completed";
993
- lastStepOutput = {
994
- ...agentResult.returnValueContent ? { content: agentResult.returnValueContent } : {},
995
- ...agentResult.returnValueResult ? { result: agentResult.returnValueResult } : {},
996
- stepDoneCalled: String(stepDoneCalled)
997
- };
998
- stepOutcome = { result: agentReturnValue, output: lastStepOutput };
999
- if (!stepDoneCalled) {
1000
- logger.debug("step_done not called, looping agent step", {
1001
- sessionId,
1002
- stepId: step.id,
1003
- iteration: iterations
1004
- });
1005
- continue;
1006
- }
1007
- break;
1008
- }
1009
- case "sub_agent": {
1010
- const subStep = step;
1011
- const turnMetrics = new TurnMetrics();
1012
- const promptTemplate = subStep.prompt ?? "Perform your task.";
1013
- const resolvedPrompt = resolveTemplate(promptTemplate, templateCtx);
1014
- const allAgents = await loadAllAgentsDefault();
1015
- const agentDef = findAgentById(subStep.subAgentType, allAgents);
1016
- if (!agentDef) {
1017
- logger.error("Sub-agent definition not found", { subAgentType: subStep.subAgentType });
1018
- stepOutcome = { result: "error", output: {} };
1019
- break;
1020
- }
1021
- const toolRegistry = getToolRegistryForAgent(agentDef);
1022
- const filteredToolRegistry = {
1023
- tools: toolRegistry.tools.filter((t) => t.name !== "step_done"),
1024
- definitions: toolRegistry.definitions.filter((d) => d.type === "function" && d.function.name !== "step_done"),
1025
- execute: toolRegistry.execute
1026
- };
1027
- const result = await executeSubAgent({
1028
- subAgentType: subStep.subAgentType,
1029
- prompt: resolvedPrompt,
1030
- sessionManager,
1031
- sessionId,
1032
- llmClient,
1033
- toolRegistry: filteredToolRegistry,
1034
- turnMetrics,
1035
- statsIdentity: options.statsIdentity ?? {
1036
- providerId: "",
1037
- providerName: "",
1038
- backend: "unknown",
1039
- model: llmClient.getModel()
1040
- },
1041
- ...signal ? { signal } : {},
1042
- ...onMessage ? { onMessage } : {}
1043
- });
1044
- lastStepOutput = { content: result.content ?? "", ...result.result ? { result: result.result } : {} };
1045
- stepOutcome = { result: result.result ?? "success", output: lastStepOutput };
1046
- break;
1047
- }
1048
- case "shell": {
1049
- const shellStep = step;
1050
- const command = resolveTemplate(shellStep.command, templateCtx);
1051
- const timeout = shellStep.timeout ?? 6e4;
1052
- const successCodes = shellStep.successExitCodes ?? [0];
1053
- const shellMsgId = crypto.randomUUID();
1054
- eventStore.append(
1055
- sessionId,
1056
- createMessageStartEvent(shellMsgId, "user", `Running: \`${command}\``, {
1057
- ...currentWindowMessageOptions ?? {},
1058
- isSystemGenerated: true,
1059
- messageKind: "auto-prompt",
1060
- metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
1061
- })
1062
- );
1063
- if (onMessage) {
1064
- onMessage(
1065
- createChatMessageMessage({
1066
- id: shellMsgId,
1067
- role: "user",
1068
- content: `Running: \`${command}\``,
1069
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1070
- isSystemGenerated: true,
1071
- messageKind: "auto-prompt",
1072
- metadata: { type: "workflow", name: "Workflow", color: "#f59e0b" }
1073
- })
1074
- );
1075
- }
1076
- const result = await executeShellCommand(
1077
- command,
1078
- sessionManager.getEffectiveWorkdir(sessionId),
1079
- timeout,
1080
- signal
1081
- );
1082
- const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
1083
- lastStepOutput = { stdout: result.stdout ?? "", stderr: result.stderr ?? "", exitCode: String(result.exitCode) };
1084
- const outputContent = output ? `Exit code: ${result.exitCode}
1085
- \`\`\`
1086
- ${output.slice(0, 1e4)}
1087
- \`\`\`` : `Exit code: ${result.exitCode}`;
1088
- eventStore.append(sessionId, { type: "message.done", data: { messageId: shellMsgId } });
1089
- const outputMsgId = crypto.randomUUID();
1090
- eventStore.append(
1091
- sessionId,
1092
- createMessageStartEvent(outputMsgId, "user", outputContent, {
1093
- ...currentWindowMessageOptions ?? {},
1094
- isSystemGenerated: true,
1095
- messageKind: "correction"
1096
- })
1097
- );
1098
- eventStore.append(sessionId, { type: "message.done", data: { messageId: outputMsgId } });
1099
- if (onMessage) {
1100
- onMessage(
1101
- createChatMessageMessage({
1102
- id: outputMsgId,
1103
- role: "user",
1104
- content: outputContent,
1105
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1106
- isSystemGenerated: true,
1107
- messageKind: "correction"
1108
- })
1109
- );
1110
- }
1111
- stepOutcome = { result: successCodes.includes(result.exitCode) ? "success" : "failure", output: lastStepOutput };
1112
- break;
1113
- }
1114
- case "user": {
1115
- if (resumeFromStep === step.id) {
1116
- const choice = options.userChoice;
1117
- const result = choice === void 0 || choice === CONTINUE_CHOICE_ID ? DEFAULT_USER_RESULT : choice;
1118
- stepOutcome = { result, output: lastStepOutput };
1119
- break;
1120
- }
1121
- if (executionId) {
1122
- const choices = userStepChoices(step).map((choice) => {
1123
- const target = choice.goto ? stepsById.get(choice.goto) : void 0;
1124
- return target ? { ...choice, nextStepName: target.name } : choice;
1125
- });
1126
- sessionManager.waitAtStep(
1127
- sessionId,
1128
- executionId,
1129
- step.id,
1130
- step.name,
1131
- lastStepOutput,
1132
- workflow.metadata.id,
1133
- workflow.metadata.name,
1134
- workflow.metadata.color,
1135
- choices
1136
- );
1137
- }
1138
- logger.debug("Workflow paused at user step", { sessionId, stepId: step.id, stepName: step.name });
1139
- return {
1140
- finalAction: {
1141
- type: "WAITING",
1142
- reason: `Paused at user step: ${step.name}`,
1143
- workflowId: workflow.metadata.id,
1144
- stepId: step.id,
1145
- stepOutput: lastStepOutput
1146
- },
1147
- iterations,
1148
- totalTime: (performance.now() - startTime) / 1e3
1149
- };
1150
- }
1151
- }
1152
- const refreshedSession = sessionManager.requireSession(sessionId);
1153
- const effectiveTransitions = subGroup ? step.transitions.filter((t) => !t.subGroup || t.subGroup === subGroup) : step.transitions;
1154
- const rawNextStepId = evaluateTransitions(effectiveTransitions, stepOutcome, refreshedSession.metadataEntries);
1155
- const nextStepId = subGroup && rawNextStepId !== TERMINAL_DONE && rawNextStepId !== TERMINAL_BLOCKED && !activeStepIds.has(rawNextStepId) ? TERMINAL_DONE : rawNextStepId;
1156
- if (nextStepId === TERMINAL_DONE) {
1157
- sessionManager.setPhase(sessionId, "done");
1158
- if (executionId) {
1159
- sessionManager.completeWorkflow(
1160
- sessionId,
1161
- executionId,
1162
- workflow.metadata.id,
1163
- workflow.metadata.name,
1164
- workflow.metadata.color
1165
- );
1166
- }
1167
- const totalTimeSeconds = Math.round((performance.now() - startTime) / 100) / 10;
1168
- const completedSession = sessionManager.requireSession(sessionId);
1169
- const workflowMessages = completedSession.messages.slice(messagesBeforeWorkflow);
1170
- const workflowStats = computeSessionStats(workflowMessages);
1171
- const totalToolCalls = workflowMessages.reduce((sum, m) => sum + (m.toolCalls?.length ?? 0), 0);
1172
- const taskCompletedData = {
1173
- summary: null,
1174
- iterations,
1175
- totalTimeSeconds,
1176
- totalToolCalls,
1177
- totalTokensGenerated: workflowStats?.generationTokens ?? 0,
1178
- avgGenerationSpeed: workflowStats?.avgGenerationSpeed ?? 0,
1179
- responseCount: workflowStats?.responseCount ?? 0,
1180
- llmCallCount: workflowStats?.llmCallCount ?? 0,
1181
- criteria: [],
1182
- workflowName: workflow.metadata.name,
1183
- workflowId: workflow.metadata.id,
1184
- ...workflow.metadata.color ? { workflowColor: workflow.metadata.color } : {}
1185
- };
1186
- eventStore.append(sessionId, { type: "task.completed", data: taskCompletedData });
1187
- const markerMsgId = crypto.randomUUID();
1188
- eventStore.append(
1189
- sessionId,
1190
- createMessageStartEvent(markerMsgId, "user", JSON.stringify(taskCompletedData), {
1191
- ...currentWindowMessageOptions ?? {},
1192
- isSystemGenerated: true,
1193
- messageKind: "task-completed"
1194
- })
1195
- );
1196
- eventStore.append(sessionId, { type: "message.done", data: { messageId: markerMsgId } });
1197
- logger.debug("Workflow executor complete", { sessionId, iterations });
1198
- const doneAction = { type: "DONE" };
1199
- return {
1200
- finalAction: doneAction,
1201
- iterations,
1202
- totalTime: totalTimeSeconds
1203
- };
1204
- }
1205
- if (nextStepId === TERMINAL_BLOCKED) {
1206
- sessionManager.setPhase(sessionId, "blocked");
1207
- if (executionId) {
1208
- sessionManager.blockWorkflow(
1209
- sessionId,
1210
- executionId,
1211
- workflow.metadata.id,
1212
- workflow.metadata.name,
1213
- workflow.metadata.color
1214
- );
1215
- }
1216
- const reason = "No matching transition";
1217
- emitWorkflowMessage(eventStore, sessionId, `Runner blocked: ${reason}`, currentWindowMessageOptions, onMessage);
1218
- logger.warn("Workflow executor blocked", { sessionId, iterations, reason });
1219
- const blockedAction = { type: "BLOCKED", reason, blockedCriteria: [] };
1220
- return {
1221
- finalAction: blockedAction,
1222
- iterations,
1223
- totalTime: (performance.now() - startTime) / 1e3
1224
- };
1225
- }
1226
- currentStepId = nextStepId;
1227
- }
1228
- logger.warn("Workflow executor max iterations reached", { sessionId, iterations });
1229
- return {
1230
- finalAction: {
1231
- type: "BLOCKED",
1232
- reason: `Max iterations (${workflow.settings.maxIterations}) reached`,
1233
- blockedCriteria: []
1234
- },
1235
- iterations,
1236
- totalTime: (performance.now() - startTime) / 1e3
1237
- };
1238
- }
1239
-
1240
- // src/server/runner/orchestrator.ts
1241
- async function runOrchestrator(options) {
1242
- const runtimeConfig = getRuntimeConfig();
1243
- const workflowId = options.workflowId ?? runtimeConfig.activeWorkflowId ?? "default";
1244
- const configDir = getGlobalConfigDir(runtimeConfig.mode ?? "production");
1245
- const session = options.sessionManager.requireSession(options.sessionId);
1246
- const projectDir = session.workdir;
1247
- const scope = normalizeWorkflowScope(options.scope);
1248
- let workflow;
1249
- if (scope === "builtin") {
1250
- workflow = findWorkflowById(workflowId, await loadDefaultWorkflows());
1251
- } else if (scope === "user") {
1252
- workflow = findWorkflowById(workflowId, await loadUserWorkflows(configDir));
1253
- } else if (scope === "project") {
1254
- workflow = projectDir ? findWorkflowById(workflowId, await loadProjectWorkflows(projectDir)) : void 0;
1255
- } else {
1256
- workflow = void 0;
1257
- }
1258
- if (!workflow) {
1259
- const workflows = await loadAllWorkflows(configDir, projectDir);
1260
- workflow = findWorkflowById(workflowId, workflows);
1261
- }
1262
- if (!workflow) {
1263
- throw new Error(`Workflow "${workflowId}" not found`);
1264
- }
1265
- const requiredParams = (workflow.metadata.parameters ?? []).filter((p) => p.required);
1266
- const suppliedParams = options.params ?? {};
1267
- const missing = requiredParams.filter((p) => !(p.id in suppliedParams));
1268
- if (missing.length > 0) {
1269
- const names = missing.map((p) => p.label || p.id).join(", ");
1270
- throw new Error(`Missing required parameter${missing.length > 1 ? "s" : ""}: ${names}`);
1271
- }
1272
- logger.debug("Using workflow executor", {
1273
- sessionId: options.sessionId,
1274
- workflow: workflow.metadata.id,
1275
- subGroup: options.subGroup
1276
- });
1277
- return executeWorkflow(workflow, options, options.subGroup);
1278
- }
1279
-
1280
333
  // src/server/auth.ts
1281
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
1282
- import { join as join2, dirname as dirname2, basename } from "path";
334
+ import { readFile, writeFile, mkdir } from "fs/promises";
335
+ import { join, dirname, basename } from "path";
1283
336
  import { createHash, privateDecrypt, createPublicKey } from "crypto";
1284
337
  function getAuthConfigPath() {
1285
338
  const configDir = getRuntimeConfig();
1286
339
  const mode = configDir.mode === "development" ? "development" : configDir.mode === "test" ? "test" : "production";
1287
340
  if (mode === "test") {
1288
341
  const cwd = process.cwd();
1289
- const base = basename(cwd) === "e2e" ? cwd : join2(cwd, "e2e");
1290
- const testAuthPath = join2(base, ".openfox-test", "auth.json");
342
+ const base = basename(cwd) === "e2e" ? cwd : join(cwd, "e2e");
343
+ const testAuthPath = join(base, ".openfox-test", "auth.json");
1291
344
  return testAuthPath;
1292
345
  }
1293
346
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "";
@@ -1297,8 +350,8 @@ function getAuthConfigPath() {
1297
350
  }
1298
351
  function getKeyPath() {
1299
352
  const authPath = getAuthConfigPath();
1300
- const dir = dirname2(authPath);
1301
- return join2(dir, "auth.key");
353
+ const dir = dirname(authPath);
354
+ return join(dir, "auth.key");
1302
355
  }
1303
356
  var cachedAuth = null;
1304
357
  var cachedPrivateKey = null;
@@ -1307,9 +360,9 @@ async function loadPrivateKey() {
1307
360
  return cachedPrivateKey;
1308
361
  }
1309
362
  const keyPath = getKeyPath();
1310
- const keyDir = dirname2(keyPath);
363
+ const keyDir = dirname(keyPath);
1311
364
  try {
1312
- cachedPrivateKey = await readFile2(keyPath, "utf-8");
365
+ cachedPrivateKey = await readFile(keyPath, "utf-8");
1313
366
  return cachedPrivateKey;
1314
367
  } catch {
1315
368
  const { privateKey } = await import("crypto").then(
@@ -1319,8 +372,8 @@ async function loadPrivateKey() {
1319
372
  publicKeyEncoding: { type: "spki", format: "pem" }
1320
373
  })
1321
374
  );
1322
- await mkdir2(keyDir, { recursive: true });
1323
- await writeFile2(keyPath, privateKey, { mode: 384 });
375
+ await mkdir(keyDir, { recursive: true });
376
+ await writeFile(keyPath, privateKey, { mode: 384 });
1324
377
  cachedPrivateKey = privateKey;
1325
378
  return privateKey;
1326
379
  }
@@ -1335,7 +388,7 @@ async function loadServerAuthConfig() {
1335
388
  }
1336
389
  try {
1337
390
  const authPath = getAuthConfigPath();
1338
- const data = await readFile2(authPath, "utf-8");
391
+ const data = await readFile(authPath, "utf-8");
1339
392
  const authConfig = JSON.parse(data);
1340
393
  cachedAuth = authConfig;
1341
394
  return authConfig;
@@ -1410,7 +463,7 @@ function signalMcpReady() {
1410
463
  }
1411
464
  function moduleGitBranch(cwd) {
1412
465
  return new Promise((resolve) => {
1413
- const proc = spawn3("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
466
+ const proc = spawn2("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
1414
467
  cwd,
1415
468
  env: gitSpawnEnv(),
1416
469
  stdio: ["ignore", "pipe", "ignore"],
@@ -1436,13 +489,13 @@ function hashContent(content) {
1436
489
  function moduleGitDiff(cwd) {
1437
490
  return new Promise((resolve) => {
1438
491
  const env = gitSpawnEnv();
1439
- const diffProc = spawn3("git", ["diff", "--name-status", "HEAD"], {
492
+ const diffProc = spawn2("git", ["diff", "--name-status", "HEAD"], {
1440
493
  cwd,
1441
494
  env,
1442
495
  stdio: ["ignore", "pipe", "pipe"],
1443
496
  windowsHide: true
1444
497
  });
1445
- const statusProc = spawn3("git", ["status", "--porcelain"], {
498
+ const statusProc = spawn2("git", ["status", "--porcelain"], {
1446
499
  cwd,
1447
500
  env,
1448
501
  stdio: ["ignore", "pipe", "pipe"],
@@ -2220,8 +1273,8 @@ async function handleClientMessage(ws, client, message, _getLLMClient, _getActiv
2220
1273
  const sessionId = client.activeSessionId;
2221
1274
  const session = sessionManager.requireSession(sessionId);
2222
1275
  try {
2223
- const { buildCachedPrompt } = await import("./dynamic-context-F2XTQJR5.js");
2224
- const allAgents = await import("./registry-VCKDSVKA.js");
1276
+ const { buildCachedPrompt } = await import("./dynamic-context-MVGOF5V2.js");
1277
+ const allAgents = await import("./registry-ZP4TN2IN.js");
2225
1278
  const agentDef = allAgents.findAgentById(session.mode, await allAgents.loadAllAgentsDefault()) ?? allAgents.findAgentById("planner", await allAgents.loadAllAgentsDefault());
2226
1279
  const modelName = session.providerModel ?? _providerManager?.getCurrentModel();
2227
1280
  const { systemPrompt: newPrompt, hash: newHash } = await buildCachedPrompt(
@@ -2341,8 +1394,6 @@ ${content}` : workflowInfo;
2341
1394
  const hasUserAttachments = launchAttachments && launchAttachments.length > 0;
2342
1395
  const hasUserMessage = hasUserContent || hasUserAttachments;
2343
1396
  const isResume = !!launchPayload?.resumeFrom;
2344
- sessionManager.setRunning(sessionId, true);
2345
- sendForSession(sessionId, createSessionRunningMessage(true));
2346
1397
  const controller = new AbortController();
2347
1398
  const existingController = activeAgents.get(sessionId);
2348
1399
  if (existingController) {
@@ -2371,71 +1422,30 @@ ${content}` : workflowInfo;
2371
1422
  );
2372
1423
  }
2373
1424
  }
2374
- runOrchestrator({
2375
- sessionManager,
2376
- sessionId,
2377
- llmClient: llmForSession(sessionId),
2378
- statsIdentity: statsForSession(sessionId),
2379
- scope: normalizeWorkflowScope(launchPayload?.scope),
2380
- ...launchPayload?.workflowId ? { workflowId: launchPayload.workflowId } : {},
2381
- ...launchPayload?.subGroup ? { subGroup: launchPayload.subGroup } : {},
2382
- ...isResume && launchPayload?.resumeFrom ? { resumeFromStep: launchPayload.resumeFrom } : {},
2383
- ...isResume && launchPayload?.stepOutput ? { initialStepOutput: launchPayload.stepOutput } : {},
2384
- ...isResume && launchPayload?.userChoice ? { userChoice: launchPayload.userChoice } : {},
2385
- ...launchPayload?.params ? { params: launchPayload.params } : {},
2386
- // On resume, prefer params/stepOutput from the persisted workflow execution
2387
- ...isResume ? (() => {
2388
- const exec = sessionManager.getActiveWorkflowExecution(sessionId);
2389
- if (!exec) return {};
2390
- if (exec.status === "waiting") {
2391
- const resumed = sessionManager.resumeWorkflow(
2392
- sessionId,
2393
- exec.id,
2394
- exec.workflowId,
2395
- exec.workflowName,
2396
- exec.workflowColor
2397
- );
2398
- if (resumed) {
2399
- return {
2400
- params: resumed.params,
2401
- initialStepOutput: resumed.stepOutput,
2402
- ...exec.currentStepId ? { resumeFromStep: exec.currentStepId } : {}
2403
- };
2404
- }
2405
- }
2406
- return {
2407
- ...Object.keys(exec.params).length > 0 ? { params: exec.params } : {},
2408
- ...Object.keys(exec.stepOutput).length > 0 ? { initialStepOutput: exec.stepOutput } : {},
2409
- ...exec.currentStepId ? { resumeFromStep: exec.currentStepId } : {}
2410
- };
2411
- })() : {},
2412
- ...hasUserMessage ? {
2413
- userMessage: {
1425
+ launchWorkflowRun(
1426
+ {
1427
+ sessionManager,
1428
+ sessionId,
1429
+ controller,
1430
+ llmClient: llmForSession(sessionId),
1431
+ statsIdentity: statsForSession(sessionId),
1432
+ broadcastForSession: (sid, msg) => _broadcastForSession(sid, msg),
1433
+ onFinished: () => cleanupAfterTurn(sessionId, controller, sendForSession, true)
1434
+ },
1435
+ {
1436
+ ...launchPayload?.workflowId ? { workflowId: launchPayload.workflowId } : {},
1437
+ ...launchPayload?.subGroup ? { subGroup: launchPayload.subGroup } : {},
1438
+ ...launchPayload?.scope ? { scope: launchPayload.scope } : {},
1439
+ ...isResume && launchPayload?.resumeFrom ? { resumeFrom: launchPayload.resumeFrom } : {},
1440
+ ...isResume && launchPayload?.stepOutput ? { stepOutput: launchPayload.stepOutput } : {},
1441
+ ...isResume && launchPayload?.userChoice ? { userChoice: launchPayload.userChoice } : {},
1442
+ ...launchPayload?.params ? { params: launchPayload.params } : {},
1443
+ ...hasUserMessage ? {
2414
1444
  content: hasUserContent ? launchPayload.content : "",
2415
1445
  ...hasUserAttachments ? { attachments: launchAttachments } : {}
2416
- }
2417
- } : {},
2418
- signal: controller.signal,
2419
- onMessage: (msg) => _broadcastForSession(sessionId, msg)
2420
- // For path confirmation dialogs
2421
- }).catch((error) => {
2422
- if (error instanceof Error && error.message === "Aborted") {
2423
- return;
1446
+ } : {}
2424
1447
  }
2425
- const errorMessage = error instanceof Error ? error.message : String(error);
2426
- logger.error("Runner error", { error: errorMessage, sessionId });
2427
- _broadcastForSession(
2428
- sessionId,
2429
- createServerMessage("chat.error", { error: errorMessage, recoverable: false })
2430
- );
2431
- }).finally(() => {
2432
- try {
2433
- sessionManager.setRunning(sessionId, false);
2434
- sendForSession(sessionId, createSessionRunningMessage(false));
2435
- cleanupAfterTurn(sessionId, controller, sendForSession, true);
2436
- } catch {
2437
- }
2438
- });
1448
+ );
2439
1449
  break;
2440
1450
  }
2441
1451
  // =========================================================================
@@ -2522,20 +1532,6 @@ ${content}` : workflowInfo;
2522
1532
 
2523
1533
  export {
2524
1534
  terminalManager,
2525
- normalizeWorkflowScope,
2526
- loadDefaultWorkflows,
2527
- loadUserWorkflows,
2528
- loadProjectWorkflows,
2529
- loadAllWorkflows,
2530
- saveWorkflowToProject,
2531
- deleteProjectWorkflow,
2532
- getDefaultWorkflowIds,
2533
- isDefaultWorkflow,
2534
- findWorkflowById,
2535
- workflowExists,
2536
- saveWorkflow,
2537
- deleteWorkflow,
2538
- TEMPLATE_VARIABLES,
2539
1535
  loadServerAuthConfig,
2540
1536
  getAuthConfig,
2541
1537
  requiresAuth,
@@ -2546,4 +1542,4 @@ export {
2546
1542
  signalMcpReady,
2547
1543
  createWebSocketServer
2548
1544
  };
2549
- //# sourceMappingURL=chunk-HGOTZWON.js.map
1545
+ //# sourceMappingURL=chunk-7GWARYQC.js.map