jinzd-ai-cli 0.4.241 → 0.4.243
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 +2 -2
- package/dist/{batch-K66BLTLJ.js → batch-CUVZUPRK.js} +2 -2
- package/dist/{chat-index-7HXBWQFH.js → chat-index-ALUHFJKI.js} +3 -2
- package/dist/{chat-index-WYXYD7YP.js → chat-index-ML5FF5L6.js} +2 -1
- package/dist/{chunk-SMQHEJSH.js → chunk-66CE3E6X.js} +1 -1
- package/dist/chunk-B5TYJO7V.js +123 -0
- package/dist/{chunk-PGHTAKIA.js → chunk-DJGCG7SF.js} +1 -1
- package/dist/{chunk-2QQKS56X.js → chunk-DT77O33T.js} +1 -1
- package/dist/{chunk-2LLQOMMW.js → chunk-EMFCHE2B.js} +1 -1
- package/dist/chunk-GEWPLNKA.js +164 -0
- package/dist/{chunk-LXSUPLCK.js → chunk-H3ARWBYR.js} +2 -2
- package/dist/{chunk-3AIR7N5M.js → chunk-HNJX3N2V.js} +5 -5
- package/dist/{chunk-5MYPIQ3Y.js → chunk-IGPFYNZA.js} +4 -2
- package/dist/{chunk-GORPFFV4.js → chunk-KILKF2VN.js} +97 -254
- package/dist/{chunk-JMP3LJC2.js → chunk-KWQKQVPH.js} +4 -2
- package/dist/{chunk-NAQPP3GZ.js → chunk-L5IRDRWG.js} +1 -1
- package/dist/{chunk-UO3XWZFE.js → chunk-NV63EYFL.js} +3 -119
- package/dist/{chunk-KCEO2XJ4.js → chunk-PJ3ONBWZ.js} +0 -119
- package/dist/{chunk-ZPXMT2B6.js → chunk-PLEXBFCR.js} +4 -163
- package/dist/chunk-PNNZRJ67.js +523 -0
- package/dist/{chunk-CHFFEVVT.js → chunk-QNK7GUUB.js} +3 -3
- package/dist/chunk-TY4FSEZS.js +432 -0
- package/dist/{chunk-IV6GCDVR.js → chunk-X73Y4JZI.js} +7 -1
- package/dist/chunk-YVTASHS5.js +121 -0
- package/dist/{ci-T2ABDMMQ.js → ci-3O3JR6FX.js} +4 -4
- package/dist/{ci-format-S2PPU27O.js → ci-format-KGWF6KOU.js} +2 -2
- package/dist/{constants-RS7OUU7X.js → constants-NMFRZ5LW.js} +1 -1
- package/dist/{doctor-cli-TGAW6RAP.js → doctor-cli-4QUHTJZ4.js} +4 -4
- package/dist/electron-server.js +446 -579
- package/dist/{hub-GL5ZU6WS.js → hub-2GXFPWOR.js} +2 -2
- package/dist/index.js +273 -62
- package/dist/{persist-AMH5SQ4W.js → persist-WGIJ6RXY.js} +4 -3
- package/dist/persistent-memory-VFBRMKGG.js +65 -0
- package/dist/persistent-memory-ZCQKLIC5.js +63 -0
- package/dist/{pr-TJFKUZ4B.js → pr-GIDFO4KP.js} +5 -5
- package/dist/{run-tests-KEI7IXTB.js → run-tests-BMH6QJN2.js} +2 -2
- package/dist/{run-tests-EWMU34A4.js → run-tests-WCZBWQFS.js} +2 -1
- package/dist/{server-UVS2D4M6.js → server-A5NGGDMP.js} +130 -47
- package/dist/{server-E545UIX7.js → server-FEFIFJDA.js} +8 -6
- package/dist/{task-orchestrator-PWXV2EBN.js → task-orchestrator-J2H6OV6R.js} +8 -6
- package/dist/{usage-EDJ6QOWB.js → usage-7WJC234G.js} +2 -2
- package/package.json +1 -1
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
redactString
|
|
3
|
+
} from "./chunk-YVTASHS5.js";
|
|
1
4
|
import {
|
|
2
5
|
EMBEDDING_DIM,
|
|
3
6
|
embed,
|
|
@@ -13,121 +16,6 @@ import path from "path";
|
|
|
13
16
|
import os from "os";
|
|
14
17
|
import crypto from "crypto";
|
|
15
18
|
|
|
16
|
-
// src/security/redactor.ts
|
|
17
|
-
var DEFAULT_PATTERNS = [
|
|
18
|
-
// password: xxx / password = xxx / password="xxx"
|
|
19
|
-
// Covers YAML / JSON / shell-ish / env-file forms.
|
|
20
|
-
{ kind: "password", regex: /\b(password|passwd|pwd)\s*[:=]\s*["']?([^\s"',;{}]{4,200})["']?/gi },
|
|
21
|
-
// PGPASSWORD=xxx (explicit bash env-var form, separate rule because no quotes usually)
|
|
22
|
-
{ kind: "pgpassword-env", regex: /\b(PGPASSWORD)=([^\s"']{4,200})/g },
|
|
23
|
-
// JDBC/PG/MySQL/Mongo connection strings with inline credentials
|
|
24
|
-
// postgresql://user:pass@host/db → redact pass
|
|
25
|
-
{ kind: "db-uri-password", regex: /(\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp|mssql):\/\/[^:\s]+:)([^@\s]+)(@)/gi },
|
|
26
|
-
// Anthropic API keys
|
|
27
|
-
{ kind: "anthropic-key", regex: /(sk-ant-[a-zA-Z0-9_-]{90,})/g },
|
|
28
|
-
// L6 (v0.4.108): Zhipu / GLM API keys — `<24+ hex/base64-ish>.<32+>`
|
|
29
|
-
// Two segments separated by a dot, each safely identifiable by length
|
|
30
|
-
// and char class. Conservative on the lower bound so we don't eat
|
|
31
|
-
// version strings like `1.0.0` or filenames.
|
|
32
|
-
{ kind: "zhipu-key", regex: /\b([a-zA-Z0-9]{24,}\.[a-zA-Z0-9]{32,})\b/g },
|
|
33
|
-
// OpenAI / generic sk- keys — requires length ≥32 to avoid eating short identifiers
|
|
34
|
-
{ kind: "openai-key", regex: /(sk-(?:proj-)?[a-zA-Z0-9_-]{32,})/g },
|
|
35
|
-
// GitHub personal access tokens
|
|
36
|
-
{ kind: "github-pat", regex: /\b(ghp_[a-zA-Z0-9]{36})\b/g },
|
|
37
|
-
{ kind: "github-oauth", regex: /\b(gho_[a-zA-Z0-9]{36})\b/g },
|
|
38
|
-
{ kind: "github-install", regex: /\b(ghs_[a-zA-Z0-9]{36})\b/g },
|
|
39
|
-
// Slack tokens
|
|
40
|
-
{ kind: "slack-bot", regex: /\b(xoxb-\d+-\d+-[a-zA-Z0-9]+)\b/g },
|
|
41
|
-
{ kind: "slack-user", regex: /\b(xoxp-\d+-\d+-\d+-[a-zA-Z0-9]+)\b/g },
|
|
42
|
-
// AWS access key IDs (AKIA...) and secret access keys are context-dependent;
|
|
43
|
-
// we only catch the ID because secret key alone is indistinguishable from random base64.
|
|
44
|
-
{ kind: "aws-access-key-id", regex: /\b(AKIA[0-9A-Z]{16})\b/g },
|
|
45
|
-
// Google API keys
|
|
46
|
-
{ kind: "google-api-key", regex: /\b(AIza[0-9A-Za-z_-]{35})\b/g },
|
|
47
|
-
// Generic "api_key": "..." / "apiKey": "..." / api-key=xxx
|
|
48
|
-
{ kind: "api-key", regex: /\b(api[_-]?key)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{16,200})["']?/gi },
|
|
49
|
-
// Generic token: xxx (only when value looks token-shaped; avoids eating human prose)
|
|
50
|
-
{ kind: "token", regex: /\b(token|access[_-]?token|bearer[_-]?token)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{20,300})["']?/gi },
|
|
51
|
-
// Bearer <token> in Authorization headers
|
|
52
|
-
{ kind: "bearer", regex: /\b(Authorization:\s*Bearer\s+)([a-zA-Z0-9_\-.=]{20,500})/g },
|
|
53
|
-
// Private key PEM blocks — catch the header+footer together
|
|
54
|
-
// P2-PERF-02: PEM bodies use strict Base64 + =\n — narrowed char class avoids backtracking
|
|
55
|
-
{ 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 }
|
|
56
|
-
];
|
|
57
|
-
var MAX_CUSTOM = 32;
|
|
58
|
-
var MAX_PATTERN_LEN = 500;
|
|
59
|
-
var SUSPICIOUS_REDOS = /\([^)]*[+*][^)]*\)\s*[+*{]/;
|
|
60
|
-
var MAX_REDACT_INPUT = 512e3;
|
|
61
|
-
function render(placeholder, kind) {
|
|
62
|
-
return placeholder.replace("{kind}", kind);
|
|
63
|
-
}
|
|
64
|
-
function redactString(input, options) {
|
|
65
|
-
if (!options.enabled || !input) return { redacted: input, hits: [] };
|
|
66
|
-
if (input.length > MAX_REDACT_INPUT) return { redacted: input, hits: [] };
|
|
67
|
-
const placeholder = options.placeholder ?? "[REDACTED:{kind}]";
|
|
68
|
-
const customSrcs = (options.customRegexes ?? []).slice(0, MAX_CUSTOM);
|
|
69
|
-
const patterns = [
|
|
70
|
-
...options.patterns ?? DEFAULT_PATTERNS,
|
|
71
|
-
...customSrcs.flatMap((src, i) => {
|
|
72
|
-
if (typeof src !== "string" || src.length === 0 || src.length > MAX_PATTERN_LEN) return [];
|
|
73
|
-
try {
|
|
74
|
-
const flags = src.match(/^\/.*\/([gimsuy]*)$/)?.[1] ?? "";
|
|
75
|
-
const body = src.replace(/^\/(.*)\/[gimsuy]*$/, "$1");
|
|
76
|
-
if (SUSPICIOUS_REDOS.test(body)) return [];
|
|
77
|
-
const regex = new RegExp(body, flags.includes("g") ? flags : flags + "g");
|
|
78
|
-
return [{ kind: `custom-${i}`, regex }];
|
|
79
|
-
} catch {
|
|
80
|
-
return [];
|
|
81
|
-
}
|
|
82
|
-
})
|
|
83
|
-
];
|
|
84
|
-
let redacted = input;
|
|
85
|
-
const hits = [];
|
|
86
|
-
for (const { kind, regex } of patterns) {
|
|
87
|
-
const rx = new RegExp(regex.source, regex.flags);
|
|
88
|
-
const captureCount = new RegExp(rx.source + "|").exec("").length - 1;
|
|
89
|
-
redacted = redacted.replace(rx, (...args) => {
|
|
90
|
-
const match = args[0];
|
|
91
|
-
const g1 = captureCount >= 1 ? args[1] : void 0;
|
|
92
|
-
const g2 = captureCount >= 2 ? args[2] : void 0;
|
|
93
|
-
const offset = args[1 + captureCount];
|
|
94
|
-
if (captureCount >= 2 && typeof g2 === "string") {
|
|
95
|
-
hits.push({ kind, start: offset + (g1?.length ?? 0), length: g2.length, secret: g2 });
|
|
96
|
-
return `${g1}${render(placeholder, kind)}`;
|
|
97
|
-
}
|
|
98
|
-
hits.push({ kind, start: offset, length: match.length, secret: g1 ?? match });
|
|
99
|
-
return render(placeholder, kind);
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
return { redacted, hits };
|
|
103
|
-
}
|
|
104
|
-
function redactJson(value, options) {
|
|
105
|
-
if (!options.enabled) return { value, hits: [] };
|
|
106
|
-
const allHits = [];
|
|
107
|
-
function walk(v) {
|
|
108
|
-
if (typeof v === "string") {
|
|
109
|
-
const r = redactString(v, options);
|
|
110
|
-
allHits.push(...r.hits);
|
|
111
|
-
return r.redacted;
|
|
112
|
-
}
|
|
113
|
-
if (Array.isArray(v)) return v.map(walk);
|
|
114
|
-
if (v && typeof v === "object") {
|
|
115
|
-
const out = {};
|
|
116
|
-
for (const [k, vv] of Object.entries(v)) {
|
|
117
|
-
out[k] = walk(vv);
|
|
118
|
-
}
|
|
119
|
-
return out;
|
|
120
|
-
}
|
|
121
|
-
return v;
|
|
122
|
-
}
|
|
123
|
-
const redacted = walk(value);
|
|
124
|
-
return { value: redacted, hits: allHits };
|
|
125
|
-
}
|
|
126
|
-
function scanString(input, options) {
|
|
127
|
-
const { hits } = redactString(input, { ...options, enabled: true });
|
|
128
|
-
return hits;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
19
|
// src/session/session-index.ts
|
|
132
20
|
import { existsSync, readFileSync as readFileSync2, readdirSync, statSync } from "fs";
|
|
133
21
|
import { join } from "path";
|
|
@@ -749,10 +637,6 @@ function getChatIndexStatus() {
|
|
|
749
637
|
}
|
|
750
638
|
|
|
751
639
|
export {
|
|
752
|
-
DEFAULT_PATTERNS,
|
|
753
|
-
redactString,
|
|
754
|
-
redactJson,
|
|
755
|
-
scanString,
|
|
756
640
|
safeDate,
|
|
757
641
|
readSessionMeta,
|
|
758
642
|
updateSessionInIndex,
|
|
@@ -3,121 +3,6 @@ import {
|
|
|
3
3
|
atomicWriteFileSync
|
|
4
4
|
} from "./chunk-IW3Q7AE5.js";
|
|
5
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
6
|
// src/session/session-index.ts
|
|
122
7
|
import { existsSync, readFileSync as readFileSync2, readdirSync, statSync } from "fs";
|
|
123
8
|
import { join } from "path";
|
|
@@ -406,10 +291,6 @@ function tokenize(text) {
|
|
|
406
291
|
}
|
|
407
292
|
|
|
408
293
|
export {
|
|
409
|
-
DEFAULT_PATTERNS,
|
|
410
|
-
redactString,
|
|
411
|
-
redactJson,
|
|
412
|
-
scanString,
|
|
413
294
|
safeDate,
|
|
414
295
|
readSessionMeta,
|
|
415
296
|
updateSessionInIndex,
|
|
@@ -1,140 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TEST_TIMEOUT
|
|
3
|
+
} from "./chunk-GEWPLNKA.js";
|
|
4
|
+
|
|
1
5
|
// src/tools/builtin/run-tests.ts
|
|
2
6
|
import { execSync, spawnSync } from "child_process";
|
|
3
7
|
import { existsSync, readFileSync, readdirSync } from "fs";
|
|
4
8
|
import { join } from "path";
|
|
5
9
|
import { platform } from "os";
|
|
6
10
|
import chalk from "chalk";
|
|
7
|
-
|
|
8
|
-
// src/core/constants.ts
|
|
9
|
-
var VERSION = "0.4.241";
|
|
10
|
-
var APP_NAME = "ai-cli";
|
|
11
|
-
var CONFIG_DIR_NAME = ".aicli";
|
|
12
|
-
var CONFIG_FILE_NAME = "config.json";
|
|
13
|
-
var HISTORY_DIR_NAME = "history";
|
|
14
|
-
var PLUGINS_DIR_NAME = "plugins";
|
|
15
|
-
var SKILLS_DIR_NAME = "skills";
|
|
16
|
-
var CUSTOM_COMMANDS_DIR_NAME = "commands";
|
|
17
|
-
var CONTEXT_FILE_CANDIDATES = ["AICLI.override.md", "AGENTS.override.md", "AICLI.md", "CLAUDE.md", "AGENTS.md"];
|
|
18
|
-
var CONTEXT_FILE_MAX_BYTES = 32 * 1024;
|
|
19
|
-
var MEMORY_FILE_NAME = "memory.md";
|
|
20
|
-
var MEMORY_STORE_FILE_NAME = "memory.jsonl";
|
|
21
|
-
var MEMORY_MAX_CHARS = 1e4;
|
|
22
|
-
var DEV_STATE_FILE_NAME = "dev-state.md";
|
|
23
|
-
var DEFAULT_MAX_TOKENS = 8192;
|
|
24
|
-
var DEFAULT_MAX_TOOL_ROUNDS = 200;
|
|
25
|
-
var DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP = 5e5;
|
|
26
|
-
var MCP_TOOL_PREFIX = "mcp__";
|
|
27
|
-
var MCP_PROJECT_CONFIG_NAME = ".mcp.json";
|
|
28
|
-
var MCP_CONNECT_TIMEOUT = 3e4;
|
|
29
|
-
var MCP_CALL_TIMEOUT = 6e4;
|
|
30
|
-
var MCP_PROTOCOL_VERSION = "2024-11-05";
|
|
31
|
-
var PLAN_MODE_READONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
32
|
-
"read_file",
|
|
33
|
-
"list_dir",
|
|
34
|
-
"grep_files",
|
|
35
|
-
"glob_files",
|
|
36
|
-
"web_fetch",
|
|
37
|
-
"google_search",
|
|
38
|
-
"ask_user",
|
|
39
|
-
// 允许:可向用户澄清需求
|
|
40
|
-
"write_todos",
|
|
41
|
-
// 允许:可输出任务列表作为实施计划
|
|
42
|
-
"find_symbol",
|
|
43
|
-
// C1 symbol index (read-only)
|
|
44
|
-
"get_outline",
|
|
45
|
-
// C1 symbol index (read-only)
|
|
46
|
-
"find_references",
|
|
47
|
-
// C1 symbol index (read-only)
|
|
48
|
-
"search_code"
|
|
49
|
-
// C2 semantic search (read-only)
|
|
50
|
-
]);
|
|
51
|
-
var PLAN_MODE_SYSTEM_ADDON = `# \u{1F50D} Plan Mode \u2014 Read-Only Planning Mode
|
|
52
|
-
|
|
53
|
-
You are currently in read-only planning (Plan) mode.
|
|
54
|
-
|
|
55
|
-
**Allowed tools**: read_file \xB7 list_dir \xB7 grep_files \xB7 glob_files \xB7 web_fetch \xB7 google_search \xB7 ask_user \xB7 write_todos
|
|
56
|
-
**Disabled tools**: bash \xB7 write_file \xB7 edit_file \xB7 run_interactive \xB7 save_last_response \xB7 save_memory and all MCP tools
|
|
57
|
-
|
|
58
|
-
**Your task**:
|
|
59
|
-
1. Use read-only tools to thoroughly analyze the codebase, file structure, and existing implementation
|
|
60
|
-
2. Use ask_user to clarify any ambiguous requirements with the user
|
|
61
|
-
3. Develop a detailed implementation plan (you may use write_todos to present the task list), including:
|
|
62
|
-
- List of files to be modified or created
|
|
63
|
-
- Specific changes for each file
|
|
64
|
-
- Execution order and dependencies
|
|
65
|
-
- Potential risks and considerations
|
|
66
|
-
|
|
67
|
-
**CRITICAL RULES**:
|
|
68
|
-
- Do NOT attempt to call bash, write_file, edit_file, or any disabled tool \u2014 they will fail silently.
|
|
69
|
-
- Do NOT write shell commands, SQL queries, or code in your text response as a substitute for tool calls \u2014 the user's system will misinterpret this as a pseudo-tool-call error.
|
|
70
|
-
- If the user asks you to run commands, test connections, or modify files, respond with: "This requires execution tools. Please type \`/plan execute\` to switch to execute mode, then I can perform these operations."
|
|
71
|
-
- Do NOT call write_todos repeatedly with the same content \u2014 call it once, then give a text response.
|
|
72
|
-
- Focus your analysis on reading files and producing actionable plans.
|
|
73
|
-
|
|
74
|
-
Once planning is complete, clearly inform the user: type \`/plan execute\` to begin executing the plan, or \`/plan exit\` to discard it.`;
|
|
75
|
-
var SUBAGENT_DEFAULT_MAX_ROUNDS = 15;
|
|
76
|
-
var SUBAGENT_MAX_ROUNDS_LIMIT = 30;
|
|
77
|
-
var SUBAGENT_ALLOWED_TOOLS = /* @__PURE__ */ new Set([
|
|
78
|
-
"read_file",
|
|
79
|
-
"write_file",
|
|
80
|
-
"edit_file",
|
|
81
|
-
"list_dir",
|
|
82
|
-
"grep_files",
|
|
83
|
-
"glob_files",
|
|
84
|
-
"web_fetch",
|
|
85
|
-
"google_search",
|
|
86
|
-
"write_todos",
|
|
87
|
-
"find_symbol",
|
|
88
|
-
"get_outline",
|
|
89
|
-
"find_references",
|
|
90
|
-
"search_code"
|
|
91
|
-
]);
|
|
92
|
-
var TEST_TIMEOUT = 3e5;
|
|
93
|
-
var AGENTIC_BEHAVIOR_GUIDELINE = `# Important Behavioral Guidelines
|
|
94
|
-
|
|
95
|
-
**Respond appropriately to the user's intent \u2014 do NOT over-react**:
|
|
96
|
-
- For **greetings and casual chat** (e.g., "hello", "hi", "hey", "\u4F60\u597D", "what's up"): respond naturally with a friendly greeting. Do NOT use any tools. Do NOT explore directories, read files, or start any project work. Just chat.
|
|
97
|
-
- When the user asks you to "read", "understand", "review", "analyze", "examine", or "look at" files or a project, your task is only to **read and summarize**, then wait for the user's next instruction. Do not automatically start executing tasks described in the project.
|
|
98
|
-
- Only begin using write/execute tools when the user **explicitly requests** an action (e.g., "generate", "create", "modify", "run", "start", etc.).
|
|
99
|
-
- **Stop when the explicit task is done \u2014 do NOT autonomously test, verify, or run what you just created.** If the user asks "write/create/save file X", finish writing the file and STOP. Do not run it, do not test it, do not "verify it works" with bash/run_interactive. The user will run it themselves and tell you if anything is wrong. Only run/test when the user explicitly says "run", "test", "execute", "try it", "verify", "make sure it works", etc.
|
|
100
|
-
- **Do NOT retry the same failing command with variants.** If a command fails (exit code non-zero), report the failure to the user with a brief diagnosis and STOP. Do not loop through alternate shells, alternate quoting, alternate paths, or alternate Python invocations. The user can decide whether to retry.
|
|
101
|
-
- Project context files (AICLI.md, CLAUDE.md, AGENTS.md, and override variants) provide background information about the project. They are NOT instructions to start working. Only use them as reference when the user asks a project-related question or task.
|
|
102
|
-
- If you are unsure about the user's intent, use the ask_user tool to confirm with the user, rather than assuming and executing on your own.
|
|
103
|
-
- **Do NOT abuse ask_user for redundant confirmations**: When the user has already given a clear, explicit instruction (e.g., "write lesson 142", "generate file X", "create the report"), execute it immediately. Do NOT ask "are you sure?" or request details that can be found in project documents. Repeatedly asking the user to confirm wastes their time and is extremely frustrating. Only use ask_user when critical information is genuinely missing and cannot be inferred from context files.`;
|
|
104
|
-
function buildUserIdentityPrompt(profile) {
|
|
105
|
-
const lines = [];
|
|
106
|
-
const displayName = profile.nickname || profile.name;
|
|
107
|
-
if (displayName) {
|
|
108
|
-
lines.push(`The user's name is **${profile.name || displayName}**${profile.nickname && profile.name ? ` (prefers to be called **${profile.nickname}**)` : ""}.`);
|
|
109
|
-
}
|
|
110
|
-
if (profile.role) {
|
|
111
|
-
lines.push(`Role: ${profile.role}.`);
|
|
112
|
-
}
|
|
113
|
-
if (profile.bio) {
|
|
114
|
-
lines.push(`About: ${profile.bio}`);
|
|
115
|
-
}
|
|
116
|
-
if (profile.interests && profile.interests.length > 0) {
|
|
117
|
-
lines.push(`Interests & expertise: ${profile.interests.join(", ")}.`);
|
|
118
|
-
}
|
|
119
|
-
if (profile.locale) {
|
|
120
|
-
lines.push(`Preferred language: ${profile.locale}. Please respond in this language unless the user explicitly uses another language.`);
|
|
121
|
-
}
|
|
122
|
-
if (profile.extra) {
|
|
123
|
-
lines.push(`
|
|
124
|
-
${profile.extra}`);
|
|
125
|
-
}
|
|
126
|
-
if (lines.length === 0) return null;
|
|
127
|
-
return `# Who You're Talking To
|
|
128
|
-
|
|
129
|
-
${lines.join("\n")}
|
|
130
|
-
|
|
131
|
-
Address the user personally and adapt your communication style to their background. This identity persists across all conversations and all AI providers.`;
|
|
132
|
-
}
|
|
133
|
-
var AUTHOR = "Jin Zhengdong";
|
|
134
|
-
var AUTHOR_EMAIL = "zhengdong.jin@gmail.com";
|
|
135
|
-
var DESCRIPTION = "Cross-platform REPL-style AI conversation tool with multi-provider and agentic tool calling support";
|
|
136
|
-
|
|
137
|
-
// src/tools/builtin/run-tests.ts
|
|
138
11
|
var FILTER_WHITELIST = /^[\w.\-/:#\s*?()\[\]@+]{1,200}$/;
|
|
139
12
|
var IS_WINDOWS = platform() === "win32";
|
|
140
13
|
function detectNodeTestFramework(cwd, pkg) {
|
|
@@ -542,38 +415,6 @@ var runTestsTool = {
|
|
|
542
415
|
};
|
|
543
416
|
|
|
544
417
|
export {
|
|
545
|
-
VERSION,
|
|
546
|
-
APP_NAME,
|
|
547
|
-
CONFIG_DIR_NAME,
|
|
548
|
-
CONFIG_FILE_NAME,
|
|
549
|
-
HISTORY_DIR_NAME,
|
|
550
|
-
PLUGINS_DIR_NAME,
|
|
551
|
-
SKILLS_DIR_NAME,
|
|
552
|
-
CUSTOM_COMMANDS_DIR_NAME,
|
|
553
|
-
CONTEXT_FILE_CANDIDATES,
|
|
554
|
-
CONTEXT_FILE_MAX_BYTES,
|
|
555
|
-
MEMORY_FILE_NAME,
|
|
556
|
-
MEMORY_STORE_FILE_NAME,
|
|
557
|
-
MEMORY_MAX_CHARS,
|
|
558
|
-
DEV_STATE_FILE_NAME,
|
|
559
|
-
DEFAULT_MAX_TOKENS,
|
|
560
|
-
DEFAULT_MAX_TOOL_ROUNDS,
|
|
561
|
-
DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
|
|
562
|
-
MCP_TOOL_PREFIX,
|
|
563
|
-
MCP_PROJECT_CONFIG_NAME,
|
|
564
|
-
MCP_CONNECT_TIMEOUT,
|
|
565
|
-
MCP_CALL_TIMEOUT,
|
|
566
|
-
MCP_PROTOCOL_VERSION,
|
|
567
|
-
PLAN_MODE_READONLY_TOOLS,
|
|
568
|
-
PLAN_MODE_SYSTEM_ADDON,
|
|
569
|
-
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
570
|
-
SUBAGENT_MAX_ROUNDS_LIMIT,
|
|
571
|
-
SUBAGENT_ALLOWED_TOOLS,
|
|
572
|
-
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
573
|
-
buildUserIdentityPrompt,
|
|
574
|
-
AUTHOR,
|
|
575
|
-
AUTHOR_EMAIL,
|
|
576
|
-
DESCRIPTION,
|
|
577
418
|
executeTests,
|
|
578
419
|
runTestsTool
|
|
579
420
|
};
|