@sema-agent/client-core 0.91.0 → 0.93.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 (195) hide show
  1. package/CHANGELOG.md +351 -0
  2. package/README.md +51 -34
  3. package/dist/adapt/arms.js +6 -12
  4. package/dist/adapt/panelTasks.d.ts +0 -2
  5. package/dist/adapt/panelTasks.js +6 -26
  6. package/dist/adapt/toolCards.js +6 -4
  7. package/dist/adapt.d.ts +1 -1
  8. package/dist/adapt.js +3 -3
  9. package/dist/adapter/activeRunSelfHeal.d.ts +0 -2
  10. package/dist/adapter/activeRunSelfHeal.js +5 -27
  11. package/dist/adapter/downstream/terminalToSdkResult.js +16 -7
  12. package/dist/adapter/runStream.js +6 -2
  13. package/dist/agentsWireCaps.js +1 -1
  14. package/dist/approvalDecidedByCapability.d.ts +16 -0
  15. package/dist/approvalDecidedByCapability.js +47 -0
  16. package/dist/approvalsStreamLiveCapability.js +3 -3
  17. package/dist/askSurvivesStandingAnswer.d.ts +4 -1
  18. package/dist/askSurvivesStandingAnswer.js +13 -0
  19. package/dist/autoModeUnavailable.js +3 -2
  20. package/dist/centerWiringCapability.js +1 -1
  21. package/dist/cloudConfigWireCaps.js +10 -9
  22. package/dist/compensations.js +7 -7
  23. package/dist/controlRouter.d.ts +23 -23
  24. package/dist/controlRouter.js +114 -49
  25. package/dist/coreValuePorts.d.ts +4 -2
  26. package/dist/coreValuePorts.js +5 -0
  27. package/dist/decideFailureNote.js +4 -2
  28. package/dist/decideReceipt.d.ts +11 -0
  29. package/dist/decideReceipt.js +95 -9
  30. package/dist/detachWire.d.ts +2 -14
  31. package/dist/detachWire.js +1 -47
  32. package/dist/deviceExecutorManagementCapability.d.ts +6 -2
  33. package/dist/deviceExecutorManagementCapability.js +61 -15
  34. package/dist/displayUntrusted.js +2 -1
  35. package/dist/effectiveFacts.d.ts +14 -4
  36. package/dist/effectiveFacts.js +45 -5
  37. package/dist/engineAgentAbsence.js +2 -1
  38. package/dist/engineCapReader.js +16 -10
  39. package/dist/engineCapsCache.d.ts +2 -0
  40. package/dist/engineCapsCache.js +13 -2
  41. package/dist/engineConfigDrift.d.ts +20 -0
  42. package/dist/engineConfigDrift.js +54 -0
  43. package/dist/engineErrorCodes.d.ts +17 -0
  44. package/dist/engineErrorCodes.js +45 -0
  45. package/dist/engineInlineTaskStats.d.ts +1 -0
  46. package/dist/engineNoticeCodes.d.ts +16 -2
  47. package/dist/engineNoticeCodes.js +71 -0
  48. package/dist/engineWireFor.d.ts +22 -0
  49. package/dist/engineWireFor.js +154 -9
  50. package/dist/engineWireSdk.d.ts +0 -1
  51. package/dist/engineWireSdk.js +0 -3
  52. package/dist/executionLaneCapability.js +4 -2
  53. package/dist/fileHistoryCaptureCapability.d.ts +1 -1
  54. package/dist/fileHistoryCaptureCapability.js +1 -6
  55. package/dist/fileHistoryLegNotice.d.ts +1 -1
  56. package/dist/fileHistoryLegNotice.js +1 -6
  57. package/dist/gateOutcome.js +2 -17
  58. package/dist/gateVocabulary.d.ts +2 -8
  59. package/dist/gateVocabulary.js +6 -32
  60. package/dist/generated/engineFactTables.d.ts +17 -1
  61. package/dist/generated/engineFactTables.js +91 -0
  62. package/dist/generated/engineNoticeTables.d.ts +1 -1
  63. package/dist/generated/engineNoticeTables.js +4 -1
  64. package/dist/generated/settingsSchemaTables.d.ts +8 -0
  65. package/dist/generated/settingsSchemaTables.js +40 -0
  66. package/dist/goalStopHook.d.ts +1 -8
  67. package/dist/goalStopHook.js +2 -58
  68. package/dist/headlessPermissionModeWire.d.ts +3 -2
  69. package/dist/headlessPermissionModeWire.js +46 -5
  70. package/dist/hitl/allowRuleShadow.d.ts +21 -0
  71. package/dist/hitl/allowRuleShadow.js +167 -0
  72. package/dist/hitl/askClassPair.d.ts +14 -0
  73. package/dist/hitl/askClassPair.js +42 -0
  74. package/dist/hitl/askGateWire.js +1 -0
  75. package/dist/hitl/askParkRowRouting.js +2 -2
  76. package/dist/hitl/askSurvivesPosture.d.ts +5 -0
  77. package/dist/hitl/askSurvivesPosture.js +17 -0
  78. package/dist/hitl/automaticAnswerVerdict.d.ts +21 -0
  79. package/dist/hitl/automaticAnswerVerdict.js +143 -0
  80. package/dist/hitl/crashConverged.d.ts +1 -0
  81. package/dist/hitl/crashConverged.js +1 -1
  82. package/dist/hitl/frameRouter.d.ts +2 -0
  83. package/dist/hitl/frameRouter.js +73 -16
  84. package/dist/hitl/gateLedger.d.ts +7 -0
  85. package/dist/hitl/gateLedger.js +37 -5
  86. package/dist/hitl/hitlBridge.d.ts +1 -0
  87. package/dist/hitl/hitlBridge.js +6 -1
  88. package/dist/hitl/hitlHostSurface.d.ts +5 -2
  89. package/dist/hitl/hitlHostSurface.js +25 -3
  90. package/dist/hitl/livePendingAsk.js +24 -5
  91. package/dist/hitl/parkResolver.js +24 -4
  92. package/dist/hitl/persistedRulesWire.d.ts +4 -1
  93. package/dist/hitl/persistedRulesWire.js +38 -19
  94. package/dist/hitl/planReviewWire.d.ts +0 -2
  95. package/dist/hitl/planReviewWire.js +3 -20
  96. package/dist/hitl/replayedApproval.d.ts +21 -0
  97. package/dist/hitl/replayedApproval.js +89 -0
  98. package/dist/hitl/sessionPolicyDeliverable.js +20 -2
  99. package/dist/hitl/sessionPolicyWire.d.ts +10 -0
  100. package/dist/hitl/sessionPolicyWire.js +19 -6
  101. package/dist/hitl/toolApprovalWire.d.ts +27 -7
  102. package/dist/hitl/toolApprovalWire.js +153 -94
  103. package/dist/hookMatcherVerdict.js +2 -1
  104. package/dist/hooksWireCaps.d.ts +1 -1
  105. package/dist/hooksWireCaps.js +1 -1
  106. package/dist/humanTurn.js +3 -4
  107. package/dist/index.d.ts +21 -6
  108. package/dist/index.js +17 -4
  109. package/dist/inheritEnvWire.d.ts +1 -4
  110. package/dist/inheritEnvWire.js +3 -22
  111. package/dist/limitsWire.d.ts +0 -6
  112. package/dist/limitsWire.js +0 -38
  113. package/dist/mcpLiveness.js +2 -1
  114. package/dist/mcpProbeCapability.js +1 -1
  115. package/dist/mcpProbeWire.js +10 -12
  116. package/dist/mcpReconnect.d.ts +5 -0
  117. package/dist/mcpReconnect.js +28 -0
  118. package/dist/memoryComplianceCapability.js +2 -2
  119. package/dist/memoryOriginCapability.js +2 -2
  120. package/dist/memoryVerbsWire.d.ts +1 -1
  121. package/dist/memoryVerbsWire.js +17 -13
  122. package/dist/model/catalog.js +2 -1
  123. package/dist/model/providerPresets.d.ts +3 -1
  124. package/dist/model/tierVocabulary.d.ts +2 -1
  125. package/dist/model/tierVocabulary.js +3 -8
  126. package/dist/ownKey.d.ts +2 -0
  127. package/dist/ownKey.js +15 -0
  128. package/dist/peerFrames.js +2 -2
  129. package/dist/peerLaneCapability.js +2 -2
  130. package/dist/permissionModesCapability.d.ts +16 -0
  131. package/dist/permissionModesCapability.js +71 -0
  132. package/dist/permissionRuleIssue.js +10 -7
  133. package/dist/permissionRulesWriteCapability.js +2 -2
  134. package/dist/permissionWireCaps.d.ts +2 -0
  135. package/dist/permissionWireCaps.js +8 -1
  136. package/dist/permissionsAllowGrantCapability.js +7 -2
  137. package/dist/permissionsDeclaration.d.ts +7 -1
  138. package/dist/permissionsDeclaration.js +29 -20
  139. package/dist/pluginHooksWire.js +2 -11
  140. package/dist/postureKnob.js +1 -1
  141. package/dist/promptProfileWireCaps.d.ts +2 -1
  142. package/dist/protocolSegment.d.ts +11 -0
  143. package/dist/protocolSegment.js +31 -0
  144. package/dist/readFacePosture.js +1 -1
  145. package/dist/request/taskRequest.js +1 -15
  146. package/dist/resumeRefusalCopy.d.ts +1 -0
  147. package/dist/resumeRefusalCopy.js +26 -3
  148. package/dist/retryStatus.js +2 -1
  149. package/dist/rewindArchiveCapability.js +2 -2
  150. package/dist/ruleCompileVerdict.d.ts +2 -0
  151. package/dist/ruleCompileVerdict.js +13 -0
  152. package/dist/ruleRemovalConsequence.d.ts +2 -1
  153. package/dist/runCancelContext.d.ts +12 -0
  154. package/dist/runCancelContext.js +83 -1
  155. package/dist/runTerminal.d.ts +16 -0
  156. package/dist/runTerminal.js +32 -3
  157. package/dist/seam.d.ts +1 -0
  158. package/dist/seam.js +1 -1
  159. package/dist/seatContract.d.ts +2 -1
  160. package/dist/sessionMemoryStatus.d.ts +2 -4
  161. package/dist/sessionPolicyCapability.js +1 -1
  162. package/dist/sessionSyncFileHistoryCapability.d.ts +18 -0
  163. package/dist/sessionSyncFileHistoryCapability.js +50 -0
  164. package/dist/skillToolListsCapability.d.ts +18 -0
  165. package/dist/skillToolListsCapability.js +50 -0
  166. package/dist/sqlEngineCapability.js +2 -9
  167. package/dist/steerPriorityCapability.d.ts +18 -0
  168. package/dist/steerPriorityCapability.js +80 -0
  169. package/dist/steerReceipt.d.ts +9 -0
  170. package/dist/steerReceipt.js +25 -0
  171. package/dist/storePostureCapability.js +2 -2
  172. package/dist/subagent/engineSubagentSteer.js +2 -9
  173. package/dist/supportFloor.d.ts +1 -0
  174. package/dist/supportFloor.js +15 -5
  175. package/dist/taskRequestWords.d.ts +4 -2
  176. package/dist/taskRequestWords.js +1 -1
  177. package/dist/toolHistoryBadTurn.js +1 -2
  178. package/dist/toolResult.d.ts +10 -1
  179. package/dist/toolResult.js +80 -6
  180. package/dist/types/engineState.d.ts +2 -12
  181. package/dist/userInvokedSkillsCapability.d.ts +18 -0
  182. package/dist/userInvokedSkillsCapability.js +50 -0
  183. package/dist/webSearchBackendCapability.js +2 -2
  184. package/dist/webSearchWireCaps.d.ts +1 -1
  185. package/dist/webSearchWireCaps.js +40 -2
  186. package/dist/wireFailureShape.d.ts +2 -0
  187. package/dist/wireFailureShape.js +6 -2
  188. package/dist/wireRefusalCopy.d.ts +9 -3
  189. package/dist/wireRefusalCopy.js +41 -4
  190. package/dist/workflowsJournalCapability.d.ts +18 -0
  191. package/dist/workflowsJournalCapability.js +50 -0
  192. package/dist/writeProtectionCapability.d.ts +2 -4
  193. package/dist/writeProtectionCapability.js +1 -1
  194. package/docs/INTEGRATION-CLIENTS.md +1516 -18
  195. package/package.json +2 -2
@@ -1,11 +1,12 @@
1
1
  import { type GateCurrentPending, type HitlFailureStage, type HitlSafetyCode, type HitlClientLike, type DecideOperationObserver } from './hitlBridge.js';
2
- import { type RuleStoreUnreadableKind } from '../gateVocabulary.js';
2
+ import { type AllowRuleShadowedWireMember, type ApprovalAllowRuleShadow } from './allowRuleShadow.js';
3
3
  import { type ApprovalMandateWord } from '../gateVocabulary.js';
4
4
  import type { ToolPermissionRequest } from '../seatContract.js';
5
5
  import { type DenyAttributionRefusalDetail } from '../wireRefusalCopy.js';
6
+ import { type ApprovalDecidedByReading } from '../approvalDecidedByCapability.js';
6
7
  import { type DecideReceiptView } from '../decideReceipt.js';
7
8
  import { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS, RULE_OFFERS_ABSENCE_REASONS } from '@sema-agent/sdk';
8
- import type { RuleSuggestion, ToolApprovalRespondAck, PersistedRuleAnchor as SdkPersistedRuleAnchor, RuleOfferMatch as SdkRuleOfferMatch, RuleOfferBatchMember as SdkRuleOfferBatchMember, RuleOfferUncoveredDetail as SdkRuleOfferUncoveredDetail, RuleOfferUncoveredReason as SdkRuleOfferUncoveredReason, AskOrigin as SdkAskOrigin, RuleOffersAbsence as SdkRuleOffersAbsence, DenialLimitKind as SdkDenialLimitKind, DenialLimitFallback as SdkDenialLimitFallback } from '@sema-agent/sdk';
9
+ import type { ToolApprovalRespondAck, PersistedRuleAnchor as SdkPersistedRuleAnchor, RuleOfferMatch as SdkRuleOfferMatch, RuleOfferBatchMember as SdkRuleOfferBatchMember, RuleOfferUncoveredDetail as SdkRuleOfferUncoveredDetail, RuleOfferUncoveredReason as SdkRuleOfferUncoveredReason, AskOrigin as SdkAskOrigin, RuleOffersAbsence as SdkRuleOffersAbsence, DenialLimitKind as SdkDenialLimitKind, DenialLimitFallback as SdkDenialLimitFallback } from '@sema-agent/sdk';
9
10
  export declare function isFsApprovalGate(gate: {
10
11
  kind?: unknown;
11
12
  toolName?: unknown;
@@ -23,6 +24,7 @@ export type FsApprovalOutcome = {
23
24
  denySettledBy?: ApprovalDenySettledBy | undefined;
24
25
  denyReason?: string | undefined;
25
26
  denyAttributionDropped?: true;
27
+ denyAttributionRenamed?: true;
26
28
  receipt?: DecideReceiptView | undefined;
27
29
  } | {
28
30
  kind: 'aborted';
@@ -48,6 +50,7 @@ export interface FsApprovalWireDeps {
48
50
  client: HitlClientLike;
49
51
  onPresented?: () => void;
50
52
  onDecideOperation?: DecideOperationObserver;
53
+ approvalDecidedBy?: ApprovalDecidedByReading | undefined;
51
54
  }
52
55
  export declare function structurallyEqual(a: unknown, b: unknown): boolean;
53
56
  export type RuleOfferMatch = SdkRuleOfferMatch;
@@ -131,8 +134,10 @@ export interface ApprovalCardRequest {
131
134
  inputHasBidi?: true;
132
135
  hasBidiControls?: true;
133
136
  persistedRuleShadowed?: string;
137
+ allowRuleShadow?: ApprovalAllowRuleShadow;
134
138
  probeCause?: unknown;
135
139
  probeReason?: string;
140
+ rememberRefused?: true;
136
141
  ruleEvidence?: unknown;
137
142
  requiresRealApproval?: true;
138
143
  irreversibleParkGate?: true;
@@ -148,7 +153,6 @@ export interface ApprovalCardRequest {
148
153
  origin?: string;
149
154
  askClass?: string;
150
155
  classes?: readonly string[];
151
- ruleStoreUnreadable?: RuleStoreUnreadableKind;
152
156
  }
153
157
  export type ApprovalCardPort = (req: ApprovalCardRequest) => Promise<ApprovalCardDecision>;
154
158
  export declare function installApprovalCardPort(port: ApprovalCardPort | null): () => void;
@@ -161,6 +165,11 @@ export declare function approvalCardPortFor(sessionKey: string): ApprovalCardPor
161
165
  export declare function _resetApprovalCardPortForTest(): void;
162
166
  export declare function surfaceApprovalCard(req: ApprovalCardRequest): Promise<ApprovalCardDecision>;
163
167
  export declare function surfaceFsApprovalAndDecide(deps: FsApprovalWireDeps, taskId: string, argsByCall: Map<string, unknown>, signal?: AbortSignal, parkGatedCallId?: string): Promise<FsApprovalOutcome>;
168
+ export interface BoundSkillGrantsWire {
169
+ readonly skill: string | null;
170
+ readonly allowedTools: readonly string[];
171
+ readonly disallowedTools: readonly string[];
172
+ }
164
173
  export interface ToolApprovalFrame {
165
174
  type: 'tool_approval' | 'tool_approval_complete';
166
175
  approvalId: string;
@@ -175,14 +184,17 @@ export interface ToolApprovalFrame {
175
184
  sourceAgentName?: string;
176
185
  governanceForced?: true;
177
186
  delegation?: ToolApprovalDelegation;
178
- ruleSuggestions?: RuleSuggestion[];
179
187
  ruleOffers?: readonly WireRuleOffer[];
180
188
  ruleOffersAbsence?: string;
181
189
  denialLimitFallback?: DenialLimitFallback;
182
- ruleStoreUnreadable?: string;
183
190
  persistedRuleShadowed?: string;
191
+ allowRuleShadowed?: readonly AllowRuleShadowedWireMember[];
192
+ boundGrantDigest?: string;
193
+ boundGrants?: BoundSkillGrantsWire;
194
+ classifierNoRuling?: string;
184
195
  probeCause?: unknown;
185
196
  probeReason?: string;
197
+ rememberRefused?: true;
186
198
  ruleEvidence?: unknown;
187
199
  requiresRealApproval?: true;
188
200
  mandated?: true;
@@ -207,7 +219,7 @@ export interface ToolApprovalDelegation {
207
219
  depth: number;
208
220
  agentName?: string;
209
221
  }
210
- export declare const TOOL_APPROVAL_FRAME_KEYS_MIRROR: readonly ["type", "approvalId", "toolCallId", "toolName", "sourceTaskId", "fromSubagent", "sourceAgentName", "message", "args", "argsOmitted", "governanceForced", "ruleSuggestions", "ruleOffers", "ruleOffersAbsence", "denialLimitFallback", "ruleStoreUnreadable", "readRootCandidate", "mandated", "mandate", "origin", "askClass", "classes", "inputHasBidi", "parked", "persistedRuleShadowed", "probeCause", "probeReason", "ruleEvidence", "requiresRealApproval", "expiresInMs", "expiresAtMs", "serverNowMs", "delegation", "outcome"];
222
+ export declare const TOOL_APPROVAL_FRAME_KEYS_MIRROR: readonly ["type", "approvalId", "toolCallId", "toolName", "sourceTaskId", "fromSubagent", "sourceAgentName", "message", "args", "argsOmitted", "governanceForced", "ruleOffers", "ruleOffersAbsence", "denialLimitFallback", "readRootCandidate", "mandated", "mandate", "origin", "askClass", "classes", "inputHasBidi", "parked", "persistedRuleShadowed", "allowRuleShadowed", "probeCause", "probeReason", "rememberRefused", "boundGrantDigest", "boundGrants", "classifierNoRuling", "ruleEvidence", "requiresRealApproval", "expiresInMs", "expiresAtMs", "serverNowMs", "delegation", "outcome"];
211
223
  export interface ApprovalMandatedFacts {
212
224
  readonly mandated?: true;
213
225
  readonly ruleOffersAbsence?: string;
@@ -228,11 +240,17 @@ export interface RespondToolApprovalOpts {
228
240
  persistRuleBatchOfferIndex?: number;
229
241
  note?: string;
230
242
  settledBy?: 'policy';
243
+ decidedBy?: 'policy';
231
244
  }
232
245
  export type RespondToolApprovalFn = (approvalId: string, decision: ToolApprovalRespondDecision, opts?: RespondToolApprovalOpts) => Promise<ToolApprovalRespondAck | void>;
233
246
  export type ToolApprovalRespondAckView = ToolApprovalRespondAck;
234
247
  export type PersistedRuleAnchor = SdkPersistedRuleAnchor;
235
248
  export declare function readToolApprovalRespondAck(v: unknown): ToolApprovalRespondAckView | undefined;
249
+ export declare function decisionAttributionKeyOf(reading: ApprovalDecidedByReading | undefined, denySettledBy: ApprovalDenySettledBy | undefined): {
250
+ decidedBy: 'policy';
251
+ } | {
252
+ settledBy: 'policy';
253
+ } | Record<never, never>;
236
254
  export interface ToolApprovalFrameOutcome {
237
255
  decision: ToolApprovalRespondDecision | 'unresolved';
238
256
  ack?: ToolApprovalRespondAckView;
@@ -243,6 +261,7 @@ export interface ToolApprovalFrameOutcome {
243
261
  denyReason?: string;
244
262
  denyAttributionRefusal?: DenyAttributionRefusalDetail;
245
263
  denyAttributionDropped?: true;
264
+ denyAttributionRenamed?: true;
246
265
  }
247
266
  interface ToolApprovalRespondRefusalFields {
248
267
  status?: number;
@@ -260,11 +279,12 @@ export declare function readToolApprovalRespondRefusal(err: unknown): ToolApprov
260
279
  export declare function isToolApprovalFrame(ev: unknown): ev is ToolApprovalFrame;
261
280
  export declare function readDenialLimitFallback(v: unknown): DenialLimitFallback | undefined;
262
281
  export declare function readRuleOffers(v: unknown): RuleOffer[] | undefined;
263
- export declare function readRuleOfferSupply(offers: unknown, legacy: unknown): RuleOffer[] | undefined;
282
+ export declare function readRuleOfferSupply(offers: unknown): RuleOffer[] | undefined;
264
283
  export interface ToolApprovalFrameLaneOpts {
265
284
  approvalDecisionNoteCapable?: boolean;
266
285
  respondFreeFormRulesCapable?: boolean;
267
286
  respondBatchRuleOffersCapable?: boolean;
287
+ approvalDecidedBy?: ApprovalDecidedByReading | undefined;
268
288
  windowIsCurrent?: boolean;
269
289
  argsUnavailable?: true;
270
290
  }
@@ -1,14 +1,16 @@
1
1
  import { APPROVAL_CARD_PORT_KEY_MISMATCH_REASON, DEFAULT_DENY_REASON, DecideTransportRetryExhaustedError, HitlBridge, NO_APPROVAL_CARD_PORT_REASON, HitlSafetyError, denyReasonForWire, findPendingForTask, readDecideCurrentPending, readWireErrorCode, } from './hitlBridge.js';
2
2
  import { askParkRowArm } from './askParkRowRouting.js';
3
3
  import { hostLog } from '../host.js';
4
- import { readOwnNonEmptyString } from '../ownKey.js';
4
+ import { readOwnDataValue, readOwnNonEmptyString } from '../ownKey.js';
5
+ import { readAskClassPair } from './askClassPair.js';
6
+ import { legacyShadowedRuleTextOf, readAllowRuleShadowFromWire } from './allowRuleShadow.js';
5
7
  import { createSessionSlot, DEFAULT_SESSION_KEY } from '../sessionSlot.js';
6
8
  import { readEngineActiveBgTasks } from '../fleet/fleetLedger.js';
7
9
  import { observeCancelByDeny, surfaceRememberNotApplied, surfaceEditNotForwarded, surfaceEditRefusedOnBlindAsk, surfaceRuleArmNotSent, surfaceRuleArmRejected } from './hitlHostSurface.js';
8
10
  import { approvalCallKey, liveFrameCallKey } from './gateIdentity.js';
9
- import { isRuleStoreUnreadableKind } from '../gateVocabulary.js';
10
11
  import { isApprovalMandateWord } from '../gateVocabulary.js';
11
12
  import { denyAttributionRefusalFromError } from '../wireRefusalCopy.js';
13
+ import { approvalDecidedByAdmitted } from '../approvalDecidedByCapability.js';
12
14
  import { decideFailureNote } from '../decideFailureNote.js';
13
15
  import { refusalSaysStillPending } from '../engineErrorCodes.js';
14
16
  import { readDecideReceipt } from '../decideReceipt.js';
@@ -169,6 +171,7 @@ function isParkRowInputSizeMarker(v) {
169
171
  return o.truncated === true && typeof o.bytes === 'number' && Number.isFinite(o.bytes) && o.bytes >= 0;
170
172
  }
171
173
  export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signal, parkGatedCallId) {
174
+ const decidedByReading = decidedByReadingSnapshotOf(deps);
172
175
  const found = await findPendingForTask(deps.client, taskId, (toolName) => toolName !== undefined && (toolNameIsFsWrite(toolName) || toolNameIsShellExec(toolName)), signal ? { signal } : undefined, parkGatedCallId, (row) => askParkRowArm(row) === 'tool-gate');
173
176
  if (!found.ok)
174
177
  return { kind: 'failed', stage: 'fetch', reason: found.reason, ...(found.code !== undefined ? { code: found.code } : {}) };
@@ -189,12 +192,11 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
189
192
  }
190
193
  const bridge = new HitlBridge(deps.client, taskId, deps.onDecideOperation ? { onDecideOperation: deps.onDecideOperation } : undefined);
191
194
  const callKey = approvalCallKey(gatedCallId, taskId);
192
- const ruleOffersReadOnly = readRuleOfferSupply(pending.ruleOffers, pending.ruleSuggestions);
195
+ const ruleOffersReadOnly = readRuleOffers(pending.ruleOffers);
193
196
  const durableProbeCause = pending.riskDescriptor?.probeCause;
194
197
  const durableProbeReason = readProbeReason(pending.riskDescriptor);
195
- const durableShadowedRule = pending.riskDescriptor?.shadowedRule;
198
+ const durableShadow = readAllowRuleShadowFromWire(pending, 'row');
196
199
  const durableRuleOffersAbsence = pending.ruleOffersAbsence;
197
- const durableRuleStoreUnreadable = readRuleStoreUnreadable(pending.ruleStoreUnreadable);
198
200
  deps.onPresented?.();
199
201
  const card = await surfaceApprovalCard({
200
202
  toolName,
@@ -218,12 +220,9 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
218
220
  ...(ruleOffersReadOnly !== undefined ? { ruleOffersReadOnly } : {}),
219
221
  ...(isWireRecordCarrier(durableProbeCause) ? { probeCause: durableProbeCause } : {}),
220
222
  ...(durableProbeReason !== undefined ? { probeReason: durableProbeReason } : {}),
221
- ...(durableRuleStoreUnreadable !== undefined
222
- ? { ruleStoreUnreadable: durableRuleStoreUnreadable }
223
- : {}),
224
- ...(typeof durableShadowedRule === 'string' && durableShadowedRule.trim() !== ''
225
- ? { persistedRuleShadowed: durableShadowedRule }
226
- : {}),
223
+ ...(readRememberRefused(pending) ? { rememberRefused: true } : {}),
224
+ ...(durableShadow !== undefined ? { allowRuleShadow: durableShadow } : {}),
225
+ ...((t) => (t !== undefined ? { persistedRuleShadowed: t } : {}))(legacyShadowedRuleTextOf(durableShadow)),
227
226
  ...(typeof durableRuleOffersAbsence === 'string' && durableRuleOffersAbsence !== ''
228
227
  ? { ruleOffersAbsence: durableRuleOffersAbsence }
229
228
  : {}),
@@ -298,31 +297,56 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
298
297
  }
299
298
  case 'deny': {
300
299
  const denySettledByForWire = readApprovalDenySettledBy(card);
300
+ const attributionKeys = decisionAttributionKeyOf(decidedByReading, denySettledByForWire);
301
301
  const denyReasonSnapshot = typeof card.reason === 'string' ? card.reason : undefined;
302
302
  let lastSendCarriedAttribution = false;
303
303
  try {
304
304
  const denyBody = {
305
305
  decision: 'deny',
306
306
  reason: denyReasonForWire(denyReasonSnapshot, `task ${taskId}`) ?? DEFAULT_DENY_REASON,
307
- ...(denySettledByForWire === 'policy' ? { settledBy: 'policy' } : {}),
307
+ ...attributionKeys,
308
308
  };
309
309
  let attributionDropped = false;
310
+ let attributionRenamed = false;
310
311
  let raw;
311
- lastSendCarriedAttribution = denySettledByForWire === 'policy';
312
+ lastSendCarriedAttribution = carriesAttributionKey(attributionKeys);
312
313
  try {
313
314
  raw = await bridge.decideTool(denyBody, gatedCallId, decideOpts, pending);
314
315
  }
315
316
  catch (first) {
316
- if (!shouldResendWithoutAttribution(first, lastSendCarriedAttribution, signal))
317
+ if (shouldResendWithoutAttribution(first, lastSendCarriedAttribution, signal)) {
318
+ const withoutAttribution = withoutAttributionKey(denyBody);
319
+ lastSendCarriedAttribution = false;
320
+ hostLog('debug', `liveToolApprovalWire: decide(deny) for task ${taskId} was refused because the settlement note is not part of ` +
321
+ 'what this deployment signs — re-sending the SAME decision exactly once with that one key removed ' +
322
+ '(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)');
323
+ raw = await bridge.decideTool(withoutAttribution, gatedCallId, decideOpts, pending);
324
+ attributionDropped = true;
325
+ }
326
+ else if (shouldResendUnderSuccessorKey(first, Object.hasOwn(denyBody, 'settledBy'), signal)) {
327
+ const renamed = withAttributionKeyRenamed(denyBody);
328
+ hostLog('debug', `liveToolApprovalWire: decide(deny) for task ${taskId} was refused because the settlement note was sent under a name ` +
329
+ 'this engine has retired — re-sending the SAME decision exactly once with that one key renamed to the name the refusal points to ' +
330
+ '(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)');
331
+ try {
332
+ raw = await bridge.decideTool(renamed, gatedCallId, decideOpts, pending);
333
+ attributionRenamed = true;
334
+ }
335
+ catch (second) {
336
+ if (!shouldResendWithoutAttribution(second, true, signal))
337
+ throw second;
338
+ const renamedWithoutAttribution = withoutAttributionKey(renamed);
339
+ lastSendCarriedAttribution = false;
340
+ hostLog('debug', `liveToolApprovalWire: decide(deny) for task ${taskId} was refused again because the settlement note is not part of ` +
341
+ 'what this deployment signs — re-sending the SAME decision exactly once more with that key removed ' +
342
+ '(still before the approval was judged)');
343
+ raw = await bridge.decideTool(renamedWithoutAttribution, gatedCallId, decideOpts, pending);
344
+ attributionDropped = true;
345
+ }
346
+ }
347
+ else {
317
348
  throw first;
318
- const { settledBy: _droppedKey, ...withoutAttribution } = denyBody;
319
- void _droppedKey;
320
- lastSendCarriedAttribution = false;
321
- hostLog('debug', `liveToolApprovalWire: decide(deny) for task ${taskId} was refused because the settlement note is not part of ` +
322
- 'what this deployment signs — re-sending the SAME decision exactly once with that one key removed ' +
323
- '(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)');
324
- raw = await bridge.decideTool(withoutAttribution, gatedCallId, decideOpts, pending);
325
- attributionDropped = true;
349
+ }
326
350
  }
327
351
  const receipt = readDecideReceipt(raw);
328
352
  const denySettledBy = denySettledByForWire;
@@ -334,6 +358,7 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
334
358
  ...(denySettledBy !== undefined ? { denySettledBy } : {}),
335
359
  ...(denyReason !== undefined ? { denyReason } : {}),
336
360
  ...(attributionDropped ? { denyAttributionDropped: true } : {}),
361
+ ...(attributionRenamed ? { denyAttributionRenamed: true } : {}),
337
362
  ...(receipt !== undefined ? { receipt } : {}),
338
363
  };
339
364
  }
@@ -363,6 +388,8 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
363
388
  decideSpan.close();
364
389
  }
365
390
  }
391
+ const _boundGrantsPin = [true, true, true];
392
+ void _boundGrantsPin;
366
393
  function readReadRootCandidate(v) {
367
394
  if (typeof v !== 'object' || v === null)
368
395
  return undefined;
@@ -385,11 +412,9 @@ export const TOOL_APPROVAL_FRAME_KEYS_MIRROR = [
385
412
  'args',
386
413
  'argsOmitted',
387
414
  'governanceForced',
388
- 'ruleSuggestions',
389
415
  'ruleOffers',
390
416
  'ruleOffersAbsence',
391
417
  'denialLimitFallback',
392
- 'ruleStoreUnreadable',
393
418
  'readRootCandidate',
394
419
  'mandated',
395
420
  'mandate',
@@ -399,8 +424,13 @@ export const TOOL_APPROVAL_FRAME_KEYS_MIRROR = [
399
424
  'inputHasBidi',
400
425
  'parked',
401
426
  'persistedRuleShadowed',
427
+ 'allowRuleShadowed',
402
428
  'probeCause',
403
429
  'probeReason',
430
+ 'rememberRefused',
431
+ 'boundGrantDigest',
432
+ 'boundGrants',
433
+ 'classifierNoRuling',
404
434
  'ruleEvidence',
405
435
  'requiresRealApproval',
406
436
  'expiresInMs',
@@ -445,30 +475,6 @@ export function toolPermissionRequestAskBits(card) {
445
475
  ...(askClassPair ?? {}),
446
476
  };
447
477
  }
448
- function readAskClassPair(v) {
449
- if (typeof v !== 'object' || v === null)
450
- return undefined;
451
- const askClass = readOwnNonEmptyString(v, 'askClass');
452
- if (askClass === undefined || !Object.hasOwn(v, 'classes'))
453
- return undefined;
454
- const raw = v.classes;
455
- if (!Array.isArray(raw) || raw.length === 0)
456
- return undefined;
457
- const classes = [];
458
- const seen = new Set();
459
- for (let i = 0; i < raw.length; i++) {
460
- if (!Object.hasOwn(raw, i))
461
- return undefined;
462
- const c = raw[i];
463
- if (typeof c !== 'string' || c === '' || seen.has(c))
464
- return undefined;
465
- seen.add(c);
466
- classes.push(c);
467
- }
468
- if (classes[0] !== askClass)
469
- return undefined;
470
- return { askClass, classes: Object.freeze(classes) };
471
- }
472
478
  function hasOwnStrictTrue(v, key) {
473
479
  return Object.hasOwn(v, key) && v[key] === true;
474
480
  }
@@ -575,13 +581,50 @@ function readPersistedRuleAnchors(v) {
575
581
  function isNonNegativeSafeInt(v) {
576
582
  return typeof v === 'number' && Number.isSafeInteger(v) && v >= 0;
577
583
  }
578
- function shouldResendWithoutAttribution(e, sentSettledBy, signal) {
579
- if (!sentSettledBy)
584
+ function shouldResendWithoutAttribution(e, sentAttributionKey, signal) {
585
+ if (!sentAttributionKey)
580
586
  return false;
581
587
  if (signal?.aborted === true)
582
588
  return false;
583
589
  return denyAttributionRefusalFromError(e, true)?.kind === 'not_in_proof';
584
590
  }
591
+ function shouldResendUnderSuccessorKey(e, lastSendCarriedRetiredKey, signal) {
592
+ if (!lastSendCarriedRetiredKey)
593
+ return false;
594
+ if (signal?.aborted === true)
595
+ return false;
596
+ return denyAttributionRefusalFromError(e, true)?.kind === 'retired_key';
597
+ }
598
+ export function decisionAttributionKeyOf(reading, denySettledBy) {
599
+ if (denySettledBy !== 'policy')
600
+ return {};
601
+ return approvalDecidedByAdmitted(reading) ? { decidedBy: 'policy' } : { settledBy: 'policy' };
602
+ }
603
+ function carriesAttributionKey(body) {
604
+ return Object.hasOwn(body, 'settledBy') || Object.hasOwn(body, 'decidedBy');
605
+ }
606
+ function withoutAttributionKey(body) {
607
+ const { settledBy: _droppedSettledBy, decidedBy: _droppedDecidedBy, ...rest } = body;
608
+ void _droppedSettledBy;
609
+ void _droppedDecidedBy;
610
+ return rest;
611
+ }
612
+ function withAttributionKeyRenamed(body) {
613
+ const { settledBy, decidedBy: _replaced, ...rest } = body;
614
+ void _replaced;
615
+ return settledBy === undefined ? rest : { ...rest, decidedBy: settledBy };
616
+ }
617
+ function readDecidedByReadingOf(holder) {
618
+ try {
619
+ return readOwnDataValue(holder, 'approvalDecidedBy');
620
+ }
621
+ catch {
622
+ return undefined;
623
+ }
624
+ }
625
+ function decidedByReadingSnapshotOf(holder) {
626
+ return approvalDecidedByAdmitted(readDecidedByReadingOf(holder)) ? Object.freeze({ kind: 'present', value: true }) : undefined;
627
+ }
585
628
  export function readToolApprovalRespondRefusal(err) {
586
629
  const pick = (key) => {
587
630
  try {
@@ -663,6 +706,14 @@ function readProbeReason(v) {
663
706
  return undefined;
664
707
  }
665
708
  }
709
+ function readRememberRefused(v) {
710
+ try {
711
+ return typeof v === 'object' && v !== null && Object.hasOwn(v, 'rememberRefused') && v.rememberRefused === true;
712
+ }
713
+ catch {
714
+ return false;
715
+ }
716
+ }
666
717
  function isNonNegativeFinite(v) {
667
718
  return typeof v === 'number' && Number.isFinite(v) && v >= 0;
668
719
  }
@@ -688,9 +739,6 @@ export function readDenialLimitFallback(v) {
688
739
  autoDenyAfterMs: d.autoDenyAfterMs,
689
740
  };
690
741
  }
691
- function readRuleStoreUnreadable(v) {
692
- return isRuleStoreUnreadableKind(v) ? v : undefined;
693
- }
694
742
  function isRuleOfferMatch(v) {
695
743
  return typeof v === 'string' && RULE_OFFER_MATCHES.includes(v);
696
744
  }
@@ -809,24 +857,8 @@ export function readRuleOffers(v) {
809
857
  }
810
858
  return out.length > 0 ? out : undefined;
811
859
  }
812
- function readLegacyRuleSuggestions(v) {
813
- if (!Array.isArray(v))
814
- return undefined;
815
- if (v.length === 0 || v.length > MAX_RULE_OFFERS_TOLERATED)
816
- return undefined;
817
- const out = [];
818
- for (let i = 0; i < v.length; i++) {
819
- const triple = readRuleTriple(v[i]);
820
- if (triple === undefined)
821
- continue;
822
- out.push({ kind: 'single', offerIndex: i, ...triple });
823
- }
824
- return out.length > 0 ? out : undefined;
825
- }
826
- export function readRuleOfferSupply(offers, legacy) {
827
- if (offers !== undefined && offers !== null)
828
- return readRuleOffers(offers);
829
- return readLegacyRuleSuggestions(legacy);
860
+ export function readRuleOfferSupply(offers) {
861
+ return readRuleOffers(offers);
830
862
  }
831
863
  function subagentBadgeFor(frame) {
832
864
  let name = typeof frame.sourceAgentName === 'string' && frame.sourceAgentName.length > 0 ? frame.sourceAgentName : '';
@@ -850,6 +882,7 @@ const MAX_RESPOND_NOTE_CHARS = 2048;
850
882
  export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamArgs, signal, lane) {
851
883
  const approvalId = frame.approvalId;
852
884
  const frameToolCallId = typeof frame.toolCallId === 'string' && frame.toolCallId !== '' ? frame.toolCallId : undefined;
885
+ const decidedByReading = decidedByReadingSnapshotOf(lane);
853
886
  const toolName = typeof frame.toolName === 'string' ? frame.toolName : 'Write';
854
887
  let args = streamArgs !== undefined && streamArgs !== null
855
888
  ? streamArgs
@@ -874,8 +907,9 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
874
907
  }
875
908
  }
876
909
  const argsNotRealInput = argsFallback || lane?.argsUnavailable === true;
877
- const ruleOffers = readRuleOfferSupply(frame.ruleOffers, frame.ruleSuggestions);
910
+ const ruleOffers = readRuleOffers(frame.ruleOffers);
878
911
  const denialLimitFallback = readDenialLimitFallback(frame.denialLimitFallback);
912
+ const frameShadow = readAllowRuleShadowFromWire(frame, 'frame');
879
913
  const card = await surfaceApprovalCard({
880
914
  toolName,
881
915
  args: args,
@@ -902,11 +936,11 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
902
936
  ? { delegation: frame.delegation }
903
937
  : {}),
904
938
  ...(ruleOffers !== undefined ? { ruleOffers } : {}),
905
- ...(typeof frame.persistedRuleShadowed === 'string' && frame.persistedRuleShadowed.trim() !== ''
906
- ? { persistedRuleShadowed: frame.persistedRuleShadowed }
907
- : {}),
939
+ ...((sh) => (sh !== undefined ? { allowRuleShadow: sh } : {}))(frameShadow),
940
+ ...((t) => (t !== undefined ? { persistedRuleShadowed: t } : {}))(legacyShadowedRuleTextOf(frameShadow)),
908
941
  ...(isWireRecordCarrier(frame.probeCause) ? { probeCause: frame.probeCause } : {}),
909
942
  ...((r) => (r !== undefined ? { probeReason: r } : {}))(readProbeReason(frame)),
943
+ ...(readRememberRefused(frame) ? { rememberRefused: true } : {}),
910
944
  ...(isWireRecordCarrier(frame.ruleEvidence) ? { ruleEvidence: frame.ruleEvidence } : {}),
911
945
  ...(frame.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
912
946
  ...(hasOwnStrictTrue(frame, 'mandated') ? { mandated: true } : {}),
@@ -917,7 +951,6 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
917
951
  ? { ruleOffersAbsence: frame.ruleOffersAbsence }
918
952
  : {}),
919
953
  ...(denialLimitFallback !== undefined ? { denialLimitFallback } : {}),
920
- ...((k) => (k !== undefined ? { ruleStoreUnreadable: k } : {}))(readRuleStoreUnreadable(frame.ruleStoreUnreadable)),
921
954
  ...((o) => (o !== undefined ? { origin: o } : {}))(readOwnNonEmptyString(frame, 'origin')),
922
955
  ...(readAskClassPair(frame) ?? {}),
923
956
  });
@@ -932,8 +965,9 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
932
965
  }
933
966
  const decision = card.kind === 'allow' ? (card.allowSession ? 'allow_session' : 'allow') : 'deny';
934
967
  const denySettledByForWire = card.kind === 'deny' ? readApprovalDenySettledBy(card) : undefined;
935
- const sentSettledBy = decision === 'deny' && denySettledByForWire === 'policy';
936
- let lastSendCarriedAttribution = sentSettledBy;
968
+ const attributionKeys = decision === 'deny' ? decisionAttributionKeyOf(decidedByReading, denySettledByForWire) : {};
969
+ const sentAttributionKey = carriesAttributionKey(attributionKeys);
970
+ let lastSendCarriedAttribution = sentAttributionKey;
937
971
  const denyReasonSnapshot = card.kind === 'deny' && typeof card.reason === 'string' ? card.reason : undefined;
938
972
  if (card.kind === 'failed') {
939
973
  hostLog('debug', `liveToolApprovalWire: approval card unavailable (${card.reason}) — fail-closed deny for ${approvalId}`);
@@ -960,14 +994,14 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
960
994
  let persistRuleBatchOfferIndex;
961
995
  let batchArmTarget;
962
996
  let ruleArmDroppedForCaps = false;
963
- let ruleArmDroppedForCheck = false;
997
+ let ruleArmDroppedForCheck;
964
998
  const wantsTextArm = card.kind === 'allow' && typeof card.persistRule === 'string' && card.persistRule !== '';
965
999
  const wantsBatchArm = card.kind === 'allow' && card.persistRuleBatchOfferIndex !== undefined;
966
1000
  if (wantsTextArm && wantsBatchArm) {
967
1001
  hostLog('error', `liveToolApprovalWire: DROPPING the whole persistRule arm for ${approvalId} — the card returned BOTH a rule ` +
968
1002
  'text and a batchOfferIndex; the server rejects that combination with a 400 that would take the decision down ' +
969
1003
  'with it, and picking one arm here would be deciding on the user\'s behalf (the decision itself still goes through)');
970
- ruleArmDroppedForCheck = true;
1004
+ ruleArmDroppedForCheck = 'both_arms';
971
1005
  }
972
1006
  else if (card.kind === 'allow' &&
973
1007
  card.persistRuleBatchOfferIndex !== undefined &&
@@ -992,7 +1026,7 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
992
1026
  hostLog('error', `liveToolApprovalWire: DROPPING persistRuleBatchOfferIndex(${String(idx)}) for ${approvalId} — that wire ` +
993
1027
  'index is not a batch offer on this frame (out of range, a single offer, or not a non-negative integer); ' +
994
1028
  'never redeeming an index the engine did not offer as a batch');
995
- ruleArmDroppedForCheck = true;
1029
+ ruleArmDroppedForCheck = 'index_not_a_batch_offer';
996
1030
  }
997
1031
  }
998
1032
  else if (wantsTextArm && card.kind === 'allow' && typeof card.persistRule === 'string' && decision !== 'deny') {
@@ -1014,7 +1048,7 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
1014
1048
  }
1015
1049
  else {
1016
1050
  hostLog('error', `liveToolApprovalWire: DROPPING persistRule for ${approvalId} — the card returned a rule that is not among the frame's SINGLE offers (a batch member's text is not a selectable candidate either: a conjunction batch is redeemed by index, all-or-nothing) — never sending un-offered text to the rule store`);
1017
- ruleArmDroppedForCheck = true;
1051
+ ruleArmDroppedForCheck = 'text_not_offered';
1018
1052
  }
1019
1053
  }
1020
1054
  const respondOpts = {
@@ -1024,24 +1058,48 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
1024
1058
  ...(persistRuleEdited !== undefined ? { persistRuleEdited } : {}),
1025
1059
  ...(persistRuleBatchOfferIndex !== undefined ? { persistRuleBatchOfferIndex } : {}),
1026
1060
  ...(note !== undefined ? { note } : {}),
1027
- ...(sentSettledBy ? { settledBy: 'policy' } : {}),
1061
+ ...attributionKeys,
1028
1062
  };
1029
1063
  let attributionDropped = false;
1064
+ let attributionRenamed = false;
1030
1065
  let raw;
1031
1066
  try {
1032
1067
  raw = await respond(approvalId, decision, respondOpts);
1033
1068
  }
1034
1069
  catch (first) {
1035
- if (!shouldResendWithoutAttribution(first, lastSendCarriedAttribution, signal))
1070
+ if (shouldResendWithoutAttribution(first, lastSendCarriedAttribution, signal)) {
1071
+ const withoutAttribution = withoutAttributionKey(respondOpts);
1072
+ lastSendCarriedAttribution = false;
1073
+ hostLog('debug', `liveToolApprovalWire: respond(deny) for ${approvalId} was refused because the settlement note is not part of ` +
1074
+ 'what this deployment signs — re-sending the SAME decision exactly once with that one key removed ' +
1075
+ '(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)');
1076
+ raw = await respond(approvalId, decision, withoutAttribution);
1077
+ attributionDropped = true;
1078
+ }
1079
+ else if (shouldResendUnderSuccessorKey(first, Object.hasOwn(respondOpts, 'settledBy'), signal)) {
1080
+ const renamed = withAttributionKeyRenamed(respondOpts);
1081
+ hostLog('debug', `liveToolApprovalWire: respond(deny) for ${approvalId} was refused because the settlement note was sent under a name ` +
1082
+ 'this engine has retired — re-sending the SAME decision exactly once with that one key renamed to the name the refusal points to ' +
1083
+ '(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)');
1084
+ try {
1085
+ raw = await respond(approvalId, decision, renamed);
1086
+ attributionRenamed = true;
1087
+ }
1088
+ catch (second) {
1089
+ if (!shouldResendWithoutAttribution(second, true, signal))
1090
+ throw second;
1091
+ const renamedWithoutAttribution = withoutAttributionKey(renamed);
1092
+ lastSendCarriedAttribution = false;
1093
+ hostLog('debug', `liveToolApprovalWire: respond(deny) for ${approvalId} was refused again because the settlement note is not part of ` +
1094
+ 'what this deployment signs — re-sending the SAME decision exactly once more with that key removed ' +
1095
+ '(still before the approval was judged)');
1096
+ raw = await respond(approvalId, decision, renamedWithoutAttribution);
1097
+ attributionDropped = true;
1098
+ }
1099
+ }
1100
+ else {
1036
1101
  throw first;
1037
- const { settledBy: _droppedKey, ...withoutAttribution } = respondOpts;
1038
- void _droppedKey;
1039
- lastSendCarriedAttribution = false;
1040
- hostLog('debug', `liveToolApprovalWire: respond(deny) for ${approvalId} was refused because the settlement note is not part of ` +
1041
- 'what this deployment signs — re-sending the SAME decision exactly once with that one key removed ' +
1042
- '(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)');
1043
- raw = await respond(approvalId, decision, withoutAttribution);
1044
- attributionDropped = true;
1102
+ }
1045
1103
  }
1046
1104
  const parsed = readToolApprovalRespondAck(raw);
1047
1105
  let ack = parsed;
@@ -1097,8 +1155,8 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
1097
1155
  }
1098
1156
  if (ruleArmDroppedForCaps)
1099
1157
  surfaceRuleArmNotSent();
1100
- if (ruleArmDroppedForCheck)
1101
- surfaceRuleArmRejected();
1158
+ if (ruleArmDroppedForCheck !== undefined)
1159
+ surfaceRuleArmRejected(ruleArmDroppedForCheck);
1102
1160
  if (decision === 'allow_session' && ack?.rememberApplied === false) {
1103
1161
  logAfterDecided(`liveToolApprovalWire: ${approvalId} allow_session ack rememberApplied=false — grant not stored, surfacing honest notice`);
1104
1162
  surfaceRememberNotApplied();
@@ -1114,6 +1172,7 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
1114
1172
  const denyAttribution = decision === 'deny'
1115
1173
  ? {
1116
1174
  ...(attributionDropped ? { denyAttributionDropped: true } : {}),
1175
+ ...(attributionRenamed ? { denyAttributionRenamed: true } : {}),
1117
1176
  ...(denySettledByForWire !== undefined ? { denySettledBy: denySettledByForWire } : {}),
1118
1177
  ...(denyReasonSnapshot !== undefined && denyReasonSnapshot.trim() !== ''
1119
1178
  ? { denyReason: denyReasonSnapshot }
@@ -1,5 +1,6 @@
1
1
  import { HOOK_TOOL_ALIASES } from './hookToolAliases.js';
2
- const TOOL_NAME_MATCHER_EVENTS = new Set(['PreToolUse', 'PostToolUse', 'PostToolUseFailure']);
2
+ import { SETTINGS_TOOL_NAME_MATCHER_EVENTS } from './generated/settingsSchemaTables.js';
3
+ const TOOL_NAME_MATCHER_EVENTS = new Set(SETTINGS_TOOL_NAME_MATCHER_EVENTS);
3
4
  const MATCHER_MAX_CHARS = 8192;
4
5
  const PATTERN_WORK_BUDGET = 10_000_000;
5
6
  const PATTERN_MAX_DEPTH = 32;
@@ -1,7 +1,7 @@
1
1
  import { type HooksWirePlan, type HooksWirePlanOptions } from './pluginHooksWire.js';
2
2
  import { type HookFailureNotice } from './notifications.js';
3
3
  import type { WireHooksConfig } from './finalVerifyWire.js';
4
- export { GOAL_STOP_HOOK_WIRE_ENV, CC_STOP_SEMANTICS_MIN_SERVER, ccStopSemanticsFromVersion, engineCcStopSemantics, isGoalStopHookWireArmed, setWireSessionStopHook, getWireSessionStopHook, getWireSessionStopHookCcSemantics, buildGoalStopHookPrompt, } from './goalStopHook.js';
4
+ export { GOAL_STOP_HOOK_WIRE_ENV, isGoalStopHookWireArmed, setWireSessionStopHook, getWireSessionStopHook, } from './goalStopHook.js';
5
5
  export type { WireHooksConfig };
6
6
  export interface HooksForWireOptions {
7
7
  readonly plan?: HooksWirePlan;
@@ -5,7 +5,7 @@ import { hostLog, hostSettings } from './host.js';
5
5
  import { createSettingsHookJudge, decidePluginHooks, dedupeSettingsHookGroups, filterSettingsHookGroups, occupancyOf, settingsHookDropText, } from './pluginHooksWire.js';
6
6
  import { MAX_HOOK_NOTICE_TEXT_CHARS } from './notifications.js';
7
7
  import { goalStopHookMatcher, __resetGoalStopHookForTests } from './goalStopHook.js';
8
- export { GOAL_STOP_HOOK_WIRE_ENV, CC_STOP_SEMANTICS_MIN_SERVER, ccStopSemanticsFromVersion, engineCcStopSemantics, isGoalStopHookWireArmed, setWireSessionStopHook, getWireSessionStopHook, getWireSessionStopHookCcSemantics, buildGoalStopHookPrompt, } from './goalStopHook.js';
8
+ export { GOAL_STOP_HOOK_WIRE_ENV, isGoalStopHookWireArmed, setWireSessionStopHook, getWireSessionStopHook, } from './goalStopHook.js';
9
9
  const EDITABLE_HOOK_SOURCES = ['userSettings', 'projectSettings', 'localSettings'];
10
10
  const ALL_HOOK_SOURCES = ['policySettings', ...EDITABLE_HOOK_SOURCES, 'flagSettings'];
11
11
  const _hookSourceListsPin = [true, true];