@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,529 @@
1
+ #!/usr/bin/env ts-node
2
+
3
+ import { execSync } from 'child_process';
4
+ import * as path from 'path';
5
+ import * as fs from 'fs';
6
+ import { logSuccess, logError, logInfo, logWarning } from '../utils/logger';
7
+ import { colorize } from '../utils/colors';
8
+ import { installPermissionSyncHook, uninstallPermissionSyncHook, syncAllWorkspacePermissions, installWorkspaceSkills, uninstallWorkspaceSkills, installWorkspaceStatusLine, uninstallWorkspaceStatusLine } from '../utils/permission-sync';
9
+ import { WORKSPACES_DIR, getUserConfig } from '../utils/config';
10
+ import { generateMcpConfig, backfillAgentRules } from '../utils/claude-integration';
11
+ import { listWorkspaces } from '../utils/workspace-meta';
12
+ import { getActiveAgents, isAgentCliAvailable, getMcpAgents } from '../utils/agent-config';
13
+ import { installPiExtensions, uninstallPiExtensions, getPiExtensionStatus } from '../utils/pi-extensions';
14
+ import { checkForUpdate } from '../utils/version-check';
15
+
16
+ /**
17
+ * Install shell integration (w/workspace shell functions for auto-CD).
18
+ * Non-interactive and idempotent — safe to call from postinstall or mcp install.
19
+ */
20
+ function installShellIntegration(): void {
21
+ const shell = process.env.SHELL || '';
22
+ let shellType: string;
23
+
24
+ if (shell.endsWith('/zsh')) {
25
+ shellType = 'zsh';
26
+ } else if (shell.endsWith('/bash')) {
27
+ shellType = 'bash';
28
+ } else {
29
+ logInfo('Unknown shell — skipping shell integration (auto-CD)');
30
+ return;
31
+ }
32
+
33
+ const scriptPath = path.join(__dirname, '..', '..', 'install-shell-integration.sh');
34
+ if (!fs.existsSync(scriptPath)) {
35
+ logInfo('Shell integration script not found — skipping');
36
+ return;
37
+ }
38
+
39
+ try {
40
+ execSync(`bash "${scriptPath}" ${shellType}`, { stdio: 'inherit' });
41
+ logSuccess('Shell integration installed (auto-CD for w/workspace commands)');
42
+ } catch {
43
+ logInfo('Shell integration install skipped (non-critical)');
44
+ }
45
+
46
+ // Print a prominent reminder — without sourcing, the shell function is
47
+ // not active in the current session and 'w' resolves to the system binary.
48
+ const rcFile = shellType === 'zsh' ? '~/.zshrc' : '~/.bashrc';
49
+ console.log('');
50
+ console.log(' \x1b[33m⚠️ IMPORTANT — activate the shell function in this session:\x1b[0m');
51
+ console.log('');
52
+ console.log(` \x1b[36msource ${rcFile}\x1b[0m`);
53
+ console.log('');
54
+ console.log(' Or open a new terminal tab. Until then, \x1b[36mw\x1b[0m resolves to the');
55
+ console.log(' Unix \x1b[90mw\x1b[0m command (shows logged-in users), not workspace manager.');
56
+ console.log('');
57
+ console.log(' Tip: \x1b[36mworkspace\x1b[0m works immediately without sourcing:');
58
+ console.log(' \x1b[36mworkspace configure\x1b[0m \x1b[90m# first-time setup\x1b[0m');
59
+ console.log(' \x1b[36mworkspace list\x1b[0m \x1b[90m# list workspaces\x1b[0m');
60
+ console.log('');
61
+ }
62
+
63
+ function getMcpServerPath(): string {
64
+ // When compiled, __dirname is dist/mcp/ — server.js is a sibling
65
+ const distPath = path.join(__dirname, 'server.js');
66
+ // When running from ts-node, __dirname is src/mcp/ — compiled output is at dist/mcp/server.js
67
+ const srcPath = path.join(__dirname, '..', '..', 'dist', 'mcp', 'server.js');
68
+
69
+ if (fs.existsSync(distPath)) {
70
+ return distPath;
71
+ }
72
+ if (fs.existsSync(srcPath)) {
73
+ return srcPath;
74
+ }
75
+
76
+ throw new Error(
77
+ 'Could not find mcp-server.js. Make sure to run `npm run build` first.'
78
+ );
79
+ }
80
+
81
+ /**
82
+ * Install/update hooks and skills (idempotent).
83
+ * Shared by both `install` and `upgrade` commands.
84
+ */
85
+ function installHooksAndSkills() {
86
+ const agents = getActiveAgents();
87
+ const claudeActive = agents.some(a => a.type === 'claude');
88
+ const piActive = agents.some(a => a.type === 'pi');
89
+ const config = getUserConfig();
90
+
91
+ // Claude-specific hooks (only install if Claude is active)
92
+ if (claudeActive) {
93
+ // Install permission sync hook
94
+ try {
95
+ installPermissionSyncHook();
96
+ } catch (error) {
97
+ logError('Failed to install permission sync hook');
98
+ if (error instanceof Error) {
99
+ logError(error.message);
100
+ }
101
+ }
102
+
103
+ // Install workspace repo-table status line (only if enabled in config)
104
+ if (config.claudeWorkspaceStatusLine !== false) {
105
+ try {
106
+ installWorkspaceStatusLine();
107
+ } catch (error) {
108
+ logError('Failed to install workspace status-line');
109
+ if (error instanceof Error) logError(error.message);
110
+ }
111
+ } else {
112
+ // Opt-out: remove any previously installed status line
113
+ try { uninstallWorkspaceStatusLine(); } catch { /* ignore */ }
114
+ }
115
+ }
116
+
117
+ // Install workspace-manager skills (MCP + CLI command skills) — always for all active agents
118
+ try {
119
+ installWorkspaceSkills();
120
+ } catch (error) {
121
+ logError('Failed to install workspace-manager skills');
122
+ if (error instanceof Error) {
123
+ logError(error.message);
124
+ }
125
+ }
126
+
127
+ // Install Pi extensions (if Pi is an active agent)
128
+ if (piActive) {
129
+ try {
130
+ installPiExtensions(undefined, { workspaceInputStatus: config.piWorkspaceInputStatus !== false });
131
+ } catch (error) {
132
+ logError('Failed to install Pi extensions');
133
+ if (error instanceof Error) {
134
+ logError(error.message);
135
+ }
136
+ }
137
+ // If input-status widget is disabled, remove any previously installed copy
138
+ if (config.piWorkspaceInputStatus === false) {
139
+ try { uninstallPiExtensions(undefined, { onlyNames: ['ws-workspace-input-status.ts'] }); } catch { /* ignore */ }
140
+ }
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Backfill .mcp.json for all existing workspaces that don't have the
146
+ * workspace-manager entry yet.
147
+ */
148
+ async function backfillMcpJson() {
149
+ const { installMcp } = getUserConfig();
150
+ if (!installMcp) return;
151
+
152
+ try {
153
+ const workspaces = await listWorkspaces(false);
154
+ if (workspaces.length === 0) return;
155
+
156
+ logInfo(`Backfilling .mcp.json for ${workspaces.length} existing workspace(s)...`);
157
+ let updated = 0;
158
+
159
+ for (const ws of workspaces) {
160
+ const success = await generateMcpConfig(ws.path);
161
+ if (success) updated++;
162
+ }
163
+
164
+ if (updated > 0) {
165
+ logSuccess(`Updated .mcp.json in ${updated} workspace(s)`);
166
+ }
167
+ } catch (error) {
168
+ logWarning('Could not backfill .mcp.json for existing workspaces');
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Backfill AGENTS.md (Pi context file) for existing workspaces that only
174
+ * have .claude.md. Runs during install/upgrade when Pi is an active agent.
175
+ * Also patches in the "AI Agent Rules" section for any context file that
176
+ * pre-dates it (idempotent).
177
+ */
178
+ async function backfillAgentsContext() {
179
+ const agents = getActiveAgents();
180
+ const piActive = agents.some(a => a.type === 'pi');
181
+ const claudeActive = agents.some(a => a.type === 'claude');
182
+
183
+ try {
184
+ const workspaces = await listWorkspaces(false);
185
+ if (workspaces.length === 0) return;
186
+
187
+ let converted = 0;
188
+ let claudeRenamed = 0;
189
+ let rulesPatched = 0;
190
+
191
+ for (const ws of workspaces) {
192
+ const agentsMdPath = path.join(ws.path, 'AGENTS.md');
193
+ const claudeMdPath = path.join(ws.path, '.claude.md');
194
+ const claudeMdUpper = path.join(ws.path, 'CLAUDE.md');
195
+
196
+ // Convert .claude.md → AGENTS.md for Pi users (original backfill behaviour)
197
+ if (piActive && fs.existsSync(claudeMdPath) && !fs.existsSync(agentsMdPath)) {
198
+ try {
199
+ const content = fs.readFileSync(claudeMdPath, 'utf-8');
200
+ const fixed = content.replace(/\.claude\.md/g, 'AGENTS.md');
201
+ fs.writeFileSync(agentsMdPath, fixed, 'utf-8');
202
+ converted++;
203
+ } catch { /* skip on error */ }
204
+ }
205
+
206
+ // Migrate the dead hidden .claude.md → CLAUDE.md for Claude users (issue
207
+ // #186): Claude Code never auto-loaded '.claude.md', so the workspace
208
+ // context never surfaced. Create the correctly-named CLAUDE.md (unless
209
+ // one already exists — don't clobber a real one) and remove the dead file.
210
+ // The pi conversion above already ran, so AGENTS.md is preserved.
211
+ if (claudeActive && fs.existsSync(claudeMdPath) && !fs.existsSync(claudeMdUpper)) {
212
+ try {
213
+ const content = fs.readFileSync(claudeMdPath, 'utf-8');
214
+ const fixed = content.replace(/\.claude\.md/g, 'CLAUDE.md');
215
+ fs.writeFileSync(claudeMdUpper, fixed, 'utf-8');
216
+ fs.rmSync(claudeMdPath, { force: true });
217
+ claudeRenamed++;
218
+ } catch { /* skip on error */ }
219
+ }
220
+
221
+ // Patch the AI Agent Rules section into any existing context file that
222
+ // was created before this section was introduced (idempotent).
223
+ try {
224
+ const wsName = ws.name;
225
+ const n = await backfillAgentRules(ws.path, wsName);
226
+ rulesPatched += n;
227
+ } catch { /* non-critical */ }
228
+ }
229
+
230
+ if (converted > 0) {
231
+ logSuccess(`Backfilled AGENTS.md in ${converted} workspace(s) for Pi compatibility`);
232
+ }
233
+ if (claudeRenamed > 0) {
234
+ logSuccess(`Migrated .claude.md → CLAUDE.md in ${claudeRenamed} workspace(s) so Claude Code auto-loads it`);
235
+ }
236
+ if (rulesPatched > 0) {
237
+ logSuccess(`Added AI Agent Rules section to ${rulesPatched} workspace context file(s)`);
238
+ }
239
+ } catch (error) {
240
+ logWarning('Could not backfill AGENTS.md for existing workspaces');
241
+ }
242
+ }
243
+
244
+ async function install() {
245
+ const agents = getActiveAgents();
246
+ const mcpAgents = getMcpAgents();
247
+
248
+ // Check that at least one configured agent CLI is available
249
+ const availableAgents = agents.filter(a => isAgentCliAvailable(a.type));
250
+ if (availableAgents.length === 0) {
251
+ logError('No configured AI agent CLI found. Install at least one:');
252
+ for (const a of agents) {
253
+ if (a.type === 'claude') console.log(' npm install -g @anthropic-ai/claude-code');
254
+ if (a.type === 'pi') console.log(' npm install -g @earendil-works/pi-coding-agent');
255
+ if (a.type === 'opencode') console.log(' npm install -g opencode-ai');
256
+ }
257
+ process.exit(1);
258
+ }
259
+
260
+ // Register MCP server with Claude Code (only agent that supports MCP CLI registration)
261
+ const claudeAgent = mcpAgents.find(a => a.type === 'claude');
262
+ if (claudeAgent && isAgentCliAvailable('claude')) {
263
+ const serverPath = getMcpServerPath();
264
+ logInfo(`MCP server path: ${colorize(serverPath, 'cyan')}`);
265
+
266
+ try {
267
+ execSync(
268
+ `claude mcp add workspace-manager -s user -- node "${serverPath}"`,
269
+ { stdio: 'pipe' }
270
+ );
271
+ logSuccess('MCP server registered globally with Claude Code');
272
+ console.log('\nYou can now use workspace-manager tools in any Claude Code session.');
273
+ console.log('Try asking: "list my workspaces" or "what\'s the status of my-workspace"');
274
+ } catch (error) {
275
+ const stderr = error instanceof Error && 'stderr' in error
276
+ ? String((error as { stderr: unknown }).stderr)
277
+ : '';
278
+ if (stderr.includes('already exists') || (error instanceof Error && error.message.includes('already exists'))) {
279
+ logInfo('MCP server already registered with Claude Code — skipping');
280
+ } else {
281
+ logError('Failed to register MCP server with Claude Code');
282
+ if (error instanceof Error) {
283
+ logError(error.message);
284
+ }
285
+ }
286
+ }
287
+ } else if (mcpAgents.length > 0) {
288
+ logInfo('Claude Code CLI not found — skipping MCP registration');
289
+ }
290
+
291
+ // Log Pi-specific info
292
+ const piAgent = agents.find(a => a.type === 'pi');
293
+ if (piAgent) {
294
+ logInfo('Pi uses extensions instead of MCP — skills will be installed to ' + piAgent.skillsDir);
295
+ }
296
+
297
+ // Log OpenCode-specific info
298
+ const opencodeAgent = agents.find(a => a.type === 'opencode');
299
+ if (opencodeAgent) {
300
+ logInfo('OpenCode supports MCP natively — configure in .opencode/opencode.jsonc');
301
+ logInfo('Skills will be installed to ' + opencodeAgent.skillsDir);
302
+ }
303
+
304
+ installHooksAndSkills();
305
+ installShellIntegration();
306
+ await backfillMcpJson();
307
+ await backfillAgentsContext();
308
+ }
309
+
310
+ async function upgrade() {
311
+ // Warn immediately if a newer package version is available.
312
+ // This is the most common reason extensions are missing after
313
+ // running upgrade — the user upgraded npm but didn't re-install.
314
+ const updateMsg = await checkForUpdate();
315
+ if (updateMsg) {
316
+ console.log('');
317
+ console.log(updateMsg);
318
+ console.log('\x1b[33m ⚠️ Run npm install first, then re-run w mcp upgrade to get new features.\x1b[0m');
319
+ console.log('');
320
+ }
321
+
322
+ const agents = getActiveAgents();
323
+ const availableAgents = agents.filter(a => isAgentCliAvailable(a.type));
324
+
325
+ if (availableAgents.length === 0) {
326
+ logError('No configured AI agent CLI found. Install at least one:');
327
+ for (const a of agents) {
328
+ if (a.type === 'claude') console.log(' npm install -g @anthropic-ai/claude-code');
329
+ if (a.type === 'pi') console.log(' npm install -g @earendil-works/pi-coding-agent');
330
+ if (a.type === 'opencode') console.log(' npm install -g opencode-ai');
331
+ }
332
+ process.exit(1);
333
+ }
334
+
335
+ logInfo(`Upgrading hooks and skills for: ${availableAgents.map(a => a.type).join(', ')}...`);
336
+ installHooksAndSkills();
337
+ installShellIntegration();
338
+ await backfillMcpJson();
339
+ await backfillAgentsContext();
340
+ logSuccess('Upgrade complete');
341
+ }
342
+
343
+ function uninstall() {
344
+ // Remove workspace-manager skills (from all agent directories)
345
+ try {
346
+ uninstallWorkspaceSkills();
347
+ logSuccess('Workspace-manager skills removed from all agents');
348
+ } catch (error) {
349
+ logError('Failed to remove workspace-manager skills');
350
+ if (error instanceof Error) {
351
+ logError(error.message);
352
+ }
353
+ }
354
+
355
+ // Remove Pi extensions
356
+ try {
357
+ uninstallPiExtensions();
358
+ logSuccess('Pi extensions removed');
359
+ } catch (error) {
360
+ logError('Failed to remove Pi extensions');
361
+ if (error instanceof Error) {
362
+ logError(error.message);
363
+ }
364
+ }
365
+
366
+ // Remove workspace status-line (Claude Code statusLine + script)
367
+ try {
368
+ uninstallWorkspaceStatusLine();
369
+ } catch (error) {
370
+ logError('Failed to remove workspace status-line');
371
+ if (error instanceof Error) logError(error.message);
372
+ }
373
+
374
+ // Remove permission sync hook
375
+ try {
376
+ uninstallPermissionSyncHook();
377
+ } catch (error) {
378
+ logError('Failed to remove permission sync hook');
379
+ if (error instanceof Error) {
380
+ logError(error.message);
381
+ }
382
+ }
383
+
384
+ // Unregister MCP from Claude (if available)
385
+ if (isAgentCliAvailable('claude')) {
386
+ try {
387
+ execSync('claude mcp remove workspace-manager -s user', { stdio: 'inherit' });
388
+ logSuccess('MCP server unregistered from Claude Code');
389
+ } catch (error) {
390
+ logError('Failed to unregister MCP server');
391
+ if (error instanceof Error) {
392
+ logError(error.message);
393
+ }
394
+ }
395
+ } else {
396
+ logInfo('Claude Code CLI not found — skipping MCP unregistration');
397
+ }
398
+ }
399
+
400
+ function status() {
401
+ const agents = getActiveAgents();
402
+ let anyFound = false;
403
+
404
+ for (const agent of agents) {
405
+ console.log(`\n${colorize(agent.type.toUpperCase(), 'bright')}:`);
406
+
407
+ if (!isAgentCliAvailable(agent.type)) {
408
+ logInfo(` ${agent.type} CLI not found`);
409
+ continue;
410
+ }
411
+
412
+ anyFound = true;
413
+
414
+ // Check skills installation
415
+ const skillsExist = fs.existsSync(agent.skillsDir);
416
+ if (skillsExist) {
417
+ const skillCount = fs.readdirSync(agent.skillsDir).filter(d => {
418
+ const skillPath = path.join(agent.skillsDir, d, 'SKILL.md');
419
+ return fs.existsSync(skillPath);
420
+ }).length;
421
+ logSuccess(` ${skillCount} skills installed in ${agent.skillsDir}`);
422
+ } else {
423
+ logInfo(` No skills directory at ${agent.skillsDir}`);
424
+ }
425
+
426
+ // Check MCP (Claude only)
427
+ if (agent.supportsMcp) {
428
+ try {
429
+ const output = execSync('claude mcp list', { encoding: 'utf-8' });
430
+ const isRegistered = output.includes('workspace-manager');
431
+ if (isRegistered) {
432
+ logSuccess(' MCP server registered');
433
+ const lines = output.split('\n').filter(l => l.includes('workspace-manager'));
434
+ if (lines.length > 0) {
435
+ console.log(` ${lines[0].trim()}`);
436
+ }
437
+ } else {
438
+ logInfo(' MCP server not registered');
439
+ console.log(' Run: w mcp install');
440
+ }
441
+ } catch (error) {
442
+ logError(' Failed to check MCP status');
443
+ }
444
+ } else {
445
+ logInfo(` ${agent.type} uses extensions instead of MCP`);
446
+ // Show Pi extension status
447
+ const extStatus = getPiExtensionStatus();
448
+ if (extStatus.installed.length > 0) {
449
+ logSuccess(` ${extStatus.installed.length} managed extension(s) installed`);
450
+ for (const ext of extStatus.installed) {
451
+ console.log(` ✓ ${ext}`);
452
+ }
453
+ }
454
+ if (extStatus.missing.length > 0) {
455
+ logWarning(` ${extStatus.missing.length} managed extension(s) missing`);
456
+ for (const ext of extStatus.missing) {
457
+ console.log(` ✗ ${ext}`);
458
+ }
459
+ console.log(' Run: w mcp install');
460
+ }
461
+ }
462
+ }
463
+
464
+ if (!anyFound) {
465
+ logError('No configured AI agent CLI found');
466
+ process.exit(1);
467
+ }
468
+ }
469
+
470
+ function syncPermissions() {
471
+ logInfo('Scanning workspaces for permissions to sync...');
472
+ syncAllWorkspacePermissions(WORKSPACES_DIR);
473
+ }
474
+
475
+ function updateSkills() {
476
+ logInfo('Updating workspace-manager skills...');
477
+ try {
478
+ installWorkspaceSkills();
479
+ } catch (error) {
480
+ logError('Failed to update skills');
481
+ if (error instanceof Error) {
482
+ logError(error.message);
483
+ }
484
+ process.exit(1);
485
+ }
486
+ }
487
+
488
+ export async function main(subCommandArg?: string) {
489
+ const subCommand = subCommandArg ?? process.argv[2];
490
+
491
+ switch (subCommand) {
492
+ case 'install':
493
+ await install();
494
+ break;
495
+ case 'uninstall':
496
+ uninstall();
497
+ break;
498
+ case 'upgrade':
499
+ await upgrade();
500
+ break;
501
+ case 'status':
502
+ status();
503
+ break;
504
+ case 'sync-permissions':
505
+ syncPermissions();
506
+ break;
507
+ case 'update-skills':
508
+ updateSkills();
509
+ break;
510
+ default:
511
+ console.log(`
512
+ MCP Integration
513
+
514
+ Usage:
515
+ w mcp install Register workspace-manager MCP server with Claude Code
516
+ w mcp uninstall Unregister the MCP server
517
+ w mcp upgrade Update hooks and skills without re-registering the MCP server
518
+ w mcp update-skills Update only the Claude Code skills (faster than full upgrade)
519
+ w mcp status Check if the MCP server is registered
520
+ w mcp sync-permissions Merge all workspace permissions into global settings
521
+ `);
522
+ break;
523
+ }
524
+ }
525
+
526
+ // Auto-execute only when run directly (not when imported by Commander)
527
+ if (require.main === module) {
528
+ main().catch(err => { logError(err.message); process.exit(1); });
529
+ }