jinzd-ai-cli 0.4.235 → 0.4.237
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 +5 -5
- package/dist/{batch-Y7MHXVR7.js → batch-S2NUD45K.js} +2 -2
- package/dist/{chunk-GDXKFWFL.js → chunk-25FKQO3A.js} +1 -1
- package/dist/{chunk-CDOQNIVV.js → chunk-45TJA46E.js} +3 -3
- package/dist/{chunk-Q5GVANMH.js → chunk-6RU5AKXB.js} +1 -1
- package/dist/{chunk-BFTTW5LS.js → chunk-CSATDZ3Z.js} +1 -1
- package/dist/{chunk-HHYMSEWS.js → chunk-EG5P3AMC.js} +1 -1
- package/dist/{chunk-WXFQ6LYN.js → chunk-J2M4GOFE.js} +1 -1
- package/dist/{chunk-DHNYGJYB.js → chunk-KQJ55BTD.js} +3 -3
- package/dist/{chunk-GFDRC2JZ.js → chunk-MSK2BAKT.js} +115 -18
- package/dist/{chunk-7D5EJBHO.js → chunk-NAPAMAFY.js} +3 -3
- package/dist/{chunk-FYJGVFXL.js → chunk-WI4DN5FN.js} +51 -7
- package/dist/{ci-OAFNH3MA.js → ci-HDGRBALH.js} +4 -4
- package/dist/{ci-format-4LSXJNND.js → ci-format-W6DDOFS7.js} +2 -2
- package/dist/{constants-ERIAS7GV.js → constants-3KMOIJNP.js} +1 -1
- package/dist/{doctor-cli-VFSVWZU6.js → doctor-cli-E5MBY7CZ.js} +4 -4
- package/dist/electron-server.js +208 -67
- package/dist/{hub-X4EUYRIN.js → hub-2WPMT242.js} +1 -1
- package/dist/index.js +2438 -2436
- package/dist/{pr-2CZN5JLE.js → pr-RRHV7P7D.js} +4 -4
- package/dist/{run-tests-DXRJDPFF.js → run-tests-GP7ZMSAX.js} +2 -2
- package/dist/{run-tests-YSRET52H.js → run-tests-K36VNQ5W.js} +1 -1
- package/dist/{server-5ZAXMKRI.js → server-J36CY5EU.js} +28 -28
- package/dist/{server-FGJGXHZD.js → server-JEVAHG53.js} +4 -4
- package/dist/{task-orchestrator-QMERCD77.js → task-orchestrator-D66BJZKU.js} +4 -4
- package/dist/{usage-633DUDNT.js → usage-5QO5AFYC.js} +2 -2
- package/package.json +1 -1
package/dist/electron-server.js
CHANGED
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
VERSION,
|
|
39
39
|
buildUserIdentityPrompt,
|
|
40
40
|
runTestsTool
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-EG5P3AMC.js";
|
|
42
42
|
import {
|
|
43
43
|
hasSemanticIndex,
|
|
44
44
|
semanticSearch
|
|
@@ -70,8 +70,8 @@ import {
|
|
|
70
70
|
import express from "express";
|
|
71
71
|
import { createServer } from "http";
|
|
72
72
|
import { WebSocketServer } from "ws";
|
|
73
|
-
import { join as join28, dirname as
|
|
74
|
-
import { existsSync as
|
|
73
|
+
import { join as join28, dirname as dirname11, resolve as resolve13, relative as relative6, sep as sep4 } from "path";
|
|
74
|
+
import { existsSync as existsSync33, readFileSync as readFileSync25, readdirSync as readdirSync16, statSync as statSync14, realpathSync as realpathSync3 } from "fs";
|
|
75
75
|
import { networkInterfaces } from "os";
|
|
76
76
|
|
|
77
77
|
// src/config/config-manager.ts
|
|
@@ -9153,6 +9153,14 @@ var webFetchTool = {
|
|
|
9153
9153
|
}
|
|
9154
9154
|
const cause = err.cause;
|
|
9155
9155
|
if (cause?.message?.startsWith("Blocked:")) throw new NetworkError(cause.message);
|
|
9156
|
+
if (err instanceof Error && err.message === "fetch failed") {
|
|
9157
|
+
const detail = cause?.message ? ` (${cause.message})` : "";
|
|
9158
|
+
throw new NetworkError(
|
|
9159
|
+
`Connection failed for ${url}${detail}. The domain may be unreachable from the current network (some sites require a proxy \u2014 see config.proxy) or temporarily down. Do not retry the same URL; try an alternative source.`,
|
|
9160
|
+
void 0,
|
|
9161
|
+
err
|
|
9162
|
+
);
|
|
9163
|
+
}
|
|
9156
9164
|
throw err;
|
|
9157
9165
|
} finally {
|
|
9158
9166
|
void dispatcher.close().catch(() => {
|
|
@@ -9301,8 +9309,44 @@ function classifyBingWeakness(query, results) {
|
|
|
9301
9309
|
if (homepageCount / results.length >= 0.6) {
|
|
9302
9310
|
return `${homepageCount}/${results.length} results are bare site homepages (popular-sites fallback)`;
|
|
9303
9311
|
}
|
|
9312
|
+
if (!hasDefinitionIntent(query) && countAsciiWords(query) >= 4) {
|
|
9313
|
+
const dictHits = results.filter(isDictionaryResult).length;
|
|
9314
|
+
if (dictHits >= 2 || isDictionaryResult(results[0])) {
|
|
9315
|
+
return `${dictHits}/${results.length} dictionary word-lookup results for a multi-word query (word-match fallback)`;
|
|
9316
|
+
}
|
|
9317
|
+
}
|
|
9318
|
+
if (!hasDefinitionIntent(query)) {
|
|
9319
|
+
const { total, best } = tokenCoverage(query, results);
|
|
9320
|
+
if (total >= 4 && best < 2) {
|
|
9321
|
+
return `low query-token coverage (best result matches only ${best}/${total} query terms)`;
|
|
9322
|
+
}
|
|
9323
|
+
}
|
|
9304
9324
|
return null;
|
|
9305
9325
|
}
|
|
9326
|
+
function tokenCoverage(query, results) {
|
|
9327
|
+
const tokens = extractQueryTokens(query);
|
|
9328
|
+
let best = 0;
|
|
9329
|
+
for (const r of results) {
|
|
9330
|
+
const haystack = (r.title + " " + r.snippet).toLowerCase();
|
|
9331
|
+
let matched = 0;
|
|
9332
|
+
for (const t of tokens) {
|
|
9333
|
+
if (haystack.includes(t.toLowerCase())) matched++;
|
|
9334
|
+
}
|
|
9335
|
+
if (matched > best) best = matched;
|
|
9336
|
+
}
|
|
9337
|
+
return { total: tokens.size, best };
|
|
9338
|
+
}
|
|
9339
|
+
var DICT_DOMAIN_RE = /\b(iciba\.com|dict\.youdao\.com|youdao\.com\/w\/|dict\.cn|dict\.baidu\.com|dictionary\.cambridge\.org|merriam-webster\.com|vocabulary\.com|bing\.com\/dict)/i;
|
|
9340
|
+
var DICT_TITLE_RE = /(是什么意思|的翻译|_音标_|权威在线词典|剑桥词典|Definition\s*&\s*Meaning)/i;
|
|
9341
|
+
function isDictionaryResult(r) {
|
|
9342
|
+
return DICT_DOMAIN_RE.test(r.url) || DICT_TITLE_RE.test(r.title);
|
|
9343
|
+
}
|
|
9344
|
+
function hasDefinitionIntent(query) {
|
|
9345
|
+
return /(meaning|definition|define\b|translat|pronounc|是什么意思|什么意思|翻译|词典|发音|读音|用法)/i.test(query);
|
|
9346
|
+
}
|
|
9347
|
+
function countAsciiWords(query) {
|
|
9348
|
+
return (query.match(/[a-zA-Z]{3,}/g) ?? []).length;
|
|
9349
|
+
}
|
|
9306
9350
|
function isBareHomepage(url) {
|
|
9307
9351
|
try {
|
|
9308
9352
|
return new URL(url).pathname.replace(/\/+$/, "") === "";
|
|
@@ -10146,8 +10190,8 @@ import { join as join14 } from "path";
|
|
|
10146
10190
|
import { homedir as homedir6 } from "os";
|
|
10147
10191
|
|
|
10148
10192
|
// src/plugins/plugin-manager.ts
|
|
10149
|
-
import { existsSync as existsSync18, mkdirSync as mkdirSync9, readdirSync as readdirSync7, readFileSync as readFileSync13, cpSync, rmSync, statSync as statSync7 } from "fs";
|
|
10150
|
-
import { basename as basename6, dirname as dirname8, join as join13, resolve as resolve7 } from "path";
|
|
10193
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync9, readdirSync as readdirSync7, readFileSync as readFileSync13, realpathSync as realpathSync2, cpSync, rmSync, statSync as statSync7 } from "fs";
|
|
10194
|
+
import { basename as basename6, dirname as dirname8, join as join13, relative as relative3, resolve as resolve7, sep as sep3 } from "path";
|
|
10151
10195
|
import { createHash as createHash3 } from "crypto";
|
|
10152
10196
|
import { z as z2 } from "zod";
|
|
10153
10197
|
var MANIFEST_RELATIVE = ".aicli-plugin/plugin.json";
|
|
@@ -10217,20 +10261,117 @@ function statePath(configDir) {
|
|
|
10217
10261
|
}
|
|
10218
10262
|
function loadState(configDir) {
|
|
10219
10263
|
const file = statePath(configDir);
|
|
10220
|
-
if (!existsSync18(file)) return { version:
|
|
10264
|
+
if (!existsSync18(file)) return { version: 2, plugins: [] };
|
|
10221
10265
|
try {
|
|
10222
10266
|
const parsed = JSON.parse(readFileSync13(file, "utf-8"));
|
|
10223
|
-
|
|
10267
|
+
const rawPlugins = Array.isArray(parsed.plugins) ? parsed.plugins : [];
|
|
10268
|
+
return { version: 2, plugins: rawPlugins.map((p) => migrateEntry(p)) };
|
|
10224
10269
|
} catch {
|
|
10225
|
-
return { version:
|
|
10270
|
+
return { version: 2, plugins: [] };
|
|
10226
10271
|
}
|
|
10227
10272
|
}
|
|
10273
|
+
function migrateEntry(entry) {
|
|
10274
|
+
const name = String(entry.name ?? "");
|
|
10275
|
+
const contentHash = typeof entry.contentHash === "string" ? entry.contentHash : void 0;
|
|
10276
|
+
const legacyHash = typeof entry.hash === "string" ? entry.hash : void 0;
|
|
10277
|
+
const trusted = contentHash ? entry.trusted === true : false;
|
|
10278
|
+
return {
|
|
10279
|
+
name,
|
|
10280
|
+
enabled: entry.enabled === true,
|
|
10281
|
+
trusted,
|
|
10282
|
+
contentHash: contentHash ?? legacyHash,
|
|
10283
|
+
installedAt: String(entry.installedAt ?? (/* @__PURE__ */ new Date(0)).toISOString()),
|
|
10284
|
+
trustedAt: trusted && entry.trustedAt ? String(entry.trustedAt) : void 0,
|
|
10285
|
+
enabledAt: entry.enabledAt ? String(entry.enabledAt) : void 0
|
|
10286
|
+
};
|
|
10287
|
+
}
|
|
10228
10288
|
function saveState(configDir, state2) {
|
|
10229
10289
|
mkdirSync9(pluginRoot(configDir), { recursive: true });
|
|
10230
10290
|
atomicWriteFileSync(statePath(configDir), JSON.stringify(state2, null, 2));
|
|
10231
10291
|
}
|
|
10232
|
-
function
|
|
10233
|
-
|
|
10292
|
+
function normalizeForHash(buf) {
|
|
10293
|
+
const str = buf.toString("utf-8").replaceAll("\r\n", "\n");
|
|
10294
|
+
return Buffer.from(str, "utf-8");
|
|
10295
|
+
}
|
|
10296
|
+
function extractCommandPaths(command, pluginDir) {
|
|
10297
|
+
const resolvedDir = resolve7(pluginDir);
|
|
10298
|
+
const refs = [];
|
|
10299
|
+
for (const m of command.matchAll(/\$PLUGIN_DIR[\\/]([^"'\s]+)/g)) {
|
|
10300
|
+
refs.push(m[1]);
|
|
10301
|
+
}
|
|
10302
|
+
for (const m of command.matchAll(/\$\{pluginDir\}[\\/]([^"'\s}]+)/g)) {
|
|
10303
|
+
refs.push(m[1]);
|
|
10304
|
+
}
|
|
10305
|
+
for (const m of command.matchAll(/(?<=["'\s])(\.?[.\\/][^"'\s]+)/g)) {
|
|
10306
|
+
refs.push(m[0]);
|
|
10307
|
+
}
|
|
10308
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10309
|
+
const valid = [];
|
|
10310
|
+
for (const ref of refs) {
|
|
10311
|
+
if (seen.has(ref)) continue;
|
|
10312
|
+
seen.add(ref);
|
|
10313
|
+
try {
|
|
10314
|
+
const abs = resolve7(resolvedDir, ref);
|
|
10315
|
+
if (!abs.startsWith(resolvedDir + sep3)) continue;
|
|
10316
|
+
if (existsSync18(abs)) {
|
|
10317
|
+
const real = realpathSync2(abs);
|
|
10318
|
+
if (!real.startsWith(resolvedDir + sep3)) continue;
|
|
10319
|
+
valid.push(relative3(resolvedDir, real));
|
|
10320
|
+
}
|
|
10321
|
+
} catch {
|
|
10322
|
+
}
|
|
10323
|
+
}
|
|
10324
|
+
return valid;
|
|
10325
|
+
}
|
|
10326
|
+
function hashPluginContent(pluginDir, manifest) {
|
|
10327
|
+
const resolvedDir = resolve7(pluginDir);
|
|
10328
|
+
const assetRels = /* @__PURE__ */ new Set(
|
|
10329
|
+
[...manifest.skills, ...manifest.commands, ...manifest.agents]
|
|
10330
|
+
);
|
|
10331
|
+
for (const raw of Object.values(manifest.hooks?.events ?? {})) {
|
|
10332
|
+
const items = Array.isArray(raw) ? raw : [raw];
|
|
10333
|
+
for (const item of items) {
|
|
10334
|
+
const cmd = typeof item === "string" ? item : item.command;
|
|
10335
|
+
if (cmd) {
|
|
10336
|
+
for (const p of extractCommandPaths(cmd, pluginDir)) assetRels.add(p);
|
|
10337
|
+
}
|
|
10338
|
+
}
|
|
10339
|
+
}
|
|
10340
|
+
for (const server of Object.values(manifest.mcpServers ?? {})) {
|
|
10341
|
+
for (const p of extractCommandPaths(server.command, pluginDir)) assetRels.add(p);
|
|
10342
|
+
for (const arg of server.args ?? []) {
|
|
10343
|
+
for (const p of extractCommandPaths(arg, pluginDir)) assetRels.add(p);
|
|
10344
|
+
}
|
|
10345
|
+
}
|
|
10346
|
+
const sorted = [...assetRels].sort();
|
|
10347
|
+
const hasher = createHash3("sha256");
|
|
10348
|
+
const manifestPath = join13(resolvedDir, MANIFEST_RELATIVE);
|
|
10349
|
+
hasher.update(normalizeForHash(readFileSync13(manifestPath)));
|
|
10350
|
+
for (const rel of sorted) {
|
|
10351
|
+
const abs = resolve7(resolvedDir, rel);
|
|
10352
|
+
if (!abs.startsWith(resolvedDir + sep3)) {
|
|
10353
|
+
throw new Error(`plugin asset escapes plugin dir: ${rel}`);
|
|
10354
|
+
}
|
|
10355
|
+
let realPath;
|
|
10356
|
+
try {
|
|
10357
|
+
realPath = realpathSync2(abs);
|
|
10358
|
+
} catch {
|
|
10359
|
+
continue;
|
|
10360
|
+
}
|
|
10361
|
+
try {
|
|
10362
|
+
if (statSync7(realPath).isDirectory()) continue;
|
|
10363
|
+
} catch {
|
|
10364
|
+
continue;
|
|
10365
|
+
}
|
|
10366
|
+
if (!realPath.startsWith(resolvedDir + sep3)) {
|
|
10367
|
+
throw new Error(`plugin asset symlink escapes plugin dir: ${rel} \u2192 ${realPath}`);
|
|
10368
|
+
}
|
|
10369
|
+
hasher.update(normalizeForHash(readFileSync13(abs)));
|
|
10370
|
+
}
|
|
10371
|
+
return hasher.digest("hex");
|
|
10372
|
+
}
|
|
10373
|
+
function effectiveHash(entry) {
|
|
10374
|
+
return entry.contentHash ?? entry.hash ?? "";
|
|
10234
10375
|
}
|
|
10235
10376
|
function readPluginManifest(manifestPath) {
|
|
10236
10377
|
return PluginManifestSchema.parse(JSON.parse(readFileSync13(manifestPath, "utf-8")));
|
|
@@ -10251,19 +10392,19 @@ function installPlugin(configDir, inputPath) {
|
|
|
10251
10392
|
if (existsSync18(targetDir)) rmSync(targetDir, { recursive: true, force: true });
|
|
10252
10393
|
cpSync(sourceDir, targetDir, { recursive: true });
|
|
10253
10394
|
const manifestPath = pluginManifestPath(targetDir);
|
|
10254
|
-
const
|
|
10395
|
+
const contentHash = hashPluginContent(targetDir, manifest);
|
|
10255
10396
|
const state2 = loadState(configDir);
|
|
10256
10397
|
const previous = state2.plugins.find((p) => p.name === manifest.name);
|
|
10257
10398
|
const next = {
|
|
10258
10399
|
name: manifest.name,
|
|
10259
10400
|
enabled: previous?.enabled ?? false,
|
|
10260
10401
|
trusted: false,
|
|
10261
|
-
|
|
10402
|
+
contentHash,
|
|
10262
10403
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10263
10404
|
};
|
|
10264
10405
|
state2.plugins = [...state2.plugins.filter((p) => p.name !== manifest.name), next];
|
|
10265
10406
|
saveState(configDir, state2);
|
|
10266
|
-
return { name: manifest.name, dir: targetDir, manifestPath, manifest, hash, enabled: next.enabled, trusted: false, valid: true };
|
|
10407
|
+
return { name: manifest.name, dir: targetDir, manifestPath, manifest, hash: contentHash, enabled: next.enabled, trusted: false, valid: true };
|
|
10267
10408
|
}
|
|
10268
10409
|
function setPluginEnabled(configDir, name, enabled) {
|
|
10269
10410
|
const plugin = getInstalledPlugin(configDir, name);
|
|
@@ -10273,10 +10414,10 @@ function setPluginEnabled(configDir, name, enabled) {
|
|
|
10273
10414
|
name: plugin.name,
|
|
10274
10415
|
enabled: false,
|
|
10275
10416
|
trusted: false,
|
|
10276
|
-
|
|
10417
|
+
contentHash: plugin.hash,
|
|
10277
10418
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10278
10419
|
};
|
|
10279
|
-
const next = { ...current, enabled,
|
|
10420
|
+
const next = { ...current, enabled, contentHash: plugin.hash, enabledAt: enabled ? (/* @__PURE__ */ new Date()).toISOString() : current.enabledAt };
|
|
10280
10421
|
state2.plugins = [...state2.plugins.filter((p) => p.name !== plugin.name), next];
|
|
10281
10422
|
saveState(configDir, state2);
|
|
10282
10423
|
return next;
|
|
@@ -10289,10 +10430,10 @@ function trustPlugin(configDir, name) {
|
|
|
10289
10430
|
name: plugin.name,
|
|
10290
10431
|
enabled: false,
|
|
10291
10432
|
trusted: false,
|
|
10292
|
-
|
|
10433
|
+
contentHash: plugin.hash,
|
|
10293
10434
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10294
10435
|
};
|
|
10295
|
-
const next = { ...current, trusted: true,
|
|
10436
|
+
const next = { ...current, trusted: true, contentHash: plugin.hash, trustedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
10296
10437
|
state2.plugins = [...state2.plugins.filter((p) => p.name !== plugin.name), next];
|
|
10297
10438
|
saveState(configDir, state2);
|
|
10298
10439
|
return next;
|
|
@@ -10320,15 +10461,15 @@ function listInstalledPlugins(configDir) {
|
|
|
10320
10461
|
if (!existsSync18(manifestPath)) continue;
|
|
10321
10462
|
try {
|
|
10322
10463
|
const manifest = readPluginManifest(manifestPath);
|
|
10323
|
-
const
|
|
10464
|
+
const contentHash = hashPluginContent(dir, manifest);
|
|
10324
10465
|
const st = state2.plugins.find((p) => p.name === manifest.name);
|
|
10325
|
-
const trusted = st?.trusted === true && st
|
|
10466
|
+
const trusted = st?.trusted === true && effectiveHash(st) === contentHash;
|
|
10326
10467
|
out.push({
|
|
10327
10468
|
name: manifest.name,
|
|
10328
10469
|
dir,
|
|
10329
10470
|
manifestPath,
|
|
10330
10471
|
manifest,
|
|
10331
|
-
hash,
|
|
10472
|
+
hash: contentHash,
|
|
10332
10473
|
enabled: st?.enabled === true,
|
|
10333
10474
|
trusted,
|
|
10334
10475
|
valid: true
|
|
@@ -13607,7 +13748,7 @@ function autoTrimSessionIfNeeded(session, sizeLimit = SESSION_SIZE_LIMIT) {
|
|
|
13607
13748
|
|
|
13608
13749
|
// src/core/context-files.ts
|
|
13609
13750
|
import { existsSync as existsSync26, readFileSync as readFileSync19 } from "fs";
|
|
13610
|
-
import { join as join19, relative as
|
|
13751
|
+
import { join as join19, relative as relative4, resolve as resolve9 } from "path";
|
|
13611
13752
|
function uniqueNonEmpty(values) {
|
|
13612
13753
|
const seen = /* @__PURE__ */ new Set();
|
|
13613
13754
|
const out = [];
|
|
@@ -13623,14 +13764,14 @@ function buildContextFileCandidates(fallbackFilenames = []) {
|
|
|
13623
13764
|
return uniqueNonEmpty([...CONTEXT_FILE_CANDIDATES, ...fallbackFilenames]);
|
|
13624
13765
|
}
|
|
13625
13766
|
function displayPath(filePath, cwd) {
|
|
13626
|
-
const rel =
|
|
13767
|
+
const rel = relative4(cwd, filePath);
|
|
13627
13768
|
if (rel && !rel.startsWith("..") && !rel.startsWith("/") && !rel.startsWith("\\")) {
|
|
13628
13769
|
return rel;
|
|
13629
13770
|
}
|
|
13630
13771
|
return filePath;
|
|
13631
13772
|
}
|
|
13632
13773
|
function isInsideOrEqual(parent, child) {
|
|
13633
|
-
const rel =
|
|
13774
|
+
const rel = relative4(resolve9(parent), resolve9(child));
|
|
13634
13775
|
return rel === "" || !!rel && !rel.startsWith("..") && !rel.startsWith("/") && !rel.startsWith("\\");
|
|
13635
13776
|
}
|
|
13636
13777
|
function readContextFile(level, filePath, cwd, maxBytes) {
|
|
@@ -13763,8 +13904,8 @@ function loadContextFiles(options) {
|
|
|
13763
13904
|
}
|
|
13764
13905
|
|
|
13765
13906
|
// src/web/session-handler.ts
|
|
13766
|
-
import { mkdirSync as
|
|
13767
|
-
import { join as join26, dirname as
|
|
13907
|
+
import { mkdirSync as mkdirSync15, createWriteStream as createWriteStream2 } from "fs";
|
|
13908
|
+
import { join as join26, dirname as dirname10 } from "path";
|
|
13768
13909
|
|
|
13769
13910
|
// src/repl/commands/project-init.ts
|
|
13770
13911
|
import { existsSync as existsSync27, readFileSync as readFileSync20, readdirSync as readdirSync11, statSync as statSync9 } from "fs";
|
|
@@ -15889,7 +16030,7 @@ async function handleSecurityReview(args, ctx) {
|
|
|
15889
16030
|
async function handleTest(args, ctx) {
|
|
15890
16031
|
ctx.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
15891
16032
|
try {
|
|
15892
|
-
const { executeTests } = await import("./run-tests-
|
|
16033
|
+
const { executeTests } = await import("./run-tests-K36VNQ5W.js");
|
|
15893
16034
|
const argStr = args.join(" ").trim();
|
|
15894
16035
|
let testArgs = {};
|
|
15895
16036
|
if (argStr) {
|
|
@@ -17217,7 +17358,7 @@ Try: /compact to reduce context, /clear to reset, or switch to a larger-context
|
|
|
17217
17358
|
this.send({ type: "response_done", content, usage });
|
|
17218
17359
|
if (pendingTeeSave && isCleanDocumentBody(content)) {
|
|
17219
17360
|
try {
|
|
17220
|
-
|
|
17361
|
+
mkdirSync15(dirname10(pendingTeeSave), { recursive: true });
|
|
17221
17362
|
const bodyToSave = stripOuterCodeFence(content);
|
|
17222
17363
|
atomicWriteFileSync(pendingTeeSave, bodyToSave);
|
|
17223
17364
|
undoStack.push(pendingTeeSave, `save_last_response (deferred): ${pendingTeeSave}`);
|
|
@@ -17393,8 +17534,8 @@ ${summaryContent}`,
|
|
|
17393
17534
|
let isError = false;
|
|
17394
17535
|
let summary;
|
|
17395
17536
|
try {
|
|
17396
|
-
|
|
17397
|
-
fileStream =
|
|
17537
|
+
mkdirSync15(dirname10(saveToFile), { recursive: true });
|
|
17538
|
+
fileStream = createWriteStream2(saveToFile);
|
|
17398
17539
|
const teeSystemPrompt = stripToolCallReminder(systemPrompt ?? "") + CONTENT_ONLY_STREAM_REMINDER;
|
|
17399
17540
|
const teeExtraMessages = extraMessages.length > 0 ? [...extraMessages, { role: "user", content: TEE_FINAL_USER_NUDGE }] : [{ role: "user", content: TEE_FINAL_USER_NUDGE }];
|
|
17400
17541
|
const chatRequest = {
|
|
@@ -17968,8 +18109,8 @@ async function setupProxy(configProxy) {
|
|
|
17968
18109
|
}
|
|
17969
18110
|
|
|
17970
18111
|
// src/web/auth.ts
|
|
17971
|
-
import { existsSync as
|
|
17972
|
-
import { isAbsolute as isAbsolute3, join as join27, relative as
|
|
18112
|
+
import { existsSync as existsSync32, readFileSync as readFileSync24, writeFileSync as writeFileSync5, mkdirSync as mkdirSync16, readdirSync as readdirSync15, copyFileSync } from "fs";
|
|
18113
|
+
import { isAbsolute as isAbsolute3, join as join27, relative as relative5 } from "path";
|
|
17973
18114
|
import { createHmac, randomBytes, timingSafeEqual, pbkdf2Sync } from "crypto";
|
|
17974
18115
|
var USERS_FILE = "users.json";
|
|
17975
18116
|
var TOKEN_EXPIRY_HOURS = 24;
|
|
@@ -18015,7 +18156,7 @@ var AuthManager = class {
|
|
|
18015
18156
|
const passwordHash = this.hashPassword(password, salt);
|
|
18016
18157
|
const dataDir = join27(USERS_DIR, username);
|
|
18017
18158
|
const fullDataDir = join27(this.baseDir, dataDir);
|
|
18018
|
-
|
|
18159
|
+
mkdirSync16(join27(fullDataDir, "history"), { recursive: true });
|
|
18019
18160
|
const user = {
|
|
18020
18161
|
username,
|
|
18021
18162
|
passwordHash,
|
|
@@ -18167,25 +18308,25 @@ var AuthManager = class {
|
|
|
18167
18308
|
if (err) return err;
|
|
18168
18309
|
const userDir = this.getUserDataDir(username);
|
|
18169
18310
|
const globalConfig = join27(this.baseDir, "config.json");
|
|
18170
|
-
if (
|
|
18311
|
+
if (existsSync32(globalConfig)) {
|
|
18171
18312
|
try {
|
|
18172
|
-
const content =
|
|
18173
|
-
|
|
18313
|
+
const content = readFileSync24(globalConfig, "utf-8");
|
|
18314
|
+
writeFileSync5(join27(userDir, "config.json"), content, "utf-8");
|
|
18174
18315
|
} catch {
|
|
18175
18316
|
}
|
|
18176
18317
|
}
|
|
18177
18318
|
const globalMemory = join27(this.baseDir, "memory.md");
|
|
18178
|
-
if (
|
|
18319
|
+
if (existsSync32(globalMemory)) {
|
|
18179
18320
|
try {
|
|
18180
|
-
const content =
|
|
18181
|
-
|
|
18321
|
+
const content = readFileSync24(globalMemory, "utf-8");
|
|
18322
|
+
writeFileSync5(join27(userDir, "memory.md"), content, "utf-8");
|
|
18182
18323
|
} catch {
|
|
18183
18324
|
}
|
|
18184
18325
|
}
|
|
18185
18326
|
const globalHistory = join27(this.baseDir, "history");
|
|
18186
|
-
if (
|
|
18327
|
+
if (existsSync32(globalHistory)) {
|
|
18187
18328
|
try {
|
|
18188
|
-
const files =
|
|
18329
|
+
const files = readdirSync15(globalHistory).filter((f) => f.endsWith(".json"));
|
|
18189
18330
|
const userHistory = join27(userDir, "history");
|
|
18190
18331
|
for (const f of files) {
|
|
18191
18332
|
try {
|
|
@@ -18200,9 +18341,9 @@ var AuthManager = class {
|
|
|
18200
18341
|
}
|
|
18201
18342
|
// ── Private methods ────────────────────────────────────────────
|
|
18202
18343
|
loadOrCreate() {
|
|
18203
|
-
if (
|
|
18344
|
+
if (existsSync32(this.usersFile)) {
|
|
18204
18345
|
try {
|
|
18205
|
-
const parsed = JSON.parse(
|
|
18346
|
+
const parsed = JSON.parse(readFileSync24(this.usersFile, "utf-8"));
|
|
18206
18347
|
if (!this.isValidUsersDB(parsed)) {
|
|
18207
18348
|
throw new Error("database structure is invalid");
|
|
18208
18349
|
}
|
|
@@ -18236,7 +18377,7 @@ var AuthManager = class {
|
|
|
18236
18377
|
if (typeof record.username !== "string" || !/^[a-z0-9_-]{2,32}$/.test(record.username) || usernames.has(record.username) || typeof record.passwordHash !== "string" || record.passwordHash.length === 0 || typeof record.salt !== "string" || record.salt.length === 0 || typeof record.createdAt !== "string" || typeof record.dataDir !== "string" || record.dataDir.length === 0 || isAbsolute3(record.dataDir)) {
|
|
18237
18378
|
return false;
|
|
18238
18379
|
}
|
|
18239
|
-
const dataDirFromBase =
|
|
18380
|
+
const dataDirFromBase = relative5(this.baseDir, join27(this.baseDir, record.dataDir));
|
|
18240
18381
|
if (dataDirFromBase.startsWith("..") || isAbsolute3(dataDirFromBase)) return false;
|
|
18241
18382
|
if (record.hashVersion !== void 0 && record.hashVersion !== 1 && record.hashVersion !== 2) return false;
|
|
18242
18383
|
if (record.tokensRevokedBefore !== void 0 && !Number.isFinite(record.tokensRevokedBefore)) return false;
|
|
@@ -18248,7 +18389,7 @@ var AuthManager = class {
|
|
|
18248
18389
|
this.saveDB(this.db);
|
|
18249
18390
|
}
|
|
18250
18391
|
saveDB(db) {
|
|
18251
|
-
|
|
18392
|
+
mkdirSync16(this.baseDir, { recursive: true });
|
|
18252
18393
|
atomicWriteFileSync(this.usersFile, JSON.stringify(db, null, 2));
|
|
18253
18394
|
}
|
|
18254
18395
|
/** Legacy hash — kept only for migrating old users (v0.2.x) */
|
|
@@ -18280,7 +18421,7 @@ function getModuleDir() {
|
|
|
18280
18421
|
if (typeof import.meta?.url === "string") {
|
|
18281
18422
|
const url = new URL(import.meta.url);
|
|
18282
18423
|
const filePath = url.pathname.replace(/^\/([A-Z]:)/i, "$1");
|
|
18283
|
-
return
|
|
18424
|
+
return dirname11(filePath);
|
|
18284
18425
|
}
|
|
18285
18426
|
} catch {
|
|
18286
18427
|
}
|
|
@@ -18353,7 +18494,7 @@ async function startWebServer(options = {}) {
|
|
|
18353
18494
|
}
|
|
18354
18495
|
let skillManager = null;
|
|
18355
18496
|
const skillsDir = join28(config.getConfigDir(), SKILLS_DIR_NAME);
|
|
18356
|
-
if (
|
|
18497
|
+
if (existsSync33(skillsDir)) {
|
|
18357
18498
|
skillManager = new SkillManager(skillsDir, config.get("ui").skillSizeWarn);
|
|
18358
18499
|
skillManager.loadSkills(pluginAssets.skillDirs);
|
|
18359
18500
|
const count = skillManager.listSkills().length;
|
|
@@ -18425,13 +18566,13 @@ async function startWebServer(options = {}) {
|
|
|
18425
18566
|
};
|
|
18426
18567
|
const moduleDir = getModuleDir();
|
|
18427
18568
|
let clientDir = join28(moduleDir, "web", "client");
|
|
18428
|
-
if (!
|
|
18569
|
+
if (!existsSync33(clientDir)) {
|
|
18429
18570
|
clientDir = join28(moduleDir, "client");
|
|
18430
18571
|
}
|
|
18431
|
-
if (!
|
|
18572
|
+
if (!existsSync33(clientDir)) {
|
|
18432
18573
|
clientDir = join28(moduleDir, "..", "..", "src", "web", "client");
|
|
18433
18574
|
}
|
|
18434
|
-
if (!
|
|
18575
|
+
if (!existsSync33(clientDir)) {
|
|
18435
18576
|
clientDir = join28(process.cwd(), "src", "web", "client");
|
|
18436
18577
|
}
|
|
18437
18578
|
console.log(` Static files: ${clientDir}`);
|
|
@@ -18504,9 +18645,9 @@ async function startWebServer(options = {}) {
|
|
|
18504
18645
|
const prefix = req.query.prefix || "";
|
|
18505
18646
|
const targetDir = join28(cwd, prefix);
|
|
18506
18647
|
try {
|
|
18507
|
-
const canonicalTarget =
|
|
18508
|
-
const canonicalCwd =
|
|
18509
|
-
if (!canonicalTarget.startsWith(canonicalCwd +
|
|
18648
|
+
const canonicalTarget = realpathSync3(resolve13(targetDir));
|
|
18649
|
+
const canonicalCwd = realpathSync3(resolve13(cwd));
|
|
18650
|
+
if (!canonicalTarget.startsWith(canonicalCwd + sep4) && canonicalTarget !== canonicalCwd) {
|
|
18510
18651
|
res.json({ files: [] });
|
|
18511
18652
|
return;
|
|
18512
18653
|
}
|
|
@@ -18516,10 +18657,10 @@ async function startWebServer(options = {}) {
|
|
|
18516
18657
|
}
|
|
18517
18658
|
try {
|
|
18518
18659
|
const SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "dist-cjs", "release", "__pycache__", ".next", ".nuxt", "coverage", ".cache"]);
|
|
18519
|
-
const entries =
|
|
18660
|
+
const entries = readdirSync16(targetDir, { withFileTypes: true });
|
|
18520
18661
|
const files = entries.filter((e) => !SKIP.has(e.name) && !e.name.startsWith(".")).slice(0, 50).map((e) => ({
|
|
18521
18662
|
name: e.name,
|
|
18522
|
-
path:
|
|
18663
|
+
path: relative6(cwd, join28(targetDir, e.name)).replace(/\\/g, "/"),
|
|
18523
18664
|
isDir: e.isDirectory()
|
|
18524
18665
|
}));
|
|
18525
18666
|
res.json({ files });
|
|
@@ -18560,14 +18701,14 @@ async function startWebServer(options = {}) {
|
|
|
18560
18701
|
const authUser = req._authUser;
|
|
18561
18702
|
const histDir = authUser ? getUserShared(authUser).config.getHistoryDir() : config.getHistoryDir();
|
|
18562
18703
|
const filePath = join28(histDir, `${id}.json`);
|
|
18563
|
-
if (!
|
|
18704
|
+
if (!existsSync33(filePath)) {
|
|
18564
18705
|
res.status(404).json({ error: "Session not found" });
|
|
18565
18706
|
return;
|
|
18566
18707
|
}
|
|
18567
18708
|
try {
|
|
18568
|
-
const canonicalFile =
|
|
18569
|
-
const canonicalDir =
|
|
18570
|
-
if (!canonicalFile.startsWith(canonicalDir +
|
|
18709
|
+
const canonicalFile = realpathSync3(filePath);
|
|
18710
|
+
const canonicalDir = realpathSync3(histDir);
|
|
18711
|
+
if (!canonicalFile.startsWith(canonicalDir + sep4)) {
|
|
18571
18712
|
res.status(404).json({ error: "Session not found" });
|
|
18572
18713
|
return;
|
|
18573
18714
|
}
|
|
@@ -18575,7 +18716,7 @@ async function startWebServer(options = {}) {
|
|
|
18575
18716
|
res.status(404).json({ error: "Session not found" });
|
|
18576
18717
|
return;
|
|
18577
18718
|
}
|
|
18578
|
-
const data = JSON.parse(
|
|
18719
|
+
const data = JSON.parse(readFileSync25(filePath, "utf-8"));
|
|
18579
18720
|
res.json({ session: data });
|
|
18580
18721
|
} catch (err) {
|
|
18581
18722
|
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
@@ -18590,9 +18731,9 @@ async function startWebServer(options = {}) {
|
|
|
18590
18731
|
const cwd = process.cwd();
|
|
18591
18732
|
const fullPath = resolve13(join28(cwd, filePath));
|
|
18592
18733
|
try {
|
|
18593
|
-
const canonicalFull =
|
|
18594
|
-
const canonicalCwd =
|
|
18595
|
-
if (!canonicalFull.startsWith(canonicalCwd +
|
|
18734
|
+
const canonicalFull = realpathSync3(fullPath);
|
|
18735
|
+
const canonicalCwd = realpathSync3(resolve13(cwd));
|
|
18736
|
+
if (!canonicalFull.startsWith(canonicalCwd + sep4) && canonicalFull !== canonicalCwd) {
|
|
18596
18737
|
res.json({ error: "Access denied" });
|
|
18597
18738
|
return;
|
|
18598
18739
|
}
|
|
@@ -18601,12 +18742,12 @@ async function startWebServer(options = {}) {
|
|
|
18601
18742
|
return;
|
|
18602
18743
|
}
|
|
18603
18744
|
try {
|
|
18604
|
-
const stat =
|
|
18745
|
+
const stat = statSync14(fullPath);
|
|
18605
18746
|
if (stat.size > 512 * 1024) {
|
|
18606
18747
|
res.json({ error: `File too large (${(stat.size / 1024).toFixed(0)} KB, max 512 KB)` });
|
|
18607
18748
|
return;
|
|
18608
18749
|
}
|
|
18609
|
-
const content =
|
|
18750
|
+
const content = readFileSync25(fullPath, "utf-8");
|
|
18610
18751
|
res.json({ content, size: stat.size });
|
|
18611
18752
|
} catch {
|
|
18612
18753
|
res.json({ error: "Cannot read file" });
|
|
@@ -18862,16 +19003,16 @@ function resolveProjectMcpPath() {
|
|
|
18862
19003
|
const gitRoot = getGitRoot(cwd);
|
|
18863
19004
|
const projectRoot = gitRoot ?? cwd;
|
|
18864
19005
|
const configPath = join28(projectRoot, MCP_PROJECT_CONFIG_NAME);
|
|
18865
|
-
return
|
|
19006
|
+
return existsSync33(configPath) ? configPath : null;
|
|
18866
19007
|
}
|
|
18867
19008
|
function loadProjectMcpConfig() {
|
|
18868
19009
|
const cwd = process.cwd();
|
|
18869
19010
|
const gitRoot = getGitRoot(cwd);
|
|
18870
19011
|
const projectRoot = gitRoot ?? cwd;
|
|
18871
19012
|
const configPath = join28(projectRoot, MCP_PROJECT_CONFIG_NAME);
|
|
18872
|
-
if (!
|
|
19013
|
+
if (!existsSync33(configPath)) return null;
|
|
18873
19014
|
try {
|
|
18874
|
-
const raw = JSON.parse(
|
|
19015
|
+
const raw = JSON.parse(readFileSync25(configPath, "utf-8"));
|
|
18875
19016
|
return raw.mcpServers ?? raw;
|
|
18876
19017
|
} catch {
|
|
18877
19018
|
return null;
|
|
@@ -154,7 +154,7 @@ ${content}`);
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
async function runTaskMode(config, providers, configManager, topic) {
|
|
157
|
-
const { TaskOrchestrator } = await import("./task-orchestrator-
|
|
157
|
+
const { TaskOrchestrator } = await import("./task-orchestrator-D66BJZKU.js");
|
|
158
158
|
const orchestrator = new TaskOrchestrator(config, providers, configManager);
|
|
159
159
|
let interrupted = false;
|
|
160
160
|
const onSigint = () => {
|