@sema-agent/client-core 0.97.1 → 0.98.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 (281) hide show
  1. package/CHANGELOG.md +408 -0
  2. package/README.md +74 -37
  3. package/dist/adapt/arms.d.ts +1 -0
  4. package/dist/adapt/arms.js +128 -34
  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/textStream.d.ts +1 -0
  10. package/dist/adapt/textStream.js +24 -7
  11. package/dist/adapt/toolCards.d.ts +27 -5
  12. package/dist/adapt/toolCards.js +39 -6
  13. package/dist/adapt/wireShapes.js +6 -2
  14. package/dist/adapt.d.ts +2 -0
  15. package/dist/adapt.js +8 -3
  16. package/dist/adapter/activeRunSelfHeal.d.ts +5 -0
  17. package/dist/adapter/activeRunSelfHeal.js +51 -28
  18. package/dist/adapter/downstream/eventToSdkMessage.d.ts +2 -5
  19. package/dist/adapter/downstream/eventToSdkMessage.js +27 -34
  20. package/dist/adapter/downstream/terminalToSdkResult.js +11 -4
  21. package/dist/adapter/downstream/turnUsageToModelUsage.d.ts +5 -2
  22. package/dist/adapter/downstream/turnUsageToModelUsage.js +2 -0
  23. package/dist/adapter/runStream.js +29 -13
  24. package/dist/adapter/types.d.ts +4 -4
  25. package/dist/agentSession/backgroundView.js +2 -1
  26. package/dist/agentSession/engineAgentRegistryRead.d.ts +2 -2
  27. package/dist/agentSession/engineAgentRegistryRead.js +12 -13
  28. package/dist/agentsWireCaps.d.ts +8 -8
  29. package/dist/agentsWireCaps.js +168 -175
  30. package/dist/approvalDecidedByCapability.d.ts +0 -4
  31. package/dist/approvalDecidedByCapability.js +0 -6
  32. package/dist/approvalsStreamLiveCapability.d.ts +0 -4
  33. package/dist/approvalsStreamLiveCapability.js +0 -6
  34. package/dist/assistantInbox.d.ts +34 -0
  35. package/dist/assistantInbox.js +118 -0
  36. package/dist/centerWiringCapability.js +9 -1
  37. package/dist/clientSlice.d.ts +0 -9
  38. package/dist/clientSlice.js +0 -3
  39. package/dist/cloudConfigWireCaps.d.ts +4 -2
  40. package/dist/cloudConfigWireCaps.js +81 -61
  41. package/dist/compensations.js +1 -1
  42. package/dist/connectorStatus.d.ts +21 -0
  43. package/dist/connectorStatus.js +112 -0
  44. package/dist/controlRouter.d.ts +14 -1
  45. package/dist/controlRouter.js +68 -17
  46. package/dist/coreValuePorts.d.ts +3 -3
  47. package/dist/decideReceipt.d.ts +2 -2
  48. package/dist/decideReceipt.js +5 -2
  49. package/dist/declared/supportFloorDeclared.js +3 -3
  50. package/dist/deviceExecutorManagementCapability.d.ts +0 -4
  51. package/dist/deviceExecutorManagementCapability.js +0 -6
  52. package/dist/deviceRebind.d.ts +49 -1
  53. package/dist/deviceRebind.js +221 -3
  54. package/dist/displayUntrusted.d.ts +1 -0
  55. package/dist/displayUntrusted.js +250 -76
  56. package/dist/engineAgentAbsence.d.ts +1 -1
  57. package/dist/engineAgentPanelStore.d.ts +5 -4
  58. package/dist/engineAgentPanelStore.js +3 -12
  59. package/dist/engineCapReader.d.ts +0 -4
  60. package/dist/engineCapReader.js +1 -5
  61. package/dist/engineCapsCache.d.ts +4 -0
  62. package/dist/engineCapsCache.js +17 -12
  63. package/dist/engineClosedSets.d.ts +1 -0
  64. package/dist/engineClosedSets.js +4 -1
  65. package/dist/engineErrorCodes.d.ts +9 -2
  66. package/dist/engineErrorCodes.js +9 -1
  67. package/dist/engineIdentity.d.ts +1 -0
  68. package/dist/engineIdentity.js +8 -0
  69. package/dist/engineRowRef.d.ts +28 -0
  70. package/dist/engineRowRef.js +111 -0
  71. package/dist/engineSessionMessages.d.ts +67 -0
  72. package/dist/engineSessionMessages.js +364 -0
  73. package/dist/engineToolDirectory.d.ts +0 -9
  74. package/dist/engineToolDirectory.js +1 -94
  75. package/dist/engineUrl.d.ts +18 -0
  76. package/dist/engineUrl.js +52 -0
  77. package/dist/env/uiLanguage.d.ts +9 -0
  78. package/dist/env/uiLanguage.js +35 -0
  79. package/dist/eventLeg.d.ts +92 -0
  80. package/dist/eventLeg.js +285 -0
  81. package/dist/executionLaneCapability.d.ts +0 -4
  82. package/dist/executionLaneCapability.js +3 -16
  83. package/dist/fileHistoryCaptureCapability.d.ts +0 -4
  84. package/dist/fileHistoryCaptureCapability.js +5 -7
  85. package/dist/fleet/fleetLedger.d.ts +0 -3
  86. package/dist/fleet/fleetLedger.js +21 -36
  87. package/dist/fleet/fleetProjection.d.ts +2 -2
  88. package/dist/fleet/fleetProjection.js +10 -8
  89. package/dist/frameBinding.d.ts +5 -0
  90. package/dist/frameBinding.js +23 -0
  91. package/dist/gateFailureCodes.d.ts +2 -0
  92. package/dist/gateFailureCodes.js +15 -0
  93. package/dist/gateOutcome.d.ts +3 -1
  94. package/dist/gateOutcome.js +25 -6
  95. package/dist/gateVocabulary.d.ts +5 -0
  96. package/dist/gateVocabulary.js +64 -2
  97. package/dist/generated/engineAskFaceTables.js +2 -2
  98. package/dist/generated/engineFactTables.d.ts +6 -3
  99. package/dist/generated/engineFactTables.js +22 -4
  100. package/dist/generated/engineNoticeTables.js +9 -0
  101. package/dist/generated/toolNameTables.d.ts +1 -0
  102. package/dist/generated/toolNameTables.js +1 -0
  103. package/dist/hitl/allowRuleShadow.d.ts +6 -1
  104. package/dist/hitl/allowRuleShadow.js +21 -17
  105. package/dist/hitl/approvalCardReading.d.ts +15 -0
  106. package/dist/hitl/approvalCardReading.js +154 -0
  107. package/dist/hitl/approvalCardReasons.d.ts +13 -0
  108. package/dist/hitl/approvalCardReasons.js +120 -0
  109. package/dist/hitl/approvalHolds.d.ts +47 -15
  110. package/dist/hitl/approvalHolds.js +134 -28
  111. package/dist/hitl/approvalResolution.d.ts +51 -26
  112. package/dist/hitl/approvalResolution.js +86 -122
  113. package/dist/hitl/approvalsFeed.js +6 -18
  114. package/dist/hitl/askClassPair.d.ts +2 -0
  115. package/dist/hitl/askClassPair.js +1 -0
  116. package/dist/hitl/askGateWire.d.ts +20 -2
  117. package/dist/hitl/askGateWire.js +49 -1
  118. package/dist/hitl/askParkRowRouting.d.ts +5 -0
  119. package/dist/hitl/askParkRowRouting.js +32 -1
  120. package/dist/hitl/askSettlementLine.d.ts +18 -0
  121. package/dist/hitl/askSettlementLine.js +79 -0
  122. package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
  123. package/dist/hitl/automaticAnswerVerdict.js +21 -5
  124. package/dist/hitl/crashConverged.d.ts +11 -20
  125. package/dist/hitl/crashConverged.js +56 -0
  126. package/dist/hitl/crashConvergedNotice.d.ts +3 -1
  127. package/dist/hitl/crashConvergedNotice.js +48 -11
  128. package/dist/hitl/decisionConflict.js +3 -10
  129. package/dist/hitl/decisionRefusal.d.ts +40 -1
  130. package/dist/hitl/decisionRefusal.js +199 -42
  131. package/dist/hitl/frameRouter.d.ts +5 -2
  132. package/dist/hitl/frameRouter.js +20 -16
  133. package/dist/hitl/gateLedger.d.ts +2 -0
  134. package/dist/hitl/gateLedger.js +50 -13
  135. package/dist/hitl/hitlBridge.d.ts +1 -2
  136. package/dist/hitl/hitlBridge.js +10 -7
  137. package/dist/hitl/livePendingAsk.d.ts +3 -3
  138. package/dist/hitl/livePendingAsk.js +7 -18
  139. package/dist/hitl/parkResolver.d.ts +2 -24
  140. package/dist/hitl/parkResolver.js +61 -97
  141. package/dist/hitl/persistedRulesWire.d.ts +24 -0
  142. package/dist/hitl/persistedRulesWire.js +122 -2
  143. package/dist/hitl/planReviewWire.d.ts +26 -13
  144. package/dist/hitl/planReviewWire.js +112 -78
  145. package/dist/hitl/refusedToolNameProse.d.ts +0 -1
  146. package/dist/hitl/refusedToolNameProse.js +0 -3
  147. package/dist/hitl/replayedApproval.d.ts +4 -3
  148. package/dist/hitl/replayedApproval.js +7 -4
  149. package/dist/hitl/sessionPolicyDeliverable.js +2 -4
  150. package/dist/hitl/sessionPolicyWire.d.ts +32 -20
  151. package/dist/hitl/sessionPolicyWire.js +162 -52
  152. package/dist/hitl/standingRows.d.ts +20 -2
  153. package/dist/hitl/standingRows.js +69 -8
  154. package/dist/hitl/toolApprovalWire.d.ts +87 -152
  155. package/dist/hitl/toolApprovalWire.js +591 -380
  156. package/dist/hookMatcherVerdict.d.ts +6 -1
  157. package/dist/hookMatcherVerdict.js +14 -7
  158. package/dist/hooksWireCaps.d.ts +2 -2
  159. package/dist/hooksWireCaps.js +59 -55
  160. package/dist/i18n/messages.en.d.ts +121 -0
  161. package/dist/i18n/messages.en.js +119 -0
  162. package/dist/i18n/messages.zh.d.ts +3 -0
  163. package/dist/i18n/messages.zh.js +120 -0
  164. package/dist/i18n/translate.d.ts +25 -0
  165. package/dist/i18n/translate.js +127 -0
  166. package/dist/index.d.ts +53 -20
  167. package/dist/index.js +38 -11
  168. package/dist/inheritEnvCapability.d.ts +31 -0
  169. package/dist/inheritEnvCapability.js +104 -0
  170. package/dist/liveModelCatalog.d.ts +1 -2
  171. package/dist/liveModelCatalog.js +2 -6
  172. package/dist/liveQuestionStore.d.ts +2 -21
  173. package/dist/mcpLiveness.d.ts +2 -1
  174. package/dist/mcpProbeWire.d.ts +6 -1
  175. package/dist/mcpProbeWire.js +1 -1
  176. package/dist/mcpWireCaps.d.ts +13 -2
  177. package/dist/mcpWireCaps.js +48 -0
  178. package/dist/memoryEntriesWire.d.ts +4 -9
  179. package/dist/model/modelSupplyRules.d.ts +0 -2
  180. package/dist/model/modelSupplyRules.js +3 -12
  181. package/dist/model/modelsPolicy.d.ts +0 -5
  182. package/dist/model/modelsPolicy.js +6 -36
  183. package/dist/model/subagentModelWord.d.ts +31 -0
  184. package/dist/model/subagentModelWord.js +261 -0
  185. package/dist/notifications.d.ts +6 -0
  186. package/dist/notifications.js +71 -23
  187. package/dist/outputStyleSeatCapability.d.ts +0 -3
  188. package/dist/outputStyleSeatCapability.js +0 -3
  189. package/dist/ownKey.d.ts +15 -0
  190. package/dist/ownKey.js +60 -3
  191. package/dist/panelReduce.d.ts +15 -9
  192. package/dist/panelReduce.js +680 -549
  193. package/dist/panelStateHolder.d.ts +3 -7
  194. package/dist/panelStateHolder.js +14 -130
  195. package/dist/peerLaneCapability.d.ts +0 -4
  196. package/dist/peerLaneCapability.js +0 -6
  197. package/dist/permissionRulesWriteCapability.d.ts +0 -4
  198. package/dist/permissionRulesWriteCapability.js +0 -6
  199. package/dist/permissionWireCaps.d.ts +2 -2
  200. package/dist/permissionWireCaps.js +2 -0
  201. package/dist/permissionsAllowGrantCapability.d.ts +0 -4
  202. package/dist/permissionsAllowGrantCapability.js +0 -6
  203. package/dist/permissionsDeclaration.d.ts +0 -11
  204. package/dist/permissionsDeclaration.js +60 -53
  205. package/dist/pluginHooksWire.d.ts +1 -1
  206. package/dist/pluginHooksWire.js +3 -6
  207. package/dist/preemptWire.d.ts +44 -0
  208. package/dist/preemptWire.js +83 -0
  209. package/dist/printToolResultFrame.js +15 -4
  210. package/dist/replayBody.d.ts +3 -0
  211. package/dist/replayBody.js +14 -0
  212. package/dist/request/taskRequest.d.ts +0 -1
  213. package/dist/request/taskRequest.js +0 -3
  214. package/dist/resumeRefusalCopy.d.ts +2 -1
  215. package/dist/resumeRefusalCopy.js +38 -2
  216. package/dist/retryStatus.d.ts +8 -0
  217. package/dist/retryStatus.js +106 -1
  218. package/dist/rewindArchiveCapability.d.ts +0 -4
  219. package/dist/rewindArchiveCapability.js +2 -10
  220. package/dist/rewindArchiveReading.d.ts +0 -1
  221. package/dist/rewindArchiveReading.js +0 -3
  222. package/dist/runCancelContext.d.ts +2 -1
  223. package/dist/runCancelContext.js +4 -2
  224. package/dist/runReattachPolicy.d.ts +31 -0
  225. package/dist/runReattachPolicy.js +46 -0
  226. package/dist/runTerminal.d.ts +3 -6
  227. package/dist/runTerminal.js +8 -9
  228. package/dist/sandboxWire.d.ts +3 -1
  229. package/dist/sandboxWire.js +76 -27
  230. package/dist/scenarioWire.js +1 -1
  231. package/dist/seam.d.ts +24 -2
  232. package/dist/seam.js +15 -3
  233. package/dist/seatContract.d.ts +53 -10
  234. package/dist/seatContract.js +132 -81
  235. package/dist/sessionPolicyCapability.d.ts +0 -4
  236. package/dist/sessionPolicyCapability.js +0 -6
  237. package/dist/sessionSyncFileHistoryCapability.d.ts +0 -3
  238. package/dist/sessionSyncFileHistoryCapability.js +0 -3
  239. package/dist/skillToolListsCapability.d.ts +0 -3
  240. package/dist/skillToolListsCapability.js +0 -3
  241. package/dist/sqlEngineCapability.d.ts +0 -4
  242. package/dist/sqlEngineCapability.js +0 -6
  243. package/dist/steerPriorityCapability.d.ts +0 -3
  244. package/dist/steerPriorityCapability.js +0 -3
  245. package/dist/streamDrainingLegs.d.ts +4 -0
  246. package/dist/streamDrainingLegs.js +6 -1
  247. package/dist/subagent/engineCompactWire.d.ts +0 -1
  248. package/dist/subagent/engineCompactWire.js +7 -5
  249. package/dist/subagent/engineTaskHandleWire.js +4 -7
  250. package/dist/subagentContentStore.js +1 -11
  251. package/dist/submitReopen.d.ts +24 -0
  252. package/dist/submitReopen.js +75 -0
  253. package/dist/terminalStatuses.d.ts +3 -0
  254. package/dist/terminalStatuses.js +10 -2
  255. package/dist/toolResult.d.ts +10 -1
  256. package/dist/toolResult.js +34 -6
  257. package/dist/toolRoster.d.ts +0 -2
  258. package/dist/toolRoster.js +0 -2
  259. package/dist/turnFailurePresentation.d.ts +28 -0
  260. package/dist/turnFailurePresentation.js +205 -0
  261. package/dist/userInvokedSkillsCapability.d.ts +0 -3
  262. package/dist/userInvokedSkillsCapability.js +0 -3
  263. package/dist/webSearchBackendCapability.d.ts +0 -4
  264. package/dist/webSearchBackendCapability.js +0 -6
  265. package/dist/wireErrorTriage.js +5 -24
  266. package/dist/wireFailureShape.d.ts +62 -5
  267. package/dist/wireFailureShape.js +105 -5
  268. package/dist/wireRefusalCopy.d.ts +12 -2
  269. package/dist/wireRefusalCopy.js +50 -52
  270. package/dist/workflowsJournalCapability.d.ts +0 -4
  271. package/dist/workflowsJournalCapability.js +0 -6
  272. package/dist/writeProtectionCapability.d.ts +0 -4
  273. package/dist/writeProtectionCapability.js +0 -6
  274. package/docs/INTEGRATION-CLIENTS.md +1253 -46
  275. package/package.json +5 -4
  276. package/dist/attachmentSeatCapability.d.ts +0 -12
  277. package/dist/attachmentSeatCapability.js +0 -23
  278. package/dist/hitl/approvalOutcomeNote.d.ts +0 -10
  279. package/dist/hitl/approvalOutcomeNote.js +0 -29
  280. package/dist/sessionReadRedactionCapability.d.ts +0 -13
  281. package/dist/sessionReadRedactionCapability.js +0 -35
@@ -1,10 +1,12 @@
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 { guardedRead, readOwnDataValue } from '../ownKey.js';
6
8
  import { observedPermissionRulesWrite, permissionRulesWriteAvailable } from '../permissionRulesWriteCapability.js';
7
- import { readToolApprovalRespondAck } from './toolApprovalWire.js';
9
+ import { isToolApprovalRespondReplayed, readToolApprovalRespondAck } from './toolApprovalWire.js';
8
10
  export function persistedRulesLaneAvailable(baseUrl) {
9
11
  return engineCapTrue(baseUrl, 'permissionRules');
10
12
  }
@@ -112,6 +114,124 @@ export const PERSISTED_RULE_BEHAVIOR_UNKNOWN = '(unknown)';
112
114
  export function persistedRuleBehaviorLabel(rule) {
113
115
  return rowStr(rule, 'behavior') ?? PERSISTED_RULE_BEHAVIOR_UNKNOWN;
114
116
  }
117
+ const PERSISTED_RULE_ORIGIN_PHRASES = Object.freeze({
118
+ user: 'added by you',
119
+ 'imported-cc': 'imported',
120
+ starter: 'preset',
121
+ });
122
+ const UNKNOWN_ORIGIN_PHRASE = 'an origin this build does not know';
123
+ const NO_ORIGIN_PHRASE = 'unknown origin';
124
+ function ownSlot(o, key) {
125
+ if (typeof o !== 'object' || o === null)
126
+ return undefined;
127
+ return guardedRead(() => readOwnDataValue(o, key));
128
+ }
129
+ const ORIGINS_READ_MAX = 256;
130
+ export function persistedRuleAddOriginLabel(origin) {
131
+ return typeof origin === 'string' && Object.hasOwn(PERSISTED_RULE_ORIGIN_PHRASES, origin)
132
+ ? PERSISTED_RULE_ORIGIN_PHRASES[origin]
133
+ : UNKNOWN_ORIGIN_PHRASE;
134
+ }
135
+ export function persistedRuleOriginsLabel(rule) {
136
+ const adds = ownSlot(rule, 'adds');
137
+ const isArr = guardedRead(() => (Array.isArray(adds) ? true : undefined));
138
+ if (isArr !== true)
139
+ return NO_ORIGIN_PHRASE;
140
+ const lenRaw = ownSlot(adds, 'length');
141
+ const len = typeof lenRaw === 'number' && Number.isSafeInteger(lenRaw) && lenRaw > 0 ? Math.min(lenRaw, ORIGINS_READ_MAX) : 0;
142
+ const seen = [];
143
+ for (let i = 0; i < len; i++) {
144
+ const origin = ownSlot(ownSlot(adds, String(i)), 'origin');
145
+ const phrase = persistedRuleAddOriginLabel(typeof origin === 'string' ? origin : undefined);
146
+ if (!seen.includes(phrase))
147
+ seen.push(phrase);
148
+ }
149
+ return seen.length === 0 ? NO_ORIGIN_PHRASE : seen.join(' + ');
150
+ }
151
+ const UNKNOWN_SCOPE_PHRASE = 'a scope this build does not know';
152
+ export function persistedRuleScopeLabel(scope) {
153
+ if (scope === 'global')
154
+ return 'all projects';
155
+ if (typeof scope === 'string' && scope.startsWith('project:') && scope.length > 'project:'.length) {
156
+ const shown = displayUntrusted(scope.slice('project:'.length), { max: 400, blanks: true });
157
+ return shown === '' ? UNKNOWN_SCOPE_PHRASE : shown;
158
+ }
159
+ return UNKNOWN_SCOPE_PHRASE;
160
+ }
161
+ const PERSISTED_RULE_REVOKE_LINES = Object.freeze({
162
+ removed: {
163
+ yes: {
164
+ notice: '{rule}: a tombstone was written, but the rule is still live — it was approved again during the call.',
165
+ change: 'Revoked saved rule {rule} (still live — approved again meanwhile)',
166
+ },
167
+ unknown: {
168
+ notice: '{rule}: a tombstone was written, but whether the rule is still live could not be confirmed — treat it as still in effect and check the list.',
169
+ change: 'Revoked saved rule {rule} (liveness could not be confirmed — treated as still in effect)',
170
+ },
171
+ no: { notice: 'Removed {rule}.', change: 'Revoked saved rule {rule}' },
172
+ },
173
+ 'nothing-written': {
174
+ yes: {
175
+ notice: '{rule}: nothing was written, and the rule is still live — it was not removed; check the list.',
176
+ change: 'Removing saved rule {rule} wrote nothing — the rule is still live',
177
+ },
178
+ unknown: {
179
+ notice: '{rule}: nothing was written, and whether the rule is still live could not be confirmed — treat it as still in effect and check the list.',
180
+ change: 'Removing saved rule {rule} wrote nothing — liveness could not be confirmed',
181
+ },
182
+ no: { notice: '{rule}: nothing to remove.', change: 'Removing saved rule {rule} wrote nothing (nothing to remove)' },
183
+ },
184
+ });
185
+ const REVOKE_UNKNOWN_STATUS = Object.freeze({
186
+ absent: {
187
+ notice: '{rule}: the engine did not say what this removal did, so whether anything was removed is unclear — check the list.',
188
+ change: 'Removing saved rule {rule} came back without saying what it did',
189
+ },
190
+ unrecognised: {
191
+ notice: '{rule}: the engine answered with a status this build does not know, so whether anything was removed is unclear — check the list.',
192
+ change: 'Removing saved rule {rule} returned a status this build does not know',
193
+ },
194
+ liveness: { yes: ' It also reports the rule is still live.', unknown: ' Whether the rule is still live could not be confirmed either.', no: '' },
195
+ });
196
+ const fillRule = (template, rule) => template.split('{rule}').join(rule);
197
+ export function persistedRuleRevokeOutcome(ruleText, result) {
198
+ const quoted = typeof ruleText === 'string' ? quoteUntrustedForSentence(ruleText, 120) : undefined;
199
+ const rule = quoted ?? 'this rule';
200
+ const status = ownSlot(result, 'status');
201
+ const rawLive = ownSlot(result, 'stillLive');
202
+ const liveness = rawLive === 'yes' || rawLive === 'no' || rawLive === 'unknown' ? rawLive : 'unknown';
203
+ if (status === 'removed' || status === 'no-op') {
204
+ const outcome = status === 'removed' ? 'removed' : 'nothing-written';
205
+ const line = PERSISTED_RULE_REVOKE_LINES[outcome][liveness];
206
+ return Object.freeze({ outcome, liveness, notice: fillRule(line.notice, rule), change: fillRule(line.change, rule) });
207
+ }
208
+ const head = typeof status === 'string' && status !== '' ? REVOKE_UNKNOWN_STATUS.unrecognised : REVOKE_UNKNOWN_STATUS.absent;
209
+ return Object.freeze({
210
+ outcome: 'unknown-status',
211
+ liveness,
212
+ notice: `${fillRule(head.notice, rule)}${REVOKE_UNKNOWN_STATUS.liveness[liveness]}`,
213
+ change: fillRule(head.change, rule),
214
+ });
215
+ }
216
+ const PERSISTED_RULE_MATCH_LABELS = Object.freeze({
217
+ exact: 'exact match',
218
+ prefix: 'prefix match',
219
+ wildcard: 'wildcard match',
220
+ subpath: 'subpath match',
221
+ path: 'path match',
222
+ name: 'skill name match',
223
+ name_prefix: 'skill name prefix match',
224
+ host: 'web domain match (one host)',
225
+ subdomain: 'web domain match (every host under the domain)',
226
+ });
227
+ export function persistedRuleMatchLabel(ruleOrMatch) {
228
+ const word = typeof ruleOrMatch === 'string' ? ruleOrMatch : ownSlot(ruleOrMatch, 'match');
229
+ if (typeof word !== 'string' || word === '')
230
+ return 'an unreported match form';
231
+ return Object.hasOwn(PERSISTED_RULE_MATCH_LABELS, word)
232
+ ? PERSISTED_RULE_MATCH_LABELS[word]
233
+ : 'a match form this build does not know';
234
+ }
115
235
  export function revokeTargetFromPersistedRule(rule, opts) {
116
236
  const behavior = persistedRuleBehaviorOf(rule);
117
237
  if (behavior === undefined)
@@ -434,7 +554,7 @@ export function classifySkippedReason(reason) {
434
554
  }
435
555
  export function readRulePersistOutcome(ack) {
436
556
  const parsed = readToolApprovalRespondAck(ack);
437
- if (parsed === undefined)
557
+ if (parsed === undefined || isToolApprovalRespondReplayed(parsed))
438
558
  return { state: 'unknown' };
439
559
  if (parsed.rulePersisted === true)
440
560
  return { state: 'persisted' };
@@ -28,6 +28,16 @@ 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 declare function planReviewOfferedModeOf(card: string | PlanReviewCardLike): PlanReviewOfferedMode;
31
41
  export interface ArmPlanReviewOptions {
32
42
  submittedInPlanMode?: boolean;
33
43
  readGateInstanceKeys?: PlanReviewGateInstanceReader;
@@ -76,22 +86,25 @@ export declare function notePlanReviewGateLeft(taskId: string): void;
76
86
  export declare function latestPlanReviewDecisionMark(taskId: string): number | null;
77
87
  export declare function __resetPlanReviewDecisionLatchForTests(): void;
78
88
  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>;
89
+ export interface ReopenPlanReviewSharedOpts {
82
90
  sessionKey?: string;
83
- wire?: PlanReviewWire;
84
- onOutcome?: PlanReviewDeliveryOptions['onOutcome'];
85
- presentationReceiptMs?: number;
91
+ presentationReceiptMs: number;
86
92
  trigger?: PlanReviewReopenTrigger;
87
93
  readGateInstanceKeys?: PlanReviewGateInstanceReader;
88
94
  pendingReadStartedAt?: number;
89
95
  }
96
+ export interface ReopenPlanReviewFreshOpts extends ReopenPlanReviewSharedOpts {
97
+ mintFreshQuestionId?: true;
98
+ deliverDecision?: (taskId: string, decision: 'approve' | 'reject', reason?: string) => void | Promise<void>;
99
+ wire?: PlanReviewWire;
100
+ onOutcome?: PlanReviewDeliveryOptions['onOutcome'];
101
+ }
102
+ export interface ReopenPlanReviewReuseOpts extends ReopenPlanReviewSharedOpts {
103
+ mintFreshQuestionId: false;
104
+ deliverDecision?: never;
105
+ wire?: never;
106
+ onOutcome?: never;
107
+ }
108
+ export type ReopenPlanReviewOpts = ReopenPlanReviewFreshOpts | ReopenPlanReviewReuseOpts;
90
109
  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>;
110
+ 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,77 @@ 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
+ function offeredModeFromQuestionId(questionId) {
304
+ if (taskIdFromPlanReviewQuestionId(questionId) === undefined)
305
+ return 'unknown';
306
+ const recorded = offeredModeByQuestionId.get(questionId);
307
+ if (recorded !== undefined)
308
+ return recorded ? 'three_choice' : 'two_choice';
309
+ return questionId.includes(REOPEN_ID_TAIL) ? 'two_choice' : 'unknown';
310
+ }
311
+ export function planReviewOfferedModeOf(card) {
312
+ try {
313
+ if (typeof card === 'string')
314
+ return offeredModeFromQuestionId(card);
315
+ if (typeof card !== 'object' || card === null)
316
+ return 'unknown';
317
+ const fromLabels = offeredModeFromLabels(card);
318
+ if (fromLabels !== undefined)
319
+ return fromLabels;
320
+ const questionId = readOwnDataNonEmptyString(card, 'questionId');
321
+ return questionId === undefined ? 'unknown' : offeredModeFromQuestionId(questionId);
322
+ }
323
+ catch {
324
+ return 'unknown';
325
+ }
256
326
  }
257
327
  export function armPlanReviewApproval(result, sessionKey, opts) {
258
328
  let armedTaskId;
@@ -752,13 +822,13 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
752
822
  else if (typeof status === 'number' && corruptStoredRowWhere(e) !== undefined) {
753
823
  const where = corruptStoredRowWhere(e);
754
824
  hostLog('debug', `planReviewWire: ${decision} → ${String(status)} corrupt (stored resume context unreadable)`);
755
- effect = 'not_applied';
825
+ effect = refusalDeliveryOf(e, { route: 'plan_review' }).delivery === 'refused' ? 'not_applied' : 'unconfirmed';
756
826
  outcome = `This ${decision} was not applied. ${corruptStoredRowContent(where)}`;
757
827
  }
758
828
  else if (typeof status === 'number') {
759
829
  const failureTexts = wireFailureTextsOf(e);
760
830
  hostLog('debug', `planReviewWire: ${decision} → ${status} ${failureTexts.log.slice(0, 200)}`);
761
- effect = (status >= 400 && status < 500) || (typeof refusedCode === 'string' && isUnavailableFaceCode(refusedCode)) ? 'not_applied' : 'unconfirmed';
831
+ effect = refusalDeliveryOf(e, { route: 'plan_review' }).delivery === 'refused' ? 'not_applied' : 'unconfirmed';
762
832
  outcome = `${`The plan_review decision failed: HTTP ${status} ${failureTexts.reason}`.trim()}${decideFailureNote(e)}`;
763
833
  }
764
834
  else if (noAnswer === 'time-limit' || noAnswer === 'deadline') {
@@ -828,8 +898,6 @@ export function _resetActiveReopenRespondersForTest() {
828
898
  const reopenFlights = new Map();
829
899
  function joinReopenFlight(flight, taskId, receiptMs) {
830
900
  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
901
  const ac = new AbortController();
834
902
  return Promise.race([
835
903
  flight.presented.then((v) => v === true, () => false),
@@ -867,17 +935,13 @@ function mintPlanReviewReopen(taskId, opts, sessionKey, receiptMs) {
867
935
  settle(false);
868
936
  throw e;
869
937
  }
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;
938
+ return verdict.then((v) => {
939
+ settle(v.reopened === true);
940
+ return v;
941
+ }, (e) => {
942
+ settle(false);
943
+ throw e;
944
+ });
881
945
  }
882
946
  function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
883
947
  const markBefore = dismissalEntryFor(sessionKey, taskId);
@@ -893,30 +957,10 @@ function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
893
957
  const mintFresh = opts?.mintFreshQuestionId !== false;
894
958
  if (!mintFresh && hasLocalQuestionResponder(canonicalId)) {
895
959
  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
960
  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 };
961
+ const receipt = waitForGateArmedFor(sessionKey, [canonicalId], receiptMs);
962
+ publishQuestionFrameFor(sessionKey, planReviewQuestionFrame(canonicalId, ARM_QUESTION, offerModeAfterByTask.get(taskId) === true));
963
+ return settleOnReceipt(receipt, firstSight);
920
964
  }
921
965
  retireActiveReopen(sessionKey, canonicalId);
922
966
  if (unregisterLocalQuestionResponder(canonicalId)) {
@@ -961,23 +1005,9 @@ function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
961
1005
  return { ok: true };
962
1006
  });
963
1007
  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 };
1008
+ const receipt = waitForGateArmedFor(sessionKey, [questionId], receiptMs);
1009
+ publishQuestionFrameFor(sessionKey, planReviewQuestionFrame(questionId, REOPEN_QUESTION, false, true));
1010
+ return settleOnReceipt(receipt, firstSight);
981
1011
  }
982
1012
  function noPresentationSurfaceVerdict(taskId, sessionKey) {
983
1013
  const verdict = { reopened: false, _sema_noPresentationSurface: true };
@@ -1075,44 +1105,48 @@ async function staleDismissalVerdict(current, sessionKey, taskId, receiptMs) {
1075
1105
  }
1076
1106
  export function reopenPlanReviewCard(taskId, opts) {
1077
1107
  const receiptMs = opts?.presentationReceiptMs;
1108
+ if (typeof receiptMs !== 'number' || Number.isNaN(receiptMs)) {
1109
+ 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`);
1110
+ return Promise.resolve({ reopened: false });
1111
+ }
1078
1112
  try {
1079
1113
  if (typeof taskId !== 'string' || taskId.length === 0) {
1080
- return receiptMs === undefined ? { reopened: false } : Promise.resolve({ reopened: false });
1114
+ return Promise.resolve({ reopened: false });
1115
+ }
1116
+ const injected = opts;
1117
+ if (opts?.mintFreshQuestionId === false && (injected?.deliverDecision !== undefined || injected?.wire !== undefined || injected?.onOutcome !== undefined)) {
1118
+ hostLog('error', `planReviewWire: plan_review reopen for task ${taskId} refused — mintFreshQuestionId:false reuses the armed card's responder and its delivery, ` +
1119
+ 'so deliverDecision / wire / onOutcome cannot be given with it; drop mintFreshQuestionId:false to deliver through the injected path');
1120
+ return Promise.resolve({ reopened: false });
1081
1121
  }
1082
- const readStart = typeof opts?.pendingReadStartedAt === 'number' && Number.isFinite(opts.pendingReadStartedAt) ? opts.pendingReadStartedAt : undefined;
1122
+ const readStart = typeof opts.pendingReadStartedAt === 'number' && Number.isFinite(opts.pendingReadStartedAt) ? opts.pendingReadStartedAt : undefined;
1083
1123
  if (planReviewDecisionInFlight(taskId, readStart)) {
1084
1124
  hostLog('debug', `planReviewWire: reopen for task ${taskId} refused — a decision for this task is in flight (its answer is still being delivered)`);
1085
1125
  const refused = { reopened: false, _sema_decisionInFlight: true };
1086
- return receiptMs === undefined ? refused : Promise.resolve(refused);
1126
+ return Promise.resolve(refused);
1087
1127
  }
1088
1128
  const guardStartedAt = planReviewPendingReadMark();
1089
1129
  const recheckReadStart = readStart === undefined ? guardStartedAt : Math.min(readStart, guardStartedAt);
1090
- const sessionKey = opts?.sessionKey ?? DEFAULT_SESSION_KEY;
1130
+ const sessionKey = opts.sessionKey ?? DEFAULT_SESSION_KEY;
1091
1131
  if (!hasQuestionOverlayFor(sessionKey)) {
1092
- const noSurface = noPresentationSurfaceVerdict(taskId, sessionKey);
1093
- return receiptMs === undefined ? noSurface : Promise.resolve(noSurface);
1132
+ return Promise.resolve(noPresentationSurfaceVerdict(taskId, sessionKey));
1094
1133
  }
1095
- if (sessionKey !== DEFAULT_SESSION_KEY && opts?.deliverDecision === undefined && opts?.wire === undefined) {
1134
+ if (sessionKey !== DEFAULT_SESSION_KEY && opts.deliverDecision === undefined && opts.wire === undefined) {
1096
1135
  hostLog('error', `planReviewWire: plan_review 卡未重开 —— sessionKey=${JSON.stringify(sessionKey)} 是非默认槽,` +
1097
1136
  '而缺省决断投递口(decidePlanReview)今天固定打默认槽的 baseUrl/token/principal。' +
1098
1137
  '整条链转 keyed 之前,非默认槽要重开请自带 deliverDecision(按本槽投递);' +
1099
1138
  '此处拒绝而不是照发 —— 照发会把这条会话的决断发到另一个槽上。');
1100
- return receiptMs === undefined ? { reopened: false } : Promise.resolve({ reopened: false });
1139
+ return Promise.resolve({ reopened: false });
1101
1140
  }
1102
- const trigger = opts?.trigger === undefined ? undefined : opts.trigger === 'user' ? 'user' : 'automatic';
1141
+ const trigger = opts.trigger === undefined ? undefined : opts.trigger === 'user' ? 'user' : 'automatic';
1103
1142
  if (trigger === 'automatic') {
1104
1143
  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
- }
1144
+ if (mark !== undefined)
1110
1145
  return reopenAfterDismissalCheck(taskId, opts, sessionKey, receiptMs, mark, recheckReadStart);
1111
- }
1112
1146
  }
1113
1147
  return mintPlanReviewReopen(taskId, opts, sessionKey, receiptMs);
1114
1148
  }
1115
1149
  catch {
1116
- return receiptMs === undefined ? { reopened: false } : Promise.resolve({ reopened: false });
1150
+ return Promise.resolve({ reopened: false });
1117
1151
  }
1118
1152
  }
@@ -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,8 +1,8 @@
1
- import { CONFIG_LEGACY_TOOL_NAME, RULES_LEGACY_TOOL_NAME } from '../engineErrorCodes.js';
1
+ import { CONFIG_LEGACY_TOOL_NAME } from '../engineErrorCodes.js';
2
2
  import { rosterMountedNames } from '../rosterMountedNames.js';
3
3
  import { ruleCompileVerdict } from '../ruleCompileVerdict.js';
4
4
  import { ruleToolNameVerdictOf } from '../protocolSegment.js';
5
- import { PREFIXES_IN_PROSE, REFUSED_NAME_CLASSES, REFUSED_NAME_FIX, RULES_LEGACY_TOOL_NAME_WRITE_NOTE } from './refusedToolNameProse.js';
5
+ import { PREFIXES_IN_PROSE, REFUSED_NAME_CLASSES, REFUSED_NAME_FIX } from './refusedToolNameProse.js';
6
6
  import { CORE_PROTOCOL_PREFIXES } from '../generated/toolNameTables.js';
7
7
  const COVERING_NAMESPACE_PREFIXES = CORE_PROTOCOL_PREFIXES;
8
8
  const WITHHELD_NOTICE = {
@@ -132,7 +132,5 @@ const LEGACY_TOOL_NAME_FAILURE_NOTE = `This run did not start: a tool rule appli
132
132
  export function legacyToolNameFailureNoteOf(code) {
133
133
  if (code === CONFIG_LEGACY_TOOL_NAME)
134
134
  return LEGACY_TOOL_NAME_FAILURE_NOTE;
135
- if (code === RULES_LEGACY_TOOL_NAME)
136
- return RULES_LEGACY_TOOL_NAME_WRITE_NOTE;
137
135
  return undefined;
138
136
  }