@mebular/fleet 0.0.0-stage → 0.1.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/agentdir.d.ts +43 -0
- package/dist/agentdir.d.ts.map +1 -0
- package/dist/agentdir.js +107 -0
- package/dist/agentdir.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1135 -0
- package/dist/cli.js.map +1 -0
- package/dist/collab/chatter.d.ts +54 -0
- package/dist/collab/chatter.d.ts.map +1 -0
- package/dist/collab/chatter.js +94 -0
- package/dist/collab/chatter.js.map +1 -0
- package/dist/collab/dag.d.ts +27 -0
- package/dist/collab/dag.d.ts.map +1 -0
- package/dist/collab/dag.js +107 -0
- package/dist/collab/dag.js.map +1 -0
- package/dist/collab/negotiation.d.ts +60 -0
- package/dist/collab/negotiation.d.ts.map +1 -0
- package/dist/collab/negotiation.js +90 -0
- package/dist/collab/negotiation.js.map +1 -0
- package/dist/collab/tree.d.ts +39 -0
- package/dist/collab/tree.d.ts.map +1 -0
- package/dist/collab/tree.js +177 -0
- package/dist/collab/tree.js.map +1 -0
- package/dist/config.d.ts +123 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +206 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/join.d.ts +50 -0
- package/dist/join.d.ts.map +1 -0
- package/dist/join.js +167 -0
- package/dist/join.js.map +1 -0
- package/dist/jointoken.d.ts +144 -0
- package/dist/jointoken.d.ts.map +1 -0
- package/dist/jointoken.js +472 -0
- package/dist/jointoken.js.map +1 -0
- package/dist/model.d.ts +64 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +158 -0
- package/dist/model.js.map +1 -0
- package/dist/onboard.d.ts +90 -0
- package/dist/onboard.d.ts.map +1 -0
- package/dist/onboard.js +510 -0
- package/dist/onboard.js.map +1 -0
- package/dist/protocol/envelope.d.ts +94 -0
- package/dist/protocol/envelope.d.ts.map +1 -0
- package/dist/protocol/envelope.js +169 -0
- package/dist/protocol/envelope.js.map +1 -0
- package/dist/protocol/events.d.ts +51 -0
- package/dist/protocol/events.d.ts.map +1 -0
- package/dist/protocol/events.js +87 -0
- package/dist/protocol/events.js.map +1 -0
- package/dist/qr.d.ts +15 -0
- package/dist/qr.d.ts.map +1 -0
- package/dist/qr.js +52 -0
- package/dist/qr.js.map +1 -0
- package/dist/quickstart.d.ts +167 -0
- package/dist/quickstart.d.ts.map +1 -0
- package/dist/quickstart.js +482 -0
- package/dist/quickstart.js.map +1 -0
- package/dist/quota.d.ts +41 -0
- package/dist/quota.d.ts.map +1 -0
- package/dist/quota.js +84 -0
- package/dist/quota.js.map +1 -0
- package/dist/runtime/agent.d.ts +100 -0
- package/dist/runtime/agent.d.ts.map +1 -0
- package/dist/runtime/agent.js +260 -0
- package/dist/runtime/agent.js.map +1 -0
- package/dist/runtime/executor.d.ts +42 -0
- package/dist/runtime/executor.d.ts.map +1 -0
- package/dist/runtime/executor.js +87 -0
- package/dist/runtime/executor.js.map +1 -0
- package/dist/runtime/fairness.d.ts +25 -0
- package/dist/runtime/fairness.d.ts.map +1 -0
- package/dist/runtime/fairness.js +79 -0
- package/dist/runtime/fairness.js.map +1 -0
- package/dist/runtime/node.d.ts +91 -0
- package/dist/runtime/node.d.ts.map +1 -0
- package/dist/runtime/node.js +203 -0
- package/dist/runtime/node.js.map +1 -0
- package/dist/runtime/openchamber-http.d.ts +27 -0
- package/dist/runtime/openchamber-http.d.ts.map +1 -0
- package/dist/runtime/openchamber-http.js +118 -0
- package/dist/runtime/openchamber-http.js.map +1 -0
- package/dist/runtime/openchamber.d.ts +38 -0
- package/dist/runtime/openchamber.d.ts.map +1 -0
- package/dist/runtime/openchamber.js +43 -0
- package/dist/runtime/openchamber.js.map +1 -0
- package/dist/runtime/planner.d.ts +23 -0
- package/dist/runtime/planner.d.ts.map +1 -0
- package/dist/runtime/planner.js +17 -0
- package/dist/runtime/planner.js.map +1 -0
- package/dist/runtime/worker.d.ts +96 -0
- package/dist/runtime/worker.d.ts.map +1 -0
- package/dist/runtime/worker.js +296 -0
- package/dist/runtime/worker.js.map +1 -0
- package/dist/security.d.ts +462 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +1197 -0
- package/dist/security.js.map +1 -0
- package/dist/store/daemon-store.d.ts +33 -0
- package/dist/store/daemon-store.d.ts.map +1 -0
- package/dist/store/daemon-store.js +115 -0
- package/dist/store/daemon-store.js.map +1 -0
- package/dist/store/file-store.d.ts +22 -0
- package/dist/store/file-store.d.ts.map +1 -0
- package/dist/store/file-store.js +63 -0
- package/dist/store/file-store.js.map +1 -0
- package/dist/store/mebular-store.d.ts +22 -0
- package/dist/store/mebular-store.d.ts.map +1 -0
- package/dist/store/mebular-store.js +53 -0
- package/dist/store/mebular-store.js.map +1 -0
- package/dist/store/message-store.d.ts +26 -0
- package/dist/store/message-store.d.ts.map +1 -0
- package/dist/store/message-store.js +51 -0
- package/dist/store/message-store.js.map +1 -0
- package/dist/surface.d.ts +43 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +515 -0
- package/dist/surface.js.map +1 -0
- package/dist/transport/null.d.ts +7 -0
- package/dist/transport/null.d.ts.map +1 -0
- package/dist/transport/null.js +16 -0
- package/dist/transport/null.js.map +1 -0
- package/dist/transport/spool.d.ts +12 -0
- package/dist/transport/spool.d.ts.map +1 -0
- package/dist/transport/spool.js +54 -0
- package/dist/transport/spool.js.map +1 -0
- package/dist/transport/types.d.ts +21 -0
- package/dist/transport/types.d.ts.map +1 -0
- package/dist/transport/types.js +6 -0
- package/dist/transport/types.js.map +1 -0
- package/dist/version.json +6 -0
- package/package.json +37 -4
- package/protocol/collab.example.json +23 -0
- package/protocol/daemon-home.example.json +66 -0
- package/protocol/envelope.example.json +12 -0
- package/protocol/state-machine.json +14 -0
- package/protocol/task-tree.example.json +72 -0
- package/src/agentdir.ts +138 -0
- package/src/cli.ts +1192 -0
- package/src/collab/chatter.ts +116 -0
- package/src/collab/dag.ts +124 -0
- package/src/collab/negotiation.ts +130 -0
- package/src/collab/tree.ts +184 -0
- package/src/config.ts +286 -0
- package/src/index.ts +39 -0
- package/src/join.ts +227 -0
- package/src/jointoken.ts +609 -0
- package/src/model.ts +203 -0
- package/src/onboard.ts +601 -0
- package/src/protocol/envelope.ts +228 -0
- package/src/protocol/events.ts +135 -0
- package/src/qr.ts +68 -0
- package/src/quickstart.ts +632 -0
- package/src/quota.ts +112 -0
- package/src/runtime/agent.ts +313 -0
- package/src/runtime/executor.ts +114 -0
- package/src/runtime/fairness.ts +90 -0
- package/src/runtime/node.ts +250 -0
- package/src/runtime/openchamber-http.ts +137 -0
- package/src/runtime/openchamber.ts +66 -0
- package/src/runtime/planner.ts +36 -0
- package/src/runtime/worker.ts +354 -0
- package/src/security.ts +1660 -0
- package/src/store/daemon-store.ts +144 -0
- package/src/store/file-store.ts +75 -0
- package/src/store/mebular-store.ts +66 -0
- package/src/store/message-store.ts +62 -0
- package/src/surface.ts +535 -0
- package/src/transport/null.ts +20 -0
- package/src/transport/spool.ts +62 -0
- package/src/transport/types.ts +27 -0
- package/README.md +0 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spool.js","sourceRoot":"","sources":["../../src/transport/spool.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,EAAE;AACF,6EAA6E;AAC7E,kCAAkC;AAElC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAI1C,MAAM,OAAO,cAAc;IACR,IAAI,CAAS;IAE9B,YAAY,QAAgB;QAC1B,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,MAAc;QAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACjC,CAAC;IAEO,SAAS,CAAC,MAAc;QAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAqB;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,KAAK,OAAO,CAAC,CAAC;QAChD,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,SAAwB;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACzC,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,MAAM,KAAK,GAAG,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7E,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACnD,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE5C,MAAM,QAAQ,GAAmB,EAAE,CAAC;QACpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAC7B,IAAI,MAAoB,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAiB,CAAC;YACrE,CAAC;YAAC,MAAM,CAAC;gBACP,wCAAwC;gBACxC,MAAM,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC;gBACvD,SAAS;YACX,CAAC;YACD,MAAM,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;YAC1C,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxB,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,aAAa;IACf,CAAC;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FleetEndpoint } from '../protocol/envelope.js';
|
|
2
|
+
import type { TaskEvent } from '../protocol/events.js';
|
|
3
|
+
/** 传输消息:一次投递(可重复;`event.eventId` 为幂等键)。 */
|
|
4
|
+
export interface FleetMessage {
|
|
5
|
+
/** 传输层消息 id(每次投递唯一,与 `event.eventId` 无关) */
|
|
6
|
+
msgId: string;
|
|
7
|
+
from: FleetEndpoint;
|
|
8
|
+
to: FleetEndpoint;
|
|
9
|
+
event: TaskEvent;
|
|
10
|
+
}
|
|
11
|
+
/** 设备间传输。`drain` 拉取并消费本端收件箱(已消费的不得再次返回;崩溃时允许重投)。 */
|
|
12
|
+
export interface TaskTransport {
|
|
13
|
+
publish(message: FleetMessage): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* 拉取发往 `recipient` 的未消费消息(确定性顺序);拉取后标记为已消费。
|
|
16
|
+
* 至少一次:崩溃可能重投,故消费方必须按 `event.eventId` 幂等。
|
|
17
|
+
*/
|
|
18
|
+
drain(recipient: FleetEndpoint): Promise<FleetMessage[]>;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/transport/types.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,2CAA2C;AAC3C,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,aAAa,CAAC;IACpB,EAAE,EAAE,aAAa,CAAC;IAClB,KAAK,EAAE,SAAS,CAAC;CAClB;AAED,oDAAoD;AACpD,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C;;;OAGG;IACH,KAAK,CAAC,SAAS,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACzD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/transport/types.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,EAAE;AACF,kDAAkD;AAClD,2DAA2D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mebular/fleet",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Mebular 跨设备多 Agent 协作(任务=记忆):task-as-memory 的派发与回收,无中心协调",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"private": false,
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"fleet": "./dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"main": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"src",
|
|
21
|
+
"dist",
|
|
22
|
+
"protocol"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=20"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"prepack": "node ../../scripts/chmod-bins.mjs && node ../../scripts/publish-manifest.mjs set",
|
|
32
|
+
"postpack": "node ../../scripts/publish-manifest.mjs restore"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@mebular/core": "^0.1.0",
|
|
36
|
+
"@mebular/service": "^0.1.0",
|
|
37
|
+
"qrcode-generator": "2.0.4"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"negotiation": {
|
|
3
|
+
"v": 1,
|
|
4
|
+
"messageId": "task-A#neg#1@device-B",
|
|
5
|
+
"taskId": "task-A",
|
|
6
|
+
"round": 1,
|
|
7
|
+
"from": { "device": "device-B", "agent": "worker" },
|
|
8
|
+
"kind": "counter",
|
|
9
|
+
"text": "need more detail"
|
|
10
|
+
},
|
|
11
|
+
"chatter": {
|
|
12
|
+
"v": 1,
|
|
13
|
+
"messageId": "chat-1@device-A",
|
|
14
|
+
"from": { "device": "device-A", "agent": "board" },
|
|
15
|
+
"topic": "status",
|
|
16
|
+
"text": "hello"
|
|
17
|
+
},
|
|
18
|
+
"dagPlan": {
|
|
19
|
+
"root": [{ "intent": "child-0" }, { "intent": "child-1" }],
|
|
20
|
+
"child-0": [],
|
|
21
|
+
"child-1": []
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"note": "W2 一机一节点:统一 home 的守护 config 与 fleet 客户端 config 样例(identity/store 模式字段先行)。",
|
|
3
|
+
"daemonConfig": {
|
|
4
|
+
"storagePath": "~/.mebular/store.jsonl",
|
|
5
|
+
"deviceId": "device-A",
|
|
6
|
+
"identity": {
|
|
7
|
+
"mode": "root"
|
|
8
|
+
},
|
|
9
|
+
"encryption": {
|
|
10
|
+
"level": "none",
|
|
11
|
+
"keyFile": "~/.mebular/master-key.json"
|
|
12
|
+
},
|
|
13
|
+
"network": {
|
|
14
|
+
"enabled": true,
|
|
15
|
+
"libp2p": {
|
|
16
|
+
"listen": [
|
|
17
|
+
"/ip4/0.0.0.0/tcp/4001"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"sync": {
|
|
22
|
+
"namespaces": [
|
|
23
|
+
"tasks"
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
"joinService": {
|
|
27
|
+
"enabled": true,
|
|
28
|
+
"bind": "0.0.0.0",
|
|
29
|
+
"port": 4002
|
|
30
|
+
},
|
|
31
|
+
"mcp": {
|
|
32
|
+
"http": {
|
|
33
|
+
"host": "127.0.0.1",
|
|
34
|
+
"port": 7331,
|
|
35
|
+
"auth": "bearer",
|
|
36
|
+
"tokensFile": "~/.mebular/auth/tokens.json"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"delegatedDaemonConfig": {
|
|
41
|
+
"identity": {
|
|
42
|
+
"mode": "delegated"
|
|
43
|
+
},
|
|
44
|
+
"encryption": {
|
|
45
|
+
"level": "none",
|
|
46
|
+
"userMasterPublicKeyFile": "~/.mebular/user-master-key.json"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"fleetClientConfig": {
|
|
50
|
+
"store": "daemon",
|
|
51
|
+
"daemon": {
|
|
52
|
+
"endpoint": "http://127.0.0.1:7331",
|
|
53
|
+
"token": "meb_<secret>"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"modes": {
|
|
57
|
+
"identity": [
|
|
58
|
+
"root",
|
|
59
|
+
"delegated"
|
|
60
|
+
],
|
|
61
|
+
"store": [
|
|
62
|
+
"daemon",
|
|
63
|
+
"embedded"
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"v": 1,
|
|
3
|
+
"taskId": "task-0001",
|
|
4
|
+
"from": { "device": "device-A", "agent": "planner" },
|
|
5
|
+
"to": { "device": "device-B", "agent": "*" },
|
|
6
|
+
"intent": "summarize",
|
|
7
|
+
"payloadRef": "node-abc123",
|
|
8
|
+
"status": "queued",
|
|
9
|
+
"attempts": 0,
|
|
10
|
+
"expiresAt": 1735689600000,
|
|
11
|
+
"trace": { "causedBy": "task-0000", "chain": ["task-0000"] }
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"statuses": ["queued", "claimed", "running", "done", "failed"],
|
|
4
|
+
"rank": { "queued": 0, "claimed": 1, "running": 2, "done": 3, "failed": 3 },
|
|
5
|
+
"terminal": ["done", "failed"],
|
|
6
|
+
"terminalPrecedence": { "queued": 0, "claimed": 0, "running": 0, "done": 1, "failed": 2 },
|
|
7
|
+
"transitions": {
|
|
8
|
+
"queued": ["claimed", "failed"],
|
|
9
|
+
"claimed": ["running", "failed"],
|
|
10
|
+
"running": ["done", "failed"],
|
|
11
|
+
"done": [],
|
|
12
|
+
"failed": []
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"v": 1,
|
|
3
|
+
"note": "W1 任务树夹具:root 声明预算与派发策略;子任务预算 ≤ 父剩余(越深越小)。",
|
|
4
|
+
"root": {
|
|
5
|
+
"v": 1,
|
|
6
|
+
"eventId": "task-A-root#created",
|
|
7
|
+
"taskId": "task-A-root",
|
|
8
|
+
"type": "created",
|
|
9
|
+
"actor": { "device": "device-A", "agent": "board" },
|
|
10
|
+
"at": 1700000000000,
|
|
11
|
+
"toStatus": "queued",
|
|
12
|
+
"trace": { "chain": [] },
|
|
13
|
+
"to": { "device": "device-B", "agent": "worker" },
|
|
14
|
+
"intent": "root",
|
|
15
|
+
"budget": { "maxDepth": 2, "maxChildren": 4, "maxTasks": 8 },
|
|
16
|
+
"dispatch": "children-ok"
|
|
17
|
+
},
|
|
18
|
+
"childWithinBudget": {
|
|
19
|
+
"v": 1,
|
|
20
|
+
"eventId": "task-A-root~c0#created",
|
|
21
|
+
"taskId": "task-A-root~c0",
|
|
22
|
+
"type": "created",
|
|
23
|
+
"actor": { "device": "device-B", "agent": "worker" },
|
|
24
|
+
"at": 1700000000001,
|
|
25
|
+
"toStatus": "queued",
|
|
26
|
+
"trace": { "causedBy": "task-A-root", "chain": ["task-A-root"] },
|
|
27
|
+
"to": { "device": "device-B", "agent": "worker" },
|
|
28
|
+
"intent": "child-0",
|
|
29
|
+
"budget": { "maxDepth": 1, "maxChildren": 4, "maxTasks": 7 }
|
|
30
|
+
},
|
|
31
|
+
"childOverBudget": {
|
|
32
|
+
"v": 1,
|
|
33
|
+
"eventId": "task-A-root~c1#created",
|
|
34
|
+
"taskId": "task-A-root~c1",
|
|
35
|
+
"type": "created",
|
|
36
|
+
"actor": { "device": "device-B", "agent": "worker" },
|
|
37
|
+
"at": 1700000000002,
|
|
38
|
+
"toStatus": "queued",
|
|
39
|
+
"trace": { "causedBy": "task-A-root", "chain": ["task-A-root"] },
|
|
40
|
+
"to": { "device": "device-B", "agent": "worker" },
|
|
41
|
+
"intent": "child-1",
|
|
42
|
+
"budget": { "maxDepth": 2, "maxChildren": 4, "maxTasks": 7 }
|
|
43
|
+
},
|
|
44
|
+
"rootOnlyChild": {
|
|
45
|
+
"v": 1,
|
|
46
|
+
"eventId": "task-A-ro#created",
|
|
47
|
+
"taskId": "task-A-ro~c0",
|
|
48
|
+
"type": "created",
|
|
49
|
+
"actor": { "device": "device-B", "agent": "worker" },
|
|
50
|
+
"at": 1700000000003,
|
|
51
|
+
"toStatus": "queued",
|
|
52
|
+
"trace": { "causedBy": "task-A-ro", "chain": ["task-A-ro"] },
|
|
53
|
+
"to": { "device": "device-B", "agent": "worker" },
|
|
54
|
+
"intent": "child",
|
|
55
|
+
"budget": { "maxDepth": 1, "maxChildren": 4, "maxTasks": 7 },
|
|
56
|
+
"note": "需与 rootOnlyRoot 同树;此处仅字段样例"
|
|
57
|
+
},
|
|
58
|
+
"rootOnlyRoot": {
|
|
59
|
+
"v": 1,
|
|
60
|
+
"eventId": "task-A-ro#created",
|
|
61
|
+
"taskId": "task-A-ro",
|
|
62
|
+
"type": "created",
|
|
63
|
+
"actor": { "device": "device-A", "agent": "board" },
|
|
64
|
+
"at": 1700000000003,
|
|
65
|
+
"toStatus": "queued",
|
|
66
|
+
"trace": { "chain": [] },
|
|
67
|
+
"to": { "device": "device-B", "agent": "worker" },
|
|
68
|
+
"intent": "root",
|
|
69
|
+
"budget": { "maxDepth": 3, "maxChildren": 4, "maxTasks": 8 },
|
|
70
|
+
"dispatch": "root-only"
|
|
71
|
+
}
|
|
72
|
+
}
|
package/src/agentdir.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// W1 每设备 Agent 目录(普通记忆域,默认 `agents`)。
|
|
2
|
+
//
|
|
3
|
+
// 每设备一条**签名**记录(作者=设备;随已有记忆同步,证书链由 core 校验):
|
|
4
|
+
// { device, agents:[{name,kind,capabilities?,concurrency,capacity?}], updatedAt, version }
|
|
5
|
+
// `task_targets` = **我 L1 授权过的对端** ∩ 其目录里的 `(device, agent)`。
|
|
6
|
+
// `capacity`/`load` 为**建议性**(不参与授权与一致性判定)。
|
|
7
|
+
|
|
8
|
+
import type { Mebular } from '@mebular/core';
|
|
9
|
+
import { MebularMessageStore } from './store/message-store.js';
|
|
10
|
+
|
|
11
|
+
export const AGENT_DIRECTORY_MESSAGE_TYPE = 'agent_directory';
|
|
12
|
+
|
|
13
|
+
export interface AgentDirectoryAgent {
|
|
14
|
+
name: string;
|
|
15
|
+
/** 执行器 kind(与 `FleetAgentConfig.kind` 对齐:echo/command/hermes/openchamber) */
|
|
16
|
+
kind: string;
|
|
17
|
+
capabilities?: string[];
|
|
18
|
+
concurrency?: number;
|
|
19
|
+
/** 建议性容量提示(**不参与授权/一致性**) */
|
|
20
|
+
capacity?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface AgentDirectoryEntry {
|
|
24
|
+
v: number;
|
|
25
|
+
device: string;
|
|
26
|
+
agents: AgentDirectoryAgent[];
|
|
27
|
+
/** 本机墙钟(**advisory**;不参与一致性判定) */
|
|
28
|
+
updatedAt: number;
|
|
29
|
+
/** 单调版本:同设备取最大者(R-c 式确定序,无墙钟) */
|
|
30
|
+
version: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function isNonEmptyString(value: unknown): value is string {
|
|
34
|
+
return typeof value === 'string' && value.length > 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface AgentDirectoryValidation {
|
|
38
|
+
ok: boolean;
|
|
39
|
+
errors: string[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function validateAgentDirectory(input: unknown): AgentDirectoryValidation {
|
|
43
|
+
const errors: string[] = [];
|
|
44
|
+
if (typeof input !== 'object' || input === null || Array.isArray(input)) return { ok: false, errors: ['目录必须是对象'] };
|
|
45
|
+
const e = input as Record<string, unknown>;
|
|
46
|
+
if (e.v !== 1) errors.push('v 必须为 1');
|
|
47
|
+
if (!isNonEmptyString(e.device)) errors.push('device 必须为非空字符串');
|
|
48
|
+
if (typeof e.updatedAt !== 'number' || !Number.isFinite(e.updatedAt)) errors.push('updatedAt 必须为有限数字');
|
|
49
|
+
if (typeof e.version !== 'number' || !Number.isInteger(e.version) || e.version < 0) errors.push('version 必须为非负整数');
|
|
50
|
+
if (!Array.isArray(e.agents)) {
|
|
51
|
+
errors.push('agents 必须为数组');
|
|
52
|
+
} else {
|
|
53
|
+
for (const a of e.agents as Array<Record<string, unknown>>) {
|
|
54
|
+
if (!isNonEmptyString(a?.name)) errors.push('agent.name 必须为非空字符串');
|
|
55
|
+
if (!isNonEmptyString(a?.kind)) errors.push('agent.kind 必须为非空字符串');
|
|
56
|
+
if (a?.capabilities !== undefined && (!Array.isArray(a.capabilities) || a.capabilities.some((c) => typeof c !== 'string'))) {
|
|
57
|
+
errors.push('agent.capabilities 若存在须为字符串数组');
|
|
58
|
+
}
|
|
59
|
+
if (a?.concurrency !== undefined && (typeof a.concurrency !== 'number' || !Number.isInteger(a.concurrency) || a.concurrency < 1)) {
|
|
60
|
+
errors.push('agent.concurrency 若存在须为正整数');
|
|
61
|
+
}
|
|
62
|
+
if (a?.capacity !== undefined && (typeof a.capacity !== 'number' || !Number.isFinite(a.capacity) || a.capacity < 0)) {
|
|
63
|
+
errors.push('agent.capacity 若存在须为非负数字(advisory)');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return { ok: errors.length === 0, errors };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** 构造目录存储(校验 + 幂等键 `device@version`)。 */
|
|
71
|
+
export function agentDirectoryStore(mebular: Mebular, namespace = 'agents'): MebularMessageStore<AgentDirectoryEntry> {
|
|
72
|
+
return new MebularMessageStore<AgentDirectoryEntry>(mebular, {
|
|
73
|
+
type: AGENT_DIRECTORY_MESSAGE_TYPE,
|
|
74
|
+
namespace,
|
|
75
|
+
validate: validateAgentDirectory,
|
|
76
|
+
idOf: (e) => `${e.device}@${e.version}`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** 每设备最新目录(同设备取 `version` 最大;平局取稳定序列化较大者,确定性)。 */
|
|
81
|
+
export function latestDirectories(entries: readonly AgentDirectoryEntry[]): AgentDirectoryEntry[] {
|
|
82
|
+
const byDevice = new Map<string, AgentDirectoryEntry>();
|
|
83
|
+
for (const e of entries) {
|
|
84
|
+
const prev = byDevice.get(e.device);
|
|
85
|
+
if (prev === undefined) {
|
|
86
|
+
byDevice.set(e.device, e);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const stronger =
|
|
90
|
+
e.version !== prev.version
|
|
91
|
+
? e.version > prev.version
|
|
92
|
+
: stable(e) > stable(prev);
|
|
93
|
+
if (stronger) byDevice.set(e.device, e);
|
|
94
|
+
}
|
|
95
|
+
return [...byDevice.values()].sort((a, b) => (a.device < b.device ? -1 : a.device > b.device ? 1 : 0));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function stable(value: unknown): string {
|
|
99
|
+
if (value === undefined) return 'null';
|
|
100
|
+
if (value === null || typeof value !== 'object') return JSON.stringify(value);
|
|
101
|
+
if (Array.isArray(value)) return `[${value.map(stable).join(',')}]`;
|
|
102
|
+
const rec = value as Record<string, unknown>;
|
|
103
|
+
return `{${Object.keys(rec).sort().map((k) => `${JSON.stringify(k)}:${stable(rec[k])}`).join(',')}}`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface TaskTarget {
|
|
107
|
+
device: string;
|
|
108
|
+
agent: string;
|
|
109
|
+
kind: string;
|
|
110
|
+
concurrency?: number;
|
|
111
|
+
capacity?: number;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* `task_targets` = **L1 授权过的对端** ∩ 其目录里的 `(device, agent)`。
|
|
116
|
+
* 授权集合外的设备记录一律忽略(默认拒绝;授权是前提)。确定序(device, agent)。
|
|
117
|
+
*/
|
|
118
|
+
export function expandTargets(
|
|
119
|
+
entries: readonly AgentDirectoryEntry[],
|
|
120
|
+
authorizedDevices: readonly string[],
|
|
121
|
+
): TaskTarget[] {
|
|
122
|
+
const allowed = new Set(authorizedDevices);
|
|
123
|
+
const targets: TaskTarget[] = [];
|
|
124
|
+
for (const entry of latestDirectories(entries)) {
|
|
125
|
+
if (!allowed.has(entry.device)) continue;
|
|
126
|
+
for (const agent of [...entry.agents].sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))) {
|
|
127
|
+
if (!isNonEmptyString(agent.name) || !isNonEmptyString(agent.kind)) continue;
|
|
128
|
+
targets.push({
|
|
129
|
+
device: entry.device,
|
|
130
|
+
agent: agent.name,
|
|
131
|
+
kind: agent.kind,
|
|
132
|
+
...(agent.concurrency !== undefined ? { concurrency: agent.concurrency } : {}),
|
|
133
|
+
...(agent.capacity !== undefined ? { capacity: agent.capacity } : {}),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return targets;
|
|
138
|
+
}
|