jinzd-ai-cli 0.4.235 → 0.4.236
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 +5 -5
- package/dist/{batch-Y7MHXVR7.js → batch-HZI7QAE7.js} +2 -2
- package/dist/{chunk-Q5GVANMH.js → chunk-7VAE3I3D.js} +1 -1
- package/dist/{chunk-GDXKFWFL.js → chunk-CGQARJMP.js} +1 -1
- package/dist/{chunk-HHYMSEWS.js → chunk-MFWAL5S2.js} +1 -1
- package/dist/{chunk-CDOQNIVV.js → chunk-O4QYY6SF.js} +3 -3
- package/dist/{chunk-7D5EJBHO.js → chunk-QDP3NUPX.js} +3 -3
- package/dist/{chunk-FYJGVFXL.js → chunk-SBSWH2EG.js} +7 -7
- package/dist/{chunk-WXFQ6LYN.js → chunk-SCFGLRB3.js} +1 -1
- package/dist/{chunk-GFDRC2JZ.js → chunk-T6EIBUKW.js} +115 -18
- package/dist/{chunk-DHNYGJYB.js → chunk-TT7YURG3.js} +3 -3
- package/dist/{chunk-BFTTW5LS.js → chunk-VBAW4ZPY.js} +1 -1
- package/dist/{ci-OAFNH3MA.js → ci-FYLCHRN3.js} +4 -4
- package/dist/{ci-format-4LSXJNND.js → ci-format-TH2ZTFKU.js} +2 -2
- package/dist/{constants-ERIAS7GV.js → constants-BF6YNKRW.js} +1 -1
- package/dist/{doctor-cli-VFSVWZU6.js → doctor-cli-B6GE4BYJ.js} +4 -4
- package/dist/electron-server.js +164 -67
- package/dist/{hub-X4EUYRIN.js → hub-QBQCKEPE.js} +1 -1
- package/dist/index.js +2438 -2436
- package/dist/{pr-2CZN5JLE.js → pr-KV2WK7SU.js} +4 -4
- package/dist/{run-tests-YSRET52H.js → run-tests-DI6WEYHX.js} +1 -1
- package/dist/{run-tests-DXRJDPFF.js → run-tests-MEHC73SQ.js} +2 -2
- package/dist/{server-FGJGXHZD.js → server-ETIGAZX5.js} +4 -4
- package/dist/{server-5ZAXMKRI.js → server-KZAP5JN3.js} +28 -28
- package/dist/{task-orchestrator-QMERCD77.js → task-orchestrator-WS724BUX.js} +4 -4
- package/dist/{usage-633DUDNT.js → usage-DHZR5PG7.js} +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://www.npmjs.com/package/jinzd-ai-cli)
|
|
8
8
|
[](LICENSE)
|
|
9
9
|
[](https://nodejs.org)
|
|
10
|
-
[]()
|
|
11
11
|
[](https://github.com/jinzhengdong/ai-cli/releases)
|
|
12
12
|
[](https://github.com/jinzhengdong/ai-cli/actions/workflows/ci.yml)
|
|
13
13
|
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
- **Conversation Branching** *(v0.4.74+)* — `/branch list/new/switch/delete/rename` inside the REPL, plus a 🌿 "fork here" button on every replay step — explore alternate directions without losing the original thread
|
|
32
32
|
- **Symbol Index** *(v0.4.76+, multi-language since v0.4.143)* — persistent tree-sitter index for TypeScript / JavaScript / TSX / Python / Go / Rust / Java / C/C++ powers three new AI tools: `find_symbol`, `get_outline`, `find_references`. Orders of magnitude faster than grep for definition lookups; background refresh on REPL startup, `/index status|rebuild|clear` to manage
|
|
33
33
|
- **Semantic Code Search** *(v0.4.77+)* — `search_code` tool finds code by meaning, not name. Local sentence embeddings (multilingual MiniLM, 117 MB one-time download) score symbols by cosine similarity against natural-language queries in English or Chinese ("where are users authenticated", "哪里做了速率限制"). No API key, runs on CPU. Manage with `/index semantic-rebuild|semantic-clear`
|
|
34
|
-
- **MCP Server Mode** *(v0.4.84+)* — `aicli mcp-serve` reverses ai-cli into an MCP server (JSON-RPC 2.0 over stdio), exposing its
|
|
34
|
+
- **MCP Server Mode** *(v0.4.84+)* — `aicli mcp-serve` reverses ai-cli into an MCP server (JSON-RPC 2.0 over stdio), exposing its 30 built-in tools (incl. `find_symbol` / `search_code` / `run_tests`) to Claude Desktop / Cursor / any MCP client. Opt-in destructive-tool allow, `--tools` whitelist, `--cwd` override
|
|
35
35
|
- **Session Sensitive-Data Redaction** *(v0.4.88+)* — unified redactor scrubs `password=` / `api_key` / bearer tokens / OpenAI-style keys from every message **before it hits disk**. Query text is redacted too, so secrets never reach embeddings or logs. `/security status` + `/security scan` to audit
|
|
36
36
|
- **Human-like Long-Term Memory** *(v0.4.89+, B4)* — semantic index over every past chat session + `recall_memory` AI tool + `/memory rebuild|refresh|status|recall` commands. AI is prompted to auto-recall when it sees "last time" / "之前" / ambiguous references. Reuses the same MiniLM embedder as semantic code search
|
|
37
37
|
- **Governed Persistent Memory** *(v0.4.217+)* — `save_memory` and `/memory add` write auditable `memory.jsonl` entries with id/scope/source/sensitivity/approval/expiry; low-risk entries auto-approve, sensitive entries stay pending until `/memory approve <id>`, and project-scoped memories only inject inside the same project
|
|
@@ -156,7 +156,7 @@ aicli
|
|
|
156
156
|
|
|
157
157
|
## Built-in Tools (Agentic)
|
|
158
158
|
|
|
159
|
-
AI autonomously invokes these
|
|
159
|
+
AI autonomously invokes these 30 tools during conversations:
|
|
160
160
|
|
|
161
161
|
| Tool | Safety | Description |
|
|
162
162
|
|------|--------|-------------|
|
|
@@ -225,7 +225,7 @@ AI autonomously invokes these 27 tools during conversations:
|
|
|
225
225
|
|
|
226
226
|
**Multi-line input**: Use `\` at end of line for continuation, or paste multi-line content directly (auto-detected and merged).
|
|
227
227
|
|
|
228
|
-
Type `/help` in the REPL to see all
|
|
228
|
+
Type `/help` in the REPL to see all 48 commands.
|
|
229
229
|
|
|
230
230
|
## CLI Parameters
|
|
231
231
|
|
|
@@ -512,7 +512,7 @@ The Web UI (`aicli web`) provides a full-featured browser interface:
|
|
|
512
512
|
## Testing
|
|
513
513
|
|
|
514
514
|
```bash
|
|
515
|
-
npm test # Offline regression suite:
|
|
515
|
+
npm test # Offline regression suite: 91 files, 1639 passed, 2 skipped
|
|
516
516
|
npm run test:providers # Real-provider smoke tests (network/API-key dependent)
|
|
517
517
|
npm run test:e2e-web # Playwright browser smoke; may need browser-process permission in sandboxes
|
|
518
518
|
npm run test:watch # Watch mode
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ConfigManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-VBAW4ZPY.js";
|
|
5
5
|
import "./chunk-5ULLIOVC.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-CGQARJMP.js";
|
|
7
7
|
import {
|
|
8
8
|
atomicWriteFileSync
|
|
9
9
|
} from "./chunk-IW3Q7AE5.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
evaluateCiGate,
|
|
4
4
|
normalizeCiThresholds
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-SCFGLRB3.js";
|
|
6
6
|
import {
|
|
7
7
|
buildReviewPrompt,
|
|
8
8
|
buildSecurityReviewPrompt,
|
|
@@ -13,10 +13,10 @@ import {
|
|
|
13
13
|
} from "./chunk-QYQI7ZWK.js";
|
|
14
14
|
import {
|
|
15
15
|
ConfigManager
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-VBAW4ZPY.js";
|
|
17
17
|
import {
|
|
18
18
|
VERSION
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-CGQARJMP.js";
|
|
20
20
|
|
|
21
21
|
// src/cli/ci.ts
|
|
22
22
|
import { execFileSync } from "child_process";
|
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
listHooks,
|
|
12
12
|
listInstalledPlugins,
|
|
13
13
|
resetStats
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-T6EIBUKW.js";
|
|
15
15
|
import {
|
|
16
16
|
ConfigManager
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-VBAW4ZPY.js";
|
|
18
18
|
import {
|
|
19
19
|
getGitRoot
|
|
20
20
|
} from "./chunk-HOSJZMQS.js";
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
MCP_PROJECT_CONFIG_NAME,
|
|
27
27
|
MEMORY_FILE_NAME,
|
|
28
28
|
VERSION
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-CGQARJMP.js";
|
|
30
30
|
|
|
31
31
|
// src/diagnostics/doctor-report.ts
|
|
32
32
|
import { existsSync as existsSync3, statSync as statSync2 } from "fs";
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
runHook,
|
|
15
15
|
runLifecycleHooks,
|
|
16
16
|
runTool
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-T6EIBUKW.js";
|
|
18
18
|
import {
|
|
19
19
|
getDangerLevel,
|
|
20
20
|
isFileWriteTool,
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
} from "./chunk-4BKXL7SM.js";
|
|
34
34
|
import {
|
|
35
35
|
runTestsTool
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-7VAE3I3D.js";
|
|
37
37
|
import {
|
|
38
38
|
CONFIG_DIR_NAME,
|
|
39
39
|
DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
|
|
@@ -43,7 +43,7 @@ import {
|
|
|
43
43
|
SUBAGENT_ALLOWED_TOOLS,
|
|
44
44
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
45
45
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
46
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-CGQARJMP.js";
|
|
47
47
|
import {
|
|
48
48
|
loadChatIndex,
|
|
49
49
|
searchChatMemory
|
|
@@ -7005,10 +7005,6 @@ export {
|
|
|
7005
7005
|
initTheme,
|
|
7006
7006
|
theme,
|
|
7007
7007
|
undoStack,
|
|
7008
|
-
recordRecentlyDeniedAutoAction,
|
|
7009
|
-
getRecentlyDeniedAutoActions,
|
|
7010
|
-
clearRecentlyDeniedAutoActions,
|
|
7011
|
-
defaultActionClassifier,
|
|
7012
7008
|
renderDiff,
|
|
7013
7009
|
memoryStorePath,
|
|
7014
7010
|
memoryMarkdownPath,
|
|
@@ -7020,6 +7016,10 @@ export {
|
|
|
7020
7016
|
expireMemoryEntry,
|
|
7021
7017
|
exportMemoryEntries,
|
|
7022
7018
|
formatMemoryForPrompt,
|
|
7019
|
+
recordRecentlyDeniedAutoAction,
|
|
7020
|
+
getRecentlyDeniedAutoActions,
|
|
7021
|
+
clearRecentlyDeniedAutoActions,
|
|
7022
|
+
defaultActionClassifier,
|
|
7023
7023
|
isInterrupted,
|
|
7024
7024
|
requestInterrupt,
|
|
7025
7025
|
resetInterrupt,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
CONFIG_DIR_NAME,
|
|
4
4
|
PLUGINS_DIR_NAME
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-CGQARJMP.js";
|
|
6
6
|
import {
|
|
7
7
|
atomicWriteFileSync
|
|
8
8
|
} from "./chunk-IW3Q7AE5.js";
|
|
@@ -121,8 +121,8 @@ function installFlushOnExit() {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
// src/plugins/plugin-manager.ts
|
|
124
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2, cpSync, rmSync, statSync } from "fs";
|
|
125
|
-
import { basename, dirname as dirname2, join as join2, resolve } from "path";
|
|
124
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2, realpathSync, cpSync, rmSync, statSync } from "fs";
|
|
125
|
+
import { basename, dirname as dirname2, join as join2, relative, resolve, sep } from "path";
|
|
126
126
|
import { createHash } from "crypto";
|
|
127
127
|
import { z } from "zod";
|
|
128
128
|
var MANIFEST_RELATIVE = ".aicli-plugin/plugin.json";
|
|
@@ -192,20 +192,117 @@ function statePath(configDir) {
|
|
|
192
192
|
}
|
|
193
193
|
function loadState(configDir) {
|
|
194
194
|
const file = statePath(configDir);
|
|
195
|
-
if (!existsSync2(file)) return { version:
|
|
195
|
+
if (!existsSync2(file)) return { version: 2, plugins: [] };
|
|
196
196
|
try {
|
|
197
197
|
const parsed = JSON.parse(readFileSync2(file, "utf-8"));
|
|
198
|
-
|
|
198
|
+
const rawPlugins = Array.isArray(parsed.plugins) ? parsed.plugins : [];
|
|
199
|
+
return { version: 2, plugins: rawPlugins.map((p) => migrateEntry(p)) };
|
|
199
200
|
} catch {
|
|
200
|
-
return { version:
|
|
201
|
+
return { version: 2, plugins: [] };
|
|
201
202
|
}
|
|
202
203
|
}
|
|
204
|
+
function migrateEntry(entry) {
|
|
205
|
+
const name = String(entry.name ?? "");
|
|
206
|
+
const contentHash = typeof entry.contentHash === "string" ? entry.contentHash : void 0;
|
|
207
|
+
const legacyHash = typeof entry.hash === "string" ? entry.hash : void 0;
|
|
208
|
+
const trusted = contentHash ? entry.trusted === true : false;
|
|
209
|
+
return {
|
|
210
|
+
name,
|
|
211
|
+
enabled: entry.enabled === true,
|
|
212
|
+
trusted,
|
|
213
|
+
contentHash: contentHash ?? legacyHash,
|
|
214
|
+
installedAt: String(entry.installedAt ?? (/* @__PURE__ */ new Date(0)).toISOString()),
|
|
215
|
+
trustedAt: trusted && entry.trustedAt ? String(entry.trustedAt) : void 0,
|
|
216
|
+
enabledAt: entry.enabledAt ? String(entry.enabledAt) : void 0
|
|
217
|
+
};
|
|
218
|
+
}
|
|
203
219
|
function saveState(configDir, state2) {
|
|
204
220
|
mkdirSync2(pluginRoot(configDir), { recursive: true });
|
|
205
221
|
atomicWriteFileSync(statePath(configDir), JSON.stringify(state2, null, 2));
|
|
206
222
|
}
|
|
207
|
-
function
|
|
208
|
-
|
|
223
|
+
function normalizeForHash(buf) {
|
|
224
|
+
const str = buf.toString("utf-8").replaceAll("\r\n", "\n");
|
|
225
|
+
return Buffer.from(str, "utf-8");
|
|
226
|
+
}
|
|
227
|
+
function extractCommandPaths(command, pluginDir) {
|
|
228
|
+
const resolvedDir = resolve(pluginDir);
|
|
229
|
+
const refs = [];
|
|
230
|
+
for (const m of command.matchAll(/\$PLUGIN_DIR[\\/]([^"'\s]+)/g)) {
|
|
231
|
+
refs.push(m[1]);
|
|
232
|
+
}
|
|
233
|
+
for (const m of command.matchAll(/\$\{pluginDir\}[\\/]([^"'\s}]+)/g)) {
|
|
234
|
+
refs.push(m[1]);
|
|
235
|
+
}
|
|
236
|
+
for (const m of command.matchAll(/(?<=["'\s])(\.?[.\\/][^"'\s]+)/g)) {
|
|
237
|
+
refs.push(m[0]);
|
|
238
|
+
}
|
|
239
|
+
const seen = /* @__PURE__ */ new Set();
|
|
240
|
+
const valid = [];
|
|
241
|
+
for (const ref of refs) {
|
|
242
|
+
if (seen.has(ref)) continue;
|
|
243
|
+
seen.add(ref);
|
|
244
|
+
try {
|
|
245
|
+
const abs = resolve(resolvedDir, ref);
|
|
246
|
+
if (!abs.startsWith(resolvedDir + sep)) continue;
|
|
247
|
+
if (existsSync2(abs)) {
|
|
248
|
+
const real = realpathSync(abs);
|
|
249
|
+
if (!real.startsWith(resolvedDir + sep)) continue;
|
|
250
|
+
valid.push(relative(resolvedDir, real));
|
|
251
|
+
}
|
|
252
|
+
} catch {
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return valid;
|
|
256
|
+
}
|
|
257
|
+
function hashPluginContent(pluginDir, manifest) {
|
|
258
|
+
const resolvedDir = resolve(pluginDir);
|
|
259
|
+
const assetRels = /* @__PURE__ */ new Set(
|
|
260
|
+
[...manifest.skills, ...manifest.commands, ...manifest.agents]
|
|
261
|
+
);
|
|
262
|
+
for (const raw of Object.values(manifest.hooks?.events ?? {})) {
|
|
263
|
+
const items = Array.isArray(raw) ? raw : [raw];
|
|
264
|
+
for (const item of items) {
|
|
265
|
+
const cmd = typeof item === "string" ? item : item.command;
|
|
266
|
+
if (cmd) {
|
|
267
|
+
for (const p of extractCommandPaths(cmd, pluginDir)) assetRels.add(p);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
for (const server of Object.values(manifest.mcpServers ?? {})) {
|
|
272
|
+
for (const p of extractCommandPaths(server.command, pluginDir)) assetRels.add(p);
|
|
273
|
+
for (const arg of server.args ?? []) {
|
|
274
|
+
for (const p of extractCommandPaths(arg, pluginDir)) assetRels.add(p);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
const sorted = [...assetRels].sort();
|
|
278
|
+
const hasher = createHash("sha256");
|
|
279
|
+
const manifestPath = join2(resolvedDir, MANIFEST_RELATIVE);
|
|
280
|
+
hasher.update(normalizeForHash(readFileSync2(manifestPath)));
|
|
281
|
+
for (const rel of sorted) {
|
|
282
|
+
const abs = resolve(resolvedDir, rel);
|
|
283
|
+
if (!abs.startsWith(resolvedDir + sep)) {
|
|
284
|
+
throw new Error(`plugin asset escapes plugin dir: ${rel}`);
|
|
285
|
+
}
|
|
286
|
+
let realPath;
|
|
287
|
+
try {
|
|
288
|
+
realPath = realpathSync(abs);
|
|
289
|
+
} catch {
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
try {
|
|
293
|
+
if (statSync(realPath).isDirectory()) continue;
|
|
294
|
+
} catch {
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
if (!realPath.startsWith(resolvedDir + sep)) {
|
|
298
|
+
throw new Error(`plugin asset symlink escapes plugin dir: ${rel} \u2192 ${realPath}`);
|
|
299
|
+
}
|
|
300
|
+
hasher.update(normalizeForHash(readFileSync2(abs)));
|
|
301
|
+
}
|
|
302
|
+
return hasher.digest("hex");
|
|
303
|
+
}
|
|
304
|
+
function effectiveHash(entry) {
|
|
305
|
+
return entry.contentHash ?? entry.hash ?? "";
|
|
209
306
|
}
|
|
210
307
|
function readPluginManifest(manifestPath) {
|
|
211
308
|
return PluginManifestSchema.parse(JSON.parse(readFileSync2(manifestPath, "utf-8")));
|
|
@@ -226,19 +323,19 @@ function installPlugin(configDir, inputPath) {
|
|
|
226
323
|
if (existsSync2(targetDir)) rmSync(targetDir, { recursive: true, force: true });
|
|
227
324
|
cpSync(sourceDir, targetDir, { recursive: true });
|
|
228
325
|
const manifestPath = pluginManifestPath(targetDir);
|
|
229
|
-
const
|
|
326
|
+
const contentHash = hashPluginContent(targetDir, manifest);
|
|
230
327
|
const state2 = loadState(configDir);
|
|
231
328
|
const previous = state2.plugins.find((p) => p.name === manifest.name);
|
|
232
329
|
const next = {
|
|
233
330
|
name: manifest.name,
|
|
234
331
|
enabled: previous?.enabled ?? false,
|
|
235
332
|
trusted: false,
|
|
236
|
-
|
|
333
|
+
contentHash,
|
|
237
334
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
238
335
|
};
|
|
239
336
|
state2.plugins = [...state2.plugins.filter((p) => p.name !== manifest.name), next];
|
|
240
337
|
saveState(configDir, state2);
|
|
241
|
-
return { name: manifest.name, dir: targetDir, manifestPath, manifest, hash, enabled: next.enabled, trusted: false, valid: true };
|
|
338
|
+
return { name: manifest.name, dir: targetDir, manifestPath, manifest, hash: contentHash, enabled: next.enabled, trusted: false, valid: true };
|
|
242
339
|
}
|
|
243
340
|
function setPluginEnabled(configDir, name, enabled) {
|
|
244
341
|
const plugin = getInstalledPlugin(configDir, name);
|
|
@@ -248,10 +345,10 @@ function setPluginEnabled(configDir, name, enabled) {
|
|
|
248
345
|
name: plugin.name,
|
|
249
346
|
enabled: false,
|
|
250
347
|
trusted: false,
|
|
251
|
-
|
|
348
|
+
contentHash: plugin.hash,
|
|
252
349
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
253
350
|
};
|
|
254
|
-
const next = { ...current, enabled,
|
|
351
|
+
const next = { ...current, enabled, contentHash: plugin.hash, enabledAt: enabled ? (/* @__PURE__ */ new Date()).toISOString() : current.enabledAt };
|
|
255
352
|
state2.plugins = [...state2.plugins.filter((p) => p.name !== plugin.name), next];
|
|
256
353
|
saveState(configDir, state2);
|
|
257
354
|
return next;
|
|
@@ -264,10 +361,10 @@ function trustPlugin(configDir, name) {
|
|
|
264
361
|
name: plugin.name,
|
|
265
362
|
enabled: false,
|
|
266
363
|
trusted: false,
|
|
267
|
-
|
|
364
|
+
contentHash: plugin.hash,
|
|
268
365
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
269
366
|
};
|
|
270
|
-
const next = { ...current, trusted: true,
|
|
367
|
+
const next = { ...current, trusted: true, contentHash: plugin.hash, trustedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
271
368
|
state2.plugins = [...state2.plugins.filter((p) => p.name !== plugin.name), next];
|
|
272
369
|
saveState(configDir, state2);
|
|
273
370
|
return next;
|
|
@@ -295,15 +392,15 @@ function listInstalledPlugins(configDir) {
|
|
|
295
392
|
if (!existsSync2(manifestPath)) continue;
|
|
296
393
|
try {
|
|
297
394
|
const manifest = readPluginManifest(manifestPath);
|
|
298
|
-
const
|
|
395
|
+
const contentHash = hashPluginContent(dir, manifest);
|
|
299
396
|
const st = state2.plugins.find((p) => p.name === manifest.name);
|
|
300
|
-
const trusted = st?.trusted === true && st
|
|
397
|
+
const trusted = st?.trusted === true && effectiveHash(st) === contentHash;
|
|
301
398
|
out.push({
|
|
302
399
|
name: manifest.name,
|
|
303
400
|
dir,
|
|
304
401
|
manifestPath,
|
|
305
402
|
manifest,
|
|
306
|
-
hash,
|
|
403
|
+
hash: contentHash,
|
|
307
404
|
enabled: st?.enabled === true,
|
|
308
405
|
trusted,
|
|
309
406
|
valid: true
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
truncateForPersist
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-SBSWH2EG.js";
|
|
5
5
|
import {
|
|
6
6
|
APP_NAME,
|
|
7
7
|
CONFIG_DIR_NAME,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
MCP_PROTOCOL_VERSION,
|
|
12
12
|
MCP_TOOL_PREFIX,
|
|
13
13
|
VERSION
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-CGQARJMP.js";
|
|
15
15
|
import {
|
|
16
16
|
atomicWriteFileSync
|
|
17
17
|
} from "./chunk-IW3Q7AE5.js";
|
|
@@ -1078,10 +1078,10 @@ function readGitDiff(options = {}) {
|
|
|
1078
1078
|
}
|
|
1079
1079
|
|
|
1080
1080
|
export {
|
|
1081
|
+
readGitDiff,
|
|
1081
1082
|
scanDirTree,
|
|
1082
1083
|
scanProject,
|
|
1083
1084
|
buildInitPrompt,
|
|
1084
|
-
readGitDiff,
|
|
1085
1085
|
parseSimpleYaml,
|
|
1086
1086
|
persistToolRound,
|
|
1087
1087
|
autoTrimSessionIfNeeded,
|
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
CI_COMMENT_MARKER,
|
|
4
4
|
countSeverity,
|
|
5
5
|
runCi
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-O4QYY6SF.js";
|
|
7
|
+
import "./chunk-SCFGLRB3.js";
|
|
8
8
|
import "./chunk-HLWUDRBO.js";
|
|
9
9
|
import "./chunk-QYQI7ZWK.js";
|
|
10
10
|
import "./chunk-O3XSFPYH.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-VBAW4ZPY.js";
|
|
12
12
|
import "./chunk-5ULLIOVC.js";
|
|
13
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-CGQARJMP.js";
|
|
14
14
|
import "./chunk-IW3Q7AE5.js";
|
|
15
15
|
export {
|
|
16
16
|
CI_COMMENT_MARKER,
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import {
|
|
3
3
|
formatDoctorReport,
|
|
4
4
|
runDoctorCli
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-QDP3NUPX.js";
|
|
6
6
|
import "./chunk-QYQI7ZWK.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-T6EIBUKW.js";
|
|
8
8
|
import "./chunk-O3XSFPYH.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-VBAW4ZPY.js";
|
|
10
10
|
import "./chunk-5ULLIOVC.js";
|
|
11
11
|
import "./chunk-HOSJZMQS.js";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-CGQARJMP.js";
|
|
13
13
|
import "./chunk-IW3Q7AE5.js";
|
|
14
14
|
export {
|
|
15
15
|
formatDoctorReport,
|