agor-live 0.3.7
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/LICENSE +94 -0
- package/README.md +163 -0
- package/bin/agor-daemon.js +20 -0
- package/bin/agor.js +14 -0
- package/dist/cli/base-command.d.ts +29 -0
- package/dist/cli/base-command.js +41 -0
- package/dist/cli/commands/board/add-session.d.ts +15 -0
- package/dist/cli/commands/board/add-session.js +102 -0
- package/dist/cli/commands/board/list.d.ts +14 -0
- package/dist/cli/commands/board/list.js +74 -0
- package/dist/cli/commands/config/clear.d.ts +13 -0
- package/dist/cli/commands/config/clear.js +21 -0
- package/dist/cli/commands/config/get.d.ts +13 -0
- package/dist/cli/commands/config/get.js +41 -0
- package/dist/cli/commands/config/index.d.ts +13 -0
- package/dist/cli/commands/config/index.js +118 -0
- package/dist/cli/commands/config/set.d.ts +14 -0
- package/dist/cli/commands/config/set.js +50 -0
- package/dist/cli/commands/config/unset.d.ts +13 -0
- package/dist/cli/commands/config/unset.js +35 -0
- package/dist/cli/commands/daemon/index.d.ts +13 -0
- package/dist/cli/commands/daemon/index.js +65 -0
- package/dist/cli/commands/daemon/logs.d.ts +13 -0
- package/dist/cli/commands/daemon/logs.js +78 -0
- package/dist/cli/commands/daemon/restart.d.ts +13 -0
- package/dist/cli/commands/daemon/restart.js +177 -0
- package/dist/cli/commands/daemon/start.d.ts +13 -0
- package/dist/cli/commands/daemon/start.js +193 -0
- package/dist/cli/commands/daemon/status.d.ts +13 -0
- package/dist/cli/commands/daemon/status.js +93 -0
- package/dist/cli/commands/daemon/stop.d.ts +13 -0
- package/dist/cli/commands/daemon/stop.js +108 -0
- package/dist/cli/commands/init.d.ts +44 -0
- package/dist/cli/commands/init.js +459 -0
- package/dist/cli/commands/mcp/add.d.ts +26 -0
- package/dist/cli/commands/mcp/add.js +162 -0
- package/dist/cli/commands/mcp/list.d.ts +16 -0
- package/dist/cli/commands/mcp/list.js +89 -0
- package/dist/cli/commands/mcp/remove.d.ts +17 -0
- package/dist/cli/commands/mcp/remove.js +86 -0
- package/dist/cli/commands/mcp/show.d.ts +14 -0
- package/dist/cli/commands/mcp/show.js +131 -0
- package/dist/cli/commands/repo/add.d.ts +16 -0
- package/dist/cli/commands/repo/add.js +105 -0
- package/dist/cli/commands/repo/list.d.ts +17 -0
- package/dist/cli/commands/repo/list.js +99 -0
- package/dist/cli/commands/repo/rm.d.ts +17 -0
- package/dist/cli/commands/repo/rm.js +126 -0
- package/dist/cli/commands/repo/worktree/add.d.ts +21 -0
- package/dist/cli/commands/repo/worktree/add.js +145 -0
- package/dist/cli/commands/repo/worktree/list.d.ts +21 -0
- package/dist/cli/commands/repo/worktree/list.js +136 -0
- package/dist/cli/commands/session/list.d.ts +30 -0
- package/dist/cli/commands/session/list.js +204 -0
- package/dist/cli/commands/session/load-claude.d.ts +16 -0
- package/dist/cli/commands/session/load-claude.js +211 -0
- package/dist/cli/commands/user/create-admin.d.ts +13 -0
- package/dist/cli/commands/user/create-admin.js +65 -0
- package/dist/cli/commands/user/create.d.ts +16 -0
- package/dist/cli/commands/user/create.js +126 -0
- package/dist/cli/commands/user/delete.d.ts +16 -0
- package/dist/cli/commands/user/delete.js +77 -0
- package/dist/cli/commands/user/list.d.ts +13 -0
- package/dist/cli/commands/user/list.js +78 -0
- package/dist/cli/commands/user/update.d.ts +19 -0
- package/dist/cli/commands/user/update.js +149 -0
- package/dist/cli/hooks/command-not-found.d.ts +9 -0
- package/dist/cli/hooks/command-not-found.js +14 -0
- package/dist/cli/lib/banner.d.ts +25 -0
- package/dist/cli/lib/banner.js +25 -0
- package/dist/cli/lib/context.d.ts +27 -0
- package/dist/cli/lib/context.js +32 -0
- package/dist/cli/lib/daemon-manager.d.ts +48 -0
- package/dist/cli/lib/daemon-manager.js +109 -0
- package/dist/cli/lib/help.d.ts +13 -0
- package/dist/cli/lib/help.js +46 -0
- package/dist/core/agentic-tool-B_gFNpk5.d.ts +33 -0
- package/dist/core/agentic-tool-DsyX8diw.d.cts +33 -0
- package/dist/core/api/index.cjs +98 -0
- package/dist/core/api/index.d.cts +174 -0
- package/dist/core/api/index.d.ts +174 -0
- package/dist/core/api/index.js +62 -0
- package/dist/core/board-comment-BUm0fpmD.d.cts +134 -0
- package/dist/core/board-comment-gC_-twPx.d.ts +134 -0
- package/dist/core/claude/index.cjs +673 -0
- package/dist/core/claude/index.d.cts +124 -0
- package/dist/core/claude/index.d.ts +124 -0
- package/dist/core/claude/index.js +629 -0
- package/dist/core/config/browser.cjs +165 -0
- package/dist/core/config/browser.d.cts +289 -0
- package/dist/core/config/browser.d.ts +289 -0
- package/dist/core/config/browser.js +131 -0
- package/dist/core/config/index.cjs +518 -0
- package/dist/core/config/index.d.cts +246 -0
- package/dist/core/config/index.d.ts +246 -0
- package/dist/core/config/index.js +451 -0
- package/dist/core/db/index.cjs +3726 -0
- package/dist/core/db/index.d.cts +631 -0
- package/dist/core/db/index.d.ts +631 -0
- package/dist/core/db/index.js +3649 -0
- package/dist/core/dist/agentic-tool-B_gFNpk5.d.ts +33 -0
- package/dist/core/dist/agentic-tool-DsyX8diw.d.cts +33 -0
- package/dist/core/dist/api/index.cjs +98 -0
- package/dist/core/dist/api/index.d.cts +174 -0
- package/dist/core/dist/api/index.d.ts +174 -0
- package/dist/core/dist/api/index.js +62 -0
- package/dist/core/dist/board-comment-BUm0fpmD.d.cts +134 -0
- package/dist/core/dist/board-comment-gC_-twPx.d.ts +134 -0
- package/dist/core/dist/claude/index.cjs +673 -0
- package/dist/core/dist/claude/index.d.cts +124 -0
- package/dist/core/dist/claude/index.d.ts +124 -0
- package/dist/core/dist/claude/index.js +629 -0
- package/dist/core/dist/config/browser.cjs +165 -0
- package/dist/core/dist/config/browser.d.cts +289 -0
- package/dist/core/dist/config/browser.d.ts +289 -0
- package/dist/core/dist/config/browser.js +131 -0
- package/dist/core/dist/config/index.cjs +518 -0
- package/dist/core/dist/config/index.d.cts +246 -0
- package/dist/core/dist/config/index.d.ts +246 -0
- package/dist/core/dist/config/index.js +451 -0
- package/dist/core/dist/db/index.cjs +3726 -0
- package/dist/core/dist/db/index.d.cts +631 -0
- package/dist/core/dist/db/index.d.ts +631 -0
- package/dist/core/dist/db/index.js +3649 -0
- package/dist/core/dist/environment/variable-resolver.cjs +92 -0
- package/dist/core/dist/environment/variable-resolver.d.cts +52 -0
- package/dist/core/dist/environment/variable-resolver.d.ts +52 -0
- package/dist/core/dist/environment/variable-resolver.js +53 -0
- package/dist/core/dist/feathers/index.cjs +66 -0
- package/dist/core/dist/feathers/index.d.cts +7 -0
- package/dist/core/dist/feathers/index.d.ts +7 -0
- package/dist/core/dist/feathers/index.js +25 -0
- package/dist/core/dist/feathers-BzHEPnpl.d.cts +228 -0
- package/dist/core/dist/feathers-BzHEPnpl.d.ts +228 -0
- package/dist/core/dist/git/index.cjs +302 -0
- package/dist/core/dist/git/index.d.cts +137 -0
- package/dist/core/dist/git/index.d.ts +137 -0
- package/dist/core/dist/git/index.js +260 -0
- package/dist/core/dist/id-DMqyogFB.d.cts +131 -0
- package/dist/core/dist/id-DMqyogFB.d.ts +131 -0
- package/dist/core/dist/index.cjs +4653 -0
- package/dist/core/dist/index.d.cts +23 -0
- package/dist/core/dist/index.d.ts +23 -0
- package/dist/core/dist/index.js +4509 -0
- package/dist/core/dist/message-BoxZISHg.d.cts +120 -0
- package/dist/core/dist/message-DvBzHu7V.d.ts +120 -0
- package/dist/core/dist/permissions/index.cjs +112 -0
- package/dist/core/dist/permissions/index.d.cts +81 -0
- package/dist/core/dist/permissions/index.d.ts +81 -0
- package/dist/core/dist/permissions/index.js +85 -0
- package/dist/core/dist/repo-3CUrCRbq.d.cts +405 -0
- package/dist/core/dist/repo-CnvJ0B6-.d.ts +405 -0
- package/dist/core/dist/session-BPjJlVdZ.d.cts +429 -0
- package/dist/core/dist/session-wAzjHatv.d.ts +429 -0
- package/dist/core/dist/task-BIEgT1DK.d.cts +163 -0
- package/dist/core/dist/task-DuIfiUbW.d.ts +163 -0
- package/dist/core/dist/templates/handlebars-helpers.cjs +156 -0
- package/dist/core/dist/templates/handlebars-helpers.d.cts +45 -0
- package/dist/core/dist/templates/handlebars-helpers.d.ts +45 -0
- package/dist/core/dist/templates/handlebars-helpers.js +119 -0
- package/dist/core/dist/tools/claude/models.cjs +70 -0
- package/dist/core/dist/tools/claude/models.d.cts +27 -0
- package/dist/core/dist/tools/claude/models.d.ts +27 -0
- package/dist/core/dist/tools/claude/models.js +44 -0
- package/dist/core/dist/tools/index.cjs +3367 -0
- package/dist/core/dist/tools/index.d.cts +967 -0
- package/dist/core/dist/tools/index.d.ts +967 -0
- package/dist/core/dist/tools/index.js +3314 -0
- package/dist/core/dist/tools/models.cjs +119 -0
- package/dist/core/dist/tools/models.d.cts +47 -0
- package/dist/core/dist/tools/models.d.ts +47 -0
- package/dist/core/dist/tools/models.js +86 -0
- package/dist/core/dist/types/index.cjs +152 -0
- package/dist/core/dist/types/index.d.cts +214 -0
- package/dist/core/dist/types/index.d.ts +214 -0
- package/dist/core/dist/types/index.js +112 -0
- package/dist/core/dist/user-BmL3kFol.d.ts +50 -0
- package/dist/core/dist/user-eUuKj7yM.d.cts +50 -0
- package/dist/core/dist/utils/pricing.cjs +102 -0
- package/dist/core/dist/utils/pricing.d.cts +43 -0
- package/dist/core/dist/utils/pricing.d.ts +43 -0
- package/dist/core/dist/utils/pricing.js +75 -0
- package/dist/core/dist/worktrees-BzIxB1U6.d.cts +2745 -0
- package/dist/core/dist/worktrees-CYem1ya2.d.ts +2745 -0
- package/dist/core/environment/variable-resolver.cjs +92 -0
- package/dist/core/environment/variable-resolver.d.cts +52 -0
- package/dist/core/environment/variable-resolver.d.ts +52 -0
- package/dist/core/environment/variable-resolver.js +53 -0
- package/dist/core/feathers/index.cjs +66 -0
- package/dist/core/feathers/index.d.cts +7 -0
- package/dist/core/feathers/index.d.ts +7 -0
- package/dist/core/feathers/index.js +25 -0
- package/dist/core/feathers-BzHEPnpl.d.cts +228 -0
- package/dist/core/feathers-BzHEPnpl.d.ts +228 -0
- package/dist/core/git/index.cjs +302 -0
- package/dist/core/git/index.d.cts +137 -0
- package/dist/core/git/index.d.ts +137 -0
- package/dist/core/git/index.js +260 -0
- package/dist/core/id-DMqyogFB.d.cts +131 -0
- package/dist/core/id-DMqyogFB.d.ts +131 -0
- package/dist/core/index.cjs +4653 -0
- package/dist/core/index.d.cts +23 -0
- package/dist/core/index.d.ts +23 -0
- package/dist/core/index.js +4509 -0
- package/dist/core/message-BoxZISHg.d.cts +120 -0
- package/dist/core/message-DvBzHu7V.d.ts +120 -0
- package/dist/core/package.json +133 -0
- package/dist/core/permissions/index.cjs +112 -0
- package/dist/core/permissions/index.d.cts +81 -0
- package/dist/core/permissions/index.d.ts +81 -0
- package/dist/core/permissions/index.js +85 -0
- package/dist/core/repo-3CUrCRbq.d.cts +405 -0
- package/dist/core/repo-CnvJ0B6-.d.ts +405 -0
- package/dist/core/session-BPjJlVdZ.d.cts +429 -0
- package/dist/core/session-wAzjHatv.d.ts +429 -0
- package/dist/core/task-BIEgT1DK.d.cts +163 -0
- package/dist/core/task-DuIfiUbW.d.ts +163 -0
- package/dist/core/templates/handlebars-helpers.cjs +156 -0
- package/dist/core/templates/handlebars-helpers.d.cts +45 -0
- package/dist/core/templates/handlebars-helpers.d.ts +45 -0
- package/dist/core/templates/handlebars-helpers.js +119 -0
- package/dist/core/tools/claude/models.cjs +70 -0
- package/dist/core/tools/claude/models.d.cts +27 -0
- package/dist/core/tools/claude/models.d.ts +27 -0
- package/dist/core/tools/claude/models.js +44 -0
- package/dist/core/tools/index.cjs +3367 -0
- package/dist/core/tools/index.d.cts +967 -0
- package/dist/core/tools/index.d.ts +967 -0
- package/dist/core/tools/index.js +3314 -0
- package/dist/core/tools/models.cjs +119 -0
- package/dist/core/tools/models.d.cts +47 -0
- package/dist/core/tools/models.d.ts +47 -0
- package/dist/core/tools/models.js +86 -0
- package/dist/core/types/index.cjs +152 -0
- package/dist/core/types/index.d.cts +214 -0
- package/dist/core/types/index.d.ts +214 -0
- package/dist/core/types/index.js +112 -0
- package/dist/core/user-BmL3kFol.d.ts +50 -0
- package/dist/core/user-eUuKj7yM.d.cts +50 -0
- package/dist/core/utils/pricing.cjs +102 -0
- package/dist/core/utils/pricing.d.cts +43 -0
- package/dist/core/utils/pricing.d.ts +43 -0
- package/dist/core/utils/pricing.js +75 -0
- package/dist/core/worktrees-BzIxB1U6.d.cts +2745 -0
- package/dist/core/worktrees-CYem1ya2.d.ts +2745 -0
- package/dist/daemon/adapters/drizzle.d.ts +114 -0
- package/dist/daemon/adapters/drizzle.js +219 -0
- package/dist/daemon/declarations.d.ts +101 -0
- package/dist/daemon/declarations.js +0 -0
- package/dist/daemon/index.d.ts +2 -0
- package/dist/daemon/index.js +4093 -0
- package/dist/daemon/mcp/routes.d.ts +15 -0
- package/dist/daemon/mcp/routes.js +641 -0
- package/dist/daemon/mcp/tokens.d.ts +50 -0
- package/dist/daemon/mcp/tokens.js +85 -0
- package/dist/daemon/services/board-comments.d.ts +97 -0
- package/dist/daemon/services/board-comments.js +326 -0
- package/dist/daemon/services/board-objects.d.ts +71 -0
- package/dist/daemon/services/board-objects.js +117 -0
- package/dist/daemon/services/boards.d.ts +64 -0
- package/dist/daemon/services/boards.js +286 -0
- package/dist/daemon/services/config.d.ts +35 -0
- package/dist/daemon/services/config.js +68 -0
- package/dist/daemon/services/context.d.ts +55 -0
- package/dist/daemon/services/context.js +113 -0
- package/dist/daemon/services/health-monitor.d.ts +58 -0
- package/dist/daemon/services/health-monitor.js +158 -0
- package/dist/daemon/services/mcp-servers.d.ts +42 -0
- package/dist/daemon/services/mcp-servers.js +275 -0
- package/dist/daemon/services/messages.d.ts +49 -0
- package/dist/daemon/services/messages.js +269 -0
- package/dist/daemon/services/repos.d.ts +61 -0
- package/dist/daemon/services/repos.js +350 -0
- package/dist/daemon/services/session-mcp-servers.d.ts +56 -0
- package/dist/daemon/services/session-mcp-servers.js +51 -0
- package/dist/daemon/services/sessions.d.ts +64 -0
- package/dist/daemon/services/sessions.js +398 -0
- package/dist/daemon/services/tasks.d.ts +55 -0
- package/dist/daemon/services/tasks.js +318 -0
- package/dist/daemon/services/terminals.d.ts +75 -0
- package/dist/daemon/services/terminals.js +110 -0
- package/dist/daemon/services/users.d.ts +98 -0
- package/dist/daemon/services/users.js +177 -0
- package/dist/daemon/services/worktrees.d.ts +98 -0
- package/dist/daemon/services/worktrees.js +719 -0
- package/dist/daemon/strategies/anonymous.d.ts +20 -0
- package/dist/daemon/strategies/anonymous.js +32 -0
- package/dist/ui/assets/cc-CYmbalCD.png +0 -0
- package/dist/ui/assets/codex-4sLD1mVS.png +0 -0
- package/dist/ui/assets/cursor-BUy5pFVL.png +0 -0
- package/dist/ui/assets/gemini-ajOb7iAl.png +0 -0
- package/dist/ui/assets/index-Dc4ELxry.css +32 -0
- package/dist/ui/assets/index-KfIu8v4V.js +578 -0
- package/dist/ui/favicon.png +0 -0
- package/dist/ui/index.html +26 -0
- package/dist/ui/vite.svg +1 -0
- package/package.json +90 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Database } from '@agor/core/db';
|
|
2
|
+
import { QueryParams, Board, BoardObject } from '@agor/core/types';
|
|
3
|
+
import { DrizzleService } from '../adapters/drizzle.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Boards Service
|
|
7
|
+
*
|
|
8
|
+
* Provides REST + WebSocket API for board management.
|
|
9
|
+
* Uses DrizzleService adapter with BoardRepository.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Board service params
|
|
14
|
+
*/
|
|
15
|
+
type BoardParams = QueryParams<{
|
|
16
|
+
slug?: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* Extended boards service with custom methods
|
|
21
|
+
*/
|
|
22
|
+
declare class BoardsService extends DrizzleService<Board, Partial<Board>, BoardParams> {
|
|
23
|
+
private boardRepo;
|
|
24
|
+
constructor(db: Database);
|
|
25
|
+
/**
|
|
26
|
+
* Custom method: Find board by slug
|
|
27
|
+
*/
|
|
28
|
+
findBySlug(slug: string, _params?: BoardParams): Promise<Board | null>;
|
|
29
|
+
/**
|
|
30
|
+
* DEPRECATED: Add session to board
|
|
31
|
+
* Use board-objects service instead
|
|
32
|
+
*/
|
|
33
|
+
addSession(_id: string, _sessionId: string, _params?: BoardParams): Promise<Board>;
|
|
34
|
+
/**
|
|
35
|
+
* DEPRECATED: Remove session from board
|
|
36
|
+
* Use board-objects service instead
|
|
37
|
+
*/
|
|
38
|
+
removeSession(_id: string, _sessionId: string, _params?: BoardParams): Promise<Board>;
|
|
39
|
+
/**
|
|
40
|
+
* Custom method: Atomically add or update a board object
|
|
41
|
+
*/
|
|
42
|
+
upsertBoardObject(boardId: string, objectId: string, objectData: BoardObject, _params?: BoardParams): Promise<Board>;
|
|
43
|
+
/**
|
|
44
|
+
* Custom method: Atomically remove a board object
|
|
45
|
+
*/
|
|
46
|
+
removeBoardObject(boardId: string, objectId: string, _params?: BoardParams): Promise<Board>;
|
|
47
|
+
/**
|
|
48
|
+
* Custom method: Batch upsert board objects
|
|
49
|
+
*/
|
|
50
|
+
batchUpsertBoardObjects(boardId: string, objects: Record<string, BoardObject>, _params?: BoardParams): Promise<Board>;
|
|
51
|
+
/**
|
|
52
|
+
* Custom method: Delete a zone and handle associated sessions
|
|
53
|
+
*/
|
|
54
|
+
deleteZone(boardId: string, objectId: string, deleteAssociatedSessions: boolean, _params?: BoardParams): Promise<{
|
|
55
|
+
board: Board;
|
|
56
|
+
affectedSessions: string[];
|
|
57
|
+
}>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Service factory function
|
|
61
|
+
*/
|
|
62
|
+
declare function createBoardsService(db: Database): BoardsService;
|
|
63
|
+
|
|
64
|
+
export { type BoardParams, BoardsService, createBoardsService };
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
// src/services/boards.ts
|
|
2
|
+
import { BoardRepository } from "@agor/core/db";
|
|
3
|
+
|
|
4
|
+
// src/adapters/drizzle.ts
|
|
5
|
+
var DrizzleService = class {
|
|
6
|
+
constructor(repository, options = {}) {
|
|
7
|
+
this.repository = repository;
|
|
8
|
+
this.id = options.id ?? "id";
|
|
9
|
+
this.paginate = options.paginate;
|
|
10
|
+
this.multi = options.multi ?? false;
|
|
11
|
+
}
|
|
12
|
+
id;
|
|
13
|
+
paginate;
|
|
14
|
+
multi;
|
|
15
|
+
// Event emitter for FeathersJS (will be injected by framework)
|
|
16
|
+
// biome-ignore lint/suspicious/noExplicitAny: FeathersJS event system
|
|
17
|
+
emit;
|
|
18
|
+
/**
|
|
19
|
+
* Extract query parameters from params
|
|
20
|
+
*/
|
|
21
|
+
getQuery(params) {
|
|
22
|
+
return params?.query ?? {};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Apply filters to data array (client-side filtering)
|
|
26
|
+
*/
|
|
27
|
+
filterData(data, query) {
|
|
28
|
+
let filtered = [...data];
|
|
29
|
+
for (const [key, value] of Object.entries(query)) {
|
|
30
|
+
if (key.startsWith("$")) continue;
|
|
31
|
+
filtered = filtered.filter((item) => {
|
|
32
|
+
if (typeof value === "object" && value !== null) {
|
|
33
|
+
for (const [op, opValue] of Object.entries(value)) {
|
|
34
|
+
switch (op) {
|
|
35
|
+
case "$in":
|
|
36
|
+
return Array.isArray(opValue) && opValue.includes(item[key]);
|
|
37
|
+
case "$nin":
|
|
38
|
+
return Array.isArray(opValue) && !opValue.includes(item[key]);
|
|
39
|
+
case "$ne":
|
|
40
|
+
return item[key] !== opValue;
|
|
41
|
+
case "$gt":
|
|
42
|
+
return item[key] > opValue;
|
|
43
|
+
case "$gte":
|
|
44
|
+
return item[key] >= opValue;
|
|
45
|
+
case "$lt":
|
|
46
|
+
return item[key] < opValue;
|
|
47
|
+
case "$lte":
|
|
48
|
+
return item[key] <= opValue;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return item[key] === value;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return filtered;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Sort data array
|
|
59
|
+
*/
|
|
60
|
+
sortData(data, sortSpec) {
|
|
61
|
+
if (!sortSpec) return data;
|
|
62
|
+
const sorted = [...data];
|
|
63
|
+
const entries = Object.entries(sortSpec);
|
|
64
|
+
sorted.sort((a, b) => {
|
|
65
|
+
for (const [field, direction] of entries) {
|
|
66
|
+
const aVal = a[field];
|
|
67
|
+
const bVal = b[field];
|
|
68
|
+
if (aVal < bVal) return direction === 1 ? -1 : 1;
|
|
69
|
+
if (aVal > bVal) return direction === 1 ? 1 : -1;
|
|
70
|
+
}
|
|
71
|
+
return 0;
|
|
72
|
+
});
|
|
73
|
+
return sorted;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Select specific fields from data
|
|
77
|
+
*/
|
|
78
|
+
selectFields(data, fields) {
|
|
79
|
+
if (!fields || fields.length === 0) return data;
|
|
80
|
+
return data.map((item) => {
|
|
81
|
+
const selected = {};
|
|
82
|
+
for (const field of fields) {
|
|
83
|
+
if (field in item) {
|
|
84
|
+
selected[field] = item[field];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return selected;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Apply pagination to data
|
|
92
|
+
*/
|
|
93
|
+
paginateData(data, query, total) {
|
|
94
|
+
const limit = query.$limit ?? this.paginate?.default ?? data.length;
|
|
95
|
+
const skip = query.$skip ?? 0;
|
|
96
|
+
if (!this.paginate) {
|
|
97
|
+
return data;
|
|
98
|
+
}
|
|
99
|
+
const maxLimit = this.paginate.max ?? 1e3;
|
|
100
|
+
const actualLimit = Math.min(limit, maxLimit);
|
|
101
|
+
const paginated = data.slice(skip, skip + actualLimit);
|
|
102
|
+
return {
|
|
103
|
+
total,
|
|
104
|
+
limit: actualLimit,
|
|
105
|
+
skip,
|
|
106
|
+
data: paginated
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Find records
|
|
111
|
+
*/
|
|
112
|
+
async find(params) {
|
|
113
|
+
const query = this.getQuery(params);
|
|
114
|
+
let data = await this.repository.findAll();
|
|
115
|
+
const total = data.length;
|
|
116
|
+
data = this.filterData(data, query);
|
|
117
|
+
data = this.sortData(data, query.$sort);
|
|
118
|
+
const selected = this.selectFields(data, query.$select);
|
|
119
|
+
return this.paginateData(selected, query, total);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get a single record by ID
|
|
123
|
+
*/
|
|
124
|
+
async get(id, _params) {
|
|
125
|
+
const result = await this.repository.findById(String(id));
|
|
126
|
+
if (!result) {
|
|
127
|
+
throw new Error(`No record found for id '${id}'`);
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Create one or more records
|
|
133
|
+
*/
|
|
134
|
+
async create(data, params) {
|
|
135
|
+
if (Array.isArray(data)) {
|
|
136
|
+
const results = await Promise.all(
|
|
137
|
+
data.map((item) => this.repository.create(item))
|
|
138
|
+
);
|
|
139
|
+
for (const result2 of results) {
|
|
140
|
+
this.emit?.("created", result2, params);
|
|
141
|
+
}
|
|
142
|
+
return results;
|
|
143
|
+
}
|
|
144
|
+
const result = await this.repository.create(data);
|
|
145
|
+
console.log("\u{1F514} [DrizzleService] Emitting created event, emit function exists:", !!this.emit);
|
|
146
|
+
this.emit?.("created", result, params);
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Update a record (complete replacement)
|
|
151
|
+
*/
|
|
152
|
+
async update(id, data, params) {
|
|
153
|
+
const existing = await this.get(id, params);
|
|
154
|
+
if (!existing) {
|
|
155
|
+
throw new Error(`No record found for id '${id}'`);
|
|
156
|
+
}
|
|
157
|
+
const result = await this.repository.update(String(id), data);
|
|
158
|
+
this.emit?.("updated", result, params);
|
|
159
|
+
this.emit?.("patched", result, params);
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Patch a record (partial update)
|
|
164
|
+
*/
|
|
165
|
+
async patch(id, data, params) {
|
|
166
|
+
if (id === null) {
|
|
167
|
+
if (!this.multi) {
|
|
168
|
+
throw new Error("Multi-patch is not enabled");
|
|
169
|
+
}
|
|
170
|
+
const query = this.getQuery(params);
|
|
171
|
+
let records = await this.repository.findAll();
|
|
172
|
+
records = this.filterData(records, query);
|
|
173
|
+
const results = await Promise.all(
|
|
174
|
+
records.map(
|
|
175
|
+
(record) => this.repository.update(
|
|
176
|
+
record[this.id],
|
|
177
|
+
data
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
);
|
|
181
|
+
for (const result2 of results) {
|
|
182
|
+
this.emit?.("patched", result2, params);
|
|
183
|
+
}
|
|
184
|
+
return results;
|
|
185
|
+
}
|
|
186
|
+
const existing = await this.get(id, params);
|
|
187
|
+
if (!existing) {
|
|
188
|
+
throw new Error(`No record found for id '${id}'`);
|
|
189
|
+
}
|
|
190
|
+
const result = await this.repository.update(String(id), data);
|
|
191
|
+
this.emit?.("patched", result, params);
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Remove one or more records
|
|
196
|
+
*/
|
|
197
|
+
async remove(id, params) {
|
|
198
|
+
if (id === null) {
|
|
199
|
+
if (!this.multi) {
|
|
200
|
+
throw new Error("Multi-remove is not enabled");
|
|
201
|
+
}
|
|
202
|
+
const query = this.getQuery(params);
|
|
203
|
+
let records = await this.repository.findAll();
|
|
204
|
+
records = this.filterData(records, query);
|
|
205
|
+
await Promise.all(records.map((record) => this.repository.delete(record[this.id])));
|
|
206
|
+
for (const record of records) {
|
|
207
|
+
this.emit?.("removed", record, params);
|
|
208
|
+
}
|
|
209
|
+
return records;
|
|
210
|
+
}
|
|
211
|
+
const existing = await this.get(id, params);
|
|
212
|
+
if (!existing) {
|
|
213
|
+
throw new Error(`No record found for id '${id}'`);
|
|
214
|
+
}
|
|
215
|
+
await this.repository.delete(String(id));
|
|
216
|
+
this.emit?.("removed", existing, params);
|
|
217
|
+
return existing;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
// src/services/boards.ts
|
|
222
|
+
var BoardsService = class extends DrizzleService {
|
|
223
|
+
boardRepo;
|
|
224
|
+
constructor(db) {
|
|
225
|
+
const boardRepo = new BoardRepository(db);
|
|
226
|
+
super(boardRepo, {
|
|
227
|
+
id: "board_id",
|
|
228
|
+
paginate: {
|
|
229
|
+
default: 50,
|
|
230
|
+
max: 100
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
this.boardRepo = boardRepo;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Custom method: Find board by slug
|
|
237
|
+
*/
|
|
238
|
+
async findBySlug(slug, _params) {
|
|
239
|
+
return this.boardRepo.findBySlug(slug);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* DEPRECATED: Add session to board
|
|
243
|
+
* Use board-objects service instead
|
|
244
|
+
*/
|
|
245
|
+
async addSession(_id, _sessionId, _params) {
|
|
246
|
+
throw new Error("addSession is deprecated - use board-objects service");
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* DEPRECATED: Remove session from board
|
|
250
|
+
* Use board-objects service instead
|
|
251
|
+
*/
|
|
252
|
+
async removeSession(_id, _sessionId, _params) {
|
|
253
|
+
throw new Error("removeSession is deprecated - use board-objects service");
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Custom method: Atomically add or update a board object
|
|
257
|
+
*/
|
|
258
|
+
async upsertBoardObject(boardId, objectId, objectData, _params) {
|
|
259
|
+
return this.boardRepo.upsertBoardObject(boardId, objectId, objectData);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Custom method: Atomically remove a board object
|
|
263
|
+
*/
|
|
264
|
+
async removeBoardObject(boardId, objectId, _params) {
|
|
265
|
+
return this.boardRepo.removeBoardObject(boardId, objectId);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Custom method: Batch upsert board objects
|
|
269
|
+
*/
|
|
270
|
+
async batchUpsertBoardObjects(boardId, objects, _params) {
|
|
271
|
+
return this.boardRepo.batchUpsertBoardObjects(boardId, objects);
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Custom method: Delete a zone and handle associated sessions
|
|
275
|
+
*/
|
|
276
|
+
async deleteZone(boardId, objectId, deleteAssociatedSessions, _params) {
|
|
277
|
+
return this.boardRepo.deleteZone(boardId, objectId, deleteAssociatedSessions);
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
function createBoardsService(db) {
|
|
281
|
+
return new BoardsService(db);
|
|
282
|
+
}
|
|
283
|
+
export {
|
|
284
|
+
BoardsService,
|
|
285
|
+
createBoardsService
|
|
286
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { AgorConfig } from '@agor/core/config';
|
|
2
|
+
import { Params } from '@agor/core/types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Config Service
|
|
6
|
+
*
|
|
7
|
+
* Provides REST + WebSocket API for configuration management.
|
|
8
|
+
* Wraps @agor/core/config functions for UI access.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Config service class
|
|
13
|
+
*/
|
|
14
|
+
declare class ConfigService {
|
|
15
|
+
/**
|
|
16
|
+
* Get full config (masked)
|
|
17
|
+
*/
|
|
18
|
+
find(_params?: Params): Promise<AgorConfig>;
|
|
19
|
+
/**
|
|
20
|
+
* Get specific config section or value
|
|
21
|
+
*/
|
|
22
|
+
get(id: string, _params?: Params): Promise<unknown>;
|
|
23
|
+
/**
|
|
24
|
+
* Update config values
|
|
25
|
+
*
|
|
26
|
+
* SECURITY: Only allow updating credentials section from UI
|
|
27
|
+
*/
|
|
28
|
+
patch(_id: null, data: Partial<AgorConfig>, _params?: Params): Promise<AgorConfig>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Service factory function
|
|
32
|
+
*/
|
|
33
|
+
declare function createConfigService(): ConfigService;
|
|
34
|
+
|
|
35
|
+
export { ConfigService, createConfigService };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// src/services/config.ts
|
|
2
|
+
import { loadConfig, saveConfig } from "@agor/core/config";
|
|
3
|
+
function maskApiKey(key) {
|
|
4
|
+
if (!key || typeof key !== "string") return void 0;
|
|
5
|
+
if (key.length <= 10) return "***";
|
|
6
|
+
return `${key.substring(0, 10)}...`;
|
|
7
|
+
}
|
|
8
|
+
function maskCredentials(config) {
|
|
9
|
+
if (!config.credentials) return config;
|
|
10
|
+
return {
|
|
11
|
+
...config,
|
|
12
|
+
credentials: {
|
|
13
|
+
ANTHROPIC_API_KEY: maskApiKey(config.credentials.ANTHROPIC_API_KEY),
|
|
14
|
+
OPENAI_API_KEY: maskApiKey(config.credentials.OPENAI_API_KEY),
|
|
15
|
+
GEMINI_API_KEY: maskApiKey(config.credentials.GEMINI_API_KEY),
|
|
16
|
+
CURSOR_API_KEY: maskApiKey(config.credentials.CURSOR_API_KEY)
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
var ConfigService = class {
|
|
21
|
+
/**
|
|
22
|
+
* Get full config (masked)
|
|
23
|
+
*/
|
|
24
|
+
async find(_params) {
|
|
25
|
+
const config = await loadConfig();
|
|
26
|
+
return maskCredentials(config);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get specific config section or value
|
|
30
|
+
*/
|
|
31
|
+
async get(id, _params) {
|
|
32
|
+
const config = await loadConfig();
|
|
33
|
+
const masked = maskCredentials(config);
|
|
34
|
+
const parts = id.split(".");
|
|
35
|
+
let value = masked;
|
|
36
|
+
for (const part of parts) {
|
|
37
|
+
if (value && typeof value === "object" && part in value) {
|
|
38
|
+
value = value[part];
|
|
39
|
+
} else {
|
|
40
|
+
return void 0;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Update config values
|
|
47
|
+
*
|
|
48
|
+
* SECURITY: Only allow updating credentials section from UI
|
|
49
|
+
*/
|
|
50
|
+
async patch(_id, data, _params) {
|
|
51
|
+
const config = await loadConfig();
|
|
52
|
+
if (data.credentials) {
|
|
53
|
+
config.credentials = {
|
|
54
|
+
...config.credentials,
|
|
55
|
+
...data.credentials
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
await saveConfig(config);
|
|
59
|
+
return maskCredentials(config);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
function createConfigService() {
|
|
63
|
+
return new ConfigService();
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
ConfigService,
|
|
67
|
+
createConfigService
|
|
68
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { WorktreeRepository } from '@agor/core/db';
|
|
2
|
+
import { QueryParams, ServiceMethods, ContextFileListItem, ContextFileDetail, Id } from '@agor/core/types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Context Service
|
|
6
|
+
*
|
|
7
|
+
* Provides read-only REST + WebSocket API for browsing markdown files in worktree context/ directories.
|
|
8
|
+
* Does not use database - reads directly from filesystem.
|
|
9
|
+
*
|
|
10
|
+
* Configuration:
|
|
11
|
+
* - Scans context/ folder from worktree path when worktree_id is provided
|
|
12
|
+
* - Recursively finds all .md files in context/ and subdirectories
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Context service params (read-only, no create/update/delete)
|
|
17
|
+
*/
|
|
18
|
+
type ContextParams = QueryParams<{
|
|
19
|
+
worktree_id?: string;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Context service - read-only filesystem browser for worktree concept files
|
|
23
|
+
*/
|
|
24
|
+
declare class ContextService implements Pick<ServiceMethods<ContextFileListItem | ContextFileDetail>, 'find' | 'get' | 'setup' | 'teardown'> {
|
|
25
|
+
private worktreeRepo;
|
|
26
|
+
constructor(worktreeRepo: WorktreeRepository);
|
|
27
|
+
/**
|
|
28
|
+
* Find all markdown files (GET /context?worktree_id=xxx)
|
|
29
|
+
* Returns lightweight list items without content
|
|
30
|
+
*/
|
|
31
|
+
find(params?: ContextParams): Promise<ContextFileListItem[]>;
|
|
32
|
+
/**
|
|
33
|
+
* Get specific markdown file (GET /context/:path?worktree_id=xxx)
|
|
34
|
+
* Returns full details with content
|
|
35
|
+
*
|
|
36
|
+
* @param id - Relative path from worktree root (e.g., "context/concepts/core.md", "CLAUDE.md")
|
|
37
|
+
*/
|
|
38
|
+
get(id: Id, params?: ContextParams): Promise<ContextFileDetail>;
|
|
39
|
+
/**
|
|
40
|
+
* Recursively scan directory for markdown files
|
|
41
|
+
*/
|
|
42
|
+
private scanDirectory;
|
|
43
|
+
/**
|
|
44
|
+
* Extract title from markdown content (first H1) or fallback to filename
|
|
45
|
+
*/
|
|
46
|
+
private extractTitle;
|
|
47
|
+
setup(): Promise<void>;
|
|
48
|
+
teardown(): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Service factory function
|
|
52
|
+
*/
|
|
53
|
+
declare function createContextService(worktreeRepo: WorktreeRepository): ContextService;
|
|
54
|
+
|
|
55
|
+
export { type ContextParams, ContextService, createContextService };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// src/services/context.ts
|
|
2
|
+
import { readdir, readFile, stat } from "fs/promises";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
var ContextService = class {
|
|
5
|
+
worktreeRepo;
|
|
6
|
+
constructor(worktreeRepo) {
|
|
7
|
+
this.worktreeRepo = worktreeRepo;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Find all markdown files (GET /context?worktree_id=xxx)
|
|
11
|
+
* Returns lightweight list items without content
|
|
12
|
+
*/
|
|
13
|
+
async find(params) {
|
|
14
|
+
const worktreeId = params?.query?.worktree_id;
|
|
15
|
+
if (!worktreeId) {
|
|
16
|
+
throw new Error("worktree_id query parameter is required");
|
|
17
|
+
}
|
|
18
|
+
const worktree = await this.worktreeRepo.findById(worktreeId);
|
|
19
|
+
if (!worktree) {
|
|
20
|
+
throw new Error(`Worktree not found: ${worktreeId}`);
|
|
21
|
+
}
|
|
22
|
+
console.log("[Context Service] Worktree:", {
|
|
23
|
+
worktree_id: worktree.worktree_id,
|
|
24
|
+
name: worktree.name,
|
|
25
|
+
path: worktree.path
|
|
26
|
+
});
|
|
27
|
+
const files = [];
|
|
28
|
+
await this.scanDirectory(worktree.path, "context", files);
|
|
29
|
+
console.log("[Context Service] Found files:", files.length);
|
|
30
|
+
return files;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get specific markdown file (GET /context/:path?worktree_id=xxx)
|
|
34
|
+
* Returns full details with content
|
|
35
|
+
*
|
|
36
|
+
* @param id - Relative path from worktree root (e.g., "context/concepts/core.md", "CLAUDE.md")
|
|
37
|
+
*/
|
|
38
|
+
async get(id, params) {
|
|
39
|
+
const worktreeId = params?.query?.worktree_id;
|
|
40
|
+
if (!worktreeId) {
|
|
41
|
+
throw new Error("worktree_id query parameter is required");
|
|
42
|
+
}
|
|
43
|
+
const worktree = await this.worktreeRepo.findById(worktreeId);
|
|
44
|
+
if (!worktree) {
|
|
45
|
+
throw new Error(`Worktree not found: ${worktreeId}`);
|
|
46
|
+
}
|
|
47
|
+
const relativePath = id.toString();
|
|
48
|
+
const fullPath = join(worktree.path, relativePath);
|
|
49
|
+
try {
|
|
50
|
+
const content = await readFile(fullPath, "utf-8");
|
|
51
|
+
const stats = await stat(fullPath);
|
|
52
|
+
const title = this.extractTitle(content, relativePath);
|
|
53
|
+
return {
|
|
54
|
+
path: relativePath,
|
|
55
|
+
title,
|
|
56
|
+
size: stats.size,
|
|
57
|
+
lastModified: stats.mtime.toISOString(),
|
|
58
|
+
content
|
|
59
|
+
};
|
|
60
|
+
} catch (error) {
|
|
61
|
+
throw new Error(`Failed to read context file: ${error}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Recursively scan directory for markdown files
|
|
66
|
+
*/
|
|
67
|
+
async scanDirectory(basePath, relativePath, files) {
|
|
68
|
+
const dirPath = join(basePath, relativePath);
|
|
69
|
+
try {
|
|
70
|
+
const entries = await readdir(dirPath, { withFileTypes: true });
|
|
71
|
+
for (const entry of entries) {
|
|
72
|
+
const entryRelPath = relativePath ? join(relativePath, entry.name) : entry.name;
|
|
73
|
+
if (entry.isDirectory()) {
|
|
74
|
+
await this.scanDirectory(basePath, entryRelPath, files);
|
|
75
|
+
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
76
|
+
const fullPath = join(dirPath, entry.name);
|
|
77
|
+
const stats = await stat(fullPath);
|
|
78
|
+
const content = await readFile(fullPath, "utf-8");
|
|
79
|
+
const title = this.extractTitle(content, entryRelPath);
|
|
80
|
+
files.push({
|
|
81
|
+
path: entryRelPath,
|
|
82
|
+
title,
|
|
83
|
+
size: stats.size,
|
|
84
|
+
lastModified: stats.mtime.toISOString()
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
} catch (_error) {
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Extract title from markdown content (first H1) or fallback to filename
|
|
93
|
+
*/
|
|
94
|
+
extractTitle(content, relativePath) {
|
|
95
|
+
const h1Match = content.match(/^#\s+(.+)$/m);
|
|
96
|
+
if (h1Match) {
|
|
97
|
+
return h1Match[1].trim();
|
|
98
|
+
}
|
|
99
|
+
const filename = relativePath.split("/").pop() || relativePath;
|
|
100
|
+
return filename.replace(/\.md$/, "");
|
|
101
|
+
}
|
|
102
|
+
async setup() {
|
|
103
|
+
}
|
|
104
|
+
async teardown() {
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
function createContextService(worktreeRepo) {
|
|
108
|
+
return new ContextService(worktreeRepo);
|
|
109
|
+
}
|
|
110
|
+
export {
|
|
111
|
+
ContextService,
|
|
112
|
+
createContextService
|
|
113
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as _agor_core from '@agor/core';
|
|
2
|
+
import { Application } from '@agor/core/feathers';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Health Monitor - Singleton service for periodic health checks
|
|
6
|
+
*/
|
|
7
|
+
declare class HealthMonitor {
|
|
8
|
+
private app;
|
|
9
|
+
private intervals;
|
|
10
|
+
private isShuttingDown;
|
|
11
|
+
constructor(app: Application);
|
|
12
|
+
/**
|
|
13
|
+
* Set up WebSocket listeners for worktree changes
|
|
14
|
+
*/
|
|
15
|
+
private setupWorktreeListeners;
|
|
16
|
+
/**
|
|
17
|
+
* Handle worktree state changes
|
|
18
|
+
*/
|
|
19
|
+
private handleWorktreeUpdate;
|
|
20
|
+
/**
|
|
21
|
+
* Start monitoring a worktree's health
|
|
22
|
+
*/
|
|
23
|
+
private startMonitoring;
|
|
24
|
+
/**
|
|
25
|
+
* Stop monitoring a worktree's health
|
|
26
|
+
*/
|
|
27
|
+
private stopMonitoring;
|
|
28
|
+
/**
|
|
29
|
+
* Perform health check for a specific worktree
|
|
30
|
+
*/
|
|
31
|
+
private checkHealth;
|
|
32
|
+
/**
|
|
33
|
+
* Initialize monitoring for all currently running worktrees
|
|
34
|
+
*
|
|
35
|
+
* Called on daemon startup to resume monitoring existing environments
|
|
36
|
+
*/
|
|
37
|
+
initialize(): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Cleanup all monitoring intervals
|
|
40
|
+
*
|
|
41
|
+
* Called on daemon shutdown
|
|
42
|
+
*/
|
|
43
|
+
cleanup(): void;
|
|
44
|
+
/**
|
|
45
|
+
* Get monitoring status (for debugging)
|
|
46
|
+
*/
|
|
47
|
+
getStatus(): {
|
|
48
|
+
isShuttingDown: boolean;
|
|
49
|
+
monitoredWorktrees: _agor_core.UUID[];
|
|
50
|
+
monitoringCount: number;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Create and initialize Health Monitor service
|
|
55
|
+
*/
|
|
56
|
+
declare function createHealthMonitor(app: Application): Promise<HealthMonitor>;
|
|
57
|
+
|
|
58
|
+
export { HealthMonitor, createHealthMonitor };
|