jinzd-ai-cli 0.4.306 → 0.4.308

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 (95) hide show
  1. package/README.md +1 -0
  2. package/THIRD_PARTY_NOTICES.md +3 -0
  3. package/dist/{agent-client-6GX6QQDU.js → agent-client-TIEAYZXV.js} +4 -1
  4. package/dist/{auth-PE3Z5OHS.js → auth-QTQNZ6IX.js} +2 -2
  5. package/dist/{batch-JLGWQ7HU.js → batch-S7XLEEOH.js} +3 -3
  6. package/dist/{chat-index-2D5GK2DB.js → chat-index-7CLR4CBG.js} +4 -3
  7. package/dist/{chat-index-DGUOUUQW.js → chat-index-RLVLQRRC.js} +3 -2
  8. package/dist/{chunk-JDT6UG6R.js → chunk-2DYQDLLF.js} +1 -1
  9. package/dist/{chunk-T6WQEQI4.js → chunk-2MNUMLN4.js} +1 -1
  10. package/dist/chunk-2XMUCC42.js +67 -0
  11. package/dist/{chunk-7SSCSSC6.js → chunk-3537CQ5M.js} +2 -2
  12. package/dist/{chunk-OAXLMF3U.js → chunk-3YVNDYOY.js} +1 -1
  13. package/dist/{chunk-RYQBBEMM.js → chunk-4PR5AVJ5.js} +115 -19
  14. package/dist/{chunk-GHWZVPUV.js → chunk-6JHACXB3.js} +7 -5
  15. package/dist/{chunk-WZWRA7R2.js → chunk-7OHXFTZO.js} +2 -2
  16. package/dist/{chunk-IUVDZVZ4.js → chunk-AXTLYOA7.js} +24 -17
  17. package/dist/{chunk-XJOK5353.js → chunk-B3MPYI4E.js} +2 -2
  18. package/dist/{chunk-3RDJEYF7.js → chunk-BGZN4K7Q.js} +4 -4
  19. package/dist/chunk-BMLQPSHP.js +69 -0
  20. package/dist/{chunk-NRSYBKWA.js → chunk-C7CKDFJS.js} +1 -1
  21. package/dist/{chunk-JFNBJHR6.js → chunk-E2PNXNKI.js} +4 -4
  22. package/dist/chunk-FVXNEZEW.js +161 -0
  23. package/dist/{chunk-YKJO3SI4.js → chunk-G6DVGQ4I.js} +1 -1
  24. package/dist/{chunk-AYLK4EGA.js → chunk-HC33C4U3.js} +18 -18
  25. package/dist/chunk-JJFJWD35.js +162 -0
  26. package/dist/{chunk-W6PLV3EY.js → chunk-JJNUASMJ.js} +263 -55
  27. package/dist/{chunk-NYNSYLFY.js → chunk-JL44HGZC.js} +1 -1
  28. package/dist/{chunk-NUJTNH76.js → chunk-LBWKMTT3.js} +1 -1
  29. package/dist/{chunk-LAP7TPPK.js → chunk-LR3TGZWQ.js} +2 -2
  30. package/dist/{chunk-WQ3OMEC4.js → chunk-M6HLYG33.js} +1 -1
  31. package/dist/{chunk-I4GQRMFV.js → chunk-M6YV5KSS.js} +6 -4
  32. package/dist/{chunk-K5SDDTN7.js → chunk-NLK45GUS.js} +1 -1
  33. package/dist/{chunk-KBDKKHXB.js → chunk-O6CGOVD4.js} +2 -2
  34. package/dist/chunk-QMFMST2T.js +39 -0
  35. package/dist/{chunk-MI4SFZGX.js → chunk-RMEJR3AW.js} +5 -2
  36. package/dist/{chunk-UFW4S3RU.js → chunk-RVMCY6DP.js} +1 -1
  37. package/dist/{chunk-LF67HWWR.js → chunk-RWRZVQCB.js} +1 -1
  38. package/dist/chunk-SXIJLSVF.js +41 -0
  39. package/dist/chunk-TDQW2YHK.js +65 -0
  40. package/dist/{chunk-VLDB2SVN.js → chunk-TPTFV3Y6.js} +383 -513
  41. package/dist/{chunk-45UVJXFQ.js → chunk-W2UOVGRC.js} +1 -1
  42. package/dist/{chunk-VXEF2SWG.js → chunk-WT252ZDV.js} +2 -2
  43. package/dist/{chunk-NLB7JZSO.js → chunk-WVEIUSXE.js} +246 -55
  44. package/dist/{chunk-OC2XHG5L.js → chunk-YBZM7PHI.js} +4 -4
  45. package/dist/{ci-6PHEL3C7.js → ci-5HONSUAS.js} +7 -7
  46. package/dist/{ci-format-AZYUP6BL.js → ci-format-URUH3ZZ5.js} +2 -2
  47. package/dist/{constants-CPNWIUGZ.js → constants-BLDBI7IG.js} +1 -1
  48. package/dist/{constants-AXBD2EEB.js → constants-FG27DQMS.js} +1 -1
  49. package/dist/doctor-cli-QQLMNJN7.js +18 -0
  50. package/dist/electron-server.js +1003 -829
  51. package/dist/file-checkpoint-64A2AXHE.js +7 -0
  52. package/dist/{file-checkpoint-NKBHGC7L.js → file-checkpoint-VVPUJNCI.js} +2 -1
  53. package/dist/{hub-DDYAWLF2.js → hub-GGFW3DCC.js} +3 -3
  54. package/dist/{hub-server-CBKCP5VD.js → hub-server-JLC7CNP7.js} +55 -17
  55. package/dist/index.js +42 -40
  56. package/dist/{indexer-P3FPRTPJ.js → indexer-GKIWSSRP.js} +3 -3
  57. package/dist/indexer-VRXDZ74A.js +10 -0
  58. package/dist/{persist-S77WRVLD.js → persist-ZZXRWFBX.js} +4 -4
  59. package/dist/{persistent-memory-XZISXRWT.js → persistent-memory-UNLCXUWH.js} +3 -3
  60. package/dist/{persistent-memory-6XYYOMSC.js → persistent-memory-YYWIN6BG.js} +3 -3
  61. package/dist/{pr-UY4ZCZNI.js → pr-YCFGPFI7.js} +7 -7
  62. package/dist/{project-trust-MUG325AW.js → project-trust-6CJB5ZMX.js} +1 -1
  63. package/dist/{project-trust-NKYHL3VZ.js → project-trust-KGG2BWKC.js} +1 -1
  64. package/dist/run-tests-GHY4BYDE.js +13 -0
  65. package/dist/run-tests-KRNMFXAN.js +12 -0
  66. package/dist/{semantic-7GM5M4MU.js → semantic-N227CLSC.js} +4 -4
  67. package/dist/{semantic-QOBAXEQ4.js → semantic-TRQAZSRY.js} +4 -4
  68. package/dist/{server-6IC33CJK.js → server-73UBHSFV.js} +16 -14
  69. package/dist/{server-DBHLVQVP.js → server-QRAWSG4Z.js} +231 -103
  70. package/dist/{store-SIKHCUYJ.js → store-2N6PPPBP.js} +2 -2
  71. package/dist/{store-CMSSWZF7.js → store-76VVFDXM.js} +2 -2
  72. package/dist/{task-orchestrator-RDDETDW2.js → task-orchestrator-GI3RGLZI.js} +15 -14
  73. package/dist/{usage-D473ZVIP.js → usage-GWTIGZF5.js} +4 -4
  74. package/dist/{vector-store-JAXWDZYW.js → vector-store-T2DVUMY4.js} +2 -2
  75. package/dist/{vector-store-PWIOQFTP.js → vector-store-V6UGEYWK.js} +2 -2
  76. package/dist/web/client/app.js +7 -0
  77. package/dist/web/client/app.js.br +0 -0
  78. package/dist/web/client/app.js.gz +0 -0
  79. package/dist/web/client/util.js +14 -23
  80. package/dist/web/client/util.js.br +0 -0
  81. package/dist/web/client/util.js.gz +0 -0
  82. package/dist/web/client/vendor/DOMPurify-LICENSE.txt +202 -0
  83. package/dist/web/client/vendor/purify.es.mjs +2722 -0
  84. package/dist/web/client/vendor/purify.es.mjs.br +0 -0
  85. package/dist/web/client/vendor/purify.es.mjs.gz +0 -0
  86. package/package.json +4 -2
  87. package/dist/chunk-4BKXL7SM.js +0 -98
  88. package/dist/chunk-6BUTA5VW.js +0 -38
  89. package/dist/chunk-IW3Q7AE5.js +0 -40
  90. package/dist/chunk-SKET65WZ.js +0 -96
  91. package/dist/doctor-cli-DDHHDMMJ.js +0 -18
  92. package/dist/file-checkpoint-CGH6OJVI.js +0 -6
  93. package/dist/indexer-FPKY7LCT.js +0 -10
  94. package/dist/run-tests-BAMLVLO6.js +0 -10
  95. package/dist/run-tests-UEE3OMLS.js +0 -9
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  evaluateCiGate,
4
4
  normalizeCiThresholds
5
- } from "./chunk-K5SDDTN7.js";
5
+ } from "./chunk-NLK45GUS.js";
6
6
  import {
7
7
  buildReviewPrompt,
8
8
  buildSecurityReviewPrompt,
@@ -13,13 +13,13 @@ import {
13
13
  } from "./chunk-6YZEZFX5.js";
14
14
  import {
15
15
  ProviderRegistry
16
- } from "./chunk-VXEF2SWG.js";
16
+ } from "./chunk-WT252ZDV.js";
17
17
  import {
18
18
  ConfigManager
19
- } from "./chunk-OC2XHG5L.js";
19
+ } from "./chunk-YBZM7PHI.js";
20
20
  import {
21
21
  VERSION
22
- } from "./chunk-T6WQEQI4.js";
22
+ } from "./chunk-2MNUMLN4.js";
23
23
 
24
24
  // src/cli/ci.ts
25
25
  import { execFileSync } from "child_process";
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/core/atomic-write.ts
4
+ import fs from "fs";
5
+ import { randomUUID } from "crypto";
6
+ import { setTimeout as delay } from "timers/promises";
7
+ function modeFor(target, options) {
8
+ if (options.mode !== void 0) return options.mode;
9
+ try {
10
+ return fs.statSync(target).mode & 511;
11
+ } catch {
12
+ return 384;
13
+ }
14
+ }
15
+ function atomicWriteFileSync(target, data, options = {}) {
16
+ const tmp = `${target}.${process.pid}.${randomUUID()}.tmp`;
17
+ try {
18
+ fs.writeFileSync(tmp, data, { flag: "wx", mode: modeFor(target, options) });
19
+ fs.renameSync(tmp, target);
20
+ } finally {
21
+ try {
22
+ fs.unlinkSync(tmp);
23
+ } catch {
24
+ }
25
+ }
26
+ }
27
+ var pending = /* @__PURE__ */ new Map();
28
+ async function atomicWriteFile(target, data, options = {}) {
29
+ const previous = pending.get(target) ?? Promise.resolve();
30
+ const operation = previous.catch(() => {
31
+ }).then(async () => {
32
+ const tmp = `${target}.${process.pid}.${randomUUID()}.tmp`;
33
+ try {
34
+ let mode = options.mode ?? 384;
35
+ if (options.mode === void 0) {
36
+ try {
37
+ mode = (await fs.promises.stat(target)).mode & 511;
38
+ } catch {
39
+ }
40
+ }
41
+ await fs.promises.writeFile(tmp, data, { flag: "wx", mode });
42
+ for (let attempt = 0; ; attempt++) {
43
+ try {
44
+ await fs.promises.rename(tmp, target);
45
+ break;
46
+ } catch (error) {
47
+ if (attempt >= 10 || !["EPERM", "EBUSY", "EACCES"].includes(error.code ?? "")) throw error;
48
+ await delay(5 * (attempt + 1));
49
+ }
50
+ }
51
+ } finally {
52
+ try {
53
+ await fs.promises.unlink(tmp);
54
+ } catch {
55
+ }
56
+ }
57
+ });
58
+ pending.set(target, operation);
59
+ try {
60
+ await operation;
61
+ } finally {
62
+ if (pending.get(target) === operation) pending.delete(target);
63
+ }
64
+ }
65
+
66
+ export {
67
+ atomicWriteFileSync,
68
+ atomicWriteFile
69
+ };
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-KHYD3WXE.js";
5
5
  import {
6
6
  atomicWriteFileSync
7
- } from "./chunk-IW3Q7AE5.js";
7
+ } from "./chunk-BMLQPSHP.js";
8
8
 
9
9
  // src/symbols/vector-store.ts
10
10
  import fs from "fs";
@@ -8,13 +8,13 @@ import {
8
8
  listHooks,
9
9
  listInstalledPlugins,
10
10
  resetStats
11
- } from "./chunk-7SSCSSC6.js";
11
+ } from "./chunk-3537CQ5M.js";
12
12
  import {
13
13
  ProviderRegistry
14
- } from "./chunk-VXEF2SWG.js";
14
+ } from "./chunk-WT252ZDV.js";
15
15
  import {
16
16
  ConfigManager
17
- } from "./chunk-OC2XHG5L.js";
17
+ } from "./chunk-YBZM7PHI.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-T6WQEQI4.js";
29
+ } from "./chunk-2MNUMLN4.js";
30
30
 
31
31
  // src/diagnostics/doctor-report.ts
32
32
  import { existsSync as existsSync3, statSync as statSync2 } from "fs";
@@ -0,0 +1,161 @@
1
+ import {
2
+ getExecutionConfigDir,
3
+ scopedState
4
+ } from "./chunk-QMFMST2T.js";
5
+
6
+ // src/security/file-access.ts
7
+ import { existsSync, realpathSync, openSync, readSync, closeSync, statSync } from "fs";
8
+ import { basename, dirname, resolve, join } from "path";
9
+ import { homedir } from "os";
10
+ function canonicalPath(value) {
11
+ let cursor = resolve(value);
12
+ const missing = [];
13
+ while (!existsSync(cursor)) {
14
+ const parent = dirname(cursor);
15
+ if (parent === cursor) throw new Error("Cannot resolve path");
16
+ missing.unshift(basename(cursor));
17
+ cursor = parent;
18
+ }
19
+ return resolve(realpathSync(cursor), ...missing);
20
+ }
21
+ function isCredentialVault(value) {
22
+ const normalize = (p) => process.platform === "win32" ? p.toLowerCase() : p;
23
+ const target = normalize(canonicalPath(value));
24
+ const hostRoot = normalize(canonicalPath(join(homedir(), ".aicli")));
25
+ if (basename(target) === "config.json" && normalize(dirname(dirname(dirname(target)))) === hostRoot && basename(dirname(dirname(target))) === "users") return true;
26
+ return [getExecutionConfigDir(), join(homedir(), ".aicli")].some((root) => ["config.json", "users.json"].some((file) => {
27
+ const vault = canonicalPath(join(root, file));
28
+ if (target === normalize(vault)) return true;
29
+ try {
30
+ const a = statSync(target), b = statSync(vault);
31
+ return a.ino !== 0 && a.dev === b.dev && a.ino === b.ino;
32
+ } catch {
33
+ return false;
34
+ }
35
+ }));
36
+ }
37
+ function assertReadablePath(value) {
38
+ if (isCredentialVault(value)) throw new Error("[Refused] Credential vault files cannot be read by tools. Use aicli config or an external editor.");
39
+ }
40
+ var MAX_SNAPSHOT_BYTES = 2 * 1024 * 1024;
41
+ var MAX_SNAPSHOT_TOTAL_BYTES = 16 * 1024 * 1024;
42
+ function readSnapshot(value) {
43
+ const fd = openSync(value, "r");
44
+ try {
45
+ const buffer = Buffer.alloc(MAX_SNAPSHOT_BYTES + 1);
46
+ let bytes = 0;
47
+ while (bytes < buffer.length) {
48
+ const n = readSync(fd, buffer, bytes, buffer.length - bytes, null);
49
+ if (!n) break;
50
+ bytes += n;
51
+ }
52
+ if (bytes > MAX_SNAPSHOT_BYTES) throw new Error("File exceeds 2 MiB snapshot limit; edit refused because a complete undo snapshot cannot be kept.");
53
+ return buffer.subarray(0, bytes).toString("utf8");
54
+ } finally {
55
+ closeSync(fd);
56
+ }
57
+ }
58
+
59
+ // src/tools/file-checkpoint.ts
60
+ import { existsSync as existsSync2, writeFileSync, unlinkSync } from "fs";
61
+ var MAX_SNAPSHOTS = 200;
62
+ var FileCheckpointStore = class {
63
+ stateKey = /* @__PURE__ */ Symbol("snapshots");
64
+ get snapshots() {
65
+ return scopedState(this.stateKey, () => ({ items: [] })).items;
66
+ }
67
+ set snapshots(items) {
68
+ scopedState(this.stateKey, () => ({ items: [] })).items = items;
69
+ }
70
+ /**
71
+ * 在文件写入前调用,保存当前文件内容。
72
+ * 同一 messageIndex 下同一文件只记录首次快照。
73
+ */
74
+ snapshot(filePath, messageIndex) {
75
+ const exists = this.snapshots.some(
76
+ (s) => s.filePath === filePath && s.messageIndex === messageIndex
77
+ );
78
+ if (exists) return;
79
+ let content = null;
80
+ if (existsSync2(filePath)) {
81
+ content = readSnapshot(filePath);
82
+ }
83
+ this.snapshots.push({
84
+ filePath,
85
+ content,
86
+ messageIndex,
87
+ timestamp: Date.now()
88
+ });
89
+ while (this.snapshots.length > MAX_SNAPSHOTS || this.snapshots.reduce((n, e) => n + Buffer.byteLength(e.content ?? ""), 0) > MAX_SNAPSHOT_TOTAL_BYTES) {
90
+ this.snapshots.shift();
91
+ }
92
+ }
93
+ /**
94
+ * 恢复所有在指定消息索引之后被修改的文件到该索引时的状态。
95
+ * @returns 恢复和删除的文件数量
96
+ */
97
+ restoreToMessageIndex(targetIndex) {
98
+ const modifiedAfter = this.snapshots.filter((s) => s.messageIndex > targetIndex);
99
+ const uniqueFiles = [...new Set(modifiedAfter.map((s) => s.filePath))];
100
+ let restored = 0;
101
+ let deleted = 0;
102
+ const files = [];
103
+ for (const filePath of uniqueFiles) {
104
+ const beforeSnapshots = this.snapshots.filter((s) => s.filePath === filePath && s.messageIndex <= targetIndex).sort((a, b) => b.messageIndex - a.messageIndex);
105
+ const restoreTo = beforeSnapshots[0];
106
+ try {
107
+ if (restoreTo) {
108
+ if (restoreTo.content === null) {
109
+ if (existsSync2(filePath)) {
110
+ unlinkSync(filePath);
111
+ deleted++;
112
+ files.push(filePath);
113
+ }
114
+ } else {
115
+ writeFileSync(filePath, restoreTo.content, "utf-8");
116
+ restored++;
117
+ files.push(filePath);
118
+ }
119
+ } else {
120
+ const earliest = this.snapshots.filter((s) => s.filePath === filePath).sort((a, b) => a.messageIndex - b.messageIndex)[0];
121
+ if (earliest && earliest.content === null) {
122
+ if (existsSync2(filePath)) {
123
+ unlinkSync(filePath);
124
+ deleted++;
125
+ files.push(filePath);
126
+ }
127
+ } else if (earliest) {
128
+ writeFileSync(filePath, earliest.content, "utf-8");
129
+ restored++;
130
+ files.push(filePath);
131
+ }
132
+ }
133
+ } catch {
134
+ }
135
+ }
136
+ this.snapshots = this.snapshots.filter((s) => s.messageIndex <= targetIndex);
137
+ return { restored, deleted, files };
138
+ }
139
+ /** 获取所有快照(供调试/显示) */
140
+ getSnapshots() {
141
+ return this.snapshots;
142
+ }
143
+ /** 获取有快照的消息索引列表(去重排序) */
144
+ getMessageIndices() {
145
+ return [...new Set(this.snapshots.map((s) => s.messageIndex))].sort((a, b) => a - b);
146
+ }
147
+ /** 清空所有快照(新会话/清除时调用) */
148
+ clear() {
149
+ this.snapshots = [];
150
+ }
151
+ };
152
+ var fileCheckpoints = new FileCheckpointStore();
153
+
154
+ export {
155
+ canonicalPath,
156
+ isCredentialVault,
157
+ assertReadablePath,
158
+ MAX_SNAPSHOT_TOTAL_BYTES,
159
+ readSnapshot,
160
+ fileCheckpoints
161
+ };
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-RS7SKYTS.js";
5
5
  import {
6
6
  atomicWriteFileSync
7
- } from "./chunk-IW3Q7AE5.js";
7
+ } from "./chunk-BMLQPSHP.js";
8
8
 
9
9
  // src/core/pricing.ts
10
10
  var CNY_PER_USD = 6.9;
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  computeCost,
4
4
  formatCost
5
- } from "./chunk-YKJO3SI4.js";
5
+ } from "./chunk-G6DVGQ4I.js";
6
6
  import {
7
7
  clearRecentlyDeniedAutoActions,
8
8
  estimateTokens,
@@ -16,7 +16,7 @@ import {
16
16
  setPreferredAgentName,
17
17
  truncateForPersist,
18
18
  undoStack
19
- } from "./chunk-VLDB2SVN.js";
19
+ } from "./chunk-TPTFV3Y6.js";
20
20
  import {
21
21
  buildReviewPrompt,
22
22
  buildSecurityReviewPrompt
@@ -26,7 +26,7 @@ import {
26
26
  clearChatIndex,
27
27
  getChatIndexStatus,
28
28
  searchChatMemory
29
- } from "./chunk-GHWZVPUV.js";
29
+ } from "./chunk-6JHACXB3.js";
30
30
  import {
31
31
  addMemoryEntry,
32
32
  backupMemoryStore,
@@ -51,13 +51,13 @@ import {
51
51
  touchMemoryReferences,
52
52
  updateMemoryApproval,
53
53
  updateMemoryEntry
54
- } from "./chunk-LAP7TPPK.js";
54
+ } from "./chunk-LR3TGZWQ.js";
55
55
  import {
56
56
  theme
57
57
  } from "./chunk-5C76XDDF.js";
58
58
  import {
59
59
  getContentText
60
- } from "./chunk-IUVDZVZ4.js";
60
+ } from "./chunk-AXTLYOA7.js";
61
61
  import {
62
62
  DEFAULT_PATTERNS,
63
63
  scanString
@@ -65,7 +65,7 @@ import {
65
65
  import {
66
66
  buildDoctorReport,
67
67
  formatDoctorReport
68
- } from "./chunk-JFNBJHR6.js";
68
+ } from "./chunk-E2PNXNKI.js";
69
69
  import {
70
70
  describePlugin,
71
71
  getActivePluginAssets,
@@ -80,24 +80,24 @@ import {
80
80
  trustHook,
81
81
  trustPlugin,
82
82
  untrustHook
83
- } from "./chunk-7SSCSSC6.js";
83
+ } from "./chunk-3537CQ5M.js";
84
84
  import {
85
85
  isCleanDocumentBody,
86
86
  stripOuterCodeFence
87
- } from "./chunk-MI4SFZGX.js";
87
+ } from "./chunk-RMEJR3AW.js";
88
88
  import {
89
89
  formatGitContextForPrompt,
90
90
  getGitContext
91
91
  } from "./chunk-HOSJZMQS.js";
92
92
  import {
93
93
  atomicWriteFileSync
94
- } from "./chunk-IW3Q7AE5.js";
94
+ } from "./chunk-BMLQPSHP.js";
95
95
  import {
96
96
  applyConfigCommand
97
97
  } from "./chunk-XNFIYS7G.js";
98
98
  import {
99
99
  fileCheckpoints
100
- } from "./chunk-4BKXL7SM.js";
100
+ } from "./chunk-JJFJWD35.js";
101
101
  import {
102
102
  APP_NAME,
103
103
  CONFIG_DIR_NAME,
@@ -109,7 +109,7 @@ import {
109
109
  MCP_TOOL_PREFIX,
110
110
  REPO_URL,
111
111
  VERSION
112
- } from "./chunk-T6WQEQI4.js";
112
+ } from "./chunk-2MNUMLN4.js";
113
113
 
114
114
  // src/skills/manager.ts
115
115
  import { existsSync, readdirSync, mkdirSync, statSync } from "fs";
@@ -2426,8 +2426,8 @@ No tools match "${filter}".
2426
2426
  const { join: join6 } = await import("path");
2427
2427
  const { existsSync: existsSync6 } = await import("fs");
2428
2428
  const { getGitRoot } = await import("./git-context-EXOEHQSF.js");
2429
- const { MCP_PROJECT_CONFIG_NAME } = await import("./constants-CPNWIUGZ.js");
2430
- const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
2429
+ const { MCP_PROJECT_CONFIG_NAME } = await import("./constants-BLDBI7IG.js");
2430
+ const { approveProject, hashMcpFile } = await import("./project-trust-KGG2BWKC.js");
2431
2431
  const cwd = process.cwd();
2432
2432
  const projectRoot = getGitRoot(cwd) ?? cwd;
2433
2433
  const mcpPath = join6(projectRoot, MCP_PROJECT_CONFIG_NAME);
@@ -3534,7 +3534,7 @@ function createReviewCommands() {
3534
3534
  usage: "/test [command|filter]",
3535
3535
  async execute(args, ctx) {
3536
3536
  try {
3537
- const { executeTests } = await import("./run-tests-BAMLVLO6.js");
3537
+ const { executeTests } = await import("./run-tests-GHY4BYDE.js");
3538
3538
  const argStr = args.join(" ").trim();
3539
3539
  let testArgs = {};
3540
3540
  if (argStr) {
@@ -3900,9 +3900,9 @@ function createMemoryCommands() {
3900
3900
  async execute(args, ctx) {
3901
3901
  const sub = (args[0] ?? "status").toLowerCase();
3902
3902
  const root = process.cwd();
3903
- const { loadIndex, clearIndex } = await import("./store-CMSSWZF7.js");
3904
- const { indexProject } = await import("./indexer-P3FPRTPJ.js");
3905
- const { loadVectorStore, clearVectorStore } = await import("./vector-store-PWIOQFTP.js");
3903
+ const { loadIndex, clearIndex } = await import("./store-76VVFDXM.js");
3904
+ const { indexProject } = await import("./indexer-GKIWSSRP.js");
3905
+ const { loadVectorStore, clearVectorStore } = await import("./vector-store-V6UGEYWK.js");
3906
3906
  if (sub === "status") {
3907
3907
  const idx = loadIndex(root);
3908
3908
  const vec = loadVectorStore(root);
@@ -3962,7 +3962,7 @@ function createMemoryCommands() {
3962
3962
  }
3963
3963
  console.log(theme.dim(` Building semantic index for ${idx.symbolCount} symbols\u2026`));
3964
3964
  console.log(theme.dim(" (First run downloads ~117 MB embedding model to ~/.aicli/models/)"));
3965
- const { rebuildSemanticIndex } = await import("./semantic-7GM5M4MU.js");
3965
+ const { rebuildSemanticIndex } = await import("./semantic-N227CLSC.js");
3966
3966
  try {
3967
3967
  const stats = await rebuildSemanticIndex(root, {
3968
3968
  onProgress: (done, total) => {
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ getExecutionConfigDir,
4
+ scopedState
5
+ } from "./chunk-SXIJLSVF.js";
6
+
7
+ // src/security/file-access.ts
8
+ import { existsSync, realpathSync, openSync, readSync, closeSync, statSync } from "fs";
9
+ import { basename, dirname, resolve, join } from "path";
10
+ import { homedir } from "os";
11
+ function canonicalPath(value) {
12
+ let cursor = resolve(value);
13
+ const missing = [];
14
+ while (!existsSync(cursor)) {
15
+ const parent = dirname(cursor);
16
+ if (parent === cursor) throw new Error("Cannot resolve path");
17
+ missing.unshift(basename(cursor));
18
+ cursor = parent;
19
+ }
20
+ return resolve(realpathSync(cursor), ...missing);
21
+ }
22
+ function isCredentialVault(value) {
23
+ const normalize = (p) => process.platform === "win32" ? p.toLowerCase() : p;
24
+ const target = normalize(canonicalPath(value));
25
+ const hostRoot = normalize(canonicalPath(join(homedir(), ".aicli")));
26
+ if (basename(target) === "config.json" && normalize(dirname(dirname(dirname(target)))) === hostRoot && basename(dirname(dirname(target))) === "users") return true;
27
+ return [getExecutionConfigDir(), join(homedir(), ".aicli")].some((root) => ["config.json", "users.json"].some((file) => {
28
+ const vault = canonicalPath(join(root, file));
29
+ if (target === normalize(vault)) return true;
30
+ try {
31
+ const a = statSync(target), b = statSync(vault);
32
+ return a.ino !== 0 && a.dev === b.dev && a.ino === b.ino;
33
+ } catch {
34
+ return false;
35
+ }
36
+ }));
37
+ }
38
+ function assertReadablePath(value) {
39
+ if (isCredentialVault(value)) throw new Error("[Refused] Credential vault files cannot be read by tools. Use aicli config or an external editor.");
40
+ }
41
+ var MAX_SNAPSHOT_BYTES = 2 * 1024 * 1024;
42
+ var MAX_SNAPSHOT_TOTAL_BYTES = 16 * 1024 * 1024;
43
+ function readSnapshot(value) {
44
+ const fd = openSync(value, "r");
45
+ try {
46
+ const buffer = Buffer.alloc(MAX_SNAPSHOT_BYTES + 1);
47
+ let bytes = 0;
48
+ while (bytes < buffer.length) {
49
+ const n = readSync(fd, buffer, bytes, buffer.length - bytes, null);
50
+ if (!n) break;
51
+ bytes += n;
52
+ }
53
+ if (bytes > MAX_SNAPSHOT_BYTES) throw new Error("File exceeds 2 MiB snapshot limit; edit refused because a complete undo snapshot cannot be kept.");
54
+ return buffer.subarray(0, bytes).toString("utf8");
55
+ } finally {
56
+ closeSync(fd);
57
+ }
58
+ }
59
+
60
+ // src/tools/file-checkpoint.ts
61
+ import { existsSync as existsSync2, writeFileSync, unlinkSync } from "fs";
62
+ var MAX_SNAPSHOTS = 200;
63
+ var FileCheckpointStore = class {
64
+ stateKey = /* @__PURE__ */ Symbol("snapshots");
65
+ get snapshots() {
66
+ return scopedState(this.stateKey, () => ({ items: [] })).items;
67
+ }
68
+ set snapshots(items) {
69
+ scopedState(this.stateKey, () => ({ items: [] })).items = items;
70
+ }
71
+ /**
72
+ * 在文件写入前调用,保存当前文件内容。
73
+ * 同一 messageIndex 下同一文件只记录首次快照。
74
+ */
75
+ snapshot(filePath, messageIndex) {
76
+ const exists = this.snapshots.some(
77
+ (s) => s.filePath === filePath && s.messageIndex === messageIndex
78
+ );
79
+ if (exists) return;
80
+ let content = null;
81
+ if (existsSync2(filePath)) {
82
+ content = readSnapshot(filePath);
83
+ }
84
+ this.snapshots.push({
85
+ filePath,
86
+ content,
87
+ messageIndex,
88
+ timestamp: Date.now()
89
+ });
90
+ while (this.snapshots.length > MAX_SNAPSHOTS || this.snapshots.reduce((n, e) => n + Buffer.byteLength(e.content ?? ""), 0) > MAX_SNAPSHOT_TOTAL_BYTES) {
91
+ this.snapshots.shift();
92
+ }
93
+ }
94
+ /**
95
+ * 恢复所有在指定消息索引之后被修改的文件到该索引时的状态。
96
+ * @returns 恢复和删除的文件数量
97
+ */
98
+ restoreToMessageIndex(targetIndex) {
99
+ const modifiedAfter = this.snapshots.filter((s) => s.messageIndex > targetIndex);
100
+ const uniqueFiles = [...new Set(modifiedAfter.map((s) => s.filePath))];
101
+ let restored = 0;
102
+ let deleted = 0;
103
+ const files = [];
104
+ for (const filePath of uniqueFiles) {
105
+ const beforeSnapshots = this.snapshots.filter((s) => s.filePath === filePath && s.messageIndex <= targetIndex).sort((a, b) => b.messageIndex - a.messageIndex);
106
+ const restoreTo = beforeSnapshots[0];
107
+ try {
108
+ if (restoreTo) {
109
+ if (restoreTo.content === null) {
110
+ if (existsSync2(filePath)) {
111
+ unlinkSync(filePath);
112
+ deleted++;
113
+ files.push(filePath);
114
+ }
115
+ } else {
116
+ writeFileSync(filePath, restoreTo.content, "utf-8");
117
+ restored++;
118
+ files.push(filePath);
119
+ }
120
+ } else {
121
+ const earliest = this.snapshots.filter((s) => s.filePath === filePath).sort((a, b) => a.messageIndex - b.messageIndex)[0];
122
+ if (earliest && earliest.content === null) {
123
+ if (existsSync2(filePath)) {
124
+ unlinkSync(filePath);
125
+ deleted++;
126
+ files.push(filePath);
127
+ }
128
+ } else if (earliest) {
129
+ writeFileSync(filePath, earliest.content, "utf-8");
130
+ restored++;
131
+ files.push(filePath);
132
+ }
133
+ }
134
+ } catch {
135
+ }
136
+ }
137
+ this.snapshots = this.snapshots.filter((s) => s.messageIndex <= targetIndex);
138
+ return { restored, deleted, files };
139
+ }
140
+ /** 获取所有快照(供调试/显示) */
141
+ getSnapshots() {
142
+ return this.snapshots;
143
+ }
144
+ /** 获取有快照的消息索引列表(去重排序) */
145
+ getMessageIndices() {
146
+ return [...new Set(this.snapshots.map((s) => s.messageIndex))].sort((a, b) => a - b);
147
+ }
148
+ /** 清空所有快照(新会话/清除时调用) */
149
+ clear() {
150
+ this.snapshots = [];
151
+ }
152
+ };
153
+ var fileCheckpoints = new FileCheckpointStore();
154
+
155
+ export {
156
+ canonicalPath,
157
+ isCredentialVault,
158
+ assertReadablePath,
159
+ MAX_SNAPSHOT_TOTAL_BYTES,
160
+ readSnapshot,
161
+ fileCheckpoints
162
+ };