@sema-agent/client-core 0.102.0 → 0.104.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 (117) hide show
  1. package/CHANGELOG.md +172 -0
  2. package/README.md +23 -17
  3. package/dist/adapt/toolCards.d.ts +2 -1
  4. package/dist/adapt/toolCards.js +3 -1
  5. package/dist/adapter/downstream/eventToSdkMessage.d.ts +5 -1
  6. package/dist/adapter/downstream/eventToSdkMessage.js +23 -3
  7. package/dist/adapter/downstream/terminalToSdkResult.d.ts +0 -1
  8. package/dist/adapter/downstream/terminalToSdkResult.js +3 -2
  9. package/dist/adapter/downstream/wiringManifestView.js +4 -1
  10. package/dist/agentSession/engineAgentRegistryRead.js +3 -0
  11. package/dist/cloudConfigWireCaps.js +6 -3
  12. package/dist/coreValuePorts.d.ts +3 -1
  13. package/dist/coreValuePorts.js +5 -0
  14. package/dist/credentialPlaneCapability.d.ts +22 -0
  15. package/dist/credentialPlaneCapability.js +75 -0
  16. package/dist/deviceExecutorManagementCapability.d.ts +1 -0
  17. package/dist/deviceExecutorManagementCapability.js +3 -1
  18. package/dist/deviceRebind.d.ts +17 -4
  19. package/dist/deviceRebind.js +43 -14
  20. package/dist/engineAgentAbsence.d.ts +1 -0
  21. package/dist/engineErrorCodes.d.ts +1 -0
  22. package/dist/engineErrorCodes.js +3 -1
  23. package/dist/engineNoticeCodes.d.ts +26 -0
  24. package/dist/engineNoticeCodes.js +121 -12
  25. package/dist/engineRowRef.js +1 -0
  26. package/dist/errorSupplementRoles.js +1 -3
  27. package/dist/eventLeg.js +2 -1
  28. package/dist/executionPlacementWords.d.ts +3 -0
  29. package/dist/executionPlacementWords.js +2 -0
  30. package/dist/fleet/fleetProjection.js +15 -9
  31. package/dist/gateOutcome.d.ts +20 -0
  32. package/dist/gateOutcome.js +89 -0
  33. package/dist/generated/engineAskFaceTables.js +2 -2
  34. package/dist/generated/engineFactTables.d.ts +8 -3
  35. package/dist/generated/engineFactTables.js +58 -2
  36. package/dist/generated/engineNoticeTables.js +30 -0
  37. package/dist/generated/settingsSchemaDefaultModel.d.ts +1 -1
  38. package/dist/generated/settingsSchemaDefaultModel.js +2 -2
  39. package/dist/generated/settingsSchemaFns.d.ts +15 -0
  40. package/dist/generated/settingsSchemaFns.js +25 -2
  41. package/dist/generated/settingsSchemaHooksClassifier.js +109 -29
  42. package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -1
  43. package/dist/generated/settingsSchemaMcpRequestEntry.js +213 -93
  44. package/dist/generated/settingsSchemaMcpServerName.d.ts +1 -0
  45. package/dist/generated/settingsSchemaMcpServerName.js +8 -0
  46. package/dist/generated/settingsSchemaOwnKeyRead.d.ts +1 -0
  47. package/dist/generated/settingsSchemaOwnKeyRead.js +172 -0
  48. package/dist/generated/settingsSchemaPlainJsonObject.d.ts +1 -0
  49. package/dist/generated/settingsSchemaPlainJsonObject.js +28 -0
  50. package/dist/generated/settingsSchemaSafetyMergeSpec.js +10 -7
  51. package/dist/generated/settingsSchemaTierWords.d.ts +1 -0
  52. package/dist/generated/settingsSchemaTierWords.js +7 -0
  53. package/dist/generated/settingsSchemaTypes.d.ts +3 -1
  54. package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
  55. package/dist/hitl/automaticAnswerVerdict.js +47 -11
  56. package/dist/hitl/decisionConflict.js +11 -11
  57. package/dist/hitl/decisionRefusal.d.ts +1 -0
  58. package/dist/hitl/decisionRefusal.js +4 -2
  59. package/dist/hitl/editedRuleTextPrecheck.d.ts +1 -0
  60. package/dist/hitl/editedRuleTextPrecheck.js +26 -1
  61. package/dist/hitl/persistedRulesWire.js +1 -0
  62. package/dist/hitl/planReviewWire.d.ts +2 -1
  63. package/dist/hitl/planReviewWire.js +8 -12
  64. package/dist/hitl/sessionPolicyDeliverable.d.ts +0 -1
  65. package/dist/hitl/sessionPolicyDeliverable.js +31 -10
  66. package/dist/hitl/sessionPolicyWire.js +1 -1
  67. package/dist/hitl/toolApprovalWire.d.ts +20 -7
  68. package/dist/hitl/toolApprovalWire.js +171 -19
  69. package/dist/host.d.ts +0 -3
  70. package/dist/hostTurnSettings.js +3 -1
  71. package/dist/humanTurn.js +2 -2
  72. package/dist/i18n/messages.en.d.ts +5 -0
  73. package/dist/i18n/messages.en.js +6 -1
  74. package/dist/i18n/messages.zh.js +6 -1
  75. package/dist/index.d.ts +8 -4
  76. package/dist/index.js +3 -1
  77. package/dist/inheritEnvWire.d.ts +1 -0
  78. package/dist/inheritEnvWire.js +8 -5
  79. package/dist/jsonFaithful.js +5 -3
  80. package/dist/mcpEngineLeg.d.ts +3 -0
  81. package/dist/mcpEngineLeg.js +4 -1
  82. package/dist/mcpLiveness.d.ts +18 -0
  83. package/dist/mcpLiveness.js +48 -1
  84. package/dist/mcpReconnect.d.ts +3 -0
  85. package/dist/mcpReconnect.js +6 -0
  86. package/dist/mcpStatusSupersetKeys.js +24 -1
  87. package/dist/mcpWireCaps.d.ts +2 -3
  88. package/dist/mcpWireCaps.js +10 -9
  89. package/dist/memoryEntriesWire.d.ts +35 -1
  90. package/dist/memoryEntriesWire.js +110 -14
  91. package/dist/modsFace.js +7 -3
  92. package/dist/postureKnob.js +1 -1
  93. package/dist/prepareRefusal.d.ts +0 -1
  94. package/dist/prepareRefusal.js +0 -3
  95. package/dist/printModelStatus.d.ts +1 -0
  96. package/dist/printModelStatus.js +6 -2
  97. package/dist/promptProfileWireCaps.d.ts +1 -3
  98. package/dist/promptProfileWireCaps.js +2 -2
  99. package/dist/request/taskRequest.d.ts +1 -1
  100. package/dist/request/taskRequest.js +3 -3
  101. package/dist/retryStatus.d.ts +20 -1
  102. package/dist/retryStatus.js +31 -7
  103. package/dist/ruleCompileVerdict.d.ts +1 -0
  104. package/dist/ruleCompileVerdict.js +3 -1
  105. package/dist/seatContract.d.ts +7 -7
  106. package/dist/seatContract.js +49 -10
  107. package/dist/sessionMemoryErase.js +24 -2
  108. package/dist/sessionRowTag.d.ts +24 -0
  109. package/dist/sessionRowTag.js +77 -0
  110. package/dist/systemReminderTag.js +14 -4
  111. package/dist/turnFailurePresentation.js +8 -1
  112. package/dist/wireFailureShape.d.ts +12 -1
  113. package/dist/wireFailureShape.js +58 -24
  114. package/dist/wireRefusalCopy.d.ts +0 -3
  115. package/dist/wireRefusalCopy.js +0 -17
  116. package/docs/INTEGRATION-CLIENTS.md +400 -14
  117. package/package.json +5 -5
@@ -118,7 +118,7 @@ export interface McpEntryKeyIssue {
118
118
  readonly path: string;
119
119
  readonly reason: string;
120
120
  readonly member?: string;
121
- readonly fault?: "not_plain_record" | "member_not_string" | "member_name_reserved";
121
+ readonly fault?: PlainStringRecordFault;
122
122
  }
123
123
  export type RequestMcpTransportRead = {
124
124
  ok: true;
@@ -128,6 +128,8 @@ export type RequestMcpTransportRead = {
128
128
  ok: false;
129
129
  issue: McpEntryKeyIssue;
130
130
  };
131
+ declare const PLAIN_STRING_RECORD_FAULTS: readonly ["not_plain_record", "member_not_string", "member_name_reserved"];
132
+ export type PlainStringRecordFault = (typeof PLAIN_STRING_RECORD_FAULTS)[number];
131
133
  declare const MCP_CONTENT_ORIGINS: readonly ["local", "execution", "external"];
132
134
  export type McpContentOrigin = (typeof MCP_CONTENT_ORIGINS)[number];
133
135
  export {};
@@ -20,7 +20,7 @@ export type AutomaticAnswerVerdict = {
20
20
  readonly kind: 'unknown';
21
21
  readonly why: AutomaticAnswerUnknownWhy;
22
22
  };
23
- export declare const MODE_ARBITRATION: Readonly<Record<"hook" | "write_protection" | "mode" | "target_unresolved" | "content_question" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "org_rule" | "rule_unreadable" | "ask_rule" | "denial_limit_fallback" | "classifier_no_ruling" | "requires_user_interaction" | "cross_boundary" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", CoreModeArbitrationRow>>;
23
+ export declare const MODE_ARBITRATION: Readonly<Record<"hook" | "write_protection" | "mode" | "target_unresolved" | "content_question" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "org_rule" | "rule_unreadable" | "ask_rule" | "denial_limit_fallback" | "classifier_no_ruling" | "requires_user_interaction" | "cross_boundary" | "operator_forced" | "shell_floor" | "probe" | "write_protection_on_disk" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", CoreModeArbitrationRow>>;
24
24
  export declare function foldModeArbitrationRow(classes: Iterable<string>, askFace?: AutomaticAnswerAskFace): CoreModeArbitrationRow;
25
25
  export declare function automaticAnswerVerdict(card: object | null | undefined, lane: AutomaticAnswerLane, facts?: AutomaticAnswerFacts | null): AutomaticAnswerVerdict;
26
26
  export declare function mandatedApprovalDetailOf(card: object | null | undefined, lang?: UiLanguage): string;
@@ -1,4 +1,4 @@
1
- import { CORE_MODE_ARBITRATION, CORE_MODE_RELEASE_REASONS } from '../generated/engineFactTables.js';
1
+ import { CORE_MODE_ARBITRATION, CORE_MODE_RELEASE_REASONS, CORE_REAL_APPROVAL_ASK_CLASSES } from '../generated/engineFactTables.js';
2
2
  import { CORE_RELEASABLE_ASK_CLASSES_BY_FACE, CORE_SHELL_FACE_TOOL_NAMES } from '../generated/engineAskFaceTables.js';
3
3
  import { mandatedApprovalDetail } from '../gateVocabulary.js';
4
4
  import { msg, renderMessage } from '../i18n/translate.js';
@@ -60,12 +60,13 @@ export function foldModeArbitrationRow(classes, askFace) {
60
60
  return ORDINARY_ROW;
61
61
  return Object.freeze({ bypassImmune, classifierEligible, sandboxAdmission, ruleMayClear, hookAskFloor });
62
62
  }
63
- function rowBlocks(lane, row) {
64
- return lane === 'mode_posture' ? row.bypassImmune : !row.ruleMayClear;
65
- }
63
+ const REAL_APPROVAL_CLASSES = new Set(CORE_REAL_APPROVAL_ASK_CLASSES);
66
64
  function classBlocks(lane, c, face) {
67
- const row = TABLE[c];
68
- return lane === 'mode_posture' ? bypassImmuneOn(c, face) : !row.ruleMayClear;
65
+ if (lane === 'mode_posture')
66
+ return bypassImmuneOn(c, face);
67
+ if (lane === 'standing_rule')
68
+ return !TABLE[c].ruleMayClear;
69
+ return REAL_APPROVAL_CLASSES.has(c);
69
70
  }
70
71
  function mustAsk(road, extra) {
71
72
  return Object.freeze({ kind: 'must_ask', road, ...(extra?.askClass !== undefined ? { askClass: extra.askClass } : {}), ...(extra?.origin !== undefined ? { origin: extra.origin } : {}) });
@@ -88,6 +89,42 @@ function evidenceView(card, ...keys) {
88
89
  }
89
90
  return out;
90
91
  }
92
+ const SLOT_ABSENT = Object.freeze({ kind: 'absent' });
93
+ const SLOT_UNREADABLE = Object.freeze({ kind: 'unreadable' });
94
+ const EVIDENCE_CHAIN_MAX = 32;
95
+ function evidenceSlotOf(o, key) {
96
+ let at = o;
97
+ for (let depth = 0; at !== null; depth++) {
98
+ if (depth >= EVIDENCE_CHAIN_MAX)
99
+ return SLOT_UNREADABLE;
100
+ const d = Object.getOwnPropertyDescriptor(at, key);
101
+ if (d !== undefined)
102
+ return Object.hasOwn(d, 'value') ? Object.freeze({ kind: 'data', value: d.value }) : SLOT_UNREADABLE;
103
+ at = Object.getPrototypeOf(at);
104
+ }
105
+ return SLOT_ABSENT;
106
+ }
107
+ const EVIDENCE_BOOLEAN_KEYS = Object.freeze(['requiresRealApproval', 'governanceForced', 'mandated']);
108
+ const EVIDENCE_STRING_KEYS = Object.freeze(['origin', 'ruleOffersAbsence', 'mandate']);
109
+ function evidenceUnreadable(card) {
110
+ for (const k of EVIDENCE_BOOLEAN_KEYS) {
111
+ const slot = evidenceSlotOf(card, k);
112
+ if (slot.kind === 'unreadable' || (slot.kind === 'data' && slot.value !== undefined && typeof slot.value !== 'boolean'))
113
+ return true;
114
+ }
115
+ for (const k of EVIDENCE_STRING_KEYS) {
116
+ const slot = evidenceSlotOf(card, k);
117
+ if (slot.kind === 'unreadable' || (slot.kind === 'data' && slot.value !== undefined && (typeof slot.value !== 'string' || slot.value === '')))
118
+ return true;
119
+ }
120
+ const risk = evidenceSlotOf(card, 'risk');
121
+ if (risk.kind === 'absent' || (risk.kind === 'data' && risk.value === undefined))
122
+ return false;
123
+ if (risk.kind === 'unreadable' || typeof risk.value !== 'object' || risk.value === null)
124
+ return true;
125
+ const nested = evidenceSlotOf(risk.value, 'requiresRealApproval');
126
+ return nested.kind !== 'data' || typeof nested.value !== 'boolean';
127
+ }
91
128
  function readHostAskRuleMatched(facts) {
92
129
  if (typeof facts !== 'object' || facts === null)
93
130
  return undefined;
@@ -138,14 +175,14 @@ export function automaticAnswerVerdict(card, lane, facts) {
138
175
  return mustAsk('allow_rule_shadow');
139
176
  }
140
177
  }
178
+ if (evidenceUnreadable(card))
179
+ return UNKNOWN.card_unreadable;
141
180
  const pair = readAskClassPairState(card);
142
181
  if (pair.state === 'malformed')
143
182
  return UNKNOWN.classes_malformed;
144
183
  if (pair.state === 'absent')
145
184
  return UNKNOWN.classes_absent;
146
185
  const classes = pair.classes;
147
- const folded = foldModeArbitrationRow(classes, face);
148
- let anyKnown = false;
149
186
  let firstBlocking;
150
187
  let anyUnknown = false;
151
188
  for (const c of classes) {
@@ -153,12 +190,11 @@ export function automaticAnswerVerdict(card, lane, facts) {
153
190
  anyUnknown = true;
154
191
  continue;
155
192
  }
156
- anyKnown = true;
157
193
  if (firstBlocking === undefined && classBlocks(lane, c, face))
158
194
  firstBlocking = c;
159
195
  }
160
- if (anyKnown && rowBlocks(lane, folded))
161
- return mustAsk('ask_class', firstBlocking !== undefined ? { askClass: firstBlocking } : undefined);
196
+ if (firstBlocking !== undefined)
197
+ return mustAsk('ask_class', { askClass: firstBlocking });
162
198
  if (anyUnknown)
163
199
  return UNKNOWN.class_not_in_table;
164
200
  if (lane !== 'mode_posture')
@@ -1,9 +1,10 @@
1
1
  import { APPROVAL_BINDING_MISMATCH, CHECKPOINT_UNSUPPORTED_VERSION, RESUME_OUTCOME_INVALID } from '../engineErrorCodes.js';
2
2
  import { msg, renderMessage } from '../i18n/translate.js';
3
3
  import { ownDataField } from '../ownKey.js';
4
- import { isSlotCarrier, PROTOCOL_ERROR_NAME, protocolErrorNameOf, readRefusalField } from '../wireFailureShape.js';
4
+ import { isSlotCarrier, PROTOCOL_ERROR_NAME, protocolErrorNameReading, readRefusalSlots, readThrownExtraSnapshot } from '../wireFailureShape.js';
5
5
  const BINDING_SEAT_FIELDS = new Set(['boundCallId', 'boundInputHash']);
6
6
  const ANSWER_FIELD = 'answer';
7
+ const REFUSAL_WORD_KEYS = Object.freeze(['field', 'reason']);
7
8
  const GRANT_DIGEST_FIELD = 'boundGrantDigest';
8
9
  function namedProtocolOf(r) {
9
10
  return r.state === 'named' ? r.name : undefined;
@@ -11,6 +12,7 @@ function namedProtocolOf(r) {
11
12
  export function decisionConflictOf(err, captured, protocolNameRead) {
12
13
  if (!isSlotCarrier(err))
13
14
  return undefined;
15
+ const extra = readThrownExtraSnapshot(err);
14
16
  let code;
15
17
  if (captured !== undefined) {
16
18
  if (captured.state !== 'read')
@@ -25,23 +27,21 @@ export function decisionConflictOf(err, captured, protocolNameRead) {
25
27
  return undefined;
26
28
  }
27
29
  }
28
- const protocolName = protocolNameRead !== undefined ? namedProtocolOf(protocolNameRead) : protocolErrorNameOf(err);
30
+ const protocolName = namedProtocolOf(protocolNameRead ?? protocolErrorNameReading(err, extra));
29
31
  if (code === CHECKPOINT_UNSUPPORTED_VERSION)
30
32
  return 'format_version';
31
33
  const bindingFamily = code === APPROVAL_BINDING_MISMATCH || (code === undefined && protocolName === PROTOCOL_ERROR_NAME.ApprovalBindingMismatchError);
32
34
  if (!bindingFamily && code !== RESUME_OUTCOME_INVALID)
33
35
  return undefined;
34
- let field;
35
- try {
36
- field = readRefusalField(err);
37
- }
38
- catch {
39
- field = undefined;
40
- }
36
+ const slots = readRefusalSlots(err, REFUSAL_WORD_KEYS, extra.bag);
37
+ const field = slots.field.word;
41
38
  if (code === RESUME_OUTCOME_INVALID)
42
39
  return field === ANSWER_FIELD ? 'answer_invalid' : field === GRANT_DIGEST_FIELD ? 'grant_changed' : undefined;
43
- if (field === undefined)
44
- return 'row_integrity';
40
+ if (field === undefined) {
41
+ if (slots.field.present)
42
+ return undefined;
43
+ return slots.reason.word !== undefined ? 'row_integrity' : undefined;
44
+ }
45
45
  return BINDING_SEAT_FIELDS.has(field) ? 'binding_mismatch' : undefined;
46
46
  }
47
47
  export const DECISION_ANSWER_INVALID_CONTENT = 'The engine rejected the answer itself because it does not fit the question that was asked · Nothing was decided and the question is still waiting · Correct the answer and send it again';
@@ -54,6 +54,7 @@ export interface DecisionRefusalReading {
54
54
  readonly transient?: true;
55
55
  readonly conflict?: DecisionRefusalConflict;
56
56
  readonly unrecoverable?: true;
57
+ readonly acceptableForm?: {} | null;
57
58
  }
58
59
  export declare function mintDecisionRefusalReading(err: {} | null | undefined, context?: RefusalRouteContext, attributionCarried?: boolean, delivered?: DeliveredReading, carried?: RefusalCarrier): DecisionRefusalReading;
59
60
  export declare function readDecisionRefusalReading(err: {} | null | undefined, context?: RefusalRouteContext): DecisionRefusalReading;
@@ -1,4 +1,4 @@
1
- import { ASK_GONE, ASK_GONE_PARKED, RESUME_PREFLIGHT_REJECTED, isDecideAlreadyResolvedCode, isDecideParkMovedCode, isDecideRowUnrevivableCode, refusalRetriableReading, refusalSaysStillPending } from '../engineErrorCodes.js';
1
+ import { ASK_GONE, ASK_GONE_PARKED, RESUME_CONSTRAINT_REJECTED, RESUME_PREFLIGHT_REJECTED, isDecideAlreadyResolvedCode, isDecideParkMovedCode, isDecideRowUnrevivableCode, refusalRetriableReading, refusalSaysStillPending } from '../engineErrorCodes.js';
2
2
  import { isUiLanguage } from '../env/uiLanguage.js';
3
3
  import { msg, renderMessage } from '../i18n/translate.js';
4
4
  import { notPendingCauseReading, refusalCauseWordOf } from './approvalEndingCause.js';
@@ -7,7 +7,7 @@ import { isAlreadyResolvedGateReason, isCodeClassifiedGateFailure } from './park
7
7
  import { decisionConflictOf } from './decisionConflict.js';
8
8
  import { readLivePendingRows } from './livePendingAsk.js';
9
9
  import { guardedRead, ownDataField, readOwnDataValue } from '../ownKey.js';
10
- import { PROTOCOL_ERROR_NAME, THROWN_SLOT_UNREADABLE, isDisplayableWireCode, isSlotCarrier, ownFoldedCodeBitsOf, protocolErrorNameReading, readErrorRecord, readRefusalField, readThrownSlot } from '../wireFailureShape.js';
10
+ import { PROTOCOL_ERROR_NAME, THROWN_SLOT_UNREADABLE, isDisplayableWireCode, isSlotCarrier, ownFoldedCodeBitsOf, protocolErrorNameReading, readErrorPresent, readErrorRecord, readRefusalField, readThrownSlot } from '../wireFailureShape.js';
11
11
  import { attributionRefusalOf, carrierReadOf } from './attributionLadder.js';
12
12
  import { CODE_UNREADABLE, ownReadingSlot } from '../engineWireFor.js';
13
13
  export const ASK_DECIDED_CODE = 'conflict.ask_decided';
@@ -223,6 +223,7 @@ export function mintDecisionRefusalReading(err, context, attributionCarried, del
223
223
  const inRange = standing !== undefined && status !== undefined;
224
224
  const conflict = inRange && status === 409 && obj !== undefined ? isolated(() => decisionConflictOf(obj, captured, pn)) : undefined;
225
225
  const unrecoverable = inRange && status !== undefined && Number.isInteger(status) && status >= 400 && status <= 599 && isDecideRowUnrevivableCode(errorCode);
226
+ const acceptableForm = errorCode === RESUME_CONSTRAINT_REJECTED && obj !== undefined ? isolated(() => readErrorPresent(obj, 'acceptableForm')) : undefined;
226
227
  const transient = inRange &&
227
228
  conflict !== 'grant_changed' &&
228
229
  !unrecoverable &&
@@ -244,6 +245,7 @@ export function mintDecisionRefusalReading(err, context, attributionCarried, del
244
245
  ...(transient ? { transient: true } : {}),
245
246
  ...(conflict !== undefined ? { conflict } : {}),
246
247
  ...(unrecoverable ? { unrecoverable: true } : {}),
248
+ ...(acceptableForm !== undefined ? { acceptableForm } : {}),
247
249
  });
248
250
  }
249
251
  export function readDecisionRefusalReading(err, context) {
@@ -12,6 +12,7 @@ export type EditedRuleTextPrecheck = {
12
12
  message: string;
13
13
  };
14
14
  export type EditedRuleTextPrechecker = (text: string, command: string) => EditedRuleTextPrecheck;
15
+ export declare function trimEditedRuleText(text: string): string;
15
16
  export declare function installEditedRuleTextPrechecker(fn: EditedRuleTextPrechecker | null): () => void;
16
17
  export declare function hasEditedRuleTextPrechecker(): boolean;
17
18
  export declare function precheckEditedRuleText(text: string, command: string): EditedRuleTextPrecheck | undefined;
@@ -1,4 +1,29 @@
1
1
  let installed = null;
2
+ function escapedAt(s, i) {
3
+ let n = 0;
4
+ for (let j = i - 1; j >= 0 && s[j] === '\\'; j -= 1)
5
+ n += 1;
6
+ return n % 2 === 1;
7
+ }
8
+ export function trimEditedRuleText(text) {
9
+ if (typeof text !== 'string')
10
+ return text;
11
+ const outer = text.trim();
12
+ let open = -1;
13
+ for (let i = 0; i < outer.length; i += 1) {
14
+ if (outer[i] === '(' && !escapedAt(outer, i)) {
15
+ open = i;
16
+ break;
17
+ }
18
+ }
19
+ if (open <= 0)
20
+ return outer;
21
+ const head = outer.slice(0, open);
22
+ const name = head.trimEnd();
23
+ if (name === head || name.length === 0 || name.endsWith('\\'))
24
+ return outer;
25
+ return name + outer.slice(open);
26
+ }
2
27
  export function installEditedRuleTextPrechecker(fn) {
3
28
  const prev = installed;
4
29
  installed = fn;
@@ -13,7 +38,7 @@ export function precheckEditedRuleText(text, command) {
13
38
  const fn = installed;
14
39
  if (fn === null)
15
40
  return undefined;
16
- return fn(text, command);
41
+ return fn(trimEditedRuleText(text), command);
17
42
  }
18
43
  export function _resetEditedRuleTextPrecheckerForTest() {
19
44
  installed = null;
@@ -208,6 +208,7 @@ const PERSISTED_RULE_MATCH_KEYS = Object.freeze({
208
208
  host: 'rules.match.host',
209
209
  subdomain: 'rules.match.subdomain',
210
210
  pattern: 'rules.match.pattern',
211
+ tool: 'rules.match.tool',
211
212
  });
212
213
  export function persistedRuleMatchLabel(ruleOrMatch, lang) {
213
214
  const word = typeof ruleOrMatch === 'string' ? ruleOrMatch : ownSlot(ruleOrMatch, 'match');
@@ -1,4 +1,5 @@
1
1
  import { type QuestionAnswer } from '../liveQuestionStore.js';
2
+ import type { EngineWireInjection } from '../engineWireSdk.js';
2
3
  import { type PlanReviewModeAfter } from './hitlBridge.js';
3
4
  import type { AgentClient } from '@sema-agent/sdk';
4
5
  import type { ReopenCardVerdict } from '../adapter/activeRunSelfHeal.js';
@@ -66,7 +67,7 @@ export type PlanReviewWireClient = {
66
67
  assistant: Pick<AgentClient['assistant'], 'planReview'>;
67
68
  runs: Pick<AgentClient['runs'], 'get'>;
68
69
  };
69
- export interface PlanReviewWire {
70
+ export interface PlanReviewWire extends EngineWireInjection<PlanReviewWireClient> {
70
71
  client: PlanReviewWireClient;
71
72
  }
72
73
  export interface PlanReviewDecisionOutcome extends PlanReviewOutcomeMeta {
@@ -2,6 +2,7 @@ import { publishQuestionFrame, publishQuestionFrameFor, registerLocalQuestionRes
2
2
  import { hostLog } from '../host.js';
3
3
  import { abortableSleep, settleWithinDeadline } from '../abortableSleep.js';
4
4
  import { clientHasVerbs, engineWireFor, noAnswerKindOf, sendOnce } from '../engineWireFor.js';
5
+ import { engineCapTrue } from '../engineCapsCache.js';
5
6
  import { engineWireTarget } from '../engineWireTarget.js';
6
7
  import { enqueuePlanReviewOutcome } from '../notifications.js';
7
8
  import { corruptStoredRowContent, corruptStoredRowWhere } from '../wireErrorTriage.js';
@@ -370,7 +371,7 @@ export function armPlanReviewApproval(result, sessionKey, opts) {
370
371
  }
371
372
  const wire = opts?.wire;
372
373
  if (wire !== undefined) {
373
- if (!usablePlanReviewWireClient(wire.client)) {
374
+ if (engineWireFor(wire, DEFAULT_SESSION_KEY, usablePlanReviewWireClient).kind !== 'injected') {
374
375
  hostLog('error', 'planReviewWire: plan_review card NOT armed — the engine client supplied by the host is not usable (needs assistant.planReview and runs.get)');
375
376
  return false;
376
377
  }
@@ -454,15 +455,6 @@ export function planReviewOutcomeTail(taskId, decision, effect, cause) {
454
455
  return `Do not state the result as fact: tell the user the ${decision} was submitted but its effect could not be confirmed; TaskOutput("${taskId}") shows where the task stands.`;
455
456
  }
456
457
  }
457
- function clientOnlyView(wire) {
458
- if (wire === undefined || wire === null || typeof wire !== 'object')
459
- return wire;
460
- return {
461
- get client() {
462
- return wire.client;
463
- },
464
- };
465
- }
466
458
  function planReviewDecisionTimedOutOutcome(decision) {
467
459
  return (`The plan_review ${decision} was sent, but no answer came back from the engine within the time limit this host allows for it — ` +
468
460
  `it may have taken effect (${decision === 'approve' ? 'an approval keeps the engine busy until the resumed work finishes' : 'the engine may still be applying it'}).`);
@@ -654,7 +646,7 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
654
646
  let stillParkedCause;
655
647
  let statusSeen;
656
648
  const wire = opts?.wire;
657
- const resolved = engineWireFor(clientOnlyView(wire), DEFAULT_SESSION_KEY, usablePlanReviewWireClient);
649
+ const resolved = engineWireFor(wire, DEFAULT_SESSION_KEY, usablePlanReviewWireClient);
658
650
  const badMode = permissionModeAfter !== undefined && !isPlanReviewModeAfter(permissionModeAfter);
659
651
  if (badMode) {
660
652
  hostLog('error', `planReviewWire: ${decision} NOT sent — permissionModeAfter must be "default" or "acceptEdits"`);
@@ -683,11 +675,15 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
683
675
  try {
684
676
  const mode = isPlanReviewModeAfter(permissionModeAfter) ? permissionModeAfter : undefined;
685
677
  const reason = denyReasonForWire(opts?.reason, `plan-review ${taskId}`);
678
+ const capsBase = resolved.kind === 'target' ? resolved.target.baseUrl : resolved.capsBaseUrl;
679
+ const checkpointId = gateBefore !== undefined && engineCapTrue(capsBase, 'planReviewCheckpointId') ? gateBefore : undefined;
686
680
  const reqBody = { decision };
687
681
  if (reason !== undefined)
688
682
  reqBody.reason = reason;
689
683
  if (mode !== undefined)
690
684
  reqBody.permissionModeAfter = mode;
685
+ if (checkpointId !== undefined)
686
+ reqBody.checkpointId = checkpointId;
691
687
  let body;
692
688
  try {
693
689
  body = await sendOnce(undefined, () => client.assistant.planReview(taskId, reqBody));
@@ -697,7 +693,7 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
697
693
  const defaultConflict = mode === 'default' && conflict?.status === 400 && conflict?.errorCode === REQUEST_FIELD_CONFLICT;
698
694
  if (defaultConflict && !directFailureVerdictOf(e1, directSafetyStopOf(e1)).yields) {
699
695
  hostLog('debug', 'planReviewWire: permissionModeAfter "default" refused as not applicable — re-sending the approval without the key (same meaning)');
700
- body = await sendOnce(undefined, () => client.assistant.planReview(taskId, reason !== undefined ? { decision, reason } : { decision }));
696
+ body = await sendOnce(undefined, () => client.assistant.planReview(taskId, { decision, ...(reason !== undefined ? { reason } : {}), ...(checkpointId !== undefined ? { checkpointId } : {}) }));
701
697
  }
702
698
  else {
703
699
  throw e1;
@@ -22,4 +22,3 @@ export interface SessionPolicyDeliverableOptions {
22
22
  }
23
23
  export declare function sessionPolicyDeliverable(behavior: 'deny' | 'ask', rules: readonly string[], opts?: SessionPolicyDeliverableOptions): SessionPolicyDeliverability;
24
24
  export declare function sessionPolicyWithheldNotice(why: SessionPolicyWithheldWhy, lang?: UiLanguage): string;
25
- export declare function legacyToolNameFailureNoteOf(code: string | undefined): string | undefined;
@@ -1,11 +1,10 @@
1
- import { CONFIG_LEGACY_TOOL_NAME } from '../engineErrorCodes.js';
2
1
  import { rosterMountedNames } from '../rosterMountedNames.js';
3
2
  import { msg, renderMessage } from '../i18n/translate.js';
4
3
  import { readOwnDataValue } from '../ownKey.js';
5
4
  import { denyEntryReading, ruleCompileVerdict } from '../ruleCompileVerdict.js';
5
+ import { hasCoreValuePort, ruleNameCovers } from '../coreValuePorts.js';
6
6
  import { ruleToolNameVerdictOf } from '../protocolSegment.js';
7
7
  import { PREFIXES_IN_PROSE, REFUSED_NAME_FIX } from './refusedToolNameProse.js';
8
- import { prepareRefusalNoteOf } from '../prepareRefusal.js';
9
8
  import { CORE_PROTOCOL_PREFIXES } from '../generated/toolNameTables.js';
10
9
  const COVERING_NAMESPACE_PREFIXES = CORE_PROTOCOL_PREFIXES;
11
10
  const WITHHELD_NOTICE = {
@@ -15,7 +14,7 @@ const WITHHELD_NOTICE = {
15
14
  wildcard: 'Not written to this session’s rule record: this rule uses a wildcard (*), and an engine that matches that record by exact tool name would block none of the tools it covers.',
16
15
  not_a_tool_name: 'Not written to this session’s rule record: this entry is not exactly one tool name — it is empty, not text, has spaces around the name, is not a single tool name in rule syntax (for example it contains a backslash or a parenthesis, or is longer than a rule can be), or spells its server or agent peer part in a way the engine never uses when naming tools (for example with a dot or a space), so no tool would ever match it.',
17
16
  legacy_tool_name: `Not written to this session’s rule record: unless a tool by exactly this name is available, the engine refuses it — it is a retired tool name, or it contains "__" but does not start with ${PREFIXES_IN_PROSE} — and with it in that record every later run of this session would fail at startup until that entry is removed from the record. ${REFUSED_NAME_FIX}`,
18
- not_in_roster: 'Not written to this session’s rule record: the tool roster supplied for this check has no tool by exactly this name, as a name or an alias, with letter case counted — it may be misspelled, or name a tool this deployment does not provide — so recorded as it is it would block nothing here.',
17
+ not_in_roster: 'Not written to this session’s rule record: the tool roster supplied for this check has no tool this rule would block — no tool by exactly this name, as a name or an alias, with letter case counted, and, where the engine also reads the name as naming every tool of a server (a server whose own name contains "__"), no tool of that server either — it may be misspelled, or name a tool this deployment does not provide — so recorded as it is it would block nothing here.',
19
18
  namespace_covering_unconfirmed: msg('session.policy.withheld.namespaceCoveringUnconfirmed'),
20
19
  };
21
20
  export const SESSION_POLICY_WITHHELD_WHY = Object.freeze(Object.keys(WITHHELD_NOTICE));
@@ -153,11 +152,14 @@ export function sessionPolicyDeliverable(behavior, rules, opts) {
153
152
  why = 'not_a_tool_name';
154
153
  }
155
154
  let inertReason;
155
+ let coveringRow = false;
156
156
  if (engineAsked) {
157
157
  const reading = entryReadingOf(r);
158
158
  if (reading === 'unknown')
159
159
  return unreadable();
160
- if (reading !== 'row') {
160
+ if (reading === 'covering')
161
+ coveringRow = true;
162
+ else if (reading !== 'row') {
161
163
  inertReason = reading.reason;
162
164
  if (why === undefined)
163
165
  why = reading.why;
@@ -170,8 +172,13 @@ export function sessionPolicyDeliverable(behavior, rules, opts) {
170
172
  if (grammar === 'refused')
171
173
  why = 'not_a_tool_name';
172
174
  }
173
- if (why === undefined && mounted !== undefined && !mounted.has(r) && covering === undefined)
174
- why = 'not_in_roster';
175
+ if (why === undefined && mounted !== undefined && !mounted.has(r) && covering === undefined) {
176
+ const reach = coveringRow ? coveredRosterName(r, mounted) : 'none';
177
+ if (reach === 'unknown')
178
+ return unreadable();
179
+ if (reach === 'none')
180
+ why = 'not_in_roster';
181
+ }
175
182
  if (why === undefined)
176
183
  exact.push(r);
177
184
  else {
@@ -191,12 +198,29 @@ export function sessionPolicyDeliverable(behavior, rules, opts) {
191
198
  function entryReadingOf(rule) {
192
199
  const reading = denyEntryReading(rule);
193
200
  if (reading.kind === 'row')
194
- return 'row';
201
+ return reading.covering === true ? 'covering' : 'row';
195
202
  if (reading.kind === 'unknown')
196
203
  return 'unknown';
197
204
  const reason = reading.reason;
198
205
  return reason === 'grammar' || reason === 'content_unsupported' ? { why: 'not_a_tool_name', reason } : { why: 'wildcard', reason };
199
206
  }
207
+ function coveredRosterName(rule, mounted) {
208
+ if (!hasCoreValuePort('ruleNameCovers'))
209
+ return 'unknown';
210
+ try {
211
+ for (const name of mounted) {
212
+ const v = ruleNameCovers(rule, name);
213
+ if (v === true)
214
+ return 'covers';
215
+ if (v !== false)
216
+ return 'unknown';
217
+ }
218
+ return 'none';
219
+ }
220
+ catch {
221
+ return 'unknown';
222
+ }
223
+ }
200
224
  export function sessionPolicyWithheldNotice(why, lang) {
201
225
  if (typeof why === 'string' && Object.hasOwn(WITHHELD_NOTICE, why)) {
202
226
  const sentence = WITHHELD_NOTICE[why];
@@ -204,6 +228,3 @@ export function sessionPolicyWithheldNotice(why, lang) {
204
228
  }
205
229
  return 'Not written to this session’s rule record.';
206
230
  }
207
- export function legacyToolNameFailureNoteOf(code) {
208
- return code === CONFIG_LEGACY_TOOL_NAME ? prepareRefusalNoteOf(code) : undefined;
209
- }
@@ -21,7 +21,7 @@ const RULE_FIELD_PRESENCE = {
21
21
  toolDeny: true,
22
22
  allowDirs: true,
23
23
  };
24
- const RECORD_META_KEYS = Object.freeze(['rev', 'gen', 'grammar']);
24
+ const RECORD_META_KEYS = Object.freeze(['rev', 'gen', 'grammar', 'operatorRules']);
25
25
  const _metaKeysPin = true;
26
26
  void _metaKeysPin;
27
27
  export const SESSION_POLICY_RULE_FIELDS = Object.freeze(Object.keys(RULE_FIELD_PRESENCE));
@@ -1,6 +1,7 @@
1
1
  import { type HitlClientLike, type DecideOperationObserver } from './hitlBridge.js';
2
2
  import { readApprovalCardWord, type ApprovalCardWord } from './approvalCardReading.js';
3
3
  import { type ApprovalAllowRuleShadow } from './allowRuleShadow.js';
4
+ import { CORE_PERSISTED_RULE_MATCHES } from '../generated/engineFactTables.js';
4
5
  import type { UiLanguage } from '../env/uiLanguage.js';
5
6
  import type { SessionRuleInertReason } from './sessionPolicyWire.js';
6
7
  import { type ApprovalCardClaim } from './approvalHolds.js';
@@ -30,22 +31,33 @@ export type { RuleOfferBatchMember };
30
31
  export type { RuleOfferUncoveredDetail };
31
32
  export type { RuleOfferUncoveredReason };
32
33
  export { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS };
34
+ type RuleOfferMatchWord = (typeof CORE_PERSISTED_RULE_MATCHES)[number];
35
+ type RuleOfferBatchMemberReading = Exclude<RuleOfferBatchMember, {
36
+ kind: 'command';
37
+ }> | (Omit<Extract<RuleOfferBatchMember, {
38
+ kind: 'command';
39
+ }>, 'match'> & {
40
+ match: RuleOfferMatchWord;
41
+ });
33
42
  export type { AskOrigin };
34
43
  export type { RuleOffersAbsence };
35
44
  export type { DenialLimitKind };
36
45
  export type { DenialLimitFallback };
37
46
  export { RULE_OFFERS_ABSENCE_REASONS };
38
47
  export declare const ASK_ORIGIN_WORDS: readonly string[];
39
- export type RuleOfferReading = (Extract<SdkRuleOffer, {
48
+ export type RuleOfferReading = (Omit<Extract<SdkRuleOffer, {
40
49
  kind: 'single';
41
- }> & {
50
+ }>, 'match'> & {
51
+ match: RuleOfferMatchWord;
42
52
  offerIndex: number;
43
53
  }) | (Omit<Extract<SdkRuleOffer, {
44
54
  kind: 'batch';
45
- }>, 'uncoveredDetail'> & {
55
+ }>, 'uncoveredDetail' | 'rules'> & RuleOfferBatchReadingSeats);
56
+ interface RuleOfferBatchReadingSeats {
57
+ rules: RuleOfferBatchMemberReading[];
46
58
  offerIndex: number;
47
59
  uncoveredDetail?: readonly RuleOfferUncoveredDetail[];
48
- });
60
+ }
49
61
  export interface ApprovalCardAllowDecision {
50
62
  kind: 'allow';
51
63
  allowSession: boolean;
@@ -85,6 +97,7 @@ export interface ApprovalCardRequest {
85
97
  };
86
98
  wireNote?: string;
87
99
  argsUnavailable?: true;
100
+ argsRewritten?: true;
88
101
  governanceForced?: true;
89
102
  delegation?: ToolApprovalDelegation;
90
103
  ruleOffers?: RuleOfferReading[];
@@ -166,7 +179,7 @@ export interface ReadRootCandidateView {
166
179
  covers?: 'exact';
167
180
  }
168
181
  export type ToolApprovalDelegation = ApprovalCardDelegation;
169
- 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", "approvalCard", "askClass", "classes", "inputHasBidi", "parked", "persistedRuleShadowed", "allowRuleShadowed", "probeCause", "probeReason", "rememberRefused", "boundGrantDigest", "boundGrantAbsence", "boundGrants", "classifierNoRuling", "ruleEvidence", "requiresRealApproval", "expiresInMs", "expiresAtMs", "serverNowMs", "delegation", "outcome", "cause"];
182
+ 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", "approvalCard", "askClass", "classes", "inputHasBidi", "parked", "persistedRuleShadowed", "allowRuleShadowed", "probeCause", "probeReason", "rememberRefused", "boundGrantDigest", "boundGrantAbsence", "boundGrants", "classifierNoRuling", "ruleEvidence", "requiresRealApproval", "expiresInMs", "expiresAtMs", "serverNowMs", "delegation", "outcome", "cause", "requestedBy"];
170
183
  export interface ApprovalMandatedFacts {
171
184
  readonly mandated?: true;
172
185
  readonly ruleOffersAbsence?: string;
@@ -263,8 +276,8 @@ export declare function approvalSupersedesDetail(card: Pick<ApprovalCardRequest,
263
276
  export declare function readDenialLimitFallback(v: unknown): DenialLimitFallback | undefined;
264
277
  export declare function readRuleOffers(v: unknown): RuleOfferReading[] | undefined;
265
278
  export declare function readRuleOfferSupply(offers: unknown): RuleOfferReading[] | undefined;
266
- export type ApprovalCardV1Facts = Pick<ApprovalCardRequest, 'toolName' | 'args'> & Pick<ApprovalCardRequest, 'toolCallId' | 'workerBadge' | 'wireNote' | 'argsUnavailable' | 'governanceForced' | 'delegation' | 'ruleOffersReadOnly' | 'inputHasBidi' | 'allowRuleShadow' | 'probeCause' | 'rememberRefused' | 'ruleEvidence' | 'requiresRealApproval' | 'ruleOffersAbsence' | 'denialLimitFallback' | 'askClass' | 'classes' | 'grantBinding' | 'unreadableEvidence' | 'message'>;
267
- export type ApprovalCardFacts = ApprovalCardV1Facts & Pick<ApprovalCardRequest, 'ruleOffers' | 'probeReason' | 'mandated' | 'mandate' | 'readRootCandidate' | 'origin' | 'approvalCard' | 'boundGrants' | 'classifierNoRuling' | 'allowSessionCarried' | 'cardPayloadUnreadable'>;
279
+ export type ApprovalCardV1Facts = Pick<ApprovalCardRequest, 'toolName' | 'args'> & Pick<ApprovalCardRequest, 'toolCallId' | 'workerBadge' | 'wireNote' | 'argsUnavailable' | 'governanceForced' | 'delegation' | 'ruleOffersReadOnly' | 'inputHasBidi' | 'allowRuleShadow' | 'probeCause' | 'rememberRefused' | 'ruleEvidence' | 'requiresRealApproval' | 'ruleOffersAbsence' | 'denialLimitFallback' | 'askClass' | 'classes' | 'grantBinding' | 'unreadableEvidence' | 'message' | 'approvalCard'>;
280
+ export type ApprovalCardFacts = ApprovalCardV1Facts & Pick<ApprovalCardRequest, 'argsRewritten' | 'ruleOffers' | 'probeReason' | 'mandated' | 'mandate' | 'readRootCandidate' | 'origin' | 'boundGrants' | 'classifierNoRuling' | 'allowSessionCarried' | 'cardPayloadUnreadable'>;
268
281
  export interface ApprovalCardFrameFactsOptions {
269
282
  readonly streamArgs?: object;
270
283
  readonly argsUnavailable?: true;