jinzd-ai-cli 0.4.233 → 0.4.234

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 (35) hide show
  1. package/dist/{batch-WWNPYQ6G.js → batch-T3FRX4B6.js} +2 -2
  2. package/dist/{chat-index-O56HDGFI.js → chat-index-7HXBWQFH.js} +2 -2
  3. package/dist/{chat-index-WSI7ULRQ.js → chat-index-WYXYD7YP.js} +1 -1
  4. package/dist/{chunk-4KM53GLG.js → chunk-2QQKS56X.js} +1 -1
  5. package/dist/{chunk-ACTO5C6K.js → chunk-3KTSJ2EL.js} +1 -1
  6. package/dist/{chunk-NXYXFRPA.js → chunk-5DTEEWYC.js} +3 -3
  7. package/dist/{chunk-NVUCDUXE.js → chunk-5MYPIQ3Y.js} +11 -5
  8. package/dist/{chunk-7KS3RGZ7.js → chunk-5VPRZMZB.js} +2 -2
  9. package/dist/{chunk-FQSAK75P.js → chunk-6MJMHHRK.js} +3 -3
  10. package/dist/{chunk-M4FW2NPU.js → chunk-AFT6VFMI.js} +1 -1
  11. package/dist/{chunk-HX67JAK6.js → chunk-E5RLXMSU.js} +5 -5
  12. package/dist/{chunk-4OAV7QMB.js → chunk-ETJ5X6V7.js} +1 -1
  13. package/dist/{chunk-EZGZOK6E.js → chunk-II6RZRTF.js} +1 -1
  14. package/dist/{chunk-ZWU7FWHO.js → chunk-JMP3LJC2.js} +38 -91
  15. package/dist/chunk-KCEO2XJ4.js +420 -0
  16. package/dist/{chunk-5PKNKJYP.js → chunk-L5PNAQ6O.js} +1 -1
  17. package/dist/{chunk-TJK7AU65.js → chunk-TAXIG7HH.js} +1 -1
  18. package/dist/{chunk-LF3OUJHK.js → chunk-UO3XWZFE.js} +302 -4
  19. package/dist/{ci-V5V3JSJC.js → ci-GJ53GPLA.js} +4 -4
  20. package/dist/{ci-format-XS7LKBO5.js → ci-format-AXE4QCI6.js} +2 -2
  21. package/dist/{constants-UROQJXLY.js → constants-DC4EXFSB.js} +1 -1
  22. package/dist/{doctor-cli-BY3FIV2B.js → doctor-cli-HKREND6Q.js} +4 -4
  23. package/dist/electron-server.js +43 -96
  24. package/dist/{hub-L2QCRI5M.js → hub-LTTKRGZC.js} +2 -2
  25. package/dist/index.js +22 -22
  26. package/dist/{persist-I3JI27OK.js → persist-AMH5SQ4W.js} +3 -3
  27. package/dist/{pr-IJRUPR5C.js → pr-4VODJVRV.js} +4 -4
  28. package/dist/{run-tests-FLCVJ6TK.js → run-tests-G5BNTMWQ.js} +2 -2
  29. package/dist/{run-tests-NNXBS4EL.js → run-tests-QR2PYR2P.js} +1 -1
  30. package/dist/{server-W2X3C6GJ.js → server-64WZVZZN.js} +15 -15
  31. package/dist/{server-E6LZB72O.js → server-EO6VQHKL.js} +6 -6
  32. package/dist/{task-orchestrator-W55VKYTC.js → task-orchestrator-4INCZMLT.js} +6 -6
  33. package/dist/{usage-MZCDTJWB.js → usage-T3HFMNNV.js} +2 -2
  34. package/package.json +1 -1
  35. package/dist/chunk-B5TYJO7V.js +0 -123
@@ -0,0 +1,420 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ atomicWriteFileSync
4
+ } from "./chunk-IW3Q7AE5.js";
5
+
6
+ // src/security/redactor.ts
7
+ var DEFAULT_PATTERNS = [
8
+ // password: xxx / password = xxx / password="xxx"
9
+ // Covers YAML / JSON / shell-ish / env-file forms.
10
+ { kind: "password", regex: /\b(password|passwd|pwd)\s*[:=]\s*["']?([^\s"',;{}]{4,200})["']?/gi },
11
+ // PGPASSWORD=xxx (explicit bash env-var form, separate rule because no quotes usually)
12
+ { kind: "pgpassword-env", regex: /\b(PGPASSWORD)=([^\s"']{4,200})/g },
13
+ // JDBC/PG/MySQL/Mongo connection strings with inline credentials
14
+ // postgresql://user:pass@host/db → redact pass
15
+ { kind: "db-uri-password", regex: /(\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp|mssql):\/\/[^:\s]+:)([^@\s]+)(@)/gi },
16
+ // Anthropic API keys
17
+ { kind: "anthropic-key", regex: /(sk-ant-[a-zA-Z0-9_-]{90,})/g },
18
+ // L6 (v0.4.108): Zhipu / GLM API keys — `<24+ hex/base64-ish>.<32+>`
19
+ // Two segments separated by a dot, each safely identifiable by length
20
+ // and char class. Conservative on the lower bound so we don't eat
21
+ // version strings like `1.0.0` or filenames.
22
+ { kind: "zhipu-key", regex: /\b([a-zA-Z0-9]{24,}\.[a-zA-Z0-9]{32,})\b/g },
23
+ // OpenAI / generic sk- keys — requires length ≥32 to avoid eating short identifiers
24
+ { kind: "openai-key", regex: /(sk-(?:proj-)?[a-zA-Z0-9_-]{32,})/g },
25
+ // GitHub personal access tokens
26
+ { kind: "github-pat", regex: /\b(ghp_[a-zA-Z0-9]{36})\b/g },
27
+ { kind: "github-oauth", regex: /\b(gho_[a-zA-Z0-9]{36})\b/g },
28
+ { kind: "github-install", regex: /\b(ghs_[a-zA-Z0-9]{36})\b/g },
29
+ // Slack tokens
30
+ { kind: "slack-bot", regex: /\b(xoxb-\d+-\d+-[a-zA-Z0-9]+)\b/g },
31
+ { kind: "slack-user", regex: /\b(xoxp-\d+-\d+-\d+-[a-zA-Z0-9]+)\b/g },
32
+ // AWS access key IDs (AKIA...) and secret access keys are context-dependent;
33
+ // we only catch the ID because secret key alone is indistinguishable from random base64.
34
+ { kind: "aws-access-key-id", regex: /\b(AKIA[0-9A-Z]{16})\b/g },
35
+ // Google API keys
36
+ { kind: "google-api-key", regex: /\b(AIza[0-9A-Za-z_-]{35})\b/g },
37
+ // Generic "api_key": "..." / "apiKey": "..." / api-key=xxx
38
+ { kind: "api-key", regex: /\b(api[_-]?key)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{16,200})["']?/gi },
39
+ // Generic token: xxx (only when value looks token-shaped; avoids eating human prose)
40
+ { kind: "token", regex: /\b(token|access[_-]?token|bearer[_-]?token)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{20,300})["']?/gi },
41
+ // Bearer <token> in Authorization headers
42
+ { kind: "bearer", regex: /\b(Authorization:\s*Bearer\s+)([a-zA-Z0-9_\-.=]{20,500})/g },
43
+ // Private key PEM blocks — catch the header+footer together
44
+ // P2-PERF-02: PEM bodies use strict Base64 + =\n — narrowed char class avoids backtracking
45
+ { kind: "private-key", regex: /-----BEGIN [A-Z ]*PRIVATE KEY-----[ \t\n\r]*[A-Za-z0-9+/=\n\r-]*[ \t\n\r]*-----END [A-Z ]*PRIVATE KEY-----/g }
46
+ ];
47
+ var MAX_CUSTOM = 32;
48
+ var MAX_PATTERN_LEN = 500;
49
+ var SUSPICIOUS_REDOS = /\([^)]*[+*][^)]*\)\s*[+*{]/;
50
+ var MAX_REDACT_INPUT = 512e3;
51
+ function render(placeholder, kind) {
52
+ return placeholder.replace("{kind}", kind);
53
+ }
54
+ function redactString(input, options) {
55
+ if (!options.enabled || !input) return { redacted: input, hits: [] };
56
+ if (input.length > MAX_REDACT_INPUT) return { redacted: input, hits: [] };
57
+ const placeholder = options.placeholder ?? "[REDACTED:{kind}]";
58
+ const customSrcs = (options.customRegexes ?? []).slice(0, MAX_CUSTOM);
59
+ const patterns = [
60
+ ...options.patterns ?? DEFAULT_PATTERNS,
61
+ ...customSrcs.flatMap((src, i) => {
62
+ if (typeof src !== "string" || src.length === 0 || src.length > MAX_PATTERN_LEN) return [];
63
+ try {
64
+ const flags = src.match(/^\/.*\/([gimsuy]*)$/)?.[1] ?? "";
65
+ const body = src.replace(/^\/(.*)\/[gimsuy]*$/, "$1");
66
+ if (SUSPICIOUS_REDOS.test(body)) return [];
67
+ const regex = new RegExp(body, flags.includes("g") ? flags : flags + "g");
68
+ return [{ kind: `custom-${i}`, regex }];
69
+ } catch {
70
+ return [];
71
+ }
72
+ })
73
+ ];
74
+ let redacted = input;
75
+ const hits = [];
76
+ for (const { kind, regex } of patterns) {
77
+ const rx = new RegExp(regex.source, regex.flags);
78
+ const captureCount = new RegExp(rx.source + "|").exec("").length - 1;
79
+ redacted = redacted.replace(rx, (...args) => {
80
+ const match = args[0];
81
+ const g1 = captureCount >= 1 ? args[1] : void 0;
82
+ const g2 = captureCount >= 2 ? args[2] : void 0;
83
+ const offset = args[1 + captureCount];
84
+ if (captureCount >= 2 && typeof g2 === "string") {
85
+ hits.push({ kind, start: offset + (g1?.length ?? 0), length: g2.length, secret: g2 });
86
+ return `${g1}${render(placeholder, kind)}`;
87
+ }
88
+ hits.push({ kind, start: offset, length: match.length, secret: g1 ?? match });
89
+ return render(placeholder, kind);
90
+ });
91
+ }
92
+ return { redacted, hits };
93
+ }
94
+ function redactJson(value, options) {
95
+ if (!options.enabled) return { value, hits: [] };
96
+ const allHits = [];
97
+ function walk(v) {
98
+ if (typeof v === "string") {
99
+ const r = redactString(v, options);
100
+ allHits.push(...r.hits);
101
+ return r.redacted;
102
+ }
103
+ if (Array.isArray(v)) return v.map(walk);
104
+ if (v && typeof v === "object") {
105
+ const out = {};
106
+ for (const [k, vv] of Object.entries(v)) {
107
+ out[k] = walk(vv);
108
+ }
109
+ return out;
110
+ }
111
+ return v;
112
+ }
113
+ const redacted = walk(value);
114
+ return { value: redacted, hits: allHits };
115
+ }
116
+ function scanString(input, options) {
117
+ const { hits } = redactString(input, { ...options, enabled: true });
118
+ return hits;
119
+ }
120
+
121
+ // src/session/session-index.ts
122
+ import { existsSync, readFileSync as readFileSync2, readdirSync, statSync } from "fs";
123
+ import { join } from "path";
124
+
125
+ // src/session/session-meta.ts
126
+ import { readFileSync, openSync, readSync, closeSync } from "fs";
127
+ function safeDate(value) {
128
+ const d = new Date(value);
129
+ return isNaN(d.getTime()) ? /* @__PURE__ */ new Date(0) : d;
130
+ }
131
+ function extractJsonField(header, field) {
132
+ const re = new RegExp(`"${field}"\\s*:\\s*"([^"]*)"`, "i");
133
+ const m = header.match(re);
134
+ return m ? m[1] : void 0;
135
+ }
136
+ function extractJsonNumberField(header, field) {
137
+ const m = header.match(new RegExp(`"${field}"\\s*:\\s*(\\d+)`));
138
+ return m ? Number(m[1]) : void 0;
139
+ }
140
+ function readSessionMeta(filePath) {
141
+ const HEADER_SIZE = 1024;
142
+ let header;
143
+ try {
144
+ const fd = openSync(filePath, "r");
145
+ const buf = Buffer.alloc(HEADER_SIZE);
146
+ const bytesRead = readSync(fd, buf, 0, HEADER_SIZE, 0);
147
+ closeSync(fd);
148
+ header = buf.toString("utf-8", 0, bytesRead);
149
+ } catch {
150
+ return null;
151
+ }
152
+ const id = extractJsonField(header, "id");
153
+ const provider = extractJsonField(header, "provider");
154
+ const model = extractJsonField(header, "model");
155
+ const created = extractJsonField(header, "created");
156
+ const updated = extractJsonField(header, "updated");
157
+ const title = extractJsonField(header, "title");
158
+ if (id && provider && model) {
159
+ let messageCount = extractJsonNumberField(header, "messageCount");
160
+ if (messageCount === void 0) {
161
+ messageCount = 0;
162
+ try {
163
+ const full = readFileSync(filePath, "utf-8");
164
+ const matches = full.match(/"role"\s*:/g);
165
+ messageCount = matches ? matches.length : 0;
166
+ } catch {
167
+ }
168
+ }
169
+ let branchCount;
170
+ let activeBranch;
171
+ try {
172
+ const brMatch = header.match(/"branches"\s*:\s*\[/);
173
+ if (brMatch) {
174
+ const parentMatches = header.match(/"parentBranchId"/g);
175
+ branchCount = parentMatches ? parentMatches.length + 1 : 1;
176
+ }
177
+ activeBranch = extractJsonField(header, "activeBranchId");
178
+ } catch {
179
+ }
180
+ return {
181
+ id,
182
+ provider,
183
+ model,
184
+ messageCount,
185
+ created: safeDate(created),
186
+ updated: safeDate(updated),
187
+ title: title || void 0,
188
+ branchCount,
189
+ activeBranch
190
+ };
191
+ }
192
+ const data = JSON.parse(readFileSync(filePath, "utf-8"));
193
+ return {
194
+ id: data.id,
195
+ provider: data.provider,
196
+ model: data.model,
197
+ messageCount: data.messages?.length ?? 0,
198
+ created: safeDate(data.created),
199
+ updated: safeDate(data.updated),
200
+ title: data.title,
201
+ branchCount: data.branches?.length ?? 1,
202
+ activeBranch: data.activeBranchId
203
+ };
204
+ }
205
+
206
+ // src/session/session-index.ts
207
+ var INDEX_FILE = "sessions.index.json";
208
+ function indexFilePath(historyDir) {
209
+ return join(historyDir, INDEX_FILE);
210
+ }
211
+ function loadIndex(historyDir) {
212
+ const fp = indexFilePath(historyDir);
213
+ if (!existsSync(fp)) return null;
214
+ try {
215
+ const data = JSON.parse(readFileSync2(fp, "utf-8"));
216
+ if (data?.version === 1 && data.sessions && data.invertedIndex) {
217
+ return data;
218
+ }
219
+ return null;
220
+ } catch {
221
+ return null;
222
+ }
223
+ }
224
+ function saveIndex(historyDir, idx) {
225
+ idx.built = (/* @__PURE__ */ new Date()).toISOString();
226
+ const fp = indexFilePath(historyDir);
227
+ atomicWriteFileSync(fp, JSON.stringify(idx));
228
+ }
229
+ function rebuildIndex(historyDir) {
230
+ if (!existsSync(historyDir)) {
231
+ const empty = { version: 1, built: (/* @__PURE__ */ new Date()).toISOString(), sessions: {}, invertedIndex: {} };
232
+ return empty;
233
+ }
234
+ const files = readdirSync(historyDir).filter((f) => f.endsWith(".json"));
235
+ const sessions = {};
236
+ const invertedIndex = /* @__PURE__ */ new Map();
237
+ for (const file of files) {
238
+ const filePath = join(historyDir, file);
239
+ const meta = readSessionMeta(filePath);
240
+ if (!meta) continue;
241
+ let fileSize = 0;
242
+ try {
243
+ fileSize = statSync(filePath).size;
244
+ } catch {
245
+ }
246
+ let mtimeMs = 0;
247
+ try {
248
+ mtimeMs = statSync(filePath).mtimeMs;
249
+ } catch {
250
+ }
251
+ const entry = {
252
+ id: meta.id,
253
+ provider: meta.provider,
254
+ model: meta.model,
255
+ title: meta.title,
256
+ messageCount: meta.messageCount,
257
+ fileSize,
258
+ created: meta.created.toISOString(),
259
+ updated: meta.updated.toISOString(),
260
+ branchCount: meta.branchCount,
261
+ activeBranch: meta.activeBranch,
262
+ _mtimeMs: mtimeMs
263
+ };
264
+ sessions[meta.id] = entry;
265
+ addTokensToIndex(invertedIndex, meta.title ?? "", meta.id);
266
+ }
267
+ const serializedIndex = {};
268
+ for (const [token, ids] of invertedIndex) {
269
+ serializedIndex[token] = [...ids];
270
+ }
271
+ const idx = {
272
+ version: 1,
273
+ built: (/* @__PURE__ */ new Date()).toISOString(),
274
+ sessions,
275
+ invertedIndex: serializedIndex
276
+ };
277
+ saveIndex(historyDir, idx);
278
+ return idx;
279
+ }
280
+ function updateSessionInIndex(historyDir, meta, filePath) {
281
+ let idx = loadIndex(historyDir);
282
+ if (!idx) {
283
+ rebuildIndex(historyDir);
284
+ return;
285
+ }
286
+ let fileSize = 0;
287
+ try {
288
+ fileSize = statSync(filePath).size;
289
+ } catch {
290
+ }
291
+ let mtimeMs = 0;
292
+ try {
293
+ mtimeMs = statSync(filePath).mtimeMs;
294
+ } catch {
295
+ }
296
+ const id = meta.id;
297
+ for (const [token, ids] of Object.entries(idx.invertedIndex)) {
298
+ const filtered = ids.filter((sid) => sid !== id);
299
+ if (filtered.length === 0) {
300
+ delete idx.invertedIndex[token];
301
+ } else {
302
+ idx.invertedIndex[token] = filtered;
303
+ }
304
+ }
305
+ idx.sessions[id] = {
306
+ id,
307
+ provider: meta.provider,
308
+ model: meta.model,
309
+ title: meta.title,
310
+ messageCount: meta.messageCount,
311
+ fileSize,
312
+ created: meta.created.toISOString(),
313
+ updated: meta.updated.toISOString(),
314
+ _mtimeMs: mtimeMs
315
+ };
316
+ const tokens = tokenize(meta.title ?? "");
317
+ for (const token of tokens) {
318
+ const existing = idx.invertedIndex[token] ?? [];
319
+ if (!existing.includes(id)) {
320
+ existing.push(id);
321
+ idx.invertedIndex[token] = existing;
322
+ }
323
+ }
324
+ saveIndex(historyDir, idx);
325
+ }
326
+ function removeSessionFromIndex(historyDir, id) {
327
+ const idx = loadIndex(historyDir);
328
+ if (!idx) return;
329
+ delete idx.sessions[id];
330
+ for (const [token, ids] of Object.entries(idx.invertedIndex)) {
331
+ const filtered = ids.filter((sid) => sid !== id);
332
+ if (filtered.length === 0) {
333
+ delete idx.invertedIndex[token];
334
+ } else {
335
+ idx.invertedIndex[token] = filtered;
336
+ }
337
+ }
338
+ saveIndex(historyDir, idx);
339
+ }
340
+ function listFromIndex(historyDir, opts) {
341
+ let idx = loadIndex(historyDir);
342
+ if (!idx) {
343
+ idx = rebuildIndex(historyDir);
344
+ }
345
+ return Object.values(idx.sessions).map((entry) => ({
346
+ id: entry.id,
347
+ provider: entry.provider,
348
+ model: entry.model,
349
+ title: entry.title,
350
+ messageCount: entry.messageCount,
351
+ created: new Date(entry.created),
352
+ updated: new Date(entry.updated),
353
+ fileSize: opts?.includeFileSize ? entry.fileSize : void 0,
354
+ branchCount: entry.branchCount,
355
+ activeBranch: entry.activeBranch
356
+ })).sort((a, b) => b.updated.getTime() - a.updated.getTime());
357
+ }
358
+ function searchCandidates(historyDir, query) {
359
+ const idx = loadIndex(historyDir);
360
+ if (!idx) return null;
361
+ const queryTokens = tokenize(query.toLowerCase());
362
+ if (queryTokens.length === 0) return null;
363
+ const scoreMap = /* @__PURE__ */ new Map();
364
+ for (const token of queryTokens) {
365
+ const matchingIds = idx.invertedIndex[token];
366
+ if (!matchingIds) continue;
367
+ for (const sid of matchingIds) {
368
+ scoreMap.set(sid, (scoreMap.get(sid) ?? 0) + 1);
369
+ }
370
+ }
371
+ const candidates = [...scoreMap.entries()].filter(([, score]) => score > 0).sort((a, b) => {
372
+ const scoreDiff = b[1] - a[1];
373
+ if (scoreDiff !== 0) return scoreDiff;
374
+ const aMeta = idx.sessions[a[0]];
375
+ const bMeta = idx.sessions[b[0]];
376
+ return (bMeta?.updated ?? "").localeCompare(aMeta?.updated ?? "");
377
+ }).map(([sid]) => sid);
378
+ return candidates.length > 0 ? candidates : null;
379
+ }
380
+ function getIndexMtimeMap(historyDir) {
381
+ const idx = loadIndex(historyDir);
382
+ if (!idx) return null;
383
+ const map = {};
384
+ for (const entry of Object.values(idx.sessions)) {
385
+ map[entry.id] = entry._mtimeMs;
386
+ }
387
+ return map;
388
+ }
389
+ function addTokensToIndex(invertedIndex, text, sessionId) {
390
+ for (const token of tokenize(text)) {
391
+ const s = invertedIndex.get(token) ?? /* @__PURE__ */ new Set();
392
+ s.add(sessionId);
393
+ invertedIndex.set(token, s);
394
+ }
395
+ }
396
+ function tokenize(text) {
397
+ const tokens = /* @__PURE__ */ new Set();
398
+ const cjkOnly = text.replace(/[^\u4e00-\u9fff\u3400-\u4dbf]/g, "");
399
+ for (let i = 0; i < cjkOnly.length - 1; i++) {
400
+ tokens.add(cjkOnly.slice(i, i + 2));
401
+ }
402
+ const english = text.replace(/[\u4e00-\u9fff\u3400-\u4dbf]/g, " ").toLowerCase();
403
+ const words = english.split(/[^a-z0-9]+/).filter((w) => w.length >= 2);
404
+ for (const w of words) tokens.add(w);
405
+ return [...tokens];
406
+ }
407
+
408
+ export {
409
+ DEFAULT_PATTERNS,
410
+ redactString,
411
+ redactJson,
412
+ scanString,
413
+ safeDate,
414
+ readSessionMeta,
415
+ updateSessionInIndex,
416
+ removeSessionFromIndex,
417
+ listFromIndex,
418
+ searchCandidates,
419
+ getIndexMtimeMap
420
+ };
@@ -8,7 +8,7 @@ import {
8
8
  CONFIG_FILE_NAME,
9
9
  HISTORY_DIR_NAME,
10
10
  PLUGINS_DIR_NAME
11
- } from "./chunk-ACTO5C6K.js";
11
+ } from "./chunk-3KTSJ2EL.js";
12
12
  import {
13
13
  atomicWriteFileSync
14
14
  } from "./chunk-IW3Q7AE5.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  VERSION
4
- } from "./chunk-ACTO5C6K.js";
4
+ } from "./chunk-3KTSJ2EL.js";
5
5
 
6
6
  // src/cli/ci-format.ts
7
7
  var DEFAULT_CI_THRESHOLDS = {