@sema-agent/client-core 0.90.0 → 0.92.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.
- package/CHANGELOG.md +365 -0
- package/README.md +48 -32
- package/dist/adapt/arms.js +13 -12
- package/dist/adapt/panelTasks.d.ts +0 -2
- package/dist/adapt/panelTasks.js +6 -26
- package/dist/adapt.js +2 -2
- package/dist/adapter/activeRunSelfHeal.d.ts +0 -2
- package/dist/adapter/activeRunSelfHeal.js +5 -27
- package/dist/adapter/downstream/eventToSdkMessage.js +4 -2
- package/dist/adapter/downstream/terminalToSdkResult.js +16 -7
- package/dist/adapter/downstream/wiringManifestView.d.ts +6 -0
- package/dist/adapter/downstream/wiringManifestView.js +16 -0
- package/dist/adapter/runStream.js +39 -20
- package/dist/askSurvivesStandingAnswer.d.ts +13 -0
- package/dist/askSurvivesStandingAnswer.js +53 -0
- package/dist/attachmentSeatCapability.d.ts +11 -0
- package/dist/attachmentSeatCapability.js +27 -0
- package/dist/attachmentsWireCaps.d.ts +9 -0
- package/dist/attachmentsWireCaps.js +74 -21
- package/dist/autoModeUnavailable.js +3 -2
- package/dist/cloudConfigWireCaps.js +5 -4
- package/dist/compensations.js +13 -17
- package/dist/controlRouter.d.ts +32 -25
- package/dist/controlRouter.js +166 -63
- package/dist/coreValuePorts.d.ts +4 -2
- package/dist/coreValuePorts.js +5 -0
- package/dist/decideFailureNote.js +7 -3
- package/dist/decideReceipt.d.ts +9 -0
- package/dist/decideReceipt.js +62 -1
- package/dist/disableSkillsWire.d.ts +1 -0
- package/dist/disableSkillsWire.js +8 -1
- package/dist/displayUntrusted.js +155 -5
- package/dist/effectiveFacts.d.ts +14 -4
- package/dist/effectiveFacts.js +45 -5
- package/dist/engineAgentAbsence.js +2 -1
- package/dist/engineCapReader.js +16 -10
- package/dist/engineCapsCache.d.ts +5 -1
- package/dist/engineCapsCache.js +69 -8
- package/dist/engineClosedSets.d.ts +2 -0
- package/dist/engineClosedSets.js +3 -0
- package/dist/engineErrorCodes.d.ts +17 -0
- package/dist/engineErrorCodes.js +47 -0
- package/dist/engineNoticeCodes.d.ts +14 -0
- package/dist/engineNoticeCodes.js +71 -0
- package/dist/executionLaneCapability.js +2 -0
- package/dist/gateOutcome.js +2 -17
- package/dist/gateVocabulary.d.ts +2 -4
- package/dist/gateVocabulary.js +3 -11
- package/dist/generated/engineFactTables.d.ts +27 -0
- package/dist/generated/engineFactTables.js +128 -0
- package/dist/generated/engineNoticeTables.js +3 -0
- package/dist/generated/settingsSchemaTables.d.ts +8 -0
- package/dist/generated/settingsSchemaTables.js +40 -0
- package/dist/hitl/allowRuleShadow.d.ts +21 -0
- package/dist/hitl/allowRuleShadow.js +167 -0
- package/dist/hitl/askClassPair.d.ts +14 -0
- package/dist/hitl/askClassPair.js +42 -0
- package/dist/hitl/askGateWire.d.ts +1 -1
- package/dist/hitl/askGateWire.js +2 -1
- package/dist/hitl/askSurvivesPosture.d.ts +5 -0
- package/dist/hitl/askSurvivesPosture.js +17 -0
- package/dist/hitl/automaticAnswerVerdict.d.ts +21 -0
- package/dist/hitl/automaticAnswerVerdict.js +143 -0
- package/dist/hitl/crashConverged.d.ts +8 -0
- package/dist/hitl/crashConverged.js +58 -1
- package/dist/hitl/crashConvergedNotice.d.ts +4 -0
- package/dist/hitl/crashConvergedNotice.js +57 -0
- package/dist/hitl/frameRouter.d.ts +2 -0
- package/dist/hitl/frameRouter.js +66 -14
- package/dist/hitl/gateLedger.d.ts +6 -0
- package/dist/hitl/gateLedger.js +34 -5
- package/dist/hitl/hitlBridge.d.ts +7 -4
- package/dist/hitl/hitlHostSurface.d.ts +2 -0
- package/dist/hitl/hitlHostSurface.js +7 -0
- package/dist/hitl/livePendingAsk.js +24 -5
- package/dist/hitl/parkResolver.d.ts +7 -2
- package/dist/hitl/parkResolver.js +21 -7
- package/dist/hitl/persistedRulesWire.d.ts +4 -1
- package/dist/hitl/persistedRulesWire.js +9 -2
- package/dist/hitl/planReviewWire.d.ts +1 -1
- package/dist/hitl/planReviewWire.js +19 -5
- package/dist/hitl/replayedApproval.d.ts +21 -0
- package/dist/hitl/replayedApproval.js +89 -0
- package/dist/hitl/sessionPolicyDeliverable.js +20 -2
- package/dist/hitl/sessionPolicyWire.d.ts +13 -0
- package/dist/hitl/sessionPolicyWire.js +75 -2
- package/dist/hitl/suspendedReopen.js +2 -2
- package/dist/hitl/toolApprovalWire.d.ts +9 -1
- package/dist/hitl/toolApprovalWire.js +40 -40
- package/dist/hookMatcherVerdict.d.ts +29 -0
- package/dist/hookMatcherVerdict.js +266 -0
- package/dist/humanTurn.d.ts +91 -0
- package/dist/humanTurn.js +252 -0
- package/dist/humanTurnRead.d.ts +105 -0
- package/dist/humanTurnRead.js +331 -0
- package/dist/index.d.ts +38 -11
- package/dist/index.js +27 -8
- package/dist/inheritEnvWire.js +4 -5
- package/dist/liveModelCatalog.d.ts +2 -0
- package/dist/liveModelCatalog.js +51 -3
- package/dist/mcpLiveness.js +2 -1
- package/dist/memoryVerbsWire.d.ts +1 -1
- package/dist/memoryVerbsWire.js +3 -0
- package/dist/model/catalog.js +2 -1
- package/dist/model/providerPresets.d.ts +3 -1
- package/dist/model/tierVocabulary.d.ts +2 -1
- package/dist/model/tierVocabulary.js +3 -8
- package/dist/peerFrames.js +2 -2
- package/dist/permissionRuleIssue.d.ts +1 -1
- package/dist/permissionRuleIssue.js +31 -9
- package/dist/permissionsAllowGrantCapability.d.ts +2 -1
- package/dist/permissionsAllowGrantCapability.js +11 -2
- package/dist/permissionsDeclaration.d.ts +29 -0
- package/dist/permissionsDeclaration.js +155 -66
- package/dist/pluginHooksWire.js +2 -11
- package/dist/promptDelivery.d.ts +11 -3
- package/dist/promptDelivery.js +164 -29
- package/dist/promptProfileWireCaps.d.ts +2 -1
- package/dist/protocolSegment.d.ts +9 -0
- package/dist/protocolSegment.js +28 -0
- package/dist/providerRejection.d.ts +1 -0
- package/dist/providerRejection.js +20 -0
- package/dist/readDenyTiers.d.ts +10 -0
- package/dist/readDenyTiers.js +29 -0
- package/dist/request/taskRequest.js +3 -17
- package/dist/resumeRefusalCopy.d.ts +11 -0
- package/dist/resumeRefusalCopy.js +61 -4
- package/dist/rewindArchiveCapability.js +4 -4
- package/dist/rewindWireCaps.d.ts +2 -1
- package/dist/rewindWireCaps.js +19 -2
- package/dist/ruleCompileVerdict.d.ts +2 -0
- package/dist/ruleCompileVerdict.js +13 -0
- package/dist/ruleRemovalConsequence.d.ts +2 -1
- package/dist/runCancelContext.d.ts +12 -0
- package/dist/runCancelContext.js +83 -1
- package/dist/seam.d.ts +2 -0
- package/dist/seam.js +1 -1
- package/dist/seatContract.d.ts +2 -1
- package/dist/sessionMemoryStatus.d.ts +2 -4
- package/dist/sessionSyncFileHistoryCapability.d.ts +18 -0
- package/dist/sessionSyncFileHistoryCapability.js +50 -0
- package/dist/skillToolListsCapability.d.ts +18 -0
- package/dist/skillToolListsCapability.js +50 -0
- package/dist/sqlEngineCapability.js +1 -8
- package/dist/steerPriorityCapability.d.ts +18 -0
- package/dist/steerPriorityCapability.js +80 -0
- package/dist/steerReceipt.d.ts +9 -0
- package/dist/steerReceipt.js +25 -0
- package/dist/subagent/engineSubagentSteer.js +2 -9
- package/dist/supportFloor.js +2 -2
- package/dist/taskRequestWords.d.ts +7 -1
- package/dist/taskRequestWords.js +18 -8
- package/dist/toolHistoryBadTurn.d.ts +1 -0
- package/dist/toolHistoryBadTurn.js +89 -0
- package/dist/toolHistoryMismatch.d.ts +2 -1
- package/dist/toolHistoryMismatch.js +19 -6
- package/dist/toolResult.d.ts +8 -0
- package/dist/toolResult.js +47 -3
- package/dist/types/engineState.d.ts +2 -12
- package/dist/userAttachmentEnvelope.d.ts +61 -0
- package/dist/userAttachmentEnvelope.js +204 -0
- package/dist/userInvokedSkillsCapability.d.ts +18 -0
- package/dist/userInvokedSkillsCapability.js +50 -0
- package/dist/wireFailureShape.d.ts +3 -0
- package/dist/wireFailureShape.js +8 -0
- package/dist/wireRefusalCopy.d.ts +6 -0
- package/dist/wireRefusalCopy.js +26 -3
- package/dist/workflowsJournalCapability.d.ts +18 -0
- package/dist/workflowsJournalCapability.js +50 -0
- package/dist/writeProtectionCapability.d.ts +2 -4
- package/docs/INTEGRATION-CLIENTS.md +1489 -16
- package/package.json +3 -3
|
@@ -4,6 +4,10 @@ import { isEngineRefusedToolName } from './sessionPolicyDeliverable.js';
|
|
|
4
4
|
import { RULES_LEGACY_TOOL_NAME_WRITE_NOTE } from './refusedToolNameProse.js';
|
|
5
5
|
import { RULES_LEGACY_TOOL_NAME, isRulesRefusalCode } from '../engineErrorCodes.js';
|
|
6
6
|
import { rosterMountedNames } from './rosterMountedNames.js';
|
|
7
|
+
import { CORE_RULE_TOOL_NAME_VERDICTS } from '../generated/engineFactTables.js';
|
|
8
|
+
function isLegacyToolNameVerdict(v) {
|
|
9
|
+
return typeof v === 'string' && v !== 'current' && CORE_RULE_TOOL_NAME_VERDICTS.includes(v);
|
|
10
|
+
}
|
|
7
11
|
const RULE_FIELD_PRESENCE = {
|
|
8
12
|
toolAllow: true,
|
|
9
13
|
toolDeny: true,
|
|
@@ -14,7 +18,7 @@ const RULE_FIELD_PRESENCE = {
|
|
|
14
18
|
export const SESSION_POLICY_RULE_FIELDS = Object.freeze(Object.keys(RULE_FIELD_PRESENCE));
|
|
15
19
|
const MAX_RULE_ENTRIES = 10_000;
|
|
16
20
|
export function classifySessionPolicyFailure(e) {
|
|
17
|
-
const { status, errorCode, message, bodyField, bodyName } = wireFailureShapeOf(e);
|
|
21
|
+
const { status, errorCode, message, bodyField, bodyName, bodyVerdict, bodyCurrentName } = wireFailureShapeOf(e);
|
|
18
22
|
if (errorCode === undefined || errorCode === '')
|
|
19
23
|
return { kind: 'no-verdict', message };
|
|
20
24
|
if (errorCode === RULES_LEGACY_TOOL_NAME) {
|
|
@@ -23,6 +27,8 @@ export function classifySessionPolicyFailure(e) {
|
|
|
23
27
|
message,
|
|
24
28
|
...(bodyField === 'toolDeny' || bodyField === 'toolAllow' ? { field: bodyField } : {}),
|
|
25
29
|
...(bodyName !== undefined && bodyName !== '' ? { name: bodyName } : {}),
|
|
30
|
+
...(isLegacyToolNameVerdict(bodyVerdict) ? { verdict: bodyVerdict } : {}),
|
|
31
|
+
...(bodyCurrentName !== undefined && bodyCurrentName !== '' ? { currentName: bodyCurrentName } : {}),
|
|
26
32
|
};
|
|
27
33
|
}
|
|
28
34
|
if (isRulesRefusalCode(errorCode) && status !== undefined && status >= 400 && status < 500)
|
|
@@ -227,7 +233,7 @@ function unknownFrom(failure, leg) {
|
|
|
227
233
|
}
|
|
228
234
|
}
|
|
229
235
|
function legacyToolNameOutcome(failure, prior, add) {
|
|
230
|
-
const { field, name } = failure;
|
|
236
|
+
const { field, name, verdict, currentName } = failure;
|
|
231
237
|
let alreadyInRecord;
|
|
232
238
|
if (field !== undefined && name !== undefined) {
|
|
233
239
|
const inPrior = Object.hasOwn(prior, field) ? prior[field] : undefined;
|
|
@@ -242,6 +248,8 @@ function legacyToolNameOutcome(failure, prior, add) {
|
|
|
242
248
|
message: failure.message,
|
|
243
249
|
...(field !== undefined ? { field } : {}),
|
|
244
250
|
...(name !== undefined ? { name } : {}),
|
|
251
|
+
...(verdict !== undefined ? { verdict } : {}),
|
|
252
|
+
...(currentName !== undefined ? { currentName } : {}),
|
|
245
253
|
...(alreadyInRecord !== undefined ? { alreadyInRecord } : {}),
|
|
246
254
|
};
|
|
247
255
|
}
|
|
@@ -344,6 +352,69 @@ export function sessionPolicyTightenNotice(outcome) {
|
|
|
344
352
|
}
|
|
345
353
|
}
|
|
346
354
|
}
|
|
355
|
+
const READ_NOTICE_GENERIC = 'This session’s rule record could not be shown, so what it holds is not known. Try reading it again.';
|
|
356
|
+
const READ_NOTICE_NO_TARGET = 'There is no engine connection for this session, so its rule record cannot be read and what it holds is not known. Look again once it is connected.';
|
|
357
|
+
function readFailureSentence(kind) {
|
|
358
|
+
switch (kind) {
|
|
359
|
+
case 'face-unavailable':
|
|
360
|
+
return 'This deployment does not keep per-session tool rules, so there is no session rule record to read.';
|
|
361
|
+
case 'loosen-forbidden':
|
|
362
|
+
return 'The engine answered this read with a refusal that only applies to relaxing rules, so this session’s rule record could not be read. Try again; if it keeps happening, whoever runs the engine needs to look at it.';
|
|
363
|
+
case 'store-corrupt':
|
|
364
|
+
return 'The engine could not establish which version this session’s rules are at, so it would not hand the record over. This needs an operator to look at the rule store.';
|
|
365
|
+
case 'cas-conflict':
|
|
366
|
+
return 'The engine reported a version clash on this session’s rule record, so it could not be read this time. Try again.';
|
|
367
|
+
case 'session-ownerless':
|
|
368
|
+
return 'This session has no owner, so it has no rule record to read.';
|
|
369
|
+
case 'session-not-found':
|
|
370
|
+
return 'This session is not readable from here — it may not exist, or it may belong to someone else — so its rule record cannot be shown. Check that you are connected to the engine and the session you meant, or continue in a new session.';
|
|
371
|
+
case 'request-rejected':
|
|
372
|
+
return 'The engine rejected the request to read this session’s rule record as malformed, so it could not be read. Sending the same request again will not change that; check which session was asked for.';
|
|
373
|
+
case 'legacy-tool-name':
|
|
374
|
+
return 'The engine answered this read with a refusal about a tool name it no longer accepts, so this session’s rule record could not be read. Try again; if it keeps happening, whoever runs the engine needs to look at it.';
|
|
375
|
+
case 'unauthorized':
|
|
376
|
+
return 'This call could not present a verifiable identity, so this session’s rule record could not be read.';
|
|
377
|
+
case 'error':
|
|
378
|
+
return 'The engine refused to hand over this session’s rule record for a reason this version has no wording for, so it could not be read. Try again; if it keeps happening, whoever runs the engine needs to look at it.';
|
|
379
|
+
case 'no-verdict':
|
|
380
|
+
return 'No clear answer came back from the engine when this session’s rule record was read, so what it holds is not known — that is not the same as holding nothing. Try again.';
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
function readMalformedSentence(why) {
|
|
384
|
+
switch (why) {
|
|
385
|
+
case 'envelope':
|
|
386
|
+
return 'The engine answered, but not in a form this version can read as a session rule record, so what the record holds is not known. Try again; if it keeps happening, this version and the engine may be out of step.';
|
|
387
|
+
case 'rev':
|
|
388
|
+
return 'The engine’s answer for this session’s rule record carried no usable version, so this version will not show it — a record it cannot place may still hold restrictions that are in effect. Try again.';
|
|
389
|
+
case 'rule_field':
|
|
390
|
+
return 'One of the lists in this session’s rule record came back in a form this version cannot read, so none of the record is shown rather than part of it — a partly shown record could leave out restrictions that are in effect.';
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function ownRead(o, key) {
|
|
394
|
+
const d = Object.getOwnPropertyDescriptor(o, key);
|
|
395
|
+
return d !== undefined && Object.hasOwn(d, 'value') ? d.value : undefined;
|
|
396
|
+
}
|
|
397
|
+
export function sessionPolicyReadNotice(outcome) {
|
|
398
|
+
try {
|
|
399
|
+
if (outcome === null || typeof outcome !== 'object')
|
|
400
|
+
return READ_NOTICE_GENERIC;
|
|
401
|
+
const arm = ownRead(outcome, 'kind');
|
|
402
|
+
if (arm === 'failed') {
|
|
403
|
+
const failure = ownRead(outcome, 'failure');
|
|
404
|
+
if (failure === null || typeof failure !== 'object')
|
|
405
|
+
return READ_NOTICE_GENERIC;
|
|
406
|
+
return readFailureSentence(ownRead(failure, 'kind')) ?? READ_NOTICE_GENERIC;
|
|
407
|
+
}
|
|
408
|
+
if (arm === 'malformed')
|
|
409
|
+
return readMalformedSentence(ownRead(outcome, 'why')) ?? READ_NOTICE_GENERIC;
|
|
410
|
+
if (arm === 'no_target')
|
|
411
|
+
return READ_NOTICE_NO_TARGET;
|
|
412
|
+
return READ_NOTICE_GENERIC;
|
|
413
|
+
}
|
|
414
|
+
catch {
|
|
415
|
+
return READ_NOTICE_GENERIC;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
347
418
|
function withoutRefusedEntries(prior, mounted) {
|
|
348
419
|
const REFUSABLE_NAME_FIELDS = ['toolDeny', 'toolAllow'];
|
|
349
420
|
const isRefusable = (f) => REFUSABLE_NAME_FIELDS.includes(f);
|
|
@@ -425,6 +496,8 @@ async function attemptRemoval(facade, sessionId, mounted, opts) {
|
|
|
425
496
|
message: failure.message,
|
|
426
497
|
...(failure.field !== undefined ? { field: failure.field } : {}),
|
|
427
498
|
...(failure.name !== undefined ? { name: failure.name } : {}),
|
|
499
|
+
...(failure.verdict !== undefined ? { verdict: failure.verdict } : {}),
|
|
500
|
+
...(failure.currentName !== undefined ? { currentName: failure.currentName } : {}),
|
|
428
501
|
},
|
|
429
502
|
};
|
|
430
503
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RESUME_REOPEN_CODES, RESUME_ENV_FAILED, RESUME_TOOL_UNAVAILABLE } from '../engineErrorCodes.js';
|
|
1
|
+
import { RESUME_REOPEN_CODES, RESUME_ENV_FAILED, RESUME_TOOL_UNAVAILABLE, refusalSaysStillPending } from '../engineErrorCodes.js';
|
|
2
2
|
const UNSTATED = Object.freeze({ kind: 'unstated' });
|
|
3
3
|
const NOT_REOPENED = Object.freeze({ kind: 'not_reopened' });
|
|
4
4
|
export function suspendedReopenOf(ev) {
|
|
@@ -25,7 +25,7 @@ export function resumeReopenFromError(err) {
|
|
|
25
25
|
const code = err.errorCode;
|
|
26
26
|
if (typeof code !== 'string' || !RESUME_REOPEN_CODES.includes(code))
|
|
27
27
|
return null;
|
|
28
|
-
if (err
|
|
28
|
+
if (!refusalSaysStillPending(err))
|
|
29
29
|
return null;
|
|
30
30
|
const reason = code.slice('resume.'.length);
|
|
31
31
|
return { code, reason, retriable: true };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type GateCurrentPending, type HitlFailureStage, type HitlSafetyCode, type HitlClientLike, type DecideOperationObserver } from './hitlBridge.js';
|
|
2
|
+
import { type AllowRuleShadowedWireMember, type ApprovalAllowRuleShadow } from './allowRuleShadow.js';
|
|
2
3
|
import { type RuleStoreUnreadableKind } from '../gateVocabulary.js';
|
|
3
4
|
import { type ApprovalMandateWord } from '../gateVocabulary.js';
|
|
4
5
|
import type { ToolPermissionRequest } from '../seatContract.js';
|
|
@@ -37,6 +38,7 @@ export type FsApprovalOutcome = {
|
|
|
37
38
|
reason: string;
|
|
38
39
|
code?: 'no_pending' | undefined;
|
|
39
40
|
errorCode?: string | undefined;
|
|
41
|
+
retriable?: true;
|
|
40
42
|
safetyCode?: HitlSafetyCode | undefined;
|
|
41
43
|
retryExhausted?: true;
|
|
42
44
|
currentPending?: GateCurrentPending | undefined;
|
|
@@ -130,7 +132,10 @@ export interface ApprovalCardRequest {
|
|
|
130
132
|
inputHasBidi?: true;
|
|
131
133
|
hasBidiControls?: true;
|
|
132
134
|
persistedRuleShadowed?: string;
|
|
135
|
+
allowRuleShadow?: ApprovalAllowRuleShadow;
|
|
133
136
|
probeCause?: unknown;
|
|
137
|
+
probeReason?: string;
|
|
138
|
+
rememberRefused?: true;
|
|
134
139
|
ruleEvidence?: unknown;
|
|
135
140
|
requiresRealApproval?: true;
|
|
136
141
|
irreversibleParkGate?: true;
|
|
@@ -179,7 +184,10 @@ export interface ToolApprovalFrame {
|
|
|
179
184
|
denialLimitFallback?: DenialLimitFallback;
|
|
180
185
|
ruleStoreUnreadable?: string;
|
|
181
186
|
persistedRuleShadowed?: string;
|
|
187
|
+
allowRuleShadowed?: readonly AllowRuleShadowedWireMember[];
|
|
182
188
|
probeCause?: unknown;
|
|
189
|
+
probeReason?: string;
|
|
190
|
+
rememberRefused?: true;
|
|
183
191
|
ruleEvidence?: unknown;
|
|
184
192
|
requiresRealApproval?: true;
|
|
185
193
|
mandated?: true;
|
|
@@ -204,7 +212,7 @@ export interface ToolApprovalDelegation {
|
|
|
204
212
|
depth: number;
|
|
205
213
|
agentName?: string;
|
|
206
214
|
}
|
|
207
|
-
export declare const TOOL_APPROVAL_FRAME_KEYS_MIRROR: readonly ["type", "approvalId", "toolCallId", "toolName", "sourceTaskId", "fromSubagent", "sourceAgentName", "message", "args", "argsOmitted", "governanceForced", "ruleSuggestions", "ruleOffers", "ruleOffersAbsence", "denialLimitFallback", "ruleStoreUnreadable", "readRootCandidate", "mandated", "mandate", "origin", "askClass", "classes", "inputHasBidi", "parked", "persistedRuleShadowed", "probeCause", "ruleEvidence", "requiresRealApproval", "expiresInMs", "expiresAtMs", "serverNowMs", "delegation", "outcome"];
|
|
215
|
+
export declare const TOOL_APPROVAL_FRAME_KEYS_MIRROR: readonly ["type", "approvalId", "toolCallId", "toolName", "sourceTaskId", "fromSubagent", "sourceAgentName", "message", "args", "argsOmitted", "governanceForced", "ruleSuggestions", "ruleOffers", "ruleOffersAbsence", "denialLimitFallback", "ruleStoreUnreadable", "readRootCandidate", "mandated", "mandate", "origin", "askClass", "classes", "inputHasBidi", "parked", "persistedRuleShadowed", "allowRuleShadowed", "probeCause", "probeReason", "rememberRefused", "ruleEvidence", "requiresRealApproval", "expiresInMs", "expiresAtMs", "serverNowMs", "delegation", "outcome"];
|
|
208
216
|
export interface ApprovalMandatedFacts {
|
|
209
217
|
readonly mandated?: true;
|
|
210
218
|
readonly ruleOffersAbsence?: string;
|
|
@@ -2,14 +2,16 @@ import { APPROVAL_CARD_PORT_KEY_MISMATCH_REASON, DEFAULT_DENY_REASON, DecideTran
|
|
|
2
2
|
import { askParkRowArm } from './askParkRowRouting.js';
|
|
3
3
|
import { hostLog } from '../host.js';
|
|
4
4
|
import { readOwnNonEmptyString } from '../ownKey.js';
|
|
5
|
+
import { readAskClassPair } from './askClassPair.js';
|
|
6
|
+
import { legacyShadowedRuleTextOf, readAllowRuleShadowFromWire } from './allowRuleShadow.js';
|
|
5
7
|
import { createSessionSlot, DEFAULT_SESSION_KEY } from '../sessionSlot.js';
|
|
6
8
|
import { readEngineActiveBgTasks } from '../fleet/fleetLedger.js';
|
|
7
9
|
import { observeCancelByDeny, surfaceRememberNotApplied, surfaceEditNotForwarded, surfaceEditRefusedOnBlindAsk, surfaceRuleArmNotSent, surfaceRuleArmRejected } from './hitlHostSurface.js';
|
|
8
10
|
import { approvalCallKey, liveFrameCallKey } from './gateIdentity.js';
|
|
9
|
-
import { isRuleStoreUnreadableKind } from '../gateVocabulary.js';
|
|
10
11
|
import { isApprovalMandateWord } from '../gateVocabulary.js';
|
|
11
12
|
import { denyAttributionRefusalFromError } from '../wireRefusalCopy.js';
|
|
12
13
|
import { decideFailureNote } from '../decideFailureNote.js';
|
|
14
|
+
import { refusalSaysStillPending } from '../engineErrorCodes.js';
|
|
13
15
|
import { readDecideReceipt } from '../decideReceipt.js';
|
|
14
16
|
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';
|
|
15
17
|
export function isFsApprovalGate(gate) {
|
|
@@ -190,9 +192,9 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
|
|
|
190
192
|
const callKey = approvalCallKey(gatedCallId, taskId);
|
|
191
193
|
const ruleOffersReadOnly = readRuleOfferSupply(pending.ruleOffers, pending.ruleSuggestions);
|
|
192
194
|
const durableProbeCause = pending.riskDescriptor?.probeCause;
|
|
193
|
-
const
|
|
195
|
+
const durableProbeReason = readProbeReason(pending.riskDescriptor);
|
|
196
|
+
const durableShadow = readAllowRuleShadowFromWire(pending, 'row');
|
|
194
197
|
const durableRuleOffersAbsence = pending.ruleOffersAbsence;
|
|
195
|
-
const durableRuleStoreUnreadable = readRuleStoreUnreadable(pending.ruleStoreUnreadable);
|
|
196
198
|
deps.onPresented?.();
|
|
197
199
|
const card = await surfaceApprovalCard({
|
|
198
200
|
toolName,
|
|
@@ -215,12 +217,10 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
|
|
|
215
217
|
...(pending.hasBidiControls === true ? { hasBidiControls: true } : {}),
|
|
216
218
|
...(ruleOffersReadOnly !== undefined ? { ruleOffersReadOnly } : {}),
|
|
217
219
|
...(isWireRecordCarrier(durableProbeCause) ? { probeCause: durableProbeCause } : {}),
|
|
218
|
-
...(
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
...(
|
|
222
|
-
? { persistedRuleShadowed: durableShadowedRule }
|
|
223
|
-
: {}),
|
|
220
|
+
...(durableProbeReason !== undefined ? { probeReason: durableProbeReason } : {}),
|
|
221
|
+
...(readRememberRefused(pending) ? { rememberRefused: true } : {}),
|
|
222
|
+
...(durableShadow !== undefined ? { allowRuleShadow: durableShadow } : {}),
|
|
223
|
+
...((t) => (t !== undefined ? { persistedRuleShadowed: t } : {}))(legacyShadowedRuleTextOf(durableShadow)),
|
|
224
224
|
...(typeof durableRuleOffersAbsence === 'string' && durableRuleOffersAbsence !== ''
|
|
225
225
|
? { ruleOffersAbsence: durableRuleOffersAbsence }
|
|
226
226
|
: {}),
|
|
@@ -279,6 +279,7 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
|
|
|
279
279
|
catch (e) {
|
|
280
280
|
const currentPending = readDecideCurrentPending(e);
|
|
281
281
|
const wireCode = readWireErrorCode(e);
|
|
282
|
+
const wireRetriable = typeof e === 'object' && e !== null && refusalSaysStillPending(e);
|
|
282
283
|
const safetyCode = e instanceof HitlSafetyError ? e.code : undefined;
|
|
283
284
|
return {
|
|
284
285
|
kind: 'failed',
|
|
@@ -288,6 +289,7 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
|
|
|
288
289
|
...(e instanceof DecideTransportRetryExhaustedError ? { retryExhausted: true } : {}),
|
|
289
290
|
...(currentPending !== undefined ? { currentPending } : {}),
|
|
290
291
|
...(wireCode !== undefined ? { errorCode: wireCode } : {}),
|
|
292
|
+
...(wireRetriable ? { retriable: true } : {}),
|
|
291
293
|
...(safetyCode !== undefined ? { safetyCode } : {}),
|
|
292
294
|
};
|
|
293
295
|
}
|
|
@@ -335,6 +337,7 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
|
|
|
335
337
|
catch (e) {
|
|
336
338
|
const currentPending = readDecideCurrentPending(e);
|
|
337
339
|
const wireCode = readWireErrorCode(e);
|
|
340
|
+
const wireRetriable = typeof e === 'object' && e !== null && refusalSaysStillPending(e);
|
|
338
341
|
const safetyCode = e instanceof HitlSafetyError ? e.code : undefined;
|
|
339
342
|
const attributionRefusal = denyAttributionRefusalFromError(e, lastSendCarriedAttribution);
|
|
340
343
|
return {
|
|
@@ -345,6 +348,7 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
|
|
|
345
348
|
...(e instanceof DecideTransportRetryExhaustedError ? { retryExhausted: true } : {}),
|
|
346
349
|
...(currentPending !== undefined ? { currentPending } : {}),
|
|
347
350
|
...(wireCode !== undefined ? { errorCode: wireCode } : {}),
|
|
351
|
+
...(wireRetriable ? { retriable: true } : {}),
|
|
348
352
|
...(safetyCode !== undefined ? { safetyCode } : {}),
|
|
349
353
|
...(attributionRefusal !== null ? { denyAttributionRefusal: attributionRefusal } : {}),
|
|
350
354
|
};
|
|
@@ -392,7 +396,10 @@ export const TOOL_APPROVAL_FRAME_KEYS_MIRROR = [
|
|
|
392
396
|
'inputHasBidi',
|
|
393
397
|
'parked',
|
|
394
398
|
'persistedRuleShadowed',
|
|
399
|
+
'allowRuleShadowed',
|
|
395
400
|
'probeCause',
|
|
401
|
+
'probeReason',
|
|
402
|
+
'rememberRefused',
|
|
396
403
|
'ruleEvidence',
|
|
397
404
|
'requiresRealApproval',
|
|
398
405
|
'expiresInMs',
|
|
@@ -437,30 +444,6 @@ export function toolPermissionRequestAskBits(card) {
|
|
|
437
444
|
...(askClassPair ?? {}),
|
|
438
445
|
};
|
|
439
446
|
}
|
|
440
|
-
function readAskClassPair(v) {
|
|
441
|
-
if (typeof v !== 'object' || v === null)
|
|
442
|
-
return undefined;
|
|
443
|
-
const askClass = readOwnNonEmptyString(v, 'askClass');
|
|
444
|
-
if (askClass === undefined || !Object.hasOwn(v, 'classes'))
|
|
445
|
-
return undefined;
|
|
446
|
-
const raw = v.classes;
|
|
447
|
-
if (!Array.isArray(raw) || raw.length === 0)
|
|
448
|
-
return undefined;
|
|
449
|
-
const classes = [];
|
|
450
|
-
const seen = new Set();
|
|
451
|
-
for (let i = 0; i < raw.length; i++) {
|
|
452
|
-
if (!Object.hasOwn(raw, i))
|
|
453
|
-
return undefined;
|
|
454
|
-
const c = raw[i];
|
|
455
|
-
if (typeof c !== 'string' || c === '' || seen.has(c))
|
|
456
|
-
return undefined;
|
|
457
|
-
seen.add(c);
|
|
458
|
-
classes.push(c);
|
|
459
|
-
}
|
|
460
|
-
if (classes[0] !== askClass)
|
|
461
|
-
return undefined;
|
|
462
|
-
return { askClass, classes: Object.freeze(classes) };
|
|
463
|
-
}
|
|
464
447
|
function hasOwnStrictTrue(v, key) {
|
|
465
448
|
return Object.hasOwn(v, key) && v[key] === true;
|
|
466
449
|
}
|
|
@@ -644,6 +627,25 @@ function pathFromGateMessage(message) {
|
|
|
644
627
|
return undefined;
|
|
645
628
|
return body.slice(0, close);
|
|
646
629
|
}
|
|
630
|
+
function readProbeReason(v) {
|
|
631
|
+
try {
|
|
632
|
+
if (typeof v !== 'object' || v === null || !Object.hasOwn(v, 'probeReason'))
|
|
633
|
+
return undefined;
|
|
634
|
+
const raw = v.probeReason;
|
|
635
|
+
return typeof raw === 'string' && raw.trim() !== '' ? raw : undefined;
|
|
636
|
+
}
|
|
637
|
+
catch {
|
|
638
|
+
return undefined;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
function readRememberRefused(v) {
|
|
642
|
+
try {
|
|
643
|
+
return typeof v === 'object' && v !== null && Object.hasOwn(v, 'rememberRefused') && v.rememberRefused === true;
|
|
644
|
+
}
|
|
645
|
+
catch {
|
|
646
|
+
return false;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
647
649
|
function isNonNegativeFinite(v) {
|
|
648
650
|
return typeof v === 'number' && Number.isFinite(v) && v >= 0;
|
|
649
651
|
}
|
|
@@ -669,9 +671,6 @@ export function readDenialLimitFallback(v) {
|
|
|
669
671
|
autoDenyAfterMs: d.autoDenyAfterMs,
|
|
670
672
|
};
|
|
671
673
|
}
|
|
672
|
-
function readRuleStoreUnreadable(v) {
|
|
673
|
-
return isRuleStoreUnreadableKind(v) ? v : undefined;
|
|
674
|
-
}
|
|
675
674
|
function isRuleOfferMatch(v) {
|
|
676
675
|
return typeof v === 'string' && RULE_OFFER_MATCHES.includes(v);
|
|
677
676
|
}
|
|
@@ -857,6 +856,7 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
857
856
|
const argsNotRealInput = argsFallback || lane?.argsUnavailable === true;
|
|
858
857
|
const ruleOffers = readRuleOfferSupply(frame.ruleOffers, frame.ruleSuggestions);
|
|
859
858
|
const denialLimitFallback = readDenialLimitFallback(frame.denialLimitFallback);
|
|
859
|
+
const frameShadow = readAllowRuleShadowFromWire(frame, 'frame');
|
|
860
860
|
const card = await surfaceApprovalCard({
|
|
861
861
|
toolName,
|
|
862
862
|
args: args,
|
|
@@ -883,10 +883,11 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
883
883
|
? { delegation: frame.delegation }
|
|
884
884
|
: {}),
|
|
885
885
|
...(ruleOffers !== undefined ? { ruleOffers } : {}),
|
|
886
|
-
...(
|
|
887
|
-
|
|
888
|
-
: {}),
|
|
886
|
+
...((sh) => (sh !== undefined ? { allowRuleShadow: sh } : {}))(frameShadow),
|
|
887
|
+
...((t) => (t !== undefined ? { persistedRuleShadowed: t } : {}))(legacyShadowedRuleTextOf(frameShadow)),
|
|
889
888
|
...(isWireRecordCarrier(frame.probeCause) ? { probeCause: frame.probeCause } : {}),
|
|
889
|
+
...((r) => (r !== undefined ? { probeReason: r } : {}))(readProbeReason(frame)),
|
|
890
|
+
...(readRememberRefused(frame) ? { rememberRefused: true } : {}),
|
|
890
891
|
...(isWireRecordCarrier(frame.ruleEvidence) ? { ruleEvidence: frame.ruleEvidence } : {}),
|
|
891
892
|
...(frame.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
892
893
|
...(hasOwnStrictTrue(frame, 'mandated') ? { mandated: true } : {}),
|
|
@@ -897,7 +898,6 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
897
898
|
? { ruleOffersAbsence: frame.ruleOffersAbsence }
|
|
898
899
|
: {}),
|
|
899
900
|
...(denialLimitFallback !== undefined ? { denialLimitFallback } : {}),
|
|
900
|
-
...((k) => (k !== undefined ? { ruleStoreUnreadable: k } : {}))(readRuleStoreUnreadable(frame.ruleStoreUnreadable)),
|
|
901
901
|
...((o) => (o !== undefined ? { origin: o } : {}))(readOwnNonEmptyString(frame, 'origin')),
|
|
902
902
|
...(readAskClassPair(frame) ?? {}),
|
|
903
903
|
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type HookMatcherUnjudgedReason = 'event_out_of_scope' | 'not_a_string' | 'oversize' | 'invalid_pattern' | 'pattern_unsupported' | 'over_budget';
|
|
2
|
+
export type HookMatcherVerdict = {
|
|
3
|
+
readonly kind: 'matchesAll';
|
|
4
|
+
} | {
|
|
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';
|
|
15
|
+
readonly aliases: readonly {
|
|
16
|
+
readonly alias: string;
|
|
17
|
+
readonly canonical: string;
|
|
18
|
+
}[];
|
|
19
|
+
} | {
|
|
20
|
+
readonly kind: 'refused';
|
|
21
|
+
readonly reason: 'alias_without_canonical';
|
|
22
|
+
readonly reading: 'names' | 'pattern';
|
|
23
|
+
readonly alias: string;
|
|
24
|
+
readonly canonical: string;
|
|
25
|
+
} | {
|
|
26
|
+
readonly kind: 'unjudged';
|
|
27
|
+
readonly reason: HookMatcherUnjudgedReason;
|
|
28
|
+
};
|
|
29
|
+
export declare function hookMatcherVerdict(event: string, matcher: unknown): HookMatcherVerdict;
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { HOOK_TOOL_ALIASES } from './hookToolAliases.js';
|
|
2
|
+
import { SETTINGS_TOOL_NAME_MATCHER_EVENTS } from './generated/settingsSchemaTables.js';
|
|
3
|
+
const TOOL_NAME_MATCHER_EVENTS = new Set(SETTINGS_TOOL_NAME_MATCHER_EVENTS);
|
|
4
|
+
const MATCHER_MAX_CHARS = 8192;
|
|
5
|
+
const PATTERN_WORK_BUDGET = 10_000_000;
|
|
6
|
+
const PATTERN_MAX_DEPTH = 32;
|
|
7
|
+
const COUNTED_REPEAT_MAX = 1000;
|
|
8
|
+
function unjudged(reason) {
|
|
9
|
+
return Object.freeze({ kind: 'unjudged', reason });
|
|
10
|
+
}
|
|
11
|
+
function refused(reading, p) {
|
|
12
|
+
return Object.freeze({ kind: 'refused', reason: 'alias_without_canonical', reading, alias: p.alias, canonical: p.canonical });
|
|
13
|
+
}
|
|
14
|
+
function aliasPairs() {
|
|
15
|
+
return Object.entries(HOOK_TOOL_ALIASES).map(([alias, canonical]) => ({ alias, canonical }));
|
|
16
|
+
}
|
|
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
|
+
const UNSUPPORTED = Symbol('unsupported');
|
|
42
|
+
const SINGLE_CHAR_ESCAPES = 'dDwWsStnrfv^$\\.*+?()[]{}|/-';
|
|
43
|
+
function patternBound(src, n) {
|
|
44
|
+
let i = 0;
|
|
45
|
+
let depth = 0;
|
|
46
|
+
const fail = () => {
|
|
47
|
+
throw UNSUPPORTED;
|
|
48
|
+
};
|
|
49
|
+
const quantifier = () => {
|
|
50
|
+
const c = src[i];
|
|
51
|
+
let lo;
|
|
52
|
+
let hi;
|
|
53
|
+
if (c === '*') {
|
|
54
|
+
lo = 0;
|
|
55
|
+
hi = Infinity;
|
|
56
|
+
i++;
|
|
57
|
+
}
|
|
58
|
+
else if (c === '+') {
|
|
59
|
+
lo = 1;
|
|
60
|
+
hi = Infinity;
|
|
61
|
+
i++;
|
|
62
|
+
}
|
|
63
|
+
else if (c === '?') {
|
|
64
|
+
lo = 0;
|
|
65
|
+
hi = 1;
|
|
66
|
+
i++;
|
|
67
|
+
}
|
|
68
|
+
else if (c === '{') {
|
|
69
|
+
const q = /^\{(\d{1,4})(?:(,)(\d{0,4}))?\}/.exec(src.slice(i, i + 12));
|
|
70
|
+
if (q === null)
|
|
71
|
+
return fail();
|
|
72
|
+
lo = Number(q[1]);
|
|
73
|
+
hi = q[2] === undefined ? lo : q[3] === '' || q[3] === undefined ? Infinity : Number(q[3]);
|
|
74
|
+
if (lo > COUNTED_REPEAT_MAX || (hi !== Infinity && hi > COUNTED_REPEAT_MAX) || hi < lo)
|
|
75
|
+
fail();
|
|
76
|
+
i += q[0].length;
|
|
77
|
+
}
|
|
78
|
+
else
|
|
79
|
+
return undefined;
|
|
80
|
+
if (src[i] === '?')
|
|
81
|
+
i++;
|
|
82
|
+
return { lo, hi };
|
|
83
|
+
};
|
|
84
|
+
const term = () => {
|
|
85
|
+
const c = src[i];
|
|
86
|
+
if (c === '^' || c === '$') {
|
|
87
|
+
i++;
|
|
88
|
+
if (quantifier() !== undefined)
|
|
89
|
+
fail();
|
|
90
|
+
return [1, 1];
|
|
91
|
+
}
|
|
92
|
+
if (c === '\\' && (src[i + 1] === 'b' || src[i + 1] === 'B')) {
|
|
93
|
+
i += 2;
|
|
94
|
+
if (quantifier() !== undefined)
|
|
95
|
+
fail();
|
|
96
|
+
return [1, 1];
|
|
97
|
+
}
|
|
98
|
+
let paths = 1;
|
|
99
|
+
let steps = 1;
|
|
100
|
+
let single = true;
|
|
101
|
+
if (c === '(') {
|
|
102
|
+
i++;
|
|
103
|
+
if (src[i] === '?') {
|
|
104
|
+
if (src[i + 1] === ':')
|
|
105
|
+
i += 2;
|
|
106
|
+
else {
|
|
107
|
+
const named = /^\?<([A-Za-z_$][A-Za-z0-9_$]*)>/.exec(src.slice(i, i + 80));
|
|
108
|
+
if (named === null)
|
|
109
|
+
fail();
|
|
110
|
+
else
|
|
111
|
+
i += named[0].length;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (++depth > PATTERN_MAX_DEPTH)
|
|
115
|
+
fail();
|
|
116
|
+
[paths, steps] = disjunction();
|
|
117
|
+
if (src[i] !== ')')
|
|
118
|
+
fail();
|
|
119
|
+
i++;
|
|
120
|
+
depth--;
|
|
121
|
+
single = false;
|
|
122
|
+
}
|
|
123
|
+
else if (c === '[') {
|
|
124
|
+
i++;
|
|
125
|
+
if (src[i] === '^')
|
|
126
|
+
i++;
|
|
127
|
+
for (;;) {
|
|
128
|
+
if (i >= src.length)
|
|
129
|
+
fail();
|
|
130
|
+
const d = src[i];
|
|
131
|
+
if (d === ']') {
|
|
132
|
+
i++;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
i += d === '\\' ? 2 : 1;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
else if (c === '.')
|
|
139
|
+
i++;
|
|
140
|
+
else if (c === '\\') {
|
|
141
|
+
const e = src[i + 1];
|
|
142
|
+
if (e === undefined || !SINGLE_CHAR_ESCAPES.includes(e))
|
|
143
|
+
fail();
|
|
144
|
+
i += 2;
|
|
145
|
+
}
|
|
146
|
+
else if (c === undefined || '*+?{}]|)'.includes(c))
|
|
147
|
+
fail();
|
|
148
|
+
else
|
|
149
|
+
i++;
|
|
150
|
+
const q = quantifier();
|
|
151
|
+
if (q === undefined)
|
|
152
|
+
return [paths, steps];
|
|
153
|
+
if (single) {
|
|
154
|
+
if (q.lo > n)
|
|
155
|
+
return [1, n + 1];
|
|
156
|
+
const top = Math.min(q.hi, n);
|
|
157
|
+
return [top - q.lo + 1, top + 1];
|
|
158
|
+
}
|
|
159
|
+
const hiEff = Math.min(q.hi, Math.max(q.lo, n + 1));
|
|
160
|
+
if (q.lo > hiEff)
|
|
161
|
+
return [1, 1];
|
|
162
|
+
let sum = 0;
|
|
163
|
+
for (let k = q.lo; k <= hiEff; k++) {
|
|
164
|
+
sum += paths ** k;
|
|
165
|
+
if (sum === Infinity)
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
return [sum, hiEff * steps + 1];
|
|
169
|
+
};
|
|
170
|
+
const alternative = () => {
|
|
171
|
+
let paths = 1;
|
|
172
|
+
let steps = 0;
|
|
173
|
+
while (i < src.length && src[i] !== '|' && src[i] !== ')') {
|
|
174
|
+
const [p, s] = term();
|
|
175
|
+
paths *= p;
|
|
176
|
+
steps += s;
|
|
177
|
+
}
|
|
178
|
+
return [paths, steps];
|
|
179
|
+
};
|
|
180
|
+
const disjunction = () => {
|
|
181
|
+
let [paths, steps] = alternative();
|
|
182
|
+
while (src[i] === '|') {
|
|
183
|
+
i++;
|
|
184
|
+
const [p, s] = alternative();
|
|
185
|
+
paths += p;
|
|
186
|
+
steps = Math.max(steps, s);
|
|
187
|
+
}
|
|
188
|
+
return [paths, steps];
|
|
189
|
+
};
|
|
190
|
+
try {
|
|
191
|
+
const r = disjunction();
|
|
192
|
+
if (i !== src.length)
|
|
193
|
+
fail();
|
|
194
|
+
return r;
|
|
195
|
+
}
|
|
196
|
+
catch (e) {
|
|
197
|
+
if (e === UNSUPPORTED)
|
|
198
|
+
return undefined;
|
|
199
|
+
throw e;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
export function hookMatcherVerdict(event, matcher) {
|
|
203
|
+
if (typeof event !== 'string' || !TOOL_NAME_MATCHER_EVENTS.has(event))
|
|
204
|
+
return unjudged('event_out_of_scope');
|
|
205
|
+
if (matcher === undefined)
|
|
206
|
+
return Object.freeze({ kind: 'matchesAll' });
|
|
207
|
+
if (typeof matcher !== 'string')
|
|
208
|
+
return unjudged('not_a_string');
|
|
209
|
+
if (matcher.length > MATCHER_MAX_CHARS)
|
|
210
|
+
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 {
|
|
232
|
+
return unjudged('invalid_pattern');
|
|
233
|
+
}
|
|
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
|
+
const selects = (name) => {
|
|
242
|
+
if (matcher === name)
|
|
243
|
+
return true;
|
|
244
|
+
try {
|
|
245
|
+
return re.test(name);
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
const selected = [];
|
|
252
|
+
for (const p of pairs) {
|
|
253
|
+
const a = selects(p.alias);
|
|
254
|
+
if (a === undefined)
|
|
255
|
+
return unjudged('invalid_pattern');
|
|
256
|
+
if (!a)
|
|
257
|
+
continue;
|
|
258
|
+
const c = selects(p.canonical);
|
|
259
|
+
if (c === undefined)
|
|
260
|
+
return unjudged('invalid_pattern');
|
|
261
|
+
if (!c)
|
|
262
|
+
return refused('pattern', p);
|
|
263
|
+
selected.push(p);
|
|
264
|
+
}
|
|
265
|
+
return Object.freeze({ kind: 'accepted', reading: 'pattern', aliases: Object.freeze(selected.map((p) => Object.freeze({ ...p }))) });
|
|
266
|
+
}
|