@nemus-cli/nemus 0.2.1

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 (320) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/LICENSE +21 -0
  3. package/README.md +275 -0
  4. package/assets/README.md +53 -0
  5. package/assets/banner.png +0 -0
  6. package/assets/banner.svg +66 -0
  7. package/assets/favicon-32.png +0 -0
  8. package/assets/favicon-64.png +0 -0
  9. package/assets/icon-256.png +0 -0
  10. package/assets/icon.svg +23 -0
  11. package/assets/logo-256.png +0 -0
  12. package/assets/logo-512.png +0 -0
  13. package/assets/logo-wordmark.svg +35 -0
  14. package/assets/logo.svg +32 -0
  15. package/bin/workspace.js +130 -0
  16. package/dist/cli/ai-prompt.js +421 -0
  17. package/dist/cli/dashboard/AgentList.js +61 -0
  18. package/dist/cli/dashboard/DashboardSidebar.js +280 -0
  19. package/dist/cli/dashboard/HelpFooter.js +73 -0
  20. package/dist/cli/dashboard/StatusBadge.js +50 -0
  21. package/dist/cli/dashboard/index.js +11 -0
  22. package/dist/cli/dashboard/types.js +2 -0
  23. package/dist/cli/tui.js +48 -0
  24. package/dist/commands/ai-prompt.js +22 -0
  25. package/dist/commands/analyze-deps.js +138 -0
  26. package/dist/commands/archive.js +113 -0
  27. package/dist/commands/branch/create.js +119 -0
  28. package/dist/commands/branch/index.js +104 -0
  29. package/dist/commands/branch/merge.js +90 -0
  30. package/dist/commands/branch/rebase.js +84 -0
  31. package/dist/commands/branch/switch.js +165 -0
  32. package/dist/commands/cache/index.js +80 -0
  33. package/dist/commands/cache/manager.js +198 -0
  34. package/dist/commands/cleanup.js +153 -0
  35. package/dist/commands/configure-claude.js +55 -0
  36. package/dist/commands/configure.js +231 -0
  37. package/dist/commands/create.js +204 -0
  38. package/dist/commands/dashboard/hook-handler.js +162 -0
  39. package/dist/commands/dashboard/index.js +258 -0
  40. package/dist/commands/dashboard/launcher.js +40 -0
  41. package/dist/commands/dashboard/session-picker.js +106 -0
  42. package/dist/commands/dashboard/sidebar.js +39 -0
  43. package/dist/commands/dashboard/workspace-picker.js +95 -0
  44. package/dist/commands/delete.js +194 -0
  45. package/dist/commands/deprecated-aliases.js +44 -0
  46. package/dist/commands/diff.js +129 -0
  47. package/dist/commands/doctor.js +141 -0
  48. package/dist/commands/generate-docs.js +77 -0
  49. package/dist/commands/ghq-status.js +72 -0
  50. package/dist/commands/go.js +154 -0
  51. package/dist/commands/history.js +124 -0
  52. package/dist/commands/list.js +191 -0
  53. package/dist/commands/mcp/index.js +69 -0
  54. package/dist/commands/migrate.js +296 -0
  55. package/dist/commands/remove-repo.js +217 -0
  56. package/dist/commands/report-bug.js +112 -0
  57. package/dist/commands/run.js +147 -0
  58. package/dist/commands/save-context.js +171 -0
  59. package/dist/commands/sessions.js +129 -0
  60. package/dist/commands/status.js +138 -0
  61. package/dist/commands/suite/create.js +212 -0
  62. package/dist/commands/suite/delete.js +64 -0
  63. package/dist/commands/suite/export.js +126 -0
  64. package/dist/commands/suite/import.js +128 -0
  65. package/dist/commands/suite/index.js +94 -0
  66. package/dist/commands/suite/list.js +49 -0
  67. package/dist/commands/suite/use.js +227 -0
  68. package/dist/commands/sync.js +117 -0
  69. package/dist/commands/update.js +203 -0
  70. package/dist/mcp/install.js +550 -0
  71. package/dist/mcp/server.js +398 -0
  72. package/dist/mcp/tools.js +922 -0
  73. package/dist/pi-extensions/permission-sync.ts.template +41 -0
  74. package/dist/pi-extensions/permissions-gate.ts.template +69 -0
  75. package/dist/pi-extensions/pr-fix-trigger.ts.template +124 -0
  76. package/dist/pi-extensions/review-reminder.ts.template +58 -0
  77. package/dist/pi-extensions/workspace-input-status.ts.template +919 -0
  78. package/dist/program.js +136 -0
  79. package/dist/scripts/workspace-table.py +394 -0
  80. package/dist/types/dashboard.js +11 -0
  81. package/dist/types/index.js +2 -0
  82. package/dist/utils/agent-config.js +263 -0
  83. package/dist/utils/agent-state.js +178 -0
  84. package/dist/utils/banner.js +24 -0
  85. package/dist/utils/branch-operations.js +232 -0
  86. package/dist/utils/bug-report.js +355 -0
  87. package/dist/utils/cache.js +168 -0
  88. package/dist/utils/claude-integration.js +617 -0
  89. package/dist/utils/claude-sessions.js +260 -0
  90. package/dist/utils/cleanup-operations.js +120 -0
  91. package/dist/utils/colors.js +26 -0
  92. package/dist/utils/command-helpers.js +44 -0
  93. package/dist/utils/config.js +150 -0
  94. package/dist/utils/context-file.js +33 -0
  95. package/dist/utils/dashboard-hooks.js +172 -0
  96. package/dist/utils/dependency-analyzer.js +234 -0
  97. package/dist/utils/diff-operations.js +80 -0
  98. package/dist/utils/doc-generator.js +184 -0
  99. package/dist/utils/ghq-integration.js +332 -0
  100. package/dist/utils/git-operations.js +237 -0
  101. package/dist/utils/git-status.js +187 -0
  102. package/dist/utils/github.js +68 -0
  103. package/dist/utils/health-checks.js +345 -0
  104. package/dist/utils/history.js +150 -0
  105. package/dist/utils/hooks.js +100 -0
  106. package/dist/utils/logger.js +40 -0
  107. package/dist/utils/permission-sync.js +681 -0
  108. package/dist/utils/pi-extensions.js +224 -0
  109. package/dist/utils/progress.js +92 -0
  110. package/dist/utils/prompts.js +279 -0
  111. package/dist/utils/repo-resolver.js +260 -0
  112. package/dist/utils/retry.js +65 -0
  113. package/dist/utils/run-operations.js +30 -0
  114. package/dist/utils/suite.js +159 -0
  115. package/dist/utils/sync-operations.js +107 -0
  116. package/dist/utils/tmux-dashboard.js +184 -0
  117. package/dist/utils/validation.js +153 -0
  118. package/dist/utils/version-check.js +121 -0
  119. package/dist/utils/workspace-meta.js +185 -0
  120. package/install-shell-integration.sh +532 -0
  121. package/install.sh +401 -0
  122. package/package.json +90 -0
  123. package/remove-shell-block.awk +44 -0
  124. package/scripts/postinstall.js +85 -0
  125. package/skills/analyze-deps.md +23 -0
  126. package/skills/archive-workspace.md +26 -0
  127. package/skills/branch-create.md +18 -0
  128. package/skills/create-workspace.md +39 -0
  129. package/skills/delete-workspace.md +37 -0
  130. package/skills/list-org-repos.md +26 -0
  131. package/skills/list-suites.md +24 -0
  132. package/skills/list-workspaces.md +27 -0
  133. package/skills/refresh-workspace-docs.md +89 -0
  134. package/skills/remove-repo.md +25 -0
  135. package/skills/run-command.md +23 -0
  136. package/skills/save-context.md +68 -0
  137. package/skills/search-repos.md +31 -0
  138. package/skills/snapshot-list.md +18 -0
  139. package/skills/snapshot-save.md +12 -0
  140. package/skills/switch-branch.md +18 -0
  141. package/skills/update-cache.md +21 -0
  142. package/skills/update-workspace.md +66 -0
  143. package/skills/workspace-cleanup.md +18 -0
  144. package/skills/workspace-diff.md +23 -0
  145. package/skills/workspace-doctor.md +23 -0
  146. package/skills/workspace-info.md +45 -0
  147. package/skills/workspace-manager/SKILL.md +201 -0
  148. package/skills/workspace-manager/references/ai-prompt.md +44 -0
  149. package/skills/workspace-manager/references/analyze-deps.md +45 -0
  150. package/skills/workspace-manager/references/archive-workspace.md +38 -0
  151. package/skills/workspace-manager/references/branch-create.md +31 -0
  152. package/skills/workspace-manager/references/branch-merge.md +22 -0
  153. package/skills/workspace-manager/references/branch-rebase.md +22 -0
  154. package/skills/workspace-manager/references/cache-clear.md +18 -0
  155. package/skills/workspace-manager/references/cache-info.md +22 -0
  156. package/skills/workspace-manager/references/configure-claude.md +31 -0
  157. package/skills/workspace-manager/references/configure.md +35 -0
  158. package/skills/workspace-manager/references/create-workspace.md +45 -0
  159. package/skills/workspace-manager/references/dashboard.md +61 -0
  160. package/skills/workspace-manager/references/delete-workspace.md +33 -0
  161. package/skills/workspace-manager/references/generate-docs.md +36 -0
  162. package/skills/workspace-manager/references/ghq-status.md +28 -0
  163. package/skills/workspace-manager/references/go.md +33 -0
  164. package/skills/workspace-manager/references/history.md +41 -0
  165. package/skills/workspace-manager/references/list-org-repos.md +26 -0
  166. package/skills/workspace-manager/references/list-suites.md +21 -0
  167. package/skills/workspace-manager/references/list-workspaces.md +27 -0
  168. package/skills/workspace-manager/references/mcp.md +49 -0
  169. package/skills/workspace-manager/references/remove-repo.md +26 -0
  170. package/skills/workspace-manager/references/run-command.md +44 -0
  171. package/skills/workspace-manager/references/search-repos.md +24 -0
  172. package/skills/workspace-manager/references/sessions.md +27 -0
  173. package/skills/workspace-manager/references/suite-create.md +22 -0
  174. package/skills/workspace-manager/references/suite-delete.md +21 -0
  175. package/skills/workspace-manager/references/suite-export.md +19 -0
  176. package/skills/workspace-manager/references/suite-import.md +19 -0
  177. package/skills/workspace-manager/references/suite-use.md +27 -0
  178. package/skills/workspace-manager/references/switch-branch.md +25 -0
  179. package/skills/workspace-manager/references/update-cache.md +22 -0
  180. package/skills/workspace-manager/references/update-workspace.md +50 -0
  181. package/skills/workspace-manager/references/workspace-cleanup.md +33 -0
  182. package/skills/workspace-manager/references/workspace-diff.md +27 -0
  183. package/skills/workspace-manager/references/workspace-doctor.md +27 -0
  184. package/skills/workspace-manager/references/workspace-info.md +33 -0
  185. package/skills/workspace-manager/references/workspace-status.md +43 -0
  186. package/skills/workspace-manager/references/workspace-sync.md +26 -0
  187. package/skills/workspace-status.md +26 -0
  188. package/skills/workspace-sync.md +23 -0
  189. package/src/cli/ai-prompt.test.ts +667 -0
  190. package/src/cli/ai-prompt.ts +421 -0
  191. package/src/cli/dashboard/AgentList.tsx +44 -0
  192. package/src/cli/dashboard/DashboardSidebar.tsx +291 -0
  193. package/src/cli/dashboard/HelpFooter.tsx +22 -0
  194. package/src/cli/dashboard/StatusBadge.tsx +23 -0
  195. package/src/cli/dashboard/index.ts +5 -0
  196. package/src/cli/dashboard/types.ts +16 -0
  197. package/src/cli/tui.tsx +51 -0
  198. package/src/cli/workspace-cli.test.ts +30 -0
  199. package/src/commands/ai-prompt.ts +21 -0
  200. package/src/commands/analyze-deps.ts +119 -0
  201. package/src/commands/archive.ts +114 -0
  202. package/src/commands/branch/create.ts +94 -0
  203. package/src/commands/branch/index.ts +74 -0
  204. package/src/commands/branch/merge.ts +61 -0
  205. package/src/commands/branch/rebase.ts +54 -0
  206. package/src/commands/branch/switch.ts +150 -0
  207. package/src/commands/cache/index.ts +51 -0
  208. package/src/commands/cache/manager.ts +168 -0
  209. package/src/commands/cleanup.ts +132 -0
  210. package/src/commands/configure-claude.ts +55 -0
  211. package/src/commands/configure.ts +204 -0
  212. package/src/commands/create.ts +196 -0
  213. package/src/commands/dashboard/hook-handler.ts +138 -0
  214. package/src/commands/dashboard/index.ts +248 -0
  215. package/src/commands/dashboard/launcher.ts +42 -0
  216. package/src/commands/dashboard/session-picker.ts +73 -0
  217. package/src/commands/dashboard/sidebar.js +39 -0
  218. package/src/commands/dashboard/workspace-picker.ts +62 -0
  219. package/src/commands/delete.test.ts +250 -0
  220. package/src/commands/delete.ts +171 -0
  221. package/src/commands/deprecated-aliases.ts +55 -0
  222. package/src/commands/diff.ts +106 -0
  223. package/src/commands/doctor.ts +110 -0
  224. package/src/commands/generate-docs.ts +45 -0
  225. package/src/commands/ghq-status.ts +70 -0
  226. package/src/commands/go.ts +125 -0
  227. package/src/commands/history.ts +136 -0
  228. package/src/commands/list.test.ts +219 -0
  229. package/src/commands/list.ts +176 -0
  230. package/src/commands/mcp/index.ts +39 -0
  231. package/src/commands/migrate.ts +277 -0
  232. package/src/commands/remove-repo.ts +194 -0
  233. package/src/commands/report-bug.ts +88 -0
  234. package/src/commands/run.ts +125 -0
  235. package/src/commands/save-context.test.ts +113 -0
  236. package/src/commands/save-context.ts +141 -0
  237. package/src/commands/sessions.ts +99 -0
  238. package/src/commands/status.ts +111 -0
  239. package/src/commands/suite/create.ts +240 -0
  240. package/src/commands/suite/delete.ts +65 -0
  241. package/src/commands/suite/export.ts +97 -0
  242. package/src/commands/suite/import.ts +100 -0
  243. package/src/commands/suite/index.ts +66 -0
  244. package/src/commands/suite/list.ts +54 -0
  245. package/src/commands/suite/use.ts +232 -0
  246. package/src/commands/sync.ts +97 -0
  247. package/src/commands/update.ts +197 -0
  248. package/src/mcp/install.ts +529 -0
  249. package/src/mcp/server.ts +579 -0
  250. package/src/mcp/tools.test.ts +545 -0
  251. package/src/mcp/tools.ts +1019 -0
  252. package/src/mcp/update-workspace.test.ts +220 -0
  253. package/src/pi-extensions/permission-sync.ts.template +41 -0
  254. package/src/pi-extensions/permissions-gate.ts.template +69 -0
  255. package/src/pi-extensions/pr-fix-trigger.ts.template +124 -0
  256. package/src/pi-extensions/review-reminder.ts.template +58 -0
  257. package/src/pi-extensions/workspace-input-status.ts.template +919 -0
  258. package/src/program.ts +112 -0
  259. package/src/scripts/workspace-table.py +394 -0
  260. package/src/types/dashboard.ts +29 -0
  261. package/src/types/index.ts +109 -0
  262. package/src/types/ink.d.ts +171 -0
  263. package/src/utils/agent-config.test.ts +303 -0
  264. package/src/utils/agent-config.ts +264 -0
  265. package/src/utils/agent-state.test.ts +166 -0
  266. package/src/utils/agent-state.ts +135 -0
  267. package/src/utils/banner.ts +24 -0
  268. package/src/utils/branch-operations.ts +237 -0
  269. package/src/utils/bug-report.test.ts +174 -0
  270. package/src/utils/bug-report.ts +355 -0
  271. package/src/utils/cache.ts +150 -0
  272. package/src/utils/claude-integration.test.ts +381 -0
  273. package/src/utils/claude-integration.ts +649 -0
  274. package/src/utils/claude-sessions.test.ts +262 -0
  275. package/src/utils/claude-sessions.ts +251 -0
  276. package/src/utils/cleanup-operations.ts +94 -0
  277. package/src/utils/colors.ts +25 -0
  278. package/src/utils/command-helpers.ts +46 -0
  279. package/src/utils/config.test.ts +203 -0
  280. package/src/utils/config.ts +133 -0
  281. package/src/utils/context-file.ts +36 -0
  282. package/src/utils/dashboard-hooks.test.ts +168 -0
  283. package/src/utils/dashboard-hooks.ts +163 -0
  284. package/src/utils/dependency-analyzer.ts +243 -0
  285. package/src/utils/diff-operations.ts +59 -0
  286. package/src/utils/doc-generator.ts +187 -0
  287. package/src/utils/ghq-integration.test.ts +195 -0
  288. package/src/utils/ghq-integration.ts +317 -0
  289. package/src/utils/git-operations.test.ts +265 -0
  290. package/src/utils/git-operations.ts +233 -0
  291. package/src/utils/git-status.ts +171 -0
  292. package/src/utils/github.ts +74 -0
  293. package/src/utils/health-checks.ts +359 -0
  294. package/src/utils/history.ts +140 -0
  295. package/src/utils/hooks.ts +92 -0
  296. package/src/utils/logger.ts +37 -0
  297. package/src/utils/permission-sync.test.ts +593 -0
  298. package/src/utils/permission-sync.ts +720 -0
  299. package/src/utils/pi-extensions.test.ts +182 -0
  300. package/src/utils/pi-extensions.ts +226 -0
  301. package/src/utils/progress.ts +73 -0
  302. package/src/utils/prompts.test.ts +169 -0
  303. package/src/utils/prompts.ts +296 -0
  304. package/src/utils/repo-resolver.test.ts +313 -0
  305. package/src/utils/repo-resolver.ts +294 -0
  306. package/src/utils/retry.test.ts +124 -0
  307. package/src/utils/retry.ts +85 -0
  308. package/src/utils/run-operations.ts +38 -0
  309. package/src/utils/suite.test.ts +256 -0
  310. package/src/utils/suite.ts +144 -0
  311. package/src/utils/sync-operations.ts +87 -0
  312. package/src/utils/tmux-dashboard.ts +193 -0
  313. package/src/utils/validation.test.ts +139 -0
  314. package/src/utils/validation.ts +128 -0
  315. package/src/utils/version-check.test.ts +108 -0
  316. package/src/utils/version-check.ts +96 -0
  317. package/src/utils/workspace-meta.ts +173 -0
  318. package/sync-permissions.sh +137 -0
  319. package/tsconfig.json +20 -0
  320. package/uninstall.sh +162 -0
@@ -0,0 +1,398 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
5
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
+ const zod_1 = require("zod");
7
+ // Traversal-safe name for any parameter used to build a filesystem path (a
8
+ // workspace name). Blocks path separators, drive letters, "."/".." and NUL, so an
9
+ // MCP client cannot escape the workspaces sandbox; spaces are allowed because the
10
+ // create path sanitizes them to hyphens. Handlers still call safeWorkspacePath()
11
+ // as the authoritative check 2014 this is defense in depth with a clean client error.
12
+ const WS_NAME_RE = /^[A-Za-z0-9 _-]+$/;
13
+ const wsName = zod_1.z.string().min(1).max(64).regex(WS_NAME_RE, 'may contain only letters, numbers, spaces, hyphens, and underscores (no path separators, "..", or other special characters)');
14
+ const tools_1 = require("./tools");
15
+ const config_1 = require("../utils/config");
16
+ const server = new mcp_js_1.McpServer({
17
+ name: 'workspace-manager',
18
+ version: (0, config_1.getPackageVersion)(),
19
+ });
20
+ server.tool('list-workspaces', 'List all workspaces with their repo counts and creation dates', {
21
+ includeArchived: zod_1.z.boolean().optional().default(false).describe('Include archived workspaces in the listing'),
22
+ }, async ({ includeArchived }) => {
23
+ try {
24
+ const result = await (0, tools_1.handleListWorkspaces)(includeArchived);
25
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
26
+ }
27
+ catch (error) {
28
+ const msg = error instanceof Error ? error.message : 'Unknown error';
29
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
30
+ }
31
+ });
32
+ server.tool('archive-workspace', 'Archive a workspace so it is hidden from default listing. Archived workspaces auto-delete after 30 days.', {
33
+ workspace: wsName.describe('Name of the workspace to archive'),
34
+ }, async ({ workspace }) => {
35
+ try {
36
+ const result = await (0, tools_1.handleArchiveWorkspace)(workspace);
37
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
38
+ }
39
+ catch (error) {
40
+ const msg = error instanceof Error ? error.message : 'Unknown error';
41
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
42
+ }
43
+ });
44
+ server.tool('unarchive-workspace', 'Unarchive a previously archived workspace, making it active again', {
45
+ workspace: wsName.describe('Name of the workspace to unarchive'),
46
+ }, async ({ workspace }) => {
47
+ try {
48
+ const result = await (0, tools_1.handleUnarchiveWorkspace)(workspace);
49
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
50
+ }
51
+ catch (error) {
52
+ const msg = error instanceof Error ? error.message : 'Unknown error';
53
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
54
+ }
55
+ });
56
+ server.tool('workspace-status', 'Show git status (branch, clean/dirty, ahead/behind) for all repos in a workspace', { workspace: wsName.describe('Name of the workspace') }, async ({ workspace }) => {
57
+ try {
58
+ const result = await (0, tools_1.handleWorkspaceStatus)(workspace);
59
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
60
+ }
61
+ catch (error) {
62
+ const msg = error instanceof Error ? error.message : 'Unknown error';
63
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
64
+ }
65
+ });
66
+ server.tool('workspace-diff', 'Show diff summary (staged/unstaged file counts, insertions, deletions) for all repos in a workspace', {
67
+ workspace: wsName.describe('Name of the workspace'),
68
+ full: zod_1.z.boolean().optional().describe('Include full diff output'),
69
+ }, async ({ workspace, full }) => {
70
+ try {
71
+ const result = await (0, tools_1.handleWorkspaceDiff)(workspace, full);
72
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
73
+ }
74
+ catch (error) {
75
+ const msg = error instanceof Error ? error.message : 'Unknown error';
76
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
77
+ }
78
+ });
79
+ server.tool('workspace-sync', 'Git pull all repos in a workspace (skips repos with uncommitted changes)', { workspace: wsName.describe('Name of the workspace') }, async ({ workspace }) => {
80
+ try {
81
+ const result = await (0, tools_1.handleWorkspaceSync)(workspace);
82
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
83
+ }
84
+ catch (error) {
85
+ const msg = error instanceof Error ? error.message : 'Unknown error';
86
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
87
+ }
88
+ });
89
+ server.tool('run-command', 'Run a shell command across all repos in a workspace (3 concurrent, 5min timeout)', {
90
+ workspace: wsName.describe('Name of the workspace'),
91
+ command: zod_1.z.string().describe('Shell command to run in each repo'),
92
+ }, async ({ workspace, command }) => {
93
+ try {
94
+ const result = await (0, tools_1.handleRunCommand)(workspace, command);
95
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
96
+ }
97
+ catch (error) {
98
+ const msg = error instanceof Error ? error.message : 'Unknown error';
99
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
100
+ }
101
+ });
102
+ server.tool('list-suites', 'List all saved suites (reusable repo collections) with their repo counts', {}, async () => {
103
+ try {
104
+ const result = await (0, tools_1.handleListSuites)();
105
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
106
+ }
107
+ catch (error) {
108
+ const msg = error instanceof Error ? error.message : 'Unknown error';
109
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
110
+ }
111
+ });
112
+ server.tool('workspace-info', 'Get detailed metadata for a workspace including all repository info, dependencies, and tags', { workspace: wsName.describe('Name of the workspace') }, async ({ workspace }) => {
113
+ try {
114
+ const result = await (0, tools_1.handleWorkspaceInfo)(workspace);
115
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
116
+ }
117
+ catch (error) {
118
+ const msg = error instanceof Error ? error.message : 'Unknown error';
119
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
120
+ }
121
+ });
122
+ server.tool('create-workspace', 'Create a new workspace by cloning specified repositories. Provide the workspace name and an array of repository names (e.g., ["api", "web", "shared-lib"]).', {
123
+ workspace: wsName.describe('Name of the workspace to create'),
124
+ repos: zod_1.z.array(zod_1.z.string()).describe('Array of repository names to clone'),
125
+ }, async ({ workspace, repos }) => {
126
+ try {
127
+ const result = await (0, tools_1.handleCreateWorkspace)(workspace, repos);
128
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
129
+ }
130
+ catch (error) {
131
+ const msg = error instanceof Error ? error.message : 'Unknown error';
132
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
133
+ }
134
+ });
135
+ server.tool('update-workspace', 'Add repositories to an existing workspace. Provide the workspace name and an array of repository names to add. Each entry can be a string (e.g., "partnerships-api") or an object with name and suffix (e.g., {"name": "partnerships-api", "suffix": "v2"}) to add the same repo again under a different directory name (partnerships-api-v2). Skips repos whose target directory name already exists in the workspace.', {
136
+ workspace: wsName.describe('Name of the existing workspace to update'),
137
+ repos: zod_1.z.array(zod_1.z.union([
138
+ zod_1.z.string(),
139
+ zod_1.z.object({
140
+ name: zod_1.z.string().describe('repository name'),
141
+ suffix: zod_1.z.string().describe('Suffix to append to directory name (e.g., "v2" creates "repo-name-v2")'),
142
+ }),
143
+ ])).describe('Array of repo names (strings) or objects with {name, suffix} for adding duplicate repos under a different directory'),
144
+ }, async ({ workspace, repos }) => {
145
+ try {
146
+ const result = await (0, tools_1.handleUpdateWorkspace)(workspace, repos);
147
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
148
+ }
149
+ catch (error) {
150
+ const msg = error instanceof Error ? error.message : 'Unknown error';
151
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
152
+ }
153
+ });
154
+ server.tool('search-repos', 'Search org repositories by name or description using fuzzy matching', {
155
+ query: zod_1.z.string().describe('Search query to match against repo names and descriptions'),
156
+ limit: zod_1.z.number().optional().default(20).describe('Maximum number of results to return'),
157
+ }, async ({ query, limit }) => {
158
+ try {
159
+ const result = await (0, tools_1.handleSearchRepos)(query, limit);
160
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
161
+ }
162
+ catch (error) {
163
+ const msg = error instanceof Error ? error.message : 'Unknown error';
164
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
165
+ }
166
+ });
167
+ server.tool('list-org-repos', 'List all organization repositories from GitHub', {
168
+ forceRefresh: zod_1.z.boolean().optional().default(false).describe('Force refresh the cached repo list'),
169
+ }, async ({ forceRefresh }) => {
170
+ try {
171
+ const result = await (0, tools_1.handleListOrgRepos)(forceRefresh);
172
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
173
+ }
174
+ catch (error) {
175
+ const msg = error instanceof Error ? error.message : 'Unknown error';
176
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
177
+ }
178
+ });
179
+ server.tool('delete-workspace', 'Delete one or more workspaces and all their contents permanently. Works even if a workspace has no repos or no metadata file.', {
180
+ workspaces: zod_1.z.union([
181
+ wsName,
182
+ zod_1.z.array(wsName),
183
+ ]).describe('Name of the workspace(s) to delete — a single string or an array of names'),
184
+ }, async ({ workspaces }) => {
185
+ try {
186
+ const result = await (0, tools_1.handleDeleteWorkspace)(workspaces);
187
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
188
+ }
189
+ catch (error) {
190
+ const msg = error instanceof Error ? error.message : 'Unknown error';
191
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
192
+ }
193
+ });
194
+ server.tool('remove-repo', 'Remove a repository from a workspace', {
195
+ workspace: wsName.describe('Name of the workspace'),
196
+ repo: zod_1.z.string().describe('Directory name of the repository to remove'),
197
+ }, async ({ workspace, repo }) => {
198
+ try {
199
+ const result = await (0, tools_1.handleRemoveRepo)(workspace, repo);
200
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
201
+ }
202
+ catch (error) {
203
+ const msg = error instanceof Error ? error.message : 'Unknown error';
204
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
205
+ }
206
+ });
207
+ server.tool('workspace-doctor', 'Run health checks on a workspace and return a health score (0-100)', {
208
+ workspace: wsName.describe('Name of the workspace to check'),
209
+ }, async ({ workspace }) => {
210
+ try {
211
+ const result = await (0, tools_1.handleWorkspaceDoctor)(workspace);
212
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
213
+ }
214
+ catch (error) {
215
+ const msg = error instanceof Error ? error.message : 'Unknown error';
216
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
217
+ }
218
+ });
219
+ server.tool('analyze-deps', 'Analyze inter-repository dependencies within a workspace and detect circular dependencies', {
220
+ workspace: wsName.describe('Name of the workspace to analyze'),
221
+ }, async ({ workspace }) => {
222
+ try {
223
+ const result = await (0, tools_1.handleAnalyzeDeps)(workspace);
224
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
225
+ }
226
+ catch (error) {
227
+ const msg = error instanceof Error ? error.message : 'Unknown error';
228
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
229
+ }
230
+ });
231
+ server.tool('branch-create', 'Create a new branch across all repos in a workspace', {
232
+ workspace: wsName.describe('Name of the workspace'),
233
+ branchName: zod_1.z.string().describe('Name of the new branch to create'),
234
+ baseBranch: zod_1.z.string().optional().describe('Base branch to create from (defaults to current branch)'),
235
+ }, async ({ workspace, branchName, baseBranch }) => {
236
+ try {
237
+ const result = await (0, tools_1.handleBranchCreate)(workspace, branchName, baseBranch);
238
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
239
+ }
240
+ catch (error) {
241
+ const msg = error instanceof Error ? error.message : 'Unknown error';
242
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
243
+ }
244
+ });
245
+ server.tool('switch-branch', 'Switch all repos in a workspace to a specified branch', {
246
+ workspace: wsName.describe('Name of the workspace'),
247
+ branch: zod_1.z.string().describe('Target branch to switch to'),
248
+ }, async ({ workspace, branch }) => {
249
+ try {
250
+ const result = await (0, tools_1.handleSwitchBranch)(workspace, branch);
251
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
252
+ }
253
+ catch (error) {
254
+ const msg = error instanceof Error ? error.message : 'Unknown error';
255
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
256
+ }
257
+ });
258
+ server.tool('workspace-cleanup', 'Remove node_modules and build artifacts from all repos in a workspace to free disk space', {
259
+ workspace: wsName.describe('Name of the workspace'),
260
+ includeNodeModules: zod_1.z.boolean().optional().default(true).describe('Remove node_modules directories'),
261
+ includeBuildArtifacts: zod_1.z.boolean().optional().default(true).describe('Remove build artifact directories (dist, build, .next, coverage, out)'),
262
+ }, async ({ workspace, includeNodeModules, includeBuildArtifacts }) => {
263
+ try {
264
+ const result = await (0, tools_1.handleWorkspaceCleanup)(workspace, includeNodeModules, includeBuildArtifacts);
265
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
266
+ }
267
+ catch (error) {
268
+ const msg = error instanceof Error ? error.message : 'Unknown error';
269
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
270
+ }
271
+ });
272
+ server.tool('update-cache', 'Force refresh the GitHub repository cache so newly added repos become searchable', {}, async () => {
273
+ try {
274
+ const result = await (0, tools_1.handleUpdateCache)();
275
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
276
+ }
277
+ catch (error) {
278
+ const msg = error instanceof Error ? error.message : 'Unknown error';
279
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
280
+ }
281
+ });
282
+ // --- Branch merge/rebase ---
283
+ server.tool('branch-merge', 'Merge a source branch into a target branch across all repos in a workspace', {
284
+ workspace: wsName.describe('Name of the workspace'),
285
+ sourceBranch: zod_1.z.string().describe('Branch to merge from'),
286
+ targetBranch: zod_1.z.string().describe('Branch to merge into'),
287
+ strategy: zod_1.z.enum(['no-ff', 'ff-only', 'squash']).optional().describe('Merge strategy'),
288
+ }, async ({ workspace, sourceBranch, targetBranch, strategy }) => {
289
+ try {
290
+ const result = await (0, tools_1.handleBranchMerge)(workspace, sourceBranch, targetBranch, strategy);
291
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
292
+ }
293
+ catch (error) {
294
+ const msg = error instanceof Error ? error.message : 'Unknown error';
295
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
296
+ }
297
+ });
298
+ server.tool('branch-rebase', 'Rebase all repos in a workspace onto a target branch', {
299
+ workspace: wsName.describe('Name of the workspace'),
300
+ targetBranch: zod_1.z.string().describe('Branch to rebase onto'),
301
+ }, async ({ workspace, targetBranch }) => {
302
+ try {
303
+ const result = await (0, tools_1.handleBranchRebase)(workspace, targetBranch);
304
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
305
+ }
306
+ catch (error) {
307
+ const msg = error instanceof Error ? error.message : 'Unknown error';
308
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
309
+ }
310
+ });
311
+ // --- Suite operations ---
312
+ server.tool('suite-create', 'Create a new suite (reusable collection of repositories)', {
313
+ name: zod_1.z.string().describe('Name for the new suite'),
314
+ repos: zod_1.z.array(zod_1.z.string()).describe('Array of repository names to include'),
315
+ description: zod_1.z.string().optional().describe('Optional description of the suite'),
316
+ }, async ({ name, repos, description }) => {
317
+ try {
318
+ const result = await (0, tools_1.handleSuiteCreate)(name, repos, description);
319
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
320
+ }
321
+ catch (error) {
322
+ const msg = error instanceof Error ? error.message : 'Unknown error';
323
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
324
+ }
325
+ });
326
+ server.tool('suite-delete', 'Delete a saved suite', {
327
+ name: zod_1.z.string().describe('Name of the suite to delete'),
328
+ }, async ({ name }) => {
329
+ try {
330
+ const result = await (0, tools_1.handleSuiteDelete)(name);
331
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
332
+ }
333
+ catch (error) {
334
+ const msg = error instanceof Error ? error.message : 'Unknown error';
335
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
336
+ }
337
+ });
338
+ server.tool('suite-export', 'Export suite(s) as JSON. Omit name to export all suites.', {
339
+ name: zod_1.z.string().optional().describe('Name of a specific suite to export (omit for all)'),
340
+ }, async ({ name }) => {
341
+ try {
342
+ const result = await (0, tools_1.handleSuiteExport)(name);
343
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
344
+ }
345
+ catch (error) {
346
+ const msg = error instanceof Error ? error.message : 'Unknown error';
347
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
348
+ }
349
+ });
350
+ server.tool('suite-import', 'Import suites from a JSON string (same format as suite-export output)', {
351
+ content: zod_1.z.string().describe('JSON string containing suites to import'),
352
+ overwrite: zod_1.z.boolean().optional().default(false).describe('Overwrite existing suites with same name'),
353
+ }, async ({ content, overwrite }) => {
354
+ try {
355
+ const result = await (0, tools_1.handleSuiteImport)(content, overwrite);
356
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
357
+ }
358
+ catch (error) {
359
+ const msg = error instanceof Error ? error.message : 'Unknown error';
360
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
361
+ }
362
+ });
363
+ server.tool('suite-use', 'Create a new workspace from a saved suite', {
364
+ suite: zod_1.z.string().describe('Name of the suite to use'),
365
+ workspace: wsName.describe('Name for the new workspace to create'),
366
+ }, async ({ suite, workspace }) => {
367
+ try {
368
+ const result = await (0, tools_1.handleSuiteUse)(suite, workspace);
369
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
370
+ }
371
+ catch (error) {
372
+ const msg = error instanceof Error ? error.message : 'Unknown error';
373
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
374
+ }
375
+ });
376
+ server.tool('save-context', 'Save a progress summary to the workspace. Use this to persist important context that should survive /clear or session restarts. The content is saved to CONTEXT.md in the workspace root.', {
377
+ workspace: wsName.describe('Name of the workspace'),
378
+ content: zod_1.z.string().describe('The progress summary or context to save (markdown supported)'),
379
+ append: zod_1.z.boolean().optional().describe('Append to existing context instead of replacing (default: false)'),
380
+ }, async ({ workspace, content, append }) => {
381
+ try {
382
+ const result = await (0, tools_1.handleSaveContext)(workspace, content, append);
383
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
384
+ }
385
+ catch (error) {
386
+ const msg = error instanceof Error ? error.message : 'Unknown error';
387
+ return { content: [{ type: 'text', text: `Error: ${msg}` }], isError: true };
388
+ }
389
+ });
390
+ async function main() {
391
+ const transport = new stdio_js_1.StdioServerTransport();
392
+ await server.connect(transport);
393
+ process.stderr.write('workspace-manager MCP server started\n');
394
+ }
395
+ main().catch((error) => {
396
+ process.stderr.write(`MCP server error: ${error}\n`);
397
+ process.exit(1);
398
+ });