@sema-agent/server 7.139.0 → 7.140.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.
Files changed (194) hide show
  1. package/MIGRATION.md +181 -0
  2. package/USAGE.md +19 -13
  3. package/dist/adoption/runner.js +1 -1
  4. package/dist/adoption/sql.js +1 -1
  5. package/dist/approval-card.d.ts +6 -6
  6. package/dist/bench/s1/live-deps.js +3 -2
  7. package/dist/bench/s1/row.d.ts +5 -2
  8. package/dist/bench/s1/row.js +2 -22
  9. package/dist/boot/adoption.js +1 -1
  10. package/dist/boot/execution-env.js +12 -10
  11. package/dist/boot/execution-lane.d.ts +8 -0
  12. package/dist/boot/execution-lane.js +6 -1
  13. package/dist/boot/memory-boundary.d.ts +14 -51
  14. package/dist/boot/memory-boundary.js +10 -20
  15. package/dist/boot/memory-consolidation.d.ts +15 -11
  16. package/dist/boot/memory-consolidation.js +23 -12
  17. package/dist/boot/resolve-spec.d.ts +3 -5
  18. package/dist/boot/resolve-spec.js +2 -4
  19. package/dist/boot/runner-deps.d.ts +3 -3
  20. package/dist/boot/runner-deps.js +1 -0
  21. package/dist/boot/stage-03-store-backend.d.ts +2 -6
  22. package/dist/boot/stage-03-store-backend.js +2 -3
  23. package/dist/boot/stage-04-stores.d.ts +2 -6
  24. package/dist/boot/stage-04-stores.js +5 -5
  25. package/dist/boot/stage-05-execution-env.d.ts +2 -6
  26. package/dist/boot/stage-06-runners.d.ts +2 -6
  27. package/dist/boot/stage-06-runners.js +2 -2
  28. package/dist/boot/stage-07-capability-layer.d.ts +2 -6
  29. package/dist/boot/stage-08-reapers.d.ts +2 -6
  30. package/dist/boot/stage-09-leader.d.ts +2 -6
  31. package/dist/boot/stage-10-http-server.d.ts +2 -6
  32. package/dist/boot/stage-10-http-server.js +5 -4
  33. package/dist/boot/stores.d.ts +3 -6
  34. package/dist/boot/stores.js +27 -40
  35. package/dist/boot/task-list-lane.d.ts +1 -1
  36. package/dist/boot/task-list-lane.js +1 -1
  37. package/dist/boot/web-admin.js +35 -9
  38. package/dist/capabilities/execution-lane.d.ts +2 -2
  39. package/dist/config-catalog.js +2 -1
  40. package/dist/config-provider.d.ts +14 -13
  41. package/dist/config-provider.js +24 -18
  42. package/dist/config-types.d.ts +11 -2
  43. package/dist/config.js +2 -1
  44. package/dist/delegated-session-owner.d.ts +2 -1
  45. package/dist/delegated-session-owner.js +1 -1
  46. package/dist/deployment-shape.d.ts +9 -8
  47. package/dist/deployment-shape.js +4 -4
  48. package/dist/execution-lane-caps.d.ts +97 -106
  49. package/dist/execution-lane-caps.js +67 -83
  50. package/dist/http/memory-compliance-failure-reply.d.ts +3 -1
  51. package/dist/http/memory-compliance-failure-reply.js +5 -0
  52. package/dist/http/memory-layer-reply.d.ts +30 -0
  53. package/dist/http/memory-layer-reply.js +24 -0
  54. package/dist/http/resume-legs.js +13 -16
  55. package/dist/http/retired-service-deps.d.ts +1 -1
  56. package/dist/http/retired-service-deps.js +1 -1
  57. package/dist/http/routes/adoption.js +1 -1
  58. package/dist/http/routes/memory-bundle.js +3 -0
  59. package/dist/http/routes/memory-compliance.js +8 -1
  60. package/dist/http/routes/memory-consolidation.js +12 -1
  61. package/dist/http/routes/memory-origin.js +14 -2
  62. package/dist/http/routes/memory-policy.js +5 -0
  63. package/dist/http/routes/sessions.js +28 -11
  64. package/dist/http/routes/tasks.js +4 -2
  65. package/dist/http/server.d.ts +5 -25
  66. package/dist/http/server.js +2 -2
  67. package/dist/identity-source.d.ts +1 -1
  68. package/dist/identity-source.js +1 -1
  69. package/dist/lane-home-probe.d.ts +68 -42
  70. package/dist/lane-home-probe.js +53 -30
  71. package/dist/leader/wire.js +5 -4
  72. package/dist/memory-bundle-engine.d.ts +16 -9
  73. package/dist/memory-bundle-engine.js +29 -6
  74. package/dist/memory-operator-faces.d.ts +85 -30
  75. package/dist/memory-operator-faces.js +136 -30
  76. package/dist/memory-project-layer.d.ts +3 -21
  77. package/dist/memory-project-layer.js +11 -8
  78. package/dist/memory-scope-stores.d.ts +73 -0
  79. package/dist/memory-scope-stores.js +86 -0
  80. package/dist/memory-scope.d.ts +29 -5
  81. package/dist/memory-scope.js +16 -4
  82. package/dist/memory-sync-client.d.ts +20 -7
  83. package/dist/memory-sync-client.js +31 -13
  84. package/dist/plugins/adoption-log-sql.js +4 -4
  85. package/dist/plugins/approval-ask-store-sql.js +14 -14
  86. package/dist/plugins/approval-nonce-store.js +4 -4
  87. package/dist/plugins/blob-backend.d.ts +4 -4
  88. package/dist/plugins/blob-backend.js +7 -7
  89. package/dist/plugins/breaker-state-sql.js +2 -2
  90. package/dist/plugins/checkpoint-index-columns.js +2 -2
  91. package/dist/plugins/checkpoint-store-sql.js +16 -16
  92. package/dist/plugins/device-store-sql.js +19 -19
  93. package/dist/plugins/ensure-index.d.ts +1 -2
  94. package/dist/plugins/execution-placement-sql.d.ts +8 -8
  95. package/dist/plugins/execution-placement-sql.js +8 -8
  96. package/dist/plugins/file-history-store-sql.d.ts +2 -2
  97. package/dist/plugins/file-history-store-sql.js +4 -4
  98. package/dist/plugins/image-bake-store-sql.js +9 -9
  99. package/dist/plugins/image-index-sql.js +11 -11
  100. package/dist/plugins/leader-run-store-sql.js +4 -4
  101. package/dist/plugins/mailbox-store-sql.d.ts +2 -1
  102. package/dist/plugins/mailbox-store-sql.js +4 -4
  103. package/dist/plugins/memory-engine-tidb.js +5 -5
  104. package/dist/plugins/memory-optout-grant-store-sql.js +1 -1
  105. package/dist/plugins/memory-sync-store-tidb.js +3 -3
  106. package/dist/plugins/one-time-migrations.d.ts +10 -9
  107. package/dist/plugins/one-time-migrations.js +36 -36
  108. package/dist/plugins/org-delivery-quota-store.js +2 -2
  109. package/dist/plugins/outcome-ledger-sql.js +2 -2
  110. package/dist/plugins/permission-rule-store-sql.d.ts +4 -4
  111. package/dist/plugins/permission-rule-store-sql.js +16 -16
  112. package/dist/plugins/remote-env-adb.d.ts +7 -24
  113. package/dist/plugins/remote-env-adb.js +22 -5
  114. package/dist/plugins/remote-env-device.d.ts +2 -28
  115. package/dist/plugins/remote-env-device.js +2 -1
  116. package/dist/plugins/remote-env-e2b.d.ts +18 -26
  117. package/dist/plugins/remote-env-e2b.js +51 -4
  118. package/dist/plugins/remote-env-file-error.d.ts +1 -1
  119. package/dist/plugins/remote-env-file-error.js +8 -2
  120. package/dist/plugins/remote-env-host.d.ts +19 -35
  121. package/dist/plugins/remote-env-host.js +26 -3
  122. package/dist/plugins/remote-env-k8s.d.ts +3 -14
  123. package/dist/plugins/remote-env-k8s.js +3 -2
  124. package/dist/plugins/remote-env-local-docker.d.ts +4 -15
  125. package/dist/plugins/remote-env-local-docker.js +5 -4
  126. package/dist/plugins/remote-env-ssh.d.ts +4 -24
  127. package/dist/plugins/remote-env-ssh.js +4 -3
  128. package/dist/plugins/resume-anchor-store-sql.js +2 -2
  129. package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
  130. package/dist/plugins/retention-lane-store-sql.js +2 -2
  131. package/dist/plugins/retention-store-sql.d.ts +1 -1
  132. package/dist/plugins/retention-store-sql.js +6 -6
  133. package/dist/plugins/run-store-sql.js +15 -15
  134. package/dist/plugins/schema-consistency.d.ts +6 -6
  135. package/dist/plugins/schema-consistency.js +1 -1
  136. package/dist/plugins/schema-ensure-legs.d.ts +2 -3
  137. package/dist/plugins/schema-ensure-legs.js +2 -2
  138. package/dist/plugins/schema-live-columns.d.ts +1 -1
  139. package/dist/plugins/session-capture-record-store-sql.js +1 -1
  140. package/dist/plugins/session-rules-column.d.ts +1 -1
  141. package/dist/plugins/session-rules-column.js +1 -1
  142. package/dist/plugins/session-workspace-cell.d.ts +1 -1
  143. package/dist/plugins/session-workspace-cell.js +1 -1
  144. package/dist/plugins/shared-memory-store-sql.js +2 -2
  145. package/dist/plugins/sql-driver.d.ts +10 -5
  146. package/dist/plugins/sql-driver.js +6 -6
  147. package/dist/plugins/sql-errors.js +1 -1
  148. package/dist/plugins/store-backend.d.ts +4 -6
  149. package/dist/plugins/store-backend.js +6 -6
  150. package/dist/plugins/task-list-store-sql.js +11 -11
  151. package/dist/plugins/tidb-pool.js +5 -5
  152. package/dist/plugins/tidb-session-storage.js +4 -4
  153. package/dist/plugins/tidb-session-store.js +13 -13
  154. package/dist/plugins/tool-result-store-sql.d.ts +2 -2
  155. package/dist/plugins/tool-result-store-sql.js +3 -3
  156. package/dist/plugins/user-input-ledger-sql.js +2 -2
  157. package/dist/plugins/workflow-journal-store-sql.js +5 -5
  158. package/dist/plugins/workflow-run-store-sql.js +19 -19
  159. package/dist/plugins/write-behind-counter.d.ts +2 -3
  160. package/dist/plugins/write-behind-counter.js +5 -5
  161. package/dist/resource-suspend.d.ts +14 -12
  162. package/dist/resource-suspend.js +1 -1
  163. package/dist/resource-window.d.ts +4 -3
  164. package/dist/run-local.js +14 -19
  165. package/dist/runs.d.ts +8 -4
  166. package/dist/runs.js +49 -65
  167. package/dist/session-incarnation.d.ts +1 -1
  168. package/dist/session-incarnation.js +1 -1
  169. package/dist/session-policy-wire.d.ts +1 -1
  170. package/dist/sql-engine-posture.d.ts +1 -1
  171. package/dist/sql-engine-posture.js +1 -1
  172. package/dist/{plugins → stores-sql}/background-agent-store-sql.d.ts +2 -2
  173. package/dist/{plugins → stores-sql}/background-agent-store-sql.js +8 -8
  174. package/dist/{plugins → stores-sql}/session-policy-store-sql.d.ts +7 -5
  175. package/dist/{plugins → stores-sql}/session-policy-store-sql.js +12 -12
  176. package/dist/{plugins → stores-sql}/usage-window-store-sql.d.ts +1 -1
  177. package/dist/{plugins → stores-sql}/usage-window-store-sql.js +3 -3
  178. package/dist/task-a2a.js +5 -6
  179. package/dist/task-mcp.d.ts +20 -7
  180. package/dist/task-mcp.js +17 -9
  181. package/dist/terminal.d.ts +27 -0
  182. package/dist/terminal.js +6 -0
  183. package/dist/trace/redact.d.ts +3 -1
  184. package/dist/trace/redact.js +80 -28
  185. package/dist/trace/self-minted-wire.d.ts +58 -0
  186. package/dist/trace/self-minted-wire.js +16 -0
  187. package/dist/web-admin-client/candidate-gate.d.ts +11 -7
  188. package/dist/web-admin-client/candidate-gate.js +1 -1
  189. package/dist/web-admin-client/http-client.d.ts +5 -4
  190. package/dist/web-admin-client/http-client.js +2 -2
  191. package/dist/web-admin-client/read-warnings.d.ts +7 -17
  192. package/dist/web-admin-client/read-warnings.js +5 -9
  193. package/package.json +2 -2
  194. package/wire-changes/server@7.140.0.json +184 -0
@@ -1,39 +1,53 @@
1
1
  /**
2
- * 执行环境的家目录:**声明 × 实测**的唯一判官与唯一的座(纯叶:零值依赖)。
2
+ * 执行环境的家目录:**主张 × 实测**的唯一判官与唯一的座(纯叶:零值依赖)。
3
3
  *
4
- * ## 病(一)—— 声明了却对不上
5
- * `REMOTE_EXEC_HOME_DIR` 是运维对「执行环境以哪个用户的家目录运行」的声明,它是 `~/` 形权限规则的基、引擎家锚拒读行(`~/.ssh` / `~/.npmrc` …)
6
- * 的落点(`execution-lane-caps.ts` `executionLaneHomeDir` 一只属主,几个消费面同读)。k8s / local-docker / ssh 三条车道的家目录是镜像 / 目标机
7
- * 登录用户的属性,boot 期不可知 —— 声明了就照单全收。声明 `/home/y` 而车道真实家目录是 `/home/x` 时,`Edit(~/.ssh/**)` 守的是 `/home/y`,
8
- * `/home/x/.ssh` 照读照写,运维与用户零告警:限制写了不生效且无人知。
4
+ * ## 病(一)—— 给了家目录却对不上
5
+ * 部署事先给每只执行环境一个家目录:运维声明 `REMOTE_EXEC_HOME_DIR`,或车道自己的出厂答案(声明缺席时 host = 本进程的家目录、e2b = 平台固定用户的
6
+ * `/home/user`;`execution-lane-caps.ts` `executionLaneHomeDir` 一只属主)。它是 `~/` 形权限规则的基、引擎家锚拒读行(`~/.ssh` / `~/.npmrc` …)的落点。
7
+ * 给的是 `/home/y` 而环境里命令真看到的 `$HOME` 是 `/home/x` 时,`Edit(~/.ssh/**)` 守的是 `/home/y`,`/home/x/.ssh` 照读照写,运维与用户零告警:
8
+ * 限制写了不生效且无人知(镜像换代换了用户、e2b 自定义模板换了用户、host 上会话 `settings.env` 改了 `HOME` —— 都是这一形)。
9
9
  *
10
- * ## 病(二)—— 没声明就恒问人
11
- * 执行环境不声明家目录时,引擎的家锚拒读行放不下 ⇒ 每一次泄内容的递归读(`grep -r` / `rg` / `git grep` / `tar c`)在全 shell 面恒问人、只读面直接拒。
10
+ * ## 病(二)—— 没给就恒问人
11
+ * 执行环境没有家目录时,引擎的家锚拒读行放不下 ⇒ 每一次泄内容的递归读(`grep -r` / `rg` / `git grep` / `tar c`)在全 shell 面恒问人、只读面直接拒。
12
12
  * 家目录是执行环境自己的事实,车道开环境那一拍问一次就知道 —— 不必要运维手填。
13
13
  *
14
- * ## 律(一只座、两个来源、一条取值律 —— {@link LaneHomeSeat},四条会问的车道各持一只,不各写一份)
15
- * · **声明在场 ⇒ 声明**(座 = 声明原样)。车道对证与否是车道的姿势(`verifiesDeclared`):对证的车道在开环境那一拍问一次(与命令同一条 shell、同一份 env:
16
- * `printf %s "$HOME"`),两者不一致 ⇒ 这只执行环境不开(拒句点名两值与两条改法),环境答了的判定记在环境上(同一镜像 / 同一目标机再问也是同一个答案,不重试成风暴);
17
- * 问不出答案同样不开(证不了声明 = 不拿一个没证过的目录去守),但不记 —— 与任何一次建连失败同,下一次重问;不对证的车道(adb:Android 没有 POSIX 登录家目录,声明是运维的断言)声明照单全收。
18
- * · **没声明 ⇒ 实测**:同一拍问同一句;答出绝对路径 ⇒ 座 = 它,之后不再问;
19
- * · **实测也缺席**(问不出 / 答的不是绝对路径,含空串)⇒ 座缺席(引擎失败关闭,不猜、不补 `/`),环境照开(没声明就没有声明可拒),一行 warn(点名读到了什么与出路)。
20
- * 规则基与 422 门在下单那一刻就要家目录,而那一刻执行环境还没开 —— 它们仍只读声明(`executionLaneHomeDir`);实测值只填引擎手里的这一只座。
14
+ * ## 律(一条:读得出就读,读数是真源 —— {@link LaneHomeSeat},每只读得出家目录的适配器各持一只,不各写一份)
15
+ * · **有主张 ⇒ 证**:座 = 主张原样(下单门与引擎 prepare 在环境开起来之前就要基);开环境那一拍读一次(与命令同一条 shell、同一份 env:
16
+ * `printf %s "$HOME"`;host 直接读它自己组合给子进程的那份 env),两者不一致 ⇒ 这只执行环境不开(拒句点名两值与改法),环境答了的判定记在环境上
17
+ * (同一镜像 / 同一目标机再问也是同一个答案,不重试成风暴);读不出同样不开(证不了主张 = 不拿一个没证过的目录去守),但不记 —— 与任何一次建连失败同,下一次重问。
18
+ * · **没主张 ⇒ 实测**:同一拍问同一句;答出绝对路径 ⇒ 座 = 它,之后不再问;
19
+ * · **实测也缺席**(问不出 / 答的不是绝对路径,含空串)⇒ 座缺席(引擎失败关闭,不猜、不补 `/`),环境照开(没主张就没有主张可拒),一行 warn(点名读到了什么与出路)。
20
+ * 读不了家目录的车道(device:设备协议没有读数)不持座 —— 声明就是座,起服披露「来自声明、未实测」(`execution-lane-caps.ts` `buildLaneHomeBootNote`)。
21
+ * 规则基与 422 门在下单那一刻就要家目录,而那一刻执行环境还没开 —— 它们只读主张(`executionLaneHomeDir`);环境开起来时主张被证,证不了的环境不开。
21
22
  */
22
- /** 探针答案的行首标记:登录脚本 / profile 往 stdout 打的横幅不会被读成家目录 —— 只认带这个标记的那一行(取最后一行)。 */
23
+ /** 探针答案的行首标记:登录脚本 / profile 往 stdout 打的横幅不会被读成家目录 —— 只认带这个标记的那一行(恰一条,见 `markedHome`)。 */
23
24
  export declare const LANE_HOME_PROBE_MARKER = "sema-lane-home=";
24
25
  /**
25
26
  * 执行环境里问家目录的那一句 —— 经车道自己的命令通道跑(同一条 shell、同一份 env),答的就是命令看到的 `$HOME`。
26
27
  * 先换一行再打标记行:横幅没以换行收尾时,标记行照样从行首开始。
27
28
  */
28
29
  export declare const LANE_HOME_PROBE_COMMAND = "printf '\\nsema-lane-home=%s\\n' \"$HOME\"";
29
- /** 一次问家目录的读数:问到了(stdout 原文)/ 没问到(原因)。 */
30
+ /**
31
+ * 一次问家目录的读数:探针的 stdout 原文(经车道命令通道跑 {@link LANE_HOME_PROBE_COMMAND})/ 直接读到的值(适配器自己组合子进程 env 的车道 —— host:
32
+ * 那份 env 里的 `HOME`;缺席时读子进程 shell 对 `~` 的展开,见 `remote-env-host.ts` `childHome`)/ 没问到(原因)。
33
+ */
30
34
  export type LaneHomeProbe = {
31
35
  readonly ok: true;
32
36
  readonly stdout: string;
37
+ } | {
38
+ readonly ok: true;
39
+ readonly value: string;
33
40
  } | {
34
41
  readonly ok: false;
35
42
  readonly reason: string;
36
43
  };
44
+ /** 主张的来源 —— 只进拒句(改法随它):运维声明(`REMOTE_EXEC_HOME_DIR`)/ 车道自己的出厂答案(声明缺席时;没有「删声明」这条路)。 */
45
+ export type LaneHomeSource = "declared" | "lane";
46
+ /** 部署交给一只执行环境的家目录主张:值 + 来源。 */
47
+ export interface LaneHomeClaim {
48
+ readonly home: string;
49
+ readonly source: LaneHomeSource;
50
+ }
37
51
  /**
38
52
  * 判定:`undefined` = 一致,照开;否则这只环境不开 —— `refusal` 是拒句,`answered` = 环境**答了**它的家目录(不一致 / 不是绝对路径;同一镜像 / 同一登录用户
39
53
  * 再问也是同一个答案 ⇒ 调用方记在环境上),`false` = 没答上(探针失败 / 超时 / 非零退出 / 输出里没有标记行 ⇒ 这一次不开、不记、下一次重问)。
@@ -43,9 +57,17 @@ export type LaneHomeVerdict = {
43
57
  readonly answered: boolean;
44
58
  } | undefined;
45
59
  /**
46
- * 声明 × 实测的判官。`lane` 只进句子。拒句三形:实测与声明不一致 / 实测不是绝对路径(含空)/ 没问到。每一形都点名声明值与改法,不回显任何别的东西。
60
+ * 执行环境的路径平台 —— 「绝对」与「同一个目录」两条判据随它:远端车道(k8s / local-docker / ssh / adb / e2b,Linux / Android 的 POSIX shell)= `posix`;
61
+ * win32 宿主上的 host 车道 = `win32`(子进程的 `HOME` 是盘符形)。车道没得选:是环境自己的平台,由持座的适配器说(缺省 `posix`)。
47
62
  */
48
- export declare function judgeLaneHome(lane: string, declared: string, probe: LaneHomeProbe): LaneHomeVerdict;
63
+ export type LanePathFlavor = "posix" | "win32";
64
+ /**
65
+ * 主张 × 实测的判官(全仓唯一一只:每只读得出家目录的适配器经 {@link LaneHomeSeat} 用它,自己不比)。`lane` 只进句子。
66
+ * 拒句闭集 3 形 × 2 来源:实测与主张不一致 / 实测不是绝对路径(含空)/ 没问到;每一句都点名主张(与实测值,有就点名)和改法,不回显任何别的东西。
67
+ * 改法随来源:声明 ⇒「改成实测值或删掉声明」;出厂答案 ⇒ 只有「设成实测值」(没有声明可删)。另一条路两种来源同:让环境的 `HOME` 读主张那个值。
68
+ * 次序:读不出 → 不是绝对路径 → 一致 → 不一致(「绝对」先于「一致」:主张自己是相对串时,一个同样相对的读数也不放行)。
69
+ */
70
+ export declare function judgeLaneHome(lane: string, claim: LaneHomeClaim, probe: LaneHomeProbe, paths?: LanePathFlavor): LaneHomeVerdict;
49
71
  /** 起服与每只环境「家目录答不出」那一行 warn 的事件名 —— 一只 code,起服(车道读不了)与环境(实测缺席)共用。 */
50
72
  export declare const LANE_HOME_UNDECLARED_EVENT = "execution_lane_home_undeclared";
51
73
  /**
@@ -55,52 +77,56 @@ export declare const LANE_HOME_UNDECLARED_EVENT = "execution_lane_home_undeclare
55
77
  export declare function buildHomeAbsentNote(lane: string, cause: string, remedy: string): string;
56
78
  /** 车道读不了家目录时的出路(起服那一行):声明它。 */
57
79
  export declare const DECLARE_HOME_REMEDY = "Declare the home: REMOTE_EXEC_HOME_DIR=<the absolute path the environment's $HOME reads>";
80
+ /** 读不了家目录的车道(今天只有 device)上声明在场时,起服那一行 warn 的事件名:座 = 声明,没有任何读数证过它。 */
81
+ export declare const LANE_HOME_UNMEASURED_EVENT = "execution_lane_home_unmeasured";
82
+ /**
83
+ * 「这条车道的家目录来自声明、未实测」的一句(纯字符串 ⇒ `build*`)—— 读得出的车道由 {@link judgeLaneHome} 证主张,读不了的车道没有那一步,起服把这件事说出来:
84
+ * 规则落在哪、对不上时会怎样、运维要守住什么。
85
+ */
86
+ export declare function buildHomeUnmeasuredNote(lane: string, declared: string): string;
58
87
  /** 一行「这只环境没有家目录」的事实:交给运维的那一行 warn 的两个字段。 */
59
88
  export interface LaneHomeAbsence {
60
89
  readonly provider: string;
61
90
  readonly note: string;
62
91
  }
63
- /** 这条车道的座怎么长出来:`declared` = 运维声明(`REMOTE_EXEC_HOME_DIR`,boot 期的唯一属主 `executionLaneHomeDir` 的答案);`verifiesDeclared` = 车道对声明对证。 */
64
- export interface LaneHomeSeatOptions {
65
- readonly lane: string;
66
- readonly declared: string | undefined;
67
- readonly verifiesDeclared: boolean;
68
- /** 实测缺席时交出那一行 warn(缺席 = 不交;生产装配由 boot 递一只带去重的报告座,见 {@link createLaneHomeAbsenceReporter})。 */
69
- readonly onAbsent?: ((absence: LaneHomeAbsence) => void) | undefined;
70
- }
71
92
  /**
72
- * 四条会问家目录的车道(k8s / local-docker / ssh / adb)的适配器配置里与家目录有关的两个键 —— 文字只写这一处,四个配置接口 `extends` 它。
93
+ * 会读家目录的车道(k8s / local-docker / ssh / adb / e2b / host)的适配器配置里与家目录有关的三个键 —— 文字只写这一处,各配置接口 `extends` 它;
94
+ * {@link LaneHomeSeat} 直接吃它。
73
95
  */
74
96
  export interface LaneHomeConfig {
75
97
  /**
76
- * [ref]④ / core [ref] —— 运维声明的执行环境 **home 目录**(绝对路径,本环境自己的命名空间里;`REMOTE_EXEC_HOME_DIR`)。`~/…` 形权限规则(`Edit(~/.ssh/**)`)对**跑在本 env 里的调用**
77
- * 就以它为基。值由 `boot/execution-env.ts` 从**唯一属主** `execution-lane-caps.ts` 的 `executionLaneHomeDir` 递进来;adapter 不自算(两处各算一份 = 422 门与引擎对同一条规则给相反答案)。
78
- * 缺席 ⇒ 不声明:车道建环境时自己问执行环境的 `$HOME`({@link LaneHomeSeat});实测也缺席 ⇒ 本 env 的 `homeDir` 座缺席,core 对 `~/` 规则判 `unreadable`
98
+ * [ref]④ / core [ref] —— 部署给本执行环境的 **home 目录主张**(绝对路径,本环境自己的命名空间里):运维声明 `REMOTE_EXEC_HOME_DIR`,或车道出厂答案。
99
+ * `~/…` 形权限规则(`Edit(~/.ssh/**)`)对**跑在本 env 里的调用**就以它为基。值由 `boot/execution-env.ts` 从**唯一属主** `execution-lane-caps.ts` 的
100
+ * `buildLaneHomeClaim` 递进来;adapter 不自算(两处各算一份 = 422 门与引擎对同一条规则给相反答案)。在场 ⇒ 环境开起来时与 `$HOME` 对证,不一致 ⇒ 这只环境不开。
101
+ * 缺席 ⇒ 车道建环境时自己问执行环境的 `$HOME`({@link LaneHomeSeat});实测也缺席 ⇒ 本 env 的 `homeDir` 座缺席,core 对 `~/` 规则判 `unreadable`
79
102
  * (fail-closed 的 ask),绝不回落引擎进程自己的 home(那在远端腿上是另一个用户的另一个目录 —— 静默守错目录正是 [ref] 的病)。
80
103
  */
81
104
  homeDir?: string;
82
- /** 实测缺席(没声明、也没问到绝对路径)时交出那一行 warn;缺席 = 不交。生产装配由 boot 递一只带去重的报告座({@link createLaneHomeAbsenceReporter})。 */
105
+ /** {@link homeDir} 的来源(只进拒句的改法):`declared` = `REMOTE_EXEC_HOME_DIR`;`lane` = 车道出厂答案。缺席读作 `declared`。 */
106
+ homeDirSource?: LaneHomeSource;
107
+ /** 实测缺席(没主张、也没问到绝对路径)时交出那一行 warn;缺席 = 不交。生产装配由 boot 递一只带去重的报告座({@link createLaneHomeAbsenceReporter})。 */
83
108
  onHomeAbsent?: (absence: LaneHomeAbsence) => void;
84
109
  }
85
110
  /**
86
- * 一只执行环境的家目录座 —— `ExecutionEnv.homeDir` 的**唯一取值律**:声明在场 ⇒ 声明;否则 ⇒ 车道开环境时实测到的绝对路径;实测也缺席 ⇒ `undefined`(引擎失败关闭)。
87
- * 车道只做两件事:`asks` 为真时经自己的命令通道跑一次 {@link LANE_HOME_PROBE_COMMAND},把读数交给 {@link settle};`homeDir` 读 {@link home}。
111
+ * 一只执行环境的家目录座 —— `ExecutionEnv.homeDir` 的**唯一取值律**:主张在场 ⇒ 主张(并在开环境时被证);否则 ⇒ 车道开环境时实测到的绝对路径;
112
+ * 实测也缺席 ⇒ `undefined`(引擎失败关闭)。车道只做两件事:`asks` 为真时读一次(命令通道跑 {@link LANE_HOME_PROBE_COMMAND},或直接读自己组合的 env),
113
+ * 把读数交给 {@link settle};`homeDir` 读 {@link home}。
88
114
  */
89
115
  export declare class LaneHomeSeat {
90
116
  private measured;
91
117
  private readonly lane;
92
- private readonly declared;
93
- private readonly verifiesDeclared;
118
+ private readonly claim;
94
119
  private readonly onAbsent;
95
- constructor(options: LaneHomeSeatOptions);
96
- /** 座:声明胜,否则实测,否则缺席。 */
120
+ private readonly paths;
121
+ /** `paths` = 执行环境自己的路径平台({@link LanePathFlavor};缺省 POSIX —— 只有 win32 宿主上的 host 适配器说 `win32`)。 */
122
+ constructor(lane: string, config: LaneHomeConfig, paths?: LanePathFlavor);
123
+ /** 座:主张胜,否则实测,否则缺席。 */
97
124
  get home(): string | undefined;
98
- /** 这一拍还要不要问:声明在场 ⇒ 只有对证的车道问(每次连接);没声明 ⇒ 问到量出绝对路径为止。 */
125
+ /** 这一拍还要不要问:主张在场 ⇒ 每只新环境 / 每条新连接都问(对证);没主张 ⇒ 问到量出绝对路径为止。 */
99
126
  get asks(): boolean;
100
127
  /**
101
- * 收一次读数。声明在场(且车道对证)⇒ {@link judgeLaneHome}:`undefined` = 一致,否则这只环境不开(拒句 + 记不记见 {@link LaneHomeVerdict});
102
- * 没声明 ⇒ 读到绝对路径就记下;读不到 / 不是绝对路径 ⇒ 座缺席、交一行 warn、**不拒环境**(`undefined`)—— 没声明就没有声明可拒,引擎对缺席座失败关闭。
103
- * 不对证的车道声明在场时不该来问(`asks` 为假),来了照单全收。
128
+ * 收一次读数。主张在场 ⇒ {@link judgeLaneHome}:`undefined` = 一致,否则这只环境不开(拒句 + 记不记见 {@link LaneHomeVerdict});
129
+ * 没主张 ⇒ 读到绝对路径就记下;读不到 / 不是绝对路径 ⇒ 座缺席、交一行 warn、**不拒环境**(`undefined`)—— 没主张就没有主张可拒,引擎对缺席座失败关闭。
104
130
  */
105
131
  settle(probe: LaneHomeProbe): LaneHomeVerdict;
106
132
  }
@@ -2,7 +2,13 @@ export const LANE_HOME_PROBE_MARKER = "sema-lane-home=";
2
2
  export const LANE_HOME_PROBE_COMMAND = `printf '\\n${LANE_HOME_PROBE_MARKER}%s\\n' "$HOME"`;
3
3
  const SHOWN_MAX = 256;
4
4
  const shown = (raw) => JSON.stringify(raw.length > SHOWN_MAX ? `${raw.slice(0, SHOWN_MAX)}…` : raw);
5
- const comparable = (p) => (p.length > 1 ? p.replace(/\/+$/, "") : p);
5
+ const isAbsoluteHome = (p, paths) => (paths === "win32" ? /^[A-Za-z]:[\\/]/.test(p) || /^[\\/]{2}[^\\/]/.test(p) : p.startsWith("/"));
6
+ const comparable = (p, paths) => {
7
+ if (paths === "posix")
8
+ return p.length > 1 ? p.replace(/\/+$/, "") : p;
9
+ const q = p.replace(/\//g, "\\").toLowerCase();
10
+ return /^[a-z]:\\$/.test(q) ? q : q.replace(/\\+$/, "");
11
+ };
6
12
  function markedHome(stdout) {
7
13
  const lines = stdout.split("\n").map((l) => l.replace(/\r$/, ""));
8
14
  const marked = lines.flatMap((l, i) => (l.startsWith(LANE_HOME_PROBE_MARKER) ? [i] : []));
@@ -13,34 +19,45 @@ function markedHome(stdout) {
13
19
  return { why: "the probe output holds more than one home line or text after it, so it cannot be read as one path" };
14
20
  return { home: lines[at].slice(LANE_HOME_PROBE_MARKER.length) };
15
21
  }
16
- function readLaneHome(probe) {
22
+ function readLaneHome(probe, paths) {
17
23
  if (!probe.ok)
18
24
  return { kind: "unread", reason: probe.reason };
19
- const marked = markedHome(probe.stdout);
20
- if ("why" in marked)
21
- return { kind: "unread", reason: marked.why };
22
- return marked.home.startsWith("/") ? { kind: "home", home: marked.home } : { kind: "not_absolute", value: marked.home };
25
+ let home;
26
+ if ("value" in probe)
27
+ home = probe.value;
28
+ else {
29
+ const marked = markedHome(probe.stdout);
30
+ if ("why" in marked)
31
+ return { kind: "unread", reason: marked.why };
32
+ home = marked.home;
33
+ }
34
+ return isAbsoluteHome(home, paths) ? { kind: "home", home } : { kind: "not_absolute", value: home };
23
35
  }
24
- export function judgeLaneHome(lane, declared, probe) {
25
- const head = `REMOTE_EXEC_HOME_DIR=${shown(declared)} is the home "~/" permission rules and the engine's home-anchored read-deny rows are placed under on the ${lane} execution lane`;
26
- const reading = readLaneHome(probe);
36
+ export function judgeLaneHome(lane, claim, probe, paths = "posix") {
37
+ const declared = claim.source === "declared";
38
+ const head = declared
39
+ ? `REMOTE_EXEC_HOME_DIR=${shown(claim.home)} is the home "~/" permission rules and the engine's home-anchored read-deny rows are placed under on the ${lane} execution lane`
40
+ : `${shown(claim.home)} — the ${lane} execution lane's own home, used because REMOTE_EXEC_HOME_DIR is unset — is the home "~/" permission rules and the engine's home-anchored read-deny rows are placed under`;
41
+ const unconfirmed = declared ? "the declaration cannot be confirmed" : "that home cannot be confirmed";
42
+ const reading = readLaneHome(probe, paths);
27
43
  if (reading.kind === "unread") {
28
44
  return {
29
- refusal: `${head}, but the home of this execution environment could not be read (${reading.reason}) — the declaration cannot be confirmed, so this environment is not started. Fix the lane, or unset REMOTE_EXEC_HOME_DIR (home-relative rules are then refused at submission instead).`,
45
+ refusal: `${head}, but the home of this execution environment could not be read (${reading.reason}) — ${unconfirmed}, so this environment is not started. ${declared ? "Fix the lane, or unset REMOTE_EXEC_HOME_DIR." : "Fix the lane so the environment answers its $HOME."}`,
30
46
  answered: false,
31
47
  };
32
48
  }
33
49
  if (reading.kind === "not_absolute") {
34
50
  return {
35
- refusal: `${head}, but this execution environment reports HOME=${shown(reading.value)}, not an absolute path — the declaration cannot be confirmed, so this environment is not started. Give the environment's user a home (HOME), or unset REMOTE_EXEC_HOME_DIR.`,
51
+ refusal: `${head}, but this execution environment reports HOME=${shown(reading.value)}, not an absolute path — ${unconfirmed}, so this environment is not started. ${declared ? "Give the environment's user a home (HOME), or unset REMOTE_EXEC_HOME_DIR." : "Give the environment's user a home (HOME)."}`,
36
52
  answered: true,
37
53
  };
38
54
  }
39
- if (comparable(reading.home) === comparable(declared))
55
+ if (comparable(reading.home, paths) === comparable(claim.home, paths))
40
56
  return undefined;
57
+ const measured = shown(reading.home);
41
58
  return {
42
- refusal: `${head}, but its commands run with HOME=${shown(reading.home)} — rules would guard ${shown(declared)} while ${shown(reading.home)} stays readable and writable, ` +
43
- `so this environment is not started. Set REMOTE_EXEC_HOME_DIR to ${shown(reading.home)}, or run the environment as the user whose home is ${shown(declared)}.`,
59
+ refusal: `${head}, but its commands run with HOME=${measured} — rules would guard ${shown(claim.home)} while ${measured} stays readable and writable, ` +
60
+ `so this environment is not started. Set REMOTE_EXEC_HOME_DIR to ${measured}${declared ? " or remove it" : ""}, or make the environment's HOME read ${shown(claim.home)}.`,
44
61
  answered: true,
45
62
  };
46
63
  }
@@ -52,37 +69,43 @@ export function buildHomeAbsentNote(lane, cause, remedy) {
52
69
  }
53
70
  const DECLARE_ARG = "REMOTE_EXEC_HOME_DIR=<the absolute path the environment's $HOME reads>";
54
71
  export const DECLARE_HOME_REMEDY = `Declare the home: ${DECLARE_ARG}`;
72
+ export const LANE_HOME_UNMEASURED_EVENT = "execution_lane_home_unmeasured";
73
+ export function buildHomeUnmeasuredNote(lane, declared) {
74
+ return (`the ${lane} lane cannot read its execution environment's home, so REMOTE_EXEC_HOME_DIR=${shown(declared)} is taken as declared, not measured: ` +
75
+ `"~/" permission rules and the engine's home-anchored read-deny rows are placed under it. If the environment's $HOME is another directory, those rules guard ${shown(declared)} ` +
76
+ `while the real home stays readable and writable — keep REMOTE_EXEC_HOME_DIR equal to the $HOME the environment's commands see.`);
77
+ }
55
78
  export class LaneHomeSeat {
56
79
  measured;
57
80
  lane;
58
- declared;
59
- verifiesDeclared;
81
+ claim;
60
82
  onAbsent;
61
- constructor(options) {
62
- this.lane = options.lane;
63
- this.declared = options.declared;
64
- this.verifiesDeclared = options.verifiesDeclared;
65
- this.onAbsent = options.onAbsent;
83
+ paths;
84
+ constructor(lane, config, paths = "posix") {
85
+ this.lane = lane;
86
+ this.paths = paths;
87
+ this.claim = config.homeDir === undefined ? undefined : { home: config.homeDir, source: config.homeDirSource ?? "declared" };
88
+ this.onAbsent = config.onHomeAbsent;
66
89
  }
67
90
  get home() {
68
- return this.declared ?? this.measured;
91
+ return this.claim?.home ?? this.measured;
69
92
  }
70
93
  get asks() {
71
- return this.declared === undefined ? this.measured === undefined : this.verifiesDeclared;
94
+ return this.claim !== undefined || this.measured === undefined;
72
95
  }
73
96
  settle(probe) {
74
- if (this.declared !== undefined)
75
- return this.verifiesDeclared ? judgeLaneHome(this.lane, this.declared, probe) : undefined;
76
- const reading = readLaneHome(probe);
97
+ if (this.claim !== undefined)
98
+ return judgeLaneHome(this.lane, this.claim, probe, this.paths);
99
+ const reading = readLaneHome(probe, this.paths);
77
100
  if (reading.kind === "home") {
78
101
  this.measured = reading.home;
79
102
  return undefined;
80
103
  }
81
104
  const because = reading.kind === "unread" ? `could not be read (${reading.reason})` : `reads ${shown(reading.value)}, not an absolute path`;
82
- const remedy = this.verifiesDeclared
83
- ? "Give the environment's user an absolute HOME (a declared REMOTE_EXEC_HOME_DIR is checked against it, so declaring cannot stand in for it)."
84
- : `Give the environment's user an absolute HOME, or declare it: ${DECLARE_ARG}.`;
85
- this.onAbsent?.({ provider: this.lane, note: buildHomeAbsentNote(this.lane, `REMOTE_EXEC_HOME_DIR is unset and the environment's own $HOME ${because}`, remedy) });
105
+ this.onAbsent?.({
106
+ provider: this.lane,
107
+ note: buildHomeAbsentNote(this.lane, `REMOTE_EXEC_HOME_DIR is unset and the environment's own $HOME ${because}`, "Give the environment's user an absolute HOME (a declared REMOTE_EXEC_HOME_DIR is checked against it, so declaring cannot stand in for it)."),
108
+ });
86
109
  return undefined;
87
110
  }
88
111
  }
@@ -9,7 +9,8 @@ import { leaderEntryRefusal, leaderRunEntry } from "./run-entry.js";
9
9
  import { buildCheckpointCtx } from "../http/checkpoint-ctx.js";
10
10
  import { serviceVersion } from "../service-version.js";
11
11
  import { RemoteContainerExecutionEnv } from "../plugins/remote-env-e2b.js";
12
- import { E2B_SANDBOX_HOME } from "../execution-lane-caps.js";
12
+ import { buildLaneHomeClaim } from "../execution-lane-caps.js";
13
+ const e2bBaseTemplateHomeSeat = buildLaneHomeClaim({ remoteExec: { provider: "e2b" } });
13
14
  import { createDurableAskPolicy } from "../approval.js";
14
15
  import { gitSubprocessEnv } from "../server-secret-env.js";
15
16
  import { presignS3Url } from "../plugins/s3-presign.js";
@@ -366,7 +367,7 @@ export function createLeaderRunner(cfg) {
366
367
  }
367
368
  if (!cfg.e2bApiKey)
368
369
  throw new Error("leader wire: no envFactory+s3 (factory mode) and no e2bApiKey (static mode)");
369
- const env = new RemoteContainerExecutionEnv({ apiKey: cfg.e2bApiKey, timeoutMs: leaderTimeoutMs, homeDir: E2B_SANDBOX_HOME });
370
+ const env = new RemoteContainerExecutionEnv({ apiKey: cfg.e2bApiKey, timeoutMs: leaderTimeoutMs, ...e2bBaseTemplateHomeSeat });
370
371
  if (!(await env.connect()).ok)
371
372
  throw new Error(`connect failed for ${sub.workerId}`);
372
373
  await sh(env)(`${body.seedCmd}; cd ${repo}; git checkout -q -b ${sub.branch}`);
@@ -399,7 +400,7 @@ export function createLeaderRunner(cfg) {
399
400
  }
400
401
  if (!cfg.e2bApiKey)
401
402
  throw new Error("leader wire: no envFactory and no e2bApiKey");
402
- const env = new RemoteContainerExecutionEnv({ apiKey: cfg.e2bApiKey, timeoutMs: leaderTimeoutMs, homeDir: E2B_SANDBOX_HOME });
403
+ const env = new RemoteContainerExecutionEnv({ apiKey: cfg.e2bApiKey, timeoutMs: leaderTimeoutMs, ...e2bBaseTemplateHomeSeat });
403
404
  if (!(await env.connect()).ok) {
404
405
  await env.destroy().catch(() => { });
405
406
  throw new Error("integ connect failed");
@@ -439,7 +440,7 @@ export function createLeaderRunner(cfg) {
439
440
  else {
440
441
  if (!cfg.e2bApiKey)
441
442
  throw new Error("leader wire: repair-loop grader needs an envFactory or e2bApiKey");
442
- const e2b = new RemoteContainerExecutionEnv({ apiKey: cfg.e2bApiKey, timeoutMs: leaderTimeoutMs, homeDir: E2B_SANDBOX_HOME });
443
+ const e2b = new RemoteContainerExecutionEnv({ apiKey: cfg.e2bApiKey, timeoutMs: leaderTimeoutMs, ...e2bBaseTemplateHomeSeat });
443
444
  if (!(await e2b.connect()).ok) {
444
445
  await e2b.destroy().catch(() => { });
445
446
  throw new Error("repair-loop grader connect failed");
@@ -4,11 +4,18 @@
4
4
  * ## 为什么需要这个模块(而不是在 main.ts 里直接 new)
5
5
  *
6
6
  * 本仓**没有**一个长命的 `MemoryEngine` 实例:`boot/stores.ts` 装配出来的 `memoryEngine` 是
7
- * `{ backend, root }` 二元组,真正的引擎由 **core 的 Runner 每任务现构**
7
+ * 记忆作用域店(`memory-scope-stores.ts`:部署的店 + 引擎根 + 「一层住哪只店」的唯一读者),真正的引擎由 **core 的 Runner 每任务现构**
8
8
  * (`core/runner/prepare-memory.js`),而且构出来的 `memoryDir` 是**按任务的 scope 平面**决定的
9
9
  * (personal / project / dual-root 三形,还要看仓根、项目标记、pinned 目录)。
10
10
  * 也就是说「这个部署的那一个记忆引擎」这个东西**在本仓不存在** —— HTTP 面若要一个引擎,必须自己构。
11
11
  *
12
+ * ## 引擎建在哪只店上:包点名的层住的那只
13
+ * 导出按请求的 `scopes` 定店,导入按包自己的 `bundle.scopes` 定店(core 的整包判决保证包里每一条的层都在 `bundle.scopes` 里 —— 自洽是它的校验项);
14
+ * 几层分住两只店 ⇒ 拒(`request.memory_layer`):一只包是**一只店**单锁复合面里的一个 epoch,两只店封不出一只包。规则唯一属主
15
+ * `memory-scope-stores.ts` 的 {@link memoryStoreForRequest}。`bundle.scopes` 读不成「非空的非空串数组」的包,本来就过不了 core 的整包判决
16
+ * (结构项第一条),交部署的店那只引擎去判 —— 拒是包本身的函数,哪只引擎判都一样,什么都不落。
17
+ * 修前两面都在部署的店上建引擎:目录钉住的部署上,类型化个人层的条目在个人挂载上的另一只店里 —— 导出的包里没有会话写的条目,导入的落在会话不读的店。
18
+ *
12
19
  * ## 为什么自己构是安全的:这两个面是 **backend-scoped**,不碰 `memoryDir`
13
20
  *
14
21
  * 亲读 core 5.40.0 的 `memory-engine/engine.js`(不信 JSDoc,读实现):
@@ -41,7 +48,9 @@
41
48
  * `memory.export_incomplete` —— 那是诚实的运行期拒,附录 A 单列一条。绝不在这里回落到「用通用读面拼
42
49
  * 一个包」:core 明写那正是它拒绝生产的形(a governance-less export is the laundering shape)。
43
50
  */
44
- import { type MemoryBackend, type MemoryExportBundle, type MemoryImportReport, type SessionCaptureRecordStore } from "@sema-agent/core";
51
+ import { type MemoryExportBundle, type MemoryImportReport } from "@sema-agent/core";
52
+ import { type MemoryScopeStores } from "./memory-scope-stores.js";
53
+ import type { SessionCaptureRecordSource } from "./plugins/store-backend.js";
45
54
  /** 两口 HTTP 面消费的窄能力面(`ServiceDeps.memoryBundle{Export,Import}` 的实参来源)。 */
46
55
  export interface MemoryBundleFaces {
47
56
  exportScopes: (scopes: readonly string[]) => Promise<MemoryExportBundle>;
@@ -51,17 +60,15 @@ export interface MemoryBundleFaces {
51
60
  }) => Promise<MemoryImportReport>;
52
61
  }
53
62
  /**
54
- * 在**已装配的记忆后端**上建 bundle 两面。命名照 CLAUDE.md 工厂律:返回的是带行为的活对象 ⇒ `create*`。
63
+ * 在**记忆作用域店**上建 bundle 两面。命名照 CLAUDE.md 工厂律:返回的是带行为的活对象 ⇒ `create*`。
55
64
  *
56
- * `memoryDir` = 引擎的**挂载平面**(`memoryMountRootOf(backend, root)` 单铸点;全仓自构引擎同一条规则,
65
+ * 店:见文件头「引擎建在哪只店上」;一只店一只引擎。
66
+ * `memoryDir` = 那只店的**挂载平面**(`memoryMountRootOf(store, root)` 单铸点;全仓自构引擎同一条规则,
57
67
  * 由 `test/memory-layout-plane.test.ts` 的归一门咬住)。见文件头:这两条路径**不读它**(机器钉在
58
68
  * `test/memory-bundle-engine.test.ts`:给一个不存在的 `memoryDir` 也照样工作),传对的那一只是为了
59
69
  * 万一 core 日后真用上时,它拿到的是本部署真正的挂载平面,而不是高一层的配置根。
60
70
  */
61
- export declare function createMemoryBundleFaces(store: {
62
- backend: MemoryBackend;
63
- root: string;
64
- }, opts?: {
65
- captureRecordStore?: SessionCaptureRecordStore;
71
+ export declare function createMemoryBundleFaces(stores: MemoryScopeStores, opts?: {
72
+ captureRecords?: SessionCaptureRecordSource;
66
73
  }): MemoryBundleFaces | undefined;
67
74
  //# sourceMappingURL=memory-bundle-engine.d.ts.map
@@ -1,13 +1,36 @@
1
1
  import { MemoryEngine } from "@sema-agent/core";
2
2
  import { memoryMountRootOf } from "./memory-scope.js";
3
- export function createMemoryBundleFaces(store, opts) {
4
- const b = store.backend;
5
- if (typeof b.exportSnapshotOf !== "function" || typeof b.importBundleCommit !== "function")
3
+ import { memoryStoreForRequest } from "./memory-scope-stores.js";
4
+ import { captureRecordStoreOf } from "./memory-operator-faces.js";
5
+ export function createMemoryBundleFaces(stores, opts) {
6
+ if (!carriesBundleComposite(stores.backend))
6
7
  return undefined;
7
- const engine = new MemoryEngine({ backend: store.backend, memoryDir: memoryMountRootOf(store.backend, store.root), ...(opts?.captureRecordStore !== undefined ? { captureRecordStore: opts.captureRecordStore } : {}) });
8
+ const engines = new Map();
9
+ const engineOf = (store) => {
10
+ const known = engines.get(store);
11
+ if (known !== undefined)
12
+ return known;
13
+ if (!carriesBundleComposite(store))
14
+ throw new Error("the memory store that holds these layers implements no v2-c bundle composite (exportSnapshotOf / importBundleCommit) — a bundle is never assembled outside one");
15
+ const records = captureRecordStoreOf(opts?.captureRecords, store);
16
+ const engine = new MemoryEngine({ backend: store, memoryDir: memoryMountRootOf(store, stores.root), ...(records !== undefined ? { captureRecordStore: records } : {}) });
17
+ engines.set(store, engine);
18
+ return engine;
19
+ };
8
20
  return {
9
- exportScopes: (scopes) => engine.exportMemoryScopes(scopes),
10
- importBundle: (bundle, opts) => engine.importMemoryBundle(bundle, opts),
21
+ exportScopes: async (scopes) => engineOf(memoryStoreForRequest(stores, scopes)).exportMemoryScopes(scopes),
22
+ importBundle: async (bundle, opts) => {
23
+ const layers = bundleLayersOf(bundle);
24
+ return engineOf(layers.length > 0 ? memoryStoreForRequest(stores, layers) : stores.backend).importMemoryBundle(bundle, opts);
25
+ },
11
26
  };
12
27
  }
28
+ function carriesBundleComposite(store) {
29
+ const b = store;
30
+ return typeof b.exportSnapshotOf === "function" && typeof b.importBundleCommit === "function";
31
+ }
32
+ function bundleLayersOf(bundle) {
33
+ const scopes = typeof bundle === "object" && bundle !== null ? bundle.scopes : undefined;
34
+ return Array.isArray(scopes) && scopes.length > 0 && scopes.every((s) => typeof s === "string" && s.length > 0) ? scopes : [];
35
+ }
13
36
  //# sourceMappingURL=memory-bundle-engine.js.map