jinzd-ai-cli 0.4.217 → 0.4.219
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/README.md +5 -2
- package/dist/{batch-YCOVKTXD.js → batch-CHAPYRVM.js} +2 -2
- package/dist/chunk-3I4RZYYO.js +638 -0
- package/dist/{chunk-KOPUCJXM.js → chunk-4ZN6L6K5.js} +3 -3
- package/dist/{chunk-VTH7BLXK.js → chunk-64NUW3WL.js} +1 -1
- package/dist/{chunk-QAYOI57M.js → chunk-EGMORH5W.js} +1 -1
- package/dist/{chunk-MGBMNCHG.js → chunk-GEN4O5QH.js} +94 -270
- package/dist/chunk-GGKQHPB3.js +604 -0
- package/dist/{chunk-WKOQ5CYC.js → chunk-KIEZBTVD.js} +1 -1
- package/dist/{chunk-OUAZOE5U.js → chunk-QUFYBR6Q.js} +47 -206
- package/dist/{chunk-XJGEQIYS.js → chunk-U7KVU25H.js} +1 -1
- package/dist/{chunk-WZ3VKLF3.js → chunk-VADHBW7T.js} +1 -1
- package/dist/{ci-52RZIYWB.js → ci-QPP66T53.js} +4 -4
- package/dist/{ci-format-73UXKE65.js → ci-format-5S3EEYRK.js} +2 -2
- package/dist/{constants-DIXAD35W.js → constants-FJOLBABC.js} +1 -1
- package/dist/doctor-cli-KB2LUDF3.js +17 -0
- package/dist/electron-server.js +921 -274
- package/dist/{hub-GIGBITZN.js → hub-DIM7SKKY.js} +1 -1
- package/dist/index.js +192 -200
- package/dist/{pr-KPQ5RPKB.js → pr-YQGH72N6.js} +4 -4
- package/dist/{run-tests-ZDSA3QES.js → run-tests-GEZSSNJM.js} +2 -2
- package/dist/{run-tests-K7QR5QN4.js → run-tests-O76JIBCW.js} +1 -1
- package/dist/{server-QT3SC2KI.js → server-5E2AIXVX.js} +108 -80
- package/dist/{server-22YF3U34.js → server-Z6O3G2LY.js} +9 -9
- package/dist/{task-orchestrator-BHQQCVTY.js → task-orchestrator-5HBW4O64.js} +9 -9
- package/dist/{usage-WZZFSFLM.js → usage-BMK6M5U3.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-524WZOKS.js +0 -166
- package/dist/chunk-SNJAOXFT.js +0 -129
- package/dist/doctor-cli-7GOQPULZ.js +0 -226
|
@@ -1,14 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
indexProject
|
|
4
|
+
} from "./chunk-K3CF65QH.js";
|
|
2
5
|
import {
|
|
3
6
|
hasSemanticIndex,
|
|
4
7
|
semanticSearch
|
|
5
8
|
} from "./chunk-T2NL5ZIA.js";
|
|
6
9
|
import {
|
|
7
10
|
runTestsTool
|
|
8
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-64NUW3WL.js";
|
|
12
|
+
import {
|
|
13
|
+
fileCheckpoints
|
|
14
|
+
} from "./chunk-4BKXL7SM.js";
|
|
9
15
|
import {
|
|
16
|
+
loadChatIndex,
|
|
17
|
+
searchChatMemory
|
|
18
|
+
} from "./chunk-TB4W4Y4T.js";
|
|
19
|
+
import {
|
|
20
|
+
DEFAULT_PATTERNS,
|
|
21
|
+
redactString
|
|
22
|
+
} from "./chunk-SLSWPBK3.js";
|
|
23
|
+
import {
|
|
24
|
+
getActivePluginAssets,
|
|
25
|
+
runHook,
|
|
26
|
+
runLifecycleHooks,
|
|
10
27
|
runTool
|
|
11
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-GGKQHPB3.js";
|
|
12
29
|
import {
|
|
13
30
|
getDangerLevel,
|
|
14
31
|
isFileWriteTool,
|
|
@@ -28,24 +45,10 @@ import {
|
|
|
28
45
|
SUBAGENT_ALLOWED_TOOLS,
|
|
29
46
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
30
47
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
31
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-U7KVU25H.js";
|
|
32
49
|
import {
|
|
33
50
|
getGitRoot
|
|
34
51
|
} from "./chunk-HOSJZMQS.js";
|
|
35
|
-
import {
|
|
36
|
-
fileCheckpoints
|
|
37
|
-
} from "./chunk-4BKXL7SM.js";
|
|
38
|
-
import {
|
|
39
|
-
loadChatIndex,
|
|
40
|
-
searchChatMemory
|
|
41
|
-
} from "./chunk-TB4W4Y4T.js";
|
|
42
|
-
import {
|
|
43
|
-
DEFAULT_PATTERNS,
|
|
44
|
-
redactString
|
|
45
|
-
} from "./chunk-SLSWPBK3.js";
|
|
46
|
-
import {
|
|
47
|
-
indexProject
|
|
48
|
-
} from "./chunk-K3CF65QH.js";
|
|
49
52
|
import {
|
|
50
53
|
loadIndex
|
|
51
54
|
} from "./chunk-CKH4KQ4E.js";
|
|
@@ -1059,12 +1062,12 @@ ${content}`;
|
|
|
1059
1062
|
};
|
|
1060
1063
|
|
|
1061
1064
|
// src/tools/builtin/write-file.ts
|
|
1062
|
-
import { appendFileSync, mkdirSync
|
|
1065
|
+
import { appendFileSync, mkdirSync } from "fs";
|
|
1063
1066
|
import { dirname as dirname2 } from "path";
|
|
1064
1067
|
|
|
1065
1068
|
// src/tools/executor.ts
|
|
1066
1069
|
import chalk3 from "chalk";
|
|
1067
|
-
import { existsSync as
|
|
1070
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
1068
1071
|
import { tmpdir } from "os";
|
|
1069
1072
|
|
|
1070
1073
|
// src/core/readline-internal.ts
|
|
@@ -1270,184 +1273,6 @@ function simpleDiff(oldLines, newLines) {
|
|
|
1270
1273
|
return result;
|
|
1271
1274
|
}
|
|
1272
1275
|
|
|
1273
|
-
// src/tools/hooks.ts
|
|
1274
|
-
import { execSync } from "child_process";
|
|
1275
|
-
import { createHash } from "crypto";
|
|
1276
|
-
import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync3 } from "fs";
|
|
1277
|
-
import { join } from "path";
|
|
1278
|
-
var TRUST_FILE = "hooks-trust.json";
|
|
1279
|
-
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
1280
|
-
function asArray(entry) {
|
|
1281
|
-
if (!entry) return [];
|
|
1282
|
-
const raw = Array.isArray(entry) ? entry : [entry];
|
|
1283
|
-
return raw.map((item) => typeof item === "string" ? { command: item } : item);
|
|
1284
|
-
}
|
|
1285
|
-
function hookTrustPath(configDir) {
|
|
1286
|
-
return join(configDir, TRUST_FILE);
|
|
1287
|
-
}
|
|
1288
|
-
function loadHookTrustStore(configDir) {
|
|
1289
|
-
const file = hookTrustPath(configDir);
|
|
1290
|
-
if (!existsSync4(file)) return { records: [] };
|
|
1291
|
-
try {
|
|
1292
|
-
const parsed = JSON.parse(readFileSync3(file, "utf-8"));
|
|
1293
|
-
return { records: Array.isArray(parsed.records) ? parsed.records : [] };
|
|
1294
|
-
} catch {
|
|
1295
|
-
return { records: [] };
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1298
|
-
function saveHookTrustStore(configDir, store) {
|
|
1299
|
-
mkdirSync(configDir, { recursive: true });
|
|
1300
|
-
atomicWriteFileSync(hookTrustPath(configDir), JSON.stringify(store, null, 2));
|
|
1301
|
-
}
|
|
1302
|
-
function hashHook(event, command) {
|
|
1303
|
-
return createHash("sha256").update(`${event}
|
|
1304
|
-
${command}`, "utf-8").digest("hex");
|
|
1305
|
-
}
|
|
1306
|
-
function isTrusted(source, event, hash, store) {
|
|
1307
|
-
if (source === "user" || source === "managed") return true;
|
|
1308
|
-
return store.records.some((r) => r.source === source && r.event === event && r.hash === hash);
|
|
1309
|
-
}
|
|
1310
|
-
function listHooks(config, configDir) {
|
|
1311
|
-
if (!config || config.enabled === false) return [];
|
|
1312
|
-
const store = loadHookTrustStore(configDir);
|
|
1313
|
-
const out = [];
|
|
1314
|
-
const push = (event, hook, index) => {
|
|
1315
|
-
if (!hook.command) return;
|
|
1316
|
-
const source = hook.source ?? "user";
|
|
1317
|
-
const hash = hashHook(event, hook.command);
|
|
1318
|
-
out.push({
|
|
1319
|
-
id: `${event}:${index}`,
|
|
1320
|
-
event,
|
|
1321
|
-
command: hook.command,
|
|
1322
|
-
source,
|
|
1323
|
-
hash,
|
|
1324
|
-
trusted: isTrusted(source, event, hash, store),
|
|
1325
|
-
disabled: hook.disabled === true,
|
|
1326
|
-
description: hook.description
|
|
1327
|
-
});
|
|
1328
|
-
};
|
|
1329
|
-
if (config.preToolExecution) push("PreToolUse", { command: config.preToolExecution }, 0);
|
|
1330
|
-
if (config.postToolExecution) push("PostToolUse", { command: config.postToolExecution }, 0);
|
|
1331
|
-
for (const [event, entry] of Object.entries(config.events ?? {})) {
|
|
1332
|
-
asArray(entry).forEach((hook, i) => push(event, hook, i));
|
|
1333
|
-
}
|
|
1334
|
-
return out;
|
|
1335
|
-
}
|
|
1336
|
-
function trustHook(configDir, hook) {
|
|
1337
|
-
const store = loadHookTrustStore(configDir);
|
|
1338
|
-
const next = store.records.filter((r) => !(r.source === hook.source && r.event === hook.event && r.id === hook.id));
|
|
1339
|
-
next.push({ id: hook.id, event: hook.event, source: hook.source, hash: hook.hash, trustedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1340
|
-
saveHookTrustStore(configDir, { records: next });
|
|
1341
|
-
}
|
|
1342
|
-
function untrustHook(configDir, hook) {
|
|
1343
|
-
const store = loadHookTrustStore(configDir);
|
|
1344
|
-
saveHookTrustStore(configDir, {
|
|
1345
|
-
records: store.records.filter((r) => !(r.source === hook.source && r.event === hook.event && r.hash === hook.hash))
|
|
1346
|
-
});
|
|
1347
|
-
}
|
|
1348
|
-
function getPendingHookTrust(config, configDir) {
|
|
1349
|
-
return listHooks(config, configDir).filter((h) => h.source === "project" && !h.disabled && !h.trusted);
|
|
1350
|
-
}
|
|
1351
|
-
function normalizeDecision(value, hook) {
|
|
1352
|
-
if (!value || typeof value !== "object") return null;
|
|
1353
|
-
const obj = value;
|
|
1354
|
-
const action = obj.action;
|
|
1355
|
-
if (action !== "allow" && action !== "deny" && action !== "ask") return null;
|
|
1356
|
-
return {
|
|
1357
|
-
action,
|
|
1358
|
-
reason: typeof obj.reason === "string" ? obj.reason : void 0,
|
|
1359
|
-
prompt: typeof obj.prompt === "string" ? obj.prompt : void 0,
|
|
1360
|
-
contextAppend: typeof obj.contextAppend === "string" ? obj.contextAppend : void 0,
|
|
1361
|
-
warning: typeof obj.warning === "string" ? obj.warning : void 0,
|
|
1362
|
-
warnings: Array.isArray(obj.warnings) ? obj.warnings.filter((x) => typeof x === "string") : void 0,
|
|
1363
|
-
hook
|
|
1364
|
-
};
|
|
1365
|
-
}
|
|
1366
|
-
function runStructuredHook(hook, descriptor, payload) {
|
|
1367
|
-
if (hook.disabled === true) return null;
|
|
1368
|
-
const timeout = Math.max(100, Math.min(hook.timeoutMs ?? DEFAULT_TIMEOUT_MS, 3e4));
|
|
1369
|
-
try {
|
|
1370
|
-
const stdout = execSync(hook.command, {
|
|
1371
|
-
timeout,
|
|
1372
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
1373
|
-
encoding: "utf-8",
|
|
1374
|
-
env: {
|
|
1375
|
-
...process.env,
|
|
1376
|
-
AICLI_HOOK_EVENT: payload.event,
|
|
1377
|
-
AICLI_HOOK_EVENT_JSON: JSON.stringify(payload)
|
|
1378
|
-
}
|
|
1379
|
-
}).trim();
|
|
1380
|
-
if (!stdout) return null;
|
|
1381
|
-
return normalizeDecision(JSON.parse(stdout), descriptor);
|
|
1382
|
-
} catch (err) {
|
|
1383
|
-
process.stderr.write(`\u26A0 Hook failed: ${hook.command.slice(0, 100)}
|
|
1384
|
-
`);
|
|
1385
|
-
if (hook.required) {
|
|
1386
|
-
return { action: "deny", reason: err instanceof Error ? err.message : String(err), hook: descriptor };
|
|
1387
|
-
}
|
|
1388
|
-
return null;
|
|
1389
|
-
}
|
|
1390
|
-
}
|
|
1391
|
-
function runLifecycleHooks(config, event, payload, opts) {
|
|
1392
|
-
if (!config || config.enabled === false) return [];
|
|
1393
|
-
const options = typeof opts === "string" ? { configDir: opts } : opts;
|
|
1394
|
-
const store = loadHookTrustStore(options.configDir);
|
|
1395
|
-
const hooks = asArray(config.events?.[event]);
|
|
1396
|
-
const decisions = [];
|
|
1397
|
-
for (let i = 0; i < hooks.length; i++) {
|
|
1398
|
-
const hook = hooks[i];
|
|
1399
|
-
if (!hook.command || hook.disabled) continue;
|
|
1400
|
-
const source = hook.source ?? "user";
|
|
1401
|
-
const hash = hashHook(event, hook.command);
|
|
1402
|
-
const descriptor = {
|
|
1403
|
-
id: `${event}:${i}`,
|
|
1404
|
-
event,
|
|
1405
|
-
command: hook.command,
|
|
1406
|
-
source,
|
|
1407
|
-
hash,
|
|
1408
|
-
trusted: isTrusted(source, event, hash, store),
|
|
1409
|
-
disabled: false,
|
|
1410
|
-
description: hook.description
|
|
1411
|
-
};
|
|
1412
|
-
if (!descriptor.trusted) {
|
|
1413
|
-
options.onSummary?.(`hook skipped: ${event} project hook requires trust (${hash.slice(0, 12)})`);
|
|
1414
|
-
continue;
|
|
1415
|
-
}
|
|
1416
|
-
const decision = runStructuredHook(hook, descriptor, { event, ...payload });
|
|
1417
|
-
if (decision) {
|
|
1418
|
-
decisions.push(decision);
|
|
1419
|
-
options.onSummary?.(`hook ${event}: ${decision.action}${decision.reason ? ` (${decision.reason})` : ""}`);
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
|
-
return decisions;
|
|
1423
|
-
}
|
|
1424
|
-
function rewriteTemplate(template, isWindows) {
|
|
1425
|
-
const ref = (name) => isWindows ? `%${name}%` : `$${name}`;
|
|
1426
|
-
return template.replace(/\{tool\}/g, ref("AICLI_HOOK_TOOL")).replace(/\{dangerLevel\}/g, ref("AICLI_HOOK_DANGER_LEVEL")).replace(/\{args\}/g, ref("AICLI_HOOK_ARGS")).replace(/\{status\}/g, ref("AICLI_HOOK_STATUS"));
|
|
1427
|
-
}
|
|
1428
|
-
function runHook(template, vars) {
|
|
1429
|
-
if (!template) return;
|
|
1430
|
-
const isWindows = process.platform === "win32";
|
|
1431
|
-
const cmd = rewriteTemplate(template, isWindows);
|
|
1432
|
-
try {
|
|
1433
|
-
execSync(cmd, {
|
|
1434
|
-
timeout: DEFAULT_TIMEOUT_MS,
|
|
1435
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
1436
|
-
encoding: "utf-8",
|
|
1437
|
-
env: {
|
|
1438
|
-
...process.env,
|
|
1439
|
-
AICLI_HOOK_TOOL: vars.tool,
|
|
1440
|
-
AICLI_HOOK_DANGER_LEVEL: vars.dangerLevel ?? "",
|
|
1441
|
-
AICLI_HOOK_ARGS: vars.args ?? "",
|
|
1442
|
-
AICLI_HOOK_STATUS: vars.status ?? ""
|
|
1443
|
-
}
|
|
1444
|
-
});
|
|
1445
|
-
} catch {
|
|
1446
|
-
process.stderr.write(`\u26A0 Hook failed: ${cmd.slice(0, 100)}
|
|
1447
|
-
`);
|
|
1448
|
-
}
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1451
1276
|
// src/tools/permissions.ts
|
|
1452
1277
|
import { isAbsolute, resolve as resolve3 } from "path";
|
|
1453
1278
|
function checkPermission(toolName, args, dangerLevel, rules, defaultAction = "confirm") {
|
|
@@ -1870,8 +1695,8 @@ var theme = new Proxy(DARK_THEME, {
|
|
|
1870
1695
|
});
|
|
1871
1696
|
|
|
1872
1697
|
// src/tools/action-classifier.ts
|
|
1873
|
-
import { existsSync as
|
|
1874
|
-
import { isAbsolute as isAbsolute2, join
|
|
1698
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
1699
|
+
import { isAbsolute as isAbsolute2, join, resolve as resolve4 } from "path";
|
|
1875
1700
|
var RECENT_DENIED_LIMIT = 50;
|
|
1876
1701
|
var recentlyDenied = [];
|
|
1877
1702
|
function recordRecentlyDeniedAutoAction(call, classification) {
|
|
@@ -1912,10 +1737,10 @@ function splitShellWords(command) {
|
|
|
1912
1737
|
return out.filter(Boolean);
|
|
1913
1738
|
}
|
|
1914
1739
|
function readPackageManifest(root) {
|
|
1915
|
-
const p =
|
|
1916
|
-
if (!
|
|
1740
|
+
const p = join(root, "package.json");
|
|
1741
|
+
if (!existsSync4(p)) return null;
|
|
1917
1742
|
try {
|
|
1918
|
-
return JSON.parse(
|
|
1743
|
+
return JSON.parse(readFileSync3(p, "utf-8"));
|
|
1919
1744
|
} catch {
|
|
1920
1745
|
return null;
|
|
1921
1746
|
}
|
|
@@ -1931,10 +1756,10 @@ function manifestHasDependency(root, name) {
|
|
|
1931
1756
|
}
|
|
1932
1757
|
function lockfileMentions(root, name) {
|
|
1933
1758
|
for (const file of ["package-lock.json", "pnpm-lock.yaml", "yarn.lock"]) {
|
|
1934
|
-
const p =
|
|
1935
|
-
if (!
|
|
1759
|
+
const p = join(root, file);
|
|
1760
|
+
if (!existsSync4(p)) continue;
|
|
1936
1761
|
try {
|
|
1937
|
-
if (
|
|
1762
|
+
if (readFileSync3(p, "utf-8").includes(name)) return true;
|
|
1938
1763
|
} catch {
|
|
1939
1764
|
}
|
|
1940
1765
|
}
|
|
@@ -2498,10 +2323,10 @@ var ToolExecutor = class {
|
|
|
2498
2323
|
const filePath = String(call.arguments["path"] ?? "");
|
|
2499
2324
|
const newContent = String(call.arguments["content"] ?? "");
|
|
2500
2325
|
if (!filePath) return;
|
|
2501
|
-
if (
|
|
2326
|
+
if (existsSync5(filePath)) {
|
|
2502
2327
|
let oldContent;
|
|
2503
2328
|
try {
|
|
2504
|
-
oldContent =
|
|
2329
|
+
oldContent = readFileSync4(filePath, "utf-8");
|
|
2505
2330
|
} catch {
|
|
2506
2331
|
return;
|
|
2507
2332
|
}
|
|
@@ -2524,7 +2349,7 @@ var ToolExecutor = class {
|
|
|
2524
2349
|
}
|
|
2525
2350
|
} else if (call.name === "edit_file") {
|
|
2526
2351
|
const filePath = String(call.arguments["path"] ?? "");
|
|
2527
|
-
if (!filePath || !
|
|
2352
|
+
if (!filePath || !existsSync5(filePath)) return;
|
|
2528
2353
|
const oldStr = call.arguments["old_str"];
|
|
2529
2354
|
const newStr = call.arguments["new_str"];
|
|
2530
2355
|
if (oldStr !== void 0) {
|
|
@@ -2551,7 +2376,7 @@ var ToolExecutor = class {
|
|
|
2551
2376
|
const to = Number(call.arguments["delete_to_line"] ?? from);
|
|
2552
2377
|
let fileContent;
|
|
2553
2378
|
try {
|
|
2554
|
-
fileContent =
|
|
2379
|
+
fileContent = readFileSync4(filePath, "utf-8");
|
|
2555
2380
|
} catch {
|
|
2556
2381
|
return;
|
|
2557
2382
|
}
|
|
@@ -2786,7 +2611,7 @@ Do NOT split a long document into many write_file(append=true) calls. That patte
|
|
|
2786
2611
|
}
|
|
2787
2612
|
undoStack.push(filePath, `write_file${appendMode ? " (append)" : ""}: ${filePath}`);
|
|
2788
2613
|
fileCheckpoints.snapshot(filePath, ToolExecutor.currentMessageIndex);
|
|
2789
|
-
|
|
2614
|
+
mkdirSync(dirname2(filePath), { recursive: true });
|
|
2790
2615
|
if (appendMode) {
|
|
2791
2616
|
appendFileSync(filePath, content, encoding);
|
|
2792
2617
|
} else {
|
|
@@ -2806,7 +2631,7 @@ Do NOT split a long document into many write_file(append=true) calls. That patte
|
|
|
2806
2631
|
};
|
|
2807
2632
|
|
|
2808
2633
|
// src/tools/builtin/edit-file.ts
|
|
2809
|
-
import { readFileSync as
|
|
2634
|
+
import { readFileSync as readFileSync5, existsSync as existsSync6 } from "fs";
|
|
2810
2635
|
|
|
2811
2636
|
// src/tools/builtin/patch-apply.ts
|
|
2812
2637
|
function parseUnifiedDiff(patch) {
|
|
@@ -3167,7 +2992,7 @@ Note: Path can be absolute or relative to cwd.`,
|
|
|
3167
2992
|
const filePath = String(args["path"] ?? "");
|
|
3168
2993
|
const encoding = args["encoding"] ?? "utf-8";
|
|
3169
2994
|
if (!filePath) throw new ToolError("edit_file", "path is required");
|
|
3170
|
-
if (!
|
|
2995
|
+
if (!existsSync6(filePath)) throw new ToolError("edit_file", `File not found: ${filePath}`);
|
|
3171
2996
|
const verdict = classifyWritePath(filePath);
|
|
3172
2997
|
if (verdict.sensitive && subAgentGuard.active) {
|
|
3173
2998
|
throw new ToolError(
|
|
@@ -3175,7 +3000,7 @@ Note: Path can be absolute or relative to cwd.`,
|
|
|
3175
3000
|
`Refused: sub-agents cannot edit sensitive paths \u2014 ${verdict.reason}. If this is genuinely needed, ask the parent agent to perform the edit so the user can approve it.`
|
|
3176
3001
|
);
|
|
3177
3002
|
}
|
|
3178
|
-
const original =
|
|
3003
|
+
const original = readFileSync5(filePath, encoding);
|
|
3179
3004
|
if (args["patch"] !== void 0) {
|
|
3180
3005
|
const patchText = String(args["patch"] ?? "");
|
|
3181
3006
|
const stopOnError = args["stop_on_error"] !== false;
|
|
@@ -3333,8 +3158,8 @@ function truncatePreview(str, maxLen = 80) {
|
|
|
3333
3158
|
}
|
|
3334
3159
|
|
|
3335
3160
|
// src/tools/builtin/list-dir.ts
|
|
3336
|
-
import { readdirSync as readdirSync3, statSync as statSync3, existsSync as
|
|
3337
|
-
import { join as
|
|
3161
|
+
import { readdirSync as readdirSync3, statSync as statSync3, existsSync as existsSync7 } from "fs";
|
|
3162
|
+
import { join as join2, basename as basename3 } from "path";
|
|
3338
3163
|
var listDirTool = {
|
|
3339
3164
|
definition: {
|
|
3340
3165
|
name: "list_dir",
|
|
@@ -3356,7 +3181,7 @@ var listDirTool = {
|
|
|
3356
3181
|
async execute(args) {
|
|
3357
3182
|
const dirPath = String(args["path"] ?? process.cwd());
|
|
3358
3183
|
const recursive = Boolean(args["recursive"] ?? false);
|
|
3359
|
-
if (!
|
|
3184
|
+
if (!existsSync7(dirPath)) {
|
|
3360
3185
|
const targetName = basename3(dirPath).toLowerCase();
|
|
3361
3186
|
const cwd = process.cwd();
|
|
3362
3187
|
const suggestions = [];
|
|
@@ -3414,11 +3239,11 @@ function listRecursive(basePath, indent, recursive, lines) {
|
|
|
3414
3239
|
if (entry.isDirectory()) {
|
|
3415
3240
|
lines.push(`${indent}\u{1F4C1} ${entry.name}/`);
|
|
3416
3241
|
if (recursive) {
|
|
3417
|
-
listRecursive(
|
|
3242
|
+
listRecursive(join2(basePath, entry.name), indent + " ", true, lines);
|
|
3418
3243
|
}
|
|
3419
3244
|
} else {
|
|
3420
3245
|
try {
|
|
3421
|
-
const stat = statSync3(
|
|
3246
|
+
const stat = statSync3(join2(basePath, entry.name));
|
|
3422
3247
|
const size = formatSize(stat.size);
|
|
3423
3248
|
lines.push(`${indent}\u{1F4C4} ${entry.name} (${size})`);
|
|
3424
3249
|
} catch {
|
|
@@ -3434,9 +3259,9 @@ function formatSize(bytes) {
|
|
|
3434
3259
|
}
|
|
3435
3260
|
|
|
3436
3261
|
// src/tools/builtin/grep-files.ts
|
|
3437
|
-
import { readdirSync as readdirSync4, readFileSync as
|
|
3262
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as statSync4, existsSync as existsSync8 } from "fs";
|
|
3438
3263
|
import { readFile } from "fs/promises";
|
|
3439
|
-
import { join as
|
|
3264
|
+
import { join as join3, relative } from "path";
|
|
3440
3265
|
var grepFilesTool = {
|
|
3441
3266
|
definition: {
|
|
3442
3267
|
name: "grep_files",
|
|
@@ -3487,7 +3312,7 @@ Supports regex. Automatically skips node_modules, dist, .git directories.`,
|
|
|
3487
3312
|
const contextLines = Math.max(0, Number(args["context_lines"] ?? 0));
|
|
3488
3313
|
const maxResults = Math.max(1, Number(args["max_results"] ?? 50));
|
|
3489
3314
|
if (!pattern) throw new ToolError("grep_files", "pattern is required");
|
|
3490
|
-
if (!
|
|
3315
|
+
if (!existsSync8(rootPath)) throw new ToolError("grep_files", `Path not found: ${rootPath}`);
|
|
3491
3316
|
const MAX_PATTERN_LENGTH = 1e3;
|
|
3492
3317
|
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
3493
3318
|
throw new ToolError("grep_files", `Pattern too long (${pattern.length} chars, max ${MAX_PATTERN_LENGTH}). Use a shorter pattern.`);
|
|
@@ -3581,11 +3406,11 @@ function collectFilePaths(rootPath, filePattern, maxFiles) {
|
|
|
3581
3406
|
if (paths.length >= maxFiles) return;
|
|
3582
3407
|
if (entry.isDirectory()) {
|
|
3583
3408
|
if (SKIP_DIRS.has(entry.name) || entry.name.startsWith(".")) continue;
|
|
3584
|
-
walk(
|
|
3409
|
+
walk(join3(dirPath, entry.name));
|
|
3585
3410
|
} else if (entry.isFile()) {
|
|
3586
3411
|
if (isBinary(entry.name)) continue;
|
|
3587
3412
|
if (filePattern && !matchesFilePattern(entry.name, filePattern)) continue;
|
|
3588
|
-
const fullPath =
|
|
3413
|
+
const fullPath = join3(dirPath, entry.name);
|
|
3589
3414
|
try {
|
|
3590
3415
|
if (statSync4(fullPath).size > 1e6) continue;
|
|
3591
3416
|
} catch {
|
|
@@ -3640,7 +3465,7 @@ function searchInFile(fullPath, displayPath, regex, contextLines, maxResults, re
|
|
|
3640
3465
|
}
|
|
3641
3466
|
let content;
|
|
3642
3467
|
try {
|
|
3643
|
-
content =
|
|
3468
|
+
content = readFileSync6(fullPath, "utf-8");
|
|
3644
3469
|
} catch {
|
|
3645
3470
|
return;
|
|
3646
3471
|
}
|
|
@@ -3671,8 +3496,8 @@ function searchInFile(fullPath, displayPath, regex, contextLines, maxResults, re
|
|
|
3671
3496
|
}
|
|
3672
3497
|
|
|
3673
3498
|
// src/tools/builtin/glob-files.ts
|
|
3674
|
-
import { readdirSync as readdirSync5, statSync as statSync5, existsSync as
|
|
3675
|
-
import { join as
|
|
3499
|
+
import { readdirSync as readdirSync5, statSync as statSync5, existsSync as existsSync9 } from "fs";
|
|
3500
|
+
import { join as join4, relative as relative2, basename as basename4 } from "path";
|
|
3676
3501
|
var globFilesTool = {
|
|
3677
3502
|
definition: {
|
|
3678
3503
|
name: "glob_files",
|
|
@@ -3705,7 +3530,7 @@ Results sorted by most recent modification time. Automatically skips node_module
|
|
|
3705
3530
|
const rootPath = String(args["path"] ?? process.cwd());
|
|
3706
3531
|
const maxResults = Math.max(1, Number(args["max_results"] ?? 100));
|
|
3707
3532
|
if (!pattern) throw new ToolError("glob_files", "pattern is required");
|
|
3708
|
-
if (!
|
|
3533
|
+
if (!existsSync9(rootPath)) throw new ToolError("glob_files", `Path not found: ${rootPath}`);
|
|
3709
3534
|
const regex = globToRegex(pattern);
|
|
3710
3535
|
const matches = [];
|
|
3711
3536
|
collectMatchingFiles(rootPath, rootPath, regex, matches, maxResults);
|
|
@@ -3782,7 +3607,7 @@ function collectMatchingFiles(dirPath, rootPath, regex, results, maxResults) {
|
|
|
3782
3607
|
}
|
|
3783
3608
|
for (const entry of entries) {
|
|
3784
3609
|
if (results.length >= maxResults) break;
|
|
3785
|
-
const fullPath =
|
|
3610
|
+
const fullPath = join4(dirPath, entry.name);
|
|
3786
3611
|
if (entry.isDirectory()) {
|
|
3787
3612
|
if (SKIP_DIRS2.has(entry.name) || entry.name.startsWith(".")) continue;
|
|
3788
3613
|
collectMatchingFiles(fullPath, rootPath, regex, results, maxResults);
|
|
@@ -4522,7 +4347,7 @@ ${preamble}`;
|
|
|
4522
4347
|
}
|
|
4523
4348
|
|
|
4524
4349
|
// src/tools/builtin/save-last-response.ts
|
|
4525
|
-
import { mkdirSync as
|
|
4350
|
+
import { mkdirSync as mkdirSync2, unlinkSync as unlinkSync2, rmdirSync as rmdirSync2 } from "fs";
|
|
4526
4351
|
import { dirname as dirname3 } from "path";
|
|
4527
4352
|
var lastResponseStore = { content: "" };
|
|
4528
4353
|
function cleanupRejectedTeeFile(filePath) {
|
|
@@ -4572,7 +4397,7 @@ Any of these triggers means use save_last_response, NOT write_file:
|
|
|
4572
4397
|
throw new ToolError("save_last_response", "No content to save: AI has not produced any response yet, or the last response was empty.");
|
|
4573
4398
|
}
|
|
4574
4399
|
undoStack.push(filePath, `save_last_response: ${filePath}`);
|
|
4575
|
-
|
|
4400
|
+
mkdirSync2(dirname3(filePath), { recursive: true });
|
|
4576
4401
|
atomicWriteFileSync(filePath, content);
|
|
4577
4402
|
const lines = content.split("\n").length;
|
|
4578
4403
|
return `File saved: ${filePath} (${lines} lines, ${content.length} bytes)`;
|
|
@@ -4580,18 +4405,18 @@ Any of these triggers means use save_last_response, NOT write_file:
|
|
|
4580
4405
|
};
|
|
4581
4406
|
|
|
4582
4407
|
// src/tools/builtin/save-memory.ts
|
|
4583
|
-
import { join as
|
|
4408
|
+
import { join as join6 } from "path";
|
|
4584
4409
|
import { homedir as homedir3 } from "os";
|
|
4585
4410
|
|
|
4586
4411
|
// src/memory/persistent-memory.ts
|
|
4587
|
-
import { existsSync as
|
|
4588
|
-
import { randomUUID, createHash
|
|
4589
|
-
import { dirname as dirname4, join as
|
|
4412
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync7 } from "fs";
|
|
4413
|
+
import { randomUUID, createHash } from "crypto";
|
|
4414
|
+
import { dirname as dirname4, join as join5, resolve as resolve6 } from "path";
|
|
4590
4415
|
function memoryStorePath(configDir) {
|
|
4591
|
-
return
|
|
4416
|
+
return join5(configDir, MEMORY_STORE_FILE_NAME);
|
|
4592
4417
|
}
|
|
4593
4418
|
function memoryMarkdownPath(configDir) {
|
|
4594
|
-
return
|
|
4419
|
+
return join5(configDir, MEMORY_FILE_NAME);
|
|
4595
4420
|
}
|
|
4596
4421
|
function getProjectKey(cwd = process.cwd()) {
|
|
4597
4422
|
return resolve6(getGitRoot(cwd) ?? cwd);
|
|
@@ -4627,8 +4452,8 @@ function normalizeEntry(value) {
|
|
|
4627
4452
|
}
|
|
4628
4453
|
function legacyEntriesFromMarkdown(configDir) {
|
|
4629
4454
|
const file = memoryMarkdownPath(configDir);
|
|
4630
|
-
if (!
|
|
4631
|
-
const content =
|
|
4455
|
+
if (!existsSync10(file)) return [];
|
|
4456
|
+
const content = readFileSync7(file, "utf-8").trim();
|
|
4632
4457
|
if (!content) return [];
|
|
4633
4458
|
const parts = content.split(/\n(?=##\s+\d{4}-\d{2}-\d{2})/g);
|
|
4634
4459
|
const chunks = parts.length > 1 ? parts : [content];
|
|
@@ -4637,15 +4462,15 @@ function legacyEntriesFromMarkdown(configDir) {
|
|
|
4637
4462
|
const body = (match ? match[2] : chunk).trim();
|
|
4638
4463
|
const parsed = match ? Date.parse(match[1].replace(" ", "T")) : NaN;
|
|
4639
4464
|
const createdAt = Number.isFinite(parsed) ? new Date(parsed).toISOString() : nowIso();
|
|
4640
|
-
const id = "legacy-" +
|
|
4465
|
+
const id = "legacy-" + createHash("sha1").update(`${index}
|
|
4641
4466
|
${chunk}`).digest("hex").slice(0, 12);
|
|
4642
4467
|
return normalizeEntry({ id, content: body, scope: "personal", createdAt, updatedAt: createdAt, sensitivity: "low", approved: true });
|
|
4643
4468
|
}).filter((entry) => Boolean(entry));
|
|
4644
4469
|
}
|
|
4645
4470
|
function loadMemoryEntries(configDir) {
|
|
4646
4471
|
const file = memoryStorePath(configDir);
|
|
4647
|
-
if (!
|
|
4648
|
-
const text =
|
|
4472
|
+
if (!existsSync10(file)) return legacyEntriesFromMarkdown(configDir);
|
|
4473
|
+
const text = readFileSync7(file, "utf-8").trim();
|
|
4649
4474
|
if (!text) return [];
|
|
4650
4475
|
const entries = [];
|
|
4651
4476
|
for (const line of text.split("\n")) {
|
|
@@ -4660,7 +4485,7 @@ function loadMemoryEntries(configDir) {
|
|
|
4660
4485
|
return entries;
|
|
4661
4486
|
}
|
|
4662
4487
|
function saveMemoryEntries(configDir, entries) {
|
|
4663
|
-
|
|
4488
|
+
mkdirSync3(configDir, { recursive: true });
|
|
4664
4489
|
const jsonl = entries.map((entry) => JSON.stringify(entry)).join("\n");
|
|
4665
4490
|
atomicWriteFileSync(memoryStorePath(configDir), jsonl ? jsonl + "\n" : "");
|
|
4666
4491
|
syncLegacyMarkdown(configDir, entries);
|
|
@@ -4735,7 +4560,7 @@ function findUnique(entries, idPrefix) {
|
|
|
4735
4560
|
return matches[0];
|
|
4736
4561
|
}
|
|
4737
4562
|
function syncLegacyMarkdown(configDir, entries = loadMemoryEntries(configDir)) {
|
|
4738
|
-
|
|
4563
|
+
mkdirSync3(dirname4(memoryMarkdownPath(configDir)), { recursive: true });
|
|
4739
4564
|
const active = entries.filter((entry) => entry.approved && !isMemoryExpired(entry));
|
|
4740
4565
|
const markdown = active.map((entry) => {
|
|
4741
4566
|
const date = entry.createdAt.replace("T", " ").slice(0, 19);
|
|
@@ -4778,7 +4603,7 @@ ${entry.content}`;
|
|
|
4778
4603
|
|
|
4779
4604
|
// src/tools/builtin/save-memory.ts
|
|
4780
4605
|
function getConfigDir() {
|
|
4781
|
-
return
|
|
4606
|
+
return join6(homedir3(), CONFIG_DIR_NAME);
|
|
4782
4607
|
}
|
|
4783
4608
|
function parseScope(value) {
|
|
4784
4609
|
return value === "personal" || value === "project" || value === "session" || value === "team" ? value : void 0;
|
|
@@ -5112,8 +4937,8 @@ function formatResults2(query, data, _requested) {
|
|
|
5112
4937
|
}
|
|
5113
4938
|
|
|
5114
4939
|
// src/agents/agent-config.ts
|
|
5115
|
-
import { existsSync as
|
|
5116
|
-
import { join as
|
|
4940
|
+
import { existsSync as existsSync11, readdirSync as readdirSync6, readFileSync as readFileSync8 } from "fs";
|
|
4941
|
+
import { join as join7 } from "path";
|
|
5117
4942
|
import { homedir as homedir4 } from "os";
|
|
5118
4943
|
var READ_ONLY_TOOLS2 = /* @__PURE__ */ new Set([
|
|
5119
4944
|
"read_file",
|
|
@@ -5208,13 +5033,13 @@ function parseAgentConfig(raw, source, path3) {
|
|
|
5208
5033
|
return cfg;
|
|
5209
5034
|
}
|
|
5210
5035
|
function loadAgentDir(dir, source) {
|
|
5211
|
-
if (!
|
|
5036
|
+
if (!existsSync11(dir)) return [];
|
|
5212
5037
|
const out = [];
|
|
5213
5038
|
for (const file of readdirSync6(dir)) {
|
|
5214
5039
|
if (!file.endsWith(".json")) continue;
|
|
5215
|
-
const path3 =
|
|
5040
|
+
const path3 = join7(dir, file);
|
|
5216
5041
|
try {
|
|
5217
|
-
const parsed = JSON.parse(
|
|
5042
|
+
const parsed = JSON.parse(readFileSync8(path3, "utf-8"));
|
|
5218
5043
|
const cfg = parseAgentConfig(parsed, source, path3);
|
|
5219
5044
|
if (cfg) out.push(cfg);
|
|
5220
5045
|
} catch {
|
|
@@ -5224,8 +5049,8 @@ function loadAgentDir(dir, source) {
|
|
|
5224
5049
|
}
|
|
5225
5050
|
function getAgentDirs(configDir, cwd = process.cwd()) {
|
|
5226
5051
|
return {
|
|
5227
|
-
user:
|
|
5228
|
-
project:
|
|
5052
|
+
user: join7(configDir ?? join7(homedir4(), CONFIG_DIR_NAME), "agents"),
|
|
5053
|
+
project: join7(cwd, CONFIG_DIR_NAME, "agents")
|
|
5229
5054
|
};
|
|
5230
5055
|
}
|
|
5231
5056
|
function listAgentConfigs(configDir, cwd = process.cwd()) {
|
|
@@ -5233,6 +5058,11 @@ function listAgentConfigs(configDir, cwd = process.cwd()) {
|
|
|
5233
5058
|
const byName = /* @__PURE__ */ new Map();
|
|
5234
5059
|
for (const cfg of BUILTIN_AGENTS) byName.set(normalizeName(cfg.name), { ...cfg });
|
|
5235
5060
|
for (const cfg of loadAgentDir(dirs.user, "user")) byName.set(normalizeName(cfg.name), cfg);
|
|
5061
|
+
if (configDir) {
|
|
5062
|
+
for (const dir of getActivePluginAssets(configDir).agentDirs) {
|
|
5063
|
+
for (const cfg of loadAgentDir(dir, "plugin")) byName.set(normalizeName(cfg.name), cfg);
|
|
5064
|
+
}
|
|
5065
|
+
}
|
|
5236
5066
|
for (const cfg of loadAgentDir(dirs.project, "project")) byName.set(normalizeName(cfg.name), cfg);
|
|
5237
5067
|
return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
5238
5068
|
}
|
|
@@ -5935,14 +5765,14 @@ var taskStopTool = {
|
|
|
5935
5765
|
|
|
5936
5766
|
// src/tools/builtin/git-tools.ts
|
|
5937
5767
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
5938
|
-
import { existsSync as
|
|
5939
|
-
import { join as
|
|
5768
|
+
import { existsSync as existsSync12 } from "fs";
|
|
5769
|
+
import { join as join8 } from "path";
|
|
5940
5770
|
function assertGitRepo(cwd) {
|
|
5941
5771
|
let dir = cwd;
|
|
5942
5772
|
const root = dir.split(/[\\/]/)[0] + (dir.includes("\\") ? "\\" : "/");
|
|
5943
5773
|
while (dir && dir !== root) {
|
|
5944
|
-
if (
|
|
5945
|
-
const parent =
|
|
5774
|
+
if (existsSync12(join8(dir, ".git"))) return;
|
|
5775
|
+
const parent = join8(dir, "..");
|
|
5946
5776
|
if (parent === dir) break;
|
|
5947
5777
|
dir = parent;
|
|
5948
5778
|
}
|
|
@@ -6207,7 +6037,7 @@ ${commitOutput.trim()}`;
|
|
|
6207
6037
|
};
|
|
6208
6038
|
|
|
6209
6039
|
// src/tools/builtin/notebook-edit.ts
|
|
6210
|
-
import { readFileSync as
|
|
6040
|
+
import { readFileSync as readFileSync9, existsSync as existsSync13 } from "fs";
|
|
6211
6041
|
import { writeFile } from "fs/promises";
|
|
6212
6042
|
import { resolve as resolve7, extname as extname2 } from "path";
|
|
6213
6043
|
var notebookEditTool = {
|
|
@@ -6262,10 +6092,10 @@ var notebookEditTool = {
|
|
|
6262
6092
|
if (extname2(absPath).toLowerCase() !== ".ipynb") {
|
|
6263
6093
|
throw new ToolError("notebook_edit", "path must point to a .ipynb file");
|
|
6264
6094
|
}
|
|
6265
|
-
if (!
|
|
6095
|
+
if (!existsSync13(absPath)) {
|
|
6266
6096
|
throw new ToolError("notebook_edit", `Notebook not found: ${filePath}`);
|
|
6267
6097
|
}
|
|
6268
|
-
const raw =
|
|
6098
|
+
const raw = readFileSync9(absPath, "utf-8");
|
|
6269
6099
|
const nb = parseNotebook(raw);
|
|
6270
6100
|
const cellIdx0 = cellIndexRaw - 1;
|
|
6271
6101
|
undoStack.push(absPath, `notebook_edit (${action}): ${filePath}`);
|
|
@@ -6682,8 +6512,8 @@ function estimateToolDefinitionTokens(def) {
|
|
|
6682
6512
|
|
|
6683
6513
|
// src/tools/registry.ts
|
|
6684
6514
|
import { pathToFileURL } from "url";
|
|
6685
|
-
import { existsSync as
|
|
6686
|
-
import { join as
|
|
6515
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync4, readdirSync as readdirSync7 } from "fs";
|
|
6516
|
+
import { join as join9 } from "path";
|
|
6687
6517
|
var ToolRegistry = class {
|
|
6688
6518
|
tools = /* @__PURE__ */ new Map();
|
|
6689
6519
|
pluginToolNames = /* @__PURE__ */ new Set();
|
|
@@ -6844,9 +6674,9 @@ var ToolRegistry = class {
|
|
|
6844
6674
|
* Returns the number of successfully loaded plugins.
|
|
6845
6675
|
*/
|
|
6846
6676
|
async loadPlugins(pluginsDir, allowPlugins = false) {
|
|
6847
|
-
if (!
|
|
6677
|
+
if (!existsSync14(pluginsDir)) {
|
|
6848
6678
|
try {
|
|
6849
|
-
|
|
6679
|
+
mkdirSync4(pluginsDir, { recursive: true });
|
|
6850
6680
|
} catch {
|
|
6851
6681
|
}
|
|
6852
6682
|
return 0;
|
|
@@ -6870,12 +6700,12 @@ var ToolRegistry = class {
|
|
|
6870
6700
|
process.stderr.write(
|
|
6871
6701
|
`
|
|
6872
6702
|
[plugins] \u26A0 Loading ${files.length} plugin(s) with FULL system privileges:
|
|
6873
|
-
` + files.map((f) => ` + ${
|
|
6703
|
+
` + files.map((f) => ` + ${join9(pluginsDir, f)}`).join("\n") + "\n\n"
|
|
6874
6704
|
);
|
|
6875
6705
|
let loaded = 0;
|
|
6876
6706
|
for (const file of files) {
|
|
6877
6707
|
try {
|
|
6878
|
-
const fileUrl = pathToFileURL(
|
|
6708
|
+
const fileUrl = pathToFileURL(join9(pluginsDir, file)).href;
|
|
6879
6709
|
const mod = await import(fileUrl);
|
|
6880
6710
|
const tool = mod.tool ?? mod.default?.tool ?? mod.default;
|
|
6881
6711
|
if (!tool || typeof tool.execute !== "function" || !tool.definition?.name) {
|
|
@@ -6907,12 +6737,6 @@ export {
|
|
|
6907
6737
|
theme,
|
|
6908
6738
|
undoStack,
|
|
6909
6739
|
renderDiff,
|
|
6910
|
-
listHooks,
|
|
6911
|
-
trustHook,
|
|
6912
|
-
untrustHook,
|
|
6913
|
-
getPendingHookTrust,
|
|
6914
|
-
runLifecycleHooks,
|
|
6915
|
-
runHook,
|
|
6916
6740
|
recordRecentlyDeniedAutoAction,
|
|
6917
6741
|
getRecentlyDeniedAutoActions,
|
|
6918
6742
|
clearRecentlyDeniedAutoActions,
|