@sema-agent/core 5.0.0 → 5.0.1
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 +16 -0
- package/dist/agents/repair-loop.js +9 -1
- package/dist/agents/send-message-tool.js +1 -1
- package/dist/agents/subagent.js +7 -2
- package/dist/core/permission-rules.d.ts +2 -2
- package/dist/core/permission-rules.js +10 -0
- package/dist/core/runner/prepare-task.js +22 -10
- package/dist/core/runner/session-rule-policy.d.ts +2 -2
- package/dist/core/runner/session-rule-policy.js +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.0.1 (2026-08-02)
|
|
4
|
+
|
|
5
|
+
_Post-release review patch: the 5.0.0 review wave (five domain reviewers + two independent codex legs) surfaced silent-widening gaps in the new audit surfaces plus wiring/anchoring stragglers. All fixes are loud-direction; no new API._
|
|
6
|
+
|
|
7
|
+
**Fixed**
|
|
8
|
+
|
|
9
|
+
- **Persisted session/ancestor rules join the retired-name audit (review G-2).** Session-rule policies were composed after the only policy-name audit pass and exposed no name metadata — a stored `{toolDeny: ["bash"]}` compiled clean and silently widened. The audit is now a reusable pass run over every narrowing layer, and `createSessionRulePolicy` returns a `NamedToolPolicy`.
|
|
10
|
+
- **Pre-prefix MCP names reach the hard arm (review G-3).** The `config.legacy_tool_name` check only consulted the static `RETIRED_TOOL_NAMES` map, which cannot enumerate dynamic MCP names — a v4-era policy entry like `github__delete_repository` (auto-prefixed by the retired canonicalizer) degraded to an advisory and the destructive call ran. An unmatched `__`-shaped name without the `mcp__` prefix now hard-fails prepare with prefix guidance; an `mcp__*` miss stays advisory (the server may not be mounted this run).
|
|
11
|
+
- **Repair-loop accounts stay live across an in-flight attempt (review G-4, time half).** A checkpoint minted mid-attempt clones the threaded bundle at that instant, and only a pre-dispatch stamp existed — an attempt that ran 900ms and parked persisted ~zero elapsed time, so the resume re-granted the washed budget. An unref'd 1s interval keeps the stamp current. (The money half — mid-flight partial spend — is tracked separately: it has a double-count design question against the resumed attempt's own stats.)
|
|
12
|
+
- **Permission-rule policies join the retired-name audit (review F-6).** `createPermissionRulePolicy` now returns a `NamedToolPolicy` exposing its compiled tool names as `nameSets`, so the prepare-time policy-name audit covers rule policies: a rule written with a RETIRED name (e.g. `{rule: "bash", behavior: "deny"}`) that matches nothing in the run's roster is now the same HARD `config.legacy_tool_name` prepare failure as a list policy — previously it compiled with zero issues and the deny silently guarded nothing. A deployment mounting its own tool under a retired name is unaffected (roster hit). Behavior note: configs carrying such stale rules now fail loudly at prepare instead of running silently widened.
|
|
13
|
+
- **Name-addressed revives anchor correctly (review F-1).** The SendMessage by-name resolution hand-copy dropped `createdAt`, so a `{to: NAME}` revive's spawn frame fell back to the wake instant for `startedAt` — the exact-id rung was fixed in 5.0.0, the name rung is now too.
|
|
14
|
+
- **Two more revive legs chain `root ?? parent` (review F-8).** The revived child's own spec internals and the re-minted registry row now derive the same root anchor as the roster/observer legs — a pre-floor row no longer yields an internally inconsistent agent (fleet view anchored, `canAccess` root arm blind).
|
|
15
|
+
- **The disclosure channel reaches both remaining composition roots (review F-2/F-3).** The runner's SendMessage mount wires `onNotifyError` to the `observer.notify_failed` trace lane, and the delegation tool's steer-lane resume threads `opts.onObserverError` — a throwing deployment sink on either revive path is now disclosed instead of counted on an unread notifier.
|
|
16
|
+
- **Checkpoint mints read the clock once.** All three checkpoint mint points stamped `createdAt` and `deadline` from separate `Date.now()` reads; a mint straddling a ms tick violated `deadline = createdAt + ttl` by 1ms.
|
|
17
|
+
- Comment-truth sweep: 14 sites still narrating the deleted OLD_TO_NEW/tombstone machinery rewritten to post-5.0.0 behavior; `markStopSourceByShellId`'s orphaned docstring relocated and corrected (env is REQUIRED for effect — an env-less call is a no-op).
|
|
18
|
+
|
|
3
19
|
## 5.0.0 (2026-08-02)
|
|
4
20
|
|
|
5
21
|
_The baggage-unload major: the compatibility faces RB-476 cleared for tool NAMES are now cleared for id arguments, adapters and indexes too (RB-479), plus the revive-frame anchoring fix a downstream consumer was blocked on (RB-478). Everything that used to resolve silently under an old spelling now refuses loudly with the current spelling named._
|
|
@@ -194,7 +194,15 @@ export async function runRepairLoop(runner, implSpec, config) {
|
|
|
194
194
|
}
|
|
195
195
|
: implSpec;
|
|
196
196
|
restartedOnce = false;
|
|
197
|
-
const
|
|
197
|
+
const liveStamp = setInterval(stampAccount, 1_000);
|
|
198
|
+
liveStamp.unref?.();
|
|
199
|
+
let result;
|
|
200
|
+
try {
|
|
201
|
+
result = await runner.runTask(spec, { repairBundle: bundle });
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
clearInterval(liveStamp);
|
|
205
|
+
}
|
|
198
206
|
spend += (result.stats.costMicroUsd ?? 0) + (result.stats.nested?.costMicroUsd ?? 0);
|
|
199
207
|
stampAccount();
|
|
200
208
|
accumulate(result.stats);
|
|
@@ -369,7 +369,7 @@ export function createSendMessageTool(opts) {
|
|
|
369
369
|
}
|
|
370
370
|
if (byName.status === "found") {
|
|
371
371
|
const h = byName.handle;
|
|
372
|
-
target = { task_id: h.id, type: h.type, status: h.status, ...(h.toolUseId !== undefined ? { toolUseId: h.toolUseId } : {}), ...(h.sessionScoped ? { sessionScoped: true } : {}), ...(h.description !== undefined ? { description: h.description } : {}), ...(h.name !== undefined ? { name: h.name } : {}), ...(h.agentType !== undefined ? { agentType: h.agentType } : {}), ...(h.owner !== undefined ? { owner: h.owner } : {}), ...(h.scope !== undefined ? { scope: h.scope } : {}), ...(h.parentTaskId !== undefined ? { parentTaskId: h.parentTaskId } : {}), ...(h.parentSessionId !== undefined ? { parentSessionId: h.parentSessionId } : {}), ...(h.rootSessionId !== undefined ? { rootSessionId: h.rootSessionId } : {}) };
|
|
372
|
+
target = { task_id: h.id, type: h.type, status: h.status, createdAt: h.createdAt, ...(h.toolUseId !== undefined ? { toolUseId: h.toolUseId } : {}), ...(h.sessionScoped ? { sessionScoped: true } : {}), ...(h.description !== undefined ? { description: h.description } : {}), ...(h.name !== undefined ? { name: h.name } : {}), ...(h.agentType !== undefined ? { agentType: h.agentType } : {}), ...(h.owner !== undefined ? { owner: h.owner } : {}), ...(h.scope !== undefined ? { scope: h.scope } : {}), ...(h.parentTaskId !== undefined ? { parentTaskId: h.parentTaskId } : {}), ...(h.parentSessionId !== undefined ? { parentSessionId: h.parentSessionId } : {}), ...(h.rootSessionId !== undefined ? { rootSessionId: h.rootSessionId } : {}) };
|
|
373
373
|
}
|
|
374
374
|
else {
|
|
375
375
|
let rosterHit;
|
package/dist/agents/subagent.js
CHANGED
|
@@ -1381,7 +1381,9 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
1381
1381
|
? {
|
|
1382
1382
|
...(reviveClaim.row.parentTaskId !== undefined ? { parentTaskId: reviveClaim.row.parentTaskId } : {}),
|
|
1383
1383
|
...(reviveClaim.row.parentSessionId !== undefined ? { parentSessionId: reviveClaim.row.parentSessionId } : {}),
|
|
1384
|
-
...(reviveClaim.row.rootSessionId
|
|
1384
|
+
...((reviveClaim.row.rootSessionId ?? reviveClaim.row.parentSessionId) !== undefined
|
|
1385
|
+
? { rootSessionId: reviveClaim.row.rootSessionId ?? reviveClaim.row.parentSessionId }
|
|
1386
|
+
: {}),
|
|
1385
1387
|
}
|
|
1386
1388
|
: {
|
|
1387
1389
|
...(ctx.taskId !== undefined ? { parentTaskId: ctx.taskId } : {}),
|
|
@@ -2045,7 +2047,9 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
2045
2047
|
...(reviveRow.name !== undefined ? { name: reviveRow.name } : {}),
|
|
2046
2048
|
...(reviveRow.parentTaskId !== undefined ? { parentTaskId: reviveRow.parentTaskId } : {}),
|
|
2047
2049
|
...(reviveRow.parentSessionId !== undefined ? { parentSessionId: reviveRow.parentSessionId } : {}),
|
|
2048
|
-
...(reviveRow.rootSessionId
|
|
2050
|
+
...((reviveRow.rootSessionId ?? reviveRow.parentSessionId) !== undefined
|
|
2051
|
+
? { rootSessionId: reviveRow.rootSessionId ?? reviveRow.parentSessionId }
|
|
2052
|
+
: {}),
|
|
2049
2053
|
...(reviveRow.model !== undefined ? { model: reviveRow.model } : {}),
|
|
2050
2054
|
...(reviveRow.teamName !== undefined ? { teamName: reviveRow.teamName } : {}),
|
|
2051
2055
|
deliveryChannel: "attaching",
|
|
@@ -2673,6 +2677,7 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
2673
2677
|
...(opts.background?.notify ? { notify: opts.background.notify } : {}),
|
|
2674
2678
|
sink: ctx.onSubagentSpawn,
|
|
2675
2679
|
...(opts.background ? { registry: opts.background.registry } : {}),
|
|
2680
|
+
...(opts.onObserverError !== undefined ? { onNotifyError: (f) => opts.onObserverError?.(f.error, { site: f.site }) } : {}),
|
|
2676
2681
|
});
|
|
2677
2682
|
notifier.notify(() => ctx.onSubagentSpawn?.(createSteerHandle(stream, ctx.toolCallId, childAgentName, settled, {
|
|
2678
2683
|
resume,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { NamedToolPolicy } from "./tool-policy.js";
|
|
2
2
|
export declare const BASH_GENERIC_PARAMS: ReadonlySet<string>;
|
|
3
3
|
export interface PermissionRule {
|
|
4
4
|
rule: string;
|
|
@@ -32,4 +32,4 @@ export declare function parsePermissionRule(rule: string): ParsedPermissionRule;
|
|
|
32
32
|
export declare function wildcardMatch(pattern: string, value: string): boolean;
|
|
33
33
|
export declare const fileToolParamVocabulary: (canonicalTool: string) => ReadonlySet<string> | undefined;
|
|
34
34
|
export declare function validatePermissionRules(rules: PermissionRule[], opts?: Pick<PermissionRulePolicyOptions, "primaryFieldGeneric" | "caps">): PermissionRuleIssue[];
|
|
35
|
-
export declare function createPermissionRulePolicy(rules: PermissionRule[], opts?: PermissionRulePolicyOptions):
|
|
35
|
+
export declare function createPermissionRulePolicy(rules: PermissionRule[], opts?: PermissionRulePolicyOptions): NamedToolPolicy;
|
|
@@ -259,7 +259,17 @@ export function createPermissionRulePolicy(rules, opts) {
|
|
|
259
259
|
}
|
|
260
260
|
}
|
|
261
261
|
const defaultAction = opts?.defaultAction ?? "allow";
|
|
262
|
+
const nameSets = { deny: [], ask: [], allow: [] };
|
|
263
|
+
for (const [toolName, entry] of byTool) {
|
|
264
|
+
if (entry.bare.deny !== undefined || entry.param.deny.length > 0)
|
|
265
|
+
nameSets.deny.push(toolName);
|
|
266
|
+
if (entry.bare.ask !== undefined || entry.param.ask.length > 0)
|
|
267
|
+
nameSets.ask.push(toolName);
|
|
268
|
+
if (entry.bare.allow !== undefined)
|
|
269
|
+
nameSets.allow.push(toolName);
|
|
270
|
+
}
|
|
262
271
|
return {
|
|
272
|
+
nameSets: [nameSets],
|
|
263
273
|
check(req) {
|
|
264
274
|
const entry = byTool.get(req.toolName);
|
|
265
275
|
if (entry) {
|
|
@@ -1378,6 +1378,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1378
1378
|
...(deps.backgroundAgentStore !== undefined ? { agentStore: deps.backgroundAgentStore } : {}),
|
|
1379
1379
|
...(deps.mailboxStore !== undefined ? { mailbox: deps.mailboxStore } : {}),
|
|
1380
1380
|
...(reviveSpawn !== undefined ? { reviveSpawn } : {}),
|
|
1381
|
+
onNotifyError: (f) => emitTrace(deps.tracer, () => ({ kind: "observer.notify_failed", version: 1, taskId: hostTaskId, site: f.site, message: f.error.message, ts: Date.now() })),
|
|
1381
1382
|
})));
|
|
1382
1383
|
if (!(spec.tools ?? []).some((t) => t.name === AGENT_TRANSCRIPT_TOOL_NAME)) {
|
|
1383
1384
|
tools.push(firstPartyOffload(createAgentTranscriptTool({
|
|
@@ -2190,8 +2191,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2190
2191
|
}
|
|
2191
2192
|
}
|
|
2192
2193
|
const policy = spec.toolPolicy ?? deps.toolPolicy;
|
|
2193
|
-
{
|
|
2194
|
-
const nameGroups = toolPolicyNameSets(
|
|
2194
|
+
const auditPolicyNames = (auditee) => {
|
|
2195
|
+
const nameGroups = toolPolicyNameSets(auditee);
|
|
2195
2196
|
if (nameGroups.length > 0) {
|
|
2196
2197
|
const known = new Set(tools.flatMap((t) => [t.name, ...(t.aliases ?? [])]));
|
|
2197
2198
|
for (const t of harnessTools)
|
|
@@ -2208,6 +2209,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2208
2209
|
err.code = "config.legacy_tool_name";
|
|
2209
2210
|
throw err;
|
|
2210
2211
|
}
|
|
2212
|
+
if (n.includes("__") && !n.startsWith("mcp__")) {
|
|
2213
|
+
const err = new Error(`tool policy ${kind}-list entry "${n}" is a pre-prefix MCP tool name and matches nothing in this run's roster — MCP tools are named "mcp__<server>__<tool>" and legacy-name normalization was removed (RB-476-A), so this entry would silently guard nothing. Prefix the entry with "mcp__".`);
|
|
2214
|
+
err.code = "config.legacy_tool_name";
|
|
2215
|
+
throw err;
|
|
2216
|
+
}
|
|
2211
2217
|
unmatched.add(`"${n}" (${kind})`);
|
|
2212
2218
|
}
|
|
2213
2219
|
}
|
|
@@ -2231,7 +2237,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2231
2237
|
}
|
|
2232
2238
|
}
|
|
2233
2239
|
}
|
|
2234
|
-
}
|
|
2240
|
+
};
|
|
2241
|
+
auditPolicyNames(policy);
|
|
2235
2242
|
let sessionRulePolicy;
|
|
2236
2243
|
if (deps.sessionPolicyStore && spec.sessionId) {
|
|
2237
2244
|
const rules = await deps.sessionPolicyStore.getRules(spec.sessionId, spec.principal);
|
|
@@ -2268,6 +2275,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2268
2275
|
})
|
|
2269
2276
|
: undefined;
|
|
2270
2277
|
const narrowingLayers = [sessionRulePolicy, ...ancestorRulePolicies, skillScopePolicy].filter((p) => p !== undefined);
|
|
2278
|
+
for (const layer of narrowingLayers)
|
|
2279
|
+
auditPolicyNames(layer);
|
|
2271
2280
|
const denyNarrowingPolicy = narrowingLayers.length === 0 ? undefined : narrowingLayers.length === 1 ? narrowingLayers[0] : combinePolicies(...narrowingLayers);
|
|
2272
2281
|
const basePolicyForResumeEdit = spec.toolPolicy ?? deps.toolPolicy;
|
|
2273
2282
|
const sameInstanceAncestorCount = policy === undefined ? 0 : (inheritedParentConstraints ?? []).reduce((n, pc) => (pc.policy === policy ? n + 1 : n), 0);
|
|
@@ -2878,6 +2887,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2878
2887
|
const token = mintCheckpointToken();
|
|
2879
2888
|
const gate = { kind: "resource_limit", reason };
|
|
2880
2889
|
const resourceLedgerOut = debitLedger(priorLedger, sliceSpend, resourceTotal);
|
|
2890
|
+
const mintedAt = Date.now();
|
|
2881
2891
|
const cp = {
|
|
2882
2892
|
token,
|
|
2883
2893
|
version: resourceLedgerOut.totalWalltimeSec !== undefined ? WALLTIME_CHECKPOINT_VERSION : RESOURCE_CHECKPOINT_VERSION,
|
|
@@ -2888,8 +2898,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2888
2898
|
pendingAction: { kind: "resource_limit", reason },
|
|
2889
2899
|
state: serializeCheckpointState(remoteHandle),
|
|
2890
2900
|
status: "pending",
|
|
2891
|
-
createdAt:
|
|
2892
|
-
deadline:
|
|
2901
|
+
createdAt: mintedAt,
|
|
2902
|
+
deadline: mintedAt + (sanitizedTtlMs(rs.ttlMs) ?? DEFAULT_RESOURCE_TTL_MS),
|
|
2893
2903
|
suspendCount: priorSuspendCount,
|
|
2894
2904
|
humanReview: humanReviewRef.count > 0
|
|
2895
2905
|
? { count: humanReviewRef.count, totalWaitMs: humanReviewRef.totalWaitMs, gates: [...humanReviewRef.gates] }
|
|
@@ -2958,6 +2968,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2958
2968
|
const scope = checkpointScopeOf(spec);
|
|
2959
2969
|
const gate = { kind: "plan_review", reason: reason ?? `plan review requested` };
|
|
2960
2970
|
const reviewLedger = debitLedger(priorLedger, liveSpendRef.get?.() ?? { costMicroUsd: 0, tokens: 0, turns: 0, walltimeMs: 0 }, resourceTotal, { countSlice: false });
|
|
2971
|
+
const mintedAt = Date.now();
|
|
2961
2972
|
const cp = {
|
|
2962
2973
|
token,
|
|
2963
2974
|
version: reviewLedger.totalWalltimeSec !== undefined ? WALLTIME_CHECKPOINT_VERSION : BINDING_CHECKPOINT_VERSION,
|
|
@@ -2968,9 +2979,9 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2968
2979
|
pendingAction: { kind: "plan_review" },
|
|
2969
2980
|
state: serializeCheckpointState(remoteHandle),
|
|
2970
2981
|
status: "pending",
|
|
2971
|
-
createdAt:
|
|
2982
|
+
createdAt: mintedAt,
|
|
2972
2983
|
suspendedAt: now(),
|
|
2973
|
-
deadline:
|
|
2984
|
+
deadline: mintedAt + (sanitizedTtlMs(spec.durableApproval?.ttlMs) ?? DEFAULT_RESOURCE_TTL_MS),
|
|
2974
2985
|
suspendCount: priorSuspendCount + 1,
|
|
2975
2986
|
humanReview: humanReviewRef.count > 0
|
|
2976
2987
|
? { count: humanReviewRef.count, totalWaitMs: humanReviewRef.totalWaitMs, gates: [...humanReviewRef.gates] }
|
|
@@ -3082,6 +3093,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3082
3093
|
const ttlMs = sanitizedTtlMs(durableApproval?.ttlMs);
|
|
3083
3094
|
const checkpointState = serializeCheckpointState(remoteHandle);
|
|
3084
3095
|
const approvalLedger = debitLedger(priorLedger, liveSpendRef.get?.() ?? { costMicroUsd: 0, tokens: 0, turns: 0, walltimeMs: 0 }, resourceTotal, { countSlice: false });
|
|
3096
|
+
const mintedAt = Date.now();
|
|
3085
3097
|
cp = {
|
|
3086
3098
|
token,
|
|
3087
3099
|
version: approvalLedger.totalWalltimeSec !== undefined ? WALLTIME_CHECKPOINT_VERSION : BINDING_CHECKPOINT_VERSION,
|
|
@@ -3104,12 +3116,12 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3104
3116
|
},
|
|
3105
3117
|
state: checkpointState,
|
|
3106
3118
|
deadline: ttlMs !== undefined
|
|
3107
|
-
?
|
|
3119
|
+
? mintedAt + ttlMs
|
|
3108
3120
|
: durableApproval !== undefined
|
|
3109
3121
|
? undefined
|
|
3110
|
-
:
|
|
3122
|
+
: mintedAt + DEFAULT_UNATTENDED_APPROVAL_TTL_MS,
|
|
3111
3123
|
status: "pending",
|
|
3112
|
-
createdAt:
|
|
3124
|
+
createdAt: mintedAt,
|
|
3113
3125
|
suspendedAt: now(),
|
|
3114
3126
|
humanReview: humanReviewRef.count > 0
|
|
3115
3127
|
? { count: humanReviewRef.count, totalWaitMs: humanReviewRef.totalWaitMs, gates: [...humanReviewRef.gates] }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ExecutionEnv } from "../../internal/harness-types.js";
|
|
2
2
|
import type { ToolEffect } from "../types.js";
|
|
3
|
-
import { type
|
|
3
|
+
import { type NamedToolPolicy } from "../tool-policy.js";
|
|
4
4
|
import type { SessionPermissionRules } from "../session-policy-store.js";
|
|
5
5
|
export declare const PATH_WRITE_TOOLS: ReadonlySet<string>;
|
|
6
6
|
export declare function isWithin(root: string, p: string): boolean;
|
|
@@ -8,4 +8,4 @@ export declare function createSessionRulePolicy(rules: SessionPermissionRules, o
|
|
|
8
8
|
env: ExecutionEnv;
|
|
9
9
|
rootPath?: string;
|
|
10
10
|
toolEffects?: ReadonlyMap<string, ToolEffect>;
|
|
11
|
-
}):
|
|
11
|
+
}): NamedToolPolicy;
|
|
@@ -32,6 +32,7 @@ export function createSessionRulePolicy(rules, opts) {
|
|
|
32
32
|
: undefined;
|
|
33
33
|
const allowDirs = rules.allowDirs && rules.allowDirs.length > 0 ? rules.allowDirs : undefined;
|
|
34
34
|
return {
|
|
35
|
+
nameSets: [{ ...(rules.toolDeny?.length ? { deny: [...rules.toolDeny] } : {}), ...(rules.toolAllow?.length ? { allow: [...rules.toolAllow] } : {}) }],
|
|
35
36
|
async check(req, signal) {
|
|
36
37
|
const toolName = req.toolName;
|
|
37
38
|
if (toolDeny.has(toolName))
|