@sema-agent/client-core 0.93.1 → 0.95.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 (321) hide show
  1. package/CHANGELOG.md +554 -0
  2. package/README.md +89 -55
  3. package/dist/adapt/arms.js +13 -11
  4. package/dist/adapt/panelTasks.js +4 -10
  5. package/dist/adapt/toolCards.js +2 -2
  6. package/dist/adapt/wireShapes.js +3 -8
  7. package/dist/adapter/activeRunSelfHeal.d.ts +8 -3
  8. package/dist/adapter/activeRunSelfHeal.js +20 -12
  9. package/dist/adapter/downstream/eventToSdkMessage.js +24 -17
  10. package/dist/adapter/downstream/terminalToSdkResult.js +13 -6
  11. package/dist/adapter/runStream.js +2 -1
  12. package/dist/adapter/types.d.ts +7 -0
  13. package/dist/adapter/types.js +15 -0
  14. package/dist/agentSession/backgroundView.js +5 -1
  15. package/dist/agentSession/engineAgentRegistryRead.js +2 -1
  16. package/dist/agentSession/engineSessionBackgroundStop.js +5 -3
  17. package/dist/agentsWireCaps.d.ts +17 -0
  18. package/dist/agentsWireCaps.js +111 -1
  19. package/dist/approvalDecidedByCapability.d.ts +0 -1
  20. package/dist/approvalDecidedByCapability.js +2 -7
  21. package/dist/approvalReachWire.d.ts +18 -0
  22. package/dist/approvalReachWire.js +58 -0
  23. package/dist/approvalsStreamLiveCapability.d.ts +0 -1
  24. package/dist/approvalsStreamLiveCapability.js +15 -14
  25. package/dist/atMostOnce.d.ts +8 -0
  26. package/dist/atMostOnce.js +36 -0
  27. package/dist/attachmentSeatCapability.d.ts +0 -1
  28. package/dist/attachmentSeatCapability.js +0 -3
  29. package/dist/attachmentsWireCaps.js +11 -6
  30. package/dist/bashExitReading.d.ts +10 -0
  31. package/dist/bashExitReading.js +12 -0
  32. package/dist/callerCwdCapability.d.ts +15 -0
  33. package/dist/callerCwdCapability.js +42 -0
  34. package/dist/centerWiringCapability.d.ts +1 -3
  35. package/dist/centerWiringCapability.js +18 -21
  36. package/dist/classifierStatus.js +4 -4
  37. package/dist/cloudConfigWireCaps.js +43 -21
  38. package/dist/compensations.js +1 -1
  39. package/dist/controlRouter.js +3 -10
  40. package/dist/coreValuePorts.d.ts +64 -1
  41. package/dist/coreValuePorts.js +30 -0
  42. package/dist/cycleOrder.d.ts +15 -0
  43. package/dist/cycleOrder.js +45 -0
  44. package/dist/decideFailureNote.js +4 -1
  45. package/dist/decideReceipt.d.ts +2 -1
  46. package/dist/decideReceipt.js +41 -13
  47. package/dist/declared/supportFloorDeclared.d.ts +1 -0
  48. package/dist/declared/supportFloorDeclared.js +5 -0
  49. package/dist/detachWire.d.ts +1 -4
  50. package/dist/detachWire.js +1 -1
  51. package/dist/deviceExecutorManagementCapability.d.ts +0 -1
  52. package/dist/deviceExecutorManagementCapability.js +36 -40
  53. package/dist/deviceFlowPolling.d.ts +5 -0
  54. package/dist/deviceFlowPolling.js +28 -0
  55. package/dist/deviceRebind.d.ts +88 -0
  56. package/dist/deviceRebind.js +242 -0
  57. package/dist/displayUntrusted.d.ts +1 -0
  58. package/dist/displayUntrusted.js +963 -30
  59. package/dist/engineAgentAbsence.d.ts +2 -2
  60. package/dist/engineAgentPanelStore.d.ts +8 -18
  61. package/dist/engineAgentPanelStore.js +19 -537
  62. package/dist/engineCapReader.d.ts +6 -6
  63. package/dist/engineCapReader.js +30 -43
  64. package/dist/engineCapsCache.d.ts +7 -2
  65. package/dist/engineCapsCache.js +64 -26
  66. package/dist/engineCredentialRequirement.d.ts +9 -0
  67. package/dist/engineCredentialRequirement.js +23 -0
  68. package/dist/engineEnvSourcing.d.ts +53 -0
  69. package/dist/engineEnvSourcing.js +81 -0
  70. package/dist/engineErrorCodes.d.ts +19 -4
  71. package/dist/engineErrorCodes.js +39 -21
  72. package/dist/engineIdentity.js +2 -0
  73. package/dist/engineNoticeCodes.d.ts +22 -2
  74. package/dist/engineNoticeCodes.js +73 -6
  75. package/dist/engineRefusedToolName.d.ts +1 -0
  76. package/dist/engineRefusedToolName.js +8 -0
  77. package/dist/engineWireSdk.js +2 -2
  78. package/dist/executionLaneCapability.d.ts +2 -3
  79. package/dist/executionLaneCapability.js +28 -28
  80. package/dist/fileHistoryCaptureCapability.d.ts +0 -1
  81. package/dist/fileHistoryCaptureCapability.js +13 -12
  82. package/dist/fileHistoryLegNotice.d.ts +14 -2
  83. package/dist/fileHistoryLegNotice.js +101 -15
  84. package/dist/fleet/fleetLedger.d.ts +2 -0
  85. package/dist/fleet/fleetLedger.js +74 -52
  86. package/dist/fleet/fleetProjection.d.ts +0 -3
  87. package/dist/fleet/fleetProjection.js +9 -16
  88. package/dist/fleetAgentPanelProjection.d.ts +4 -17
  89. package/dist/fleetAgentPanelProjection.js +7 -197
  90. package/dist/fleetAgentRowLike.d.ts +16 -0
  91. package/dist/fleetAgentRowLike.js +1 -0
  92. package/dist/gateOutcome.d.ts +2 -1
  93. package/dist/gateOutcome.js +33 -18
  94. package/dist/gateVocabulary.js +1 -1
  95. package/dist/generated/engineAskFaceTables.d.ts +3 -0
  96. package/dist/generated/engineAskFaceTables.js +12 -0
  97. package/dist/generated/engineFactTables.d.ts +4 -2
  98. package/dist/generated/engineFactTables.js +13 -0
  99. package/dist/generated/engineNoticeTables.d.ts +5 -0
  100. package/dist/generated/engineNoticeTables.js +7 -0
  101. package/dist/generated/sdkFactTables.d.ts +5 -0
  102. package/dist/generated/sdkFactTables.js +34 -0
  103. package/dist/generated/settingsSchemaFns.d.ts +10 -0
  104. package/dist/generated/settingsSchemaFns.js +22 -0
  105. package/dist/generated/settingsSchemaTables.d.ts +3 -0
  106. package/dist/generated/settingsSchemaTables.js +3 -0
  107. package/dist/headlessPermissionModeWire.d.ts +2 -2
  108. package/dist/headlessPermissionModeWire.js +11 -21
  109. package/dist/headlessReconnectWire.js +49 -20
  110. package/dist/hitl/allowRuleShadow.d.ts +1 -1
  111. package/dist/hitl/allowRuleShadow.js +49 -8
  112. package/dist/hitl/approvalCompleteParked.d.ts +1 -0
  113. package/dist/hitl/approvalCompleteParked.js +14 -0
  114. package/dist/hitl/approvalEndingCause.d.ts +5 -0
  115. package/dist/hitl/approvalEndingCause.js +61 -0
  116. package/dist/hitl/approvalHolds.d.ts +46 -0
  117. package/dist/hitl/approvalHolds.js +140 -0
  118. package/dist/hitl/approvalOutcomeNote.js +2 -1
  119. package/dist/hitl/approvalResolution.js +9 -1
  120. package/dist/hitl/approvalsFeed.js +23 -6
  121. package/dist/hitl/askGateWire.d.ts +2 -1
  122. package/dist/hitl/askGateWire.js +29 -1
  123. package/dist/hitl/automaticAnswerVerdict.d.ts +8 -2
  124. package/dist/hitl/automaticAnswerVerdict.js +71 -23
  125. package/dist/hitl/crashConverged.js +2 -0
  126. package/dist/hitl/decisionConflict.d.ts +3 -0
  127. package/dist/hitl/decisionConflict.js +43 -0
  128. package/dist/hitl/decisionRefusal.d.ts +23 -0
  129. package/dist/hitl/decisionRefusal.js +88 -0
  130. package/dist/hitl/frameRouter.d.ts +10 -0
  131. package/dist/hitl/frameRouter.js +71 -32
  132. package/dist/hitl/gateLedger.d.ts +8 -0
  133. package/dist/hitl/gateLedger.js +38 -0
  134. package/dist/hitl/hitlBridge.d.ts +14 -3
  135. package/dist/hitl/hitlBridge.js +75 -62
  136. package/dist/hitl/hitlHostSurface.d.ts +3 -0
  137. package/dist/hitl/hitlHostSurface.js +17 -15
  138. package/dist/hitl/livePendingAsk.d.ts +16 -6
  139. package/dist/hitl/livePendingAsk.js +36 -4
  140. package/dist/hitl/localAllowRule.js +2 -1
  141. package/dist/hitl/noAllowCause.d.ts +9 -0
  142. package/dist/hitl/noAllowCause.js +26 -0
  143. package/dist/hitl/parkExpiryJudgements.d.ts +19 -0
  144. package/dist/hitl/parkExpiryJudgements.js +46 -0
  145. package/dist/hitl/parkResolver.d.ts +3 -7
  146. package/dist/hitl/parkResolver.js +55 -28
  147. package/dist/hitl/parkRowBirthWait.js +2 -1
  148. package/dist/hitl/persistedRulesWire.d.ts +6 -1
  149. package/dist/hitl/persistedRulesWire.js +16 -4
  150. package/dist/hitl/planReviewWire.d.ts +2 -3
  151. package/dist/hitl/planReviewWire.js +86 -39
  152. package/dist/hitl/replayedApproval.d.ts +8 -0
  153. package/dist/hitl/replayedApproval.js +125 -10
  154. package/dist/hitl/resumeRunningCard.d.ts +2 -0
  155. package/dist/hitl/resumeRunningCard.js +15 -4
  156. package/dist/hitl/sessionPolicyDeliverable.d.ts +1 -1
  157. package/dist/hitl/sessionPolicyDeliverable.js +3 -8
  158. package/dist/hitl/sessionPolicyWire.js +1 -1
  159. package/dist/hitl/toolApprovalWire.d.ts +50 -5
  160. package/dist/hitl/toolApprovalWire.js +368 -56
  161. package/dist/hooksWireCaps.js +38 -6
  162. package/dist/host.d.ts +5 -0
  163. package/dist/host.js +3 -1
  164. package/dist/hostCallbackGuard.d.ts +1 -0
  165. package/dist/hostCallbackGuard.js +25 -0
  166. package/dist/humanTurnRead.d.ts +15 -1
  167. package/dist/humanTurnRead.js +28 -2
  168. package/dist/index.d.ts +45 -14
  169. package/dist/index.js +33 -12
  170. package/dist/interactiveInterrupt.d.ts +8 -0
  171. package/dist/interactiveInterrupt.js +54 -0
  172. package/dist/limitsWire.d.ts +5 -1
  173. package/dist/limitsWire.js +51 -13
  174. package/dist/liveModelCatalog.d.ts +109 -0
  175. package/dist/liveModelCatalog.js +344 -18
  176. package/dist/mcpEngineLeg.d.ts +25 -0
  177. package/dist/mcpEngineLeg.js +71 -15
  178. package/dist/mcpPanel.js +2 -1
  179. package/dist/mcpProbeCapability.d.ts +0 -1
  180. package/dist/mcpProbeCapability.js +13 -12
  181. package/dist/mcpReconnect.d.ts +1 -3
  182. package/dist/mcpReconnect.js +20 -10
  183. package/dist/memoryComplianceCapability.d.ts +0 -1
  184. package/dist/memoryComplianceCapability.js +14 -13
  185. package/dist/memoryOriginCapability.d.ts +0 -1
  186. package/dist/memoryOriginCapability.js +14 -13
  187. package/dist/memoryVerbsWire.d.ts +1 -1
  188. package/dist/memoryVerbsWire.js +4 -0
  189. package/dist/model/liveCatalogShape.d.ts +14 -0
  190. package/dist/model/liveCatalogShape.js +71 -0
  191. package/dist/model/modelSupplyRules.d.ts +1 -0
  192. package/dist/model/modelSupplyRules.js +30 -9
  193. package/dist/model/modelsPolicy.d.ts +21 -0
  194. package/dist/model/modelsPolicy.js +90 -0
  195. package/dist/modelIdentityResolvability.d.ts +4 -2
  196. package/dist/modelIdentityResolvability.js +25 -5
  197. package/dist/modelSwitchFallback.d.ts +69 -0
  198. package/dist/modelSwitchFallback.js +206 -0
  199. package/dist/notifications.js +12 -11
  200. package/dist/outputStyleSeatCapability.d.ts +15 -0
  201. package/dist/outputStyleSeatCapability.js +42 -0
  202. package/dist/ownKey.d.ts +7 -0
  203. package/dist/ownKey.js +58 -0
  204. package/dist/panelReduce.d.ts +114 -0
  205. package/dist/panelReduce.js +1135 -0
  206. package/dist/panelStateHolder.d.ts +17 -0
  207. package/dist/panelStateHolder.js +201 -0
  208. package/dist/peerLaneCapability.d.ts +0 -1
  209. package/dist/peerLaneCapability.js +15 -14
  210. package/dist/permissionModesCapability.d.ts +0 -1
  211. package/dist/permissionModesCapability.js +5 -10
  212. package/dist/permissionRuleIssue.js +1 -1
  213. package/dist/permissionRulesWriteCapability.d.ts +0 -1
  214. package/dist/permissionRulesWriteCapability.js +15 -14
  215. package/dist/permissionsAllowGrantCapability.d.ts +2 -1
  216. package/dist/permissionsAllowGrantCapability.js +35 -19
  217. package/dist/permissionsDeclaration.d.ts +16 -1
  218. package/dist/permissionsDeclaration.js +142 -15
  219. package/dist/printToolResultFrame.js +2 -10
  220. package/dist/promptDelivery.js +0 -8
  221. package/dist/protocolSegment.d.ts +1 -0
  222. package/dist/protocolSegment.js +13 -1
  223. package/dist/request/taskRequest.d.ts +11 -3
  224. package/dist/request/taskRequest.js +13 -1
  225. package/dist/resultFrameKeys.d.ts +4 -0
  226. package/dist/resultFrameKeys.js +13 -0
  227. package/dist/resumeRefusalCopy.d.ts +18 -1
  228. package/dist/resumeRefusalCopy.js +132 -31
  229. package/dist/retryStatus.js +6 -4
  230. package/dist/rewindArchiveCapability.d.ts +2 -1
  231. package/dist/rewindArchiveCapability.js +28 -15
  232. package/dist/rewindEngineAction.d.ts +21 -0
  233. package/dist/rewindEngineAction.js +36 -0
  234. package/dist/rewindWireCaps.d.ts +2 -1
  235. package/dist/rewindWireCaps.js +1 -0
  236. package/dist/{hitl/rosterMountedNames.d.ts → rosterMountedNames.d.ts} +1 -1
  237. package/dist/runCancelContext.js +2 -1
  238. package/dist/runTerminal.d.ts +0 -11
  239. package/dist/runTerminal.js +4 -27
  240. package/dist/sdkRegistryTransit.d.ts +2 -1
  241. package/dist/sdkRegistryTransit.js +1 -0
  242. package/dist/sealedKeyCapability.d.ts +0 -1
  243. package/dist/sealedKeyCapability.js +19 -20
  244. package/dist/seatContract.d.ts +85 -28
  245. package/dist/seatContract.js +512 -148
  246. package/dist/sessionIdSegment.d.ts +1 -0
  247. package/dist/sessionIdSegment.js +11 -0
  248. package/dist/sessionMemoryErase.d.ts +1 -1
  249. package/dist/sessionMemoryErase.js +6 -1
  250. package/dist/sessionMemoryStatus.js +3 -2
  251. package/dist/sessionPolicyCapability.d.ts +0 -1
  252. package/dist/sessionPolicyCapability.js +14 -13
  253. package/dist/sessionReadRedactionCapability.d.ts +15 -0
  254. package/dist/sessionReadRedactionCapability.js +42 -0
  255. package/dist/sessionSyncFileHistoryCapability.d.ts +0 -1
  256. package/dist/sessionSyncFileHistoryCapability.js +13 -12
  257. package/dist/skillToolListsCapability.d.ts +0 -1
  258. package/dist/skillToolListsCapability.js +13 -12
  259. package/dist/skillsWireCaps.d.ts +4 -0
  260. package/dist/skillsWireCaps.js +66 -1
  261. package/dist/sqlEngineCapability.d.ts +0 -1
  262. package/dist/sqlEngineCapability.js +21 -21
  263. package/dist/steerPriorityCapability.d.ts +0 -1
  264. package/dist/steerPriorityCapability.js +18 -19
  265. package/dist/storePostureCapability.d.ts +1 -1
  266. package/dist/storePostureCapability.js +16 -16
  267. package/dist/streamDrainingLegs.d.ts +6 -0
  268. package/dist/streamDrainingLegs.js +23 -0
  269. package/dist/subagent/agentStateDetail.d.ts +1 -0
  270. package/dist/subagent/agentStateDetail.js +41 -0
  271. package/dist/subagent/engineCompactWire.d.ts +15 -0
  272. package/dist/subagent/engineCompactWire.js +82 -45
  273. package/dist/subagent/engineDelegatedPrompt.js +10 -6
  274. package/dist/subagent/engineSubagentOutput.d.ts +0 -1
  275. package/dist/subagent/engineSubagentOutput.js +5 -20
  276. package/dist/subagent/engineSubagentTail.d.ts +0 -1
  277. package/dist/subagent/engineSubagentTail.js +7 -32
  278. package/dist/subagentContentStore.js +3 -3
  279. package/dist/supportFloor.js +2 -5
  280. package/dist/taskRequestWords.d.ts +2 -4
  281. package/dist/taskRequestWords.js +3 -2
  282. package/dist/terminalStatuses.d.ts +30 -0
  283. package/dist/terminalStatuses.js +67 -0
  284. package/dist/toolResult.d.ts +5 -0
  285. package/dist/toolResult.js +88 -36
  286. package/dist/types/engineState.d.ts +2 -1
  287. package/dist/usageAnalytics.d.ts +146 -0
  288. package/dist/usageAnalytics.js +311 -0
  289. package/dist/userAttachmentEnvelope.d.ts +22 -1
  290. package/dist/userAttachmentEnvelope.js +90 -2
  291. package/dist/userInvokedSkillsCapability.d.ts +0 -1
  292. package/dist/userInvokedSkillsCapability.js +13 -12
  293. package/dist/webSearchBackendCapability.d.ts +0 -1
  294. package/dist/webSearchBackendCapability.js +20 -19
  295. package/dist/webSearchWireCaps.js +3 -11
  296. package/dist/wireErrorTriage.d.ts +11 -0
  297. package/dist/wireErrorTriage.js +35 -0
  298. package/dist/wireFailureShape.d.ts +10 -0
  299. package/dist/wireFailureShape.js +72 -5
  300. package/dist/wireRefusalCopy.d.ts +6 -1
  301. package/dist/wireRefusalCopy.js +23 -25
  302. package/dist/wiringInstructionsAttribution.d.ts +10 -0
  303. package/dist/wiringInstructionsAttribution.js +67 -0
  304. package/dist/workflowClient.js +19 -2
  305. package/dist/workflowsJournalCapability.d.ts +0 -1
  306. package/dist/workflowsJournalCapability.js +13 -12
  307. package/dist/writeProtectionCapability.d.ts +0 -1
  308. package/dist/writeProtectionCapability.js +26 -26
  309. package/docs/INTEGRATION-CLIENTS.md +1733 -52
  310. package/package.json +5 -5
  311. package/dist/askSurvivesStandingAnswer.d.ts +0 -13
  312. package/dist/askSurvivesStandingAnswer.js +0 -53
  313. package/dist/engineCapsGenerationGuard.d.ts +0 -4
  314. package/dist/engineCapsGenerationGuard.js +0 -19
  315. package/dist/hitl/askSurvivesPosture.d.ts +0 -20
  316. package/dist/hitl/askSurvivesPosture.js +0 -48
  317. package/dist/panelRunningHistory.d.ts +0 -22
  318. package/dist/panelRunningHistory.js +0 -82
  319. package/dist/registryConflict.d.ts +0 -3
  320. package/dist/registryConflict.js +0 -44
  321. /package/dist/{hitl/rosterMountedNames.js → rosterMountedNames.js} +0 -0
@@ -0,0 +1,14 @@
1
+ function ownData(o, key) {
2
+ const d = Object.getOwnPropertyDescriptor(o, key);
3
+ return d !== undefined && 'value' in d ? d.value : undefined;
4
+ }
5
+ export function approvalCompleteParked(frame) {
6
+ try {
7
+ if (frame === null || typeof frame !== 'object')
8
+ return false;
9
+ return ownData(frame, 'outcome') === 'expired' && ownData(frame, 'parked') === true;
10
+ }
11
+ catch {
12
+ return false;
13
+ }
14
+ }
@@ -0,0 +1,5 @@
1
+ import type { ApprovalSettleCause, AskRowEndingCause } from '@sema-agent/sdk';
2
+ export declare const ASK_ROW_ENDING_CAUSE_WORDS: readonly ["routing_failure_fail_closed", "run_cancelled", "run_exited", "batch_aborted", "batch_sibling_withdrawn", "batch_bound_elsewhere", "adhoc_leg_no_durable_domain", "orphan_ttl_exceeded", "crashed_before_park", "shutdown_before_park"];
3
+ export declare function askRowEndingCauseFor(state: 'VOID' | 'DENIED' | undefined, word: unknown): AskRowEndingCause | undefined;
4
+ export declare function approvalCompleteCauseOf(frame: unknown): ApprovalSettleCause | undefined;
5
+ export declare function notPendingCauseSaysEnded(err: object): boolean;
@@ -0,0 +1,61 @@
1
+ import { ASK_GONE_DENIED_WORD } from '../engineErrorCodes.js';
2
+ import { SDK_ASK_ROW_ENDING_CAUSES } from '../generated/sdkFactTables.js';
3
+ export const ASK_ROW_ENDING_CAUSE_WORDS = SDK_ASK_ROW_ENDING_CAUSES;
4
+ const _askRowCausePin = true;
5
+ void _askRowCausePin;
6
+ const DENIED_GROUP_WORD = ASK_GONE_DENIED_WORD;
7
+ const WAIT_CLASS_SETTLE_CAUSE_WORDS = Object.freeze({
8
+ ttl_expired: true,
9
+ broadcast_lost: true,
10
+ stream_disconnected: true,
11
+ undeliverable: true,
12
+ });
13
+ function isAskRowEndingCause(v) {
14
+ return typeof v === 'string' && ASK_ROW_ENDING_CAUSE_WORDS.includes(v);
15
+ }
16
+ function isApprovalSettleCause(v) {
17
+ return isAskRowEndingCause(v) || (typeof v === 'string' && Object.hasOwn(WAIT_CLASS_SETTLE_CAUSE_WORDS, v));
18
+ }
19
+ export function askRowEndingCauseFor(state, word) {
20
+ if (!isAskRowEndingCause(word))
21
+ return undefined;
22
+ if (state === 'DENIED')
23
+ return word === DENIED_GROUP_WORD ? word : undefined;
24
+ if (state === 'VOID')
25
+ return word !== DENIED_GROUP_WORD ? word : undefined;
26
+ return undefined;
27
+ }
28
+ export function approvalCompleteCauseOf(frame) {
29
+ try {
30
+ if (typeof frame !== 'object' || frame === null)
31
+ return undefined;
32
+ const typeSlot = Object.getOwnPropertyDescriptor(frame, 'type');
33
+ if (typeSlot === undefined || !Object.hasOwn(typeSlot, 'value') || typeSlot.value !== 'tool_approval_complete')
34
+ return undefined;
35
+ const causeSlot = Object.getOwnPropertyDescriptor(frame, 'cause');
36
+ if (causeSlot === undefined || !Object.hasOwn(causeSlot, 'value'))
37
+ return undefined;
38
+ const word = causeSlot.value;
39
+ return isApprovalSettleCause(word) ? word : undefined;
40
+ }
41
+ catch {
42
+ return undefined;
43
+ }
44
+ }
45
+ const LEGACY_NOT_PENDING_ENDED_WORDS = new Set(['voided', 'denied']);
46
+ export function notPendingCauseSaysEnded(err) {
47
+ try {
48
+ const extraSlot = Object.getOwnPropertyDescriptor(err, 'extra');
49
+ const extra = extraSlot !== undefined && Object.hasOwn(extraSlot, 'value') ? extraSlot.value : undefined;
50
+ if (typeof extra !== 'object' || extra === null || Array.isArray(extra))
51
+ return false;
52
+ const causeSlot = Object.getOwnPropertyDescriptor(extra, 'cause');
53
+ if (causeSlot === undefined || !Object.hasOwn(causeSlot, 'value'))
54
+ return false;
55
+ const word = causeSlot.value;
56
+ return isAskRowEndingCause(word) || (typeof word === 'string' && LEGACY_NOT_PENDING_ENDED_WORDS.has(word));
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ }
@@ -0,0 +1,46 @@
1
+ import type { ApprovalHolderIdentity, FsApprovalOutcome, ToolApprovalFrameOutcome } from './toolApprovalWire.js';
2
+ export interface DurableDecisionHold {
3
+ readonly lane: 'durable';
4
+ readonly outcome: Promise<FsApprovalOutcome>;
5
+ presented: boolean;
6
+ readonly interrupt: () => void;
7
+ readonly cardSignal: AbortSignal;
8
+ trailing?: Promise<unknown>;
9
+ }
10
+ export interface LiveCardHold {
11
+ readonly lane: 'live';
12
+ readonly identity: LiveCardIdentity;
13
+ readonly outcome: Promise<ToolApprovalFrameOutcome>;
14
+ phase: 'card' | 'respond';
15
+ superseded?: {
16
+ readonly parked: boolean;
17
+ };
18
+ readonly cardSignal: AbortSignal;
19
+ readonly interrupt: () => void;
20
+ trailing?: Promise<void>;
21
+ }
22
+ export type ApprovalHold = DurableDecisionHold | LiveCardHold;
23
+ export interface LiveCardIdentity {
24
+ readonly approvalId: string;
25
+ readonly toolCallId?: string;
26
+ readonly taskId?: string;
27
+ readonly sessionId?: string;
28
+ }
29
+ export declare function liveCardHoldFor(who: ApprovalHolderIdentity): LiveCardHold | undefined;
30
+ export declare function liveCardAnsweredHow(o: ToolApprovalFrameOutcome): 'answered' | 'interrupted' | undefined;
31
+ export declare function awaitLiveCardHolder(hold: LiveCardHold, signal: AbortSignal | undefined): Promise<ToolApprovalFrameOutcome | undefined>;
32
+ export interface ApprovalDecisionHoldTable {
33
+ readonly inFlight: Map<string, ApprovalHold>;
34
+ readonly settled: Map<string, DurableSettledHold>;
35
+ readonly openReads: Set<number>;
36
+ clock: number;
37
+ }
38
+ export interface DurableSettledHold {
39
+ readonly at: number;
40
+ readonly hold: DurableDecisionHold;
41
+ }
42
+ export declare const approvalDecisionHolds: ApprovalDecisionHoldTable;
43
+ export declare function liveCardHoldOf(key: string): LiveCardHold | undefined;
44
+ export declare function holdLiveCard(identity: LiveCardIdentity, callerSignal: AbortSignal | undefined, present: (hold: LiveCardHold) => Promise<ToolApprovalFrameOutcome>): Promise<ToolApprovalFrameOutcome>;
45
+ export declare function joinLiveCard(hold: LiveCardHold, signal: AbortSignal | undefined): Promise<ToolApprovalFrameOutcome>;
46
+ export declare function supersedeLiveCard(key: string, parked: boolean): boolean;
@@ -0,0 +1,140 @@
1
+ import { hostLog } from '../host.js';
2
+ import { liveFrameCallKey } from './gateIdentity.js';
3
+ import { approvalResolutionOf } from './approvalResolution.js';
4
+ const nonEmpty = (v) => typeof v === 'string' && v !== '';
5
+ export function liveCardHoldFor(who) {
6
+ if (nonEmpty(who.approvalId))
7
+ return liveCardHoldOf(liveFrameCallKey(who.approvalId));
8
+ if (!nonEmpty(who.taskId) || !nonEmpty(who.toolCallId))
9
+ return undefined;
10
+ for (const h of approvalDecisionHolds.inFlight.values()) {
11
+ if (h.lane !== 'live' || h.phase !== 'card')
12
+ continue;
13
+ const id = h.identity;
14
+ if (id.taskId !== who.taskId || id.toolCallId !== who.toolCallId)
15
+ continue;
16
+ if (nonEmpty(who.sessionId) && nonEmpty(id.sessionId) && id.sessionId !== who.sessionId)
17
+ continue;
18
+ return h;
19
+ }
20
+ return undefined;
21
+ }
22
+ function liveCardSettledQuestion(hold, o) {
23
+ const r = approvalResolutionOf(o);
24
+ if (answeredHowOf(r) !== undefined)
25
+ return true;
26
+ if (r.kind === 'unsettled')
27
+ return false;
28
+ return hold.superseded !== undefined && !hold.superseded.parked;
29
+ }
30
+ export function liveCardAnsweredHow(o) {
31
+ return answeredHowOf(approvalResolutionOf(o));
32
+ }
33
+ function answeredHowOf(r) {
34
+ if (r.kind === 'decided')
35
+ return 'answered';
36
+ return r.kind === 'unsettled' && r.cause === 'interrupted' ? 'interrupted' : undefined;
37
+ }
38
+ export async function awaitLiveCardHolder(hold, signal) {
39
+ const unsubscribe = followCallerSignal(signal, hold.interrupt);
40
+ let o;
41
+ try {
42
+ o = await hold.outcome;
43
+ }
44
+ catch {
45
+ return undefined;
46
+ }
47
+ finally {
48
+ unsubscribe();
49
+ }
50
+ return liveCardSettledQuestion(hold, o) ? { ...o, joinedInFlight: true } : undefined;
51
+ }
52
+ export const approvalDecisionHolds = { inFlight: new Map(), settled: new Map(), openReads: new Set(), clock: 0 };
53
+ export function liveCardHoldOf(key) {
54
+ const h = approvalDecisionHolds.inFlight.get(key);
55
+ return h !== undefined && h.lane === 'live' ? h : undefined;
56
+ }
57
+ export function holdLiveCard(identity, callerSignal, present) {
58
+ const key = liveFrameCallKey(identity.approvalId);
59
+ const h = approvalDecisionHolds;
60
+ const cut = new AbortController();
61
+ let settled = false;
62
+ const interrupt = () => {
63
+ if (!settled && !cut.signal.aborted)
64
+ cut.abort();
65
+ };
66
+ const unsubscribe = followCallerSignal(callerSignal, interrupt);
67
+ let resolveOutcome = () => { };
68
+ let rejectOutcome = () => { };
69
+ const outcome = new Promise((resolve, reject) => {
70
+ resolveOutcome = resolve;
71
+ rejectOutcome = reject;
72
+ });
73
+ const hold = { lane: 'live', identity: Object.freeze({ ...identity }), outcome, phase: 'card', cardSignal: cut.signal, interrupt };
74
+ h.inFlight.set(key, hold);
75
+ const release = () => {
76
+ if (h.inFlight.get(key) === hold)
77
+ h.inFlight.delete(key);
78
+ };
79
+ const settle = (give) => {
80
+ settled = true;
81
+ unsubscribe();
82
+ const trailing = hold.trailing;
83
+ if (trailing === undefined) {
84
+ release();
85
+ give();
86
+ return;
87
+ }
88
+ give();
89
+ trailing.then(release, release);
90
+ };
91
+ let run;
92
+ try {
93
+ run = present(hold);
94
+ }
95
+ catch (e) {
96
+ run = Promise.reject(e);
97
+ }
98
+ run.then((o) => settle(() => resolveOutcome(o)), (e) => settle(() => rejectOutcome(e)));
99
+ return outcome;
100
+ }
101
+ export async function joinLiveCard(hold, signal) {
102
+ const unsubscribe = followCallerSignal(signal, hold.interrupt);
103
+ try {
104
+ const o = await hold.outcome;
105
+ return { ...o, joinedInFlight: true };
106
+ }
107
+ finally {
108
+ unsubscribe();
109
+ }
110
+ }
111
+ function followCallerSignal(signal, onAbort) {
112
+ if (signal === undefined || signal === null)
113
+ return () => { };
114
+ try {
115
+ if (signal.aborted === true) {
116
+ onAbort();
117
+ return () => { };
118
+ }
119
+ signal.addEventListener('abort', onAbort, { once: true });
120
+ }
121
+ catch {
122
+ return () => { };
123
+ }
124
+ return () => {
125
+ try {
126
+ signal.removeEventListener('abort', onAbort);
127
+ }
128
+ catch (e) {
129
+ hostLog('debug', `approvalHolds: could not detach from the caller's abort signal (${String(e).slice(0, 120)}) — the listener is one-shot and inert after settle`);
130
+ }
131
+ };
132
+ }
133
+ export function supersedeLiveCard(key, parked) {
134
+ const hold = liveCardHoldOf(key);
135
+ if (hold === undefined || hold.phase !== 'card' || hold.superseded !== undefined)
136
+ return false;
137
+ hold.superseded = Object.freeze({ parked });
138
+ hold.interrupt();
139
+ return true;
140
+ }
@@ -17,7 +17,8 @@ function detailOf(r) {
17
17
  }
18
18
  export function approvalOutcomeNoteOf(frame, outcome) {
19
19
  const r = approvalResolutionOf(outcome);
20
- const retracted = approvalNotSentCause(r) === 'retracted';
20
+ const cause = approvalNotSentCause(r);
21
+ const retracted = cause === 'retracted';
21
22
  const detail = detailOf(r);
22
23
  return {
23
24
  approvalId: frame.approvalId,
@@ -106,13 +106,21 @@ function parkingViewOf(v) {
106
106
  const hint = pick(v, 'retryAfterMs');
107
107
  const retryAfterMs = typeof hint === 'number' && Number.isFinite(hint) && hint >= 0 ? hint : undefined;
108
108
  const decidePath = str(pick(v, 'decidePath'));
109
- return { approvalId, ...(retryAfterMs !== undefined ? { retryAfterMs } : {}), ...(decidePath !== undefined ? { decidePath } : {}) };
109
+ const message = str(pick(v, 'message'));
110
+ return {
111
+ approvalId,
112
+ ...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
113
+ ...(decidePath !== undefined ? { decidePath } : {}),
114
+ ...(message !== undefined ? { message } : {}),
115
+ };
110
116
  }
111
117
  function frameLegResolution(outcome) {
112
118
  if (pick(outcome, 'retracted') === true)
113
119
  return { kind: 'not_sent', cause: 'retracted' };
114
120
  if (pick(outcome, 'editRefused') === true)
115
121
  return { kind: 'not_sent', cause: 'edit_refused' };
122
+ if (pick(outcome, 'aborted') === true)
123
+ return { kind: 'unsettled', cause: 'interrupted' };
116
124
  const parking = parkingViewOf(pick(outcome, 'parking'));
117
125
  if (parking !== undefined)
118
126
  return { kind: 'unsettled', cause: 'parking_in_progress', parking };
@@ -1,6 +1,7 @@
1
1
  import { hostLog } from '../host.js';
2
2
  import { unrefTimer } from '../unrefTimer.js';
3
3
  import { readLivePendingRows } from './livePendingAsk.js';
4
+ import { createStreamDrainingLegs } from '../streamDrainingLegs.js';
4
5
  const MAX_CONSECUTIVE_POLL_ESCAPES = 5;
5
6
  function readDurablePendingRows(raw) {
6
7
  if (!Array.isArray(raw))
@@ -364,7 +365,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
364
365
  .then(() => scheduleReconcile());
365
366
  }, reconcileDelayMs));
366
367
  }
367
- function scheduleStreamRetry() {
368
+ function scheduleStreamRetry(afterMs = streamRetryMs) {
368
369
  if (stopped || ac.signal.aborted || streamRetryMs <= 0)
369
370
  return;
370
371
  if (!client.approvals.stream)
@@ -377,9 +378,9 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
377
378
  return;
378
379
  hostLog('debug', 'approvalsFeed: retrying push leg (降级是暂时的,服务端升级后不该还要重启客户端)');
379
380
  void runStream();
380
- }, streamRetryMs));
381
+ }, afterMs));
381
382
  }
382
- function degradeToPoll(why, real = true) {
383
+ function degradeToPoll(why, real = true, retryAfterMs) {
383
384
  if (stopped)
384
385
  return;
385
386
  if (real)
@@ -389,8 +390,9 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
389
390
  }
390
391
  mode = 'poll';
391
392
  schedulePoll();
392
- scheduleStreamRetry();
393
+ scheduleStreamRetry(retryAfterMs);
393
394
  }
395
+ const drains = createStreamDrainingLegs();
394
396
  async function runStream() {
395
397
  const stream = client.approvals.stream;
396
398
  if (!stream) {
@@ -401,6 +403,10 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
401
403
  for await (const ev of stream.call(client.approvals, { signal: ac.signal })) {
402
404
  if (stopped || ac.signal.aborted)
403
405
  return;
406
+ if (drains.see(ev)) {
407
+ hostLog('debug', 'approvalsFeed: push leg received the drain end frame — the engine is going down; this leg ends with it and reopens on the draining ladder');
408
+ continue;
409
+ }
404
410
  if (mode !== 'push') {
405
411
  mode = 'push';
406
412
  if (pollTimer !== undefined) {
@@ -418,10 +424,21 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
418
424
  stats.pushEvents++;
419
425
  await take('push');
420
426
  }
421
- if (!stopped && !ac.signal.aborted)
422
- degradeToPoll('stream ended without progress');
427
+ if (stopped || ac.signal.aborted)
428
+ return;
429
+ const drained = drains.legEnded('returned');
430
+ if (drained !== undefined) {
431
+ const decision = drained;
432
+ if ('reconnectAfterMs' in decision)
433
+ degradeToPoll(`engine draining — push leg closed; reopening in ${decision.reconnectAfterMs}ms`, false, decision.reconnectAfterMs);
434
+ else
435
+ degradeToPoll(`engine draining — reconnect attempts exhausted (${decision.giveUp})`);
436
+ return;
437
+ }
438
+ degradeToPoll('stream ended without progress');
423
439
  }
424
440
  catch (e) {
441
+ drains.legEnded('threw');
425
442
  if (stopped || ac.signal.aborted)
426
443
  return;
427
444
  degradeToPoll(String(e));
@@ -8,9 +8,10 @@ export type { AskAnsweredOutput } from './gateLedger.js';
8
8
  export { SEMA_COLLATERAL_ABORT_KEY } from './gateLedger.js';
9
9
  export { SEMA_DENIAL_KIND_KEY } from './gateLedger.js';
10
10
  export type { GateDenyAttribution } from './gateLedger.js';
11
- export { toAnsweredOutput, isAlreadyResolvedFailure, isAlreadyResolvedGateReason, isGateStandingErrorCode, isCodeClassifiedGateFailure, GATE_FAILURE_CODES, nextHopBudget, MAX_GATE_HOPS, MAX_TOTAL_PARKS } from './parkResolver.js';
11
+ export { toAnsweredOutput, isAlreadyResolvedFailure, isAlreadyResolvedGateReason, isGateStandingErrorCode, isCodeClassifiedGateFailure, nextHopBudget, MAX_GATE_HOPS, MAX_TOTAL_PARKS } from './parkResolver.js';
12
12
  export type { HopBudget, HopRound } from './parkResolver.js';
13
13
  export type { GateOutcome, GateFailureCode } from './parkResolver.js';
14
+ export { GATE_FAILURE_CODES } from './hitlBridge.js';
14
15
  export declare function bridgeAskUserQuestionGates(source: AsyncGenerator<AgentEvent>, deps: AskGateWireDeps, opts?: {
15
16
  signal?: AbortSignal;
16
17
  taskId?: string;
@@ -1,12 +1,16 @@
1
1
  import { createGateLedger } from './gateLedger.js';
2
2
  import { flushHeldWithInterruptRewrite, isHostProgressFrame, routeFrame, } from './frameRouter.js';
3
3
  import { resolvePark, nextHopBudget, stalledTerminal, MAX_GATE_HOPS } from './parkResolver.js';
4
+ import { createStreamDrainingLegs } from '../streamDrainingLegs.js';
5
+ import { abortableSleep } from '../abortableSleep.js';
6
+ import { hostLog } from '../host.js';
4
7
  export { HITL_REJECT_MESSAGE, ENGINE_ABORT_TOOL_RESULT } from './frameRouter.js';
5
8
  export { HITL_INTERRUPT_MESSAGE_FOR_TOOL_USE } from './frameRouter.js';
6
9
  export { HITL_POLICY_DENY_MESSAGE } from './frameRouter.js';
7
10
  export { SEMA_COLLATERAL_ABORT_KEY } from './gateLedger.js';
8
11
  export { SEMA_DENIAL_KIND_KEY } from './gateLedger.js';
9
- export { toAnsweredOutput, isAlreadyResolvedFailure, isAlreadyResolvedGateReason, isGateStandingErrorCode, isCodeClassifiedGateFailure, GATE_FAILURE_CODES, nextHopBudget, MAX_GATE_HOPS, MAX_TOTAL_PARKS } from './parkResolver.js';
12
+ export { toAnsweredOutput, isAlreadyResolvedFailure, isAlreadyResolvedGateReason, isGateStandingErrorCode, isCodeClassifiedGateFailure, nextHopBudget, MAX_GATE_HOPS, MAX_TOTAL_PARKS } from './parkResolver.js';
13
+ export { GATE_FAILURE_CODES } from './hitlBridge.js';
10
14
  export async function* bridgeAskUserQuestionGates(source, deps, opts) {
11
15
  const led = createGateLedger();
12
16
  const taskId = { current: opts?.taskId };
@@ -24,9 +28,15 @@ export async function* bridgeAskUserQuestionGates(source, deps, opts) {
24
28
  let lastResolvedGatedCallId;
25
29
  let lastRoundDecided = false;
26
30
  let unverifiableParks = 0;
31
+ const drains = createStreamDrainingLegs();
27
32
  while (true) {
28
33
  let park = null;
29
34
  for await (const ev of stream) {
35
+ if (drains.see(ev))
36
+ continue;
37
+ const answering = led.answeringLiveCards();
38
+ if (answering.length > 0)
39
+ await Promise.all(answering);
30
40
  led.noteSeq(ev);
31
41
  if (isHostProgressFrame(ev))
32
42
  progressedSinceReattach = true;
@@ -54,6 +64,24 @@ export async function* bridgeAskUserQuestionGates(source, deps, opts) {
54
64
  break;
55
65
  }
56
66
  if (!park) {
67
+ const drained = drains.legEnded('returned');
68
+ if (drained !== undefined) {
69
+ const reopenAfterMs = 'reconnectAfterMs' in drained ? drained.reconnectAfterMs : undefined;
70
+ if (reopenAfterMs !== undefined && taskId.current !== undefined && !opts?.signal?.aborted) {
71
+ hostLog('debug', `liveHitlAskWire: runs.events(${taskId.current}) ended on the drain end frame — the engine is going down; reopening in ${reopenAfterMs}ms`);
72
+ await abortableSleep(reopenAfterMs, opts?.signal ?? new AbortController().signal);
73
+ if (!opts?.signal?.aborted) {
74
+ const seq = led.lastSeq();
75
+ led.beginStreamSegment();
76
+ stream = deps.runsEvents(taskId.current, {
77
+ ...(seq !== undefined ? { lastEventId: seq } : {}),
78
+ ...(opts?.signal ? { signal: opts.signal } : {}),
79
+ });
80
+ continue;
81
+ }
82
+ }
83
+ hostLog('debug', `liveHitlAskWire: runs.events ended on the drain end frame and is not reopened (${'giveUp' in drained ? drained.giveUp : taskId.current === undefined ? 'no run handle' : 'aborted'}) — ending this leg like a dropped stream`);
84
+ }
57
85
  yield* flushHeldWithInterruptRewrite(led, { signal: opts?.signal });
58
86
  return;
59
87
  }
@@ -1,5 +1,7 @@
1
1
  import { type CoreModeArbitrationRow } from '../generated/engineFactTables.js';
2
- export type AutomaticAnswerLane = 'mode_posture' | 'standing_rule';
2
+ import { CORE_ASK_FACES } from '../generated/engineAskFaceTables.js';
3
+ export type AutomaticAnswerLane = 'mode_posture' | 'standing_rule' | 'permission_request_hook';
4
+ export type AutomaticAnswerAskFace = (typeof CORE_ASK_FACES)[number];
3
5
  export interface AutomaticAnswerFacts {
4
6
  readonly settingsAskRuleMatched?: boolean;
5
7
  }
@@ -17,5 +19,9 @@ export type AutomaticAnswerVerdict = {
17
19
  readonly kind: 'unknown';
18
20
  readonly why: AutomaticAnswerUnknownWhy;
19
21
  };
20
- export declare function foldModeArbitrationRow(classes: Iterable<string>): CoreModeArbitrationRow;
22
+ export declare const MODE_ARBITRATION: Readonly<Record<"hook" | "write_protection" | "mode" | "rule_unreadable" | "write_protection_unresolved" | "content_question" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "transcript_write" | "org_rule" | "governance_unavailable" | "ask_rule" | "denial_limit_fallback" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", CoreModeArbitrationRow>>;
23
+ export declare function foldModeArbitrationRow(classes: Iterable<string>, askFace?: AutomaticAnswerAskFace): CoreModeArbitrationRow;
21
24
  export declare function automaticAnswerVerdict(card: object | null | undefined, lane: AutomaticAnswerLane, facts?: AutomaticAnswerFacts | null): AutomaticAnswerVerdict;
25
+ export declare function mandatedApprovalDetailOf(card: object | null | undefined): string;
26
+ export type PermissionRequestHookScope = 'allow_or_deny' | 'deny_only' | 'skip';
27
+ export declare function permissionRequestHookScope(verdict: AutomaticAnswerVerdict | null | undefined): PermissionRequestHookScope;
@@ -1,8 +1,11 @@
1
1
  import { CORE_MODE_ARBITRATION, CORE_MODE_RELEASE_REASONS } from '../generated/engineFactTables.js';
2
- import { readOwnNonEmptyString } from '../ownKey.js';
2
+ import { CORE_RELEASABLE_ASK_CLASSES_BY_FACE, CORE_SHELL_FACE_TOOL_NAMES } from '../generated/engineAskFaceTables.js';
3
+ import { mandatedApprovalDetail } from '../gateVocabulary.js';
4
+ import { readAskOrigin, readOwnNonEmptyString } from '../ownKey.js';
3
5
  import { readAskClassPairState } from './askClassPair.js';
4
6
  import { approvalAllowRuleShadowed } from './allowRuleShadow.js';
5
7
  import { approvalIsMandated, readApprovalMandate } from './toolApprovalWire.js';
8
+ export const MODE_ARBITRATION = CORE_MODE_ARBITRATION;
6
9
  const TABLE = CORE_MODE_ARBITRATION;
7
10
  const ORIGIN_IMPLIES_CLASS = Object.freeze({
8
11
  content_question: 'content_question',
@@ -12,12 +15,26 @@ const ORIGIN_IMPLIES_CLASS = Object.freeze({
12
15
  ask_rule: 'ask_rule',
13
16
  denial_limit_fallback: 'denial_limit_fallback',
14
17
  });
15
- const MANDATE_WORD_IMPLIES_CLASS = Object.freeze({
16
- operator_always: 'shell_floor',
17
- write_protection_unresolved: 'write_protection_unresolved',
18
- });
18
+ function mandateWordClass(word) {
19
+ if (word === 'operator_always')
20
+ return 'shell_floor';
21
+ return Object.hasOwn(TABLE, word) ? word : undefined;
22
+ }
19
23
  const ORDINARY_ROW = CORE_MODE_ARBITRATION.ordinary;
20
- export function foldModeArbitrationRow(classes) {
24
+ function bypassImmuneOn(c, face) {
25
+ const on = face !== undefined && Object.hasOwn(CORE_RELEASABLE_ASK_CLASSES_BY_FACE, face) ? face : 'other';
26
+ return !CORE_RELEASABLE_ASK_CLASSES_BY_FACE[on].includes(c);
27
+ }
28
+ function askFaceOfCard(card) {
29
+ try {
30
+ const d = Object.getOwnPropertyDescriptor(card, 'toolName');
31
+ return d !== undefined && 'value' in d && typeof d.value === 'string' && CORE_SHELL_FACE_TOOL_NAMES.includes(d.value) ? 'shell' : 'other';
32
+ }
33
+ catch {
34
+ return 'other';
35
+ }
36
+ }
37
+ export function foldModeArbitrationRow(classes, askFace) {
21
38
  let any = false;
22
39
  let bypassImmune = false;
23
40
  let classifierEligible = true;
@@ -29,7 +46,7 @@ export function foldModeArbitrationRow(classes) {
29
46
  continue;
30
47
  const row = TABLE[c];
31
48
  any = true;
32
- bypassImmune ||= row.bypassImmune;
49
+ bypassImmune ||= bypassImmuneOn(c, askFace);
33
50
  classifierEligible &&= row.classifierEligible;
34
51
  sandboxAdmission &&= row.sandboxAdmission;
35
52
  ruleMayClear &&= row.ruleMayClear;
@@ -39,8 +56,12 @@ export function foldModeArbitrationRow(classes) {
39
56
  return ORDINARY_ROW;
40
57
  return Object.freeze({ bypassImmune, classifierEligible, sandboxAdmission, ruleMayClear, hookAskFloor });
41
58
  }
42
- function laneBlocks(lane, row) {
43
- return lane === 'mode_posture' ? row.bypassImmune : !row.ruleMayClear;
59
+ function rowBlocks(lane, row) {
60
+ return lane === 'mode_posture' ? row.bypassImmune : lane === 'standing_rule' ? !row.ruleMayClear : row.hookAskFloor;
61
+ }
62
+ function classBlocks(lane, c, face) {
63
+ const row = TABLE[c];
64
+ return lane === 'mode_posture' ? bypassImmuneOn(c, face) : lane === 'standing_rule' ? !row.ruleMayClear : row.hookAskFloor;
44
65
  }
45
66
  function mustAsk(road, extra) {
46
67
  return Object.freeze({ kind: 'must_ask', road, ...(extra?.askClass !== undefined ? { askClass: extra.askClass } : {}), ...(extra?.origin !== undefined ? { origin: extra.origin } : {}) });
@@ -75,34 +96,33 @@ function readHostAskRuleMatched(facts) {
75
96
  }
76
97
  }
77
98
  export function automaticAnswerVerdict(card, lane, facts) {
78
- if (lane !== 'mode_posture' && lane !== 'standing_rule')
99
+ if (lane !== 'mode_posture' && lane !== 'standing_rule' && lane !== 'permission_request_hook')
79
100
  return UNKNOWN.lane_not_recognised;
80
101
  try {
81
102
  if (typeof card !== 'object' || card === null)
82
103
  return UNKNOWN.card_unreadable;
83
- const origin = readOwnNonEmptyString(evidenceView(card, 'origin'), 'origin');
104
+ const face = lane === 'mode_posture' ? askFaceOfCard(card) : undefined;
105
+ const origin = readAskOrigin(evidenceView(card, 'origin'));
84
106
  if (origin !== undefined && Object.hasOwn(ORIGIN_IMPLIES_CLASS, origin)) {
85
107
  const cls = ORIGIN_IMPLIES_CLASS[origin];
86
- if (laneBlocks(lane, TABLE[cls]))
108
+ if (classBlocks(lane, cls, face))
87
109
  return mustAsk('origin', { origin, askClass: cls });
88
110
  }
89
- if (lane === 'standing_rule' && evidenceView(card, 'requiresRealApproval').requiresRealApproval === true)
111
+ if (lane !== 'mode_posture' && evidenceView(card, 'requiresRealApproval').requiresRealApproval === true)
90
112
  return mustAsk('requires_real_approval');
91
113
  if (evidenceView(card, 'governanceForced').governanceForced === true)
92
114
  return mustAsk('governance');
93
115
  if (lane === 'mode_posture') {
94
116
  const word = readApprovalMandate(evidenceView(card, 'mandate'));
95
- if (word !== undefined && Object.hasOwn(MANDATE_WORD_IMPLIES_CLASS, word)) {
96
- const cls = MANDATE_WORD_IMPLIES_CLASS[word];
97
- if (laneBlocks(lane, TABLE[cls]))
98
- return mustAsk('mandate_word', { askClass: cls });
99
- }
117
+ const cls = word !== undefined ? mandateWordClass(word) : undefined;
118
+ if (cls !== undefined && classBlocks(lane, cls, face))
119
+ return mustAsk('mandate_word', { askClass: cls });
100
120
  }
101
121
  else {
102
122
  const mandateView = evidenceView(card, 'mandated', 'ruleOffersAbsence', 'mandate');
103
123
  if (approvalIsMandated(mandateView))
104
124
  return mustAsk('mandated');
105
- if (approvalAllowRuleShadowed(card) || readOwnNonEmptyString(mandateView, 'ruleOffersAbsence') === 'shadowed')
125
+ if (lane === 'standing_rule' && (approvalAllowRuleShadowed(card) || readOwnNonEmptyString(mandateView, 'ruleOffersAbsence') === 'shadowed'))
106
126
  return mustAsk('allow_rule_shadow');
107
127
  }
108
128
  const pair = readAskClassPairState(card);
@@ -110,7 +130,7 @@ export function automaticAnswerVerdict(card, lane, facts) {
110
130
  return UNKNOWN.classes_malformed;
111
131
  if (pair.state === 'absent')
112
132
  return UNKNOWN.classes_absent;
113
- const folded = foldModeArbitrationRow(pair.classes);
133
+ const folded = foldModeArbitrationRow(pair.classes, face);
114
134
  let anyKnown = false;
115
135
  let firstBlocking;
116
136
  let anyUnknown = false;
@@ -120,14 +140,14 @@ export function automaticAnswerVerdict(card, lane, facts) {
120
140
  continue;
121
141
  }
122
142
  anyKnown = true;
123
- if (firstBlocking === undefined && laneBlocks(lane, TABLE[c]))
143
+ if (firstBlocking === undefined && classBlocks(lane, c, face))
124
144
  firstBlocking = c;
125
145
  }
126
- if (anyKnown && laneBlocks(lane, folded))
146
+ if (anyKnown && rowBlocks(lane, folded))
127
147
  return mustAsk('ask_class', firstBlocking !== undefined ? { askClass: firstBlocking } : undefined);
128
148
  if (anyUnknown)
129
149
  return UNKNOWN.class_not_in_table;
130
- if (lane === 'standing_rule')
150
+ if (lane !== 'mode_posture')
131
151
  return MAY_ANSWER;
132
152
  const matched = readHostAskRuleMatched(facts);
133
153
  if (matched === true)
@@ -141,3 +161,31 @@ export function automaticAnswerVerdict(card, lane, facts) {
141
161
  return UNKNOWN.card_unreadable;
142
162
  }
143
163
  }
164
+ export function mandatedApprovalDetailOf(card) {
165
+ try {
166
+ if (typeof card !== 'object' || card === null)
167
+ return mandatedApprovalDetail();
168
+ const pair = readAskClassPairState(card);
169
+ if (pair.state !== 'pair')
170
+ return mandatedApprovalDetail();
171
+ if (pair.classes.some((c) => !Object.hasOwn(TABLE, c)))
172
+ return mandatedApprovalDetail();
173
+ const row = foldModeArbitrationRow(pair.classes);
174
+ if (row.classifierEligible || row.sandboxAdmission)
175
+ return mandatedApprovalDetail();
176
+ return MANDATED_NO_AUTOMATIC_CHECK_DETAIL;
177
+ }
178
+ catch {
179
+ return mandatedApprovalDetail();
180
+ }
181
+ }
182
+ const MANDATED_NO_AUTOMATIC_CHECK_DETAIL = 'no saved allow rule and no remembered answer can retire this question, and no automatic check answers it; each call is settled on its own, by you here, and an answer covers only that call';
183
+ export function permissionRequestHookScope(verdict) {
184
+ try {
185
+ const kind = typeof verdict === 'object' && verdict !== null ? verdict.kind : undefined;
186
+ return kind === 'may_answer' ? 'allow_or_deny' : kind === 'must_ask' ? 'skip' : 'deny_only';
187
+ }
188
+ catch {
189
+ return 'deny_only';
190
+ }
191
+ }
@@ -3,6 +3,8 @@ const CRASH_CONVERGED_CAUSE_WORDS = Object.freeze({
3
3
  shutdown_before_park: true,
4
4
  });
5
5
  export const isCrashConvergedCause = (v) => typeof v === 'string' && Object.hasOwn(CRASH_CONVERGED_CAUSE_WORDS, v);
6
+ const _crashConvergedCausePin = true;
7
+ void _crashConvergedCausePin;
6
8
  const isString = (v) => typeof v === 'string';
7
9
  const isNumber = (v) => typeof v === 'number';
8
10
  const nonEmptyString = (v) => typeof v === 'string' && v.length > 0;
@@ -0,0 +1,3 @@
1
+ export type DecisionRefusalConflict = 'binding_mismatch' | 'row_integrity' | 'format_version' | 'answer_invalid';
2
+ export declare function decisionConflictOf(err: unknown): DecisionRefusalConflict | undefined;
3
+ export declare const DECISION_ANSWER_INVALID_CONTENT = "The engine rejected the answer itself because it does not fit the question that was asked \u00B7 Nothing was decided and the question is still waiting \u00B7 Correct the answer and send it again";