@sema-agent/client-core 0.98.0 → 0.99.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/CHANGELOG.md +199 -0
  2. package/README.md +35 -22
  3. package/dist/adapt/arms.js +61 -20
  4. package/dist/adapt/panelTasks.d.ts +1 -1
  5. package/dist/adapt/panelTasks.js +2 -2
  6. package/dist/adapter/activeRunSelfHeal.d.ts +4 -3
  7. package/dist/adapter/activeRunSelfHeal.js +162 -293
  8. package/dist/adapter/downstream/eventToSdkMessage.js +52 -4
  9. package/dist/adapter/runStream.js +52 -37
  10. package/dist/adapter/types.js +2 -1
  11. package/dist/agentSession/engineSessionBackgroundStop.js +16 -8
  12. package/dist/agentsWireCaps.d.ts +0 -3
  13. package/dist/agentsWireCaps.js +33 -24
  14. package/dist/cloudConfigWireCaps.d.ts +1 -1
  15. package/dist/cloudConfigWireCaps.js +26 -4
  16. package/dist/controlRouter.d.ts +4 -2
  17. package/dist/controlRouter.js +39 -51
  18. package/dist/coreValuePorts.d.ts +26 -1
  19. package/dist/coreValuePorts.js +10 -0
  20. package/dist/corruptSessionCopy.d.ts +2 -1
  21. package/dist/corruptSessionCopy.js +3 -3
  22. package/dist/declared/supportFloorDeclared.js +1 -1
  23. package/dist/detachWire.js +3 -2
  24. package/dist/devicesFace.d.ts +34 -0
  25. package/dist/devicesFace.js +90 -0
  26. package/dist/displayUntrusted.d.ts +1 -0
  27. package/dist/displayUntrusted.js +3 -0
  28. package/dist/engineAgentPanelStore.d.ts +7 -0
  29. package/dist/engineAgentPanelStore.js +14 -0
  30. package/dist/engineCapReader.d.ts +2 -1
  31. package/dist/engineCapReader.js +7 -5
  32. package/dist/engineCapsCache.d.ts +8 -0
  33. package/dist/engineCapsCache.js +59 -6
  34. package/dist/engineCapsChange.d.ts +2 -0
  35. package/dist/engineCapsChange.js +9 -0
  36. package/dist/engineErrorCodes.d.ts +2 -1
  37. package/dist/engineErrorCodes.js +2 -7
  38. package/dist/engineRowRef.js +3 -0
  39. package/dist/engineSessionMessages.d.ts +1 -0
  40. package/dist/engineSessionMessages.js +7 -1
  41. package/dist/engineTargetSeat.d.ts +27 -0
  42. package/dist/engineTargetSeat.js +199 -0
  43. package/dist/engineWireFor.js +3 -8
  44. package/dist/env/uiLanguage.d.ts +2 -1
  45. package/dist/env/uiLanguage.js +3 -2
  46. package/dist/eventLeg.d.ts +8 -0
  47. package/dist/eventLeg.js +61 -41
  48. package/dist/fileHistoryCaptureCapability.d.ts +2 -1
  49. package/dist/fileHistoryCaptureCapability.js +12 -18
  50. package/dist/fileHistoryLegNotice.d.ts +2 -1
  51. package/dist/fileHistoryLegNotice.js +3 -3
  52. package/dist/frameBinding.d.ts +3 -0
  53. package/dist/frameBinding.js +12 -0
  54. package/dist/gateOutcome.js +16 -2
  55. package/dist/gateVocabulary.d.ts +8 -7
  56. package/dist/gateVocabulary.js +71 -73
  57. package/dist/generated/engineFactTables.d.ts +17 -1
  58. package/dist/generated/engineFactTables.js +29 -0
  59. package/dist/generated/engineNoticeTables.js +9 -3
  60. package/dist/generated/settingsSchemaFns.d.ts +6 -0
  61. package/dist/generated/settingsSchemaFns.js +57 -0
  62. package/dist/generated/settingsSchemaHooksClassifier.d.ts +2 -0
  63. package/dist/generated/settingsSchemaHooksClassifier.js +254 -0
  64. package/dist/generated/settingsSchemaTables.d.ts +1 -0
  65. package/dist/generated/settingsSchemaTables.js +4 -0
  66. package/dist/generated/settingsSchemaTypes.d.ts +105 -0
  67. package/dist/generated/settingsSchemaTypes.js +1 -0
  68. package/dist/hitl/allowRuleShadow.d.ts +2 -1
  69. package/dist/hitl/allowRuleShadow.js +17 -14
  70. package/dist/hitl/approvalCardReasons.d.ts +3 -2
  71. package/dist/hitl/approvalCardReasons.js +27 -28
  72. package/dist/hitl/approvalHolds.d.ts +3 -0
  73. package/dist/hitl/approvalHolds.js +73 -29
  74. package/dist/hitl/askClassPair.d.ts +1 -1
  75. package/dist/hitl/askClassPair.js +16 -0
  76. package/dist/hitl/askGateWire.js +2 -1
  77. package/dist/hitl/askSettlementLine.d.ts +14 -4
  78. package/dist/hitl/askSettlementLine.js +67 -47
  79. package/dist/hitl/automaticAnswerVerdict.d.ts +2 -1
  80. package/dist/hitl/automaticAnswerVerdict.js +8 -8
  81. package/dist/hitl/crashConvergedNotice.d.ts +5 -4
  82. package/dist/hitl/crashConvergedNotice.js +28 -41
  83. package/dist/hitl/frameRouter.js +7 -8
  84. package/dist/hitl/hitlBridge.d.ts +1 -0
  85. package/dist/hitl/hitlBridge.js +3 -3
  86. package/dist/hitl/persistedRulesWire.d.ts +6 -5
  87. package/dist/hitl/persistedRulesWire.js +55 -73
  88. package/dist/hitl/planReviewWire.d.ts +5 -0
  89. package/dist/hitl/planReviewWire.js +8 -0
  90. package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
  91. package/dist/hitl/sessionPolicyDeliverable.js +46 -3
  92. package/dist/hitl/sessionPolicyWire.d.ts +2 -1
  93. package/dist/hitl/sessionPolicyWire.js +23 -24
  94. package/dist/hitl/suspendedReopen.d.ts +2 -1
  95. package/dist/hitl/suspendedReopen.js +7 -10
  96. package/dist/hitl/toolApprovalWire.d.ts +17 -5
  97. package/dist/hitl/toolApprovalWire.js +79 -40
  98. package/dist/hooksWireCaps.js +145 -56
  99. package/dist/host.d.ts +21 -0
  100. package/dist/hostTurnSettings.d.ts +71 -0
  101. package/dist/hostTurnSettings.js +291 -0
  102. package/dist/humanTurn.d.ts +14 -1
  103. package/dist/humanTurn.js +100 -12
  104. package/dist/humanTurnRead.d.ts +2 -0
  105. package/dist/humanTurnRead.js +22 -1
  106. package/dist/i18n/messages.en.d.ts +582 -0
  107. package/dist/i18n/messages.en.js +582 -0
  108. package/dist/i18n/messages.zh.js +718 -1
  109. package/dist/index.d.ts +29 -13
  110. package/dist/index.js +18 -9
  111. package/dist/inheritEnvCapability.d.ts +3 -2
  112. package/dist/inheritEnvCapability.js +3 -3
  113. package/dist/inheritEnvWire.d.ts +3 -2
  114. package/dist/inheritEnvWire.js +12 -14
  115. package/dist/interactiveHalt.js +17 -6
  116. package/dist/liveModelCatalog.d.ts +2 -1
  117. package/dist/liveModelCatalog.js +14 -8
  118. package/dist/mcpPanel.d.ts +10 -1
  119. package/dist/mcpPanel.js +40 -13
  120. package/dist/mcpProbeCapability.d.ts +2 -1
  121. package/dist/mcpProbeCapability.js +7 -11
  122. package/dist/mcpProbeWire.d.ts +3 -1
  123. package/dist/mcpProbeWire.js +5 -0
  124. package/dist/mcpWireCaps.d.ts +34 -0
  125. package/dist/mcpWireCaps.js +117 -17
  126. package/dist/memoryEntriesWire.js +5 -10
  127. package/dist/model/onboardJudgement.d.ts +93 -0
  128. package/dist/model/onboardJudgement.js +415 -0
  129. package/dist/model/tierVocabulary.d.ts +2 -0
  130. package/dist/model/tierVocabulary.js +17 -5
  131. package/dist/modelCapabilityProbe.d.ts +64 -0
  132. package/dist/modelCapabilityProbe.js +600 -0
  133. package/dist/modelIdentityResolvability.d.ts +3 -0
  134. package/dist/modelIdentityResolvability.js +26 -17
  135. package/dist/ownKey.d.ts +7 -0
  136. package/dist/ownKey.js +34 -0
  137. package/dist/panelReduce.d.ts +6 -1
  138. package/dist/panelReduce.js +50 -3
  139. package/dist/permissionRuleIssue.js +2 -0
  140. package/dist/permissionRulesWriteCapability.d.ts +2 -1
  141. package/dist/permissionRulesWriteCapability.js +8 -6
  142. package/dist/pluginHooksWire.d.ts +46 -3
  143. package/dist/pluginHooksWire.js +217 -11
  144. package/dist/printModelStatus.d.ts +63 -0
  145. package/dist/printModelStatus.js +155 -0
  146. package/dist/request/taskRequest.d.ts +11 -5
  147. package/dist/request/taskRequest.js +112 -16
  148. package/dist/resumeRefusalCopy.d.ts +12 -9
  149. package/dist/resumeRefusalCopy.js +70 -143
  150. package/dist/retryStatus.d.ts +37 -0
  151. package/dist/retryStatus.js +79 -0
  152. package/dist/scenarioRefusal.d.ts +9 -0
  153. package/dist/scenarioRefusal.js +111 -0
  154. package/dist/seam.d.ts +25 -1
  155. package/dist/seam.js +10 -1
  156. package/dist/seatContract.d.ts +260 -10
  157. package/dist/seatContract.js +692 -19
  158. package/dist/selfOrchestrationDenial.js +7 -19
  159. package/dist/sessionIdSegment.d.ts +6 -0
  160. package/dist/sessionIdSegment.js +24 -0
  161. package/dist/sessionMemoryStatus.js +6 -11
  162. package/dist/sessionPolicyCapability.d.ts +2 -1
  163. package/dist/sessionPolicyCapability.js +8 -6
  164. package/dist/settingsHooksSalvage.d.ts +44 -0
  165. package/dist/settingsHooksSalvage.js +211 -0
  166. package/dist/skillToolListsCapability.d.ts +2 -1
  167. package/dist/skillToolListsCapability.js +8 -6
  168. package/dist/sseIdleTriage.js +3 -2
  169. package/dist/subagent/engineSubagentResume.js +15 -9
  170. package/dist/subagentContentStore.d.ts +3 -0
  171. package/dist/subagentContentStore.js +22 -0
  172. package/dist/toolHistoryMismatch.js +3 -2
  173. package/dist/toolRoster.d.ts +3 -2
  174. package/dist/toolRoster.js +21 -20
  175. package/dist/turnFailurePresentation.d.ts +12 -1
  176. package/dist/turnFailurePresentation.js +212 -15
  177. package/dist/usageAnalytics.js +6 -11
  178. package/dist/userAttachmentEnvelope.d.ts +1 -0
  179. package/dist/userAttachmentEnvelope.js +37 -7
  180. package/dist/userAttachmentSeat.d.ts +21 -0
  181. package/dist/userAttachmentSeat.js +75 -0
  182. package/dist/userInvokedSkillsCapability.d.ts +11 -1
  183. package/dist/userInvokedSkillsCapability.js +31 -7
  184. package/dist/wireErrorTriage.d.ts +7 -0
  185. package/dist/wireErrorTriage.js +23 -1
  186. package/dist/wireFailureShape.js +2 -1
  187. package/dist/wireRefusalCopy.d.ts +13 -1
  188. package/dist/wireRefusalCopy.js +24 -28
  189. package/dist/workflowsJournalCapability.d.ts +2 -1
  190. package/dist/workflowsJournalCapability.js +8 -6
  191. package/docs/INTEGRATION-CLIENTS.md +542 -30
  192. package/package.json +5 -5
@@ -8,7 +8,7 @@ import { PROTOCOL_ERROR_NAME, THROWN_SLOT_UNREADABLE, protocolErrorNameReading,
8
8
  import { APPROVAL_BINDING_MISMATCH, CHECKPOINT_INVALID_OUTCOME, RESUME_POLICY_FOLD_CODE } from '../engineErrorCodes.js';
9
9
  import { suspendedReopenOf } from './suspendedReopen.js';
10
10
  export const DEFAULT_DENY_REASON = 'The user rejected this tool use';
11
- const MAX_DENY_REASON_CHARS = 4096;
11
+ export const MAX_DENY_REASON_CHARS = 4096;
12
12
  export function denyReasonForWire(reason, tag) {
13
13
  if (typeof reason !== 'string')
14
14
  return undefined;
@@ -146,13 +146,13 @@ function isTransientDecideTransportFailure(e, depth = 0) {
146
146
  return false;
147
147
  if (thrownIsInstanceOf(e, HitlSafetyError))
148
148
  return false;
149
- const status = readThrownSlot(e, 'status');
149
+ const status = readThrownSlot(e, 'status', 'data');
150
150
  if (status === THROWN_SLOT_UNREADABLE || typeof status === 'number')
151
151
  return false;
152
152
  const name = readThrownSlot(e, 'name');
153
153
  if (name === 'TimeoutError' || name === 'AbortError')
154
154
  return true;
155
- const code = readThrownSlot(e, 'code');
155
+ const code = readThrownSlot(e, 'code', 'data');
156
156
  if (typeof code === 'string' && TRANSIENT_NETWORK_CODES.has(code))
157
157
  return true;
158
158
  const message = readThrownSlot(e, 'message');
@@ -1,4 +1,5 @@
1
1
  import type { CcImportLayer, CcImportPrepareResult, CcImportRedeemResult, PersistedRule, RuleBehavior, RuleListParams, RuleListResult, RuleRevokeRequest, RemovalLiveness, RuleRevokeResult, RuleWriteRequest, RuleWriteResult } from '@sema-agent/sdk';
2
+ import type { UiLanguage } from '../env/uiLanguage.js';
2
3
  export interface RulesFacade {
3
4
  list(params?: RuleListParams, opts?: {
4
5
  signal?: AbortSignal;
@@ -93,9 +94,9 @@ export interface PersistedRuleOriginsRow {
93
94
  readonly origin?: string | undefined;
94
95
  }[] | undefined;
95
96
  }
96
- export declare function persistedRuleAddOriginLabel(origin: string | undefined): string;
97
- export declare function persistedRuleOriginsLabel(rule: PersistedRuleOriginsRow): string;
98
- export declare function persistedRuleScopeLabel(scope: string | undefined): string;
97
+ export declare function persistedRuleAddOriginLabel(origin: string | undefined, lang?: UiLanguage): string;
98
+ export declare function persistedRuleOriginsLabel(rule: PersistedRuleOriginsRow, lang?: UiLanguage): string;
99
+ export declare function persistedRuleScopeLabel(scope: string | undefined, lang?: UiLanguage): string;
99
100
  export type PersistedRuleRevokeOutcomeWord = 'removed' | 'nothing-written' | 'unknown-status';
100
101
  export interface PersistedRuleRevokeResultBody {
101
102
  readonly status?: string | undefined;
@@ -107,11 +108,11 @@ export interface PersistedRuleRevokeOutcome {
107
108
  readonly notice: string;
108
109
  readonly change: string;
109
110
  }
110
- export declare function persistedRuleRevokeOutcome(ruleText: string | undefined, result: PersistedRuleRevokeResultBody | undefined): PersistedRuleRevokeOutcome;
111
+ export declare function persistedRuleRevokeOutcome(ruleText: string | undefined, result: PersistedRuleRevokeResultBody | undefined, lang?: UiLanguage): PersistedRuleRevokeOutcome;
111
112
  export interface PersistedRuleMatchRow {
112
113
  readonly match?: string | undefined;
113
114
  }
114
- export declare function persistedRuleMatchLabel(ruleOrMatch: string | PersistedRuleMatchRow | undefined): string;
115
+ export declare function persistedRuleMatchLabel(ruleOrMatch: string | PersistedRuleMatchRow | undefined, lang?: UiLanguage): string;
115
116
  export declare function revokeTargetFromPersistedRule(rule: unknown, opts?: {
116
117
  principal?: string;
117
118
  }): RuleRevokeRequest | undefined;
@@ -4,6 +4,7 @@ import { CORE_RULE_BEHAVIORS } from '../generated/engineFactTables.js';
4
4
  import { wireFailureShapeOf } from '../wireFailureShape.js';
5
5
  import { CAPABILITY_OPERATOR_PRINCIPALS_REQUIRED } from '../engineErrorCodes.js';
6
6
  import { hostLog } from '../host.js';
7
+ import { msg, renderMessage } from '../i18n/translate.js';
7
8
  import { guardedRead, readOwnDataValue } from '../ownKey.js';
8
9
  import { observedPermissionRulesWrite, permissionRulesWriteAvailable } from '../permissionRulesWriteCapability.js';
9
10
  import { isToolApprovalRespondReplayed, readToolApprovalRespondAck } from './toolApprovalWire.js';
@@ -114,123 +115,104 @@ export const PERSISTED_RULE_BEHAVIOR_UNKNOWN = '(unknown)';
114
115
  export function persistedRuleBehaviorLabel(rule) {
115
116
  return rowStr(rule, 'behavior') ?? PERSISTED_RULE_BEHAVIOR_UNKNOWN;
116
117
  }
117
- const PERSISTED_RULE_ORIGIN_PHRASES = Object.freeze({
118
- user: 'added by you',
119
- 'imported-cc': 'imported',
120
- starter: 'preset',
118
+ const PERSISTED_RULE_ORIGIN_KEYS = Object.freeze({
119
+ user: 'rules.origin.user',
120
+ 'imported-cc': 'rules.origin.importedCc',
121
+ starter: 'rules.origin.starter',
121
122
  });
122
- const UNKNOWN_ORIGIN_PHRASE = 'an origin this build does not know';
123
- const NO_ORIGIN_PHRASE = 'unknown origin';
123
+ const UNKNOWN_ORIGIN_KEY = 'rules.origin.unknownWord';
124
+ const NO_ORIGIN_KEY = 'rules.origin.none';
125
+ function originKeyOf(origin) {
126
+ return typeof origin === 'string' && Object.hasOwn(PERSISTED_RULE_ORIGIN_KEYS, origin) ? PERSISTED_RULE_ORIGIN_KEYS[origin] : UNKNOWN_ORIGIN_KEY;
127
+ }
124
128
  function ownSlot(o, key) {
125
129
  if (typeof o !== 'object' || o === null)
126
130
  return undefined;
127
131
  return guardedRead(() => readOwnDataValue(o, key));
128
132
  }
129
133
  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
+ export function persistedRuleAddOriginLabel(origin, lang) {
135
+ return renderMessage(msg(originKeyOf(origin)), lang);
134
136
  }
135
- export function persistedRuleOriginsLabel(rule) {
137
+ export function persistedRuleOriginsLabel(rule, lang) {
136
138
  const adds = ownSlot(rule, 'adds');
137
139
  const isArr = guardedRead(() => (Array.isArray(adds) ? true : undefined));
138
140
  if (isArr !== true)
139
- return NO_ORIGIN_PHRASE;
141
+ return renderMessage(msg(NO_ORIGIN_KEY), lang);
140
142
  const lenRaw = ownSlot(adds, 'length');
141
143
  const len = typeof lenRaw === 'number' && Number.isSafeInteger(lenRaw) && lenRaw > 0 ? Math.min(lenRaw, ORIGINS_READ_MAX) : 0;
142
144
  const seen = [];
143
145
  for (let i = 0; i < len; i++) {
144
146
  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);
147
+ const key = originKeyOf(typeof origin === 'string' ? origin : undefined);
148
+ if (!seen.includes(key))
149
+ seen.push(key);
148
150
  }
149
- return seen.length === 0 ? NO_ORIGIN_PHRASE : seen.join(' + ');
151
+ return seen.length === 0 ? renderMessage(msg(NO_ORIGIN_KEY), lang) : seen.map((k) => renderMessage(msg(k), lang)).join(renderMessage(msg('rules.origin.join'), lang));
150
152
  }
151
- const UNKNOWN_SCOPE_PHRASE = 'a scope this build does not know';
152
- export function persistedRuleScopeLabel(scope) {
153
+ const UNKNOWN_SCOPE_KEY = 'rules.scope.unknown';
154
+ export function persistedRuleScopeLabel(scope, lang) {
153
155
  if (scope === 'global')
154
- return 'all projects';
156
+ return renderMessage(msg('rules.scope.all'), lang);
155
157
  if (typeof scope === 'string' && scope.startsWith('project:') && scope.length > 'project:'.length) {
156
158
  const shown = displayUntrusted(scope.slice('project:'.length), { max: 400, blanks: true });
157
- return shown === '' ? UNKNOWN_SCOPE_PHRASE : shown;
159
+ return shown === '' ? renderMessage(msg(UNKNOWN_SCOPE_KEY), lang) : shown;
158
160
  }
159
- return UNKNOWN_SCOPE_PHRASE;
161
+ return renderMessage(msg(UNKNOWN_SCOPE_KEY), lang);
160
162
  }
161
- const PERSISTED_RULE_REVOKE_LINES = Object.freeze({
163
+ const PERSISTED_RULE_REVOKE_KEYS = Object.freeze({
162
164
  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}' },
165
+ yes: { notice: 'rules.revoke.removed.yes.notice', change: 'rules.revoke.removed.yes.change' },
166
+ unknown: { notice: 'rules.revoke.removed.unknown.notice', change: 'rules.revoke.removed.unknown.change' },
167
+ no: { notice: 'rules.revoke.removed.no.notice', change: 'rules.revoke.removed.no.change' },
172
168
  },
173
169
  '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)' },
170
+ yes: { notice: 'rules.revoke.nothingWritten.yes.notice', change: 'rules.revoke.nothingWritten.yes.change' },
171
+ unknown: { notice: 'rules.revoke.nothingWritten.unknown.notice', change: 'rules.revoke.nothingWritten.unknown.change' },
172
+ no: { notice: 'rules.revoke.nothingWritten.no.notice', change: 'rules.revoke.nothingWritten.no.change' },
183
173
  },
184
174
  });
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: '' },
175
+ const REVOKE_UNKNOWN_STATUS_KEYS = Object.freeze({
176
+ absent: { notice: 'rules.revoke.absent.notice', change: 'rules.revoke.absent.change' },
177
+ unrecognised: { notice: 'rules.revoke.unrecognised.notice', change: 'rules.revoke.unrecognised.change' },
178
+ liveness: { yes: 'rules.revoke.liveness.yes', unknown: 'rules.revoke.liveness.unknown', no: undefined },
195
179
  });
196
- const fillRule = (template, rule) => template.split('{rule}').join(rule);
197
- export function persistedRuleRevokeOutcome(ruleText, result) {
180
+ export function persistedRuleRevokeOutcome(ruleText, result, lang) {
198
181
  const quoted = typeof ruleText === 'string' ? quoteUntrustedForSentence(ruleText, 120) : undefined;
199
- const rule = quoted ?? 'this rule';
182
+ const rule = quoted ?? msg('rules.revoke.thisRule');
200
183
  const status = ownSlot(result, 'status');
201
184
  const rawLive = ownSlot(result, 'stillLive');
202
185
  const liveness = rawLive === 'yes' || rawLive === 'no' || rawLive === 'unknown' ? rawLive : 'unknown';
203
186
  if (status === 'removed' || status === 'no-op') {
204
187
  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) });
188
+ const line = PERSISTED_RULE_REVOKE_KEYS[outcome][liveness];
189
+ return Object.freeze({ outcome, liveness, notice: renderMessage(msg(line.notice, { rule }), lang), change: renderMessage(msg(line.change, { rule }), lang) });
207
190
  }
208
- const head = typeof status === 'string' && status !== '' ? REVOKE_UNKNOWN_STATUS.unrecognised : REVOKE_UNKNOWN_STATUS.absent;
191
+ const head = typeof status === 'string' && status !== '' ? REVOKE_UNKNOWN_STATUS_KEYS.unrecognised : REVOKE_UNKNOWN_STATUS_KEYS.absent;
192
+ const tailKey = REVOKE_UNKNOWN_STATUS_KEYS.liveness[liveness];
209
193
  return Object.freeze({
210
194
  outcome: 'unknown-status',
211
195
  liveness,
212
- notice: `${fillRule(head.notice, rule)}${REVOKE_UNKNOWN_STATUS.liveness[liveness]}`,
213
- change: fillRule(head.change, rule),
196
+ notice: `${renderMessage(msg(head.notice, { rule }), lang)}${tailKey === undefined ? '' : renderMessage(msg(tailKey), lang)}`,
197
+ change: renderMessage(msg(head.change, { rule }), lang),
214
198
  });
215
199
  }
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)',
200
+ const PERSISTED_RULE_MATCH_KEYS = Object.freeze({
201
+ exact: 'rules.match.exact',
202
+ prefix: 'rules.match.prefix',
203
+ wildcard: 'rules.match.wildcard',
204
+ subpath: 'rules.match.subpath',
205
+ path: 'rules.match.path',
206
+ name: 'rules.match.name',
207
+ name_prefix: 'rules.match.namePrefix',
208
+ host: 'rules.match.host',
209
+ subdomain: 'rules.match.subdomain',
226
210
  });
227
- export function persistedRuleMatchLabel(ruleOrMatch) {
211
+ export function persistedRuleMatchLabel(ruleOrMatch, lang) {
228
212
  const word = typeof ruleOrMatch === 'string' ? ruleOrMatch : ownSlot(ruleOrMatch, 'match');
229
213
  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';
214
+ return renderMessage(msg('rules.match.unreported'), lang);
215
+ return renderMessage(msg(Object.hasOwn(PERSISTED_RULE_MATCH_KEYS, word) ? PERSISTED_RULE_MATCH_KEYS[word] : 'rules.match.unknown'), lang);
234
216
  }
235
217
  export function revokeTargetFromPersistedRule(rule, opts) {
236
218
  const behavior = persistedRuleBehaviorOf(rule);
@@ -37,6 +37,11 @@ export interface PlanReviewCardLike {
37
37
  }>;
38
38
  }>;
39
39
  }
40
+ export interface PlanReviewQuestionIdReading {
41
+ readonly taskId: string;
42
+ readonly reopened: boolean;
43
+ }
44
+ export declare function planReviewTaskIdFromQuestionId(questionId: {} | null | undefined): PlanReviewQuestionIdReading | undefined;
40
45
  export declare function planReviewOfferedModeOf(card: string | PlanReviewCardLike): PlanReviewOfferedMode;
41
46
  export interface ArmPlanReviewOptions {
42
47
  submittedInPlanMode?: boolean;
@@ -300,6 +300,14 @@ function offeredModeFromLabels(card) {
300
300
  return 'two_choice';
301
301
  return undefined;
302
302
  }
303
+ export function planReviewTaskIdFromQuestionId(questionId) {
304
+ if (typeof questionId !== 'string')
305
+ return undefined;
306
+ const taskId = taskIdFromPlanReviewQuestionId(questionId);
307
+ if (taskId === undefined)
308
+ return undefined;
309
+ return Object.freeze({ taskId, reopened: questionId.includes(REOPEN_ID_TAIL) });
310
+ }
303
311
  function offeredModeFromQuestionId(questionId) {
304
312
  if (taskIdFromPlanReviewQuestionId(questionId) === undefined)
305
313
  return 'unknown';
@@ -1,11 +1,13 @@
1
1
  import type { SessionPermissionRules } from '@sema-agent/sdk';
2
2
  import type { ToolRosterView } from '../toolRoster.js';
3
+ import type { SessionRuleInertReason } from './sessionPolicyWire.js';
3
4
  export type SessionPolicyWithheldWhy = 'ask_no_bucket' | 'qualified_deny' | 'peer_wide' | 'wildcard' | 'not_a_tool_name' | 'legacy_tool_name' | 'not_in_roster';
4
5
  export declare const SESSION_POLICY_WITHHELD_WHY: readonly SessionPolicyWithheldWhy[];
5
6
  export interface SessionPolicyWithheldRule {
6
7
  readonly rule: string;
7
8
  readonly why: SessionPolicyWithheldWhy;
8
9
  readonly currentName?: string;
10
+ readonly inertReason?: SessionRuleInertReason;
9
11
  }
10
12
  export interface SessionPolicyDeliverability {
11
13
  readonly deliverable: SessionPermissionRules;
@@ -1,6 +1,8 @@
1
1
  import { CONFIG_LEGACY_TOOL_NAME } from '../engineErrorCodes.js';
2
2
  import { rosterMountedNames } from '../rosterMountedNames.js';
3
3
  import { ruleCompileVerdict } from '../ruleCompileVerdict.js';
4
+ import { readRuleEntry } from '../coreValuePorts.js';
5
+ import { readOwnDataValue } from '../ownKey.js';
4
6
  import { ruleToolNameVerdictOf } from '../protocolSegment.js';
5
7
  import { PREFIXES_IN_PROSE, REFUSED_NAME_CLASSES, REFUSED_NAME_FIX } from './refusedToolNameProse.js';
6
8
  import { CORE_PROTOCOL_PREFIXES } from '../generated/toolNameTables.js';
@@ -90,8 +92,9 @@ export function sessionPolicyDeliverable(behavior, rules, opts) {
90
92
  continue;
91
93
  }
92
94
  let why = withheldWhyOf(r);
95
+ const engineAsked = why === undefined;
93
96
  let currentName;
94
- if (why === undefined) {
97
+ if (engineAsked) {
95
98
  const verdict = ruleToolNameVerdictOf(r);
96
99
  if (verdict.kind === 'unknown')
97
100
  return unreadable();
@@ -103,6 +106,17 @@ export function sessionPolicyDeliverable(behavior, rules, opts) {
103
106
  else if (verdict.kind === 'unmintable_segment')
104
107
  why = 'not_a_tool_name';
105
108
  }
109
+ let inertReason;
110
+ if (engineAsked) {
111
+ const reading = entryReadingOf(r);
112
+ if (reading === 'unknown')
113
+ return unreadable();
114
+ if (reading !== 'row') {
115
+ inertReason = reading.reason;
116
+ if (why === undefined)
117
+ why = reading.why;
118
+ }
119
+ }
106
120
  if (why === undefined) {
107
121
  const grammar = ruleCompileVerdict(r, 'deny').kind;
108
122
  if (grammar === 'unknown')
@@ -115,13 +129,42 @@ export function sessionPolicyDeliverable(behavior, rules, opts) {
115
129
  if (why === undefined)
116
130
  exact.push(r);
117
131
  else {
118
- withheld.push(why === 'legacy_tool_name' && currentName !== undefined ? { rule: r, why, currentName } : { rule: r, why });
132
+ withheld.push({
133
+ rule: r,
134
+ why,
135
+ ...(why === 'legacy_tool_name' && currentName !== undefined ? { currentName } : {}),
136
+ ...(inertReason !== undefined ? { inertReason } : {}),
137
+ });
119
138
  }
120
139
  }
121
- if (withheld.length > 0 || exact.length === 0)
140
+ const blocking = withheld.some((w) => w.inertReason === undefined);
141
+ if (blocking || exact.length === 0)
122
142
  return { deliverable: {}, withheld };
123
143
  return { deliverable: { toolDeny: exact }, withheld };
124
144
  }
145
+ function entryReadingOf(rule) {
146
+ try {
147
+ const reading = readRuleEntry(rule, 'deny');
148
+ if (typeof reading !== 'object' || reading === null)
149
+ return 'unknown';
150
+ const kind = readOwnDataValue(reading, 'kind');
151
+ if (kind === 'row') {
152
+ const compiled = readOwnDataValue(reading, 'compiled');
153
+ return typeof compiled === 'object' && compiled !== null ? 'row' : 'unknown';
154
+ }
155
+ if (kind !== 'inert')
156
+ return 'unknown';
157
+ const reason = readOwnDataValue(reading, 'reason');
158
+ if (reason === 'grammar' || reason === 'content_unsupported')
159
+ return { why: 'not_a_tool_name', reason };
160
+ if (reason === 'wildcard_all' || reason === 'namespace_wildcard')
161
+ return { why: 'wildcard', reason };
162
+ return 'unknown';
163
+ }
164
+ catch {
165
+ return 'unknown';
166
+ }
167
+ }
125
168
  export function sessionPolicyWithheldNotice(why) {
126
169
  return typeof why === 'string' && Object.hasOwn(WITHHELD_NOTICE, why)
127
170
  ? WITHHELD_NOTICE[why]
@@ -1,4 +1,5 @@
1
1
  import type { SessionPermissionRules, StoredSessionRules } from '@sema-agent/sdk';
2
+ import type { UiLanguage } from '../env/uiLanguage.js';
2
3
  import type { SessionPolicyReading } from '../sessionPolicyCapability.js';
3
4
  import type { ToolRosterView } from '../toolRoster.js';
4
5
  import { CORE_ALLOW_ENTRY_INERT_REASONS, CORE_RULE_TOOL_NAME_VERDICTS } from '../generated/engineFactTables.js';
@@ -127,7 +128,7 @@ export interface SessionPolicyInertEntryRefusal {
127
128
  export declare function tightenSessionPolicy(facade: SessionPolicyFacade, req: SessionPolicyTightenRequest, opts?: {
128
129
  signal?: AbortSignal;
129
130
  }): Promise<SessionPolicyTightenOutcome>;
130
- export declare function sessionPolicyTightenNotice(outcome: SessionPolicyTightenOutcome): string;
131
+ export declare function sessionPolicyTightenNotice(outcome: SessionPolicyTightenOutcome, lang?: UiLanguage): string;
131
132
  export declare function sessionPolicyReadNotice(outcome: Exclude<SessionPolicyReadOutcome, {
132
133
  kind: 'present';
133
134
  }> | {
@@ -1,5 +1,6 @@
1
1
  import { wireFailureShapeOf } from '../wireFailureShape.js';
2
2
  import { hostLog } from '../host.js';
3
+ import { msg, renderMessage } from '../i18n/translate.js';
3
4
  import { ruleToolNameVerdictOf } from '../protocolSegment.js';
4
5
  import { RULES_INERT_ENTRY, RULES_INVALID_SHAPE, isRulesRefusalCode } from '../engineErrorCodes.js';
5
6
  import { deniedEntryToolName } from '../engineToolDirectory.js';
@@ -411,50 +412,48 @@ export async function tightenSessionPolicy(facade, req, opts) {
411
412
  return second.done;
412
413
  return { kind: 'conflict', rev: second.retryAtRev };
413
414
  }
414
- const SESSION_POLICY_INERT_ENTRY_WRITE_NOTE = 'The engine refused to write these session rules, and the stored record was not changed at all: one entry in them reads as matching nothing — written in, it would neither block nor allow any call (the engine’s own error text names the entry and why). Correct that entry or take it out, then write the rules again. 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.';
415
- const SESSION_POLICY_EARLIER_GRAMMAR_NOTE = 'Nothing was written: this session’s rules were saved before the current rule grammar, when an allow entry written in a tool’s own rule form (such as Bash(git:*)) was read as a plain tool name and so allowed nothing. Writing the record back now would read those entries in the current grammar, where they do allow calls — a widening nobody asked for — so the record was left as it is. Rewrite this session’s allow entries in the current form, or take those entries out, before changing its rules here.';
416
- export function sessionPolicyTightenNotice(outcome) {
415
+ const earlierGrammarNote = (lang) => renderMessage(msg('rules.sessionPolicy.tighten.earlierGrammar'), lang);
416
+ export function sessionPolicyTightenNotice(outcome, lang) {
417
+ const say = (key, params) => renderMessage(msg(key, params), lang);
417
418
  switch (outcome.kind) {
418
419
  case 'written':
419
- return `Session rules saved (version ${outcome.rev}) — the record now holds everything it already had plus the entries sent here, and it applies from this session’s next tool gate onward; the step already running is not interrupted.`;
420
+ return say('rules.sessionPolicy.tighten.written', { rev: outcome.rev });
420
421
  case 'conflict':
421
- return 'Session rules were changed by someone else while this tightening was being written, twice in a row — nothing was written. Re-read the current rules and try again, or let the other writer finish first.';
422
+ return say('rules.sessionPolicy.tighten.conflict');
422
423
  case 'loosen_forbidden':
423
- return 'The engine refused this write because it would relax the session rules: at least one entry sent here widens what is allowed rather than narrowing it. Only entries that add restrictions are accepted on this path.';
424
+ return say('rules.sessionPolicy.tighten.loosenForbidden');
424
425
  case 'capability_absent':
425
- return outcome.why === 'absent'
426
- ? 'This deployment does not keep per-session tool rules, so there is nothing to tighten here.'
427
- : 'This engine does not say whether it keeps per-session tool rules — it predates that answer — so the tightening entry stays hidden rather than being written blind.';
426
+ return outcome.why === 'absent' ? say('rules.sessionPolicy.tighten.capabilityAbsent') : say('rules.sessionPolicy.tighten.capabilityNotReported');
428
427
  case 'refused':
429
- return SESSION_POLICY_EARLIER_GRAMMAR_NOTE;
428
+ return earlierGrammarNote(lang);
430
429
  case 'inert_entry':
431
- return SESSION_POLICY_INERT_ENTRY_WRITE_NOTE;
430
+ return say('rules.sessionPolicy.tighten.inertEntry');
432
431
  case 'unknown':
433
432
  switch (outcome.why) {
434
433
  case 'face_unavailable':
435
- return 'This deployment does not keep per-session tool rules, so nothing was written.';
434
+ return say('rules.sessionPolicy.tighten.unknown.faceUnavailable');
436
435
  case 'session_not_found':
437
- return 'This session is not readable from here — it may not exist, or it may belong to someone else (the engine answers both the same way, so this client cannot tell which); nothing was written.';
436
+ return say('rules.sessionPolicy.tighten.unknown.sessionNotFound');
438
437
  case 'session_ownerless':
439
- return 'This session has no owner, so a rule written for it could never be read back; nothing was written. Attach an identity to the session and try again.';
438
+ return say('rules.sessionPolicy.tighten.unknown.sessionOwnerless');
440
439
  case 'unauthorized':
441
- return 'This call could not present a verifiable identity, so nothing was written.';
440
+ return say('rules.sessionPolicy.tighten.unknown.unauthorized');
442
441
  case 'request_rejected':
443
- return 'The engine rejected the shape of this rule record, so nothing was written. Fix the entries before sending them again.';
442
+ return say('rules.sessionPolicy.tighten.unknown.requestRejected');
444
443
  case 'store_corrupt':
445
- return 'The engine could not establish which version this session’s rules are at and refused to stamp a new one, so nothing was written. The entries sent here are not the problem — this needs an operator to look at the rule store.';
444
+ return say('rules.sessionPolicy.tighten.unknown.storeCorrupt');
446
445
  case 'read_unreadable':
447
- return 'The session’s current rules could not be read, so nothing was written — writing over a record that cannot be read would replace real restrictions with an empty one.';
446
+ return say('rules.sessionPolicy.tighten.unknown.readUnreadable');
448
447
  case 'read_failed':
449
- return 'The session’s current rules could not be fetched, so nothing was written.';
448
+ return say('rules.sessionPolicy.tighten.unknown.readFailed');
450
449
  case 'write_refused':
451
- return 'The engine refused this write, so nothing was written. Re-read the current rules before trying again.';
450
+ return say('rules.sessionPolicy.tighten.unknown.writeRefused');
452
451
  case 'write_indeterminate':
453
- return 'The write never came back with an answer from the engine — it may or may not have taken effect. Re-read the current rules before writing anything else.';
452
+ return say('rules.sessionPolicy.tighten.unknown.writeIndeterminate');
454
453
  case 'write_receipt_unreadable':
455
- return 'The tightening was sent but the engine’s answer could not be read — it may already be in effect. Re-read the current rules before writing anything else.';
454
+ return say('rules.sessionPolicy.tighten.unknown.writeReceiptUnreadable');
456
455
  case 'write_receipt_mismatch':
457
- return 'The tightening was sent but the engine’s answer does not account for it (the version did not advance, the entries sent here are not in the returned record, or the record came back without the rule-grammar mark it was sent with, so its entries may now read differently) — it may already be in effect. Re-read the current rules before writing anything else.';
456
+ return say('rules.sessionPolicy.tighten.unknown.writeReceiptMismatch');
458
457
  }
459
458
  }
460
459
  }
@@ -718,7 +717,7 @@ export function sessionPolicyRemovalNotice(outcome) {
718
717
  case 'write_unconfirmed':
719
718
  return 'The removal was sent but no clear answer came back from the engine — it may already be in effect. Run the removal again: it re-reads the record, and reports nothing left to remove if it did take effect.';
720
719
  case 'refused':
721
- return SESSION_POLICY_EARLIER_GRAMMAR_NOTE;
720
+ return earlierGrammarNote();
722
721
  case 'inert_entry':
723
722
  return 'Nothing was changed: the engine refused to write this session’s rule record back, because an entry this removal keeps reads as matching nothing (the engine’s own error text names the entry and why). This removal only takes out names the engine refuses to start a run with, so it leaves that entry for a person to correct or remove; while the record holds it, it cannot be written, so the entries this removal meant to take out stay in it as well.';
724
723
  default:
@@ -1,3 +1,4 @@
1
+ import type { UiLanguage } from '../env/uiLanguage.js';
1
2
  export type SuspendedReopenReading = {
2
3
  readonly kind: 'reopened';
3
4
  readonly code: string;
@@ -13,4 +14,4 @@ export interface ResumeReopenDetail {
13
14
  retriable: true;
14
15
  }
15
16
  export declare function resumeReopenFromError(err: unknown): ResumeReopenDetail | null;
16
- export declare function resumeReopenContent(detail: ResumeReopenDetail): string;
17
+ export declare function resumeReopenContent(detail: ResumeReopenDetail, lang?: UiLanguage): string;
@@ -1,4 +1,5 @@
1
1
  import { RESUME_REOPEN_CODES, RESUME_ENV_FAILED, RESUME_TOOL_UNAVAILABLE, refusalSaysStillPending } from '../engineErrorCodes.js';
2
+ import { msg, renderMessage } from '../i18n/translate.js';
2
3
  import { guardedRead, ownDataField } from '../ownKey.js';
3
4
  const UNSTATED = Object.freeze({ kind: 'unstated' });
4
5
  const NOT_REOPENED = Object.freeze({ kind: 'not_reopened' });
@@ -31,15 +32,11 @@ export function resumeReopenFromError(err) {
31
32
  const reason = code.slice('resume.'.length);
32
33
  return { code, reason, retriable: true };
33
34
  }
34
- export function resumeReopenContent(detail) {
35
- const first = detail.code === RESUME_ENV_FAILED
36
- ? 'The execution environment for this parked work could not be brought back'
35
+ export function resumeReopenContent(detail, lang) {
36
+ const first = msg(detail.code === RESUME_ENV_FAILED
37
+ ? 'resume.reopen.first.envFailed'
37
38
  : detail.code === RESUME_TOOL_UNAVAILABLE
38
- ? 'The tool this approval was granted for is not available on this engine'
39
- : 'The tool this approval was granted for has changed since the approval was recorded';
40
- return [
41
- first,
42
- 'The engine re-parked the work before consuming anything — the approval is still pending and your decision was not consumed',
43
- 'Re-fetch the pending approvals and decide again on an engine where the same tool is available',
44
- ].join(' · ');
39
+ ? 'resume.reopen.first.toolUnavailable'
40
+ : 'resume.reopen.first.toolContractMismatch');
41
+ return renderMessage(msg('resume.reopen.content', { first }), lang);
45
42
  }
@@ -1,5 +1,7 @@
1
1
  import { type HitlClientLike, type DecideOperationObserver } from './hitlBridge.js';
2
2
  import { type ApprovalAllowRuleShadow } from './allowRuleShadow.js';
3
+ import type { UiLanguage } from '../env/uiLanguage.js';
4
+ import type { SessionRuleInertReason } from './sessionPolicyWire.js';
3
5
  import { type ApprovalCardClaim } from './approvalHolds.js';
4
6
  import { type ApprovalResolution } from './approvalResolution.js';
5
7
  import { type ApprovalMandateWord } from '../gateVocabulary.js';
@@ -243,14 +245,21 @@ export declare function decisionAttributionKeyOf(reading: ApprovalDecidedByReadi
243
245
  settledBy: 'policy';
244
246
  } | Record<never, never>;
245
247
  export declare function isToolApprovalFrame(ev: unknown): ev is ToolApprovalFrame;
246
- export declare function askProbeReasonDetail(card: Pick<ApprovalCardRequest, 'probeReason' | 'probeCause'> | null | undefined): string | undefined;
248
+ export declare function askProbeReasonDetail(card: Pick<ApprovalCardRequest, 'probeReason' | 'probeCause'> | null | undefined, lang?: UiLanguage): string | undefined;
247
249
  export declare function readApprovalRememberRefused(v: unknown): boolean;
248
250
  export declare function readApprovalBoundGrants(v: unknown): BoundSkillGrantsWire | undefined;
251
+ export type BoundGrantEntryReading = {
252
+ readonly kind: 'rule';
253
+ } | {
254
+ readonly kind: 'reads_as_nothing';
255
+ readonly reason?: SessionRuleInertReason;
256
+ };
257
+ export declare function readBoundGrantEntry(entry: string): BoundGrantEntryReading | undefined;
249
258
  export type ApprovalGrantBinding = 'bound' | 'none' | 'unreadable';
250
259
  export declare function readApprovalClassifierNoRuling(v: unknown): string | undefined;
251
- export declare function classifierNoRulingDetail(word: string | undefined): string;
252
- export declare function approvalBoundGrantsDetail(grants: BoundSkillGrantsWire | null | undefined): string | undefined;
253
- export declare function approvalPriorCardsDetail(card: Pick<ApprovalCardRequest, 'priorCardsForCall' | 'origin'> | null | undefined): string | undefined;
260
+ export declare function classifierNoRulingDetail(word: string | undefined, lang?: UiLanguage): string;
261
+ export declare function approvalBoundGrantsDetail(grants: BoundSkillGrantsWire | null | undefined, lang?: UiLanguage): string | undefined;
262
+ export declare function approvalPriorCardsDetail(card: Pick<ApprovalCardRequest, 'priorCardsForCall' | 'origin'> | null | undefined, lang?: UiLanguage): string | undefined;
254
263
  export declare function approvalSupersedesDetail(card: Pick<ApprovalCardRequest, 'supersedes'> | null | undefined): string | undefined;
255
264
  export declare function readDenialLimitFallback(v: unknown): DenialLimitFallback | undefined;
256
265
  export declare function readRuleOffers(v: unknown): RuleOfferReading[] | undefined;
@@ -289,5 +298,8 @@ export type ApprovalHolderJoin = {
289
298
  readonly kind: 'free';
290
299
  };
291
300
  export declare function joinApprovalHolder(identity: ApprovalHolderIdentity, signal?: AbortSignal): Promise<ApprovalHolderJoin>;
292
- export declare function claimApprovalCard(identity: ApprovalHolderIdentity, signal?: AbortSignal): Promise<ApprovalCardClaim>;
301
+ export interface ApprovalCardClaimOptions {
302
+ readonly signal?: AbortSignal;
303
+ }
304
+ export declare function claimApprovalCard(identity: ApprovalHolderIdentity, options?: ApprovalCardClaimOptions): Promise<ApprovalCardClaim>;
293
305
  export type { ApprovalCardClaim, HostApprovalCardHold } from './approvalHolds.js';