@aigne/aos 0.2.0-beta

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 (533) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/LICENSE.md +26 -0
  3. package/dist/agent-dsl.cjs +116 -0
  4. package/dist/agent-dsl.d.cts +31 -0
  5. package/dist/agent-dsl.d.cts.map +1 -0
  6. package/dist/agent-dsl.d.mts +31 -0
  7. package/dist/agent-dsl.d.mts.map +1 -0
  8. package/dist/agent-dsl.mjs +115 -0
  9. package/dist/agent-dsl.mjs.map +1 -0
  10. package/dist/arc-compat.cjs +125 -0
  11. package/dist/arc-compat.d.cts +17 -0
  12. package/dist/arc-compat.d.cts.map +1 -0
  13. package/dist/arc-compat.d.mts +17 -0
  14. package/dist/arc-compat.d.mts.map +1 -0
  15. package/dist/arc-compat.mjs +123 -0
  16. package/dist/arc-compat.mjs.map +1 -0
  17. package/dist/auto-surface/compiler.cjs +36 -0
  18. package/dist/auto-surface/compiler.d.cts +7 -0
  19. package/dist/auto-surface/compiler.d.cts.map +1 -0
  20. package/dist/auto-surface/compiler.d.mts +7 -0
  21. package/dist/auto-surface/compiler.d.mts.map +1 -0
  22. package/dist/auto-surface/compiler.mjs +37 -0
  23. package/dist/auto-surface/compiler.mjs.map +1 -0
  24. package/dist/auto-surface/definition-dsl.cjs +333 -0
  25. package/dist/auto-surface/definition-dsl.d.cts +41 -0
  26. package/dist/auto-surface/definition-dsl.d.cts.map +1 -0
  27. package/dist/auto-surface/definition-dsl.d.mts +41 -0
  28. package/dist/auto-surface/definition-dsl.d.mts.map +1 -0
  29. package/dist/auto-surface/definition-dsl.mjs +332 -0
  30. package/dist/auto-surface/definition-dsl.mjs.map +1 -0
  31. package/dist/auto-surface/fragments.cjs +177 -0
  32. package/dist/auto-surface/fragments.d.cts +23 -0
  33. package/dist/auto-surface/fragments.d.cts.map +1 -0
  34. package/dist/auto-surface/fragments.d.mts +23 -0
  35. package/dist/auto-surface/fragments.d.mts.map +1 -0
  36. package/dist/auto-surface/fragments.mjs +175 -0
  37. package/dist/auto-surface/fragments.mjs.map +1 -0
  38. package/dist/auto-surface/index.d.mts +9 -0
  39. package/dist/auto-surface/layering.cjs +43 -0
  40. package/dist/auto-surface/layering.d.cts +7 -0
  41. package/dist/auto-surface/layering.d.cts.map +1 -0
  42. package/dist/auto-surface/layering.d.mts +7 -0
  43. package/dist/auto-surface/layering.d.mts.map +1 -0
  44. package/dist/auto-surface/layering.mjs +43 -0
  45. package/dist/auto-surface/layering.mjs.map +1 -0
  46. package/dist/auto-surface/projection.cjs +11 -0
  47. package/dist/auto-surface/projection.d.cts +11 -0
  48. package/dist/auto-surface/projection.d.cts.map +1 -0
  49. package/dist/auto-surface/projection.d.mts +11 -0
  50. package/dist/auto-surface/projection.d.mts.map +1 -0
  51. package/dist/auto-surface/projection.mjs +12 -0
  52. package/dist/auto-surface/projection.mjs.map +1 -0
  53. package/dist/auto-surface/projectors/settings-shell.cjs +114 -0
  54. package/dist/auto-surface/projectors/settings-shell.d.cts +10 -0
  55. package/dist/auto-surface/projectors/settings-shell.d.cts.map +1 -0
  56. package/dist/auto-surface/projectors/settings-shell.d.mts +10 -0
  57. package/dist/auto-surface/projectors/settings-shell.d.mts.map +1 -0
  58. package/dist/auto-surface/projectors/settings-shell.mjs +114 -0
  59. package/dist/auto-surface/projectors/settings-shell.mjs.map +1 -0
  60. package/dist/auto-surface/scenario.cjs +38 -0
  61. package/dist/auto-surface/scenario.d.cts +31 -0
  62. package/dist/auto-surface/scenario.d.cts.map +1 -0
  63. package/dist/auto-surface/scenario.d.mts +31 -0
  64. package/dist/auto-surface/scenario.d.mts.map +1 -0
  65. package/dist/auto-surface/scenario.mjs +37 -0
  66. package/dist/auto-surface/scenario.mjs.map +1 -0
  67. package/dist/auto-surface/types.cjs +9 -0
  68. package/dist/auto-surface/types.d.cts +153 -0
  69. package/dist/auto-surface/types.d.cts.map +1 -0
  70. package/dist/auto-surface/types.d.mts +153 -0
  71. package/dist/auto-surface/types.d.mts.map +1 -0
  72. package/dist/auto-surface/types.mjs +9 -0
  73. package/dist/auto-surface/types.mjs.map +1 -0
  74. package/dist/auto-surface/value-dsl.cjs +80 -0
  75. package/dist/auto-surface/value-dsl.d.cts +24 -0
  76. package/dist/auto-surface/value-dsl.d.cts.map +1 -0
  77. package/dist/auto-surface/value-dsl.d.mts +24 -0
  78. package/dist/auto-surface/value-dsl.d.mts.map +1 -0
  79. package/dist/auto-surface/value-dsl.mjs +79 -0
  80. package/dist/auto-surface/value-dsl.mjs.map +1 -0
  81. package/dist/blocklet/activation.cjs +94 -0
  82. package/dist/blocklet/activation.d.cts +30 -0
  83. package/dist/blocklet/activation.d.cts.map +1 -0
  84. package/dist/blocklet/activation.d.mts +30 -0
  85. package/dist/blocklet/activation.d.mts.map +1 -0
  86. package/dist/blocklet/activation.mjs +94 -0
  87. package/dist/blocklet/activation.mjs.map +1 -0
  88. package/dist/blocklet/did-space-registry.cjs +282 -0
  89. package/dist/blocklet/did-space-registry.d.cts +82 -0
  90. package/dist/blocklet/did-space-registry.d.cts.map +1 -0
  91. package/dist/blocklet/did-space-registry.d.mts +82 -0
  92. package/dist/blocklet/did-space-registry.d.mts.map +1 -0
  93. package/dist/blocklet/did-space-registry.mjs +281 -0
  94. package/dist/blocklet/did-space-registry.mjs.map +1 -0
  95. package/dist/blocklet/handlers.cjs +66 -0
  96. package/dist/blocklet/handlers.d.cts +16 -0
  97. package/dist/blocklet/handlers.d.cts.map +1 -0
  98. package/dist/blocklet/handlers.d.mts +16 -0
  99. package/dist/blocklet/handlers.d.mts.map +1 -0
  100. package/dist/blocklet/handlers.mjs +65 -0
  101. package/dist/blocklet/handlers.mjs.map +1 -0
  102. package/dist/blocklet/index.d.mts +7 -0
  103. package/dist/blocklet/manifest.d.cts +2 -0
  104. package/dist/blocklet/manifest.d.mts +2 -0
  105. package/dist/blocklet/manifest.mjs +3 -0
  106. package/dist/blocklet/registry.cjs +447 -0
  107. package/dist/blocklet/registry.d.cts +197 -0
  108. package/dist/blocklet/registry.d.cts.map +1 -0
  109. package/dist/blocklet/registry.d.mts +197 -0
  110. package/dist/blocklet/registry.d.mts.map +1 -0
  111. package/dist/blocklet/registry.mjs +441 -0
  112. package/dist/blocklet/registry.mjs.map +1 -0
  113. package/dist/blocklet/static-render.cjs +183 -0
  114. package/dist/blocklet/static-render.d.cts +55 -0
  115. package/dist/blocklet/static-render.d.cts.map +1 -0
  116. package/dist/blocklet/static-render.d.mts +55 -0
  117. package/dist/blocklet/static-render.d.mts.map +1 -0
  118. package/dist/blocklet/static-render.mjs +181 -0
  119. package/dist/blocklet/static-render.mjs.map +1 -0
  120. package/dist/blocklet/types.d.cts +70 -0
  121. package/dist/blocklet/types.d.cts.map +1 -0
  122. package/dist/blocklet/types.d.mts +70 -0
  123. package/dist/blocklet/types.d.mts.map +1 -0
  124. package/dist/devices/chain.cjs +127 -0
  125. package/dist/devices/chain.d.cts +48 -0
  126. package/dist/devices/chain.d.cts.map +1 -0
  127. package/dist/devices/chain.d.mts +48 -0
  128. package/dist/devices/chain.d.mts.map +1 -0
  129. package/dist/devices/chain.mjs +125 -0
  130. package/dist/devices/chain.mjs.map +1 -0
  131. package/dist/dsl-shared.cjs +290 -0
  132. package/dist/dsl-shared.d.cts +54 -0
  133. package/dist/dsl-shared.d.cts.map +1 -0
  134. package/dist/dsl-shared.d.mts +54 -0
  135. package/dist/dsl-shared.d.mts.map +1 -0
  136. package/dist/dsl-shared.mjs +287 -0
  137. package/dist/dsl-shared.mjs.map +1 -0
  138. package/dist/http/afs-mcp.cjs +85 -0
  139. package/dist/http/afs-mcp.d.cts +14 -0
  140. package/dist/http/afs-mcp.d.cts.map +1 -0
  141. package/dist/http/afs-mcp.d.mts +14 -0
  142. package/dist/http/afs-mcp.d.mts.map +1 -0
  143. package/dist/http/afs-mcp.mjs +86 -0
  144. package/dist/http/afs-mcp.mjs.map +1 -0
  145. package/dist/http/afs-raw.cjs +264 -0
  146. package/dist/http/afs-raw.d.cts +31 -0
  147. package/dist/http/afs-raw.d.cts.map +1 -0
  148. package/dist/http/afs-raw.d.mts +31 -0
  149. package/dist/http/afs-raw.d.mts.map +1 -0
  150. package/dist/http/afs-raw.mjs +264 -0
  151. package/dist/http/afs-raw.mjs.map +1 -0
  152. package/dist/http/afs-rest.cjs +30 -0
  153. package/dist/http/afs-rest.d.cts +21 -0
  154. package/dist/http/afs-rest.d.cts.map +1 -0
  155. package/dist/http/afs-rest.d.mts +21 -0
  156. package/dist/http/afs-rest.d.mts.map +1 -0
  157. package/dist/http/afs-rest.mjs +31 -0
  158. package/dist/http/afs-rest.mjs.map +1 -0
  159. package/dist/http/afs-rpc-wire.cjs +271 -0
  160. package/dist/http/afs-rpc-wire.d.cts +195 -0
  161. package/dist/http/afs-rpc-wire.d.cts.map +1 -0
  162. package/dist/http/afs-rpc-wire.d.mts +195 -0
  163. package/dist/http/afs-rpc-wire.d.mts.map +1 -0
  164. package/dist/http/afs-rpc-wire.mjs +262 -0
  165. package/dist/http/afs-rpc-wire.mjs.map +1 -0
  166. package/dist/http/afs-rpc.cjs +729 -0
  167. package/dist/http/afs-rpc.d.cts +103 -0
  168. package/dist/http/afs-rpc.d.cts.map +1 -0
  169. package/dist/http/afs-rpc.d.mts +103 -0
  170. package/dist/http/afs-rpc.d.mts.map +1 -0
  171. package/dist/http/afs-rpc.mjs +729 -0
  172. package/dist/http/afs-rpc.mjs.map +1 -0
  173. package/dist/http/afs-upload.cjs +116 -0
  174. package/dist/http/afs-upload.d.cts +40 -0
  175. package/dist/http/afs-upload.d.cts.map +1 -0
  176. package/dist/http/afs-upload.d.mts +40 -0
  177. package/dist/http/afs-upload.d.mts.map +1 -0
  178. package/dist/http/afs-upload.mjs +116 -0
  179. package/dist/http/afs-upload.mjs.map +1 -0
  180. package/dist/http/aup-client.cjs +60 -0
  181. package/dist/http/aup-client.d.cts +22 -0
  182. package/dist/http/aup-client.d.cts.map +1 -0
  183. package/dist/http/aup-client.d.mts +22 -0
  184. package/dist/http/aup-client.d.mts.map +1 -0
  185. package/dist/http/aup-client.mjs +59 -0
  186. package/dist/http/aup-client.mjs.map +1 -0
  187. package/dist/http/aup-event.cjs +100 -0
  188. package/dist/http/aup-event.d.cts +38 -0
  189. package/dist/http/aup-event.d.cts.map +1 -0
  190. package/dist/http/aup-event.d.mts +38 -0
  191. package/dist/http/aup-event.d.mts.map +1 -0
  192. package/dist/http/aup-event.mjs +101 -0
  193. package/dist/http/aup-event.mjs.map +1 -0
  194. package/dist/http/auth-context.cjs +66 -0
  195. package/dist/http/auth-context.d.cts +64 -0
  196. package/dist/http/auth-context.d.cts.map +1 -0
  197. package/dist/http/auth-context.d.mts +64 -0
  198. package/dist/http/auth-context.d.mts.map +1 -0
  199. package/dist/http/auth-context.mjs +66 -0
  200. package/dist/http/auth-context.mjs.map +1 -0
  201. package/dist/http/csrf.cjs +50 -0
  202. package/dist/http/csrf.d.cts +8 -0
  203. package/dist/http/csrf.d.cts.map +1 -0
  204. package/dist/http/csrf.d.mts +8 -0
  205. package/dist/http/csrf.d.mts.map +1 -0
  206. package/dist/http/csrf.mjs +49 -0
  207. package/dist/http/csrf.mjs.map +1 -0
  208. package/dist/http/handlers.cjs +106 -0
  209. package/dist/http/handlers.d.cts +39 -0
  210. package/dist/http/handlers.d.cts.map +1 -0
  211. package/dist/http/handlers.d.mts +39 -0
  212. package/dist/http/handlers.d.mts.map +1 -0
  213. package/dist/http/handlers.mjs +104 -0
  214. package/dist/http/handlers.mjs.map +1 -0
  215. package/dist/http/index.d.mts +1 -0
  216. package/dist/http/ingest-facade.cjs +315 -0
  217. package/dist/http/ingest-facade.mjs +314 -0
  218. package/dist/http/ingest-facade.mjs.map +1 -0
  219. package/dist/http/raw-url.cjs +136 -0
  220. package/dist/http/raw-url.d.cts +54 -0
  221. package/dist/http/raw-url.d.cts.map +1 -0
  222. package/dist/http/raw-url.d.mts +54 -0
  223. package/dist/http/raw-url.d.mts.map +1 -0
  224. package/dist/http/raw-url.mjs +136 -0
  225. package/dist/http/raw-url.mjs.map +1 -0
  226. package/dist/http/request-context.cjs +178 -0
  227. package/dist/http/request-context.d.cts +76 -0
  228. package/dist/http/request-context.d.cts.map +1 -0
  229. package/dist/http/request-context.d.mts +76 -0
  230. package/dist/http/request-context.d.mts.map +1 -0
  231. package/dist/http/request-context.mjs +179 -0
  232. package/dist/http/request-context.mjs.map +1 -0
  233. package/dist/index.cjs +197 -0
  234. package/dist/index.d.cts +63 -0
  235. package/dist/index.d.mts +68 -0
  236. package/dist/index.mjs +61 -0
  237. package/dist/mcp/index.cjs +9 -0
  238. package/dist/mcp/index.d.cts +5 -0
  239. package/dist/mcp/index.d.mts +5 -0
  240. package/dist/mcp/index.mjs +6 -0
  241. package/dist/mcp/prompts.cjs +17 -0
  242. package/dist/mcp/prompts.d.cts +8 -0
  243. package/dist/mcp/prompts.d.cts.map +1 -0
  244. package/dist/mcp/prompts.d.mts +8 -0
  245. package/dist/mcp/prompts.d.mts.map +1 -0
  246. package/dist/mcp/prompts.mjs +17 -0
  247. package/dist/mcp/prompts.mjs.map +1 -0
  248. package/dist/mcp/resources.cjs +22 -0
  249. package/dist/mcp/resources.d.cts +8 -0
  250. package/dist/mcp/resources.d.cts.map +1 -0
  251. package/dist/mcp/resources.d.mts +8 -0
  252. package/dist/mcp/resources.d.mts.map +1 -0
  253. package/dist/mcp/resources.mjs +22 -0
  254. package/dist/mcp/resources.mjs.map +1 -0
  255. package/dist/mcp/server.cjs +51 -0
  256. package/dist/mcp/server.d.cts +20 -0
  257. package/dist/mcp/server.d.cts.map +1 -0
  258. package/dist/mcp/server.d.mts +20 -0
  259. package/dist/mcp/server.d.mts.map +1 -0
  260. package/dist/mcp/server.mjs +52 -0
  261. package/dist/mcp/server.mjs.map +1 -0
  262. package/dist/mcp/tools.cjs +218 -0
  263. package/dist/mcp/tools.d.cts +8 -0
  264. package/dist/mcp/tools.d.cts.map +1 -0
  265. package/dist/mcp/tools.d.mts +8 -0
  266. package/dist/mcp/tools.d.mts.map +1 -0
  267. package/dist/mcp/tools.mjs +219 -0
  268. package/dist/mcp/tools.mjs.map +1 -0
  269. package/dist/mcp/utils.cjs +75 -0
  270. package/dist/mcp/utils.mjs +69 -0
  271. package/dist/mcp/utils.mjs.map +1 -0
  272. package/dist/mount/index.cjs +4 -0
  273. package/dist/mount/index.d.cts +3 -0
  274. package/dist/mount/index.d.mts +3 -0
  275. package/dist/mount/index.mjs +3 -0
  276. package/dist/mount/materializer.cjs +167 -0
  277. package/dist/mount/materializer.d.cts +97 -0
  278. package/dist/mount/materializer.d.cts.map +1 -0
  279. package/dist/mount/materializer.d.mts +97 -0
  280. package/dist/mount/materializer.d.mts.map +1 -0
  281. package/dist/mount/materializer.mjs +167 -0
  282. package/dist/mount/materializer.mjs.map +1 -0
  283. package/dist/mount/types.d.cts +90 -0
  284. package/dist/mount/types.d.cts.map +1 -0
  285. package/dist/mount/types.d.mts +90 -0
  286. package/dist/mount/types.d.mts.map +1 -0
  287. package/dist/mount-config.cjs +61 -0
  288. package/dist/mount-config.d.cts +19 -0
  289. package/dist/mount-config.d.cts.map +1 -0
  290. package/dist/mount-config.d.mts +19 -0
  291. package/dist/mount-config.d.mts.map +1 -0
  292. package/dist/mount-config.mjs +61 -0
  293. package/dist/mount-config.mjs.map +1 -0
  294. package/dist/projectors/aup-projector.cjs +190 -0
  295. package/dist/projectors/aup-projector.d.cts +59 -0
  296. package/dist/projectors/aup-projector.d.cts.map +1 -0
  297. package/dist/projectors/aup-projector.d.mts +59 -0
  298. package/dist/projectors/aup-projector.d.mts.map +1 -0
  299. package/dist/projectors/aup-projector.mjs +188 -0
  300. package/dist/projectors/aup-projector.mjs.map +1 -0
  301. package/dist/projectors/index.cjs +6 -0
  302. package/dist/projectors/index.d.cts +2 -0
  303. package/dist/projectors/index.d.mts +2 -0
  304. package/dist/projectors/index.mjs +3 -0
  305. package/dist/scaffold/afs.cjs +195 -0
  306. package/dist/scaffold/afs.d.cts +16 -0
  307. package/dist/scaffold/afs.d.cts.map +1 -0
  308. package/dist/scaffold/afs.d.mts +16 -0
  309. package/dist/scaffold/afs.d.mts.map +1 -0
  310. package/dist/scaffold/afs.mjs +195 -0
  311. package/dist/scaffold/afs.mjs.map +1 -0
  312. package/dist/scaffold/composition.cjs +92 -0
  313. package/dist/scaffold/composition.d.cts +10 -0
  314. package/dist/scaffold/composition.d.cts.map +1 -0
  315. package/dist/scaffold/composition.d.mts +10 -0
  316. package/dist/scaffold/composition.d.mts.map +1 -0
  317. package/dist/scaffold/composition.mjs +92 -0
  318. package/dist/scaffold/composition.mjs.map +1 -0
  319. package/dist/scaffold/dsl-error.cjs +21 -0
  320. package/dist/scaffold/dsl-error.d.cts +11 -0
  321. package/dist/scaffold/dsl-error.d.cts.map +1 -0
  322. package/dist/scaffold/dsl-error.d.mts +11 -0
  323. package/dist/scaffold/dsl-error.d.mts.map +1 -0
  324. package/dist/scaffold/dsl-error.mjs +20 -0
  325. package/dist/scaffold/dsl-error.mjs.map +1 -0
  326. package/dist/scaffold/index.d.mts +12 -0
  327. package/dist/scaffold/manifest-dsl.cjs +188 -0
  328. package/dist/scaffold/manifest-dsl.d.cts +8 -0
  329. package/dist/scaffold/manifest-dsl.d.cts.map +1 -0
  330. package/dist/scaffold/manifest-dsl.d.mts +8 -0
  331. package/dist/scaffold/manifest-dsl.d.mts.map +1 -0
  332. package/dist/scaffold/manifest-dsl.mjs +188 -0
  333. package/dist/scaffold/manifest-dsl.mjs.map +1 -0
  334. package/dist/scaffold/module-dsl.cjs +284 -0
  335. package/dist/scaffold/module-dsl.d.cts +8 -0
  336. package/dist/scaffold/module-dsl.d.cts.map +1 -0
  337. package/dist/scaffold/module-dsl.d.mts +8 -0
  338. package/dist/scaffold/module-dsl.d.mts.map +1 -0
  339. package/dist/scaffold/module-dsl.mjs +284 -0
  340. package/dist/scaffold/module-dsl.mjs.map +1 -0
  341. package/dist/scaffold/resolver.cjs +156 -0
  342. package/dist/scaffold/resolver.d.cts +7 -0
  343. package/dist/scaffold/resolver.d.cts.map +1 -0
  344. package/dist/scaffold/resolver.d.mts +7 -0
  345. package/dist/scaffold/resolver.d.mts.map +1 -0
  346. package/dist/scaffold/resolver.mjs +156 -0
  347. package/dist/scaffold/resolver.mjs.map +1 -0
  348. package/dist/scaffold/runtime.cjs +24 -0
  349. package/dist/scaffold/runtime.d.cts +19 -0
  350. package/dist/scaffold/runtime.d.cts.map +1 -0
  351. package/dist/scaffold/runtime.d.mts +19 -0
  352. package/dist/scaffold/runtime.d.mts.map +1 -0
  353. package/dist/scaffold/runtime.mjs +25 -0
  354. package/dist/scaffold/runtime.mjs.map +1 -0
  355. package/dist/scaffold/shell-dsl.cjs +279 -0
  356. package/dist/scaffold/shell-dsl.d.cts +8 -0
  357. package/dist/scaffold/shell-dsl.d.cts.map +1 -0
  358. package/dist/scaffold/shell-dsl.d.mts +8 -0
  359. package/dist/scaffold/shell-dsl.d.mts.map +1 -0
  360. package/dist/scaffold/shell-dsl.mjs +279 -0
  361. package/dist/scaffold/shell-dsl.mjs.map +1 -0
  362. package/dist/scaffold/surface-dsl.cjs +182 -0
  363. package/dist/scaffold/surface-dsl.d.cts +8 -0
  364. package/dist/scaffold/surface-dsl.d.cts.map +1 -0
  365. package/dist/scaffold/surface-dsl.d.mts +8 -0
  366. package/dist/scaffold/surface-dsl.d.mts.map +1 -0
  367. package/dist/scaffold/surface-dsl.mjs +182 -0
  368. package/dist/scaffold/surface-dsl.mjs.map +1 -0
  369. package/dist/scaffold/surfaces.cjs +84 -0
  370. package/dist/scaffold/surfaces.d.cts +23 -0
  371. package/dist/scaffold/surfaces.d.cts.map +1 -0
  372. package/dist/scaffold/surfaces.d.mts +24 -0
  373. package/dist/scaffold/surfaces.d.mts.map +1 -0
  374. package/dist/scaffold/surfaces.mjs +84 -0
  375. package/dist/scaffold/surfaces.mjs.map +1 -0
  376. package/dist/scaffold/types.d.cts +264 -0
  377. package/dist/scaffold/types.d.cts.map +1 -0
  378. package/dist/scaffold/types.d.mts +265 -0
  379. package/dist/scaffold/types.d.mts.map +1 -0
  380. package/dist/scaffold/workspace-dsl.cjs +339 -0
  381. package/dist/scaffold/workspace-dsl.d.cts +49 -0
  382. package/dist/scaffold/workspace-dsl.d.cts.map +1 -0
  383. package/dist/scaffold/workspace-dsl.d.mts +49 -0
  384. package/dist/scaffold/workspace-dsl.d.mts.map +1 -0
  385. package/dist/scaffold/workspace-dsl.mjs +337 -0
  386. package/dist/scaffold/workspace-dsl.mjs.map +1 -0
  387. package/dist/scope/index.d.mts +3 -0
  388. package/dist/scope/read-blocklet-scope.cjs +29 -0
  389. package/dist/scope/read-blocklet-scope.d.cts +8 -0
  390. package/dist/scope/read-blocklet-scope.d.cts.map +1 -0
  391. package/dist/scope/read-blocklet-scope.d.mts +8 -0
  392. package/dist/scope/read-blocklet-scope.d.mts.map +1 -0
  393. package/dist/scope/read-blocklet-scope.mjs +30 -0
  394. package/dist/scope/read-blocklet-scope.mjs.map +1 -0
  395. package/dist/scope/resolve-scoped-afs.cjs +87 -0
  396. package/dist/scope/resolve-scoped-afs.d.cts +7 -0
  397. package/dist/scope/resolve-scoped-afs.d.cts.map +1 -0
  398. package/dist/scope/resolve-scoped-afs.d.mts +7 -0
  399. package/dist/scope/resolve-scoped-afs.d.mts.map +1 -0
  400. package/dist/scope/resolve-scoped-afs.mjs +88 -0
  401. package/dist/scope/resolve-scoped-afs.mjs.map +1 -0
  402. package/dist/scope/types.d.cts +25 -0
  403. package/dist/scope/types.d.cts.map +1 -0
  404. package/dist/scope/types.d.mts +25 -0
  405. package/dist/scope/types.d.mts.map +1 -0
  406. package/dist/session/backends.cjs +90 -0
  407. package/dist/session/backends.d.cts +35 -0
  408. package/dist/session/backends.d.cts.map +1 -0
  409. package/dist/session/backends.d.mts +35 -0
  410. package/dist/session/backends.d.mts.map +1 -0
  411. package/dist/session/backends.mjs +89 -0
  412. package/dist/session/backends.mjs.map +1 -0
  413. package/dist/session/replication-resolver.cjs +323 -0
  414. package/dist/session/replication-resolver.d.cts +71 -0
  415. package/dist/session/replication-resolver.d.cts.map +1 -0
  416. package/dist/session/replication-resolver.d.mts +71 -0
  417. package/dist/session/replication-resolver.d.mts.map +1 -0
  418. package/dist/session/replication-resolver.mjs +323 -0
  419. package/dist/session/replication-resolver.mjs.map +1 -0
  420. package/dist/session/role-level.cjs +36 -0
  421. package/dist/session/role-level.d.cts +24 -0
  422. package/dist/session/role-level.d.cts.map +1 -0
  423. package/dist/session/role-level.d.mts +24 -0
  424. package/dist/session/role-level.d.mts.map +1 -0
  425. package/dist/session/role-level.mjs +35 -0
  426. package/dist/session/role-level.mjs.map +1 -0
  427. package/dist/session/session-dir-providers.cjs +254 -0
  428. package/dist/session/session-dir-providers.d.cts +32 -0
  429. package/dist/session/session-dir-providers.d.cts.map +1 -0
  430. package/dist/session/session-dir-providers.d.mts +32 -0
  431. package/dist/session/session-dir-providers.d.mts.map +1 -0
  432. package/dist/session/session-dir-providers.mjs +252 -0
  433. package/dist/session/session-dir-providers.mjs.map +1 -0
  434. package/dist/session/session-id.cjs +20 -0
  435. package/dist/session/session-id.d.cts +15 -0
  436. package/dist/session/session-id.d.cts.map +1 -0
  437. package/dist/session/session-id.d.mts +15 -0
  438. package/dist/session/session-id.d.mts.map +1 -0
  439. package/dist/session/session-id.mjs +20 -0
  440. package/dist/session/session-id.mjs.map +1 -0
  441. package/dist/session/session-user-afs.cjs +899 -0
  442. package/dist/session/session-user-afs.d.cts +296 -0
  443. package/dist/session/session-user-afs.d.cts.map +1 -0
  444. package/dist/session/session-user-afs.d.mts +296 -0
  445. package/dist/session/session-user-afs.d.mts.map +1 -0
  446. package/dist/session/session-user-afs.mjs +896 -0
  447. package/dist/session/session-user-afs.mjs.map +1 -0
  448. package/dist/session/settings-cascade.cjs +69 -0
  449. package/dist/session/settings-cascade.d.cts +81 -0
  450. package/dist/session/settings-cascade.d.cts.map +1 -0
  451. package/dist/session/settings-cascade.d.mts +81 -0
  452. package/dist/session/settings-cascade.d.mts.map +1 -0
  453. package/dist/session/settings-cascade.mjs +69 -0
  454. package/dist/session/settings-cascade.mjs.map +1 -0
  455. package/dist/session/settings-resolver.cjs +770 -0
  456. package/dist/session/settings-resolver.d.cts +177 -0
  457. package/dist/session/settings-resolver.d.cts.map +1 -0
  458. package/dist/session/settings-resolver.d.mts +177 -0
  459. package/dist/session/settings-resolver.d.mts.map +1 -0
  460. package/dist/session/settings-resolver.mjs +771 -0
  461. package/dist/session/settings-resolver.mjs.map +1 -0
  462. package/dist/session/settings-schema-store.cjs +0 -0
  463. package/dist/session/settings-schema-store.d.cts +72 -0
  464. package/dist/session/settings-schema-store.d.cts.map +1 -0
  465. package/dist/session/settings-schema-store.d.mts +72 -0
  466. package/dist/session/settings-schema-store.d.mts.map +1 -0
  467. package/dist/session/settings-schema-store.mjs +0 -0
  468. package/dist/session/settings-schema-store.mjs.map +1 -0
  469. package/dist/system-mounts/index.cjs +14 -0
  470. package/dist/system-mounts/index.d.cts +6 -0
  471. package/dist/system-mounts/index.d.mts +6 -0
  472. package/dist/system-mounts/index.mjs +6 -0
  473. package/dist/system-mounts/install.cjs +101 -0
  474. package/dist/system-mounts/install.d.cts +36 -0
  475. package/dist/system-mounts/install.d.cts.map +1 -0
  476. package/dist/system-mounts/install.d.mts +37 -0
  477. package/dist/system-mounts/install.d.mts.map +1 -0
  478. package/dist/system-mounts/install.mjs +102 -0
  479. package/dist/system-mounts/install.mjs.map +1 -0
  480. package/dist/system-mounts/installers.cjs +247 -0
  481. package/dist/system-mounts/installers.d.cts +13 -0
  482. package/dist/system-mounts/installers.d.cts.map +1 -0
  483. package/dist/system-mounts/installers.d.mts +14 -0
  484. package/dist/system-mounts/installers.d.mts.map +1 -0
  485. package/dist/system-mounts/installers.mjs +244 -0
  486. package/dist/system-mounts/installers.mjs.map +1 -0
  487. package/dist/system-mounts/lists.cjs +122 -0
  488. package/dist/system-mounts/lists.d.cts +34 -0
  489. package/dist/system-mounts/lists.d.cts.map +1 -0
  490. package/dist/system-mounts/lists.d.mts +34 -0
  491. package/dist/system-mounts/lists.d.mts.map +1 -0
  492. package/dist/system-mounts/lists.mjs +122 -0
  493. package/dist/system-mounts/lists.mjs.map +1 -0
  494. package/dist/system-mounts/types.d.cts +124 -0
  495. package/dist/system-mounts/types.d.cts.map +1 -0
  496. package/dist/system-mounts/types.d.mts +125 -0
  497. package/dist/system-mounts/types.d.mts.map +1 -0
  498. package/dist/system-mounts/validate.cjs +56 -0
  499. package/dist/system-mounts/validate.d.cts +34 -0
  500. package/dist/system-mounts/validate.d.cts.map +1 -0
  501. package/dist/system-mounts/validate.d.mts +34 -0
  502. package/dist/system-mounts/validate.d.mts.map +1 -0
  503. package/dist/system-mounts/validate.mjs +56 -0
  504. package/dist/system-mounts/validate.mjs.map +1 -0
  505. package/dist/terminal-llm.cjs +90 -0
  506. package/dist/terminal-llm.d.cts +50 -0
  507. package/dist/terminal-llm.d.cts.map +1 -0
  508. package/dist/terminal-llm.d.mts +50 -0
  509. package/dist/terminal-llm.d.mts.map +1 -0
  510. package/dist/terminal-llm.mjs +90 -0
  511. package/dist/terminal-llm.mjs.map +1 -0
  512. package/dist/terminal-repl.cjs +371 -0
  513. package/dist/terminal-repl.d.cts +69 -0
  514. package/dist/terminal-repl.d.cts.map +1 -0
  515. package/dist/terminal-repl.d.mts +69 -0
  516. package/dist/terminal-repl.d.mts.map +1 -0
  517. package/dist/terminal-repl.mjs +370 -0
  518. package/dist/terminal-repl.mjs.map +1 -0
  519. package/dist/transport/idle-timer.cjs +136 -0
  520. package/dist/transport/idle-timer.d.cts +92 -0
  521. package/dist/transport/idle-timer.d.cts.map +1 -0
  522. package/dist/transport/idle-timer.d.mts +92 -0
  523. package/dist/transport/idle-timer.d.mts.map +1 -0
  524. package/dist/transport/idle-timer.mjs +132 -0
  525. package/dist/transport/idle-timer.mjs.map +1 -0
  526. package/dist/web-component-dsl.cjs +153 -0
  527. package/dist/web-component-dsl.d.cts +27 -0
  528. package/dist/web-component-dsl.d.cts.map +1 -0
  529. package/dist/web-component-dsl.d.mts +27 -0
  530. package/dist/web-component-dsl.d.mts.map +1 -0
  531. package/dist/web-component-dsl.mjs +152 -0
  532. package/dist/web-component-dsl.mjs.map +1 -0
  533. package/package.json +81 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-resolver.mjs","names":["data"],"sources":["../../src/session/settings-resolver.ts"],"sourcesContent":["/**\n * SettingsResolver — per-session two-level (instance + user) settings cascade.\n *\n * Mounted by `SessionUserAFS` as a third overlay at `/instance/settings` (P2),\n * this provider turns a single flat schema tree into a per-caller cascade:\n *\n * effective(field) = (caller's write-layer value) ?? instanceValue ?? schemaSeed\n *\n * Two physical backing stores feed it (the resolver receives paths RELATIVE to\n * its `/instance/settings` mount and re-prefixes them):\n *\n * instance layer = base.read(\"/instance/settings/<rel>\") ← full wrapper\n * (`{ label, value, scope, options, ... }`) — schema + org default\n * user layer = userProvider.read(\"/settings/<rel>\") ← bare override value\n *\n * Which layer a caller reads/writes is decided ONCE by `resolveWriteLayer(scope)`\n * — the single source of truth shared across read/list/stat (and write/delete in\n * P1) so \"the layer you read == the layer you write\" always holds.\n *\n * Visibility model (design §1.4): `read`/`list` are UNIFORM and caller-agnostic\n * — every path is always readable, the returned *value* follows the cascade.\n * `visible`/`editable` are caller-relative capability HINTS baked into the\n * result (the presentation layer filters on them; they are NOT a read boundary).\n * The only security boundary is `write`/`delete` (role enforcement, P1).\n *\n * LOAD-BEARING ASSUMPTION (must hold): `/instance/settings/**` stores only\n * NON-SECRET org defaults (theme, retention days, domain policy…). Secrets go to\n * the `vault` provider, never here. Because of this, \"read is open to every\n * caller\" leaks nothing — a field a non-admin must never read is a modeling\n * error (it belongs in vault), not a reason to make settings `read` lie.\n *\n * Implemented: pure functions + read/list/stat (P0) + write/delete routing,\n * role enforcement, reset, ifMatch passthrough (P1) + subscribe (P4: dual-layer\n * bridge re-emitting instance/user changes into `/instance/settings/...` for\n * propBind, with origin passthrough for echo suppression).\n */\n\nimport type {\n AFSDeleteOptions,\n AFSDeleteResult,\n AFSEntry,\n AFSEvent,\n AFSEventCallback,\n AFSEventFilter,\n AFSListOptions,\n AFSListResult,\n AFSModule,\n AFSReadOptions,\n AFSReadResult,\n AFSRoot,\n AFSStatOptions,\n AFSStatResult,\n AFSUnsubscribe,\n AFSWriteEntryPayload,\n AFSWriteOptions,\n AFSWriteResult,\n} from \"@aigne/afs\";\nimport { AFSForbiddenError, AFSNotFoundError, makeNsLog } from \"@aigne/afs\";\nimport { joinURL } from \"ufo\";\nimport { cascade } from \"./settings-cascade.js\";\nimport type { SettingsSchemaHandle } from \"./settings-schema-store.js\";\n\nconst log = makeNsLog(\"aos\");\n\n/** Where a field's value is *declared* (the schema-level cascade tag). */\nexport type SettingsScope = \"instance\" | \"user\" | \"shared\";\n/** The physical layer a given caller reads/writes for a scope. */\nexport type SettingsLayer = \"instance\" | \"user\";\n\n/** Root of the instance-layer schema tree on the Small World base. */\nconst INSTANCE_SETTINGS_ROOT = \"/instance/settings\";\n/** Root of the per-user override store on the caller's `/user` backing. */\nconst USER_SETTINGS_ROOT = \"/settings\";\n\n/** Keys that must never be copied out of a parsed wrapper (prototype-pollution + control fields). */\nconst DANGEROUS_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\nconst CONTROL_KEYS = new Set([\n \"value\",\n \"scope\",\n \"source\",\n \"overridden\",\n \"inheritedValue\",\n \"visible\",\n \"editable\",\n]);\n\nexport interface SettingsResolverOptions {\n /** The Small World base (owns `/instance/settings/<rel>` wrapper files). */\n base: AFSRoot;\n /** The caller's per-user provider (`/user` backing), or null for anonymous. */\n userProvider: AFSModule | null;\n /** The caller's role, from `getCallerForSession().role`. Unknown → non-admin. */\n role: string | undefined;\n /** Owning session id — used for event origin tagging in P4. */\n sessionId: string;\n /**\n * Derived schema index handle (settings-layering Phase 1c). When wired, the\n * resolver lazily materializes the blocklet's package-schema scope on first\n * settings access (idempotent, store-side single-flight). Phase 2 makes it\n * the existence/schema source; until then resolution is unchanged.\n */\n schema?: SettingsSchemaHandle | null;\n}\n\n/** Strip dangerous keys from a parsed object (prototype pollution defense). */\nfunction sanitizeObject(obj: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(obj)) {\n if (DANGEROUS_KEYS.has(k)) continue;\n out[k] = v;\n }\n return out;\n}\n\n/**\n * Parse an instance-layer wrapper. Defensive: malformed JSON degrades to a\n * bare `{ value: <raw> }` (scope absent → instance) rather than throwing — a\n * broken file must not take down the whole settings page.\n */\nfunction parseWrapper(raw: unknown): Record<string, unknown> {\n let obj: unknown = raw;\n if (typeof raw === \"string\") {\n try {\n obj = JSON.parse(raw);\n } catch {\n return { value: raw };\n }\n }\n if (obj === null || typeof obj !== \"object\") return { value: obj };\n return sanitizeObject(obj as Record<string, unknown>);\n}\n\nfunction sanitizeScope(s: unknown): SettingsScope {\n return s === \"user\" || s === \"shared\" ? s : \"instance\";\n}\n\n/**\n * Coerce a bare user-override value (read back from the per-user fs backing,\n * which stringifies everything) to the type of the instance default. The schema\n * default is the type oracle: a boolean field's \"false\" → false, a number\n * field's \"7\" → 7. Strings and already-correct types pass through; an\n * un-coercible value is returned as-is rather than fabricating a wrong type.\n */\nfunction coerceToSchemaType(raw: unknown, schemaValue: unknown): unknown {\n if (typeof schemaValue === \"boolean\") {\n if (raw === true || raw === false) return raw;\n if (raw === \"true\") return true;\n if (raw === \"false\") return false;\n return raw;\n }\n if (typeof schemaValue === \"number\") {\n if (typeof raw === \"number\") return raw;\n if (typeof raw === \"string\" && raw.trim() !== \"\") {\n const n = Number(raw);\n if (Number.isFinite(n)) return n;\n }\n return raw;\n }\n return raw; // string / object / null — bare fs storage already round-trips\n}\n\nfunction isNotFound(e: unknown): boolean {\n return (\n e instanceof AFSNotFoundError ||\n (typeof e === \"object\" && e !== null && (e as { code?: string }).code === \"AFS_NOT_FOUND\")\n );\n}\n\nfunction lastSegment(path: string): string {\n return path.split(\"/\").filter(Boolean).pop() ?? \"\";\n}\n\n/**\n * Split a resolver-relative path into the wrapper file part and an optional\n * sub-key. Settings fields are always `<name>.json`; anything before the first\n * `.json` segment is the wrapper, anything after is a key inside it\n * (`value`, `label`, …). No `.json` segment → a structure directory.\n *\n * Segment-based, not raw string slicing (CLAUDE.md path rules).\n */\nfunction splitWrapper(sub: string): { wrapperSub: string | null; subKey?: string } {\n const segs = sub.split(\"/\").filter(Boolean);\n const idx = segs.findIndex((s) => s.endsWith(\".json\"));\n if (idx === -1) return { wrapperSub: null };\n const wrapperSub = joinURL(\"/\", ...segs.slice(0, idx + 1));\n const rest = segs.slice(idx + 1);\n return { wrapperSub, subKey: rest.length ? rest.join(\"/\") : undefined };\n}\n\n/**\n * Map a resolver-relative subscribe path to the two underlying layer paths a\n * propBind subscription must watch (§3.6 dual-layer subscribe). Pure — exported\n * for unit testing (T4.1).\n *\n * A field bind like `/cascade/theme.json/value` maps to:\n * - instancePath: `/instance/settings/cascade/theme.json` (base WRAPPER FILE —\n * instance-layer writes land on the whole wrapper, never the `/value`\n * sub-path, so we must watch the file, not the sub-key)\n * - userPath: `/settings/cascade/theme.json` (user bare-value file)\n *\n * A directory / path-less subscribe (`/cascade`, `/`) has no `.json` segment, so\n * `wrapperSub` is null and we watch the directory itself on both layers. The\n * re-emit path is then derived per-event from the underlying path (see\n * `subscribe()`), not from a fixed field path.\n */\nexport function mapSubscribePaths(relPath: string): {\n instancePath: string;\n userPath: string;\n /** True when relPath addresses a specific wrapper file (vs a directory). */\n isField: boolean;\n} {\n const { wrapperSub } = splitWrapper(relPath);\n const tail = wrapperSub ?? relPath;\n return {\n instancePath: joinURL(INSTANCE_SETTINGS_ROOT, tail),\n userPath: joinURL(USER_SETTINGS_ROOT, tail),\n isField: wrapperSub !== null,\n };\n}\n\ninterface InstanceWrapper {\n /** Sanitized wrapper object (schema + instance default value). */\n inst: Record<string, unknown>;\n /** Resolved scope (D-e: absent/illegal → instance). */\n scope: SettingsScope;\n}\n\n/**\n * On-disk key holding EXPLICIT admin schema-text overrides in a converged\n * (override-only) instance row: `{ value?, overrides?: { label: \"...\", … } }`.\n * The nesting is the legacy/explicit discriminator (settings-layering §2.D):\n * a LEGACY full wrapper carries its schema keys FLAT and is ignored on read\n * (package schema wins — legacy-no-shadow); keys under `overrides` were\n * deliberately written by an admin through `write()` and DO overlay the\n * package schema.\n */\nconst OVERRIDES_KEY = \"overrides\";\n\n/**\n * Per-render snapshot (settings-layering §2.B): built once in `beginRender`,\n * immutable for the render, discarded in `endRender`. The auto-surface walk's\n * list/read traffic resolves against these maps with ZERO extra I/O.\n * All keys are wrapper-relative with a leading slash (`/todo/theme.json`).\n */\ninterface RenderSnapshot {\n /** Parsed package schemas (null when resolving in legacy mode). */\n schemas: Map<string, Record<string, unknown>> | null;\n /** Parsed raw instance rows (legacy full wrappers OR sparse override rows). */\n instance: Map<string, Record<string, unknown>>;\n /** Bare user override values. */\n user: Map<string, unknown>;\n}\n\n/** Everything `read`/`stat`/`write` need to know about one field. */\ninterface FieldData {\n scope: SettingsScope;\n visible: boolean;\n editable: boolean;\n overridden: boolean;\n /** Effective (cascaded) value. */\n eff: unknown;\n /** Render-ready merged wrapper. */\n synth: Record<string, unknown>;\n /** Raw instance row as stored (null when absent). For the write strip. */\n instRow: Record<string, unknown> | null;\n /** True when the field resolved through the derived package schema. */\n fromPackage: boolean;\n}\n\nexport class SettingsResolver implements AFSModule {\n readonly name: string;\n readonly accessMode = \"readwrite\" as const;\n\n private readonly base: AFSRoot;\n private readonly userProvider: AFSModule | null;\n private readonly role: string | undefined;\n private readonly schema: SettingsSchemaHandle | null;\n /** Memoized lazy ingest — at most one ensure() flight per session. */\n private schemaReady: Promise<void> | null = null;\n /**\n * Outcome of the lazy ingest. `ready` = the package declares settings and\n * the derived index is consumable (STORE MODE: existence/schema come from\n * the package index). `empty` = package declares none; `failed` = store\n * unavailable; `unwired` = no handle. All non-`ready` states resolve in\n * LEGACY MODE (instance rows define existence + schema) — the pre-Phase-2\n * behavior, so blocklets without package settings keep working.\n */\n private schemaState: \"unwired\" | \"ready\" | \"empty\" | \"failed\" = \"unwired\";\n /**\n * Active render snapshots, insertion-ordered by `beginRender`. Ops resolve\n * against the MOST RECENTLY begun snapshot (walks are sequential per\n * render; concurrent renders each get their own immutable entry).\n */\n private readonly snapshots = new Map<string, RenderSnapshot>();\n\n constructor(opts: SettingsResolverOptions) {\n this.base = opts.base;\n this.userProvider = opts.userProvider;\n this.role = opts.role;\n this.schema = opts.schema ?? null;\n // sessionId is only needed to label this instance today; P4 re-introduces a\n // stored field when `subscribe` needs it for event origin tagging.\n this.name = `settings-resolver:${opts.sessionId}`;\n }\n\n /**\n * Lazily materialize the package-schema scope (Phase 1c plumbing). Memoized\n * per resolver (per session); the store's own single-flight + completion\n * marker make cross-session work idempotent. BEST-EFFORT in Phase 1: a\n * failed ingest logs and falls back to legacy resolution (Phase 2 will\n * consume the scope for existence/schema and define the hard contract).\n */\n private ensureSchemaIngested(): Promise<void> {\n if (!this.schema) return Promise.resolve();\n this.schemaReady ??= this.schema.ensure().then(\n (result) => {\n this.schemaState = result.fileCount > 0 ? \"ready\" : \"empty\";\n },\n (err) => {\n this.schemaState = \"failed\";\n log.warn(\n `[settings-resolver] schema ingest failed (legacy resolution continues): ${\n err instanceof Error ? err.message : err\n }`,\n );\n },\n );\n return this.schemaReady;\n }\n\n /** STORE MODE — existence/schema from the derived package index (§1.4). */\n private get storeMode(): boolean {\n return this.schemaState === \"ready\";\n }\n\n // ── render snapshot boundary (settings-layering §2.B — Phase 0 contract) ──\n\n /**\n * Begin a render-scoped snapshot. Called by the auto-surface walk entry\n * point (via `SessionUserAFS.beginRender` proxy) with a fresh `renderId`\n * before walking; the resolver builds the WHOLE settings snapshot once\n * (1× derived-index listEntries + instance/user override list + sparse\n * reads) and serves every list/read of that render from memory.\n *\n * Phase 0: contract only — no-op. Phase 2 implements the snapshot builder.\n * Idempotency contract: repeated `beginRender` with the same renderId and\n * `endRender` without a matching begin are both safe no-ops.\n */\n async beginRender(renderId: string): Promise<void> {\n if (this.snapshots.has(renderId)) return; // repeated begin — idempotent\n await this.ensureSchemaIngested();\n\n // Build the whole-page snapshot: 1× schema bulk read + one walk each over\n // the instance/user override trees. Per-source failures degrade to empty\n // maps (a missing override tree is the normal fresh-install state).\n const [schemas, instance, user] = await Promise.all([\n this.storeMode ? this.loadSchemaMap() : Promise.resolve(null),\n this.loadLayerRows(this.base as unknown as AFSModule, INSTANCE_SETTINGS_ROOT, true),\n this.userProvider\n ? this.loadLayerRows(this.userProvider, USER_SETTINGS_ROOT, false)\n : Promise.resolve(new Map<string, unknown>()),\n ]);\n this.snapshots.set(renderId, {\n schemas,\n instance: instance as Map<string, Record<string, unknown>>,\n user,\n });\n }\n\n /** Discard the render snapshot for `renderId`. See {@link beginRender}. */\n endRender(renderId: string): void {\n this.snapshots.delete(renderId); // end-without-begin — safe no-op\n }\n\n /** The snapshot ops resolve against: the most recently begun, still active. */\n private get activeSnapshot(): RenderSnapshot | null {\n let last: RenderSnapshot | null = null;\n for (const snap of this.snapshots.values()) last = snap;\n return last;\n }\n\n /** Bulk-read + parse the derived package schemas (1 store query). */\n private async loadSchemaMap(): Promise<Map<string, Record<string, unknown>>> {\n const map = new Map<string, Record<string, unknown>>();\n if (!this.schema) return map;\n try {\n for (const { path, content } of await this.schema.listSchemas()) {\n map.set(joinURL(\"/\", path), parseWrapper(content));\n }\n } catch (err) {\n log.warn(\n `[settings-resolver] schema bulk read failed: ${err instanceof Error ? err.message : err}`,\n );\n }\n return map;\n }\n\n /**\n * Walk one override layer's tree and read every `.json` row. Sparse by\n * design (converged rows: 0-5); legacy instances pay row-count reads ONCE\n * per render — all in-process, replacing the per-field WS round-trips.\n */\n private async loadLayerRows(\n provider: AFSModule,\n root: string,\n parse: boolean,\n ): Promise<Map<string, unknown>> {\n const map = new Map<string, unknown>();\n if (!provider.list || !provider.read) return map;\n\n const walk = async (dir: string): Promise<void> => {\n let entries: AFSEntry[];\n try {\n entries = (await provider.list?.(dir))?.data ?? [];\n } catch {\n return; // absent layer/dir — normal (fresh install, anonymous user)\n }\n for (const entry of entries) {\n const name = entry.path.split(\"/\").filter(Boolean).pop();\n if (!name || name.startsWith(\".\")) continue;\n const full = joinURL(dir, name);\n if (name.endsWith(\".json\")) {\n try {\n const raw = (await provider.read?.(full))?.data?.content;\n if (raw === undefined) continue;\n map.set(full.slice(root.length), parse ? parseWrapper(raw) : raw);\n } catch {\n // unreadable row — field falls back to non-snapshot semantics\n }\n } else {\n await walk(full);\n }\n }\n };\n await walk(root);\n return map;\n }\n\n // ── §3.0 single source of truth (pure, role/auth-derived) ─────────────────\n\n private get isAuthed(): boolean {\n return this.userProvider != null;\n }\n\n private get isOwnerOrAdmin(): boolean {\n // Fail-closed: any unknown / absent role is treated as a non-admin.\n return this.role === \"owner\" || this.role === \"admin\";\n }\n\n /** The physical layer this caller reads AND writes for the given scope. */\n resolveWriteLayer(scope: SettingsScope): SettingsLayer {\n if (scope === \"instance\") return \"instance\";\n if (scope === \"user\") return \"user\";\n return this.isOwnerOrAdmin ? \"instance\" : \"user\"; // shared (D-a)\n }\n\n /** Presentation hint: should this caller's form render the field at all? */\n visible(scope: SettingsScope): boolean {\n if (scope === \"instance\") return this.isOwnerOrAdmin;\n if (scope === \"user\") return this.isAuthed;\n return true; // shared — anonymous sees it (read-only)\n }\n\n /** Capability hint + (P1) write-enforcement basis: may this caller edit it? */\n editable(scope: SettingsScope): boolean {\n if (scope === \"instance\") return this.isOwnerOrAdmin;\n if (scope === \"user\") return this.isAuthed;\n return this.isAuthed; // shared — anonymous: visible but read-only\n }\n\n // ── path helpers ──────────────────────────────────────────────────────────\n\n /** Normalize an incoming resolver-relative path; reject traversal outright. */\n private normalizeSub(path: string): string {\n const p = path.startsWith(\"/\") ? path : `/${path}`;\n if (p.split(\"/\").some((seg) => seg === \"..\")) {\n throw new AFSForbiddenError(path, \"path traversal rejected\");\n }\n return p;\n }\n\n /** Translate an underlying layer path back into the resolver-relative space. */\n private underlyingToRelative(fullPath: string, layer: SettingsLayer): string {\n const root = layer === \"instance\" ? INSTANCE_SETTINGS_ROOT : USER_SETTINGS_ROOT;\n if (fullPath === root) return \"/\";\n if (fullPath.startsWith(`${root}/`)) return fullPath.slice(root.length);\n return fullPath; // already relative / unexpected — pass through unchanged\n }\n\n // ── instance / user layer access ──────────────────────────────────────────\n\n // base.read / base.stat are optional on AFSRoot — guard once (SessionUserAFS pattern).\n private baseRead(path: string, options?: AFSReadOptions): Promise<AFSReadResult> {\n if (!this.base.read) throw new Error(\"base.read not supported\");\n return this.base.read(path, options);\n }\n\n private baseStat(path: string, options?: AFSStatOptions): Promise<AFSStatResult> {\n if (!this.base.stat) throw new Error(\"base.stat not supported\");\n return this.base.stat(path, options);\n }\n\n private async loadInstanceWrapper(wrapperSub: string): Promise<InstanceWrapper> {\n const instancePath = joinURL(INSTANCE_SETTINGS_ROOT, wrapperSub);\n let raw: unknown;\n try {\n raw = (await this.baseRead(instancePath)).data?.content;\n } catch (e) {\n if (isNotFound(e)) throw new AFSNotFoundError(wrapperSub);\n throw e;\n }\n if (raw === undefined) throw new AFSNotFoundError(wrapperSub);\n const inst = parseWrapper(raw);\n return { inst, scope: sanitizeScope(inst.scope) };\n }\n\n /** Read the caller's bare override value, or undefined when absent/anonymous. */\n private async readUserOverride(wrapperSub: string): Promise<unknown> {\n const snap = this.activeSnapshot;\n if (snap) return this.userProvider ? snap.user.get(wrapperSub) : undefined;\n if (!this.userProvider?.read) return undefined;\n try {\n return (await this.userProvider.read(joinURL(USER_SETTINGS_ROOT, wrapperSub))).data?.content;\n } catch (e) {\n if (isNotFound(e)) return undefined;\n throw e;\n }\n }\n\n // ── three-source field loading (settings-layering §1.2/§2.A/§2.D) ─────────\n\n /** Parsed package schema for a field, or null (store mode only). */\n private async getSchemaWrapper(wrapperSub: string): Promise<Record<string, unknown> | null> {\n const snap = this.activeSnapshot;\n if (snap?.schemas) return snap.schemas.get(wrapperSub) ?? null;\n if (!this.schema) return null;\n const raw = await this.schema.getSchema(wrapperSub);\n return raw === null ? null : parseWrapper(raw);\n }\n\n /** Parsed raw instance row, or null when absent (never throws not-found). */\n private async getInstanceRow(wrapperSub: string): Promise<Record<string, unknown> | null> {\n const snap = this.activeSnapshot;\n if (snap) return (snap.instance.get(wrapperSub) as Record<string, unknown>) ?? null;\n try {\n return (await this.loadInstanceWrapper(wrapperSub)).inst;\n } catch (e) {\n if (isNotFound(e)) return null;\n throw e;\n }\n }\n\n /**\n * Reduce a raw instance row to its OVERRIDE-ONLY contribution (§2.D):\n * `value` (when present) + keys explicitly written under `overrides`.\n * A LEGACY full wrapper's flat schema keys are deliberately dropped —\n * the package schema is authoritative (legacy-no-shadow).\n */\n private stripToOverrideOnly(row: Record<string, unknown> | null): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (!row) return out;\n if (row.value !== undefined) out.value = row.value;\n const ov = row[OVERRIDES_KEY];\n if (ov && typeof ov === \"object\" && !Array.isArray(ov)) {\n for (const [k, v] of Object.entries(ov as Record<string, unknown>)) {\n if (DANGEROUS_KEYS.has(k) || CONTROL_KEYS.has(k) || k === OVERRIDES_KEY) continue;\n out[k] = v;\n }\n }\n return out;\n }\n\n /**\n * Load one field through the cascade. Returns null when the field does not\n * exist — store mode: not in the derived package index (orphan instance\n * rows are IGNORED, §5.4.5); legacy mode: no instance row.\n */\n private async loadField(wrapperSub: string): Promise<FieldData | null> {\n let pkg: Record<string, unknown>;\n let instOverride: Record<string, unknown>;\n let instRow: Record<string, unknown> | null;\n\n if (this.storeMode) {\n const schemaWrapper = await this.getSchemaWrapper(wrapperSub);\n if (!schemaWrapper) return null; // existence comes from the package (§1.4)\n instRow = await this.getInstanceRow(wrapperSub);\n pkg = schemaWrapper;\n instOverride = this.stripToOverrideOnly(instRow);\n } else {\n // LEGACY: the full instance wrapper IS schema + org default in one\n // object — feed it to the cascade as the package layer (byte-compatible\n // with the pre-Phase-2 resolution).\n instRow = await this.getInstanceRow(wrapperSub);\n if (!instRow) return null;\n pkg = instRow;\n instOverride = {};\n }\n\n const scope = sanitizeScope(pkg.scope);\n const layer = this.resolveWriteLayer(scope);\n const rawUser = layer === \"user\" ? await this.readUserOverride(wrapperSub) : undefined;\n // The user layer stores BARE values on fs backings that stringify — coerce\n // against the inherited (pre-user) value, the type oracle (§1.5 note).\n const inherited = instOverride.value !== undefined ? instOverride.value : pkg.value;\n const user =\n rawUser === undefined ? undefined : { value: coerceToSchemaType(rawUser, inherited) };\n\n const eff = cascade(pkg, instOverride, user);\n const overridden = eff.source === \"user\";\n const editable = this.editable(scope);\n const visible = this.visible(scope);\n const synth: Record<string, unknown> = {\n ...eff.synth,\n // Back-compat: the presentation contract is two-way (`user` vs\n // `instance`) — package-default and instance-override both render as\n // \"instance\" provenance, exactly as before.\n source: overridden ? \"user\" : \"instance\",\n editable,\n visible,\n };\n\n return {\n scope,\n visible,\n editable,\n overridden,\n eff: eff.value,\n synth,\n instRow,\n fromPackage: this.storeMode,\n };\n }\n\n /** Opaque version of the layer this caller would write — §3.7. */\n private async writeTargetVersion(\n scope: SettingsScope,\n wrapperSub: string,\n ): Promise<string | undefined> {\n const layer = this.resolveWriteLayer(scope);\n try {\n if (layer === \"instance\") {\n const r = await this.baseStat(joinURL(INSTANCE_SETTINGS_ROOT, wrapperSub));\n return r.data?.meta?.version;\n }\n if (this.userProvider?.stat) {\n const r = await this.userProvider.stat(joinURL(USER_SETTINGS_ROOT, wrapperSub));\n return r.data?.meta?.version;\n }\n } catch (e) {\n if (!isNotFound(e)) throw e; // genuine errors propagate; absence → undefined\n }\n return undefined;\n }\n\n // ── read (uniform, caller-agnostic existence; cascade value) ──────────────\n\n async read(path: string, options?: AFSReadOptions): Promise<AFSReadResult> {\n await this.ensureSchemaIngested();\n const sub = this.normalizeSub(path);\n const { wrapperSub, subKey } = splitWrapper(sub);\n\n if (!wrapperSub) {\n // Structure directory. Store mode: existence is projected from the\n // package index (an instance dir may legitimately not exist yet).\n if (this.storeMode) {\n if (!(await this.dirExists(sub))) throw new AFSNotFoundError(sub);\n return {\n data: {\n id: lastSegment(sub) || \"settings\",\n path: sub,\n content: `Settings directory: ${sub}`,\n meta: { kind: \"directory\" },\n },\n };\n }\n // Legacy — delegate to base, translate path back.\n const instancePath = joinURL(INSTANCE_SETTINGS_ROOT, sub);\n let r: AFSReadResult;\n try {\n r = await this.baseRead(instancePath, options);\n } catch (e) {\n if (isNotFound(e)) throw new AFSNotFoundError(sub);\n throw e;\n }\n if (!r.data) throw new AFSNotFoundError(sub);\n return { data: { ...r.data, path: sub, meta: { ...r.data.meta, kind: \"directory\" } } };\n }\n\n const field = await this.loadField(wrapperSub);\n if (!field) throw new AFSNotFoundError(wrapperSub);\n // The opaque write-target version costs a per-field stat — skipped inside\n // a render snapshot (the bind layer re-stats immediately before every\n // write anyway; rendered trees never consume it).\n const version = this.activeSnapshot\n ? undefined\n : await this.writeTargetVersion(field.scope, wrapperSub);\n const meta = {\n accessMode: field.editable ? \"readwrite\" : \"readonly\",\n visible: field.visible,\n editable: field.editable,\n scope: field.scope,\n version,\n };\n\n if (subKey === undefined) {\n // The whole wrapper, as a BLOB (content = JSON string) — NOT a\n // `kind:json:object` container — so auto-surface's readContent takes the\n // parseContent path, not readSubTree (design §3.1).\n return {\n data: {\n id: lastSegment(wrapperSub),\n path: wrapperSub,\n content: JSON.stringify(field.synth),\n meta,\n },\n };\n }\n // Sub-key read: `value` → effective value; any other key → wrapper field.\n const content = subKey === \"value\" ? field.eff : field.synth[subKey];\n return { data: { id: lastSegment(subKey), path: joinURL(wrapperSub, subKey), content, meta } };\n }\n\n /** Store-mode directory existence: any package field lives under `sub`. */\n private async dirExists(sub: string): Promise<boolean> {\n if (sub === \"/\") return true;\n const prefix = `${sub}/`;\n for (const key of (await this.schemaMap()).keys()) {\n if (key.startsWith(prefix)) return true;\n }\n return false;\n }\n\n /**\n * The full schema map (store mode): from the active snapshot when present,\n * else one bulk store query — replacing the legacy per-field N+1 scope peek.\n */\n private async schemaMap(): Promise<Map<string, Record<string, unknown>>> {\n const snap = this.activeSnapshot;\n if (snap?.schemas) return snap.schemas;\n return this.loadSchemaMap();\n }\n\n // ── list (uniform — all entries, visible/editable hints in meta) ──────────\n\n async list(path: string, options?: AFSListOptions): Promise<AFSListResult> {\n await this.ensureSchemaIngested();\n const sub = this.normalizeSub(path);\n\n // STORE MODE — project the listing from the derived package index (§1.4):\n // existence comes from the package, so an EMPTY (fresh-install) instance\n // tree still yields the full field set; orphan instance rows never appear.\n if (this.storeMode) {\n const schemas = await this.schemaMap();\n const prefix = sub === \"/\" ? \"/\" : `${sub}/`;\n const children = new Map<string, boolean>(); // seg → isDir\n for (const key of schemas.keys()) {\n if (!key.startsWith(prefix)) continue;\n const rest = key.slice(prefix.length);\n const seg = rest.split(\"/\")[0];\n if (!seg) continue;\n children.set(seg, children.get(seg) || rest.includes(\"/\"));\n }\n if (children.size === 0 && sub !== \"/\") {\n throw new AFSNotFoundError(sub);\n }\n const data: AFSEntry[] = [];\n for (const [seg, isDir] of children) {\n const childSub = joinURL(sub, seg);\n if (isDir) {\n data.push({\n id: seg,\n path: childSub,\n meta: { kind: \"directory\", childrenCount: -1 },\n });\n continue;\n }\n const scope = sanitizeScope(schemas.get(childSub)?.scope);\n const editable = this.editable(scope);\n const visible = this.visible(scope);\n data.push({\n id: seg,\n path: childSub,\n meta: {\n accessMode: editable ? \"readwrite\" : \"readonly\",\n scope,\n visible,\n editable,\n },\n });\n }\n return { data };\n }\n\n // LEGACY — delegate to base and decorate (pre-Phase-2 behavior).\n const instanceDir = joinURL(INSTANCE_SETTINGS_ROOT, sub);\n const result = await this.base.list(instanceDir, options);\n const data = await Promise.all(\n (result.data ?? []).map(async (e) => {\n const relPath = this.underlyingToRelative(e.path, \"instance\");\n if (!relPath.endsWith(\".json\")) {\n // Structure directory entry — kind/childrenCount so isDirectoryEntry\n // (auto-surface) classifies it correctly.\n return {\n ...e,\n path: relPath,\n meta: { ...e.meta, kind: \"directory\", childrenCount: e.meta?.childrenCount ?? -1 },\n };\n }\n // Field entry — attach caller-relative visible/editable hints. The\n // scope peek hits the render snapshot when one is active (§2.B);\n // otherwise it is the legacy N+1 read (settings fields are few).\n let scope: SettingsScope = \"instance\";\n try {\n const row = await this.getInstanceRow(relPath);\n if (row) scope = sanitizeScope(row.scope);\n } catch {\n // Unreadable/broken wrapper → fail-closed to instance scope.\n }\n const editable = this.editable(scope);\n const visible = this.visible(scope);\n return {\n ...e,\n path: relPath,\n meta: {\n ...e.meta,\n kind: undefined,\n childrenCount: undefined,\n accessMode: editable ? \"readwrite\" : \"readonly\",\n scope,\n visible,\n editable,\n },\n } as AFSEntry;\n }),\n );\n return { ...result, data };\n }\n\n // ── stat (write-target version + capability hints) ────────────────────────\n\n async stat(path: string, options?: AFSStatOptions): Promise<AFSStatResult> {\n await this.ensureSchemaIngested();\n const sub = this.normalizeSub(path);\n const { wrapperSub, subKey } = splitWrapper(sub);\n\n if (!wrapperSub) {\n if (this.storeMode) {\n if (!(await this.dirExists(sub))) throw new AFSNotFoundError(sub);\n return {\n data: {\n id: lastSegment(sub) || \"settings\",\n path: sub,\n meta: { kind: \"directory\", childrenCount: -1 },\n },\n };\n }\n const instancePath = joinURL(INSTANCE_SETTINGS_ROOT, sub);\n let r: AFSStatResult;\n try {\n r = await this.baseStat(instancePath, options);\n } catch (e) {\n if (isNotFound(e)) throw new AFSNotFoundError(sub);\n throw e;\n }\n if (!r.data) throw new AFSNotFoundError(sub);\n return { data: { ...r.data, path: sub, meta: { ...r.data.meta, kind: \"directory\" } } };\n }\n\n const field = await this.loadField(wrapperSub);\n if (!field) throw new AFSNotFoundError(wrapperSub);\n const version = await this.writeTargetVersion(field.scope, wrapperSub);\n const statPath = subKey ? joinURL(wrapperSub, subKey) : wrapperSub;\n return {\n data: {\n id: lastSegment(statPath),\n path: statPath,\n meta: {\n accessMode: field.editable ? \"readwrite\" : \"readonly\",\n visible: field.visible,\n editable: field.editable,\n scope: field.scope,\n version,\n },\n },\n };\n }\n\n // ── write (scope + role routing; enforcement is the only security boundary) ─\n\n async write(\n path: string,\n content: AFSWriteEntryPayload,\n options?: AFSWriteOptions,\n ): Promise<AFSWriteResult> {\n await this.ensureSchemaIngested();\n const sub = this.normalizeSub(path);\n const { wrapperSub, subKey } = splitWrapper(sub);\n if (!wrapperSub) {\n throw new AFSForbiddenError(\n path,\n \"settings writes must target a field, e.g. .../x.json/value\",\n );\n }\n if (subKey === undefined) {\n throw new AFSForbiddenError(\n path,\n \"settings writes must target a field sub-path (.../x.json/value)\",\n );\n }\n // Validate the field exists — 404 means no auto-create (store mode: the\n // PACKAGE defines existence; legacy: the instance layer does).\n const field = await this.loadField(wrapperSub);\n if (!field) throw new AFSNotFoundError(wrapperSub);\n const ifMatch = options?.ifMatch;\n // Forward the caller's context so the underlying provider tags its\n // `afs:write` event with `origin.sessionId` — the subscribe-bridge (§3.6)\n // relies on this for echo suppression. Dropping it (the P0/P1 shape) made\n // every bridged event origin-less → writers received their own patches.\n const context = options?.context;\n\n // The RMW base for instance-layer writes (§2.D write strip). Store mode:\n // reduce the raw row to override-only FIRST — a legacy full wrapper's\n // copied schema keys are dropped here, so the first write CONVERGES the\n // row to sparse (legacy-first-write-strip) and value writes can never\n // re-create per-instance schema copies (the G0 disaster shape). Steady\n // state (already sparse / fresh) makes the strip a no-op. Legacy mode\n // keeps the full-wrapper RMW — there is no package source to fall back\n // to, so stripping would LOSE the schema.\n const instBase = this.storeMode\n ? this.overrideOnlyDiskShape(field.instRow)\n : (field.instRow ?? {});\n\n if (subKey !== \"value\") {\n // Non-value keys (label, description, options, …) are schema text —\n // editing them is a schema change, owner/admin only. Store mode nests\n // them under `overrides` (the explicit-override discriminator, §2.D);\n // legacy mode keeps the flat wrapper key.\n if (!this.isOwnerOrAdmin) {\n throw new AFSForbiddenError(path, \"editing settings schema requires owner/admin\");\n }\n if (this.storeMode) {\n const prior = (instBase[OVERRIDES_KEY] ?? {}) as Record<string, unknown>;\n return this.writeInstanceWrapper(\n wrapperSub,\n instBase,\n OVERRIDES_KEY,\n { ...prior, [subKey]: content.content },\n { ifMatch, context },\n );\n }\n return this.writeInstanceWrapper(wrapperSub, instBase, subKey, content.content, {\n ifMatch,\n context,\n });\n }\n\n // subKey === \"value\" — routed by the field's write layer.\n if (this.resolveWriteLayer(field.scope) === \"instance\") {\n if (!this.isOwnerOrAdmin) {\n throw new AFSForbiddenError(path, \"instance-scope settings require owner/admin\");\n }\n return this.writeInstanceWrapper(wrapperSub, instBase, \"value\", content.content, {\n ifMatch,\n context,\n });\n }\n // user layer — personal override (bare value).\n if (!this.isAuthed || !this.userProvider?.write) {\n throw new AFSForbiddenError(path, \"sign in to personalize this setting\");\n }\n return this.userProvider.write(\n joinURL(USER_SETTINGS_ROOT, wrapperSub),\n { content: content.content },\n this.writeOptions(ifMatch, context),\n );\n }\n\n /**\n * The ON-DISK override-only shape of an instance row: `{ value?, overrides? }`.\n * Distinct from {@link stripToOverrideOnly} (the flattened READ-side\n * contribution) — this preserves the nested `overrides` object so a write\n * RMW keeps prior explicit schema-text edits.\n */\n private overrideOnlyDiskShape(row: Record<string, unknown> | null): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (!row) return out;\n if (row.value !== undefined) out.value = row.value;\n const ov = row[OVERRIDES_KEY];\n if (ov && typeof ov === \"object\" && !Array.isArray(ov)) out[OVERRIDES_KEY] = ov;\n return out;\n }\n\n /** Assemble write options, omitting empties so providers see a clean shape. */\n private writeOptions(ifMatch?: string, context?: AFSWriteOptions[\"context\"]): AFSWriteOptions {\n const out: AFSWriteOptions = {};\n if (ifMatch != null) out.ifMatch = ifMatch; // \"\" is a valid token — don't drop it\n if (context != null) out.context = context;\n return out;\n }\n\n /**\n * Read-modify-write the FULL instance wrapper so siblings\n * (label/description/options/…) survive — the G0 regression guard. ifMatch\n * (if supplied) is compared by the base provider against the wrapper version;\n * context (if supplied) flows through so the emitted event carries origin.\n */\n private writeInstanceWrapper(\n wrapperSub: string,\n inst: Record<string, unknown>,\n key: string,\n value: unknown,\n opts: { ifMatch?: string; context?: AFSWriteOptions[\"context\"] },\n ): Promise<AFSWriteResult> {\n if (!this.base.write) throw new Error(\"base.write not supported\");\n const next = { ...inst, [key]: value };\n return this.base.write(\n joinURL(INSTANCE_SETTINGS_ROOT, wrapperSub),\n { content: JSON.stringify(next) },\n this.writeOptions(opts.ifMatch, opts.context),\n );\n }\n\n // ── delete (reset = clear personal override; instance is immutable) ────────\n\n async delete(path: string, options?: AFSDeleteOptions): Promise<AFSDeleteResult> {\n await this.ensureSchemaIngested();\n const sub = this.normalizeSub(path);\n const { wrapperSub, subKey } = splitWrapper(sub);\n if (!wrapperSub) throw new AFSForbiddenError(path, \"not a settings field path\");\n if (subKey !== undefined && subKey !== \"value\") {\n throw new AFSForbiddenError(path, \"only a field's value can be reset\");\n }\n const field = await this.loadField(wrapperSub);\n if (!field) throw new AFSNotFoundError(wrapperSub);\n if (this.resolveWriteLayer(field.scope) === \"instance\") {\n throw new AFSForbiddenError(\n path,\n \"instance settings cannot be deleted; admin edits via write\",\n );\n }\n if (!this.isAuthed || !this.userProvider?.delete) {\n throw new AFSForbiddenError(path, \"sign in to reset this setting\");\n }\n return this.userProvider.delete(joinURL(USER_SETTINGS_ROOT, wrapperSub), options);\n }\n\n // ── subscribe (§3.6 dual-layer bridge → propBind reactivity) ──────────────\n\n /**\n * Bridge instance-layer + user-layer change events into the\n * `/instance/settings/...` namespace so propBind can react to a cascade write\n * regardless of which physical layer it landed on.\n *\n * For a FIELD subscription (`/cascade/theme.json/value`):\n * - watch the instance WRAPPER FILE on `base` and the bare-value file on\n * `userProvider` (see `mapSubscribePaths`);\n * - re-emit at the EXACT filter path so the bridged event matches what the\n * subscriber (PropBindSubscriber) asked for — SessionUserAFS then\n * re-prefixes the resolver-relative path back to `/instance/settings/...`.\n *\n * Two invariants make echo suppression + reset work:\n * 1. ORIGIN PASSTHROUGH — `{ ...evt }` preserves `origin.sessionId`, so the\n * writer's own session is filtered out by PropBindSubscriber and a\n * different session still receives the patch. (The underlying write\n * carries origin only because `write()` now forwards `options.context`.)\n * 2. TYPE NORMALIZATION — a user-layer DELETE (reset, D-f) is re-emitted as\n * `afs:write` because, from the cascade's point of view, the effective\n * value changed (reverted to the instance default); subscribers re-read\n * either way. We therefore drop the type filter on the underlying\n * subscription so deletes are not missed.\n */\n subscribe(filter: AFSEventFilter, callback: AFSEventCallback): AFSUnsubscribe {\n const rawPath = typeof filter.path === \"string\" ? filter.path || \"/\" : \"/\";\n const relPath = this.normalizeSub(rawPath); // rejects traversal\n const { instancePath, userPath, isField } = mapSubscribePaths(relPath);\n\n const emit = (evt: AFSEvent, layer: SettingsLayer): void => {\n const path = isField ? relPath : this.underlyingToRelative(evt.path, layer);\n callback({ ...evt, type: \"afs:write\", path });\n };\n\n const unsubs: AFSUnsubscribe[] = [];\n if (this.base.subscribe) {\n unsubs.push(this.base.subscribe({ path: instancePath }, (evt) => emit(evt, \"instance\")));\n }\n if (this.userProvider?.subscribe) {\n unsubs.push(this.userProvider.subscribe({ path: userPath }, (evt) => emit(evt, \"user\")));\n }\n return () => {\n for (const u of unsubs) {\n try {\n u();\n } catch {\n // tolerate downstream unsubscribe errors (provider torn down)\n }\n }\n };\n }\n\n setEventSink(sink: Parameters<NonNullable<AFSModule[\"setEventSink\"]>>[0]): void {\n // Participate in the event system by delegating to the backing stores,\n // exactly as SessionUserAFS does — `subscribe` then bridges the events the\n // backing buses emit. The resolver does NOT self-emit (it forwards origin\n // from the underlying write instead), so there is no sink to capture here.\n this.base.setEventSink?.(sink);\n this.userProvider?.setEventSink?.(sink);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ import { AFSRoot } from "@aigne/afs";
2
+ import { VersionedContentFile } from "@aigne/afs-did-space";
3
+
4
+ //#region src/session/settings-schema-store.d.ts
5
+ /**
6
+ * STRUCTURAL view of `VersionedContentStore` — exactly the three methods this
7
+ * glue consumes. Kept structural (not the concrete class) so runtimes that
8
+ * hold the real class instance from their own `@aigne/afs-did-space` build
9
+ * assign cleanly (the class has private members, which would otherwise pin
10
+ * type identity to one declaration file).
11
+ */
12
+ interface SettingsSchemaStoreLike {
13
+ ensure(opts: {
14
+ scope: string;
15
+ group: string;
16
+ load: () => Promise<VersionedContentFile[] | {
17
+ files: VersionedContentFile[];
18
+ seedDigest?: string;
19
+ }>;
20
+ seedDigest?: string;
21
+ verifyDigest?: boolean;
22
+ force?: boolean;
23
+ }): Promise<{
24
+ built: boolean;
25
+ fileCount: number;
26
+ }>;
27
+ listEntries(scope: string, prefix?: string): Promise<{
28
+ entries: Array<{
29
+ path: string;
30
+ content?: string;
31
+ }>;
32
+ }>;
33
+ get(scope: string, path: string): Promise<string | null>;
34
+ }
35
+ /** Blocklet package identity (`manifest.id` + optional `manifest.version`). */
36
+ interface BlockletPackageIdentity {
37
+ id: string;
38
+ version?: string;
39
+ }
40
+ /** What the SettingsResolver needs from the schema store — nothing more. */
41
+ interface SettingsSchemaHandle {
42
+ /**
43
+ * Materialize the blocklet's schema scope (lazy, idempotent; single-flight
44
+ * inside the store). Resolvers call this before consuming schemas.
45
+ */
46
+ ensure(): Promise<{
47
+ built: boolean;
48
+ fileCount: number;
49
+ }>;
50
+ /** One-query bulk read: every schema row (path relative to settings root). */
51
+ listSchemas(): Promise<Array<{
52
+ path: string;
53
+ content: string;
54
+ }>>;
55
+ /** Single schema row (null when the field does not exist in the package). */
56
+ getSchema(path: string): Promise<string | null>;
57
+ }
58
+ interface CreateSettingsSchemaHandleOptions {
59
+ store: SettingsSchemaStoreLike;
60
+ identity: BlockletPackageIdentity;
61
+ /** The blocklet's runtime AFS (must project `/packages`). */
62
+ base: AFSRoot;
63
+ /**
64
+ * Dev mode: recompute the seed digest every ensure and rebuild on drift
65
+ * (changed seed without a version bump). Prod default: off.
66
+ */
67
+ verifyDigest?: boolean;
68
+ }
69
+ declare function createSettingsSchemaHandle(opts: CreateSettingsSchemaHandleOptions): SettingsSchemaHandle;
70
+ //#endregion
71
+ export { BlockletPackageIdentity, CreateSettingsSchemaHandleOptions, SettingsSchemaHandle, SettingsSchemaStoreLike, createSettingsSchemaHandle };
72
+ //# sourceMappingURL=settings-schema-store.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-schema-store.d.cts","names":[],"sources":["../../src/session/settings-schema-store.ts"],"mappings":";;;;;;;;;;;UAkCiB,uBAAA;EACf,MAAA,CAAO,IAAA;IACL,KAAA;IACA,KAAA;IACA,IAAA,QAAY,OAAA,CACV,oBAAA;MAA2B,KAAA,EAAO,oBAAA;MAAwB,UAAA;IAAA;IAE5D,UAAA;IACA,YAAA;IACA,KAAA;EAAA,IACE,OAAA;IAAU,KAAA;IAAgB,SAAA;EAAA;EAC9B,WAAA,CACE,KAAA,UACA,MAAA,YACC,OAAA;IAAU,OAAA,EAAS,KAAA;MAAQ,IAAA;MAAc,OAAA;IAAA;EAAA;EAC5C,GAAA,CAAI,KAAA,UAAe,IAAA,WAAe,OAAA;AAAA;;UAQnB,uBAAA;EACf,EAAA;EACA,OAAA;AAAA;;UAIe,oBAAA;EAKf;;;;EAAA,MAAA,IAAU,OAAA;IAAU,KAAA;IAAgB,SAAA;EAAA;EAES;EAA7C,WAAA,IAAe,OAAA,CAAQ,KAAA;IAAQ,IAAA;IAAc,OAAA;EAAA;EAEb;EAAhC,SAAA,CAAU,IAAA,WAAe,OAAA;AAAA;AAAA,UAGV,iCAAA;EACf,KAAA,EAAO,uBAAA;EACP,QAAA,EAAU,uBAAA;EAEJ;EAAN,IAAA,EAAM,OAAA;EAAO;;;;EAKb,YAAA;AAAA;AAAA,iBA6Dc,0BAAA,CACd,IAAA,EAAM,iCAAA,GACL,oBAAA"}
@@ -0,0 +1,72 @@
1
+ import { AFSRoot } from "@aigne/afs";
2
+ import { VersionedContentFile } from "@aigne/afs-did-space";
3
+
4
+ //#region src/session/settings-schema-store.d.ts
5
+ /**
6
+ * STRUCTURAL view of `VersionedContentStore` — exactly the three methods this
7
+ * glue consumes. Kept structural (not the concrete class) so runtimes that
8
+ * hold the real class instance from their own `@aigne/afs-did-space` build
9
+ * assign cleanly (the class has private members, which would otherwise pin
10
+ * type identity to one declaration file).
11
+ */
12
+ interface SettingsSchemaStoreLike {
13
+ ensure(opts: {
14
+ scope: string;
15
+ group: string;
16
+ load: () => Promise<VersionedContentFile[] | {
17
+ files: VersionedContentFile[];
18
+ seedDigest?: string;
19
+ }>;
20
+ seedDigest?: string;
21
+ verifyDigest?: boolean;
22
+ force?: boolean;
23
+ }): Promise<{
24
+ built: boolean;
25
+ fileCount: number;
26
+ }>;
27
+ listEntries(scope: string, prefix?: string): Promise<{
28
+ entries: Array<{
29
+ path: string;
30
+ content?: string;
31
+ }>;
32
+ }>;
33
+ get(scope: string, path: string): Promise<string | null>;
34
+ }
35
+ /** Blocklet package identity (`manifest.id` + optional `manifest.version`). */
36
+ interface BlockletPackageIdentity {
37
+ id: string;
38
+ version?: string;
39
+ }
40
+ /** What the SettingsResolver needs from the schema store — nothing more. */
41
+ interface SettingsSchemaHandle {
42
+ /**
43
+ * Materialize the blocklet's schema scope (lazy, idempotent; single-flight
44
+ * inside the store). Resolvers call this before consuming schemas.
45
+ */
46
+ ensure(): Promise<{
47
+ built: boolean;
48
+ fileCount: number;
49
+ }>;
50
+ /** One-query bulk read: every schema row (path relative to settings root). */
51
+ listSchemas(): Promise<Array<{
52
+ path: string;
53
+ content: string;
54
+ }>>;
55
+ /** Single schema row (null when the field does not exist in the package). */
56
+ getSchema(path: string): Promise<string | null>;
57
+ }
58
+ interface CreateSettingsSchemaHandleOptions {
59
+ store: SettingsSchemaStoreLike;
60
+ identity: BlockletPackageIdentity;
61
+ /** The blocklet's runtime AFS (must project `/packages`). */
62
+ base: AFSRoot;
63
+ /**
64
+ * Dev mode: recompute the seed digest every ensure and rebuild on drift
65
+ * (changed seed without a version bump). Prod default: off.
66
+ */
67
+ verifyDigest?: boolean;
68
+ }
69
+ declare function createSettingsSchemaHandle(opts: CreateSettingsSchemaHandleOptions): SettingsSchemaHandle;
70
+ //#endregion
71
+ export { BlockletPackageIdentity, CreateSettingsSchemaHandleOptions, SettingsSchemaHandle, SettingsSchemaStoreLike, createSettingsSchemaHandle };
72
+ //# sourceMappingURL=settings-schema-store.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-schema-store.d.mts","names":[],"sources":["../../src/session/settings-schema-store.ts"],"mappings":";;;;;;;;;;;UAkCiB,uBAAA;EACf,MAAA,CAAO,IAAA;IACL,KAAA;IACA,KAAA;IACA,IAAA,QAAY,OAAA,CACV,oBAAA;MAA2B,KAAA,EAAO,oBAAA;MAAwB,UAAA;IAAA;IAE5D,UAAA;IACA,YAAA;IACA,KAAA;EAAA,IACE,OAAA;IAAU,KAAA;IAAgB,SAAA;EAAA;EAC9B,WAAA,CACE,KAAA,UACA,MAAA,YACC,OAAA;IAAU,OAAA,EAAS,KAAA;MAAQ,IAAA;MAAc,OAAA;IAAA;EAAA;EAC5C,GAAA,CAAI,KAAA,UAAe,IAAA,WAAe,OAAA;AAAA;;UAQnB,uBAAA;EACf,EAAA;EACA,OAAA;AAAA;;UAIe,oBAAA;EAKf;;;;EAAA,MAAA,IAAU,OAAA;IAAU,KAAA;IAAgB,SAAA;EAAA;EAES;EAA7C,WAAA,IAAe,OAAA,CAAQ,KAAA;IAAQ,IAAA;IAAc,OAAA;EAAA;EAEb;EAAhC,SAAA,CAAU,IAAA,WAAe,OAAA;AAAA;AAAA,UAGV,iCAAA;EACf,KAAA,EAAO,uBAAA;EACP,QAAA,EAAU,uBAAA;EAEJ;EAAN,IAAA,EAAM,OAAA;EAAO;;;;EAKb,YAAA;AAAA;AAAA,iBA6Dc,0BAAA,CACd,IAAA,EAAM,iCAAA,GACL,oBAAA"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-schema-store.mjs","names":[],"sources":["../../src/session/settings-schema-store.ts"],"sourcesContent":["/**\n * Settings schema handle — the SETTINGS consumer of the generic versioned\n * content store (settings-layering §1.6 / Layer 2 glue).\n *\n * Maps a blocklet's authored seed settings (`/packages/seed/settings/**`,\n * read VIA AFS — never the filesystem) into the kind-agnostic\n * `VersionedContentStore` under `kind=\"schema\"`:\n *\n * scope = schema:<manifest.id>:<versionToken>\n * versionToken = manifest.version, else the seed-content digest\n *\n * Digest discipline (§1.6): prod NEVER computes a digest on the read path —\n * the scope key (id + version) is the immutability guarantee, and the digest\n * is computed once at ingest and stored as scope metadata. Dev mode\n * (`verifyDigest`) recomputes from source each ensure to catch\n * changed-seed-same-version packages, at dev-only cost.\n *\n * The handle is pre-bound to one blocklet + one base AFS, so consumers\n * (SettingsResolver via createSessionView) hold a zero-knowledge interface:\n * `ensure()` + `listSchemas()` + `getSchema(path)`.\n */\n\nimport type { AFSEntry, AFSRoot } from \"@aigne/afs\";\nimport type { VersionedContentFile } from \"@aigne/afs-did-space\";\nimport { resolveVersionToken, versionedScope, versionedScopeGroup } from \"@aigne/afs-did-space\";\nimport { joinURL } from \"ufo\";\n\n/**\n * STRUCTURAL view of `VersionedContentStore` — exactly the three methods this\n * glue consumes. Kept structural (not the concrete class) so runtimes that\n * hold the real class instance from their own `@aigne/afs-did-space` build\n * assign cleanly (the class has private members, which would otherwise pin\n * type identity to one declaration file).\n */\nexport interface SettingsSchemaStoreLike {\n ensure(opts: {\n scope: string;\n group: string;\n load: () => Promise<\n VersionedContentFile[] | { files: VersionedContentFile[]; seedDigest?: string }\n >;\n seedDigest?: string;\n verifyDigest?: boolean;\n force?: boolean;\n }): Promise<{ built: boolean; fileCount: number }>;\n listEntries(\n scope: string,\n prefix?: string,\n ): Promise<{ entries: Array<{ path: string; content?: string }> }>;\n get(scope: string, path: string): Promise<string | null>;\n}\n\n/** Where blocklet authors put settings wrappers inside the package. */\nconst SEED_SETTINGS_ROOT = \"/packages/seed/settings\";\nconst SETTINGS_SCHEMA_KIND = \"schema\";\n\n/** Blocklet package identity (`manifest.id` + optional `manifest.version`). */\nexport interface BlockletPackageIdentity {\n id: string;\n version?: string;\n}\n\n/** What the SettingsResolver needs from the schema store — nothing more. */\nexport interface SettingsSchemaHandle {\n /**\n * Materialize the blocklet's schema scope (lazy, idempotent; single-flight\n * inside the store). Resolvers call this before consuming schemas.\n */\n ensure(): Promise<{ built: boolean; fileCount: number }>;\n /** One-query bulk read: every schema row (path relative to settings root). */\n listSchemas(): Promise<Array<{ path: string; content: string }>>;\n /** Single schema row (null when the field does not exist in the package). */\n getSchema(path: string): Promise<string | null>;\n}\n\nexport interface CreateSettingsSchemaHandleOptions {\n store: SettingsSchemaStoreLike;\n identity: BlockletPackageIdentity;\n /** The blocklet's runtime AFS (must project `/packages`). */\n base: AFSRoot;\n /**\n * Dev mode: recompute the seed digest every ensure and rebuild on drift\n * (changed seed without a version bump). Prod default: off.\n */\n verifyDigest?: boolean;\n}\n\n/** SHA-256 hex over the sorted (path, content) pairs — the seed fingerprint. */\nasync function computeSeedDigest(files: readonly VersionedContentFile[]): Promise<string> {\n const canonical = [...files]\n .sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0))\n .map((f) => `${f.path}\u0000${f.content}\u0000`)\n .join(\"\");\n const bytes = new TextEncoder().encode(canonical);\n const hash = await crypto.subtle.digest(\"SHA-256\", bytes);\n return [...new Uint8Array(hash)].map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nfunction isDirectoryEntry(entry: AFSEntry): boolean {\n const meta = entry.meta ?? {};\n return (\n meta.kind === \"fs:directory\" ||\n meta.kind === \"directory\" ||\n (Array.isArray(meta.kinds) && meta.kinds.includes(\"fs:directory\")) ||\n typeof meta.childrenCount === \"number\"\n );\n}\n\n/** Recursively read every file under the seed settings root — VIA AFS. */\nasync function loadSeedSettingsFiles(base: AFSRoot): Promise<VersionedContentFile[]> {\n const files: VersionedContentFile[] = [];\n\n async function walk(dir: string): Promise<void> {\n let entries: AFSEntry[];\n try {\n entries = (await base.list(dir)).data ?? [];\n } catch {\n return; // no settings/ in the package — empty scope is legal\n }\n for (const entry of entries) {\n const name = entry.path.split(\"/\").filter(Boolean).pop();\n if (!name || name.startsWith(\".\")) continue;\n const full = joinURL(dir, name);\n if (isDirectoryEntry(entry)) {\n await walk(full);\n continue;\n }\n if (!base.read) continue;\n try {\n const raw = (await base.read(full)).data?.content;\n const content =\n typeof raw === \"string\" ? raw : raw === undefined ? undefined : JSON.stringify(raw);\n if (content === undefined) continue;\n files.push({ path: full.slice(`${SEED_SETTINGS_ROOT}/`.length), content });\n } catch {\n // unreadable seed file — skip (a broken file must not block the scope;\n // the resolver will surface the field's absence instead)\n }\n }\n }\n\n await walk(SEED_SETTINGS_ROOT);\n return files;\n}\n\nexport function createSettingsSchemaHandle(\n opts: CreateSettingsSchemaHandleOptions,\n): SettingsSchemaHandle {\n const { store, identity, base, verifyDigest = false } = opts;\n const group = versionedScopeGroup(SETTINGS_SCHEMA_KIND, identity.id);\n\n /** Resolved once per handle — version-keyed scope, or digest-keyed for unversioned packages. */\n let scopePromise: Promise<{ scope: string; files?: VersionedContentFile[]; digest?: string }>;\n\n function resolveScope() {\n scopePromise ??= (async () => {\n if (identity.version && !verifyDigest) {\n // Prod hot path: exact key, no digest, no source I/O.\n return { scope: versionedScope(SETTINGS_SCHEMA_KIND, identity.id, identity.version) };\n }\n // Unversioned package or dev verification — the digest IS needed, which\n // requires loading the source once per handle (per session).\n const files = await loadSeedSettingsFiles(base);\n const digest = await computeSeedDigest(files);\n const token = resolveVersionToken(identity, digest);\n return { scope: versionedScope(SETTINGS_SCHEMA_KIND, identity.id, token), files, digest };\n })();\n return scopePromise;\n }\n\n return {\n async ensure() {\n const { scope, files, digest } = await resolveScope();\n return store.ensure({\n scope,\n group,\n seedDigest: digest,\n verifyDigest,\n load: async () => {\n const loaded = files ?? (await loadSeedSettingsFiles(base));\n return { files: loaded, seedDigest: digest ?? (await computeSeedDigest(loaded)) };\n },\n });\n },\n async listSchemas() {\n const { scope } = await resolveScope();\n const result = await store.listEntries(scope);\n return result.entries\n .filter((e) => e.content !== undefined)\n .map((e) => ({ path: e.path, content: e.content as string }));\n },\n async getSchema(path: string) {\n const { scope } = await resolveScope();\n return store.get(scope, path.startsWith(\"/\") ? path.slice(1) : path);\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ const require_installers = require('./installers.cjs');
2
+ const require_lists = require('./lists.cjs');
3
+ const require_validate = require('./validate.cjs');
4
+ const require_install = require('./install.cjs');
5
+
6
+ exports.SMALL_WORLD_PROJECTION = require_lists.SMALL_WORLD_PROJECTION;
7
+ exports.SYSTEM_MOUNTS = require_lists.SYSTEM_MOUNTS;
8
+ exports.aiInstall = require_installers.aiInstall;
9
+ exports.chainInstall = require_installers.chainInstall;
10
+ exports.deviceInstall = require_installers.deviceInstall;
11
+ exports.installSystemMounts = require_install.installSystemMounts;
12
+ exports.messagingInstall = require_installers.messagingInstall;
13
+ exports.observabilityInstall = require_installers.observabilityInstall;
14
+ exports.validateDescriptor = require_validate.validateDescriptor;
@@ -0,0 +1,6 @@
1
+ import { InstallOutcome, SmallWorldProjection, SystemMountContext, SystemMountDescriptor } from "./types.cjs";
2
+ import { InstallSystemMountsResult, installSystemMounts } from "./install.cjs";
3
+ import { aiInstall, chainInstall, deviceInstall, messagingInstall, observabilityInstall } from "./installers.cjs";
4
+ import { SMALL_WORLD_PROJECTION, SYSTEM_MOUNTS } from "./lists.cjs";
5
+ import { ValidateResult, validateDescriptor } from "./validate.cjs";
6
+ export { type InstallOutcome, type InstallSystemMountsResult, SMALL_WORLD_PROJECTION, SYSTEM_MOUNTS, type SmallWorldProjection, type SystemMountContext, type SystemMountDescriptor, type ValidateResult, aiInstall, chainInstall, deviceInstall, installSystemMounts, messagingInstall, observabilityInstall, validateDescriptor };
@@ -0,0 +1,6 @@
1
+ import { InstallOutcome, SmallWorldProjection, SystemMountContext, SystemMountDescriptor } from "./types.mjs";
2
+ import { InstallSystemMountsResult, installSystemMounts } from "./install.mjs";
3
+ import { aiInstall, chainInstall, deviceInstall, messagingInstall, observabilityInstall } from "./installers.mjs";
4
+ import { SMALL_WORLD_PROJECTION, SYSTEM_MOUNTS } from "./lists.mjs";
5
+ import { ValidateResult, validateDescriptor } from "./validate.mjs";
6
+ export { type InstallOutcome, type InstallSystemMountsResult, SMALL_WORLD_PROJECTION, SYSTEM_MOUNTS, type SmallWorldProjection, type SystemMountContext, type SystemMountDescriptor, type ValidateResult, aiInstall, chainInstall, deviceInstall, installSystemMounts, messagingInstall, observabilityInstall, validateDescriptor };
@@ -0,0 +1,6 @@
1
+ import { aiInstall, chainInstall, deviceInstall, messagingInstall, observabilityInstall } from "./installers.mjs";
2
+ import { SMALL_WORLD_PROJECTION, SYSTEM_MOUNTS } from "./lists.mjs";
3
+ import { validateDescriptor } from "./validate.mjs";
4
+ import { installSystemMounts } from "./install.mjs";
5
+
6
+ export { SMALL_WORLD_PROJECTION, SYSTEM_MOUNTS, aiInstall, chainInstall, deviceInstall, installSystemMounts, messagingInstall, observabilityInstall, validateDescriptor };
@@ -0,0 +1,101 @@
1
+ const require_materializer = require('../mount/materializer.cjs');
2
+ const require_aup_projector = require('../projectors/aup-projector.cjs');
3
+ const require_lists = require('./lists.cjs');
4
+ const require_validate = require('./validate.cjs');
5
+ let _aigne_afs_timing = require("@aigne/afs-timing");
6
+
7
+ //#region src/system-mounts/install.ts
8
+ function hasMount(afs, path) {
9
+ const getMounts = afs.getMounts;
10
+ if (typeof getMounts !== "function") return false;
11
+ return getMounts.call(afs).some((m) => m.path === path);
12
+ }
13
+ /**
14
+ * Per-descriptor Server-Timing key so cold-start cost is attributable to a
15
+ * single system device (`mnt.dev.chain`, `mnt.dev.ai`, …) instead of hiding
16
+ * inside the aggregate `op.prov`. Slashes → dots to keep the metric name a
17
+ * valid Server-Timing token. Diagnostic only — `time()` is a no-op when no
18
+ * TimingCollector is active on the ALS.
19
+ */
20
+ const mntKey = (path) => `mnt${path.replace(/\//g, ".")}`;
21
+ /**
22
+ * Install the system mounts described by `descriptors` (defaults to the
23
+ * shared {@link SYSTEM_MOUNTS}) onto `afs`.
24
+ *
25
+ * Per descriptor, in `order`:
26
+ * 1. {@link validateDescriptor} — invalid → skip + warning (path/`..`/proto
27
+ * pollution caught here, reusing the Phase 0 guard).
28
+ * 2. `conditional(ctx) === false` → skip.
29
+ * 3. `install` present → call it (composite hatch owns its own mounts +
30
+ * idempotency + degradation). A throw propagates — chain config errors
31
+ * stay fatal, matching the legacy daemon. Other hatches catch internally.
32
+ * 4. else `registry[providerKey]` absent → skip (this is how CF gets a
33
+ * subset without a control-flow fork).
34
+ * 5. else already mounted → skip (idempotent).
35
+ * 6. else `materializeProviderMount` with the AUP projector. A materialize
36
+ * failure degrades to a warning (matches legacy ash/agent/index, which
37
+ * were individually non-fatal).
38
+ */
39
+ async function installSystemMounts(afs, registry, ctx, descriptors = require_lists.SYSTEM_MOUNTS) {
40
+ const mounted = [];
41
+ const skipped = [];
42
+ const warnings = [];
43
+ const ordered = [...descriptors].sort((a, b) => a.order - b.order);
44
+ for (const descriptor of ordered) {
45
+ const validation = require_validate.validateDescriptor(descriptor);
46
+ if (!validation.ok) {
47
+ const label = descriptor?.path ?? "<unknown>";
48
+ warnings.push(`${label}: invalid descriptor — ${validation.errors.join("; ")}`);
49
+ skipped.push(String(label));
50
+ continue;
51
+ }
52
+ if (descriptor.install) {
53
+ const outcome = await (0, _aigne_afs_timing.time)(mntKey(descriptor.path), () => descriptor.install(afs, ctx, registry));
54
+ mounted.push(...outcome.mounted);
55
+ warnings.push(...outcome.warnings);
56
+ continue;
57
+ }
58
+ const factory = registry[descriptor.providerKey];
59
+ if (!factory) {
60
+ skipped.push(descriptor.path);
61
+ continue;
62
+ }
63
+ if (descriptor.conditional && !descriptor.conditional(ctx)) {
64
+ skipped.push(descriptor.path);
65
+ continue;
66
+ }
67
+ if (hasMount(afs, descriptor.path)) {
68
+ skipped.push(descriptor.path);
69
+ continue;
70
+ }
71
+ const options = typeof descriptor.options === "function" ? descriptor.options(ctx) : descriptor.options;
72
+ try {
73
+ await (0, _aigne_afs_timing.time)(mntKey(descriptor.path), () => require_materializer.materializeProviderMount({
74
+ afs,
75
+ mountPath: descriptor.path,
76
+ definition: {
77
+ uri: `${descriptor.providerKey}://system${descriptor.path}`,
78
+ type: descriptor.providerKey,
79
+ ...options !== void 0 ? { options } : {}
80
+ },
81
+ factory,
82
+ projectors: [require_aup_projector.aupResourceProjector],
83
+ scope: "host",
84
+ ...descriptor.mountOptions ? { mountOptions: descriptor.mountOptions } : {},
85
+ projectionFailure: descriptor.projectionFailure ?? "warn"
86
+ }));
87
+ mounted.push(descriptor.path);
88
+ } catch (err) {
89
+ warnings.push(`${descriptor.path}: mount failed — ${require_materializer.redactError(err)}`);
90
+ skipped.push(descriptor.path);
91
+ }
92
+ }
93
+ return {
94
+ mounted,
95
+ skipped,
96
+ warnings
97
+ };
98
+ }
99
+
100
+ //#endregion
101
+ exports.installSystemMounts = installSystemMounts;
@@ -0,0 +1,36 @@
1
+ import { ProviderFactory } from "../mount/types.cjs";
2
+ import { SystemMountContext, SystemMountDescriptor } from "./types.cjs";
3
+ import { AFSRoot } from "@aigne/afs";
4
+
5
+ //#region src/system-mounts/install.d.ts
6
+ /** Aggregate result of an {@link installSystemMounts} run. */
7
+ interface InstallSystemMountsResult {
8
+ /** Every path actually mounted (across default + install-hatch entries). */
9
+ mounted: string[];
10
+ /** Descriptor paths that were intentionally skipped (missing key, conditional, invalid). */
11
+ skipped: string[];
12
+ /** Non-fatal failures, prefixed with the offending path. */
13
+ warnings: string[];
14
+ }
15
+ /**
16
+ * Install the system mounts described by `descriptors` (defaults to the
17
+ * shared {@link SYSTEM_MOUNTS}) onto `afs`.
18
+ *
19
+ * Per descriptor, in `order`:
20
+ * 1. {@link validateDescriptor} — invalid → skip + warning (path/`..`/proto
21
+ * pollution caught here, reusing the Phase 0 guard).
22
+ * 2. `conditional(ctx) === false` → skip.
23
+ * 3. `install` present → call it (composite hatch owns its own mounts +
24
+ * idempotency + degradation). A throw propagates — chain config errors
25
+ * stay fatal, matching the legacy daemon. Other hatches catch internally.
26
+ * 4. else `registry[providerKey]` absent → skip (this is how CF gets a
27
+ * subset without a control-flow fork).
28
+ * 5. else already mounted → skip (idempotent).
29
+ * 6. else `materializeProviderMount` with the AUP projector. A materialize
30
+ * failure degrades to a warning (matches legacy ash/agent/index, which
31
+ * were individually non-fatal).
32
+ */
33
+ declare function installSystemMounts(afs: AFSRoot, registry: Record<string, ProviderFactory>, ctx: SystemMountContext, descriptors?: readonly SystemMountDescriptor[]): Promise<InstallSystemMountsResult>;
34
+ //#endregion
35
+ export { InstallSystemMountsResult, installSystemMounts };
36
+ //# sourceMappingURL=install.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.cts","names":[],"sources":["../../src/system-mounts/install.ts"],"mappings":";;;;;;UAuBiB,yBAAA;EA4CU;EA1CzB,OAAA;EA2CK;EAzCL,OAAA;EA2CS;EAzCT,QAAA;AAAA;;;;;;;;;;;;;;;;;;;iBAoCoB,mBAAA,CACpB,GAAA,EAAK,OAAA,EACL,QAAA,EAAU,MAAA,SAAe,eAAA,GACzB,GAAA,EAAK,kBAAA,EACL,WAAA,YAAsB,qBAAA,KACrB,OAAA,CAAQ,yBAAA"}
@@ -0,0 +1,37 @@
1
+ import { ProviderFactory } from "../mount/types.mjs";
2
+ import "../mount/index.mjs";
3
+ import { SystemMountContext, SystemMountDescriptor } from "./types.mjs";
4
+ import { AFSRoot } from "@aigne/afs";
5
+
6
+ //#region src/system-mounts/install.d.ts
7
+ /** Aggregate result of an {@link installSystemMounts} run. */
8
+ interface InstallSystemMountsResult {
9
+ /** Every path actually mounted (across default + install-hatch entries). */
10
+ mounted: string[];
11
+ /** Descriptor paths that were intentionally skipped (missing key, conditional, invalid). */
12
+ skipped: string[];
13
+ /** Non-fatal failures, prefixed with the offending path. */
14
+ warnings: string[];
15
+ }
16
+ /**
17
+ * Install the system mounts described by `descriptors` (defaults to the
18
+ * shared {@link SYSTEM_MOUNTS}) onto `afs`.
19
+ *
20
+ * Per descriptor, in `order`:
21
+ * 1. {@link validateDescriptor} — invalid → skip + warning (path/`..`/proto
22
+ * pollution caught here, reusing the Phase 0 guard).
23
+ * 2. `conditional(ctx) === false` → skip.
24
+ * 3. `install` present → call it (composite hatch owns its own mounts +
25
+ * idempotency + degradation). A throw propagates — chain config errors
26
+ * stay fatal, matching the legacy daemon. Other hatches catch internally.
27
+ * 4. else `registry[providerKey]` absent → skip (this is how CF gets a
28
+ * subset without a control-flow fork).
29
+ * 5. else already mounted → skip (idempotent).
30
+ * 6. else `materializeProviderMount` with the AUP projector. A materialize
31
+ * failure degrades to a warning (matches legacy ash/agent/index, which
32
+ * were individually non-fatal).
33
+ */
34
+ declare function installSystemMounts(afs: AFSRoot, registry: Record<string, ProviderFactory>, ctx: SystemMountContext, descriptors?: readonly SystemMountDescriptor[]): Promise<InstallSystemMountsResult>;
35
+ //#endregion
36
+ export { InstallSystemMountsResult, installSystemMounts };
37
+ //# sourceMappingURL=install.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.mts","names":[],"sources":["../../src/system-mounts/install.ts"],"mappings":";;;;;;;UAuBiB,yBAAA;EA2CV;EAzCL,OAAA;EA0CU;EAxCV,OAAA;EA0CsB;EAxCtB,QAAA;AAAA;;;;;;;;;;;;;;;;;;;iBAoCoB,mBAAA,CACpB,GAAA,EAAK,OAAA,EACL,QAAA,EAAU,MAAA,SAAe,eAAA,GACzB,GAAA,EAAK,kBAAA,EACL,WAAA,YAAsB,qBAAA,KACrB,OAAA,CAAQ,yBAAA"}