jinzd-ai-cli 0.4.85 → 0.4.87

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.
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConfigManager
4
- } from "./chunk-APU36NHI.js";
4
+ } from "./chunk-Y75YPB5F.js";
5
5
  import "./chunk-2ZD3YTVM.js";
6
- import "./chunk-XEXVG3CQ.js";
6
+ import "./chunk-BAOIXQHD.js";
7
7
 
8
8
  // src/cli/batch.ts
9
9
  import Anthropic from "@anthropic-ai/sdk";
10
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
10
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, renameSync, unlinkSync } from "fs";
11
11
  import { join } from "path";
12
12
  function parseBatchInput(jsonl) {
13
13
  const lines = jsonl.split("\n").map((l) => l.trim()).filter(Boolean);
@@ -72,7 +72,18 @@ function loadTrackedBatches(config) {
72
72
  }
73
73
  function saveTrackedBatches(config, batches) {
74
74
  mkdirSync(config.getConfigDir(), { recursive: true });
75
- writeFileSync(getBatchesPath(config), JSON.stringify({ batches }, null, 2), "utf-8");
75
+ const finalPath = getBatchesPath(config);
76
+ const tmpPath = `${finalPath}.tmp.${process.pid}.${Date.now()}`;
77
+ try {
78
+ writeFileSync(tmpPath, JSON.stringify({ batches }, null, 2), "utf-8");
79
+ renameSync(tmpPath, finalPath);
80
+ } catch (err) {
81
+ try {
82
+ unlinkSync(tmpPath);
83
+ } catch {
84
+ }
85
+ throw err;
86
+ }
76
87
  }
77
88
  function getClaudeClient(config) {
78
89
  const apiKey = config.getApiKey("claude");
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  schemaToJsonSchema,
4
4
  truncateForPersist
5
- } from "./chunk-YBL4QDLD.js";
5
+ } from "./chunk-SP6RFAKW.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-XEXVG3CQ.js";
21
+ } from "./chunk-BAOIXQHD.js";
22
22
 
23
23
  // src/providers/claude.ts
24
24
  import Anthropic from "@anthropic-ai/sdk";
@@ -1291,17 +1291,41 @@ var DeepSeekProvider = class extends OpenAICompatibleProvider {
1291
1291
  // src/providers/zhipu.ts
1292
1292
  var ZhipuProvider = class extends OpenAICompatibleProvider {
1293
1293
  defaultBaseUrl = "https://open.bigmodel.cn/api/paas/v4";
1294
- // GLM-5 等深度思考模型生成长内容需要较长时间,默认 5 分钟
1294
+ // GLM-5 / GLM-5.1 等深度思考模型生成长内容需要较长时间,默认 5 分钟
1295
1295
  defaultTimeout = 3e5;
1296
1296
  info = {
1297
1297
  id: "zhipu",
1298
1298
  displayName: "Zhipu (GLM)",
1299
- defaultModel: "glm-5",
1299
+ // 默认选 GLM-4.6:中文写作口碑最稳 + 200K 上下文 + 价格只有 5.1 的 ~1/2。
1300
+ // 需要 Agent 长跑 / 代码工程时再手动 /model glm-5.1。
1301
+ defaultModel: "glm-4.6",
1300
1302
  apiKeyEnvVar: "AICLI_API_KEY_ZHIPU",
1301
1303
  requiresApiKey: true,
1302
1304
  baseUrl: this.defaultBaseUrl,
1303
1305
  models: [
1304
- // GLM-5 旗舰系列(最新,支持深度思考)
1306
+ // ── GLM-5.1 系列(2026-04 旗舰,主打长程 Agent + 代码工程) ──
1307
+ {
1308
+ id: "glm-5.1",
1309
+ displayName: "GLM-5.1 (2026 Flagship, 200K, Agent+Code)",
1310
+ contextWindow: 204800,
1311
+ supportsStreaming: true,
1312
+ supportsThinking: true
1313
+ },
1314
+ {
1315
+ id: "glm-5.1-reasoning",
1316
+ displayName: "GLM-5.1 Reasoning (Deep Thinking)",
1317
+ contextWindow: 204800,
1318
+ supportsStreaming: true,
1319
+ supportsThinking: true
1320
+ },
1321
+ {
1322
+ id: "glm-5.1-air",
1323
+ displayName: "GLM-5.1 Air (Lightweight 5.1)",
1324
+ contextWindow: 204800,
1325
+ supportsStreaming: true,
1326
+ supportsThinking: true
1327
+ },
1328
+ // ── GLM-5 系列(2026-02) ──
1305
1329
  {
1306
1330
  id: "glm-5",
1307
1331
  displayName: "GLM-5 (Flagship, Deep Thinking)",
@@ -1309,7 +1333,13 @@ var ZhipuProvider = class extends OpenAICompatibleProvider {
1309
1333
  supportsStreaming: true,
1310
1334
  supportsThinking: true
1311
1335
  },
1312
- // GLM-4.6 系列(视觉 + 思考)
1336
+ // ── GLM-4.6 系列(2025-09,中文写作口碑最佳) ──
1337
+ {
1338
+ id: "glm-4.6",
1339
+ displayName: "GLM-4.6 (200K, \u4E2D\u6587\u5199\u4F5C\u63A8\u8350)",
1340
+ contextWindow: 204800,
1341
+ supportsStreaming: true
1342
+ },
1313
1343
  {
1314
1344
  id: "glm-4.6v",
1315
1345
  displayName: "GLM-4.6V (Vision + Thinking)",
@@ -1317,7 +1347,7 @@ var ZhipuProvider = class extends OpenAICompatibleProvider {
1317
1347
  supportsStreaming: true,
1318
1348
  supportsThinking: true
1319
1349
  },
1320
- // GLM-Z1 推理系列(支持深度思考)
1350
+ // ── GLM-Z1 推理系列 ──
1321
1351
  {
1322
1352
  id: "glm-z1",
1323
1353
  displayName: "GLM-Z1 (Reasoning Flagship)",
@@ -1339,7 +1369,7 @@ var ZhipuProvider = class extends OpenAICompatibleProvider {
1339
1369
  supportsStreaming: true,
1340
1370
  supportsThinking: true
1341
1371
  },
1342
- // GLM-4 系列(稳定)
1372
+ // ── GLM-4 系列(稳定,价格低) ──
1343
1373
  {
1344
1374
  id: "glm-4-plus",
1345
1375
  displayName: "GLM-4 Plus",
@@ -3653,7 +3683,15 @@ var PRICING_TABLE = {
3653
3683
  "glm-4": { input: 0.14, output: 0.14 },
3654
3684
  "glm-4-flash": { input: 0, output: 0 },
3655
3685
  "glm-4.5": { input: 0.29, output: 1.14 },
3656
- "glm-4.6": { input: 0.6, output: 2.2 }
3686
+ "glm-4.6": { input: 0.6, output: 2.2 },
3687
+ "glm-4.6v": { input: 0.6, output: 2.2 },
3688
+ "glm-5": { input: 0.85, output: 2.85 },
3689
+ "glm-5.1": { input: 0.95, output: 3.15 },
3690
+ "glm-5.1-reasoning": { input: 1.4, output: 4.4 },
3691
+ "glm-5.1-air": { input: 0.4, output: 1.2 },
3692
+ "glm-z1": { input: 0.5, output: 1.5 },
3693
+ "glm-z1-air": { input: 0.2, output: 0.6 },
3694
+ "glm-z1-flash": { input: 0, output: 0 }
3657
3695
  // ── OpenRouter (pass-through — actual cost depends on underlying model) ──
3658
3696
  // Left empty; callers should resolve via underlying model ID.
3659
3697
  // ── Ollama (local, zero cost) ─────────────────────────────────
@@ -6,7 +6,7 @@ import { platform } from "os";
6
6
  import chalk from "chalk";
7
7
 
8
8
  // src/core/constants.ts
9
- var VERSION = "0.4.85";
9
+ var VERSION = "0.4.87";
10
10
  var APP_NAME = "ai-cli";
11
11
  var CONFIG_DIR_NAME = ".aicli";
12
12
  var CONFIG_FILE_NAME = "config.json";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/core/constants.ts
4
- var VERSION = "0.4.85";
4
+ var VERSION = "0.4.87";
5
5
  var APP_NAME = "ai-cli";
6
6
  var CONFIG_DIR_NAME = ".aicli";
7
7
  var CONFIG_FILE_NAME = "config.json";
@@ -19,7 +19,7 @@ import {
19
19
  } from "./chunk-6VRJGH25.js";
20
20
  import {
21
21
  runTestsTool
22
- } from "./chunk-AX7T3J7G.js";
22
+ } from "./chunk-TFLBQRQM.js";
23
23
  import {
24
24
  CONFIG_DIR_NAME,
25
25
  DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
@@ -27,7 +27,7 @@ import {
27
27
  SUBAGENT_ALLOWED_TOOLS,
28
28
  SUBAGENT_DEFAULT_MAX_ROUNDS,
29
29
  SUBAGENT_MAX_ROUNDS_LIMIT
30
- } from "./chunk-XEXVG3CQ.js";
30
+ } from "./chunk-BAOIXQHD.js";
31
31
 
32
32
  // src/tools/types.ts
33
33
  function isFileWriteTool(name) {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-XEXVG3CQ.js";
4
+ } from "./chunk-BAOIXQHD.js";
5
5
 
6
6
  // src/tools/builtin/run-tests.ts
7
7
  import { execSync } from "child_process";
@@ -8,7 +8,7 @@ import {
8
8
  CONFIG_FILE_NAME,
9
9
  HISTORY_DIR_NAME,
10
10
  PLUGINS_DIR_NAME
11
- } from "./chunk-XEXVG3CQ.js";
11
+ } from "./chunk-BAOIXQHD.js";
12
12
 
13
13
  // src/config/config-manager.ts
14
14
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
@@ -36,7 +36,7 @@ import {
36
36
  VERSION,
37
37
  buildUserIdentityPrompt,
38
38
  runTestsTool
39
- } from "./chunk-4GMAVGPX.js";
39
+ } from "./chunk-AQX3GYRD.js";
40
40
  import {
41
41
  hasSemanticIndex,
42
42
  semanticSearch
@@ -1779,17 +1779,41 @@ var DeepSeekProvider = class extends OpenAICompatibleProvider {
1779
1779
  // src/providers/zhipu.ts
1780
1780
  var ZhipuProvider = class extends OpenAICompatibleProvider {
1781
1781
  defaultBaseUrl = "https://open.bigmodel.cn/api/paas/v4";
1782
- // GLM-5 等深度思考模型生成长内容需要较长时间,默认 5 分钟
1782
+ // GLM-5 / GLM-5.1 等深度思考模型生成长内容需要较长时间,默认 5 分钟
1783
1783
  defaultTimeout = 3e5;
1784
1784
  info = {
1785
1785
  id: "zhipu",
1786
1786
  displayName: "Zhipu (GLM)",
1787
- defaultModel: "glm-5",
1787
+ // 默认选 GLM-4.6:中文写作口碑最稳 + 200K 上下文 + 价格只有 5.1 的 ~1/2。
1788
+ // 需要 Agent 长跑 / 代码工程时再手动 /model glm-5.1。
1789
+ defaultModel: "glm-4.6",
1788
1790
  apiKeyEnvVar: "AICLI_API_KEY_ZHIPU",
1789
1791
  requiresApiKey: true,
1790
1792
  baseUrl: this.defaultBaseUrl,
1791
1793
  models: [
1792
- // GLM-5 旗舰系列(最新,支持深度思考)
1794
+ // ── GLM-5.1 系列(2026-04 旗舰,主打长程 Agent + 代码工程) ──
1795
+ {
1796
+ id: "glm-5.1",
1797
+ displayName: "GLM-5.1 (2026 Flagship, 200K, Agent+Code)",
1798
+ contextWindow: 204800,
1799
+ supportsStreaming: true,
1800
+ supportsThinking: true
1801
+ },
1802
+ {
1803
+ id: "glm-5.1-reasoning",
1804
+ displayName: "GLM-5.1 Reasoning (Deep Thinking)",
1805
+ contextWindow: 204800,
1806
+ supportsStreaming: true,
1807
+ supportsThinking: true
1808
+ },
1809
+ {
1810
+ id: "glm-5.1-air",
1811
+ displayName: "GLM-5.1 Air (Lightweight 5.1)",
1812
+ contextWindow: 204800,
1813
+ supportsStreaming: true,
1814
+ supportsThinking: true
1815
+ },
1816
+ // ── GLM-5 系列(2026-02) ──
1793
1817
  {
1794
1818
  id: "glm-5",
1795
1819
  displayName: "GLM-5 (Flagship, Deep Thinking)",
@@ -1797,7 +1821,13 @@ var ZhipuProvider = class extends OpenAICompatibleProvider {
1797
1821
  supportsStreaming: true,
1798
1822
  supportsThinking: true
1799
1823
  },
1800
- // GLM-4.6 系列(视觉 + 思考)
1824
+ // ── GLM-4.6 系列(2025-09,中文写作口碑最佳) ──
1825
+ {
1826
+ id: "glm-4.6",
1827
+ displayName: "GLM-4.6 (200K, \u4E2D\u6587\u5199\u4F5C\u63A8\u8350)",
1828
+ contextWindow: 204800,
1829
+ supportsStreaming: true
1830
+ },
1801
1831
  {
1802
1832
  id: "glm-4.6v",
1803
1833
  displayName: "GLM-4.6V (Vision + Thinking)",
@@ -1805,7 +1835,7 @@ var ZhipuProvider = class extends OpenAICompatibleProvider {
1805
1835
  supportsStreaming: true,
1806
1836
  supportsThinking: true
1807
1837
  },
1808
- // GLM-Z1 推理系列(支持深度思考)
1838
+ // ── GLM-Z1 推理系列 ──
1809
1839
  {
1810
1840
  id: "glm-z1",
1811
1841
  displayName: "GLM-Z1 (Reasoning Flagship)",
@@ -1827,7 +1857,7 @@ var ZhipuProvider = class extends OpenAICompatibleProvider {
1827
1857
  supportsStreaming: true,
1828
1858
  supportsThinking: true
1829
1859
  },
1830
- // GLM-4 系列(稳定)
1860
+ // ── GLM-4 系列(稳定,价格低) ──
1831
1861
  {
1832
1862
  id: "glm-4-plus",
1833
1863
  displayName: "GLM-4 Plus",
@@ -9035,7 +9065,15 @@ var PRICING_TABLE = {
9035
9065
  "glm-4": { input: 0.14, output: 0.14 },
9036
9066
  "glm-4-flash": { input: 0, output: 0 },
9037
9067
  "glm-4.5": { input: 0.29, output: 1.14 },
9038
- "glm-4.6": { input: 0.6, output: 2.2 }
9068
+ "glm-4.6": { input: 0.6, output: 2.2 },
9069
+ "glm-4.6v": { input: 0.6, output: 2.2 },
9070
+ "glm-5": { input: 0.85, output: 2.85 },
9071
+ "glm-5.1": { input: 0.95, output: 3.15 },
9072
+ "glm-5.1-reasoning": { input: 1.4, output: 4.4 },
9073
+ "glm-5.1-air": { input: 0.4, output: 1.2 },
9074
+ "glm-z1": { input: 0.5, output: 1.5 },
9075
+ "glm-z1-air": { input: 0.2, output: 0.6 },
9076
+ "glm-z1-flash": { input: 0, output: 0 }
9039
9077
  // ── OpenRouter (pass-through — actual cost depends on underlying model) ──
9040
9078
  // Left empty; callers should resolve via underlying model ID.
9041
9079
  // ── Ollama (local, zero cost) ─────────────────────────────────
@@ -11070,7 +11108,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
11070
11108
  case "test": {
11071
11109
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
11072
11110
  try {
11073
- const { executeTests } = await import("./run-tests-PIISCS6B.js");
11111
+ const { executeTests } = await import("./run-tests-P7GIZ6UH.js");
11074
11112
  const argStr = args.join(" ").trim();
11075
11113
  let testArgs = {};
11076
11114
  if (argStr) {
@@ -12238,7 +12276,11 @@ async function startWebServer(options = {}) {
12238
12276
  };
12239
12277
  const app = express();
12240
12278
  const server = createServer(app);
12241
- const wss = new WebSocketServer({ server });
12279
+ const WS_MAX_PAYLOAD = 1 * 1024 * 1024;
12280
+ const WS_MSG_RATE_PER_SEC = 30;
12281
+ const WS_MSG_BURST = 60;
12282
+ const WS_PREAUTH_TIMEOUT_MS = 3e4;
12283
+ const wss = new WebSocketServer({ server, maxPayload: WS_MAX_PAYLOAD });
12242
12284
  const authManager = new AuthManager(config.getConfigDir());
12243
12285
  if (authManager.isEnabled()) {
12244
12286
  console.log(` Auth: ${authManager.listUsers().length} user(s) registered`);
@@ -12337,9 +12379,11 @@ async function startWebServer(options = {}) {
12337
12379
  res.json({ files: [] });
12338
12380
  }
12339
12381
  });
12340
- app.get("/api/sessions", requireAuth, (_req, res) => {
12382
+ app.get("/api/sessions", requireAuth, (req, res) => {
12341
12383
  try {
12342
- const list = sessions.listSessions();
12384
+ const authUser = req._authUser;
12385
+ const sm = authUser ? getUserShared(authUser).sessions : sessions;
12386
+ const list = sm.listSessions();
12343
12387
  res.json({
12344
12388
  sessions: list.slice(0, 50).map((s) => ({
12345
12389
  id: s.id,
@@ -12368,6 +12412,17 @@ async function startWebServer(options = {}) {
12368
12412
  res.status(404).json({ error: "Session not found" });
12369
12413
  return;
12370
12414
  }
12415
+ try {
12416
+ const canonicalFile = realpathSync(filePath);
12417
+ const canonicalDir = realpathSync(histDir);
12418
+ if (!canonicalFile.startsWith(canonicalDir + sep2)) {
12419
+ res.status(404).json({ error: "Session not found" });
12420
+ return;
12421
+ }
12422
+ } catch {
12423
+ res.status(404).json({ error: "Session not found" });
12424
+ return;
12425
+ }
12371
12426
  const data = JSON.parse(readFileSync15(filePath, "utf-8"));
12372
12427
  res.json({ session: data });
12373
12428
  } catch (err) {
@@ -12444,8 +12499,35 @@ async function startWebServer(options = {}) {
12444
12499
  existing.onDisconnect();
12445
12500
  handlers.delete(tabId);
12446
12501
  }
12502
+ let tokens = WS_MSG_BURST;
12503
+ let lastRefill = Date.now();
12504
+ const takeToken = () => {
12505
+ const now = Date.now();
12506
+ const refill = (now - lastRefill) / 1e3 * WS_MSG_RATE_PER_SEC;
12507
+ if (refill > 0) {
12508
+ tokens = Math.min(WS_MSG_BURST, tokens + refill);
12509
+ lastRefill = now;
12510
+ }
12511
+ if (tokens < 1) return false;
12512
+ tokens -= 1;
12513
+ return true;
12514
+ };
12447
12515
  let authenticatedUser = null;
12448
12516
  let handler = null;
12517
+ let preAuthTimer = setTimeout(() => {
12518
+ if (!handler && ws.readyState === ws.OPEN) {
12519
+ try {
12520
+ ws.close(1008, "auth timeout");
12521
+ } catch {
12522
+ }
12523
+ }
12524
+ }, WS_PREAUTH_TIMEOUT_MS);
12525
+ const clearPreAuthTimer = () => {
12526
+ if (preAuthTimer) {
12527
+ clearTimeout(preAuthTimer);
12528
+ preAuthTimer = null;
12529
+ }
12530
+ };
12449
12531
  if (token) {
12450
12532
  authenticatedUser = authManager.verifyToken(token);
12451
12533
  }
@@ -12454,11 +12536,13 @@ async function startWebServer(options = {}) {
12454
12536
  console.log(` \u2713 Tab connected: ${tabId.slice(0, 12)} (no auth) (total: ${handlers.size + 1})`);
12455
12537
  handler = new SessionHandler(ws, shared);
12456
12538
  handlers.set(tabId, handler);
12539
+ clearPreAuthTimer();
12457
12540
  } else if (authenticatedUser) {
12458
12541
  console.log(` \u2713 Tab connected: ${tabId.slice(0, 12)} (user: ${authenticatedUser}) (total: ${handlers.size + 1})`);
12459
12542
  const userShared = getUserShared(authenticatedUser);
12460
12543
  handler = new SessionHandler(ws, userShared);
12461
12544
  handlers.set(tabId, handler);
12545
+ clearPreAuthTimer();
12462
12546
  } else {
12463
12547
  console.log(` \u23F3 Tab waiting auth: ${tabId.slice(0, 12)}`);
12464
12548
  if (ws.readyState === ws.OPEN) {
@@ -12469,6 +12553,15 @@ async function startWebServer(options = {}) {
12469
12553
  }
12470
12554
  }
12471
12555
  ws.on("message", async (data) => {
12556
+ if (!takeToken()) {
12557
+ if (ws.readyState === ws.OPEN) {
12558
+ try {
12559
+ ws.close(1008, "rate limit exceeded");
12560
+ } catch {
12561
+ }
12562
+ }
12563
+ return;
12564
+ }
12472
12565
  try {
12473
12566
  const raw = data.toString();
12474
12567
  const parsed = JSON.parse(raw);
@@ -12491,6 +12584,7 @@ async function startWebServer(options = {}) {
12491
12584
  const userShared = getUserShared(username);
12492
12585
  handler = new SessionHandler(ws, userShared);
12493
12586
  handlers.set(tabId, handler);
12587
+ clearPreAuthTimer();
12494
12588
  console.log(` \u2713 User registered & connected: ${username} (tab: ${tabId.slice(0, 12)})`);
12495
12589
  ws.send(JSON.stringify({ type: "auth_result", success: true, token: newToken, username, setCookie: true }));
12496
12590
  return;
@@ -12506,6 +12600,7 @@ async function startWebServer(options = {}) {
12506
12600
  const userShared = getUserShared(verifiedUser);
12507
12601
  handler = new SessionHandler(ws, userShared);
12508
12602
  handlers.set(tabId, handler);
12603
+ clearPreAuthTimer();
12509
12604
  console.log(` \u2713 Token auth: ${verifiedUser} (tab: ${tabId.slice(0, 12)})`);
12510
12605
  ws.send(JSON.stringify({ type: "auth_result", success: true, token: clientToken, username: verifiedUser }));
12511
12606
  return;
@@ -12520,6 +12615,7 @@ async function startWebServer(options = {}) {
12520
12615
  const userShared = getUserShared(username);
12521
12616
  handler = new SessionHandler(ws, userShared);
12522
12617
  handlers.set(tabId, handler);
12618
+ clearPreAuthTimer();
12523
12619
  console.log(` \u2713 User logged in: ${username} (tab: ${tabId.slice(0, 12)})`);
12524
12620
  ws.send(JSON.stringify({ type: "auth_result", success: true, token: loginToken, username, setCookie: true }));
12525
12621
  return;
@@ -12546,6 +12642,7 @@ async function startWebServer(options = {}) {
12546
12642
  }
12547
12643
  });
12548
12644
  ws.on("close", () => {
12645
+ clearPreAuthTimer();
12549
12646
  console.log(` \u2717 Tab disconnected: ${tabId.slice(0, 12)} (total: ${handlers.size - 1})`);
12550
12647
  if (handler) handler.onDisconnect();
12551
12648
  handlers.delete(tabId);
@@ -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-H73NIC6T.js");
388
+ const { TaskOrchestrator } = await import("./task-orchestrator-36SFPCP7.js");
389
389
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
390
390
  let interrupted = false;
391
391
  const onSigint = () => {
package/dist/index.js CHANGED
@@ -30,10 +30,10 @@ import {
30
30
  saveDevState,
31
31
  sessionHasMeaningfulContent,
32
32
  setupProxy
33
- } from "./chunk-6IOQPMMT.js";
33
+ } from "./chunk-3DGNN4RM.js";
34
34
  import {
35
35
  ConfigManager
36
- } from "./chunk-APU36NHI.js";
36
+ } from "./chunk-Y75YPB5F.js";
37
37
  import {
38
38
  ToolExecutor,
39
39
  ToolRegistry,
@@ -49,7 +49,7 @@ import {
49
49
  spawnAgentContext,
50
50
  theme,
51
51
  undoStack
52
- } from "./chunk-YBL4QDLD.js";
52
+ } from "./chunk-SP6RFAKW.js";
53
53
  import "./chunk-2ZD3YTVM.js";
54
54
  import {
55
55
  fileCheckpoints
@@ -58,7 +58,7 @@ import "./chunk-NHNWUBXB.js";
58
58
  import "./chunk-CQQQFNND.js";
59
59
  import "./chunk-6VRJGH25.js";
60
60
  import "./chunk-PFYAAX2S.js";
61
- import "./chunk-AX7T3J7G.js";
61
+ import "./chunk-TFLBQRQM.js";
62
62
  import {
63
63
  AGENTIC_BEHAVIOR_GUIDELINE,
64
64
  AUTHOR,
@@ -80,7 +80,7 @@ import {
80
80
  SKILLS_DIR_NAME,
81
81
  VERSION,
82
82
  buildUserIdentityPrompt
83
- } from "./chunk-XEXVG3CQ.js";
83
+ } from "./chunk-BAOIXQHD.js";
84
84
 
85
85
  // src/index.ts
86
86
  import { program } from "commander";
@@ -2592,7 +2592,7 @@ ${hint}` : "")
2592
2592
  usage: "/test [command|filter]",
2593
2593
  async execute(args, ctx) {
2594
2594
  try {
2595
- const { executeTests } = await import("./run-tests-KWVQL2PO.js");
2595
+ const { executeTests } = await import("./run-tests-7PTRRO4D.js");
2596
2596
  const argStr = args.join(" ").trim();
2597
2597
  let testArgs = {};
2598
2598
  if (argStr) {
@@ -6485,7 +6485,7 @@ program.command("web").description("Start Web UI server with browser-based chat
6485
6485
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
6486
6486
  process.exit(1);
6487
6487
  }
6488
- const { startWebServer } = await import("./server-WNL7UU5Q.js");
6488
+ const { startWebServer } = await import("./server-TRTN3RVO.js");
6489
6489
  await startWebServer({ port, host: options.host });
6490
6490
  });
6491
6491
  program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | migrate <name>)").action(async (action, username) => {
@@ -6608,7 +6608,7 @@ program.command("sessions").description("List recent conversation sessions").act
6608
6608
  });
6609
6609
  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) => {
6610
6610
  try {
6611
- const batch = await import("./batch-YBWWF5BJ.js");
6611
+ const batch = await import("./batch-FNHSLCMV.js");
6612
6612
  switch (action) {
6613
6613
  case "submit":
6614
6614
  if (!arg) {
@@ -6651,7 +6651,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
6651
6651
  }
6652
6652
  });
6653
6653
  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) => {
6654
- const { startMcpServer } = await import("./server-GAKP7VZ7.js");
6654
+ const { startMcpServer } = await import("./server-GJRBVTTQ.js");
6655
6655
  await startMcpServer({
6656
6656
  allowDestructive: !!options.allowDestructive,
6657
6657
  allowOutsideCwd: !!options.allowOutsideCwd,
@@ -6778,7 +6778,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
6778
6778
  }),
6779
6779
  config.get("customProviders")
6780
6780
  );
6781
- const { startHub } = await import("./hub-RCX7G5T6.js");
6781
+ const { startHub } = await import("./hub-HEC4GYKR.js");
6782
6782
  await startHub(
6783
6783
  {
6784
6784
  topic: topic ?? "",
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  executeTests,
4
4
  runTestsTool
5
- } from "./chunk-AX7T3J7G.js";
6
- import "./chunk-XEXVG3CQ.js";
5
+ } from "./chunk-TFLBQRQM.js";
6
+ import "./chunk-BAOIXQHD.js";
7
7
  export {
8
8
  executeTests,
9
9
  runTestsTool
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  executeTests,
3
3
  runTestsTool
4
- } from "./chunk-4GMAVGPX.js";
4
+ } from "./chunk-AQX3GYRD.js";
5
5
  export {
6
6
  executeTests,
7
7
  runTestsTool
@@ -3,17 +3,17 @@ import {
3
3
  ToolRegistry,
4
4
  getDangerLevel,
5
5
  schemaToJsonSchema
6
- } from "./chunk-YBL4QDLD.js";
6
+ } from "./chunk-SP6RFAKW.js";
7
7
  import "./chunk-2ZD3YTVM.js";
8
8
  import "./chunk-4BKXL7SM.js";
9
9
  import "./chunk-NHNWUBXB.js";
10
10
  import "./chunk-CQQQFNND.js";
11
11
  import "./chunk-6VRJGH25.js";
12
12
  import "./chunk-PFYAAX2S.js";
13
- import "./chunk-AX7T3J7G.js";
13
+ import "./chunk-TFLBQRQM.js";
14
14
  import {
15
15
  VERSION
16
- } from "./chunk-XEXVG3CQ.js";
16
+ } from "./chunk-BAOIXQHD.js";
17
17
 
18
18
  // src/mcp/server.ts
19
19
  import { createInterface } from "readline";
@@ -20,10 +20,10 @@ import {
20
20
  persistToolRound,
21
21
  rebuildExtraMessages,
22
22
  setupProxy
23
- } from "./chunk-6IOQPMMT.js";
23
+ } from "./chunk-3DGNN4RM.js";
24
24
  import {
25
25
  ConfigManager
26
- } from "./chunk-APU36NHI.js";
26
+ } from "./chunk-Y75YPB5F.js";
27
27
  import {
28
28
  ToolExecutor,
29
29
  ToolRegistry,
@@ -41,14 +41,14 @@ import {
41
41
  spawnAgentContext,
42
42
  truncateOutput,
43
43
  undoStack
44
- } from "./chunk-YBL4QDLD.js";
44
+ } from "./chunk-SP6RFAKW.js";
45
45
  import "./chunk-2ZD3YTVM.js";
46
46
  import "./chunk-4BKXL7SM.js";
47
47
  import "./chunk-NHNWUBXB.js";
48
48
  import "./chunk-CQQQFNND.js";
49
49
  import "./chunk-6VRJGH25.js";
50
50
  import "./chunk-PFYAAX2S.js";
51
- import "./chunk-AX7T3J7G.js";
51
+ import "./chunk-TFLBQRQM.js";
52
52
  import {
53
53
  AGENTIC_BEHAVIOR_GUIDELINE,
54
54
  AUTHOR,
@@ -67,7 +67,7 @@ import {
67
67
  SKILLS_DIR_NAME,
68
68
  VERSION,
69
69
  buildUserIdentityPrompt
70
- } from "./chunk-XEXVG3CQ.js";
70
+ } from "./chunk-BAOIXQHD.js";
71
71
  import {
72
72
  AuthManager
73
73
  } from "./chunk-BYNY5JPB.js";
@@ -2229,7 +2229,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
2229
2229
  case "test": {
2230
2230
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
2231
2231
  try {
2232
- const { executeTests } = await import("./run-tests-KWVQL2PO.js");
2232
+ const { executeTests } = await import("./run-tests-7PTRRO4D.js");
2233
2233
  const argStr = args.join(" ").trim();
2234
2234
  let testArgs = {};
2235
2235
  if (argStr) {
@@ -3175,7 +3175,11 @@ async function startWebServer(options = {}) {
3175
3175
  };
3176
3176
  const app = express();
3177
3177
  const server = createServer(app);
3178
- const wss = new WebSocketServer({ server });
3178
+ const WS_MAX_PAYLOAD = 1 * 1024 * 1024;
3179
+ const WS_MSG_RATE_PER_SEC = 30;
3180
+ const WS_MSG_BURST = 60;
3181
+ const WS_PREAUTH_TIMEOUT_MS = 3e4;
3182
+ const wss = new WebSocketServer({ server, maxPayload: WS_MAX_PAYLOAD });
3179
3183
  const authManager = new AuthManager(config.getConfigDir());
3180
3184
  if (authManager.isEnabled()) {
3181
3185
  console.log(` Auth: ${authManager.listUsers().length} user(s) registered`);
@@ -3274,9 +3278,11 @@ async function startWebServer(options = {}) {
3274
3278
  res.json({ files: [] });
3275
3279
  }
3276
3280
  });
3277
- app.get("/api/sessions", requireAuth, (_req, res) => {
3281
+ app.get("/api/sessions", requireAuth, (req, res) => {
3278
3282
  try {
3279
- const list = sessions.listSessions();
3283
+ const authUser = req._authUser;
3284
+ const sm = authUser ? getUserShared(authUser).sessions : sessions;
3285
+ const list = sm.listSessions();
3280
3286
  res.json({
3281
3287
  sessions: list.slice(0, 50).map((s) => ({
3282
3288
  id: s.id,
@@ -3305,6 +3311,17 @@ async function startWebServer(options = {}) {
3305
3311
  res.status(404).json({ error: "Session not found" });
3306
3312
  return;
3307
3313
  }
3314
+ try {
3315
+ const canonicalFile = realpathSync(filePath);
3316
+ const canonicalDir = realpathSync(histDir);
3317
+ if (!canonicalFile.startsWith(canonicalDir + sep)) {
3318
+ res.status(404).json({ error: "Session not found" });
3319
+ return;
3320
+ }
3321
+ } catch {
3322
+ res.status(404).json({ error: "Session not found" });
3323
+ return;
3324
+ }
3308
3325
  const data = JSON.parse(readFileSync4(filePath, "utf-8"));
3309
3326
  res.json({ session: data });
3310
3327
  } catch (err) {
@@ -3381,8 +3398,35 @@ async function startWebServer(options = {}) {
3381
3398
  existing.onDisconnect();
3382
3399
  handlers.delete(tabId);
3383
3400
  }
3401
+ let tokens = WS_MSG_BURST;
3402
+ let lastRefill = Date.now();
3403
+ const takeToken = () => {
3404
+ const now = Date.now();
3405
+ const refill = (now - lastRefill) / 1e3 * WS_MSG_RATE_PER_SEC;
3406
+ if (refill > 0) {
3407
+ tokens = Math.min(WS_MSG_BURST, tokens + refill);
3408
+ lastRefill = now;
3409
+ }
3410
+ if (tokens < 1) return false;
3411
+ tokens -= 1;
3412
+ return true;
3413
+ };
3384
3414
  let authenticatedUser = null;
3385
3415
  let handler = null;
3416
+ let preAuthTimer = setTimeout(() => {
3417
+ if (!handler && ws.readyState === ws.OPEN) {
3418
+ try {
3419
+ ws.close(1008, "auth timeout");
3420
+ } catch {
3421
+ }
3422
+ }
3423
+ }, WS_PREAUTH_TIMEOUT_MS);
3424
+ const clearPreAuthTimer = () => {
3425
+ if (preAuthTimer) {
3426
+ clearTimeout(preAuthTimer);
3427
+ preAuthTimer = null;
3428
+ }
3429
+ };
3386
3430
  if (token) {
3387
3431
  authenticatedUser = authManager.verifyToken(token);
3388
3432
  }
@@ -3391,11 +3435,13 @@ async function startWebServer(options = {}) {
3391
3435
  console.log(` \u2713 Tab connected: ${tabId.slice(0, 12)} (no auth) (total: ${handlers.size + 1})`);
3392
3436
  handler = new SessionHandler(ws, shared);
3393
3437
  handlers.set(tabId, handler);
3438
+ clearPreAuthTimer();
3394
3439
  } else if (authenticatedUser) {
3395
3440
  console.log(` \u2713 Tab connected: ${tabId.slice(0, 12)} (user: ${authenticatedUser}) (total: ${handlers.size + 1})`);
3396
3441
  const userShared = getUserShared(authenticatedUser);
3397
3442
  handler = new SessionHandler(ws, userShared);
3398
3443
  handlers.set(tabId, handler);
3444
+ clearPreAuthTimer();
3399
3445
  } else {
3400
3446
  console.log(` \u23F3 Tab waiting auth: ${tabId.slice(0, 12)}`);
3401
3447
  if (ws.readyState === ws.OPEN) {
@@ -3406,6 +3452,15 @@ async function startWebServer(options = {}) {
3406
3452
  }
3407
3453
  }
3408
3454
  ws.on("message", async (data) => {
3455
+ if (!takeToken()) {
3456
+ if (ws.readyState === ws.OPEN) {
3457
+ try {
3458
+ ws.close(1008, "rate limit exceeded");
3459
+ } catch {
3460
+ }
3461
+ }
3462
+ return;
3463
+ }
3409
3464
  try {
3410
3465
  const raw = data.toString();
3411
3466
  const parsed = JSON.parse(raw);
@@ -3428,6 +3483,7 @@ async function startWebServer(options = {}) {
3428
3483
  const userShared = getUserShared(username);
3429
3484
  handler = new SessionHandler(ws, userShared);
3430
3485
  handlers.set(tabId, handler);
3486
+ clearPreAuthTimer();
3431
3487
  console.log(` \u2713 User registered & connected: ${username} (tab: ${tabId.slice(0, 12)})`);
3432
3488
  ws.send(JSON.stringify({ type: "auth_result", success: true, token: newToken, username, setCookie: true }));
3433
3489
  return;
@@ -3443,6 +3499,7 @@ async function startWebServer(options = {}) {
3443
3499
  const userShared = getUserShared(verifiedUser);
3444
3500
  handler = new SessionHandler(ws, userShared);
3445
3501
  handlers.set(tabId, handler);
3502
+ clearPreAuthTimer();
3446
3503
  console.log(` \u2713 Token auth: ${verifiedUser} (tab: ${tabId.slice(0, 12)})`);
3447
3504
  ws.send(JSON.stringify({ type: "auth_result", success: true, token: clientToken, username: verifiedUser }));
3448
3505
  return;
@@ -3457,6 +3514,7 @@ async function startWebServer(options = {}) {
3457
3514
  const userShared = getUserShared(username);
3458
3515
  handler = new SessionHandler(ws, userShared);
3459
3516
  handlers.set(tabId, handler);
3517
+ clearPreAuthTimer();
3460
3518
  console.log(` \u2713 User logged in: ${username} (tab: ${tabId.slice(0, 12)})`);
3461
3519
  ws.send(JSON.stringify({ type: "auth_result", success: true, token: loginToken, username, setCookie: true }));
3462
3520
  return;
@@ -3483,6 +3541,7 @@ async function startWebServer(options = {}) {
3483
3541
  }
3484
3542
  });
3485
3543
  ws.on("close", () => {
3544
+ clearPreAuthTimer();
3486
3545
  console.log(` \u2717 Tab disconnected: ${tabId.slice(0, 12)} (total: ${handlers.size - 1})`);
3487
3546
  if (handler) handler.onDisconnect();
3488
3547
  handlers.delete(tabId);
@@ -4,17 +4,17 @@ import {
4
4
  getDangerLevel,
5
5
  googleSearchContext,
6
6
  truncateOutput
7
- } from "./chunk-YBL4QDLD.js";
7
+ } from "./chunk-SP6RFAKW.js";
8
8
  import "./chunk-2ZD3YTVM.js";
9
9
  import "./chunk-4BKXL7SM.js";
10
10
  import "./chunk-NHNWUBXB.js";
11
11
  import "./chunk-CQQQFNND.js";
12
12
  import "./chunk-6VRJGH25.js";
13
13
  import "./chunk-PFYAAX2S.js";
14
- import "./chunk-AX7T3J7G.js";
14
+ import "./chunk-TFLBQRQM.js";
15
15
  import {
16
16
  SUBAGENT_ALLOWED_TOOLS
17
- } from "./chunk-XEXVG3CQ.js";
17
+ } from "./chunk-BAOIXQHD.js";
18
18
 
19
19
  // src/hub/task-orchestrator.ts
20
20
  import { createInterface } from "readline";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.4.85",
3
+ "version": "0.4.87",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",