engine7 7.1.118 → 7.1.120
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/cli.mjs +1054 -891
- package/dist/engine-startup.mjs +394 -275
- package/dist/main.mjs +394 -275
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -395,6 +395,17 @@ var init_live = __esm({
|
|
|
395
395
|
Object.assign(this.current, newConfig);
|
|
396
396
|
}
|
|
397
397
|
/** 改活树上的值;文件承载路径同步持久化(read-modify-write 回 config 文件) */
|
|
398
|
+
/**
|
|
399
|
+
* 改活树 + 落盘。
|
|
400
|
+
*
|
|
401
|
+
* 返回值 = **落盘**是否成功(活树无论成败都已同步——它是先改的)。绝大多数调用点照旧
|
|
402
|
+
* `void liveConfig.set(...)` 不理它;但**要打成功日志的调用点必须 await 这个布尔值**。
|
|
403
|
+
*
|
|
404
|
+
* 为什么把这个信号交出去(1001 审查捞回):本方法本来是 fire-and-forget,落盘失败只在
|
|
405
|
+
* `persistToFile` 里 warn 一行;而启动早段的调用点(两个免费档 fixup)紧接着打了句
|
|
406
|
+
* "免费档补齐 xxx" 的成功日志 ⇒ 配置**没写进文件**却被读成"写好了":进程内生效、托盘
|
|
407
|
+
* 读文件还是旧值、下次启动重放同一句——正是本仓最恨的假信号。
|
|
408
|
+
*/
|
|
398
409
|
async set(dotPath, val) {
|
|
399
410
|
if (!this.current) throw new Error("[liveConfig] not initialized \u2014 call liveConfig.init() first");
|
|
400
411
|
const keys = dotPath.split(".");
|
|
@@ -404,18 +415,18 @@ var init_live = __esm({
|
|
|
404
415
|
obj = obj[keys[i]];
|
|
405
416
|
}
|
|
406
417
|
obj[keys[keys.length - 1]] = val;
|
|
407
|
-
|
|
418
|
+
return this.persistToFile(dotPath, val);
|
|
408
419
|
}
|
|
409
|
-
/** 把改动写回 config
|
|
420
|
+
/** 把改动写回 config 文件对应段(找不到文件路径则只内存生效)。返回是否真的落盘。 */
|
|
410
421
|
async persistToFile(dotPath, val) {
|
|
411
|
-
const
|
|
422
|
+
const fs44 = await import("node:fs");
|
|
412
423
|
const cfgPath = this.current?._configFilePath;
|
|
413
|
-
if (!cfgPath || !
|
|
424
|
+
if (!cfgPath || !fs44.existsSync(cfgPath)) {
|
|
414
425
|
console.warn(`[liveConfig] set: no config file path, in-memory only (${dotPath})`);
|
|
415
|
-
return;
|
|
426
|
+
return false;
|
|
416
427
|
}
|
|
417
428
|
try {
|
|
418
|
-
const raw = JSON.parse(
|
|
429
|
+
const raw = JSON.parse(fs44.readFileSync(cfgPath, "utf-8"));
|
|
419
430
|
const keys = dotPath.split(".");
|
|
420
431
|
let o = raw;
|
|
421
432
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
@@ -423,11 +434,13 @@ var init_live = __esm({
|
|
|
423
434
|
o = o[keys[i]];
|
|
424
435
|
}
|
|
425
436
|
o[keys[keys.length - 1]] = val;
|
|
426
|
-
|
|
437
|
+
fs44.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
|
|
427
438
|
console.log(`[liveConfig] persisted ${dotPath} = ${JSON.stringify(val)} to ${cfgPath}`);
|
|
428
439
|
markSelfWrite();
|
|
440
|
+
return true;
|
|
429
441
|
} catch (e) {
|
|
430
442
|
console.warn(`[liveConfig] persist failed (${dotPath}): ${e.message}`);
|
|
443
|
+
return false;
|
|
431
444
|
}
|
|
432
445
|
}
|
|
433
446
|
/** 是否已初始化 */
|
|
@@ -714,8 +727,8 @@ function listSchemaFields() {
|
|
|
714
727
|
if (process.env.ENGINE7_INTERNAL === "1") return FIELDS.slice();
|
|
715
728
|
return FIELDS.filter((f) => !f.internal);
|
|
716
729
|
}
|
|
717
|
-
function getField(
|
|
718
|
-
return FIELDS.find((f) => f.path ===
|
|
730
|
+
function getField(path44) {
|
|
731
|
+
return FIELDS.find((f) => f.path === path44);
|
|
719
732
|
}
|
|
720
733
|
function pick(obj, dotPath) {
|
|
721
734
|
let cur = obj;
|
|
@@ -1549,6 +1562,16 @@ function secretRef(envKey, value) {
|
|
|
1549
1562
|
function isFreeTier(v) {
|
|
1550
1563
|
return v.freeTier === true || v.primaryProvider === "7yi";
|
|
1551
1564
|
}
|
|
1565
|
+
function freeTierVoiceConfig(existing) {
|
|
1566
|
+
const mv = existing && typeof existing === "object" ? existing : {};
|
|
1567
|
+
return {
|
|
1568
|
+
...mv,
|
|
1569
|
+
provider: "relay",
|
|
1570
|
+
relayProviderId: FREE_TIER_PROVIDER_ID,
|
|
1571
|
+
relayModel: "engine7-tts",
|
|
1572
|
+
voice: mv.voice || DEFAULT_FREE_VOICE
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1552
1575
|
function resolveRelayUrl(relayArg, env = process.env) {
|
|
1553
1576
|
return (relayArg || "").trim() || (env.E7_RELAY_URL || "").trim() || FREE_TIER_RELAY_URL;
|
|
1554
1577
|
}
|
|
@@ -1612,9 +1635,21 @@ function generateConfig(v) {
|
|
|
1612
1635
|
},
|
|
1613
1636
|
// 0917:my_eyes(看图工具)读的是 tools.my_eyes.model,不是 tools.vision——
|
|
1614
1637
|
// 后者是模板里遗留的死键(全仓零读者),已删。visionModel 解析不出就不写这个块。
|
|
1638
|
+
//
|
|
1639
|
+
// 1001 发语音条(§7.4):免费档必须把这块写全。此前唯一会写 `tools.my_voice` 的是
|
|
1640
|
+
// `applyFreeTier`,而它只从「切换到免费档」那张卡触发——配置已经是免费档时卡片不显示
|
|
1641
|
+
// ⇒ **新装机永远没有这块**:托盘「合成引擎」显示 edge-tts(面板在 provider 缺失时
|
|
1642
|
+
// 默认选它),引擎 `pickProvider` 也落 edge,而 edge 要本机 Python + `edge_tts`
|
|
1643
|
+
// (安装包一个都不带)⇒ 用户第一次说"发条语音"就报错。郭叔 1001 装机实测撞到。
|
|
1644
|
+
// 形状走 `freeTierVoiceConfig()`(唯一源,与 applyFreeTier / 启动补齐同一份)。
|
|
1615
1645
|
tools: {
|
|
1616
1646
|
...v.tavilyKey ? { tavily: { apiKey: v.tavilyKey } } : {},
|
|
1617
1647
|
...v.visionModel ? { my_eyes: { model: v.visionModel } } : {},
|
|
1648
|
+
// ⚠️ 判据是 **provider 真的是 7yi**,不是 `isFreeTier(v)`:后者会因 `freeTier:true`
|
|
1649
|
+
// 单独为真(answers 手写坏组合时),而那种 config 里**根本没有 7yi provider 块**,
|
|
1650
|
+
// 写进去就是个悬空引用(第一次发语音报"免费池未配置",把用户指向错误的排查方向)。
|
|
1651
|
+
// 与下面 vision/video 的收口闸同一条纪律:**引用必须落在本次真实写出的 provider 里**。
|
|
1652
|
+
...v.primaryProvider === FREE_TIER_PROVIDER_ID ? { my_voice: freeTierVoiceConfig() } : {},
|
|
1618
1653
|
// 自拍(§4.3):免费档必须显式写 provider:'relay'。不写的话 getProvider()
|
|
1619
1654
|
// 会落回默认值 'fal',而免费装机没有 fal key——第一次自拍就失败。
|
|
1620
1655
|
// 非免费档只在用户真给了形象时才写这个块,且不替他决定 provider。
|
|
@@ -1837,13 +1872,15 @@ function generateConfig(v) {
|
|
|
1837
1872
|
}
|
|
1838
1873
|
return config;
|
|
1839
1874
|
}
|
|
1840
|
-
var SCHEMA_VERSION, FREE_TIER_RELAY_URL, DEFAULT_PRIMARY_MODEL, VISION_CAPABLE, PROVIDER_DEFS, MODEL_CHOICES, CUSTOM_DEFAULT_INPUT, TEMPLATE_VALUES;
|
|
1875
|
+
var SCHEMA_VERSION, FREE_TIER_RELAY_URL, FREE_TIER_PROVIDER_ID, DEFAULT_FREE_VOICE, DEFAULT_PRIMARY_MODEL, VISION_CAPABLE, PROVIDER_DEFS, MODEL_CHOICES, CUSTOM_DEFAULT_INPUT, TEMPLATE_VALUES;
|
|
1841
1876
|
var init_cli_init_config = __esm({
|
|
1842
1877
|
"src/cli-init-config.ts"() {
|
|
1843
1878
|
"use strict";
|
|
1844
1879
|
init_registry();
|
|
1845
1880
|
SCHEMA_VERSION = 1;
|
|
1846
1881
|
FREE_TIER_RELAY_URL = "https://www.twinsun.top:8866";
|
|
1882
|
+
FREE_TIER_PROVIDER_ID = "7yi";
|
|
1883
|
+
DEFAULT_FREE_VOICE = "Chinese (Mandarin)_Warm_Girl";
|
|
1847
1884
|
DEFAULT_PRIMARY_MODEL = {
|
|
1848
1885
|
dashscope: "dashscope/qwen3.8-max",
|
|
1849
1886
|
minimax: "minimax/MiniMax-M3",
|
|
@@ -2073,6 +2110,19 @@ function resolveConfigIdentity(configPath) {
|
|
|
2073
2110
|
const stateDir = basename2(cfgDir) === "configs" ? dirname2(cfgDir) : cfgDir;
|
|
2074
2111
|
return { stateDir, configName: cfgName };
|
|
2075
2112
|
}
|
|
2113
|
+
function engineStateDirOfConfig(configPath, env = process.env) {
|
|
2114
|
+
let raw;
|
|
2115
|
+
try {
|
|
2116
|
+
raw = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
2117
|
+
} catch {
|
|
2118
|
+
return null;
|
|
2119
|
+
}
|
|
2120
|
+
if (typeof raw?.stateDir === "string" && raw.stateDir.trim()) return raw.stateDir.trim();
|
|
2121
|
+
const fromEnv = env.ENGINE_STATE_DIR;
|
|
2122
|
+
if (fromEnv && fromEnv.trim()) return fromEnv.trim();
|
|
2123
|
+
if (basename2(dirname2(configPath)) !== "configs") return null;
|
|
2124
|
+
return resolveConfigIdentity(configPath).stateDir;
|
|
2125
|
+
}
|
|
2076
2126
|
function writeSecretsValue(configPath, envKey, value) {
|
|
2077
2127
|
const { stateDir, configName } = resolveConfigIdentity(configPath);
|
|
2078
2128
|
const dir = join3(secretsHome(), ".engine7-secrets");
|
|
@@ -2191,8 +2241,8 @@ __export(loader_exports, {
|
|
|
2191
2241
|
resolveTimezone: () => resolveTimezone,
|
|
2192
2242
|
takeLoadWarnings: () => takeLoadWarnings
|
|
2193
2243
|
});
|
|
2194
|
-
import * as
|
|
2195
|
-
import * as
|
|
2244
|
+
import * as fs4 from "node:fs";
|
|
2245
|
+
import * as path4 from "node:path";
|
|
2196
2246
|
function parseModelRef(ref) {
|
|
2197
2247
|
const idx = ref.indexOf("/");
|
|
2198
2248
|
if (idx <= 0 || idx === ref.length - 1) {
|
|
@@ -2232,13 +2282,13 @@ function isUnresolvedEnvRef(value) {
|
|
|
2232
2282
|
return typeof value === "string" && ENV_REF_RE.test(value);
|
|
2233
2283
|
}
|
|
2234
2284
|
function loadConfig(configPath) {
|
|
2235
|
-
const resolvedPath =
|
|
2285
|
+
const resolvedPath = path4.resolve(
|
|
2236
2286
|
configPath || process.env.ENGINE_CONFIG || "engine-config.json"
|
|
2237
2287
|
);
|
|
2238
|
-
if (!
|
|
2288
|
+
if (!fs4.existsSync(resolvedPath)) {
|
|
2239
2289
|
throw new Error(`Config file not found: ${resolvedPath}`);
|
|
2240
2290
|
}
|
|
2241
|
-
const raw = JSON.parse(
|
|
2291
|
+
const raw = JSON.parse(fs4.readFileSync(resolvedPath, "utf-8"));
|
|
2242
2292
|
const missingEnvKeys = /* @__PURE__ */ new Set();
|
|
2243
2293
|
const resolveEnv = (node) => {
|
|
2244
2294
|
if (typeof node === "string") {
|
|
@@ -2341,9 +2391,9 @@ function loadConfig(configPath) {
|
|
|
2341
2391
|
}
|
|
2342
2392
|
}
|
|
2343
2393
|
}
|
|
2344
|
-
const stateDir = raw.stateDir || process.env.ENGINE_STATE_DIR ||
|
|
2345
|
-
const workspace = process.env.ENGINE_WORKSPACE || agentDefaults.workspace ||
|
|
2346
|
-
const mediaDir = raw.mediaDir ||
|
|
2394
|
+
const stateDir = raw.stateDir || process.env.ENGINE_STATE_DIR || path4.resolve(".engine");
|
|
2395
|
+
const workspace = process.env.ENGINE_WORKSPACE || agentDefaults.workspace || path4.join(stateDir, "workspace");
|
|
2396
|
+
const mediaDir = raw.mediaDir || path4.join(stateDir, "media", "inbound");
|
|
2347
2397
|
if (!agentDefaults.features) agentDefaults.features = {};
|
|
2348
2398
|
for (const [k, v] of Object.entries(FEATURE_DEFAULTS)) {
|
|
2349
2399
|
if (agentDefaults.features[k] === void 0) {
|
|
@@ -2615,17 +2665,17 @@ var init_registry2 = __esm({
|
|
|
2615
2665
|
});
|
|
2616
2666
|
|
|
2617
2667
|
// src/calendar/db.ts
|
|
2618
|
-
import * as
|
|
2619
|
-
import * as
|
|
2668
|
+
import * as path5 from "node:path";
|
|
2669
|
+
import * as fs5 from "node:fs";
|
|
2620
2670
|
import { createRequire as createRequire2 } from "node:module";
|
|
2621
2671
|
function getSqlite() {
|
|
2622
2672
|
if (!_sqlite) _sqlite = createRequire2(import.meta.url)("node:sqlite");
|
|
2623
2673
|
return _sqlite;
|
|
2624
2674
|
}
|
|
2625
2675
|
function openDb(workspace) {
|
|
2626
|
-
const dir =
|
|
2627
|
-
|
|
2628
|
-
const dbPath =
|
|
2676
|
+
const dir = path5.join(workspace, ".calendar");
|
|
2677
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
2678
|
+
const dbPath = path5.join(dir, "calendar.db");
|
|
2629
2679
|
const db2 = new DatabaseSync(dbPath);
|
|
2630
2680
|
db2.exec("PRAGMA journal_mode=WAL");
|
|
2631
2681
|
db2.exec(`CREATE TABLE IF NOT EXISTS events (
|
|
@@ -2699,14 +2749,14 @@ var init_db = __esm({
|
|
|
2699
2749
|
});
|
|
2700
2750
|
|
|
2701
2751
|
// src/goals/store.ts
|
|
2702
|
-
import
|
|
2703
|
-
import
|
|
2752
|
+
import fs6 from "node:fs";
|
|
2753
|
+
import path6 from "node:path";
|
|
2704
2754
|
import crypto from "node:crypto";
|
|
2705
2755
|
function file(stateDir) {
|
|
2706
|
-
return
|
|
2756
|
+
return path6.join(stateDir, "goals.json");
|
|
2707
2757
|
}
|
|
2708
2758
|
function eventFile(stateDir) {
|
|
2709
|
-
return
|
|
2759
|
+
return path6.join(stateDir, "goal-events.jsonl");
|
|
2710
2760
|
}
|
|
2711
2761
|
function db(stateDir) {
|
|
2712
2762
|
const d = openDb(stateDir);
|
|
@@ -2723,17 +2773,17 @@ function db(stateDir) {
|
|
|
2723
2773
|
return d;
|
|
2724
2774
|
}
|
|
2725
2775
|
function event(stateDir, goalId, type2, payload = {}) {
|
|
2726
|
-
|
|
2776
|
+
fs6.mkdirSync(stateDir, { recursive: true });
|
|
2727
2777
|
const id = `ge-${Date.now()}-${crypto.randomBytes(3).toString("hex")}`;
|
|
2728
2778
|
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
2729
|
-
|
|
2779
|
+
fs6.appendFileSync(eventFile(stateDir), JSON.stringify({ eventId: id, goalId, type: type2, at, ...payload }) + "\n", "utf8");
|
|
2730
2780
|
const d = db(stateDir);
|
|
2731
2781
|
d.prepare("INSERT INTO goal_events (event_id, goal_id, type, payload_json, created_at) VALUES (?, ?, ?, ?, ?)").run(id, goalId, type2, JSON.stringify(payload), at);
|
|
2732
2782
|
d.close?.();
|
|
2733
2783
|
}
|
|
2734
2784
|
function read(stateDir) {
|
|
2735
2785
|
try {
|
|
2736
|
-
const v = JSON.parse(
|
|
2786
|
+
const v = JSON.parse(fs6.readFileSync(file(stateDir), "utf8"));
|
|
2737
2787
|
return Array.isArray(v) ? v : [];
|
|
2738
2788
|
} catch {
|
|
2739
2789
|
return [];
|
|
@@ -2756,7 +2806,7 @@ function listGoals(stateDir) {
|
|
|
2756
2806
|
}
|
|
2757
2807
|
function listGoalEvents(stateDir) {
|
|
2758
2808
|
try {
|
|
2759
|
-
return
|
|
2809
|
+
return fs6.readFileSync(eventFile(stateDir), "utf8").split(/\r?\n/).filter(Boolean).map((line) => JSON.parse(line));
|
|
2760
2810
|
} catch {
|
|
2761
2811
|
return [];
|
|
2762
2812
|
}
|
|
@@ -2826,9 +2876,9 @@ function isAutoMemPath(absolutePath, workspace) {
|
|
|
2826
2876
|
return normalizedPath.startsWith(getAutoMemPath(workspace));
|
|
2827
2877
|
}
|
|
2828
2878
|
async function ensureMemoryDirExists(memoryDir) {
|
|
2829
|
-
const
|
|
2879
|
+
const fs44 = await import("node:fs");
|
|
2830
2880
|
try {
|
|
2831
|
-
await
|
|
2881
|
+
await fs44.promises.mkdir(memoryDir, { recursive: true });
|
|
2832
2882
|
} catch (e) {
|
|
2833
2883
|
const code = e?.code;
|
|
2834
2884
|
if (code !== "EEXIST") {
|
|
@@ -3159,13 +3209,13 @@ __export(prompt_exports, {
|
|
|
3159
3209
|
buildSystemPrompt: () => buildSystemPrompt,
|
|
3160
3210
|
buildVolatileRuntimeContext: () => buildVolatileRuntimeContext
|
|
3161
3211
|
});
|
|
3162
|
-
import * as
|
|
3163
|
-
import * as
|
|
3212
|
+
import * as path7 from "node:path";
|
|
3213
|
+
import * as fs7 from "node:fs";
|
|
3164
3214
|
import * as os2 from "node:os";
|
|
3165
3215
|
function readFileIfExists(filePath) {
|
|
3166
3216
|
try {
|
|
3167
|
-
if (
|
|
3168
|
-
return
|
|
3217
|
+
if (fs7.existsSync(filePath)) {
|
|
3218
|
+
return fs7.readFileSync(filePath, "utf-8");
|
|
3169
3219
|
}
|
|
3170
3220
|
} catch {
|
|
3171
3221
|
}
|
|
@@ -3324,7 +3374,7 @@ function loadStaticFiles(workspace, staticFiles) {
|
|
|
3324
3374
|
if (!staticFiles || staticFiles.length === 0) return null;
|
|
3325
3375
|
const parts = [];
|
|
3326
3376
|
for (const file2 of staticFiles) {
|
|
3327
|
-
const filePath =
|
|
3377
|
+
const filePath = path7.isAbsolute(file2) ? file2 : path7.join(workspace, file2);
|
|
3328
3378
|
const content = readFileIfExists(filePath);
|
|
3329
3379
|
if (content) parts.push(content);
|
|
3330
3380
|
}
|
|
@@ -3343,7 +3393,7 @@ function loadMemoryInstructions(workspace) {
|
|
|
3343
3393
|
}
|
|
3344
3394
|
}
|
|
3345
3395
|
function resolveBlockContent(block, ctx) {
|
|
3346
|
-
const overridePath =
|
|
3396
|
+
const overridePath = path7.join(ctx.workspace, "prompts", `${block.name}.md`);
|
|
3347
3397
|
const override = readFileIfExists(overridePath);
|
|
3348
3398
|
if (override) return override;
|
|
3349
3399
|
return block.generate(ctx);
|
|
@@ -3392,7 +3442,7 @@ function buildCustomPrompt(workspace, config) {
|
|
|
3392
3442
|
continue;
|
|
3393
3443
|
}
|
|
3394
3444
|
if (name.endsWith(".md")) {
|
|
3395
|
-
const filePath =
|
|
3445
|
+
const filePath = path7.isAbsolute(name) ? name : path7.join(workspace, name);
|
|
3396
3446
|
const content = readFileIfExists(filePath);
|
|
3397
3447
|
if (content) {
|
|
3398
3448
|
parts.push(content);
|
|
@@ -3508,7 +3558,7 @@ var init_prompt = __esm({
|
|
|
3508
3558
|
{ name: "tone-style", description: "\u8BED\u6C14\u98CE\u683C\uFF08\u7B80\u6D01\u3001\u4E0D\u7528emoji\uFF09", generate: (_) => getToneAndStyleSection() },
|
|
3509
3559
|
{ name: "output-efficiency", description: "\u8F93\u51FA\u6548\u7387\uFF08\u76F4\u5954\u4E3B\u9898\uFF09", generate: (_) => getOutputEfficiencySection() },
|
|
3510
3560
|
// OpenClaw 叠加层
|
|
3511
|
-
{ name: "soul", description: "SOUL.md \u4EBA\u683C\u8EAB\u4EFD", generate: (ctx) => readFileIfExists(
|
|
3561
|
+
{ name: "soul", description: "SOUL.md \u4EBA\u683C\u8EAB\u4EFD", generate: (ctx) => readFileIfExists(path7.join(ctx.workspace, "SOUL.md")) },
|
|
3512
3562
|
{ name: "static-files", description: "\u914D\u7F6E\u6587\u4EF6\u6307\u5B9A\u7684\u989D\u5916\u6587\u4EF6\uFF08AGENTS/USER/MEMORY\u7B49\uFF09", generate: (ctx) => loadStaticFiles(ctx.workspace, ctx.staticFiles) },
|
|
3513
3563
|
{ name: "auto-memory-instructions", description: "auto memory \u5B8C\u6574\u6307\u4EE4\uFF08\u5B58+\u8BFB+recall\u8BF4\u660E\uFF09", generate: (ctx) => loadMemoryInstructions(ctx.workspace) },
|
|
3514
3564
|
// Boundary(永远在最后)
|
|
@@ -6462,8 +6512,8 @@ var init_attachments = __esm({
|
|
|
6462
6512
|
});
|
|
6463
6513
|
|
|
6464
6514
|
// src/utils/context-dump.ts
|
|
6465
|
-
import * as
|
|
6466
|
-
import * as
|
|
6515
|
+
import * as fs8 from "node:fs";
|
|
6516
|
+
import * as path8 from "node:path";
|
|
6467
6517
|
function dumpApiRequest(opts) {
|
|
6468
6518
|
const lines = [
|
|
6469
6519
|
"=== API Request Debug\uFF08\u53D1\u7ED9 LLM \u7684\u6700\u7EC8\u8BF7\u6C42\u4F53\uFF0C\u6BCF\u6B21\u8986\u76D6\u5199\uFF09===",
|
|
@@ -6496,7 +6546,7 @@ function dumpApiRequest(opts) {
|
|
|
6496
6546
|
lines.push(`[${i}] ${m.role}: (empty)`);
|
|
6497
6547
|
}
|
|
6498
6548
|
}
|
|
6499
|
-
|
|
6549
|
+
fs8.writeFileSync(path8.join(opts.workspace, ".context-debug.txt"), lines.join("\n") + "\n", "utf-8");
|
|
6500
6550
|
}
|
|
6501
6551
|
var init_context_dump = __esm({
|
|
6502
6552
|
"src/utils/context-dump.ts"() {
|
|
@@ -7556,7 +7606,7 @@ var init_contextOverflow = __esm({
|
|
|
7556
7606
|
});
|
|
7557
7607
|
|
|
7558
7608
|
// src/utils/path.ts
|
|
7559
|
-
import * as
|
|
7609
|
+
import * as path9 from "node:path";
|
|
7560
7610
|
function fixMsysPath(p) {
|
|
7561
7611
|
let fixed = p.includes("\\") ? p.replace(/\\/g, "/") : p;
|
|
7562
7612
|
if (process.platform === "win32") {
|
|
@@ -7566,15 +7616,15 @@ function fixMsysPath(p) {
|
|
|
7566
7616
|
}
|
|
7567
7617
|
function resolvePath(p, workspace) {
|
|
7568
7618
|
const fixed = fixMsysPath(p);
|
|
7569
|
-
const resolved =
|
|
7570
|
-
const normalized =
|
|
7571
|
-
const normalizedWorkspace =
|
|
7619
|
+
const resolved = path9.isAbsolute(fixed) ? path9.normalize(fixed) : path9.resolve(workspace, fixed);
|
|
7620
|
+
const normalized = path9.normalize(resolved);
|
|
7621
|
+
const normalizedWorkspace = path9.normalize(workspace);
|
|
7572
7622
|
if (sandboxOff) return normalized;
|
|
7573
|
-
if (normalized === normalizedWorkspace || normalized.startsWith(normalizedWorkspace +
|
|
7623
|
+
if (normalized === normalizedWorkspace || normalized.startsWith(normalizedWorkspace + path9.sep)) {
|
|
7574
7624
|
return normalized;
|
|
7575
7625
|
}
|
|
7576
7626
|
for (const allowed of extraAllowedPaths) {
|
|
7577
|
-
if (normalized === allowed || normalized.startsWith(allowed +
|
|
7627
|
+
if (normalized === allowed || normalized.startsWith(allowed + path9.sep)) {
|
|
7578
7628
|
return normalized;
|
|
7579
7629
|
}
|
|
7580
7630
|
}
|
|
@@ -7809,9 +7859,9 @@ __export(BashTool_exports, {
|
|
|
7809
7859
|
findShell: () => findShell,
|
|
7810
7860
|
killChild: () => killChild
|
|
7811
7861
|
});
|
|
7812
|
-
import { spawn as spawn2, execSync } from "node:child_process";
|
|
7813
|
-
import * as
|
|
7814
|
-
import * as
|
|
7862
|
+
import { spawn as spawn2, execSync as execSync2 } from "node:child_process";
|
|
7863
|
+
import * as fs9 from "node:fs";
|
|
7864
|
+
import * as path10 from "node:path";
|
|
7815
7865
|
function isWslBash(p) {
|
|
7816
7866
|
const normalized = p.replace(/\//g, "\\").toLowerCase();
|
|
7817
7867
|
return WSL_PATH_MARKERS.some((m) => normalized.includes(m.toLowerCase()));
|
|
@@ -7823,14 +7873,14 @@ function findShell() {
|
|
|
7823
7873
|
return cachedShell;
|
|
7824
7874
|
}
|
|
7825
7875
|
try {
|
|
7826
|
-
const result =
|
|
7876
|
+
const result = execSync2("where.exe bash", {
|
|
7827
7877
|
encoding: "utf-8",
|
|
7828
7878
|
timeout: 5e3,
|
|
7829
7879
|
stdio: ["ignore", "pipe", "ignore"]
|
|
7830
7880
|
});
|
|
7831
7881
|
const candidates = result.trim().split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
7832
7882
|
const nonWsl = candidates.find((p) => !isWslBash(p));
|
|
7833
|
-
if (nonWsl &&
|
|
7883
|
+
if (nonWsl && fs9.existsSync(nonWsl)) {
|
|
7834
7884
|
cachedShell = { shell: nonWsl, args: ["-c"] };
|
|
7835
7885
|
return cachedShell;
|
|
7836
7886
|
}
|
|
@@ -7840,10 +7890,10 @@ function findShell() {
|
|
|
7840
7890
|
"C:\\Program Files\\Git\\bin\\bash.exe",
|
|
7841
7891
|
"C:\\Program Files (x86)\\Git\\bin\\bash.exe",
|
|
7842
7892
|
"C:\\Program Files\\Git\\usr\\bin\\bash.exe",
|
|
7843
|
-
|
|
7893
|
+
path10.join(process.env.LOCALAPPDATA || "", "Programs", "Git", "bin", "bash.exe")
|
|
7844
7894
|
];
|
|
7845
7895
|
for (const p of knownPaths) {
|
|
7846
|
-
if (p &&
|
|
7896
|
+
if (p && fs9.existsSync(p)) {
|
|
7847
7897
|
cachedShell = { shell: p, args: ["-c"] };
|
|
7848
7898
|
return cachedShell;
|
|
7849
7899
|
}
|
|
@@ -7946,8 +7996,8 @@ For commands that are harder to parse at a glance (piped commands, obscure flags
|
|
|
7946
7996
|
}
|
|
7947
7997
|
const MAX_OUTPUT = 100 * 1024;
|
|
7948
7998
|
const osMod = await import("node:os");
|
|
7949
|
-
const outputFile =
|
|
7950
|
-
const outputHandle = await
|
|
7999
|
+
const outputFile = path10.join(osMod.tmpdir(), `exec-${Date.now()}-${Math.random().toString(36).slice(2)}.out`);
|
|
8000
|
+
const outputHandle = await fs9.promises.open(outputFile, "w");
|
|
7951
8001
|
return new Promise((resolve12) => {
|
|
7952
8002
|
const { shell, args: shellArgs } = findShell();
|
|
7953
8003
|
const child = spawn2(shell, [...shellArgs, command], {
|
|
@@ -7966,21 +8016,21 @@ For commands that are harder to parse at a glance (piped commands, obscure flags
|
|
|
7966
8016
|
let fileOutput = "";
|
|
7967
8017
|
let truncated = false;
|
|
7968
8018
|
try {
|
|
7969
|
-
const st = await
|
|
8019
|
+
const st = await fs9.promises.stat(outputFile);
|
|
7970
8020
|
if (st.size > MAX_OUTPUT) {
|
|
7971
|
-
const rfd = await
|
|
8021
|
+
const rfd = await fs9.promises.open(outputFile, "r");
|
|
7972
8022
|
const buf = Buffer.alloc(MAX_OUTPUT);
|
|
7973
8023
|
await rfd.read(buf, 0, MAX_OUTPUT, 0);
|
|
7974
8024
|
await rfd.close();
|
|
7975
8025
|
fileOutput = buf.toString("utf-8");
|
|
7976
8026
|
truncated = true;
|
|
7977
8027
|
} else {
|
|
7978
|
-
fileOutput = await
|
|
8028
|
+
fileOutput = await fs9.promises.readFile(outputFile, "utf-8");
|
|
7979
8029
|
}
|
|
7980
8030
|
} catch {
|
|
7981
8031
|
}
|
|
7982
8032
|
try {
|
|
7983
|
-
await
|
|
8033
|
+
await fs9.promises.unlink(outputFile);
|
|
7984
8034
|
} catch {
|
|
7985
8035
|
}
|
|
7986
8036
|
const processedStdout = fileOutput.replace(/^(\s*\n)+/, "").trimEnd();
|
|
@@ -8057,8 +8107,8 @@ __export(task_manager_exports, {
|
|
|
8057
8107
|
});
|
|
8058
8108
|
import { randomBytes } from "node:crypto";
|
|
8059
8109
|
import { spawn as spawn3 } from "node:child_process";
|
|
8060
|
-
import * as
|
|
8061
|
-
import * as
|
|
8110
|
+
import * as fs10 from "node:fs";
|
|
8111
|
+
import * as path11 from "node:path";
|
|
8062
8112
|
function generateTaskId(type2 = "local_bash") {
|
|
8063
8113
|
const prefix = TASK_ID_PREFIXES[type2] ?? "x";
|
|
8064
8114
|
const bytes = randomBytes(8);
|
|
@@ -8071,42 +8121,42 @@ function generateTaskId(type2 = "local_bash") {
|
|
|
8071
8121
|
function getTaskOutputDir() {
|
|
8072
8122
|
if (_taskOutputDir === void 0) {
|
|
8073
8123
|
const stateDir = process.env.ENGINE_STATE_DIR || process.cwd();
|
|
8074
|
-
_taskOutputDir =
|
|
8124
|
+
_taskOutputDir = path11.join(stateDir, "tasks");
|
|
8075
8125
|
}
|
|
8076
8126
|
return _taskOutputDir;
|
|
8077
8127
|
}
|
|
8078
8128
|
function getTaskOutputPath(taskId) {
|
|
8079
|
-
return
|
|
8129
|
+
return path11.join(getTaskOutputDir(), `${taskId}.output`);
|
|
8080
8130
|
}
|
|
8081
8131
|
function ensureOutputDir() {
|
|
8082
8132
|
const dir = getTaskOutputDir();
|
|
8083
|
-
if (!
|
|
8084
|
-
|
|
8133
|
+
if (!fs10.existsSync(dir)) {
|
|
8134
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
8085
8135
|
}
|
|
8086
8136
|
}
|
|
8087
8137
|
function initTaskOutput(taskId) {
|
|
8088
8138
|
ensureOutputDir();
|
|
8089
8139
|
const outputPath = getTaskOutputPath(taskId);
|
|
8090
|
-
|
|
8140
|
+
fs10.writeFileSync(outputPath, "", "utf-8");
|
|
8091
8141
|
return outputPath;
|
|
8092
8142
|
}
|
|
8093
8143
|
function persistTask(state2) {
|
|
8094
8144
|
try {
|
|
8095
8145
|
ensureOutputDir();
|
|
8096
8146
|
const p = taskIndexPath();
|
|
8097
|
-
const existing =
|
|
8147
|
+
const existing = fs10.existsSync(p) ? JSON.parse(fs10.readFileSync(p, "utf8")) : [];
|
|
8098
8148
|
const next = existing.filter((t) => t.id !== state2.id);
|
|
8099
8149
|
next.push({ ...state2 });
|
|
8100
8150
|
const tmp = `${p}.${process.pid}.tmp`;
|
|
8101
|
-
|
|
8102
|
-
|
|
8151
|
+
fs10.writeFileSync(tmp, JSON.stringify(next, null, 2));
|
|
8152
|
+
fs10.renameSync(tmp, p);
|
|
8103
8153
|
} catch (err) {
|
|
8104
8154
|
console.warn(`[task-manager] persist failed: ${err.message}`);
|
|
8105
8155
|
}
|
|
8106
8156
|
}
|
|
8107
8157
|
function loadPersistedTasks() {
|
|
8108
8158
|
try {
|
|
8109
|
-
const v = JSON.parse(
|
|
8159
|
+
const v = JSON.parse(fs10.readFileSync(taskIndexPath(), "utf8"));
|
|
8110
8160
|
return Array.isArray(v) ? v : [];
|
|
8111
8161
|
} catch {
|
|
8112
8162
|
return [];
|
|
@@ -8116,7 +8166,7 @@ function loadNotificationQueue() {
|
|
|
8116
8166
|
if (notificationsLoaded) return;
|
|
8117
8167
|
notificationsLoaded = true;
|
|
8118
8168
|
try {
|
|
8119
|
-
const value = JSON.parse(
|
|
8169
|
+
const value = JSON.parse(fs10.readFileSync(notificationQueuePath(), "utf8"));
|
|
8120
8170
|
if (Array.isArray(value)) pendingNotifications.push(...value.filter((x) => x && typeof x.notification === "string"));
|
|
8121
8171
|
} catch {
|
|
8122
8172
|
}
|
|
@@ -8126,8 +8176,8 @@ function persistNotificationQueue() {
|
|
|
8126
8176
|
ensureOutputDir();
|
|
8127
8177
|
const p = notificationQueuePath();
|
|
8128
8178
|
const tmp = `${p}.${process.pid}.tmp`;
|
|
8129
|
-
|
|
8130
|
-
|
|
8179
|
+
fs10.writeFileSync(tmp, JSON.stringify(pendingNotifications, null, 2), "utf8");
|
|
8180
|
+
fs10.renameSync(tmp, p);
|
|
8131
8181
|
} catch (err) {
|
|
8132
8182
|
console.warn(`[task-manager] notification persist failed: ${err.message}`);
|
|
8133
8183
|
}
|
|
@@ -8264,14 +8314,14 @@ function spawnBackgroundTask(opts) {
|
|
|
8264
8314
|
const taskId = generateTaskId("local_bash");
|
|
8265
8315
|
const outputPath = initTaskOutput(taskId);
|
|
8266
8316
|
const { shell, args: shellArgs } = findShell();
|
|
8267
|
-
const outputFd =
|
|
8317
|
+
const outputFd = fs10.openSync(outputPath, "w");
|
|
8268
8318
|
const child = spawn3(shell, [...shellArgs, opts.command], {
|
|
8269
8319
|
cwd: opts.cwd,
|
|
8270
8320
|
env: opts.env || process.env,
|
|
8271
8321
|
stdio: ["ignore", outputFd, outputFd]
|
|
8272
8322
|
});
|
|
8273
8323
|
try {
|
|
8274
|
-
|
|
8324
|
+
fs10.closeSync(outputFd);
|
|
8275
8325
|
} catch {
|
|
8276
8326
|
}
|
|
8277
8327
|
processes.set(taskId, child);
|
|
@@ -8303,12 +8353,12 @@ function spawnBackgroundTask(opts) {
|
|
|
8303
8353
|
let killedForSize = false;
|
|
8304
8354
|
sizeWatchdog = setInterval(() => {
|
|
8305
8355
|
if (tasks.get(taskId)?.status !== "running") return;
|
|
8306
|
-
|
|
8356
|
+
fs10.stat(outputPath, (err, st) => {
|
|
8307
8357
|
if (err || st.size <= MAX_TASK_OUTPUT_BYTES) return;
|
|
8308
8358
|
killedForSize = true;
|
|
8309
8359
|
if (sizeWatchdog) clearInterval(sizeWatchdog);
|
|
8310
8360
|
try {
|
|
8311
|
-
|
|
8361
|
+
fs10.appendFileSync(outputPath, "\n[output truncated: exceeded 5GB disk cap]\n");
|
|
8312
8362
|
} catch {
|
|
8313
8363
|
}
|
|
8314
8364
|
killChild(child);
|
|
@@ -8438,16 +8488,16 @@ function getTaskOutput(taskId, maxBytes = 8 * 1024 * 1024) {
|
|
|
8438
8488
|
if (!state2) return "";
|
|
8439
8489
|
try {
|
|
8440
8490
|
const outputPath = state2.outputFile;
|
|
8441
|
-
if (!
|
|
8442
|
-
const stat4 =
|
|
8491
|
+
if (!fs10.existsSync(outputPath)) return "";
|
|
8492
|
+
const stat4 = fs10.statSync(outputPath);
|
|
8443
8493
|
if (stat4.size <= maxBytes) {
|
|
8444
|
-
return
|
|
8494
|
+
return fs10.readFileSync(outputPath, "utf-8");
|
|
8445
8495
|
}
|
|
8446
|
-
const fd =
|
|
8496
|
+
const fd = fs10.openSync(outputPath, "r");
|
|
8447
8497
|
const start = stat4.size - maxBytes;
|
|
8448
8498
|
const buf = Buffer.alloc(maxBytes);
|
|
8449
|
-
|
|
8450
|
-
|
|
8499
|
+
fs10.readSync(fd, buf, 0, maxBytes, start);
|
|
8500
|
+
fs10.closeSync(fd);
|
|
8451
8501
|
const content = buf.toString("utf-8");
|
|
8452
8502
|
const omitted = Math.round((stat4.size - maxBytes) / 1024);
|
|
8453
8503
|
return `[${omitted}KB of earlier output omitted]
|
|
@@ -8461,14 +8511,14 @@ function getTaskOutputDelta(taskId, fromOffset, maxBytes = 8 * 1024 * 1024) {
|
|
|
8461
8511
|
if (!state2) return { content: "", newOffset: fromOffset };
|
|
8462
8512
|
try {
|
|
8463
8513
|
const outputPath = state2.outputFile;
|
|
8464
|
-
if (!
|
|
8465
|
-
const stat4 =
|
|
8514
|
+
if (!fs10.existsSync(outputPath)) return { content: "", newOffset: fromOffset };
|
|
8515
|
+
const stat4 = fs10.statSync(outputPath);
|
|
8466
8516
|
if (fromOffset >= stat4.size) return { content: "", newOffset: stat4.size };
|
|
8467
8517
|
const readLen = Math.min(maxBytes, stat4.size - fromOffset);
|
|
8468
8518
|
const buf = Buffer.alloc(readLen);
|
|
8469
|
-
const fd =
|
|
8470
|
-
|
|
8471
|
-
|
|
8519
|
+
const fd = fs10.openSync(outputPath, "r");
|
|
8520
|
+
fs10.readSync(fd, buf, 0, readLen, fromOffset);
|
|
8521
|
+
fs10.closeSync(fd);
|
|
8472
8522
|
return { content: buf.toString("utf-8"), newOffset: fromOffset + readLen };
|
|
8473
8523
|
} catch {
|
|
8474
8524
|
return { content: "", newOffset: fromOffset };
|
|
@@ -8478,8 +8528,8 @@ function getTaskOutputSize(taskId) {
|
|
|
8478
8528
|
const state2 = tasks.get(taskId);
|
|
8479
8529
|
if (!state2) return 0;
|
|
8480
8530
|
try {
|
|
8481
|
-
if (!
|
|
8482
|
-
return
|
|
8531
|
+
if (!fs10.existsSync(state2.outputFile)) return 0;
|
|
8532
|
+
return fs10.statSync(state2.outputFile).size;
|
|
8483
8533
|
} catch {
|
|
8484
8534
|
return 0;
|
|
8485
8535
|
}
|
|
@@ -8517,10 +8567,10 @@ var init_task_manager = __esm({
|
|
|
8517
8567
|
MAX_TASK_OUTPUT_BYTES = 5 * 1024 * 1024 * 1024;
|
|
8518
8568
|
tasks = /* @__PURE__ */ new Map();
|
|
8519
8569
|
processes = /* @__PURE__ */ new Map();
|
|
8520
|
-
taskIndexPath = () =>
|
|
8570
|
+
taskIndexPath = () => path11.join(process.env.ENGINE_STATE_DIR || process.cwd(), "tasks", "index.json");
|
|
8521
8571
|
pendingNotifications = [];
|
|
8522
8572
|
notificationsLoaded = false;
|
|
8523
|
-
notificationQueuePath = () =>
|
|
8573
|
+
notificationQueuePath = () => path11.join(process.env.ENGINE_STATE_DIR || process.cwd(), "tasks", "notifications.json");
|
|
8524
8574
|
notificationCallback = null;
|
|
8525
8575
|
DEAD_LETTER_MAX_ATTEMPTS = 10;
|
|
8526
8576
|
RETRY_BASE_MS = 1e3;
|
|
@@ -8662,8 +8712,8 @@ __export(context_analyzer_exports, {
|
|
|
8662
8712
|
formatContextReport: () => formatContextReport,
|
|
8663
8713
|
scanMemoryFiles: () => scanMemoryFiles
|
|
8664
8714
|
});
|
|
8665
|
-
import * as
|
|
8666
|
-
import * as
|
|
8715
|
+
import * as fs11 from "node:fs";
|
|
8716
|
+
import * as path12 from "node:path";
|
|
8667
8717
|
function estimateMessageTokens2(m) {
|
|
8668
8718
|
let tokens = 0;
|
|
8669
8719
|
if (typeof m.content === "string") {
|
|
@@ -8773,9 +8823,9 @@ function breakdownMessages(messages) {
|
|
|
8773
8823
|
}
|
|
8774
8824
|
async function scanMemoryFiles(workspace) {
|
|
8775
8825
|
const files = [];
|
|
8776
|
-
const soul = readFileIfExists2(
|
|
8826
|
+
const soul = readFileIfExists2(path12.join(workspace, "SOUL.md"));
|
|
8777
8827
|
if (soul) files.push({ path: "SOUL.md", tokens: roughTokenCountEstimation(soul), stable: true });
|
|
8778
|
-
const agents = readFileIfExists2(
|
|
8828
|
+
const agents = readFileIfExists2(path12.join(workspace, "AGENTS.md"));
|
|
8779
8829
|
if (agents) files.push({ path: "AGENTS.md", tokens: roughTokenCountEstimation(agents), stable: true });
|
|
8780
8830
|
try {
|
|
8781
8831
|
const { buildMemoryPrompt: buildMemoryPrompt2 } = await Promise.resolve().then(() => (init_memdir(), memdir_exports));
|
|
@@ -8791,7 +8841,7 @@ async function scanMemoryFiles(workspace) {
|
|
|
8791
8841
|
}
|
|
8792
8842
|
function readFileIfExists2(filePath) {
|
|
8793
8843
|
try {
|
|
8794
|
-
if (
|
|
8844
|
+
if (fs11.existsSync(filePath)) return fs11.readFileSync(filePath, "utf-8");
|
|
8795
8845
|
} catch {
|
|
8796
8846
|
}
|
|
8797
8847
|
return null;
|
|
@@ -9770,8 +9820,8 @@ ${perTurnSystemDynamic}` : deferredHint || perTurnSystemDynamic;
|
|
|
9770
9820
|
});
|
|
9771
9821
|
|
|
9772
9822
|
// src/session/writer.ts
|
|
9773
|
-
import * as
|
|
9774
|
-
import * as
|
|
9823
|
+
import * as fs12 from "node:fs";
|
|
9824
|
+
import * as path13 from "node:path";
|
|
9775
9825
|
import * as crypto2 from "node:crypto";
|
|
9776
9826
|
function assistantWriteParamsFrom(m) {
|
|
9777
9827
|
const anyM = m;
|
|
@@ -9807,7 +9857,7 @@ var init_writer = __esm({
|
|
|
9807
9857
|
this.sessionId = sessionId || crypto2.randomUUID();
|
|
9808
9858
|
this.engineSessionId = "";
|
|
9809
9859
|
const filename = `${this.sessionId}.jsonl`;
|
|
9810
|
-
this.filePath =
|
|
9860
|
+
this.filePath = path13.join(sessionsDir, filename);
|
|
9811
9861
|
}
|
|
9812
9862
|
get id() {
|
|
9813
9863
|
return this.sessionId;
|
|
@@ -9818,9 +9868,9 @@ var init_writer = __esm({
|
|
|
9818
9868
|
/** 打开文件写入 header(新文件才写 header) */
|
|
9819
9869
|
open(cwd, engineSessionId) {
|
|
9820
9870
|
this.engineSessionId = engineSessionId || "";
|
|
9821
|
-
|
|
9822
|
-
const fileExists =
|
|
9823
|
-
this.stream =
|
|
9871
|
+
fs12.mkdirSync(path13.dirname(this.filePath), { recursive: true });
|
|
9872
|
+
const fileExists = fs12.existsSync(this.filePath) && fs12.statSync(this.filePath).size > 0;
|
|
9873
|
+
this.stream = fs12.createWriteStream(this.filePath, { flags: "a" });
|
|
9824
9874
|
this.stream.on("error", (err) => {
|
|
9825
9875
|
console.error(`[SessionWriter] write error on ${this.filePath}:`, err.message);
|
|
9826
9876
|
});
|
|
@@ -10023,17 +10073,17 @@ var init_writer = __esm({
|
|
|
10023
10073
|
this.stream.end();
|
|
10024
10074
|
this.stream = null;
|
|
10025
10075
|
}
|
|
10026
|
-
if (!
|
|
10027
|
-
const fileSize =
|
|
10076
|
+
if (!fs12.existsSync(this.filePath)) return null;
|
|
10077
|
+
const fileSize = fs12.statSync(this.filePath).size;
|
|
10028
10078
|
if (fileSize === 0) return null;
|
|
10029
10079
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
|
|
10030
10080
|
const archivedPath = `${this.filePath}.${reason}.${ts}`;
|
|
10031
|
-
|
|
10081
|
+
fs12.renameSync(this.filePath, archivedPath);
|
|
10032
10082
|
const sizeMB = (fileSize / 1024 / 1024).toFixed(1);
|
|
10033
|
-
console.log(`[SessionWriter] Archived JSONL: ${
|
|
10083
|
+
console.log(`[SessionWriter] Archived JSONL: ${path13.basename(this.filePath)} \u2192 ${path13.basename(archivedPath)} (${sizeMB}MB)`);
|
|
10034
10084
|
const postBoundaryData = this.readPostBoundaryFromArchived(archivedPath);
|
|
10035
|
-
const dir =
|
|
10036
|
-
|
|
10085
|
+
const dir = path13.dirname(this.filePath);
|
|
10086
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
10037
10087
|
const header = {
|
|
10038
10088
|
type: "session",
|
|
10039
10089
|
version: 3,
|
|
@@ -10047,8 +10097,8 @@ var init_writer = __esm({
|
|
|
10047
10097
|
if (postBoundaryData.length > 0) {
|
|
10048
10098
|
initialData += postBoundaryData.toString("utf-8");
|
|
10049
10099
|
}
|
|
10050
|
-
|
|
10051
|
-
this.stream =
|
|
10100
|
+
fs12.writeFileSync(this.filePath, initialData, "utf-8");
|
|
10101
|
+
this.stream = fs12.createWriteStream(this.filePath, { flags: "a" });
|
|
10052
10102
|
this.stream.on("error", (err) => {
|
|
10053
10103
|
console.error(`[SessionWriter] write error on ${this.filePath}:`, err.message);
|
|
10054
10104
|
});
|
|
@@ -10058,10 +10108,10 @@ var init_writer = __esm({
|
|
|
10058
10108
|
* 从归档文件中读取最后一个 compact_boundary 之后的内容
|
|
10059
10109
|
*/
|
|
10060
10110
|
readPostBoundaryFromArchived(archivedPath) {
|
|
10061
|
-
const fileSize =
|
|
10111
|
+
const fileSize = fs12.statSync(archivedPath).size;
|
|
10062
10112
|
if (fileSize === 0) return Buffer.alloc(0);
|
|
10063
10113
|
if (fileSize <= 5 * 1024 * 1024) {
|
|
10064
|
-
const content =
|
|
10114
|
+
const content = fs12.readFileSync(archivedPath, "utf-8");
|
|
10065
10115
|
const lines = content.split("\n");
|
|
10066
10116
|
let lastBoundaryIdx = -1;
|
|
10067
10117
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
@@ -10078,11 +10128,11 @@ var init_writer = __esm({
|
|
|
10078
10128
|
{
|
|
10079
10129
|
const probeSize = Math.min(fileSize, 1024 * 1024);
|
|
10080
10130
|
const probeBuf = Buffer.allocUnsafe(probeSize);
|
|
10081
|
-
const probeFd =
|
|
10131
|
+
const probeFd = fs12.openSync(archivedPath, "r");
|
|
10082
10132
|
let hasBoundary = false;
|
|
10083
10133
|
let probed = 0;
|
|
10084
10134
|
while (probed < fileSize) {
|
|
10085
|
-
const n =
|
|
10135
|
+
const n = fs12.readSync(probeFd, probeBuf, 0, Math.min(probeSize, fileSize - probed), probed);
|
|
10086
10136
|
if (n === 0) break;
|
|
10087
10137
|
if (probeBuf.subarray(0, n).includes(Buffer.from(boundaryMarker))) {
|
|
10088
10138
|
hasBoundary = true;
|
|
@@ -10090,19 +10140,19 @@ var init_writer = __esm({
|
|
|
10090
10140
|
}
|
|
10091
10141
|
probed += n;
|
|
10092
10142
|
}
|
|
10093
|
-
|
|
10143
|
+
fs12.closeSync(probeFd);
|
|
10094
10144
|
if (!hasBoundary) return Buffer.alloc(0);
|
|
10095
10145
|
}
|
|
10096
10146
|
const outBuf = Buffer.allocUnsafe(Math.min(fileSize, 8 * 1024 * 1024));
|
|
10097
10147
|
let outLen = 0;
|
|
10098
10148
|
const chunk = Buffer.allocUnsafe(CHUNK_SIZE);
|
|
10099
|
-
const fd =
|
|
10149
|
+
const fd = fs12.openSync(archivedPath, "r");
|
|
10100
10150
|
try {
|
|
10101
10151
|
let filePos = 0;
|
|
10102
10152
|
let carryBuf;
|
|
10103
10153
|
let carryLen = 0;
|
|
10104
10154
|
while (filePos < fileSize) {
|
|
10105
|
-
const bytesRead =
|
|
10155
|
+
const bytesRead = fs12.readSync(fd, chunk, 0, Math.min(CHUNK_SIZE, fileSize - filePos), filePos);
|
|
10106
10156
|
if (bytesRead === 0) break;
|
|
10107
10157
|
filePos += bytesRead;
|
|
10108
10158
|
let scanBuf;
|
|
@@ -10151,7 +10201,7 @@ var init_writer = __esm({
|
|
|
10151
10201
|
}
|
|
10152
10202
|
}
|
|
10153
10203
|
} finally {
|
|
10154
|
-
|
|
10204
|
+
fs12.closeSync(fd);
|
|
10155
10205
|
}
|
|
10156
10206
|
return outBuf.subarray(0, outLen);
|
|
10157
10207
|
}
|
|
@@ -10163,15 +10213,15 @@ var init_writer = __esm({
|
|
|
10163
10213
|
*/
|
|
10164
10214
|
readLastId() {
|
|
10165
10215
|
try {
|
|
10166
|
-
const stat4 =
|
|
10216
|
+
const stat4 = fs12.statSync(this.filePath);
|
|
10167
10217
|
if (stat4.size === 0) return null;
|
|
10168
10218
|
const readSize = Math.min(stat4.size, 4096);
|
|
10169
10219
|
const buf = Buffer.alloc(readSize);
|
|
10170
|
-
const fd =
|
|
10220
|
+
const fd = fs12.openSync(this.filePath, "r");
|
|
10171
10221
|
try {
|
|
10172
|
-
|
|
10222
|
+
fs12.readSync(fd, buf, 0, readSize, stat4.size - readSize);
|
|
10173
10223
|
} finally {
|
|
10174
|
-
|
|
10224
|
+
fs12.closeSync(fd);
|
|
10175
10225
|
}
|
|
10176
10226
|
const text = buf.toString("utf-8");
|
|
10177
10227
|
const lines = text.split("\n").filter((l) => l.trim().length > 0);
|
|
@@ -10218,11 +10268,11 @@ var init_writer = __esm({
|
|
|
10218
10268
|
});
|
|
10219
10269
|
|
|
10220
10270
|
// src/session/reader.ts
|
|
10221
|
-
import * as
|
|
10222
|
-
import * as
|
|
10271
|
+
import * as fs13 from "node:fs";
|
|
10272
|
+
import * as path14 from "node:path";
|
|
10223
10273
|
import * as readline from "node:readline";
|
|
10224
10274
|
async function readSessionHeader(filePath) {
|
|
10225
|
-
const stream =
|
|
10275
|
+
const stream = fs13.createReadStream(filePath, { encoding: "utf-8" });
|
|
10226
10276
|
const rl = readline.createInterface({ input: stream });
|
|
10227
10277
|
return new Promise((resolve12) => {
|
|
10228
10278
|
let resolved = false;
|
|
@@ -10253,7 +10303,7 @@ async function readSessionHeader(filePath) {
|
|
|
10253
10303
|
});
|
|
10254
10304
|
}
|
|
10255
10305
|
async function readLargeFilePostBoundary(filePath) {
|
|
10256
|
-
const stat4 =
|
|
10306
|
+
const stat4 = fs13.statSync(filePath);
|
|
10257
10307
|
const fileSize = stat4.size;
|
|
10258
10308
|
const boundaryMarker = '"compact_boundary"';
|
|
10259
10309
|
const CHUNK_SIZE = TRANSCRIPT_READ_CHUNK_SIZE;
|
|
@@ -10261,13 +10311,13 @@ async function readLargeFilePostBoundary(filePath) {
|
|
|
10261
10311
|
let outLen = 0;
|
|
10262
10312
|
let boundaryStartOffset = 0;
|
|
10263
10313
|
const chunk = Buffer.allocUnsafe(CHUNK_SIZE);
|
|
10264
|
-
const fd =
|
|
10314
|
+
const fd = fs13.openSync(filePath, "r");
|
|
10265
10315
|
try {
|
|
10266
10316
|
let filePos = 0;
|
|
10267
10317
|
let carryBuf;
|
|
10268
10318
|
let carryLen = 0;
|
|
10269
10319
|
while (filePos < fileSize) {
|
|
10270
|
-
const bytesRead =
|
|
10320
|
+
const bytesRead = fs13.readSync(fd, chunk, 0, Math.min(CHUNK_SIZE, fileSize - filePos), filePos);
|
|
10271
10321
|
if (bytesRead === 0) break;
|
|
10272
10322
|
filePos += bytesRead;
|
|
10273
10323
|
let scanBuf;
|
|
@@ -10319,7 +10369,7 @@ async function readLargeFilePostBoundary(filePath) {
|
|
|
10319
10369
|
}
|
|
10320
10370
|
}
|
|
10321
10371
|
} finally {
|
|
10322
|
-
|
|
10372
|
+
fs13.closeSync(fd);
|
|
10323
10373
|
}
|
|
10324
10374
|
const postBoundaryText = outBuf.subarray(0, outLen).toString("utf-8");
|
|
10325
10375
|
return postBoundaryText.split("\n").filter((l) => l.trim().length > 0);
|
|
@@ -10443,7 +10493,7 @@ function recoverOrphanedParallelToolResults(allEntries, chain, byUuid, seen) {
|
|
|
10443
10493
|
return result;
|
|
10444
10494
|
}
|
|
10445
10495
|
async function readSessionHistory(filePath) {
|
|
10446
|
-
const stat4 =
|
|
10496
|
+
const stat4 = fs13.statSync(filePath);
|
|
10447
10497
|
const fileSize = stat4.size;
|
|
10448
10498
|
if (fileSize > MAX_TRANSCRIPT_READ_BYTES) {
|
|
10449
10499
|
console.warn(`[reader] Session file exceeds 50MB limit (${(fileSize / 1024 / 1024).toFixed(1)}MB), using chunked fd read with boundary skip`);
|
|
@@ -10482,7 +10532,7 @@ async function readSessionHistory(filePath) {
|
|
|
10482
10532
|
return [...sessionStarts, ...filtered, ...restAttachments];
|
|
10483
10533
|
}
|
|
10484
10534
|
async function readAllLines(filePath) {
|
|
10485
|
-
const stream =
|
|
10535
|
+
const stream = fs13.createReadStream(filePath, { encoding: "utf-8" });
|
|
10486
10536
|
const rl = readline.createInterface({ input: stream });
|
|
10487
10537
|
const lines = [];
|
|
10488
10538
|
return new Promise((resolve12, reject) => {
|
|
@@ -10636,12 +10686,12 @@ function extractText(content) {
|
|
|
10636
10686
|
return content.filter((b) => b.type === "text").map((b) => b.text || "").join("") || null;
|
|
10637
10687
|
}
|
|
10638
10688
|
function listSessions(sessionsDir) {
|
|
10639
|
-
if (!
|
|
10640
|
-
const files =
|
|
10641
|
-
file:
|
|
10689
|
+
if (!fs13.existsSync(sessionsDir)) return [];
|
|
10690
|
+
const files = fs13.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") || f.includes(".jsonl.")).map((f) => ({
|
|
10691
|
+
file: path14.join(sessionsDir, f),
|
|
10642
10692
|
id: f.replace(/\.jsonl.*$/, ""),
|
|
10643
10693
|
// strip .jsonl and everything after (archived suffix)
|
|
10644
|
-
modified: new Date(
|
|
10694
|
+
modified: new Date(fs13.statSync(path14.join(sessionsDir, f)).mtimeMs)
|
|
10645
10695
|
})).sort((a, b) => b.modified.getTime() - a.modified.getTime());
|
|
10646
10696
|
return files;
|
|
10647
10697
|
}
|
|
@@ -10662,8 +10712,8 @@ __export(session_manager_exports, {
|
|
|
10662
10712
|
SessionManager: () => SessionManager,
|
|
10663
10713
|
alignRestoreHeadToTurnBoundary: () => alignRestoreHeadToTurnBoundary
|
|
10664
10714
|
});
|
|
10665
|
-
import * as
|
|
10666
|
-
import * as
|
|
10715
|
+
import * as path15 from "node:path";
|
|
10716
|
+
import * as fs14 from "node:fs";
|
|
10667
10717
|
import * as crypto3 from "node:crypto";
|
|
10668
10718
|
function alignRestoreHeadToTurnBoundary(messages, minKeep = RESTORE_MIN_KEEP_MESSAGES) {
|
|
10669
10719
|
const isTurnBoundary = (m) => isAttachmentMessage(m) ? true : m.role === "user";
|
|
@@ -10702,24 +10752,24 @@ var init_session_manager = __esm({
|
|
|
10702
10752
|
constructor(config) {
|
|
10703
10753
|
this.config = config;
|
|
10704
10754
|
this.scopeConfig = config.scopeConfig;
|
|
10705
|
-
this.sessionsDir =
|
|
10706
|
-
this.indexPath =
|
|
10707
|
-
this.platformMapPath =
|
|
10708
|
-
|
|
10755
|
+
this.sessionsDir = path15.join(config.stateDir, "agents", "main", "sessions");
|
|
10756
|
+
this.indexPath = path15.join(this.sessionsDir, "session-index.json");
|
|
10757
|
+
this.platformMapPath = path15.join(this.sessionsDir, "platform-map.json");
|
|
10758
|
+
fs14.mkdirSync(this.sessionsDir, { recursive: true });
|
|
10709
10759
|
}
|
|
10710
10760
|
// === 索引操作 ===
|
|
10711
10761
|
loadIndex() {
|
|
10712
10762
|
try {
|
|
10713
|
-
if (
|
|
10714
|
-
const raw =
|
|
10763
|
+
if (fs14.existsSync(this.indexPath)) {
|
|
10764
|
+
const raw = fs14.readFileSync(this.indexPath, "utf-8");
|
|
10715
10765
|
const obj = JSON.parse(raw);
|
|
10716
10766
|
this.index = new Map(Object.entries(obj));
|
|
10717
10767
|
let fixed = 0;
|
|
10718
10768
|
for (const [key, entry] of this.index) {
|
|
10719
|
-
if (
|
|
10720
|
-
const basename10 =
|
|
10721
|
-
const localPath =
|
|
10722
|
-
if (
|
|
10769
|
+
if (fs14.existsSync(entry.file)) continue;
|
|
10770
|
+
const basename10 = path15.basename(entry.file);
|
|
10771
|
+
const localPath = path15.join(this.sessionsDir, basename10);
|
|
10772
|
+
if (fs14.existsSync(localPath)) {
|
|
10723
10773
|
entry.file = localPath;
|
|
10724
10774
|
fixed++;
|
|
10725
10775
|
}
|
|
@@ -10738,7 +10788,7 @@ var init_session_manager = __esm({
|
|
|
10738
10788
|
try {
|
|
10739
10789
|
const obj = {};
|
|
10740
10790
|
for (const [k, v] of this.index) obj[k] = v;
|
|
10741
|
-
|
|
10791
|
+
fs14.writeFileSync(this.indexPath, JSON.stringify(obj, null, 2));
|
|
10742
10792
|
} catch (err) {
|
|
10743
10793
|
console.error(`[session] Failed to save index: ${err.message}`);
|
|
10744
10794
|
}
|
|
@@ -10746,8 +10796,8 @@ var init_session_manager = __esm({
|
|
|
10746
10796
|
// === 平台映射 ===
|
|
10747
10797
|
loadPlatformMap() {
|
|
10748
10798
|
try {
|
|
10749
|
-
if (
|
|
10750
|
-
const raw =
|
|
10799
|
+
if (fs14.existsSync(this.platformMapPath)) {
|
|
10800
|
+
const raw = fs14.readFileSync(this.platformMapPath, "utf-8");
|
|
10751
10801
|
const obj = JSON.parse(raw);
|
|
10752
10802
|
this.platformMap = new Map(Object.entries(obj));
|
|
10753
10803
|
console.log(`[session] Platform map loaded: ${this.platformMap.size} entries`);
|
|
@@ -10759,7 +10809,7 @@ var init_session_manager = __esm({
|
|
|
10759
10809
|
try {
|
|
10760
10810
|
const obj = {};
|
|
10761
10811
|
for (const [k, v] of this.platformMap) obj[k] = v;
|
|
10762
|
-
|
|
10812
|
+
fs14.writeFileSync(this.platformMapPath, JSON.stringify(obj, null, 2));
|
|
10763
10813
|
} catch (err) {
|
|
10764
10814
|
console.error(`[session] Failed to save platform map: ${err.message}`);
|
|
10765
10815
|
}
|
|
@@ -10798,17 +10848,17 @@ var init_session_manager = __esm({
|
|
|
10798
10848
|
*/
|
|
10799
10849
|
getSessionFilePath(sessionId) {
|
|
10800
10850
|
const entry = this.index.get(sessionId);
|
|
10801
|
-
if (entry &&
|
|
10802
|
-
const direct =
|
|
10803
|
-
return
|
|
10851
|
+
if (entry && fs14.existsSync(entry.file)) return entry.file;
|
|
10852
|
+
const direct = path15.join(this.sessionsDir, `${sessionId}.jsonl`);
|
|
10853
|
+
return fs14.existsSync(direct) ? direct : null;
|
|
10804
10854
|
}
|
|
10805
10855
|
// === Writer 管理 ===
|
|
10806
10856
|
getWriter(sessionId) {
|
|
10807
10857
|
let writer = this.writers.get(sessionId);
|
|
10808
10858
|
if (!writer) {
|
|
10809
10859
|
const existing = this.index.get(sessionId);
|
|
10810
|
-
if (existing &&
|
|
10811
|
-
const existingFileId =
|
|
10860
|
+
if (existing && fs14.existsSync(existing.file)) {
|
|
10861
|
+
const existingFileId = path15.basename(existing.file, ".jsonl");
|
|
10812
10862
|
writer = new SessionWriter(this.sessionsDir, existingFileId);
|
|
10813
10863
|
writer.open(this.config.workspace, sessionId);
|
|
10814
10864
|
} else {
|
|
@@ -10820,7 +10870,7 @@ var init_session_manager = __esm({
|
|
|
10820
10870
|
this.saveIndex();
|
|
10821
10871
|
this.writers.set(sessionId, writer);
|
|
10822
10872
|
this.onWriterCreated?.(writer, sessionId);
|
|
10823
|
-
console.log(`[session] ${existing ? "Resumed" : "New"}: ${sessionId} \u2192 ${
|
|
10873
|
+
console.log(`[session] ${existing ? "Resumed" : "New"}: ${sessionId} \u2192 ${path15.basename(writer.path)}`);
|
|
10824
10874
|
}
|
|
10825
10875
|
return writer;
|
|
10826
10876
|
}
|
|
@@ -10839,7 +10889,7 @@ var init_session_manager = __esm({
|
|
|
10839
10889
|
if (!writer) return null;
|
|
10840
10890
|
try {
|
|
10841
10891
|
this.lastArchiveCheck = Date.now();
|
|
10842
|
-
const stat4 =
|
|
10892
|
+
const stat4 = fs14.statSync(writer.path);
|
|
10843
10893
|
if (stat4.size < threshold) return null;
|
|
10844
10894
|
const sizeMB = (stat4.size / 1024 / 1024).toFixed(1);
|
|
10845
10895
|
const thresholdMB = (threshold / 1024 / 1024).toFixed(1);
|
|
@@ -10848,10 +10898,10 @@ var init_session_manager = __esm({
|
|
|
10848
10898
|
if (archivedPath) {
|
|
10849
10899
|
this.index.set(sessionId, { file: writer.path, updatedAt: Date.now() });
|
|
10850
10900
|
this.saveIndex();
|
|
10851
|
-
const newSize =
|
|
10901
|
+
const newSize = fs14.statSync(writer.path).size;
|
|
10852
10902
|
const oldSizeMB = (stat4.size / 1024 / 1024).toFixed(1);
|
|
10853
|
-
console.log(`[session] Archive complete: ${
|
|
10854
|
-
const fileId =
|
|
10903
|
+
console.log(`[session] Archive complete: ${path15.basename(archivedPath)} (${oldSizeMB}MB) \u2192 new JSONL created (${newSize} bytes)`);
|
|
10904
|
+
const fileId = path15.basename(writer.path).replace(/\.jsonl$/, "");
|
|
10855
10905
|
this.purgeOldArchives(fileId, 3);
|
|
10856
10906
|
return archivedPath;
|
|
10857
10907
|
}
|
|
@@ -10867,15 +10917,15 @@ var init_session_manager = __esm({
|
|
|
10867
10917
|
purgeOldArchives(sessionId, keepCount = 3) {
|
|
10868
10918
|
try {
|
|
10869
10919
|
const dir = this.sessionsDir;
|
|
10870
|
-
if (!
|
|
10871
|
-
const allFiles =
|
|
10920
|
+
if (!fs14.existsSync(dir)) return;
|
|
10921
|
+
const allFiles = fs14.readdirSync(dir);
|
|
10872
10922
|
const archiveFiles = allFiles.filter((f) => {
|
|
10873
10923
|
if (!f.startsWith(sessionId)) return false;
|
|
10874
10924
|
return f.includes(".archived.") || f.includes(".compaction.");
|
|
10875
10925
|
}).map((f) => ({
|
|
10876
10926
|
name: f,
|
|
10877
|
-
path:
|
|
10878
|
-
mtime:
|
|
10927
|
+
path: path15.join(dir, f),
|
|
10928
|
+
mtime: fs14.statSync(path15.join(dir, f)).mtimeMs
|
|
10879
10929
|
})).sort((a, b) => b.mtime - a.mtime);
|
|
10880
10930
|
console.log(`[session] purgeOldArchives: sessionId=${sessionId.substring(0, 8)}... found=${archiveFiles.length} keep=${keepCount}`);
|
|
10881
10931
|
if (archiveFiles.length <= keepCount) return;
|
|
@@ -10885,7 +10935,7 @@ var init_session_manager = __esm({
|
|
|
10885
10935
|
console.log(`[session] Skipping archived (kept for history): ${f.name}`);
|
|
10886
10936
|
continue;
|
|
10887
10937
|
}
|
|
10888
|
-
|
|
10938
|
+
fs14.unlinkSync(f.path);
|
|
10889
10939
|
console.log(`[session] Purged old archive: ${f.name}`);
|
|
10890
10940
|
}
|
|
10891
10941
|
if (toDelete.length > 0) {
|
|
@@ -10934,29 +10984,29 @@ var init_session_manager = __esm({
|
|
|
10934
10984
|
/** 列出 session 的所有文件(当前 + 归档),按修改时间排序 */
|
|
10935
10985
|
findAllSessionFiles(sessionId) {
|
|
10936
10986
|
const results = [];
|
|
10937
|
-
const mainFile =
|
|
10938
|
-
if (
|
|
10987
|
+
const mainFile = path15.join(this.sessionsDir, `${sessionId}.jsonl`);
|
|
10988
|
+
if (fs14.existsSync(mainFile)) {
|
|
10939
10989
|
results.push(mainFile);
|
|
10940
10990
|
}
|
|
10941
|
-
if (
|
|
10942
|
-
const compactionFiles =
|
|
10991
|
+
if (fs14.existsSync(this.sessionsDir)) {
|
|
10992
|
+
const compactionFiles = fs14.readdirSync(this.sessionsDir).filter((f) => f.startsWith(`${sessionId}.jsonl.compaction.`)).map((f) => ({
|
|
10943
10993
|
name: f,
|
|
10944
|
-
path:
|
|
10945
|
-
mtime:
|
|
10994
|
+
path: path15.join(this.sessionsDir, f),
|
|
10995
|
+
mtime: fs14.statSync(path15.join(this.sessionsDir, f)).mtimeMs
|
|
10946
10996
|
})).sort((a, b) => b.mtime - a.mtime);
|
|
10947
10997
|
if (compactionFiles.length > 0) {
|
|
10948
10998
|
results.push(compactionFiles[0].path);
|
|
10949
10999
|
}
|
|
10950
11000
|
}
|
|
10951
11001
|
results.sort((a, b) => {
|
|
10952
|
-
const ta =
|
|
10953
|
-
const tb =
|
|
11002
|
+
const ta = fs14.statSync(a).mtimeMs;
|
|
11003
|
+
const tb = fs14.statSync(b).mtimeMs;
|
|
10954
11004
|
return ta - tb;
|
|
10955
11005
|
});
|
|
10956
11006
|
return results;
|
|
10957
11007
|
}
|
|
10958
11008
|
async findSessionFiles(sessionId) {
|
|
10959
|
-
if (!
|
|
11009
|
+
if (!fs14.existsSync(this.sessionsDir)) {
|
|
10960
11010
|
console.log(`[session:find] SESSIONS_DIR not found: ${this.sessionsDir}`);
|
|
10961
11011
|
return [];
|
|
10962
11012
|
}
|
|
@@ -10968,15 +11018,15 @@ var init_session_manager = __esm({
|
|
|
10968
11018
|
return mappedFiles;
|
|
10969
11019
|
}
|
|
10970
11020
|
const indexedEntry = this.index.get(mappedId);
|
|
10971
|
-
if (indexedEntry &&
|
|
10972
|
-
const fileUuid =
|
|
11021
|
+
if (indexedEntry && fs14.existsSync(indexedEntry.file)) {
|
|
11022
|
+
const fileUuid = path15.basename(indexedEntry.file, ".jsonl");
|
|
10973
11023
|
return this.findAllSessionFiles(fileUuid);
|
|
10974
11024
|
}
|
|
10975
11025
|
}
|
|
10976
11026
|
const allFiles = this.findAllSessionFiles(sessionId);
|
|
10977
11027
|
if (allFiles.length > 0) {
|
|
10978
11028
|
const labels = allFiles.map((f) => {
|
|
10979
|
-
const base =
|
|
11029
|
+
const base = path15.basename(f);
|
|
10980
11030
|
return base.endsWith(".jsonl") ? base : `${base} (archived)`;
|
|
10981
11031
|
});
|
|
10982
11032
|
console.log(`[session:find] Found ${allFiles.length} file(s) for ${sessionId}: ${labels.join(", ")}`);
|
|
@@ -10984,9 +11034,9 @@ var init_session_manager = __esm({
|
|
|
10984
11034
|
}
|
|
10985
11035
|
const indexed = this.index.get(sessionId);
|
|
10986
11036
|
if (indexed) {
|
|
10987
|
-
console.log(`[session:find] Index hit: ${sessionId} \u2192 ${indexed.file} (exists=${
|
|
10988
|
-
if (
|
|
10989
|
-
return this.findAllSessionFiles(
|
|
11037
|
+
console.log(`[session:find] Index hit: ${sessionId} \u2192 ${indexed.file} (exists=${fs14.existsSync(indexed.file)})`);
|
|
11038
|
+
if (fs14.existsSync(indexed.file)) {
|
|
11039
|
+
return this.findAllSessionFiles(path15.basename(indexed.file, ".jsonl"));
|
|
10990
11040
|
}
|
|
10991
11041
|
} else {
|
|
10992
11042
|
console.log(`[session:find] Index miss: ${sessionId} (index has ${this.index.size} entries)`);
|
|
@@ -11015,8 +11065,8 @@ var init_session_manager = __esm({
|
|
|
11015
11065
|
return [];
|
|
11016
11066
|
}
|
|
11017
11067
|
files.sort((a, b) => {
|
|
11018
|
-
const ta =
|
|
11019
|
-
const tb =
|
|
11068
|
+
const ta = fs14.statSync(a).mtimeMs;
|
|
11069
|
+
const tb = fs14.statSync(b).mtimeMs;
|
|
11020
11070
|
return ta - tb;
|
|
11021
11071
|
});
|
|
11022
11072
|
const latestFile = files[files.length - 1];
|
|
@@ -11024,7 +11074,7 @@ var init_session_manager = __esm({
|
|
|
11024
11074
|
if (!currentEntry || currentEntry.file !== latestFile) {
|
|
11025
11075
|
this.index.set(sessionId, { file: latestFile, updatedAt: Date.now() });
|
|
11026
11076
|
this.saveIndex();
|
|
11027
|
-
console.log(`[session:restore] Synced index: ${sessionId} \u2192 ${
|
|
11077
|
+
console.log(`[session:restore] Synced index: ${sessionId} \u2192 ${path15.basename(latestFile)}`);
|
|
11028
11078
|
}
|
|
11029
11079
|
const allMessages = [];
|
|
11030
11080
|
for (const file2 of files) {
|
|
@@ -11063,7 +11113,7 @@ var init_session_manager = __esm({
|
|
|
11063
11113
|
if (isAttachmentMessage(m) && m.attachment.type === "relevant_memories") {
|
|
11064
11114
|
for (const mem of m.attachment.memories) {
|
|
11065
11115
|
rawCount++;
|
|
11066
|
-
restoredPaths.add(
|
|
11116
|
+
restoredPaths.add(path15.resolve(mem.path));
|
|
11067
11117
|
}
|
|
11068
11118
|
}
|
|
11069
11119
|
}
|
|
@@ -11095,15 +11145,15 @@ var init_session_manager = __esm({
|
|
|
11095
11145
|
*/
|
|
11096
11146
|
rotateMainSession() {
|
|
11097
11147
|
const entry = this.index.get("main");
|
|
11098
|
-
if (!entry || !
|
|
11099
|
-
const oldFileId =
|
|
11100
|
-
const stat4 =
|
|
11148
|
+
if (!entry || !fs14.existsSync(entry.file)) return;
|
|
11149
|
+
const oldFileId = path15.basename(entry.file, ".jsonl");
|
|
11150
|
+
const stat4 = fs14.statSync(entry.file);
|
|
11101
11151
|
if (stat4.size < 1024) return;
|
|
11102
11152
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
|
|
11103
11153
|
const archivedPath = `${entry.file}.archived.${ts}`;
|
|
11104
|
-
|
|
11154
|
+
fs14.renameSync(entry.file, archivedPath);
|
|
11105
11155
|
const sizeMB = (stat4.size / 1024 / 1024).toFixed(1);
|
|
11106
|
-
console.log(`[session] Archived: ${
|
|
11156
|
+
console.log(`[session] Archived: ${path15.basename(entry.file)} \u2192 ${path15.basename(archivedPath)} (${sizeMB}MB)`);
|
|
11107
11157
|
const newWriter = new SessionWriter(this.sessionsDir);
|
|
11108
11158
|
newWriter.open(this.config.workspace, "main");
|
|
11109
11159
|
newWriter.writeModelChange(this.config.providerId, this.config.model);
|
|
@@ -11112,7 +11162,7 @@ var init_session_manager = __esm({
|
|
|
11112
11162
|
this.index.set("main", { file: newPath, updatedAt: Date.now() });
|
|
11113
11163
|
this.saveIndex();
|
|
11114
11164
|
this.purgeOldArchives(oldFileId, 3);
|
|
11115
|
-
console.log(`[session] Rotated main: ${oldFileId}.jsonl \u2192 ${
|
|
11165
|
+
console.log(`[session] Rotated main: ${oldFileId}.jsonl \u2192 ${path15.basename(newPath)}`);
|
|
11116
11166
|
}
|
|
11117
11167
|
// === 迁移 ===
|
|
11118
11168
|
/** 迁移旧索引:session-index.json 里有 "discord:xxx" 格式的 key 时,生成 UUID 替换 */
|
|
@@ -11177,15 +11227,15 @@ var init_session_manager = __esm({
|
|
|
11177
11227
|
});
|
|
11178
11228
|
|
|
11179
11229
|
// src/tools/read.ts
|
|
11180
|
-
import * as
|
|
11181
|
-
import * as
|
|
11230
|
+
import * as fs15 from "node:fs";
|
|
11231
|
+
import * as path16 from "node:path";
|
|
11182
11232
|
function isBlockedDevicePath(filePath) {
|
|
11183
11233
|
if (BLOCKED_DEVICE_PATHS.has(filePath)) return true;
|
|
11184
11234
|
if (filePath.startsWith("/proc/") && (filePath.endsWith("/fd/0") || filePath.endsWith("/fd/1") || filePath.endsWith("/fd/2"))) return true;
|
|
11185
11235
|
return false;
|
|
11186
11236
|
}
|
|
11187
11237
|
function checkReadLoop(filePath, offset, limit) {
|
|
11188
|
-
const stat4 =
|
|
11238
|
+
const stat4 = fs15.statSync(filePath);
|
|
11189
11239
|
const mtimeMs = stat4.mtimeMs;
|
|
11190
11240
|
const prev = readHistory.get(filePath);
|
|
11191
11241
|
if (prev && prev.offset === offset && prev.limit === limit && prev.mtimeMs === mtimeMs) {
|
|
@@ -11199,19 +11249,19 @@ function checkReadLoop(filePath, offset, limit) {
|
|
|
11199
11249
|
return null;
|
|
11200
11250
|
}
|
|
11201
11251
|
function readFileContent(filePath) {
|
|
11202
|
-
const fd =
|
|
11252
|
+
const fd = fs15.openSync(filePath, "r");
|
|
11203
11253
|
const bom = Buffer.alloc(2);
|
|
11204
|
-
|
|
11205
|
-
|
|
11254
|
+
fs15.readSync(fd, bom, 0, 2, 0);
|
|
11255
|
+
fs15.closeSync(fd);
|
|
11206
11256
|
let encoding = "utf8";
|
|
11207
11257
|
if (bom[0] === 255 && bom[1] === 254) {
|
|
11208
11258
|
encoding = "utf16le";
|
|
11209
11259
|
}
|
|
11210
|
-
const stat4 =
|
|
11260
|
+
const stat4 = fs15.statSync(filePath);
|
|
11211
11261
|
if (stat4.size > MAX_FILE_SIZE) {
|
|
11212
11262
|
throw new Error(`\u6587\u4EF6\u592A\u5927 (${(stat4.size / 1024).toFixed(1)}KB)\uFF0C\u8D85\u8FC7 ${MAX_FILE_SIZE / 1024}KB \u9650\u5236\u3002\u8BF7\u4F7F\u7528 offset + limit \u5206\u6BB5\u8BFB\u53D6\u3002`);
|
|
11213
11263
|
}
|
|
11214
|
-
const raw =
|
|
11264
|
+
const raw = fs15.readFileSync(filePath, encoding);
|
|
11215
11265
|
const content = raw.toString().replaceAll("\r\n", "\n");
|
|
11216
11266
|
return { content, encoding };
|
|
11217
11267
|
}
|
|
@@ -11353,11 +11403,11 @@ Usage:
|
|
|
11353
11403
|
} catch (e) {
|
|
11354
11404
|
return { content: e.message, isError: true };
|
|
11355
11405
|
}
|
|
11356
|
-
if (!
|
|
11406
|
+
if (!fs15.existsSync(filePath)) {
|
|
11357
11407
|
return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
|
|
11358
11408
|
}
|
|
11359
|
-
const stat4 =
|
|
11360
|
-
const baseName =
|
|
11409
|
+
const stat4 = fs15.statSync(filePath);
|
|
11410
|
+
const baseName = path16.basename(filePath).toUpperCase();
|
|
11361
11411
|
if (BLOCKED_BASENAMES.has(baseName)) {
|
|
11362
11412
|
return { content: `\u8BBE\u5907\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6: ${filePath}`, isError: true };
|
|
11363
11413
|
}
|
|
@@ -11365,11 +11415,11 @@ Usage:
|
|
|
11365
11415
|
return { content: `\u8BBE\u5907\u6587\u4EF6\u4F1A\u963B\u585E\u6216\u4EA7\u751F\u65E0\u9650\u8F93\u51FA: ${filePath}`, isError: true };
|
|
11366
11416
|
}
|
|
11367
11417
|
if (stat4.isDirectory()) {
|
|
11368
|
-
const entries2 =
|
|
11418
|
+
const entries2 = fs15.readdirSync(filePath);
|
|
11369
11419
|
const items = entries2.map((e) => {
|
|
11370
|
-
const full =
|
|
11420
|
+
const full = path16.join(filePath, e);
|
|
11371
11421
|
try {
|
|
11372
|
-
const s =
|
|
11422
|
+
const s = fs15.statSync(full);
|
|
11373
11423
|
return s.isDirectory() ? `${e}/` : e;
|
|
11374
11424
|
} catch {
|
|
11375
11425
|
return e;
|
|
@@ -11378,7 +11428,7 @@ Usage:
|
|
|
11378
11428
|
return { content: `\u76EE\u5F55 (${entries2.length} \u9879):
|
|
11379
11429
|
${items.join("\n")}` };
|
|
11380
11430
|
}
|
|
11381
|
-
const ext =
|
|
11431
|
+
const ext = path16.extname(filePath).toLowerCase();
|
|
11382
11432
|
if (BINARY_EXTENSIONS.has(ext)) {
|
|
11383
11433
|
return { content: `\u4E8C\u8FDB\u5236\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6 (${ext}): ${filePath}`, isError: true };
|
|
11384
11434
|
}
|
|
@@ -11425,22 +11475,22 @@ ${result}` : result };
|
|
|
11425
11475
|
});
|
|
11426
11476
|
|
|
11427
11477
|
// src/tools/write.ts
|
|
11428
|
-
import * as
|
|
11429
|
-
import * as
|
|
11478
|
+
import * as fs16 from "node:fs";
|
|
11479
|
+
import * as path17 from "node:path";
|
|
11430
11480
|
function isBlockedPath(filePath) {
|
|
11431
11481
|
return BLOCKED_PATTERNS.some((p) => p.test(filePath));
|
|
11432
11482
|
}
|
|
11433
11483
|
function atomicWrite(filePath, content) {
|
|
11434
11484
|
const tmpPath = filePath + ".tmp." + Date.now() + ".write";
|
|
11435
|
-
|
|
11485
|
+
fs16.writeFileSync(tmpPath, content, "utf-8");
|
|
11436
11486
|
try {
|
|
11437
|
-
|
|
11487
|
+
fs16.renameSync(tmpPath, filePath);
|
|
11438
11488
|
} catch (e) {
|
|
11439
11489
|
try {
|
|
11440
|
-
|
|
11490
|
+
fs16.unlinkSync(tmpPath);
|
|
11441
11491
|
} catch {
|
|
11442
11492
|
}
|
|
11443
|
-
|
|
11493
|
+
fs16.writeFileSync(filePath, content, "utf-8");
|
|
11444
11494
|
}
|
|
11445
11495
|
}
|
|
11446
11496
|
function simpleDiff(oldContent, newContent) {
|
|
@@ -11534,15 +11584,15 @@ Usage:
|
|
|
11534
11584
|
}
|
|
11535
11585
|
const rawContent = args.content;
|
|
11536
11586
|
const content = rawContent.replaceAll("\r\n", "\n");
|
|
11537
|
-
if (
|
|
11587
|
+
if (fs16.existsSync(filePath) && fs16.statSync(filePath).isDirectory()) {
|
|
11538
11588
|
return { content: `\u8DEF\u5F84\u662F\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6: ${filePath}`, isError: true };
|
|
11539
11589
|
}
|
|
11540
11590
|
let oldContent = null;
|
|
11541
11591
|
let isCreate = true;
|
|
11542
|
-
if (
|
|
11592
|
+
if (fs16.existsSync(filePath)) {
|
|
11543
11593
|
isCreate = false;
|
|
11544
11594
|
try {
|
|
11545
|
-
oldContent =
|
|
11595
|
+
oldContent = fs16.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
|
|
11546
11596
|
} catch {
|
|
11547
11597
|
isCreate = true;
|
|
11548
11598
|
}
|
|
@@ -11558,10 +11608,10 @@ Usage:
|
|
|
11558
11608
|
isError: true
|
|
11559
11609
|
};
|
|
11560
11610
|
}
|
|
11561
|
-
const currentStat =
|
|
11611
|
+
const currentStat = fs16.statSync(filePath);
|
|
11562
11612
|
const lastWriteTime = Math.floor(currentStat.mtimeMs);
|
|
11563
11613
|
if (lastWriteTime > readState.timestamp) {
|
|
11564
|
-
const currentContent =
|
|
11614
|
+
const currentContent = fs16.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
|
|
11565
11615
|
if (currentContent !== oldContent) {
|
|
11566
11616
|
return {
|
|
11567
11617
|
content: `\u6587\u4EF6\u5728\u8BFB\u53D6\u540E\u88AB\u4FEE\u6539\u3002\u8BF7\u5148\u91CD\u65B0\u8BFB\u53D6\u6587\u4EF6\u518D\u5199\u5165: ${filePath}`,
|
|
@@ -11570,9 +11620,9 @@ Usage:
|
|
|
11570
11620
|
}
|
|
11571
11621
|
}
|
|
11572
11622
|
}
|
|
11573
|
-
const dir =
|
|
11623
|
+
const dir = path17.dirname(filePath);
|
|
11574
11624
|
try {
|
|
11575
|
-
|
|
11625
|
+
fs16.mkdirSync(dir, { recursive: true });
|
|
11576
11626
|
} catch (e) {
|
|
11577
11627
|
return { content: `\u65E0\u6CD5\u521B\u5EFA\u76EE\u5F55: ${dir} \u2014 ${e.message}`, isError: true };
|
|
11578
11628
|
}
|
|
@@ -11581,11 +11631,11 @@ Usage:
|
|
|
11581
11631
|
} catch (e) {
|
|
11582
11632
|
return { content: `\u5199\u5165\u5931\u8D25: ${e.message}`, isError: true };
|
|
11583
11633
|
}
|
|
11584
|
-
readFileState.set(filePath, { timestamp:
|
|
11634
|
+
readFileState.set(filePath, { timestamp: fs16.statSync(filePath).mtimeMs });
|
|
11585
11635
|
const action = isCreate ? "\u521B\u5EFA" : "\u66F4\u65B0";
|
|
11586
11636
|
const lines = content.split("\n").length;
|
|
11587
11637
|
const chars = content.length;
|
|
11588
|
-
const stat4 =
|
|
11638
|
+
const stat4 = fs16.statSync(filePath);
|
|
11589
11639
|
let diff = "";
|
|
11590
11640
|
if (!isCreate && oldContent !== null) {
|
|
11591
11641
|
diff = `
|
|
@@ -11604,8 +11654,8 @@ ${simpleDiff(oldContent, content)}`;
|
|
|
11604
11654
|
});
|
|
11605
11655
|
|
|
11606
11656
|
// src/tools/edit.ts
|
|
11607
|
-
import * as
|
|
11608
|
-
import * as
|
|
11657
|
+
import * as fs17 from "node:fs";
|
|
11658
|
+
import * as path18 from "node:path";
|
|
11609
11659
|
function normalizeQuotes(str) {
|
|
11610
11660
|
return str.replaceAll(LEFT_SINGLE_CURLY, "'").replaceAll(RIGHT_SINGLE_CURLY, "'").replaceAll(LEFT_DOUBLE_CURLY, '"').replaceAll(RIGHT_DOUBLE_CURLY, '"');
|
|
11611
11661
|
}
|
|
@@ -11758,7 +11808,7 @@ Usage:
|
|
|
11758
11808
|
}
|
|
11759
11809
|
let fileContent = null;
|
|
11760
11810
|
try {
|
|
11761
|
-
const stat4 =
|
|
11811
|
+
const stat4 = fs17.statSync(filePath);
|
|
11762
11812
|
if (stat4.isDirectory()) {
|
|
11763
11813
|
return { content: `\u8DEF\u5F84\u662F\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6: ${filePath}`, isError: true };
|
|
11764
11814
|
}
|
|
@@ -11768,21 +11818,21 @@ Usage:
|
|
|
11768
11818
|
} catch (e) {
|
|
11769
11819
|
if (e.code === "ENOENT") {
|
|
11770
11820
|
if (oldString === "") {
|
|
11771
|
-
const dir =
|
|
11772
|
-
|
|
11773
|
-
|
|
11774
|
-
readFileState.set(filePath, { timestamp:
|
|
11821
|
+
const dir = path18.dirname(filePath);
|
|
11822
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
11823
|
+
fs17.writeFileSync(filePath, newString, "utf-8");
|
|
11824
|
+
readFileState.set(filePath, { timestamp: fs17.statSync(filePath).mtimeMs });
|
|
11775
11825
|
return { content: `\u521B\u5EFA\u6587\u4EF6: ${filePath} (${newString.split("\n").length} \u884C)` };
|
|
11776
11826
|
}
|
|
11777
11827
|
return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
|
|
11778
11828
|
}
|
|
11779
11829
|
throw e;
|
|
11780
11830
|
}
|
|
11781
|
-
const rawContent =
|
|
11831
|
+
const rawContent = fs17.readFileSync(filePath, "utf-8");
|
|
11782
11832
|
fileContent = rawContent.replaceAll("\r\n", "\n");
|
|
11783
11833
|
if (oldString === "" && fileContent.trim() === "") {
|
|
11784
|
-
|
|
11785
|
-
readFileState.set(filePath, { timestamp:
|
|
11834
|
+
fs17.writeFileSync(filePath, newString, "utf-8");
|
|
11835
|
+
readFileState.set(filePath, { timestamp: fs17.statSync(filePath).mtimeMs });
|
|
11786
11836
|
return { content: `\u5199\u5165\u7A7A\u6587\u4EF6: ${filePath} (${newString.split("\n").length} \u884C)` };
|
|
11787
11837
|
}
|
|
11788
11838
|
const readState = readFileState.get(filePath);
|
|
@@ -11792,11 +11842,11 @@ Usage:
|
|
|
11792
11842
|
isError: true
|
|
11793
11843
|
};
|
|
11794
11844
|
}
|
|
11795
|
-
const currentStat =
|
|
11845
|
+
const currentStat = fs17.statSync(filePath);
|
|
11796
11846
|
const lastWriteTime = Math.floor(currentStat.mtimeMs);
|
|
11797
11847
|
if (lastWriteTime > readState.timestamp) {
|
|
11798
11848
|
if (fileContent !== rawContent.replaceAll("\r\n", "\n")) {
|
|
11799
|
-
if (fileContent !==
|
|
11849
|
+
if (fileContent !== fs17.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n")) {
|
|
11800
11850
|
return {
|
|
11801
11851
|
content: `\u6587\u4EF6\u5728\u8BFB\u53D6\u540E\u88AB\u4FEE\u6539\u3002\u8BF7\u5148\u91CD\u65B0\u8BFB\u53D6\u6587\u4EF6\u518D\u7F16\u8F91: ${filePath}`,
|
|
11802
11852
|
isError: true
|
|
@@ -11828,8 +11878,8 @@ ${preview}
|
|
|
11828
11878
|
const actualNewString = preserveQuoteStyle(oldString, actualOldString, newString);
|
|
11829
11879
|
const diffView = generateEditDiff(fileContent, actualOldString, actualNewString);
|
|
11830
11880
|
const newContent = applyEditToFile(fileContent, actualOldString, actualNewString, replaceAll);
|
|
11831
|
-
|
|
11832
|
-
readFileState.set(filePath, { timestamp:
|
|
11881
|
+
fs17.writeFileSync(filePath, newContent, "utf-8");
|
|
11882
|
+
readFileState.set(filePath, { timestamp: fs17.statSync(filePath).mtimeMs });
|
|
11833
11883
|
const strategy = actualOldString === oldString ? "\u7CBE\u786E\u5339\u914D" : "\u5F15\u53F7\u89C4\u8303\u5316\u5339\u914D";
|
|
11834
11884
|
const count = replaceAll ? matchCount : 1;
|
|
11835
11885
|
const diff = `${oldString.length}\u2192${newString.length}\u5B57\u7B26`;
|
|
@@ -11846,8 +11896,8 @@ ${diffView}`
|
|
|
11846
11896
|
});
|
|
11847
11897
|
|
|
11848
11898
|
// src/tools/glob.ts
|
|
11849
|
-
import * as
|
|
11850
|
-
import * as
|
|
11899
|
+
import * as fs18 from "node:fs";
|
|
11900
|
+
import * as path19 from "node:path";
|
|
11851
11901
|
function globMatch(pattern, filename) {
|
|
11852
11902
|
const regexStr = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]").replace(/\{\{GLOBSTAR\}\}/g, ".*");
|
|
11853
11903
|
try {
|
|
@@ -11867,18 +11917,18 @@ function findFiles(dir, pattern, limit, baseDir) {
|
|
|
11867
11917
|
}
|
|
11868
11918
|
let entries2;
|
|
11869
11919
|
try {
|
|
11870
|
-
entries2 =
|
|
11920
|
+
entries2 = fs18.readdirSync(currentDir, { withFileTypes: true });
|
|
11871
11921
|
} catch {
|
|
11872
11922
|
return;
|
|
11873
11923
|
}
|
|
11874
11924
|
for (const entry of entries2) {
|
|
11875
11925
|
if (truncated) return;
|
|
11876
|
-
const fullPath =
|
|
11926
|
+
const fullPath = path19.join(currentDir, entry.name);
|
|
11877
11927
|
if (entry.isDirectory()) {
|
|
11878
11928
|
if (VCS_DIRS.has(entry.name)) continue;
|
|
11879
11929
|
walk(fullPath);
|
|
11880
11930
|
} else if (entry.isFile()) {
|
|
11881
|
-
const relativePath =
|
|
11931
|
+
const relativePath = path19.relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
11882
11932
|
const patternsToTry = [pattern];
|
|
11883
11933
|
if (pattern.startsWith("**/")) {
|
|
11884
11934
|
patternsToTry.push(pattern.slice(3));
|
|
@@ -11888,7 +11938,7 @@ function findFiles(dir, pattern, limit, baseDir) {
|
|
|
11888
11938
|
);
|
|
11889
11939
|
if (matched) {
|
|
11890
11940
|
try {
|
|
11891
|
-
const stat4 =
|
|
11941
|
+
const stat4 = fs18.statSync(fullPath);
|
|
11892
11942
|
results.push({ path: fullPath, mtimeMs: stat4.mtimeMs });
|
|
11893
11943
|
} catch {
|
|
11894
11944
|
}
|
|
@@ -11905,7 +11955,7 @@ function findFiles(dir, pattern, limit, baseDir) {
|
|
|
11905
11955
|
};
|
|
11906
11956
|
}
|
|
11907
11957
|
function toRelativePath(absolutePath, cwd) {
|
|
11908
|
-
if (absolutePath.startsWith(cwd +
|
|
11958
|
+
if (absolutePath.startsWith(cwd + path19.sep)) {
|
|
11909
11959
|
return absolutePath.slice(cwd.length + 1);
|
|
11910
11960
|
}
|
|
11911
11961
|
return absolutePath;
|
|
@@ -11938,10 +11988,10 @@ var init_glob = __esm({
|
|
|
11938
11988
|
const searchPath = args.path ? resolvePath(args.path, ctx.workspace) : ctx.workspace;
|
|
11939
11989
|
const pattern = args.pattern;
|
|
11940
11990
|
const limit = args.limit || DEFAULT_LIMIT;
|
|
11941
|
-
if (!
|
|
11991
|
+
if (!fs18.existsSync(searchPath)) {
|
|
11942
11992
|
return { content: `\u76EE\u5F55\u4E0D\u5B58\u5728: ${searchPath}`, isError: true };
|
|
11943
11993
|
}
|
|
11944
|
-
if (!
|
|
11994
|
+
if (!fs18.statSync(searchPath).isDirectory()) {
|
|
11945
11995
|
return { content: `\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55: ${searchPath}`, isError: true };
|
|
11946
11996
|
}
|
|
11947
11997
|
const start = Date.now();
|
|
@@ -11965,7 +12015,7 @@ ${filenames.join("\n")}${truncatedNote}`
|
|
|
11965
12015
|
|
|
11966
12016
|
// src/tools/grep.ts
|
|
11967
12017
|
import { execFile } from "node:child_process";
|
|
11968
|
-
import * as
|
|
12018
|
+
import * as path20 from "node:path";
|
|
11969
12019
|
function ripGrep(args, searchPath, signal) {
|
|
11970
12020
|
return new Promise((resolve12) => {
|
|
11971
12021
|
const fullArgs = [...args, searchPath];
|
|
@@ -11997,7 +12047,7 @@ function applyHeadLimit(items, limit, offset = 0) {
|
|
|
11997
12047
|
};
|
|
11998
12048
|
}
|
|
11999
12049
|
function toRelativePath2(absolutePath, cwd) {
|
|
12000
|
-
if (absolutePath.startsWith(cwd +
|
|
12050
|
+
if (absolutePath.startsWith(cwd + path20.sep)) {
|
|
12001
12051
|
return absolutePath.slice(cwd.length + 1);
|
|
12002
12052
|
}
|
|
12003
12053
|
if (absolutePath.startsWith(cwd)) {
|
|
@@ -13247,7 +13297,7 @@ async function acquireLock(inboxPath) {
|
|
|
13247
13297
|
for (let i = 0; i < LOCK_RETRIES; i++) {
|
|
13248
13298
|
if (await isLockStale(lockPath2)) {
|
|
13249
13299
|
try {
|
|
13250
|
-
await import("node:fs/promises").then((
|
|
13300
|
+
await import("node:fs/promises").then((fs44) => fs44.rm(lockPath2, { force: true }));
|
|
13251
13301
|
} catch {
|
|
13252
13302
|
}
|
|
13253
13303
|
}
|
|
@@ -13255,7 +13305,7 @@ async function acquireLock(inboxPath) {
|
|
|
13255
13305
|
await writeFile2(lockPath2, `${process.pid}-${Date.now()}`, { encoding: "utf-8", flag: "wx" });
|
|
13256
13306
|
return async () => {
|
|
13257
13307
|
try {
|
|
13258
|
-
await import("node:fs/promises").then((
|
|
13308
|
+
await import("node:fs/promises").then((fs44) => fs44.rm(lockPath2, { force: true }));
|
|
13259
13309
|
} catch {
|
|
13260
13310
|
}
|
|
13261
13311
|
};
|
|
@@ -14498,12 +14548,12 @@ Examples:
|
|
|
14498
14548
|
});
|
|
14499
14549
|
|
|
14500
14550
|
// src/tools/msg-husband.ts
|
|
14501
|
-
import
|
|
14502
|
-
import
|
|
14551
|
+
import fs19 from "node:fs";
|
|
14552
|
+
import path21 from "node:path";
|
|
14503
14553
|
function getHusbandFeishuId(workspace) {
|
|
14504
|
-
const contactsPath =
|
|
14554
|
+
const contactsPath = path21.join(workspace, "prompts", "contacts.md");
|
|
14505
14555
|
try {
|
|
14506
|
-
const text =
|
|
14556
|
+
const text = fs19.readFileSync(contactsPath, "utf-8");
|
|
14507
14557
|
const m = text.match(/\|\s*翀哥\s*\|\s*(ou_[a-f0-9]+)\s*\|/);
|
|
14508
14558
|
return m ? m[1] : null;
|
|
14509
14559
|
} catch {
|
|
@@ -14656,8 +14706,8 @@ Examples:
|
|
|
14656
14706
|
if (!to && !resolvedChannelId) {
|
|
14657
14707
|
return { content: "to \u548C channel_id \u4E0D\u80FD\u540C\u65F6\u4E3A\u7A7A\uFF0C\u4E14\u6CA1\u6709\u53EF\u7528\u7684\u6765\u6E90\u9891\u9053", isError: true };
|
|
14658
14708
|
}
|
|
14659
|
-
const
|
|
14660
|
-
if (!
|
|
14709
|
+
const fs44 = await import("node:fs");
|
|
14710
|
+
if (!fs44.existsSync(filePath)) {
|
|
14661
14711
|
return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6\u4E0D\u5B58\u5728 ${filePath}`, isError: true };
|
|
14662
14712
|
}
|
|
14663
14713
|
const toIds = to ? to.split(",").map((s) => s.trim()).filter(Boolean) : [];
|
|
@@ -14685,7 +14735,7 @@ Examples:
|
|
|
14685
14735
|
md: "text/markdown"
|
|
14686
14736
|
};
|
|
14687
14737
|
const mimeType = mimeTypeMap[ext] || "application/octet-stream";
|
|
14688
|
-
const stat4 =
|
|
14738
|
+
const stat4 = fs44.statSync(filePath);
|
|
14689
14739
|
const sizeMB = stat4.size / 1024 / 1024;
|
|
14690
14740
|
if (sizeMB > 25) {
|
|
14691
14741
|
return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6 ${sizeMB.toFixed(1)}MB \u8D85\u8FC7 Discord 25MB \u9650\u5236`, isError: true };
|
|
@@ -14714,8 +14764,8 @@ Examples:
|
|
|
14714
14764
|
});
|
|
14715
14765
|
|
|
14716
14766
|
// src/tools/my-eyes.ts
|
|
14717
|
-
import * as
|
|
14718
|
-
import * as
|
|
14767
|
+
import * as fs20 from "node:fs";
|
|
14768
|
+
import * as path22 from "node:path";
|
|
14719
14769
|
function extractUsage(data) {
|
|
14720
14770
|
try {
|
|
14721
14771
|
const u = data?.usage ?? data?.usageMetadata;
|
|
@@ -14730,9 +14780,9 @@ function extractUsage(data) {
|
|
|
14730
14780
|
}
|
|
14731
14781
|
}
|
|
14732
14782
|
function resolveLatestImage(specifiedPath, mediaDir) {
|
|
14733
|
-
if (specifiedPath &&
|
|
14734
|
-
if (!
|
|
14735
|
-
const files =
|
|
14783
|
+
if (specifiedPath && fs20.existsSync(specifiedPath)) return specifiedPath;
|
|
14784
|
+
if (!fs20.existsSync(mediaDir)) return null;
|
|
14785
|
+
const files = fs20.readdirSync(mediaDir).filter((f) => /\.(jpg|jpeg|png|webp|gif|bmp|mp4|mov)$/i.test(f)).map((f) => ({ name: f, p: path22.join(mediaDir, f), mtime: fs20.statSync(path22.join(mediaDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
14736
14786
|
return files[0]?.p || null;
|
|
14737
14787
|
}
|
|
14738
14788
|
var MIME_MAP, VIDEO_EXT, VIDEO_MAX_BYTES;
|
|
@@ -14780,15 +14830,15 @@ var init_my_eyes = __esm({
|
|
|
14780
14830
|
if (!provider?.streamChat) {
|
|
14781
14831
|
return { content: "Error: provider \u4E0D\u53EF\u7528\u3002", isError: true };
|
|
14782
14832
|
}
|
|
14783
|
-
const mediaDir =
|
|
14833
|
+
const mediaDir = path22.join(ctx.stateDir, "media", "inbound");
|
|
14784
14834
|
const imagePath = resolveLatestImage(args.image_path, mediaDir);
|
|
14785
14835
|
if (!imagePath) {
|
|
14786
14836
|
return { content: "Error: no image found. Provide image_path or ensure media/inbound has images.", isError: true };
|
|
14787
14837
|
}
|
|
14788
14838
|
const rawPrompt = args.prompt?.trim() || "\u63CF\u8FF0\u8FD9\u5F20\u56FE\u7247\u7684\u5185\u5BB9";
|
|
14789
|
-
const ext =
|
|
14839
|
+
const ext = path22.extname(imagePath).toLowerCase();
|
|
14790
14840
|
if (VIDEO_EXT.test(imagePath)) {
|
|
14791
|
-
const stat4 =
|
|
14841
|
+
const stat4 = fs20.statSync(imagePath);
|
|
14792
14842
|
if (stat4.size > VIDEO_MAX_BYTES) {
|
|
14793
14843
|
return { content: `Error: video too large (${(stat4.size / 1e6).toFixed(1)}MB > ${(VIDEO_MAX_BYTES / 1e6).toFixed(0)}MB). Compress or trim first.`, isError: true };
|
|
14794
14844
|
}
|
|
@@ -14802,7 +14852,7 @@ var init_my_eyes = __esm({
|
|
|
14802
14852
|
}
|
|
14803
14853
|
const explicit = liveConfig.get("tools.my_eyes.videoBaseUrl");
|
|
14804
14854
|
const baseUrl = explicit || vProviderCfg.baseUrl.replace(/\/anthropic\/?$/, "/v1").replace(/\/$/, "");
|
|
14805
|
-
const vidB64 =
|
|
14855
|
+
const vidB64 = fs20.readFileSync(imagePath).toString("base64");
|
|
14806
14856
|
try {
|
|
14807
14857
|
const res = await fetch(`${baseUrl}/chat/completions`, {
|
|
14808
14858
|
method: "POST",
|
|
@@ -14833,7 +14883,7 @@ var init_my_eyes = __esm({
|
|
|
14833
14883
|
}
|
|
14834
14884
|
}
|
|
14835
14885
|
const mime = MIME_MAP[ext] || "jpeg";
|
|
14836
|
-
const imgB64 =
|
|
14886
|
+
const imgB64 = fs20.readFileSync(imagePath).toString("base64");
|
|
14837
14887
|
const userMsg = {
|
|
14838
14888
|
role: "user",
|
|
14839
14889
|
content: [
|
|
@@ -14868,7 +14918,7 @@ var init_my_eyes = __esm({
|
|
|
14868
14918
|
});
|
|
14869
14919
|
|
|
14870
14920
|
// src/tools/opus-encoder.ts
|
|
14871
|
-
import * as
|
|
14921
|
+
import * as fs21 from "node:fs";
|
|
14872
14922
|
function oggCrc32(buf) {
|
|
14873
14923
|
let crc = 0;
|
|
14874
14924
|
for (let i = 0; i < buf.length; i++) {
|
|
@@ -14928,7 +14978,7 @@ async function wavToOggOpusNative(wavPath) {
|
|
|
14928
14978
|
const mod = await import("@discordjs/opus");
|
|
14929
14979
|
const OpusEncoder = mod.OpusEncoder ?? mod.default?.OpusEncoder;
|
|
14930
14980
|
if (!OpusEncoder) throw new Error("@discordjs/opus export shape unexpected");
|
|
14931
|
-
const wav = parseWav(
|
|
14981
|
+
const wav = parseWav(fs21.readFileSync(wavPath));
|
|
14932
14982
|
if (wav.channels !== 1) throw new Error(`unsupported ${wav.channels}ch (need mono)`);
|
|
14933
14983
|
if (!NATIVE_RATES.includes(wav.sampleRate)) throw new Error(`unsupported rate ${wav.sampleRate}`);
|
|
14934
14984
|
if (wav.pcm.length === 0) throw new Error("empty pcm data");
|
|
@@ -14964,7 +15014,7 @@ async function wavToOggOpusNative(wavPath) {
|
|
|
14964
15014
|
}
|
|
14965
15015
|
ogg.page(cur, pageGranule, false, true);
|
|
14966
15016
|
const oggPath = wavPath.replace(/\.wav$/, ".ogg");
|
|
14967
|
-
|
|
15017
|
+
fs21.writeFileSync(oggPath, ogg.finish());
|
|
14968
15018
|
return oggPath;
|
|
14969
15019
|
}
|
|
14970
15020
|
var FRAME_MS, PRESKIP_48K, OPUS_RATE, NATIVE_RATES, BITRATE, CRC_TABLE, OggWriter;
|
|
@@ -15072,8 +15122,8 @@ var init_voice_chat_tts_daemon = __esm({
|
|
|
15072
15122
|
import { execFile as execFile2 } from "node:child_process";
|
|
15073
15123
|
import { createInterface as createInterface2 } from "node:readline";
|
|
15074
15124
|
import { promisify } from "node:util";
|
|
15075
|
-
import * as
|
|
15076
|
-
import * as
|
|
15125
|
+
import * as fs22 from "node:fs";
|
|
15126
|
+
import * as path23 from "node:path";
|
|
15077
15127
|
import * as os4 from "node:os";
|
|
15078
15128
|
function wavDurationSec(buf) {
|
|
15079
15129
|
if (buf.length < 12 || buf.toString("ascii", 0, 4) !== "RIFF" || buf.toString("ascii", 8, 12) !== "WAVE") {
|
|
@@ -15128,8 +15178,8 @@ function resolvePython(configuredPath) {
|
|
|
15128
15178
|
// LOCALAPPDATA 缺席(非 Windows / 精简环境)时**不加这两个候选**:
|
|
15129
15179
|
// 拼出来会是相对路径 'Microsoft/WindowsApps/python.exe',那可能撞上 cwd 里的东西。
|
|
15130
15180
|
...localAppData ? [
|
|
15131
|
-
|
|
15132
|
-
|
|
15181
|
+
path23.join(localAppData, "Microsoft", "WindowsApps", "python3.exe"),
|
|
15182
|
+
path23.join(localAppData, "Microsoft", "WindowsApps", "python.exe")
|
|
15133
15183
|
] : []
|
|
15134
15184
|
];
|
|
15135
15185
|
for (const c of candidates) {
|
|
@@ -15149,8 +15199,8 @@ async function ttsCosyvoice(text, apiKey, model, voice, workspaceId, instruction
|
|
|
15149
15199
|
}
|
|
15150
15200
|
async function ttsCosyvoiceStream(text, cfg, onChunk) {
|
|
15151
15201
|
const { apiKey, model, voice, workspaceId, instruction } = cfg;
|
|
15152
|
-
|
|
15153
|
-
const output =
|
|
15202
|
+
fs22.mkdirSync(VOICE_DIR, { recursive: true });
|
|
15203
|
+
const output = path23.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
15154
15204
|
const script = `
|
|
15155
15205
|
import sys, json, base64, threading
|
|
15156
15206
|
import dashscope
|
|
@@ -15235,7 +15285,7 @@ print('EOS')
|
|
|
15235
15285
|
header.writeUInt16LE(16, 34);
|
|
15236
15286
|
header.write("data", 36);
|
|
15237
15287
|
header.writeUInt32LE(pcm.length, 40);
|
|
15238
|
-
|
|
15288
|
+
fs22.writeFileSync(output, Buffer.concat([header, pcm]));
|
|
15239
15289
|
return output;
|
|
15240
15290
|
}
|
|
15241
15291
|
async function ttsQwen3Local(text, cfg, onChunk) {
|
|
@@ -15287,9 +15337,9 @@ async function ttsQwen3Opus(text, cfg) {
|
|
|
15287
15337
|
const ogg = Buffer.from(await res.arrayBuffer());
|
|
15288
15338
|
if (ogg.length < 20) throw new Error("qwen3-3060 opus: empty output");
|
|
15289
15339
|
const durationMs = parseInt(res.headers.get("x-duration-ms") || "0", 10);
|
|
15290
|
-
|
|
15291
|
-
const oggPath =
|
|
15292
|
-
|
|
15340
|
+
fs22.mkdirSync(VOICE_DIR, { recursive: true });
|
|
15341
|
+
const oggPath = path23.join(VOICE_DIR, `tts_${Date.now()}.ogg`);
|
|
15342
|
+
fs22.writeFileSync(oggPath, ogg);
|
|
15293
15343
|
return { oggPath, durationMs };
|
|
15294
15344
|
}
|
|
15295
15345
|
async function ttsGptsovits(text, c) {
|
|
@@ -15301,8 +15351,8 @@ async function ttsGptsovits(text, c) {
|
|
|
15301
15351
|
"gptsovits \u672A\u914D\u7F6E\uFF1A\u9700\u8981 tools.my_voice \u91CC\u7684 gptsovitsUrl / gptsovitsRefWav / gptsovitsRefText\u3002\u53C2\u8003\u97F3\u9891\u4E0E\u53C2\u8003\u6587\u672C**\u5FC5\u987B\u9010\u5B57\u5BF9\u5E94**\uFF0C\u5426\u5219\u5408\u6210\u51FA\u6765\u7684\u58F0\u97F3\u4F1A\u5E26\u6742\u97F3\uFF080925 \u8E29\u8FC7\u88C1\u574F ref.wav \u7684\u5751\uFF09\u3002"
|
|
15302
15352
|
);
|
|
15303
15353
|
}
|
|
15304
|
-
|
|
15305
|
-
const output =
|
|
15354
|
+
fs22.mkdirSync(VOICE_DIR, { recursive: true });
|
|
15355
|
+
const output = path23.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
15306
15356
|
const params = new URLSearchParams({
|
|
15307
15357
|
text,
|
|
15308
15358
|
text_language: "zh",
|
|
@@ -15313,12 +15363,12 @@ async function ttsGptsovits(text, c) {
|
|
|
15313
15363
|
const res = await fetch(`${url}/?${params}`);
|
|
15314
15364
|
if (!res.ok) throw new Error(`GPT-SoVITS API ${res.status}`);
|
|
15315
15365
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
15316
|
-
|
|
15366
|
+
fs22.writeFileSync(output, buf);
|
|
15317
15367
|
return output;
|
|
15318
15368
|
}
|
|
15319
15369
|
async function ttsEdge(text) {
|
|
15320
|
-
|
|
15321
|
-
const output =
|
|
15370
|
+
fs22.mkdirSync(VOICE_DIR, { recursive: true });
|
|
15371
|
+
const output = path23.join(VOICE_DIR, `tts_${Date.now()}.mp3`);
|
|
15322
15372
|
const script = `
|
|
15323
15373
|
import asyncio, edge_tts, sys
|
|
15324
15374
|
async def main():
|
|
@@ -15356,8 +15406,8 @@ async function synthQwen3(text, _sink) {
|
|
|
15356
15406
|
const pcmChunks = [];
|
|
15357
15407
|
await ttsQwen3Local(text, { url: c.url, voice: c.voice, lang: c.lang }, (pcm2) => pcmChunks.push(pcm2));
|
|
15358
15408
|
const pcm = Buffer.concat(pcmChunks);
|
|
15359
|
-
|
|
15360
|
-
const wavPath =
|
|
15409
|
+
fs22.mkdirSync(VOICE_DIR, { recursive: true });
|
|
15410
|
+
const wavPath = path23.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
15361
15411
|
const header = Buffer.alloc(44);
|
|
15362
15412
|
header.write("RIFF", 0);
|
|
15363
15413
|
header.writeUInt32LE(36 + pcm.length, 4);
|
|
@@ -15372,7 +15422,7 @@ async function synthQwen3(text, _sink) {
|
|
|
15372
15422
|
header.writeUInt16LE(16, 34);
|
|
15373
15423
|
header.write("data", 36);
|
|
15374
15424
|
header.writeUInt32LE(pcm.length, 40);
|
|
15375
|
-
|
|
15425
|
+
fs22.writeFileSync(wavPath, Buffer.concat([header, pcm]));
|
|
15376
15426
|
return { path: wavPath, format: "wav", unit: unit(text), voice: c.voice };
|
|
15377
15427
|
}
|
|
15378
15428
|
}
|
|
@@ -15388,7 +15438,7 @@ var init_impl = __esm({
|
|
|
15388
15438
|
init_well_formed();
|
|
15389
15439
|
init_voice_chat_tts_daemon();
|
|
15390
15440
|
execFileAsync = promisify(execFile2);
|
|
15391
|
-
VOICE_DIR =
|
|
15441
|
+
VOICE_DIR = path23.join(os4.tmpdir(), "engine-voice");
|
|
15392
15442
|
_pyCache = null;
|
|
15393
15443
|
EDGE_VOICE = "zh-CN-XiaoxiaoNeural";
|
|
15394
15444
|
unit = (text) => ({ kind: "chars", amount: [...text].length });
|
|
@@ -15402,9 +15452,9 @@ var init_impl = __esm({
|
|
|
15402
15452
|
});
|
|
15403
15453
|
|
|
15404
15454
|
// src/tools/tts/relay.ts
|
|
15405
|
-
import * as
|
|
15455
|
+
import * as fs23 from "node:fs";
|
|
15406
15456
|
import * as os5 from "node:os";
|
|
15407
|
-
import * as
|
|
15457
|
+
import * as path24 from "node:path";
|
|
15408
15458
|
async function synthRelay(text, cfg) {
|
|
15409
15459
|
const res = await fetchFn(`${cfg.baseUrl}/audio/speech`, {
|
|
15410
15460
|
method: "POST",
|
|
@@ -15422,9 +15472,9 @@ async function synthRelay(text, cfg) {
|
|
|
15422
15472
|
}
|
|
15423
15473
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
15424
15474
|
if (buf.length < 20) throw new Error(`relay tts: \u54CD\u5E94\u4F53\u53EA\u6709 ${buf.length} \u5B57\u8282\uFF0C\u4E0D\u662F\u6709\u6548\u97F3\u9891`);
|
|
15425
|
-
|
|
15426
|
-
const out =
|
|
15427
|
-
|
|
15475
|
+
fs23.mkdirSync(VOICE_DIR2, { recursive: true });
|
|
15476
|
+
const out = path24.join(VOICE_DIR2, `tts_relay_${Date.now()}.mp3`);
|
|
15477
|
+
fs23.writeFileSync(out, buf);
|
|
15428
15478
|
return {
|
|
15429
15479
|
path: out,
|
|
15430
15480
|
format: "mp3",
|
|
@@ -15437,7 +15487,7 @@ var VOICE_DIR2, fetchFn;
|
|
|
15437
15487
|
var init_relay = __esm({
|
|
15438
15488
|
"src/tools/tts/relay.ts"() {
|
|
15439
15489
|
"use strict";
|
|
15440
|
-
VOICE_DIR2 =
|
|
15490
|
+
VOICE_DIR2 = path24.join(os5.tmpdir(), "engine-voice");
|
|
15441
15491
|
fetchFn = fetch;
|
|
15442
15492
|
}
|
|
15443
15493
|
});
|
|
@@ -15562,7 +15612,7 @@ var init_providers = __esm({
|
|
|
15562
15612
|
if (r.warning) console.warn(`[my-voice] ${r.warning}`);
|
|
15563
15613
|
if (!r.voice) {
|
|
15564
15614
|
throw new TtsConfigError(
|
|
15565
|
-
"relay TTS \u7F3A\u97F3\u8272\uFF1Atools.my_voice.voice \u662F\u7A7A\u7684\uFF0C\u4E0A\u6E38\u4F1A\u62D2\u3002\u514D\u8D39\u6863\u88C5\u673A\u5E94\u5DF2\
|
|
15615
|
+
"relay TTS \u7F3A\u97F3\u8272\uFF1Atools.my_voice.voice \u662F\u7A7A\u7684\uFF0C\u4E0A\u6E38\u4F1A\u62D2\u3002\u514D\u8D39\u6863\u88C5\u673A\u5E94\u5DF2\u81EA\u52A8\u586B\u597D\u9ED8\u8BA4\u97F3\u8272\uFF08\u65B0\u88C5\u673A generateConfig / \u8001\u88C5\u673A\u542F\u52A8\u8865\u9F50 / \u5207\u6362\u514D\u8D39\u6863 applyFreeTier \u4E09\u6761\u8DEF\uFF0C\u89C1 cli-init-config.ts \u7684 freeTierVoiceConfig\uFF09\u3002"
|
|
15566
15616
|
);
|
|
15567
15617
|
}
|
|
15568
15618
|
try {
|
|
@@ -15608,13 +15658,13 @@ var init_providers = __esm({
|
|
|
15608
15658
|
});
|
|
15609
15659
|
|
|
15610
15660
|
// src/utils/ffmpeg-path.ts
|
|
15611
|
-
import * as
|
|
15661
|
+
import * as fs24 from "node:fs";
|
|
15612
15662
|
function resolveFfmpegPath() {
|
|
15613
15663
|
const env = (process.env.E7_FFMPEG_PATH || "").trim();
|
|
15614
|
-
if (env &&
|
|
15664
|
+
if (env && fs24.existsSync(env)) return env;
|
|
15615
15665
|
try {
|
|
15616
15666
|
const p = __require("@ffmpeg-installer/ffmpeg")?.path;
|
|
15617
|
-
if (p &&
|
|
15667
|
+
if (p && fs24.existsSync(p)) return p;
|
|
15618
15668
|
} catch {
|
|
15619
15669
|
}
|
|
15620
15670
|
return "ffmpeg";
|
|
@@ -15628,8 +15678,8 @@ var init_ffmpeg_path = __esm({
|
|
|
15628
15678
|
// src/tools/my-voice.ts
|
|
15629
15679
|
import { execFile as execFile3 } from "node:child_process";
|
|
15630
15680
|
import { promisify as promisify2 } from "node:util";
|
|
15631
|
-
import * as
|
|
15632
|
-
import * as
|
|
15681
|
+
import * as fs25 from "node:fs";
|
|
15682
|
+
import * as path25 from "node:path";
|
|
15633
15683
|
async function toWav24kWithDuration(audioPath) {
|
|
15634
15684
|
let wavPath = audioPath;
|
|
15635
15685
|
if (!audioPath.endsWith(".wav")) {
|
|
@@ -15646,15 +15696,15 @@ async function toWav24kWithDuration(audioPath) {
|
|
|
15646
15696
|
"pcm_s16le",
|
|
15647
15697
|
wavPath
|
|
15648
15698
|
], { timeout: 3e4 });
|
|
15649
|
-
if (!
|
|
15699
|
+
if (!fs25.existsSync(wavPath) || fs25.statSync(wavPath).size < 44) {
|
|
15650
15700
|
throw new Error("toWav24k produced empty output");
|
|
15651
15701
|
}
|
|
15652
15702
|
try {
|
|
15653
|
-
|
|
15703
|
+
fs25.unlinkSync(audioPath);
|
|
15654
15704
|
} catch {
|
|
15655
15705
|
}
|
|
15656
15706
|
}
|
|
15657
|
-
const durationSec = wavDurationSec(
|
|
15707
|
+
const durationSec = wavDurationSec(fs25.readFileSync(wavPath));
|
|
15658
15708
|
return { wavPath, durationSec };
|
|
15659
15709
|
}
|
|
15660
15710
|
async function compressWav(wavPath) {
|
|
@@ -15672,7 +15722,7 @@ async function compressWav(wavPath) {
|
|
|
15672
15722
|
"+faststart",
|
|
15673
15723
|
m4aPath
|
|
15674
15724
|
], { timeout: 3e4 });
|
|
15675
|
-
|
|
15725
|
+
fs25.unlinkSync(wavPath);
|
|
15676
15726
|
return m4aPath;
|
|
15677
15727
|
} catch {
|
|
15678
15728
|
return wavPath;
|
|
@@ -15699,10 +15749,10 @@ async function wavToOggOpus(wavPath) {
|
|
|
15699
15749
|
oggPath
|
|
15700
15750
|
], { timeout: 3e4 });
|
|
15701
15751
|
}
|
|
15702
|
-
if (!
|
|
15752
|
+
if (!fs25.existsSync(oggPath) || fs25.statSync(oggPath).size < 20) {
|
|
15703
15753
|
throw new Error("ogg/opus encode produced empty output");
|
|
15704
15754
|
}
|
|
15705
|
-
|
|
15755
|
+
fs25.unlinkSync(wavPath);
|
|
15706
15756
|
return oggPath;
|
|
15707
15757
|
}
|
|
15708
15758
|
async function sendVoiceToMulticaIssue(text, issueId, opts) {
|
|
@@ -15717,7 +15767,7 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
|
|
|
15717
15767
|
} catch (e) {
|
|
15718
15768
|
return { content: `\u8BED\u97F3\u751F\u6210\u5931\u8D25\uFF08headless\u2192multaca\uFF09\uFF1A${e.message}\u3002\u8BF7\u7528\u6587\u5B57\u56DE\u590D\u4EE3\u66FF\u3002`, isError: true };
|
|
15719
15769
|
}
|
|
15720
|
-
if (!audioPath || !
|
|
15770
|
+
if (!audioPath || !fs25.existsSync(audioPath)) {
|
|
15721
15771
|
return { content: "\u8BED\u97F3\u751F\u6210\u5931\u8D25\uFF08headless\u2192multaca\uFF09\uFF1ATTS \u672A\u4EA7\u51FA\u6587\u4EF6\u3002\u8BF7\u7528\u6587\u5B57\u56DE\u590D\u4EE3\u66FF\u3002", isError: true };
|
|
15722
15772
|
}
|
|
15723
15773
|
if (audioPath.endsWith(".wav")) {
|
|
@@ -15727,21 +15777,21 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
|
|
|
15727
15777
|
console.warn(`[my-voice:multaca] opus encode failed (${e.message}), attaching wav`);
|
|
15728
15778
|
}
|
|
15729
15779
|
}
|
|
15730
|
-
const ext =
|
|
15731
|
-
const sizeKB =
|
|
15780
|
+
const ext = path25.extname(audioPath).toLowerCase();
|
|
15781
|
+
const sizeKB = fs25.statSync(audioPath).size / 1024;
|
|
15732
15782
|
const voiceFile = `voice_${Date.now()}${ext}`;
|
|
15733
|
-
const cwdCopy =
|
|
15783
|
+
const cwdCopy = path25.join(process.cwd(), voiceFile);
|
|
15734
15784
|
try {
|
|
15735
|
-
|
|
15785
|
+
fs25.copyFileSync(audioPath, cwdCopy);
|
|
15736
15786
|
} catch (e) {
|
|
15737
15787
|
try {
|
|
15738
|
-
|
|
15788
|
+
fs25.unlinkSync(audioPath);
|
|
15739
15789
|
} catch {
|
|
15740
15790
|
}
|
|
15741
15791
|
return { content: `\u8BED\u97F3\u6302\u8F7D\u5931\u8D25\uFF08\u62F7\u8D1D\u5230\u5DE5\u4F5C\u76EE\u5F55\uFF09\uFF1A${e.message}`, isError: true };
|
|
15742
15792
|
}
|
|
15743
15793
|
try {
|
|
15744
|
-
|
|
15794
|
+
fs25.unlinkSync(audioPath);
|
|
15745
15795
|
} catch {
|
|
15746
15796
|
}
|
|
15747
15797
|
const content = opts.caption || `\u{1F399}\uFE0F \u8BED\u97F3\u6D88\u606F\uFF08${text.length} \u5B57\uFF09`;
|
|
@@ -15770,13 +15820,13 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
|
|
|
15770
15820
|
}
|
|
15771
15821
|
if (!ok) throw new Error(`unexpected CLI output: ${String(stdout).slice(0, 200)}`);
|
|
15772
15822
|
try {
|
|
15773
|
-
|
|
15823
|
+
fs25.unlinkSync(cwdCopy);
|
|
15774
15824
|
} catch {
|
|
15775
15825
|
}
|
|
15776
15826
|
return { content: `Voice sent to multaca issue ${issueId}! (${actualEngine}, ${sizeKB.toFixed(0)}KB, \u9644\u4EF6\u5DF2\u6302\u5230\u8BC4\u8BBA\u2014\u2014\u5728 multaca \u5BA2\u6237\u7AEF\u64AD\u653E)` };
|
|
15777
15827
|
} catch (e) {
|
|
15778
15828
|
try {
|
|
15779
|
-
|
|
15829
|
+
fs25.unlinkSync(cwdCopy);
|
|
15780
15830
|
} catch {
|
|
15781
15831
|
}
|
|
15782
15832
|
return { content: `\u8BED\u97F3\u6302\u5230 multaca issue \u5931\u8D25\uFF1A${e.message}\u3002\u8BF7\u7528\u6587\u5B57\u56DE\u590D\u4EE3\u66FF\u3002`, isError: true };
|
|
@@ -15811,7 +15861,7 @@ var init_my_voice = __esm({
|
|
|
15811
15861
|
description: "TTS engine. relay = 7yi \u4E2D\u8F6C\u7AD9\uFF08\u514D\u8D39\u6863\u9ED8\u8BA4\uFF09\uFF0Ccosyvoice = \u767E\u70BC API\uFF0Cgptsovits = \u672C\u5730\u514B\u9686\uFF0Cqwen3-3060 = \u672C\u5730 GGML\uFF0Cedge = \u515C\u5E95\u3002"
|
|
15812
15862
|
},
|
|
15813
15863
|
channel: { type: "string", enum: ["weixin", "feishu", "discord"], description: "Target channel. Default: current channel." },
|
|
15814
|
-
to: { type: "string", description:
|
|
15864
|
+
to: { type: "string", description: 'Recipient ID, ONLY when sending to someone else. \u5FAE\u4FE1\u683C\u5F0F o\u5F00\u5934@im.wechat\u7ED3\u5C3E\uFF0C\u98DE\u4E66\u683C\u5F0F ou_\u5F00\u5934 open_id\uFF1B\u53D1\u7ED9\u522B\u4EBA\u524D read prompts/contacts.md \u67E5\u6536\u4EF6\u4EBA ID\u3002**\u53D1\u7ED9\u5F53\u524D\u5BF9\u8BDD\u7684\u4EBA\uFF08"\u53D1\u7ED9\u6211/\u53D1\u6761\u8BED\u97F3"\uFF09\u4E0D\u8981\u586B to**\u2014\u2014\u7559\u7A7A\u5373\u53D1\u5F53\u524D\u4F1A\u8BDD\uFF0C\u8FD9\u662F\u9ED8\u8BA4\u4E5F\u662F\u66F4\u7A33\u7684\u8DEF\uFF08\u90E8\u5206\u79DF\u6237\u4F1A\u62D2"\u6309\u7528\u6237 ID \u76F4\u53D1"\uFF0C\u89C1 1001 \u6848\u4F8B\uFF09\u3002multaca \u4EFB\u52A1\u91CC\u4E0D\u9700\u8981\u586B to\u2014\u2014\u8BED\u97F3\u4F1A\u6302\u5230\u5F53\u524D issue \u8BC4\u8BBA\uFF0C\u586B issueId \u6307\u5B9A\u76EE\u6807 issue\u3002' },
|
|
15815
15865
|
issueId: { type: "string", description: 'multaca headless \u4E13\u7528\uFF1A\u76EE\u6807 issue ID\uFF08\u4EFB\u52A1 prompt \u91CC\u7684 "Your assigned issue ID"\uFF09\u3002\u666E\u901A\u98DE\u4E66/\u5FAE\u4FE1\u573A\u666F\u4E0D\u8981\u586B\u3002' },
|
|
15816
15866
|
caption: { type: "string", description: "Optional text to accompany the voice message." }
|
|
15817
15867
|
},
|
|
@@ -15906,10 +15956,10 @@ var init_my_voice = __esm({
|
|
|
15906
15956
|
audioPath = await compressWav(audioPath);
|
|
15907
15957
|
}
|
|
15908
15958
|
}
|
|
15909
|
-
const ext =
|
|
15959
|
+
const ext = path25.extname(audioPath).toLowerCase();
|
|
15910
15960
|
const mimeMap = { ".mp3": "audio/mpeg", ".wav": "audio/wav", ".m4a": "audio/mp4", ".ogg": "audio/ogg", ".silk": "audio/silk" };
|
|
15911
15961
|
const mimeType = mimeMap[ext] || "audio/mpeg";
|
|
15912
|
-
const sizeKB =
|
|
15962
|
+
const sizeKB = fs25.statSync(audioPath).size / 1024;
|
|
15913
15963
|
try {
|
|
15914
15964
|
await mgr.sendFile(resolvedChannel, target, caption, {
|
|
15915
15965
|
path: audioPath,
|
|
@@ -15918,12 +15968,13 @@ var init_my_voice = __esm({
|
|
|
15918
15968
|
...voiceDurationSec !== void 0 ? { voiceDurationSec } : {}
|
|
15919
15969
|
});
|
|
15920
15970
|
try {
|
|
15921
|
-
|
|
15971
|
+
fs25.unlinkSync(audioPath);
|
|
15922
15972
|
} catch {
|
|
15923
15973
|
}
|
|
15924
15974
|
return { content: `Voice sent! (${actualEngine}, ${sizeKB.toFixed(0)}KB, ${resolvedChannel})` };
|
|
15925
15975
|
} catch (err) {
|
|
15926
|
-
|
|
15976
|
+
const toHint = args.to ? '\u3002\u26A0\uFE0F \u8FD9\u6B21\u5E26\u7684\u662F to=\u6536\u4EF6\u4EBA ID\uFF1A\u82E5\u6536\u4EF6\u4EBA\u5C31\u662F**\u5F53\u524D\u5BF9\u8BDD\u7684\u4EBA**\uFF0C\u53BB\u6389 to \u91CD\u8BD5\u2014\u2014\u5F15\u64CE\u4F1A\u53D1\u7ED9\u5F53\u524D\u4F1A\u8BDD\uFF0C\u90E8\u5206\u79DF\u6237\u4F1A\u62D2"\u6309\u7528\u6237 ID \u76F4\u53D1"\uFF08\u98DE\u4E66 230101\uFF09' : "";
|
|
15977
|
+
return { content: `Voice send failed: ${err.message}${toHint}`, isError: true };
|
|
15927
15978
|
}
|
|
15928
15979
|
},
|
|
15929
15980
|
isConcurrencySafe: () => false,
|
|
@@ -15940,8 +15991,8 @@ __export(my_selfie_exports, {
|
|
|
15940
15991
|
dimsOf: () => dimsOf,
|
|
15941
15992
|
resolvePortraitDesc: () => resolvePortraitDesc
|
|
15942
15993
|
});
|
|
15943
|
-
import * as
|
|
15944
|
-
import * as
|
|
15994
|
+
import * as fs26 from "node:fs";
|
|
15995
|
+
import * as path26 from "node:path";
|
|
15945
15996
|
function getProxyDispatcher2() {
|
|
15946
15997
|
const cfg = liveConfig.all();
|
|
15947
15998
|
const proxy = cfg.providers?.xai?.proxy;
|
|
@@ -15955,7 +16006,7 @@ function getProxyDispatcher2() {
|
|
|
15955
16006
|
}
|
|
15956
16007
|
function dimsOf(p) {
|
|
15957
16008
|
try {
|
|
15958
|
-
const b =
|
|
16009
|
+
const b = fs26.readFileSync(p);
|
|
15959
16010
|
let w = 0, h = 0;
|
|
15960
16011
|
if (b.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
|
|
15961
16012
|
w = b.readUInt32BE(16);
|
|
@@ -16068,9 +16119,9 @@ function registerPortrait(relPath, name) {
|
|
|
16068
16119
|
const cur = cfg?.tools?.my_selfie?.references || cfg?.my_selfie?.references || [];
|
|
16069
16120
|
const next = Array.isArray(cur) ? cur.filter((r) => r?.name !== name) : [];
|
|
16070
16121
|
next.unshift({ name, path: relPath });
|
|
16071
|
-
const
|
|
16072
|
-
void liveConfig.set(
|
|
16073
|
-
console.log(`[my-selfie] \u5F62\u8C61\u5DF2\u767B\u8BB0\uFF1A${
|
|
16122
|
+
const path44 = cfg?.tools?.my_selfie ? "tools.my_selfie.references" : "my_selfie.references";
|
|
16123
|
+
void liveConfig.set(path44, next);
|
|
16124
|
+
console.log(`[my-selfie] \u5F62\u8C61\u5DF2\u767B\u8BB0\uFF1A${path44}[0] = ${relPath}`);
|
|
16074
16125
|
} catch (e) {
|
|
16075
16126
|
console.warn(`[my-selfie] \u5199\u5165 references \u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u672C\u6B21\u51FA\u56FE\uFF09: ${e.message}`);
|
|
16076
16127
|
}
|
|
@@ -16368,10 +16419,10 @@ var init_my_selfie = __esm({
|
|
|
16368
16419
|
const REFERENCES = getReferences(ctx);
|
|
16369
16420
|
const refName = args.reference || "default";
|
|
16370
16421
|
const refEntry = REFERENCES.find((r) => r.name === refName) || REFERENCES[0];
|
|
16371
|
-
let refPath =
|
|
16422
|
+
let refPath = path26.join(ctx.workspace, refEntry.p);
|
|
16372
16423
|
const adoptImg = args.referenceImage?.trim();
|
|
16373
16424
|
if (adoptImg) {
|
|
16374
|
-
if (!
|
|
16425
|
+
if (!fs26.existsSync(adoptImg)) {
|
|
16375
16426
|
return { content: `\u627E\u4E0D\u5230\u90A3\u5F20\u56FE\uFF1A${adoptImg}`, isError: true };
|
|
16376
16427
|
}
|
|
16377
16428
|
const acheck = dimsOf(adoptImg);
|
|
@@ -16382,16 +16433,16 @@ var init_my_selfie = __esm({
|
|
|
16382
16433
|
isError: true
|
|
16383
16434
|
};
|
|
16384
16435
|
}
|
|
16385
|
-
const adir =
|
|
16386
|
-
if (!
|
|
16387
|
-
const aext = (
|
|
16436
|
+
const adir = path26.join(ctx.workspace, "images");
|
|
16437
|
+
if (!fs26.existsSync(adir)) fs26.mkdirSync(adir, { recursive: true });
|
|
16438
|
+
const aext = (path26.extname(adoptImg) || ".png").toLowerCase();
|
|
16388
16439
|
const afname = `portrait_${Date.now()}${aext}`;
|
|
16389
|
-
|
|
16440
|
+
fs26.copyFileSync(adoptImg, path26.join(adir, afname));
|
|
16390
16441
|
registerPortrait(`images/${afname}`, refName);
|
|
16391
|
-
refPath =
|
|
16442
|
+
refPath = path26.join(adir, afname);
|
|
16392
16443
|
console.log(`[my-selfie] \u91C7\u7EB3\u73B0\u6210\u56FE\u5F53\u5F62\u8C61\uFF1Aimages/${afname}${acheck ? ` (${acheck})` : ""}`);
|
|
16393
16444
|
}
|
|
16394
|
-
if (provider !== "autodl" && !
|
|
16445
|
+
if (provider !== "autodl" && !fs26.existsSync(refPath)) {
|
|
16395
16446
|
const cfgAll = liveConfig.all();
|
|
16396
16447
|
const portraitDesc = resolvePortraitDesc(
|
|
16397
16448
|
args.portrait,
|
|
@@ -16416,16 +16467,16 @@ var init_my_selfie = __esm({
|
|
|
16416
16467
|
} catch (e) {
|
|
16417
16468
|
return { content: `\u5851\u9020\u5F62\u8C61\u5931\u8D25\uFF1A${e.message}`, isError: true };
|
|
16418
16469
|
}
|
|
16419
|
-
const pdir =
|
|
16420
|
-
if (!
|
|
16470
|
+
const pdir = path26.join(ctx.workspace, "images");
|
|
16471
|
+
if (!fs26.existsSync(pdir)) fs26.mkdirSync(pdir, { recursive: true });
|
|
16421
16472
|
const pfname = `portrait_${Date.now()}.png`;
|
|
16422
|
-
|
|
16473
|
+
fs26.writeFileSync(path26.join(pdir, pfname), portraitBuf);
|
|
16423
16474
|
registerPortrait(`images/${pfname}`, refName);
|
|
16424
|
-
refPath =
|
|
16475
|
+
refPath = path26.join(pdir, pfname);
|
|
16425
16476
|
console.log(`[my-selfie] \u5F62\u8C61\u5DF2\u5B58 images/${pfname}\uFF0C\u7EE7\u7EED\u8FD9\u6B21\u81EA\u62CD`);
|
|
16426
16477
|
}
|
|
16427
16478
|
const resolution = args.resolution || DEFAULT_RESOLUTION;
|
|
16428
|
-
const refB64 =
|
|
16479
|
+
const refB64 = fs26.existsSync(refPath) ? fs26.readFileSync(refPath).toString("base64") : "";
|
|
16429
16480
|
let imageBuffer;
|
|
16430
16481
|
try {
|
|
16431
16482
|
if (provider === "autodl") {
|
|
@@ -16441,7 +16492,7 @@ var init_my_selfie = __esm({
|
|
|
16441
16492
|
return { content: `Error: relay provider \u672A\u914D\u7F6E\u3002config \u91CC\u8981\u6709 models.providers.${cfgAll?.my_selfie?.relayProviderId || "7yi"} \u7684 baseUrl \u548C apiKey\u3002`, isError: true };
|
|
16442
16493
|
}
|
|
16443
16494
|
const model = cfgAll?.my_selfie?.relayModel || cfgAll?.tools?.my_selfie?.relayModel || "engine7-img-free";
|
|
16444
|
-
const ext =
|
|
16495
|
+
const ext = path26.extname(refPath).toLowerCase();
|
|
16445
16496
|
const mime = ext === ".png" ? "image/png" : ext === ".webp" ? "image/webp" : "image/jpeg";
|
|
16446
16497
|
imageBuffer = await generateWithRelay(refB64, fullPrompt, mime, relay.baseUrl, relay.apiKey, model);
|
|
16447
16498
|
} else {
|
|
@@ -16450,11 +16501,11 @@ var init_my_selfie = __esm({
|
|
|
16450
16501
|
} catch (err) {
|
|
16451
16502
|
return { content: `Selfie generation failed: ${err.message}`, isError: true };
|
|
16452
16503
|
}
|
|
16453
|
-
const imagesDir =
|
|
16454
|
-
if (!
|
|
16504
|
+
const imagesDir = path26.join(ctx.workspace, "images");
|
|
16505
|
+
if (!fs26.existsSync(imagesDir)) fs26.mkdirSync(imagesDir, { recursive: true });
|
|
16455
16506
|
const filename = `selfie_${Date.now()}.jpg`;
|
|
16456
|
-
const outputPath =
|
|
16457
|
-
|
|
16507
|
+
const outputPath = path26.join(imagesDir, filename);
|
|
16508
|
+
fs26.writeFileSync(outputPath, imageBuffer);
|
|
16458
16509
|
const mgr = ctx.channelManager;
|
|
16459
16510
|
if (mgr) {
|
|
16460
16511
|
const resolvedChannel = ctx.channel || "feishu";
|
|
@@ -16465,11 +16516,11 @@ var init_my_selfie = __esm({
|
|
|
16465
16516
|
mimeType: "image/jpeg"
|
|
16466
16517
|
});
|
|
16467
16518
|
} catch (err) {
|
|
16468
|
-
return { content: `Selfie generated but send failed: ${err.message}. Image: ${
|
|
16519
|
+
return { content: `Selfie generated but send failed: ${err.message}. Image: ${path26.resolve(outputPath)}`, isError: false };
|
|
16469
16520
|
}
|
|
16470
16521
|
return { content: `Selfie sent! Mode: ${mode}, Provider: ${provider}, Ref: ${refEntry.name}` };
|
|
16471
16522
|
}
|
|
16472
|
-
return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${
|
|
16523
|
+
return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${path26.resolve(outputPath)}` };
|
|
16473
16524
|
},
|
|
16474
16525
|
isConcurrencySafe: () => false,
|
|
16475
16526
|
interruptBehavior: () => "block",
|
|
@@ -17299,8 +17350,8 @@ var init_calendar = __esm({
|
|
|
17299
17350
|
});
|
|
17300
17351
|
|
|
17301
17352
|
// src/tools/service.ts
|
|
17302
|
-
import * as
|
|
17303
|
-
import * as
|
|
17353
|
+
import * as fs27 from "node:fs";
|
|
17354
|
+
import * as path27 from "node:path";
|
|
17304
17355
|
import { exec, spawn as spawn4 } from "node:child_process";
|
|
17305
17356
|
import { promisify as promisify3 } from "node:util";
|
|
17306
17357
|
function getServices() {
|
|
@@ -17308,9 +17359,9 @@ function getServices() {
|
|
|
17308
17359
|
}
|
|
17309
17360
|
function serviceLogPath(fileName) {
|
|
17310
17361
|
const stateDir = String(liveConfig.get("stateDir") ?? "");
|
|
17311
|
-
const logDir =
|
|
17312
|
-
if (!
|
|
17313
|
-
return
|
|
17362
|
+
const logDir = path27.join(stateDir, "logs");
|
|
17363
|
+
if (!fs27.existsSync(logDir)) fs27.mkdirSync(logDir, { recursive: true });
|
|
17364
|
+
return path27.join(logDir, fileName);
|
|
17314
17365
|
}
|
|
17315
17366
|
async function runCmd(cmd, timeoutMs = 15e3) {
|
|
17316
17367
|
try {
|
|
@@ -17525,24 +17576,24 @@ var init_constants5 = __esm({
|
|
|
17525
17576
|
});
|
|
17526
17577
|
|
|
17527
17578
|
// src/tools/TodoWriteTool/TodoWriteTool.ts
|
|
17528
|
-
import
|
|
17529
|
-
import
|
|
17579
|
+
import fs28 from "node:fs";
|
|
17580
|
+
import path28 from "node:path";
|
|
17530
17581
|
function todoFilePath(sessionId) {
|
|
17531
|
-
return
|
|
17582
|
+
return path28.join(todosDir, `${sessionId}.json`);
|
|
17532
17583
|
}
|
|
17533
17584
|
function loadTodos(sessionId) {
|
|
17534
17585
|
if (!todosDir) return [];
|
|
17535
17586
|
try {
|
|
17536
17587
|
const filePath = todoFilePath(sessionId);
|
|
17537
|
-
if (!
|
|
17538
|
-
return JSON.parse(
|
|
17588
|
+
if (!fs28.existsSync(filePath)) return [];
|
|
17589
|
+
return JSON.parse(fs28.readFileSync(filePath, "utf-8"));
|
|
17539
17590
|
} catch {
|
|
17540
17591
|
return [];
|
|
17541
17592
|
}
|
|
17542
17593
|
}
|
|
17543
17594
|
function saveTodos(sessionId, todos) {
|
|
17544
17595
|
if (!todosDir) return;
|
|
17545
|
-
|
|
17596
|
+
fs28.writeFileSync(todoFilePath(sessionId), JSON.stringify(todos, null, 2), "utf-8");
|
|
17546
17597
|
}
|
|
17547
17598
|
var todosDir;
|
|
17548
17599
|
var init_TodoWriteTool = __esm({
|
|
@@ -17799,15 +17850,15 @@ var init_constants7 = __esm({
|
|
|
17799
17850
|
});
|
|
17800
17851
|
|
|
17801
17852
|
// src/utils/plans.ts
|
|
17802
|
-
import * as
|
|
17803
|
-
import * as
|
|
17853
|
+
import * as fs29 from "node:fs";
|
|
17854
|
+
import * as path29 from "node:path";
|
|
17804
17855
|
import * as crypto4 from "node:crypto";
|
|
17805
17856
|
function generateSlug() {
|
|
17806
17857
|
return crypto4.randomBytes(4).toString("hex");
|
|
17807
17858
|
}
|
|
17808
17859
|
function getPlansDirectory(stateDir) {
|
|
17809
|
-
const plansDir =
|
|
17810
|
-
|
|
17860
|
+
const plansDir = path29.join(stateDir, "plans");
|
|
17861
|
+
fs29.mkdirSync(plansDir, { recursive: true });
|
|
17811
17862
|
return plansDir;
|
|
17812
17863
|
}
|
|
17813
17864
|
function getPlanSlug(sessionId, stateDir) {
|
|
@@ -17816,8 +17867,8 @@ function getPlanSlug(sessionId, stateDir) {
|
|
|
17816
17867
|
const plansDir = getPlansDirectory(stateDir);
|
|
17817
17868
|
for (let i = 0; i < MAX_SLUG_RETRIES; i++) {
|
|
17818
17869
|
slug = generateSlug();
|
|
17819
|
-
const filePath =
|
|
17820
|
-
if (!
|
|
17870
|
+
const filePath = path29.join(plansDir, `${slug}.md`);
|
|
17871
|
+
if (!fs29.existsSync(filePath)) {
|
|
17821
17872
|
break;
|
|
17822
17873
|
}
|
|
17823
17874
|
}
|
|
@@ -17828,21 +17879,21 @@ function getPlanSlug(sessionId, stateDir) {
|
|
|
17828
17879
|
function getPlanFilePath(sessionId, stateDir, agentId) {
|
|
17829
17880
|
const slug = getPlanSlug(sessionId, stateDir);
|
|
17830
17881
|
if (!agentId) {
|
|
17831
|
-
return
|
|
17882
|
+
return path29.join(getPlansDirectory(stateDir), `${slug}.md`);
|
|
17832
17883
|
}
|
|
17833
|
-
return
|
|
17884
|
+
return path29.join(getPlansDirectory(stateDir), `${slug}-agent-${agentId}.md`);
|
|
17834
17885
|
}
|
|
17835
17886
|
function getPlan(sessionId, stateDir, agentId) {
|
|
17836
17887
|
const filePath = getPlanFilePath(sessionId, stateDir, agentId);
|
|
17837
17888
|
try {
|
|
17838
|
-
return
|
|
17889
|
+
return fs29.readFileSync(filePath, "utf-8");
|
|
17839
17890
|
} catch {
|
|
17840
17891
|
return null;
|
|
17841
17892
|
}
|
|
17842
17893
|
}
|
|
17843
17894
|
function writePlan(sessionId, stateDir, content, agentId) {
|
|
17844
17895
|
const filePath = getPlanFilePath(sessionId, stateDir, agentId);
|
|
17845
|
-
|
|
17896
|
+
fs29.writeFileSync(filePath, content, "utf-8");
|
|
17846
17897
|
return filePath;
|
|
17847
17898
|
}
|
|
17848
17899
|
var MAX_SLUG_RETRIES, planSlugCache;
|
|
@@ -17990,28 +18041,28 @@ var init_constants8 = __esm({
|
|
|
17990
18041
|
});
|
|
17991
18042
|
|
|
17992
18043
|
// src/utils/tasks.ts
|
|
17993
|
-
import * as
|
|
17994
|
-
import * as
|
|
18044
|
+
import * as fs30 from "node:fs";
|
|
18045
|
+
import * as path30 from "node:path";
|
|
17995
18046
|
function sanitizePathComponent2(input) {
|
|
17996
18047
|
return input.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
17997
18048
|
}
|
|
17998
18049
|
function getTasksDir2(stateDir, listId) {
|
|
17999
|
-
return
|
|
18050
|
+
return path30.join(stateDir, "tasks", sanitizePathComponent2(listId));
|
|
18000
18051
|
}
|
|
18001
18052
|
function getTaskPath(stateDir, listId, taskId) {
|
|
18002
|
-
return
|
|
18053
|
+
return path30.join(getTasksDir2(stateDir, listId), `${sanitizePathComponent2(taskId)}.json`);
|
|
18003
18054
|
}
|
|
18004
18055
|
function ensureTasksDir2(stateDir, listId) {
|
|
18005
18056
|
const dir = getTasksDir2(stateDir, listId);
|
|
18006
|
-
|
|
18057
|
+
fs30.mkdirSync(dir, { recursive: true });
|
|
18007
18058
|
return dir;
|
|
18008
18059
|
}
|
|
18009
18060
|
function getHighWaterMarkPath(stateDir, listId) {
|
|
18010
|
-
return
|
|
18061
|
+
return path30.join(getTasksDir2(stateDir, listId), HIGH_WATER_MARK_FILE);
|
|
18011
18062
|
}
|
|
18012
18063
|
function readHighWaterMark(stateDir, listId) {
|
|
18013
18064
|
try {
|
|
18014
|
-
const content =
|
|
18065
|
+
const content = fs30.readFileSync(getHighWaterMarkPath(stateDir, listId), "utf-8").trim();
|
|
18015
18066
|
const value = parseInt(content, 10);
|
|
18016
18067
|
return isNaN(value) ? 0 : value;
|
|
18017
18068
|
} catch {
|
|
@@ -18019,13 +18070,13 @@ function readHighWaterMark(stateDir, listId) {
|
|
|
18019
18070
|
}
|
|
18020
18071
|
}
|
|
18021
18072
|
function writeHighWaterMark(stateDir, listId, value) {
|
|
18022
|
-
|
|
18073
|
+
fs30.writeFileSync(getHighWaterMarkPath(stateDir, listId), String(value));
|
|
18023
18074
|
}
|
|
18024
18075
|
function findHighestTaskIdFromFiles(stateDir, listId) {
|
|
18025
18076
|
const dir = getTasksDir2(stateDir, listId);
|
|
18026
18077
|
let files;
|
|
18027
18078
|
try {
|
|
18028
|
-
files =
|
|
18079
|
+
files = fs30.readdirSync(dir);
|
|
18029
18080
|
} catch {
|
|
18030
18081
|
return 0;
|
|
18031
18082
|
}
|
|
@@ -18051,14 +18102,14 @@ function createTask(stateDir, listId, taskData) {
|
|
|
18051
18102
|
const id = String(highestId + 1);
|
|
18052
18103
|
const task = { id, ...taskData };
|
|
18053
18104
|
const filePath = getTaskPath(stateDir, listId, id);
|
|
18054
|
-
|
|
18105
|
+
fs30.writeFileSync(filePath, JSON.stringify(task, null, 2));
|
|
18055
18106
|
return id;
|
|
18056
18107
|
});
|
|
18057
18108
|
}
|
|
18058
18109
|
function getTask2(stateDir, listId, taskId) {
|
|
18059
18110
|
const filePath = getTaskPath(stateDir, listId, taskId);
|
|
18060
18111
|
try {
|
|
18061
|
-
const content =
|
|
18112
|
+
const content = fs30.readFileSync(filePath, "utf-8");
|
|
18062
18113
|
return JSON.parse(content);
|
|
18063
18114
|
} catch {
|
|
18064
18115
|
return null;
|
|
@@ -18068,7 +18119,7 @@ function listTasks2(stateDir, listId) {
|
|
|
18068
18119
|
const dir = getTasksDir2(stateDir, listId);
|
|
18069
18120
|
let files;
|
|
18070
18121
|
try {
|
|
18071
|
-
files =
|
|
18122
|
+
files = fs30.readdirSync(dir);
|
|
18072
18123
|
} catch {
|
|
18073
18124
|
return [];
|
|
18074
18125
|
}
|
|
@@ -18080,7 +18131,7 @@ function updateTask(stateDir, listId, taskId, updates) {
|
|
|
18080
18131
|
if (!existing) return null;
|
|
18081
18132
|
const updated = { ...existing, ...updates, id: taskId };
|
|
18082
18133
|
const filePath = getTaskPath(stateDir, listId, taskId);
|
|
18083
|
-
|
|
18134
|
+
fs30.writeFileSync(filePath, JSON.stringify(updated, null, 2));
|
|
18084
18135
|
return updated;
|
|
18085
18136
|
}
|
|
18086
18137
|
function deleteTask(stateDir, listId, taskId) {
|
|
@@ -18094,7 +18145,7 @@ function deleteTask(stateDir, listId, taskId) {
|
|
|
18094
18145
|
}
|
|
18095
18146
|
}
|
|
18096
18147
|
try {
|
|
18097
|
-
|
|
18148
|
+
fs30.unlinkSync(filePath);
|
|
18098
18149
|
} catch {
|
|
18099
18150
|
return false;
|
|
18100
18151
|
}
|
|
@@ -19527,10 +19578,10 @@ function ensureLoaded(workspace, configIds) {
|
|
|
19527
19578
|
if (!state.blockedUserIds.includes(id)) state.blockedUserIds.push(id);
|
|
19528
19579
|
}
|
|
19529
19580
|
}
|
|
19530
|
-
const
|
|
19581
|
+
const path44 = join28(workspace, ".reply-blocklist.json");
|
|
19531
19582
|
try {
|
|
19532
|
-
if (existsSync22(
|
|
19533
|
-
const raw = readFileSync21(
|
|
19583
|
+
if (existsSync22(path44)) {
|
|
19584
|
+
const raw = readFileSync21(path44, "utf-8");
|
|
19534
19585
|
const parsed = JSON.parse(raw);
|
|
19535
19586
|
if (parsed.blockedUserIds) {
|
|
19536
19587
|
for (const id of parsed.blockedUserIds) {
|
|
@@ -19546,9 +19597,9 @@ function ensureLoaded(workspace, configIds) {
|
|
|
19546
19597
|
loaded = true;
|
|
19547
19598
|
}
|
|
19548
19599
|
function save(workspace) {
|
|
19549
|
-
const
|
|
19600
|
+
const path44 = join28(workspace, ".reply-blocklist.json");
|
|
19550
19601
|
try {
|
|
19551
|
-
writeFileSync16(
|
|
19602
|
+
writeFileSync16(path44, JSON.stringify(state, null, 2), "utf-8");
|
|
19552
19603
|
} catch (err) {
|
|
19553
19604
|
console.warn(`[reply-blocklist] Failed to save: ${err.message}`);
|
|
19554
19605
|
}
|
|
@@ -20744,8 +20795,8 @@ var extractMemories_exports = {};
|
|
|
20744
20795
|
__export(extractMemories_exports, {
|
|
20745
20796
|
createMemoryExtractor: () => createMemoryExtractor
|
|
20746
20797
|
});
|
|
20747
|
-
import * as
|
|
20748
|
-
import * as
|
|
20798
|
+
import * as fs31 from "fs";
|
|
20799
|
+
import * as path31 from "path";
|
|
20749
20800
|
function isModelVisibleMessage(message) {
|
|
20750
20801
|
return message.role === "user" || message.role === "assistant";
|
|
20751
20802
|
}
|
|
@@ -20768,13 +20819,13 @@ function getMemoryTools() {
|
|
|
20768
20819
|
return allDefs.filter((d) => MEMORY_TOOL_NAMES.includes(d.function.name));
|
|
20769
20820
|
}
|
|
20770
20821
|
function getStatePath(workspace) {
|
|
20771
|
-
return
|
|
20822
|
+
return path31.join(workspace, STATE_FILE);
|
|
20772
20823
|
}
|
|
20773
20824
|
function loadPersistedState(workspace) {
|
|
20774
20825
|
try {
|
|
20775
20826
|
const p = getStatePath(workspace);
|
|
20776
|
-
if (
|
|
20777
|
-
const data = JSON.parse(
|
|
20827
|
+
if (fs31.existsSync(p)) {
|
|
20828
|
+
const data = JSON.parse(fs31.readFileSync(p, "utf-8"));
|
|
20778
20829
|
for (const [sid, ts] of Object.entries(data.lastTs ?? {})) {
|
|
20779
20830
|
lastTsMap.set(sid, ts);
|
|
20780
20831
|
}
|
|
@@ -20794,7 +20845,7 @@ function persistState(workspace) {
|
|
|
20794
20845
|
for (const [sid, ts] of lastTsMap.entries()) lastTs[sid] = ts;
|
|
20795
20846
|
for (const [sid, ts] of lastExtractTimeMap.entries()) timestamps[sid] = ts;
|
|
20796
20847
|
const data = JSON.stringify({ lastTs, timestamps }, null, 2);
|
|
20797
|
-
|
|
20848
|
+
fs31.writeFileSync(getStatePath(workspace), data, "utf-8");
|
|
20798
20849
|
} catch (e) {
|
|
20799
20850
|
console.warn(`[memory] failed to persist extract state: ${e?.message ?? e}`);
|
|
20800
20851
|
}
|
|
@@ -20835,11 +20886,11 @@ function createMemoryExtractor(workspace, enabled) {
|
|
|
20835
20886
|
const existingMemories = formatMemoryManifest(
|
|
20836
20887
|
await scanMemoryFiles2(memoryDir, new AbortController().signal)
|
|
20837
20888
|
);
|
|
20838
|
-
const extractOverridePath =
|
|
20889
|
+
const extractOverridePath = path31.join(workspace, "prompts", "extract.md");
|
|
20839
20890
|
let systemPrompt;
|
|
20840
20891
|
try {
|
|
20841
|
-
if (
|
|
20842
|
-
systemPrompt =
|
|
20892
|
+
if (fs31.existsSync(extractOverridePath)) {
|
|
20893
|
+
systemPrompt = fs31.readFileSync(extractOverridePath, { encoding: "utf-8" });
|
|
20843
20894
|
if (existingMemories.length > 0) {
|
|
20844
20895
|
systemPrompt += `
|
|
20845
20896
|
|
|
@@ -20965,8 +21016,8 @@ __export(ingest_exports, {
|
|
|
20965
21016
|
pushConversation: () => pushConversation,
|
|
20966
21017
|
toPayload: () => toPayload
|
|
20967
21018
|
});
|
|
20968
|
-
import
|
|
20969
|
-
import
|
|
21019
|
+
import fs32 from "node:fs";
|
|
21020
|
+
import path32 from "node:path";
|
|
20970
21021
|
async function readConfig() {
|
|
20971
21022
|
const defaults = {
|
|
20972
21023
|
url: "http://127.0.0.1:8100",
|
|
@@ -20996,9 +21047,9 @@ async function readConfig() {
|
|
|
20996
21047
|
}
|
|
20997
21048
|
function loadPushTs(workspace, sessionId) {
|
|
20998
21049
|
try {
|
|
20999
|
-
const p =
|
|
21000
|
-
if (
|
|
21001
|
-
const data = JSON.parse(
|
|
21050
|
+
const p = path32.join(workspace, PUSH_STATE_FILE);
|
|
21051
|
+
if (fs32.existsSync(p)) {
|
|
21052
|
+
const data = JSON.parse(fs32.readFileSync(p, "utf-8"));
|
|
21002
21053
|
return typeof data[sessionId] === "number" ? data[sessionId] : 0;
|
|
21003
21054
|
}
|
|
21004
21055
|
} catch (e) {
|
|
@@ -21008,14 +21059,14 @@ function loadPushTs(workspace, sessionId) {
|
|
|
21008
21059
|
}
|
|
21009
21060
|
function savePushTs(workspace, sessionId, ts) {
|
|
21010
21061
|
try {
|
|
21011
|
-
const p =
|
|
21062
|
+
const p = path32.join(workspace, PUSH_STATE_FILE);
|
|
21012
21063
|
let data = {};
|
|
21013
21064
|
try {
|
|
21014
|
-
if (
|
|
21065
|
+
if (fs32.existsSync(p)) data = JSON.parse(fs32.readFileSync(p, "utf-8"));
|
|
21015
21066
|
} catch {
|
|
21016
21067
|
}
|
|
21017
21068
|
data[sessionId] = ts;
|
|
21018
|
-
|
|
21069
|
+
fs32.writeFileSync(p, JSON.stringify(data, null, 2), "utf-8");
|
|
21019
21070
|
} catch (e) {
|
|
21020
21071
|
console.warn(`[everos-ingest] save pushTs failed: ${e?.message ?? e}`);
|
|
21021
21072
|
}
|
|
@@ -27940,11 +27991,11 @@ async function readLastConsolidatedAt(memoryDir) {
|
|
|
27940
27991
|
}
|
|
27941
27992
|
}
|
|
27942
27993
|
async function tryAcquireConsolidationLock(memoryDir) {
|
|
27943
|
-
const
|
|
27994
|
+
const path44 = lockPath(memoryDir);
|
|
27944
27995
|
let mtimeMs;
|
|
27945
27996
|
let holderPid;
|
|
27946
27997
|
try {
|
|
27947
|
-
const [s, raw] = await Promise.all([stat3(
|
|
27998
|
+
const [s, raw] = await Promise.all([stat3(path44), readFile5(path44, "utf8")]);
|
|
27948
27999
|
mtimeMs = s.mtimeMs;
|
|
27949
28000
|
const parsed = parseInt(raw.trim(), 10);
|
|
27950
28001
|
holderPid = Number.isFinite(parsed) ? parsed : void 0;
|
|
@@ -27957,10 +28008,10 @@ async function tryAcquireConsolidationLock(memoryDir) {
|
|
|
27957
28008
|
}
|
|
27958
28009
|
}
|
|
27959
28010
|
await mkdir3(memoryDir, { recursive: true });
|
|
27960
|
-
await writeFile4(
|
|
28011
|
+
await writeFile4(path44, String(process.pid));
|
|
27961
28012
|
let verify2;
|
|
27962
28013
|
try {
|
|
27963
|
-
verify2 = await readFile5(
|
|
28014
|
+
verify2 = await readFile5(path44, "utf8");
|
|
27964
28015
|
} catch {
|
|
27965
28016
|
return null;
|
|
27966
28017
|
}
|
|
@@ -27968,15 +28019,15 @@ async function tryAcquireConsolidationLock(memoryDir) {
|
|
|
27968
28019
|
return mtimeMs ?? 0;
|
|
27969
28020
|
}
|
|
27970
28021
|
async function rollbackConsolidationLock(memoryDir, priorMtime) {
|
|
27971
|
-
const
|
|
28022
|
+
const path44 = lockPath(memoryDir);
|
|
27972
28023
|
try {
|
|
27973
28024
|
if (priorMtime === 0) {
|
|
27974
|
-
await unlink(
|
|
28025
|
+
await unlink(path44);
|
|
27975
28026
|
return;
|
|
27976
28027
|
}
|
|
27977
|
-
await writeFile4(
|
|
28028
|
+
await writeFile4(path44, "");
|
|
27978
28029
|
const t = priorMtime / 1e3;
|
|
27979
|
-
await utimes(
|
|
28030
|
+
await utimes(path44, t, t);
|
|
27980
28031
|
} catch (e) {
|
|
27981
28032
|
console.log(`[autoDream] rollback failed: ${e.message} \u2014 next trigger delayed to minHours`);
|
|
27982
28033
|
}
|
|
@@ -28263,7 +28314,7 @@ __export(handle_query_exports, {
|
|
|
28263
28314
|
});
|
|
28264
28315
|
import { readFileSync as readFileSync37, existsSync as existsSync31, statSync as statSync13 } from "node:fs";
|
|
28265
28316
|
import { join as join48, resolve as resolve8 } from "node:path";
|
|
28266
|
-
import * as
|
|
28317
|
+
import * as path33 from "node:path";
|
|
28267
28318
|
function resolveSystemPrompt(v) {
|
|
28268
28319
|
return typeof v === "function" ? v() : v || "";
|
|
28269
28320
|
}
|
|
@@ -28271,18 +28322,18 @@ function resetSessionStartInjection(sessionId) {
|
|
|
28271
28322
|
sessionStartDone.delete(sessionId);
|
|
28272
28323
|
}
|
|
28273
28324
|
function loadExternalChanRules(workspace) {
|
|
28274
|
-
const
|
|
28275
|
-
if (externalChanRulesCache && externalChanRulesCache.path ===
|
|
28325
|
+
const path44 = join48(workspace, "prompts", "external-chan-rules.md");
|
|
28326
|
+
if (externalChanRulesCache && externalChanRulesCache.path === path44) return externalChanRulesCache;
|
|
28276
28327
|
let content = "";
|
|
28277
|
-
if (existsSync31(
|
|
28328
|
+
if (existsSync31(path44)) {
|
|
28278
28329
|
try {
|
|
28279
|
-
content = readFileSync37(
|
|
28330
|
+
content = readFileSync37(path44, "utf-8").trim();
|
|
28280
28331
|
} catch (e) {
|
|
28281
28332
|
console.warn(`[external-chan-rules] Failed to load: ${e}`);
|
|
28282
28333
|
}
|
|
28283
28334
|
}
|
|
28284
|
-
externalChanRulesCache = { path:
|
|
28285
|
-
console.log(`[external-chan-rules] Loaded ${content.length} chars from ${
|
|
28335
|
+
externalChanRulesCache = { path: path44, content };
|
|
28336
|
+
console.log(`[external-chan-rules] Loaded ${content.length} chars from ${path44}`);
|
|
28286
28337
|
return externalChanRulesCache;
|
|
28287
28338
|
}
|
|
28288
28339
|
function getExternalChanRulesBlock(inboundMeta, workspace) {
|
|
@@ -29097,7 +29148,7 @@ stack: ${err.stack ?? "(none)"}`);
|
|
|
29097
29148
|
}
|
|
29098
29149
|
} catch (err) {
|
|
29099
29150
|
try {
|
|
29100
|
-
(await import("node:fs")).appendFileSync(join48(process.env.ENGINE7_STATE_DIR ||
|
|
29151
|
+
(await import("node:fs")).appendFileSync(join48(process.env.ENGINE7_STATE_DIR || path33.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7"), "logs", "autoDream-debug.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] [handle-query] autoDream trigger TRY-CATCH: ${err.message}
|
|
29101
29152
|
stack: ${err.stack ?? "(none)"}
|
|
29102
29153
|
`);
|
|
29103
29154
|
} catch {
|
|
@@ -29785,8 +29836,8 @@ __export(free_tier_apply_exports, {
|
|
|
29785
29836
|
isFreeTierConfig: () => isFreeTierConfig,
|
|
29786
29837
|
resolveConfigPath: () => resolveConfigPath
|
|
29787
29838
|
});
|
|
29788
|
-
import * as
|
|
29789
|
-
import * as
|
|
29839
|
+
import * as fs33 from "node:fs";
|
|
29840
|
+
import * as path34 from "node:path";
|
|
29790
29841
|
function isFreeTierConfig(cfg) {
|
|
29791
29842
|
const hasProvider = !!cfg?.models?.providers?.[FREE_TIER_PROVIDER_ID];
|
|
29792
29843
|
const primary = String(cfg?.agents?.defaults?.model?.primary || "");
|
|
@@ -29822,31 +29873,23 @@ function applyFreeTier(cfg, opts = {}) {
|
|
|
29822
29873
|
const mv = cfg.tools.my_voice || null;
|
|
29823
29874
|
const existingProvider = typeof mv?.provider === "string" ? mv.provider : "";
|
|
29824
29875
|
if (!mv || existingProvider === "relay") {
|
|
29825
|
-
cfg.tools.my_voice =
|
|
29826
|
-
...mv || {},
|
|
29827
|
-
provider: "relay",
|
|
29828
|
-
relayProviderId: FREE_TIER_PROVIDER_ID,
|
|
29829
|
-
// '7yi'
|
|
29830
|
-
relayModel: "engine7-tts",
|
|
29831
|
-
// 有块就不夺 ⇒ 走到这里时 mv 要么不存在、要么 voice 就是 relay 的;非 relay 的块已跳过
|
|
29832
|
-
voice: mv?.voice || DEFAULT_FREE_VOICE
|
|
29833
|
-
};
|
|
29876
|
+
cfg.tools.my_voice = freeTierVoiceConfig(mv);
|
|
29834
29877
|
}
|
|
29835
29878
|
return cfg;
|
|
29836
29879
|
}
|
|
29837
29880
|
function resolveConfigPath(stateDir, configName) {
|
|
29838
|
-
const configsDir =
|
|
29881
|
+
const configsDir = path34.join(stateDir, "configs");
|
|
29839
29882
|
if (configName) {
|
|
29840
|
-
const p =
|
|
29841
|
-
return
|
|
29842
|
-
}
|
|
29843
|
-
const main2 =
|
|
29844
|
-
if (
|
|
29845
|
-
if (!
|
|
29846
|
-
for (const f of
|
|
29847
|
-
const full =
|
|
29883
|
+
const p = path34.join(configsDir, configName);
|
|
29884
|
+
return fs33.existsSync(p) ? p : "";
|
|
29885
|
+
}
|
|
29886
|
+
const main2 = path34.join(configsDir, "main7.json");
|
|
29887
|
+
if (fs33.existsSync(main2)) return main2;
|
|
29888
|
+
if (!fs33.existsSync(configsDir)) return "";
|
|
29889
|
+
for (const f of fs33.readdirSync(configsDir).filter((x) => x.endsWith(".json"))) {
|
|
29890
|
+
const full = path34.join(configsDir, f);
|
|
29848
29891
|
try {
|
|
29849
|
-
if (JSON.parse(
|
|
29892
|
+
if (JSON.parse(fs33.readFileSync(full, "utf8")).models?.providers) return full;
|
|
29850
29893
|
} catch {
|
|
29851
29894
|
}
|
|
29852
29895
|
}
|
|
@@ -29855,16 +29898,16 @@ function resolveConfigPath(stateDir, configName) {
|
|
|
29855
29898
|
function applyFreeTierToConfig(configPath, opts = {}) {
|
|
29856
29899
|
let cfg;
|
|
29857
29900
|
try {
|
|
29858
|
-
cfg = JSON.parse(
|
|
29901
|
+
cfg = JSON.parse(fs33.readFileSync(configPath, "utf8"));
|
|
29859
29902
|
} catch (e) {
|
|
29860
29903
|
throw new Error(`\u8BFB\u53D6 config \u5931\u8D25: ${configPath}\uFF08${e?.message || e}\uFF09`);
|
|
29861
29904
|
}
|
|
29862
29905
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
29863
29906
|
const backupPath = `${configPath}.bak-${stamp}`;
|
|
29864
|
-
|
|
29907
|
+
fs33.copyFileSync(configPath, backupPath);
|
|
29865
29908
|
applyFreeTier(cfg, opts);
|
|
29866
29909
|
try {
|
|
29867
|
-
|
|
29910
|
+
fs33.writeFileSync(configPath, JSON.stringify(cfg, null, 2), "utf8");
|
|
29868
29911
|
} catch (e) {
|
|
29869
29912
|
throw new Error(`\u5199\u5165 config \u5931\u8D25: ${configPath}\uFF08${e?.message || e}\uFF09\uFF1B\u539F\u6587\u4EF6\u672A\u6539\u52A8\uFF0C\u5907\u4EFD\u5728 ${backupPath}`);
|
|
29870
29913
|
}
|
|
@@ -29876,15 +29919,14 @@ function applyFreeTierToConfig(configPath, opts = {}) {
|
|
|
29876
29919
|
video: cfg.agents.defaults.model.video ?? null
|
|
29877
29920
|
};
|
|
29878
29921
|
}
|
|
29879
|
-
var
|
|
29922
|
+
var FREE_TIER_PRIMARY;
|
|
29880
29923
|
var init_free_tier_apply = __esm({
|
|
29881
29924
|
"src/free-tier-apply.ts"() {
|
|
29882
29925
|
"use strict";
|
|
29883
29926
|
init_cli_init_config();
|
|
29884
29927
|
init_provision_free();
|
|
29885
|
-
|
|
29928
|
+
init_cli_init_config();
|
|
29886
29929
|
FREE_TIER_PRIMARY = "7yi/engine7-free";
|
|
29887
|
-
DEFAULT_FREE_VOICE = "Chinese (Mandarin)_Warm_Girl";
|
|
29888
29930
|
}
|
|
29889
29931
|
});
|
|
29890
29932
|
|
|
@@ -29894,15 +29936,15 @@ __export(cli_doctor_exports, {
|
|
|
29894
29936
|
resolveStateDirFromArgs: () => resolveStateDirFromArgs,
|
|
29895
29937
|
runDoctor: () => runDoctor
|
|
29896
29938
|
});
|
|
29897
|
-
import * as
|
|
29898
|
-
import * as
|
|
29939
|
+
import * as fs34 from "node:fs";
|
|
29940
|
+
import * as path35 from "node:path";
|
|
29899
29941
|
import * as net from "node:net";
|
|
29900
29942
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
29901
29943
|
function readVersion() {
|
|
29902
|
-
const here =
|
|
29903
|
-
for (const p of [
|
|
29944
|
+
const here = path35.dirname(fileURLToPath6(import.meta.url));
|
|
29945
|
+
for (const p of [path35.join(here, "..", "package.json"), path35.join(here, "..", "..", "package.json")]) {
|
|
29904
29946
|
try {
|
|
29905
|
-
return JSON.parse(
|
|
29947
|
+
return JSON.parse(fs34.readFileSync(p, "utf8")).version || "unknown";
|
|
29906
29948
|
} catch {
|
|
29907
29949
|
}
|
|
29908
29950
|
}
|
|
@@ -29932,7 +29974,7 @@ function probePort(port, timeoutMs) {
|
|
|
29932
29974
|
});
|
|
29933
29975
|
}
|
|
29934
29976
|
async function runDoctor(stateDir, opts) {
|
|
29935
|
-
const configPath =
|
|
29977
|
+
const configPath = path35.join(stateDir, "configs", "main7.json");
|
|
29936
29978
|
const report = {
|
|
29937
29979
|
version: readVersion(),
|
|
29938
29980
|
stateDir,
|
|
@@ -29948,10 +29990,10 @@ async function runDoctor(stateDir, opts) {
|
|
|
29948
29990
|
};
|
|
29949
29991
|
let config = null;
|
|
29950
29992
|
try {
|
|
29951
|
-
config = JSON.parse(
|
|
29993
|
+
config = JSON.parse(fs34.readFileSync(configPath, "utf8"));
|
|
29952
29994
|
report.configValid = true;
|
|
29953
29995
|
} catch (e) {
|
|
29954
|
-
report.configError =
|
|
29996
|
+
report.configError = fs34.existsSync(configPath) ? `\u89E3\u6790\u5931\u8D25: ${e.message}` : "config \u4E0D\u5B58\u5728\uFF08\u5148 engine7 init\uFF09";
|
|
29955
29997
|
}
|
|
29956
29998
|
if (config?.channels) {
|
|
29957
29999
|
for (const [name, conf] of Object.entries(config.channels)) {
|
|
@@ -29959,13 +30001,13 @@ async function runDoctor(stateDir, opts) {
|
|
|
29959
30001
|
report.channels.push({ name, enabled: !!c.enabled, hasCredentials: channelHasCredentials(name, c) });
|
|
29960
30002
|
}
|
|
29961
30003
|
}
|
|
29962
|
-
const cfgBase =
|
|
30004
|
+
const cfgBase = path35.basename(report.configPath, ".json") || "main7";
|
|
29963
30005
|
const candidates = secretsCandidates(stateDir, cfgBase);
|
|
29964
|
-
const secretsFile = candidates.find((p) =>
|
|
30006
|
+
const secretsFile = candidates.find((p) => fs34.existsSync(p)) || candidates[0];
|
|
29965
30007
|
report.secrets.file = secretsFile;
|
|
29966
|
-
if (
|
|
30008
|
+
if (fs34.existsSync(secretsFile)) {
|
|
29967
30009
|
report.secrets.exists = true;
|
|
29968
|
-
for (const line of
|
|
30010
|
+
for (const line of fs34.readFileSync(secretsFile, "utf8").split("\n")) {
|
|
29969
30011
|
const eq = line.indexOf("=");
|
|
29970
30012
|
if (eq > 0 && !line.startsWith("#")) report.secrets.keys.push(line.slice(0, eq).trim());
|
|
29971
30013
|
}
|
|
@@ -30005,10 +30047,10 @@ async function runDoctor(stateDir, opts) {
|
|
|
30005
30047
|
report.missingEnvKeys = [...missing].sort();
|
|
30006
30048
|
const stale = [];
|
|
30007
30049
|
for (const rel of ["workspace/SESSION-STATE.md", "SESSION-STATE.md"]) {
|
|
30008
|
-
const p =
|
|
30050
|
+
const p = path35.join(stateDir, rel);
|
|
30009
30051
|
try {
|
|
30010
|
-
if (!
|
|
30011
|
-
const head =
|
|
30052
|
+
if (!fs34.existsSync(p)) continue;
|
|
30053
|
+
const head = fs34.readFileSync(p, "utf8").split("\n").slice(0, 10).join("\n");
|
|
30012
30054
|
const m = head.match(/^#{1,3}\s*当前时间\s*$\n+\s*(\d{4}-\d{2}-\d{2})/m);
|
|
30013
30055
|
if (!m) continue;
|
|
30014
30056
|
const ageH = (Date.now() - (/* @__PURE__ */ new Date(`${m[1]}T00:00:00Z`)).getTime()) / 36e5;
|
|
@@ -30026,19 +30068,19 @@ function resolveStateDirFromArgs(args) {
|
|
|
30026
30068
|
for (let i = 0; i < args.length; i++) {
|
|
30027
30069
|
if (args[i] === "--state-dir" && args[i + 1]) stateDir = args[++i].trim();
|
|
30028
30070
|
}
|
|
30029
|
-
if (stateDir) return
|
|
30071
|
+
if (stateDir) return path35.resolve(stateDir);
|
|
30030
30072
|
const home = process.env.HOME || process.env.USERPROFILE || ".";
|
|
30031
|
-
const cwd =
|
|
30032
|
-
if (
|
|
30033
|
-
const pointer =
|
|
30034
|
-
if (
|
|
30073
|
+
const cwd = path35.resolve(process.cwd());
|
|
30074
|
+
if (fs34.existsSync(path35.join(cwd, "configs"))) return cwd;
|
|
30075
|
+
const pointer = path35.join(home, ".engine7.json");
|
|
30076
|
+
if (fs34.existsSync(pointer)) {
|
|
30035
30077
|
try {
|
|
30036
|
-
const ptrStateDir = JSON.parse(
|
|
30037
|
-
if (typeof ptrStateDir === "string" && ptrStateDir.trim()) return
|
|
30078
|
+
const ptrStateDir = JSON.parse(fs34.readFileSync(pointer, "utf8")).stateDir;
|
|
30079
|
+
if (typeof ptrStateDir === "string" && ptrStateDir.trim()) return path35.resolve(ptrStateDir);
|
|
30038
30080
|
} catch {
|
|
30039
30081
|
}
|
|
30040
30082
|
}
|
|
30041
|
-
return
|
|
30083
|
+
return path35.join(home, ".engine7");
|
|
30042
30084
|
}
|
|
30043
30085
|
var init_cli_doctor = __esm({
|
|
30044
30086
|
"src/cli-doctor.ts"() {
|
|
@@ -30051,8 +30093,8 @@ var init_cli_doctor = __esm({
|
|
|
30051
30093
|
});
|
|
30052
30094
|
|
|
30053
30095
|
// src/config/writer.ts
|
|
30054
|
-
import
|
|
30055
|
-
import
|
|
30096
|
+
import fs35 from "node:fs";
|
|
30097
|
+
import path36 from "node:path";
|
|
30056
30098
|
function isNormalized(text) {
|
|
30057
30099
|
if (text === "") return true;
|
|
30058
30100
|
if (text.includes("\r")) return false;
|
|
@@ -30067,13 +30109,13 @@ function isNormalized(text) {
|
|
|
30067
30109
|
return minIndent === 2 || minIndent === Infinity;
|
|
30068
30110
|
}
|
|
30069
30111
|
function rotateBaks(filePath) {
|
|
30070
|
-
const dir =
|
|
30071
|
-
const base =
|
|
30072
|
-
const baks =
|
|
30112
|
+
const dir = path36.dirname(filePath);
|
|
30113
|
+
const base = path36.basename(filePath);
|
|
30114
|
+
const baks = fs35.readdirSync(dir).filter((n) => n.startsWith(base + ".bak-")).sort();
|
|
30073
30115
|
while (baks.length >= KEEP_BAKS) {
|
|
30074
30116
|
const victim = baks.shift();
|
|
30075
30117
|
try {
|
|
30076
|
-
|
|
30118
|
+
fs35.unlinkSync(path36.join(dir, victim));
|
|
30077
30119
|
} catch {
|
|
30078
30120
|
}
|
|
30079
30121
|
}
|
|
@@ -30092,7 +30134,7 @@ function writeFailure(filePath, primary, extra) {
|
|
|
30092
30134
|
function renameWithRetry(from, to) {
|
|
30093
30135
|
for (let attempt = 1; ; attempt++) {
|
|
30094
30136
|
try {
|
|
30095
|
-
|
|
30137
|
+
fs35.renameSync(from, to);
|
|
30096
30138
|
return;
|
|
30097
30139
|
} catch (err) {
|
|
30098
30140
|
if (attempt >= RENAME_ATTEMPTS || !RETRYABLE_CODES.has(errCode(err))) throw err;
|
|
@@ -30107,32 +30149,32 @@ function commitFile(tmp, filePath) {
|
|
|
30107
30149
|
} catch (primaryErr) {
|
|
30108
30150
|
const old = `${filePath}.old`;
|
|
30109
30151
|
try {
|
|
30110
|
-
|
|
30152
|
+
fs35.renameSync(filePath, old);
|
|
30111
30153
|
} catch (err) {
|
|
30112
30154
|
throw writeFailure(filePath, primaryErr, `\u6539\u540D .old \u5907\u4EFD\u4E5F\u5931\u8D25\uFF08${errCode(err) || "\u672A\u77E5"}\uFF09`);
|
|
30113
30155
|
}
|
|
30114
30156
|
try {
|
|
30115
|
-
|
|
30157
|
+
fs35.renameSync(tmp, filePath);
|
|
30116
30158
|
} catch (err) {
|
|
30117
30159
|
try {
|
|
30118
|
-
|
|
30160
|
+
fs35.renameSync(old, filePath);
|
|
30119
30161
|
} catch {
|
|
30120
30162
|
throw writeFailure(filePath, primaryErr, `\u65B0\u5185\u5BB9\u843D\u76D8\u4E0E\u56DE\u6EDA\u90FD\u5931\u8D25\uFF0C\u65E7\u5185\u5BB9\u7559\u5728 ${old}`);
|
|
30121
30163
|
}
|
|
30122
30164
|
throw writeFailure(filePath, primaryErr, `\u6362\u540D\u843D\u76D8\u5931\u8D25\uFF08${errCode(err) || "\u672A\u77E5"}\uFF09`);
|
|
30123
30165
|
}
|
|
30124
30166
|
try {
|
|
30125
|
-
|
|
30167
|
+
fs35.unlinkSync(old);
|
|
30126
30168
|
} catch {
|
|
30127
30169
|
}
|
|
30128
30170
|
}
|
|
30129
30171
|
}
|
|
30130
30172
|
function writeConfigAtomic(filePath, obj) {
|
|
30131
|
-
const existed =
|
|
30173
|
+
const existed = fs35.existsSync(filePath);
|
|
30132
30174
|
let prevText = "";
|
|
30133
30175
|
if (existed) {
|
|
30134
30176
|
try {
|
|
30135
|
-
prevText =
|
|
30177
|
+
prevText = fs35.readFileSync(filePath, "utf-8");
|
|
30136
30178
|
} catch (err) {
|
|
30137
30179
|
throw writeFailure(filePath, err);
|
|
30138
30180
|
}
|
|
@@ -30140,27 +30182,27 @@ function writeConfigAtomic(filePath, obj) {
|
|
|
30140
30182
|
const normalized = !existed || !isNormalized(prevText);
|
|
30141
30183
|
if (prevText) {
|
|
30142
30184
|
try {
|
|
30143
|
-
|
|
30185
|
+
fs35.copyFileSync(filePath, `${filePath}.bak-${Date.now()}`);
|
|
30144
30186
|
} catch {
|
|
30145
30187
|
}
|
|
30146
30188
|
rotateBaks(filePath);
|
|
30147
30189
|
}
|
|
30148
30190
|
const content = JSON.stringify(obj, null, 2) + "\n";
|
|
30149
|
-
const tmp =
|
|
30191
|
+
const tmp = path36.join(path36.dirname(filePath), `.${path36.basename(filePath)}.tmp-${process.pid}`);
|
|
30150
30192
|
try {
|
|
30151
|
-
const fd =
|
|
30193
|
+
const fd = fs35.openSync(tmp, "w");
|
|
30152
30194
|
try {
|
|
30153
|
-
|
|
30154
|
-
|
|
30195
|
+
fs35.writeFileSync(fd, content, "utf-8");
|
|
30196
|
+
fs35.fsyncSync(fd);
|
|
30155
30197
|
} finally {
|
|
30156
|
-
|
|
30198
|
+
fs35.closeSync(fd);
|
|
30157
30199
|
}
|
|
30158
30200
|
commitFile(tmp, filePath);
|
|
30159
30201
|
} catch (err) {
|
|
30160
30202
|
throw err instanceof ConfigWriteError ? err : writeFailure(filePath, err);
|
|
30161
30203
|
} finally {
|
|
30162
30204
|
try {
|
|
30163
|
-
|
|
30205
|
+
fs35.unlinkSync(tmp);
|
|
30164
30206
|
} catch {
|
|
30165
30207
|
}
|
|
30166
30208
|
}
|
|
@@ -30186,18 +30228,18 @@ var init_writer2 = __esm({
|
|
|
30186
30228
|
});
|
|
30187
30229
|
|
|
30188
30230
|
// src/config/secrets-io.ts
|
|
30189
|
-
import
|
|
30190
|
-
import
|
|
30231
|
+
import fs36 from "node:fs";
|
|
30232
|
+
import path37 from "node:path";
|
|
30191
30233
|
function resolveSecretPath(stateDir, configName) {
|
|
30192
30234
|
return secretsCandidates(stateDir, configName)[0];
|
|
30193
30235
|
}
|
|
30194
30236
|
function resolveSecretReadPath(stateDir, configName) {
|
|
30195
|
-
return secretsCandidates(stateDir, configName).find((c) =>
|
|
30237
|
+
return secretsCandidates(stateDir, configName).find((c) => fs36.existsSync(c)) ?? null;
|
|
30196
30238
|
}
|
|
30197
30239
|
function readSecretStatus(stateDir, configName, names) {
|
|
30198
30240
|
const p = resolveSecretReadPath(stateDir, configName);
|
|
30199
30241
|
const out = {};
|
|
30200
|
-
const text = p ?
|
|
30242
|
+
const text = p ? fs36.readFileSync(p, "utf-8") : "";
|
|
30201
30243
|
const present = /* @__PURE__ */ new Set();
|
|
30202
30244
|
for (const line of text.split("\n")) {
|
|
30203
30245
|
const t = line.trim();
|
|
@@ -30210,7 +30252,7 @@ function readSecretStatus(stateDir, configName, names) {
|
|
|
30210
30252
|
return out;
|
|
30211
30253
|
}
|
|
30212
30254
|
function writeSecret(stateDir, configName, name, value) {
|
|
30213
|
-
writeSecretsValue(
|
|
30255
|
+
writeSecretsValue(path37.join(stateDir, "configs", `${configName}.json`), name, value);
|
|
30214
30256
|
}
|
|
30215
30257
|
var init_secrets_io = __esm({
|
|
30216
30258
|
"src/config/secrets-io.ts"() {
|
|
@@ -30220,8 +30262,8 @@ var init_secrets_io = __esm({
|
|
|
30220
30262
|
});
|
|
30221
30263
|
|
|
30222
30264
|
// src/config/migrations/index.ts
|
|
30223
|
-
import
|
|
30224
|
-
import
|
|
30265
|
+
import fs37 from "node:fs";
|
|
30266
|
+
import path38 from "node:path";
|
|
30225
30267
|
function registerMigration(m) {
|
|
30226
30268
|
if (REGISTRY.has(m.name)) {
|
|
30227
30269
|
throw new Error(`[migrations] \u8FC1\u79FB "${m.name}" \u91CD\u590D\u6CE8\u518C\u2014\u2014\u540C\u540D\u4F1A\u6309 import \u987A\u5E8F\u9759\u9ED8\u8986\u76D6`);
|
|
@@ -30237,21 +30279,21 @@ async function runMigration(name, ctx) {
|
|
|
30237
30279
|
return await m.run(ctx);
|
|
30238
30280
|
}
|
|
30239
30281
|
function rotateBaks2(filePath) {
|
|
30240
|
-
const dir =
|
|
30241
|
-
const base =
|
|
30242
|
-
const baks =
|
|
30282
|
+
const dir = path38.dirname(filePath);
|
|
30283
|
+
const base = path38.basename(filePath);
|
|
30284
|
+
const baks = fs37.readdirSync(dir).filter((n) => n.startsWith(base + ".bak-")).sort();
|
|
30243
30285
|
while (baks.length > KEEP_BAKS2) {
|
|
30244
30286
|
const victim = baks.shift();
|
|
30245
30287
|
try {
|
|
30246
|
-
|
|
30288
|
+
fs37.unlinkSync(path38.join(dir, victim));
|
|
30247
30289
|
} catch {
|
|
30248
30290
|
}
|
|
30249
30291
|
}
|
|
30250
30292
|
}
|
|
30251
30293
|
function backupFile(filePath) {
|
|
30252
|
-
if (!
|
|
30294
|
+
if (!fs37.existsSync(filePath)) return null;
|
|
30253
30295
|
const bak = `${filePath}.bak-${Date.now()}`;
|
|
30254
|
-
|
|
30296
|
+
fs37.copyFileSync(filePath, bak);
|
|
30255
30297
|
rotateBaks2(filePath);
|
|
30256
30298
|
return bak;
|
|
30257
30299
|
}
|
|
@@ -30265,11 +30307,11 @@ var init_migrations = __esm({
|
|
|
30265
30307
|
});
|
|
30266
30308
|
|
|
30267
30309
|
// src/config/migrations/persona.ts
|
|
30268
|
-
import
|
|
30269
|
-
import
|
|
30310
|
+
import fs38 from "node:fs";
|
|
30311
|
+
import path39 from "node:path";
|
|
30270
30312
|
function readFileOrNull(p) {
|
|
30271
30313
|
try {
|
|
30272
|
-
return
|
|
30314
|
+
return fs38.readFileSync(p, "utf-8");
|
|
30273
30315
|
} catch {
|
|
30274
30316
|
return null;
|
|
30275
30317
|
}
|
|
@@ -30289,22 +30331,22 @@ var init_persona = __esm({
|
|
|
30289
30331
|
run(ctx) {
|
|
30290
30332
|
const persona = ctx.values?.agents?.defaults?.persona;
|
|
30291
30333
|
if (typeof persona !== "string" || !persona) return { changed: [] };
|
|
30292
|
-
const dir =
|
|
30293
|
-
if (!
|
|
30334
|
+
const dir = path39.join(ctx.workspace, "personas", persona);
|
|
30335
|
+
if (!fs38.existsSync(dir)) {
|
|
30294
30336
|
return { changed: [] };
|
|
30295
30337
|
}
|
|
30296
30338
|
const changed = [];
|
|
30297
30339
|
for (const name of POINTER_FILES) {
|
|
30298
|
-
const src =
|
|
30340
|
+
const src = path39.join(dir, name);
|
|
30299
30341
|
const content = readFileOrNull(src);
|
|
30300
30342
|
if (content === null) continue;
|
|
30301
|
-
const legacy =
|
|
30343
|
+
const legacy = path39.join(ctx.workspace, LEGACY_PATHS[name]);
|
|
30302
30344
|
const legacyContent = readFileOrNull(legacy);
|
|
30303
30345
|
if (legacyContent !== null && legacyContent === content) {
|
|
30304
|
-
|
|
30346
|
+
fs38.renameSync(legacy, `${legacy}.migrated-${Date.now()}`);
|
|
30305
30347
|
changed.push(`${LEGACY_PATHS[name]} \u2192 personas/${persona}/${name}`);
|
|
30306
30348
|
} else if (legacyContent !== null) {
|
|
30307
|
-
|
|
30349
|
+
fs38.renameSync(legacy, `${legacy}.bak-${Date.now()}`);
|
|
30308
30350
|
changed.push(`${LEGACY_PATHS[name]} \u2192 .bak\uFF08\u5185\u5BB9\u4E0E\u6A21\u677F\u4E0D\u540C\uFF0C\u4FDD\u5B88\u4FDD\u7559\uFF09`);
|
|
30309
30351
|
}
|
|
30310
30352
|
}
|
|
@@ -30316,7 +30358,7 @@ var init_persona = __esm({
|
|
|
30316
30358
|
});
|
|
30317
30359
|
|
|
30318
30360
|
// src/config/migrations/channel-secrets.ts
|
|
30319
|
-
import
|
|
30361
|
+
import fs39 from "node:fs";
|
|
30320
30362
|
function envNameFor(dotPath) {
|
|
30321
30363
|
const declared = getField(dotPath)?.envKey;
|
|
30322
30364
|
if (declared) return declared;
|
|
@@ -30358,15 +30400,15 @@ function planChannelSecretMoves(config) {
|
|
|
30358
30400
|
}
|
|
30359
30401
|
function restoreEnv(envPath, before) {
|
|
30360
30402
|
try {
|
|
30361
|
-
if (before === null)
|
|
30362
|
-
else
|
|
30403
|
+
if (before === null) fs39.unlinkSync(envPath);
|
|
30404
|
+
else fs39.writeFileSync(envPath, before, "utf8");
|
|
30363
30405
|
} catch {
|
|
30364
30406
|
}
|
|
30365
30407
|
}
|
|
30366
30408
|
function dropBackup(backup) {
|
|
30367
30409
|
if (backup) {
|
|
30368
30410
|
try {
|
|
30369
|
-
|
|
30411
|
+
fs39.unlinkSync(backup);
|
|
30370
30412
|
} catch {
|
|
30371
30413
|
}
|
|
30372
30414
|
}
|
|
@@ -30375,7 +30417,7 @@ function migrateChannelSecrets(configPath, deps = {}) {
|
|
|
30375
30417
|
const writeConfig = deps.writeConfig ?? ((p, obj) => writeConfigAtomic(p, obj));
|
|
30376
30418
|
let text;
|
|
30377
30419
|
try {
|
|
30378
|
-
text =
|
|
30420
|
+
text = fs39.readFileSync(configPath, "utf-8");
|
|
30379
30421
|
} catch {
|
|
30380
30422
|
return { changed: [], backup: null, secretsFile: null };
|
|
30381
30423
|
}
|
|
@@ -30392,7 +30434,7 @@ function migrateChannelSecrets(configPath, deps = {}) {
|
|
|
30392
30434
|
if (moves.length === 0) return { changed: [], backup: null, secretsFile: null };
|
|
30393
30435
|
const { stateDir, configName } = resolveConfigIdentity(configPath);
|
|
30394
30436
|
const envPath = secretsCandidates(stateDir, configName)[0];
|
|
30395
|
-
const envBefore =
|
|
30437
|
+
const envBefore = fs39.existsSync(envPath) ? fs39.readFileSync(envPath, "utf-8") : null;
|
|
30396
30438
|
const backup = backupFile(configPath);
|
|
30397
30439
|
try {
|
|
30398
30440
|
for (const m of moves) writeSecret(stateDir, configName, m.envName, m.value);
|
|
@@ -30413,7 +30455,7 @@ function migrateChannelSecrets(configPath, deps = {}) {
|
|
|
30413
30455
|
const problem = verify(configPath, envPath, moves);
|
|
30414
30456
|
if (problem) {
|
|
30415
30457
|
try {
|
|
30416
|
-
if (backup)
|
|
30458
|
+
if (backup) fs39.copyFileSync(backup, configPath);
|
|
30417
30459
|
} catch {
|
|
30418
30460
|
}
|
|
30419
30461
|
restoreEnv(envPath, envBefore);
|
|
@@ -30425,7 +30467,7 @@ function migrateChannelSecrets(configPath, deps = {}) {
|
|
|
30425
30467
|
function verify(configPath, envPath, moves) {
|
|
30426
30468
|
let cfg;
|
|
30427
30469
|
try {
|
|
30428
|
-
cfg = JSON.parse(
|
|
30470
|
+
cfg = JSON.parse(fs39.readFileSync(configPath, "utf-8"));
|
|
30429
30471
|
} catch (e) {
|
|
30430
30472
|
return `config \u8BFB\u4E0D\u56DE\u6765\u4E86\uFF08${e?.message || String(e)}\uFF09`;
|
|
30431
30473
|
}
|
|
@@ -30435,7 +30477,7 @@ function verify(configPath, envPath, moves) {
|
|
|
30435
30477
|
}
|
|
30436
30478
|
let env = "";
|
|
30437
30479
|
try {
|
|
30438
|
-
env =
|
|
30480
|
+
env = fs39.readFileSync(envPath, "utf-8");
|
|
30439
30481
|
} catch (e) {
|
|
30440
30482
|
return `secrets \u6587\u4EF6\u8BFB\u4E0D\u56DE\u6765\uFF08${e?.message || String(e)}\uFF09`;
|
|
30441
30483
|
}
|
|
@@ -30473,14 +30515,14 @@ __export(cli_config_exports, {
|
|
|
30473
30515
|
isSafeConfigName: () => isSafeConfigName,
|
|
30474
30516
|
runConfigCommand: () => runConfigCommand
|
|
30475
30517
|
});
|
|
30476
|
-
import
|
|
30477
|
-
import
|
|
30518
|
+
import fs40 from "node:fs";
|
|
30519
|
+
import path40 from "node:path";
|
|
30478
30520
|
function isSafeConfigName(name) {
|
|
30479
30521
|
return /^[\w.-]+$/.test(name);
|
|
30480
30522
|
}
|
|
30481
30523
|
function sameDir(a, b) {
|
|
30482
30524
|
const norm = (s) => {
|
|
30483
|
-
const r =
|
|
30525
|
+
const r = path40.resolve(s);
|
|
30484
30526
|
return process.platform === "win32" ? r.toLowerCase() : r;
|
|
30485
30527
|
};
|
|
30486
30528
|
return norm(a) === norm(b);
|
|
@@ -30508,7 +30550,7 @@ function parseArgs(args) {
|
|
|
30508
30550
|
badArgs.push(a);
|
|
30509
30551
|
}
|
|
30510
30552
|
if (config) {
|
|
30511
|
-
const configPath =
|
|
30553
|
+
const configPath = path40.resolve(config);
|
|
30512
30554
|
if (!/\.json$/i.test(configPath)) {
|
|
30513
30555
|
return {
|
|
30514
30556
|
stateDir,
|
|
@@ -30532,9 +30574,9 @@ function parseArgs(args) {
|
|
|
30532
30574
|
}
|
|
30533
30575
|
return { stateDir: ident.stateDir, configPath, configName: ident.configName, file: file2, badArgs };
|
|
30534
30576
|
}
|
|
30535
|
-
if (!stateDir) stateDir = process.env.ENGINE_STATE_DIR ||
|
|
30577
|
+
if (!stateDir) stateDir = process.env.ENGINE_STATE_DIR || path40.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
|
|
30536
30578
|
const configName = CONFIG_NAME;
|
|
30537
|
-
return { stateDir, configPath:
|
|
30579
|
+
return { stateDir, configPath: path40.join(stateDir, "configs", `${configName}.json`), configName, file: file2, badArgs };
|
|
30538
30580
|
}
|
|
30539
30581
|
function emit2(obj) {
|
|
30540
30582
|
process.stdout.write(JSON.stringify(obj) + "\n");
|
|
@@ -30572,7 +30614,7 @@ function shapeOf(v) {
|
|
|
30572
30614
|
function readConfigObject(configPath) {
|
|
30573
30615
|
let text;
|
|
30574
30616
|
try {
|
|
30575
|
-
text =
|
|
30617
|
+
text = fs40.readFileSync(configPath, "utf-8");
|
|
30576
30618
|
} catch {
|
|
30577
30619
|
return { obj: {}, corrupt: false };
|
|
30578
30620
|
}
|
|
@@ -30630,7 +30672,7 @@ function findMaskedCredentials(value, prefix, out) {
|
|
|
30630
30672
|
function readEnvKeys(file2) {
|
|
30631
30673
|
const out = [];
|
|
30632
30674
|
try {
|
|
30633
|
-
for (const line of
|
|
30675
|
+
for (const line of fs40.readFileSync(file2, "utf-8").split("\n")) {
|
|
30634
30676
|
const t = line.trim();
|
|
30635
30677
|
if (!t || t.startsWith("#")) continue;
|
|
30636
30678
|
const eq = t.indexOf("=");
|
|
@@ -30686,7 +30728,7 @@ async function runConfigCommand(args) {
|
|
|
30686
30728
|
}
|
|
30687
30729
|
let parsedPayload;
|
|
30688
30730
|
try {
|
|
30689
|
-
parsedPayload = JSON.parse(
|
|
30731
|
+
parsedPayload = JSON.parse(fs40.readFileSync(p.file, "utf-8"));
|
|
30690
30732
|
} catch (e) {
|
|
30691
30733
|
process.stderr.write(`[config] \u8BFB\u4E0D\u4E86 payload: ${e.message}
|
|
30692
30734
|
`);
|
|
@@ -30792,7 +30834,7 @@ async function runConfigCommand(args) {
|
|
|
30792
30834
|
}
|
|
30793
30835
|
if (secretWrites.length > 0) {
|
|
30794
30836
|
const writePath2 = resolveSecretPath(p.stateDir, p.configName);
|
|
30795
|
-
const fallback =
|
|
30837
|
+
const fallback = fs40.existsSync(writePath2) ? void 0 : secretsCandidates(p.stateDir, p.configName).find((c) => fs40.existsSync(c));
|
|
30796
30838
|
if (fallback) {
|
|
30797
30839
|
const writing = new Set(secretWrites.map((s) => s.name));
|
|
30798
30840
|
const others = readEnvKeys(fallback).filter((k) => !writing.has(k));
|
|
@@ -30801,11 +30843,11 @@ async function runConfigCommand(args) {
|
|
|
30801
30843
|
}
|
|
30802
30844
|
}
|
|
30803
30845
|
}
|
|
30804
|
-
if (
|
|
30846
|
+
if (fs40.existsSync(p.configPath) && !isNormalized(fs40.readFileSync(p.configPath, "utf-8"))) {
|
|
30805
30847
|
warnings.push("config \u9996\u6B21\u89C4\u8303\u5316\uFF1A\u884C\u5C3E\u7EDF\u4E00\u4E3A LF\u3001\u7F29\u8FDB\u7EDF\u4E00\u4E3A 2 \u7A7A\u683C\uFF08\u4E00\u6B21\u6027\u5927 diff\uFF09");
|
|
30806
30848
|
}
|
|
30807
|
-
const configDir =
|
|
30808
|
-
if (!
|
|
30849
|
+
const configDir = path40.dirname(p.configPath);
|
|
30850
|
+
if (!fs40.existsSync(configDir)) fs40.mkdirSync(configDir, { recursive: true });
|
|
30809
30851
|
try {
|
|
30810
30852
|
writeConfigAtomic(p.configPath, merged);
|
|
30811
30853
|
} catch (e) {
|
|
@@ -30820,7 +30862,7 @@ async function runConfigCommand(args) {
|
|
|
30820
30862
|
warnings.push(`secrets \u5199\u5165\u5931\u8D25\uFF08${s.name}\uFF09\uFF1A${e?.message || String(e)}\u2014\u2014config \u5DF2\u5199\u5165`);
|
|
30821
30863
|
}
|
|
30822
30864
|
}
|
|
30823
|
-
const workspace =
|
|
30865
|
+
const workspace = path40.join(p.stateDir, "workspace");
|
|
30824
30866
|
const ctx = { workspace, stateDir: p.stateDir, values: nested, all: merged, configPath: p.configPath };
|
|
30825
30867
|
for (const dotPath of [...new Set(changed)]) {
|
|
30826
30868
|
const migrationName = getField(dotPath)?.migration;
|
|
@@ -30909,41 +30951,41 @@ __export(cli_reconfig_exports, {
|
|
|
30909
30951
|
doReconfigFeishu: () => doReconfigFeishu,
|
|
30910
30952
|
doReconfigWechat: () => doReconfigWechat
|
|
30911
30953
|
});
|
|
30912
|
-
import * as
|
|
30913
|
-
import * as
|
|
30954
|
+
import * as fs41 from "node:fs";
|
|
30955
|
+
import * as path41 from "node:path";
|
|
30914
30956
|
function scanForChannelsConfig(configsDir) {
|
|
30915
|
-
if (!
|
|
30916
|
-
for (const f of
|
|
30917
|
-
const full =
|
|
30957
|
+
if (!fs41.existsSync(configsDir)) return "";
|
|
30958
|
+
for (const f of fs41.readdirSync(configsDir).filter((x) => x.endsWith(".json"))) {
|
|
30959
|
+
const full = path41.join(configsDir, f);
|
|
30918
30960
|
try {
|
|
30919
|
-
if (JSON.parse(
|
|
30961
|
+
if (JSON.parse(fs41.readFileSync(full, "utf8")).channels) return full;
|
|
30920
30962
|
} catch {
|
|
30921
30963
|
}
|
|
30922
30964
|
}
|
|
30923
30965
|
return "";
|
|
30924
30966
|
}
|
|
30925
30967
|
function findFeishuConfigFile(stateDir, configName) {
|
|
30926
|
-
const configsDir =
|
|
30968
|
+
const configsDir = path41.join(stateDir, "configs");
|
|
30927
30969
|
if (configName) {
|
|
30928
|
-
const p =
|
|
30929
|
-
if (
|
|
30970
|
+
const p = path41.join(configsDir, configName);
|
|
30971
|
+
if (fs41.existsSync(p)) return p;
|
|
30930
30972
|
}
|
|
30931
30973
|
return scanForChannelsConfig(configsDir);
|
|
30932
30974
|
}
|
|
30933
30975
|
function findWechatConfigFile(stateDir, configName) {
|
|
30934
|
-
const configsDir =
|
|
30976
|
+
const configsDir = path41.join(stateDir, "configs");
|
|
30935
30977
|
if (configName) {
|
|
30936
|
-
const p =
|
|
30937
|
-
return
|
|
30978
|
+
const p = path41.join(configsDir, configName);
|
|
30979
|
+
return fs41.existsSync(p) ? p : "";
|
|
30938
30980
|
}
|
|
30939
30981
|
const scanned = scanForChannelsConfig(configsDir);
|
|
30940
30982
|
if (scanned) return scanned;
|
|
30941
|
-
if (
|
|
30942
|
-
const candidates =
|
|
30983
|
+
if (fs41.existsSync(configsDir)) {
|
|
30984
|
+
const candidates = fs41.readdirSync(configsDir).filter((f) => f.endsWith(".json"));
|
|
30943
30985
|
if (candidates.length) {
|
|
30944
|
-
const first =
|
|
30986
|
+
const first = path41.join(configsDir, candidates[0]);
|
|
30945
30987
|
try {
|
|
30946
|
-
JSON.parse(
|
|
30988
|
+
JSON.parse(fs41.readFileSync(first, "utf8"));
|
|
30947
30989
|
return first;
|
|
30948
30990
|
} catch {
|
|
30949
30991
|
}
|
|
@@ -30982,11 +31024,11 @@ async function doReconfigFeishu(opts) {
|
|
|
30982
31024
|
return 2;
|
|
30983
31025
|
}
|
|
30984
31026
|
const configFile = findFeishuConfigFile(stateDir, configName);
|
|
30985
|
-
if (configFile &&
|
|
31027
|
+
if (configFile && fs41.existsSync(configFile)) {
|
|
30986
31028
|
if (events) emit3?.({ event: "progress", step: "write_config" });
|
|
30987
31029
|
let j;
|
|
30988
31030
|
try {
|
|
30989
|
-
j = JSON.parse(
|
|
31031
|
+
j = JSON.parse(fs41.readFileSync(configFile, "utf8"));
|
|
30990
31032
|
} catch (err) {
|
|
30991
31033
|
if (events) emit3?.({ event: "error", message: `\u8BFB\u53D6 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09` });
|
|
30992
31034
|
else console.error(`\u274C \u8BFB\u53D6 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09`);
|
|
@@ -31004,7 +31046,7 @@ async function doReconfigFeishu(opts) {
|
|
|
31004
31046
|
}
|
|
31005
31047
|
j.channels.feishu = { enabled: true, appId: result.appId, appSecret: secretRef(feishuSecretEnv, result.appSecret), connectionMode: "websocket", dmPolicy: "pairing", groupPolicy: "open" };
|
|
31006
31048
|
try {
|
|
31007
|
-
|
|
31049
|
+
fs41.writeFileSync(configFile, JSON.stringify(j, null, 2), "utf8");
|
|
31008
31050
|
} catch (err) {
|
|
31009
31051
|
if (events) emit3?.({ event: "error", message: `\u5199\u5165 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09` });
|
|
31010
31052
|
else console.error(`\u274C \u5199\u5165 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09`);
|
|
@@ -31037,7 +31079,7 @@ async function doReconfigWechat(opts) {
|
|
|
31037
31079
|
return 2;
|
|
31038
31080
|
}
|
|
31039
31081
|
const configFile = findWechatConfigFile(stateDir, configName);
|
|
31040
|
-
if (!configFile || !
|
|
31082
|
+
if (!configFile || !fs41.existsSync(configFile)) {
|
|
31041
31083
|
console.log("\n\u26A0\uFE0F \u6CA1\u627E\u5230 config \u6587\u4EF6\uFF0C\u8BF7\u624B\u52A8\u628A\u4EE5\u4E0B\u6BB5\u52A0\u8FDB\u4F60\u7684 config \u7684 channels \u91CC\uFF1A");
|
|
31042
31084
|
console.log(JSON.stringify({ wechat: { enabled: true, token: cred.token, accountId: cred.accountId, dmPolicy: "pairing", group: { policy: "disabled" } } }, null, 2));
|
|
31043
31085
|
if (events) emit3?.({ event: "done", channel: "wechat", detail: cred.accountId, restart_required: true });
|
|
@@ -31046,7 +31088,7 @@ async function doReconfigWechat(opts) {
|
|
|
31046
31088
|
if (events) emit3?.({ event: "progress", step: "write_config" });
|
|
31047
31089
|
let j;
|
|
31048
31090
|
try {
|
|
31049
|
-
j = JSON.parse(
|
|
31091
|
+
j = JSON.parse(fs41.readFileSync(configFile, "utf8"));
|
|
31050
31092
|
} catch (err) {
|
|
31051
31093
|
if (events) emit3?.({ event: "error", message: `\u8BFB\u53D6 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09` });
|
|
31052
31094
|
else console.error(`\u274C \u8BFB\u53D6 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09`);
|
|
@@ -31064,7 +31106,7 @@ async function doReconfigWechat(opts) {
|
|
|
31064
31106
|
}
|
|
31065
31107
|
j.channels.wechat = { enabled: true, token: secretRef(wechatSecretEnv, cred.token), accountId: cred.accountId, dmPolicy: "pairing", group: { policy: "disabled" } };
|
|
31066
31108
|
try {
|
|
31067
|
-
|
|
31109
|
+
fs41.writeFileSync(configFile, JSON.stringify(j, null, 2), "utf8");
|
|
31068
31110
|
} catch (err) {
|
|
31069
31111
|
if (events) emit3?.({ event: "error", message: `\u5199\u5165 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09` });
|
|
31070
31112
|
else console.error(`\u274C \u5199\u5165 config \u5931\u8D25: ${configFile}\uFF08${err?.message || err}\uFF09`);
|
|
@@ -31101,20 +31143,20 @@ __export(cli_travel_exports, {
|
|
|
31101
31143
|
resolveArchiveForTest: () => resolveArchiveForTest,
|
|
31102
31144
|
saveTravelConfig: () => saveTravelConfig
|
|
31103
31145
|
});
|
|
31104
|
-
import * as
|
|
31105
|
-
import * as
|
|
31146
|
+
import * as path42 from "node:path";
|
|
31147
|
+
import * as fs42 from "node:fs";
|
|
31106
31148
|
import * as os6 from "node:os";
|
|
31107
|
-
import { execSync as
|
|
31149
|
+
import { execSync as execSync3 } from "node:child_process";
|
|
31108
31150
|
function loadTravelConfig() {
|
|
31109
31151
|
try {
|
|
31110
|
-
if (!
|
|
31111
|
-
return JSON.parse(
|
|
31152
|
+
if (!fs42.existsSync(CONFIG_PATH)) return null;
|
|
31153
|
+
return JSON.parse(fs42.readFileSync(CONFIG_PATH, "utf-8"));
|
|
31112
31154
|
} catch {
|
|
31113
31155
|
return null;
|
|
31114
31156
|
}
|
|
31115
31157
|
}
|
|
31116
31158
|
function saveTravelConfig(cfg) {
|
|
31117
|
-
|
|
31159
|
+
fs42.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2));
|
|
31118
31160
|
}
|
|
31119
31161
|
function sanitizeContent(content, dirs) {
|
|
31120
31162
|
let result = content;
|
|
@@ -31139,7 +31181,7 @@ function restoreContent(content, dirs) {
|
|
|
31139
31181
|
return result;
|
|
31140
31182
|
}
|
|
31141
31183
|
function isTextFile(filePath) {
|
|
31142
|
-
const ext =
|
|
31184
|
+
const ext = path42.extname(filePath).toLowerCase();
|
|
31143
31185
|
return TEXT_EXTENSIONS.has(ext);
|
|
31144
31186
|
}
|
|
31145
31187
|
function shouldExclude(name) {
|
|
@@ -31154,14 +31196,14 @@ function shouldExclude(name) {
|
|
|
31154
31196
|
}
|
|
31155
31197
|
function collectFiles(rootDir, includeSet, optionalSet) {
|
|
31156
31198
|
const files = [];
|
|
31157
|
-
const entries2 =
|
|
31199
|
+
const entries2 = fs42.readdirSync(rootDir, { withFileTypes: true });
|
|
31158
31200
|
for (const entry of entries2) {
|
|
31159
31201
|
if (shouldExclude(entry.name)) continue;
|
|
31160
|
-
const fullPath =
|
|
31161
|
-
const realPath =
|
|
31202
|
+
const fullPath = path42.join(rootDir, entry.name);
|
|
31203
|
+
const realPath = fs42.realpathSync(fullPath);
|
|
31162
31204
|
if (realPath !== fullPath) {
|
|
31163
31205
|
try {
|
|
31164
|
-
const lstat =
|
|
31206
|
+
const lstat = fs42.lstatSync(fullPath);
|
|
31165
31207
|
if (lstat.isSymbolicLink()) {
|
|
31166
31208
|
continue;
|
|
31167
31209
|
}
|
|
@@ -31182,12 +31224,12 @@ function collectFiles(rootDir, includeSet, optionalSet) {
|
|
|
31182
31224
|
function collectAllFiles(dir) {
|
|
31183
31225
|
const files = [];
|
|
31184
31226
|
try {
|
|
31185
|
-
const entries2 =
|
|
31227
|
+
const entries2 = fs42.readdirSync(dir, { withFileTypes: true });
|
|
31186
31228
|
for (const entry of entries2) {
|
|
31187
31229
|
if (shouldExclude(entry.name)) continue;
|
|
31188
|
-
const fullPath =
|
|
31230
|
+
const fullPath = path42.join(dir, entry.name);
|
|
31189
31231
|
try {
|
|
31190
|
-
if (
|
|
31232
|
+
if (fs42.lstatSync(fullPath).isSymbolicLink()) continue;
|
|
31191
31233
|
} catch {
|
|
31192
31234
|
}
|
|
31193
31235
|
if (entry.isDirectory()) {
|
|
@@ -31202,16 +31244,16 @@ function collectAllFiles(dir) {
|
|
|
31202
31244
|
}
|
|
31203
31245
|
function readMainEngineUuid(agentsDir) {
|
|
31204
31246
|
try {
|
|
31205
|
-
const platformMapPath =
|
|
31206
|
-
const indexMapPath =
|
|
31207
|
-
if (!
|
|
31208
|
-
const platformMap = JSON.parse(
|
|
31247
|
+
const platformMapPath = path42.join(agentsDir, "main", "sessions", "platform-map.json");
|
|
31248
|
+
const indexMapPath = path42.join(agentsDir, "main", "sessions", "session-index.json");
|
|
31249
|
+
if (!fs42.existsSync(platformMapPath) || !fs42.existsSync(indexMapPath)) return null;
|
|
31250
|
+
const platformMap = JSON.parse(fs42.readFileSync(platformMapPath, "utf-8"));
|
|
31209
31251
|
const mainPlatformId = platformMap["scope:main"] || platformMap["main"];
|
|
31210
31252
|
if (!mainPlatformId) return null;
|
|
31211
|
-
const indexMap = JSON.parse(
|
|
31253
|
+
const indexMap = JSON.parse(fs42.readFileSync(indexMapPath, "utf-8"));
|
|
31212
31254
|
const entry = indexMap[mainPlatformId];
|
|
31213
31255
|
if (!entry || !entry.file) return null;
|
|
31214
|
-
const basename10 =
|
|
31256
|
+
const basename10 = path42.basename(entry.file).replace(/\.jsonl$/, "");
|
|
31215
31257
|
return basename10;
|
|
31216
31258
|
} catch {
|
|
31217
31259
|
return null;
|
|
@@ -31219,13 +31261,13 @@ function readMainEngineUuid(agentsDir) {
|
|
|
31219
31261
|
}
|
|
31220
31262
|
function collectRecentSessions(agentsDir, _days = 7) {
|
|
31221
31263
|
const files = [];
|
|
31222
|
-
if (!
|
|
31264
|
+
if (!fs42.existsSync(agentsDir)) return files;
|
|
31223
31265
|
const sessionGroups = /* @__PURE__ */ new Map();
|
|
31224
31266
|
function scanSessionsDir(dir) {
|
|
31225
31267
|
try {
|
|
31226
|
-
const entries2 =
|
|
31268
|
+
const entries2 = fs42.readdirSync(dir, { withFileTypes: true });
|
|
31227
31269
|
for (const entry of entries2) {
|
|
31228
|
-
const fullPath =
|
|
31270
|
+
const fullPath = path42.join(dir, entry.name);
|
|
31229
31271
|
if (entry.isDirectory()) {
|
|
31230
31272
|
scanSessionsDir(fullPath);
|
|
31231
31273
|
continue;
|
|
@@ -31249,7 +31291,7 @@ function collectRecentSessions(agentsDir, _days = 7) {
|
|
|
31249
31291
|
if (entry.name.endsWith(".jsonl")) {
|
|
31250
31292
|
group.jsonl = fullPath;
|
|
31251
31293
|
} else {
|
|
31252
|
-
const stat4 =
|
|
31294
|
+
const stat4 = fs42.statSync(fullPath);
|
|
31253
31295
|
group.archived.push({ file: fullPath, mtime: stat4.mtimeMs });
|
|
31254
31296
|
}
|
|
31255
31297
|
}
|
|
@@ -31268,21 +31310,21 @@ function collectRecentSessions(agentsDir, _days = 7) {
|
|
|
31268
31310
|
}
|
|
31269
31311
|
function collectExportFileSet(stateDir, workspace) {
|
|
31270
31312
|
const wsFiles = collectFiles(workspace, WORKSPACE_INCLUDE, WORKSPACE_OPTIONAL);
|
|
31271
|
-
const sessionFiles = collectRecentSessions(
|
|
31272
|
-
const configsDir =
|
|
31313
|
+
const sessionFiles = collectRecentSessions(path42.join(stateDir, "agents"), 7);
|
|
31314
|
+
const configsDir = path42.join(stateDir, "configs");
|
|
31273
31315
|
const configFiles = [];
|
|
31274
|
-
if (
|
|
31316
|
+
if (fs42.existsSync(configsDir)) {
|
|
31275
31317
|
for (const f of collectAllFiles(configsDir)) {
|
|
31276
|
-
if (shouldExclude(
|
|
31318
|
+
if (shouldExclude(path42.basename(f))) continue;
|
|
31277
31319
|
configFiles.push(f);
|
|
31278
31320
|
}
|
|
31279
31321
|
}
|
|
31280
31322
|
const EVEROS_SKIP = /* @__PURE__ */ new Set([".tmp", ".lock", "import.log", "import_progress.json"]);
|
|
31281
|
-
const everosDir =
|
|
31323
|
+
const everosDir = path42.join(stateDir, ".everos");
|
|
31282
31324
|
const everosFiles = [];
|
|
31283
|
-
if (
|
|
31325
|
+
if (fs42.existsSync(everosDir)) {
|
|
31284
31326
|
for (const f of collectAllFiles(everosDir)) {
|
|
31285
|
-
if (EVEROS_SKIP.has(
|
|
31327
|
+
if (EVEROS_SKIP.has(path42.basename(f))) continue;
|
|
31286
31328
|
everosFiles.push(f);
|
|
31287
31329
|
}
|
|
31288
31330
|
}
|
|
@@ -31290,13 +31332,13 @@ function collectExportFileSet(stateDir, workspace) {
|
|
|
31290
31332
|
}
|
|
31291
31333
|
async function doExport(opts) {
|
|
31292
31334
|
const { agentName, stateDir, note, dryRun: dryRun2 } = opts;
|
|
31293
|
-
const workspace = (opts.workspace ||
|
|
31294
|
-
const engineHome =
|
|
31335
|
+
const workspace = (opts.workspace || path42.join(stateDir, "workspace")).replace(/[/\\]+$/, "");
|
|
31336
|
+
const engineHome = path42.join(os6.homedir(), ".engine7").replace(/[/\\]+$/, "");
|
|
31295
31337
|
console.log(`\u{1F4E6} engine7 export`);
|
|
31296
31338
|
console.log(` agent: ${agentName}`);
|
|
31297
31339
|
console.log(` state: ${stateDir}`);
|
|
31298
31340
|
console.log(` workspace: ${workspace}`);
|
|
31299
|
-
if (!
|
|
31341
|
+
if (!fs42.existsSync(workspace)) {
|
|
31300
31342
|
console.error(`\u274C workspace \u4E0D\u5B58\u5728: ${workspace}`);
|
|
31301
31343
|
process.exit(1);
|
|
31302
31344
|
}
|
|
@@ -31305,16 +31347,16 @@ async function doExport(opts) {
|
|
|
31305
31347
|
console.log(` workspace \u6587\u4EF6: ${wsFiles.length}`);
|
|
31306
31348
|
console.log(` session jsonl: ${sessionFiles.length} (\u6700\u8FD17\u5929)`);
|
|
31307
31349
|
console.log(` configs: ${configFiles.length}`);
|
|
31308
|
-
console.log(` everos: ${everosFiles.length} (${(everosFiles.reduce((s, f) => s +
|
|
31350
|
+
console.log(` everos: ${everosFiles.length} (${(everosFiles.reduce((s, f) => s + fs42.statSync(f).size, 0) / 1024 / 1024).toFixed(1)} MB)`);
|
|
31309
31351
|
if (dryRun2) {
|
|
31310
31352
|
console.log(`
|
|
31311
31353
|
[DRY RUN] \u4F1A\u6253\u5305\u4EE5\u4E0B\u6587\u4EF6:`);
|
|
31312
|
-
wsFiles.slice(0, 20).forEach((f) => console.log(` ${
|
|
31354
|
+
wsFiles.slice(0, 20).forEach((f) => console.log(` ${path42.relative(workspace, f)}`));
|
|
31313
31355
|
if (wsFiles.length > 20) console.log(` ... \u8FD8\u6709 ${wsFiles.length - 20} \u4E2A\u6587\u4EF6`);
|
|
31314
31356
|
if (everosFiles.length > 0) {
|
|
31315
31357
|
console.log(`
|
|
31316
31358
|
[DRY RUN] everos (${everosFiles.length} \u6587\u4EF6):`);
|
|
31317
|
-
everosFiles.slice(0, 10).forEach((f) => console.log(` ${
|
|
31359
|
+
everosFiles.slice(0, 10).forEach((f) => console.log(` ${path42.relative(stateDir, f)}`));
|
|
31318
31360
|
if (everosFiles.length > 10) console.log(` ... \u8FD8\u6709 ${everosFiles.length - 10} \u4E2A\u6587\u4EF6`);
|
|
31319
31361
|
}
|
|
31320
31362
|
console.log(`
|
|
@@ -31322,46 +31364,46 @@ async function doExport(opts) {
|
|
|
31322
31364
|
return;
|
|
31323
31365
|
}
|
|
31324
31366
|
const version = formatLog().replace(/[-: ]/g, "").slice(0, 12).replace(/(d{8})(d{4})/, "$1-$2");
|
|
31325
|
-
const tmpDir =
|
|
31326
|
-
|
|
31327
|
-
const stagingDir =
|
|
31328
|
-
|
|
31367
|
+
const tmpDir = path42.join(os6.tmpdir(), `engine7-export-${agentName}-${version}`);
|
|
31368
|
+
fs42.mkdirSync(tmpDir, { recursive: true });
|
|
31369
|
+
const stagingDir = path42.join(tmpDir, agentName);
|
|
31370
|
+
fs42.mkdirSync(stagingDir, { recursive: true });
|
|
31329
31371
|
let fileCount = 0;
|
|
31330
31372
|
let totalSize = 0;
|
|
31331
31373
|
let copyFail = 0;
|
|
31332
31374
|
const copyOne = (srcFile, relRoot, destRoot) => {
|
|
31333
|
-
const relPath =
|
|
31334
|
-
const destFile =
|
|
31335
|
-
|
|
31375
|
+
const relPath = path42.relative(relRoot, srcFile);
|
|
31376
|
+
const destFile = path42.join(destRoot, relPath);
|
|
31377
|
+
fs42.mkdirSync(path42.dirname(destFile), { recursive: true });
|
|
31336
31378
|
try {
|
|
31337
31379
|
if (isTextFile(srcFile)) {
|
|
31338
|
-
const content =
|
|
31339
|
-
|
|
31380
|
+
const content = fs42.readFileSync(srcFile, "utf-8");
|
|
31381
|
+
fs42.writeFileSync(destFile, sanitizeContent(content, dirs));
|
|
31340
31382
|
} else {
|
|
31341
|
-
|
|
31383
|
+
fs42.copyFileSync(srcFile, destFile);
|
|
31342
31384
|
}
|
|
31343
31385
|
fileCount++;
|
|
31344
|
-
totalSize +=
|
|
31386
|
+
totalSize += fs42.statSync(srcFile).size;
|
|
31345
31387
|
} catch (e) {
|
|
31346
31388
|
copyFail++;
|
|
31347
31389
|
console.warn(` \u26A0\uFE0F \u62F7\u8D1D\u5931\u8D25: ${relPath} (${e.code || e.message})`);
|
|
31348
31390
|
}
|
|
31349
31391
|
};
|
|
31350
|
-
for (const srcFile of wsFiles) copyOne(srcFile, workspace,
|
|
31392
|
+
for (const srcFile of wsFiles) copyOne(srcFile, workspace, path42.join(stagingDir, "workspace"));
|
|
31351
31393
|
for (const srcFile of sessionFiles) {
|
|
31352
|
-
const relPath =
|
|
31353
|
-
const destFile =
|
|
31354
|
-
|
|
31394
|
+
const relPath = path42.relative(stateDir, srcFile);
|
|
31395
|
+
const destFile = path42.join(stagingDir, relPath);
|
|
31396
|
+
fs42.mkdirSync(path42.dirname(destFile), { recursive: true });
|
|
31355
31397
|
try {
|
|
31356
|
-
let content =
|
|
31398
|
+
let content = fs42.readFileSync(srcFile, "utf-8");
|
|
31357
31399
|
content = sanitizeContent(content, dirs);
|
|
31358
|
-
const baseName =
|
|
31400
|
+
const baseName = path42.basename(srcFile);
|
|
31359
31401
|
if (baseName === "session-index.json" || baseName === "platform-map.json") {
|
|
31360
31402
|
content = content.split("\\\\").join("/");
|
|
31361
31403
|
}
|
|
31362
|
-
|
|
31404
|
+
fs42.writeFileSync(destFile, content);
|
|
31363
31405
|
fileCount++;
|
|
31364
|
-
totalSize +=
|
|
31406
|
+
totalSize += fs42.statSync(srcFile).size;
|
|
31365
31407
|
} catch (e) {
|
|
31366
31408
|
copyFail++;
|
|
31367
31409
|
console.warn(` \u26A0\uFE0F \u62F7\u8D1D\u5931\u8D25: ${relPath} (${e.code || e.message})`);
|
|
@@ -31383,13 +31425,13 @@ async function doExport(opts) {
|
|
|
31383
31425
|
totalSize,
|
|
31384
31426
|
note
|
|
31385
31427
|
};
|
|
31386
|
-
|
|
31387
|
-
const archiveFile =
|
|
31428
|
+
fs42.writeFileSync(path42.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
31429
|
+
const archiveFile = path42.join(tmpDir, `${agentName}-${version}.tar.gz`);
|
|
31388
31430
|
console.log(`
|
|
31389
31431
|
\u{1F5DC}\uFE0F \u6253\u5305\u4E2D...`);
|
|
31390
31432
|
const tarExe = process.platform === "win32" ? "C:\\Windows\\System32\\tar.exe" : "tar";
|
|
31391
|
-
|
|
31392
|
-
const archiveSize =
|
|
31433
|
+
execSync3(`"${tarExe}" -czf "${archiveFile}" -C "${tmpDir}" ${agentName}`, { stdio: "pipe" });
|
|
31434
|
+
const archiveSize = fs42.statSync(archiveFile).size;
|
|
31393
31435
|
console.log(`\u2705 \u6253\u5305\u5B8C\u6210: ${archiveFile} (${(archiveSize / 1024 / 1024).toFixed(1)} MB, ${fileCount} \u6587\u4EF6${copyFail ? `, \u5931\u8D25 ${copyFail}` : ""})`);
|
|
31394
31436
|
const cfg = loadTravelConfig();
|
|
31395
31437
|
if (!cfg || !cfg.githubToken) {
|
|
@@ -31415,12 +31457,12 @@ function parseImportArgs(args) {
|
|
|
31415
31457
|
else if (args[i] === "--dry-run") dryRun2 = true;
|
|
31416
31458
|
}
|
|
31417
31459
|
if (!stateDir) throw new Error("import \u9700\u8981 --state-dir <path>");
|
|
31418
|
-
if (!agentName) agentName =
|
|
31460
|
+
if (!agentName) agentName = path42.basename(stateDir);
|
|
31419
31461
|
return { stateDir, agentName, version, archiveFile, dryRun: dryRun2 };
|
|
31420
31462
|
}
|
|
31421
31463
|
async function resolveArchiveForTest(opts) {
|
|
31422
31464
|
if (opts.archiveFile) {
|
|
31423
|
-
if (!
|
|
31465
|
+
if (!fs42.existsSync(opts.archiveFile)) {
|
|
31424
31466
|
throw new Error(`\u672C\u5730\u5305\u4E0D\u5B58\u5728: ${opts.archiveFile}`);
|
|
31425
31467
|
}
|
|
31426
31468
|
return opts.archiveFile;
|
|
@@ -31432,8 +31474,8 @@ async function doImport(opts) {
|
|
|
31432
31474
|
console.log(`\u{1F4E5} engine7 import`);
|
|
31433
31475
|
console.log(` agent: ${agentName}`);
|
|
31434
31476
|
console.log(` target: ${stateDir}`);
|
|
31435
|
-
const tmpDir =
|
|
31436
|
-
|
|
31477
|
+
const tmpDir = path42.join(os6.tmpdir(), `engine7-import-${agentName}-${Date.now()}`);
|
|
31478
|
+
fs42.mkdirSync(tmpDir, { recursive: true });
|
|
31437
31479
|
const resolved = await resolveArchiveForTest({
|
|
31438
31480
|
archiveFile: archiveFile || "",
|
|
31439
31481
|
tmpDir,
|
|
@@ -31457,100 +31499,100 @@ async function doImport(opts) {
|
|
|
31457
31499
|
}
|
|
31458
31500
|
console.log(`\u{1F4C2} \u89E3\u5305\u4E2D...`);
|
|
31459
31501
|
const tarExe = process.platform === "win32" ? "C:\\Windows\\System32\\tar.exe" : "tar";
|
|
31460
|
-
|
|
31461
|
-
const stagingDir =
|
|
31462
|
-
const manifestPath =
|
|
31463
|
-
if (!
|
|
31502
|
+
execSync3(`"${tarExe}" -xzf "${finalArchive}" -C "${tmpDir}"`, { stdio: "pipe" });
|
|
31503
|
+
const stagingDir = path42.join(tmpDir, agentName);
|
|
31504
|
+
const manifestPath = path42.join(stagingDir, "manifest.json");
|
|
31505
|
+
if (!fs42.existsSync(manifestPath)) {
|
|
31464
31506
|
console.error(`\u274C manifest.json \u4E0D\u5B58\u5728\uFF0C\u6587\u4EF6\u53EF\u80FD\u635F\u574F`);
|
|
31465
31507
|
process.exit(1);
|
|
31466
31508
|
}
|
|
31467
|
-
const manifest = JSON.parse(
|
|
31468
|
-
const workspace =
|
|
31469
|
-
const engineHome =
|
|
31509
|
+
const manifest = JSON.parse(fs42.readFileSync(manifestPath, "utf-8"));
|
|
31510
|
+
const workspace = path42.join(stateDir, "workspace").replace(/\\/g, "/").replace(/[/\\]+$/, "");
|
|
31511
|
+
const engineHome = path42.join(os6.homedir(), ".engine7").replace(/\\/g, "/").replace(/[/\\]+$/, "");
|
|
31470
31512
|
const dirs = { workspace, stateDir: stateDir.replace(/\\/g, "/").replace(/[/\\]+$/, ""), engineHome };
|
|
31471
31513
|
console.log(` \u7248\u672C: ${manifest.version}`);
|
|
31472
31514
|
console.log(` \u521B\u5EFA: ${manifest.createdAt}`);
|
|
31473
31515
|
console.log(` \u6587\u4EF6\u6570: ${manifest.fileCount}`);
|
|
31474
|
-
const wsStaging =
|
|
31516
|
+
const wsStaging = path42.join(stagingDir, "workspace");
|
|
31475
31517
|
let restoredCount = 0;
|
|
31476
31518
|
let skipCount = 0;
|
|
31477
|
-
if (
|
|
31519
|
+
if (fs42.existsSync(wsStaging)) {
|
|
31478
31520
|
const allFiles = collectAllFiles(wsStaging);
|
|
31479
31521
|
for (const srcFile of allFiles) {
|
|
31480
|
-
const relPath =
|
|
31481
|
-
const destFile =
|
|
31482
|
-
|
|
31522
|
+
const relPath = path42.relative(wsStaging, srcFile);
|
|
31523
|
+
const destFile = path42.join(workspace, relPath);
|
|
31524
|
+
fs42.mkdirSync(path42.dirname(destFile), { recursive: true });
|
|
31483
31525
|
try {
|
|
31484
31526
|
if (isTextFile(srcFile)) {
|
|
31485
|
-
const content =
|
|
31486
|
-
|
|
31527
|
+
const content = fs42.readFileSync(srcFile, "utf-8");
|
|
31528
|
+
fs42.writeFileSync(destFile, restoreContent(content, dirs));
|
|
31487
31529
|
} else {
|
|
31488
|
-
|
|
31530
|
+
fs42.copyFileSync(srcFile, destFile);
|
|
31489
31531
|
}
|
|
31490
31532
|
restoredCount++;
|
|
31491
31533
|
} catch (e) {
|
|
31492
31534
|
skipCount++;
|
|
31493
|
-
console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${
|
|
31535
|
+
console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${path42.relative(wsStaging, srcFile)} (${e.code || e.message})`);
|
|
31494
31536
|
}
|
|
31495
31537
|
}
|
|
31496
31538
|
}
|
|
31497
|
-
const agentsStaging =
|
|
31498
|
-
if (
|
|
31539
|
+
const agentsStaging = path42.join(stagingDir, "agents");
|
|
31540
|
+
if (fs42.existsSync(agentsStaging)) {
|
|
31499
31541
|
const sessionFiles = collectAllFiles(agentsStaging);
|
|
31500
31542
|
for (const srcFile of sessionFiles) {
|
|
31501
|
-
const relPath =
|
|
31502
|
-
const destFile =
|
|
31503
|
-
|
|
31504
|
-
const content =
|
|
31505
|
-
|
|
31543
|
+
const relPath = path42.relative(stagingDir, srcFile);
|
|
31544
|
+
const destFile = path42.join(stateDir, relPath);
|
|
31545
|
+
fs42.mkdirSync(path42.dirname(destFile), { recursive: true });
|
|
31546
|
+
const content = fs42.readFileSync(srcFile, "utf-8");
|
|
31547
|
+
fs42.writeFileSync(destFile, restoreContent(content, dirs));
|
|
31506
31548
|
restoredCount++;
|
|
31507
31549
|
}
|
|
31508
31550
|
}
|
|
31509
|
-
const configsStaging =
|
|
31510
|
-
if (
|
|
31551
|
+
const configsStaging = path42.join(stagingDir, "configs");
|
|
31552
|
+
if (fs42.existsSync(configsStaging)) {
|
|
31511
31553
|
const cfgFiles = collectAllFiles(configsStaging);
|
|
31512
31554
|
for (const srcFile of cfgFiles) {
|
|
31513
|
-
const relPath =
|
|
31514
|
-
const destFile =
|
|
31515
|
-
|
|
31555
|
+
const relPath = path42.relative(stagingDir, srcFile);
|
|
31556
|
+
const destFile = path42.join(stateDir, relPath);
|
|
31557
|
+
fs42.mkdirSync(path42.dirname(destFile), { recursive: true });
|
|
31516
31558
|
if (isTextFile(srcFile)) {
|
|
31517
|
-
const content =
|
|
31518
|
-
|
|
31559
|
+
const content = fs42.readFileSync(srcFile, "utf-8");
|
|
31560
|
+
fs42.writeFileSync(destFile, restoreContent(content, dirs));
|
|
31519
31561
|
} else {
|
|
31520
|
-
|
|
31562
|
+
fs42.copyFileSync(srcFile, destFile);
|
|
31521
31563
|
}
|
|
31522
31564
|
restoredCount++;
|
|
31523
31565
|
}
|
|
31524
31566
|
}
|
|
31525
|
-
const everosStaging =
|
|
31526
|
-
if (
|
|
31567
|
+
const everosStaging = path42.join(stagingDir, ".everos");
|
|
31568
|
+
if (fs42.existsSync(everosStaging)) {
|
|
31527
31569
|
const everosFiles = collectAllFiles(everosStaging);
|
|
31528
31570
|
for (const srcFile of everosFiles) {
|
|
31529
|
-
const relPath =
|
|
31530
|
-
const destFile =
|
|
31531
|
-
|
|
31571
|
+
const relPath = path42.relative(stagingDir, srcFile);
|
|
31572
|
+
const destFile = path42.join(stateDir, relPath);
|
|
31573
|
+
fs42.mkdirSync(path42.dirname(destFile), { recursive: true });
|
|
31532
31574
|
try {
|
|
31533
31575
|
if (isTextFile(srcFile)) {
|
|
31534
|
-
const content =
|
|
31535
|
-
|
|
31576
|
+
const content = fs42.readFileSync(srcFile, "utf-8");
|
|
31577
|
+
fs42.writeFileSync(destFile, restoreContent(content, dirs));
|
|
31536
31578
|
} else {
|
|
31537
|
-
|
|
31579
|
+
fs42.copyFileSync(srcFile, destFile);
|
|
31538
31580
|
}
|
|
31539
31581
|
restoredCount++;
|
|
31540
31582
|
} catch (e) {
|
|
31541
31583
|
skipCount++;
|
|
31542
|
-
console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${
|
|
31584
|
+
console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${path42.relative(everosStaging, srcFile)} (${e.code || e.message})`);
|
|
31543
31585
|
}
|
|
31544
31586
|
}
|
|
31545
31587
|
console.log(` everos: ${everosFiles.length} \u6587\u4EF6\u5DF2\u6062\u590D`);
|
|
31546
31588
|
}
|
|
31547
31589
|
console.log(`\u2705 \u6062\u590D\u5B8C\u6210: ${restoredCount} \u6587\u4EF6 \u2192 ${stateDir}${skipCount ? ` (\u8DF3\u8FC7 ${skipCount})` : ""}`);
|
|
31548
31590
|
const platformConfigName = process.platform === "darwin" ? "xiaoke-mac.json" : "xiaoke-win.json";
|
|
31549
|
-
const restoredConfigPath =
|
|
31550
|
-
const configToUse =
|
|
31591
|
+
const restoredConfigPath = path42.join(stateDir, "configs", platformConfigName);
|
|
31592
|
+
const configToUse = fs42.existsSync(restoredConfigPath) ? restoredConfigPath : path42.join(stateDir, "configs", "xiaoke.json");
|
|
31551
31593
|
console.log(`
|
|
31552
31594
|
\u{1F4A1} \u4E0B\u4E00\u6B65: engine7 start --config "${configToUse}"`);
|
|
31553
|
-
|
|
31595
|
+
fs42.rmSync(tmpDir, { recursive: true, force: true });
|
|
31554
31596
|
}
|
|
31555
31597
|
async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
|
|
31556
31598
|
const repo = `${cfg.githubOwner}/${cfg.repoName}`;
|
|
@@ -31580,8 +31622,8 @@ async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
|
|
|
31580
31622
|
}
|
|
31581
31623
|
const release2 = await createRes.json();
|
|
31582
31624
|
const uploadUrl = release2.upload_url.replace("{?name,label}", "");
|
|
31583
|
-
const fileBuffer =
|
|
31584
|
-
const fileName =
|
|
31625
|
+
const fileBuffer = fs42.readFileSync(archiveFile);
|
|
31626
|
+
const fileName = path42.basename(archiveFile);
|
|
31585
31627
|
const uploadRes = await fetch(`${uploadUrl}?name=${fileName}`, {
|
|
31586
31628
|
method: "POST",
|
|
31587
31629
|
headers: {
|
|
@@ -31604,7 +31646,7 @@ async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
|
|
|
31604
31646
|
throw e;
|
|
31605
31647
|
}
|
|
31606
31648
|
try {
|
|
31607
|
-
|
|
31649
|
+
fs42.rmSync(path42.dirname(archiveFile), { recursive: true, force: true });
|
|
31608
31650
|
} catch {
|
|
31609
31651
|
}
|
|
31610
31652
|
}
|
|
@@ -31636,8 +31678,8 @@ async function downloadFromGitHub(cfg, agentName, version, destDir) {
|
|
|
31636
31678
|
throw new Error(`\u4E0B\u8F7D asset \u5931\u8D25: ${downloadRes.status}`);
|
|
31637
31679
|
}
|
|
31638
31680
|
const buffer = Buffer.from(await downloadRes.arrayBuffer());
|
|
31639
|
-
const archiveFile =
|
|
31640
|
-
|
|
31681
|
+
const archiveFile = path42.join(destDir, asset.name);
|
|
31682
|
+
fs42.writeFileSync(archiveFile, buffer);
|
|
31641
31683
|
return archiveFile;
|
|
31642
31684
|
}
|
|
31643
31685
|
async function getLatestReleaseTag(cfg, agentName) {
|
|
@@ -31663,7 +31705,7 @@ var init_cli_travel = __esm({
|
|
|
31663
31705
|
"src/cli-travel.ts"() {
|
|
31664
31706
|
"use strict";
|
|
31665
31707
|
init_clock();
|
|
31666
|
-
CONFIG_PATH =
|
|
31708
|
+
CONFIG_PATH = path42.join(os6.homedir(), ".engine7-travel.json");
|
|
31667
31709
|
PATH_PLACEHOLDERS = [
|
|
31668
31710
|
{ placeholder: "{{WORKSPACE}}", getOriginal: (d) => d.workspace },
|
|
31669
31711
|
{ placeholder: "{{ENGINE_HOME}}", getOriginal: (d) => d.engineHome },
|
|
@@ -31736,8 +31778,8 @@ var init_cli_travel = __esm({
|
|
|
31736
31778
|
});
|
|
31737
31779
|
|
|
31738
31780
|
// src/cli-init.ts
|
|
31739
|
-
import * as
|
|
31740
|
-
import * as
|
|
31781
|
+
import * as path43 from "node:path";
|
|
31782
|
+
import * as fs43 from "node:fs";
|
|
31741
31783
|
|
|
31742
31784
|
// src/cli-service.ts
|
|
31743
31785
|
function parseServiceArgs(args) {
|
|
@@ -31892,6 +31934,136 @@ function buildConfigValuesFromAnswers(stateDir, a, existing = {}) {
|
|
|
31892
31934
|
|
|
31893
31935
|
// src/cli-init.ts
|
|
31894
31936
|
init_secrets_env();
|
|
31937
|
+
|
|
31938
|
+
// src/pid-lock.ts
|
|
31939
|
+
import fs3 from "node:fs";
|
|
31940
|
+
import path3 from "node:path";
|
|
31941
|
+
import { execSync } from "node:child_process";
|
|
31942
|
+
function enginePidFile(stateDir) {
|
|
31943
|
+
return path3.join(stateDir, ".engine.pid");
|
|
31944
|
+
}
|
|
31945
|
+
function isEngineImage(text) {
|
|
31946
|
+
return /node|engine7|electron/i.test(text);
|
|
31947
|
+
}
|
|
31948
|
+
function isPidAlive(pid) {
|
|
31949
|
+
try {
|
|
31950
|
+
process.kill(pid, 0);
|
|
31951
|
+
return true;
|
|
31952
|
+
} catch {
|
|
31953
|
+
return false;
|
|
31954
|
+
}
|
|
31955
|
+
}
|
|
31956
|
+
function probeImage(pid) {
|
|
31957
|
+
try {
|
|
31958
|
+
if (process.platform === "win32") {
|
|
31959
|
+
return execSync(`tasklist /FI "PID eq ${pid}" /NH /FO CSV`, {
|
|
31960
|
+
encoding: "utf-8",
|
|
31961
|
+
timeout: 3e3,
|
|
31962
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
31963
|
+
});
|
|
31964
|
+
}
|
|
31965
|
+
if (process.platform === "darwin") {
|
|
31966
|
+
return execSync(`ps -p ${pid} -o comm=`, {
|
|
31967
|
+
encoding: "utf-8",
|
|
31968
|
+
timeout: 3e3,
|
|
31969
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
31970
|
+
});
|
|
31971
|
+
}
|
|
31972
|
+
return fs3.readFileSync(`/proc/${pid}/comm`, "utf-8");
|
|
31973
|
+
} catch {
|
|
31974
|
+
return null;
|
|
31975
|
+
}
|
|
31976
|
+
}
|
|
31977
|
+
function probeEngineImage(pid) {
|
|
31978
|
+
return isEngineImage(probeImage(pid) ?? "");
|
|
31979
|
+
}
|
|
31980
|
+
function isCliWrapperImage(text) {
|
|
31981
|
+
return /node/i.test(text);
|
|
31982
|
+
}
|
|
31983
|
+
function probeIsCliWrapper(pid) {
|
|
31984
|
+
return isCliWrapperImage(probeImage(pid) ?? "");
|
|
31985
|
+
}
|
|
31986
|
+
function readOwnEnginePidText(stateDir) {
|
|
31987
|
+
try {
|
|
31988
|
+
return fs3.readFileSync(enginePidFile(stateDir), "utf-8");
|
|
31989
|
+
} catch (err) {
|
|
31990
|
+
if (err?.code !== "ENOENT") console.warn(`[pid-lock] read lock failed: ${err.message}`);
|
|
31991
|
+
return null;
|
|
31992
|
+
}
|
|
31993
|
+
}
|
|
31994
|
+
function pickOwnEnginePid(probe) {
|
|
31995
|
+
const pid = parseInt((probe.pidFileContent ?? "").trim(), 10);
|
|
31996
|
+
if (!Number.isInteger(pid) || pid <= 0) return null;
|
|
31997
|
+
if (pid === probe.myPid) return null;
|
|
31998
|
+
if (!probe.isAlive(pid)) return null;
|
|
31999
|
+
if (!probe.isEngineImage(pid)) return null;
|
|
32000
|
+
return pid;
|
|
32001
|
+
}
|
|
32002
|
+
function ownEnginePid(stateDir, myPid = process.pid) {
|
|
32003
|
+
return pickOwnEnginePid({
|
|
32004
|
+
pidFileContent: readOwnEnginePidText(stateDir),
|
|
32005
|
+
myPid,
|
|
32006
|
+
isAlive: isPidAlive,
|
|
32007
|
+
isEngineImage: probeEngineImage
|
|
32008
|
+
});
|
|
32009
|
+
}
|
|
32010
|
+
function killOwnEngineForStateDir(stateDir) {
|
|
32011
|
+
const pid = ownEnginePid(stateDir);
|
|
32012
|
+
if (pid === null) return null;
|
|
32013
|
+
killTree(pid);
|
|
32014
|
+
return pid;
|
|
32015
|
+
}
|
|
32016
|
+
async function waitForPidGone(pid, timeoutMs = 5e3) {
|
|
32017
|
+
const t0 = Date.now();
|
|
32018
|
+
while (Date.now() - t0 < timeoutMs) {
|
|
32019
|
+
if (!isPidAlive(pid)) return true;
|
|
32020
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
32021
|
+
}
|
|
32022
|
+
return !isPidAlive(pid);
|
|
32023
|
+
}
|
|
32024
|
+
function pickParentPid(procStatus, psOutput) {
|
|
32025
|
+
const fromProc = Number(/PPid:\s*(\d+)/.exec(procStatus ?? "")?.[1] ?? NaN);
|
|
32026
|
+
if (Number.isInteger(fromProc) && fromProc > 0) return fromProc;
|
|
32027
|
+
const fromPs = Number((psOutput ?? "").trim());
|
|
32028
|
+
return Number.isInteger(fromPs) && fromPs > 0 ? fromPs : 0;
|
|
32029
|
+
}
|
|
32030
|
+
function killTree(pid) {
|
|
32031
|
+
try {
|
|
32032
|
+
if (process.platform === "win32") {
|
|
32033
|
+
execSync(`taskkill /PID ${pid} /T /F`, { stdio: "ignore", timeout: 8e3 });
|
|
32034
|
+
try {
|
|
32035
|
+
const parentPid = parseInt(execSync(`wmic process where ProcessId=${pid} get ParentProcessId /value`, { encoding: "utf-8", timeout: 3e3, stdio: ["ignore", "pipe", "ignore"] }).match(/ParentProcessId=(\d+)/)?.[1] ?? "0", 10);
|
|
32036
|
+
if (parentPid && parentPid !== process.ppid && probeIsCliWrapper(parentPid)) {
|
|
32037
|
+
execSync(`taskkill /PID ${parentPid} /F`, { stdio: "ignore", timeout: 3e3 });
|
|
32038
|
+
}
|
|
32039
|
+
} catch {
|
|
32040
|
+
}
|
|
32041
|
+
} else {
|
|
32042
|
+
process.kill(pid, "SIGKILL");
|
|
32043
|
+
let parentPid = 0;
|
|
32044
|
+
try {
|
|
32045
|
+
parentPid = pickParentPid(fs3.readFileSync(`/proc/${pid}/status`, "utf-8"), null);
|
|
32046
|
+
} catch {
|
|
32047
|
+
}
|
|
32048
|
+
if (!parentPid) {
|
|
32049
|
+
try {
|
|
32050
|
+
parentPid = pickParentPid(null, execSync(`ps -p ${pid} -o ppid=`, { encoding: "utf-8", timeout: 3e3, stdio: ["ignore", "pipe", "ignore"] }));
|
|
32051
|
+
} catch {
|
|
32052
|
+
}
|
|
32053
|
+
}
|
|
32054
|
+
if (parentPid > 1 && parentPid !== process.ppid && probeIsCliWrapper(parentPid)) {
|
|
32055
|
+
try {
|
|
32056
|
+
process.kill(parentPid, "SIGKILL");
|
|
32057
|
+
} catch {
|
|
32058
|
+
}
|
|
32059
|
+
}
|
|
32060
|
+
}
|
|
32061
|
+
} catch (err) {
|
|
32062
|
+
console.warn(`[pid-lock] kill ${pid} failed: ${err.message}`);
|
|
32063
|
+
}
|
|
32064
|
+
}
|
|
32065
|
+
|
|
32066
|
+
// src/cli-init.ts
|
|
31895
32067
|
init_clock();
|
|
31896
32068
|
init_cli_init_config();
|
|
31897
32069
|
init_registry();
|
|
@@ -31910,7 +32082,7 @@ function describeCurrentToken(v) {
|
|
|
31910
32082
|
return /^(?:env:|{{\s*)[A-Z0-9_]+/.test(v) ? "\u5DF2\u5B58\u5728 secrets \u4E2D" : v.slice(0, 12) + "...";
|
|
31911
32083
|
}
|
|
31912
32084
|
var __filename2 = fileURLToPath7(import.meta.url);
|
|
31913
|
-
var __dirname =
|
|
32085
|
+
var __dirname = path43.dirname(__filename2);
|
|
31914
32086
|
function parseArgs2() {
|
|
31915
32087
|
const args = process.argv.slice(2);
|
|
31916
32088
|
let stateDir = "";
|
|
@@ -31937,10 +32109,10 @@ function parseArgs2() {
|
|
|
31937
32109
|
}
|
|
31938
32110
|
}
|
|
31939
32111
|
if (!stateDir) {
|
|
31940
|
-
stateDir =
|
|
32112
|
+
stateDir = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
|
|
31941
32113
|
console.log(` \u4F7F\u7528\u9ED8\u8BA4\u76EE\u5F55: ${stateDir}`);
|
|
31942
32114
|
}
|
|
31943
|
-
stateDir =
|
|
32115
|
+
stateDir = path43.resolve(stateDir);
|
|
31944
32116
|
return { stateDir, quick, dryRun: dryRun2, force, answersPath };
|
|
31945
32117
|
}
|
|
31946
32118
|
function printHelp() {
|
|
@@ -32061,16 +32233,16 @@ function getDefaultValues(stateDir) {
|
|
|
32061
32233
|
};
|
|
32062
32234
|
}
|
|
32063
32235
|
function loadExistingValues(stateDir) {
|
|
32064
|
-
const configPath =
|
|
32236
|
+
const configPath = path43.join(stateDir, "configs", "main7.json");
|
|
32065
32237
|
try {
|
|
32066
|
-
if (!
|
|
32067
|
-
const j = JSON.parse(
|
|
32238
|
+
if (!fs43.existsSync(configPath)) return {};
|
|
32239
|
+
const j = JSON.parse(fs43.readFileSync(configPath, "utf8"));
|
|
32068
32240
|
const out = {};
|
|
32069
32241
|
if (typeof j.timezone === "string" && j.timezone) out.timezone = j.timezone;
|
|
32070
32242
|
if (j.agents?.defaults?.name) out.agentName = j.agents.defaults.name;
|
|
32071
32243
|
if (j.agents?.defaults?.persona) out.persona = j.agents.defaults.persona;
|
|
32072
32244
|
try {
|
|
32073
|
-
const wm =
|
|
32245
|
+
const wm = fs43.readFileSync(path43.join(stateDir, "workspace", ".work-mode"), "utf8").trim();
|
|
32074
32246
|
if (wm === "on") out.chatMode = "work";
|
|
32075
32247
|
else if (wm === "off") out.chatMode = "emotion";
|
|
32076
32248
|
} catch {
|
|
@@ -32127,8 +32299,8 @@ function readSecretsValue(stateDir, envName) {
|
|
|
32127
32299
|
try {
|
|
32128
32300
|
const cfgBase = "main7";
|
|
32129
32301
|
for (const p of secretsCandidates(stateDir, cfgBase)) {
|
|
32130
|
-
if (
|
|
32131
|
-
for (const line of
|
|
32302
|
+
if (fs43.existsSync(p)) {
|
|
32303
|
+
for (const line of fs43.readFileSync(p, "utf8").split("\n")) {
|
|
32132
32304
|
const eq = line.indexOf("=");
|
|
32133
32305
|
if (eq > 0 && line.slice(0, eq).trim() === envName) {
|
|
32134
32306
|
return line.slice(eq + 1).trim();
|
|
@@ -32362,29 +32534,29 @@ async function configureWechat(rl, v) {
|
|
|
32362
32534
|
}
|
|
32363
32535
|
function buildDirTree(v) {
|
|
32364
32536
|
const d = v.stateDir;
|
|
32365
|
-
const w =
|
|
32537
|
+
const w = path43.join(d, "workspace");
|
|
32366
32538
|
return [
|
|
32367
32539
|
// 目录
|
|
32368
|
-
{ path:
|
|
32369
|
-
{ path:
|
|
32370
|
-
{ path:
|
|
32371
|
-
{ path:
|
|
32372
|
-
{ path:
|
|
32373
|
-
{ path:
|
|
32374
|
-
{ path:
|
|
32375
|
-
{ path:
|
|
32376
|
-
{ path:
|
|
32377
|
-
{ path:
|
|
32378
|
-
{ path:
|
|
32540
|
+
{ path: path43.join(d, "configs"), type: "dir" },
|
|
32541
|
+
{ path: path43.join(d, "state", "agents", "main", "sessions"), type: "dir" },
|
|
32542
|
+
{ path: path43.join(w, "prompts"), type: "dir" },
|
|
32543
|
+
{ path: path43.join(w, "memory", "daily"), type: "dir" },
|
|
32544
|
+
{ path: path43.join(w, "docs", "research"), type: "dir" },
|
|
32545
|
+
{ path: path43.join(w, "docs", "todo"), type: "dir" },
|
|
32546
|
+
{ path: path43.join(w, "docs", "decisions"), type: "dir" },
|
|
32547
|
+
{ path: path43.join(w, "docs", "knowledge"), type: "dir" },
|
|
32548
|
+
{ path: path43.join(w, "docs", "sop"), type: "dir" },
|
|
32549
|
+
{ path: path43.join(d, "logs"), type: "dir" },
|
|
32550
|
+
{ path: path43.join(d, "media", "inbound"), type: "dir" },
|
|
32379
32551
|
// workspace 文件
|
|
32380
32552
|
{
|
|
32381
|
-
path:
|
|
32553
|
+
path: path43.join(w, "SESSION-STATE.md"),
|
|
32382
32554
|
type: "file",
|
|
32383
32555
|
content: readTemplate("workspace/SESSION-STATE.md")
|
|
32384
32556
|
},
|
|
32385
|
-
{ path:
|
|
32557
|
+
{ path: path43.join(w, "HEARTBEAT.md"), type: "file", content: readTemplate("workspace/HEARTBEAT.md") },
|
|
32386
32558
|
{
|
|
32387
|
-
path:
|
|
32559
|
+
path: path43.join(w, "SOUL.md"),
|
|
32388
32560
|
type: "file",
|
|
32389
32561
|
// 0917:SOUL 按人设取模板(templates/workspace/souls/<persona>.md),
|
|
32390
32562
|
// 单一人设模板缺失时回退通用骨架(workspace/SOUL.md)
|
|
@@ -32396,12 +32568,12 @@ function buildDirTree(v) {
|
|
|
32396
32568
|
}
|
|
32397
32569
|
})()
|
|
32398
32570
|
},
|
|
32399
|
-
{ path:
|
|
32571
|
+
{ path: path43.join(w, "AGENTS.md"), type: "file", content: readTemplate("workspace/AGENTS.md") },
|
|
32400
32572
|
{
|
|
32401
32573
|
// 0920 翀哥拍板:EMOTION.md 模板按人设装(templates/workspace/emotion/<persona>.md)
|
|
32402
32574
|
// 冷启动默认带"想 TA 了就直接发(msg_send)"那段(写在每份模板 §一)
|
|
32403
32575
|
// 单一人设模板缺失时回退通用骨架(emotion/_default.md)
|
|
32404
|
-
path:
|
|
32576
|
+
path: path43.join(w, "EMOTION.md"),
|
|
32405
32577
|
type: "file",
|
|
32406
32578
|
content: (() => {
|
|
32407
32579
|
try {
|
|
@@ -32412,39 +32584,39 @@ function buildDirTree(v) {
|
|
|
32412
32584
|
})()
|
|
32413
32585
|
},
|
|
32414
32586
|
{
|
|
32415
|
-
path:
|
|
32587
|
+
path: path43.join(w, "prompts", "contacts.md"),
|
|
32416
32588
|
type: "file",
|
|
32417
32589
|
content: readTemplate("workspace/prompts/contacts.md").replace("{{DISCORD_USER_ID}}", v.discordUserId || "YOUR_DISCORD_ID").replace("{{FEISHU_OPEN_ID}}", v.feishuOpenId || "YOUR_FEISHU_OPEN_ID")
|
|
32418
32590
|
},
|
|
32419
|
-
{ path:
|
|
32591
|
+
{ path: path43.join(w, "prompts", "auto-memory-instructions.md"), type: "file", content: readTemplate("workspace/prompts/auto-memory-instructions.md") },
|
|
32420
32592
|
{
|
|
32421
32593
|
// 0925:proactive 到期处理规则。此前仓内**零模板**——那份规则只在私有部署的
|
|
32422
32594
|
// stateDir 里手工存在,装机用户吃的是引擎内置兜底文案(那份也没点名工具)。
|
|
32423
32595
|
// 结果:agent 用正文写判定、不调工具,判定全部不落库。
|
|
32424
32596
|
// 注意 readTemplate 找不到模板会 **throw**,所以本文件与 templates/ 下那份必须成对存在。
|
|
32425
|
-
path:
|
|
32597
|
+
path: path43.join(w, "prompts", "proactive.md"),
|
|
32426
32598
|
type: "file",
|
|
32427
32599
|
content: readTemplate("workspace/prompts/proactive.md")
|
|
32428
32600
|
},
|
|
32429
32601
|
{
|
|
32430
32602
|
// 0917:inner-voice 定制 prompt 按人设装(templates/workspace/inner-voice/<persona>.md)
|
|
32431
|
-
path:
|
|
32603
|
+
path: path43.join(w, "prompts", "my-inner-voice.md"),
|
|
32432
32604
|
type: "file",
|
|
32433
32605
|
content: readTemplate(`workspace/inner-voice/${v.persona}.md`).replace(/\{\{AGENT_NAME\}\}/g, v.agentName)
|
|
32434
32606
|
},
|
|
32435
|
-
{ path:
|
|
32436
|
-
{ path:
|
|
32607
|
+
{ path: path43.join(w, "MEMORY.md"), type: "file", content: "# MEMORY.md \u2014 \u8BB0\u5FC6\u6587\u4EF6\u7D22\u5F15\n\n> \u6700\u540E\u66F4\u65B0\uFF1A\u521D\u59CB\u5316\n" },
|
|
32608
|
+
{ path: path43.join(w, "USER.md"), type: "file", content: "# USER.md \u2014 \u7528\u6237\u4FE1\u606F\n\n\uFF08\u5728\u8FD9\u91CC\u8BB0\u5F55\u7528\u6237\u7684\u504F\u597D\u3001\u80CC\u666F\u7B49\uFF09\n" },
|
|
32437
32609
|
// 情绪状态机(0917):脚本 + hook 接线 + 人设情绪表(用户在 init 选的 persona)
|
|
32438
32610
|
//
|
|
32439
32611
|
// 0920 起装的是 **.mjs 版**(原来是 .py,见下面 hook 命令那段)。老装机的 workspace
|
|
32440
32612
|
// 里那份 .py 不动它——没被引用就不会跑,删了反而无据可查。
|
|
32441
32613
|
{
|
|
32442
|
-
path:
|
|
32614
|
+
path: path43.join(w, "scripts", "emotion_state_machine.mjs"),
|
|
32443
32615
|
type: "file",
|
|
32444
32616
|
content: readTemplate("workspace/scripts/emotion_state_machine.mjs")
|
|
32445
32617
|
},
|
|
32446
32618
|
{
|
|
32447
|
-
path:
|
|
32619
|
+
path: path43.join(w, ".hooks.json"),
|
|
32448
32620
|
type: "file",
|
|
32449
32621
|
content: JSON.stringify({
|
|
32450
32622
|
hooks: {
|
|
@@ -32459,26 +32631,26 @@ function buildDirTree(v) {
|
|
|
32459
32631
|
// (hook 的 env 是 {...process.env} 继承的),所以它就是个 node。
|
|
32460
32632
|
// 与 `service install --node-exe` 同一个路子。
|
|
32461
32633
|
// 路径两侧都加引号:stateDir 可能带空格(C:\Users\Foo Bar\...)。
|
|
32462
|
-
{ hooks: [{ type: "command", command: '"${E7_NODE}" "' +
|
|
32634
|
+
{ hooks: [{ type: "command", command: '"${E7_NODE}" "' + path43.join(w, "scripts", "emotion_state_machine.mjs") + '"' }] }
|
|
32463
32635
|
]
|
|
32464
32636
|
}
|
|
32465
32637
|
}, null, 2) + "\n"
|
|
32466
32638
|
},
|
|
32467
32639
|
{
|
|
32468
|
-
path:
|
|
32640
|
+
path: path43.join(w, ".emotion_states.json"),
|
|
32469
32641
|
type: "file",
|
|
32470
32642
|
content: readTemplate(`workspace/emotion-states/${v.persona}.json`)
|
|
32471
32643
|
},
|
|
32472
32644
|
// 模式档位(0920):与 /work 命令写的是同一个文件,读端只认 on/off,
|
|
32473
32645
|
// 没有这个键就是 auto。auto 刻意不写——写个 "auto" 进去反而多一种除了这里没人认得的状态。
|
|
32474
32646
|
...v.chatMode === "work" || v.chatMode === "emotion" ? [{
|
|
32475
|
-
path:
|
|
32647
|
+
path: path43.join(w, ".work-mode"),
|
|
32476
32648
|
type: "file",
|
|
32477
32649
|
content: v.chatMode === "work" ? "on" : "off"
|
|
32478
32650
|
}] : [],
|
|
32479
32651
|
// package.json — 让 agent 目录成为独立 npm 项目根,防止 npm hoisting
|
|
32480
32652
|
{
|
|
32481
|
-
path:
|
|
32653
|
+
path: path43.join(d, "package.json"),
|
|
32482
32654
|
type: "file",
|
|
32483
32655
|
content: JSON.stringify({
|
|
32484
32656
|
name: v.agentName.toLowerCase().replace(/[^a-z0-9-]/g, "-") || "agent",
|
|
@@ -32489,7 +32661,7 @@ function buildDirTree(v) {
|
|
|
32489
32661
|
},
|
|
32490
32662
|
// 启动脚本(根据 OS 生成)
|
|
32491
32663
|
...process.platform === "win32" ? [{
|
|
32492
|
-
path:
|
|
32664
|
+
path: path43.join(d, "start.cmd"),
|
|
32493
32665
|
type: "file",
|
|
32494
32666
|
content: `@echo off
|
|
32495
32667
|
rem Engine 7 startup script
|
|
@@ -32521,7 +32693,7 @@ if %ERRORLEVEL% NEQ 0 (
|
|
|
32521
32693
|
)
|
|
32522
32694
|
`
|
|
32523
32695
|
}] : [{
|
|
32524
|
-
path:
|
|
32696
|
+
path: path43.join(d, "start.sh"),
|
|
32525
32697
|
type: "file",
|
|
32526
32698
|
content: `#!/bin/bash
|
|
32527
32699
|
# Engine 7 startup script
|
|
@@ -32555,24 +32727,24 @@ node "$ENGINE7_BIN" --engine-config "$CFG_ABS"
|
|
|
32555
32727
|
}
|
|
32556
32728
|
function readTemplate(relativePath) {
|
|
32557
32729
|
const candidates = [
|
|
32558
|
-
|
|
32559
|
-
|
|
32560
|
-
|
|
32730
|
+
path43.join(__dirname, "..", "templates", relativePath),
|
|
32731
|
+
path43.join(__dirname, "..", "..", "templates", relativePath),
|
|
32732
|
+
path43.join(process.cwd(), "templates", relativePath)
|
|
32561
32733
|
];
|
|
32562
32734
|
for (const p of candidates) {
|
|
32563
|
-
if (
|
|
32564
|
-
return
|
|
32735
|
+
if (fs43.existsSync(p)) {
|
|
32736
|
+
return fs43.readFileSync(p, "utf-8");
|
|
32565
32737
|
}
|
|
32566
32738
|
}
|
|
32567
32739
|
throw new Error(`\u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${relativePath}\uFF08\u627E\u4E86: ${candidates.join(", ")}\uFF09`);
|
|
32568
32740
|
}
|
|
32569
32741
|
function looksLikeAppInstall(dir) {
|
|
32570
|
-
return ["", "install"].some((sub) =>
|
|
32742
|
+
return ["", "install"].some((sub) => fs43.existsSync(path43.join(dir, sub, "Engine7.exe")) && fs43.existsSync(path43.join(dir, sub, "resources", "engine7", "dist", "cli.mjs")));
|
|
32571
32743
|
}
|
|
32572
32744
|
var PHOTO_EXTS = [".png", ".jpg", ".jpeg", ".webp"];
|
|
32573
32745
|
function hasOnlyEngineBookkeeping(dir) {
|
|
32574
32746
|
try {
|
|
32575
|
-
const entries2 =
|
|
32747
|
+
const entries2 = fs43.readdirSync(dir);
|
|
32576
32748
|
return entries2.length > 0 && entries2.every((e) => e === "install-identity.json");
|
|
32577
32749
|
} catch {
|
|
32578
32750
|
return false;
|
|
@@ -32588,11 +32760,11 @@ function dryRun(entries2) {
|
|
|
32588
32760
|
function execute(entries2) {
|
|
32589
32761
|
for (const e of entries2) {
|
|
32590
32762
|
if (e.type === "dir") {
|
|
32591
|
-
|
|
32763
|
+
fs43.mkdirSync(e.path, { recursive: true });
|
|
32592
32764
|
console.log(` \u{1F4C1} ${e.path}`);
|
|
32593
32765
|
} else {
|
|
32594
|
-
|
|
32595
|
-
|
|
32766
|
+
fs43.mkdirSync(path43.dirname(e.path), { recursive: true });
|
|
32767
|
+
fs43.writeFileSync(e.path, e.content || "", "utf-8");
|
|
32596
32768
|
console.log(` \u{1F4C4} ${e.path}`);
|
|
32597
32769
|
}
|
|
32598
32770
|
}
|
|
@@ -32626,8 +32798,8 @@ async function main() {
|
|
|
32626
32798
|
if (subcommand === "--version" || subcommand === "-v") {
|
|
32627
32799
|
let ver = "unknown";
|
|
32628
32800
|
try {
|
|
32629
|
-
const pkgPath =
|
|
32630
|
-
ver = JSON.parse(
|
|
32801
|
+
const pkgPath = path43.join(path43.dirname(__filename2), "..", "package.json");
|
|
32802
|
+
ver = JSON.parse(fs43.readFileSync(pkgPath, "utf8")).version || "unknown";
|
|
32631
32803
|
} catch {
|
|
32632
32804
|
}
|
|
32633
32805
|
console.log(`engine7 ${ver}`);
|
|
@@ -32656,14 +32828,14 @@ async function main() {
|
|
|
32656
32828
|
relay = resolveRelayUrl(relay, process.env);
|
|
32657
32829
|
if (!relayFromArg) console.error(` \u4E2D\u8F6C\u7AD9: ${relay}\uFF08\u8981\u6362\u5730\u5740\u7528 --relay <\u5730\u5740>\uFF09`);
|
|
32658
32830
|
const { resolveStateDirFromArgs: resolveStateDirFromArgs2 } = await Promise.resolve().then(() => (init_cli_doctor(), cli_doctor_exports));
|
|
32659
|
-
stateDir = stateDir ?
|
|
32831
|
+
stateDir = stateDir ? path43.resolve(stateDir) : resolveStateDirFromArgs2(args.slice(1));
|
|
32660
32832
|
try {
|
|
32661
32833
|
const { provisionFreeToken: provisionFreeToken2 } = await Promise.resolve().then(() => (init_provision_free(), provision_free_exports));
|
|
32662
32834
|
const result = await provisionFreeToken2({
|
|
32663
32835
|
relayBaseUrl: relay,
|
|
32664
32836
|
stateDir,
|
|
32665
32837
|
// 和 init 写 config 的路径一致(cli-init.ts 里 configPath 就是这么拼的)
|
|
32666
|
-
configPath:
|
|
32838
|
+
configPath: path43.join(stateDir, "configs", "main7.json")
|
|
32667
32839
|
});
|
|
32668
32840
|
console.log(JSON.stringify(result, null, 2));
|
|
32669
32841
|
process.exit(0);
|
|
@@ -32690,18 +32862,18 @@ async function main() {
|
|
|
32690
32862
|
else if (args[i] === "--base-url" && args[i + 1]) relayBaseUrl = args[++i].trim();
|
|
32691
32863
|
}
|
|
32692
32864
|
if (!stateDir) {
|
|
32693
|
-
const cwd =
|
|
32694
|
-
if (
|
|
32865
|
+
const cwd = path43.resolve(process.cwd());
|
|
32866
|
+
if (fs43.existsSync(path43.join(cwd, "configs"))) {
|
|
32695
32867
|
stateDir = cwd;
|
|
32696
32868
|
} else {
|
|
32697
|
-
const pointer =
|
|
32698
|
-
if (
|
|
32869
|
+
const pointer = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
|
|
32870
|
+
if (fs43.existsSync(pointer)) {
|
|
32699
32871
|
try {
|
|
32700
|
-
stateDir = JSON.parse(
|
|
32872
|
+
stateDir = JSON.parse(fs43.readFileSync(pointer, "utf8")).stateDir || "";
|
|
32701
32873
|
} catch {
|
|
32702
32874
|
}
|
|
32703
32875
|
}
|
|
32704
|
-
if (!stateDir) stateDir =
|
|
32876
|
+
if (!stateDir) stateDir = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
|
|
32705
32877
|
}
|
|
32706
32878
|
}
|
|
32707
32879
|
if (!target && !isLegacyAddchannel) {
|
|
@@ -32721,12 +32893,12 @@ async function main() {
|
|
|
32721
32893
|
process.exit(0);
|
|
32722
32894
|
}
|
|
32723
32895
|
if (channel === "channels") {
|
|
32724
|
-
const configsDir =
|
|
32725
|
-
if (
|
|
32726
|
-
const files =
|
|
32896
|
+
const configsDir = path43.join(stateDir, "configs");
|
|
32897
|
+
if (fs43.existsSync(configsDir)) {
|
|
32898
|
+
const files = fs43.readdirSync(configsDir).filter((f) => f.endsWith(".json"));
|
|
32727
32899
|
for (const f of files) {
|
|
32728
32900
|
try {
|
|
32729
|
-
const j = JSON.parse(
|
|
32901
|
+
const j = JSON.parse(fs43.readFileSync(path43.join(configsDir, f), "utf8"));
|
|
32730
32902
|
if (!j.channels) continue;
|
|
32731
32903
|
console.log(`
|
|
32732
32904
|
\u{1F4C4} ${f}:`);
|
|
@@ -32763,7 +32935,7 @@ async function main() {
|
|
|
32763
32935
|
}
|
|
32764
32936
|
const configFile = resolveConfigPath2(stateDir, configName);
|
|
32765
32937
|
if (!configFile) {
|
|
32766
|
-
fail2(`\u6CA1\u627E\u5230\u53EF\u6539\u7684 config\uFF1A\u5728 ${
|
|
32938
|
+
fail2(`\u6CA1\u627E\u5230\u53EF\u6539\u7684 config\uFF1A\u5728 ${path43.join(stateDir, "configs")} \u4E0B\u65E2\u6CA1\u6709 main7.json\uFF0C\u4E5F\u6CA1\u6709\u542B models.providers \u7684 json\u3002\u7528 --config <\u6587\u4EF6\u540D> \u6307\u5B9A\u3002`);
|
|
32767
32939
|
}
|
|
32768
32940
|
if (!readSecretsValue(stateDir, FREE_TIER_ENV_KEY2)) {
|
|
32769
32941
|
fail2(`\u514D\u8D39\u6863\u7F3A\u5C11\u4EE4\u724C\uFF1Asecrets \u91CC\u6CA1\u6709 ${FREE_TIER_ENV_KEY2}\u3002\u5148\u9886\u53F7\uFF1A
|
|
@@ -32830,8 +33002,8 @@ async function main() {
|
|
|
32830
33002
|
else if (args[i] === "--note" && args[i + 1]) note = args[++i];
|
|
32831
33003
|
else if (args[i] === "--dry-run") dryRun2 = true;
|
|
32832
33004
|
}
|
|
32833
|
-
if (!exportStateDir) exportStateDir =
|
|
32834
|
-
if (!agentName) agentName =
|
|
33005
|
+
if (!exportStateDir) exportStateDir = path43.resolve(process.cwd());
|
|
33006
|
+
if (!agentName) agentName = path43.basename(exportStateDir);
|
|
32835
33007
|
await doExport2({ agentName, stateDir: exportStateDir, note, dryRun: dryRun2 });
|
|
32836
33008
|
process.exit(0);
|
|
32837
33009
|
}
|
|
@@ -32853,7 +33025,7 @@ async function main() {
|
|
|
32853
33025
|
console.error("\u274C import \u9700\u8981 --state-dir <path>");
|
|
32854
33026
|
process.exit(1);
|
|
32855
33027
|
}
|
|
32856
|
-
if (!agentName) agentName =
|
|
33028
|
+
if (!agentName) agentName = path43.basename(importStateDir);
|
|
32857
33029
|
await doImport2({ agentName, stateDir: importStateDir, version, archiveFile: archiveFile || void 0, dryRun: dryRun2 });
|
|
32858
33030
|
process.exit(0);
|
|
32859
33031
|
}
|
|
@@ -32881,18 +33053,18 @@ engine7 start \u2014 \u542F\u52A8 Engine
|
|
|
32881
33053
|
}
|
|
32882
33054
|
}
|
|
32883
33055
|
if (!configPath2) {
|
|
32884
|
-
const defaultCfg =
|
|
32885
|
-
const homeCfg =
|
|
32886
|
-
if (
|
|
33056
|
+
const defaultCfg = path43.join("configs", "main7.json");
|
|
33057
|
+
const homeCfg = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
|
|
33058
|
+
if (fs43.existsSync(defaultCfg)) {
|
|
32887
33059
|
configPath2 = defaultCfg;
|
|
32888
|
-
} else if (
|
|
33060
|
+
} else if (fs43.existsSync(homeCfg)) {
|
|
32889
33061
|
configPath2 = homeCfg;
|
|
32890
33062
|
console.log(` \u4F7F\u7528\u9ED8\u8BA4 config: ${homeCfg}`);
|
|
32891
33063
|
} else {
|
|
32892
33064
|
const ptr = readHomePointer();
|
|
32893
33065
|
if (ptr?.stateDir) {
|
|
32894
|
-
const ptrCfg =
|
|
32895
|
-
if (
|
|
33066
|
+
const ptrCfg = path43.join(ptr.stateDir, "configs", "main7.json");
|
|
33067
|
+
if (fs43.existsSync(ptrCfg)) {
|
|
32896
33068
|
configPath2 = ptrCfg;
|
|
32897
33069
|
console.log(` \u4F7F\u7528 config: ${ptrCfg}`);
|
|
32898
33070
|
}
|
|
@@ -32905,26 +33077,26 @@ engine7 start \u2014 \u542F\u52A8 Engine
|
|
|
32905
33077
|
}
|
|
32906
33078
|
}
|
|
32907
33079
|
}
|
|
32908
|
-
if (configPath2 && !
|
|
33080
|
+
if (configPath2 && !fs43.existsSync(configPath2)) {
|
|
32909
33081
|
console.error(`\u274C config \u6587\u4EF6\u4E0D\u5B58\u5728: ${configPath2}`);
|
|
32910
33082
|
console.error(" \u7528\u6CD5: engine7 start [configs/xxx.json | --config <path>]");
|
|
32911
33083
|
process.exit(1);
|
|
32912
33084
|
}
|
|
32913
|
-
const { execSync:
|
|
33085
|
+
const { execSync: execSync4, spawn: spawn5 } = await import("node:child_process");
|
|
32914
33086
|
let enginePath;
|
|
32915
|
-
const localPath =
|
|
32916
|
-
if (
|
|
33087
|
+
const localPath = path43.join("node_modules", "engine7", "dist", "main.mjs");
|
|
33088
|
+
if (fs43.existsSync(localPath)) {
|
|
32917
33089
|
enginePath = localPath;
|
|
32918
33090
|
} else {
|
|
32919
|
-
const cliPath =
|
|
32920
|
-
const distDir =
|
|
32921
|
-
const candidate =
|
|
32922
|
-
if (
|
|
33091
|
+
const cliPath = path43.resolve(process.argv[1]);
|
|
33092
|
+
const distDir = path43.dirname(cliPath);
|
|
33093
|
+
const candidate = path43.join(distDir, "main.mjs");
|
|
33094
|
+
if (fs43.existsSync(candidate)) {
|
|
32923
33095
|
enginePath = candidate;
|
|
32924
33096
|
} else {
|
|
32925
33097
|
try {
|
|
32926
|
-
const globalRoot =
|
|
32927
|
-
enginePath =
|
|
33098
|
+
const globalRoot = execSync4("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
33099
|
+
enginePath = path43.join(globalRoot, "engine7", "dist", "main.mjs");
|
|
32928
33100
|
} catch {
|
|
32929
33101
|
console.error("\u274C \u627E\u4E0D\u5230 engine7 main.mjs");
|
|
32930
33102
|
process.exit(1);
|
|
@@ -32934,29 +33106,23 @@ engine7 start \u2014 \u542F\u52A8 Engine
|
|
|
32934
33106
|
console.log(label);
|
|
32935
33107
|
console.log(` config: ${configPath2}`);
|
|
32936
33108
|
console.log(` engine: ${enginePath}`);
|
|
32937
|
-
const
|
|
32938
|
-
const configAbs = path42.resolve(configPath2);
|
|
32939
|
-
const myPid = process.pid;
|
|
33109
|
+
const configAbs = path43.resolve(configPath2);
|
|
32940
33110
|
try {
|
|
32941
|
-
|
|
32942
|
-
|
|
32943
|
-
|
|
32944
|
-
|
|
32945
|
-
|
|
32946
|
-
if (otherPids) {
|
|
32947
|
-
console.log(`[start] Killing existing engine (PID: ${otherPids})...`);
|
|
32948
|
-
execSync3(`echo "${otherPids}" | xargs kill -9 2>/dev/null || true`);
|
|
32949
|
-
await new Promise((r) => setTimeout(r, 2e3));
|
|
32950
|
-
}
|
|
33111
|
+
const stateDir = engineStateDirOfConfig(configAbs);
|
|
33112
|
+
const killed = stateDir ? killOwnEngineForStateDir(stateDir) : null;
|
|
33113
|
+
if (killed !== null) {
|
|
33114
|
+
console.log(`[start] Killing existing engine (PID: ${killed})...`);
|
|
33115
|
+
await waitForPidGone(killed);
|
|
32951
33116
|
}
|
|
32952
|
-
} catch {
|
|
33117
|
+
} catch (err) {
|
|
33118
|
+
console.warn(`[start] \u6740\u65E7\u8FDB\u7A0B\u5931\u8D25\uFF08\u4E0D\u6321\u542F\u52A8\uFF09\uFF1A${err.message}`);
|
|
32953
33119
|
}
|
|
32954
33120
|
console.log("");
|
|
32955
33121
|
const envForChild = { ...process.env };
|
|
32956
33122
|
const { stateDir: secretsStateDir, configName: secretsCfgName } = resolveConfigIdentity(configPath2);
|
|
32957
33123
|
for (const secretPath of secretsCandidates(secretsStateDir, secretsCfgName)) {
|
|
32958
|
-
if (
|
|
32959
|
-
const content =
|
|
33124
|
+
if (fs43.existsSync(secretPath)) {
|
|
33125
|
+
const content = fs43.readFileSync(secretPath, "utf-8");
|
|
32960
33126
|
for (const line of content.split("\n")) {
|
|
32961
33127
|
const trimmed = line.trim();
|
|
32962
33128
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -33004,7 +33170,6 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
|
|
|
33004
33170
|
process.exit(0);
|
|
33005
33171
|
}
|
|
33006
33172
|
if (action === "reset") {
|
|
33007
|
-
const { execSync: execSync3 } = await import("node:child_process");
|
|
33008
33173
|
let configPath2 = "";
|
|
33009
33174
|
let mode = "archive";
|
|
33010
33175
|
let dropN = 3;
|
|
@@ -33031,14 +33196,14 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
|
|
|
33031
33196
|
console.error(`\u274C \u672A\u77E5\u6A21\u5F0F: ${mode}\uFF08\u53EF\u9009: archive / drop-last / strip-images\uFF09`);
|
|
33032
33197
|
process.exit(1);
|
|
33033
33198
|
}
|
|
33034
|
-
const configRaw = JSON.parse(
|
|
33199
|
+
const configRaw = JSON.parse(fs43.readFileSync(configPath2, "utf-8"));
|
|
33035
33200
|
const stateDir = configRaw.stateDir;
|
|
33036
33201
|
if (!stateDir) {
|
|
33037
33202
|
console.error("\u274C config \u91CC\u6CA1\u6709 stateDir");
|
|
33038
33203
|
process.exit(1);
|
|
33039
33204
|
}
|
|
33040
|
-
const sessionsDir =
|
|
33041
|
-
if (!
|
|
33205
|
+
const sessionsDir = path43.join(stateDir, "agents", "main", "sessions");
|
|
33206
|
+
if (!fs43.existsSync(sessionsDir)) {
|
|
33042
33207
|
console.error(`\u274C sessions \u76EE\u5F55\u4E0D\u5B58\u5728: ${sessionsDir}`);
|
|
33043
33208
|
process.exit(1);
|
|
33044
33209
|
}
|
|
@@ -33046,56 +33211,54 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
|
|
|
33046
33211
|
console.log(` config: ${configPath2}`);
|
|
33047
33212
|
console.log(` mode: ${mode}`);
|
|
33048
33213
|
if (mode === "drop-last") console.log(` n: ${dropN}`);
|
|
33049
|
-
const platformMapPath =
|
|
33050
|
-
const indexPath =
|
|
33214
|
+
const platformMapPath = path43.join(sessionsDir, "platform-map.json");
|
|
33215
|
+
const indexPath = path43.join(sessionsDir, "session-index.json");
|
|
33051
33216
|
let sessionFileUUID = null;
|
|
33052
|
-
if (
|
|
33053
|
-
const index = JSON.parse(
|
|
33217
|
+
if (fs43.existsSync(indexPath)) {
|
|
33218
|
+
const index = JSON.parse(fs43.readFileSync(indexPath, "utf-8"));
|
|
33054
33219
|
const entries2 = Object.values(index);
|
|
33055
33220
|
if (entries2.length > 0) {
|
|
33056
33221
|
const fileVal = entries2[0].file || "";
|
|
33057
|
-
sessionFileUUID =
|
|
33222
|
+
sessionFileUUID = path43.isAbsolute(fileVal) ? path43.basename(fileVal, ".jsonl") : fileVal.replace(".jsonl", "");
|
|
33058
33223
|
}
|
|
33059
33224
|
}
|
|
33060
33225
|
if (!sessionFileUUID) {
|
|
33061
|
-
const jsonlFiles =
|
|
33226
|
+
const jsonlFiles = fs43.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") && !f.includes(".archived.") && !f.includes(".compaction.")).map((f) => ({ name: f, mtime: fs43.statSync(path43.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
33062
33227
|
if (jsonlFiles.length === 0) {
|
|
33063
33228
|
console.error("\u274C \u627E\u4E0D\u5230\u6D3B\u8DC3\u7684 session JSONL \u6587\u4EF6");
|
|
33064
33229
|
process.exit(1);
|
|
33065
33230
|
}
|
|
33066
33231
|
sessionFileUUID = jsonlFiles[0].name.replace(".jsonl", "");
|
|
33067
33232
|
}
|
|
33068
|
-
let jsonlPath =
|
|
33069
|
-
if (!
|
|
33070
|
-
const jsonlFiles =
|
|
33233
|
+
let jsonlPath = path43.join(sessionsDir, `${sessionFileUUID}.jsonl`);
|
|
33234
|
+
if (!fs43.existsSync(jsonlPath)) {
|
|
33235
|
+
const jsonlFiles = fs43.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") && !f.includes(".archived.") && !f.includes(".compaction.")).map((f) => ({ name: f, mtime: fs43.statSync(path43.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
33071
33236
|
if (jsonlFiles.length === 0) {
|
|
33072
33237
|
console.error(`\u274C JSONL \u6587\u4EF6\u4E0D\u5B58\u5728: ${jsonlPath}`);
|
|
33073
33238
|
process.exit(1);
|
|
33074
33239
|
}
|
|
33075
33240
|
sessionFileUUID = jsonlFiles[0].name.replace(".jsonl", "");
|
|
33076
|
-
jsonlPath =
|
|
33241
|
+
jsonlPath = path43.join(sessionsDir, `${sessionFileUUID}.jsonl`);
|
|
33077
33242
|
}
|
|
33078
33243
|
console.log(` file: ${jsonlPath}`);
|
|
33079
|
-
const configName = path42.basename(configPath2);
|
|
33080
33244
|
if (autoRestart) {
|
|
33081
33245
|
try {
|
|
33082
|
-
const
|
|
33083
|
-
const
|
|
33084
|
-
|
|
33085
|
-
if (otherPids) {
|
|
33246
|
+
const stateDir2 = engineStateDirOfConfig(path43.resolve(configPath2));
|
|
33247
|
+
const killed = stateDir2 ? killOwnEngineForStateDir(stateDir2) : null;
|
|
33248
|
+
if (killed !== null) {
|
|
33086
33249
|
console.log(`
|
|
33087
|
-
Killing engine (PID: ${
|
|
33088
|
-
|
|
33089
|
-
await new Promise((r) => setTimeout(r, 2e3));
|
|
33250
|
+
Killing engine (PID: ${killed})...`);
|
|
33251
|
+
await waitForPidGone(killed);
|
|
33090
33252
|
}
|
|
33091
|
-
} catch {
|
|
33253
|
+
} catch (err) {
|
|
33254
|
+
console.warn(`[session] \u6740\u65E7\u8FDB\u7A0B\u5931\u8D25\uFF08\u4E0D\u6321\u91CD\u7F6E\uFF09\uFF1A${err.message}`);
|
|
33092
33255
|
}
|
|
33093
33256
|
}
|
|
33094
33257
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
33095
|
-
const { readFileSync: readFileSync45, writeFileSync: writeFileSync26, renameSync: renameSync5 } =
|
|
33258
|
+
const { readFileSync: readFileSync45, writeFileSync: writeFileSync26, renameSync: renameSync5 } = fs43;
|
|
33096
33259
|
if (mode === "archive") {
|
|
33097
33260
|
const archiveName = `${sessionFileUUID}.jsonl.archived.${timestamp}`;
|
|
33098
|
-
renameSync5(jsonlPath,
|
|
33261
|
+
renameSync5(jsonlPath, path43.join(sessionsDir, archiveName));
|
|
33099
33262
|
console.log(`
|
|
33100
33263
|
\u2705 \u5F52\u6863\u5B8C\u6210: ${archiveName}`);
|
|
33101
33264
|
console.log(` \u91CD\u542F\u540E\u5C06\u4ECE\u7A7A\u767D\u4F1A\u8BDD\u5F00\u59CB`);
|
|
@@ -33170,12 +33333,12 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
|
|
|
33170
33333
|
\u2705 \u6458\u9664 ${stripped} \u884C\u56FE\u7247\u76F8\u5173\u5185\u5BB9`);
|
|
33171
33334
|
}
|
|
33172
33335
|
if (autoRestart) {
|
|
33173
|
-
const realCliPath =
|
|
33174
|
-
const cliDir =
|
|
33175
|
-
const pkgRoot =
|
|
33176
|
-
let enginePath =
|
|
33177
|
-
if (!
|
|
33178
|
-
enginePath =
|
|
33336
|
+
const realCliPath = fs43.realpathSync(process.argv[1]);
|
|
33337
|
+
const cliDir = path43.dirname(realCliPath);
|
|
33338
|
+
const pkgRoot = path43.resolve(cliDir, "..");
|
|
33339
|
+
let enginePath = path43.join(pkgRoot, "dist", "main.mjs");
|
|
33340
|
+
if (!fs43.existsSync(enginePath)) {
|
|
33341
|
+
enginePath = path43.join(cliDir, "main.mjs");
|
|
33179
33342
|
}
|
|
33180
33343
|
console.log(`
|
|
33181
33344
|
\u{1F680} \u62C9\u8D77 engine...`);
|
|
@@ -33215,18 +33378,18 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
|
|
|
33215
33378
|
let configPath2 = cfg;
|
|
33216
33379
|
let cwd = svcCwd;
|
|
33217
33380
|
if (!configPath2) {
|
|
33218
|
-
const defaultCfg =
|
|
33219
|
-
const homeCfg =
|
|
33220
|
-
if (
|
|
33381
|
+
const defaultCfg = path43.join(cwd, "configs", "main7.json");
|
|
33382
|
+
const homeCfg = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
|
|
33383
|
+
if (fs43.existsSync(defaultCfg)) {
|
|
33221
33384
|
configPath2 = defaultCfg;
|
|
33222
|
-
} else if (
|
|
33385
|
+
} else if (fs43.existsSync(homeCfg)) {
|
|
33223
33386
|
configPath2 = homeCfg;
|
|
33224
|
-
cwd =
|
|
33387
|
+
cwd = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
|
|
33225
33388
|
} else {
|
|
33226
33389
|
const ptr = readHomePointer();
|
|
33227
33390
|
if (ptr?.stateDir) {
|
|
33228
|
-
const ptrCfg =
|
|
33229
|
-
if (
|
|
33391
|
+
const ptrCfg = path43.join(ptr.stateDir, "configs", "main7.json");
|
|
33392
|
+
if (fs43.existsSync(ptrCfg)) {
|
|
33230
33393
|
configPath2 = ptrCfg;
|
|
33231
33394
|
cwd = ptr.stateDir;
|
|
33232
33395
|
}
|
|
@@ -33239,32 +33402,32 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
|
|
|
33239
33402
|
}
|
|
33240
33403
|
}
|
|
33241
33404
|
}
|
|
33242
|
-
const { execSync:
|
|
33405
|
+
const { execSync: execSync4 } = await import("node:child_process");
|
|
33243
33406
|
const engine7Bin = process.argv[1];
|
|
33244
33407
|
if (action === "install") {
|
|
33245
33408
|
if (process.platform === "win32") {
|
|
33246
33409
|
const taskName = "Engine7";
|
|
33247
|
-
const wrapperPath =
|
|
33410
|
+
const wrapperPath = path43.join(cwd, "engine7-start.cmd");
|
|
33248
33411
|
const wrapperContent = buildServiceWrapper({
|
|
33249
33412
|
cwd,
|
|
33250
33413
|
nodeExe: nodeExe || void 0,
|
|
33251
|
-
cliMjs:
|
|
33252
|
-
configPath:
|
|
33414
|
+
cliMjs: path43.resolve(engine7Bin),
|
|
33415
|
+
configPath: path43.resolve(configPath2)
|
|
33253
33416
|
});
|
|
33254
|
-
|
|
33255
|
-
const startupDir =
|
|
33256
|
-
process.env.APPDATA ||
|
|
33417
|
+
fs43.writeFileSync(wrapperPath, wrapperContent);
|
|
33418
|
+
const startupDir = path43.join(
|
|
33419
|
+
process.env.APPDATA || path43.join(process.env.USERPROFILE || "", "AppData", "Roaming"),
|
|
33257
33420
|
"Microsoft",
|
|
33258
33421
|
"Windows",
|
|
33259
33422
|
"Start Menu",
|
|
33260
33423
|
"Programs",
|
|
33261
33424
|
"Startup"
|
|
33262
33425
|
);
|
|
33263
|
-
|
|
33264
|
-
const vbsPath =
|
|
33426
|
+
fs43.mkdirSync(startupDir, { recursive: true });
|
|
33427
|
+
const vbsPath = path43.join(startupDir, "Engine7.vbs");
|
|
33265
33428
|
const nodeExePath = nodeExe || process.execPath;
|
|
33266
|
-
const cliMjsPath =
|
|
33267
|
-
const absCfg =
|
|
33429
|
+
const cliMjsPath = path43.resolve(engine7Bin);
|
|
33430
|
+
const absCfg = path43.resolve(configPath2);
|
|
33268
33431
|
const vbs = [
|
|
33269
33432
|
"' Engine 7 \u5F00\u673A\u81EA\u542F\uFF08\u542F\u52A8\u6587\u4EF6\u5939\uFF0C\u514D\u7BA1\u7406\u5458\uFF09",
|
|
33270
33433
|
'Set fso = CreateObject("Scripting.FileSystemObject")',
|
|
@@ -33280,15 +33443,15 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
|
|
|
33280
33443
|
's.Run """' + nodeExePath + '"" ""' + cliMjsPath + '"" start --config ""' + absCfg + '""", 0, False',
|
|
33281
33444
|
""
|
|
33282
33445
|
].join(String.fromCharCode(13) + String.fromCharCode(10));
|
|
33283
|
-
|
|
33446
|
+
fs43.writeFileSync(vbsPath, vbs);
|
|
33284
33447
|
console.log(`\u2705 \u5F00\u673A\u81EA\u542F\u52A8\u5DF2\u6CE8\u518C\uFF08\u542F\u52A8\u6587\u4EF6\u5939: ${vbsPath}\uFF09`);
|
|
33285
33448
|
} else if (process.platform === "darwin") {
|
|
33286
33449
|
const label = "com.engine7.agent";
|
|
33287
|
-
const plistDir =
|
|
33288
|
-
|
|
33289
|
-
const plistPath =
|
|
33290
|
-
const localCli =
|
|
33291
|
-
const cliMjs =
|
|
33450
|
+
const plistDir = path43.join(process.env.HOME, "Library", "LaunchAgents");
|
|
33451
|
+
fs43.mkdirSync(plistDir, { recursive: true });
|
|
33452
|
+
const plistPath = path43.join(plistDir, `${label}.plist`);
|
|
33453
|
+
const localCli = path43.join("node_modules", "engine7", "dist", "cli.mjs");
|
|
33454
|
+
const cliMjs = fs43.existsSync(localCli) ? path43.resolve(localCli) : path43.join(path43.dirname(path43.dirname(engine7Bin)), "lib", "node_modules", "engine7", "dist", "cli.mjs");
|
|
33292
33455
|
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
33293
33456
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
33294
33457
|
<plist version="1.0">
|
|
@@ -33300,16 +33463,16 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
|
|
|
33300
33463
|
<string>${cliMjs}</string>
|
|
33301
33464
|
<string>start</string>
|
|
33302
33465
|
<string>--config</string>
|
|
33303
|
-
<string>${
|
|
33466
|
+
<string>${path43.resolve(configPath2)}</string>
|
|
33304
33467
|
</array>
|
|
33305
33468
|
<key>WorkingDirectory</key><string>${cwd}</string>
|
|
33306
33469
|
<key>RunAtLoad</key><true/>
|
|
33307
33470
|
<key>KeepAlive</key><true/>
|
|
33308
33471
|
</dict>
|
|
33309
33472
|
</plist>`;
|
|
33310
|
-
|
|
33473
|
+
fs43.writeFileSync(plistPath, plist);
|
|
33311
33474
|
try {
|
|
33312
|
-
|
|
33475
|
+
execSync4(`launchctl load "${plistPath}"`, { stdio: "inherit" });
|
|
33313
33476
|
console.log(`\u2705 Mac launchd \u670D\u52A1\u5DF2\u521B\u5EFA\uFF08\u5F00\u673A\u81EA\u542F\u52A8\uFF09`);
|
|
33314
33477
|
console.log(` ${plistPath}`);
|
|
33315
33478
|
} catch {
|
|
@@ -33318,9 +33481,9 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
|
|
|
33318
33481
|
}
|
|
33319
33482
|
} else {
|
|
33320
33483
|
const svcName = "engine7";
|
|
33321
|
-
const svcDir =
|
|
33322
|
-
|
|
33323
|
-
const svcPath =
|
|
33484
|
+
const svcDir = path43.join(process.env.HOME, ".config", "systemd", "user");
|
|
33485
|
+
fs43.mkdirSync(svcDir, { recursive: true });
|
|
33486
|
+
const svcPath = path43.join(svcDir, `${svcName}.service`);
|
|
33324
33487
|
const svc = `[Unit]
|
|
33325
33488
|
Description=Engine 7 Agent
|
|
33326
33489
|
After=network.target
|
|
@@ -33328,16 +33491,16 @@ After=network.target
|
|
|
33328
33491
|
[Service]
|
|
33329
33492
|
Type=simple
|
|
33330
33493
|
WorkingDirectory=${cwd}
|
|
33331
|
-
ExecStart=${process.execPath} ${engine7Bin} start --config ${
|
|
33494
|
+
ExecStart=${process.execPath} ${engine7Bin} start --config ${path43.resolve(configPath2)}
|
|
33332
33495
|
Restart=on-failure
|
|
33333
33496
|
RestartSec=10
|
|
33334
33497
|
|
|
33335
33498
|
[Install]
|
|
33336
33499
|
WantedBy=default.target`;
|
|
33337
|
-
|
|
33500
|
+
fs43.writeFileSync(svcPath, svc);
|
|
33338
33501
|
try {
|
|
33339
|
-
|
|
33340
|
-
|
|
33502
|
+
execSync4(`systemctl --user daemon-reload`, { stdio: "inherit" });
|
|
33503
|
+
execSync4(`systemctl --user enable ${svcName}`, { stdio: "inherit" });
|
|
33341
33504
|
console.log(`\u2705 systemd \u7528\u6237\u670D\u52A1\u5DF2\u521B\u5EFA\uFF08\u5F00\u673A\u81EA\u542F\u52A8\uFF09`);
|
|
33342
33505
|
console.log(` ${svcPath}`);
|
|
33343
33506
|
} catch {
|
|
@@ -33347,8 +33510,8 @@ WantedBy=default.target`;
|
|
|
33347
33510
|
}
|
|
33348
33511
|
} else if (action === "uninstall") {
|
|
33349
33512
|
if (process.platform === "win32") {
|
|
33350
|
-
const vbsPath =
|
|
33351
|
-
process.env.APPDATA ||
|
|
33513
|
+
const vbsPath = path43.join(
|
|
33514
|
+
process.env.APPDATA || path43.join(process.env.USERPROFILE || "", "AppData", "Roaming"),
|
|
33352
33515
|
"Microsoft",
|
|
33353
33516
|
"Windows",
|
|
33354
33517
|
"Start Menu",
|
|
@@ -33357,46 +33520,46 @@ WantedBy=default.target`;
|
|
|
33357
33520
|
"Engine7.vbs"
|
|
33358
33521
|
);
|
|
33359
33522
|
try {
|
|
33360
|
-
|
|
33523
|
+
execSync4(`schtasks /delete /tn "Engine7" /f`, { stdio: "ignore" });
|
|
33361
33524
|
} catch {
|
|
33362
33525
|
}
|
|
33363
|
-
if (
|
|
33364
|
-
|
|
33526
|
+
if (fs43.existsSync(vbsPath)) {
|
|
33527
|
+
fs43.rmSync(vbsPath, { force: true });
|
|
33365
33528
|
console.log(`\u2705 \u5F00\u673A\u81EA\u542F\u52A8\u5DF2\u79FB\u9664\uFF08${vbsPath}\uFF09`);
|
|
33366
33529
|
} else {
|
|
33367
33530
|
console.log("\uFF08\u5F00\u673A\u81EA\u542F\u52A8\u672C\u6765\u5C31\u6CA1\u6CE8\u518C\uFF09");
|
|
33368
33531
|
}
|
|
33369
33532
|
} else if (process.platform === "darwin") {
|
|
33370
|
-
const plistPath =
|
|
33533
|
+
const plistPath = path43.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
|
|
33371
33534
|
try {
|
|
33372
|
-
|
|
33535
|
+
execSync4(`launchctl unload "${plistPath}"`, { stdio: "inherit" });
|
|
33373
33536
|
} catch {
|
|
33374
33537
|
}
|
|
33375
33538
|
try {
|
|
33376
|
-
|
|
33539
|
+
fs43.unlinkSync(plistPath);
|
|
33377
33540
|
} catch {
|
|
33378
33541
|
}
|
|
33379
33542
|
console.log(`\u2705 Mac launchd \u670D\u52A1\u5DF2\u5220\u9664`);
|
|
33380
33543
|
} else {
|
|
33381
33544
|
try {
|
|
33382
|
-
|
|
33545
|
+
execSync4(`systemctl --user disable engine7`, { stdio: "inherit" });
|
|
33383
33546
|
} catch {
|
|
33384
33547
|
}
|
|
33385
|
-
const svcPath =
|
|
33548
|
+
const svcPath = path43.join(process.env.HOME, ".config", "systemd", "user", "engine7.service");
|
|
33386
33549
|
try {
|
|
33387
|
-
|
|
33550
|
+
fs43.unlinkSync(svcPath);
|
|
33388
33551
|
} catch {
|
|
33389
33552
|
}
|
|
33390
33553
|
try {
|
|
33391
|
-
|
|
33554
|
+
execSync4(`systemctl --user daemon-reload`, { stdio: "inherit" });
|
|
33392
33555
|
} catch {
|
|
33393
33556
|
}
|
|
33394
33557
|
console.log(`\u2705 systemd \u7528\u6237\u670D\u52A1\u5DF2\u5220\u9664`);
|
|
33395
33558
|
}
|
|
33396
33559
|
} else if (action === "status") {
|
|
33397
33560
|
if (process.platform === "win32") {
|
|
33398
|
-
const vbsPath =
|
|
33399
|
-
process.env.APPDATA ||
|
|
33561
|
+
const vbsPath = path43.join(
|
|
33562
|
+
process.env.APPDATA || path43.join(process.env.USERPROFILE || "", "AppData", "Roaming"),
|
|
33400
33563
|
"Microsoft",
|
|
33401
33564
|
"Windows",
|
|
33402
33565
|
"Start Menu",
|
|
@@ -33404,17 +33567,17 @@ WantedBy=default.target`;
|
|
|
33404
33567
|
"Startup",
|
|
33405
33568
|
"Engine7.vbs"
|
|
33406
33569
|
);
|
|
33407
|
-
console.log(
|
|
33570
|
+
console.log(fs43.existsSync(vbsPath) ? `\u2705 \u5DF2\u6CE8\u518C\uFF08\u542F\u52A8\u6587\u4EF6\u5939\uFF09: ${vbsPath}` : "\u274C \u672A\u6CE8\u518C");
|
|
33408
33571
|
} else if (process.platform === "darwin") {
|
|
33409
|
-
const plistPath =
|
|
33410
|
-
if (
|
|
33572
|
+
const plistPath = path43.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
|
|
33573
|
+
if (fs43.existsSync(plistPath)) {
|
|
33411
33574
|
console.log("\u2705 \u5DF2\u5B89\u88C5\uFF08launchd\uFF09");
|
|
33412
33575
|
} else {
|
|
33413
33576
|
console.log("\u274C \u672A\u5B89\u88C5");
|
|
33414
33577
|
}
|
|
33415
33578
|
} else {
|
|
33416
33579
|
try {
|
|
33417
|
-
|
|
33580
|
+
execSync4(`systemctl --user is-enabled engine7`, { stdio: "inherit" });
|
|
33418
33581
|
} catch {
|
|
33419
33582
|
console.log("\u274C \u672A\u5B89\u88C5");
|
|
33420
33583
|
}
|
|
@@ -33440,8 +33603,8 @@ WantedBy=default.target`;
|
|
|
33440
33603
|
console.log(`
|
|
33441
33604
|
\u{1F680} engine7 init`);
|
|
33442
33605
|
console.log(` state-dir: ${opts.stateDir}`);
|
|
33443
|
-
if (
|
|
33444
|
-
const files =
|
|
33606
|
+
if (fs43.existsSync(opts.stateDir) && !opts.dryRun) {
|
|
33607
|
+
const files = fs43.readdirSync(opts.stateDir);
|
|
33445
33608
|
if (files.length > 0) {
|
|
33446
33609
|
if (opts.force) {
|
|
33447
33610
|
if (looksLikeAppInstall(opts.stateDir)) {
|
|
@@ -33454,10 +33617,10 @@ WantedBy=default.target`;
|
|
|
33454
33617
|
}
|
|
33455
33618
|
console.log(`
|
|
33456
33619
|
\u26A0\uFE0F --force: \u6E05\u7A7A\u5DF2\u6709\u76EE\u5F55 ${opts.stateDir}`);
|
|
33457
|
-
|
|
33620
|
+
fs43.rmSync(opts.stateDir, { recursive: true, force: true });
|
|
33458
33621
|
} else {
|
|
33459
|
-
const existingConfig =
|
|
33460
|
-
if (
|
|
33622
|
+
const existingConfig = path43.join(opts.stateDir, "configs", "main7.json");
|
|
33623
|
+
if (fs43.existsSync(existingConfig)) {
|
|
33461
33624
|
console.log(`
|
|
33462
33625
|
\u267B\uFE0F \u68C0\u6D4B\u5230\u5DF2\u6709\u914D\u7F6E: ${existingConfig}`);
|
|
33463
33626
|
console.log(` \u2192 \u590D\u8DD1\u6A21\u5F0F\uFF1A\u663E\u793A\u73B0\u6709\u914D\u7F6E\uFF0C\u56DE\u8F66\u4FDD\u7559\uFF0C\u6539\u4E86\u624D\u751F\u6548\uFF08\u4E0D\u4F1A\u6E05\u7A7A\u76EE\u5F55\uFF09`);
|
|
@@ -33538,12 +33701,12 @@ WantedBy=default.target`;
|
|
|
33538
33701
|
let photoSrc = "";
|
|
33539
33702
|
if (answers?.selfie?.photoPath) {
|
|
33540
33703
|
const { dimsOf: dimsOf2 } = await Promise.resolve().then(() => (init_my_selfie(), my_selfie_exports));
|
|
33541
|
-
const src =
|
|
33542
|
-
const ext =
|
|
33704
|
+
const src = path43.resolve(answers.selfie.photoPath.trim());
|
|
33705
|
+
const ext = path43.extname(src).toLowerCase();
|
|
33543
33706
|
if (!PHOTO_EXTS.includes(ext)) {
|
|
33544
33707
|
throw new Error(`\u7167\u7247\u683C\u5F0F\u4E0D\u652F\u6301\uFF1A${ext || "(\u6CA1\u6709\u540E\u7F00)"}\u3002\u8BF7\u7528 PNG / JPEG / WebP\u3002`);
|
|
33545
33708
|
}
|
|
33546
|
-
if (!
|
|
33709
|
+
if (!fs43.existsSync(src)) {
|
|
33547
33710
|
throw new Error(`\u7167\u7247\u4E0D\u5B58\u5728\uFF1A${src}`);
|
|
33548
33711
|
}
|
|
33549
33712
|
const dims = dimsOf2(src);
|
|
@@ -33554,7 +33717,7 @@ WantedBy=default.target`;
|
|
|
33554
33717
|
photoSrc = src;
|
|
33555
33718
|
}
|
|
33556
33719
|
const config = generateConfig(values);
|
|
33557
|
-
const configPath =
|
|
33720
|
+
const configPath = path43.join(opts.stateDir, "configs", "main7.json");
|
|
33558
33721
|
const tree = buildDirTree(values);
|
|
33559
33722
|
if (headlessEmit) headlessEmit({ event: "progress", step: "write_config" });
|
|
33560
33723
|
tree.push({
|
|
@@ -33566,22 +33729,22 @@ WantedBy=default.target`;
|
|
|
33566
33729
|
dryRun(tree);
|
|
33567
33730
|
const skillsSrc = findTemplateDir("skills");
|
|
33568
33731
|
if (skillsSrc) {
|
|
33569
|
-
const skills =
|
|
33732
|
+
const skills = fs43.readdirSync(skillsSrc);
|
|
33570
33733
|
for (const s of skills) {
|
|
33571
|
-
console.log(` \u{1F4C1} ${
|
|
33734
|
+
console.log(` \u{1F4C1} ${path43.join(opts.stateDir, "workspace", "skills", s)}`);
|
|
33572
33735
|
}
|
|
33573
33736
|
}
|
|
33574
33737
|
} else {
|
|
33575
33738
|
if (values.chatMode === "auto") {
|
|
33576
33739
|
try {
|
|
33577
|
-
|
|
33740
|
+
fs43.unlinkSync(path43.join(opts.stateDir, "workspace", ".work-mode"));
|
|
33578
33741
|
} catch {
|
|
33579
33742
|
}
|
|
33580
33743
|
}
|
|
33581
33744
|
if (photoSrc && values.selfiePhotoRelPath) {
|
|
33582
|
-
const dest =
|
|
33583
|
-
|
|
33584
|
-
|
|
33745
|
+
const dest = path43.join(opts.stateDir, "workspace", values.selfiePhotoRelPath);
|
|
33746
|
+
fs43.mkdirSync(path43.dirname(dest), { recursive: true });
|
|
33747
|
+
fs43.copyFileSync(photoSrc, dest);
|
|
33585
33748
|
console.log(` \u{1F5BC} \u5F62\u8C61: ${dest}`);
|
|
33586
33749
|
}
|
|
33587
33750
|
if (headlessEmit) headlessEmit({ event: "progress", step: "create_dirs" });
|
|
@@ -33610,58 +33773,58 @@ WantedBy=default.target`;
|
|
|
33610
33773
|
if (headlessEmit) headlessEmit({ event: "progress", step: "copy_skills" });
|
|
33611
33774
|
const skillsSrc = findTemplateDir("skills");
|
|
33612
33775
|
if (skillsSrc) {
|
|
33613
|
-
const skillsDest =
|
|
33614
|
-
|
|
33615
|
-
const skills =
|
|
33776
|
+
const skillsDest = path43.join(opts.stateDir, "workspace", "skills");
|
|
33777
|
+
fs43.mkdirSync(skillsDest, { recursive: true });
|
|
33778
|
+
const skills = fs43.readdirSync(skillsSrc);
|
|
33616
33779
|
for (const s of skills) {
|
|
33617
|
-
copyDirRecursive(
|
|
33780
|
+
copyDirRecursive(path43.join(skillsSrc, s), path43.join(skillsDest, s));
|
|
33618
33781
|
console.log(` \u{1F4E6} skill: ${s}`);
|
|
33619
33782
|
}
|
|
33620
33783
|
}
|
|
33621
33784
|
console.log(`
|
|
33622
33785
|
\u2705 \u521D\u59CB\u5316\u5B8C\u6210\uFF01
|
|
33623
33786
|
`);
|
|
33624
|
-
const homePointer =
|
|
33787
|
+
const homePointer = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
|
|
33625
33788
|
const pointerData = { stateDir: opts.stateDir };
|
|
33626
|
-
|
|
33789
|
+
fs43.writeFileSync(homePointer, JSON.stringify(pointerData, null, 2) + "\n");
|
|
33627
33790
|
console.log(` \u{1F4C4} ${homePointer}\uFF08\u4ECE\u4EFB\u610F\u76EE\u5F55\u90FD\u80FD\u627E\u5230\u6B64 agent\uFF09`);
|
|
33628
33791
|
console.log(`\u4E0B\u4E00\u6B65\uFF1A`);
|
|
33629
33792
|
console.log(` 1. \u68C0\u67E5\u5E76\u4FEE\u6539 ${opts.stateDir}/configs/main7.json`);
|
|
33630
33793
|
console.log(` 2. \u542F\u52A8 Engine: engine7 start\uFF08\u5728\u4EFB\u610F\u76EE\u5F55\u90FD\u884C\uFF09`);
|
|
33631
33794
|
console.log(` 3. \u5F00\u673A\u81EA\u542F: engine7 service install\uFF08\u5728\u4EFB\u610F\u76EE\u5F55\u90FD\u884C\uFF09`);
|
|
33632
|
-
console.log(` 4. \u67E5\u770B workspace: ${
|
|
33795
|
+
console.log(` 4. \u67E5\u770B workspace: ${path43.join(opts.stateDir, "workspace")}`);
|
|
33633
33796
|
if (headlessEmit) {
|
|
33634
33797
|
headlessEmit({ event: "done", stateDir: opts.stateDir.replace(/\\/g, "/"), configPath: configPath.replace(/\\/g, "/") });
|
|
33635
33798
|
}
|
|
33636
33799
|
}
|
|
33637
33800
|
}
|
|
33638
33801
|
function copyDirRecursive(src, dest) {
|
|
33639
|
-
|
|
33640
|
-
for (const entry of
|
|
33641
|
-
const srcPath =
|
|
33642
|
-
const destPath =
|
|
33802
|
+
fs43.mkdirSync(dest, { recursive: true });
|
|
33803
|
+
for (const entry of fs43.readdirSync(src, { withFileTypes: true })) {
|
|
33804
|
+
const srcPath = path43.join(src, entry.name);
|
|
33805
|
+
const destPath = path43.join(dest, entry.name);
|
|
33643
33806
|
if (entry.isDirectory()) {
|
|
33644
33807
|
copyDirRecursive(srcPath, destPath);
|
|
33645
33808
|
} else {
|
|
33646
|
-
|
|
33809
|
+
fs43.copyFileSync(srcPath, destPath);
|
|
33647
33810
|
}
|
|
33648
33811
|
}
|
|
33649
33812
|
}
|
|
33650
33813
|
function findTemplateDir(name) {
|
|
33651
33814
|
const candidates = [
|
|
33652
|
-
|
|
33653
|
-
|
|
33654
|
-
|
|
33815
|
+
path43.join(__dirname, "..", "templates", name),
|
|
33816
|
+
path43.join(__dirname, "..", "..", "templates", name),
|
|
33817
|
+
path43.join(process.cwd(), "templates", name)
|
|
33655
33818
|
];
|
|
33656
33819
|
for (const p of candidates) {
|
|
33657
|
-
if (
|
|
33820
|
+
if (fs43.existsSync(p)) return p;
|
|
33658
33821
|
}
|
|
33659
33822
|
return null;
|
|
33660
33823
|
}
|
|
33661
33824
|
function readHomePointer() {
|
|
33662
|
-
const ptrPath =
|
|
33825
|
+
const ptrPath = path43.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
|
|
33663
33826
|
try {
|
|
33664
|
-
return JSON.parse(
|
|
33827
|
+
return JSON.parse(fs43.readFileSync(ptrPath, "utf-8"));
|
|
33665
33828
|
} catch {
|
|
33666
33829
|
return null;
|
|
33667
33830
|
}
|