@sema-agent/client-core 0.100.0 → 0.101.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. package/CHANGELOG.md +395 -0
  2. package/README.md +164 -117
  3. package/dist/adapt/arms.js +51 -16
  4. package/dist/adapt/textStream.js +7 -4
  5. package/dist/adapt/toolCards.js +9 -8
  6. package/dist/adapt.js +7 -1
  7. package/dist/adapter/activeRunSelfHeal.d.ts +24 -2
  8. package/dist/adapter/activeRunSelfHeal.js +108 -6
  9. package/dist/adapter/downstream/eventToSdkMessage.js +33 -12
  10. package/dist/adapter/downstream/terminalToSdkResult.d.ts +60 -1
  11. package/dist/adapter/downstream/terminalToSdkResult.js +209 -39
  12. package/dist/adapter/runStream.d.ts +4 -4
  13. package/dist/adapter/runStream.js +158 -43
  14. package/dist/agentsWireCaps.d.ts +2 -7
  15. package/dist/agentsWireCaps.js +1 -2
  16. package/dist/approvalDecidedByCapability.js +2 -2
  17. package/dist/approvalFrameFamilies.d.ts +33 -0
  18. package/dist/approvalFrameFamilies.js +120 -0
  19. package/dist/approvalsStreamLiveCapability.js +2 -2
  20. package/dist/attachmentsWireCaps.js +41 -13
  21. package/dist/callerCwdCapability.js +2 -2
  22. package/dist/centerWiringCapability.js +2 -2
  23. package/dist/clockReading.d.ts +2 -0
  24. package/dist/clockReading.js +4 -0
  25. package/dist/cloudConfigWireCaps.d.ts +19 -5
  26. package/dist/cloudConfigWireCaps.js +193 -56
  27. package/dist/coreValuePorts.d.ts +12 -2
  28. package/dist/coreValuePorts.js +9 -0
  29. package/dist/decideFailureNote.js +5 -3
  30. package/dist/decideReceipt.js +2 -2
  31. package/dist/deviceExecutorManagementCapability.js +2 -2
  32. package/dist/deviceFlowPolling.js +1 -1
  33. package/dist/disableSkillsWire.d.ts +1 -1
  34. package/dist/disableSkillsWire.js +4 -3
  35. package/dist/displayUntrusted.d.ts +1 -0
  36. package/dist/displayUntrusted.js +65 -8
  37. package/dist/engineCapReader.js +1 -1
  38. package/dist/engineConfigDrift.js +1 -1
  39. package/dist/engineErrorCodes.d.ts +14 -5
  40. package/dist/engineErrorCodes.js +27 -6
  41. package/dist/engineGenerationConvergence.d.ts +39 -0
  42. package/dist/engineGenerationConvergence.js +95 -0
  43. package/dist/engineGenerationPort.d.ts +61 -0
  44. package/dist/engineGenerationPort.js +144 -0
  45. package/dist/engineHealthFacts.d.ts +23 -0
  46. package/dist/engineHealthFacts.js +92 -0
  47. package/dist/engineIdentity.d.ts +4 -0
  48. package/dist/engineIdentity.js +11 -0
  49. package/dist/engineNoticeCodes.d.ts +2 -5
  50. package/dist/engineRowRef.js +3 -0
  51. package/dist/engineSessionMessages.js +2 -2
  52. package/dist/engineToolDirectory.js +2 -2
  53. package/dist/engineWireFor.d.ts +99 -0
  54. package/dist/engineWireFor.js +248 -6
  55. package/dist/engineWireTarget.d.ts +1 -0
  56. package/dist/engineWireTarget.js +8 -0
  57. package/dist/env/uiLanguage.js +1 -1
  58. package/dist/errorSupplementRoles.d.ts +3 -0
  59. package/dist/errorSupplementRoles.js +37 -0
  60. package/dist/executionLaneCapability.js +2 -2
  61. package/dist/fileHistoryCaptureCapability.js +3 -3
  62. package/dist/finalVerifyWire.d.ts +6 -3
  63. package/dist/finalVerifyWire.js +6 -23
  64. package/dist/flagInput.d.ts +4 -0
  65. package/dist/flagInput.js +24 -0
  66. package/dist/fleet/fleetLedger.js +5 -2
  67. package/dist/fleet/fleetProjection.d.ts +1 -0
  68. package/dist/fleet/fleetProjection.js +15 -2
  69. package/dist/gateVocabulary.js +3 -0
  70. package/dist/generated/engineFactTables.d.ts +7 -3
  71. package/dist/generated/engineFactTables.js +52 -0
  72. package/dist/generated/engineNoticeTables.js +12 -0
  73. package/dist/generated/settingsSchemaActiveTiers.d.ts +1 -0
  74. package/dist/generated/settingsSchemaActiveTiers.js +14 -0
  75. package/dist/generated/settingsSchemaCallerTextEcho.d.ts +1 -0
  76. package/dist/generated/settingsSchemaCallerTextEcho.js +8 -0
  77. package/dist/generated/settingsSchemaControlAndBidi.d.ts +1 -0
  78. package/dist/generated/settingsSchemaControlAndBidi.js +8 -0
  79. package/dist/generated/settingsSchemaDefaultModel.d.ts +11 -0
  80. package/dist/generated/settingsSchemaDefaultModel.js +25 -0
  81. package/dist/generated/settingsSchemaFns.d.ts +54 -0
  82. package/dist/generated/settingsSchemaFns.js +26 -1
  83. package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -1
  84. package/dist/generated/settingsSchemaMcpRequestEntry.js +1 -7
  85. package/dist/generated/settingsSchemaSafetyMergeSpec.d.ts +1 -0
  86. package/dist/generated/settingsSchemaSafetyMergeSpec.js +95 -0
  87. package/dist/generated/settingsSchemaSettingsSources.d.ts +1 -0
  88. package/dist/generated/settingsSchemaSettingsSources.js +58 -0
  89. package/dist/generated/settingsSchemaTables.d.ts +2 -0
  90. package/dist/generated/settingsSchemaTables.js +13 -0
  91. package/dist/generated/settingsSchemaUrlPattern.d.ts +1 -0
  92. package/dist/generated/settingsSchemaUrlPattern.js +183 -0
  93. package/dist/headlessPermissionModeWire.d.ts +18 -2
  94. package/dist/headlessPermissionModeWire.js +30 -19
  95. package/dist/hitl/allowRuleShadow.js +7 -5
  96. package/dist/hitl/approvalCardReading.d.ts +3 -0
  97. package/dist/hitl/approvalCardReading.js +17 -0
  98. package/dist/hitl/approvalCompleteParked.js +1 -1
  99. package/dist/hitl/approvalDelivery.d.ts +87 -0
  100. package/dist/hitl/approvalDelivery.js +193 -0
  101. package/dist/hitl/approvalResolution.d.ts +11 -0
  102. package/dist/hitl/approvalResolution.js +50 -11
  103. package/dist/hitl/askClassPair.d.ts +6 -0
  104. package/dist/hitl/askClassPair.js +30 -3
  105. package/dist/hitl/askParkAutoReopenBlock.d.ts +30 -0
  106. package/dist/hitl/askParkAutoReopenBlock.js +117 -0
  107. package/dist/hitl/askParkRowRouting.js +4 -1
  108. package/dist/hitl/attributionLadder.d.ts +42 -3
  109. package/dist/hitl/attributionLadder.js +79 -8
  110. package/dist/hitl/automaticAnswerVerdict.d.ts +6 -1
  111. package/dist/hitl/automaticAnswerVerdict.js +46 -11
  112. package/dist/hitl/crashConverged.js +2 -2
  113. package/dist/hitl/decisionConflict.d.ts +6 -2
  114. package/dist/hitl/decisionConflict.js +24 -9
  115. package/dist/hitl/decisionRefusal.d.ts +20 -10
  116. package/dist/hitl/decisionRefusal.js +99 -54
  117. package/dist/hitl/decisionSend.d.ts +3 -0
  118. package/dist/hitl/decisionSend.js +87 -103
  119. package/dist/hitl/frameRouter.d.ts +1 -0
  120. package/dist/hitl/frameRouter.js +9 -2
  121. package/dist/hitl/hitlBridge.d.ts +18 -6
  122. package/dist/hitl/hitlBridge.js +41 -37
  123. package/dist/hitl/livePendingAsk.js +4 -3
  124. package/dist/hitl/noAllowCause.js +1 -1
  125. package/dist/hitl/parkResolver.js +3 -2
  126. package/dist/hitl/persistedRulesWire.js +1 -0
  127. package/dist/hitl/planReviewWire.d.ts +4 -0
  128. package/dist/hitl/planReviewWire.js +59 -30
  129. package/dist/hitl/resumeRunningCard.d.ts +3 -2
  130. package/dist/hitl/resumeRunningCard.js +17 -11
  131. package/dist/hitl/sessionPolicyDeliverable.d.ts +5 -2
  132. package/dist/hitl/sessionPolicyDeliverable.js +62 -29
  133. package/dist/hitl/sessionPolicyWire.d.ts +13 -3
  134. package/dist/hitl/sessionPolicyWire.js +81 -16
  135. package/dist/hitl/standingRows.js +1 -1
  136. package/dist/hitl/toolApprovalWire.d.ts +9 -10
  137. package/dist/hitl/toolApprovalWire.js +72 -54
  138. package/dist/hookMatcherVerdict.d.ts +2 -0
  139. package/dist/hookMatcherVerdict.js +12 -0
  140. package/dist/hooksCompactTransition.d.ts +19 -0
  141. package/dist/hooksCompactTransition.js +41 -0
  142. package/dist/hooksWireCaps.d.ts +1 -1
  143. package/dist/hooksWireCaps.js +202 -203
  144. package/dist/host.d.ts +1 -14
  145. package/dist/host.js +0 -8
  146. package/dist/hostCallbackGuard.d.ts +1 -0
  147. package/dist/hostCallbackGuard.js +1 -1
  148. package/dist/hostSettingsSource.d.ts +172 -0
  149. package/dist/hostSettingsSource.js +675 -0
  150. package/dist/hostTurnSettings.d.ts +73 -17
  151. package/dist/hostTurnSettings.js +594 -97
  152. package/dist/httpHookPolicy.d.ts +37 -0
  153. package/dist/httpHookPolicy.js +176 -0
  154. package/dist/humanTurn.d.ts +2 -1
  155. package/dist/humanTurn.js +37 -7
  156. package/dist/humanTurnRead.js +4 -3
  157. package/dist/humanTurnSentences.d.ts +10 -0
  158. package/dist/humanTurnSentences.js +74 -0
  159. package/dist/i18n/messages.en.d.ts +184 -2
  160. package/dist/i18n/messages.en.js +187 -5
  161. package/dist/i18n/messages.zh.js +197 -5
  162. package/dist/i18n/translate.js +3 -3
  163. package/dist/index.d.ts +69 -15
  164. package/dist/index.js +45 -13
  165. package/dist/inheritEnvCapability.d.ts +3 -1
  166. package/dist/inheritEnvCapability.js +31 -17
  167. package/dist/inheritEnvWire.d.ts +2 -1
  168. package/dist/inheritEnvWire.js +11 -5
  169. package/dist/interactiveToolsWire.d.ts +4 -2
  170. package/dist/interactiveToolsWire.js +5 -5
  171. package/dist/jsonFaithful.d.ts +20 -0
  172. package/dist/jsonFaithful.js +152 -0
  173. package/dist/limitsWire.d.ts +7 -2
  174. package/dist/limitsWire.js +19 -13
  175. package/dist/liveInitToolFace.d.ts +6 -1
  176. package/dist/liveInitToolFace.js +5 -3
  177. package/dist/liveModelCatalog.d.ts +22 -0
  178. package/dist/liveModelCatalog.js +132 -18
  179. package/dist/mcpPanel.js +1 -1
  180. package/dist/mcpProbeCapability.js +2 -2
  181. package/dist/mcpStatusSupersetKeys.d.ts +24 -0
  182. package/dist/mcpStatusSupersetKeys.js +45 -0
  183. package/dist/mcpToolToggles.js +2 -1
  184. package/dist/mcpWireCaps.d.ts +39 -1
  185. package/dist/mcpWireCaps.js +254 -50
  186. package/dist/memoryComplianceCapability.js +2 -2
  187. package/dist/memoryOriginCapability.js +2 -2
  188. package/dist/model/catalogDefault.d.ts +24 -0
  189. package/dist/model/catalogDefault.js +4 -0
  190. package/dist/model/liveCatalogShape.js +5 -4
  191. package/dist/model/modelsPolicy.js +4 -3
  192. package/dist/model/onboardJudgement.d.ts +1 -0
  193. package/dist/model/onboardJudgement.js +1 -1
  194. package/dist/model/subagentModelWord.js +2 -2
  195. package/dist/modelCapabilityProbe.js +6 -6
  196. package/dist/modelIdentityResolvability.d.ts +10 -1
  197. package/dist/modelIdentityResolvability.js +62 -39
  198. package/dist/modsKernelIdentity.d.ts +10 -0
  199. package/dist/modsKernelIdentity.js +103 -0
  200. package/dist/modsKernelTransit.d.ts +8 -0
  201. package/dist/modsKernelTransit.js +6 -0
  202. package/dist/notifications.d.ts +30 -12
  203. package/dist/notifications.js +241 -53
  204. package/dist/outputStyleSeatCapability.js +2 -2
  205. package/dist/ownKey.d.ts +11 -0
  206. package/dist/ownKey.js +164 -3
  207. package/dist/panelReduce.js +1 -1
  208. package/dist/peerFrames.d.ts +1 -1
  209. package/dist/peerFrames.js +6 -2
  210. package/dist/peerLaneCapability.js +2 -2
  211. package/dist/permissionModesCapability.js +4 -4
  212. package/dist/permissionRuleIssue.js +2 -0
  213. package/dist/permissionRulesWriteCapability.js +2 -2
  214. package/dist/permissionsAllowGrantCapability.js +2 -2
  215. package/dist/permissionsDeclaration.d.ts +43 -4
  216. package/dist/permissionsDeclaration.js +102 -35
  217. package/dist/pluginHooksWire.d.ts +20 -4
  218. package/dist/pluginHooksWire.js +92 -53
  219. package/dist/prepareRefusal.d.ts +3 -2
  220. package/dist/prepareRefusal.js +27 -9
  221. package/dist/printInitToolFace.js +2 -2
  222. package/dist/printModelStatus.js +1 -1
  223. package/dist/projectMemory.d.ts +32 -0
  224. package/dist/projectMemory.js +70 -0
  225. package/dist/promptBlockedCopy.d.ts +2 -1
  226. package/dist/promptBlockedCopy.js +2 -1
  227. package/dist/promptDelivery.d.ts +23 -3
  228. package/dist/promptDelivery.js +169 -30
  229. package/dist/providerRejection.d.ts +19 -1
  230. package/dist/providerRejection.js +75 -4
  231. package/dist/queuedDelivery.d.ts +48 -0
  232. package/dist/queuedDelivery.js +233 -0
  233. package/dist/reattachWindow.d.ts +94 -0
  234. package/dist/reattachWindow.js +127 -0
  235. package/dist/request/printNotification.d.ts +1 -1
  236. package/dist/request/printNotification.js +5 -1
  237. package/dist/request/submissionIdentity.d.ts +37 -0
  238. package/dist/request/submissionIdentity.js +65 -0
  239. package/dist/request/taskRequest.d.ts +12 -4
  240. package/dist/request/taskRequest.js +221 -152
  241. package/dist/resultFrameKeys.d.ts +1 -0
  242. package/dist/resultFrameKeys.js +4 -1
  243. package/dist/retryStatus.d.ts +8 -0
  244. package/dist/retryStatus.js +57 -9
  245. package/dist/rewindArchiveCapability.js +2 -2
  246. package/dist/rewindEngineAction.d.ts +2 -0
  247. package/dist/rewindEngineAction.js +23 -1
  248. package/dist/rowKind.d.ts +36 -0
  249. package/dist/rowKind.js +97 -0
  250. package/dist/ruleCompileVerdict.d.ts +18 -0
  251. package/dist/ruleCompileVerdict.js +67 -2
  252. package/dist/ruleReadings.d.ts +58 -0
  253. package/dist/ruleReadings.js +132 -0
  254. package/dist/ruleRefusalSentence.d.ts +4 -0
  255. package/dist/ruleRefusalSentence.js +9 -3
  256. package/dist/runCancelContext.d.ts +0 -1
  257. package/dist/runCancelContext.js +1 -2
  258. package/dist/runTerminal.d.ts +5 -0
  259. package/dist/runTerminal.js +52 -17
  260. package/dist/sandboxWire.d.ts +1 -1
  261. package/dist/sandboxWire.js +4 -6
  262. package/dist/scenarioRefusal.js +1 -1
  263. package/dist/scenarioSkills.d.ts +20 -0
  264. package/dist/scenarioSkills.js +72 -0
  265. package/dist/scenarioWire.d.ts +5 -2
  266. package/dist/scenarioWire.js +9 -9
  267. package/dist/sealedKeyCapability.js +2 -2
  268. package/dist/seam.d.ts +2 -0
  269. package/dist/seam.js +2 -2
  270. package/dist/seatContract.d.ts +46 -1
  271. package/dist/seatContract.js +49 -19
  272. package/dist/selfOrchestrationDenial.js +1 -1
  273. package/dist/sessionPolicyCapability.js +2 -2
  274. package/dist/sessionRulesChildrenReadLive.d.ts +6 -0
  275. package/dist/sessionRulesChildrenReadLive.js +5 -0
  276. package/dist/sessionRulesNamespaceFormsCapability.d.ts +12 -0
  277. package/dist/sessionRulesNamespaceFormsCapability.js +29 -0
  278. package/dist/sessionSyncFileHistoryCapability.js +2 -2
  279. package/dist/settingsCredentialKeyPaths.js +60 -5
  280. package/dist/settingsHooksSalvage.d.ts +1 -0
  281. package/dist/settingsHooksSalvage.js +7 -1
  282. package/dist/settingsLayerAdmission.d.ts +4 -0
  283. package/dist/settingsLayerAdmission.js +16 -0
  284. package/dist/skillToolListsCapability.js +6 -5
  285. package/dist/skillsWireCaps.d.ts +14 -0
  286. package/dist/skillsWireCaps.js +47 -16
  287. package/dist/slashCommandGate.d.ts +24 -0
  288. package/dist/slashCommandGate.js +74 -0
  289. package/dist/slashCommandTable.d.ts +14 -0
  290. package/dist/slashCommandTable.js +99 -0
  291. package/dist/sqlEngineCapability.js +2 -2
  292. package/dist/steerPriorityCapability.js +2 -2
  293. package/dist/storePostureCapability.js +2 -2
  294. package/dist/subagent/agentStateDetail.js +1 -1
  295. package/dist/subagent/engineDelegatedPrompt.d.ts +9 -0
  296. package/dist/subagent/engineDelegatedPrompt.js +38 -7
  297. package/dist/subagent/engineRowStopGate.js +2 -2
  298. package/dist/subagent/engineSubagentResume.js +3 -3
  299. package/dist/subagent/engineTaskHandleWire.d.ts +1 -0
  300. package/dist/subagent/engineTaskHandleWire.js +10 -0
  301. package/dist/submitFailure.d.ts +8 -0
  302. package/dist/submitFailure.js +17 -0
  303. package/dist/supportFloor.d.ts +1 -0
  304. package/dist/supportFloor.js +7 -0
  305. package/dist/terminationIntent.d.ts +55 -0
  306. package/dist/terminationIntent.js +352 -0
  307. package/dist/toolHistoryMismatch.d.ts +8 -0
  308. package/dist/toolHistoryMismatch.js +37 -6
  309. package/dist/toolResult.d.ts +13 -3
  310. package/dist/toolResult.js +158 -9
  311. package/dist/toolResultContent.d.ts +13 -0
  312. package/dist/toolResultContent.js +82 -7
  313. package/dist/toolRoster.d.ts +18 -0
  314. package/dist/toolRoster.js +64 -0
  315. package/dist/turnFailurePresentation.js +27 -90
  316. package/dist/usageLimitAutoResume.d.ts +74 -0
  317. package/dist/usageLimitAutoResume.js +227 -0
  318. package/dist/userAttachmentEnvelope.js +1 -1
  319. package/dist/userAttachmentSeat.js +5 -5
  320. package/dist/userInvokedSkillsCapability.js +2 -2
  321. package/dist/webSearchBackendCapability.js +2 -2
  322. package/dist/wireErrorTriage.js +99 -50
  323. package/dist/wireFailureShape.d.ts +25 -1
  324. package/dist/wireFailureShape.js +92 -5
  325. package/dist/wireRefusalCopy.d.ts +24 -1
  326. package/dist/wireRefusalCopy.js +253 -32
  327. package/dist/wiringFleetDoctor.d.ts +3 -0
  328. package/dist/wiringFleetDoctor.js +21 -0
  329. package/dist/workflow.d.ts +2 -1
  330. package/dist/workflow.js +38 -1
  331. package/dist/workflowClient.d.ts +2 -7
  332. package/dist/workflowsJournalCapability.js +2 -2
  333. package/dist/writeProtectionCapability.js +2 -2
  334. package/docs/INTEGRATION-CLIENTS.md +607 -181
  335. package/package.json +14 -3
@@ -1,8 +1,17 @@
1
1
  import { SETTINGS_CLASSIFY_HOOKS_CONFIG } from './generated/settingsSchemaFns.js';
2
- import { hooksWirePlanShapeOf } from './pluginHooksWire.js';
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': () => 'The hooks for this request could not be checked before sending, so the request is not sent. Reload your settings and try again.',
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 u = unwrap(src.value, 'plan');
105
- if (u.kind === 'none')
112
+ const facts = src.value;
113
+ if (facts === 'none')
106
114
  return noSourceArm(key);
107
- if (u.kind === 'bad' || hooksWirePlanShapeOf(u.value) !== 'plan')
108
- throw badSource(key, '{ plan } with the plan returned by hooksWirePlan() for this turn');
109
- const plan = u.value;
110
- let wire;
111
- let salvageRows;
112
- let closedBy;
115
+ let hasPlan;
116
+ let hasSettings;
113
117
  try {
114
- wire = plan.wire;
115
- salvageRows = plan.settingsSalvage;
116
- closedBy = plan.closedBy;
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
- throw badSource(key, '{ plan } with a readable plan');
123
+ catch (e) {
124
+ if (e instanceof HostSourceShapeError)
125
+ throw e;
126
+ return unreadableArm(key);
120
127
  }
121
- const rows = Array.isArray(salvageRows) ? salvageRows : [];
122
- const layersOf = (outcome) => rows.filter((r) => isRecordShape(r) && r.outcome === outcome && typeof r.source === 'string').map((r) => r.source);
123
- const managedRejected = layersOf('rejected').includes('policySettings');
124
- if (managedRejected || layersOf('loaded-partial').includes('policySettings')) {
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: managedRejected ? 'source_rejected' : 'entries_dropped', disposition: 'refuse_turn', layers: freeze(['policySettings']) }),
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 { row: freeze({ key, cause: 'empty', disposition: BASE_DISPOSITION.empty }), notices: [], plan };
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, "{ section, env } with the raw webSearch section of the settings and the environment (since 0.100.0 the entry judges it; do not pass the judged settings)");
163
- section = v.section;
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, '{ section, env } where env is the environment record (pass {} where there is none)');
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, '{ section, env, apiKeyFor? } where apiKeyFor is a function');
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 { row: freeze({ key, cause: 'empty', disposition: BASE_DISPOSITION.empty }), notices: [] };
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?, settingsMemory? } with the --memory flag word and the memory section of the settings');
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 { row: freeze({ key, cause: 'empty', disposition: BASE_DISPOSITION.empty }), notices: [] };
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 { row: freeze({ key, cause: 'empty', disposition: BASE_DISPOSITION.empty }), notices: [] };
290
+ return emptyArm(key);
272
291
  }
273
- function passArm(key, field, src, want) {
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 u = unwrap(src.value, field);
279
- if (u.kind === 'none')
298
+ const v = src.value;
299
+ if (v === 'none')
280
300
  return noSourceArm(key);
281
- if (u.kind === 'bad')
282
- throw badSource(key, want);
283
- if (u.value === undefined || u.value === null)
284
- return { row: freeze({ key, cause: 'empty', disposition: BASE_DISPOSITION.empty }), notices: [] };
285
- return carriedArm(key, u.value);
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
- const resolved = passArm('settings.resolved', 'snapshot', read('resolved'), '{ snapshot } with the resolver snapshot');
308
- let resolvedCarried = resolved.carried;
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 = passArm('settings.outputStyle', 'name', read('outputStyle'), '{ name } with the output style name');
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
- const arms = [hooks, resolved, webSearch, outputStyle, memory, fileHistory];
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 === undefined ? freeze({ kind: 'send' }) : freeze({ kind: 'refuse', notice: refusal.notices[0] ?? notice('HS-PROJECTION', 'turn') });
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
- ...(hooks.carried !== undefined ? { hooks: hooks.carried } : {}),
330
- ...(resolvedCarried !== undefined ? { resolved: resolvedCarried } : {}),
331
- ...(webSearch.carried !== undefined ? { webSearch: webSearch.carried } : {}),
332
- ...(outputStyle.carried !== undefined ? { outputStyle: outputStyle.carried } : {}),
333
- ...(memory.carried !== undefined ? { memory: 'off' } : {}),
334
- ...(fileHistory.carried !== undefined ? { fileHistory: 'disabled' } : {}),
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 product = { verdict, rows, notices, hooks: hooks.plan, carried };
337
- if (resolvedError !== undefined)
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.push(r.key);
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.push(k);
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.push(entry);
993
+ appendOwnElement(keep, entry);
521
994
  break;
522
995
  }
523
996
  }
524
997
  if (keep.length > 0)
525
- evOut.push({ ...head, hooks: keep });
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
- if (typeof o !== 'object' || o === null)
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.push(copy);
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
- if (d.value === 'refuse_turn') {
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.push(key);
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 !== (refuses ? 'refuse' : 'send'))
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
- export const UNWIRED_HOST_TURN_SETTINGS = buildHostTurnSettings({ sources: {} }, {
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
  });