xiaozuoassistant 0.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.
Files changed (56) hide show
  1. package/README.md +90 -0
  2. package/bin/cli.js +429 -0
  3. package/config.json +36 -0
  4. package/dist/client/assets/browser-ponyfill-DNlTAU2D.js +2 -0
  5. package/dist/client/assets/index-BPATxdcV.js +153 -0
  6. package/dist/client/assets/index-CgL5gMVL.css +1 -0
  7. package/dist/client/favicon.svg +4 -0
  8. package/dist/client/index.html +354 -0
  9. package/dist/client/locales/en/translation.json +77 -0
  10. package/dist/client/locales/zh/translation.json +77 -0
  11. package/dist/server/agents/office.js +23 -0
  12. package/dist/server/app.js +50 -0
  13. package/dist/server/channels/base-channel.js +13 -0
  14. package/dist/server/channels/create-channels.js +18 -0
  15. package/dist/server/channels/dingtalk.js +83 -0
  16. package/dist/server/channels/feishu.js +95 -0
  17. package/dist/server/channels/telegram.js +53 -0
  18. package/dist/server/channels/terminal.js +49 -0
  19. package/dist/server/channels/web.js +45 -0
  20. package/dist/server/channels/wechat.js +107 -0
  21. package/dist/server/config/loader.js +73 -0
  22. package/dist/server/config/prompts.js +12 -0
  23. package/dist/server/core/agents/manager.js +22 -0
  24. package/dist/server/core/agents/runtime.js +85 -0
  25. package/dist/server/core/brain.js +131 -0
  26. package/dist/server/core/event-bus.js +24 -0
  27. package/dist/server/core/logger.js +71 -0
  28. package/dist/server/core/memories/manager.js +115 -0
  29. package/dist/server/core/memories/short-term.js +128 -0
  30. package/dist/server/core/memories/structured.js +109 -0
  31. package/dist/server/core/memories/vector.js +138 -0
  32. package/dist/server/core/memory.js +2 -0
  33. package/dist/server/core/plugin-manager.js +112 -0
  34. package/dist/server/core/plugin.js +1 -0
  35. package/dist/server/core/scheduler.js +24 -0
  36. package/dist/server/core/types.js +1 -0
  37. package/dist/server/index.js +318 -0
  38. package/dist/server/llm/openai.js +23 -0
  39. package/dist/server/routes/auth.js +28 -0
  40. package/dist/server/server/create-http.js +17 -0
  41. package/dist/server/server.js +29 -0
  42. package/dist/server/skills/base-skill.js +16 -0
  43. package/dist/server/skills/create-agent.js +58 -0
  44. package/dist/server/skills/delegate.js +39 -0
  45. package/dist/server/skills/file-system.js +137 -0
  46. package/dist/server/skills/list-agents.js +24 -0
  47. package/dist/server/skills/office-excel.js +84 -0
  48. package/dist/server/skills/office-ppt.js +58 -0
  49. package/dist/server/skills/office-word.js +90 -0
  50. package/dist/server/skills/registry.js +27 -0
  51. package/dist/server/skills/search.js +31 -0
  52. package/dist/server/skills/system-time.js +27 -0
  53. package/package.json +116 -0
  54. package/public/favicon.svg +4 -0
  55. package/public/locales/en/translation.json +77 -0
  56. package/public/locales/zh/translation.json +77 -0
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # xiaozuoAssistant(小左助理)
2
+
3
+ xiaozuoAssistant 是一个**本地优先(Local-first)**的个人 AI 助手:提供 Web UI、可扩展的技能/插件体系、以及多通道接入能力,面向办公自动化场景。
4
+
5
+ ## 亮点能力
6
+
7
+ - **Web UI + 实时通信**:浏览器访问 `http://localhost:3001`,Socket.IO 实时收发消息。
8
+ - **多通道(Channels)**:内置 Web/Terminal,并可按配置启用 Telegram/飞书/钉钉/微信等。
9
+ - **技能(Skills)+ 工具调用**:模型可触发工具调用(OpenAI tools 兼容格式),技能注册表可扩展。
10
+ - **本地记忆**:短期会话 + 结构化/向量记忆(本地存储)。
11
+ - **更易接入新模型**:统一 LLM(OpenAI 兼容) client 工厂与 provider→baseURL 解析,便于新增 provider。
12
+ - **CLI 管理**:支持 `start/stop/doctor/export/import`。
13
+
14
+ ## 快速开始(推荐:npm 全局安装)
15
+
16
+ ```bash
17
+ npm install -g xiaozuoassistant --registry=https://registry.npmjs.org
18
+ xiaozuoAssistant start
19
+ ```
20
+
21
+ 然后浏览器打开:`http://localhost:3001`
22
+
23
+ 停止服务:
24
+
25
+ ```bash
26
+ xiaozuoAssistant stop
27
+ ```
28
+
29
+ ## 常用命令
30
+
31
+ - 启动服务(后台运行):`xiaozuoAssistant start`
32
+ - 停止服务:`xiaozuoAssistant stop`
33
+ - 环境自检:`xiaozuoAssistant doctor`
34
+ - 数据导出:`xiaozuoAssistant export`
35
+ - 数据导入:`xiaozuoAssistant import`
36
+
37
+ 更完整的指令说明见:[指令集(CLI)](docs/commands.md)
38
+
39
+ ## 运行模式
40
+
41
+ ### 开发模式(前后端联调)
42
+
43
+ ```bash
44
+ npm install
45
+ npm run dev
46
+ ```
47
+
48
+ ### 生产模式(构建后运行)
49
+
50
+ ```bash
51
+ npm install
52
+ npm run build
53
+ node dist/server/index.js
54
+ ```
55
+
56
+ > `xiaozuoAssistant start` 本质上也是启动 `dist/server/index.js`,并将日志写入你执行命令的当前目录(CWD)下的 `logs/`。
57
+
58
+ ## 工作目录(非常重要)
59
+
60
+ xiaozuoAssistant 将**以你执行命令时所在目录(CWD)**作为工作目录,并在此目录读写:
61
+
62
+ - `config.json`:配置文件
63
+ - `data/`:结构化数据(如 SQLite 等)
64
+ - `memories/` 或 `data/lancedb/`:向量记忆
65
+ - `logs/`:运行日志(包含 `server.pid`)
66
+
67
+ 建议为每套数据创建独立目录,例如:
68
+
69
+ ```bash
70
+ mkdir -p ~/xiaozuo && cd ~/xiaozuo
71
+ xiaozuoAssistant start
72
+ ```
73
+
74
+ ## 配置与模型
75
+
76
+ - 你可以通过 `config.json` 或 API (`/api/config`) 更新 LLM 配置。
77
+ - 支持 OpenAI 兼容的多 provider(示例:`openai/deepseek/minimax/doubao/qwen/custom`),并会自动映射 baseURL。
78
+ - 可用环境变量:`XIAOZUO_LLM_API_KEY`(覆盖 `config.json` 中的 key)。
79
+
80
+ ## 文档
81
+
82
+ - [指令集(CLI)](docs/commands.md)
83
+ - [API 使用指南](api/usage_guide.md)
84
+ - [数据迁移指南](docs/migration_guide.md)
85
+ - [技术架构](docs/technical_architecture.md)
86
+ - [产品需求文档](docs/product_requirements.md)
87
+
88
+ ## 许可证
89
+
90
+ MIT
package/bin/cli.js ADDED
@@ -0,0 +1,429 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawn } from 'child_process';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import fs from 'fs';
7
+ import { createGzip } from 'zlib';
8
+ import { pipeline } from 'stream';
9
+ import { promisify } from 'util';
10
+ import * as tar from 'tar';
11
+ import http from 'http';
12
+ import net from 'net';
13
+
14
+ const pipe = promisify(pipeline);
15
+
16
+ const __filename = fileURLToPath(import.meta.url);
17
+ const __dirname = path.dirname(__filename);
18
+
19
+ // Determine the root directory of the package
20
+ // When running from source: bin/cli.js -> ../
21
+ // When installed globally: lib/node_modules/xiaozuoassistant/bin/cli.js -> ../
22
+ const packageRoot = path.resolve(__dirname, '..');
23
+
24
+ const args = process.argv.slice(2);
25
+ const command = args[0];
26
+
27
+ const EXPORT_FILENAME = 'xiaozuoAssistant-backup.tar.gz';
28
+
29
+ // Helper to get user's current working directory where they ran the command
30
+ const CWD = process.cwd();
31
+
32
+ // Define important paths relative to where the user *runs* the app, NOT the package location
33
+ // Assuming standard structure where config.json and data folders are in CWD
34
+ const DATA_PATHS = [
35
+ 'config.json',
36
+ 'memories', // Vector DB and others
37
+ 'data', // SQLite or other data
38
+ 'logs'
39
+ ];
40
+
41
+ function getPortFromConfig() {
42
+ let port = 3001;
43
+ const configPath = path.join(CWD, 'config.json');
44
+ if (fs.existsSync(configPath)) {
45
+ try {
46
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
47
+ if (config.server && config.server.port) {
48
+ port = config.server.port;
49
+ }
50
+ } catch (e) {
51
+ // ignore
52
+ }
53
+ }
54
+ return port;
55
+ }
56
+
57
+ function getPidFilePath() {
58
+ return path.join(CWD, 'logs', 'server.pid');
59
+ }
60
+
61
+ function isProcessRunning(pid) {
62
+ try {
63
+ process.kill(pid, 0);
64
+ return true;
65
+ } catch (e) {
66
+ return false;
67
+ }
68
+ }
69
+
70
+ async function isPortOpen(port) {
71
+ return await new Promise((resolve) => {
72
+ const socket = net.connect({ host: '127.0.0.1', port }, () => {
73
+ socket.destroy();
74
+ resolve(true);
75
+ });
76
+ socket.on('error', () => {
77
+ resolve(false);
78
+ });
79
+ socket.setTimeout(500, () => {
80
+ socket.destroy();
81
+ resolve(false);
82
+ });
83
+ });
84
+ }
85
+
86
+ async function stopServer() {
87
+ const pidFile = getPidFilePath();
88
+ const port = getPortFromConfig();
89
+
90
+ const killPid = async (pid) => {
91
+ const waitGone = async (ms) => new Promise(r => setTimeout(r, ms));
92
+
93
+ const tryKill = (targetPid, signal) => {
94
+ try {
95
+ process.kill(targetPid, signal);
96
+ return true;
97
+ } catch (e) {
98
+ return false;
99
+ }
100
+ };
101
+
102
+ const killedGroup = tryKill(-pid, 'SIGTERM');
103
+ if (!killedGroup) {
104
+ tryKill(pid, 'SIGTERM');
105
+ }
106
+
107
+ for (let i = 0; i < 10; i++) {
108
+ if (!isProcessRunning(pid)) return true;
109
+ await waitGone(300);
110
+ }
111
+
112
+ const killedGroupHard = tryKill(-pid, 'SIGKILL');
113
+ if (!killedGroupHard) {
114
+ tryKill(pid, 'SIGKILL');
115
+ }
116
+
117
+ for (let i = 0; i < 10; i++) {
118
+ if (!isProcessRunning(pid)) return true;
119
+ await waitGone(300);
120
+ }
121
+
122
+ return !isProcessRunning(pid);
123
+ };
124
+
125
+ const killByPort = async () => {
126
+ const lsof = spawn('lsof', ['-ti', `tcp:${port}`], { stdio: ['ignore', 'pipe', 'ignore'] });
127
+ let output = '';
128
+ lsof.stdout.on('data', (d) => { output += d.toString(); });
129
+ await new Promise((resolve) => lsof.on('close', resolve));
130
+
131
+ const pids = output
132
+ .split(/\s+/)
133
+ .map(s => s.trim())
134
+ .filter(Boolean)
135
+ .map(Number)
136
+ .filter(n => Number.isFinite(n) && n > 0);
137
+
138
+ if (pids.length === 0) return false;
139
+
140
+ for (const pid of pids) {
141
+ await killPid(pid);
142
+ }
143
+ return true;
144
+ };
145
+
146
+ if (fs.existsSync(pidFile)) {
147
+ const pidStr = fs.readFileSync(pidFile, 'utf-8').trim();
148
+ const pid = Number(pidStr);
149
+ if (!Number.isFinite(pid) || pid <= 0) {
150
+ fs.unlinkSync(pidFile);
151
+ console.log('[CLI] 未找到可用的 PID(已清理 pid 文件)。');
152
+ return;
153
+ }
154
+
155
+ if (!isProcessRunning(pid)) {
156
+ fs.unlinkSync(pidFile);
157
+ console.log('[CLI] 服务未在运行(已清理 pid 文件)。');
158
+ return;
159
+ }
160
+
161
+ console.log(`[CLI] 正在停止服务(PID: ${pid})...`);
162
+ await killPid(pid);
163
+ await killByPort();
164
+ try { fs.unlinkSync(pidFile); } catch (e) {}
165
+
166
+ if (!(await isPortOpen(port))) {
167
+ console.log('[CLI] ✅ 服务已停止。');
168
+ return;
169
+ }
170
+
171
+ console.error('[CLI] ❌ 停止失败:端口仍在占用。');
172
+ console.error(`[CLI] 你可以手动执行:lsof -ti tcp:${port} | xargs kill -9`);
173
+ return;
174
+ }
175
+
176
+ console.log('[CLI] 未找到 pid 文件,尝试按端口停止...');
177
+ const ok = await killByPort();
178
+ if (!ok) {
179
+ console.log(`[CLI] 未发现占用端口 ${port} 的进程。`);
180
+ return;
181
+ }
182
+ if (!(await isPortOpen(port))) {
183
+ console.log('[CLI] ✅ 服务已停止。');
184
+ return;
185
+ }
186
+ console.error('[CLI] ❌ 停止失败:端口仍在占用。');
187
+ }
188
+
189
+ async function exportData() {
190
+ console.log('📦 Starting data export...');
191
+
192
+ const filesToArchive = [];
193
+
194
+ for (const p of DATA_PATHS) {
195
+ if (fs.existsSync(path.join(CWD, p))) {
196
+ filesToArchive.push(p);
197
+ console.log(` - Found: ${p}`);
198
+ }
199
+ }
200
+
201
+ if (filesToArchive.length === 0) {
202
+ console.warn('⚠️ No data files found to export in current directory.');
203
+ return;
204
+ }
205
+
206
+ try {
207
+ await tar.c(
208
+ {
209
+ gzip: true,
210
+ file: EXPORT_FILENAME,
211
+ cwd: CWD
212
+ },
213
+ filesToArchive
214
+ );
215
+ console.log(`✅ Export successful! Backup created at: ${path.join(CWD, EXPORT_FILENAME)}`);
216
+ console.log(` Copy this file to your new machine to import.`);
217
+ } catch (err) {
218
+ console.error('❌ Export failed:', err);
219
+ }
220
+ }
221
+
222
+ async function importData() {
223
+ const backupPath = path.join(CWD, EXPORT_FILENAME);
224
+
225
+ if (!fs.existsSync(backupPath)) {
226
+ console.error(`❌ Backup file not found: ${backupPath}`);
227
+ console.log(` Please ensure '${EXPORT_FILENAME}' is in the current directory.`);
228
+ return;
229
+ }
230
+
231
+ console.log('📦 Starting data import...');
232
+ console.log('⚠️ Warning: This will overwrite existing data files (config.json, memories, etc.)');
233
+
234
+ // Simple prompt implementation for Node.js
235
+ process.stdout.write(' Are you sure? (y/N) ');
236
+ process.stdin.once('data', async (data) => {
237
+ const answer = data.toString().trim().toLowerCase();
238
+ if (answer === 'y' || answer === 'yes') {
239
+ try {
240
+ await tar.x({
241
+ file: EXPORT_FILENAME,
242
+ cwd: CWD
243
+ });
244
+ console.log('✅ Import successful! Data restored.');
245
+
246
+ // Auto-configure workspace path in config.json
247
+ const configPath = path.join(CWD, 'config.json');
248
+ if (fs.existsSync(configPath)) {
249
+ try {
250
+ const configContent = fs.readFileSync(configPath, 'utf-8');
251
+ const config = JSON.parse(configContent);
252
+
253
+ // Update workspace to current directory
254
+ const oldWorkspace = config.workspace;
255
+ config.workspace = CWD;
256
+
257
+ // Also update System Prompt if it contains the old workspace path
258
+ if (config.systemPrompt && typeof config.systemPrompt === 'string') {
259
+ if (oldWorkspace && config.systemPrompt.includes(oldWorkspace)) {
260
+ config.systemPrompt = config.systemPrompt.replace(oldWorkspace, CWD);
261
+ } else if (config.systemPrompt.includes('Current Workspace:')) {
262
+ // Fallback regex replacement if exact string match fails
263
+ config.systemPrompt = config.systemPrompt.replace(/Current Workspace: .*/, `Current Workspace: ${CWD}`);
264
+ }
265
+ }
266
+
267
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
268
+ console.log(`✅ Auto-configured workspace path to: ${CWD}`);
269
+ } catch (e) {
270
+ console.warn('⚠️ Failed to auto-update config.json path:', e);
271
+ }
272
+ }
273
+
274
+ console.log(' You can now start the application.');
275
+ } catch (err) {
276
+ console.error('❌ Import failed:', err);
277
+ }
278
+ } else {
279
+ console.log(' Import cancelled.');
280
+ }
281
+ process.exit(0);
282
+ });
283
+ }
284
+
285
+ if (command === 'start') {
286
+ console.log('Starting xiaozuoAssistant...');
287
+
288
+ const serverPath = path.join(packageRoot, 'dist', 'server', 'index.js');
289
+
290
+ // Ensure logs directory exists in CWD
291
+ const logDir = path.join(CWD, 'logs');
292
+ if (!fs.existsSync(logDir)) {
293
+ try {
294
+ fs.mkdirSync(logDir, { recursive: true });
295
+ } catch (e) {
296
+ console.error(`[CLI] Failed to create logs directory at ${logDir}:`, e);
297
+ process.exit(1);
298
+ }
299
+ }
300
+
301
+ const outLog = path.join(logDir, 'stdout.log');
302
+ const errLog = path.join(logDir, 'stderr.log');
303
+
304
+ console.log(`[CLI] Launching server from: ${serverPath}`);
305
+ console.log(`[CLI] Logs redirected to:`);
306
+ console.log(` - Stdout: ${outLog}`);
307
+ console.log(` - Stderr: ${errLog}`);
308
+ console.log(` - App Logs (Rotated): ${path.join(logDir, 'app.log')}`);
309
+
310
+ const port = getPortFromConfig();
311
+ const pidFile = getPidFilePath();
312
+
313
+ if (await isPortOpen(port)) {
314
+ console.error(`[CLI] 端口 ${port} 已被占用,可能服务已在运行。`);
315
+ console.error('[CLI] 可先执行:xiaozuoAssistant stop');
316
+ process.exit(1);
317
+ }
318
+
319
+ if (fs.existsSync(pidFile)) {
320
+ try {
321
+ const pid = Number(fs.readFileSync(pidFile, 'utf-8').trim());
322
+ if (Number.isFinite(pid) && pid > 0 && isProcessRunning(pid)) {
323
+ console.log(`[CLI] 服务已在运行(PID: ${pid})。`);
324
+ console.log(`[CLI] 访问地址: http://localhost:${port}`);
325
+ process.exit(0);
326
+ }
327
+ fs.unlinkSync(pidFile);
328
+ } catch (e) {
329
+ // ignore
330
+ }
331
+ }
332
+
333
+ console.log(`[CLI] Waiting for server to start on port ${port}...`);
334
+
335
+ try {
336
+ const out = fs.openSync(outLog, 'a');
337
+ const err = fs.openSync(errLog, 'a');
338
+
339
+ const child = spawn('node', [serverPath, ...args.slice(1)], {
340
+ detached: true, // Allow child to run independently
341
+ stdio: ['ignore', out, err], // Disconnect stdin, redirect stdout/stderr
342
+ cwd: CWD, // Run in user's current directory
343
+ env: {
344
+ ...process.env,
345
+ NODE_ENV: 'production'
346
+ }
347
+ });
348
+
349
+ try {
350
+ fs.writeFileSync(pidFile, String(child.pid));
351
+ } catch (e) {
352
+ // ignore
353
+ }
354
+
355
+ let childExited = false;
356
+ child.on('exit', (code) => {
357
+ childExited = true;
358
+ console.error(`\n[CLI] Server process exited unexpectedly with code ${code}.`);
359
+ console.error(`[CLI] Check logs at ${errLog} or ${outLog}`);
360
+ process.exit(1);
361
+ });
362
+
363
+ // Health check function
364
+ const checkHealth = async (port, retries = 30) => {
365
+ const check = () => new Promise((resolve, reject) => {
366
+ const req = http.get(`http://localhost:${port}/api/health`, (res) => {
367
+ if (res.statusCode === 200) {
368
+ resolve(true);
369
+ } else {
370
+ reject(new Error(`Status ${res.statusCode}`));
371
+ }
372
+ res.resume();
373
+ });
374
+
375
+ req.on('error', (err) => reject(err));
376
+ req.setTimeout(500, () => {
377
+ req.destroy();
378
+ reject(new Error('Timeout'));
379
+ });
380
+ });
381
+
382
+ for (let i = 0; i < retries; i++) {
383
+ if (childExited) throw new Error('Child process exited');
384
+ try {
385
+ await check();
386
+ return true;
387
+ } catch (e) {
388
+ await new Promise(r => setTimeout(r, 1000));
389
+ process.stdout.write('.');
390
+ }
391
+ }
392
+ throw new Error('Health check timed out');
393
+ };
394
+
395
+ // Perform health check
396
+ await checkHealth(port);
397
+ console.log(`\n[CLI] ✅ Health check passed!`);
398
+
399
+ // Unreference the child so the parent process can exit
400
+ child.unref();
401
+
402
+ console.log(`[CLI] Server running in background.`);
403
+ console.log(`[CLI] Access the Web UI at: http://localhost:${port}`);
404
+ process.exit(0);
405
+ } catch (error) {
406
+ try { if (fs.existsSync(pidFile)) fs.unlinkSync(pidFile); } catch (e) {}
407
+ console.error(`\n[CLI] Failed to start server: ${error.message}`);
408
+ process.exit(1);
409
+ }
410
+ } else if (command === 'doctor') {
411
+ console.log('Running doctor check...');
412
+ console.log('Package Root:', packageRoot);
413
+ console.log('Node Version:', process.version);
414
+ console.log('Doctor check complete.');
415
+ } else if (command === 'export') {
416
+ exportData();
417
+ } else if (command === 'import') {
418
+ importData();
419
+ } else if (command === 'stop') {
420
+ stopServer();
421
+ } else {
422
+ console.log('Usage: xiaozuoAssistant <command>');
423
+ console.log('Commands:');
424
+ console.log(' start Start the xiaozuoAssistant server');
425
+ console.log(' stop Stop the xiaozuoAssistant server');
426
+ console.log(' doctor Check the health and configuration');
427
+ console.log(' export Backup local data (config, memories) to a file');
428
+ console.log(' import Restore data from a backup file');
429
+ }
package/config.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "server": {
3
+ "port": 3001,
4
+ "host": "localhost"
5
+ },
6
+ "llm": {
7
+ "apiKey": "",
8
+ "baseURL": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
9
+ "model": "qwen-plus",
10
+ "temperature": 0.7
11
+ },
12
+ "logging": {
13
+ "level": "info"
14
+ },
15
+ "channels": {
16
+ "telegram": {
17
+ "token": ""
18
+ },
19
+ "feishu": {
20
+ "appId": "",
21
+ "appSecret": "",
22
+ "encryptKey": "",
23
+ "verificationToken": ""
24
+ },
25
+ "dingtalk": {
26
+ "clientId": "",
27
+ "clientSecret": "",
28
+ "robotCode": ""
29
+ }
30
+ },
31
+ "systemPrompt": "你现在是 我的个人AI助手,叫xiaozuoAssistant。\n\n核心规则:\n1. 所有记忆完全本地存储,不上传任何内容到云端。\n2. 默认工作模式:优先使用 office_work 类别的记忆。\n3. 当用户提到 Word、PPT、Excel、汇报、客户、模板、格式、数据整理、邮件等办公相关内容时,**必须先检索相关记忆**,然后再回答。\n4. 如果记忆中有明确偏好,直接应用,不要再次询问。\n5. 风格:专业、简洁、高效,像一个靠谱的行政/助理。\n6. 语言:默认用中文,必要时中英混用(比如函数名、文件名)。\n7. 主动建议:如果用户在处理重复性工作,可以提醒“您上次处理类似内容时用了XX方法,要不要继续沿用?”\nCurrent Workspace: /Users/zxz/Documents/XiaoZuoClaw",
32
+ "scheduler": {
33
+ "memoryMaintenanceCron": "0 2 * * *"
34
+ },
35
+ "workspace": "/Users/zxz/Documents/XiaoZuoClaw"
36
+ }
@@ -0,0 +1,2 @@
1
+ import{c as R,g as z}from"./index-BPATxdcV.js";function X(w,d){for(var b=0;b<d.length;b++){const y=d[b];if(typeof y!="string"&&!Array.isArray(y)){for(const h in y)if(h!=="default"&&!(h in w)){const p=Object.getOwnPropertyDescriptor(y,h);p&&Object.defineProperty(w,h,p.get?p:{enumerable:!0,get:()=>y[h]})}}}return Object.freeze(Object.defineProperty(w,Symbol.toStringTag,{value:"Module"}))}var A={exports:{}},U;function J(){return U||(U=1,(function(w,d){var b=typeof globalThis<"u"&&globalThis||typeof self<"u"&&self||typeof R<"u"&&R,y=(function(){function p(){this.fetch=!1,this.DOMException=b.DOMException}return p.prototype=b,new p})();(function(p){(function(u){var a=typeof p<"u"&&p||typeof self<"u"&&self||typeof a<"u"&&a,f={searchParams:"URLSearchParams"in a,iterable:"Symbol"in a&&"iterator"in Symbol,blob:"FileReader"in a&&"Blob"in a&&(function(){try{return new Blob,!0}catch{return!1}})(),formData:"FormData"in a,arrayBuffer:"ArrayBuffer"in a};function S(e){return e&&DataView.prototype.isPrototypeOf(e)}if(f.arrayBuffer)var F=["[object Int8Array]","[object Uint8Array]","[object Uint8ClampedArray]","[object Int16Array]","[object Uint16Array]","[object Int32Array]","[object Uint32Array]","[object Float32Array]","[object Float64Array]"],I=ArrayBuffer.isView||function(e){return e&&F.indexOf(Object.prototype.toString.call(e))>-1};function v(e){if(typeof e!="string"&&(e=String(e)),/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(e)||e==="")throw new TypeError('Invalid character in header field name: "'+e+'"');return e.toLowerCase()}function E(e){return typeof e!="string"&&(e=String(e)),e}function T(e){var t={next:function(){var r=e.shift();return{done:r===void 0,value:r}}};return f.iterable&&(t[Symbol.iterator]=function(){return t}),t}function s(e){this.map={},e instanceof s?e.forEach(function(t,r){this.append(r,t)},this):Array.isArray(e)?e.forEach(function(t){this.append(t[0],t[1])},this):e&&Object.getOwnPropertyNames(e).forEach(function(t){this.append(t,e[t])},this)}s.prototype.append=function(e,t){e=v(e),t=E(t);var r=this.map[e];this.map[e]=r?r+", "+t:t},s.prototype.delete=function(e){delete this.map[v(e)]},s.prototype.get=function(e){return e=v(e),this.has(e)?this.map[e]:null},s.prototype.has=function(e){return this.map.hasOwnProperty(v(e))},s.prototype.set=function(e,t){this.map[v(e)]=E(t)},s.prototype.forEach=function(e,t){for(var r in this.map)this.map.hasOwnProperty(r)&&e.call(t,this.map[r],r,this)},s.prototype.keys=function(){var e=[];return this.forEach(function(t,r){e.push(r)}),T(e)},s.prototype.values=function(){var e=[];return this.forEach(function(t){e.push(t)}),T(e)},s.prototype.entries=function(){var e=[];return this.forEach(function(t,r){e.push([r,t])}),T(e)},f.iterable&&(s.prototype[Symbol.iterator]=s.prototype.entries);function B(e){if(e.bodyUsed)return Promise.reject(new TypeError("Already read"));e.bodyUsed=!0}function P(e){return new Promise(function(t,r){e.onload=function(){t(e.result)},e.onerror=function(){r(e.error)}})}function M(e){var t=new FileReader,r=P(t);return t.readAsArrayBuffer(e),r}function q(e){var t=new FileReader,r=P(t);return t.readAsText(e),r}function H(e){for(var t=new Uint8Array(e),r=new Array(t.length),n=0;n<t.length;n++)r[n]=String.fromCharCode(t[n]);return r.join("")}function D(e){if(e.slice)return e.slice(0);var t=new Uint8Array(e.byteLength);return t.set(new Uint8Array(e)),t.buffer}function x(){return this.bodyUsed=!1,this._initBody=function(e){this.bodyUsed=this.bodyUsed,this._bodyInit=e,e?typeof e=="string"?this._bodyText=e:f.blob&&Blob.prototype.isPrototypeOf(e)?this._bodyBlob=e:f.formData&&FormData.prototype.isPrototypeOf(e)?this._bodyFormData=e:f.searchParams&&URLSearchParams.prototype.isPrototypeOf(e)?this._bodyText=e.toString():f.arrayBuffer&&f.blob&&S(e)?(this._bodyArrayBuffer=D(e.buffer),this._bodyInit=new Blob([this._bodyArrayBuffer])):f.arrayBuffer&&(ArrayBuffer.prototype.isPrototypeOf(e)||I(e))?this._bodyArrayBuffer=D(e):this._bodyText=e=Object.prototype.toString.call(e):this._bodyText="",this.headers.get("content-type")||(typeof e=="string"?this.headers.set("content-type","text/plain;charset=UTF-8"):this._bodyBlob&&this._bodyBlob.type?this.headers.set("content-type",this._bodyBlob.type):f.searchParams&&URLSearchParams.prototype.isPrototypeOf(e)&&this.headers.set("content-type","application/x-www-form-urlencoded;charset=UTF-8"))},f.blob&&(this.blob=function(){var e=B(this);if(e)return e;if(this._bodyBlob)return Promise.resolve(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(new Blob([this._bodyArrayBuffer]));if(this._bodyFormData)throw new Error("could not read FormData body as blob");return Promise.resolve(new Blob([this._bodyText]))},this.arrayBuffer=function(){if(this._bodyArrayBuffer){var e=B(this);return e||(ArrayBuffer.isView(this._bodyArrayBuffer)?Promise.resolve(this._bodyArrayBuffer.buffer.slice(this._bodyArrayBuffer.byteOffset,this._bodyArrayBuffer.byteOffset+this._bodyArrayBuffer.byteLength)):Promise.resolve(this._bodyArrayBuffer))}else return this.blob().then(M)}),this.text=function(){var e=B(this);if(e)return e;if(this._bodyBlob)return q(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(H(this._bodyArrayBuffer));if(this._bodyFormData)throw new Error("could not read FormData body as text");return Promise.resolve(this._bodyText)},f.formData&&(this.formData=function(){return this.text().then(k)}),this.json=function(){return this.text().then(JSON.parse)},this}var L=["DELETE","GET","HEAD","OPTIONS","POST","PUT"];function C(e){var t=e.toUpperCase();return L.indexOf(t)>-1?t:e}function m(e,t){if(!(this instanceof m))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');t=t||{};var r=t.body;if(e instanceof m){if(e.bodyUsed)throw new TypeError("Already read");this.url=e.url,this.credentials=e.credentials,t.headers||(this.headers=new s(e.headers)),this.method=e.method,this.mode=e.mode,this.signal=e.signal,!r&&e._bodyInit!=null&&(r=e._bodyInit,e.bodyUsed=!0)}else this.url=String(e);if(this.credentials=t.credentials||this.credentials||"same-origin",(t.headers||!this.headers)&&(this.headers=new s(t.headers)),this.method=C(t.method||this.method||"GET"),this.mode=t.mode||this.mode||null,this.signal=t.signal||this.signal,this.referrer=null,(this.method==="GET"||this.method==="HEAD")&&r)throw new TypeError("Body not allowed for GET or HEAD requests");if(this._initBody(r),(this.method==="GET"||this.method==="HEAD")&&(t.cache==="no-store"||t.cache==="no-cache")){var n=/([?&])_=[^&]*/;if(n.test(this.url))this.url=this.url.replace(n,"$1_="+new Date().getTime());else{var i=/\?/;this.url+=(i.test(this.url)?"&":"?")+"_="+new Date().getTime()}}}m.prototype.clone=function(){return new m(this,{body:this._bodyInit})};function k(e){var t=new FormData;return e.trim().split("&").forEach(function(r){if(r){var n=r.split("="),i=n.shift().replace(/\+/g," "),o=n.join("=").replace(/\+/g," ");t.append(decodeURIComponent(i),decodeURIComponent(o))}}),t}function N(e){var t=new s,r=e.replace(/\r?\n[\t ]+/g," ");return r.split("\r").map(function(n){return n.indexOf(`
2
+ `)===0?n.substr(1,n.length):n}).forEach(function(n){var i=n.split(":"),o=i.shift().trim();if(o){var _=i.join(":").trim();t.append(o,_)}}),t}x.call(m.prototype);function c(e,t){if(!(this instanceof c))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');t||(t={}),this.type="default",this.status=t.status===void 0?200:t.status,this.ok=this.status>=200&&this.status<300,this.statusText=t.statusText===void 0?"":""+t.statusText,this.headers=new s(t.headers),this.url=t.url||"",this._initBody(e)}x.call(c.prototype),c.prototype.clone=function(){return new c(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new s(this.headers),url:this.url})},c.error=function(){var e=new c(null,{status:0,statusText:""});return e.type="error",e};var G=[301,302,303,307,308];c.redirect=function(e,t){if(G.indexOf(t)===-1)throw new RangeError("Invalid status code");return new c(null,{status:t,headers:{location:e}})},u.DOMException=a.DOMException;try{new u.DOMException}catch{u.DOMException=function(t,r){this.message=t,this.name=r;var n=Error(t);this.stack=n.stack},u.DOMException.prototype=Object.create(Error.prototype),u.DOMException.prototype.constructor=u.DOMException}function O(e,t){return new Promise(function(r,n){var i=new m(e,t);if(i.signal&&i.signal.aborted)return n(new u.DOMException("Aborted","AbortError"));var o=new XMLHttpRequest;function _(){o.abort()}o.onload=function(){var l={status:o.status,statusText:o.statusText,headers:N(o.getAllResponseHeaders()||"")};l.url="responseURL"in o?o.responseURL:l.headers.get("X-Request-URL");var g="response"in o?o.response:o.responseText;setTimeout(function(){r(new c(g,l))},0)},o.onerror=function(){setTimeout(function(){n(new TypeError("Network request failed"))},0)},o.ontimeout=function(){setTimeout(function(){n(new TypeError("Network request failed"))},0)},o.onabort=function(){setTimeout(function(){n(new u.DOMException("Aborted","AbortError"))},0)};function V(l){try{return l===""&&a.location.href?a.location.href:l}catch{return l}}o.open(i.method,V(i.url),!0),i.credentials==="include"?o.withCredentials=!0:i.credentials==="omit"&&(o.withCredentials=!1),"responseType"in o&&(f.blob?o.responseType="blob":f.arrayBuffer&&i.headers.get("Content-Type")&&i.headers.get("Content-Type").indexOf("application/octet-stream")!==-1&&(o.responseType="arraybuffer")),t&&typeof t.headers=="object"&&!(t.headers instanceof s)?Object.getOwnPropertyNames(t.headers).forEach(function(l){o.setRequestHeader(l,E(t.headers[l]))}):i.headers.forEach(function(l,g){o.setRequestHeader(g,l)}),i.signal&&(i.signal.addEventListener("abort",_),o.onreadystatechange=function(){o.readyState===4&&i.signal.removeEventListener("abort",_)}),o.send(typeof i._bodyInit>"u"?null:i._bodyInit)})}return O.polyfill=!0,a.fetch||(a.fetch=O,a.Headers=s,a.Request=m,a.Response=c),u.Headers=s,u.Request=m,u.Response=c,u.fetch=O,u})({})})(y),y.fetch.ponyfill=!0,delete y.fetch.polyfill;var h=b.fetch?b:y;d=h.fetch,d.default=h.fetch,d.fetch=h.fetch,d.Headers=h.Headers,d.Request=h.Request,d.Response=h.Response,w.exports=d})(A,A.exports)),A.exports}var j=J();const K=z(j),W=X({__proto__:null,default:K},[j]);export{W as b};