jinzd-ai-cli 0.4.83 → 0.4.85

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,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConfigManager
4
- } from "./chunk-AQDUA2NT.js";
4
+ } from "./chunk-APU36NHI.js";
5
5
  import "./chunk-2ZD3YTVM.js";
6
- import "./chunk-MNL53XPD.js";
6
+ import "./chunk-XEXVG3CQ.js";
7
7
 
8
8
  // src/cli/batch.ts
9
9
  import Anthropic from "@anthropic-ai/sdk";
@@ -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.83";
9
+ var VERSION = "0.4.85";
10
10
  var APP_NAME = "ai-cli";
11
11
  var CONFIG_DIR_NAME = ".aicli";
12
12
  var CONFIG_FILE_NAME = "config.json";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  schemaToJsonSchema,
4
4
  truncateForPersist
5
- } from "./chunk-H3CIS4XQ.js";
5
+ } from "./chunk-YBL4QDLD.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-MNL53XPD.js";
21
+ } from "./chunk-XEXVG3CQ.js";
22
22
 
23
23
  // src/providers/claude.ts
24
24
  import Anthropic from "@anthropic-ai/sdk";
@@ -8,7 +8,7 @@ import {
8
8
  CONFIG_FILE_NAME,
9
9
  HISTORY_DIR_NAME,
10
10
  PLUGINS_DIR_NAME
11
- } from "./chunk-MNL53XPD.js";
11
+ } from "./chunk-XEXVG3CQ.js";
12
12
 
13
13
  // src/config/config-manager.ts
14
14
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-MNL53XPD.js";
4
+ } from "./chunk-XEXVG3CQ.js";
5
5
 
6
6
  // src/tools/builtin/run-tests.ts
7
7
  import { execSync } from "child_process";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/core/constants.ts
4
- var VERSION = "0.4.83";
4
+ var VERSION = "0.4.85";
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-BXN2BJAI.js";
22
+ } from "./chunk-AX7T3J7G.js";
23
23
  import {
24
24
  CONFIG_DIR_NAME,
25
25
  DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
@@ -27,7 +27,56 @@ import {
27
27
  SUBAGENT_ALLOWED_TOOLS,
28
28
  SUBAGENT_DEFAULT_MAX_ROUNDS,
29
29
  SUBAGENT_MAX_ROUNDS_LIMIT
30
- } from "./chunk-MNL53XPD.js";
30
+ } from "./chunk-XEXVG3CQ.js";
31
+
32
+ // src/tools/types.ts
33
+ function isFileWriteTool(name) {
34
+ return name === "write_file" || name === "edit_file" || name === "notebook_edit";
35
+ }
36
+ function getDangerLevel(toolName, args) {
37
+ if (toolName.startsWith("mcp__")) return "safe";
38
+ if (toolName === "bash") {
39
+ const cmd = String(args["command"] ?? "");
40
+ if (/\brm\s+[^\n]*(?:-\w*[rRfF]\w*|--recursive|--force)\b/.test(cmd)) return "destructive";
41
+ if (/\brm\s+\S/.test(cmd)) return "destructive";
42
+ if (/\brmdir\b|\bformat\b|\bmkfs\b/.test(cmd)) return "destructive";
43
+ if (/\bRemove-Item\b.*(?:-Recurse|-Force)|\bri\s+.*-(?:Recurse|Force)\b|\brd\s+\/s\b|\brmdir\s+\/s\b/i.test(cmd)) return "destructive";
44
+ if (/\bdel\s+\S/.test(cmd)) return "destructive";
45
+ if (/\becho\b.*>>?|\btee\b|\bcp\b|\bmv\b/.test(cmd)) return "write";
46
+ if (/\bSet-Content\b|\bOut-File\b|\bAdd-Content\b|\bCopy-Item\b|\bMove-Item\b/i.test(cmd)) return "write";
47
+ return "safe";
48
+ }
49
+ if (toolName === "write_file") return "write";
50
+ if (toolName === "edit_file") return "write";
51
+ if (toolName === "save_last_response") return "write";
52
+ if (toolName === "run_interactive") {
53
+ const exe = String(args["executable"] ?? "").toLowerCase();
54
+ if (/\b(rm|rmdir|del|format|mkfs|Remove-Item)\b/i.test(exe)) return "destructive";
55
+ if (/\b(bash|sh|zsh|cmd|powershell|pwsh|python|node|ruby|perl)\b/i.test(exe)) return "write";
56
+ return "write";
57
+ }
58
+ if (toolName === "task_create" || toolName === "task_stop") return "write";
59
+ if (toolName === "task_list") return "safe";
60
+ if (toolName === "git_commit") return "write";
61
+ if (toolName === "git_status" || toolName === "git_diff" || toolName === "git_log") return "safe";
62
+ if (toolName === "notebook_edit") return "write";
63
+ if (toolName === "read_file" || toolName === "list_dir" || toolName === "grep_files" || toolName === "glob_files" || toolName === "web_fetch" || toolName === "save_memory" || toolName === "ask_user" || toolName === "write_todos" || toolName === "google_search" || toolName === "spawn_agent" || toolName === "run_tests") return "safe";
64
+ return "write";
65
+ }
66
+ function schemaToJsonSchema(schema) {
67
+ const result = {
68
+ type: schema.type,
69
+ description: schema.description
70
+ };
71
+ if (schema.enum) result["enum"] = schema.enum;
72
+ if (schema.items) result["items"] = schemaToJsonSchema(schema.items);
73
+ if (schema.properties) {
74
+ result["properties"] = Object.fromEntries(
75
+ Object.entries(schema.properties).map(([k, v]) => [k, schemaToJsonSchema(v)])
76
+ );
77
+ }
78
+ return result;
79
+ }
31
80
 
32
81
  // src/tools/builtin/bash.ts
33
82
  import { execSync } from "child_process";
@@ -383,7 +432,7 @@ function updateCwdFromCommand(command, baseCwd) {
383
432
 
384
433
  // src/tools/builtin/read-file.ts
385
434
  import { readFileSync as readFileSync2, existsSync as existsSync3, statSync as statSync2, readdirSync as readdirSync2 } from "fs";
386
- import { execSync as execSync2 } from "child_process";
435
+ import { execFileSync } from "child_process";
387
436
  import { extname, resolve as resolve2, basename, sep, dirname } from "path";
388
437
  import { homedir } from "os";
389
438
 
@@ -584,7 +633,7 @@ function findSimilarFiles(filePath) {
584
633
  }
585
634
  function tryExtractPdfText(absPath) {
586
635
  try {
587
- const output = execSync2(`pdftotext "${absPath}" -`, {
636
+ const output = execFileSync("pdftotext", [absPath, "-"], {
588
637
  timeout: 15e3,
589
638
  encoding: "utf-8",
590
639
  stdio: ["pipe", "pipe", "pipe"]
@@ -593,8 +642,8 @@ function tryExtractPdfText(absPath) {
593
642
  } catch {
594
643
  }
595
644
  try {
596
- const pyScript = `import sys; exec("try:\\n from pdfminer.high_level import extract_text\\n print(extract_text(sys.argv[1]))\\nexcept: pass")`;
597
- const output = execSync2(`python -c "${pyScript}" "${absPath}"`, {
645
+ const pyScript = 'import sys; exec("try:\\n from pdfminer.high_level import extract_text\\n print(extract_text(sys.argv[1]))\\nexcept: pass")';
646
+ const output = execFileSync("python", ["-c", pyScript, absPath], {
598
647
  timeout: 15e3,
599
648
  encoding: "utf-8",
600
649
  stdio: ["pipe", "pipe", "pipe"],
@@ -760,55 +809,6 @@ function rlInternal(rl) {
760
809
  return rl;
761
810
  }
762
811
 
763
- // src/tools/types.ts
764
- function isFileWriteTool(name) {
765
- return name === "write_file" || name === "edit_file" || name === "notebook_edit";
766
- }
767
- function getDangerLevel(toolName, args) {
768
- if (toolName.startsWith("mcp__")) return "safe";
769
- if (toolName === "bash") {
770
- const cmd = String(args["command"] ?? "");
771
- if (/\brm\s+[^\n]*(?:-\w*[rRfF]\w*|--recursive|--force)\b/.test(cmd)) return "destructive";
772
- if (/\brm\s+\S/.test(cmd)) return "destructive";
773
- if (/\brmdir\b|\bformat\b|\bmkfs\b/.test(cmd)) return "destructive";
774
- if (/\bRemove-Item\b.*(?:-Recurse|-Force)|\bri\s+.*-(?:Recurse|Force)\b|\brd\s+\/s\b|\brmdir\s+\/s\b/i.test(cmd)) return "destructive";
775
- if (/\bdel\s+\S/.test(cmd)) return "destructive";
776
- if (/\becho\b.*>>?|\btee\b|\bcp\b|\bmv\b/.test(cmd)) return "write";
777
- if (/\bSet-Content\b|\bOut-File\b|\bAdd-Content\b|\bCopy-Item\b|\bMove-Item\b/i.test(cmd)) return "write";
778
- return "safe";
779
- }
780
- if (toolName === "write_file") return "write";
781
- if (toolName === "edit_file") return "write";
782
- if (toolName === "save_last_response") return "write";
783
- if (toolName === "run_interactive") {
784
- const exe = String(args["executable"] ?? "").toLowerCase();
785
- if (/\b(rm|rmdir|del|format|mkfs|Remove-Item)\b/i.test(exe)) return "destructive";
786
- if (/\b(bash|sh|zsh|cmd|powershell|pwsh|python|node|ruby|perl)\b/i.test(exe)) return "write";
787
- return "write";
788
- }
789
- if (toolName === "task_create" || toolName === "task_stop") return "write";
790
- if (toolName === "task_list") return "safe";
791
- if (toolName === "git_commit") return "write";
792
- if (toolName === "git_status" || toolName === "git_diff" || toolName === "git_log") return "safe";
793
- if (toolName === "notebook_edit") return "write";
794
- if (toolName === "read_file" || toolName === "list_dir" || toolName === "grep_files" || toolName === "glob_files" || toolName === "web_fetch" || toolName === "save_memory" || toolName === "ask_user" || toolName === "write_todos" || toolName === "google_search" || toolName === "spawn_agent" || toolName === "run_tests") return "safe";
795
- return "write";
796
- }
797
- function schemaToJsonSchema(schema) {
798
- const result = {
799
- type: schema.type,
800
- description: schema.description
801
- };
802
- if (schema.enum) result["enum"] = schema.enum;
803
- if (schema.items) result["items"] = schemaToJsonSchema(schema.items);
804
- if (schema.properties) {
805
- result["properties"] = Object.fromEntries(
806
- Object.entries(schema.properties).map(([k, v]) => [k, schemaToJsonSchema(v)])
807
- );
808
- }
809
- return result;
810
- }
811
-
812
812
  // src/tools/executor-phases.ts
813
813
  function groupCallsByPhase(calls) {
814
814
  const safeParallel = [];
@@ -1008,7 +1008,7 @@ function simpleDiff(oldLines, newLines) {
1008
1008
  }
1009
1009
 
1010
1010
  // src/tools/hooks.ts
1011
- import { execSync as execSync3 } from "child_process";
1011
+ import { execSync as execSync2 } from "child_process";
1012
1012
  function shellEscape(value) {
1013
1013
  return "'" + value.replace(/'/g, "'\\''") + "'";
1014
1014
  }
@@ -1020,7 +1020,7 @@ function runHook(template, vars) {
1020
1020
  cmd = cmd.replace(/\{args\}/g, shellEscape(vars.args ?? ""));
1021
1021
  cmd = cmd.replace(/\{status\}/g, shellEscape(vars.status ?? ""));
1022
1022
  try {
1023
- execSync3(cmd, {
1023
+ execSync2(cmd, {
1024
1024
  timeout: 5e3,
1025
1025
  stdio: ["pipe", "pipe", "pipe"],
1026
1026
  encoding: "utf-8"
@@ -3922,7 +3922,7 @@ var taskStopTool = {
3922
3922
  };
3923
3923
 
3924
3924
  // src/tools/builtin/git-tools.ts
3925
- import { execSync as execSync4 } from "child_process";
3925
+ import { execFileSync as execFileSync2 } from "child_process";
3926
3926
  import { existsSync as existsSync10 } from "fs";
3927
3927
  import { join as join5 } from "path";
3928
3928
  function assertGitRepo(cwd) {
@@ -3938,7 +3938,7 @@ function assertGitRepo(cwd) {
3938
3938
  }
3939
3939
  function runGit(args, cwd, maxBuffer = 10 * 1024 * 1024) {
3940
3940
  try {
3941
- const output = execSync4(`git ${args.map((a) => /\s/.test(a) ? `"${a.replace(/"/g, '\\"')}"` : a).join(" ")}`, {
3941
+ const output = execFileSync2("git", args, {
3942
3942
  cwd,
3943
3943
  encoding: "utf-8",
3944
3944
  maxBuffer,
@@ -36,7 +36,7 @@ import {
36
36
  VERSION,
37
37
  buildUserIdentityPrompt,
38
38
  runTestsTool
39
- } from "./chunk-HF47VUGH.js";
39
+ } from "./chunk-4GMAVGPX.js";
40
40
  import {
41
41
  hasSemanticIndex,
42
42
  semanticSearch
@@ -3581,7 +3581,7 @@ function updateCwdFromCommand(command, baseCwd) {
3581
3581
 
3582
3582
  // src/tools/builtin/read-file.ts
3583
3583
  import { readFileSync as readFileSync4, existsSync as existsSync5, statSync as statSync2, readdirSync as readdirSync3 } from "fs";
3584
- import { execSync as execSync2 } from "child_process";
3584
+ import { execFileSync } from "child_process";
3585
3585
  import { extname, resolve as resolve2, basename, sep, dirname } from "path";
3586
3586
  import { homedir as homedir2 } from "os";
3587
3587
 
@@ -3782,7 +3782,7 @@ function findSimilarFiles(filePath) {
3782
3782
  }
3783
3783
  function tryExtractPdfText(absPath) {
3784
3784
  try {
3785
- const output = execSync2(`pdftotext "${absPath}" -`, {
3785
+ const output = execFileSync("pdftotext", [absPath, "-"], {
3786
3786
  timeout: 15e3,
3787
3787
  encoding: "utf-8",
3788
3788
  stdio: ["pipe", "pipe", "pipe"]
@@ -3791,8 +3791,8 @@ function tryExtractPdfText(absPath) {
3791
3791
  } catch {
3792
3792
  }
3793
3793
  try {
3794
- const pyScript = `import sys; exec("try:\\n from pdfminer.high_level import extract_text\\n print(extract_text(sys.argv[1]))\\nexcept: pass")`;
3795
- const output = execSync2(`python -c "${pyScript}" "${absPath}"`, {
3794
+ const pyScript = 'import sys; exec("try:\\n from pdfminer.high_level import extract_text\\n print(extract_text(sys.argv[1]))\\nexcept: pass")';
3795
+ const output = execFileSync("python", ["-c", pyScript, absPath], {
3796
3796
  timeout: 15e3,
3797
3797
  encoding: "utf-8",
3798
3798
  stdio: ["pipe", "pipe", "pipe"],
@@ -4157,7 +4157,7 @@ function simpleDiff(oldLines, newLines) {
4157
4157
  }
4158
4158
 
4159
4159
  // src/tools/hooks.ts
4160
- import { execSync as execSync3 } from "child_process";
4160
+ import { execSync as execSync2 } from "child_process";
4161
4161
  function shellEscape(value) {
4162
4162
  return "'" + value.replace(/'/g, "'\\''") + "'";
4163
4163
  }
@@ -4169,7 +4169,7 @@ function runHook(template, vars) {
4169
4169
  cmd = cmd.replace(/\{args\}/g, shellEscape(vars.args ?? ""));
4170
4170
  cmd = cmd.replace(/\{status\}/g, shellEscape(vars.status ?? ""));
4171
4171
  try {
4172
- execSync3(cmd, {
4172
+ execSync2(cmd, {
4173
4173
  timeout: 5e3,
4174
4174
  stdio: ["pipe", "pipe", "pipe"],
4175
4175
  encoding: "utf-8"
@@ -7032,7 +7032,7 @@ var taskStopTool = {
7032
7032
  };
7033
7033
 
7034
7034
  // src/tools/builtin/git-tools.ts
7035
- import { execSync as execSync4 } from "child_process";
7035
+ import { execFileSync as execFileSync2 } from "child_process";
7036
7036
  import { existsSync as existsSync12 } from "fs";
7037
7037
  import { join as join7 } from "path";
7038
7038
  function assertGitRepo(cwd) {
@@ -7048,7 +7048,7 @@ function assertGitRepo(cwd) {
7048
7048
  }
7049
7049
  function runGit(args, cwd, maxBuffer = 10 * 1024 * 1024) {
7050
7050
  try {
7051
- const output = execSync4(`git ${args.map((a) => /\s/.test(a) ? `"${a.replace(/"/g, '\\"')}"` : a).join(" ")}`, {
7051
+ const output = execFileSync2("git", args, {
7052
7052
  cwd,
7053
7053
  encoding: "utf-8",
7054
7054
  maxBuffer,
@@ -9221,15 +9221,15 @@ function autoTrimSessionIfNeeded(session, sizeLimit = SESSION_SIZE_LIMIT) {
9221
9221
  // src/web/session-handler.ts
9222
9222
  import { existsSync as existsSync20, readFileSync as readFileSync13, appendFileSync as appendFileSync3, writeFileSync as writeFileSync8, mkdirSync as mkdirSync9, readdirSync as readdirSync9, statSync as statSync8 } from "fs";
9223
9223
  import { join as join13, resolve as resolve4 } from "path";
9224
- import { execSync as execSync6 } from "child_process";
9224
+ import { execSync as execSync4 } from "child_process";
9225
9225
 
9226
9226
  // src/tools/git-context.ts
9227
- import { execSync as execSync5 } from "child_process";
9227
+ import { execSync as execSync3 } from "child_process";
9228
9228
  import { existsSync as existsSync19 } from "fs";
9229
9229
  import { join as join12 } from "path";
9230
9230
  function runGit2(cmd, cwd) {
9231
9231
  try {
9232
- return execSync5(`git ${cmd}`, {
9232
+ return execSync3(`git ${cmd}`, {
9233
9233
  cwd,
9234
9234
  encoding: "utf-8",
9235
9235
  stdio: ["pipe", "pipe", "pipe"],
@@ -10953,7 +10953,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
10953
10953
  let diff;
10954
10954
  try {
10955
10955
  const cmd = staged ? "git diff --staged" : "git diff";
10956
- diff = execSync6(cmd, { encoding: "utf-8", timeout: 1e4 }).trim();
10956
+ diff = execSync4(cmd, { encoding: "utf-8", timeout: 1e4 }).trim();
10957
10957
  } catch {
10958
10958
  this.send({ type: "error", message: "Failed to run git diff." });
10959
10959
  break;
@@ -10992,7 +10992,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
10992
10992
  let secDiff;
10993
10993
  try {
10994
10994
  const cmd = secStaged ? "git diff --staged" : "git diff";
10995
- secDiff = execSync6(cmd, { encoding: "utf-8", timeout: 1e4 }).trim();
10995
+ secDiff = execSync4(cmd, { encoding: "utf-8", timeout: 1e4 }).trim();
10996
10996
  } catch {
10997
10997
  this.send({ type: "error", message: "Failed to run git diff." });
10998
10998
  break;
@@ -11070,7 +11070,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
11070
11070
  case "test": {
11071
11071
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
11072
11072
  try {
11073
- const { executeTests } = await import("./run-tests-P2OZOWXA.js");
11073
+ const { executeTests } = await import("./run-tests-PIISCS6B.js");
11074
11074
  const argStr = args.join(" ").trim();
11075
11075
  let testArgs = {};
11076
11076
  if (argStr) {
@@ -385,7 +385,7 @@ ${content}`);
385
385
  }
386
386
  }
387
387
  async function runTaskMode(config, providers, configManager, topic) {
388
- const { TaskOrchestrator } = await import("./task-orchestrator-TT5F2OBH.js");
388
+ const { TaskOrchestrator } = await import("./task-orchestrator-H73NIC6T.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-SEUAEDAI.js";
33
+ } from "./chunk-6IOQPMMT.js";
34
34
  import {
35
35
  ConfigManager
36
- } from "./chunk-AQDUA2NT.js";
36
+ } from "./chunk-APU36NHI.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-H3CIS4XQ.js";
52
+ } from "./chunk-YBL4QDLD.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-BXN2BJAI.js";
61
+ import "./chunk-AX7T3J7G.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-MNL53XPD.js";
83
+ } from "./chunk-XEXVG3CQ.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-6ABISSWK.js");
2595
+ const { executeTests } = await import("./run-tests-KWVQL2PO.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-J2G6B6LP.js");
6488
+ const { startWebServer } = await import("./server-WNL7UU5Q.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-KMEDSLFU.js");
6611
+ const batch = await import("./batch-YBWWF5BJ.js");
6612
6612
  switch (action) {
6613
6613
  case "submit":
6614
6614
  if (!arg) {
@@ -6650,6 +6650,15 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
6650
6650
  process.exit(1);
6651
6651
  }
6652
6652
  });
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");
6655
+ await startMcpServer({
6656
+ allowDestructive: !!options.allowDestructive,
6657
+ allowOutsideCwd: !!options.allowOutsideCwd,
6658
+ tools: options.tools ? options.tools.split(",").map((s) => s.trim()).filter(Boolean) : void 0,
6659
+ cwd: options.cwd
6660
+ });
6661
+ });
6653
6662
  program.command("help").description("Show a comprehensive guide to all aicli features and commands").action(() => {
6654
6663
  const B = "\x1B[1m";
6655
6664
  const D = "\x1B[2m";
@@ -6676,6 +6685,7 @@ program.command("help").description("Show a comprehensive guide to all aicli fea
6676
6685
  ` ${G}aicli sessions${R} List recent conversation sessions`,
6677
6686
  ` ${G}aicli user <action>${R} User management (list/create/delete)`,
6678
6687
  ` ${G}aicli batch <action>${R} Anthropic Batches API (50% off, 24h): submit/list/status/results/cancel`,
6688
+ ` ${G}aicli mcp-serve${R} MCP server over STDIO (expose tools to Claude Desktop / Cursor)`,
6679
6689
  "",
6680
6690
  `${B}${C} \u25A0 STARTUP OPTIONS${R}`,
6681
6691
  ` ${Y}--provider <name>${R} Set AI provider`,
@@ -6768,7 +6778,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
6768
6778
  }),
6769
6779
  config.get("customProviders")
6770
6780
  );
6771
- const { startHub } = await import("./hub-DZMTUFKU.js");
6781
+ const { startHub } = await import("./hub-RCX7G5T6.js");
6772
6782
  await startHub(
6773
6783
  {
6774
6784
  topic: topic ?? "",
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  executeTests,
4
4
  runTestsTool
5
- } from "./chunk-BXN2BJAI.js";
6
- import "./chunk-MNL53XPD.js";
5
+ } from "./chunk-AX7T3J7G.js";
6
+ import "./chunk-XEXVG3CQ.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-HF47VUGH.js";
4
+ } from "./chunk-4GMAVGPX.js";
5
5
  export {
6
6
  executeTests,
7
7
  runTestsTool
@@ -0,0 +1,283 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ToolRegistry,
4
+ getDangerLevel,
5
+ schemaToJsonSchema
6
+ } from "./chunk-YBL4QDLD.js";
7
+ import "./chunk-2ZD3YTVM.js";
8
+ import "./chunk-4BKXL7SM.js";
9
+ import "./chunk-NHNWUBXB.js";
10
+ import "./chunk-CQQQFNND.js";
11
+ import "./chunk-6VRJGH25.js";
12
+ import "./chunk-PFYAAX2S.js";
13
+ import "./chunk-AX7T3J7G.js";
14
+ import {
15
+ VERSION
16
+ } from "./chunk-XEXVG3CQ.js";
17
+
18
+ // src/mcp/server.ts
19
+ import { createInterface } from "readline";
20
+ import { resolve } from "path";
21
+ import { realpathSync } from "fs";
22
+ var STDIN_TOOLS = /* @__PURE__ */ new Set(["ask_user", "spawn_agent"]);
23
+ var MCP_ALWAYS_DESTRUCTIVE = /* @__PURE__ */ new Set([
24
+ "bash",
25
+ "run_interactive",
26
+ "task_create"
27
+ ]);
28
+ var TOOL_PATH_ARGS = {
29
+ read_file: ["path"],
30
+ write_file: ["path"],
31
+ edit_file: ["path"],
32
+ list_dir: ["path"],
33
+ grep_files: ["path"],
34
+ glob_files: ["path"],
35
+ notebook_edit: ["path"],
36
+ save_last_response: ["path"],
37
+ git_status: ["path"],
38
+ git_diff: ["path", "file"],
39
+ git_log: ["path", "file"],
40
+ git_commit: ["path", "files"],
41
+ find_symbol: ["path"],
42
+ get_outline: ["file", "path"],
43
+ find_references: ["path"],
44
+ search_code: ["path"],
45
+ bash: ["cwd"],
46
+ run_interactive: ["cwd"]
47
+ };
48
+ var McpServer = class {
49
+ registry;
50
+ opts;
51
+ initialized = false;
52
+ sandboxRoot;
53
+ eligibleNames;
54
+ constructor(registry, opts = {}) {
55
+ this.registry = registry;
56
+ this.opts = opts;
57
+ this.sandboxRoot = this.resolveSandboxRoot(opts.cwd);
58
+ this.eligibleNames = this.computeEligibleNames();
59
+ }
60
+ resolveSandboxRoot(cwd) {
61
+ const base = cwd ? resolve(cwd) : process.cwd();
62
+ try {
63
+ return realpathSync(base);
64
+ } catch {
65
+ return base;
66
+ }
67
+ }
68
+ computeEligibleNames() {
69
+ const names = /* @__PURE__ */ new Set();
70
+ const whitelist = this.opts.tools && this.opts.tools.length > 0 ? new Set(this.opts.tools) : null;
71
+ for (const tool of this.registry.listAll()) {
72
+ const name = tool.definition.name;
73
+ if (STDIN_TOOLS.has(name)) continue;
74
+ if (whitelist && !whitelist.has(name)) continue;
75
+ names.add(name);
76
+ }
77
+ return names;
78
+ }
79
+ async start() {
80
+ if (this.opts.cwd) {
81
+ try {
82
+ process.chdir(this.opts.cwd);
83
+ } catch {
84
+ }
85
+ }
86
+ const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });
87
+ rl.on("line", async (line) => {
88
+ const trimmed = line.trim();
89
+ if (!trimmed) return;
90
+ let msg;
91
+ try {
92
+ msg = JSON.parse(trimmed);
93
+ } catch {
94
+ this.sendError(null, -32700, "Parse error");
95
+ return;
96
+ }
97
+ await this.dispatch(msg);
98
+ });
99
+ rl.on("close", () => process.exit(0));
100
+ process.stdin.resume();
101
+ this.log(`aicli MCP server v${VERSION} started. sandboxRoot=${this.sandboxRoot}`);
102
+ if (this.opts.allowDestructive) this.log("WARNING: --allow-destructive enabled");
103
+ if (this.opts.allowOutsideCwd) this.log("WARNING: --allow-outside-cwd enabled");
104
+ }
105
+ // ── dispatcher ─────────────────────────────────────────────────────────────
106
+ async dispatch(msg) {
107
+ const id = "id" in msg ? msg["id"] : void 0;
108
+ const method = msg["method"];
109
+ const params = msg["params"] ?? {};
110
+ if (id === void 0) {
111
+ if (method === "notifications/initialized") this.initialized = true;
112
+ return;
113
+ }
114
+ if (!method) {
115
+ this.sendError(id, -32600, "Invalid request: missing method");
116
+ return;
117
+ }
118
+ try {
119
+ switch (method) {
120
+ case "initialize":
121
+ this.handleInitialize(id, params);
122
+ break;
123
+ case "tools/list":
124
+ if (!this.initialized) {
125
+ this.sendError(id, -32002, "Server not initialized");
126
+ break;
127
+ }
128
+ this.handleToolsList(id);
129
+ break;
130
+ case "tools/call":
131
+ if (!this.initialized) {
132
+ this.sendError(id, -32002, "Server not initialized");
133
+ break;
134
+ }
135
+ await this.handleToolCall(id, params);
136
+ break;
137
+ case "ping":
138
+ this.sendResult(id, {});
139
+ break;
140
+ default:
141
+ this.sendError(id, -32601, `Method not found: ${method}`);
142
+ }
143
+ } catch (err) {
144
+ const emsg = err instanceof Error ? err.message : String(err);
145
+ this.sendError(id, -32603, `Internal error: ${emsg}`);
146
+ }
147
+ }
148
+ // ── handlers ───────────────────────────────────────────────────────────────
149
+ handleInitialize(id, _params) {
150
+ this.initialized = true;
151
+ this.sendResult(id, {
152
+ protocolVersion: "2024-11-05",
153
+ capabilities: { tools: {} },
154
+ serverInfo: { name: "aicli", version: VERSION }
155
+ });
156
+ }
157
+ handleToolsList(id) {
158
+ const tools = [...this.eligibleNames].map((n) => this.registry.get(n)).filter((t) => !!t);
159
+ const list = tools.map((tool) => {
160
+ const params = tool.definition.parameters;
161
+ const properties = {};
162
+ const required = [];
163
+ for (const [key, schema] of Object.entries(params)) {
164
+ properties[key] = schemaToJsonSchema(schema);
165
+ if (schema.required) required.push(key);
166
+ }
167
+ return {
168
+ name: tool.definition.name,
169
+ description: tool.definition.description,
170
+ inputSchema: {
171
+ type: "object",
172
+ properties,
173
+ ...required.length > 0 ? { required } : {}
174
+ }
175
+ };
176
+ });
177
+ this.sendResult(id, { tools: list });
178
+ }
179
+ async handleToolCall(id, params) {
180
+ const name = params["name"];
181
+ const args = params["arguments"] ?? {};
182
+ if (!name) {
183
+ this.sendError(id, -32602, "Missing required param: name");
184
+ return;
185
+ }
186
+ if (!this.eligibleNames.has(name)) {
187
+ this.sendError(id, -32602, `Tool not exposed: ${name}`);
188
+ return;
189
+ }
190
+ const tool = this.registry.get(name);
191
+ if (!tool) {
192
+ this.sendError(id, -32602, `Unknown tool: ${name}`);
193
+ return;
194
+ }
195
+ const forcedDestructive = MCP_ALWAYS_DESTRUCTIVE.has(name);
196
+ const level = forcedDestructive ? "destructive" : getDangerLevel(name, args);
197
+ if (level === "destructive" && !this.opts.allowDestructive) {
198
+ this.sendResult(id, {
199
+ content: [{ type: "text", text: `Tool '${name}' requires --allow-destructive in MCP mode.` }],
200
+ isError: true
201
+ });
202
+ return;
203
+ }
204
+ const pathErr = this.validatePathArgs(name, args);
205
+ if (pathErr) {
206
+ this.sendResult(id, {
207
+ content: [{ type: "text", text: pathErr }],
208
+ isError: true
209
+ });
210
+ return;
211
+ }
212
+ try {
213
+ const output = await tool.execute(args);
214
+ this.sendResult(id, {
215
+ content: [{ type: "text", text: output }]
216
+ });
217
+ } catch (err) {
218
+ const text = err instanceof Error ? err.message : String(err);
219
+ this.sendResult(id, {
220
+ content: [{ type: "text", text }],
221
+ isError: true
222
+ });
223
+ }
224
+ }
225
+ /**
226
+ * Validate that every known path-bearing argument of `toolName` resolves
227
+ * inside the sandbox root. Returns an error message on violation, else undef.
228
+ *
229
+ * We do NOT realpath() per-call: write_file targets may not exist yet, and
230
+ * realpath on every call is a syscall per arg. The root itself is realpath'd
231
+ * once at construction, which stops the "sandbox root is a symlink pointing
232
+ * elsewhere" class of attack. Symlinks inside the tree are allowed.
233
+ */
234
+ validatePathArgs(toolName, args) {
235
+ if (this.opts.allowOutsideCwd) return void 0;
236
+ const keys = TOOL_PATH_ARGS[toolName];
237
+ if (!keys) return void 0;
238
+ for (const key of keys) {
239
+ const value = args[key];
240
+ if (value === void 0 || value === null) continue;
241
+ const list = Array.isArray(value) ? value : [value];
242
+ for (const entry of list) {
243
+ if (typeof entry !== "string" || entry.length === 0) continue;
244
+ const abs = resolve(this.sandboxRoot, entry);
245
+ if (!this.isInsideSandbox(abs)) {
246
+ return `Path '${entry}' escapes sandbox root '${this.sandboxRoot}'. Pass --allow-outside-cwd to permit.`;
247
+ }
248
+ }
249
+ }
250
+ return void 0;
251
+ }
252
+ isInsideSandbox(abs) {
253
+ const norm = process.platform === "win32" ? abs.toLowerCase() : abs;
254
+ const root = process.platform === "win32" ? this.sandboxRoot.toLowerCase() : this.sandboxRoot;
255
+ if (norm === root) return true;
256
+ const sep = process.platform === "win32" ? "\\" : "/";
257
+ return norm.startsWith(root + sep);
258
+ }
259
+ // ── transport ──────────────────────────────────────────────────────────────
260
+ sendResult(id, result) {
261
+ this.write({ jsonrpc: "2.0", id, result });
262
+ }
263
+ sendError(id, code, message) {
264
+ this.write({ jsonrpc: "2.0", id, error: { code, message } });
265
+ }
266
+ write(obj) {
267
+ process.stdout.write(JSON.stringify(obj) + "\n");
268
+ }
269
+ /** MCP servers must use stderr for diagnostics so stdout stays JSON-RPC clean. */
270
+ log(msg) {
271
+ process.stderr.write(`[aicli-mcp] ${msg}
272
+ `);
273
+ }
274
+ };
275
+ async function startMcpServer(opts) {
276
+ const registry = new ToolRegistry();
277
+ const server = new McpServer(registry, opts);
278
+ await server.start();
279
+ }
280
+ export {
281
+ McpServer,
282
+ startMcpServer
283
+ };
@@ -20,10 +20,10 @@ import {
20
20
  persistToolRound,
21
21
  rebuildExtraMessages,
22
22
  setupProxy
23
- } from "./chunk-SEUAEDAI.js";
23
+ } from "./chunk-6IOQPMMT.js";
24
24
  import {
25
25
  ConfigManager
26
- } from "./chunk-AQDUA2NT.js";
26
+ } from "./chunk-APU36NHI.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-H3CIS4XQ.js";
44
+ } from "./chunk-YBL4QDLD.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-BXN2BJAI.js";
51
+ import "./chunk-AX7T3J7G.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-MNL53XPD.js";
70
+ } from "./chunk-XEXVG3CQ.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-6ABISSWK.js");
2232
+ const { executeTests } = await import("./run-tests-KWVQL2PO.js");
2233
2233
  const argStr = args.join(" ").trim();
2234
2234
  let testArgs = {};
2235
2235
  if (argStr) {
@@ -4,17 +4,17 @@ import {
4
4
  getDangerLevel,
5
5
  googleSearchContext,
6
6
  truncateOutput
7
- } from "./chunk-H3CIS4XQ.js";
7
+ } from "./chunk-YBL4QDLD.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-BXN2BJAI.js";
14
+ import "./chunk-AX7T3J7G.js";
15
15
  import {
16
16
  SUBAGENT_ALLOWED_TOOLS
17
- } from "./chunk-MNL53XPD.js";
17
+ } from "./chunk-XEXVG3CQ.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.83",
3
+ "version": "0.4.85",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",