engine7 7.1.7 → 7.1.9

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 CHANGED
@@ -1,10 +1,500 @@
1
- // src/cli-init.ts
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res) => function __init() {
4
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
+ };
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+
11
+ // src/cli-travel.ts
12
+ var cli_travel_exports = {};
13
+ __export(cli_travel_exports, {
14
+ doExport: () => doExport,
15
+ doImport: () => doImport,
16
+ loadTravelConfig: () => loadTravelConfig,
17
+ saveTravelConfig: () => saveTravelConfig
18
+ });
2
19
  import * as path from "node:path";
3
20
  import * as fs from "node:fs";
21
+ import * as os from "node:os";
22
+ import { execSync } from "node:child_process";
23
+ function loadTravelConfig() {
24
+ try {
25
+ if (!fs.existsSync(CONFIG_PATH)) return null;
26
+ return JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8"));
27
+ } catch {
28
+ return null;
29
+ }
30
+ }
31
+ function saveTravelConfig(cfg) {
32
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2));
33
+ }
34
+ function sanitizeContent(content, dirs) {
35
+ let result = content;
36
+ for (const { placeholder, getOriginal } of PATH_PLACEHOLDERS) {
37
+ const original = getOriginal(dirs);
38
+ if (original) {
39
+ result = result.split(original).join(placeholder);
40
+ result = result.split(original.replace(/\//g, "\\")).join(placeholder);
41
+ }
42
+ }
43
+ return result;
44
+ }
45
+ function restoreContent(content, dirs) {
46
+ let result = content;
47
+ for (const { placeholder, getOriginal } of PATH_PLACEHOLDERS) {
48
+ const target = getOriginal(dirs);
49
+ if (target) {
50
+ result = result.split(placeholder).join(target);
51
+ }
52
+ }
53
+ return result;
54
+ }
55
+ function isTextFile(filePath) {
56
+ const ext = path.extname(filePath).toLowerCase();
57
+ return TEXT_EXTENSIONS.has(ext);
58
+ }
59
+ function shouldExclude(name) {
60
+ for (const pattern of WORKSPACE_EXCLUDE) {
61
+ if (pattern.startsWith("*")) {
62
+ if (name.includes(pattern.slice(1).replace("*", ""))) return true;
63
+ } else if (name === pattern) {
64
+ return true;
65
+ }
66
+ }
67
+ return false;
68
+ }
69
+ function collectFiles(rootDir, includeSet, optionalSet) {
70
+ const files = [];
71
+ const entries = fs.readdirSync(rootDir, { withFileTypes: true });
72
+ for (const entry of entries) {
73
+ if (shouldExclude(entry.name)) continue;
74
+ const fullPath = path.join(rootDir, entry.name);
75
+ const realPath = fs.realpathSync(fullPath);
76
+ if (realPath !== fullPath) {
77
+ try {
78
+ const lstat = fs.lstatSync(fullPath);
79
+ if (lstat.isSymbolicLink()) {
80
+ continue;
81
+ }
82
+ } catch {
83
+ }
84
+ }
85
+ const isInclude = includeSet.has(entry.name) || optionalSet.has(entry.name);
86
+ if (!isInclude) continue;
87
+ if (entry.isDirectory()) {
88
+ const subFiles = collectAllFiles(fullPath);
89
+ files.push(...subFiles);
90
+ } else {
91
+ files.push(fullPath);
92
+ }
93
+ }
94
+ return files;
95
+ }
96
+ function collectAllFiles(dir) {
97
+ const files = [];
98
+ try {
99
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
100
+ for (const entry of entries) {
101
+ if (shouldExclude(entry.name)) continue;
102
+ const fullPath = path.join(dir, entry.name);
103
+ try {
104
+ if (fs.lstatSync(fullPath).isSymbolicLink()) continue;
105
+ } catch {
106
+ }
107
+ if (entry.isDirectory()) {
108
+ files.push(...collectAllFiles(fullPath));
109
+ } else {
110
+ files.push(fullPath);
111
+ }
112
+ }
113
+ } catch {
114
+ }
115
+ return files;
116
+ }
117
+ function collectRecentSessions(agentsDir, days = 7) {
118
+ const files = [];
119
+ if (!fs.existsSync(agentsDir)) return files;
120
+ const cutoff = Date.now() - days * 24 * 60 * 60 * 1e3;
121
+ try {
122
+ const entries = fs.readdirSync(agentsDir, { withFileTypes: true });
123
+ for (const entry of entries) {
124
+ const fullPath = path.join(agentsDir, entry.name);
125
+ if (entry.isDirectory()) {
126
+ const sub = collectAllFiles(fullPath);
127
+ for (const f of sub) {
128
+ if (!f.endsWith(".jsonl")) continue;
129
+ const stat = fs.statSync(f);
130
+ if (stat.mtimeMs > cutoff) files.push(f);
131
+ }
132
+ } else if (entry.name.endsWith(".jsonl")) {
133
+ const stat = fs.statSync(fullPath);
134
+ if (stat.mtimeMs > cutoff) files.push(fullPath);
135
+ }
136
+ }
137
+ } catch {
138
+ }
139
+ return files;
140
+ }
141
+ async function doExport(opts) {
142
+ const { agentName, stateDir, note, dryRun: dryRun2 } = opts;
143
+ const workspace = opts.workspace || path.join(stateDir, "workspace");
144
+ const engineHome = path.join(os.homedir(), ".openclaw");
145
+ console.log(`\u{1F4E6} engine7 export`);
146
+ console.log(` agent: ${agentName}`);
147
+ console.log(` state: ${stateDir}`);
148
+ console.log(` workspace: ${workspace}`);
149
+ if (!fs.existsSync(workspace)) {
150
+ console.error(`\u274C workspace \u4E0D\u5B58\u5728: ${workspace}`);
151
+ process.exit(1);
152
+ }
153
+ const dirs = { workspace, stateDir, engineHome };
154
+ const wsFiles = collectFiles(workspace, WORKSPACE_INCLUDE, WORKSPACE_OPTIONAL);
155
+ const sessionFiles = collectRecentSessions(path.join(stateDir, "agents"), 7);
156
+ console.log(` workspace \u6587\u4EF6: ${wsFiles.length}`);
157
+ console.log(` session jsonl: ${sessionFiles.length} (\u6700\u8FD17\u5929)`);
158
+ if (dryRun2) {
159
+ console.log(`
160
+ [DRY RUN] \u4F1A\u6253\u5305\u4EE5\u4E0B\u6587\u4EF6:`);
161
+ wsFiles.slice(0, 20).forEach((f) => console.log(` ${path.relative(workspace, f)}`));
162
+ if (wsFiles.length > 20) console.log(` ... \u8FD8\u6709 ${wsFiles.length - 20} \u4E2A\u6587\u4EF6`);
163
+ console.log(`
164
+ [DRY RUN] \u4E0D\u5B9E\u9645\u6253\u5305`);
165
+ return;
166
+ }
167
+ const now = /* @__PURE__ */ new Date();
168
+ 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")}`;
169
+ const tmpDir = path.join(os.tmpdir(), `engine7-export-${agentName}-${version}`);
170
+ fs.mkdirSync(tmpDir, { recursive: true });
171
+ const stagingDir = path.join(tmpDir, agentName);
172
+ fs.mkdirSync(stagingDir, { recursive: true });
173
+ let fileCount = 0;
174
+ let totalSize = 0;
175
+ for (const srcFile of wsFiles) {
176
+ const relPath = path.relative(workspace, srcFile);
177
+ const destFile = path.join(stagingDir, "workspace", relPath);
178
+ fs.mkdirSync(path.dirname(destFile), { recursive: true });
179
+ if (isTextFile(srcFile)) {
180
+ const content = fs.readFileSync(srcFile, "utf-8");
181
+ fs.writeFileSync(destFile, sanitizeContent(content, dirs));
182
+ } else {
183
+ fs.copyFileSync(srcFile, destFile);
184
+ }
185
+ fileCount++;
186
+ totalSize += fs.statSync(srcFile).size;
187
+ }
188
+ for (const srcFile of sessionFiles) {
189
+ const relPath = path.relative(stateDir, srcFile);
190
+ const destFile = path.join(stagingDir, relPath);
191
+ fs.mkdirSync(path.dirname(destFile), { recursive: true });
192
+ fs.copyFileSync(srcFile, destFile);
193
+ fileCount++;
194
+ totalSize += fs.statSync(srcFile).size;
195
+ }
196
+ const manifest = {
197
+ agentName,
198
+ version,
199
+ createdAt: now.toISOString(),
200
+ engineVersion: "7.x",
201
+ originalPaths: {
202
+ WORKSPACE: workspace,
203
+ STATE_DIR: stateDir,
204
+ ENGINE_HOME: engineHome
205
+ },
206
+ fileCount,
207
+ totalSize,
208
+ note
209
+ };
210
+ fs.writeFileSync(path.join(stagingDir, "manifest.json"), JSON.stringify(manifest, null, 2));
211
+ const archiveFile = path.join(tmpDir, `${agentName}-${version}.zip`);
212
+ console.log(`
213
+ \u{1F5DC}\uFE0F \u6253\u5305\u4E2D...`);
214
+ if (process.platform === "win32") {
215
+ const stagingParent = path.dirname(stagingDir).replace(/\\/g, "/");
216
+ const childName = path.basename(stagingDir);
217
+ execSync(`powershell -Command "Compress-Archive -Path '${stagingParent}/${childName}' -DestinationPath '${archiveFile}' -Force"`, { stdio: "pipe" });
218
+ } else {
219
+ execSync(`cd "${tmpDir}" && zip -r -q "${archiveFile}" ${agentName}`, { stdio: "pipe" });
220
+ }
221
+ const archiveSize = fs.statSync(archiveFile).size;
222
+ console.log(`\u2705 \u6253\u5305\u5B8C\u6210: ${archiveFile} (${(archiveSize / 1024 / 1024).toFixed(1)} MB, ${fileCount} \u6587\u4EF6)`);
223
+ const cfg = loadTravelConfig();
224
+ if (!cfg || !cfg.githubToken) {
225
+ console.log(`
226
+ \u26A0\uFE0F \u672A\u914D\u7F6E GitHub\uFF0Ctar.gz \u5DF2\u751F\u6210: ${tarFile}`);
227
+ console.log(` \u914D\u7F6E GitHub: \u7F16\u8F91 ${CONFIG_PATH}`);
228
+ console.log(` \u6216\u624B\u52A8\u4E0A\u4F20\u5230 GitHub private repo release`);
229
+ return;
230
+ }
231
+ await uploadToGitHub(cfg, archiveFile, agentName, version, manifest);
232
+ }
233
+ async function doImport(opts) {
234
+ const { agentName, stateDir, version, dryRun: dryRun2 } = opts;
235
+ console.log(`\u{1F4E5} engine7 import`);
236
+ console.log(` agent: ${agentName}`);
237
+ console.log(` target: ${stateDir}`);
238
+ const cfg = loadTravelConfig();
239
+ if (!cfg || !cfg.githubToken) {
240
+ console.error(`\u274C \u672A\u914D\u7F6E GitHub\uFF0C\u65E0\u6CD5\u4E0B\u8F7D`);
241
+ console.error(` \u914D\u7F6E: \u7F16\u8F91 ${CONFIG_PATH}`);
242
+ process.exit(1);
243
+ }
244
+ const tmpDir = path.join(os.tmpdir(), `engine7-import-${agentName}-${Date.now()}`);
245
+ fs.mkdirSync(tmpDir, { recursive: true });
246
+ const archiveFile = await downloadFromGitHub(cfg, agentName, version, tmpDir);
247
+ console.log(`\u2705 \u4E0B\u8F7D\u5B8C\u6210: ${archiveFile}`);
248
+ if (dryRun2) {
249
+ console.log(`
250
+ [DRY RUN] \u53EA\u4E0B\u8F7D\u4E0D\u6062\u590D`);
251
+ return;
252
+ }
253
+ console.log(`\u{1F4C2} \u89E3\u5305\u4E2D...`);
254
+ if (archiveFile.endsWith(".tar.gz")) {
255
+ if (process.platform === "win32") {
256
+ execSync(`tar -xzf "${archiveFile}" -C "${tmpDir}"`, { stdio: "pipe" });
257
+ } else {
258
+ execSync(`tar -xzf "${archiveFile}" -C "${tmpDir}"`, { stdio: "pipe" });
259
+ }
260
+ } else {
261
+ if (process.platform === "win32") {
262
+ execSync(`powershell -Command "Expand-Archive -Path '${archiveFile}' -DestinationPath '${tmpDir}' -Force"`, { stdio: "pipe" });
263
+ } else {
264
+ execSync(`unzip -q -o "${archiveFile}" -d "${tmpDir}"`, { stdio: "pipe" });
265
+ }
266
+ }
267
+ const stagingDir = path.join(tmpDir, agentName);
268
+ const manifestPath = path.join(stagingDir, "manifest.json");
269
+ if (!fs.existsSync(manifestPath)) {
270
+ console.error(`\u274C manifest.json \u4E0D\u5B58\u5728\uFF0C\u6587\u4EF6\u53EF\u80FD\u635F\u574F`);
271
+ process.exit(1);
272
+ }
273
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
274
+ const workspace = path.join(stateDir, "workspace");
275
+ const engineHome = path.join(os.homedir(), ".openclaw");
276
+ const dirs = { workspace, stateDir, engineHome };
277
+ console.log(` \u7248\u672C: ${manifest.version}`);
278
+ console.log(` \u521B\u5EFA: ${manifest.createdAt}`);
279
+ console.log(` \u6587\u4EF6\u6570: ${manifest.fileCount}`);
280
+ const wsStaging = path.join(stagingDir, "workspace");
281
+ let restoredCount = 0;
282
+ if (fs.existsSync(wsStaging)) {
283
+ const allFiles = collectAllFiles(wsStaging);
284
+ for (const srcFile of allFiles) {
285
+ const relPath = path.relative(wsStaging, srcFile);
286
+ const destFile = path.join(workspace, relPath);
287
+ fs.mkdirSync(path.dirname(destFile), { recursive: true });
288
+ if (isTextFile(srcFile)) {
289
+ const content = fs.readFileSync(srcFile, "utf-8");
290
+ fs.writeFileSync(destFile, restoreContent(content, dirs));
291
+ } else {
292
+ fs.copyFileSync(srcFile, destFile);
293
+ }
294
+ restoredCount++;
295
+ }
296
+ }
297
+ const agentsStaging = path.join(stagingDir, "agents");
298
+ if (fs.existsSync(agentsStaging)) {
299
+ const sessionFiles = collectAllFiles(agentsStaging);
300
+ for (const srcFile of sessionFiles) {
301
+ const relPath = path.relative(stagingDir, srcFile);
302
+ const destFile = path.join(stateDir, relPath);
303
+ fs.mkdirSync(path.dirname(destFile), { recursive: true });
304
+ fs.copyFileSync(srcFile, destFile);
305
+ restoredCount++;
306
+ }
307
+ }
308
+ console.log(`\u2705 \u6062\u590D\u5B8C\u6210: ${restoredCount} \u6587\u4EF6 \u2192 ${stateDir}`);
309
+ console.log(`
310
+ \u{1F4A1} \u4E0B\u4E00\u6B65: engine7 start --config <path>`);
311
+ fs.rmSync(tmpDir, { recursive: true, force: true });
312
+ }
313
+ async function uploadToGitHub(cfg, archiveFile, agentName, version, manifest) {
314
+ const repo = `${cfg.githubOwner}/${cfg.repoName}`;
315
+ const tag = `${agentName}-${version}`;
316
+ console.log(`
317
+ \u{1F4E4} \u4E0A\u4F20\u5230 GitHub: ${repo} release ${tag}`);
318
+ try {
319
+ const releaseBody = Object.entries(manifest).map(([k, v]) => `- **${k}**: ${typeof v === "object" ? JSON.stringify(v) : v}`).join("\n");
320
+ const createRes = await fetch(`https://api.github.com/repos/${repo}/releases`, {
321
+ method: "POST",
322
+ headers: {
323
+ "Authorization": `Bearer ${cfg.githubToken}`,
324
+ "Accept": "application/vnd.github+json",
325
+ "Content-Type": "application/json"
326
+ },
327
+ body: JSON.stringify({
328
+ tag_name: tag,
329
+ name: `${agentName} ${version}`,
330
+ body: releaseBody,
331
+ prerelease: false,
332
+ make_latest: "true"
333
+ })
334
+ });
335
+ if (!createRes.ok) {
336
+ const err = await createRes.text();
337
+ throw new Error(`\u521B\u5EFA release \u5931\u8D25: ${createRes.status} ${err}`);
338
+ }
339
+ const release = await createRes.json();
340
+ const uploadUrl = release.upload_url.replace("{?name,label}", "");
341
+ const fileBuffer = fs.readFileSync(archiveFile);
342
+ const fileName = path.basename(archiveFile);
343
+ const uploadRes = await fetch(`${uploadUrl}?name=${fileName}`, {
344
+ method: "POST",
345
+ headers: {
346
+ "Authorization": `Bearer ${cfg.githubToken}`,
347
+ "Accept": "application/vnd.github+json",
348
+ "Content-Type": "application/zip",
349
+ "Content-Length": String(fileBuffer.length)
350
+ },
351
+ body: fileBuffer
352
+ });
353
+ if (!uploadRes.ok) {
354
+ const err = await uploadRes.text();
355
+ throw new Error(`\u4E0A\u4F20 asset \u5931\u8D25: ${uploadRes.status} ${err}`);
356
+ }
357
+ console.log(`\u2705 \u4E0A\u4F20\u6210\u529F!`);
358
+ console.log(` release: ${release.html_url}`);
359
+ } catch (e) {
360
+ console.error(`\u274C GitHub \u4E0A\u4F20\u5931\u8D25: ${e.message}`);
361
+ console.error(` archive \u4ECD\u5728: ${archiveFile}`);
362
+ throw e;
363
+ }
364
+ try {
365
+ fs.rmSync(path.dirname(archiveFile), { recursive: true, force: true });
366
+ } catch {
367
+ }
368
+ }
369
+ async function downloadFromGitHub(cfg, agentName, version, destDir) {
370
+ const repo = `${cfg.githubOwner}/${cfg.repoName}`;
371
+ const tag = version || await getLatestReleaseTag(cfg, agentName);
372
+ console.log(`\u2B07\uFE0F \u4E0B\u8F7D: ${repo} release ${tag}`);
373
+ const res = await fetch(`https://api.github.com/repos/${repo}/releases/tags/${tag}`, {
374
+ headers: {
375
+ "Authorization": `Bearer ${cfg.githubToken}`,
376
+ "Accept": "application/vnd.github+json"
377
+ }
378
+ });
379
+ if (!res.ok) {
380
+ throw new Error(`\u83B7\u53D6 release \u5931\u8D25: ${res.status}`);
381
+ }
382
+ const release = await res.json();
383
+ const asset = release.assets?.find((a) => a.name.endsWith(".zip") || a.name.endsWith(".tar.gz"));
384
+ if (!asset) {
385
+ throw new Error(`release ${tag} \u6CA1\u6709 zip/tar.gz asset`);
386
+ }
387
+ const downloadRes = await fetch(asset.url, {
388
+ headers: {
389
+ "Authorization": `Bearer ${cfg.githubToken}`,
390
+ "Accept": "application/octet-stream"
391
+ }
392
+ });
393
+ if (!downloadRes.ok) {
394
+ throw new Error(`\u4E0B\u8F7D asset \u5931\u8D25: ${downloadRes.status}`);
395
+ }
396
+ const buffer = Buffer.from(await downloadRes.arrayBuffer());
397
+ const archiveFile = path.join(destDir, asset.name);
398
+ fs.writeFileSync(archiveFile, buffer);
399
+ return archiveFile;
400
+ }
401
+ async function getLatestReleaseTag(cfg, agentName) {
402
+ const repo = `${cfg.githubOwner}/${cfg.repoName}`;
403
+ const res = await fetch(`https://api.github.com/repos/${repo}/releases?per_page=30`, {
404
+ headers: {
405
+ "Authorization": `Bearer ${cfg.githubToken}`,
406
+ "Accept": "application/vnd.github+json"
407
+ }
408
+ });
409
+ if (!res.ok) {
410
+ throw new Error(`\u83B7\u53D6 release \u5217\u8868\u5931\u8D25: ${res.status}`);
411
+ }
412
+ const releases = await res.json();
413
+ const match = releases.find((r) => r.tag_name?.startsWith(`${agentName}-`));
414
+ if (!match) {
415
+ throw new Error(`\u6CA1\u6709\u627E\u5230 ${agentName} \u7684 release`);
416
+ }
417
+ return match.tag_name;
418
+ }
419
+ var CONFIG_PATH, PATH_PLACEHOLDERS, WORKSPACE_INCLUDE, WORKSPACE_OPTIONAL, WORKSPACE_EXCLUDE, TEXT_EXTENSIONS;
420
+ var init_cli_travel = __esm({
421
+ "src/cli-travel.ts"() {
422
+ "use strict";
423
+ CONFIG_PATH = path.join(os.homedir(), ".engine7-travel.json");
424
+ PATH_PLACEHOLDERS = [
425
+ { placeholder: "{{WORKSPACE}}", getOriginal: (d) => d.workspace },
426
+ { placeholder: "{{ENGINE_HOME}}", getOriginal: (d) => d.engineHome },
427
+ { placeholder: "{{STATE_DIR}}", getOriginal: (d) => d.stateDir }
428
+ ];
429
+ WORKSPACE_INCLUDE = /* @__PURE__ */ new Set([
430
+ // 核心文件
431
+ "AGENTS.md",
432
+ "SOUL.md",
433
+ "MEMORY.md",
434
+ "USER.md",
435
+ "HEARTBEAT.md",
436
+ "INDEX.md",
437
+ "SESSION-STATE.md",
438
+ // 核心目录
439
+ "prompts",
440
+ "topics",
441
+ "memory",
442
+ "inner-voice",
443
+ "docs",
444
+ "skills",
445
+ "voice-chat",
446
+ "scripts",
447
+ "selfie",
448
+ "moodboard",
449
+ // 状态文件
450
+ "calendar.db",
451
+ "nudge-state.json"
452
+ ]);
453
+ WORKSPACE_OPTIONAL = /* @__PURE__ */ new Set([
454
+ "images",
455
+ "tools"
456
+ ]);
457
+ WORKSPACE_EXCLUDE = /* @__PURE__ */ new Set([
458
+ "livestream",
459
+ "content-library",
460
+ "tmp",
461
+ ".git",
462
+ "node_modules",
463
+ "memory_runs",
464
+ "workspace",
465
+ "prompt-archive",
466
+ "aim-archive",
467
+ "test-agent",
468
+ "nul",
469
+ "*.bak*",
470
+ "*.bak-*"
471
+ ]);
472
+ TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
473
+ ".md",
474
+ ".json",
475
+ ".txt",
476
+ ".js",
477
+ ".ts",
478
+ ".mjs",
479
+ ".py",
480
+ ".yaml",
481
+ ".yml",
482
+ ".cmd",
483
+ ".bat",
484
+ ".sh",
485
+ ".csv",
486
+ ".html"
487
+ ]);
488
+ }
489
+ });
490
+
491
+ // src/cli-init.ts
492
+ import * as path2 from "node:path";
493
+ import * as fs2 from "node:fs";
4
494
  import * as readline from "node:readline";
5
495
  import { fileURLToPath } from "node:url";
6
496
  var __filename = fileURLToPath(import.meta.url);
7
- var __dirname = path.dirname(__filename);
497
+ var __dirname = path2.dirname(__filename);
8
498
  var SCHEMA_VERSION = 1;
9
499
  function parseArgs() {
10
500
  const args = process.argv.slice(2);
@@ -26,10 +516,10 @@ function parseArgs() {
26
516
  }
27
517
  }
28
518
  if (!stateDir) {
29
- stateDir = path.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
519
+ stateDir = path2.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
30
520
  console.log(` \u4F7F\u7528\u9ED8\u8BA4\u76EE\u5F55: ${stateDir}`);
31
521
  }
32
- stateDir = path.resolve(stateDir);
522
+ stateDir = path2.resolve(stateDir);
33
523
  return { stateDir, quick, dryRun: dryRun2 };
34
524
  }
35
525
  function printHelp() {
@@ -41,6 +531,8 @@ Engine 7 \u2014 Self-hosted AI agent engine
41
531
  engine7 start [--config <path>] \u542F\u52A8 Engine
42
532
  engine7 restart [--config <path>] \u91CD\u542F Engine\uFF08\u6740\u65E7\u8FDB\u7A0B+\u542F\u52A8\uFF09
43
533
  engine7 service install|uninstall|status \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
534
+ engine7 export [--state-dir <path>] \u6253\u5305 agent workspace \u2192 GitHub release
535
+ engine7 import --state-dir <path> \u4ECE GitHub release \u6062\u590D agent
44
536
 
45
537
  init \u9009\u9879:
46
538
  --state-dir <path> agent \u6839\u76EE\u5F55\uFF08\u5FC5\u586B\uFF0C\u652F\u6301\u76F8\u5BF9\u8DEF\u5F84\uFF09
@@ -50,11 +542,25 @@ init \u9009\u9879:
50
542
  start \u9009\u9879:
51
543
  --config <path> config \u6587\u4EF6\u8DEF\u5F84\uFF08\u9ED8\u8BA4: configs/main7.json\uFF09
52
544
 
545
+ export \u9009\u9879:
546
+ --state-dir <path> agent \u6839\u76EE\u5F55\uFF08\u9ED8\u8BA4: \u5F53\u524D\u76EE\u5F55\u4E0A\u7EA7\uFF09
547
+ --agent <name> agent \u540D\u79F0\uFF08\u9ED8\u8BA4: state-dir basename\uFF09
548
+ --note <text> \u7248\u672C\u5907\u6CE8
549
+ --dry-run \u53EA\u5217\u51FA\u4F1A\u6253\u5305\u4EC0\u4E48\uFF0C\u4E0D\u5B9E\u9645\u4E0A\u4F20
550
+
551
+ import \u9009\u9879:
552
+ --state-dir <path> \u76EE\u6807 agent \u6839\u76EE\u5F55\uFF08\u5FC5\u586B\uFF09
553
+ --agent <name> agent \u540D\u79F0
554
+ --version <tag> \u6307\u5B9A\u7248\u672C\uFF08\u9ED8\u8BA4: \u6700\u65B0\uFF09
555
+ --dry-run \u53EA\u4E0B\u8F7D\u4E0D\u6062\u590D
556
+
53
557
  \u793A\u4F8B:
54
558
  engine7 init --state-dir D:/my-agent
55
559
  engine7 init --state-dir ./my-agent --quick
56
560
  engine7 start
57
561
  engine7 start --config configs/xiaowen.json
562
+ engine7 export --state-dir D:/xiaoke --agent xiaoke --note "travel test"
563
+ engine7 import --state-dir D:/xiaoke --agent xiaoke
58
564
  `);
59
565
  }
60
566
  function createReadline() {
@@ -166,7 +672,7 @@ async function interactiveConfig(rl, defaults) {
166
672
  return v;
167
673
  }
168
674
  function generateConfig(v) {
169
- const workspace = path.join(v.stateDir, "workspace").replace(/\\/g, "/");
675
+ const workspace = path2.join(v.stateDir, "workspace").replace(/\\/g, "/");
170
676
  const config = {
171
677
  schemaVersion: SCHEMA_VERSION,
172
678
  stateDir: v.stateDir.replace(/\\/g, "/"),
@@ -292,45 +798,45 @@ function generateConfig(v) {
292
798
  }
293
799
  function buildDirTree(v) {
294
800
  const d = v.stateDir;
295
- const w = path.join(d, "workspace");
801
+ const w = path2.join(d, "workspace");
296
802
  const now = (/* @__PURE__ */ new Date()).toLocaleString("sv-SE", { timeZone: "Asia/Shanghai", hour12: false });
297
803
  return [
298
804
  // 目录
299
- { path: path.join(d, "configs"), type: "dir" },
300
- { path: path.join(d, "state", "agents", "main", "sessions"), type: "dir" },
301
- { path: path.join(w, "prompts"), type: "dir" },
302
- { path: path.join(w, "memory", "daily"), type: "dir" },
303
- { path: path.join(w, "docs", "research"), type: "dir" },
304
- { path: path.join(w, "docs", "todo"), type: "dir" },
305
- { path: path.join(w, "docs", "decisions"), type: "dir" },
306
- { path: path.join(w, "docs", "knowledge"), type: "dir" },
307
- { path: path.join(w, "docs", "sop"), type: "dir" },
308
- { path: path.join(d, "logs"), type: "dir" },
309
- { path: path.join(d, "media", "inbound"), type: "dir" },
805
+ { path: path2.join(d, "configs"), type: "dir" },
806
+ { path: path2.join(d, "state", "agents", "main", "sessions"), type: "dir" },
807
+ { path: path2.join(w, "prompts"), type: "dir" },
808
+ { path: path2.join(w, "memory", "daily"), type: "dir" },
809
+ { path: path2.join(w, "docs", "research"), type: "dir" },
810
+ { path: path2.join(w, "docs", "todo"), type: "dir" },
811
+ { path: path2.join(w, "docs", "decisions"), type: "dir" },
812
+ { path: path2.join(w, "docs", "knowledge"), type: "dir" },
813
+ { path: path2.join(w, "docs", "sop"), type: "dir" },
814
+ { path: path2.join(d, "logs"), type: "dir" },
815
+ { path: path2.join(d, "media", "inbound"), type: "dir" },
310
816
  // workspace 文件
311
817
  {
312
- path: path.join(w, "SESSION-STATE.md"),
818
+ path: path2.join(w, "SESSION-STATE.md"),
313
819
  type: "file",
314
820
  content: readTemplate("workspace/SESSION-STATE.md").replace("{{CURRENT_TIME}}", now)
315
821
  },
316
- { path: path.join(w, "HEARTBEAT.md"), type: "file", content: readTemplate("workspace/HEARTBEAT.md") },
822
+ { path: path2.join(w, "HEARTBEAT.md"), type: "file", content: readTemplate("workspace/HEARTBEAT.md") },
317
823
  {
318
- path: path.join(w, "SOUL.md"),
824
+ path: path2.join(w, "SOUL.md"),
319
825
  type: "file",
320
826
  content: readTemplate("workspace/SOUL.md").replace(/\{\{AGENT_NAME\}\}/g, v.agentName)
321
827
  },
322
- { path: path.join(w, "AGENTS.md"), type: "file", content: readTemplate("workspace/AGENTS.md") },
828
+ { path: path2.join(w, "AGENTS.md"), type: "file", content: readTemplate("workspace/AGENTS.md") },
323
829
  {
324
- path: path.join(w, "prompts", "contacts.md"),
830
+ path: path2.join(w, "prompts", "contacts.md"),
325
831
  type: "file",
326
832
  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")
327
833
  },
328
- { path: path.join(w, "prompts", "auto-memory-instructions.md"), type: "file", content: readTemplate("workspace/prompts/auto-memory-instructions.md") },
329
- { path: path.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" },
330
- { path: path.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" },
834
+ { path: path2.join(w, "prompts", "auto-memory-instructions.md"), type: "file", content: readTemplate("workspace/prompts/auto-memory-instructions.md") },
835
+ { path: path2.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" },
836
+ { path: path2.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" },
331
837
  // package.json — 让 agent 目录成为独立 npm 项目根,防止 npm hoisting
332
838
  {
333
- path: path.join(d, "package.json"),
839
+ path: path2.join(d, "package.json"),
334
840
  type: "file",
335
841
  content: JSON.stringify({
336
842
  name: v.agentName.toLowerCase().replace(/[^a-z0-9-]/g, "-") || "agent",
@@ -341,7 +847,7 @@ function buildDirTree(v) {
341
847
  },
342
848
  // 启动脚本(根据 OS 生成)
343
849
  ...process.platform === "win32" ? [{
344
- path: path.join(d, "start.cmd"),
850
+ path: path2.join(d, "start.cmd"),
345
851
  type: "file",
346
852
  content: `@echo off
347
853
  rem Engine 7 startup script
@@ -373,7 +879,7 @@ if %ERRORLEVEL% NEQ 0 (
373
879
  )
374
880
  `
375
881
  }] : [{
376
- path: path.join(d, "start.sh"),
882
+ path: path2.join(d, "start.sh"),
377
883
  type: "file",
378
884
  content: `#!/bin/bash
379
885
  # Engine 7 startup script
@@ -406,13 +912,13 @@ node "$ENGINE7_BIN" --engine-config configs/main7.json
406
912
  }
407
913
  function readTemplate(relativePath) {
408
914
  const candidates = [
409
- path.join(__dirname, "..", "templates", relativePath),
410
- path.join(__dirname, "..", "..", "templates", relativePath),
411
- path.join(process.cwd(), "templates", relativePath)
915
+ path2.join(__dirname, "..", "templates", relativePath),
916
+ path2.join(__dirname, "..", "..", "templates", relativePath),
917
+ path2.join(process.cwd(), "templates", relativePath)
412
918
  ];
413
919
  for (const p of candidates) {
414
- if (fs.existsSync(p)) {
415
- return fs.readFileSync(p, "utf-8");
920
+ if (fs2.existsSync(p)) {
921
+ return fs2.readFileSync(p, "utf-8");
416
922
  }
417
923
  }
418
924
  throw new Error(`\u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${relativePath}\uFF08\u627E\u4E86: ${candidates.join(", ")}\uFF09`);
@@ -427,11 +933,11 @@ function dryRun(entries) {
427
933
  function execute(entries) {
428
934
  for (const e of entries) {
429
935
  if (e.type === "dir") {
430
- fs.mkdirSync(e.path, { recursive: true });
936
+ fs2.mkdirSync(e.path, { recursive: true });
431
937
  console.log(` \u{1F4C1} ${e.path}`);
432
938
  } else {
433
- fs.mkdirSync(path.dirname(e.path), { recursive: true });
434
- fs.writeFileSync(e.path, e.content || "", "utf-8");
939
+ fs2.mkdirSync(path2.dirname(e.path), { recursive: true });
940
+ fs2.writeFileSync(e.path, e.content || "", "utf-8");
435
941
  console.log(` \u{1F4C4} ${e.path}`);
436
942
  }
437
943
  }
@@ -447,6 +953,43 @@ async function main() {
447
953
  printHelp();
448
954
  process.exit(0);
449
955
  }
956
+ if (subcommand === "export") {
957
+ const { doExport: doExport2 } = await Promise.resolve().then(() => (init_cli_travel(), cli_travel_exports));
958
+ let exportStateDir = "";
959
+ let agentName = "";
960
+ let note = "";
961
+ let dryRun2 = false;
962
+ for (let i = 1; i < args.length; i++) {
963
+ if (args[i] === "--state-dir" && args[i + 1]) exportStateDir = args[++i];
964
+ else if (args[i] === "--agent" && args[i + 1]) agentName = args[++i];
965
+ else if (args[i] === "--note" && args[i + 1]) note = args[++i];
966
+ else if (args[i] === "--dry-run") dryRun2 = true;
967
+ }
968
+ if (!exportStateDir) exportStateDir = path2.resolve(process.cwd());
969
+ if (!agentName) agentName = path2.basename(exportStateDir);
970
+ await doExport2({ agentName, stateDir: exportStateDir, note, dryRun: dryRun2 });
971
+ process.exit(0);
972
+ }
973
+ if (subcommand === "import") {
974
+ const { doImport: doImport2 } = await Promise.resolve().then(() => (init_cli_travel(), cli_travel_exports));
975
+ let importStateDir = "";
976
+ let agentName = "";
977
+ let version = "";
978
+ let dryRun2 = false;
979
+ for (let i = 1; i < args.length; i++) {
980
+ if (args[i] === "--state-dir" && args[i + 1]) importStateDir = args[++i];
981
+ else if (args[i] === "--agent" && args[i + 1]) agentName = args[++i];
982
+ else if (args[i] === "--version" && args[i + 1]) version = args[++i];
983
+ else if (args[i] === "--dry-run") dryRun2 = true;
984
+ }
985
+ if (!importStateDir) {
986
+ console.error("\u274C import \u9700\u8981 --state-dir <path>");
987
+ process.exit(1);
988
+ }
989
+ if (!agentName) agentName = path2.basename(importStateDir);
990
+ await doImport2({ agentName, stateDir: importStateDir, version, dryRun: dryRun2 });
991
+ process.exit(0);
992
+ }
450
993
  if (subcommand === "start" || subcommand === "restart") {
451
994
  const label = subcommand === "restart" ? "\u{1F504} engine7 restart" : "\u{1F680} engine7 start";
452
995
  let configPath2 = "";
@@ -468,18 +1011,18 @@ engine7 start \u2014 \u542F\u52A8 Engine
468
1011
  }
469
1012
  }
470
1013
  if (!configPath2) {
471
- const defaultCfg = path.join("configs", "main7.json");
472
- const homeCfg = path.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
473
- if (fs.existsSync(defaultCfg)) {
1014
+ const defaultCfg = path2.join("configs", "main7.json");
1015
+ const homeCfg = path2.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
1016
+ if (fs2.existsSync(defaultCfg)) {
474
1017
  configPath2 = defaultCfg;
475
- } else if (fs.existsSync(homeCfg)) {
1018
+ } else if (fs2.existsSync(homeCfg)) {
476
1019
  configPath2 = homeCfg;
477
1020
  console.log(` \u4F7F\u7528\u9ED8\u8BA4 config: ${homeCfg}`);
478
1021
  } else {
479
1022
  const ptr = readHomePointer();
480
1023
  if (ptr?.stateDir) {
481
- const ptrCfg = path.join(ptr.stateDir, "configs", "main7.json");
482
- if (fs.existsSync(ptrCfg)) {
1024
+ const ptrCfg = path2.join(ptr.stateDir, "configs", "main7.json");
1025
+ if (fs2.existsSync(ptrCfg)) {
483
1026
  configPath2 = ptrCfg;
484
1027
  console.log(` \u4F7F\u7528 config: ${ptrCfg}`);
485
1028
  }
@@ -492,21 +1035,21 @@ engine7 start \u2014 \u542F\u52A8 Engine
492
1035
  }
493
1036
  }
494
1037
  }
495
- const { execSync, spawn } = await import("node:child_process");
1038
+ const { execSync: execSync2, spawn } = await import("node:child_process");
496
1039
  let enginePath;
497
- const localPath = path.join("node_modules", "engine7", "dist", "main.mjs");
498
- if (fs.existsSync(localPath)) {
1040
+ const localPath = path2.join("node_modules", "engine7", "dist", "main.mjs");
1041
+ if (fs2.existsSync(localPath)) {
499
1042
  enginePath = localPath;
500
1043
  } else {
501
- const cliPath = path.resolve(process.argv[1]);
502
- const distDir = path.dirname(cliPath);
503
- const candidate = path.join(distDir, "main.mjs");
504
- if (fs.existsSync(candidate)) {
1044
+ const cliPath = path2.resolve(process.argv[1]);
1045
+ const distDir = path2.dirname(cliPath);
1046
+ const candidate = path2.join(distDir, "main.mjs");
1047
+ if (fs2.existsSync(candidate)) {
505
1048
  enginePath = candidate;
506
1049
  } else {
507
1050
  try {
508
- const globalRoot = execSync("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
509
- enginePath = path.join(globalRoot, "engine7", "dist", "main.mjs");
1051
+ const globalRoot = execSync2("npm root -g", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
1052
+ enginePath = path2.join(globalRoot, "engine7", "dist", "main.mjs");
510
1053
  } catch {
511
1054
  console.error("\u274C \u627E\u4E0D\u5230 engine7 main.mjs");
512
1055
  process.exit(1);
@@ -516,17 +1059,17 @@ engine7 start \u2014 \u542F\u52A8 Engine
516
1059
  console.log(label);
517
1060
  console.log(` config: ${configPath2}`);
518
1061
  console.log(` engine: ${enginePath}`);
519
- const configName = path.basename(configPath2);
1062
+ const configName = path2.basename(configPath2);
520
1063
  const myPid = process.pid;
521
1064
  try {
522
1065
  if (process.platform === "win32") {
523
- execSync(`powershell -Command "Get-WmiObject Win32_Process | Where-Object { $_.Name -eq 'node.exe' -and $_.CommandLine -like '*${configName}*' -and $_.CommandLine -like '*dist*' -and $_.ProcessId -ne ${myPid} } | ForEach-Object { Write-Host '[start] Killing PID' $_.ProcessId; Stop-Process -Id $_.ProcessId -Force }"`, { stdio: "inherit" });
1066
+ execSync2(`powershell -Command "Get-WmiObject Win32_Process | Where-Object { $_.Name -eq 'node.exe' -and $_.CommandLine -like '*${configName}*' -and $_.CommandLine -like '*dist*' -and $_.ProcessId -ne ${myPid} } | ForEach-Object { Write-Host '[start] Killing PID' $_.ProcessId; Stop-Process -Id $_.ProcessId -Force }"`, { stdio: "inherit" });
524
1067
  } else {
525
- const pids = execSync(`pgrep -f "dist/main.mjs.*${configName}" 2>/dev/null || true`, { encoding: "utf-8" }).trim();
1068
+ const pids = execSync2(`pgrep -f "dist/main.mjs.*${configName}" 2>/dev/null || true`, { encoding: "utf-8" }).trim();
526
1069
  const otherPids = pids.split("\n").filter((p) => p && p.trim() !== String(myPid)).join("\n").trim();
527
1070
  if (otherPids) {
528
1071
  console.log(`[start] Killing existing engine (PID: ${otherPids})...`);
529
- execSync(`echo "${otherPids}" | xargs kill -9 2>/dev/null || true`);
1072
+ execSync2(`echo "${otherPids}" | xargs kill -9 2>/dev/null || true`);
530
1073
  await new Promise((r) => setTimeout(r, 2e3));
531
1074
  }
532
1075
  }
@@ -564,18 +1107,18 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
564
1107
  else if (args[i] === "--cwd" && args[i + 1]) cwd = args[++i];
565
1108
  }
566
1109
  if (!configPath2) {
567
- const defaultCfg = path.join(cwd, "configs", "main7.json");
568
- const homeCfg = path.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
569
- if (fs.existsSync(defaultCfg)) {
1110
+ const defaultCfg = path2.join(cwd, "configs", "main7.json");
1111
+ const homeCfg = path2.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7", "configs", "main7.json");
1112
+ if (fs2.existsSync(defaultCfg)) {
570
1113
  configPath2 = defaultCfg;
571
- } else if (fs.existsSync(homeCfg)) {
1114
+ } else if (fs2.existsSync(homeCfg)) {
572
1115
  configPath2 = homeCfg;
573
- cwd = path.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
1116
+ cwd = path2.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
574
1117
  } else {
575
1118
  const ptr = readHomePointer();
576
1119
  if (ptr?.stateDir) {
577
- const ptrCfg = path.join(ptr.stateDir, "configs", "main7.json");
578
- if (fs.existsSync(ptrCfg)) {
1120
+ const ptrCfg = path2.join(ptr.stateDir, "configs", "main7.json");
1121
+ if (fs2.existsSync(ptrCfg)) {
579
1122
  configPath2 = ptrCfg;
580
1123
  cwd = ptr.stateDir;
581
1124
  }
@@ -588,22 +1131,22 @@ engine7 service \u2014 \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
588
1131
  }
589
1132
  }
590
1133
  }
591
- const { execSync } = await import("node:child_process");
1134
+ const { execSync: execSync2 } = await import("node:child_process");
592
1135
  const engine7Bin = process.argv[1];
593
1136
  if (action === "install") {
594
1137
  if (process.platform === "win32") {
595
1138
  const taskName = "Engine7";
596
1139
  const nodeExe = process.execPath;
597
- const cliMjs = path.resolve(engine7Bin);
598
- const absConfig = path.resolve(configPath2);
599
- const wrapperPath = path.join(cwd, "engine7-start.cmd");
1140
+ const cliMjs = path2.resolve(engine7Bin);
1141
+ const absConfig = path2.resolve(configPath2);
1142
+ const wrapperPath = path2.join(cwd, "engine7-start.cmd");
600
1143
  const wrapperContent = `@echo off\r
601
1144
  cd /d "${cwd}"\r
602
1145
  "${nodeExe}" "${cliMjs}" start --config "${absConfig}"\r
603
1146
  `;
604
- fs.writeFileSync(wrapperPath, wrapperContent);
1147
+ fs2.writeFileSync(wrapperPath, wrapperContent);
605
1148
  try {
606
- execSync(`schtasks /create /tn "${taskName}" /tr "${wrapperPath}" /sc onlogon /rl highest /f`, { stdio: "inherit", shell: true });
1149
+ execSync2(`schtasks /create /tn "${taskName}" /tr "${wrapperPath}" /sc onlogon /rl highest /f`, { stdio: "inherit", shell: true });
607
1150
  console.log(`\u2705 Windows \u8BA1\u5212\u4EFB\u52A1 "${taskName}" \u5DF2\u521B\u5EFA\uFF08\u5F00\u673A\u81EA\u542F\u52A8\uFF09`);
608
1151
  console.log(` wrapper: ${wrapperPath}`);
609
1152
  } catch {
@@ -612,11 +1155,11 @@ cd /d "${cwd}"\r
612
1155
  }
613
1156
  } else if (process.platform === "darwin") {
614
1157
  const label = "com.engine7.agent";
615
- const plistDir = path.join(process.env.HOME, "Library", "LaunchAgents");
616
- fs.mkdirSync(plistDir, { recursive: true });
617
- const plistPath = path.join(plistDir, `${label}.plist`);
618
- const localCli = path.join("node_modules", "engine7", "dist", "cli.mjs");
619
- const cliMjs = fs.existsSync(localCli) ? path.resolve(localCli) : path.join(path.dirname(path.dirname(engine7Bin)), "lib", "node_modules", "engine7", "dist", "cli.mjs");
1158
+ const plistDir = path2.join(process.env.HOME, "Library", "LaunchAgents");
1159
+ fs2.mkdirSync(plistDir, { recursive: true });
1160
+ const plistPath = path2.join(plistDir, `${label}.plist`);
1161
+ const localCli = path2.join("node_modules", "engine7", "dist", "cli.mjs");
1162
+ const cliMjs = fs2.existsSync(localCli) ? path2.resolve(localCli) : path2.join(path2.dirname(path2.dirname(engine7Bin)), "lib", "node_modules", "engine7", "dist", "cli.mjs");
620
1163
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
621
1164
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
622
1165
  <plist version="1.0">
@@ -628,16 +1171,16 @@ cd /d "${cwd}"\r
628
1171
  <string>${cliMjs}</string>
629
1172
  <string>start</string>
630
1173
  <string>--config</string>
631
- <string>${path.resolve(configPath2)}</string>
1174
+ <string>${path2.resolve(configPath2)}</string>
632
1175
  </array>
633
1176
  <key>WorkingDirectory</key><string>${cwd}</string>
634
1177
  <key>RunAtLoad</key><true/>
635
1178
  <key>KeepAlive</key><true/>
636
1179
  </dict>
637
1180
  </plist>`;
638
- fs.writeFileSync(plistPath, plist);
1181
+ fs2.writeFileSync(plistPath, plist);
639
1182
  try {
640
- execSync(`launchctl load "${plistPath}"`, { stdio: "inherit" });
1183
+ execSync2(`launchctl load "${plistPath}"`, { stdio: "inherit" });
641
1184
  console.log(`\u2705 Mac launchd \u670D\u52A1\u5DF2\u521B\u5EFA\uFF08\u5F00\u673A\u81EA\u542F\u52A8\uFF09`);
642
1185
  console.log(` ${plistPath}`);
643
1186
  } catch {
@@ -646,9 +1189,9 @@ cd /d "${cwd}"\r
646
1189
  }
647
1190
  } else {
648
1191
  const svcName = "engine7";
649
- const svcDir = path.join(process.env.HOME, ".config", "systemd", "user");
650
- fs.mkdirSync(svcDir, { recursive: true });
651
- const svcPath = path.join(svcDir, `${svcName}.service`);
1192
+ const svcDir = path2.join(process.env.HOME, ".config", "systemd", "user");
1193
+ fs2.mkdirSync(svcDir, { recursive: true });
1194
+ const svcPath = path2.join(svcDir, `${svcName}.service`);
652
1195
  const svc = `[Unit]
653
1196
  Description=Engine 7 Agent
654
1197
  After=network.target
@@ -656,16 +1199,16 @@ After=network.target
656
1199
  [Service]
657
1200
  Type=simple
658
1201
  WorkingDirectory=${cwd}
659
- ExecStart=${process.execPath} ${engine7Bin} start --config ${path.resolve(configPath2)}
1202
+ ExecStart=${process.execPath} ${engine7Bin} start --config ${path2.resolve(configPath2)}
660
1203
  Restart=on-failure
661
1204
  RestartSec=10
662
1205
 
663
1206
  [Install]
664
1207
  WantedBy=default.target`;
665
- fs.writeFileSync(svcPath, svc);
1208
+ fs2.writeFileSync(svcPath, svc);
666
1209
  try {
667
- execSync(`systemctl --user daemon-reload`, { stdio: "inherit" });
668
- execSync(`systemctl --user enable ${svcName}`, { stdio: "inherit" });
1210
+ execSync2(`systemctl --user daemon-reload`, { stdio: "inherit" });
1211
+ execSync2(`systemctl --user enable ${svcName}`, { stdio: "inherit" });
669
1212
  console.log(`\u2705 systemd \u7528\u6237\u670D\u52A1\u5DF2\u521B\u5EFA\uFF08\u5F00\u673A\u81EA\u542F\u52A8\uFF09`);
670
1213
  console.log(` ${svcPath}`);
671
1214
  } catch {
@@ -676,35 +1219,35 @@ WantedBy=default.target`;
676
1219
  } else if (action === "uninstall") {
677
1220
  if (process.platform === "win32") {
678
1221
  try {
679
- execSync(`schtasks /delete /tn "Engine7" /f`, { stdio: "inherit", shell: true });
1222
+ execSync2(`schtasks /delete /tn "Engine7" /f`, { stdio: "inherit", shell: true });
680
1223
  console.log(`\u2705 Windows \u8BA1\u5212\u4EFB\u52A1\u5DF2\u5220\u9664`);
681
1224
  } catch {
682
1225
  console.error("\u274C \u5220\u9664\u5931\u8D25\uFF0C\u4EFB\u52A1\u53EF\u80FD\u4E0D\u5B58\u5728");
683
1226
  process.exit(1);
684
1227
  }
685
1228
  } else if (process.platform === "darwin") {
686
- const plistPath = path.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
1229
+ const plistPath = path2.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
687
1230
  try {
688
- execSync(`launchctl unload "${plistPath}"`, { stdio: "inherit" });
1231
+ execSync2(`launchctl unload "${plistPath}"`, { stdio: "inherit" });
689
1232
  } catch {
690
1233
  }
691
1234
  try {
692
- fs.unlinkSync(plistPath);
1235
+ fs2.unlinkSync(plistPath);
693
1236
  } catch {
694
1237
  }
695
1238
  console.log(`\u2705 Mac launchd \u670D\u52A1\u5DF2\u5220\u9664`);
696
1239
  } else {
697
1240
  try {
698
- execSync(`systemctl --user disable engine7`, { stdio: "inherit" });
1241
+ execSync2(`systemctl --user disable engine7`, { stdio: "inherit" });
699
1242
  } catch {
700
1243
  }
701
- const svcPath = path.join(process.env.HOME, ".config", "systemd", "user", "engine7.service");
1244
+ const svcPath = path2.join(process.env.HOME, ".config", "systemd", "user", "engine7.service");
702
1245
  try {
703
- fs.unlinkSync(svcPath);
1246
+ fs2.unlinkSync(svcPath);
704
1247
  } catch {
705
1248
  }
706
1249
  try {
707
- execSync(`systemctl --user daemon-reload`, { stdio: "inherit" });
1250
+ execSync2(`systemctl --user daemon-reload`, { stdio: "inherit" });
708
1251
  } catch {
709
1252
  }
710
1253
  console.log(`\u2705 systemd \u7528\u6237\u670D\u52A1\u5DF2\u5220\u9664`);
@@ -712,20 +1255,20 @@ WantedBy=default.target`;
712
1255
  } else if (action === "status") {
713
1256
  if (process.platform === "win32") {
714
1257
  try {
715
- execSync(`schtasks /query /tn "Engine7"`, { stdio: "inherit", shell: true });
1258
+ execSync2(`schtasks /query /tn "Engine7"`, { stdio: "inherit", shell: true });
716
1259
  } catch {
717
1260
  console.log("\u274C \u672A\u5B89\u88C5");
718
1261
  }
719
1262
  } else if (process.platform === "darwin") {
720
- const plistPath = path.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
721
- if (fs.existsSync(plistPath)) {
1263
+ const plistPath = path2.join(process.env.HOME, "Library", "LaunchAgents", "com.engine7.agent.plist");
1264
+ if (fs2.existsSync(plistPath)) {
722
1265
  console.log("\u2705 \u5DF2\u5B89\u88C5\uFF08launchd\uFF09");
723
1266
  } else {
724
1267
  console.log("\u274C \u672A\u5B89\u88C5");
725
1268
  }
726
1269
  } else {
727
1270
  try {
728
- execSync(`systemctl --user is-enabled engine7`, { stdio: "inherit" });
1271
+ execSync2(`systemctl --user is-enabled engine7`, { stdio: "inherit" });
729
1272
  } catch {
730
1273
  console.log("\u274C \u672A\u5B89\u88C5");
731
1274
  }
@@ -741,8 +1284,8 @@ WantedBy=default.target`;
741
1284
  console.log(`
742
1285
  \u{1F680} engine7 init`);
743
1286
  console.log(` state-dir: ${opts.stateDir}`);
744
- if (fs.existsSync(opts.stateDir) && !opts.dryRun) {
745
- const files = fs.readdirSync(opts.stateDir);
1287
+ if (fs2.existsSync(opts.stateDir) && !opts.dryRun) {
1288
+ const files = fs2.readdirSync(opts.stateDir);
746
1289
  if (files.length > 0) {
747
1290
  console.error(`
748
1291
  \u274C \u76EE\u5F55\u5DF2\u5B58\u5728\u4E14\u975E\u7A7A: ${opts.stateDir}`);
@@ -760,7 +1303,7 @@ WantedBy=default.target`;
760
1303
  rl.close();
761
1304
  }
762
1305
  const config = generateConfig(values);
763
- const configPath = path.join(opts.stateDir, "configs", "main7.json");
1306
+ const configPath = path2.join(opts.stateDir, "configs", "main7.json");
764
1307
  const tree = buildDirTree(values);
765
1308
  tree.push({
766
1309
  path: configPath,
@@ -771,9 +1314,9 @@ WantedBy=default.target`;
771
1314
  dryRun(tree);
772
1315
  const skillsSrc = findTemplateDir("skills");
773
1316
  if (skillsSrc) {
774
- const skills = fs.readdirSync(skillsSrc);
1317
+ const skills = fs2.readdirSync(skillsSrc);
775
1318
  for (const s of skills) {
776
- console.log(` \u{1F4C1} ${path.join(opts.stateDir, "workspace", "skills", s)}`);
1319
+ console.log(` \u{1F4C1} ${path2.join(opts.stateDir, "workspace", "skills", s)}`);
777
1320
  }
778
1321
  }
779
1322
  } else {
@@ -781,55 +1324,55 @@ WantedBy=default.target`;
781
1324
  execute(tree);
782
1325
  const skillsSrc = findTemplateDir("skills");
783
1326
  if (skillsSrc) {
784
- const skillsDest = path.join(opts.stateDir, "workspace", "skills");
785
- fs.mkdirSync(skillsDest, { recursive: true });
786
- const skills = fs.readdirSync(skillsSrc);
1327
+ const skillsDest = path2.join(opts.stateDir, "workspace", "skills");
1328
+ fs2.mkdirSync(skillsDest, { recursive: true });
1329
+ const skills = fs2.readdirSync(skillsSrc);
787
1330
  for (const s of skills) {
788
- copyDirRecursive(path.join(skillsSrc, s), path.join(skillsDest, s));
1331
+ copyDirRecursive(path2.join(skillsSrc, s), path2.join(skillsDest, s));
789
1332
  console.log(` \u{1F4E6} skill: ${s}`);
790
1333
  }
791
1334
  }
792
1335
  console.log(`
793
1336
  \u2705 \u521D\u59CB\u5316\u5B8C\u6210\uFF01
794
1337
  `);
795
- const homePointer = path.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
1338
+ const homePointer = path2.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
796
1339
  const pointerData = { stateDir: opts.stateDir };
797
- fs.writeFileSync(homePointer, JSON.stringify(pointerData, null, 2) + "\n");
1340
+ fs2.writeFileSync(homePointer, JSON.stringify(pointerData, null, 2) + "\n");
798
1341
  console.log(` \u{1F4C4} ${homePointer}\uFF08\u4ECE\u4EFB\u610F\u76EE\u5F55\u90FD\u80FD\u627E\u5230\u6B64 agent\uFF09`);
799
1342
  console.log(`\u4E0B\u4E00\u6B65\uFF1A`);
800
1343
  console.log(` 1. \u68C0\u67E5\u5E76\u4FEE\u6539 ${opts.stateDir}/configs/main7.json`);
801
1344
  console.log(` 2. \u542F\u52A8 Engine: engine7 start\uFF08\u5728\u4EFB\u610F\u76EE\u5F55\u90FD\u884C\uFF09`);
802
1345
  console.log(` 3. \u5F00\u673A\u81EA\u542F: engine7 service install\uFF08\u5728\u4EFB\u610F\u76EE\u5F55\u90FD\u884C\uFF09`);
803
- console.log(` 4. \u67E5\u770B workspace: ${path.join(opts.stateDir, "workspace")}`);
1346
+ console.log(` 4. \u67E5\u770B workspace: ${path2.join(opts.stateDir, "workspace")}`);
804
1347
  }
805
1348
  }
806
1349
  function copyDirRecursive(src, dest) {
807
- fs.mkdirSync(dest, { recursive: true });
808
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
809
- const srcPath = path.join(src, entry.name);
810
- const destPath = path.join(dest, entry.name);
1350
+ fs2.mkdirSync(dest, { recursive: true });
1351
+ for (const entry of fs2.readdirSync(src, { withFileTypes: true })) {
1352
+ const srcPath = path2.join(src, entry.name);
1353
+ const destPath = path2.join(dest, entry.name);
811
1354
  if (entry.isDirectory()) {
812
1355
  copyDirRecursive(srcPath, destPath);
813
1356
  } else {
814
- fs.copyFileSync(srcPath, destPath);
1357
+ fs2.copyFileSync(srcPath, destPath);
815
1358
  }
816
1359
  }
817
1360
  }
818
1361
  function findTemplateDir(name) {
819
1362
  const candidates = [
820
- path.join(__dirname, "..", "templates", name),
821
- path.join(__dirname, "..", "..", "templates", name),
822
- path.join(process.cwd(), "templates", name)
1363
+ path2.join(__dirname, "..", "templates", name),
1364
+ path2.join(__dirname, "..", "..", "templates", name),
1365
+ path2.join(process.cwd(), "templates", name)
823
1366
  ];
824
1367
  for (const p of candidates) {
825
- if (fs.existsSync(p)) return p;
1368
+ if (fs2.existsSync(p)) return p;
826
1369
  }
827
1370
  return null;
828
1371
  }
829
1372
  function readHomePointer() {
830
- const ptrPath = path.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
1373
+ const ptrPath = path2.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7.json");
831
1374
  try {
832
- return JSON.parse(fs.readFileSync(ptrPath, "utf-8"));
1375
+ return JSON.parse(fs2.readFileSync(ptrPath, "utf-8"));
833
1376
  } catch {
834
1377
  return null;
835
1378
  }