@jini-ai/cms 0.3.11 → 0.4.1

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 (262) 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 +27 -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 +103 -44
  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/core/tools/registration-kit.d.ts +0 -346
  226. package/dist/core/tools/registration-kit.js +0 -426
  227. package/dist/identity/admin-crud-service.d.ts +0 -280
  228. package/dist/identity/admin-crud-service.js +0 -468
  229. package/dist/identity/agent-tool-input.d.ts +0 -58
  230. package/dist/identity/agent-tool-input.js +0 -126
  231. package/dist/identity/agent-tools.d.ts +0 -101
  232. package/dist/identity/agent-tools.js +0 -290
  233. package/dist/identity/auth-service.d.ts +0 -118
  234. package/dist/identity/auth-service.js +0 -170
  235. package/dist/identity/authorize.d.ts +0 -90
  236. package/dist/identity/authorize.js +0 -94
  237. package/dist/identity/grant-service.d.ts +0 -198
  238. package/dist/identity/grant-service.js +0 -361
  239. package/dist/identity/hasher.d.ts +0 -39
  240. package/dist/identity/hasher.js +0 -39
  241. package/dist/identity/index.d.ts +0 -62
  242. package/dist/identity/index.js +0 -54
  243. package/dist/identity/password-policy.d.ts +0 -57
  244. package/dist/identity/password-policy.js +0 -66
  245. package/dist/identity/permission-migrations.d.ts +0 -86
  246. package/dist/identity/permission-migrations.js +0 -67
  247. package/dist/identity/permissions.d.ts +0 -35
  248. package/dist/identity/permissions.js +0 -603
  249. package/dist/identity/ports.d.ts +0 -201
  250. package/dist/identity/repo.memory.d.ts +0 -164
  251. package/dist/identity/repo.memory.js +0 -224
  252. package/dist/identity/seed.d.ts +0 -54
  253. package/dist/identity/seed.js +0 -429
  254. package/dist/identity/tool-registrations.d.ts +0 -50
  255. package/dist/identity/tool-registrations.js +0 -419
  256. package/dist/identity/types.d.ts +0 -185
  257. package/dist/identity/types.js +0 -64
  258. package/dist/identity/username.d.ts +0 -12
  259. package/dist/identity/username.js +0 -14
  260. package/dist/server/index.d.ts +0 -28
  261. package/dist/server/index.js +0 -28
  262. /package/dist/{identity → media/import}/ports.js +0 -0
@@ -0,0 +1,154 @@
1
+ import { adaptLegacyAuthorize } from "../core/tools/index.js";
2
+ import { ToolInputError } from "@jini-ai/core";
3
+ import { ForbiddenError as PermissionDeniedError } from "../core/commands/command.js";
4
+ import { requireToolPermission } from "../core/tools/index.js";
5
+ import { AGENT_WRITE_CONFIRMATION_SETTINGS, AGENT_WRITE_DENIED_SETTINGS, findAgentWriteRule } from "./agent-write-denylist.js";
6
+ import { DefinitionNotFoundError, DefinitionTombstonedError, ForbiddenError, ScopeNotAllowedError, ValueValidationFailedError } from "./errors.js";
7
+ import { getEffective, resolveDefinitionRaw, validateValueAgainstSchema } from "./settings.js";
8
+ import { SCOPE_BIT } from "./types.js";
9
+ import { clear, deriveRequiredPermission, set } from "./write-service.js";
10
+ /** Strict boundary, including direct handler calls. JSON is cloned before the first await
11
+ * so a held-open card cannot consent to a value later changed by the caller. O(input size). */
12
+ function parseTarget(toolId, raw) {
13
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
14
+ throw new ToolInputError({ message: `${toolId}: input must be an object containing namespace and key.` });
15
+ const input = raw;
16
+ const fields = toolId === "settings_set_value" ? ["namespace", "key", "value", "scope"] : ["namespace", "key", "scope"];
17
+ const extra = Object.keys(input).find((key) => !fields.includes(key));
18
+ if (extra)
19
+ throw new ToolInputError({ message: `${toolId}: unexpected input '${extra}'. Only ${fields.join(", ")} are accepted; the caller's own user layer is the only user target.` });
20
+ for (const field of ["namespace", "key"]) {
21
+ if (typeof input[field] !== "string" || !input[field].trim())
22
+ throw new ToolInputError({ message: `${toolId}: '${field}' must be a non-empty string. Call settings_list_definitions to see valid keys.` });
23
+ }
24
+ const namespace = input.namespace;
25
+ const key = input.key;
26
+ const scope = input.scope === undefined ? "workspace" : input.scope;
27
+ if (scope !== "workspace" && scope !== "user")
28
+ throw new ToolInputError({ message: `${toolId}: scope must be 'workspace' or 'user'; global settings are not writable by this tool.` });
29
+ if (toolId === "settings_clear_value")
30
+ return { namespace, key, scope };
31
+ if (!("value" in input))
32
+ throw new ToolInputError({ message: `${toolId}: a JSON 'value' is required.` });
33
+ // The executor validates JSON input too. The round trip protects direct callers and isolates
34
+ // the snapshot; values JSON would silently change (NaN, undefined, functions) are rejected.
35
+ let serialized;
36
+ try {
37
+ serialized = JSON.stringify(input.value, (_key, value) => {
38
+ if (value === undefined || typeof value === "function" || typeof value === "symbol" || (typeof value === "number" && !Number.isFinite(value)))
39
+ throw new Error("not JSON");
40
+ return value;
41
+ });
42
+ }
43
+ catch {
44
+ throw new ToolInputError({ message: `${toolId}: value must be valid JSON.` });
45
+ }
46
+ if (serialized === undefined)
47
+ throw new ToolInputError({ message: `${toolId}: value must be valid JSON.` });
48
+ return { namespace, key, scope, value: JSON.parse(serialized) };
49
+ }
50
+ /** Definition/scope/value preflight for readable refusal before any card. O(1) repository
51
+ * lookups plus alias resolution and schema validation, with no writes. */
52
+ async function resolveTarget(deps, target, isSet) {
53
+ const definition = await resolveDefinitionRaw({ repo: deps.settingsRepo }, { namespace: target.namespace, key: target.key, workspaceId: deps.workspaceId });
54
+ const name = `${target.namespace}.${target.key}`;
55
+ if (!definition)
56
+ throw new DefinitionNotFoundError(`setting '${name}' was not found`);
57
+ if (definition.status === "tombstone")
58
+ throw new DefinitionTombstonedError(`setting '${name}' has been tombstoned`);
59
+ if ((definition.scopes & SCOPE_BIT[target.scope]) === 0)
60
+ throw new ScopeNotAllowedError(name);
61
+ if (isSet && !validateValueAgainstSchema(definition.schema, target.value))
62
+ throw new ValueValidationFailedError(`value for '${name}' does not match the definition schema`);
63
+ return definition;
64
+ }
65
+ /** Reads exactly the override being changed, never an effective value or another principal.
66
+ * One repository read, O(1) outside adapter cost. */
67
+ function readLayer(deps, target, settingId, principalId) {
68
+ const base = { workspaceId: deps.workspaceId, settingId };
69
+ return target.scope === "user" ? deps.settingsRepo.getUserValue({ ...base, principalId }) : deps.settingsRepo.getWorkspaceValue(base);
70
+ }
71
+ /** Fail closed on host-denied keys, including a protected target reached through an alias.
72
+ * Returns a confirmation rule if either coordinate needs one; O(r) in fixed policy rules. */
73
+ function writePolicy(deps, toolId, target, definition) {
74
+ const targets = definition ? [target, definition] : [target];
75
+ const denied = [...AGENT_WRITE_DENIED_SETTINGS, ...(deps.extraDeniedSettings ?? [])];
76
+ for (const coordinate of targets) {
77
+ const rule = findAgentWriteRule(denied, coordinate);
78
+ if (rule)
79
+ throw new ToolInputError({ message: `${toolId}: '${coordinate.namespace}.${coordinate.key}' can't be changed by the assistant: ${rule.reason}. The owner can change it in Settings.` });
80
+ }
81
+ const confirmation = [...AGENT_WRITE_CONFIRMATION_SETTINGS, ...(deps.extraConfirmationSettings ?? [])];
82
+ for (const coordinate of targets) {
83
+ const rule = findAgentWriteRule(confirmation, coordinate);
84
+ if (rule)
85
+ return { ...rule, namespace: coordinate.namespace, key: coordinate.key };
86
+ }
87
+ return undefined;
88
+ }
89
+ /** Maps expected caller-fixable errors; infrastructure failures remain untouched. O(1). */
90
+ function rethrowWriteError(error, toolId, target, permission) {
91
+ if (error instanceof DefinitionNotFoundError || error instanceof DefinitionTombstonedError)
92
+ throw new ToolInputError({ message: `${toolId}: ${error.message}. Call settings_list_definitions to see valid keys.` });
93
+ if (error instanceof ScopeNotAllowedError)
94
+ throw new ToolInputError({ message: `${toolId}: '${target.namespace}.${target.key}' can't be set ${target.scope === "user" ? "per-user" : "at workspace scope"}. Call settings_list_definitions to see allowed scopes.` });
95
+ if (error instanceof ValueValidationFailedError)
96
+ throw new ToolInputError({ message: `${toolId}: ${error.message}. Call settings_list_definitions and use a value matching the setting's schema.` });
97
+ if (error instanceof ForbiddenError || error instanceof PermissionDeniedError)
98
+ throw new ToolInputError({ message: `${toolId}: permission '${permission}' is required. Ask the owner to grant it before retrying.` });
99
+ throw error;
100
+ }
101
+ /** Builds one value-write handler. Effects: authorize -> raw read -> optional human card ->
102
+ * service write -> result. The service rechecks authorization and performs its normal transaction.
103
+ * @complexity O(value size + rule count) plus bounded repository calls and a human wait.
104
+ * @throws ToolInputError for invalid input, denied keys, absent/declined/stale confirmation. */
105
+ export function buildSettingsValueWriteHandler(deps, toolId) {
106
+ return async (ctx, options) => {
107
+ const target = parseTarget(toolId, ctx.input);
108
+ const permission = deriveRequiredPermission({ scope: target.scope, callerPrincipalId: ctx.principal.id });
109
+ const isSet = toolId === "settings_set_value";
110
+ try {
111
+ if (ctx.signal.aborted)
112
+ throw new ToolInputError({ message: `${toolId}: the run ended before the change could be applied. Nothing was changed.` });
113
+ writePolicy(deps, toolId, target);
114
+ await Promise.all([deps.settingsReady, deps.settingsUiTabsReady]);
115
+ await requireToolPermission({ authorize: adaptLegacyAuthorize({ authorize: deps.authorize }), workspaceId: deps.workspaceId, principalId: ctx.principal.id, permission }, { entityType: "setting-value" });
116
+ const definition = await resolveTarget(deps, target, isSet);
117
+ const rule = writePolicy(deps, toolId, target, definition);
118
+ const layer = await readLayer(deps, target, definition.settingId, ctx.principal.id);
119
+ const previous = layer?.state === "set" ? structuredClone(layer.valueJson) : null;
120
+ // Cancellation may have arrived during readiness, authorization or the raw read.
121
+ // Check before opening a card so a finished run cannot leave a new exchange waiting.
122
+ if (ctx.signal.aborted)
123
+ throw new ToolInputError({ message: `${toolId}: the run ended before the change could be applied. Nothing was changed.` });
124
+ if (rule) {
125
+ if (!deps.confirmWrite)
126
+ throw new ToolInputError({ message: `${toolId}: '${rule.namespace}.${rule.key}' requires a human confirmation card: ${rule.reason}. The owner can change it in Settings.` });
127
+ const confirmed = await deps.confirmWrite({ ctx, toolId, namespace: rule.namespace, key: rule.key, scope: target.scope, previous: structuredClone(previous), ...(isSet ? { value: structuredClone(target.value) } : {}), reason: rule.reason }, options);
128
+ if (confirmed !== true)
129
+ throw new ToolInputError({ message: `${toolId}: the human did not confirm the change. Nothing was changed.` });
130
+ const current = await resolveTarget(deps, target, isSet);
131
+ const currentLayer = await readLayer(deps, target, current.settingId, ctx.principal.id);
132
+ if (current.settingId !== definition.settingId || current.version !== definition.version || currentLayer?.seq !== layer?.seq)
133
+ throw new ToolInputError({ message: `${toolId}: this setting changed while the confirmation card was open. Read it again and request a new confirmation. Nothing was changed by this call.` });
134
+ }
135
+ if (ctx.signal.aborted)
136
+ throw new ToolInputError({ message: `${toolId}: the run ended before the change could be applied. Nothing was changed.` });
137
+ const writeDeps = { repo: deps.settingsRepo, clock: deps.clock, ids: deps.idGen, authorize: deps.authorize, principals: deps.principalRepo };
138
+ // Resolved coordinates preserve host validators even when the request named an alias.
139
+ const input = { namespace: definition.namespace, key: definition.key, scope: target.scope, workspaceId: deps.workspaceId, callerPrincipalId: ctx.principal.id, authWorkspaceId: deps.workspaceId };
140
+ const key = `${target.namespace}.${target.key}`;
141
+ if (isSet) {
142
+ const result = await (deps.setValue ?? set)({ deps: writeDeps, input: { ...input, value: target.value } });
143
+ return { key, scope: target.scope, previous, value: result.value, revisionSeq: result.revisionSeq };
144
+ }
145
+ await clear({ deps: writeDeps, input });
146
+ const effective = await getEffective({ repo: deps.settingsRepo }, { namespace: definition.namespace, key: definition.key, scopeContext: { workspaceId: deps.workspaceId, principalId: ctx.principal.id } });
147
+ return { key, scope: target.scope, previous, effective: effective?.value ?? null };
148
+ }
149
+ catch (error) {
150
+ rethrowWriteError(error, toolId, target, permission);
151
+ }
152
+ };
153
+ }
154
+ //# sourceMappingURL=agent-value-write-tools.js.map
@@ -2,25 +2,14 @@
2
2
  * @file The curated list of setting keys an agent may write — the precondition
3
3
  * `agent-tools.ts`'s header names.
4
4
  *
5
- * ## Why this file has to exist before any settings write can be wired
5
+ * ## The curated surface and the generic value tools
6
6
  *
7
- * The generic setter (`settings_set`) is excluded from agent callability because there is no fixed,
8
- * curated list of named settings to wire tools against for a generic admin surface — an operator
9
- * can type any namespace string and edit any value through a raw editor. `ui-tab-definitions.ts`
10
- * changes that for one specific slice: it registers a fixed, statically-declared set of keys — each
11
- * with a schema, a default, and a scope mask — because the settings-dialog tabs need named keys to
12
- * bind to. This module is the subset of THAT list which is safe for an agent to write.
13
- *
14
- * The exclusion's sharpest objection was that schema validation "constrains the VALUE shape, not
15
- * WHICH key is targeted". That is exactly right about the generic setter, and exactly what
16
- * {@link AGENT_WRITABLE_PREFERENCE_IDS} fixes: it is published as a JSON Schema `enum`, so the
17
- * targeted key is constrained by the same mechanism that constrains everything else in the tool
18
- * surface. The two halves together are complete — this file bounds WHICH key, and the ledger's
19
- * own registered definition schema bounds the VALUE (`write-service.ts`'s `set()` validates
20
- * against it and rejects a mismatch before any write lands).
21
- *
22
- * So the generic setter stays excluded, permanently and for its original reason. This is the
23
- * curated alternative that exclusion explicitly pointed at, not a relaxation of it.
7
+ * This enum still bounds WHICH display preference settings_set_ui_preference may change.
8
+ * Value schemas alone do not bound target keys: the original concern remains valid.
9
+ * The owner reversed the generic setter's permanent exclusion on 2026-10-01. See agent-tools.ts
10
+ * and agent-write-denylist.ts: generic value tools require a human card for privacy consent and
11
+ * standing instructions, while ordinary settings run directly. The curated display tool stays
12
+ * caller-only and has no confirmation bypass for protected keys.
24
13
  *
25
14
  * ## What is deliberately NOT here
26
15
  *
@@ -34,8 +23,7 @@
34
23
  * allowlist cannot express.
35
24
  * - **`core.instructions.custom`** — the custom instructions prepended to every admin-assistant
36
25
  * conversation. An agent writing this edits its own standing prompt for all future runs. That
37
- * may well be worth allowing later, but it is a self-modification question and not a display
38
- * preference, so it does not ride in on the same decision.
26
+ * is self-modification, not a display preference: the generic tool now requires a human card.
39
27
  *
40
28
  * Every key that IS here is a per-operator display preference: reversible in one call, scoped to
41
29
  * the caller's own user layer, and visible in the admin UI the moment it changes — which is what
@@ -0,0 +1,19 @@
1
+ /** One key or an entire namespace governed by a host's agent-write policy. */
2
+ export interface AgentSettingWriteRule {
3
+ readonly namespace: string;
4
+ readonly key?: string;
5
+ readonly reason: string;
6
+ }
7
+ /** Owner decision 2026-10-01: these keys are writable with a HUMAN confirmation card.
8
+ * Schema validation bounds the value, not which key. Keep that original concern explicit:
9
+ * telemetry must record a human decision; custom instructions modify the assistant itself. */
10
+ export declare const AGENT_WRITE_CONFIRMATION_SETTINGS: readonly AgentSettingWriteRule[];
11
+ /** No built-in permanent deny under the owner's updated rule. Hosts may add restrictions
12
+ * through extraDeniedSettings; assistant self-configuration belongs in confirmation rules. */
13
+ export declare const AGENT_WRITE_DENIED_SETTINGS: readonly AgentSettingWriteRule[];
14
+ /** Returns the first matching namespace/key rule, or undefined; pure, O(r) in fixed rules. */
15
+ export declare function findAgentWriteRule(rules: readonly AgentSettingWriteRule[], target: {
16
+ namespace: string;
17
+ key: string;
18
+ }): AgentSettingWriteRule | undefined;
19
+ //# sourceMappingURL=agent-write-denylist.d.ts.map
@@ -0,0 +1,15 @@
1
+ /** Owner decision 2026-10-01: these keys are writable with a HUMAN confirmation card.
2
+ * Schema validation bounds the value, not which key. Keep that original concern explicit:
3
+ * telemetry must record a human decision; custom instructions modify the assistant itself. */
4
+ export const AGENT_WRITE_CONFIRMATION_SETTINGS = [
5
+ { namespace: "core.privacy", reason: "Telemetry consent must record a human decision" },
6
+ { namespace: "core.instructions", key: "custom", reason: "The assistant's own standing instructions are self-modification" },
7
+ ];
8
+ /** No built-in permanent deny under the owner's updated rule. Hosts may add restrictions
9
+ * through extraDeniedSettings; assistant self-configuration belongs in confirmation rules. */
10
+ export const AGENT_WRITE_DENIED_SETTINGS = [];
11
+ /** Returns the first matching namespace/key rule, or undefined; pure, O(r) in fixed rules. */
12
+ export function findAgentWriteRule(rules, target) {
13
+ return rules.find((rule) => rule.namespace === target.namespace && (rule.key === undefined || rule.key === target.key));
14
+ }
15
+ //# sourceMappingURL=agent-write-denylist.js.map
@@ -47,7 +47,10 @@ export interface ChangeFeedViewer {
47
47
  * @complexity O(1).
48
48
  * @overallScore 100
49
49
  */
50
- export declare function isRevisionVisibleTo(revision: SettingRevisionRecord, viewer: ChangeFeedViewer): boolean;
50
+ export declare function isRevisionVisibleTo({ revision, viewer }: {
51
+ revision: SettingRevisionRecord;
52
+ viewer: ChangeFeedViewer;
53
+ }, _optional?: Record<string, never>): boolean;
51
54
  /** One batch of visible changes, plus the cursor a subscriber resumes from. */
52
55
  export interface ChangeFeedBatch {
53
56
  /** Namespaces to re-read, de-duplicated. Empty when nothing visible changed. */
@@ -70,5 +73,11 @@ export interface ChangeFeedBatch {
70
73
  * @complexity O(n) in `revisions`, plus one `resolveNamespace` per visible revision.
71
74
  * @overallScore 100
72
75
  */
73
- export declare function collectChangedNamespaces(revisions: readonly SettingRevisionRecord[], viewer: ChangeFeedViewer, resolveNamespace: (settingId: string) => Promise<string | null>): Promise<ChangeFeedBatch>;
76
+ export declare function collectChangedNamespaces({ revisions, viewer, resolveNamespace }: {
77
+ revisions: readonly SettingRevisionRecord[];
78
+ viewer: ChangeFeedViewer;
79
+ resolveNamespace: (required: {
80
+ settingId: string;
81
+ }) => Promise<string | null>;
82
+ }, _optional?: Record<string, never>): Promise<ChangeFeedBatch>;
74
83
  //# sourceMappingURL=change-feed.d.ts.map
@@ -14,7 +14,7 @@
14
14
  * @complexity O(1).
15
15
  * @overallScore 100
16
16
  */
17
- export function isRevisionVisibleTo(revision, viewer) {
17
+ export function isRevisionVisibleTo({ revision, viewer }, _optional = {}) {
18
18
  if (revision.entityKind === "definition") {
19
19
  return revision.workspaceId === null || revision.workspaceId === viewer.workspaceId;
20
20
  }
@@ -44,15 +44,15 @@ export function isRevisionVisibleTo(revision, viewer) {
44
44
  * @complexity O(n) in `revisions`, plus one `resolveNamespace` per visible revision.
45
45
  * @overallScore 100
46
46
  */
47
- export async function collectChangedNamespaces(revisions, viewer, resolveNamespace) {
47
+ export async function collectChangedNamespaces({ revisions, viewer, resolveNamespace }, _optional = {}) {
48
48
  const namespaces = new Set();
49
49
  let cursor = 0;
50
50
  for (const revision of revisions) {
51
51
  if (revision.seq > cursor)
52
52
  cursor = revision.seq;
53
- if (!isRevisionVisibleTo(revision, viewer))
53
+ if (!isRevisionVisibleTo({ revision, viewer }))
54
54
  continue;
55
- const namespace = await resolveNamespace(revision.settingId);
55
+ const namespace = await resolveNamespace({ settingId: revision.settingId });
56
56
  if (namespace)
57
57
  namespaces.add(namespace);
58
58
  }
@@ -1,4 +1,4 @@
1
- import type { JsonValue, UUID } from "../core/ports.js";
1
+ import type { JsonValue, UUID } from "@jini-ai/core/primitives";
2
2
  import type { SettingOwnerKind, SettingValueSchema } from "./types.js";
3
3
  import type { SettingsWriteServiceDeps } from "./write-service.js";
4
4
  /**
@@ -34,7 +34,10 @@ export interface DefinitionOpContext {
34
34
  callerPrincipalId: UUID;
35
35
  authWorkspaceId: UUID;
36
36
  }
37
- export type DefinitionOpHandler = (ctx: DefinitionOpContext, item: DefinitionOpRequestItem) => Promise<void>;
37
+ export type DefinitionOpHandler = (required: {
38
+ ctx: DefinitionOpContext;
39
+ item: DefinitionOpRequestItem;
40
+ }, optional?: Record<string, never>) => Promise<void>;
38
41
  /**
39
42
  * The closed set of non-`register` ops: an untrusted `op` string is narrowed to this union at the
40
43
  * parse boundary via {@link parseNonRegisterDefinitionOp} BEFORE any dispatch table lookup, so the
@@ -46,6 +49,8 @@ export type DefinitionOpHandler = (ctx: DefinitionOpContext, item: DefinitionOpR
46
49
  export declare const NON_REGISTER_DEFINITION_OP_NAMES: readonly ["rename", "retype", "deprecate", "tombstone"];
47
50
  export type NonRegisterDefinitionOp = (typeof NON_REGISTER_DEFINITION_OP_NAMES)[number];
48
51
  /** Narrows an untrusted `op` string to {@link NonRegisterDefinitionOp}, or `null` if it isn't one. */
49
- export declare function parseNonRegisterDefinitionOp(op: string): NonRegisterDefinitionOp | null;
52
+ export declare function parseNonRegisterDefinitionOp({ op }: {
53
+ op: string;
54
+ }, _optional?: Record<string, never>): NonRegisterDefinitionOp | null;
50
55
  export declare const NON_REGISTER_DEFINITION_OPS: Record<NonRegisterDefinitionOp, DefinitionOpHandler>;
51
56
  //# sourceMappingURL=definitions-dispatch.d.ts.map
@@ -13,7 +13,7 @@ function resolveCoercionTag(coercionJson) {
13
13
  */
14
14
  export const NON_REGISTER_DEFINITION_OP_NAMES = ["rename", "retype", "deprecate", "tombstone"];
15
15
  /** Narrows an untrusted `op` string to {@link NonRegisterDefinitionOp}, or `null` if it isn't one. */
16
- export function parseNonRegisterDefinitionOp(op) {
16
+ export function parseNonRegisterDefinitionOp({ op }, _optional = {}) {
17
17
  return NON_REGISTER_DEFINITION_OP_NAMES.includes(op)
18
18
  ? op
19
19
  : null;
@@ -26,7 +26,7 @@ export function parseNonRegisterDefinitionOp(op) {
26
26
  * future regression that skips the parse step.
27
27
  */
28
28
  const nonRegisterDefinitionOps = {
29
- rename: async (ctx, item) => {
29
+ rename: async ({ ctx, item }) => {
30
30
  await renameDefinition({
31
31
  deps: ctx.deps,
32
32
  input: {
@@ -40,7 +40,7 @@ const nonRegisterDefinitionOps = {
40
40
  },
41
41
  });
42
42
  },
43
- retype: async (ctx, item) => {
43
+ retype: async ({ ctx, item }) => {
44
44
  await retypeDefinition({
45
45
  deps: ctx.deps,
46
46
  input: {
@@ -57,7 +57,7 @@ const nonRegisterDefinitionOps = {
57
57
  },
58
58
  });
59
59
  },
60
- deprecate: async (ctx, item) => {
60
+ deprecate: async ({ ctx, item }) => {
61
61
  await deprecateDefinition({
62
62
  deps: ctx.deps,
63
63
  input: {
@@ -69,7 +69,7 @@ const nonRegisterDefinitionOps = {
69
69
  },
70
70
  });
71
71
  },
72
- tombstone: async (ctx, item) => {
72
+ tombstone: async ({ ctx, item }) => {
73
73
  await tombstoneDefinition({
74
74
  deps: ctx.deps,
75
75
  input: {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @file Settings-dialog chrome dictionary — the 24 generic tab labels/subtitles for the Settings
2
+ * @file Settings-dialog chrome dictionary — the 23 generic tab labels/subtitles for the Settings
3
3
  * screen (Instructions, Notifications, Privacy, MCP server, Memory, Skills, Version, etc.).
4
4
  *
5
5
  * Relocated here from Jini's `@jini-ai/ui` (2026-08-08): these keys aren't UI-rendering logic,
@@ -41,5 +41,8 @@ export { SETTINGS_DIALOG_ES, SETTINGS_DIALOG_ID, SETTINGS_DIALOG_DE, SETTINGS_DI
41
41
  export declare const SETTINGS_DIALOG_DICTIONARIES: Readonly<Record<string, Record<string, string>>>;
42
42
  /** `dict[locale]?.[key] ?? key` — no separate English dict to fall back to, since the key
43
43
  * itself already is the English text. */
44
- export declare function translateSettingsDialog(locale: string, key: string): string;
44
+ export declare function translateSettingsDialog({ locale, key }: {
45
+ locale: string;
46
+ key: string;
47
+ }, _optional?: Record<string, never>): string;
45
48
  //# sourceMappingURL=index.d.ts.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @file Settings-dialog chrome dictionary — the 24 generic tab labels/subtitles for the Settings
2
+ * @file Settings-dialog chrome dictionary — the 23 generic tab labels/subtitles for the Settings
3
3
  * screen (Instructions, Notifications, Privacy, MCP server, Memory, Skills, Version, etc.).
4
4
  *
5
5
  * Relocated here from Jini's `@jini-ai/ui` (2026-08-08): these keys aren't UI-rendering logic,
@@ -63,7 +63,7 @@ export const SETTINGS_DIALOG_DICTIONARIES = {
63
63
  };
64
64
  /** `dict[locale]?.[key] ?? key` — no separate English dict to fall back to, since the key
65
65
  * itself already is the English text. */
66
- export function translateSettingsDialog(locale, key) {
66
+ export function translateSettingsDialog({ locale, key }, _optional = {}) {
67
67
  return SETTINGS_DIALOG_DICTIONARIES[locale]?.[key] ?? key;
68
68
  }
69
69
  //# sourceMappingURL=index.js.map
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_AR = {
12
12
  "MCP server": "خادم MCP",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "اربط عميل MCP. يُعرض ناتج نموذجي — لم يتم ربطه بعد بخادم فعلي.",
14
14
  "API keys for image, video, and audio generation.": "مفاتيح API لإنشاء الصور والفيديو والصوت.",
15
- "Third-party accounts and APIs via Composio.": "حسابات وواجهات برمجة تطبيقات تابعة لجهات خارجية عبر Composio.",
16
15
  "Memory": "الذاكرة",
17
16
  "Saved facts and context for future chats.": "حقائق وسياق محفوظان للمحادثات المستقبلية.",
18
17
  "External MCP": "MCP خارجي",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_BN = {
12
12
  "MCP server": "MCP সার্ভার",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "একটি MCP ক্লায়েন্ট সংযুক্ত করুন। নমুনা আউটপুট দেখানো হচ্ছে — এখনও কোনো লাইভ সার্ভারের সাথে সংযুক্ত নয়।",
14
14
  "API keys for image, video, and audio generation.": "ছবি, ভিডিও এবং অডিও তৈরির জন্য API কী।",
15
- "Third-party accounts and APIs via Composio.": "Composio-এর মাধ্যমে তৃতীয়-পক্ষের অ্যাকাউন্ট ও API।",
16
15
  "Memory": "মেমরি",
17
16
  "Saved facts and context for future chats.": "ভবিষ্যতের কথোপকথনের জন্য সংরক্ষিত তথ্য ও প্রসঙ্গ।",
18
17
  "External MCP": "এক্সটার্নাল MCP",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_DE = {
12
12
  "MCP server": "MCP-Server",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "Verbinde einen MCP-Client. Zeigt Beispielausgabe — noch nicht mit einem echten Server verbunden.",
14
14
  "API keys for image, video, and audio generation.": "API-Schlüssel für die Erzeugung von Bildern, Videos und Audio.",
15
- "Third-party accounts and APIs via Composio.": "Konten und APIs von Drittanbietern über Composio.",
16
15
  "Memory": "Gedächtnis",
17
16
  "Saved facts and context for future chats.": "Gespeicherte Fakten und Kontext für zukünftige Chats.",
18
17
  "External MCP": "Externes MCP",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_ES = {
12
12
  "MCP server": "Servidor MCP",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "Conecta un cliente MCP. Se muestra un resultado de ejemplo — aún no está conectado a un servidor real.",
14
14
  "API keys for image, video, and audio generation.": "Claves de API para generar imágenes, video y audio.",
15
- "Third-party accounts and APIs via Composio.": "Cuentas y APIs de terceros a través de Composio.",
16
15
  "Memory": "Memoria",
17
16
  "Saved facts and context for future chats.": "Datos y contexto guardados para futuras conversaciones.",
18
17
  "External MCP": "MCP externo",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_FA = {
12
12
  "MCP server": "سرور MCP",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "یک کلاینت MCP متصل کنید. خروجی نمونه نمایش داده می‌شود — هنوز به سرور واقعی متصل نشده است.",
14
14
  "API keys for image, video, and audio generation.": "کلیدهای API برای تولید تصویر، ویدئو و صدا.",
15
- "Third-party accounts and APIs via Composio.": "حساب‌ها و APIهای شخص ثالث از طریق Composio.",
16
15
  "Memory": "حافظه",
17
16
  "Saved facts and context for future chats.": "واقعیت‌ها و زمینهٔ ذخیره‌شده برای گفتگوهای آینده.",
18
17
  "External MCP": "MCP خارجی",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_FR = {
12
12
  "MCP server": "Serveur MCP",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "Connectez un client MCP. Exemple de résultat affiché — pas encore relié à un serveur réel.",
14
14
  "API keys for image, video, and audio generation.": "Clés API pour la génération d'images, de vidéos et d'audio.",
15
- "Third-party accounts and APIs via Composio.": "Comptes et API tiers via Composio.",
16
15
  "Memory": "Mémoire",
17
16
  "Saved facts and context for future chats.": "Faits et contexte enregistrés pour les futures conversations.",
18
17
  "External MCP": "MCP externe",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_HI = {
12
12
  "MCP server": "MCP सर्वर",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "एक MCP क्लाइंट कनेक्ट करें. नमूना आउटपुट दिखाया जा रहा है — अभी तक किसी लाइव सर्वर से नहीं जुड़ा है.",
14
14
  "API keys for image, video, and audio generation.": "छवि, वीडियो और ऑडियो जनरेशन के लिए API कुंजियाँ.",
15
- "Third-party accounts and APIs via Composio.": "Composio के ज़रिए थर्ड-पार्टी खाते और API.",
16
15
  "Memory": "मेमोरी",
17
16
  "Saved facts and context for future chats.": "भविष्य की बातचीत के लिए सहेजे गए तथ्य और संदर्भ.",
18
17
  "External MCP": "बाहरी MCP",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_HU = {
12
12
  "MCP server": "MCP-szerver",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "Csatlakoztass egy MCP-klienst. Egy minta kimenet látható — még nincs élő szerverhez kapcsolva.",
14
14
  "API keys for image, video, and audio generation.": "API-kulcsok kép-, videó- és hanggeneráláshoz.",
15
- "Third-party accounts and APIs via Composio.": "Harmadik féltől származó fiókok és API-k a Composión keresztül.",
16
15
  "Memory": "Memória",
17
16
  "Saved facts and context for future chats.": "Mentett tények és kontextus a jövőbeli beszélgetésekhez.",
18
17
  "External MCP": "Külső MCP",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_ID = {
12
12
  "MCP server": "Server MCP",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "Hubungkan klien MCP. Menampilkan output contoh — belum terhubung ke server sesungguhnya.",
14
14
  "API keys for image, video, and audio generation.": "Kunci API untuk pembuatan gambar, video, dan audio.",
15
- "Third-party accounts and APIs via Composio.": "Akun dan API pihak ketiga melalui Composio.",
16
15
  "Memory": "Memori",
17
16
  "Saved facts and context for future chats.": "Fakta dan konteks tersimpan untuk percakapan mendatang.",
18
17
  "External MCP": "MCP eksternal",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_IT = {
12
12
  "MCP server": "Server MCP",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "Connetti un client MCP. Viene mostrato un output di esempio — non ancora collegato a un server reale.",
14
14
  "API keys for image, video, and audio generation.": "Chiavi API per la generazione di immagini, video e audio.",
15
- "Third-party accounts and APIs via Composio.": "Account e API di terze parti tramite Composio.",
16
15
  "Memory": "Memoria",
17
16
  "Saved facts and context for future chats.": "Fatti e contesto salvati per le conversazioni future.",
18
17
  "External MCP": "MCP esterno",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_JA = {
12
12
  "MCP server": "MCPサーバー",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "MCPクライアントに接続します。サンプル出力を表示しています — まだ実際のサーバーには接続されていません。",
14
14
  "API keys for image, video, and audio generation.": "画像、動画、音声生成用のAPIキーです。",
15
- "Third-party accounts and APIs via Composio.": "Composio経由のサードパーティアカウントとAPIです。",
16
15
  "Memory": "メモリー",
17
16
  "Saved facts and context for future chats.": "今後のチャットのために保存された事実とコンテキストです。",
18
17
  "External MCP": "外部MCP",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_KO = {
12
12
  "MCP server": "MCP 서버",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "MCP 클라이언트를 연결합니다. 예시 출력을 표시하고 있으며, 아직 실제 서버에 연결되어 있지 않습니다.",
14
14
  "API keys for image, video, and audio generation.": "이미지, 동영상, 오디오 생성을 위한 API 키입니다.",
15
- "Third-party accounts and APIs via Composio.": "Composio를 통한 타사 계정 및 API입니다.",
16
15
  "Memory": "메모리",
17
16
  "Saved facts and context for future chats.": "향후 대화를 위해 저장된 사실 및 컨텍스트입니다.",
18
17
  "External MCP": "외부 MCP",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_PL = {
12
12
  "MCP server": "Serwer MCP",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "Połącz klienta MCP. Wyświetlany jest przykładowy wynik — jeszcze niepodłączony do rzeczywistego serwera.",
14
14
  "API keys for image, video, and audio generation.": "Klucze API do generowania obrazów, wideo i dźwięku.",
15
- "Third-party accounts and APIs via Composio.": "Konta i API innych firm za pośrednictwem Composio.",
16
15
  "Memory": "Pamięć",
17
16
  "Saved facts and context for future chats.": "Zapisane fakty i kontekst na potrzeby przyszłych rozmów.",
18
17
  "External MCP": "Zewnętrzne MCP",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_PT_BR = {
12
12
  "MCP server": "Servidor MCP",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "Conecte um cliente MCP. Mostrando uma saída de exemplo — ainda não conectado a um servidor real.",
14
14
  "API keys for image, video, and audio generation.": "Chaves de API para geração de imagem, vídeo e áudio.",
15
- "Third-party accounts and APIs via Composio.": "Contas e APIs de terceiros via Composio.",
16
15
  "Memory": "Memória",
17
16
  "Saved facts and context for future chats.": "Fatos e contexto salvos para conversas futuras.",
18
17
  "External MCP": "MCP externo",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_RU = {
12
12
  "MCP server": "Сервер MCP",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "Подключите клиент MCP. Показан пример вывода — пока не подключено к реальному серверу.",
14
14
  "API keys for image, video, and audio generation.": "Ключи API для генерации изображений, видео и аудио.",
15
- "Third-party accounts and APIs via Composio.": "Сторонние аккаунты и API через Composio.",
16
15
  "Memory": "Память",
17
16
  "Saved facts and context for future chats.": "Сохранённые факты и контекст для будущих диалогов.",
18
17
  "External MCP": "Внешний MCP",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_TH = {
12
12
  "MCP server": "เซิร์ฟเวอร์ MCP",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "เชื่อมต่อไคลเอนต์ MCP กำลังแสดงผลลัพธ์ตัวอย่าง — ยังไม่ได้เชื่อมต่อกับเซิร์ฟเวอร์จริง",
14
14
  "API keys for image, video, and audio generation.": "คีย์ API สำหรับสร้างภาพ วิดีโอ และเสียง",
15
- "Third-party accounts and APIs via Composio.": "บัญชีและ API ของบุคคลที่สามผ่าน Composio",
16
15
  "Memory": "หน่วยความจำ",
17
16
  "Saved facts and context for future chats.": "ข้อเท็จจริงและบริบทที่บันทึกไว้สำหรับการสนทนาในอนาคต",
18
17
  "External MCP": "MCP ภายนอก",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_TR = {
12
12
  "MCP server": "MCP sunucusu",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "Bir MCP istemcisi bağlayın. Örnek çıktı gösteriliyor — henüz canlı bir sunucuya bağlanmadı.",
14
14
  "API keys for image, video, and audio generation.": "Görsel, video ve ses oluşturma için API anahtarları.",
15
- "Third-party accounts and APIs via Composio.": "Composio üzerinden üçüncü taraf hesapları ve API'ler.",
16
15
  "Memory": "Bellek",
17
16
  "Saved facts and context for future chats.": "Gelecekteki sohbetler için kaydedilmiş bilgiler ve bağlam.",
18
17
  "External MCP": "Harici MCP",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_UK = {
12
12
  "MCP server": "Сервер MCP",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "Підключіть клієнт MCP. Показано приклад виведення — ще не підключено до реального сервера.",
14
14
  "API keys for image, video, and audio generation.": "Ключі API для генерації зображень, відео та аудіо.",
15
- "Third-party accounts and APIs via Composio.": "Сторонні облікові записи та API через Composio.",
16
15
  "Memory": "Пам'ять",
17
16
  "Saved facts and context for future chats.": "Збережені факти та контекст для майбутніх чатів.",
18
17
  "External MCP": "Зовнішній MCP",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_UR = {
12
12
  "MCP server": "MCP سرور",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "ایک MCP کلائنٹ کنیکٹ کریں۔ نمونہ آؤٹ پٹ دکھایا جا رہا ہے — ابھی تک کسی لائیو سرور سے منسلک نہیں۔",
14
14
  "API keys for image, video, and audio generation.": "تصویر، ویڈیو اور آڈیو تخلیق کے لیے API کیز۔",
15
- "Third-party accounts and APIs via Composio.": "Composio کے ذریعے تھرڈ پارٹی اکاؤنٹس اور APIs۔",
16
15
  "Memory": "میموری",
17
16
  "Saved facts and context for future chats.": "مستقبل کی گفتگو کے لیے محفوظ شدہ حقائق اور سیاق و سباق۔",
18
17
  "External MCP": "خارجی MCP",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_ZH_CN = {
12
12
  "MCP server": "MCP 服务器",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "连接一个 MCP 客户端。当前显示的是示例输出——尚未接入实际服务器。",
14
14
  "API keys for image, video, and audio generation.": "用于生成图像、视频和音频的 API 密钥。",
15
- "Third-party accounts and APIs via Composio.": "通过 Composio 接入的第三方账户和 API。",
16
15
  "Memory": "记忆",
17
16
  "Saved facts and context for future chats.": "为后续对话保存的事实和上下文。",
18
17
  "External MCP": "外部 MCP",
@@ -12,7 +12,6 @@ export const SETTINGS_DIALOG_ZH_TW = {
12
12
  "MCP server": "MCP 伺服器",
13
13
  "Connect an MCP client. Showing sample output — not yet wired to a live server.": "連接一個 MCP 用戶端。目前顯示的是範例輸出——尚未接上實際伺服器。",
14
14
  "API keys for image, video, and audio generation.": "用於產生圖片、影片與音訊的 API 金鑰。",
15
- "Third-party accounts and APIs via Composio.": "透過 Composio 串接的第三方帳戶與 API。",
16
15
  "Memory": "記憶",
17
16
  "Saved facts and context for future chats.": "為日後對話保存的事實與脈絡資訊。",
18
17
  "External MCP": "外部 MCP",