@next-open-ai/openbot 0.1.1
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 +212 -0
- package/dist/agent/agent-dir.d.ts +14 -0
- package/dist/agent/agent-dir.js +75 -0
- package/dist/agent/agent-manager.d.ts +61 -0
- package/dist/agent/agent-manager.js +257 -0
- package/dist/agent/config-manager.d.ts +25 -0
- package/dist/agent/config-manager.js +84 -0
- package/dist/agent/desktop-config.d.ts +15 -0
- package/dist/agent/desktop-config.js +91 -0
- package/dist/agent/run.d.ts +26 -0
- package/dist/agent/run.js +65 -0
- package/dist/agent/skills.d.ts +20 -0
- package/dist/agent/skills.js +86 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +168 -0
- package/dist/gateway/backend-url.d.ts +2 -0
- package/dist/gateway/backend-url.js +11 -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/desktop-config.d.ts +7 -0
- package/dist/gateway/desktop-config.js +25 -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 +194 -0
- package/dist/gateway/methods/connect.d.ts +8 -0
- package/dist/gateway/methods/connect.js +15 -0
- package/dist/gateway/methods/install-skill-from-path.d.ts +13 -0
- package/dist/gateway/methods/install-skill-from-path.js +48 -0
- package/dist/gateway/methods/run-scheduled-task.d.ts +13 -0
- package/dist/gateway/methods/run-scheduled-task.js +164 -0
- package/dist/gateway/server.d.ts +10 -0
- package/dist/gateway/server.js +268 -0
- package/dist/gateway/types.d.ts +76 -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/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/memory/build-summary.d.ts +6 -0
- package/dist/memory/build-summary.js +27 -0
- package/dist/memory/compaction-extension.d.ts +6 -0
- package/dist/memory/compaction-extension.js +23 -0
- package/dist/memory/embedding.d.ts +10 -0
- package/dist/memory/embedding.js +22 -0
- package/dist/memory/index.d.ts +29 -0
- package/dist/memory/index.js +66 -0
- package/dist/memory/types.d.ts +16 -0
- package/dist/memory/types.js +1 -0
- package/dist/memory/vector-store.d.ts +15 -0
- package/dist/memory/vector-store.js +65 -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 +34 -0
- package/dist/server/agent-config/agent-config.service.js +171 -0
- package/dist/server/agents/agents.controller.d.ts +41 -0
- package/dist/server/agents/agents.controller.js +120 -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 +167 -0
- package/dist/server/app.module.d.ts +2 -0
- package/dist/server/app.module.js +36 -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/config/config.controller.d.ts +51 -0
- package/dist/server/config/config.controller.js +81 -0
- package/dist/server/config/config.module.d.ts +2 -0
- package/dist/server/config/config.module.js +19 -0
- package/dist/server/config/config.service.d.ts +34 -0
- package/dist/server/config/config.service.js +91 -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 +11 -0
- package/dist/server/database/database.service.js +137 -0
- package/dist/server/main.d.ts +1 -0
- package/dist/server/main.js +18 -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 +63 -0
- package/dist/server/skills/skills.service.js +324 -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 +22 -0
- package/dist/server/tasks/tasks.service.d.ts +84 -0
- package/dist/server/tasks/tasks.service.js +313 -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 +25 -0
- package/dist/server/workspace/workspace.service.js +103 -0
- package/dist/tools/browser-tool.d.ts +10 -0
- package/dist/tools/browser-tool.js +362 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +3 -0
- package/dist/tools/install-skill-tool.d.ts +9 -0
- package/dist/tools/install-skill-tool.js +77 -0
- package/dist/tools/save-experience-tool.d.ts +5 -0
- package/dist/tools/save-experience-tool.js +54 -0
- package/package.json +80 -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
|
@@ -0,0 +1,140 @@
|
|
|
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, ConflictException, NotFoundException } from '@nestjs/common';
|
|
11
|
+
import { readFile, writeFile, mkdir } from 'fs/promises';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
import { existsSync } from 'fs';
|
|
14
|
+
import { randomUUID } from 'crypto';
|
|
15
|
+
const DEFAULT_ADMIN_USERNAME = 'admin';
|
|
16
|
+
const DEFAULT_ADMIN_PASSWORD = '123456';
|
|
17
|
+
let UsersService = class UsersService {
|
|
18
|
+
usersPath;
|
|
19
|
+
constructor() {
|
|
20
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
|
|
21
|
+
const configDir = join(homeDir, '.openbot', 'desktop');
|
|
22
|
+
this.usersPath = join(configDir, 'users.json');
|
|
23
|
+
if (!existsSync(configDir)) {
|
|
24
|
+
mkdir(configDir, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async load() {
|
|
28
|
+
let users = [];
|
|
29
|
+
try {
|
|
30
|
+
if (existsSync(this.usersPath)) {
|
|
31
|
+
const content = await readFile(this.usersPath, 'utf-8');
|
|
32
|
+
const data = JSON.parse(content);
|
|
33
|
+
users = Array.isArray(data.users) ? data.users : [];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
console.error('Load users failed:', e);
|
|
38
|
+
}
|
|
39
|
+
if (users.length === 0) {
|
|
40
|
+
const defaultAdmin = {
|
|
41
|
+
id: randomUUID(),
|
|
42
|
+
username: DEFAULT_ADMIN_USERNAME,
|
|
43
|
+
password: DEFAULT_ADMIN_PASSWORD,
|
|
44
|
+
};
|
|
45
|
+
users = [defaultAdmin];
|
|
46
|
+
await this.save(users);
|
|
47
|
+
}
|
|
48
|
+
return users;
|
|
49
|
+
}
|
|
50
|
+
async save(users) {
|
|
51
|
+
await writeFile(this.usersPath, JSON.stringify({ users }, null, 2));
|
|
52
|
+
}
|
|
53
|
+
async list() {
|
|
54
|
+
const users = await this.load();
|
|
55
|
+
return users.map((u) => ({ id: u.id, username: u.username }));
|
|
56
|
+
}
|
|
57
|
+
async create(username, password) {
|
|
58
|
+
const trimmed = (username ?? '').trim();
|
|
59
|
+
const pass = (password ?? '').trim();
|
|
60
|
+
if (!trimmed)
|
|
61
|
+
throw new ConflictException('Username is required');
|
|
62
|
+
const users = await this.load();
|
|
63
|
+
const lower = trimmed.toLowerCase();
|
|
64
|
+
if (users.some((u) => u.username.toLowerCase() === lower)) {
|
|
65
|
+
throw new ConflictException('Username already exists');
|
|
66
|
+
}
|
|
67
|
+
const id = randomUUID();
|
|
68
|
+
users.push({ id, username: trimmed, password: pass });
|
|
69
|
+
await this.save(users);
|
|
70
|
+
return { id, username: trimmed };
|
|
71
|
+
}
|
|
72
|
+
async update(id, updates) {
|
|
73
|
+
const users = await this.load();
|
|
74
|
+
const idx = users.findIndex((u) => u.id === id);
|
|
75
|
+
if (idx < 0)
|
|
76
|
+
throw new NotFoundException('User not found');
|
|
77
|
+
if (updates.username !== undefined) {
|
|
78
|
+
const trimmed = updates.username.trim();
|
|
79
|
+
if (!trimmed)
|
|
80
|
+
throw new ConflictException('Username is required');
|
|
81
|
+
const lower = trimmed.toLowerCase();
|
|
82
|
+
if (users.some((u, i) => i !== idx && u.username.toLowerCase() === lower)) {
|
|
83
|
+
throw new ConflictException('Username already exists');
|
|
84
|
+
}
|
|
85
|
+
users[idx].username = trimmed;
|
|
86
|
+
}
|
|
87
|
+
if (updates.password !== undefined) {
|
|
88
|
+
users[idx].password = updates.password.trim();
|
|
89
|
+
}
|
|
90
|
+
await this.save(users);
|
|
91
|
+
return { id: users[idx].id, username: users[idx].username };
|
|
92
|
+
}
|
|
93
|
+
async delete(id) {
|
|
94
|
+
const users = await this.load();
|
|
95
|
+
const filtered = users.filter((u) => u.id !== id);
|
|
96
|
+
if (filtered.length === users.length)
|
|
97
|
+
throw new NotFoundException('User not found');
|
|
98
|
+
await this.save(filtered);
|
|
99
|
+
}
|
|
100
|
+
async validateCredentials(username, password) {
|
|
101
|
+
const users = await this.load();
|
|
102
|
+
if (users.length === 0)
|
|
103
|
+
return false;
|
|
104
|
+
const user = (username ?? '').trim().toLowerCase();
|
|
105
|
+
const pass = (password ?? '').trim();
|
|
106
|
+
const found = users.find((u) => u.username.toLowerCase() === user);
|
|
107
|
+
return found ? found.password === pass : false;
|
|
108
|
+
}
|
|
109
|
+
/** 根据用户名查找用户(用于登录后返回当前用户信息) */
|
|
110
|
+
async findByUsername(username) {
|
|
111
|
+
const users = await this.load();
|
|
112
|
+
const lower = (username ?? '').trim().toLowerCase();
|
|
113
|
+
const found = users.find((u) => u.username.toLowerCase() === lower);
|
|
114
|
+
return found ? { id: found.id, username: found.username } : null;
|
|
115
|
+
}
|
|
116
|
+
async hasUsers() {
|
|
117
|
+
const users = await this.load();
|
|
118
|
+
return users.length > 0;
|
|
119
|
+
}
|
|
120
|
+
/** 确保缺省 admin 用户存在,若不存在则创建并保存。返回该用户的 { id, username } */
|
|
121
|
+
async ensureDefaultAdmin() {
|
|
122
|
+
const users = await this.load();
|
|
123
|
+
const existing = users.find((u) => u.username.toLowerCase() === DEFAULT_ADMIN_USERNAME.toLowerCase());
|
|
124
|
+
if (existing)
|
|
125
|
+
return { id: existing.id, username: existing.username };
|
|
126
|
+
const defaultAdmin = {
|
|
127
|
+
id: randomUUID(),
|
|
128
|
+
username: DEFAULT_ADMIN_USERNAME,
|
|
129
|
+
password: DEFAULT_ADMIN_PASSWORD,
|
|
130
|
+
};
|
|
131
|
+
users.push(defaultAdmin);
|
|
132
|
+
await this.save(users);
|
|
133
|
+
return { id: defaultAdmin.id, username: defaultAdmin.username };
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
UsersService = __decorate([
|
|
137
|
+
Injectable(),
|
|
138
|
+
__metadata("design:paramtypes", [])
|
|
139
|
+
], UsersService);
|
|
140
|
+
export { UsersService };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Response } from 'express';
|
|
2
|
+
import { WorkspaceService } from './workspace.service.js';
|
|
3
|
+
import { ConfigService } from '../config/config.service.js';
|
|
4
|
+
export declare class WorkspaceController {
|
|
5
|
+
private readonly workspaceService;
|
|
6
|
+
private readonly configService;
|
|
7
|
+
constructor(workspaceService: WorkspaceService, configService: ConfigService);
|
|
8
|
+
listWorkspaces(): Promise<{
|
|
9
|
+
success: boolean;
|
|
10
|
+
data: string[];
|
|
11
|
+
}>;
|
|
12
|
+
getCurrentWorkspace(): Promise<{
|
|
13
|
+
success: boolean;
|
|
14
|
+
data: string;
|
|
15
|
+
}>;
|
|
16
|
+
listDocuments(workspace: string, path?: string): Promise<{
|
|
17
|
+
success: boolean;
|
|
18
|
+
data: import("./workspace.service.js").WorkspaceItem[];
|
|
19
|
+
}>;
|
|
20
|
+
serveFile(workspace: string, path: string, download: string, res: Response): Promise<void>;
|
|
21
|
+
deleteDocument(workspace: string, path: string): Promise<{
|
|
22
|
+
success: boolean;
|
|
23
|
+
}>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
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
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { Controller, Get, Delete, Query, Res, HttpException, HttpStatus, NotFoundException, } from '@nestjs/common';
|
|
14
|
+
import { createReadStream } from 'fs';
|
|
15
|
+
import { existsSync } from 'fs';
|
|
16
|
+
import { stat } from 'fs/promises';
|
|
17
|
+
import { WorkspaceService } from './workspace.service.js';
|
|
18
|
+
import { ConfigService } from '../config/config.service.js';
|
|
19
|
+
const PREVIEW_TYPES = new Set([
|
|
20
|
+
'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml',
|
|
21
|
+
'application/pdf',
|
|
22
|
+
'text/plain', 'text/html', 'text/markdown', 'application/json',
|
|
23
|
+
]);
|
|
24
|
+
function getMimeType(filename) {
|
|
25
|
+
const ext = filename.split('.').pop()?.toLowerCase() || '';
|
|
26
|
+
const map = {
|
|
27
|
+
jpg: 'image/jpeg', jpeg: 'image/jpeg', png: 'image/png', gif: 'image/gif',
|
|
28
|
+
webp: 'image/webp', svg: 'image/svg+xml', pdf: 'application/pdf',
|
|
29
|
+
txt: 'text/plain', html: 'text/html', htm: 'text/html', md: 'text/markdown',
|
|
30
|
+
json: 'application/json',
|
|
31
|
+
};
|
|
32
|
+
return map[ext] || 'application/octet-stream';
|
|
33
|
+
}
|
|
34
|
+
let WorkspaceController = class WorkspaceController {
|
|
35
|
+
workspaceService;
|
|
36
|
+
configService;
|
|
37
|
+
constructor(workspaceService, configService) {
|
|
38
|
+
this.workspaceService = workspaceService;
|
|
39
|
+
this.configService = configService;
|
|
40
|
+
}
|
|
41
|
+
async listWorkspaces() {
|
|
42
|
+
const list = await this.workspaceService.listWorkspaces();
|
|
43
|
+
return { success: true, data: list };
|
|
44
|
+
}
|
|
45
|
+
async getCurrentWorkspace() {
|
|
46
|
+
const config = await this.configService.getConfig();
|
|
47
|
+
return { success: true, data: this.configService.getDefaultAgentId(config) };
|
|
48
|
+
}
|
|
49
|
+
async listDocuments(workspace, path = '') {
|
|
50
|
+
const name = workspace || this.configService.getDefaultAgentId(await this.configService.getConfig());
|
|
51
|
+
const items = await this.workspaceService.listDocuments(name, path);
|
|
52
|
+
return { success: true, data: items };
|
|
53
|
+
}
|
|
54
|
+
async serveFile(workspace, path, download, res) {
|
|
55
|
+
if (!path) {
|
|
56
|
+
throw new HttpException('path is required', HttpStatus.BAD_REQUEST);
|
|
57
|
+
}
|
|
58
|
+
const name = workspace || this.configService.getDefaultAgentId(await this.configService.getConfig());
|
|
59
|
+
const { absolutePath, safe } = this.workspaceService.resolveFilePath(name, path);
|
|
60
|
+
if (!safe || !existsSync(absolutePath)) {
|
|
61
|
+
throw new NotFoundException('File not found');
|
|
62
|
+
}
|
|
63
|
+
const fileStat = await stat(absolutePath);
|
|
64
|
+
if (!fileStat.isFile()) {
|
|
65
|
+
throw new HttpException('Not a file', HttpStatus.BAD_REQUEST);
|
|
66
|
+
}
|
|
67
|
+
const filename = path.split('/').pop() || path;
|
|
68
|
+
const mime = getMimeType(filename);
|
|
69
|
+
const isPreview = !download && PREVIEW_TYPES.has(mime);
|
|
70
|
+
res.setHeader('Content-Type', mime);
|
|
71
|
+
if (!isPreview) {
|
|
72
|
+
res.setHeader('Content-Disposition', `attachment; filename="${encodeURIComponent(filename)}"`);
|
|
73
|
+
}
|
|
74
|
+
const stream = createReadStream(absolutePath);
|
|
75
|
+
stream.pipe(res);
|
|
76
|
+
}
|
|
77
|
+
async deleteDocument(workspace, path) {
|
|
78
|
+
if (!path) {
|
|
79
|
+
throw new HttpException('path is required', HttpStatus.BAD_REQUEST);
|
|
80
|
+
}
|
|
81
|
+
const name = workspace || this.configService.getDefaultAgentId(await this.configService.getConfig());
|
|
82
|
+
const deleted = await this.workspaceService.deletePath(name, path);
|
|
83
|
+
if (!deleted) {
|
|
84
|
+
throw new NotFoundException('File or folder not found');
|
|
85
|
+
}
|
|
86
|
+
return { success: true };
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
__decorate([
|
|
90
|
+
Get(),
|
|
91
|
+
__metadata("design:type", Function),
|
|
92
|
+
__metadata("design:paramtypes", []),
|
|
93
|
+
__metadata("design:returntype", Promise)
|
|
94
|
+
], WorkspaceController.prototype, "listWorkspaces", null);
|
|
95
|
+
__decorate([
|
|
96
|
+
Get('current'),
|
|
97
|
+
__metadata("design:type", Function),
|
|
98
|
+
__metadata("design:paramtypes", []),
|
|
99
|
+
__metadata("design:returntype", Promise)
|
|
100
|
+
], WorkspaceController.prototype, "getCurrentWorkspace", null);
|
|
101
|
+
__decorate([
|
|
102
|
+
Get('documents'),
|
|
103
|
+
__param(0, Query('workspace')),
|
|
104
|
+
__param(1, Query('path')),
|
|
105
|
+
__metadata("design:type", Function),
|
|
106
|
+
__metadata("design:paramtypes", [String, String]),
|
|
107
|
+
__metadata("design:returntype", Promise)
|
|
108
|
+
], WorkspaceController.prototype, "listDocuments", null);
|
|
109
|
+
__decorate([
|
|
110
|
+
Get('files/serve'),
|
|
111
|
+
__param(0, Query('workspace')),
|
|
112
|
+
__param(1, Query('path')),
|
|
113
|
+
__param(2, Query('download')),
|
|
114
|
+
__param(3, Res({ passthrough: false })),
|
|
115
|
+
__metadata("design:type", Function),
|
|
116
|
+
__metadata("design:paramtypes", [String, String, String, Object]),
|
|
117
|
+
__metadata("design:returntype", Promise)
|
|
118
|
+
], WorkspaceController.prototype, "serveFile", null);
|
|
119
|
+
__decorate([
|
|
120
|
+
Delete('files'),
|
|
121
|
+
__param(0, Query('workspace')),
|
|
122
|
+
__param(1, Query('path')),
|
|
123
|
+
__metadata("design:type", Function),
|
|
124
|
+
__metadata("design:paramtypes", [String, String]),
|
|
125
|
+
__metadata("design:returntype", Promise)
|
|
126
|
+
], WorkspaceController.prototype, "deleteDocument", null);
|
|
127
|
+
WorkspaceController = __decorate([
|
|
128
|
+
Controller('workspace'),
|
|
129
|
+
__metadata("design:paramtypes", [WorkspaceService,
|
|
130
|
+
ConfigService])
|
|
131
|
+
], WorkspaceController);
|
|
132
|
+
export { WorkspaceController };
|
|
@@ -0,0 +1,21 @@
|
|
|
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 { Module } from '@nestjs/common';
|
|
8
|
+
import { WorkspaceController } from './workspace.controller.js';
|
|
9
|
+
import { WorkspaceService } from './workspace.service.js';
|
|
10
|
+
import { ConfigModule } from '../config/config.module.js';
|
|
11
|
+
let WorkspaceModule = class WorkspaceModule {
|
|
12
|
+
};
|
|
13
|
+
WorkspaceModule = __decorate([
|
|
14
|
+
Module({
|
|
15
|
+
imports: [ConfigModule],
|
|
16
|
+
controllers: [WorkspaceController],
|
|
17
|
+
providers: [WorkspaceService],
|
|
18
|
+
exports: [WorkspaceService],
|
|
19
|
+
})
|
|
20
|
+
], WorkspaceModule);
|
|
21
|
+
export { WorkspaceModule };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface WorkspaceItem {
|
|
2
|
+
name: string;
|
|
3
|
+
path: string;
|
|
4
|
+
isDirectory: boolean;
|
|
5
|
+
size?: number;
|
|
6
|
+
mtime?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare class WorkspaceService {
|
|
9
|
+
private getWorkspaceRoot;
|
|
10
|
+
/** List workspace names (directories under OPENBOT_WORKSPACE_DIR, default ~/.openbot/workspace) */
|
|
11
|
+
listWorkspaces(): Promise<string[]>;
|
|
12
|
+
/** List files and folders under a path relative to workspace root. Empty path = root. */
|
|
13
|
+
listDocuments(workspaceName: string, relativePath?: string): Promise<WorkspaceItem[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Resolve a relative path and ensure it stays under workspace root.
|
|
16
|
+
* Returns path suitable for join(workspaceRoot, result).
|
|
17
|
+
*/
|
|
18
|
+
resolveFilePath(workspaceName: string, relativePath: string): {
|
|
19
|
+
absolutePath: string;
|
|
20
|
+
safe: boolean;
|
|
21
|
+
};
|
|
22
|
+
/** Delete a file or directory (recursive) under workspace. Returns true if deleted. skills 与 .skills 目录禁止删除。 */
|
|
23
|
+
deletePath(workspaceName: string, relativePath: string): Promise<boolean>;
|
|
24
|
+
private safeRelativePath;
|
|
25
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
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 { readdir, stat, rm } from 'fs/promises';
|
|
9
|
+
import { join, resolve, relative } from 'path';
|
|
10
|
+
import { existsSync } from 'fs';
|
|
11
|
+
import { getOpenbotWorkspaceDir } from '../../agent/agent-dir.js';
|
|
12
|
+
let WorkspaceService = class WorkspaceService {
|
|
13
|
+
getWorkspaceRoot(name) {
|
|
14
|
+
return join(getOpenbotWorkspaceDir(), name);
|
|
15
|
+
}
|
|
16
|
+
/** List workspace names (directories under OPENBOT_WORKSPACE_DIR, default ~/.openbot/workspace) */
|
|
17
|
+
async listWorkspaces() {
|
|
18
|
+
const base = getOpenbotWorkspaceDir();
|
|
19
|
+
if (!existsSync(base)) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
const entries = await readdir(base, { withFileTypes: true });
|
|
23
|
+
return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
24
|
+
}
|
|
25
|
+
/** List files and folders under a path relative to workspace root. Empty path = root. */
|
|
26
|
+
async listDocuments(workspaceName, relativePath = '') {
|
|
27
|
+
const root = resolve(this.getWorkspaceRoot(workspaceName));
|
|
28
|
+
if (!existsSync(root)) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
const safePath = this.safeRelativePath(relativePath);
|
|
32
|
+
const dir = resolve(root, safePath);
|
|
33
|
+
const dirNormalized = resolve(dir);
|
|
34
|
+
const rootNormalized = resolve(root);
|
|
35
|
+
if (!dirNormalized.startsWith(rootNormalized) || !existsSync(dirNormalized)) {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
const entries = await readdir(dirNormalized, { withFileTypes: true });
|
|
39
|
+
const items = [];
|
|
40
|
+
const hiddenDirNames = new Set(['skills', '.skills']);
|
|
41
|
+
for (const e of entries) {
|
|
42
|
+
if (e.isDirectory() && hiddenDirNames.has(e.name))
|
|
43
|
+
continue;
|
|
44
|
+
const fullPath = join(dirNormalized, e.name);
|
|
45
|
+
const rel = relative(rootNormalized, fullPath);
|
|
46
|
+
let st;
|
|
47
|
+
try {
|
|
48
|
+
st = await stat(fullPath);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
if (err?.code === 'ENOENT')
|
|
52
|
+
continue;
|
|
53
|
+
throw err;
|
|
54
|
+
}
|
|
55
|
+
items.push({
|
|
56
|
+
name: e.name,
|
|
57
|
+
path: rel,
|
|
58
|
+
isDirectory: st.isDirectory(),
|
|
59
|
+
size: st.isFile() ? st.size : undefined,
|
|
60
|
+
mtime: st.mtimeMs,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return items.sort((a, b) => {
|
|
64
|
+
if (a.isDirectory !== b.isDirectory)
|
|
65
|
+
return a.isDirectory ? -1 : 1;
|
|
66
|
+
return a.name.localeCompare(b.name);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Resolve a relative path and ensure it stays under workspace root.
|
|
71
|
+
* Returns path suitable for join(workspaceRoot, result).
|
|
72
|
+
*/
|
|
73
|
+
resolveFilePath(workspaceName, relativePath) {
|
|
74
|
+
const root = resolve(this.getWorkspaceRoot(workspaceName));
|
|
75
|
+
const safe = this.safeRelativePath(relativePath);
|
|
76
|
+
const absolute = resolve(root, safe);
|
|
77
|
+
const ok = resolve(absolute).startsWith(root) && existsSync(absolute);
|
|
78
|
+
return { absolutePath: absolute, safe: ok };
|
|
79
|
+
}
|
|
80
|
+
/** Delete a file or directory (recursive) under workspace. Returns true if deleted. skills 与 .skills 目录禁止删除。 */
|
|
81
|
+
async deletePath(workspaceName, relativePath) {
|
|
82
|
+
const safe = this.safeRelativePath(relativePath);
|
|
83
|
+
const topDir = safe.split('/')[0];
|
|
84
|
+
if (topDir === 'skills' || topDir === '.skills')
|
|
85
|
+
return false;
|
|
86
|
+
const { absolutePath, safe: resolved } = this.resolveFilePath(workspaceName, relativePath);
|
|
87
|
+
if (!resolved || !existsSync(absolutePath))
|
|
88
|
+
return false;
|
|
89
|
+
await rm(absolutePath, { recursive: true });
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
safeRelativePath(relativePath) {
|
|
93
|
+
if (!relativePath || relativePath === '.')
|
|
94
|
+
return '';
|
|
95
|
+
const normalized = relativePath.replace(/\\/g, '/').replace(/\/+/g, '/').replace(/^\/+/, '');
|
|
96
|
+
const parts = normalized.split('/').filter((p) => p !== '..' && p !== '.');
|
|
97
|
+
return parts.join('/');
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
WorkspaceService = __decorate([
|
|
101
|
+
Injectable()
|
|
102
|
+
], WorkspaceService);
|
|
103
|
+
export { WorkspaceService };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AgentTool } from "@mariozechner/pi-agent-core";
|
|
2
|
+
/**
|
|
3
|
+
* Create browser automation tool
|
|
4
|
+
* @param workspaceDir Optional workspace directory for downloads
|
|
5
|
+
*/
|
|
6
|
+
export declare function createBrowserTool(workspaceDir?: string): AgentTool<any>;
|
|
7
|
+
/**
|
|
8
|
+
* Cleanup function to close browser on process exit
|
|
9
|
+
*/
|
|
10
|
+
export declare function closeBrowser(): Promise<void>;
|