xiaozuoassistant 0.1.47 → 0.1.48
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/bin/cli.js +101 -27
- package/package.json +3 -2
- package/scripts/init-app-home.cjs +43 -0
package/bin/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ import { spawn } from 'child_process';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import fs from 'fs';
|
|
7
|
+
import os from 'os';
|
|
7
8
|
import { createGzip } from 'zlib';
|
|
8
9
|
import { pipeline } from 'stream';
|
|
9
10
|
import { promisify } from 'util';
|
|
@@ -28,20 +29,80 @@ const commandArgs = args.slice(1);
|
|
|
28
29
|
const EXPORT_FILENAME = 'xiaozuoAssistant-backup.tar.gz';
|
|
29
30
|
|
|
30
31
|
// Helper to get user's current working directory where they ran the command
|
|
32
|
+
// This is kept only for display/backward compatibility; runtime data is stored in APP_HOME.
|
|
31
33
|
const CWD = process.cwd();
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
function getAppHome() {
|
|
36
|
+
const fromFlag = getFlagValue('--home');
|
|
37
|
+
const fromEnv = process.env.XIAOZUOASSISTANT_HOME;
|
|
38
|
+
const base = (fromFlag || fromEnv || path.join(os.homedir(), '.xiaozuoassistant')).trim();
|
|
39
|
+
return path.resolve(base);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const APP_HOME = getAppHome();
|
|
43
|
+
|
|
44
|
+
// Unified runtime data directory
|
|
35
45
|
const DATA_PATHS = [
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
46
|
+
'config.json',
|
|
47
|
+
'memories',
|
|
48
|
+
'data',
|
|
49
|
+
'logs',
|
|
50
|
+
'sessions',
|
|
51
|
+
'workspace'
|
|
40
52
|
];
|
|
41
53
|
|
|
54
|
+
function ensureAppHome() {
|
|
55
|
+
try {
|
|
56
|
+
fs.mkdirSync(APP_HOME, { recursive: true });
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.error(`[CLI] 无法创建数据目录:${APP_HOME}`);
|
|
59
|
+
console.error(e);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function ensureDefaultConfig() {
|
|
65
|
+
const configPath = path.join(APP_HOME, 'config.json');
|
|
66
|
+
if (fs.existsSync(configPath)) return;
|
|
67
|
+
const templatePath = path.join(packageRoot, 'config.json');
|
|
68
|
+
try {
|
|
69
|
+
if (fs.existsSync(templatePath)) {
|
|
70
|
+
fs.copyFileSync(templatePath, configPath);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
} catch (e) {
|
|
74
|
+
// ignore
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const fallback = {
|
|
78
|
+
server: { port: 3001, host: 'localhost' },
|
|
79
|
+
llm: { apiKey: '', baseURL: '', model: '', temperature: 0.7 },
|
|
80
|
+
logging: { level: 'info' },
|
|
81
|
+
channels: {},
|
|
82
|
+
systemPrompt: ''
|
|
83
|
+
};
|
|
84
|
+
try {
|
|
85
|
+
fs.writeFileSync(configPath, JSON.stringify(fallback, null, 2));
|
|
86
|
+
} catch (e) {
|
|
87
|
+
console.error(`[CLI] 无法写入默认配置:${configPath}`);
|
|
88
|
+
console.error(e);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function ensureDefaultDirs() {
|
|
94
|
+
for (const dir of ['logs', 'data', 'memories', 'sessions', 'workspace']) {
|
|
95
|
+
try {
|
|
96
|
+
fs.mkdirSync(path.join(APP_HOME, dir), { recursive: true });
|
|
97
|
+
} catch {
|
|
98
|
+
// ignore
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
42
103
|
function getPortFromConfig() {
|
|
43
104
|
let port = 3001;
|
|
44
|
-
const configPath = path.join(
|
|
105
|
+
const configPath = path.join(APP_HOME, 'config.json');
|
|
45
106
|
if (fs.existsSync(configPath)) {
|
|
46
107
|
try {
|
|
47
108
|
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
@@ -56,7 +117,7 @@ function getPortFromConfig() {
|
|
|
56
117
|
}
|
|
57
118
|
|
|
58
119
|
function getPidFilePath() {
|
|
59
|
-
return path.join(
|
|
120
|
+
return path.join(APP_HOME, 'logs', 'server.pid');
|
|
60
121
|
}
|
|
61
122
|
|
|
62
123
|
function hasFlag(flag) {
|
|
@@ -247,7 +308,7 @@ async function updateApp() {
|
|
|
247
308
|
console.error('[CLI] ❌ 更新失败。');
|
|
248
309
|
if (wasRunning) {
|
|
249
310
|
console.log('[CLI] 更新失败,尝试恢复启动旧版本服务...');
|
|
250
|
-
await runCommand('node', [path.join(packageRoot, 'bin', 'cli.js'), 'start'], { cwd:
|
|
311
|
+
await runCommand('node', [path.join(packageRoot, 'bin', 'cli.js'), 'start'], { cwd: APP_HOME });
|
|
251
312
|
}
|
|
252
313
|
process.exit(code);
|
|
253
314
|
}
|
|
@@ -256,7 +317,7 @@ async function updateApp() {
|
|
|
256
317
|
|
|
257
318
|
if (wasRunning) {
|
|
258
319
|
console.log('[CLI] 正在自动重启服务...');
|
|
259
|
-
const restartCode = await runCommand('xiaozuoAssistant', ['start'], { cwd:
|
|
320
|
+
const restartCode = await runCommand('xiaozuoAssistant', ['start'], { cwd: APP_HOME });
|
|
260
321
|
process.exit(restartCode);
|
|
261
322
|
}
|
|
262
323
|
}
|
|
@@ -264,7 +325,7 @@ async function updateApp() {
|
|
|
264
325
|
async function removeApp() {
|
|
265
326
|
const registry = getRegistry();
|
|
266
327
|
const targets = ['config.json', 'memories', 'data', 'logs', 'sessions', 'workspace']
|
|
267
|
-
.map(p => path.join(
|
|
328
|
+
.map(p => path.join(APP_HOME, p));
|
|
268
329
|
|
|
269
330
|
const doRemove = async () => {
|
|
270
331
|
await stopServer();
|
|
@@ -329,12 +390,14 @@ function printVersion() {
|
|
|
329
390
|
}
|
|
330
391
|
|
|
331
392
|
async function exportData() {
|
|
393
|
+
ensureAppHome();
|
|
394
|
+
ensureDefaultDirs();
|
|
332
395
|
console.log('📦 Starting data export...');
|
|
333
396
|
|
|
334
397
|
const filesToArchive = [];
|
|
335
398
|
|
|
336
399
|
for (const p of DATA_PATHS) {
|
|
337
|
-
if (fs.existsSync(path.join(
|
|
400
|
+
if (fs.existsSync(path.join(APP_HOME, p))) {
|
|
338
401
|
filesToArchive.push(p);
|
|
339
402
|
console.log(` - Found: ${p}`);
|
|
340
403
|
}
|
|
@@ -349,12 +412,12 @@ async function exportData() {
|
|
|
349
412
|
await tar.c(
|
|
350
413
|
{
|
|
351
414
|
gzip: true,
|
|
352
|
-
file: EXPORT_FILENAME,
|
|
353
|
-
cwd:
|
|
415
|
+
file: path.join(APP_HOME, EXPORT_FILENAME),
|
|
416
|
+
cwd: APP_HOME
|
|
354
417
|
},
|
|
355
418
|
filesToArchive
|
|
356
419
|
);
|
|
357
|
-
console.log(`✅ Export successful! Backup created at: ${path.join(
|
|
420
|
+
console.log(`✅ Export successful! Backup created at: ${path.join(APP_HOME, EXPORT_FILENAME)}`);
|
|
358
421
|
console.log(` Copy this file to your new machine to import.`);
|
|
359
422
|
} catch (err) {
|
|
360
423
|
console.error('❌ Export failed:', err);
|
|
@@ -362,11 +425,12 @@ async function exportData() {
|
|
|
362
425
|
}
|
|
363
426
|
|
|
364
427
|
async function importData() {
|
|
365
|
-
|
|
428
|
+
ensureAppHome();
|
|
429
|
+
const backupPath = path.join(APP_HOME, EXPORT_FILENAME);
|
|
366
430
|
|
|
367
431
|
if (!fs.existsSync(backupPath)) {
|
|
368
432
|
console.error(`❌ Backup file not found: ${backupPath}`);
|
|
369
|
-
console.log(` Please ensure '${EXPORT_FILENAME}' is in
|
|
433
|
+
console.log(` Please ensure '${EXPORT_FILENAME}' is in ${APP_HOME}`);
|
|
370
434
|
return;
|
|
371
435
|
}
|
|
372
436
|
|
|
@@ -380,13 +444,13 @@ async function importData() {
|
|
|
380
444
|
if (answer === 'y' || answer === 'yes') {
|
|
381
445
|
try {
|
|
382
446
|
await tar.x({
|
|
383
|
-
file:
|
|
384
|
-
cwd:
|
|
447
|
+
file: backupPath,
|
|
448
|
+
cwd: APP_HOME
|
|
385
449
|
});
|
|
386
450
|
console.log('✅ Import successful! Data restored.');
|
|
387
451
|
|
|
388
452
|
// Auto-configure workspace path in config.json
|
|
389
|
-
const configPath = path.join(
|
|
453
|
+
const configPath = path.join(APP_HOME, 'config.json');
|
|
390
454
|
if (fs.existsSync(configPath)) {
|
|
391
455
|
try {
|
|
392
456
|
const configContent = fs.readFileSync(configPath, 'utf-8');
|
|
@@ -394,20 +458,20 @@ async function importData() {
|
|
|
394
458
|
|
|
395
459
|
// Update workspace to current directory
|
|
396
460
|
const oldWorkspace = config.workspace;
|
|
397
|
-
config.workspace =
|
|
461
|
+
config.workspace = APP_HOME;
|
|
398
462
|
|
|
399
463
|
// Also update System Prompt if it contains the old workspace path
|
|
400
464
|
if (config.systemPrompt && typeof config.systemPrompt === 'string') {
|
|
401
465
|
if (oldWorkspace && config.systemPrompt.includes(oldWorkspace)) {
|
|
402
|
-
config.systemPrompt = config.systemPrompt.replace(oldWorkspace,
|
|
466
|
+
config.systemPrompt = config.systemPrompt.replace(oldWorkspace, APP_HOME);
|
|
403
467
|
} else if (config.systemPrompt.includes('Current Workspace:')) {
|
|
404
468
|
// Fallback regex replacement if exact string match fails
|
|
405
|
-
config.systemPrompt = config.systemPrompt.replace(/Current Workspace: .*/, `Current Workspace: ${
|
|
469
|
+
config.systemPrompt = config.systemPrompt.replace(/Current Workspace: .*/, `Current Workspace: ${APP_HOME}`);
|
|
406
470
|
}
|
|
407
471
|
}
|
|
408
472
|
|
|
409
473
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
410
|
-
console.log(`✅ Auto-configured workspace path to: ${
|
|
474
|
+
console.log(`✅ Auto-configured workspace path to: ${APP_HOME}`);
|
|
411
475
|
} catch (e) {
|
|
412
476
|
console.warn('⚠️ Failed to auto-update config.json path:', e);
|
|
413
477
|
}
|
|
@@ -425,12 +489,15 @@ async function importData() {
|
|
|
425
489
|
}
|
|
426
490
|
|
|
427
491
|
if (command === 'start') {
|
|
492
|
+
ensureAppHome();
|
|
493
|
+
ensureDefaultDirs();
|
|
494
|
+
ensureDefaultConfig();
|
|
428
495
|
console.log('Starting xiaozuoAssistant...');
|
|
429
496
|
|
|
430
497
|
const serverPath = path.join(packageRoot, 'dist', 'server', 'index.js');
|
|
431
498
|
|
|
432
|
-
// Ensure logs directory exists in
|
|
433
|
-
const logDir = path.join(
|
|
499
|
+
// Ensure logs directory exists in APP_HOME
|
|
500
|
+
const logDir = path.join(APP_HOME, 'logs');
|
|
434
501
|
if (!fs.existsSync(logDir)) {
|
|
435
502
|
try {
|
|
436
503
|
fs.mkdirSync(logDir, { recursive: true });
|
|
@@ -481,7 +548,7 @@ if (command === 'start') {
|
|
|
481
548
|
const child = spawn('node', [serverPath, ...args.slice(1)], {
|
|
482
549
|
detached: true, // Allow child to run independently
|
|
483
550
|
stdio: ['ignore', out, err], // Disconnect stdin, redirect stdout/stderr
|
|
484
|
-
cwd:
|
|
551
|
+
cwd: APP_HOME, // Run in unified app home
|
|
485
552
|
env: {
|
|
486
553
|
...process.env,
|
|
487
554
|
NODE_ENV: 'production'
|
|
@@ -550,6 +617,8 @@ if (command === 'start') {
|
|
|
550
617
|
process.exit(1);
|
|
551
618
|
}
|
|
552
619
|
} else if (command === 'doctor') {
|
|
620
|
+
ensureAppHome();
|
|
621
|
+
ensureDefaultDirs();
|
|
553
622
|
console.log('Running doctor check...');
|
|
554
623
|
try {
|
|
555
624
|
const pkgPath = path.join(packageRoot, 'package.json');
|
|
@@ -563,6 +632,7 @@ if (command === 'start') {
|
|
|
563
632
|
console.log('Node Version:', process.version);
|
|
564
633
|
console.log('Doctor check complete.');
|
|
565
634
|
} else if (command === 'version') {
|
|
635
|
+
ensureAppHome();
|
|
566
636
|
printVersion();
|
|
567
637
|
} else if (command === 'update') {
|
|
568
638
|
updateApp();
|
|
@@ -573,6 +643,7 @@ if (command === 'start') {
|
|
|
573
643
|
} else if (command === 'import') {
|
|
574
644
|
importData();
|
|
575
645
|
} else if (command === 'stop') {
|
|
646
|
+
ensureAppHome();
|
|
576
647
|
stopServer();
|
|
577
648
|
} else {
|
|
578
649
|
console.log('Usage: xiaozuoAssistant <command>');
|
|
@@ -585,4 +656,7 @@ if (command === 'start') {
|
|
|
585
656
|
console.log(' remove Uninstall and delete data in current directory');
|
|
586
657
|
console.log(' export Backup local data (config, memories) to a file');
|
|
587
658
|
console.log(' import Restore data from a backup file');
|
|
659
|
+
console.log('');
|
|
660
|
+
console.log(`Data Dir: ${APP_HOME}`);
|
|
661
|
+
console.log(' Use --home <path> or env XIAOZUOASSISTANT_HOME to override.');
|
|
588
662
|
}
|
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.
|
|
5
|
+
"version": "0.1.48",
|
|
6
6
|
"author": "mantle.lau",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"files": [
|
|
26
26
|
"dist",
|
|
27
27
|
"bin",
|
|
28
|
+
"scripts",
|
|
28
29
|
"public",
|
|
29
30
|
"config.json",
|
|
30
31
|
"README.md"
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
"check": "tsc --noEmit",
|
|
38
39
|
"server:dev": "nodemon --watch src --watch config.json --exec tsx src/index.ts",
|
|
39
40
|
"dev": "concurrently \"npm run client:dev\" \"npm run server:dev\"",
|
|
40
|
-
"postinstall": "cp node_modules/@lancedb/lancedb-darwin-x64/lancedb.darwin-x64.node node_modules/@lancedb/lancedb/dist/ 2>/dev/null || true && npm rebuild better-sqlite3"
|
|
41
|
+
"postinstall": "node scripts/init-app-home.cjs || true && cp node_modules/@lancedb/lancedb-darwin-x64/lancedb.darwin-x64.node node_modules/@lancedb/lancedb/dist/ 2>/dev/null || true && npm rebuild better-sqlite3"
|
|
41
42
|
},
|
|
42
43
|
"dependencies": {
|
|
43
44
|
"@lancedb/lancedb": "0.22.3",
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
function guessHomeFromSudoUser() {
|
|
6
|
+
const sudoUser = process.env.SUDO_USER;
|
|
7
|
+
if (!sudoUser) return null;
|
|
8
|
+
|
|
9
|
+
const candidates = [
|
|
10
|
+
path.join('/Users', sudoUser),
|
|
11
|
+
path.join('/home', sudoUser)
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
for (const p of candidates) {
|
|
15
|
+
try {
|
|
16
|
+
if (fs.existsSync(p)) return p;
|
|
17
|
+
} catch {
|
|
18
|
+
// ignore
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function resolveTargetHome() {
|
|
26
|
+
const guessed = guessHomeFromSudoUser();
|
|
27
|
+
if (guessed) return guessed;
|
|
28
|
+
return os.homedir();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function main() {
|
|
32
|
+
const home = resolveTargetHome();
|
|
33
|
+
const appHome = path.join(home, '.xiaozuoassistant');
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
fs.mkdirSync(appHome, { recursive: true });
|
|
37
|
+
} catch {
|
|
38
|
+
process.exit(0);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
main();
|
|
43
|
+
|