jinzd-ai-cli 0.4.86 → 0.4.88
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/dist/{batch-KN3ESR3U.js → batch-7XCYSPJU.js} +2 -2
- package/dist/{chunk-P6XKBTP4.js → chunk-L3MBIO36.js} +174 -10
- package/dist/{chunk-CHJFRDUB.js → chunk-P6EQZKKG.js} +1 -1
- package/dist/{chunk-YRWBFUYH.js → chunk-QT2KNL3V.js} +19 -1
- package/dist/{chunk-ZC4DN6C7.js → chunk-V3NMERIB.js} +1 -1
- package/dist/{chunk-CKCGAHEF.js → chunk-VGXNE37B.js} +1 -1
- package/dist/{chunk-M7KYMJT5.js → chunk-YDHIU24C.js} +2 -2
- package/dist/electron-server.js +186 -10
- package/dist/{hub-6GS4DYZO.js → hub-IR4INXSU.js} +1 -1
- package/dist/index.js +101 -10
- package/dist/{run-tests-BQMCZVI4.js → run-tests-FQHDUYOG.js} +2 -2
- package/dist/{run-tests-NWQ3YPDN.js → run-tests-JVWIGY7P.js} +1 -1
- package/dist/{server-73EENVYE.js → server-HTVVWKFN.js} +3 -3
- package/dist/{server-GD5OGIOF.js → server-UWKRV5DK.js} +6 -6
- package/dist/{task-orchestrator-YW33QQKO.js → task-orchestrator-6MI6LD7T.js} +3 -3
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ConfigManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QT2KNL3V.js";
|
|
5
5
|
import "./chunk-2ZD3YTVM.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-VGXNE37B.js";
|
|
7
7
|
|
|
8
8
|
// src/cli/batch.ts
|
|
9
9
|
import Anthropic from "@anthropic-ai/sdk";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
schemaToJsonSchema,
|
|
4
4
|
truncateForPersist
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-YDHIU24C.js";
|
|
6
6
|
import {
|
|
7
7
|
AuthError,
|
|
8
8
|
ProviderError,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
MCP_PROTOCOL_VERSION,
|
|
19
19
|
MCP_TOOL_PREFIX,
|
|
20
20
|
VERSION
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-VGXNE37B.js";
|
|
22
22
|
|
|
23
23
|
// src/providers/claude.ts
|
|
24
24
|
import Anthropic from "@anthropic-ai/sdk";
|
|
@@ -1291,17 +1291,41 @@ var DeepSeekProvider = class extends OpenAICompatibleProvider {
|
|
|
1291
1291
|
// src/providers/zhipu.ts
|
|
1292
1292
|
var ZhipuProvider = class extends OpenAICompatibleProvider {
|
|
1293
1293
|
defaultBaseUrl = "https://open.bigmodel.cn/api/paas/v4";
|
|
1294
|
-
// GLM-5 等深度思考模型生成长内容需要较长时间,默认 5 分钟
|
|
1294
|
+
// GLM-5 / GLM-5.1 等深度思考模型生成长内容需要较长时间,默认 5 分钟
|
|
1295
1295
|
defaultTimeout = 3e5;
|
|
1296
1296
|
info = {
|
|
1297
1297
|
id: "zhipu",
|
|
1298
1298
|
displayName: "Zhipu (GLM)",
|
|
1299
|
-
|
|
1299
|
+
// 默认选 GLM-4.6:中文写作口碑最稳 + 200K 上下文 + 价格只有 5.1 的 ~1/2。
|
|
1300
|
+
// 需要 Agent 长跑 / 代码工程时再手动 /model glm-5.1。
|
|
1301
|
+
defaultModel: "glm-4.6",
|
|
1300
1302
|
apiKeyEnvVar: "AICLI_API_KEY_ZHIPU",
|
|
1301
1303
|
requiresApiKey: true,
|
|
1302
1304
|
baseUrl: this.defaultBaseUrl,
|
|
1303
1305
|
models: [
|
|
1304
|
-
// GLM-5
|
|
1306
|
+
// ── GLM-5.1 系列(2026-04 旗舰,主打长程 Agent + 代码工程) ──
|
|
1307
|
+
{
|
|
1308
|
+
id: "glm-5.1",
|
|
1309
|
+
displayName: "GLM-5.1 (2026 Flagship, 200K, Agent+Code)",
|
|
1310
|
+
contextWindow: 204800,
|
|
1311
|
+
supportsStreaming: true,
|
|
1312
|
+
supportsThinking: true
|
|
1313
|
+
},
|
|
1314
|
+
{
|
|
1315
|
+
id: "glm-5.1-reasoning",
|
|
1316
|
+
displayName: "GLM-5.1 Reasoning (Deep Thinking)",
|
|
1317
|
+
contextWindow: 204800,
|
|
1318
|
+
supportsStreaming: true,
|
|
1319
|
+
supportsThinking: true
|
|
1320
|
+
},
|
|
1321
|
+
{
|
|
1322
|
+
id: "glm-5.1-air",
|
|
1323
|
+
displayName: "GLM-5.1 Air (Lightweight 5.1)",
|
|
1324
|
+
contextWindow: 204800,
|
|
1325
|
+
supportsStreaming: true,
|
|
1326
|
+
supportsThinking: true
|
|
1327
|
+
},
|
|
1328
|
+
// ── GLM-5 系列(2026-02) ──
|
|
1305
1329
|
{
|
|
1306
1330
|
id: "glm-5",
|
|
1307
1331
|
displayName: "GLM-5 (Flagship, Deep Thinking)",
|
|
@@ -1309,7 +1333,13 @@ var ZhipuProvider = class extends OpenAICompatibleProvider {
|
|
|
1309
1333
|
supportsStreaming: true,
|
|
1310
1334
|
supportsThinking: true
|
|
1311
1335
|
},
|
|
1312
|
-
// GLM-4.6
|
|
1336
|
+
// ── GLM-4.6 系列(2025-09,中文写作口碑最佳) ──
|
|
1337
|
+
{
|
|
1338
|
+
id: "glm-4.6",
|
|
1339
|
+
displayName: "GLM-4.6 (200K, \u4E2D\u6587\u5199\u4F5C\u63A8\u8350)",
|
|
1340
|
+
contextWindow: 204800,
|
|
1341
|
+
supportsStreaming: true
|
|
1342
|
+
},
|
|
1313
1343
|
{
|
|
1314
1344
|
id: "glm-4.6v",
|
|
1315
1345
|
displayName: "GLM-4.6V (Vision + Thinking)",
|
|
@@ -1317,7 +1347,7 @@ var ZhipuProvider = class extends OpenAICompatibleProvider {
|
|
|
1317
1347
|
supportsStreaming: true,
|
|
1318
1348
|
supportsThinking: true
|
|
1319
1349
|
},
|
|
1320
|
-
// GLM-Z1
|
|
1350
|
+
// ── GLM-Z1 推理系列 ──
|
|
1321
1351
|
{
|
|
1322
1352
|
id: "glm-z1",
|
|
1323
1353
|
displayName: "GLM-Z1 (Reasoning Flagship)",
|
|
@@ -1339,7 +1369,7 @@ var ZhipuProvider = class extends OpenAICompatibleProvider {
|
|
|
1339
1369
|
supportsStreaming: true,
|
|
1340
1370
|
supportsThinking: true
|
|
1341
1371
|
},
|
|
1342
|
-
// GLM-4
|
|
1372
|
+
// ── GLM-4 系列(稳定,价格低) ──
|
|
1343
1373
|
{
|
|
1344
1374
|
id: "glm-4-plus",
|
|
1345
1375
|
displayName: "GLM-4 Plus",
|
|
@@ -2625,6 +2655,108 @@ var Session = class _Session {
|
|
|
2625
2655
|
}
|
|
2626
2656
|
};
|
|
2627
2657
|
|
|
2658
|
+
// src/security/redactor.ts
|
|
2659
|
+
var DEFAULT_PATTERNS = [
|
|
2660
|
+
// password: xxx / password = xxx / password="xxx"
|
|
2661
|
+
// Covers YAML / JSON / shell-ish / env-file forms.
|
|
2662
|
+
{ kind: "password", regex: /\b(password|passwd|pwd)\s*[:=]\s*["']?([^\s"',;{}]{4,200})["']?/gi },
|
|
2663
|
+
// PGPASSWORD=xxx (explicit bash env-var form, separate rule because no quotes usually)
|
|
2664
|
+
{ kind: "pgpassword-env", regex: /\b(PGPASSWORD)=([^\s"']{4,200})/g },
|
|
2665
|
+
// JDBC/PG/MySQL/Mongo connection strings with inline credentials
|
|
2666
|
+
// postgresql://user:pass@host/db → redact pass
|
|
2667
|
+
{ kind: "db-uri-password", regex: /(\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp|mssql):\/\/[^:\s]+:)([^@\s]+)(@)/gi },
|
|
2668
|
+
// Anthropic API keys
|
|
2669
|
+
{ kind: "anthropic-key", regex: /(sk-ant-[a-zA-Z0-9_-]{90,})/g },
|
|
2670
|
+
// OpenAI / generic sk- keys — requires length ≥32 to avoid eating short identifiers
|
|
2671
|
+
{ kind: "openai-key", regex: /(sk-(?:proj-)?[a-zA-Z0-9_-]{32,})/g },
|
|
2672
|
+
// GitHub personal access tokens
|
|
2673
|
+
{ kind: "github-pat", regex: /\b(ghp_[a-zA-Z0-9]{36})\b/g },
|
|
2674
|
+
{ kind: "github-oauth", regex: /\b(gho_[a-zA-Z0-9]{36})\b/g },
|
|
2675
|
+
{ kind: "github-install", regex: /\b(ghs_[a-zA-Z0-9]{36})\b/g },
|
|
2676
|
+
// Slack tokens
|
|
2677
|
+
{ kind: "slack-bot", regex: /\b(xoxb-\d+-\d+-[a-zA-Z0-9]+)\b/g },
|
|
2678
|
+
{ kind: "slack-user", regex: /\b(xoxp-\d+-\d+-\d+-[a-zA-Z0-9]+)\b/g },
|
|
2679
|
+
// AWS access key IDs (AKIA...) and secret access keys are context-dependent;
|
|
2680
|
+
// we only catch the ID because secret key alone is indistinguishable from random base64.
|
|
2681
|
+
{ kind: "aws-access-key-id", regex: /\b(AKIA[0-9A-Z]{16})\b/g },
|
|
2682
|
+
// Google API keys
|
|
2683
|
+
{ kind: "google-api-key", regex: /\b(AIza[0-9A-Za-z_-]{35})\b/g },
|
|
2684
|
+
// Generic "api_key": "..." / "apiKey": "..." / api-key=xxx
|
|
2685
|
+
{ kind: "api-key", regex: /\b(api[_-]?key)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{16,200})["']?/gi },
|
|
2686
|
+
// Generic token: xxx (only when value looks token-shaped; avoids eating human prose)
|
|
2687
|
+
{ kind: "token", regex: /\b(token|access[_-]?token|bearer[_-]?token)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{20,300})["']?/gi },
|
|
2688
|
+
// Bearer <token> in Authorization headers
|
|
2689
|
+
{ kind: "bearer", regex: /\b(Authorization:\s*Bearer\s+)([a-zA-Z0-9_\-.=]{20,500})/g },
|
|
2690
|
+
// Private key PEM blocks — catch the header+footer together
|
|
2691
|
+
{ kind: "private-key", regex: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g }
|
|
2692
|
+
];
|
|
2693
|
+
function render(placeholder, kind) {
|
|
2694
|
+
return placeholder.replace("{kind}", kind);
|
|
2695
|
+
}
|
|
2696
|
+
function redactString(input, options) {
|
|
2697
|
+
if (!options.enabled || !input) return { redacted: input, hits: [] };
|
|
2698
|
+
const placeholder = options.placeholder ?? "[REDACTED:{kind}]";
|
|
2699
|
+
const patterns = [
|
|
2700
|
+
...options.patterns ?? DEFAULT_PATTERNS,
|
|
2701
|
+
...(options.customRegexes ?? []).flatMap((src, i) => {
|
|
2702
|
+
try {
|
|
2703
|
+
const flags = src.match(/^\/.*\/([gimsuy]*)$/)?.[1] ?? "";
|
|
2704
|
+
const body = src.replace(/^\/(.*)\/[gimsuy]*$/, "$1");
|
|
2705
|
+
const regex = new RegExp(body, flags.includes("g") ? flags : flags + "g");
|
|
2706
|
+
return [{ kind: `custom-${i}`, regex }];
|
|
2707
|
+
} catch {
|
|
2708
|
+
return [];
|
|
2709
|
+
}
|
|
2710
|
+
})
|
|
2711
|
+
];
|
|
2712
|
+
let redacted = input;
|
|
2713
|
+
const hits = [];
|
|
2714
|
+
for (const { kind, regex } of patterns) {
|
|
2715
|
+
const rx = new RegExp(regex.source, regex.flags);
|
|
2716
|
+
redacted = redacted.replace(rx, (...args) => {
|
|
2717
|
+
const match = args[0];
|
|
2718
|
+
const probe = new RegExp(rx.source).exec(match);
|
|
2719
|
+
const captureCount = probe ? probe.length - 1 : 0;
|
|
2720
|
+
const g1 = captureCount >= 1 ? args[1] : void 0;
|
|
2721
|
+
const g2 = captureCount >= 2 ? args[2] : void 0;
|
|
2722
|
+
const offset = args[1 + captureCount];
|
|
2723
|
+
if (captureCount >= 2 && typeof g2 === "string") {
|
|
2724
|
+
hits.push({ kind, start: offset + (g1?.length ?? 0), length: g2.length, secret: g2 });
|
|
2725
|
+
return `${g1}${render(placeholder, kind)}`;
|
|
2726
|
+
}
|
|
2727
|
+
hits.push({ kind, start: offset, length: match.length, secret: g1 ?? match });
|
|
2728
|
+
return render(placeholder, kind);
|
|
2729
|
+
});
|
|
2730
|
+
}
|
|
2731
|
+
return { redacted, hits };
|
|
2732
|
+
}
|
|
2733
|
+
function redactJson(value, options) {
|
|
2734
|
+
if (!options.enabled) return { value, hits: [] };
|
|
2735
|
+
const allHits = [];
|
|
2736
|
+
function walk(v) {
|
|
2737
|
+
if (typeof v === "string") {
|
|
2738
|
+
const r = redactString(v, options);
|
|
2739
|
+
allHits.push(...r.hits);
|
|
2740
|
+
return r.redacted;
|
|
2741
|
+
}
|
|
2742
|
+
if (Array.isArray(v)) return v.map(walk);
|
|
2743
|
+
if (v && typeof v === "object") {
|
|
2744
|
+
const out = {};
|
|
2745
|
+
for (const [k, vv] of Object.entries(v)) {
|
|
2746
|
+
out[k] = walk(vv);
|
|
2747
|
+
}
|
|
2748
|
+
return out;
|
|
2749
|
+
}
|
|
2750
|
+
return v;
|
|
2751
|
+
}
|
|
2752
|
+
const redacted = walk(value);
|
|
2753
|
+
return { value: redacted, hits: allHits };
|
|
2754
|
+
}
|
|
2755
|
+
function scanString(input, options) {
|
|
2756
|
+
const { hits } = redactString(input, { ...options, enabled: true });
|
|
2757
|
+
return hits;
|
|
2758
|
+
}
|
|
2759
|
+
|
|
2628
2760
|
// src/session/session-manager.ts
|
|
2629
2761
|
function safeDate(value) {
|
|
2630
2762
|
const d = new Date(value);
|
|
@@ -2638,9 +2770,27 @@ function extractJsonField(header, field) {
|
|
|
2638
2770
|
var SessionManager = class {
|
|
2639
2771
|
_current = null;
|
|
2640
2772
|
historyDir;
|
|
2773
|
+
config;
|
|
2774
|
+
/** Last save's redaction hit count — exposed for /security status reporting */
|
|
2775
|
+
lastRedactionHits = 0;
|
|
2641
2776
|
constructor(config) {
|
|
2777
|
+
this.config = config;
|
|
2642
2778
|
this.historyDir = config.getHistoryDir();
|
|
2643
2779
|
}
|
|
2780
|
+
/**
|
|
2781
|
+
* Build redaction options from config. Returns `{ enabled: false }` when
|
|
2782
|
+
* `security.redactOnSave` is off or `security.mode` is 'off'.
|
|
2783
|
+
*/
|
|
2784
|
+
redactOptionsForSave() {
|
|
2785
|
+
const security = this.config.get("security");
|
|
2786
|
+
if (!security || !security.redactOnSave || security.mode === "off") {
|
|
2787
|
+
return { enabled: false };
|
|
2788
|
+
}
|
|
2789
|
+
return {
|
|
2790
|
+
enabled: true,
|
|
2791
|
+
customRegexes: security.customPatterns ?? []
|
|
2792
|
+
};
|
|
2793
|
+
}
|
|
2644
2794
|
get current() {
|
|
2645
2795
|
return this._current;
|
|
2646
2796
|
}
|
|
@@ -2666,8 +2816,12 @@ var SessionManager = class {
|
|
|
2666
2816
|
if (!this._current) return;
|
|
2667
2817
|
mkdirSync(this.historyDir, { recursive: true });
|
|
2668
2818
|
const filePath = join(this.historyDir, `${this._current.id}.json`);
|
|
2819
|
+
const raw = this._current.toJSON();
|
|
2820
|
+
const opts = this.redactOptionsForSave();
|
|
2821
|
+
const { value: payload, hits } = redactJson(raw, opts);
|
|
2822
|
+
this.lastRedactionHits = hits.length;
|
|
2669
2823
|
const tmpPath = filePath + ".tmp";
|
|
2670
|
-
writeFileSync(tmpPath, JSON.stringify(
|
|
2824
|
+
writeFileSync(tmpPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
2671
2825
|
renameSync(tmpPath, filePath);
|
|
2672
2826
|
}
|
|
2673
2827
|
loadSession(id) {
|
|
@@ -3653,7 +3807,15 @@ var PRICING_TABLE = {
|
|
|
3653
3807
|
"glm-4": { input: 0.14, output: 0.14 },
|
|
3654
3808
|
"glm-4-flash": { input: 0, output: 0 },
|
|
3655
3809
|
"glm-4.5": { input: 0.29, output: 1.14 },
|
|
3656
|
-
"glm-4.6": { input: 0.6, output: 2.2 }
|
|
3810
|
+
"glm-4.6": { input: 0.6, output: 2.2 },
|
|
3811
|
+
"glm-4.6v": { input: 0.6, output: 2.2 },
|
|
3812
|
+
"glm-5": { input: 0.85, output: 2.85 },
|
|
3813
|
+
"glm-5.1": { input: 0.95, output: 3.15 },
|
|
3814
|
+
"glm-5.1-reasoning": { input: 1.4, output: 4.4 },
|
|
3815
|
+
"glm-5.1-air": { input: 0.4, output: 1.2 },
|
|
3816
|
+
"glm-z1": { input: 0.5, output: 1.5 },
|
|
3817
|
+
"glm-z1-air": { input: 0.2, output: 0.6 },
|
|
3818
|
+
"glm-z1-flash": { input: 0, output: 0 }
|
|
3657
3819
|
// ── OpenRouter (pass-through — actual cost depends on underlying model) ──
|
|
3658
3820
|
// Left empty; callers should resolve via underlying model ID.
|
|
3659
3821
|
// ── Ollama (local, zero cost) ─────────────────────────────────
|
|
@@ -3937,6 +4099,8 @@ export {
|
|
|
3937
4099
|
buildPhantomCorrectionMessage,
|
|
3938
4100
|
ProviderRegistry,
|
|
3939
4101
|
getContentText,
|
|
4102
|
+
DEFAULT_PATTERNS,
|
|
4103
|
+
scanString,
|
|
3940
4104
|
SessionManager,
|
|
3941
4105
|
getGitRoot,
|
|
3942
4106
|
getGitContext,
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
CONFIG_FILE_NAME,
|
|
9
9
|
HISTORY_DIR_NAME,
|
|
10
10
|
PLUGINS_DIR_NAME
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-VGXNE37B.js";
|
|
12
12
|
|
|
13
13
|
// src/config/config-manager.ts
|
|
14
14
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
@@ -179,6 +179,24 @@ var ConfigSchema = z.object({
|
|
|
179
179
|
// 必须确认插件来源可信后,再设为 true 启用。
|
|
180
180
|
// 可通过 /config 命令或直接编辑 ~/.aicli/config.json 开启。
|
|
181
181
|
allowPlugins: z.boolean().default(false),
|
|
182
|
+
// 敏感信息脱敏(v0.4.88+,2026-04 凭据泄漏事件后引入)
|
|
183
|
+
// 会话保存到磁盘 / 发送给 Provider 前,自动将 API key、密码、PEM 私钥等
|
|
184
|
+
// 按正则替换为 [REDACTED:kind] 占位符。模式定义在 src/security/redactor.ts。
|
|
185
|
+
//
|
|
186
|
+
// redactOnSave 默认 true:保存到 ~/.aicli/history/*.json 时脱敏(推荐开启)
|
|
187
|
+
// redactOnSend 默认 false:发送到 Provider 时脱敏(激进,可能影响工具结果)
|
|
188
|
+
// mode:
|
|
189
|
+
// 'default' — 使用内置 13 条模式(推荐)
|
|
190
|
+
// 'strict' — 同 default,但阈值更低(更激进,可能误报)
|
|
191
|
+
// 'off' — 禁用所有模式(等同 redactOnSave=false)
|
|
192
|
+
// customPatterns — 用户补充正则字符串(支持 /pattern/flags 形式),
|
|
193
|
+
// 无效正则会静默跳过,不会中断保存。
|
|
194
|
+
security: z.object({
|
|
195
|
+
redactOnSave: z.boolean().default(true),
|
|
196
|
+
redactOnSend: z.boolean().default(false),
|
|
197
|
+
mode: z.enum(["default", "strict", "off"]).default("default"),
|
|
198
|
+
customPatterns: z.array(z.string()).default([])
|
|
199
|
+
}).default({}),
|
|
182
200
|
// 智能模型路由(v0.4.68+)
|
|
183
201
|
// 按用户每轮输入的内容/标签/长度动态选择模型,在同一 provider 内切换,
|
|
184
202
|
// 例:短问题走 haiku(省钱),planning 走 opus(质量)。
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
} from "./chunk-6VRJGH25.js";
|
|
20
20
|
import {
|
|
21
21
|
runTestsTool
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-V3NMERIB.js";
|
|
23
23
|
import {
|
|
24
24
|
CONFIG_DIR_NAME,
|
|
25
25
|
DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
SUBAGENT_ALLOWED_TOOLS,
|
|
28
28
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
29
29
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-VGXNE37B.js";
|
|
31
31
|
|
|
32
32
|
// src/tools/types.ts
|
|
33
33
|
function isFileWriteTool(name) {
|
package/dist/electron-server.js
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
VERSION,
|
|
37
37
|
buildUserIdentityPrompt,
|
|
38
38
|
runTestsTool
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-P6EQZKKG.js";
|
|
40
40
|
import {
|
|
41
41
|
hasSemanticIndex,
|
|
42
42
|
semanticSearch
|
|
@@ -223,6 +223,24 @@ var ConfigSchema = z.object({
|
|
|
223
223
|
// 必须确认插件来源可信后,再设为 true 启用。
|
|
224
224
|
// 可通过 /config 命令或直接编辑 ~/.aicli/config.json 开启。
|
|
225
225
|
allowPlugins: z.boolean().default(false),
|
|
226
|
+
// 敏感信息脱敏(v0.4.88+,2026-04 凭据泄漏事件后引入)
|
|
227
|
+
// 会话保存到磁盘 / 发送给 Provider 前,自动将 API key、密码、PEM 私钥等
|
|
228
|
+
// 按正则替换为 [REDACTED:kind] 占位符。模式定义在 src/security/redactor.ts。
|
|
229
|
+
//
|
|
230
|
+
// redactOnSave 默认 true:保存到 ~/.aicli/history/*.json 时脱敏(推荐开启)
|
|
231
|
+
// redactOnSend 默认 false:发送到 Provider 时脱敏(激进,可能影响工具结果)
|
|
232
|
+
// mode:
|
|
233
|
+
// 'default' — 使用内置 13 条模式(推荐)
|
|
234
|
+
// 'strict' — 同 default,但阈值更低(更激进,可能误报)
|
|
235
|
+
// 'off' — 禁用所有模式(等同 redactOnSave=false)
|
|
236
|
+
// customPatterns — 用户补充正则字符串(支持 /pattern/flags 形式),
|
|
237
|
+
// 无效正则会静默跳过,不会中断保存。
|
|
238
|
+
security: z.object({
|
|
239
|
+
redactOnSave: z.boolean().default(true),
|
|
240
|
+
redactOnSend: z.boolean().default(false),
|
|
241
|
+
mode: z.enum(["default", "strict", "off"]).default("default"),
|
|
242
|
+
customPatterns: z.array(z.string()).default([])
|
|
243
|
+
}).default({}),
|
|
226
244
|
// 智能模型路由(v0.4.68+)
|
|
227
245
|
// 按用户每轮输入的内容/标签/长度动态选择模型,在同一 provider 内切换,
|
|
228
246
|
// 例:短问题走 haiku(省钱),planning 走 opus(质量)。
|
|
@@ -1779,17 +1797,41 @@ var DeepSeekProvider = class extends OpenAICompatibleProvider {
|
|
|
1779
1797
|
// src/providers/zhipu.ts
|
|
1780
1798
|
var ZhipuProvider = class extends OpenAICompatibleProvider {
|
|
1781
1799
|
defaultBaseUrl = "https://open.bigmodel.cn/api/paas/v4";
|
|
1782
|
-
// GLM-5 等深度思考模型生成长内容需要较长时间,默认 5 分钟
|
|
1800
|
+
// GLM-5 / GLM-5.1 等深度思考模型生成长内容需要较长时间,默认 5 分钟
|
|
1783
1801
|
defaultTimeout = 3e5;
|
|
1784
1802
|
info = {
|
|
1785
1803
|
id: "zhipu",
|
|
1786
1804
|
displayName: "Zhipu (GLM)",
|
|
1787
|
-
|
|
1805
|
+
// 默认选 GLM-4.6:中文写作口碑最稳 + 200K 上下文 + 价格只有 5.1 的 ~1/2。
|
|
1806
|
+
// 需要 Agent 长跑 / 代码工程时再手动 /model glm-5.1。
|
|
1807
|
+
defaultModel: "glm-4.6",
|
|
1788
1808
|
apiKeyEnvVar: "AICLI_API_KEY_ZHIPU",
|
|
1789
1809
|
requiresApiKey: true,
|
|
1790
1810
|
baseUrl: this.defaultBaseUrl,
|
|
1791
1811
|
models: [
|
|
1792
|
-
// GLM-5
|
|
1812
|
+
// ── GLM-5.1 系列(2026-04 旗舰,主打长程 Agent + 代码工程) ──
|
|
1813
|
+
{
|
|
1814
|
+
id: "glm-5.1",
|
|
1815
|
+
displayName: "GLM-5.1 (2026 Flagship, 200K, Agent+Code)",
|
|
1816
|
+
contextWindow: 204800,
|
|
1817
|
+
supportsStreaming: true,
|
|
1818
|
+
supportsThinking: true
|
|
1819
|
+
},
|
|
1820
|
+
{
|
|
1821
|
+
id: "glm-5.1-reasoning",
|
|
1822
|
+
displayName: "GLM-5.1 Reasoning (Deep Thinking)",
|
|
1823
|
+
contextWindow: 204800,
|
|
1824
|
+
supportsStreaming: true,
|
|
1825
|
+
supportsThinking: true
|
|
1826
|
+
},
|
|
1827
|
+
{
|
|
1828
|
+
id: "glm-5.1-air",
|
|
1829
|
+
displayName: "GLM-5.1 Air (Lightweight 5.1)",
|
|
1830
|
+
contextWindow: 204800,
|
|
1831
|
+
supportsStreaming: true,
|
|
1832
|
+
supportsThinking: true
|
|
1833
|
+
},
|
|
1834
|
+
// ── GLM-5 系列(2026-02) ──
|
|
1793
1835
|
{
|
|
1794
1836
|
id: "glm-5",
|
|
1795
1837
|
displayName: "GLM-5 (Flagship, Deep Thinking)",
|
|
@@ -1797,7 +1839,13 @@ var ZhipuProvider = class extends OpenAICompatibleProvider {
|
|
|
1797
1839
|
supportsStreaming: true,
|
|
1798
1840
|
supportsThinking: true
|
|
1799
1841
|
},
|
|
1800
|
-
// GLM-4.6
|
|
1842
|
+
// ── GLM-4.6 系列(2025-09,中文写作口碑最佳) ──
|
|
1843
|
+
{
|
|
1844
|
+
id: "glm-4.6",
|
|
1845
|
+
displayName: "GLM-4.6 (200K, \u4E2D\u6587\u5199\u4F5C\u63A8\u8350)",
|
|
1846
|
+
contextWindow: 204800,
|
|
1847
|
+
supportsStreaming: true
|
|
1848
|
+
},
|
|
1801
1849
|
{
|
|
1802
1850
|
id: "glm-4.6v",
|
|
1803
1851
|
displayName: "GLM-4.6V (Vision + Thinking)",
|
|
@@ -1805,7 +1853,7 @@ var ZhipuProvider = class extends OpenAICompatibleProvider {
|
|
|
1805
1853
|
supportsStreaming: true,
|
|
1806
1854
|
supportsThinking: true
|
|
1807
1855
|
},
|
|
1808
|
-
// GLM-Z1
|
|
1856
|
+
// ── GLM-Z1 推理系列 ──
|
|
1809
1857
|
{
|
|
1810
1858
|
id: "glm-z1",
|
|
1811
1859
|
displayName: "GLM-Z1 (Reasoning Flagship)",
|
|
@@ -1827,7 +1875,7 @@ var ZhipuProvider = class extends OpenAICompatibleProvider {
|
|
|
1827
1875
|
supportsStreaming: true,
|
|
1828
1876
|
supportsThinking: true
|
|
1829
1877
|
},
|
|
1830
|
-
// GLM-4
|
|
1878
|
+
// ── GLM-4 系列(稳定,价格低) ──
|
|
1831
1879
|
{
|
|
1832
1880
|
id: "glm-4-plus",
|
|
1833
1881
|
displayName: "GLM-4 Plus",
|
|
@@ -3006,6 +3054,104 @@ var Session = class _Session {
|
|
|
3006
3054
|
}
|
|
3007
3055
|
};
|
|
3008
3056
|
|
|
3057
|
+
// src/security/redactor.ts
|
|
3058
|
+
var DEFAULT_PATTERNS = [
|
|
3059
|
+
// password: xxx / password = xxx / password="xxx"
|
|
3060
|
+
// Covers YAML / JSON / shell-ish / env-file forms.
|
|
3061
|
+
{ kind: "password", regex: /\b(password|passwd|pwd)\s*[:=]\s*["']?([^\s"',;{}]{4,200})["']?/gi },
|
|
3062
|
+
// PGPASSWORD=xxx (explicit bash env-var form, separate rule because no quotes usually)
|
|
3063
|
+
{ kind: "pgpassword-env", regex: /\b(PGPASSWORD)=([^\s"']{4,200})/g },
|
|
3064
|
+
// JDBC/PG/MySQL/Mongo connection strings with inline credentials
|
|
3065
|
+
// postgresql://user:pass@host/db → redact pass
|
|
3066
|
+
{ kind: "db-uri-password", regex: /(\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp|mssql):\/\/[^:\s]+:)([^@\s]+)(@)/gi },
|
|
3067
|
+
// Anthropic API keys
|
|
3068
|
+
{ kind: "anthropic-key", regex: /(sk-ant-[a-zA-Z0-9_-]{90,})/g },
|
|
3069
|
+
// OpenAI / generic sk- keys — requires length ≥32 to avoid eating short identifiers
|
|
3070
|
+
{ kind: "openai-key", regex: /(sk-(?:proj-)?[a-zA-Z0-9_-]{32,})/g },
|
|
3071
|
+
// GitHub personal access tokens
|
|
3072
|
+
{ kind: "github-pat", regex: /\b(ghp_[a-zA-Z0-9]{36})\b/g },
|
|
3073
|
+
{ kind: "github-oauth", regex: /\b(gho_[a-zA-Z0-9]{36})\b/g },
|
|
3074
|
+
{ kind: "github-install", regex: /\b(ghs_[a-zA-Z0-9]{36})\b/g },
|
|
3075
|
+
// Slack tokens
|
|
3076
|
+
{ kind: "slack-bot", regex: /\b(xoxb-\d+-\d+-[a-zA-Z0-9]+)\b/g },
|
|
3077
|
+
{ kind: "slack-user", regex: /\b(xoxp-\d+-\d+-\d+-[a-zA-Z0-9]+)\b/g },
|
|
3078
|
+
// AWS access key IDs (AKIA...) and secret access keys are context-dependent;
|
|
3079
|
+
// we only catch the ID because secret key alone is indistinguishable from random base64.
|
|
3080
|
+
{ kind: "aws-access-key-id", regex: /\b(AKIA[0-9A-Z]{16})\b/g },
|
|
3081
|
+
// Google API keys
|
|
3082
|
+
{ kind: "google-api-key", regex: /\b(AIza[0-9A-Za-z_-]{35})\b/g },
|
|
3083
|
+
// Generic "api_key": "..." / "apiKey": "..." / api-key=xxx
|
|
3084
|
+
{ kind: "api-key", regex: /\b(api[_-]?key)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{16,200})["']?/gi },
|
|
3085
|
+
// Generic token: xxx (only when value looks token-shaped; avoids eating human prose)
|
|
3086
|
+
{ kind: "token", regex: /\b(token|access[_-]?token|bearer[_-]?token)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{20,300})["']?/gi },
|
|
3087
|
+
// Bearer <token> in Authorization headers
|
|
3088
|
+
{ kind: "bearer", regex: /\b(Authorization:\s*Bearer\s+)([a-zA-Z0-9_\-.=]{20,500})/g },
|
|
3089
|
+
// Private key PEM blocks — catch the header+footer together
|
|
3090
|
+
{ kind: "private-key", regex: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g }
|
|
3091
|
+
];
|
|
3092
|
+
function render(placeholder, kind) {
|
|
3093
|
+
return placeholder.replace("{kind}", kind);
|
|
3094
|
+
}
|
|
3095
|
+
function redactString(input, options) {
|
|
3096
|
+
if (!options.enabled || !input) return { redacted: input, hits: [] };
|
|
3097
|
+
const placeholder = options.placeholder ?? "[REDACTED:{kind}]";
|
|
3098
|
+
const patterns = [
|
|
3099
|
+
...options.patterns ?? DEFAULT_PATTERNS,
|
|
3100
|
+
...(options.customRegexes ?? []).flatMap((src, i) => {
|
|
3101
|
+
try {
|
|
3102
|
+
const flags = src.match(/^\/.*\/([gimsuy]*)$/)?.[1] ?? "";
|
|
3103
|
+
const body = src.replace(/^\/(.*)\/[gimsuy]*$/, "$1");
|
|
3104
|
+
const regex = new RegExp(body, flags.includes("g") ? flags : flags + "g");
|
|
3105
|
+
return [{ kind: `custom-${i}`, regex }];
|
|
3106
|
+
} catch {
|
|
3107
|
+
return [];
|
|
3108
|
+
}
|
|
3109
|
+
})
|
|
3110
|
+
];
|
|
3111
|
+
let redacted = input;
|
|
3112
|
+
const hits = [];
|
|
3113
|
+
for (const { kind, regex } of patterns) {
|
|
3114
|
+
const rx = new RegExp(regex.source, regex.flags);
|
|
3115
|
+
redacted = redacted.replace(rx, (...args) => {
|
|
3116
|
+
const match = args[0];
|
|
3117
|
+
const probe = new RegExp(rx.source).exec(match);
|
|
3118
|
+
const captureCount = probe ? probe.length - 1 : 0;
|
|
3119
|
+
const g1 = captureCount >= 1 ? args[1] : void 0;
|
|
3120
|
+
const g2 = captureCount >= 2 ? args[2] : void 0;
|
|
3121
|
+
const offset = args[1 + captureCount];
|
|
3122
|
+
if (captureCount >= 2 && typeof g2 === "string") {
|
|
3123
|
+
hits.push({ kind, start: offset + (g1?.length ?? 0), length: g2.length, secret: g2 });
|
|
3124
|
+
return `${g1}${render(placeholder, kind)}`;
|
|
3125
|
+
}
|
|
3126
|
+
hits.push({ kind, start: offset, length: match.length, secret: g1 ?? match });
|
|
3127
|
+
return render(placeholder, kind);
|
|
3128
|
+
});
|
|
3129
|
+
}
|
|
3130
|
+
return { redacted, hits };
|
|
3131
|
+
}
|
|
3132
|
+
function redactJson(value, options) {
|
|
3133
|
+
if (!options.enabled) return { value, hits: [] };
|
|
3134
|
+
const allHits = [];
|
|
3135
|
+
function walk(v) {
|
|
3136
|
+
if (typeof v === "string") {
|
|
3137
|
+
const r = redactString(v, options);
|
|
3138
|
+
allHits.push(...r.hits);
|
|
3139
|
+
return r.redacted;
|
|
3140
|
+
}
|
|
3141
|
+
if (Array.isArray(v)) return v.map(walk);
|
|
3142
|
+
if (v && typeof v === "object") {
|
|
3143
|
+
const out = {};
|
|
3144
|
+
for (const [k, vv] of Object.entries(v)) {
|
|
3145
|
+
out[k] = walk(vv);
|
|
3146
|
+
}
|
|
3147
|
+
return out;
|
|
3148
|
+
}
|
|
3149
|
+
return v;
|
|
3150
|
+
}
|
|
3151
|
+
const redacted = walk(value);
|
|
3152
|
+
return { value: redacted, hits: allHits };
|
|
3153
|
+
}
|
|
3154
|
+
|
|
3009
3155
|
// src/session/session-manager.ts
|
|
3010
3156
|
function safeDate(value) {
|
|
3011
3157
|
const d = new Date(value);
|
|
@@ -3019,9 +3165,27 @@ function extractJsonField(header, field) {
|
|
|
3019
3165
|
var SessionManager = class {
|
|
3020
3166
|
_current = null;
|
|
3021
3167
|
historyDir;
|
|
3168
|
+
config;
|
|
3169
|
+
/** Last save's redaction hit count — exposed for /security status reporting */
|
|
3170
|
+
lastRedactionHits = 0;
|
|
3022
3171
|
constructor(config) {
|
|
3172
|
+
this.config = config;
|
|
3023
3173
|
this.historyDir = config.getHistoryDir();
|
|
3024
3174
|
}
|
|
3175
|
+
/**
|
|
3176
|
+
* Build redaction options from config. Returns `{ enabled: false }` when
|
|
3177
|
+
* `security.redactOnSave` is off or `security.mode` is 'off'.
|
|
3178
|
+
*/
|
|
3179
|
+
redactOptionsForSave() {
|
|
3180
|
+
const security = this.config.get("security");
|
|
3181
|
+
if (!security || !security.redactOnSave || security.mode === "off") {
|
|
3182
|
+
return { enabled: false };
|
|
3183
|
+
}
|
|
3184
|
+
return {
|
|
3185
|
+
enabled: true,
|
|
3186
|
+
customRegexes: security.customPatterns ?? []
|
|
3187
|
+
};
|
|
3188
|
+
}
|
|
3025
3189
|
get current() {
|
|
3026
3190
|
return this._current;
|
|
3027
3191
|
}
|
|
@@ -3047,8 +3211,12 @@ var SessionManager = class {
|
|
|
3047
3211
|
if (!this._current) return;
|
|
3048
3212
|
mkdirSync2(this.historyDir, { recursive: true });
|
|
3049
3213
|
const filePath = join2(this.historyDir, `${this._current.id}.json`);
|
|
3214
|
+
const raw = this._current.toJSON();
|
|
3215
|
+
const opts = this.redactOptionsForSave();
|
|
3216
|
+
const { value: payload, hits } = redactJson(raw, opts);
|
|
3217
|
+
this.lastRedactionHits = hits.length;
|
|
3050
3218
|
const tmpPath = filePath + ".tmp";
|
|
3051
|
-
writeFileSync2(tmpPath, JSON.stringify(
|
|
3219
|
+
writeFileSync2(tmpPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
3052
3220
|
renameSync(tmpPath, filePath);
|
|
3053
3221
|
}
|
|
3054
3222
|
loadSession(id) {
|
|
@@ -9035,7 +9203,15 @@ var PRICING_TABLE = {
|
|
|
9035
9203
|
"glm-4": { input: 0.14, output: 0.14 },
|
|
9036
9204
|
"glm-4-flash": { input: 0, output: 0 },
|
|
9037
9205
|
"glm-4.5": { input: 0.29, output: 1.14 },
|
|
9038
|
-
"glm-4.6": { input: 0.6, output: 2.2 }
|
|
9206
|
+
"glm-4.6": { input: 0.6, output: 2.2 },
|
|
9207
|
+
"glm-4.6v": { input: 0.6, output: 2.2 },
|
|
9208
|
+
"glm-5": { input: 0.85, output: 2.85 },
|
|
9209
|
+
"glm-5.1": { input: 0.95, output: 3.15 },
|
|
9210
|
+
"glm-5.1-reasoning": { input: 1.4, output: 4.4 },
|
|
9211
|
+
"glm-5.1-air": { input: 0.4, output: 1.2 },
|
|
9212
|
+
"glm-z1": { input: 0.5, output: 1.5 },
|
|
9213
|
+
"glm-z1-air": { input: 0.2, output: 0.6 },
|
|
9214
|
+
"glm-z1-flash": { input: 0, output: 0 }
|
|
9039
9215
|
// ── OpenRouter (pass-through — actual cost depends on underlying model) ──
|
|
9040
9216
|
// Left empty; callers should resolve via underlying model ID.
|
|
9041
9217
|
// ── Ollama (local, zero cost) ─────────────────────────────────
|
|
@@ -11070,7 +11246,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11070
11246
|
case "test": {
|
|
11071
11247
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
11072
11248
|
try {
|
|
11073
|
-
const { executeTests } = await import("./run-tests-
|
|
11249
|
+
const { executeTests } = await import("./run-tests-JVWIGY7P.js");
|
|
11074
11250
|
const argStr = args.join(" ").trim();
|
|
11075
11251
|
let testArgs = {};
|
|
11076
11252
|
if (argStr) {
|
|
@@ -385,7 +385,7 @@ ${content}`);
|
|
|
385
385
|
}
|
|
386
386
|
}
|
|
387
387
|
async function runTaskMode(config, providers, configManager, topic) {
|
|
388
|
-
const { TaskOrchestrator } = await import("./task-orchestrator-
|
|
388
|
+
const { TaskOrchestrator } = await import("./task-orchestrator-6MI6LD7T.js");
|
|
389
389
|
const orchestrator = new TaskOrchestrator(config, providers, configManager);
|
|
390
390
|
let interrupted = false;
|
|
391
391
|
const onSigint = () => {
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
DEFAULT_PATTERNS,
|
|
3
4
|
HALLUCINATION_CORRECTION_MESSAGE,
|
|
4
5
|
McpManager,
|
|
5
6
|
ProviderRegistry,
|
|
@@ -28,12 +29,13 @@ import {
|
|
|
28
29
|
persistToolRound,
|
|
29
30
|
rebuildExtraMessages,
|
|
30
31
|
saveDevState,
|
|
32
|
+
scanString,
|
|
31
33
|
sessionHasMeaningfulContent,
|
|
32
34
|
setupProxy
|
|
33
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-L3MBIO36.js";
|
|
34
36
|
import {
|
|
35
37
|
ConfigManager
|
|
36
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-QT2KNL3V.js";
|
|
37
39
|
import {
|
|
38
40
|
ToolExecutor,
|
|
39
41
|
ToolRegistry,
|
|
@@ -49,7 +51,7 @@ import {
|
|
|
49
51
|
spawnAgentContext,
|
|
50
52
|
theme,
|
|
51
53
|
undoStack
|
|
52
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-YDHIU24C.js";
|
|
53
55
|
import "./chunk-2ZD3YTVM.js";
|
|
54
56
|
import {
|
|
55
57
|
fileCheckpoints
|
|
@@ -58,7 +60,7 @@ import "./chunk-NHNWUBXB.js";
|
|
|
58
60
|
import "./chunk-CQQQFNND.js";
|
|
59
61
|
import "./chunk-6VRJGH25.js";
|
|
60
62
|
import "./chunk-PFYAAX2S.js";
|
|
61
|
-
import "./chunk-
|
|
63
|
+
import "./chunk-V3NMERIB.js";
|
|
62
64
|
import {
|
|
63
65
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
64
66
|
AUTHOR,
|
|
@@ -80,7 +82,7 @@ import {
|
|
|
80
82
|
SKILLS_DIR_NAME,
|
|
81
83
|
VERSION,
|
|
82
84
|
buildUserIdentityPrompt
|
|
83
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-VGXNE37B.js";
|
|
84
86
|
|
|
85
87
|
// src/index.ts
|
|
86
88
|
import { program } from "commander";
|
|
@@ -980,6 +982,7 @@ function createDefaultCommands() {
|
|
|
980
982
|
" /fork [checkpoint] - Fork session from checkpoint or current position",
|
|
981
983
|
" /branch [list|new|switch|delete|rename|diff|cherry-pick] - Manage conversation branches (fork tree, cross-branch picks)",
|
|
982
984
|
" /index [status|rebuild|clear|semantic-rebuild|semantic-clear] - Symbol + semantic index (find_symbol / search_code)",
|
|
985
|
+
" /security [status|scan|on|off] - Sensitive-data redaction status & session scan",
|
|
983
986
|
" /yolo [on|off] - Toggle session auto-approve (skip confirmations)",
|
|
984
987
|
" /exit - Exit"
|
|
985
988
|
] : [];
|
|
@@ -2592,7 +2595,7 @@ ${hint}` : "")
|
|
|
2592
2595
|
usage: "/test [command|filter]",
|
|
2593
2596
|
async execute(args, ctx) {
|
|
2594
2597
|
try {
|
|
2595
|
-
const { executeTests } = await import("./run-tests-
|
|
2598
|
+
const { executeTests } = await import("./run-tests-FQHDUYOG.js");
|
|
2596
2599
|
const argStr = args.join(" ").trim();
|
|
2597
2600
|
let testArgs = {};
|
|
2598
2601
|
if (argStr) {
|
|
@@ -3031,6 +3034,94 @@ Summary: ${fileMap.size} file(s) \u2014 ${newFiles} new, ${modifiedFiles} modifi
|
|
|
3031
3034
|
}
|
|
3032
3035
|
}
|
|
3033
3036
|
},
|
|
3037
|
+
{
|
|
3038
|
+
name: "security",
|
|
3039
|
+
description: "Sensitive-data redaction \u2014 status, scan sessions, toggle on/off",
|
|
3040
|
+
usage: "/security [status|scan [--all]|on|off]",
|
|
3041
|
+
async execute(args, ctx) {
|
|
3042
|
+
const sub = (args[0] || "status").toLowerCase();
|
|
3043
|
+
const security = ctx.config.get("security") ?? {
|
|
3044
|
+
redactOnSave: true,
|
|
3045
|
+
redactOnSend: false,
|
|
3046
|
+
mode: "default",
|
|
3047
|
+
customPatterns: []
|
|
3048
|
+
};
|
|
3049
|
+
if (sub === "status") {
|
|
3050
|
+
console.log(theme.heading(" \u{1F6E1} Security / Redaction"));
|
|
3051
|
+
console.log(` redactOnSave : ${security.redactOnSave ? theme.success("on") : theme.warning("off")}`);
|
|
3052
|
+
console.log(` redactOnSend : ${security.redactOnSend ? theme.success("on") : theme.dim("off")}`);
|
|
3053
|
+
console.log(` mode : ${security.mode}`);
|
|
3054
|
+
console.log(` patterns : ${DEFAULT_PATTERNS.length} built-in + ${security.customPatterns?.length ?? 0} custom`);
|
|
3055
|
+
console.log(` last save : ${ctx.sessions.lastRedactionHits} hit(s) redacted`);
|
|
3056
|
+
console.log();
|
|
3057
|
+
console.log(theme.dim(" /security scan \u2014 scan current session for leaks"));
|
|
3058
|
+
console.log(theme.dim(" /security scan --all \u2014 scan all saved sessions"));
|
|
3059
|
+
console.log(theme.dim(" /security on|off \u2014 toggle redactOnSave"));
|
|
3060
|
+
console.log();
|
|
3061
|
+
return;
|
|
3062
|
+
}
|
|
3063
|
+
if (sub === "on" || sub === "off") {
|
|
3064
|
+
ctx.config.set("security", { ...security, redactOnSave: sub === "on" });
|
|
3065
|
+
console.log(theme.success(` \u2713 redactOnSave = ${sub}`));
|
|
3066
|
+
console.log();
|
|
3067
|
+
return;
|
|
3068
|
+
}
|
|
3069
|
+
if (sub === "scan") {
|
|
3070
|
+
const scanAll = args.includes("--all");
|
|
3071
|
+
const opts = { customRegexes: security.customPatterns ?? [] };
|
|
3072
|
+
let totalHits = 0;
|
|
3073
|
+
let filesWithHits = 0;
|
|
3074
|
+
if (scanAll) {
|
|
3075
|
+
const metas = ctx.sessions.listSessions();
|
|
3076
|
+
console.log(theme.info(` Scanning ${metas.length} session(s)\u2026`));
|
|
3077
|
+
const { readFileSync: readFileSync5 } = await import("fs");
|
|
3078
|
+
const { join: join6 } = await import("path");
|
|
3079
|
+
const historyDir = ctx.config.getHistoryDir();
|
|
3080
|
+
for (const m of metas) {
|
|
3081
|
+
try {
|
|
3082
|
+
const content = readFileSync5(join6(historyDir, `${m.id}.json`), "utf-8");
|
|
3083
|
+
const hits2 = scanString(content, opts);
|
|
3084
|
+
if (hits2.length) {
|
|
3085
|
+
filesWithHits++;
|
|
3086
|
+
totalHits += hits2.length;
|
|
3087
|
+
const kinds = [...new Set(hits2.map((h) => h.kind))].join(", ");
|
|
3088
|
+
console.log(` ${theme.warning("\u26A0")} ${m.id.slice(0, 8)}\u2026 ${theme.dim(m.title || "")} \u2014 ${hits2.length} hit(s) [${kinds}]`);
|
|
3089
|
+
}
|
|
3090
|
+
} catch {
|
|
3091
|
+
}
|
|
3092
|
+
}
|
|
3093
|
+
console.log();
|
|
3094
|
+
console.log(
|
|
3095
|
+
totalHits === 0 ? theme.success(` \u2713 No secrets found in ${metas.length} session(s).`) : theme.warning(` Found ${totalHits} hit(s) across ${filesWithHits} session(s). Re-save them with redactOnSave=on to sanitize.`)
|
|
3096
|
+
);
|
|
3097
|
+
console.log();
|
|
3098
|
+
return;
|
|
3099
|
+
}
|
|
3100
|
+
const current = ctx.sessions.current;
|
|
3101
|
+
if (!current) {
|
|
3102
|
+
console.log(theme.warning(" No active session to scan."));
|
|
3103
|
+
console.log();
|
|
3104
|
+
return;
|
|
3105
|
+
}
|
|
3106
|
+
const json = JSON.stringify(current.toJSON());
|
|
3107
|
+
const hits = scanString(json, opts);
|
|
3108
|
+
if (hits.length === 0) {
|
|
3109
|
+
console.log(theme.success(" \u2713 Current session: no secrets detected."));
|
|
3110
|
+
} else {
|
|
3111
|
+
const byKind = /* @__PURE__ */ new Map();
|
|
3112
|
+
for (const h of hits) byKind.set(h.kind, (byKind.get(h.kind) ?? 0) + 1);
|
|
3113
|
+
console.log(theme.warning(` \u26A0 Current session: ${hits.length} hit(s)`));
|
|
3114
|
+
for (const [k, n] of byKind) console.log(` \u2022 ${k}: ${n}`);
|
|
3115
|
+
console.log(theme.dim(" (save the session to replace them with placeholders)"));
|
|
3116
|
+
}
|
|
3117
|
+
console.log();
|
|
3118
|
+
return;
|
|
3119
|
+
}
|
|
3120
|
+
console.log(theme.error(` Unknown subcommand: ${sub}`));
|
|
3121
|
+
console.log(theme.dim(" Usage: /security [status|scan [--all]|on|off]"));
|
|
3122
|
+
console.log();
|
|
3123
|
+
}
|
|
3124
|
+
},
|
|
3034
3125
|
{
|
|
3035
3126
|
name: "yolo",
|
|
3036
3127
|
description: "Toggle session auto-approve (skip all confirmations)",
|
|
@@ -6485,7 +6576,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
6485
6576
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
6486
6577
|
process.exit(1);
|
|
6487
6578
|
}
|
|
6488
|
-
const { startWebServer } = await import("./server-
|
|
6579
|
+
const { startWebServer } = await import("./server-UWKRV5DK.js");
|
|
6489
6580
|
await startWebServer({ port, host: options.host });
|
|
6490
6581
|
});
|
|
6491
6582
|
program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | migrate <name>)").action(async (action, username) => {
|
|
@@ -6608,7 +6699,7 @@ program.command("sessions").description("List recent conversation sessions").act
|
|
|
6608
6699
|
});
|
|
6609
6700
|
program.command("batch <action> [arg] [arg2]").description("Anthropic Message Batches: submit | list | status <id> | results <id> [out] | cancel <id>").option("--dry-run", "Parse and validate input without submitting (submit only)").action(async (action, arg, arg2, options) => {
|
|
6610
6701
|
try {
|
|
6611
|
-
const batch = await import("./batch-
|
|
6702
|
+
const batch = await import("./batch-7XCYSPJU.js");
|
|
6612
6703
|
switch (action) {
|
|
6613
6704
|
case "submit":
|
|
6614
6705
|
if (!arg) {
|
|
@@ -6651,7 +6742,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
|
|
|
6651
6742
|
}
|
|
6652
6743
|
});
|
|
6653
6744
|
program.command("mcp-serve").description("Start an MCP server over STDIO, exposing aicli's built-in tools to Claude Desktop / Cursor / other MCP clients").option("--allow-destructive", "Allow bash / run_interactive / task_create (always destructive in MCP mode)").option("--allow-outside-cwd", "Allow tool path arguments to escape the sandbox root \u2014 disabled by default").option("--tools <list>", "Comma-separated whitelist of tools to expose (default: all eligible tools)").option("--cwd <path>", "Working directory AND sandbox root (default: current directory)").action(async (options) => {
|
|
6654
|
-
const { startMcpServer } = await import("./server-
|
|
6745
|
+
const { startMcpServer } = await import("./server-HTVVWKFN.js");
|
|
6655
6746
|
await startMcpServer({
|
|
6656
6747
|
allowDestructive: !!options.allowDestructive,
|
|
6657
6748
|
allowOutsideCwd: !!options.allowOutsideCwd,
|
|
@@ -6778,7 +6869,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
6778
6869
|
}),
|
|
6779
6870
|
config.get("customProviders")
|
|
6780
6871
|
);
|
|
6781
|
-
const { startHub } = await import("./hub-
|
|
6872
|
+
const { startHub } = await import("./hub-IR4INXSU.js");
|
|
6782
6873
|
await startHub(
|
|
6783
6874
|
{
|
|
6784
6875
|
topic: topic ?? "",
|
|
@@ -3,17 +3,17 @@ import {
|
|
|
3
3
|
ToolRegistry,
|
|
4
4
|
getDangerLevel,
|
|
5
5
|
schemaToJsonSchema
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-YDHIU24C.js";
|
|
7
7
|
import "./chunk-2ZD3YTVM.js";
|
|
8
8
|
import "./chunk-4BKXL7SM.js";
|
|
9
9
|
import "./chunk-NHNWUBXB.js";
|
|
10
10
|
import "./chunk-CQQQFNND.js";
|
|
11
11
|
import "./chunk-6VRJGH25.js";
|
|
12
12
|
import "./chunk-PFYAAX2S.js";
|
|
13
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-V3NMERIB.js";
|
|
14
14
|
import {
|
|
15
15
|
VERSION
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-VGXNE37B.js";
|
|
17
17
|
|
|
18
18
|
// src/mcp/server.ts
|
|
19
19
|
import { createInterface } from "readline";
|
|
@@ -20,10 +20,10 @@ import {
|
|
|
20
20
|
persistToolRound,
|
|
21
21
|
rebuildExtraMessages,
|
|
22
22
|
setupProxy
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-L3MBIO36.js";
|
|
24
24
|
import {
|
|
25
25
|
ConfigManager
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-QT2KNL3V.js";
|
|
27
27
|
import {
|
|
28
28
|
ToolExecutor,
|
|
29
29
|
ToolRegistry,
|
|
@@ -41,14 +41,14 @@ import {
|
|
|
41
41
|
spawnAgentContext,
|
|
42
42
|
truncateOutput,
|
|
43
43
|
undoStack
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-YDHIU24C.js";
|
|
45
45
|
import "./chunk-2ZD3YTVM.js";
|
|
46
46
|
import "./chunk-4BKXL7SM.js";
|
|
47
47
|
import "./chunk-NHNWUBXB.js";
|
|
48
48
|
import "./chunk-CQQQFNND.js";
|
|
49
49
|
import "./chunk-6VRJGH25.js";
|
|
50
50
|
import "./chunk-PFYAAX2S.js";
|
|
51
|
-
import "./chunk-
|
|
51
|
+
import "./chunk-V3NMERIB.js";
|
|
52
52
|
import {
|
|
53
53
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
54
54
|
AUTHOR,
|
|
@@ -67,7 +67,7 @@ import {
|
|
|
67
67
|
SKILLS_DIR_NAME,
|
|
68
68
|
VERSION,
|
|
69
69
|
buildUserIdentityPrompt
|
|
70
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-VGXNE37B.js";
|
|
71
71
|
import {
|
|
72
72
|
AuthManager
|
|
73
73
|
} from "./chunk-BYNY5JPB.js";
|
|
@@ -2229,7 +2229,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
2229
2229
|
case "test": {
|
|
2230
2230
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
2231
2231
|
try {
|
|
2232
|
-
const { executeTests } = await import("./run-tests-
|
|
2232
|
+
const { executeTests } = await import("./run-tests-FQHDUYOG.js");
|
|
2233
2233
|
const argStr = args.join(" ").trim();
|
|
2234
2234
|
let testArgs = {};
|
|
2235
2235
|
if (argStr) {
|
|
@@ -4,17 +4,17 @@ import {
|
|
|
4
4
|
getDangerLevel,
|
|
5
5
|
googleSearchContext,
|
|
6
6
|
truncateOutput
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-YDHIU24C.js";
|
|
8
8
|
import "./chunk-2ZD3YTVM.js";
|
|
9
9
|
import "./chunk-4BKXL7SM.js";
|
|
10
10
|
import "./chunk-NHNWUBXB.js";
|
|
11
11
|
import "./chunk-CQQQFNND.js";
|
|
12
12
|
import "./chunk-6VRJGH25.js";
|
|
13
13
|
import "./chunk-PFYAAX2S.js";
|
|
14
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-V3NMERIB.js";
|
|
15
15
|
import {
|
|
16
16
|
SUBAGENT_ALLOWED_TOOLS
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-VGXNE37B.js";
|
|
18
18
|
|
|
19
19
|
// src/hub/task-orchestrator.ts
|
|
20
20
|
import { createInterface } from "readline";
|