jinzd-ai-cli 0.4.88 → 0.4.90
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-3MJ56YAA.js} +2 -2
- package/dist/chat-index-QKFH7ZP6.js +17 -0
- package/dist/chat-index-W2UZ34ZI.js +18 -0
- package/dist/{chunk-PFYAAX2S.js → chunk-2DXY7UGF.js} +16 -63
- package/dist/chunk-5S3PIG5O.js +453 -0
- package/dist/{chunk-QT2KNL3V.js → chunk-AB2LA33A.js} +1 -1
- package/dist/chunk-ANYYM4CF.js +460 -0
- package/dist/{chunk-P6EQZKKG.js → chunk-BJXGZFE6.js} +1 -1
- package/dist/{chunk-L3MBIO36.js → chunk-DJGP7AR6.js} +5 -106
- package/dist/{chunk-V3NMERIB.js → chunk-EEEAFWNK.js} +1 -1
- package/dist/{chunk-YDHIU24C.js → chunk-G65IDWVP.js} +76 -3
- package/dist/chunk-JV5N65KN.js +50 -0
- package/dist/chunk-KHYD3WXE.js +52 -0
- package/dist/{chunk-CQQQFNND.js → chunk-KJLJPUY2.js} +6 -4
- package/dist/{chunk-GTKJUEBS.js → chunk-MO7MWNWC.js} +6 -4
- package/dist/{chunk-XMA222FQ.js → chunk-PASCDYMH.js} +17 -63
- package/dist/{chunk-VGXNE37B.js → chunk-WPQ4D6T3.js} +1 -1
- package/dist/electron-server.js +187 -104
- package/dist/{hub-IR4INXSU.js → hub-B7NJSCWF.js} +1 -1
- package/dist/index.js +158 -19
- package/dist/{run-tests-FQHDUYOG.js → run-tests-2DYVHTIH.js} +2 -2
- package/dist/{run-tests-JVWIGY7P.js → run-tests-37FEBJTR.js} +1 -1
- package/dist/{semantic-MYAXLDCZ.js → semantic-3KJPAUW6.js} +3 -2
- package/dist/{semantic-ICJ536BG.js → semantic-YDRPPVWK.js} +3 -2
- package/dist/{server-UWKRV5DK.js → server-FCTPLKGO.js} +121 -13
- package/dist/{server-HTVVWKFN.js → server-S6JYNMMF.js} +7 -5
- package/dist/{task-orchestrator-6MI6LD7T.js → task-orchestrator-K6HDX4YE.js} +7 -5
- package/dist/{vector-store-UR7IARXB.js → vector-store-NDUFLNGN.js} +2 -1
- package/dist/{vector-store-YTVHACBV.js → vector-store-QARQ2P6D.js} +2 -1
- package/dist/web/client/app.js +201 -0
- package/dist/web/client/index.html +24 -0
- package/package.json +1 -1
package/dist/electron-server.js
CHANGED
|
@@ -36,15 +36,21 @@ import {
|
|
|
36
36
|
VERSION,
|
|
37
37
|
buildUserIdentityPrompt,
|
|
38
38
|
runTestsTool
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-BJXGZFE6.js";
|
|
40
40
|
import {
|
|
41
41
|
hasSemanticIndex,
|
|
42
42
|
semanticSearch
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-MO7MWNWC.js";
|
|
44
44
|
import {
|
|
45
45
|
loadIndex
|
|
46
46
|
} from "./chunk-BJAT4GNC.js";
|
|
47
|
-
import "./chunk-
|
|
47
|
+
import "./chunk-PASCDYMH.js";
|
|
48
|
+
import {
|
|
49
|
+
loadChatIndex,
|
|
50
|
+
redactJson,
|
|
51
|
+
searchChatMemory
|
|
52
|
+
} from "./chunk-5S3PIG5O.js";
|
|
53
|
+
import "./chunk-JV5N65KN.js";
|
|
48
54
|
|
|
49
55
|
// src/web/server.ts
|
|
50
56
|
import express from "express";
|
|
@@ -3054,104 +3060,6 @@ var Session = class _Session {
|
|
|
3054
3060
|
}
|
|
3055
3061
|
};
|
|
3056
3062
|
|
|
3057
|
-
// src/security/redactor.ts
|
|
3058
|
-
var DEFAULT_PATTERNS = [
|
|
3059
|
-
// password: xxx / password = xxx / password="xxx"
|
|
3060
|
-
// Covers YAML / JSON / shell-ish / env-file forms.
|
|
3061
|
-
{ kind: "password", regex: /\b(password|passwd|pwd)\s*[:=]\s*["']?([^\s"',;{}]{4,200})["']?/gi },
|
|
3062
|
-
// PGPASSWORD=xxx (explicit bash env-var form, separate rule because no quotes usually)
|
|
3063
|
-
{ kind: "pgpassword-env", regex: /\b(PGPASSWORD)=([^\s"']{4,200})/g },
|
|
3064
|
-
// JDBC/PG/MySQL/Mongo connection strings with inline credentials
|
|
3065
|
-
// postgresql://user:pass@host/db → redact pass
|
|
3066
|
-
{ kind: "db-uri-password", regex: /(\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp|mssql):\/\/[^:\s]+:)([^@\s]+)(@)/gi },
|
|
3067
|
-
// Anthropic API keys
|
|
3068
|
-
{ kind: "anthropic-key", regex: /(sk-ant-[a-zA-Z0-9_-]{90,})/g },
|
|
3069
|
-
// OpenAI / generic sk- keys — requires length ≥32 to avoid eating short identifiers
|
|
3070
|
-
{ kind: "openai-key", regex: /(sk-(?:proj-)?[a-zA-Z0-9_-]{32,})/g },
|
|
3071
|
-
// GitHub personal access tokens
|
|
3072
|
-
{ kind: "github-pat", regex: /\b(ghp_[a-zA-Z0-9]{36})\b/g },
|
|
3073
|
-
{ kind: "github-oauth", regex: /\b(gho_[a-zA-Z0-9]{36})\b/g },
|
|
3074
|
-
{ kind: "github-install", regex: /\b(ghs_[a-zA-Z0-9]{36})\b/g },
|
|
3075
|
-
// Slack tokens
|
|
3076
|
-
{ kind: "slack-bot", regex: /\b(xoxb-\d+-\d+-[a-zA-Z0-9]+)\b/g },
|
|
3077
|
-
{ kind: "slack-user", regex: /\b(xoxp-\d+-\d+-\d+-[a-zA-Z0-9]+)\b/g },
|
|
3078
|
-
// AWS access key IDs (AKIA...) and secret access keys are context-dependent;
|
|
3079
|
-
// we only catch the ID because secret key alone is indistinguishable from random base64.
|
|
3080
|
-
{ kind: "aws-access-key-id", regex: /\b(AKIA[0-9A-Z]{16})\b/g },
|
|
3081
|
-
// Google API keys
|
|
3082
|
-
{ kind: "google-api-key", regex: /\b(AIza[0-9A-Za-z_-]{35})\b/g },
|
|
3083
|
-
// Generic "api_key": "..." / "apiKey": "..." / api-key=xxx
|
|
3084
|
-
{ kind: "api-key", regex: /\b(api[_-]?key)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{16,200})["']?/gi },
|
|
3085
|
-
// Generic token: xxx (only when value looks token-shaped; avoids eating human prose)
|
|
3086
|
-
{ kind: "token", regex: /\b(token|access[_-]?token|bearer[_-]?token)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{20,300})["']?/gi },
|
|
3087
|
-
// Bearer <token> in Authorization headers
|
|
3088
|
-
{ kind: "bearer", regex: /\b(Authorization:\s*Bearer\s+)([a-zA-Z0-9_\-.=]{20,500})/g },
|
|
3089
|
-
// Private key PEM blocks — catch the header+footer together
|
|
3090
|
-
{ kind: "private-key", regex: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g }
|
|
3091
|
-
];
|
|
3092
|
-
function render(placeholder, kind) {
|
|
3093
|
-
return placeholder.replace("{kind}", kind);
|
|
3094
|
-
}
|
|
3095
|
-
function redactString(input, options) {
|
|
3096
|
-
if (!options.enabled || !input) return { redacted: input, hits: [] };
|
|
3097
|
-
const placeholder = options.placeholder ?? "[REDACTED:{kind}]";
|
|
3098
|
-
const patterns = [
|
|
3099
|
-
...options.patterns ?? DEFAULT_PATTERNS,
|
|
3100
|
-
...(options.customRegexes ?? []).flatMap((src, i) => {
|
|
3101
|
-
try {
|
|
3102
|
-
const flags = src.match(/^\/.*\/([gimsuy]*)$/)?.[1] ?? "";
|
|
3103
|
-
const body = src.replace(/^\/(.*)\/[gimsuy]*$/, "$1");
|
|
3104
|
-
const regex = new RegExp(body, flags.includes("g") ? flags : flags + "g");
|
|
3105
|
-
return [{ kind: `custom-${i}`, regex }];
|
|
3106
|
-
} catch {
|
|
3107
|
-
return [];
|
|
3108
|
-
}
|
|
3109
|
-
})
|
|
3110
|
-
];
|
|
3111
|
-
let redacted = input;
|
|
3112
|
-
const hits = [];
|
|
3113
|
-
for (const { kind, regex } of patterns) {
|
|
3114
|
-
const rx = new RegExp(regex.source, regex.flags);
|
|
3115
|
-
redacted = redacted.replace(rx, (...args) => {
|
|
3116
|
-
const match = args[0];
|
|
3117
|
-
const probe = new RegExp(rx.source).exec(match);
|
|
3118
|
-
const captureCount = probe ? probe.length - 1 : 0;
|
|
3119
|
-
const g1 = captureCount >= 1 ? args[1] : void 0;
|
|
3120
|
-
const g2 = captureCount >= 2 ? args[2] : void 0;
|
|
3121
|
-
const offset = args[1 + captureCount];
|
|
3122
|
-
if (captureCount >= 2 && typeof g2 === "string") {
|
|
3123
|
-
hits.push({ kind, start: offset + (g1?.length ?? 0), length: g2.length, secret: g2 });
|
|
3124
|
-
return `${g1}${render(placeholder, kind)}`;
|
|
3125
|
-
}
|
|
3126
|
-
hits.push({ kind, start: offset, length: match.length, secret: g1 ?? match });
|
|
3127
|
-
return render(placeholder, kind);
|
|
3128
|
-
});
|
|
3129
|
-
}
|
|
3130
|
-
return { redacted, hits };
|
|
3131
|
-
}
|
|
3132
|
-
function redactJson(value, options) {
|
|
3133
|
-
if (!options.enabled) return { value, hits: [] };
|
|
3134
|
-
const allHits = [];
|
|
3135
|
-
function walk(v) {
|
|
3136
|
-
if (typeof v === "string") {
|
|
3137
|
-
const r = redactString(v, options);
|
|
3138
|
-
allHits.push(...r.hits);
|
|
3139
|
-
return r.redacted;
|
|
3140
|
-
}
|
|
3141
|
-
if (Array.isArray(v)) return v.map(walk);
|
|
3142
|
-
if (v && typeof v === "object") {
|
|
3143
|
-
const out = {};
|
|
3144
|
-
for (const [k, vv] of Object.entries(v)) {
|
|
3145
|
-
out[k] = walk(vv);
|
|
3146
|
-
}
|
|
3147
|
-
return out;
|
|
3148
|
-
}
|
|
3149
|
-
return v;
|
|
3150
|
-
}
|
|
3151
|
-
const redacted = walk(value);
|
|
3152
|
-
return { value: redacted, hits: allHits };
|
|
3153
|
-
}
|
|
3154
|
-
|
|
3155
3063
|
// src/session/session-manager.ts
|
|
3156
3064
|
function safeDate(value) {
|
|
3157
3065
|
const d = new Date(value);
|
|
@@ -7856,6 +7764,74 @@ ${lines.join("\n")}`;
|
|
|
7856
7764
|
}
|
|
7857
7765
|
};
|
|
7858
7766
|
|
|
7767
|
+
// src/tools/builtin/recall-memory.ts
|
|
7768
|
+
function formatHit(h, i) {
|
|
7769
|
+
const ts = h.chunk.timestamp.slice(0, 16).replace("T", " ");
|
|
7770
|
+
const title = h.chunk.sessionTitle ? ` \xB7 ${h.chunk.sessionTitle}` : "";
|
|
7771
|
+
const sid = h.chunk.sessionId.slice(0, 8);
|
|
7772
|
+
const score = h.score.toFixed(3);
|
|
7773
|
+
const body = h.chunk.text.length > 600 ? h.chunk.text.slice(0, 600) + "\u2026" : h.chunk.text;
|
|
7774
|
+
return `\u2500\u2500\u2500 Hit ${i + 1} (score ${score}, session ${sid}${title}, ${ts}) \u2500\u2500\u2500
|
|
7775
|
+
` + body;
|
|
7776
|
+
}
|
|
7777
|
+
var recallMemoryTool = {
|
|
7778
|
+
definition: {
|
|
7779
|
+
name: "recall_memory",
|
|
7780
|
+
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".',
|
|
7781
|
+
parameters: {
|
|
7782
|
+
query: {
|
|
7783
|
+
type: "string",
|
|
7784
|
+
description: "Natural-language description of what to recall. Chinese or English both work.",
|
|
7785
|
+
required: true
|
|
7786
|
+
},
|
|
7787
|
+
topK: {
|
|
7788
|
+
type: "number",
|
|
7789
|
+
description: "Max number of snippets to return (default 5, max 20).",
|
|
7790
|
+
required: false
|
|
7791
|
+
},
|
|
7792
|
+
excludeCurrentSession: {
|
|
7793
|
+
type: "boolean",
|
|
7794
|
+
description: "If true, exclude the current session from results (avoid echoing what you just said). Default false.",
|
|
7795
|
+
required: false
|
|
7796
|
+
},
|
|
7797
|
+
currentSessionId: {
|
|
7798
|
+
type: "string",
|
|
7799
|
+
description: "Session ID to exclude when excludeCurrentSession=true. Usually the active session.",
|
|
7800
|
+
required: false
|
|
7801
|
+
},
|
|
7802
|
+
minScore: {
|
|
7803
|
+
type: "number",
|
|
7804
|
+
description: "Drop hits below this cosine score. Default 0.25. Raise to 0.35+ for stricter matches.",
|
|
7805
|
+
required: false
|
|
7806
|
+
}
|
|
7807
|
+
},
|
|
7808
|
+
dangerous: false
|
|
7809
|
+
},
|
|
7810
|
+
async execute(args) {
|
|
7811
|
+
const query = String(args["query"] ?? "").trim();
|
|
7812
|
+
if (!query) throw new ToolError("recall_memory", "query is required");
|
|
7813
|
+
const topK = Math.max(1, Math.min(20, Number(args["topK"] ?? 5)));
|
|
7814
|
+
const excludeCurrent = Boolean(args["excludeCurrentSession"]);
|
|
7815
|
+
const currentId = args["currentSessionId"] ? String(args["currentSessionId"]) : void 0;
|
|
7816
|
+
const minScore = args["minScore"] !== void 0 ? Number(args["minScore"]) : 0.25;
|
|
7817
|
+
const status = loadChatIndex();
|
|
7818
|
+
if (!status) {
|
|
7819
|
+
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.";
|
|
7820
|
+
}
|
|
7821
|
+
const hits = await searchChatMemory(query, {
|
|
7822
|
+
topK,
|
|
7823
|
+
minScore,
|
|
7824
|
+
excludeSessionId: excludeCurrent ? currentId : void 0
|
|
7825
|
+
});
|
|
7826
|
+
if (hits.length === 0) {
|
|
7827
|
+
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.`;
|
|
7828
|
+
}
|
|
7829
|
+
const header = `Found ${hits.length} memory hit(s) for "${query}" (min-score ${minScore}):
|
|
7830
|
+
`;
|
|
7831
|
+
return header + "\n" + hits.map(formatHit).join("\n\n");
|
|
7832
|
+
}
|
|
7833
|
+
};
|
|
7834
|
+
|
|
7859
7835
|
// src/core/token-estimator.ts
|
|
7860
7836
|
var CJK_REGEX = /[\u2E80-\u9FFF\uA000-\uA4FF\uAC00-\uD7FF\uF900-\uFAFF\uFE30-\uFE4F\uFF00-\uFFEF]/g;
|
|
7861
7837
|
function estimateTokens(text) {
|
|
@@ -7915,6 +7891,7 @@ var ToolRegistry = class {
|
|
|
7915
7891
|
this.register(getOutlineTool);
|
|
7916
7892
|
this.register(findReferencesTool);
|
|
7917
7893
|
this.register(searchCodeTool);
|
|
7894
|
+
this.register(recallMemoryTool);
|
|
7918
7895
|
}
|
|
7919
7896
|
register(tool) {
|
|
7920
7897
|
this.tools.set(tool.definition.name, tool);
|
|
@@ -9637,6 +9614,12 @@ var SessionHandler = class _SessionHandler {
|
|
|
9637
9614
|
}
|
|
9638
9615
|
return;
|
|
9639
9616
|
}
|
|
9617
|
+
case "memory_search":
|
|
9618
|
+
return this.handleMemorySearch(msg.query, msg.topK, msg.minScore, msg.excludeCurrentSession);
|
|
9619
|
+
case "memory_status_request":
|
|
9620
|
+
return this.handleMemoryStatus();
|
|
9621
|
+
case "memory_rebuild":
|
|
9622
|
+
return this.handleMemoryRebuild(Boolean(msg.full));
|
|
9640
9623
|
case "auto_pause_response": {
|
|
9641
9624
|
const resolve6 = this.pendingAutoPause.get(msg.requestId);
|
|
9642
9625
|
if (resolve6) {
|
|
@@ -11010,7 +10993,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11010
10993
|
const root = process.cwd();
|
|
11011
10994
|
const { loadIndex: loadIndex2, clearIndex } = await import("./store-247B3TAU.js");
|
|
11012
10995
|
const { indexProject: indexProject2 } = await import("./indexer-O5FCGFBJ.js");
|
|
11013
|
-
const { loadVectorStore, clearVectorStore } = await import("./vector-store-
|
|
10996
|
+
const { loadVectorStore, clearVectorStore } = await import("./vector-store-NDUFLNGN.js");
|
|
11014
10997
|
if (sub === "status") {
|
|
11015
10998
|
const idx = loadIndex2(root);
|
|
11016
10999
|
const vec = loadVectorStore(root);
|
|
@@ -11059,7 +11042,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11059
11042
|
message: `Building semantic index for ${idx.symbolCount} symbols\u2026 (first run downloads ~117 MB model)`
|
|
11060
11043
|
});
|
|
11061
11044
|
try {
|
|
11062
|
-
const { rebuildSemanticIndex } = await import("./semantic-
|
|
11045
|
+
const { rebuildSemanticIndex } = await import("./semantic-3KJPAUW6.js");
|
|
11063
11046
|
const stats = await rebuildSemanticIndex(root);
|
|
11064
11047
|
const first = stats.modelFirstLoadMs ? ` (model load+first batch ${stats.modelFirstLoadMs}ms)` : "";
|
|
11065
11048
|
this.send({
|
|
@@ -11246,7 +11229,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11246
11229
|
case "test": {
|
|
11247
11230
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
11248
11231
|
try {
|
|
11249
|
-
const { executeTests } = await import("./run-tests-
|
|
11232
|
+
const { executeTests } = await import("./run-tests-37FEBJTR.js");
|
|
11250
11233
|
const argStr = args.join(" ").trim();
|
|
11251
11234
|
let testArgs = {};
|
|
11252
11235
|
if (argStr) {
|
|
@@ -11760,6 +11743,106 @@ Add .md files to create commands.` });
|
|
|
11760
11743
|
this.send({ type: "error", message: `Failed to clear memory: ${err.message}` });
|
|
11761
11744
|
}
|
|
11762
11745
|
}
|
|
11746
|
+
// ── B4 chat memory recall (v0.4.90+) ──────────────────────────────
|
|
11747
|
+
// Lazy-imported so the 117 MB embedder stays out of the load path for
|
|
11748
|
+
// clients that never open the Memory panel.
|
|
11749
|
+
async handleMemorySearch(query, topK, minScore, excludeCurrent) {
|
|
11750
|
+
const q = (query ?? "").trim();
|
|
11751
|
+
if (!q) {
|
|
11752
|
+
this.send({ type: "error", message: "Memory search: query is empty." });
|
|
11753
|
+
return;
|
|
11754
|
+
}
|
|
11755
|
+
try {
|
|
11756
|
+
const { searchChatMemory: searchChatMemory2, loadChatIndex: loadChatIndex2 } = await import("./chat-index-QKFH7ZP6.js");
|
|
11757
|
+
const loaded = loadChatIndex2();
|
|
11758
|
+
if (!loaded || loaded.idx.chunks.length === 0) {
|
|
11759
|
+
this.send({ type: "memory_hits", query: q, hits: [], indexMissing: true });
|
|
11760
|
+
return;
|
|
11761
|
+
}
|
|
11762
|
+
const hits = await searchChatMemory2(q, {
|
|
11763
|
+
topK: topK ?? 8,
|
|
11764
|
+
minScore: minScore ?? 0.2,
|
|
11765
|
+
excludeSessionId: excludeCurrent ? this.sessions.current?.id : void 0
|
|
11766
|
+
});
|
|
11767
|
+
this.send({
|
|
11768
|
+
type: "memory_hits",
|
|
11769
|
+
query: q,
|
|
11770
|
+
hits: hits.map((h) => ({
|
|
11771
|
+
id: h.chunk.id,
|
|
11772
|
+
sessionId: h.chunk.sessionId,
|
|
11773
|
+
sessionTitle: h.chunk.sessionTitle,
|
|
11774
|
+
provider: h.chunk.provider,
|
|
11775
|
+
model: h.chunk.model,
|
|
11776
|
+
timestamp: h.chunk.timestamp,
|
|
11777
|
+
score: h.score,
|
|
11778
|
+
text: h.chunk.text,
|
|
11779
|
+
startMessageIdx: h.chunk.startMessageIdx,
|
|
11780
|
+
endMessageIdx: h.chunk.endMessageIdx
|
|
11781
|
+
}))
|
|
11782
|
+
});
|
|
11783
|
+
} catch (err) {
|
|
11784
|
+
this.send({
|
|
11785
|
+
type: "error",
|
|
11786
|
+
message: `Memory search failed: ${err instanceof Error ? err.message : String(err)}`
|
|
11787
|
+
});
|
|
11788
|
+
}
|
|
11789
|
+
}
|
|
11790
|
+
async handleMemoryStatus() {
|
|
11791
|
+
try {
|
|
11792
|
+
const { getChatIndexStatus } = await import("./chat-index-QKFH7ZP6.js");
|
|
11793
|
+
const s = getChatIndexStatus();
|
|
11794
|
+
this.send({
|
|
11795
|
+
type: "memory_status",
|
|
11796
|
+
exists: s.exists,
|
|
11797
|
+
chunks: s.chunks,
|
|
11798
|
+
sessions: s.sessions,
|
|
11799
|
+
built: s.built,
|
|
11800
|
+
model: s.model,
|
|
11801
|
+
vecFileSizeBytes: s.vecFileSizeBytes,
|
|
11802
|
+
chunksFileSizeBytes: s.chunksFileSizeBytes
|
|
11803
|
+
});
|
|
11804
|
+
} catch (err) {
|
|
11805
|
+
this.send({
|
|
11806
|
+
type: "error",
|
|
11807
|
+
message: `Memory status failed: ${err instanceof Error ? err.message : String(err)}`
|
|
11808
|
+
});
|
|
11809
|
+
}
|
|
11810
|
+
}
|
|
11811
|
+
async handleMemoryRebuild(full) {
|
|
11812
|
+
try {
|
|
11813
|
+
this.send({
|
|
11814
|
+
type: "info",
|
|
11815
|
+
message: full ? "\u{1F9E0} Rebuilding chat memory index (this may take a while on first run \u2014 ~117 MB embedder)." : "\u{1F9E0} Refreshing chat memory index (incremental)\u2026"
|
|
11816
|
+
});
|
|
11817
|
+
const { buildChatIndex } = await import("./chat-index-QKFH7ZP6.js");
|
|
11818
|
+
const stats = await buildChatIndex({
|
|
11819
|
+
full,
|
|
11820
|
+
onProgress: (p) => {
|
|
11821
|
+
this.send({
|
|
11822
|
+
type: "memory_rebuild_progress",
|
|
11823
|
+
stage: p.stage,
|
|
11824
|
+
processed: p.processed,
|
|
11825
|
+
total: p.total
|
|
11826
|
+
});
|
|
11827
|
+
}
|
|
11828
|
+
});
|
|
11829
|
+
this.send({
|
|
11830
|
+
type: "memory_rebuild_done",
|
|
11831
|
+
chunksTotal: stats.chunksTotal,
|
|
11832
|
+
chunksAdded: stats.chunksAdded,
|
|
11833
|
+
chunksRemoved: stats.chunksRemoved,
|
|
11834
|
+
sessionsIndexed: stats.sessionsIndexed,
|
|
11835
|
+
sessionsSkipped: stats.sessionsSkipped,
|
|
11836
|
+
durationMs: stats.durationMs
|
|
11837
|
+
});
|
|
11838
|
+
await this.handleMemoryStatus();
|
|
11839
|
+
} catch (err) {
|
|
11840
|
+
this.send({
|
|
11841
|
+
type: "error",
|
|
11842
|
+
message: `Memory rebuild failed: ${err instanceof Error ? err.message : String(err)}`
|
|
11843
|
+
});
|
|
11844
|
+
}
|
|
11845
|
+
}
|
|
11763
11846
|
sendSessionMessages() {
|
|
11764
11847
|
const session = this.sessions.current;
|
|
11765
11848
|
if (!session) return;
|
|
@@ -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-K6HDX4YE.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-DJGP7AR6.js";
|
|
36
34
|
import {
|
|
37
35
|
ConfigManager
|
|
38
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-AB2LA33A.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-G65IDWVP.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-EEEAFWNK.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-WPQ4D6T3.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-2DYVHTIH.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-FCTPLKGO.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-3MJ56YAA.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-S6JYNMMF.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-B7NJSCWF.js");
|
|
6873
7012
|
await startHub(
|
|
6874
7013
|
{
|
|
6875
7014
|
topic: topic ?? "",
|