@sema-agent/client-core 0.102.0 → 0.104.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.
- package/CHANGELOG.md +172 -0
- package/README.md +23 -17
- package/dist/adapt/toolCards.d.ts +2 -1
- package/dist/adapt/toolCards.js +3 -1
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +5 -1
- package/dist/adapter/downstream/eventToSdkMessage.js +23 -3
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +0 -1
- package/dist/adapter/downstream/terminalToSdkResult.js +3 -2
- package/dist/adapter/downstream/wiringManifestView.js +4 -1
- package/dist/agentSession/engineAgentRegistryRead.js +3 -0
- package/dist/cloudConfigWireCaps.js +6 -3
- package/dist/coreValuePorts.d.ts +3 -1
- package/dist/coreValuePorts.js +5 -0
- package/dist/credentialPlaneCapability.d.ts +22 -0
- package/dist/credentialPlaneCapability.js +75 -0
- package/dist/deviceExecutorManagementCapability.d.ts +1 -0
- package/dist/deviceExecutorManagementCapability.js +3 -1
- package/dist/deviceRebind.d.ts +17 -4
- package/dist/deviceRebind.js +43 -14
- package/dist/engineAgentAbsence.d.ts +1 -0
- package/dist/engineErrorCodes.d.ts +1 -0
- package/dist/engineErrorCodes.js +3 -1
- package/dist/engineNoticeCodes.d.ts +26 -0
- package/dist/engineNoticeCodes.js +121 -12
- package/dist/engineRowRef.js +1 -0
- package/dist/errorSupplementRoles.js +1 -3
- package/dist/eventLeg.js +2 -1
- package/dist/executionPlacementWords.d.ts +3 -0
- package/dist/executionPlacementWords.js +2 -0
- package/dist/fleet/fleetProjection.js +15 -9
- package/dist/gateOutcome.d.ts +20 -0
- package/dist/gateOutcome.js +89 -0
- package/dist/generated/engineAskFaceTables.js +2 -2
- package/dist/generated/engineFactTables.d.ts +8 -3
- package/dist/generated/engineFactTables.js +58 -2
- package/dist/generated/engineNoticeTables.js +30 -0
- package/dist/generated/settingsSchemaDefaultModel.d.ts +1 -1
- package/dist/generated/settingsSchemaDefaultModel.js +2 -2
- package/dist/generated/settingsSchemaFns.d.ts +15 -0
- package/dist/generated/settingsSchemaFns.js +25 -2
- package/dist/generated/settingsSchemaHooksClassifier.js +109 -29
- package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -1
- package/dist/generated/settingsSchemaMcpRequestEntry.js +213 -93
- package/dist/generated/settingsSchemaMcpServerName.d.ts +1 -0
- package/dist/generated/settingsSchemaMcpServerName.js +8 -0
- package/dist/generated/settingsSchemaOwnKeyRead.d.ts +1 -0
- package/dist/generated/settingsSchemaOwnKeyRead.js +172 -0
- package/dist/generated/settingsSchemaPlainJsonObject.d.ts +1 -0
- package/dist/generated/settingsSchemaPlainJsonObject.js +28 -0
- package/dist/generated/settingsSchemaSafetyMergeSpec.js +10 -7
- package/dist/generated/settingsSchemaTierWords.d.ts +1 -0
- package/dist/generated/settingsSchemaTierWords.js +7 -0
- package/dist/generated/settingsSchemaTypes.d.ts +3 -1
- package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
- package/dist/hitl/automaticAnswerVerdict.js +47 -11
- package/dist/hitl/decisionConflict.js +11 -11
- package/dist/hitl/decisionRefusal.d.ts +1 -0
- package/dist/hitl/decisionRefusal.js +4 -2
- package/dist/hitl/editedRuleTextPrecheck.d.ts +1 -0
- package/dist/hitl/editedRuleTextPrecheck.js +26 -1
- package/dist/hitl/persistedRulesWire.js +1 -0
- package/dist/hitl/planReviewWire.d.ts +2 -1
- package/dist/hitl/planReviewWire.js +8 -12
- package/dist/hitl/sessionPolicyDeliverable.d.ts +0 -1
- package/dist/hitl/sessionPolicyDeliverable.js +31 -10
- package/dist/hitl/sessionPolicyWire.js +1 -1
- package/dist/hitl/toolApprovalWire.d.ts +20 -7
- package/dist/hitl/toolApprovalWire.js +171 -19
- package/dist/host.d.ts +0 -3
- package/dist/hostTurnSettings.js +3 -1
- package/dist/humanTurn.js +2 -2
- package/dist/i18n/messages.en.d.ts +5 -0
- package/dist/i18n/messages.en.js +6 -1
- package/dist/i18n/messages.zh.js +6 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.js +3 -1
- package/dist/inheritEnvWire.d.ts +1 -0
- package/dist/inheritEnvWire.js +8 -5
- package/dist/jsonFaithful.js +5 -3
- package/dist/mcpEngineLeg.d.ts +3 -0
- package/dist/mcpEngineLeg.js +4 -1
- package/dist/mcpLiveness.d.ts +18 -0
- package/dist/mcpLiveness.js +48 -1
- package/dist/mcpReconnect.d.ts +3 -0
- package/dist/mcpReconnect.js +6 -0
- package/dist/mcpStatusSupersetKeys.js +24 -1
- package/dist/mcpWireCaps.d.ts +2 -3
- package/dist/mcpWireCaps.js +10 -9
- package/dist/memoryEntriesWire.d.ts +35 -1
- package/dist/memoryEntriesWire.js +110 -14
- package/dist/modsFace.js +7 -3
- package/dist/postureKnob.js +1 -1
- package/dist/prepareRefusal.d.ts +0 -1
- package/dist/prepareRefusal.js +0 -3
- package/dist/printModelStatus.d.ts +1 -0
- package/dist/printModelStatus.js +6 -2
- package/dist/promptProfileWireCaps.d.ts +1 -3
- package/dist/promptProfileWireCaps.js +2 -2
- package/dist/request/taskRequest.d.ts +1 -1
- package/dist/request/taskRequest.js +3 -3
- package/dist/retryStatus.d.ts +20 -1
- package/dist/retryStatus.js +31 -7
- package/dist/ruleCompileVerdict.d.ts +1 -0
- package/dist/ruleCompileVerdict.js +3 -1
- package/dist/seatContract.d.ts +7 -7
- package/dist/seatContract.js +49 -10
- package/dist/sessionMemoryErase.js +24 -2
- package/dist/sessionRowTag.d.ts +24 -0
- package/dist/sessionRowTag.js +77 -0
- package/dist/systemReminderTag.js +14 -4
- package/dist/turnFailurePresentation.js +8 -1
- package/dist/wireFailureShape.d.ts +12 -1
- package/dist/wireFailureShape.js +58 -24
- package/dist/wireRefusalCopy.d.ts +0 -3
- package/dist/wireRefusalCopy.js +0 -17
- package/docs/INTEGRATION-CLIENTS.md +400 -14
- 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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
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
|
|
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) :
|
|
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
|
-
|
|
50
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
109
|
-
|
|
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
|
-
|
|
112
|
-
|
|
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
|
-
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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 ===
|
|
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
|
|
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 ===
|
|
252
|
+
if (name === PLAIN_STRING_RECORD_RESERVED_MEMBER)
|
|
137
253
|
reservedMember = true;
|
|
138
254
|
else
|
|
139
|
-
|
|
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
|
-
|
|
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
|
-
|
|
149
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
|
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
|
-
|
|
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;
|