@sema-agent/client-core 0.110.0 → 0.112.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 +244 -0
- package/README.md +59 -18
- package/dist/abortableSleep.d.ts +7 -0
- package/dist/abortableSleep.js +37 -0
- package/dist/adapt/arms.js +25 -4
- package/dist/adapt/toolCards.d.ts +3 -1
- package/dist/adapt/toolCards.js +4 -2
- package/dist/adapter/activeRunSelfHeal.d.ts +39 -0
- package/dist/adapter/activeRunSelfHeal.js +171 -3
- package/dist/adapter/downstream/eventToSdkMessage.js +10 -10
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -0
- package/dist/adapter/downstream/terminalToSdkResult.js +11 -0
- package/dist/adapter/runStream.d.ts +5 -0
- package/dist/adapter/runStream.js +15 -3
- package/dist/agentSession/engineSessionBackgroundStop.js +2 -2
- package/dist/attachmentRoute.d.ts +20 -0
- package/dist/attachmentRoute.js +39 -0
- package/dist/attachmentsWireCaps.js +1 -1
- package/dist/builtinOutputStyles.d.ts +12 -0
- package/dist/builtinOutputStyles.js +147 -0
- package/dist/checkpointRowVerdict.d.ts +3 -0
- package/dist/checkpointRowVerdict.js +14 -1
- package/dist/compactionStatus.d.ts +9 -0
- package/dist/compactionStatus.js +29 -5
- package/dist/consoleCaPin.d.ts +136 -0
- package/dist/consoleCaPin.js +827 -0
- package/dist/controlRouter.js +2 -1
- package/dist/coreValuePorts.d.ts +39 -1
- package/dist/coreValuePorts.js +10 -0
- package/dist/decideReceipt.d.ts +2 -1
- package/dist/deviceRebind.js +3 -3
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +6 -0
- package/dist/effectiveFacts.d.ts +9 -0
- package/dist/effectiveFacts.js +33 -0
- package/dist/engineAddress.d.ts +1 -0
- package/dist/engineAddress.js +4 -1
- package/dist/engineCredentialRelease.d.ts +54 -0
- package/dist/engineCredentialRelease.js +146 -0
- package/dist/engineErrorCodes.d.ts +1 -0
- package/dist/engineErrorCodes.js +1 -0
- package/dist/engineHealthProbeVerdict.d.ts +24 -0
- package/dist/engineHealthProbeVerdict.js +123 -0
- package/dist/engineNoticeCodes.js +5 -7
- package/dist/engineRepoint.d.ts +12 -5
- package/dist/engineRepoint.js +44 -19
- package/dist/engineRowRef.d.ts +3 -0
- package/dist/engineRowRef.js +11 -1
- package/dist/engineSwapCrossing.d.ts +57 -0
- package/dist/engineSwapCrossing.js +297 -0
- package/dist/engineUnavailable.d.ts +45 -0
- package/dist/engineUnavailable.js +496 -0
- package/dist/engineUrl.js +4 -2
- package/dist/eventLeg.js +3 -3
- package/dist/gateFailureCodes.js +2 -2
- package/dist/generated/sdkFactTables.d.ts +2 -1
- package/dist/generated/sdkFactTables.js +14 -0
- package/dist/generated/settingsSchemaFns.d.ts +1 -0
- package/dist/generated/settingsSchemaFns.js +3 -0
- package/dist/generated/settingsSchemaHooksClassifier.js +38 -9
- package/dist/generated/settingsSchemaTables.d.ts +56 -0
- package/dist/generated/settingsSchemaTables.js +19 -0
- package/dist/generated/settingsSchemaTypes.d.ts +23 -13
- package/dist/generated/settingsSchemaUrlShape.d.ts +1 -0
- package/dist/generated/settingsSchemaUrlShape.js +17 -0
- package/dist/hitl/approvalDelivery.d.ts +1 -0
- package/dist/hitl/approvalDelivery.js +1 -1
- package/dist/hitl/approvalResolution.d.ts +1 -1
- package/dist/hitl/approvalResolution.js +2 -1
- package/dist/hitl/askGateWire.js +5 -6
- package/dist/hitl/decisionRefusal.d.ts +6 -0
- package/dist/hitl/decisionRefusal.js +19 -10
- package/dist/hitl/decisionRefusalCarrier.d.ts +3 -0
- package/dist/hitl/decisionRefusalCarrier.js +348 -0
- package/dist/hitl/decisionSend.d.ts +7 -0
- package/dist/hitl/decisionSend.js +34 -12
- package/dist/hitl/editedApprovalAcceptance.js +1 -1
- package/dist/hitl/elicitationRefusal.d.ts +4 -0
- package/dist/hitl/elicitationRefusal.js +23 -0
- package/dist/hitl/frameRouter.d.ts +2 -2
- package/dist/hitl/frameRouter.js +8 -15
- package/dist/hitl/gateIdentity.d.ts +5 -0
- package/dist/hitl/gateIdentity.js +23 -0
- package/dist/hitl/hitlBridge.d.ts +6 -0
- package/dist/hitl/hitlBridge.js +10 -4
- package/dist/hitl/hitlHostSurface.d.ts +2 -1
- package/dist/hitl/hitlHostSurface.js +7 -2
- package/dist/hitl/localAllowRedemption.d.ts +70 -0
- package/dist/hitl/localAllowRedemption.js +276 -0
- package/dist/hitl/parkOwnership.js +2 -1
- package/dist/hitl/parkResolver.js +14 -4
- package/dist/hitl/persistedRulesWire.d.ts +16 -0
- package/dist/hitl/persistedRulesWire.js +70 -0
- package/dist/hitl/planReviewWire.d.ts +3 -0
- package/dist/hitl/planReviewWire.js +23 -6
- package/dist/hitl/policyDenyCause.d.ts +1 -1
- package/dist/hitl/policyDenyCause.js +1 -1
- package/dist/hitl/resumeRunningCard.d.ts +1 -0
- package/dist/hitl/resumeRunningCard.js +1 -0
- package/dist/hitl/screenCardCarriers.d.ts +15 -0
- package/dist/hitl/screenCardCarriers.js +41 -0
- package/dist/hitl/screenDecisionCards.d.ts +98 -0
- package/dist/hitl/screenDecisionCards.js +363 -0
- package/dist/hitl/sessionPolicyWire.js +2 -2
- package/dist/hitl/standingRows.d.ts +6 -2
- package/dist/hitl/standingRows.js +27 -2
- package/dist/hitl/toolApprovalWire.d.ts +30 -8
- package/dist/hitl/toolApprovalWire.js +264 -121
- package/dist/hooksReaderGenerations.js +1 -1
- package/dist/hooksWireCaps.js +3 -3
- package/dist/hostSettingNoticeArm.d.ts +3 -0
- package/dist/hostSettingNoticeArm.js +12 -0
- package/dist/hostTurnSettings.d.ts +3 -0
- package/dist/hostTurnSettings.js +38 -5
- package/dist/humanTurnRead.js +11 -1
- package/dist/i18n/messages.en.d.ts +292 -0
- package/dist/i18n/messages.en.js +298 -7
- package/dist/i18n/messages.zh.js +316 -6
- package/dist/i18n/translate.d.ts +3 -0
- package/dist/i18n/translate.js +78 -10
- package/dist/i18n/zh.d.ts +1 -0
- package/dist/i18n/zh.js +1 -0
- package/dist/index.d.ts +71 -20
- package/dist/index.js +44 -13
- package/dist/interactiveHalt.js +2 -1
- package/dist/interactiveInterrupt.js +20 -2
- package/dist/liveModelCatalog.d.ts +4 -0
- package/dist/liveModelCatalog.js +12 -3
- package/dist/localConfig/documents.d.ts +61 -0
- package/dist/localConfig/documents.js +51 -0
- package/dist/localConfig/kernel.d.ts +149 -0
- package/dist/localConfig/kernel.js +597 -0
- package/dist/localConfig/mcp/edit.d.ts +161 -0
- package/dist/localConfig/mcp/edit.js +846 -0
- package/dist/localConfig/mcp/servers.d.ts +165 -0
- package/dist/localConfig/mcp/servers.js +776 -0
- package/dist/localConfig/mcp/views.d.ts +170 -0
- package/dist/localConfig/mcp/views.js +429 -0
- package/dist/localConfig/modelPool.d.ts +262 -0
- package/dist/localConfig/modelPool.js +1489 -0
- package/dist/localConfig/modelPoolWords.d.ts +13 -0
- package/dist/localConfig/modelPoolWords.js +20 -0
- package/dist/localConfig/receiptShape.d.ts +7 -0
- package/dist/localConfig/receiptShape.js +135 -0
- package/dist/localConfig/settingsWrite.d.ts +127 -0
- package/dist/localConfig/settingsWrite.js +237 -0
- package/dist/localConfig/skills.d.ts +124 -0
- package/dist/localConfig/skills.js +397 -0
- package/dist/localConfig/skillsWords.d.ts +10 -0
- package/dist/localConfig/skillsWords.js +5 -0
- package/dist/localEngineSeatReading.d.ts +2 -2
- package/dist/localEngineSeatReading.js +5 -3
- package/dist/localEngineSpawn.d.ts +0 -7
- package/dist/localEngineSpawn.js +0 -92
- package/dist/localEngineStep.d.ts +2 -2
- package/dist/localEngineStep.js +2 -0
- package/dist/mcpProbeWire.js +2 -1
- package/dist/mcpReconnect.js +3 -3
- package/dist/mcpWireCaps.js +1 -1
- package/dist/memoryVerbsWire.js +3 -2
- package/dist/model/engineModelWords.d.ts +3 -0
- package/dist/model/engineModelWords.js +13 -0
- package/dist/model/onboardJudgement.d.ts +14 -4
- package/dist/model/onboardJudgement.js +91 -139
- package/dist/model/subagentModelWord.d.ts +21 -2
- package/dist/model/subagentModelWord.js +100 -29
- package/dist/modelCapabilityProbe.js +3 -40
- package/dist/modelConfigGapNotice.d.ts +20 -0
- package/dist/modelConfigGapNotice.js +102 -0
- package/dist/modsKernelIdentity.js +2 -47
- package/dist/notifications.d.ts +19 -0
- package/dist/notifications.js +114 -12
- package/dist/ownKey.d.ts +7 -0
- package/dist/ownKey.js +71 -8
- package/dist/pendingUserRow.d.ts +4 -0
- package/dist/pendingUserRow.js +16 -0
- package/dist/permissionsDeclaration.d.ts +3 -1
- package/dist/permissionsDeclaration.js +33 -9
- package/dist/planReviewCardFacts.d.ts +3 -0
- package/dist/planReviewCardFacts.js +52 -2
- package/dist/pluginHooksWire.d.ts +9 -1
- package/dist/pluginHooksWire.js +40 -6
- package/dist/printToolResultFrame.js +4 -2
- package/dist/promptBlockedCopy.js +12 -7
- package/dist/promptSuggestionBatch.d.ts +7 -0
- package/dist/promptSuggestionBatch.js +9 -0
- package/dist/promptSuggestionsTail.d.ts +39 -0
- package/dist/promptSuggestionsTail.js +116 -0
- package/dist/request/taskRequest.js +10 -6
- package/dist/requestCoordinate.d.ts +1 -0
- package/dist/requestCoordinate.js +13 -0
- package/dist/resumeRefusalCopy.d.ts +3 -1
- package/dist/resumeRefusalCopy.js +12 -4
- package/dist/rewindArchiveReading.js +4 -4
- package/dist/runCancelContext.d.ts +2 -1
- package/dist/runCancelContext.js +1 -0
- package/dist/runLedgerSnapshot.js +3 -3
- package/dist/runPermissionModeSwitch.js +3 -4
- package/dist/scenarioRefusal.js +11 -13
- package/dist/scenarioSkills.js +11 -6
- package/dist/seam.d.ts +16 -2
- package/dist/seam.js +10 -0
- package/dist/seatContract.d.ts +259 -9
- package/dist/seatContract.js +444 -15
- package/dist/sessionCostReading.d.ts +70 -0
- package/dist/sessionCostReading.js +150 -0
- package/dist/sessionHooksRoster.d.ts +4 -0
- package/dist/sessionHooksRoster.js +158 -0
- package/dist/sessionIdSegment.d.ts +1 -0
- package/dist/sessionIdSegment.js +4 -1
- package/dist/sessionMemoryErase.js +2 -1
- package/dist/sessionMemoryStatus.js +2 -2
- package/dist/sessionReadRedaction.d.ts +7 -0
- package/dist/sessionReadRedaction.js +26 -0
- package/dist/sessionSyncFileHistory.js +8 -9
- package/dist/settingsHooksSalvage.js +2 -1
- package/dist/sha256Bytes.d.ts +1 -0
- package/dist/sha256Bytes.js +46 -0
- package/dist/skillOverrideChain.d.ts +83 -0
- package/dist/skillOverrideChain.js +378 -0
- package/dist/skillsWireCaps.d.ts +3 -0
- package/dist/skillsWireCaps.js +16 -1
- package/dist/sseIdleTriage.js +2 -1
- package/dist/storeDurabilityWord.d.ts +15 -0
- package/dist/storeDurabilityWord.js +18 -0
- package/dist/storePostureCapability.d.ts +7 -3
- package/dist/storePostureCapability.js +69 -39
- package/dist/subagent/engineSubagentResume.js +2 -2
- package/dist/subagent/engineSubagentTail.js +2 -1
- package/dist/subagentContentStore.d.ts +11 -0
- package/dist/subagentContentStore.js +28 -2
- package/dist/toolResult.d.ts +1 -0
- package/dist/toolResult.js +2 -0
- package/dist/turnFailurePresentation.js +4 -10
- package/dist/userAttachmentEnvelope.d.ts +2 -1
- package/dist/userAttachmentEnvelope.js +10 -0
- package/dist/wireErrorTriage.js +2 -1
- package/dist/wireFailureShape.d.ts +4 -0
- package/dist/wireFailureShape.js +141 -19
- package/dist/wireRefusalCopy.d.ts +6 -5
- package/dist/wireRefusalCopy.js +49 -92
- package/docs/INTEGRATION-CLIENTS.md +2718 -17
- package/package.json +7 -3
|
@@ -0,0 +1,776 @@
|
|
|
1
|
+
import { LOCAL_CONFIG_WRITE_INTENTS } from '../settingsWrite.js';
|
|
2
|
+
import { projectMcpConfigs, mcpTransportVerdict } from '../../mcpWireCaps.js';
|
|
3
|
+
import { readHostSettingsOnce, CC_MERGE_ORDER } from '../../hostSettingsSource.js';
|
|
4
|
+
import { layerAdmissionWord } from '../../settingsLayerAdmission.js';
|
|
5
|
+
import { msg, renderMessage } from '../../i18n/translate.js';
|
|
6
|
+
export const MCP_SERVER_SCOPES = Object.freeze(['user', 'project', 'local']);
|
|
7
|
+
export const MCP_SERVER_ROW_STATES = Object.freeze(['active', 'pending_approval', 'rejected', 'disabled', 'withheld', 'unusable']);
|
|
8
|
+
export const MCP_SERVER_WITHHELD_CAUSES = Object.freeze(['narrowing_conflict', 'narrowing_invalid', 'layer_unreadable', 'policy_locked']);
|
|
9
|
+
const isRecord = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
10
|
+
export function ownData(v, key) {
|
|
11
|
+
try {
|
|
12
|
+
if (typeof v !== 'object' || v === null)
|
|
13
|
+
return { ok: true, value: undefined };
|
|
14
|
+
const d = Object.getOwnPropertyDescriptor(v, key);
|
|
15
|
+
if (d === undefined)
|
|
16
|
+
return { ok: true, value: undefined };
|
|
17
|
+
return Object.hasOwn(d, 'value') ? { ok: true, value: d.value } : { ok: false };
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return { ok: false };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const ownValue = (v, key) => {
|
|
24
|
+
const r = ownData(v, key);
|
|
25
|
+
return r.ok ? r.value : undefined;
|
|
26
|
+
};
|
|
27
|
+
export function stringListOf(v) {
|
|
28
|
+
try {
|
|
29
|
+
if (!Array.isArray(v) || v.length > 100_000)
|
|
30
|
+
return undefined;
|
|
31
|
+
const out = [];
|
|
32
|
+
for (let i = 0; i < v.length; i++) {
|
|
33
|
+
const r = ownData(v, String(i));
|
|
34
|
+
if (!r.ok || typeof r.value !== 'string')
|
|
35
|
+
return undefined;
|
|
36
|
+
out.push(r.value);
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function nameListOf(holder, key) {
|
|
45
|
+
const r = ownData(holder, key);
|
|
46
|
+
if (!r.ok)
|
|
47
|
+
return { kind: 'bad' };
|
|
48
|
+
if (r.value === undefined)
|
|
49
|
+
return { kind: 'absent' };
|
|
50
|
+
const list = stringListOf(r.value);
|
|
51
|
+
return list === undefined ? { kind: 'bad' } : { kind: 'list', list: Object.freeze(list) };
|
|
52
|
+
}
|
|
53
|
+
const grantedNames = (r) => new Set(r.kind === 'list' ? r.list : []);
|
|
54
|
+
function ownArrayLength(v) {
|
|
55
|
+
try {
|
|
56
|
+
if (!Array.isArray(v))
|
|
57
|
+
return undefined;
|
|
58
|
+
const d = Object.getOwnPropertyDescriptor(v, 'length');
|
|
59
|
+
return d !== undefined && typeof d.value === 'number' && Number.isSafeInteger(d.value) && d.value >= 0 && d.value <= 100_000 ? d.value : undefined;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function pureJsonOf(v, depth, path) {
|
|
66
|
+
try {
|
|
67
|
+
if (v === null || typeof v === 'string' || typeof v === 'boolean')
|
|
68
|
+
return JSON.stringify(v);
|
|
69
|
+
if (typeof v === 'number')
|
|
70
|
+
return Number.isFinite(v) ? JSON.stringify(v) : undefined;
|
|
71
|
+
if (typeof v !== 'object' || depth > 32 || path.has(v))
|
|
72
|
+
return undefined;
|
|
73
|
+
const arr = Array.isArray(v);
|
|
74
|
+
const proto = Object.getPrototypeOf(v);
|
|
75
|
+
if (arr ? proto !== Array.prototype : proto !== Object.prototype && proto !== null)
|
|
76
|
+
return undefined;
|
|
77
|
+
path.add(v);
|
|
78
|
+
try {
|
|
79
|
+
const parts = [];
|
|
80
|
+
const keys = Reflect.ownKeys(v);
|
|
81
|
+
if (arr) {
|
|
82
|
+
const len = ownArrayLength(v);
|
|
83
|
+
if (len === undefined || keys.length !== len + 1)
|
|
84
|
+
return undefined;
|
|
85
|
+
for (let i = 0; i < len; i++) {
|
|
86
|
+
const d = Object.getOwnPropertyDescriptor(v, String(i));
|
|
87
|
+
if (d === undefined || !Object.hasOwn(d, 'value'))
|
|
88
|
+
return undefined;
|
|
89
|
+
const s = pureJsonOf(d.value, depth + 1, path);
|
|
90
|
+
if (s === undefined)
|
|
91
|
+
return undefined;
|
|
92
|
+
parts.push(s);
|
|
93
|
+
}
|
|
94
|
+
return `[${parts.join(',')}]`;
|
|
95
|
+
}
|
|
96
|
+
for (const k of keys) {
|
|
97
|
+
if (typeof k !== 'string')
|
|
98
|
+
return undefined;
|
|
99
|
+
const d = Object.getOwnPropertyDescriptor(v, k);
|
|
100
|
+
if (d === undefined)
|
|
101
|
+
continue;
|
|
102
|
+
if (!Object.hasOwn(d, 'value') || d.enumerable !== true)
|
|
103
|
+
return undefined;
|
|
104
|
+
const s = pureJsonOf(d.value, depth + 1, path);
|
|
105
|
+
if (s === undefined)
|
|
106
|
+
return undefined;
|
|
107
|
+
parts.push(`${JSON.stringify(k)}:${s}`);
|
|
108
|
+
}
|
|
109
|
+
return `{${parts.join(',')}}`;
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
path.delete(v);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function envSignatureOf(entry) {
|
|
120
|
+
const r = ownData(entry, 'env');
|
|
121
|
+
if (!r.ok)
|
|
122
|
+
return undefined;
|
|
123
|
+
return r.value === undefined ? 'null' : pureJsonOf(r.value, 0, new Set());
|
|
124
|
+
}
|
|
125
|
+
function ownKeysOf(v) {
|
|
126
|
+
try {
|
|
127
|
+
return Object.keys(v);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export function subTableOf(doc, path) {
|
|
134
|
+
let box = doc;
|
|
135
|
+
for (const seg of path) {
|
|
136
|
+
if (!isRecord(box))
|
|
137
|
+
return { kind: 'bad' };
|
|
138
|
+
const r = ownData(box, seg);
|
|
139
|
+
if (!r.ok)
|
|
140
|
+
return { kind: 'bad' };
|
|
141
|
+
if (r.value === undefined)
|
|
142
|
+
return { kind: 'absent' };
|
|
143
|
+
box = r.value;
|
|
144
|
+
}
|
|
145
|
+
return isRecord(box) ? { kind: 'table', table: box } : { kind: 'bad' };
|
|
146
|
+
}
|
|
147
|
+
export function documentOf(r) {
|
|
148
|
+
if (r === undefined)
|
|
149
|
+
return undefined;
|
|
150
|
+
if (r.status === 'loaded')
|
|
151
|
+
return r.doc;
|
|
152
|
+
return r.status === 'absent' ? {} : undefined;
|
|
153
|
+
}
|
|
154
|
+
export const localScopePath = (projectKey) => Object.freeze(['projects', projectKey, 'mcpServers']);
|
|
155
|
+
export const USER_SCOPE_PATH = Object.freeze(['mcpServers']);
|
|
156
|
+
export const PROJECT_FILE_PATH = Object.freeze(['mcpServers']);
|
|
157
|
+
function splitPath(p, sep) {
|
|
158
|
+
if (sep === '/') {
|
|
159
|
+
if (!p.startsWith('/'))
|
|
160
|
+
return undefined;
|
|
161
|
+
return { root: '/', parts: p.split('/').filter((s) => s !== '') };
|
|
162
|
+
}
|
|
163
|
+
const m = /^([A-Za-z]:)\\/.exec(p);
|
|
164
|
+
if (m === null)
|
|
165
|
+
return undefined;
|
|
166
|
+
return { root: `${m[1]}\\`, parts: p.slice(m[0].length).split('\\').filter((s) => s !== '') };
|
|
167
|
+
}
|
|
168
|
+
const joinPath = (root, parts, sep) => root + parts.join(sep);
|
|
169
|
+
export function mcpProjectChainOf(startDir, sep, fence) {
|
|
170
|
+
try {
|
|
171
|
+
if (typeof startDir !== 'string' || (sep !== '/' && sep !== '\\'))
|
|
172
|
+
return Object.freeze([]);
|
|
173
|
+
const s = splitPath(startDir, sep);
|
|
174
|
+
if (s === undefined || s.parts.length === 0)
|
|
175
|
+
return Object.freeze([]);
|
|
176
|
+
let floor = 1;
|
|
177
|
+
if (fence !== undefined) {
|
|
178
|
+
if (typeof fence !== 'string')
|
|
179
|
+
return Object.freeze([]);
|
|
180
|
+
const f = splitPath(fence, sep);
|
|
181
|
+
if (f === undefined || f.root !== s.root || f.parts.length > s.parts.length || f.parts.some((x, i) => s.parts[i] !== x))
|
|
182
|
+
return Object.freeze([]);
|
|
183
|
+
floor = Math.max(1, f.parts.length);
|
|
184
|
+
}
|
|
185
|
+
const out = [];
|
|
186
|
+
for (let n = floor; n <= s.parts.length; n++)
|
|
187
|
+
out.push(joinPath(s.root, s.parts.slice(0, n), sep));
|
|
188
|
+
return Object.freeze(out);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
return Object.freeze([]);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
export function mcpPathWithinFence(physicalPath, fence, sep) {
|
|
195
|
+
try {
|
|
196
|
+
if (typeof physicalPath !== 'string' || typeof fence !== 'string')
|
|
197
|
+
return false;
|
|
198
|
+
const p = splitPath(physicalPath, sep);
|
|
199
|
+
const f = splitPath(fence, sep);
|
|
200
|
+
if (p === undefined || f === undefined || p.root !== f.root || f.parts.length > p.parts.length)
|
|
201
|
+
return false;
|
|
202
|
+
return f.parts.every((x, i) => p.parts[i] === x);
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const REMOTE_SINK_WITHHELD_NAMES = new Set([
|
|
209
|
+
'AWS_ACCESS_KEY_ID',
|
|
210
|
+
'AWS_SECRET_ACCESS_KEY',
|
|
211
|
+
'AWS_SESSION_TOKEN',
|
|
212
|
+
'AZURE_CLIENT_SECRET',
|
|
213
|
+
'GOOGLE_APPLICATION_CREDENTIALS',
|
|
214
|
+
'GITHUB_TOKEN',
|
|
215
|
+
'GH_TOKEN',
|
|
216
|
+
'GITLAB_TOKEN',
|
|
217
|
+
'NPM_TOKEN',
|
|
218
|
+
'NODE_AUTH_TOKEN',
|
|
219
|
+
'PYPI_TOKEN',
|
|
220
|
+
'ANTHROPIC_API_KEY',
|
|
221
|
+
'OPENAI_API_KEY',
|
|
222
|
+
]);
|
|
223
|
+
const VAR_RE = /\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g;
|
|
224
|
+
export function expandMcpServerEntry(entry, env, target) {
|
|
225
|
+
const missing = [];
|
|
226
|
+
const withheld = [];
|
|
227
|
+
try {
|
|
228
|
+
if (!isRecord(entry))
|
|
229
|
+
return Object.freeze({ entry, missing: Object.freeze([]), withheld: Object.freeze([]) });
|
|
230
|
+
const values = env !== undefined && isRecord(env) ? ownValue(env, 'values') : undefined;
|
|
231
|
+
const secrets = new Set(stringListOf(env !== undefined && isRecord(env) ? ownValue(env, 'hostSecretNames') : undefined) ?? []);
|
|
232
|
+
const x = (s) => s.replace(VAR_RE, (whole, name, def) => {
|
|
233
|
+
if (secrets.has(name) || (target === 'remote' && REMOTE_SINK_WITHHELD_NAMES.has(name))) {
|
|
234
|
+
if (!withheld.includes(name))
|
|
235
|
+
withheld.push(name);
|
|
236
|
+
return def ?? '';
|
|
237
|
+
}
|
|
238
|
+
const v = isRecord(values) ? ownValue(values, name) : undefined;
|
|
239
|
+
if (typeof v === 'string')
|
|
240
|
+
return v;
|
|
241
|
+
if (def !== undefined)
|
|
242
|
+
return def;
|
|
243
|
+
if (!missing.includes(name))
|
|
244
|
+
missing.push(name);
|
|
245
|
+
return whole;
|
|
246
|
+
});
|
|
247
|
+
const out = {};
|
|
248
|
+
const keys = ownKeysOf(entry) ?? [];
|
|
249
|
+
for (const k of keys) {
|
|
250
|
+
const r = ownData(entry, k);
|
|
251
|
+
if (!r.ok) {
|
|
252
|
+
const d = Object.getOwnPropertyDescriptor(entry, k);
|
|
253
|
+
if (d !== undefined)
|
|
254
|
+
Object.defineProperty(out, k, d);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
let v = r.value;
|
|
258
|
+
if ((k === 'command' || k === 'url') && typeof v === 'string')
|
|
259
|
+
v = x(v);
|
|
260
|
+
else if (k === 'args') {
|
|
261
|
+
const list = stringListOf(v);
|
|
262
|
+
if (list !== undefined)
|
|
263
|
+
v = list.map(x);
|
|
264
|
+
}
|
|
265
|
+
else if ((k === 'env' || k === 'headers') && isRecord(v)) {
|
|
266
|
+
const src = v;
|
|
267
|
+
const map = {};
|
|
268
|
+
let ok = true;
|
|
269
|
+
for (const mk of ownKeysOf(src) ?? []) {
|
|
270
|
+
const mr = ownData(src, mk);
|
|
271
|
+
if (!mr.ok) {
|
|
272
|
+
ok = false;
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
Object.defineProperty(map, mk, { value: typeof mr.value === 'string' ? x(mr.value) : mr.value, writable: true, enumerable: true, configurable: true });
|
|
276
|
+
}
|
|
277
|
+
if (ok)
|
|
278
|
+
v = map;
|
|
279
|
+
}
|
|
280
|
+
Object.defineProperty(out, k, { value: v, writable: true, enumerable: true, configurable: true });
|
|
281
|
+
}
|
|
282
|
+
return Object.freeze({ entry: out, missing: Object.freeze([...missing]), withheld: Object.freeze([...withheld]) });
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
return Object.freeze({ entry, missing: Object.freeze([...missing]), withheld: Object.freeze([...withheld]) });
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
export function expansionTargetOf(entry) {
|
|
289
|
+
const t = ownValue(entry, 'type');
|
|
290
|
+
if (typeof t === 'string')
|
|
291
|
+
return t === 'stdio' ? 'plain' : 'remote';
|
|
292
|
+
return typeof ownValue(entry, 'url') === 'string' && ownValue(entry, 'command') === undefined ? 'remote' : 'plain';
|
|
293
|
+
}
|
|
294
|
+
const NAME_REASONS = Object.freeze({ name_blank: true, name_edge_whitespace: true, name_collides_after_trim: true, name_too_long: true, name_reserved: true });
|
|
295
|
+
export function judgeTable(table, env, opts) {
|
|
296
|
+
try {
|
|
297
|
+
if (!isRecord(table))
|
|
298
|
+
return undefined;
|
|
299
|
+
const names = ownKeysOf(table);
|
|
300
|
+
if (names === undefined)
|
|
301
|
+
return undefined;
|
|
302
|
+
const forJudge = {};
|
|
303
|
+
const pre = [];
|
|
304
|
+
for (const name of names) {
|
|
305
|
+
const r = ownData(table, name);
|
|
306
|
+
const raw = r.ok ? r.value : undefined;
|
|
307
|
+
const reserved = opts.reserved.has(name);
|
|
308
|
+
const envSig = opts.signature === true && r.ok ? envSignatureOf(raw) : undefined;
|
|
309
|
+
const readable = r.ok && (opts.signature !== true || envSig !== undefined);
|
|
310
|
+
const exp = readable && !reserved ? (opts.expand ? expandMcpServerEntry(raw, env, expansionTargetOf(raw)) : { entry: raw, missing: [], withheld: [] }) : undefined;
|
|
311
|
+
pre.push({ name, raw, readable, exp, reserved, envSig });
|
|
312
|
+
if (!reserved && readable)
|
|
313
|
+
Object.defineProperty(forJudge, name, { value: exp?.entry, writable: true, enumerable: true, configurable: true });
|
|
314
|
+
else if (!reserved)
|
|
315
|
+
Object.defineProperty(forJudge, name, {
|
|
316
|
+
get() {
|
|
317
|
+
throw new Error('entry unreadable');
|
|
318
|
+
},
|
|
319
|
+
enumerable: true,
|
|
320
|
+
configurable: true,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
const projected = projectMcpConfigs(forJudge, opts.lang === undefined ? undefined : { lang: opts.lang });
|
|
324
|
+
const out = [];
|
|
325
|
+
for (const p of pre) {
|
|
326
|
+
if (p.reserved) {
|
|
327
|
+
out.push({ name: p.name, raw: p.raw, spec: undefined, problems: Object.freeze([{ reason: 'name_reserved', notice: renderMessage(msg('config.mcpServers.problem.nameReserved'), opts.lang) }]), missing: [], withheld: [], vote: { kind: 'none' }, reserved: true, ...(p.envSig === undefined ? {} : { envSig: p.envSig }) });
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
const spec = projected.specs.find((s) => s.name === p.name);
|
|
331
|
+
const drops = projected.dropped.filter((d) => d.name === p.name);
|
|
332
|
+
const problems = drops.map((d) => Object.freeze({ reason: d.reason, ...(d.path === undefined ? {} : { path: d.path }), notice: d.notice }));
|
|
333
|
+
if (spec === undefined && problems.length === 0) {
|
|
334
|
+
const tv = isRecord(p.exp?.entry) ? mcpTransportVerdict(p.exp?.entry) : undefined;
|
|
335
|
+
problems.push(Object.freeze({ reason: 'transport_invalid', path: tv !== undefined && tv.kind === 'bad' ? tv.key : 'transport.kind', notice: tv !== undefined && tv.kind === 'bad' ? tv.detail : 'transport not supported' }));
|
|
336
|
+
}
|
|
337
|
+
const nameBad = drops.some((d) => Object.hasOwn(NAME_REASONS, d.reason));
|
|
338
|
+
const notObject = !p.readable || !isRecord(p.raw);
|
|
339
|
+
let vote;
|
|
340
|
+
if (nameBad || notObject)
|
|
341
|
+
vote = { kind: 'none' };
|
|
342
|
+
else {
|
|
343
|
+
const a = ownData(p.raw, 'allowTools');
|
|
344
|
+
const transportBad = spec === undefined && problems.some((x) => x.reason === 'transport_invalid' || x.reason === 'identity_headers_both_set');
|
|
345
|
+
if (!a.ok)
|
|
346
|
+
vote = { kind: 'bad' };
|
|
347
|
+
else if (a.value === undefined)
|
|
348
|
+
vote = { kind: 'absent' };
|
|
349
|
+
else if (transportBad)
|
|
350
|
+
vote = { kind: 'bad' };
|
|
351
|
+
else {
|
|
352
|
+
const list = stringListOf(a.value);
|
|
353
|
+
vote = list === undefined ? { kind: 'bad' } : { kind: 'list', list: Object.freeze(list) };
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
out.push({ name: p.name, raw: p.raw, spec, problems: Object.freeze(problems), missing: p.exp?.missing ?? [], withheld: p.exp?.withheld ?? [], vote, reserved: false, ...(p.envSig === undefined ? {} : { envSig: p.envSig }) });
|
|
357
|
+
}
|
|
358
|
+
return Object.freeze(out);
|
|
359
|
+
}
|
|
360
|
+
catch {
|
|
361
|
+
return undefined;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
const LOOSEN_LAYERS = CC_MERGE_ORDER;
|
|
365
|
+
function approvalCategoryOf() {
|
|
366
|
+
const row = LOCAL_CONFIG_WRITE_INTENTS.find((r) => r.intent === 'mcpJsonEnabled');
|
|
367
|
+
return row === undefined ? '' : row.admitVia;
|
|
368
|
+
}
|
|
369
|
+
function approvalFactsOf(read, facts, purpose) {
|
|
370
|
+
const session = grantedNames(nameListOf(facts, 'sessionApproved'));
|
|
371
|
+
if (read === undefined)
|
|
372
|
+
return { rejected: new Set(), rejectedUnreadable: false, approvedBySettings: () => false, session, mayApprove: session.size > 0, autoBy: undefined, withheld: Object.freeze([]) };
|
|
373
|
+
const rejected = new Set();
|
|
374
|
+
let rejectedUnreadable = false;
|
|
375
|
+
const admitted = [];
|
|
376
|
+
const withheld = [];
|
|
377
|
+
for (const layer of LOOSEN_LAYERS) {
|
|
378
|
+
const snap = read.layers[layer];
|
|
379
|
+
if (!snap.enabled || snap.doc === null)
|
|
380
|
+
continue;
|
|
381
|
+
const rej = nameListOf(snap.doc, 'disabledMcpjsonServers');
|
|
382
|
+
if (rej.kind === 'bad')
|
|
383
|
+
rejectedUnreadable = true;
|
|
384
|
+
else if (rej.kind === 'list')
|
|
385
|
+
for (const n of rej.list)
|
|
386
|
+
rejected.add(n);
|
|
387
|
+
let word;
|
|
388
|
+
try {
|
|
389
|
+
word = layerAdmissionWord(layer, read.trust, approvalCategoryOf());
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
word = 'unknown';
|
|
393
|
+
}
|
|
394
|
+
if (word === 'admitted')
|
|
395
|
+
admitted.push(layer);
|
|
396
|
+
else if (word === 'trust_withheld' && (layer === 'projectSettings' || layer === 'localSettings')) {
|
|
397
|
+
const all = ownValue(snap.doc, 'enableAllProjectMcpServers') === true;
|
|
398
|
+
const en = nameListOf(snap.doc, 'enabledMcpjsonServers');
|
|
399
|
+
const named = en.kind === 'bad' || (en.kind === 'list' && en.list.length > 0);
|
|
400
|
+
if (all || named)
|
|
401
|
+
withheld.push({ layer, cause: 'trust_withheld' });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
const lists = admitted.map((l) => grantedNames(nameListOf(read.layers[l].doc, 'enabledMcpjsonServers')));
|
|
405
|
+
const union = new Set(lists.flatMap((s) => [...s]));
|
|
406
|
+
let approvedBySettings;
|
|
407
|
+
let mayApprove;
|
|
408
|
+
if (read.trust === 'accepted') {
|
|
409
|
+
let all;
|
|
410
|
+
for (const l of admitted) {
|
|
411
|
+
const v = ownValue(read.layers[l].doc, 'enableAllProjectMcpServers');
|
|
412
|
+
if (typeof v === 'boolean')
|
|
413
|
+
all = v;
|
|
414
|
+
}
|
|
415
|
+
approvedBySettings = (name) => all === true || union.has(name);
|
|
416
|
+
mayApprove = all === true || union.size > 0;
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
const anyAll = admitted.some((l) => ownValue(read.layers[l].doc, 'enableAllProjectMcpServers') === true);
|
|
420
|
+
approvedBySettings = (name) => anyAll || union.has(name);
|
|
421
|
+
mayApprove = anyAll || union.size > 0;
|
|
422
|
+
}
|
|
423
|
+
let autoBy;
|
|
424
|
+
if (purpose === 'load' && read.layers.projectSettings.enabled) {
|
|
425
|
+
const skip = ['policySettings', 'userSettings'].some((l) => read.layers[l].doc !== null && ownValue(read.layers[l].doc, 'skipDangerousModePermissionPrompt') === true);
|
|
426
|
+
if (ownValue(facts, 'permissionMode') === 'bypass' && skip)
|
|
427
|
+
autoBy = 'bypass';
|
|
428
|
+
else if (ownValue(facts, 'nonInteractive') === true)
|
|
429
|
+
autoBy = 'non_interactive';
|
|
430
|
+
}
|
|
431
|
+
return { rejected, rejectedUnreadable, approvedBySettings, session, mayApprove: mayApprove || session.size > 0 || autoBy !== undefined, autoBy, withheld: Object.freeze(withheld) };
|
|
432
|
+
}
|
|
433
|
+
function approvalOf(a, name) {
|
|
434
|
+
if (a.rejected.has(name))
|
|
435
|
+
return { state: 'rejected' };
|
|
436
|
+
if (a.approvedBySettings(name))
|
|
437
|
+
return { state: 'approved', by: 'settings' };
|
|
438
|
+
if (a.session.has(name))
|
|
439
|
+
return { state: 'approved', by: 'session' };
|
|
440
|
+
if (a.autoBy !== undefined)
|
|
441
|
+
return { state: 'approved', by: a.autoBy };
|
|
442
|
+
return { state: 'pending' };
|
|
443
|
+
}
|
|
444
|
+
export function fileReadingOf(holder, key, missing) {
|
|
445
|
+
const slot = ownData(holder, key);
|
|
446
|
+
if (!slot.ok)
|
|
447
|
+
return { status: 'unreadable', cause: 'io' };
|
|
448
|
+
const r = slot.value;
|
|
449
|
+
if (r === undefined)
|
|
450
|
+
return missing === 'absent' ? { status: 'absent' } : { status: 'unreadable', cause: 'io' };
|
|
451
|
+
if (!isRecord(r))
|
|
452
|
+
return { status: 'unreadable', cause: 'io' };
|
|
453
|
+
const status = ownData(r, 'status');
|
|
454
|
+
if (!status.ok)
|
|
455
|
+
return { status: 'unreadable', cause: 'io' };
|
|
456
|
+
if (status.value === 'absent')
|
|
457
|
+
return { status: 'absent' };
|
|
458
|
+
if (status.value === 'outside_fence')
|
|
459
|
+
return { status: 'outside_fence' };
|
|
460
|
+
if (status.value !== 'loaded')
|
|
461
|
+
return { status: 'unreadable', cause: 'io' };
|
|
462
|
+
const doc = ownData(r, 'doc');
|
|
463
|
+
const revision = ownData(r, 'revision');
|
|
464
|
+
if (!doc.ok || !isRecord(doc.value) || !revision.ok || typeof revision.value !== 'string' || revision.value === '')
|
|
465
|
+
return { status: 'unreadable', cause: 'io' };
|
|
466
|
+
const loaded = { status: 'loaded', doc: doc.value, revision: revision.value };
|
|
467
|
+
return Object.freeze(loaded);
|
|
468
|
+
}
|
|
469
|
+
const revisionOf = (r) => (r.status === 'loaded' ? r.revision : null);
|
|
470
|
+
const sourceTableOf = (r, path) => (r.status === 'outside_fence' ? { kind: 'absent' } : subTableOf(documentOf(r), path));
|
|
471
|
+
function signatureOf(entry) {
|
|
472
|
+
const url = ownValue(entry, 'url');
|
|
473
|
+
if (typeof url === 'string')
|
|
474
|
+
return `u:${url}`;
|
|
475
|
+
const cmd = ownValue(entry, 'command');
|
|
476
|
+
if (typeof cmd !== 'string')
|
|
477
|
+
return undefined;
|
|
478
|
+
return `c:${JSON.stringify([cmd, stringListOf(ownValue(entry, 'args')) ?? []])}`;
|
|
479
|
+
}
|
|
480
|
+
export function mergeMcpServers(input, purpose) {
|
|
481
|
+
const lang = input.lang;
|
|
482
|
+
const facts = isRecord(input.facts) ? input.facts : {};
|
|
483
|
+
const files = isRecord(input.files) ? input.files : {};
|
|
484
|
+
const supplementary = isRecord(input.supplementarySources) ? input.supplementarySources : {};
|
|
485
|
+
let read;
|
|
486
|
+
if (input.settings !== 'none') {
|
|
487
|
+
try {
|
|
488
|
+
read = readHostSettingsOnce(input.settings, 'mcpServersReport');
|
|
489
|
+
}
|
|
490
|
+
catch {
|
|
491
|
+
read = undefined;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
const env = ownValue(facts, 'env');
|
|
495
|
+
const reserved = new Set(stringListOf(ownValue(facts, 'reservedNames')) ?? []);
|
|
496
|
+
const none = new Set();
|
|
497
|
+
const approvals = approvalFactsOf(read, facts, purpose);
|
|
498
|
+
const unreadable = new Set();
|
|
499
|
+
const g = fileReadingOf(files, 'global', 'absent');
|
|
500
|
+
const ent = fileReadingOf(files, 'enterprise', 'absent');
|
|
501
|
+
const projectKeyRaw = ownValue(files, 'projectKey');
|
|
502
|
+
const projectKey = typeof projectKeyRaw === 'string' && projectKeyRaw !== '' ? projectKeyRaw : undefined;
|
|
503
|
+
const chain = [];
|
|
504
|
+
const chainSlot = ownData(files, 'projectChain');
|
|
505
|
+
if (!chainSlot.ok)
|
|
506
|
+
chain.push({ status: 'unreadable', cause: 'io' });
|
|
507
|
+
else if (chainSlot.value !== undefined) {
|
|
508
|
+
const len = ownArrayLength(chainSlot.value);
|
|
509
|
+
if (len === undefined)
|
|
510
|
+
chain.push({ status: 'unreadable', cause: 'io' });
|
|
511
|
+
else
|
|
512
|
+
for (let i = 0; i < len; i++)
|
|
513
|
+
chain.push(fileReadingOf(chainSlot.value, String(i), 'unreadable'));
|
|
514
|
+
}
|
|
515
|
+
const policyDoc = read !== undefined ? read.layers.policySettings.doc : null;
|
|
516
|
+
const pluginOnlyRaw = policyDoc === null ? undefined : ownValue(policyDoc, 'strictPluginOnlyCustomization');
|
|
517
|
+
const pluginOnly = pluginOnlyRaw === true || (stringListOf(pluginOnlyRaw) ?? []).includes('mcp');
|
|
518
|
+
const enterpriseBranch = ent.status === 'loaded' || ent.status === 'unreadable';
|
|
519
|
+
const strict = ownValue(supplementary, 'strictDynamicOnly') === true;
|
|
520
|
+
const locked = enterpriseBranch ? 'enterprise_config' : pluginOnly ? 'plugin_only' : undefined;
|
|
521
|
+
const managedState = read?.managed;
|
|
522
|
+
const managedWithhold = managedState === 'in-effect-pieces' || managedState === 'remote-unknown' || managedState === 'unreadable-covered' || managedState === 'unreadable-uncovered';
|
|
523
|
+
const projectEligible = !pluginOnly && approvals.mayApprove;
|
|
524
|
+
const sources = [];
|
|
525
|
+
const lockedOut = [];
|
|
526
|
+
const push = (s, out = sources) => {
|
|
527
|
+
out.push(s);
|
|
528
|
+
};
|
|
529
|
+
const judged = (t, opts) => t.kind === 'absent' ? 'absent' : t.kind === 'bad' ? 'unreadable' : (judgeTable(t.table, env, opts) ?? 'unreadable');
|
|
530
|
+
const slot = (key) => {
|
|
531
|
+
const r = ownData(supplementary, key);
|
|
532
|
+
if (!r.ok)
|
|
533
|
+
return 'unreadable';
|
|
534
|
+
return r.value === undefined ? undefined : isRecord(r.value) ? r.value : 'unreadable';
|
|
535
|
+
};
|
|
536
|
+
const agentSlot = (() => {
|
|
537
|
+
const r = ownData(supplementary, 'agent');
|
|
538
|
+
if (!r.ok)
|
|
539
|
+
return 'unreadable';
|
|
540
|
+
const v = r.value;
|
|
541
|
+
if (v === undefined)
|
|
542
|
+
return undefined;
|
|
543
|
+
if (!isRecord(v))
|
|
544
|
+
return 'unreadable';
|
|
545
|
+
const servers = ownValue(v, 'servers');
|
|
546
|
+
return isRecord(servers) ? { fromFlagSettings: ownValue(v, 'fromFlagSettings') === true, servers } : 'unreadable';
|
|
547
|
+
})();
|
|
548
|
+
const addExtra = (scope, table, useReserved) => {
|
|
549
|
+
if (table === undefined)
|
|
550
|
+
return;
|
|
551
|
+
const entries = table === 'unreadable' ? 'unreadable' : judged({ kind: 'table', table }, { expand: true, reserved: useReserved ? reserved : none, lang, ...(scope === 'plugin' ? { signature: true } : {}) });
|
|
552
|
+
if (entries === 'unreadable')
|
|
553
|
+
unreadable.add('supplementary');
|
|
554
|
+
else if (entries !== 'absent')
|
|
555
|
+
push({ scope, file: 'supplementary', revision: null, entries, project: false, writable: false });
|
|
556
|
+
};
|
|
557
|
+
const addManaged = () => {
|
|
558
|
+
const entries = judged(policyDoc === null ? { kind: 'absent' } : subTableOf(policyDoc, ['managedMcpServers']), { expand: false, reserved: none, lang });
|
|
559
|
+
if (entries === 'unreadable')
|
|
560
|
+
unreadable.add('managed');
|
|
561
|
+
else if (entries !== 'absent')
|
|
562
|
+
push({ scope: 'managed', file: 'managed', revision: null, entries, project: false, writable: false });
|
|
563
|
+
};
|
|
564
|
+
if (managedWithhold)
|
|
565
|
+
unreadable.add('managed');
|
|
566
|
+
if (enterpriseBranch) {
|
|
567
|
+
addManaged();
|
|
568
|
+
const entries = judged(sourceTableOf(ent, PROJECT_FILE_PATH), { expand: true, reserved, lang });
|
|
569
|
+
if (entries === 'unreadable')
|
|
570
|
+
unreadable.add('enterprise');
|
|
571
|
+
else if (entries !== 'absent')
|
|
572
|
+
push({ scope: 'enterprise', file: 'enterprise', revision: revisionOf(ent), entries, project: false, writable: false });
|
|
573
|
+
}
|
|
574
|
+
else if (strict) {
|
|
575
|
+
if (agentSlot !== undefined && agentSlot !== 'unreadable' && agentSlot.fromFlagSettings)
|
|
576
|
+
addExtra('agent', agentSlot.servers, false);
|
|
577
|
+
else if (agentSlot === 'unreadable')
|
|
578
|
+
unreadable.add('supplementary');
|
|
579
|
+
addExtra('dynamic', slot('dynamic'), false);
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
addExtra('claudeai', slot('claudeai'), true);
|
|
583
|
+
addExtra('plugin', slot('plugin'), true);
|
|
584
|
+
const fileSink = pluginOnly ? lockedOut : sources;
|
|
585
|
+
const userEntries = judged(sourceTableOf(g, USER_SCOPE_PATH), { expand: true, reserved, lang });
|
|
586
|
+
if (userEntries === 'unreadable') {
|
|
587
|
+
if (!pluginOnly)
|
|
588
|
+
unreadable.add('global');
|
|
589
|
+
}
|
|
590
|
+
else if (userEntries !== 'absent')
|
|
591
|
+
push({ scope: 'user', file: 'global', revision: revisionOf(g), entries: userEntries, project: false, writable: !pluginOnly }, fileSink);
|
|
592
|
+
for (let ci = 0; ci < chain.length; ci++) {
|
|
593
|
+
const f = chain[ci];
|
|
594
|
+
const entries = judged(sourceTableOf(f, PROJECT_FILE_PATH), { expand: true, reserved, lang });
|
|
595
|
+
if (entries === 'unreadable') {
|
|
596
|
+
if (projectEligible)
|
|
597
|
+
unreadable.add('project');
|
|
598
|
+
}
|
|
599
|
+
else if (entries !== 'absent')
|
|
600
|
+
push({ scope: 'project', file: 'project', revision: revisionOf(f), entries, project: true, writable: !pluginOnly && ci === chain.length - 1 && ownValue(facts, 'projectConfigRootSet') !== true }, fileSink);
|
|
601
|
+
}
|
|
602
|
+
if (approvals.rejectedUnreadable && projectEligible && sources.some((s) => s.project && s.entries.length > 0))
|
|
603
|
+
unreadable.add('project');
|
|
604
|
+
if (projectKey !== undefined) {
|
|
605
|
+
const localEntries = judged(sourceTableOf(g, localScopePath(projectKey)), { expand: true, reserved, lang });
|
|
606
|
+
if (localEntries === 'unreadable') {
|
|
607
|
+
if (!pluginOnly)
|
|
608
|
+
unreadable.add('global');
|
|
609
|
+
}
|
|
610
|
+
else if (localEntries !== 'absent')
|
|
611
|
+
push({ scope: 'local', file: 'global', revision: revisionOf(g), entries: localEntries, project: false, writable: !pluginOnly }, fileSink);
|
|
612
|
+
}
|
|
613
|
+
addManaged();
|
|
614
|
+
if (agentSlot === 'unreadable')
|
|
615
|
+
unreadable.add('supplementary');
|
|
616
|
+
else if (agentSlot !== undefined)
|
|
617
|
+
addExtra('agent', agentSlot.servers, false);
|
|
618
|
+
addExtra('dynamic', slot('dynamic'), false);
|
|
619
|
+
}
|
|
620
|
+
const approvalByName = new Map();
|
|
621
|
+
const participates = (s, e) => {
|
|
622
|
+
if (!s.project)
|
|
623
|
+
return true;
|
|
624
|
+
let v = approvalByName.get(e.name);
|
|
625
|
+
if (v === undefined) {
|
|
626
|
+
v = approvalOf(approvals, e.name);
|
|
627
|
+
approvalByName.set(e.name, v);
|
|
628
|
+
}
|
|
629
|
+
return v.state === 'approved';
|
|
630
|
+
};
|
|
631
|
+
const manualSigs = new Set();
|
|
632
|
+
for (const s of sources) {
|
|
633
|
+
if (s.scope === 'plugin' || s.scope === 'claudeai')
|
|
634
|
+
continue;
|
|
635
|
+
for (const e of s.entries)
|
|
636
|
+
if (e.spec !== undefined && participates(s, e)) {
|
|
637
|
+
const sig = signatureOf(e.raw);
|
|
638
|
+
if (sig !== undefined)
|
|
639
|
+
manualSigs.add(sig);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
const pluginSigs = new Set();
|
|
643
|
+
const suppressed = new Set();
|
|
644
|
+
for (const s of sources) {
|
|
645
|
+
if (s.scope !== 'plugin')
|
|
646
|
+
continue;
|
|
647
|
+
for (const e of s.entries) {
|
|
648
|
+
if (e.envSig === undefined)
|
|
649
|
+
continue;
|
|
650
|
+
const sig = signatureOf(e.raw);
|
|
651
|
+
if (sig === undefined)
|
|
652
|
+
continue;
|
|
653
|
+
const withEnv = `${sig}|${e.envSig}`;
|
|
654
|
+
if (manualSigs.has(sig) || pluginSigs.has(withEnv))
|
|
655
|
+
suppressed.add(e);
|
|
656
|
+
else
|
|
657
|
+
pluginSigs.add(withEnv);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
const votes = new Map();
|
|
661
|
+
for (const s of sources)
|
|
662
|
+
for (const e of s.entries) {
|
|
663
|
+
if (e.vote.kind === 'none' || suppressed.has(e) || !participates(s, e))
|
|
664
|
+
continue;
|
|
665
|
+
const list = votes.get(e.name) ?? [];
|
|
666
|
+
list.push(e.vote);
|
|
667
|
+
votes.set(e.name, list);
|
|
668
|
+
}
|
|
669
|
+
const ledgerOf = (name) => {
|
|
670
|
+
const vs = votes.get(name) ?? [];
|
|
671
|
+
if (vs.some((v) => v.kind === 'bad'))
|
|
672
|
+
return { kind: 'withheld', by: 'narrowing_invalid' };
|
|
673
|
+
const lists = vs.filter((v) => v.kind === 'list');
|
|
674
|
+
if (lists.length === 0)
|
|
675
|
+
return { kind: 'ok' };
|
|
676
|
+
if (lists.length !== vs.length)
|
|
677
|
+
return { kind: 'withheld', by: 'narrowing_conflict' };
|
|
678
|
+
const first = JSON.stringify(lists[0].list);
|
|
679
|
+
return lists.every((l) => JSON.stringify(l.list) === first) ? { kind: 'ok' } : { kind: 'withheld', by: 'narrowing_conflict' };
|
|
680
|
+
};
|
|
681
|
+
let disabled = new Set();
|
|
682
|
+
if (projectKey !== undefined) {
|
|
683
|
+
const pt = sourceTableOf(g, ['projects', projectKey]);
|
|
684
|
+
const list = pt.kind === 'table' ? nameListOf(pt.table, 'disabledMcpServers') : pt.kind === 'absent' ? { kind: 'absent' } : { kind: 'bad' };
|
|
685
|
+
if (list.kind === 'bad')
|
|
686
|
+
unreadable.add('global');
|
|
687
|
+
else if (list.kind === 'list')
|
|
688
|
+
disabled = new Set(list.list);
|
|
689
|
+
}
|
|
690
|
+
const q2 = unreadable.size > 0;
|
|
691
|
+
const order = [];
|
|
692
|
+
const byName = new Map();
|
|
693
|
+
const slotOf = (name) => {
|
|
694
|
+
let x = byName.get(name);
|
|
695
|
+
if (x === undefined) {
|
|
696
|
+
x = { shadows: [] };
|
|
697
|
+
byName.set(name, x);
|
|
698
|
+
order.push(name);
|
|
699
|
+
}
|
|
700
|
+
return x;
|
|
701
|
+
};
|
|
702
|
+
for (const s of sources)
|
|
703
|
+
for (const e of s.entries) {
|
|
704
|
+
if (suppressed.has(e))
|
|
705
|
+
continue;
|
|
706
|
+
const x = slotOf(e.name);
|
|
707
|
+
if (s.project && !participates(s, e)) {
|
|
708
|
+
x.pending = { s, e, v: approvalByName.get(e.name) ?? { state: 'pending' } };
|
|
709
|
+
continue;
|
|
710
|
+
}
|
|
711
|
+
if (e.spec === undefined) {
|
|
712
|
+
x.unusable = { s, e };
|
|
713
|
+
continue;
|
|
714
|
+
}
|
|
715
|
+
if (x.winner !== undefined && !x.shadows.includes(x.winner.s.scope))
|
|
716
|
+
x.shadows.push(x.winner.s.scope);
|
|
717
|
+
x.winner = { s, e };
|
|
718
|
+
}
|
|
719
|
+
for (const s of lockedOut)
|
|
720
|
+
for (const e of s.entries)
|
|
721
|
+
slotOf(e.name);
|
|
722
|
+
const rows = [];
|
|
723
|
+
for (const name of order) {
|
|
724
|
+
const x = byName.get(name);
|
|
725
|
+
if (x.winner !== undefined) {
|
|
726
|
+
const { s, e } = x.winner;
|
|
727
|
+
const ledger = ledgerOf(name);
|
|
728
|
+
const base = { name, scope: s.scope, entry: e.raw, shadows: Object.freeze([...x.shadows]), origin: Object.freeze({ file: s.file, revision: s.revision }), writable: s.writable, missing: e.missing, withheldVars: e.withheld };
|
|
729
|
+
const av = s.project ? approvalByName.get(name) : undefined;
|
|
730
|
+
const approvedBy = av !== undefined && av.state === 'approved' ? av.by : undefined;
|
|
731
|
+
const withApproval = approvedBy === undefined ? {} : { approvedBy };
|
|
732
|
+
if (q2)
|
|
733
|
+
rows.push(Object.freeze({ ...base, ...withApproval, state: 'withheld', withheldBy: 'layer_unreadable' }));
|
|
734
|
+
else if (ledger.kind === 'withheld')
|
|
735
|
+
rows.push(Object.freeze({ ...base, ...withApproval, state: 'withheld', withheldBy: ledger.by }));
|
|
736
|
+
else if (disabled.has(name))
|
|
737
|
+
rows.push(Object.freeze({ ...base, ...withApproval, state: 'disabled' }));
|
|
738
|
+
else
|
|
739
|
+
rows.push(Object.freeze({ ...base, ...withApproval, state: 'active', ...(e.spec === undefined ? {} : { spec: e.spec }) }));
|
|
740
|
+
continue;
|
|
741
|
+
}
|
|
742
|
+
if (x.pending !== undefined) {
|
|
743
|
+
const { s, e, v } = x.pending;
|
|
744
|
+
rows.push(Object.freeze({ name, scope: s.scope, entry: e.raw, shadows: Object.freeze([]), state: v.state === 'rejected' ? 'rejected' : 'pending_approval', origin: Object.freeze({ file: s.file, revision: s.revision }), writable: s.writable, missing: e.missing, withheldVars: e.withheld }));
|
|
745
|
+
continue;
|
|
746
|
+
}
|
|
747
|
+
if (x.unusable !== undefined) {
|
|
748
|
+
const { s, e } = x.unusable;
|
|
749
|
+
rows.push(Object.freeze({ name, scope: s.scope, entry: e.raw, shadows: Object.freeze([]), state: 'unusable', problems: e.problems, origin: Object.freeze({ file: s.file, revision: s.revision }), writable: s.writable, missing: e.missing, withheldVars: e.withheld }));
|
|
750
|
+
continue;
|
|
751
|
+
}
|
|
752
|
+
for (const s of lockedOut) {
|
|
753
|
+
const e = s.entries.filter((y) => y.name === name).pop();
|
|
754
|
+
if (e === undefined)
|
|
755
|
+
continue;
|
|
756
|
+
rows.push(Object.freeze({ name, scope: s.scope, entry: e.raw, shadows: Object.freeze([]), state: 'withheld', withheldBy: 'policy_locked', origin: Object.freeze({ file: s.file, revision: s.revision }), writable: false, missing: e.missing, withheldVars: e.withheld }));
|
|
757
|
+
break;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
const dep = ownValue(facts, 'deploymentNames');
|
|
761
|
+
const depList = stringListOf(dep);
|
|
762
|
+
const deployment = depList !== undefined ? Object.freeze({ state: 'read', names: Object.freeze(depList) }) : Object.freeze({ state: 'unknown' });
|
|
763
|
+
return Object.freeze({
|
|
764
|
+
rows: Object.freeze(rows),
|
|
765
|
+
unreadable: Object.freeze(['global', 'project', 'enterprise', 'managed', 'supplementary'].filter((f) => unreadable.has(f))),
|
|
766
|
+
locked,
|
|
767
|
+
purpose,
|
|
768
|
+
approvalsWithheld: approvals.withheld,
|
|
769
|
+
deployment,
|
|
770
|
+
pluginRoster: slot('plugin') === undefined ? 'absent' : 'host_supplied',
|
|
771
|
+
promptsAndResources: 'not_yet',
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
export function mcpServersReport(files, facts, settings, supplementarySources, lang) {
|
|
775
|
+
return mergeMcpServers({ files, facts, settings, ...(supplementarySources === undefined ? {} : { supplementarySources }), ...(lang === undefined ? {} : { lang }) }, 'report');
|
|
776
|
+
}
|