@sema-agent/client-core 0.99.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 (374) hide show
  1. package/CHANGELOG.md +572 -0
  2. package/README.md +174 -114
  3. package/dist/adapt/arms.js +109 -50
  4. package/dist/adapt/panelTasks.d.ts +2 -1
  5. package/dist/adapt/panelTasks.js +32 -9
  6. package/dist/adapt/textStream.d.ts +1 -1
  7. package/dist/adapt/textStream.js +58 -32
  8. package/dist/adapt/toolCards.js +9 -8
  9. package/dist/adapt.js +7 -1
  10. package/dist/adapter/activeRunSelfHeal.d.ts +31 -2
  11. package/dist/adapter/activeRunSelfHeal.js +162 -13
  12. package/dist/adapter/downstream/eventToSdkMessage.d.ts +25 -6
  13. package/dist/adapter/downstream/eventToSdkMessage.js +157 -20
  14. package/dist/adapter/downstream/terminalToSdkResult.d.ts +60 -1
  15. package/dist/adapter/downstream/terminalToSdkResult.js +219 -39
  16. package/dist/adapter/downstream/wiringManifestView.d.ts +3 -1
  17. package/dist/adapter/downstream/wiringManifestView.js +1 -0
  18. package/dist/adapter/runStream.d.ts +4 -4
  19. package/dist/adapter/runStream.js +184 -42
  20. package/dist/adapter/types.d.ts +2 -0
  21. package/dist/agentsWireCaps.d.ts +9 -7
  22. package/dist/agentsWireCaps.js +101 -17
  23. package/dist/approvalDecidedByCapability.js +2 -2
  24. package/dist/approvalFrameFamilies.d.ts +33 -0
  25. package/dist/approvalFrameFamilies.js +120 -0
  26. package/dist/approvalsStreamLiveCapability.js +2 -2
  27. package/dist/attachmentsWireCaps.js +41 -13
  28. package/dist/callerCwdCapability.js +2 -2
  29. package/dist/centerWiringCapability.js +2 -2
  30. package/dist/clockReading.d.ts +2 -0
  31. package/dist/clockReading.js +4 -0
  32. package/dist/cloudConfigWireCaps.d.ts +28 -5
  33. package/dist/cloudConfigWireCaps.js +334 -103
  34. package/dist/compactionStatus.d.ts +34 -0
  35. package/dist/compactionStatus.js +196 -0
  36. package/dist/coreValuePorts.d.ts +12 -2
  37. package/dist/coreValuePorts.js +9 -0
  38. package/dist/decideFailureNote.js +8 -6
  39. package/dist/decideReceipt.js +2 -2
  40. package/dist/deviceExecutorManagementCapability.js +2 -2
  41. package/dist/deviceFlowPolling.js +1 -1
  42. package/dist/disableSkillsWire.d.ts +1 -1
  43. package/dist/disableSkillsWire.js +4 -3
  44. package/dist/displayUntrusted.d.ts +1 -0
  45. package/dist/displayUntrusted.js +215 -13
  46. package/dist/engineAgentPanelStore.d.ts +7 -4
  47. package/dist/engineCapReader.js +1 -1
  48. package/dist/engineConfigDrift.js +1 -1
  49. package/dist/engineErrorCodes.d.ts +23 -6
  50. package/dist/engineErrorCodes.js +36 -11
  51. package/dist/engineGenerationConvergence.d.ts +39 -0
  52. package/dist/engineGenerationConvergence.js +95 -0
  53. package/dist/engineGenerationPort.d.ts +61 -0
  54. package/dist/engineGenerationPort.js +144 -0
  55. package/dist/engineHealthFacts.d.ts +23 -0
  56. package/dist/engineHealthFacts.js +92 -0
  57. package/dist/engineIdentity.d.ts +4 -0
  58. package/dist/engineIdentity.js +11 -0
  59. package/dist/engineNoticeCodes.d.ts +2 -5
  60. package/dist/engineRowRef.js +4 -0
  61. package/dist/engineSessionMessages.js +2 -2
  62. package/dist/engineToolDirectory.d.ts +3 -0
  63. package/dist/engineToolDirectory.js +6 -4
  64. package/dist/engineWireFor.d.ts +99 -0
  65. package/dist/engineWireFor.js +248 -6
  66. package/dist/engineWireTarget.d.ts +1 -0
  67. package/dist/engineWireTarget.js +8 -0
  68. package/dist/env/uiLanguage.js +1 -1
  69. package/dist/errorSupplementRoles.d.ts +3 -0
  70. package/dist/errorSupplementRoles.js +37 -0
  71. package/dist/eventLeg.d.ts +1 -7
  72. package/dist/eventLeg.js +7 -8
  73. package/dist/executionLaneCapability.js +2 -2
  74. package/dist/fileHistoryCaptureCapability.d.ts +0 -3
  75. package/dist/fileHistoryCaptureCapability.js +3 -7
  76. package/dist/finalVerifyWire.d.ts +6 -3
  77. package/dist/finalVerifyWire.js +6 -23
  78. package/dist/flagInput.d.ts +4 -0
  79. package/dist/flagInput.js +24 -0
  80. package/dist/fleet/fleetLedger.js +5 -2
  81. package/dist/fleet/fleetProjection.d.ts +1 -0
  82. package/dist/fleet/fleetProjection.js +15 -2
  83. package/dist/gateVocabulary.js +3 -0
  84. package/dist/generated/engineFactTables.d.ts +7 -2
  85. package/dist/generated/engineFactTables.js +79 -0
  86. package/dist/generated/engineNoticeTables.js +15 -0
  87. package/dist/generated/settingsSchemaActiveTiers.d.ts +1 -0
  88. package/dist/generated/settingsSchemaActiveTiers.js +14 -0
  89. package/dist/generated/settingsSchemaCallerTextEcho.d.ts +1 -0
  90. package/dist/generated/settingsSchemaCallerTextEcho.js +8 -0
  91. package/dist/generated/settingsSchemaControlAndBidi.d.ts +1 -0
  92. package/dist/generated/settingsSchemaControlAndBidi.js +8 -0
  93. package/dist/generated/settingsSchemaDefaultModel.d.ts +11 -0
  94. package/dist/generated/settingsSchemaDefaultModel.js +25 -0
  95. package/dist/generated/settingsSchemaFns.d.ts +66 -0
  96. package/dist/generated/settingsSchemaFns.js +38 -0
  97. package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -0
  98. package/dist/generated/settingsSchemaMcpRequestEntry.js +156 -0
  99. package/dist/generated/settingsSchemaSafetyMergeSpec.d.ts +1 -0
  100. package/dist/generated/settingsSchemaSafetyMergeSpec.js +95 -0
  101. package/dist/generated/settingsSchemaSettingsSources.d.ts +1 -0
  102. package/dist/generated/settingsSchemaSettingsSources.js +58 -0
  103. package/dist/generated/settingsSchemaTables.d.ts +3 -0
  104. package/dist/generated/settingsSchemaTables.js +18 -0
  105. package/dist/generated/settingsSchemaTypes.d.ts +28 -0
  106. package/dist/generated/settingsSchemaUrlPattern.d.ts +1 -0
  107. package/dist/generated/settingsSchemaUrlPattern.js +183 -0
  108. package/dist/headlessPermissionModeWire.d.ts +18 -2
  109. package/dist/headlessPermissionModeWire.js +30 -19
  110. package/dist/hitl/allowRuleShadow.js +9 -7
  111. package/dist/hitl/approvalCardReading.d.ts +3 -0
  112. package/dist/hitl/approvalCardReading.js +17 -0
  113. package/dist/hitl/approvalCardReasons.js +2 -2
  114. package/dist/hitl/approvalCompleteParked.js +1 -1
  115. package/dist/hitl/approvalDelivery.d.ts +87 -0
  116. package/dist/hitl/approvalDelivery.js +193 -0
  117. package/dist/hitl/approvalHolds.d.ts +14 -0
  118. package/dist/hitl/approvalHolds.js +41 -0
  119. package/dist/hitl/approvalResolution.d.ts +11 -0
  120. package/dist/hitl/approvalResolution.js +50 -11
  121. package/dist/hitl/askClassPair.d.ts +8 -2
  122. package/dist/hitl/askClassPair.js +31 -4
  123. package/dist/hitl/askParkAutoReopenBlock.d.ts +30 -0
  124. package/dist/hitl/askParkAutoReopenBlock.js +117 -0
  125. package/dist/hitl/askParkRowRouting.js +4 -1
  126. package/dist/hitl/attributionLadder.d.ts +62 -0
  127. package/dist/hitl/attributionLadder.js +138 -0
  128. package/dist/hitl/automaticAnswerVerdict.d.ts +6 -1
  129. package/dist/hitl/automaticAnswerVerdict.js +46 -11
  130. package/dist/hitl/crashConverged.js +2 -2
  131. package/dist/hitl/decisionConflict.d.ts +6 -2
  132. package/dist/hitl/decisionConflict.js +24 -9
  133. package/dist/hitl/decisionLedger.d.ts +55 -0
  134. package/dist/hitl/decisionLedger.js +156 -0
  135. package/dist/hitl/decisionRefusal.d.ts +21 -10
  136. package/dist/hitl/decisionRefusal.js +100 -55
  137. package/dist/hitl/decisionSend.d.ts +116 -0
  138. package/dist/hitl/decisionSend.js +563 -0
  139. package/dist/hitl/frameRouter.d.ts +1 -0
  140. package/dist/hitl/frameRouter.js +9 -2
  141. package/dist/hitl/hitlBridge.d.ts +18 -6
  142. package/dist/hitl/hitlBridge.js +59 -43
  143. package/dist/hitl/livePendingAsk.js +4 -3
  144. package/dist/hitl/noAllowCause.js +1 -1
  145. package/dist/hitl/parkResolver.js +3 -2
  146. package/dist/hitl/persistedRulesWire.js +1 -0
  147. package/dist/hitl/planReviewWire.d.ts +4 -0
  148. package/dist/hitl/planReviewWire.js +104 -106
  149. package/dist/hitl/resumeRunningCard.d.ts +3 -2
  150. package/dist/hitl/resumeRunningCard.js +17 -11
  151. package/dist/hitl/sessionPolicyDeliverable.d.ts +5 -2
  152. package/dist/hitl/sessionPolicyDeliverable.js +65 -35
  153. package/dist/hitl/sessionPolicyWire.d.ts +13 -3
  154. package/dist/hitl/sessionPolicyWire.js +81 -16
  155. package/dist/hitl/standingRows.js +1 -1
  156. package/dist/hitl/toolApprovalWire.d.ts +9 -10
  157. package/dist/hitl/toolApprovalWire.js +103 -151
  158. package/dist/hookMatcherVerdict.d.ts +2 -0
  159. package/dist/hookMatcherVerdict.js +12 -0
  160. package/dist/hooksCompactTransition.d.ts +19 -0
  161. package/dist/hooksCompactTransition.js +41 -0
  162. package/dist/hooksWireCaps.d.ts +1 -1
  163. package/dist/hooksWireCaps.js +202 -203
  164. package/dist/host.d.ts +1 -14
  165. package/dist/host.js +0 -8
  166. package/dist/hostCallbackGuard.d.ts +1 -0
  167. package/dist/hostCallbackGuard.js +1 -1
  168. package/dist/hostSettingsSource.d.ts +172 -0
  169. package/dist/hostSettingsSource.js +675 -0
  170. package/dist/hostTurnSettings.d.ts +114 -19
  171. package/dist/hostTurnSettings.js +966 -68
  172. package/dist/httpHookPolicy.d.ts +37 -0
  173. package/dist/httpHookPolicy.js +176 -0
  174. package/dist/humanTurn.d.ts +4 -2
  175. package/dist/humanTurn.js +40 -10
  176. package/dist/humanTurnRead.js +4 -3
  177. package/dist/humanTurnSentences.d.ts +10 -0
  178. package/dist/humanTurnSentences.js +74 -0
  179. package/dist/i18n/messages.en.d.ts +313 -0
  180. package/dist/i18n/messages.en.js +326 -13
  181. package/dist/i18n/messages.zh.js +341 -13
  182. package/dist/i18n/translate.js +3 -3
  183. package/dist/index.d.ts +85 -15
  184. package/dist/index.js +53 -12
  185. package/dist/inheritEnvCapability.d.ts +4 -1
  186. package/dist/inheritEnvCapability.js +38 -17
  187. package/dist/inheritEnvWire.d.ts +2 -1
  188. package/dist/inheritEnvWire.js +11 -5
  189. package/dist/injectionLaneNotice.d.ts +5 -0
  190. package/dist/injectionLaneNotice.js +46 -0
  191. package/dist/interactiveToolsWire.d.ts +4 -2
  192. package/dist/interactiveToolsWire.js +5 -5
  193. package/dist/jsonFaithful.d.ts +20 -0
  194. package/dist/jsonFaithful.js +152 -0
  195. package/dist/limitsWire.d.ts +7 -2
  196. package/dist/limitsWire.js +19 -13
  197. package/dist/liveInitToolFace.d.ts +6 -1
  198. package/dist/liveInitToolFace.js +5 -3
  199. package/dist/liveModelCatalog.d.ts +22 -0
  200. package/dist/liveModelCatalog.js +132 -18
  201. package/dist/mcpPanel.js +3 -1
  202. package/dist/mcpProbeCapability.js +2 -2
  203. package/dist/mcpReconnect.js +2 -2
  204. package/dist/mcpStatusSupersetKeys.d.ts +24 -0
  205. package/dist/mcpStatusSupersetKeys.js +45 -0
  206. package/dist/mcpToolToggles.d.ts +6 -0
  207. package/dist/mcpToolToggles.js +47 -0
  208. package/dist/mcpWireCaps.d.ts +48 -4
  209. package/dist/mcpWireCaps.js +338 -99
  210. package/dist/mcpWireTransport.d.ts +4 -0
  211. package/dist/mcpWireTransport.js +18 -0
  212. package/dist/memoryComplianceCapability.js +2 -2
  213. package/dist/memoryOriginCapability.js +2 -2
  214. package/dist/model/catalogDefault.d.ts +24 -0
  215. package/dist/model/catalogDefault.js +4 -0
  216. package/dist/model/liveCatalogShape.js +5 -4
  217. package/dist/model/modelsPolicy.js +4 -3
  218. package/dist/model/onboardJudgement.d.ts +1 -0
  219. package/dist/model/onboardJudgement.js +1 -1
  220. package/dist/model/subagentModelWord.js +2 -2
  221. package/dist/modelCapabilityProbe.d.ts +2 -1
  222. package/dist/modelCapabilityProbe.js +16 -15
  223. package/dist/modelIdentityResolvability.d.ts +12 -1
  224. package/dist/modelIdentityResolvability.js +69 -28
  225. package/dist/modsKernelIdentity.d.ts +10 -0
  226. package/dist/modsKernelIdentity.js +103 -0
  227. package/dist/modsKernelTransit.d.ts +8 -0
  228. package/dist/modsKernelTransit.js +6 -0
  229. package/dist/notifications.d.ts +30 -12
  230. package/dist/notifications.js +241 -53
  231. package/dist/outputStyleSeatCapability.js +2 -2
  232. package/dist/ownKey.d.ts +37 -0
  233. package/dist/ownKey.js +238 -2
  234. package/dist/panelReduce.d.ts +5 -0
  235. package/dist/panelReduce.js +45 -13
  236. package/dist/panelStateHolder.d.ts +1 -0
  237. package/dist/panelStateHolder.js +10 -1
  238. package/dist/peerFrames.d.ts +1 -1
  239. package/dist/peerFrames.js +6 -2
  240. package/dist/peerLaneCapability.js +2 -2
  241. package/dist/permissionModesCapability.js +4 -4
  242. package/dist/permissionRuleIssue.d.ts +2 -1
  243. package/dist/permissionRuleIssue.js +24 -21
  244. package/dist/permissionRulesWriteCapability.js +2 -2
  245. package/dist/permissionsAllowGrantCapability.js +2 -2
  246. package/dist/permissionsDeclaration.d.ts +43 -4
  247. package/dist/permissionsDeclaration.js +102 -35
  248. package/dist/pluginHooksWire.d.ts +20 -4
  249. package/dist/pluginHooksWire.js +101 -60
  250. package/dist/prepareRefusal.d.ts +9 -0
  251. package/dist/prepareRefusal.js +90 -0
  252. package/dist/printInitToolFace.js +2 -2
  253. package/dist/printModelStatus.js +1 -1
  254. package/dist/projectMemory.d.ts +32 -0
  255. package/dist/projectMemory.js +70 -0
  256. package/dist/promptBlockedCopy.d.ts +2 -1
  257. package/dist/promptBlockedCopy.js +2 -1
  258. package/dist/promptDelivery.d.ts +23 -3
  259. package/dist/promptDelivery.js +169 -30
  260. package/dist/providerRejection.d.ts +19 -1
  261. package/dist/providerRejection.js +75 -4
  262. package/dist/queuedDelivery.d.ts +48 -0
  263. package/dist/queuedDelivery.js +233 -0
  264. package/dist/reattachWindow.d.ts +94 -0
  265. package/dist/reattachWindow.js +127 -0
  266. package/dist/request/printNotification.d.ts +1 -1
  267. package/dist/request/printNotification.js +5 -1
  268. package/dist/request/submissionIdentity.d.ts +37 -0
  269. package/dist/request/submissionIdentity.js +65 -0
  270. package/dist/request/taskRequest.d.ts +22 -14
  271. package/dist/request/taskRequest.js +312 -202
  272. package/dist/resultFrameKeys.d.ts +1 -0
  273. package/dist/resultFrameKeys.js +4 -1
  274. package/dist/resumeRefusalCopy.d.ts +3 -1
  275. package/dist/resumeRefusalCopy.js +22 -4
  276. package/dist/retryStatus.d.ts +26 -0
  277. package/dist/retryStatus.js +133 -28
  278. package/dist/rewindArchiveCapability.js +2 -2
  279. package/dist/rewindEngineAction.d.ts +2 -0
  280. package/dist/rewindEngineAction.js +23 -1
  281. package/dist/rowKind.d.ts +36 -0
  282. package/dist/rowKind.js +97 -0
  283. package/dist/ruleCompileVerdict.d.ts +18 -0
  284. package/dist/ruleCompileVerdict.js +67 -2
  285. package/dist/ruleReadings.d.ts +58 -0
  286. package/dist/ruleReadings.js +132 -0
  287. package/dist/ruleRefusalSentence.d.ts +8 -0
  288. package/dist/ruleRefusalSentence.js +64 -0
  289. package/dist/runCancelContext.d.ts +0 -1
  290. package/dist/runCancelContext.js +1 -2
  291. package/dist/runTerminal.d.ts +5 -0
  292. package/dist/runTerminal.js +52 -17
  293. package/dist/sandboxWire.d.ts +3 -2
  294. package/dist/sandboxWire.js +59 -27
  295. package/dist/scenarioRefusal.d.ts +2 -1
  296. package/dist/scenarioRefusal.js +6 -6
  297. package/dist/scenarioSkills.d.ts +20 -0
  298. package/dist/scenarioSkills.js +72 -0
  299. package/dist/scenarioWire.d.ts +5 -2
  300. package/dist/scenarioWire.js +9 -9
  301. package/dist/sealedKeyCapability.js +2 -2
  302. package/dist/seam.d.ts +26 -9
  303. package/dist/seam.js +44 -4
  304. package/dist/seatContract.d.ts +62 -9
  305. package/dist/seatContract.js +70 -25
  306. package/dist/selfOrchestrationDenial.js +1 -1
  307. package/dist/sessionPolicyCapability.js +2 -2
  308. package/dist/sessionRulesChildrenReadLive.d.ts +6 -0
  309. package/dist/sessionRulesChildrenReadLive.js +5 -0
  310. package/dist/sessionRulesNamespaceFormsCapability.d.ts +12 -0
  311. package/dist/sessionRulesNamespaceFormsCapability.js +29 -0
  312. package/dist/sessionSyncFileHistoryCapability.js +2 -2
  313. package/dist/settingsCredentialKeyPaths.d.ts +8 -0
  314. package/dist/settingsCredentialKeyPaths.js +274 -0
  315. package/dist/settingsHooksSalvage.d.ts +1 -0
  316. package/dist/settingsHooksSalvage.js +7 -1
  317. package/dist/settingsLayerAdmission.d.ts +4 -0
  318. package/dist/settingsLayerAdmission.js +16 -0
  319. package/dist/skillToolListsCapability.js +6 -5
  320. package/dist/skillsWireCaps.d.ts +14 -3
  321. package/dist/skillsWireCaps.js +48 -18
  322. package/dist/slashCommandGate.d.ts +24 -0
  323. package/dist/slashCommandGate.js +74 -0
  324. package/dist/slashCommandTable.d.ts +14 -0
  325. package/dist/slashCommandTable.js +99 -0
  326. package/dist/sqlEngineCapability.js +2 -2
  327. package/dist/steerPriorityCapability.js +2 -2
  328. package/dist/storePostureCapability.js +2 -2
  329. package/dist/subagent/agentStateDetail.js +1 -1
  330. package/dist/subagent/engineDelegatedPrompt.d.ts +9 -0
  331. package/dist/subagent/engineDelegatedPrompt.js +38 -7
  332. package/dist/subagent/engineRowStopGate.js +2 -2
  333. package/dist/subagent/engineSubagentResume.js +3 -3
  334. package/dist/subagent/engineTaskHandleWire.d.ts +1 -0
  335. package/dist/subagent/engineTaskHandleWire.js +10 -0
  336. package/dist/subagentContentStore.d.ts +1 -0
  337. package/dist/subagentContentStore.js +135 -27
  338. package/dist/submitFailure.d.ts +8 -0
  339. package/dist/submitFailure.js +17 -0
  340. package/dist/supportFloor.d.ts +1 -0
  341. package/dist/supportFloor.js +7 -0
  342. package/dist/terminationIntent.d.ts +55 -0
  343. package/dist/terminationIntent.js +352 -0
  344. package/dist/toolHistoryMismatch.d.ts +8 -0
  345. package/dist/toolHistoryMismatch.js +37 -6
  346. package/dist/toolResult.d.ts +13 -3
  347. package/dist/toolResult.js +158 -9
  348. package/dist/toolResultContent.d.ts +13 -0
  349. package/dist/toolResultContent.js +82 -7
  350. package/dist/toolRoster.d.ts +18 -0
  351. package/dist/toolRoster.js +64 -0
  352. package/dist/toolsFlagNames.d.ts +8 -0
  353. package/dist/toolsFlagNames.js +110 -0
  354. package/dist/turnFailurePresentation.js +41 -96
  355. package/dist/usageLimitAutoResume.d.ts +74 -0
  356. package/dist/usageLimitAutoResume.js +227 -0
  357. package/dist/userAttachmentEnvelope.js +1 -1
  358. package/dist/userAttachmentSeat.js +5 -5
  359. package/dist/userInvokedSkillsCapability.js +2 -2
  360. package/dist/webSearchBackendCapability.js +2 -2
  361. package/dist/wireErrorTriage.js +99 -50
  362. package/dist/wireFailureShape.d.ts +25 -1
  363. package/dist/wireFailureShape.js +92 -5
  364. package/dist/wireRefusalCopy.d.ts +75 -18
  365. package/dist/wireRefusalCopy.js +532 -148
  366. package/dist/wiringFleetDoctor.d.ts +3 -0
  367. package/dist/wiringFleetDoctor.js +21 -0
  368. package/dist/workflow.d.ts +2 -1
  369. package/dist/workflow.js +38 -1
  370. package/dist/workflowClient.d.ts +2 -7
  371. package/dist/workflowsJournalCapability.js +2 -2
  372. package/dist/writeProtectionCapability.js +2 -2
  373. package/docs/INTEGRATION-CLIENTS.md +1013 -190
  374. package/package.json +15 -4
@@ -1,6 +1,18 @@
1
1
  import { SETTINGS_CLASSIFY_HOOKS_CONFIG } from './generated/settingsSchemaFns.js';
2
- import { hooksWirePlanShapeOf } from './pluginHooksWire.js';
3
- export const HOST_SUPPLIED_KEYS = Object.freeze(['settings.hooks', 'settings.resolved', 'settings.webSearch', 'settings.outputStyle']);
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';
8
+ import { resolveWebSearchVerdict, webSearchVerdictMessage } from './webSearchWireCaps.js';
9
+ import { fileHistoryTightenVerdict, fileHistoryUnjudgedRefusal } from './fileHistoryCaptureCapability.js';
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';
15
+ export const HOST_SUPPLIED_KEYS = Object.freeze(['settings.hooks', 'settings.resolved', 'settings.webSearch', 'settings.outputStyle', 'memory', 'fileHistory']);
4
16
  export const HOST_SETTING_CAUSES = Object.freeze([
5
17
  'carried',
6
18
  'entries_dropped',
@@ -10,19 +22,33 @@ export const HOST_SETTING_CAUSES = Object.freeze([
10
22
  'empty',
11
23
  'no_source',
12
24
  'host_port_missing',
25
+ 'value_malformed',
26
+ 'held_previous',
27
+ 'policy_withheld',
13
28
  ]);
14
- 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']);
15
30
  const HOST_SETTING_NOTICE_TEXT = {
16
31
  'HS-UNWIRED': (what) => `This app has not connected ${what} from your settings, so it is not sent with your requests.`,
17
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.',
18
- '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),
19
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.`,
35
+ 'HS-WEBSEARCH-MALFORMED': (sentence) => sentence,
36
+ 'HS-SWITCH-MALFORMED': () => renderMessage(msg('session.hostSettings.memorySwitchMalformed')),
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')),
20
44
  };
21
45
  const KEY_NOUN = {
22
46
  'settings.hooks': 'the hooks',
23
47
  'settings.resolved': 'the permission rules',
24
48
  'settings.webSearch': 'the web search setup',
25
49
  'settings.outputStyle': 'the output style',
50
+ memory: 'auto-memory',
51
+ fileHistory: 'file checkpoints',
26
52
  };
27
53
  const BASE_DISPOSITION = {
28
54
  carried: 'carry',
@@ -33,6 +59,9 @@ const BASE_DISPOSITION = {
33
59
  empty: 'nothing_to_carry',
34
60
  no_source: 'nothing_to_carry',
35
61
  host_port_missing: 'unwired',
62
+ value_malformed: 'refuse_turn',
63
+ held_previous: 'carry',
64
+ policy_withheld: 'withhold_by_policy',
36
65
  };
37
66
  const freeze = (o) => Object.freeze(o);
38
67
  const mint = (o) => o;
@@ -48,18 +77,6 @@ function readSource(sources, key) {
48
77
  return { kind: 'threw' };
49
78
  }
50
79
  }
51
- function unwrap(v, field) {
52
- if (v === 'none')
53
- return { kind: 'none' };
54
- try {
55
- if (typeof v !== 'object' || v === null || Array.isArray(v) || !Object.hasOwn(v, field))
56
- return { kind: 'bad' };
57
- return { kind: 'value', value: v[field] };
58
- }
59
- catch {
60
- return { kind: 'bad' };
61
- }
62
- }
63
80
  const isRecordShape = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
64
81
  function hooksPassJudge(wire) {
65
82
  try {
@@ -69,8 +86,11 @@ function hooksPassJudge(wire) {
69
86
  return false;
70
87
  }
71
88
  }
89
+ class HostSourceShapeError extends TypeError {
90
+ code = 'host_source_shape';
91
+ }
72
92
  function badSource(key, want) {
73
- return new TypeError(`hostTurnSettings: sources.${key.replace(/^settings\./, '')} must be 'none' or ${want} — got something else (the value is not echoed).`);
93
+ return new HostSourceShapeError(`hostTurnSettings: sources.${key.replace(/^settings\./, '')} must be 'none' or ${want} — got something else (the value is not echoed).`);
74
94
  }
75
95
  const missingArm = (key) => ({
76
96
  row: freeze({ key, cause: 'host_port_missing', disposition: BASE_DISPOSITION.host_port_missing }),
@@ -81,41 +101,50 @@ const unreadableArm = (key) => ({
81
101
  notices: [notice('HS-SOURCE-UNREADABLE', 'turn', KEY_NOUN[key])],
82
102
  });
83
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: [] });
84
105
  const carriedArm = (key, value) => ({ row: freeze({ key, cause: 'carried', disposition: BASE_DISPOSITION.carried }), notices: [], carried: value });
85
- function hooksArm(src) {
106
+ function hooksArm(src, side) {
86
107
  const key = 'settings.hooks';
87
108
  if (src.kind === 'missing')
88
109
  return missingArm(key);
89
110
  if (src.kind === 'threw')
90
111
  return unreadableArm(key);
91
- const u = unwrap(src.value, 'plan');
92
- if (u.kind === 'none')
112
+ const facts = src.value;
113
+ if (facts === 'none')
93
114
  return noSourceArm(key);
94
- if (u.kind === 'bad' || hooksWirePlanShapeOf(u.value) !== 'plan')
95
- throw badSource(key, '{ plan } with the plan returned by hooksWirePlan() for this turn');
96
- const plan = u.value;
97
- let wire;
98
- let salvageRows;
99
- let closedBy;
115
+ let hasPlan;
116
+ let hasSettings;
100
117
  try {
101
- wire = plan.wire;
102
- salvageRows = plan.settingsSalvage;
103
- 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');
104
122
  }
105
- catch {
106
- throw badSource(key, '{ plan } with a readable plan');
123
+ catch (e) {
124
+ if (e instanceof HostSourceShapeError)
125
+ throw e;
126
+ return unreadableArm(key);
107
127
  }
108
- const rows = Array.isArray(salvageRows) ? salvageRows : [];
109
- const layersOf = (outcome) => rows.filter((r) => isRecordShape(r) && r.outcome === outcome && typeof r.source === 'string').map((r) => r.source);
110
- const managedRejected = layersOf('rejected').includes('policySettings');
111
- 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) {
112
141
  return {
113
- 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])]) }),
114
143
  notices: [notice('HS-MANAGED-REJECTED', 'turn')],
115
144
  plan,
116
145
  };
117
146
  }
118
- if (closedBy === 'governance_unreadable')
147
+ if (plan.closedBy === 'governance_unreadable')
119
148
  return { ...unreadableArm(key), plan };
120
149
  if (wire !== undefined && !hooksPassJudge(wire)) {
121
150
  return { row: freeze({ key, cause: 'projection_failed', disposition: BASE_DISPOSITION.projection_failed }), notices: [notice('HS-PROJECTION', 'turn')], plan };
@@ -129,23 +158,372 @@ function hooksArm(src) {
129
158
  return { row: freeze({ key, cause, disposition: carried !== undefined ? 'carry_partial' : 'withhold_notice', layers }), notices: [], carried, plan };
130
159
  }
131
160
  if (carried === undefined)
132
- return { row: freeze({ key, cause: 'empty', disposition: BASE_DISPOSITION.empty }), notices: [], plan };
161
+ return { ...emptyArm(key), plan };
133
162
  return { ...carriedArm(key, carried), plan };
134
163
  }
135
- function passArm(key, field, src, want) {
164
+ function webSearchArm(src, side) {
165
+ const key = 'settings.webSearch';
166
+ if (src.kind === 'missing')
167
+ return missingArm(key);
168
+ if (src.kind === 'threw')
169
+ return unreadableArm(key);
170
+ const v = src.value;
171
+ if (v === 'none')
172
+ return noSourceArm(key);
173
+ let env;
174
+ let apiKeyFor;
175
+ try {
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
+ }
179
+ env = v.env;
180
+ apiKeyFor = v.apiKeyFor;
181
+ }
182
+ catch (e) {
183
+ if (e instanceof HostSourceShapeError)
184
+ throw e;
185
+ return unreadableArm(key);
186
+ }
187
+ if (!isRecordShape(env))
188
+ throw badSource(key, '{ env } where env is the environment record (pass {} where there is none)');
189
+ if (apiKeyFor !== undefined && typeof apiKeyFor !== '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;
194
+ const verdict = resolveWebSearchVerdict(env, section, apiKeyFor);
195
+ if (verdict.kind === 'absent')
196
+ return emptyArm(key);
197
+ if (verdict.kind === 'honored')
198
+ return carriedArm(key, freeze({ ...verdict.settings }));
199
+ return {
200
+ row: freeze({ key, cause: 'value_malformed', disposition: BASE_DISPOSITION.value_malformed }),
201
+ notices: [notice('HS-WEBSEARCH-MALFORMED', 'turn', webSearchVerdictMessage(verdict, 'submit') ?? '')],
202
+ };
203
+ }
204
+ function memoryArm(src, side, judge) {
205
+ const key = 'memory';
206
+ if (src.kind === 'missing')
207
+ return missingArm(key);
208
+ if (src.kind === 'threw')
209
+ return unreadableArm(key);
210
+ const v = src.value;
211
+ if (v === 'none')
212
+ return noSourceArm(key);
213
+ let flag;
214
+ try {
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)');
217
+ flag = v.flag;
218
+ }
219
+ catch (e) {
220
+ if (e instanceof HostSourceShapeError)
221
+ throw e;
222
+ return unreadableArm(key);
223
+ }
224
+ if (judge({ flag }))
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;
229
+ let bySettings;
230
+ try {
231
+ bySettings = judge({ settingsMemory });
232
+ }
233
+ catch {
234
+ return { row: freeze({ key, cause: 'value_malformed', disposition: 'withhold_notice' }), notices: [notice('HS-SWITCH-MALFORMED', 'session')] };
235
+ }
236
+ if (bySettings)
237
+ return carriedArm(key, 'off');
238
+ return emptyArm(key);
239
+ }
240
+ const UNOBSERVED_READING = Object.freeze({ kind: 'unobserved' });
241
+ function fileHistoryReadingSnapshot(reading) {
242
+ try {
243
+ if (typeof reading !== 'object' || reading === null)
244
+ return UNOBSERVED_READING;
245
+ const kind = reading.kind;
246
+ if (kind === 'present') {
247
+ const word = reading.word;
248
+ return Object.freeze({ kind, word });
249
+ }
250
+ return Object.freeze({ kind });
251
+ }
252
+ catch {
253
+ return UNOBSERVED_READING;
254
+ }
255
+ }
256
+ function fileHistoryArm(src) {
257
+ const key = 'fileHistory';
258
+ if (src.kind === 'missing')
259
+ return missingArm(key);
260
+ if (src.kind === 'threw')
261
+ return unreadableArm(key);
262
+ const v = src.value;
263
+ if (v === 'none')
264
+ return noSourceArm(key);
265
+ let reading;
266
+ let captureOff;
267
+ try {
268
+ if (!isRecordShape(v) || !Object.hasOwn(v, 'captureOff'))
269
+ throw badSource(key, '{ reading, captureOff } with the engine capability reading and the switch');
270
+ reading = v.reading;
271
+ captureOff = v.captureOff;
272
+ }
273
+ catch (e) {
274
+ if (e instanceof HostSourceShapeError)
275
+ throw e;
276
+ return unreadableArm(key);
277
+ }
278
+ if (typeof captureOff !== 'boolean')
279
+ throw badSource(key, '{ reading, captureOff } where captureOff is a boolean');
280
+ const snap = fileHistoryReadingSnapshot(reading);
281
+ const verdict = fileHistoryTightenVerdict(snap, captureOff);
282
+ if (verdict === 'declare')
283
+ return carriedArm(key, 'disabled');
284
+ if (verdict === 'unjudged') {
285
+ return {
286
+ row: freeze({ key, cause: 'value_malformed', disposition: 'refuse_turn' }),
287
+ notices: [notice('HS-FILEHISTORY-UNJUDGED', 'turn', fileHistoryUnjudgedRefusal(snap, true) ?? fileHistoryUnjudgedRefusal(UNOBSERVED_READING, true) ?? '')],
288
+ };
289
+ }
290
+ return emptyArm(key);
291
+ }
292
+ function outputStyleArm(src, side) {
293
+ const key = 'settings.outputStyle';
294
+ if (src.kind === 'missing')
295
+ return missingArm(key);
296
+ if (src.kind === 'threw')
297
+ return unreadableArm(key);
298
+ const v = src.value;
299
+ if (v === 'none')
300
+ return noSourceArm(key);
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);
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';
136
393
  if (src.kind === 'missing')
137
394
  return missingArm(key);
138
395
  if (src.kind === 'threw')
139
396
  return unreadableArm(key);
140
- const u = unwrap(src.value, field);
141
- if (u.kind === 'none')
397
+ const v = src.value;
398
+ if (v === 'none')
142
399
  return noSourceArm(key);
143
- if (u.kind === 'bad')
144
- throw badSource(key, want);
145
- if (u.value === undefined || u.value === null)
146
- return { row: freeze({ key, cause: 'empty', disposition: BASE_DISPOSITION.empty }), notices: [] };
147
- return carriedArm(key, u.value);
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');
148
525
  }
526
+ const REFUSAL_CAUSE = Symbol('hostTurnSettings.refusalCause');
149
527
  const RESOLVED_DEFERRED_ERROR = Symbol('hostTurnSettings.resolvedDeferredError');
150
528
  export function rethrowHostResolvedDeferred(product) {
151
529
  const rec = product;
@@ -155,7 +533,60 @@ export function rethrowHostResolvedDeferred(product) {
155
533
  if (box !== undefined)
156
534
  throw box.error;
157
535
  }
158
- export function buildHostTurnSettings(input, materialize) {
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
+ }
588
+ export function buildHostTurnSettings(input, judges) {
589
+ const materialize = judges.materialize;
159
590
  let sources;
160
591
  let sourcesThrew = false;
161
592
  try {
@@ -165,8 +596,28 @@ export function buildHostTurnSettings(input, materialize) {
165
596
  sourcesThrew = true;
166
597
  }
167
598
  const read = (key) => (sourcesThrew ? { kind: 'threw' } : readSource(sources, key));
168
- const resolved = passArm('settings.resolved', 'snapshot', read('resolved'), '{ snapshot } with the resolver snapshot');
169
- 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;
170
621
  let resolvedError;
171
622
  if (resolvedCarried !== undefined) {
172
623
  try {
@@ -176,25 +627,182 @@ export function buildHostTurnSettings(input, materialize) {
176
627
  resolvedError = freeze({ error });
177
628
  }
178
629
  }
179
- const hooks = hooksArm(read('hooks'));
180
- const webSearch = passArm('settings.webSearch', 'settings', read('webSearch'), '{ settings } with the web search settings');
181
- const outputStyle = passArm('settings.outputStyle', 'name', read('outputStyle'), '{ name } with the output style name');
182
- const arms = [hooks, resolved, webSearch, outputStyle];
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);
634
+ const fileHistory = fileHistoryArm(read('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;
183
690
  const rows = freeze(arms.map((a) => a.row));
184
- const notices = freeze(arms.flatMap((a) => a.notices));
691
+ const notices = freeze([...arms.flatMap((a) => a.notices), ...notLoadedNotices, ...heldNotices]);
185
692
  const refusal = arms.find((a) => a.row.disposition === 'refuse_turn');
186
- 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;
187
704
  const carried = freeze({
188
- ...(hooks.carried !== undefined ? { hooks: hooks.carried } : {}),
189
- ...(resolvedCarried !== undefined ? { resolved: resolvedCarried } : {}),
190
- ...(webSearch.carried !== undefined ? { webSearch: webSearch.carried } : {}),
191
- ...(outputStyle.carried !== undefined ? { outputStyle: outputStyle.carried } : {}),
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' } : {}),
192
711
  });
193
- const product = { verdict, rows, notices, hooks: hooks.plan, carried };
194
- 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)
195
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 });
196
722
  return mint(freeze(product));
197
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
+ }
198
806
  export function hostSettingsSelfCheck(product) {
199
807
  try {
200
808
  const rows = product.rows;
@@ -207,17 +815,19 @@ export function hostSettingsSelfCheck(product) {
207
815
  continue;
208
816
  seen.add(r.key);
209
817
  if (r.disposition === 'unwired' && HOST_SUPPLIED_KEYS.includes(r.key))
210
- out.push(r.key);
818
+ appendOwnElement(out, r.key);
211
819
  }
212
820
  for (const k of HOST_SUPPLIED_KEYS)
213
821
  if (!seen.has(k) && !out.includes(k))
214
- out.push(k);
822
+ appendOwnElement(out, k);
215
823
  return freeze(out);
216
824
  }
217
825
  catch {
218
826
  return HOST_SUPPLIED_KEYS;
219
827
  }
220
828
  }
829
+ export const hostProjectionNotice = () => notice('HS-PROJECTION', 'turn');
830
+ export const hostFileHistoryRestoreNotice = () => notice('HS-FILEHISTORY-RESTORE', 'turn');
221
831
  export class HostSettingsRefused extends Error {
222
832
  notice;
223
833
  constructor(n) {
@@ -260,25 +870,36 @@ export function hostTurnSettingsOf(v, depth = 'full') {
260
870
  const p = view;
261
871
  const rows = p.rows;
262
872
  const carried = p.carried;
263
- const subs = HOST_SUPPLIED_KEYS.map((k) => k.slice('settings.'.length));
873
+ const subs = HOST_SUPPLIED_KEYS.map(carriedKeyOf);
264
874
  if (Object.keys(carried).some((k) => !subs.includes(k)))
265
875
  return undefined;
876
+ if (carried.memory !== undefined && carried.memory !== 'off')
877
+ return undefined;
878
+ if (carried.fileHistory !== undefined && carried.fileHistory !== 'disabled')
879
+ return undefined;
266
880
  let refuses = false;
881
+ let holds = false;
267
882
  for (const [i, r] of rows.entries()) {
268
883
  const disposition = r.disposition;
269
884
  if (!HOST_SETTING_DISPOSITIONS.includes(disposition))
270
885
  return undefined;
271
886
  if (disposition === 'refuse_turn')
272
887
  refuses = true;
888
+ if (disposition === 'hold_for_consent')
889
+ holds = true;
890
+ if (r.cause === 'projection_failed' && disposition !== 'refuse_turn')
891
+ return undefined;
273
892
  const sub = subs[i] ?? '';
274
893
  const has = Object.hasOwn(carried, sub) && carried[sub] !== undefined;
275
- if (has !== CARRYING.has(disposition))
894
+ if (disposition !== 'hold_for_consent' && has !== CARRYING.has(disposition))
276
895
  return undefined;
277
896
  }
278
897
  const verdict = p.verdict;
279
- if (verdict.kind !== (refuses ? 'refuse' : 'send'))
898
+ if (verdict.kind !== (refuses ? 'refuse' : holds ? 'hold' : 'send'))
899
+ return undefined;
900
+ if ((refuses || holds) && !(isRecordShape(verdict.notice) && typeof verdict.notice.text === 'string'))
280
901
  return undefined;
281
- if (refuses && !(isRecordShape(verdict.notice) && typeof verdict.notice.text === 'string'))
902
+ if (!refuses && holds && typeof verdict.consentKey !== 'string')
282
903
  return undefined;
283
904
  if (Object.hasOwn(carried, 'hooks') && carried.hooks !== undefined && !hooksPassJudge(carried.hooks))
284
905
  return undefined;
@@ -288,4 +909,281 @@ export function hostTurnSettingsOf(v, depth = 'full') {
288
909
  return undefined;
289
910
  }
290
911
  }
291
- export const UNWIRED_HOST_TURN_SETTINGS = buildHostTurnSettings({ sources: {} }, (snapshot) => snapshot);
912
+ function wireFormOf(v) {
913
+ const text = JSON.stringify(v);
914
+ return text === undefined ? undefined : JSON.parse(text);
915
+ }
916
+ function sameJson(a, b) {
917
+ if (a === b)
918
+ return true;
919
+ if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null)
920
+ return false;
921
+ if (Array.isArray(a) !== Array.isArray(b))
922
+ return false;
923
+ if (Array.isArray(a) && Array.isArray(b))
924
+ return a.length === b.length && a.every((x, i) => sameJson(x, b[i]));
925
+ const ra = a;
926
+ const rb = b;
927
+ const ka = Object.keys(ra);
928
+ if (ka.length !== Object.keys(rb).length)
929
+ return false;
930
+ return ka.every((k) => Object.hasOwn(rb, k) && sameJson(ra[k], rb[k]));
931
+ }
932
+ function groupHead(g) {
933
+ if (!isRecordShape(g))
934
+ return undefined;
935
+ const head = {};
936
+ for (const k of Object.keys(g))
937
+ if (k !== 'hooks')
938
+ head[k] = g[k];
939
+ return head;
940
+ }
941
+ export function intersectHostHooks(sent, now) {
942
+ try {
943
+ return intersectHostHooksUnguarded(sent, now);
944
+ }
945
+ catch {
946
+ return { hooks: undefined, dropped: 0, judged: false };
947
+ }
948
+ }
949
+ function intersectHostHooksUnguarded(sentIn, nowIn) {
950
+ const sent = wireFormOf(sentIn);
951
+ const now = nowIn === undefined ? undefined : wireFormOf(nowIn);
952
+ const entriesOf = (cfg) => {
953
+ if (!isRecordShape(cfg))
954
+ return 0;
955
+ let n = 0;
956
+ for (const ev of Object.keys(cfg)) {
957
+ const groups = cfg[ev];
958
+ if (!Array.isArray(groups))
959
+ continue;
960
+ for (const g of groups)
961
+ if (isRecordShape(g) && Array.isArray(g.hooks))
962
+ n += g.hooks.length;
963
+ }
964
+ return n;
965
+ };
966
+ const total = entriesOf(sent);
967
+ if (!isRecordShape(sent))
968
+ return { hooks: undefined, dropped: 0, judged: true };
969
+ if (!isRecordShape(now))
970
+ return { hooks: undefined, dropped: total, judged: true };
971
+ const out = {};
972
+ let kept = 0;
973
+ for (const ev of Object.keys(sent)) {
974
+ const groups = sent[ev];
975
+ const nowGroups = now[ev];
976
+ if (!Array.isArray(groups) || !Array.isArray(nowGroups))
977
+ continue;
978
+ const pool = nowGroups.map((g) => ({ head: groupHead(g), left: isRecordShape(g) && Array.isArray(g.hooks) ? [...g.hooks] : [] }));
979
+ const evOut = [];
980
+ for (const g of groups) {
981
+ const head = groupHead(g);
982
+ if (head === undefined || !isRecordShape(g) || !Array.isArray(g.hooks))
983
+ continue;
984
+ const keep = [];
985
+ for (const entry of g.hooks) {
986
+ for (const slot of pool) {
987
+ if (slot.head === undefined || !sameJson(slot.head, head))
988
+ continue;
989
+ const at = slot.left.findIndex((x) => sameJson(x, entry));
990
+ if (at < 0)
991
+ continue;
992
+ slot.left.splice(at, 1);
993
+ appendOwnElement(keep, entry);
994
+ break;
995
+ }
996
+ }
997
+ if (keep.length > 0)
998
+ appendOwnElement(evOut, { ...head, hooks: keep });
999
+ kept += keep.length;
1000
+ }
1001
+ if (evOut.length > 0)
1002
+ out[ev] = evOut;
1003
+ }
1004
+ const hooks = Object.keys(out).length > 0 ? out : undefined;
1005
+ return { hooks, dropped: total - kept, judged: hooks === undefined || hooksPassJudge(hooks) };
1006
+ }
1007
+ function ownDataOf(o, k) {
1008
+ if (typeof o !== 'object' || o === null)
1009
+ return { ok: false };
1010
+ try {
1011
+ return { ok: true, value: ownDataField(o, k) };
1012
+ }
1013
+ catch {
1014
+ return { ok: false };
1015
+ }
1016
+ }
1017
+ function managedOnlySwitchOn(policyDoc) {
1018
+ const r = ownDataOf(policyDoc, 'allowManagedPermissionRulesOnly');
1019
+ return r.ok && r.value === true;
1020
+ }
1021
+ function noticeCopyOf(n) {
1022
+ const id = ownDataOf(n, 'id');
1023
+ const plane = ownDataOf(n, 'plane');
1024
+ const text = ownDataOf(n, 'text');
1025
+ if (!id.ok || !plane.ok || !text.ok || typeof id.value !== 'string' || typeof plane.value !== 'string' || typeof text.value !== 'string')
1026
+ return undefined;
1027
+ return freeze({ id: id.value, plane: plane.value, text: text.value });
1028
+ }
1029
+ function turnNoticesOf(product) {
1030
+ try {
1031
+ return turnNoticesUnguarded(product);
1032
+ }
1033
+ catch {
1034
+ return undefined;
1035
+ }
1036
+ }
1037
+ function turnNoticesUnguarded(product) {
1038
+ const ns = ownDataOf(product, 'notices');
1039
+ if (!ns.ok || !Array.isArray(ns.value))
1040
+ return undefined;
1041
+ const len = ownDataOf(ns.value, 'length');
1042
+ if (!len.ok || typeof len.value !== 'number')
1043
+ return undefined;
1044
+ const out = [];
1045
+ for (let i = 0; i < len.value; i++) {
1046
+ const e = ownDataOf(ns.value, String(i));
1047
+ const copy = e.ok ? noticeCopyOf(e.value) : undefined;
1048
+ if (copy === undefined)
1049
+ return undefined;
1050
+ if (copy.plane === 'turn')
1051
+ appendOwnElement(out, copy);
1052
+ }
1053
+ return freeze(out);
1054
+ }
1055
+ function deepFreeze(v) {
1056
+ if (typeof v === 'object' && v !== null) {
1057
+ for (const x of Object.values(v))
1058
+ deepFreeze(x);
1059
+ Object.freeze(v);
1060
+ }
1061
+ return v;
1062
+ }
1063
+ export function hostIntakeSnapshotOf(product, onResolved) {
1064
+ try {
1065
+ return intakeSnapshotUnguarded(product, onResolved);
1066
+ }
1067
+ catch {
1068
+ return undefined;
1069
+ }
1070
+ }
1071
+ function intakeSnapshotUnguarded(product, onResolved) {
1072
+ if (product === UNWIRED_HOST_TURN_SETTINGS) {
1073
+ return freeze({
1074
+ carried: freeze({}),
1075
+ refuses: false,
1076
+ dispositions: freeze(Object.fromEntries(HOST_SUPPLIED_KEYS.map((k) => [k, 'unwired']))),
1077
+ refusingKeys: freeze([]),
1078
+ turnNotices: freeze([]),
1079
+ notice: undefined,
1080
+ refusalCause: undefined,
1081
+ });
1082
+ }
1083
+ const c = ownDataOf(product, 'carried');
1084
+ if (!c.ok || !isRecordShape(c.value))
1085
+ return undefined;
1086
+ const carriedIn = c.value;
1087
+ const subs = HOST_SUPPLIED_KEYS.map(carriedKeyOf);
1088
+ let keys;
1089
+ try {
1090
+ keys = Reflect.ownKeys(carriedIn);
1091
+ }
1092
+ catch {
1093
+ return undefined;
1094
+ }
1095
+ if (keys.some((k) => typeof k !== 'string' || !subs.includes(k)))
1096
+ return undefined;
1097
+ const values = {};
1098
+ const resolvedR = ownDataOf(carriedIn, 'resolved');
1099
+ if (!resolvedR.ok)
1100
+ return undefined;
1101
+ onResolved?.(resolvedR.value);
1102
+ if (resolvedR.value !== undefined)
1103
+ values.resolved = resolvedR.value;
1104
+ for (const sub of subs.filter((x) => x !== 'resolved')) {
1105
+ const r = ownDataOf(carriedIn, sub);
1106
+ if (!r.ok)
1107
+ return undefined;
1108
+ const copy = deepFreeze(wireFormOf(r.value));
1109
+ if (copy !== undefined)
1110
+ values[sub] = copy;
1111
+ }
1112
+ const rowsR = ownDataOf(product, 'rows');
1113
+ if (!rowsR.ok || !Array.isArray(rowsR.value) || rowsR.value.length !== HOST_SUPPLIED_KEYS.length)
1114
+ return undefined;
1115
+ let refuses = false;
1116
+ let anyRefuse = false;
1117
+ const refusingKeys = [];
1118
+ const dispositions = {};
1119
+ for (const [i, key] of HOST_SUPPLIED_KEYS.entries()) {
1120
+ const rowR = ownDataOf(rowsR.value, String(i));
1121
+ if (!rowR.ok)
1122
+ return undefined;
1123
+ const k = ownDataOf(rowR.value, 'key');
1124
+ const d = ownDataOf(rowR.value, 'disposition');
1125
+ if (!k.ok || !d.ok || k.value !== key || !HOST_SETTING_DISPOSITIONS.includes(d.value))
1126
+ return undefined;
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') {
1131
+ refuses = true;
1132
+ appendOwnElement(refusingKeys, key);
1133
+ }
1134
+ if (d.value === 'refuse_turn')
1135
+ anyRefuse = true;
1136
+ dispositions[key] = d.value;
1137
+ if (d.value !== 'hold_for_consent' && (values[carriedKeyOf(key)] !== undefined) !== CARRYING.has(d.value))
1138
+ return undefined;
1139
+ }
1140
+ if (values.memory !== undefined && values.memory !== 'off')
1141
+ return undefined;
1142
+ if (values.fileHistory !== undefined && values.fileHistory !== 'disabled')
1143
+ return undefined;
1144
+ if (values.hooks !== undefined && !hooksPassJudge(values.hooks))
1145
+ return undefined;
1146
+ const v = ownDataOf(product, 'verdict');
1147
+ if (!v.ok)
1148
+ return undefined;
1149
+ const kind = ownDataOf(v.value, 'kind');
1150
+ if (!kind.ok || kind.value !== (anyRefuse ? 'refuse' : refuses ? 'hold' : 'send'))
1151
+ return undefined;
1152
+ const noticeR = refuses ? ownDataOf(v.value, 'notice') : undefined;
1153
+ const notice = noticeR === undefined ? undefined : ((noticeR.ok ? noticeCopyOf(noticeR.value) : undefined) ?? hostProjectionNotice());
1154
+ return freeze({
1155
+ carried: freeze(values),
1156
+ refuses,
1157
+ dispositions: freeze(dispositions),
1158
+ refusingKeys: freeze(refusingKeys),
1159
+ turnNotices: turnNoticesOf(product),
1160
+ notice,
1161
+ refusalCause: anyRefuse ? refusalCauseOf(product) : undefined,
1162
+ });
1163
+ }
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 }, {
1182
+ materialize: (snapshot) => snapshot,
1183
+ memoryOffDeclared: () => false,
1184
+ });
1185
+ function carriedKeyOf(k) {
1186
+ return k.startsWith('settings.') ? k.slice('settings.'.length) : k;
1187
+ }
1188
+ const _armsPin = [true, true, true, true];
1189
+ void _armsPin;