@xgjktech/xg_cwork_im 1.17.25 → 1.17.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +2 -2
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +8 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/src/account-connection.d.ts.map +1 -1
  6. package/dist/src/account-connection.js +32 -18
  7. package/dist/src/account-connection.js.map +1 -1
  8. package/dist/src/account-reconciler.d.ts.map +1 -1
  9. package/dist/src/account-reconciler.js +6 -6
  10. package/dist/src/account-reconciler.js.map +1 -1
  11. package/dist/src/active-round-registry.d.ts +29 -0
  12. package/dist/src/active-round-registry.d.ts.map +1 -0
  13. package/dist/src/active-round-registry.js +60 -0
  14. package/dist/src/active-round-registry.js.map +1 -0
  15. package/dist/src/active-round-registry.test.d.ts +2 -0
  16. package/dist/src/active-round-registry.test.d.ts.map +1 -0
  17. package/dist/src/active-round-registry.test.js +62 -0
  18. package/dist/src/active-round-registry.test.js.map +1 -0
  19. package/dist/src/agent-context-types.js +2 -2
  20. package/dist/src/agent-context-types.js.map +1 -1
  21. package/dist/src/agent-context-types.test.js +9 -0
  22. package/dist/src/agent-context-types.test.js.map +1 -1
  23. package/dist/src/channel-config.d.ts +60 -12
  24. package/dist/src/channel-config.d.ts.map +1 -1
  25. package/dist/src/channel-config.js +6 -2
  26. package/dist/src/channel-config.js.map +1 -1
  27. package/dist/src/dispatch-mentioned-reply.d.ts +3 -0
  28. package/dist/src/dispatch-mentioned-reply.d.ts.map +1 -1
  29. package/dist/src/dispatch-mentioned-reply.js +43 -16
  30. package/dist/src/dispatch-mentioned-reply.js.map +1 -1
  31. package/dist/src/interrupt-round.d.ts +9 -0
  32. package/dist/src/interrupt-round.d.ts.map +1 -0
  33. package/dist/src/interrupt-round.js +44 -0
  34. package/dist/src/interrupt-round.js.map +1 -0
  35. package/dist/src/interrupt-round.test.d.ts +2 -0
  36. package/dist/src/interrupt-round.test.d.ts.map +1 -0
  37. package/dist/src/interrupt-round.test.js +133 -0
  38. package/dist/src/interrupt-round.test.js.map +1 -0
  39. package/dist/src/nas-volumes.d.ts.map +1 -1
  40. package/dist/src/nas-volumes.js +145 -29
  41. package/dist/src/nas-volumes.js.map +1 -1
  42. package/dist/src/nas-volumes.test.js +135 -17
  43. package/dist/src/nas-volumes.test.js.map +1 -1
  44. package/dist/src/session-im-context.d.ts +1 -0
  45. package/dist/src/session-im-context.d.ts.map +1 -1
  46. package/dist/src/session-im-context.js +9 -0
  47. package/dist/src/session-im-context.js.map +1 -1
  48. package/dist/src/subagent-monitor.d.ts +16 -10
  49. package/dist/src/subagent-monitor.d.ts.map +1 -1
  50. package/dist/src/subagent-monitor.js +210 -329
  51. package/dist/src/subagent-monitor.js.map +1 -1
  52. package/dist/src/types.d.ts +9 -4
  53. package/dist/src/types.d.ts.map +1 -1
  54. package/dist/src/types.js.map +1 -1
  55. package/package.json +2 -2
@@ -0,0 +1,133 @@
1
+ import assert from "node:assert/strict";
2
+ import { afterEach, describe, it } from "node:test";
3
+ import { __resetActiveRoundRegistryForTests, prepareActiveRoundInterrupt, registerActiveRound, } from "./active-round-registry.js";
4
+ import { finalizeRoundInterrupt, prepareRoundInterrupt } from "./interrupt-round.js";
5
+ import { __resetSubagentMonitorForTests, markSubagentCompleted, startMonitor, } from "./subagent-monitor.js";
6
+ import { getSessionImContext, setSessionImContext } from "./session-im-context.js";
7
+ afterEach(() => {
8
+ __resetSubagentMonitorForTests();
9
+ __resetActiveRoundRegistryForTests();
10
+ });
11
+ function createClient(events, failSuspended = false) {
12
+ return {
13
+ start: async () => undefined,
14
+ streamProgress: async () => undefined,
15
+ streamUsage: async () => undefined,
16
+ sendEvent: async (event) => {
17
+ events.push(`${event.event}:${String(event.data.subagentList[0]?.status)}`);
18
+ if (failSuspended)
19
+ throw new Error("send failed");
20
+ },
21
+ end: async (reason) => {
22
+ events.push(`FINISHED:${reason}`);
23
+ },
24
+ };
25
+ }
26
+ describe("round interrupt", () => {
27
+ it("先发送 suspended,再发送 FINISHED(aborted),并阻止旧 monitor 复活", async () => {
28
+ const events = [];
29
+ const round = registerActiveRound({
30
+ accountId: "account-a",
31
+ groupId: "group-1",
32
+ agentId: "main",
33
+ sessionKey: "session-1",
34
+ replyToMsgId: "reply-1",
35
+ streamClient: createClient(events),
36
+ });
37
+ assert.equal(startMonitor({
38
+ roundKey: round.roundKey,
39
+ generation: round.generation,
40
+ groupId: round.groupId,
41
+ agentId: round.agentId,
42
+ streamClient: round.streamClient,
43
+ replyToMsgId: round.replyToMsgId,
44
+ spawn: { childSessionKey: "child-1", runId: "run-1", label: "子任务" },
45
+ }), true);
46
+ events.length = 0;
47
+ setSessionImContext(round.sessionKey, {
48
+ groupId: round.groupId,
49
+ replyToMsgId: round.replyToMsgId,
50
+ agentId: round.agentId,
51
+ });
52
+ const prepared = prepareRoundInterrupt("account-a", "group-1");
53
+ assert.ok(prepared);
54
+ assert.equal(getSessionImContext(round.sessionKey), undefined);
55
+ assert.equal(prepared.subagents[0]?.status, "suspended");
56
+ assert.equal(startMonitor({
57
+ roundKey: round.roundKey,
58
+ generation: round.generation,
59
+ groupId: round.groupId,
60
+ agentId: round.agentId,
61
+ streamClient: round.streamClient,
62
+ replyToMsgId: round.replyToMsgId,
63
+ spawn: { childSessionKey: "child-late", runId: "run-late" },
64
+ }), false);
65
+ markSubagentCompleted("child-1", "run-1");
66
+ await finalizeRoundInterrupt(prepared);
67
+ assert.deepEqual(events, ["SUBAGENT_STAT:suspended", "FINISHED:aborted"]);
68
+ assert.equal(prepareActiveRoundInterrupt("account-a", "group-1"), undefined);
69
+ });
70
+ it("suspended 发送失败时仍尝试 aborted 并清理活动轮次", async () => {
71
+ const events = [];
72
+ const round = registerActiveRound({
73
+ accountId: "account-a",
74
+ groupId: "group-1",
75
+ agentId: "main",
76
+ sessionKey: "session-1",
77
+ replyToMsgId: "reply-1",
78
+ streamClient: createClient(events, true),
79
+ });
80
+ startMonitor({
81
+ roundKey: round.roundKey,
82
+ generation: round.generation,
83
+ groupId: round.groupId,
84
+ agentId: round.agentId,
85
+ streamClient: round.streamClient,
86
+ replyToMsgId: round.replyToMsgId,
87
+ spawn: { childSessionKey: "child-1", runId: "run-1" },
88
+ });
89
+ events.length = 0;
90
+ const prepared = prepareRoundInterrupt("account-a", "group-1");
91
+ assert.ok(prepared);
92
+ await finalizeRoundInterrupt(prepared);
93
+ assert.deepEqual(events, ["SUBAGENT_STAT:suspended", "FINISHED:aborted"]);
94
+ assert.equal(prepareActiveRoundInterrupt("account-a", "group-1"), undefined);
95
+ });
96
+ it("停止混合子 Agent 时保留 completed,并只把 running 改为 suspended", async () => {
97
+ const events = [];
98
+ const client = createClient(events);
99
+ const round = registerActiveRound({
100
+ accountId: "account-a",
101
+ groupId: "group-1",
102
+ agentId: "main",
103
+ sessionKey: "session-1",
104
+ replyToMsgId: "reply-1",
105
+ streamClient: client,
106
+ });
107
+ const common = {
108
+ roundKey: round.roundKey,
109
+ generation: round.generation,
110
+ groupId: round.groupId,
111
+ agentId: round.agentId,
112
+ streamClient: client,
113
+ replyToMsgId: round.replyToMsgId,
114
+ };
115
+ startMonitor({
116
+ ...common,
117
+ spawn: { childSessionKey: "child-complete", runId: "run-complete" },
118
+ });
119
+ startMonitor({
120
+ ...common,
121
+ spawn: { childSessionKey: "child-running", runId: "run-running" },
122
+ });
123
+ markSubagentCompleted("child-complete", "run-complete");
124
+ await new Promise((resolve) => setImmediate(resolve));
125
+ const prepared = prepareRoundInterrupt("account-a", "group-1");
126
+ assert.ok(prepared);
127
+ assert.deepEqual(prepared.subagents.map(({ runId, status }) => ({ runId, status })), [
128
+ { runId: "run-complete", status: "completed" },
129
+ { runId: "run-running", status: "suspended" },
130
+ ]);
131
+ });
132
+ });
133
+ //# sourceMappingURL=interrupt-round.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interrupt-round.test.js","sourceRoot":"","sources":["../../src/interrupt-round.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AAEpD,OAAO,EACH,kCAAkC,EAClC,2BAA2B,EAC3B,mBAAmB,GACtB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AACrF,OAAO,EACH,8BAA8B,EAC9B,qBAAqB,EACrB,YAAY,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAEnF,SAAS,CAAC,GAAG,EAAE;IACX,8BAA8B,EAAE,CAAC;IACjC,kCAAkC,EAAE,CAAC;AACzC,CAAC,CAAC,CAAC;AAEH,SAAS,YAAY,CAAC,MAAgB,EAAE,aAAa,GAAG,KAAK;IACzD,OAAO;QACH,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS;QAC5B,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS;QACrC,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS;QAClC,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACvB,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,IAAI,MAAM,CAAE,KAAK,CAAC,IAAI,CAAC,YAA0C,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;YAC3G,IAAI,aAAa;gBAAE,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC;QACtD,CAAC;QACD,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAClB,MAAM,CAAC,IAAI,CAAC,YAAY,MAAM,EAAE,CAAC,CAAC;QACtC,CAAC;KACJ,CAAC;AACN,CAAC;AAED,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,mBAAmB,CAAC;YAC9B,SAAS,EAAE,WAAW;YACtB,OAAO,EAAE,SAAS;YAClB,OAAO,EAAE,MAAM;YACf,UAAU,EAAE,WAAW;YACvB,YAAY,EAAE,SAAS;YACvB,YAAY,EAAE,YAAY,CAAC,MAAM,CAAC;SACrC,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CACR,YAAY,CAAC;YACT,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,KAAK,EAAE,EAAE,eAAe,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE;SACtE,CAAC,EACF,IAAI,CACP,CAAC;QACF,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QAClB,mBAAmB,CAAC,KAAK,CAAC,UAAU,EAAE;YAClC,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,OAAO,EAAE,KAAK,CAAC,OAAO;SACzB,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,qBAAqB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QAC/D,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;QACpB,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC,CAAC;QAC/D,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;QACzD,MAAM,CAAC,KAAK,CACR,YAAY,CAAC;YACT,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,KAAK,EAAE,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE;SAC9D,CAAC,EACF,KAAK,CACR,CAAC;QACF,qBAAqB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAE1C,MAAM,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,yBAAyB,EAAE,kBAAkB,CAAC,CAAC,CAAC;QAC1E,MAAM,CAAC,KAAK,CAAC,2BAA2B,CAAC,WAAW,EAAE,SAAS,CAAC,EAAE,SAAS,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,mBAAmB,CAAC;YAC9B,SAAS,EAAE,WAAW;YACtB,OAAO,EAAE,SAAS;YAClB,OAAO,EAAE,MAAM;YACf,UAAU,EAAE,WAAW;YACvB,YAAY,EAAE,SAAS;YACvB,YAAY,EAAE,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC;SAC3C,CAAC,CAAC;QACH,YAAY,CAAC;YACT,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,KAAK,EAAE,EAAE,eAAe,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE;SACxD,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QAElB,MAAM,QAAQ,GAAG,qBAAqB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QAC/D,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;QACpB,MAAM,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAEvC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,yBAAyB,EAAE,kBAAkB,CAAC,CAAC,CAAC;QAC1E,MAAM,CAAC,KAAK,CAAC,2BAA2B,CAAC,WAAW,EAAE,SAAS,CAAC,EAAE,SAAS,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,KAAK,GAAG,mBAAmB,CAAC;YAC9B,SAAS,EAAE,WAAW;YACtB,OAAO,EAAE,SAAS;YAClB,OAAO,EAAE,MAAM;YACf,UAAU,EAAE,WAAW;YACvB,YAAY,EAAE,SAAS;YACvB,YAAY,EAAE,MAAM;SACvB,CAAC,CAAC;QACH,MAAM,MAAM,GAAG;YACX,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,YAAY,EAAE,MAAM;YACpB,YAAY,EAAE,KAAK,CAAC,YAAY;SACnC,CAAC;QACF,YAAY,CAAC;YACT,GAAG,MAAM;YACT,KAAK,EAAE,EAAE,eAAe,EAAE,gBAAgB,EAAE,KAAK,EAAE,cAAc,EAAE;SACtE,CAAC,CAAC;QACH,YAAY,CAAC;YACT,GAAG,MAAM;YACT,KAAK,EAAE,EAAE,eAAe,EAAE,eAAe,EAAE,KAAK,EAAE,aAAa,EAAE;SACpE,CAAC,CAAC;QACH,qBAAqB,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC;QACxD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;QAE5D,MAAM,QAAQ,GAAG,qBAAqB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QAC/D,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;QACpB,MAAM,CAAC,SAAS,CACZ,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,EAClE;YACI,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE;YAC9C,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE;SAChD,CACJ,CAAC;IACN,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"nas-volumes.d.ts","sourceRoot":"","sources":["../../src/nas-volumes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI7C,MAAM,WAAW,mBAAmB;IAChC,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;CACrB;AAeD,4DAA4D;AAC5D,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAqBzD;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,gDAAgD;AAChD,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,SAAS,GAAG,KAAK,CAAC;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;CACrB,CAAC,CAMD;AA+BD,wBAAgB,8BAA8B,CAC1C,OAAO,EAAE,SAAS,EAAE,EACpB,MAAM,EAAE,UAAU,GACnB,mBAAmB,EAAE,CAwBvB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,MAAM,CAKxE;AAwDD;;GAEG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE;IACjD,GAAG,EAAE,cAAc,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC;CACzB,GAAG;IAAE,GAAG,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CA8B9D;AAED,yBAAyB;AACzB,wBAAgB,2BAA2B,IAAI,IAAI,CAElD"}
1
+ {"version":3,"file":"nas-volumes.d.ts","sourceRoot":"","sources":["../../src/nas-volumes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAQ7C,MAAM,WAAW,mBAAmB;IAChC,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;CACrB;AAqED,4DAA4D;AAC5D,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAqBzD;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,gDAAgD;AAChD,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,SAAS,GAAG,KAAK,CAAC;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;CACrB,CAAC,CAMD;AA6GD,wBAAgB,8BAA8B,CAC1C,OAAO,EAAE,SAAS,EAAE,EACpB,MAAM,EAAE,UAAU,GACnB,mBAAmB,EAAE,CAcvB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,MAAM,CAKxE;AAyDD;;GAEG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE;IACjD,GAAG,EAAE,cAAc,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC;CACzB,GAAG;IAAE,GAAG,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CA0C9D;AAED,yBAAyB;AACzB,wBAAgB,2BAA2B,IAAI,IAAI,CAGlD"}
@@ -2,14 +2,66 @@
2
2
  * 会话级 NAS 目录声明:路径规范化、安全校验、幂等指纹与 OpenClaw sandbox bind 注入。
3
3
  */
4
4
  import { createHash } from "node:crypto";
5
- import { realpathSync, statSync } from "node:fs";
5
+ import { existsSync, mkdirSync, realpathSync, statSync } from "node:fs";
6
6
  import path from "node:path";
7
7
  const SANDBOX_WORKSPACE_ROOT = "/workspace";
8
+ /** 缓存仅用于短期复用同一会话声明;硬上限防止长期运行时随历史会话无限增长。 */
9
+ const SESSION_NAS_VOLUME_STATE_MAX_ENTRIES = 2_000;
10
+ const SESSION_NAS_VOLUME_STATE_TTL_MS = 2 * 60 * 60 * 1_000;
11
+ const SESSION_NAS_VOLUME_STATE_PRUNE_INTERVAL_MS = 60 * 1_000;
8
12
  const sessionVolumeStates = new Map();
13
+ let lastSessionVolumeStatePruneAt = 0;
14
+ function pruneSessionNasVolumeStates(now, force = false) {
15
+ if (!force &&
16
+ sessionVolumeStates.size <= SESSION_NAS_VOLUME_STATE_MAX_ENTRIES &&
17
+ now - lastSessionVolumeStatePruneAt < SESSION_NAS_VOLUME_STATE_PRUNE_INTERVAL_MS) {
18
+ return;
19
+ }
20
+ lastSessionVolumeStatePruneAt = now;
21
+ for (const [key, state] of sessionVolumeStates) {
22
+ if (now - state.lastSeenAt >= SESSION_NAS_VOLUME_STATE_TTL_MS) {
23
+ sessionVolumeStates.delete(key);
24
+ }
25
+ }
26
+ while (sessionVolumeStates.size > SESSION_NAS_VOLUME_STATE_MAX_ENTRIES) {
27
+ const oldestKey = sessionVolumeStates.keys().next().value;
28
+ if (oldestKey == null)
29
+ break;
30
+ sessionVolumeStates.delete(oldestKey);
31
+ }
32
+ }
9
33
  function isInsideOrEqual(root, target) {
10
34
  const relative = path.relative(root, target);
11
35
  return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
12
36
  }
37
+ function bindContainerTarget(bind) {
38
+ const parts = bind.split(":");
39
+ for (let index = parts.length - 1; index >= 0; index -= 1) {
40
+ const candidate = parts[index].trim().replace(/\\/g, "/");
41
+ if (candidate.startsWith("/"))
42
+ return path.posix.normalize(candidate);
43
+ }
44
+ return undefined;
45
+ }
46
+ function assertNoExistingBindTargetConflicts(existingBinds, incomingBinds) {
47
+ for (const incoming of incomingBinds) {
48
+ const incomingTarget = bindContainerTarget(incoming);
49
+ if (!incomingTarget)
50
+ continue;
51
+ for (const existing of existingBinds) {
52
+ if (existing === incoming)
53
+ continue;
54
+ const existingTarget = bindContainerTarget(existing);
55
+ if (!existingTarget)
56
+ continue;
57
+ if (incomingTarget === existingTarget ||
58
+ incomingTarget.startsWith(`${existingTarget}/`) ||
59
+ existingTarget.startsWith(`${incomingTarget}/`)) {
60
+ throw new Error(`NAS_VOLUME_TARGET_CONFLICT: dockerDir 与已有 sandbox bind 目标冲突: ${incomingTarget}, ${existingTarget}`);
61
+ }
62
+ }
63
+ }
64
+ }
13
65
  /** 将 IM 的 dockerDir 规范为不带 /workspace 前缀的 workspace 相对路径。 */
14
66
  export function normalizeNasDockerDir(raw) {
15
67
  let value = raw.trim().replace(/\\/g, "/");
@@ -49,20 +101,81 @@ export function normalizeNasVolumesForPrompt(volumes) {
49
101
  });
50
102
  }
51
103
  function normalizeAllowedRoots(config) {
52
- const configured = config.nasVolumeAllowedRoots?.map((entry) => entry.trim()).filter(Boolean) ?? [];
53
- if (configured.length === 0) {
54
- throw new Error("NAS_VOLUME_ROOTS_NOT_CONFIGURED: channels.xg_cwork_im.nasVolumeAllowedRoots 未配置");
104
+ const mappings = config.nasVolumeRootMappings ?? [];
105
+ if (mappings.length === 0) {
106
+ throw new Error("NAS_VOLUME_ROOTS_NOT_CONFIGURED: channels.xg_cwork_im.nasVolumeRootMappings 未配置");
55
107
  }
56
- return configured.map((root) => {
57
- if (!path.isAbsolute(root)) {
58
- throw new Error(`NAS_VOLUME_ROOT_INVALID: 允许根目录必须是宿主机绝对路径: ${root}`);
108
+ return mappings.map((mapping) => {
109
+ const logicalRoot = normalizeLogicalRoot(mapping.logicalRoot);
110
+ const hostRoot = mapping.hostRoot.trim();
111
+ if (!path.isAbsolute(hostRoot)) {
112
+ throw new Error(`NAS_VOLUME_ROOT_INVALID: hostRoot 必须是宿主机绝对路径: ${hostRoot}`);
59
113
  }
60
- const realRoot = realpathSync(root);
114
+ const configuredRoot = path.resolve(hostRoot);
115
+ const realRoot = realpathSync(configuredRoot);
61
116
  if (!statSync(realRoot).isDirectory()) {
62
- throw new Error(`NAS_VOLUME_ROOT_INVALID: 允许根目录不是目录: ${root}`);
117
+ throw new Error(`NAS_VOLUME_ROOT_INVALID: hostRoot 不是目录: ${hostRoot}`);
63
118
  }
64
- return realRoot;
65
- });
119
+ return { logicalRoot, configuredRoot, realRoot };
120
+ }).sort((left, right) => right.logicalRoot.length - left.logicalRoot.length);
121
+ }
122
+ function normalizeLogicalRoot(raw) {
123
+ const value = raw.trim().replace(/\\/g, "/");
124
+ if (!value.startsWith("/")) {
125
+ throw new Error(`NAS_VOLUME_ROOT_INVALID: logicalRoot 必须是绝对逻辑路径: ${raw}`);
126
+ }
127
+ const normalized = path.posix.normalize(value).replace(/\/+$/, "") || "/";
128
+ if (normalized === "/") {
129
+ throw new Error("NAS_VOLUME_ROOT_INVALID: logicalRoot 不能是根目录 /");
130
+ }
131
+ return normalized;
132
+ }
133
+ function nearestExistingAncestor(target) {
134
+ let current = target;
135
+ while (!existsSync(current)) {
136
+ const parent = path.dirname(current);
137
+ if (parent === current)
138
+ break;
139
+ current = parent;
140
+ }
141
+ return current;
142
+ }
143
+ /**
144
+ * 业务目录允许按需创建,但创建前后都必须确认路径仍位于已存在的白名单根内。
145
+ */
146
+ function ensureNasSourceDirectory(rawDir, allowedRoots) {
147
+ const logicalDir = path.posix.normalize(rawDir.trim().replace(/\\/g, "/"));
148
+ if (!logicalDir.startsWith("/")) {
149
+ throw new Error(`NAS_VOLUME_SOURCE_INVALID: realDir 必须是绝对逻辑路径: ${rawDir}`);
150
+ }
151
+ const allowed = allowedRoots.find((root) => logicalDir !== root.logicalRoot && logicalDir.startsWith(`${root.logicalRoot}/`));
152
+ if (!allowed) {
153
+ throw new Error(`NAS_VOLUME_SOURCE_FORBIDDEN: realDir 未匹配允许的 logicalRoot: ${rawDir}`);
154
+ }
155
+ const target = path.resolve(allowed.configuredRoot, ...path.posix.relative(allowed.logicalRoot, logicalDir).split("/"));
156
+ if (!isInsideOrEqual(allowed.configuredRoot, target) || target === allowed.configuredRoot) {
157
+ throw new Error(`NAS_VOLUME_SOURCE_FORBIDDEN: realDir 越出映射根目录: ${rawDir}`);
158
+ }
159
+ if (!existsSync(target)) {
160
+ const existingAncestor = realpathSync(nearestExistingAncestor(target));
161
+ if (!isInsideOrEqual(allowed.realRoot, existingAncestor)) {
162
+ throw new Error(`NAS_VOLUME_SOURCE_FORBIDDEN: realDir 的父目录越出允许根: ${rawDir}`);
163
+ }
164
+ mkdirSync(target, { recursive: true });
165
+ }
166
+ const realDir = realpathSync(target);
167
+ if (realDir === allowed.realRoot || !isInsideOrEqual(allowed.realRoot, realDir)) {
168
+ throw new Error(`NAS_VOLUME_SOURCE_FORBIDDEN: realDir 不在允许根的业务子目录内: ${rawDir}`);
169
+ }
170
+ if (!statSync(realDir).isDirectory()) {
171
+ throw new Error(`NAS_VOLUME_SOURCE_INVALID: realDir 不是目录: ${rawDir}`);
172
+ }
173
+ const colonIndex = realDir.indexOf(":");
174
+ const isWindowsDrivePrefix = process.platform === "win32" && colonIndex === 1 && /^[A-Za-z]:[\\/]/.test(realDir);
175
+ if (colonIndex >= 0 && !isWindowsDrivePrefix) {
176
+ throw new Error(`NAS_VOLUME_SOURCE_INVALID: realDir 含 Docker bind 不支持的冒号: ${rawDir}`);
177
+ }
178
+ return realDir;
66
179
  }
67
180
  function assertNonOverlappingTargets(volumes) {
68
181
  for (let i = 0; i < volumes.length; i += 1) {
@@ -78,17 +191,7 @@ function assertNonOverlappingTargets(volumes) {
78
191
  export function validateAndNormalizeNasVolumes(volumes, config) {
79
192
  const allowedRoots = normalizeAllowedRoots(config);
80
193
  const normalized = volumes.map((volume) => {
81
- if (!path.isAbsolute(volume.realDir.trim())) {
82
- throw new Error(`NAS_VOLUME_SOURCE_INVALID: realDir 必须是宿主机绝对路径: ${volume.realDir}`);
83
- }
84
- const realDir = realpathSync(volume.realDir.trim());
85
- if (!statSync(realDir).isDirectory()) {
86
- throw new Error(`NAS_VOLUME_SOURCE_INVALID: realDir 不是目录: ${volume.realDir}`);
87
- }
88
- const allowedRoot = allowedRoots.find((root) => isInsideOrEqual(root, realDir));
89
- if (!allowedRoot || realDir === allowedRoot) {
90
- throw new Error(`NAS_VOLUME_SOURCE_FORBIDDEN: realDir 不在允许根的业务子目录内: ${volume.realDir}`);
91
- }
194
+ const realDir = ensureNasSourceDirectory(volume.realDir.trim(), allowedRoots);
92
195
  const dockerDir = normalizeNasDockerDir(volume.dockerDir);
93
196
  return {
94
197
  realDir,
@@ -126,6 +229,7 @@ function injectDockerBinds(cfg, agentId, binds) {
126
229
  const existingBinds = Array.isArray(docker.binds)
127
230
  ? docker.binds.filter((entry) => typeof entry === "string")
128
231
  : [];
232
+ assertNoExistingBindTargetConflicts(existingBinds, binds);
129
233
  return {
130
234
  ...holder,
131
235
  sandbox: {
@@ -156,18 +260,25 @@ function injectDockerBinds(cfg, agentId, binds) {
156
260
  */
157
261
  export function resolveNasVolumeDispatchConfig(args) {
158
262
  const stateKey = `${args.agentId}\0${args.sessionKey}`;
159
- const prior = sessionVolumeStates.get(stateKey);
160
- let normalized;
263
+ const now = Date.now();
264
+ pruneSessionNasVolumeStates(now);
265
+ let prior = sessionVolumeStates.get(stateKey);
266
+ if (prior && now - prior.lastSeenAt >= SESSION_NAS_VOLUME_STATE_TTL_MS) {
267
+ sessionVolumeStates.delete(stateKey);
268
+ prior = undefined;
269
+ }
270
+ let binds;
161
271
  let specHash;
162
272
  if (args.volumes?.length) {
163
- normalized = validateAndNormalizeNasVolumes(args.volumes, args.config);
273
+ const normalized = validateAndNormalizeNasVolumes(args.volumes, args.config);
164
274
  specHash = nasVolumeSpecHash(normalized);
275
+ binds = normalized.map((volume) => `${volume.realDir}:${volume.sandboxDir}:${volume.mode}`);
165
276
  if (prior && prior.specHash !== specHash) {
166
277
  throw new Error("NAS_VOLUME_SESSION_CONFLICT: 当前会话已绑定另一组 NAS 目录,请创建新会话");
167
278
  }
168
279
  }
169
280
  else if (prior) {
170
- normalized = prior.volumes;
281
+ binds = prior.binds;
171
282
  specHash = prior.specHash;
172
283
  }
173
284
  else {
@@ -176,10 +287,14 @@ export function resolveNasVolumeDispatchConfig(args) {
176
287
  if (effectiveSandboxScope(args.cfg, args.agentId) !== "session") {
177
288
  throw new Error("NAS_VOLUME_SANDBOX_SCOPE_INVALID: NAS 挂载要求 sandbox.scope=session");
178
289
  }
179
- sessionVolumeStates.set(stateKey, { specHash, volumes: normalized, lastSeenAt: Date.now() });
180
- const binds = normalized.map((volume) => `${volume.realDir}:${volume.sandboxDir}:${volume.mode}`);
290
+ // 先完成无状态的配置注入与冲突校验,失败时不得污染会话缓存。
291
+ const nextCfg = injectDockerBinds(args.cfg, args.agentId, binds);
292
+ // delete + set 让 Map 插入顺序同时承担 LRU 顺序;达到硬上限时淘汰最久未使用项。
293
+ sessionVolumeStates.delete(stateKey);
294
+ sessionVolumeStates.set(stateKey, { specHash, binds, lastSeenAt: now });
295
+ pruneSessionNasVolumeStates(now, sessionVolumeStates.size > SESSION_NAS_VOLUME_STATE_MAX_ENTRIES);
181
296
  return {
182
- cfg: injectDockerBinds(args.cfg, args.agentId, binds),
297
+ cfg: nextCfg,
183
298
  specHash,
184
299
  reused: prior?.specHash === specHash,
185
300
  };
@@ -187,5 +302,6 @@ export function resolveNasVolumeDispatchConfig(args) {
187
302
  /** 测试与 Gateway 停止时使用。 */
188
303
  export function clearSessionNasVolumeStates() {
189
304
  sessionVolumeStates.clear();
305
+ lastSessionVolumeStatePruneAt = 0;
190
306
  }
191
307
  //# sourceMappingURL=nas-volumes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"nas-volumes.js","sourceRoot":"","sources":["../../src/nas-volumes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"nas-volumes.js","sourceRoot":"","sources":["../../src/nas-volumes.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import assert from "node:assert/strict";
2
- import { mkdtemp, mkdir, rm } from "node:fs/promises";
2
+ import { mkdtemp, mkdir, rm, stat } from "node:fs/promises";
3
3
  import os from "node:os";
4
4
  import path from "node:path";
5
5
  import { afterEach, describe, it } from "node:test";
@@ -27,6 +27,12 @@ function openClawCfg() {
27
27
  },
28
28
  };
29
29
  }
30
+ function mappingConfig(hostRoot) {
31
+ return {
32
+ baseUrl: "https://im.example.test",
33
+ nasVolumeRootMappings: [{ logicalRoot: "/data/touqian", hostRoot }],
34
+ };
35
+ }
30
36
  describe("nasVolumes", () => {
31
37
  it("normalizes workspace-relative dockerDir", () => {
32
38
  assert.equal(normalizeNasDockerDir("/workspace/touqian/2026/08/a/"), "touqian/2026/08/a");
@@ -44,14 +50,14 @@ describe("nasVolumes", () => {
44
50
  assert.equal(result.specHash, undefined);
45
51
  });
46
52
  it("injects binds and reuses the same session spec", async () => {
47
- const { root, caseA } = await fixture();
48
- const config = { baseUrl: "https://im.example.test", nasVolumeAllowedRoots: [root] };
53
+ const { root } = await fixture();
54
+ const config = mappingConfig(root);
49
55
  const args = {
50
56
  cfg: openClawCfg(),
51
57
  config,
52
58
  agentId: "main",
53
59
  sessionKey: "agent:main:xg_cwork_im:group-1",
54
- volumes: [{ realDir: caseA, dockerDir: "touqian/case-a", mode: "ro" }],
60
+ volumes: [{ realDir: "/data/touqian/case-a", dockerDir: "touqian/case-a", mode: "ro" }],
55
61
  };
56
62
  const first = resolveNasVolumeDispatchConfig(args);
57
63
  const second = resolveNasVolumeDispatchConfig(args);
@@ -64,10 +70,125 @@ describe("nasVolumes", () => {
64
70
  assert.ok(docker.binds.some((bind) => bind.endsWith(":/workspace/touqian/case-a:ro")));
65
71
  assert.equal(docker.dangerouslyAllowExternalBindSources, true);
66
72
  assert.equal(docker.dangerouslyAllowReservedContainerTargets, true);
73
+ assert.equal(docker.binds.at(-1), `${path.resolve(root, "case-a")}:/workspace/touqian/case-a:ro`);
74
+ });
75
+ it("rejects a NAS target that conflicts with an existing sandbox bind", async () => {
76
+ const { root } = await fixture();
77
+ const cfg = openClawCfg();
78
+ cfg.agents.defaults.sandbox.docker.binds.push("/other/source:/workspace/touqian/case-a:ro");
79
+ assert.throws(() => resolveNasVolumeDispatchConfig({
80
+ cfg,
81
+ config: mappingConfig(root),
82
+ agentId: "main",
83
+ sessionKey: "agent:main:xg_cwork_im:existing-bind-conflict",
84
+ volumes: [{ realDir: "/data/touqian/case-a", dockerDir: "touqian/case-a", mode: "ro" }],
85
+ }), /NAS_VOLUME_TARGET_CONFLICT/);
86
+ const recovered = resolveNasVolumeDispatchConfig({
87
+ cfg: openClawCfg(),
88
+ config: mappingConfig(root),
89
+ agentId: "main",
90
+ sessionKey: "agent:main:xg_cwork_im:existing-bind-conflict",
91
+ volumes: [{ realDir: "/data/touqian/case-b", dockerDir: "touqian/case-b", mode: "ro" }],
92
+ });
93
+ assert.equal(recovered.reused, false, "失败的配置注入不得污染会话挂载缓存");
94
+ });
95
+ it("expires an idle session mount state after two hours", async () => {
96
+ const { root } = await fixture();
97
+ const originalNow = Date.now;
98
+ let now = originalNow();
99
+ Date.now = () => now;
100
+ try {
101
+ const common = {
102
+ config: mappingConfig(root),
103
+ agentId: "main",
104
+ sessionKey: "agent:main:xg_cwork_im:ttl-session",
105
+ };
106
+ resolveNasVolumeDispatchConfig({
107
+ ...common,
108
+ cfg: openClawCfg(),
109
+ volumes: [{ realDir: "/data/touqian/case-a", dockerDir: "touqian/case-a", mode: "ro" }],
110
+ });
111
+ now += 2 * 60 * 60 * 1_000 + 1;
112
+ const cfg = openClawCfg();
113
+ const expired = resolveNasVolumeDispatchConfig({ ...common, cfg });
114
+ assert.strictEqual(expired.cfg, cfg);
115
+ assert.equal(expired.specHash, undefined);
116
+ }
117
+ finally {
118
+ Date.now = originalNow;
119
+ }
120
+ });
121
+ it("caps cached session mount states and evicts the least recently used entry", async () => {
122
+ const { root } = await fixture();
123
+ const config = mappingConfig(root);
124
+ const volume = [{ realDir: "/data/touqian/case-a", dockerDir: "touqian/case-a", mode: "ro" }];
125
+ for (let index = 0; index <= 2_000; index += 1) {
126
+ resolveNasVolumeDispatchConfig({
127
+ cfg: openClawCfg(),
128
+ config,
129
+ agentId: "main",
130
+ sessionKey: `agent:main:xg_cwork_im:bounded-${index}`,
131
+ volumes: volume,
132
+ });
133
+ }
134
+ const oldestCfg = openClawCfg();
135
+ const oldest = resolveNasVolumeDispatchConfig({
136
+ cfg: oldestCfg,
137
+ config,
138
+ agentId: "main",
139
+ sessionKey: "agent:main:xg_cwork_im:bounded-0",
140
+ });
141
+ assert.strictEqual(oldest.cfg, oldestCfg);
142
+ assert.equal(oldest.specHash, undefined);
143
+ const newest = resolveNasVolumeDispatchConfig({
144
+ cfg: openClawCfg(),
145
+ config,
146
+ agentId: "main",
147
+ sessionKey: "agent:main:xg_cwork_im:bounded-2000",
148
+ });
149
+ assert.ok(newest.specHash);
150
+ assert.equal(newest.reused, true);
151
+ });
152
+ it("creates a missing business source directory below an allowed root", async () => {
153
+ const { root } = await fixture();
154
+ const missing = path.join(root, "CP202205250005", "sequences", "0001", "input");
155
+ const result = resolveNasVolumeDispatchConfig({
156
+ cfg: openClawCfg(),
157
+ config: {
158
+ baseUrl: "https://im.example.test",
159
+ nasVolumeRootMappings: [
160
+ { logicalRoot: "/data/touqian", hostRoot: root },
161
+ ],
162
+ },
163
+ agentId: "main",
164
+ sessionKey: "agent:main:xg_cwork_im:group-create",
165
+ volumes: [
166
+ {
167
+ realDir: "/data/touqian/CP202205250005/sequences/0001/input",
168
+ dockerDir: "touqian/case/input",
169
+ mode: "rw",
170
+ },
171
+ ],
172
+ });
173
+ assert.equal((await stat(missing)).isDirectory(), true);
174
+ const docker = result.cfg.agents.defaults.sandbox.docker;
175
+ assert.ok(docker.binds.some((bind) => bind.endsWith(":/workspace/touqian/case/input:rw")));
176
+ });
177
+ it("never creates a missing directory outside the allowed root", async () => {
178
+ const { root } = await fixture();
179
+ const outside = path.join(root, "outside", "must-not-exist");
180
+ assert.throws(() => resolveNasVolumeDispatchConfig({
181
+ cfg: openClawCfg(),
182
+ config: mappingConfig(root),
183
+ agentId: "main",
184
+ sessionKey: "agent:main:xg_cwork_im:group-outside",
185
+ volumes: [{ realDir: "/data/other/must-not-exist", dockerDir: "touqian/outside", mode: "rw" }],
186
+ }), /NAS_VOLUME_SOURCE_FORBIDDEN/);
187
+ await assert.rejects(stat(outside), /ENOENT/);
67
188
  });
68
189
  it("rejects changing NAS directories in the same session", async () => {
69
- const { root, caseA, caseB } = await fixture();
70
- const config = { baseUrl: "https://im.example.test", nasVolumeAllowedRoots: [root] };
190
+ const { root } = await fixture();
191
+ const config = mappingConfig(root);
71
192
  const common = {
72
193
  cfg: openClawCfg(),
73
194
  config,
@@ -76,15 +197,15 @@ describe("nasVolumes", () => {
76
197
  };
77
198
  resolveNasVolumeDispatchConfig({
78
199
  ...common,
79
- volumes: [{ realDir: caseA, dockerDir: "touqian/case", mode: "ro" }],
200
+ volumes: [{ realDir: "/data/touqian/case-a", dockerDir: "touqian/case", mode: "ro" }],
80
201
  });
81
202
  assert.throws(() => resolveNasVolumeDispatchConfig({
82
203
  ...common,
83
- volumes: [{ realDir: caseB, dockerDir: "touqian/case", mode: "ro" }],
204
+ volumes: [{ realDir: "/data/touqian/case-b", dockerDir: "touqian/case", mode: "ro" }],
84
205
  }), /NAS_VOLUME_SESSION_CONFLICT/);
85
206
  });
86
- it("requires a configured realDir allowlist and rejects overlapping targets", async () => {
87
- const { root, caseA, caseB } = await fixture();
207
+ it("requires root mappings and rejects overlapping targets", async () => {
208
+ const { root } = await fixture();
88
209
  const common = {
89
210
  cfg: openClawCfg(),
90
211
  agentId: "main",
@@ -93,17 +214,14 @@ describe("nasVolumes", () => {
93
214
  assert.throws(() => resolveNasVolumeDispatchConfig({
94
215
  ...common,
95
216
  config: { baseUrl: "https://im.example.test" },
96
- volumes: [{ realDir: caseA, dockerDir: "touqian/case", mode: "ro" }],
217
+ volumes: [{ realDir: "/data/touqian/case-a", dockerDir: "touqian/case", mode: "ro" }],
97
218
  }), /NAS_VOLUME_ROOTS_NOT_CONFIGURED/);
98
219
  assert.throws(() => resolveNasVolumeDispatchConfig({
99
220
  ...common,
100
- config: {
101
- baseUrl: "https://im.example.test",
102
- nasVolumeAllowedRoots: [root],
103
- },
221
+ config: mappingConfig(root),
104
222
  volumes: [
105
- { realDir: caseA, dockerDir: "touqian/case", mode: "ro" },
106
- { realDir: caseB, dockerDir: "touqian/case/output", mode: "rw" },
223
+ { realDir: "/data/touqian/case-a", dockerDir: "touqian/case", mode: "ro" },
224
+ { realDir: "/data/touqian/case-b", dockerDir: "touqian/case/output", mode: "rw" },
107
225
  ],
108
226
  }), /NAS_VOLUME_TARGET_CONFLICT/);
109
227
  });