@sema-agent/client-core 0.97.1 → 0.99.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 (353) hide show
  1. package/CHANGELOG.md +607 -0
  2. package/README.md +96 -46
  3. package/dist/adapt/arms.d.ts +1 -0
  4. package/dist/adapt/arms.js +188 -53
  5. package/dist/adapt/ids.d.ts +12 -1
  6. package/dist/adapt/ids.js +59 -8
  7. package/dist/adapt/instanceLedger.d.ts +50 -0
  8. package/dist/adapt/instanceLedger.js +147 -0
  9. package/dist/adapt/panelTasks.d.ts +1 -1
  10. package/dist/adapt/panelTasks.js +2 -2
  11. package/dist/adapt/textStream.d.ts +1 -0
  12. package/dist/adapt/textStream.js +24 -7
  13. package/dist/adapt/toolCards.d.ts +27 -5
  14. package/dist/adapt/toolCards.js +39 -6
  15. package/dist/adapt/wireShapes.js +6 -2
  16. package/dist/adapt.d.ts +2 -0
  17. package/dist/adapt.js +8 -3
  18. package/dist/adapter/activeRunSelfHeal.d.ts +9 -3
  19. package/dist/adapter/activeRunSelfHeal.js +205 -313
  20. package/dist/adapter/downstream/eventToSdkMessage.d.ts +2 -5
  21. package/dist/adapter/downstream/eventToSdkMessage.js +77 -36
  22. package/dist/adapter/downstream/terminalToSdkResult.js +11 -4
  23. package/dist/adapter/downstream/turnUsageToModelUsage.d.ts +5 -2
  24. package/dist/adapter/downstream/turnUsageToModelUsage.js +2 -0
  25. package/dist/adapter/runStream.js +79 -48
  26. package/dist/adapter/types.d.ts +4 -4
  27. package/dist/adapter/types.js +2 -1
  28. package/dist/agentSession/backgroundView.js +2 -1
  29. package/dist/agentSession/engineAgentRegistryRead.d.ts +2 -2
  30. package/dist/agentSession/engineAgentRegistryRead.js +12 -13
  31. package/dist/agentSession/engineSessionBackgroundStop.js +16 -8
  32. package/dist/agentsWireCaps.d.ts +8 -11
  33. package/dist/agentsWireCaps.js +196 -194
  34. package/dist/approvalDecidedByCapability.d.ts +0 -4
  35. package/dist/approvalDecidedByCapability.js +0 -6
  36. package/dist/approvalsStreamLiveCapability.d.ts +0 -4
  37. package/dist/approvalsStreamLiveCapability.js +0 -6
  38. package/dist/assistantInbox.d.ts +34 -0
  39. package/dist/assistantInbox.js +118 -0
  40. package/dist/centerWiringCapability.js +9 -1
  41. package/dist/clientSlice.d.ts +0 -9
  42. package/dist/clientSlice.js +0 -3
  43. package/dist/cloudConfigWireCaps.d.ts +5 -3
  44. package/dist/cloudConfigWireCaps.js +106 -64
  45. package/dist/compensations.js +1 -1
  46. package/dist/connectorStatus.d.ts +21 -0
  47. package/dist/connectorStatus.js +112 -0
  48. package/dist/controlRouter.d.ts +18 -3
  49. package/dist/controlRouter.js +106 -67
  50. package/dist/coreValuePorts.d.ts +29 -4
  51. package/dist/coreValuePorts.js +10 -0
  52. package/dist/corruptSessionCopy.d.ts +2 -1
  53. package/dist/corruptSessionCopy.js +3 -3
  54. package/dist/decideReceipt.d.ts +2 -2
  55. package/dist/decideReceipt.js +5 -2
  56. package/dist/declared/supportFloorDeclared.js +3 -3
  57. package/dist/detachWire.js +3 -2
  58. package/dist/deviceExecutorManagementCapability.d.ts +0 -4
  59. package/dist/deviceExecutorManagementCapability.js +0 -6
  60. package/dist/deviceRebind.d.ts +49 -1
  61. package/dist/deviceRebind.js +221 -3
  62. package/dist/devicesFace.d.ts +34 -0
  63. package/dist/devicesFace.js +90 -0
  64. package/dist/displayUntrusted.d.ts +2 -0
  65. package/dist/displayUntrusted.js +253 -76
  66. package/dist/engineAgentAbsence.d.ts +1 -1
  67. package/dist/engineAgentPanelStore.d.ts +12 -4
  68. package/dist/engineAgentPanelStore.js +16 -11
  69. package/dist/engineCapReader.d.ts +2 -5
  70. package/dist/engineCapReader.js +8 -10
  71. package/dist/engineCapsCache.d.ts +12 -0
  72. package/dist/engineCapsCache.js +76 -18
  73. package/dist/engineCapsChange.d.ts +2 -0
  74. package/dist/engineCapsChange.js +9 -0
  75. package/dist/engineClosedSets.d.ts +1 -0
  76. package/dist/engineClosedSets.js +4 -1
  77. package/dist/engineErrorCodes.d.ts +11 -3
  78. package/dist/engineErrorCodes.js +11 -8
  79. package/dist/engineIdentity.d.ts +1 -0
  80. package/dist/engineIdentity.js +8 -0
  81. package/dist/engineRowRef.d.ts +28 -0
  82. package/dist/engineRowRef.js +114 -0
  83. package/dist/engineSessionMessages.d.ts +68 -0
  84. package/dist/engineSessionMessages.js +370 -0
  85. package/dist/engineTargetSeat.d.ts +27 -0
  86. package/dist/engineTargetSeat.js +199 -0
  87. package/dist/engineToolDirectory.d.ts +0 -9
  88. package/dist/engineToolDirectory.js +1 -94
  89. package/dist/engineUrl.d.ts +18 -0
  90. package/dist/engineUrl.js +52 -0
  91. package/dist/engineWireFor.js +3 -8
  92. package/dist/env/uiLanguage.d.ts +11 -1
  93. package/dist/env/uiLanguage.js +38 -2
  94. package/dist/eventLeg.d.ts +100 -0
  95. package/dist/eventLeg.js +305 -0
  96. package/dist/executionLaneCapability.d.ts +0 -4
  97. package/dist/executionLaneCapability.js +3 -16
  98. package/dist/fileHistoryCaptureCapability.d.ts +2 -5
  99. package/dist/fileHistoryCaptureCapability.js +13 -21
  100. package/dist/fileHistoryLegNotice.d.ts +2 -1
  101. package/dist/fileHistoryLegNotice.js +3 -3
  102. package/dist/fleet/fleetLedger.d.ts +0 -3
  103. package/dist/fleet/fleetLedger.js +21 -36
  104. package/dist/fleet/fleetProjection.d.ts +2 -2
  105. package/dist/fleet/fleetProjection.js +10 -8
  106. package/dist/frameBinding.d.ts +8 -0
  107. package/dist/frameBinding.js +35 -0
  108. package/dist/gateFailureCodes.d.ts +2 -0
  109. package/dist/gateFailureCodes.js +15 -0
  110. package/dist/gateOutcome.d.ts +3 -1
  111. package/dist/gateOutcome.js +41 -8
  112. package/dist/gateVocabulary.d.ts +10 -4
  113. package/dist/gateVocabulary.js +107 -47
  114. package/dist/generated/engineAskFaceTables.js +2 -2
  115. package/dist/generated/engineFactTables.d.ts +22 -3
  116. package/dist/generated/engineFactTables.js +51 -4
  117. package/dist/generated/engineNoticeTables.js +18 -3
  118. package/dist/generated/settingsSchemaFns.d.ts +6 -0
  119. package/dist/generated/settingsSchemaFns.js +57 -0
  120. package/dist/generated/settingsSchemaHooksClassifier.d.ts +2 -0
  121. package/dist/generated/settingsSchemaHooksClassifier.js +254 -0
  122. package/dist/generated/settingsSchemaTables.d.ts +1 -0
  123. package/dist/generated/settingsSchemaTables.js +4 -0
  124. package/dist/generated/settingsSchemaTypes.d.ts +105 -0
  125. package/dist/generated/settingsSchemaTypes.js +1 -0
  126. package/dist/generated/toolNameTables.d.ts +1 -0
  127. package/dist/generated/toolNameTables.js +1 -0
  128. package/dist/hitl/allowRuleShadow.d.ts +8 -2
  129. package/dist/hitl/allowRuleShadow.js +36 -29
  130. package/dist/hitl/approvalCardReading.d.ts +15 -0
  131. package/dist/hitl/approvalCardReading.js +154 -0
  132. package/dist/hitl/approvalCardReasons.d.ts +14 -0
  133. package/dist/hitl/approvalCardReasons.js +119 -0
  134. package/dist/hitl/approvalHolds.d.ts +50 -15
  135. package/dist/hitl/approvalHolds.js +177 -27
  136. package/dist/hitl/approvalResolution.d.ts +51 -26
  137. package/dist/hitl/approvalResolution.js +86 -122
  138. package/dist/hitl/approvalsFeed.js +6 -18
  139. package/dist/hitl/askClassPair.d.ts +2 -0
  140. package/dist/hitl/askClassPair.js +17 -0
  141. package/dist/hitl/askGateWire.d.ts +20 -2
  142. package/dist/hitl/askGateWire.js +50 -1
  143. package/dist/hitl/askParkRowRouting.d.ts +5 -0
  144. package/dist/hitl/askParkRowRouting.js +32 -1
  145. package/dist/hitl/askSettlementLine.d.ts +28 -0
  146. package/dist/hitl/askSettlementLine.js +99 -0
  147. package/dist/hitl/automaticAnswerVerdict.d.ts +3 -2
  148. package/dist/hitl/automaticAnswerVerdict.js +29 -13
  149. package/dist/hitl/crashConverged.d.ts +11 -20
  150. package/dist/hitl/crashConverged.js +56 -0
  151. package/dist/hitl/crashConvergedNotice.d.ts +6 -3
  152. package/dist/hitl/crashConvergedNotice.js +48 -24
  153. package/dist/hitl/decisionConflict.js +3 -10
  154. package/dist/hitl/decisionRefusal.d.ts +40 -1
  155. package/dist/hitl/decisionRefusal.js +199 -42
  156. package/dist/hitl/frameRouter.d.ts +5 -2
  157. package/dist/hitl/frameRouter.js +27 -24
  158. package/dist/hitl/gateLedger.d.ts +2 -0
  159. package/dist/hitl/gateLedger.js +50 -13
  160. package/dist/hitl/hitlBridge.d.ts +2 -2
  161. package/dist/hitl/hitlBridge.js +13 -10
  162. package/dist/hitl/livePendingAsk.d.ts +3 -3
  163. package/dist/hitl/livePendingAsk.js +7 -18
  164. package/dist/hitl/parkResolver.d.ts +2 -24
  165. package/dist/hitl/parkResolver.js +61 -97
  166. package/dist/hitl/persistedRulesWire.d.ts +25 -0
  167. package/dist/hitl/persistedRulesWire.js +104 -2
  168. package/dist/hitl/planReviewWire.d.ts +31 -13
  169. package/dist/hitl/planReviewWire.js +120 -78
  170. package/dist/hitl/refusedToolNameProse.d.ts +0 -1
  171. package/dist/hitl/refusedToolNameProse.js +0 -3
  172. package/dist/hitl/replayedApproval.d.ts +4 -3
  173. package/dist/hitl/replayedApproval.js +7 -4
  174. package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
  175. package/dist/hitl/sessionPolicyDeliverable.js +48 -7
  176. package/dist/hitl/sessionPolicyWire.d.ts +34 -21
  177. package/dist/hitl/sessionPolicyWire.js +179 -70
  178. package/dist/hitl/standingRows.d.ts +20 -2
  179. package/dist/hitl/standingRows.js +69 -8
  180. package/dist/hitl/suspendedReopen.d.ts +2 -1
  181. package/dist/hitl/suspendedReopen.js +7 -10
  182. package/dist/hitl/toolApprovalWire.d.ts +103 -156
  183. package/dist/hitl/toolApprovalWire.js +661 -411
  184. package/dist/hookMatcherVerdict.d.ts +6 -1
  185. package/dist/hookMatcherVerdict.js +14 -7
  186. package/dist/hooksWireCaps.d.ts +2 -2
  187. package/dist/hooksWireCaps.js +174 -81
  188. package/dist/host.d.ts +21 -0
  189. package/dist/hostTurnSettings.d.ts +71 -0
  190. package/dist/hostTurnSettings.js +291 -0
  191. package/dist/humanTurn.d.ts +14 -1
  192. package/dist/humanTurn.js +100 -12
  193. package/dist/humanTurnRead.d.ts +2 -0
  194. package/dist/humanTurnRead.js +22 -1
  195. package/dist/i18n/messages.en.d.ts +703 -0
  196. package/dist/i18n/messages.en.js +701 -0
  197. package/dist/i18n/messages.zh.d.ts +3 -0
  198. package/dist/i18n/messages.zh.js +837 -0
  199. package/dist/i18n/translate.d.ts +25 -0
  200. package/dist/i18n/translate.js +127 -0
  201. package/dist/index.d.ts +78 -29
  202. package/dist/index.js +54 -18
  203. package/dist/inheritEnvCapability.d.ts +32 -0
  204. package/dist/inheritEnvCapability.js +104 -0
  205. package/dist/inheritEnvWire.d.ts +3 -2
  206. package/dist/inheritEnvWire.js +12 -14
  207. package/dist/interactiveHalt.js +17 -6
  208. package/dist/liveModelCatalog.d.ts +3 -3
  209. package/dist/liveModelCatalog.js +15 -13
  210. package/dist/liveQuestionStore.d.ts +2 -21
  211. package/dist/mcpLiveness.d.ts +2 -1
  212. package/dist/mcpPanel.d.ts +10 -1
  213. package/dist/mcpPanel.js +40 -13
  214. package/dist/mcpProbeCapability.d.ts +2 -1
  215. package/dist/mcpProbeCapability.js +7 -11
  216. package/dist/mcpProbeWire.d.ts +9 -2
  217. package/dist/mcpProbeWire.js +6 -1
  218. package/dist/mcpWireCaps.d.ts +47 -2
  219. package/dist/mcpWireCaps.js +164 -16
  220. package/dist/memoryEntriesWire.d.ts +4 -9
  221. package/dist/memoryEntriesWire.js +5 -10
  222. package/dist/model/modelSupplyRules.d.ts +0 -2
  223. package/dist/model/modelSupplyRules.js +3 -12
  224. package/dist/model/modelsPolicy.d.ts +0 -5
  225. package/dist/model/modelsPolicy.js +6 -36
  226. package/dist/model/onboardJudgement.d.ts +93 -0
  227. package/dist/model/onboardJudgement.js +415 -0
  228. package/dist/model/subagentModelWord.d.ts +31 -0
  229. package/dist/model/subagentModelWord.js +261 -0
  230. package/dist/model/tierVocabulary.d.ts +2 -0
  231. package/dist/model/tierVocabulary.js +17 -5
  232. package/dist/modelCapabilityProbe.d.ts +64 -0
  233. package/dist/modelCapabilityProbe.js +600 -0
  234. package/dist/modelIdentityResolvability.d.ts +3 -0
  235. package/dist/modelIdentityResolvability.js +26 -17
  236. package/dist/notifications.d.ts +6 -0
  237. package/dist/notifications.js +71 -23
  238. package/dist/outputStyleSeatCapability.d.ts +0 -3
  239. package/dist/outputStyleSeatCapability.js +0 -3
  240. package/dist/ownKey.d.ts +22 -0
  241. package/dist/ownKey.js +94 -3
  242. package/dist/panelReduce.d.ts +21 -10
  243. package/dist/panelReduce.js +728 -550
  244. package/dist/panelStateHolder.d.ts +3 -7
  245. package/dist/panelStateHolder.js +14 -130
  246. package/dist/peerLaneCapability.d.ts +0 -4
  247. package/dist/peerLaneCapability.js +0 -6
  248. package/dist/permissionRuleIssue.js +2 -0
  249. package/dist/permissionRulesWriteCapability.d.ts +2 -5
  250. package/dist/permissionRulesWriteCapability.js +8 -12
  251. package/dist/permissionWireCaps.d.ts +2 -2
  252. package/dist/permissionWireCaps.js +2 -0
  253. package/dist/permissionsAllowGrantCapability.d.ts +0 -4
  254. package/dist/permissionsAllowGrantCapability.js +0 -6
  255. package/dist/permissionsDeclaration.d.ts +0 -11
  256. package/dist/permissionsDeclaration.js +60 -53
  257. package/dist/pluginHooksWire.d.ts +46 -3
  258. package/dist/pluginHooksWire.js +219 -16
  259. package/dist/preemptWire.d.ts +44 -0
  260. package/dist/preemptWire.js +83 -0
  261. package/dist/printModelStatus.d.ts +63 -0
  262. package/dist/printModelStatus.js +155 -0
  263. package/dist/printToolResultFrame.js +15 -4
  264. package/dist/replayBody.d.ts +3 -0
  265. package/dist/replayBody.js +14 -0
  266. package/dist/request/taskRequest.d.ts +11 -6
  267. package/dist/request/taskRequest.js +112 -19
  268. package/dist/resumeRefusalCopy.d.ts +13 -9
  269. package/dist/resumeRefusalCopy.js +81 -118
  270. package/dist/retryStatus.d.ts +45 -0
  271. package/dist/retryStatus.js +185 -1
  272. package/dist/rewindArchiveCapability.d.ts +0 -4
  273. package/dist/rewindArchiveCapability.js +2 -10
  274. package/dist/rewindArchiveReading.d.ts +0 -1
  275. package/dist/rewindArchiveReading.js +0 -3
  276. package/dist/runCancelContext.d.ts +2 -1
  277. package/dist/runCancelContext.js +4 -2
  278. package/dist/runReattachPolicy.d.ts +31 -0
  279. package/dist/runReattachPolicy.js +46 -0
  280. package/dist/runTerminal.d.ts +3 -6
  281. package/dist/runTerminal.js +8 -9
  282. package/dist/sandboxWire.d.ts +3 -1
  283. package/dist/sandboxWire.js +76 -27
  284. package/dist/scenarioRefusal.d.ts +9 -0
  285. package/dist/scenarioRefusal.js +111 -0
  286. package/dist/scenarioWire.js +1 -1
  287. package/dist/seam.d.ts +48 -2
  288. package/dist/seam.js +25 -4
  289. package/dist/seatContract.d.ts +311 -18
  290. package/dist/seatContract.js +824 -100
  291. package/dist/selfOrchestrationDenial.js +7 -19
  292. package/dist/sessionIdSegment.d.ts +6 -0
  293. package/dist/sessionIdSegment.js +24 -0
  294. package/dist/sessionMemoryStatus.js +6 -11
  295. package/dist/sessionPolicyCapability.d.ts +2 -5
  296. package/dist/sessionPolicyCapability.js +8 -12
  297. package/dist/sessionSyncFileHistoryCapability.d.ts +0 -3
  298. package/dist/sessionSyncFileHistoryCapability.js +0 -3
  299. package/dist/settingsHooksSalvage.d.ts +44 -0
  300. package/dist/settingsHooksSalvage.js +211 -0
  301. package/dist/skillToolListsCapability.d.ts +2 -4
  302. package/dist/skillToolListsCapability.js +8 -9
  303. package/dist/sqlEngineCapability.d.ts +0 -4
  304. package/dist/sqlEngineCapability.js +0 -6
  305. package/dist/sseIdleTriage.js +3 -2
  306. package/dist/steerPriorityCapability.d.ts +0 -3
  307. package/dist/steerPriorityCapability.js +0 -3
  308. package/dist/streamDrainingLegs.d.ts +4 -0
  309. package/dist/streamDrainingLegs.js +6 -1
  310. package/dist/subagent/engineCompactWire.d.ts +0 -1
  311. package/dist/subagent/engineCompactWire.js +7 -5
  312. package/dist/subagent/engineSubagentResume.js +15 -9
  313. package/dist/subagent/engineTaskHandleWire.js +4 -7
  314. package/dist/subagentContentStore.d.ts +3 -0
  315. package/dist/subagentContentStore.js +22 -10
  316. package/dist/submitReopen.d.ts +24 -0
  317. package/dist/submitReopen.js +75 -0
  318. package/dist/terminalStatuses.d.ts +3 -0
  319. package/dist/terminalStatuses.js +10 -2
  320. package/dist/toolHistoryMismatch.js +3 -2
  321. package/dist/toolResult.d.ts +10 -1
  322. package/dist/toolResult.js +34 -6
  323. package/dist/toolRoster.d.ts +3 -4
  324. package/dist/toolRoster.js +21 -22
  325. package/dist/turnFailurePresentation.d.ts +39 -0
  326. package/dist/turnFailurePresentation.js +402 -0
  327. package/dist/usageAnalytics.js +6 -11
  328. package/dist/userAttachmentEnvelope.d.ts +1 -0
  329. package/dist/userAttachmentEnvelope.js +37 -7
  330. package/dist/userAttachmentSeat.d.ts +21 -0
  331. package/dist/userAttachmentSeat.js +75 -0
  332. package/dist/userInvokedSkillsCapability.d.ts +11 -4
  333. package/dist/userInvokedSkillsCapability.js +31 -10
  334. package/dist/webSearchBackendCapability.d.ts +0 -4
  335. package/dist/webSearchBackendCapability.js +0 -6
  336. package/dist/wireErrorTriage.d.ts +7 -0
  337. package/dist/wireErrorTriage.js +26 -23
  338. package/dist/wireFailureShape.d.ts +62 -5
  339. package/dist/wireFailureShape.js +106 -5
  340. package/dist/wireRefusalCopy.d.ts +25 -3
  341. package/dist/wireRefusalCopy.js +74 -80
  342. package/dist/workflowsJournalCapability.d.ts +2 -5
  343. package/dist/workflowsJournalCapability.js +8 -12
  344. package/dist/writeProtectionCapability.d.ts +0 -4
  345. package/dist/writeProtectionCapability.js +0 -6
  346. package/docs/INTEGRATION-CLIENTS.md +1775 -56
  347. package/package.json +6 -5
  348. package/dist/attachmentSeatCapability.d.ts +0 -12
  349. package/dist/attachmentSeatCapability.js +0 -23
  350. package/dist/hitl/approvalOutcomeNote.d.ts +0 -10
  351. package/dist/hitl/approvalOutcomeNote.js +0 -29
  352. package/dist/sessionReadRedactionCapability.d.ts +0 -13
  353. package/dist/sessionReadRedactionCapability.js +0 -35
@@ -1,10 +1,13 @@
1
+ import { displayUntrusted, quoteUntrustedForSentence } from '../displayUntrusted.js';
1
2
  import { engineCapTrue } from '../engineCapsCache.js';
2
3
  import { CORE_RULE_BEHAVIORS } from '../generated/engineFactTables.js';
3
4
  import { wireFailureShapeOf } from '../wireFailureShape.js';
4
5
  import { CAPABILITY_OPERATOR_PRINCIPALS_REQUIRED } from '../engineErrorCodes.js';
5
6
  import { hostLog } from '../host.js';
7
+ import { msg, renderMessage } from '../i18n/translate.js';
8
+ import { guardedRead, readOwnDataValue } from '../ownKey.js';
6
9
  import { observedPermissionRulesWrite, permissionRulesWriteAvailable } from '../permissionRulesWriteCapability.js';
7
- import { readToolApprovalRespondAck } from './toolApprovalWire.js';
10
+ import { isToolApprovalRespondReplayed, readToolApprovalRespondAck } from './toolApprovalWire.js';
8
11
  export function persistedRulesLaneAvailable(baseUrl) {
9
12
  return engineCapTrue(baseUrl, 'permissionRules');
10
13
  }
@@ -112,6 +115,105 @@ export const PERSISTED_RULE_BEHAVIOR_UNKNOWN = '(unknown)';
112
115
  export function persistedRuleBehaviorLabel(rule) {
113
116
  return rowStr(rule, 'behavior') ?? PERSISTED_RULE_BEHAVIOR_UNKNOWN;
114
117
  }
118
+ const PERSISTED_RULE_ORIGIN_KEYS = Object.freeze({
119
+ user: 'rules.origin.user',
120
+ 'imported-cc': 'rules.origin.importedCc',
121
+ starter: 'rules.origin.starter',
122
+ });
123
+ const UNKNOWN_ORIGIN_KEY = 'rules.origin.unknownWord';
124
+ const NO_ORIGIN_KEY = 'rules.origin.none';
125
+ function originKeyOf(origin) {
126
+ return typeof origin === 'string' && Object.hasOwn(PERSISTED_RULE_ORIGIN_KEYS, origin) ? PERSISTED_RULE_ORIGIN_KEYS[origin] : UNKNOWN_ORIGIN_KEY;
127
+ }
128
+ function ownSlot(o, key) {
129
+ if (typeof o !== 'object' || o === null)
130
+ return undefined;
131
+ return guardedRead(() => readOwnDataValue(o, key));
132
+ }
133
+ const ORIGINS_READ_MAX = 256;
134
+ export function persistedRuleAddOriginLabel(origin, lang) {
135
+ return renderMessage(msg(originKeyOf(origin)), lang);
136
+ }
137
+ export function persistedRuleOriginsLabel(rule, lang) {
138
+ const adds = ownSlot(rule, 'adds');
139
+ const isArr = guardedRead(() => (Array.isArray(adds) ? true : undefined));
140
+ if (isArr !== true)
141
+ return renderMessage(msg(NO_ORIGIN_KEY), lang);
142
+ const lenRaw = ownSlot(adds, 'length');
143
+ const len = typeof lenRaw === 'number' && Number.isSafeInteger(lenRaw) && lenRaw > 0 ? Math.min(lenRaw, ORIGINS_READ_MAX) : 0;
144
+ const seen = [];
145
+ for (let i = 0; i < len; i++) {
146
+ const origin = ownSlot(ownSlot(adds, String(i)), 'origin');
147
+ const key = originKeyOf(typeof origin === 'string' ? origin : undefined);
148
+ if (!seen.includes(key))
149
+ seen.push(key);
150
+ }
151
+ return seen.length === 0 ? renderMessage(msg(NO_ORIGIN_KEY), lang) : seen.map((k) => renderMessage(msg(k), lang)).join(renderMessage(msg('rules.origin.join'), lang));
152
+ }
153
+ const UNKNOWN_SCOPE_KEY = 'rules.scope.unknown';
154
+ export function persistedRuleScopeLabel(scope, lang) {
155
+ if (scope === 'global')
156
+ return renderMessage(msg('rules.scope.all'), lang);
157
+ if (typeof scope === 'string' && scope.startsWith('project:') && scope.length > 'project:'.length) {
158
+ const shown = displayUntrusted(scope.slice('project:'.length), { max: 400, blanks: true });
159
+ return shown === '' ? renderMessage(msg(UNKNOWN_SCOPE_KEY), lang) : shown;
160
+ }
161
+ return renderMessage(msg(UNKNOWN_SCOPE_KEY), lang);
162
+ }
163
+ const PERSISTED_RULE_REVOKE_KEYS = Object.freeze({
164
+ removed: {
165
+ yes: { notice: 'rules.revoke.removed.yes.notice', change: 'rules.revoke.removed.yes.change' },
166
+ unknown: { notice: 'rules.revoke.removed.unknown.notice', change: 'rules.revoke.removed.unknown.change' },
167
+ no: { notice: 'rules.revoke.removed.no.notice', change: 'rules.revoke.removed.no.change' },
168
+ },
169
+ 'nothing-written': {
170
+ yes: { notice: 'rules.revoke.nothingWritten.yes.notice', change: 'rules.revoke.nothingWritten.yes.change' },
171
+ unknown: { notice: 'rules.revoke.nothingWritten.unknown.notice', change: 'rules.revoke.nothingWritten.unknown.change' },
172
+ no: { notice: 'rules.revoke.nothingWritten.no.notice', change: 'rules.revoke.nothingWritten.no.change' },
173
+ },
174
+ });
175
+ const REVOKE_UNKNOWN_STATUS_KEYS = Object.freeze({
176
+ absent: { notice: 'rules.revoke.absent.notice', change: 'rules.revoke.absent.change' },
177
+ unrecognised: { notice: 'rules.revoke.unrecognised.notice', change: 'rules.revoke.unrecognised.change' },
178
+ liveness: { yes: 'rules.revoke.liveness.yes', unknown: 'rules.revoke.liveness.unknown', no: undefined },
179
+ });
180
+ export function persistedRuleRevokeOutcome(ruleText, result, lang) {
181
+ const quoted = typeof ruleText === 'string' ? quoteUntrustedForSentence(ruleText, 120) : undefined;
182
+ const rule = quoted ?? msg('rules.revoke.thisRule');
183
+ const status = ownSlot(result, 'status');
184
+ const rawLive = ownSlot(result, 'stillLive');
185
+ const liveness = rawLive === 'yes' || rawLive === 'no' || rawLive === 'unknown' ? rawLive : 'unknown';
186
+ if (status === 'removed' || status === 'no-op') {
187
+ const outcome = status === 'removed' ? 'removed' : 'nothing-written';
188
+ const line = PERSISTED_RULE_REVOKE_KEYS[outcome][liveness];
189
+ return Object.freeze({ outcome, liveness, notice: renderMessage(msg(line.notice, { rule }), lang), change: renderMessage(msg(line.change, { rule }), lang) });
190
+ }
191
+ const head = typeof status === 'string' && status !== '' ? REVOKE_UNKNOWN_STATUS_KEYS.unrecognised : REVOKE_UNKNOWN_STATUS_KEYS.absent;
192
+ const tailKey = REVOKE_UNKNOWN_STATUS_KEYS.liveness[liveness];
193
+ return Object.freeze({
194
+ outcome: 'unknown-status',
195
+ liveness,
196
+ notice: `${renderMessage(msg(head.notice, { rule }), lang)}${tailKey === undefined ? '' : renderMessage(msg(tailKey), lang)}`,
197
+ change: renderMessage(msg(head.change, { rule }), lang),
198
+ });
199
+ }
200
+ const PERSISTED_RULE_MATCH_KEYS = Object.freeze({
201
+ exact: 'rules.match.exact',
202
+ prefix: 'rules.match.prefix',
203
+ wildcard: 'rules.match.wildcard',
204
+ subpath: 'rules.match.subpath',
205
+ path: 'rules.match.path',
206
+ name: 'rules.match.name',
207
+ name_prefix: 'rules.match.namePrefix',
208
+ host: 'rules.match.host',
209
+ subdomain: 'rules.match.subdomain',
210
+ });
211
+ export function persistedRuleMatchLabel(ruleOrMatch, lang) {
212
+ const word = typeof ruleOrMatch === 'string' ? ruleOrMatch : ownSlot(ruleOrMatch, 'match');
213
+ if (typeof word !== 'string' || word === '')
214
+ return renderMessage(msg('rules.match.unreported'), lang);
215
+ return renderMessage(msg(Object.hasOwn(PERSISTED_RULE_MATCH_KEYS, word) ? PERSISTED_RULE_MATCH_KEYS[word] : 'rules.match.unknown'), lang);
216
+ }
115
217
  export function revokeTargetFromPersistedRule(rule, opts) {
116
218
  const behavior = persistedRuleBehaviorOf(rule);
117
219
  if (behavior === undefined)
@@ -434,7 +536,7 @@ export function classifySkippedReason(reason) {
434
536
  }
435
537
  export function readRulePersistOutcome(ack) {
436
538
  const parsed = readToolApprovalRespondAck(ack);
437
- if (parsed === undefined)
539
+ if (parsed === undefined || isToolApprovalRespondReplayed(parsed))
438
540
  return { state: 'unknown' };
439
541
  if (parsed.rulePersisted === true)
440
542
  return { state: 'persisted' };
@@ -28,6 +28,21 @@ export declare function _resetArmedPlanReviewsForTest(): void;
28
28
  export type PlanReviewReopenTrigger = 'user' | 'automatic';
29
29
  export type PlanReviewGateInstanceReader = (taskId: string) => Promise<ReadonlySet<string> | null>;
30
30
  export declare function clearPlanReviewUserDismissals(sessionKey?: string): void;
31
+ export type PlanReviewOfferedMode = 'three_choice' | 'two_choice' | 'unknown';
32
+ export interface PlanReviewCardLike {
33
+ readonly questionId?: string;
34
+ readonly questions?: ReadonlyArray<{
35
+ readonly options?: ReadonlyArray<{
36
+ readonly label?: string;
37
+ }>;
38
+ }>;
39
+ }
40
+ export interface PlanReviewQuestionIdReading {
41
+ readonly taskId: string;
42
+ readonly reopened: boolean;
43
+ }
44
+ export declare function planReviewTaskIdFromQuestionId(questionId: {} | null | undefined): PlanReviewQuestionIdReading | undefined;
45
+ export declare function planReviewOfferedModeOf(card: string | PlanReviewCardLike): PlanReviewOfferedMode;
31
46
  export interface ArmPlanReviewOptions {
32
47
  submittedInPlanMode?: boolean;
33
48
  readGateInstanceKeys?: PlanReviewGateInstanceReader;
@@ -76,22 +91,25 @@ export declare function notePlanReviewGateLeft(taskId: string): void;
76
91
  export declare function latestPlanReviewDecisionMark(taskId: string): number | null;
77
92
  export declare function __resetPlanReviewDecisionLatchForTests(): void;
78
93
  export declare function decidePlanReview(taskId: string, decision: 'approve' | 'reject', permissionModeAfter?: string, opts?: DecidePlanReviewOptions): Promise<void>;
79
- export interface ReopenPlanReviewOpts {
80
- mintFreshQuestionId?: boolean;
81
- deliverDecision?: (taskId: string, decision: 'approve' | 'reject', reason?: string) => void | Promise<void>;
94
+ export interface ReopenPlanReviewSharedOpts {
82
95
  sessionKey?: string;
83
- wire?: PlanReviewWire;
84
- onOutcome?: PlanReviewDeliveryOptions['onOutcome'];
85
- presentationReceiptMs?: number;
96
+ presentationReceiptMs: number;
86
97
  trigger?: PlanReviewReopenTrigger;
87
98
  readGateInstanceKeys?: PlanReviewGateInstanceReader;
88
99
  pendingReadStartedAt?: number;
89
100
  }
101
+ export interface ReopenPlanReviewFreshOpts extends ReopenPlanReviewSharedOpts {
102
+ mintFreshQuestionId?: true;
103
+ deliverDecision?: (taskId: string, decision: 'approve' | 'reject', reason?: string) => void | Promise<void>;
104
+ wire?: PlanReviewWire;
105
+ onOutcome?: PlanReviewDeliveryOptions['onOutcome'];
106
+ }
107
+ export interface ReopenPlanReviewReuseOpts extends ReopenPlanReviewSharedOpts {
108
+ mintFreshQuestionId: false;
109
+ deliverDecision?: never;
110
+ wire?: never;
111
+ onOutcome?: never;
112
+ }
113
+ export type ReopenPlanReviewOpts = ReopenPlanReviewFreshOpts | ReopenPlanReviewReuseOpts;
90
114
  export declare function _resetActiveReopenRespondersForTest(): void;
91
- export declare function reopenPlanReviewCard(taskId: string, opts: ReopenPlanReviewOpts & {
92
- presentationReceiptMs: number;
93
- }): Promise<ReopenCardVerdict>;
94
- export declare function reopenPlanReviewCard(taskId: string, opts?: ReopenPlanReviewOpts & {
95
- presentationReceiptMs?: undefined;
96
- }): ReopenCardVerdict;
97
- export declare function reopenPlanReviewCard(taskId: string, opts?: ReopenPlanReviewOpts): ReopenCardVerdict | Promise<ReopenCardVerdict>;
115
+ export declare function reopenPlanReviewCard(taskId: string, opts: ReopenPlanReviewOpts): Promise<ReopenCardVerdict>;
@@ -7,11 +7,13 @@ import { enqueuePlanReviewOutcome } from '../notifications.js';
7
7
  import { corruptStoredRowContent, corruptStoredRowWhere } from '../wireErrorTriage.js';
8
8
  import { decideFailureNote } from '../decideFailureNote.js';
9
9
  import { wireFailureTextsOf } from '../wireFailureShape.js';
10
+ import { readOwnDataNonEmptyString, readOwnDataValue } from '../ownKey.js';
10
11
  import { checkpointUnsupportedVersionContent, checkpointUnsupportedVersionFromError, resumeContextUnavailableContent, resumeContextUnavailableFromError } from '../resumeRefusalCopy.js';
11
- import { REQUEST_FIELD_CONFLICT, isUnavailableFaceCode } from '../engineErrorCodes.js';
12
+ import { REQUEST_FIELD_CONFLICT } from '../engineErrorCodes.js';
13
+ import { refusalDeliveryOf } from './decisionRefusal.js';
12
14
  import { denyReasonForWire, isPlanReviewModeAfter } from './hitlBridge.js';
13
15
  import { planReviewQuestionId, REOPEN_ID_TAIL, taskIdFromPlanReviewQuestionId } from './gateIdentity.js';
14
- import { notePlanReviewAnswered, notePlanReviewAnsweredFor, planReviewArmedKeyFor, registerArmedGateFor, waitForGateArmedFor, wasGateArmedFor, } from './armedGateRegistry.js';
16
+ import { notePlanReviewAnswered, notePlanReviewAnsweredFor, planReviewArmedKeyFor, waitForGateArmedFor, wasGateArmedFor, } from './armedGateRegistry.js';
15
17
  import { createSessionSlot, DEFAULT_SESSION_KEY } from '../sessionSlot.js';
16
18
  import { PLAN_REVIEW_GATE_KIND, durableDecideLegOf } from '../adapter/activeRunSelfHeal.js';
17
19
  import { readRunTerminal, runTerminalGateKind } from '../runTerminal.js';
@@ -144,9 +146,12 @@ function pausedGateKindOf(carrier) {
144
146
  }
145
147
  const armedPlanReviewTaskIds = new Set();
146
148
  const offerModeAfterByTask = new Map();
149
+ const offeredModeByQuestionId = new Map();
150
+ const OFFERED_MODE_LEDGER_MAX = 64;
147
151
  export function _resetArmedPlanReviewsForTest() {
148
152
  armedPlanReviewTaskIds.clear();
149
153
  offerModeAfterByTask.clear();
154
+ offeredModeByQuestionId.clear();
150
155
  planReviewDismissalsByKey.clear();
151
156
  }
152
157
  const ON_SCREEN = Promise.resolve(true);
@@ -247,12 +252,85 @@ function planReviewQuestions(question, offerModeAfter = false) {
247
252
  },
248
253
  ];
249
254
  }
255
+ function planReviewQuestionFrame(questionId, question, offerModeAfter, reopened = false) {
256
+ if (!reopened) {
257
+ offeredModeByQuestionId.delete(questionId);
258
+ offeredModeByQuestionId.set(questionId, offerModeAfter);
259
+ while (offeredModeByQuestionId.size > OFFERED_MODE_LEDGER_MAX) {
260
+ const oldest = offeredModeByQuestionId.keys().next();
261
+ if (oldest.done === true)
262
+ break;
263
+ offeredModeByQuestionId.delete(oldest.value);
264
+ }
265
+ }
266
+ return { type: 'question', questionId, questions: planReviewQuestions(question, offerModeAfter) };
267
+ }
250
268
  function publishPlanReviewCard(taskId) {
251
- publishQuestionFrame({
252
- type: 'question',
253
- questionId: planReviewQuestionId(taskId),
254
- questions: planReviewQuestions(ARM_QUESTION, offerModeAfterByTask.get(taskId) === true),
255
- });
269
+ publishQuestionFrame(planReviewQuestionFrame(planReviewQuestionId(taskId), ARM_QUESTION, offerModeAfterByTask.get(taskId) === true));
270
+ }
271
+ const OFFERED_MODE_SCAN_MAX = 32;
272
+ function ownElementsOf(v, max) {
273
+ if (!Array.isArray(v))
274
+ return [];
275
+ const n = Math.min(v.length, max);
276
+ const out = [];
277
+ for (let i = 0; i < n; i++)
278
+ out.push(readOwnDataValue(v, String(i)));
279
+ return out;
280
+ }
281
+ function offeredModeFromLabels(card) {
282
+ let modeAfter = false;
283
+ let plain = false;
284
+ for (const q of ownElementsOf(readOwnDataValue(card, 'questions'), OFFERED_MODE_SCAN_MAX)) {
285
+ if (typeof q !== 'object' || q === null)
286
+ continue;
287
+ for (const o of ownElementsOf(readOwnDataValue(q, 'options'), OFFERED_MODE_SCAN_MAX)) {
288
+ if (typeof o !== 'object' || o === null)
289
+ continue;
290
+ const label = readOwnDataNonEmptyString(o, 'label');
291
+ if (label === PLAN_REVIEW_APPROVE_AUTO_LABEL || label === PLAN_REVIEW_APPROVE_MANUAL_LABEL)
292
+ modeAfter = true;
293
+ else if (label === APPROVE_LABEL)
294
+ plain = true;
295
+ }
296
+ }
297
+ if (modeAfter && !plain)
298
+ return 'three_choice';
299
+ if (plain && !modeAfter)
300
+ return 'two_choice';
301
+ return undefined;
302
+ }
303
+ export function planReviewTaskIdFromQuestionId(questionId) {
304
+ if (typeof questionId !== 'string')
305
+ return undefined;
306
+ const taskId = taskIdFromPlanReviewQuestionId(questionId);
307
+ if (taskId === undefined)
308
+ return undefined;
309
+ return Object.freeze({ taskId, reopened: questionId.includes(REOPEN_ID_TAIL) });
310
+ }
311
+ function offeredModeFromQuestionId(questionId) {
312
+ if (taskIdFromPlanReviewQuestionId(questionId) === undefined)
313
+ return 'unknown';
314
+ const recorded = offeredModeByQuestionId.get(questionId);
315
+ if (recorded !== undefined)
316
+ return recorded ? 'three_choice' : 'two_choice';
317
+ return questionId.includes(REOPEN_ID_TAIL) ? 'two_choice' : 'unknown';
318
+ }
319
+ export function planReviewOfferedModeOf(card) {
320
+ try {
321
+ if (typeof card === 'string')
322
+ return offeredModeFromQuestionId(card);
323
+ if (typeof card !== 'object' || card === null)
324
+ return 'unknown';
325
+ const fromLabels = offeredModeFromLabels(card);
326
+ if (fromLabels !== undefined)
327
+ return fromLabels;
328
+ const questionId = readOwnDataNonEmptyString(card, 'questionId');
329
+ return questionId === undefined ? 'unknown' : offeredModeFromQuestionId(questionId);
330
+ }
331
+ catch {
332
+ return 'unknown';
333
+ }
256
334
  }
257
335
  export function armPlanReviewApproval(result, sessionKey, opts) {
258
336
  let armedTaskId;
@@ -752,13 +830,13 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
752
830
  else if (typeof status === 'number' && corruptStoredRowWhere(e) !== undefined) {
753
831
  const where = corruptStoredRowWhere(e);
754
832
  hostLog('debug', `planReviewWire: ${decision} → ${String(status)} corrupt (stored resume context unreadable)`);
755
- effect = 'not_applied';
833
+ effect = refusalDeliveryOf(e, { route: 'plan_review' }).delivery === 'refused' ? 'not_applied' : 'unconfirmed';
756
834
  outcome = `This ${decision} was not applied. ${corruptStoredRowContent(where)}`;
757
835
  }
758
836
  else if (typeof status === 'number') {
759
837
  const failureTexts = wireFailureTextsOf(e);
760
838
  hostLog('debug', `planReviewWire: ${decision} → ${status} ${failureTexts.log.slice(0, 200)}`);
761
- effect = (status >= 400 && status < 500) || (typeof refusedCode === 'string' && isUnavailableFaceCode(refusedCode)) ? 'not_applied' : 'unconfirmed';
839
+ effect = refusalDeliveryOf(e, { route: 'plan_review' }).delivery === 'refused' ? 'not_applied' : 'unconfirmed';
762
840
  outcome = `${`The plan_review decision failed: HTTP ${status} ${failureTexts.reason}`.trim()}${decideFailureNote(e)}`;
763
841
  }
764
842
  else if (noAnswer === 'time-limit' || noAnswer === 'deadline') {
@@ -828,8 +906,6 @@ export function _resetActiveReopenRespondersForTest() {
828
906
  const reopenFlights = new Map();
829
907
  function joinReopenFlight(flight, taskId, receiptMs) {
830
908
  hostLog('debug', `planReviewWire: reopen for task ${taskId} joined the card already on its way (no second card, its answer path kept)`);
831
- if (receiptMs === undefined)
832
- return { reopened: true, firstSight: false };
833
909
  const ac = new AbortController();
834
910
  return Promise.race([
835
911
  flight.presented.then((v) => v === true, () => false),
@@ -867,17 +943,13 @@ function mintPlanReviewReopen(taskId, opts, sessionKey, receiptMs) {
867
943
  settle(false);
868
944
  throw e;
869
945
  }
870
- if (verdict instanceof Promise) {
871
- return verdict.then((v) => {
872
- settle(v.reopened === true);
873
- return v;
874
- }, (e) => {
875
- settle(false);
876
- throw e;
877
- });
878
- }
879
- settle(verdict.reopened === true);
880
- return verdict;
946
+ return verdict.then((v) => {
947
+ settle(v.reopened === true);
948
+ return v;
949
+ }, (e) => {
950
+ settle(false);
951
+ throw e;
952
+ });
881
953
  }
882
954
  function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
883
955
  const markBefore = dismissalEntryFor(sessionKey, taskId);
@@ -893,30 +965,10 @@ function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
893
965
  const mintFresh = opts?.mintFreshQuestionId !== false;
894
966
  if (!mintFresh && hasLocalQuestionResponder(canonicalId)) {
895
967
  hostLog('debug', `planReviewWire: reopen for task ${taskId} reusing the canonical responder (path=reopen-canonical)`);
896
- if (opts?.deliverDecision !== undefined) {
897
- hostLog('debug', `planReviewWire: reopen canonical-reuse branch for task ${taskId} ignores opts.deliverDecision (answers route through the existing arm responder — documented exception)`);
898
- }
899
- if (opts?.wire !== undefined || opts?.onOutcome !== undefined) {
900
- hostLog('debug', `planReviewWire: reopen canonical-reuse branch for task ${taskId} ignores opts.wire / opts.onOutcome (answers route through the existing arm responder and the wire it was armed with — documented exception)`);
901
- }
902
968
  retireActiveReopen(sessionKey, canonicalId);
903
- if (receiptMs !== undefined) {
904
- const receipt = waitForGateArmedFor(sessionKey, [canonicalId], receiptMs);
905
- publishQuestionFrameFor(sessionKey, {
906
- type: 'question',
907
- questionId: canonicalId,
908
- questions: planReviewQuestions(ARM_QUESTION, offerModeAfterByTask.get(taskId) === true),
909
- });
910
- return settleOnReceipt(receipt, firstSight);
911
- }
912
- publishQuestionFrameFor(sessionKey, {
913
- type: 'question',
914
- questionId: canonicalId,
915
- questions: planReviewQuestions(ARM_QUESTION, offerModeAfterByTask.get(taskId) === true),
916
- });
917
- registerArmedGateFor(sessionKey, armedKey);
918
- revokePlanReviewUserDismissal(sessionKey, taskId, markBefore);
919
- return { reopened: true, firstSight };
969
+ const receipt = waitForGateArmedFor(sessionKey, [canonicalId], receiptMs);
970
+ publishQuestionFrameFor(sessionKey, planReviewQuestionFrame(canonicalId, ARM_QUESTION, offerModeAfterByTask.get(taskId) === true));
971
+ return settleOnReceipt(receipt, firstSight);
920
972
  }
921
973
  retireActiveReopen(sessionKey, canonicalId);
922
974
  if (unregisterLocalQuestionResponder(canonicalId)) {
@@ -961,23 +1013,9 @@ function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
961
1013
  return { ok: true };
962
1014
  });
963
1015
  activeReopenResponders.set(activeKey, { questionId, unregister });
964
- if (receiptMs !== undefined) {
965
- const receipt = waitForGateArmedFor(sessionKey, [questionId], receiptMs);
966
- publishQuestionFrameFor(sessionKey, {
967
- type: 'question',
968
- questionId,
969
- questions: planReviewQuestions(REOPEN_QUESTION),
970
- });
971
- return settleOnReceipt(receipt, firstSight);
972
- }
973
- registerArmedGateFor(sessionKey, armedKey);
974
- publishQuestionFrameFor(sessionKey, {
975
- type: 'question',
976
- questionId,
977
- questions: planReviewQuestions(REOPEN_QUESTION),
978
- });
979
- revokePlanReviewUserDismissal(sessionKey, taskId, markBefore);
980
- return { reopened: true, firstSight };
1016
+ const receipt = waitForGateArmedFor(sessionKey, [questionId], receiptMs);
1017
+ publishQuestionFrameFor(sessionKey, planReviewQuestionFrame(questionId, REOPEN_QUESTION, false, true));
1018
+ return settleOnReceipt(receipt, firstSight);
981
1019
  }
982
1020
  function noPresentationSurfaceVerdict(taskId, sessionKey) {
983
1021
  const verdict = { reopened: false, _sema_noPresentationSurface: true };
@@ -1075,44 +1113,48 @@ async function staleDismissalVerdict(current, sessionKey, taskId, receiptMs) {
1075
1113
  }
1076
1114
  export function reopenPlanReviewCard(taskId, opts) {
1077
1115
  const receiptMs = opts?.presentationReceiptMs;
1116
+ if (typeof receiptMs !== 'number' || Number.isNaN(receiptMs)) {
1117
+ hostLog('debug', `planReviewWire: reopen for task ${String(taskId)} refused — presentationReceiptMs is required (a number of milliseconds); the synchronous form was retired in 0.98.0`);
1118
+ return Promise.resolve({ reopened: false });
1119
+ }
1078
1120
  try {
1079
1121
  if (typeof taskId !== 'string' || taskId.length === 0) {
1080
- return receiptMs === undefined ? { reopened: false } : Promise.resolve({ reopened: false });
1122
+ return Promise.resolve({ reopened: false });
1123
+ }
1124
+ const injected = opts;
1125
+ if (opts?.mintFreshQuestionId === false && (injected?.deliverDecision !== undefined || injected?.wire !== undefined || injected?.onOutcome !== undefined)) {
1126
+ hostLog('error', `planReviewWire: plan_review reopen for task ${taskId} refused — mintFreshQuestionId:false reuses the armed card's responder and its delivery, ` +
1127
+ 'so deliverDecision / wire / onOutcome cannot be given with it; drop mintFreshQuestionId:false to deliver through the injected path');
1128
+ return Promise.resolve({ reopened: false });
1081
1129
  }
1082
- const readStart = typeof opts?.pendingReadStartedAt === 'number' && Number.isFinite(opts.pendingReadStartedAt) ? opts.pendingReadStartedAt : undefined;
1130
+ const readStart = typeof opts.pendingReadStartedAt === 'number' && Number.isFinite(opts.pendingReadStartedAt) ? opts.pendingReadStartedAt : undefined;
1083
1131
  if (planReviewDecisionInFlight(taskId, readStart)) {
1084
1132
  hostLog('debug', `planReviewWire: reopen for task ${taskId} refused — a decision for this task is in flight (its answer is still being delivered)`);
1085
1133
  const refused = { reopened: false, _sema_decisionInFlight: true };
1086
- return receiptMs === undefined ? refused : Promise.resolve(refused);
1134
+ return Promise.resolve(refused);
1087
1135
  }
1088
1136
  const guardStartedAt = planReviewPendingReadMark();
1089
1137
  const recheckReadStart = readStart === undefined ? guardStartedAt : Math.min(readStart, guardStartedAt);
1090
- const sessionKey = opts?.sessionKey ?? DEFAULT_SESSION_KEY;
1138
+ const sessionKey = opts.sessionKey ?? DEFAULT_SESSION_KEY;
1091
1139
  if (!hasQuestionOverlayFor(sessionKey)) {
1092
- const noSurface = noPresentationSurfaceVerdict(taskId, sessionKey);
1093
- return receiptMs === undefined ? noSurface : Promise.resolve(noSurface);
1140
+ return Promise.resolve(noPresentationSurfaceVerdict(taskId, sessionKey));
1094
1141
  }
1095
- if (sessionKey !== DEFAULT_SESSION_KEY && opts?.deliverDecision === undefined && opts?.wire === undefined) {
1142
+ if (sessionKey !== DEFAULT_SESSION_KEY && opts.deliverDecision === undefined && opts.wire === undefined) {
1096
1143
  hostLog('error', `planReviewWire: plan_review 卡未重开 —— sessionKey=${JSON.stringify(sessionKey)} 是非默认槽,` +
1097
1144
  '而缺省决断投递口(decidePlanReview)今天固定打默认槽的 baseUrl/token/principal。' +
1098
1145
  '整条链转 keyed 之前,非默认槽要重开请自带 deliverDecision(按本槽投递);' +
1099
1146
  '此处拒绝而不是照发 —— 照发会把这条会话的决断发到另一个槽上。');
1100
- return receiptMs === undefined ? { reopened: false } : Promise.resolve({ reopened: false });
1147
+ return Promise.resolve({ reopened: false });
1101
1148
  }
1102
- const trigger = opts?.trigger === undefined ? undefined : opts.trigger === 'user' ? 'user' : 'automatic';
1149
+ const trigger = opts.trigger === undefined ? undefined : opts.trigger === 'user' ? 'user' : 'automatic';
1103
1150
  if (trigger === 'automatic') {
1104
1151
  const mark = planReviewUserDismissalMarkFor(sessionKey, taskId);
1105
- if (mark !== undefined) {
1106
- if (receiptMs === undefined || opts === undefined) {
1107
- hostLog('debug', `planReviewWire: automatic reopen for task ${taskId} refused — the user closed this gate's card`);
1108
- return { reopened: false, dismissedByUser: true };
1109
- }
1152
+ if (mark !== undefined)
1110
1153
  return reopenAfterDismissalCheck(taskId, opts, sessionKey, receiptMs, mark, recheckReadStart);
1111
- }
1112
1154
  }
1113
1155
  return mintPlanReviewReopen(taskId, opts, sessionKey, receiptMs);
1114
1156
  }
1115
1157
  catch {
1116
- return receiptMs === undefined ? { reopened: false } : Promise.resolve({ reopened: false });
1158
+ return Promise.resolve({ reopened: false });
1117
1159
  }
1118
1160
  }
@@ -1,4 +1,3 @@
1
1
  export declare const PREFIXES_IN_PROSE: string;
2
2
  export declare const REFUSED_NAME_CLASSES: string;
3
3
  export declare const REFUSED_NAME_FIX: string;
4
- export declare const RULES_LEGACY_TOOL_NAME_WRITE_NOTE: string;
@@ -2,6 +2,3 @@ import { CORE_PROTOCOL_PREFIXES } from '../generated/toolNameTables.js';
2
2
  export const PREFIXES_IN_PROSE = CORE_PROTOCOL_PREFIXES.map((prefix) => `"${prefix}"`).join(' or ');
3
3
  export const REFUSED_NAME_CLASSES = `a retired tool name, or a name that contains "__" but does not start with ${PREFIXES_IN_PROSE}`;
4
4
  export const REFUSED_NAME_FIX = `If the tool still exists, use its current name; a server or agent-peer tool name starts with ${PREFIXES_IN_PROSE}.`;
5
- export const RULES_LEGACY_TOOL_NAME_WRITE_NOTE = `The engine refused to write these session rules, and the stored record was not changed at all: they name a tool the engine refuses — ${REFUSED_NAME_CLASSES} (the engine's own error text names the entry). ` +
6
- `${REFUSED_NAME_FIX} Then write the rules again. ` +
7
- 'If that entry was already in this session’s rule record, it has to be removed from the record before the record can be written again.';
@@ -1,13 +1,14 @@
1
1
  import { type ApprovalSettledHow } from './approvalHolds.js';
2
- import { type ApprovalsListEnvelope, type CrashConvergedRow } from './crashConverged.js';
2
+ import { type ApprovalsListEnvelope, type CrashConvergedRowReading } from './crashConverged.js';
3
3
  export type ReplayedApprovalDisposition = {
4
4
  readonly kind: 'live';
5
5
  readonly basis: 'live_leg' | 'preamble' | 'pending_list';
6
6
  } | {
7
7
  readonly kind: 'decided';
8
- readonly cause?: CrashConvergedRow['cause'];
9
- readonly needsHumanReason?: NonNullable<CrashConvergedRow['needsHumanReason']>;
8
+ readonly cause?: CrashConvergedRowReading['cause'];
9
+ readonly needsHumanReason?: NonNullable<CrashConvergedRowReading['needsHumanReason']>;
10
10
  readonly settled?: ApprovalSettledHow;
11
+ readonly parked?: true;
11
12
  } | {
12
13
  readonly kind: 'unknown';
13
14
  readonly why: 'unreadable_frame' | 'no_approval_id' | 'not_read' | 'list_unreadable' | 'list_not_reported' | 'list_incomplete';
@@ -1,5 +1,5 @@
1
1
  import { hasLedgerPositionKey } from './gateLedger.js';
2
- import { anyApprovalSettled, settledApprovalOf } from './approvalHolds.js';
2
+ import { anyApprovalSettled, APPROVAL_SETTLED_HOWS, settledApprovalOf } from './approvalHolds.js';
3
3
  import { readLivePendingRows } from './livePendingAsk.js';
4
4
  import { projectCrashConverged } from './crashConverged.js';
5
5
  import { quoteUntrustedForSentence } from '../displayUntrusted.js';
@@ -9,7 +9,7 @@ const unknown = (why) => Object.freeze({ kind: 'unknown', why });
9
9
  const decided = (row) => Object.freeze(row === undefined
10
10
  ? { kind: 'decided' }
11
11
  : { kind: 'decided', cause: row.cause, ...(row.needsHumanReason !== undefined ? { needsHumanReason: row.needsHumanReason } : {}) });
12
- const decidedSettled = (how) => Object.freeze({ kind: 'decided', settled: how });
12
+ const decidedSettled = (how, parked) => Object.freeze(parked && how === 'closed_by_engine' ? { kind: 'decided', settled: how, parked: true } : { kind: 'decided', settled: how });
13
13
  function approvalIdOf(frame) {
14
14
  const v = frame.approvalId;
15
15
  return typeof v === 'string' && v !== '' ? v : undefined;
@@ -29,7 +29,7 @@ export function settledApprovalDisposition(frame) {
29
29
  if (!anyApprovalSettled())
30
30
  return undefined;
31
31
  const entry = settledApprovalOf(approvalIdOf(frame));
32
- return entry === undefined ? undefined : decidedSettled(entry.how);
32
+ return entry === undefined ? undefined : decidedSettled(entry.how, entry.parked);
33
33
  }
34
34
  catch {
35
35
  return undefined;
@@ -161,7 +161,10 @@ export function replayedApprovalClosesCardFrame(disposition) {
161
161
  if (readOwnDataValue(disposition, 'kind') !== 'decided')
162
162
  return false;
163
163
  const cause = readOwnDataValue(disposition, 'cause');
164
- return typeof cause === 'string' && Object.hasOwn(STOPPED_BY_CAUSE, cause);
164
+ if (typeof cause === 'string' && Object.hasOwn(STOPPED_BY_CAUSE, cause))
165
+ return true;
166
+ const settled = readOwnDataValue(disposition, 'settled');
167
+ return typeof settled === 'string' && APPROVAL_SETTLED_HOWS.includes(settled) && !('parked' in disposition);
165
168
  }
166
169
  catch {
167
170
  return false;
@@ -1,11 +1,13 @@
1
1
  import type { SessionPermissionRules } from '@sema-agent/sdk';
2
2
  import type { ToolRosterView } from '../toolRoster.js';
3
+ import type { SessionRuleInertReason } from './sessionPolicyWire.js';
3
4
  export type SessionPolicyWithheldWhy = 'ask_no_bucket' | 'qualified_deny' | 'peer_wide' | 'wildcard' | 'not_a_tool_name' | 'legacy_tool_name' | 'not_in_roster';
4
5
  export declare const SESSION_POLICY_WITHHELD_WHY: readonly SessionPolicyWithheldWhy[];
5
6
  export interface SessionPolicyWithheldRule {
6
7
  readonly rule: string;
7
8
  readonly why: SessionPolicyWithheldWhy;
8
9
  readonly currentName?: string;
10
+ readonly inertReason?: SessionRuleInertReason;
9
11
  }
10
12
  export interface SessionPolicyDeliverability {
11
13
  readonly deliverable: SessionPermissionRules;