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.
- package/CHANGELOG.md +22 -0
- package/dist/CHANGELOG.md +22 -0
- package/dist/agent-defaults/builder.agent.md +1 -0
- package/dist/agent-defaults/planner.agent.md +1 -0
- package/dist/{backend-P3GHHLHJ.js → backend-LVYHLGQJ.js} +2 -2
- package/dist/{chat-handler-PEK5JDHO.js → chat-handler-KWXRSWXZ.js} +31 -25
- package/dist/{chunk-HKD4IMOE.js → chunk-2XD65L7M.js} +2 -2
- package/dist/{chunk-AZFZE36I.js → chunk-3O77NT4T.js} +17 -7
- package/dist/{chunk-HGOTZWON.js → chunk-7GWARYQC.js} +60 -1064
- package/dist/{chunk-YHEQTVFV.js → chunk-AZHWLLPP.js} +1 -1
- package/dist/{chunk-6UPBZ2ZR.js → chunk-BZVW77PI.js} +4 -4
- package/dist/{chunk-YGPPFVLJ.js → chunk-FW4NDUBL.js} +15 -15
- package/dist/{chunk-O2YSYW2F.js → chunk-GUHHUDNL.js} +6 -6
- package/dist/{chunk-WWTYWLDM.js → chunk-HP5CIB66.js} +2 -2
- package/dist/{chunk-ONONXV3N.js → chunk-HV6IALXF.js} +4 -4
- package/dist/{chunk-4NMGX5F2.js → chunk-I7FY2LTR.js} +2 -2
- package/dist/{chunk-Y64PEWKP.js → chunk-JP7NM545.js} +2 -2
- package/dist/{chunk-CP44U7BT.js → chunk-JXLRL5JR.js} +5 -5
- package/dist/{chunk-5VYSKVZT.js → chunk-K733B5T2.js} +254 -20
- package/dist/{chunk-SNLLOXCM.js → chunk-L63Q4JQJ.js} +3 -3
- package/dist/{chunk-43M7QZMX.js → chunk-LXYPMFTH.js} +3 -3
- package/dist/{chunk-TCGWZBTS.js → chunk-MUSPWEBB.js} +3 -3
- package/dist/chunk-NCZRWCJN.js +7 -0
- package/dist/{chunk-JR54MDZI.js → chunk-NLO64UE3.js} +2 -2
- package/dist/{chunk-3R43CMLS.js → chunk-NWJLWLKF.js} +8 -8
- package/dist/chunk-OSXPQSLW.js +128 -0
- package/dist/chunk-OTYAEEX3.js +1081 -0
- package/dist/{chunk-V4664YKR.js → chunk-OXSTNSCF.js} +2 -2
- package/dist/{chunk-R2MTWC7C.js → chunk-P5UANBBX.js} +6 -4
- package/dist/{chunk-PWXBIUEY.js → chunk-PBW3YC3G.js} +85 -1
- package/dist/{chunk-TEQEDOWI.js → chunk-QD7MRMCH.js} +245 -289
- package/dist/{chunk-BNFGDTEU.js → chunk-SA34STZ6.js} +2 -2
- package/dist/{chunk-VGRVPYZ5.js → chunk-SBSUDHL4.js} +2 -2
- package/dist/{chunk-XQR76MQ5.js → chunk-SFZGMB2G.js} +2 -2
- package/dist/{chunk-EC5T5A6O.js → chunk-TKKP56QK.js} +3 -3
- package/dist/{chunk-BYSUSSSC.js → chunk-UPBWEHIL.js} +30 -148
- package/dist/{chunk-YB6WYVNY.js → chunk-UTIQ7OO5.js} +2 -2
- package/dist/{chunk-EMI3YYLP.js → chunk-VPVLO436.js} +4 -4
- package/dist/chunk-W77NBJAZ.js +957 -0
- package/dist/{chunk-BKCW3JLL.js → chunk-X25Q6RAV.js} +1 -1
- package/dist/{chunk-FF2EKUQO.js → chunk-YGJIK3CG.js} +4 -4
- package/dist/cli/dev.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/{client-3LJGD6KY.js → client-EM7ISGUP.js} +6 -6
- package/dist/{compactor-ZBNKANHV.js → compactor-V3LR7APW.js} +13 -12
- package/dist/{dynamic-context-F2XTQJR5.js → dynamic-context-MVGOF5V2.js} +10 -9
- package/dist/{events-224IO5NJ.js → events-PI7IMPHT.js} +8 -7
- package/dist/{folding-YTTTVS56.js → folding-FO57K4JM.js} +6 -5
- package/dist/http-client-33EZ3BLR.js +11 -0
- package/dist/{inspect-proxy-B7LGGTM7.js → inspect-proxy-NHKQQ2CD.js} +4 -4
- package/dist/launch-L5ROVNI3.js +52 -0
- package/dist/{manager-4QGXI6WZ.js → manager-66YAEO7K.js} +5 -5
- package/dist/{model-overrides-OY2YKUNV.js → model-overrides-L53PZNZA.js} +4 -4
- package/dist/orchestrator-XK5K3RPL.js +63 -0
- package/dist/package.json +3 -3
- package/dist/{path-security-PFMZY7IA.js → path-security-RSEI3YKB.js} +12 -11
- package/dist/{platform-QNGCKX4L.js → platform-WA4GK5BO.js} +4 -4
- package/dist/{processor-NYPJ5PFA.js → processor-WDZSFBVO.js} +30 -24
- package/dist/{project-creator-AWP2JUFS.js → project-creator-676WQXVI.js} +3 -3
- package/dist/{projects-C4353IQK.js → projects-SSBWIYL4.js} +3 -3
- package/dist/{protocol-CBT1d98i.d.ts → protocol-BzHs024-.d.ts} +21 -3
- package/dist/{protocol-LZZ7C4VQ.js → protocol-RKSWKNXI.js} +3 -3
- package/dist/provider/index.d.ts +4 -4
- package/dist/{provider-PIRPN2CC.js → provider-PLIWRBCF.js} +7 -7
- package/dist/{provider-manager-GNEPR6UN.js → provider-manager-2QSJTPWS.js} +7 -7
- package/dist/{registry-VCKDSVKA.js → registry-ZP4TN2IN.js} +5 -4
- package/dist/{serve-6DRHQLCG.js → serve-MZ3BCCWC.js} +35 -32
- package/dist/server/index.d.ts +4 -4
- package/dist/server/index.js +34 -31
- package/dist/server-EPXODFMB.js +55 -0
- package/dist/service-54PGIPDQ.js +25 -0
- package/dist/{session-overrides-RNKV35MU.js → session-overrides-LXN6W7SA.js} +7 -6
- package/dist/{sessions-D5CEPQGU.js → sessions-CHPVUG6H.js} +6 -5
- package/dist/{settings-BNRNX6IW.js → settings-NEBM3GQX.js} +3 -3
- package/dist/shared/index.d.ts +3 -3
- package/dist/shared/index.js +1 -1
- package/dist/skill-defaults/workflows/SKILL.md +24 -6
- package/dist/tasks-TJXG2V3U.js +217 -0
- package/dist/{tools-2B363F7L.js → tools-CIM26IFB.js} +30 -22
- package/dist/{types-BAxh20ZL.d.ts → types-CMtHpDWT.d.ts} +74 -1
- package/dist/{types-cVfqOj6M.d.ts → types-CbggXFvR.d.ts} +1 -1
- package/dist/{update-IQMRYN7J.js → update-UZBBO42X.js} +2 -2
- package/dist/web/assets/{index-CjWC6EQ4.css → index-BmILAZrT.css} +1 -1
- package/dist/web/assets/index-rZHXkfMq.js +324 -0
- package/dist/web/index.html +2 -2
- package/dist/web/sw.js +1 -1
- package/dist/workflow-defaults/default.workflow.json +5 -3
- package/dist/{workspace-YUNHV4WS.js → workspace-2XODU4YJ.js} +4 -4
- package/package.json +3 -3
- package/dist/chunk-B2PHPBFU.js +0 -7
- package/dist/http-client-YC3UA5OZ.js +0 -11
- package/dist/orchestrator-JKBY7B3P.js +0 -57
- package/dist/server-HUHFJW7U.js +0 -48
- 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-
|
|
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-
|
|
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-
|
|
19
|
+
} from "./chunk-GUHHUDNL.js";
|
|
15
20
|
import {
|
|
16
21
|
appendCompactionPrompt
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import {
|
|
19
|
-
devServerManager,
|
|
20
|
-
executeSubAgent,
|
|
21
|
-
getToolRegistryForAgent
|
|
22
|
-
} from "./chunk-5VYSKVZT.js";
|
|
22
|
+
} from "./chunk-VPVLO436.js";
|
|
23
23
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
} from "./chunk-JR54MDZI.js";
|
|
24
|
+
onProcessEvent
|
|
25
|
+
} from "./chunk-TKKP56QK.js";
|
|
27
26
|
import {
|
|
28
|
-
|
|
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-
|
|
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-
|
|
50
|
+
} from "./chunk-I7FY2LTR.js";
|
|
60
51
|
import {
|
|
61
52
|
getPlatformShell
|
|
62
|
-
} from "./chunk-
|
|
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-
|
|
61
|
+
} from "./chunk-UTIQ7OO5.js";
|
|
71
62
|
import {
|
|
72
|
-
|
|
73
|
-
|
|
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-
|
|
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-
|
|
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
|
|
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
|
|
1282
|
-
import { join
|
|
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 :
|
|
1290
|
-
const testAuthPath =
|
|
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 =
|
|
1301
|
-
return
|
|
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 =
|
|
363
|
+
const keyDir = dirname(keyPath);
|
|
1311
364
|
try {
|
|
1312
|
-
cachedPrivateKey = await
|
|
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
|
|
1323
|
-
await
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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-
|
|
2224
|
-
const allAgents = await import("./registry-
|
|
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
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
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
|
-
|
|
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-
|
|
1545
|
+
//# sourceMappingURL=chunk-7GWARYQC.js.map
|