@next-open-ai/openbot 0.2.1 → 0.3.2

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 (67) hide show
  1. package/README.md +117 -17
  2. package/apps/desktop/renderer/dist/assets/index-DKtaRFW4.js +89 -0
  3. package/apps/desktop/renderer/dist/assets/index-QHuqXpWQ.css +10 -0
  4. package/apps/desktop/renderer/dist/index.html +3 -3
  5. package/dist/cli/cli.js +27 -1
  6. package/dist/cli/service.d.ts +13 -0
  7. package/dist/cli/service.js +243 -0
  8. package/dist/core/agent/agent-manager.d.ts +3 -0
  9. package/dist/core/agent/agent-manager.js +12 -6
  10. package/dist/core/config/desktop-config.d.ts +4 -0
  11. package/dist/core/config/desktop-config.js +5 -1
  12. package/dist/core/installer/index.d.ts +1 -1
  13. package/dist/core/installer/index.js +1 -1
  14. package/dist/core/installer/skill-installer.d.ts +9 -0
  15. package/dist/core/installer/skill-installer.js +94 -0
  16. package/dist/core/mcp/adapter.d.ts +17 -0
  17. package/dist/core/mcp/adapter.js +49 -0
  18. package/dist/core/mcp/client.d.ts +24 -0
  19. package/dist/core/mcp/client.js +70 -0
  20. package/dist/core/mcp/config.d.ts +22 -0
  21. package/dist/core/mcp/config.js +69 -0
  22. package/dist/core/mcp/index.d.ts +18 -0
  23. package/dist/core/mcp/index.js +20 -0
  24. package/dist/core/mcp/operator.d.ts +15 -0
  25. package/dist/core/mcp/operator.js +72 -0
  26. package/dist/core/mcp/transport/index.d.ts +11 -0
  27. package/dist/core/mcp/transport/index.js +16 -0
  28. package/dist/core/mcp/transport/sse.d.ts +20 -0
  29. package/dist/core/mcp/transport/sse.js +82 -0
  30. package/dist/core/mcp/transport/stdio.d.ts +32 -0
  31. package/dist/core/mcp/transport/stdio.js +132 -0
  32. package/dist/core/mcp/types.d.ts +72 -0
  33. package/dist/core/mcp/types.js +5 -0
  34. package/dist/core/tools/bookmark-tool.d.ts +9 -0
  35. package/dist/core/tools/bookmark-tool.js +118 -0
  36. package/dist/core/tools/index.d.ts +1 -0
  37. package/dist/core/tools/index.js +1 -0
  38. package/dist/gateway/methods/agent-chat.js +1 -0
  39. package/dist/gateway/methods/install-skill-from-upload.d.ts +14 -0
  40. package/dist/gateway/methods/install-skill-from-upload.js +13 -0
  41. package/dist/gateway/methods/run-scheduled-task.js +1 -0
  42. package/dist/gateway/server.js +26 -1
  43. package/dist/server/agent-config/agent-config.controller.d.ts +1 -1
  44. package/dist/server/agent-config/agent-config.service.d.ts +4 -1
  45. package/dist/server/agent-config/agent-config.service.js +2 -0
  46. package/dist/server/agents/agents.controller.js +3 -5
  47. package/dist/server/agents/agents.service.d.ts +1 -1
  48. package/dist/server/agents/agents.service.js +4 -2
  49. package/dist/server/app.module.js +2 -0
  50. package/dist/server/database/database.service.d.ts +7 -0
  51. package/dist/server/database/database.service.js +54 -5
  52. package/dist/server/saved-items/saved-items.controller.d.ts +26 -0
  53. package/dist/server/saved-items/saved-items.controller.js +78 -0
  54. package/dist/server/saved-items/saved-items.module.d.ts +2 -0
  55. package/dist/server/saved-items/saved-items.module.js +23 -0
  56. package/dist/server/saved-items/saved-items.service.d.ts +31 -0
  57. package/dist/server/saved-items/saved-items.service.js +105 -0
  58. package/dist/server/saved-items/tags.controller.d.ts +30 -0
  59. package/dist/server/saved-items/tags.controller.js +85 -0
  60. package/dist/server/saved-items/tags.service.d.ts +24 -0
  61. package/dist/server/saved-items/tags.service.js +84 -0
  62. package/dist/server/skills/skills.service.d.ts +2 -0
  63. package/dist/server/skills/skills.service.js +80 -16
  64. package/package.json +8 -2
  65. package/skills/url-bookmark/SKILL.md +36 -0
  66. package/apps/desktop/renderer/dist/assets/index-BOS-F8a4.js +0 -89
  67. package/apps/desktop/renderer/dist/assets/index-DxqxayUL.css +0 -10
@@ -15,6 +15,7 @@ import { UsersModule } from './users/users.module.js';
15
15
  import { WorkspaceModule } from './workspace/workspace.module.js';
16
16
  import { TasksModule } from './tasks/tasks.module.js';
17
17
  import { UsageModule } from './usage/usage.module.js';
18
+ import { SavedItemsModule } from './saved-items/saved-items.module.js';
18
19
  let AppModule = class AppModule {
19
20
  };
20
21
  AppModule = __decorate([
@@ -30,6 +31,7 @@ AppModule = __decorate([
30
31
  WorkspaceModule,
31
32
  TasksModule,
32
33
  UsageModule,
34
+ SavedItemsModule,
33
35
  ],
34
36
  })
35
37
  ], AppModule);
@@ -13,6 +13,13 @@ export declare class DatabaseService implements OnModuleInit, OnModuleDestroy {
13
13
  private getDb;
14
14
  private runMigrations;
15
15
  run(sql: string, params?: unknown[]): RunResult;
16
+ /**
17
+ * 使用文件 DB 时立即落盘。每次 run() 写入后都会调用,保证「每次保存马上写到磁盘」。
18
+ * 落盘失败时重新抛出,便于上层返回错误、前端不乐观更新,避免「删了但重启又出现」。
19
+ */
20
+ private persistIfFile;
21
+ /** 供删除等关键操作后显式落盘,确保删除结果持久化 */
22
+ persist(): void;
16
23
  get<T>(sql: string, params?: unknown[]): T | undefined;
17
24
  all<T>(sql: string, params?: unknown[]): T[];
18
25
  onModuleDestroy(): void;
@@ -6,7 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { Injectable } from '@nestjs/common';
8
8
  import { mkdirSync, existsSync, readFileSync, writeFileSync } from 'fs';
9
- import { join } from 'path';
9
+ import { join, resolve } from 'path';
10
10
  import { homedir } from 'os';
11
11
  let DatabaseService = class DatabaseService {
12
12
  sqlDb = null;
@@ -25,7 +25,8 @@ let DatabaseService = class DatabaseService {
25
25
  ? ':memory:'
26
26
  : pathEnv ?? join(process.env.OPENBOT_DB_DIR ?? defaultDir, 'openbot.db');
27
27
  if (path !== ':memory:') {
28
- const dir = path.endsWith('.db') ? join(path, '..') : path;
28
+ const resolvedPath = resolve(path);
29
+ const dir = resolvedPath.endsWith('.db') ? join(resolvedPath, '..') : resolvedPath;
29
30
  if (!existsSync(dir)) {
30
31
  mkdirSync(dir, { recursive: true });
31
32
  }
@@ -38,18 +39,23 @@ let DatabaseService = class DatabaseService {
38
39
  this.dbPath = ':memory:';
39
40
  }
40
41
  else {
41
- if (existsSync(path)) {
42
- const buf = readFileSync(path);
42
+ const absolutePath = resolve(path);
43
+ if (existsSync(absolutePath)) {
44
+ const buf = readFileSync(absolutePath);
43
45
  db = new SQL.Database(new Uint8Array(buf));
44
46
  }
45
47
  else {
46
48
  db = new SQL.Database();
47
49
  }
48
- this.dbPath = path;
50
+ this.dbPath = absolutePath;
49
51
  }
50
52
  this.sqlDb = db;
51
53
  db.run('PRAGMA foreign_keys = ON;');
52
54
  this.runMigrations();
55
+ if (path !== ':memory:') {
56
+ this.persistIfFile();
57
+ console.log('[DatabaseService] Database file:', this.dbPath);
58
+ }
53
59
  }
54
60
  getDb() {
55
61
  if (!this.sqlDb) {
@@ -127,6 +133,28 @@ let DatabaseService = class DatabaseService {
127
133
  );
128
134
  CREATE INDEX IF NOT EXISTS idx_token_usage_session_id ON token_usage(session_id);
129
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);
130
158
  `;
131
159
  const statements = ddl.split(';').map((s) => s.trim()).filter(Boolean);
132
160
  for (const stmt of statements) {
@@ -148,11 +176,32 @@ let DatabaseService = class DatabaseService {
148
176
  run(sql, params = []) {
149
177
  const db = this.getDb();
150
178
  db.run(sql, params);
179
+ this.persistIfFile();
151
180
  const rows = db.exec('SELECT changes() AS c, last_insert_rowid() AS id');
152
181
  const c = rows[0]?.values?.[0]?.[0] ?? 0;
153
182
  const id = rows[0]?.values?.[0]?.[1] ?? 0;
154
183
  return { changes: Number(c), lastInsertRowid: Number(id) };
155
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
+ }
156
205
  get(sql, params = []) {
157
206
  const db = this.getDb();
158
207
  const stmt = db.prepare(sql);
@@ -0,0 +1,26 @@
1
+ import { SavedItemsService } from './saved-items.service.js';
2
+ export declare class SavedItemsController {
3
+ private readonly savedItemsService;
4
+ constructor(savedItemsService: SavedItemsService);
5
+ list(tagId?: string, workspace?: string): Promise<{
6
+ success: boolean;
7
+ data: import("./saved-items.service.js").SavedItem[];
8
+ }>;
9
+ get(id: string): Promise<{
10
+ success: boolean;
11
+ data: import("./saved-items.service.js").SavedItem;
12
+ }>;
13
+ create(body: {
14
+ url: string;
15
+ title?: string;
16
+ workspace?: string;
17
+ tagNames?: string[];
18
+ tagIds?: string[];
19
+ }): Promise<{
20
+ success: boolean;
21
+ data: import("./saved-items.service.js").SavedItem;
22
+ }>;
23
+ delete(id: string): Promise<{
24
+ success: boolean;
25
+ }>;
26
+ }
@@ -0,0 +1,78 @@
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, Post, Delete, Body, Param, Query, HttpException, HttpStatus, } from '@nestjs/common';
14
+ import { SavedItemsService } from './saved-items.service.js';
15
+ let SavedItemsController = class SavedItemsController {
16
+ savedItemsService;
17
+ constructor(savedItemsService) {
18
+ this.savedItemsService = savedItemsService;
19
+ }
20
+ async list(tagId, workspace) {
21
+ const data = await this.savedItemsService.findAll({ tagId, workspace });
22
+ return { success: true, data };
23
+ }
24
+ async get(id) {
25
+ const data = await this.savedItemsService.findById(id);
26
+ if (!data)
27
+ throw new HttpException('Saved item not found', HttpStatus.NOT_FOUND);
28
+ return { success: true, data };
29
+ }
30
+ async create(body) {
31
+ const data = await this.savedItemsService.create({
32
+ url: body.url,
33
+ title: body.title,
34
+ workspace: body.workspace,
35
+ tagNames: body.tagNames,
36
+ tagIds: body.tagIds,
37
+ });
38
+ return { success: true, data };
39
+ }
40
+ async delete(id) {
41
+ await this.savedItemsService.delete(id);
42
+ return { success: true };
43
+ }
44
+ };
45
+ __decorate([
46
+ Get(),
47
+ __param(0, Query('tagId')),
48
+ __param(1, Query('workspace')),
49
+ __metadata("design:type", Function),
50
+ __metadata("design:paramtypes", [String, String]),
51
+ __metadata("design:returntype", Promise)
52
+ ], SavedItemsController.prototype, "list", null);
53
+ __decorate([
54
+ Get(':id'),
55
+ __param(0, Param('id')),
56
+ __metadata("design:type", Function),
57
+ __metadata("design:paramtypes", [String]),
58
+ __metadata("design:returntype", Promise)
59
+ ], SavedItemsController.prototype, "get", null);
60
+ __decorate([
61
+ Post(),
62
+ __param(0, Body()),
63
+ __metadata("design:type", Function),
64
+ __metadata("design:paramtypes", [Object]),
65
+ __metadata("design:returntype", Promise)
66
+ ], SavedItemsController.prototype, "create", null);
67
+ __decorate([
68
+ Delete(':id'),
69
+ __param(0, Param('id')),
70
+ __metadata("design:type", Function),
71
+ __metadata("design:paramtypes", [String]),
72
+ __metadata("design:returntype", Promise)
73
+ ], SavedItemsController.prototype, "delete", null);
74
+ SavedItemsController = __decorate([
75
+ Controller('saved-items'),
76
+ __metadata("design:paramtypes", [SavedItemsService])
77
+ ], SavedItemsController);
78
+ export { SavedItemsController };
@@ -0,0 +1,2 @@
1
+ export declare class SavedItemsModule {
2
+ }
@@ -0,0 +1,23 @@
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 { DatabaseModule } from '../database/database.module.js';
9
+ import { TagsService } from './tags.service.js';
10
+ import { TagsController } from './tags.controller.js';
11
+ import { SavedItemsService } from './saved-items.service.js';
12
+ import { SavedItemsController } from './saved-items.controller.js';
13
+ let SavedItemsModule = class SavedItemsModule {
14
+ };
15
+ SavedItemsModule = __decorate([
16
+ Module({
17
+ imports: [DatabaseModule],
18
+ controllers: [TagsController, SavedItemsController],
19
+ providers: [TagsService, SavedItemsService],
20
+ exports: [TagsService, SavedItemsService],
21
+ })
22
+ ], SavedItemsModule);
23
+ export { SavedItemsModule };
@@ -0,0 +1,31 @@
1
+ import { DatabaseService } from '../database/database.service.js';
2
+ import { TagsService } from './tags.service.js';
3
+ export interface SavedItem {
4
+ id: string;
5
+ url: string;
6
+ title: string | null;
7
+ workspace: string;
8
+ createdAt: number;
9
+ tagIds: string[];
10
+ tagNames?: string[];
11
+ }
12
+ export declare class SavedItemsService {
13
+ private readonly db;
14
+ private readonly tagsService;
15
+ constructor(db: DatabaseService, tagsService: TagsService);
16
+ private getTagIdsForItem;
17
+ private rowToSavedItem;
18
+ create(dto: {
19
+ url: string;
20
+ title?: string;
21
+ workspace?: string;
22
+ tagNames?: string[];
23
+ tagIds?: string[];
24
+ }): Promise<SavedItem>;
25
+ findAll(options?: {
26
+ tagId?: string;
27
+ workspace?: string;
28
+ }): Promise<SavedItem[]>;
29
+ findById(id: string): Promise<SavedItem | null>;
30
+ delete(id: string): Promise<void>;
31
+ }
@@ -0,0 +1,105 @@
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, NotFoundException } from '@nestjs/common';
11
+ import { DatabaseService } from '../database/database.service.js';
12
+ import { TagsService } from './tags.service.js';
13
+ import { randomUUID } from 'crypto';
14
+ let SavedItemsService = class SavedItemsService {
15
+ db;
16
+ tagsService;
17
+ constructor(db, tagsService) {
18
+ this.db = db;
19
+ this.tagsService = tagsService;
20
+ }
21
+ async getTagIdsForItem(savedItemId) {
22
+ const rows = this.db.all('SELECT tag_id FROM saved_item_tags WHERE saved_item_id = ?', [savedItemId]);
23
+ return rows.map((r) => r.tag_id);
24
+ }
25
+ async rowToSavedItem(row) {
26
+ const tagIds = await this.getTagIdsForItem(row.id);
27
+ const tagNames = [];
28
+ for (const tagId of tagIds) {
29
+ const tag = await this.tagsService.findById(tagId);
30
+ if (tag)
31
+ tagNames.push(tag.name);
32
+ }
33
+ return {
34
+ id: row.id,
35
+ url: row.url,
36
+ title: row.title,
37
+ workspace: row.workspace,
38
+ createdAt: row.created_at,
39
+ tagIds,
40
+ tagNames,
41
+ };
42
+ }
43
+ async create(dto) {
44
+ const url = (dto.url ?? '').trim();
45
+ if (!url)
46
+ throw new Error('url is required');
47
+ const workspace = (dto.workspace ?? 'default').trim() || 'default';
48
+ const title = dto.title?.trim() ?? null;
49
+ const id = randomUUID();
50
+ const createdAt = Date.now();
51
+ this.db.run('INSERT INTO saved_items (id, url, title, workspace, created_at) VALUES (?, ?, ?, ?, ?)', [id, url, title, workspace, createdAt]);
52
+ let tagIds = [];
53
+ if (dto.tagIds?.length) {
54
+ tagIds = dto.tagIds;
55
+ }
56
+ else if (dto.tagNames?.length) {
57
+ for (const name of dto.tagNames) {
58
+ const tag = await this.tagsService.findByName(name.trim());
59
+ if (tag)
60
+ tagIds.push(tag.id);
61
+ }
62
+ }
63
+ for (const tagId of tagIds) {
64
+ this.db.run('INSERT INTO saved_item_tags (saved_item_id, tag_id) VALUES (?, ?)', [id, tagId]);
65
+ }
66
+ const row = { id, url, title, workspace, created_at: createdAt };
67
+ return this.rowToSavedItem(row);
68
+ }
69
+ async findAll(options) {
70
+ let sql = 'SELECT id, url, title, workspace, created_at FROM saved_items WHERE 1=1';
71
+ const params = [];
72
+ if (options?.workspace) {
73
+ sql += ' AND workspace = ?';
74
+ params.push(options.workspace);
75
+ }
76
+ if (options?.tagId) {
77
+ sql += ' AND id IN (SELECT saved_item_id FROM saved_item_tags WHERE tag_id = ?)';
78
+ params.push(options.tagId);
79
+ }
80
+ sql += ' ORDER BY created_at DESC';
81
+ const rows = this.db.all(sql, params);
82
+ const result = [];
83
+ for (const row of rows) {
84
+ result.push(await this.rowToSavedItem(row));
85
+ }
86
+ return result;
87
+ }
88
+ async findById(id) {
89
+ const row = this.db.get('SELECT id, url, title, workspace, created_at FROM saved_items WHERE id = ?', [id]);
90
+ return row ? this.rowToSavedItem(row) : null;
91
+ }
92
+ async delete(id) {
93
+ const item = await this.findById(id);
94
+ if (!item)
95
+ throw new NotFoundException('收藏不存在');
96
+ this.db.run('DELETE FROM saved_item_tags WHERE saved_item_id = ?', [id]);
97
+ this.db.run('DELETE FROM saved_items WHERE id = ?', [id]);
98
+ }
99
+ };
100
+ SavedItemsService = __decorate([
101
+ Injectable(),
102
+ __metadata("design:paramtypes", [DatabaseService,
103
+ TagsService])
104
+ ], SavedItemsService);
105
+ export { SavedItemsService };
@@ -0,0 +1,30 @@
1
+ import { TagsService } from './tags.service.js';
2
+ export declare class TagsController {
3
+ private readonly tagsService;
4
+ constructor(tagsService: TagsService);
5
+ list(): Promise<{
6
+ success: boolean;
7
+ data: import("./tags.service.js").Tag[];
8
+ }>;
9
+ get(id: string): Promise<{
10
+ success: boolean;
11
+ data: import("./tags.service.js").Tag;
12
+ }>;
13
+ create(body: {
14
+ name: string;
15
+ sortOrder?: number;
16
+ }): Promise<{
17
+ success: boolean;
18
+ data: import("./tags.service.js").Tag;
19
+ }>;
20
+ update(id: string, body: {
21
+ name?: string;
22
+ sortOrder?: number;
23
+ }): Promise<{
24
+ success: boolean;
25
+ data: import("./tags.service.js").Tag;
26
+ }>;
27
+ delete(id: string): Promise<{
28
+ success: boolean;
29
+ }>;
30
+ }
@@ -0,0 +1,85 @@
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, Post, Put, Delete, Body, Param, HttpException, HttpStatus } from '@nestjs/common';
14
+ import { TagsService } from './tags.service.js';
15
+ let TagsController = class TagsController {
16
+ tagsService;
17
+ constructor(tagsService) {
18
+ this.tagsService = tagsService;
19
+ }
20
+ async list() {
21
+ const data = await this.tagsService.findAll();
22
+ return { success: true, data };
23
+ }
24
+ async get(id) {
25
+ const data = await this.tagsService.findById(id);
26
+ if (!data)
27
+ throw new HttpException('Tag not found', HttpStatus.NOT_FOUND);
28
+ return { success: true, data };
29
+ }
30
+ async create(body) {
31
+ const data = await this.tagsService.create({
32
+ name: body.name,
33
+ sortOrder: body.sortOrder,
34
+ });
35
+ return { success: true, data };
36
+ }
37
+ async update(id, body) {
38
+ const data = await this.tagsService.update(id, body);
39
+ return { success: true, data };
40
+ }
41
+ async delete(id) {
42
+ await this.tagsService.delete(id);
43
+ return { success: true };
44
+ }
45
+ };
46
+ __decorate([
47
+ Get(),
48
+ __metadata("design:type", Function),
49
+ __metadata("design:paramtypes", []),
50
+ __metadata("design:returntype", Promise)
51
+ ], TagsController.prototype, "list", null);
52
+ __decorate([
53
+ Get(':id'),
54
+ __param(0, Param('id')),
55
+ __metadata("design:type", Function),
56
+ __metadata("design:paramtypes", [String]),
57
+ __metadata("design:returntype", Promise)
58
+ ], TagsController.prototype, "get", null);
59
+ __decorate([
60
+ Post(),
61
+ __param(0, Body()),
62
+ __metadata("design:type", Function),
63
+ __metadata("design:paramtypes", [Object]),
64
+ __metadata("design:returntype", Promise)
65
+ ], TagsController.prototype, "create", null);
66
+ __decorate([
67
+ Put(':id'),
68
+ __param(0, Param('id')),
69
+ __param(1, Body()),
70
+ __metadata("design:type", Function),
71
+ __metadata("design:paramtypes", [String, Object]),
72
+ __metadata("design:returntype", Promise)
73
+ ], TagsController.prototype, "update", null);
74
+ __decorate([
75
+ Delete(':id'),
76
+ __param(0, Param('id')),
77
+ __metadata("design:type", Function),
78
+ __metadata("design:paramtypes", [String]),
79
+ __metadata("design:returntype", Promise)
80
+ ], TagsController.prototype, "delete", null);
81
+ TagsController = __decorate([
82
+ Controller('tags'),
83
+ __metadata("design:paramtypes", [TagsService])
84
+ ], TagsController);
85
+ export { TagsController };
@@ -0,0 +1,24 @@
1
+ import { DatabaseService } from '../database/database.service.js';
2
+ export interface Tag {
3
+ id: string;
4
+ name: string;
5
+ sortOrder: number;
6
+ createdAt: number;
7
+ }
8
+ export declare class TagsService {
9
+ private readonly db;
10
+ constructor(db: DatabaseService);
11
+ private rowToTag;
12
+ findAll(): Promise<Tag[]>;
13
+ findById(id: string): Promise<Tag | null>;
14
+ findByName(name: string): Promise<Tag | null>;
15
+ create(dto: {
16
+ name: string;
17
+ sortOrder?: number;
18
+ }): Promise<Tag>;
19
+ update(id: string, dto: {
20
+ name?: string;
21
+ sortOrder?: number;
22
+ }): Promise<Tag>;
23
+ delete(id: string): Promise<void>;
24
+ }
@@ -0,0 +1,84 @@
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 { DatabaseService } from '../database/database.service.js';
12
+ import { randomUUID } from 'crypto';
13
+ let TagsService = class TagsService {
14
+ db;
15
+ constructor(db) {
16
+ this.db = db;
17
+ }
18
+ rowToTag(row) {
19
+ return {
20
+ id: row.id,
21
+ name: row.name,
22
+ sortOrder: row.sort_order,
23
+ createdAt: row.created_at,
24
+ };
25
+ }
26
+ async findAll() {
27
+ const rows = this.db.all('SELECT id, name, sort_order, created_at FROM tags ORDER BY sort_order ASC, name ASC', []);
28
+ return rows.map((r) => this.rowToTag(r));
29
+ }
30
+ async findById(id) {
31
+ const row = this.db.get('SELECT id, name, sort_order, created_at FROM tags WHERE id = ?', [id]);
32
+ return row ? this.rowToTag(row) : null;
33
+ }
34
+ async findByName(name) {
35
+ const row = this.db.get('SELECT id, name, sort_order, created_at FROM tags WHERE name = ?', [
36
+ name.trim(),
37
+ ]);
38
+ return row ? this.rowToTag(row) : null;
39
+ }
40
+ async create(dto) {
41
+ const name = (dto.name ?? '').trim();
42
+ if (!name)
43
+ throw new ConflictException('标签名不能为空');
44
+ const existing = await this.findByName(name);
45
+ if (existing)
46
+ throw new ConflictException('该标签名已存在');
47
+ const id = randomUUID();
48
+ const sortOrder = dto.sortOrder ?? 0;
49
+ const createdAt = Date.now();
50
+ this.db.run('INSERT INTO tags (id, name, sort_order, created_at) VALUES (?, ?, ?, ?)', [id, name, sortOrder, createdAt]);
51
+ return { id, name, sortOrder, createdAt };
52
+ }
53
+ async update(id, dto) {
54
+ const tag = await this.findById(id);
55
+ if (!tag)
56
+ throw new NotFoundException('标签不存在');
57
+ if (dto.name !== undefined) {
58
+ const name = dto.name.trim();
59
+ if (!name)
60
+ throw new ConflictException('标签名不能为空');
61
+ const existing = await this.findByName(name);
62
+ if (existing && existing.id !== id)
63
+ throw new ConflictException('该标签名已存在');
64
+ this.db.run('UPDATE tags SET name = ? WHERE id = ?', [name, id]);
65
+ tag.name = name;
66
+ }
67
+ if (dto.sortOrder !== undefined) {
68
+ this.db.run('UPDATE tags SET sort_order = ? WHERE id = ?', [dto.sortOrder, id]);
69
+ tag.sortOrder = dto.sortOrder;
70
+ }
71
+ return tag;
72
+ }
73
+ async delete(id) {
74
+ const tag = await this.findById(id);
75
+ if (!tag)
76
+ throw new NotFoundException('标签不存在');
77
+ this.db.run('DELETE FROM tags WHERE id = ?', [id]);
78
+ }
79
+ };
80
+ TagsService = __decorate([
81
+ Injectable(),
82
+ __metadata("design:paramtypes", [DatabaseService])
83
+ ], TagsService);
84
+ export { TagsService };
@@ -51,6 +51,8 @@ export declare class SkillsService {
51
51
  getSkillContent(name: string): Promise<string | null>;
52
52
  /** 仅返回指定工作区下的技能(文件目录管理,不涉及 SQLite) */
53
53
  getSkillsForWorkspace(workspaceName: string): Promise<Skill[]>;
54
+ /** 从 skill.json 或 package.json 解析出 Skill(兼容无 SKILL.md 的 npm 风格技能目录) */
55
+ private parseSkillJson;
54
56
  getSkillContentForWorkspace(workspaceName: string, name: string): Promise<string | null>;
55
57
  /** 在工作区下新增技能(创建目录 + SKILL.md) */
56
58
  addSkill(workspaceName: string, name: string, options?: {