@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
@@ -11,7 +11,13 @@ import { extractUsageFromOutput } from '../storage/usage.js';
11
11
  const DEFAULT_AGENT_ROLE = 'agent';
12
12
  export const AGENT_GENERATOR_PRESET_ID = 'agent-generator';
13
13
  export const AGENT_COMMIT_PRESET_ID = 'commit-agent';
14
- const VALID_RUNTIME_KINDS = ['open-agent-sdk', 'claude-code', 'codex', 'langchain'];
14
+ export const AGENT_TITLE_GENERATOR_PRESET_ID = 'title-generator';
15
+ const BUILT_IN_AGENT_IDS = [
16
+ AGENT_GENERATOR_PRESET_ID,
17
+ AGENT_COMMIT_PRESET_ID,
18
+ AGENT_TITLE_GENERATOR_PRESET_ID,
19
+ ];
20
+ const VALID_RUNTIME_KINDS = ['open-agent-sdk', 'claude-code', 'codex', 'langchain', 'hermes', 'oh-my-pi'];
15
21
  const VALID_TOOL_NAMES = new Set(BUILT_IN_AGENT_TOOLS.map((tool) => tool.name));
16
22
  const CLAUDE_BUILT_IN_DIRS = ['agents', 'commands'];
17
23
  const ANTHROPIC_BRIDGE_PROVIDERS = [
@@ -27,18 +33,12 @@ export function isValidRole(role) {
27
33
  export function listTemplates() {
28
34
  const root = getGlobalAgentTemplatesDir();
29
35
  if (!existsSync(root))
30
- return [getDefaultAgentGeneratorPreset(), getDefaultCommitAgentPreset()];
36
+ return getDefaultBuiltInAgentPresets();
31
37
  const templates = readdirSync(root, { withFileTypes: true })
32
38
  .filter((entry) => entry.isDirectory())
33
39
  .map((entry) => readAgentTemplate(entry.name))
34
40
  .filter((template) => Boolean(template));
35
- if (!templates.some((template) => template.id === AGENT_GENERATOR_PRESET_ID)) {
36
- templates.unshift(getDefaultAgentGeneratorPreset());
37
- }
38
- if (!templates.some((template) => template.id === AGENT_COMMIT_PRESET_ID)) {
39
- templates.unshift(getDefaultCommitAgentPreset());
40
- }
41
- return templates;
41
+ return withBuiltInTemplatesFirst(templates);
42
42
  }
43
43
  export async function testConnection(workspaceId, data) {
44
44
  if (workspaceId) {
@@ -279,8 +279,11 @@ export function createPreset(_workspaceId, data) {
279
279
  skills: normalizeSkillNames(data.skills),
280
280
  tools: normalizeToolNames(data.tools ?? BUILT_IN_AGENT_TOOLS.map((tool) => tool.name)),
281
281
  systemPrompt: data.systemPrompt || '',
282
+ outputStyle: data.outputStyle,
282
283
  temperature: data.temperature ?? 0.3,
283
284
  maxTokens: data.maxTokens ?? 4096,
285
+ avatarUrl: data.avatarUrl,
286
+ icon: data.icon,
284
287
  sandboxDirs: data.sandboxDirs,
285
288
  maxRetries: data.maxRetries,
286
289
  templateId: data.templateId,
@@ -316,12 +319,8 @@ export function updatePreset(_workspaceId, presetId, data) {
316
319
  return updated;
317
320
  }
318
321
  export function getAllowedTools(mcps) {
319
- if (!mcps)
320
- return undefined;
321
- const servers = mcps.mcpServers;
322
- if (!servers || typeof servers !== 'object' || Array.isArray(servers))
323
- return undefined;
324
- return Object.keys(servers);
322
+ const servers = getMcpServers(mcps);
323
+ return servers ? Object.keys(servers) : undefined;
325
324
  }
326
325
  export function getMcpServers(mcps) {
327
326
  if (!mcps)
@@ -329,7 +328,11 @@ export function getMcpServers(mcps) {
329
328
  const servers = mcps.mcpServers;
330
329
  if (!servers || typeof servers !== 'object' || Array.isArray(servers))
331
330
  return undefined;
332
- return servers;
331
+ const resolved = Object.fromEntries(Object.entries(servers).flatMap(([name, server]) => {
332
+ const config = getRunnableMcpServerConfig(server) ?? readStoredMcpServerConfig(name);
333
+ return config ? [[name, config]] : [];
334
+ }));
335
+ return Object.keys(resolved).length > 0 ? resolved : undefined;
333
336
  }
334
337
  export function getAgentConfigDir(workspaceId, preset) {
335
338
  const ws = getWorkspace(workspaceId);
@@ -362,13 +365,13 @@ export function getAvailableSkillNames(agentDir, skills) {
362
365
  if (!skill)
363
366
  return false;
364
367
  const skillsBase = join(agentDir, 'skills');
365
- // Check folder structure first, then flat .md
366
- const skillFolder = join(skillsBase, skill);
367
- if (existsSync(skillFolder) && statSync(skillFolder).isDirectory()) {
368
- return readdirSync(skillFolder).some((f) => f.endsWith('.md'));
369
- }
370
- const skillFile = join(skillsBase, `${skill}.md`);
371
- return existsSync(skillFile) && statSync(skillFile).size > 0;
368
+ if (hasReadableSkillSource(skillsBase, skill))
369
+ return true;
370
+ const globalSkillFile = join(getDataDir(), 'skills', skill, 'SKILL.md');
371
+ if (existsSync(globalSkillFile) && statSync(globalSkillFile).size > 0)
372
+ return true;
373
+ const globalLegacySkillFile = join(getDataDir(), 'skills', `${skill}.md`);
374
+ return existsSync(globalLegacySkillFile) && statSync(globalLegacySkillFile).size > 0;
372
375
  });
373
376
  }
374
377
  export function resolveWorkingDir(workspaceId, preset) {
@@ -423,6 +426,31 @@ function normalizeMcpConfig(mcps) {
423
426
  return {};
424
427
  return mcps;
425
428
  }
429
+ function getRunnableMcpServerConfig(server) {
430
+ if (!server || typeof server !== 'object' || Array.isArray(server))
431
+ return null;
432
+ const record = server;
433
+ if (typeof record.command === 'string' && record.command.trim())
434
+ return record;
435
+ if (typeof record.url === 'string' && record.url.trim())
436
+ return record;
437
+ return null;
438
+ }
439
+ function readStoredMcpServerConfig(name) {
440
+ const filePath = join(getDataDir(), 'mcps', `${sanitizeMcpName(name)}.json`);
441
+ if (!existsSync(filePath))
442
+ return null;
443
+ try {
444
+ const parsed = JSON.parse(readFileSync(filePath, 'utf-8'));
445
+ return getRunnableMcpServerConfig(parsed.config);
446
+ }
447
+ catch {
448
+ return null;
449
+ }
450
+ }
451
+ function sanitizeMcpName(name) {
452
+ return name.replace(/[^a-zA-Z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || 'mcp-server';
453
+ }
426
454
  function normalizeModelProvider(provider) {
427
455
  return provider || undefined;
428
456
  }
@@ -565,10 +593,24 @@ function ensureWorkspaceAgentCopy(preset, agentspaceDir) {
565
593
  && statSync(sourceBuiltInDir).isDirectory()
566
594
  && countFiles(sourceBuiltInDir) > countFiles(targetBuiltInDir);
567
595
  });
568
- if (!missingRequiredFile && !missingBuiltInDir)
596
+ const missingSkill = (preset.skills ?? []).some((skill) => {
597
+ const skillName = skill.replace(/\.md$/i, '');
598
+ const targetSkillsDir = join(workspaceAgentDir, 'skills');
599
+ return !hasReadableSkillSource(targetSkillsDir, skillName);
600
+ });
601
+ if (!missingRequiredFile && !missingBuiltInDir && !missingSkill)
569
602
  return;
570
603
  writeWorkspaceAgentCopy(preset, agentspaceDir);
571
604
  }
605
+ function hasReadableSkillSource(skillsDir, skillName) {
606
+ const skillDir = join(skillsDir, skillName);
607
+ const skillFile = join(skillDir, 'SKILL.md');
608
+ if (existsSync(skillDir) && statSync(skillDir).isDirectory()) {
609
+ return existsSync(skillFile) && statSync(skillFile).size > 0;
610
+ }
611
+ const legacySkillFile = join(skillsDir, `${skillName}.md`);
612
+ return existsSync(legacySkillFile) && statSync(legacySkillFile).size > 0;
613
+ }
572
614
  function countFiles(dir) {
573
615
  if (!existsSync(dir) || !statSync(dir).isDirectory())
574
616
  return 0;
@@ -582,19 +624,37 @@ function countFiles(dir) {
582
624
  export function readAgentTemplate(agentId) {
583
625
  const filePath = join(getGlobalAgentTemplateDir(agentId), 'agent.json');
584
626
  if (!existsSync(filePath)) {
585
- return agentId === AGENT_GENERATOR_PRESET_ID ? getDefaultAgentGeneratorPreset()
586
- : agentId === AGENT_COMMIT_PRESET_ID ? getDefaultCommitAgentPreset()
587
- : null;
627
+ return getDefaultBuiltInAgentPreset(agentId);
588
628
  }
589
629
  try {
590
630
  return JSON.parse(readFileSync(filePath, 'utf-8'));
591
631
  }
592
632
  catch {
593
- return agentId === AGENT_GENERATOR_PRESET_ID ? getDefaultAgentGeneratorPreset()
594
- : agentId === AGENT_COMMIT_PRESET_ID ? getDefaultCommitAgentPreset()
595
- : null;
633
+ return getDefaultBuiltInAgentPreset(agentId);
596
634
  }
597
635
  }
636
+ function getDefaultBuiltInAgentPresets() {
637
+ return [
638
+ getDefaultAgentGeneratorPreset(),
639
+ getDefaultCommitAgentPreset(),
640
+ getDefaultTitleGeneratorPreset(),
641
+ ];
642
+ }
643
+ function getDefaultBuiltInAgentPreset(agentId) {
644
+ if (agentId === AGENT_GENERATOR_PRESET_ID)
645
+ return getDefaultAgentGeneratorPreset();
646
+ if (agentId === AGENT_COMMIT_PRESET_ID)
647
+ return getDefaultCommitAgentPreset();
648
+ if (agentId === AGENT_TITLE_GENERATOR_PRESET_ID)
649
+ return getDefaultTitleGeneratorPreset();
650
+ return null;
651
+ }
652
+ function withBuiltInTemplatesFirst(templates) {
653
+ const byId = new Map(templates.map((template) => [template.id, template]));
654
+ const builtIns = getDefaultBuiltInAgentPresets().map((preset) => byId.get(preset.id) ?? preset);
655
+ const custom = templates.filter((template) => !BUILT_IN_AGENT_IDS.includes(template.id));
656
+ return [...builtIns, ...custom];
657
+ }
598
658
  function getDefaultAgentGeneratorPreset() {
599
659
  return {
600
660
  id: AGENT_GENERATOR_PRESET_ID,
@@ -658,15 +718,44 @@ export function getDefaultCommitAgentPreset() {
658
718
  enabled: true,
659
719
  };
660
720
  }
721
+ export function getDefaultTitleGeneratorPreset() {
722
+ return {
723
+ id: AGENT_TITLE_GENERATOR_PRESET_ID,
724
+ name: 'Title Generator',
725
+ role: 'agent',
726
+ description: 'Generate short titles for channels and issues from user requirements.',
727
+ runtimeKind: 'claude-code',
728
+ modelProvider: undefined,
729
+ modelId: '',
730
+ apiBase: '',
731
+ apiKey: '',
732
+ workingDir: '',
733
+ mcps: {},
734
+ skills: [],
735
+ tools: [],
736
+ systemPrompt: [
737
+ 'You generate objective scene titles for Agent Spaces channels and issues.',
738
+ 'Return exactly one title and nothing else.',
739
+ 'The title must describe the scenario, task, or intent objectively.',
740
+ 'Do not include a speaking subject, assistant identity, user identity, first-person wording, second-person wording, greetings, replies, questions, or conversational text.',
741
+ 'For Chinese, prefer a short noun phrase ending with 场景, 任务, 问题, 需求, 讨论, or 分析 when appropriate.',
742
+ 'Examples: user says "你好" -> "打招呼场景"; user says "帮我修复登录报错" -> "登录报错修复"; user says "分析这段代码" -> "代码分析任务".',
743
+ 'Use the same language as the user request when it is clear.',
744
+ 'Keep the title under 20 Chinese characters or under 8 English words.',
745
+ 'Do not use quotes, markdown, punctuation-only endings, prefixes, explanations, or multiple options.',
746
+ ].join(' '),
747
+ temperature: 0.2,
748
+ maxTokens: 64,
749
+ enabled: true,
750
+ };
751
+ }
661
752
  function sanitizeMarkdownFilename(name) {
662
753
  const raw = basename(name).replace(/\.md$/i, '');
663
754
  const safe = raw.replace(/[^a-zA-Z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || 'skill';
664
755
  return `${safe}.md`;
665
756
  }
666
757
  export function deletePreset(workspaceId, presetId) {
667
- if (presetId === AGENT_GENERATOR_PRESET_ID)
668
- return false;
669
- if (presetId === AGENT_COMMIT_PRESET_ID)
758
+ if (BUILT_IN_AGENT_IDS.includes(presetId))
670
759
  return false;
671
760
  const ws = getWorkspace(workspaceId);
672
761
  if (!ws)
@@ -755,9 +844,7 @@ export function updateGlobalPreset(presetId, data) {
755
844
  return updated;
756
845
  }
757
846
  export function deleteGlobalPreset(presetId) {
758
- if (presetId === AGENT_GENERATOR_PRESET_ID)
759
- return false;
760
- if (presetId === AGENT_COMMIT_PRESET_ID)
847
+ if (BUILT_IN_AGENT_IDS.includes(presetId))
761
848
  return false;
762
849
  const templateDir = getGlobalAgentTemplateDir(presetId);
763
850
  if (!existsSync(templateDir))
@@ -0,0 +1,185 @@
1
+ export async function requestAiText(config, input) {
2
+ const provider = config.modelProvider ?? inferProvider(config.apiBase);
3
+ if (provider === 'anthropic-messages')
4
+ return requestAnthropic(config, input.systemPrompt, input.userPrompt);
5
+ if (provider === 'gemini-generate-content')
6
+ return requestGemini(config, input.systemPrompt, input.userPrompt);
7
+ return requestOpenAICompatible(config, input.systemPrompt, input.userPrompt, provider === 'openai-responses' || provider === 'openai-responses-to-anthropic-messages');
8
+ }
9
+ export function maskAiTextUrl(url) {
10
+ if (!url)
11
+ return undefined;
12
+ try {
13
+ const parsed = new URL(url);
14
+ return `${parsed.origin}${parsed.pathname}`;
15
+ }
16
+ catch {
17
+ return url.slice(0, 80);
18
+ }
19
+ }
20
+ async function requestOpenAICompatible(config, systemPrompt, userPrompt, useResponsesApi) {
21
+ const response = await fetch(joinUrl(config.apiBase, useResponsesApi ? '/responses' : '/chat/completions'), {
22
+ method: 'POST',
23
+ headers: {
24
+ Authorization: `Bearer ${config.apiKey}`,
25
+ 'Content-Type': 'application/json',
26
+ },
27
+ body: JSON.stringify(useResponsesApi
28
+ ? {
29
+ model: config.modelId,
30
+ input: `${systemPrompt}\n\n${userPrompt}`,
31
+ temperature: config.temperature ?? 0.2,
32
+ max_output_tokens: config.maxTokens ?? 1024,
33
+ }
34
+ : {
35
+ model: config.modelId,
36
+ messages: [
37
+ { role: 'system', content: systemPrompt },
38
+ { role: 'user', content: userPrompt },
39
+ ],
40
+ temperature: config.temperature ?? 0.2,
41
+ max_tokens: config.maxTokens ?? 1024,
42
+ }),
43
+ });
44
+ const body = await readResponseBody(response);
45
+ if (!response.ok || body.error)
46
+ throw new Error(body.error || `AI text request failed with status ${response.status}`);
47
+ return body.text;
48
+ }
49
+ async function requestAnthropic(config, systemPrompt, userPrompt) {
50
+ const response = await fetch(getAnthropicMessagesUrl(config.apiBase), {
51
+ method: 'POST',
52
+ headers: {
53
+ 'x-api-key': config.apiKey,
54
+ 'anthropic-version': '2023-06-01',
55
+ 'Content-Type': 'application/json',
56
+ },
57
+ body: JSON.stringify({
58
+ model: config.modelId,
59
+ system: systemPrompt,
60
+ messages: [{ role: 'user', content: userPrompt }],
61
+ max_tokens: config.maxTokens ?? 1024,
62
+ temperature: config.temperature ?? 0.2,
63
+ }),
64
+ });
65
+ const body = await readResponseBody(response);
66
+ if (!response.ok || body.error)
67
+ throw new Error(body.error || `AI text request failed with status ${response.status}`);
68
+ return body.text;
69
+ }
70
+ async function requestGemini(config, systemPrompt, userPrompt) {
71
+ const response = await fetch(joinUrl(config.apiBase, `/models/${encodeURIComponent(config.modelId)}:generateContent`), {
72
+ method: 'POST',
73
+ headers: {
74
+ 'x-goog-api-key': config.apiKey,
75
+ 'Content-Type': 'application/json',
76
+ },
77
+ body: JSON.stringify({
78
+ systemInstruction: { parts: [{ text: systemPrompt }] },
79
+ contents: [{ role: 'user', parts: [{ text: userPrompt }] }],
80
+ generationConfig: {
81
+ temperature: config.temperature ?? 0.2,
82
+ maxOutputTokens: config.maxTokens ?? 1024,
83
+ },
84
+ }),
85
+ });
86
+ const body = await readResponseBody(response);
87
+ if (!response.ok || body.error)
88
+ throw new Error(body.error || `AI text request failed with status ${response.status}`);
89
+ return body.text;
90
+ }
91
+ async function readResponseBody(response) {
92
+ const raw = await response.text();
93
+ if (!raw)
94
+ return { text: '' };
95
+ try {
96
+ const json = JSON.parse(raw);
97
+ return {
98
+ text: extractText(json),
99
+ error: extractError(json),
100
+ };
101
+ }
102
+ catch {
103
+ return { text: raw };
104
+ }
105
+ }
106
+ function extractText(json) {
107
+ const outputText = json.output_text;
108
+ if (typeof outputText === 'string')
109
+ return outputText;
110
+ const output = Array.isArray(json.output) ? json.output : [];
111
+ const responseOutputText = output
112
+ .flatMap((item) => Array.isArray(item.content) ? item.content : [])
113
+ .map((part) => typeof part.text === 'string' ? part.text : '')
114
+ .filter(Boolean)
115
+ .join('\n');
116
+ if (responseOutputText)
117
+ return responseOutputText;
118
+ const choices = Array.isArray(json.choices) ? json.choices : [];
119
+ const firstChoice = choices[0];
120
+ if (typeof firstChoice?.text === 'string')
121
+ return firstChoice.text;
122
+ const message = firstChoice?.message;
123
+ if (typeof message?.content === 'string')
124
+ return message.content;
125
+ if (Array.isArray(message?.content)) {
126
+ const messageText = message.content
127
+ .map((part) => typeof part.text === 'string' ? part.text : '')
128
+ .filter(Boolean)
129
+ .join('\n');
130
+ if (messageText)
131
+ return messageText;
132
+ }
133
+ const content = Array.isArray(json.content) ? json.content : [];
134
+ const anthropicText = content
135
+ .map((part) => typeof part.text === 'string' ? part.text : '')
136
+ .filter(Boolean)
137
+ .join('\n');
138
+ if (anthropicText)
139
+ return anthropicText;
140
+ const candidates = Array.isArray(json.candidates) ? json.candidates : [];
141
+ const firstCandidate = candidates[0];
142
+ const parts = (firstCandidate?.content?.parts ?? []);
143
+ return parts
144
+ .map((part) => typeof part.text === 'string' ? part.text : '')
145
+ .filter(Boolean)
146
+ .join('\n');
147
+ }
148
+ function extractError(json) {
149
+ if (json.success === false) {
150
+ return typeof json.msg === 'string' ? json.msg : 'Provider returned success=false';
151
+ }
152
+ const error = json.error;
153
+ if (typeof error === 'string')
154
+ return error;
155
+ if (error && typeof error === 'object') {
156
+ const message = error.message;
157
+ if (typeof message === 'string')
158
+ return message;
159
+ }
160
+ return typeof json.message === 'string' ? json.message : undefined;
161
+ }
162
+ function inferProvider(apiBase) {
163
+ if (apiBase?.includes('anthropic.com'))
164
+ return 'anthropic-messages';
165
+ if (apiBase?.includes('generativelanguage.googleapis.com'))
166
+ return 'gemini-generate-content';
167
+ return 'openai-chat-completions';
168
+ }
169
+ function joinUrl(base, path) {
170
+ return `${base.replace(/\/+$/, '')}${path}`;
171
+ }
172
+ function getAnthropicMessagesUrl(apiBase) {
173
+ try {
174
+ const url = new URL(apiBase);
175
+ if (url.pathname.endsWith('/messages'))
176
+ return apiBase;
177
+ if (url.hostname === 'api.anthropic.com')
178
+ return joinUrl(apiBase, '/messages');
179
+ return joinUrl(apiBase, '/v1/messages');
180
+ }
181
+ catch {
182
+ return apiBase;
183
+ }
184
+ }
185
+ //# sourceMappingURL=ai-text.js.map
@@ -2,4 +2,5 @@ export { createIssueFunctionTools, isBuiltInIssueToolName } from './issue-tools.
2
2
  export { createCommandFunctionTools } from './command-tools.js';
3
3
  export { createDatabaseFunctionTools } from './database-tools.js';
4
4
  export { createKanbanFunctionTools } from './kanban-tools.js';
5
+ export { createWorkflowExecutionFunctionTools, setWorkflowExecutionManager } from './workflow-exec-tools.js';
5
6
  //# sourceMappingURL=index.js.map