@agent-spaces/server 0.3.65 → 0.4.0

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 (278) hide show
  1. package/dist/adapters/agent-runtime.js +8 -0
  2. package/dist/adapters/codex-function-tool-bridge.js +152 -0
  3. package/dist/adapters/codex-runtime.js +23 -4
  4. package/dist/adapters/git.js +25 -3
  5. package/dist/adapters/hermes-runtime.js +813 -0
  6. package/dist/adapters/langchain-runtime.js +384 -21
  7. package/dist/adapters/oh-my-pi-runtime.js +858 -0
  8. package/dist/adapters/open-agent-sdk-runtime.js +202 -5
  9. package/dist/adapters/open-agent-sdk-runtime.test.js +35 -0
  10. package/dist/agents/agent-message-parts.js +52 -2
  11. package/dist/agents/issue-task-controller.js +71 -2
  12. package/dist/agents/pull-request-agent.js +115 -0
  13. package/dist/agents/scheduler-agent.js +1 -1
  14. package/dist/agents/title-generator-agent.js +120 -0
  15. package/dist/app.js +61 -4
  16. package/dist/middleware/auth.js +1 -1
  17. package/dist/package.json +2 -1
  18. package/dist/routes/agent-sse.js +70 -6
  19. package/dist/routes/channel.js +23 -2
  20. package/dist/routes/chat-run.js +191 -0
  21. package/dist/routes/chat.js +142 -0
  22. package/dist/routes/command.js +16 -0
  23. package/dist/routes/data.js +189 -0
  24. package/dist/routes/git.js +10 -1
  25. package/dist/routes/import.js +199 -0
  26. package/dist/routes/issue.js +17 -5
  27. package/dist/routes/notification.js +10 -0
  28. package/dist/routes/plugin.js +69 -0
  29. package/dist/routes/version.js +95 -0
  30. package/dist/routes/workflow-hook.js +71 -0
  31. package/dist/routes/workflow.js +282 -7
  32. package/dist/routes/workspace.js +13 -4
  33. package/dist/routes/worktree.js +93 -0
  34. package/dist/services/agent.js +123 -36
  35. package/dist/services/ai-text.js +185 -0
  36. package/dist/services/builtin-tools/index.js +1 -0
  37. package/dist/services/builtin-tools/workflow-editor-tools.js +509 -0
  38. package/dist/services/builtin-tools/workflow-exec-tools.js +320 -0
  39. package/dist/services/chat.js +134 -0
  40. package/dist/services/command-process-manager.js +16 -0
  41. package/dist/services/execution-manager.js +1346 -0
  42. package/dist/services/generated-title.js +59 -0
  43. package/dist/services/gitignore.js +22 -18
  44. package/dist/services/interaction-manager.js +114 -0
  45. package/dist/services/issue-retry.js +25 -0
  46. package/dist/services/notification-center.js +9 -0
  47. package/dist/services/output-style.js +8 -1
  48. package/dist/services/plugin.js +257 -0
  49. package/dist/services/prompt-template.js +8 -1
  50. package/dist/services/pty.js +20 -0
  51. package/dist/services/search.js +16 -6
  52. package/dist/services/skill.js +2 -0
  53. package/dist/services/version.js +69 -0
  54. package/dist/services/workflow-command-runner.js +24 -0
  55. package/dist/services/workflow-trigger-service.js +137 -0
  56. package/dist/services/workflow.js +219 -39
  57. package/dist/services/workspace.js +23 -1
  58. package/dist/services/worktree.js +207 -0
  59. package/dist/storage/agent-store.js +8 -0
  60. package/dist/storage/chat-store.js +151 -0
  61. package/dist/storage/database-store.js +6 -0
  62. package/dist/storage/json-store.js +2 -1
  63. package/dist/storage/kanban-store.js +6 -0
  64. package/dist/storage/workflow-store.js +386 -22
  65. package/dist/storage/worktree-store.js +33 -0
  66. package/dist/web/404.html +1 -1
  67. package/dist/web/__next.__PAGE__.txt +4 -4
  68. package/dist/web/__next._full.txt +21 -21
  69. package/dist/web/__next._head.txt +4 -4
  70. package/dist/web/__next._index.txt +13 -13
  71. package/dist/web/__next._tree.txt +2 -2
  72. package/dist/web/_next/static/chunks/{08x85faoz58i7.js → 0-92u-tiuy40a.js} +4 -4
  73. package/dist/web/_next/static/chunks/{0db14450oqzhg.js → 0-yizd8osmas2.js} +1 -1
  74. package/dist/web/_next/static/chunks/0.ln~3mnv8.69.js +1 -0
  75. package/dist/web/_next/static/chunks/{11cchuwoupmbf.js → 01y3e9pemva7b.js} +10 -10
  76. package/dist/web/_next/static/chunks/02l~tmzrgny.~.js +1 -0
  77. package/dist/web/_next/static/chunks/03f1bwuynjdmk.js +1 -0
  78. package/dist/web/_next/static/chunks/04cb4kc9r2pd1.js +1 -0
  79. package/dist/web/_next/static/chunks/04de6ha5_e3pp.js +1 -0
  80. package/dist/web/_next/static/chunks/09he0p79ov1rn.js +1 -0
  81. package/dist/web/_next/static/chunks/09vpocs4zuc8h.js +1 -0
  82. package/dist/web/_next/static/chunks/0_o2exgr0e_nh.js +1 -0
  83. package/dist/web/_next/static/chunks/{0xbaakj0dfc0..js → 0_y9nskc-xt2k.js} +1 -1
  84. package/dist/web/_next/static/chunks/0clnj-1fi6u8j.js +3 -0
  85. package/dist/web/_next/static/chunks/0gv40by0zzxs_.js +1 -0
  86. package/dist/web/_next/static/chunks/0iusr8y88.kjg.js +1 -0
  87. package/dist/web/_next/static/chunks/{0-a.-hl3wv99k.js → 0j-8418fxvkd1.js} +1 -1
  88. package/dist/web/_next/static/chunks/0j.wxxyoclma5.js +1 -0
  89. package/dist/web/_next/static/chunks/{0.6b64sy0g5.3.js → 0jq.16sozqik..js} +1 -1
  90. package/dist/web/_next/static/chunks/0jw8xdk_fpnp0.css +1 -0
  91. package/dist/web/_next/static/chunks/0l1lkd-wcotma.js +1 -0
  92. package/dist/web/_next/static/chunks/{0u6h-hqc_i52e.js → 0ncxf_zr4n839.js} +1 -1
  93. package/dist/web/_next/static/chunks/0ndo7um~v7vco.js +1 -0
  94. package/dist/web/_next/static/chunks/0ngk.~kan8wq_.js +1 -0
  95. package/dist/web/_next/static/chunks/0ppr271hz0xoq.js +1 -0
  96. package/dist/web/_next/static/chunks/0rt9bofnn6qvn.js +1 -0
  97. package/dist/web/_next/static/chunks/0t64.9jd00hio.js +3 -0
  98. package/dist/web/_next/static/chunks/0taui9--5n6-5.js +1 -0
  99. package/dist/web/_next/static/chunks/0ty39169lh~z3.js +1 -0
  100. package/dist/web/_next/static/chunks/0v8nof~waedlu.js +1 -0
  101. package/dist/web/_next/static/chunks/{0-pi.67w.ymsr.js → 0vcfoagnpf.aw.js} +1 -1
  102. package/dist/web/_next/static/chunks/{0vis~lx0nxgn-.js → 0wwwq.gyyz0vg.js} +3 -3
  103. package/dist/web/_next/static/chunks/0x5lak8yz7pm7.js +1 -0
  104. package/dist/web/_next/static/chunks/0xon_.4-o0_zq.js +7 -0
  105. package/dist/web/_next/static/chunks/0zjnrbt7inime.js +1 -0
  106. package/dist/web/_next/static/chunks/0zwebpitvpuv1.js +1 -0
  107. package/dist/web/_next/static/chunks/0~02o4g-o6n~m.js +1 -0
  108. package/dist/web/_next/static/chunks/{0w7.tb29958zj.js → 0~fjezp.k4qk3.js} +1 -1
  109. package/dist/web/_next/static/chunks/0~sh93re1-_rp.js +1 -0
  110. package/dist/web/_next/static/chunks/10_niiq0k6o-p.js +5 -0
  111. package/dist/web/_next/static/chunks/12tjr0_2ccrtq.js +2 -0
  112. package/dist/web/_next/static/chunks/12x5.go_x9mfk.js +1 -0
  113. package/dist/web/_next/static/chunks/{0l2w0qz1ea7ql.js → 12~5dk9i9d16t.js} +2 -2
  114. package/dist/web/_next/static/chunks/13iye4rv5p31b.js +1 -0
  115. package/dist/web/_next/static/chunks/{01~quun6sefgl.js → 13~y-b.b9rrw4.js} +1 -1
  116. package/dist/web/_next/static/chunks/151wzhb5q0lo5.js +1 -0
  117. package/dist/web/_not-found/__next._full.txt +19 -19
  118. package/dist/web/_not-found/__next._head.txt +4 -4
  119. package/dist/web/_not-found/__next._index.txt +13 -13
  120. package/dist/web/_not-found/__next._not-found.__PAGE__.txt +2 -2
  121. package/dist/web/_not-found/__next._not-found.txt +3 -3
  122. package/dist/web/_not-found/__next._tree.txt +2 -2
  123. package/dist/web/_not-found.html +1 -1
  124. package/dist/web/_not-found.txt +19 -19
  125. package/dist/web/index.html +1 -1
  126. package/dist/web/index.txt +21 -21
  127. package/dist/web/login/__next._full.txt +21 -21
  128. package/dist/web/login/__next._head.txt +4 -4
  129. package/dist/web/login/__next._index.txt +13 -13
  130. package/dist/web/login/__next._tree.txt +2 -2
  131. package/dist/web/login/__next.login.__PAGE__.txt +4 -4
  132. package/dist/web/login/__next.login.txt +3 -3
  133. package/dist/web/login.html +1 -1
  134. package/dist/web/login.txt +21 -21
  135. package/dist/web/settings/__next._full.txt +23 -23
  136. package/dist/web/settings/__next._head.txt +4 -4
  137. package/dist/web/settings/__next._index.txt +13 -13
  138. package/dist/web/settings/__next._tree.txt +2 -2
  139. package/dist/web/settings/__next.settings.__PAGE__.txt +4 -4
  140. package/dist/web/settings/__next.settings.txt +5 -5
  141. package/dist/web/settings/agents/__next._full.txt +23 -23
  142. package/dist/web/settings/agents/__next._head.txt +4 -4
  143. package/dist/web/settings/agents/__next._index.txt +13 -13
  144. package/dist/web/settings/agents/__next._tree.txt +2 -2
  145. package/dist/web/settings/agents/__next.settings.agents.__PAGE__.txt +4 -4
  146. package/dist/web/settings/agents/__next.settings.agents.txt +3 -3
  147. package/dist/web/settings/agents/__next.settings.txt +5 -5
  148. package/dist/web/settings/agents.html +1 -1
  149. package/dist/web/settings/agents.txt +23 -23
  150. package/dist/web/settings/mcps/__next._full.txt +23 -23
  151. package/dist/web/settings/mcps/__next._head.txt +4 -4
  152. package/dist/web/settings/mcps/__next._index.txt +13 -13
  153. package/dist/web/settings/mcps/__next._tree.txt +2 -2
  154. package/dist/web/settings/mcps/__next.settings.mcps.__PAGE__.txt +4 -4
  155. package/dist/web/settings/mcps/__next.settings.mcps.txt +3 -3
  156. package/dist/web/settings/mcps/__next.settings.txt +5 -5
  157. package/dist/web/settings/mcps.html +1 -1
  158. package/dist/web/settings/mcps.txt +23 -23
  159. package/dist/web/settings/models/__next._full.txt +23 -23
  160. package/dist/web/settings/models/__next._head.txt +4 -4
  161. package/dist/web/settings/models/__next._index.txt +13 -13
  162. package/dist/web/settings/models/__next._tree.txt +2 -2
  163. package/dist/web/settings/models/__next.settings.models.__PAGE__.txt +4 -4
  164. package/dist/web/settings/models/__next.settings.models.txt +3 -3
  165. package/dist/web/settings/models/__next.settings.txt +5 -5
  166. package/dist/web/settings/models.html +1 -1
  167. package/dist/web/settings/models.txt +23 -23
  168. package/dist/web/settings/output-styles/__next._full.txt +23 -23
  169. package/dist/web/settings/output-styles/__next._head.txt +4 -4
  170. package/dist/web/settings/output-styles/__next._index.txt +13 -13
  171. package/dist/web/settings/output-styles/__next._tree.txt +2 -2
  172. package/dist/web/settings/output-styles/__next.settings.output-styles.__PAGE__.txt +4 -4
  173. package/dist/web/settings/output-styles/__next.settings.output-styles.txt +3 -3
  174. package/dist/web/settings/output-styles/__next.settings.txt +5 -5
  175. package/dist/web/settings/output-styles.html +1 -1
  176. package/dist/web/settings/output-styles.txt +23 -23
  177. package/dist/web/settings/prompts/__next._full.txt +23 -23
  178. package/dist/web/settings/prompts/__next._head.txt +4 -4
  179. package/dist/web/settings/prompts/__next._index.txt +13 -13
  180. package/dist/web/settings/prompts/__next._tree.txt +2 -2
  181. package/dist/web/settings/prompts/__next.settings.prompts.__PAGE__.txt +4 -4
  182. package/dist/web/settings/prompts/__next.settings.prompts.txt +3 -3
  183. package/dist/web/settings/prompts/__next.settings.txt +5 -5
  184. package/dist/web/settings/prompts.html +1 -1
  185. package/dist/web/settings/prompts.txt +23 -23
  186. package/dist/web/settings/providers/__next._full.txt +23 -23
  187. package/dist/web/settings/providers/__next._head.txt +4 -4
  188. package/dist/web/settings/providers/__next._index.txt +13 -13
  189. package/dist/web/settings/providers/__next._tree.txt +2 -2
  190. package/dist/web/settings/providers/__next.settings.providers.__PAGE__.txt +4 -4
  191. package/dist/web/settings/providers/__next.settings.providers.txt +3 -3
  192. package/dist/web/settings/providers/__next.settings.txt +5 -5
  193. package/dist/web/settings/providers.html +1 -1
  194. package/dist/web/settings/providers.txt +23 -23
  195. package/dist/web/settings/skills/__next._full.txt +23 -23
  196. package/dist/web/settings/skills/__next._head.txt +4 -4
  197. package/dist/web/settings/skills/__next._index.txt +13 -13
  198. package/dist/web/settings/skills/__next._tree.txt +2 -2
  199. package/dist/web/settings/skills/__next.settings.skills.__PAGE__.txt +4 -4
  200. package/dist/web/settings/skills/__next.settings.skills.txt +3 -3
  201. package/dist/web/settings/skills/__next.settings.txt +5 -5
  202. package/dist/web/settings/skills.html +1 -1
  203. package/dist/web/settings/skills.txt +23 -23
  204. package/dist/web/settings/tools/__next._full.txt +23 -23
  205. package/dist/web/settings/tools/__next._head.txt +4 -4
  206. package/dist/web/settings/tools/__next._index.txt +13 -13
  207. package/dist/web/settings/tools/__next._tree.txt +2 -2
  208. package/dist/web/settings/tools/__next.settings.tools.__PAGE__.txt +4 -4
  209. package/dist/web/settings/tools/__next.settings.tools.txt +3 -3
  210. package/dist/web/settings/tools/__next.settings.txt +5 -5
  211. package/dist/web/settings/tools.html +1 -1
  212. package/dist/web/settings/tools.txt +23 -23
  213. package/dist/web/settings.html +1 -1
  214. package/dist/web/settings.txt +23 -23
  215. package/dist/web/workflows/__next._full.txt +22 -22
  216. package/dist/web/workflows/__next._head.txt +4 -4
  217. package/dist/web/workflows/__next._index.txt +13 -13
  218. package/dist/web/workflows/__next._tree.txt +2 -2
  219. package/dist/web/workflows/__next.workflows.__PAGE__.txt +4 -4
  220. package/dist/web/workflows/__next.workflows.txt +3 -3
  221. package/dist/web/workflows.html +1 -1
  222. package/dist/web/workflows.txt +22 -22
  223. package/dist/web/workspace/_/__next._full.txt +20 -20
  224. package/dist/web/workspace/_/__next._head.txt +4 -4
  225. package/dist/web/workspace/_/__next._index.txt +13 -13
  226. package/dist/web/workspace/_/__next._tree.txt +2 -2
  227. package/dist/web/workspace/_/__next.workspace.$d$id.__PAGE__.txt +3 -3
  228. package/dist/web/workspace/_/__next.workspace.$d$id.txt +3 -3
  229. package/dist/web/workspace/_/__next.workspace.txt +3 -3
  230. package/dist/web/workspace/_.html +1 -1
  231. package/dist/web/workspace/_.txt +20 -20
  232. package/dist/web/workspaces/__next._full.txt +21 -21
  233. package/dist/web/workspaces/__next._head.txt +4 -4
  234. package/dist/web/workspaces/__next._index.txt +13 -13
  235. package/dist/web/workspaces/__next._tree.txt +2 -2
  236. package/dist/web/workspaces/__next.workspaces.__PAGE__.txt +4 -4
  237. package/dist/web/workspaces/__next.workspaces.txt +3 -3
  238. package/dist/web/workspaces.html +1 -1
  239. package/dist/web/workspaces.txt +21 -21
  240. package/dist/ws/agent-prompt.js +36 -3
  241. package/dist/ws/agent-runner.js +30 -18
  242. package/dist/ws/chat-handler.js +89 -0
  243. package/dist/ws/connection-manager.js +49 -2
  244. package/dist/ws/execution-channels.js +88 -0
  245. package/dist/ws/handler.js +32 -5
  246. package/dist/ws/message-parts.js +130 -12
  247. package/dist/ws/terminal-handler.js +26 -0
  248. package/package.json +13 -1
  249. package/public/avatars/user.jpg +0 -0
  250. package/dist/web/_next/static/chunks/0-v_p6j5u3_9l.js +0 -1
  251. package/dist/web/_next/static/chunks/0.-x29t-8gk0r.js +0 -1
  252. package/dist/web/_next/static/chunks/0.l5e8~r7_0~p.js +0 -1
  253. package/dist/web/_next/static/chunks/0.n~yfwf4~6w-.js +0 -1
  254. package/dist/web/_next/static/chunks/00-syqzi-6zxr.js +0 -1
  255. package/dist/web/_next/static/chunks/02j4sr9psucf-.js +0 -1
  256. package/dist/web/_next/static/chunks/06si8l0doqe8p.js +0 -1
  257. package/dist/web/_next/static/chunks/08kfx8on9oty~.js +0 -1
  258. package/dist/web/_next/static/chunks/08ugbvzr20drp.js +0 -2
  259. package/dist/web/_next/static/chunks/0_cqojbge48kq.js +0 -5
  260. package/dist/web/_next/static/chunks/0d6~~lv0-6kex.js +0 -3
  261. package/dist/web/_next/static/chunks/0gdwop9cnpmtu.js +0 -1
  262. package/dist/web/_next/static/chunks/0ghx3j_.-gdyd.js +0 -1
  263. package/dist/web/_next/static/chunks/0kbvoxla7f751.js +0 -1
  264. package/dist/web/_next/static/chunks/0paaat8y96ayc.js +0 -7
  265. package/dist/web/_next/static/chunks/0pq318f8xgafg.js +0 -1
  266. package/dist/web/_next/static/chunks/0t6s8of0qr6nc.js +0 -1
  267. package/dist/web/_next/static/chunks/0xt-8wk21gs7g.js +0 -1
  268. package/dist/web/_next/static/chunks/0yd.m1afqg.2t.js +0 -3
  269. package/dist/web/_next/static/chunks/0yhbr8hl09b-5.js +0 -1
  270. package/dist/web/_next/static/chunks/0z~vqzbm_q371.js +0 -1
  271. package/dist/web/_next/static/chunks/0~~_ltu6dx_ch.js +0 -1
  272. package/dist/web/_next/static/chunks/12oxcgyhpaxw~.js +0 -1
  273. package/dist/web/_next/static/chunks/1452eibz62gs6.css +0 -1
  274. package/dist/web/_next/static/chunks/16zlreiems5cn.js +0 -1
  275. package/dist/web/_next/static/chunks/18awqjk9-o5m0.js +0 -1
  276. /package/dist/web/_next/static/{x4-CsKe6qUQyFDWVtfvUg → rGXyAK8rgod1NjF3bLZAY}/_buildManifest.js +0 -0
  277. /package/dist/web/_next/static/{x4-CsKe6qUQyFDWVtfvUg → rGXyAK8rgod1NjF3bLZAY}/_clientMiddlewareManifest.js +0 -0
  278. /package/dist/web/_next/static/{x4-CsKe6qUQyFDWVtfvUg → rGXyAK8rgod1NjF3bLZAY}/_ssgManifest.js +0 -0
@@ -0,0 +1,207 @@
1
+ import { v4 as uuid } from 'uuid';
2
+ import simpleGit from 'simple-git';
3
+ import { join } from 'node:path';
4
+ import { execFileSync } from 'node:child_process';
5
+ import { getDataDir, ensureDir } from '../storage/json-store.js';
6
+ import { listWorktrees, getWorktree, createWorktree as storeCreate, updateWorktree, } from '../storage/worktree-store.js';
7
+ import { getWorkspace, createWorkspace, deleteWorkspace, } from '../storage/workspace-store.js';
8
+ import { broadcastToWorkspace } from '../ws/connection-manager.js';
9
+ import { runPullRequestAgent } from '../agents/pull-request-agent.js';
10
+ function worktreesBaseDir(workspaceId) {
11
+ return join(getDataDir(), 'workspaces', workspaceId, 'worktrees');
12
+ }
13
+ export function listWorkspaceWorktrees(workspaceId) {
14
+ return listWorktrees(workspaceId).filter(wt => wt.status === 'active');
15
+ }
16
+ export function getWorkspaceWorktree(workspaceId, worktreeId) {
17
+ return getWorktree(workspaceId, worktreeId);
18
+ }
19
+ export async function createWorkspaceWorktree(workspaceId, input) {
20
+ const ws = getWorkspace(workspaceId);
21
+ if (!ws)
22
+ throw new Error('Workspace not found');
23
+ const id = uuid();
24
+ let branch = input.branch || `${input.name}-${Date.now()}`;
25
+ const wtPath = join(worktreesBaseDir(workspaceId), id);
26
+ ensureDir(join(worktreesBaseDir(workspaceId)));
27
+ const git = simpleGit(ws.boundDirs[0]);
28
+ // Auto-resolve branch name conflicts
29
+ const branches = await git.branch();
30
+ let suffix = 1;
31
+ const baseBranch = branch;
32
+ while (branches.all.includes(branch)) {
33
+ suffix++;
34
+ branch = `${baseBranch}-${suffix}`;
35
+ }
36
+ await git.raw(['worktree', 'add', wtPath, '-b', branch]);
37
+ const now = new Date().toISOString();
38
+ const info = {
39
+ id, workspaceId, name: input.name, branch, path: wtPath,
40
+ agentId: input.agentId, issueId: input.issueId, taskId: input.taskId,
41
+ status: 'active', createdAt: now, updatedAt: now,
42
+ };
43
+ storeCreate(workspaceId, info);
44
+ // Write virtual workspace.json so getWorkspace(wtId) resolves for all sub-routes
45
+ const virtualWs = {
46
+ id, name: `${input.name} (Worktree)`, boundDirs: [wtPath],
47
+ agentspaceDir: join(wtPath, '.agentspace'),
48
+ isWorktree: true, parentWorkspaceId: workspaceId,
49
+ createdAt: now, updatedAt: now, activeChannels: [], activeIssues: [],
50
+ };
51
+ createWorkspace(virtualWs);
52
+ broadcastToWorkspace(workspaceId, 'worktree.created', info);
53
+ return info;
54
+ }
55
+ export async function deleteWorkspaceWorktree(workspaceId, worktreeId) {
56
+ const info = getWorktree(workspaceId, worktreeId);
57
+ if (!info)
58
+ throw new Error('Worktree not found');
59
+ const ws = getWorkspace(workspaceId);
60
+ if (!ws)
61
+ throw new Error('Workspace not found');
62
+ const git = simpleGit(ws.boundDirs[0]);
63
+ await git.raw(['worktree', 'remove', info.path, '--force']).catch(() => { });
64
+ // Clean up virtual workspace entry.
65
+ deleteWorkspace(worktreeId);
66
+ info.status = 'deleted';
67
+ info.updatedAt = new Date().toISOString();
68
+ updateWorktree(workspaceId, info);
69
+ broadcastToWorkspace(workspaceId, 'worktree.deleted', { id: worktreeId, workspaceId });
70
+ }
71
+ export async function getWorktreeDiff(workspaceId, worktreeId) {
72
+ const info = getWorktree(workspaceId, worktreeId);
73
+ if (!info)
74
+ throw new Error('Worktree not found');
75
+ const ws = getWorkspace(workspaceId);
76
+ if (!ws)
77
+ throw new Error('Workspace not found');
78
+ const git = simpleGit(ws.boundDirs[0]);
79
+ const defaultBranch = await getDefaultBranch(git);
80
+ const nameOnlyRaw = await git.diff(['--name-only', `${defaultBranch}...${info.branch}`]);
81
+ const files = nameOnlyRaw.split('\n').filter(Boolean);
82
+ const diffs = [];
83
+ for (const f of files) {
84
+ const binary = isBinaryPath(f);
85
+ const oldContent = binary ? '' : await git.show([`${defaultBranch}:${f}`]).catch(() => '');
86
+ const newContent = binary ? '' : await git.show([`${info.branch}:${f}`]).catch(() => '');
87
+ diffs.push({ path: f, oldContent, newContent, isBinary: binary, isNew: !oldContent, isDeleted: !newContent });
88
+ }
89
+ return diffs;
90
+ }
91
+ export async function createWorktreePR(workspaceId, worktreeId, title, body) {
92
+ const info = getWorktree(workspaceId, worktreeId);
93
+ if (!info)
94
+ throw new Error('Worktree not found');
95
+ const ws = getWorkspace(workspaceId);
96
+ if (!ws)
97
+ throw new Error('Workspace not found');
98
+ const git = simpleGit(ws.boundDirs[0]);
99
+ const defaultBranch = await getDefaultBranch(git);
100
+ const log = await git.log([`${defaultBranch}..${info.branch}`]);
101
+ if (log.total === 0) {
102
+ throw new Error('Cannot create PR: no commits on this branch. Make changes and commit first.');
103
+ }
104
+ try {
105
+ await git.push('origin', info.branch, ['--set-upstream']);
106
+ }
107
+ catch (e) {
108
+ const msg = e?.stderr || e?.message || String(e);
109
+ throw new Error(`Failed to push branch before creating PR: ${msg.replace(/^(Command failed: )?git\s*/, '').trim()}`);
110
+ }
111
+ const prTitle = title || `[${info.name}] ${info.branch}`;
112
+ const ghArgs = [
113
+ 'pr', 'create',
114
+ '--base', defaultBranch,
115
+ '--head', info.branch,
116
+ '--title', prTitle,
117
+ '--body', body || '',
118
+ ];
119
+ let result;
120
+ try {
121
+ result = execFileSync('gh', ghArgs, { cwd: ws.boundDirs[0], encoding: 'utf-8' });
122
+ }
123
+ catch (e) {
124
+ const msg = e?.stderr || e?.message || String(e);
125
+ throw new Error(`Failed to create PR: ${msg.replace(/^(Command failed: )?gh\s*/, '').trim()}`);
126
+ }
127
+ const urlMatch = result.match(/https:\/\/[^\s]+/);
128
+ if (!urlMatch)
129
+ throw new Error('PR created but failed to parse URL from output');
130
+ info.prUrl = urlMatch[0];
131
+ info.updatedAt = new Date().toISOString();
132
+ updateWorktree(workspaceId, info);
133
+ broadcastToWorkspace(workspaceId, 'worktree.pr_created', info);
134
+ return info.prUrl;
135
+ }
136
+ export async function getWorktreePRDraft(workspaceId, worktreeId, title) {
137
+ const info = getWorktree(workspaceId, worktreeId);
138
+ if (!info)
139
+ throw new Error('Worktree not found');
140
+ const ws = getWorkspace(workspaceId);
141
+ if (!ws)
142
+ throw new Error('Workspace not found');
143
+ const git = simpleGit(ws.boundDirs[0]);
144
+ const defaultBranch = await getDefaultBranch(git);
145
+ const commits = await git.log([`${defaultBranch}..${info.branch}`])
146
+ .then((log) => log.all.map((entry) => entry.message));
147
+ const diff = await git.diff([`${defaultBranch}...${info.branch}`]);
148
+ const body = await runPullRequestAgent(workspaceId, {
149
+ worktree: info,
150
+ baseBranch: defaultBranch,
151
+ commits,
152
+ diff,
153
+ });
154
+ return {
155
+ title: title || `[${info.name}] ${info.branch}`,
156
+ body,
157
+ baseBranch: defaultBranch,
158
+ };
159
+ }
160
+ export async function mergeWorktreePR(workspaceId, worktreeId) {
161
+ const info = getWorktree(workspaceId, worktreeId);
162
+ if (!info)
163
+ throw new Error('Worktree not found');
164
+ if (!info.prUrl)
165
+ throw new Error('No PR associated with this worktree');
166
+ const ws = getWorkspace(workspaceId);
167
+ if (!ws)
168
+ throw new Error('Workspace not found');
169
+ const git = simpleGit(ws.boundDirs[0]);
170
+ try {
171
+ execFileSync('gh', ['pr', 'merge', info.prUrl, '--merge'], { cwd: ws.boundDirs[0], encoding: 'utf-8' });
172
+ }
173
+ catch (e) {
174
+ const msg = e?.stderr || e?.message || String(e);
175
+ throw new Error(`Failed to merge PR: ${msg.replace(/^(Command failed: )?gh\s*/, '').trim()}`);
176
+ }
177
+ await git.raw(['worktree', 'remove', info.path]).catch(() => { });
178
+ await git.raw(['branch', '-d', info.branch]).catch(() => { });
179
+ // Clean up virtual workspace entry.
180
+ deleteWorkspace(worktreeId);
181
+ info.status = 'merged';
182
+ info.updatedAt = new Date().toISOString();
183
+ updateWorktree(workspaceId, info);
184
+ broadcastToWorkspace(workspaceId, 'worktree.merged', info);
185
+ }
186
+ const BINARY_EXTS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.ico', '.webp', '.avif', '.mp3', '.mp4', '.zip', '.gz', '.tar', '.woff', '.woff2', '.ttf', '.eot', '.pdf', '.wasm']);
187
+ function isBinaryPath(filePath) {
188
+ const ext = filePath.slice(filePath.lastIndexOf('.')).toLowerCase();
189
+ return BINARY_EXTS.has(ext);
190
+ }
191
+ async function getDefaultBranch(git) {
192
+ try {
193
+ const result = await git.raw(['symbolic-ref', 'refs/remotes/origin/HEAD']);
194
+ const match = result.match(/refs\/remotes\/origin\/(.+)/);
195
+ if (match)
196
+ return match[1].trim();
197
+ }
198
+ catch { }
199
+ // Fallback: try common names
200
+ const branches = await git.branch();
201
+ if (branches.all.includes('main'))
202
+ return 'main';
203
+ if (branches.all.includes('master'))
204
+ return 'master';
205
+ return 'main';
206
+ }
207
+ //# sourceMappingURL=worktree.js.map
@@ -149,6 +149,7 @@ export function getAgentUsageDashboard(days = 30) {
149
149
  dailyMap.set(key, {
150
150
  date: key,
151
151
  label: date.toLocaleDateString('en-US', { weekday: 'short' }),
152
+ requests: 0,
152
153
  inputTokens: 0,
153
154
  outputTokens: 0,
154
155
  totalTokens: 0,
@@ -161,6 +162,7 @@ export function getAgentUsageDashboard(days = 30) {
161
162
  for (const record of records) {
162
163
  const day = dailyMap.get(record.completedAt.slice(0, 10));
163
164
  if (day) {
165
+ day.requests += 1;
164
166
  day.inputTokens += record.inputTokens + record.cachedInputTokens;
165
167
  day.outputTokens += record.outputTokens + record.reasoningTokens;
166
168
  day.totalTokens += record.totalTokens;
@@ -323,4 +325,10 @@ function findConfiguredModelCost(model) {
323
325
  outputPerMillion: toMoney(configured.cost.outputPerMillion),
324
326
  };
325
327
  }
328
+ export function closeDb() {
329
+ if (db) {
330
+ db.close();
331
+ db = null;
332
+ }
333
+ }
326
334
  //# sourceMappingURL=agent-store.js.map
@@ -0,0 +1,151 @@
1
+ import { getDataDir, ensureDir, readJsonFile, writeJsonFile, deleteFile } from './json-store.js';
2
+ import path from 'node:path';
3
+ import { existsSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
4
+ function chatDir() {
5
+ return path.join(getDataDir(), 'chat');
6
+ }
7
+ function chatTemplatesDir() {
8
+ return path.join(getDataDir(), 'chat-templates');
9
+ }
10
+ export function agentDir(agentId) {
11
+ return path.join(chatTemplatesDir(), agentId);
12
+ }
13
+ function agentFile(agentId) {
14
+ return path.join(agentDir(agentId), 'agent.json');
15
+ }
16
+ function mcpFile(agentId) {
17
+ return path.join(agentDir(agentId), 'mcp.json');
18
+ }
19
+ function skillsDir(agentId) {
20
+ return path.join(agentDir(agentId), 'skills');
21
+ }
22
+ export function chatSessionDir(chatId) {
23
+ return path.join(chatDir(), chatId);
24
+ }
25
+ export function chatWorkspaceDir(chatId) {
26
+ return path.join(chatSessionDir(chatId), 'workspaces');
27
+ }
28
+ function chatWorkspaceSkillsDir(chatId) {
29
+ return path.join(chatWorkspaceDir(chatId), 'skills');
30
+ }
31
+ export function messageHistoryDir(agentId) {
32
+ return chatSessionDir(agentId);
33
+ }
34
+ function messagesFile(chatId) {
35
+ return path.join(chatSessionDir(chatId), 'messages.json');
36
+ }
37
+ // --- Agent functions ---
38
+ export function listAgents() {
39
+ ensureDir(chatTemplatesDir());
40
+ return readdirSync(chatTemplatesDir(), { withFileTypes: true })
41
+ .filter(entry => entry.isDirectory())
42
+ .flatMap(entry => {
43
+ const agent = readJsonFile(agentFile(entry.name));
44
+ return agent ? [agent] : [];
45
+ })
46
+ .sort((a, b) => a.createdAt.localeCompare(b.createdAt));
47
+ }
48
+ export function saveAgent(agent, skillInputs) {
49
+ const dir = agentDir(agent.id);
50
+ ensureDir(dir);
51
+ ensureDir(skillsDir(agent.id));
52
+ ensureDir(chatWorkspaceDir(agent.id));
53
+ ensureDir(chatWorkspaceSkillsDir(agent.id));
54
+ writeJsonFile(agentFile(agent.id), agent);
55
+ writeJsonFile(mcpFile(agent.id), agent.mcps ?? {});
56
+ writeSkills(agent.id, skillInputs, agent.skills ?? []);
57
+ }
58
+ export function findAgent(id) {
59
+ return readJsonFile(agentFile(id)) ?? undefined;
60
+ }
61
+ export function deleteAgent(id) {
62
+ rmSync(agentDir(id), { recursive: true, force: true });
63
+ rmSync(chatSessionDir(id), { recursive: true, force: true });
64
+ }
65
+ // --- Message functions ---
66
+ export function listMessages(agentId, limit, before) {
67
+ ensureDir(chatSessionDir(agentId));
68
+ let messages = readJsonFile(messagesFile(agentId)) ?? [];
69
+ messages = messages.filter(msg => msg.agentId === agentId);
70
+ // Sort descending by timestamp
71
+ messages.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
72
+ // Cursor pagination: skip messages at or after 'before' timestamp
73
+ if (before) {
74
+ const idx = messages.findIndex(m => m.timestamp <= before);
75
+ if (idx === -1) {
76
+ messages = [];
77
+ }
78
+ else {
79
+ messages = messages.slice(idx);
80
+ }
81
+ }
82
+ // Apply limit
83
+ if (limit && limit > 0) {
84
+ messages = messages.slice(0, limit);
85
+ }
86
+ // Return ascending order
87
+ messages.reverse();
88
+ return messages;
89
+ }
90
+ export function saveMessage(msg) {
91
+ const messages = readJsonFile(messagesFile(msg.agentId)) ?? [];
92
+ messages.push(msg);
93
+ writeJsonFile(messagesFile(msg.agentId), messages);
94
+ }
95
+ export function deleteMessagesByAgent(agentId) {
96
+ deleteFile(messagesFile(agentId));
97
+ }
98
+ export function getRecentMessages(agentId, limit = 50) {
99
+ return listMessages(agentId, limit);
100
+ }
101
+ function writeSkills(agentId, skillInputs, skillNames) {
102
+ const dir = skillsDir(agentId);
103
+ if (skillInputs?.some(skill => typeof skill !== 'string')) {
104
+ rmSync(dir, { recursive: true, force: true });
105
+ ensureDir(dir);
106
+ for (const skill of skillInputs) {
107
+ if (typeof skill === 'string' || !skill.name.trim())
108
+ continue;
109
+ const filename = sanitizeMarkdownFilename(skill.name);
110
+ const content = skill.content ?? readSkillContent(skill.name) ?? '';
111
+ writeJsonSkillFile(path.join(dir, filename), content);
112
+ writeJsonSkillFile(path.join(chatWorkspaceSkillsDir(agentId), filename), content);
113
+ }
114
+ return;
115
+ }
116
+ for (const name of skillNames.map(skill => typeof skill === 'string' ? skill : skill.name)) {
117
+ const filename = sanitizeMarkdownFilename(name);
118
+ const content = readSkillContent(name) ?? '';
119
+ const filePath = path.join(dir, filename);
120
+ if (content || !existsSync(filePath))
121
+ writeJsonSkillFile(filePath, content);
122
+ const workspaceSkillPath = path.join(chatWorkspaceSkillsDir(agentId), filename);
123
+ if (content || !existsSync(workspaceSkillPath))
124
+ writeJsonSkillFile(workspaceSkillPath, content);
125
+ }
126
+ }
127
+ function writeJsonSkillFile(filePath, content) {
128
+ ensureDir(path.dirname(filePath));
129
+ writeFileSync(filePath, content, 'utf-8');
130
+ }
131
+ function sanitizeMarkdownFilename(name) {
132
+ const base = name.trim().replace(/[/\\:*?"<>|]+/g, '-');
133
+ return base.toLowerCase().endsWith('.md') ? base : `${base}.md`;
134
+ }
135
+ function readSkillContent(name) {
136
+ const skillName = name.trim().replace(/\.md$/i, '');
137
+ if (!skillName)
138
+ return undefined;
139
+ const candidates = [
140
+ path.join(getDataDir(), 'skills', skillName, 'SKILL.md'),
141
+ path.join(getDataDir(), 'skills', `${skillName}.md`),
142
+ path.join(process.cwd(), 'skills', skillName, 'SKILL.md'),
143
+ path.join(process.cwd(), 'skills', `${skillName}.md`),
144
+ ];
145
+ const source = candidates.find(file => existsSync(file));
146
+ if (!source)
147
+ return undefined;
148
+ const content = readFileSync(source, 'utf-8');
149
+ return content.trim() ? content : undefined;
150
+ }
151
+ //# sourceMappingURL=chat-store.js.map
@@ -362,4 +362,10 @@ export function listDatabaseEmbeddings(workspaceId, databaseId) {
362
362
  embedding: JSON.parse(row.embedding),
363
363
  }));
364
364
  }
365
+ export function closeDb() {
366
+ if (db) {
367
+ db.close();
368
+ db = null;
369
+ }
370
+ }
365
371
  //# sourceMappingURL=database-store.js.map
@@ -1,6 +1,7 @@
1
1
  import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync } from 'node:fs';
2
2
  import { join, dirname } from 'node:path';
3
- const DEFAULT_DATA_DIR = join(process.env.HOME || '~', '.agent-spaces-data');
3
+ import { homedir } from 'node:os';
4
+ const DEFAULT_DATA_DIR = join(process.env.HOME || process.env.USERPROFILE || homedir(), '.agent-spaces-data');
4
5
  export function getDataDir() {
5
6
  return process.env.AGENT_SPACES_DATA_DIR || DEFAULT_DATA_DIR;
6
7
  }
@@ -139,4 +139,10 @@ export function saveTasks(boardId, tasks) {
139
139
  }
140
140
  database.prepare('UPDATE kanban_boards SET updated_at = ? WHERE id = ?').run(Date.now(), boardId);
141
141
  }
142
+ export function closeDb() {
143
+ if (db) {
144
+ db.close();
145
+ db = null;
146
+ }
147
+ }
142
148
  //# sourceMappingURL=kanban-store.js.map