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.
Files changed (297) hide show
  1. package/LICENSE +94 -0
  2. package/README.md +163 -0
  3. package/bin/agor-daemon.js +20 -0
  4. package/bin/agor.js +14 -0
  5. package/dist/cli/base-command.d.ts +29 -0
  6. package/dist/cli/base-command.js +41 -0
  7. package/dist/cli/commands/board/add-session.d.ts +15 -0
  8. package/dist/cli/commands/board/add-session.js +102 -0
  9. package/dist/cli/commands/board/list.d.ts +14 -0
  10. package/dist/cli/commands/board/list.js +74 -0
  11. package/dist/cli/commands/config/clear.d.ts +13 -0
  12. package/dist/cli/commands/config/clear.js +21 -0
  13. package/dist/cli/commands/config/get.d.ts +13 -0
  14. package/dist/cli/commands/config/get.js +41 -0
  15. package/dist/cli/commands/config/index.d.ts +13 -0
  16. package/dist/cli/commands/config/index.js +118 -0
  17. package/dist/cli/commands/config/set.d.ts +14 -0
  18. package/dist/cli/commands/config/set.js +50 -0
  19. package/dist/cli/commands/config/unset.d.ts +13 -0
  20. package/dist/cli/commands/config/unset.js +35 -0
  21. package/dist/cli/commands/daemon/index.d.ts +13 -0
  22. package/dist/cli/commands/daemon/index.js +65 -0
  23. package/dist/cli/commands/daemon/logs.d.ts +13 -0
  24. package/dist/cli/commands/daemon/logs.js +78 -0
  25. package/dist/cli/commands/daemon/restart.d.ts +13 -0
  26. package/dist/cli/commands/daemon/restart.js +177 -0
  27. package/dist/cli/commands/daemon/start.d.ts +13 -0
  28. package/dist/cli/commands/daemon/start.js +193 -0
  29. package/dist/cli/commands/daemon/status.d.ts +13 -0
  30. package/dist/cli/commands/daemon/status.js +93 -0
  31. package/dist/cli/commands/daemon/stop.d.ts +13 -0
  32. package/dist/cli/commands/daemon/stop.js +108 -0
  33. package/dist/cli/commands/init.d.ts +44 -0
  34. package/dist/cli/commands/init.js +459 -0
  35. package/dist/cli/commands/mcp/add.d.ts +26 -0
  36. package/dist/cli/commands/mcp/add.js +162 -0
  37. package/dist/cli/commands/mcp/list.d.ts +16 -0
  38. package/dist/cli/commands/mcp/list.js +89 -0
  39. package/dist/cli/commands/mcp/remove.d.ts +17 -0
  40. package/dist/cli/commands/mcp/remove.js +86 -0
  41. package/dist/cli/commands/mcp/show.d.ts +14 -0
  42. package/dist/cli/commands/mcp/show.js +131 -0
  43. package/dist/cli/commands/repo/add.d.ts +16 -0
  44. package/dist/cli/commands/repo/add.js +105 -0
  45. package/dist/cli/commands/repo/list.d.ts +17 -0
  46. package/dist/cli/commands/repo/list.js +99 -0
  47. package/dist/cli/commands/repo/rm.d.ts +17 -0
  48. package/dist/cli/commands/repo/rm.js +126 -0
  49. package/dist/cli/commands/repo/worktree/add.d.ts +21 -0
  50. package/dist/cli/commands/repo/worktree/add.js +145 -0
  51. package/dist/cli/commands/repo/worktree/list.d.ts +21 -0
  52. package/dist/cli/commands/repo/worktree/list.js +136 -0
  53. package/dist/cli/commands/session/list.d.ts +30 -0
  54. package/dist/cli/commands/session/list.js +204 -0
  55. package/dist/cli/commands/session/load-claude.d.ts +16 -0
  56. package/dist/cli/commands/session/load-claude.js +211 -0
  57. package/dist/cli/commands/user/create-admin.d.ts +13 -0
  58. package/dist/cli/commands/user/create-admin.js +65 -0
  59. package/dist/cli/commands/user/create.d.ts +16 -0
  60. package/dist/cli/commands/user/create.js +126 -0
  61. package/dist/cli/commands/user/delete.d.ts +16 -0
  62. package/dist/cli/commands/user/delete.js +77 -0
  63. package/dist/cli/commands/user/list.d.ts +13 -0
  64. package/dist/cli/commands/user/list.js +78 -0
  65. package/dist/cli/commands/user/update.d.ts +19 -0
  66. package/dist/cli/commands/user/update.js +149 -0
  67. package/dist/cli/hooks/command-not-found.d.ts +9 -0
  68. package/dist/cli/hooks/command-not-found.js +14 -0
  69. package/dist/cli/lib/banner.d.ts +25 -0
  70. package/dist/cli/lib/banner.js +25 -0
  71. package/dist/cli/lib/context.d.ts +27 -0
  72. package/dist/cli/lib/context.js +32 -0
  73. package/dist/cli/lib/daemon-manager.d.ts +48 -0
  74. package/dist/cli/lib/daemon-manager.js +109 -0
  75. package/dist/cli/lib/help.d.ts +13 -0
  76. package/dist/cli/lib/help.js +46 -0
  77. package/dist/core/agentic-tool-B_gFNpk5.d.ts +33 -0
  78. package/dist/core/agentic-tool-DsyX8diw.d.cts +33 -0
  79. package/dist/core/api/index.cjs +98 -0
  80. package/dist/core/api/index.d.cts +174 -0
  81. package/dist/core/api/index.d.ts +174 -0
  82. package/dist/core/api/index.js +62 -0
  83. package/dist/core/board-comment-BUm0fpmD.d.cts +134 -0
  84. package/dist/core/board-comment-gC_-twPx.d.ts +134 -0
  85. package/dist/core/claude/index.cjs +673 -0
  86. package/dist/core/claude/index.d.cts +124 -0
  87. package/dist/core/claude/index.d.ts +124 -0
  88. package/dist/core/claude/index.js +629 -0
  89. package/dist/core/config/browser.cjs +165 -0
  90. package/dist/core/config/browser.d.cts +289 -0
  91. package/dist/core/config/browser.d.ts +289 -0
  92. package/dist/core/config/browser.js +131 -0
  93. package/dist/core/config/index.cjs +518 -0
  94. package/dist/core/config/index.d.cts +246 -0
  95. package/dist/core/config/index.d.ts +246 -0
  96. package/dist/core/config/index.js +451 -0
  97. package/dist/core/db/index.cjs +3726 -0
  98. package/dist/core/db/index.d.cts +631 -0
  99. package/dist/core/db/index.d.ts +631 -0
  100. package/dist/core/db/index.js +3649 -0
  101. package/dist/core/dist/agentic-tool-B_gFNpk5.d.ts +33 -0
  102. package/dist/core/dist/agentic-tool-DsyX8diw.d.cts +33 -0
  103. package/dist/core/dist/api/index.cjs +98 -0
  104. package/dist/core/dist/api/index.d.cts +174 -0
  105. package/dist/core/dist/api/index.d.ts +174 -0
  106. package/dist/core/dist/api/index.js +62 -0
  107. package/dist/core/dist/board-comment-BUm0fpmD.d.cts +134 -0
  108. package/dist/core/dist/board-comment-gC_-twPx.d.ts +134 -0
  109. package/dist/core/dist/claude/index.cjs +673 -0
  110. package/dist/core/dist/claude/index.d.cts +124 -0
  111. package/dist/core/dist/claude/index.d.ts +124 -0
  112. package/dist/core/dist/claude/index.js +629 -0
  113. package/dist/core/dist/config/browser.cjs +165 -0
  114. package/dist/core/dist/config/browser.d.cts +289 -0
  115. package/dist/core/dist/config/browser.d.ts +289 -0
  116. package/dist/core/dist/config/browser.js +131 -0
  117. package/dist/core/dist/config/index.cjs +518 -0
  118. package/dist/core/dist/config/index.d.cts +246 -0
  119. package/dist/core/dist/config/index.d.ts +246 -0
  120. package/dist/core/dist/config/index.js +451 -0
  121. package/dist/core/dist/db/index.cjs +3726 -0
  122. package/dist/core/dist/db/index.d.cts +631 -0
  123. package/dist/core/dist/db/index.d.ts +631 -0
  124. package/dist/core/dist/db/index.js +3649 -0
  125. package/dist/core/dist/environment/variable-resolver.cjs +92 -0
  126. package/dist/core/dist/environment/variable-resolver.d.cts +52 -0
  127. package/dist/core/dist/environment/variable-resolver.d.ts +52 -0
  128. package/dist/core/dist/environment/variable-resolver.js +53 -0
  129. package/dist/core/dist/feathers/index.cjs +66 -0
  130. package/dist/core/dist/feathers/index.d.cts +7 -0
  131. package/dist/core/dist/feathers/index.d.ts +7 -0
  132. package/dist/core/dist/feathers/index.js +25 -0
  133. package/dist/core/dist/feathers-BzHEPnpl.d.cts +228 -0
  134. package/dist/core/dist/feathers-BzHEPnpl.d.ts +228 -0
  135. package/dist/core/dist/git/index.cjs +302 -0
  136. package/dist/core/dist/git/index.d.cts +137 -0
  137. package/dist/core/dist/git/index.d.ts +137 -0
  138. package/dist/core/dist/git/index.js +260 -0
  139. package/dist/core/dist/id-DMqyogFB.d.cts +131 -0
  140. package/dist/core/dist/id-DMqyogFB.d.ts +131 -0
  141. package/dist/core/dist/index.cjs +4653 -0
  142. package/dist/core/dist/index.d.cts +23 -0
  143. package/dist/core/dist/index.d.ts +23 -0
  144. package/dist/core/dist/index.js +4509 -0
  145. package/dist/core/dist/message-BoxZISHg.d.cts +120 -0
  146. package/dist/core/dist/message-DvBzHu7V.d.ts +120 -0
  147. package/dist/core/dist/permissions/index.cjs +112 -0
  148. package/dist/core/dist/permissions/index.d.cts +81 -0
  149. package/dist/core/dist/permissions/index.d.ts +81 -0
  150. package/dist/core/dist/permissions/index.js +85 -0
  151. package/dist/core/dist/repo-3CUrCRbq.d.cts +405 -0
  152. package/dist/core/dist/repo-CnvJ0B6-.d.ts +405 -0
  153. package/dist/core/dist/session-BPjJlVdZ.d.cts +429 -0
  154. package/dist/core/dist/session-wAzjHatv.d.ts +429 -0
  155. package/dist/core/dist/task-BIEgT1DK.d.cts +163 -0
  156. package/dist/core/dist/task-DuIfiUbW.d.ts +163 -0
  157. package/dist/core/dist/templates/handlebars-helpers.cjs +156 -0
  158. package/dist/core/dist/templates/handlebars-helpers.d.cts +45 -0
  159. package/dist/core/dist/templates/handlebars-helpers.d.ts +45 -0
  160. package/dist/core/dist/templates/handlebars-helpers.js +119 -0
  161. package/dist/core/dist/tools/claude/models.cjs +70 -0
  162. package/dist/core/dist/tools/claude/models.d.cts +27 -0
  163. package/dist/core/dist/tools/claude/models.d.ts +27 -0
  164. package/dist/core/dist/tools/claude/models.js +44 -0
  165. package/dist/core/dist/tools/index.cjs +3367 -0
  166. package/dist/core/dist/tools/index.d.cts +967 -0
  167. package/dist/core/dist/tools/index.d.ts +967 -0
  168. package/dist/core/dist/tools/index.js +3314 -0
  169. package/dist/core/dist/tools/models.cjs +119 -0
  170. package/dist/core/dist/tools/models.d.cts +47 -0
  171. package/dist/core/dist/tools/models.d.ts +47 -0
  172. package/dist/core/dist/tools/models.js +86 -0
  173. package/dist/core/dist/types/index.cjs +152 -0
  174. package/dist/core/dist/types/index.d.cts +214 -0
  175. package/dist/core/dist/types/index.d.ts +214 -0
  176. package/dist/core/dist/types/index.js +112 -0
  177. package/dist/core/dist/user-BmL3kFol.d.ts +50 -0
  178. package/dist/core/dist/user-eUuKj7yM.d.cts +50 -0
  179. package/dist/core/dist/utils/pricing.cjs +102 -0
  180. package/dist/core/dist/utils/pricing.d.cts +43 -0
  181. package/dist/core/dist/utils/pricing.d.ts +43 -0
  182. package/dist/core/dist/utils/pricing.js +75 -0
  183. package/dist/core/dist/worktrees-BzIxB1U6.d.cts +2745 -0
  184. package/dist/core/dist/worktrees-CYem1ya2.d.ts +2745 -0
  185. package/dist/core/environment/variable-resolver.cjs +92 -0
  186. package/dist/core/environment/variable-resolver.d.cts +52 -0
  187. package/dist/core/environment/variable-resolver.d.ts +52 -0
  188. package/dist/core/environment/variable-resolver.js +53 -0
  189. package/dist/core/feathers/index.cjs +66 -0
  190. package/dist/core/feathers/index.d.cts +7 -0
  191. package/dist/core/feathers/index.d.ts +7 -0
  192. package/dist/core/feathers/index.js +25 -0
  193. package/dist/core/feathers-BzHEPnpl.d.cts +228 -0
  194. package/dist/core/feathers-BzHEPnpl.d.ts +228 -0
  195. package/dist/core/git/index.cjs +302 -0
  196. package/dist/core/git/index.d.cts +137 -0
  197. package/dist/core/git/index.d.ts +137 -0
  198. package/dist/core/git/index.js +260 -0
  199. package/dist/core/id-DMqyogFB.d.cts +131 -0
  200. package/dist/core/id-DMqyogFB.d.ts +131 -0
  201. package/dist/core/index.cjs +4653 -0
  202. package/dist/core/index.d.cts +23 -0
  203. package/dist/core/index.d.ts +23 -0
  204. package/dist/core/index.js +4509 -0
  205. package/dist/core/message-BoxZISHg.d.cts +120 -0
  206. package/dist/core/message-DvBzHu7V.d.ts +120 -0
  207. package/dist/core/package.json +133 -0
  208. package/dist/core/permissions/index.cjs +112 -0
  209. package/dist/core/permissions/index.d.cts +81 -0
  210. package/dist/core/permissions/index.d.ts +81 -0
  211. package/dist/core/permissions/index.js +85 -0
  212. package/dist/core/repo-3CUrCRbq.d.cts +405 -0
  213. package/dist/core/repo-CnvJ0B6-.d.ts +405 -0
  214. package/dist/core/session-BPjJlVdZ.d.cts +429 -0
  215. package/dist/core/session-wAzjHatv.d.ts +429 -0
  216. package/dist/core/task-BIEgT1DK.d.cts +163 -0
  217. package/dist/core/task-DuIfiUbW.d.ts +163 -0
  218. package/dist/core/templates/handlebars-helpers.cjs +156 -0
  219. package/dist/core/templates/handlebars-helpers.d.cts +45 -0
  220. package/dist/core/templates/handlebars-helpers.d.ts +45 -0
  221. package/dist/core/templates/handlebars-helpers.js +119 -0
  222. package/dist/core/tools/claude/models.cjs +70 -0
  223. package/dist/core/tools/claude/models.d.cts +27 -0
  224. package/dist/core/tools/claude/models.d.ts +27 -0
  225. package/dist/core/tools/claude/models.js +44 -0
  226. package/dist/core/tools/index.cjs +3367 -0
  227. package/dist/core/tools/index.d.cts +967 -0
  228. package/dist/core/tools/index.d.ts +967 -0
  229. package/dist/core/tools/index.js +3314 -0
  230. package/dist/core/tools/models.cjs +119 -0
  231. package/dist/core/tools/models.d.cts +47 -0
  232. package/dist/core/tools/models.d.ts +47 -0
  233. package/dist/core/tools/models.js +86 -0
  234. package/dist/core/types/index.cjs +152 -0
  235. package/dist/core/types/index.d.cts +214 -0
  236. package/dist/core/types/index.d.ts +214 -0
  237. package/dist/core/types/index.js +112 -0
  238. package/dist/core/user-BmL3kFol.d.ts +50 -0
  239. package/dist/core/user-eUuKj7yM.d.cts +50 -0
  240. package/dist/core/utils/pricing.cjs +102 -0
  241. package/dist/core/utils/pricing.d.cts +43 -0
  242. package/dist/core/utils/pricing.d.ts +43 -0
  243. package/dist/core/utils/pricing.js +75 -0
  244. package/dist/core/worktrees-BzIxB1U6.d.cts +2745 -0
  245. package/dist/core/worktrees-CYem1ya2.d.ts +2745 -0
  246. package/dist/daemon/adapters/drizzle.d.ts +114 -0
  247. package/dist/daemon/adapters/drizzle.js +219 -0
  248. package/dist/daemon/declarations.d.ts +101 -0
  249. package/dist/daemon/declarations.js +0 -0
  250. package/dist/daemon/index.d.ts +2 -0
  251. package/dist/daemon/index.js +4093 -0
  252. package/dist/daemon/mcp/routes.d.ts +15 -0
  253. package/dist/daemon/mcp/routes.js +641 -0
  254. package/dist/daemon/mcp/tokens.d.ts +50 -0
  255. package/dist/daemon/mcp/tokens.js +85 -0
  256. package/dist/daemon/services/board-comments.d.ts +97 -0
  257. package/dist/daemon/services/board-comments.js +326 -0
  258. package/dist/daemon/services/board-objects.d.ts +71 -0
  259. package/dist/daemon/services/board-objects.js +117 -0
  260. package/dist/daemon/services/boards.d.ts +64 -0
  261. package/dist/daemon/services/boards.js +286 -0
  262. package/dist/daemon/services/config.d.ts +35 -0
  263. package/dist/daemon/services/config.js +68 -0
  264. package/dist/daemon/services/context.d.ts +55 -0
  265. package/dist/daemon/services/context.js +113 -0
  266. package/dist/daemon/services/health-monitor.d.ts +58 -0
  267. package/dist/daemon/services/health-monitor.js +158 -0
  268. package/dist/daemon/services/mcp-servers.d.ts +42 -0
  269. package/dist/daemon/services/mcp-servers.js +275 -0
  270. package/dist/daemon/services/messages.d.ts +49 -0
  271. package/dist/daemon/services/messages.js +269 -0
  272. package/dist/daemon/services/repos.d.ts +61 -0
  273. package/dist/daemon/services/repos.js +350 -0
  274. package/dist/daemon/services/session-mcp-servers.d.ts +56 -0
  275. package/dist/daemon/services/session-mcp-servers.js +51 -0
  276. package/dist/daemon/services/sessions.d.ts +64 -0
  277. package/dist/daemon/services/sessions.js +398 -0
  278. package/dist/daemon/services/tasks.d.ts +55 -0
  279. package/dist/daemon/services/tasks.js +318 -0
  280. package/dist/daemon/services/terminals.d.ts +75 -0
  281. package/dist/daemon/services/terminals.js +110 -0
  282. package/dist/daemon/services/users.d.ts +98 -0
  283. package/dist/daemon/services/users.js +177 -0
  284. package/dist/daemon/services/worktrees.d.ts +98 -0
  285. package/dist/daemon/services/worktrees.js +719 -0
  286. package/dist/daemon/strategies/anonymous.d.ts +20 -0
  287. package/dist/daemon/strategies/anonymous.js +32 -0
  288. package/dist/ui/assets/cc-CYmbalCD.png +0 -0
  289. package/dist/ui/assets/codex-4sLD1mVS.png +0 -0
  290. package/dist/ui/assets/cursor-BUy5pFVL.png +0 -0
  291. package/dist/ui/assets/gemini-ajOb7iAl.png +0 -0
  292. package/dist/ui/assets/index-Dc4ELxry.css +32 -0
  293. package/dist/ui/assets/index-KfIu8v4V.js +578 -0
  294. package/dist/ui/favicon.png +0 -0
  295. package/dist/ui/index.html +26 -0
  296. package/dist/ui/vite.svg +1 -0
  297. 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 };