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.
Files changed (27) hide show
  1. package/README.md +5 -5
  2. package/dist/{batch-Y7MHXVR7.js → batch-HZI7QAE7.js} +2 -2
  3. package/dist/{chunk-Q5GVANMH.js → chunk-7VAE3I3D.js} +1 -1
  4. package/dist/{chunk-GDXKFWFL.js → chunk-CGQARJMP.js} +1 -1
  5. package/dist/{chunk-HHYMSEWS.js → chunk-MFWAL5S2.js} +1 -1
  6. package/dist/{chunk-CDOQNIVV.js → chunk-O4QYY6SF.js} +3 -3
  7. package/dist/{chunk-7D5EJBHO.js → chunk-QDP3NUPX.js} +3 -3
  8. package/dist/{chunk-FYJGVFXL.js → chunk-SBSWH2EG.js} +7 -7
  9. package/dist/{chunk-WXFQ6LYN.js → chunk-SCFGLRB3.js} +1 -1
  10. package/dist/{chunk-GFDRC2JZ.js → chunk-T6EIBUKW.js} +115 -18
  11. package/dist/{chunk-DHNYGJYB.js → chunk-TT7YURG3.js} +3 -3
  12. package/dist/{chunk-BFTTW5LS.js → chunk-VBAW4ZPY.js} +1 -1
  13. package/dist/{ci-OAFNH3MA.js → ci-FYLCHRN3.js} +4 -4
  14. package/dist/{ci-format-4LSXJNND.js → ci-format-TH2ZTFKU.js} +2 -2
  15. package/dist/{constants-ERIAS7GV.js → constants-BF6YNKRW.js} +1 -1
  16. package/dist/{doctor-cli-VFSVWZU6.js → doctor-cli-B6GE4BYJ.js} +4 -4
  17. package/dist/electron-server.js +164 -67
  18. package/dist/{hub-X4EUYRIN.js → hub-QBQCKEPE.js} +1 -1
  19. package/dist/index.js +2438 -2436
  20. package/dist/{pr-2CZN5JLE.js → pr-KV2WK7SU.js} +4 -4
  21. package/dist/{run-tests-YSRET52H.js → run-tests-DI6WEYHX.js} +1 -1
  22. package/dist/{run-tests-DXRJDPFF.js → run-tests-MEHC73SQ.js} +2 -2
  23. package/dist/{server-FGJGXHZD.js → server-ETIGAZX5.js} +4 -4
  24. package/dist/{server-5ZAXMKRI.js → server-KZAP5JN3.js} +28 -28
  25. package/dist/{task-orchestrator-QMERCD77.js → task-orchestrator-WS724BUX.js} +4 -4
  26. package/dist/{usage-633DUDNT.js → usage-DHZR5PG7.js} +2 -2
  27. package/package.json +1 -1
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [![npm version](https://img.shields.io/npm/v/jinzd-ai-cli)](https://www.npmjs.com/package/jinzd-ai-cli)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
9
9
  [![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org)
10
- [![Tests](https://img.shields.io/badge/tests-1393%20passing-brightgreen)]()
10
+ [![Tests](https://img.shields.io/badge/tests-1639%20passing-brightgreen)]()
11
11
  [![GitHub Release](https://img.shields.io/github/v/release/jinzhengdong/ai-cli)](https://github.com/jinzhengdong/ai-cli/releases)
12
12
  [![CI](https://github.com/jinzhengdong/ai-cli/actions/workflows/ci.yml/badge.svg)](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 28 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
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 27 tools during conversations:
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 40 commands.
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: 79 files, 1393 passed, 1 skipped
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-BFTTW5LS.js";
4
+ } from "./chunk-VBAW4ZPY.js";
5
5
  import "./chunk-5ULLIOVC.js";
6
- import "./chunk-GDXKFWFL.js";
6
+ import "./chunk-CGQARJMP.js";
7
7
  import {
8
8
  atomicWriteFileSync
9
9
  } from "./chunk-IW3Q7AE5.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-GDXKFWFL.js";
4
+ } from "./chunk-CGQARJMP.js";
5
5
 
6
6
  // src/tools/builtin/run-tests.ts
7
7
  import { execSync, spawnSync } 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.235";
4
+ var VERSION = "0.4.236";
5
5
  var APP_NAME = "ai-cli";
6
6
  var CONFIG_DIR_NAME = ".aicli";
7
7
  var CONFIG_FILE_NAME = "config.json";
@@ -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.235";
9
+ var VERSION = "0.4.236";
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
  evaluateCiGate,
4
4
  normalizeCiThresholds
5
- } from "./chunk-WXFQ6LYN.js";
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-BFTTW5LS.js";
16
+ } from "./chunk-VBAW4ZPY.js";
17
17
  import {
18
18
  VERSION
19
- } from "./chunk-GDXKFWFL.js";
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-GFDRC2JZ.js";
14
+ } from "./chunk-T6EIBUKW.js";
15
15
  import {
16
16
  ConfigManager
17
- } from "./chunk-BFTTW5LS.js";
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-GDXKFWFL.js";
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-GFDRC2JZ.js";
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-Q5GVANMH.js";
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-GDXKFWFL.js";
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,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  VERSION
4
- } from "./chunk-GDXKFWFL.js";
4
+ } from "./chunk-CGQARJMP.js";
5
5
 
6
6
  // src/cli/ci-format.ts
7
7
  var DEFAULT_CI_THRESHOLDS = {
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  CONFIG_DIR_NAME,
4
4
  PLUGINS_DIR_NAME
5
- } from "./chunk-GDXKFWFL.js";
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: 1, plugins: [] };
195
+ if (!existsSync2(file)) return { version: 2, plugins: [] };
196
196
  try {
197
197
  const parsed = JSON.parse(readFileSync2(file, "utf-8"));
198
- return { version: 1, plugins: Array.isArray(parsed.plugins) ? parsed.plugins : [] };
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: 1, plugins: [] };
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 hashPluginManifest(manifestPath) {
208
- return createHash("sha256").update(readFileSync2(manifestPath)).digest("hex");
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 hash = hashPluginManifest(manifestPath);
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
- hash,
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
- hash: plugin.hash,
348
+ contentHash: plugin.hash,
252
349
  installedAt: (/* @__PURE__ */ new Date()).toISOString()
253
350
  };
254
- const next = { ...current, enabled, hash: plugin.hash, enabledAt: enabled ? (/* @__PURE__ */ new Date()).toISOString() : current.enabledAt };
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
- hash: plugin.hash,
364
+ contentHash: plugin.hash,
268
365
  installedAt: (/* @__PURE__ */ new Date()).toISOString()
269
366
  };
270
- const next = { ...current, trusted: true, hash: plugin.hash, trustedAt: (/* @__PURE__ */ new Date()).toISOString() };
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 hash = hashPluginManifest(manifestPath);
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.hash === hash;
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-FYJGVFXL.js";
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-GDXKFWFL.js";
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,
@@ -8,7 +8,7 @@ import {
8
8
  CONFIG_FILE_NAME,
9
9
  HISTORY_DIR_NAME,
10
10
  PLUGINS_DIR_NAME
11
- } from "./chunk-GDXKFWFL.js";
11
+ } from "./chunk-CGQARJMP.js";
12
12
  import {
13
13
  atomicWriteFileSync
14
14
  } from "./chunk-IW3Q7AE5.js";
@@ -3,14 +3,14 @@ import {
3
3
  CI_COMMENT_MARKER,
4
4
  countSeverity,
5
5
  runCi
6
- } from "./chunk-CDOQNIVV.js";
7
- import "./chunk-WXFQ6LYN.js";
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-BFTTW5LS.js";
11
+ import "./chunk-VBAW4ZPY.js";
12
12
  import "./chunk-5ULLIOVC.js";
13
- import "./chunk-GDXKFWFL.js";
13
+ import "./chunk-CGQARJMP.js";
14
14
  import "./chunk-IW3Q7AE5.js";
15
15
  export {
16
16
  CI_COMMENT_MARKER,
@@ -6,8 +6,8 @@ import {
6
6
  formatCiResult,
7
7
  formatCiSarif,
8
8
  normalizeCiThresholds
9
- } from "./chunk-WXFQ6LYN.js";
10
- import "./chunk-GDXKFWFL.js";
9
+ } from "./chunk-SCFGLRB3.js";
10
+ import "./chunk-CGQARJMP.js";
11
11
  export {
12
12
  DEFAULT_CI_THRESHOLDS,
13
13
  detectCiGateSignals,
@@ -38,7 +38,7 @@ import {
38
38
  TEST_TIMEOUT,
39
39
  VERSION,
40
40
  buildUserIdentityPrompt
41
- } from "./chunk-GDXKFWFL.js";
41
+ } from "./chunk-CGQARJMP.js";
42
42
  export {
43
43
  AGENTIC_BEHAVIOR_GUIDELINE,
44
44
  APP_NAME,
@@ -2,14 +2,14 @@
2
2
  import {
3
3
  formatDoctorReport,
4
4
  runDoctorCli
5
- } from "./chunk-7D5EJBHO.js";
5
+ } from "./chunk-QDP3NUPX.js";
6
6
  import "./chunk-QYQI7ZWK.js";
7
- import "./chunk-GFDRC2JZ.js";
7
+ import "./chunk-T6EIBUKW.js";
8
8
  import "./chunk-O3XSFPYH.js";
9
- import "./chunk-BFTTW5LS.js";
9
+ import "./chunk-VBAW4ZPY.js";
10
10
  import "./chunk-5ULLIOVC.js";
11
11
  import "./chunk-HOSJZMQS.js";
12
- import "./chunk-GDXKFWFL.js";
12
+ import "./chunk-CGQARJMP.js";
13
13
  import "./chunk-IW3Q7AE5.js";
14
14
  export {
15
15
  formatDoctorReport,