agent-phonon 0.2.10 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +578 -83
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +504 -83
- package/dist/daemon.js.map +1 -1
- package/package.json +3 -3
package/dist/daemon.js
CHANGED
|
@@ -939,7 +939,7 @@ var init_project = __esm({
|
|
|
939
939
|
|
|
940
940
|
// ../protocol/dist/schemas/skill.js
|
|
941
941
|
import { z as z10 } from "zod";
|
|
942
|
-
var SkillScope, SkillSource, SkillDescriptor, SkillInstallParams, SkillInstallResult, SkillUninstallParams, SkillUninstallResult, SkillListParams, SkillListResult;
|
|
942
|
+
var SkillScope, SkillSource, SkillDescriptor, SkillInstallParams, SkillInstallResult, SkillUninstallParams, SkillUninstallResult, SkillListParams, SkillListResult, SkillDirsParams, SkillDirectoryDescriptor, SkillDirsResult;
|
|
943
943
|
var init_skill = __esm({
|
|
944
944
|
"../protocol/dist/schemas/skill.js"() {
|
|
945
945
|
"use strict";
|
|
@@ -1027,6 +1027,29 @@ var init_skill = __esm({
|
|
|
1027
1027
|
SkillListResult = z10.object({
|
|
1028
1028
|
skills: z10.array(SkillDescriptor)
|
|
1029
1029
|
});
|
|
1030
|
+
SkillDirsParams = z10.object({
|
|
1031
|
+
/** 可选:global scope 的目标 agent。 */
|
|
1032
|
+
agent: AgentId.optional(),
|
|
1033
|
+
/** 可选:project scope 的目标项目。 */
|
|
1034
|
+
projectId: ProjectId.optional(),
|
|
1035
|
+
/** 可选:只查 global 或 project;不传时按 agent/projectId 返回可查范围。 */
|
|
1036
|
+
scope: SkillScope.optional()
|
|
1037
|
+
});
|
|
1038
|
+
SkillDirectoryDescriptor = z10.object({
|
|
1039
|
+
/** skill 目录名。 */
|
|
1040
|
+
name: z10.string().min(1),
|
|
1041
|
+
scope: SkillScope,
|
|
1042
|
+
agent: AgentId.optional(),
|
|
1043
|
+
projectId: ProjectId.optional(),
|
|
1044
|
+
/** scope 根目录(global skill root 或 <project>/.agent/skills)。 */
|
|
1045
|
+
rootPath: z10.string().min(1),
|
|
1046
|
+
/** skill 目录真实本机路径。 */
|
|
1047
|
+
path: z10.string().min(1),
|
|
1048
|
+
exists: z10.boolean()
|
|
1049
|
+
});
|
|
1050
|
+
SkillDirsResult = z10.object({
|
|
1051
|
+
directories: z10.array(SkillDirectoryDescriptor)
|
|
1052
|
+
});
|
|
1030
1053
|
}
|
|
1031
1054
|
});
|
|
1032
1055
|
|
|
@@ -1310,43 +1333,166 @@ var init_env = __esm({
|
|
|
1310
1333
|
}
|
|
1311
1334
|
});
|
|
1312
1335
|
|
|
1313
|
-
// ../protocol/dist/schemas/
|
|
1336
|
+
// ../protocol/dist/schemas/workflow.js
|
|
1314
1337
|
import { z as z16 } from "zod";
|
|
1338
|
+
var ModelId, TurnId, ClientRequestId, WorkflowId, WorkflowNodeId, WorkflowEdgeId, WorkflowRoleId, WorkflowNode, WorkflowEdge, WorkflowDagPlan, WorkflowCommunicationGraph, WorkflowGraphPlan, WorkflowPlan, WorkflowStatus, WorkflowNodeStatus, WorkflowRunParams, WorkflowRunResult, WorkflowStatusParams, WorkflowNodeRuntime, WorkflowStatusResult, WorkflowCancelParams, WorkflowCancelResult, WorkflowListParams, WorkflowListResult, WorkflowEvent;
|
|
1339
|
+
var init_workflow = __esm({
|
|
1340
|
+
"../protocol/dist/schemas/workflow.js"() {
|
|
1341
|
+
"use strict";
|
|
1342
|
+
init_common();
|
|
1343
|
+
ModelId = z16.string().min(1);
|
|
1344
|
+
TurnId = z16.string().min(1);
|
|
1345
|
+
ClientRequestId = z16.string().min(1);
|
|
1346
|
+
WorkflowId = z16.string().min(1);
|
|
1347
|
+
WorkflowNodeId = z16.string().min(1);
|
|
1348
|
+
WorkflowEdgeId = z16.string().min(1);
|
|
1349
|
+
WorkflowRoleId = z16.string().min(1);
|
|
1350
|
+
WorkflowNode = z16.object({
|
|
1351
|
+
nodeId: WorkflowNodeId,
|
|
1352
|
+
agent: AgentId,
|
|
1353
|
+
model: ModelId,
|
|
1354
|
+
role: WorkflowRoleId.optional(),
|
|
1355
|
+
input: z16.string().optional(),
|
|
1356
|
+
systemPrompt: z16.string().optional(),
|
|
1357
|
+
dependsOn: z16.array(WorkflowNodeId).optional(),
|
|
1358
|
+
sessionId: SessionId.optional(),
|
|
1359
|
+
agentConfig: z16.record(z16.unknown()).optional(),
|
|
1360
|
+
metadata: z16.record(z16.unknown()).optional()
|
|
1361
|
+
});
|
|
1362
|
+
WorkflowEdge = z16.object({
|
|
1363
|
+
edgeId: WorkflowEdgeId.optional(),
|
|
1364
|
+
from: WorkflowNodeId,
|
|
1365
|
+
to: WorkflowNodeId,
|
|
1366
|
+
label: z16.string().optional(),
|
|
1367
|
+
condition: z16.string().optional(),
|
|
1368
|
+
metadata: z16.record(z16.unknown()).optional()
|
|
1369
|
+
});
|
|
1370
|
+
WorkflowDagPlan = z16.object({
|
|
1371
|
+
mode: z16.literal("dag"),
|
|
1372
|
+
nodes: z16.array(WorkflowNode).min(1),
|
|
1373
|
+
edges: z16.array(WorkflowEdge).optional(),
|
|
1374
|
+
finalNodeId: WorkflowNodeId.optional()
|
|
1375
|
+
});
|
|
1376
|
+
WorkflowCommunicationGraph = z16.object({
|
|
1377
|
+
edges: z16.array(WorkflowEdge).default([]),
|
|
1378
|
+
allowSelfLoop: z16.boolean().default(false),
|
|
1379
|
+
maxIterations: z16.number().int().positive().default(12)
|
|
1380
|
+
});
|
|
1381
|
+
WorkflowGraphPlan = z16.object({
|
|
1382
|
+
mode: z16.literal("graph"),
|
|
1383
|
+
executor: z16.object({
|
|
1384
|
+
nodeId: WorkflowNodeId,
|
|
1385
|
+
agent: AgentId,
|
|
1386
|
+
model: ModelId,
|
|
1387
|
+
role: z16.literal("executor").default("executor"),
|
|
1388
|
+
systemPrompt: z16.string().optional(),
|
|
1389
|
+
agentConfig: z16.record(z16.unknown()).optional()
|
|
1390
|
+
}),
|
|
1391
|
+
workers: z16.array(WorkflowNode).min(1),
|
|
1392
|
+
communicationGraph: WorkflowCommunicationGraph
|
|
1393
|
+
});
|
|
1394
|
+
WorkflowPlan = z16.discriminatedUnion("mode", [WorkflowDagPlan, WorkflowGraphPlan]);
|
|
1395
|
+
WorkflowStatus = z16.enum(["queued", "running", "completed", "failed", "cancelled", "timeout"]);
|
|
1396
|
+
WorkflowNodeStatus = z16.enum(["pending", "ready", "running", "completed", "failed", "skipped", "cancelled"]);
|
|
1397
|
+
WorkflowRunParams = z16.object({
|
|
1398
|
+
project: ProjectId,
|
|
1399
|
+
worktreeId: z16.string().optional(),
|
|
1400
|
+
plan: WorkflowPlan,
|
|
1401
|
+
input: z16.string().optional(),
|
|
1402
|
+
clientRequestId: ClientRequestId.optional(),
|
|
1403
|
+
metadata: z16.record(z16.unknown()).optional()
|
|
1404
|
+
});
|
|
1405
|
+
WorkflowRunResult = z16.object({
|
|
1406
|
+
workflowId: WorkflowId,
|
|
1407
|
+
status: WorkflowStatus,
|
|
1408
|
+
createdAt: Timestamp
|
|
1409
|
+
});
|
|
1410
|
+
WorkflowStatusParams = z16.object({ workflowId: WorkflowId });
|
|
1411
|
+
WorkflowNodeRuntime = z16.object({
|
|
1412
|
+
nodeId: WorkflowNodeId,
|
|
1413
|
+
status: WorkflowNodeStatus,
|
|
1414
|
+
agent: AgentId,
|
|
1415
|
+
model: ModelId,
|
|
1416
|
+
role: WorkflowRoleId.optional(),
|
|
1417
|
+
sessionId: SessionId.optional(),
|
|
1418
|
+
turnId: TurnId.optional(),
|
|
1419
|
+
startedAt: Timestamp.optional(),
|
|
1420
|
+
completedAt: Timestamp.optional(),
|
|
1421
|
+
error: z16.string().optional()
|
|
1422
|
+
});
|
|
1423
|
+
WorkflowStatusResult = z16.object({
|
|
1424
|
+
workflowId: WorkflowId,
|
|
1425
|
+
status: WorkflowStatus,
|
|
1426
|
+
project: ProjectId,
|
|
1427
|
+
mode: z16.enum(["dag", "graph"]),
|
|
1428
|
+
nodes: z16.array(WorkflowNodeRuntime),
|
|
1429
|
+
createdAt: Timestamp,
|
|
1430
|
+
updatedAt: Timestamp,
|
|
1431
|
+
completedAt: Timestamp.optional(),
|
|
1432
|
+
error: z16.string().optional()
|
|
1433
|
+
});
|
|
1434
|
+
WorkflowCancelParams = z16.object({ workflowId: WorkflowId, reason: z16.string().optional() });
|
|
1435
|
+
WorkflowCancelResult = z16.object({ workflowId: WorkflowId, status: z16.literal("cancelled") });
|
|
1436
|
+
WorkflowListParams = z16.object({
|
|
1437
|
+
status: WorkflowStatus.optional(),
|
|
1438
|
+
limit: z16.number().int().positive().max(100).default(50).optional(),
|
|
1439
|
+
cursor: z16.string().optional()
|
|
1440
|
+
});
|
|
1441
|
+
WorkflowListResult = z16.object({ workflows: z16.array(WorkflowStatusResult), nextCursor: z16.string().optional() });
|
|
1442
|
+
WorkflowEvent = z16.object({
|
|
1443
|
+
workflowId: WorkflowId,
|
|
1444
|
+
seq: z16.number().int().nonnegative(),
|
|
1445
|
+
type: z16.enum(["workflow.status", "node.status", "node.stream", "edge.route", "executor.decision"]),
|
|
1446
|
+
nodeId: WorkflowNodeId.optional(),
|
|
1447
|
+
sessionId: SessionId.optional(),
|
|
1448
|
+
turnId: TurnId.optional(),
|
|
1449
|
+
agent: AgentId.optional(),
|
|
1450
|
+
model: ModelId.optional(),
|
|
1451
|
+
role: WorkflowRoleId.optional(),
|
|
1452
|
+
status: z16.union([WorkflowStatus, WorkflowNodeStatus]).optional(),
|
|
1453
|
+
payload: z16.record(z16.unknown()).optional(),
|
|
1454
|
+
timestamp: Timestamp
|
|
1455
|
+
});
|
|
1456
|
+
}
|
|
1457
|
+
});
|
|
1458
|
+
|
|
1459
|
+
// ../protocol/dist/schemas/jsonrpc.js
|
|
1460
|
+
import { z as z17 } from "zod";
|
|
1315
1461
|
var JsonRpcVersion, JsonRpcId, JsonRpcRequest, JsonRpcNotification, JsonRpcSuccess, JsonRpcErrorObject, JsonRpcError, JsonRpcMessage, JSON_RPC_CODES;
|
|
1316
1462
|
var init_jsonrpc = __esm({
|
|
1317
1463
|
"../protocol/dist/schemas/jsonrpc.js"() {
|
|
1318
1464
|
"use strict";
|
|
1319
1465
|
init_common();
|
|
1320
|
-
JsonRpcVersion =
|
|
1321
|
-
JsonRpcId =
|
|
1322
|
-
JsonRpcRequest =
|
|
1466
|
+
JsonRpcVersion = z17.literal("2.0");
|
|
1467
|
+
JsonRpcId = z17.union([z17.string(), z17.number()]);
|
|
1468
|
+
JsonRpcRequest = z17.object({
|
|
1323
1469
|
jsonrpc: JsonRpcVersion,
|
|
1324
1470
|
id: JsonRpcId,
|
|
1325
|
-
method:
|
|
1326
|
-
params:
|
|
1471
|
+
method: z17.string(),
|
|
1472
|
+
params: z17.unknown().optional()
|
|
1327
1473
|
});
|
|
1328
|
-
JsonRpcNotification =
|
|
1474
|
+
JsonRpcNotification = z17.object({
|
|
1329
1475
|
jsonrpc: JsonRpcVersion,
|
|
1330
|
-
method:
|
|
1331
|
-
params:
|
|
1476
|
+
method: z17.string(),
|
|
1477
|
+
params: z17.unknown().optional()
|
|
1332
1478
|
});
|
|
1333
|
-
JsonRpcSuccess =
|
|
1479
|
+
JsonRpcSuccess = z17.object({
|
|
1334
1480
|
jsonrpc: JsonRpcVersion,
|
|
1335
1481
|
id: JsonRpcId,
|
|
1336
|
-
result:
|
|
1482
|
+
result: z17.unknown()
|
|
1337
1483
|
});
|
|
1338
|
-
JsonRpcErrorObject =
|
|
1484
|
+
JsonRpcErrorObject = z17.object({
|
|
1339
1485
|
/** JSON-RPC 传输级 code(-32700..-32600 保留;应用错误用 data.appCode 判别)。 */
|
|
1340
|
-
code:
|
|
1341
|
-
message:
|
|
1486
|
+
code: z17.number().int(),
|
|
1487
|
+
message: z17.string(),
|
|
1342
1488
|
data: PhononErrorData.optional()
|
|
1343
1489
|
});
|
|
1344
|
-
JsonRpcError =
|
|
1490
|
+
JsonRpcError = z17.object({
|
|
1345
1491
|
jsonrpc: JsonRpcVersion,
|
|
1346
1492
|
id: JsonRpcId.nullable(),
|
|
1347
1493
|
error: JsonRpcErrorObject
|
|
1348
1494
|
});
|
|
1349
|
-
JsonRpcMessage =
|
|
1495
|
+
JsonRpcMessage = z17.union([
|
|
1350
1496
|
JsonRpcRequest,
|
|
1351
1497
|
JsonRpcNotification,
|
|
1352
1498
|
JsonRpcSuccess,
|
|
@@ -1365,7 +1511,7 @@ var init_jsonrpc = __esm({
|
|
|
1365
1511
|
});
|
|
1366
1512
|
|
|
1367
1513
|
// ../protocol/dist/schemas/methods.js
|
|
1368
|
-
import { z as
|
|
1514
|
+
import { z as z18 } from "zod";
|
|
1369
1515
|
function parseParams(method, data) {
|
|
1370
1516
|
return METHODS[method].params.parse(data);
|
|
1371
1517
|
}
|
|
@@ -1385,7 +1531,8 @@ var init_methods = __esm({
|
|
|
1385
1531
|
init_device();
|
|
1386
1532
|
init_file();
|
|
1387
1533
|
init_env();
|
|
1388
|
-
|
|
1534
|
+
init_workflow();
|
|
1535
|
+
z_void = z18.undefined();
|
|
1389
1536
|
METHODS = {
|
|
1390
1537
|
// --- 握手(phonon 拨出后先发)---
|
|
1391
1538
|
"connect.hello": {
|
|
@@ -1663,6 +1810,43 @@ var init_methods = __esm({
|
|
|
1663
1810
|
kind: "request",
|
|
1664
1811
|
params: SkillListParams,
|
|
1665
1812
|
result: SkillListResult
|
|
1813
|
+
},
|
|
1814
|
+
"skill.dirs": {
|
|
1815
|
+
direction: "s2p",
|
|
1816
|
+
kind: "request",
|
|
1817
|
+
params: SkillDirsParams,
|
|
1818
|
+
result: SkillDirsResult
|
|
1819
|
+
},
|
|
1820
|
+
// --- L3 workflow orchestration (DAG / executor graph) ---
|
|
1821
|
+
"workflow.run": {
|
|
1822
|
+
direction: "s2p",
|
|
1823
|
+
kind: "request",
|
|
1824
|
+
params: WorkflowRunParams,
|
|
1825
|
+
result: WorkflowRunResult
|
|
1826
|
+
},
|
|
1827
|
+
"workflow.status": {
|
|
1828
|
+
direction: "s2p",
|
|
1829
|
+
kind: "request",
|
|
1830
|
+
params: WorkflowStatusParams,
|
|
1831
|
+
result: WorkflowStatusResult
|
|
1832
|
+
},
|
|
1833
|
+
"workflow.cancel": {
|
|
1834
|
+
direction: "s2p",
|
|
1835
|
+
kind: "request",
|
|
1836
|
+
params: WorkflowCancelParams,
|
|
1837
|
+
result: WorkflowCancelResult
|
|
1838
|
+
},
|
|
1839
|
+
"workflow.list": {
|
|
1840
|
+
direction: "s2p",
|
|
1841
|
+
kind: "request",
|
|
1842
|
+
params: WorkflowListParams,
|
|
1843
|
+
result: WorkflowListResult
|
|
1844
|
+
},
|
|
1845
|
+
"workflow.event": {
|
|
1846
|
+
direction: "p2s",
|
|
1847
|
+
kind: "notification",
|
|
1848
|
+
params: WorkflowEvent,
|
|
1849
|
+
result: z_void
|
|
1666
1850
|
}
|
|
1667
1851
|
};
|
|
1668
1852
|
METHOD_NAMES = Object.keys(METHODS);
|
|
@@ -1688,6 +1872,7 @@ var init_dist = __esm({
|
|
|
1688
1872
|
init_device();
|
|
1689
1873
|
init_file();
|
|
1690
1874
|
init_env();
|
|
1875
|
+
init_workflow();
|
|
1691
1876
|
init_jsonrpc();
|
|
1692
1877
|
init_methods();
|
|
1693
1878
|
}
|
|
@@ -1724,12 +1909,12 @@ var init_rpc = __esm({
|
|
|
1724
1909
|
requestRaw(method, params, timeoutMs = 12e4) {
|
|
1725
1910
|
const id = this.nextId++;
|
|
1726
1911
|
const msg = { jsonrpc: "2.0", id, method, params };
|
|
1727
|
-
return new Promise((
|
|
1912
|
+
return new Promise((resolve6, reject) => {
|
|
1728
1913
|
const timer = timeoutMs > 0 ? setTimeout(() => {
|
|
1729
1914
|
this.pending.delete(id);
|
|
1730
1915
|
reject(new PhononError("errInternal", `RPC timeout: ${method}`));
|
|
1731
1916
|
}, timeoutMs) : void 0;
|
|
1732
|
-
this.pending.set(id, { resolve:
|
|
1917
|
+
this.pending.set(id, { resolve: resolve6, reject, timer });
|
|
1733
1918
|
this.transport.send(JSON.stringify(msg));
|
|
1734
1919
|
});
|
|
1735
1920
|
}
|
|
@@ -2185,8 +2370,8 @@ var SessionEngine = class {
|
|
|
2185
2370
|
this.interactionWaiters.delete(requestId);
|
|
2186
2371
|
}
|
|
2187
2372
|
}
|
|
2188
|
-
registerInteractionWaiter(requestId,
|
|
2189
|
-
this.interactionWaiters.set(requestId,
|
|
2373
|
+
registerInteractionWaiter(requestId, resolve6) {
|
|
2374
|
+
this.interactionWaiters.set(requestId, resolve6);
|
|
2190
2375
|
}
|
|
2191
2376
|
list(tenantId, filter) {
|
|
2192
2377
|
const all = [];
|
|
@@ -2437,7 +2622,7 @@ var ProjectManager = class {
|
|
|
2437
2622
|
|
|
2438
2623
|
// ../core/dist/skill-manager.js
|
|
2439
2624
|
init_rpc();
|
|
2440
|
-
import { mkdir as mkdir2, rm as rm2, writeFile, readdir as readdir2, stat as stat2, mkdtemp, lstat } from "node:fs/promises";
|
|
2625
|
+
import { mkdir as mkdir2, rm as rm2, writeFile, readdir as readdir2, stat as stat2, mkdtemp, lstat, realpath } from "node:fs/promises";
|
|
2441
2626
|
import { existsSync as existsSync2 } from "node:fs";
|
|
2442
2627
|
import { join as join2, resolve as resolve2, sep } from "node:path";
|
|
2443
2628
|
import { tmpdir } from "node:os";
|
|
@@ -2540,6 +2725,36 @@ var SkillManager = class {
|
|
|
2540
2725
|
return true;
|
|
2541
2726
|
});
|
|
2542
2727
|
}
|
|
2728
|
+
async dirs(filter) {
|
|
2729
|
+
const rows = [];
|
|
2730
|
+
if (filter?.scope !== "project" && filter?.agent) {
|
|
2731
|
+
const adapter = this.registry.resolve(filter.agent);
|
|
2732
|
+
const root = adapter?.globalSkillDir?.(filter.agent);
|
|
2733
|
+
if (root)
|
|
2734
|
+
rows.push(...await this.listDirs(root, { scope: "global", agent: filter.agent }));
|
|
2735
|
+
}
|
|
2736
|
+
if (filter?.scope !== "global" && filter?.projectId) {
|
|
2737
|
+
const projPath = this.resolveProjectPath(filter.projectId);
|
|
2738
|
+
if (!projPath)
|
|
2739
|
+
throw new PhononError("errProjectNotFound", `project ${filter.projectId} not found`);
|
|
2740
|
+
rows.push(...await this.listDirs(join2(projPath, ".agent", "skills"), { scope: "project", projectId: filter.projectId }));
|
|
2741
|
+
}
|
|
2742
|
+
return rows;
|
|
2743
|
+
}
|
|
2744
|
+
async listDirs(root, base) {
|
|
2745
|
+
const rootPath = existsSync2(root) ? await realpath(root) : resolve2(root);
|
|
2746
|
+
if (!existsSync2(root))
|
|
2747
|
+
return [];
|
|
2748
|
+
const entries = await readdir2(root, { withFileTypes: true });
|
|
2749
|
+
const rows = [];
|
|
2750
|
+
for (const e of entries) {
|
|
2751
|
+
if (!e.isDirectory())
|
|
2752
|
+
continue;
|
|
2753
|
+
const full = join2(root, e.name);
|
|
2754
|
+
rows.push({ name: e.name, ...base, rootPath, path: await realpath(full), exists: true });
|
|
2755
|
+
}
|
|
2756
|
+
return rows.sort((a, b) => a.name.localeCompare(b.name));
|
|
2757
|
+
}
|
|
2543
2758
|
async installArchive(source, dest) {
|
|
2544
2759
|
if (source.format !== "tar.gz")
|
|
2545
2760
|
throw new PhononError("errSkillInstallFailed", `unsupported archive format: ${source.format}`);
|
|
@@ -3141,7 +3356,7 @@ var PhononStore = class {
|
|
|
3141
3356
|
|
|
3142
3357
|
// ../core/dist/file-manager.js
|
|
3143
3358
|
init_rpc();
|
|
3144
|
-
import { mkdir as mkdir3, readFile, readdir as readdir3, lstat as lstat2, realpath, writeFile as writeFile2 } from "node:fs/promises";
|
|
3359
|
+
import { mkdir as mkdir3, readFile, readdir as readdir3, lstat as lstat2, realpath as realpath2, writeFile as writeFile2 } from "node:fs/promises";
|
|
3145
3360
|
import { basename as basename2, dirname as dirname3, join as join4, resolve as resolve4, sep as sep2 } from "node:path";
|
|
3146
3361
|
var FileManager = class {
|
|
3147
3362
|
resolver;
|
|
@@ -3158,7 +3373,7 @@ var FileManager = class {
|
|
|
3158
3373
|
let cur = abs;
|
|
3159
3374
|
for (; ; ) {
|
|
3160
3375
|
try {
|
|
3161
|
-
const real = await
|
|
3376
|
+
const real = await realpath2(cur);
|
|
3162
3377
|
return suffix.length ? resolve4(real, ...suffix) : real;
|
|
3163
3378
|
} catch (e) {
|
|
3164
3379
|
if (e?.code !== "ENOENT")
|
|
@@ -3364,6 +3579,190 @@ async function commandExists(cmd) {
|
|
|
3364
3579
|
}
|
|
3365
3580
|
}
|
|
3366
3581
|
|
|
3582
|
+
// ../core/dist/workflow-engine.js
|
|
3583
|
+
init_rpc();
|
|
3584
|
+
var WorkflowEngine = class {
|
|
3585
|
+
opts;
|
|
3586
|
+
runs = /* @__PURE__ */ new Map();
|
|
3587
|
+
sessionToNode = /* @__PURE__ */ new Map();
|
|
3588
|
+
idSeq = 1;
|
|
3589
|
+
constructor(opts) {
|
|
3590
|
+
this.opts = opts;
|
|
3591
|
+
}
|
|
3592
|
+
async run(params) {
|
|
3593
|
+
const workflowId = `wf-${Date.now()}-${this.idSeq++}`;
|
|
3594
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3595
|
+
const nodes = this.initialNodes(params.plan);
|
|
3596
|
+
const run = { workflowId, tenantId: this.opts.tenantId, project: params.project, worktreeId: params.worktreeId, mode: params.plan.mode, plan: params.plan, input: params.input, status: "queued", nodes, createdAt: now, updatedAt: now, seq: 0 };
|
|
3597
|
+
this.runs.set(workflowId, run);
|
|
3598
|
+
this.emit(run, { type: "workflow.status", status: "queued" });
|
|
3599
|
+
void this.execute(run).catch((err) => this.fail(run, err));
|
|
3600
|
+
return { workflowId, status: run.status, createdAt: run.createdAt };
|
|
3601
|
+
}
|
|
3602
|
+
status(workflowId) {
|
|
3603
|
+
const run = this.get(workflowId);
|
|
3604
|
+
return this.toStatus(run);
|
|
3605
|
+
}
|
|
3606
|
+
list(filter) {
|
|
3607
|
+
const limit = filter?.limit ?? 50;
|
|
3608
|
+
const rows = [...this.runs.values()].filter((r) => !filter?.status || r.status === filter.status).slice(-limit).reverse();
|
|
3609
|
+
return { workflows: rows.map((r) => this.toStatus(r)) };
|
|
3610
|
+
}
|
|
3611
|
+
async cancel(workflowId, reason) {
|
|
3612
|
+
const run = this.get(workflowId);
|
|
3613
|
+
run.status = "cancelled";
|
|
3614
|
+
run.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3615
|
+
run.updatedAt = run.completedAt;
|
|
3616
|
+
for (const n of run.nodes) {
|
|
3617
|
+
if (n.sessionId && (n.status === "running" || n.status === "ready" || n.status === "pending")) {
|
|
3618
|
+
n.status = "cancelled";
|
|
3619
|
+
try {
|
|
3620
|
+
await this.opts.engine.terminate(this.opts.tenantId, n.sessionId);
|
|
3621
|
+
} catch {
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
this.emit(run, { type: "workflow.status", status: "cancelled", payload: { reason } });
|
|
3626
|
+
return { workflowId, status: "cancelled" };
|
|
3627
|
+
}
|
|
3628
|
+
onStreamEvent(ev) {
|
|
3629
|
+
const sessionId = ev.sessionId;
|
|
3630
|
+
if (!sessionId)
|
|
3631
|
+
return;
|
|
3632
|
+
const m = this.sessionToNode.get(sessionId);
|
|
3633
|
+
if (!m)
|
|
3634
|
+
return;
|
|
3635
|
+
const run = this.runs.get(m.workflowId);
|
|
3636
|
+
const node = run?.nodes.find((n) => n.nodeId === m.nodeId);
|
|
3637
|
+
if (!run || !node)
|
|
3638
|
+
return;
|
|
3639
|
+
this.emit(run, {
|
|
3640
|
+
type: "node.stream",
|
|
3641
|
+
nodeId: node.nodeId,
|
|
3642
|
+
sessionId,
|
|
3643
|
+
turnId: ev.turnId,
|
|
3644
|
+
agent: node.agent,
|
|
3645
|
+
model: node.model,
|
|
3646
|
+
role: node.role,
|
|
3647
|
+
payload: ev
|
|
3648
|
+
});
|
|
3649
|
+
}
|
|
3650
|
+
async execute(run) {
|
|
3651
|
+
run.status = "running";
|
|
3652
|
+
run.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3653
|
+
this.emit(run, { type: "workflow.status", status: "running" });
|
|
3654
|
+
if (run.plan.mode === "dag")
|
|
3655
|
+
await this.executeDag(run);
|
|
3656
|
+
else
|
|
3657
|
+
await this.executeGraph(run);
|
|
3658
|
+
if (!["cancelled", "failed"].includes(run.status)) {
|
|
3659
|
+
run.status = "completed";
|
|
3660
|
+
run.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3661
|
+
run.updatedAt = run.completedAt;
|
|
3662
|
+
this.emit(run, { type: "workflow.status", status: "completed" });
|
|
3663
|
+
}
|
|
3664
|
+
}
|
|
3665
|
+
async executeDag(run) {
|
|
3666
|
+
const plan = run.plan.mode === "dag" ? run.plan : void 0;
|
|
3667
|
+
if (!plan)
|
|
3668
|
+
return;
|
|
3669
|
+
const deps = /* @__PURE__ */ new Map();
|
|
3670
|
+
for (const n of plan.nodes)
|
|
3671
|
+
deps.set(n.nodeId, new Set(n.dependsOn ?? []));
|
|
3672
|
+
for (const e of plan.edges ?? [])
|
|
3673
|
+
deps.get(e.to)?.add(e.from);
|
|
3674
|
+
const done = /* @__PURE__ */ new Set();
|
|
3675
|
+
while (done.size < plan.nodes.length) {
|
|
3676
|
+
const ready = plan.nodes.filter((n) => !done.has(n.nodeId) && [...deps.get(n.nodeId) ?? []].every((d) => done.has(d)));
|
|
3677
|
+
if (ready.length === 0)
|
|
3678
|
+
throw new PhononError("errInvalidParams", "workflow DAG has a cycle or missing dependency");
|
|
3679
|
+
await Promise.all(ready.map((n) => this.executeNode(run, n.nodeId, n.agent, n.model, n.role, n.input ?? run.input ?? "", n.agentConfig)));
|
|
3680
|
+
for (const n of ready)
|
|
3681
|
+
done.add(n.nodeId);
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3684
|
+
async executeGraph(run) {
|
|
3685
|
+
const plan = run.plan.mode === "graph" ? run.plan : void 0;
|
|
3686
|
+
if (!plan)
|
|
3687
|
+
return;
|
|
3688
|
+
const prompt = [
|
|
3689
|
+
"You are the executor for a multi-agent graph workflow.",
|
|
3690
|
+
`Input: ${run.input ?? ""}`,
|
|
3691
|
+
`Workers: ${JSON.stringify(plan.workers.map((w) => ({ nodeId: w.nodeId, role: w.role, agent: w.agent, model: w.model })))}`,
|
|
3692
|
+
`Communication graph: ${JSON.stringify(plan.communicationGraph)}`,
|
|
3693
|
+
"Produce the first routing decision and final summary for this initial implementation."
|
|
3694
|
+
].join("\n\n");
|
|
3695
|
+
await this.executeNode(run, plan.executor.nodeId, plan.executor.agent, plan.executor.model, plan.executor.role, prompt, plan.executor.agentConfig);
|
|
3696
|
+
this.emit(run, { type: "executor.decision", nodeId: plan.executor.nodeId, payload: { initialImplementation: true } });
|
|
3697
|
+
}
|
|
3698
|
+
async executeNode(run, nodeId, agent, model, role, input, agentConfig) {
|
|
3699
|
+
const node = run.nodes.find((n) => n.nodeId === nodeId) ?? this.addNode(run, { nodeId, agent, model, role });
|
|
3700
|
+
node.status = "running";
|
|
3701
|
+
node.startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3702
|
+
run.updatedAt = node.startedAt;
|
|
3703
|
+
this.emit(run, { type: "node.status", nodeId, agent, model, role, status: "running" });
|
|
3704
|
+
try {
|
|
3705
|
+
const cwd = this.opts.resolveCwd(run.project, run.worktreeId);
|
|
3706
|
+
const created = await this.opts.engine.create({ tenantId: run.tenantId, project: run.project, worktreeId: run.worktreeId, cwd, agent, model, verbosity: "messages", agentConfig });
|
|
3707
|
+
node.sessionId = created.sessionId;
|
|
3708
|
+
this.sessionToNode.set(created.sessionId, { workflowId: run.workflowId, nodeId });
|
|
3709
|
+
const sent = await this.opts.engine.send(run.tenantId, created.sessionId, input, { environment: this.opts.env.resolveForExecution({ projectId: run.project, agent }) });
|
|
3710
|
+
node.turnId = sent.turnId;
|
|
3711
|
+
await this.waitIdle(run.tenantId, created.sessionId);
|
|
3712
|
+
node.status = "completed";
|
|
3713
|
+
node.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3714
|
+
run.updatedAt = node.completedAt;
|
|
3715
|
+
this.emit(run, { type: "node.status", nodeId, sessionId: node.sessionId, turnId: node.turnId, agent, model, role, status: "completed" });
|
|
3716
|
+
} catch (err) {
|
|
3717
|
+
node.status = "failed";
|
|
3718
|
+
node.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3719
|
+
node.error = err?.message ?? String(err);
|
|
3720
|
+
run.updatedAt = node.completedAt;
|
|
3721
|
+
this.emit(run, { type: "node.status", nodeId, agent, model, role, status: "failed", payload: { error: node.error } });
|
|
3722
|
+
throw err;
|
|
3723
|
+
}
|
|
3724
|
+
}
|
|
3725
|
+
async waitIdle(tenantId, sessionId) {
|
|
3726
|
+
for (; ; ) {
|
|
3727
|
+
const s = await this.opts.engine.status(tenantId, sessionId);
|
|
3728
|
+
if (s.status === "idle" || s.status === "terminated" || s.status === "paused")
|
|
3729
|
+
return;
|
|
3730
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
3731
|
+
}
|
|
3732
|
+
}
|
|
3733
|
+
initialNodes(plan) {
|
|
3734
|
+
const nodes = plan.mode === "dag" ? plan.nodes : [plan.executor, ...plan.workers];
|
|
3735
|
+
return nodes.map((n) => ({ nodeId: n.nodeId, status: "pending", agent: n.agent, model: n.model, role: n.role }));
|
|
3736
|
+
}
|
|
3737
|
+
addNode(run, n) {
|
|
3738
|
+
const node = { ...n, status: "pending" };
|
|
3739
|
+
run.nodes.push(node);
|
|
3740
|
+
return node;
|
|
3741
|
+
}
|
|
3742
|
+
get(workflowId) {
|
|
3743
|
+
const run = this.runs.get(workflowId);
|
|
3744
|
+
if (!run)
|
|
3745
|
+
throw new PhononError("errInvalidParams", `workflow ${workflowId} not found`);
|
|
3746
|
+
return run;
|
|
3747
|
+
}
|
|
3748
|
+
fail(run, err) {
|
|
3749
|
+
if (run.status === "cancelled")
|
|
3750
|
+
return;
|
|
3751
|
+
run.status = "failed";
|
|
3752
|
+
run.error = err?.message ?? String(err);
|
|
3753
|
+
run.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3754
|
+
run.updatedAt = run.completedAt;
|
|
3755
|
+
this.emit(run, { type: "workflow.status", status: "failed", payload: { error: run.error } });
|
|
3756
|
+
}
|
|
3757
|
+
toStatus(run) {
|
|
3758
|
+
return { workflowId: run.workflowId, status: run.status, project: run.project, mode: run.mode, nodes: run.nodes, createdAt: run.createdAt, updatedAt: run.updatedAt, completedAt: run.completedAt, error: run.error };
|
|
3759
|
+
}
|
|
3760
|
+
emit(run, partial) {
|
|
3761
|
+
const ev = { workflowId: run.workflowId, seq: run.seq++, timestamp: (/* @__PURE__ */ new Date()).toISOString(), ...partial };
|
|
3762
|
+
this.opts.emit(ev);
|
|
3763
|
+
}
|
|
3764
|
+
};
|
|
3765
|
+
|
|
3367
3766
|
// ../core/dist/env-manager.js
|
|
3368
3767
|
init_rpc();
|
|
3369
3768
|
function redact(value) {
|
|
@@ -3761,7 +4160,7 @@ ${message}`;
|
|
|
3761
4160
|
return void 0;
|
|
3762
4161
|
}
|
|
3763
4162
|
run(args, signal, environment) {
|
|
3764
|
-
return new Promise((
|
|
4163
|
+
return new Promise((resolve6, reject) => {
|
|
3765
4164
|
const child = spawn2("openclaw", args, { cwd: this.cwd, env: { ...process.env, ...environment ?? {} } });
|
|
3766
4165
|
this.current = child;
|
|
3767
4166
|
let out = "";
|
|
@@ -3779,9 +4178,9 @@ ${message}`;
|
|
|
3779
4178
|
signal?.removeEventListener("abort", onAbort);
|
|
3780
4179
|
this.current = void 0;
|
|
3781
4180
|
if (killed)
|
|
3782
|
-
return
|
|
4181
|
+
return resolve6(null);
|
|
3783
4182
|
if (code === 0)
|
|
3784
|
-
|
|
4183
|
+
resolve6(out);
|
|
3785
4184
|
else
|
|
3786
4185
|
reject(new Error(`openclaw exited ${code}: ${err.slice(0, 500)}`));
|
|
3787
4186
|
});
|
|
@@ -3833,12 +4232,12 @@ var OpenClawAdapter = class {
|
|
|
3833
4232
|
return new OpenClawSession(params.sessionId, params.model, params.cwd, openclawAgent);
|
|
3834
4233
|
}
|
|
3835
4234
|
probeVersion() {
|
|
3836
|
-
return new Promise((
|
|
4235
|
+
return new Promise((resolve6) => {
|
|
3837
4236
|
const child = spawn2("openclaw", ["--version"]);
|
|
3838
4237
|
let out = "";
|
|
3839
4238
|
child.stdout.on("data", (d) => out += d.toString());
|
|
3840
|
-
child.on("error", () =>
|
|
3841
|
-
child.on("close", (code) =>
|
|
4239
|
+
child.on("error", () => resolve6(null));
|
|
4240
|
+
child.on("close", (code) => resolve6(code === 0 ? out.trim() : null));
|
|
3842
4241
|
});
|
|
3843
4242
|
}
|
|
3844
4243
|
};
|
|
@@ -3871,7 +4270,7 @@ var GatewayClient = class {
|
|
|
3871
4270
|
return this.connectPromise;
|
|
3872
4271
|
}
|
|
3873
4272
|
doConnect() {
|
|
3874
|
-
return new Promise((
|
|
4273
|
+
return new Promise((resolve6, reject) => {
|
|
3875
4274
|
const wsUrl = this.config.baseUrl.replace(/^http/, "ws");
|
|
3876
4275
|
const ws = new WebSocket(wsUrl);
|
|
3877
4276
|
this.ws = ws;
|
|
@@ -3902,7 +4301,7 @@ var GatewayClient = class {
|
|
|
3902
4301
|
} else if (frame.type === "res" && frame.ok && frame.payload?.type === "hello-ok") {
|
|
3903
4302
|
handshakeDone = true;
|
|
3904
4303
|
this.connected = true;
|
|
3905
|
-
|
|
4304
|
+
resolve6();
|
|
3906
4305
|
} else if (frame.type === "res" && !frame.ok) {
|
|
3907
4306
|
reject(new Error(`handshake failed: ${JSON.stringify(frame.error)}`));
|
|
3908
4307
|
}
|
|
@@ -3948,13 +4347,13 @@ var GatewayClient = class {
|
|
|
3948
4347
|
async rpc(method, params, timeoutMs = 12e4) {
|
|
3949
4348
|
if (!this.connected)
|
|
3950
4349
|
await this.connect();
|
|
3951
|
-
return new Promise((
|
|
4350
|
+
return new Promise((resolve6, reject) => {
|
|
3952
4351
|
const id = randomUUID();
|
|
3953
4352
|
const timer = setTimeout(() => {
|
|
3954
4353
|
this.pending.delete(id);
|
|
3955
4354
|
reject(new Error(`RPC timeout: ${method}`));
|
|
3956
4355
|
}, timeoutMs);
|
|
3957
|
-
this.pending.set(id, { resolve:
|
|
4356
|
+
this.pending.set(id, { resolve: resolve6, reject, timer });
|
|
3958
4357
|
this.ws.send(JSON.stringify({ type: "req", id, method, params }));
|
|
3959
4358
|
});
|
|
3960
4359
|
}
|
|
@@ -4081,14 +4480,14 @@ var GatewaySession = class {
|
|
|
4081
4480
|
|
|
4082
4481
|
${input}`;
|
|
4083
4482
|
}
|
|
4084
|
-
await new Promise((
|
|
4483
|
+
await new Promise((resolve6) => {
|
|
4085
4484
|
let settled = false;
|
|
4086
4485
|
const finish = () => {
|
|
4087
4486
|
if (settled)
|
|
4088
4487
|
return;
|
|
4089
4488
|
settled = true;
|
|
4090
4489
|
clearTimeout(guard);
|
|
4091
|
-
|
|
4490
|
+
resolve6();
|
|
4092
4491
|
};
|
|
4093
4492
|
this.activeTurn = { turnId, emit, verbosity: opts.verbosity, done: finish, acc: "" };
|
|
4094
4493
|
this.gw.rpc("chat.send", {
|
|
@@ -4349,7 +4748,7 @@ var PhononClient = class {
|
|
|
4349
4748
|
}
|
|
4350
4749
|
/** 连接并完成握手,resolve 后即可接收 server 的 session.* 下发。 */
|
|
4351
4750
|
connect() {
|
|
4352
|
-
return new Promise((
|
|
4751
|
+
return new Promise((resolve6, reject) => {
|
|
4353
4752
|
const ws = new WebSocket2(this.serverUrl);
|
|
4354
4753
|
this.ws = ws;
|
|
4355
4754
|
const transport = {
|
|
@@ -4391,7 +4790,7 @@ var PhononClient = class {
|
|
|
4391
4790
|
if (wAck && wAck.length > 0) {
|
|
4392
4791
|
conn.replayPending(wAck.map((a) => ({ sessionId: a.sessionId, fromSeq: a.lastSeq })));
|
|
4393
4792
|
}
|
|
4394
|
-
|
|
4793
|
+
resolve6({ tenantId: welcome.tenantId });
|
|
4395
4794
|
} catch (err) {
|
|
4396
4795
|
reject(err);
|
|
4397
4796
|
}
|
|
@@ -4461,12 +4860,12 @@ var HookBridge = class {
|
|
|
4461
4860
|
this.token = opts?.token;
|
|
4462
4861
|
}
|
|
4463
4862
|
listen(port = 4318, host = "127.0.0.1") {
|
|
4464
|
-
return new Promise((
|
|
4863
|
+
return new Promise((resolve6) => {
|
|
4465
4864
|
const server = createServer((req, res) => this.onRequest(req, res));
|
|
4466
4865
|
this.server = server;
|
|
4467
4866
|
server.listen(port, host, () => {
|
|
4468
4867
|
const addr = server.address();
|
|
4469
|
-
|
|
4868
|
+
resolve6(typeof addr === "object" && addr ? addr.port : port);
|
|
4470
4869
|
});
|
|
4471
4870
|
});
|
|
4472
4871
|
}
|
|
@@ -4519,10 +4918,10 @@ var HookBridge = class {
|
|
|
4519
4918
|
});
|
|
4520
4919
|
}
|
|
4521
4920
|
close() {
|
|
4522
|
-
return new Promise((
|
|
4921
|
+
return new Promise((resolve6) => {
|
|
4523
4922
|
if (!this.server)
|
|
4524
|
-
return
|
|
4525
|
-
this.server.close(() =>
|
|
4923
|
+
return resolve6();
|
|
4924
|
+
this.server.close(() => resolve6());
|
|
4526
4925
|
});
|
|
4527
4926
|
}
|
|
4528
4927
|
};
|
|
@@ -4707,7 +5106,7 @@ function normalizeOpenAiModels(data) {
|
|
|
4707
5106
|
return out;
|
|
4708
5107
|
}
|
|
4709
5108
|
function fetchJson(url, headers) {
|
|
4710
|
-
return new Promise((
|
|
5109
|
+
return new Promise((resolve6, reject) => {
|
|
4711
5110
|
const u = new URL(url);
|
|
4712
5111
|
const req = (u.protocol === "http:" ? import("node:http") : import("node:https")).then((mod) => mod.request(url, { method: "GET", headers, timeout: 5e3 }, (res) => {
|
|
4713
5112
|
let body = "";
|
|
@@ -4719,7 +5118,7 @@ function fetchJson(url, headers) {
|
|
|
4719
5118
|
return;
|
|
4720
5119
|
}
|
|
4721
5120
|
try {
|
|
4722
|
-
|
|
5121
|
+
resolve6(JSON.parse(body));
|
|
4723
5122
|
} catch (e) {
|
|
4724
5123
|
reject(e);
|
|
4725
5124
|
}
|
|
@@ -4781,7 +5180,7 @@ ${prompt}`;
|
|
|
4781
5180
|
await this.run(args, prompt, turnId, emit, opts);
|
|
4782
5181
|
}
|
|
4783
5182
|
run(args, stdin, turnId, emit, opts) {
|
|
4784
|
-
return new Promise((
|
|
5183
|
+
return new Promise((resolve6) => {
|
|
4785
5184
|
const child = spawn3(this.env.binPath ?? "codex", args, {
|
|
4786
5185
|
cwd: this.cwd,
|
|
4787
5186
|
shell: process.platform === "win32",
|
|
@@ -4802,7 +5201,7 @@ ${prompt}`;
|
|
|
4802
5201
|
} else {
|
|
4803
5202
|
emit({ type: "result", sessionId: this.sessionId, turnId, seq: 0, at: (/* @__PURE__ */ new Date()).toISOString(), text, status, final: true });
|
|
4804
5203
|
}
|
|
4805
|
-
|
|
5204
|
+
resolve6();
|
|
4806
5205
|
};
|
|
4807
5206
|
const guard = setTimeout(() => finish("timeout", acc), 18e5);
|
|
4808
5207
|
opts.signal?.addEventListener("abort", () => {
|
|
@@ -4934,12 +5333,12 @@ var CodexAdapter = class {
|
|
|
4934
5333
|
return base.length > 0 ? base : CODEX_FALLBACK_MODELS;
|
|
4935
5334
|
}
|
|
4936
5335
|
probeVersion() {
|
|
4937
|
-
return new Promise((
|
|
5336
|
+
return new Promise((resolve6) => {
|
|
4938
5337
|
const child = spawn3(this.env.binPath ?? "codex", ["--version"], { shell: process.platform === "win32" });
|
|
4939
5338
|
let out = "";
|
|
4940
5339
|
child.stdout.on("data", (d) => out += d.toString());
|
|
4941
|
-
child.on("error", () =>
|
|
4942
|
-
child.on("close", (code) =>
|
|
5340
|
+
child.on("error", () => resolve6(null));
|
|
5341
|
+
child.on("close", (code) => resolve6(code === 0 ? out.trim() : null));
|
|
4943
5342
|
});
|
|
4944
5343
|
}
|
|
4945
5344
|
};
|
|
@@ -5015,7 +5414,7 @@ ${message}`;
|
|
|
5015
5414
|
await this.run(args, turnId, emit, opts);
|
|
5016
5415
|
}
|
|
5017
5416
|
run(args, turnId, emit, opts) {
|
|
5018
|
-
return new Promise((
|
|
5417
|
+
return new Promise((resolve6) => {
|
|
5019
5418
|
const child = spawn4(this.bin, args, { cwd: this.cwd, stdio: ["ignore", "pipe", "pipe"], env: { ...process.env, ...opts.environment ?? {} } });
|
|
5020
5419
|
this.current = child;
|
|
5021
5420
|
let buf = "";
|
|
@@ -5032,7 +5431,7 @@ ${message}`;
|
|
|
5032
5431
|
} else {
|
|
5033
5432
|
emit({ type: "result", sessionId: this.sessionId, turnId, seq: 0, at: (/* @__PURE__ */ new Date()).toISOString(), text, status, final: true });
|
|
5034
5433
|
}
|
|
5035
|
-
|
|
5434
|
+
resolve6();
|
|
5036
5435
|
};
|
|
5037
5436
|
const guard = setTimeout(() => finish("timeout", acc), 18e5);
|
|
5038
5437
|
opts.signal?.addEventListener("abort", () => {
|
|
@@ -5163,12 +5562,12 @@ var OpenCodeAdapter = class {
|
|
|
5163
5562
|
return new OpenCodeSession(params.sessionId, model, params.cwd, this.bin);
|
|
5164
5563
|
}
|
|
5165
5564
|
probeVersion() {
|
|
5166
|
-
return new Promise((
|
|
5565
|
+
return new Promise((resolve6) => {
|
|
5167
5566
|
const child = spawn4(this.bin, ["--version"]);
|
|
5168
5567
|
let out = "";
|
|
5169
5568
|
child.stdout.on("data", (d) => out += d.toString());
|
|
5170
|
-
child.on("error", () =>
|
|
5171
|
-
child.on("close", (code) =>
|
|
5569
|
+
child.on("error", () => resolve6(null));
|
|
5570
|
+
child.on("close", (code) => resolve6(code === 0 ? out.trim() : null));
|
|
5172
5571
|
});
|
|
5173
5572
|
}
|
|
5174
5573
|
};
|
|
@@ -5233,7 +5632,7 @@ function parseHermesConfig(configPath = join9(homedir7(), ".hermes", "config.yam
|
|
|
5233
5632
|
return { defaultModel, provider, catalogUrl };
|
|
5234
5633
|
}
|
|
5235
5634
|
function fetchHermesCatalogModels(url, provider) {
|
|
5236
|
-
return new Promise((
|
|
5635
|
+
return new Promise((resolve6) => {
|
|
5237
5636
|
const u = new URL(url);
|
|
5238
5637
|
const reqMod = u.protocol === "http:" ? import("node:http") : import("node:https");
|
|
5239
5638
|
reqMod.then((mod) => {
|
|
@@ -5247,21 +5646,21 @@ function fetchHermesCatalogModels(url, provider) {
|
|
|
5247
5646
|
const providers = data.providers ?? {};
|
|
5248
5647
|
const rows = provider ? providers[provider]?.models ?? [] : Object.values(providers).flatMap((p) => p.models ?? []);
|
|
5249
5648
|
const seen = /* @__PURE__ */ new Set();
|
|
5250
|
-
|
|
5649
|
+
resolve6(rows.flatMap((m) => {
|
|
5251
5650
|
if (!m.id || seen.has(m.id))
|
|
5252
5651
|
return [];
|
|
5253
5652
|
seen.add(m.id);
|
|
5254
5653
|
return [{ id: m.id, ...m.description ? { displayName: m.description } : {}, available: true }];
|
|
5255
5654
|
}));
|
|
5256
5655
|
} catch {
|
|
5257
|
-
|
|
5656
|
+
resolve6([]);
|
|
5258
5657
|
}
|
|
5259
5658
|
});
|
|
5260
5659
|
});
|
|
5261
5660
|
req.on("timeout", () => req.destroy());
|
|
5262
|
-
req.on("error", () =>
|
|
5661
|
+
req.on("error", () => resolve6([]));
|
|
5263
5662
|
req.end();
|
|
5264
|
-
}, () =>
|
|
5663
|
+
}, () => resolve6([]));
|
|
5265
5664
|
});
|
|
5266
5665
|
}
|
|
5267
5666
|
var HermesSession = class {
|
|
@@ -5309,7 +5708,7 @@ ${prompt}`;
|
|
|
5309
5708
|
await this.run(args, turnId, emit, opts);
|
|
5310
5709
|
}
|
|
5311
5710
|
run(args, turnId, emit, opts) {
|
|
5312
|
-
return new Promise((
|
|
5711
|
+
return new Promise((resolve6) => {
|
|
5313
5712
|
const child = spawn5(this.env.binPath ?? "hermes", args, {
|
|
5314
5713
|
cwd: this.cwd,
|
|
5315
5714
|
shell: process.platform === "win32",
|
|
@@ -5332,7 +5731,7 @@ ${prompt}`;
|
|
|
5332
5731
|
emit({ type: "message", sessionId: this.sessionId, turnId, seq: 0, at: (/* @__PURE__ */ new Date()).toISOString(), role: "assistant", text, delta: false });
|
|
5333
5732
|
emit({ type: "result", sessionId: this.sessionId, turnId, seq: 0, at: (/* @__PURE__ */ new Date()).toISOString(), text, status, final: true });
|
|
5334
5733
|
}
|
|
5335
|
-
|
|
5734
|
+
resolve6();
|
|
5336
5735
|
};
|
|
5337
5736
|
const guard = setTimeout(() => finish("timeout", out), 18e5);
|
|
5338
5737
|
opts.signal?.addEventListener("abort", () => {
|
|
@@ -5492,11 +5891,11 @@ var HermesAdapter = class {
|
|
|
5492
5891
|
}
|
|
5493
5892
|
/** 枚举 Hermes profile(去 ANSI 色解析 profile list)。 */
|
|
5494
5893
|
listProfiles() {
|
|
5495
|
-
return new Promise((
|
|
5894
|
+
return new Promise((resolve6) => {
|
|
5496
5895
|
const child = spawn5(this.env.binPath ?? "hermes", ["profile", "list"], { shell: process.platform === "win32" });
|
|
5497
5896
|
let out = "";
|
|
5498
5897
|
child.stdout.on("data", (d) => out += d.toString());
|
|
5499
|
-
child.on("error", () =>
|
|
5898
|
+
child.on("error", () => resolve6([{ name: this.defaultProfile }]));
|
|
5500
5899
|
child.on("close", () => {
|
|
5501
5900
|
const clean = out.replace(/\u001b\[[0-9;]*m/g, "");
|
|
5502
5901
|
const names = [];
|
|
@@ -5507,17 +5906,17 @@ var HermesAdapter = class {
|
|
|
5507
5906
|
names.push({ name: m[1], model: rest[0] || void 0 });
|
|
5508
5907
|
}
|
|
5509
5908
|
}
|
|
5510
|
-
|
|
5909
|
+
resolve6(names.length > 0 ? names : [{ name: this.defaultProfile }]);
|
|
5511
5910
|
});
|
|
5512
5911
|
});
|
|
5513
5912
|
}
|
|
5514
5913
|
probeVersion() {
|
|
5515
|
-
return new Promise((
|
|
5914
|
+
return new Promise((resolve6) => {
|
|
5516
5915
|
const child = spawn5(this.env.binPath ?? "hermes", ["--version"], { shell: process.platform === "win32" });
|
|
5517
5916
|
let out = "";
|
|
5518
5917
|
child.stdout.on("data", (d) => out += d.toString());
|
|
5519
|
-
child.on("error", () =>
|
|
5520
|
-
child.on("close", (code) =>
|
|
5918
|
+
child.on("error", () => resolve6(null));
|
|
5919
|
+
child.on("close", (code) => resolve6(code === 0 ? out.trim().split("\n")[0] ?? "hermes" : null));
|
|
5521
5920
|
});
|
|
5522
5921
|
}
|
|
5523
5922
|
};
|
|
@@ -5740,7 +6139,7 @@ ${prompt}`;
|
|
|
5740
6139
|
await this.run(args, envelope, turnId, emit, opts);
|
|
5741
6140
|
}
|
|
5742
6141
|
run(args, stdin, turnId, emit, opts) {
|
|
5743
|
-
return new Promise((
|
|
6142
|
+
return new Promise((resolve6) => {
|
|
5744
6143
|
const childEnv = {};
|
|
5745
6144
|
for (const [k, v] of Object.entries(process.env)) {
|
|
5746
6145
|
if (k === "CLAUDECODE" || k.startsWith("CLAUDECODE_") || k.startsWith("CLAUDE_CODE_"))
|
|
@@ -5772,7 +6171,7 @@ ${prompt}`;
|
|
|
5772
6171
|
} else {
|
|
5773
6172
|
emit({ type: "result", sessionId: this.sessionId, turnId, seq: 0, at: (/* @__PURE__ */ new Date()).toISOString(), text, status, final: true });
|
|
5774
6173
|
}
|
|
5775
|
-
|
|
6174
|
+
resolve6();
|
|
5776
6175
|
};
|
|
5777
6176
|
const guard = setTimeout(() => finish("timeout", acc), 18e5);
|
|
5778
6177
|
opts.signal?.addEventListener("abort", () => {
|
|
@@ -5889,12 +6288,12 @@ var ClaudeCodeAdapter = class {
|
|
|
5889
6288
|
return new ClaudeCodeSession(params.sessionId, params.model, params.cwd, this.env);
|
|
5890
6289
|
}
|
|
5891
6290
|
probeVersion() {
|
|
5892
|
-
return new Promise((
|
|
6291
|
+
return new Promise((resolve6) => {
|
|
5893
6292
|
const child = spawn6(this.env.binPath ?? "claude", ["--version"], { shell: process.platform === "win32" });
|
|
5894
6293
|
let out = "";
|
|
5895
6294
|
child.stdout.on("data", (d) => out += d.toString());
|
|
5896
|
-
child.on("error", () =>
|
|
5897
|
-
child.on("close", (code) =>
|
|
6295
|
+
child.on("error", () => resolve6(null));
|
|
6296
|
+
child.on("close", (code) => resolve6(code === 0 ? out.trim() : null));
|
|
5898
6297
|
});
|
|
5899
6298
|
}
|
|
5900
6299
|
};
|
|
@@ -5913,7 +6312,9 @@ var MUTATING_METHODS = /* @__PURE__ */ new Set([
|
|
|
5913
6312
|
"file.write",
|
|
5914
6313
|
"file.mkdir",
|
|
5915
6314
|
"env.set",
|
|
5916
|
-
"env.delete"
|
|
6315
|
+
"env.delete",
|
|
6316
|
+
"workflow.run",
|
|
6317
|
+
"workflow.cancel"
|
|
5917
6318
|
]);
|
|
5918
6319
|
var PhononConnection = class {
|
|
5919
6320
|
tenantId;
|
|
@@ -5929,6 +6330,7 @@ var PhononConnection = class {
|
|
|
5929
6330
|
files;
|
|
5930
6331
|
env;
|
|
5931
6332
|
obs;
|
|
6333
|
+
workflows;
|
|
5932
6334
|
/** 该 tenant 绑定的默认项目工作目录解析器(v0 简化:projectId 即绝对路径或映射)。 */
|
|
5933
6335
|
resolveProjectCwd;
|
|
5934
6336
|
constructor(opts) {
|
|
@@ -5939,6 +6341,7 @@ var PhononConnection = class {
|
|
|
5939
6341
|
this.idempotency = new IdempotencyStore({ store: this.store });
|
|
5940
6342
|
this.outbox = new Outbox({ store: this.store, tenantId: opts.tenantId });
|
|
5941
6343
|
this.engine = new SessionEngine(opts.registry, (event) => {
|
|
6344
|
+
this.workflows?.onStreamEvent(event);
|
|
5942
6345
|
this.outbox.enqueue(event);
|
|
5943
6346
|
this.peer.notifyRaw("stream.event", event);
|
|
5944
6347
|
}, opts.obs, this.store);
|
|
@@ -5968,6 +6371,13 @@ var PhononConnection = class {
|
|
|
5968
6371
|
this.env = new EnvManager(this.store, { allowReveal: () => this.policy.allowEnvReveal() });
|
|
5969
6372
|
this.resolveProjectCwd = opts.resolveProjectCwd ?? ((p) => this.projects.resolveCwd(p));
|
|
5970
6373
|
this.peer = new RpcPeer(opts.transport, (method, params) => this.dispatch(method, params));
|
|
6374
|
+
this.workflows = new WorkflowEngine({
|
|
6375
|
+
tenantId: this.tenantId,
|
|
6376
|
+
engine: this.engine,
|
|
6377
|
+
resolveCwd: (projectId, worktreeId) => this.projects.resolveCwd(projectId, worktreeId),
|
|
6378
|
+
env: this.env,
|
|
6379
|
+
emit: (event) => this.peer.notifyRaw("workflow.event", event)
|
|
6380
|
+
});
|
|
5971
6381
|
}
|
|
5972
6382
|
/** 喂入收到的文本。 */
|
|
5973
6383
|
handle(data) {
|
|
@@ -6209,6 +6619,17 @@ var PhononConnection = class {
|
|
|
6209
6619
|
}
|
|
6210
6620
|
case "skill.list":
|
|
6211
6621
|
return { skills: this.skills.list({ agent: p.agent, scope: p.scope, projectId: p.projectId }) };
|
|
6622
|
+
case "skill.dirs":
|
|
6623
|
+
return { directories: await this.skills.dirs({ agent: p.agent, scope: p.scope, projectId: p.projectId }) };
|
|
6624
|
+
// ---- L3 workflow orchestration ----
|
|
6625
|
+
case "workflow.run":
|
|
6626
|
+
return this.workflows.run({ project: p.project, worktreeId: p.worktreeId, plan: p.plan, input: p.input, metadata: p.metadata });
|
|
6627
|
+
case "workflow.status":
|
|
6628
|
+
return this.workflows.status(p.workflowId);
|
|
6629
|
+
case "workflow.cancel":
|
|
6630
|
+
return this.workflows.cancel(p.workflowId, p.reason);
|
|
6631
|
+
case "workflow.list":
|
|
6632
|
+
return this.workflows.list(p);
|
|
6212
6633
|
// ---- 连接/可靠性(s2p) ----
|
|
6213
6634
|
case "stream.ack": {
|
|
6214
6635
|
this.outbox.ack(p.sessionId, p.lastSeq);
|
|
@@ -6249,9 +6670,9 @@ function readOpenClawGatewayToken() {
|
|
|
6249
6670
|
|
|
6250
6671
|
// src/commands.ts
|
|
6251
6672
|
import { spawnSync } from "node:child_process";
|
|
6252
|
-
import { existsSync as existsSync12, cpSync, mkdirSync as mkdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync7 } from "node:fs";
|
|
6673
|
+
import { existsSync as existsSync12, cpSync, mkdirSync as mkdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync7, chmodSync as chmodSync3 } from "node:fs";
|
|
6253
6674
|
import { homedir as homedir10, platform as platform2 } from "node:os";
|
|
6254
|
-
import { join as join12, dirname as dirname5, delimiter } from "node:path";
|
|
6675
|
+
import { join as join12, dirname as dirname5, delimiter, resolve as resolve5 } from "node:path";
|
|
6255
6676
|
import { fileURLToPath } from "node:url";
|
|
6256
6677
|
function probe(bin, args = ["--version"]) {
|
|
6257
6678
|
const r = spawnSync(bin, args, { timeout: 8e3, shell: platform2() === "win32" });
|
|
@@ -6334,13 +6755,13 @@ var ObsServer = class {
|
|
|
6334
6755
|
deps.bus.onEvent((e) => this.broadcast(e));
|
|
6335
6756
|
}
|
|
6336
6757
|
listen(port = 4319, host = "127.0.0.1") {
|
|
6337
|
-
return new Promise((
|
|
6758
|
+
return new Promise((resolve6) => {
|
|
6338
6759
|
const server = createServer2((req, res) => this.handle(req, res));
|
|
6339
6760
|
this.server = server;
|
|
6340
6761
|
server.listen(port, host, () => {
|
|
6341
6762
|
const addr = server.address();
|
|
6342
6763
|
this.actualPort = typeof addr === "object" && addr ? addr.port : port;
|
|
6343
|
-
|
|
6764
|
+
resolve6(this.actualPort);
|
|
6344
6765
|
});
|
|
6345
6766
|
});
|
|
6346
6767
|
}
|
|
@@ -6418,11 +6839,11 @@ var ObsServer = class {
|
|
|
6418
6839
|
return this.actualPort;
|
|
6419
6840
|
}
|
|
6420
6841
|
close() {
|
|
6421
|
-
return new Promise((
|
|
6842
|
+
return new Promise((resolve6) => {
|
|
6422
6843
|
for (const c of this.sseClients) c.end();
|
|
6423
6844
|
this.sseClients.clear();
|
|
6424
|
-
if (!this.server) return
|
|
6425
|
-
this.server.close(() =>
|
|
6845
|
+
if (!this.server) return resolve6();
|
|
6846
|
+
this.server.close(() => resolve6());
|
|
6426
6847
|
});
|
|
6427
6848
|
}
|
|
6428
6849
|
};
|