@poolzin/pool-bot 2026.2.24 → 2026.2.25
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 +21 -0
- package/dist/acp/client.js +207 -18
- package/dist/acp/secret-file.js +22 -0
- package/dist/agents/agent-scope.js +10 -0
- package/dist/agents/bash-process-registry.test-helpers.js +29 -0
- package/dist/agents/bash-tools.exec-approval-request.js +20 -0
- package/dist/agents/bash-tools.exec-host-gateway.js +230 -0
- package/dist/agents/bash-tools.exec-host-node.js +235 -0
- package/dist/agents/bash-tools.exec-types.js +1 -0
- package/dist/agents/bash-tools.process.js +224 -218
- package/dist/agents/content-blocks.js +16 -0
- package/dist/agents/model-fallback.js +96 -101
- package/dist/agents/models-config.providers.js +299 -182
- package/dist/agents/pi-embedded-payloads.js +1 -0
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +34 -0
- package/dist/agents/skills.test-helpers.js +13 -0
- package/dist/agents/stable-stringify.js +12 -0
- package/dist/agents/subagent-registry.mocks.shared.js +12 -0
- package/dist/agents/test-helpers/assistant-message-fixtures.js +29 -0
- package/dist/agents/test-helpers/pi-tools-sandbox-context.js +27 -0
- package/dist/agents/tool-policy-shared.js +108 -0
- package/dist/agents/tools/browser-tool.js +160 -54
- package/dist/agents/tools/cron-tool.test-helpers.js +12 -0
- package/dist/agents/tools/discord-actions-moderation-shared.js +27 -0
- package/dist/agents/tools/image-tool.js +214 -99
- package/dist/agents/tools/sessions-history-tool.js +140 -108
- package/dist/agents/workspace.js +222 -46
- package/dist/auto-reply/commands-registry.js +15 -18
- package/dist/auto-reply/fallback-state.js +114 -0
- package/dist/auto-reply/model-runtime.js +68 -0
- package/dist/auto-reply/reply/agent-runner-execution.js +36 -4
- package/dist/auto-reply/reply/agent-runner.js +165 -39
- package/dist/auto-reply/reply/commands-setunset-standard.js +13 -0
- package/dist/browser/config.js +26 -0
- package/dist/browser/navigation-guard.js +31 -0
- package/dist/browser/routes/agent.act.js +431 -424
- package/dist/browser/routes/agent.shared.js +47 -3
- package/dist/browser/routes/agent.snapshot.js +122 -116
- package/dist/browser/routes/agent.storage.js +303 -297
- package/dist/browser/routes/tabs.js +154 -100
- package/dist/browser/server-lifecycle.js +37 -0
- package/dist/build-info.json +3 -3
- package/dist/channels/allow-from.js +25 -0
- package/dist/channels/plugins/account-action-gate.js +13 -0
- package/dist/channels/plugins/message-actions.js +10 -0
- package/dist/channels/telegram/api.js +18 -0
- package/dist/cli/argv.js +84 -21
- package/dist/cli/banner.js +2 -1
- package/dist/cli/exec-approvals-cli.js +92 -124
- package/dist/cli/memory-cli.js +158 -61
- package/dist/cli/nodes-cli/register.push.js +63 -0
- package/dist/cli/nodes-media-utils.js +21 -0
- package/dist/cli/plugins-cli.js +245 -61
- package/dist/cli/program/build-program.js +3 -1
- package/dist/cli/program/command-registry.js +223 -136
- package/dist/cli/program/help.js +43 -12
- package/dist/cli/route.js +1 -1
- package/dist/cli/test-runtime-capture.js +24 -0
- package/dist/commands/agent.js +163 -87
- package/dist/commands/channels.mock-harness.js +23 -0
- package/dist/commands/daemon-install-runtime-warning.js +11 -0
- package/dist/commands/sessions.test-helpers.js +61 -0
- package/dist/config/commands.js +3 -0
- package/dist/config/config.js +1 -1
- package/dist/config/env-substitution.js +62 -34
- package/dist/config/env-vars.js +9 -0
- package/dist/config/io.js +571 -171
- package/dist/config/merge-patch.js +50 -4
- package/dist/config/redact-snapshot.js +404 -76
- package/dist/config/schema.js +58 -570
- package/dist/config/validation.js +140 -85
- package/dist/config/zod-schema.hooks.js +40 -11
- package/dist/config/zod-schema.installs.js +20 -0
- package/dist/config/zod-schema.js +8 -7
- package/dist/daemon/cmd-argv.js +21 -0
- package/dist/daemon/cmd-set.js +58 -0
- package/dist/daemon/service-types.js +1 -0
- package/dist/discord/monitor/exec-approvals.js +357 -162
- package/dist/gateway/auth.js +38 -3
- package/dist/gateway/call.js +149 -68
- package/dist/gateway/canvas-capability.js +75 -0
- package/dist/gateway/control-plane-audit.js +28 -0
- package/dist/gateway/control-plane-rate-limit.js +53 -0
- package/dist/gateway/events.js +1 -0
- package/dist/gateway/hooks.js +109 -54
- package/dist/gateway/http-common.js +22 -0
- package/dist/gateway/method-scopes.js +169 -0
- package/dist/gateway/net.js +23 -0
- package/dist/gateway/openresponses-http.js +120 -110
- package/dist/gateway/probe-auth.js +2 -0
- package/dist/gateway/protocol/index.js +3 -2
- package/dist/gateway/protocol/schema/protocol-schemas.js +2 -0
- package/dist/gateway/protocol/schema/push.js +18 -0
- package/dist/gateway/protocol/schema.js +1 -0
- package/dist/gateway/server-http.js +236 -52
- package/dist/gateway/server-methods/agent.js +162 -24
- package/dist/gateway/server-methods/chat.js +461 -130
- package/dist/gateway/server-methods/config.js +193 -150
- package/dist/gateway/server-methods/nodes.helpers.js +12 -0
- package/dist/gateway/server-methods/nodes.js +251 -69
- package/dist/gateway/server-methods/push.js +53 -0
- package/dist/gateway/server-reload-handlers.js +2 -3
- package/dist/gateway/server-runtime-config.js +5 -0
- package/dist/gateway/server-runtime-state.js +2 -0
- package/dist/gateway/server-ws-runtime.js +1 -0
- package/dist/gateway/server.impl.js +296 -139
- package/dist/gateway/session-preview.test-helpers.js +11 -0
- package/dist/gateway/startup-auth.js +126 -0
- package/dist/gateway/test-helpers.agent-results.js +15 -0
- package/dist/gateway/test-helpers.mocks.js +37 -14
- package/dist/gateway/test-helpers.server.js +161 -77
- package/dist/hooks/bundled/session-memory/handler.js +165 -34
- package/dist/hooks/gmail-watcher-lifecycle.js +23 -0
- package/dist/infra/archive-path.js +49 -0
- package/dist/infra/device-pairing.js +148 -167
- package/dist/infra/exec-approvals-allowlist.js +19 -70
- package/dist/infra/exec-approvals-analysis.js +44 -17
- package/dist/infra/exec-safe-bin-policy.js +269 -0
- package/dist/infra/fixed-window-rate-limit.js +33 -0
- package/dist/infra/git-root.js +61 -0
- package/dist/infra/heartbeat-active-hours.js +2 -2
- package/dist/infra/heartbeat-reason.js +40 -0
- package/dist/infra/heartbeat-runner.js +72 -32
- package/dist/infra/install-source-utils.js +91 -7
- package/dist/infra/node-pairing.js +50 -105
- package/dist/infra/npm-integrity.js +45 -0
- package/dist/infra/npm-pack-install.js +40 -0
- package/dist/infra/outbound/channel-adapters.js +20 -7
- package/dist/infra/outbound/message-action-runner.js +107 -327
- package/dist/infra/outbound/message.js +59 -36
- package/dist/infra/outbound/outbound-policy.js +52 -25
- package/dist/infra/outbound/outbound-send-service.js +58 -71
- package/dist/infra/pairing-files.js +10 -0
- package/dist/infra/plain-object.js +9 -0
- package/dist/infra/push-apns.js +365 -0
- package/dist/infra/restart-sentinel.js +16 -1
- package/dist/infra/restart.js +229 -26
- package/dist/infra/scp-host.js +54 -0
- package/dist/infra/update-startup.js +86 -9
- package/dist/media/inbound-path-policy.js +114 -0
- package/dist/media/input-files.js +16 -0
- package/dist/memory/test-manager.js +8 -0
- package/dist/plugin-sdk/temp-path.js +47 -0
- package/dist/plugins/discovery.js +217 -23
- package/dist/plugins/hook-runner-global.js +16 -0
- package/dist/plugins/loader.js +192 -26
- package/dist/plugins/logger.js +8 -0
- package/dist/plugins/manifest-registry.js +3 -0
- package/dist/plugins/path-safety.js +34 -0
- package/dist/plugins/registry.js +5 -2
- package/dist/plugins/runtime/index.js +271 -206
- package/dist/providers/github-copilot-models.js +4 -1
- package/dist/security/audit-channel.js +8 -19
- package/dist/security/audit-extra.async.js +354 -182
- package/dist/security/audit-extra.js +11 -1
- package/dist/security/audit-extra.sync.js +340 -33
- package/dist/security/audit-fs.js +31 -13
- package/dist/security/audit.js +145 -371
- package/dist/security/dm-policy-shared.js +24 -0
- package/dist/security/external-content.js +20 -8
- package/dist/security/fix.js +49 -85
- package/dist/security/scan-paths.js +20 -0
- package/dist/security/secret-equal.js +3 -7
- package/dist/security/windows-acl.js +30 -15
- package/dist/shared/node-list-parse.js +13 -0
- package/dist/shared/operator-scope-compat.js +37 -0
- package/dist/shared/text-chunking.js +29 -0
- package/dist/slack/blocks.test-helpers.js +31 -0
- package/dist/slack/monitor/mrkdwn.js +8 -0
- package/dist/telegram/bot-message-dispatch.js +366 -164
- package/dist/telegram/draft-stream.js +30 -7
- package/dist/telegram/reasoning-lane-coordinator.js +128 -0
- package/dist/terminal/prompt-select-styled.js +9 -0
- package/dist/test-utils/command-runner.js +6 -0
- package/dist/test-utils/internal-hook-event-payload.js +10 -0
- package/dist/test-utils/model-auth-mock.js +12 -0
- package/dist/test-utils/provider-usage-fetch.js +14 -0
- package/dist/test-utils/temp-home.js +33 -0
- package/dist/tui/components/chat-log.js +9 -0
- package/dist/tui/tui-command-handlers.js +36 -27
- package/dist/tui/tui-event-handlers.js +122 -32
- package/dist/tui/tui.js +181 -45
- package/dist/utils/mask-api-key.js +10 -0
- package/dist/utils/run-with-concurrency.js +39 -0
- package/dist/web/media.js +4 -0
- package/docs/tools/slash-commands.md +5 -1
- package/extensions/feishu/src/external-keys.ts +19 -0
- package/extensions/lobster/src/windows-spawn.ts +193 -0
- package/extensions/matrix/src/matrix/actions/limits.ts +6 -0
- package/extensions/mattermost/src/mattermost/reactions.test-helpers.ts +83 -0
- package/package.json +1 -1
|
@@ -1,26 +1,14 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import JSON5 from "json5";
|
|
3
3
|
import { readExecApprovalsSnapshot, saveExecApprovals, } from "../infra/exec-approvals.js";
|
|
4
|
+
import { formatTimeAgo } from "../infra/format-time/format-relative.js";
|
|
4
5
|
import { defaultRuntime } from "../runtime.js";
|
|
5
6
|
import { formatDocsLink } from "../terminal/links.js";
|
|
6
|
-
import { isRich, theme } from "../terminal/theme.js";
|
|
7
7
|
import { renderTable } from "../terminal/table.js";
|
|
8
|
-
import {
|
|
8
|
+
import { isRich, theme } from "../terminal/theme.js";
|
|
9
9
|
import { describeUnknownError } from "./gateway-cli/shared.js";
|
|
10
|
+
import { callGatewayFromCli } from "./gateway-rpc.js";
|
|
10
11
|
import { nodesCallOpts, resolveNodeId } from "./nodes-cli/rpc.js";
|
|
11
|
-
function formatAge(msAgo) {
|
|
12
|
-
const s = Math.max(0, Math.floor(msAgo / 1000));
|
|
13
|
-
if (s < 60)
|
|
14
|
-
return `${s}s`;
|
|
15
|
-
const m = Math.floor(s / 60);
|
|
16
|
-
if (m < 60)
|
|
17
|
-
return `${m}m`;
|
|
18
|
-
const h = Math.floor(m / 60);
|
|
19
|
-
if (h < 24)
|
|
20
|
-
return `${h}h`;
|
|
21
|
-
const d = Math.floor(h / 24);
|
|
22
|
-
return `${d}d`;
|
|
23
|
-
}
|
|
24
12
|
async function readStdin() {
|
|
25
13
|
const chunks = [];
|
|
26
14
|
for await (const chunk of process.stdin) {
|
|
@@ -29,11 +17,13 @@ async function readStdin() {
|
|
|
29
17
|
return Buffer.concat(chunks).toString("utf8");
|
|
30
18
|
}
|
|
31
19
|
async function resolveTargetNodeId(opts) {
|
|
32
|
-
if (opts.gateway)
|
|
20
|
+
if (opts.gateway) {
|
|
33
21
|
return null;
|
|
22
|
+
}
|
|
34
23
|
const raw = opts.node?.trim() ?? "";
|
|
35
|
-
if (!raw)
|
|
24
|
+
if (!raw) {
|
|
36
25
|
return null;
|
|
26
|
+
}
|
|
37
27
|
return await resolveNodeId(opts, raw);
|
|
38
28
|
}
|
|
39
29
|
async function loadSnapshot(opts, nodeId) {
|
|
@@ -63,6 +53,41 @@ async function loadSnapshotTarget(opts) {
|
|
|
63
53
|
const snapshot = await loadSnapshot(opts, nodeId);
|
|
64
54
|
return { snapshot, nodeId, source: nodeId ? "node" : "gateway" };
|
|
65
55
|
}
|
|
56
|
+
function exitWithError(message) {
|
|
57
|
+
defaultRuntime.error(message);
|
|
58
|
+
defaultRuntime.exit(1);
|
|
59
|
+
throw new Error(message);
|
|
60
|
+
}
|
|
61
|
+
function requireTrimmedNonEmpty(value, message) {
|
|
62
|
+
const trimmed = value.trim();
|
|
63
|
+
if (!trimmed) {
|
|
64
|
+
exitWithError(message);
|
|
65
|
+
}
|
|
66
|
+
return trimmed;
|
|
67
|
+
}
|
|
68
|
+
async function loadWritableSnapshotTarget(opts) {
|
|
69
|
+
const { snapshot, nodeId, source } = await loadSnapshotTarget(opts);
|
|
70
|
+
if (source === "local") {
|
|
71
|
+
defaultRuntime.log(theme.muted("Writing local approvals."));
|
|
72
|
+
}
|
|
73
|
+
const targetLabel = source === "local" ? "local" : nodeId ? `node:${nodeId}` : "gateway";
|
|
74
|
+
const baseHash = snapshot.hash;
|
|
75
|
+
if (!baseHash) {
|
|
76
|
+
exitWithError("Exec approvals hash missing; reload and retry.");
|
|
77
|
+
}
|
|
78
|
+
return { snapshot, nodeId, source, targetLabel, baseHash };
|
|
79
|
+
}
|
|
80
|
+
async function saveSnapshotTargeted(params) {
|
|
81
|
+
const next = params.source === "local"
|
|
82
|
+
? saveSnapshotLocal(params.file)
|
|
83
|
+
: await saveSnapshot(params.opts, params.nodeId, params.file, params.baseHash);
|
|
84
|
+
if (params.opts.json) {
|
|
85
|
+
defaultRuntime.log(JSON.stringify(next));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
defaultRuntime.log(theme.muted(`Target: ${params.targetLabel}`));
|
|
89
|
+
renderApprovalsSnapshot(next, params.targetLabel);
|
|
90
|
+
}
|
|
66
91
|
function formatCliError(err) {
|
|
67
92
|
const msg = describeUnknownError(err);
|
|
68
93
|
return msg.includes("\n") ? msg.split("\n")[0] : msg;
|
|
@@ -89,14 +114,15 @@ function renderApprovalsSnapshot(snapshot, targetLabel) {
|
|
|
89
114
|
const allowlist = Array.isArray(agent.allowlist) ? agent.allowlist : [];
|
|
90
115
|
for (const entry of allowlist) {
|
|
91
116
|
const pattern = entry?.pattern?.trim() ?? "";
|
|
92
|
-
if (!pattern)
|
|
117
|
+
if (!pattern) {
|
|
93
118
|
continue;
|
|
119
|
+
}
|
|
94
120
|
const lastUsedAt = typeof entry.lastUsedAt === "number" ? entry.lastUsedAt : null;
|
|
95
121
|
allowlistRows.push({
|
|
96
122
|
Target: targetLabel,
|
|
97
123
|
Agent: agentId,
|
|
98
124
|
Pattern: pattern,
|
|
99
|
-
LastUsed: lastUsedAt ?
|
|
125
|
+
LastUsed: lastUsedAt ? formatTimeAgo(Math.max(0, now - lastUsedAt)) : muted("unknown"),
|
|
100
126
|
});
|
|
101
127
|
}
|
|
102
128
|
}
|
|
@@ -166,6 +192,37 @@ function isEmptyAgent(agent) {
|
|
|
166
192
|
agent.autoAllowSkills === undefined &&
|
|
167
193
|
allowlist.length === 0);
|
|
168
194
|
}
|
|
195
|
+
async function loadWritableAllowlistAgent(opts) {
|
|
196
|
+
const { snapshot, nodeId, source, targetLabel, baseHash } = await loadWritableSnapshotTarget(opts);
|
|
197
|
+
const file = snapshot.file ?? { version: 1 };
|
|
198
|
+
file.version = 1;
|
|
199
|
+
const agentKey = resolveAgentKey(opts.agent);
|
|
200
|
+
const agent = ensureAgent(file, agentKey);
|
|
201
|
+
const allowlistEntries = Array.isArray(agent.allowlist) ? agent.allowlist : [];
|
|
202
|
+
return { nodeId, source, targetLabel, baseHash, file, agentKey, agent, allowlistEntries };
|
|
203
|
+
}
|
|
204
|
+
async function runAllowlistMutation(pattern, opts, mutate) {
|
|
205
|
+
try {
|
|
206
|
+
const trimmedPattern = requireTrimmedNonEmpty(pattern, "Pattern required.");
|
|
207
|
+
const context = await loadWritableAllowlistAgent(opts);
|
|
208
|
+
const shouldSave = await mutate({ ...context, trimmedPattern });
|
|
209
|
+
if (!shouldSave) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
await saveSnapshotTargeted({
|
|
213
|
+
opts,
|
|
214
|
+
source: context.source,
|
|
215
|
+
nodeId: context.nodeId,
|
|
216
|
+
file: context.file,
|
|
217
|
+
baseHash: context.baseHash,
|
|
218
|
+
targetLabel: context.targetLabel,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
defaultRuntime.error(formatCliError(err));
|
|
223
|
+
defaultRuntime.exit(1);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
169
226
|
export function registerExecApprovalsCli(program) {
|
|
170
227
|
const formatExample = (cmd, desc) => ` ${theme.command(cmd)}\n ${theme.muted(desc)}`;
|
|
171
228
|
const approvals = program
|
|
@@ -209,45 +266,22 @@ export function registerExecApprovalsCli(program) {
|
|
|
209
266
|
.action(async (opts) => {
|
|
210
267
|
try {
|
|
211
268
|
if (!opts.file && !opts.stdin) {
|
|
212
|
-
|
|
213
|
-
defaultRuntime.exit(1);
|
|
214
|
-
return;
|
|
269
|
+
exitWithError("Provide --file or --stdin.");
|
|
215
270
|
}
|
|
216
271
|
if (opts.file && opts.stdin) {
|
|
217
|
-
|
|
218
|
-
defaultRuntime.exit(1);
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
const { snapshot, nodeId, source } = await loadSnapshotTarget(opts);
|
|
222
|
-
if (source === "local") {
|
|
223
|
-
defaultRuntime.log(theme.muted("Writing local approvals."));
|
|
224
|
-
}
|
|
225
|
-
const targetLabel = source === "local" ? "local" : nodeId ? `node:${nodeId}` : "gateway";
|
|
226
|
-
if (!snapshot.hash) {
|
|
227
|
-
defaultRuntime.error("Exec approvals hash missing; reload and retry.");
|
|
228
|
-
defaultRuntime.exit(1);
|
|
229
|
-
return;
|
|
272
|
+
exitWithError("Use either --file or --stdin (not both).");
|
|
230
273
|
}
|
|
274
|
+
const { source, nodeId, targetLabel, baseHash } = await loadWritableSnapshotTarget(opts);
|
|
231
275
|
const raw = opts.stdin ? await readStdin() : await fs.readFile(String(opts.file), "utf8");
|
|
232
276
|
let file;
|
|
233
277
|
try {
|
|
234
278
|
file = JSON5.parse(raw);
|
|
235
279
|
}
|
|
236
280
|
catch (err) {
|
|
237
|
-
|
|
238
|
-
defaultRuntime.exit(1);
|
|
239
|
-
return;
|
|
281
|
+
exitWithError(`Failed to parse approvals JSON: ${String(err)}`);
|
|
240
282
|
}
|
|
241
283
|
file.version = 1;
|
|
242
|
-
|
|
243
|
-
? saveSnapshotLocal(file)
|
|
244
|
-
: await saveSnapshot(opts, nodeId, file, snapshot.hash);
|
|
245
|
-
if (opts.json) {
|
|
246
|
-
defaultRuntime.log(JSON.stringify(next));
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
defaultRuntime.log(theme.muted(`Target: ${targetLabel}`));
|
|
250
|
-
renderApprovalsSnapshot(next, targetLabel);
|
|
284
|
+
await saveSnapshotTargeted({ opts, source, nodeId, file, baseHash, targetLabel });
|
|
251
285
|
}
|
|
252
286
|
catch (err) {
|
|
253
287
|
defaultRuntime.error(formatCliError(err));
|
|
@@ -266,49 +300,16 @@ export function registerExecApprovalsCli(program) {
|
|
|
266
300
|
.option("--gateway", "Force gateway approvals", false)
|
|
267
301
|
.option("--agent <id>", 'Agent id (defaults to "*")')
|
|
268
302
|
.action(async (pattern, opts) => {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (!trimmed) {
|
|
272
|
-
defaultRuntime.error("Pattern required.");
|
|
273
|
-
defaultRuntime.exit(1);
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
const { snapshot, nodeId, source } = await loadSnapshotTarget(opts);
|
|
277
|
-
if (source === "local") {
|
|
278
|
-
defaultRuntime.log(theme.muted("Writing local approvals."));
|
|
279
|
-
}
|
|
280
|
-
const targetLabel = source === "local" ? "local" : nodeId ? `node:${nodeId}` : "gateway";
|
|
281
|
-
if (!snapshot.hash) {
|
|
282
|
-
defaultRuntime.error("Exec approvals hash missing; reload and retry.");
|
|
283
|
-
defaultRuntime.exit(1);
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
const file = snapshot.file ?? { version: 1 };
|
|
287
|
-
file.version = 1;
|
|
288
|
-
const agentKey = resolveAgentKey(opts.agent);
|
|
289
|
-
const agent = ensureAgent(file, agentKey);
|
|
290
|
-
const allowlistEntries = Array.isArray(agent.allowlist) ? agent.allowlist : [];
|
|
291
|
-
if (allowlistEntries.some((entry) => normalizeAllowlistEntry(entry) === trimmed)) {
|
|
303
|
+
await runAllowlistMutation(pattern, opts, ({ trimmedPattern, file, agent, agentKey, allowlistEntries }) => {
|
|
304
|
+
if (allowlistEntries.some((entry) => normalizeAllowlistEntry(entry) === trimmedPattern)) {
|
|
292
305
|
defaultRuntime.log("Already allowlisted.");
|
|
293
|
-
return;
|
|
306
|
+
return false;
|
|
294
307
|
}
|
|
295
|
-
allowlistEntries.push({ pattern:
|
|
308
|
+
allowlistEntries.push({ pattern: trimmedPattern, lastUsedAt: Date.now() });
|
|
296
309
|
agent.allowlist = allowlistEntries;
|
|
297
310
|
file.agents = { ...file.agents, [agentKey]: agent };
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
: await saveSnapshot(opts, nodeId, file, snapshot.hash);
|
|
301
|
-
if (opts.json) {
|
|
302
|
-
defaultRuntime.log(JSON.stringify(next));
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
defaultRuntime.log(theme.muted(`Target: ${targetLabel}`));
|
|
306
|
-
renderApprovalsSnapshot(next, targetLabel);
|
|
307
|
-
}
|
|
308
|
-
catch (err) {
|
|
309
|
-
defaultRuntime.error(formatCliError(err));
|
|
310
|
-
defaultRuntime.exit(1);
|
|
311
|
-
}
|
|
311
|
+
return true;
|
|
312
|
+
});
|
|
312
313
|
});
|
|
313
314
|
nodesCallOpts(allowlistAdd);
|
|
314
315
|
const allowlistRemove = allowlist
|
|
@@ -318,32 +319,11 @@ export function registerExecApprovalsCli(program) {
|
|
|
318
319
|
.option("--gateway", "Force gateway approvals", false)
|
|
319
320
|
.option("--agent <id>", 'Agent id (defaults to "*")')
|
|
320
321
|
.action(async (pattern, opts) => {
|
|
321
|
-
|
|
322
|
-
const
|
|
323
|
-
if (!trimmed) {
|
|
324
|
-
defaultRuntime.error("Pattern required.");
|
|
325
|
-
defaultRuntime.exit(1);
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
const { snapshot, nodeId, source } = await loadSnapshotTarget(opts);
|
|
329
|
-
if (source === "local") {
|
|
330
|
-
defaultRuntime.log(theme.muted("Writing local approvals."));
|
|
331
|
-
}
|
|
332
|
-
const targetLabel = source === "local" ? "local" : nodeId ? `node:${nodeId}` : "gateway";
|
|
333
|
-
if (!snapshot.hash) {
|
|
334
|
-
defaultRuntime.error("Exec approvals hash missing; reload and retry.");
|
|
335
|
-
defaultRuntime.exit(1);
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
const file = snapshot.file ?? { version: 1 };
|
|
339
|
-
file.version = 1;
|
|
340
|
-
const agentKey = resolveAgentKey(opts.agent);
|
|
341
|
-
const agent = ensureAgent(file, agentKey);
|
|
342
|
-
const allowlistEntries = Array.isArray(agent.allowlist) ? agent.allowlist : [];
|
|
343
|
-
const nextEntries = allowlistEntries.filter((entry) => normalizeAllowlistEntry(entry) !== trimmed);
|
|
322
|
+
await runAllowlistMutation(pattern, opts, ({ trimmedPattern, file, agent, agentKey, allowlistEntries }) => {
|
|
323
|
+
const nextEntries = allowlistEntries.filter((entry) => normalizeAllowlistEntry(entry) !== trimmedPattern);
|
|
344
324
|
if (nextEntries.length === allowlistEntries.length) {
|
|
345
325
|
defaultRuntime.log("Pattern not found.");
|
|
346
|
-
return;
|
|
326
|
+
return false;
|
|
347
327
|
}
|
|
348
328
|
if (nextEntries.length === 0) {
|
|
349
329
|
delete agent.allowlist;
|
|
@@ -359,20 +339,8 @@ export function registerExecApprovalsCli(program) {
|
|
|
359
339
|
else {
|
|
360
340
|
file.agents = { ...file.agents, [agentKey]: agent };
|
|
361
341
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
: await saveSnapshot(opts, nodeId, file, snapshot.hash);
|
|
365
|
-
if (opts.json) {
|
|
366
|
-
defaultRuntime.log(JSON.stringify(next));
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
defaultRuntime.log(theme.muted(`Target: ${targetLabel}`));
|
|
370
|
-
renderApprovalsSnapshot(next, targetLabel);
|
|
371
|
-
}
|
|
372
|
-
catch (err) {
|
|
373
|
-
defaultRuntime.error(formatCliError(err));
|
|
374
|
-
defaultRuntime.exit(1);
|
|
375
|
-
}
|
|
342
|
+
return true;
|
|
343
|
+
});
|
|
376
344
|
});
|
|
377
345
|
nodesCallOpts(allowlistRemove);
|
|
378
346
|
}
|