jinzd-ai-cli 0.4.88 → 0.4.89
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/dist/{batch-7XCYSPJU.js → batch-UMQYXVKG.js} +2 -2
- package/dist/chat-index-W2UZ34ZI.js +18 -0
- package/dist/{chunk-PFYAAX2S.js → chunk-2DXY7UGF.js} +16 -63
- package/dist/{chunk-QT2KNL3V.js → chunk-3O3U3L5W.js} +1 -1
- package/dist/{chunk-P6EQZKKG.js → chunk-4WVXTADR.js} +1 -1
- package/dist/{chunk-YDHIU24C.js → chunk-ABPT6XCI.js} +76 -3
- package/dist/chunk-ANYYM4CF.js +460 -0
- package/dist/{chunk-VGXNE37B.js → chunk-E7YC4GWV.js} +1 -1
- package/dist/{chunk-L3MBIO36.js → chunk-FVRLRIKC.js} +5 -106
- package/dist/chunk-KHYD3WXE.js +52 -0
- package/dist/{chunk-CQQQFNND.js → chunk-KJLJPUY2.js} +6 -4
- package/dist/{chunk-V3NMERIB.js → chunk-TKYNTXKB.js} +1 -1
- package/dist/electron-server.js +171 -13
- package/dist/{hub-IR4INXSU.js → hub-4P2BH57W.js} +1 -1
- package/dist/index.js +158 -19
- package/dist/{run-tests-FQHDUYOG.js → run-tests-5TO5G3YH.js} +2 -2
- package/dist/{run-tests-JVWIGY7P.js → run-tests-TGGXTOFF.js} +1 -1
- package/dist/{semantic-ICJ536BG.js → semantic-YDRPPVWK.js} +3 -2
- package/dist/{server-UWKRV5DK.js → server-NG7AEAD5.js} +15 -13
- package/dist/{server-HTVVWKFN.js → server-U2BBLP4Y.js} +7 -5
- package/dist/{task-orchestrator-6MI6LD7T.js → task-orchestrator-ODU45UQG.js} +7 -5
- package/dist/{vector-store-YTVHACBV.js → vector-store-QARQ2P6D.js} +2 -1
- package/package.json +1 -1
package/dist/electron-server.js
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
VERSION,
|
|
37
37
|
buildUserIdentityPrompt,
|
|
38
38
|
runTestsTool
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-4WVXTADR.js";
|
|
40
40
|
import {
|
|
41
41
|
hasSemanticIndex,
|
|
42
42
|
semanticSearch
|
|
@@ -44,7 +44,10 @@ import {
|
|
|
44
44
|
import {
|
|
45
45
|
loadIndex
|
|
46
46
|
} from "./chunk-BJAT4GNC.js";
|
|
47
|
-
import
|
|
47
|
+
import {
|
|
48
|
+
EMBEDDING_DIM,
|
|
49
|
+
embedOne
|
|
50
|
+
} from "./chunk-XMA222FQ.js";
|
|
48
51
|
|
|
49
52
|
// src/web/server.ts
|
|
50
53
|
import express from "express";
|
|
@@ -432,8 +435,8 @@ ${err}`
|
|
|
432
435
|
return EnvLoader.getDefaultProvider() ?? this.config.defaultProvider;
|
|
433
436
|
}
|
|
434
437
|
/** 点分路径读取配置值,如 `ui.theme` → config.ui.theme */
|
|
435
|
-
getByPath(
|
|
436
|
-
const keys =
|
|
438
|
+
getByPath(path4) {
|
|
439
|
+
const keys = path4.split(".");
|
|
437
440
|
let current = this.config;
|
|
438
441
|
for (const key of keys) {
|
|
439
442
|
if (current == null || typeof current !== "object") return void 0;
|
|
@@ -442,8 +445,8 @@ ${err}`
|
|
|
442
445
|
return current;
|
|
443
446
|
}
|
|
444
447
|
/** 点分路径写入配置值,自动类型转换(boolean/number/string)并持久化 */
|
|
445
|
-
setByPath(
|
|
446
|
-
const keys =
|
|
448
|
+
setByPath(path4, rawValue) {
|
|
449
|
+
const keys = path4.split(".");
|
|
447
450
|
if (keys.length === 0) return;
|
|
448
451
|
let value = rawValue;
|
|
449
452
|
if (rawValue === "true") value = true;
|
|
@@ -462,7 +465,7 @@ ${err}`
|
|
|
462
465
|
const result = ConfigSchema.safeParse(draft);
|
|
463
466
|
if (!result.success) {
|
|
464
467
|
const firstErr = result.error.errors[0];
|
|
465
|
-
throw new ConfigError(`Invalid config value for "${
|
|
468
|
+
throw new ConfigError(`Invalid config value for "${path4}": ${firstErr?.message ?? "validation failed"}`);
|
|
466
469
|
}
|
|
467
470
|
this.config = result.data;
|
|
468
471
|
this.save();
|
|
@@ -4355,8 +4358,8 @@ function checkPermission(toolName, args, dangerLevel, rules, defaultAction = "co
|
|
|
4355
4358
|
if (rule.when) {
|
|
4356
4359
|
if (rule.when.dangerLevel && rule.when.dangerLevel !== dangerLevel) continue;
|
|
4357
4360
|
if (rule.when.pathPattern) {
|
|
4358
|
-
const
|
|
4359
|
-
if (!
|
|
4361
|
+
const path4 = String(args["path"] ?? args["command"] ?? "");
|
|
4362
|
+
if (!path4.includes(rule.when.pathPattern)) continue;
|
|
4360
4363
|
}
|
|
4361
4364
|
}
|
|
4362
4365
|
return rule.action;
|
|
@@ -7856,6 +7859,160 @@ ${lines.join("\n")}`;
|
|
|
7856
7859
|
}
|
|
7857
7860
|
};
|
|
7858
7861
|
|
|
7862
|
+
// src/memory/chat-index.ts
|
|
7863
|
+
import fs2 from "fs";
|
|
7864
|
+
import path3 from "path";
|
|
7865
|
+
import os from "os";
|
|
7866
|
+
import crypto from "crypto";
|
|
7867
|
+
var MEMORY_DIR_NAME = "memory-index";
|
|
7868
|
+
var CHUNKS_FILE = "chunks.json";
|
|
7869
|
+
var VECTORS_FILE = "vectors.vec";
|
|
7870
|
+
var VEC_MAGIC = 1094929750;
|
|
7871
|
+
var VEC_VERSION = 1;
|
|
7872
|
+
var VEC_HEADER_BYTES = 16;
|
|
7873
|
+
function memoryIndexDir() {
|
|
7874
|
+
return path3.join(os.homedir(), ".aicli", MEMORY_DIR_NAME);
|
|
7875
|
+
}
|
|
7876
|
+
function chunksPath() {
|
|
7877
|
+
return path3.join(memoryIndexDir(), CHUNKS_FILE);
|
|
7878
|
+
}
|
|
7879
|
+
function vectorsPath() {
|
|
7880
|
+
return path3.join(memoryIndexDir(), VECTORS_FILE);
|
|
7881
|
+
}
|
|
7882
|
+
function readVectorsFile(expectedCount) {
|
|
7883
|
+
const p = vectorsPath();
|
|
7884
|
+
if (!fs2.existsSync(p)) return null;
|
|
7885
|
+
let buf;
|
|
7886
|
+
try {
|
|
7887
|
+
buf = fs2.readFileSync(p);
|
|
7888
|
+
} catch {
|
|
7889
|
+
return null;
|
|
7890
|
+
}
|
|
7891
|
+
if (buf.length < VEC_HEADER_BYTES) return null;
|
|
7892
|
+
const magic = buf.readUInt32LE(0);
|
|
7893
|
+
const version = buf.readUInt32LE(4);
|
|
7894
|
+
const count = buf.readUInt32LE(8);
|
|
7895
|
+
const dim = buf.readUInt32LE(12);
|
|
7896
|
+
if (magic !== VEC_MAGIC || version !== VEC_VERSION || dim !== EMBEDDING_DIM) return null;
|
|
7897
|
+
if (count !== expectedCount) return null;
|
|
7898
|
+
const expected = VEC_HEADER_BYTES + count * dim * 4;
|
|
7899
|
+
if (buf.length !== expected) return null;
|
|
7900
|
+
return new Float32Array(
|
|
7901
|
+
buf.buffer.slice(buf.byteOffset + VEC_HEADER_BYTES, buf.byteOffset + expected)
|
|
7902
|
+
);
|
|
7903
|
+
}
|
|
7904
|
+
function readIndexFile() {
|
|
7905
|
+
const p = chunksPath();
|
|
7906
|
+
if (!fs2.existsSync(p)) return null;
|
|
7907
|
+
try {
|
|
7908
|
+
const raw = fs2.readFileSync(p, "utf-8");
|
|
7909
|
+
const data = JSON.parse(raw);
|
|
7910
|
+
if (data.version !== 1) return null;
|
|
7911
|
+
return data;
|
|
7912
|
+
} catch {
|
|
7913
|
+
return null;
|
|
7914
|
+
}
|
|
7915
|
+
}
|
|
7916
|
+
function loadChatIndex() {
|
|
7917
|
+
const idx = readIndexFile();
|
|
7918
|
+
if (!idx) return null;
|
|
7919
|
+
const vectors = readVectorsFile(idx.chunks.length);
|
|
7920
|
+
if (!vectors) return null;
|
|
7921
|
+
return { idx, vectors };
|
|
7922
|
+
}
|
|
7923
|
+
async function searchChatMemory(query, options = {}) {
|
|
7924
|
+
const topK = options.topK ?? 5;
|
|
7925
|
+
const minScore = options.minScore ?? 0.25;
|
|
7926
|
+
const loaded = loadChatIndex();
|
|
7927
|
+
if (!loaded || loaded.idx.chunks.length === 0) return [];
|
|
7928
|
+
const { idx, vectors } = loaded;
|
|
7929
|
+
const { redacted } = redactString(query, { enabled: true });
|
|
7930
|
+
const qvec = await embedOne(redacted);
|
|
7931
|
+
const candidates = [];
|
|
7932
|
+
for (let i = 0; i < idx.chunks.length; i++) {
|
|
7933
|
+
const c = idx.chunks[i];
|
|
7934
|
+
if (options.sessionId && c.sessionId !== options.sessionId) continue;
|
|
7935
|
+
if (options.excludeSessionId && c.sessionId === options.excludeSessionId) continue;
|
|
7936
|
+
let score = 0;
|
|
7937
|
+
const base = i * EMBEDDING_DIM;
|
|
7938
|
+
for (let d = 0; d < EMBEDDING_DIM; d++) {
|
|
7939
|
+
score += vectors[base + d] * qvec[d];
|
|
7940
|
+
}
|
|
7941
|
+
if (score < minScore) continue;
|
|
7942
|
+
candidates.push({ chunk: c, score });
|
|
7943
|
+
}
|
|
7944
|
+
candidates.sort((a, b) => b.score - a.score);
|
|
7945
|
+
return candidates.slice(0, topK);
|
|
7946
|
+
}
|
|
7947
|
+
|
|
7948
|
+
// src/tools/builtin/recall-memory.ts
|
|
7949
|
+
function formatHit(h, i) {
|
|
7950
|
+
const ts = h.chunk.timestamp.slice(0, 16).replace("T", " ");
|
|
7951
|
+
const title = h.chunk.sessionTitle ? ` \xB7 ${h.chunk.sessionTitle}` : "";
|
|
7952
|
+
const sid = h.chunk.sessionId.slice(0, 8);
|
|
7953
|
+
const score = h.score.toFixed(3);
|
|
7954
|
+
const body = h.chunk.text.length > 600 ? h.chunk.text.slice(0, 600) + "\u2026" : h.chunk.text;
|
|
7955
|
+
return `\u2500\u2500\u2500 Hit ${i + 1} (score ${score}, session ${sid}${title}, ${ts}) \u2500\u2500\u2500
|
|
7956
|
+
` + body;
|
|
7957
|
+
}
|
|
7958
|
+
var recallMemoryTool = {
|
|
7959
|
+
definition: {
|
|
7960
|
+
name: "recall_memory",
|
|
7961
|
+
description: 'Semantic search over past chat sessions. Call this whenever the user references something that may have been discussed before ("last time", "remember", "\u4E4B\u524D", "\u4E0A\u6B21"), when context is ambiguous and continuity matters, or when you want to check what decisions or preferences have been established across prior conversations. Returns up to `topK` relevant snippets with session id, timestamp, and cosine similarity score. Prefer this over asking the user "can you remind me".',
|
|
7962
|
+
parameters: {
|
|
7963
|
+
query: {
|
|
7964
|
+
type: "string",
|
|
7965
|
+
description: "Natural-language description of what to recall. Chinese or English both work.",
|
|
7966
|
+
required: true
|
|
7967
|
+
},
|
|
7968
|
+
topK: {
|
|
7969
|
+
type: "number",
|
|
7970
|
+
description: "Max number of snippets to return (default 5, max 20).",
|
|
7971
|
+
required: false
|
|
7972
|
+
},
|
|
7973
|
+
excludeCurrentSession: {
|
|
7974
|
+
type: "boolean",
|
|
7975
|
+
description: "If true, exclude the current session from results (avoid echoing what you just said). Default false.",
|
|
7976
|
+
required: false
|
|
7977
|
+
},
|
|
7978
|
+
currentSessionId: {
|
|
7979
|
+
type: "string",
|
|
7980
|
+
description: "Session ID to exclude when excludeCurrentSession=true. Usually the active session.",
|
|
7981
|
+
required: false
|
|
7982
|
+
},
|
|
7983
|
+
minScore: {
|
|
7984
|
+
type: "number",
|
|
7985
|
+
description: "Drop hits below this cosine score. Default 0.25. Raise to 0.35+ for stricter matches.",
|
|
7986
|
+
required: false
|
|
7987
|
+
}
|
|
7988
|
+
},
|
|
7989
|
+
dangerous: false
|
|
7990
|
+
},
|
|
7991
|
+
async execute(args) {
|
|
7992
|
+
const query = String(args["query"] ?? "").trim();
|
|
7993
|
+
if (!query) throw new ToolError("recall_memory", "query is required");
|
|
7994
|
+
const topK = Math.max(1, Math.min(20, Number(args["topK"] ?? 5)));
|
|
7995
|
+
const excludeCurrent = Boolean(args["excludeCurrentSession"]);
|
|
7996
|
+
const currentId = args["currentSessionId"] ? String(args["currentSessionId"]) : void 0;
|
|
7997
|
+
const minScore = args["minScore"] !== void 0 ? Number(args["minScore"]) : 0.25;
|
|
7998
|
+
const status = loadChatIndex();
|
|
7999
|
+
if (!status) {
|
|
8000
|
+
return "No chat memory index found. The index is built on REPL startup, or run `/memory rebuild` manually. If you have no past sessions yet, this is expected.";
|
|
8001
|
+
}
|
|
8002
|
+
const hits = await searchChatMemory(query, {
|
|
8003
|
+
topK,
|
|
8004
|
+
minScore,
|
|
8005
|
+
excludeSessionId: excludeCurrent ? currentId : void 0
|
|
8006
|
+
});
|
|
8007
|
+
if (hits.length === 0) {
|
|
8008
|
+
return `No memories matched "${query}" above score ${minScore}. Index has ${status.idx.chunks.length} chunks across ${Object.keys(status.idx.sessionMtimes).length} sessions. Consider lowering minScore to 0.15 or rephrasing the query.`;
|
|
8009
|
+
}
|
|
8010
|
+
const header = `Found ${hits.length} memory hit(s) for "${query}" (min-score ${minScore}):
|
|
8011
|
+
`;
|
|
8012
|
+
return header + "\n" + hits.map(formatHit).join("\n\n");
|
|
8013
|
+
}
|
|
8014
|
+
};
|
|
8015
|
+
|
|
7859
8016
|
// src/core/token-estimator.ts
|
|
7860
8017
|
var CJK_REGEX = /[\u2E80-\u9FFF\uA000-\uA4FF\uAC00-\uD7FF\uF900-\uFAFF\uFE30-\uFE4F\uFF00-\uFFEF]/g;
|
|
7861
8018
|
function estimateTokens(text) {
|
|
@@ -7915,6 +8072,7 @@ var ToolRegistry = class {
|
|
|
7915
8072
|
this.register(getOutlineTool);
|
|
7916
8073
|
this.register(findReferencesTool);
|
|
7917
8074
|
this.register(searchCodeTool);
|
|
8075
|
+
this.register(recallMemoryTool);
|
|
7918
8076
|
}
|
|
7919
8077
|
register(tool) {
|
|
7920
8078
|
this.tools.set(tool.definition.name, tool);
|
|
@@ -9082,9 +9240,9 @@ function getDevStatePath() {
|
|
|
9082
9240
|
return join10(homedir4(), CONFIG_DIR_NAME, DEV_STATE_FILE_NAME);
|
|
9083
9241
|
}
|
|
9084
9242
|
function loadDevState() {
|
|
9085
|
-
const
|
|
9086
|
-
if (!existsSync17(
|
|
9087
|
-
const content = readFileSync11(
|
|
9243
|
+
const path4 = getDevStatePath();
|
|
9244
|
+
if (!existsSync17(path4)) return null;
|
|
9245
|
+
const content = readFileSync11(path4, "utf-8").trim();
|
|
9088
9246
|
return content || null;
|
|
9089
9247
|
}
|
|
9090
9248
|
|
|
@@ -11246,7 +11404,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11246
11404
|
case "test": {
|
|
11247
11405
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
11248
11406
|
try {
|
|
11249
|
-
const { executeTests } = await import("./run-tests-
|
|
11407
|
+
const { executeTests } = await import("./run-tests-TGGXTOFF.js");
|
|
11250
11408
|
const argStr = args.join(" ").trim();
|
|
11251
11409
|
let testArgs = {};
|
|
11252
11410
|
if (argStr) {
|
|
@@ -385,7 +385,7 @@ ${content}`);
|
|
|
385
385
|
}
|
|
386
386
|
}
|
|
387
387
|
async function runTaskMode(config, providers, configManager, topic) {
|
|
388
|
-
const { TaskOrchestrator } = await import("./task-orchestrator-
|
|
388
|
+
const { TaskOrchestrator } = await import("./task-orchestrator-ODU45UQG.js");
|
|
389
389
|
const orchestrator = new TaskOrchestrator(config, providers, configManager);
|
|
390
390
|
let interrupted = false;
|
|
391
391
|
const onSigint = () => {
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
DEFAULT_PATTERNS,
|
|
4
3
|
HALLUCINATION_CORRECTION_MESSAGE,
|
|
5
4
|
McpManager,
|
|
6
5
|
ProviderRegistry,
|
|
@@ -29,13 +28,12 @@ import {
|
|
|
29
28
|
persistToolRound,
|
|
30
29
|
rebuildExtraMessages,
|
|
31
30
|
saveDevState,
|
|
32
|
-
scanString,
|
|
33
31
|
sessionHasMeaningfulContent,
|
|
34
32
|
setupProxy
|
|
35
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-FVRLRIKC.js";
|
|
36
34
|
import {
|
|
37
35
|
ConfigManager
|
|
38
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-3O3U3L5W.js";
|
|
39
37
|
import {
|
|
40
38
|
ToolExecutor,
|
|
41
39
|
ToolRegistry,
|
|
@@ -51,16 +49,25 @@ import {
|
|
|
51
49
|
spawnAgentContext,
|
|
52
50
|
theme,
|
|
53
51
|
undoStack
|
|
54
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-ABPT6XCI.js";
|
|
55
53
|
import "./chunk-2ZD3YTVM.js";
|
|
56
54
|
import {
|
|
57
55
|
fileCheckpoints
|
|
58
56
|
} from "./chunk-4BKXL7SM.js";
|
|
57
|
+
import {
|
|
58
|
+
DEFAULT_PATTERNS,
|
|
59
|
+
buildChatIndex,
|
|
60
|
+
clearChatIndex,
|
|
61
|
+
getChatIndexStatus,
|
|
62
|
+
scanString,
|
|
63
|
+
searchChatMemory
|
|
64
|
+
} from "./chunk-ANYYM4CF.js";
|
|
59
65
|
import "./chunk-NHNWUBXB.js";
|
|
60
|
-
import "./chunk-
|
|
66
|
+
import "./chunk-KJLJPUY2.js";
|
|
61
67
|
import "./chunk-6VRJGH25.js";
|
|
62
|
-
import "./chunk-
|
|
63
|
-
import "./chunk-
|
|
68
|
+
import "./chunk-2DXY7UGF.js";
|
|
69
|
+
import "./chunk-KHYD3WXE.js";
|
|
70
|
+
import "./chunk-TKYNTXKB.js";
|
|
64
71
|
import {
|
|
65
72
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
66
73
|
AUTHOR,
|
|
@@ -82,7 +89,7 @@ import {
|
|
|
82
89
|
SKILLS_DIR_NAME,
|
|
83
90
|
VERSION,
|
|
84
91
|
buildUserIdentityPrompt
|
|
85
|
-
} from "./chunk-
|
|
92
|
+
} from "./chunk-E7YC4GWV.js";
|
|
86
93
|
|
|
87
94
|
// src/index.ts
|
|
88
95
|
import { program } from "commander";
|
|
@@ -2470,7 +2477,7 @@ ${hint}` : "")
|
|
|
2470
2477
|
const root = process.cwd();
|
|
2471
2478
|
const { loadIndex, clearIndex } = await import("./store-S24SPPDZ.js");
|
|
2472
2479
|
const { indexProject } = await import("./indexer-C7QYYHSZ.js");
|
|
2473
|
-
const { loadVectorStore, clearVectorStore } = await import("./vector-store-
|
|
2480
|
+
const { loadVectorStore, clearVectorStore } = await import("./vector-store-QARQ2P6D.js");
|
|
2474
2481
|
if (sub === "status") {
|
|
2475
2482
|
const idx = loadIndex(root);
|
|
2476
2483
|
const vec = loadVectorStore(root);
|
|
@@ -2529,7 +2536,7 @@ ${hint}` : "")
|
|
|
2529
2536
|
}
|
|
2530
2537
|
console.log(theme.dim(` Building semantic index for ${idx.symbolCount} symbols\u2026`));
|
|
2531
2538
|
console.log(theme.dim(" (First run downloads ~117 MB embedding model to ~/.aicli/models/)"));
|
|
2532
|
-
const { rebuildSemanticIndex } = await import("./semantic-
|
|
2539
|
+
const { rebuildSemanticIndex } = await import("./semantic-YDRPPVWK.js");
|
|
2533
2540
|
try {
|
|
2534
2541
|
const stats = await rebuildSemanticIndex(root, {
|
|
2535
2542
|
onProgress: (done, total) => {
|
|
@@ -2595,7 +2602,7 @@ ${hint}` : "")
|
|
|
2595
2602
|
usage: "/test [command|filter]",
|
|
2596
2603
|
async execute(args, ctx) {
|
|
2597
2604
|
try {
|
|
2598
|
-
const { executeTests } = await import("./run-tests-
|
|
2605
|
+
const { executeTests } = await import("./run-tests-5TO5G3YH.js");
|
|
2599
2606
|
const argStr = args.join(" ").trim();
|
|
2600
2607
|
let testArgs = {};
|
|
2601
2608
|
if (argStr) {
|
|
@@ -2750,11 +2757,92 @@ ${hint}` : "")
|
|
|
2750
2757
|
// ── /memory ────────────────────────────────────────────────────────────────
|
|
2751
2758
|
{
|
|
2752
2759
|
name: "memory",
|
|
2753
|
-
description: "
|
|
2754
|
-
usage: "/memory [show|add <text>|clear|path]",
|
|
2755
|
-
execute(args, ctx) {
|
|
2760
|
+
description: "Persistent memory (memory.md) + chat memory recall index (v0.4.89+)",
|
|
2761
|
+
usage: "/memory [show|add <text>|clear|path|rebuild|refresh|status|recall <query>|index-clear]",
|
|
2762
|
+
async execute(args, ctx) {
|
|
2756
2763
|
const memoryFile = join2(ctx.config.getConfigDir(), MEMORY_FILE_NAME);
|
|
2757
2764
|
const sub = args[0] ?? "show";
|
|
2765
|
+
if (sub === "rebuild" || sub === "refresh") {
|
|
2766
|
+
const full = sub === "rebuild";
|
|
2767
|
+
ctx.renderer.printInfo(
|
|
2768
|
+
full ? "\u{1F9E0} Rebuilding chat memory index from scratch (this may take a while on first run \u2014 embedding model ~117 MB)\u2026" : "\u{1F9E0} Refreshing chat memory index (incremental)\u2026"
|
|
2769
|
+
);
|
|
2770
|
+
try {
|
|
2771
|
+
let lastStage = "";
|
|
2772
|
+
const stats = await buildChatIndex({
|
|
2773
|
+
full,
|
|
2774
|
+
onProgress: (p) => {
|
|
2775
|
+
if (p.stage !== lastStage) {
|
|
2776
|
+
lastStage = p.stage;
|
|
2777
|
+
if (p.stage === "embedding" && p.total) {
|
|
2778
|
+
process.stdout.write(theme.dim(` embedding ${p.total} chunk(s)\u2026
|
|
2779
|
+
`));
|
|
2780
|
+
} else if (p.stage !== "done") {
|
|
2781
|
+
process.stdout.write(theme.dim(` ${p.stage}\u2026
|
|
2782
|
+
`));
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
});
|
|
2787
|
+
ctx.renderer.printSuccess(
|
|
2788
|
+
`\u2713 Chat index: ${stats.chunksTotal} chunks (${stats.chunksAdded} new, ${stats.chunksRemoved} removed) across ${stats.sessionsIndexed + stats.sessionsSkipped} sessions (${stats.sessionsIndexed} re-indexed, ${stats.sessionsSkipped} cached) in ${stats.durationMs}ms`
|
|
2789
|
+
);
|
|
2790
|
+
} catch (err) {
|
|
2791
|
+
ctx.renderer.renderError(`Rebuild failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2792
|
+
}
|
|
2793
|
+
return;
|
|
2794
|
+
}
|
|
2795
|
+
if (sub === "status") {
|
|
2796
|
+
const s = getChatIndexStatus();
|
|
2797
|
+
console.log(theme.heading("\n\u{1F9E0} Chat Memory Index"));
|
|
2798
|
+
if (!s.exists) {
|
|
2799
|
+
console.log(theme.dim(" not built yet \u2014 run /memory rebuild\n"));
|
|
2800
|
+
return;
|
|
2801
|
+
}
|
|
2802
|
+
const mb = (n) => `${(n / 1024 / 1024).toFixed(2)} MB`;
|
|
2803
|
+
console.log(` chunks : ${s.chunks}`);
|
|
2804
|
+
console.log(` sessions : ${s.sessions}`);
|
|
2805
|
+
console.log(` built : ${s.built?.replace("T", " ").slice(0, 19) ?? "-"}`);
|
|
2806
|
+
console.log(` model : ${s.model ?? "-"}`);
|
|
2807
|
+
console.log(` vec file : ${mb(s.vecFileSizeBytes)}`);
|
|
2808
|
+
console.log(` chunks file : ${mb(s.chunksFileSizeBytes)}`);
|
|
2809
|
+
console.log();
|
|
2810
|
+
return;
|
|
2811
|
+
}
|
|
2812
|
+
if (sub === "recall") {
|
|
2813
|
+
const query = args.slice(1).join(" ").trim();
|
|
2814
|
+
if (!query) {
|
|
2815
|
+
ctx.renderer.printInfo("Usage: /memory recall <query>");
|
|
2816
|
+
return;
|
|
2817
|
+
}
|
|
2818
|
+
try {
|
|
2819
|
+
const hits = await searchChatMemory(query, { topK: 5, minScore: 0.2 });
|
|
2820
|
+
if (hits.length === 0) {
|
|
2821
|
+
console.log(theme.warning(` No memories matched "${query}" above score 0.20.`));
|
|
2822
|
+
console.log();
|
|
2823
|
+
return;
|
|
2824
|
+
}
|
|
2825
|
+
console.log(theme.heading(`
|
|
2826
|
+
\u{1F9E0} Memory recall for "${query}" \u2014 ${hits.length} hit(s):
|
|
2827
|
+
`));
|
|
2828
|
+
for (const [i, h] of hits.entries()) {
|
|
2829
|
+
const ts = h.chunk.timestamp.slice(0, 16).replace("T", " ");
|
|
2830
|
+
const title = h.chunk.sessionTitle ?? h.chunk.sessionId.slice(0, 8);
|
|
2831
|
+
console.log(theme.accent(` [${i + 1}] ${ts} \xB7 ${title} \xB7 score ${h.score.toFixed(3)}`));
|
|
2832
|
+
const body = h.chunk.text.length > 400 ? h.chunk.text.slice(0, 400) + "\u2026" : h.chunk.text;
|
|
2833
|
+
console.log(theme.dim(" ") + body.replace(/\n/g, "\n "));
|
|
2834
|
+
console.log();
|
|
2835
|
+
}
|
|
2836
|
+
} catch (err) {
|
|
2837
|
+
ctx.renderer.renderError(`Recall failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2838
|
+
}
|
|
2839
|
+
return;
|
|
2840
|
+
}
|
|
2841
|
+
if (sub === "index-clear") {
|
|
2842
|
+
clearChatIndex();
|
|
2843
|
+
ctx.renderer.printSuccess("Chat memory index cleared (memory.md untouched).");
|
|
2844
|
+
return;
|
|
2845
|
+
}
|
|
2758
2846
|
if (sub === "show" || sub === "view") {
|
|
2759
2847
|
if (!existsSync2(memoryFile)) {
|
|
2760
2848
|
ctx.renderer.printInfo("Memory is empty (memory.md not found)");
|
|
@@ -4123,6 +4211,12 @@ var Repl = class {
|
|
|
4123
4211
|
toolExecutor;
|
|
4124
4212
|
/** 运行时有效的 system prompt(合并了项目上下文 + 用户配置) */
|
|
4125
4213
|
activeSystemPrompt;
|
|
4214
|
+
/** v0.4.89: cached chat memory index status, refreshed at startup and after /memory rebuild. */
|
|
4215
|
+
chatMemoryStatus = {
|
|
4216
|
+
exists: false,
|
|
4217
|
+
chunks: 0,
|
|
4218
|
+
sessions: 0
|
|
4219
|
+
};
|
|
4126
4220
|
/** 当前加载的层级上下文(全局/项目/子目录) */
|
|
4127
4221
|
contextLayers = [];
|
|
4128
4222
|
/** 本次会话累计 token 用量 */
|
|
@@ -4580,6 +4674,23 @@ You have a maximum of ${effectiveMaxRounds} tool call rounds per conversation tu
|
|
|
4580
4674
|
if (memory) stableParts.push(`# Persistent Memory
|
|
4581
4675
|
|
|
4582
4676
|
${memory.content}`);
|
|
4677
|
+
if (this.chatMemoryStatus.exists && this.chatMemoryStatus.chunks > 0) {
|
|
4678
|
+
stableParts.push(
|
|
4679
|
+
`# Long-term Memory Recall
|
|
4680
|
+
|
|
4681
|
+
You have a semantic index over ${this.chatMemoryStatus.chunks} chunks from ${this.chatMemoryStatus.sessions} past sessions. Call \`recall_memory({ query: "\u2026" })\` whenever:
|
|
4682
|
+
- The user references something that may have been discussed before ("\u4E0A\u6B21", "\u4E4B\u524D", "last time", "remember")
|
|
4683
|
+
- A pronoun/demonstrative is ambiguous ("\u90A3\u4E2A", "it", "that project") and current context doesn't resolve it
|
|
4684
|
+
- The user asks about preferences, decisions, or conventions that might have been established earlier
|
|
4685
|
+
- Continuity across sessions would clearly help (e.g. user returns after days to the same project)
|
|
4686
|
+
|
|
4687
|
+
Do NOT call it for:
|
|
4688
|
+
- Queries fully answerable from the current conversation
|
|
4689
|
+
- Obviously-new topics with no continuity signal
|
|
4690
|
+
|
|
4691
|
+
Prefer recall over asking the user "can you remind me". When a hit is relevant, cite it briefly ("we established last session that\u2026") so the user sees you remembered.`
|
|
4692
|
+
);
|
|
4693
|
+
}
|
|
4583
4694
|
const devState = loadDevState();
|
|
4584
4695
|
if (devState) {
|
|
4585
4696
|
stableParts.push(
|
|
@@ -4913,6 +5024,34 @@ Session '${this.resumeSessionId}' not found.
|
|
|
4913
5024
|
} catch {
|
|
4914
5025
|
}
|
|
4915
5026
|
})();
|
|
5027
|
+
void (async () => {
|
|
5028
|
+
try {
|
|
5029
|
+
const { getChatIndexStatus: getChatIndexStatus2, buildChatIndex: buildChatIndex2 } = await import("./chat-index-W2UZ34ZI.js");
|
|
5030
|
+
const initial = getChatIndexStatus2();
|
|
5031
|
+
this.chatMemoryStatus = {
|
|
5032
|
+
exists: initial.exists,
|
|
5033
|
+
chunks: initial.chunks,
|
|
5034
|
+
sessions: initial.sessions
|
|
5035
|
+
};
|
|
5036
|
+
if (!initial.exists) return;
|
|
5037
|
+
const stats = await buildChatIndex2({ full: false });
|
|
5038
|
+
const after = getChatIndexStatus2();
|
|
5039
|
+
this.chatMemoryStatus = {
|
|
5040
|
+
exists: after.exists,
|
|
5041
|
+
chunks: after.chunks,
|
|
5042
|
+
sessions: after.sessions
|
|
5043
|
+
};
|
|
5044
|
+
if (stats.sessionsIndexed > 0 || stats.chunksRemoved > 0) {
|
|
5045
|
+
process.stdout.write(
|
|
5046
|
+
theme.dim(
|
|
5047
|
+
` \u{1F9E0} Chat memory refreshed: ${stats.chunksAdded} new \xB7 ${stats.chunksRemoved} removed \xB7 ${stats.chunksTotal} total
|
|
5048
|
+
`
|
|
5049
|
+
)
|
|
5050
|
+
);
|
|
5051
|
+
}
|
|
5052
|
+
} catch {
|
|
5053
|
+
}
|
|
5054
|
+
})();
|
|
4916
5055
|
const globalMcpServers = this.config.get("mcpServers") ?? {};
|
|
4917
5056
|
const projectMcpResult = this.loadProjectMcpConfig();
|
|
4918
5057
|
const projectMcpServers = projectMcpResult?.servers ?? {};
|
|
@@ -6576,7 +6715,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
6576
6715
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
6577
6716
|
process.exit(1);
|
|
6578
6717
|
}
|
|
6579
|
-
const { startWebServer } = await import("./server-
|
|
6718
|
+
const { startWebServer } = await import("./server-NG7AEAD5.js");
|
|
6580
6719
|
await startWebServer({ port, host: options.host });
|
|
6581
6720
|
});
|
|
6582
6721
|
program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | migrate <name>)").action(async (action, username) => {
|
|
@@ -6699,7 +6838,7 @@ program.command("sessions").description("List recent conversation sessions").act
|
|
|
6699
6838
|
});
|
|
6700
6839
|
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) => {
|
|
6701
6840
|
try {
|
|
6702
|
-
const batch = await import("./batch-
|
|
6841
|
+
const batch = await import("./batch-UMQYXVKG.js");
|
|
6703
6842
|
switch (action) {
|
|
6704
6843
|
case "submit":
|
|
6705
6844
|
if (!arg) {
|
|
@@ -6742,7 +6881,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
|
|
|
6742
6881
|
}
|
|
6743
6882
|
});
|
|
6744
6883
|
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) => {
|
|
6745
|
-
const { startMcpServer } = await import("./server-
|
|
6884
|
+
const { startMcpServer } = await import("./server-U2BBLP4Y.js");
|
|
6746
6885
|
await startMcpServer({
|
|
6747
6886
|
allowDestructive: !!options.allowDestructive,
|
|
6748
6887
|
allowOutsideCwd: !!options.allowOutsideCwd,
|
|
@@ -6869,7 +7008,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
6869
7008
|
}),
|
|
6870
7009
|
config.get("customProviders")
|
|
6871
7010
|
);
|
|
6872
|
-
const { startHub } = await import("./hub-
|
|
7011
|
+
const { startHub } = await import("./hub-4P2BH57W.js");
|
|
6873
7012
|
await startHub(
|
|
6874
7013
|
{
|
|
6875
7014
|
topic: topic ?? "",
|
|
@@ -5,9 +5,10 @@ import {
|
|
|
5
5
|
pathTokens,
|
|
6
6
|
rebuildSemanticIndex,
|
|
7
7
|
semanticSearch
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-KJLJPUY2.js";
|
|
9
9
|
import "./chunk-6VRJGH25.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-2DXY7UGF.js";
|
|
11
|
+
import "./chunk-KHYD3WXE.js";
|
|
11
12
|
export {
|
|
12
13
|
buildEmbeddingText,
|
|
13
14
|
hasSemanticIndex,
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
AuthManager
|
|
4
|
+
} from "./chunk-BYNY5JPB.js";
|
|
2
5
|
import {
|
|
3
6
|
HALLUCINATION_CORRECTION_MESSAGE,
|
|
4
7
|
McpManager,
|
|
@@ -20,10 +23,10 @@ import {
|
|
|
20
23
|
persistToolRound,
|
|
21
24
|
rebuildExtraMessages,
|
|
22
25
|
setupProxy
|
|
23
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-FVRLRIKC.js";
|
|
24
27
|
import {
|
|
25
28
|
ConfigManager
|
|
26
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-3O3U3L5W.js";
|
|
27
30
|
import {
|
|
28
31
|
ToolExecutor,
|
|
29
32
|
ToolRegistry,
|
|
@@ -41,14 +44,16 @@ import {
|
|
|
41
44
|
spawnAgentContext,
|
|
42
45
|
truncateOutput,
|
|
43
46
|
undoStack
|
|
44
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-ABPT6XCI.js";
|
|
45
48
|
import "./chunk-2ZD3YTVM.js";
|
|
46
49
|
import "./chunk-4BKXL7SM.js";
|
|
50
|
+
import "./chunk-ANYYM4CF.js";
|
|
47
51
|
import "./chunk-NHNWUBXB.js";
|
|
48
|
-
import "./chunk-
|
|
52
|
+
import "./chunk-KJLJPUY2.js";
|
|
49
53
|
import "./chunk-6VRJGH25.js";
|
|
50
|
-
import "./chunk-
|
|
51
|
-
import "./chunk-
|
|
54
|
+
import "./chunk-2DXY7UGF.js";
|
|
55
|
+
import "./chunk-KHYD3WXE.js";
|
|
56
|
+
import "./chunk-TKYNTXKB.js";
|
|
52
57
|
import {
|
|
53
58
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
54
59
|
AUTHOR,
|
|
@@ -67,10 +72,7 @@ import {
|
|
|
67
72
|
SKILLS_DIR_NAME,
|
|
68
73
|
VERSION,
|
|
69
74
|
buildUserIdentityPrompt
|
|
70
|
-
} from "./chunk-
|
|
71
|
-
import {
|
|
72
|
-
AuthManager
|
|
73
|
-
} from "./chunk-BYNY5JPB.js";
|
|
75
|
+
} from "./chunk-E7YC4GWV.js";
|
|
74
76
|
|
|
75
77
|
// src/web/server.ts
|
|
76
78
|
import express from "express";
|
|
@@ -1993,7 +1995,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
1993
1995
|
const root = process.cwd();
|
|
1994
1996
|
const { loadIndex, clearIndex } = await import("./store-S24SPPDZ.js");
|
|
1995
1997
|
const { indexProject } = await import("./indexer-C7QYYHSZ.js");
|
|
1996
|
-
const { loadVectorStore, clearVectorStore } = await import("./vector-store-
|
|
1998
|
+
const { loadVectorStore, clearVectorStore } = await import("./vector-store-QARQ2P6D.js");
|
|
1997
1999
|
if (sub === "status") {
|
|
1998
2000
|
const idx = loadIndex(root);
|
|
1999
2001
|
const vec = loadVectorStore(root);
|
|
@@ -2042,7 +2044,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
2042
2044
|
message: `Building semantic index for ${idx.symbolCount} symbols\u2026 (first run downloads ~117 MB model)`
|
|
2043
2045
|
});
|
|
2044
2046
|
try {
|
|
2045
|
-
const { rebuildSemanticIndex } = await import("./semantic-
|
|
2047
|
+
const { rebuildSemanticIndex } = await import("./semantic-YDRPPVWK.js");
|
|
2046
2048
|
const stats = await rebuildSemanticIndex(root);
|
|
2047
2049
|
const first = stats.modelFirstLoadMs ? ` (model load+first batch ${stats.modelFirstLoadMs}ms)` : "";
|
|
2048
2050
|
this.send({
|
|
@@ -2229,7 +2231,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
2229
2231
|
case "test": {
|
|
2230
2232
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
2231
2233
|
try {
|
|
2232
|
-
const { executeTests } = await import("./run-tests-
|
|
2234
|
+
const { executeTests } = await import("./run-tests-5TO5G3YH.js");
|
|
2233
2235
|
const argStr = args.join(" ").trim();
|
|
2234
2236
|
let testArgs = {};
|
|
2235
2237
|
if (argStr) {
|