@sema-agent/server 7.138.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 (332) hide show
  1. package/MIGRATION.md +457 -7
  2. package/README.md +7 -4
  3. package/README.zh-CN.md +6 -4
  4. package/USAGE.md +91 -41
  5. package/deploy/sema-up/README.md +1 -1
  6. package/deploy/sema-up/lib/lanes.json +3 -2
  7. package/dist/adoption/runner.js +1 -1
  8. package/dist/adoption/sql.js +1 -1
  9. package/dist/adoption/wire.d.ts +3 -3
  10. package/dist/approval-card.d.ts +26 -26
  11. package/dist/bench/s1/arms.d.ts +1 -1
  12. package/dist/bench/s1/arms.js +1 -3
  13. package/dist/bench/s1/live-deps.js +3 -2
  14. package/dist/bench/s1/row.d.ts +5 -2
  15. package/dist/bench/s1/row.js +2 -22
  16. package/dist/bench/s1/run-firm.js +2 -2
  17. package/dist/boot/adoption.js +1 -1
  18. package/dist/boot/device-lane.d.ts +8 -3
  19. package/dist/boot/device-lane.js +7 -2
  20. package/dist/boot/execution-env.d.ts +4 -2
  21. package/dist/boot/execution-env.js +28 -34
  22. package/dist/boot/execution-lane.d.ts +9 -1
  23. package/dist/boot/execution-lane.js +6 -1
  24. package/dist/boot/governance-seams.d.ts +3 -2
  25. package/dist/boot/governance-seams.js +9 -11
  26. package/dist/boot/memory-boundary.d.ts +14 -51
  27. package/dist/boot/memory-boundary.js +10 -20
  28. package/dist/boot/memory-consolidation.d.ts +15 -11
  29. package/dist/boot/memory-consolidation.js +25 -14
  30. package/dist/boot/resolve-spec.d.ts +4 -6
  31. package/dist/boot/resolve-spec.js +10 -13
  32. package/dist/boot/retention-lane.d.ts +5 -5
  33. package/dist/boot/retention-lane.js +0 -6
  34. package/dist/boot/runner-deps.d.ts +6 -4
  35. package/dist/boot/runner-deps.js +3 -1
  36. package/dist/boot/session-faces.d.ts +0 -3
  37. package/dist/boot/session-faces.js +15 -8
  38. package/dist/boot/stage-02-web-admin-pull.js +2 -2
  39. package/dist/boot/stage-03-store-backend.d.ts +2 -6
  40. package/dist/boot/stage-03-store-backend.js +2 -3
  41. package/dist/boot/stage-04-stores.d.ts +2 -6
  42. package/dist/boot/stage-04-stores.js +5 -5
  43. package/dist/boot/stage-05-execution-env.d.ts +2 -6
  44. package/dist/boot/stage-05-execution-env.js +2 -2
  45. package/dist/boot/stage-06-runners.d.ts +2 -6
  46. package/dist/boot/stage-06-runners.js +2 -3
  47. package/dist/boot/stage-07-capability-layer.d.ts +2 -6
  48. package/dist/boot/stage-08-reapers.d.ts +2 -6
  49. package/dist/boot/stage-09-leader.d.ts +2 -6
  50. package/dist/boot/stage-09-leader.js +1 -2
  51. package/dist/boot/stage-10-http-server.d.ts +2 -6
  52. package/dist/boot/stage-10-http-server.js +7 -6
  53. package/dist/boot/stores.d.ts +3 -6
  54. package/dist/boot/stores.js +27 -40
  55. package/dist/boot/task-list-lane.d.ts +1 -1
  56. package/dist/boot/task-list-lane.js +1 -1
  57. package/dist/boot/web-admin.js +37 -11
  58. package/dist/capabilities/execution-lane.d.ts +2 -2
  59. package/dist/capabilities/mcp-probe.js +1 -1
  60. package/dist/capabilities/scenarios.d.ts +1 -1
  61. package/dist/capability-facts.d.ts +15 -7
  62. package/dist/capability-facts.js +8 -3
  63. package/dist/config-catalog.js +9 -8
  64. package/dist/config-invariants.d.ts +23 -3
  65. package/dist/config-invariants.js +42 -0
  66. package/dist/config-provider.d.ts +33 -37
  67. package/dist/config-provider.js +51 -30
  68. package/dist/config-types.d.ts +21 -7
  69. package/dist/config.d.ts +33 -0
  70. package/dist/config.js +46 -16
  71. package/dist/delegated-session-owner.d.ts +4 -3
  72. package/dist/delegated-session-owner.js +1 -1
  73. package/dist/deployment-shape.d.ts +10 -9
  74. package/dist/deployment-shape.js +4 -4
  75. package/dist/device-enrollment.d.ts +41 -2
  76. package/dist/device-enrollment.js +27 -12
  77. package/dist/device-store.d.ts +58 -85
  78. package/dist/device-store.js +19 -49
  79. package/dist/device-ws-hub.js +2 -1
  80. package/dist/env-name-allowlist-knobs.d.ts +5 -4
  81. package/dist/exec-cut.d.ts +60 -0
  82. package/dist/exec-cut.js +36 -0
  83. package/dist/execution-lane-caps.d.ts +115 -105
  84. package/dist/execution-lane-caps.js +76 -82
  85. package/dist/execution-placement.d.ts +259 -0
  86. package/dist/execution-placement.js +199 -0
  87. package/dist/field-conflict.d.ts +3 -2
  88. package/dist/field-conflict.js +1 -0
  89. package/dist/hosted-posture.d.ts +2 -2
  90. package/dist/http/admission.js +8 -19
  91. package/dist/http/checkpoint-ctx.d.ts +21 -12
  92. package/dist/http/checkpoint-ctx.js +4 -2
  93. package/dist/http/claimed-run.d.ts +1 -1
  94. package/dist/http/durable-run-leg.js +9 -5
  95. package/dist/http/execution-context.d.ts +218 -0
  96. package/dist/http/execution-context.js +330 -0
  97. package/dist/http/memory-compliance-failure-reply.d.ts +3 -1
  98. package/dist/http/memory-compliance-failure-reply.js +5 -0
  99. package/dist/http/memory-layer-reply.d.ts +30 -0
  100. package/dist/http/memory-layer-reply.js +24 -0
  101. package/dist/http/resume-legs.js +63 -36
  102. package/dist/http/retired-service-deps.d.ts +1 -1
  103. package/dist/http/retired-service-deps.js +1 -1
  104. package/dist/http/route-ctx.d.ts +14 -8
  105. package/dist/http/routes/adoption.js +1 -1
  106. package/dist/http/routes/background.d.ts +29 -1
  107. package/dist/http/routes/background.js +29 -2
  108. package/dist/http/routes/devices.d.ts +13 -19
  109. package/dist/http/routes/devices.js +21 -26
  110. package/dist/http/routes/memory-bundle.js +3 -0
  111. package/dist/http/routes/memory-compliance.js +8 -1
  112. package/dist/http/routes/memory-consolidation.js +12 -1
  113. package/dist/http/routes/memory-origin.js +14 -2
  114. package/dist/http/routes/memory-policy.js +5 -0
  115. package/dist/http/routes/session-sync.js +110 -15
  116. package/dist/http/routes/sessions.d.ts +6 -0
  117. package/dist/http/routes/sessions.js +143 -22
  118. package/dist/http/routes/side-query.d.ts +12 -4
  119. package/dist/http/routes/side-query.js +4 -5
  120. package/dist/http/routes/tasks.js +41 -33
  121. package/dist/http/server.d.ts +40 -44
  122. package/dist/http/server.js +13 -2
  123. package/dist/http/session-inherit-env.d.ts +3 -4
  124. package/dist/http/session-inherit-env.js +1 -1
  125. package/dist/http/wire-types.d.ts +8 -12
  126. package/dist/identity-source.d.ts +1 -1
  127. package/dist/identity-source.js +1 -1
  128. package/dist/index.d.ts +1 -0
  129. package/dist/lane-home-probe.d.ts +68 -42
  130. package/dist/lane-home-probe.js +53 -30
  131. package/dist/leader/wire.js +5 -4
  132. package/dist/memory-bundle-engine.d.ts +16 -9
  133. package/dist/memory-bundle-engine.js +29 -6
  134. package/dist/memory-operator-faces.d.ts +85 -30
  135. package/dist/memory-operator-faces.js +136 -30
  136. package/dist/memory-project-layer.d.ts +3 -21
  137. package/dist/memory-project-layer.js +11 -8
  138. package/dist/memory-scope-stores.d.ts +73 -0
  139. package/dist/memory-scope-stores.js +86 -0
  140. package/dist/memory-scope.d.ts +29 -5
  141. package/dist/memory-scope.js +16 -4
  142. package/dist/memory-sync-client.d.ts +70 -18
  143. package/dist/memory-sync-client.js +215 -117
  144. package/dist/memory-sync.d.ts +1 -1
  145. package/dist/memory-sync.js +3 -2
  146. package/dist/observability/cost-taxonomy.d.ts +2 -2
  147. package/dist/observability/fail-open.d.ts +12 -0
  148. package/dist/observability/fail-open.js +12 -0
  149. package/dist/observability/run-terminal.js +0 -1
  150. package/dist/orchestration/workflow-notify-journal.js +4 -4
  151. package/dist/org-memory-admission.d.ts +4 -3
  152. package/dist/org-memory-admission.js +6 -6
  153. package/dist/parked-decide.d.ts +34 -9
  154. package/dist/parked-decide.js +12 -19
  155. package/dist/parked-revive-surface.d.ts +12 -15
  156. package/dist/parked-revive-surface.js +3 -6
  157. package/dist/peer-seat.d.ts +13 -7
  158. package/dist/peer-seat.js +37 -3
  159. package/dist/plugins/adoption-log-sql.js +4 -4
  160. package/dist/plugins/approval-ask-store-file.d.ts +7 -0
  161. package/dist/plugins/approval-ask-store-file.js +11 -0
  162. package/dist/plugins/approval-ask-store-memory.d.ts +6 -0
  163. package/dist/plugins/approval-ask-store-memory.js +12 -0
  164. package/dist/plugins/approval-ask-store-sql.d.ts +22 -5
  165. package/dist/plugins/approval-ask-store-sql.js +44 -26
  166. package/dist/plugins/approval-nonce-store.js +4 -4
  167. package/dist/plugins/blob-backend.d.ts +4 -4
  168. package/dist/plugins/blob-backend.js +7 -7
  169. package/dist/plugins/breaker-state-sql.js +2 -2
  170. package/dist/plugins/caching-session-store.d.ts +6 -2
  171. package/dist/plugins/caching-session-store.js +9 -3
  172. package/dist/plugins/checkpoint-index-columns.js +2 -2
  173. package/dist/plugins/checkpoint-store-sql.d.ts +6 -5
  174. package/dist/plugins/checkpoint-store-sql.js +21 -23
  175. package/dist/plugins/device-store-sql.d.ts +25 -51
  176. package/dist/plugins/device-store-sql.js +68 -122
  177. package/dist/plugins/ensure-index.d.ts +1 -2
  178. package/dist/plugins/execution-placement-sql.d.ts +151 -0
  179. package/dist/plugins/execution-placement-sql.js +223 -0
  180. package/dist/plugins/file-history-store-sql.d.ts +9 -8
  181. package/dist/plugins/file-history-store-sql.js +9 -9
  182. package/dist/plugins/file-run-store.d.ts +6 -1
  183. package/dist/plugins/file-run-store.js +4 -0
  184. package/dist/plugins/fork-routing-session-store.d.ts +6 -0
  185. package/dist/plugins/fork-routing-session-store.js +16 -0
  186. package/dist/plugins/image-bake-store-sql.js +9 -9
  187. package/dist/plugins/image-index-sql.js +11 -11
  188. package/dist/plugins/leader-run-store-sql.js +4 -4
  189. package/dist/plugins/local-session-store.d.ts +149 -50
  190. package/dist/plugins/local-session-store.js +382 -107
  191. package/dist/plugins/mailbox-store-sql.d.ts +2 -1
  192. package/dist/plugins/mailbox-store-sql.js +4 -4
  193. package/dist/plugins/memory-engine-tidb.js +5 -5
  194. package/dist/plugins/memory-key-guards.d.ts +4 -0
  195. package/dist/plugins/memory-key-guards.js +1 -0
  196. package/dist/plugins/memory-optout-grant-store-sql.js +1 -1
  197. package/dist/plugins/memory-run-store.d.ts +1 -1
  198. package/dist/plugins/memory-sync-store-tidb.js +3 -3
  199. package/dist/plugins/one-time-migrations.d.ts +117 -8
  200. package/dist/plugins/one-time-migrations.js +408 -38
  201. package/dist/plugins/org-delivery-quota-store.js +2 -2
  202. package/dist/plugins/outcome-ledger-sql.d.ts +2 -2
  203. package/dist/plugins/outcome-ledger-sql.js +2 -2
  204. package/dist/plugins/permission-rule-store-sql.d.ts +17 -19
  205. package/dist/plugins/permission-rule-store-sql.js +29 -32
  206. package/dist/plugins/pg-pool.d.ts +7 -3
  207. package/dist/plugins/pg-session-storage.d.ts +31 -20
  208. package/dist/plugins/pg-session-storage.js +120 -52
  209. package/dist/plugins/remote-env-adb.d.ts +18 -19
  210. package/dist/plugins/remote-env-adb.js +91 -66
  211. package/dist/plugins/remote-env-device.d.ts +23 -31
  212. package/dist/plugins/remote-env-device.js +19 -17
  213. package/dist/plugins/remote-env-e2b.d.ts +27 -21
  214. package/dist/plugins/remote-env-e2b.js +91 -45
  215. package/dist/plugins/remote-env-file-error.d.ts +3 -1
  216. package/dist/plugins/remote-env-file-error.js +9 -3
  217. package/dist/plugins/remote-env-host.d.ts +31 -34
  218. package/dist/plugins/remote-env-host.js +91 -72
  219. package/dist/plugins/remote-env-k8s.d.ts +13 -29
  220. package/dist/plugins/remote-env-k8s.js +63 -55
  221. package/dist/plugins/remote-env-local-docker.d.ts +24 -12
  222. package/dist/plugins/remote-env-local-docker.js +49 -61
  223. package/dist/plugins/remote-env-ssh.d.ts +11 -19
  224. package/dist/plugins/remote-env-ssh.js +74 -57
  225. package/dist/plugins/remote-shell.d.ts +100 -3
  226. package/dist/plugins/remote-shell.js +166 -2
  227. package/dist/plugins/resume-anchor-store-sql.js +2 -2
  228. package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
  229. package/dist/plugins/retention-lane-store-sql.js +2 -2
  230. package/dist/plugins/retention-store-sql.d.ts +10 -7
  231. package/dist/plugins/retention-store-sql.js +13 -7
  232. package/dist/plugins/run-store-sql.d.ts +13 -3
  233. package/dist/plugins/run-store-sql.js +20 -15
  234. package/dist/plugins/schema-consistency.d.ts +21 -11
  235. package/dist/plugins/schema-consistency.js +15 -9
  236. package/dist/plugins/schema-drift-sentence.d.ts +27 -0
  237. package/dist/plugins/schema-drift-sentence.js +38 -0
  238. package/dist/plugins/schema-ensure-legs.d.ts +2 -3
  239. package/dist/plugins/schema-ensure-legs.js +2 -2
  240. package/dist/plugins/schema-live-columns.d.ts +1 -1
  241. package/dist/plugins/session-capture-record-store-sql.js +1 -1
  242. package/dist/plugins/session-fork.d.ts +54 -0
  243. package/dist/plugins/session-fork.js +38 -1
  244. package/dist/plugins/session-row-sql.d.ts +22 -0
  245. package/dist/plugins/session-row-sql.js +81 -0
  246. package/dist/plugins/session-rules-column.d.ts +1 -1
  247. package/dist/plugins/session-rules-column.js +1 -1
  248. package/dist/plugins/session-store.d.ts +1 -1
  249. package/dist/plugins/session-workspace-cell.d.ts +1 -1
  250. package/dist/plugins/session-workspace-cell.js +1 -1
  251. package/dist/plugins/shared-memory-store-sql.js +2 -2
  252. package/dist/plugins/sql-driver.d.ts +10 -5
  253. package/dist/plugins/sql-driver.js +6 -6
  254. package/dist/plugins/sql-errors.js +1 -1
  255. package/dist/plugins/store-backend.d.ts +5 -7
  256. package/dist/plugins/store-backend.js +23 -11
  257. package/dist/plugins/store-contracts.d.ts +25 -5
  258. package/dist/plugins/task-list-store-sql.js +11 -11
  259. package/dist/plugins/tidb-pool.d.ts +12 -7
  260. package/dist/plugins/tidb-pool.js +13 -7
  261. package/dist/plugins/tidb-session-storage.js +4 -4
  262. package/dist/plugins/tidb-session-store.d.ts +57 -26
  263. package/dist/plugins/tidb-session-store.js +127 -59
  264. package/dist/plugins/tool-result-store-sql.d.ts +5 -4
  265. package/dist/plugins/tool-result-store-sql.js +21 -13
  266. package/dist/plugins/user-input-ledger-sql.js +2 -2
  267. package/dist/plugins/workflow-journal-store-sql.js +5 -5
  268. package/dist/plugins/workflow-run-store-sql.js +19 -19
  269. package/dist/plugins/write-behind-counter.d.ts +2 -3
  270. package/dist/plugins/write-behind-counter.js +5 -5
  271. package/dist/project-memory.d.ts +9 -15
  272. package/dist/project-memory.js +5 -4
  273. package/dist/request-key-closure.js +1 -1
  274. package/dist/request-value-closure.d.ts +6 -7
  275. package/dist/request-value-closure.js +1 -3
  276. package/dist/resource-suspend.d.ts +14 -12
  277. package/dist/resource-suspend.js +1 -1
  278. package/dist/resource-window.d.ts +4 -3
  279. package/dist/run-local.d.ts +6 -0
  280. package/dist/run-local.js +34 -35
  281. package/dist/runs.d.ts +10 -5
  282. package/dist/runs.js +52 -66
  283. package/dist/security.d.ts +38 -12
  284. package/dist/security.js +8 -2
  285. package/dist/server-secret-env.d.ts +9 -5
  286. package/dist/session-children-retire.d.ts +27 -9
  287. package/dist/session-children-retire.js +9 -5
  288. package/dist/session-incarnation.d.ts +20 -10
  289. package/dist/session-incarnation.js +5 -3
  290. package/dist/session-policy-wire.d.ts +1 -1
  291. package/dist/session-row.d.ts +114 -5
  292. package/dist/session-row.js +55 -5
  293. package/dist/session-titler.d.ts +2 -2
  294. package/dist/sql-engine-posture.d.ts +1 -1
  295. package/dist/sql-engine-posture.js +1 -1
  296. package/dist/{plugins → stores-sql}/background-agent-store-sql.d.ts +2 -2
  297. package/dist/{plugins → stores-sql}/background-agent-store-sql.js +8 -8
  298. package/dist/{plugins → stores-sql}/session-policy-store-sql.d.ts +7 -5
  299. package/dist/{plugins → stores-sql}/session-policy-store-sql.js +12 -12
  300. package/dist/{plugins → stores-sql}/usage-window-store-sql.d.ts +1 -1
  301. package/dist/{plugins → stores-sql}/usage-window-store-sql.js +3 -3
  302. package/dist/task-a2a.d.ts +1 -1
  303. package/dist/task-a2a.js +5 -6
  304. package/dist/task-cwd.d.ts +6 -1
  305. package/dist/task-mcp.d.ts +22 -9
  306. package/dist/task-mcp.js +17 -9
  307. package/dist/terminal.d.ts +27 -0
  308. package/dist/terminal.js +6 -0
  309. package/dist/tool-approval.d.ts +6 -0
  310. package/dist/tool-approval.js +8 -1
  311. package/dist/trace/project.d.ts +1 -0
  312. package/dist/trace/project.js +1 -0
  313. package/dist/trace/redact.d.ts +3 -1
  314. package/dist/trace/redact.js +80 -28
  315. package/dist/trace/self-minted-wire.d.ts +169 -2
  316. package/dist/trace/self-minted-wire.js +54 -1
  317. package/dist/url-refusal.d.ts +1 -1
  318. package/dist/web-admin-client/apply-effective.d.ts +17 -3
  319. package/dist/web-admin-client/apply-effective.js +20 -10
  320. package/dist/web-admin-client/candidate-gate.d.ts +11 -7
  321. package/dist/web-admin-client/candidate-gate.js +1 -1
  322. package/dist/web-admin-client/http-client.d.ts +5 -4
  323. package/dist/web-admin-client/http-client.js +2 -2
  324. package/dist/web-admin-client/read-warnings.d.ts +7 -17
  325. package/dist/web-admin-client/read-warnings.js +5 -9
  326. package/dist/web-admin-client/skills-mcp.js +3 -2
  327. package/dist/web-admin-client/types.d.ts +6 -0
  328. package/package.json +3 -3
  329. package/wire-changes/server@7.139.0.json +348 -0
  330. package/wire-changes/server@7.140.0.json +184 -0
  331. package/dist/http/device-placement.d.ts +0 -175
  332. package/dist/http/device-placement.js +0 -145
@@ -1,8 +1,59 @@
1
1
  import { MemoryEngine, } from "@sema-agent/core";
2
2
  import { memoryMountRootOf } from "./memory-scope.js";
3
+ import { memoryStoreForRequest, memoryStoresOfDeployment } from "./memory-scope-stores.js";
3
4
  export function backendOwnsControlPlane(backend) {
4
- const b = backend;
5
- return typeof b?.controlPlaneRoot === "string" && b.controlPlaneRoot !== "";
5
+ return controlPlaneRootOf(backend) !== undefined;
6
+ }
7
+ function controlPlaneRootOf(backend) {
8
+ const root = backend?.controlPlaneRoot;
9
+ return typeof root === "string" && root !== "" ? root : undefined;
10
+ }
11
+ export function captureRecordStoreOf(source, store) {
12
+ if (source === undefined)
13
+ return undefined;
14
+ const root = controlPlaneRootOf(store);
15
+ return source(root !== undefined ? { controlDir: root } : undefined);
16
+ }
17
+ const seatLayers = (at) => (at !== undefined ? [at.layer] : []);
18
+ function createEngineSeat(build) {
19
+ const engines = new Map();
20
+ return (store) => {
21
+ const known = engines.get(store);
22
+ if (known !== undefined)
23
+ return known;
24
+ if (!backendOwnsControlPlane(store))
25
+ throw new Error("the memory store that holds this layer owns no engine control plane (controlPlaneRoot) — the operator faces never answer over a store without one");
26
+ const engine = build(store);
27
+ engines.set(store, engine);
28
+ return engine;
29
+ };
30
+ }
31
+ function erasureLayersOf(input) {
32
+ if (typeof input !== "object" || input === null)
33
+ return [];
34
+ const { select, expectedScopes } = input;
35
+ const scope = typeof select === "object" && select !== null ? select.scope : undefined;
36
+ if (typeof scope === "string" && scope.length > 0)
37
+ return [scope];
38
+ if (Array.isArray(expectedScopes) && expectedScopes.length > 0 && expectedScopes.every((s) => typeof s === "string" && s.length > 0))
39
+ return expectedScopes;
40
+ return [];
41
+ }
42
+ function erasureSessionOf(input) {
43
+ if (typeof input !== "object" || input === null)
44
+ return undefined;
45
+ const { select } = input;
46
+ const sessionId = typeof select === "object" && select !== null ? select.sessionId : undefined;
47
+ return typeof sessionId === "string" && sessionId.length > 0 ? sessionId : undefined;
48
+ }
49
+ export class MemoryErasureStoreUnjudged extends Error {
50
+ code = "memory.erasure_store_unjudged";
51
+ constructor() {
52
+ super("memory erasure refused: this erasure reaches a memory store other than the deployment's store (this deployment keeps the typed personal memory layers in a second store), " +
53
+ "and this build judges an erasure requestId on the deployment's store only, so it cannot tell whether the same requestId already erased under another selector there — " +
54
+ "erasures that reach the second store are not taken in this build, and nothing was erased; the way out is the engine's deployment-wide erasure request identity, due with the next engine update");
55
+ this.name = "MemoryErasureStoreUnjudged";
56
+ }
6
57
  }
7
58
  export function erasureInputSmugglesPrototypeKey(input) {
8
59
  const stack = [input];
@@ -24,50 +75,105 @@ export function erasureInputSmugglesPrototypeKey(input) {
24
75
  }
25
76
  return false;
26
77
  }
27
- export function createMemoryComplianceFaces(store, opts) {
28
- if (!backendOwnsControlPlane(store.backend))
78
+ export function createMemoryComplianceFaces(stores, opts) {
79
+ if (!backendOwnsControlPlane(stores.backend))
29
80
  return undefined;
30
- const engine = new MemoryEngine({
31
- backend: store.backend,
32
- memoryDir: memoryMountRootOf(store.backend, store.root),
33
- ...(opts?.onIncident !== undefined ? { onIncident: opts.onIncident } : {}),
34
- ...(opts?.captureRecordStore !== undefined ? { captureRecordStore: opts.captureRecordStore } : {}),
81
+ const engineOf = createEngineSeat((store) => {
82
+ const records = captureRecordStoreOf(opts?.captureRecords, store);
83
+ return new MemoryEngine({
84
+ backend: store,
85
+ memoryDir: memoryMountRootOf(store, stores.root),
86
+ ...(opts?.onIncident !== undefined ? { onIncident: opts.onIncident } : {}),
87
+ ...(records !== undefined ? { captureRecordStore: records } : {}),
88
+ });
35
89
  });
90
+ const erasureStoreOf = async (input, at) => {
91
+ const seat = at !== undefined ? "`scope`" : "`select.scope`, or `expectedScopes` next to `select.ids` / `select.sessionId`";
92
+ const layers = at !== undefined ? seatLayers(at) : erasureLayersOf(input);
93
+ const sessionId = layers.length === 0 ? erasureSessionOf(input) : undefined;
94
+ if (sessionId === undefined) {
95
+ const store = memoryStoreForRequest(stores, layers, seat);
96
+ if (store !== stores.backend)
97
+ throw new MemoryErasureStoreUnjudged();
98
+ return store;
99
+ }
100
+ for (const other of memoryStoresOfDeployment(stores, seat)) {
101
+ if (other === stores.backend)
102
+ continue;
103
+ if ((await engineOf(other).sessionMemoryStatus(sessionId)).committedCount !== 0)
104
+ throw new MemoryErasureStoreUnjudged();
105
+ }
106
+ return stores.backend;
107
+ };
36
108
  return {
37
- provenanceOf: (entryId) => engine.provenanceOf(entryId),
38
- erase: (input) => {
109
+ provenanceOf: async (entryId, at) => engineOf(memoryStoreForRequest(stores, seatLayers(at))).provenanceOf(entryId),
110
+ erase: async (input, at) => {
39
111
  if (erasureInputSmugglesPrototypeKey(input)) {
40
112
  const e = new Error("memory erasure refused: the request carries a key that rewrites an object's prototype — such a key is not a selector, and core's selector dispatch would read it in preference to the declared one");
41
113
  e.code = "memory.erasure_selector_unsafe";
42
- return Promise.reject(e);
114
+ throw e;
43
115
  }
44
- return engine.eraseMemoryEntries(input);
116
+ const store = await erasureStoreOf(input, at);
117
+ return engineOf(store).eraseMemoryEntries(input);
45
118
  },
46
119
  };
47
120
  }
48
- export function createMemoryOriginFaces(store, opts) {
49
- if (!backendOwnsControlPlane(store.backend))
121
+ export function createMemoryOriginFaces(stores, opts) {
122
+ if (!backendOwnsControlPlane(stores.backend))
50
123
  return undefined;
51
- const engine = new MemoryEngine({
52
- backend: store.backend,
53
- memoryDir: memoryMountRootOf(store.backend, store.root),
54
- ...(opts?.onIncident !== undefined ? { onIncident: opts.onIncident } : {}),
55
- ...(opts?.captureRecordStore !== undefined ? { captureRecordStore: opts.captureRecordStore } : {}),
124
+ const engineOf = createEngineSeat((store) => {
125
+ const records = captureRecordStoreOf(opts?.captureRecords, store);
126
+ return new MemoryEngine({
127
+ backend: store,
128
+ memoryDir: memoryMountRootOf(store, stores.root),
129
+ ...(opts?.onIncident !== undefined ? { onIncident: opts.onIncident } : {}),
130
+ ...(records !== undefined ? { captureRecordStore: records } : {}),
131
+ });
56
132
  });
57
133
  return {
58
- listExternal: (scopes) => engine.listExternalOriginEntries(scopes),
59
- listClearances: () => engine.listOriginClearances(),
60
- clear: (entryId, input) => engine.clearEntryOrigin(entryId, input),
134
+ listExternal: async (scopes) => engineOf(memoryStoreForRequest(stores, scopes)).listExternalOriginEntries(scopes),
135
+ listClearances: (at) => engineOf(memoryStoreForRequest(stores, seatLayers(at))).listOriginClearances(),
136
+ clear: async (entryId, input, at) => engineOf(memoryStoreForRequest(stores, seatLayers(at))).clearEntryOrigin(entryId, input),
61
137
  };
62
138
  }
63
- export function createSessionMemoryStatusFace(store, opts) {
64
- if (!backendOwnsControlPlane(store.backend))
139
+ export function foldPlaneStatuses(statuses) {
140
+ const sum = (key) => statuses.every((s) => s[key] !== undefined) ? statuses.reduce((n, s) => n + s[key], 0) : undefined;
141
+ const committedCount = sum("committedCount");
142
+ const foldedCount = sum("foldedCount");
143
+ const captures = statuses.flatMap((s) => (s.lastCaptureAt !== undefined ? [s.lastCaptureAt] : []));
144
+ const lastCaptureAt = committedCount !== undefined && captures.length > 0 ? Math.max(...captures) : undefined;
145
+ const recorded = statuses.find((s) => s.captureOptedOut === true);
146
+ const capture = recorded !== undefined
147
+ ? { captureOptedOut: true, ...(recorded.optOutSource !== undefined ? { optOutSource: recorded.optOutSource } : {}) }
148
+ : statuses.every((s) => s.captureOptedOut === false)
149
+ ? { captureOptedOut: false }
150
+ : statuses.some((s) => s.optOutSource === "fault")
151
+ ? { optOutSource: "fault" }
152
+ : {};
153
+ return {
154
+ ...capture,
155
+ ...(committedCount !== undefined ? { committedCount } : {}),
156
+ ...(foldedCount !== undefined ? { foldedCount } : {}),
157
+ ...(lastCaptureAt !== undefined ? { lastCaptureAt } : {}),
158
+ };
159
+ }
160
+ export function createSessionMemoryStatusFace(stores, opts) {
161
+ if (!backendOwnsControlPlane(stores.backend))
65
162
  return undefined;
66
- const engine = new MemoryEngine({
67
- backend: store.backend,
68
- memoryDir: memoryMountRootOf(store.backend, store.root),
69
- ...(opts?.captureRecordStore !== undefined ? { captureRecordStore: opts.captureRecordStore } : {}),
163
+ const engineOf = createEngineSeat((store) => {
164
+ const records = captureRecordStoreOf(opts?.captureRecords, store);
165
+ return new MemoryEngine({
166
+ backend: store,
167
+ memoryDir: memoryMountRootOf(store, stores.root),
168
+ ...(records !== undefined ? { captureRecordStore: records } : {}),
169
+ });
70
170
  });
71
- return { status: (sessionId) => engine.sessionMemoryStatus(sessionId) };
171
+ const storeOf = (store) => {
172
+ const engine = engineOf(store);
173
+ return { controlPlane: engine.controlPlaneRoot, status: (sessionId) => engine.sessionMemoryStatus(sessionId) };
174
+ };
175
+ return {
176
+ storesAt: (at) => (at !== undefined ? [storeOf(memoryStoreForRequest(stores, seatLayers(at)))] : memoryStoresOfDeployment(stores).map(storeOf)),
177
+ };
72
178
  }
73
179
  //# sourceMappingURL=memory-operator-faces.js.map
@@ -1,23 +1,5 @@
1
- /**
2
- * [ref]([ref] 片二)—— 一个任务的**项目层准备一步**:求键 → 把同一 checkout 的旧层折进当前层 → 交给同步腿跟踪。
3
- * HTTP 腿(`boot/resolve-spec.ts`)与 run-local 腿共用这一只;键的规则只在 `memory-scope.ts` `memoryProjectLayerFor`(本模块不判让位、不铸键)。
4
- *
5
- * ## 折叠(`foldFrom`,由 `project-identity.ts` `projectLayerForTaskRoot` 给出,按序)
6
- * · 退役 `repo:<sha256(根)[:24]>` 层 —— **一次性迁移**(7.98.0–7.132.x 的项目键;窗、删法见 `plugins/one-time-migrations.ts` 登记表 M25);
7
- * · 当前档为 `r`(origin 远端)时本 checkout 的 `p` 档 —— **常设律**(先 `git init` 后加远端的项目,加远端那一刻不丢项目记忆)。
8
- * 折 = core `migrateScope`(id 保留、rev 按新 scope 重算、逐条 CAS;冲突留原地,下一个任务再折)。**不记「已折」**:每个任务先读一眼旧层
9
- * (`listHeaders`,空就不动),旧层之后又来了条目(仍在跑的旧任务 harvest、同步把别处的改动拉回旧层)下一个任务照折。
10
- * 🔴 **与同步轮串行**:旧层若是被同步的层(`p` 档),在飞的那一轮的应答(拉回的改动 / 删除)按 id 落盘 —— 折在它前面,应答会把刚折走的条目改回旧层
11
- * 或在新层上删掉它。所以有东西要折时,折叠排进同步腿的串行链(`MemorySyncRunner.exclusive`):等在飞的那一轮落定再折,折的时候没有轮在飞。
12
- * 折在 spec 返回之前完成(`await`)⇒ 这一任务挂载时就看得见折进来的条目(代价如实:有东西要折又恰有一轮在飞时,任务起步等那一轮)。
13
- * 折叠失败不挡任务(响亮 warn,条目原地不动、下次再折):项目层记忆暂时少了旧层那几条,比任务起不来更接近用户要的东西。
14
- *
15
- * ## 跟踪
16
- * 当前层在复制覆盖面里(否则规则已让位、根本走不到这里)且有同步腿 ⇒ `track(scope)`:本地还没有条目也每轮拉它 —— 第二台设备第一次进这个项目
17
- * 就拉得到第一台写的(拉回来可能晚于本任务挂载:第一个任务看不见,下一个任务看得见,如实)。
18
- */
19
- import { type MemoryBackend } from "@sema-agent/core";
20
1
  import type { ServiceConfig } from "./config-types.js";
2
+ import type { MemoryScopeStores } from "./memory-scope-stores.js";
21
3
  import type { MemorySyncRunner } from "./memory-sync-client.js";
22
4
  import type { MemoryProjectKey } from "./project-identity.js";
23
5
  export interface MemoryProjectLayers {
@@ -25,8 +7,8 @@ export interface MemoryProjectLayers {
25
7
  prepare(config: Pick<ServiceConfig, "requirePrincipal" | "memorySync">, scope: string | undefined, taskRoot: string | undefined): Promise<MemoryProjectKey | undefined>;
26
8
  }
27
9
  export declare function createMemoryProjectLayers(deps: {
28
- /** 本部署的记忆引擎 backend(File 或 SQL 孪生);缺席 ⇒ 没有可折的盘(记忆暗时调用方根本不会问)。 */
29
- backend: MemoryBackend | undefined;
10
+ /** 本部署的记忆作用域店(= 入口装配出的记忆引擎对象);缺席 ⇒ 没有可折的盘(记忆暗时调用方根本不会问)。 */
11
+ stores: MemoryScopeStores | undefined;
30
12
  /** 同步腿(开同步时在场):跟踪当前层;有东西要折时折叠排进它的串行链。 */
31
13
  syncRunner: Pick<MemorySyncRunner, "track" | "exclusive"> | undefined;
32
14
  log: {
@@ -1,10 +1,13 @@
1
1
  import { migrateScope } from "@sema-agent/core";
2
2
  import { memoryProjectLayerFor } from "./memory-scope.js";
3
3
  export function createMemoryProjectLayers(deps) {
4
- const fold = async (backend, from, to) => {
4
+ const fold = async (stores, from, to) => {
5
5
  let report;
6
6
  try {
7
- report = await migrateScope(backend, from, to);
7
+ const store = stores.storeOf(to);
8
+ if (stores.storeOf(from) !== store)
9
+ throw new Error(`the layers ${JSON.stringify(from)} and ${JSON.stringify(to)} live in two different memory stores — a fold moves entries inside one store`);
10
+ report = await migrateScope(store, from, to);
8
11
  }
9
12
  catch (err) {
10
13
  deps.log.warn("memory_project_layer_fold_failed", { from, to, err: String(err), note: "entries stay where they are; the next task in this project retries" });
@@ -16,10 +19,10 @@ export function createMemoryProjectLayers(deps) {
16
19
  deps.log.warn("memory_project_layer_fold_conflicts", { from, to, conflicts: report.conflicts.length, note: "conflicting entries stay in the old layer; the next task in this project retries" });
17
20
  }
18
21
  };
19
- const occupied = async (backend, sources) => {
22
+ const occupied = async (stores, sources) => {
20
23
  const out = [];
21
24
  for (const from of sources) {
22
- if ((await backend.listHeaders([from])).some((h) => h.scope === from))
25
+ if ((await stores.storeOf(from).listHeaders([from])).some((h) => h.scope === from))
23
26
  out.push(from);
24
27
  }
25
28
  return out;
@@ -30,11 +33,11 @@ export function createMemoryProjectLayers(deps) {
30
33
  const current = layer?.key.scope;
31
34
  if (layer === undefined || current === undefined)
32
35
  return layer?.key;
33
- const backend = deps.backend;
34
- if (backend !== undefined && (await occupied(backend, layer.foldFrom)).length > 0) {
36
+ const stores = deps.stores;
37
+ if (stores !== undefined && (await occupied(stores, layer.foldFrom)).length > 0) {
35
38
  const foldAll = async () => {
36
- for (const from of await occupied(backend, layer.foldFrom))
37
- await fold(backend, from, current);
39
+ for (const from of await occupied(stores, layer.foldFrom))
40
+ await fold(stores, from, current);
38
41
  };
39
42
  await (deps.syncRunner !== undefined ? deps.syncRunner.exclusive(foldAll) : foldAll());
40
43
  }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * 记忆作用域店 —— 「一层住在哪只店」在本宿主的**唯一读者**。
3
+ *
4
+ * ## 规则(一条)
5
+ * 一层(scope)的条目住哪只店,只有引擎的 `resolveMemoryScopeStore` 答;本服务在会话之外读写某一层的每一条腿(同步执行器、项目层折叠、
6
+ * 中心侧导出 / 同步、bundle 导出导入、合规抹除 / 出处、外源标记、会话记忆状态、整理)一律问**本对象**,不再自持「部署的店」当某一层的答案。
7
+ * 本对象就是起服装配出来的那只记忆引擎对象(`boot/stores.ts` 的 `memoryEngine`、`run-local.ts` 的同名量):它的 `backend` / `root`
8
+ * 正是交给 Runner 的两件事实(`RunnerDeps.memoryBackend` / `RunnerDeps.memoryEngineDir`),会话装配解析一层的店读的也是这两件 ——
9
+ * 所以宿主腿与会话对同一层答同一只店。每进程一只,所有腿共用(引擎的话:每层解析一次、留着用)。
10
+ *
11
+ * ## 喂给引擎的契约
12
+ * `scopeContract` = 本服务铸 spec 时给会话盖的同一只判据 {@link memoryScopeContractOf}(按层问与按会话问答同一只店,理由见该函数注)。
13
+ *
14
+ * ## 先判平面,再建店;一只平面一只实例
15
+ * 目录钉住的部署上,引擎对个人平面的答案是在个人挂载上**新开**的一只 File 店(契约原话:一只挂载;打开 = 建目录、收尾中断的事务、读台账)。
16
+ * 层键是调用方给的串,所以本对象**先**问平面、**再**按平面取店:
17
+ * · 平面 = 引擎同一只读法 `resolveMemoryScopeStore` 在一只**不钉目录**的探针店上的答案。引擎契约:不钉目录的店对个人平面原样答回
18
+ * 入参店(「the personal plane shares a backend without a directory」)、项目平面恒答部署的店 ⇒ 这一问只得平面、零建店零读盘,
19
+ * 层键读不出照样抛引擎的 `config.memory_scope_key`(同一只校验)。不在本层另写分类(另写就是第二个读者)。
20
+ * · 店 = 每个平面第一次用到时问引擎一次(真店入参),留下这一只;同平面的后来层复用它 —— 每个本对象至多两只店(项目 / 个人),
21
+ * 「两层同店」按实例判(下面的路由读它)。不按层键缓存:任意多把新层键不建店、不读盘、本对象不长。
22
+ * 🚧 平面的读法待引擎导出纯分类函数(`classifyScopePlanes` / `scopePlanesOf`)后改读它、删探针店;钉在 `test/memory-layer-seat-http.test.ts`。
23
+ *
24
+ * ## 请求的店({@link memoryStoreForRequest})
25
+ * 动词按它的请求**点名的层**取店;点名的几层不在同一只店 ⇒ 响亮拒(一次请求只落一只店)。请求不点名层的动词(条目 id、店级账本)
26
+ * 答在**本部署点名的层与部署的店共处的那一只店**上(`memoryLayersNamedBy`:全局层 / 同步层 / 登记簿种子 / 整理层);它们分住两只店时
27
+ * 不猜,响亮拒并指路「在请求里点名层」。单店部署(缺省 `local`、SQL 记忆后端、配置不点名个人平面键)上无层请求的答法与上一版逐字同。
28
+ *
29
+ * ## 本部署的店({@link memoryStoresOfDeployment})
30
+ * 部署的店 + 本部署点名的每一层住的店,去重、部署的店在前 —— 至多两只。会话 id 的动词读它:一只会话的记忆事实住在它各条腿写进的那只店
31
+ * (写家所在的平面),而单用户部署上会话的写家只会是项目层(部署的店)或全局层(点名的层),所以这张表就是「这只会话可能住的店」的全集。
32
+ */
33
+ import { type MemoryBackend } from "@sema-agent/core";
34
+ export interface MemoryScopeStores {
35
+ /** 部署的记忆后端 —— 交给 Runner 的那一只(`RunnerDeps.memoryBackend`)。它是「层在哪只店」那只读法的输入、项目平面的店本身,
36
+ * 不是任何一层的答案(层的答案只出自 {@link MemoryScopeStores.storeOf})。 */
37
+ readonly backend: MemoryBackend;
38
+ /** 引擎根 —— 交给 Runner 的那一个值(`RunnerDeps.memoryEngineDir`):读法的另一件输入(个人挂载在它下面),也是同步游标的根。 */
39
+ readonly root: string;
40
+ /** 层 `layer` 住的那只店(引擎的唯一读法;先判平面、每个平面一只实例)。引擎读不出的层键 ⇒ 抛引擎的 `config.memory_scope_key`,原样。 */
41
+ storeOf(layer: string): MemoryBackend;
42
+ /** 本部署配置点名的层(每次现读 —— 登记簿热换)。 */
43
+ namedLayers(): readonly string[];
44
+ }
45
+ /** 命名照工厂律:返回带行为的活对象 ⇒ `create*`。 */
46
+ export declare function createMemoryScopeStores(input: {
47
+ backend: MemoryBackend;
48
+ root: string;
49
+ namedLayers: () => readonly string[];
50
+ /** 本对象为一层开出的店(个人平面的 File 店)的构造期 incident 座(与部署的店那只同一只汇点;缺席合法)。 */
51
+ onIncident?: (err: Error & {
52
+ code?: string;
53
+ }) => void;
54
+ }): MemoryScopeStores;
55
+ /** 本服务的「这次请求落不到一只记忆店」拒(400 `request.memory_layer`):点名的层读不出 / 点名的几层分住两只店 / 两店部署上没点名层。 */
56
+ export declare class MemoryLayerRefusal extends Error {
57
+ readonly code: "request.memory_layer";
58
+ constructor(message: string, cause?: unknown);
59
+ }
60
+ /**
61
+ * 一次请求的记忆店。`layers` = 请求点名的层(空 = 没点名):
62
+ * · 点名 ⇒ 它们共住的那一只店;分住两只 ⇒ 拒(一次请求只落一只店,按店拆成几次请求)。
63
+ * · 没点名 ⇒ 本部署点名的层与部署的店共处的那一只(= 部署的店);它们分住两只 ⇒ 拒,指路在请求里点名层。
64
+ * `seat` = 这个动词点名层的那一处(拒句里指路用,如 `` `scope` ``;缺省 = 层座 `scope`)。
65
+ * 拒一律 {@link MemoryLayerRefusal}(读不出的层键同码,引擎原句随句)。
66
+ */
67
+ export declare function memoryStoreForRequest(stores: MemoryScopeStores, layers: readonly string[], seat?: string): MemoryBackend;
68
+ /**
69
+ * 本部署的店:部署的店在前,其后是本部署点名的层住的其余店(去重)—— 单店部署恰一只(部署的店本身)。点名的层读不出 ⇒ {@link MemoryLayerRefusal}(同无层那一臂)。
70
+ * 每次现算(登记簿热换当场生效);只问平面与每平面一只的店,不建多余的店。
71
+ */
72
+ export declare function memoryStoresOfDeployment(stores: MemoryScopeStores, seat?: string): readonly MemoryBackend[];
73
+ //# sourceMappingURL=memory-scope-stores.d.ts.map
@@ -0,0 +1,86 @@
1
+ import { resolveMemoryScopeStore } from "@sema-agent/core";
2
+ import { memoryScopeContractOf } from "./memory-scope.js";
3
+ export function createMemoryScopeStores(input) {
4
+ const byPlane = new Map();
5
+ const resolve = (layer, backend) => resolveMemoryScopeStore({
6
+ scope: layer,
7
+ scopeContract: memoryScopeContractOf([layer]),
8
+ backend,
9
+ memoryEngineDir: input.root,
10
+ ...(input.onIncident !== undefined ? { onIncident: input.onIncident } : {}),
11
+ });
12
+ return {
13
+ backend: input.backend,
14
+ root: input.root,
15
+ namedLayers: input.namedLayers,
16
+ storeOf(layer) {
17
+ const { plane } = resolve(layer, PLANE_PROBE);
18
+ const known = byPlane.get(plane);
19
+ if (known !== undefined)
20
+ return known;
21
+ const store = resolve(layer, input.backend).backend;
22
+ byPlane.set(plane, store);
23
+ return store;
24
+ },
25
+ };
26
+ }
27
+ const PLANE_PROBE = Object.freeze({});
28
+ export class MemoryLayerRefusal extends Error {
29
+ code = "request.memory_layer";
30
+ constructor(message, cause) {
31
+ super(message, cause !== undefined ? { cause } : undefined);
32
+ this.name = "MemoryLayerRefusal";
33
+ }
34
+ }
35
+ const quoted = (layers) => layers.map((l) => JSON.stringify(l)).join(", ");
36
+ function storeOfNamed(stores, layer, whose, seat) {
37
+ try {
38
+ return stores.storeOf(layer);
39
+ }
40
+ catch (err) {
41
+ if (err?.code !== "config.memory_scope_key")
42
+ throw err;
43
+ const why = err instanceof Error ? err.message : String(err);
44
+ throw new MemoryLayerRefusal(whose === "request"
45
+ ? `the memory layer ${JSON.stringify(layer)} cannot be read: ${why}`
46
+ : `this deployment's configured memory layer ${JSON.stringify(layer)} cannot be read (${why}), so the store a request that names no layer belongs to cannot be told — name the layer in the request (${seat})`, err);
47
+ }
48
+ }
49
+ export function memoryStoreForRequest(stores, layers, seat = "`scope`") {
50
+ if (layers.length > 0) {
51
+ const groups = new Map();
52
+ for (const layer of layers) {
53
+ const store = storeOfNamed(stores, layer, "request", seat);
54
+ const group = groups.get(store);
55
+ if (group === undefined)
56
+ groups.set(store, [layer]);
57
+ else
58
+ group.push(layer);
59
+ }
60
+ if (groups.size === 1)
61
+ return [...groups.keys()][0];
62
+ const split = [...groups.values()].map((g) => `[${quoted(g)}]`).join(" / ");
63
+ throw new MemoryLayerRefusal(`the memory layers ${quoted(layers)} live in ${groups.size} different memory stores on this deployment and one request reaches one store — send one request per store: ${split}`);
64
+ }
65
+ const groups = deploymentStoreGroups(stores, seat);
66
+ if (groups.size === 1)
67
+ return stores.backend;
68
+ const elsewhere = [...groups.entries()].filter(([store]) => store !== stores.backend).flatMap(([, g]) => g);
69
+ throw new MemoryLayerRefusal(`this deployment keeps memory layers in ${groups.size} stores — the project layers${groups.get(stores.backend).length > 0 ? ` and ${quoted(groups.get(stores.backend))}` : ""} in the deployment's store, ${quoted(elsewhere)} in another — so a request that names no layer cannot be told which store it means; name the layer in the request (${seat})`);
70
+ }
71
+ export function memoryStoresOfDeployment(stores, seat = "`scope`") {
72
+ return [...deploymentStoreGroups(stores, seat).keys()];
73
+ }
74
+ function deploymentStoreGroups(stores, seat) {
75
+ const groups = new Map([[stores.backend, []]]);
76
+ for (const layer of stores.namedLayers()) {
77
+ const store = storeOfNamed(stores, layer, "deployment", seat);
78
+ const group = groups.get(store);
79
+ if (group === undefined)
80
+ groups.set(store, [layer]);
81
+ else
82
+ group.push(layer);
83
+ }
84
+ return groups;
85
+ }
86
+ //# sourceMappingURL=memory-scope-stores.js.map
@@ -8,11 +8,35 @@ export declare const V2_SCOPE_PREFIXES: readonly string[];
8
8
  * 一个 scope 键是否带 v2 typed 前缀。
9
9
  *
10
10
  * ⚠️ 判据刻意停在**前缀**层,不升级成 core 的 `parseScopeKey`:后者对「带可识别前缀但结构坏」的键
11
- * 是 fail-loud 抛错,而本谓词的两个调用点都只是在决定「要不要挂 v2 标 / 要不要再包一层」——把抛点
12
- * 挪到这里会把 core 的校验时机整体前移(行为面改动,不在本条案的射程内)。坏键仍由 core 在它自己的
13
- * 校验点 fail-loud。
11
+ * 是 fail-loud 抛错,而本谓词的两个读者都只是在决定「要不要挂 v2 标({@link memoryScopeContractOf})/
12
+ * 同步层要不要另给(`config.ts`)」——把抛点挪到这里会把 core 的校验时机整体前移(行为面改动,不在本条案的射程内)。
13
+ * 坏键仍由 core 在它自己的校验点 fail-loud。
14
14
  */
15
15
  export declare function isV2ScopeKey(key: string): boolean;
16
+ /**
17
+ * 本服务给一组记忆层盖的**作用域契约**(core `TaskSpec.memory.scopeContract`)—— 一个判据、两个读者:
18
+ * · {@link memorySpecForRequest} 铸 spec 时盖在会话上的那一个(读列表 = 全局层 + 登记簿种子);
19
+ * · 同步执行器替一层问「这一层在哪只店」时报给引擎的那一个(`resolveMemoryScopeStore` 的 `scopeContract`,`memory-sync-client.ts`)。
20
+ * 契约决定**类型化键落哪个平面**(v2 下 `user:` / `userproj:` / `org:` 在个人平面,不透明键在项目平面;不声明则一律项目平面),
21
+ * 所以两个读者必须读同一只:会话把一层放在哪只店,同步就同步哪只店。
22
+ *
23
+ * 判据:列表里有类型化键(前缀表 {@link V2_SCOPE_PREFIXES})⇒ `"v2"`;没有 ⇒ `undefined`(不声明;显式 opt-in,不嗅探调用方数据 ——
24
+ * 这些键只来自本服务自己的铸点与运维的登记簿,见 {@link memorySpecForRequest} 的 142-S1.5 注)。
25
+ * 按层问与按会话问答同一只店:平面按**每把键自己的种类**分,契约只挪类型化键,而本判据下带类型化键的会话恒盖 `"v2"`。
26
+ * 🚧 前提是键为规范形:引擎读键前去掉首尾空白,本判据看原串 —— 带首尾空白的类型化键(`" user:alice"`,配置边界今天放行)本判据不认、引擎在 v2 下读得出,
27
+ * 于是同一把键在带类型化种子的会话里落个人平面、在不带种子的会话与同步执行器里落项目平面。这是会话面先有的不一致(不同项目的会话对同一层就答两只店,
28
+ * 同步执行器无从同时对上两者),收口点在配置边界(拒或规范化这一形,后者会挪存量记忆的平面),不在本谓词;未闭环。
29
+ */
30
+ export declare function memoryScopeContractOf(scopes: readonly string[]): "v2" | undefined;
31
+ /**
32
+ * 本部署**自己点名**的记忆层 —— 配置里写着的每一层(去重、去空串、保序):单用户的全局层(`MEMORY_SCOPE`,{@link memoryScopeFor} 单用户臂的答案)、
33
+ * 同步层(`MEMORY_SYNC_SCOPE`,缺省即全局层)、项目登记簿的种子层(`config.projects[*].defaultScopes`,{@link memorySpecForRequest} 盖进会话的读列表)、
34
+ * 整理层(`MEMORY_CONSOLIDATION_SCOPES`)。项目层(`userrepo:…`)按任务根铸、不在配置里,也就不在这里 —— 它们住部署的店。
35
+ *
36
+ * 唯一读者:记忆作用域店的「不点名层的动词答在哪只店」(`memory-scope-stores.ts` 的 {@link memoryStoreForRequest} 无层那一臂)。
37
+ * 登记簿随中心配置热换(`applyEffective` 在同一只 `config.projects` 对象上原地整表换内容),所以读者每次现调本函数,不在起服时冻一份。
38
+ */
39
+ export declare function memoryLayersNamedBy(config: Pick<ServiceConfig, "requirePrincipal" | "memoryScope" | "memorySync" | "projects" | "memoryConsolidationDriver">): string[];
16
40
  /** Resolve the memory scope for a request —— {@link memoryScopeFor} 的三形(按实现逐臂写;[ref] 合并前主会话点名:
17
41
  * 旧版这里写「多租户恒 `undefined` ⇒ 记忆暗」,与下面 DB 后端那一臂正好相反,test [ref] 就是被这句带偏的)。
18
42
  *
@@ -93,8 +117,8 @@ export declare function replicatesProjectLayersOf(coverage: MemoryReplicationCov
93
117
  * Pure posture probe (memoryEngineBackendFor consumes it; main.ts logs it): `undefined` = no plane split
94
118
  * (the lane's file plane IS this worker's fs — `in-process` / `host`), `dark` = split + fail-closed, `forced` =
95
119
  * split + operator override.
96
- * [ref]: the plane question reads the lane-caps table (`hostFilePlane`) — it used to be the hand-written synonym
97
- * `lane === undefined || lane === "host"` (fold-ban gate D, R3); readings are unchanged lane by lane.
120
+ * The plane question reads the execution environment block (`hostLocalPaths`, sole author `capabilitiesFor`) — it used to be the
121
+ * hand-written synonym `lane === undefined || lane === "host"`; readings are unchanged lane by lane.
98
122
  */
99
123
  export declare function memoryEngineRemoteLanePosture(config: ServiceConfig): {
100
124
  lane: ExecutionLane;
@@ -1,6 +1,6 @@
1
1
  import { join } from "node:path";
2
2
  import { FileMemoryEngineBackend, resolveMemoryEngineRoot, deriveControlPlaneDir, formatUserScope, formatProjScope, normalizeMemorySpec } from "@sema-agent/core";
3
- import { executionLaneCaps, executionLaneOf } from "./execution-lane-caps.js";
3
+ import { capabilitiesFor, executionLaneOf } from "./execution-lane-caps.js";
4
4
  import { assertMemoryScopeWidth } from "./plugins/memory-key-guards.js";
5
5
  import { projectLayerForTaskRoot } from "./project-identity.js";
6
6
  import { parseProjectLayerKey, projectLayerOwnerOf } from "./project-layer-key.js";
@@ -14,6 +14,18 @@ export const V2_SCOPE_PREFIXES = Object.freeze(Object.values(V2_SCOPE_PREFIX_BY_
14
14
  export function isV2ScopeKey(key) {
15
15
  return V2_SCOPE_PREFIXES.some((prefix) => key.startsWith(prefix));
16
16
  }
17
+ export function memoryScopeContractOf(scopes) {
18
+ return scopes.some(isV2ScopeKey) ? "v2" : undefined;
19
+ }
20
+ export function memoryLayersNamedBy(config) {
21
+ const named = [
22
+ ...(config.requirePrincipal === true ? [] : [config.memoryScope]),
23
+ ...(config.memorySync !== undefined ? [config.memorySync.scope] : []),
24
+ ...Object.values(config.projects ?? {}).flatMap((p) => p.defaultScopes ?? []),
25
+ ...config.memoryConsolidationDriver.scopes,
26
+ ];
27
+ return named.filter((s, i) => typeof s === "string" && s.length > 0 && named.indexOf(s) === i);
28
+ }
17
29
  export { MEMORY_SCOPE_COLUMN_CHARS, assertMemoryScopeWidth } from "./plugins/memory-key-guards.js";
18
30
  export function memoryScopeFor(config, principal, projectId) {
19
31
  if (config.requirePrincipal === true) {
@@ -64,7 +76,7 @@ export function replicatesProjectLayersOf(coverage, owner) {
64
76
  }
65
77
  export function memoryEngineRemoteLanePosture(config) {
66
78
  const lane = executionLaneOf(config.remoteExec?.provider);
67
- if (executionLaneCaps(lane).hostFilePlane === "supported")
79
+ if (capabilitiesFor(config).hostLocalPaths)
68
80
  return undefined;
69
81
  return { lane, posture: config.memoryEngineRemoteLaneAllowed === true ? "forced" : "dark" };
70
82
  }
@@ -158,14 +170,14 @@ export function memorySpecForRequest(scope, projectKey, memoryWrite, defaultScop
158
170
  throw new Error(`memory project scope ${JSON.stringify(projectScope)} equals the global memory scope (MEMORY_SCOPE) — the project layer and the global layer would be one directory. ` +
159
171
  "Set MEMORY_SCOPE to a name outside the server-minted project-key families (see src/project-layer-key.ts).");
160
172
  }
161
- const isV2 = isV2ScopeKey;
162
173
  const extras = (defaultScopes ?? []).filter((s, i, arr) => typeof s === "string" && s.length > 0 && s !== scope && s !== projectScope && arr.indexOf(s) === i);
163
174
  const layered = projectKey !== undefined
164
175
  ? { scopes: projectScope !== undefined ? [projectScope, scope, ...extras] : [scope, ...extras], writeScope: projectScope ?? scope, projectKey }
165
176
  : extras.length > 0
166
177
  ? { scopes: [scope, ...extras], writeScope: scope }
167
178
  : { scopes: [scope] };
168
- const v2 = isV2(scope) || extras.some(isV2) ? { scopeContract: "v2" } : {};
179
+ const contract = memoryScopeContractOf([scope, ...extras]);
180
+ const v2 = contract !== undefined ? { scopeContract: contract } : {};
169
181
  const stamped = {};
170
182
  if (originPolicy !== undefined) {
171
183
  if (scope.startsWith("org:"))