@agent-spaces/server 0.1.2 → 0.2.3

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 (217) hide show
  1. package/dist/adapters/claude-code-runtime/index.js +4 -1
  2. package/dist/adapters/git.js +2 -21
  3. package/dist/agents/issue-agent-runner.js +35 -21
  4. package/dist/agents/issue-task-controller.js +120 -73
  5. package/dist/agents/planner-agent.js +9 -12
  6. package/dist/app.js +12 -1
  7. package/dist/hooks/agent-hooks.js +5 -8
  8. package/dist/package.json +1 -1
  9. package/dist/routes/agent.js +40 -17
  10. package/dist/routes/channel.js +4 -1
  11. package/dist/routes/command.js +108 -0
  12. package/dist/routes/folder.js +44 -7
  13. package/dist/routes/issue.js +57 -23
  14. package/dist/routes/mcp.js +50 -0
  15. package/dist/routes/skill.js +57 -0
  16. package/dist/routes/subscription.js +49 -0
  17. package/dist/routes/task.js +16 -1
  18. package/dist/routes/workflow.js +63 -0
  19. package/dist/routes/workspace.js +2 -21
  20. package/dist/services/agent.js +140 -76
  21. package/dist/services/builtin-tools.js +72 -0
  22. package/dist/services/channel.js +5 -5
  23. package/dist/services/command-process-manager.js +136 -0
  24. package/dist/services/command.js +48 -0
  25. package/dist/services/issue.js +5 -6
  26. package/dist/services/mcp.js +120 -0
  27. package/dist/services/notification-hub/bot-commands.js +48 -16
  28. package/dist/services/notification-hub/helpers.js +12 -0
  29. package/dist/services/pty.js +10 -3
  30. package/dist/services/skill.js +171 -0
  31. package/dist/services/subscription/aicode.js +45 -0
  32. package/dist/services/subscription/base.js +3 -0
  33. package/dist/services/subscription/index.js +20 -0
  34. package/dist/services/subscription/minimax.js +60 -0
  35. package/dist/services/subscription/zhipu.js +39 -0
  36. package/dist/services/workflow.js +203 -0
  37. package/dist/services/workspace.js +0 -1
  38. package/dist/storage/command-store.js +17 -0
  39. package/dist/storage/subscription-store.js +44 -0
  40. package/dist/storage/workflow-store.js +40 -0
  41. package/dist/web/404.html +1 -1
  42. package/dist/web/__next.__PAGE__.txt +4 -4
  43. package/dist/web/__next._full.txt +22 -21
  44. package/dist/web/__next._head.txt +4 -4
  45. package/dist/web/__next._index.txt +9 -8
  46. package/dist/web/__next._tree.txt +2 -2
  47. package/dist/web/_next/static/7UtFGbIZvN_2yiatRc2g3/_buildManifest.js +11 -0
  48. package/dist/web/_next/static/chunks/0-245kun-watp.js +2 -0
  49. package/dist/web/_next/static/chunks/0-ca_fo-yp3~z.js +1 -0
  50. package/dist/web/_next/static/chunks/0-vgd3j-zh3m8.js +2 -0
  51. package/dist/web/_next/static/chunks/0.4.g.8yf4rs0.js +3 -0
  52. package/dist/web/_next/static/chunks/02m_-ngl9w8co.js +1 -0
  53. package/dist/web/_next/static/chunks/03jbh7ud0jw~g.js +1 -0
  54. package/dist/web/_next/static/chunks/07kqxmubf5dua.js +1 -0
  55. package/dist/web/_next/static/chunks/088q-5_51dsrw.js +1 -0
  56. package/dist/web/_next/static/chunks/08fqgb~~a~4ck.js +1 -0
  57. package/dist/web/_next/static/chunks/09_ki3dc5cfwv.css +1 -0
  58. package/dist/web/_next/static/chunks/09jryrjps0vl2.js +1 -0
  59. package/dist/web/_next/static/chunks/0amzlgoqe50tv.js +8 -0
  60. package/dist/web/_next/static/chunks/0b2tump5duj9j.js +1 -0
  61. package/dist/web/_next/static/chunks/0car_w834cbb6.js +1 -0
  62. package/dist/web/_next/static/chunks/0fwvdy-ml8wpk.js +1 -0
  63. package/dist/web/_next/static/chunks/0g4vm6.v0o_lt.js +1 -0
  64. package/dist/web/_next/static/chunks/0g_b4t~000.o~.js +179 -0
  65. package/dist/web/_next/static/chunks/0gyede80jpy3n.js +4 -0
  66. package/dist/web/_next/static/chunks/0h256h-tu4e0r.js +2 -0
  67. package/dist/web/_next/static/chunks/0ib18ul605e~a.js +1 -0
  68. package/dist/web/_next/static/chunks/0j1g_rd9t5ot1.js +1 -0
  69. package/dist/web/_next/static/chunks/0jn~llaqcxo4q.js +1 -0
  70. package/dist/web/_next/static/chunks/0jvmviuftg5e2.css +1 -0
  71. package/dist/web/_next/static/chunks/0lb8l2~6s_owo.js +1 -0
  72. package/dist/web/_next/static/chunks/0o4m39hw4fb_j.js +1 -0
  73. package/dist/web/_next/static/chunks/0pep4mkvt3.rh.js +31 -0
  74. package/dist/web/_next/static/chunks/0pq2670_ezbcj.js +1 -0
  75. package/dist/web/_next/static/chunks/0q_scqkk9.t53.js +2 -0
  76. package/dist/web/_next/static/chunks/0qyjxx0y7rzuu.js +1 -0
  77. package/dist/web/_next/static/chunks/0rrdur.v1a5r7.js +1 -0
  78. package/dist/web/_next/static/chunks/0spo.tmfeas-o.js +1 -0
  79. package/dist/web/_next/static/chunks/0u88ij9dqqh~-.js +1 -0
  80. package/dist/web/_next/static/chunks/0zl19l5tuoppw.js +1 -0
  81. package/dist/web/_next/static/chunks/11n16hogah-5..js +1 -0
  82. package/dist/web/_next/static/chunks/1250wo~-5dgyx.js +1 -0
  83. package/dist/web/_next/static/chunks/14n8i2xz4_y-e.js +1 -0
  84. package/dist/web/_next/static/chunks/160ji-.dfvm20.js +1 -0
  85. package/dist/web/_next/static/chunks/turbopack-0lxiiw.jhevml.js +1 -0
  86. package/dist/web/_next/static/media/favicon.0~ekuj.zhggpa.ico +0 -0
  87. package/dist/web/_not-found/__next._full.txt +26 -19
  88. package/dist/web/_not-found/__next._head.txt +4 -4
  89. package/dist/web/_not-found/__next._index.txt +9 -8
  90. package/dist/web/_not-found/__next._not-found.__PAGE__.txt +2 -2
  91. package/dist/web/_not-found/__next._not-found.txt +3 -3
  92. package/dist/web/_not-found/__next._tree.txt +2 -2
  93. package/dist/web/_not-found.html +1 -1
  94. package/dist/web/_not-found.txt +26 -19
  95. package/dist/web/apple-touch-icon.png +0 -0
  96. package/dist/web/favicon.ico +0 -0
  97. package/dist/web/icon-192.png +0 -0
  98. package/dist/web/icon-512.png +0 -0
  99. package/dist/web/index.html +1 -1
  100. package/dist/web/index.txt +22 -21
  101. package/dist/web/login/__next._full.txt +25 -23
  102. package/dist/web/login/__next._head.txt +4 -4
  103. package/dist/web/login/__next._index.txt +9 -8
  104. package/dist/web/login/__next._tree.txt +2 -2
  105. package/dist/web/login/__next.login.__PAGE__.txt +4 -4
  106. package/dist/web/login/__next.login.txt +3 -3
  107. package/dist/web/login.html +1 -1
  108. package/dist/web/login.txt +25 -23
  109. package/dist/web/settings/__next._full.txt +36 -0
  110. package/dist/web/settings/__next._head.txt +6 -0
  111. package/dist/web/settings/__next._index.txt +11 -0
  112. package/dist/web/settings/__next._tree.txt +8 -0
  113. package/dist/web/settings/__next.settings.__PAGE__.txt +9 -0
  114. package/dist/web/settings/__next.settings.txt +7 -0
  115. package/dist/web/settings/agents/__next._full.txt +39 -0
  116. package/dist/web/settings/agents/__next._head.txt +6 -0
  117. package/dist/web/settings/agents/__next._index.txt +11 -0
  118. package/dist/web/settings/agents/__next._tree.txt +8 -0
  119. package/dist/web/settings/agents/__next.settings.agents.__PAGE__.txt +9 -0
  120. package/dist/web/settings/agents/__next.settings.agents.txt +5 -0
  121. package/dist/web/settings/agents/__next.settings.txt +7 -0
  122. package/dist/web/settings/agents.html +1 -0
  123. package/dist/web/settings/agents.txt +39 -0
  124. package/dist/web/settings/mcps/__next._full.txt +39 -0
  125. package/dist/web/settings/mcps/__next._head.txt +6 -0
  126. package/dist/web/settings/mcps/__next._index.txt +11 -0
  127. package/dist/web/settings/mcps/__next._tree.txt +8 -0
  128. package/dist/web/settings/mcps/__next.settings.mcps.__PAGE__.txt +9 -0
  129. package/dist/web/settings/mcps/__next.settings.mcps.txt +5 -0
  130. package/dist/web/settings/mcps/__next.settings.txt +7 -0
  131. package/dist/web/settings/mcps.html +1 -0
  132. package/dist/web/settings/mcps.txt +39 -0
  133. package/dist/web/settings/models/__next._full.txt +39 -0
  134. package/dist/web/settings/models/__next._head.txt +6 -0
  135. package/dist/web/settings/models/__next._index.txt +11 -0
  136. package/dist/web/settings/models/__next._tree.txt +8 -0
  137. package/dist/web/settings/models/__next.settings.models.__PAGE__.txt +9 -0
  138. package/dist/web/settings/models/__next.settings.models.txt +5 -0
  139. package/dist/web/settings/models/__next.settings.txt +7 -0
  140. package/dist/web/settings/models.html +1 -0
  141. package/dist/web/settings/models.txt +39 -0
  142. package/dist/web/settings/providers/__next._full.txt +39 -0
  143. package/dist/web/settings/providers/__next._head.txt +6 -0
  144. package/dist/web/settings/providers/__next._index.txt +11 -0
  145. package/dist/web/settings/providers/__next._tree.txt +8 -0
  146. package/dist/web/settings/providers/__next.settings.providers.__PAGE__.txt +9 -0
  147. package/dist/web/settings/providers/__next.settings.providers.txt +5 -0
  148. package/dist/web/settings/providers/__next.settings.txt +7 -0
  149. package/dist/web/settings/providers.html +1 -0
  150. package/dist/web/settings/providers.txt +39 -0
  151. package/dist/web/settings/skills/__next._full.txt +39 -0
  152. package/dist/web/settings/skills/__next._head.txt +6 -0
  153. package/dist/web/settings/skills/__next._index.txt +11 -0
  154. package/dist/web/settings/skills/__next._tree.txt +8 -0
  155. package/dist/web/settings/skills/__next.settings.skills.__PAGE__.txt +9 -0
  156. package/dist/web/settings/skills/__next.settings.skills.txt +5 -0
  157. package/dist/web/settings/skills/__next.settings.txt +7 -0
  158. package/dist/web/settings/skills.html +1 -0
  159. package/dist/web/settings/skills.txt +39 -0
  160. package/dist/web/settings.html +1 -0
  161. package/dist/web/settings.txt +36 -0
  162. package/dist/web/workflows/__next._full.txt +35 -0
  163. package/dist/web/workflows/__next._head.txt +6 -0
  164. package/dist/web/workflows/__next._index.txt +11 -0
  165. package/dist/web/workflows/__next._tree.txt +9 -0
  166. package/dist/web/workflows/__next.workflows.__PAGE__.txt +10 -0
  167. package/dist/web/workflows/__next.workflows.txt +5 -0
  168. package/dist/web/workflows.html +1 -0
  169. package/dist/web/workflows.txt +35 -0
  170. package/dist/web/workspace/_/__next._full.txt +25 -20
  171. package/dist/web/workspace/_/__next._head.txt +4 -4
  172. package/dist/web/workspace/_/__next._index.txt +9 -8
  173. package/dist/web/workspace/_/__next._tree.txt +2 -2
  174. package/dist/web/workspace/_/__next.workspace.$d$id.__PAGE__.txt +3 -3
  175. package/dist/web/workspace/_/__next.workspace.$d$id.txt +3 -3
  176. package/dist/web/workspace/_/__next.workspace.txt +3 -3
  177. package/dist/web/workspace/_.html +1 -1
  178. package/dist/web/workspace/_.txt +25 -20
  179. package/dist/web/workspaces/__next._full.txt +25 -23
  180. package/dist/web/workspaces/__next._head.txt +4 -4
  181. package/dist/web/workspaces/__next._index.txt +9 -8
  182. package/dist/web/workspaces/__next._tree.txt +2 -2
  183. package/dist/web/workspaces/__next.workspaces.__PAGE__.txt +4 -4
  184. package/dist/web/workspaces/__next.workspaces.txt +3 -3
  185. package/dist/web/workspaces.html +1 -1
  186. package/dist/web/workspaces.txt +25 -23
  187. package/dist/ws/agent-prompt.js +84 -0
  188. package/dist/ws/agent-runner.js +592 -0
  189. package/dist/ws/handler.js +9 -1200
  190. package/dist/ws/html-utils.js +30 -0
  191. package/dist/ws/message-parts.js +498 -0
  192. package/package.json +12 -10
  193. package/dist/web/_next/static/chunks/038whpa0zpnas.js +0 -1
  194. package/dist/web/_next/static/chunks/06q5go~xoz5a3.js +0 -1
  195. package/dist/web/_next/static/chunks/095.wizobwtyg.js +0 -2
  196. package/dist/web/_next/static/chunks/0bfg.w~u-83h5.js +0 -1
  197. package/dist/web/_next/static/chunks/0ce7i6~sb20rv.js +0 -113
  198. package/dist/web/_next/static/chunks/0d4~pcva1uk-a.js +0 -1
  199. package/dist/web/_next/static/chunks/0iq70n_u75nyu.js +0 -1
  200. package/dist/web/_next/static/chunks/0memz-8zsbxpu.js +0 -1
  201. package/dist/web/_next/static/chunks/0nw~w.3~twebx.js +0 -2
  202. package/dist/web/_next/static/chunks/0pyytgz~5vt0f.js +0 -31
  203. package/dist/web/_next/static/chunks/0ujjcrz~1nq.q.css +0 -1
  204. package/dist/web/_next/static/chunks/0vdnx9n41dyjl.js +0 -1
  205. package/dist/web/_next/static/chunks/0yl4mqmxtll6g.js +0 -1
  206. package/dist/web/_next/static/chunks/0zcbfka5tcle3.js +0 -1
  207. package/dist/web/_next/static/chunks/0~eo58u99i.fr.js +0 -8
  208. package/dist/web/_next/static/chunks/13_2vxyccsv84.js +0 -4
  209. package/dist/web/_next/static/chunks/13wfs~urgxu0w.js +0 -1
  210. package/dist/web/_next/static/chunks/157~3c6wqkt83.js +0 -1
  211. package/dist/web/_next/static/chunks/15jvow_z4uq-..js +0 -1
  212. package/dist/web/_next/static/chunks/15v697nf~r-cy.js +0 -2
  213. package/dist/web/_next/static/chunks/turbopack-164~7ulq9o9yc.js +0 -1
  214. package/dist/web/_next/static/media/favicon.0x3dzn~oxb6tn.ico +0 -0
  215. package/dist/web/_next/static/owMnKmxATbtXK_J_k_uHh/_buildManifest.js +0 -21
  216. /package/dist/web/_next/static/{owMnKmxATbtXK_J_k_uHh → 7UtFGbIZvN_2yiatRc2g3}/_clientMiddlewareManifest.js +0 -0
  217. /package/dist/web/_next/static/{owMnKmxATbtXK_J_k_uHh → 7UtFGbIZvN_2yiatRc2g3}/_ssgManifest.js +0 -0
@@ -0,0 +1,48 @@
1
+ import { v4 as uuid } from 'uuid';
2
+ import * as commandStore from '../storage/command-store.js';
3
+ export function listCommands(workspaceId) {
4
+ return commandStore.listCommands(workspaceId);
5
+ }
6
+ export function getCommand(workspaceId, commandId) {
7
+ return commandStore.getCommand(workspaceId, commandId);
8
+ }
9
+ export function createCommand(workspaceId, input) {
10
+ const now = new Date().toISOString();
11
+ const cmd = {
12
+ id: uuid(),
13
+ name: input.name.trim(),
14
+ command: input.command,
15
+ folder: input.folder,
16
+ cwd: input.cwd,
17
+ shell: input.shell,
18
+ env: input.env,
19
+ autoRestart: input.autoRestart,
20
+ createdAt: now,
21
+ updatedAt: now,
22
+ };
23
+ const commands = commandStore.listCommands(workspaceId);
24
+ commands.push(cmd);
25
+ commandStore.saveCommands(workspaceId, commands);
26
+ return cmd;
27
+ }
28
+ export function updateCommand(workspaceId, commandId, updates) {
29
+ const commands = commandStore.listCommands(workspaceId);
30
+ const idx = commands.findIndex(c => c.id === commandId);
31
+ if (idx === -1)
32
+ throw new Error('Command not found');
33
+ commands[idx] = {
34
+ ...commands[idx],
35
+ ...updates,
36
+ updatedAt: new Date().toISOString(),
37
+ };
38
+ commandStore.saveCommands(workspaceId, commands);
39
+ return commands[idx];
40
+ }
41
+ export function deleteCommand(workspaceId, commandId) {
42
+ const commands = commandStore.listCommands(workspaceId);
43
+ const filtered = commands.filter(c => c.id !== commandId);
44
+ if (filtered.length === commands.length)
45
+ throw new Error('Command not found');
46
+ commandStore.saveCommands(workspaceId, filtered);
47
+ }
48
+ //# sourceMappingURL=command.js.map
@@ -4,7 +4,7 @@ import * as channelService from '../services/channel.js';
4
4
  import * as taskService from '../services/task.js';
5
5
  function ensureChannel(workspaceId, issue) {
6
6
  ensureRetryDefaults(workspaceId, issue);
7
- const channelMembers = ['user', ...(issue.members || [])];
7
+ const channelMembers = issue.members || [];
8
8
  if (issue.channelId) {
9
9
  channelService.updateChannel(workspaceId, issue.channelId, { type: 'issue', issueId: issue.id, members: channelMembers });
10
10
  return;
@@ -46,7 +46,7 @@ export function getById(workspaceId, issueId) {
46
46
  export function create(workspaceId, input) {
47
47
  const now = new Date().toISOString();
48
48
  const issueId = uuid();
49
- const channelMembers = ['user', ...(input.members || [])];
49
+ const channelMembers = input.members || [];
50
50
  const channel = channelService.createChannel(workspaceId, {
51
51
  name: input.title,
52
52
  type: 'issue',
@@ -61,8 +61,8 @@ export function create(workspaceId, input) {
61
61
  description: input.description,
62
62
  status: 'draft',
63
63
  tasks: [],
64
- assignedAgents: [],
65
64
  members: input.members || [],
65
+ workflowId: input.workflowId,
66
66
  retryCount: 0,
67
67
  maxRetries: 3,
68
68
  createdAt: now,
@@ -85,7 +85,6 @@ export function createForChannel(workspaceId, channelId, input) {
85
85
  description: input.description,
86
86
  status: 'draft',
87
87
  tasks: [],
88
- assignedAgents: [],
89
88
  members: [],
90
89
  retryCount: 0,
91
90
  maxRetries: 3,
@@ -171,8 +170,8 @@ export function addAgent(workspaceId, issueId, agentId) {
171
170
  const issue = getIssue(workspaceId, issueId);
172
171
  if (!issue)
173
172
  return null;
174
- if (!issue.assignedAgents.includes(agentId)) {
175
- issue.assignedAgents.push(agentId);
173
+ if (!issue.members.includes(agentId)) {
174
+ issue.members.push(agentId);
176
175
  issue.updatedAt = new Date().toISOString();
177
176
  updateIssue(issue);
178
177
  }
@@ -0,0 +1,120 @@
1
+ import { existsSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { ensureDir, getDataDir } from '../storage/json-store.js';
4
+ import { listTemplates } from './agent.js';
5
+ function getMcpsDir() {
6
+ return join(getDataDir(), 'mcps');
7
+ }
8
+ function getMcpMetaPath() {
9
+ return join(getMcpsDir(), '_meta.json');
10
+ }
11
+ function readMeta() {
12
+ const path = getMcpMetaPath();
13
+ if (!existsSync(path))
14
+ return { favorites: [] };
15
+ try {
16
+ return JSON.parse(readFileSync(path, 'utf-8'));
17
+ }
18
+ catch {
19
+ return { favorites: [] };
20
+ }
21
+ }
22
+ function writeMeta(meta) {
23
+ ensureDir(getMcpsDir());
24
+ writeFileSync(getMcpMetaPath(), JSON.stringify(meta, null, 2), 'utf-8');
25
+ }
26
+ function sanitizeName(name) {
27
+ return name.replace(/[^a-zA-Z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || 'mcp-server';
28
+ }
29
+ export function listMcps() {
30
+ const agents = listTemplates();
31
+ const mcpsDir = getMcpsDir();
32
+ const meta = readMeta();
33
+ ensureDir(mcpsDir);
34
+ const files = readdirSync(mcpsDir)
35
+ .filter((f) => f.endsWith('.json') && !f.startsWith('_'));
36
+ return files.map((filename) => {
37
+ const raw = readFileSync(join(mcpsDir, filename), 'utf-8');
38
+ const parsed = JSON.parse(raw);
39
+ const name = parsed.name || filename.replace(/\.json$/, '');
40
+ const boundAgents = agents
41
+ .filter((a) => {
42
+ const mcps = a.mcps;
43
+ if (!mcps || typeof mcps !== 'object')
44
+ return false;
45
+ const servers = mcps.mcpServers;
46
+ return servers && name in servers;
47
+ })
48
+ .map((a) => ({
49
+ id: a.id,
50
+ name: a.name || 'Agent',
51
+ avatarUrl: a.avatarUrl,
52
+ }));
53
+ return {
54
+ name,
55
+ description: parsed.description || '',
56
+ config: parsed.config || {},
57
+ favorited: meta.favorites.includes(name),
58
+ boundAgents,
59
+ };
60
+ });
61
+ }
62
+ export function importMcps(jsonText) {
63
+ const parsed = JSON.parse(jsonText);
64
+ const servers = {};
65
+ // Support both { mcpServers: {...} } and flat { name: {...} } formats
66
+ if (parsed.mcpServers && typeof parsed.mcpServers === 'object') {
67
+ Object.assign(servers, parsed.mcpServers);
68
+ }
69
+ else if (typeof parsed === 'object') {
70
+ Object.assign(servers, parsed);
71
+ }
72
+ const mcpsDir = getMcpsDir();
73
+ ensureDir(mcpsDir);
74
+ const results = [];
75
+ for (const [rawName, config] of Object.entries(servers)) {
76
+ const name = sanitizeName(rawName);
77
+ const filePath = join(mcpsDir, `${name}.json`);
78
+ writeFileSync(filePath, JSON.stringify({ name, config }, null, 2), 'utf-8');
79
+ results.push({
80
+ name,
81
+ description: '',
82
+ config: config,
83
+ favorited: false,
84
+ boundAgents: [],
85
+ });
86
+ }
87
+ return results;
88
+ }
89
+ export function updateMcpConfig(name, config) {
90
+ const mcpsDir = getMcpsDir();
91
+ const filePath = join(mcpsDir, `${name}.json`);
92
+ if (!existsSync(filePath))
93
+ return false;
94
+ const raw = readFileSync(filePath, 'utf-8');
95
+ const parsed = JSON.parse(raw);
96
+ parsed.config = config;
97
+ writeFileSync(filePath, JSON.stringify(parsed, null, 2), 'utf-8');
98
+ return true;
99
+ }
100
+ export function deleteMcp(name) {
101
+ const mcpsDir = getMcpsDir();
102
+ const filePath = join(mcpsDir, `${name}.json`);
103
+ if (!existsSync(filePath))
104
+ return false;
105
+ unlinkSync(filePath);
106
+ return true;
107
+ }
108
+ export function toggleFavorite(name) {
109
+ const meta = readMeta();
110
+ const idx = meta.favorites.indexOf(name);
111
+ if (idx >= 0) {
112
+ meta.favorites.splice(idx, 1);
113
+ }
114
+ else {
115
+ meta.favorites.push(name);
116
+ }
117
+ writeMeta(meta);
118
+ return idx < 0;
119
+ }
120
+ //# sourceMappingURL=mcp.js.map
@@ -6,6 +6,7 @@ import * as issueCommentService from '../issue-comment.js';
6
6
  import { gitCommit, gitGenerateCommitMsg, gitPull, gitPush, gitStatus } from '../../adapters/git.js';
7
7
  import { botCommandContexts } from './types.js';
8
8
  import { truncateLine } from './format.js';
9
+ import { getBotSettings, persistBotMarkdown } from './helpers.js';
9
10
  import { startIssueAutomation, getConfiguredBotAgent } from './bot-agent.js';
10
11
  import { hasActiveIssueAutomation } from '../../agents/issue-agent-runner.js';
11
12
  export function isBuiltInCommand(text) {
@@ -29,6 +30,14 @@ async function executeCommand(input) {
29
30
  const context = getBotCommandContext(input.conversationId, input.defaultWorkspaceId);
30
31
  const workspaceId = context.workspaceId ?? input.defaultWorkspaceId;
31
32
  if (command === '/workspace') {
33
+ if (args[0]) {
34
+ const workspace = resolveWorkspace(args[0]);
35
+ if (!workspace)
36
+ return `Workspace not found: ${args[0]}`;
37
+ const nextContext = { workspaceId: workspace.id };
38
+ botCommandContexts.set(input.conversationId, nextContext);
39
+ return `Switched workspace:\n${formatWorkspaceDetail(workspace)}`;
40
+ }
32
41
  const workspace = workspaceService.getById(workspaceId);
33
42
  return workspace ? formatWorkspaceDetail(workspace, context.issueId) : 'Workspace not found.';
34
43
  }
@@ -39,12 +48,11 @@ async function executeCommand(input) {
39
48
  : 'No workspaces.';
40
49
  }
41
50
  if (command === '/workspac') {
42
- const nextWorkspaceId = args[0];
43
- if (!nextWorkspaceId)
44
- return 'Usage: /workspac [id]';
45
- const workspace = workspaceService.getById(nextWorkspaceId);
51
+ if (!args[0])
52
+ return 'Usage: /workspac [id/name]';
53
+ const workspace = resolveWorkspace(args[0]);
46
54
  if (!workspace)
47
- return `Workspace not found: ${nextWorkspaceId}`;
55
+ return `Workspace not found: ${args[0]}`;
48
56
  const nextContext = { workspaceId: workspace.id };
49
57
  botCommandContexts.set(input.conversationId, nextContext);
50
58
  return `Switched workspace:\n${formatWorkspaceDetail(workspace)}`;
@@ -95,10 +103,10 @@ async function executeCommand(input) {
95
103
  const invalid = agentIds.filter((id) => !presetIds.has(id));
96
104
  if (invalid.length)
97
105
  return `Agent not found: ${invalid.join(', ')}`;
98
- issue.assignedAgents = agentIds;
106
+ issue.members = agentIds;
99
107
  issueService.save(workspaceId, issue);
100
108
  botCommandContexts.set(input.conversationId, { ...context, workspaceId, issueId: issue.id });
101
- return `Set agents for "${issue.title}": ${agentIds.join(', ')}`;
109
+ return `Set members for "${issue.title}": ${agentIds.join(', ')}`;
102
110
  }
103
111
  if (args[0]) {
104
112
  const issue = resolveIssue(workspaceId, args[0]);
@@ -163,6 +171,21 @@ async function executeCommand(input) {
163
171
  await gitPull(workspaceId);
164
172
  return 'Pulled from remote git.';
165
173
  }
174
+ if (command === '/markdown') {
175
+ const arg = args[0]?.toLowerCase();
176
+ const current = getBotSettings(workspaceId).markdown;
177
+ if (arg === 'on' || arg === 'true' || arg === '1') {
178
+ persistBotMarkdown(workspaceId, true);
179
+ botCommandContexts.set(input.conversationId, { ...context, workspaceId, markdown: true });
180
+ return 'Markdown output: ON';
181
+ }
182
+ if (arg === 'off' || arg === 'false' || arg === '0') {
183
+ persistBotMarkdown(workspaceId, false);
184
+ botCommandContexts.set(input.conversationId, { ...context, workspaceId, markdown: false });
185
+ return 'Markdown output: OFF';
186
+ }
187
+ return `Markdown output: ${current ? 'ON' : 'OFF'}\nUsage: /markdown [on/off]`;
188
+ }
166
189
  if (command === '/help')
167
190
  return buildCommandHelp();
168
191
  return buildCommandHelp();
@@ -175,7 +198,8 @@ function getBotCommandContext(conversationId, defaultWorkspaceId) {
175
198
  const issueId = existing.issueId && issueService.getById(workspaceId, existing.issueId)
176
199
  ? existing.issueId
177
200
  : undefined;
178
- const normalized = { workspaceId, issueId };
201
+ const markdown = existing.markdown ?? getBotSettings(workspaceId).markdown;
202
+ const normalized = { workspaceId, issueId, markdown };
179
203
  botCommandContexts.set(conversationId, normalized);
180
204
  return normalized;
181
205
  }
@@ -239,17 +263,26 @@ function formatWorkspaceDetail(workspace, currentIssueId) {
239
263
  currentIssueId ? `Current issue: ${currentIssueId}` : undefined,
240
264
  ].filter(Boolean).join('\n');
241
265
  }
266
+ function resolveWorkspace(idOrName) {
267
+ const byId = workspaceService.getById(idOrName);
268
+ if (byId)
269
+ return byId;
270
+ const lower = idOrName.toLowerCase();
271
+ const all = workspaceService.getAll();
272
+ const match = all.find((w) => w.name.toLowerCase().includes(lower));
273
+ return match ?? null;
274
+ }
242
275
  function resolveIssue(workspaceId, idOrIndex) {
243
276
  const byId = issueService.getById(workspaceId, idOrIndex);
244
277
  if (byId)
245
278
  return byId;
279
+ const issues = issueService.list(workspaceId)
280
+ .sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
246
281
  const index = Number(idOrIndex);
247
- if (Number.isInteger(index) && index >= 0) {
248
- const issues = issueService.list(workspaceId)
249
- .sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
282
+ if (Number.isInteger(index) && index >= 0)
250
283
  return issues[index] ?? null;
251
- }
252
- return null;
284
+ const lower = idOrIndex.toLowerCase();
285
+ return issues.find((i) => i.title.toLowerCase().includes(lower)) ?? null;
253
286
  }
254
287
  function formatAgentList(workspaceId) {
255
288
  const agents = agentService.listPresets(workspaceId) ?? [];
@@ -279,13 +312,11 @@ function formatIssueDetail(workspaceId, issueId) {
279
312
  const tasks = taskService.list(workspaceId, issue.id);
280
313
  const comments = issueCommentService.listIssueComments(workspaceId, issue.id);
281
314
  const members = issue.members.length ? issue.members.join(', ') : '-';
282
- const agents = issue.assignedAgents.length ? issue.assignedAgents.join(', ') : '-';
283
315
  return [
284
316
  `${issue.title} [${issue.status}]`,
285
317
  `ID: ${issue.id}`,
286
318
  issue.description ? `Desc: ${issue.description}` : undefined,
287
319
  `Members: ${members}`,
288
- `Agents: ${agents}`,
289
320
  `Tasks: ${tasks.length}`,
290
321
  ...tasks.map((task) => `- ${task.title} [${task.status}] ${task.id}`),
291
322
  `Comments: ${comments.length}`,
@@ -338,7 +369,7 @@ function buildCommandHelp() {
338
369
  'Supported commands:',
339
370
  '/workspace',
340
371
  '/workspaces',
341
- '/workspac [id]',
372
+ '/workspace [id/name] (alias: /workspac)',
342
373
  '/agents',
343
374
  '/issues',
344
375
  '/issue',
@@ -350,6 +381,7 @@ function buildCommandHelp() {
350
381
  '/task',
351
382
  '/comment [msg]',
352
383
  '/comments',
384
+ '/markdown [on/off]',
353
385
  '/help',
354
386
  '/changes',
355
387
  '/commit [desc/auto]',
@@ -66,6 +66,18 @@ export function persistWeChatGetUpdatesBuf(workspaceId, getUpdatesBuf) {
66
66
  },
67
67
  });
68
68
  }
69
+ export function getBotSettings(workspaceId) {
70
+ const settings = workspaceService.getById(workspaceId)?.notificationSettings;
71
+ return { markdown: settings?.botMarkdown !== false };
72
+ }
73
+ export function persistBotMarkdown(workspaceId, markdown) {
74
+ const workspace = workspaceService.getById(workspaceId);
75
+ const settings = workspace?.notificationSettings;
76
+ if (!workspace || !settings)
77
+ return;
78
+ settings.botMarkdown = markdown;
79
+ workspaceService.update(workspaceId, { notificationSettings: { ...settings } });
80
+ }
69
81
  export function sleep(ms) {
70
82
  return new Promise((resolve) => setTimeout(resolve, ms));
71
83
  }
@@ -1,15 +1,22 @@
1
1
  import pty from 'node-pty';
2
2
  import { v4 as uuid } from 'uuid';
3
3
  const sessions = new Map();
4
- export function createSession(workspaceId, cwd, onOutput, onExit, shell) {
4
+ export function createSession(workspaceId, cwd, onOutput, onExit, shell, env) {
5
5
  const id = uuid();
6
- const resolvedShell = shell || process.env.SHELL || '/bin/zsh';
6
+ const resolvedShell = shell || process.env.SHELL || (process.platform === 'win32' ? 'powershell.exe' : '/bin/zsh') || '/bin/sh';
7
+ const ptyEnv = {};
8
+ for (const [k, v] of Object.entries(process.env)) {
9
+ if (v !== undefined)
10
+ ptyEnv[k] = v;
11
+ }
12
+ if (env)
13
+ Object.assign(ptyEnv, env);
7
14
  const ptyProcess = pty.spawn(resolvedShell, [], {
8
15
  name: 'xterm-256color',
9
16
  cols: 80,
10
17
  rows: 24,
11
18
  cwd,
12
- env: { ...process.env },
19
+ env: ptyEnv,
13
20
  });
14
21
  ptyProcess.onData((data) => onOutput(id, data));
15
22
  ptyProcess.onExit(({ exitCode }) => onExit(id, exitCode ?? 0));
@@ -0,0 +1,171 @@
1
+ import { copyFileSync, existsSync, readdirSync, readFileSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
2
+ import { basename, join } from 'node:path';
3
+ import { ensureDir, getDataDir } from '../storage/json-store.js';
4
+ import { listTemplates } from './agent.js';
5
+ function getSkillsDir() {
6
+ return join(getDataDir(), 'skills');
7
+ }
8
+ function getSkillMetaPath() {
9
+ return join(getSkillsDir(), '_meta.json');
10
+ }
11
+ function readMeta() {
12
+ const path = getSkillMetaPath();
13
+ if (!existsSync(path))
14
+ return { favorites: [] };
15
+ try {
16
+ return JSON.parse(readFileSync(path, 'utf-8'));
17
+ }
18
+ catch {
19
+ return { favorites: [] };
20
+ }
21
+ }
22
+ function writeMeta(meta) {
23
+ ensureDir(getSkillsDir());
24
+ writeFileSync(getSkillMetaPath(), JSON.stringify(meta, null, 2), 'utf-8');
25
+ }
26
+ export function listSkills() {
27
+ const agents = listTemplates();
28
+ const skillsDir = getSkillsDir();
29
+ const meta = readMeta();
30
+ ensureDir(skillsDir);
31
+ const skillFiles = readdirSync(skillsDir)
32
+ .filter((f) => f.endsWith('.md') && !f.startsWith('_'));
33
+ return skillFiles.map((filename) => {
34
+ const content = readFileSync(join(skillsDir, filename), 'utf-8');
35
+ const name = basename(filename, '.md');
36
+ const fm = parseFrontmatter(content);
37
+ const boundAgents = agents
38
+ .filter((a) => (a.skills || []).some((s) => {
39
+ const skillName = s.replace(/\.md$/i, '');
40
+ return skillName === name;
41
+ }))
42
+ .map((a) => ({
43
+ id: a.id,
44
+ name: a.name || 'Agent',
45
+ avatarUrl: a.avatarUrl,
46
+ }));
47
+ return {
48
+ name,
49
+ description: fm.description || '',
50
+ filename,
51
+ content,
52
+ favorited: meta.favorites.includes(name),
53
+ boundAgents,
54
+ };
55
+ });
56
+ }
57
+ function parseFrontmatter(content) {
58
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
59
+ if (!match)
60
+ return { name: null, description: null };
61
+ const lines = match[1].split(/\r?\n/);
62
+ let name = null;
63
+ let description = null;
64
+ for (const line of lines) {
65
+ if (/^\s*name\s*:/i.test(line)) {
66
+ name = line.split(':', 2)[1].trim() || null;
67
+ }
68
+ else if (/^\s*description\s*:/i.test(line)) {
69
+ description = line.split(':', 2)[1].trim() || null;
70
+ }
71
+ }
72
+ return { name, description };
73
+ }
74
+ function sanitizeFilename(name) {
75
+ const safe = name.replace(/[^a-zA-Z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || 'skill';
76
+ return safe.endsWith('.md') ? safe : `${safe}.md`;
77
+ }
78
+ export function importSkill(filename, content) {
79
+ const fm = parseFrontmatter(content);
80
+ const finalName = fm.name
81
+ ? sanitizeFilename(fm.name)
82
+ : sanitizeFilename(filename);
83
+ const skillsDir = getSkillsDir();
84
+ ensureDir(skillsDir);
85
+ writeFileSync(join(skillsDir, finalName), content, 'utf-8');
86
+ return {
87
+ name: basename(finalName, '.md'),
88
+ description: fm.description || '',
89
+ filename: finalName,
90
+ content,
91
+ favorited: false,
92
+ boundAgents: [],
93
+ };
94
+ }
95
+ export function toggleFavorite(name) {
96
+ const meta = readMeta();
97
+ const idx = meta.favorites.indexOf(name);
98
+ if (idx >= 0) {
99
+ meta.favorites.splice(idx, 1);
100
+ }
101
+ else {
102
+ meta.favorites.push(name);
103
+ }
104
+ writeMeta(meta);
105
+ return idx < 0;
106
+ }
107
+ export function updateSkillContent(name, content) {
108
+ const skillsDir = getSkillsDir();
109
+ const filename = name.endsWith('.md') ? name : `${name}.md`;
110
+ const filePath = join(skillsDir, filename);
111
+ if (!existsSync(filePath))
112
+ return false;
113
+ writeFileSync(filePath, content, 'utf-8');
114
+ return true;
115
+ }
116
+ export function deleteSkill(name) {
117
+ const skillsDir = getSkillsDir();
118
+ const filename = name.endsWith('.md') ? name : `${name}.md`;
119
+ const filePath = join(skillsDir, filename);
120
+ if (!existsSync(filePath))
121
+ return false;
122
+ unlinkSync(filePath);
123
+ return true;
124
+ }
125
+ export function checkSkillSync() {
126
+ const globalSkillsDir = getSkillsDir();
127
+ const agents = listTemplates();
128
+ const result = [];
129
+ for (const agent of agents) {
130
+ const skillNames = (agent.skills || []).map((s) => s.replace(/\.md$/i, ''));
131
+ if (skillNames.length === 0)
132
+ continue;
133
+ const agentSkillsDir = join(getDataDir(), 'agent-templates', agent.id, 'skills');
134
+ for (const skillName of skillNames) {
135
+ const globalFile = join(globalSkillsDir, `${skillName}.md`);
136
+ const agentFile = join(agentSkillsDir, `${skillName}.md`);
137
+ if (!existsSync(globalFile))
138
+ continue;
139
+ if (!existsSync(agentFile))
140
+ continue;
141
+ const globalStat = statSync(globalFile);
142
+ const agentStat = statSync(agentFile);
143
+ if (globalStat.mtimeMs > agentStat.mtimeMs) {
144
+ result.push({
145
+ agentId: agent.id,
146
+ agentName: agent.name || agent.id,
147
+ skillName,
148
+ globalMtime: globalStat.mtime.toISOString(),
149
+ agentMtime: agentStat.mtime.toISOString(),
150
+ });
151
+ }
152
+ }
153
+ }
154
+ return result;
155
+ }
156
+ export function syncSkills(items) {
157
+ const globalSkillsDir = getSkillsDir();
158
+ let synced = 0;
159
+ for (const item of items) {
160
+ const globalFile = join(globalSkillsDir, `${item.skillName}.md`);
161
+ const agentSkillsDir = join(getDataDir(), 'agent-templates', item.agentId, 'skills');
162
+ const agentFile = join(agentSkillsDir, `${item.skillName}.md`);
163
+ if (!existsSync(globalFile))
164
+ continue;
165
+ ensureDir(agentSkillsDir);
166
+ copyFileSync(globalFile, agentFile);
167
+ synced++;
168
+ }
169
+ return synced;
170
+ }
171
+ //# sourceMappingURL=skill.js.map
@@ -0,0 +1,45 @@
1
+ import { SubscriptionProviderBase } from './base.js';
2
+ export class AiCodeSubscriptionProvider extends SubscriptionProviderBase {
3
+ provider = 'aicode';
4
+ async fetchQuota(config) {
5
+ const url = 'https://www.aicodemirror.com/api/wallet';
6
+ const res = await fetch(url, {
7
+ method: 'GET',
8
+ headers: {
9
+ 'Accept': '*/*',
10
+ 'Referer': 'https://www.aicodemirror.com/dashboard/wallet',
11
+ ...(config.cookie ? { 'Cookie': config.cookie } : {}),
12
+ ...(config.headers ?? {}),
13
+ },
14
+ });
15
+ if (!res.ok) {
16
+ throw new Error(`AiCode API returned ${res.status}: ${res.statusText}`);
17
+ }
18
+ const json = await res.json();
19
+ if (!json.success) {
20
+ throw new Error('AiCode API returned unsuccessful response');
21
+ }
22
+ const balance = Number(json.data.balance) / 1000;
23
+ const bonus = Number(json.data.bonusBalance) / 1000;
24
+ return {
25
+ provider: 'aicode',
26
+ label: config.label,
27
+ limits: [
28
+ {
29
+ type: 'balance',
30
+ currentValue: Math.round(balance * 100) / 100,
31
+ remaining: Math.round(balance * 100) / 100,
32
+ percentage: 0,
33
+ },
34
+ {
35
+ type: 'bonusBalance',
36
+ currentValue: Math.round(bonus * 100) / 100,
37
+ remaining: Math.round(bonus * 100) / 100,
38
+ percentage: 0,
39
+ },
40
+ ],
41
+ fetchedAt: new Date().toISOString(),
42
+ };
43
+ }
44
+ }
45
+ //# sourceMappingURL=aicode.js.map
@@ -0,0 +1,3 @@
1
+ export class SubscriptionProviderBase {
2
+ }
3
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1,20 @@
1
+ import { SubscriptionProviderBase } from './base.js';
2
+ import { ZhiPuSubscriptionProvider } from './zhipu.js';
3
+ import { MiniMaxSubscriptionProvider } from './minimax.js';
4
+ import { AiCodeSubscriptionProvider } from './aicode.js';
5
+ const providers = [
6
+ new ZhiPuSubscriptionProvider(),
7
+ new MiniMaxSubscriptionProvider(),
8
+ new AiCodeSubscriptionProvider(),
9
+ ];
10
+ function getProvider(provider) {
11
+ const p = providers.find(p => p.provider === provider);
12
+ if (!p)
13
+ throw new Error(`Unknown subscription provider: ${provider}`);
14
+ return p;
15
+ }
16
+ export async function fetchQuota(config) {
17
+ return getProvider(config.provider).fetchQuota(config);
18
+ }
19
+ export { SubscriptionProviderBase, ZhiPuSubscriptionProvider };
20
+ //# sourceMappingURL=index.js.map