@sema-agent/client-core 0.94.0 → 0.96.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 (332) hide show
  1. package/CHANGELOG.md +521 -0
  2. package/README.md +104 -57
  3. package/dist/adapt/arms.js +12 -7
  4. package/dist/adapt/panelTasks.js +4 -10
  5. package/dist/adapt/toolCards.d.ts +1 -0
  6. package/dist/adapt/toolCards.js +18 -5
  7. package/dist/adapt/wireShapes.js +5 -24
  8. package/dist/adapter/activeRunSelfHeal.d.ts +12 -3
  9. package/dist/adapter/activeRunSelfHeal.js +50 -16
  10. package/dist/adapter/downstream/eventToSdkMessage.js +33 -18
  11. package/dist/adapter/downstream/terminalToSdkResult.js +19 -12
  12. package/dist/adapter/runStream.js +30 -46
  13. package/dist/adapter/types.d.ts +7 -0
  14. package/dist/adapter/types.js +15 -0
  15. package/dist/agentSession/backgroundView.js +5 -1
  16. package/dist/agentSession/engineAgentRegistryRead.js +7 -5
  17. package/dist/agentSession/engineSessionBackgroundStop.js +25 -17
  18. package/dist/agentsWireCaps.d.ts +2 -0
  19. package/dist/agentsWireCaps.js +13 -2
  20. package/dist/approvalDecidedByCapability.d.ts +0 -1
  21. package/dist/approvalDecidedByCapability.js +2 -7
  22. package/dist/approvalsStreamLiveCapability.d.ts +0 -1
  23. package/dist/approvalsStreamLiveCapability.js +2 -6
  24. package/dist/atMostOnce.d.ts +8 -0
  25. package/dist/atMostOnce.js +36 -0
  26. package/dist/attachmentSeatCapability.d.ts +0 -1
  27. package/dist/attachmentSeatCapability.js +0 -3
  28. package/dist/attachmentsWireCaps.js +11 -6
  29. package/dist/bashExitReading.d.ts +10 -0
  30. package/dist/bashExitReading.js +12 -0
  31. package/dist/callerCwdCapability.d.ts +0 -5
  32. package/dist/callerCwdCapability.js +2 -13
  33. package/dist/centerWiringCapability.d.ts +1 -7
  34. package/dist/centerWiringCapability.js +18 -27
  35. package/dist/classifierStatus.js +4 -4
  36. package/dist/classifierVerdictWire.js +4 -16
  37. package/dist/clientSlice.js +1 -1
  38. package/dist/cloudConfigWireCaps.d.ts +3 -3
  39. package/dist/cloudConfigWireCaps.js +85 -43
  40. package/dist/compensations.js +1 -1
  41. package/dist/coreValuePorts.d.ts +11 -7
  42. package/dist/coreValuePorts.js +5 -8
  43. package/dist/credentialProvenance.d.ts +28 -0
  44. package/dist/credentialProvenance.js +76 -0
  45. package/dist/cycleOrder.d.ts +15 -0
  46. package/dist/cycleOrder.js +45 -0
  47. package/dist/decideFailureNote.js +7 -2
  48. package/dist/decideReceipt.d.ts +2 -1
  49. package/dist/decideReceipt.js +39 -14
  50. package/dist/declared/supportFloorDeclared.d.ts +1 -0
  51. package/dist/declared/supportFloorDeclared.js +5 -0
  52. package/dist/deviceExecutorManagementCapability.d.ts +0 -1
  53. package/dist/deviceExecutorManagementCapability.js +7 -16
  54. package/dist/deviceRebind.d.ts +88 -0
  55. package/dist/deviceRebind.js +242 -0
  56. package/dist/displayUntrusted.d.ts +8 -3
  57. package/dist/displayUntrusted.js +661 -63
  58. package/dist/engineAgentAbsence.d.ts +2 -2
  59. package/dist/engineAgentPanelStore.d.ts +8 -18
  60. package/dist/engineAgentPanelStore.js +19 -537
  61. package/dist/engineCapReader.d.ts +6 -6
  62. package/dist/engineCapReader.js +30 -43
  63. package/dist/engineCapsCache.d.ts +13 -2
  64. package/dist/engineCapsCache.js +276 -44
  65. package/dist/engineCredentialRequirement.d.ts +9 -0
  66. package/dist/engineCredentialRequirement.js +23 -0
  67. package/dist/engineDirectory.d.ts +79 -0
  68. package/dist/engineDirectory.js +186 -0
  69. package/dist/engineEnvSourcing.d.ts +53 -0
  70. package/dist/engineEnvSourcing.js +81 -0
  71. package/dist/engineErrorCodes.d.ts +28 -4
  72. package/dist/engineErrorCodes.js +68 -25
  73. package/dist/engineIdentity.js +2 -0
  74. package/dist/engineNoticeCodes.d.ts +17 -0
  75. package/dist/engineNoticeCodes.js +57 -3
  76. package/dist/engineWireSdk.js +2 -2
  77. package/dist/engineWordRenames.d.ts +8 -0
  78. package/dist/engineWordRenames.js +13 -0
  79. package/dist/executionLaneCapability.d.ts +2 -3
  80. package/dist/executionLaneCapability.js +18 -23
  81. package/dist/fileHistoryCaptureCapability.d.ts +14 -1
  82. package/dist/fileHistoryCaptureCapability.js +72 -6
  83. package/dist/fileHistoryLegNotice.d.ts +3 -2
  84. package/dist/fileHistoryLegNotice.js +51 -2
  85. package/dist/fleet/bgSubagentRow.d.ts +15 -0
  86. package/dist/fleet/bgSubagentRow.js +67 -0
  87. package/dist/fleet/fleetLedger.d.ts +3 -0
  88. package/dist/fleet/fleetLedger.js +153 -122
  89. package/dist/fleet/fleetProjection.d.ts +1 -3
  90. package/dist/fleet/fleetProjection.js +19 -19
  91. package/dist/fleetAgentPanelProjection.d.ts +4 -17
  92. package/dist/fleetAgentPanelProjection.js +7 -197
  93. package/dist/fleetAgentRowLike.d.ts +16 -0
  94. package/dist/fleetAgentRowLike.js +1 -0
  95. package/dist/fleetTaskDesc.js +4 -17
  96. package/dist/gateOutcome.d.ts +12 -1
  97. package/dist/gateOutcome.js +87 -18
  98. package/dist/gateVocabulary.d.ts +7 -2
  99. package/dist/gateVocabulary.js +5 -1
  100. package/dist/generated/engineAskFaceTables.js +1 -1
  101. package/dist/generated/engineFactTables.d.ts +5 -3
  102. package/dist/generated/engineFactTables.js +17 -4
  103. package/dist/generated/engineNoticeTables.js +12 -3
  104. package/dist/generated/sdkFactTables.d.ts +2 -0
  105. package/dist/generated/sdkFactTables.js +17 -0
  106. package/dist/generated/settingsSchemaFns.d.ts +13 -0
  107. package/dist/generated/settingsSchemaFns.js +75 -0
  108. package/dist/generated/toolNameTables.d.ts +1 -0
  109. package/dist/generated/toolNameTables.js +1 -0
  110. package/dist/headlessPermissionModeWire.d.ts +1 -1
  111. package/dist/headlessPermissionModeWire.js +1 -1
  112. package/dist/headlessReconnectWire.js +49 -20
  113. package/dist/hitl/allowRuleShadow.d.ts +1 -1
  114. package/dist/hitl/allowRuleShadow.js +49 -8
  115. package/dist/hitl/approvalCompleteParked.d.ts +1 -0
  116. package/dist/hitl/approvalCompleteParked.js +14 -0
  117. package/dist/hitl/approvalEndingCause.d.ts +7 -0
  118. package/dist/hitl/approvalEndingCause.js +71 -0
  119. package/dist/hitl/approvalHolds.d.ts +12 -2
  120. package/dist/hitl/approvalHolds.js +53 -2
  121. package/dist/hitl/approvalsFeed.js +23 -11
  122. package/dist/hitl/askGateWire.d.ts +2 -1
  123. package/dist/hitl/askGateWire.js +26 -1
  124. package/dist/hitl/askParkRowRouting.js +1 -1
  125. package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
  126. package/dist/hitl/automaticAnswerVerdict.js +15 -10
  127. package/dist/hitl/crashConverged.js +2 -0
  128. package/dist/hitl/decisionConflict.d.ts +3 -0
  129. package/dist/hitl/decisionConflict.js +41 -0
  130. package/dist/hitl/decisionRefusal.d.ts +12 -0
  131. package/dist/hitl/decisionRefusal.js +63 -4
  132. package/dist/hitl/frameRouter.d.ts +0 -1
  133. package/dist/hitl/frameRouter.js +32 -57
  134. package/dist/hitl/gateLedger.d.ts +5 -0
  135. package/dist/hitl/gateLedger.js +21 -0
  136. package/dist/hitl/hitlBridge.d.ts +17 -2
  137. package/dist/hitl/hitlBridge.js +91 -55
  138. package/dist/hitl/hitlHostSurface.js +3 -11
  139. package/dist/hitl/livePendingAsk.d.ts +16 -6
  140. package/dist/hitl/livePendingAsk.js +36 -4
  141. package/dist/hitl/localAllowRule.d.ts +1 -0
  142. package/dist/hitl/localAllowRule.js +2 -2
  143. package/dist/hitl/noAllowCause.d.ts +2 -1
  144. package/dist/hitl/noAllowCause.js +3 -2
  145. package/dist/hitl/parkExpiryJudgements.d.ts +19 -0
  146. package/dist/hitl/parkExpiryJudgements.js +46 -0
  147. package/dist/hitl/parkResolver.d.ts +4 -7
  148. package/dist/hitl/parkResolver.js +12 -34
  149. package/dist/hitl/parkRowBirthWait.d.ts +1 -0
  150. package/dist/hitl/parkRowBirthWait.js +2 -2
  151. package/dist/hitl/persistedRulesWire.js +5 -1
  152. package/dist/hitl/planReviewWire.d.ts +3 -2
  153. package/dist/hitl/planReviewWire.js +154 -50
  154. package/dist/hitl/replayedApproval.d.ts +9 -0
  155. package/dist/hitl/replayedApproval.js +139 -10
  156. package/dist/hitl/resumeRunningCard.d.ts +2 -0
  157. package/dist/hitl/resumeRunningCard.js +15 -4
  158. package/dist/hitl/sessionPolicyDeliverable.js +8 -6
  159. package/dist/hitl/standingRows.d.ts +18 -0
  160. package/dist/hitl/standingRows.js +127 -0
  161. package/dist/hitl/toolApprovalWire.d.ts +39 -7
  162. package/dist/hitl/toolApprovalWire.js +351 -61
  163. package/dist/hookMatcherVerdict.d.ts +1 -9
  164. package/dist/hookMatcherVerdict.js +21 -61
  165. package/dist/hooksWireCaps.js +40 -8
  166. package/dist/host.d.ts +5 -0
  167. package/dist/host.js +3 -1
  168. package/dist/hostCallbackGuard.d.ts +2 -0
  169. package/dist/hostCallbackGuard.js +31 -0
  170. package/dist/index.d.ts +48 -17
  171. package/dist/index.js +36 -15
  172. package/dist/interactiveInterrupt.d.ts +8 -0
  173. package/dist/interactiveInterrupt.js +54 -0
  174. package/dist/limitsWire.d.ts +5 -0
  175. package/dist/limitsWire.js +49 -3
  176. package/dist/liveModelCatalog.d.ts +95 -0
  177. package/dist/liveModelCatalog.js +297 -32
  178. package/dist/mcpEngineLeg.d.ts +25 -0
  179. package/dist/mcpEngineLeg.js +71 -15
  180. package/dist/mcpPanel.js +2 -1
  181. package/dist/mcpProbeCapability.d.ts +0 -5
  182. package/dist/mcpProbeCapability.js +2 -12
  183. package/dist/mcpReconnect.d.ts +1 -3
  184. package/dist/mcpReconnect.js +10 -5
  185. package/dist/memoryComplianceCapability.d.ts +0 -5
  186. package/dist/memoryComplianceCapability.js +2 -12
  187. package/dist/memoryOriginCapability.d.ts +0 -5
  188. package/dist/memoryOriginCapability.js +2 -12
  189. package/dist/memorySpecWire.js +2 -2
  190. package/dist/memoryVerbsWire.d.ts +1 -1
  191. package/dist/memoryVerbsWire.js +4 -0
  192. package/dist/model/liveCatalogShape.d.ts +14 -0
  193. package/dist/model/liveCatalogShape.js +71 -0
  194. package/dist/model/modelSupplyRules.d.ts +1 -0
  195. package/dist/model/modelSupplyRules.js +30 -9
  196. package/dist/model/modelsPolicy.d.ts +21 -0
  197. package/dist/model/modelsPolicy.js +90 -0
  198. package/dist/modelIdentityResolvability.d.ts +2 -2
  199. package/dist/modelIdentityResolvability.js +14 -12
  200. package/dist/modelSwitchFallback.d.ts +69 -0
  201. package/dist/modelSwitchFallback.js +206 -0
  202. package/dist/noticePresentation.d.ts +68 -0
  203. package/dist/noticePresentation.js +247 -0
  204. package/dist/notifications.js +12 -11
  205. package/dist/outputStyleSeatCapability.d.ts +0 -2
  206. package/dist/outputStyleSeatCapability.js +2 -10
  207. package/dist/ownKey.d.ts +8 -0
  208. package/dist/ownKey.js +66 -0
  209. package/dist/panelReduce.d.ts +114 -0
  210. package/dist/panelReduce.js +1135 -0
  211. package/dist/panelStateHolder.d.ts +17 -0
  212. package/dist/panelStateHolder.js +201 -0
  213. package/dist/peerFrames.js +13 -9
  214. package/dist/peerLaneCapability.d.ts +0 -1
  215. package/dist/peerLaneCapability.js +2 -6
  216. package/dist/permissionModesCapability.d.ts +0 -5
  217. package/dist/permissionModesCapability.js +5 -16
  218. package/dist/permissionRuleIssue.js +0 -3
  219. package/dist/permissionRulesWriteCapability.d.ts +0 -1
  220. package/dist/permissionRulesWriteCapability.js +2 -6
  221. package/dist/permissionsAllowGrantCapability.d.ts +0 -1
  222. package/dist/permissionsAllowGrantCapability.js +3 -9
  223. package/dist/permissionsDeclaration.d.ts +8 -0
  224. package/dist/permissionsDeclaration.js +101 -41
  225. package/dist/printPermissionOutcome.d.ts +12 -0
  226. package/dist/printPermissionOutcome.js +50 -0
  227. package/dist/printToolResultFrame.d.ts +1 -0
  228. package/dist/printToolResultFrame.js +5 -17
  229. package/dist/promptBlockedCopy.d.ts +5 -0
  230. package/dist/promptBlockedCopy.js +35 -0
  231. package/dist/promptDelivery.js +0 -8
  232. package/dist/protocolSegment.d.ts +9 -6
  233. package/dist/protocolSegment.js +31 -21
  234. package/dist/providerRejection.d.ts +4 -0
  235. package/dist/providerRejection.js +75 -14
  236. package/dist/replayBody.d.ts +12 -0
  237. package/dist/replayBody.js +25 -0
  238. package/dist/resumeRefusalCopy.d.ts +18 -1
  239. package/dist/resumeRefusalCopy.js +127 -32
  240. package/dist/retryStatus.d.ts +9 -1
  241. package/dist/retryStatus.js +9 -2
  242. package/dist/rewindArchiveCapability.d.ts +5 -14
  243. package/dist/rewindArchiveCapability.js +18 -61
  244. package/dist/rewindArchiveReading.d.ts +15 -0
  245. package/dist/rewindArchiveReading.js +56 -0
  246. package/dist/rewindEngineAction.d.ts +21 -0
  247. package/dist/rewindEngineAction.js +36 -0
  248. package/dist/rewindWireCaps.d.ts +2 -1
  249. package/dist/rewindWireCaps.js +1 -0
  250. package/dist/ruleCompileVerdict.d.ts +9 -1
  251. package/dist/ruleCompileVerdict.js +29 -4
  252. package/dist/runTerminal.d.ts +15 -12
  253. package/dist/runTerminal.js +60 -35
  254. package/dist/sandboxWire.js +13 -0
  255. package/dist/sdkRegistryTransit.d.ts +2 -1
  256. package/dist/sdkRegistryTransit.js +1 -0
  257. package/dist/sealedKeyCapability.d.ts +0 -5
  258. package/dist/sealedKeyCapability.js +3 -15
  259. package/dist/seam.js +4 -2
  260. package/dist/seatContract.d.ts +125 -34
  261. package/dist/seatContract.js +583 -179
  262. package/dist/sessionIdSegment.d.ts +1 -0
  263. package/dist/sessionIdSegment.js +11 -0
  264. package/dist/sessionMemoryErase.d.ts +1 -1
  265. package/dist/sessionMemoryErase.js +6 -1
  266. package/dist/sessionMemoryStatus.js +3 -2
  267. package/dist/sessionPolicyCapability.d.ts +0 -1
  268. package/dist/sessionPolicyCapability.js +2 -6
  269. package/dist/sessionReadRedactionCapability.d.ts +0 -5
  270. package/dist/sessionReadRedactionCapability.js +2 -13
  271. package/dist/sessionSyncFileHistory.d.ts +4 -0
  272. package/dist/sessionSyncFileHistory.js +66 -0
  273. package/dist/sessionSyncFileHistoryCapability.d.ts +0 -2
  274. package/dist/sessionSyncFileHistoryCapability.js +2 -9
  275. package/dist/skillToolListsCapability.d.ts +0 -2
  276. package/dist/skillToolListsCapability.js +2 -9
  277. package/dist/skillsWireCaps.d.ts +4 -0
  278. package/dist/skillsWireCaps.js +66 -1
  279. package/dist/sqlEngineCapability.d.ts +0 -1
  280. package/dist/sqlEngineCapability.js +9 -14
  281. package/dist/steerPriorityCapability.d.ts +0 -2
  282. package/dist/steerPriorityCapability.js +3 -12
  283. package/dist/storePostureCapability.d.ts +1 -5
  284. package/dist/storePostureCapability.js +16 -22
  285. package/dist/streamDrainingLegs.d.ts +6 -0
  286. package/dist/streamDrainingLegs.js +23 -0
  287. package/dist/subagent/engineCompactWire.js +13 -38
  288. package/dist/subagent/engineDelegatedPrompt.js +10 -6
  289. package/dist/subagent/engineSubagentOutput.d.ts +0 -1
  290. package/dist/subagent/engineSubagentOutput.js +5 -20
  291. package/dist/subagent/engineSubagentSteer.js +7 -5
  292. package/dist/subagent/engineSubagentTail.d.ts +0 -1
  293. package/dist/subagent/engineSubagentTail.js +7 -32
  294. package/dist/subagentContentStore.js +7 -18
  295. package/dist/supportFloor.d.ts +1 -0
  296. package/dist/supportFloor.js +15 -14
  297. package/dist/systemReminderTag.d.ts +1 -0
  298. package/dist/systemReminderTag.js +8 -0
  299. package/dist/terminalStatuses.d.ts +30 -0
  300. package/dist/terminalStatuses.js +67 -0
  301. package/dist/toolHistoryMismatch.d.ts +0 -3
  302. package/dist/toolHistoryMismatch.js +3 -7
  303. package/dist/toolResult.d.ts +6 -1
  304. package/dist/toolResult.js +90 -37
  305. package/dist/toolResultContent.d.ts +2 -0
  306. package/dist/toolResultContent.js +63 -0
  307. package/dist/types/engineState.d.ts +2 -1
  308. package/dist/usageAnalytics.d.ts +146 -0
  309. package/dist/usageAnalytics.js +335 -0
  310. package/dist/userInvokedSkillsCapability.d.ts +0 -2
  311. package/dist/userInvokedSkillsCapability.js +2 -9
  312. package/dist/webSearchBackendCapability.d.ts +0 -1
  313. package/dist/webSearchBackendCapability.js +3 -7
  314. package/dist/webSearchWireCaps.js +3 -11
  315. package/dist/wireErrorTriage.d.ts +2 -0
  316. package/dist/wireErrorTriage.js +34 -5
  317. package/dist/wireFailureShape.d.ts +23 -2
  318. package/dist/wireFailureShape.js +88 -43
  319. package/dist/wireRefusalCopy.js +2 -18
  320. package/dist/workflowClient.js +7 -11
  321. package/dist/workflowsJournalCapability.d.ts +0 -1
  322. package/dist/workflowsJournalCapability.js +2 -6
  323. package/dist/writeProtectionCapability.d.ts +0 -1
  324. package/dist/writeProtectionCapability.js +5 -10
  325. package/docs/INTEGRATION-CLIENTS.md +2279 -27
  326. package/package.json +5 -5
  327. package/dist/engineCapsGenerationGuard.d.ts +0 -4
  328. package/dist/engineCapsGenerationGuard.js +0 -19
  329. package/dist/panelRunningHistory.d.ts +0 -22
  330. package/dist/panelRunningHistory.js +0 -82
  331. package/dist/registryConflict.d.ts +0 -3
  332. package/dist/registryConflict.js +0 -44
@@ -13,6 +13,8 @@ export function hasLedgerPositionKey(ev) {
13
13
  return (id !== undefined && id !== null) || (seq !== undefined && seq !== null);
14
14
  }
15
15
  export const PREAMBLE_APPROVALS_MAX_ENTRIES = 4096;
16
+ export const APPROVAL_SETTLED_HOWS = Object.freeze(['answered', 'interrupted', 'closed_by_engine']);
17
+ export const SETTLED_APPROVALS_MAX_ENTRIES = 4096;
16
18
  export const START_ARGS_MAX_ENTRIES = 256;
17
19
  function normalizeDenyAttribution(a) {
18
20
  if (a === undefined)
@@ -88,6 +90,7 @@ export function createGateLedger() {
88
90
  let denyStampAttribution;
89
91
  let seq;
90
92
  const preambleApprovalIds = new Set();
93
+ const settledApprovalHows = new Map();
91
94
  const liveCards = new Set();
92
95
  return {
93
96
  noteSeq(ev) {
@@ -121,6 +124,24 @@ export function createGateLedger() {
121
124
  beginStreamSegment() {
122
125
  preambleApprovalIds.clear();
123
126
  },
127
+ noteApprovalSettled(approvalId, how) {
128
+ if (typeof approvalId !== 'string' || approvalId === '')
129
+ return;
130
+ if (!APPROVAL_SETTLED_HOWS.includes(how))
131
+ return;
132
+ if (settledApprovalHows.has(approvalId))
133
+ return;
134
+ settledApprovalHows.set(approvalId, how);
135
+ while (settledApprovalHows.size > SETTLED_APPROVALS_MAX_ENTRIES) {
136
+ const oldest = settledApprovalHows.keys().next();
137
+ if (oldest.done === true)
138
+ break;
139
+ settledApprovalHows.delete(oldest.value);
140
+ }
141
+ },
142
+ settledApprovals() {
143
+ return settledApprovalHows;
144
+ },
124
145
  trackLiveCard(phaseOf, handled) {
125
146
  const entry = { phaseOf, handled };
126
147
  liveCards.add(entry);
@@ -46,7 +46,8 @@ export interface PlanReviewOutcome {
46
46
  export declare const PLAN_REVIEW_MODE_AFTER_WORDS: readonly ["default", "acceptEdits"];
47
47
  export type PlanReviewModeAfter = (typeof PLAN_REVIEW_MODE_AFTER_WORDS)[number];
48
48
  export declare function isPlanReviewModeAfter(v: string | undefined): v is PlanReviewModeAfter;
49
- export type HitlSafetyCode = 'binding_mismatch' | 'no_pending' | 'wrong_gate' | 'bad_plan_edit' | 'bad_plan_mode' | 'empty_answer';
49
+ export declare const GATE_FAILURE_CODES: readonly ["no_pending", "binding_mismatch", "wrong_gate", "bad_plan_edit", "bad_plan_mode", "empty_answer", "binding_missing"];
50
+ export type HitlSafetyCode = (typeof GATE_FAILURE_CODES)[number];
50
51
  export type HitlFailureStage = 'fetch' | 'input' | 'card' | 'decide' | 'orchestration';
51
52
  export declare const NO_APPROVAL_CARD_PORT_REASON = "no approval card port installed (print/non-REPL mode, or host forgot installApprovalCardPort)";
52
53
  export declare const APPROVAL_CARD_PORT_KEY_MISMATCH_REASON = "no approval card port installed for the default session key, but a non-default sessionKey has one \u2014 likely a keyed-install/default-read mismatch (installApprovalCardPortFor vs the zero-arg default-key read), not a missing install";
@@ -62,9 +63,23 @@ export declare class HitlSafetyError extends Error {
62
63
  readonly code: HitlSafetyCode;
63
64
  constructor(message: string, code: HitlSafetyCode);
64
65
  }
66
+ export declare function hitlSafetyCodeOf(e: unknown): HitlSafetyCode | undefined;
65
67
  export type GateCurrentPending = Readonly<NonNullable<ApprovalStaleError['currentPending']>>;
66
68
  export declare function readDecideCurrentPending(e: unknown): GateCurrentPending | undefined;
67
69
  export declare function readWireErrorCode(e: unknown): string | undefined;
70
+ export type WireErrorCodeReading = {
71
+ readonly state: 'code';
72
+ readonly code: string;
73
+ } | {
74
+ readonly state: 'absent';
75
+ } | {
76
+ readonly state: 'unreadable';
77
+ };
78
+ export declare function readWireErrorCodeReading(e: unknown): WireErrorCodeReading;
79
+ export declare function readWireCodes(e: unknown): {
80
+ readonly errorCode?: string;
81
+ readonly blockedBy?: string;
82
+ };
68
83
  export declare function __setDecideTimeoutRetryBudgetForTests(ms?: number): void;
69
84
  export declare class DecideTransportRetryExhaustedError extends Error {
70
85
  readonly attempts: number;
@@ -105,7 +120,7 @@ export type FindPendingOutcome = {
105
120
  } | {
106
121
  ok: false;
107
122
  reason: string;
108
- code?: 'no_pending';
123
+ code?: 'no_pending' | 'wrong_gate';
109
124
  };
110
125
  export declare function findPendingForTask(client: HitlClientLike, taskId: string, matches: (toolName: string | undefined) => boolean, opts?: {
111
126
  signal?: AbortSignal;
@@ -1,9 +1,11 @@
1
1
  import { askParkForeignGateKind } from '../adapter/activeRunSelfHeal.js';
2
2
  import { eventSeq } from '../adapter/types.js';
3
3
  import { hostLog } from '../host.js';
4
+ import { invokeHostCallbackIsolated } from '../hostCallbackGuard.js';
4
5
  import { abortableSleep } from '../abortableSleep.js';
5
6
  import { readOwnDataValue } from '../ownKey.js';
6
- import { wireFailureTextsOf } from '../wireFailureShape.js';
7
+ import { THROWN_SLOT_UNREADABLE, readBlockedBy, readThrownSlot, thrownIsInstanceOf, wireFailureTextsOf } from '../wireFailureShape.js';
8
+ import { RESUME_POLICY_FOLD_CODE } from '../engineErrorCodes.js';
7
9
  import { suspendedReopenOf } from './suspendedReopen.js';
8
10
  export const DEFAULT_DENY_REASON = 'The user rejected this tool use';
9
11
  const MAX_DENY_REASON_CHARS = 4096;
@@ -27,6 +29,15 @@ export const PLAN_REVIEW_MODE_AFTER_WORDS = Object.freeze(['default', 'acceptEdi
27
29
  export function isPlanReviewModeAfter(v) {
28
30
  return v !== undefined && PLAN_REVIEW_MODE_AFTER_WORDS.includes(v);
29
31
  }
32
+ export const GATE_FAILURE_CODES = Object.freeze([
33
+ 'no_pending',
34
+ 'binding_mismatch',
35
+ 'wrong_gate',
36
+ 'bad_plan_edit',
37
+ 'bad_plan_mode',
38
+ 'empty_answer',
39
+ 'binding_missing',
40
+ ]);
30
41
  export const NO_APPROVAL_CARD_PORT_REASON = 'no approval card port installed (print/non-REPL mode, or host forgot installApprovalCardPort)';
31
42
  export const APPROVAL_CARD_PORT_KEY_MISMATCH_REASON = 'no approval card port installed for the default session key, but a non-default sessionKey has one — likely a keyed-install/default-read mismatch (installApprovalCardPortFor vs the zero-arg default-key read), not a missing install';
32
43
  export const NO_QUESTION_OVERLAY_REASON = 'no question overlay mounted (print/non-REPL mode)';
@@ -41,28 +52,55 @@ export class HitlSafetyError extends Error {
41
52
  this.name = 'HitlSafetyError';
42
53
  }
43
54
  }
55
+ export function hitlSafetyCodeOf(e) {
56
+ if (!thrownIsInstanceOf(e, HitlSafetyError))
57
+ return undefined;
58
+ const raw = readThrownSlot(e, 'code');
59
+ return typeof raw === 'string' && GATE_FAILURE_CODES.includes(raw) ? raw : undefined;
60
+ }
44
61
  const _gateCurrentPendingReadonlyPin = true;
45
62
  void _gateCurrentPendingReadonlyPin;
46
63
  export function readDecideCurrentPending(e) {
47
- const raw = e?.currentPending;
64
+ if (e === null || e === undefined)
65
+ return undefined;
66
+ const raw = readThrownSlot(e, 'currentPending');
48
67
  if (typeof raw !== 'object' || raw === null)
49
68
  return undefined;
50
- const o = raw;
51
- if (typeof o.toolName !== 'string' || o.toolName.length === 0)
69
+ const toolName = readThrownSlot(raw, 'toolName');
70
+ const boundCallId = readThrownSlot(raw, 'boundCallId');
71
+ const boundInputHash = readThrownSlot(raw, 'boundInputHash');
72
+ if (typeof toolName !== 'string' || toolName.length === 0)
52
73
  return undefined;
53
- if (typeof o.boundCallId !== 'string' || o.boundCallId.length === 0)
74
+ if (typeof boundCallId !== 'string' || boundCallId.length === 0)
54
75
  return undefined;
55
76
  return {
56
- toolName: o.toolName,
57
- boundCallId: o.boundCallId,
58
- ...(typeof o.boundInputHash === 'string' && o.boundInputHash.length > 0
59
- ? { boundInputHash: o.boundInputHash }
77
+ toolName,
78
+ boundCallId,
79
+ ...(typeof boundInputHash === 'string' && boundInputHash.length > 0
80
+ ? { boundInputHash }
60
81
  : {}),
61
82
  };
62
83
  }
63
84
  export function readWireErrorCode(e) {
64
- const raw = e?.errorCode;
65
- return typeof raw === 'string' && raw.length > 0 ? raw : undefined;
85
+ const reading = readWireErrorCodeReading(e);
86
+ return reading.state === 'code' ? reading.code : undefined;
87
+ }
88
+ export function readWireErrorCodeReading(e) {
89
+ if (e === null || e === undefined)
90
+ return { state: 'absent' };
91
+ const raw = readThrownSlot(e, 'errorCode');
92
+ if (raw === THROWN_SLOT_UNREADABLE)
93
+ return { state: 'unreadable' };
94
+ return typeof raw === 'string' && raw.length > 0 ? { state: 'code', code: raw } : { state: 'absent' };
95
+ }
96
+ export function readWireCodes(e) {
97
+ const reading = readWireErrorCodeReading(e);
98
+ if (reading.state !== 'code')
99
+ return {};
100
+ if (reading.code !== RESUME_POLICY_FOLD_CODE)
101
+ return { errorCode: reading.code };
102
+ const folded = readBlockedBy(e);
103
+ return folded.kind === 'named' ? { errorCode: reading.code, blockedBy: folded.code } : { errorCode: reading.code };
66
104
  }
67
105
  const DECIDE_TRANSPORT_RETRY_BACKOFF_MS = 750;
68
106
  const DECIDE_RETRY_BACKOFF_MAX_MS = 5_000;
@@ -80,10 +118,9 @@ function decideTimeoutRetryBudgetMs() {
80
118
  function isDecideAttemptTimeout(e, depth = 0) {
81
119
  if (depth > 3 || e === null || typeof e !== 'object')
82
120
  return false;
83
- const o = e;
84
- if (o.name === 'TimeoutError')
121
+ if (readThrownSlot(e, 'name') === 'TimeoutError')
85
122
  return true;
86
- return isDecideAttemptTimeout(o.cause, depth + 1);
123
+ return isDecideAttemptTimeout(readThrownSlot(e, 'cause'), depth + 1);
87
124
  }
88
125
  const TRANSIENT_NETWORK_CODES = new Set([
89
126
  'ECONNREFUSED', 'ECONNRESET', 'ETIMEDOUT', 'EPIPE', 'EAI_AGAIN',
@@ -93,18 +130,21 @@ const TRANSIENT_NETWORK_CODES = new Set([
93
130
  function isTransientDecideTransportFailure(e, depth = 0) {
94
131
  if (depth > 3 || e === null || typeof e !== 'object')
95
132
  return false;
96
- if (e instanceof HitlSafetyError)
133
+ if (thrownIsInstanceOf(e, HitlSafetyError))
97
134
  return false;
98
- const o = e;
99
- if (typeof o.status === 'number')
135
+ const status = readThrownSlot(e, 'status');
136
+ if (status === THROWN_SLOT_UNREADABLE || typeof status === 'number')
100
137
  return false;
101
- if (o.name === 'TimeoutError' || o.name === 'AbortError')
138
+ const name = readThrownSlot(e, 'name');
139
+ if (name === 'TimeoutError' || name === 'AbortError')
102
140
  return true;
103
- if (typeof o.code === 'string' && TRANSIENT_NETWORK_CODES.has(o.code))
141
+ const code = readThrownSlot(e, 'code');
142
+ if (typeof code === 'string' && TRANSIENT_NETWORK_CODES.has(code))
104
143
  return true;
105
- if (typeof o.message === 'string' && o.message.toLowerCase().includes('fetch failed'))
144
+ const message = readThrownSlot(e, 'message');
145
+ if (typeof message === 'string' && message.toLowerCase().includes('fetch failed'))
106
146
  return true;
107
- return isTransientDecideTransportFailure(o.cause, depth + 1);
147
+ return isTransientDecideTransportFailure(readThrownSlot(e, 'cause'), depth + 1);
108
148
  }
109
149
  export class DecideTransportRetryExhaustedError extends Error {
110
150
  attempts;
@@ -149,7 +189,7 @@ class DecideSpan {
149
189
  }
150
190
  catch (e) {
151
191
  this.ok = false;
152
- this.retryExhausted = e instanceof DecideTransportRetryExhaustedError;
192
+ this.retryExhausted = thrownIsInstanceOf(e, DecideTransportRetryExhaustedError);
153
193
  throw e;
154
194
  }
155
195
  finally {
@@ -175,32 +215,13 @@ class DecideSpan {
175
215
  notifyDecideObserver(this.observer, Object.freeze({ ...this.identity, phase: 'end', ok: this.ok, attempts: this.attempts, retryExhausted: this.retryExhausted }));
176
216
  }
177
217
  }
178
- function reportObserverFault(phase, what, e) {
179
- try {
180
- hostLog('debug', `hitlBridge: onDecideOperation(${phase}) ${what}: ${String(e).slice(0, 160)}`);
181
- return true;
182
- }
183
- catch {
184
- return false;
185
- }
186
- }
187
218
  function wireOptsOf(opts) {
188
219
  if (opts === undefined || opts.operation === undefined)
189
220
  return opts;
190
221
  return opts.signal !== undefined ? { signal: opts.signal } : undefined;
191
222
  }
192
223
  function notifyDecideObserver(observer, ev) {
193
- try {
194
- const out = observer(ev);
195
- if (out && typeof out.then === 'function') {
196
- void Promise.resolve(out).then(undefined, (e) => {
197
- reportObserverFault(ev.phase, 'rejected', e);
198
- });
199
- }
200
- }
201
- catch (e) {
202
- reportObserverFault(ev.phase, 'threw', e);
203
- }
224
+ invokeHostCallbackIsolated(`hitlBridge: onDecideOperation(${ev.phase})`, () => observer(ev));
204
225
  }
205
226
  const ANY_TOOL_FAMILY = () => true;
206
227
  export async function findPendingForTask(client, taskId, matches, opts, callId, identityAccepts = (r) => matches(typeof r.toolName === 'string' ? r.toolName : undefined)) {
@@ -213,10 +234,21 @@ export async function findPendingForTask(client, taskId, matches, opts, callId,
213
234
  hostLog('debug', `hitlBridge: approvals.list failed: ${t.log}`);
214
235
  return { ok: false, reason: `approvals.list failed: ${t.reason}` };
215
236
  }
216
- const decidable = rows.filter((r) => askParkForeignGateKind(r) === null);
237
+ const readings = rows.map((r) => ({ r, foreign: askParkForeignGateKind(r) }));
238
+ const decidable = readings.filter((x) => x.foreign === null).map((x) => x.r);
217
239
  const identityRow = callId !== undefined
218
240
  ? decidable.find((r) => r.taskId === taskId && (r.boundCallId === callId || r.toolCallId === callId))
219
241
  : undefined;
242
+ const identityForeign = callId !== undefined && identityRow === undefined
243
+ ? readings.find((x) => x.r.taskId === taskId && (x.r.boundCallId === callId || x.r.toolCallId === callId) && x.foreign !== null)
244
+ : undefined;
245
+ if (identityForeign !== undefined) {
246
+ return {
247
+ ok: false,
248
+ reason: `the pending row this park names (call ${callId}) is parked on a '${String(identityForeign.foreign)}' gate — not an approval this leg decides; refusing to decide a different row`,
249
+ code: 'wrong_gate',
250
+ };
251
+ }
220
252
  const identityConflicts = identityRow !== undefined && !identityAccepts(identityRow);
221
253
  const pool = identityConflicts ? decidable.filter((r) => identityAccepts(r)) : decidable;
222
254
  const pending = (identityConflicts ? undefined : identityRow) ??
@@ -275,7 +307,7 @@ export class HitlBridge {
275
307
  if (p.boundCallId === undefined || p.boundInputHash === undefined) {
276
308
  throw new HitlSafetyError(`pending checkpoint ${p.id ?? '<no-id>'} is missing D-1 binding fields ` +
277
309
  `(boundCallId=${String(p.boundCallId)}, boundInputHash=${String(p.boundInputHash)}) — ` +
278
- 'pre-D-1 workers are no longer supported (server 5.x requires the verbatim two-tuple echo)', 'binding_mismatch');
310
+ 'pre-D-1 workers are no longer supported (server 5.x requires the verbatim two-tuple echo)', 'binding_missing');
279
311
  }
280
312
  return { boundCallId: p.boundCallId, boundInputHash: p.boundInputHash };
281
313
  }
@@ -374,7 +406,7 @@ export class HitlBridge {
374
406
  return r;
375
407
  }
376
408
  catch (e) {
377
- retryExhausted = e instanceof DecideTransportRetryExhaustedError;
409
+ retryExhausted = thrownIsInstanceOf(e, DecideTransportRetryExhaustedError);
378
410
  throw e;
379
411
  }
380
412
  finally {
@@ -407,9 +439,12 @@ export class HitlBridge {
407
439
  return r;
408
440
  }
409
441
  catch (e) {
410
- if (isBindingMismatch(e)) {
442
+ const binding = bindingMismatchReading(e);
443
+ if (binding === 'mismatch') {
411
444
  throw new HitlSafetyError('approval_binding_mismatch — the pending action changed under the human; refetch + re-present', 'binding_mismatch');
412
445
  }
446
+ if (binding === 'unreadable')
447
+ throw e;
413
448
  if (!isTransientDecideTransportFailure(e) || callerAborted())
414
449
  throw e;
415
450
  if (isDecideAttemptTimeout(e)) {
@@ -479,16 +514,17 @@ function marshalAnswer(a) {
479
514
  entry.note = a.note;
480
515
  return entry;
481
516
  }
482
- function isBindingMismatch(e) {
517
+ function bindingMismatchReading(e) {
483
518
  if (!e || typeof e !== 'object')
484
- return false;
485
- const o = e;
486
- const code = o.errorCode;
487
- if (code === 'approval_binding_mismatch')
488
- return true;
489
- if (typeof o.name === 'string' && o.name === 'ApprovalBindingMismatchError')
490
- return true;
491
- return false;
519
+ return 'not';
520
+ const code = readWireErrorCodeReading(e);
521
+ const name = readThrownSlot(e, 'name');
522
+ const family = (code.state === 'code' && code.code === 'approval_binding_mismatch') || name === 'ApprovalBindingMismatchError';
523
+ if (family)
524
+ return 'mismatch';
525
+ if (code.state === 'unreadable')
526
+ return 'unreadable';
527
+ return 'not';
492
528
  }
493
529
  export function backendDeny(reason) {
494
530
  return {
@@ -2,7 +2,7 @@ import { createSessionSlot, DEFAULT_SESSION_KEY } from '../sessionSlot.js';
2
2
  import { hostLog } from '../host.js';
3
3
  import { unrefTimer } from '../unrefTimer.js';
4
4
  import { decideFailureNote } from '../decideFailureNote.js';
5
- import { HitlSafetyError } from './hitlBridge.js';
5
+ import { decisionRefusalSaysAskGone } from './decisionRefusal.js';
6
6
  const hostSurfaceByKey = createSessionSlot();
7
7
  const hostSurfaceMissesByKey = new Map();
8
8
  export function installHitlHostSurface(surface) {
@@ -133,14 +133,6 @@ const RULE_NOT_SENT_REJECTED_TIMEOUT_MS = 10_000;
133
133
  export function surfaceRuleArmRejected(why) {
134
134
  surfaceSelfClearingWarn(RULE_NOT_SENT_REJECTED_KEY, ruleNotSentRejectedText(why), RULE_NOT_SENT_REJECTED_TIMEOUT_MS);
135
135
  }
136
- function isNoPendingError(e) {
137
- if (e instanceof HitlSafetyError)
138
- return e.code === 'no_pending';
139
- if (typeof e !== 'object' || e === null || !('code' in e))
140
- return false;
141
- const code = e.code;
142
- return typeof code === 'string' && code === 'no_pending';
143
- }
144
136
  export function observeCancelByDeny(settle, taskId) {
145
137
  let timer;
146
138
  const budget = new Promise((_, reject) => {
@@ -152,8 +144,8 @@ export function observeCancelByDeny(settle, taskId) {
152
144
  hostLog('debug', `[hitl-cancel-deny] cancel-by-deny settled for run ${taskId} (session unlocked)`);
153
145
  })
154
146
  .catch((e) => {
155
- if (isNoPendingError(e)) {
156
- hostLog('debug', `[hitl-cancel-deny] cancel-by-deny no_pending for run ${taskId} (benign — already resolved)`);
147
+ if (decisionRefusalSaysAskGone(e)) {
148
+ hostLog('debug', `[hitl-cancel-deny] cancel-by-deny found the question no longer pending for run ${taskId} (benign — settled elsewhere, parked or gone)`);
157
149
  return;
158
150
  }
159
151
  const rowNote = decideFailureNote(e, 'deny');
@@ -22,16 +22,26 @@ export type LivePendingReading = {
22
22
  dropped: number;
23
23
  };
24
24
  export declare function readLivePendingRows(body: unknown): LivePendingReading;
25
- export interface SuspendedAskFilter {
26
- sessionId?: string;
27
- }
28
- export declare function suspendedSubagentAsks(snapshot: ApprovalsFeedEmission | null | undefined, filter?: SuspendedAskFilter): LivePendingAskView[];
25
+ export type SuspendedAskFilter = {
26
+ readonly sessionId: string;
27
+ readonly allSessions?: never;
28
+ readonly identityPending?: never;
29
+ } | {
30
+ readonly allSessions: true;
31
+ readonly sessionId?: never;
32
+ readonly identityPending?: never;
33
+ } | {
34
+ readonly identityPending: true;
35
+ readonly sessionId?: never;
36
+ readonly allSessions?: never;
37
+ };
38
+ export declare function suspendedSubagentAsks(snapshot: ApprovalsFeedEmission | null | undefined, filter: SuspendedAskFilter): LivePendingAskView[];
29
39
  export interface ApprovalsAwaitingDecisionCount {
30
40
  durable: number | null;
31
41
  live: number | null;
32
42
  suspendedSubagent: number | null;
33
43
  }
34
- export declare function countApprovalsAwaitingDecision(snapshot: ApprovalsFeedEmission | null | undefined, filter?: SuspendedAskFilter): ApprovalsAwaitingDecisionCount;
44
+ export declare function countApprovalsAwaitingDecision(snapshot: ApprovalsFeedEmission | null | undefined, filter: SuspendedAskFilter): ApprovalsAwaitingDecisionCount;
35
45
  export declare function livePendingRowToApprovalFrame(row: LivePendingAskView): ToolApprovalFrame;
36
46
  export declare function surfaceSuspendedAskAndRespond(row: LivePendingAskView, respond: RespondToolApprovalFn, signal?: AbortSignal, lane?: ToolApprovalFrameLaneOpts): Promise<ToolApprovalFrameOutcome>;
37
47
  export interface SuspendedAskDelta {
@@ -45,4 +55,4 @@ export interface SuspendedAskTracker {
45
55
  requeue(approvalId: string): void;
46
56
  noteDecided(approvalId: string): void;
47
57
  }
48
- export declare function createSuspendedAskTracker(filter?: SuspendedAskFilter): SuspendedAskTracker;
58
+ export declare function createSuspendedAskTracker(filter: SuspendedAskFilter): SuspendedAskTracker;
@@ -1,3 +1,4 @@
1
+ import { THROWN_SLOT_UNREADABLE, readThrownSlot } from '../wireFailureShape.js';
1
2
  import { isToolApprovalFrame, surfaceToolApprovalFrameAndRespond, } from './toolApprovalWire.js';
2
3
  function nonEmptyString(v) {
3
4
  return typeof v === 'string' && v !== '';
@@ -69,20 +70,48 @@ export function readLivePendingRows(body) {
69
70
  return { kind: 'malformed' };
70
71
  return { kind: 'present', rows, dropped };
71
72
  }
72
- export function suspendedSubagentAsks(snapshot, filter) {
73
+ const IDENTITY_PENDING_SCOPE = Object.freeze({ kind: 'identity_pending' });
74
+ function suspendedAskScopeOf(filter) {
75
+ if (typeof filter !== 'object' || filter === null)
76
+ return IDENTITY_PENDING_SCOPE;
77
+ const sessionId = readThrownSlot(filter, 'sessionId', true);
78
+ const allSessions = readThrownSlot(filter, 'allSessions', true);
79
+ const identityPending = readThrownSlot(filter, 'identityPending', true);
80
+ if (sessionId === THROWN_SLOT_UNREADABLE || allSessions === THROWN_SLOT_UNREADABLE || identityPending === THROWN_SLOT_UNREADABLE)
81
+ return IDENTITY_PENDING_SCOPE;
82
+ const sessionOk = typeof sessionId === 'string' && sessionId !== '';
83
+ const allOk = allSessions === true;
84
+ const pendingOk = identityPending === true;
85
+ if ((sessionId !== undefined && !sessionOk) || (allSessions !== undefined && !allOk) || (identityPending !== undefined && !pendingOk))
86
+ return IDENTITY_PENDING_SCOPE;
87
+ if (sessionOk && !allOk && !pendingOk)
88
+ return { kind: 'session', sessionId };
89
+ if (allOk && !sessionOk && !pendingOk)
90
+ return { kind: 'all' };
91
+ return IDENTITY_PENDING_SCOPE;
92
+ }
93
+ function subagentAsksIn(snapshot, scope) {
94
+ if (scope.kind === 'identity_pending')
95
+ return [];
73
96
  if (snapshot?.kind === 'unknown')
74
97
  return [];
75
98
  const rows = snapshot?.livePending;
76
99
  if (!Array.isArray(rows))
77
100
  return [];
78
- return rows.filter(r => r.fromSubagent === true && (filter?.sessionId === undefined || r.sessionId === filter.sessionId));
101
+ return rows.filter(r => r.fromSubagent === true && (scope.kind === 'all' || r.sessionId === scope.sessionId));
102
+ }
103
+ export function suspendedSubagentAsks(snapshot, filter) {
104
+ return subagentAsksIn(snapshot, suspendedAskScopeOf(filter));
79
105
  }
80
106
  export function countApprovalsAwaitingDecision(snapshot, filter) {
107
+ const scope = suspendedAskScopeOf(filter);
108
+ if (scope.kind === 'identity_pending')
109
+ return { durable: null, live: null, suspendedSubagent: null };
81
110
  if (snapshot === null || snapshot === undefined)
82
111
  return { durable: null, live: null, suspendedSubagent: null };
83
112
  if (snapshot.kind === 'unknown')
84
113
  return { durable: null, live: null, suspendedSubagent: null };
85
- const bySession = (rows) => filter?.sessionId === undefined ? [...rows] : rows.filter(r => r.sessionId === filter.sessionId);
114
+ const bySession = (rows) => scope.kind === 'session' ? rows.filter(r => r.sessionId === scope.sessionId) : [...rows];
86
115
  const durable = (snapshot.pendingDropped ?? 0) > 0 ? null : Array.isArray(snapshot.pending) ? bySession(snapshot.pending).length : null;
87
116
  if (!Array.isArray(snapshot.livePending))
88
117
  return { durable, live: null, suspendedSubagent: null };
@@ -113,6 +142,7 @@ export function surfaceSuspendedAskAndRespond(row, respond, signal, lane) {
113
142
  }
114
143
  const TRACKER_UNSEEN_CLAIMS_MAX = 512;
115
144
  export function createSuspendedAskTracker(filter) {
145
+ const scope = suspendedAskScopeOf(filter);
116
146
  const shown = new Set();
117
147
  const shownWithFrame = new Set();
118
148
  const claimed = new Map();
@@ -137,7 +167,9 @@ export function createSuspendedAskTracker(filter) {
137
167
  ingest(snapshot) {
138
168
  if (snapshot?.kind === 'unknown')
139
169
  return { appeared: [], gone: [], upgraded: [] };
140
- const rows = suspendedSubagentAsks(snapshot, filter);
170
+ if (scope.kind === 'identity_pending')
171
+ return { appeared: [], gone: [], upgraded: [] };
172
+ const rows = subagentAsksIn(snapshot, scope);
141
173
  const present = new Set(rows.map(r => r.approvalId));
142
174
  const appeared = [];
143
175
  const upgraded = [];
@@ -6,6 +6,7 @@ export interface LocalAllowRuleDeps {
6
6
  bashRuleContentHasDangerousBarePrefix(ruleContent: string): boolean;
7
7
  isDangerousBashPermission(toolName: string, ruleContent: string): boolean;
8
8
  isDangerousPowerShellPermission(toolName: string, ruleContent: string): boolean;
9
+ onFailure?(log: string): void;
9
10
  }
10
11
  export type LocalAllowRuleParse = {
11
12
  ok: true;
@@ -1,4 +1,4 @@
1
- import { wireFailureTextsOf } from '../wireFailureShape.js';
1
+ import { reasonOfThrownWithSink } from '../hostCallbackGuard.js';
2
2
  const BASH_TOOL_NAME_FOR_RULES = 'Bash';
3
3
  export function parseLocalAllowRule(rule, expectedToolName, deps) {
4
4
  if (typeof rule !== 'string' || rule === '') {
@@ -9,7 +9,7 @@ export function parseLocalAllowRule(rule, expectedToolName, deps) {
9
9
  value = deps.parseRule(rule);
10
10
  }
11
11
  catch (e) {
12
- return { ok: false, error: `rule text did not parse (${wireFailureTextsOf(e).reason})` };
12
+ return { ok: false, error: `rule text did not parse (${reasonOfThrownWithSink(e, (log) => deps.onFailure?.(log))})` };
13
13
  }
14
14
  if (typeof value.toolName !== 'string' || value.toolName === '') {
15
15
  return { ok: false, error: 'rule text carries no tool name' };
@@ -1,9 +1,10 @@
1
- export type NoAllowCause = 'no_allow_rule' | 'ask_rule' | 'budget' | 'other';
1
+ export type NoAllowCause = 'no_allow_rule' | 'ask_rule' | 'engine_ask_rule' | 'budget' | 'other';
2
2
  export interface RuleLadderNoAllowFacts {
3
3
  readonly allowed?: boolean;
4
4
  readonly denied?: boolean;
5
5
  readonly askRuleMatched?: boolean;
6
6
  readonly budgetExhausted?: boolean;
7
7
  readonly noRuleMatched?: boolean;
8
+ readonly noAskRuleMatched?: boolean;
8
9
  }
9
10
  export declare function noAllowCauseOf(card: object | null | undefined, ladder: RuleLadderNoAllowFacts | null | undefined): NoAllowCause | undefined;
@@ -18,8 +18,9 @@ export function noAllowCauseOf(card, ladder) {
18
18
  if (ladderSays(ladder, 'budgetExhausted'))
19
19
  return 'budget';
20
20
  const standing = automaticAnswerVerdict(card, 'standing_rule');
21
- if (standing.kind === 'must_ask' && (standing.askClass === 'ask_rule' || standing.origin === 'ask_rule'))
22
- return 'ask_rule';
21
+ if (standing.kind === 'must_ask' && (standing.askClass === 'ask_rule' || standing.origin === 'ask_rule')) {
22
+ return ladderSays(ladder, 'noAskRuleMatched') || ladderSays(ladder, 'noRuleMatched') ? 'engine_ask_rule' : 'ask_rule';
23
+ }
23
24
  if (ladderSays(ladder, 'noRuleMatched') && standing.kind === 'may_answer')
24
25
  return 'no_allow_rule';
25
26
  return 'other';
@@ -0,0 +1,19 @@
1
+ export type ApprovalCompleteDisposition = 'live-expired-parked' | 'live-expired-retract' | 'settled' | null;
2
+ export declare function classifyApprovalCompleteFrame(frame: unknown): ApprovalCompleteDisposition;
3
+ export type ParkRowDeadlineState = {
4
+ kind: 'none';
5
+ } | {
6
+ kind: 'pending';
7
+ deadlineMs: number;
8
+ remainingMs: number;
9
+ } | {
10
+ kind: 'past';
11
+ deadlineMs: number;
12
+ remainingMs: number;
13
+ };
14
+ export declare function parkRowDeadlineState(row: unknown, nowMs: number): ParkRowDeadlineState;
15
+ export declare function lateDecideRoute(o: {
16
+ windowClosed: boolean;
17
+ durableRowFound: boolean;
18
+ }): 'decide' | 'respond';
19
+ export declare function runReapedByDeadline(client: unknown, taskId: string): Promise<boolean>;
@@ -0,0 +1,46 @@
1
+ import { APPROVAL_EXPIRED } from '../engineErrorCodes.js';
2
+ import { approvalCompleteParked } from './approvalCompleteParked.js';
3
+ export function classifyApprovalCompleteFrame(frame) {
4
+ if (typeof frame !== 'object' || frame === null)
5
+ return null;
6
+ const f = frame;
7
+ if (f.type !== 'tool_approval_complete')
8
+ return null;
9
+ const outcome = f.outcome;
10
+ if (outcome === 'allowed' || outcome === 'denied')
11
+ return 'settled';
12
+ if (outcome !== 'expired')
13
+ return null;
14
+ return approvalCompleteParked(frame) ? 'live-expired-parked' : 'live-expired-retract';
15
+ }
16
+ const PARK_DEADLINE_MAX_SANE_MS = 24 * 60 * 60 * 1000;
17
+ export function parkRowDeadlineState(row, nowMs) {
18
+ if (typeof row !== 'object' || row === null)
19
+ return { kind: 'none' };
20
+ const raw = row.deadline;
21
+ if (typeof raw !== 'number' || !Number.isFinite(raw) || raw <= 0)
22
+ return { kind: 'none' };
23
+ const remainingMs = raw - nowMs;
24
+ if (remainingMs > PARK_DEADLINE_MAX_SANE_MS)
25
+ return { kind: 'none' };
26
+ return remainingMs > 0
27
+ ? { kind: 'pending', deadlineMs: raw, remainingMs }
28
+ : { kind: 'past', deadlineMs: raw, remainingMs };
29
+ }
30
+ export function lateDecideRoute(o) {
31
+ if (!o.windowClosed)
32
+ return 'respond';
33
+ return o.durableRowFound ? 'decide' : 'respond';
34
+ }
35
+ export async function runReapedByDeadline(client, taskId) {
36
+ try {
37
+ const runs = client?.runs;
38
+ if (typeof runs?.get !== 'function')
39
+ return false;
40
+ const rec = (await runs.get(taskId));
41
+ return rec?.errorCode === APPROVAL_EXPIRED;
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ }
@@ -1,7 +1,6 @@
1
1
  import type { AgentEvent } from '@sema-agent/sdk';
2
- import { type GateCurrentPending, type HitlFailureStage } from './hitlBridge.js';
2
+ import { type GateCurrentPending, type HitlFailureStage, type HitlSafetyCode } from './hitlBridge.js';
3
3
  import { type QuestionAnswer } from '../liveQuestionStore.js';
4
- import { type FsApprovalOutcome } from './toolApprovalWire.js';
5
4
  import type { AskAnsweredOutput, GateLedger } from './gateLedger.js';
6
5
  import { type AskGateWireDeps, type GatePark } from './frameRouter.js';
7
6
  import { type DecideReceiptView } from '../decideReceipt.js';
@@ -13,8 +12,7 @@ export interface HopBudget {
13
12
  }
14
13
  export declare function nextHopBudget(prev: HopBudget | undefined, round: HopRound): HopBudget;
15
14
  export declare const MAX_TOTAL_PARKS = 64;
16
- export declare const GATE_FAILURE_CODES: readonly ["no_pending", "binding_mismatch", "wrong_gate", "bad_plan_edit", "bad_plan_mode", "empty_answer"];
17
- export type GateFailureCode = (typeof GATE_FAILURE_CODES)[number];
15
+ export type GateFailureCode = HitlSafetyCode;
18
16
  export type GateOutcome = {
19
17
  kind: 'decided';
20
18
  gatedCallId?: string | undefined;
@@ -30,14 +28,13 @@ export type GateOutcome = {
30
28
  reason: string;
31
29
  code?: GateFailureCode | undefined;
32
30
  errorCode?: string | undefined;
31
+ blockedBy?: string | undefined;
33
32
  retriable?: true;
34
33
  retryExhausted?: true;
35
34
  currentPending?: GateCurrentPending | undefined;
36
35
  };
37
36
  export declare function isAlreadyResolvedGateReason(reason: unknown): boolean;
38
- export declare function isAlreadyResolvedFailure(outcome: Extract<GateOutcome | FsApprovalOutcome, {
39
- kind: 'failed';
40
- }>): boolean;
37
+ export declare function isAlreadyResolvedFailure(failure: unknown): boolean;
41
38
  export declare function isGateStandingErrorCode(code: string | null | undefined, retriable?: boolean): boolean;
42
39
  export declare function isCodeClassifiedGateFailure(code: string | null | undefined, retriable?: boolean): boolean;
43
40
  export declare function toAnsweredOutput(questions: unknown[], answer: QuestionAnswer): AskAnsweredOutput;