aimeat 3.2.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (507) hide show
  1. package/dist/.env.example +58 -1
  2. package/dist/build-stamp.json +4 -4
  3. package/dist/locales/en.json +41 -1
  4. package/dist/locales/es.json +41 -1
  5. package/dist/locales/fi.json +43 -3
  6. package/dist/public/changelog.json +12 -0
  7. package/dist/public/css/views/chat.css +388 -0
  8. package/dist/public/js/services/chat.js +190 -0
  9. package/dist/public/js/services/speech-reader.js +26 -0
  10. package/dist/public/lib/VENDORED.md +1 -0
  11. package/dist/public/lib/duckdb-wasm@1.32.0/duckdb-browser-eh.worker.js +14 -0
  12. package/dist/public/lib/duckdb-wasm@1.32.0/duckdb-browser.js +23 -0
  13. package/dist/public/lib/duckdb-wasm@1.32.0/duckdb-eh.wasm +0 -0
  14. package/dist/public/lib/duckdb-wasm@1.32.0/extensions/v1.4.3/wasm_eh/parquet.duckdb_extension.wasm +0 -0
  15. package/dist/public/lib/vendored-assets.json +19 -0
  16. package/dist/public/llms-full-template.txt +2706 -0
  17. package/dist/public/llms-index-template.txt +60 -0
  18. package/dist/public/robots.node.txt +64 -23
  19. package/dist/public/spa.html +8 -1
  20. package/dist/public/views/chat/parts.js +257 -0
  21. package/dist/public/views/chat.js +327 -0
  22. package/dist/public/views/landing.js +24 -1
  23. package/dist/public/views/profile/agents/scope-model.js +320 -315
  24. package/dist/scripts/audit-mcp-schemas.js +41 -0
  25. package/dist/scripts/audit-mcp-schemas.js.map +1 -1
  26. package/dist/scripts/build-sdk-libs.d.ts.map +1 -1
  27. package/dist/scripts/build-sdk-libs.js +1 -0
  28. package/dist/scripts/build-sdk-libs.js.map +1 -1
  29. package/dist/scripts/check-ai-disclosure.js +11 -0
  30. package/dist/scripts/check-ai-disclosure.js.map +1 -1
  31. package/dist/scripts/check-denial-coverage.d.ts +29 -0
  32. package/dist/scripts/check-denial-coverage.d.ts.map +1 -0
  33. package/dist/scripts/check-denial-coverage.js +237 -0
  34. package/dist/scripts/check-denial-coverage.js.map +1 -0
  35. package/dist/scripts/check-ext-entrypoints.js +14 -2
  36. package/dist/scripts/check-ext-entrypoints.js.map +1 -1
  37. package/dist/scripts/check-outbound-fetch.d.ts.map +1 -1
  38. package/dist/scripts/check-outbound-fetch.js +16 -2
  39. package/dist/scripts/check-outbound-fetch.js.map +1 -1
  40. package/dist/scripts/check-sse-parity.js +14 -0
  41. package/dist/scripts/check-sse-parity.js.map +1 -1
  42. package/dist/scripts/indexnow.js +9 -7
  43. package/dist/scripts/indexnow.js.map +1 -1
  44. package/dist/src/auth/middleware.d.ts +7 -0
  45. package/dist/src/auth/middleware.d.ts.map +1 -1
  46. package/dist/src/auth/middleware.js +15 -21
  47. package/dist/src/auth/middleware.js.map +1 -1
  48. package/dist/src/cli/connect/mcp/tools/agent-tasks.d.ts +4 -0
  49. package/dist/src/cli/connect/mcp/tools/agent-tasks.d.ts.map +1 -1
  50. package/dist/src/cli/connect/mcp/tools/agent-tasks.js +11 -1
  51. package/dist/src/cli/connect/mcp/tools/agent-tasks.js.map +1 -1
  52. package/dist/src/cli/connect/mcp/tools/apps.d.ts.map +1 -1
  53. package/dist/src/cli/connect/mcp/tools/apps.js +88 -0
  54. package/dist/src/cli/connect/mcp/tools/apps.js.map +1 -1
  55. package/dist/src/cli/connect/mcp/tools/core.d.ts +7 -0
  56. package/dist/src/cli/connect/mcp/tools/core.d.ts.map +1 -1
  57. package/dist/src/cli/connect/mcp/tools/core.js +83 -4
  58. package/dist/src/cli/connect/mcp/tools/core.js.map +1 -1
  59. package/dist/src/cli/connect/onboarding-prompt.js +1 -1
  60. package/dist/src/cli/connect/skill-bundle.js +1 -1
  61. package/dist/src/cli/connect/tool-call-defs-app-draft-edit.d.ts +21 -0
  62. package/dist/src/cli/connect/tool-call-defs-app-draft-edit.d.ts.map +1 -0
  63. package/dist/src/cli/connect/tool-call-defs-app-draft-edit.js +137 -0
  64. package/dist/src/cli/connect/tool-call-defs-app-draft-edit.js.map +1 -0
  65. package/dist/src/cli/connect/tool-call-defs-core.d.ts +1 -0
  66. package/dist/src/cli/connect/tool-call-defs-core.d.ts.map +1 -1
  67. package/dist/src/cli/connect/tool-call-defs-core.js +30 -0
  68. package/dist/src/cli/connect/tool-call-defs-core.js.map +1 -1
  69. package/dist/src/cli/connect/tool-call.d.ts.map +1 -1
  70. package/dist/src/cli/connect/tool-call.js +2 -0
  71. package/dist/src/cli/connect/tool-call.js.map +1 -1
  72. package/dist/src/config-types-ai.d.ts +76 -0
  73. package/dist/src/config-types-ai.d.ts.map +1 -0
  74. package/dist/src/config-types-ai.js +15 -0
  75. package/dist/src/config-types-ai.js.map +1 -0
  76. package/dist/src/config-types.d.ts +11 -2
  77. package/dist/src/config-types.d.ts.map +1 -1
  78. package/dist/src/config.d.ts.map +1 -1
  79. package/dist/src/config.js +25 -4
  80. package/dist/src/config.js.map +1 -1
  81. package/dist/src/data/builtin-skills.d.ts.map +1 -1
  82. package/dist/src/data/builtin-skills.js +3 -2
  83. package/dist/src/data/builtin-skills.js.map +1 -1
  84. package/dist/src/data/digital-signage-package.js +1 -1
  85. package/dist/src/data/library-packs/sdk.d.ts.map +1 -1
  86. package/dist/src/data/library-packs/sdk.js +76 -0
  87. package/dist/src/data/library-packs/sdk.js.map +1 -1
  88. package/dist/src/data/library-packs/vendored.d.ts.map +1 -1
  89. package/dist/src/data/library-packs/vendored.js +81 -0
  90. package/dist/src/data/library-packs/vendored.js.map +1 -1
  91. package/dist/src/data/library-packs.d.ts +2 -2
  92. package/dist/src/data/library-packs.js +2 -2
  93. package/dist/src/data/public-pages.d.ts +13 -0
  94. package/dist/src/data/public-pages.d.ts.map +1 -1
  95. package/dist/src/data/public-pages.js +153 -113
  96. package/dist/src/data/public-pages.js.map +1 -1
  97. package/dist/src/generated/api-types.d.ts +1652 -36
  98. package/dist/src/generated/api-types.d.ts.map +1 -1
  99. package/dist/src/index-start.d.ts.map +1 -1
  100. package/dist/src/index-start.js +3 -0
  101. package/dist/src/index-start.js.map +1 -1
  102. package/dist/src/mcp/agent-tasks.d.ts.map +1 -1
  103. package/dist/src/mcp/agent-tasks.js +5 -0
  104. package/dist/src/mcp/agent-tasks.js.map +1 -1
  105. package/dist/src/mcp/ai-image.d.ts +22 -0
  106. package/dist/src/mcp/ai-image.d.ts.map +1 -0
  107. package/dist/src/mcp/ai-image.js +60 -0
  108. package/dist/src/mcp/ai-image.js.map +1 -0
  109. package/dist/src/mcp/annotations.d.ts +5 -0
  110. package/dist/src/mcp/annotations.d.ts.map +1 -1
  111. package/dist/src/mcp/annotations.js +18 -0
  112. package/dist/src/mcp/annotations.js.map +1 -1
  113. package/dist/src/mcp/apps-draft-edit.d.ts +28 -0
  114. package/dist/src/mcp/apps-draft-edit.d.ts.map +1 -0
  115. package/dist/src/mcp/apps-draft-edit.js +164 -0
  116. package/dist/src/mcp/apps-draft-edit.js.map +1 -0
  117. package/dist/src/mcp/apps-screenshot.d.ts +26 -0
  118. package/dist/src/mcp/apps-screenshot.d.ts.map +1 -0
  119. package/dist/src/mcp/apps-screenshot.js +39 -0
  120. package/dist/src/mcp/apps-screenshot.js.map +1 -0
  121. package/dist/src/mcp/catalog/definitions/discovery-work-boards.d.ts +1 -0
  122. package/dist/src/mcp/catalog/definitions/discovery-work-boards.d.ts.map +1 -1
  123. package/dist/src/mcp/catalog/definitions/discovery-work-boards.js +40 -0
  124. package/dist/src/mcp/catalog/definitions/discovery-work-boards.js.map +1 -1
  125. package/dist/src/mcp/catalog/definitions/organisms-workspaces-apps.d.ts +3 -0
  126. package/dist/src/mcp/catalog/definitions/organisms-workspaces-apps.d.ts.map +1 -1
  127. package/dist/src/mcp/catalog/definitions/organisms-workspaces-apps.js +74 -0
  128. package/dist/src/mcp/catalog/definitions/organisms-workspaces-apps.js.map +1 -1
  129. package/dist/src/mcp/catalog/definitions/schedules-tasks-memory.d.ts.map +1 -1
  130. package/dist/src/mcp/catalog/definitions/schedules-tasks-memory.js +1 -0
  131. package/dist/src/mcp/catalog/definitions/schedules-tasks-memory.js.map +1 -1
  132. package/dist/src/mcp/catalog/scopes.d.ts.map +1 -1
  133. package/dist/src/mcp/catalog/scopes.js +19 -1
  134. package/dist/src/mcp/catalog/scopes.js.map +1 -1
  135. package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
  136. package/dist/src/mcp/catalog/surfaces.js +18 -4
  137. package/dist/src/mcp/catalog/surfaces.js.map +1 -1
  138. package/dist/src/mcp/core-datapackage.d.ts +32 -0
  139. package/dist/src/mcp/core-datapackage.d.ts.map +1 -0
  140. package/dist/src/mcp/core-datapackage.js +188 -0
  141. package/dist/src/mcp/core-datapackage.js.map +1 -0
  142. package/dist/src/mcp/core-storage.d.ts +7 -3
  143. package/dist/src/mcp/core-storage.d.ts.map +1 -1
  144. package/dist/src/mcp/core-storage.js +27 -4
  145. package/dist/src/mcp/core-storage.js.map +1 -1
  146. package/dist/src/mcp/core.d.ts.map +1 -1
  147. package/dist/src/mcp/core.js +3 -0
  148. package/dist/src/mcp/core.js.map +1 -1
  149. package/dist/src/mcp/extensions.d.ts.map +1 -1
  150. package/dist/src/mcp/extensions.js +11 -1
  151. package/dist/src/mcp/extensions.js.map +1 -1
  152. package/dist/src/mcp/index.d.ts +9 -0
  153. package/dist/src/mcp/index.d.ts.map +1 -1
  154. package/dist/src/mcp/index.js +34 -0
  155. package/dist/src/mcp/index.js.map +1 -1
  156. package/dist/src/models/agent-task-schemas.d.ts.map +1 -1
  157. package/dist/src/models/agent-task-schemas.js +12 -1
  158. package/dist/src/models/agent-task-schemas.js.map +1 -1
  159. package/dist/src/models/workflow-schemas.d.ts +178 -1
  160. package/dist/src/models/workflow-schemas.d.ts.map +1 -1
  161. package/dist/src/models/workflow-schemas.js +75 -0
  162. package/dist/src/models/workflow-schemas.js.map +1 -1
  163. package/dist/src/routes/admin-extensions.d.ts +4 -0
  164. package/dist/src/routes/admin-extensions.d.ts.map +1 -1
  165. package/dist/src/routes/admin-extensions.js +135 -142
  166. package/dist/src/routes/admin-extensions.js.map +1 -1
  167. package/dist/src/routes/agent-conventions.d.ts.map +1 -1
  168. package/dist/src/routes/agent-conventions.js +4 -2
  169. package/dist/src/routes/agent-conventions.js.map +1 -1
  170. package/dist/src/routes/agent-docs.d.ts +4 -4
  171. package/dist/src/routes/agent-docs.js +145 -145
  172. package/dist/src/routes/agent-docs.js.map +1 -1
  173. package/dist/src/routes/agent-messages.d.ts +6 -0
  174. package/dist/src/routes/agent-messages.d.ts.map +1 -1
  175. package/dist/src/routes/agent-messages.js +23 -1
  176. package/dist/src/routes/agent-messages.js.map +1 -1
  177. package/dist/src/routes/agent-tasks/create-read.d.ts.map +1 -1
  178. package/dist/src/routes/agent-tasks/create-read.js +8 -1
  179. package/dist/src/routes/agent-tasks/create-read.js.map +1 -1
  180. package/dist/src/routes/agent-tasks/lifecycle.d.ts +4 -1
  181. package/dist/src/routes/agent-tasks/lifecycle.d.ts.map +1 -1
  182. package/dist/src/routes/agent-tasks/lifecycle.js +80 -2
  183. package/dist/src/routes/agent-tasks/lifecycle.js.map +1 -1
  184. package/dist/src/routes/ai.d.ts +5 -0
  185. package/dist/src/routes/ai.d.ts.map +1 -1
  186. package/dist/src/routes/ai.js +51 -1
  187. package/dist/src/routes/ai.js.map +1 -1
  188. package/dist/src/routes/app-grants.d.ts.map +1 -1
  189. package/dist/src/routes/app-grants.js +5 -0
  190. package/dist/src/routes/app-grants.js.map +1 -1
  191. package/dist/src/routes/apps/drafts.d.ts +6 -0
  192. package/dist/src/routes/apps/drafts.d.ts.map +1 -1
  193. package/dist/src/routes/apps/drafts.js +133 -1
  194. package/dist/src/routes/apps/drafts.js.map +1 -1
  195. package/dist/src/routes/apps/read.d.ts.map +1 -1
  196. package/dist/src/routes/apps/read.js +38 -1
  197. package/dist/src/routes/apps/read.js.map +1 -1
  198. package/dist/src/routes/auth-otk.d.ts +28 -0
  199. package/dist/src/routes/auth-otk.d.ts.map +1 -0
  200. package/dist/src/routes/auth-otk.js +190 -0
  201. package/dist/src/routes/auth-otk.js.map +1 -0
  202. package/dist/src/routes/auth.d.ts +17 -0
  203. package/dist/src/routes/auth.d.ts.map +1 -1
  204. package/dist/src/routes/auth.js +44 -153
  205. package/dist/src/routes/auth.js.map +1 -1
  206. package/dist/src/routes/bootstrap.d.ts +6 -0
  207. package/dist/src/routes/bootstrap.d.ts.map +1 -1
  208. package/dist/src/routes/bootstrap.js +47 -20
  209. package/dist/src/routes/bootstrap.js.map +1 -1
  210. package/dist/src/routes/chat.d.ts +23 -0
  211. package/dist/src/routes/chat.d.ts.map +1 -0
  212. package/dist/src/routes/chat.js +165 -0
  213. package/dist/src/routes/chat.js.map +1 -0
  214. package/dist/src/routes/commerce.js +4 -4
  215. package/dist/src/routes/commerce.js.map +1 -1
  216. package/dist/src/routes/datapackages.d.ts +35 -0
  217. package/dist/src/routes/datapackages.d.ts.map +1 -0
  218. package/dist/src/routes/datapackages.js +217 -0
  219. package/dist/src/routes/datapackages.js.map +1 -0
  220. package/dist/src/routes/disputes.d.ts +8 -0
  221. package/dist/src/routes/disputes.d.ts.map +1 -1
  222. package/dist/src/routes/disputes.js +52 -1
  223. package/dist/src/routes/disputes.js.map +1 -1
  224. package/dist/src/routes/ecosystem-apps-advisories.d.ts +16 -0
  225. package/dist/src/routes/ecosystem-apps-advisories.d.ts.map +1 -0
  226. package/dist/src/routes/ecosystem-apps-advisories.js +104 -0
  227. package/dist/src/routes/ecosystem-apps-advisories.js.map +1 -0
  228. package/dist/src/routes/ecosystem-apps.d.ts +6 -0
  229. package/dist/src/routes/ecosystem-apps.d.ts.map +1 -1
  230. package/dist/src/routes/ecosystem-apps.js +31 -99
  231. package/dist/src/routes/ecosystem-apps.js.map +1 -1
  232. package/dist/src/routes/extensions/actions.d.ts.map +1 -1
  233. package/dist/src/routes/extensions/actions.js +29 -1
  234. package/dist/src/routes/extensions/actions.js.map +1 -1
  235. package/dist/src/routes/federation-sync/routing.d.ts.map +1 -1
  236. package/dist/src/routes/federation-sync/routing.js +12 -3
  237. package/dist/src/routes/federation-sync/routing.js.map +1 -1
  238. package/dist/src/routes/glossary.js +1 -1
  239. package/dist/src/routes/glossary.js.map +1 -1
  240. package/dist/src/routes/home/track.d.ts +5 -1
  241. package/dist/src/routes/home/track.d.ts.map +1 -1
  242. package/dist/src/routes/home/track.js +20 -6
  243. package/dist/src/routes/home/track.js.map +1 -1
  244. package/dist/src/routes/instances/install.d.ts +3 -0
  245. package/dist/src/routes/instances/install.d.ts.map +1 -1
  246. package/dist/src/routes/instances/install.js +17 -24
  247. package/dist/src/routes/instances/install.js.map +1 -1
  248. package/dist/src/routes/libs.js +1 -1
  249. package/dist/src/routes/libs.js.map +1 -1
  250. package/dist/src/routes/markdown-mirrors.js +1 -1
  251. package/dist/src/routes/markdown-mirrors.js.map +1 -1
  252. package/dist/src/routes/odata.d.ts +36 -0
  253. package/dist/src/routes/odata.d.ts.map +1 -0
  254. package/dist/src/routes/odata.js +143 -0
  255. package/dist/src/routes/odata.js.map +1 -0
  256. package/dist/src/routes/openrouter.d.ts +4 -0
  257. package/dist/src/routes/openrouter.d.ts.map +1 -1
  258. package/dist/src/routes/openrouter.js +10 -1
  259. package/dist/src/routes/openrouter.js.map +1 -1
  260. package/dist/src/routes/organisms/gates.d.ts.map +1 -1
  261. package/dist/src/routes/organisms/gates.js +9 -2
  262. package/dist/src/routes/organisms/gates.js.map +1 -1
  263. package/dist/src/routes/portal.d.ts +1 -0
  264. package/dist/src/routes/portal.d.ts.map +1 -1
  265. package/dist/src/routes/portal.js +13 -0
  266. package/dist/src/routes/portal.js.map +1 -1
  267. package/dist/src/routes/schedules.d.ts +4 -0
  268. package/dist/src/routes/schedules.d.ts.map +1 -1
  269. package/dist/src/routes/schedules.js +9 -1
  270. package/dist/src/routes/schedules.js.map +1 -1
  271. package/dist/src/routes/storage-files.d.ts +23 -0
  272. package/dist/src/routes/storage-files.d.ts.map +1 -1
  273. package/dist/src/routes/storage-files.js +103 -82
  274. package/dist/src/routes/storage-files.js.map +1 -1
  275. package/dist/src/routes/workflows.d.ts.map +1 -1
  276. package/dist/src/routes/workflows.js +9 -1
  277. package/dist/src/routes/workflows.js.map +1 -1
  278. package/dist/src/server-bootstrap/routes-loader.d.ts +2 -0
  279. package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
  280. package/dist/src/server-bootstrap/routes-loader.js +20 -2
  281. package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
  282. package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
  283. package/dist/src/server-bootstrap/service-init.js +12 -7
  284. package/dist/src/server-bootstrap/service-init.js.map +1 -1
  285. package/dist/src/server-bootstrap/static-files.d.ts.map +1 -1
  286. package/dist/src/server-bootstrap/static-files.js +44 -10
  287. package/dist/src/server-bootstrap/static-files.js.map +1 -1
  288. package/dist/src/services/ai-allowance.d.ts +82 -0
  289. package/dist/src/services/ai-allowance.d.ts.map +1 -0
  290. package/dist/src/services/ai-allowance.js +117 -0
  291. package/dist/src/services/ai-allowance.js.map +1 -0
  292. package/dist/src/services/ai-completion.d.ts +26 -0
  293. package/dist/src/services/ai-completion.d.ts.map +1 -1
  294. package/dist/src/services/ai-completion.js +41 -13
  295. package/dist/src/services/ai-completion.js.map +1 -1
  296. package/dist/src/services/ai-image.d.ts +70 -0
  297. package/dist/src/services/ai-image.d.ts.map +1 -0
  298. package/dist/src/services/ai-image.js +104 -0
  299. package/dist/src/services/ai-image.js.map +1 -0
  300. package/dist/src/services/ai-model-defaults.d.ts +45 -0
  301. package/dist/src/services/ai-model-defaults.d.ts.map +1 -0
  302. package/dist/src/services/ai-model-defaults.js +42 -0
  303. package/dist/src/services/ai-model-defaults.js.map +1 -0
  304. package/dist/src/services/ai-tool-setup.d.ts +5 -1
  305. package/dist/src/services/ai-tool-setup.d.ts.map +1 -1
  306. package/dist/src/services/ai-tool-setup.js +36 -0
  307. package/dist/src/services/ai-tool-setup.js.map +1 -1
  308. package/dist/src/services/ai-transcription.d.ts +5 -0
  309. package/dist/src/services/ai-transcription.d.ts.map +1 -1
  310. package/dist/src/services/ai-transcription.js +5 -2
  311. package/dist/src/services/ai-transcription.js.map +1 -1
  312. package/dist/src/services/app-agent-surfaces.js +4 -4
  313. package/dist/src/services/app-agent-surfaces.js.map +1 -1
  314. package/dist/src/services/app-draft-edit.d.ts +144 -0
  315. package/dist/src/services/app-draft-edit.d.ts.map +1 -0
  316. package/dist/src/services/app-draft-edit.js +203 -0
  317. package/dist/src/services/app-draft-edit.js.map +1 -0
  318. package/dist/src/services/auth-md.js +2 -2
  319. package/dist/src/services/auth-md.js.map +1 -1
  320. package/dist/src/services/board-write.d.ts +11 -3
  321. package/dist/src/services/board-write.d.ts.map +1 -1
  322. package/dist/src/services/board-write.js +24 -3
  323. package/dist/src/services/board-write.js.map +1 -1
  324. package/dist/src/services/chat-agent.d.ts +36 -0
  325. package/dist/src/services/chat-agent.d.ts.map +1 -0
  326. package/dist/src/services/chat-agent.js +123 -0
  327. package/dist/src/services/chat-agent.js.map +1 -0
  328. package/dist/src/services/chat-session.d.ts +58 -0
  329. package/dist/src/services/chat-session.d.ts.map +1 -0
  330. package/dist/src/services/chat-session.js +151 -0
  331. package/dist/src/services/chat-session.js.map +1 -0
  332. package/dist/src/services/chat-threads.d.ts +61 -0
  333. package/dist/src/services/chat-threads.d.ts.map +1 -0
  334. package/dist/src/services/chat-threads.js +137 -0
  335. package/dist/src/services/chat-threads.js.map +1 -0
  336. package/dist/src/services/config-schema.d.ts.map +1 -1
  337. package/dist/src/services/config-schema.js +2 -1
  338. package/dist/src/services/config-schema.js.map +1 -1
  339. package/dist/src/services/datapackage/contract.d.ts +198 -0
  340. package/dist/src/services/datapackage/contract.d.ts.map +1 -0
  341. package/dist/src/services/datapackage/contract.js +140 -0
  342. package/dist/src/services/datapackage/contract.js.map +1 -0
  343. package/dist/src/services/datapackage/ext-capability.d.ts +85 -0
  344. package/dist/src/services/datapackage/ext-capability.d.ts.map +1 -0
  345. package/dist/src/services/datapackage/ext-capability.js +72 -0
  346. package/dist/src/services/datapackage/ext-capability.js.map +1 -0
  347. package/dist/src/services/datapackage/odata.d.ts +92 -0
  348. package/dist/src/services/datapackage/odata.d.ts.map +1 -0
  349. package/dist/src/services/datapackage/odata.js +256 -0
  350. package/dist/src/services/datapackage/odata.js.map +1 -0
  351. package/dist/src/services/datapackage/odps.d.ts +24 -0
  352. package/dist/src/services/datapackage/odps.d.ts.map +1 -0
  353. package/dist/src/services/datapackage/odps.js +183 -0
  354. package/dist/src/services/datapackage/odps.js.map +1 -0
  355. package/dist/src/services/datapackage/store.d.ts +143 -0
  356. package/dist/src/services/datapackage/store.d.ts.map +1 -0
  357. package/dist/src/services/datapackage/store.js +533 -0
  358. package/dist/src/services/datapackage/store.js.map +1 -0
  359. package/dist/src/services/datapackage/table.d.ts +67 -0
  360. package/dist/src/services/datapackage/table.d.ts.map +1 -0
  361. package/dist/src/services/datapackage/table.js +0 -0
  362. package/dist/src/services/datapackage/table.js.map +1 -0
  363. package/dist/src/services/extension-ctx.d.ts +1 -0
  364. package/dist/src/services/extension-ctx.d.ts.map +1 -1
  365. package/dist/src/services/extension-ctx.js +31 -6
  366. package/dist/src/services/extension-ctx.js.map +1 -1
  367. package/dist/src/services/extension-files.d.ts +20 -0
  368. package/dist/src/services/extension-files.d.ts.map +1 -1
  369. package/dist/src/services/extension-files.js +9 -2
  370. package/dist/src/services/extension-files.js.map +1 -1
  371. package/dist/src/services/extension-lifecycle.d.ts +3 -0
  372. package/dist/src/services/extension-lifecycle.d.ts.map +1 -1
  373. package/dist/src/services/extension-lifecycle.js +2 -26
  374. package/dist/src/services/extension-lifecycle.js.map +1 -1
  375. package/dist/src/services/extension-runtime.d.ts +28 -2
  376. package/dist/src/services/extension-runtime.d.ts.map +1 -1
  377. package/dist/src/services/extension-runtime.js +22 -0
  378. package/dist/src/services/extension-runtime.js.map +1 -1
  379. package/dist/src/services/extension-schedules.d.ts +90 -0
  380. package/dist/src/services/extension-schedules.d.ts.map +1 -0
  381. package/dist/src/services/extension-schedules.js +123 -0
  382. package/dist/src/services/extension-schedules.js.map +1 -0
  383. package/dist/src/services/extension-system-run.d.ts +91 -0
  384. package/dist/src/services/extension-system-run.d.ts.map +1 -0
  385. package/dist/src/services/extension-system-run.js +100 -0
  386. package/dist/src/services/extension-system-run.js.map +1 -0
  387. package/dist/src/services/extension-upsert.d.ts +2 -0
  388. package/dist/src/services/extension-upsert.d.ts.map +1 -1
  389. package/dist/src/services/extension-upsert.js +6 -24
  390. package/dist/src/services/extension-upsert.js.map +1 -1
  391. package/dist/src/services/goose-acp.d.ts +84 -0
  392. package/dist/src/services/goose-acp.d.ts.map +1 -0
  393. package/dist/src/services/goose-acp.js +304 -0
  394. package/dist/src/services/goose-acp.js.map +1 -0
  395. package/dist/src/services/markdown-negotiation.js +1 -1
  396. package/dist/src/services/markdown-negotiation.js.map +1 -1
  397. package/dist/src/services/openrouter.d.ts +20 -1
  398. package/dist/src/services/openrouter.d.ts.map +1 -1
  399. package/dist/src/services/openrouter.js +66 -0
  400. package/dist/src/services/openrouter.js.map +1 -1
  401. package/dist/src/services/prompt-defaults/tiers-core.js +4 -4
  402. package/dist/src/services/scheduler-extension-job.d.ts +29 -6
  403. package/dist/src/services/scheduler-extension-job.d.ts.map +1 -1
  404. package/dist/src/services/scheduler-extension-job.js +29 -75
  405. package/dist/src/services/scheduler-extension-job.js.map +1 -1
  406. package/dist/src/services/scope-vocabulary-migration.d.ts +34 -1
  407. package/dist/src/services/scope-vocabulary-migration.d.ts.map +1 -1
  408. package/dist/src/services/scope-vocabulary-migration.js +60 -0
  409. package/dist/src/services/scope-vocabulary-migration.js.map +1 -1
  410. package/dist/src/services/screenshot-capture.d.ts +40 -1
  411. package/dist/src/services/screenshot-capture.d.ts.map +1 -1
  412. package/dist/src/services/screenshot-capture.js +142 -60
  413. package/dist/src/services/screenshot-capture.js.map +1 -1
  414. package/dist/src/services/skill-bundle/generator.js +1 -1
  415. package/dist/src/services/skill-bundle/generic-adapter.js +1 -1
  416. package/dist/src/services/skill-bundle/hermes-adapter.js +1 -1
  417. package/dist/src/services/storage-file-write.d.ts +36 -1
  418. package/dist/src/services/storage-file-write.d.ts.map +1 -1
  419. package/dist/src/services/storage-file-write.js +49 -3
  420. package/dist/src/services/storage-file-write.js.map +1 -1
  421. package/dist/src/services/task-outcome.d.ts +53 -0
  422. package/dist/src/services/task-outcome.d.ts.map +1 -0
  423. package/dist/src/services/task-outcome.js +28 -0
  424. package/dist/src/services/task-outcome.js.map +1 -0
  425. package/dist/src/services/workflow/engine-human.d.ts +15 -0
  426. package/dist/src/services/workflow/engine-human.d.ts.map +1 -1
  427. package/dist/src/services/workflow/engine-human.js +10 -1
  428. package/dist/src/services/workflow/engine-human.js.map +1 -1
  429. package/dist/src/services/workflow/engine-steps.d.ts +48 -3
  430. package/dist/src/services/workflow/engine-steps.d.ts.map +1 -1
  431. package/dist/src/services/workflow/engine-steps.js +361 -0
  432. package/dist/src/services/workflow/engine-steps.js.map +1 -1
  433. package/dist/src/services/workflow/engine.d.ts +1 -0
  434. package/dist/src/services/workflow/engine.d.ts.map +1 -1
  435. package/dist/src/services/workflow/engine.js +2 -1
  436. package/dist/src/services/workflow/engine.js.map +1 -1
  437. package/dist/src/services/workflow/store.d.ts.map +1 -1
  438. package/dist/src/services/workflow/store.js +60 -4
  439. package/dist/src/services/workflow/store.js.map +1 -1
  440. package/dist/src/services/write-guards.d.ts +27 -1
  441. package/dist/src/services/write-guards.d.ts.map +1 -1
  442. package/dist/src/services/write-guards.js +39 -9
  443. package/dist/src/services/write-guards.js.map +1 -1
  444. package/dist/src/storage/providers/postgres-kysely/db-types.d.ts +1 -0
  445. package/dist/src/storage/providers/postgres-kysely/db-types.d.ts.map +1 -1
  446. package/dist/src/storage/providers/postgres-kysely/methods/app-grants.d.ts +1 -0
  447. package/dist/src/storage/providers/postgres-kysely/methods/app-grants.d.ts.map +1 -1
  448. package/dist/src/storage/providers/postgres-kysely/methods/app-grants.js +3 -0
  449. package/dist/src/storage/providers/postgres-kysely/methods/app-grants.js.map +1 -1
  450. package/dist/src/storage/providers/postgres-kysely/methods/files.d.ts +2 -0
  451. package/dist/src/storage/providers/postgres-kysely/methods/files.d.ts.map +1 -1
  452. package/dist/src/storage/providers/postgres-kysely/methods/files.js +34 -2
  453. package/dist/src/storage/providers/postgres-kysely/methods/files.js.map +1 -1
  454. package/dist/src/storage/providers/postgres-kysely/migrations/0039_storage_file_utf8_verified.sql +19 -0
  455. package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
  456. package/dist/src/storage/providers/sqlite/index.js +2 -1
  457. package/dist/src/storage/providers/sqlite/index.js.map +1 -1
  458. package/dist/src/storage/providers/sqlite/methods/apps.d.ts +1 -0
  459. package/dist/src/storage/providers/sqlite/methods/apps.d.ts.map +1 -1
  460. package/dist/src/storage/providers/sqlite/methods/apps.js +33 -28
  461. package/dist/src/storage/providers/sqlite/methods/apps.js.map +1 -1
  462. package/dist/src/storage/providers/sqlite/methods/identity-nodes.d.ts +1 -12
  463. package/dist/src/storage/providers/sqlite/methods/identity-nodes.d.ts.map +1 -1
  464. package/dist/src/storage/providers/sqlite/methods/identity-nodes.js +28 -135
  465. package/dist/src/storage/providers/sqlite/methods/identity-nodes.js.map +1 -1
  466. package/dist/src/storage/providers/sqlite/methods/storage-files.d.ts +38 -0
  467. package/dist/src/storage/providers/sqlite/methods/storage-files.d.ts.map +1 -0
  468. package/dist/src/storage/providers/sqlite/methods/storage-files.js +109 -0
  469. package/dist/src/storage/providers/sqlite/methods/storage-files.js.map +1 -0
  470. package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
  471. package/dist/src/storage/providers/sqlite/schema.js +134 -130
  472. package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
  473. package/dist/src/storage/repositories/app-grant.repository.d.ts +11 -0
  474. package/dist/src/storage/repositories/app-grant.repository.d.ts.map +1 -1
  475. package/dist/src/storage/repositories/file.repository.d.ts +13 -0
  476. package/dist/src/storage/repositories/file.repository.d.ts.map +1 -1
  477. package/dist/src/storage/types/commerce.d.ts +6 -0
  478. package/dist/src/storage/types/commerce.d.ts.map +1 -1
  479. package/dist/src/utils/agent-footer.d.ts.map +1 -1
  480. package/dist/src/utils/agent-footer.js +1 -0
  481. package/dist/src/utils/agent-footer.js.map +1 -1
  482. package/dist/src/utils/app-content-type.d.ts +57 -3
  483. package/dist/src/utils/app-content-type.d.ts.map +1 -1
  484. package/dist/src/utils/app-content-type.js +81 -12
  485. package/dist/src/utils/app-content-type.js.map +1 -1
  486. package/dist/src/utils/env-config/sections-features.d.ts.map +1 -1
  487. package/dist/src/utils/env-config/sections-features.js +9 -3
  488. package/dist/src/utils/env-config/sections-features.js.map +1 -1
  489. package/dist/src/utils/file-download-headers.d.ts +5 -3
  490. package/dist/src/utils/file-download-headers.d.ts.map +1 -1
  491. package/dist/src/utils/file-download-headers.js +18 -5
  492. package/dist/src/utils/file-download-headers.js.map +1 -1
  493. package/dist/src/utils/http-range.d.ts +151 -0
  494. package/dist/src/utils/http-range.d.ts.map +1 -0
  495. package/dist/src/utils/http-range.js +190 -0
  496. package/dist/src/utils/http-range.js.map +1 -0
  497. package/dist/src/utils/page-head.d.ts +5 -0
  498. package/dist/src/utils/page-head.d.ts.map +1 -1
  499. package/dist/src/utils/page-head.js +10 -1
  500. package/dist/src/utils/page-head.js.map +1 -1
  501. package/dist/src/utils/reserved-keys.d.ts +4 -1
  502. package/dist/src/utils/reserved-keys.d.ts.map +1 -1
  503. package/dist/src/utils/reserved-keys.js +4 -1
  504. package/dist/src/utils/reserved-keys.js.map +1 -1
  505. package/dist/static/sdk-libs/datapackage/index.js +336 -0
  506. package/dist/static/sdk-libs/dist/aimeat-datapackage.js +305 -0
  507. package/package.json +10 -2
@@ -1,315 +1,320 @@
1
- /**
2
- * @file public/views/profile/agents/scope-model.js
3
- * @description What an agent's scope set IS and how the checkbox editor converts to and from it —
4
- * the pure half of scope-config.js, with no imports, so it can be executed by a unit test.
5
- *
6
- * It is separate for one reason: the editor's expand/collapse pair is a round trip, and a round
7
- * trip that silently loses a member is invisible in every screenshot. `*` used to expand into
8
- * every checkbox and a fully-ticked editor used to collapse back to `['*']`, so
9
- * `memory:write-reserved` — which the server grants on the exact string only — always LOOKED
10
- * granted and could never be SAVED. Both halves have to agree about what the wildcard carries,
11
- * and now they agree here, once, under test/unit/agent-scope-model.test.ts.
12
- * @structure NOT_IN_WILDCARD · SCOPE_DOMAINS · SCOPE_TEMPLATES · wildcardScopes · expandScopes ·
13
- * collapseScopes · bulkScopes · detectTemplate
14
- * @usage
15
- * import { expandScopes, collapseScopes } from './scope-model.js';
16
- * const checked = expandScopes(agent.default_scopes ?? ['*']);
17
- * await save(collapseScopes(checked));
18
- * @version-history
19
- * v1.5.0 — 2026-08-15 — operator:organism-repair, in its own domain and outside every wildcard.
20
- * The only word here whose effect depends on who the owner is: the node operator can put an
21
- * owner back on an organism whose creator account is unreachable, and on any other account the
22
- * box grants nothing, which its sentence says. Without a row an operator could not grant it from
23
- * this page at all.
24
- * v1.4.0 — 2026-08-13 — agent:delete, the word a fleet runtime needs to clear away the agents it
25
- * created. Inside the wildcard on purpose: the route's second condition (only agents this
26
- * caller registered) is the real fence, and a box nobody can find protects nothing.
27
- * v1.3.0 — 2026-08-11 — account:security, a sixth word outside the wildcard: the password, the
28
- * recovery address, the second factor, the identity proof, and deleting or exporting the whole
29
- * account. Its own domain, because it is not a permission over the person's data but over
30
- * whether they still reach it.
31
- * v1.2.0 — 2026-08-11 — Five words that no wildcard carries: commerce:psp,
32
- * commerce:beneficiary-verify, agent:permissions, consent:groups and social:members. Each names
33
- * a call the web door reserves to a logged-in person, so it costs its own tick rather than
34
- * riding along with Full access.
35
- * v1.1.0 — 2026-08-10 — Three new domains (agent, app, capability) plus organism:write,
36
- * organism:invite and ext:invoke. These name things an agent could already do with no
37
- * permission at all, because the MCP scope table read silence as consent.
38
- * v1.0.0 — 2026-08-08 — Split out of scope-config.js so the wildcard round trip is testable.
39
- * v1.1.0 — 2026-08-08 — The vocabulary caught up with the node, and the round trip stopped losing
40
- * things. 17 scopes the node enforces had no row — bookkeeping, outgoing email, automations,
41
- * connected accounts, the marketplace — so unticking one unrelated box dropped the agent out of
42
- * '*' and revoked every one of them at once, none of them named anywhere in the dialog. Four
43
- * boxes granted nothing (generator:*, agent:register) and one more (task:manage) was dead too.
44
- * Anything the editor does not recognise is now carried through instead of discarded, an
45
- * unknown domain wildcard no longer collapses the whole grant to ['catalogue:read'], a domain
46
- * wildcard the agent already held is re-emitted when that domain was untouched, and an empty
47
- * scope list no longer reports itself as full access.
48
- */
49
-
50
- /**
51
- * Scopes that `*` deliberately does NOT carry, mirroring the server: hasWriteReserved() in
52
- * src/routes/memory/owner-target.ts tests the EXACT string, while every other scope check honours
53
- * the wildcard. "Full access" is one click, and nobody clicking it is deciding that an agent may
54
- * point their decrypted AI key at a URL of its choosing — so that one costs its own tick.
55
- */
56
- export const NOT_IN_WILDCARD = [
57
- 'memory:write-reserved',
58
- // ── Added 2026-08-11 ─────────────────────────────────────────────────────────────────────────
59
- // Eight tool calls the web door reserves to a logged-in person and the agent surface allowed on
60
- // an ordinary permission. Each is the owner's money or who else sees their data. The agent is not
61
- // shut out — it should be able to do what a person can — but each of these costs its own tick, so
62
- // it cannot ride along with "Full access".
63
- 'commerce:psp',
64
- 'commerce:beneficiary-verify',
65
- 'agent:permissions',
66
- 'consent:groups',
67
- // Handing another account a standing right to read part of the owner's memory. Same reasoning:
68
- // assembling an audience and giving it a key space are separate acts, and only the second gives
69
- // anything away.
70
- 'share:manage',
71
- 'social:members',
72
- // ── Added 2026-08-11 ─────────────────────────────────────────────────────────────────────────
73
- // The account itself: the password, the recovery address, the second factor, the identity proof,
74
- // and deleting or exporting everything. An agent that can set the password can become the person,
75
- // so this one is never granted by a preset, a bulk header or Full access — only by this box.
76
- 'account:security',
77
- // ── Added 2026-08-15 ─────────────────────────────────────────────────────────────────────────
78
- // The node operator's break-glass over an organism's ownership, on organisms the caller does not
79
- // own. It answers an incident an unscoped agent caused, so carrying it inside "Full access" would
80
- // rebuild the same hole one level up. Only an operator's own agent can be given it at all.
81
- 'operator:organism-repair',
82
- ];
83
-
84
- /**
85
- * The vocabulary of the checkbox editor.
86
- *
87
- * The rule for what belongs here: **ticking or unticking it must change what THIS AGENT can do.**
88
- * That is stricter than "the node reads the string somewhere", and the difference is not academic —
89
- * an audit of all 49 scope strings the node checks found eight where the tick binds someone else or
90
- * nobody:
91
- *
92
- * contract:spend only an app session is ever refused (services/metered-access.ts:151)
93
- * events:emit requireRole('ecosystem') runs first, so never an agent
94
- * organism:write requireRoleOrScope('agent', …) — an agent passes by ROLE, tick or no tick
95
- * task:manage nothing in src/ reads it at all
96
- * agent:register nothing in src/ reads it at all
97
- * generator:* the Generator was removed 2026-07-18; three dead strings
98
- *
99
- * A box that grants nothing is worse than a missing box: it answers the owner's question wrongly.
100
- * The dead ones were removed rather than relabelled; an agent that still holds one now shows it in
101
- * the editor's "other permissions" section, where it can be unticked (see unknownScopes).
102
- */
103
- export const SCOPE_DOMAINS = [
104
- // write-as-owner: write into the OWNER's namespace instead of the agent's own. Same shape as
105
- // messages:send-as-owner below — an explicit, owner-granted delegation. The agent must ALSO
106
- // ask for it per call, so granting it changes nothing on its own.
107
- // write-reserved: ALSO the keys the server itself trusts (openrouter.* / ai-usage.* /
108
- // profile.*). For an agent that administers the account. Not in '*' on purpose — see
109
- // WRITE_RESERVED_SCOPE in src/routes/memory/owner-target.ts. It is a MODIFIER on write-as-owner:
110
- // on its own it lifts a block on writes the agent is not making.
111
- { key: 'memory', permissions: ['read', 'write', 'delete', 'write-as-owner', 'write-reserved'] },
112
- { key: 'storage', permissions: ['read', 'write'] },
113
- { key: 'ai', permissions: ['use'] },
114
- { key: 'work', permissions: ['request', 'read', 'accept', 'publish'] },
115
- // social:members — add or remove who may read a shared board. A different promise from posting
116
- // to one, which is what social:write covers.
117
- { key: 'social', permissions: ['read', 'write', 'members'] },
118
- { key: 'messages', permissions: ['send', 'read', 'send-as-owner'] },
119
- { key: 'wallet', permissions: ['read'] },
120
- // consent:groups — create a sharing group and decide who is in it. A sharing group IS the
121
- // boundary of who reads the owner's memory, so it is separated from managing consents.
122
- { key: 'consent', permissions: ['manage', 'groups'] },
123
- // Key-space shares: what a sharing group actually reaches. The group is the audience (consent:groups);
124
- // this is what they may read. Without a row here an owner could not grant it in this editor at all.
125
- { key: 'share', permissions: ['manage'] },
126
- { key: 'tunnel', permissions: ['connect'] },
127
- { key: 'catalogue', permissions: ['read'] },
128
- { key: 'task', permissions: ['read', 'write'] },
129
- { key: 'workflow', permissions: ['read', 'write'] },
130
- // The money and the outside world. These were enforced by the node with no row in this editor,
131
- // so an owner could neither grant nor revoke them here while an agent used them daily.
132
- { key: 'finance', permissions: ['read', 'write'] },
133
- { key: 'outbound', permissions: ['send'] },
134
- { key: 'company', permissions: ['read', 'write'] },
135
- { key: 'connections', permissions: ['read', 'write', 'use'] },
136
- { key: 'notifications', permissions: ['send'] },
137
- { key: 'exchange', permissions: ['read', 'write', 'grant', 'beneficiary'] },
138
- // commerce:psp — write or destroy the payment credentials money is paid out through.
139
- // commerce:beneficiary-verify — record a beneficiary as verified, which is what makes a payout
140
- // possible. Kept apart from the rest because a provider who could open this gate for their own
141
- // payee is not a gate at all.
142
- { key: 'commerce', permissions: ['sell', 'buy', 'psp', 'beneficiary-verify'] },
143
- // organism:read — see the organisms and workspaces this agent's owner belongs to
144
- // organism:write — create a workspace, write and publish documents in one, comment, revert
145
- // organism:invite — hand somebody else access: invite a member, grant or revoke a workspace role.
146
- // Separate from write because it changes WHO ELSE can read the owner's knowledge,
147
- // which is a different promise than changing the knowledge.
148
- { key: 'organism', permissions: ['read', 'write', 'invite'] },
149
- { key: 'provenance', permissions: ['write'] },
150
- // cortex:write — install/activate/deactivate/delete cortex libraries (browser-side UI)
151
- // ext:write — activate/deactivate/delete extensions, manage instances (server-side WASM)
152
- // Note: extension INSTALL is requireAuth-only at the route (agents can push code that stays
153
- // inert until ext:write activates it). Cortex INSTALL requires cortex:write.
154
- { key: 'cortex', permissions: ['write'] },
155
- { key: 'ext', permissions: ['write', 'invoke'] },
156
-
157
- // ── Added 2026-08-10 (August 2026 audit, step 3a) ────────────────────────────────────────────
158
- // These name things an agent could already do with no permission at all, because the MCP surface
159
- // reads a missing entry in its scope table as permission rather than as an omission. Adding the
160
- // words is what lets an owner see them and take them away.
161
- //
162
- // agent:write reconfigure ANOTHER of the owner's agents: its mode, its tags. Not its own
163
- // record, which needs nothing an agent describing itself is answering about
164
- // itself. This is the one that reaches sideways, at a sibling principal with its
165
- // own identity and its own trust score.
166
- // app:write — publish or update an app under the owner's account, and save or publish a draft.
167
- // app:manage the destructive half: delete an app, fork one, remove a template. Split from
168
- // write because publishing an update and deleting the thing are different risks.
169
- // capability:write create, update, delete or vouch for a published capability. A capability is
170
- // how this account offers work to others, so writing one speaks in the owner's name.
171
- // agent:permissions rewrite what another of the owner's agents is allowed to do. Separate
172
- // from agent:write, which is its mode and its tags: this one changes the permission set itself.
173
- // agent:delete end another of the owner's agents for good. Its own word rather than part of
174
- // agent:write, because reconfiguring a sibling and ending it are different sizes of act, and
175
- // because the caller that needs it is a fleet concierge cleaning up what it created. The route
176
- // adds a second condition the box cannot express: an agent may only delete an agent whose
177
- // registration it authorized itself.
178
- { key: 'agent', permissions: ['write', 'permissions', 'delete'] },
179
- { key: 'app', permissions: ['write', 'manage'] },
180
- { key: 'capability', permissions: ['write'] },
181
-
182
- // ── Added 2026-08-11 (August 2026 audit, H-1/H-7) ────────────────────────────────────────────
183
- // account:security the doors that decide who can sign in as this person: the password, the
184
- // recovery address, the second factor, the identity proof, and deleting or exporting the whole
185
- // account. Enforced by requireOwnerPrincipal() in src/auth/middleware.ts. Nobody was
186
- // grandfathered onto it, so an agent has it only if the owner ticked this box.
187
- { key: 'account', permissions: ['security'] },
188
-
189
- // ── Added 2026-08-15 ─────────────────────────────────────────────────────────────────────────
190
- // operator:organism-repair install an owner on an organism this account does not own. The node
191
- // operator's break-glass, and the ONLY scope here whose effect depends on who the owner is: the
192
- // gate (requireOperatorPrincipal, src/auth/middleware.ts) reads the OWNER's roles first, so on a
193
- // normal account this box grants nothing and the sentence says so. It exists because an
194
- // organism whose creator became unreachable had no repair path on any surface, and a capability
195
- // an operator cannot grant from this page is a capability with no door.
196
- { key: 'operator', permissions: ['organism-repair'] },
197
- ];
198
-
199
- export const SCOPE_TEMPLATES = {
200
- readonly: ['memory:read', 'storage:read', 'catalogue:read', 'social:read'],
201
- standard: ['memory:read', 'memory:write', 'storage:read', 'storage:write', 'catalogue:read', 'social:read', 'work:request', 'work:read'],
202
- full: ['*'],
203
- };
204
-
205
- /** Every scope `*` actually carries — each box in the editor except the out-of-wildcard ones. */
206
- export function wildcardScopes() {
207
- const set = new Set();
208
- for (const d of SCOPE_DOMAINS) {
209
- for (const p of d.permissions) {
210
- const s = `${d.key}:${p}`;
211
- if (!NOT_IN_WILDCARD.includes(s)) set.add(s);
212
- }
213
- }
214
- return set;
215
- }
216
-
217
- /**
218
- * The scopes a domain's "all" header covers. An out-of-wildcard scope is left out on purpose: it
219
- * costs an explicit tick precisely so it cannot ride along with a bulk gesture.
220
- */
221
- export function bulkScopes(domDef) {
222
- return domDef.permissions.map(p => `${domDef.key}:${p}`).filter(s => !NOT_IN_WILDCARD.includes(s));
223
- }
224
-
225
- /** Every scope string the editor has a row for. */
226
- export function knownScopes() {
227
- const set = new Set();
228
- for (const d of SCOPE_DOMAINS) for (const p of d.permissions) set.add(`${d.key}:${p}`);
229
- return set;
230
- }
231
-
232
- /**
233
- * Scopes this agent holds that the editor has no row for an unknown domain, a scope added to the
234
- * node before the editor caught up, or a malformed string from a hand-written PATCH.
235
- *
236
- * They are surfaced rather than dropped. A scope the owner cannot see is one they cannot revoke,
237
- * and silently discarding it on save revokes it without telling them — both directions are wrong,
238
- * and which one hurts depends only on whether the scope was doing something.
239
- */
240
- export function unknownScopes(scopeList) {
241
- const known = knownScopes();
242
- return scopeList.filter(s => s !== '*' && !known.has(s) && !isKnownDomainWildcard(s));
243
- }
244
-
245
- function isKnownDomainWildcard(s) {
246
- const [domain, perm] = s.split(':');
247
- return perm === '*' && SCOPE_DOMAINS.some(d => d.key === domain);
248
- }
249
-
250
- /** A stored scope array → the set of ticked boxes (plus any scope with no box, kept verbatim). */
251
- export function expandScopes(scopeList) {
252
- // `*` first, then the explicit entries on top: an agent can hold ['*', 'memory:write-reserved'],
253
- // and the wildcard must not erase the extra that was granted alongside it.
254
- const set = scopeList.includes('*') ? wildcardScopes() : new Set();
255
- for (const s of scopeList) {
256
- if (s === '*') continue;
257
- const [domain, perm] = s.split(':');
258
- if (perm === '*') {
259
- const domDef = SCOPE_DOMAINS.find(d => d.key === domain);
260
- // A domain wildcard carries no more than the global one does. One for a domain the editor
261
- // does NOT know is kept as-is: dropping it silently revoked a real grant — `['finance:*']`
262
- // used to open-and-save into `['catalogue:read']`.
263
- if (domDef) bulkScopes(domDef).forEach(sc => set.add(sc));
264
- else set.add(s);
265
- } else {
266
- set.add(s);
267
- }
268
- }
269
- return set;
270
- }
271
-
272
- /**
273
- * The ticked boxes → the scope array to store.
274
- *
275
- * Collapses to `*` only over what the wildcard carries, keeps every out-of-wildcard scope spelled
276
- * out beside it, and carries through anything the editor has no row for. `original` is the array
277
- * the dialog opened with: a domain wildcard the agent already held is re-emitted when that domain
278
- * was left alone, so looking at an agent and pressing Save does not quietly rewrite `memory:*` into
279
- * a snapshot that stops covering whatever memory scope the node adds next.
280
- */
281
- export function collapseScopes(checked, original = []) {
282
- const known = knownScopes();
283
- const extras = NOT_IN_WILDCARD.filter(s => checked.has(s));
284
- const carried = [...checked].filter(s => !known.has(s));
285
- if ([...wildcardScopes()].every(s => checked.has(s))) return ['*', ...extras, ...carried];
286
-
287
- const out = [];
288
- const consumed = new Set();
289
- for (const d of SCOPE_DOMAINS) {
290
- const domainWildcard = `${d.key}:*`;
291
- const bulk = bulkScopes(d);
292
- if (original.includes(domainWildcard) && bulk.every(s => checked.has(s))) {
293
- out.push(domainWildcard);
294
- bulk.forEach(s => consumed.add(s));
295
- }
296
- }
297
- for (const s of checked) if (!consumed.has(s)) out.push(s);
298
- return out.length > 0 ? out : ['catalogue:read'];
299
- }
300
-
301
- export function detectTemplate(scopes) {
302
- // A MISSING scope list is the legacy "everything" default (both call sites read
303
- // `default_scopes ?? ['*']`). An EMPTY one is not the same thing, and calling it full access
304
- // labelled a zero-access agent as the maximum grant.
305
- if (!scopes) return 'full';
306
- if (scopes.length === 0) return 'custom';
307
- if (scopes.includes('*')) return 'full';
308
- const sorted = [...scopes].sort();
309
- for (const [name, tpl] of Object.entries(SCOPE_TEMPLATES)) {
310
- if (name === 'full') continue;
311
- const tplSorted = [...tpl].sort();
312
- if (sorted.length === tplSorted.length && sorted.every((s, i) => s === tplSorted[i])) return name;
313
- }
314
- return 'custom';
315
- }
1
+ /**
2
+ * @file public/views/profile/agents/scope-model.js
3
+ * @description What an agent's scope set IS and how the checkbox editor converts to and from it —
4
+ * the pure half of scope-config.js, with no imports, so it can be executed by a unit test.
5
+ *
6
+ * It is separate for one reason: the editor's expand/collapse pair is a round trip, and a round
7
+ * trip that silently loses a member is invisible in every screenshot. `*` used to expand into
8
+ * every checkbox and a fully-ticked editor used to collapse back to `['*']`, so
9
+ * `memory:write-reserved` — which the server grants on the exact string only — always LOOKED
10
+ * granted and could never be SAVED. Both halves have to agree about what the wildcard carries,
11
+ * and now they agree here, once, under test/unit/agent-scope-model.test.ts.
12
+ * @structure NOT_IN_WILDCARD · SCOPE_DOMAINS · SCOPE_TEMPLATES · wildcardScopes · expandScopes ·
13
+ * collapseScopes · bulkScopes · detectTemplate
14
+ * @usage
15
+ * import { expandScopes, collapseScopes } from './scope-model.js';
16
+ * const checked = expandScopes(agent.default_scopes ?? ['*']);
17
+ * await save(collapseScopes(checked));
18
+ * @version-history
19
+ * v1.5.0 — 2026-08-15 — operator:organism-repair, in its own domain and outside every wildcard.
20
+ * The only word here whose effect depends on who the owner is: the node operator can put an
21
+ * owner back on an organism whose creator account is unreachable, and on any other account the
22
+ * box grants nothing, which its sentence says. Without a row an operator could not grant it from
23
+ * this page at all.
24
+ * v1.4.0 — 2026-08-13 — agent:delete, the word a fleet runtime needs to clear away the agents it
25
+ * created. Inside the wildcard on purpose: the route's second condition (only agents this
26
+ * caller registered) is the real fence, and a box nobody can find protects nothing.
27
+ * v1.3.0 — 2026-08-11 — account:security, a sixth word outside the wildcard: the password, the
28
+ * recovery address, the second factor, the identity proof, and deleting or exporting the whole
29
+ * account. Its own domain, because it is not a permission over the person's data but over
30
+ * whether they still reach it.
31
+ * v1.2.0 — 2026-08-11 — Five words that no wildcard carries: commerce:psp,
32
+ * commerce:beneficiary-verify, agent:permissions, consent:groups and social:members. Each names
33
+ * a call the web door reserves to a logged-in person, so it costs its own tick rather than
34
+ * riding along with Full access.
35
+ * v1.1.0 — 2026-08-10 — Three new domains (agent, app, capability) plus organism:write,
36
+ * organism:invite and ext:invoke. These name things an agent could already do with no
37
+ * permission at all, because the MCP scope table read silence as consent.
38
+ * v1.0.0 — 2026-08-08 — Split out of scope-config.js so the wildcard round trip is testable.
39
+ * v1.1.0 — 2026-08-08 — The vocabulary caught up with the node, and the round trip stopped losing
40
+ * things. 17 scopes the node enforces had no row — bookkeeping, outgoing email, automations,
41
+ * connected accounts, the marketplace — so unticking one unrelated box dropped the agent out of
42
+ * '*' and revoked every one of them at once, none of them named anywhere in the dialog. Four
43
+ * boxes granted nothing (generator:*, agent:register) and one more (task:manage) was dead too.
44
+ * Anything the editor does not recognise is now carried through instead of discarded, an
45
+ * unknown domain wildcard no longer collapses the whole grant to ['catalogue:read'], a domain
46
+ * wildcard the agent already held is re-emitted when that domain was untouched, and an empty
47
+ * scope list no longer reports itself as full access.
48
+ */
49
+
50
+ /**
51
+ * Scopes that `*` deliberately does NOT carry, mirroring the server: hasWriteReserved() in
52
+ * src/routes/memory/owner-target.ts tests the EXACT string, while every other scope check honours
53
+ * the wildcard. "Full access" is one click, and nobody clicking it is deciding that an agent may
54
+ * point their decrypted AI key at a URL of its choosing — so that one costs its own tick.
55
+ */
56
+ export const NOT_IN_WILDCARD = [
57
+ 'memory:write-reserved',
58
+ // ── Added 2026-08-11 ─────────────────────────────────────────────────────────────────────────
59
+ // Eight tool calls the web door reserves to a logged-in person and the agent surface allowed on
60
+ // an ordinary permission. Each is the owner's money or who else sees their data. The agent is not
61
+ // shut out — it should be able to do what a person can — but each of these costs its own tick, so
62
+ // it cannot ride along with "Full access".
63
+ 'commerce:psp',
64
+ 'commerce:beneficiary-verify',
65
+ 'agent:permissions',
66
+ 'consent:groups',
67
+ // Handing another account a standing right to read part of the owner's memory. Same reasoning:
68
+ // assembling an audience and giving it a key space are separate acts, and only the second gives
69
+ // anything away.
70
+ 'share:manage',
71
+ 'social:members',
72
+ // ── Added 2026-08-11 ─────────────────────────────────────────────────────────────────────────
73
+ // The account itself: the password, the recovery address, the second factor, the identity proof,
74
+ // and deleting or exporting everything. An agent that can set the password can become the person,
75
+ // so this one is never granted by a preset, a bulk header or Full access — only by this box.
76
+ 'account:security',
77
+ // ── Added 2026-08-15 ─────────────────────────────────────────────────────────────────────────
78
+ // The node operator's break-glass over an organism's ownership, on organisms the caller does not
79
+ // own. It answers an incident an unscoped agent caused, so carrying it inside "Full access" would
80
+ // rebuild the same hole one level up. Only an operator's own agent can be given it at all.
81
+ 'operator:organism-repair',
82
+ ];
83
+
84
+ /**
85
+ * The vocabulary of the checkbox editor.
86
+ *
87
+ * The rule for what belongs here: **ticking or unticking it must change what THIS AGENT can do.**
88
+ * That is stricter than "the node reads the string somewhere", and the difference is not academic —
89
+ * an audit of all 49 scope strings the node checks found eight where the tick binds someone else or
90
+ * nobody:
91
+ *
92
+ * contract:spend only an app session is ever refused (services/metered-access.ts:151)
93
+ * events:emit requireRole('ecosystem') runs first, so never an agent
94
+ * organism:write requireRoleOrScope('agent', …) — an agent passes by ROLE, tick or no tick
95
+ * task:manage nothing in src/ reads it at all
96
+ * agent:register nothing in src/ reads it at all
97
+ * generator:* the Generator was removed 2026-07-18; three dead strings
98
+ *
99
+ * A box that grants nothing is worse than a missing box: it answers the owner's question wrongly.
100
+ * The dead ones were removed rather than relabelled; an agent that still holds one now shows it in
101
+ * the editor's "other permissions" section, where it can be unticked (see unknownScopes).
102
+ */
103
+ export const SCOPE_DOMAINS = [
104
+ // write-as-owner: write into the OWNER's namespace instead of the agent's own. Same shape as
105
+ // messages:send-as-owner below — an explicit, owner-granted delegation. The agent must ALSO
106
+ // ask for it per call, so granting it changes nothing on its own.
107
+ // write-reserved: ALSO the keys the server itself trusts (openrouter.* / ai-usage.* /
108
+ // profile.*). For an agent that administers the account. Not in '*' on purpose — see
109
+ // WRITE_RESERVED_SCOPE in src/routes/memory/owner-target.ts. It is a MODIFIER on write-as-owner:
110
+ // on its own it lifts a block on writes the agent is not making.
111
+ { key: 'memory', permissions: ['read', 'write', 'delete', 'write-as-owner', 'write-reserved'] },
112
+ { key: 'storage', permissions: ['read', 'write'] },
113
+ { key: 'ai', permissions: ['use'] },
114
+ { key: 'work', permissions: ['request', 'read', 'accept', 'publish'] },
115
+ // social:members — add or remove who may read a shared board. A different promise from posting
116
+ // to one, which is what social:write covers.
117
+ { key: 'social', permissions: ['read', 'write', 'members'] },
118
+ { key: 'messages', permissions: ['send', 'read', 'send-as-owner'] },
119
+ { key: 'wallet', permissions: ['read'] },
120
+ // consent:groups — create a sharing group and decide who is in it. A sharing group IS the
121
+ // boundary of who reads the owner's memory, so it is separated from managing consents.
122
+ { key: 'consent', permissions: ['manage', 'groups'] },
123
+ // Key-space shares: what a sharing group actually reaches. The group is the audience (consent:groups);
124
+ // this is what they may read. Without a row here an owner could not grant it in this editor at all.
125
+ { key: 'share', permissions: ['manage'] },
126
+ { key: 'tunnel', permissions: ['connect'] },
127
+ { key: 'catalogue', permissions: ['read'] },
128
+ { key: 'task', permissions: ['read', 'write'] },
129
+ { key: 'workflow', permissions: ['read', 'write'] },
130
+ // The money and the outside world. These were enforced by the node with no row in this editor,
131
+ // so an owner could neither grant nor revoke them here while an agent used them daily.
132
+ { key: 'finance', permissions: ['read', 'write'] },
133
+ { key: 'outbound', permissions: ['send'] },
134
+ { key: 'company', permissions: ['read', 'write'] },
135
+ { key: 'connections', permissions: ['read', 'write', 'use'] },
136
+ { key: 'notifications', permissions: ['send'] },
137
+ { key: 'exchange', permissions: ['read', 'write', 'grant', 'beneficiary'] },
138
+ // commerce:psp — write or destroy the payment credentials money is paid out through.
139
+ // commerce:beneficiary-verify — record a beneficiary as verified, which is what makes a payout
140
+ // possible. Kept apart from the rest because a provider who could open this gate for their own
141
+ // payee is not a gate at all.
142
+ { key: 'commerce', permissions: ['sell', 'buy', 'psp', 'beneficiary-verify'] },
143
+ // organism:read — see the organisms and workspaces this agent's owner belongs to
144
+ // organism:write — create a workspace, write and publish documents in one, comment, revert
145
+ // organism:invite — hand somebody else access: invite a member, grant or revoke a workspace role.
146
+ // Separate from write because it changes WHO ELSE can read the owner's knowledge,
147
+ // which is a different promise than changing the knowledge.
148
+ { key: 'organism', permissions: ['read', 'write', 'invite'] },
149
+ { key: 'provenance', permissions: ['write'] },
150
+ // cortex:write — install/activate/deactivate/delete cortex libraries (browser-side UI)
151
+ // ext:write — activate/deactivate/delete extensions, manage instances (server-side WASM)
152
+ // Note: extension INSTALL is requireAuth-only at the route (agents can push code that stays
153
+ // inert until ext:write activates it). Cortex INSTALL requires cortex:write.
154
+ { key: 'cortex', permissions: ['write'] },
155
+ { key: 'ext', permissions: ['write', 'invoke'] },
156
+ // packages:write — install a package. That REGISTERS its app, its cortex, its extension and any
157
+ // @activate cron the manifest declares, all under the installer's identity, so it is the widest
158
+ // single act in this list and it asked for nothing at all until 2026-08-15. A row here is what
159
+ // lets an owner see it and take it away.
160
+ { key: 'packages', permissions: ['write'] },
161
+
162
+ // ── Added 2026-08-10 (August 2026 audit, step 3a) ────────────────────────────────────────────
163
+ // These name things an agent could already do with no permission at all, because the MCP surface
164
+ // reads a missing entry in its scope table as permission rather than as an omission. Adding the
165
+ // words is what lets an owner see them and take them away.
166
+ //
167
+ // agent:write reconfigure ANOTHER of the owner's agents: its mode, its tags. Not its own
168
+ // record, which needs nothing an agent describing itself is answering about
169
+ // itself. This is the one that reaches sideways, at a sibling principal with its
170
+ // own identity and its own trust score.
171
+ // app:write publish or update an app under the owner's account, and save or publish a draft.
172
+ // app:manage — the destructive half: delete an app, fork one, remove a template. Split from
173
+ // write because publishing an update and deleting the thing are different risks.
174
+ // capability:write create, update, delete or vouch for a published capability. A capability is
175
+ // how this account offers work to others, so writing one speaks in the owner's name.
176
+ // agent:permissions rewrite what another of the owner's agents is allowed to do. Separate
177
+ // from agent:write, which is its mode and its tags: this one changes the permission set itself.
178
+ // agent:delete end another of the owner's agents for good. Its own word rather than part of
179
+ // agent:write, because reconfiguring a sibling and ending it are different sizes of act, and
180
+ // because the caller that needs it is a fleet concierge cleaning up what it created. The route
181
+ // adds a second condition the box cannot express: an agent may only delete an agent whose
182
+ // registration it authorized itself.
183
+ { key: 'agent', permissions: ['write', 'permissions', 'delete'] },
184
+ { key: 'app', permissions: ['write', 'manage'] },
185
+ { key: 'capability', permissions: ['write'] },
186
+
187
+ // ── Added 2026-08-11 (August 2026 audit, H-1/H-7) ────────────────────────────────────────────
188
+ // account:security — the doors that decide who can sign in as this person: the password, the
189
+ // recovery address, the second factor, the identity proof, and deleting or exporting the whole
190
+ // account. Enforced by requireOwnerPrincipal() in src/auth/middleware.ts. Nobody was
191
+ // grandfathered onto it, so an agent has it only if the owner ticked this box.
192
+ { key: 'account', permissions: ['security'] },
193
+
194
+ // ── Added 2026-08-15 ─────────────────────────────────────────────────────────────────────────
195
+ // operator:organism-repair install an owner on an organism this account does not own. The node
196
+ // operator's break-glass, and the ONLY scope here whose effect depends on who the owner is: the
197
+ // gate (requireOperatorPrincipal, src/auth/middleware.ts) reads the OWNER's roles first, so on a
198
+ // normal account this box grants nothing and the sentence says so. It exists because an
199
+ // organism whose creator became unreachable had no repair path on any surface, and a capability
200
+ // an operator cannot grant from this page is a capability with no door.
201
+ { key: 'operator', permissions: ['organism-repair'] },
202
+ ];
203
+
204
+ export const SCOPE_TEMPLATES = {
205
+ readonly: ['memory:read', 'storage:read', 'catalogue:read', 'social:read'],
206
+ standard: ['memory:read', 'memory:write', 'storage:read', 'storage:write', 'catalogue:read', 'social:read', 'work:request', 'work:read'],
207
+ full: ['*'],
208
+ };
209
+
210
+ /** Every scope `*` actually carries — each box in the editor except the out-of-wildcard ones. */
211
+ export function wildcardScopes() {
212
+ const set = new Set();
213
+ for (const d of SCOPE_DOMAINS) {
214
+ for (const p of d.permissions) {
215
+ const s = `${d.key}:${p}`;
216
+ if (!NOT_IN_WILDCARD.includes(s)) set.add(s);
217
+ }
218
+ }
219
+ return set;
220
+ }
221
+
222
+ /**
223
+ * The scopes a domain's "all" header covers. An out-of-wildcard scope is left out on purpose: it
224
+ * costs an explicit tick precisely so it cannot ride along with a bulk gesture.
225
+ */
226
+ export function bulkScopes(domDef) {
227
+ return domDef.permissions.map(p => `${domDef.key}:${p}`).filter(s => !NOT_IN_WILDCARD.includes(s));
228
+ }
229
+
230
+ /** Every scope string the editor has a row for. */
231
+ export function knownScopes() {
232
+ const set = new Set();
233
+ for (const d of SCOPE_DOMAINS) for (const p of d.permissions) set.add(`${d.key}:${p}`);
234
+ return set;
235
+ }
236
+
237
+ /**
238
+ * Scopes this agent holds that the editor has no row for — an unknown domain, a scope added to the
239
+ * node before the editor caught up, or a malformed string from a hand-written PATCH.
240
+ *
241
+ * They are surfaced rather than dropped. A scope the owner cannot see is one they cannot revoke,
242
+ * and silently discarding it on save revokes it without telling them — both directions are wrong,
243
+ * and which one hurts depends only on whether the scope was doing something.
244
+ */
245
+ export function unknownScopes(scopeList) {
246
+ const known = knownScopes();
247
+ return scopeList.filter(s => s !== '*' && !known.has(s) && !isKnownDomainWildcard(s));
248
+ }
249
+
250
+ function isKnownDomainWildcard(s) {
251
+ const [domain, perm] = s.split(':');
252
+ return perm === '*' && SCOPE_DOMAINS.some(d => d.key === domain);
253
+ }
254
+
255
+ /** A stored scope array → the set of ticked boxes (plus any scope with no box, kept verbatim). */
256
+ export function expandScopes(scopeList) {
257
+ // `*` first, then the explicit entries on top: an agent can hold ['*', 'memory:write-reserved'],
258
+ // and the wildcard must not erase the extra that was granted alongside it.
259
+ const set = scopeList.includes('*') ? wildcardScopes() : new Set();
260
+ for (const s of scopeList) {
261
+ if (s === '*') continue;
262
+ const [domain, perm] = s.split(':');
263
+ if (perm === '*') {
264
+ const domDef = SCOPE_DOMAINS.find(d => d.key === domain);
265
+ // A domain wildcard carries no more than the global one does. One for a domain the editor
266
+ // does NOT know is kept as-is: dropping it silently revoked a real grant — `['finance:*']`
267
+ // used to open-and-save into `['catalogue:read']`.
268
+ if (domDef) bulkScopes(domDef).forEach(sc => set.add(sc));
269
+ else set.add(s);
270
+ } else {
271
+ set.add(s);
272
+ }
273
+ }
274
+ return set;
275
+ }
276
+
277
+ /**
278
+ * The ticked boxes the scope array to store.
279
+ *
280
+ * Collapses to `*` only over what the wildcard carries, keeps every out-of-wildcard scope spelled
281
+ * out beside it, and carries through anything the editor has no row for. `original` is the array
282
+ * the dialog opened with: a domain wildcard the agent already held is re-emitted when that domain
283
+ * was left alone, so looking at an agent and pressing Save does not quietly rewrite `memory:*` into
284
+ * a snapshot that stops covering whatever memory scope the node adds next.
285
+ */
286
+ export function collapseScopes(checked, original = []) {
287
+ const known = knownScopes();
288
+ const extras = NOT_IN_WILDCARD.filter(s => checked.has(s));
289
+ const carried = [...checked].filter(s => !known.has(s));
290
+ if ([...wildcardScopes()].every(s => checked.has(s))) return ['*', ...extras, ...carried];
291
+
292
+ const out = [];
293
+ const consumed = new Set();
294
+ for (const d of SCOPE_DOMAINS) {
295
+ const domainWildcard = `${d.key}:*`;
296
+ const bulk = bulkScopes(d);
297
+ if (original.includes(domainWildcard) && bulk.every(s => checked.has(s))) {
298
+ out.push(domainWildcard);
299
+ bulk.forEach(s => consumed.add(s));
300
+ }
301
+ }
302
+ for (const s of checked) if (!consumed.has(s)) out.push(s);
303
+ return out.length > 0 ? out : ['catalogue:read'];
304
+ }
305
+
306
+ export function detectTemplate(scopes) {
307
+ // A MISSING scope list is the legacy "everything" default (both call sites read
308
+ // `default_scopes ?? ['*']`). An EMPTY one is not the same thing, and calling it full access
309
+ // labelled a zero-access agent as the maximum grant.
310
+ if (!scopes) return 'full';
311
+ if (scopes.length === 0) return 'custom';
312
+ if (scopes.includes('*')) return 'full';
313
+ const sorted = [...scopes].sort();
314
+ for (const [name, tpl] of Object.entries(SCOPE_TEMPLATES)) {
315
+ if (name === 'full') continue;
316
+ const tplSorted = [...tpl].sort();
317
+ if (sorted.length === tplSorted.length && sorted.every((s, i) => s === tplSorted[i])) return name;
318
+ }
319
+ return 'custom';
320
+ }