@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.
- package/CHANGELOG.md +86 -0
- package/LICENSE +21 -0
- package/README.md +275 -0
- package/assets/README.md +53 -0
- package/assets/banner.png +0 -0
- package/assets/banner.svg +66 -0
- package/assets/favicon-32.png +0 -0
- package/assets/favicon-64.png +0 -0
- package/assets/icon-256.png +0 -0
- package/assets/icon.svg +23 -0
- package/assets/logo-256.png +0 -0
- package/assets/logo-512.png +0 -0
- package/assets/logo-wordmark.svg +35 -0
- package/assets/logo.svg +32 -0
- package/bin/workspace.js +130 -0
- package/dist/cli/ai-prompt.js +421 -0
- package/dist/cli/dashboard/AgentList.js +61 -0
- package/dist/cli/dashboard/DashboardSidebar.js +280 -0
- package/dist/cli/dashboard/HelpFooter.js +73 -0
- package/dist/cli/dashboard/StatusBadge.js +50 -0
- package/dist/cli/dashboard/index.js +11 -0
- package/dist/cli/dashboard/types.js +2 -0
- package/dist/cli/tui.js +48 -0
- package/dist/commands/ai-prompt.js +22 -0
- package/dist/commands/analyze-deps.js +138 -0
- package/dist/commands/archive.js +113 -0
- package/dist/commands/branch/create.js +119 -0
- package/dist/commands/branch/index.js +104 -0
- package/dist/commands/branch/merge.js +90 -0
- package/dist/commands/branch/rebase.js +84 -0
- package/dist/commands/branch/switch.js +165 -0
- package/dist/commands/cache/index.js +80 -0
- package/dist/commands/cache/manager.js +198 -0
- package/dist/commands/cleanup.js +153 -0
- package/dist/commands/configure-claude.js +55 -0
- package/dist/commands/configure.js +231 -0
- package/dist/commands/create.js +204 -0
- package/dist/commands/dashboard/hook-handler.js +162 -0
- package/dist/commands/dashboard/index.js +258 -0
- package/dist/commands/dashboard/launcher.js +40 -0
- package/dist/commands/dashboard/session-picker.js +106 -0
- package/dist/commands/dashboard/sidebar.js +39 -0
- package/dist/commands/dashboard/workspace-picker.js +95 -0
- package/dist/commands/delete.js +194 -0
- package/dist/commands/deprecated-aliases.js +44 -0
- package/dist/commands/diff.js +129 -0
- package/dist/commands/doctor.js +141 -0
- package/dist/commands/generate-docs.js +77 -0
- package/dist/commands/ghq-status.js +72 -0
- package/dist/commands/go.js +154 -0
- package/dist/commands/history.js +124 -0
- package/dist/commands/list.js +191 -0
- package/dist/commands/mcp/index.js +69 -0
- package/dist/commands/migrate.js +296 -0
- package/dist/commands/remove-repo.js +217 -0
- package/dist/commands/report-bug.js +112 -0
- package/dist/commands/run.js +147 -0
- package/dist/commands/save-context.js +171 -0
- package/dist/commands/sessions.js +129 -0
- package/dist/commands/status.js +138 -0
- package/dist/commands/suite/create.js +212 -0
- package/dist/commands/suite/delete.js +64 -0
- package/dist/commands/suite/export.js +126 -0
- package/dist/commands/suite/import.js +128 -0
- package/dist/commands/suite/index.js +94 -0
- package/dist/commands/suite/list.js +49 -0
- package/dist/commands/suite/use.js +227 -0
- package/dist/commands/sync.js +117 -0
- package/dist/commands/update.js +203 -0
- package/dist/mcp/install.js +550 -0
- package/dist/mcp/server.js +398 -0
- package/dist/mcp/tools.js +922 -0
- package/dist/pi-extensions/permission-sync.ts.template +41 -0
- package/dist/pi-extensions/permissions-gate.ts.template +69 -0
- package/dist/pi-extensions/pr-fix-trigger.ts.template +124 -0
- package/dist/pi-extensions/review-reminder.ts.template +58 -0
- package/dist/pi-extensions/workspace-input-status.ts.template +919 -0
- package/dist/program.js +136 -0
- package/dist/scripts/workspace-table.py +394 -0
- package/dist/types/dashboard.js +11 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/agent-config.js +263 -0
- package/dist/utils/agent-state.js +178 -0
- package/dist/utils/banner.js +24 -0
- package/dist/utils/branch-operations.js +232 -0
- package/dist/utils/bug-report.js +355 -0
- package/dist/utils/cache.js +168 -0
- package/dist/utils/claude-integration.js +617 -0
- package/dist/utils/claude-sessions.js +260 -0
- package/dist/utils/cleanup-operations.js +120 -0
- package/dist/utils/colors.js +26 -0
- package/dist/utils/command-helpers.js +44 -0
- package/dist/utils/config.js +150 -0
- package/dist/utils/context-file.js +33 -0
- package/dist/utils/dashboard-hooks.js +172 -0
- package/dist/utils/dependency-analyzer.js +234 -0
- package/dist/utils/diff-operations.js +80 -0
- package/dist/utils/doc-generator.js +184 -0
- package/dist/utils/ghq-integration.js +332 -0
- package/dist/utils/git-operations.js +237 -0
- package/dist/utils/git-status.js +187 -0
- package/dist/utils/github.js +68 -0
- package/dist/utils/health-checks.js +345 -0
- package/dist/utils/history.js +150 -0
- package/dist/utils/hooks.js +100 -0
- package/dist/utils/logger.js +40 -0
- package/dist/utils/permission-sync.js +681 -0
- package/dist/utils/pi-extensions.js +224 -0
- package/dist/utils/progress.js +92 -0
- package/dist/utils/prompts.js +279 -0
- package/dist/utils/repo-resolver.js +260 -0
- package/dist/utils/retry.js +65 -0
- package/dist/utils/run-operations.js +30 -0
- package/dist/utils/suite.js +159 -0
- package/dist/utils/sync-operations.js +107 -0
- package/dist/utils/tmux-dashboard.js +184 -0
- package/dist/utils/validation.js +153 -0
- package/dist/utils/version-check.js +121 -0
- package/dist/utils/workspace-meta.js +185 -0
- package/install-shell-integration.sh +532 -0
- package/install.sh +401 -0
- package/package.json +90 -0
- package/remove-shell-block.awk +44 -0
- package/scripts/postinstall.js +85 -0
- package/skills/analyze-deps.md +23 -0
- package/skills/archive-workspace.md +26 -0
- package/skills/branch-create.md +18 -0
- package/skills/create-workspace.md +39 -0
- package/skills/delete-workspace.md +37 -0
- package/skills/list-org-repos.md +26 -0
- package/skills/list-suites.md +24 -0
- package/skills/list-workspaces.md +27 -0
- package/skills/refresh-workspace-docs.md +89 -0
- package/skills/remove-repo.md +25 -0
- package/skills/run-command.md +23 -0
- package/skills/save-context.md +68 -0
- package/skills/search-repos.md +31 -0
- package/skills/snapshot-list.md +18 -0
- package/skills/snapshot-save.md +12 -0
- package/skills/switch-branch.md +18 -0
- package/skills/update-cache.md +21 -0
- package/skills/update-workspace.md +66 -0
- package/skills/workspace-cleanup.md +18 -0
- package/skills/workspace-diff.md +23 -0
- package/skills/workspace-doctor.md +23 -0
- package/skills/workspace-info.md +45 -0
- package/skills/workspace-manager/SKILL.md +201 -0
- package/skills/workspace-manager/references/ai-prompt.md +44 -0
- package/skills/workspace-manager/references/analyze-deps.md +45 -0
- package/skills/workspace-manager/references/archive-workspace.md +38 -0
- package/skills/workspace-manager/references/branch-create.md +31 -0
- package/skills/workspace-manager/references/branch-merge.md +22 -0
- package/skills/workspace-manager/references/branch-rebase.md +22 -0
- package/skills/workspace-manager/references/cache-clear.md +18 -0
- package/skills/workspace-manager/references/cache-info.md +22 -0
- package/skills/workspace-manager/references/configure-claude.md +31 -0
- package/skills/workspace-manager/references/configure.md +35 -0
- package/skills/workspace-manager/references/create-workspace.md +45 -0
- package/skills/workspace-manager/references/dashboard.md +61 -0
- package/skills/workspace-manager/references/delete-workspace.md +33 -0
- package/skills/workspace-manager/references/generate-docs.md +36 -0
- package/skills/workspace-manager/references/ghq-status.md +28 -0
- package/skills/workspace-manager/references/go.md +33 -0
- package/skills/workspace-manager/references/history.md +41 -0
- package/skills/workspace-manager/references/list-org-repos.md +26 -0
- package/skills/workspace-manager/references/list-suites.md +21 -0
- package/skills/workspace-manager/references/list-workspaces.md +27 -0
- package/skills/workspace-manager/references/mcp.md +49 -0
- package/skills/workspace-manager/references/remove-repo.md +26 -0
- package/skills/workspace-manager/references/run-command.md +44 -0
- package/skills/workspace-manager/references/search-repos.md +24 -0
- package/skills/workspace-manager/references/sessions.md +27 -0
- package/skills/workspace-manager/references/suite-create.md +22 -0
- package/skills/workspace-manager/references/suite-delete.md +21 -0
- package/skills/workspace-manager/references/suite-export.md +19 -0
- package/skills/workspace-manager/references/suite-import.md +19 -0
- package/skills/workspace-manager/references/suite-use.md +27 -0
- package/skills/workspace-manager/references/switch-branch.md +25 -0
- package/skills/workspace-manager/references/update-cache.md +22 -0
- package/skills/workspace-manager/references/update-workspace.md +50 -0
- package/skills/workspace-manager/references/workspace-cleanup.md +33 -0
- package/skills/workspace-manager/references/workspace-diff.md +27 -0
- package/skills/workspace-manager/references/workspace-doctor.md +27 -0
- package/skills/workspace-manager/references/workspace-info.md +33 -0
- package/skills/workspace-manager/references/workspace-status.md +43 -0
- package/skills/workspace-manager/references/workspace-sync.md +26 -0
- package/skills/workspace-status.md +26 -0
- package/skills/workspace-sync.md +23 -0
- package/src/cli/ai-prompt.test.ts +667 -0
- package/src/cli/ai-prompt.ts +421 -0
- package/src/cli/dashboard/AgentList.tsx +44 -0
- package/src/cli/dashboard/DashboardSidebar.tsx +291 -0
- package/src/cli/dashboard/HelpFooter.tsx +22 -0
- package/src/cli/dashboard/StatusBadge.tsx +23 -0
- package/src/cli/dashboard/index.ts +5 -0
- package/src/cli/dashboard/types.ts +16 -0
- package/src/cli/tui.tsx +51 -0
- package/src/cli/workspace-cli.test.ts +30 -0
- package/src/commands/ai-prompt.ts +21 -0
- package/src/commands/analyze-deps.ts +119 -0
- package/src/commands/archive.ts +114 -0
- package/src/commands/branch/create.ts +94 -0
- package/src/commands/branch/index.ts +74 -0
- package/src/commands/branch/merge.ts +61 -0
- package/src/commands/branch/rebase.ts +54 -0
- package/src/commands/branch/switch.ts +150 -0
- package/src/commands/cache/index.ts +51 -0
- package/src/commands/cache/manager.ts +168 -0
- package/src/commands/cleanup.ts +132 -0
- package/src/commands/configure-claude.ts +55 -0
- package/src/commands/configure.ts +204 -0
- package/src/commands/create.ts +196 -0
- package/src/commands/dashboard/hook-handler.ts +138 -0
- package/src/commands/dashboard/index.ts +248 -0
- package/src/commands/dashboard/launcher.ts +42 -0
- package/src/commands/dashboard/session-picker.ts +73 -0
- package/src/commands/dashboard/sidebar.js +39 -0
- package/src/commands/dashboard/workspace-picker.ts +62 -0
- package/src/commands/delete.test.ts +250 -0
- package/src/commands/delete.ts +171 -0
- package/src/commands/deprecated-aliases.ts +55 -0
- package/src/commands/diff.ts +106 -0
- package/src/commands/doctor.ts +110 -0
- package/src/commands/generate-docs.ts +45 -0
- package/src/commands/ghq-status.ts +70 -0
- package/src/commands/go.ts +125 -0
- package/src/commands/history.ts +136 -0
- package/src/commands/list.test.ts +219 -0
- package/src/commands/list.ts +176 -0
- package/src/commands/mcp/index.ts +39 -0
- package/src/commands/migrate.ts +277 -0
- package/src/commands/remove-repo.ts +194 -0
- package/src/commands/report-bug.ts +88 -0
- package/src/commands/run.ts +125 -0
- package/src/commands/save-context.test.ts +113 -0
- package/src/commands/save-context.ts +141 -0
- package/src/commands/sessions.ts +99 -0
- package/src/commands/status.ts +111 -0
- package/src/commands/suite/create.ts +240 -0
- package/src/commands/suite/delete.ts +65 -0
- package/src/commands/suite/export.ts +97 -0
- package/src/commands/suite/import.ts +100 -0
- package/src/commands/suite/index.ts +66 -0
- package/src/commands/suite/list.ts +54 -0
- package/src/commands/suite/use.ts +232 -0
- package/src/commands/sync.ts +97 -0
- package/src/commands/update.ts +197 -0
- package/src/mcp/install.ts +529 -0
- package/src/mcp/server.ts +579 -0
- package/src/mcp/tools.test.ts +545 -0
- package/src/mcp/tools.ts +1019 -0
- package/src/mcp/update-workspace.test.ts +220 -0
- package/src/pi-extensions/permission-sync.ts.template +41 -0
- package/src/pi-extensions/permissions-gate.ts.template +69 -0
- package/src/pi-extensions/pr-fix-trigger.ts.template +124 -0
- package/src/pi-extensions/review-reminder.ts.template +58 -0
- package/src/pi-extensions/workspace-input-status.ts.template +919 -0
- package/src/program.ts +112 -0
- package/src/scripts/workspace-table.py +394 -0
- package/src/types/dashboard.ts +29 -0
- package/src/types/index.ts +109 -0
- package/src/types/ink.d.ts +171 -0
- package/src/utils/agent-config.test.ts +303 -0
- package/src/utils/agent-config.ts +264 -0
- package/src/utils/agent-state.test.ts +166 -0
- package/src/utils/agent-state.ts +135 -0
- package/src/utils/banner.ts +24 -0
- package/src/utils/branch-operations.ts +237 -0
- package/src/utils/bug-report.test.ts +174 -0
- package/src/utils/bug-report.ts +355 -0
- package/src/utils/cache.ts +150 -0
- package/src/utils/claude-integration.test.ts +381 -0
- package/src/utils/claude-integration.ts +649 -0
- package/src/utils/claude-sessions.test.ts +262 -0
- package/src/utils/claude-sessions.ts +251 -0
- package/src/utils/cleanup-operations.ts +94 -0
- package/src/utils/colors.ts +25 -0
- package/src/utils/command-helpers.ts +46 -0
- package/src/utils/config.test.ts +203 -0
- package/src/utils/config.ts +133 -0
- package/src/utils/context-file.ts +36 -0
- package/src/utils/dashboard-hooks.test.ts +168 -0
- package/src/utils/dashboard-hooks.ts +163 -0
- package/src/utils/dependency-analyzer.ts +243 -0
- package/src/utils/diff-operations.ts +59 -0
- package/src/utils/doc-generator.ts +187 -0
- package/src/utils/ghq-integration.test.ts +195 -0
- package/src/utils/ghq-integration.ts +317 -0
- package/src/utils/git-operations.test.ts +265 -0
- package/src/utils/git-operations.ts +233 -0
- package/src/utils/git-status.ts +171 -0
- package/src/utils/github.ts +74 -0
- package/src/utils/health-checks.ts +359 -0
- package/src/utils/history.ts +140 -0
- package/src/utils/hooks.ts +92 -0
- package/src/utils/logger.ts +37 -0
- package/src/utils/permission-sync.test.ts +593 -0
- package/src/utils/permission-sync.ts +720 -0
- package/src/utils/pi-extensions.test.ts +182 -0
- package/src/utils/pi-extensions.ts +226 -0
- package/src/utils/progress.ts +73 -0
- package/src/utils/prompts.test.ts +169 -0
- package/src/utils/prompts.ts +296 -0
- package/src/utils/repo-resolver.test.ts +313 -0
- package/src/utils/repo-resolver.ts +294 -0
- package/src/utils/retry.test.ts +124 -0
- package/src/utils/retry.ts +85 -0
- package/src/utils/run-operations.ts +38 -0
- package/src/utils/suite.test.ts +256 -0
- package/src/utils/suite.ts +144 -0
- package/src/utils/sync-operations.ts +87 -0
- package/src/utils/tmux-dashboard.ts +193 -0
- package/src/utils/validation.test.ts +139 -0
- package/src/utils/validation.ts +128 -0
- package/src/utils/version-check.test.ts +108 -0
- package/src/utils/version-check.ts +96 -0
- package/src/utils/workspace-meta.ts +173 -0
- package/sync-permissions.sh +137 -0
- package/tsconfig.json +20 -0
- 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
|
+
}
|