engine7 7.1.40 → 7.1.41
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 +438 -255
- package/dist/engine-startup.mjs +2107 -1799
- package/dist/main.mjs +2106 -1798
- package/package.json +1 -1
- package/templates/config.template.json +2 -1
package/dist/cli.mjs
CHANGED
|
@@ -22,20 +22,20 @@ __export(cli_travel_exports, {
|
|
|
22
22
|
loadTravelConfig: () => loadTravelConfig,
|
|
23
23
|
saveTravelConfig: () => saveTravelConfig
|
|
24
24
|
});
|
|
25
|
-
import * as
|
|
26
|
-
import * as
|
|
27
|
-
import * as
|
|
25
|
+
import * as path2 from "node:path";
|
|
26
|
+
import * as fs2 from "node:fs";
|
|
27
|
+
import * as os2 from "node:os";
|
|
28
28
|
import { execSync } from "node:child_process";
|
|
29
29
|
function loadTravelConfig() {
|
|
30
30
|
try {
|
|
31
|
-
if (!
|
|
32
|
-
return JSON.parse(
|
|
31
|
+
if (!fs2.existsSync(CONFIG_PATH)) return null;
|
|
32
|
+
return JSON.parse(fs2.readFileSync(CONFIG_PATH, "utf-8"));
|
|
33
33
|
} catch {
|
|
34
34
|
return null;
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
function saveTravelConfig(cfg) {
|
|
38
|
-
|
|
38
|
+
fs2.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2));
|
|
39
39
|
}
|
|
40
40
|
function sanitizeContent(content, dirs) {
|
|
41
41
|
let result = content;
|
|
@@ -60,7 +60,7 @@ function restoreContent(content, dirs) {
|
|
|
60
60
|
return result;
|
|
61
61
|
}
|
|
62
62
|
function isTextFile(filePath) {
|
|
63
|
-
const ext =
|
|
63
|
+
const ext = path2.extname(filePath).toLowerCase();
|
|
64
64
|
return TEXT_EXTENSIONS.has(ext);
|
|
65
65
|
}
|
|
66
66
|
function shouldExclude(name) {
|
|
@@ -75,14 +75,14 @@ function shouldExclude(name) {
|
|
|
75
75
|
}
|
|
76
76
|
function collectFiles(rootDir, includeSet, optionalSet) {
|
|
77
77
|
const files = [];
|
|
78
|
-
const entries =
|
|
78
|
+
const entries = fs2.readdirSync(rootDir, { withFileTypes: true });
|
|
79
79
|
for (const entry of entries) {
|
|
80
80
|
if (shouldExclude(entry.name)) continue;
|
|
81
|
-
const fullPath =
|
|
82
|
-
const realPath =
|
|
81
|
+
const fullPath = path2.join(rootDir, entry.name);
|
|
82
|
+
const realPath = fs2.realpathSync(fullPath);
|
|
83
83
|
if (realPath !== fullPath) {
|
|
84
84
|
try {
|
|
85
|
-
const lstat =
|
|
85
|
+
const lstat = fs2.lstatSync(fullPath);
|
|
86
86
|
if (lstat.isSymbolicLink()) {
|
|
87
87
|
continue;
|
|
88
88
|
}
|
|
@@ -103,12 +103,12 @@ function collectFiles(rootDir, includeSet, optionalSet) {
|
|
|
103
103
|
function collectAllFiles(dir) {
|
|
104
104
|
const files = [];
|
|
105
105
|
try {
|
|
106
|
-
const entries =
|
|
106
|
+
const entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
107
107
|
for (const entry of entries) {
|
|
108
108
|
if (shouldExclude(entry.name)) continue;
|
|
109
|
-
const fullPath =
|
|
109
|
+
const fullPath = path2.join(dir, entry.name);
|
|
110
110
|
try {
|
|
111
|
-
if (
|
|
111
|
+
if (fs2.lstatSync(fullPath).isSymbolicLink()) continue;
|
|
112
112
|
} catch {
|
|
113
113
|
}
|
|
114
114
|
if (entry.isDirectory()) {
|
|
@@ -123,30 +123,30 @@ function collectAllFiles(dir) {
|
|
|
123
123
|
}
|
|
124
124
|
function readMainEngineUuid(agentsDir) {
|
|
125
125
|
try {
|
|
126
|
-
const platformMapPath =
|
|
127
|
-
const indexMapPath =
|
|
128
|
-
if (!
|
|
129
|
-
const platformMap = JSON.parse(
|
|
126
|
+
const platformMapPath = path2.join(agentsDir, "main", "sessions", "platform-map.json");
|
|
127
|
+
const indexMapPath = path2.join(agentsDir, "main", "sessions", "session-index.json");
|
|
128
|
+
if (!fs2.existsSync(platformMapPath) || !fs2.existsSync(indexMapPath)) return null;
|
|
129
|
+
const platformMap = JSON.parse(fs2.readFileSync(platformMapPath, "utf-8"));
|
|
130
130
|
const mainPlatformId = platformMap["scope:main"] || platformMap["main"];
|
|
131
131
|
if (!mainPlatformId) return null;
|
|
132
|
-
const indexMap = JSON.parse(
|
|
132
|
+
const indexMap = JSON.parse(fs2.readFileSync(indexMapPath, "utf-8"));
|
|
133
133
|
const entry = indexMap[mainPlatformId];
|
|
134
134
|
if (!entry || !entry.file) return null;
|
|
135
|
-
const
|
|
136
|
-
return
|
|
135
|
+
const basename4 = path2.basename(entry.file).replace(/\.jsonl$/, "");
|
|
136
|
+
return basename4;
|
|
137
137
|
} catch {
|
|
138
138
|
return null;
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
function collectRecentSessions(agentsDir, _days = 7) {
|
|
142
142
|
const files = [];
|
|
143
|
-
if (!
|
|
143
|
+
if (!fs2.existsSync(agentsDir)) return files;
|
|
144
144
|
const sessionGroups = /* @__PURE__ */ new Map();
|
|
145
145
|
function scanSessionsDir(dir) {
|
|
146
146
|
try {
|
|
147
|
-
const entries =
|
|
147
|
+
const entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
148
148
|
for (const entry of entries) {
|
|
149
|
-
const fullPath =
|
|
149
|
+
const fullPath = path2.join(dir, entry.name);
|
|
150
150
|
if (entry.isDirectory()) {
|
|
151
151
|
scanSessionsDir(fullPath);
|
|
152
152
|
continue;
|
|
@@ -170,7 +170,7 @@ function collectRecentSessions(agentsDir, _days = 7) {
|
|
|
170
170
|
if (entry.name.endsWith(".jsonl")) {
|
|
171
171
|
group.jsonl = fullPath;
|
|
172
172
|
} else {
|
|
173
|
-
const stat =
|
|
173
|
+
const stat = fs2.statSync(fullPath);
|
|
174
174
|
group.archived.push({ file: fullPath, mtime: stat.mtimeMs });
|
|
175
175
|
}
|
|
176
176
|
}
|
|
@@ -189,37 +189,37 @@ function collectRecentSessions(agentsDir, _days = 7) {
|
|
|
189
189
|
}
|
|
190
190
|
async function doExport(opts) {
|
|
191
191
|
const { agentName, stateDir, note, dryRun: dryRun2 } = opts;
|
|
192
|
-
const workspace = (opts.workspace ||
|
|
193
|
-
const engineHome =
|
|
192
|
+
const workspace = (opts.workspace || path2.join(stateDir, "workspace")).replace(/[/\\]+$/, "");
|
|
193
|
+
const engineHome = path2.join(os2.homedir(), ".engine7").replace(/[/\\]+$/, "");
|
|
194
194
|
console.log(`\u{1F4E6} engine7 export`);
|
|
195
195
|
console.log(` agent: ${agentName}`);
|
|
196
196
|
console.log(` state: ${stateDir}`);
|
|
197
197
|
console.log(` workspace: ${workspace}`);
|
|
198
|
-
if (!
|
|
198
|
+
if (!fs2.existsSync(workspace)) {
|
|
199
199
|
console.error(`\u274C workspace \u4E0D\u5B58\u5728: ${workspace}`);
|
|
200
200
|
process.exit(1);
|
|
201
201
|
}
|
|
202
202
|
const dirs = { workspace, stateDir, engineHome };
|
|
203
203
|
const wsFiles = collectFiles(workspace, WORKSPACE_INCLUDE, WORKSPACE_OPTIONAL);
|
|
204
|
-
const sessionFiles = collectRecentSessions(
|
|
205
|
-
const configsDir =
|
|
204
|
+
const sessionFiles = collectRecentSessions(path2.join(stateDir, "agents"), 7);
|
|
205
|
+
const configsDir = path2.join(stateDir, "configs");
|
|
206
206
|
const configFiles = [];
|
|
207
|
-
if (
|
|
207
|
+
if (fs2.existsSync(configsDir)) {
|
|
208
208
|
for (const f of collectAllFiles(configsDir)) {
|
|
209
|
-
if (shouldExclude(
|
|
209
|
+
if (shouldExclude(path2.basename(f))) continue;
|
|
210
210
|
configFiles.push(f);
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
213
|
const EVEROS_SKIP = /* @__PURE__ */ new Set([".tmp", ".lock", "import.log", "import_progress.json"]);
|
|
214
|
-
const everosDir =
|
|
214
|
+
const everosDir = path2.join(stateDir, ".everos");
|
|
215
215
|
const everosFiles = [];
|
|
216
|
-
if (
|
|
216
|
+
if (fs2.existsSync(everosDir)) {
|
|
217
217
|
for (const f of collectAllFiles(everosDir)) {
|
|
218
|
-
if (EVEROS_SKIP.has(
|
|
218
|
+
if (EVEROS_SKIP.has(path2.basename(f))) continue;
|
|
219
219
|
everosFiles.push(f);
|
|
220
220
|
}
|
|
221
|
-
const walFile =
|
|
222
|
-
if (
|
|
221
|
+
const walFile = path2.join(everosDir, ".index", "sqlite", "system.db-wal");
|
|
222
|
+
if (fs2.existsSync(walFile) && fs2.statSync(walFile).size > 0) {
|
|
223
223
|
console.warn(`\u26A0\uFE0F .everos/system.db-wal \u975E\u7A7A\u2014\u2014everos \u670D\u52A1\u53EF\u80FD\u6B63\u5728\u5199\u5165\uFF0C\u5FEB\u7167\u53EF\u80FD\u4E0D\u4E00\u81F4`);
|
|
224
224
|
console.warn(` \u5EFA\u8BAE: \u5148\u505C everos \u670D\u52A1\u518D export\uFF0C\u6216 import \u540E\u91CD\u5EFA\u7D22\u5F15`);
|
|
225
225
|
}
|
|
@@ -227,16 +227,16 @@ async function doExport(opts) {
|
|
|
227
227
|
console.log(` workspace \u6587\u4EF6: ${wsFiles.length}`);
|
|
228
228
|
console.log(` session jsonl: ${sessionFiles.length} (\u6700\u8FD17\u5929)`);
|
|
229
229
|
console.log(` configs: ${configFiles.length}`);
|
|
230
|
-
console.log(` everos: ${everosFiles.length} (${(everosFiles.reduce((s, f) => s +
|
|
230
|
+
console.log(` everos: ${everosFiles.length} (${(everosFiles.reduce((s, f) => s + fs2.statSync(f).size, 0) / 1024 / 1024).toFixed(1)} MB)`);
|
|
231
231
|
if (dryRun2) {
|
|
232
232
|
console.log(`
|
|
233
233
|
[DRY RUN] \u4F1A\u6253\u5305\u4EE5\u4E0B\u6587\u4EF6:`);
|
|
234
|
-
wsFiles.slice(0, 20).forEach((f) => console.log(` ${
|
|
234
|
+
wsFiles.slice(0, 20).forEach((f) => console.log(` ${path2.relative(workspace, f)}`));
|
|
235
235
|
if (wsFiles.length > 20) console.log(` ... \u8FD8\u6709 ${wsFiles.length - 20} \u4E2A\u6587\u4EF6`);
|
|
236
236
|
if (everosFiles.length > 0) {
|
|
237
237
|
console.log(`
|
|
238
238
|
[DRY RUN] everos (${everosFiles.length} \u6587\u4EF6):`);
|
|
239
|
-
everosFiles.slice(0, 10).forEach((f) => console.log(` ${
|
|
239
|
+
everosFiles.slice(0, 10).forEach((f) => console.log(` ${path2.relative(stateDir, f)}`));
|
|
240
240
|
if (everosFiles.length > 10) console.log(` ... \u8FD8\u6709 ${everosFiles.length - 10} \u4E2A\u6587\u4EF6`);
|
|
241
241
|
}
|
|
242
242
|
console.log(`
|
|
@@ -245,46 +245,46 @@ async function doExport(opts) {
|
|
|
245
245
|
}
|
|
246
246
|
const now = /* @__PURE__ */ new Date();
|
|
247
247
|
const version = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, "0")}${String(now.getDate()).padStart(2, "0")}-${String(now.getHours()).padStart(2, "0")}${String(now.getMinutes()).padStart(2, "0")}`;
|
|
248
|
-
const tmpDir =
|
|
249
|
-
|
|
250
|
-
const stagingDir =
|
|
251
|
-
|
|
248
|
+
const tmpDir = path2.join(os2.tmpdir(), `engine7-export-${agentName}-${version}`);
|
|
249
|
+
fs2.mkdirSync(tmpDir, { recursive: true });
|
|
250
|
+
const stagingDir = path2.join(tmpDir, agentName);
|
|
251
|
+
fs2.mkdirSync(stagingDir, { recursive: true });
|
|
252
252
|
let fileCount = 0;
|
|
253
253
|
let totalSize = 0;
|
|
254
254
|
let copyFail = 0;
|
|
255
255
|
const copyOne = (srcFile, relRoot, destRoot) => {
|
|
256
|
-
const relPath =
|
|
257
|
-
const destFile =
|
|
258
|
-
|
|
256
|
+
const relPath = path2.relative(relRoot, srcFile);
|
|
257
|
+
const destFile = path2.join(destRoot, relPath);
|
|
258
|
+
fs2.mkdirSync(path2.dirname(destFile), { recursive: true });
|
|
259
259
|
try {
|
|
260
260
|
if (isTextFile(srcFile)) {
|
|
261
|
-
const content =
|
|
262
|
-
|
|
261
|
+
const content = fs2.readFileSync(srcFile, "utf-8");
|
|
262
|
+
fs2.writeFileSync(destFile, sanitizeContent(content, dirs));
|
|
263
263
|
} else {
|
|
264
|
-
|
|
264
|
+
fs2.copyFileSync(srcFile, destFile);
|
|
265
265
|
}
|
|
266
266
|
fileCount++;
|
|
267
|
-
totalSize +=
|
|
267
|
+
totalSize += fs2.statSync(srcFile).size;
|
|
268
268
|
} catch (e) {
|
|
269
269
|
copyFail++;
|
|
270
270
|
console.warn(` \u26A0\uFE0F \u62F7\u8D1D\u5931\u8D25: ${relPath} (${e.code || e.message})`);
|
|
271
271
|
}
|
|
272
272
|
};
|
|
273
|
-
for (const srcFile of wsFiles) copyOne(srcFile, workspace,
|
|
273
|
+
for (const srcFile of wsFiles) copyOne(srcFile, workspace, path2.join(stagingDir, "workspace"));
|
|
274
274
|
for (const srcFile of sessionFiles) {
|
|
275
|
-
const relPath =
|
|
276
|
-
const destFile =
|
|
277
|
-
|
|
275
|
+
const relPath = path2.relative(stateDir, srcFile);
|
|
276
|
+
const destFile = path2.join(stagingDir, relPath);
|
|
277
|
+
fs2.mkdirSync(path2.dirname(destFile), { recursive: true });
|
|
278
278
|
try {
|
|
279
|
-
let content =
|
|
279
|
+
let content = fs2.readFileSync(srcFile, "utf-8");
|
|
280
280
|
content = sanitizeContent(content, dirs);
|
|
281
|
-
const baseName =
|
|
281
|
+
const baseName = path2.basename(srcFile);
|
|
282
282
|
if (baseName === "session-index.json" || baseName === "platform-map.json") {
|
|
283
283
|
content = content.split("\\\\").join("/");
|
|
284
284
|
}
|
|
285
|
-
|
|
285
|
+
fs2.writeFileSync(destFile, content);
|
|
286
286
|
fileCount++;
|
|
287
|
-
totalSize +=
|
|
287
|
+
totalSize += fs2.statSync(srcFile).size;
|
|
288
288
|
} catch (e) {
|
|
289
289
|
copyFail++;
|
|
290
290
|
console.warn(` \u26A0\uFE0F \u62F7\u8D1D\u5931\u8D25: ${relPath} (${e.code || e.message})`);
|
|
@@ -306,13 +306,13 @@ async function doExport(opts) {
|
|
|
306
306
|
totalSize,
|
|
307
307
|
note
|
|
308
308
|
};
|
|
309
|
-
|
|
310
|
-
const archiveFile =
|
|
309
|
+
fs2.writeFileSync(path2.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
310
|
+
const archiveFile = path2.join(tmpDir, `${agentName}-${version}.tar.gz`);
|
|
311
311
|
console.log(`
|
|
312
312
|
\u{1F5DC}\uFE0F \u6253\u5305\u4E2D...`);
|
|
313
313
|
const tarExe = process.platform === "win32" ? "C:\\Windows\\System32\\tar.exe" : "tar";
|
|
314
314
|
execSync(`"${tarExe}" -czf "${archiveFile}" -C "${tmpDir}" ${agentName}`, { stdio: "pipe" });
|
|
315
|
-
const archiveSize =
|
|
315
|
+
const archiveSize = fs2.statSync(archiveFile).size;
|
|
316
316
|
console.log(`\u2705 \u6253\u5305\u5B8C\u6210: ${archiveFile} (${(archiveSize / 1024 / 1024).toFixed(1)} MB, ${fileCount} \u6587\u4EF6${copyFail ? `, \u5931\u8D25 ${copyFail}` : ""})`);
|
|
317
317
|
const cfg = loadTravelConfig();
|
|
318
318
|
if (!cfg || !cfg.githubToken) {
|
|
@@ -335,8 +335,8 @@ async function doImport(opts) {
|
|
|
335
335
|
console.error(` \u914D\u7F6E: \u7F16\u8F91 ${CONFIG_PATH}`);
|
|
336
336
|
process.exit(1);
|
|
337
337
|
}
|
|
338
|
-
const tmpDir =
|
|
339
|
-
|
|
338
|
+
const tmpDir = path2.join(os2.tmpdir(), `engine7-import-${agentName}-${Date.now()}`);
|
|
339
|
+
fs2.mkdirSync(tmpDir, { recursive: true });
|
|
340
340
|
const archiveFile = await downloadFromGitHub(cfg, agentName, version, tmpDir);
|
|
341
341
|
console.log(`\u2705 \u4E0B\u8F7D\u5B8C\u6210: ${archiveFile}`);
|
|
342
342
|
if (dryRun2) {
|
|
@@ -347,99 +347,99 @@ async function doImport(opts) {
|
|
|
347
347
|
console.log(`\u{1F4C2} \u89E3\u5305\u4E2D...`);
|
|
348
348
|
const tarExe = process.platform === "win32" ? "C:\\Windows\\System32\\tar.exe" : "tar";
|
|
349
349
|
execSync(`"${tarExe}" -xzf "${archiveFile}" -C "${tmpDir}"`, { stdio: "pipe" });
|
|
350
|
-
const stagingDir =
|
|
351
|
-
const manifestPath =
|
|
352
|
-
if (!
|
|
350
|
+
const stagingDir = path2.join(tmpDir, agentName);
|
|
351
|
+
const manifestPath = path2.join(stagingDir, "manifest.json");
|
|
352
|
+
if (!fs2.existsSync(manifestPath)) {
|
|
353
353
|
console.error(`\u274C manifest.json \u4E0D\u5B58\u5728\uFF0C\u6587\u4EF6\u53EF\u80FD\u635F\u574F`);
|
|
354
354
|
process.exit(1);
|
|
355
355
|
}
|
|
356
|
-
const manifest = JSON.parse(
|
|
357
|
-
const workspace =
|
|
358
|
-
const engineHome =
|
|
356
|
+
const manifest = JSON.parse(fs2.readFileSync(manifestPath, "utf-8"));
|
|
357
|
+
const workspace = path2.join(stateDir, "workspace").replace(/\\/g, "/").replace(/[/\\]+$/, "");
|
|
358
|
+
const engineHome = path2.join(os2.homedir(), ".engine7").replace(/\\/g, "/").replace(/[/\\]+$/, "");
|
|
359
359
|
const dirs = { workspace, stateDir: stateDir.replace(/\\/g, "/").replace(/[/\\]+$/, ""), engineHome };
|
|
360
360
|
console.log(` \u7248\u672C: ${manifest.version}`);
|
|
361
361
|
console.log(` \u521B\u5EFA: ${manifest.createdAt}`);
|
|
362
362
|
console.log(` \u6587\u4EF6\u6570: ${manifest.fileCount}`);
|
|
363
|
-
const wsStaging =
|
|
363
|
+
const wsStaging = path2.join(stagingDir, "workspace");
|
|
364
364
|
let restoredCount = 0;
|
|
365
365
|
let skipCount = 0;
|
|
366
|
-
if (
|
|
366
|
+
if (fs2.existsSync(wsStaging)) {
|
|
367
367
|
const allFiles = collectAllFiles(wsStaging);
|
|
368
368
|
for (const srcFile of allFiles) {
|
|
369
|
-
const relPath =
|
|
370
|
-
const destFile =
|
|
371
|
-
|
|
369
|
+
const relPath = path2.relative(wsStaging, srcFile);
|
|
370
|
+
const destFile = path2.join(workspace, relPath);
|
|
371
|
+
fs2.mkdirSync(path2.dirname(destFile), { recursive: true });
|
|
372
372
|
try {
|
|
373
373
|
if (isTextFile(srcFile)) {
|
|
374
|
-
const content =
|
|
375
|
-
|
|
374
|
+
const content = fs2.readFileSync(srcFile, "utf-8");
|
|
375
|
+
fs2.writeFileSync(destFile, restoreContent(content, dirs));
|
|
376
376
|
} else {
|
|
377
|
-
|
|
377
|
+
fs2.copyFileSync(srcFile, destFile);
|
|
378
378
|
}
|
|
379
379
|
restoredCount++;
|
|
380
380
|
} catch (e) {
|
|
381
381
|
skipCount++;
|
|
382
|
-
console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${
|
|
382
|
+
console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${path2.relative(wsStaging, srcFile)} (${e.code || e.message})`);
|
|
383
383
|
}
|
|
384
384
|
}
|
|
385
385
|
}
|
|
386
|
-
const agentsStaging =
|
|
387
|
-
if (
|
|
386
|
+
const agentsStaging = path2.join(stagingDir, "agents");
|
|
387
|
+
if (fs2.existsSync(agentsStaging)) {
|
|
388
388
|
const sessionFiles = collectAllFiles(agentsStaging);
|
|
389
389
|
for (const srcFile of sessionFiles) {
|
|
390
|
-
const relPath =
|
|
391
|
-
const destFile =
|
|
392
|
-
|
|
393
|
-
const content =
|
|
394
|
-
|
|
390
|
+
const relPath = path2.relative(stagingDir, srcFile);
|
|
391
|
+
const destFile = path2.join(stateDir, relPath);
|
|
392
|
+
fs2.mkdirSync(path2.dirname(destFile), { recursive: true });
|
|
393
|
+
const content = fs2.readFileSync(srcFile, "utf-8");
|
|
394
|
+
fs2.writeFileSync(destFile, restoreContent(content, dirs));
|
|
395
395
|
restoredCount++;
|
|
396
396
|
}
|
|
397
397
|
}
|
|
398
|
-
const configsStaging =
|
|
399
|
-
if (
|
|
398
|
+
const configsStaging = path2.join(stagingDir, "configs");
|
|
399
|
+
if (fs2.existsSync(configsStaging)) {
|
|
400
400
|
const cfgFiles = collectAllFiles(configsStaging);
|
|
401
401
|
for (const srcFile of cfgFiles) {
|
|
402
|
-
const relPath =
|
|
403
|
-
const destFile =
|
|
404
|
-
|
|
402
|
+
const relPath = path2.relative(stagingDir, srcFile);
|
|
403
|
+
const destFile = path2.join(stateDir, relPath);
|
|
404
|
+
fs2.mkdirSync(path2.dirname(destFile), { recursive: true });
|
|
405
405
|
if (isTextFile(srcFile)) {
|
|
406
|
-
const content =
|
|
407
|
-
|
|
406
|
+
const content = fs2.readFileSync(srcFile, "utf-8");
|
|
407
|
+
fs2.writeFileSync(destFile, restoreContent(content, dirs));
|
|
408
408
|
} else {
|
|
409
|
-
|
|
409
|
+
fs2.copyFileSync(srcFile, destFile);
|
|
410
410
|
}
|
|
411
411
|
restoredCount++;
|
|
412
412
|
}
|
|
413
413
|
}
|
|
414
|
-
const everosStaging =
|
|
415
|
-
if (
|
|
414
|
+
const everosStaging = path2.join(stagingDir, ".everos");
|
|
415
|
+
if (fs2.existsSync(everosStaging)) {
|
|
416
416
|
const everosFiles = collectAllFiles(everosStaging);
|
|
417
417
|
for (const srcFile of everosFiles) {
|
|
418
|
-
const relPath =
|
|
419
|
-
const destFile =
|
|
420
|
-
|
|
418
|
+
const relPath = path2.relative(stagingDir, srcFile);
|
|
419
|
+
const destFile = path2.join(stateDir, relPath);
|
|
420
|
+
fs2.mkdirSync(path2.dirname(destFile), { recursive: true });
|
|
421
421
|
try {
|
|
422
422
|
if (isTextFile(srcFile)) {
|
|
423
|
-
const content =
|
|
424
|
-
|
|
423
|
+
const content = fs2.readFileSync(srcFile, "utf-8");
|
|
424
|
+
fs2.writeFileSync(destFile, restoreContent(content, dirs));
|
|
425
425
|
} else {
|
|
426
|
-
|
|
426
|
+
fs2.copyFileSync(srcFile, destFile);
|
|
427
427
|
}
|
|
428
428
|
restoredCount++;
|
|
429
429
|
} catch (e) {
|
|
430
430
|
skipCount++;
|
|
431
|
-
console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${
|
|
431
|
+
console.log(` \u26A0\uFE0F \u8DF3\u8FC7: ${path2.relative(everosStaging, srcFile)} (${e.code || e.message})`);
|
|
432
432
|
}
|
|
433
433
|
}
|
|
434
434
|
console.log(` everos: ${everosFiles.length} \u6587\u4EF6\u5DF2\u6062\u590D`);
|
|
435
435
|
}
|
|
436
436
|
console.log(`\u2705 \u6062\u590D\u5B8C\u6210: ${restoredCount} \u6587\u4EF6 \u2192 ${stateDir}${skipCount ? ` (\u8DF3\u8FC7 ${skipCount})` : ""}`);
|
|
437
437
|
const platformConfigName = process.platform === "darwin" ? "xiaoke-mac.json" : "xiaoke-win.json";
|
|
438
|
-
const restoredConfigPath =
|
|
439
|
-
const configToUse =
|
|
438
|
+
const restoredConfigPath = path2.join(stateDir, "configs", platformConfigName);
|
|
439
|
+
const configToUse = fs2.existsSync(restoredConfigPath) ? restoredConfigPath : path2.join(stateDir, "configs", "xiaoke.json");
|
|
440
440
|
console.log(`
|
|
441
441
|
\u{1F4A1} \u4E0B\u4E00\u6B65: engine7 start --config "${configToUse}"`);
|
|
442
|
-
|
|
442
|
+
fs2.rmSync(tmpDir, { recursive: true, force: true });
|
|
443
443
|
}
|
|
444
444
|
async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
|
|
445
445
|
const repo = `${cfg.githubOwner}/${cfg.repoName}`;
|
|
@@ -469,8 +469,8 @@ async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
|
|
|
469
469
|
}
|
|
470
470
|
const release = await createRes.json();
|
|
471
471
|
const uploadUrl = release.upload_url.replace("{?name,label}", "");
|
|
472
|
-
const fileBuffer =
|
|
473
|
-
const fileName =
|
|
472
|
+
const fileBuffer = fs2.readFileSync(archiveFile);
|
|
473
|
+
const fileName = path2.basename(archiveFile);
|
|
474
474
|
const uploadRes = await fetch(`${uploadUrl}?name=${fileName}`, {
|
|
475
475
|
method: "POST",
|
|
476
476
|
headers: {
|
|
@@ -493,7 +493,7 @@ async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
|
|
|
493
493
|
throw e;
|
|
494
494
|
}
|
|
495
495
|
try {
|
|
496
|
-
|
|
496
|
+
fs2.rmSync(path2.dirname(archiveFile), { recursive: true, force: true });
|
|
497
497
|
} catch {
|
|
498
498
|
}
|
|
499
499
|
}
|
|
@@ -525,8 +525,8 @@ async function downloadFromGitHub(cfg, agentName, version, destDir) {
|
|
|
525
525
|
throw new Error(`\u4E0B\u8F7D asset \u5931\u8D25: ${downloadRes.status}`);
|
|
526
526
|
}
|
|
527
527
|
const buffer = Buffer.from(await downloadRes.arrayBuffer());
|
|
528
|
-
const archiveFile =
|
|
529
|
-
|
|
528
|
+
const archiveFile = path2.join(destDir, asset.name);
|
|
529
|
+
fs2.writeFileSync(archiveFile, buffer);
|
|
530
530
|
return archiveFile;
|
|
531
531
|
}
|
|
532
532
|
async function getLatestReleaseTag(cfg, agentName) {
|
|
@@ -551,7 +551,7 @@ var CONFIG_PATH, PATH_PLACEHOLDERS, WORKSPACE_INCLUDE, WORKSPACE_OPTIONAL, WORKS
|
|
|
551
551
|
var init_cli_travel = __esm({
|
|
552
552
|
"src/cli-travel.ts"() {
|
|
553
553
|
"use strict";
|
|
554
|
-
CONFIG_PATH =
|
|
554
|
+
CONFIG_PATH = path2.join(os2.homedir(), ".engine7-travel.json");
|
|
555
555
|
PATH_PLACEHOLDERS = [
|
|
556
556
|
{ placeholder: "{{WORKSPACE}}", getOriginal: (d) => d.workspace },
|
|
557
557
|
{ placeholder: "{{ENGINE_HOME}}", getOriginal: (d) => d.engineHome },
|
|
@@ -624,8 +624,8 @@ var init_cli_travel = __esm({
|
|
|
624
624
|
});
|
|
625
625
|
|
|
626
626
|
// src/cli-init.ts
|
|
627
|
-
import * as
|
|
628
|
-
import * as
|
|
627
|
+
import * as path3 from "node:path";
|
|
628
|
+
import * as fs3 from "node:fs";
|
|
629
629
|
import * as readline from "node:readline";
|
|
630
630
|
import { fileURLToPath } from "node:url";
|
|
631
631
|
|
|
@@ -743,6 +743,128 @@ function sleep(ms) {
|
|
|
743
743
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
744
744
|
}
|
|
745
745
|
|
|
746
|
+
// src/channels/wechat.ts
|
|
747
|
+
import * as fs from "fs";
|
|
748
|
+
import * as path from "path";
|
|
749
|
+
import * as os from "os";
|
|
750
|
+
function sleep2(ms) {
|
|
751
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
752
|
+
}
|
|
753
|
+
var ILINK_BASE_URL = "https://ilinkai.weixin.qq.com";
|
|
754
|
+
var ILINK_APP_CLIENT_VERSION = 2 << 16 | 2 << 8 | 0;
|
|
755
|
+
var EP_GET_BOT_QR = "ilink/bot/get_bot_qrcode";
|
|
756
|
+
var EP_GET_QR_STATUS = "ilink/bot/get_qrcode_status";
|
|
757
|
+
var QR_TIMEOUT_MS = 15e3;
|
|
758
|
+
async function wechatQrLogin(options) {
|
|
759
|
+
const botType = options?.botType || "3";
|
|
760
|
+
const timeoutSeconds = options?.timeoutSeconds || 480;
|
|
761
|
+
const stateDir = options?.stateDir || path.join(os.homedir?.() || "/tmp", ".engine7");
|
|
762
|
+
console.log("[wechat] Fetching QR code from iLink...");
|
|
763
|
+
let qrResp;
|
|
764
|
+
try {
|
|
765
|
+
qrResp = await apiGet(ILINK_BASE_URL, `${EP_GET_BOT_QR}?bot_type=${botType}`, "", QR_TIMEOUT_MS);
|
|
766
|
+
} catch (err) {
|
|
767
|
+
console.error(`[wechat] Failed to fetch QR code: ${err.message}`);
|
|
768
|
+
return null;
|
|
769
|
+
}
|
|
770
|
+
const qrcodeValue = String(qrResp?.qrcode || "");
|
|
771
|
+
const qrcodeUrl = String(qrResp?.qrcode_img_content || "");
|
|
772
|
+
if (!qrcodeValue) {
|
|
773
|
+
console.error("[wechat] QR response missing qrcode field");
|
|
774
|
+
return null;
|
|
775
|
+
}
|
|
776
|
+
const qrScanData = qrcodeUrl || qrcodeValue;
|
|
777
|
+
console.log("\n========== \u5FAE\u4FE1\u626B\u7801\u767B\u5F55 ==========");
|
|
778
|
+
if (qrcodeUrl) {
|
|
779
|
+
console.log(`\u626B\u7801\u94FE\u63A5: ${qrcodeUrl}`);
|
|
780
|
+
}
|
|
781
|
+
console.log("\u8BF7\u7528\u5FAE\u4FE1\u626B\u63CF\u4E8C\u7EF4\u7801\uFF08\u6216\u6253\u5F00\u4E0A\u9762\u7684\u94FE\u63A5\uFF09:");
|
|
782
|
+
console.log("===================================\n");
|
|
783
|
+
const deadline = Date.now() + timeoutSeconds * 1e3;
|
|
784
|
+
let currentBaseUrl = ILINK_BASE_URL;
|
|
785
|
+
let refreshCount = 0;
|
|
786
|
+
while (Date.now() < deadline) {
|
|
787
|
+
let statusResp;
|
|
788
|
+
try {
|
|
789
|
+
statusResp = await apiGet(currentBaseUrl, `${EP_GET_QR_STATUS}?qrcode=${qrcodeValue}`, "", QR_TIMEOUT_MS);
|
|
790
|
+
} catch {
|
|
791
|
+
await sleep2(1e3);
|
|
792
|
+
continue;
|
|
793
|
+
}
|
|
794
|
+
const status = String(statusResp?.status || "wait");
|
|
795
|
+
if (status === "wait") {
|
|
796
|
+
process.stdout.write(".");
|
|
797
|
+
} else if (status === "scaned") {
|
|
798
|
+
console.log("\n\u5DF2\u626B\u7801\uFF0C\u8BF7\u5728\u5FAE\u4FE1\u91CC\u786E\u8BA4...");
|
|
799
|
+
} else if (status === "scaned_but_redirect") {
|
|
800
|
+
const redirectHost = String(statusResp?.redirect_host || "");
|
|
801
|
+
if (redirectHost) currentBaseUrl = `https://${redirectHost}`;
|
|
802
|
+
} else if (status === "expired") {
|
|
803
|
+
refreshCount++;
|
|
804
|
+
if (refreshCount > 3) {
|
|
805
|
+
console.log("\n\u4E8C\u7EF4\u7801\u591A\u6B21\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C\u767B\u5F55\u3002");
|
|
806
|
+
return null;
|
|
807
|
+
}
|
|
808
|
+
console.log(`
|
|
809
|
+
\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\uFF0C\u5237\u65B0\u4E2D... (${refreshCount}/3)`);
|
|
810
|
+
try {
|
|
811
|
+
qrResp = await apiGet(ILINK_BASE_URL, `${EP_GET_BOT_QR}?bot_type=${botType}`, "", QR_TIMEOUT_MS);
|
|
812
|
+
const newQrValue = String(qrResp?.qrcode || "");
|
|
813
|
+
const newQrUrl = String(qrResp?.qrcode_img_content || "");
|
|
814
|
+
if (newQrUrl) console.log(`\u65B0\u626B\u7801\u94FE\u63A5: ${newQrUrl}`);
|
|
815
|
+
} catch (err) {
|
|
816
|
+
console.error(`[wechat] QR refresh failed: ${err.message}`);
|
|
817
|
+
return null;
|
|
818
|
+
}
|
|
819
|
+
} else if (status === "confirmed") {
|
|
820
|
+
const accountId = String(statusResp?.ilink_bot_id || "");
|
|
821
|
+
const token = String(statusResp?.bot_token || "");
|
|
822
|
+
const baseUrl = String(statusResp?.baseurl || ILINK_BASE_URL);
|
|
823
|
+
const userId = String(statusResp?.ilink_user_id || "");
|
|
824
|
+
if (!accountId || !token) {
|
|
825
|
+
console.error("[wechat] QR confirmed but credential payload incomplete");
|
|
826
|
+
return null;
|
|
827
|
+
}
|
|
828
|
+
if (!fs.existsSync(stateDir)) fs.mkdirSync(stateDir, { recursive: true });
|
|
829
|
+
const credFile = path.join(stateDir, `weixin-${accountId}.json`);
|
|
830
|
+
fs.writeFileSync(credFile, JSON.stringify({ accountId, token, baseUrl, userId }, null, 2), "utf8");
|
|
831
|
+
console.log(`
|
|
832
|
+
\u2705 \u5FAE\u4FE1\u767B\u5F55\u6210\u529F!`);
|
|
833
|
+
console.log(` accountId: ${accountId}`);
|
|
834
|
+
console.log(` \u51ED\u8BC1\u5DF2\u4FDD\u5B58: ${credFile}`);
|
|
835
|
+
console.log(`
|
|
836
|
+
\u8BF7\u5C06\u4EE5\u4E0B\u914D\u7F6E\u6DFB\u52A0\u5230 xiaoke.json:`);
|
|
837
|
+
console.log(JSON.stringify({
|
|
838
|
+
wechat: {
|
|
839
|
+
token,
|
|
840
|
+
accountId,
|
|
841
|
+
baseUrl: baseUrl !== ILINK_BASE_URL ? baseUrl : void 0
|
|
842
|
+
}
|
|
843
|
+
}, null, 2));
|
|
844
|
+
return { accountId, token, baseUrl, userId };
|
|
845
|
+
}
|
|
846
|
+
await sleep2(1e3);
|
|
847
|
+
}
|
|
848
|
+
console.log("\n[wechat] QR login timed out");
|
|
849
|
+
return null;
|
|
850
|
+
}
|
|
851
|
+
async function apiGet(baseUrl, endpoint, _token, timeoutMs) {
|
|
852
|
+
const url = `${baseUrl.replace(/\/$/, "")}/${endpoint.replace(/^\//, "")}`;
|
|
853
|
+
const controller = new AbortController();
|
|
854
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
855
|
+
try {
|
|
856
|
+
const resp = await fetch(url, {
|
|
857
|
+
method: "GET",
|
|
858
|
+
signal: controller.signal,
|
|
859
|
+
headers: { "Accept": "application/json" }
|
|
860
|
+
});
|
|
861
|
+
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
|
862
|
+
return await resp.json();
|
|
863
|
+
} finally {
|
|
864
|
+
clearTimeout(timer);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
746
868
|
// src/qr-render.ts
|
|
747
869
|
import { createRequire } from "node:module";
|
|
748
870
|
var require2 = createRequire(import.meta.url);
|
|
@@ -761,7 +883,7 @@ async function renderQrTerminal(url, options) {
|
|
|
761
883
|
|
|
762
884
|
// src/cli-init.ts
|
|
763
885
|
var __filename = fileURLToPath(import.meta.url);
|
|
764
|
-
var __dirname =
|
|
886
|
+
var __dirname = path3.dirname(__filename);
|
|
765
887
|
var SCHEMA_VERSION = 1;
|
|
766
888
|
function parseArgs() {
|
|
767
889
|
const args = process.argv.slice(2);
|
|
@@ -786,10 +908,10 @@ function parseArgs() {
|
|
|
786
908
|
}
|
|
787
909
|
}
|
|
788
910
|
if (!stateDir) {
|
|
789
|
-
stateDir =
|
|
911
|
+
stateDir = path3.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
|
|
790
912
|
console.log(` \u4F7F\u7528\u9ED8\u8BA4\u76EE\u5F55: ${stateDir}`);
|
|
791
913
|
}
|
|
792
|
-
stateDir =
|
|
914
|
+
stateDir = path3.resolve(stateDir);
|
|
793
915
|
return { stateDir, quick, dryRun: dryRun2, force };
|
|
794
916
|
}
|
|
795
917
|
function printHelp() {
|
|
@@ -860,6 +982,7 @@ function getDefaultValues(stateDir) {
|
|
|
860
982
|
stateDir,
|
|
861
983
|
agentName: "Agent",
|
|
862
984
|
primaryProvider: "dashscope",
|
|
985
|
+
zhipuPlan: "",
|
|
863
986
|
primaryApiKey: "",
|
|
864
987
|
primaryModel: "dashscope/qwen3.7-max",
|
|
865
988
|
visionModel: "dashscope/qwen3.7-max",
|
|
@@ -870,6 +993,9 @@ function getDefaultValues(stateDir) {
|
|
|
870
993
|
feishuAppId: "",
|
|
871
994
|
feishuAppSecret: "",
|
|
872
995
|
feishuOpenId: "",
|
|
996
|
+
wechatEnabled: false,
|
|
997
|
+
wechatToken: "",
|
|
998
|
+
wechatAccountId: "",
|
|
873
999
|
tavilyKey: "",
|
|
874
1000
|
apiPort: 16990
|
|
875
1001
|
};
|
|
@@ -887,6 +1013,12 @@ async function interactiveConfig(rl, defaults) {
|
|
|
887
1013
|
};
|
|
888
1014
|
const chosenProvider = await askChoice(rl, "\u4E3B\u6A21\u578B Provider:", providers, 0);
|
|
889
1015
|
v.primaryProvider = providerMap[chosenProvider] || "dashscope";
|
|
1016
|
+
v.zhipuPlan = "";
|
|
1017
|
+
if (v.primaryProvider === "zhipu") {
|
|
1018
|
+
const planOptions = ["coding-plan (GLM Coding \u8BA2\u9605)", "token-plan (\u666E\u901A\u6309\u91CF/TokenPlan)"];
|
|
1019
|
+
const chosenPlan = await askChoice(rl, "\u667A\u8C31\u8BA2\u9605\u7C7B\u578B:", planOptions, 0);
|
|
1020
|
+
v.zhipuPlan = chosenPlan.startsWith("coding") ? "coding" : "token";
|
|
1021
|
+
}
|
|
890
1022
|
const keyMap = {
|
|
891
1023
|
dashscope: "DashScope API Key",
|
|
892
1024
|
minimax: "MiniMax API Key",
|
|
@@ -974,6 +1106,44 @@ async function interactiveConfig(rl, defaults) {
|
|
|
974
1106
|
v.feishuOpenId = await ask(rl, "\u4F60\u7684\u98DE\u4E66 open_id\uFF08\u56DE\u8F66\u8DF3\u8FC7\uFF09", "");
|
|
975
1107
|
}
|
|
976
1108
|
}
|
|
1109
|
+
const wechatAns = await ask(rl, "\u542F\u7528\u5FAE\u4FE1? (y/n)", "n");
|
|
1110
|
+
v.wechatEnabled = wechatAns.toLowerCase() === "y";
|
|
1111
|
+
if (v.wechatEnabled) {
|
|
1112
|
+
console.log("\n \u5FAE\u4FE1\u63A5\u5165\u65B9\u5F0F\uFF1A");
|
|
1113
|
+
console.log(" 1. \u626B\u7801\u7ED1\u5B9A\uFF08\u63A8\u8350\uFF0C\u7528\u4F60\u81EA\u5DF1\u7684\u5FAE\u4FE1\u626B\u4E00\u4E0B\u5C31\u884C\uFF09");
|
|
1114
|
+
console.log(" 2. \u624B\u52A8\u8F93\u5165 token\uFF08\u5DF2\u6709\u51ED\u8BC1\u65F6\uFF09");
|
|
1115
|
+
const wechatMode = await ask(rl, "\u9009\u62E9 (1/2)", "1");
|
|
1116
|
+
if (wechatMode === "1") {
|
|
1117
|
+
console.log("\n\u{1F4DD} \u6B63\u5728\u751F\u6210\u5FAE\u4FE1\u4E8C\u7EF4\u7801...\n");
|
|
1118
|
+
console.log(" \u63D0\u793A\uFF1A\u4E00\u4E2A\u5FAE\u4FE1\u53F7\u53EA\u80FD\u7ED1\u4E00\u4E2A bot\uFF1Bbot \u4E0D\u8FDB\u7FA4\uFF08\u817E\u8BAF\u9650\u5236\uFF09\uFF0C\u79C1\u804A 1v1");
|
|
1119
|
+
const cred = await wechatQrLogin({ timeoutSeconds: 300, stateDir: v.stateDir });
|
|
1120
|
+
if (cred) {
|
|
1121
|
+
v.wechatToken = cred.token;
|
|
1122
|
+
v.wechatAccountId = cred.accountId;
|
|
1123
|
+
console.log(`
|
|
1124
|
+
\u2705 accountId: ${cred.accountId}`);
|
|
1125
|
+
console.log(` \u2705 \u51ED\u8BC1\u5DF2\u81EA\u52A8\u4FDD\u5B58\uFF0Cconfig \u5C06\u81EA\u52A8\u5199\u5165`);
|
|
1126
|
+
} else {
|
|
1127
|
+
console.log("\n \u26A0\uFE0F \u626B\u7801\u8D85\u65F6\u6216\u5931\u8D25");
|
|
1128
|
+
const retry = await ask(rl, "\u91CD\u8BD5\u626B\u7801? (y/n)", "y");
|
|
1129
|
+
if (retry.toLowerCase() === "y") {
|
|
1130
|
+
const cred2 = await wechatQrLogin({ timeoutSeconds: 300, stateDir: v.stateDir });
|
|
1131
|
+
if (cred2) {
|
|
1132
|
+
v.wechatToken = cred2.token;
|
|
1133
|
+
v.wechatAccountId = cred2.accountId;
|
|
1134
|
+
} else {
|
|
1135
|
+
console.log("\n \u26A0\uFE0F \u518D\u6B21\u5931\u8D25\uFF0C\u8DF3\u8FC7\u5FAE\u4FE1\uFF08\u4E4B\u540E\u53EF\u624B\u52A8\u914D\u7F6E\uFF09");
|
|
1136
|
+
v.wechatEnabled = false;
|
|
1137
|
+
}
|
|
1138
|
+
} else {
|
|
1139
|
+
v.wechatEnabled = false;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
} else {
|
|
1143
|
+
v.wechatToken = await ask(rl, "\u5FAE\u4FE1 token");
|
|
1144
|
+
v.wechatAccountId = await ask(rl, "\u5FAE\u4FE1 accountId");
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
977
1147
|
const tavilyKey = await ask(rl, "Tavily API Key\uFF08\u8054\u7F51\u641C\u7D22\uFF0C\u56DE\u8F66\u8DF3\u8FC7\uFF09", "");
|
|
978
1148
|
v.tavilyKey = tavilyKey;
|
|
979
1149
|
const portAns = await ask(rl, "API \u7AEF\u53E3", String(defaults.apiPort));
|
|
@@ -981,7 +1151,7 @@ async function interactiveConfig(rl, defaults) {
|
|
|
981
1151
|
return v;
|
|
982
1152
|
}
|
|
983
1153
|
function generateConfig(v) {
|
|
984
|
-
const workspace =
|
|
1154
|
+
const workspace = path3.join(v.stateDir, "workspace").replace(/\\/g, "/");
|
|
985
1155
|
const config = {
|
|
986
1156
|
schemaVersion: SCHEMA_VERSION,
|
|
987
1157
|
stateDir: v.stateDir.replace(/\\/g, "/"),
|
|
@@ -1041,7 +1211,16 @@ function generateConfig(v) {
|
|
|
1041
1211
|
connectionMode: "websocket",
|
|
1042
1212
|
dmPolicy: "pairing",
|
|
1043
1213
|
groupPolicy: "open"
|
|
1044
|
-
}
|
|
1214
|
+
},
|
|
1215
|
+
...v.wechatEnabled && v.wechatToken ? {
|
|
1216
|
+
wechat: {
|
|
1217
|
+
enabled: true,
|
|
1218
|
+
token: v.wechatToken,
|
|
1219
|
+
accountId: v.wechatAccountId,
|
|
1220
|
+
dmPolicy: "pairing",
|
|
1221
|
+
group: { policy: "disabled" }
|
|
1222
|
+
}
|
|
1223
|
+
} : {}
|
|
1045
1224
|
},
|
|
1046
1225
|
api: { port: v.apiPort },
|
|
1047
1226
|
prompt: {
|
|
@@ -1080,7 +1259,7 @@ function generateConfig(v) {
|
|
|
1080
1259
|
]
|
|
1081
1260
|
},
|
|
1082
1261
|
zhipu: {
|
|
1083
|
-
baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4
|
|
1262
|
+
baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4",
|
|
1084
1263
|
api: "openai-completions",
|
|
1085
1264
|
models: [
|
|
1086
1265
|
{ id: "glm-5.1", name: "GLM-5.1", reasoning: true, input: ["text"], contextWindow: 204800, maxTokens: 131072 },
|
|
@@ -1098,8 +1277,12 @@ function generateConfig(v) {
|
|
|
1098
1277
|
}
|
|
1099
1278
|
};
|
|
1100
1279
|
if (providerDefs[v.primaryProvider]) {
|
|
1280
|
+
const def = { ...providerDefs[v.primaryProvider] };
|
|
1281
|
+
if (v.primaryProvider === "zhipu" && v.zhipuPlan === "token") {
|
|
1282
|
+
def.baseUrl = "https://open.bigmodel.cn/api/paas/v4";
|
|
1283
|
+
}
|
|
1101
1284
|
config.models.providers[v.primaryProvider] = {
|
|
1102
|
-
...
|
|
1285
|
+
...def,
|
|
1103
1286
|
apiKey: v.primaryApiKey
|
|
1104
1287
|
};
|
|
1105
1288
|
}
|
|
@@ -1107,45 +1290,45 @@ function generateConfig(v) {
|
|
|
1107
1290
|
}
|
|
1108
1291
|
function buildDirTree(v) {
|
|
1109
1292
|
const d = v.stateDir;
|
|
1110
|
-
const w =
|
|
1293
|
+
const w = path3.join(d, "workspace");
|
|
1111
1294
|
const now = (/* @__PURE__ */ new Date()).toLocaleString("sv-SE", { timeZone: "Asia/Shanghai", hour12: false });
|
|
1112
1295
|
return [
|
|
1113
1296
|
// 目录
|
|
1114
|
-
{ path:
|
|
1115
|
-
{ path:
|
|
1116
|
-
{ path:
|
|
1117
|
-
{ path:
|
|
1118
|
-
{ path:
|
|
1119
|
-
{ path:
|
|
1120
|
-
{ path:
|
|
1121
|
-
{ path:
|
|
1122
|
-
{ path:
|
|
1123
|
-
{ path:
|
|
1124
|
-
{ path:
|
|
1297
|
+
{ path: path3.join(d, "configs"), type: "dir" },
|
|
1298
|
+
{ path: path3.join(d, "state", "agents", "main", "sessions"), type: "dir" },
|
|
1299
|
+
{ path: path3.join(w, "prompts"), type: "dir" },
|
|
1300
|
+
{ path: path3.join(w, "memory", "daily"), type: "dir" },
|
|
1301
|
+
{ path: path3.join(w, "docs", "research"), type: "dir" },
|
|
1302
|
+
{ path: path3.join(w, "docs", "todo"), type: "dir" },
|
|
1303
|
+
{ path: path3.join(w, "docs", "decisions"), type: "dir" },
|
|
1304
|
+
{ path: path3.join(w, "docs", "knowledge"), type: "dir" },
|
|
1305
|
+
{ path: path3.join(w, "docs", "sop"), type: "dir" },
|
|
1306
|
+
{ path: path3.join(d, "logs"), type: "dir" },
|
|
1307
|
+
{ path: path3.join(d, "media", "inbound"), type: "dir" },
|
|
1125
1308
|
// workspace 文件
|
|
1126
1309
|
{
|
|
1127
|
-
path:
|
|
1310
|
+
path: path3.join(w, "SESSION-STATE.md"),
|
|
1128
1311
|
type: "file",
|
|
1129
1312
|
content: readTemplate("workspace/SESSION-STATE.md").replace("{{CURRENT_TIME}}", now)
|
|
1130
1313
|
},
|
|
1131
|
-
{ path:
|
|
1314
|
+
{ path: path3.join(w, "HEARTBEAT.md"), type: "file", content: readTemplate("workspace/HEARTBEAT.md") },
|
|
1132
1315
|
{
|
|
1133
|
-
path:
|
|
1316
|
+
path: path3.join(w, "SOUL.md"),
|
|
1134
1317
|
type: "file",
|
|
1135
1318
|
content: readTemplate("workspace/SOUL.md").replace(/\{\{AGENT_NAME\}\}/g, v.agentName)
|
|
1136
1319
|
},
|
|
1137
|
-
{ path:
|
|
1320
|
+
{ path: path3.join(w, "AGENTS.md"), type: "file", content: readTemplate("workspace/AGENTS.md") },
|
|
1138
1321
|
{
|
|
1139
|
-
path:
|
|
1322
|
+
path: path3.join(w, "prompts", "contacts.md"),
|
|
1140
1323
|
type: "file",
|
|
1141
1324
|
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")
|
|
1142
1325
|
},
|
|
1143
|
-
{ path:
|
|
1144
|
-
{ path:
|
|
1145
|
-
{ path:
|
|
1326
|
+
{ path: path3.join(w, "prompts", "auto-memory-instructions.md"), type: "file", content: readTemplate("workspace/prompts/auto-memory-instructions.md") },
|
|
1327
|
+
{ path: path3.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" },
|
|
1328
|
+
{ path: path3.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" },
|
|
1146
1329
|
// package.json — 让 agent 目录成为独立 npm 项目根,防止 npm hoisting
|
|
1147
1330
|
{
|
|
1148
|
-
path:
|
|
1331
|
+
path: path3.join(d, "package.json"),
|
|
1149
1332
|
type: "file",
|
|
1150
1333
|
content: JSON.stringify({
|
|
1151
1334
|
name: v.agentName.toLowerCase().replace(/[^a-z0-9-]/g, "-") || "agent",
|
|
@@ -1156,7 +1339,7 @@ function buildDirTree(v) {
|
|
|
1156
1339
|
},
|
|
1157
1340
|
// 启动脚本(根据 OS 生成)
|
|
1158
1341
|
...process.platform === "win32" ? [{
|
|
1159
|
-
path:
|
|
1342
|
+
path: path3.join(d, "start.cmd"),
|
|
1160
1343
|
type: "file",
|
|
1161
1344
|
content: `@echo off
|
|
1162
1345
|
rem Engine 7 startup script
|
|
@@ -1188,7 +1371,7 @@ if %ERRORLEVEL% NEQ 0 (
|
|
|
1188
1371
|
)
|
|
1189
1372
|
`
|
|
1190
1373
|
}] : [{
|
|
1191
|
-
path:
|
|
1374
|
+
path: path3.join(d, "start.sh"),
|
|
1192
1375
|
type: "file",
|
|
1193
1376
|
content: `#!/bin/bash
|
|
1194
1377
|
# Engine 7 startup script
|
|
@@ -1221,13 +1404,13 @@ node "$ENGINE7_BIN" --engine-config configs/main7.json
|
|
|
1221
1404
|
}
|
|
1222
1405
|
function readTemplate(relativePath) {
|
|
1223
1406
|
const candidates = [
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1407
|
+
path3.join(__dirname, "..", "templates", relativePath),
|
|
1408
|
+
path3.join(__dirname, "..", "..", "templates", relativePath),
|
|
1409
|
+
path3.join(process.cwd(), "templates", relativePath)
|
|
1227
1410
|
];
|
|
1228
1411
|
for (const p of candidates) {
|
|
1229
|
-
if (
|
|
1230
|
-
return
|
|
1412
|
+
if (fs3.existsSync(p)) {
|
|
1413
|
+
return fs3.readFileSync(p, "utf-8");
|
|
1231
1414
|
}
|
|
1232
1415
|
}
|
|
1233
1416
|
throw new Error(`\u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${relativePath}\uFF08\u627E\u4E86: ${candidates.join(", ")}\uFF09`);
|
|
@@ -1242,11 +1425,11 @@ function dryRun(entries) {
|
|
|
1242
1425
|
function execute(entries) {
|
|
1243
1426
|
for (const e of entries) {
|
|
1244
1427
|
if (e.type === "dir") {
|
|
1245
|
-
|
|
1428
|
+
fs3.mkdirSync(e.path, { recursive: true });
|
|
1246
1429
|
console.log(` \u{1F4C1} ${e.path}`);
|
|
1247
1430
|
} else {
|
|
1248
|
-
|
|
1249
|
-
|
|
1431
|
+
fs3.mkdirSync(path3.dirname(e.path), { recursive: true });
|
|
1432
|
+
fs3.writeFileSync(e.path, e.content || "", "utf-8");
|
|
1250
1433
|
console.log(` \u{1F4C4} ${e.path}`);
|
|
1251
1434
|
}
|
|
1252
1435
|
}
|
|
@@ -1274,8 +1457,8 @@ async function main() {
|
|
|
1274
1457
|
else if (args[i] === "--note" && args[i + 1]) note = args[++i];
|
|
1275
1458
|
else if (args[i] === "--dry-run") dryRun2 = true;
|
|
1276
1459
|
}
|
|
1277
|
-
if (!exportStateDir) exportStateDir =
|
|
1278
|
-
if (!agentName) agentName =
|
|
1460
|
+
if (!exportStateDir) exportStateDir = path3.resolve(process.cwd());
|
|
1461
|
+
if (!agentName) agentName = path3.basename(exportStateDir);
|
|
1279
1462
|
await doExport2({ agentName, stateDir: exportStateDir, note, dryRun: dryRun2 });
|
|
1280
1463
|
process.exit(0);
|
|
1281
1464
|
}
|
|
@@ -1295,7 +1478,7 @@ async function main() {
|
|
|
1295
1478
|
console.error("\u274C import \u9700\u8981 --state-dir <path>");
|
|
1296
1479
|
process.exit(1);
|
|
1297
1480
|
}
|
|
1298
|
-
if (!agentName) agentName =
|
|
1481
|
+
if (!agentName) agentName = path3.basename(importStateDir);
|
|
1299
1482
|
await doImport2({ agentName, stateDir: importStateDir, version, dryRun: dryRun2 });
|
|
1300
1483
|
process.exit(0);
|
|
1301
1484
|
}
|
|
@@ -1320,18 +1503,18 @@ engine7 start \u2014 \u542F\u52A8 Engine
|
|
|
1320
1503
|
}
|
|
1321
1504
|
}
|
|
1322
1505
|
if (!configPath2) {
|
|
1323
|
-
const defaultCfg =
|
|
1324
|
-
const homeCfg =
|
|
1325
|
-
if (
|
|
1506
|
+
const defaultCfg = path3.join("configs", "main7.json");
|
|
1507
|
+
const homeCfg = path3.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
|
|
1508
|
+
if (fs3.existsSync(defaultCfg)) {
|
|
1326
1509
|
configPath2 = defaultCfg;
|
|
1327
|
-
} else if (
|
|
1510
|
+
} else if (fs3.existsSync(homeCfg)) {
|
|
1328
1511
|
configPath2 = homeCfg;
|
|
1329
1512
|
console.log(` \u4F7F\u7528\u9ED8\u8BA4 config: ${homeCfg}`);
|
|
1330
1513
|
} else {
|
|
1331
1514
|
const ptr = readHomePointer();
|
|
1332
1515
|
if (ptr?.stateDir) {
|
|
1333
|
-
const ptrCfg =
|
|
1334
|
-
if (
|
|
1516
|
+
const ptrCfg = path3.join(ptr.stateDir, "configs", "main7.json");
|
|
1517
|
+
if (fs3.existsSync(ptrCfg)) {
|
|
1335
1518
|
configPath2 = ptrCfg;
|
|
1336
1519
|
console.log(` \u4F7F\u7528 config: ${ptrCfg}`);
|
|
1337
1520
|
}
|
|
@@ -1346,19 +1529,19 @@ engine7 start \u2014 \u542F\u52A8 Engine
|
|
|
1346
1529
|
}
|
|
1347
1530
|
const { execSync: execSync2, spawn } = await import("node:child_process");
|
|
1348
1531
|
let enginePath;
|
|
1349
|
-
const localPath =
|
|
1350
|
-
if (
|
|
1532
|
+
const localPath = path3.join("node_modules", "engine7", "dist", "main.mjs");
|
|
1533
|
+
if (fs3.existsSync(localPath)) {
|
|
1351
1534
|
enginePath = localPath;
|
|
1352
1535
|
} else {
|
|
1353
|
-
const cliPath =
|
|
1354
|
-
const distDir =
|
|
1355
|
-
const candidate =
|
|
1356
|
-
if (
|
|
1536
|
+
const cliPath = path3.resolve(process.argv[1]);
|
|
1537
|
+
const distDir = path3.dirname(cliPath);
|
|
1538
|
+
const candidate = path3.join(distDir, "main.mjs");
|
|
1539
|
+
if (fs3.existsSync(candidate)) {
|
|
1357
1540
|
enginePath = candidate;
|
|
1358
1541
|
} else {
|
|
1359
1542
|
try {
|
|
1360
1543
|
const globalRoot = execSync2("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
1361
|
-
enginePath =
|
|
1544
|
+
enginePath = path3.join(globalRoot, "engine7", "dist", "main.mjs");
|
|
1362
1545
|
} catch {
|
|
1363
1546
|
console.error("\u274C \u627E\u4E0D\u5230 engine7 main.mjs");
|
|
1364
1547
|
process.exit(1);
|
|
@@ -1368,7 +1551,7 @@ engine7 start \u2014 \u542F\u52A8 Engine
|
|
|
1368
1551
|
console.log(label);
|
|
1369
1552
|
console.log(` config: ${configPath2}`);
|
|
1370
1553
|
console.log(` engine: ${enginePath}`);
|
|
1371
|
-
const configName =
|
|
1554
|
+
const configName = path3.basename(configPath2);
|
|
1372
1555
|
const myPid = process.pid;
|
|
1373
1556
|
try {
|
|
1374
1557
|
if (process.platform === "win32") {
|
|
@@ -1386,16 +1569,16 @@ engine7 start \u2014 \u542F\u52A8 Engine
|
|
|
1386
1569
|
}
|
|
1387
1570
|
console.log("");
|
|
1388
1571
|
const envForChild = { ...process.env };
|
|
1389
|
-
const secretsDir =
|
|
1390
|
-
const cfgBase =
|
|
1572
|
+
const secretsDir = path3.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7-secrets");
|
|
1573
|
+
const cfgBase = path3.basename(configPath2, ".json");
|
|
1391
1574
|
const secretCandidates = [
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1575
|
+
path3.join(secretsDir, `${cfgBase}.env`),
|
|
1576
|
+
path3.join(path3.dirname(configPath2), `.env.${cfgBase}`),
|
|
1577
|
+
path3.join(path3.dirname(configPath2), ".env")
|
|
1395
1578
|
];
|
|
1396
1579
|
for (const secretPath of secretCandidates) {
|
|
1397
|
-
if (
|
|
1398
|
-
const content =
|
|
1580
|
+
if (fs3.existsSync(secretPath)) {
|
|
1581
|
+
const content = fs3.readFileSync(secretPath, "utf-8");
|
|
1399
1582
|
for (const line of content.split("\n")) {
|
|
1400
1583
|
const trimmed = line.trim();
|
|
1401
1584
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -1469,14 +1652,14 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
|
|
|
1469
1652
|
console.error(`\u274C \u672A\u77E5\u6A21\u5F0F: ${mode}\uFF08\u53EF\u9009: archive / drop-last / strip-images\uFF09`);
|
|
1470
1653
|
process.exit(1);
|
|
1471
1654
|
}
|
|
1472
|
-
const configRaw = JSON.parse(
|
|
1655
|
+
const configRaw = JSON.parse(fs3.readFileSync(configPath2, "utf-8"));
|
|
1473
1656
|
const stateDir = configRaw.stateDir;
|
|
1474
1657
|
if (!stateDir) {
|
|
1475
1658
|
console.error("\u274C config \u91CC\u6CA1\u6709 stateDir");
|
|
1476
1659
|
process.exit(1);
|
|
1477
1660
|
}
|
|
1478
|
-
const sessionsDir =
|
|
1479
|
-
if (!
|
|
1661
|
+
const sessionsDir = path3.join(stateDir, "agents", "main", "sessions");
|
|
1662
|
+
if (!fs3.existsSync(sessionsDir)) {
|
|
1480
1663
|
console.error(`\u274C sessions \u76EE\u5F55\u4E0D\u5B58\u5728: ${sessionsDir}`);
|
|
1481
1664
|
process.exit(1);
|
|
1482
1665
|
}
|
|
@@ -1484,37 +1667,37 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
|
|
|
1484
1667
|
console.log(` config: ${configPath2}`);
|
|
1485
1668
|
console.log(` mode: ${mode}`);
|
|
1486
1669
|
if (mode === "drop-last") console.log(` n: ${dropN}`);
|
|
1487
|
-
const platformMapPath =
|
|
1488
|
-
const indexPath =
|
|
1670
|
+
const platformMapPath = path3.join(sessionsDir, "platform-map.json");
|
|
1671
|
+
const indexPath = path3.join(sessionsDir, "session-index.json");
|
|
1489
1672
|
let sessionFileUUID = null;
|
|
1490
|
-
if (
|
|
1491
|
-
const index = JSON.parse(
|
|
1673
|
+
if (fs3.existsSync(indexPath)) {
|
|
1674
|
+
const index = JSON.parse(fs3.readFileSync(indexPath, "utf-8"));
|
|
1492
1675
|
const entries = Object.values(index);
|
|
1493
1676
|
if (entries.length > 0) {
|
|
1494
1677
|
const fileVal = entries[0].file || "";
|
|
1495
|
-
sessionFileUUID =
|
|
1678
|
+
sessionFileUUID = path3.isAbsolute(fileVal) ? path3.basename(fileVal, ".jsonl") : fileVal.replace(".jsonl", "");
|
|
1496
1679
|
}
|
|
1497
1680
|
}
|
|
1498
1681
|
if (!sessionFileUUID) {
|
|
1499
|
-
const jsonlFiles =
|
|
1682
|
+
const jsonlFiles = fs3.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") && !f.includes(".archived.") && !f.includes(".compaction.")).map((f) => ({ name: f, mtime: fs3.statSync(path3.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
1500
1683
|
if (jsonlFiles.length === 0) {
|
|
1501
1684
|
console.error("\u274C \u627E\u4E0D\u5230\u6D3B\u8DC3\u7684 session JSONL \u6587\u4EF6");
|
|
1502
1685
|
process.exit(1);
|
|
1503
1686
|
}
|
|
1504
1687
|
sessionFileUUID = jsonlFiles[0].name.replace(".jsonl", "");
|
|
1505
1688
|
}
|
|
1506
|
-
let jsonlPath =
|
|
1507
|
-
if (!
|
|
1508
|
-
const jsonlFiles =
|
|
1689
|
+
let jsonlPath = path3.join(sessionsDir, `${sessionFileUUID}.jsonl`);
|
|
1690
|
+
if (!fs3.existsSync(jsonlPath)) {
|
|
1691
|
+
const jsonlFiles = fs3.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") && !f.includes(".archived.") && !f.includes(".compaction.")).map((f) => ({ name: f, mtime: fs3.statSync(path3.join(sessionsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
1509
1692
|
if (jsonlFiles.length === 0) {
|
|
1510
1693
|
console.error(`\u274C JSONL \u6587\u4EF6\u4E0D\u5B58\u5728: ${jsonlPath}`);
|
|
1511
1694
|
process.exit(1);
|
|
1512
1695
|
}
|
|
1513
1696
|
sessionFileUUID = jsonlFiles[0].name.replace(".jsonl", "");
|
|
1514
|
-
jsonlPath =
|
|
1697
|
+
jsonlPath = path3.join(sessionsDir, `${sessionFileUUID}.jsonl`);
|
|
1515
1698
|
}
|
|
1516
1699
|
console.log(` file: ${jsonlPath}`);
|
|
1517
|
-
const configName =
|
|
1700
|
+
const configName = path3.basename(configPath2);
|
|
1518
1701
|
if (autoRestart) {
|
|
1519
1702
|
try {
|
|
1520
1703
|
const myPid = process.pid;
|
|
@@ -1530,15 +1713,15 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
|
|
|
1530
1713
|
}
|
|
1531
1714
|
}
|
|
1532
1715
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1533
|
-
const { readFileSync:
|
|
1716
|
+
const { readFileSync: readFileSync4, writeFileSync: writeFileSync4, renameSync } = fs3;
|
|
1534
1717
|
if (mode === "archive") {
|
|
1535
1718
|
const archiveName = `${sessionFileUUID}.jsonl.archived.${timestamp}`;
|
|
1536
|
-
renameSync(jsonlPath,
|
|
1719
|
+
renameSync(jsonlPath, path3.join(sessionsDir, archiveName));
|
|
1537
1720
|
console.log(`
|
|
1538
1721
|
\u2705 \u5F52\u6863\u5B8C\u6210: ${archiveName}`);
|
|
1539
1722
|
console.log(` \u91CD\u542F\u540E\u5C06\u4ECE\u7A7A\u767D\u4F1A\u8BDD\u5F00\u59CB`);
|
|
1540
1723
|
} else if (mode === "drop-last") {
|
|
1541
|
-
const lines =
|
|
1724
|
+
const lines = readFileSync4(jsonlPath, "utf-8").trim().split("\n");
|
|
1542
1725
|
const parsed = lines.map((l) => {
|
|
1543
1726
|
try {
|
|
1544
1727
|
return JSON.parse(l);
|
|
@@ -1557,12 +1740,12 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
|
|
|
1557
1740
|
}
|
|
1558
1741
|
const kept = parsed.slice(0, cutIndex);
|
|
1559
1742
|
const newContent = kept.map((p) => JSON.stringify(p)).join("\n") + "\n";
|
|
1560
|
-
|
|
1743
|
+
writeFileSync4(jsonlPath, newContent);
|
|
1561
1744
|
console.log(`
|
|
1562
1745
|
\u2705 \u780D\u6389\u6700\u8FD1 ${parsed.length - cutIndex} \u884C\uFF08${dropN} \u8F6E\uFF09`);
|
|
1563
1746
|
console.log(` \u4FDD\u7559 ${kept.length} \u884C`);
|
|
1564
1747
|
} else if (mode === "strip-images") {
|
|
1565
|
-
const lines =
|
|
1748
|
+
const lines = readFileSync4(jsonlPath, "utf-8").trim().split("\n");
|
|
1566
1749
|
let stripped = 0;
|
|
1567
1750
|
const newLines = lines.map((line) => {
|
|
1568
1751
|
try {
|
|
@@ -1603,17 +1786,17 @@ engine7 session \u2014 \u4F1A\u8BDD\u7BA1\u7406\u5DE5\u5177
|
|
|
1603
1786
|
return line;
|
|
1604
1787
|
}
|
|
1605
1788
|
});
|
|
1606
|
-
|
|
1789
|
+
writeFileSync4(jsonlPath, newLines.join("\n") + "\n");
|
|
1607
1790
|
console.log(`
|
|
1608
1791
|
\u2705 \u6458\u9664 ${stripped} \u884C\u56FE\u7247\u76F8\u5173\u5185\u5BB9`);
|
|
1609
1792
|
}
|
|
1610
1793
|
if (autoRestart) {
|
|
1611
|
-
const realCliPath =
|
|
1612
|
-
const cliDir =
|
|
1613
|
-
const pkgRoot =
|
|
1614
|
-
let enginePath =
|
|
1615
|
-
if (!
|
|
1616
|
-
enginePath =
|
|
1794
|
+
const realCliPath = fs3.realpathSync(process.argv[1]);
|
|
1795
|
+
const cliDir = path3.dirname(realCliPath);
|
|
1796
|
+
const pkgRoot = path3.resolve(cliDir, "..");
|
|
1797
|
+
let enginePath = path3.join(pkgRoot, "dist", "main.mjs");
|
|
1798
|
+
if (!fs3.existsSync(enginePath)) {
|
|
1799
|
+
enginePath = path3.join(cliDir, "main.mjs");
|
|
1617
1800
|
}
|
|
1618
1801
|
console.log(`
|
|
1619
1802
|
\u{1F680} \u62C9\u8D77 engine...`);
|
|
@@ -1656,18 +1839,18 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
|
|
|
1656
1839
|
else if (args[i] === "--cwd" && args[i + 1]) cwd = args[++i];
|
|
1657
1840
|
}
|
|
1658
1841
|
if (!configPath2) {
|
|
1659
|
-
const defaultCfg =
|
|
1660
|
-
const homeCfg =
|
|
1661
|
-
if (
|
|
1842
|
+
const defaultCfg = path3.join(cwd, "configs", "main7.json");
|
|
1843
|
+
const homeCfg = path3.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
|
|
1844
|
+
if (fs3.existsSync(defaultCfg)) {
|
|
1662
1845
|
configPath2 = defaultCfg;
|
|
1663
|
-
} else if (
|
|
1846
|
+
} else if (fs3.existsSync(homeCfg)) {
|
|
1664
1847
|
configPath2 = homeCfg;
|
|
1665
|
-
cwd =
|
|
1848
|
+
cwd = path3.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
|
|
1666
1849
|
} else {
|
|
1667
1850
|
const ptr = readHomePointer();
|
|
1668
1851
|
if (ptr?.stateDir) {
|
|
1669
|
-
const ptrCfg =
|
|
1670
|
-
if (
|
|
1852
|
+
const ptrCfg = path3.join(ptr.stateDir, "configs", "main7.json");
|
|
1853
|
+
if (fs3.existsSync(ptrCfg)) {
|
|
1671
1854
|
configPath2 = ptrCfg;
|
|
1672
1855
|
cwd = ptr.stateDir;
|
|
1673
1856
|
}
|
|
@@ -1686,14 +1869,14 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
|
|
|
1686
1869
|
if (process.platform === "win32") {
|
|
1687
1870
|
const taskName = "Engine7";
|
|
1688
1871
|
const nodeExe = process.execPath;
|
|
1689
|
-
const cliMjs =
|
|
1690
|
-
const absConfig =
|
|
1691
|
-
const wrapperPath =
|
|
1872
|
+
const cliMjs = path3.resolve(engine7Bin);
|
|
1873
|
+
const absConfig = path3.resolve(configPath2);
|
|
1874
|
+
const wrapperPath = path3.join(cwd, "engine7-start.cmd");
|
|
1692
1875
|
const wrapperContent = `@echo off\r
|
|
1693
1876
|
cd /d "${cwd}"\r
|
|
1694
1877
|
"${nodeExe}" "${cliMjs}" start --config "${absConfig}"\r
|
|
1695
1878
|
`;
|
|
1696
|
-
|
|
1879
|
+
fs3.writeFileSync(wrapperPath, wrapperContent);
|
|
1697
1880
|
try {
|
|
1698
1881
|
execSync2(`schtasks /create /tn "${taskName}" /tr "${wrapperPath}" /sc onlogon /rl highest /f`, { stdio: "inherit", shell: true });
|
|
1699
1882
|
console.log(`\u2705 Windows \u8BA1\u5212\u4EFB\u52A1 "${taskName}" \u5DF2\u521B\u5EFA\uFF08\u5F00\u673A\u81EA\u542F\u52A8\uFF09`);
|
|
@@ -1704,11 +1887,11 @@ cd /d "${cwd}"\r
|
|
|
1704
1887
|
}
|
|
1705
1888
|
} else if (process.platform === "darwin") {
|
|
1706
1889
|
const label = "com.engine7.agent";
|
|
1707
|
-
const plistDir =
|
|
1708
|
-
|
|
1709
|
-
const plistPath =
|
|
1710
|
-
const localCli =
|
|
1711
|
-
const cliMjs =
|
|
1890
|
+
const plistDir = path3.join(process.env.HOME, "Library", "LaunchAgents");
|
|
1891
|
+
fs3.mkdirSync(plistDir, { recursive: true });
|
|
1892
|
+
const plistPath = path3.join(plistDir, `${label}.plist`);
|
|
1893
|
+
const localCli = path3.join("node_modules", "engine7", "dist", "cli.mjs");
|
|
1894
|
+
const cliMjs = fs3.existsSync(localCli) ? path3.resolve(localCli) : path3.join(path3.dirname(path3.dirname(engine7Bin)), "lib", "node_modules", "engine7", "dist", "cli.mjs");
|
|
1712
1895
|
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1713
1896
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
1714
1897
|
<plist version="1.0">
|
|
@@ -1720,14 +1903,14 @@ cd /d "${cwd}"\r
|
|
|
1720
1903
|
<string>${cliMjs}</string>
|
|
1721
1904
|
<string>start</string>
|
|
1722
1905
|
<string>--config</string>
|
|
1723
|
-
<string>${
|
|
1906
|
+
<string>${path3.resolve(configPath2)}</string>
|
|
1724
1907
|
</array>
|
|
1725
1908
|
<key>WorkingDirectory</key><string>${cwd}</string>
|
|
1726
1909
|
<key>RunAtLoad</key><true/>
|
|
1727
1910
|
<key>KeepAlive</key><true/>
|
|
1728
1911
|
</dict>
|
|
1729
1912
|
</plist>`;
|
|
1730
|
-
|
|
1913
|
+
fs3.writeFileSync(plistPath, plist);
|
|
1731
1914
|
try {
|
|
1732
1915
|
execSync2(`launchctl load "${plistPath}"`, { stdio: "inherit" });
|
|
1733
1916
|
console.log(`\u2705 Mac launchd \u670D\u52A1\u5DF2\u521B\u5EFA\uFF08\u5F00\u673A\u81EA\u542F\u52A8\uFF09`);
|
|
@@ -1738,9 +1921,9 @@ cd /d "${cwd}"\r
|
|
|
1738
1921
|
}
|
|
1739
1922
|
} else {
|
|
1740
1923
|
const svcName = "engine7";
|
|
1741
|
-
const svcDir =
|
|
1742
|
-
|
|
1743
|
-
const svcPath =
|
|
1924
|
+
const svcDir = path3.join(process.env.HOME, ".config", "systemd", "user");
|
|
1925
|
+
fs3.mkdirSync(svcDir, { recursive: true });
|
|
1926
|
+
const svcPath = path3.join(svcDir, `${svcName}.service`);
|
|
1744
1927
|
const svc = `[Unit]
|
|
1745
1928
|
Description=Engine 7 Agent
|
|
1746
1929
|
After=network.target
|
|
@@ -1748,13 +1931,13 @@ After=network.target
|
|
|
1748
1931
|
[Service]
|
|
1749
1932
|
Type=simple
|
|
1750
1933
|
WorkingDirectory=${cwd}
|
|
1751
|
-
ExecStart=${process.execPath} ${engine7Bin} start --config ${
|
|
1934
|
+
ExecStart=${process.execPath} ${engine7Bin} start --config ${path3.resolve(configPath2)}
|
|
1752
1935
|
Restart=on-failure
|
|
1753
1936
|
RestartSec=10
|
|
1754
1937
|
|
|
1755
1938
|
[Install]
|
|
1756
1939
|
WantedBy=default.target`;
|
|
1757
|
-
|
|
1940
|
+
fs3.writeFileSync(svcPath, svc);
|
|
1758
1941
|
try {
|
|
1759
1942
|
execSync2(`systemctl --user daemon-reload`, { stdio: "inherit" });
|
|
1760
1943
|
execSync2(`systemctl --user enable ${svcName}`, { stdio: "inherit" });
|
|
@@ -1775,13 +1958,13 @@ WantedBy=default.target`;
|
|
|
1775
1958
|
process.exit(1);
|
|
1776
1959
|
}
|
|
1777
1960
|
} else if (process.platform === "darwin") {
|
|
1778
|
-
const plistPath =
|
|
1961
|
+
const plistPath = path3.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
|
|
1779
1962
|
try {
|
|
1780
1963
|
execSync2(`launchctl unload "${plistPath}"`, { stdio: "inherit" });
|
|
1781
1964
|
} catch {
|
|
1782
1965
|
}
|
|
1783
1966
|
try {
|
|
1784
|
-
|
|
1967
|
+
fs3.unlinkSync(plistPath);
|
|
1785
1968
|
} catch {
|
|
1786
1969
|
}
|
|
1787
1970
|
console.log(`\u2705 Mac launchd \u670D\u52A1\u5DF2\u5220\u9664`);
|
|
@@ -1790,9 +1973,9 @@ WantedBy=default.target`;
|
|
|
1790
1973
|
execSync2(`systemctl --user disable engine7`, { stdio: "inherit" });
|
|
1791
1974
|
} catch {
|
|
1792
1975
|
}
|
|
1793
|
-
const svcPath =
|
|
1976
|
+
const svcPath = path3.join(process.env.HOME, ".config", "systemd", "user", "engine7.service");
|
|
1794
1977
|
try {
|
|
1795
|
-
|
|
1978
|
+
fs3.unlinkSync(svcPath);
|
|
1796
1979
|
} catch {
|
|
1797
1980
|
}
|
|
1798
1981
|
try {
|
|
@@ -1809,8 +1992,8 @@ WantedBy=default.target`;
|
|
|
1809
1992
|
console.log("\u274C \u672A\u5B89\u88C5");
|
|
1810
1993
|
}
|
|
1811
1994
|
} else if (process.platform === "darwin") {
|
|
1812
|
-
const plistPath =
|
|
1813
|
-
if (
|
|
1995
|
+
const plistPath = path3.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
|
|
1996
|
+
if (fs3.existsSync(plistPath)) {
|
|
1814
1997
|
console.log("\u2705 \u5DF2\u5B89\u88C5\uFF08launchd\uFF09");
|
|
1815
1998
|
} else {
|
|
1816
1999
|
console.log("\u274C \u672A\u5B89\u88C5");
|
|
@@ -1833,13 +2016,13 @@ WantedBy=default.target`;
|
|
|
1833
2016
|
console.log(`
|
|
1834
2017
|
\u{1F680} engine7 init`);
|
|
1835
2018
|
console.log(` state-dir: ${opts.stateDir}`);
|
|
1836
|
-
if (
|
|
1837
|
-
const files =
|
|
2019
|
+
if (fs3.existsSync(opts.stateDir) && !opts.dryRun) {
|
|
2020
|
+
const files = fs3.readdirSync(opts.stateDir);
|
|
1838
2021
|
if (files.length > 0) {
|
|
1839
2022
|
if (opts.force) {
|
|
1840
2023
|
console.log(`
|
|
1841
2024
|
\u26A0\uFE0F --force: \u6E05\u7A7A\u5DF2\u6709\u76EE\u5F55 ${opts.stateDir}`);
|
|
1842
|
-
|
|
2025
|
+
fs3.rmSync(opts.stateDir, { recursive: true, force: true });
|
|
1843
2026
|
} else {
|
|
1844
2027
|
console.error(`
|
|
1845
2028
|
\u274C \u76EE\u5F55\u5DF2\u5B58\u5728\u4E14\u975E\u7A7A: ${opts.stateDir}`);
|
|
@@ -1859,7 +2042,7 @@ WantedBy=default.target`;
|
|
|
1859
2042
|
rl.close();
|
|
1860
2043
|
}
|
|
1861
2044
|
const config = generateConfig(values);
|
|
1862
|
-
const configPath =
|
|
2045
|
+
const configPath = path3.join(opts.stateDir, "configs", "main7.json");
|
|
1863
2046
|
const tree = buildDirTree(values);
|
|
1864
2047
|
tree.push({
|
|
1865
2048
|
path: configPath,
|
|
@@ -1870,9 +2053,9 @@ WantedBy=default.target`;
|
|
|
1870
2053
|
dryRun(tree);
|
|
1871
2054
|
const skillsSrc = findTemplateDir("skills");
|
|
1872
2055
|
if (skillsSrc) {
|
|
1873
|
-
const skills =
|
|
2056
|
+
const skills = fs3.readdirSync(skillsSrc);
|
|
1874
2057
|
for (const s of skills) {
|
|
1875
|
-
console.log(` \u{1F4C1} ${
|
|
2058
|
+
console.log(` \u{1F4C1} ${path3.join(opts.stateDir, "workspace", "skills", s)}`);
|
|
1876
2059
|
}
|
|
1877
2060
|
}
|
|
1878
2061
|
} else {
|
|
@@ -1880,55 +2063,55 @@ WantedBy=default.target`;
|
|
|
1880
2063
|
execute(tree);
|
|
1881
2064
|
const skillsSrc = findTemplateDir("skills");
|
|
1882
2065
|
if (skillsSrc) {
|
|
1883
|
-
const skillsDest =
|
|
1884
|
-
|
|
1885
|
-
const skills =
|
|
2066
|
+
const skillsDest = path3.join(opts.stateDir, "workspace", "skills");
|
|
2067
|
+
fs3.mkdirSync(skillsDest, { recursive: true });
|
|
2068
|
+
const skills = fs3.readdirSync(skillsSrc);
|
|
1886
2069
|
for (const s of skills) {
|
|
1887
|
-
copyDirRecursive(
|
|
2070
|
+
copyDirRecursive(path3.join(skillsSrc, s), path3.join(skillsDest, s));
|
|
1888
2071
|
console.log(` \u{1F4E6} skill: ${s}`);
|
|
1889
2072
|
}
|
|
1890
2073
|
}
|
|
1891
2074
|
console.log(`
|
|
1892
2075
|
\u2705 \u521D\u59CB\u5316\u5B8C\u6210\uFF01
|
|
1893
2076
|
`);
|
|
1894
|
-
const homePointer =
|
|
2077
|
+
const homePointer = path3.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
|
|
1895
2078
|
const pointerData = { stateDir: opts.stateDir };
|
|
1896
|
-
|
|
2079
|
+
fs3.writeFileSync(homePointer, JSON.stringify(pointerData, null, 2) + "\n");
|
|
1897
2080
|
console.log(` \u{1F4C4} ${homePointer}\uFF08\u4ECE\u4EFB\u610F\u76EE\u5F55\u90FD\u80FD\u627E\u5230\u6B64 agent\uFF09`);
|
|
1898
2081
|
console.log(`\u4E0B\u4E00\u6B65\uFF1A`);
|
|
1899
2082
|
console.log(` 1. \u68C0\u67E5\u5E76\u4FEE\u6539 ${opts.stateDir}/configs/main7.json`);
|
|
1900
2083
|
console.log(` 2. \u542F\u52A8 Engine: engine7 start\uFF08\u5728\u4EFB\u610F\u76EE\u5F55\u90FD\u884C\uFF09`);
|
|
1901
2084
|
console.log(` 3. \u5F00\u673A\u81EA\u542F: engine7 service install\uFF08\u5728\u4EFB\u610F\u76EE\u5F55\u90FD\u884C\uFF09`);
|
|
1902
|
-
console.log(` 4. \u67E5\u770B workspace: ${
|
|
2085
|
+
console.log(` 4. \u67E5\u770B workspace: ${path3.join(opts.stateDir, "workspace")}`);
|
|
1903
2086
|
}
|
|
1904
2087
|
}
|
|
1905
2088
|
function copyDirRecursive(src, dest) {
|
|
1906
|
-
|
|
1907
|
-
for (const entry of
|
|
1908
|
-
const srcPath =
|
|
1909
|
-
const destPath =
|
|
2089
|
+
fs3.mkdirSync(dest, { recursive: true });
|
|
2090
|
+
for (const entry of fs3.readdirSync(src, { withFileTypes: true })) {
|
|
2091
|
+
const srcPath = path3.join(src, entry.name);
|
|
2092
|
+
const destPath = path3.join(dest, entry.name);
|
|
1910
2093
|
if (entry.isDirectory()) {
|
|
1911
2094
|
copyDirRecursive(srcPath, destPath);
|
|
1912
2095
|
} else {
|
|
1913
|
-
|
|
2096
|
+
fs3.copyFileSync(srcPath, destPath);
|
|
1914
2097
|
}
|
|
1915
2098
|
}
|
|
1916
2099
|
}
|
|
1917
2100
|
function findTemplateDir(name) {
|
|
1918
2101
|
const candidates = [
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
2102
|
+
path3.join(__dirname, "..", "templates", name),
|
|
2103
|
+
path3.join(__dirname, "..", "..", "templates", name),
|
|
2104
|
+
path3.join(process.cwd(), "templates", name)
|
|
1922
2105
|
];
|
|
1923
2106
|
for (const p of candidates) {
|
|
1924
|
-
if (
|
|
2107
|
+
if (fs3.existsSync(p)) return p;
|
|
1925
2108
|
}
|
|
1926
2109
|
return null;
|
|
1927
2110
|
}
|
|
1928
2111
|
function readHomePointer() {
|
|
1929
|
-
const ptrPath =
|
|
2112
|
+
const ptrPath = path3.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
|
|
1930
2113
|
try {
|
|
1931
|
-
return JSON.parse(
|
|
2114
|
+
return JSON.parse(fs3.readFileSync(ptrPath, "utf-8"));
|
|
1932
2115
|
} catch {
|
|
1933
2116
|
return null;
|
|
1934
2117
|
}
|