@sema-agent/client-core 0.95.0 → 0.96.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/CHANGELOG.md +180 -0
  2. package/README.md +49 -25
  3. package/dist/adapt/arms.js +7 -1
  4. package/dist/adapt/toolCards.d.ts +1 -0
  5. package/dist/adapt/toolCards.js +16 -3
  6. package/dist/adapt/wireShapes.js +2 -16
  7. package/dist/adapter/activeRunSelfHeal.d.ts +4 -0
  8. package/dist/adapter/activeRunSelfHeal.js +30 -4
  9. package/dist/adapter/downstream/eventToSdkMessage.js +11 -3
  10. package/dist/adapter/downstream/terminalToSdkResult.js +8 -9
  11. package/dist/adapter/runStream.js +30 -47
  12. package/dist/agentSession/engineAgentRegistryRead.js +5 -4
  13. package/dist/agentSession/engineSessionBackgroundStop.js +22 -15
  14. package/dist/agentsWireCaps.js +13 -2
  15. package/dist/callerCwdCapability.d.ts +0 -4
  16. package/dist/callerCwdCapability.js +0 -6
  17. package/dist/centerWiringCapability.d.ts +0 -4
  18. package/dist/centerWiringCapability.js +0 -6
  19. package/dist/classifierVerdictWire.js +4 -16
  20. package/dist/clientSlice.js +1 -1
  21. package/dist/cloudConfigWireCaps.d.ts +3 -3
  22. package/dist/cloudConfigWireCaps.js +65 -45
  23. package/dist/coreValuePorts.d.ts +11 -7
  24. package/dist/coreValuePorts.js +5 -8
  25. package/dist/credentialProvenance.d.ts +28 -0
  26. package/dist/credentialProvenance.js +76 -0
  27. package/dist/decideFailureNote.js +3 -1
  28. package/dist/decideReceipt.js +7 -10
  29. package/dist/declared/supportFloorDeclared.js +3 -3
  30. package/dist/displayUntrusted.d.ts +7 -3
  31. package/dist/displayUntrusted.js +356 -60
  32. package/dist/engineCapsCache.d.ts +6 -0
  33. package/dist/engineCapsCache.js +226 -32
  34. package/dist/engineDirectory.d.ts +79 -0
  35. package/dist/engineDirectory.js +186 -0
  36. package/dist/engineErrorCodes.d.ts +14 -1
  37. package/dist/engineErrorCodes.js +37 -15
  38. package/dist/engineNoticeCodes.d.ts +17 -0
  39. package/dist/engineNoticeCodes.js +57 -3
  40. package/dist/engineWordRenames.d.ts +8 -0
  41. package/dist/engineWordRenames.js +13 -0
  42. package/dist/fileHistoryCaptureCapability.d.ts +14 -0
  43. package/dist/fileHistoryCaptureCapability.js +70 -0
  44. package/dist/fleet/bgSubagentRow.d.ts +15 -0
  45. package/dist/fleet/bgSubagentRow.js +67 -0
  46. package/dist/fleet/fleetLedger.d.ts +1 -0
  47. package/dist/fleet/fleetLedger.js +103 -89
  48. package/dist/fleet/fleetProjection.d.ts +1 -0
  49. package/dist/fleet/fleetProjection.js +10 -3
  50. package/dist/fleetTaskDesc.js +4 -17
  51. package/dist/gateOutcome.d.ts +12 -1
  52. package/dist/gateOutcome.js +58 -1
  53. package/dist/gateVocabulary.d.ts +7 -2
  54. package/dist/gateVocabulary.js +5 -1
  55. package/dist/generated/engineAskFaceTables.js +1 -1
  56. package/dist/generated/engineFactTables.d.ts +5 -3
  57. package/dist/generated/engineFactTables.js +17 -4
  58. package/dist/generated/engineNoticeTables.js +12 -3
  59. package/dist/generated/settingsSchemaFns.d.ts +3 -0
  60. package/dist/generated/settingsSchemaFns.js +53 -0
  61. package/dist/generated/toolNameTables.d.ts +1 -0
  62. package/dist/generated/toolNameTables.js +1 -0
  63. package/dist/hitl/approvalEndingCause.d.ts +2 -0
  64. package/dist/hitl/approvalEndingCause.js +31 -21
  65. package/dist/hitl/askParkRowRouting.js +1 -1
  66. package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
  67. package/dist/hitl/automaticAnswerVerdict.js +13 -8
  68. package/dist/hitl/decisionConflict.js +0 -2
  69. package/dist/hitl/decisionRefusal.d.ts +8 -0
  70. package/dist/hitl/decisionRefusal.js +48 -14
  71. package/dist/hitl/frameRouter.d.ts +0 -1
  72. package/dist/hitl/frameRouter.js +6 -14
  73. package/dist/hitl/hitlBridge.d.ts +6 -2
  74. package/dist/hitl/hitlBridge.js +28 -7
  75. package/dist/hitl/localAllowRule.d.ts +1 -0
  76. package/dist/hitl/localAllowRule.js +2 -2
  77. package/dist/hitl/noAllowCause.d.ts +2 -1
  78. package/dist/hitl/noAllowCause.js +3 -2
  79. package/dist/hitl/parkResolver.d.ts +1 -0
  80. package/dist/hitl/parkResolver.js +8 -54
  81. package/dist/hitl/parkRowBirthWait.d.ts +1 -0
  82. package/dist/hitl/parkRowBirthWait.js +2 -2
  83. package/dist/hitl/planReviewWire.d.ts +1 -0
  84. package/dist/hitl/planReviewWire.js +98 -20
  85. package/dist/hitl/replayedApproval.d.ts +1 -0
  86. package/dist/hitl/replayedApproval.js +14 -0
  87. package/dist/hitl/sessionPolicyDeliverable.js +8 -6
  88. package/dist/hitl/standingRows.d.ts +18 -0
  89. package/dist/hitl/standingRows.js +127 -0
  90. package/dist/hitl/toolApprovalWire.d.ts +15 -3
  91. package/dist/hitl/toolApprovalWire.js +238 -25
  92. package/dist/hookMatcherVerdict.d.ts +1 -9
  93. package/dist/hookMatcherVerdict.js +21 -61
  94. package/dist/hooksWireCaps.js +2 -2
  95. package/dist/hostCallbackGuard.d.ts +1 -0
  96. package/dist/hostCallbackGuard.js +6 -0
  97. package/dist/index.d.ts +21 -9
  98. package/dist/index.js +17 -8
  99. package/dist/mcpProbeCapability.d.ts +0 -4
  100. package/dist/mcpProbeCapability.js +0 -6
  101. package/dist/memoryComplianceCapability.d.ts +0 -4
  102. package/dist/memoryComplianceCapability.js +0 -6
  103. package/dist/memoryOriginCapability.d.ts +0 -4
  104. package/dist/memoryOriginCapability.js +0 -6
  105. package/dist/memorySpecWire.js +2 -2
  106. package/dist/modelIdentityResolvability.d.ts +2 -2
  107. package/dist/modelIdentityResolvability.js +12 -3
  108. package/dist/noticePresentation.d.ts +68 -0
  109. package/dist/noticePresentation.js +247 -0
  110. package/dist/outputStyleSeatCapability.d.ts +0 -1
  111. package/dist/outputStyleSeatCapability.js +0 -3
  112. package/dist/ownKey.d.ts +2 -0
  113. package/dist/ownKey.js +18 -0
  114. package/dist/peerFrames.js +13 -9
  115. package/dist/permissionModesCapability.d.ts +0 -4
  116. package/dist/permissionModesCapability.js +0 -6
  117. package/dist/permissionRuleIssue.js +0 -3
  118. package/dist/permissionsDeclaration.d.ts +2 -0
  119. package/dist/permissionsDeclaration.js +56 -41
  120. package/dist/printPermissionOutcome.d.ts +12 -0
  121. package/dist/printPermissionOutcome.js +50 -0
  122. package/dist/printToolResultFrame.d.ts +1 -0
  123. package/dist/printToolResultFrame.js +5 -9
  124. package/dist/promptBlockedCopy.d.ts +5 -0
  125. package/dist/promptBlockedCopy.js +35 -0
  126. package/dist/protocolSegment.d.ts +9 -6
  127. package/dist/protocolSegment.js +31 -21
  128. package/dist/providerRejection.d.ts +4 -0
  129. package/dist/providerRejection.js +75 -14
  130. package/dist/replayBody.d.ts +12 -0
  131. package/dist/replayBody.js +25 -0
  132. package/dist/resumeRefusalCopy.js +5 -21
  133. package/dist/retryStatus.d.ts +9 -1
  134. package/dist/retryStatus.js +9 -2
  135. package/dist/rewindArchiveCapability.d.ts +3 -13
  136. package/dist/rewindArchiveCapability.js +7 -58
  137. package/dist/rewindArchiveReading.d.ts +15 -0
  138. package/dist/rewindArchiveReading.js +56 -0
  139. package/dist/ruleCompileVerdict.d.ts +9 -1
  140. package/dist/ruleCompileVerdict.js +29 -4
  141. package/dist/runTerminal.d.ts +15 -1
  142. package/dist/runTerminal.js +56 -8
  143. package/dist/sandboxWire.js +13 -0
  144. package/dist/sealedKeyCapability.d.ts +0 -4
  145. package/dist/sealedKeyCapability.js +0 -6
  146. package/dist/seam.js +4 -2
  147. package/dist/seatContract.d.ts +73 -11
  148. package/dist/seatContract.js +195 -14
  149. package/dist/sessionReadRedactionCapability.d.ts +0 -4
  150. package/dist/sessionReadRedactionCapability.js +0 -6
  151. package/dist/sessionSyncFileHistory.d.ts +4 -0
  152. package/dist/sessionSyncFileHistory.js +66 -0
  153. package/dist/sessionSyncFileHistoryCapability.d.ts +0 -1
  154. package/dist/sessionSyncFileHistoryCapability.js +0 -3
  155. package/dist/skillToolListsCapability.d.ts +0 -1
  156. package/dist/skillToolListsCapability.js +0 -3
  157. package/dist/steerPriorityCapability.d.ts +0 -1
  158. package/dist/steerPriorityCapability.js +0 -3
  159. package/dist/storePostureCapability.d.ts +0 -4
  160. package/dist/storePostureCapability.js +0 -6
  161. package/dist/subagent/engineSubagentSteer.js +7 -5
  162. package/dist/subagentContentStore.js +4 -15
  163. package/dist/supportFloor.d.ts +1 -0
  164. package/dist/supportFloor.js +13 -9
  165. package/dist/systemReminderTag.d.ts +1 -0
  166. package/dist/systemReminderTag.js +8 -0
  167. package/dist/toolHistoryMismatch.d.ts +0 -3
  168. package/dist/toolHistoryMismatch.js +3 -7
  169. package/dist/toolResult.d.ts +1 -1
  170. package/dist/toolResult.js +2 -1
  171. package/dist/toolResultContent.d.ts +2 -0
  172. package/dist/toolResultContent.js +63 -0
  173. package/dist/usageAnalytics.js +40 -16
  174. package/dist/userInvokedSkillsCapability.d.ts +0 -1
  175. package/dist/userInvokedSkillsCapability.js +0 -3
  176. package/dist/wireErrorTriage.d.ts +2 -0
  177. package/dist/wireErrorTriage.js +34 -5
  178. package/dist/wireFailureShape.d.ts +19 -2
  179. package/dist/wireFailureShape.js +55 -50
  180. package/docs/INTEGRATION-CLIENTS.md +1262 -17
  181. package/package.json +5 -5
@@ -1,4 +1,4 @@
1
- import { APPROVAL_CARD_PORT_KEY_MISMATCH_REASON, DEFAULT_DENY_REASON, DecideTransportRetryExhaustedError, HitlBridge, NO_APPROVAL_CARD_PORT_REASON, denyReasonForWire, findPendingForTask, hitlSafetyCodeOf, readDecideCurrentPending, readWireErrorCode, readWireErrorCodeReading, } from './hitlBridge.js';
1
+ import { APPROVAL_CARD_PORT_KEY_MISMATCH_REASON, DEFAULT_DENY_REASON, DecideTransportRetryExhaustedError, HitlBridge, NO_APPROVAL_CARD_PORT_REASON, denyReasonForWire, findPendingForTask, hitlSafetyCodeOf, readDecideCurrentPending, readWireCodes, readWireErrorCodeReading, } from './hitlBridge.js';
2
2
  import { askParkRowArm } from './askParkRowRouting.js';
3
3
  import { hostLog } from '../host.js';
4
4
  import { readAskOrigin, readOwnDataNonEmptyString, readOwnDataValue, readOwnNonEmptyString } from '../ownKey.js';
@@ -6,6 +6,7 @@ import { readAskClassPair } from './askClassPair.js';
6
6
  import { readAllowRuleShadowFromWire } from './allowRuleShadow.js';
7
7
  import { createSessionSlot, DEFAULT_SESSION_KEY } from '../sessionSlot.js';
8
8
  import { readEngineActiveBgTasks } from '../fleet/fleetLedger.js';
9
+ import { CORE_SKILL_TOOL_NAME } from '../generated/toolNameTables.js';
9
10
  import { INTERRUPT_DENY_REASON, observeCancelByDeny, surfaceApprovalParking, surfaceRememberNotApplied, surfaceEditNotForwarded, surfaceEditRefusedOnBlindAsk, surfaceRuleArmNotSent, surfaceRuleArmRejected } from './hitlHostSurface.js';
10
11
  import { approvalCallKey, liveFrameCallKey } from './gateIdentity.js';
11
12
  import { displayUntrusted } from '../displayUntrusted.js';
@@ -15,10 +16,12 @@ import { isApprovalMandateWord } from '../gateVocabulary.js';
15
16
  import { denyAttributionRefusalFromError } from '../wireRefusalCopy.js';
16
17
  import { approvalDecidedByAdmitted } from '../approvalDecidedByCapability.js';
17
18
  import { decideFailureNote } from '../decideFailureNote.js';
18
- import { thrownIsInstanceOf, wireFailureTextsOf } from '../wireFailureShape.js';
19
+ import { readRefusalField, thrownIsInstanceOf, wireFailureTextsOf } from '../wireFailureShape.js';
20
+ import { refusalCauseWordOf } from './approvalEndingCause.js';
21
+ import { readDecisionRefusalAsk } from './decisionRefusal.js';
19
22
  import { DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED, refusalSaysStillPending } from '../engineErrorCodes.js';
20
23
  import { readDecideReceipt } from '../decideReceipt.js';
21
- import { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS, RULE_OFFERS_ABSENCE_REASONS, ASK_ORIGINS, PERSISTED_RULE_MANDATES, } from '@sema-agent/sdk';
24
+ import { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS, RULE_OFFERS_ABSENCE_REASONS, ASK_ORIGINS, } from '@sema-agent/sdk';
22
25
  export function isFsApprovalGate(gate) {
23
26
  if (!gate)
24
27
  return false;
@@ -61,7 +64,6 @@ export function structurallyEqual(a, b) {
61
64
  export { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS };
62
65
  export { RULE_OFFERS_ABSENCE_REASONS };
63
66
  export const ASK_ORIGIN_WORDS = ASK_ORIGINS;
64
- export const APPROVAL_MANDATE_WORDS = PERSISTED_RULE_MANDATES;
65
67
  export const APPROVAL_DENY_SETTLED_BY_WORDS = Object.freeze(['human', 'policy']);
66
68
  export function readApprovalDenySettledBy(decision) {
67
69
  if (decision === null || typeof decision !== 'object')
@@ -166,6 +168,14 @@ const ARGS_OMITTED_PATH_RECOVERED_NOTE = 'tool arguments exceeded the wire cap a
166
168
  const ARGS_OMITTED_NOTHING_RECOVERED_NOTE = 'tool arguments exceeded the wire cap and were omitted, and nothing could be recovered from the approval question — ' +
167
169
  'you are deciding without seeing what this call will do; deny it if you are not sure. ' +
168
170
  'Edits are not accepted on this card: there is no original input to edit';
171
+ function argsFallbackOf(message, argsOmitted) {
172
+ const p = pathFromGateMessage(typeof message === 'string' ? message : undefined);
173
+ return {
174
+ args: p !== undefined ? { file_path: p } : {},
175
+ pathRecovered: p !== undefined,
176
+ ...(argsOmitted === true ? { omittedNote: p !== undefined ? ARGS_OMITTED_PATH_RECOVERED_NOTE : ARGS_OMITTED_NOTHING_RECOVERED_NOTE } : {}),
177
+ };
178
+ }
169
179
  const PARK_ROW_ARGS_ABSENT_NOTE = "this request's tool arguments are not available on this surface — neither the event stream nor the pending approval record " +
170
180
  'carries them, so you are deciding without seeing them; deny it if you are not sure what it will do. ' +
171
181
  'Edits are not accepted on this card: there is no original input to edit';
@@ -357,7 +367,7 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
357
367
  const durableRuleOffersAbsence = pending.ruleOffersAbsence;
358
368
  hold.presented = true;
359
369
  deps.onPresented?.();
360
- const card = await surfaceCallTrackedCard(gatedCallId, undefined, ledgerSlot, {
370
+ const card = await surfaceCallTrackedCard(gatedCallId, undefined, ledgerSlot, withUnreadableEvidence(pending, 'row', {
361
371
  toolName,
362
372
  args,
363
373
  callKey,
@@ -387,7 +397,9 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
387
397
  ...(typeof pending.toolCallId === 'string' && pending.toolCallId !== ''
388
398
  ? { toolCallId: pending.toolCallId }
389
399
  : {}),
390
- });
400
+ allowSessionCarried: true,
401
+ grantBinding: readApprovalGrantBinding(pending),
402
+ }));
391
403
  if (rowArgsGap !== undefined && card.kind === 'allow' && card.updatedInput !== undefined) {
392
404
  hostLog('error', `liveToolApprovalWire: approval card for ${gatedCallId ?? `task ${taskId}`} returned an edited approval, but the tool input is ${rowArgsGap === 'truncated' ? 'a size marker on the pending row' : 'missing from both the stream and the pending row'} — nothing sent (the park stays pending)`);
393
405
  surfaceEditRefusedOnBlindAsk();
@@ -441,7 +453,7 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
441
453
  }
442
454
  catch (e) {
443
455
  const currentPending = readDecideCurrentPending(e);
444
- const wireCode = readWireErrorCode(e);
456
+ const wireCodes = readWireCodes(e);
445
457
  const wireRetriable = typeof e === 'object' && e !== null && refusalSaysStillPending(e);
446
458
  const safetyCode = hitlSafetyCodeOf(e);
447
459
  const failureTexts = wireFailureTextsOf(e);
@@ -453,7 +465,7 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
453
465
  reason: `decide(approve) failed: ${failureTexts.reason}${decideFailureNote(e, 'approve')}`,
454
466
  ...(thrownIsInstanceOf(e, DecideTransportRetryExhaustedError) ? { retryExhausted: true } : {}),
455
467
  ...(currentPending !== undefined ? { currentPending } : {}),
456
- ...(wireCode !== undefined ? { errorCode: wireCode } : {}),
468
+ ...wireCodes,
457
469
  ...(wireRetriable ? { retriable: true } : {}),
458
470
  ...(safetyCode !== undefined ? { safetyCode } : {}),
459
471
  };
@@ -527,7 +539,7 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
527
539
  }
528
540
  catch (e) {
529
541
  const currentPending = readDecideCurrentPending(e);
530
- const wireCode = readWireErrorCode(e);
542
+ const wireCodes = readWireCodes(e);
531
543
  const wireRetriable = typeof e === 'object' && e !== null && refusalSaysStillPending(e);
532
544
  const safetyCode = hitlSafetyCodeOf(e);
533
545
  const attributionRefusal = denyAttributionRefusalFromError(e, lastSendCarriedAttribution);
@@ -540,7 +552,7 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
540
552
  reason: `decide(deny) failed: ${failureTexts.reason}${decideFailureNote(e, 'deny')}`,
541
553
  ...(thrownIsInstanceOf(e, DecideTransportRetryExhaustedError) ? { retryExhausted: true } : {}),
542
554
  ...(currentPending !== undefined ? { currentPending } : {}),
543
- ...(wireCode !== undefined ? { errorCode: wireCode } : {}),
555
+ ...wireCodes,
544
556
  ...(wireRetriable ? { retriable: true } : {}),
545
557
  ...(safetyCode !== undefined ? { safetyCode } : {}),
546
558
  ...(attributionRefusal !== null ? { denyAttributionRefusal: attributionRefusal } : {}),
@@ -639,6 +651,7 @@ export function toolPermissionRequestAskBits(card) {
639
651
  ...(origin !== undefined ? { origin } : {}),
640
652
  ...(ruleOffersAbsence !== undefined ? { ruleOffersAbsence } : {}),
641
653
  ...(askClassPair ?? {}),
654
+ ...(readApprovalRememberRefused(card) ? { rememberRefused: true } : {}),
642
655
  };
643
656
  }
644
657
  function hasOwnStrictTrue(v, key) {
@@ -837,10 +850,20 @@ export function readToolApprovalRespondRefusal(err) {
837
850
  const message = refusalTextOf(err, pick('message'));
838
851
  if (status === undefined && errorCode === undefined && message === undefined)
839
852
  return undefined;
853
+ const machine = typeof err === 'object' && err !== null ? err : undefined;
854
+ const retriable = machine !== undefined && refusalSaysStillPending(machine);
855
+ const cause = machine !== undefined ? refusalCauseWordOf(machine) : undefined;
856
+ const field = machine !== undefined ? readRefusalField(machine) : undefined;
857
+ const unreadable = machine !== undefined && readDecisionRefusalAsk(machine).reading === 'unreadable';
840
858
  const rest = {
841
859
  ...(status !== undefined ? { status } : {}),
842
860
  ...(errorCode !== undefined ? { errorCode } : {}),
843
861
  ...(message !== undefined ? { message } : {}),
862
+ ...(retriable ? { retriable: true } : {}),
863
+ ...(cause !== undefined || field !== undefined
864
+ ? { extra: { ...(cause !== undefined ? { cause } : {}), ...(field !== undefined ? { field } : {}) } }
865
+ : {}),
866
+ ...(unreadable ? { unreadable: true } : {}),
844
867
  };
845
868
  if (status !== undefined)
846
869
  return { ...rest, status };
@@ -906,15 +929,26 @@ function usableProbeReason(raw) {
906
929
  }
907
930
  const PROBE_CAUSE_CODE_WORD = /^[a-z][a-z0-9_]{0,31}(?:\.[a-z][a-z0-9_]{0,31}){1,3}$/;
908
931
  export function askProbeReasonDetail(card) {
909
- const reason = usableProbeReason(ownDataValue(card, 'probeReason'));
910
- if (reason !== undefined)
911
- return displayUntrusted(reason);
912
- const cause = ownDataValue(card, 'probeCause');
913
- if (!isWireRecordCarrier(cause))
932
+ const prose = usableProbeReason(ownDataValue(card, 'probeReason'));
933
+ const shown = prose === undefined ? '' : displayUntrusted(prose);
934
+ const sentence = probeCauseSentence(ownDataValue(card, 'probeCause'), shown !== '');
935
+ if (sentence === undefined)
936
+ return shown === '' ? undefined : shown;
937
+ return shown === '' ? sentence : `${sentence} ${shown}`;
938
+ }
939
+ function probeCauseSentence(cause, withProse) {
940
+ try {
941
+ if (!isWireRecordCarrier(cause))
942
+ return undefined;
943
+ const code = ownDataValue(cause, 'code');
944
+ const head = withProse
945
+ ? 'An automatic check could not clear this call, so it is asking you'
946
+ : 'An automatic check could not clear this call, so it is asking you; the engine did not say the specific reason';
947
+ return typeof code === 'string' && PROBE_CAUSE_CODE_WORD.test(code) ? `${head} (check code: ${code}).` : `${head}.`;
948
+ }
949
+ catch {
914
950
  return undefined;
915
- const code = ownDataValue(cause, 'code');
916
- const head = 'An automatic check could not clear this call, so it is asking you; the engine did not say the specific reason';
917
- return typeof code === 'string' && PROBE_CAUSE_CODE_WORD.test(code) ? `${head} (check code: ${code}).` : `${head}.`;
951
+ }
918
952
  }
919
953
  export function readApprovalRememberRefused(v) {
920
954
  try {
@@ -968,6 +1002,76 @@ export function readApprovalBoundGrants(v) {
968
1002
  return undefined;
969
1003
  return Object.freeze({ skill, allowedTools, disallowedTools });
970
1004
  }
1005
+ function readApprovalGrantBinding(carrier) {
1006
+ if (typeof carrier !== 'object' || carrier === null)
1007
+ return 'unreadable';
1008
+ try {
1009
+ if (Object.hasOwn(carrier, 'boundGrantDigest')) {
1010
+ const digest = ownDataValue(carrier, 'boundGrantDigest');
1011
+ return typeof digest === 'string' && digest.length > 0 ? 'bound' : 'unreadable';
1012
+ }
1013
+ const tool = ownDataValue(carrier, 'toolName');
1014
+ if (typeof tool !== 'string' || tool.length === 0)
1015
+ return 'unreadable';
1016
+ return tool === CORE_SKILL_TOOL_NAME ? 'unreadable' : 'none';
1017
+ }
1018
+ catch {
1019
+ return 'unreadable';
1020
+ }
1021
+ }
1022
+ const UNREADABLE_EVIDENCE_KEYS = Object.freeze({
1023
+ frame: Object.freeze([
1024
+ ['rememberRefused', 'rememberRefused'], ['governanceForced', 'governanceForced'], ['requiresRealApproval', 'requiresRealApproval'],
1025
+ ['mandated', 'mandated'], ['mandate', 'mandate'], ['origin', 'origin'], ['ruleOffersAbsence', 'ruleOffersAbsence'], ['ruleOffers', 'ruleOffers'],
1026
+ ['allowRuleShadowed', 'allowRuleShadow'], ['persistedRuleShadowed', 'allowRuleShadow'], ['askClass', 'askClass'], ['classes', 'classes'],
1027
+ ]),
1028
+ row: Object.freeze([
1029
+ ['rememberRefused', 'rememberRefused'], ['governanceForced', 'governanceForced'], ['requiresRealApproval', 'requiresRealApproval'],
1030
+ ['mandated', 'mandated'], ['mandate', 'mandate'], ['origin', 'origin'], ['ruleOffersAbsence', 'ruleOffersAbsence'], ['ruleOffers', 'ruleOffersReadOnly'],
1031
+ ['askClass', 'askClass'], ['classes', 'classes'],
1032
+ ]),
1033
+ v1: Object.freeze([
1034
+ ['rememberRefused', 'rememberRefused'], ['governanceForced', 'governanceForced'], ['ruleOffersAbsence', 'ruleOffersAbsence'], ['ruleOffers', 'ruleOffersReadOnly'],
1035
+ ['allowRuleShadowed', 'allowRuleShadow'], ['persistedRuleShadowed', 'allowRuleShadow'], ['askClass', 'askClass'], ['classes', 'classes'],
1036
+ ]),
1037
+ });
1038
+ function carrierHas(carrier, key) {
1039
+ if (typeof carrier !== 'object' || carrier === null)
1040
+ return false;
1041
+ try {
1042
+ return key in carrier;
1043
+ }
1044
+ catch {
1045
+ return true;
1046
+ }
1047
+ }
1048
+ function v1RiskUnreadable(card) {
1049
+ if (!carrierHas(card, 'risk'))
1050
+ return false;
1051
+ try {
1052
+ const risk = card.risk;
1053
+ return typeof risk !== 'object' || risk === null || typeof risk.requiresRealApproval !== 'boolean';
1054
+ }
1055
+ catch {
1056
+ return true;
1057
+ }
1058
+ }
1059
+ function withUnreadableEvidence(carrier, leg, req) {
1060
+ const keys = new Set();
1061
+ for (const [from, to] of UNREADABLE_EVIDENCE_KEYS[leg]) {
1062
+ if (carrierHas(carrier, from) && !Object.hasOwn(req, to))
1063
+ keys.add(from);
1064
+ }
1065
+ if (leg === 'row') {
1066
+ const rd = ownDataValue(carrier, 'riskDescriptor');
1067
+ for (const k of ['allowRuleShadowed', 'shadowedRule'])
1068
+ if (carrierHas(rd, k) && !Object.hasOwn(req, 'allowRuleShadow'))
1069
+ keys.add(`riskDescriptor.${k}`);
1070
+ }
1071
+ if (leg === 'v1' && v1RiskUnreadable(carrier))
1072
+ keys.add('risk');
1073
+ return keys.size === 0 ? req : { ...req, unreadableEvidence: Object.freeze([...keys].sort()) };
1074
+ }
971
1075
  const CAUSE_WORD = /^[a-z][a-z0-9_]{0,63}$/;
972
1076
  export function readApprovalClassifierNoRuling(v) {
973
1077
  const w = ownDataValue(v, 'classifierNoRuling');
@@ -1249,6 +1353,113 @@ function subagentBadgeFor(frame) {
1249
1353
  name = `${name.slice(0, 31)}…`;
1250
1354
  return { name, color: 'cyan' };
1251
1355
  }
1356
+ function v1Bit(stamp) {
1357
+ try {
1358
+ stamp();
1359
+ }
1360
+ catch {
1361
+ }
1362
+ }
1363
+ export function approvalCardFactsOfV1(card) {
1364
+ if (typeof card !== 'object' || card === null)
1365
+ return undefined;
1366
+ const c = card;
1367
+ const asFrame = card;
1368
+ const fromSubagent = (() => {
1369
+ try {
1370
+ return isFromSubagent(asFrame);
1371
+ }
1372
+ catch {
1373
+ return false;
1374
+ }
1375
+ })();
1376
+ const argsPart = (() => {
1377
+ try {
1378
+ const raw = c.args !== undefined && c.args !== null ? c.args : undefined;
1379
+ if (typeof raw === 'object' && raw !== null)
1380
+ return { args: raw };
1381
+ const fallback = argsFallbackOf(c.message, c.argsOmitted);
1382
+ return { args: fallback.args, argsUnavailable: true, ...(fallback.omittedNote !== undefined ? { wireNote: fallback.omittedNote } : {}) };
1383
+ }
1384
+ catch {
1385
+ return { args: {}, argsUnavailable: true };
1386
+ }
1387
+ })();
1388
+ const out = { toolName: '', ...argsPart };
1389
+ v1Bit(() => {
1390
+ if (typeof c.toolName === 'string')
1391
+ out.toolName = c.toolName;
1392
+ });
1393
+ v1Bit(() => {
1394
+ if (typeof c.toolCallId === 'string' && c.toolCallId !== '')
1395
+ out.toolCallId = c.toolCallId;
1396
+ });
1397
+ v1Bit(() => {
1398
+ if (fromSubagent)
1399
+ out.workerBadge = subagentBadgeFor(asFrame);
1400
+ });
1401
+ v1Bit(() => {
1402
+ if (c.governanceForced === true)
1403
+ out.governanceForced = true;
1404
+ });
1405
+ v1Bit(() => {
1406
+ const d = c.delegation;
1407
+ if (fromSubagent && isToolApprovalDelegation(d))
1408
+ out.delegation = d;
1409
+ });
1410
+ v1Bit(() => {
1411
+ const offers = readRuleOffers(c.ruleOffers);
1412
+ if (offers !== undefined)
1413
+ out.ruleOffersReadOnly = offers;
1414
+ });
1415
+ v1Bit(() => {
1416
+ const shadow = readAllowRuleShadowFromWire(card, 'frame');
1417
+ if (shadow !== undefined)
1418
+ out.allowRuleShadow = shadow;
1419
+ });
1420
+ v1Bit(() => {
1421
+ const pc = c.probeCause;
1422
+ if (isWireRecordCarrier(pc))
1423
+ out.probeCause = pc;
1424
+ });
1425
+ v1Bit(() => {
1426
+ if (readApprovalRememberRefused(card))
1427
+ out.rememberRefused = true;
1428
+ });
1429
+ v1Bit(() => {
1430
+ const re = c.ruleEvidence;
1431
+ if (isWireRecordCarrier(re))
1432
+ out.ruleEvidence = re;
1433
+ });
1434
+ v1Bit(() => {
1435
+ const risk = c.risk;
1436
+ if (typeof risk === 'object' && risk !== null && risk.requiresRealApproval === true)
1437
+ out.requiresRealApproval = true;
1438
+ });
1439
+ v1Bit(() => {
1440
+ if (c.inputHasBidi === true)
1441
+ out.inputHasBidi = true;
1442
+ });
1443
+ v1Bit(() => {
1444
+ const w = c.ruleOffersAbsence;
1445
+ if (typeof w === 'string' && w !== '')
1446
+ out.ruleOffersAbsence = w;
1447
+ });
1448
+ v1Bit(() => {
1449
+ const dlf = readDenialLimitFallback(c.denialLimitFallback);
1450
+ if (dlf !== undefined)
1451
+ out.denialLimitFallback = dlf;
1452
+ });
1453
+ v1Bit(() => {
1454
+ const pair = readAskClassPair(card);
1455
+ if (pair !== undefined) {
1456
+ out.askClass = pair.askClass;
1457
+ out.classes = pair.classes;
1458
+ }
1459
+ });
1460
+ out.grantBinding = readApprovalGrantBinding(card);
1461
+ return Object.freeze(withUnreadableEvidence(card, 'v1', out));
1462
+ }
1252
1463
  const MAX_RESPOND_NOTE_CHARS = 2048;
1253
1464
  export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamArgs, signal, lane, run) {
1254
1465
  const approvalId = frame.approvalId;
@@ -1312,11 +1523,11 @@ async function presentToolApprovalFrameAndRespond(frame, approvalId, respond, st
1312
1523
  let argsFallback = false;
1313
1524
  if (typeof args !== 'object' || args === null) {
1314
1525
  argsFallback = true;
1315
- const p = pathFromGateMessage(frame.message);
1316
- args = p !== undefined ? { file_path: p } : {};
1317
- if (frame.argsOmitted === true) {
1318
- wireNote = p !== undefined ? ARGS_OMITTED_PATH_RECOVERED_NOTE : ARGS_OMITTED_NOTHING_RECOVERED_NOTE;
1319
- hostLog('debug', `liveToolApprovalWire: frame ${approvalId} args omitted (>16KiB wire cap) — card falls back to ${p !== undefined ? 'the message-derived path' : 'an empty input (no path could be derived from the message)'}`);
1526
+ const fallback = argsFallbackOf(frame.message, frame.argsOmitted);
1527
+ args = fallback.args;
1528
+ if (fallback.omittedNote !== undefined) {
1529
+ wireNote = fallback.omittedNote;
1530
+ hostLog('debug', `liveToolApprovalWire: frame ${approvalId} args omitted (>16KiB wire cap) — card falls back to ${fallback.pathRecovered ? 'the message-derived path' : 'an empty input (no path could be derived from the message)'}`);
1320
1531
  }
1321
1532
  if (lane?.argsUnavailable === true) {
1322
1533
  wireNote =
@@ -1329,7 +1540,7 @@ async function presentToolApprovalFrameAndRespond(frame, approvalId, respond, st
1329
1540
  const ruleOffers = readRuleOffers(frame.ruleOffers);
1330
1541
  const denialLimitFallback = readDenialLimitFallback(frame.denialLimitFallback);
1331
1542
  const frameShadow = readAllowRuleShadowFromWire(frame, 'frame');
1332
- const card = await surfaceCallTrackedCard(frameToolCallId, approvalId, ledgerSlot, {
1543
+ const card = await surfaceCallTrackedCard(frameToolCallId, approvalId, ledgerSlot, withUnreadableEvidence(frame, 'frame', {
1333
1544
  toolName,
1334
1545
  args: args,
1335
1546
  callKey: liveFrameCallKey(approvalId),
@@ -1373,7 +1584,9 @@ async function presentToolApprovalFrameAndRespond(frame, approvalId, respond, st
1373
1584
  ...(readAskClassPair(frame) ?? {}),
1374
1585
  ...((g) => (g !== undefined ? { boundGrants: g } : {}))(readApprovalBoundGrants(frame)),
1375
1586
  ...((w) => (w !== undefined ? { classifierNoRuling: w } : {}))(readApprovalClassifierNoRuling(frame)),
1376
- });
1587
+ allowSessionCarried: true,
1588
+ grantBinding: readApprovalGrantBinding(frame),
1589
+ }));
1377
1590
  if (hold.superseded !== undefined) {
1378
1591
  hostLog('debug', `liveToolApprovalWire: ${approvalId} was settled by the engine while its card was up${hold.superseded.parked ? ' (parked)' : ''} — card withdrawn; ` +
1379
1592
  `the card came back ${card.kind}; nothing sent`);
@@ -3,15 +3,7 @@ export type HookMatcherVerdict = {
3
3
  readonly kind: 'matchesAll';
4
4
  } | {
5
5
  readonly kind: 'accepted';
6
- readonly reading: 'names';
7
- readonly names: readonly string[];
8
- readonly aliases: readonly {
9
- readonly alias: string;
10
- readonly canonical: string;
11
- }[];
12
- } | {
13
- readonly kind: 'accepted';
14
- readonly reading: 'pattern';
6
+ readonly reading: 'names' | 'pattern';
15
7
  readonly aliases: readonly {
16
8
  readonly alias: string;
17
9
  readonly canonical: string;
@@ -1,5 +1,6 @@
1
1
  import { HOOK_TOOL_ALIASES } from './hookToolAliases.js';
2
2
  import { SETTINGS_TOOL_NAME_MATCHER_EVENTS } from './generated/settingsSchemaTables.js';
3
+ import { SETTINGS_HOOK_MATCHER_FORM, SETTINGS_HOOK_MATCHER_SELECTS } from './generated/settingsSchemaFns.js';
3
4
  const TOOL_NAME_MATCHER_EVENTS = new Set(SETTINGS_TOOL_NAME_MATCHER_EVENTS);
4
5
  const MATCHER_MAX_CHARS = 8192;
5
6
  const PATTERN_WORK_BUDGET = 10_000_000;
@@ -14,30 +15,6 @@ function refused(reading, p) {
14
15
  function aliasPairs() {
15
16
  return Object.entries(HOOK_TOOL_ALIASES).map(([alias, canonical]) => ({ alias, canonical }));
16
17
  }
17
- function literalNames(matcher) {
18
- const names = [];
19
- let first = -1;
20
- let last = -1;
21
- for (let i = 0; i <= matcher.length; i++) {
22
- const c = i < matcher.length ? matcher.charCodeAt(i) : 0x7c;
23
- if (c === 0x7c || c === 0x2c) {
24
- if (first !== -1)
25
- names.push(matcher.slice(first, last + 1));
26
- first = -1;
27
- last = -1;
28
- continue;
29
- }
30
- if (c === 0x20)
31
- continue;
32
- const nameChar = (c >= 0x30 && c <= 0x39) || (c >= 0x41 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a) || c === 0x5f || c === 0x2d;
33
- if (!nameChar)
34
- return undefined;
35
- if (first === -1)
36
- first = i;
37
- last = i;
38
- }
39
- return names;
40
- }
41
18
  const UNSUPPORTED = Symbol('unsupported');
42
19
  const SINGLE_CHAR_ESCAPES = 'dDwWsStnrfv^$\\.*+?()[]{}|/-';
43
20
  function patternBound(src, n) {
@@ -202,52 +179,35 @@ function patternBound(src, n) {
202
179
  export function hookMatcherVerdict(event, matcher) {
203
180
  if (typeof event !== 'string' || !TOOL_NAME_MATCHER_EVENTS.has(event))
204
181
  return unjudged('event_out_of_scope');
205
- if (matcher === undefined)
206
- return Object.freeze({ kind: 'matchesAll' });
207
- if (typeof matcher !== 'string')
182
+ if (matcher !== undefined && typeof matcher !== 'string')
208
183
  return unjudged('not_a_string');
209
- if (matcher.length > MATCHER_MAX_CHARS)
184
+ if (matcher !== undefined && matcher.length > MATCHER_MAX_CHARS)
210
185
  return unjudged('oversize');
211
- if (matcher === '' || matcher === '*')
212
- return Object.freeze({ kind: 'matchesAll' });
213
- const pairs = aliasPairs();
214
- const names = literalNames(matcher);
215
- if (names !== undefined) {
216
- const dead = pairs.find((p) => names.includes(p.alias) && !names.includes(p.canonical));
217
- if (dead !== undefined)
218
- return refused('names', dead);
219
- return Object.freeze({
220
- kind: 'accepted',
221
- reading: 'names',
222
- names: Object.freeze([...names]),
223
- aliases: Object.freeze(pairs.filter((p) => names.includes(p.alias)).map((p) => Object.freeze({ ...p }))),
224
- });
225
- }
226
- const src = `^(?:${matcher})$`;
227
- let re;
228
- try {
229
- re = new RegExp(src);
230
- }
231
- catch {
186
+ const form = SETTINGS_HOOK_MATCHER_FORM(matcher);
187
+ if (form === 'invalid')
232
188
  return unjudged('invalid_pattern');
189
+ const pairs = aliasPairs();
190
+ if (form === 'regex' && matcher !== undefined) {
191
+ const subjects = pairs.flatMap((p) => [p.alias, p.canonical]);
192
+ const n = subjects.reduce((a, s) => Math.max(a, s.length), 0);
193
+ const bound = patternBound(matcher, n);
194
+ if (bound === undefined)
195
+ return unjudged('pattern_unsupported');
196
+ if (bound[0] * bound[1] * (n + 1) * subjects.length > PATTERN_WORK_BUDGET)
197
+ return unjudged('over_budget');
233
198
  }
234
- const subjects = pairs.flatMap((p) => [p.alias, p.canonical]);
235
- const n = subjects.reduce((a, s) => Math.max(a, s.length), 0);
236
- const bound = patternBound(src, n);
237
- if (bound === undefined)
238
- return unjudged('pattern_unsupported');
239
- if (bound[0] * bound[1] * (n + 1) * subjects.length > PATTERN_WORK_BUDGET)
240
- return unjudged('over_budget');
241
199
  const selects = (name) => {
242
- if (matcher === name)
243
- return true;
244
200
  try {
245
- return re.test(name);
201
+ const v = SETTINGS_HOOK_MATCHER_SELECTS(matcher, name);
202
+ return typeof v === 'boolean' ? v : undefined;
246
203
  }
247
204
  catch {
248
205
  return undefined;
249
206
  }
250
207
  };
208
+ if (form === 'literal' && selects('') === true)
209
+ return Object.freeze({ kind: 'matchesAll' });
210
+ const reading = form === 'regex' ? 'pattern' : 'names';
251
211
  const selected = [];
252
212
  for (const p of pairs) {
253
213
  const a = selects(p.alias);
@@ -259,8 +219,8 @@ export function hookMatcherVerdict(event, matcher) {
259
219
  if (c === undefined)
260
220
  return unjudged('invalid_pattern');
261
221
  if (!c)
262
- return refused('pattern', p);
222
+ return refused(reading, p);
263
223
  selected.push(p);
264
224
  }
265
- return Object.freeze({ kind: 'accepted', reading: 'pattern', aliases: Object.freeze(selected.map((p) => Object.freeze({ ...p }))) });
225
+ return Object.freeze({ kind: 'accepted', reading, aliases: Object.freeze(selected.map((p) => Object.freeze({ ...p }))) });
266
226
  }
@@ -1,6 +1,6 @@
1
1
  import { engineCapNestedTrue, engineCapState, engineCapValue } from './engineCapsCache.js';
2
2
  import { displayUntrusted } from './displayUntrusted.js';
3
- import { collapseLabel } from './fleetTaskDesc.js';
3
+ import { capForDisplay, collapseLabel } from './fleetTaskDesc.js';
4
4
  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';
@@ -462,5 +462,5 @@ export function hookFailureNoticeText(n) {
462
462
  const name = collapseLabel(n.hookName);
463
463
  const tail = n.stderr !== undefined ? `: ${collapseLabel(n.stderr)}` : '';
464
464
  const line = `${HOOK_FAILURE_WARN_PREFIX}: ${name} (${code})${tail}`;
465
- return line.length <= MAX_HOOK_NOTICE_TEXT_CHARS ? line : line.slice(0, MAX_HOOK_NOTICE_TEXT_CHARS);
465
+ return capForDisplay(line, MAX_HOOK_NOTICE_TEXT_CHARS);
466
466
  }
@@ -1 +1,2 @@
1
1
  export declare function invokeHostCallbackIsolated(label: string, call: () => void): void;
2
+ export declare function reasonOfThrownWithSink(e: unknown, sink: (log: string) => void): string;
@@ -1,4 +1,5 @@
1
1
  import { hostLog } from './host.js';
2
+ import { wireFailureTextsOf } from './wireFailureShape.js';
2
3
  function faultText(e) {
3
4
  try {
4
5
  return String(e).slice(0, 160);
@@ -23,3 +24,8 @@ export function invokeHostCallbackIsolated(label, call) {
23
24
  reportHostCallbackFault(label, 'threw', e);
24
25
  }
25
26
  }
27
+ export function reasonOfThrownWithSink(e, sink) {
28
+ const t = wireFailureTextsOf(e);
29
+ invokeHostCallbackIsolated('hostCallbackGuard: onFailure', () => sink(t.log));
30
+ return t.reason;
31
+ }