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/cli.js
CHANGED
|
@@ -940,7 +940,7 @@ var init_project = __esm({
|
|
|
940
940
|
|
|
941
941
|
// ../protocol/dist/schemas/skill.js
|
|
942
942
|
import { z as z10 } from "zod";
|
|
943
|
-
var SkillScope, SkillSource, SkillDescriptor, SkillInstallParams, SkillInstallResult, SkillUninstallParams, SkillUninstallResult, SkillListParams, SkillListResult;
|
|
943
|
+
var SkillScope, SkillSource, SkillDescriptor, SkillInstallParams, SkillInstallResult, SkillUninstallParams, SkillUninstallResult, SkillListParams, SkillListResult, SkillDirsParams, SkillDirectoryDescriptor, SkillDirsResult;
|
|
944
944
|
var init_skill = __esm({
|
|
945
945
|
"../protocol/dist/schemas/skill.js"() {
|
|
946
946
|
"use strict";
|
|
@@ -1028,6 +1028,29 @@ var init_skill = __esm({
|
|
|
1028
1028
|
SkillListResult = z10.object({
|
|
1029
1029
|
skills: z10.array(SkillDescriptor)
|
|
1030
1030
|
});
|
|
1031
|
+
SkillDirsParams = z10.object({
|
|
1032
|
+
/** 可选:global scope 的目标 agent。 */
|
|
1033
|
+
agent: AgentId.optional(),
|
|
1034
|
+
/** 可选:project scope 的目标项目。 */
|
|
1035
|
+
projectId: ProjectId.optional(),
|
|
1036
|
+
/** 可选:只查 global 或 project;不传时按 agent/projectId 返回可查范围。 */
|
|
1037
|
+
scope: SkillScope.optional()
|
|
1038
|
+
});
|
|
1039
|
+
SkillDirectoryDescriptor = z10.object({
|
|
1040
|
+
/** skill 目录名。 */
|
|
1041
|
+
name: z10.string().min(1),
|
|
1042
|
+
scope: SkillScope,
|
|
1043
|
+
agent: AgentId.optional(),
|
|
1044
|
+
projectId: ProjectId.optional(),
|
|
1045
|
+
/** scope 根目录(global skill root 或 <project>/.agent/skills)。 */
|
|
1046
|
+
rootPath: z10.string().min(1),
|
|
1047
|
+
/** skill 目录真实本机路径。 */
|
|
1048
|
+
path: z10.string().min(1),
|
|
1049
|
+
exists: z10.boolean()
|
|
1050
|
+
});
|
|
1051
|
+
SkillDirsResult = z10.object({
|
|
1052
|
+
directories: z10.array(SkillDirectoryDescriptor)
|
|
1053
|
+
});
|
|
1031
1054
|
}
|
|
1032
1055
|
});
|
|
1033
1056
|
|
|
@@ -1311,43 +1334,166 @@ var init_env = __esm({
|
|
|
1311
1334
|
}
|
|
1312
1335
|
});
|
|
1313
1336
|
|
|
1314
|
-
// ../protocol/dist/schemas/
|
|
1337
|
+
// ../protocol/dist/schemas/workflow.js
|
|
1315
1338
|
import { z as z16 } from "zod";
|
|
1339
|
+
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;
|
|
1340
|
+
var init_workflow = __esm({
|
|
1341
|
+
"../protocol/dist/schemas/workflow.js"() {
|
|
1342
|
+
"use strict";
|
|
1343
|
+
init_common();
|
|
1344
|
+
ModelId = z16.string().min(1);
|
|
1345
|
+
TurnId = z16.string().min(1);
|
|
1346
|
+
ClientRequestId = z16.string().min(1);
|
|
1347
|
+
WorkflowId = z16.string().min(1);
|
|
1348
|
+
WorkflowNodeId = z16.string().min(1);
|
|
1349
|
+
WorkflowEdgeId = z16.string().min(1);
|
|
1350
|
+
WorkflowRoleId = z16.string().min(1);
|
|
1351
|
+
WorkflowNode = z16.object({
|
|
1352
|
+
nodeId: WorkflowNodeId,
|
|
1353
|
+
agent: AgentId,
|
|
1354
|
+
model: ModelId,
|
|
1355
|
+
role: WorkflowRoleId.optional(),
|
|
1356
|
+
input: z16.string().optional(),
|
|
1357
|
+
systemPrompt: z16.string().optional(),
|
|
1358
|
+
dependsOn: z16.array(WorkflowNodeId).optional(),
|
|
1359
|
+
sessionId: SessionId.optional(),
|
|
1360
|
+
agentConfig: z16.record(z16.unknown()).optional(),
|
|
1361
|
+
metadata: z16.record(z16.unknown()).optional()
|
|
1362
|
+
});
|
|
1363
|
+
WorkflowEdge = z16.object({
|
|
1364
|
+
edgeId: WorkflowEdgeId.optional(),
|
|
1365
|
+
from: WorkflowNodeId,
|
|
1366
|
+
to: WorkflowNodeId,
|
|
1367
|
+
label: z16.string().optional(),
|
|
1368
|
+
condition: z16.string().optional(),
|
|
1369
|
+
metadata: z16.record(z16.unknown()).optional()
|
|
1370
|
+
});
|
|
1371
|
+
WorkflowDagPlan = z16.object({
|
|
1372
|
+
mode: z16.literal("dag"),
|
|
1373
|
+
nodes: z16.array(WorkflowNode).min(1),
|
|
1374
|
+
edges: z16.array(WorkflowEdge).optional(),
|
|
1375
|
+
finalNodeId: WorkflowNodeId.optional()
|
|
1376
|
+
});
|
|
1377
|
+
WorkflowCommunicationGraph = z16.object({
|
|
1378
|
+
edges: z16.array(WorkflowEdge).default([]),
|
|
1379
|
+
allowSelfLoop: z16.boolean().default(false),
|
|
1380
|
+
maxIterations: z16.number().int().positive().default(12)
|
|
1381
|
+
});
|
|
1382
|
+
WorkflowGraphPlan = z16.object({
|
|
1383
|
+
mode: z16.literal("graph"),
|
|
1384
|
+
executor: z16.object({
|
|
1385
|
+
nodeId: WorkflowNodeId,
|
|
1386
|
+
agent: AgentId,
|
|
1387
|
+
model: ModelId,
|
|
1388
|
+
role: z16.literal("executor").default("executor"),
|
|
1389
|
+
systemPrompt: z16.string().optional(),
|
|
1390
|
+
agentConfig: z16.record(z16.unknown()).optional()
|
|
1391
|
+
}),
|
|
1392
|
+
workers: z16.array(WorkflowNode).min(1),
|
|
1393
|
+
communicationGraph: WorkflowCommunicationGraph
|
|
1394
|
+
});
|
|
1395
|
+
WorkflowPlan = z16.discriminatedUnion("mode", [WorkflowDagPlan, WorkflowGraphPlan]);
|
|
1396
|
+
WorkflowStatus = z16.enum(["queued", "running", "completed", "failed", "cancelled", "timeout"]);
|
|
1397
|
+
WorkflowNodeStatus = z16.enum(["pending", "ready", "running", "completed", "failed", "skipped", "cancelled"]);
|
|
1398
|
+
WorkflowRunParams = z16.object({
|
|
1399
|
+
project: ProjectId,
|
|
1400
|
+
worktreeId: z16.string().optional(),
|
|
1401
|
+
plan: WorkflowPlan,
|
|
1402
|
+
input: z16.string().optional(),
|
|
1403
|
+
clientRequestId: ClientRequestId.optional(),
|
|
1404
|
+
metadata: z16.record(z16.unknown()).optional()
|
|
1405
|
+
});
|
|
1406
|
+
WorkflowRunResult = z16.object({
|
|
1407
|
+
workflowId: WorkflowId,
|
|
1408
|
+
status: WorkflowStatus,
|
|
1409
|
+
createdAt: Timestamp
|
|
1410
|
+
});
|
|
1411
|
+
WorkflowStatusParams = z16.object({ workflowId: WorkflowId });
|
|
1412
|
+
WorkflowNodeRuntime = z16.object({
|
|
1413
|
+
nodeId: WorkflowNodeId,
|
|
1414
|
+
status: WorkflowNodeStatus,
|
|
1415
|
+
agent: AgentId,
|
|
1416
|
+
model: ModelId,
|
|
1417
|
+
role: WorkflowRoleId.optional(),
|
|
1418
|
+
sessionId: SessionId.optional(),
|
|
1419
|
+
turnId: TurnId.optional(),
|
|
1420
|
+
startedAt: Timestamp.optional(),
|
|
1421
|
+
completedAt: Timestamp.optional(),
|
|
1422
|
+
error: z16.string().optional()
|
|
1423
|
+
});
|
|
1424
|
+
WorkflowStatusResult = z16.object({
|
|
1425
|
+
workflowId: WorkflowId,
|
|
1426
|
+
status: WorkflowStatus,
|
|
1427
|
+
project: ProjectId,
|
|
1428
|
+
mode: z16.enum(["dag", "graph"]),
|
|
1429
|
+
nodes: z16.array(WorkflowNodeRuntime),
|
|
1430
|
+
createdAt: Timestamp,
|
|
1431
|
+
updatedAt: Timestamp,
|
|
1432
|
+
completedAt: Timestamp.optional(),
|
|
1433
|
+
error: z16.string().optional()
|
|
1434
|
+
});
|
|
1435
|
+
WorkflowCancelParams = z16.object({ workflowId: WorkflowId, reason: z16.string().optional() });
|
|
1436
|
+
WorkflowCancelResult = z16.object({ workflowId: WorkflowId, status: z16.literal("cancelled") });
|
|
1437
|
+
WorkflowListParams = z16.object({
|
|
1438
|
+
status: WorkflowStatus.optional(),
|
|
1439
|
+
limit: z16.number().int().positive().max(100).default(50).optional(),
|
|
1440
|
+
cursor: z16.string().optional()
|
|
1441
|
+
});
|
|
1442
|
+
WorkflowListResult = z16.object({ workflows: z16.array(WorkflowStatusResult), nextCursor: z16.string().optional() });
|
|
1443
|
+
WorkflowEvent = z16.object({
|
|
1444
|
+
workflowId: WorkflowId,
|
|
1445
|
+
seq: z16.number().int().nonnegative(),
|
|
1446
|
+
type: z16.enum(["workflow.status", "node.status", "node.stream", "edge.route", "executor.decision"]),
|
|
1447
|
+
nodeId: WorkflowNodeId.optional(),
|
|
1448
|
+
sessionId: SessionId.optional(),
|
|
1449
|
+
turnId: TurnId.optional(),
|
|
1450
|
+
agent: AgentId.optional(),
|
|
1451
|
+
model: ModelId.optional(),
|
|
1452
|
+
role: WorkflowRoleId.optional(),
|
|
1453
|
+
status: z16.union([WorkflowStatus, WorkflowNodeStatus]).optional(),
|
|
1454
|
+
payload: z16.record(z16.unknown()).optional(),
|
|
1455
|
+
timestamp: Timestamp
|
|
1456
|
+
});
|
|
1457
|
+
}
|
|
1458
|
+
});
|
|
1459
|
+
|
|
1460
|
+
// ../protocol/dist/schemas/jsonrpc.js
|
|
1461
|
+
import { z as z17 } from "zod";
|
|
1316
1462
|
var JsonRpcVersion, JsonRpcId, JsonRpcRequest, JsonRpcNotification, JsonRpcSuccess, JsonRpcErrorObject, JsonRpcError, JsonRpcMessage, JSON_RPC_CODES;
|
|
1317
1463
|
var init_jsonrpc = __esm({
|
|
1318
1464
|
"../protocol/dist/schemas/jsonrpc.js"() {
|
|
1319
1465
|
"use strict";
|
|
1320
1466
|
init_common();
|
|
1321
|
-
JsonRpcVersion =
|
|
1322
|
-
JsonRpcId =
|
|
1323
|
-
JsonRpcRequest =
|
|
1467
|
+
JsonRpcVersion = z17.literal("2.0");
|
|
1468
|
+
JsonRpcId = z17.union([z17.string(), z17.number()]);
|
|
1469
|
+
JsonRpcRequest = z17.object({
|
|
1324
1470
|
jsonrpc: JsonRpcVersion,
|
|
1325
1471
|
id: JsonRpcId,
|
|
1326
|
-
method:
|
|
1327
|
-
params:
|
|
1472
|
+
method: z17.string(),
|
|
1473
|
+
params: z17.unknown().optional()
|
|
1328
1474
|
});
|
|
1329
|
-
JsonRpcNotification =
|
|
1475
|
+
JsonRpcNotification = z17.object({
|
|
1330
1476
|
jsonrpc: JsonRpcVersion,
|
|
1331
|
-
method:
|
|
1332
|
-
params:
|
|
1477
|
+
method: z17.string(),
|
|
1478
|
+
params: z17.unknown().optional()
|
|
1333
1479
|
});
|
|
1334
|
-
JsonRpcSuccess =
|
|
1480
|
+
JsonRpcSuccess = z17.object({
|
|
1335
1481
|
jsonrpc: JsonRpcVersion,
|
|
1336
1482
|
id: JsonRpcId,
|
|
1337
|
-
result:
|
|
1483
|
+
result: z17.unknown()
|
|
1338
1484
|
});
|
|
1339
|
-
JsonRpcErrorObject =
|
|
1485
|
+
JsonRpcErrorObject = z17.object({
|
|
1340
1486
|
/** JSON-RPC 传输级 code(-32700..-32600 保留;应用错误用 data.appCode 判别)。 */
|
|
1341
|
-
code:
|
|
1342
|
-
message:
|
|
1487
|
+
code: z17.number().int(),
|
|
1488
|
+
message: z17.string(),
|
|
1343
1489
|
data: PhononErrorData.optional()
|
|
1344
1490
|
});
|
|
1345
|
-
JsonRpcError =
|
|
1491
|
+
JsonRpcError = z17.object({
|
|
1346
1492
|
jsonrpc: JsonRpcVersion,
|
|
1347
1493
|
id: JsonRpcId.nullable(),
|
|
1348
1494
|
error: JsonRpcErrorObject
|
|
1349
1495
|
});
|
|
1350
|
-
JsonRpcMessage =
|
|
1496
|
+
JsonRpcMessage = z17.union([
|
|
1351
1497
|
JsonRpcRequest,
|
|
1352
1498
|
JsonRpcNotification,
|
|
1353
1499
|
JsonRpcSuccess,
|
|
@@ -1366,7 +1512,7 @@ var init_jsonrpc = __esm({
|
|
|
1366
1512
|
});
|
|
1367
1513
|
|
|
1368
1514
|
// ../protocol/dist/schemas/methods.js
|
|
1369
|
-
import { z as
|
|
1515
|
+
import { z as z18 } from "zod";
|
|
1370
1516
|
function parseParams(method, data) {
|
|
1371
1517
|
return METHODS[method].params.parse(data);
|
|
1372
1518
|
}
|
|
@@ -1386,7 +1532,8 @@ var init_methods = __esm({
|
|
|
1386
1532
|
init_device();
|
|
1387
1533
|
init_file();
|
|
1388
1534
|
init_env();
|
|
1389
|
-
|
|
1535
|
+
init_workflow();
|
|
1536
|
+
z_void = z18.undefined();
|
|
1390
1537
|
METHODS = {
|
|
1391
1538
|
// --- 握手(phonon 拨出后先发)---
|
|
1392
1539
|
"connect.hello": {
|
|
@@ -1664,6 +1811,43 @@ var init_methods = __esm({
|
|
|
1664
1811
|
kind: "request",
|
|
1665
1812
|
params: SkillListParams,
|
|
1666
1813
|
result: SkillListResult
|
|
1814
|
+
},
|
|
1815
|
+
"skill.dirs": {
|
|
1816
|
+
direction: "s2p",
|
|
1817
|
+
kind: "request",
|
|
1818
|
+
params: SkillDirsParams,
|
|
1819
|
+
result: SkillDirsResult
|
|
1820
|
+
},
|
|
1821
|
+
// --- L3 workflow orchestration (DAG / executor graph) ---
|
|
1822
|
+
"workflow.run": {
|
|
1823
|
+
direction: "s2p",
|
|
1824
|
+
kind: "request",
|
|
1825
|
+
params: WorkflowRunParams,
|
|
1826
|
+
result: WorkflowRunResult
|
|
1827
|
+
},
|
|
1828
|
+
"workflow.status": {
|
|
1829
|
+
direction: "s2p",
|
|
1830
|
+
kind: "request",
|
|
1831
|
+
params: WorkflowStatusParams,
|
|
1832
|
+
result: WorkflowStatusResult
|
|
1833
|
+
},
|
|
1834
|
+
"workflow.cancel": {
|
|
1835
|
+
direction: "s2p",
|
|
1836
|
+
kind: "request",
|
|
1837
|
+
params: WorkflowCancelParams,
|
|
1838
|
+
result: WorkflowCancelResult
|
|
1839
|
+
},
|
|
1840
|
+
"workflow.list": {
|
|
1841
|
+
direction: "s2p",
|
|
1842
|
+
kind: "request",
|
|
1843
|
+
params: WorkflowListParams,
|
|
1844
|
+
result: WorkflowListResult
|
|
1845
|
+
},
|
|
1846
|
+
"workflow.event": {
|
|
1847
|
+
direction: "p2s",
|
|
1848
|
+
kind: "notification",
|
|
1849
|
+
params: WorkflowEvent,
|
|
1850
|
+
result: z_void
|
|
1667
1851
|
}
|
|
1668
1852
|
};
|
|
1669
1853
|
METHOD_NAMES = Object.keys(METHODS);
|
|
@@ -1689,6 +1873,7 @@ var init_dist = __esm({
|
|
|
1689
1873
|
init_device();
|
|
1690
1874
|
init_file();
|
|
1691
1875
|
init_env();
|
|
1876
|
+
init_workflow();
|
|
1692
1877
|
init_jsonrpc();
|
|
1693
1878
|
init_methods();
|
|
1694
1879
|
}
|
|
@@ -1725,12 +1910,12 @@ var init_rpc = __esm({
|
|
|
1725
1910
|
requestRaw(method, params, timeoutMs = 12e4) {
|
|
1726
1911
|
const id = this.nextId++;
|
|
1727
1912
|
const msg = { jsonrpc: "2.0", id, method, params };
|
|
1728
|
-
return new Promise((
|
|
1913
|
+
return new Promise((resolve6, reject) => {
|
|
1729
1914
|
const timer = timeoutMs > 0 ? setTimeout(() => {
|
|
1730
1915
|
this.pending.delete(id);
|
|
1731
1916
|
reject(new PhononError("errInternal", `RPC timeout: ${method}`));
|
|
1732
1917
|
}, timeoutMs) : void 0;
|
|
1733
|
-
this.pending.set(id, { resolve:
|
|
1918
|
+
this.pending.set(id, { resolve: resolve6, reject, timer });
|
|
1734
1919
|
this.transport.send(JSON.stringify(msg));
|
|
1735
1920
|
});
|
|
1736
1921
|
}
|
|
@@ -2186,8 +2371,8 @@ var SessionEngine = class {
|
|
|
2186
2371
|
this.interactionWaiters.delete(requestId);
|
|
2187
2372
|
}
|
|
2188
2373
|
}
|
|
2189
|
-
registerInteractionWaiter(requestId,
|
|
2190
|
-
this.interactionWaiters.set(requestId,
|
|
2374
|
+
registerInteractionWaiter(requestId, resolve6) {
|
|
2375
|
+
this.interactionWaiters.set(requestId, resolve6);
|
|
2191
2376
|
}
|
|
2192
2377
|
list(tenantId, filter) {
|
|
2193
2378
|
const all = [];
|
|
@@ -2438,7 +2623,7 @@ var ProjectManager = class {
|
|
|
2438
2623
|
|
|
2439
2624
|
// ../core/dist/skill-manager.js
|
|
2440
2625
|
init_rpc();
|
|
2441
|
-
import { mkdir as mkdir2, rm as rm2, writeFile, readdir as readdir2, stat as stat2, mkdtemp, lstat } from "node:fs/promises";
|
|
2626
|
+
import { mkdir as mkdir2, rm as rm2, writeFile, readdir as readdir2, stat as stat2, mkdtemp, lstat, realpath } from "node:fs/promises";
|
|
2442
2627
|
import { existsSync as existsSync2 } from "node:fs";
|
|
2443
2628
|
import { join as join2, resolve as resolve2, sep } from "node:path";
|
|
2444
2629
|
import { tmpdir } from "node:os";
|
|
@@ -2541,6 +2726,36 @@ var SkillManager = class {
|
|
|
2541
2726
|
return true;
|
|
2542
2727
|
});
|
|
2543
2728
|
}
|
|
2729
|
+
async dirs(filter) {
|
|
2730
|
+
const rows = [];
|
|
2731
|
+
if (filter?.scope !== "project" && filter?.agent) {
|
|
2732
|
+
const adapter = this.registry.resolve(filter.agent);
|
|
2733
|
+
const root = adapter?.globalSkillDir?.(filter.agent);
|
|
2734
|
+
if (root)
|
|
2735
|
+
rows.push(...await this.listDirs(root, { scope: "global", agent: filter.agent }));
|
|
2736
|
+
}
|
|
2737
|
+
if (filter?.scope !== "global" && filter?.projectId) {
|
|
2738
|
+
const projPath = this.resolveProjectPath(filter.projectId);
|
|
2739
|
+
if (!projPath)
|
|
2740
|
+
throw new PhononError("errProjectNotFound", `project ${filter.projectId} not found`);
|
|
2741
|
+
rows.push(...await this.listDirs(join2(projPath, ".agent", "skills"), { scope: "project", projectId: filter.projectId }));
|
|
2742
|
+
}
|
|
2743
|
+
return rows;
|
|
2744
|
+
}
|
|
2745
|
+
async listDirs(root, base) {
|
|
2746
|
+
const rootPath = existsSync2(root) ? await realpath(root) : resolve2(root);
|
|
2747
|
+
if (!existsSync2(root))
|
|
2748
|
+
return [];
|
|
2749
|
+
const entries = await readdir2(root, { withFileTypes: true });
|
|
2750
|
+
const rows = [];
|
|
2751
|
+
for (const e of entries) {
|
|
2752
|
+
if (!e.isDirectory())
|
|
2753
|
+
continue;
|
|
2754
|
+
const full = join2(root, e.name);
|
|
2755
|
+
rows.push({ name: e.name, ...base, rootPath, path: await realpath(full), exists: true });
|
|
2756
|
+
}
|
|
2757
|
+
return rows.sort((a, b) => a.name.localeCompare(b.name));
|
|
2758
|
+
}
|
|
2544
2759
|
async installArchive(source, dest) {
|
|
2545
2760
|
if (source.format !== "tar.gz")
|
|
2546
2761
|
throw new PhononError("errSkillInstallFailed", `unsupported archive format: ${source.format}`);
|
|
@@ -3142,7 +3357,7 @@ var PhononStore = class {
|
|
|
3142
3357
|
|
|
3143
3358
|
// ../core/dist/file-manager.js
|
|
3144
3359
|
init_rpc();
|
|
3145
|
-
import { mkdir as mkdir3, readFile, readdir as readdir3, lstat as lstat2, realpath, writeFile as writeFile2 } from "node:fs/promises";
|
|
3360
|
+
import { mkdir as mkdir3, readFile, readdir as readdir3, lstat as lstat2, realpath as realpath2, writeFile as writeFile2 } from "node:fs/promises";
|
|
3146
3361
|
import { basename as basename2, dirname as dirname3, join as join4, resolve as resolve4, sep as sep2 } from "node:path";
|
|
3147
3362
|
var FileManager = class {
|
|
3148
3363
|
resolver;
|
|
@@ -3159,7 +3374,7 @@ var FileManager = class {
|
|
|
3159
3374
|
let cur = abs;
|
|
3160
3375
|
for (; ; ) {
|
|
3161
3376
|
try {
|
|
3162
|
-
const real = await
|
|
3377
|
+
const real = await realpath2(cur);
|
|
3163
3378
|
return suffix.length ? resolve4(real, ...suffix) : real;
|
|
3164
3379
|
} catch (e) {
|
|
3165
3380
|
if (e?.code !== "ENOENT")
|
|
@@ -3365,6 +3580,190 @@ async function commandExists(cmd2) {
|
|
|
3365
3580
|
}
|
|
3366
3581
|
}
|
|
3367
3582
|
|
|
3583
|
+
// ../core/dist/workflow-engine.js
|
|
3584
|
+
init_rpc();
|
|
3585
|
+
var WorkflowEngine = class {
|
|
3586
|
+
opts;
|
|
3587
|
+
runs = /* @__PURE__ */ new Map();
|
|
3588
|
+
sessionToNode = /* @__PURE__ */ new Map();
|
|
3589
|
+
idSeq = 1;
|
|
3590
|
+
constructor(opts) {
|
|
3591
|
+
this.opts = opts;
|
|
3592
|
+
}
|
|
3593
|
+
async run(params) {
|
|
3594
|
+
const workflowId = `wf-${Date.now()}-${this.idSeq++}`;
|
|
3595
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3596
|
+
const nodes = this.initialNodes(params.plan);
|
|
3597
|
+
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 };
|
|
3598
|
+
this.runs.set(workflowId, run);
|
|
3599
|
+
this.emit(run, { type: "workflow.status", status: "queued" });
|
|
3600
|
+
void this.execute(run).catch((err) => this.fail(run, err));
|
|
3601
|
+
return { workflowId, status: run.status, createdAt: run.createdAt };
|
|
3602
|
+
}
|
|
3603
|
+
status(workflowId) {
|
|
3604
|
+
const run = this.get(workflowId);
|
|
3605
|
+
return this.toStatus(run);
|
|
3606
|
+
}
|
|
3607
|
+
list(filter) {
|
|
3608
|
+
const limit = filter?.limit ?? 50;
|
|
3609
|
+
const rows = [...this.runs.values()].filter((r) => !filter?.status || r.status === filter.status).slice(-limit).reverse();
|
|
3610
|
+
return { workflows: rows.map((r) => this.toStatus(r)) };
|
|
3611
|
+
}
|
|
3612
|
+
async cancel(workflowId, reason) {
|
|
3613
|
+
const run = this.get(workflowId);
|
|
3614
|
+
run.status = "cancelled";
|
|
3615
|
+
run.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3616
|
+
run.updatedAt = run.completedAt;
|
|
3617
|
+
for (const n of run.nodes) {
|
|
3618
|
+
if (n.sessionId && (n.status === "running" || n.status === "ready" || n.status === "pending")) {
|
|
3619
|
+
n.status = "cancelled";
|
|
3620
|
+
try {
|
|
3621
|
+
await this.opts.engine.terminate(this.opts.tenantId, n.sessionId);
|
|
3622
|
+
} catch {
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
this.emit(run, { type: "workflow.status", status: "cancelled", payload: { reason } });
|
|
3627
|
+
return { workflowId, status: "cancelled" };
|
|
3628
|
+
}
|
|
3629
|
+
onStreamEvent(ev) {
|
|
3630
|
+
const sessionId = ev.sessionId;
|
|
3631
|
+
if (!sessionId)
|
|
3632
|
+
return;
|
|
3633
|
+
const m = this.sessionToNode.get(sessionId);
|
|
3634
|
+
if (!m)
|
|
3635
|
+
return;
|
|
3636
|
+
const run = this.runs.get(m.workflowId);
|
|
3637
|
+
const node = run?.nodes.find((n) => n.nodeId === m.nodeId);
|
|
3638
|
+
if (!run || !node)
|
|
3639
|
+
return;
|
|
3640
|
+
this.emit(run, {
|
|
3641
|
+
type: "node.stream",
|
|
3642
|
+
nodeId: node.nodeId,
|
|
3643
|
+
sessionId,
|
|
3644
|
+
turnId: ev.turnId,
|
|
3645
|
+
agent: node.agent,
|
|
3646
|
+
model: node.model,
|
|
3647
|
+
role: node.role,
|
|
3648
|
+
payload: ev
|
|
3649
|
+
});
|
|
3650
|
+
}
|
|
3651
|
+
async execute(run) {
|
|
3652
|
+
run.status = "running";
|
|
3653
|
+
run.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3654
|
+
this.emit(run, { type: "workflow.status", status: "running" });
|
|
3655
|
+
if (run.plan.mode === "dag")
|
|
3656
|
+
await this.executeDag(run);
|
|
3657
|
+
else
|
|
3658
|
+
await this.executeGraph(run);
|
|
3659
|
+
if (!["cancelled", "failed"].includes(run.status)) {
|
|
3660
|
+
run.status = "completed";
|
|
3661
|
+
run.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3662
|
+
run.updatedAt = run.completedAt;
|
|
3663
|
+
this.emit(run, { type: "workflow.status", status: "completed" });
|
|
3664
|
+
}
|
|
3665
|
+
}
|
|
3666
|
+
async executeDag(run) {
|
|
3667
|
+
const plan = run.plan.mode === "dag" ? run.plan : void 0;
|
|
3668
|
+
if (!plan)
|
|
3669
|
+
return;
|
|
3670
|
+
const deps = /* @__PURE__ */ new Map();
|
|
3671
|
+
for (const n of plan.nodes)
|
|
3672
|
+
deps.set(n.nodeId, new Set(n.dependsOn ?? []));
|
|
3673
|
+
for (const e of plan.edges ?? [])
|
|
3674
|
+
deps.get(e.to)?.add(e.from);
|
|
3675
|
+
const done = /* @__PURE__ */ new Set();
|
|
3676
|
+
while (done.size < plan.nodes.length) {
|
|
3677
|
+
const ready = plan.nodes.filter((n) => !done.has(n.nodeId) && [...deps.get(n.nodeId) ?? []].every((d) => done.has(d)));
|
|
3678
|
+
if (ready.length === 0)
|
|
3679
|
+
throw new PhononError("errInvalidParams", "workflow DAG has a cycle or missing dependency");
|
|
3680
|
+
await Promise.all(ready.map((n) => this.executeNode(run, n.nodeId, n.agent, n.model, n.role, n.input ?? run.input ?? "", n.agentConfig)));
|
|
3681
|
+
for (const n of ready)
|
|
3682
|
+
done.add(n.nodeId);
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3685
|
+
async executeGraph(run) {
|
|
3686
|
+
const plan = run.plan.mode === "graph" ? run.plan : void 0;
|
|
3687
|
+
if (!plan)
|
|
3688
|
+
return;
|
|
3689
|
+
const prompt = [
|
|
3690
|
+
"You are the executor for a multi-agent graph workflow.",
|
|
3691
|
+
`Input: ${run.input ?? ""}`,
|
|
3692
|
+
`Workers: ${JSON.stringify(plan.workers.map((w) => ({ nodeId: w.nodeId, role: w.role, agent: w.agent, model: w.model })))}`,
|
|
3693
|
+
`Communication graph: ${JSON.stringify(plan.communicationGraph)}`,
|
|
3694
|
+
"Produce the first routing decision and final summary for this initial implementation."
|
|
3695
|
+
].join("\n\n");
|
|
3696
|
+
await this.executeNode(run, plan.executor.nodeId, plan.executor.agent, plan.executor.model, plan.executor.role, prompt, plan.executor.agentConfig);
|
|
3697
|
+
this.emit(run, { type: "executor.decision", nodeId: plan.executor.nodeId, payload: { initialImplementation: true } });
|
|
3698
|
+
}
|
|
3699
|
+
async executeNode(run, nodeId, agent, model, role, input, agentConfig) {
|
|
3700
|
+
const node = run.nodes.find((n) => n.nodeId === nodeId) ?? this.addNode(run, { nodeId, agent, model, role });
|
|
3701
|
+
node.status = "running";
|
|
3702
|
+
node.startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3703
|
+
run.updatedAt = node.startedAt;
|
|
3704
|
+
this.emit(run, { type: "node.status", nodeId, agent, model, role, status: "running" });
|
|
3705
|
+
try {
|
|
3706
|
+
const cwd = this.opts.resolveCwd(run.project, run.worktreeId);
|
|
3707
|
+
const created = await this.opts.engine.create({ tenantId: run.tenantId, project: run.project, worktreeId: run.worktreeId, cwd, agent, model, verbosity: "messages", agentConfig });
|
|
3708
|
+
node.sessionId = created.sessionId;
|
|
3709
|
+
this.sessionToNode.set(created.sessionId, { workflowId: run.workflowId, nodeId });
|
|
3710
|
+
const sent = await this.opts.engine.send(run.tenantId, created.sessionId, input, { environment: this.opts.env.resolveForExecution({ projectId: run.project, agent }) });
|
|
3711
|
+
node.turnId = sent.turnId;
|
|
3712
|
+
await this.waitIdle(run.tenantId, created.sessionId);
|
|
3713
|
+
node.status = "completed";
|
|
3714
|
+
node.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3715
|
+
run.updatedAt = node.completedAt;
|
|
3716
|
+
this.emit(run, { type: "node.status", nodeId, sessionId: node.sessionId, turnId: node.turnId, agent, model, role, status: "completed" });
|
|
3717
|
+
} catch (err) {
|
|
3718
|
+
node.status = "failed";
|
|
3719
|
+
node.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3720
|
+
node.error = err?.message ?? String(err);
|
|
3721
|
+
run.updatedAt = node.completedAt;
|
|
3722
|
+
this.emit(run, { type: "node.status", nodeId, agent, model, role, status: "failed", payload: { error: node.error } });
|
|
3723
|
+
throw err;
|
|
3724
|
+
}
|
|
3725
|
+
}
|
|
3726
|
+
async waitIdle(tenantId, sessionId) {
|
|
3727
|
+
for (; ; ) {
|
|
3728
|
+
const s = await this.opts.engine.status(tenantId, sessionId);
|
|
3729
|
+
if (s.status === "idle" || s.status === "terminated" || s.status === "paused")
|
|
3730
|
+
return;
|
|
3731
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
3732
|
+
}
|
|
3733
|
+
}
|
|
3734
|
+
initialNodes(plan) {
|
|
3735
|
+
const nodes = plan.mode === "dag" ? plan.nodes : [plan.executor, ...plan.workers];
|
|
3736
|
+
return nodes.map((n) => ({ nodeId: n.nodeId, status: "pending", agent: n.agent, model: n.model, role: n.role }));
|
|
3737
|
+
}
|
|
3738
|
+
addNode(run, n) {
|
|
3739
|
+
const node = { ...n, status: "pending" };
|
|
3740
|
+
run.nodes.push(node);
|
|
3741
|
+
return node;
|
|
3742
|
+
}
|
|
3743
|
+
get(workflowId) {
|
|
3744
|
+
const run = this.runs.get(workflowId);
|
|
3745
|
+
if (!run)
|
|
3746
|
+
throw new PhononError("errInvalidParams", `workflow ${workflowId} not found`);
|
|
3747
|
+
return run;
|
|
3748
|
+
}
|
|
3749
|
+
fail(run, err) {
|
|
3750
|
+
if (run.status === "cancelled")
|
|
3751
|
+
return;
|
|
3752
|
+
run.status = "failed";
|
|
3753
|
+
run.error = err?.message ?? String(err);
|
|
3754
|
+
run.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3755
|
+
run.updatedAt = run.completedAt;
|
|
3756
|
+
this.emit(run, { type: "workflow.status", status: "failed", payload: { error: run.error } });
|
|
3757
|
+
}
|
|
3758
|
+
toStatus(run) {
|
|
3759
|
+
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 };
|
|
3760
|
+
}
|
|
3761
|
+
emit(run, partial) {
|
|
3762
|
+
const ev = { workflowId: run.workflowId, seq: run.seq++, timestamp: (/* @__PURE__ */ new Date()).toISOString(), ...partial };
|
|
3763
|
+
this.opts.emit(ev);
|
|
3764
|
+
}
|
|
3765
|
+
};
|
|
3766
|
+
|
|
3368
3767
|
// ../core/dist/env-manager.js
|
|
3369
3768
|
init_rpc();
|
|
3370
3769
|
function redact(value) {
|
|
@@ -3762,7 +4161,7 @@ ${message}`;
|
|
|
3762
4161
|
return void 0;
|
|
3763
4162
|
}
|
|
3764
4163
|
run(args2, signal, environment) {
|
|
3765
|
-
return new Promise((
|
|
4164
|
+
return new Promise((resolve6, reject) => {
|
|
3766
4165
|
const child = spawn2("openclaw", args2, { cwd: this.cwd, env: { ...process.env, ...environment ?? {} } });
|
|
3767
4166
|
this.current = child;
|
|
3768
4167
|
let out = "";
|
|
@@ -3780,9 +4179,9 @@ ${message}`;
|
|
|
3780
4179
|
signal?.removeEventListener("abort", onAbort);
|
|
3781
4180
|
this.current = void 0;
|
|
3782
4181
|
if (killed)
|
|
3783
|
-
return
|
|
4182
|
+
return resolve6(null);
|
|
3784
4183
|
if (code === 0)
|
|
3785
|
-
|
|
4184
|
+
resolve6(out);
|
|
3786
4185
|
else
|
|
3787
4186
|
reject(new Error(`openclaw exited ${code}: ${err.slice(0, 500)}`));
|
|
3788
4187
|
});
|
|
@@ -3834,12 +4233,12 @@ var OpenClawAdapter = class {
|
|
|
3834
4233
|
return new OpenClawSession(params.sessionId, params.model, params.cwd, openclawAgent);
|
|
3835
4234
|
}
|
|
3836
4235
|
probeVersion() {
|
|
3837
|
-
return new Promise((
|
|
4236
|
+
return new Promise((resolve6) => {
|
|
3838
4237
|
const child = spawn2("openclaw", ["--version"]);
|
|
3839
4238
|
let out = "";
|
|
3840
4239
|
child.stdout.on("data", (d) => out += d.toString());
|
|
3841
|
-
child.on("error", () =>
|
|
3842
|
-
child.on("close", (code) =>
|
|
4240
|
+
child.on("error", () => resolve6(null));
|
|
4241
|
+
child.on("close", (code) => resolve6(code === 0 ? out.trim() : null));
|
|
3843
4242
|
});
|
|
3844
4243
|
}
|
|
3845
4244
|
};
|
|
@@ -3872,7 +4271,7 @@ var GatewayClient = class {
|
|
|
3872
4271
|
return this.connectPromise;
|
|
3873
4272
|
}
|
|
3874
4273
|
doConnect() {
|
|
3875
|
-
return new Promise((
|
|
4274
|
+
return new Promise((resolve6, reject) => {
|
|
3876
4275
|
const wsUrl = this.config.baseUrl.replace(/^http/, "ws");
|
|
3877
4276
|
const ws = new WebSocket(wsUrl);
|
|
3878
4277
|
this.ws = ws;
|
|
@@ -3903,7 +4302,7 @@ var GatewayClient = class {
|
|
|
3903
4302
|
} else if (frame.type === "res" && frame.ok && frame.payload?.type === "hello-ok") {
|
|
3904
4303
|
handshakeDone = true;
|
|
3905
4304
|
this.connected = true;
|
|
3906
|
-
|
|
4305
|
+
resolve6();
|
|
3907
4306
|
} else if (frame.type === "res" && !frame.ok) {
|
|
3908
4307
|
reject(new Error(`handshake failed: ${JSON.stringify(frame.error)}`));
|
|
3909
4308
|
}
|
|
@@ -3949,13 +4348,13 @@ var GatewayClient = class {
|
|
|
3949
4348
|
async rpc(method, params, timeoutMs = 12e4) {
|
|
3950
4349
|
if (!this.connected)
|
|
3951
4350
|
await this.connect();
|
|
3952
|
-
return new Promise((
|
|
4351
|
+
return new Promise((resolve6, reject) => {
|
|
3953
4352
|
const id = randomUUID();
|
|
3954
4353
|
const timer = setTimeout(() => {
|
|
3955
4354
|
this.pending.delete(id);
|
|
3956
4355
|
reject(new Error(`RPC timeout: ${method}`));
|
|
3957
4356
|
}, timeoutMs);
|
|
3958
|
-
this.pending.set(id, { resolve:
|
|
4357
|
+
this.pending.set(id, { resolve: resolve6, reject, timer });
|
|
3959
4358
|
this.ws.send(JSON.stringify({ type: "req", id, method, params }));
|
|
3960
4359
|
});
|
|
3961
4360
|
}
|
|
@@ -4082,14 +4481,14 @@ var GatewaySession = class {
|
|
|
4082
4481
|
|
|
4083
4482
|
${input}`;
|
|
4084
4483
|
}
|
|
4085
|
-
await new Promise((
|
|
4484
|
+
await new Promise((resolve6) => {
|
|
4086
4485
|
let settled = false;
|
|
4087
4486
|
const finish = () => {
|
|
4088
4487
|
if (settled)
|
|
4089
4488
|
return;
|
|
4090
4489
|
settled = true;
|
|
4091
4490
|
clearTimeout(guard);
|
|
4092
|
-
|
|
4491
|
+
resolve6();
|
|
4093
4492
|
};
|
|
4094
4493
|
this.activeTurn = { turnId, emit, verbosity: opts.verbosity, done: finish, acc: "" };
|
|
4095
4494
|
this.gw.rpc("chat.send", {
|
|
@@ -4350,7 +4749,7 @@ var PhononClient = class {
|
|
|
4350
4749
|
}
|
|
4351
4750
|
/** 连接并完成握手,resolve 后即可接收 server 的 session.* 下发。 */
|
|
4352
4751
|
connect() {
|
|
4353
|
-
return new Promise((
|
|
4752
|
+
return new Promise((resolve6, reject) => {
|
|
4354
4753
|
const ws = new WebSocket2(this.serverUrl);
|
|
4355
4754
|
this.ws = ws;
|
|
4356
4755
|
const transport = {
|
|
@@ -4392,7 +4791,7 @@ var PhononClient = class {
|
|
|
4392
4791
|
if (wAck && wAck.length > 0) {
|
|
4393
4792
|
conn.replayPending(wAck.map((a) => ({ sessionId: a.sessionId, fromSeq: a.lastSeq })));
|
|
4394
4793
|
}
|
|
4395
|
-
|
|
4794
|
+
resolve6({ tenantId: welcome.tenantId });
|
|
4396
4795
|
} catch (err) {
|
|
4397
4796
|
reject(err);
|
|
4398
4797
|
}
|
|
@@ -4462,12 +4861,12 @@ var HookBridge = class {
|
|
|
4462
4861
|
this.token = opts?.token;
|
|
4463
4862
|
}
|
|
4464
4863
|
listen(port = 4318, host = "127.0.0.1") {
|
|
4465
|
-
return new Promise((
|
|
4864
|
+
return new Promise((resolve6) => {
|
|
4466
4865
|
const server = createServer((req, res) => this.onRequest(req, res));
|
|
4467
4866
|
this.server = server;
|
|
4468
4867
|
server.listen(port, host, () => {
|
|
4469
4868
|
const addr = server.address();
|
|
4470
|
-
|
|
4869
|
+
resolve6(typeof addr === "object" && addr ? addr.port : port);
|
|
4471
4870
|
});
|
|
4472
4871
|
});
|
|
4473
4872
|
}
|
|
@@ -4520,10 +4919,10 @@ var HookBridge = class {
|
|
|
4520
4919
|
});
|
|
4521
4920
|
}
|
|
4522
4921
|
close() {
|
|
4523
|
-
return new Promise((
|
|
4922
|
+
return new Promise((resolve6) => {
|
|
4524
4923
|
if (!this.server)
|
|
4525
|
-
return
|
|
4526
|
-
this.server.close(() =>
|
|
4924
|
+
return resolve6();
|
|
4925
|
+
this.server.close(() => resolve6());
|
|
4527
4926
|
});
|
|
4528
4927
|
}
|
|
4529
4928
|
};
|
|
@@ -4708,7 +5107,7 @@ function normalizeOpenAiModels(data) {
|
|
|
4708
5107
|
return out;
|
|
4709
5108
|
}
|
|
4710
5109
|
function fetchJson(url, headers) {
|
|
4711
|
-
return new Promise((
|
|
5110
|
+
return new Promise((resolve6, reject) => {
|
|
4712
5111
|
const u = new URL(url);
|
|
4713
5112
|
const req = (u.protocol === "http:" ? import("node:http") : import("node:https")).then((mod) => mod.request(url, { method: "GET", headers, timeout: 5e3 }, (res) => {
|
|
4714
5113
|
let body = "";
|
|
@@ -4720,7 +5119,7 @@ function fetchJson(url, headers) {
|
|
|
4720
5119
|
return;
|
|
4721
5120
|
}
|
|
4722
5121
|
try {
|
|
4723
|
-
|
|
5122
|
+
resolve6(JSON.parse(body));
|
|
4724
5123
|
} catch (e) {
|
|
4725
5124
|
reject(e);
|
|
4726
5125
|
}
|
|
@@ -4782,7 +5181,7 @@ ${prompt}`;
|
|
|
4782
5181
|
await this.run(args2, prompt, turnId, emit, opts);
|
|
4783
5182
|
}
|
|
4784
5183
|
run(args2, stdin, turnId, emit, opts) {
|
|
4785
|
-
return new Promise((
|
|
5184
|
+
return new Promise((resolve6) => {
|
|
4786
5185
|
const child = spawn3(this.env.binPath ?? "codex", args2, {
|
|
4787
5186
|
cwd: this.cwd,
|
|
4788
5187
|
shell: process.platform === "win32",
|
|
@@ -4803,7 +5202,7 @@ ${prompt}`;
|
|
|
4803
5202
|
} else {
|
|
4804
5203
|
emit({ type: "result", sessionId: this.sessionId, turnId, seq: 0, at: (/* @__PURE__ */ new Date()).toISOString(), text, status, final: true });
|
|
4805
5204
|
}
|
|
4806
|
-
|
|
5205
|
+
resolve6();
|
|
4807
5206
|
};
|
|
4808
5207
|
const guard = setTimeout(() => finish("timeout", acc), 18e5);
|
|
4809
5208
|
opts.signal?.addEventListener("abort", () => {
|
|
@@ -4935,12 +5334,12 @@ var CodexAdapter = class {
|
|
|
4935
5334
|
return base.length > 0 ? base : CODEX_FALLBACK_MODELS;
|
|
4936
5335
|
}
|
|
4937
5336
|
probeVersion() {
|
|
4938
|
-
return new Promise((
|
|
5337
|
+
return new Promise((resolve6) => {
|
|
4939
5338
|
const child = spawn3(this.env.binPath ?? "codex", ["--version"], { shell: process.platform === "win32" });
|
|
4940
5339
|
let out = "";
|
|
4941
5340
|
child.stdout.on("data", (d) => out += d.toString());
|
|
4942
|
-
child.on("error", () =>
|
|
4943
|
-
child.on("close", (code) =>
|
|
5341
|
+
child.on("error", () => resolve6(null));
|
|
5342
|
+
child.on("close", (code) => resolve6(code === 0 ? out.trim() : null));
|
|
4944
5343
|
});
|
|
4945
5344
|
}
|
|
4946
5345
|
};
|
|
@@ -5016,7 +5415,7 @@ ${message}`;
|
|
|
5016
5415
|
await this.run(args2, turnId, emit, opts);
|
|
5017
5416
|
}
|
|
5018
5417
|
run(args2, turnId, emit, opts) {
|
|
5019
|
-
return new Promise((
|
|
5418
|
+
return new Promise((resolve6) => {
|
|
5020
5419
|
const child = spawn4(this.bin, args2, { cwd: this.cwd, stdio: ["ignore", "pipe", "pipe"], env: { ...process.env, ...opts.environment ?? {} } });
|
|
5021
5420
|
this.current = child;
|
|
5022
5421
|
let buf = "";
|
|
@@ -5033,7 +5432,7 @@ ${message}`;
|
|
|
5033
5432
|
} else {
|
|
5034
5433
|
emit({ type: "result", sessionId: this.sessionId, turnId, seq: 0, at: (/* @__PURE__ */ new Date()).toISOString(), text, status, final: true });
|
|
5035
5434
|
}
|
|
5036
|
-
|
|
5435
|
+
resolve6();
|
|
5037
5436
|
};
|
|
5038
5437
|
const guard = setTimeout(() => finish("timeout", acc), 18e5);
|
|
5039
5438
|
opts.signal?.addEventListener("abort", () => {
|
|
@@ -5164,12 +5563,12 @@ var OpenCodeAdapter = class {
|
|
|
5164
5563
|
return new OpenCodeSession(params.sessionId, model, params.cwd, this.bin);
|
|
5165
5564
|
}
|
|
5166
5565
|
probeVersion() {
|
|
5167
|
-
return new Promise((
|
|
5566
|
+
return new Promise((resolve6) => {
|
|
5168
5567
|
const child = spawn4(this.bin, ["--version"]);
|
|
5169
5568
|
let out = "";
|
|
5170
5569
|
child.stdout.on("data", (d) => out += d.toString());
|
|
5171
|
-
child.on("error", () =>
|
|
5172
|
-
child.on("close", (code) =>
|
|
5570
|
+
child.on("error", () => resolve6(null));
|
|
5571
|
+
child.on("close", (code) => resolve6(code === 0 ? out.trim() : null));
|
|
5173
5572
|
});
|
|
5174
5573
|
}
|
|
5175
5574
|
};
|
|
@@ -5234,7 +5633,7 @@ function parseHermesConfig(configPath = join9(homedir7(), ".hermes", "config.yam
|
|
|
5234
5633
|
return { defaultModel, provider, catalogUrl };
|
|
5235
5634
|
}
|
|
5236
5635
|
function fetchHermesCatalogModels(url, provider) {
|
|
5237
|
-
return new Promise((
|
|
5636
|
+
return new Promise((resolve6) => {
|
|
5238
5637
|
const u = new URL(url);
|
|
5239
5638
|
const reqMod = u.protocol === "http:" ? import("node:http") : import("node:https");
|
|
5240
5639
|
reqMod.then((mod) => {
|
|
@@ -5248,21 +5647,21 @@ function fetchHermesCatalogModels(url, provider) {
|
|
|
5248
5647
|
const providers = data.providers ?? {};
|
|
5249
5648
|
const rows = provider ? providers[provider]?.models ?? [] : Object.values(providers).flatMap((p) => p.models ?? []);
|
|
5250
5649
|
const seen = /* @__PURE__ */ new Set();
|
|
5251
|
-
|
|
5650
|
+
resolve6(rows.flatMap((m) => {
|
|
5252
5651
|
if (!m.id || seen.has(m.id))
|
|
5253
5652
|
return [];
|
|
5254
5653
|
seen.add(m.id);
|
|
5255
5654
|
return [{ id: m.id, ...m.description ? { displayName: m.description } : {}, available: true }];
|
|
5256
5655
|
}));
|
|
5257
5656
|
} catch {
|
|
5258
|
-
|
|
5657
|
+
resolve6([]);
|
|
5259
5658
|
}
|
|
5260
5659
|
});
|
|
5261
5660
|
});
|
|
5262
5661
|
req.on("timeout", () => req.destroy());
|
|
5263
|
-
req.on("error", () =>
|
|
5662
|
+
req.on("error", () => resolve6([]));
|
|
5264
5663
|
req.end();
|
|
5265
|
-
}, () =>
|
|
5664
|
+
}, () => resolve6([]));
|
|
5266
5665
|
});
|
|
5267
5666
|
}
|
|
5268
5667
|
var HermesSession = class {
|
|
@@ -5310,7 +5709,7 @@ ${prompt}`;
|
|
|
5310
5709
|
await this.run(args2, turnId, emit, opts);
|
|
5311
5710
|
}
|
|
5312
5711
|
run(args2, turnId, emit, opts) {
|
|
5313
|
-
return new Promise((
|
|
5712
|
+
return new Promise((resolve6) => {
|
|
5314
5713
|
const child = spawn5(this.env.binPath ?? "hermes", args2, {
|
|
5315
5714
|
cwd: this.cwd,
|
|
5316
5715
|
shell: process.platform === "win32",
|
|
@@ -5333,7 +5732,7 @@ ${prompt}`;
|
|
|
5333
5732
|
emit({ type: "message", sessionId: this.sessionId, turnId, seq: 0, at: (/* @__PURE__ */ new Date()).toISOString(), role: "assistant", text, delta: false });
|
|
5334
5733
|
emit({ type: "result", sessionId: this.sessionId, turnId, seq: 0, at: (/* @__PURE__ */ new Date()).toISOString(), text, status, final: true });
|
|
5335
5734
|
}
|
|
5336
|
-
|
|
5735
|
+
resolve6();
|
|
5337
5736
|
};
|
|
5338
5737
|
const guard = setTimeout(() => finish("timeout", out), 18e5);
|
|
5339
5738
|
opts.signal?.addEventListener("abort", () => {
|
|
@@ -5493,11 +5892,11 @@ var HermesAdapter = class {
|
|
|
5493
5892
|
}
|
|
5494
5893
|
/** 枚举 Hermes profile(去 ANSI 色解析 profile list)。 */
|
|
5495
5894
|
listProfiles() {
|
|
5496
|
-
return new Promise((
|
|
5895
|
+
return new Promise((resolve6) => {
|
|
5497
5896
|
const child = spawn5(this.env.binPath ?? "hermes", ["profile", "list"], { shell: process.platform === "win32" });
|
|
5498
5897
|
let out = "";
|
|
5499
5898
|
child.stdout.on("data", (d) => out += d.toString());
|
|
5500
|
-
child.on("error", () =>
|
|
5899
|
+
child.on("error", () => resolve6([{ name: this.defaultProfile }]));
|
|
5501
5900
|
child.on("close", () => {
|
|
5502
5901
|
const clean = out.replace(/\u001b\[[0-9;]*m/g, "");
|
|
5503
5902
|
const names = [];
|
|
@@ -5508,17 +5907,17 @@ var HermesAdapter = class {
|
|
|
5508
5907
|
names.push({ name: m[1], model: rest[0] || void 0 });
|
|
5509
5908
|
}
|
|
5510
5909
|
}
|
|
5511
|
-
|
|
5910
|
+
resolve6(names.length > 0 ? names : [{ name: this.defaultProfile }]);
|
|
5512
5911
|
});
|
|
5513
5912
|
});
|
|
5514
5913
|
}
|
|
5515
5914
|
probeVersion() {
|
|
5516
|
-
return new Promise((
|
|
5915
|
+
return new Promise((resolve6) => {
|
|
5517
5916
|
const child = spawn5(this.env.binPath ?? "hermes", ["--version"], { shell: process.platform === "win32" });
|
|
5518
5917
|
let out = "";
|
|
5519
5918
|
child.stdout.on("data", (d) => out += d.toString());
|
|
5520
|
-
child.on("error", () =>
|
|
5521
|
-
child.on("close", (code) =>
|
|
5919
|
+
child.on("error", () => resolve6(null));
|
|
5920
|
+
child.on("close", (code) => resolve6(code === 0 ? out.trim().split("\n")[0] ?? "hermes" : null));
|
|
5522
5921
|
});
|
|
5523
5922
|
}
|
|
5524
5923
|
};
|
|
@@ -5741,7 +6140,7 @@ ${prompt}`;
|
|
|
5741
6140
|
await this.run(args2, envelope, turnId, emit, opts);
|
|
5742
6141
|
}
|
|
5743
6142
|
run(args2, stdin, turnId, emit, opts) {
|
|
5744
|
-
return new Promise((
|
|
6143
|
+
return new Promise((resolve6) => {
|
|
5745
6144
|
const childEnv = {};
|
|
5746
6145
|
for (const [k, v] of Object.entries(process.env)) {
|
|
5747
6146
|
if (k === "CLAUDECODE" || k.startsWith("CLAUDECODE_") || k.startsWith("CLAUDE_CODE_"))
|
|
@@ -5773,7 +6172,7 @@ ${prompt}`;
|
|
|
5773
6172
|
} else {
|
|
5774
6173
|
emit({ type: "result", sessionId: this.sessionId, turnId, seq: 0, at: (/* @__PURE__ */ new Date()).toISOString(), text, status, final: true });
|
|
5775
6174
|
}
|
|
5776
|
-
|
|
6175
|
+
resolve6();
|
|
5777
6176
|
};
|
|
5778
6177
|
const guard = setTimeout(() => finish("timeout", acc), 18e5);
|
|
5779
6178
|
opts.signal?.addEventListener("abort", () => {
|
|
@@ -5890,12 +6289,12 @@ var ClaudeCodeAdapter = class {
|
|
|
5890
6289
|
return new ClaudeCodeSession(params.sessionId, params.model, params.cwd, this.env);
|
|
5891
6290
|
}
|
|
5892
6291
|
probeVersion() {
|
|
5893
|
-
return new Promise((
|
|
6292
|
+
return new Promise((resolve6) => {
|
|
5894
6293
|
const child = spawn6(this.env.binPath ?? "claude", ["--version"], { shell: process.platform === "win32" });
|
|
5895
6294
|
let out = "";
|
|
5896
6295
|
child.stdout.on("data", (d) => out += d.toString());
|
|
5897
|
-
child.on("error", () =>
|
|
5898
|
-
child.on("close", (code) =>
|
|
6296
|
+
child.on("error", () => resolve6(null));
|
|
6297
|
+
child.on("close", (code) => resolve6(code === 0 ? out.trim() : null));
|
|
5899
6298
|
});
|
|
5900
6299
|
}
|
|
5901
6300
|
};
|
|
@@ -5914,7 +6313,9 @@ var MUTATING_METHODS = /* @__PURE__ */ new Set([
|
|
|
5914
6313
|
"file.write",
|
|
5915
6314
|
"file.mkdir",
|
|
5916
6315
|
"env.set",
|
|
5917
|
-
"env.delete"
|
|
6316
|
+
"env.delete",
|
|
6317
|
+
"workflow.run",
|
|
6318
|
+
"workflow.cancel"
|
|
5918
6319
|
]);
|
|
5919
6320
|
var PhononConnection = class {
|
|
5920
6321
|
tenantId;
|
|
@@ -5930,6 +6331,7 @@ var PhononConnection = class {
|
|
|
5930
6331
|
files;
|
|
5931
6332
|
env;
|
|
5932
6333
|
obs;
|
|
6334
|
+
workflows;
|
|
5933
6335
|
/** 该 tenant 绑定的默认项目工作目录解析器(v0 简化:projectId 即绝对路径或映射)。 */
|
|
5934
6336
|
resolveProjectCwd;
|
|
5935
6337
|
constructor(opts) {
|
|
@@ -5940,6 +6342,7 @@ var PhononConnection = class {
|
|
|
5940
6342
|
this.idempotency = new IdempotencyStore({ store: this.store });
|
|
5941
6343
|
this.outbox = new Outbox({ store: this.store, tenantId: opts.tenantId });
|
|
5942
6344
|
this.engine = new SessionEngine(opts.registry, (event) => {
|
|
6345
|
+
this.workflows?.onStreamEvent(event);
|
|
5943
6346
|
this.outbox.enqueue(event);
|
|
5944
6347
|
this.peer.notifyRaw("stream.event", event);
|
|
5945
6348
|
}, opts.obs, this.store);
|
|
@@ -5969,6 +6372,13 @@ var PhononConnection = class {
|
|
|
5969
6372
|
this.env = new EnvManager(this.store, { allowReveal: () => this.policy.allowEnvReveal() });
|
|
5970
6373
|
this.resolveProjectCwd = opts.resolveProjectCwd ?? ((p) => this.projects.resolveCwd(p));
|
|
5971
6374
|
this.peer = new RpcPeer(opts.transport, (method, params) => this.dispatch(method, params));
|
|
6375
|
+
this.workflows = new WorkflowEngine({
|
|
6376
|
+
tenantId: this.tenantId,
|
|
6377
|
+
engine: this.engine,
|
|
6378
|
+
resolveCwd: (projectId, worktreeId) => this.projects.resolveCwd(projectId, worktreeId),
|
|
6379
|
+
env: this.env,
|
|
6380
|
+
emit: (event) => this.peer.notifyRaw("workflow.event", event)
|
|
6381
|
+
});
|
|
5972
6382
|
}
|
|
5973
6383
|
/** 喂入收到的文本。 */
|
|
5974
6384
|
handle(data) {
|
|
@@ -6210,6 +6620,17 @@ var PhononConnection = class {
|
|
|
6210
6620
|
}
|
|
6211
6621
|
case "skill.list":
|
|
6212
6622
|
return { skills: this.skills.list({ agent: p.agent, scope: p.scope, projectId: p.projectId }) };
|
|
6623
|
+
case "skill.dirs":
|
|
6624
|
+
return { directories: await this.skills.dirs({ agent: p.agent, scope: p.scope, projectId: p.projectId }) };
|
|
6625
|
+
// ---- L3 workflow orchestration ----
|
|
6626
|
+
case "workflow.run":
|
|
6627
|
+
return this.workflows.run({ project: p.project, worktreeId: p.worktreeId, plan: p.plan, input: p.input, metadata: p.metadata });
|
|
6628
|
+
case "workflow.status":
|
|
6629
|
+
return this.workflows.status(p.workflowId);
|
|
6630
|
+
case "workflow.cancel":
|
|
6631
|
+
return this.workflows.cancel(p.workflowId, p.reason);
|
|
6632
|
+
case "workflow.list":
|
|
6633
|
+
return this.workflows.list(p);
|
|
6213
6634
|
// ---- 连接/可靠性(s2p) ----
|
|
6214
6635
|
case "stream.ack": {
|
|
6215
6636
|
this.outbox.ack(p.sessionId, p.lastSeq);
|
|
@@ -6301,9 +6722,9 @@ function readOpenClawGatewayToken() {
|
|
|
6301
6722
|
|
|
6302
6723
|
// src/commands.ts
|
|
6303
6724
|
import { spawnSync } from "node:child_process";
|
|
6304
|
-
import { existsSync as existsSync12, cpSync, mkdirSync as mkdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync7 } from "node:fs";
|
|
6725
|
+
import { existsSync as existsSync12, cpSync, mkdirSync as mkdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync7, chmodSync as chmodSync3 } from "node:fs";
|
|
6305
6726
|
import { homedir as homedir10, platform as platform2 } from "node:os";
|
|
6306
|
-
import { join as join12, dirname as dirname5, delimiter } from "node:path";
|
|
6727
|
+
import { join as join12, dirname as dirname5, delimiter, resolve as resolve5 } from "node:path";
|
|
6307
6728
|
import { fileURLToPath } from "node:url";
|
|
6308
6729
|
function probe(bin, args2 = ["--version"]) {
|
|
6309
6730
|
const r = spawnSync(bin, args2, { timeout: 8e3, shell: platform2() === "win32" });
|
|
@@ -6483,6 +6904,75 @@ function cmdAdapterList() {
|
|
|
6483
6904
|
console.log(`- ${a.type}${a.defaultAgent ? ` (agent: ${a.defaultAgent})` : ""}${auto}`);
|
|
6484
6905
|
}
|
|
6485
6906
|
}
|
|
6907
|
+
function systemctlUser(args2) {
|
|
6908
|
+
const r = spawnSync("systemctl", ["--user", ...args2], { stdio: "inherit" });
|
|
6909
|
+
if (r.status !== 0) fail(`systemctl --user ${args2.join(" ")} failed`);
|
|
6910
|
+
}
|
|
6911
|
+
function serviceUnitPath() {
|
|
6912
|
+
return join12(homedir10(), ".config", "systemd", "user", "agent-phonon.service");
|
|
6913
|
+
}
|
|
6914
|
+
function serviceUnitContent() {
|
|
6915
|
+
const node = process.execPath;
|
|
6916
|
+
const cli = resolve5(process.argv[1] ?? fileURLToPath(import.meta.url));
|
|
6917
|
+
return `[Unit]
|
|
6918
|
+
Description=agent-phonon device daemon
|
|
6919
|
+
After=network-online.target
|
|
6920
|
+
Wants=network-online.target
|
|
6921
|
+
|
|
6922
|
+
[Service]
|
|
6923
|
+
Type=simple
|
|
6924
|
+
ExecStart=${node} ${cli} start
|
|
6925
|
+
Restart=always
|
|
6926
|
+
RestartSec=5
|
|
6927
|
+
MemoryMax=256M
|
|
6928
|
+
|
|
6929
|
+
[Install]
|
|
6930
|
+
WantedBy=default.target
|
|
6931
|
+
`;
|
|
6932
|
+
}
|
|
6933
|
+
function cmdService(sub, opts = {}) {
|
|
6934
|
+
if (platform2() !== "linux") {
|
|
6935
|
+
fail(`service ${sub ?? ""} is currently implemented for Linux systemd --user only (platform=${platform2()})`);
|
|
6936
|
+
}
|
|
6937
|
+
const unit = serviceUnitPath();
|
|
6938
|
+
switch (sub) {
|
|
6939
|
+
case "install": {
|
|
6940
|
+
if (existsSync12(unit) && !opts.force) fail(`${unit} already exists (use --force to overwrite)`);
|
|
6941
|
+
mkdirSync4(dirname5(unit), { recursive: true });
|
|
6942
|
+
writeFileSync4(unit, serviceUnitContent(), { mode: 420 });
|
|
6943
|
+
chmodSync3(unit, 420);
|
|
6944
|
+
systemctlUser(["daemon-reload"]);
|
|
6945
|
+
systemctlUser(["enable", "agent-phonon.service"]);
|
|
6946
|
+
console.log(`installed systemd user service \u2192 ${unit}`);
|
|
6947
|
+
console.log("start it with: agent-phonon service start");
|
|
6948
|
+
if (!existsSync12(join12(homedir10(), ".agent-phonon", "config.json"))) console.log("config not found yet; run: agent-phonon init");
|
|
6949
|
+
break;
|
|
6950
|
+
}
|
|
6951
|
+
case "start":
|
|
6952
|
+
systemctlUser(["start", "agent-phonon.service"]);
|
|
6953
|
+
console.log("started agent-phonon.service");
|
|
6954
|
+
break;
|
|
6955
|
+
case "stop":
|
|
6956
|
+
systemctlUser(["stop", "agent-phonon.service"]);
|
|
6957
|
+
console.log("stopped agent-phonon.service");
|
|
6958
|
+
break;
|
|
6959
|
+
case "restart":
|
|
6960
|
+
systemctlUser(["restart", "agent-phonon.service"]);
|
|
6961
|
+
console.log("restarted agent-phonon.service");
|
|
6962
|
+
break;
|
|
6963
|
+
case "status":
|
|
6964
|
+
systemctlUser(["status", "agent-phonon.service", "--no-pager"]);
|
|
6965
|
+
break;
|
|
6966
|
+
case "uninstall":
|
|
6967
|
+
systemctlUser(["disable", "--now", "agent-phonon.service"]);
|
|
6968
|
+
rmSync3(unit, { force: true });
|
|
6969
|
+
systemctlUser(["daemon-reload"]);
|
|
6970
|
+
console.log(`removed ${unit}`);
|
|
6971
|
+
break;
|
|
6972
|
+
default:
|
|
6973
|
+
fail("usage: agent-phonon service install|start|stop|restart|status|uninstall [--force]");
|
|
6974
|
+
}
|
|
6975
|
+
}
|
|
6486
6976
|
function cmdPluginInstall(which) {
|
|
6487
6977
|
if (which !== "openclaw") return fail(`plugin install supports: openclaw (got: ${which})`);
|
|
6488
6978
|
const here = dirname5(fileURLToPath(import.meta.url));
|
|
@@ -6521,13 +7011,13 @@ var ObsServer = class {
|
|
|
6521
7011
|
deps.bus.onEvent((e) => this.broadcast(e));
|
|
6522
7012
|
}
|
|
6523
7013
|
listen(port = 4319, host = "127.0.0.1") {
|
|
6524
|
-
return new Promise((
|
|
7014
|
+
return new Promise((resolve6) => {
|
|
6525
7015
|
const server = createServer2((req, res) => this.handle(req, res));
|
|
6526
7016
|
this.server = server;
|
|
6527
7017
|
server.listen(port, host, () => {
|
|
6528
7018
|
const addr = server.address();
|
|
6529
7019
|
this.actualPort = typeof addr === "object" && addr ? addr.port : port;
|
|
6530
|
-
|
|
7020
|
+
resolve6(this.actualPort);
|
|
6531
7021
|
});
|
|
6532
7022
|
});
|
|
6533
7023
|
}
|
|
@@ -6605,11 +7095,11 @@ var ObsServer = class {
|
|
|
6605
7095
|
return this.actualPort;
|
|
6606
7096
|
}
|
|
6607
7097
|
close() {
|
|
6608
|
-
return new Promise((
|
|
7098
|
+
return new Promise((resolve6) => {
|
|
6609
7099
|
for (const c of this.sseClients) c.end();
|
|
6610
7100
|
this.sseClients.clear();
|
|
6611
|
-
if (!this.server) return
|
|
6612
|
-
this.server.close(() =>
|
|
7101
|
+
if (!this.server) return resolve6();
|
|
7102
|
+
this.server.close(() => resolve6());
|
|
6613
7103
|
});
|
|
6614
7104
|
}
|
|
6615
7105
|
};
|
|
@@ -6835,6 +7325,10 @@ async function main() {
|
|
|
6835
7325
|
}
|
|
6836
7326
|
break;
|
|
6837
7327
|
}
|
|
7328
|
+
case "service": {
|
|
7329
|
+
cmdService(args[0], { force: flag("force") });
|
|
7330
|
+
break;
|
|
7331
|
+
}
|
|
6838
7332
|
case "plugin": {
|
|
6839
7333
|
const sub = args[0];
|
|
6840
7334
|
if (sub === "install") cmdPluginInstall(args[1] ?? "");
|
|
@@ -6852,6 +7346,7 @@ async function main() {
|
|
|
6852
7346
|
console.log(" adapter add <type> [opts] configure an adapter override (auto-detect covers common local agents)");
|
|
6853
7347
|
console.log(" adapter list list configured + auto-detected adapters");
|
|
6854
7348
|
console.log(" plugin install openclaw install OpenClaw HITL plugin");
|
|
7349
|
+
console.log(" service install|start|status manage Linux systemd --user service");
|
|
6855
7350
|
console.log(" server add <url> [--trust-local] [--device-key <k>]");
|
|
6856
7351
|
console.log(" server list");
|
|
6857
7352
|
console.log(" config [--show-secrets] show config (redacted by default)");
|