@next-open-ai/openclawx 0.6.6
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/README.md +523 -0
- package/apps/desktop/README.md +210 -0
- package/apps/desktop/renderer/dist/assets/index-CYkSfhcp.css +10 -0
- package/apps/desktop/renderer/dist/assets/index-FI6O25Ms.js +89 -0
- package/apps/desktop/renderer/dist/index.html +22 -0
- package/dist/cli/cli.d.ts +2 -0
- package/dist/cli/cli.js +198 -0
- package/dist/cli/service.d.ts +13 -0
- package/dist/cli/service.js +243 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +5 -0
- package/dist/core/agent/agent-dir.d.ts +14 -0
- package/dist/core/agent/agent-dir.js +75 -0
- package/dist/core/agent/agent-manager.d.ts +64 -0
- package/dist/core/agent/agent-manager.js +278 -0
- package/dist/core/agent/config-manager.d.ts +25 -0
- package/dist/core/agent/config-manager.js +84 -0
- package/dist/core/agent/run.d.ts +26 -0
- package/dist/core/agent/run.js +65 -0
- package/dist/core/agent/skills.d.ts +20 -0
- package/dist/core/agent/skills.js +86 -0
- package/dist/core/config/desktop-config.d.ts +90 -0
- package/dist/core/config/desktop-config.js +521 -0
- package/dist/core/config/provider-support-default.d.ts +21 -0
- package/dist/core/config/provider-support-default.js +57 -0
- package/dist/core/installer/index.d.ts +1 -0
- package/dist/core/installer/index.js +1 -0
- package/dist/core/installer/skill-installer.d.ts +39 -0
- package/dist/core/installer/skill-installer.js +215 -0
- package/dist/core/mcp/adapter.d.ts +17 -0
- package/dist/core/mcp/adapter.js +49 -0
- package/dist/core/mcp/client.d.ts +24 -0
- package/dist/core/mcp/client.js +70 -0
- package/dist/core/mcp/config.d.ts +22 -0
- package/dist/core/mcp/config.js +69 -0
- package/dist/core/mcp/index.d.ts +18 -0
- package/dist/core/mcp/index.js +20 -0
- package/dist/core/mcp/operator.d.ts +15 -0
- package/dist/core/mcp/operator.js +72 -0
- package/dist/core/mcp/transport/index.d.ts +11 -0
- package/dist/core/mcp/transport/index.js +16 -0
- package/dist/core/mcp/transport/sse.d.ts +20 -0
- package/dist/core/mcp/transport/sse.js +82 -0
- package/dist/core/mcp/transport/stdio.d.ts +32 -0
- package/dist/core/mcp/transport/stdio.js +132 -0
- package/dist/core/mcp/types.d.ts +72 -0
- package/dist/core/mcp/types.js +5 -0
- package/dist/core/memory/build-summary.d.ts +6 -0
- package/dist/core/memory/build-summary.js +27 -0
- package/dist/core/memory/compaction-extension.d.ts +6 -0
- package/dist/core/memory/compaction-extension.js +23 -0
- package/dist/core/memory/embedding.d.ts +4 -0
- package/dist/core/memory/embedding.js +15 -0
- package/dist/core/memory/index.d.ts +29 -0
- package/dist/core/memory/index.js +70 -0
- package/dist/core/memory/remote-embedding.d.ts +10 -0
- package/dist/core/memory/remote-embedding.js +36 -0
- package/dist/core/memory/types.d.ts +16 -0
- package/dist/core/memory/types.js +1 -0
- package/dist/core/memory/vector-store.d.ts +15 -0
- package/dist/core/memory/vector-store.js +65 -0
- package/dist/core/tools/bookmark-tool.d.ts +9 -0
- package/dist/core/tools/bookmark-tool.js +118 -0
- package/dist/core/tools/browser-tool.d.ts +10 -0
- package/dist/core/tools/browser-tool.js +362 -0
- package/dist/core/tools/index.d.ts +4 -0
- package/dist/core/tools/index.js +4 -0
- package/dist/core/tools/install-skill-tool.d.ts +6 -0
- package/dist/core/tools/install-skill-tool.js +53 -0
- package/dist/core/tools/save-experience-tool.d.ts +5 -0
- package/dist/core/tools/save-experience-tool.js +54 -0
- package/dist/gateway/auth-hooks.d.ts +17 -0
- package/dist/gateway/auth-hooks.js +19 -0
- package/dist/gateway/backend-url.d.ts +2 -0
- package/dist/gateway/backend-url.js +11 -0
- package/dist/gateway/channel-handler.d.ts +6 -0
- package/dist/gateway/channel-handler.js +3 -0
- package/dist/gateway/clients.d.ts +5 -0
- package/dist/gateway/clients.js +4 -0
- package/dist/gateway/connection-handler.d.ts +6 -0
- package/dist/gateway/connection-handler.js +48 -0
- package/dist/gateway/index.d.ts +3 -0
- package/dist/gateway/index.js +2 -0
- package/dist/gateway/message-handler.d.ts +5 -0
- package/dist/gateway/message-handler.js +65 -0
- package/dist/gateway/methods/agent-cancel.d.ts +10 -0
- package/dist/gateway/methods/agent-cancel.js +17 -0
- package/dist/gateway/methods/agent-chat.d.ts +8 -0
- package/dist/gateway/methods/agent-chat.js +148 -0
- package/dist/gateway/methods/connect.d.ts +9 -0
- package/dist/gateway/methods/connect.js +18 -0
- package/dist/gateway/methods/install-skill-from-path.d.ts +13 -0
- package/dist/gateway/methods/install-skill-from-path.js +15 -0
- package/dist/gateway/methods/install-skill-from-upload.d.ts +14 -0
- package/dist/gateway/methods/install-skill-from-upload.js +13 -0
- package/dist/gateway/methods/run-scheduled-task.d.ts +15 -0
- package/dist/gateway/methods/run-scheduled-task.js +127 -0
- package/dist/gateway/paths.d.ts +20 -0
- package/dist/gateway/paths.js +19 -0
- package/dist/gateway/server.d.ts +8 -0
- package/dist/gateway/server.js +190 -0
- package/dist/gateway/sse-handler.d.ts +6 -0
- package/dist/gateway/sse-handler.js +3 -0
- package/dist/gateway/types.d.ts +90 -0
- package/dist/gateway/types.js +1 -0
- package/dist/gateway/utils.d.ts +22 -0
- package/dist/gateway/utils.js +67 -0
- package/dist/gateway/voice-handler.d.ts +12 -0
- package/dist/gateway/voice-handler.js +18 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/server/agent-config/agent-config.controller.d.ts +30 -0
- package/dist/server/agent-config/agent-config.controller.js +83 -0
- package/dist/server/agent-config/agent-config.module.d.ts +2 -0
- package/dist/server/agent-config/agent-config.module.js +19 -0
- package/dist/server/agent-config/agent-config.service.d.ts +53 -0
- package/dist/server/agent-config/agent-config.service.js +213 -0
- package/dist/server/agents/agents.controller.d.ts +41 -0
- package/dist/server/agents/agents.controller.js +118 -0
- package/dist/server/agents/agents.gateway.d.ts +21 -0
- package/dist/server/agents/agents.gateway.js +103 -0
- package/dist/server/agents/agents.module.d.ts +2 -0
- package/dist/server/agents/agents.module.js +20 -0
- package/dist/server/agents/agents.service.d.ts +63 -0
- package/dist/server/agents/agents.service.js +169 -0
- package/dist/server/app.module.d.ts +2 -0
- package/dist/server/app.module.js +38 -0
- package/dist/server/auth/auth.controller.d.ts +20 -0
- package/dist/server/auth/auth.controller.js +64 -0
- package/dist/server/auth/auth.module.d.ts +2 -0
- package/dist/server/auth/auth.module.js +19 -0
- package/dist/server/bootstrap.d.ts +15 -0
- package/dist/server/bootstrap.js +38 -0
- package/dist/server/config/config.controller.d.ts +73 -0
- package/dist/server/config/config.controller.js +95 -0
- package/dist/server/config/config.module.d.ts +2 -0
- package/dist/server/config/config.module.js +21 -0
- package/dist/server/config/config.service.d.ts +82 -0
- package/dist/server/config/config.service.js +123 -0
- package/dist/server/database/database.module.d.ts +2 -0
- package/dist/server/database/database.module.js +18 -0
- package/dist/server/database/database.service.d.ts +26 -0
- package/dist/server/database/database.service.js +253 -0
- package/dist/server/main.d.ts +1 -0
- package/dist/server/main.js +9 -0
- package/dist/server/saved-items/saved-items.controller.d.ts +57 -0
- package/dist/server/saved-items/saved-items.controller.js +229 -0
- package/dist/server/saved-items/saved-items.module.d.ts +2 -0
- package/dist/server/saved-items/saved-items.module.js +25 -0
- package/dist/server/saved-items/saved-items.service.d.ts +31 -0
- package/dist/server/saved-items/saved-items.service.js +105 -0
- package/dist/server/saved-items/tags.controller.d.ts +30 -0
- package/dist/server/saved-items/tags.controller.js +85 -0
- package/dist/server/saved-items/tags.service.d.ts +24 -0
- package/dist/server/saved-items/tags.service.js +84 -0
- package/dist/server/skills/skills.controller.d.ts +63 -0
- package/dist/server/skills/skills.controller.js +194 -0
- package/dist/server/skills/skills.module.d.ts +2 -0
- package/dist/server/skills/skills.module.js +22 -0
- package/dist/server/skills/skills.service.d.ts +65 -0
- package/dist/server/skills/skills.service.js +388 -0
- package/dist/server/tasks/tasks.controller.d.ts +52 -0
- package/dist/server/tasks/tasks.controller.js +163 -0
- package/dist/server/tasks/tasks.module.d.ts +2 -0
- package/dist/server/tasks/tasks.module.js +23 -0
- package/dist/server/tasks/tasks.service.d.ts +86 -0
- package/dist/server/tasks/tasks.service.js +327 -0
- package/dist/server/usage/usage.controller.d.ts +12 -0
- package/dist/server/usage/usage.controller.js +46 -0
- package/dist/server/usage/usage.module.d.ts +2 -0
- package/dist/server/usage/usage.module.js +19 -0
- package/dist/server/usage/usage.service.d.ts +21 -0
- package/dist/server/usage/usage.service.js +55 -0
- package/dist/server/users/users.controller.d.ts +35 -0
- package/dist/server/users/users.controller.js +69 -0
- package/dist/server/users/users.module.d.ts +2 -0
- package/dist/server/users/users.module.js +19 -0
- package/dist/server/users/users.service.d.ts +39 -0
- package/dist/server/users/users.service.js +140 -0
- package/dist/server/workspace/workspace.controller.d.ts +24 -0
- package/dist/server/workspace/workspace.controller.js +132 -0
- package/dist/server/workspace/workspace.module.d.ts +2 -0
- package/dist/server/workspace/workspace.module.js +21 -0
- package/dist/server/workspace/workspace.service.d.ts +36 -0
- package/dist/server/workspace/workspace.service.js +142 -0
- package/package.json +90 -0
- package/skills/agent-browser/SKILL.md +207 -0
- package/skills/agent-browser/references/authentication.md +202 -0
- package/skills/agent-browser/references/commands.md +259 -0
- package/skills/agent-browser/references/proxy-support.md +188 -0
- package/skills/agent-browser/references/session-management.md +193 -0
- package/skills/agent-browser/references/snapshot-refs.md +194 -0
- package/skills/agent-browser/references/video-recording.md +173 -0
- package/skills/agent-browser/templates/authenticated-session.sh +97 -0
- package/skills/agent-browser/templates/capture-workflow.sh +69 -0
- package/skills/agent-browser/templates/form-automation.sh +62 -0
- package/skills/find-skills/SKILL.md +140 -0
- package/skills/url-bookmark/SKILL.md +36 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { Injectable } from '@nestjs/common';
|
|
11
|
+
import { readFile, writeFile, mkdir } from 'fs/promises';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
import { existsSync } from 'fs';
|
|
14
|
+
import { getProviderSupport, syncDesktopConfigToModelsJson } from '../../core/config/desktop-config.js';
|
|
15
|
+
import { AgentConfigService } from '../agent-config/agent-config.service.js';
|
|
16
|
+
let ConfigService = class ConfigService {
|
|
17
|
+
agentConfigService;
|
|
18
|
+
configPath;
|
|
19
|
+
config;
|
|
20
|
+
constructor(agentConfigService) {
|
|
21
|
+
this.agentConfigService = agentConfigService;
|
|
22
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
|
|
23
|
+
const configDir = join(homeDir, '.openbot', 'desktop');
|
|
24
|
+
this.configPath = join(configDir, 'config.json');
|
|
25
|
+
// Ensure config directory exists
|
|
26
|
+
if (!existsSync(configDir)) {
|
|
27
|
+
mkdir(configDir, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
this.config = this.getDefaultConfig();
|
|
30
|
+
this.loadConfig();
|
|
31
|
+
}
|
|
32
|
+
getDefaultConfig() {
|
|
33
|
+
return {
|
|
34
|
+
gatewayUrl: 'ws://localhost:38080',
|
|
35
|
+
defaultProvider: 'deepseek',
|
|
36
|
+
defaultModel: 'deepseek-chat',
|
|
37
|
+
defaultAgentId: 'default',
|
|
38
|
+
theme: 'dark',
|
|
39
|
+
maxAgentSessions: 5,
|
|
40
|
+
providers: {},
|
|
41
|
+
configuredModels: [],
|
|
42
|
+
rag: undefined,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** 当前缺省智能体 id */
|
|
46
|
+
getDefaultAgentId(config) {
|
|
47
|
+
const c = config ?? this.config;
|
|
48
|
+
return (c.defaultAgentId ?? 'default').trim() || 'default';
|
|
49
|
+
}
|
|
50
|
+
async loadConfig() {
|
|
51
|
+
try {
|
|
52
|
+
if (existsSync(this.configPath)) {
|
|
53
|
+
const content = await readFile(this.configPath, 'utf-8');
|
|
54
|
+
this.config = { ...this.getDefaultConfig(), ...JSON.parse(content) };
|
|
55
|
+
this.config.defaultAgentId = this.getDefaultAgentId(this.config);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
console.error('Error loading config:', error);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** 每次获取前从磁盘重新读取,保证打开配置界面时显示最新(含 CLI 写入的配置) */
|
|
63
|
+
async getConfig() {
|
|
64
|
+
await this.loadConfig();
|
|
65
|
+
return this.config;
|
|
66
|
+
}
|
|
67
|
+
async updateConfig(updates) {
|
|
68
|
+
this.config = { ...this.config, ...updates };
|
|
69
|
+
this.config.defaultAgentId = this.getDefaultAgentId(this.config);
|
|
70
|
+
const p = this.config.defaultProvider;
|
|
71
|
+
const m = this.config.defaultModel;
|
|
72
|
+
const list = this.config.configuredModels ?? [];
|
|
73
|
+
if (p && m && list.length) {
|
|
74
|
+
const item = list.find((x) => x.provider === p && x.modelId === m);
|
|
75
|
+
if (item?.modelItemCode)
|
|
76
|
+
this.config.defaultModelItemCode = item.modelItemCode;
|
|
77
|
+
}
|
|
78
|
+
await this.saveConfig();
|
|
79
|
+
await this.agentConfigService.syncDefaultAgentFromConfig(this.config).catch((err) => console.warn('[ConfigService] syncDefaultAgentFromConfig failed', err));
|
|
80
|
+
await syncDesktopConfigToModelsJson().catch((err) => console.warn('[ConfigService] syncDesktopConfigToModelsJson failed', err));
|
|
81
|
+
return this.config;
|
|
82
|
+
}
|
|
83
|
+
async saveConfig() {
|
|
84
|
+
try {
|
|
85
|
+
await writeFile(this.configPath, JSON.stringify(this.config, null, 2));
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
console.error('Error saving config:', error);
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** 支持的 provider 列表(来自 provider-support.json,供配置时下拉) */
|
|
93
|
+
async getProviders() {
|
|
94
|
+
const support = await getProviderSupport();
|
|
95
|
+
return Object.keys(support);
|
|
96
|
+
}
|
|
97
|
+
/** 某 provider 下的可用模型(来自 provider-support);可按 type 筛选(llm/embedding/image/audio/video) */
|
|
98
|
+
async getModels(provider, type) {
|
|
99
|
+
const support = await getProviderSupport();
|
|
100
|
+
const entry = support[provider];
|
|
101
|
+
if (!entry?.models?.length)
|
|
102
|
+
return [];
|
|
103
|
+
let list = entry.models.map((m) => ({
|
|
104
|
+
id: m.id,
|
|
105
|
+
name: m.name || m.id,
|
|
106
|
+
types: m.types && m.types.length > 0 ? m.types : ["llm"],
|
|
107
|
+
}));
|
|
108
|
+
if (type && type.trim()) {
|
|
109
|
+
const t = type.trim().toLowerCase();
|
|
110
|
+
list = list.filter((m) => m.types?.includes(t));
|
|
111
|
+
}
|
|
112
|
+
return list;
|
|
113
|
+
}
|
|
114
|
+
/** 完整 provider 目录(支持列表 + 各 provider 的模型),供前端一次拉取 */
|
|
115
|
+
async getProviderSupport() {
|
|
116
|
+
return getProviderSupport();
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
ConfigService = __decorate([
|
|
120
|
+
Injectable(),
|
|
121
|
+
__metadata("design:paramtypes", [AgentConfigService])
|
|
122
|
+
], ConfigService);
|
|
123
|
+
export { ConfigService };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { Global, Module } from '@nestjs/common';
|
|
8
|
+
import { DatabaseService } from './database.service.js';
|
|
9
|
+
let DatabaseModule = class DatabaseModule {
|
|
10
|
+
};
|
|
11
|
+
DatabaseModule = __decorate([
|
|
12
|
+
Global(),
|
|
13
|
+
Module({
|
|
14
|
+
providers: [DatabaseService],
|
|
15
|
+
exports: [DatabaseService],
|
|
16
|
+
})
|
|
17
|
+
], DatabaseModule);
|
|
18
|
+
export { DatabaseModule };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { OnModuleDestroy, OnModuleInit } from '@nestjs/common';
|
|
2
|
+
/** RunResult compatible with better-sqlite3 for callers that use .changes / .lastInsertRowid */
|
|
3
|
+
export interface RunResult {
|
|
4
|
+
changes: number;
|
|
5
|
+
lastInsertRowid: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class DatabaseService implements OnModuleInit, OnModuleDestroy {
|
|
8
|
+
private sqlDb;
|
|
9
|
+
private dbPath;
|
|
10
|
+
private initPromise;
|
|
11
|
+
onModuleInit(): Promise<void>;
|
|
12
|
+
private doInit;
|
|
13
|
+
private getDb;
|
|
14
|
+
private runMigrations;
|
|
15
|
+
run(sql: string, params?: unknown[]): RunResult;
|
|
16
|
+
/**
|
|
17
|
+
* 使用文件 DB 时立即落盘。每次 run() 写入后都会调用,保证「每次保存马上写到磁盘」。
|
|
18
|
+
* 落盘失败时重新抛出,便于上层返回错误、前端不乐观更新,避免「删了但重启又出现」。
|
|
19
|
+
*/
|
|
20
|
+
private persistIfFile;
|
|
21
|
+
/** 供删除等关键操作后显式落盘,确保删除结果持久化 */
|
|
22
|
+
persist(): void;
|
|
23
|
+
get<T>(sql: string, params?: unknown[]): T | undefined;
|
|
24
|
+
all<T>(sql: string, params?: unknown[]): T[];
|
|
25
|
+
onModuleDestroy(): void;
|
|
26
|
+
}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { Injectable } from '@nestjs/common';
|
|
8
|
+
import { mkdirSync, existsSync, readFileSync, writeFileSync } from 'fs';
|
|
9
|
+
import { join, resolve } from 'path';
|
|
10
|
+
import { homedir } from 'os';
|
|
11
|
+
let DatabaseService = class DatabaseService {
|
|
12
|
+
sqlDb = null;
|
|
13
|
+
dbPath = null;
|
|
14
|
+
initPromise = null;
|
|
15
|
+
async onModuleInit() {
|
|
16
|
+
if (this.initPromise)
|
|
17
|
+
return this.initPromise;
|
|
18
|
+
this.initPromise = this.doInit();
|
|
19
|
+
return this.initPromise;
|
|
20
|
+
}
|
|
21
|
+
async doInit() {
|
|
22
|
+
const pathEnv = process.env.OPENBOT_DB_PATH;
|
|
23
|
+
const defaultDir = join(homedir(), '.openbot', 'desktop', 'data');
|
|
24
|
+
const path = pathEnv === ':memory:' || pathEnv === ''
|
|
25
|
+
? ':memory:'
|
|
26
|
+
: pathEnv ?? join(process.env.OPENBOT_DB_DIR ?? defaultDir, 'openbot.db');
|
|
27
|
+
if (path !== ':memory:') {
|
|
28
|
+
const resolvedPath = resolve(path);
|
|
29
|
+
const dir = resolvedPath.endsWith('.db') ? join(resolvedPath, '..') : resolvedPath;
|
|
30
|
+
if (!existsSync(dir)) {
|
|
31
|
+
mkdirSync(dir, { recursive: true });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const initSqlJs = (await import('sql.js')).default;
|
|
35
|
+
const SQL = await initSqlJs();
|
|
36
|
+
let db;
|
|
37
|
+
if (path === ':memory:') {
|
|
38
|
+
db = new SQL.Database();
|
|
39
|
+
this.dbPath = ':memory:';
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
const absolutePath = resolve(path);
|
|
43
|
+
if (existsSync(absolutePath)) {
|
|
44
|
+
const buf = readFileSync(absolutePath);
|
|
45
|
+
db = new SQL.Database(new Uint8Array(buf));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
db = new SQL.Database();
|
|
49
|
+
}
|
|
50
|
+
this.dbPath = absolutePath;
|
|
51
|
+
}
|
|
52
|
+
this.sqlDb = db;
|
|
53
|
+
db.run('PRAGMA foreign_keys = ON;');
|
|
54
|
+
this.runMigrations();
|
|
55
|
+
if (path !== ':memory:') {
|
|
56
|
+
this.persistIfFile();
|
|
57
|
+
console.log('[DatabaseService] Database file:', this.dbPath);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
getDb() {
|
|
61
|
+
if (!this.sqlDb) {
|
|
62
|
+
throw new Error('Database not initialized. Ensure onModuleInit() has completed (Nest awaits it before listening).');
|
|
63
|
+
}
|
|
64
|
+
return this.sqlDb;
|
|
65
|
+
}
|
|
66
|
+
runMigrations() {
|
|
67
|
+
const db = this.getDb();
|
|
68
|
+
const ddl = `
|
|
69
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
70
|
+
id TEXT PRIMARY KEY,
|
|
71
|
+
created_at INTEGER NOT NULL,
|
|
72
|
+
last_active_at INTEGER NOT NULL,
|
|
73
|
+
message_count INTEGER NOT NULL DEFAULT 0,
|
|
74
|
+
status TEXT NOT NULL DEFAULT 'idle',
|
|
75
|
+
agent_id TEXT DEFAULT 'default',
|
|
76
|
+
workspace TEXT,
|
|
77
|
+
provider TEXT,
|
|
78
|
+
model TEXT,
|
|
79
|
+
title TEXT,
|
|
80
|
+
preview TEXT,
|
|
81
|
+
type TEXT DEFAULT 'chat'
|
|
82
|
+
);
|
|
83
|
+
CREATE TABLE IF NOT EXISTS chat_messages (
|
|
84
|
+
id TEXT PRIMARY KEY,
|
|
85
|
+
session_id TEXT NOT NULL,
|
|
86
|
+
role TEXT NOT NULL,
|
|
87
|
+
content TEXT NOT NULL,
|
|
88
|
+
timestamp INTEGER NOT NULL,
|
|
89
|
+
tool_calls_json TEXT,
|
|
90
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
91
|
+
);
|
|
92
|
+
CREATE INDEX IF NOT EXISTS idx_chat_messages_session_id ON chat_messages(session_id);
|
|
93
|
+
|
|
94
|
+
CREATE TABLE IF NOT EXISTS scheduled_tasks (
|
|
95
|
+
id TEXT PRIMARY KEY,
|
|
96
|
+
workspace TEXT NOT NULL DEFAULT 'default',
|
|
97
|
+
message TEXT NOT NULL,
|
|
98
|
+
schedule_type TEXT NOT NULL,
|
|
99
|
+
run_at INTEGER,
|
|
100
|
+
cron_expr TEXT,
|
|
101
|
+
repeat_rule_json TEXT,
|
|
102
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
103
|
+
last_run_at INTEGER,
|
|
104
|
+
created_at INTEGER NOT NULL,
|
|
105
|
+
updated_at INTEGER NOT NULL
|
|
106
|
+
);
|
|
107
|
+
CREATE INDEX IF NOT EXISTS idx_scheduled_tasks_enabled ON scheduled_tasks(enabled);
|
|
108
|
+
|
|
109
|
+
CREATE TABLE IF NOT EXISTS scheduled_task_executions (
|
|
110
|
+
id TEXT PRIMARY KEY,
|
|
111
|
+
task_id TEXT NOT NULL,
|
|
112
|
+
ran_at INTEGER NOT NULL,
|
|
113
|
+
status TEXT NOT NULL,
|
|
114
|
+
session_id TEXT,
|
|
115
|
+
user_message TEXT NOT NULL,
|
|
116
|
+
assistant_content TEXT,
|
|
117
|
+
error_message TEXT,
|
|
118
|
+
created_at INTEGER NOT NULL,
|
|
119
|
+
FOREIGN KEY (task_id) REFERENCES scheduled_tasks(id) ON DELETE CASCADE
|
|
120
|
+
);
|
|
121
|
+
CREATE INDEX IF NOT EXISTS idx_task_executions_task_id ON scheduled_task_executions(task_id);
|
|
122
|
+
|
|
123
|
+
CREATE TABLE IF NOT EXISTS token_usage (
|
|
124
|
+
id TEXT PRIMARY KEY,
|
|
125
|
+
session_id TEXT NOT NULL,
|
|
126
|
+
source TEXT NOT NULL,
|
|
127
|
+
task_id TEXT,
|
|
128
|
+
execution_id TEXT,
|
|
129
|
+
prompt_tokens INTEGER NOT NULL DEFAULT 0,
|
|
130
|
+
completion_tokens INTEGER NOT NULL DEFAULT 0,
|
|
131
|
+
total_tokens INTEGER NOT NULL DEFAULT 0,
|
|
132
|
+
created_at INTEGER NOT NULL
|
|
133
|
+
);
|
|
134
|
+
CREATE INDEX IF NOT EXISTS idx_token_usage_session_id ON token_usage(session_id);
|
|
135
|
+
CREATE INDEX IF NOT EXISTS idx_token_usage_created_at ON token_usage(created_at);
|
|
136
|
+
|
|
137
|
+
CREATE TABLE IF NOT EXISTS tags (
|
|
138
|
+
id TEXT PRIMARY KEY,
|
|
139
|
+
name TEXT UNIQUE NOT NULL,
|
|
140
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
141
|
+
created_at INTEGER NOT NULL
|
|
142
|
+
);
|
|
143
|
+
CREATE TABLE IF NOT EXISTS saved_items (
|
|
144
|
+
id TEXT PRIMARY KEY,
|
|
145
|
+
url TEXT NOT NULL,
|
|
146
|
+
title TEXT,
|
|
147
|
+
workspace TEXT NOT NULL DEFAULT 'default',
|
|
148
|
+
created_at INTEGER NOT NULL
|
|
149
|
+
);
|
|
150
|
+
CREATE TABLE IF NOT EXISTS saved_item_tags (
|
|
151
|
+
saved_item_id TEXT NOT NULL,
|
|
152
|
+
tag_id TEXT NOT NULL,
|
|
153
|
+
PRIMARY KEY (saved_item_id, tag_id),
|
|
154
|
+
FOREIGN KEY (saved_item_id) REFERENCES saved_items(id) ON DELETE CASCADE,
|
|
155
|
+
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
|
|
156
|
+
);
|
|
157
|
+
CREATE INDEX IF NOT EXISTS idx_saved_item_tags_tag_id ON saved_item_tags(tag_id);
|
|
158
|
+
`;
|
|
159
|
+
const statements = ddl.split(';').map((s) => s.trim()).filter(Boolean);
|
|
160
|
+
for (const stmt of statements) {
|
|
161
|
+
db.run(stmt + ';');
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
const info = this.all('PRAGMA table_info(sessions)', []);
|
|
165
|
+
if (!info.some((c) => c.name === 'type')) {
|
|
166
|
+
db.run("ALTER TABLE sessions ADD COLUMN type TEXT DEFAULT 'chat';");
|
|
167
|
+
}
|
|
168
|
+
if (!info.some((c) => c.name === 'agent_id')) {
|
|
169
|
+
db.run("ALTER TABLE sessions ADD COLUMN agent_id TEXT DEFAULT 'default';");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (_) {
|
|
173
|
+
// ignore
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
run(sql, params = []) {
|
|
177
|
+
const db = this.getDb();
|
|
178
|
+
db.run(sql, params);
|
|
179
|
+
this.persistIfFile();
|
|
180
|
+
const rows = db.exec('SELECT changes() AS c, last_insert_rowid() AS id');
|
|
181
|
+
const c = rows[0]?.values?.[0]?.[0] ?? 0;
|
|
182
|
+
const id = rows[0]?.values?.[0]?.[1] ?? 0;
|
|
183
|
+
return { changes: Number(c), lastInsertRowid: Number(id) };
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* 使用文件 DB 时立即落盘。每次 run() 写入后都会调用,保证「每次保存马上写到磁盘」。
|
|
187
|
+
* 落盘失败时重新抛出,便于上层返回错误、前端不乐观更新,避免「删了但重启又出现」。
|
|
188
|
+
*/
|
|
189
|
+
persistIfFile() {
|
|
190
|
+
if (!this.sqlDb || !this.dbPath || this.dbPath === ':memory:')
|
|
191
|
+
return;
|
|
192
|
+
try {
|
|
193
|
+
const data = this.sqlDb.export();
|
|
194
|
+
writeFileSync(this.dbPath, Buffer.from(data));
|
|
195
|
+
}
|
|
196
|
+
catch (e) {
|
|
197
|
+
console.error('[DatabaseService] Failed to persist database:', e);
|
|
198
|
+
throw e;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/** 供删除等关键操作后显式落盘,确保删除结果持久化 */
|
|
202
|
+
persist() {
|
|
203
|
+
this.persistIfFile();
|
|
204
|
+
}
|
|
205
|
+
get(sql, params = []) {
|
|
206
|
+
const db = this.getDb();
|
|
207
|
+
const stmt = db.prepare(sql);
|
|
208
|
+
try {
|
|
209
|
+
stmt.bind(params);
|
|
210
|
+
const hasRow = stmt.step();
|
|
211
|
+
return (hasRow ? stmt.getAsObject() : undefined);
|
|
212
|
+
}
|
|
213
|
+
finally {
|
|
214
|
+
stmt.free();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
all(sql, params = []) {
|
|
218
|
+
const db = this.getDb();
|
|
219
|
+
const stmt = db.prepare(sql);
|
|
220
|
+
try {
|
|
221
|
+
stmt.bind(params);
|
|
222
|
+
const rows = [];
|
|
223
|
+
while (stmt.step()) {
|
|
224
|
+
rows.push(stmt.getAsObject());
|
|
225
|
+
}
|
|
226
|
+
return rows;
|
|
227
|
+
}
|
|
228
|
+
finally {
|
|
229
|
+
stmt.free();
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
onModuleDestroy() {
|
|
233
|
+
if (!this.sqlDb)
|
|
234
|
+
return;
|
|
235
|
+
if (this.dbPath && this.dbPath !== ':memory:') {
|
|
236
|
+
try {
|
|
237
|
+
const data = this.sqlDb.export();
|
|
238
|
+
writeFileSync(this.dbPath, Buffer.from(data));
|
|
239
|
+
}
|
|
240
|
+
catch (e) {
|
|
241
|
+
console.error('[DatabaseService] Failed to persist database:', e);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
this.sqlDb.close();
|
|
245
|
+
this.sqlDb = null;
|
|
246
|
+
this.dbPath = null;
|
|
247
|
+
this.initPromise = null;
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
DatabaseService = __decorate([
|
|
251
|
+
Injectable()
|
|
252
|
+
], DatabaseService);
|
|
253
|
+
export { DatabaseService };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenBot Desktop 后端入口(独立模式)。
|
|
3
|
+
* 内嵌到 Gateway 时由 gateway/server 调用 createNestAppEmbedded,不经过本文件。
|
|
4
|
+
*/
|
|
5
|
+
import { createNestAppStandalone } from './bootstrap.js';
|
|
6
|
+
const port = Number(process.env.PORT) || 38081;
|
|
7
|
+
createNestAppStandalone(port).then(() => {
|
|
8
|
+
console.log(`🚀 OpenBot Desktop Server running on http://localhost:${port}`);
|
|
9
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Response } from 'express';
|
|
2
|
+
import { SavedItemsService } from './saved-items.service.js';
|
|
3
|
+
import { WorkspaceService } from '../workspace/workspace.service.js';
|
|
4
|
+
import { ConfigService } from '../config/config.service.js';
|
|
5
|
+
export declare class SavedItemsController {
|
|
6
|
+
private readonly savedItemsService;
|
|
7
|
+
private readonly workspaceService;
|
|
8
|
+
private readonly configService;
|
|
9
|
+
constructor(savedItemsService: SavedItemsService, workspaceService: WorkspaceService, configService: ConfigService);
|
|
10
|
+
list(tagId?: string, workspace?: string): Promise<{
|
|
11
|
+
success: boolean;
|
|
12
|
+
data: import("./saved-items.service.js").SavedItem[];
|
|
13
|
+
}>;
|
|
14
|
+
imageProxy(url: string, res: Response): Promise<void>;
|
|
15
|
+
get(id: string): Promise<{
|
|
16
|
+
success: boolean;
|
|
17
|
+
data: import("./saved-items.service.js").SavedItem;
|
|
18
|
+
}>;
|
|
19
|
+
create(body: {
|
|
20
|
+
url: string;
|
|
21
|
+
title?: string;
|
|
22
|
+
workspace?: string;
|
|
23
|
+
tagNames?: string[];
|
|
24
|
+
tagIds?: string[];
|
|
25
|
+
}): Promise<{
|
|
26
|
+
success: boolean;
|
|
27
|
+
data: import("./saved-items.service.js").SavedItem;
|
|
28
|
+
}>;
|
|
29
|
+
delete(id: string): Promise<{
|
|
30
|
+
success: boolean;
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* Download the saved item URL to workspace .favorite or to a user-chosen directory.
|
|
34
|
+
* Body: { workspace?: string, targetDir?: string }.
|
|
35
|
+
* If targetDir (absolute path) is provided, file is written there; otherwise to workspace/.favorite.
|
|
36
|
+
*/
|
|
37
|
+
downloadToWorkspace(id: string, body: {
|
|
38
|
+
workspace?: string;
|
|
39
|
+
targetDir?: string;
|
|
40
|
+
}): Promise<{
|
|
41
|
+
success: boolean;
|
|
42
|
+
data: {
|
|
43
|
+
absolutePath: string;
|
|
44
|
+
targetDir: string;
|
|
45
|
+
relativePath?: undefined;
|
|
46
|
+
workspace?: undefined;
|
|
47
|
+
};
|
|
48
|
+
} | {
|
|
49
|
+
success: boolean;
|
|
50
|
+
data: {
|
|
51
|
+
relativePath: string;
|
|
52
|
+
workspace: string;
|
|
53
|
+
absolutePath?: undefined;
|
|
54
|
+
targetDir?: undefined;
|
|
55
|
+
};
|
|
56
|
+
}>;
|
|
57
|
+
}
|