@sema-agent/client-core 0.105.0 → 0.106.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 +220 -0
- package/README.md +26 -11
- package/dist/adapt/arms.js +10 -1
- package/dist/adapter/activeRunSelfHeal.d.ts +13 -2
- package/dist/adapter/activeRunSelfHeal.js +80 -7
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +0 -5
- package/dist/adapter/downstream/eventToSdkMessage.js +20 -19
- package/dist/adapter/downstream/terminalToSdkResult.js +2 -3
- package/dist/adapter/downstream/wiringManifestView.d.ts +1 -3
- package/dist/adapter/downstream/wiringManifestView.js +0 -1
- package/dist/adapter/runStream.js +3 -4
- package/dist/approvalReachWire.d.ts +1 -0
- package/dist/approvalReachWire.js +4 -1
- package/dist/approvalSeat.d.ts +21 -0
- package/dist/approvalSeat.js +73 -0
- package/dist/assistantInbox.d.ts +2 -0
- package/dist/assistantInbox.js +3 -0
- package/dist/checkpointRowVerdict.d.ts +23 -0
- package/dist/checkpointRowVerdict.js +89 -0
- package/dist/coreValuePorts.d.ts +12 -1
- package/dist/coreValuePorts.js +10 -0
- package/dist/decideFailureNote.js +3 -1
- package/dist/decideReceipt.d.ts +9 -0
- package/dist/decideReceipt.js +29 -1
- package/dist/declared/supportFloorDeclared.js +2 -2
- package/dist/deviceRebind.d.ts +7 -0
- package/dist/deviceRebind.js +39 -5
- package/dist/engineAddress.d.ts +3 -0
- package/dist/engineAddress.js +25 -0
- package/dist/engineDirectory.js +9 -17
- package/dist/engineErrorCodes.d.ts +8 -0
- package/dist/engineErrorCodes.js +8 -0
- package/dist/engineNoticeCodes.d.ts +26 -3
- package/dist/engineNoticeCodes.js +52 -7
- package/dist/engineRowRef.js +1 -1
- package/dist/errorSupplementRoles.js +2 -0
- package/dist/eventLeg.d.ts +2 -2
- package/dist/eventLeg.js +2 -1
- package/dist/fleet/fleetProjection.js +26 -5
- package/dist/generated/engineFactTables.d.ts +2 -1
- package/dist/generated/engineFactTables.js +3 -1
- package/dist/generated/engineNoticeTables.js +19 -4
- package/dist/generated/sdkFactTables.d.ts +3 -0
- package/dist/generated/sdkFactTables.js +15 -0
- package/dist/generated/settingsSchemaFns.d.ts +11 -0
- package/dist/generated/settingsSchemaFns.js +2 -1
- package/dist/generated/settingsSchemaSafetyMergeSpec.js +1 -1
- package/dist/generated/settingsSchemaSettingsSources.d.ts +1 -1
- package/dist/generated/settingsSchemaSettingsSources.js +22 -2
- package/dist/hitl/approvalLiveFace.d.ts +17 -0
- package/dist/hitl/approvalLiveFace.js +35 -0
- package/dist/hitl/approvalQueueRow.d.ts +21 -0
- package/dist/hitl/approvalQueueRow.js +69 -0
- package/dist/hitl/approvalsFeed.d.ts +5 -4
- package/dist/hitl/approvalsFeed.js +38 -6
- package/dist/hitl/askParkRowRouting.d.ts +4 -3
- package/dist/hitl/askParkRowRouting.js +15 -3
- package/dist/hitl/automaticAnswerVerdict.js +13 -10
- package/dist/hitl/crashConverged.d.ts +5 -1
- package/dist/hitl/decisionConflict.js +2 -1
- package/dist/hitl/decisionRefusal.js +1 -1
- package/dist/hitl/decisionSend.d.ts +1 -0
- package/dist/hitl/decisionSend.js +14 -2
- package/dist/hitl/frameRouter.js +4 -5
- package/dist/hitl/hitlBridge.d.ts +1 -1
- package/dist/hitl/hitlBridge.js +26 -5
- package/dist/hitl/livePendingAsk.d.ts +5 -0
- package/dist/hitl/livePendingAsk.js +6 -1
- package/dist/hitl/planReviewCard.d.ts +2 -0
- package/dist/hitl/planReviewCard.js +21 -0
- package/dist/hitl/planReviewWire.d.ts +2 -2
- package/dist/hitl/planReviewWire.js +101 -36
- package/dist/hitl/sessionAllowRoute.d.ts +2 -0
- package/dist/hitl/sessionAllowRoute.js +7 -0
- package/dist/hitl/sessionPolicyWire.d.ts +1 -7
- package/dist/hitl/sessionPolicyWire.js +3 -43
- package/dist/hitl/subagentSource.d.ts +1 -0
- package/dist/hitl/subagentSource.js +13 -0
- package/dist/hitl/toolApprovalWire.d.ts +3 -2
- package/dist/hitl/toolApprovalWire.js +79 -37
- package/dist/hostSettingsSource.d.ts +4 -1
- package/dist/hostSettingsSource.js +11 -6
- package/dist/hostTurnSettings.d.ts +4 -5
- package/dist/hostTurnSettings.js +80 -19
- package/dist/i18n/messages.en.d.ts +35 -12
- package/dist/i18n/messages.en.js +36 -13
- package/dist/i18n/messages.zh.js +38 -13
- package/dist/index.d.ts +21 -2
- package/dist/index.js +11 -2
- package/dist/liveInitToolFace.js +0 -1
- package/dist/liveModelCatalog.d.ts +15 -0
- package/dist/liveModelCatalog.js +40 -0
- package/dist/mcpWireCaps.js +1 -1
- package/dist/modelCapabilityProbe.js +66 -33
- package/dist/ownKey.d.ts +0 -1
- package/dist/ownKey.js +0 -2
- package/dist/permissionsDeclaration.d.ts +2 -2
- package/dist/permissionsDeclaration.js +12 -14
- package/dist/projectSeed.d.ts +39 -0
- package/dist/projectSeed.js +80 -0
- package/dist/promptDelivery.js +1 -1
- package/dist/replayBody.d.ts +7 -6
- package/dist/replayBody.js +62 -7
- package/dist/request/taskRequest.js +3 -4
- package/dist/ruleCompileVerdict.d.ts +0 -2
- package/dist/ruleCompileVerdict.js +0 -31
- package/dist/ruleRefusalSentence.js +0 -3
- package/dist/runReattachPolicy.d.ts +3 -0
- package/dist/runReattachPolicy.js +15 -2
- package/dist/runTerminal.js +30 -8
- package/dist/sandboxWire.d.ts +0 -3
- package/dist/sandboxWire.js +0 -9
- package/dist/seam.d.ts +14 -7
- package/dist/seam.js +12 -0
- package/dist/seatContract.d.ts +57 -7
- package/dist/seatContract.js +132 -3
- package/dist/serverSupportRange.d.ts +18 -0
- package/dist/serverSupportRange.js +25 -0
- package/dist/sessionEngine.d.ts +156 -0
- package/dist/sessionEngine.js +464 -0
- package/dist/sessionMap.d.ts +11 -1
- package/dist/sessionMap.js +35 -9
- package/dist/sessionMemorySync.d.ts +31 -0
- package/dist/sessionMemorySync.js +95 -0
- package/dist/sessionRowTag.d.ts +4 -0
- package/dist/sessionRowTag.js +18 -0
- package/dist/settingsLayerAdmission.d.ts +1 -0
- package/dist/settingsLayerAdmission.js +4 -1
- package/dist/toolResult.js +1 -1
- package/dist/wireRefusalCopy.js +2 -6
- package/docs/INTEGRATION-CLIENTS.md +1022 -16
- package/package.json +5 -5
|
@@ -15,9 +15,10 @@ import { readEngineActiveBgTasks } from '../fleet/fleetLedger.js';
|
|
|
15
15
|
import { CORE_SKILL_TOOL_NAME } from '../generated/toolNameTables.js';
|
|
16
16
|
import { CORE_ALLOW_ENTRY_INERT_REASONS, CORE_PERSISTED_RULE_MATCHES } from '../generated/engineFactTables.js';
|
|
17
17
|
import { msg, renderMessage } from '../i18n/translate.js';
|
|
18
|
+
import { sessionAllowCarried } from './sessionAllowRoute.js';
|
|
18
19
|
import { INTERRUPT_DENY_REASON, observeCancelByDeny, surfaceApprovalParking, surfaceRememberNotApplied, surfaceEditNotForwarded, surfaceEditRefusedOnBlindAsk, surfaceRuleArmNotSent, surfaceRuleArmRejected } from './hitlHostSurface.js';
|
|
19
20
|
import { approvalCallKey, liveFrameCallKey } from './gateIdentity.js';
|
|
20
|
-
import { displayUntrusted } from '../displayUntrusted.js';
|
|
21
|
+
import { displayUntrusted, quoteUntrustedForSentence } from '../displayUntrusted.js';
|
|
21
22
|
import { frameBindingOf } from '../frameBinding.js';
|
|
22
23
|
import { carriesAttributionKey, deliverWithAttributionLadder } from './attributionLadder.js';
|
|
23
24
|
import { deliverApprovalDecision, newSendTally } from './approvalDelivery.js';
|
|
@@ -28,6 +29,8 @@ import { isApprovalMandateWord } from '../gateVocabulary.js';
|
|
|
28
29
|
import { approvalDecidedByAdmitted } from '../approvalDecidedByCapability.js';
|
|
29
30
|
import { decideFailureNote } from '../decideFailureNote.js';
|
|
30
31
|
import { slotPresenceOf, wireFailureTextsOf } from '../wireFailureShape.js';
|
|
32
|
+
import { APPROVAL_LIVE_FACE_KEYS, approvalLiveFaceOf, hasOwnStrictTrue } from './approvalLiveFace.js';
|
|
33
|
+
import { subagentSourceSessionOf } from './subagentSource.js';
|
|
31
34
|
import { isPlainRecord } from '../jsonFaithful.js';
|
|
32
35
|
import { DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED } from '../engineErrorCodes.js';
|
|
33
36
|
import { readDecideReceipt } from '../decideReceipt.js';
|
|
@@ -156,7 +159,6 @@ function cardPortMissReason() {
|
|
|
156
159
|
}
|
|
157
160
|
const REMEMBER_REFUSAL_CODES = Object.freeze([
|
|
158
161
|
'remember_not_in_proof',
|
|
159
|
-
'remember_requires_binding',
|
|
160
162
|
'capability.store_required',
|
|
161
163
|
DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED,
|
|
162
164
|
'decide.parked_remember_unsupported',
|
|
@@ -512,9 +514,7 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
512
514
|
...(argsRewritten ? { argsRewritten: true, wireNote: ARGS_REWRITTEN_NOTE } : {}),
|
|
513
515
|
...(pending.governanceForced === true ? { governanceForced: true } : {}),
|
|
514
516
|
...(readRequiresRealApproval(pending) ? { requiresRealApproval: true } : {}),
|
|
515
|
-
...(
|
|
516
|
-
...((w) => (w !== undefined ? { mandate: w } : {}))(readApprovalMandate(pending)),
|
|
517
|
-
...((o) => (o !== undefined ? { origin: o } : {}))(readAskOrigin(pending)),
|
|
517
|
+
...approvalLiveFaceOf(pending).facts,
|
|
518
518
|
...((w) => (w !== undefined ? { approvalCard: w } : {}))(readApprovalCardWord(pending)),
|
|
519
519
|
...(readAskClassPair(pending) ?? {}),
|
|
520
520
|
...(pending.gateKind === 'irreversible_ask' ? { irreversibleParkGate: true } : {}),
|
|
@@ -683,6 +683,9 @@ export const TOOL_APPROVAL_FRAME_KEYS_MIRROR = [
|
|
|
683
683
|
'toolCallId',
|
|
684
684
|
'toolName',
|
|
685
685
|
'sourceTaskId',
|
|
686
|
+
'sourceSessionId',
|
|
687
|
+
'agentId',
|
|
688
|
+
'askReasons',
|
|
686
689
|
'fromSubagent',
|
|
687
690
|
'sourceAgentName',
|
|
688
691
|
'message',
|
|
@@ -758,9 +761,6 @@ export function toolPermissionRequestAskBits(card, requestId) {
|
|
|
758
761
|
...(seatSessionRowOf(card, requestId) ? { sessionRow: true } : {}),
|
|
759
762
|
};
|
|
760
763
|
}
|
|
761
|
-
function hasOwnStrictTrue(v, key) {
|
|
762
|
-
return Object.hasOwn(v, key) && v[key] === true;
|
|
763
|
-
}
|
|
764
764
|
function isToolApprovalDelegation(v) {
|
|
765
765
|
if (v === null || typeof v !== 'object')
|
|
766
766
|
return false;
|
|
@@ -1283,6 +1283,30 @@ export function classifierNoRulingDetail(word, lang) {
|
|
|
1283
1283
|
return renderMessage(msg('approval.classifier.noRulingOther', { reason: displayUntrusted(word) }), lang);
|
|
1284
1284
|
return renderMessage(msg('approval.classifier.noRulingBare'), lang);
|
|
1285
1285
|
}
|
|
1286
|
+
const BOUND_GRANT_NAMES_SHOWN = 6;
|
|
1287
|
+
const BOUND_GRANT_NAME_MAX = 512;
|
|
1288
|
+
const BOUND_GRANT_NAME_INPUT_MAX = 8192;
|
|
1289
|
+
const BOUND_GRANT_NAMES_LOOKAHEAD = 32;
|
|
1290
|
+
function boundGrantNameList(rules, lang) {
|
|
1291
|
+
const shown = [];
|
|
1292
|
+
let looked = 0;
|
|
1293
|
+
for (const entry of rules) {
|
|
1294
|
+
if (shown.length >= BOUND_GRANT_NAMES_SHOWN || looked >= BOUND_GRANT_NAMES_LOOKAHEAD)
|
|
1295
|
+
break;
|
|
1296
|
+
looked += 1;
|
|
1297
|
+
if (entry.length > BOUND_GRANT_NAME_INPUT_MAX)
|
|
1298
|
+
continue;
|
|
1299
|
+
const quoted = quoteUntrustedForSentence(entry, BOUND_GRANT_NAME_MAX);
|
|
1300
|
+
if (quoted !== undefined)
|
|
1301
|
+
shown.push(quoted);
|
|
1302
|
+
}
|
|
1303
|
+
if (shown.length === 0)
|
|
1304
|
+
return undefined;
|
|
1305
|
+
const rest = rules.length - shown.length;
|
|
1306
|
+
if (rest > 0)
|
|
1307
|
+
shown.push(renderMessage(msg('approval.boundGrants.more', { count: rest }), lang));
|
|
1308
|
+
return shown.join(' · ');
|
|
1309
|
+
}
|
|
1286
1310
|
export function approvalBoundGrantsDetail(grants, lang) {
|
|
1287
1311
|
const g = readApprovalBoundGrants({ boundGrants: grants });
|
|
1288
1312
|
if (g === undefined)
|
|
@@ -1290,8 +1314,10 @@ export function approvalBoundGrantsDetail(grants, lang) {
|
|
|
1290
1314
|
if (g.skill === null)
|
|
1291
1315
|
return renderMessage(msg('approval.boundGrants.noSkill'), lang);
|
|
1292
1316
|
const isRule = (e) => readBoundGrantEntry(e)?.kind === 'rule';
|
|
1293
|
-
const
|
|
1294
|
-
const
|
|
1317
|
+
const allowRules = g.allowedTools.filter(isRule);
|
|
1318
|
+
const denyRules = g.disallowedTools.filter(isRule);
|
|
1319
|
+
const a = allowRules.length;
|
|
1320
|
+
const d = denyRules.length;
|
|
1295
1321
|
const allowNothing = g.allowedTools.length - a;
|
|
1296
1322
|
const denyNothing = g.disallowedTools.length - d;
|
|
1297
1323
|
if (denyNothing > 0) {
|
|
@@ -1302,8 +1328,14 @@ export function approvalBoundGrantsDetail(grants, lang) {
|
|
|
1302
1328
|
return renderMessage(allowNothing === 1 ? msg('approval.boundGrants.listsNoToolsWithNothing.one') : msg('approval.boundGrants.listsNoToolsWithNothing.other', { count: String(allowNothing) }), lang);
|
|
1303
1329
|
return renderMessage(msg('approval.boundGrants.listsNoTools'), lang);
|
|
1304
1330
|
}
|
|
1305
|
-
const
|
|
1306
|
-
const
|
|
1331
|
+
const allowNames = boundGrantNameList(allowRules, lang);
|
|
1332
|
+
const denyNames = boundGrantNameList(denyRules, lang);
|
|
1333
|
+
const allow = allowNames !== undefined
|
|
1334
|
+
? (a === 1 ? msg('approval.boundGrants.allowPart.named.one', { names: allowNames }) : msg('approval.boundGrants.allowPart.named.other', { count: a, names: allowNames }))
|
|
1335
|
+
: (a === 1 ? msg('approval.boundGrants.allowPart.one') : msg('approval.boundGrants.allowPart.other', { count: a }));
|
|
1336
|
+
const deny = denyNames !== undefined
|
|
1337
|
+
? (d === 1 ? msg('approval.boundGrants.denyPart.named.one', { names: denyNames }) : msg('approval.boundGrants.denyPart.named.other', { count: d, names: denyNames }))
|
|
1338
|
+
: (d === 1 ? msg('approval.boundGrants.denyPart.one') : msg('approval.boundGrants.denyPart.other', { count: d }));
|
|
1307
1339
|
if (allowNothing > 0) {
|
|
1308
1340
|
return renderMessage(allowNothing === 1 ? msg('approval.boundGrants.activatesWithNothing.one', { allow, deny }) : msg('approval.boundGrants.activatesWithNothing.other', { allow, deny, count: String(allowNothing) }), lang);
|
|
1309
1341
|
}
|
|
@@ -1320,7 +1352,8 @@ function askSigOf(classes, origin, mandate) {
|
|
|
1320
1352
|
}
|
|
1321
1353
|
function carrierAskSig(v, live) {
|
|
1322
1354
|
try {
|
|
1323
|
-
|
|
1355
|
+
const face = live === undefined ? undefined : approvalLiveFaceOf(live);
|
|
1356
|
+
return askSigOf(readAskClassPair(v)?.classes, face?.facts.origin, face?.facts.mandate);
|
|
1324
1357
|
}
|
|
1325
1358
|
catch {
|
|
1326
1359
|
return undefined;
|
|
@@ -1605,10 +1638,11 @@ export function readRuleOfferSupply(offers) {
|
|
|
1605
1638
|
}
|
|
1606
1639
|
function subagentBadgeFor(frame) {
|
|
1607
1640
|
let name = typeof frame.sourceAgentName === 'string' && frame.sourceAgentName.length > 0 ? frame.sourceAgentName : '';
|
|
1608
|
-
|
|
1609
|
-
|
|
1641
|
+
const source = subagentSourceSessionOf(frame);
|
|
1642
|
+
if (!name && source !== undefined) {
|
|
1643
|
+
name = source;
|
|
1610
1644
|
try {
|
|
1611
|
-
const row = readEngineActiveBgTasks().tasks.find(t => t.id ===
|
|
1645
|
+
const row = readEngineActiveBgTasks().tasks.find(t => t.id === source);
|
|
1612
1646
|
if (typeof row?.name === 'string' && row.name.length > 0)
|
|
1613
1647
|
name = row.name;
|
|
1614
1648
|
}
|
|
@@ -1631,10 +1665,11 @@ function v1Bit(stamp) {
|
|
|
1631
1665
|
const SUSPENDED_ASK_ARGS_NOTE = "this request's tool arguments are not available on this surface — it was raised while no client was connected, " +
|
|
1632
1666
|
'so you are deciding without seeing them; deny it if you are not sure what it will do. ' +
|
|
1633
1667
|
'Edits are not accepted on this card: there is no original input to edit';
|
|
1634
|
-
function cardFactsOf(carrier, leg, opts, liveFacts) {
|
|
1668
|
+
function cardFactsOf(carrier, leg, opts, liveFacts, approvalId) {
|
|
1635
1669
|
const c = carrier;
|
|
1636
1670
|
const full = leg !== 'generic';
|
|
1637
1671
|
const live = leg === 'frame' ? carrier : leg === 'v1' ? liveFacts : undefined;
|
|
1672
|
+
let face;
|
|
1638
1673
|
const asFrame = carrier;
|
|
1639
1674
|
const fromSubagent = full
|
|
1640
1675
|
? (() => {
|
|
@@ -1747,15 +1782,11 @@ function cardFactsOf(carrier, leg, opts, liveFacts) {
|
|
|
1747
1782
|
realApprovalUnreadable = true;
|
|
1748
1783
|
}
|
|
1749
1784
|
if (live !== undefined) {
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
const w = readApprovalMandate(live);
|
|
1756
|
-
if (w !== undefined)
|
|
1757
|
-
out.mandate = w;
|
|
1758
|
-
});
|
|
1785
|
+
face = approvalLiveFaceOf(live);
|
|
1786
|
+
if (face.facts.mandated === true)
|
|
1787
|
+
out.mandated = true;
|
|
1788
|
+
if (face.facts.mandate !== undefined)
|
|
1789
|
+
out.mandate = face.facts.mandate;
|
|
1759
1790
|
v1Bit(() => {
|
|
1760
1791
|
const rc = readReadRootCandidate(live.readRootCandidate);
|
|
1761
1792
|
if (rc !== undefined)
|
|
@@ -1777,13 +1808,8 @@ function cardFactsOf(carrier, leg, opts, liveFacts) {
|
|
|
1777
1808
|
if (dlf !== undefined)
|
|
1778
1809
|
out.denialLimitFallback = dlf;
|
|
1779
1810
|
});
|
|
1780
|
-
if (
|
|
1781
|
-
|
|
1782
|
-
const o = readAskOrigin(live);
|
|
1783
|
-
if (o !== undefined)
|
|
1784
|
-
out.origin = o;
|
|
1785
|
-
});
|
|
1786
|
-
}
|
|
1811
|
+
if (face !== undefined && face.facts.origin !== undefined)
|
|
1812
|
+
out.origin = face.facts.origin;
|
|
1787
1813
|
if (leg !== 'generic') {
|
|
1788
1814
|
v1Bit(() => {
|
|
1789
1815
|
const w = readApprovalCardWord(carrier);
|
|
@@ -1817,16 +1843,32 @@ function cardFactsOf(carrier, leg, opts, liveFacts) {
|
|
|
1817
1843
|
});
|
|
1818
1844
|
if (leg === 'generic')
|
|
1819
1845
|
out.cardPayloadUnreadable = true;
|
|
1820
|
-
if (leg
|
|
1846
|
+
if (sessionAllowCarried(leg, approvalId))
|
|
1821
1847
|
out.allowSessionCarried = true;
|
|
1822
1848
|
out.grantBinding = readApprovalGrantBinding(carrier);
|
|
1823
|
-
|
|
1849
|
+
const reported = realApprovalUnreadable ? ['requiresRealApproval'] : [];
|
|
1850
|
+
if (face?.layerUnknown === 'marked' || (leg === 'v1' && face?.layerUnknown === 'absent'))
|
|
1851
|
+
reported.push(...APPROVAL_LIVE_FACE_KEYS);
|
|
1852
|
+
return withUnreadableEvidence(carrier, leg, out, reported, live);
|
|
1824
1853
|
}
|
|
1825
1854
|
export function approvalCardFactsOfV1(card) {
|
|
1826
1855
|
if (typeof card !== 'object' || card === null)
|
|
1827
1856
|
return undefined;
|
|
1828
1857
|
return Object.freeze(cardFactsOf(card, 'v1'));
|
|
1829
1858
|
}
|
|
1859
|
+
export function approvalCardFactsOfV1Frame(frame) {
|
|
1860
|
+
if (typeof frame !== 'object' || frame === null)
|
|
1861
|
+
return undefined;
|
|
1862
|
+
try {
|
|
1863
|
+
const carriers = openingFrameCarriersOf(frame);
|
|
1864
|
+
if (carriers.leg !== 'v1')
|
|
1865
|
+
return undefined;
|
|
1866
|
+
return Object.freeze(cardFactsOf(carriers.body, 'v1', null, carriers.live, ownDataValue(frame, 'approvalId')));
|
|
1867
|
+
}
|
|
1868
|
+
catch {
|
|
1869
|
+
return undefined;
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1830
1872
|
export function approvalCardFactsOfFrame(frame, opts) {
|
|
1831
1873
|
if (typeof frame !== 'object' || frame === null)
|
|
1832
1874
|
return undefined;
|
|
@@ -1888,7 +1930,7 @@ function liveCardIdentityOf(approvalId, frame, carriers, run) {
|
|
|
1888
1930
|
const fromSubagent = isFromSubagent(carriers.body);
|
|
1889
1931
|
const bound = fromSubagent ? undefined : frameBindingOf(frame);
|
|
1890
1932
|
const source = bound ?? run;
|
|
1891
|
-
const ownRun = fromSubagent ? body
|
|
1933
|
+
const ownRun = fromSubagent ? subagentSourceSessionOf(carriers.body) : source?.taskId;
|
|
1892
1934
|
const taskId = typeof ownRun === 'string' && ownRun !== '' ? ownRun : undefined;
|
|
1893
1935
|
const sessionId = !fromSubagent && typeof source?.sessionId === 'string' && source.sessionId !== '' ? source.sessionId : undefined;
|
|
1894
1936
|
const askSig = carrierAskSig(carriers.body, carriers.live);
|
|
@@ -1950,7 +1992,7 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
1950
1992
|
const bodyToolCallId = carriers.body.toolCallId;
|
|
1951
1993
|
const frameToolCallId = typeof bodyToolCallId === 'string' && bodyToolCallId !== '' ? bodyToolCallId : undefined;
|
|
1952
1994
|
const decidedByReading = decidedByReadingSnapshotOf(lane);
|
|
1953
|
-
const facts = cardFactsOf(carriers.body, carriers.leg, { streamArgs, ...(lane?.argsUnavailable === true ? { argsUnavailable: true } : {}) }, carriers.live);
|
|
1995
|
+
const facts = cardFactsOf(carriers.body, carriers.leg, { streamArgs, ...(lane?.argsUnavailable === true ? { argsUnavailable: true } : {}) }, carriers.live, approvalId);
|
|
1954
1996
|
const argsNotRealInput = facts.argsUnavailable === true;
|
|
1955
1997
|
const ruleOffers = facts.ruleOffers;
|
|
1956
1998
|
if (argsNotRealInput && lane?.argsUnavailable !== true && facts.wireNote !== undefined) {
|
|
@@ -2,7 +2,7 @@ import { SETTINGS_WORKSPACE_TRUST_STATES } from './generated/settingsSchemaTable
|
|
|
2
2
|
import type { ManagedPolicyState, PluginHooksReading, SessionHooksReading, SettingsDocument } from './host.js';
|
|
3
3
|
import type { PluginHookReaderState } from './pluginHooksWire.js';
|
|
4
4
|
export type WorkspaceTrustState = (typeof SETTINGS_WORKSPACE_TRUST_STATES)[number];
|
|
5
|
-
export declare const HOST_SETTINGS_LAYERS: readonly ["policySettings", "userSettings", "projectSettings", "localSettings", "flagSettings"];
|
|
5
|
+
export declare const HOST_SETTINGS_LAYERS: readonly ["policySettings", "userSettings", "projectSettings", "localSettings", "flagSettings", "foreignProjectSettings"];
|
|
6
6
|
export type HostSettingsLayer = (typeof HOST_SETTINGS_LAYERS)[number];
|
|
7
7
|
export declare const MANAGED_POLICY_STATES: readonly ["absent", "in-effect", "in-effect-pieces", "unreadable-covered", "unreadable-uncovered", "remote-unknown"];
|
|
8
8
|
export declare const HOST_STARTUP_MODES: readonly ["safe", "bare", "none"];
|
|
@@ -71,6 +71,8 @@ export declare function sourceOfRead(read: HostSettingsRead): HostSettingsSource
|
|
|
71
71
|
export declare function settingsValueOf(read: HostSettingsRead, key: string): {} | null | undefined;
|
|
72
72
|
export declare function mergedBooleanOf(read: HostSettingsRead, key: string): boolean | undefined;
|
|
73
73
|
export declare const CC_MERGE_ORDER: readonly ["userSettings", "projectSettings", "localSettings", "flagSettings", "policySettings"];
|
|
74
|
+
export type TightenOnlyHostSettingsLayer = Exclude<HostSettingsLayer, (typeof CC_MERGE_ORDER)[number]>;
|
|
75
|
+
export declare const TIGHTEN_ONLY_HOST_SETTINGS_LAYERS: readonly TightenOnlyHostSettingsLayer[];
|
|
74
76
|
export declare function nonManagedLayerDown(read: HostSettingsRead): boolean;
|
|
75
77
|
export declare const ADOPTED_LAYERS: readonly ["userSettings", "projectSettings", "localSettings", "flagSettings"];
|
|
76
78
|
export type AdoptedLayer = (typeof ADOPTED_LAYERS)[number];
|
|
@@ -102,6 +104,7 @@ export declare function hostSettingsSessionFollows(stored: HostSettingsSession |
|
|
|
102
104
|
export declare const FIRST_SESSION: HostSettingsSession;
|
|
103
105
|
export declare function sessionSnapshotOf(previous: {} | null | undefined): HostSettingsSession | undefined;
|
|
104
106
|
export declare function permissionRulesOf(doc: SettingsDocument | null, bucket: 'allow' | 'deny' | 'ask'): readonly string[];
|
|
107
|
+
export declare function permissionBucketOf(doc: SettingsDocument | null, bucket: 'allow' | 'deny' | 'ask'): readonly string[] | undefined;
|
|
105
108
|
export interface HostSettingsAdoption {
|
|
106
109
|
readonly read: HostSettingsRead;
|
|
107
110
|
readonly session: HostSettingsSession;
|
|
@@ -2,7 +2,7 @@ import { appendOwnElement } from './ownKey.js';
|
|
|
2
2
|
import { SETTINGS_WORKSPACE_TRUST_STATES } from './generated/settingsSchemaTables.js';
|
|
3
3
|
import { jsonFaithfulCost, materializeJsonFaithful } from './jsonFaithful.js';
|
|
4
4
|
import { faultText } from './hostCallbackGuard.js';
|
|
5
|
-
export const HOST_SETTINGS_LAYERS = Object.freeze(['policySettings', 'userSettings', 'projectSettings', 'localSettings', 'flagSettings']);
|
|
5
|
+
export const HOST_SETTINGS_LAYERS = Object.freeze(['policySettings', 'userSettings', 'projectSettings', 'localSettings', 'flagSettings', 'foreignProjectSettings']);
|
|
6
6
|
export const MANAGED_POLICY_STATES = Object.freeze(['absent', 'in-effect', 'in-effect-pieces', 'unreadable-covered', 'unreadable-uncovered', 'remote-unknown']);
|
|
7
7
|
export const HOST_STARTUP_MODES = Object.freeze(['safe', 'bare', 'none']);
|
|
8
8
|
export const HOST_SETTINGS_CARRIER_STATUSES = Object.freeze(['loaded', 'loaded-partial', 'empty', 'absent', 'unreadable', 'not-loaded']);
|
|
@@ -394,8 +394,9 @@ export function mergedBooleanOf(read, key) {
|
|
|
394
394
|
return out;
|
|
395
395
|
}
|
|
396
396
|
export const CC_MERGE_ORDER = Object.freeze(['userSettings', 'projectSettings', 'localSettings', 'flagSettings', 'policySettings']);
|
|
397
|
+
export const TIGHTEN_ONLY_HOST_SETTINGS_LAYERS = Object.freeze(HOST_SETTINGS_LAYERS.filter((l) => !CC_MERGE_ORDER.includes(l)));
|
|
397
398
|
export function nonManagedLayerDown(read) {
|
|
398
|
-
return
|
|
399
|
+
return CC_MERGE_ORDER.some((l) => {
|
|
399
400
|
if (l === 'policySettings')
|
|
400
401
|
return false;
|
|
401
402
|
const snap = read.layers[l];
|
|
@@ -403,6 +404,7 @@ export function nonManagedLayerDown(read) {
|
|
|
403
404
|
});
|
|
404
405
|
}
|
|
405
406
|
export const ADOPTED_LAYERS = Object.freeze(['userSettings', 'projectSettings', 'localSettings', 'flagSettings']);
|
|
407
|
+
const isAdoptedLayer = (l) => ADOPTED_LAYERS.includes(l);
|
|
406
408
|
const GENESIS_VERSION = '0';
|
|
407
409
|
export const parentVersionOf = (session) => (session.version === GENESIS_VERSION ? null : session.version);
|
|
408
410
|
function canonicalOf(v) {
|
|
@@ -512,13 +514,16 @@ export function sessionSnapshotOf(previous) {
|
|
|
512
514
|
}
|
|
513
515
|
const LOADED = new Set(['loaded', 'loaded-partial']);
|
|
514
516
|
export function permissionRulesOf(doc, bucket) {
|
|
517
|
+
return permissionBucketOf(doc, bucket) ?? [];
|
|
518
|
+
}
|
|
519
|
+
export function permissionBucketOf(doc, bucket) {
|
|
515
520
|
if (doc === null)
|
|
516
|
-
return
|
|
521
|
+
return undefined;
|
|
517
522
|
const p = ownData(doc, 'permissions');
|
|
518
523
|
if (!p.ok || !isRecord(p.value))
|
|
519
|
-
return
|
|
524
|
+
return undefined;
|
|
520
525
|
const b = ownData(p.value, bucket);
|
|
521
|
-
return b.ok && Array.isArray(b.value) ? b.value.filter((x) => typeof x === 'string') :
|
|
526
|
+
return b.ok && Array.isArray(b.value) ? b.value.filter((x) => typeof x === 'string') : undefined;
|
|
522
527
|
}
|
|
523
528
|
function overflowOf(read, session) {
|
|
524
529
|
return Object.freeze({ read, session: remintSameContent(session), trusted: false, clean: false, extraTighten: NO_EXTRA, allowByLayer: emptyByLayer(), overflow: true });
|
|
@@ -624,7 +629,7 @@ export function adoptHostSettingsRead(read, session, allowAdmitted = () => true,
|
|
|
624
629
|
const effectiveLayers = {};
|
|
625
630
|
for (const l of HOST_SETTINGS_LAYERS) {
|
|
626
631
|
const snap = read.layers[l];
|
|
627
|
-
effectiveLayers[l] = l
|
|
632
|
+
effectiveLayers[l] = isAdoptedLayer(l) ? Object.freeze({ ...snap, doc: base.docs[l] }) : snap;
|
|
628
633
|
}
|
|
629
634
|
const effective = Object.freeze({ ...read, layers: Object.freeze(effectiveLayers), current: read, debug: Object.freeze([]) });
|
|
630
635
|
const idOf = (layer, rule) => (layeredRules ? JSON.stringify([layer, rule]) : rule);
|
|
@@ -3,8 +3,8 @@ import type { WireHooksConfig } from './finalVerifyWire.js';
|
|
|
3
3
|
import type { memoryOffDeclared as MemoryOffDeclared } from './request/taskRequest.js';
|
|
4
4
|
import type { EnvLike } from './hostEnv.js';
|
|
5
5
|
import { type SettingsDocument } from './host.js';
|
|
6
|
-
import type {
|
|
7
|
-
import { type HostSettingsSession, type HostSettingsSource } from './hostSettingsSource.js';
|
|
6
|
+
import type { HooksWirePlan, HooksWirePlanOptions } from './pluginHooksWire.js';
|
|
7
|
+
import { type HostSettingsLayer, type HostSettingsSession, type HostSettingsSource } from './hostSettingsSource.js';
|
|
8
8
|
import { type SubmissionIdentity } from './request/submissionIdentity.js';
|
|
9
9
|
import { type WebSearchApiKeyFor } from './webSearchWireCaps.js';
|
|
10
10
|
import { type FileHistoryCaptureReading } from './fileHistoryCaptureCapability.js';
|
|
@@ -16,12 +16,12 @@ export type HostSettingCause = (typeof HOST_SETTING_CAUSES)[number];
|
|
|
16
16
|
export declare const HOST_SETTING_DISPOSITIONS: readonly ["carry", "carry_partial", "withhold_notice", "withhold_by_policy", "hold_for_consent", "refuse_turn", "unwired", "nothing_to_carry"];
|
|
17
17
|
export type HostSettingDisposition = (typeof HOST_SETTING_DISPOSITIONS)[number];
|
|
18
18
|
export type HostSettingPlane = 'turn' | 'session' | 'diagnostic';
|
|
19
|
-
export type HostSettingNoticeId = 'HS-UNWIRED' | 'HS-MANAGED-REJECTED' | 'HS-PROJECTION' | 'HS-SOURCE-UNREADABLE' | 'HS-WEBSEARCH-MALFORMED' | 'HS-SWITCH-MALFORMED' | 'HS-FILEHISTORY-UNJUDGED' | 'HS-FILEHISTORY-RESTORE' | 'HS-MANAGED-UNREADABLE' | 'HS-LAYER-NOT-LOADED' | 'HS-HELD-PREVIOUS' | 'HS-STYLE-MISSING' | 'HS-STYLE-SAFE';
|
|
19
|
+
export type HostSettingNoticeId = 'HS-UNWIRED' | 'HS-MANAGED-REJECTED' | 'HS-PROJECTION' | 'HS-SOURCE-UNREADABLE' | 'HS-WEBSEARCH-MALFORMED' | 'HS-SWITCH-MALFORMED' | 'HS-FILEHISTORY-UNJUDGED' | 'HS-FILEHISTORY-RESTORE' | 'HS-MANAGED-UNREADABLE' | 'HS-LAYER-NOT-LOADED' | 'HS-HELD-PREVIOUS' | 'HS-STYLE-MISSING' | 'HS-STYLE-SAFE' | 'HS-LAYER-PARTS-UNREAD';
|
|
20
20
|
export interface HostSettingRow {
|
|
21
21
|
readonly key: HostSuppliedKey;
|
|
22
22
|
readonly cause: HostSettingCause;
|
|
23
23
|
readonly disposition: HostSettingDisposition;
|
|
24
|
-
readonly layers?: readonly
|
|
24
|
+
readonly layers?: readonly HostSettingsLayer[];
|
|
25
25
|
}
|
|
26
26
|
export interface HostSettingNotice {
|
|
27
27
|
readonly id: HostSettingNoticeId;
|
|
@@ -123,7 +123,6 @@ export interface HostPermissionFacts {
|
|
|
123
123
|
readonly ask?: readonly string[];
|
|
124
124
|
};
|
|
125
125
|
readonly clientOwnedServers?: readonly string[];
|
|
126
|
-
readonly serverVersion?: string;
|
|
127
126
|
}
|
|
128
127
|
export declare function rethrowHostResolvedDeferred(product: HostTurnSettings): void;
|
|
129
128
|
export type HostResolvedMaterializer = (snapshot: SettingsDocument) => SettingsDocument;
|
package/dist/hostTurnSettings.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SETTINGS_CLASSIFY_HOOKS_CONFIG } from './generated/settingsSchemaFns.js';
|
|
2
2
|
import { hostLog } from './host.js';
|
|
3
3
|
import { layerNotAppliedRefusesTurn, salvageSettingsHooksEntries } from './settingsHooksSalvage.js';
|
|
4
|
-
import { ADOPTED_LAYERS, HOST_SETTINGS_LAYERS, HostSettingsSourceShapeError, permissionRulesOf, MANAGED_READING_DISPOSITIONS, adoptHostSettingsRead, mintHostSettingsSession, readHostSettingsOnce, remintSameContent, sessionSnapshotOf, settingsValueOf, sourceOfRead, } from './hostSettingsSource.js';
|
|
4
|
+
import { ADOPTED_LAYERS, HOST_SETTINGS_LAYERS, HostSettingsSourceShapeError, TIGHTEN_ONLY_HOST_SETTINGS_LAYERS, permissionBucketOf, permissionRulesOf, MANAGED_READING_DISPOSITIONS, adoptHostSettingsRead, mintHostSettingsSession, readHostSettingsOnce, remintSameContent, sessionSnapshotOf, settingsValueOf, sourceOfRead, } from './hostSettingsSource.js';
|
|
5
5
|
import { hooksWirePlan } from './hooksWireCaps.js';
|
|
6
6
|
import { submissionSurfaceOf } from './request/submissionIdentity.js';
|
|
7
7
|
import { displayUntrusted } from './displayUntrusted.js';
|
|
@@ -11,7 +11,8 @@ import { msg, renderMessage } from './i18n/translate.js';
|
|
|
11
11
|
import { newRulePortsProjection, projectPermissionsDeclaration, rulePortsMissingOf, WIRE_RULE_TRUST_ORDER } from './permissionsDeclaration.js';
|
|
12
12
|
import { assemblyRefusalOf } from './wireFailureShape.js';
|
|
13
13
|
import { permissionRuleLayersOn } from './permissionsAllowGrantCapability.js';
|
|
14
|
-
import { layerAdmitted } from './settingsLayerAdmission.js';
|
|
14
|
+
import { layerAdmissionReading, layerAdmitted } from './settingsLayerAdmission.js';
|
|
15
|
+
import { SETTINGS_BUILD_LAYER_PARTS_UNREAD_NOTICE } from './generated/settingsSchemaFns.js';
|
|
15
16
|
import { appendOwnElement, ownDataField } from './ownKey.js';
|
|
16
17
|
export const HOST_SUPPLIED_KEYS = Object.freeze(['settings.hooks', 'settings.resolved', 'settings.webSearch', 'settings.outputStyle', 'memory', 'fileHistory']);
|
|
17
18
|
export const HOST_SETTING_CAUSES = Object.freeze([
|
|
@@ -42,6 +43,7 @@ const HOST_SETTING_NOTICE_TEXT = {
|
|
|
42
43
|
'HS-HELD-PREVIOUS': () => renderMessage(msg('session.hostSettings.heldPrevious')),
|
|
43
44
|
'HS-STYLE-MISSING': (what) => renderMessage(msg('session.hostSettings.styleMissing', { name: what })),
|
|
44
45
|
'HS-STYLE-SAFE': () => renderMessage(msg('session.hostSettings.styleSafeMode')),
|
|
46
|
+
'HS-LAYER-PARTS-UNREAD': (line) => line,
|
|
45
47
|
};
|
|
46
48
|
const KEY_NOUN = {
|
|
47
49
|
'settings.hooks': 'the hooks',
|
|
@@ -367,10 +369,60 @@ function stringListOf(v) {
|
|
|
367
369
|
function permissionMemberAdmitted(layer, read, bucket) {
|
|
368
370
|
return layerAdmitted(layer, read.trust, 'permissions', bucket);
|
|
369
371
|
}
|
|
372
|
+
function managedRulesOnly(read) {
|
|
373
|
+
const policyDoc = read.layers.policySettings.doc;
|
|
374
|
+
return MANAGED_READING_DISPOSITIONS[read.managed].ruleScope === 'by-switch' && policyDoc !== null && managedOnlySwitchOn(policyDoc);
|
|
375
|
+
}
|
|
376
|
+
const TIGHTEN_ONLY_LAYER_BUCKETS = Object.freeze(['deny', 'ask']);
|
|
377
|
+
function tightenOnlyBucketsRead(read, layer) {
|
|
378
|
+
if (managedRulesOnly(read))
|
|
379
|
+
return [];
|
|
380
|
+
const doc = read.layers[layer].doc;
|
|
381
|
+
return TIGHTEN_ONLY_LAYER_BUCKETS.filter((bucket) => permissionMemberAdmitted(layer, read, bucket) && permissionBucketOf(doc, bucket) !== undefined);
|
|
382
|
+
}
|
|
383
|
+
function tightenOnlyLayerPartsUnread(read, layer, permissionsRead) {
|
|
384
|
+
const doc = read.layers[layer].doc;
|
|
385
|
+
if (doc === null)
|
|
386
|
+
return [];
|
|
387
|
+
const readBuckets = permissionsRead ? tightenOnlyBucketsRead(read, layer) : [];
|
|
388
|
+
const parts = [];
|
|
389
|
+
const rec = doc;
|
|
390
|
+
for (const key of Object.keys(rec)) {
|
|
391
|
+
const v = rec[key];
|
|
392
|
+
if (key !== 'permissions')
|
|
393
|
+
appendOwnElement(parts, key);
|
|
394
|
+
else if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
395
|
+
appendOwnElement(parts, key);
|
|
396
|
+
else
|
|
397
|
+
for (const member of Object.keys(v))
|
|
398
|
+
if (!readBuckets.includes(member))
|
|
399
|
+
appendOwnElement(parts, `${key}.${member}`);
|
|
400
|
+
}
|
|
401
|
+
for (const c of read.layers[layer].carriers)
|
|
402
|
+
if (c.status === 'loaded-partial')
|
|
403
|
+
for (const k of c.issues ?? [])
|
|
404
|
+
if (!parts.includes(k))
|
|
405
|
+
appendOwnElement(parts, k);
|
|
406
|
+
return parts;
|
|
407
|
+
}
|
|
408
|
+
function tightenOnlyLayerNotices(read, permissionsRead) {
|
|
409
|
+
const out = [];
|
|
410
|
+
for (const layer of TIGHTEN_ONLY_HOST_SETTINGS_LAYERS) {
|
|
411
|
+
const snap = read.layers[layer];
|
|
412
|
+
if (!snap.enabled || snap.doc === null)
|
|
413
|
+
continue;
|
|
414
|
+
const parts = tightenOnlyLayerPartsUnread(read, layer, permissionsRead);
|
|
415
|
+
const loaded = snap.carriers.filter((c) => c.status === 'loaded' || c.status === 'loaded-partial').map((c) => c.id);
|
|
416
|
+
const file = (loaded.length > 0 ? loaded : snap.carriers.map((c) => c.id)).join(', ');
|
|
417
|
+
const n = SETTINGS_BUILD_LAYER_PARTS_UNREAD_NOTICE({ source: layer, workspace: layerAdmissionReading(read.trust), file, parts });
|
|
418
|
+
if (n !== undefined)
|
|
419
|
+
appendOwnElement(out, notice('HS-LAYER-PARTS-UNREAD', 'session', displayUntrusted(n.line)));
|
|
420
|
+
}
|
|
421
|
+
return out;
|
|
422
|
+
}
|
|
370
423
|
function allowAdmittedFor(read) {
|
|
371
424
|
const disp = MANAGED_READING_DISPOSITIONS[read.managed];
|
|
372
|
-
const
|
|
373
|
-
const managedOnlySwitch = disp.ruleScope === 'by-switch' && policyDoc !== null && managedOnlySwitchOn(policyDoc);
|
|
425
|
+
const managedOnlySwitch = managedRulesOnly(read);
|
|
374
426
|
const degrade = disp.ruleScope === 'degrade';
|
|
375
427
|
return (layer) => {
|
|
376
428
|
if (degrade || managedOnlySwitch)
|
|
@@ -387,7 +439,7 @@ function allowAdmittedFor(read) {
|
|
|
387
439
|
};
|
|
388
440
|
}
|
|
389
441
|
function badPermissionsSource() {
|
|
390
|
-
return new HostSourceShapeError(`hostTurnSettings: sources.resolved must be 'none' or { allowGrantReading, cliArg?, session?, clientOwnedServers
|
|
442
|
+
return new HostSourceShapeError(`hostTurnSettings: sources.resolved must be 'none' or { allowGrantReading, cliArg?, session?, clientOwnedServers? } — since 0.101.0 the permission rules of the settings files come from the settings the entry reads; do not pass snapshot — got something else (the value is not echoed).`);
|
|
391
443
|
}
|
|
392
444
|
function readPermissionSource(src) {
|
|
393
445
|
const key = 'settings.resolved';
|
|
@@ -405,12 +457,9 @@ function readPermissionSource(src) {
|
|
|
405
457
|
let sesAsk;
|
|
406
458
|
let owned;
|
|
407
459
|
let ownedRaw;
|
|
408
|
-
let serverVersion;
|
|
409
460
|
try {
|
|
410
461
|
if (!isRecordShape(v) || Object.hasOwn(v, 'snapshot') || !Object.hasOwn(v, 'allowGrantReading'))
|
|
411
462
|
throw badPermissionsSource();
|
|
412
|
-
const sver = ownDataOf(v, 'serverVersion');
|
|
413
|
-
serverVersion = sver.ok && typeof sver.value === 'string' ? sver.value : undefined;
|
|
414
463
|
const g = ownDataOf(v, 'allowGrantReading');
|
|
415
464
|
const c = ownDataOf(v, 'cliArg');
|
|
416
465
|
const se = ownDataOf(v, 'session');
|
|
@@ -444,13 +493,13 @@ function readPermissionSource(src) {
|
|
|
444
493
|
}
|
|
445
494
|
if (cliAllow === undefined || cliDeny === undefined || sesDeny === undefined || sesAsk === undefined || (owned === undefined && ownedRaw !== undefined))
|
|
446
495
|
throw badPermissionsSource();
|
|
447
|
-
return { kind: 'facts', allowGrantReading, cliAllow, cliDeny, sesDeny, sesAsk, owned
|
|
496
|
+
return { kind: 'facts', allowGrantReading, cliAllow, cliDeny, sesDeny, sesAsk, owned };
|
|
448
497
|
}
|
|
449
498
|
function permissionsArm(facts, side, adoption, layered) {
|
|
450
499
|
const key = 'settings.resolved';
|
|
451
500
|
if (facts.kind === 'arm')
|
|
452
501
|
return facts.arm;
|
|
453
|
-
const { allowGrantReading, cliAllow, cliDeny, sesDeny, sesAsk, owned
|
|
502
|
+
const { allowGrantReading, cliAllow, cliDeny, sesDeny, sesAsk, owned } = facts;
|
|
454
503
|
if (side.kind === 'missing')
|
|
455
504
|
return missingArm(key);
|
|
456
505
|
const buckets = { deny: [], ask: [], allow: [] };
|
|
@@ -482,7 +531,7 @@ function permissionsArm(facts, side, adoption, layered) {
|
|
|
482
531
|
const read = side.read;
|
|
483
532
|
const disp = MANAGED_READING_DISPOSITIONS[read.managed];
|
|
484
533
|
const policyDoc = read.layers.policySettings.doc;
|
|
485
|
-
const managedOnlySwitch =
|
|
534
|
+
const managedOnlySwitch = managedRulesOnly(read);
|
|
486
535
|
const degrade = disp.ruleScope === 'degrade';
|
|
487
536
|
try {
|
|
488
537
|
for (const bucket of Object.keys(buckets)) {
|
|
@@ -506,6 +555,10 @@ function permissionsArm(facts, side, adoption, layered) {
|
|
|
506
555
|
for (const r of adoption?.extraTighten[bucket] ?? [])
|
|
507
556
|
if (permissionMemberAdmitted(r.layer, read, bucket))
|
|
508
557
|
add(bucket, r.rule, r.layer);
|
|
558
|
+
for (const l of TIGHTEN_ONLY_HOST_SETTINGS_LAYERS)
|
|
559
|
+
for (const bucket of tightenOnlyBucketsRead(read, l))
|
|
560
|
+
for (const r of permissionRulesOf(read.layers[l].doc, bucket))
|
|
561
|
+
add(bucket, r, l);
|
|
509
562
|
}
|
|
510
563
|
}
|
|
511
564
|
catch (error) {
|
|
@@ -521,7 +574,7 @@ function permissionsArm(facts, side, adoption, layered) {
|
|
|
521
574
|
let declared;
|
|
522
575
|
if (projectionError === undefined) {
|
|
523
576
|
try {
|
|
524
|
-
const d = projectPermissionsDeclaration({ deny: buckets.deny, ask: buckets.ask, allow: buckets.allow, origins, cliDeny, settingsRead: 'clean', ...(owned !== undefined && owned.length > 0 ? { clientOwnedServers: owned } : {})
|
|
577
|
+
const d = projectPermissionsDeclaration({ deny: buckets.deny, ask: buckets.ask, allow: buckets.allow, origins, cliDeny, settingsRead: 'clean', ...(owned !== undefined && owned.length > 0 ? { clientOwnedServers: owned } : {}) }, allowGrantReading, portsProjection, layered ? freeze({ deny: freeze([...contributions.deny]), ask: freeze([...contributions.ask]) }) : undefined);
|
|
525
578
|
declared = d.permissions !== undefined ? { permissions: d.permissions } : undefined;
|
|
526
579
|
}
|
|
527
580
|
catch (error) {
|
|
@@ -584,8 +637,11 @@ function notLoadedLayers(read, plan) {
|
|
|
584
637
|
}
|
|
585
638
|
return out;
|
|
586
639
|
}
|
|
640
|
+
const isTightenOnlyLayer = (l) => TIGHTEN_ONLY_HOST_SETTINGS_LAYERS.includes(l);
|
|
587
641
|
function notLoadedSentence(n, form) {
|
|
588
642
|
const layer = msg(`session.hostSettings.layer.${n.layer}`);
|
|
643
|
+
if (isTightenOnlyLayer(n.layer))
|
|
644
|
+
return renderMessage(msg(form === 'hold' ? 'session.hostSettings.layerNotLoaded.restrictions.hold' : 'session.hostSettings.layerNotLoaded.restrictions.sent', { layer }));
|
|
589
645
|
return renderMessage(msg(form === 'hold' ? `session.hostSettings.layerNotLoaded.hold.${n.how}` : 'session.hostSettings.layerNotLoaded.sent.unreadable', { layer }));
|
|
590
646
|
}
|
|
591
647
|
function settingsSideOf(input) {
|
|
@@ -679,17 +735,19 @@ export function buildHostTurnSettings(input, judges) {
|
|
|
679
735
|
if (notLoaded.length > 0) {
|
|
680
736
|
const key = `hs1-${fnv1a(JSON.stringify(notLoaded.map((n) => n.key)))}`;
|
|
681
737
|
const ask = surface === 'interactive' && !session.consented.includes(key);
|
|
682
|
-
const
|
|
683
|
-
const cause = notLoaded.some((n) => n.how === 'unreadable') ? 'source_unreadable' : 'source_rejected';
|
|
684
|
-
const reshape = (a) => {
|
|
738
|
+
const reshape = (a, feeds) => {
|
|
685
739
|
const d = a.row.disposition;
|
|
686
740
|
if (d === 'refuse_turn' || d === 'unwired' || a.row.cause === 'no_source')
|
|
687
741
|
return a;
|
|
742
|
+
const mine = notLoaded.filter((n) => feeds(n.layer));
|
|
743
|
+
if (mine.length === 0)
|
|
744
|
+
return a;
|
|
745
|
+
const cause = mine.some((n) => n.how === 'unreadable') ? 'source_unreadable' : 'source_rejected';
|
|
688
746
|
const disposition = ask ? 'hold_for_consent' : a.carried !== undefined ? 'carry_partial' : 'withhold_notice';
|
|
689
|
-
return { ...a, row: freeze({ key: a.row.key, cause, disposition, layers }) };
|
|
747
|
+
return { ...a, row: freeze({ key: a.row.key, cause, disposition, layers: freeze(mine.map((n) => n.layer)) }) };
|
|
690
748
|
};
|
|
691
749
|
const before = armsByKey;
|
|
692
|
-
armsByKey = [{ ...reshape(before[0]), ...(hooks.plan !== undefined ? { plan: hooks.plan } : {}) }, reshape(before[1]), before[2], before[3], before[4], before[5]];
|
|
750
|
+
armsByKey = [{ ...reshape(before[0], (l) => !isTightenOnlyLayer(l)), ...(hooks.plan !== undefined ? { plan: hooks.plan } : {}) }, reshape(before[1], () => true), before[2], before[3], before[4], before[5]];
|
|
693
751
|
if (ask && armsByKey.slice(0, 2).some((a) => a.row.disposition === 'hold_for_consent'))
|
|
694
752
|
consentKey = key;
|
|
695
753
|
for (const n of notLoaded) {
|
|
@@ -709,7 +767,11 @@ export function buildHostTurnSettings(input, judges) {
|
|
|
709
767
|
}
|
|
710
768
|
const arms = armsByKey;
|
|
711
769
|
const rows = freeze(arms.map((a) => a.row));
|
|
712
|
-
const
|
|
770
|
+
const resolvedOut = arms[1]?.row.disposition === 'carry' || arms[1]?.row.disposition === 'carry_partial' || arms[1]?.row.disposition === 'hold_for_consent' ? resolvedCarried : undefined;
|
|
771
|
+
const permissionsRow = arms[1]?.row;
|
|
772
|
+
const permissionsRead = permissionsRow !== undefined && permissionsRow.disposition !== 'refuse_turn' && permissionsRow.disposition !== 'unwired' && permissionsRow.cause !== 'no_source';
|
|
773
|
+
const partsNotices = side.kind === 'read' ? tightenOnlyLayerNotices(side.read, permissionsRead) : [];
|
|
774
|
+
const notices = freeze([...arms.flatMap((a) => a.notices), ...notLoadedNotices, ...heldNotices, ...partsNotices]);
|
|
713
775
|
const refusal = arms.find((a) => a.row.disposition === 'refuse_turn');
|
|
714
776
|
const verdict = refusal !== undefined
|
|
715
777
|
? freeze({ kind: 'refuse', notice: refusal.notices[0] ?? notices.find((n) => n.plane === 'turn') ?? notice('HS-PROJECTION', 'turn') })
|
|
@@ -721,7 +783,6 @@ export function buildHostTurnSettings(input, judges) {
|
|
|
721
783
|
return a.row.disposition === 'carry' || a.row.disposition === 'carry_partial' || a.row.disposition === 'hold_for_consent' ? a.carried : undefined;
|
|
722
784
|
};
|
|
723
785
|
const hooksCarried = carriedOf(0);
|
|
724
|
-
const resolvedOut = arms[1]?.row.disposition === 'carry' || arms[1]?.row.disposition === 'carry_partial' || arms[1]?.row.disposition === 'hold_for_consent' ? resolvedCarried : undefined;
|
|
725
786
|
const carried = freeze({
|
|
726
787
|
...(hooksCarried !== undefined ? { hooks: hooksCarried } : {}),
|
|
727
788
|
...(resolvedOut !== undefined ? { resolved: resolvedOut } : {}),
|