jinzd-ai-cli 0.4.245 → 0.4.247
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 +8 -3
- package/README.zh-CN.md +8 -3
- package/dist/{batch-MRP2KUFC.js → batch-UE7XQMQB.js} +2 -2
- package/dist/{chat-index-ALUHFJKI.js → chat-index-7MMTGQNA.js} +2 -2
- package/dist/{chat-index-ML5FF5L6.js → chat-index-Q6BKWWAM.js} +1 -1
- package/dist/{chunk-JM2DX7OY.js → chunk-3IIKIWT2.js} +1 -1
- package/dist/{chunk-H3PEWUFY.js → chunk-3IM53IFO.js} +1 -1
- package/dist/{chunk-UM2OVVLP.js → chunk-4EZWVX7G.js} +1 -1
- package/dist/{chunk-WKXADWWK.js → chunk-4GKWLTU3.js} +4 -4
- package/dist/{chunk-KEAUVMKS.js → chunk-6Q2XAWKP.js} +1 -1
- package/dist/{chunk-IGPFYNZA.js → chunk-6RPGQ5CG.js} +1 -1
- package/dist/{chunk-K3CF65QH.js → chunk-GLSR2NR3.js} +1 -1
- package/dist/{chunk-WWHTQHIN.js → chunk-IP7LPVRW.js} +1 -1
- package/dist/{chunk-DT77O33T.js → chunk-JQXXPTWL.js} +1 -1
- package/dist/{chunk-XYXVTHOB.js → chunk-KPRU6QY3.js} +4 -5
- package/dist/{chunk-PJ3ONBWZ.js → chunk-NYNSYLFY.js} +1 -1
- package/dist/{chunk-KWQKQVPH.js → chunk-OBULDJSU.js} +1 -1
- package/dist/{chunk-A4MLBB4H.js → chunk-Q2OMGJIQ.js} +28 -15
- package/dist/{chunk-BNERFXVO.js → chunk-QCG6UU2S.js} +1 -1
- package/dist/{chunk-O357YW7E.js → chunk-REBKFMF3.js} +1 -1
- package/dist/{chunk-4UIVLJAP.js → chunk-RZV6WSER.js} +1 -1
- package/dist/{chunk-QYQI7ZWK.js → chunk-S7ZS7X23.js} +0 -1
- package/dist/{chunk-XH4JPEIZ.js → chunk-TBXMRJHS.js} +1 -1
- package/dist/{chunk-Y6KDBGY7.js → chunk-VN6OGMSV.js} +1 -1
- package/dist/{chunk-M7BQVFMF.js → chunk-VPM5WRJ2.js} +4 -4
- package/dist/{chunk-NV63EYFL.js → chunk-ZWEZNKDW.js} +1 -1
- package/dist/{ci-Q3LQQT7K.js → ci-EY6USUO7.js} +5 -5
- package/dist/{ci-format-L2WPVFFC.js → ci-format-CZNUUWEV.js} +2 -2
- package/dist/{constants-DTPJHB6W.js → constants-UDRMWAPN.js} +1 -1
- package/dist/{doctor-cli-AEVPW6VY.js → doctor-cli-GY654USP.js} +5 -5
- package/dist/electron-server.js +170 -139
- package/dist/{hub-PPNKIMPG.js → hub-L2WX4255.js} +2 -2
- package/dist/index.js +29 -30
- package/dist/{indexer-4WWS3VIL.js → indexer-M2LJGTY2.js} +1 -1
- package/dist/{indexer-2AG4G6B5.js → indexer-VZETNE4H.js} +1 -1
- package/dist/{persist-WGIJ6RXY.js → persist-A2QSXYFY.js} +3 -3
- package/dist/{persistent-memory-YLB2ZSB2.js → persistent-memory-G24RJ5LA.js} +2 -2
- package/dist/{persistent-memory-ZIC4UA2W.js → persistent-memory-JCX3P2CF.js} +2 -2
- package/dist/{pr-Z3NX3SG5.js → pr-B5P2M6DV.js} +5 -5
- package/dist/{run-tests-WW6VCT23.js → run-tests-N2JQGL4C.js} +2 -2
- package/dist/{run-tests-42DWRQAR.js → run-tests-QEIR322E.js} +2 -2
- package/dist/{server-KX6WKW6V.js → server-4OAE6OEK.js} +8 -8
- package/dist/{server-NNDBF3SH.js → server-QDMMCD3O.js} +112 -92
- package/dist/{task-orchestrator-DEDL6YAZ.js → task-orchestrator-VZXU2HK3.js} +8 -9
- package/dist/{usage-QAMWSX52.js → usage-LH3LNYAS.js} +2 -2
- package/package.json +5 -4
package/dist/electron-server.js
CHANGED
|
@@ -7,13 +7,13 @@ import {
|
|
|
7
7
|
searchCandidates,
|
|
8
8
|
searchChatMemory,
|
|
9
9
|
updateSessionInIndex
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-ZWEZNKDW.js";
|
|
11
11
|
import {
|
|
12
12
|
fileCheckpoints
|
|
13
13
|
} from "./chunk-SKET65WZ.js";
|
|
14
14
|
import {
|
|
15
15
|
indexProject
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-QCG6UU2S.js";
|
|
17
17
|
import {
|
|
18
18
|
addMemoryEntry,
|
|
19
19
|
clearMemoryEntries,
|
|
@@ -34,14 +34,14 @@ import {
|
|
|
34
34
|
touchMemoryReferences,
|
|
35
35
|
updateMemoryApproval,
|
|
36
36
|
updateMemoryEntry
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-REBKFMF3.js";
|
|
38
38
|
import {
|
|
39
39
|
redactJson,
|
|
40
40
|
scanString
|
|
41
41
|
} from "./chunk-YVTASHS5.js";
|
|
42
42
|
import {
|
|
43
43
|
runTestsTool
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-IP7LPVRW.js";
|
|
45
45
|
import {
|
|
46
46
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
47
47
|
APP_NAME,
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
SUBAGENT_MAX_ROUNDS_LIMIT,
|
|
74
74
|
VERSION,
|
|
75
75
|
buildUserIdentityPrompt
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-4EZWVX7G.js";
|
|
77
77
|
import {
|
|
78
78
|
hasSemanticIndex,
|
|
79
79
|
semanticSearch
|
|
@@ -91,8 +91,8 @@ import {
|
|
|
91
91
|
import express from "express";
|
|
92
92
|
import { createServer } from "http";
|
|
93
93
|
import { WebSocketServer } from "ws";
|
|
94
|
-
import { join as
|
|
95
|
-
import { existsSync as
|
|
94
|
+
import { join as join25, dirname as dirname10, resolve as resolve10, relative as relative6, sep as sep4 } from "path";
|
|
95
|
+
import { existsSync as existsSync30, readFileSync as readFileSync23, readdirSync as readdirSync15, statSync as statSync13, realpathSync as realpathSync3 } from "fs";
|
|
96
96
|
import { networkInterfaces } from "os";
|
|
97
97
|
|
|
98
98
|
// src/config/config-manager.ts
|
|
@@ -2982,7 +2982,6 @@ var OpenAICompatibleProvider = class extends BaseProvider {
|
|
|
2982
2982
|
const message = firstChoice.message;
|
|
2983
2983
|
const finishReason = firstChoice.finish_reason;
|
|
2984
2984
|
const usage = toUsage(response.usage);
|
|
2985
|
-
const contentStr = typeof message.content === "string" ? message.content : "";
|
|
2986
2985
|
const hasToolCalls = !!(message.tool_calls && message.tool_calls.length > 0);
|
|
2987
2986
|
const reasoningContent = message.reasoning_content;
|
|
2988
2987
|
if (message.tool_calls && message.tool_calls.length > 0) {
|
|
@@ -4996,7 +4995,7 @@ async function execInPool(sessionKey, command, timeout, cwd, abortSignal) {
|
|
|
4996
4995
|
const markerStart = `AICLI_MARKER_START:${id}`;
|
|
4997
4996
|
const markerEnd = `AICLI_MARKER_END:${id}`;
|
|
4998
4997
|
const wrappedCmd = IS_WINDOWS2 ? `${WIN_UTF8_PREAMBLE} echo "${markerStart}"; ${command}; echo "${markerEnd}:0"` : `echo "${markerStart}"; ${command}; echo "${markerEnd}:$?"`;
|
|
4999
|
-
return new Promise((
|
|
4998
|
+
return new Promise((resolve11) => {
|
|
5000
4999
|
let stdout = "";
|
|
5001
5000
|
let stderr = "";
|
|
5002
5001
|
let timedOut = false;
|
|
@@ -5008,11 +5007,11 @@ async function execInPool(sessionKey, command, timeout, cwd, abortSignal) {
|
|
|
5008
5007
|
stdout += IS_WINDOWS2 ? decodeWindowsBuffer(chunk) : chunk.toString("utf-8");
|
|
5009
5008
|
if (!resolved && stdout.includes(markerEndPattern)) {
|
|
5010
5009
|
const endLine = stdout.split("\n").find((l) => l.includes(markerEndPattern));
|
|
5011
|
-
const exitCode = endLine ? parseEndMarker(endLine
|
|
5010
|
+
const exitCode = endLine ? parseEndMarker(endLine) : null;
|
|
5012
5011
|
stdout = stripMarkerOutput(stdout, markerStartPattern, markerEndPattern);
|
|
5013
5012
|
resolved = true;
|
|
5014
5013
|
cleanup();
|
|
5015
|
-
|
|
5014
|
+
resolve11({ stdout, stderr, exitCode, timedOut, aborted });
|
|
5016
5015
|
}
|
|
5017
5016
|
};
|
|
5018
5017
|
const onErr = (chunk) => {
|
|
@@ -5027,7 +5026,7 @@ async function execInPool(sessionKey, command, timeout, cwd, abortSignal) {
|
|
|
5027
5026
|
resolved = true;
|
|
5028
5027
|
stdout = stripMarkerOutput(stdout, markerStartPattern, markerEndPattern);
|
|
5029
5028
|
cleanup();
|
|
5030
|
-
|
|
5029
|
+
resolve11({ stdout, stderr, exitCode: null, timedOut, aborted });
|
|
5031
5030
|
killProcessTree(proc);
|
|
5032
5031
|
pool.delete(sessionKey);
|
|
5033
5032
|
}, timeout);
|
|
@@ -5037,7 +5036,7 @@ async function execInPool(sessionKey, command, timeout, cwd, abortSignal) {
|
|
|
5037
5036
|
resolved = true;
|
|
5038
5037
|
cleanup();
|
|
5039
5038
|
stdout = stripMarkerOutput(stdout, markerStartPattern, markerEndPattern);
|
|
5040
|
-
|
|
5039
|
+
resolve11({ stdout, stderr, exitCode: null, timedOut, aborted });
|
|
5041
5040
|
killProcessTree(proc);
|
|
5042
5041
|
pool.delete(sessionKey);
|
|
5043
5042
|
};
|
|
@@ -5052,7 +5051,7 @@ async function execInPool(sessionKey, command, timeout, cwd, abortSignal) {
|
|
|
5052
5051
|
stderr += `
|
|
5053
5052
|
[pool error] ${err.message}`;
|
|
5054
5053
|
cleanup();
|
|
5055
|
-
|
|
5054
|
+
resolve11({ stdout, stderr, exitCode: null, timedOut, aborted });
|
|
5056
5055
|
pool.delete(sessionKey);
|
|
5057
5056
|
};
|
|
5058
5057
|
proc.on("error", onError);
|
|
@@ -5065,7 +5064,7 @@ async function execInPool(sessionKey, command, timeout, cwd, abortSignal) {
|
|
|
5065
5064
|
}
|
|
5066
5065
|
try {
|
|
5067
5066
|
proc.stdin?.write(wrappedCmd + "\n");
|
|
5068
|
-
} catch
|
|
5067
|
+
} catch {
|
|
5069
5068
|
if (!resolved) {
|
|
5070
5069
|
cleanup();
|
|
5071
5070
|
pool.delete(sessionKey);
|
|
@@ -5073,7 +5072,7 @@ async function execInPool(sessionKey, command, timeout, cwd, abortSignal) {
|
|
|
5073
5072
|
}
|
|
5074
5073
|
});
|
|
5075
5074
|
}
|
|
5076
|
-
function parseEndMarker(line
|
|
5075
|
+
function parseEndMarker(line) {
|
|
5077
5076
|
const idx = line.lastIndexOf(":");
|
|
5078
5077
|
if (idx < 0) return null;
|
|
5079
5078
|
const code = line.slice(idx + 1).trim();
|
|
@@ -5243,7 +5242,7 @@ Important rules:
|
|
|
5243
5242
|
}
|
|
5244
5243
|
if (timedOut) {
|
|
5245
5244
|
pushBashUndoEntries(beforeSnapshot, parsedTargetsBefore, effectiveCwd);
|
|
5246
|
-
throw new ToolError("bash", formatTimeoutMessage(timeout, MAX_TIMEOUT));
|
|
5245
|
+
throw new ToolError("bash", formatTimeoutMessage(timeout, MAX_TIMEOUT, command));
|
|
5247
5246
|
}
|
|
5248
5247
|
if (status !== 0 || timedOut) {
|
|
5249
5248
|
const poolStdout = (stdout ?? "").trim();
|
|
@@ -5306,7 +5305,7 @@ ${combined || formatFailureFallback(status)}
|
|
|
5306
5305
|
const execErr = err;
|
|
5307
5306
|
const isTimeout = execErr.code === "ETIMEDOUT" || execErr.status == null && execErr.signal === "SIGTERM" || /ETIMEDOUT/i.test(execErr.message ?? "");
|
|
5308
5307
|
if (isTimeout) {
|
|
5309
|
-
throw new ToolError("bash", formatTimeoutMessage(timeout, MAX_TIMEOUT));
|
|
5308
|
+
throw new ToolError("bash", formatTimeoutMessage(timeout, MAX_TIMEOUT, command));
|
|
5310
5309
|
}
|
|
5311
5310
|
if ("status" in execErr && execErr.status !== void 0) {
|
|
5312
5311
|
const stderr = IS_WINDOWS3 && Buffer.isBuffer(execErr.stderr) ? decodeWindowsBuffer(execErr.stderr).trim() : execErr.stderr?.toString().trim() ?? "";
|
|
@@ -5331,11 +5330,24 @@ ${combined || execErr.message || formatFailureFallback(execErr.status)}
|
|
|
5331
5330
|
function formatFailureHeader(status) {
|
|
5332
5331
|
return typeof status === "number" ? `Exit code ${status}:` : "Command failed before exit code could be determined:";
|
|
5333
5332
|
}
|
|
5334
|
-
function
|
|
5333
|
+
function looksLikeTestCommand(command) {
|
|
5334
|
+
return (
|
|
5335
|
+
// jest / vitest / mocha / pytest(可带 npx/yarn/pnpm 前缀,或跟在 cd xxx; 之后)
|
|
5336
|
+
/(?:^|[;&|(\s])(?:npx\s+|yarn\s+(?:run\s+)?|pnpm\s+(?:run\s+|exec\s+)?)?(?:jest|vitest|mocha|pytest)\b/.test(command) || // npm test / npm run test:xxx / yarn test / pnpm test
|
|
5337
|
+
/(?:^|[;&|(\s])(?:npm|yarn|pnpm)\s+(?:run\s+)?test\b/.test(command) || // go test / cargo test
|
|
5338
|
+
/(?:^|[;&|(\s])(?:go|cargo)\s+test\b/.test(command)
|
|
5339
|
+
);
|
|
5340
|
+
}
|
|
5341
|
+
function formatTimeoutMessage(timeout, maxTimeout, command) {
|
|
5335
5342
|
const seconds = Math.round(timeout / 1e3);
|
|
5343
|
+
const testRunnerHint = command !== void 0 && looksLikeTestCommand(command) ? [
|
|
5344
|
+
"This looks like a TEST run. Prefer the 'run_tests' tool instead of running the test runner through bash: it has a 5-minute timeout, auto-detects the framework, and returns a structured summary (no findstr/grep filtering needed).",
|
|
5345
|
+
""
|
|
5346
|
+
] : [];
|
|
5336
5347
|
return [
|
|
5337
5348
|
`Command timed out after ${seconds}s.`,
|
|
5338
5349
|
"",
|
|
5350
|
+
...testRunnerHint,
|
|
5339
5351
|
"The previous command ran for longer than the timeout limit and was killed. This usually means it is scanning a large filesystem tree (recursive Get-ChildItem / find), compressing a big archive, or waiting on a network request.",
|
|
5340
5352
|
"",
|
|
5341
5353
|
"How to recover (pick ONE \u2014 do NOT retry the same command):",
|
|
@@ -7197,7 +7209,7 @@ var ToolExecutor = class {
|
|
|
7197
7209
|
};
|
|
7198
7210
|
}
|
|
7199
7211
|
if (permission.action === "auto-approve" && networkPermission?.action !== "confirm") {
|
|
7200
|
-
this.printToolCall(call);
|
|
7212
|
+
if (!toolCallAlreadyPrinted) this.printToolCall(call);
|
|
7201
7213
|
try {
|
|
7202
7214
|
const rawContent = await runTool(tool, call.arguments, call.name);
|
|
7203
7215
|
const content = truncateOutput(rawContent, call.name);
|
|
@@ -7428,7 +7440,7 @@ var ToolExecutor = class {
|
|
|
7428
7440
|
rl.resume();
|
|
7429
7441
|
process.stdout.write(prompt);
|
|
7430
7442
|
this.confirming = true;
|
|
7431
|
-
return new Promise((
|
|
7443
|
+
return new Promise((resolve11) => {
|
|
7432
7444
|
let completed = false;
|
|
7433
7445
|
const cleanup = (result) => {
|
|
7434
7446
|
if (completed) return;
|
|
@@ -7438,7 +7450,7 @@ var ToolExecutor = class {
|
|
|
7438
7450
|
rl.pause();
|
|
7439
7451
|
rlAny.output = savedOutput;
|
|
7440
7452
|
this.confirming = false;
|
|
7441
|
-
|
|
7453
|
+
resolve11(result);
|
|
7442
7454
|
};
|
|
7443
7455
|
const onLine = (line) => {
|
|
7444
7456
|
const trimmed = line.trim();
|
|
@@ -7612,7 +7624,7 @@ var ToolExecutor = class {
|
|
|
7612
7624
|
rl.resume();
|
|
7613
7625
|
process.stdout.write(color("Proceed? [y/N] (type y + Enter to confirm) "));
|
|
7614
7626
|
this.confirming = true;
|
|
7615
|
-
return new Promise((
|
|
7627
|
+
return new Promise((resolve11) => {
|
|
7616
7628
|
let completed = false;
|
|
7617
7629
|
const cleanup = (answer) => {
|
|
7618
7630
|
if (completed) return;
|
|
@@ -7622,7 +7634,7 @@ var ToolExecutor = class {
|
|
|
7622
7634
|
rl.pause();
|
|
7623
7635
|
rlAny.output = savedOutput;
|
|
7624
7636
|
this.confirming = false;
|
|
7625
|
-
|
|
7637
|
+
resolve11(answer === "y");
|
|
7626
7638
|
};
|
|
7627
7639
|
const onLine = (line) => {
|
|
7628
7640
|
const trimmed = line.trim();
|
|
@@ -7803,7 +7815,7 @@ Do NOT split a long document into many write_file(append=true) calls. That patte
|
|
|
7803
7815
|
const mode = appendMode ? "appended" : "written";
|
|
7804
7816
|
void (async () => {
|
|
7805
7817
|
try {
|
|
7806
|
-
const { updateFile } = await import("./indexer-
|
|
7818
|
+
const { updateFile } = await import("./indexer-M2LJGTY2.js");
|
|
7807
7819
|
await updateFile(process.cwd(), filePath);
|
|
7808
7820
|
} catch {
|
|
7809
7821
|
}
|
|
@@ -8871,7 +8883,7 @@ var runInteractiveTool = {
|
|
|
8871
8883
|
PYTHONDONTWRITEBYTECODE: "1"
|
|
8872
8884
|
};
|
|
8873
8885
|
const prefixWarnings = [argsTypeWarning, stdinTypeWarning].filter(Boolean).join("");
|
|
8874
|
-
return new Promise((
|
|
8886
|
+
return new Promise((resolve11) => {
|
|
8875
8887
|
const child = spawn4(executable, cmdArgs.map(String), {
|
|
8876
8888
|
cwd: process.cwd(),
|
|
8877
8889
|
env,
|
|
@@ -8904,22 +8916,22 @@ var runInteractiveTool = {
|
|
|
8904
8916
|
setTimeout(writeNextLine, 400);
|
|
8905
8917
|
const timer = setTimeout(() => {
|
|
8906
8918
|
child.kill();
|
|
8907
|
-
|
|
8919
|
+
resolve11(`${prefixWarnings}[Timeout after ${timeout}ms]
|
|
8908
8920
|
${buildOutput(stdout, stderr)}`);
|
|
8909
8921
|
}, timeout);
|
|
8910
8922
|
child.on("close", (code) => {
|
|
8911
8923
|
clearTimeout(timer);
|
|
8912
8924
|
const output = buildOutput(stdout, stderr);
|
|
8913
8925
|
if (code !== 0 && code !== null) {
|
|
8914
|
-
|
|
8926
|
+
resolve11(`${prefixWarnings}Exit code ${code}:
|
|
8915
8927
|
${output}`);
|
|
8916
8928
|
} else {
|
|
8917
|
-
|
|
8929
|
+
resolve11(`${prefixWarnings}${output || "(no output)"}`);
|
|
8918
8930
|
}
|
|
8919
8931
|
});
|
|
8920
8932
|
child.on("error", (err) => {
|
|
8921
8933
|
clearTimeout(timer);
|
|
8922
|
-
|
|
8934
|
+
resolve11(
|
|
8923
8935
|
`${prefixWarnings}Failed to start process "${executable}": ${err.message}
|
|
8924
8936
|
Hint: On Windows, use the full path to the executable, e.g.:
|
|
8925
8937
|
C:\\Users\\Jinzd\\anaconda3\\envs\\python312\\python.exe`
|
|
@@ -9222,7 +9234,7 @@ var webFetchTool = {
|
|
|
9222
9234
|
} else {
|
|
9223
9235
|
const title = extractTitle(rawHtml);
|
|
9224
9236
|
const desc = extractDescription(rawHtml);
|
|
9225
|
-
|
|
9237
|
+
const body = htmlToText(rawHtml);
|
|
9226
9238
|
const header = [
|
|
9227
9239
|
title ? `# ${title}` : "",
|
|
9228
9240
|
desc ? `> ${desc}` : "",
|
|
@@ -9741,7 +9753,7 @@ function promptUser(rl, question) {
|
|
|
9741
9753
|
console.log();
|
|
9742
9754
|
console.log(chalk4.cyan("\u2753 ") + chalk4.bold(question));
|
|
9743
9755
|
process.stdout.write(chalk4.cyan("> "));
|
|
9744
|
-
return new Promise((
|
|
9756
|
+
return new Promise((resolve11) => {
|
|
9745
9757
|
let completed = false;
|
|
9746
9758
|
const cleanup = (answer) => {
|
|
9747
9759
|
if (completed) return;
|
|
@@ -9751,7 +9763,7 @@ function promptUser(rl, question) {
|
|
|
9751
9763
|
rl.pause();
|
|
9752
9764
|
rlAny.output = savedOutput;
|
|
9753
9765
|
askUserContext.prompting = false;
|
|
9754
|
-
|
|
9766
|
+
resolve11(answer);
|
|
9755
9767
|
};
|
|
9756
9768
|
const onLine = (line) => {
|
|
9757
9769
|
cleanup(line);
|
|
@@ -12307,7 +12319,7 @@ var McpClient = class {
|
|
|
12307
12319
|
// 内部方法:JSON-RPC 通信
|
|
12308
12320
|
// ══════════════════════════════════════════════════════════════════
|
|
12309
12321
|
sendRequest(method, params) {
|
|
12310
|
-
return new Promise((
|
|
12322
|
+
return new Promise((resolve11, reject) => {
|
|
12311
12323
|
if (!this.process?.stdin?.writable) {
|
|
12312
12324
|
return reject(new Error(`MCP server [${this.serverId}] stdin not writable`));
|
|
12313
12325
|
}
|
|
@@ -12319,19 +12331,18 @@ var McpClient = class {
|
|
|
12319
12331
|
method,
|
|
12320
12332
|
...params !== void 0 ? { params } : {}
|
|
12321
12333
|
};
|
|
12322
|
-
let timer;
|
|
12323
12334
|
const cleanup = () => {
|
|
12324
12335
|
this.pendingRequests.delete(id);
|
|
12325
12336
|
clearTimeout(timer);
|
|
12326
12337
|
};
|
|
12327
|
-
timer = setTimeout(() => {
|
|
12338
|
+
const timer = setTimeout(() => {
|
|
12328
12339
|
cleanup();
|
|
12329
12340
|
reject(new Error(`MCP request [${method}] timed out (internal)`));
|
|
12330
12341
|
}, MCP_CALL_TIMEOUT * 2);
|
|
12331
12342
|
this.pendingRequests.set(id, {
|
|
12332
12343
|
resolve: (result) => {
|
|
12333
12344
|
cleanup();
|
|
12334
|
-
|
|
12345
|
+
resolve11(result);
|
|
12335
12346
|
},
|
|
12336
12347
|
reject: (error) => {
|
|
12337
12348
|
cleanup();
|
|
@@ -12408,13 +12419,13 @@ var McpClient = class {
|
|
|
12408
12419
|
}
|
|
12409
12420
|
/** Promise 超时包装 */
|
|
12410
12421
|
withTimeout(promise, ms, label) {
|
|
12411
|
-
return new Promise((
|
|
12422
|
+
return new Promise((resolve11, reject) => {
|
|
12412
12423
|
const timer = setTimeout(() => {
|
|
12413
12424
|
reject(new Error(`MCP [${this.serverId}] ${label} timed out after ${ms}ms`));
|
|
12414
12425
|
}, ms);
|
|
12415
12426
|
promise.then((val) => {
|
|
12416
12427
|
clearTimeout(timer);
|
|
12417
|
-
|
|
12428
|
+
resolve11(val);
|
|
12418
12429
|
}).catch((err) => {
|
|
12419
12430
|
clearTimeout(timer);
|
|
12420
12431
|
reject(err);
|
|
@@ -12918,33 +12929,33 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
12918
12929
|
}
|
|
12919
12930
|
/** Resolve a pending confirm from client response */
|
|
12920
12931
|
resolveConfirm(requestId, approved) {
|
|
12921
|
-
const
|
|
12922
|
-
if (
|
|
12932
|
+
const resolve11 = this.pendingConfirms.get(requestId);
|
|
12933
|
+
if (resolve11) {
|
|
12923
12934
|
this.clearPendingTimer(requestId);
|
|
12924
12935
|
this.pendingConfirms.delete(requestId);
|
|
12925
12936
|
this.confirming = false;
|
|
12926
|
-
|
|
12937
|
+
resolve11(approved);
|
|
12927
12938
|
}
|
|
12928
12939
|
}
|
|
12929
12940
|
/** Resolve a pending batch confirm from client response */
|
|
12930
12941
|
resolveBatchConfirm(requestId, decision) {
|
|
12931
|
-
const
|
|
12932
|
-
if (
|
|
12942
|
+
const resolve11 = this.pendingBatchConfirms.get(requestId);
|
|
12943
|
+
if (resolve11) {
|
|
12933
12944
|
this.clearPendingTimer(requestId);
|
|
12934
12945
|
this.pendingBatchConfirms.delete(requestId);
|
|
12935
12946
|
this.confirming = false;
|
|
12936
12947
|
if (decision === "all" || decision === "none") {
|
|
12937
|
-
|
|
12948
|
+
resolve11(decision);
|
|
12938
12949
|
} else {
|
|
12939
|
-
|
|
12950
|
+
resolve11(new Set(decision));
|
|
12940
12951
|
}
|
|
12941
12952
|
}
|
|
12942
12953
|
}
|
|
12943
12954
|
/** Cancel all pending confirms (e.g., on disconnect) */
|
|
12944
12955
|
cancelAll() {
|
|
12945
|
-
for (const
|
|
12956
|
+
for (const resolve11 of this.pendingConfirms.values()) resolve11(false);
|
|
12946
12957
|
this.pendingConfirms.clear();
|
|
12947
|
-
for (const
|
|
12958
|
+
for (const resolve11 of this.pendingBatchConfirms.values()) resolve11("none");
|
|
12948
12959
|
this.pendingBatchConfirms.clear();
|
|
12949
12960
|
this.confirming = false;
|
|
12950
12961
|
}
|
|
@@ -13020,8 +13031,8 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
13020
13031
|
diff: this.getDiffPreview(call)
|
|
13021
13032
|
};
|
|
13022
13033
|
this.send(msg);
|
|
13023
|
-
return new Promise((
|
|
13024
|
-
this.pendingConfirms.set(requestId,
|
|
13034
|
+
return new Promise((resolve11) => {
|
|
13035
|
+
this.pendingConfirms.set(requestId, resolve11);
|
|
13025
13036
|
this.pendingTimers.set(requestId, setTimeout(() => {
|
|
13026
13037
|
if (this.pendingConfirms.has(requestId)) {
|
|
13027
13038
|
this.resolveConfirm(requestId, false);
|
|
@@ -13045,8 +13056,8 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
13045
13056
|
files
|
|
13046
13057
|
};
|
|
13047
13058
|
this.send(msg);
|
|
13048
|
-
return new Promise((
|
|
13049
|
-
this.pendingBatchConfirms.set(requestId,
|
|
13059
|
+
return new Promise((resolve11) => {
|
|
13060
|
+
this.pendingBatchConfirms.set(requestId, resolve11);
|
|
13050
13061
|
this.pendingTimers.set(requestId, setTimeout(() => {
|
|
13051
13062
|
if (this.pendingBatchConfirms.has(requestId)) {
|
|
13052
13063
|
this.resolveBatchConfirm(requestId, "none");
|
|
@@ -13156,7 +13167,7 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
13156
13167
|
return { callId: call.id, content: rejectionMsg, isError: true };
|
|
13157
13168
|
}
|
|
13158
13169
|
}
|
|
13159
|
-
this.sendToolCallStart(call);
|
|
13170
|
+
if (!toolCallStarted) this.sendToolCallStart(call);
|
|
13160
13171
|
if (this.sessionAutoMode && networkPermission?.action !== "confirm") {
|
|
13161
13172
|
const classification = defaultActionClassifier.classify(call, dangerLevel, {
|
|
13162
13173
|
workspaceRoot: this.workspaceRoot,
|
|
@@ -13535,7 +13546,7 @@ function autoTrimSessionIfNeeded(session, sizeLimit = SESSION_SIZE_LIMIT) {
|
|
|
13535
13546
|
const originalSize = JSON.stringify(session.toJSON()).length;
|
|
13536
13547
|
if (originalSize <= sizeLimit) return false;
|
|
13537
13548
|
const snapshotLen = session.messages.length;
|
|
13538
|
-
|
|
13549
|
+
const working = cloneMessages(session.messages.slice(0, snapshotLen));
|
|
13539
13550
|
let committedSize = originalSize;
|
|
13540
13551
|
let anyTrim = false;
|
|
13541
13552
|
let keepRecent = 10;
|
|
@@ -15100,7 +15111,7 @@ Cache: write=${cacheCreate} read=${cacheRead}` : "";
|
|
|
15100
15111
|
Cost: ${formatCost(cost)}` : "";
|
|
15101
15112
|
let memoryLine = "";
|
|
15102
15113
|
try {
|
|
15103
|
-
const { countPendingMemories } = await import("./persistent-memory-
|
|
15114
|
+
const { countPendingMemories } = await import("./persistent-memory-G24RJ5LA.js");
|
|
15104
15115
|
const pending = countPendingMemories(ctx.config.getConfigDir());
|
|
15105
15116
|
if (pending > 0) memoryLine = `
|
|
15106
15117
|
Memory: \u26A0 ${pending} pending approval \u2014 see the Memory panel or /memory`;
|
|
@@ -15407,7 +15418,7 @@ async function handleBranch(args, ctx) {
|
|
|
15407
15418
|
return;
|
|
15408
15419
|
}
|
|
15409
15420
|
const sub = args[0]?.toLowerCase();
|
|
15410
|
-
const
|
|
15421
|
+
const resolve11 = (ref) => {
|
|
15411
15422
|
const r = session.resolveBranchRef(ref);
|
|
15412
15423
|
if (r.ok) return r.id;
|
|
15413
15424
|
if (r.reason === "ambiguous") {
|
|
@@ -15461,7 +15472,7 @@ async function handleBranch(args, ctx) {
|
|
|
15461
15472
|
ctx.send({ type: "error", message: "Usage: /branch switch <id|title>" });
|
|
15462
15473
|
return;
|
|
15463
15474
|
}
|
|
15464
|
-
const id =
|
|
15475
|
+
const id = resolve11(ref);
|
|
15465
15476
|
if (!id) return;
|
|
15466
15477
|
const ok = session.switchBranch(id);
|
|
15467
15478
|
if (ok) {
|
|
@@ -15481,7 +15492,7 @@ async function handleBranch(args, ctx) {
|
|
|
15481
15492
|
ctx.send({ type: "error", message: "Usage: /branch delete <id|title>" });
|
|
15482
15493
|
return;
|
|
15483
15494
|
}
|
|
15484
|
-
const id =
|
|
15495
|
+
const id = resolve11(ref);
|
|
15485
15496
|
if (!id) return;
|
|
15486
15497
|
const ok = session.deleteBranch(id);
|
|
15487
15498
|
if (ok) {
|
|
@@ -15500,7 +15511,7 @@ async function handleBranch(args, ctx) {
|
|
|
15500
15511
|
ctx.send({ type: "error", message: "Usage: /branch rename <id|title> <new title>" });
|
|
15501
15512
|
return;
|
|
15502
15513
|
}
|
|
15503
|
-
const id =
|
|
15514
|
+
const id = resolve11(ref);
|
|
15504
15515
|
if (!id) return;
|
|
15505
15516
|
const ok = session.renameBranch(id, title);
|
|
15506
15517
|
if (ok) {
|
|
@@ -15518,7 +15529,7 @@ async function handleBranch(args, ctx) {
|
|
|
15518
15529
|
ctx.send({ type: "error", message: "Usage: /branch diff <id|title>" });
|
|
15519
15530
|
return;
|
|
15520
15531
|
}
|
|
15521
|
-
const id =
|
|
15532
|
+
const id = resolve11(ref);
|
|
15522
15533
|
if (!id) return;
|
|
15523
15534
|
const d = session.diffBranches(id);
|
|
15524
15535
|
if (!d) {
|
|
@@ -15560,7 +15571,7 @@ async function handleBranch(args, ctx) {
|
|
|
15560
15571
|
ctx.send({ type: "error", message: "Usage: /branch cherry-pick <source-id|title> <msg-index>" });
|
|
15561
15572
|
return;
|
|
15562
15573
|
}
|
|
15563
|
-
const id =
|
|
15574
|
+
const id = resolve11(ref);
|
|
15564
15575
|
if (!id) return;
|
|
15565
15576
|
const idx = parseInt(idxStr, 10);
|
|
15566
15577
|
if (Number.isNaN(idx)) {
|
|
@@ -15909,7 +15920,7 @@ async function handleSecurityReview(args, ctx) {
|
|
|
15909
15920
|
async function handleTest(args, ctx) {
|
|
15910
15921
|
ctx.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
15911
15922
|
try {
|
|
15912
|
-
const { executeTests } = await import("./run-tests-
|
|
15923
|
+
const { executeTests } = await import("./run-tests-QEIR322E.js");
|
|
15913
15924
|
const argStr = args.join(" ").trim();
|
|
15914
15925
|
let testArgs = {};
|
|
15915
15926
|
if (argStr) {
|
|
@@ -16066,7 +16077,7 @@ async function handleIndex(args, ctx) {
|
|
|
16066
16077
|
const sub = (args[0] ?? "status").toLowerCase();
|
|
16067
16078
|
const root = process.cwd();
|
|
16068
16079
|
const { loadIndex: loadIndex2, clearIndex } = await import("./store-VO37H6LS.js");
|
|
16069
|
-
const { indexProject: indexProject2 } = await import("./indexer-
|
|
16080
|
+
const { indexProject: indexProject2 } = await import("./indexer-M2LJGTY2.js");
|
|
16070
16081
|
const { loadVectorStore, clearVectorStore } = await import("./vector-store-JBAE6PS4.js");
|
|
16071
16082
|
if (sub === "status") {
|
|
16072
16083
|
const idx = loadIndex2(root);
|
|
@@ -16173,7 +16184,7 @@ async function handleMemory(args, ctx) {
|
|
|
16173
16184
|
ctx.handleMemoryManage(sub, args[1], sub === "expire" ? args[2] : void 0);
|
|
16174
16185
|
} else if (sub === "export") {
|
|
16175
16186
|
if (args[1] === "md") {
|
|
16176
|
-
const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-
|
|
16187
|
+
const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-G24RJ5LA.js");
|
|
16177
16188
|
ctx.send({
|
|
16178
16189
|
type: "export_data",
|
|
16179
16190
|
format: "md",
|
|
@@ -16539,6 +16550,15 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
16539
16550
|
}
|
|
16540
16551
|
|
|
16541
16552
|
// src/web/session-handler.ts
|
|
16553
|
+
var CLI_ONLY_WEB_COMMANDS = /* @__PURE__ */ new Set([
|
|
16554
|
+
"copy",
|
|
16555
|
+
"paste",
|
|
16556
|
+
"exit",
|
|
16557
|
+
"quit",
|
|
16558
|
+
"snapshot",
|
|
16559
|
+
"hooks",
|
|
16560
|
+
"hook"
|
|
16561
|
+
]);
|
|
16542
16562
|
var webCommandHandlers = {
|
|
16543
16563
|
provider: handleProvider,
|
|
16544
16564
|
model: handleModel,
|
|
@@ -16776,10 +16796,10 @@ var SessionHandler = class {
|
|
|
16776
16796
|
return;
|
|
16777
16797
|
}
|
|
16778
16798
|
case "ask_user_response": {
|
|
16779
|
-
const
|
|
16780
|
-
if (
|
|
16799
|
+
const resolve11 = this.pendingAskUser.get(msg.requestId);
|
|
16800
|
+
if (resolve11) {
|
|
16781
16801
|
this.pendingAskUser.delete(msg.requestId);
|
|
16782
|
-
|
|
16802
|
+
resolve11(msg.answer);
|
|
16783
16803
|
}
|
|
16784
16804
|
return;
|
|
16785
16805
|
}
|
|
@@ -16792,10 +16812,10 @@ var SessionHandler = class {
|
|
|
16792
16812
|
case "memory_manage":
|
|
16793
16813
|
return this.handleMemoryManage(msg.action, msg.id, msg.expiresAt);
|
|
16794
16814
|
case "auto_pause_response": {
|
|
16795
|
-
const
|
|
16796
|
-
if (
|
|
16815
|
+
const resolve11 = this.pendingAutoPause.get(msg.requestId);
|
|
16816
|
+
if (resolve11) {
|
|
16797
16817
|
this.pendingAutoPause.delete(msg.requestId);
|
|
16798
|
-
|
|
16818
|
+
resolve11({ action: msg.action, message: msg.message });
|
|
16799
16819
|
}
|
|
16800
16820
|
return;
|
|
16801
16821
|
}
|
|
@@ -16810,10 +16830,10 @@ var SessionHandler = class {
|
|
|
16810
16830
|
this.hubOrchestrator?.abort();
|
|
16811
16831
|
return;
|
|
16812
16832
|
case "hub_steer": {
|
|
16813
|
-
const
|
|
16814
|
-
if (
|
|
16833
|
+
const resolve11 = this.pendingHubReview.get(msg.requestId);
|
|
16834
|
+
if (resolve11) {
|
|
16815
16835
|
this.pendingHubReview.delete(msg.requestId);
|
|
16816
|
-
|
|
16836
|
+
resolve11({ action: msg.action, message: msg.message });
|
|
16817
16837
|
}
|
|
16818
16838
|
return;
|
|
16819
16839
|
}
|
|
@@ -16826,9 +16846,9 @@ var SessionHandler = class {
|
|
|
16826
16846
|
runLifecycleHooks(mergePluginHooks(this.config.get("hooks") ?? void 0, this.config.getConfigDir()), "Stop", { sessionId: this.sessions.current?.id }, { configDir: this.config.getConfigDir() });
|
|
16827
16847
|
this.toolExecutor.cancelAll();
|
|
16828
16848
|
if (this.abortController) this.abortController.abort();
|
|
16829
|
-
for (const
|
|
16849
|
+
for (const resolve11 of this.pendingAskUser.values()) resolve11(null);
|
|
16830
16850
|
this.pendingAskUser.clear();
|
|
16831
|
-
for (const
|
|
16851
|
+
for (const resolve11 of this.pendingAutoPause.values()) resolve11({ action: "stop" });
|
|
16832
16852
|
this.pendingAutoPause.clear();
|
|
16833
16853
|
this.saveIfNeeded();
|
|
16834
16854
|
if (this._bashSessionKey) clearBashSession(this._bashSessionKey);
|
|
@@ -16963,9 +16983,9 @@ var SessionHandler = class {
|
|
|
16963
16983
|
this.hubOrchestrator = orchestrator;
|
|
16964
16984
|
orchestrator.onEvent = (event) => this.send({ type: "hub_event", event });
|
|
16965
16985
|
if (config.humanSteer) {
|
|
16966
|
-
orchestrator.onRoundReview = ({ round, maxRounds }) => new Promise((
|
|
16986
|
+
orchestrator.onRoundReview = ({ round, maxRounds }) => new Promise((resolve11) => {
|
|
16967
16987
|
const requestId = `hubrev_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
16968
|
-
this.pendingHubReview.set(requestId,
|
|
16988
|
+
this.pendingHubReview.set(requestId, resolve11);
|
|
16969
16989
|
this.send({ type: "hub_review", requestId, round, maxRounds });
|
|
16970
16990
|
});
|
|
16971
16991
|
}
|
|
@@ -17323,8 +17343,8 @@ Try: /compact to reduce context, /clear to reset, or switch to a larger-context
|
|
|
17323
17343
|
onMcpToolUsed: (name) => this.usedMcpToolNames.add(name),
|
|
17324
17344
|
requestAutoPause: async ({ effectiveRound, maxToolRounds: totalRounds, toolSummary }) => {
|
|
17325
17345
|
const requestId = `pause_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
17326
|
-
const pauseResp = await new Promise((
|
|
17327
|
-
this.pendingAutoPause.set(requestId,
|
|
17346
|
+
const pauseResp = await new Promise((resolve11) => {
|
|
17347
|
+
this.pendingAutoPause.set(requestId, resolve11);
|
|
17328
17348
|
this.send({
|
|
17329
17349
|
type: "auto_pause_request",
|
|
17330
17350
|
requestId,
|
|
@@ -17503,8 +17523,8 @@ ${summaryContent}`,
|
|
|
17503
17523
|
}
|
|
17504
17524
|
if (chunk.done) break;
|
|
17505
17525
|
}
|
|
17506
|
-
await new Promise((
|
|
17507
|
-
fileStream.end((err) => err ? reject(err) :
|
|
17526
|
+
await new Promise((resolve11, reject) => {
|
|
17527
|
+
fileStream.end((err) => err ? reject(err) : resolve11());
|
|
17508
17528
|
});
|
|
17509
17529
|
const verdict = evaluateTeeContent(fullContent, saveToFile, priorContent);
|
|
17510
17530
|
if (verdict.kind === "reject") {
|
|
@@ -17530,7 +17550,7 @@ ${summaryContent}`,
|
|
|
17530
17550
|
} catch (err) {
|
|
17531
17551
|
if (fileStream) {
|
|
17532
17552
|
try {
|
|
17533
|
-
await new Promise((
|
|
17553
|
+
await new Promise((resolve11) => fileStream.end(() => resolve11()));
|
|
17534
17554
|
} catch {
|
|
17535
17555
|
}
|
|
17536
17556
|
}
|
|
@@ -17578,6 +17598,13 @@ ${summaryContent}`,
|
|
|
17578
17598
|
}
|
|
17579
17599
|
// ── Commands ─────────────────────────────────────────────────────
|
|
17580
17600
|
async handleCommand(name, args) {
|
|
17601
|
+
if (CLI_ONLY_WEB_COMMANDS.has(name)) {
|
|
17602
|
+
this.send({
|
|
17603
|
+
type: "error",
|
|
17604
|
+
message: `/${name} is only available in the terminal REPL. Run \`aicli\` in a terminal and use /${name} there.`
|
|
17605
|
+
});
|
|
17606
|
+
return;
|
|
17607
|
+
}
|
|
17581
17608
|
const handler = webCommandHandlers[name];
|
|
17582
17609
|
if (handler) {
|
|
17583
17610
|
await handler(args, this);
|
|
@@ -17853,7 +17880,7 @@ Backup saved: ${result.backupPath}` : "";
|
|
|
17853
17880
|
return;
|
|
17854
17881
|
}
|
|
17855
17882
|
try {
|
|
17856
|
-
const { searchChatMemory: searchChatMemory2, loadChatIndex: loadChatIndex2 } = await import("./chat-index-
|
|
17883
|
+
const { searchChatMemory: searchChatMemory2, loadChatIndex: loadChatIndex2 } = await import("./chat-index-Q6BKWWAM.js");
|
|
17857
17884
|
const loaded = loadChatIndex2();
|
|
17858
17885
|
if (!loaded || loaded.idx.chunks.length === 0) {
|
|
17859
17886
|
this.send({ type: "memory_hits", query: q, hits: [], indexMissing: true });
|
|
@@ -17889,7 +17916,7 @@ Backup saved: ${result.backupPath}` : "";
|
|
|
17889
17916
|
}
|
|
17890
17917
|
async handleMemoryStatus() {
|
|
17891
17918
|
try {
|
|
17892
|
-
const { getChatIndexStatus } = await import("./chat-index-
|
|
17919
|
+
const { getChatIndexStatus } = await import("./chat-index-Q6BKWWAM.js");
|
|
17893
17920
|
const s = getChatIndexStatus();
|
|
17894
17921
|
this.send({
|
|
17895
17922
|
type: "memory_status",
|
|
@@ -17914,7 +17941,7 @@ Backup saved: ${result.backupPath}` : "";
|
|
|
17914
17941
|
type: "info",
|
|
17915
17942
|
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"
|
|
17916
17943
|
});
|
|
17917
|
-
const { buildChatIndex } = await import("./chat-index-
|
|
17944
|
+
const { buildChatIndex } = await import("./chat-index-Q6BKWWAM.js");
|
|
17918
17945
|
const stats = await buildChatIndex({
|
|
17919
17946
|
full,
|
|
17920
17947
|
onProgress: (p) => {
|
|
@@ -18070,8 +18097,8 @@ async function setupProxy(configProxy) {
|
|
|
18070
18097
|
}
|
|
18071
18098
|
|
|
18072
18099
|
// src/web/auth.ts
|
|
18073
|
-
import { existsSync as
|
|
18074
|
-
import { isAbsolute as isAbsolute3, join as
|
|
18100
|
+
import { existsSync as existsSync29, readFileSync as readFileSync22, writeFileSync as writeFileSync4, mkdirSync as mkdirSync15, readdirSync as readdirSync14, copyFileSync } from "fs";
|
|
18101
|
+
import { isAbsolute as isAbsolute3, join as join24, relative as relative5 } from "path";
|
|
18075
18102
|
import { createHmac, randomBytes, timingSafeEqual, pbkdf2Sync } from "crypto";
|
|
18076
18103
|
var USERS_FILE = "users.json";
|
|
18077
18104
|
var TOKEN_EXPIRY_HOURS = 24;
|
|
@@ -18086,7 +18113,7 @@ var AuthManager = class {
|
|
|
18086
18113
|
db;
|
|
18087
18114
|
constructor(baseDir) {
|
|
18088
18115
|
this.baseDir = baseDir;
|
|
18089
|
-
this.usersFile =
|
|
18116
|
+
this.usersFile = join24(baseDir, USERS_FILE);
|
|
18090
18117
|
this.db = this.loadOrCreate();
|
|
18091
18118
|
}
|
|
18092
18119
|
// ── Public API ─────────────────────────────────────────────────
|
|
@@ -18115,9 +18142,9 @@ var AuthManager = class {
|
|
|
18115
18142
|
}
|
|
18116
18143
|
const salt = randomBytes(16).toString("hex");
|
|
18117
18144
|
const passwordHash = this.hashPassword(password, salt);
|
|
18118
|
-
const dataDir =
|
|
18119
|
-
const fullDataDir =
|
|
18120
|
-
mkdirSync15(
|
|
18145
|
+
const dataDir = join24(USERS_DIR, username);
|
|
18146
|
+
const fullDataDir = join24(this.baseDir, dataDir);
|
|
18147
|
+
mkdirSync15(join24(fullDataDir, "history"), { recursive: true });
|
|
18121
18148
|
const user = {
|
|
18122
18149
|
username,
|
|
18123
18150
|
passwordHash,
|
|
@@ -18232,7 +18259,7 @@ var AuthManager = class {
|
|
|
18232
18259
|
getUserDataDir(username) {
|
|
18233
18260
|
const user = this.db.users.find((u) => u.username === username);
|
|
18234
18261
|
if (!user) throw new Error(`User not found: ${username}`);
|
|
18235
|
-
return
|
|
18262
|
+
return join24(this.baseDir, user.dataDir);
|
|
18236
18263
|
}
|
|
18237
18264
|
/** List all usernames */
|
|
18238
18265
|
listUsers() {
|
|
@@ -18268,30 +18295,30 @@ var AuthManager = class {
|
|
|
18268
18295
|
const err = this.register(username, password);
|
|
18269
18296
|
if (err) return err;
|
|
18270
18297
|
const userDir = this.getUserDataDir(username);
|
|
18271
|
-
const globalConfig =
|
|
18272
|
-
if (
|
|
18298
|
+
const globalConfig = join24(this.baseDir, "config.json");
|
|
18299
|
+
if (existsSync29(globalConfig)) {
|
|
18273
18300
|
try {
|
|
18274
|
-
const content =
|
|
18275
|
-
|
|
18301
|
+
const content = readFileSync22(globalConfig, "utf-8");
|
|
18302
|
+
writeFileSync4(join24(userDir, "config.json"), content, "utf-8");
|
|
18276
18303
|
} catch {
|
|
18277
18304
|
}
|
|
18278
18305
|
}
|
|
18279
|
-
const globalMemory =
|
|
18280
|
-
if (
|
|
18306
|
+
const globalMemory = join24(this.baseDir, "memory.md");
|
|
18307
|
+
if (existsSync29(globalMemory)) {
|
|
18281
18308
|
try {
|
|
18282
|
-
const content =
|
|
18283
|
-
|
|
18309
|
+
const content = readFileSync22(globalMemory, "utf-8");
|
|
18310
|
+
writeFileSync4(join24(userDir, "memory.md"), content, "utf-8");
|
|
18284
18311
|
} catch {
|
|
18285
18312
|
}
|
|
18286
18313
|
}
|
|
18287
|
-
const globalHistory =
|
|
18288
|
-
if (
|
|
18314
|
+
const globalHistory = join24(this.baseDir, "history");
|
|
18315
|
+
if (existsSync29(globalHistory)) {
|
|
18289
18316
|
try {
|
|
18290
|
-
const files =
|
|
18291
|
-
const userHistory =
|
|
18317
|
+
const files = readdirSync14(globalHistory).filter((f) => f.endsWith(".json"));
|
|
18318
|
+
const userHistory = join24(userDir, "history");
|
|
18292
18319
|
for (const f of files) {
|
|
18293
18320
|
try {
|
|
18294
|
-
copyFileSync(
|
|
18321
|
+
copyFileSync(join24(globalHistory, f), join24(userHistory, f));
|
|
18295
18322
|
} catch {
|
|
18296
18323
|
}
|
|
18297
18324
|
}
|
|
@@ -18302,9 +18329,9 @@ var AuthManager = class {
|
|
|
18302
18329
|
}
|
|
18303
18330
|
// ── Private methods ────────────────────────────────────────────
|
|
18304
18331
|
loadOrCreate() {
|
|
18305
|
-
if (
|
|
18332
|
+
if (existsSync29(this.usersFile)) {
|
|
18306
18333
|
try {
|
|
18307
|
-
const parsed = JSON.parse(
|
|
18334
|
+
const parsed = JSON.parse(readFileSync22(this.usersFile, "utf-8"));
|
|
18308
18335
|
if (!this.isValidUsersDB(parsed)) {
|
|
18309
18336
|
throw new Error("database structure is invalid");
|
|
18310
18337
|
}
|
|
@@ -18338,7 +18365,7 @@ var AuthManager = class {
|
|
|
18338
18365
|
if (typeof record.username !== "string" || !/^[a-z0-9_-]{2,32}$/.test(record.username) || usernames.has(record.username) || typeof record.passwordHash !== "string" || record.passwordHash.length === 0 || typeof record.salt !== "string" || record.salt.length === 0 || typeof record.createdAt !== "string" || typeof record.dataDir !== "string" || record.dataDir.length === 0 || isAbsolute3(record.dataDir)) {
|
|
18339
18366
|
return false;
|
|
18340
18367
|
}
|
|
18341
|
-
const dataDirFromBase = relative5(this.baseDir,
|
|
18368
|
+
const dataDirFromBase = relative5(this.baseDir, join24(this.baseDir, record.dataDir));
|
|
18342
18369
|
if (dataDirFromBase.startsWith("..") || isAbsolute3(dataDirFromBase)) return false;
|
|
18343
18370
|
if (record.hashVersion !== void 0 && record.hashVersion !== 1 && record.hashVersion !== 2) return false;
|
|
18344
18371
|
if (record.tokensRevokedBefore !== void 0 && !Number.isFinite(record.tokensRevokedBefore)) return false;
|
|
@@ -18386,7 +18413,7 @@ function getModuleDir() {
|
|
|
18386
18413
|
}
|
|
18387
18414
|
} catch {
|
|
18388
18415
|
}
|
|
18389
|
-
return
|
|
18416
|
+
return resolve10(".");
|
|
18390
18417
|
}
|
|
18391
18418
|
async function startWebServer(options = {}) {
|
|
18392
18419
|
const port = options.port ?? 3e3;
|
|
@@ -18454,8 +18481,8 @@ async function startWebServer(options = {}) {
|
|
|
18454
18481
|
}
|
|
18455
18482
|
}
|
|
18456
18483
|
let skillManager = null;
|
|
18457
|
-
const skillsDir =
|
|
18458
|
-
if (
|
|
18484
|
+
const skillsDir = join25(config.getConfigDir(), SKILLS_DIR_NAME);
|
|
18485
|
+
if (existsSync30(skillsDir)) {
|
|
18459
18486
|
skillManager = new SkillManager(skillsDir, config.get("ui").skillSizeWarn);
|
|
18460
18487
|
skillManager.loadSkills(pluginAssets.skillDirs);
|
|
18461
18488
|
const count = skillManager.listSkills().length;
|
|
@@ -18506,6 +18533,10 @@ async function startWebServer(options = {}) {
|
|
|
18506
18533
|
console.log(` Auth: ${authManager.listUsers().length} user(s) registered`);
|
|
18507
18534
|
} else {
|
|
18508
18535
|
console.log(` Auth: disabled (no users registered)`);
|
|
18536
|
+
if (host === "0.0.0.0" || host === "::") {
|
|
18537
|
+
console.log(" WARNING: Web UI is reachable from the network without authentication.");
|
|
18538
|
+
console.log(" Create a user first for LAN/team use: aicli user create <name>");
|
|
18539
|
+
}
|
|
18509
18540
|
}
|
|
18510
18541
|
const requireAuth = (req, res, next) => {
|
|
18511
18542
|
if (!authManager.isEnabled()) return next();
|
|
@@ -18526,18 +18557,18 @@ async function startWebServer(options = {}) {
|
|
|
18526
18557
|
next();
|
|
18527
18558
|
};
|
|
18528
18559
|
const moduleDir = getModuleDir();
|
|
18529
|
-
let clientDir =
|
|
18530
|
-
if (!
|
|
18531
|
-
clientDir =
|
|
18560
|
+
let clientDir = join25(moduleDir, "web", "client");
|
|
18561
|
+
if (!existsSync30(clientDir)) {
|
|
18562
|
+
clientDir = join25(moduleDir, "client");
|
|
18532
18563
|
}
|
|
18533
|
-
if (!
|
|
18534
|
-
clientDir =
|
|
18564
|
+
if (!existsSync30(clientDir)) {
|
|
18565
|
+
clientDir = join25(moduleDir, "..", "..", "src", "web", "client");
|
|
18535
18566
|
}
|
|
18536
|
-
if (!
|
|
18537
|
-
clientDir =
|
|
18567
|
+
if (!existsSync30(clientDir)) {
|
|
18568
|
+
clientDir = join25(process.cwd(), "src", "web", "client");
|
|
18538
18569
|
}
|
|
18539
18570
|
console.log(` Static files: ${clientDir}`);
|
|
18540
|
-
app.use("/vendor", express.static(
|
|
18571
|
+
app.use("/vendor", express.static(join25(clientDir, "vendor"), { maxAge: "1y", immutable: true }));
|
|
18541
18572
|
app.use(express.static(clientDir));
|
|
18542
18573
|
app.get("/api/status", (_req, res) => {
|
|
18543
18574
|
res.json({
|
|
@@ -18604,10 +18635,10 @@ async function startWebServer(options = {}) {
|
|
|
18604
18635
|
app.get("/api/files", requireAuth, (req, res) => {
|
|
18605
18636
|
const cwd = process.cwd();
|
|
18606
18637
|
const prefix = req.query.prefix || "";
|
|
18607
|
-
const targetDir =
|
|
18638
|
+
const targetDir = join25(cwd, prefix);
|
|
18608
18639
|
try {
|
|
18609
|
-
const canonicalTarget = realpathSync3(
|
|
18610
|
-
const canonicalCwd = realpathSync3(
|
|
18640
|
+
const canonicalTarget = realpathSync3(resolve10(targetDir));
|
|
18641
|
+
const canonicalCwd = realpathSync3(resolve10(cwd));
|
|
18611
18642
|
if (!canonicalTarget.startsWith(canonicalCwd + sep4) && canonicalTarget !== canonicalCwd) {
|
|
18612
18643
|
res.json({ files: [] });
|
|
18613
18644
|
return;
|
|
@@ -18618,10 +18649,10 @@ async function startWebServer(options = {}) {
|
|
|
18618
18649
|
}
|
|
18619
18650
|
try {
|
|
18620
18651
|
const SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "dist-cjs", "release", "__pycache__", ".next", ".nuxt", "coverage", ".cache"]);
|
|
18621
|
-
const entries =
|
|
18652
|
+
const entries = readdirSync15(targetDir, { withFileTypes: true });
|
|
18622
18653
|
const files = entries.filter((e) => !SKIP.has(e.name) && !e.name.startsWith(".")).slice(0, 50).map((e) => ({
|
|
18623
18654
|
name: e.name,
|
|
18624
|
-
path: relative6(cwd,
|
|
18655
|
+
path: relative6(cwd, join25(targetDir, e.name)).replace(/\\/g, "/"),
|
|
18625
18656
|
isDir: e.isDirectory()
|
|
18626
18657
|
}));
|
|
18627
18658
|
res.json({ files });
|
|
@@ -18661,8 +18692,8 @@ async function startWebServer(options = {}) {
|
|
|
18661
18692
|
try {
|
|
18662
18693
|
const authUser = req._authUser;
|
|
18663
18694
|
const histDir = authUser ? getUserShared(authUser).config.getHistoryDir() : config.getHistoryDir();
|
|
18664
|
-
const filePath =
|
|
18665
|
-
if (!
|
|
18695
|
+
const filePath = join25(histDir, `${id}.json`);
|
|
18696
|
+
if (!existsSync30(filePath)) {
|
|
18666
18697
|
res.status(404).json({ error: "Session not found" });
|
|
18667
18698
|
return;
|
|
18668
18699
|
}
|
|
@@ -18677,7 +18708,7 @@ async function startWebServer(options = {}) {
|
|
|
18677
18708
|
res.status(404).json({ error: "Session not found" });
|
|
18678
18709
|
return;
|
|
18679
18710
|
}
|
|
18680
|
-
const data = JSON.parse(
|
|
18711
|
+
const data = JSON.parse(readFileSync23(filePath, "utf-8"));
|
|
18681
18712
|
res.json({ session: data });
|
|
18682
18713
|
} catch (err) {
|
|
18683
18714
|
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
@@ -18690,10 +18721,10 @@ async function startWebServer(options = {}) {
|
|
|
18690
18721
|
return;
|
|
18691
18722
|
}
|
|
18692
18723
|
const cwd = process.cwd();
|
|
18693
|
-
const fullPath =
|
|
18724
|
+
const fullPath = resolve10(join25(cwd, filePath));
|
|
18694
18725
|
try {
|
|
18695
18726
|
const canonicalFull = realpathSync3(fullPath);
|
|
18696
|
-
const canonicalCwd = realpathSync3(
|
|
18727
|
+
const canonicalCwd = realpathSync3(resolve10(cwd));
|
|
18697
18728
|
if (!canonicalFull.startsWith(canonicalCwd + sep4) && canonicalFull !== canonicalCwd) {
|
|
18698
18729
|
res.json({ error: "Access denied" });
|
|
18699
18730
|
return;
|
|
@@ -18703,12 +18734,12 @@ async function startWebServer(options = {}) {
|
|
|
18703
18734
|
return;
|
|
18704
18735
|
}
|
|
18705
18736
|
try {
|
|
18706
|
-
const stat =
|
|
18737
|
+
const stat = statSync13(fullPath);
|
|
18707
18738
|
if (stat.size > 512 * 1024) {
|
|
18708
18739
|
res.json({ error: `File too large (${(stat.size / 1024).toFixed(0)} KB, max 512 KB)` });
|
|
18709
18740
|
return;
|
|
18710
18741
|
}
|
|
18711
|
-
const content =
|
|
18742
|
+
const content = readFileSync23(fullPath, "utf-8");
|
|
18712
18743
|
res.json({ content, size: stat.size });
|
|
18713
18744
|
} catch {
|
|
18714
18745
|
res.json({ error: "Cannot read file" });
|
|
@@ -18837,7 +18868,7 @@ async function startWebServer(options = {}) {
|
|
|
18837
18868
|
ws.send(JSON.stringify({ type: "auth_result", success: false, error: err }));
|
|
18838
18869
|
return;
|
|
18839
18870
|
}
|
|
18840
|
-
|
|
18871
|
+
authManager.login(username, password);
|
|
18841
18872
|
authenticatedUser = username;
|
|
18842
18873
|
const userShared = getUserShared(username);
|
|
18843
18874
|
handler = new SessionHandler(ws, userShared);
|
|
@@ -18912,7 +18943,7 @@ async function startWebServer(options = {}) {
|
|
|
18912
18943
|
});
|
|
18913
18944
|
const MAX_PORT_ATTEMPTS = 10;
|
|
18914
18945
|
let actualPort = port;
|
|
18915
|
-
const result = await new Promise((
|
|
18946
|
+
const result = await new Promise((resolve11, reject) => {
|
|
18916
18947
|
const tryListen = (attempt) => {
|
|
18917
18948
|
server.once("error", (err) => {
|
|
18918
18949
|
if (err.code === "EADDRINUSE" && attempt < MAX_PORT_ATTEMPTS) {
|
|
@@ -18943,7 +18974,7 @@ async function startWebServer(options = {}) {
|
|
|
18943
18974
|
}
|
|
18944
18975
|
console.log(` Press Ctrl+C to stop
|
|
18945
18976
|
`);
|
|
18946
|
-
|
|
18977
|
+
resolve11({ port: actualPort, host, url });
|
|
18947
18978
|
});
|
|
18948
18979
|
};
|
|
18949
18980
|
tryListen(1);
|
|
@@ -18963,17 +18994,17 @@ function resolveProjectMcpPath() {
|
|
|
18963
18994
|
const cwd = process.cwd();
|
|
18964
18995
|
const gitRoot = getGitRoot(cwd);
|
|
18965
18996
|
const projectRoot = gitRoot ?? cwd;
|
|
18966
|
-
const configPath =
|
|
18967
|
-
return
|
|
18997
|
+
const configPath = join25(projectRoot, MCP_PROJECT_CONFIG_NAME);
|
|
18998
|
+
return existsSync30(configPath) ? configPath : null;
|
|
18968
18999
|
}
|
|
18969
19000
|
function loadProjectMcpConfig() {
|
|
18970
19001
|
const cwd = process.cwd();
|
|
18971
19002
|
const gitRoot = getGitRoot(cwd);
|
|
18972
19003
|
const projectRoot = gitRoot ?? cwd;
|
|
18973
|
-
const configPath =
|
|
18974
|
-
if (!
|
|
19004
|
+
const configPath = join25(projectRoot, MCP_PROJECT_CONFIG_NAME);
|
|
19005
|
+
if (!existsSync30(configPath)) return null;
|
|
18975
19006
|
try {
|
|
18976
|
-
const raw = JSON.parse(
|
|
19007
|
+
const raw = JSON.parse(readFileSync23(configPath, "utf-8"));
|
|
18977
19008
|
return raw.mcpServers ?? raw;
|
|
18978
19009
|
} catch {
|
|
18979
19010
|
return null;
|