@sema-agent/client-core 0.100.0 → 0.102.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 +452 -0
- package/README.md +172 -120
- package/dist/adapt/arms.js +51 -16
- package/dist/adapt/textStream.js +7 -4
- package/dist/adapt/toolCards.d.ts +2 -1
- package/dist/adapt/toolCards.js +28 -13
- package/dist/adapt.d.ts +1 -1
- package/dist/adapt.js +8 -2
- package/dist/adapter/activeRunSelfHeal.d.ts +24 -2
- package/dist/adapter/activeRunSelfHeal.js +108 -6
- package/dist/adapter/downstream/eventToSdkMessage.js +38 -79
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +60 -1
- package/dist/adapter/downstream/terminalToSdkResult.js +209 -39
- package/dist/adapter/downstream/wiringManifestView.d.ts +1 -0
- package/dist/adapter/downstream/wiringManifestView.js +138 -0
- package/dist/adapter/runStream.d.ts +4 -4
- package/dist/adapter/runStream.js +158 -43
- package/dist/agentsWireCaps.d.ts +2 -7
- package/dist/agentsWireCaps.js +1 -2
- package/dist/approvalDecidedByCapability.js +2 -2
- package/dist/approvalFrameFamilies.d.ts +33 -0
- package/dist/approvalFrameFamilies.js +120 -0
- package/dist/approvalsStreamLiveCapability.js +2 -2
- package/dist/attachmentsWireCaps.js +41 -13
- package/dist/callerCwdCapability.js +2 -2
- package/dist/centerWiringCapability.js +2 -2
- package/dist/clockReading.d.ts +2 -0
- package/dist/clockReading.js +4 -0
- package/dist/cloudConfigWireCaps.d.ts +19 -5
- package/dist/cloudConfigWireCaps.js +193 -56
- package/dist/compensations.js +1 -1
- package/dist/coreValuePorts.d.ts +12 -2
- package/dist/coreValuePorts.js +9 -0
- package/dist/decideFailureNote.js +5 -3
- package/dist/decideReceipt.js +2 -2
- package/dist/deviceExecutorManagementCapability.js +2 -2
- package/dist/deviceFlowPolling.js +1 -1
- package/dist/disableSkillsWire.d.ts +1 -1
- package/dist/disableSkillsWire.js +4 -3
- package/dist/displayUntrusted.d.ts +9 -4
- package/dist/displayUntrusted.js +834 -104
- package/dist/engineCapReader.js +1 -1
- package/dist/engineConfigDrift.js +1 -1
- package/dist/engineErrorCodes.d.ts +14 -5
- package/dist/engineErrorCodes.js +27 -6
- package/dist/engineGenerationConvergence.d.ts +39 -0
- package/dist/engineGenerationConvergence.js +95 -0
- package/dist/engineGenerationPort.d.ts +61 -0
- package/dist/engineGenerationPort.js +144 -0
- package/dist/engineHealthFacts.d.ts +23 -0
- package/dist/engineHealthFacts.js +92 -0
- package/dist/engineIdentity.d.ts +4 -0
- package/dist/engineIdentity.js +11 -0
- package/dist/engineNoticeCodes.d.ts +2 -5
- package/dist/engineRowRef.js +4 -0
- package/dist/engineSessionMessages.js +2 -2
- package/dist/engineToolDirectory.js +2 -2
- package/dist/engineWireFor.d.ts +99 -0
- package/dist/engineWireFor.js +248 -6
- package/dist/engineWireTarget.d.ts +1 -0
- package/dist/engineWireTarget.js +8 -0
- package/dist/env/uiLanguage.js +1 -1
- package/dist/errorSupplementRoles.d.ts +3 -0
- package/dist/errorSupplementRoles.js +37 -0
- package/dist/executionLaneCapability.js +2 -2
- package/dist/fileHistoryCaptureCapability.js +3 -3
- package/dist/finalVerifyWire.d.ts +6 -3
- package/dist/finalVerifyWire.js +6 -23
- package/dist/flagInput.d.ts +4 -0
- package/dist/flagInput.js +24 -0
- package/dist/fleet/fleetLedger.js +5 -2
- package/dist/fleet/fleetProjection.d.ts +1 -0
- package/dist/fleet/fleetProjection.js +16 -3
- package/dist/gateVocabulary.js +3 -0
- package/dist/generated/engineFactTables.d.ts +7 -3
- package/dist/generated/engineFactTables.js +52 -0
- package/dist/generated/engineNoticeTables.js +12 -0
- package/dist/generated/settingsSchemaActiveTiers.d.ts +1 -0
- package/dist/generated/settingsSchemaActiveTiers.js +14 -0
- package/dist/generated/settingsSchemaCallerTextEcho.d.ts +1 -0
- package/dist/generated/settingsSchemaCallerTextEcho.js +8 -0
- package/dist/generated/settingsSchemaControlAndBidi.d.ts +1 -0
- package/dist/generated/settingsSchemaControlAndBidi.js +8 -0
- package/dist/generated/settingsSchemaDefaultModel.d.ts +11 -0
- package/dist/generated/settingsSchemaDefaultModel.js +25 -0
- package/dist/generated/settingsSchemaFns.d.ts +54 -0
- package/dist/generated/settingsSchemaFns.js +26 -1
- package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -1
- package/dist/generated/settingsSchemaMcpRequestEntry.js +1 -7
- package/dist/generated/settingsSchemaSafetyMergeSpec.d.ts +1 -0
- package/dist/generated/settingsSchemaSafetyMergeSpec.js +95 -0
- package/dist/generated/settingsSchemaSettingsSources.d.ts +1 -0
- package/dist/generated/settingsSchemaSettingsSources.js +58 -0
- package/dist/generated/settingsSchemaTables.d.ts +2 -0
- package/dist/generated/settingsSchemaTables.js +13 -0
- package/dist/generated/settingsSchemaUrlPattern.d.ts +1 -0
- package/dist/generated/settingsSchemaUrlPattern.js +183 -0
- package/dist/headlessPermissionModeWire.d.ts +18 -2
- package/dist/headlessPermissionModeWire.js +30 -19
- package/dist/hitl/allowRuleShadow.js +7 -5
- package/dist/hitl/approvalCardReading.d.ts +3 -0
- package/dist/hitl/approvalCardReading.js +17 -0
- package/dist/hitl/approvalCompleteParked.js +1 -1
- package/dist/hitl/approvalDelivery.d.ts +87 -0
- package/dist/hitl/approvalDelivery.js +193 -0
- package/dist/hitl/approvalResolution.d.ts +11 -0
- package/dist/hitl/approvalResolution.js +50 -11
- package/dist/hitl/askClassPair.d.ts +6 -0
- package/dist/hitl/askClassPair.js +30 -3
- package/dist/hitl/askParkAutoReopenBlock.d.ts +30 -0
- package/dist/hitl/askParkAutoReopenBlock.js +117 -0
- package/dist/hitl/askParkRowRouting.js +4 -1
- package/dist/hitl/attributionLadder.d.ts +42 -3
- package/dist/hitl/attributionLadder.js +79 -8
- package/dist/hitl/automaticAnswerVerdict.d.ts +6 -1
- package/dist/hitl/automaticAnswerVerdict.js +46 -11
- package/dist/hitl/crashConverged.js +2 -2
- package/dist/hitl/decisionConflict.d.ts +6 -2
- package/dist/hitl/decisionConflict.js +24 -9
- package/dist/hitl/decisionRefusal.d.ts +20 -10
- package/dist/hitl/decisionRefusal.js +99 -54
- package/dist/hitl/decisionSend.d.ts +3 -0
- package/dist/hitl/decisionSend.js +87 -103
- package/dist/hitl/frameRouter.d.ts +1 -0
- package/dist/hitl/frameRouter.js +9 -2
- package/dist/hitl/hitlBridge.d.ts +18 -6
- package/dist/hitl/hitlBridge.js +41 -37
- package/dist/hitl/livePendingAsk.js +4 -3
- package/dist/hitl/noAllowCause.js +1 -1
- package/dist/hitl/parkResolver.js +3 -2
- package/dist/hitl/persistedRulesWire.js +1 -0
- package/dist/hitl/planReviewWire.d.ts +4 -0
- package/dist/hitl/planReviewWire.js +59 -30
- package/dist/hitl/resumeRunningCard.d.ts +3 -2
- package/dist/hitl/resumeRunningCard.js +17 -11
- package/dist/hitl/sessionPolicyDeliverable.d.ts +5 -2
- package/dist/hitl/sessionPolicyDeliverable.js +62 -29
- package/dist/hitl/sessionPolicyWire.d.ts +13 -3
- package/dist/hitl/sessionPolicyWire.js +81 -16
- package/dist/hitl/standingRows.js +1 -1
- package/dist/hitl/toolApprovalWire.d.ts +9 -10
- package/dist/hitl/toolApprovalWire.js +72 -54
- package/dist/hookMatcherVerdict.d.ts +2 -0
- package/dist/hookMatcherVerdict.js +12 -0
- package/dist/hooksCompactTransition.d.ts +19 -0
- package/dist/hooksCompactTransition.js +41 -0
- package/dist/hooksWireCaps.d.ts +1 -1
- package/dist/hooksWireCaps.js +202 -203
- package/dist/host.d.ts +1 -14
- package/dist/host.js +0 -8
- package/dist/hostCallbackGuard.d.ts +1 -0
- package/dist/hostCallbackGuard.js +1 -1
- package/dist/hostSettingsSource.d.ts +172 -0
- package/dist/hostSettingsSource.js +675 -0
- package/dist/hostTurnSettings.d.ts +73 -17
- package/dist/hostTurnSettings.js +594 -97
- package/dist/httpHookPolicy.d.ts +37 -0
- package/dist/httpHookPolicy.js +176 -0
- package/dist/humanTurn.d.ts +2 -1
- package/dist/humanTurn.js +37 -7
- package/dist/humanTurnRead.js +4 -3
- package/dist/humanTurnSentences.d.ts +10 -0
- package/dist/humanTurnSentences.js +74 -0
- package/dist/i18n/messages.en.d.ts +222 -2
- package/dist/i18n/messages.en.js +225 -5
- package/dist/i18n/messages.zh.js +237 -5
- package/dist/i18n/translate.js +3 -3
- package/dist/index.d.ts +77 -15
- package/dist/index.js +50 -13
- package/dist/inheritEnvCapability.d.ts +3 -1
- package/dist/inheritEnvCapability.js +31 -17
- package/dist/inheritEnvWire.d.ts +2 -1
- package/dist/inheritEnvWire.js +11 -5
- package/dist/interactiveHalt.d.ts +3 -1
- package/dist/interactiveHalt.js +2 -0
- package/dist/interactiveInterrupt.d.ts +2 -0
- package/dist/interactiveInterrupt.js +15 -0
- package/dist/interactiveToolsWire.d.ts +4 -2
- package/dist/interactiveToolsWire.js +5 -5
- package/dist/jsonFaithful.d.ts +20 -0
- package/dist/jsonFaithful.js +152 -0
- package/dist/limitsWire.d.ts +7 -2
- package/dist/limitsWire.js +19 -13
- package/dist/liveInitToolFace.d.ts +6 -1
- package/dist/liveInitToolFace.js +5 -3
- package/dist/liveModelCatalog.d.ts +22 -0
- package/dist/liveModelCatalog.js +132 -18
- package/dist/mcpPanel.js +1 -1
- package/dist/mcpProbeCapability.js +2 -2
- package/dist/mcpStatusSupersetKeys.d.ts +24 -0
- package/dist/mcpStatusSupersetKeys.js +45 -0
- package/dist/mcpToolToggles.js +2 -1
- package/dist/mcpWireCaps.d.ts +39 -1
- package/dist/mcpWireCaps.js +254 -50
- package/dist/memoryComplianceCapability.js +2 -2
- package/dist/memoryOriginCapability.js +2 -2
- package/dist/model/catalogDefault.d.ts +24 -0
- package/dist/model/catalogDefault.js +4 -0
- package/dist/model/liveCatalogShape.js +5 -4
- package/dist/model/modelsPolicy.js +4 -3
- package/dist/model/onboardJudgement.d.ts +1 -0
- package/dist/model/onboardJudgement.js +1 -1
- package/dist/model/subagentModelWord.js +2 -2
- package/dist/modelCapabilityProbe.js +6 -6
- package/dist/modelIdentityResolvability.d.ts +10 -1
- package/dist/modelIdentityResolvability.js +62 -39
- package/dist/modsFace.d.ts +8 -0
- package/dist/modsFace.js +59 -0
- package/dist/modsKernelIdentity.d.ts +10 -0
- package/dist/modsKernelIdentity.js +103 -0
- package/dist/modsKernelTransit.d.ts +8 -0
- package/dist/modsKernelTransit.js +6 -0
- package/dist/notifications.d.ts +30 -12
- package/dist/notifications.js +241 -53
- package/dist/outputStyleSeatCapability.js +2 -2
- package/dist/ownKey.d.ts +12 -0
- package/dist/ownKey.js +179 -3
- package/dist/panelReduce.js +1 -1
- package/dist/peerFrames.d.ts +1 -1
- package/dist/peerFrames.js +6 -2
- package/dist/peerLaneCapability.js +2 -2
- package/dist/permissionModesCapability.js +4 -4
- package/dist/permissionRuleIssue.js +2 -0
- package/dist/permissionRulesWriteCapability.js +2 -2
- package/dist/permissionsAllowGrantCapability.js +2 -2
- package/dist/permissionsDeclaration.d.ts +43 -4
- package/dist/permissionsDeclaration.js +102 -35
- package/dist/pluginHooksWire.d.ts +20 -4
- package/dist/pluginHooksWire.js +92 -53
- package/dist/prepareRefusal.d.ts +3 -2
- package/dist/prepareRefusal.js +27 -9
- package/dist/printInitToolFace.js +2 -2
- package/dist/printModelStatus.js +1 -1
- package/dist/printToolResultFrame.js +1 -1
- package/dist/projectMemory.d.ts +32 -0
- package/dist/projectMemory.js +70 -0
- package/dist/promptBlockedCopy.d.ts +2 -1
- package/dist/promptBlockedCopy.js +2 -1
- package/dist/promptDelivery.d.ts +23 -3
- package/dist/promptDelivery.js +169 -30
- package/dist/providerRejection.d.ts +19 -1
- package/dist/providerRejection.js +75 -4
- package/dist/queuedDelivery.d.ts +48 -0
- package/dist/queuedDelivery.js +233 -0
- package/dist/reattachWindow.d.ts +94 -0
- package/dist/reattachWindow.js +127 -0
- package/dist/request/printNotification.d.ts +1 -1
- package/dist/request/printNotification.js +6 -2
- package/dist/request/submissionIdentity.d.ts +37 -0
- package/dist/request/submissionIdentity.js +65 -0
- package/dist/request/taskRequest.d.ts +33 -4
- package/dist/request/taskRequest.js +341 -156
- package/dist/resultFrameKeys.d.ts +1 -0
- package/dist/resultFrameKeys.js +4 -1
- package/dist/retryStatus.d.ts +8 -0
- package/dist/retryStatus.js +57 -9
- package/dist/rewindArchiveCapability.js +2 -2
- package/dist/rewindEngineAction.d.ts +2 -0
- package/dist/rewindEngineAction.js +23 -1
- package/dist/rowKind.d.ts +36 -0
- package/dist/rowKind.js +97 -0
- package/dist/ruleCompileVerdict.d.ts +18 -0
- package/dist/ruleCompileVerdict.js +67 -2
- package/dist/ruleReadings.d.ts +58 -0
- package/dist/ruleReadings.js +132 -0
- package/dist/ruleRefusalSentence.d.ts +4 -0
- package/dist/ruleRefusalSentence.js +9 -3
- package/dist/runCancelContext.d.ts +0 -1
- package/dist/runCancelContext.js +1 -2
- package/dist/runTerminal.d.ts +5 -0
- package/dist/runTerminal.js +52 -17
- package/dist/sandboxWire.d.ts +1 -1
- package/dist/sandboxWire.js +4 -6
- package/dist/scenarioRefusal.js +1 -1
- package/dist/scenarioSkills.d.ts +20 -0
- package/dist/scenarioSkills.js +72 -0
- package/dist/scenarioWire.d.ts +5 -2
- package/dist/scenarioWire.js +9 -9
- package/dist/sealedKeyCapability.js +2 -2
- package/dist/seam.d.ts +2 -0
- package/dist/seam.js +3 -3
- package/dist/seatContract.d.ts +68 -7
- package/dist/seatContract.js +84 -25
- package/dist/selfOrchestrationDenial.js +1 -1
- package/dist/sessionBackground.d.ts +165 -0
- package/dist/sessionBackground.js +781 -0
- package/dist/sessionBackgroundHandoff.d.ts +54 -0
- package/dist/sessionBackgroundHandoff.js +321 -0
- package/dist/sessionMap.js +4 -1
- package/dist/sessionPolicyCapability.js +2 -2
- package/dist/sessionRulesChildrenReadLive.d.ts +6 -0
- package/dist/sessionRulesChildrenReadLive.js +5 -0
- package/dist/sessionRulesNamespaceFormsCapability.d.ts +12 -0
- package/dist/sessionRulesNamespaceFormsCapability.js +29 -0
- package/dist/sessionSyncFileHistoryCapability.js +2 -2
- package/dist/settingsCredentialKeyPaths.js +55 -15
- package/dist/settingsHooksSalvage.d.ts +1 -0
- package/dist/settingsHooksSalvage.js +7 -1
- package/dist/settingsLayerAdmission.d.ts +4 -0
- package/dist/settingsLayerAdmission.js +16 -0
- package/dist/skillToolListsCapability.js +6 -5
- package/dist/skillsWireCaps.d.ts +14 -0
- package/dist/skillsWireCaps.js +47 -16
- package/dist/slashCommandGate.d.ts +24 -0
- package/dist/slashCommandGate.js +74 -0
- package/dist/slashCommandTable.d.ts +14 -0
- package/dist/slashCommandTable.js +99 -0
- package/dist/sqlEngineCapability.js +2 -2
- package/dist/steerPriorityCapability.js +2 -2
- package/dist/storePostureCapability.js +2 -2
- package/dist/subagent/agentStateDetail.js +1 -1
- package/dist/subagent/engineDelegatedPrompt.d.ts +9 -0
- package/dist/subagent/engineDelegatedPrompt.js +38 -7
- package/dist/subagent/engineRowStopGate.js +2 -2
- package/dist/subagent/engineSubagentResume.js +3 -3
- package/dist/subagent/engineTaskHandleWire.d.ts +1 -0
- package/dist/subagent/engineTaskHandleWire.js +10 -0
- package/dist/submitFailure.d.ts +8 -0
- package/dist/submitFailure.js +17 -0
- package/dist/supportFloor.d.ts +1 -0
- package/dist/supportFloor.js +7 -0
- package/dist/terminationIntent.d.ts +55 -0
- package/dist/terminationIntent.js +352 -0
- package/dist/thinkingLatch.d.ts +69 -0
- package/dist/thinkingLatch.js +255 -0
- package/dist/thinkingLatchWords.d.ts +7 -0
- package/dist/thinkingLatchWords.js +4 -0
- package/dist/toolHistoryMismatch.d.ts +8 -0
- package/dist/toolHistoryMismatch.js +37 -6
- package/dist/toolResult.d.ts +13 -3
- package/dist/toolResult.js +159 -32
- package/dist/toolResultContent.d.ts +13 -0
- package/dist/toolResultContent.js +82 -7
- package/dist/toolRoster.d.ts +18 -0
- package/dist/toolRoster.js +64 -0
- package/dist/turnFailurePresentation.js +27 -90
- package/dist/usageLimitAutoResume.d.ts +74 -0
- package/dist/usageLimitAutoResume.js +227 -0
- package/dist/userAttachmentEnvelope.js +1 -1
- package/dist/userAttachmentSeat.js +5 -5
- package/dist/userInvokedSkillsCapability.js +2 -2
- package/dist/webSearchBackendCapability.js +2 -2
- package/dist/wireErrorTriage.js +99 -50
- package/dist/wireFailureShape.d.ts +25 -1
- package/dist/wireFailureShape.js +92 -5
- package/dist/wireRefusalCopy.d.ts +24 -1
- package/dist/wireRefusalCopy.js +253 -32
- package/dist/wiringFleetDoctor.d.ts +3 -0
- package/dist/wiringFleetDoctor.js +21 -0
- package/dist/workflow.d.ts +2 -1
- package/dist/workflow.js +38 -1
- package/dist/workflowClient.d.ts +2 -7
- package/dist/workflowsJournalCapability.js +2 -2
- package/dist/writeProtectionCapability.js +2 -2
- package/docs/INTEGRATION-CLIENTS.md +907 -182
- package/package.json +14 -3
- package/dist/argvFlagValue.d.ts +0 -8
- package/dist/argvFlagValue.js +0 -37
package/dist/hostTurnSettings.js
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { SETTINGS_CLASSIFY_HOOKS_CONFIG } from './generated/settingsSchemaFns.js';
|
|
2
|
-
import {
|
|
2
|
+
import { hostLog } from './host.js';
|
|
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';
|
|
5
|
+
import { hooksWirePlan } from './hooksWireCaps.js';
|
|
6
|
+
import { submissionSurfaceOf } from './request/submissionIdentity.js';
|
|
7
|
+
import { displayUntrusted } from './displayUntrusted.js';
|
|
3
8
|
import { resolveWebSearchVerdict, webSearchVerdictMessage } from './webSearchWireCaps.js';
|
|
4
9
|
import { fileHistoryTightenVerdict, fileHistoryUnjudgedRefusal } from './fileHistoryCaptureCapability.js';
|
|
5
10
|
import { msg, renderMessage } from './i18n/translate.js';
|
|
11
|
+
import { newRulePortsProjection, projectPermissionsDeclaration, rulePortsMissingOf, WIRE_RULE_TRUST_ORDER } from './permissionsDeclaration.js';
|
|
12
|
+
import { assemblyRefusalOf } from './wireFailureShape.js';
|
|
13
|
+
import { layerAdmitted } from './settingsLayerAdmission.js';
|
|
14
|
+
import { appendOwnElement, ownDataField } from './ownKey.js';
|
|
6
15
|
export const HOST_SUPPLIED_KEYS = Object.freeze(['settings.hooks', 'settings.resolved', 'settings.webSearch', 'settings.outputStyle', 'memory', 'fileHistory']);
|
|
7
16
|
export const HOST_SETTING_CAUSES = Object.freeze([
|
|
8
17
|
'carried',
|
|
@@ -14,16 +23,24 @@ export const HOST_SETTING_CAUSES = Object.freeze([
|
|
|
14
23
|
'no_source',
|
|
15
24
|
'host_port_missing',
|
|
16
25
|
'value_malformed',
|
|
26
|
+
'held_previous',
|
|
27
|
+
'policy_withheld',
|
|
17
28
|
]);
|
|
18
|
-
export const HOST_SETTING_DISPOSITIONS = Object.freeze(['carry', 'carry_partial', 'withhold_notice', 'refuse_turn', 'unwired', 'nothing_to_carry']);
|
|
29
|
+
export const HOST_SETTING_DISPOSITIONS = Object.freeze(['carry', 'carry_partial', 'withhold_notice', 'withhold_by_policy', 'hold_for_consent', 'refuse_turn', 'unwired', 'nothing_to_carry']);
|
|
19
30
|
const HOST_SETTING_NOTICE_TEXT = {
|
|
20
31
|
'HS-UNWIRED': (what) => `This app has not connected ${what} from your settings, so it is not sent with your requests.`,
|
|
21
32
|
'HS-MANAGED-REJECTED': () => 'Managed settings: the hooks your administrator configured could not be loaded, so requests are not sent until the managed settings are fixed.',
|
|
22
|
-
'HS-PROJECTION': () =>
|
|
33
|
+
'HS-PROJECTION': (sentence) => (sentence === '' ? renderMessage(msg('session.hostSettings.projectionUnchecked')) : sentence),
|
|
23
34
|
'HS-SOURCE-UNREADABLE': (what) => `This app could not read ${what} from your settings, so the request is not sent. Reload your settings and try again.`,
|
|
24
35
|
'HS-WEBSEARCH-MALFORMED': (sentence) => sentence,
|
|
25
36
|
'HS-SWITCH-MALFORMED': () => renderMessage(msg('session.hostSettings.memorySwitchMalformed')),
|
|
26
37
|
'HS-FILEHISTORY-UNJUDGED': (sentence) => sentence,
|
|
38
|
+
'HS-FILEHISTORY-RESTORE': () => renderMessage(msg('session.hostSettings.fileHistoryRestoreConflict')),
|
|
39
|
+
'HS-MANAGED-UNREADABLE': () => renderMessage(msg('session.hostSettings.managedUnreadable')),
|
|
40
|
+
'HS-LAYER-NOT-LOADED': (sentence) => sentence,
|
|
41
|
+
'HS-HELD-PREVIOUS': () => renderMessage(msg('session.hostSettings.heldPrevious')),
|
|
42
|
+
'HS-STYLE-MISSING': (what) => renderMessage(msg('session.hostSettings.styleMissing', { name: what })),
|
|
43
|
+
'HS-STYLE-SAFE': () => renderMessage(msg('session.hostSettings.styleSafeMode')),
|
|
27
44
|
};
|
|
28
45
|
const KEY_NOUN = {
|
|
29
46
|
'settings.hooks': 'the hooks',
|
|
@@ -43,6 +60,8 @@ const BASE_DISPOSITION = {
|
|
|
43
60
|
no_source: 'nothing_to_carry',
|
|
44
61
|
host_port_missing: 'unwired',
|
|
45
62
|
value_malformed: 'refuse_turn',
|
|
63
|
+
held_previous: 'carry',
|
|
64
|
+
policy_withheld: 'withhold_by_policy',
|
|
46
65
|
};
|
|
47
66
|
const freeze = (o) => Object.freeze(o);
|
|
48
67
|
const mint = (o) => o;
|
|
@@ -58,18 +77,6 @@ function readSource(sources, key) {
|
|
|
58
77
|
return { kind: 'threw' };
|
|
59
78
|
}
|
|
60
79
|
}
|
|
61
|
-
function unwrap(v, field) {
|
|
62
|
-
if (v === 'none')
|
|
63
|
-
return { kind: 'none' };
|
|
64
|
-
try {
|
|
65
|
-
if (typeof v !== 'object' || v === null || Array.isArray(v) || !Object.hasOwn(v, field))
|
|
66
|
-
return { kind: 'bad' };
|
|
67
|
-
return { kind: 'value', value: v[field] };
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
return { kind: 'bad' };
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
80
|
const isRecordShape = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
74
81
|
function hooksPassJudge(wire) {
|
|
75
82
|
try {
|
|
@@ -94,41 +101,50 @@ const unreadableArm = (key) => ({
|
|
|
94
101
|
notices: [notice('HS-SOURCE-UNREADABLE', 'turn', KEY_NOUN[key])],
|
|
95
102
|
});
|
|
96
103
|
const noSourceArm = (key) => ({ row: freeze({ key, cause: 'no_source', disposition: BASE_DISPOSITION.no_source }), notices: [] });
|
|
104
|
+
const emptyArm = (key) => ({ row: freeze({ key, cause: 'empty', disposition: BASE_DISPOSITION.empty }), notices: [] });
|
|
97
105
|
const carriedArm = (key, value) => ({ row: freeze({ key, cause: 'carried', disposition: BASE_DISPOSITION.carried }), notices: [], carried: value });
|
|
98
|
-
function hooksArm(src) {
|
|
106
|
+
function hooksArm(src, side) {
|
|
99
107
|
const key = 'settings.hooks';
|
|
100
108
|
if (src.kind === 'missing')
|
|
101
109
|
return missingArm(key);
|
|
102
110
|
if (src.kind === 'threw')
|
|
103
111
|
return unreadableArm(key);
|
|
104
|
-
const
|
|
105
|
-
if (
|
|
112
|
+
const facts = src.value;
|
|
113
|
+
if (facts === 'none')
|
|
106
114
|
return noSourceArm(key);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const plan = u.value;
|
|
110
|
-
let wire;
|
|
111
|
-
let salvageRows;
|
|
112
|
-
let closedBy;
|
|
115
|
+
let hasPlan;
|
|
116
|
+
let hasSettings;
|
|
113
117
|
try {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
118
|
+
if (!isRecordShape(facts))
|
|
119
|
+
throw badSource(key, "the hooks plan facts ({ baseUrl?, engineOwnedByThisShell?, shellHookEvents?, … }) — since 0.101.0 the entry builds the plan from the settings it reads");
|
|
120
|
+
hasPlan = Object.hasOwn(facts, 'plan');
|
|
121
|
+
hasSettings = Object.hasOwn(facts, 'settings');
|
|
117
122
|
}
|
|
118
|
-
catch {
|
|
119
|
-
|
|
123
|
+
catch (e) {
|
|
124
|
+
if (e instanceof HostSourceShapeError)
|
|
125
|
+
throw e;
|
|
126
|
+
return unreadableArm(key);
|
|
120
127
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
128
|
+
if (hasPlan || hasSettings)
|
|
129
|
+
throw badSource(key, "the hooks plan facts — since 0.101.0 do not pass { plan } (the entry builds the plan) nor settings (pass it once as the entry's settings)");
|
|
130
|
+
if (side.kind === 'missing')
|
|
131
|
+
return missingArm(key);
|
|
132
|
+
if (side.kind === 'none')
|
|
133
|
+
return noSourceArm(key);
|
|
134
|
+
const plan = hooksWirePlan({ ...facts, settings: sourceOfRead(side.read) });
|
|
135
|
+
const wire = plan.wire;
|
|
136
|
+
const rows = plan.settingsSalvage;
|
|
137
|
+
const layersOf = (outcome) => rows.filter((r) => r.outcome === outcome).map((r) => r.source);
|
|
138
|
+
const refusingRejected = layersOf('rejected').filter(layerNotAppliedRefusesTurn);
|
|
139
|
+
const refusingPartial = layersOf('loaded-partial').filter(layerNotAppliedRefusesTurn);
|
|
140
|
+
if (refusingRejected.length > 0 || refusingPartial.length > 0) {
|
|
125
141
|
return {
|
|
126
|
-
row: freeze({ key, cause:
|
|
142
|
+
row: freeze({ key, cause: refusingRejected.length > 0 ? 'source_rejected' : 'entries_dropped', disposition: 'refuse_turn', layers: freeze([...new Set([...refusingRejected, ...refusingPartial])]) }),
|
|
127
143
|
notices: [notice('HS-MANAGED-REJECTED', 'turn')],
|
|
128
144
|
plan,
|
|
129
145
|
};
|
|
130
146
|
}
|
|
131
|
-
if (closedBy === 'governance_unreadable')
|
|
147
|
+
if (plan.closedBy === 'governance_unreadable')
|
|
132
148
|
return { ...unreadableArm(key), plan };
|
|
133
149
|
if (wire !== undefined && !hooksPassJudge(wire)) {
|
|
134
150
|
return { row: freeze({ key, cause: 'projection_failed', disposition: BASE_DISPOSITION.projection_failed }), notices: [notice('HS-PROJECTION', 'turn')], plan };
|
|
@@ -142,10 +158,10 @@ function hooksArm(src) {
|
|
|
142
158
|
return { row: freeze({ key, cause, disposition: carried !== undefined ? 'carry_partial' : 'withhold_notice', layers }), notices: [], carried, plan };
|
|
143
159
|
}
|
|
144
160
|
if (carried === undefined)
|
|
145
|
-
return {
|
|
161
|
+
return { ...emptyArm(key), plan };
|
|
146
162
|
return { ...carriedArm(key, carried), plan };
|
|
147
163
|
}
|
|
148
|
-
function webSearchArm(src) {
|
|
164
|
+
function webSearchArm(src, side) {
|
|
149
165
|
const key = 'settings.webSearch';
|
|
150
166
|
if (src.kind === 'missing')
|
|
151
167
|
return missingArm(key);
|
|
@@ -154,13 +170,12 @@ function webSearchArm(src) {
|
|
|
154
170
|
const v = src.value;
|
|
155
171
|
if (v === 'none')
|
|
156
172
|
return noSourceArm(key);
|
|
157
|
-
let section;
|
|
158
173
|
let env;
|
|
159
174
|
let apiKeyFor;
|
|
160
175
|
try {
|
|
161
|
-
if (!isRecordShape(v) || !Object.hasOwn(v, 'env') || Object.hasOwn(v, 'settings'))
|
|
162
|
-
throw badSource(key, "{
|
|
163
|
-
|
|
176
|
+
if (!isRecordShape(v) || !Object.hasOwn(v, 'env') || Object.hasOwn(v, 'settings') || Object.hasOwn(v, 'section')) {
|
|
177
|
+
throw badSource(key, "{ env, apiKeyFor? } with the environment (since 0.101.0 the webSearch section comes from the settings the entry reads — do not pass section)");
|
|
178
|
+
}
|
|
164
179
|
env = v.env;
|
|
165
180
|
apiKeyFor = v.apiKeyFor;
|
|
166
181
|
}
|
|
@@ -170,12 +185,15 @@ function webSearchArm(src) {
|
|
|
170
185
|
return unreadableArm(key);
|
|
171
186
|
}
|
|
172
187
|
if (!isRecordShape(env))
|
|
173
|
-
throw badSource(key, '{
|
|
188
|
+
throw badSource(key, '{ env } where env is the environment record (pass {} where there is none)');
|
|
174
189
|
if (apiKeyFor !== undefined && typeof apiKeyFor !== 'function')
|
|
175
|
-
throw badSource(key, '{
|
|
190
|
+
throw badSource(key, '{ env, apiKeyFor? } where apiKeyFor is a function');
|
|
191
|
+
if (side.kind === 'missing')
|
|
192
|
+
return missingArm(key);
|
|
193
|
+
const section = side.kind === 'read' ? settingsValueOf(side.read, 'webSearch') : undefined;
|
|
176
194
|
const verdict = resolveWebSearchVerdict(env, section, apiKeyFor);
|
|
177
195
|
if (verdict.kind === 'absent')
|
|
178
|
-
return
|
|
196
|
+
return emptyArm(key);
|
|
179
197
|
if (verdict.kind === 'honored')
|
|
180
198
|
return carriedArm(key, freeze({ ...verdict.settings }));
|
|
181
199
|
return {
|
|
@@ -183,7 +201,7 @@ function webSearchArm(src) {
|
|
|
183
201
|
notices: [notice('HS-WEBSEARCH-MALFORMED', 'turn', webSearchVerdictMessage(verdict, 'submit') ?? '')],
|
|
184
202
|
};
|
|
185
203
|
}
|
|
186
|
-
function memoryArm(src, judge) {
|
|
204
|
+
function memoryArm(src, side, judge) {
|
|
187
205
|
const key = 'memory';
|
|
188
206
|
if (src.kind === 'missing')
|
|
189
207
|
return missingArm(key);
|
|
@@ -193,12 +211,10 @@ function memoryArm(src, judge) {
|
|
|
193
211
|
if (v === 'none')
|
|
194
212
|
return noSourceArm(key);
|
|
195
213
|
let flag;
|
|
196
|
-
let settingsMemory;
|
|
197
214
|
try {
|
|
198
|
-
if (!isRecordShape(v))
|
|
199
|
-
throw badSource(key, '{ flag
|
|
215
|
+
if (!isRecordShape(v) || Object.hasOwn(v, 'settingsMemory'))
|
|
216
|
+
throw badSource(key, '{ flag? } with the --memory flag word (since 0.101.0 the memory section comes from the settings the entry reads — do not pass settingsMemory)');
|
|
200
217
|
flag = v.flag;
|
|
201
|
-
settingsMemory = v.settingsMemory;
|
|
202
218
|
}
|
|
203
219
|
catch (e) {
|
|
204
220
|
if (e instanceof HostSourceShapeError)
|
|
@@ -207,6 +223,9 @@ function memoryArm(src, judge) {
|
|
|
207
223
|
}
|
|
208
224
|
if (judge({ flag }))
|
|
209
225
|
return carriedArm(key, 'off');
|
|
226
|
+
if (side.kind === 'missing')
|
|
227
|
+
return missingArm(key);
|
|
228
|
+
const settingsMemory = side.kind === 'read' ? settingsValueOf(side.read, 'memory') : undefined;
|
|
210
229
|
let bySettings;
|
|
211
230
|
try {
|
|
212
231
|
bySettings = judge({ settingsMemory });
|
|
@@ -216,7 +235,7 @@ function memoryArm(src, judge) {
|
|
|
216
235
|
}
|
|
217
236
|
if (bySettings)
|
|
218
237
|
return carriedArm(key, 'off');
|
|
219
|
-
return
|
|
238
|
+
return emptyArm(key);
|
|
220
239
|
}
|
|
221
240
|
const UNOBSERVED_READING = Object.freeze({ kind: 'unobserved' });
|
|
222
241
|
function fileHistoryReadingSnapshot(reading) {
|
|
@@ -268,22 +287,243 @@ function fileHistoryArm(src) {
|
|
|
268
287
|
notices: [notice('HS-FILEHISTORY-UNJUDGED', 'turn', fileHistoryUnjudgedRefusal(snap, true) ?? fileHistoryUnjudgedRefusal(UNOBSERVED_READING, true) ?? '')],
|
|
269
288
|
};
|
|
270
289
|
}
|
|
271
|
-
return
|
|
290
|
+
return emptyArm(key);
|
|
272
291
|
}
|
|
273
|
-
function
|
|
292
|
+
function outputStyleArm(src, side) {
|
|
293
|
+
const key = 'settings.outputStyle';
|
|
274
294
|
if (src.kind === 'missing')
|
|
275
295
|
return missingArm(key);
|
|
276
296
|
if (src.kind === 'threw')
|
|
277
297
|
return unreadableArm(key);
|
|
278
|
-
const
|
|
279
|
-
if (
|
|
298
|
+
const v = src.value;
|
|
299
|
+
if (v === 'none')
|
|
280
300
|
return noSourceArm(key);
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
301
|
+
let readBody;
|
|
302
|
+
try {
|
|
303
|
+
if (!isRecordShape(v) || Object.hasOwn(v, 'name'))
|
|
304
|
+
throw badSource(key, '{ readBody(name) } (since 0.101.0 the style name comes from the settings the entry reads — do not pass name)');
|
|
305
|
+
readBody = v.readBody;
|
|
306
|
+
}
|
|
307
|
+
catch (e) {
|
|
308
|
+
if (e instanceof HostSourceShapeError)
|
|
309
|
+
throw e;
|
|
310
|
+
return unreadableArm(key);
|
|
311
|
+
}
|
|
312
|
+
if (typeof readBody !== 'function')
|
|
313
|
+
throw badSource(key, '{ readBody(name) } where readBody is a method');
|
|
314
|
+
if (side.kind === 'missing')
|
|
315
|
+
return missingArm(key);
|
|
316
|
+
if (side.kind === 'none')
|
|
317
|
+
return noSourceArm(key);
|
|
318
|
+
const name = settingsValueOf(side.read, 'outputStyle');
|
|
319
|
+
if (typeof name !== 'string' || name === '')
|
|
320
|
+
return emptyArm(key);
|
|
321
|
+
if (side.read.startup === 'safe') {
|
|
322
|
+
return { row: freeze({ key, cause: 'policy_withheld', disposition: BASE_DISPOSITION.policy_withheld }), notices: [notice('HS-STYLE-SAFE', 'diagnostic')] };
|
|
323
|
+
}
|
|
324
|
+
let body;
|
|
325
|
+
try {
|
|
326
|
+
body = readBody.call(v, name);
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
body = undefined;
|
|
330
|
+
}
|
|
331
|
+
const state = ownDataOf(body, 'state');
|
|
332
|
+
const text = state.ok && state.value === 'present' ? ownDataOf(body, 'body') : undefined;
|
|
333
|
+
const reminder = state.ok && state.value === 'present' ? ownDataOf(body, 'turnReminder') : undefined;
|
|
334
|
+
if (text !== undefined && text.ok && typeof text.value === 'string' && reminder !== undefined && reminder.ok && (reminder.value === undefined || typeof reminder.value === 'string')) {
|
|
335
|
+
const facts = freeze({ name, body: text.value, ...(reminder.value !== undefined ? { turnReminder: reminder.value } : {}) });
|
|
336
|
+
return { ...carriedArm(key, name), facts };
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
row: freeze({ key, cause: 'source_unreadable', disposition: 'withhold_notice' }),
|
|
340
|
+
notices: [notice('HS-STYLE-MISSING', 'session', displayUntrusted(name))],
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
function stringListOf(v) {
|
|
344
|
+
if (v === undefined)
|
|
345
|
+
return [];
|
|
346
|
+
try {
|
|
347
|
+
if (!Array.isArray(v))
|
|
348
|
+
return undefined;
|
|
349
|
+
const ld = Object.getOwnPropertyDescriptor(v, 'length');
|
|
350
|
+
if (ld === undefined || !Object.hasOwn(ld, 'value') || typeof ld.value !== 'number' || !Number.isSafeInteger(ld.value) || ld.value < 0 || ld.value > 100_000)
|
|
351
|
+
return undefined;
|
|
352
|
+
const len = ld.value;
|
|
353
|
+
const out = [];
|
|
354
|
+
for (let i = 0; i < len; i++) {
|
|
355
|
+
const d = Object.getOwnPropertyDescriptor(v, i);
|
|
356
|
+
if (d === undefined || !Object.hasOwn(d, 'value') || typeof d.value !== 'string')
|
|
357
|
+
return undefined;
|
|
358
|
+
appendOwnElement(out, d.value);
|
|
359
|
+
}
|
|
360
|
+
return out;
|
|
361
|
+
}
|
|
362
|
+
catch {
|
|
363
|
+
return undefined;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
function permissionMemberAdmitted(layer, read, bucket) {
|
|
367
|
+
return layerAdmitted(layer, read.trust, 'permissions', bucket);
|
|
286
368
|
}
|
|
369
|
+
function allowAdmittedFor(read) {
|
|
370
|
+
const disp = MANAGED_READING_DISPOSITIONS[read.managed];
|
|
371
|
+
const policyDoc = read.layers.policySettings.doc;
|
|
372
|
+
const managedOnlySwitch = disp.ruleScope === 'by-switch' && policyDoc !== null && managedOnlySwitchOn(policyDoc);
|
|
373
|
+
const degrade = disp.ruleScope === 'degrade';
|
|
374
|
+
return (layer) => {
|
|
375
|
+
if (degrade || managedOnlySwitch)
|
|
376
|
+
return false;
|
|
377
|
+
try {
|
|
378
|
+
const doc = read.layers[layer].doc;
|
|
379
|
+
if (doc !== null && salvageSettingsHooksEntries(doc).outcome === 'rejected')
|
|
380
|
+
return false;
|
|
381
|
+
return layerAdmitted(layer, read.trust, 'permissions', 'allow');
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
function badPermissionsSource() {
|
|
389
|
+
return new HostSourceShapeError(`hostTurnSettings: sources.resolved must be 'none' or { allowGrantReading, cliArg?, session?, clientOwnedServers?, serverVersion? } — 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).`);
|
|
390
|
+
}
|
|
391
|
+
function permissionsArm(src, side, adoption) {
|
|
392
|
+
const key = 'settings.resolved';
|
|
393
|
+
if (src.kind === 'missing')
|
|
394
|
+
return missingArm(key);
|
|
395
|
+
if (src.kind === 'threw')
|
|
396
|
+
return unreadableArm(key);
|
|
397
|
+
const v = src.value;
|
|
398
|
+
if (v === 'none')
|
|
399
|
+
return noSourceArm(key);
|
|
400
|
+
let allowGrantReading;
|
|
401
|
+
let cliAllow;
|
|
402
|
+
let cliDeny;
|
|
403
|
+
let sesDeny;
|
|
404
|
+
let sesAsk;
|
|
405
|
+
let owned;
|
|
406
|
+
let ownedRaw;
|
|
407
|
+
let serverVersion;
|
|
408
|
+
try {
|
|
409
|
+
if (!isRecordShape(v) || Object.hasOwn(v, 'snapshot') || !Object.hasOwn(v, 'allowGrantReading'))
|
|
410
|
+
throw badPermissionsSource();
|
|
411
|
+
const sver = ownDataOf(v, 'serverVersion');
|
|
412
|
+
serverVersion = sver.ok && typeof sver.value === 'string' ? sver.value : undefined;
|
|
413
|
+
const g = ownDataOf(v, 'allowGrantReading');
|
|
414
|
+
const c = ownDataOf(v, 'cliArg');
|
|
415
|
+
const se = ownDataOf(v, 'session');
|
|
416
|
+
const o = ownDataOf(v, 'clientOwnedServers');
|
|
417
|
+
if (!g.ok || !c.ok || !se.ok || !o.ok)
|
|
418
|
+
return unreadableArm(key);
|
|
419
|
+
allowGrantReading = g.value;
|
|
420
|
+
const cv = c.value;
|
|
421
|
+
const sv = se.value;
|
|
422
|
+
if (cv !== undefined && !isRecordShape(cv))
|
|
423
|
+
throw badPermissionsSource();
|
|
424
|
+
if (sv !== undefined && !isRecordShape(sv))
|
|
425
|
+
throw badPermissionsSource();
|
|
426
|
+
const ca = cv === undefined ? { ok: true, value: undefined } : ownDataOf(cv, 'allow');
|
|
427
|
+
const cd = cv === undefined ? { ok: true, value: undefined } : ownDataOf(cv, 'deny');
|
|
428
|
+
const sd = sv === undefined ? { ok: true, value: undefined } : ownDataOf(sv, 'deny');
|
|
429
|
+
const sa = sv === undefined ? { ok: true, value: undefined } : ownDataOf(sv, 'ask');
|
|
430
|
+
if (!ca.ok || !cd.ok || !sd.ok || !sa.ok)
|
|
431
|
+
return unreadableArm(key);
|
|
432
|
+
cliAllow = stringListOf(ca.value);
|
|
433
|
+
cliDeny = stringListOf(cd.value);
|
|
434
|
+
sesDeny = stringListOf(sd.value);
|
|
435
|
+
sesAsk = stringListOf(sa.value);
|
|
436
|
+
ownedRaw = o.value;
|
|
437
|
+
owned = o.value === undefined ? undefined : stringListOf(o.value);
|
|
438
|
+
}
|
|
439
|
+
catch (e) {
|
|
440
|
+
if (e instanceof HostSourceShapeError)
|
|
441
|
+
throw e;
|
|
442
|
+
return unreadableArm(key);
|
|
443
|
+
}
|
|
444
|
+
if (cliAllow === undefined || cliDeny === undefined || sesDeny === undefined || sesAsk === undefined || (owned === undefined && ownedRaw !== undefined))
|
|
445
|
+
throw badPermissionsSource();
|
|
446
|
+
if (side.kind === 'missing')
|
|
447
|
+
return missingArm(key);
|
|
448
|
+
const buckets = { deny: [], ask: [], allow: [] };
|
|
449
|
+
const origins = { deny: new Map(), ask: new Map(), allow: new Map() };
|
|
450
|
+
const rank = (o) => WIRE_RULE_TRUST_ORDER.indexOf(o);
|
|
451
|
+
const add = (bucket, rule, origin) => {
|
|
452
|
+
const prev = origins[bucket].get(rule);
|
|
453
|
+
if (prev === undefined) {
|
|
454
|
+
appendOwnElement(buckets[bucket], rule);
|
|
455
|
+
origins[bucket].set(rule, origin);
|
|
456
|
+
}
|
|
457
|
+
else if (rank(origin) < rank(prev))
|
|
458
|
+
origins[bucket].set(rule, origin);
|
|
459
|
+
};
|
|
460
|
+
let projectionError;
|
|
461
|
+
const portsProjection = newRulePortsProjection();
|
|
462
|
+
if (side.kind === 'read') {
|
|
463
|
+
const read = side.read;
|
|
464
|
+
const disp = MANAGED_READING_DISPOSITIONS[read.managed];
|
|
465
|
+
const policyDoc = read.layers.policySettings.doc;
|
|
466
|
+
const managedOnlySwitch = disp.ruleScope === 'by-switch' && policyDoc !== null && managedOnlySwitchOn(policyDoc);
|
|
467
|
+
const degrade = disp.ruleScope === 'degrade';
|
|
468
|
+
try {
|
|
469
|
+
for (const bucket of Object.keys(buckets)) {
|
|
470
|
+
if (bucket === 'allow' && degrade)
|
|
471
|
+
continue;
|
|
472
|
+
if (permissionMemberAdmitted('policySettings', read, bucket))
|
|
473
|
+
for (const r of permissionRulesOf(policyDoc, bucket))
|
|
474
|
+
add(bucket, r, 'policySettings');
|
|
475
|
+
}
|
|
476
|
+
if (!managedOnlySwitch) {
|
|
477
|
+
for (const l of ADOPTED_LAYERS) {
|
|
478
|
+
for (const bucket of ['deny', 'ask'])
|
|
479
|
+
if (permissionMemberAdmitted(l, read, bucket))
|
|
480
|
+
for (const r of permissionRulesOf(read.layers[l].doc, bucket))
|
|
481
|
+
add(bucket, r, l);
|
|
482
|
+
if (!degrade && permissionMemberAdmitted(l, read, 'allow'))
|
|
483
|
+
for (const r of adoption?.allowByLayer[l] ?? [])
|
|
484
|
+
add('allow', r, l);
|
|
485
|
+
}
|
|
486
|
+
for (const bucket of ['deny', 'ask'])
|
|
487
|
+
for (const r of adoption?.extraTighten[bucket] ?? [])
|
|
488
|
+
if (permissionMemberAdmitted(r.layer, read, bucket))
|
|
489
|
+
add(bucket, r.rule, r.layer);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
catch (error) {
|
|
493
|
+
projectionError = freeze({ error: error });
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
for (const r of cliAllow)
|
|
497
|
+
add('allow', r, 'cliArg');
|
|
498
|
+
for (const r of sesDeny)
|
|
499
|
+
add('deny', r, 'session');
|
|
500
|
+
for (const r of sesAsk)
|
|
501
|
+
add('ask', r, 'session');
|
|
502
|
+
let declared;
|
|
503
|
+
if (projectionError === undefined) {
|
|
504
|
+
try {
|
|
505
|
+
const d = projectPermissionsDeclaration({ deny: buckets.deny, ask: buckets.ask, allow: buckets.allow, origins, cliDeny, settingsRead: 'clean', ...(owned !== undefined && owned.length > 0 ? { clientOwnedServers: owned } : {}), ...(serverVersion !== undefined ? { serverVersion } : {}) }, allowGrantReading, portsProjection);
|
|
506
|
+
declared = d.permissions !== undefined ? { permissions: d.permissions } : undefined;
|
|
507
|
+
}
|
|
508
|
+
catch (error) {
|
|
509
|
+
projectionError = freeze({ error: error });
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (projectionError !== undefined)
|
|
513
|
+
return { row: freeze({ key, cause: 'projection_failed', disposition: BASE_DISPOSITION.projection_failed }), notices: [projectionRefusedNotice(projectionError.error, portsProjection)], refusalCause: projectionError };
|
|
514
|
+
if (declared === undefined)
|
|
515
|
+
return emptyArm(key);
|
|
516
|
+
return carriedArm(key, declared);
|
|
517
|
+
}
|
|
518
|
+
function projectionRefusedNotice(error, projection) {
|
|
519
|
+
const ports = rulePortsMissingOf(error, projection);
|
|
520
|
+
if (ports !== undefined && ports.length > 0)
|
|
521
|
+
return notice('HS-PROJECTION', 'turn', renderMessage(msg('session.hostSettings.projectionUncheckedPortsMissing', { ports: ports.join(' / ') })));
|
|
522
|
+
if (assemblyRefusalOf(error)?.cause === 'judge_unanswerable')
|
|
523
|
+
return notice('HS-PROJECTION', 'turn', renderMessage(msg('session.hostSettings.projectionUncheckedJudgeFailed')));
|
|
524
|
+
return notice('HS-PROJECTION', 'turn');
|
|
525
|
+
}
|
|
526
|
+
const REFUSAL_CAUSE = Symbol('hostTurnSettings.refusalCause');
|
|
287
527
|
const RESOLVED_DEFERRED_ERROR = Symbol('hostTurnSettings.resolvedDeferredError');
|
|
288
528
|
export function rethrowHostResolvedDeferred(product) {
|
|
289
529
|
const rec = product;
|
|
@@ -293,6 +533,58 @@ export function rethrowHostResolvedDeferred(product) {
|
|
|
293
533
|
if (box !== undefined)
|
|
294
534
|
throw box.error;
|
|
295
535
|
}
|
|
536
|
+
function sessionOf(previous) {
|
|
537
|
+
const s = sessionSnapshotOf(previous);
|
|
538
|
+
if (s === undefined)
|
|
539
|
+
throw new HostSourceShapeError('hostTurnSettings: previous must be the session of the previous product of this session (product.session) or absent — got something else (the value is not echoed).');
|
|
540
|
+
return s;
|
|
541
|
+
}
|
|
542
|
+
const NON_MANAGED_LAYERS = HOST_SETTINGS_LAYERS.filter((l) => l !== 'policySettings');
|
|
543
|
+
function fnv1a(text) {
|
|
544
|
+
let h = 0x811c9dc5;
|
|
545
|
+
for (let i = 0; i < text.length; i++) {
|
|
546
|
+
h ^= text.charCodeAt(i);
|
|
547
|
+
h = Math.imul(h, 0x01000193) >>> 0;
|
|
548
|
+
}
|
|
549
|
+
return h.toString(16).padStart(8, '0');
|
|
550
|
+
}
|
|
551
|
+
function notLoadedLayers(read, plan) {
|
|
552
|
+
const out = [];
|
|
553
|
+
for (const layer of NON_MANAGED_LAYERS) {
|
|
554
|
+
const snap = read.layers[layer];
|
|
555
|
+
if (!snap.enabled)
|
|
556
|
+
continue;
|
|
557
|
+
const down = snap.carriers.filter((c) => c.status === 'unreadable' || c.status === 'not-loaded');
|
|
558
|
+
if (snap.malformed || down.length > 0) {
|
|
559
|
+
appendOwnElement(out, { layer, how: 'unreadable', key: JSON.stringify([layer, 'unreadable', down.map((c) => [c.id, c.status])]) });
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
if (plan?.settingsSalvage.some((r) => r.source === layer && r.outcome === 'rejected') === true) {
|
|
563
|
+
appendOwnElement(out, { layer, how: 'rejected', key: JSON.stringify([layer, 'rejected', fnv1a(JSON.stringify(snap.doc))]) });
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
return out;
|
|
567
|
+
}
|
|
568
|
+
function notLoadedSentence(n, form) {
|
|
569
|
+
const layer = msg(`session.hostSettings.layer.${n.layer}`);
|
|
570
|
+
return renderMessage(msg(form === 'hold' ? `session.hostSettings.layerNotLoaded.hold.${n.how}` : 'session.hostSettings.layerNotLoaded.sent.unreadable', { layer }));
|
|
571
|
+
}
|
|
572
|
+
function settingsSideOf(input) {
|
|
573
|
+
let given;
|
|
574
|
+
let has;
|
|
575
|
+
try {
|
|
576
|
+
has = typeof input === 'object' && input !== null && Object.hasOwn(input, 'settings');
|
|
577
|
+
given = has ? input.settings : undefined;
|
|
578
|
+
}
|
|
579
|
+
catch {
|
|
580
|
+
throw new HostSettingsSourceShapeError('hostTurnSettings: reading input.settings threw — pass the HostSettingsSource for this turn, or \'none\'.');
|
|
581
|
+
}
|
|
582
|
+
if (!has || given === undefined)
|
|
583
|
+
return { kind: 'missing' };
|
|
584
|
+
if (given === 'none')
|
|
585
|
+
return { kind: 'none' };
|
|
586
|
+
return { kind: 'read', read: readHostSettingsOnce(given, 'hostTurnSettings') };
|
|
587
|
+
}
|
|
296
588
|
export function buildHostTurnSettings(input, judges) {
|
|
297
589
|
const materialize = judges.materialize;
|
|
298
590
|
let sources;
|
|
@@ -304,8 +596,28 @@ export function buildHostTurnSettings(input, judges) {
|
|
|
304
596
|
sourcesThrew = true;
|
|
305
597
|
}
|
|
306
598
|
const read = (key) => (sourcesThrew ? { kind: 'threw' } : readSource(sources, key));
|
|
307
|
-
|
|
308
|
-
let
|
|
599
|
+
let identityIn;
|
|
600
|
+
let previousIn;
|
|
601
|
+
try {
|
|
602
|
+
identityIn = input.identity;
|
|
603
|
+
previousIn = input.previous;
|
|
604
|
+
}
|
|
605
|
+
catch {
|
|
606
|
+
throw new HostSourceShapeError('hostTurnSettings: reading input.identity / input.previous threw (the value is not echoed).');
|
|
607
|
+
}
|
|
608
|
+
const surface = submissionSurfaceOf(identityIn);
|
|
609
|
+
if (surface === undefined)
|
|
610
|
+
throw new HostSourceShapeError('hostTurnSettings: identity must be the submission identity of this turn ({ surface, origin, tools }) — got something else (the value is not echoed).');
|
|
611
|
+
const session = sessionOf(previousIn);
|
|
612
|
+
const rawSide = settingsSideOf(input);
|
|
613
|
+
if (rawSide.kind === 'read')
|
|
614
|
+
for (const line of rawSide.read.debug)
|
|
615
|
+
hostLog('debug', line);
|
|
616
|
+
const adoption = rawSide.kind === 'read' ? adoptHostSettingsRead(rawSide.read, session, allowAdmittedFor(rawSide.read)) : undefined;
|
|
617
|
+
const side = adoption !== undefined ? { kind: 'read', read: adoption.read } : rawSide;
|
|
618
|
+
const nextSession = adoption?.session ?? remintSameContent(session);
|
|
619
|
+
const resolvedArm = permissionsArm(read('resolved'), side, adoption);
|
|
620
|
+
let resolvedCarried = resolvedArm.carried;
|
|
309
621
|
let resolvedError;
|
|
310
622
|
if (resolvedCarried !== undefined) {
|
|
311
623
|
try {
|
|
@@ -315,29 +627,182 @@ export function buildHostTurnSettings(input, judges) {
|
|
|
315
627
|
resolvedError = freeze({ error });
|
|
316
628
|
}
|
|
317
629
|
}
|
|
318
|
-
const hooks = hooksArm(read('hooks'));
|
|
319
|
-
const webSearch = webSearchArm(read('webSearch'));
|
|
320
|
-
const outputStyle =
|
|
321
|
-
const memory = memoryArm(read('memory'), judges.memoryOffDeclared);
|
|
630
|
+
const hooks = hooksArm(read('hooks'), side);
|
|
631
|
+
const webSearch = webSearchArm(read('webSearch'), side);
|
|
632
|
+
const outputStyle = outputStyleArm(read('outputStyle'), side);
|
|
633
|
+
const memory = memoryArm(read('memory'), side, judges.memoryOffDeclared);
|
|
322
634
|
const fileHistory = fileHistoryArm(read('fileHistory'));
|
|
323
|
-
|
|
635
|
+
let resolved = resolvedArm;
|
|
636
|
+
let armsByKey = [hooks, resolved, webSearch, outputStyle, memory, fileHistory];
|
|
637
|
+
if (side.kind === 'read' && MANAGED_READING_DISPOSITIONS[side.read.managed].commit === 'refuse') {
|
|
638
|
+
let said = false;
|
|
639
|
+
const managedArm = (a) => {
|
|
640
|
+
if (a.row.cause === 'host_port_missing' || a.row.cause === 'no_source')
|
|
641
|
+
return a;
|
|
642
|
+
const out = { row: freeze({ key: a.row.key, cause: 'source_unreadable', disposition: 'refuse_turn', layers: freeze(['policySettings']) }), notices: said ? [] : [notice('HS-MANAGED-UNREADABLE', 'turn')] };
|
|
643
|
+
said = true;
|
|
644
|
+
return out;
|
|
645
|
+
};
|
|
646
|
+
const hooksM = managedArm(hooks);
|
|
647
|
+
resolved = managedArm(resolved);
|
|
648
|
+
armsByKey = [{ ...hooksM, ...(hooks.plan !== undefined ? { plan: hooks.plan } : {}) }, resolved, managedArm(webSearch), outputStyle, memory, fileHistory];
|
|
649
|
+
}
|
|
650
|
+
if (adoption?.overflow === true) {
|
|
651
|
+
const over = (a) => (a.row.cause === 'host_port_missing' || a.row.cause === 'no_source' || a.row.disposition === 'refuse_turn' ? a : unreadableArm(a.row.key));
|
|
652
|
+
armsByKey = [{ ...over(armsByKey[0]), ...(hooks.plan !== undefined ? { plan: hooks.plan } : {}) }, over(armsByKey[1]), armsByKey[2], armsByKey[3], armsByKey[4], armsByKey[5]];
|
|
653
|
+
}
|
|
654
|
+
const heldLayer = (l) => adoption !== undefined && !adoption.trusted && (session.baseline?.loaded.some((k) => k.startsWith(`${l}|`)) ?? false);
|
|
655
|
+
const notLoaded = side.kind === 'read' ? notLoadedLayers(side.read, hooks.plan).filter((n) => !heldLayer(n.layer)) : [];
|
|
656
|
+
let consentKey;
|
|
657
|
+
const notLoadedNotices = [];
|
|
658
|
+
if (notLoaded.length > 0) {
|
|
659
|
+
const key = `hs1-${fnv1a(JSON.stringify(notLoaded.map((n) => n.key)))}`;
|
|
660
|
+
const ask = surface === 'interactive' && !session.consented.includes(key);
|
|
661
|
+
const layers = freeze(notLoaded.map((n) => n.layer));
|
|
662
|
+
const cause = notLoaded.some((n) => n.how === 'unreadable') ? 'source_unreadable' : 'source_rejected';
|
|
663
|
+
const reshape = (a) => {
|
|
664
|
+
const d = a.row.disposition;
|
|
665
|
+
if (d === 'refuse_turn' || d === 'unwired' || a.row.cause === 'no_source')
|
|
666
|
+
return a;
|
|
667
|
+
const disposition = ask ? 'hold_for_consent' : a.carried !== undefined ? 'carry_partial' : 'withhold_notice';
|
|
668
|
+
return { ...a, row: freeze({ key: a.row.key, cause, disposition, layers }) };
|
|
669
|
+
};
|
|
670
|
+
const before = armsByKey;
|
|
671
|
+
armsByKey = [{ ...reshape(before[0]), ...(hooks.plan !== undefined ? { plan: hooks.plan } : {}) }, reshape(before[1]), before[2], before[3], before[4], before[5]];
|
|
672
|
+
if (ask && armsByKey.slice(0, 2).some((a) => a.row.disposition === 'hold_for_consent'))
|
|
673
|
+
consentKey = key;
|
|
674
|
+
for (const n of notLoaded) {
|
|
675
|
+
if (consentKey !== undefined)
|
|
676
|
+
appendOwnElement(notLoadedNotices, notice('HS-LAYER-NOT-LOADED', 'turn', notLoadedSentence(n, 'hold')));
|
|
677
|
+
else if (n.how === 'unreadable')
|
|
678
|
+
appendOwnElement(notLoadedNotices, notice('HS-LAYER-NOT-LOADED', 'session', notLoadedSentence(n, 'sent')));
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
const heldNotices = [];
|
|
682
|
+
let held;
|
|
683
|
+
if (adoption?.held !== undefined) {
|
|
684
|
+
held = freeze({ wouldDrop: adoption.held.wouldDrop, version: nextSession.version });
|
|
685
|
+
const mark = (a) => (a.row.disposition === 'carry' && a.row.cause === 'carried' ? { ...a, row: freeze({ ...a.row, cause: 'held_previous' }) } : a);
|
|
686
|
+
armsByKey = [{ ...mark(armsByKey[0]), ...(hooks.plan !== undefined ? { plan: hooks.plan } : {}) }, mark(armsByKey[1]), armsByKey[2], armsByKey[3], armsByKey[4], armsByKey[5]];
|
|
687
|
+
appendOwnElement(heldNotices, notice('HS-HELD-PREVIOUS', 'diagnostic'));
|
|
688
|
+
}
|
|
689
|
+
const arms = armsByKey;
|
|
324
690
|
const rows = freeze(arms.map((a) => a.row));
|
|
325
|
-
const notices = freeze(arms.flatMap((a) => a.notices));
|
|
691
|
+
const notices = freeze([...arms.flatMap((a) => a.notices), ...notLoadedNotices, ...heldNotices]);
|
|
326
692
|
const refusal = arms.find((a) => a.row.disposition === 'refuse_turn');
|
|
327
|
-
const verdict = refusal
|
|
693
|
+
const verdict = refusal !== undefined
|
|
694
|
+
? freeze({ kind: 'refuse', notice: refusal.notices[0] ?? notices.find((n) => n.plane === 'turn') ?? notice('HS-PROJECTION', 'turn') })
|
|
695
|
+
: consentKey !== undefined
|
|
696
|
+
? freeze({ kind: 'hold', consentKey, notice: notLoadedNotices[0] })
|
|
697
|
+
: freeze({ kind: 'send' });
|
|
698
|
+
const carriedOf = (i) => {
|
|
699
|
+
const a = arms[i];
|
|
700
|
+
return a.row.disposition === 'carry' || a.row.disposition === 'carry_partial' || a.row.disposition === 'hold_for_consent' ? a.carried : undefined;
|
|
701
|
+
};
|
|
702
|
+
const hooksCarried = carriedOf(0);
|
|
703
|
+
const resolvedOut = arms[1]?.row.disposition === 'carry' || arms[1]?.row.disposition === 'carry_partial' || arms[1]?.row.disposition === 'hold_for_consent' ? resolvedCarried : undefined;
|
|
328
704
|
const carried = freeze({
|
|
329
|
-
...(
|
|
330
|
-
...(
|
|
331
|
-
...(
|
|
332
|
-
...(
|
|
333
|
-
...(
|
|
334
|
-
...(
|
|
705
|
+
...(hooksCarried !== undefined ? { hooks: hooksCarried } : {}),
|
|
706
|
+
...(resolvedOut !== undefined ? { resolved: resolvedOut } : {}),
|
|
707
|
+
...(carriedOf(2) !== undefined ? { webSearch: carriedOf(2) } : {}),
|
|
708
|
+
...(carriedOf(3) !== undefined ? { outputStyle: carriedOf(3) } : {}),
|
|
709
|
+
...(carriedOf(4) !== undefined ? { memory: 'off' } : {}),
|
|
710
|
+
...(carriedOf(5) !== undefined ? { fileHistory: 'disabled' } : {}),
|
|
335
711
|
});
|
|
336
|
-
const
|
|
337
|
-
|
|
712
|
+
const styleFacts = arms[3]?.row.disposition === 'carry' ? outputStyle.facts : undefined;
|
|
713
|
+
const product = { verdict, rows, notices, hooks: hooks.plan, carried, session: nextSession, outputStyle: styleFacts, held };
|
|
714
|
+
if (resolvedError !== undefined && resolvedOut !== undefined)
|
|
338
715
|
Object.defineProperty(product, RESOLVED_DEFERRED_ERROR, { value: resolvedError, enumerable: false });
|
|
716
|
+
const resolvedFinal = arms[1];
|
|
717
|
+
if (resolvedFinal?.refusalCause !== undefined && resolvedFinal.row.cause === 'projection_failed' && resolvedFinal.row.disposition === 'refuse_turn') {
|
|
718
|
+
Object.defineProperty(product, REFUSAL_CAUSE, { value: freeze({ key: resolvedFinal.row.key, error: resolvedFinal.refusalCause.error }), enumerable: false });
|
|
719
|
+
}
|
|
720
|
+
if (adoption?.held?.candidate !== undefined)
|
|
721
|
+
Object.defineProperty(product, ACCEPT_CANDIDATE, { value: adoption.held.candidate, enumerable: false });
|
|
339
722
|
return mint(freeze(product));
|
|
340
723
|
}
|
|
724
|
+
export function hostSettingsConsent(product) {
|
|
725
|
+
const snap = hostTurnSettingsOf(product);
|
|
726
|
+
if (snap === undefined || snap === UNWIRED_HOST_TURN_SETTINGS)
|
|
727
|
+
throw new HostSourceShapeError('hostSettingsConsent: pass the product returned by hostTurnSettings() for this turn (the value is not echoed).');
|
|
728
|
+
const p = snap;
|
|
729
|
+
if (p.verdict.kind !== 'hold')
|
|
730
|
+
return product;
|
|
731
|
+
const key = p.verdict.consentKey;
|
|
732
|
+
const rows = freeze(p.rows.map((r) => r.disposition !== 'hold_for_consent'
|
|
733
|
+
? r
|
|
734
|
+
: freeze({ ...r, disposition: (Object.hasOwn(p.carried, carriedKeyOf(r.key)) ? 'carry_partial' : 'withhold_notice') })));
|
|
735
|
+
const notices = freeze(p.notices.filter((n) => !(n.id === 'HS-LAYER-NOT-LOADED' && n.plane === 'turn')));
|
|
736
|
+
const session = mintHostSettingsSession(p.session.parent, [...p.session.consented, key], p.session.baseline);
|
|
737
|
+
if (session === undefined)
|
|
738
|
+
return product;
|
|
739
|
+
return mint(freeze({ verdict: freeze({ kind: 'send' }), rows, notices, hooks: p.hooks, carried: p.carried, session, outputStyle: p.outputStyle, held: p.held }));
|
|
740
|
+
}
|
|
741
|
+
const ACCEPT_CANDIDATE = Symbol('hostTurnSettings.acceptCandidate');
|
|
742
|
+
export function hostSettingsAcceptCurrent(product, confirmation) {
|
|
743
|
+
const c = captureConfirmation(confirmation);
|
|
744
|
+
if (c === undefined)
|
|
745
|
+
throw new HostSourceShapeError('hostSettingsAcceptCurrent: confirmation must be { version, deny, ask } — the session version of the product the user saw (held.version) and the deny / ask rules the user confirmed to stop sending (the value is not echoed).');
|
|
746
|
+
let candidate;
|
|
747
|
+
let held;
|
|
748
|
+
try {
|
|
749
|
+
if (typeof product !== 'object' || product === null)
|
|
750
|
+
return undefined;
|
|
751
|
+
const d = Object.getOwnPropertyDescriptor(product, ACCEPT_CANDIDATE);
|
|
752
|
+
candidate = d !== undefined && Object.hasOwn(d, 'value') ? d.value : undefined;
|
|
753
|
+
const h = Object.getOwnPropertyDescriptor(product, 'held');
|
|
754
|
+
held = h !== undefined && Object.hasOwn(h, 'value') ? h.value : undefined;
|
|
755
|
+
}
|
|
756
|
+
catch {
|
|
757
|
+
return undefined;
|
|
758
|
+
}
|
|
759
|
+
if (candidate === undefined || !isRecordShape(held))
|
|
760
|
+
return undefined;
|
|
761
|
+
const h = held;
|
|
762
|
+
if (h.version !== c.version)
|
|
763
|
+
return undefined;
|
|
764
|
+
const wd = h.wouldDrop;
|
|
765
|
+
if (!isRecordShape(wd) || !Array.isArray(wd.deny) || !Array.isArray(wd.ask))
|
|
766
|
+
return undefined;
|
|
767
|
+
if (!wd.deny.every((r) => typeof r === 'string' && c.deny.includes(r)))
|
|
768
|
+
return undefined;
|
|
769
|
+
if (!wd.ask.every((r) => typeof r === 'string' && c.ask.includes(r)))
|
|
770
|
+
return undefined;
|
|
771
|
+
return candidate;
|
|
772
|
+
}
|
|
773
|
+
function captureConfirmation(v) {
|
|
774
|
+
const version = ownDataOf(v, 'version');
|
|
775
|
+
const deny = ownDataOf(v, 'deny');
|
|
776
|
+
const ask = ownDataOf(v, 'ask');
|
|
777
|
+
if (!version.ok || !deny.ok || !ask.ok || typeof version.value !== 'string' || version.value.length === 0)
|
|
778
|
+
return undefined;
|
|
779
|
+
const strs = (x) => {
|
|
780
|
+
try {
|
|
781
|
+
if (!Array.isArray(x))
|
|
782
|
+
return undefined;
|
|
783
|
+
const ld = Object.getOwnPropertyDescriptor(x, 'length');
|
|
784
|
+
if (ld === undefined || !Object.hasOwn(ld, 'value') || typeof ld.value !== 'number' || !Number.isSafeInteger(ld.value) || ld.value < 0 || ld.value > 100_000)
|
|
785
|
+
return undefined;
|
|
786
|
+
const len = ld.value;
|
|
787
|
+
const out = [];
|
|
788
|
+
for (let i = 0; i < len; i++) {
|
|
789
|
+
const d = Object.getOwnPropertyDescriptor(x, i);
|
|
790
|
+
if (d === undefined || !Object.hasOwn(d, 'value') || typeof d.value !== 'string')
|
|
791
|
+
return undefined;
|
|
792
|
+
appendOwnElement(out, d.value);
|
|
793
|
+
}
|
|
794
|
+
return out;
|
|
795
|
+
}
|
|
796
|
+
catch {
|
|
797
|
+
return undefined;
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
const dn = strs(deny.value);
|
|
801
|
+
const ak = strs(ask.value);
|
|
802
|
+
if (dn === undefined || ak === undefined)
|
|
803
|
+
return undefined;
|
|
804
|
+
return freeze({ version: version.value, deny: freeze(dn), ask: freeze(ak) });
|
|
805
|
+
}
|
|
341
806
|
export function hostSettingsSelfCheck(product) {
|
|
342
807
|
try {
|
|
343
808
|
const rows = product.rows;
|
|
@@ -350,11 +815,11 @@ export function hostSettingsSelfCheck(product) {
|
|
|
350
815
|
continue;
|
|
351
816
|
seen.add(r.key);
|
|
352
817
|
if (r.disposition === 'unwired' && HOST_SUPPLIED_KEYS.includes(r.key))
|
|
353
|
-
out
|
|
818
|
+
appendOwnElement(out, r.key);
|
|
354
819
|
}
|
|
355
820
|
for (const k of HOST_SUPPLIED_KEYS)
|
|
356
821
|
if (!seen.has(k) && !out.includes(k))
|
|
357
|
-
out
|
|
822
|
+
appendOwnElement(out, k);
|
|
358
823
|
return freeze(out);
|
|
359
824
|
}
|
|
360
825
|
catch {
|
|
@@ -362,6 +827,7 @@ export function hostSettingsSelfCheck(product) {
|
|
|
362
827
|
}
|
|
363
828
|
}
|
|
364
829
|
export const hostProjectionNotice = () => notice('HS-PROJECTION', 'turn');
|
|
830
|
+
export const hostFileHistoryRestoreNotice = () => notice('HS-FILEHISTORY-RESTORE', 'turn');
|
|
365
831
|
export class HostSettingsRefused extends Error {
|
|
366
832
|
notice;
|
|
367
833
|
constructor(n) {
|
|
@@ -412,21 +878,28 @@ export function hostTurnSettingsOf(v, depth = 'full') {
|
|
|
412
878
|
if (carried.fileHistory !== undefined && carried.fileHistory !== 'disabled')
|
|
413
879
|
return undefined;
|
|
414
880
|
let refuses = false;
|
|
881
|
+
let holds = false;
|
|
415
882
|
for (const [i, r] of rows.entries()) {
|
|
416
883
|
const disposition = r.disposition;
|
|
417
884
|
if (!HOST_SETTING_DISPOSITIONS.includes(disposition))
|
|
418
885
|
return undefined;
|
|
419
886
|
if (disposition === 'refuse_turn')
|
|
420
887
|
refuses = true;
|
|
888
|
+
if (disposition === 'hold_for_consent')
|
|
889
|
+
holds = true;
|
|
890
|
+
if (r.cause === 'projection_failed' && disposition !== 'refuse_turn')
|
|
891
|
+
return undefined;
|
|
421
892
|
const sub = subs[i] ?? '';
|
|
422
893
|
const has = Object.hasOwn(carried, sub) && carried[sub] !== undefined;
|
|
423
|
-
if (has !== CARRYING.has(disposition))
|
|
894
|
+
if (disposition !== 'hold_for_consent' && has !== CARRYING.has(disposition))
|
|
424
895
|
return undefined;
|
|
425
896
|
}
|
|
426
897
|
const verdict = p.verdict;
|
|
427
|
-
if (verdict.kind !== (refuses ? 'refuse' : 'send'))
|
|
898
|
+
if (verdict.kind !== (refuses ? 'refuse' : holds ? 'hold' : 'send'))
|
|
428
899
|
return undefined;
|
|
429
|
-
if (refuses && !(isRecordShape(verdict.notice) && typeof verdict.notice.text === 'string'))
|
|
900
|
+
if ((refuses || holds) && !(isRecordShape(verdict.notice) && typeof verdict.notice.text === 'string'))
|
|
901
|
+
return undefined;
|
|
902
|
+
if (!refuses && holds && typeof verdict.consentKey !== 'string')
|
|
430
903
|
return undefined;
|
|
431
904
|
if (Object.hasOwn(carried, 'hooks') && carried.hooks !== undefined && !hooksPassJudge(carried.hooks))
|
|
432
905
|
return undefined;
|
|
@@ -517,12 +990,12 @@ function intersectHostHooksUnguarded(sentIn, nowIn) {
|
|
|
517
990
|
if (at < 0)
|
|
518
991
|
continue;
|
|
519
992
|
slot.left.splice(at, 1);
|
|
520
|
-
keep
|
|
993
|
+
appendOwnElement(keep, entry);
|
|
521
994
|
break;
|
|
522
995
|
}
|
|
523
996
|
}
|
|
524
997
|
if (keep.length > 0)
|
|
525
|
-
evOut
|
|
998
|
+
appendOwnElement(evOut, { ...head, hooks: keep });
|
|
526
999
|
kept += keep.length;
|
|
527
1000
|
}
|
|
528
1001
|
if (evOut.length > 0)
|
|
@@ -532,20 +1005,19 @@ function intersectHostHooksUnguarded(sentIn, nowIn) {
|
|
|
532
1005
|
return { hooks, dropped: total - kept, judged: hooks === undefined || hooksPassJudge(hooks) };
|
|
533
1006
|
}
|
|
534
1007
|
function ownDataOf(o, k) {
|
|
1008
|
+
if (typeof o !== 'object' || o === null)
|
|
1009
|
+
return { ok: false };
|
|
535
1010
|
try {
|
|
536
|
-
|
|
537
|
-
return { ok: false };
|
|
538
|
-
const d = Object.getOwnPropertyDescriptor(o, k);
|
|
539
|
-
if (d === undefined)
|
|
540
|
-
return { ok: true, value: undefined };
|
|
541
|
-
if (!('value' in d))
|
|
542
|
-
return { ok: false };
|
|
543
|
-
return { ok: true, value: d.value };
|
|
1011
|
+
return { ok: true, value: ownDataField(o, k) };
|
|
544
1012
|
}
|
|
545
1013
|
catch {
|
|
546
1014
|
return { ok: false };
|
|
547
1015
|
}
|
|
548
1016
|
}
|
|
1017
|
+
function managedOnlySwitchOn(policyDoc) {
|
|
1018
|
+
const r = ownDataOf(policyDoc, 'allowManagedPermissionRulesOnly');
|
|
1019
|
+
return r.ok && r.value === true;
|
|
1020
|
+
}
|
|
549
1021
|
function noticeCopyOf(n) {
|
|
550
1022
|
const id = ownDataOf(n, 'id');
|
|
551
1023
|
const plane = ownDataOf(n, 'plane');
|
|
@@ -576,7 +1048,7 @@ function turnNoticesUnguarded(product) {
|
|
|
576
1048
|
if (copy === undefined)
|
|
577
1049
|
return undefined;
|
|
578
1050
|
if (copy.plane === 'turn')
|
|
579
|
-
out
|
|
1051
|
+
appendOwnElement(out, copy);
|
|
580
1052
|
}
|
|
581
1053
|
return freeze(out);
|
|
582
1054
|
}
|
|
@@ -605,6 +1077,7 @@ function intakeSnapshotUnguarded(product, onResolved) {
|
|
|
605
1077
|
refusingKeys: freeze([]),
|
|
606
1078
|
turnNotices: freeze([]),
|
|
607
1079
|
notice: undefined,
|
|
1080
|
+
refusalCause: undefined,
|
|
608
1081
|
});
|
|
609
1082
|
}
|
|
610
1083
|
const c = ownDataOf(product, 'carried');
|
|
@@ -640,6 +1113,7 @@ function intakeSnapshotUnguarded(product, onResolved) {
|
|
|
640
1113
|
if (!rowsR.ok || !Array.isArray(rowsR.value) || rowsR.value.length !== HOST_SUPPLIED_KEYS.length)
|
|
641
1114
|
return undefined;
|
|
642
1115
|
let refuses = false;
|
|
1116
|
+
let anyRefuse = false;
|
|
643
1117
|
const refusingKeys = [];
|
|
644
1118
|
const dispositions = {};
|
|
645
1119
|
for (const [i, key] of HOST_SUPPLIED_KEYS.entries()) {
|
|
@@ -650,12 +1124,17 @@ function intakeSnapshotUnguarded(product, onResolved) {
|
|
|
650
1124
|
const d = ownDataOf(rowR.value, 'disposition');
|
|
651
1125
|
if (!k.ok || !d.ok || k.value !== key || !HOST_SETTING_DISPOSITIONS.includes(d.value))
|
|
652
1126
|
return undefined;
|
|
653
|
-
|
|
1127
|
+
const cause = ownDataOf(rowR.value, 'cause');
|
|
1128
|
+
if (!cause.ok || (cause.value === 'projection_failed' && d.value !== 'refuse_turn'))
|
|
1129
|
+
return undefined;
|
|
1130
|
+
if (d.value === 'refuse_turn' || d.value === 'hold_for_consent') {
|
|
654
1131
|
refuses = true;
|
|
655
|
-
refusingKeys
|
|
1132
|
+
appendOwnElement(refusingKeys, key);
|
|
656
1133
|
}
|
|
1134
|
+
if (d.value === 'refuse_turn')
|
|
1135
|
+
anyRefuse = true;
|
|
657
1136
|
dispositions[key] = d.value;
|
|
658
|
-
if ((values[carriedKeyOf(key)] !== undefined) !== CARRYING.has(d.value))
|
|
1137
|
+
if (d.value !== 'hold_for_consent' && (values[carriedKeyOf(key)] !== undefined) !== CARRYING.has(d.value))
|
|
659
1138
|
return undefined;
|
|
660
1139
|
}
|
|
661
1140
|
if (values.memory !== undefined && values.memory !== 'off')
|
|
@@ -668,7 +1147,7 @@ function intakeSnapshotUnguarded(product, onResolved) {
|
|
|
668
1147
|
if (!v.ok)
|
|
669
1148
|
return undefined;
|
|
670
1149
|
const kind = ownDataOf(v.value, 'kind');
|
|
671
|
-
if (!kind.ok || kind.value !== (
|
|
1150
|
+
if (!kind.ok || kind.value !== (anyRefuse ? 'refuse' : refuses ? 'hold' : 'send'))
|
|
672
1151
|
return undefined;
|
|
673
1152
|
const noticeR = refuses ? ownDataOf(v.value, 'notice') : undefined;
|
|
674
1153
|
const notice = noticeR === undefined ? undefined : ((noticeR.ok ? noticeCopyOf(noticeR.value) : undefined) ?? hostProjectionNotice());
|
|
@@ -679,9 +1158,27 @@ function intakeSnapshotUnguarded(product, onResolved) {
|
|
|
679
1158
|
refusingKeys: freeze(refusingKeys),
|
|
680
1159
|
turnNotices: turnNoticesOf(product),
|
|
681
1160
|
notice,
|
|
1161
|
+
refusalCause: anyRefuse ? refusalCauseOf(product) : undefined,
|
|
682
1162
|
});
|
|
683
1163
|
}
|
|
684
|
-
|
|
1164
|
+
function refusalCauseOf(product) {
|
|
1165
|
+
try {
|
|
1166
|
+
const d = Object.getOwnPropertyDescriptor(product, REFUSAL_CAUSE);
|
|
1167
|
+
return d !== undefined && Object.hasOwn(d, 'value') ? d.value : undefined;
|
|
1168
|
+
}
|
|
1169
|
+
catch {
|
|
1170
|
+
return undefined;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
export function hostSettingsRefusedError(n, intake, firstSeatedKey) {
|
|
1174
|
+
const e = new HostSettingsRefused(n);
|
|
1175
|
+
const cause = intake.refusalCause;
|
|
1176
|
+
if (cause !== undefined && firstSeatedKey === cause.key && n.id === 'HS-PROJECTION')
|
|
1177
|
+
Object.defineProperty(e, 'cause', { value: cause.error, writable: true, enumerable: false, configurable: true });
|
|
1178
|
+
return e;
|
|
1179
|
+
}
|
|
1180
|
+
const UNWIRED_IDENTITY = Object.freeze({ surface: 'print', origin: 'user', tools: 'full' });
|
|
1181
|
+
export const UNWIRED_HOST_TURN_SETTINGS = buildHostTurnSettings({ sources: {}, identity: UNWIRED_IDENTITY }, {
|
|
685
1182
|
materialize: (snapshot) => snapshot,
|
|
686
1183
|
memoryOffDeclared: () => false,
|
|
687
1184
|
});
|