jinzd-ai-cli 0.4.106 → 0.4.107
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-PF2EB4BE.js → batch-QNHPXV6U.js} +2 -2
- package/dist/{chunk-ITHFJSJQ.js → chunk-76UBRJUT.js} +1 -1
- package/dist/{chunk-OSGGBJSW.js → chunk-7J2GXVS5.js} +16 -2
- package/dist/{chunk-W7ZG4KRQ.js → chunk-7JPMYNVW.js} +1 -1
- package/dist/{chunk-RD4RCKIB.js → chunk-PXTMQ4TC.js} +1 -1
- package/dist/{chunk-ML7ISZ7A.js → chunk-QJ42A4GF.js} +15 -10
- package/dist/{chunk-RSZ75E2W.js → chunk-YMFTF57T.js} +2 -2
- package/dist/{constants-FVJPGHS7.js → constants-G7IWRPVI.js} +1 -1
- package/dist/electron-server.js +51 -14
- package/dist/{hub-3KDAZUH4.js → hub-GBL3BURO.js} +1 -1
- package/dist/index.js +11 -11
- package/dist/{run-tests-UZGGOXOS.js → run-tests-3JWA5IJ2.js} +2 -2
- package/dist/{run-tests-6FVJND6Q.js → run-tests-GMO7E3UK.js} +1 -1
- package/dist/{server-5MJQOIZU.js → server-2BKTE6Z4.js} +3 -3
- package/dist/{server-CWDCYN3N.js → server-RTABJZZZ.js} +27 -9
- package/dist/{task-orchestrator-32DSRTMN.js → task-orchestrator-FAQWRMJH.js} +3 -3
- package/dist/web/client/app.js +61 -23
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ConfigManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-7J2GXVS5.js";
|
|
5
5
|
import "./chunk-2ZD3YTVM.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-76UBRJUT.js";
|
|
7
7
|
import "./chunk-PDX44BCA.js";
|
|
8
8
|
|
|
9
9
|
// src/cli/batch.ts
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
CONFIG_FILE_NAME,
|
|
9
9
|
HISTORY_DIR_NAME,
|
|
10
10
|
PLUGINS_DIR_NAME
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-76UBRJUT.js";
|
|
12
12
|
|
|
13
13
|
// src/config/config-manager.ts
|
|
14
14
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
@@ -268,9 +268,23 @@ ${err}`
|
|
|
268
268
|
/**
|
|
269
269
|
* 仅修改内存中的配置值,不持久化到磁盘。
|
|
270
270
|
* 用于 CLI 命令行参数覆盖(-p, -m, --no-stream),使其只对当前进程生效。
|
|
271
|
+
*
|
|
272
|
+
* M6 fix (v0.4.107):原版直接赋值不走 Zod,调用点必须自律确保来源可信
|
|
273
|
+
* (如 CLI flag、global config)。如果未来谁把外部输入接到这里,类型系统
|
|
274
|
+
* 不会阻止恶意值偷渡进 config。现在用 partial Zod parse 校验单字段,
|
|
275
|
+
* 失败时抛 ConfigError。setTransient 永远不接受外部不可信输入——这是
|
|
276
|
+
* 「调用方信任」契约的硬实现。
|
|
271
277
|
*/
|
|
272
278
|
setTransient(key, value) {
|
|
273
|
-
this.config[key]
|
|
279
|
+
const draft = { ...this.config, [key]: value };
|
|
280
|
+
const result = ConfigSchema.safeParse(draft);
|
|
281
|
+
if (!result.success) {
|
|
282
|
+
const firstErr = result.error.errors[0];
|
|
283
|
+
throw new ConfigError(
|
|
284
|
+
`Invalid transient config value for "${String(key)}": ${firstErr?.message ?? "validation failed"}`
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
this.config = result.data;
|
|
274
288
|
}
|
|
275
289
|
isFirstRun() {
|
|
276
290
|
return !existsSync(this.configPath);
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-3BICTI5M.js";
|
|
6
6
|
import {
|
|
7
7
|
runTestsTool
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-7JPMYNVW.js";
|
|
9
9
|
import {
|
|
10
10
|
EnvLoader,
|
|
11
11
|
NetworkError,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
SUBAGENT_ALLOWED_TOOLS,
|
|
19
19
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
20
20
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-76UBRJUT.js";
|
|
22
22
|
import {
|
|
23
23
|
fileCheckpoints
|
|
24
24
|
} from "./chunk-4BKXL7SM.js";
|
|
@@ -1136,21 +1136,26 @@ function simpleDiff(oldLines, newLines) {
|
|
|
1136
1136
|
|
|
1137
1137
|
// src/tools/hooks.ts
|
|
1138
1138
|
import { execSync } from "child_process";
|
|
1139
|
-
function
|
|
1140
|
-
|
|
1139
|
+
function rewriteTemplate(template, isWindows) {
|
|
1140
|
+
const ref = (name) => isWindows ? `%${name}%` : `$${name}`;
|
|
1141
|
+
return template.replace(/\{tool\}/g, ref("AICLI_HOOK_TOOL")).replace(/\{dangerLevel\}/g, ref("AICLI_HOOK_DANGER_LEVEL")).replace(/\{args\}/g, ref("AICLI_HOOK_ARGS")).replace(/\{status\}/g, ref("AICLI_HOOK_STATUS"));
|
|
1141
1142
|
}
|
|
1142
1143
|
function runHook(template, vars) {
|
|
1143
1144
|
if (!template) return;
|
|
1144
|
-
|
|
1145
|
-
cmd =
|
|
1146
|
-
cmd = cmd.replace(/\{dangerLevel\}/g, shellEscape(vars.dangerLevel ?? ""));
|
|
1147
|
-
cmd = cmd.replace(/\{args\}/g, shellEscape(vars.args ?? ""));
|
|
1148
|
-
cmd = cmd.replace(/\{status\}/g, shellEscape(vars.status ?? ""));
|
|
1145
|
+
const isWindows = process.platform === "win32";
|
|
1146
|
+
const cmd = rewriteTemplate(template, isWindows);
|
|
1149
1147
|
try {
|
|
1150
1148
|
execSync(cmd, {
|
|
1151
1149
|
timeout: 5e3,
|
|
1152
1150
|
stdio: ["pipe", "pipe", "pipe"],
|
|
1153
|
-
encoding: "utf-8"
|
|
1151
|
+
encoding: "utf-8",
|
|
1152
|
+
env: {
|
|
1153
|
+
...process.env,
|
|
1154
|
+
AICLI_HOOK_TOOL: vars.tool,
|
|
1155
|
+
AICLI_HOOK_DANGER_LEVEL: vars.dangerLevel ?? "",
|
|
1156
|
+
AICLI_HOOK_ARGS: vars.args ?? "",
|
|
1157
|
+
AICLI_HOOK_STATUS: vars.status ?? ""
|
|
1158
|
+
}
|
|
1154
1159
|
});
|
|
1155
1160
|
} catch {
|
|
1156
1161
|
process.stderr.write(`\u26A0 Hook failed: ${cmd.slice(0, 100)}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
schemaToJsonSchema,
|
|
4
4
|
truncateForPersist
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-QJ42A4GF.js";
|
|
6
6
|
import {
|
|
7
7
|
AuthError,
|
|
8
8
|
ProviderError,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
MCP_PROTOCOL_VERSION,
|
|
19
19
|
MCP_TOOL_PREFIX,
|
|
20
20
|
VERSION
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-76UBRJUT.js";
|
|
22
22
|
import {
|
|
23
23
|
redactJson
|
|
24
24
|
} from "./chunk-ANYYM4CF.js";
|
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-PXTMQ4TC.js";
|
|
40
40
|
import {
|
|
41
41
|
hasSemanticIndex,
|
|
42
42
|
semanticSearch
|
|
@@ -421,9 +421,23 @@ ${err}`
|
|
|
421
421
|
/**
|
|
422
422
|
* 仅修改内存中的配置值,不持久化到磁盘。
|
|
423
423
|
* 用于 CLI 命令行参数覆盖(-p, -m, --no-stream),使其只对当前进程生效。
|
|
424
|
+
*
|
|
425
|
+
* M6 fix (v0.4.107):原版直接赋值不走 Zod,调用点必须自律确保来源可信
|
|
426
|
+
* (如 CLI flag、global config)。如果未来谁把外部输入接到这里,类型系统
|
|
427
|
+
* 不会阻止恶意值偷渡进 config。现在用 partial Zod parse 校验单字段,
|
|
428
|
+
* 失败时抛 ConfigError。setTransient 永远不接受外部不可信输入——这是
|
|
429
|
+
* 「调用方信任」契约的硬实现。
|
|
424
430
|
*/
|
|
425
431
|
setTransient(key, value) {
|
|
426
|
-
this.config[key]
|
|
432
|
+
const draft = { ...this.config, [key]: value };
|
|
433
|
+
const result = ConfigSchema.safeParse(draft);
|
|
434
|
+
if (!result.success) {
|
|
435
|
+
const firstErr = result.error.errors[0];
|
|
436
|
+
throw new ConfigError(
|
|
437
|
+
`Invalid transient config value for "${String(key)}": ${firstErr?.message ?? "validation failed"}`
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
this.config = result.data;
|
|
427
441
|
}
|
|
428
442
|
isFirstRun() {
|
|
429
443
|
return !existsSync(this.configPath);
|
|
@@ -4528,21 +4542,26 @@ function simpleDiff(oldLines, newLines) {
|
|
|
4528
4542
|
|
|
4529
4543
|
// src/tools/hooks.ts
|
|
4530
4544
|
import { execSync } from "child_process";
|
|
4531
|
-
function
|
|
4532
|
-
|
|
4545
|
+
function rewriteTemplate(template, isWindows) {
|
|
4546
|
+
const ref = (name) => isWindows ? `%${name}%` : `$${name}`;
|
|
4547
|
+
return template.replace(/\{tool\}/g, ref("AICLI_HOOK_TOOL")).replace(/\{dangerLevel\}/g, ref("AICLI_HOOK_DANGER_LEVEL")).replace(/\{args\}/g, ref("AICLI_HOOK_ARGS")).replace(/\{status\}/g, ref("AICLI_HOOK_STATUS"));
|
|
4533
4548
|
}
|
|
4534
4549
|
function runHook(template, vars) {
|
|
4535
4550
|
if (!template) return;
|
|
4536
|
-
|
|
4537
|
-
cmd =
|
|
4538
|
-
cmd = cmd.replace(/\{dangerLevel\}/g, shellEscape(vars.dangerLevel ?? ""));
|
|
4539
|
-
cmd = cmd.replace(/\{args\}/g, shellEscape(vars.args ?? ""));
|
|
4540
|
-
cmd = cmd.replace(/\{status\}/g, shellEscape(vars.status ?? ""));
|
|
4551
|
+
const isWindows = process.platform === "win32";
|
|
4552
|
+
const cmd = rewriteTemplate(template, isWindows);
|
|
4541
4553
|
try {
|
|
4542
4554
|
execSync(cmd, {
|
|
4543
4555
|
timeout: 5e3,
|
|
4544
4556
|
stdio: ["pipe", "pipe", "pipe"],
|
|
4545
|
-
encoding: "utf-8"
|
|
4557
|
+
encoding: "utf-8",
|
|
4558
|
+
env: {
|
|
4559
|
+
...process.env,
|
|
4560
|
+
AICLI_HOOK_TOOL: vars.tool,
|
|
4561
|
+
AICLI_HOOK_DANGER_LEVEL: vars.dangerLevel ?? "",
|
|
4562
|
+
AICLI_HOOK_ARGS: vars.args ?? "",
|
|
4563
|
+
AICLI_HOOK_STATUS: vars.status ?? ""
|
|
4564
|
+
}
|
|
4546
4565
|
});
|
|
4547
4566
|
} catch {
|
|
4548
4567
|
process.stderr.write(`\u26A0 Hook failed: ${cmd.slice(0, 100)}
|
|
@@ -11754,7 +11773,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11754
11773
|
case "test": {
|
|
11755
11774
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
11756
11775
|
try {
|
|
11757
|
-
const { executeTests } = await import("./run-tests-
|
|
11776
|
+
const { executeTests } = await import("./run-tests-GMO7E3UK.js");
|
|
11758
11777
|
const argStr = args.join(" ").trim();
|
|
11759
11778
|
let testArgs = {};
|
|
11760
11779
|
if (argStr) {
|
|
@@ -13117,7 +13136,25 @@ async function startWebServer(options = {}) {
|
|
|
13117
13136
|
const token = authManager.login(username, password);
|
|
13118
13137
|
console.log(` \u2713 User registered via API: ${username}${firstRun ? " (first-run)" : ""}`);
|
|
13119
13138
|
res.cookie("aicli_token", token, { httpOnly: true, sameSite: "strict", maxAge: 7 * 24 * 3600 * 1e3 });
|
|
13120
|
-
res.json({ success: true,
|
|
13139
|
+
res.json({ success: true, username });
|
|
13140
|
+
});
|
|
13141
|
+
app.post("/api/auth/login", (req, res) => {
|
|
13142
|
+
const { username, password } = req.body ?? {};
|
|
13143
|
+
if (!username || !password) {
|
|
13144
|
+
res.status(400).json({ error: "Username and password required" });
|
|
13145
|
+
return;
|
|
13146
|
+
}
|
|
13147
|
+
const token = authManager.login(username, password);
|
|
13148
|
+
if (!token) {
|
|
13149
|
+
res.status(401).json({ error: "Invalid username or password" });
|
|
13150
|
+
return;
|
|
13151
|
+
}
|
|
13152
|
+
res.cookie("aicli_token", token, { httpOnly: true, sameSite: "strict", maxAge: 7 * 24 * 3600 * 1e3 });
|
|
13153
|
+
res.json({ success: true, username });
|
|
13154
|
+
});
|
|
13155
|
+
app.post("/api/auth/logout", (_req, res) => {
|
|
13156
|
+
res.clearCookie("aicli_token", { httpOnly: true, sameSite: "strict" });
|
|
13157
|
+
res.json({ success: true });
|
|
13121
13158
|
});
|
|
13122
13159
|
app.get("/api/files", requireAuth, (req, res) => {
|
|
13123
13160
|
const cwd = process.cwd();
|
|
@@ -13358,7 +13395,7 @@ async function startWebServer(options = {}) {
|
|
|
13358
13395
|
handlers.set(tabId, handler);
|
|
13359
13396
|
clearPreAuthTimer();
|
|
13360
13397
|
console.log(` \u2713 User registered & connected: ${username} (tab: ${tabId.slice(0, 12)})`);
|
|
13361
|
-
ws.send(JSON.stringify({ type: "auth_result", success: true, token: newToken, username
|
|
13398
|
+
ws.send(JSON.stringify({ type: "auth_result", success: true, token: newToken, username }));
|
|
13362
13399
|
return;
|
|
13363
13400
|
}
|
|
13364
13401
|
if (action === "token") {
|
|
@@ -13389,7 +13426,7 @@ async function startWebServer(options = {}) {
|
|
|
13389
13426
|
handlers.set(tabId, handler);
|
|
13390
13427
|
clearPreAuthTimer();
|
|
13391
13428
|
console.log(` \u2713 User logged in: ${username} (tab: ${tabId.slice(0, 12)})`);
|
|
13392
|
-
ws.send(JSON.stringify({ type: "auth_result", success: true, token: loginToken, username
|
|
13429
|
+
ws.send(JSON.stringify({ type: "auth_result", success: true, token: loginToken, username }));
|
|
13393
13430
|
return;
|
|
13394
13431
|
}
|
|
13395
13432
|
ws.send(JSON.stringify({ type: "auth_result", success: false, error: "Unknown auth action" }));
|
|
@@ -386,7 +386,7 @@ ${content}`);
|
|
|
386
386
|
}
|
|
387
387
|
}
|
|
388
388
|
async function runTaskMode(config, providers, configManager, topic) {
|
|
389
|
-
const { TaskOrchestrator } = await import("./task-orchestrator-
|
|
389
|
+
const { TaskOrchestrator } = await import("./task-orchestrator-FAQWRMJH.js");
|
|
390
390
|
const orchestrator = new TaskOrchestrator(config, providers, configManager);
|
|
391
391
|
let interrupted = false;
|
|
392
392
|
const onSigint = () => {
|
package/dist/index.js
CHANGED
|
@@ -25,10 +25,10 @@ import {
|
|
|
25
25
|
saveDevState,
|
|
26
26
|
sessionHasMeaningfulContent,
|
|
27
27
|
setupProxy
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-YMFTF57T.js";
|
|
29
29
|
import {
|
|
30
30
|
ConfigManager
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-7J2GXVS5.js";
|
|
32
32
|
import {
|
|
33
33
|
ToolExecutor,
|
|
34
34
|
ToolRegistry,
|
|
@@ -47,10 +47,10 @@ import {
|
|
|
47
47
|
spawnAgentContext,
|
|
48
48
|
theme,
|
|
49
49
|
undoStack
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-QJ42A4GF.js";
|
|
51
51
|
import "./chunk-3BICTI5M.js";
|
|
52
52
|
import "./chunk-2DXY7UGF.js";
|
|
53
|
-
import "./chunk-
|
|
53
|
+
import "./chunk-7JPMYNVW.js";
|
|
54
54
|
import "./chunk-2ZD3YTVM.js";
|
|
55
55
|
import {
|
|
56
56
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
SKILLS_DIR_NAME,
|
|
74
74
|
VERSION,
|
|
75
75
|
buildUserIdentityPrompt
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-76UBRJUT.js";
|
|
77
77
|
import {
|
|
78
78
|
formatGitContextForPrompt,
|
|
79
79
|
getGitContext,
|
|
@@ -1594,7 +1594,7 @@ ${text}
|
|
|
1594
1594
|
const { join: join6 } = await import("path");
|
|
1595
1595
|
const { existsSync: existsSync6 } = await import("fs");
|
|
1596
1596
|
const { getGitRoot: getGitRoot2 } = await import("./git-context-7KIP4X2V.js");
|
|
1597
|
-
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-
|
|
1597
|
+
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-G7IWRPVI.js");
|
|
1598
1598
|
const { approveProject, hashMcpFile } = await import("./project-trust-IFM7FXEV.js");
|
|
1599
1599
|
const cwd = process.cwd();
|
|
1600
1600
|
const projectRoot = getGitRoot2(cwd) ?? cwd;
|
|
@@ -2644,7 +2644,7 @@ ${hint}` : "")
|
|
|
2644
2644
|
usage: "/test [command|filter]",
|
|
2645
2645
|
async execute(args, ctx) {
|
|
2646
2646
|
try {
|
|
2647
|
-
const { executeTests } = await import("./run-tests-
|
|
2647
|
+
const { executeTests } = await import("./run-tests-3JWA5IJ2.js");
|
|
2648
2648
|
const argStr = args.join(" ").trim();
|
|
2649
2649
|
let testArgs = {};
|
|
2650
2650
|
if (argStr) {
|
|
@@ -6800,7 +6800,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
6800
6800
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
6801
6801
|
process.exit(1);
|
|
6802
6802
|
}
|
|
6803
|
-
const { startWebServer } = await import("./server-
|
|
6803
|
+
const { startWebServer } = await import("./server-RTABJZZZ.js");
|
|
6804
6804
|
await startWebServer({ port, host: options.host });
|
|
6805
6805
|
});
|
|
6806
6806
|
program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | migrate <name>)").action(async (action, username) => {
|
|
@@ -6923,7 +6923,7 @@ program.command("sessions").description("List recent conversation sessions").act
|
|
|
6923
6923
|
});
|
|
6924
6924
|
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) => {
|
|
6925
6925
|
try {
|
|
6926
|
-
const batch = await import("./batch-
|
|
6926
|
+
const batch = await import("./batch-QNHPXV6U.js");
|
|
6927
6927
|
switch (action) {
|
|
6928
6928
|
case "submit":
|
|
6929
6929
|
if (!arg) {
|
|
@@ -6966,7 +6966,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
|
|
|
6966
6966
|
}
|
|
6967
6967
|
});
|
|
6968
6968
|
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) => {
|
|
6969
|
-
const { startMcpServer } = await import("./server-
|
|
6969
|
+
const { startMcpServer } = await import("./server-2BKTE6Z4.js");
|
|
6970
6970
|
await startMcpServer({
|
|
6971
6971
|
allowDestructive: !!options.allowDestructive,
|
|
6972
6972
|
allowOutsideCwd: !!options.allowOutsideCwd,
|
|
@@ -7093,7 +7093,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
7093
7093
|
}),
|
|
7094
7094
|
config.get("customProviders")
|
|
7095
7095
|
);
|
|
7096
|
-
const { startHub } = await import("./hub-
|
|
7096
|
+
const { startHub } = await import("./hub-GBL3BURO.js");
|
|
7097
7097
|
await startHub(
|
|
7098
7098
|
{
|
|
7099
7099
|
topic: topic ?? "",
|
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
ToolRegistry,
|
|
4
4
|
getDangerLevel,
|
|
5
5
|
schemaToJsonSchema
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-QJ42A4GF.js";
|
|
7
7
|
import "./chunk-3BICTI5M.js";
|
|
8
8
|
import "./chunk-2DXY7UGF.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-7JPMYNVW.js";
|
|
10
10
|
import "./chunk-2ZD3YTVM.js";
|
|
11
11
|
import {
|
|
12
12
|
VERSION
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-76UBRJUT.js";
|
|
14
14
|
import "./chunk-4BKXL7SM.js";
|
|
15
15
|
import "./chunk-ANYYM4CF.js";
|
|
16
16
|
import "./chunk-KHYD3WXE.js";
|
|
@@ -18,10 +18,10 @@ import {
|
|
|
18
18
|
loadDevState,
|
|
19
19
|
persistToolRound,
|
|
20
20
|
setupProxy
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-YMFTF57T.js";
|
|
22
22
|
import {
|
|
23
23
|
ConfigManager
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-7J2GXVS5.js";
|
|
25
25
|
import {
|
|
26
26
|
ToolExecutor,
|
|
27
27
|
ToolRegistry,
|
|
@@ -39,10 +39,10 @@ import {
|
|
|
39
39
|
spawnAgentContext,
|
|
40
40
|
truncateOutput,
|
|
41
41
|
undoStack
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-QJ42A4GF.js";
|
|
43
43
|
import "./chunk-3BICTI5M.js";
|
|
44
44
|
import "./chunk-2DXY7UGF.js";
|
|
45
|
-
import "./chunk-
|
|
45
|
+
import "./chunk-7JPMYNVW.js";
|
|
46
46
|
import "./chunk-2ZD3YTVM.js";
|
|
47
47
|
import {
|
|
48
48
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
@@ -62,7 +62,7 @@ import {
|
|
|
62
62
|
SKILLS_DIR_NAME,
|
|
63
63
|
VERSION,
|
|
64
64
|
buildUserIdentityPrompt
|
|
65
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-76UBRJUT.js";
|
|
66
66
|
import {
|
|
67
67
|
formatGitContextForPrompt,
|
|
68
68
|
getGitContext,
|
|
@@ -2383,7 +2383,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
2383
2383
|
case "test": {
|
|
2384
2384
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
2385
2385
|
try {
|
|
2386
|
-
const { executeTests } = await import("./run-tests-
|
|
2386
|
+
const { executeTests } = await import("./run-tests-3JWA5IJ2.js");
|
|
2387
2387
|
const argStr = args.join(" ").trim();
|
|
2388
2388
|
let testArgs = {};
|
|
2389
2389
|
if (argStr) {
|
|
@@ -3524,7 +3524,25 @@ async function startWebServer(options = {}) {
|
|
|
3524
3524
|
const token = authManager.login(username, password);
|
|
3525
3525
|
console.log(` \u2713 User registered via API: ${username}${firstRun ? " (first-run)" : ""}`);
|
|
3526
3526
|
res.cookie("aicli_token", token, { httpOnly: true, sameSite: "strict", maxAge: 7 * 24 * 3600 * 1e3 });
|
|
3527
|
-
res.json({ success: true,
|
|
3527
|
+
res.json({ success: true, username });
|
|
3528
|
+
});
|
|
3529
|
+
app.post("/api/auth/login", (req, res) => {
|
|
3530
|
+
const { username, password } = req.body ?? {};
|
|
3531
|
+
if (!username || !password) {
|
|
3532
|
+
res.status(400).json({ error: "Username and password required" });
|
|
3533
|
+
return;
|
|
3534
|
+
}
|
|
3535
|
+
const token = authManager.login(username, password);
|
|
3536
|
+
if (!token) {
|
|
3537
|
+
res.status(401).json({ error: "Invalid username or password" });
|
|
3538
|
+
return;
|
|
3539
|
+
}
|
|
3540
|
+
res.cookie("aicli_token", token, { httpOnly: true, sameSite: "strict", maxAge: 7 * 24 * 3600 * 1e3 });
|
|
3541
|
+
res.json({ success: true, username });
|
|
3542
|
+
});
|
|
3543
|
+
app.post("/api/auth/logout", (_req, res) => {
|
|
3544
|
+
res.clearCookie("aicli_token", { httpOnly: true, sameSite: "strict" });
|
|
3545
|
+
res.json({ success: true });
|
|
3528
3546
|
});
|
|
3529
3547
|
app.get("/api/files", requireAuth, (req, res) => {
|
|
3530
3548
|
const cwd = process.cwd();
|
|
@@ -3765,7 +3783,7 @@ async function startWebServer(options = {}) {
|
|
|
3765
3783
|
handlers.set(tabId, handler);
|
|
3766
3784
|
clearPreAuthTimer();
|
|
3767
3785
|
console.log(` \u2713 User registered & connected: ${username} (tab: ${tabId.slice(0, 12)})`);
|
|
3768
|
-
ws.send(JSON.stringify({ type: "auth_result", success: true, token: newToken, username
|
|
3786
|
+
ws.send(JSON.stringify({ type: "auth_result", success: true, token: newToken, username }));
|
|
3769
3787
|
return;
|
|
3770
3788
|
}
|
|
3771
3789
|
if (action === "token") {
|
|
@@ -3796,7 +3814,7 @@ async function startWebServer(options = {}) {
|
|
|
3796
3814
|
handlers.set(tabId, handler);
|
|
3797
3815
|
clearPreAuthTimer();
|
|
3798
3816
|
console.log(` \u2713 User logged in: ${username} (tab: ${tabId.slice(0, 12)})`);
|
|
3799
|
-
ws.send(JSON.stringify({ type: "auth_result", success: true, token: loginToken, username
|
|
3817
|
+
ws.send(JSON.stringify({ type: "auth_result", success: true, token: loginToken, username }));
|
|
3800
3818
|
return;
|
|
3801
3819
|
}
|
|
3802
3820
|
ws.send(JSON.stringify({ type: "auth_result", success: false, error: "Unknown auth action" }));
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
getDangerLevel,
|
|
5
5
|
googleSearchContext,
|
|
6
6
|
truncateOutput
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QJ42A4GF.js";
|
|
8
8
|
import "./chunk-3BICTI5M.js";
|
|
9
9
|
import "./chunk-2DXY7UGF.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-7JPMYNVW.js";
|
|
11
11
|
import "./chunk-2ZD3YTVM.js";
|
|
12
12
|
import {
|
|
13
13
|
SUBAGENT_ALLOWED_TOOLS
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-76UBRJUT.js";
|
|
15
15
|
import "./chunk-4BKXL7SM.js";
|
|
16
16
|
import "./chunk-ANYYM4CF.js";
|
|
17
17
|
import "./chunk-KHYD3WXE.js";
|
package/dist/web/client/app.js
CHANGED
|
@@ -8,7 +8,13 @@
|
|
|
8
8
|
let ws = null;
|
|
9
9
|
let connected = false;
|
|
10
10
|
let processing = false;
|
|
11
|
-
|
|
11
|
+
// M4 fix (v0.4.107): the auth token now lives only in an httpOnly cookie.
|
|
12
|
+
// `authToken` remains as a legacy variable so existing call sites compile,
|
|
13
|
+
// but it should always be empty — the cookie is what authenticates the WS
|
|
14
|
+
// upgrade and HTTP requests via `credentials: 'same-origin'`.
|
|
15
|
+
let authToken = '';
|
|
16
|
+
// Clear any legacy localStorage token from an older client.
|
|
17
|
+
try { localStorage.removeItem('aicli-auth-token'); } catch {}
|
|
12
18
|
let authUsername = localStorage.getItem('aicli-auth-user') || '';
|
|
13
19
|
let authMode = 'login'; // 'login' or 'register'
|
|
14
20
|
let currentAssistantEl = null;
|
|
@@ -2718,11 +2724,15 @@ function toggleAuthMode() {
|
|
|
2718
2724
|
updateAuthForm();
|
|
2719
2725
|
}
|
|
2720
2726
|
|
|
2721
|
-
|
|
2727
|
+
// M4 fix (v0.4.107): auth now goes through HTTP /api/auth/{login,register}
|
|
2728
|
+
// so the server can set an httpOnly cookie. The WS upgrade automatically
|
|
2729
|
+
// forwards the cookie. Token is no longer in JSON / localStorage / JS-cookie.
|
|
2730
|
+
async function handleAuth(event) {
|
|
2722
2731
|
event.preventDefault();
|
|
2723
2732
|
const username = document.getElementById('auth-username').value.trim();
|
|
2724
2733
|
const password = document.getElementById('auth-password').value;
|
|
2725
2734
|
const errorEl = document.getElementById('auth-error');
|
|
2735
|
+
const submitBtn = document.getElementById('auth-submit');
|
|
2726
2736
|
|
|
2727
2737
|
if (!username || !password) {
|
|
2728
2738
|
errorEl.textContent = 'Please enter username and password';
|
|
@@ -2731,32 +2741,57 @@ function handleAuth(event) {
|
|
|
2731
2741
|
}
|
|
2732
2742
|
|
|
2733
2743
|
errorEl.classList.add('hidden');
|
|
2734
|
-
|
|
2744
|
+
submitBtn.disabled = true;
|
|
2735
2745
|
|
|
2736
|
-
|
|
2746
|
+
try {
|
|
2747
|
+
const path = authMode === 'register' ? '/api/auth/register' : '/api/auth/login';
|
|
2748
|
+
const resp = await fetch(path, {
|
|
2749
|
+
method: 'POST',
|
|
2750
|
+
headers: { 'content-type': 'application/json' },
|
|
2751
|
+
credentials: 'same-origin', // ensure Set-Cookie is honored
|
|
2752
|
+
body: JSON.stringify({ username, password }),
|
|
2753
|
+
});
|
|
2754
|
+
const data = await resp.json().catch(() => ({}));
|
|
2755
|
+
if (!resp.ok || !data.success) {
|
|
2756
|
+
errorEl.textContent = data.error || `Authentication failed (HTTP ${resp.status})`;
|
|
2757
|
+
errorEl.classList.remove('hidden');
|
|
2758
|
+
submitBtn.disabled = false;
|
|
2759
|
+
return;
|
|
2760
|
+
}
|
|
2761
|
+
authUsername = data.username;
|
|
2762
|
+
// Cookie is httpOnly — we cannot read it from JS, and that's the point.
|
|
2763
|
+
// Drop any legacy localStorage token (M4 cleanup).
|
|
2764
|
+
localStorage.removeItem('aicli-auth-token');
|
|
2765
|
+
localStorage.setItem('aicli-auth-user', data.username);
|
|
2766
|
+
submitBtn.disabled = false;
|
|
2767
|
+
hideAuthScreen();
|
|
2768
|
+
// Reconnect WS so the upgrade request sends the new cookie.
|
|
2769
|
+
if (ws) ws.close();
|
|
2770
|
+
} catch (err) {
|
|
2771
|
+
errorEl.textContent = (err && err.message) ? err.message : 'Network error';
|
|
2772
|
+
errorEl.classList.remove('hidden');
|
|
2773
|
+
submitBtn.disabled = false;
|
|
2774
|
+
}
|
|
2737
2775
|
}
|
|
2738
2776
|
|
|
2777
|
+
// Legacy WS auth_result handler — kept for backwards-compat with clients/
|
|
2778
|
+
// flows that still hit the WS auth path. Token field, if present, is ignored.
|
|
2739
2779
|
function handleAuthResult(msg) {
|
|
2740
2780
|
const errorEl = document.getElementById('auth-error');
|
|
2741
2781
|
const submitBtn = document.getElementById('auth-submit');
|
|
2742
|
-
submitBtn.disabled = false;
|
|
2782
|
+
if (submitBtn) submitBtn.disabled = false;
|
|
2743
2783
|
|
|
2744
2784
|
if (msg.success) {
|
|
2745
|
-
authToken = msg.token;
|
|
2746
2785
|
authUsername = msg.username;
|
|
2747
|
-
localStorage.
|
|
2786
|
+
localStorage.removeItem('aicli-auth-token'); // M4: never store token
|
|
2748
2787
|
localStorage.setItem('aicli-auth-user', msg.username);
|
|
2749
|
-
// Set cookie for secure WebSocket auth (httpOnly cookie set by server on HTTP login,
|
|
2750
|
-
// but for WS-only login, set a JS cookie as fallback)
|
|
2751
|
-
if (msg.setCookie && msg.token) {
|
|
2752
|
-
document.cookie = `aicli_token=${encodeURIComponent(msg.token)}; path=/; max-age=${7 * 24 * 3600}; SameSite=Strict`;
|
|
2753
|
-
}
|
|
2754
2788
|
hideAuthScreen();
|
|
2755
|
-
// Request session list now that we're authenticated
|
|
2756
2789
|
requestSessionList();
|
|
2757
2790
|
} else {
|
|
2758
|
-
errorEl
|
|
2759
|
-
|
|
2791
|
+
if (errorEl) {
|
|
2792
|
+
errorEl.textContent = msg.error || 'Authentication failed';
|
|
2793
|
+
errorEl.classList.remove('hidden');
|
|
2794
|
+
}
|
|
2760
2795
|
}
|
|
2761
2796
|
}
|
|
2762
2797
|
|
|
@@ -2774,14 +2809,16 @@ function updateUserMenu() {
|
|
|
2774
2809
|
}
|
|
2775
2810
|
}
|
|
2776
2811
|
|
|
2777
|
-
function handleLogout() {
|
|
2812
|
+
async function handleLogout() {
|
|
2813
|
+
// M4 fix (v0.4.107): only the server can clear an httpOnly cookie.
|
|
2814
|
+
try {
|
|
2815
|
+
await fetch('/api/auth/logout', { method: 'POST', credentials: 'same-origin' });
|
|
2816
|
+
} catch { /* ignore — close WS anyway */ }
|
|
2778
2817
|
authToken = '';
|
|
2779
2818
|
authUsername = '';
|
|
2780
|
-
localStorage.removeItem('aicli-auth-token');
|
|
2781
|
-
document.cookie = 'aicli_token=; path=/; max-age=0'; // Clear auth cookie
|
|
2819
|
+
localStorage.removeItem('aicli-auth-token'); // legacy cleanup
|
|
2782
2820
|
localStorage.removeItem('aicli-auth-user');
|
|
2783
2821
|
sessionStorage.removeItem('aicli-active-session');
|
|
2784
|
-
// Reconnect — server will send auth_required
|
|
2785
2822
|
if (ws) ws.close();
|
|
2786
2823
|
}
|
|
2787
2824
|
|
|
@@ -2849,9 +2886,12 @@ function showEnableAuthDialog() {
|
|
|
2849
2886
|
const password = prompt('Password (min 4 chars):');
|
|
2850
2887
|
if (!password) return;
|
|
2851
2888
|
|
|
2889
|
+
// M4 fix (v0.4.107): credentials:'same-origin' lets the httpOnly cookie
|
|
2890
|
+
// come back; we no longer touch the token.
|
|
2852
2891
|
fetch('/api/auth/register', {
|
|
2853
2892
|
method: 'POST',
|
|
2854
2893
|
headers: { 'Content-Type': 'application/json' },
|
|
2894
|
+
credentials: 'same-origin',
|
|
2855
2895
|
body: JSON.stringify({ username, password }),
|
|
2856
2896
|
})
|
|
2857
2897
|
.then(r => r.json())
|
|
@@ -2860,14 +2900,12 @@ function showEnableAuthDialog() {
|
|
|
2860
2900
|
alert('Error: ' + data.error);
|
|
2861
2901
|
return;
|
|
2862
2902
|
}
|
|
2863
|
-
// Save token and reconnect with auth
|
|
2864
|
-
authToken = data.token;
|
|
2865
2903
|
authUsername = data.username;
|
|
2866
|
-
localStorage.
|
|
2904
|
+
localStorage.removeItem('aicli-auth-token');
|
|
2867
2905
|
localStorage.setItem('aicli-auth-user', data.username);
|
|
2868
2906
|
document.getElementById('btn-enable-auth').classList.add('hidden');
|
|
2869
2907
|
updateUserMenu();
|
|
2870
|
-
// Reconnect
|
|
2908
|
+
// Reconnect — WS upgrade will pick up the new httpOnly cookie.
|
|
2871
2909
|
if (ws) ws.close();
|
|
2872
2910
|
alert('✓ Auth enabled! User "' + data.username + '" created. Other users can register from the login screen.');
|
|
2873
2911
|
})
|