@sema-agent/client-core 0.102.0 → 0.103.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +8 -5
  3. package/dist/adapt/toolCards.d.ts +2 -1
  4. package/dist/adapt/toolCards.js +3 -1
  5. package/dist/adapter/downstream/eventToSdkMessage.d.ts +5 -1
  6. package/dist/adapter/downstream/eventToSdkMessage.js +21 -3
  7. package/dist/adapter/downstream/terminalToSdkResult.js +0 -1
  8. package/dist/adapter/downstream/wiringManifestView.js +4 -1
  9. package/dist/cloudConfigWireCaps.js +6 -3
  10. package/dist/credentialPlaneCapability.d.ts +22 -0
  11. package/dist/credentialPlaneCapability.js +75 -0
  12. package/dist/deviceExecutorManagementCapability.d.ts +1 -0
  13. package/dist/deviceExecutorManagementCapability.js +3 -1
  14. package/dist/engineErrorCodes.d.ts +1 -0
  15. package/dist/engineErrorCodes.js +3 -1
  16. package/dist/engineNoticeCodes.d.ts +26 -0
  17. package/dist/engineNoticeCodes.js +121 -12
  18. package/dist/engineRowRef.js +1 -0
  19. package/dist/errorSupplementRoles.js +1 -3
  20. package/dist/eventLeg.js +2 -1
  21. package/dist/fleet/fleetProjection.js +15 -9
  22. package/dist/gateOutcome.d.ts +20 -0
  23. package/dist/gateOutcome.js +89 -0
  24. package/dist/generated/engineAskFaceTables.js +2 -2
  25. package/dist/generated/engineFactTables.d.ts +6 -2
  26. package/dist/generated/engineFactTables.js +41 -1
  27. package/dist/generated/engineNoticeTables.js +18 -0
  28. package/dist/generated/settingsSchemaDefaultModel.d.ts +1 -1
  29. package/dist/generated/settingsSchemaDefaultModel.js +2 -2
  30. package/dist/generated/settingsSchemaFns.d.ts +15 -0
  31. package/dist/generated/settingsSchemaFns.js +25 -2
  32. package/dist/generated/settingsSchemaHooksClassifier.js +109 -29
  33. package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -1
  34. package/dist/generated/settingsSchemaMcpRequestEntry.js +213 -93
  35. package/dist/generated/settingsSchemaMcpServerName.d.ts +1 -0
  36. package/dist/generated/settingsSchemaMcpServerName.js +8 -0
  37. package/dist/generated/settingsSchemaOwnKeyRead.d.ts +1 -0
  38. package/dist/generated/settingsSchemaOwnKeyRead.js +172 -0
  39. package/dist/generated/settingsSchemaPlainJsonObject.d.ts +1 -0
  40. package/dist/generated/settingsSchemaPlainJsonObject.js +28 -0
  41. package/dist/generated/settingsSchemaSafetyMergeSpec.js +10 -7
  42. package/dist/generated/settingsSchemaTierWords.d.ts +1 -0
  43. package/dist/generated/settingsSchemaTierWords.js +7 -0
  44. package/dist/generated/settingsSchemaTypes.d.ts +3 -1
  45. package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
  46. package/dist/hitl/decisionConflict.js +11 -11
  47. package/dist/hitl/decisionRefusal.d.ts +1 -0
  48. package/dist/hitl/decisionRefusal.js +4 -2
  49. package/dist/hitl/editedRuleTextPrecheck.d.ts +1 -0
  50. package/dist/hitl/editedRuleTextPrecheck.js +26 -1
  51. package/dist/hitl/persistedRulesWire.js +1 -0
  52. package/dist/hitl/planReviewWire.d.ts +2 -1
  53. package/dist/hitl/planReviewWire.js +8 -12
  54. package/dist/hitl/sessionPolicyDeliverable.d.ts +0 -1
  55. package/dist/hitl/sessionPolicyDeliverable.js +0 -5
  56. package/dist/hitl/sessionPolicyWire.js +1 -1
  57. package/dist/hitl/toolApprovalWire.d.ts +18 -6
  58. package/dist/hitl/toolApprovalWire.js +9 -4
  59. package/dist/i18n/messages.en.d.ts +5 -0
  60. package/dist/i18n/messages.en.js +6 -1
  61. package/dist/i18n/messages.zh.js +6 -1
  62. package/dist/index.d.ts +3 -2
  63. package/dist/index.js +2 -1
  64. package/dist/inheritEnvWire.d.ts +1 -0
  65. package/dist/inheritEnvWire.js +8 -5
  66. package/dist/mcpEngineLeg.d.ts +3 -0
  67. package/dist/mcpEngineLeg.js +4 -1
  68. package/dist/mcpLiveness.d.ts +18 -0
  69. package/dist/mcpLiveness.js +48 -1
  70. package/dist/mcpReconnect.d.ts +3 -0
  71. package/dist/mcpReconnect.js +6 -0
  72. package/dist/mcpStatusSupersetKeys.js +24 -1
  73. package/dist/mcpWireCaps.d.ts +2 -3
  74. package/dist/mcpWireCaps.js +9 -8
  75. package/dist/memoryEntriesWire.d.ts +35 -1
  76. package/dist/memoryEntriesWire.js +110 -14
  77. package/dist/modsFace.js +7 -3
  78. package/dist/postureKnob.js +1 -1
  79. package/dist/prepareRefusal.d.ts +0 -1
  80. package/dist/prepareRefusal.js +0 -3
  81. package/dist/promptProfileWireCaps.d.ts +1 -3
  82. package/dist/promptProfileWireCaps.js +2 -2
  83. package/dist/request/taskRequest.d.ts +1 -1
  84. package/dist/request/taskRequest.js +3 -3
  85. package/dist/retryStatus.d.ts +13 -1
  86. package/dist/retryStatus.js +20 -5
  87. package/dist/seatContract.js +10 -0
  88. package/dist/sessionMemoryErase.js +24 -2
  89. package/dist/turnFailurePresentation.js +8 -1
  90. package/dist/wireFailureShape.d.ts +12 -1
  91. package/dist/wireFailureShape.js +58 -24
  92. package/dist/wireRefusalCopy.d.ts +0 -3
  93. package/dist/wireRefusalCopy.js +0 -17
  94. package/docs/INTEGRATION-CLIENTS.md +155 -10
  95. package/package.json +5 -5
@@ -1,22 +1,47 @@
1
- export const SETTINGS_MCP_REQUEST_ENTRY_CLOSURE = (MCP_CONTENT_ORIGINS, startsWithHttpScheme, echoCallerText) => {
1
+ export const SETTINGS_MCP_REQUEST_ENTRY_CLOSURE = (MCP_CONTENT_ORIGINS, startsWithHttpScheme, echoCallerText, UNINSPECTABLE, captureStringArray, dataDescriptor, inspect, ownFieldsOf, ownValueOf, readKey, isJsonArray, jsonShapeOf, isReservedMcpServerName, RESERVED_MCP_SERVER_NAME_REASON) => {
2
+ function describeKindWord(v) {
3
+ const shape = jsonShapeOf(v);
4
+ switch (shape) {
5
+ case "null":
6
+ return "null";
7
+ case "array":
8
+ return "array";
9
+ case "uninspectable":
10
+ return UNINSPECTABLE;
11
+ case "plain":
12
+ case "non_plain_object":
13
+ case "primitive":
14
+ return typeof v;
15
+ default: {
16
+ const unhandled = shape;
17
+ throw new Error(`describeKindWord: unhandled shape ${String(unhandled)}`);
18
+ }
19
+ }
20
+ }
2
21
  function describeValueShape(v) {
3
22
  if (v === undefined)
4
23
  return "nothing (the key is absent)";
5
- if (v === null)
6
- return "null";
7
- if (Array.isArray(v))
8
- return "an array";
9
- if (typeof v === "string")
10
- return v.length === 0 ? "an empty string" : `a string of ${v.length} characters`;
11
- if (typeof v === "object")
12
- return "an object";
13
- return `a ${typeof v}`;
24
+ const shape = jsonShapeOf(v);
25
+ switch (shape) {
26
+ case "null":
27
+ return "null";
28
+ case "array":
29
+ return "an array";
30
+ case "uninspectable":
31
+ return UNINSPECTABLE;
32
+ case "plain":
33
+ case "non_plain_object":
34
+ return typeof v === "function" ? "a function" : "an object";
35
+ case "primitive":
36
+ return typeof v === "string" ? (v.length === 0 ? "an empty string" : `a string of ${v.length} characters`) : `a ${typeof v}`;
37
+ default: {
38
+ const unhandled = shape;
39
+ throw new Error(`describeValueShape: unhandled shape ${String(unhandled)}`);
40
+ }
41
+ }
14
42
  }
15
43
  function describeNotStringArray(v) {
16
- return Array.isArray(v) ? "an array with a non-string element" : describeValueShape(v);
17
- }
18
- function isStringArray(v) {
19
- return Array.isArray(v) && v.every((a) => typeof a === "string");
44
+ return isJsonArray(v) ? "an array with a non-string element" : describeValueShape(v);
20
45
  }
21
46
  function quotedCallerText(text) {
22
47
  return `"${echoCallerText(text)}"`;
@@ -28,7 +53,7 @@ export const SETTINGS_MCP_REQUEST_ENTRY_CLOSURE = (MCP_CONTENT_ORIGINS, startsWi
28
53
  }
29
54
  function describeBadWireName(v) {
30
55
  if (typeof v !== "string")
31
- return v === null ? "null" : Array.isArray(v) ? "array" : typeof v;
56
+ return describeKindWord(v);
32
57
  if (v.length === 0)
33
58
  return "empty";
34
59
  const head = quotedCallerText(v);
@@ -37,120 +62,215 @@ export const SETTINGS_MCP_REQUEST_ENTRY_CLOSURE = (MCP_CONTENT_ORIGINS, startsWi
37
62
  return `${head} (${tooLong})`;
38
63
  return `${head} (${v.length > TOOL_WIRE_NAME_MAX_CHARS ? `${tooLong}, ` : ""}leading or trailing whitespace)`;
39
64
  }
65
+ function isUsableMcpServerName(v) {
66
+ return isUsableWireName(v) && !isReservedMcpServerName(v);
67
+ }
68
+ function describeBadMcpServerName(v) {
69
+ if (!isUsableWireName(v))
70
+ return describeBadWireName(v);
71
+ return `${quotedCallerText(v)} (${RESERVED_MCP_SERVER_NAME_REASON})`;
72
+ }
40
73
  const CONTENT_ORIGIN_WORDS = new Set(MCP_CONTENT_ORIGINS);
41
74
  function isContentOriginWord(v) {
42
75
  return typeof v === "string" && CONTENT_ORIGIN_WORDS.has(v);
43
76
  }
44
77
  function describeBadContentOrigin(v) {
45
- return typeof v === "string" ? quotedCallerText(v) : v === null ? "null" : Array.isArray(v) ? "array" : typeof v;
78
+ return typeof v === "string" ? quotedCallerText(v) : describeKindWord(v);
46
79
  }
47
80
  function readMcpIdentityHeaders(transport) {
81
+ const ids = identityFieldsOf(transport);
82
+ if (!ids.ok)
83
+ return {};
84
+ const { principalHeader, assertionHeader } = ids.value;
85
+ return {
86
+ ...(typeof principalHeader === "string" ? { principalHeader } : {}),
87
+ ...(typeof assertionHeader === "string" ? { assertionHeader } : {}),
88
+ };
89
+ }
90
+ function identityFieldsOf(record) {
91
+ const principal = readKey(record, "principalHeader");
92
+ if (principal.presence === "unreadable")
93
+ return { ok: false, sentence: UNINSPECTABLE };
94
+ if (principal.presence === "own" && principal.value !== undefined) {
95
+ return { ok: true, value: { principalHeader: principal.value, assertionHeader: undefined, principalInherited: false, assertionInherited: false } };
96
+ }
97
+ const assertion = readKey(record, "assertionHeader");
98
+ if (assertion.presence === "unreadable")
99
+ return { ok: false, sentence: UNINSPECTABLE };
48
100
  return {
49
- ...(typeof transport.principalHeader === "string" ? { principalHeader: transport.principalHeader } : {}),
50
- ...(transport.principalHeader === undefined && typeof transport.assertionHeader === "string" ? { assertionHeader: transport.assertionHeader } : {}),
101
+ ok: true,
102
+ value: {
103
+ principalHeader: undefined,
104
+ assertionHeader: assertion.presence === "own" ? assertion.value : undefined,
105
+ principalInherited: principal.presence === "inherited",
106
+ assertionInherited: assertion.presence === "inherited",
107
+ },
51
108
  };
52
109
  }
53
110
  const transportBad = (path, reason) => ({ ok: false, issue: { path, reason } });
111
+ const inheritedIdentityIssue = (key) => ({
112
+ path: `transport.${key}`,
113
+ reason: "inherited key ignored (the key is visible only through the prototype chain; a transport's identity headers are read from its own keys)",
114
+ });
54
115
  function readRequestMcpTransport(t) {
55
- if (!t || typeof t !== "object")
56
- return transportBad("transport", `must be an object with a "kind" of "stdio" or "http" — got ${describeValueShape(t)}`);
57
- const tr = t;
58
- const lost = [];
59
- if (tr.kind === "stdio") {
60
- if (typeof tr.command !== "string" || tr.command.length === 0)
61
- return transportBad("transport.command", `must be a non-empty string (the command to run) — got ${describeValueShape(tr.command)}`);
62
- if (tr.args !== undefined && !isStringArray(tr.args))
63
- lost.push({ path: "transport.args", reason: `must be an array of strings — got ${describeNotStringArray(tr.args)}` });
64
- const env = readTransportRecord("transport.env", tr.env, lost);
65
- return {
66
- ok: true,
67
- transport: {
68
- kind: "stdio",
69
- command: tr.command,
70
- ...(isStringArray(tr.args) ? { args: tr.args } : {}),
71
- ...(env !== undefined ? { env } : {}),
72
- },
73
- lost,
74
- };
116
+ const shape = jsonShapeOf(t);
117
+ switch (shape) {
118
+ case "plain":
119
+ case "array":
120
+ break;
121
+ case "null":
122
+ case "primitive":
123
+ return transportBad("transport", `must be an object with a "kind" of "stdio" or "http" — got ${describeValueShape(t)}`);
124
+ case "uninspectable":
125
+ return transportBad("transport", `must be an object with a "kind" of "stdio" or "http" — got ${UNINSPECTABLE}`);
126
+ case "non_plain_object":
127
+ return transportBad("transport", `must be an object with a "kind" of "stdio" or "http" — got ${typeof t === "function" ? describeValueShape(t) : "an object that is not plain data"}`);
128
+ default: {
129
+ const unhandled = shape;
130
+ throw new Error(`readRequestMcpTransport: unhandled shape ${String(unhandled)}`);
131
+ }
75
132
  }
76
- if (tr.kind === "http") {
77
- if (typeof tr.url !== "string" || !startsWithHttpScheme(tr.url))
78
- return transportBad("transport.url", "must be an absolute http(s) URL (put credentials in transport.headers, never in the URL)");
79
- const ids = readMcpIdentityHeaders(tr);
80
- const headers = readTransportRecord("transport.headers", tr.headers, lost);
81
- if (tr.principalHeader !== undefined && ids.principalHeader === undefined) {
82
- lost.push({ path: "transport.principalHeader", reason: `must be a string (the HTTP header NAME the end-user principal is injected into) — got ${describeValueShape(tr.principalHeader)}` });
133
+ const tr = t;
134
+ const snapshotRead = snapshotTransport(tr);
135
+ if (!snapshotRead.ok)
136
+ return transportBad("transport", `must be an object with a "kind" of "stdio" or "http" — got ${snapshotRead.sentence}`);
137
+ const snap = snapshotRead.value;
138
+ switch (snap.kind) {
139
+ case "stdio": {
140
+ if (typeof snap.command !== "string" || snap.command.length === 0)
141
+ return transportBad("transport.command", `must be a non-empty string (the command to run) — got ${describeValueShape(snap.command)}`);
142
+ const rawArgs = snap.args;
143
+ const args = rawArgs === undefined ? undefined : captureStringArray(rawArgs, "wide");
144
+ const argsIssue = rawArgs !== undefined && args === undefined ? { path: "transport.args", reason: `must be an array of strings — got ${describeNotStringArray(rawArgs)}` } : undefined;
145
+ const env = readTransportRecord("transport.env", snap.env);
146
+ return {
147
+ ok: true,
148
+ transport: {
149
+ kind: "stdio",
150
+ command: snap.command,
151
+ ...(args !== undefined ? { args } : {}),
152
+ ...(env.record !== undefined ? { env: env.record } : {}),
153
+ },
154
+ lost: issuesOf(argsIssue, ...env.issues),
155
+ };
156
+ }
157
+ case "http": {
158
+ if (typeof snap.url !== "string" || !startsWithHttpScheme(snap.url))
159
+ return transportBad("transport.url", "must be an absolute http(s) URL (put credentials in transport.headers, never in the URL)");
160
+ const ids = readMcpIdentityHeaders({ principalHeader: snap.principalHeader, assertionHeader: snap.assertionHeader });
161
+ const headers = readTransportRecord("transport.headers", snap.headers);
162
+ const principalIssue = snap.principalHeader !== undefined && ids.principalHeader === undefined
163
+ ? { path: "transport.principalHeader", reason: `must be a string (the HTTP header NAME the end-user principal is injected into) — got ${describeValueShape(snap.principalHeader)}` }
164
+ : undefined;
165
+ return {
166
+ ok: true,
167
+ transport: {
168
+ kind: "http",
169
+ url: snap.url,
170
+ ...(headers.record !== undefined ? { headers: headers.record } : {}),
171
+ ...ids,
172
+ },
173
+ lost: issuesOf(...headers.issues, principalIssue, snap.principalInherited ? inheritedIdentityIssue("principalHeader") : undefined, snap.assertionInherited ? inheritedIdentityIssue("assertionHeader") : undefined),
174
+ };
175
+ }
176
+ case "other":
177
+ return transportBad("transport.kind", `must be "stdio" or "http" — got ${describeValueShape(snap.value)}`);
178
+ default: {
179
+ const unhandled = snap;
180
+ throw new Error(`readRequestMcpTransport: unhandled transport kind ${String(unhandled.kind)}`);
83
181
  }
84
- return {
85
- ok: true,
86
- transport: {
87
- kind: "http",
88
- url: tr.url,
89
- ...(headers !== undefined ? { headers } : {}),
90
- ...ids,
91
- },
92
- lost,
93
- };
94
182
  }
95
- return transportBad("transport.kind", `must be "stdio" or "http" — got ${describeValueShape(tr.kind)}`);
96
183
  }
97
- const RESERVED_MEMBER_NAME = "__proto__";
98
- const RESERVED_MEMBER_FAULT = `no member of a declaration may be named "${RESERVED_MEMBER_NAME}"`;
99
- function readPlainStringRecord(v) {
100
- if (v === null || typeof v !== "object" || Array.isArray(v))
101
- return { ok: false, fault: "not_plain_record", detail: v === null ? "got null" : Array.isArray(v) ? "got an array" : `got a ${typeof v}` };
102
- let proto;
103
- let names;
104
- try {
105
- proto = Object.getPrototypeOf(v);
106
- names = Object.getOwnPropertyNames(v);
184
+ function snapshotTransport(tr) {
185
+ const kind = ownValueOf(tr, "kind");
186
+ if (!kind.ok)
187
+ return kind;
188
+ if (kind.value === "stdio") {
189
+ const fields = ownFieldsOf(tr, ["command", "args", "env"]);
190
+ if (!fields.ok)
191
+ return fields;
192
+ return { ok: true, value: { kind: "stdio", command: fields.value.command, args: fields.value.args, env: fields.value.env } };
107
193
  }
108
- catch {
109
- return { ok: false, fault: "not_plain_record", detail: "got an object that could not be inspected (a proxy trap threw)" };
194
+ if (kind.value === "http") {
195
+ const fields = ownFieldsOf(tr, ["url", "headers"]);
196
+ if (!fields.ok)
197
+ return fields;
198
+ const ids = identityFieldsOf(tr);
199
+ if (!ids.ok)
200
+ return ids;
201
+ return { ok: true, value: { kind: "http", url: fields.value.url, headers: fields.value.headers, principalHeader: ids.value.principalHeader, assertionHeader: ids.value.assertionHeader, principalInherited: ids.value.principalInherited, assertionInherited: ids.value.assertionInherited } };
110
202
  }
111
- if (proto !== Object.prototype && proto !== null) {
112
- return { ok: false, fault: "not_plain_record", detail: "got an object that is not plain data (a class instance, a Map, process.env, or a record built on a prototype; copy it into a plain object)" };
203
+ return { ok: true, value: { kind: "other", value: kind.value } };
204
+ }
205
+ const PLAIN_STRING_RECORD_RESERVED_MEMBER = "__proto__";
206
+ const RESERVED_MEMBER_FAULT = `no member of a declaration may be named "${PLAIN_STRING_RECORD_RESERVED_MEMBER}"`;
207
+ function notPlainDetail(shape, v) {
208
+ switch (shape) {
209
+ case "null":
210
+ return "got null";
211
+ case "array":
212
+ return "got an array";
213
+ case "primitive":
214
+ return `got a ${typeof v}`;
215
+ case "uninspectable":
216
+ return `got ${UNINSPECTABLE}`;
217
+ case "non_plain_object":
218
+ if (typeof v === "function")
219
+ return "got a function";
220
+ return "got an object that is not plain data (a class instance, a Map, process.env, or any object whose prototype has a prototype of its own; copy it into a plain object)";
221
+ default: {
222
+ const unhandled = shape;
223
+ throw new Error(`notPlainDetail: unhandled shape ${String(unhandled)}`);
224
+ }
113
225
  }
114
- const record = {};
226
+ }
227
+ function readPlainStringRecord(v) {
228
+ const shape = jsonShapeOf(v);
229
+ if (shape !== "plain")
230
+ return { ok: false, fault: "not_plain_record", detail: notPlainDetail(shape, v) };
231
+ const namesRead = inspect(() => Object.getOwnPropertyNames(v));
232
+ if (!namesRead.ok)
233
+ return { ok: false, fault: "not_plain_record", detail: `got ${namesRead.sentence}` };
234
+ const names = namesRead.value;
235
+ const members = Object.create(null);
115
236
  let reservedMember = false;
116
237
  for (const name of names) {
117
- let value;
118
- let unreadable = false;
119
- try {
120
- const d = Object.getOwnPropertyDescriptor(v, name);
121
- value = d === undefined ? undefined : Object.hasOwn(d, "value") ? d.value : d.get === undefined ? undefined : Reflect.apply(d.get, v, []);
122
- }
123
- catch {
124
- unreadable = true;
125
- }
238
+ const read = readKey(v, name);
239
+ const unreadable = read.presence === "unreadable";
240
+ const value = read.presence === "own" ? read.value : undefined;
126
241
  if (unreadable || typeof value !== "string") {
127
242
  const valueFault = unreadable ? "could not be read (its getter threw)" : `must be a string — got ${describeValueShape(value)}`;
128
- const reserved = name === RESERVED_MEMBER_NAME;
243
+ const reserved = name === PLAIN_STRING_RECORD_RESERVED_MEMBER;
244
+ const fault = reserved ? "member_name_reserved" : "member_not_string";
129
245
  return {
130
246
  ok: false,
131
- fault: reserved ? "member_name_reserved" : "member_not_string",
247
+ fault,
132
248
  member: echoCallerText(name),
133
249
  detail: `its member "${echoCallerText(name)}" ${reserved ? `is not allowed (${RESERVED_MEMBER_FAULT}) and its value ${valueFault}` : valueFault}`,
134
250
  };
135
251
  }
136
- if (name === RESERVED_MEMBER_NAME)
252
+ if (name === PLAIN_STRING_RECORD_RESERVED_MEMBER)
137
253
  reservedMember = true;
138
254
  else
139
- record[name] = value;
255
+ Object.defineProperty(members, name, dataDescriptor(value));
140
256
  }
141
- return { ok: true, record, reservedMember };
257
+ return { ok: true, record: { ...members }, reservedMember };
142
258
  }
143
- function readTransportRecord(path, raw, lost) {
259
+ const issuesOf = (...candidates) => candidates.filter((c) => c !== undefined);
260
+ function readTransportRecord(path, raw) {
144
261
  if (raw === undefined)
145
- return undefined;
262
+ return { record: undefined, issues: [] };
146
263
  const read = readPlainStringRecord(raw);
147
264
  if (!read.ok) {
148
- lost.push({ path, reason: `must be a plain object of string values — ${read.detail}`, ...(read.member !== undefined ? { member: read.member } : {}), fault: read.fault });
149
- return undefined;
265
+ return {
266
+ record: undefined,
267
+ issues: [{ path, reason: `must be a plain object of string values — ${read.detail}`, ...(read.member !== undefined ? { member: read.member } : {}), fault: read.fault }],
268
+ };
150
269
  }
151
- if (read.reservedMember)
152
- lost.push({ path: `${path}.${RESERVED_MEMBER_NAME}`, reason: RESERVED_MEMBER_FAULT, member: RESERVED_MEMBER_NAME, fault: "member_name_reserved" });
153
- return read.record;
270
+ return {
271
+ record: read.record,
272
+ issues: read.reservedMember ? [{ path: `${path}.${PLAIN_STRING_RECORD_RESERVED_MEMBER}`, reason: RESERVED_MEMBER_FAULT, member: PLAIN_STRING_RECORD_RESERVED_MEMBER, fault: "member_name_reserved" }] : [],
273
+ };
154
274
  }
155
- return { readRequestMcpTransport, readMcpIdentityHeaders, isUsableWireName, describeBadWireName, isContentOriginWord, describeBadContentOrigin, TOOL_WIRE_NAME_MAX_CHARS };
275
+ return { readRequestMcpTransport, readMcpIdentityHeaders, isUsableWireName, describeBadWireName, isUsableMcpServerName, describeBadMcpServerName, isContentOriginWord, describeBadContentOrigin, TOOL_WIRE_NAME_MAX_CHARS };
156
276
  };
@@ -0,0 +1 @@
1
+ export declare const SETTINGS_MCP_SERVER_NAME_CLOSURE: () => any;
@@ -0,0 +1,8 @@
1
+ export const SETTINGS_MCP_SERVER_NAME_CLOSURE = () => {
2
+ const REMOTE_MCP_SERVER_NAME_PREFIX = "remote-";
3
+ function isReservedMcpServerName(name) {
4
+ return name.startsWith(REMOTE_MCP_SERVER_NAME_PREFIX);
5
+ }
6
+ const RESERVED_MCP_SERVER_NAME_REASON = `the "${REMOTE_MCP_SERVER_NAME_PREFIX}" prefix is reserved for the remote MCP servers a device executor offers`;
7
+ return { isReservedMcpServerName, REMOTE_MCP_SERVER_NAME_PREFIX, RESERVED_MCP_SERVER_NAME_REASON };
8
+ };
@@ -0,0 +1 @@
1
+ export declare const SETTINGS_OWN_KEY_READ_CLOSURE: (isJsonArray: (v: unknown) => v is unknown[]) => any;
@@ -0,0 +1,172 @@
1
+ export const SETTINGS_OWN_KEY_READ_CLOSURE = (isJsonArray) => {
2
+ const UNINSPECTABLE = "an object that could not be inspected (a proxy trap threw)";
3
+ function inspect(read) {
4
+ try {
5
+ return { ok: true, value: read() };
6
+ }
7
+ catch (e) {
8
+ return { ok: false, sentence: sentenceOfMinted(e) ?? UNINSPECTABLE };
9
+ }
10
+ }
11
+ function readOwnDescriptor(record, key) {
12
+ const read = inspect(() => {
13
+ const descriptor = Object.getOwnPropertyDescriptor(record, key);
14
+ if (descriptor !== undefined)
15
+ return { presence: "own", descriptor };
16
+ return key in record ? { presence: "inherited" } : { presence: "absent" };
17
+ });
18
+ return read.ok ? read.value : { presence: "unreadable" };
19
+ }
20
+ const valueOfDescriptor = (record, d) => {
21
+ if (!isAccessorDescriptor(d))
22
+ return d.value;
23
+ const getter = d.get;
24
+ return getter === undefined ? undefined : Reflect.apply(getter, record, []);
25
+ };
26
+ function readKey(record, key) {
27
+ const read = readOwnDescriptor(record, key);
28
+ if (read.presence !== "own")
29
+ return read;
30
+ const descriptor = read.descriptor;
31
+ const value = inspect(() => valueOfDescriptor(record, descriptor));
32
+ return value.ok ? { presence: "own", value: value.value } : { presence: "unreadable" };
33
+ }
34
+ function ownValueOf(record, key) {
35
+ const read = readKey(record, key);
36
+ switch (read.presence) {
37
+ case "own":
38
+ return { ok: true, value: read.value };
39
+ case "inherited":
40
+ case "absent":
41
+ return { ok: true, value: undefined };
42
+ case "unreadable":
43
+ return { ok: false, sentence: UNINSPECTABLE };
44
+ default: {
45
+ const unhandled = read;
46
+ throw new Error(`ownValueOf: unhandled presence ${String(unhandled.presence)}`);
47
+ }
48
+ }
49
+ }
50
+ function ownFieldsOf(record, keys) {
51
+ const out = Object.create(null);
52
+ for (const key of keys) {
53
+ const read = ownValueOf(record, key);
54
+ if (!read.ok)
55
+ return read;
56
+ Object.defineProperty(out, key, dataDescriptor(read.value));
57
+ }
58
+ return { ok: true, value: out };
59
+ }
60
+ const MINTED = new WeakMap();
61
+ function sentenceOfMinted(thrown) {
62
+ return MINTED.get(thrown);
63
+ }
64
+ class UninspectableError extends TypeError {
65
+ constructor(sentence = UNINSPECTABLE) {
66
+ super(sentence);
67
+ this.name = "UninspectableError";
68
+ MINTED.set(this, sentence);
69
+ }
70
+ }
71
+ const isAccessorDescriptor = (d) => Object.hasOwn(d, "get") || Object.hasOwn(d, "set");
72
+ const NO_PRIOR_READS = new Map();
73
+ const containerView = (record, isArray, classification, prior = NO_PRIOR_READS) => {
74
+ const keys = inspect(() => Reflect.ownKeys(record));
75
+ if (!keys.ok)
76
+ throw new UninspectableError();
77
+ const members = [];
78
+ const add = (key, d) => appendOwn(members, [key, d]);
79
+ for (const [key, read] of prior)
80
+ if (read.presence === "own")
81
+ add(key, dataDescriptor(read.value));
82
+ let length;
83
+ let foreign = false;
84
+ for (const key of keys.value) {
85
+ if (typeof key !== "string") {
86
+ foreign = true;
87
+ continue;
88
+ }
89
+ if (prior.has(key))
90
+ continue;
91
+ const isLength = isArray && key === "length";
92
+ if (isArray && !isLength && !isArrayIndexKey(key)) {
93
+ foreign = true;
94
+ continue;
95
+ }
96
+ const read = inspect(() => Object.getOwnPropertyDescriptor(record, key));
97
+ if (!read.ok)
98
+ throw new UninspectableError();
99
+ const d = read.value;
100
+ if (d === undefined)
101
+ continue;
102
+ if (isLength) {
103
+ length = valueOfDescriptor(record, d);
104
+ continue;
105
+ }
106
+ switch (classification) {
107
+ case "strict":
108
+ if (d.enumerable !== true || isAccessorDescriptor(d))
109
+ throw new UninspectableError(NOT_PLAIN_DATA);
110
+ break;
111
+ case "wide":
112
+ if (!isArray && d.enumerable !== true)
113
+ continue;
114
+ break;
115
+ default: {
116
+ const unhandled = classification;
117
+ throw new Error(`containerView: unhandled classification ${String(unhandled)}`);
118
+ }
119
+ }
120
+ add(key, d);
121
+ }
122
+ if (isArray)
123
+ members.sort(([a], [b]) => Number(a) - Number(b));
124
+ return { members, length, foreign };
125
+ };
126
+ function denseArrayView(array, classification) {
127
+ const view = containerView(array, true, classification);
128
+ const n = view.length;
129
+ if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 0 || view.members.length !== n)
130
+ return undefined;
131
+ if (!view.members.every(([key], i) => key === String(i)))
132
+ return undefined;
133
+ return { descriptors: view.members.map(([, d]) => d), foreign: view.foreign };
134
+ }
135
+ const isArrayIndexKey = (key) => {
136
+ const n = Number(key);
137
+ return Number.isInteger(n) && n >= 0 && n < 2 ** 32 - 1 && String(n) === key;
138
+ };
139
+ const NOT_PLAIN_DATA = "a value that is not plain data (a class instance, a Map, a Date, a function, an object with a hidden — non-enumerable — or an accessor own property … — only plain objects, arrays and primitives are)";
140
+ function appendOwn(list, value) {
141
+ Object.defineProperty(list, list.length, dataDescriptor(value));
142
+ }
143
+ function dataDescriptor(value) {
144
+ const descriptor = Object.create(null);
145
+ descriptor.value = value;
146
+ descriptor.writable = true;
147
+ descriptor.enumerable = true;
148
+ descriptor.configurable = true;
149
+ return descriptor;
150
+ }
151
+ function captureStringArray(v, classification) {
152
+ return isJsonArray(v) ? captureDenseArray(v, classification, isStringEntry, "ignore") : undefined;
153
+ }
154
+ const isStringEntry = (entry) => typeof entry === "string";
155
+ function captureDenseArray(v, classification, isEntry, foreign) {
156
+ const read = inspect(() => {
157
+ const dense = denseArrayView(v, classification);
158
+ if (dense === undefined || (foreign === "refuse" && dense.foreign))
159
+ return undefined;
160
+ const copy = [];
161
+ for (let i = 0; i < dense.descriptors.length; i++) {
162
+ const entry = valueOfDescriptor(v, dense.descriptors[i]);
163
+ if (!isEntry(entry))
164
+ return undefined;
165
+ Object.defineProperty(copy, i, dataDescriptor(entry));
166
+ }
167
+ return copy;
168
+ });
169
+ return read.ok ? read.value : undefined;
170
+ }
171
+ return { captureStringArray, UNINSPECTABLE, dataDescriptor, inspect, ownFieldsOf, ownValueOf, readKey };
172
+ };
@@ -0,0 +1 @@
1
+ export declare const SETTINGS_PLAIN_JSON_OBJECT_CLOSURE: () => any;
@@ -0,0 +1,28 @@
1
+ export const SETTINGS_PLAIN_JSON_OBJECT_CLOSURE = () => {
2
+ function jsonShapeOf(v) {
3
+ try {
4
+ if (v === null)
5
+ return "null";
6
+ if (Array.isArray(v))
7
+ return "array";
8
+ if (typeof v === "function")
9
+ return "non_plain_object";
10
+ if (typeof v !== "object")
11
+ return "primitive";
12
+ const proto = Object.getPrototypeOf(v);
13
+ return proto === null || Object.getPrototypeOf(proto) === null ? "plain" : "non_plain_object";
14
+ }
15
+ catch {
16
+ return "uninspectable";
17
+ }
18
+ }
19
+ function isJsonArray(v) {
20
+ try {
21
+ return Array.isArray(v);
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ }
27
+ return { isJsonArray, jsonShapeOf };
28
+ };
@@ -21,9 +21,9 @@ export const SETTINGS_SAFETY_MERGE_CLOSURE = (MIN_TRUST_WORDS) => {
21
21
  mergeShape: "denyFirst", minTrust: "global", tighten: { rule: "policyDenyWins" }, enforcement: "gate", fail: "closed",
22
22
  seam: "toolPolicy + deny-narrowing (SessionPolicyStore)", coreAxis: "permissionDecision",
23
23
  members: {
24
- allow: { direction: "loosen", minTrust: "global" },
25
- deny: { direction: "tighten", minTrust: "local" },
26
- ask: { direction: "tighten", minTrust: "local" },
24
+ allow: { direction: "loosen", minTrust: "global", list: true },
25
+ deny: { direction: "tighten", minTrust: "local", list: true },
26
+ ask: { direction: "tighten", minTrust: "local", list: true },
27
27
  },
28
28
  },
29
29
  permissionMode: { mergeShape: "replace", minTrust: "global", tighten: { rule: "enumRank", order: ["bypassPermissions", "auto", "acceptEdits", "default", "dontAsk", "plan"] }, enforcement: "gate", fail: "closed", seam: "derive → toolPolicy / onAsk / handsReadOnly (§6.4); bypass = launch-flag only; the kill-switches are the killSwitches row" },
@@ -43,8 +43,8 @@ export const SETTINGS_SAFETY_MERGE_CLOSURE = (MIN_TRUST_WORDS) => {
43
43
  "network.allowAllUnixSockets": { direction: "tighten", minTrust: "global", boolPole: { strict: false, minTrust: "local" } },
44
44
  "network.allowLocalBinding": { direction: "tighten", minTrust: "global", boolPole: { strict: false, minTrust: "local" } },
45
45
  "filesystem.allowManagedReadPathsOnly": { direction: "tighten", minTrust: "global", boolPole: { strict: true, minTrust: "local" } },
46
- "filesystem.denyWrite": { direction: "tighten", minTrust: "local" },
47
- "filesystem.denyRead": { direction: "tighten", minTrust: "local" },
46
+ "filesystem.denyWrite": { direction: "tighten", minTrust: "local", list: true },
47
+ "filesystem.denyRead": { direction: "tighten", minTrust: "local", list: true },
48
48
  },
49
49
  },
50
50
  hooks: { mergeShape: "runAll", minTrust: "project", tighten: { rule: "none" }, enforcement: "gate", fail: "closed", seam: "hooks (single source or adapter-composed)" },
@@ -73,14 +73,17 @@ export const SETTINGS_SAFETY_MERGE_CLOSURE = (MIN_TRUST_WORDS) => {
73
73
  }
74
74
  return SAFETY_MERGE_SPEC[category];
75
75
  }
76
- function resolveMemberAdmission(spec, member, categoryLabel = "(unnamed category)", value) {
76
+ function memberRow(spec, member, categoryLabel) {
77
77
  if (spec.members === undefined) {
78
78
  throw new RangeError(`SAFETY_MERGE_SPEC: category '${categoryLabel}' has no member-level admission — its minTrust applies to the whole key`);
79
79
  }
80
80
  if (!Object.hasOwn(spec.members, member)) {
81
81
  throw new RangeError(`SAFETY_MERGE_SPEC: unknown member '${member}' of category '${categoryLabel}' (members: ${Object.keys(spec.members).join(", ")})`);
82
82
  }
83
- const row = spec.members[member];
83
+ return spec.members[member];
84
+ }
85
+ function resolveMemberAdmission(spec, member, categoryLabel = "(unnamed category)", value) {
86
+ const row = memberRow(spec, member, categoryLabel);
84
87
  const rowFloor = row.minTrust ?? spec.minTrust;
85
88
  if (row.boolPole !== undefined) {
86
89
  const floor = value === row.boolPole.strict ? row.boolPole.minTrust : rowFloor;
@@ -0,0 +1 @@
1
+ export declare const SETTINGS_TIER_WORDS_CLOSURE: () => any;
@@ -0,0 +1,7 @@
1
+ export const SETTINGS_TIER_WORDS_CLOSURE = () => {
2
+ const TIER_ORDER = ["ultra", "max", "pro", "flash", "lite"];
3
+ function tierLadderFrom(tier) {
4
+ return TIER_ORDER.slice(TIER_ORDER.indexOf(tier));
5
+ }
6
+ return { tierLadderFrom };
7
+ };