xiaozuoassistant 0.1.58 → 0.1.60

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.
Files changed (3) hide show
  1. package/README.md +6 -2
  2. package/bin/cli.js +95 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -4,7 +4,7 @@ xiaozuoAssistant 是一个**本地优先(Local-first)**的个人 AI 助手
4
4
 
5
5
  ## 亮点能力
6
6
 
7
- - **Web UI + 实时通信**:浏览器访问 `http://localhost:3001`,Socket.IO 实时收发消息。
7
+ - **Web UI + 实时通信**:浏览器访问 `http://localhost:3021`(生产环境)或 `http://localhost:3001`(开发环境),Socket.IO 实时收发消息。
8
8
  - **多通道(Channels)**:内置 Web/Terminal,并可按配置启用 Telegram/飞书/钉钉/微信等。
9
9
  - **技能(Skills)+ 工具调用**:模型可触发工具调用(OpenAI tools 兼容格式),技能注册表可扩展。
10
10
  - **增强型记忆系统(Enhanced Memory)**:
@@ -24,7 +24,7 @@ npm install -g xiaozuoassistant --registry=https://registry.npmjs.org
24
24
  xiaozuoAssistant start
25
25
  ```
26
26
 
27
- 然后浏览器打开:`http://localhost:3001`
27
+ 然后浏览器打开:`http://localhost:3021`
28
28
 
29
29
  停止服务:
30
30
 
@@ -46,6 +46,8 @@ xiaozuoAssistant stop
46
46
 
47
47
  ### 开发模式(前后端联调)
48
48
 
49
+ 端口默认为 `3001`。
50
+
49
51
  ```bash
50
52
  npm install
51
53
  npm run dev
@@ -53,6 +55,8 @@ npm run dev
53
55
 
54
56
  ### 生产模式(构建后运行)
55
57
 
58
+ 端口默认为 `3021`。
59
+
56
60
  ```bash
57
61
  npm install
58
62
  npm run build
package/bin/cli.js CHANGED
@@ -28,7 +28,9 @@ const args = process.argv.slice(2);
28
28
  const command = args[0];
29
29
  const commandArgs = args.slice(1);
30
30
 
31
- const EXPORT_FILENAME = 'xiaozuoAssistant-backup.tar.gz';
31
+ const EXPORT_FILENAME_PREFIX = 'xiaozuoAssistant-backup';
32
+ const PRODUCTION_PORT = 3021; // 生产环境(CLI)默认端口
33
+ const DEV_PORT = 3001; // 开发环境默认端口
32
34
 
33
35
  // Helper to get user's current working directory where they ran the command
34
36
  // This is kept only for display/backward compatibility; runtime data is stored in APP_HOME.
@@ -50,7 +52,8 @@ const DATA_PATHS = [
50
52
  'data',
51
53
  'logs',
52
54
  'sessions',
53
- 'workspace'
55
+ 'workspace',
56
+ 'plugins'
54
57
  ];
55
58
 
56
59
  function ensureAppHome() {
@@ -65,11 +68,37 @@ function ensureAppHome() {
65
68
 
66
69
  function ensureDefaultConfig() {
67
70
  const configPath = path.join(APP_HOME, 'config.json');
68
- if (fs.existsSync(configPath)) return;
71
+
72
+ // 如果配置文件已存在,检查是否需要迁移端口(例如从 3001 迁移到 3021)
73
+ if (fs.existsSync(configPath)) {
74
+ try {
75
+ const configContent = fs.readFileSync(configPath, 'utf-8');
76
+ const config = JSON.parse(configContent);
77
+ // 如果端口是旧的默认值 3001,自动更新为 3021
78
+ if (config.server && config.server.port === DEV_PORT) {
79
+ console.log(`[CLI] 检测到旧端口配置 (${DEV_PORT}),正在迁移到生产环境端口 (${PRODUCTION_PORT})...`);
80
+ config.server.port = PRODUCTION_PORT;
81
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
82
+ console.log(`[CLI] ✅ 端口已更新为 ${PRODUCTION_PORT}`);
83
+ }
84
+ } catch (e) {
85
+ console.warn('[CLI] 检查现有配置失败:', e);
86
+ }
87
+ return;
88
+ }
89
+
90
+ // 如果配置文件不存在,创建新的默认配置
69
91
  const templatePath = path.join(packageRoot, 'config.json');
70
92
  try {
71
93
  if (fs.existsSync(templatePath)) {
72
- fs.copyFileSync(templatePath, configPath);
94
+ // 复制模板,但强制修改端口为 3021
95
+ const templateContent = fs.readFileSync(templatePath, 'utf-8');
96
+ const templateConfig = JSON.parse(templateContent);
97
+
98
+ if (!templateConfig.server) templateConfig.server = {};
99
+ templateConfig.server.port = PRODUCTION_PORT;
100
+
101
+ fs.writeFileSync(configPath, JSON.stringify(templateConfig, null, 2));
73
102
  return;
74
103
  }
75
104
  } catch (e) {
@@ -77,7 +106,7 @@ function ensureDefaultConfig() {
77
106
  }
78
107
 
79
108
  const fallback = {
80
- server: { port: 3001, host: 'localhost' },
109
+ server: { port: PRODUCTION_PORT, host: 'localhost' },
81
110
  llm: { apiKey: '', baseURL: '', model: '', temperature: 0.7 },
82
111
  logging: { level: 'info' },
83
112
  channels: {},
@@ -103,7 +132,7 @@ function ensureDefaultDirs() {
103
132
  }
104
133
 
105
134
  function getPortFromConfig() {
106
- let port = 3001;
135
+ let port = PRODUCTION_PORT;
107
136
  const configPath = path.join(APP_HOME, 'config.json');
108
137
  if (fs.existsSync(configPath)) {
109
138
  try {
@@ -396,6 +425,11 @@ async function exportData() {
396
425
  ensureDefaultDirs();
397
426
  console.log('📦 Starting data export...');
398
427
 
428
+ // Generate filename with timestamp
429
+ const now = new Date();
430
+ const timestamp = now.toISOString().replace(/[-:T.]/g, '').slice(0, 14); // YYYYMMDDHHmmss
431
+ const exportFilename = `${EXPORT_FILENAME_PREFIX}-${timestamp}.tar.gz`;
432
+
399
433
  const filesToArchive = [];
400
434
 
401
435
  for (const p of DATA_PATHS) {
@@ -410,16 +444,19 @@ async function exportData() {
410
444
  return;
411
445
  }
412
446
 
447
+ const exportPath = path.join(APP_HOME, exportFilename);
448
+
413
449
  try {
414
450
  await tar.c(
415
451
  {
416
452
  gzip: true,
417
- file: path.join(APP_HOME, EXPORT_FILENAME),
453
+ file: exportPath,
418
454
  cwd: APP_HOME
419
455
  },
420
456
  filesToArchive
421
457
  );
422
- console.log(`✅ Export successful! Backup created at: ${path.join(APP_HOME, EXPORT_FILENAME)}`);
458
+ console.log(`✅ Export successful!`);
459
+ console.log(` Backup file: ${exportPath}`);
423
460
  console.log(` Copy this file to your new machine to import.`);
424
461
  } catch (err) {
425
462
  console.error('❌ Export failed:', err);
@@ -428,15 +465,49 @@ async function exportData() {
428
465
 
429
466
  async function importData() {
430
467
  ensureAppHome();
431
- const backupPath = path.join(APP_HOME, EXPORT_FILENAME);
468
+
469
+ // Find backup file
470
+ let backupFile = getFlagValue('--file');
471
+
472
+ if (!backupFile) {
473
+ // Try to find the latest backup file in APP_HOME
474
+ try {
475
+ const files = fs.readdirSync(APP_HOME)
476
+ .filter(f => f.startsWith(EXPORT_FILENAME_PREFIX) && f.endsWith('.tar.gz'))
477
+ .sort()
478
+ .reverse();
479
+
480
+ if (files.length > 0) {
481
+ backupFile = path.join(APP_HOME, files[0]);
482
+ console.log(`[CLI] No file specified, using latest found: ${files[0]}`);
483
+ } else {
484
+ // Fallback to old filename for compatibility
485
+ const oldFile = path.join(APP_HOME, 'xiaozuoAssistant-backup.tar.gz');
486
+ if (fs.existsSync(oldFile)) {
487
+ backupFile = oldFile;
488
+ console.log(`[CLI] Using legacy backup file: xiaozuoAssistant-backup.tar.gz`);
489
+ }
490
+ }
491
+ } catch (e) {
492
+ // ignore
493
+ }
494
+ }
495
+
496
+ if (!backupFile) {
497
+ console.error(`❌ No backup file found or specified.`);
498
+ console.log(` Use --file <path> to specify a backup file.`);
499
+ return;
500
+ }
501
+
502
+ // Resolve absolute path
503
+ const backupPath = path.resolve(process.cwd(), backupFile);
432
504
 
433
505
  if (!fs.existsSync(backupPath)) {
434
506
  console.error(`❌ Backup file not found: ${backupPath}`);
435
- console.log(` Please ensure '${EXPORT_FILENAME}' is in ${APP_HOME}`);
436
507
  return;
437
508
  }
438
509
 
439
- console.log('📦 Starting data import...');
510
+ console.log(`📦 Starting data import from: ${backupPath}`);
440
511
  console.log('⚠️ Warning: This will overwrite existing data files (config.json, memories, etc.)');
441
512
 
442
513
  // Simple prompt implementation for Node.js
@@ -445,6 +516,13 @@ async function importData() {
445
516
  const answer = data.toString().trim().toLowerCase();
446
517
  if (answer === 'y' || answer === 'yes') {
447
518
  try {
519
+ // Stop server if running before import
520
+ const pidFile = getPidFilePath();
521
+ if (fs.existsSync(pidFile)) {
522
+ console.log('[CLI] Stopping server before import...');
523
+ await stopServer();
524
+ }
525
+
448
526
  await tar.x({
449
527
  file: backupPath,
450
528
  cwd: APP_HOME
@@ -472,6 +550,12 @@ async function importData() {
472
550
  }
473
551
  }
474
552
 
553
+ // Ensure port is set to production port if it was dev port
554
+ if (config.server && config.server.port === DEV_PORT) {
555
+ config.server.port = PRODUCTION_PORT;
556
+ console.log(`[CLI] Updated port from ${DEV_PORT} to ${PRODUCTION_PORT}`);
557
+ }
558
+
475
559
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
476
560
  console.log(`✅ Auto-configured workspace path to: ${APP_HOME}`);
477
561
  } catch (e) {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "xiaozuoassistant",
3
3
  "private": false,
4
4
  "description": "Your personal, locally-hosted AI assistant for office productivity.",
5
- "version": "0.1.58",
5
+ "version": "0.1.60",
6
6
  "author": "mantle.lau",
7
7
  "license": "MIT",
8
8
  "repository": {