jinzd-ai-cli 0.4.211 → 0.4.212
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 +23 -0
- package/README.zh-CN.md +23 -0
- package/dist/{batch-DE4RXKZD.js → batch-WIKFEOAZ.js} +2 -2
- package/dist/{chat-index-UBCWHBLR.js → chat-index-R2E27VXN.js} +1 -1
- package/dist/{chunk-E5XCM4A6.js → chunk-GBBVCZ4W.js} +1 -1
- package/dist/{chunk-C3OU2OPF.js → chunk-HW2ALWQJ.js} +2 -2
- package/dist/{chunk-6NS6643Y.js → chunk-HX6N6QEY.js} +1 -1
- package/dist/{chunk-JBWA73GK.js → chunk-IFZX26K7.js} +1 -1
- package/dist/{chunk-ZY2N2N6T.js → chunk-KE4B3NOQ.js} +1 -1
- package/dist/{chunk-BE6ERF7M.js → chunk-LU6FBJQ5.js} +1 -1
- package/dist/{chunk-ZOPYREL5.js → chunk-N5LB3PPL.js} +258 -52
- package/dist/{chunk-UOROWTGG.js → chunk-NYCBOVNF.js} +26 -3
- package/dist/{chunk-W7UKO3PS.js → chunk-OQGVGPEK.js} +5 -0
- package/dist/{ci-XMUEX526.js → ci-X3LNUFZV.js} +2 -2
- package/dist/{constants-AWTIQIWG.js → constants-KDWG4KR4.js} +1 -1
- package/dist/{doctor-cli-SSI6ETFT.js → doctor-cli-TJTWIW7U.js} +4 -4
- package/dist/electron-server.js +468 -174
- package/dist/{hub-INUJND2G.js → hub-JWSV4MKC.js} +1 -1
- package/dist/index.js +142 -17
- package/dist/{run-tests-PACN4UYX.js → run-tests-D7YBY4XB.js} +1 -1
- package/dist/{run-tests-3MHWUF43.js → run-tests-H4Q2PRX6.js} +2 -2
- package/dist/{server-7USZJJAH.js → server-OFKGDRYI.js} +4 -4
- package/dist/{server-BTSKOPQI.js → server-VNCN7AY5.js} +99 -10
- package/dist/{task-orchestrator-OV4O25MX.js → task-orchestrator-AL2E642M.js} +4 -4
- package/dist/{usage-T2P6FTE7.js → usage-LB6REWPO.js} +2 -2
- package/dist/web/client/app.js +1 -1
- package/package.json +1 -1
|
@@ -154,7 +154,7 @@ ${content}`);
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
async function runTaskMode(config, providers, configManager, topic) {
|
|
157
|
-
const { TaskOrchestrator } = await import("./task-orchestrator-
|
|
157
|
+
const { TaskOrchestrator } = await import("./task-orchestrator-AL2E642M.js");
|
|
158
158
|
const orchestrator = new TaskOrchestrator(config, providers, configManager);
|
|
159
159
|
let interrupted = false;
|
|
160
160
|
const onSigint = () => {
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
scanProject,
|
|
16
16
|
sessionHasMeaningfulContent,
|
|
17
17
|
setupProxy
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-HW2ALWQJ.js";
|
|
19
19
|
import {
|
|
20
20
|
buildReviewPrompt,
|
|
21
21
|
buildSecurityReviewPrompt
|
|
@@ -27,23 +27,28 @@ import {
|
|
|
27
27
|
cleanupRejectedTeeFile,
|
|
28
28
|
estimateTokens,
|
|
29
29
|
formatPermissionProfileWarning,
|
|
30
|
+
getPendingHookTrust,
|
|
30
31
|
googleSearchContext,
|
|
31
32
|
initTheme,
|
|
32
33
|
isInterrupted,
|
|
33
34
|
lastResponseStore,
|
|
35
|
+
listHooks,
|
|
34
36
|
renderDiff,
|
|
35
37
|
requestInterrupt,
|
|
36
38
|
resetInterrupt,
|
|
37
39
|
rlInternal,
|
|
40
|
+
runLifecycleHooks,
|
|
38
41
|
setContextWindow,
|
|
39
42
|
setMaxOutputCap,
|
|
40
43
|
spawnAgentContext,
|
|
41
44
|
theme,
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
trustHook,
|
|
46
|
+
undoStack,
|
|
47
|
+
untrustHook
|
|
48
|
+
} from "./chunk-N5LB3PPL.js";
|
|
44
49
|
import "./chunk-T2NL5ZIA.js";
|
|
45
50
|
import "./chunk-BXP6YZ2P.js";
|
|
46
|
-
import "./chunk-
|
|
51
|
+
import "./chunk-HX6N6QEY.js";
|
|
47
52
|
import {
|
|
48
53
|
SessionManager,
|
|
49
54
|
getContentText
|
|
@@ -60,7 +65,7 @@ import {
|
|
|
60
65
|
getConfigDirUsage,
|
|
61
66
|
listRecentCrashes,
|
|
62
67
|
writeCrashLog
|
|
63
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-LU6FBJQ5.js";
|
|
64
69
|
import {
|
|
65
70
|
ProviderRegistry
|
|
66
71
|
} from "./chunk-QMXC327F.js";
|
|
@@ -69,7 +74,7 @@ import {
|
|
|
69
74
|
getTopFailingTools,
|
|
70
75
|
getTopUsedTools,
|
|
71
76
|
installFlushOnExit
|
|
72
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-IFZX26K7.js";
|
|
73
78
|
import {
|
|
74
79
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
75
80
|
TEE_FINAL_USER_NUDGE,
|
|
@@ -91,7 +96,7 @@ import {
|
|
|
91
96
|
} from "./chunk-XPBEJB27.js";
|
|
92
97
|
import {
|
|
93
98
|
ConfigManager
|
|
94
|
-
} from "./chunk-
|
|
99
|
+
} from "./chunk-NYCBOVNF.js";
|
|
95
100
|
import {
|
|
96
101
|
AuthError,
|
|
97
102
|
ProviderError,
|
|
@@ -117,7 +122,7 @@ import {
|
|
|
117
122
|
SKILLS_DIR_NAME,
|
|
118
123
|
VERSION,
|
|
119
124
|
buildUserIdentityPrompt
|
|
120
|
-
} from "./chunk-
|
|
125
|
+
} from "./chunk-GBBVCZ4W.js";
|
|
121
126
|
import {
|
|
122
127
|
formatGitContextForPrompt,
|
|
123
128
|
getGitContext,
|
|
@@ -934,6 +939,7 @@ function createDefaultCommands() {
|
|
|
934
939
|
["/config [set|get|show]", "Config wizard / get / set / show all"],
|
|
935
940
|
["/profile [show|set|clear]", "View or edit your identity"],
|
|
936
941
|
["/security [status|scan|on|off]", "Sensitive-data redaction"],
|
|
942
|
+
["/hooks [list|trust|untrust]", "Lifecycle hooks and project hook trust"],
|
|
937
943
|
["/doctor", "Health check (API keys, config, MCP, crashes, tool stats)"],
|
|
938
944
|
["/bug [--copy]", "Generate bug report template"],
|
|
939
945
|
["/about", "About ai-cli & author info"],
|
|
@@ -1356,6 +1362,7 @@ No commands match "${filter}".
|
|
|
1356
1362
|
console.log(` Ctx Win : ${ctxStr}`);
|
|
1357
1363
|
console.log(" PermProf : " + (ctx.config.get("defaultPermissionProfile") ?? "legacy"));
|
|
1358
1364
|
console.log(" Network : " + (ctx.config.get("networkPolicy")?.enabled ?? false ? "on" : "off"));
|
|
1365
|
+
console.log(" Hooks : " + getPendingHookTrust(ctx.config.get("hooks") ?? void 0, ctx.config.getConfigDir()).length + " pending trust");
|
|
1359
1366
|
console.log(` Messages : ${session?.messages.length ?? 0}`);
|
|
1360
1367
|
console.log(` Session : ${session?.id.slice(0, 8) ?? "none"}`);
|
|
1361
1368
|
if (layers.length > 0) {
|
|
@@ -1649,7 +1656,7 @@ No tools match "${filter}".
|
|
|
1649
1656
|
const { join: join5 } = await import("path");
|
|
1650
1657
|
const { existsSync: existsSync5 } = await import("fs");
|
|
1651
1658
|
const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
|
|
1652
|
-
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-
|
|
1659
|
+
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-KDWG4KR4.js");
|
|
1653
1660
|
const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
|
|
1654
1661
|
const cwd = process.cwd();
|
|
1655
1662
|
const projectRoot = getGitRoot2(cwd) ?? cwd;
|
|
@@ -2708,7 +2715,7 @@ ${hint}` : "")
|
|
|
2708
2715
|
usage: "/test [command|filter]",
|
|
2709
2716
|
async execute(args, ctx) {
|
|
2710
2717
|
try {
|
|
2711
|
-
const { executeTests } = await import("./run-tests-
|
|
2718
|
+
const { executeTests } = await import("./run-tests-H4Q2PRX6.js");
|
|
2712
2719
|
const argStr = args.join(" ").trim();
|
|
2713
2720
|
let testArgs = {};
|
|
2714
2721
|
if (argStr) {
|
|
@@ -3287,6 +3294,71 @@ Summary: ${fileMap.size} file(s) \u2014 ${newFiles} new, ${modifiedFiles} modifi
|
|
|
3287
3294
|
}
|
|
3288
3295
|
}
|
|
3289
3296
|
},
|
|
3297
|
+
{
|
|
3298
|
+
name: "hooks",
|
|
3299
|
+
description: "Manage lifecycle hooks and project hook trust",
|
|
3300
|
+
usage: "/hooks [list|inspect <id>|trust <id>|untrust <id>|disable]",
|
|
3301
|
+
execute(args, ctx) {
|
|
3302
|
+
const sub = (args[0] || "list").toLowerCase();
|
|
3303
|
+
const hooks = listHooks(ctx.config.get("hooks") ?? void 0, ctx.config.getConfigDir());
|
|
3304
|
+
const findHook = (id) => hooks.find((h) => h.id === id || h.hash.startsWith(id ?? ""));
|
|
3305
|
+
if (sub === "list") {
|
|
3306
|
+
console.log(theme.heading(" Hooks"));
|
|
3307
|
+
if (hooks.length === 0) {
|
|
3308
|
+
console.log(theme.dim(" No hooks configured."));
|
|
3309
|
+
} else {
|
|
3310
|
+
for (const h of hooks) {
|
|
3311
|
+
const trust = h.disabled ? theme.dim("disabled") : h.trusted ? theme.success("trusted") : theme.warning("pending");
|
|
3312
|
+
console.log(` ${h.id.padEnd(18)} ${h.source.padEnd(7)} ${trust} ${h.hash.slice(0, 12)} ${theme.dim(h.command.slice(0, 80))}`);
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
console.log();
|
|
3316
|
+
return;
|
|
3317
|
+
}
|
|
3318
|
+
if (sub === "inspect") {
|
|
3319
|
+
const h = findHook(args[1]);
|
|
3320
|
+
if (!h) {
|
|
3321
|
+
console.log(theme.warning(" Hook not found. Use /hooks list."));
|
|
3322
|
+
return;
|
|
3323
|
+
}
|
|
3324
|
+
console.log(theme.heading(" Hook"));
|
|
3325
|
+
console.log(` id : ${h.id}`);
|
|
3326
|
+
console.log(` event : ${h.event}`);
|
|
3327
|
+
console.log(` source : ${h.source}`);
|
|
3328
|
+
console.log(` hash : ${h.hash}`);
|
|
3329
|
+
console.log(` trusted : ${h.trusted ? "yes" : "no"}`);
|
|
3330
|
+
console.log(` disabled: ${h.disabled ? "yes" : "no"}`);
|
|
3331
|
+
console.log(` command : ${h.command}`);
|
|
3332
|
+
console.log();
|
|
3333
|
+
return;
|
|
3334
|
+
}
|
|
3335
|
+
if (sub === "trust" || sub === "untrust") {
|
|
3336
|
+
const h = findHook(args[1]);
|
|
3337
|
+
if (!h) {
|
|
3338
|
+
console.log(theme.warning(" Hook not found. Use /hooks list."));
|
|
3339
|
+
return;
|
|
3340
|
+
}
|
|
3341
|
+
if (sub === "trust") {
|
|
3342
|
+
trustHook(ctx.config.getConfigDir(), h);
|
|
3343
|
+
console.log(theme.success(` \u2713 trusted ${h.id} (${h.hash.slice(0, 12)})`));
|
|
3344
|
+
} else {
|
|
3345
|
+
untrustHook(ctx.config.getConfigDir(), h);
|
|
3346
|
+
console.log(theme.success(` \u2713 untrusted ${h.id}`));
|
|
3347
|
+
}
|
|
3348
|
+
console.log();
|
|
3349
|
+
return;
|
|
3350
|
+
}
|
|
3351
|
+
if (sub === "disable") {
|
|
3352
|
+
const cfg = ctx.config.get("hooks") ?? {};
|
|
3353
|
+
ctx.config.set("hooks", { ...cfg, enabled: false });
|
|
3354
|
+
console.log(theme.success(" \u2713 hooks disabled in user config"));
|
|
3355
|
+
console.log();
|
|
3356
|
+
return;
|
|
3357
|
+
}
|
|
3358
|
+
console.log(theme.warning(" Usage: /hooks [list|inspect <id>|trust <id>|untrust <id>|disable]"));
|
|
3359
|
+
console.log();
|
|
3360
|
+
}
|
|
3361
|
+
},
|
|
3290
3362
|
{
|
|
3291
3363
|
name: "security",
|
|
3292
3364
|
description: "Sensitive-data redaction \u2014 status, scan sessions, toggle on/off",
|
|
@@ -3306,6 +3378,7 @@ Summary: ${fileMap.size} file(s) \u2014 ${newFiles} new, ${modifiedFiles} modifi
|
|
|
3306
3378
|
console.log(` mode : ${security.mode}`);
|
|
3307
3379
|
console.log(" profile : " + (ctx.config.get("defaultPermissionProfile") ?? "legacy"));
|
|
3308
3380
|
console.log(" network : " + (ctx.config.get("networkPolicy")?.enabled ?? false ? "on" : "off"));
|
|
3381
|
+
console.log(" hooks : " + getPendingHookTrust(ctx.config.get("hooks") ?? void 0, ctx.config.getConfigDir()).length + " pending trust");
|
|
3309
3382
|
console.log(` patterns : ${DEFAULT_PATTERNS.length} built-in + ${security.customPatterns?.length ?? 0} custom`);
|
|
3310
3383
|
console.log(` last save : ${ctx.sessions.lastRedactionHits} hit(s) redacted`);
|
|
3311
3384
|
console.log();
|
|
@@ -4465,6 +4538,7 @@ var Repl = class {
|
|
|
4465
4538
|
const permissionProfiles = this.config.get("permissionProfiles") ?? {};
|
|
4466
4539
|
this.toolExecutor.setConfig({
|
|
4467
4540
|
hookConfig: this.config.get("hooks") ?? void 0,
|
|
4541
|
+
hookConfigDir: this.config.getConfigDir(),
|
|
4468
4542
|
permissionRules: this.config.get("permissionRules") ?? [],
|
|
4469
4543
|
defaultPermission: this.config.get("defaultPermission") ?? "confirm",
|
|
4470
4544
|
permissionProfileName,
|
|
@@ -4473,6 +4547,11 @@ var Repl = class {
|
|
|
4473
4547
|
workspaceRoot: process.cwd(),
|
|
4474
4548
|
networkPolicy: this.config.get("networkPolicy")
|
|
4475
4549
|
});
|
|
4550
|
+
const pendingHooks = getPendingHookTrust(this.config.get("hooks") ?? void 0, this.config.getConfigDir());
|
|
4551
|
+
if (pendingHooks.length > 0) {
|
|
4552
|
+
process.stderr.write(theme.warning(" \u26A0 " + pendingHooks.length + " project hook(s) require trust. Run /hooks list and /hooks trust <id>.\n"));
|
|
4553
|
+
}
|
|
4554
|
+
runLifecycleHooks(this.config.get("hooks") ?? void 0, "SessionStart", { source: "repl" }, { configDir: this.config.getConfigDir() });
|
|
4476
4555
|
if (this.config.get("alwaysYolo") === true) {
|
|
4477
4556
|
this.toolExecutor.sessionAutoApprove = true;
|
|
4478
4557
|
}
|
|
@@ -4944,6 +5023,21 @@ ${skillContent}`);
|
|
|
4944
5023
|
);
|
|
4945
5024
|
return false;
|
|
4946
5025
|
}
|
|
5026
|
+
const preDecisions = runLifecycleHooks(
|
|
5027
|
+
this.config.get("hooks") ?? void 0,
|
|
5028
|
+
"PreCompact",
|
|
5029
|
+
{ sessionId: session.id, messageCount: session.messages.length, instruction },
|
|
5030
|
+
{ configDir: this.config.getConfigDir(), onSummary: (msg) => process.stdout.write(theme.dim(" [hook] " + msg) + "\n") }
|
|
5031
|
+
);
|
|
5032
|
+
const preDeny = preDecisions.find((d) => d.action === "deny");
|
|
5033
|
+
if (preDeny) {
|
|
5034
|
+
process.stdout.write(theme.warning(" \u26A0 Compact blocked by hook: " + (preDeny.reason ?? "PreCompact denied") + "\n"));
|
|
5035
|
+
return false;
|
|
5036
|
+
}
|
|
5037
|
+
for (const d of preDecisions) {
|
|
5038
|
+
const warnings = [d.warning, ...d.warnings ?? []].filter(Boolean);
|
|
5039
|
+
for (const w of warnings) process.stdout.write(theme.warning(" \u26A0 Hook warning: " + w + "\n"));
|
|
5040
|
+
}
|
|
4947
5041
|
const provider = this.providers.get(this.currentProvider);
|
|
4948
5042
|
const modelParams = this.getModelParams();
|
|
4949
5043
|
const spinner = this.renderer.showSpinner("Compacting session...");
|
|
@@ -5005,6 +5099,12 @@ ${response.content.trim()}
|
|
|
5005
5099
|
const tokensBefore = ctxWindow > 0 ? this.estimateConversationTokens() : 0;
|
|
5006
5100
|
const removedCount = session.compact(summaryMsg, ackMsg, COMPACT_KEEP_LAST);
|
|
5007
5101
|
const afterCount = session.messages.length;
|
|
5102
|
+
runLifecycleHooks(
|
|
5103
|
+
this.config.get("hooks") ?? void 0,
|
|
5104
|
+
"PostCompact",
|
|
5105
|
+
{ sessionId: session.id, beforeCount, afterCount, removedCount, keepLast: COMPACT_KEEP_LAST, instruction },
|
|
5106
|
+
{ configDir: this.config.getConfigDir(), onSummary: (msg) => process.stdout.write(theme.dim(" [hook] " + msg) + "\n") }
|
|
5107
|
+
);
|
|
5008
5108
|
const tokensAfter = ctxWindow > 0 ? this.estimateConversationTokens() : 0;
|
|
5009
5109
|
const pctBefore = ctxWindow > 0 ? Math.round(tokensBefore / ctxWindow * 100) : 0;
|
|
5010
5110
|
const pctAfter = ctxWindow > 0 ? Math.round(tokensAfter / ctxWindow * 100) : 0;
|
|
@@ -5440,8 +5540,32 @@ Session '${this.resumeSessionId}' not found.
|
|
|
5440
5540
|
});
|
|
5441
5541
|
});
|
|
5442
5542
|
}
|
|
5543
|
+
runUserPromptHooks(sessionId, userInput) {
|
|
5544
|
+
const promptDecisions = runLifecycleHooks(
|
|
5545
|
+
this.config.get("hooks") ?? void 0,
|
|
5546
|
+
"UserPromptSubmit",
|
|
5547
|
+
{ sessionId, prompt: userInput },
|
|
5548
|
+
{ configDir: this.config.getConfigDir(), onSummary: (msg) => process.stdout.write(theme.dim(" [hook] " + msg) + "\n") }
|
|
5549
|
+
);
|
|
5550
|
+
const promptDeny = promptDecisions.find((d) => d.action === "deny");
|
|
5551
|
+
if (promptDeny) {
|
|
5552
|
+
process.stdout.write(theme.warning(" \u26A0 Prompt blocked by hook: " + (promptDeny.reason ?? "UserPromptSubmit denied") + "\n"));
|
|
5553
|
+
return false;
|
|
5554
|
+
}
|
|
5555
|
+
for (const d of promptDecisions) {
|
|
5556
|
+
const warnings = [d.warning, ...d.warnings ?? []].filter(Boolean);
|
|
5557
|
+
for (const w of warnings) process.stdout.write(theme.warning(" \u26A0 Hook warning: " + w + "\n"));
|
|
5558
|
+
}
|
|
5559
|
+
const secretHits = scanString(userInput, { customRegexes: [] });
|
|
5560
|
+
if (secretHits.length > 0) {
|
|
5561
|
+
const kinds = [...new Set(secretHits.map((h) => h.kind))].join(", ");
|
|
5562
|
+
process.stdout.write(theme.warning(" \u26A0 Possible secret in prompt (" + kinds + "). It will be sent unless you interrupt now.\n"));
|
|
5563
|
+
}
|
|
5564
|
+
return true;
|
|
5565
|
+
}
|
|
5443
5566
|
async handleChat(userInput) {
|
|
5444
5567
|
const session = this.sessions.current;
|
|
5568
|
+
if (!this.runUserPromptHooks(session.id, userInput)) return;
|
|
5445
5569
|
const { parts, hasImage, refs } = parseAtReferences(userInput, process.cwd());
|
|
5446
5570
|
for (const ref of refs) {
|
|
5447
5571
|
if (ref.type === "notfound") {
|
|
@@ -6906,6 +7030,7 @@ Tip: You can continue the conversation by asking the AI to proceed.`
|
|
|
6906
7030
|
void this.shutdownAsync();
|
|
6907
7031
|
}
|
|
6908
7032
|
async shutdownAsync() {
|
|
7033
|
+
runLifecycleHooks(this.config.get("hooks") ?? void 0, "Stop", { sessionId: this.sessions.current?.id }, { configDir: this.config.getConfigDir() });
|
|
6909
7034
|
this.running = false;
|
|
6910
7035
|
const sessionId = this.sessions.current?.id;
|
|
6911
7036
|
if (sessionId) {
|
|
@@ -7020,7 +7145,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
7020
7145
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
7021
7146
|
process.exit(1);
|
|
7022
7147
|
}
|
|
7023
|
-
const { startWebServer } = await import("./server-
|
|
7148
|
+
const { startWebServer } = await import("./server-VNCN7AY5.js");
|
|
7024
7149
|
await startWebServer({ port, host: options.host });
|
|
7025
7150
|
});
|
|
7026
7151
|
program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | logout-all <name> | migrate <name>)").action(async (action, username) => {
|
|
@@ -7187,16 +7312,16 @@ program.command("sessions").description("List recent conversation sessions").opt
|
|
|
7187
7312
|
console.log(footer + "\n");
|
|
7188
7313
|
});
|
|
7189
7314
|
program.command("usage").description("Show token + cost usage grouped by provider/model (cross-session)").option("--days <n>", "Only the last N days (inclusive of today)").option("--month <ym>", "Only a specific month, format YYYY-MM (e.g. 2026-06)").option("--json", "Output as JSON (for scripting)").action(async (options) => {
|
|
7190
|
-
const { runUsageCli } = await import("./usage-
|
|
7315
|
+
const { runUsageCli } = await import("./usage-LB6REWPO.js");
|
|
7191
7316
|
await runUsageCli(options);
|
|
7192
7317
|
});
|
|
7193
7318
|
program.command("doctor").description("Health check: API keys, config, MCP, recent crashes, tool usage, disk usage").option("--json", "Output as JSON (for scripting)").option("--reset-stats", "Reset accumulated tool usage statistics").action(async (options) => {
|
|
7194
|
-
const { runDoctorCli } = await import("./doctor-cli-
|
|
7319
|
+
const { runDoctorCli } = await import("./doctor-cli-TJTWIW7U.js");
|
|
7195
7320
|
await runDoctorCli({ json: !!options.json, resetStats: !!options.resetStats });
|
|
7196
7321
|
});
|
|
7197
7322
|
program.command("batch <action> [arg] [arg2]").description("Anthropic Message Batches: submit | list | status <id> | results <id> [out] | cancel <id>").option("--dry-run", "Parse and validate input without submitting (submit only)").action(async (action, arg, arg2, options) => {
|
|
7198
7323
|
try {
|
|
7199
|
-
const batch = await import("./batch-
|
|
7324
|
+
const batch = await import("./batch-WIKFEOAZ.js");
|
|
7200
7325
|
switch (action) {
|
|
7201
7326
|
case "submit":
|
|
7202
7327
|
if (!arg) {
|
|
@@ -7239,7 +7364,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
|
|
|
7239
7364
|
}
|
|
7240
7365
|
});
|
|
7241
7366
|
program.command("mcp-serve").description("Start an MCP server over STDIO, exposing aicli's built-in tools to Claude Desktop / Cursor / other MCP clients").option("--allow-destructive", "Allow bash / run_interactive / task_create (always destructive in MCP mode)").option("--allow-outside-cwd", "Allow tool path arguments to escape the sandbox root \u2014 disabled by default").option("--tools <list>", "Comma-separated whitelist of tools to expose (default: all eligible tools)").option("--cwd <path>", "Working directory AND sandbox root (default: current directory)").action(async (options) => {
|
|
7242
|
-
const { startMcpServer } = await import("./server-
|
|
7367
|
+
const { startMcpServer } = await import("./server-OFKGDRYI.js");
|
|
7243
7368
|
await startMcpServer({
|
|
7244
7369
|
allowDestructive: !!options.allowDestructive,
|
|
7245
7370
|
allowOutsideCwd: !!options.allowOutsideCwd,
|
|
@@ -7248,7 +7373,7 @@ program.command("mcp-serve").description("Start an MCP server over STDIO, exposi
|
|
|
7248
7373
|
});
|
|
7249
7374
|
});
|
|
7250
7375
|
program.command("ci").description("Headless PR review (code + security) \u2014 reads git/gh diff, optionally posts to PR. Designed for GitHub Actions.").option("--pr <num>", "PR number; diff fetched via `gh pr diff <num>`", (v) => parseInt(v, 10)).option("--base <ref>", "Base ref for `git diff <ref>...HEAD` (ignored when --pr set)").option("--post", "Post review as a PR comment (requires gh CLI + GH_TOKEN, needs --pr)").option("--no-update", "Always create a new comment instead of updating the previous aicli review").option("--skip-code", "Skip the code review section").option("--skip-security", "Skip the security review section").option("--detailed", "Use the detailed code-review prompt").option("--max-diff <n>", "Max diff chars sent to the model (default 30000)", (v) => parseInt(v, 10)).option("--provider <id>", "Override provider (default: config.defaultProvider)").option("--model <id>", "Override model").option("--dry-run", "Print result to stdout instead of posting (overrides --post)").action(async (options) => {
|
|
7251
|
-
const { runCi } = await import("./ci-
|
|
7376
|
+
const { runCi } = await import("./ci-X3LNUFZV.js");
|
|
7252
7377
|
const result = await runCi({
|
|
7253
7378
|
pr: options.pr,
|
|
7254
7379
|
base: options.base,
|
|
@@ -7394,7 +7519,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
7394
7519
|
}),
|
|
7395
7520
|
config.get("customProviders")
|
|
7396
7521
|
);
|
|
7397
|
-
const { startHub } = await import("./hub-
|
|
7522
|
+
const { startHub } = await import("./hub-JWSV4MKC.js");
|
|
7398
7523
|
await startHub(
|
|
7399
7524
|
{
|
|
7400
7525
|
topic: topic ?? "",
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ToolRegistry
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-N5LB3PPL.js";
|
|
5
5
|
import "./chunk-T2NL5ZIA.js";
|
|
6
6
|
import "./chunk-BXP6YZ2P.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-HX6N6QEY.js";
|
|
8
8
|
import {
|
|
9
9
|
runTool
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-IFZX26K7.js";
|
|
11
11
|
import {
|
|
12
12
|
getDangerLevel,
|
|
13
13
|
schemaToJsonSchema
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import "./chunk-TZQHYZKT.js";
|
|
16
16
|
import {
|
|
17
17
|
VERSION
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-GBBVCZ4W.js";
|
|
19
19
|
import "./chunk-4BKXL7SM.js";
|
|
20
20
|
import "./chunk-TB4W4Y4T.js";
|
|
21
21
|
import "./chunk-KHYD3WXE.js";
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
scanDirTree,
|
|
25
25
|
scanProject,
|
|
26
26
|
setupProxy
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-HW2ALWQJ.js";
|
|
28
28
|
import {
|
|
29
29
|
buildReviewPrompt,
|
|
30
30
|
buildSecurityReviewPrompt
|
|
@@ -38,10 +38,12 @@ import {
|
|
|
38
38
|
cleanupRejectedTeeFile,
|
|
39
39
|
estimateTokens,
|
|
40
40
|
formatPermissionProfileWarning,
|
|
41
|
+
getPendingHookTrust,
|
|
41
42
|
googleSearchContext,
|
|
42
43
|
groupCallsByPhase,
|
|
43
44
|
renderDiff,
|
|
44
45
|
runHook,
|
|
46
|
+
runLifecycleHooks,
|
|
45
47
|
runSafePhases,
|
|
46
48
|
runWithSessionKey,
|
|
47
49
|
setContextWindow,
|
|
@@ -49,10 +51,10 @@ import {
|
|
|
49
51
|
spawnAgentContext,
|
|
50
52
|
truncateOutput,
|
|
51
53
|
undoStack
|
|
52
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-N5LB3PPL.js";
|
|
53
55
|
import "./chunk-T2NL5ZIA.js";
|
|
54
56
|
import "./chunk-BXP6YZ2P.js";
|
|
55
|
-
import "./chunk-
|
|
57
|
+
import "./chunk-HX6N6QEY.js";
|
|
56
58
|
import {
|
|
57
59
|
SessionManager,
|
|
58
60
|
getContentText
|
|
@@ -66,7 +68,7 @@ import {
|
|
|
66
68
|
} from "./chunk-QMXC327F.js";
|
|
67
69
|
import {
|
|
68
70
|
runTool
|
|
69
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-IFZX26K7.js";
|
|
70
72
|
import {
|
|
71
73
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
72
74
|
TEE_FINAL_USER_NUDGE,
|
|
@@ -85,7 +87,7 @@ import {
|
|
|
85
87
|
} from "./chunk-XPBEJB27.js";
|
|
86
88
|
import {
|
|
87
89
|
ConfigManager
|
|
88
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-NYCBOVNF.js";
|
|
89
91
|
import "./chunk-TZQHYZKT.js";
|
|
90
92
|
import {
|
|
91
93
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
@@ -104,7 +106,7 @@ import {
|
|
|
104
106
|
SKILLS_DIR_NAME,
|
|
105
107
|
VERSION,
|
|
106
108
|
buildUserIdentityPrompt
|
|
107
|
-
} from "./chunk-
|
|
109
|
+
} from "./chunk-GBBVCZ4W.js";
|
|
108
110
|
import {
|
|
109
111
|
formatGitContextForPrompt,
|
|
110
112
|
getGitContext,
|
|
@@ -113,7 +115,9 @@ import {
|
|
|
113
115
|
import "./chunk-4BKXL7SM.js";
|
|
114
116
|
import "./chunk-TB4W4Y4T.js";
|
|
115
117
|
import "./chunk-KHYD3WXE.js";
|
|
116
|
-
import
|
|
118
|
+
import {
|
|
119
|
+
scanString
|
|
120
|
+
} from "./chunk-SLSWPBK3.js";
|
|
117
121
|
import "./chunk-K3CF65QH.js";
|
|
118
122
|
import "./chunk-CKH4KQ4E.js";
|
|
119
123
|
import {
|
|
@@ -147,6 +151,7 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
147
151
|
allowedPermissionProfiles = [];
|
|
148
152
|
workspaceRoot = process.cwd();
|
|
149
153
|
networkPolicy;
|
|
154
|
+
hookConfigDir = process.cwd();
|
|
150
155
|
/** Pending confirm promises keyed by requestId */
|
|
151
156
|
pendingConfirms = /* @__PURE__ */ new Map();
|
|
152
157
|
/** Pending batch confirm promises */
|
|
@@ -186,6 +191,7 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
186
191
|
if (opts.allowedPermissionProfiles) this.allowedPermissionProfiles = opts.allowedPermissionProfiles;
|
|
187
192
|
if (opts.workspaceRoot) this.workspaceRoot = opts.workspaceRoot;
|
|
188
193
|
if (opts.networkPolicy) this.networkPolicy = opts.networkPolicy;
|
|
194
|
+
if (opts.hookConfigDir) this.hookConfigDir = opts.hookConfigDir;
|
|
189
195
|
}
|
|
190
196
|
/** Clear M7 timeout timer for a requestId */
|
|
191
197
|
clearPendingTimer(requestId) {
|
|
@@ -234,7 +240,6 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
234
240
|
}
|
|
235
241
|
sendToolCallStart(call) {
|
|
236
242
|
const dangerLevel = getDangerLevel(call.name, call.arguments);
|
|
237
|
-
let toolCallStarted = false;
|
|
238
243
|
const startTime = Date.now();
|
|
239
244
|
this.toolStartTimes.set(call.id, startTime);
|
|
240
245
|
const msg = {
|
|
@@ -349,6 +354,26 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
349
354
|
dangerLevel,
|
|
350
355
|
args: JSON.stringify(call.arguments).slice(0, 200)
|
|
351
356
|
});
|
|
357
|
+
const preToolDecisions = runLifecycleHooks(
|
|
358
|
+
this.hookConfig,
|
|
359
|
+
"PreToolUse",
|
|
360
|
+
{ tool: call.name, dangerLevel, args: call.arguments },
|
|
361
|
+
{ configDir: this.hookConfigDir, onSummary: (message) => this.send({ type: "info", message: `[hook] ${message}` }) }
|
|
362
|
+
);
|
|
363
|
+
const preDeny = preToolDecisions.find((d) => d.action === "deny");
|
|
364
|
+
if (preDeny) {
|
|
365
|
+
const result = {
|
|
366
|
+
callId: call.id,
|
|
367
|
+
content: `[Hook denied] ${preDeny.reason ?? `PreToolUse blocked ${call.name}`}. Do not retry without asking.`,
|
|
368
|
+
isError: true
|
|
369
|
+
};
|
|
370
|
+
this.sendToolCallResult(call, result.content, true);
|
|
371
|
+
return result;
|
|
372
|
+
}
|
|
373
|
+
for (const d of preToolDecisions) {
|
|
374
|
+
const warnings = [d.warning, ...d.warnings ?? []].filter(Boolean);
|
|
375
|
+
for (const warning of warnings) this.send({ type: "info", message: `[hook] ${warning}` });
|
|
376
|
+
}
|
|
352
377
|
const permission = checkPermissionWithProfile(
|
|
353
378
|
call.name,
|
|
354
379
|
call.arguments,
|
|
@@ -364,6 +389,14 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
364
389
|
}
|
|
365
390
|
);
|
|
366
391
|
const networkPermission = checkNetworkPolicy(call.name, call.arguments, this.networkPolicy);
|
|
392
|
+
if (networkPermission?.action === "confirm" || permission.action === "confirm") {
|
|
393
|
+
runLifecycleHooks(
|
|
394
|
+
this.hookConfig,
|
|
395
|
+
"PermissionRequest",
|
|
396
|
+
{ tool: call.name, dangerLevel, args: call.arguments, reason: networkPermission?.reason ?? permission.reason },
|
|
397
|
+
{ configDir: this.hookConfigDir, onSummary: (message) => this.send({ type: "info", message: "[hook] " + message }) }
|
|
398
|
+
);
|
|
399
|
+
}
|
|
367
400
|
if (networkPermission?.action === "deny") {
|
|
368
401
|
const reason = networkPermission.reason ? ` (${networkPermission.reason})` : "";
|
|
369
402
|
return {
|
|
@@ -387,11 +420,13 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
387
420
|
const content = truncateOutput(rawContent, call.name);
|
|
388
421
|
this.sendToolCallResult(call, rawContent, false);
|
|
389
422
|
runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "ok" });
|
|
423
|
+
runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
|
|
390
424
|
return { callId: call.id, content, isError: false };
|
|
391
425
|
} catch (err) {
|
|
392
426
|
const message = err instanceof Error ? err.message : String(err);
|
|
393
427
|
this.sendToolCallResult(call, message, true);
|
|
394
428
|
runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
|
|
429
|
+
runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
|
|
395
430
|
return { callId: call.id, content: message, isError: true };
|
|
396
431
|
}
|
|
397
432
|
}
|
|
@@ -412,11 +447,13 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
412
447
|
const content = truncateOutput(rawContent, call.name);
|
|
413
448
|
this.sendToolCallResult(call, rawContent, false);
|
|
414
449
|
runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "ok" });
|
|
450
|
+
runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
|
|
415
451
|
return { callId: call.id, content, isError: false };
|
|
416
452
|
} catch (err) {
|
|
417
453
|
const message = err instanceof Error ? err.message : String(err);
|
|
418
454
|
this.sendToolCallResult(call, message, true);
|
|
419
455
|
runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
|
|
456
|
+
runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
|
|
420
457
|
return { callId: call.id, content: message, isError: true };
|
|
421
458
|
}
|
|
422
459
|
}
|
|
@@ -434,11 +471,13 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
434
471
|
const content = truncateOutput(rawContent, call.name);
|
|
435
472
|
this.sendToolCallResult(call, rawContent, false);
|
|
436
473
|
runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "ok" });
|
|
474
|
+
runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
|
|
437
475
|
return { callId: call.id, content, isError: false };
|
|
438
476
|
} catch (err) {
|
|
439
477
|
const message = err instanceof Error ? err.message : String(err);
|
|
440
478
|
this.sendToolCallResult(call, message, true);
|
|
441
479
|
runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
|
|
480
|
+
runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
|
|
442
481
|
return { callId: call.id, content: message, isError: true };
|
|
443
482
|
}
|
|
444
483
|
}
|
|
@@ -681,6 +720,7 @@ var SessionHandler = class {
|
|
|
681
720
|
const permissionProfiles = this.config.get("permissionProfiles") ?? {};
|
|
682
721
|
this.toolExecutor.setConfig({
|
|
683
722
|
hookConfig: hooks,
|
|
723
|
+
hookConfigDir: this.config.getConfigDir(),
|
|
684
724
|
permissionRules,
|
|
685
725
|
defaultPermission,
|
|
686
726
|
permissionProfileName,
|
|
@@ -693,6 +733,11 @@ var SessionHandler = class {
|
|
|
693
733
|
if (permissionProfileWarning) {
|
|
694
734
|
this.send({ type: "info", message: permissionProfileWarning });
|
|
695
735
|
}
|
|
736
|
+
const pendingHooks = getPendingHookTrust(hooks, this.config.getConfigDir());
|
|
737
|
+
if (pendingHooks.length > 0) {
|
|
738
|
+
this.send({ type: "info", message: `${pendingHooks.length} project hook(s) require trust. Use /hooks list and /hooks trust <id>.` });
|
|
739
|
+
}
|
|
740
|
+
runLifecycleHooks(hooks, "SessionStart", { source: "web" }, { configDir: this.config.getConfigDir() });
|
|
696
741
|
this.sendStatus();
|
|
697
742
|
askUserContext.rl = null;
|
|
698
743
|
askUserContext.prompting = false;
|
|
@@ -801,6 +846,7 @@ var SessionHandler = class {
|
|
|
801
846
|
}
|
|
802
847
|
}
|
|
803
848
|
onDisconnect() {
|
|
849
|
+
runLifecycleHooks(this.config.get("hooks") ?? void 0, "Stop", { sessionId: this.sessions.current?.id }, { configDir: this.config.getConfigDir() });
|
|
804
850
|
this.toolExecutor.cancelAll();
|
|
805
851
|
if (this.abortController) this.abortController.abort();
|
|
806
852
|
for (const resolve3 of this.pendingAskUser.values()) resolve3(null);
|
|
@@ -978,6 +1024,26 @@ var SessionHandler = class {
|
|
|
978
1024
|
try {
|
|
979
1025
|
this.ensureSession();
|
|
980
1026
|
const session = this.sessions.current;
|
|
1027
|
+
const promptDecisions = runLifecycleHooks(
|
|
1028
|
+
this.config.get("hooks") ?? void 0,
|
|
1029
|
+
"UserPromptSubmit",
|
|
1030
|
+
{ sessionId: session.id, prompt: content },
|
|
1031
|
+
{ configDir: this.config.getConfigDir(), onSummary: (message) => this.send({ type: "info", message: "[hook] " + message }) }
|
|
1032
|
+
);
|
|
1033
|
+
const promptDeny = promptDecisions.find((d) => d.action === "deny");
|
|
1034
|
+
if (promptDeny) {
|
|
1035
|
+
this.send({ type: "error", message: "Prompt blocked by hook: " + (promptDeny.reason ?? "UserPromptSubmit denied") });
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
for (const d of promptDecisions) {
|
|
1039
|
+
const warnings = [d.warning, ...d.warnings ?? []].filter(Boolean);
|
|
1040
|
+
for (const warning of warnings) this.send({ type: "info", message: "[hook] " + warning });
|
|
1041
|
+
}
|
|
1042
|
+
const secretHits = scanString(content, { customRegexes: [] });
|
|
1043
|
+
if (secretHits.length > 0) {
|
|
1044
|
+
const kinds = [...new Set(secretHits.map((h) => h.kind))].join(", ");
|
|
1045
|
+
this.send({ type: "info", message: "Possible secret in prompt (" + kinds + ")." });
|
|
1046
|
+
}
|
|
981
1047
|
const ALLOWED_IMAGE_MIMES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/gif", "image/webp", "image/svg+xml"]);
|
|
982
1048
|
const MAX_IMAGE_SIZE = 10 * 1024 * 1024;
|
|
983
1049
|
let msgContent;
|
|
@@ -2533,7 +2599,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
2533
2599
|
case "test": {
|
|
2534
2600
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
2535
2601
|
try {
|
|
2536
|
-
const { executeTests } = await import("./run-tests-
|
|
2602
|
+
const { executeTests } = await import("./run-tests-H4Q2PRX6.js");
|
|
2537
2603
|
const argStr = args.join(" ").trim();
|
|
2538
2604
|
let testArgs = {};
|
|
2539
2605
|
if (argStr) {
|
|
@@ -2883,6 +2949,21 @@ Add .md files to create commands.` });
|
|
|
2883
2949
|
this.send({ type: "info", message: "Not enough messages to compact." });
|
|
2884
2950
|
return;
|
|
2885
2951
|
}
|
|
2952
|
+
const preDecisions = runLifecycleHooks(
|
|
2953
|
+
this.config.get("hooks") ?? void 0,
|
|
2954
|
+
"PreCompact",
|
|
2955
|
+
{ sessionId: session.id, messageCount: session.messages.length, instruction },
|
|
2956
|
+
{ configDir: this.config.getConfigDir(), onSummary: (message) => this.send({ type: "info", message: "[hook] " + message }) }
|
|
2957
|
+
);
|
|
2958
|
+
const preDeny = preDecisions.find((d) => d.action === "deny");
|
|
2959
|
+
if (preDeny) {
|
|
2960
|
+
this.send({ type: "error", message: "Compact blocked by hook: " + (preDeny.reason ?? "PreCompact denied") });
|
|
2961
|
+
return;
|
|
2962
|
+
}
|
|
2963
|
+
for (const d of preDecisions) {
|
|
2964
|
+
const warnings = [d.warning, ...d.warnings ?? []].filter(Boolean);
|
|
2965
|
+
for (const warning of warnings) this.send({ type: "info", message: "[hook] " + warning });
|
|
2966
|
+
}
|
|
2886
2967
|
const provider = this.providers.get(this.currentProvider);
|
|
2887
2968
|
if (!provider) return;
|
|
2888
2969
|
this.send({ type: "info", message: "Compacting conversation..." });
|
|
@@ -2902,7 +2983,15 @@ Add .md files to create commands.` });
|
|
|
2902
2983
|
});
|
|
2903
2984
|
const summaryMsg = { role: "user", content: "[Conversation summary]", timestamp: /* @__PURE__ */ new Date() };
|
|
2904
2985
|
const ackMsg = { role: "assistant", content: response.content, timestamp: /* @__PURE__ */ new Date() };
|
|
2905
|
-
session.
|
|
2986
|
+
const beforeCount = session.messages.length;
|
|
2987
|
+
const removedCount = session.compact(summaryMsg, ackMsg, keepLast);
|
|
2988
|
+
const afterCount = session.messages.length;
|
|
2989
|
+
runLifecycleHooks(
|
|
2990
|
+
this.config.get("hooks") ?? void 0,
|
|
2991
|
+
"PostCompact",
|
|
2992
|
+
{ sessionId: session.id, beforeCount, afterCount, removedCount, keepLast, instruction },
|
|
2993
|
+
{ configDir: this.config.getConfigDir(), onSummary: (message) => this.send({ type: "info", message: "[hook] " + message }) }
|
|
2994
|
+
);
|
|
2906
2995
|
this.send({ type: "info", message: `Compacted: removed ${toSummarize.length} messages, kept last ${keepLast}.` });
|
|
2907
2996
|
this.sendStatus();
|
|
2908
2997
|
} catch (err) {
|