@jini-ai/cms 0.3.10 → 0.4.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 (258) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/README.md +47 -19
  3. package/dist/content-types/agent-tools.d.ts +3 -56
  4. package/dist/content-types/agent-tools.js +22 -6
  5. package/dist/content-types/cleanup.d.ts +18 -13
  6. package/dist/content-types/cleanup.js +16 -11
  7. package/dist/content-types/errors.d.ts +57 -24
  8. package/dist/content-types/errors.js +56 -39
  9. package/dist/content-types/field-defs.d.ts +8 -4
  10. package/dist/content-types/field-defs.js +19 -14
  11. package/dist/content-types/index-provisioning.d.ts +61 -47
  12. package/dist/content-types/index-provisioning.js +90 -66
  13. package/dist/content-types/index.d.ts +4 -3
  14. package/dist/content-types/lifecycle-dispatch.d.ts +11 -5
  15. package/dist/content-types/lifecycle-dispatch.js +5 -4
  16. package/dist/content-types/lifecycle.d.ts +23 -18
  17. package/dist/content-types/lifecycle.js +71 -64
  18. package/dist/content-types/repo.memory.d.ts +5 -4
  19. package/dist/content-types/repo.memory.js +3 -2
  20. package/dist/content-types/tool-registrations.d.ts +6 -8
  21. package/dist/content-types/tool-registrations.js +24 -28
  22. package/dist/content-types/types.d.ts +17 -13
  23. package/dist/content-types/types.js +11 -5
  24. package/dist/content-types/write-service.d.ts +20 -22
  25. package/dist/content-types/write-service.js +78 -75
  26. package/dist/core/authorization.d.ts +15 -0
  27. package/dist/core/authorization.js +2 -0
  28. package/dist/core/commands/change-set.d.ts +15 -7
  29. package/dist/core/commands/command.d.ts +45 -26
  30. package/dist/core/commands/command.js +73 -63
  31. package/dist/core/entity-liveness.d.ts +11 -7
  32. package/dist/core/entity-liveness.js +5 -4
  33. package/dist/core/index.d.ts +12 -5
  34. package/dist/core/index.js +10 -4
  35. package/dist/core/ports.d.ts +25 -24
  36. package/dist/core/ports.js +1 -0
  37. package/dist/core/tools/args.d.ts +49 -0
  38. package/dist/core/tools/args.js +46 -0
  39. package/dist/core/tools/index.d.ts +3 -0
  40. package/dist/core/tools/index.js +3 -0
  41. package/dist/entries/agent-tools.d.ts +1 -73
  42. package/dist/entries/agent-tools.js +19 -13
  43. package/dist/entries/errors.d.ts +28 -14
  44. package/dist/entries/errors.js +17 -11
  45. package/dist/entries/field-validation.d.ts +5 -3
  46. package/dist/entries/field-validation.js +7 -5
  47. package/dist/entries/index.d.ts +2 -2
  48. package/dist/entries/lifecycle-dispatch.d.ts +5 -2
  49. package/dist/entries/lifecycle-dispatch.js +2 -1
  50. package/dist/entries/list.d.ts +4 -2
  51. package/dist/entries/list.js +4 -3
  52. package/dist/entries/repo.memory.d.ts +12 -10
  53. package/dist/entries/repo.memory.js +11 -10
  54. package/dist/entries/tool-registrations.d.ts +6 -8
  55. package/dist/entries/tool-registrations.js +42 -41
  56. package/dist/entries/types.d.ts +0 -7
  57. package/dist/entries/write-service.d.ts +28 -29
  58. package/dist/entries/write-service.js +114 -105
  59. package/dist/http/settings/cms-adapter.d.ts +20 -0
  60. package/dist/http/settings/cms-adapter.js +124 -0
  61. package/dist/http/settings/contracts.d.ts +135 -0
  62. package/dist/http/settings/contracts.js +2 -0
  63. package/dist/http/settings/http.d.ts +10 -0
  64. package/dist/http/settings/http.js +211 -0
  65. package/dist/http/settings/index.d.ts +5 -0
  66. package/dist/http/settings/index.js +4 -0
  67. package/dist/http/settings/shared.d.ts +68 -0
  68. package/dist/http/settings/shared.js +54 -0
  69. package/dist/http/settings/stream.d.ts +24 -0
  70. package/dist/http/settings/stream.js +147 -0
  71. package/dist/media/agent-tools.d.ts +1 -66
  72. package/dist/media/agent-tools.js +5 -1
  73. package/dist/media/blob-gc-lock.d.ts +6 -2
  74. package/dist/media/blob-gc-lock.js +4 -2
  75. package/dist/media/blob-gc.d.ts +64 -51
  76. package/dist/media/blob-gc.js +62 -52
  77. package/dist/media/blob-key.d.ts +1 -1
  78. package/dist/media/content-type-sniffer.d.ts +3 -1
  79. package/dist/media/content-type-sniffer.js +1 -1
  80. package/dist/media/html-attributes.d.ts +9 -5
  81. package/dist/media/html-attributes.js +8 -6
  82. package/dist/media/image-transformer.js +1 -1
  83. package/dist/media/image-transformer.sharp.d.ts +6 -0
  84. package/dist/media/image-transformer.sharp.js +12 -6
  85. package/dist/media/import/fetch-image.d.ts +24 -0
  86. package/dist/media/import/fetch-image.js +137 -0
  87. package/dist/media/import/index.d.ts +3 -0
  88. package/dist/media/import/index.js +3 -0
  89. package/dist/media/import/ports.d.ts +38 -0
  90. package/dist/media/index.d.ts +7 -1
  91. package/dist/media/index.js +1 -0
  92. package/dist/media/media-service.d.ts +14 -10
  93. package/dist/media/media-service.js +57 -52
  94. package/dist/media/ports.d.ts +3 -2
  95. package/dist/media/rendition-service.d.ts +3 -3
  96. package/dist/media/rendition-service.js +38 -37
  97. package/dist/media/repo.memory.d.ts +18 -7
  98. package/dist/media/repo.memory.js +12 -6
  99. package/dist/media/tool-registrations.d.ts +16 -15
  100. package/dist/media/tool-registrations.js +84 -72
  101. package/dist/media/transform-lock.d.ts +22 -12
  102. package/dist/media/transform-lock.js +14 -13
  103. package/dist/media/transform-registry.d.ts +3 -3
  104. package/dist/media/transform-registry.js +19 -18
  105. package/dist/media/transform-types.d.ts +8 -3
  106. package/dist/media/transform-types.js +10 -5
  107. package/dist/media/types.d.ts +21 -4
  108. package/dist/media/types.js +15 -2
  109. package/dist/navigation/agent-tools.d.ts +1 -80
  110. package/dist/navigation/agent-tools.js +15 -3
  111. package/dist/navigation/contracts.d.ts +1 -1
  112. package/dist/navigation/index.d.ts +2 -2
  113. package/dist/navigation/menu-service.d.ts +57 -40
  114. package/dist/navigation/menu-service.js +80 -69
  115. package/dist/navigation/ports.d.ts +1 -1
  116. package/dist/navigation/read-model.d.ts +3 -1
  117. package/dist/navigation/read-model.js +2 -2
  118. package/dist/navigation/reconcile.d.ts +2 -2
  119. package/dist/navigation/reconcile.js +2 -1
  120. package/dist/navigation/repo.memory.d.ts +7 -3
  121. package/dist/navigation/repo.memory.js +4 -2
  122. package/dist/navigation/resolver.d.ts +4 -1
  123. package/dist/navigation/resolver.js +1 -1
  124. package/dist/navigation/tool-registrations.d.ts +6 -8
  125. package/dist/navigation/tool-registrations.js +44 -42
  126. package/dist/navigation/types.d.ts +1 -1
  127. package/dist/presentation/presentation.d.ts +11 -3
  128. package/dist/presentation/presentation.js +13 -6
  129. package/dist/presentation/repo.memory.d.ts +6 -2
  130. package/dist/presentation/repo.memory.js +3 -2
  131. package/dist/settings/agent-tools.d.ts +2 -75
  132. package/dist/settings/agent-tools.js +49 -45
  133. package/dist/settings/agent-value-write-tools.d.ts +22 -0
  134. package/dist/settings/agent-value-write-tools.js +154 -0
  135. package/dist/settings/agent-writable-preferences.js +8 -20
  136. package/dist/settings/agent-write-denylist.d.ts +19 -0
  137. package/dist/settings/agent-write-denylist.js +15 -0
  138. package/dist/settings/change-feed.d.ts +11 -2
  139. package/dist/settings/change-feed.js +4 -4
  140. package/dist/settings/definitions-dispatch.d.ts +8 -3
  141. package/dist/settings/definitions-dispatch.js +5 -5
  142. package/dist/settings/dictionaries/index.d.ts +5 -2
  143. package/dist/settings/dictionaries/index.js +2 -2
  144. package/dist/settings/dictionaries/settings-dialog.ar.js +0 -1
  145. package/dist/settings/dictionaries/settings-dialog.bn.js +0 -1
  146. package/dist/settings/dictionaries/settings-dialog.de.js +0 -1
  147. package/dist/settings/dictionaries/settings-dialog.es.js +0 -1
  148. package/dist/settings/dictionaries/settings-dialog.fa.js +0 -1
  149. package/dist/settings/dictionaries/settings-dialog.fr.js +0 -1
  150. package/dist/settings/dictionaries/settings-dialog.hi.js +0 -1
  151. package/dist/settings/dictionaries/settings-dialog.hu.js +0 -1
  152. package/dist/settings/dictionaries/settings-dialog.id.js +0 -1
  153. package/dist/settings/dictionaries/settings-dialog.it.js +0 -1
  154. package/dist/settings/dictionaries/settings-dialog.ja.js +0 -1
  155. package/dist/settings/dictionaries/settings-dialog.ko.js +0 -1
  156. package/dist/settings/dictionaries/settings-dialog.pl.js +0 -1
  157. package/dist/settings/dictionaries/settings-dialog.pt-BR.js +0 -1
  158. package/dist/settings/dictionaries/settings-dialog.ru.js +0 -1
  159. package/dist/settings/dictionaries/settings-dialog.th.js +0 -1
  160. package/dist/settings/dictionaries/settings-dialog.tr.js +0 -1
  161. package/dist/settings/dictionaries/settings-dialog.uk.js +0 -1
  162. package/dist/settings/dictionaries/settings-dialog.ur.js +0 -1
  163. package/dist/settings/dictionaries/settings-dialog.zh-CN.js +0 -1
  164. package/dist/settings/dictionaries/settings-dialog.zh-TW.js +0 -1
  165. package/dist/settings/ensure-definitions.d.ts +5 -5
  166. package/dist/settings/errors.d.ts +7 -1
  167. package/dist/settings/errors.js +7 -1
  168. package/dist/settings/index.d.ts +4 -1
  169. package/dist/settings/index.js +1 -0
  170. package/dist/settings/ports.d.ts +6 -5
  171. package/dist/settings/principal-lookup.d.ts +9 -0
  172. package/dist/settings/principal-lookup.js +2 -0
  173. package/dist/settings/purge-service.d.ts +5 -4
  174. package/dist/settings/purge-service.js +3 -2
  175. package/dist/settings/settings.d.ts +22 -7
  176. package/dist/settings/settings.js +47 -26
  177. package/dist/settings/tool-registrations.d.ts +25 -32
  178. package/dist/settings/tool-registrations.js +66 -56
  179. package/dist/settings/types.d.ts +1 -1
  180. package/dist/settings/ui-tab-definitions.d.ts +1 -1
  181. package/dist/settings/write-service.d.ts +32 -26
  182. package/dist/settings/write-service.js +26 -20
  183. package/dist/taxonomy/agent-tools.d.ts +1 -66
  184. package/dist/taxonomy/agent-tools.js +25 -15
  185. package/dist/taxonomy/content-lookup.js +1 -1
  186. package/dist/taxonomy/index.d.ts +2 -2
  187. package/dist/taxonomy/merge-term.d.ts +7 -4
  188. package/dist/taxonomy/merge-term.js +7 -5
  189. package/dist/taxonomy/repo.memory.d.ts +42 -19
  190. package/dist/taxonomy/repo.memory.js +14 -12
  191. package/dist/taxonomy/validation-chain.d.ts +39 -18
  192. package/dist/taxonomy/validation-chain.js +35 -25
  193. package/dist/taxonomy/write-service.d.ts +106 -45
  194. package/dist/taxonomy/write-service.js +221 -179
  195. package/dist/trash/adapters/record-store.d.ts +52 -0
  196. package/dist/trash/adapters/record-store.js +36 -0
  197. package/dist/trash/cursor.d.ts +20 -0
  198. package/dist/trash/cursor.js +36 -0
  199. package/dist/trash/follow-ups.d.ts +76 -0
  200. package/dist/trash/follow-ups.js +46 -0
  201. package/dist/trash/index.d.ts +8 -0
  202. package/dist/trash/index.js +8 -0
  203. package/dist/trash/ports.d.ts +308 -0
  204. package/dist/trash/ports.js +2 -0
  205. package/dist/trash/repo.memory.d.ts +50 -0
  206. package/dist/trash/repo.memory.js +114 -0
  207. package/dist/trash/sweeper.d.ts +77 -0
  208. package/dist/trash/sweeper.js +127 -0
  209. package/dist/trash/write-service.d.ts +100 -0
  210. package/dist/trash/write-service.js +242 -0
  211. package/dist/workspace/agent-tools.d.ts +1 -59
  212. package/dist/workspace/agent-tools.js +27 -12
  213. package/dist/workspace/create.d.ts +31 -6
  214. package/dist/workspace/create.js +18 -5
  215. package/dist/workspace/delete.d.ts +18 -13
  216. package/dist/workspace/delete.js +20 -12
  217. package/dist/workspace/index.d.ts +1 -1
  218. package/dist/workspace/repo.memory.d.ts +19 -4
  219. package/dist/workspace/repo.memory.js +26 -4
  220. package/dist/workspace/tool-registrations.d.ts +2 -2
  221. package/dist/workspace/tool-registrations.js +13 -13
  222. package/dist/workspace/update.d.ts +6 -5
  223. package/dist/workspace/update.js +9 -8
  224. package/package.json +44 -38
  225. package/dist/identity/admin-crud-service.d.ts +0 -280
  226. package/dist/identity/admin-crud-service.js +0 -468
  227. package/dist/identity/agent-tool-input.d.ts +0 -58
  228. package/dist/identity/agent-tool-input.js +0 -126
  229. package/dist/identity/agent-tools.d.ts +0 -101
  230. package/dist/identity/agent-tools.js +0 -290
  231. package/dist/identity/auth-service.d.ts +0 -118
  232. package/dist/identity/auth-service.js +0 -170
  233. package/dist/identity/authorize.d.ts +0 -90
  234. package/dist/identity/authorize.js +0 -94
  235. package/dist/identity/grant-service.d.ts +0 -198
  236. package/dist/identity/grant-service.js +0 -361
  237. package/dist/identity/hasher.d.ts +0 -39
  238. package/dist/identity/hasher.js +0 -39
  239. package/dist/identity/index.d.ts +0 -62
  240. package/dist/identity/index.js +0 -54
  241. package/dist/identity/password-policy.d.ts +0 -57
  242. package/dist/identity/password-policy.js +0 -66
  243. package/dist/identity/permission-migrations.d.ts +0 -86
  244. package/dist/identity/permission-migrations.js +0 -67
  245. package/dist/identity/permissions.d.ts +0 -35
  246. package/dist/identity/permissions.js +0 -603
  247. package/dist/identity/ports.d.ts +0 -201
  248. package/dist/identity/repo.memory.d.ts +0 -164
  249. package/dist/identity/repo.memory.js +0 -224
  250. package/dist/identity/seed.d.ts +0 -54
  251. package/dist/identity/seed.js +0 -429
  252. package/dist/identity/tool-registrations.d.ts +0 -50
  253. package/dist/identity/tool-registrations.js +0 -419
  254. package/dist/identity/types.d.ts +0 -185
  255. package/dist/identity/types.js +0 -64
  256. package/dist/identity/username.d.ts +0 -12
  257. package/dist/identity/username.js +0 -14
  258. /package/dist/{identity → media/import}/ports.js +0 -0
@@ -1,3 +1,4 @@
1
+ import { adaptLegacyAuthorize } from "../core/tools/index.js";
1
2
  /**
2
3
  * @file Navigation's (Menus') half of the agent-tool authorization wiring: maps `agent-tools.ts`'s five
3
4
  * catalog entries onto `menu-service.ts`'s read/create/update/assign operations, as
@@ -10,10 +11,11 @@
10
11
  * single evaluation for these tools, located where the real route locates it.
11
12
  */
12
13
  import { ToolInputError } from "@jini-ai/core";
13
- import { buildDomainRegistrations, indexCatalogById, requireInputRecord, requireNumber, requireString, requireToolPermission, withSchemaOnRejection, } from "../core/tools/registration-kit.js";
14
+ import { buildDomainRegistrations, indexCatalogById, requireInputRecord, requireNumber, requireString, withSchemaOnRejection } from "@jini-ai/core";
15
+ import { requireToolPermission } from "../core/tools/index.js";
14
16
  import { menusAgentToolCatalog } from "./agent-tools.js";
15
17
  import { assignLocation, createMenu, MenuNotFoundError, MenuValidationError, updateMenuTree } from "./menu-service.js";
16
- const CATALOG_BY_ID = indexCatalogById(menusAgentToolCatalog);
18
+ const CATALOG_BY_ID = indexCatalogById({ catalog: menusAgentToolCatalog });
17
19
  /**
18
20
  * This wiring layer's OWN risk classification, authored from what each handler below actually
19
21
  * calls. See `DerivedRiskByToolId` in the kit for why it is independent of the catalog's own
@@ -62,65 +64,65 @@ function menusDeps(routeDeps) {
62
64
  export function buildMenusRegistrations(routeDeps) {
63
65
  const handlers = {
64
66
  menus_list_menus: async (ctx) => {
65
- await requireToolPermission(routeDeps, { principalId: ctx.principal.id, permission: "admin.menus.read", entityType: "menu" });
67
+ await requireToolPermission({ authorize: adaptLegacyAuthorize({ authorize: routeDeps.authorize }), workspaceId: routeDeps.workspaceId, principalId: ctx.principal.id, permission: "admin.menus.read" }, { entityType: "menu" });
66
68
  const menus = await routeDeps.menuRepo.list({ workspaceId: routeDeps.workspaceId });
67
69
  return { menus: menus.map(toMenuToolView) };
68
70
  },
69
71
  menus_get_menu: async (ctx) => {
70
- const menuId = requireString(requireInputRecord(ctx.input), "menuId");
71
- await requireToolPermission(routeDeps, { principalId: ctx.principal.id, permission: "admin.menus.read", entityType: "menu", entityId: menuId });
72
+ const menuId = requireString({ input: requireInputRecord({ input: ctx.input }), key: "menuId" });
73
+ await requireToolPermission({ authorize: adaptLegacyAuthorize({ authorize: routeDeps.authorize }), workspaceId: routeDeps.workspaceId, principalId: ctx.principal.id, permission: "admin.menus.read" }, { entityType: "menu", entityId: menuId });
72
74
  const menu = await routeDeps.menuRepo.findById({ workspaceId: routeDeps.workspaceId, id: menuId });
73
75
  if (!menu)
74
- throw new MenuNotFoundError(`menu '${menuId}' was not found`);
76
+ throw new MenuNotFoundError({ message: `menu '${menuId}' was not found` });
75
77
  return { menu: toMenuToolView(menu) };
76
78
  },
77
79
  menus_create_menu: async (ctx) => {
78
- const input = requireInputRecord(ctx.input);
79
- await requireToolPermission(routeDeps, { principalId: ctx.principal.id, permission: "admin.menus.create", entityType: "menu" });
80
+ const input = requireInputRecord({ input: ctx.input });
81
+ await requireToolPermission({ authorize: adaptLegacyAuthorize({ authorize: routeDeps.authorize }), workspaceId: routeDeps.workspaceId, principalId: ctx.principal.id, permission: "admin.menus.create" }, { entityType: "menu" });
80
82
  if (input.items !== undefined && !Array.isArray(input.items)) {
81
- throw new ToolInputError("'items' must be an array of nav items");
83
+ throw new ToolInputError({ message: "'items' must be an array of nav items" });
82
84
  }
83
- return withSchemaOnRejection({ toolId: "menus_create_menu", catalog: CATALOG_BY_ID, isShapeRejection: isMenusShapeRejection }, async () => {
84
- const { menu } = await createMenu({
85
- deps: menusDeps(routeDeps),
86
- input: {
87
- workspaceId: routeDeps.workspaceId,
88
- title: requireString(input, "title"),
89
- slug: requireString(input, "slug"),
90
- items: Array.isArray(input.items) ? input.items : undefined,
91
- },
92
- });
93
- return { menu: toMenuToolView(menu) };
94
- });
85
+ return withSchemaOnRejection({ toolId: "menus_create_menu", catalog: CATALOG_BY_ID, isShapeRejection: ({ error }) => isMenusShapeRejection(error), fn: async () => {
86
+ const { menu } = await createMenu({
87
+ deps: menusDeps(routeDeps),
88
+ input: {
89
+ workspaceId: routeDeps.workspaceId,
90
+ title: requireString({ input: input, key: "title" }),
91
+ slug: requireString({ input: input, key: "slug" }),
92
+ items: Array.isArray(input.items) ? input.items : undefined,
93
+ },
94
+ });
95
+ return { menu: toMenuToolView(menu) };
96
+ } });
95
97
  },
96
98
  menus_update_menu_tree: async (ctx) => {
97
- const input = requireInputRecord(ctx.input);
98
- const menuId = requireString(input, "menuId");
99
- await requireToolPermission(routeDeps, { principalId: ctx.principal.id, permission: "admin.menus.update", entityType: "menu", entityId: menuId });
99
+ const input = requireInputRecord({ input: ctx.input });
100
+ const menuId = requireString({ input: input, key: "menuId" });
101
+ await requireToolPermission({ authorize: adaptLegacyAuthorize({ authorize: routeDeps.authorize }), workspaceId: routeDeps.workspaceId, principalId: ctx.principal.id, permission: "admin.menus.update" }, { entityType: "menu", entityId: menuId });
100
102
  if (!Array.isArray(input.items))
101
103
  throw new Error("'items' (array) is required");
102
- return withSchemaOnRejection({ toolId: "menus_update_menu_tree", catalog: CATALOG_BY_ID, isShapeRejection: isMenusShapeRejection }, async () => {
103
- const { menu } = await updateMenuTree({
104
- deps: menusDeps(routeDeps),
105
- input: {
106
- workspaceId: routeDeps.workspaceId,
107
- id: menuId,
108
- expectedVersion: requireNumber(input, "expectedVersion"),
109
- title: typeof input.title === "string" ? input.title : undefined,
110
- slug: typeof input.slug === "string" ? input.slug : undefined,
111
- items: input.items,
112
- },
113
- });
114
- return { menu: toMenuToolView(menu) };
115
- });
104
+ return withSchemaOnRejection({ toolId: "menus_update_menu_tree", catalog: CATALOG_BY_ID, isShapeRejection: ({ error }) => isMenusShapeRejection(error), fn: async () => {
105
+ const { menu } = await updateMenuTree({
106
+ deps: menusDeps(routeDeps),
107
+ input: {
108
+ workspaceId: routeDeps.workspaceId,
109
+ id: menuId,
110
+ expectedVersion: requireNumber({ input: input, key: "expectedVersion" }),
111
+ title: typeof input.title === "string" ? input.title : undefined,
112
+ slug: typeof input.slug === "string" ? input.slug : undefined,
113
+ items: input.items,
114
+ },
115
+ });
116
+ return { menu: toMenuToolView(menu) };
117
+ } });
116
118
  },
117
119
  menus_assign_location: async (ctx) => {
118
- const input = requireInputRecord(ctx.input);
119
- const menuId = requireString(input, "menuId");
120
- await requireToolPermission(routeDeps, { principalId: ctx.principal.id, permission: "admin.menus.assign", entityType: "menu", entityId: menuId });
120
+ const input = requireInputRecord({ input: ctx.input });
121
+ const menuId = requireString({ input: input, key: "menuId" });
122
+ await requireToolPermission({ authorize: adaptLegacyAuthorize({ authorize: routeDeps.authorize }), workspaceId: routeDeps.workspaceId, principalId: ctx.principal.id, permission: "admin.menus.assign" }, { entityType: "menu", entityId: menuId });
121
123
  const { menu, binding, displacedMenu } = await assignLocation({
122
124
  deps: { ...menusDeps(routeDeps), bindingRepo: routeDeps.navLocationBindingRepo },
123
- input: { workspaceId: routeDeps.workspaceId, menuId, locationKey: requireString(input, "locationKey") },
125
+ input: { workspaceId: routeDeps.workspaceId, menuId, locationKey: requireString({ input: input, key: "locationKey" }) },
124
126
  });
125
127
  return {
126
128
  menu: toMenuToolView(menu),
@@ -22,7 +22,7 @@
22
22
  * this library introduces; the entries repo, revisions, `entry_refs`, and the command
23
23
  * gateway are reused unchanged from the generic entries model.
24
24
  */
25
- import type { ISODateTime, JsonObject, UUID } from "../core/ports.js";
25
+ import type { ISODateTime, JsonObject, UUID } from "@jini-ai/core/primitives";
26
26
  /**
27
27
  * `menu` ships as a **seeded content-type registry row**, like
28
28
  * `post`/`page`/`media`. Core may special-case it in admin UI/rendering, never
@@ -1,4 +1,4 @@
1
- import type { ClockPort, UUID } from "../core/ports.js";
1
+ import type { Clock, UUID } from "@jini-ai/core/primitives";
2
2
  /**
3
3
  * @file Presentation settings — the active-theme identity of a workspace.
4
4
  *
@@ -22,7 +22,9 @@ export interface PresentationSettingsRecord {
22
22
  updatedAt: string;
23
23
  }
24
24
  export interface PresentationSettingsRepoPort {
25
- findByWorkspaceId(workspaceId: UUID): Promise<PresentationSettingsRecord | null>;
25
+ findByWorkspaceId({ workspaceId }: {
26
+ workspaceId: UUID;
27
+ }): Promise<PresentationSettingsRecord | null>;
26
28
  save(record: PresentationSettingsRecord): Promise<void>;
27
29
  /**
28
30
  * Every row across every workspace, for the one-time
@@ -43,7 +45,7 @@ export interface GetPresentationSettingsRequired {
43
45
  };
44
46
  }
45
47
  export interface SetActiveThemeDeps {
46
- clock: ClockPort;
48
+ clock: Clock;
47
49
  repo: PresentationSettingsRepoPort;
48
50
  /** Discovered valid theme ids; falls back to ALLOWED_THEME_IDS when absent. */
49
51
  availableThemeIds?: readonly string[] | undefined;
@@ -58,8 +60,14 @@ export interface SetActiveThemeRequired {
58
60
  export interface PresentationOptional {
59
61
  }
60
62
  export declare class PresentationSettingsNotFoundError extends Error {
63
+ constructor({ message }: {
64
+ message: string;
65
+ }, optionalArgs?: ErrorOptions);
61
66
  }
62
67
  export declare class PresentationSettingsValidationError extends Error {
68
+ constructor({ message }: {
69
+ message: string;
70
+ }, optionalArgs?: ErrorOptions);
63
71
  }
64
72
  export declare function getPresentationSettings(required: GetPresentationSettingsRequired, _optional?: PresentationOptional): Promise<{
65
73
  settings: PresentationSettingsRecord;
@@ -1,3 +1,4 @@
1
+ import { nowIso as kernelNowIso } from "@jini-ai/core/primitives";
1
2
  /**
2
3
  * @file Presentation settings — the active-theme identity of a workspace.
3
4
  *
@@ -14,13 +15,19 @@
14
15
  */
15
16
  export const ALLOWED_THEME_IDS = ["paper", "atlas", "glassmorphic"];
16
17
  export class PresentationSettingsNotFoundError extends Error {
18
+ constructor({ message }, optionalArgs = {}) {
19
+ super(message, optionalArgs);
20
+ }
17
21
  }
18
22
  export class PresentationSettingsValidationError extends Error {
23
+ constructor({ message }, optionalArgs = {}) {
24
+ super(message, optionalArgs);
25
+ }
19
26
  }
20
27
  export async function getPresentationSettings(required, _optional = {}) {
21
- const settings = await required.deps.repo.findByWorkspaceId(required.input.workspaceId);
28
+ const settings = await required.deps.repo.findByWorkspaceId({ workspaceId: required.input.workspaceId });
22
29
  if (!settings) {
23
- throw new PresentationSettingsNotFoundError(`presentation settings for workspace '${required.input.workspaceId}' were not found`);
30
+ throw new PresentationSettingsNotFoundError({ message: `presentation settings for workspace '${required.input.workspaceId}' were not found` });
24
31
  }
25
32
  return {
26
33
  settings,
@@ -31,16 +38,16 @@ export async function setActiveTheme(required, _optional = {}) {
31
38
  const { deps, input } = required;
32
39
  const allowed = deps.availableThemeIds ?? ALLOWED_THEME_IDS;
33
40
  if (!allowed.includes(input.activeThemeId)) {
34
- throw new PresentationSettingsValidationError(`theme '${input.activeThemeId}' is not supported`);
41
+ throw new PresentationSettingsValidationError({ message: `theme '${input.activeThemeId}' is not supported` });
35
42
  }
36
- const existing = await deps.repo.findByWorkspaceId(input.workspaceId);
43
+ const existing = await deps.repo.findByWorkspaceId({ workspaceId: input.workspaceId });
37
44
  if (!existing) {
38
- throw new PresentationSettingsNotFoundError(`presentation settings for workspace '${input.workspaceId}' were not found`);
45
+ throw new PresentationSettingsNotFoundError({ message: `presentation settings for workspace '${input.workspaceId}' were not found` });
39
46
  }
40
47
  const settings = {
41
48
  ...existing,
42
49
  activeThemeId: input.activeThemeId,
43
- updatedAt: deps.clock.nowIso(),
50
+ updatedAt: kernelNowIso({ clock: deps.clock }),
44
51
  };
45
52
  await deps.repo.save(settings);
46
53
  return {
@@ -1,8 +1,12 @@
1
1
  import type { PresentationSettingsRecord, PresentationSettingsRepoPort } from "./presentation.js";
2
2
  export declare class InMemoryPresentationSettingsRepo implements PresentationSettingsRepoPort {
3
3
  private rows;
4
- constructor(initialRows?: PresentationSettingsRecord[]);
5
- findByWorkspaceId(workspaceId: string): Promise<PresentationSettingsRecord | null>;
4
+ constructor(requiredArgs: Record<string, never>, optionalArgs?: {
5
+ initialRows?: PresentationSettingsRecord[];
6
+ });
7
+ findByWorkspaceId({ workspaceId }: {
8
+ workspaceId: string;
9
+ }): Promise<PresentationSettingsRecord | null>;
6
10
  save(record: PresentationSettingsRecord): Promise<void>;
7
11
  listAll(): Promise<PresentationSettingsRecord[]>;
8
12
  }
@@ -1,9 +1,10 @@
1
1
  export class InMemoryPresentationSettingsRepo {
2
2
  rows;
3
- constructor(initialRows = []) {
3
+ constructor(requiredArgs, optionalArgs = {}) {
4
+ const { initialRows = [] } = optionalArgs;
4
5
  this.rows = [...initialRows];
5
6
  }
6
- async findByWorkspaceId(workspaceId) {
7
+ async findByWorkspaceId({ workspaceId }) {
7
8
  return this.rows.find((row) => row.workspaceId === workspaceId) ?? null;
8
9
  }
9
10
  async save(record) {
@@ -1,79 +1,6 @@
1
+ import type { AgentToolDefinition } from "@jini-ai/core";
1
2
  /**
2
- * @file The Settings domain's agent-tool catalog, instantiating the naming/callability
3
- * convention every other domain catalog in this package already uses.
4
- *
5
- * Purpose:
6
- * A static, in-process catalog describing every agent-callable tool this domain exposes. Settings
7
- * is, by design, a broad key/value surface — a typical human admin screen for it is an uncurated,
8
- * free-text editor: the operator types ANY namespace string to load it and edits values through a
9
- * raw-JSON textarea, with no schema-exposing endpoint feeding a typed control. There is no fixed,
10
- * curated list of named settings on that surface to wire tools against.
11
- *
12
- * That disqualifies every GENERIC write in this domain from being wired here:
13
- * - `SETTINGS_SET`/`SETTINGS_CLEAR` let a caller write/clear the value of any registered
14
- * namespace+key at any scope it can name — exactly the generic "set any setting key" tool this
15
- * dispatch's brief prohibits outright, regardless of the write path's own schema validation
16
- * (validation constrains VALUE shape, not WHICH key can be targeted).
17
- *
18
- * One curated write IS wired, and it is not a weaker `settings_set`: `ui-tab-definitions.ts`
19
- * registers a fixed, statically-declared list, because the settings-dialog tabs need named keys to
20
- * bind to. `SETTINGS_SET_UI_PREFERENCE` below wires a seven-key subset of that list
21
- * (`agent-writable-preferences.ts`):
22
- *
23
- * - Its `setting` parameter is a JSON Schema `enum`, so WHICH key is targeted is constrained by
24
- * the same mechanism as everything else — the exact gap the paragraph above identifies. The
25
- * ledger's registered definition schema still bounds the VALUE, so both halves are covered.
26
- * - It exposes no `scope` and no `principalId`. Every write is `scope: "user"` against the
27
- * caller's own principal, which derives `settings.user.self.write` — the narrowest write grant
28
- * in the system — and makes writing another operator's preferences unrepresentable rather than
29
- * merely unauthorized.
30
- * - The keys are per-operator display preferences (locale, theme, accent, notification sounds),
31
- * each reversible in one call and visible in the admin UI the moment it changes.
32
- *
33
- * The generic setter stays excluded, permanently and for its original reason. Nothing above is
34
- * evidence that the other three writes may now be wired:
35
- * - `SETTINGS_RESET` is broader still: a single call clears every value in an operator-named
36
- * namespace at a scope — typically described in a host's own confirmation dialog as
37
- * irreversible.
38
- * - `SETTINGS_REGISTER_DEFINITIONS` is schema-level, not value-level: it can rename/retype/
39
- * deprecate/tombstone the DEFINITION a key resolves through, changing how every existing stored
40
- * value for that key is interpreted platform-wide.
41
- *
42
- * Reads are a different risk class and are wired: `SETTINGS_LIST_DEFINITIONS`/
43
- * `SETTINGS_GET_EFFECTIVE`/`SETTINGS_GET_RAW` cannot mutate anything, are gated by the same real
44
- * `authorize()` permissions an admin UI's own reads use (including the cross-principal
45
- * `settings.user.read` check), and cannot surface a secret value even in principle —
46
- * `settings.ts`'s `validateDefinitionInput` unconditionally refuses `secret:true` at registration
47
- * time (REQ-09/INV-08), so no secret setting can exist in this library's current state to leak.
48
- *
49
- * How it relates to a host:
50
- * A host's tool-registration layer consumes this catalog to decide which tool names an agent
51
- * session may even see; `authorize()` enforces the actual permission checks at call time — this
52
- * module only declares the catalog shape, it performs no I/O and no enforcement itself.
53
- *
54
- * Architectural role:
55
- * `settings` domain logic. Depends only on its own sibling `agent-writable-preferences.ts` (for
56
- * the curated write's enum) — no I/O, no enforcement.
57
- */
58
- export type AgentToolSideEffect = "none" | "mutates-durable-state" | "mints-token";
59
- export interface AgentToolDefinition {
60
- name: string;
61
- description: string;
62
- sideEffects: AgentToolSideEffect;
63
- authorization: {
64
- permission: string;
65
- };
66
- /**
67
- * JSON Schema for this tool's `input`, published to the model via `ToolDescriptor.inputSchema`
68
- * (a host's tool-registration layer refuses to wire any tool lacking one). Optional — the four
69
- * write entries this file documents but never wires (see file header) carry no schema at all,
70
- * since one is never published for a tool the model never sees.
71
- */
72
- inputSchema?: Readonly<Record<string, unknown>>;
73
- }
74
- /**
75
- * The Settings domain's fixed agent-tool catalog — the three reads, one curated write
76
- * (`settings_set_ui_preference`), and four generic writes documented but deliberately never
3
+ * The Settings domain's fixed agent-tool catalog — three reads, three bounded writes, and two bulk/schema writes documented but never
77
4
  * wired. See file header.
78
5
  *
79
6
  * @complexity O(1) — a fixed, statically-defined list.
@@ -9,54 +9,47 @@
9
9
  * raw-JSON textarea, with no schema-exposing endpoint feeding a typed control. There is no fixed,
10
10
  * curated list of named settings on that surface to wire tools against.
11
11
  *
12
- * That disqualifies every GENERIC write in this domain from being wired here:
13
- * - `SETTINGS_SET`/`SETTINGS_CLEAR` let a caller write/clear the value of any registered
14
- * namespace+key at any scope it can name — exactly the generic "set any setting key" tool this
15
- * dispatch's brief prohibits outright, regardless of the write path's own schema validation
16
- * (validation constrains VALUE shape, not WHICH key can be targeted).
12
+ * The original generic-write exclusion correctly observed that schema validation bounds VALUE
13
+ * shape, not WHICH key may be targeted. The owner reversed permanent exclusion on 2026-10-01:
14
+ * settings_set_value/settings_clear_value now address one registered workspace or caller-owned
15
+ * user override. Explicit key policy bounds the target; privacy consent and the assistant's own
16
+ * instructions require a HUMAN confirmation port (the agent cannot self-confirm). Hosts add
17
+ * runtime/permission policies through the same seam. Headless protected writes fail closed.
18
+ * Ordinary settings apply directly and remain undoable using the returned previous override.
17
19
  *
18
- * One curated write IS wired, and it is not a weaker `settings_set`: `ui-tab-definitions.ts`
19
- * registers a fixed, statically-declared list, because the settings-dialog tabs need named keys to
20
- * bind to. `SETTINGS_SET_UI_PREFERENCE` below wires a seven-key subset of that list
21
- * (`agent-writable-preferences.ts`):
20
+ * settings_set_ui_preference remains the fixed seven-key, caller-only display-preference surface.
21
+ * It cannot reach consent or standing instructions; use the generic tools and a human card there.
22
22
  *
23
- * - Its `setting` parameter is a JSON Schema `enum`, so WHICH key is targeted is constrained by
24
- * the same mechanism as everything else — the exact gap the paragraph above identifies. The
25
- * ledger's registered definition schema still bounds the VALUE, so both halves are covered.
26
- * - It exposes no `scope` and no `principalId`. Every write is `scope: "user"` against the
27
- * caller's own principal, which derives `settings.user.self.write` — the narrowest write grant
28
- * in the system — and makes writing another operator's preferences unrepresentable rather than
29
- * merely unauthorized.
30
- * - The keys are per-operator display preferences (locale, theme, accent, notification sounds),
31
- * each reversible in one call and visible in the admin UI the moment it changes.
32
- *
33
- * The generic setter stays excluded, permanently and for its original reason. Nothing above is
34
- * evidence that the other three writes may now be wired:
35
- * - `SETTINGS_RESET` is broader still: a single call clears every value in an operator-named
36
- * namespace at a scope — typically described in a host's own confirmation dialog as
37
- * irreversible.
38
- * - `SETTINGS_REGISTER_DEFINITIONS` is schema-level, not value-level: it can rename/retype/
39
- * deprecate/tombstone the DEFINITION a key resolves through, changing how every existing stored
40
- * value for that key is interpreted platform-wide.
23
+ * The broader operations remain excluded:
24
+ * - SETTINGS_RESET clears every value in a namespace at once, an irreversible bulk operation.
25
+ * - SETTINGS_REGISTER_DEFINITIONS can retype/rename/tombstone definitions and reinterpret values
26
+ * platform-wide. Neither gets wired by the value-write decision.
41
27
  *
42
28
  * Reads are a different risk class and are wired: `SETTINGS_LIST_DEFINITIONS`/
43
29
  * `SETTINGS_GET_EFFECTIVE`/`SETTINGS_GET_RAW` cannot mutate anything, are gated by the same real
44
- * `authorize()` permissions an admin UI's own reads use (including the cross-principal
30
+ * `authorize` permissions an admin UI's own reads use (including the cross-principal
45
31
  * `settings.user.read` check), and cannot surface a secret value even in principle —
46
32
  * `settings.ts`'s `validateDefinitionInput` unconditionally refuses `secret:true` at registration
47
- * time (REQ-09/INV-08), so no secret setting can exist in this library's current state to leak.
33
+ * time, so no secret setting can exist in this library's current state to leak.
48
34
  *
49
35
  * How it relates to a host:
50
36
  * A host's tool-registration layer consumes this catalog to decide which tool names an agent
51
- * session may even see; `authorize()` enforces the actual permission checks at call time — this
37
+ * session may even see; `authorize` enforces the actual permission checks at call time — this
52
38
  * module only declares the catalog shape, it performs no I/O and no enforcement itself.
53
39
  *
54
40
  * Architectural role:
55
41
  * `settings` domain logic. Depends only on its own sibling `agent-writable-preferences.ts` (for
56
42
  * the curated write's enum) — no I/O, no enforcement.
43
+ * See docs/decisions/DR-003-settings-ledger-invariants.md.
57
44
  */
58
45
  import { AGENT_WRITABLE_PREFERENCE_IDS, AGENT_WRITABLE_PREFERENCES } from "./agent-writable-preferences.js";
59
- /** No arguments — `settings_list_definitions` takes none; it always enumerates the caller's own
46
+ /**
47
+ * JSON Schema for this tool's `input`, published to the model via `ToolDescriptor.inputSchema`
48
+ * (a host's tool-registration layer refuses to wire any tool lacking one). Optional — the two bulk/schema
49
+ * write entries this file documents but never wires (see file header) carry no schema at all,
50
+ * since one is never published for a tool the model never sees.
51
+ *
52
+ * No arguments — `settings_list_definitions` takes none; it always enumerates the caller's own
60
53
  * (boot-wired) workspace's site-owned partition plus the shared platform partition. */
61
54
  const NO_INPUT_SCHEMA = {
62
55
  type: "object",
@@ -118,9 +111,24 @@ const SET_UI_PREFERENCE_SCHEMA = {
118
111
  },
119
112
  },
120
113
  };
114
+ /** Both generic writes target only this workspace or the caller's own user layer. */
115
+ const CLEAR_VALUE_SCHEMA = {
116
+ type: "object",
117
+ additionalProperties: false,
118
+ required: ["namespace", "key"],
119
+ properties: {
120
+ namespace: { type: "string", minLength: 1, description: "A registered settings namespace; call settings_list_definitions first." },
121
+ key: { type: "string", minLength: 1, description: "A registered key inside the namespace." },
122
+ scope: { type: "string", enum: ["workspace", "user"], default: "workspace", description: "Workspace override, or only the calling operator's own user override." },
123
+ },
124
+ };
125
+ const SET_VALUE_SCHEMA = {
126
+ ...CLEAR_VALUE_SCHEMA,
127
+ required: ["namespace", "key", "value"],
128
+ properties: { ...CLEAR_VALUE_SCHEMA.properties, value: { description: "Any JSON matching the definition schema returned by settings_list_definitions." } },
129
+ };
121
130
  /**
122
- * The Settings domain's fixed agent-tool catalog — the three reads, one curated write
123
- * (`settings_set_ui_preference`), and four generic writes documented but deliberately never
131
+ * The Settings domain's fixed agent-tool catalog — three reads, three bounded writes, and two bulk/schema writes documented but never
124
132
  * wired. See file header.
125
133
  *
126
134
  * @complexity O(1) — a fixed, statically-defined list.
@@ -130,7 +138,7 @@ export function getSettingsAgentToolCatalog() {
130
138
  return [
131
139
  {
132
140
  name: "settings_list_definitions",
133
- description: "Lists every active setting definition visible to this workspace (platform core/theme definitions plus this workspace's own site-owned definitions): namespace, key, owner kind, scope bitmask, status, and version. Metadata only — never a value.",
141
+ description: "Lists every active setting definition visible to this workspace (platform core/theme definitions plus this workspace's own site-owned definitions): namespace, key, owner kind, scope bitmask, status, version, schema, agentWritable and confirmationRequired. Use before writing a setting. Metadata only — never a value.",
134
142
  sideEffects: "none",
135
143
  authorization: { permission: "settings.read.definitions" },
136
144
  inputSchema: NO_INPUT_SCHEMA,
@@ -161,25 +169,21 @@ export function getSettingsAgentToolCatalog() {
161
169
  inputSchema: SET_UI_PREFERENCE_SCHEMA,
162
170
  },
163
171
  {
164
- // EXCLUDED BY DESIGN, never wired: see this file's header. Generic "set any setting key" —
165
- // a typical human admin UI for this domain is an uncurated free-text/raw-JSON editor, not a
166
- // fixed named list. `settings_set_ui_preference` above is the curated alternative and does
167
- // NOT make this one wireable: the whole difference is that its target key is enum-bounded.
168
- name: "settings_set",
169
- description: "Sets a setting's value at a scope. NEVER agent-callable — see file header.",
172
+ name: "settings_set_value",
173
+ description: "Sets one registered setting at workspace scope (default) or the caller's own user scope. Call settings_list_definitions for valid keys, schemas, scopes and confirmation policy. Returns {key, scope, previous, value, revisionSeq}; previous is the old override, or null if absent. Privacy, instructions and host-protected assistant settings need a human confirmation card; the agent cannot confirm itself. Rejects unknown/tombstoned keys, disallowed scopes, invalid values and missing permissions. Cannot write globally, target another operator, reset a namespace or change definitions.",
170
174
  sideEffects: "mutates-durable-state",
171
175
  authorization: { permission: "settings.workspace.write" },
176
+ inputSchema: SET_VALUE_SCHEMA,
172
177
  },
173
178
  {
174
- // EXCLUDED BY DESIGN, never wired: see this file's header. Same "generic key" exclusion as
175
- // settings_set.
176
- name: "settings_clear",
177
- description: "Clears a setting's value at a scope, reverting it to default. NEVER agent-callable — see file header.",
179
+ name: "settings_clear_value",
180
+ description: "Clears one setting override at workspace scope (default) or the caller's own user scope so the next layer/default applies. Use to put one setting back to its inherited value; not to reset a namespace or delete a definition. Returns {key, scope, previous, effective}; restore a non-null previous override with settings_set_value. Protected assistant settings require a human confirmation card. Rejects unknown/tombstoned keys, disallowed scopes and missing permissions; cannot target global or another operator's layer.",
178
181
  sideEffects: "mutates-durable-state",
179
182
  authorization: { permission: "settings.workspace.write" },
183
+ inputSchema: CLEAR_VALUE_SCHEMA,
180
184
  },
181
185
  {
182
- // EXCLUDED BY DESIGN, never wired: see this file's header. Bulk variant of settings_clear —
186
+ // EXCLUDED BY DESIGN, never wired: see this file's header. Bulk variant of a single-value clear —
183
187
  // clears every value in an operator-named namespace at a scope in one call, irreversible.
184
188
  name: "settings_reset",
185
189
  description: "Resets every setting in a namespace to defaults at a scope. NEVER agent-callable — see file header.",
@@ -0,0 +1,22 @@
1
+ import { type ToolExecutionContext, type ToolHandler } from "@jini-ai/core";
2
+ import type { JsonValue } from "@jini-ai/core/primitives";
3
+ import type { SettingsToolDeps } from "./tool-registrations.js";
4
+ export type SettingsValueWriteToolId = "settings_set_value" | "settings_clear_value";
5
+ /** Host-only port. This request is never an agent input and only the host's authenticated
6
+ * human transport may answer it. Returning true without a human violates this contract. */
7
+ export interface SettingsWriteConfirmation {
8
+ ctx: ToolExecutionContext;
9
+ toolId: SettingsValueWriteToolId;
10
+ namespace: string;
11
+ key: string;
12
+ scope: "workspace" | "user";
13
+ previous: JsonValue | null;
14
+ value?: JsonValue;
15
+ reason: string;
16
+ }
17
+ /** Builds one value-write handler. Effects: authorize -> raw read -> optional human card ->
18
+ * service write -> result. The service rechecks authorization and performs its normal transaction.
19
+ * @complexity O(value size + rule count) plus bounded repository calls and a human wait.
20
+ * @throws ToolInputError for invalid input, denied keys, absent/declined/stale confirmation. */
21
+ export declare function buildSettingsValueWriteHandler(deps: SettingsToolDeps, toolId: SettingsValueWriteToolId): ToolHandler;
22
+ //# sourceMappingURL=agent-value-write-tools.d.ts.map