@jini-ai/cms 0.5.4 → 0.5.5
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.
- package/dist/navigation/agent-tools.js +20 -3
- package/dist/navigation/index.d.ts +3 -1
- package/dist/navigation/index.js +2 -0
- package/dist/navigation/menu-html.d.ts +31 -0
- package/dist/navigation/menu-html.js +53 -0
- package/dist/navigation/menu-service.d.ts +9 -3
- package/dist/navigation/menu-service.js +15 -3
- package/dist/navigation/tool-registrations.d.ts +5 -0
- package/dist/navigation/tool-registrations.js +32 -2
- package/dist/navigation/types.d.ts +6 -0
- package/dist/widgets/resolvers/menu.d.ts +8 -0
- package/dist/widgets/resolvers/menu.js +21 -6
- package/package.json +3 -3
- package/dist/http/settings/cms-adapter.d.ts +0 -20
- package/dist/http/settings/cms-adapter.js +0 -124
- package/dist/http/settings/contracts.d.ts +0 -135
- package/dist/http/settings/contracts.js +0 -2
- package/dist/http/settings/http.d.ts +0 -10
- package/dist/http/settings/http.js +0 -211
- package/dist/http/settings/index.d.ts +0 -5
- package/dist/http/settings/index.js +0 -4
- package/dist/http/settings/shared.d.ts +0 -68
- package/dist/http/settings/shared.js +0 -54
- package/dist/http/settings/stream.d.ts +0 -24
- package/dist/http/settings/stream.js +0 -147
- package/dist/settings/agent-tools.d.ts +0 -10
- package/dist/settings/agent-tools.js +0 -204
- package/dist/settings/agent-value-write-tools.d.ts +0 -22
- package/dist/settings/agent-value-write-tools.js +0 -154
- package/dist/settings/agent-writable-preferences.d.ts +0 -67
- package/dist/settings/agent-writable-preferences.js +0 -132
- package/dist/settings/agent-write-denylist.d.ts +0 -19
- package/dist/settings/agent-write-denylist.js +0 -15
- package/dist/settings/change-feed.d.ts +0 -83
- package/dist/settings/change-feed.js +0 -61
- package/dist/settings/definitions-dispatch.d.ts +0 -56
- package/dist/settings/definitions-dispatch.js +0 -86
- package/dist/settings/dictionaries/index.d.ts +0 -48
- package/dist/settings/dictionaries/index.js +0 -69
- package/dist/settings/dictionaries/settings-dialog.ar.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.ar.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.bn.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.bn.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.de.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.de.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.es.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.es.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.fa.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.fa.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.fr.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.fr.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.hi.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.hi.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.hu.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.hu.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.id.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.id.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.it.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.it.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.ja.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.ja.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.ko.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.ko.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.pl.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.pl.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.pt-BR.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.pt-BR.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.ru.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.ru.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.th.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.th.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.tr.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.tr.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.uk.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.uk.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.ur.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.ur.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.zh-CN.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.zh-CN.js +0 -27
- package/dist/settings/dictionaries/settings-dialog.zh-TW.d.ts +0 -3
- package/dist/settings/dictionaries/settings-dialog.zh-TW.js +0 -27
- package/dist/settings/ensure-definitions.d.ts +0 -88
- package/dist/settings/ensure-definitions.js +0 -91
- package/dist/settings/errors.d.ts +0 -42
- package/dist/settings/errors.js +0 -46
- package/dist/settings/express/cms-adapter.d.ts +0 -20
- package/dist/settings/express/cms-adapter.js +0 -124
- package/dist/settings/express/contracts.d.ts +0 -135
- package/dist/settings/express/contracts.js +0 -2
- package/dist/settings/express/http.d.ts +0 -10
- package/dist/settings/express/http.js +0 -211
- package/dist/settings/express/shared.d.ts +0 -68
- package/dist/settings/express/shared.js +0 -54
- package/dist/settings/express/stream.d.ts +0 -24
- package/dist/settings/express/stream.js +0 -147
- package/dist/settings/ports.d.ts +0 -118
- package/dist/settings/ports.js +0 -2
- package/dist/settings/principal-lookup.d.ts +0 -9
- package/dist/settings/principal-lookup.js +0 -2
- package/dist/settings/purge-service.d.ts +0 -54
- package/dist/settings/purge-service.js +0 -106
- package/dist/settings/repo.memory.d.ts +0 -119
- package/dist/settings/repo.memory.js +0 -199
- package/dist/settings/settings.d.ts +0 -139
- package/dist/settings/settings.js +0 -259
- package/dist/settings/tool-registrations.d.ts +0 -51
- package/dist/settings/tool-registrations.js +0 -250
- package/dist/settings/types.d.ts +0 -125
- package/dist/settings/types.js +0 -3
- package/dist/settings/ui-tab-definitions.d.ts +0 -41
- package/dist/settings/ui-tab-definitions.js +0 -148
- package/dist/settings/write-service.d.ts +0 -320
- package/dist/settings/write-service.js +0 -683
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { AgentToolDefinition } from "@jini-ai/core";
|
|
2
|
-
/**
|
|
3
|
-
* The Settings domain's fixed agent-tool catalog — three reads, three bounded writes, and two bulk/schema writes documented but never
|
|
4
|
-
* wired. See file header.
|
|
5
|
-
*
|
|
6
|
-
* @complexity O(1) — a fixed, statically-defined list.
|
|
7
|
-
* @overallScore 100
|
|
8
|
-
*/
|
|
9
|
-
export declare function getSettingsAgentToolCatalog(): AgentToolDefinition[];
|
|
10
|
-
//# sourceMappingURL=agent-tools.d.ts.map
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file The Settings domain's agent-tool catalog, instantiating the naming/callability
|
|
3
|
-
* convention every other domain catalog in this package already uses.
|
|
4
|
-
*
|
|
5
|
-
* Purpose:
|
|
6
|
-
* A static, in-process catalog describing every agent-callable tool this domain exposes. Settings
|
|
7
|
-
* is, by design, a broad key/value surface — a typical human admin screen for it is an uncurated,
|
|
8
|
-
* free-text editor: the operator types ANY namespace string to load it and edits values through a
|
|
9
|
-
* raw-JSON textarea, with no schema-exposing endpoint feeding a typed control. There is no fixed,
|
|
10
|
-
* curated list of named settings on that surface to wire tools against.
|
|
11
|
-
*
|
|
12
|
-
* The original generic-write exclusion correctly observed that schema validation bounds VALUE
|
|
13
|
-
* shape, not WHICH key may be targeted. The owner reversed permanent exclusion on 2026-10-01:
|
|
14
|
-
* settings_set_value/settings_clear_value now address one registered workspace or caller-owned
|
|
15
|
-
* user override. Explicit key policy bounds the target; privacy consent and the assistant's own
|
|
16
|
-
* instructions require a HUMAN confirmation port (the agent cannot self-confirm). Hosts add
|
|
17
|
-
* runtime/permission policies through the same seam. Headless protected writes fail closed.
|
|
18
|
-
* Ordinary settings apply directly and remain undoable using the returned previous override.
|
|
19
|
-
*
|
|
20
|
-
* settings_set_ui_preference remains the fixed seven-key, caller-only display-preference surface.
|
|
21
|
-
* It cannot reach consent or standing instructions; use the generic tools and a human card there.
|
|
22
|
-
*
|
|
23
|
-
* The broader operations remain excluded:
|
|
24
|
-
* - SETTINGS_RESET clears every value in a namespace at once, an irreversible bulk operation.
|
|
25
|
-
* - SETTINGS_REGISTER_DEFINITIONS can retype/rename/tombstone definitions and reinterpret values
|
|
26
|
-
* platform-wide. Neither gets wired by the value-write decision.
|
|
27
|
-
*
|
|
28
|
-
* Reads are a different risk class and are wired: `SETTINGS_LIST_DEFINITIONS`/
|
|
29
|
-
* `SETTINGS_GET_EFFECTIVE`/`SETTINGS_GET_RAW` cannot mutate anything, are gated by the same real
|
|
30
|
-
* `authorize` permissions an admin UI's own reads use (including the cross-principal
|
|
31
|
-
* `settings.user.read` check), and cannot surface a secret value even in principle —
|
|
32
|
-
* `settings.ts`'s `validateDefinitionInput` unconditionally refuses `secret:true` at registration
|
|
33
|
-
* time, so no secret setting can exist in this library's current state to leak.
|
|
34
|
-
*
|
|
35
|
-
* How it relates to a host:
|
|
36
|
-
* A host's tool-registration layer consumes this catalog to decide which tool names an agent
|
|
37
|
-
* session may even see; `authorize` enforces the actual permission checks at call time — this
|
|
38
|
-
* module only declares the catalog shape, it performs no I/O and no enforcement itself.
|
|
39
|
-
*
|
|
40
|
-
* Architectural role:
|
|
41
|
-
* `settings` domain logic. Depends only on its own sibling `agent-writable-preferences.ts` (for
|
|
42
|
-
* the curated write's enum) — no I/O, no enforcement.
|
|
43
|
-
* See docs/decisions/DR-003-settings-ledger-invariants.md.
|
|
44
|
-
*/
|
|
45
|
-
import { AGENT_WRITABLE_PREFERENCE_IDS, AGENT_WRITABLE_PREFERENCES } from "./agent-writable-preferences.js";
|
|
46
|
-
/**
|
|
47
|
-
* JSON Schema for this tool's `input`, published to the model via `ToolDescriptor.inputSchema`
|
|
48
|
-
* (a host's tool-registration layer refuses to wire any tool lacking one). Optional — the two bulk/schema
|
|
49
|
-
* write entries this file documents but never wires (see file header) carry no schema at all,
|
|
50
|
-
* since one is never published for a tool the model never sees.
|
|
51
|
-
*
|
|
52
|
-
* No arguments — `settings_list_definitions` takes none; it always enumerates the caller's own
|
|
53
|
-
* (boot-wired) workspace's site-owned partition plus the shared platform partition. */
|
|
54
|
-
const NO_INPUT_SCHEMA = {
|
|
55
|
-
type: "object",
|
|
56
|
-
additionalProperties: false,
|
|
57
|
-
required: [],
|
|
58
|
-
properties: {},
|
|
59
|
-
};
|
|
60
|
-
/** Shared by `settings_get_effective`/`settings_get_raw`: naming a DIFFERENT principal than the
|
|
61
|
-
* caller requires `settings.user.read` (checked by the handler, not expressed in this schema). */
|
|
62
|
-
const PRINCIPAL_ID_PROPERTY = {
|
|
63
|
-
type: "string",
|
|
64
|
-
description: "Read another principal's user-layer value instead of the caller's own. Requires the settings.user.read permission when it names a principal other than the caller. Omit to read the caller's own user layer.",
|
|
65
|
-
};
|
|
66
|
-
const GET_EFFECTIVE_SCHEMA = {
|
|
67
|
-
type: "object",
|
|
68
|
-
additionalProperties: false,
|
|
69
|
-
required: ["namespace"],
|
|
70
|
-
properties: {
|
|
71
|
-
namespace: { type: "string", minLength: 1, description: "The settings namespace to enumerate, e.g. 'core.presentation'." },
|
|
72
|
-
principalId: PRINCIPAL_ID_PROPERTY,
|
|
73
|
-
},
|
|
74
|
-
};
|
|
75
|
-
const GET_RAW_SCHEMA = {
|
|
76
|
-
type: "object",
|
|
77
|
-
additionalProperties: false,
|
|
78
|
-
required: ["namespace", "key"],
|
|
79
|
-
properties: {
|
|
80
|
-
namespace: { type: "string", minLength: 1, description: "The settings namespace the key belongs to, e.g. 'core.presentation'." },
|
|
81
|
-
key: { type: "string", minLength: 1, description: "The setting key within the namespace." },
|
|
82
|
-
principalId: PRINCIPAL_ID_PROPERTY,
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
/**
|
|
86
|
-
* Input schema for `settings_set_ui_preference`.
|
|
87
|
-
*
|
|
88
|
-
* The `enum` on `setting` is the load-bearing part and the reason this tool is wireable at all —
|
|
89
|
-
* it is what makes "which key" a schema-constrained choice rather than free text. Built from
|
|
90
|
-
* {@link AGENT_WRITABLE_PREFERENCE_IDS} rather than listed here, so the published schema and the
|
|
91
|
-
* handler's own allowlist check cannot disagree.
|
|
92
|
-
*
|
|
93
|
-
* `value` is typed only as "present". Constraining it here would mean restating seven different
|
|
94
|
-
* per-key schemas that the ledger already holds and already enforces inside the write chokepoint
|
|
95
|
-
* (`write-service.ts`'s `set()`), and a second copy that drifts is worse than no copy: it would
|
|
96
|
-
* reject values the ledger accepts, or — far worse — describe as acceptable a shape the ledger
|
|
97
|
-
* will refuse. The per-key hints below tell the model what to send; the ledger decides.
|
|
98
|
-
*/
|
|
99
|
-
const SET_UI_PREFERENCE_SCHEMA = {
|
|
100
|
-
type: "object",
|
|
101
|
-
additionalProperties: false,
|
|
102
|
-
required: ["setting", "value"],
|
|
103
|
-
properties: {
|
|
104
|
-
setting: {
|
|
105
|
-
type: "string",
|
|
106
|
-
enum: AGENT_WRITABLE_PREFERENCE_IDS,
|
|
107
|
-
description: `The preference to set. Legal values and what each expects: ${AGENT_WRITABLE_PREFERENCES.map((p) => `${p.id} — ${p.valueHint}`).join(" | ")}`,
|
|
108
|
-
},
|
|
109
|
-
value: {
|
|
110
|
-
description: "The new value, matching the shape described for the chosen setting. Validated against that setting's registered schema; a mismatch is rejected and nothing is written.",
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
};
|
|
114
|
-
/** Both generic writes target only this workspace or the caller's own user layer. */
|
|
115
|
-
const CLEAR_VALUE_SCHEMA = {
|
|
116
|
-
type: "object",
|
|
117
|
-
additionalProperties: false,
|
|
118
|
-
required: ["namespace", "key"],
|
|
119
|
-
properties: {
|
|
120
|
-
namespace: { type: "string", minLength: 1, description: "A registered settings namespace; call settings_list_definitions first." },
|
|
121
|
-
key: { type: "string", minLength: 1, description: "A registered key inside the namespace." },
|
|
122
|
-
scope: { type: "string", enum: ["workspace", "user"], default: "workspace", description: "Workspace override, or only the calling operator's own user override." },
|
|
123
|
-
},
|
|
124
|
-
};
|
|
125
|
-
const SET_VALUE_SCHEMA = {
|
|
126
|
-
...CLEAR_VALUE_SCHEMA,
|
|
127
|
-
required: ["namespace", "key", "value"],
|
|
128
|
-
properties: { ...CLEAR_VALUE_SCHEMA.properties, value: { description: "Any JSON matching the definition schema returned by settings_list_definitions." } },
|
|
129
|
-
};
|
|
130
|
-
/**
|
|
131
|
-
* The Settings domain's fixed agent-tool catalog — three reads, three bounded writes, and two bulk/schema writes documented but never
|
|
132
|
-
* wired. See file header.
|
|
133
|
-
*
|
|
134
|
-
* @complexity O(1) — a fixed, statically-defined list.
|
|
135
|
-
* @overallScore 100
|
|
136
|
-
*/
|
|
137
|
-
export function getSettingsAgentToolCatalog() {
|
|
138
|
-
return [
|
|
139
|
-
{
|
|
140
|
-
name: "settings_list_definitions",
|
|
141
|
-
description: "Lists every active setting definition visible to this workspace (platform core/theme definitions plus this workspace's own site-owned definitions): namespace, key, owner kind, scope bitmask, status, version, schema, agentWritable and confirmationRequired. Use before writing a setting. Metadata only — never a value.",
|
|
142
|
-
sideEffects: "none",
|
|
143
|
-
authorization: { permission: "settings.read.definitions" },
|
|
144
|
-
inputSchema: NO_INPUT_SCHEMA,
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
name: "settings_get_effective",
|
|
148
|
-
description: "Returns the effective (precedence-resolved: user, then workspace, then global, then default) value of every active setting registered in a namespace.",
|
|
149
|
-
sideEffects: "none",
|
|
150
|
-
authorization: { permission: "settings.read" },
|
|
151
|
-
inputSchema: GET_EFFECTIVE_SCHEMA,
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
name: "settings_get_raw",
|
|
155
|
-
description: "Returns the per-layer raw values (global, workspace, user, default) of one setting key, unresolved by precedence.",
|
|
156
|
-
sideEffects: "none",
|
|
157
|
-
authorization: { permission: "settings.read.raw" },
|
|
158
|
-
inputSchema: GET_RAW_SCHEMA,
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
name: "settings_set_ui_preference",
|
|
162
|
-
description: "Sets one of the operator's own admin-UI preferences (interface language, theme, accent color, or notification sounds) and returns the stored value. Writes only to the calling operator's own user layer — it cannot target another operator, another scope, or any setting outside its fixed list. Use settings_get_effective to read current values first.",
|
|
163
|
-
sideEffects: "mutates-durable-state",
|
|
164
|
-
// The narrowest write grant in the system, and it is what this tool derives BECAUSE it never
|
|
165
|
-
// names a target principal (`write-service.ts`'s `deriveRequiredPermission`). Declared here
|
|
166
|
-
// to match; the handler does not pass this string, it lets the chokepoint derive it, so the
|
|
167
|
-
// two cannot drift into a state where this file advertises a check that is not the one run.
|
|
168
|
-
authorization: { permission: "settings.user.self.write" },
|
|
169
|
-
inputSchema: SET_UI_PREFERENCE_SCHEMA,
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
name: "settings_set_value",
|
|
173
|
-
description: "Sets one registered setting at workspace scope (default) or the caller's own user scope. Call settings_list_definitions for valid keys, schemas, scopes and confirmation policy. Returns {key, scope, previous, value, revisionSeq}; previous is the old override, or null if absent. Privacy, instructions and host-protected assistant settings need a human confirmation card; the agent cannot confirm itself. Rejects unknown/tombstoned keys, disallowed scopes, invalid values and missing permissions. Cannot write globally, target another operator, reset a namespace or change definitions.",
|
|
174
|
-
sideEffects: "mutates-durable-state",
|
|
175
|
-
authorization: { permission: "settings.workspace.write" },
|
|
176
|
-
inputSchema: SET_VALUE_SCHEMA,
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
name: "settings_clear_value",
|
|
180
|
-
description: "Clears one setting override at workspace scope (default) or the caller's own user scope so the next layer/default applies. Use to put one setting back to its inherited value; not to reset a namespace or delete a definition. Returns {key, scope, previous, effective}; restore a non-null previous override with settings_set_value. Protected assistant settings require a human confirmation card. Rejects unknown/tombstoned keys, disallowed scopes and missing permissions; cannot target global or another operator's layer.",
|
|
181
|
-
sideEffects: "mutates-durable-state",
|
|
182
|
-
authorization: { permission: "settings.workspace.write" },
|
|
183
|
-
inputSchema: CLEAR_VALUE_SCHEMA,
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
// EXCLUDED BY DESIGN, never wired: see this file's header. Bulk variant of a single-value clear —
|
|
187
|
-
// clears every value in an operator-named namespace at a scope in one call, irreversible.
|
|
188
|
-
name: "settings_reset",
|
|
189
|
-
description: "Resets every setting in a namespace to defaults at a scope. NEVER agent-callable — see file header.",
|
|
190
|
-
sideEffects: "mutates-durable-state",
|
|
191
|
-
authorization: { permission: "settings.reset.workspace" },
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
// EXCLUDED BY DESIGN, never wired: see this file's header. Schema-level, not value-level —
|
|
195
|
-
// can rename/retype/deprecate/tombstone the definition a key resolves through, changing how
|
|
196
|
-
// every existing stored value for that key is interpreted platform-wide.
|
|
197
|
-
name: "settings_register_definitions",
|
|
198
|
-
description: "Registers, renames, retypes, deprecates, or tombstones setting definitions. NEVER agent-callable — see file header.",
|
|
199
|
-
sideEffects: "mutates-durable-state",
|
|
200
|
-
authorization: { permission: "settings.definitions.manage" },
|
|
201
|
-
},
|
|
202
|
-
];
|
|
203
|
-
}
|
|
204
|
-
//# sourceMappingURL=agent-tools.js.map
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { type ToolExecutionContext, type ToolHandler } from "@jini-ai/core";
|
|
2
|
-
import type { JsonValue } from "@jini-ai/core/primitives";
|
|
3
|
-
import type { SettingsToolDeps } from "./tool-registrations.js";
|
|
4
|
-
export type SettingsValueWriteToolId = "settings_set_value" | "settings_clear_value";
|
|
5
|
-
/** Host-only port. This request is never an agent input and only the host's authenticated
|
|
6
|
-
* human transport may answer it. Returning true without a human violates this contract. */
|
|
7
|
-
export interface SettingsWriteConfirmation {
|
|
8
|
-
ctx: ToolExecutionContext;
|
|
9
|
-
toolId: SettingsValueWriteToolId;
|
|
10
|
-
namespace: string;
|
|
11
|
-
key: string;
|
|
12
|
-
scope: "workspace" | "user";
|
|
13
|
-
previous: JsonValue | null;
|
|
14
|
-
value?: JsonValue;
|
|
15
|
-
reason: string;
|
|
16
|
-
}
|
|
17
|
-
/** Builds one value-write handler. Effects: authorize -> raw read -> optional human card ->
|
|
18
|
-
* service write -> result. The service rechecks authorization and performs its normal transaction.
|
|
19
|
-
* @complexity O(value size + rule count) plus bounded repository calls and a human wait.
|
|
20
|
-
* @throws ToolInputError for invalid input, denied keys, absent/declined/stale confirmation. */
|
|
21
|
-
export declare function buildSettingsValueWriteHandler(deps: SettingsToolDeps, toolId: SettingsValueWriteToolId): ToolHandler;
|
|
22
|
-
//# sourceMappingURL=agent-value-write-tools.d.ts.map
|
|
@@ -1,154 +0,0 @@
|
|
|
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
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* One agent-writable preference.
|
|
3
|
-
*
|
|
4
|
-
* `namespace`/`key` are the ledger coordinates; `id` is the dotted form published to the model.
|
|
5
|
-
* They are kept as separate fields rather than split from `id` at call time because a key may
|
|
6
|
-
* itself contain dots (`telemetry.metrics` in the withheld privacy set proves the split is not
|
|
7
|
-
* unambiguous), so deriving one from the other would be a latent bug the moment the allowlist grows.
|
|
8
|
-
*/
|
|
9
|
-
export interface AgentWritablePreference {
|
|
10
|
-
/** The dotted `namespace.key`, published in the tool's `setting` enum. */
|
|
11
|
-
readonly id: string;
|
|
12
|
-
readonly namespace: string;
|
|
13
|
-
readonly key: string;
|
|
14
|
-
/**
|
|
15
|
-
* Human-readable hint published alongside the enum, so a model knows what a legal value looks
|
|
16
|
-
* like without a round trip. NOT a validator — the ledger's registered definition schema is the
|
|
17
|
-
* only thing that accepts or rejects a value, and it is checked inside the write chokepoint.
|
|
18
|
-
*/
|
|
19
|
-
readonly valueHint: string;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* The scope every write through this surface uses.
|
|
23
|
-
*
|
|
24
|
-
* `user`, always, and never operator-selectable. All seven keys register `user | workspace`
|
|
25
|
-
* (`ui-tab-definitions.ts`'s `PER_OPERATOR_SCOPES` / `NOTIFICATIONS_SCOPES`), so `workspace` is
|
|
26
|
-
* reachable in principle — and deliberately not offered. A workspace-scoped write changes the
|
|
27
|
-
* inherited default for every operator who has no user-scoped row of their own, which is a write
|
|
28
|
-
* whose blast radius the caller cannot see. The user layer affects exactly one person, and
|
|
29
|
-
* `write-service.ts`'s `deriveRequiredPermission` gates it behind `settings.user.self.write`, the
|
|
30
|
-
* narrowest write grant in the system, only because the target principal is left unnamed.
|
|
31
|
-
*/
|
|
32
|
-
export declare const AGENT_PREFERENCE_WRITE_SCOPE: "user";
|
|
33
|
-
/**
|
|
34
|
-
* Asserted by `__tests__/agent-writable-preferences.test.ts` against `ui-tab-definitions.ts`:
|
|
35
|
-
* every id below must correspond to a definition that is actually registered AND whose scope mask
|
|
36
|
-
* includes {@link SCOPE_BIT.user}. That test is the real guard on this file — an entry naming an
|
|
37
|
-
* unregistered key would otherwise fail only at call time, as a runtime `DefinitionNotFoundError`
|
|
38
|
-
* from inside the write chokepoint, on a tool the model had already been told it could call.
|
|
39
|
-
*/
|
|
40
|
-
export declare const AGENT_WRITABLE_PREFERENCES: readonly AgentWritablePreference[];
|
|
41
|
-
/**
|
|
42
|
-
* The `setting` enum published in the tool's input schema.
|
|
43
|
-
*
|
|
44
|
-
* Derived from {@link AGENT_WRITABLE_PREFERENCES} rather than written out a second time: a
|
|
45
|
-
* hand-maintained copy is how an id ends up callable after being removed from the allowlist.
|
|
46
|
-
*
|
|
47
|
-
* @complexity O(n) once at module load.
|
|
48
|
-
*/
|
|
49
|
-
export declare const AGENT_WRITABLE_PREFERENCE_IDS: readonly string[];
|
|
50
|
-
/**
|
|
51
|
-
* Resolves a model-supplied `setting` id to its ledger coordinates.
|
|
52
|
-
*
|
|
53
|
-
* Returns `undefined` for anything not on the allowlist — including ids the enum should already
|
|
54
|
-
* have rejected. The redundancy is the point: the enum lives in a schema a caller validates
|
|
55
|
-
* against, and this is the check that holds if that validation is ever bypassed, misconfigured, or
|
|
56
|
-
* outrun by a stale published descriptor. A curated allowlist that is enforced in only one place
|
|
57
|
-
* is enforced nowhere in particular.
|
|
58
|
-
*
|
|
59
|
-
* @param settingId - The dotted `namespace.key` from the tool input.
|
|
60
|
-
* @returns The matching preference, or `undefined` if it is not agent-writable.
|
|
61
|
-
* @complexity O(1).
|
|
62
|
-
* @overallScore 100
|
|
63
|
-
*/
|
|
64
|
-
export declare function resolveAgentWritablePreference(settingId: string): AgentWritablePreference | undefined;
|
|
65
|
-
/** Re-exported so the drift test can assert the scope mask without reaching into `types.ts` itself. */
|
|
66
|
-
export declare const AGENT_PREFERENCE_REQUIRED_SCOPE_BIT: 4;
|
|
67
|
-
//# sourceMappingURL=agent-writable-preferences.d.ts.map
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file The curated list of setting keys an agent may write — the precondition
|
|
3
|
-
* `agent-tools.ts`'s header names.
|
|
4
|
-
*
|
|
5
|
-
* ## The curated surface and the generic value tools
|
|
6
|
-
*
|
|
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.
|
|
13
|
-
*
|
|
14
|
-
* ## What is deliberately NOT here
|
|
15
|
-
*
|
|
16
|
-
* `ui-tab-definitions.ts` registers 12 keys. Five are withheld:
|
|
17
|
-
*
|
|
18
|
-
* - **`core.privacy.telemetry.metrics` / `telemetry.content` / `decisionAt` / `installationId`** —
|
|
19
|
-
* a telemetry consent record whose entire purpose is to attest that a HUMAN decided. An agent
|
|
20
|
-
* writing it would not be recording a decision, it would be manufacturing one, and `decisionAt`
|
|
21
|
-
* is specifically the field the tab reads to know whether to stop asking. Withheld because the
|
|
22
|
-
* value means something different depending on who wrote it — the one property a curated
|
|
23
|
-
* allowlist cannot express.
|
|
24
|
-
* - **`core.instructions.custom`** — the custom instructions prepended to every admin-assistant
|
|
25
|
-
* conversation. An agent writing this edits its own standing prompt for all future runs. That
|
|
26
|
-
* is self-modification, not a display preference: the generic tool now requires a human card.
|
|
27
|
-
*
|
|
28
|
-
* Every key that IS here is a per-operator display preference: reversible in one call, scoped to
|
|
29
|
-
* the caller's own user layer, and visible in the admin UI the moment it changes — which is what
|
|
30
|
-
* makes the whole surface auditable by looking at it.
|
|
31
|
-
*
|
|
32
|
-
* ## Architectural role
|
|
33
|
-
*
|
|
34
|
-
* `settings` domain data. No I/O, no enforcement — `tool-registrations.ts` performs the
|
|
35
|
-
* `authorize()` call and the write. Kept as data rather than inlined into the catalog so the tool
|
|
36
|
-
* schema, the handler's dispatch, and the drift test all read the same source.
|
|
37
|
-
*/
|
|
38
|
-
import { SCOPE_BIT } from "./types.js";
|
|
39
|
-
import { APPEARANCE_NAMESPACE, LANGUAGE_NAMESPACE, NOTIFICATIONS_NAMESPACE, } from "./ui-tab-definitions.js";
|
|
40
|
-
/**
|
|
41
|
-
* The scope every write through this surface uses.
|
|
42
|
-
*
|
|
43
|
-
* `user`, always, and never operator-selectable. All seven keys register `user | workspace`
|
|
44
|
-
* (`ui-tab-definitions.ts`'s `PER_OPERATOR_SCOPES` / `NOTIFICATIONS_SCOPES`), so `workspace` is
|
|
45
|
-
* reachable in principle — and deliberately not offered. A workspace-scoped write changes the
|
|
46
|
-
* inherited default for every operator who has no user-scoped row of their own, which is a write
|
|
47
|
-
* whose blast radius the caller cannot see. The user layer affects exactly one person, and
|
|
48
|
-
* `write-service.ts`'s `deriveRequiredPermission` gates it behind `settings.user.self.write`, the
|
|
49
|
-
* narrowest write grant in the system, only because the target principal is left unnamed.
|
|
50
|
-
*/
|
|
51
|
-
export const AGENT_PREFERENCE_WRITE_SCOPE = "user";
|
|
52
|
-
/**
|
|
53
|
-
* Asserted by `__tests__/agent-writable-preferences.test.ts` against `ui-tab-definitions.ts`:
|
|
54
|
-
* every id below must correspond to a definition that is actually registered AND whose scope mask
|
|
55
|
-
* includes {@link SCOPE_BIT.user}. That test is the real guard on this file — an entry naming an
|
|
56
|
-
* unregistered key would otherwise fail only at call time, as a runtime `DefinitionNotFoundError`
|
|
57
|
-
* from inside the write chokepoint, on a tool the model had already been told it could call.
|
|
58
|
-
*/
|
|
59
|
-
export const AGENT_WRITABLE_PREFERENCES = [
|
|
60
|
-
{
|
|
61
|
-
id: "core.language.locale",
|
|
62
|
-
namespace: LANGUAGE_NAMESPACE,
|
|
63
|
-
key: "locale",
|
|
64
|
-
valueHint: "A BCP-47 language code the admin UI ships a translation for, e.g. 'en' or 'es'. An unrecognized code is stored but selects no option in the UI.",
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
id: "core.appearance.theme",
|
|
68
|
-
namespace: APPEARANCE_NAMESPACE,
|
|
69
|
-
key: "theme",
|
|
70
|
-
valueHint: "One of 'system', 'light', or 'dark'.",
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
id: "core.appearance.accentColor",
|
|
74
|
-
namespace: APPEARANCE_NAMESPACE,
|
|
75
|
-
key: "accentColor",
|
|
76
|
-
valueHint: "A hex color, e.g. '#2563eb'. Malformed values are rejected at render time.",
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
id: "core.notifications.soundEnabled",
|
|
80
|
-
namespace: NOTIFICATIONS_NAMESPACE,
|
|
81
|
-
key: "soundEnabled",
|
|
82
|
-
valueHint: "Boolean — whether a sound plays when an assistant run finishes.",
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
id: "core.notifications.successSoundId",
|
|
86
|
-
namespace: NOTIFICATIONS_NAMESPACE,
|
|
87
|
-
key: "successSoundId",
|
|
88
|
-
valueHint: "Sound id for a successful run, e.g. 'ding'. An unknown id falls back to the default.",
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
id: "core.notifications.failureSoundId",
|
|
92
|
-
namespace: NOTIFICATIONS_NAMESPACE,
|
|
93
|
-
key: "failureSoundId",
|
|
94
|
-
valueHint: "Sound id for a failed run, e.g. 'buzz'. An unknown id falls back to the default.",
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
id: "core.notifications.desktopEnabled",
|
|
98
|
-
namespace: NOTIFICATIONS_NAMESPACE,
|
|
99
|
-
key: "desktopEnabled",
|
|
100
|
-
valueHint: "Boolean — the operator's INTENT to receive desktop notifications. The browser's own Notification permission is separate and not settable from here.",
|
|
101
|
-
},
|
|
102
|
-
];
|
|
103
|
-
const BY_ID = new Map(AGENT_WRITABLE_PREFERENCES.map((pref) => [pref.id, pref]));
|
|
104
|
-
/**
|
|
105
|
-
* The `setting` enum published in the tool's input schema.
|
|
106
|
-
*
|
|
107
|
-
* Derived from {@link AGENT_WRITABLE_PREFERENCES} rather than written out a second time: a
|
|
108
|
-
* hand-maintained copy is how an id ends up callable after being removed from the allowlist.
|
|
109
|
-
*
|
|
110
|
-
* @complexity O(n) once at module load.
|
|
111
|
-
*/
|
|
112
|
-
export const AGENT_WRITABLE_PREFERENCE_IDS = AGENT_WRITABLE_PREFERENCES.map((p) => p.id);
|
|
113
|
-
/**
|
|
114
|
-
* Resolves a model-supplied `setting` id to its ledger coordinates.
|
|
115
|
-
*
|
|
116
|
-
* Returns `undefined` for anything not on the allowlist — including ids the enum should already
|
|
117
|
-
* have rejected. The redundancy is the point: the enum lives in a schema a caller validates
|
|
118
|
-
* against, and this is the check that holds if that validation is ever bypassed, misconfigured, or
|
|
119
|
-
* outrun by a stale published descriptor. A curated allowlist that is enforced in only one place
|
|
120
|
-
* is enforced nowhere in particular.
|
|
121
|
-
*
|
|
122
|
-
* @param settingId - The dotted `namespace.key` from the tool input.
|
|
123
|
-
* @returns The matching preference, or `undefined` if it is not agent-writable.
|
|
124
|
-
* @complexity O(1).
|
|
125
|
-
* @overallScore 100
|
|
126
|
-
*/
|
|
127
|
-
export function resolveAgentWritablePreference(settingId) {
|
|
128
|
-
return BY_ID.get(settingId);
|
|
129
|
-
}
|
|
130
|
-
/** Re-exported so the drift test can assert the scope mask without reaching into `types.ts` itself. */
|
|
131
|
-
export const AGENT_PREFERENCE_REQUIRED_SCOPE_BIT = SCOPE_BIT.user;
|
|
132
|
-
//# sourceMappingURL=agent-writable-preferences.js.map
|
|
@@ -1,19 +0,0 @@
|
|
|
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
|
|
@@ -1,15 +0,0 @@
|
|
|
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
|