jinzd-ai-cli 0.4.75 → 0.4.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -1
- package/dist/{chunk-C4MGON2N.js → chunk-5PZMIBEN.js} +2 -2
- package/dist/chunk-6VRJGH25.js +115 -0
- package/dist/chunk-BJAT4GNC.js +113 -0
- package/dist/chunk-HPDDAXFY.js +84 -0
- package/dist/{chunk-E6RP5DBU.js → chunk-IR5EW57V.js} +15 -3
- package/dist/{chunk-MPIUYP6Q.js → chunk-LKDX2GOW.js} +305 -9
- package/dist/{chunk-ASNDBI5R.js → chunk-LQ76WLB6.js} +1 -1
- package/dist/chunk-NHNWUBXB.js +431 -0
- package/dist/chunk-PFYAAX2S.js +169 -0
- package/dist/{chunk-3BHGEPIT.js → chunk-QATT4NCL.js} +1 -1
- package/dist/chunk-RFQVUMDB.js +430 -0
- package/dist/{chunk-5P4QTZBI.js → chunk-S4WDPHKS.js} +15 -3
- package/dist/chunk-UTCC3UMT.js +83 -0
- package/dist/chunk-XMA222FQ.js +167 -0
- package/dist/{hub-W3BF22UV.js → hub-CZSXSOIH.js} +1 -1
- package/dist/index.js +137 -13
- package/dist/{run-tests-V2JJADIU.js → run-tests-GEZ4NPWJ.js} +2 -2
- package/dist/{run-tests-LEYTZHPU.js → run-tests-RHAXFEOL.js} +1 -1
- package/dist/{server-2XO72FRP.js → server-CMSF65WV.js} +86 -10
- package/dist/{task-orchestrator-277NWVSE.js → task-orchestrator-VC7LCN5J.js} +8 -4
- package/dist/wasm/tree-sitter-javascript.wasm +0 -0
- package/dist/wasm/tree-sitter-python.wasm +0 -0
- package/dist/wasm/tree-sitter-tsx.wasm +0 -0
- package/dist/wasm/tree-sitter-typescript.wasm +0 -0
- package/dist/wasm/web-tree-sitter.wasm +0 -0
- package/package.json +10 -2
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
fileCheckpoints
|
|
4
|
-
} from "./chunk-4BKXL7SM.js";
|
|
5
|
-
import {
|
|
6
|
-
runTestsTool
|
|
7
|
-
} from "./chunk-3BHGEPIT.js";
|
|
8
2
|
import {
|
|
9
3
|
EnvLoader,
|
|
10
4
|
NetworkError,
|
|
11
5
|
ToolError
|
|
12
6
|
} from "./chunk-2ZD3YTVM.js";
|
|
7
|
+
import {
|
|
8
|
+
fileCheckpoints
|
|
9
|
+
} from "./chunk-4BKXL7SM.js";
|
|
10
|
+
import {
|
|
11
|
+
indexProject
|
|
12
|
+
} from "./chunk-NHNWUBXB.js";
|
|
13
|
+
import {
|
|
14
|
+
hasSemanticIndex,
|
|
15
|
+
semanticSearch
|
|
16
|
+
} from "./chunk-HPDDAXFY.js";
|
|
17
|
+
import {
|
|
18
|
+
loadIndex
|
|
19
|
+
} from "./chunk-6VRJGH25.js";
|
|
20
|
+
import {
|
|
21
|
+
runTestsTool
|
|
22
|
+
} from "./chunk-QATT4NCL.js";
|
|
13
23
|
import {
|
|
14
24
|
CONFIG_DIR_NAME,
|
|
15
25
|
DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
|
|
@@ -17,7 +27,7 @@ import {
|
|
|
17
27
|
SUBAGENT_ALLOWED_TOOLS,
|
|
18
28
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
19
29
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
20
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-S4WDPHKS.js";
|
|
21
31
|
|
|
22
32
|
// src/tools/builtin/bash.ts
|
|
23
33
|
import { execSync } from "child_process";
|
|
@@ -1028,8 +1038,8 @@ function checkPermission(toolName, args, dangerLevel, rules, defaultAction = "co
|
|
|
1028
1038
|
if (rule.when) {
|
|
1029
1039
|
if (rule.when.dangerLevel && rule.when.dangerLevel !== dangerLevel) continue;
|
|
1030
1040
|
if (rule.when.pathPattern) {
|
|
1031
|
-
const
|
|
1032
|
-
if (!
|
|
1041
|
+
const path3 = String(args["path"] ?? args["command"] ?? "");
|
|
1042
|
+
if (!path3.includes(rule.when.pathPattern)) continue;
|
|
1033
1043
|
}
|
|
1034
1044
|
}
|
|
1035
1045
|
return rule.action;
|
|
@@ -1729,6 +1739,13 @@ Important: For long content (over 500 lines or 3000 chars), you MUST split into
|
|
|
1729
1739
|
}
|
|
1730
1740
|
const lines = content.split("\n").length;
|
|
1731
1741
|
const mode = appendMode ? "appended" : "written";
|
|
1742
|
+
void (async () => {
|
|
1743
|
+
try {
|
|
1744
|
+
const { updateFile } = await import("./indexer-C7QYYHSZ.js");
|
|
1745
|
+
await updateFile(process.cwd(), filePath);
|
|
1746
|
+
} catch {
|
|
1747
|
+
}
|
|
1748
|
+
})();
|
|
1732
1749
|
return `File ${mode}: ${filePath} (${lines} lines, ${content.length} bytes)`;
|
|
1733
1750
|
}
|
|
1734
1751
|
};
|
|
@@ -4286,6 +4303,281 @@ var notebookEditTool = {
|
|
|
4286
4303
|
}
|
|
4287
4304
|
};
|
|
4288
4305
|
|
|
4306
|
+
// src/tools/builtin/symbol-tools.ts
|
|
4307
|
+
import path2 from "path";
|
|
4308
|
+
|
|
4309
|
+
// src/symbols/queries.ts
|
|
4310
|
+
import path from "path";
|
|
4311
|
+
import fs from "fs";
|
|
4312
|
+
function findSymbol(index, opts) {
|
|
4313
|
+
const name = opts.name.toLowerCase();
|
|
4314
|
+
const exact = opts.exact !== false;
|
|
4315
|
+
const kinds = opts.kind ? new Set(Array.isArray(opts.kind) ? opts.kind : [opts.kind]) : null;
|
|
4316
|
+
const limit = opts.limit ?? 50;
|
|
4317
|
+
const out = [];
|
|
4318
|
+
for (const s of index.symbols) {
|
|
4319
|
+
if (kinds && !kinds.has(s.kind)) continue;
|
|
4320
|
+
const lower = s.name.toLowerCase();
|
|
4321
|
+
if (exact ? lower === name : lower.includes(name)) {
|
|
4322
|
+
out.push(s);
|
|
4323
|
+
if (out.length >= limit) break;
|
|
4324
|
+
}
|
|
4325
|
+
}
|
|
4326
|
+
return out;
|
|
4327
|
+
}
|
|
4328
|
+
function getOutline(index, file) {
|
|
4329
|
+
const abs = path.resolve(file);
|
|
4330
|
+
return index.symbols.filter((s) => s.location.file === abs).sort((a, b) => a.location.line - b.location.line).map((s) => ({
|
|
4331
|
+
name: s.name,
|
|
4332
|
+
kind: s.kind,
|
|
4333
|
+
line: s.location.line,
|
|
4334
|
+
signature: s.signature,
|
|
4335
|
+
container: s.container,
|
|
4336
|
+
exported: s.exported
|
|
4337
|
+
}));
|
|
4338
|
+
}
|
|
4339
|
+
function findReferences(index, name, opts = {}) {
|
|
4340
|
+
const maxFiles = opts.maxFiles ?? 2e3;
|
|
4341
|
+
const maxHits = opts.maxHits ?? 500;
|
|
4342
|
+
const re = new RegExp(`\\b${name.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")}\\b`);
|
|
4343
|
+
const hits = [];
|
|
4344
|
+
const files = Object.keys(index.files).slice(0, maxFiles);
|
|
4345
|
+
for (const file of files) {
|
|
4346
|
+
let content;
|
|
4347
|
+
try {
|
|
4348
|
+
content = fs.readFileSync(file, "utf-8");
|
|
4349
|
+
} catch {
|
|
4350
|
+
continue;
|
|
4351
|
+
}
|
|
4352
|
+
if (!re.test(content)) continue;
|
|
4353
|
+
const lines = content.split(/\r?\n/);
|
|
4354
|
+
for (let i = 0; i < lines.length; i++) {
|
|
4355
|
+
const m = re.exec(lines[i]);
|
|
4356
|
+
if (m) {
|
|
4357
|
+
hits.push({
|
|
4358
|
+
file,
|
|
4359
|
+
line: i + 1,
|
|
4360
|
+
column: m.index,
|
|
4361
|
+
text: lines[i].trim().slice(0, 200)
|
|
4362
|
+
});
|
|
4363
|
+
if (hits.length >= maxHits) return hits;
|
|
4364
|
+
}
|
|
4365
|
+
}
|
|
4366
|
+
}
|
|
4367
|
+
return hits;
|
|
4368
|
+
}
|
|
4369
|
+
|
|
4370
|
+
// src/tools/builtin/symbol-tools.ts
|
|
4371
|
+
var NO_INDEX_HINT = "No symbol index exists for this project yet. Ask the user to run `/index rebuild`, or call indexProject() first. Alternatively, use grep_files for a slower fallback.";
|
|
4372
|
+
async function ensureIndex(root, autoBuild) {
|
|
4373
|
+
let index = loadIndex(root);
|
|
4374
|
+
if (!index && autoBuild) {
|
|
4375
|
+
const result = await indexProject(root);
|
|
4376
|
+
index = result.index;
|
|
4377
|
+
}
|
|
4378
|
+
return index;
|
|
4379
|
+
}
|
|
4380
|
+
var findSymbolTool = {
|
|
4381
|
+
definition: {
|
|
4382
|
+
name: "find_symbol",
|
|
4383
|
+
description: "Locate symbol definitions (functions, classes, methods, interfaces, types, variables) across the project using the pre-built symbol index. Orders of magnitude faster than grep_files for definition lookups. Returns file:line locations plus a one-line signature.",
|
|
4384
|
+
parameters: {
|
|
4385
|
+
name: {
|
|
4386
|
+
type: "string",
|
|
4387
|
+
description: 'Symbol name to find (e.g. "handleChat", "ProviderRegistry")',
|
|
4388
|
+
required: true
|
|
4389
|
+
},
|
|
4390
|
+
exact: {
|
|
4391
|
+
type: "boolean",
|
|
4392
|
+
description: "Exact match (default true). When false, substring match (case-insensitive).",
|
|
4393
|
+
required: false
|
|
4394
|
+
},
|
|
4395
|
+
kind: {
|
|
4396
|
+
type: "string",
|
|
4397
|
+
description: "Restrict to one kind: function, method, class, interface, type, enum, variable, property. Omit to search all.",
|
|
4398
|
+
required: false
|
|
4399
|
+
},
|
|
4400
|
+
path: {
|
|
4401
|
+
type: "string",
|
|
4402
|
+
description: "Project root (defaults to current working directory).",
|
|
4403
|
+
required: false
|
|
4404
|
+
},
|
|
4405
|
+
limit: {
|
|
4406
|
+
type: "number",
|
|
4407
|
+
description: "Max results (default 50).",
|
|
4408
|
+
required: false
|
|
4409
|
+
}
|
|
4410
|
+
}
|
|
4411
|
+
},
|
|
4412
|
+
async execute(args) {
|
|
4413
|
+
const name = String(args.name ?? "").trim();
|
|
4414
|
+
if (!name) return "Error: `name` is required.";
|
|
4415
|
+
const root = path2.resolve(String(args.path ?? process.cwd()));
|
|
4416
|
+
const index = await ensureIndex(root, true);
|
|
4417
|
+
if (!index) return NO_INDEX_HINT;
|
|
4418
|
+
const kindArg = args.kind ? String(args.kind) : void 0;
|
|
4419
|
+
const hits = findSymbol(index, {
|
|
4420
|
+
name,
|
|
4421
|
+
exact: args.exact !== false,
|
|
4422
|
+
kind: kindArg,
|
|
4423
|
+
limit: typeof args.limit === "number" ? args.limit : 50
|
|
4424
|
+
});
|
|
4425
|
+
if (hits.length === 0) {
|
|
4426
|
+
return `No symbol matching "${name}" found (index has ${index.symbolCount} symbols across ${index.fileCount} files).`;
|
|
4427
|
+
}
|
|
4428
|
+
const lines = hits.map((s) => {
|
|
4429
|
+
const rel = path2.relative(index.root, s.location.file) || s.location.file;
|
|
4430
|
+
const container = s.container ? ` (in ${s.container})` : "";
|
|
4431
|
+
const exp = s.exported ? " [exported]" : "";
|
|
4432
|
+
const sig = s.signature ? `
|
|
4433
|
+
${s.signature}` : "";
|
|
4434
|
+
return `${s.kind} ${s.name}${container}${exp} \u2014 ${rel}:${s.location.line}${sig}`;
|
|
4435
|
+
});
|
|
4436
|
+
return `Found ${hits.length} symbol(s):
|
|
4437
|
+
${lines.join("\n")}`;
|
|
4438
|
+
}
|
|
4439
|
+
};
|
|
4440
|
+
var getOutlineTool = {
|
|
4441
|
+
definition: {
|
|
4442
|
+
name: "get_outline",
|
|
4443
|
+
description: "Return the complete list of top-level declarations in a single source file (classes, functions, methods, types), sorted by line number. Use this to understand file structure without reading its full contents.",
|
|
4444
|
+
parameters: {
|
|
4445
|
+
file: {
|
|
4446
|
+
type: "string",
|
|
4447
|
+
description: "Path to the source file (absolute, or relative to project root).",
|
|
4448
|
+
required: true
|
|
4449
|
+
},
|
|
4450
|
+
path: {
|
|
4451
|
+
type: "string",
|
|
4452
|
+
description: "Project root (defaults to current working directory).",
|
|
4453
|
+
required: false
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
},
|
|
4457
|
+
async execute(args) {
|
|
4458
|
+
const file = String(args.file ?? "").trim();
|
|
4459
|
+
if (!file) return "Error: `file` is required.";
|
|
4460
|
+
const root = path2.resolve(String(args.path ?? process.cwd()));
|
|
4461
|
+
const absFile = path2.isAbsolute(file) ? file : path2.resolve(root, file);
|
|
4462
|
+
const index = await ensureIndex(root, true);
|
|
4463
|
+
if (!index) return NO_INDEX_HINT;
|
|
4464
|
+
const outline = getOutline(index, absFile);
|
|
4465
|
+
if (outline.length === 0) {
|
|
4466
|
+
return `No indexed symbols found for ${path2.relative(root, absFile) || absFile}. The file may be of an unsupported language (supported: TS/JS/TSX/JSX/Python), unreadable, or not yet re-indexed.`;
|
|
4467
|
+
}
|
|
4468
|
+
const rel = path2.relative(root, absFile) || absFile;
|
|
4469
|
+
const lines = outline.map((o) => {
|
|
4470
|
+
const container = o.container ? ` (in ${o.container})` : "";
|
|
4471
|
+
const exp = o.exported ? " [exported]" : "";
|
|
4472
|
+
return ` ${String(o.line).padStart(5)}: ${o.kind} ${o.name}${container}${exp}`;
|
|
4473
|
+
});
|
|
4474
|
+
return `Outline of ${rel} (${outline.length} symbols):
|
|
4475
|
+
${lines.join("\n")}`;
|
|
4476
|
+
}
|
|
4477
|
+
};
|
|
4478
|
+
var findReferencesTool = {
|
|
4479
|
+
definition: {
|
|
4480
|
+
name: "find_references",
|
|
4481
|
+
description: "Find all textual references to a symbol name across indexed files (whole-word match). MVP: regex-based \u2014 may include unrelated identifiers with the same name. Pair with find_symbol to locate the definition.",
|
|
4482
|
+
parameters: {
|
|
4483
|
+
name: {
|
|
4484
|
+
type: "string",
|
|
4485
|
+
description: "Symbol name to find references for.",
|
|
4486
|
+
required: true
|
|
4487
|
+
},
|
|
4488
|
+
path: {
|
|
4489
|
+
type: "string",
|
|
4490
|
+
description: "Project root (defaults to current working directory).",
|
|
4491
|
+
required: false
|
|
4492
|
+
},
|
|
4493
|
+
max_hits: {
|
|
4494
|
+
type: "number",
|
|
4495
|
+
description: "Max reference hits to return (default 200).",
|
|
4496
|
+
required: false
|
|
4497
|
+
}
|
|
4498
|
+
}
|
|
4499
|
+
},
|
|
4500
|
+
async execute(args) {
|
|
4501
|
+
const name = String(args.name ?? "").trim();
|
|
4502
|
+
if (!name) return "Error: `name` is required.";
|
|
4503
|
+
const root = path2.resolve(String(args.path ?? process.cwd()));
|
|
4504
|
+
const index = await ensureIndex(root, true);
|
|
4505
|
+
if (!index) return NO_INDEX_HINT;
|
|
4506
|
+
const maxHits = typeof args.max_hits === "number" ? args.max_hits : 200;
|
|
4507
|
+
const hits = findReferences(index, name, { maxHits });
|
|
4508
|
+
if (hits.length === 0) {
|
|
4509
|
+
return `No references to "${name}" found in ${index.fileCount} indexed files.`;
|
|
4510
|
+
}
|
|
4511
|
+
const lines = hits.map((h) => {
|
|
4512
|
+
const rel = path2.relative(index.root, h.file) || h.file;
|
|
4513
|
+
return `${rel}:${h.line}:${h.column} ${h.text}`;
|
|
4514
|
+
});
|
|
4515
|
+
return `Found ${hits.length} reference(s) to "${name}":
|
|
4516
|
+
${lines.join("\n")}`;
|
|
4517
|
+
}
|
|
4518
|
+
};
|
|
4519
|
+
var searchCodeTool = {
|
|
4520
|
+
definition: {
|
|
4521
|
+
name: "search_code",
|
|
4522
|
+
description: 'Semantic (meaning-based) search across indexed code symbols using local sentence embeddings. Use this when you do NOT know the exact symbol name \u2014 it finds code by purpose, e.g. "rate limiting logic", "where users are authenticated", "error recovery retry loops". Returns ranked matches with similarity scores. Requires a prior `/index semantic-rebuild` to build embeddings (one-time 117 MB model download + a few seconds per 1K symbols). For exact name lookups use find_symbol instead.',
|
|
4523
|
+
parameters: {
|
|
4524
|
+
query: {
|
|
4525
|
+
type: "string",
|
|
4526
|
+
description: "Natural-language description of the code you're looking for. English or Chinese both work.",
|
|
4527
|
+
required: true
|
|
4528
|
+
},
|
|
4529
|
+
k: {
|
|
4530
|
+
type: "number",
|
|
4531
|
+
description: "Max results to return (default 10, max 50).",
|
|
4532
|
+
required: false
|
|
4533
|
+
},
|
|
4534
|
+
kind: {
|
|
4535
|
+
type: "string",
|
|
4536
|
+
description: "Restrict to one symbol kind: function, method, class, interface, type, enum, variable, property. Omit to search all.",
|
|
4537
|
+
required: false
|
|
4538
|
+
},
|
|
4539
|
+
path: {
|
|
4540
|
+
type: "string",
|
|
4541
|
+
description: "Project root (defaults to current working directory).",
|
|
4542
|
+
required: false
|
|
4543
|
+
}
|
|
4544
|
+
}
|
|
4545
|
+
},
|
|
4546
|
+
async execute(args) {
|
|
4547
|
+
const query = String(args.query ?? "").trim();
|
|
4548
|
+
if (!query) return "Error: `query` is required.";
|
|
4549
|
+
const root = path2.resolve(String(args.path ?? process.cwd()));
|
|
4550
|
+
const k = Math.min(50, Math.max(1, typeof args.k === "number" ? args.k : 10));
|
|
4551
|
+
const kindFilter = args.kind ? String(args.kind) : void 0;
|
|
4552
|
+
if (!hasSemanticIndex(root)) {
|
|
4553
|
+
return "No semantic index exists for this project yet. Ask the user to run `/index semantic-rebuild` (first run downloads a ~117 MB embedding model; subsequent rebuilds are fast). As a fallback, use grep_files or find_symbol for literal-name lookups.";
|
|
4554
|
+
}
|
|
4555
|
+
let hits;
|
|
4556
|
+
try {
|
|
4557
|
+
const oversampled = await semanticSearch(root, query, kindFilter ? k * 4 : k);
|
|
4558
|
+
hits = kindFilter ? oversampled.filter((h) => h.symbol.kind === kindFilter).slice(0, k) : oversampled;
|
|
4559
|
+
} catch (err) {
|
|
4560
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4561
|
+
return `Semantic search failed: ${msg}`;
|
|
4562
|
+
}
|
|
4563
|
+
if (hits.length === 0) {
|
|
4564
|
+
return `No semantic matches found for "${query}". Try a different phrasing, or run \`/index semantic-rebuild\` if the codebase has changed significantly.`;
|
|
4565
|
+
}
|
|
4566
|
+
const lines = hits.map((h) => {
|
|
4567
|
+
const s = h.symbol;
|
|
4568
|
+
const rel = path2.relative(root, s.location.file) || s.location.file;
|
|
4569
|
+
const container = s.container ? ` (in ${s.container})` : "";
|
|
4570
|
+
const exp = s.exported ? " [exported]" : "";
|
|
4571
|
+
const score = h.score.toFixed(3);
|
|
4572
|
+
const sig = s.signature ? `
|
|
4573
|
+
${s.signature}` : "";
|
|
4574
|
+
return `[score=${score}] ${s.kind} ${s.name}${container}${exp} \u2014 ${rel}:${s.location.line}${sig}`;
|
|
4575
|
+
});
|
|
4576
|
+
return `Top ${hits.length} semantic match(es) for "${query}":
|
|
4577
|
+
${lines.join("\n")}`;
|
|
4578
|
+
}
|
|
4579
|
+
};
|
|
4580
|
+
|
|
4289
4581
|
// src/core/token-estimator.ts
|
|
4290
4582
|
var CJK_REGEX = /[\u2E80-\u9FFF\uA000-\uA4FF\uAC00-\uD7FF\uF900-\uFAFF\uFE30-\uFE4F\uFF00-\uFFEF]/g;
|
|
4291
4583
|
function estimateTokens(text) {
|
|
@@ -4341,6 +4633,10 @@ var ToolRegistry = class {
|
|
|
4341
4633
|
this.register(gitLogTool);
|
|
4342
4634
|
this.register(gitCommitTool);
|
|
4343
4635
|
this.register(notebookEditTool);
|
|
4636
|
+
this.register(findSymbolTool);
|
|
4637
|
+
this.register(getOutlineTool);
|
|
4638
|
+
this.register(findReferencesTool);
|
|
4639
|
+
this.register(searchCodeTool);
|
|
4344
4640
|
}
|
|
4345
4641
|
register(tool) {
|
|
4346
4642
|
this.tools.set(tool.definition.name, tool);
|