@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,62 +1,4 @@
1
- /**
2
- * @file The Workspace domain's agent-tool catalog, instantiating this package's shared
3
- * naming/callability convention (the same shape every other domain catalog in this package
4
- * already uses).
5
- *
6
- * Purpose:
7
- * A static, in-process catalog describing every agent-callable tool this domain exposes and the
8
- * permission each one carries. This is the highest-stakes domain wired so far: a host's
9
- * `workspaceId` is fixed at process composition (a v1 install always has exactly one addressable
10
- * workspace row), so `create`/`delete` are deliberately excluded
11
- * outright rather than treated as ordinary CRUD:
12
- * - `CREATE_WORKSPACE` inserts a row no route can ever address afterwards (every other workspace
13
- * route resolves strictly against the boot-wired `workspaceId`, never a caller-supplied id)
14
- * — wiring it would let an agent mint permanently orphaned, unreferenceable rows with no
15
- * corresponding read/delete path back to them. Zero utility, non-zero clutter/spam surface.
16
- * - `DELETE_WORKSPACE` is INV-03-guarded to always refuse in v1 (there is only ever one row), but
17
- * the moment that guard's precondition changes (a second addressable workspace exists), the same
18
- * tool becomes a lever that can remove the only workspace scope a request can reach — whole-scope,
19
- * no per-domain undo, the same blast-radius class as a forward database migration or a backup
20
- * restore. Excluded by design, mirroring those two.
21
- * `UPDATE_WORKSPACE` is the one write kept: a narrow rename of `name`/`slug` on the single existing,
22
- * already-addressable workspace, no cascading effects (`id`/`createdAt` immutable by convention —
23
- * see `update.ts`), the same risk class as `identity_role_rename`.
24
- *
25
- * How it relates to the package:
26
- * A host's server-side tool filter consumes this catalog to decide which tool names an
27
- * agent session may even see; `authorize()` (the single-evaluator rule below) enforces the actual
28
- * permission checks at call time — this module only declares the catalog shape, it performs no
29
- * I/O and no enforcement itself.
30
- *
31
- * Architectural role:
32
- * `workspace` domain logic. No dependencies.
33
- */
34
- export type AgentToolSideEffect = "none" | "mutates-durable-state" | "mints-token";
35
- export type AgentToolActorClassRule = "confirmer-must-equal-own-delegatedBy" | "user-only" | "none";
36
- export interface AgentToolDefinition {
37
- name: string;
38
- description: string;
39
- sideEffects: AgentToolSideEffect;
40
- authorization: {
41
- permission: string;
42
- };
43
- actorClassRule?: AgentToolActorClassRule;
44
- /**
45
- * JSON Schema for this tool's `input`, published to the model via `ToolDescriptor.inputSchema`
46
- * by whichever host layer wires these tools (any such layer should refuse to wire a tool lacking
47
- * one). Optional, matching this package's other domain catalogs — the two entries this dispatch
48
- * leaves unwired (see file header) carry no schema at all, since one is never published for a
49
- * tool the model never sees.
50
- *
51
- * Deliberately not widened to `| undefined` (unlike most optional fields in this port) — this
52
- * type flows into `core/tools/registration-kit.ts`'s `WirableToolDefinition`, which declares both
53
- * this field and `actorClassRule` above without `| undefined`. Widening only this catalog's copy
54
- * would make it structurally incompatible with that shared interface under
55
- * `exactOptionalPropertyTypes`, the same reason `navigation`'s and `identity`'s catalogs leave
56
- * these two fields alone.
57
- */
58
- inputSchema?: Readonly<Record<string, unknown>>;
59
- }
1
+ import type { AgentToolDefinition } from "@jini-ai/core";
60
2
  /**
61
3
  * The Workspace domain's fixed agent-tool catalog.
62
4
  *
@@ -10,28 +10,43 @@
10
10
  * workspace row), so `create`/`delete` are deliberately excluded
11
11
  * outright rather than treated as ordinary CRUD:
12
12
  * - `CREATE_WORKSPACE` inserts a row no route can ever address afterwards (every other workspace
13
- * route resolves strictly against the boot-wired `workspaceId`, never a caller-supplied id)
14
- * — wiring it would let an agent mint permanently orphaned, unreferenceable rows with no
15
- * corresponding read/delete path back to them. Zero utility, non-zero clutter/spam surface.
16
- * - `DELETE_WORKSPACE` is INV-03-guarded to always refuse in v1 (there is only ever one row), but
17
- * the moment that guard's precondition changes (a second addressable workspace exists), the same
18
- * tool becomes a lever that can remove the only workspace scope a request can reach — whole-scope,
19
- * no per-domain undo, the same blast-radius class as a forward database migration or a backup
20
- * restore. Excluded by design, mirroring those two.
13
+ * route resolves strictly against the boot-wired `workspaceId`, never a caller-supplied id)
14
+ * — wiring it would let an agent mint permanently orphaned, unreferenceable rows with no
15
+ * corresponding read/delete path back to them. Zero utility, non-zero clutter/spam surface.
16
+ * - `DELETE_WORKSPACE` is -guarded to always refuse in v1 (there is only ever one row), but
17
+ * the moment that guard's precondition changes (a second addressable workspace exists), the same
18
+ * tool becomes a lever that can remove the only workspace scope a request can reach — whole-scope,
19
+ * no per-domain undo, the same blast-radius class as a forward database migration or a backup
20
+ * restore. Excluded by design, mirroring those two.
21
21
  * `UPDATE_WORKSPACE` is the one write kept: a narrow rename of `name`/`slug` on the single existing,
22
22
  * already-addressable workspace, no cascading effects (`id`/`createdAt` immutable by convention —
23
23
  * see `update.ts`), the same risk class as `identity_role_rename`.
24
24
  *
25
25
  * How it relates to the package:
26
26
  * A host's server-side tool filter consumes this catalog to decide which tool names an
27
- * agent session may even see; `authorize()` (the single-evaluator rule below) enforces the actual
27
+ * agent session may even see; `authorize` (the single-evaluator rule below) enforces the actual
28
28
  * permission checks at call time — this module only declares the catalog shape, it performs no
29
29
  * I/O and no enforcement itself.
30
30
  *
31
31
  * Architectural role:
32
32
  * `workspace` domain logic. No dependencies.
33
- */
34
- /** No arguments — `workspace_get` takes none; it always reports the caller's own boot-wired workspace. */
33
+ * See docs/decisions/DR-007-workspace-and-owner-floors.md.
34
+ *
35
+ *
36
+ * JSON Schema for this tool's `input`, published to the model via `ToolDescriptor.inputSchema`
37
+ * by whichever host layer wires these tools (any such layer should refuse to wire a tool lacking
38
+ * one). Optional, matching this package's other domain catalogs — the two entries this dispatch
39
+ * leaves unwired (see file header) carry no schema at all, since one is never published for a
40
+ * tool the model never sees.
41
+ *
42
+ * Deliberately not widened to `| undefined` (unlike most optional fields in this port) — this
43
+ * type flows into `@jini-ai/core`'s `registration-kit.ts`'s `AgentToolDefinition`, which declares both
44
+ * this field and `actorClassRule` above without `| undefined`. Widening only this catalog's copy
45
+ * would make it structurally incompatible with that shared interface under
46
+ * `exactOptionalPropertyTypes`, the same reason `navigation`'s and `identity`'s catalogs leave
47
+ * these two fields alone.
48
+ *
49
+ * No arguments — `workspace_get` takes none; it always reports the caller's own boot-wired workspace. */
35
50
  const NO_INPUT_SCHEMA = {
36
51
  type: "object",
37
52
  additionalProperties: false,
@@ -88,7 +103,7 @@ export function getWorkspaceAgentToolCatalog() {
88
103
  authorization: { permission: "workspace.manage" },
89
104
  },
90
105
  {
91
- // EXCLUDED BY DESIGN, never wired: see this file's header. INV-03-guarded to always refuse
106
+ // EXCLUDED BY DESIGN, never wired: see this file's header. -guarded to always refuse. See docs/decisions/DR-007-workspace-and-owner-floors.md.
92
107
  // today (v1 has exactly one workspace row), but the lever itself removes the only addressable
93
108
  // workspace scope the moment that guard's precondition ever changes — whole-scope,
94
109
  // irreversible, no per-domain undo. Same exclusion class as a forward database migration or a
@@ -1,4 +1,5 @@
1
- import type { ClockPort, IdGeneratorPort, OutboxPort, UUID } from "../core/ports.js";
1
+ import type { Clock, IdGenerator, UUID } from "@jini-ai/core/primitives";
2
+ import type { OutboxPort } from "../core/ports.js";
2
3
  /**
3
4
  * @file Workspace creation vertical slice (domain logic).
4
5
  *
@@ -33,8 +34,12 @@ export interface WorkspaceRecord {
33
34
  */
34
35
  export interface WorkspaceRepoPort {
35
36
  insert(record: WorkspaceRecord): Promise<void>;
36
- findBySlug(slug: string): Promise<WorkspaceRecord | null>;
37
- findById(id: UUID): Promise<WorkspaceRecord | null>;
37
+ findBySlug({ slug }: {
38
+ slug: string;
39
+ }): Promise<WorkspaceRecord | null>;
40
+ findById({ id }: {
41
+ id: UUID;
42
+ }): Promise<WorkspaceRecord | null>;
38
43
  /** A v1 install always has exactly one row (see `delete.ts`'s header);
39
44
  * the port itself is not limited to one. */
40
45
  list(): Promise<WorkspaceRecord[]>;
@@ -43,7 +48,15 @@ export interface WorkspaceRepoPort {
43
48
  update(record: WorkspaceRecord): Promise<void>;
44
49
  /** Callers (see `delete.ts`) must apply the last-workspace guard
45
50
  * themselves — this port method performs the row deletion only, no business rule. */
46
- delete(id: UUID): Promise<void>;
51
+ delete({ id }: {
52
+ id: UUID;
53
+ }): Promise<void>;
54
+ /** Optional for existing adapters; deletion needs this or an injected transaction.
55
+ * Serializes the entire count/guard/delete operation against competing deletions,
56
+ * rolling back on rejection. Durable adapters must cover all workspace writers. */
57
+ transaction?<T>(required: {
58
+ fn: () => Promise<T>;
59
+ }): Promise<T>;
47
60
  }
48
61
  /**
49
62
  * Shared `name`/`slug` validation — used by both `createWorkspace` below
@@ -68,8 +81,8 @@ export interface CreateWorkspaceInput {
68
81
  }
69
82
  /** Dependencies required by the create-workspace slice. */
70
83
  export interface CreateWorkspaceDeps {
71
- idGen: IdGeneratorPort;
72
- clock: ClockPort;
84
+ idGen: IdGenerator;
85
+ clock: Clock;
73
86
  repo: WorkspaceRepoPort;
74
87
  outbox: OutboxPort;
75
88
  }
@@ -83,12 +96,21 @@ export interface CreateWorkspaceOptional {
83
96
  }
84
97
  /** Thrown when incoming command data is invalid. */
85
98
  export declare class WorkspaceValidationError extends Error {
99
+ constructor({ message }: {
100
+ message: string;
101
+ }, optionalArgs?: ErrorOptions);
86
102
  }
87
103
  /** Thrown when uniqueness constraints are violated. */
88
104
  export declare class WorkspaceConflictError extends Error {
105
+ constructor({ message }: {
106
+ message: string;
107
+ }, optionalArgs?: ErrorOptions);
89
108
  }
90
109
  /** Thrown when a `:workspaceId` does not resolve to a row. */
91
110
  export declare class WorkspaceNotFoundError extends Error {
111
+ constructor({ message }: {
112
+ message: string;
113
+ }, optionalArgs?: ErrorOptions);
92
114
  }
93
115
  /**
94
116
  * Thrown when `deleteWorkspace` (`delete.ts`) would remove the install's
@@ -98,6 +120,9 @@ export declare class WorkspaceNotFoundError extends Error {
98
120
  * from `IdentityForbiddenError` for the identical reason (typed-reason clarity).
99
121
  */
100
122
  export declare class WorkspaceLastRemainingError extends Error {
123
+ constructor({ message }: {
124
+ message: string;
125
+ }, optionalArgs?: ErrorOptions);
101
126
  }
102
127
  /**
103
128
  * Execute create-workspace command.
@@ -1,3 +1,4 @@
1
+ import { nowIso as kernelNowIso } from "@jini-ai/core/primitives";
1
2
  /**
2
3
  * Shared `name`/`slug` validation — used by both `createWorkspace` below
3
4
  * and `updateWorkspace` (`update.ts`) so the two transitions can never drift on what counts as a
@@ -11,20 +12,29 @@ export function validateWorkspaceNameAndSlug(input) {
11
12
  const name = input.name.trim();
12
13
  const slug = input.slug.trim().toLowerCase();
13
14
  if (!name)
14
- throw new WorkspaceValidationError("name is required");
15
+ throw new WorkspaceValidationError({ message: "name is required" });
15
16
  if (!slug.match(/^[a-z0-9-]+$/)) {
16
- throw new WorkspaceValidationError("slug must use lowercase letters, numbers, and dashes");
17
+ throw new WorkspaceValidationError({ message: "slug must use lowercase letters, numbers, and dashes" });
17
18
  }
18
19
  return { name, slug };
19
20
  }
20
21
  /** Thrown when incoming command data is invalid. */
21
22
  export class WorkspaceValidationError extends Error {
23
+ constructor({ message }, optionalArgs = {}) {
24
+ super(message, optionalArgs);
25
+ }
22
26
  }
23
27
  /** Thrown when uniqueness constraints are violated. */
24
28
  export class WorkspaceConflictError extends Error {
29
+ constructor({ message }, optionalArgs = {}) {
30
+ super(message, optionalArgs);
31
+ }
25
32
  }
26
33
  /** Thrown when a `:workspaceId` does not resolve to a row. */
27
34
  export class WorkspaceNotFoundError extends Error {
35
+ constructor({ message }, optionalArgs = {}) {
36
+ super(message, optionalArgs);
37
+ }
28
38
  }
29
39
  /**
30
40
  * Thrown when `deleteWorkspace` (`delete.ts`) would remove the install's
@@ -34,6 +44,9 @@ export class WorkspaceNotFoundError extends Error {
34
44
  * from `IdentityForbiddenError` for the identical reason (typed-reason clarity).
35
45
  */
36
46
  export class WorkspaceLastRemainingError extends Error {
47
+ constructor({ message }, optionalArgs = {}) {
48
+ super(message, optionalArgs);
49
+ }
37
50
  }
38
51
  /**
39
52
  * Execute create-workspace command.
@@ -49,10 +62,10 @@ export class WorkspaceLastRemainingError extends Error {
49
62
  export async function createWorkspace(required, _optional = {}) {
50
63
  const { deps, input } = required;
51
64
  const { name, slug } = validateWorkspaceNameAndSlug(input);
52
- const existing = await deps.repo.findBySlug(slug);
65
+ const existing = await deps.repo.findBySlug({ slug: slug });
53
66
  if (existing)
54
- throw new WorkspaceConflictError(`slug '${slug}' already exists`);
55
- const now = deps.clock.nowIso();
67
+ throw new WorkspaceConflictError({ message: `slug '${slug}' already exists` });
68
+ const now = kernelNowIso({ clock: deps.clock });
56
69
  const id = deps.idGen.newId();
57
70
  await deps.repo.insert({ id, name, slug, createdAt: now });
58
71
  const event = {
@@ -1,4 +1,5 @@
1
- import type { UUID } from "../core/ports.js";
1
+ import type { TransactionalRepoPort } from "../taxonomy/write-service.js";
2
+ import type { UUID } from "@jini-ai/core/primitives";
2
3
  import { type WorkspaceRepoPort } from "./create.js";
3
4
  /**
4
5
  * @file `DELETE_WORKSPACE` — hard-delete a workspace, guarded so the
@@ -13,14 +14,15 @@ import { type WorkspaceRepoPort } from "./create.js";
13
14
  * works without further design.
14
15
  *
15
16
  * Architectural role:
16
- * Ordinary slice function — not a port. `deps.repo.list()` is the count source; the guard
17
- * check and the delete happen inside one `async` function body with no `await` yielded to another
18
- * caller in between the count read and the delete write, which — under a single Node.js
19
- * event-loop, no-concurrent-DB-transaction execution model (the same "atomic by construction"
20
- * reasoning `identity/grant-service.ts`'s own header comment documents for its transitions, and the
21
- * same model `DISABLE_PRINCIPAL`'s INV-08 count-check-then-disable already relies on) — is the
22
- * atomicity INV-03 requires. A future multi-process/multi-connection deployment would need a real
23
- * DB-level transaction here; flagged, not silently assumed away.
17
+ * Ordinary slice function — not a port. `deps.repo.list` is the count source; the guard
18
+ * check and the delete run in one transaction. The earlier single-Node-event-loop,
19
+ * "atomic by construction" reasoning (also used for `identity/grant-service.ts`'s transitions
20
+ * and `DISABLE_PRINCIPAL`'s count-check-then-disable) was insufficient: awaits can
21
+ * interleave even in one process. needs serialization across the count read and delete.
22
+ * The memory adapter queues transactions; a multi-process/multi-connection deployment needs
23
+ * a DB-level transaction that serializes all workspace writers, supplied by the host.
24
+ * Without the required transaction port, deletion fails closed before repository reads.
25
+ * See docs/decisions/DR-007-workspace-and-owner-floors.md.
24
26
  */
25
27
  /** Command payload for `DELETE_WORKSPACE`. */
26
28
  export interface DeleteWorkspaceInput {
@@ -29,6 +31,8 @@ export interface DeleteWorkspaceInput {
29
31
  /** Dependencies required by the delete-workspace slice. */
30
32
  export interface DeleteWorkspaceDeps {
31
33
  repo: WorkspaceRepoPort;
34
+ /** Required transaction; must serialize workspace writers on its store. */
35
+ transaction: TransactionalRepoPort["transaction"];
32
36
  }
33
37
  /** Required parameters for `deleteWorkspace`. */
34
38
  export interface DeleteWorkspaceRequired {
@@ -36,15 +40,16 @@ export interface DeleteWorkspaceRequired {
36
40
  input: DeleteWorkspaceInput;
37
41
  }
38
42
  /**
39
- * Execute `DELETE_WORKSPACE` (REQ-05). Throws `WorkspaceNotFoundError` if `input.id` does not
40
- * resolve to a row, else `WorkspaceLastRemainingError` (INV-03) if it is the only workspace row —
43
+ * Execute `DELETE_WORKSPACE`. Throws `WorkspaceNotFoundError` if `input.id` does not
44
+ * resolve to a row, else `WorkspaceLastRemainingError` if it is the only workspace row —
41
45
  * which is always true in v1, so this transition always refuses today. No row is deleted on either
42
46
  * rejection.
43
47
  *
44
- * @complexity O(n) in the total workspace count (`repo.list()`) — bounded by the same
45
- * operator-managed-roster assumption `identity`'s `PrincipalRepoPort.list()` already makes; not a
48
+ * @complexity O(n) in the total workspace count (`repo.list`) — bounded by the same
49
+ * operator-managed-roster assumption `identity`'s `PrincipalRepoPort.list` already makes; not a
46
50
  * caller-controlled collection.
47
51
  * @overallScore 100
52
+ * See docs/decisions/DR-007-workspace-and-owner-floors.md.
48
53
  */
49
54
  export declare function deleteWorkspace(required: DeleteWorkspaceRequired): Promise<void>;
50
55
  //# sourceMappingURL=delete.d.ts.map
@@ -1,24 +1,32 @@
1
1
  import { WorkspaceLastRemainingError, WorkspaceNotFoundError } from "./create.js";
2
2
  /**
3
- * Execute `DELETE_WORKSPACE` (REQ-05). Throws `WorkspaceNotFoundError` if `input.id` does not
4
- * resolve to a row, else `WorkspaceLastRemainingError` (INV-03) if it is the only workspace row —
3
+ * Execute `DELETE_WORKSPACE`. Throws `WorkspaceNotFoundError` if `input.id` does not
4
+ * resolve to a row, else `WorkspaceLastRemainingError` if it is the only workspace row —
5
5
  * which is always true in v1, so this transition always refuses today. No row is deleted on either
6
6
  * rejection.
7
7
  *
8
- * @complexity O(n) in the total workspace count (`repo.list()`) — bounded by the same
9
- * operator-managed-roster assumption `identity`'s `PrincipalRepoPort.list()` already makes; not a
8
+ * @complexity O(n) in the total workspace count (`repo.list`) — bounded by the same
9
+ * operator-managed-roster assumption `identity`'s `PrincipalRepoPort.list` already makes; not a
10
10
  * caller-controlled collection.
11
11
  * @overallScore 100
12
+ * See docs/decisions/DR-007-workspace-and-owner-floors.md.
12
13
  */
13
14
  export async function deleteWorkspace(required) {
14
15
  const { deps, input } = required;
15
- const existing = await deps.repo.findById(input.id);
16
- if (!existing)
17
- throw new WorkspaceNotFoundError(`workspace '${input.id}' was not found`);
18
- const all = await deps.repo.list();
19
- if (all.length <= 1) {
20
- throw new WorkspaceLastRemainingError("the install's last remaining workspace cannot be deleted (INV-03)");
21
- }
22
- await deps.repo.delete(input.id);
16
+ const transaction = deps.transaction;
17
+ if (!transaction)
18
+ throw new Error("workspace deletion requires a transaction port");
19
+ const guardedDelete = async () => {
20
+ const existing = await deps.repo.findById({ id: input.id });
21
+ if (!existing)
22
+ throw new WorkspaceNotFoundError({ message: `workspace '${input.id}' was not found` });
23
+ const all = await deps.repo.list();
24
+ if (all.length <= 1) {
25
+ // See docs/decisions/DR-007-workspace-and-owner-floors.md for the invariant behind this refusal; keep external identifiers out of caller-facing messages.
26
+ throw new WorkspaceLastRemainingError({ message: "the install's last remaining workspace cannot be deleted" });
27
+ }
28
+ await deps.repo.delete({ id: input.id });
29
+ };
30
+ await transaction({ fn: guardedDelete });
23
31
  }
24
32
  //# sourceMappingURL=delete.js.map
@@ -9,7 +9,7 @@ export { updateWorkspace, type UpdateWorkspaceDeps, type UpdateWorkspaceInput, t
9
9
  export { deleteWorkspace, type DeleteWorkspaceDeps, type DeleteWorkspaceInput, type DeleteWorkspaceRequired, } from "./delete.js";
10
10
  export { InMemoryWorkspaceRepo } from "./repo.memory.js";
11
11
  /** The agent-tool surface for this domain (see `agent-tools.ts` for what is deliberately omitted). */
12
- export { getWorkspaceAgentToolCatalog, type AgentToolDefinition as WorkspaceAgentToolDefinition, type AgentToolSideEffect as WorkspaceAgentToolSideEffect, type AgentToolActorClassRule as WorkspaceAgentToolActorClassRule, } from "./agent-tools.js";
12
+ export { getWorkspaceAgentToolCatalog, } from "./agent-tools.js";
13
13
  /**
14
14
  * The agent-tool wiring for this domain.
15
15
  *
@@ -17,18 +17,33 @@ import type { WorkspaceRecord, WorkspaceRepoPort } from "./create.js";
17
17
  export declare class InMemoryWorkspaceRepo implements WorkspaceRepoPort {
18
18
  /** Internal record storage. */
19
19
  private rows;
20
- constructor(initialRows?: WorkspaceRecord[]);
20
+ private transactionTail;
21
+ constructor(requiredArgs: Record<string, never>, optionalArgs?: {
22
+ initialRows?: WorkspaceRecord[];
23
+ });
21
24
  /** Insert one workspace record. */
22
25
  insert(record: WorkspaceRecord): Promise<void>;
23
26
  /** Find workspace by unique slug. */
24
- findBySlug(slug: string): Promise<WorkspaceRecord | null>;
27
+ findBySlug({ slug }: {
28
+ slug: string;
29
+ }): Promise<WorkspaceRecord | null>;
25
30
  /** Find workspace by id. */
26
- findById(id: string): Promise<WorkspaceRecord | null>;
31
+ findById({ id }: {
32
+ id: string;
33
+ }): Promise<WorkspaceRecord | null>;
27
34
  /** All workspace rows (v1 always has exactly one — see `delete.ts`'s header). */
28
35
  list(): Promise<WorkspaceRecord[]>;
29
36
  /** Replace the row matching `record.id` in place. */
30
37
  update(record: WorkspaceRecord): Promise<void>;
31
38
  /** Remove the row matching `id`, if present (idempotent). */
32
- delete(id: string): Promise<void>;
39
+ delete({ id }: {
40
+ id: string;
41
+ }): Promise<void>;
42
+ /** Serializes transactions on this instance, restoring rows on failure. Non-reentrant:
43
+ * callers must put every competing guarded deletion through this seam. Direct repo writes
44
+ * do not join or wait for it; this local adapter supplies no cross-process isolation. */
45
+ transaction<T>({ fn }: {
46
+ fn: () => Promise<T>;
47
+ }): Promise<T>;
33
48
  }
34
49
  //# sourceMappingURL=repo.memory.d.ts.map
@@ -16,7 +16,9 @@
16
16
  export class InMemoryWorkspaceRepo {
17
17
  /** Internal record storage. */
18
18
  rows;
19
- constructor(initialRows = []) {
19
+ transactionTail = Promise.resolve();
20
+ constructor(requiredArgs, optionalArgs = {}) {
21
+ const { initialRows = [] } = optionalArgs;
20
22
  this.rows = [...initialRows];
21
23
  }
22
24
  /** Insert one workspace record. */
@@ -24,11 +26,11 @@ export class InMemoryWorkspaceRepo {
24
26
  this.rows.push(record);
25
27
  }
26
28
  /** Find workspace by unique slug. */
27
- async findBySlug(slug) {
29
+ async findBySlug({ slug }) {
28
30
  return this.rows.find((row) => row.slug === slug) ?? null;
29
31
  }
30
32
  /** Find workspace by id. */
31
- async findById(id) {
33
+ async findById({ id }) {
32
34
  return this.rows.find((row) => row.id === id) ?? null;
33
35
  }
34
36
  /** All workspace rows (v1 always has exactly one — see `delete.ts`'s header). */
@@ -43,8 +45,28 @@ export class InMemoryWorkspaceRepo {
43
45
  this.rows[index] = record;
44
46
  }
45
47
  /** Remove the row matching `id`, if present (idempotent). */
46
- async delete(id) {
48
+ async delete({ id }) {
47
49
  this.rows = this.rows.filter((row) => row.id !== id);
48
50
  }
51
+ /** Serializes transactions on this instance, restoring rows on failure. Non-reentrant:
52
+ * callers must put every competing guarded deletion through this seam. Direct repo writes
53
+ * do not join or wait for it; this local adapter supplies no cross-process isolation. */
54
+ async transaction({ fn }) {
55
+ const previous = this.transactionTail;
56
+ let release;
57
+ this.transactionTail = new Promise((resolve) => { release = resolve; });
58
+ await previous;
59
+ const before = this.rows.map((row) => ({ ...row }));
60
+ try {
61
+ return await fn();
62
+ }
63
+ catch (error) {
64
+ this.rows = before;
65
+ throw error;
66
+ }
67
+ finally {
68
+ release();
69
+ }
70
+ }
49
71
  }
50
72
  //# sourceMappingURL=repo.memory.js.map
@@ -14,13 +14,13 @@
14
14
  * `workspace.manage` check.
15
15
  */
16
16
  import type { AuthorizeFn } from "../core/commands/command.js";
17
- import { type DerivedRiskByToolId, type ToolRegistration } from "../core/tools/registration-kit.js";
17
+ import { type DerivedRiskByToolId, type ToolRegistration } from "@jini-ai/core";
18
18
  import type { WorkspaceRepoPort } from "./create.js";
19
19
  /**
20
20
  * The exact slice of a host's route-deps bag Workspace's tool handlers read. Declared structurally
21
21
  * (rather than importing any host's `RouteDeps`) so this module carries no back-edge into a
22
22
  * composition root. A host satisfies this structurally by passing its existing deps object;
23
- * nothing there changes.
23
+ * hosts bind the declared repository and authorization ports.
24
24
  */
25
25
  export interface WorkspaceToolDeps {
26
26
  authorize: AuthorizeFn;
@@ -1,7 +1,8 @@
1
- import { buildDomainRegistrations, indexCatalogById, optionalString, requireInputRecord, requireNoInput, requireToolPermission, } from "../core/tools/registration-kit.js";
1
+ import { buildDomainRegistrations, indexCatalogById, optionalString, requireInputRecord, requireNoInput } from "@jini-ai/core";
2
+ import { adaptLegacyAuthorize, requireToolPermission } from "../core/tools/index.js";
2
3
  import { getWorkspaceAgentToolCatalog } from "./agent-tools.js";
3
4
  import { updateWorkspace } from "./update.js";
4
- const CATALOG_BY_ID = indexCatalogById(getWorkspaceAgentToolCatalog());
5
+ const CATALOG_BY_ID = indexCatalogById({ catalog: getWorkspaceAgentToolCatalog() });
5
6
  /**
6
7
  * This wiring layer's OWN risk classification, authored from what each handler below actually
7
8
  * calls. See `DerivedRiskByToolId` in the kit for why it is independent of the catalog's own
@@ -14,7 +15,7 @@ export const workspaceDerivedRisk = new Map([
14
15
  ["workspace_get", "none"],
15
16
  // -> updateWorkspace (update.ts) -> repo.findById + repo.findBySlug + repo.update: validates,
16
17
  // checks slug uniqueness excluding the row itself, writes. No domain event enqueued (matches
17
- // update.ts's own header: REQ-04 doesn't ask for one).
18
+ // update.ts's own header: doesn't ask for one). See docs/decisions/DR-007-workspace-and-owner-floors.md.
18
19
  ["workspace_update", "mutates-durable-state"],
19
20
  ]);
20
21
  /** Workspace catalog entries this pass does not wire, and why — see `./agent-tools.ts`'s own per-entry comments for the full reasoning. */
@@ -23,7 +24,7 @@ const UNWIRED_WORKSPACE_TOOL_IDS = new Set([
23
24
  // resolves strictly against the boot-wired `workspaceId`) — zero utility, non-zero
24
25
  // orphaned-row/clutter surface.
25
26
  "workspace_create",
26
- // EXCLUDED BY DESIGN: INV-03-guarded to always refuse today, but the lever removes the only
27
+ // EXCLUDED BY DESIGN: -guarded to always refuse today, but the lever removes the only. See docs/decisions/DR-007-workspace-and-owner-floors.md.
27
28
  // addressable workspace scope the moment that guard's precondition ever changes — whole-scope,
28
29
  // no per-domain undo, same exclusion class as a forward database migration or a backup restore.
29
30
  "workspace_delete",
@@ -31,9 +32,9 @@ const UNWIRED_WORKSPACE_TOOL_IDS = new Set([
31
32
  export function buildWorkspaceRegistrations(routeDeps) {
32
33
  const handlers = {
33
34
  workspace_get: async (ctx) => {
34
- requireNoInput(ctx.input);
35
- await requireToolPermission(routeDeps, { principalId: ctx.principal.id, permission: "workspace.manage", entityType: "workspace" });
36
- const workspace = await routeDeps.workspaceRepo.findById(routeDeps.workspaceId);
35
+ requireNoInput({ input: ctx.input });
36
+ await requireToolPermission({ authorize: adaptLegacyAuthorize({ authorize: routeDeps.authorize }), workspaceId: routeDeps.workspaceId, principalId: ctx.principal.id, permission: "workspace.manage" }, { entityType: "workspace" });
37
+ const workspace = await routeDeps.workspaceRepo.findById({ id: routeDeps.workspaceId });
37
38
  if (!workspace) {
38
39
  // Defensive: the boot-wired workspaceId always resolves to a real row by construction.
39
40
  // Not an expected runtime path.
@@ -42,8 +43,8 @@ export function buildWorkspaceRegistrations(routeDeps) {
42
43
  return { workspace };
43
44
  },
44
45
  workspace_update: async (ctx) => {
45
- const input = requireInputRecord(ctx.input);
46
- await requireToolPermission(routeDeps, { principalId: ctx.principal.id, permission: "workspace.manage", entityType: "workspace" });
46
+ const input = requireInputRecord({ input: ctx.input });
47
+ await requireToolPermission({ authorize: adaptLegacyAuthorize({ authorize: routeDeps.authorize }), workspaceId: routeDeps.workspaceId, principalId: ctx.principal.id, permission: "workspace.manage" }, { entityType: "workspace" });
47
48
  // WorkspaceValidationError/WorkspaceConflictError/WorkspaceNotFoundError (all real `Error`
48
49
  // subclasses, see `create.ts`) propagate as-is — a `ToolExecutor` treats any thrown error as
49
50
  // a failed execution, matching every other domain's handler convention of not rewrapping
@@ -52,8 +53,8 @@ export function buildWorkspaceRegistrations(routeDeps) {
52
53
  deps: { repo: routeDeps.workspaceRepo },
53
54
  input: {
54
55
  id: routeDeps.workspaceId,
55
- name: optionalString(input, "name"),
56
- slug: optionalString(input, "slug"),
56
+ name: optionalString({ input, key: "name" }),
57
+ slug: optionalString({ input, key: "slug" }),
57
58
  },
58
59
  });
59
60
  return { workspace };
@@ -65,7 +66,6 @@ export function buildWorkspaceRegistrations(routeDeps) {
65
66
  catalog: CATALOG_BY_ID,
66
67
  handlers,
67
68
  derivedRisk: workspaceDerivedRisk,
68
- unwiredToolIds: UNWIRED_WORKSPACE_TOOL_IDS,
69
- });
69
+ }, { unwiredToolIds: UNWIRED_WORKSPACE_TOOL_IDS });
70
70
  }
71
71
  //# sourceMappingURL=tool-registrations.js.map
@@ -1,4 +1,4 @@
1
- import type { UUID } from "../core/ports.js";
1
+ import type { UUID } from "@jini-ai/core/primitives";
2
2
  import { type WorkspaceRecord, type WorkspaceRepoPort } from "./create.js";
3
3
  /**
4
4
  * @file `UPDATE_WORKSPACE` — rename a workspace's `name` and/or `slug`.
@@ -14,7 +14,7 @@ import { type WorkspaceRecord, type WorkspaceRepoPort } from "./create.js";
14
14
  * Ordinary slice function, not a port — one implementation, the rule-of-two doesn't
15
15
  * apply to business logic, only to the repo/outbox seams it calls through `WorkspaceRepoPort`.
16
16
  */
17
- /** Command payload for `UPDATE_WORKSPACE`. At least one of `name`/`slug` must be present (EC-01). */
17
+ /** Command payload for `UPDATE_WORKSPACE`. At least one of `name`/`slug` must be present. See docs/decisions/DR-007-workspace-and-owner-floors.md. */
18
18
  export interface UpdateWorkspaceInput {
19
19
  id: UUID;
20
20
  name?: string | undefined;
@@ -30,8 +30,8 @@ export interface UpdateWorkspaceRequired {
30
30
  input: UpdateWorkspaceInput;
31
31
  }
32
32
  /**
33
- * Execute `UPDATE_WORKSPACE` (REQ-04). At least one of `name`/`slug` must be present in the input
34
- * (EC-01 — an empty-object update is rejected, not a silent no-op, so a client-side bug that drops
33
+ * Execute `UPDATE_WORKSPACE`. At least one of `name`/`slug` must be present in the input
34
+ * ( — an empty-object update is rejected, not a silent no-op, so a client-side bug that drops
35
35
  * both fields fails loudly instead of masquerading as a successful save). When only one field is
36
36
  * given, the other keeps its current stored value; both are re-validated together through
37
37
  * `validateWorkspaceNameAndSlug` either way, so a `slug`-only update still catches a blank stored
@@ -39,12 +39,13 @@ export interface UpdateWorkspaceRequired {
39
39
  * rejects that, but re-validating both together — rather than only the changed field — keeps this
40
40
  * function's invariant identical to `createWorkspace`'s with no special-cased partial path).
41
41
  *
42
- * The slug-uniqueness check excludes the row being updated (EC-02 — a workspace is never "in
42
+ * The slug-uniqueness check excludes the row being updated ( — a workspace is never "in
43
43
  * conflict with itself"): `findBySlug` naturally excludes it whenever the row's own `id` matches,
44
44
  * since that's a no-op rename, not a collision with a *different* row.
45
45
  *
46
46
  * @complexity O(1) — one lookup by id, one lookup by slug, one write.
47
47
  * @overallScore 100
48
+ * See docs/decisions/DR-007-workspace-and-owner-floors.md.
48
49
  */
49
50
  export declare function updateWorkspace(required: UpdateWorkspaceRequired): Promise<{
50
51
  workspace: WorkspaceRecord;