@lvlup-sw/exarchos-dev 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "exarchos-dev-tools",
3
+ "description": "Developer convenience plugins for Exarchos — GitHub, Serena, Context7, Microsoft Learn",
4
+ "version": "2.0.0",
5
+ "author": { "name": "Levelup Software" },
6
+ "repository": "https://github.com/lvlup-sw/exarchos",
7
+ "keywords": ["exarchos", "dev-tools", "github", "serena", "context7"],
8
+ "mcpServers": "./.mcp.json"
9
+ }
package/.mcp.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "microsoft-learn": {
4
+ "type": "http",
5
+ "url": "https://learn.microsoft.com/api/mcp"
6
+ }
7
+ }
8
+ }
package/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # @lvlup-sw/exarchos-dev
2
+
3
+ Developer convenience plugins for [Exarchos](https://github.com/lvlup-sw/exarchos) — the agent governance system for Claude Code.
4
+
5
+ ## What It Does
6
+
7
+ Adds optional developer tooling to your Exarchos installation:
8
+
9
+ - **GitHub** plugin — PRs, issues, code search
10
+ - **Serena** plugin — Semantic code analysis
11
+ - **Context7** plugin — Up-to-date library documentation
12
+ - **Microsoft Learn** MCP — Official Azure/.NET docs
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npx @lvlup-sw/exarchos-dev
18
+ ```
19
+
20
+ Or with bun:
21
+
22
+ ```bash
23
+ bunx @lvlup-sw/exarchos-dev
24
+ ```
25
+
26
+ This enables the three Claude Code plugins in `~/.claude/settings.json` and registers the Microsoft Learn MCP server in `~/.claude.json`.
27
+
28
+ ## Prerequisites
29
+
30
+ - [Exarchos](https://github.com/lvlup-sw/exarchos) installed (via marketplace or dev mode)
31
+ - Node.js >= 20
32
+
33
+ ## License
34
+
35
+ Apache-2.0 — see [LICENSE](../LICENSE) for details.
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ export declare function installCompanion(claudeHome?: string, claudeJsonPath?: string): {
3
+ pluginsEnabled: string[];
4
+ mcpServersAdded: string[];
5
+ contentOverlays: string[];
6
+ };
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, realpathSync, symlinkSync, lstatSync } from 'node:fs';
3
+ import { join, dirname } from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ import { fileURLToPath } from 'node:url';
6
+ const PLUGINS_TO_ENABLE = {
7
+ 'github@claude-plugins-official': true,
8
+ 'serena@claude-plugins-official': true,
9
+ 'context7@claude-plugins-official': true,
10
+ };
11
+ const MCP_SERVERS_TO_ADD = {
12
+ 'microsoft-learn': {
13
+ type: 'http',
14
+ url: 'https://learn.microsoft.com/api/mcp',
15
+ },
16
+ };
17
+ const CONTENT_OVERLAYS = [
18
+ { source: 'rules/mcp-tool-guidance.md', target: 'rules/mcp-tool-guidance.md' },
19
+ { source: 'skills/workflow-state/references/companion-mcp-reference.md', target: 'skills/workflow-state/references/companion-mcp-reference.md' },
20
+ ];
21
+ export function installCompanion(claudeHome, claudeJsonPath) {
22
+ const home = claudeHome ?? join(homedir(), '.claude');
23
+ const configPath = claudeJsonPath ?? join(homedir(), '.claude.json');
24
+ const pluginsEnabled = installPlugins(home);
25
+ const mcpServersAdded = installMcpServers(configPath);
26
+ const contentOverlays = installContentOverlays(home);
27
+ return { pluginsEnabled, mcpServersAdded, contentOverlays };
28
+ }
29
+ function installContentOverlays(claudeHome) {
30
+ const companionRoot = join(dirname(fileURLToPath(import.meta.url)), '..');
31
+ const installed = [];
32
+ for (const overlay of CONTENT_OVERLAYS) {
33
+ const sourcePath = join(companionRoot, overlay.source);
34
+ const targetPath = join(claudeHome, overlay.target);
35
+ // Ensure target directory exists
36
+ mkdirSync(dirname(targetPath), { recursive: true });
37
+ // Skip if already symlinked to the same source
38
+ try {
39
+ const existing = lstatSync(targetPath);
40
+ if (existing.isSymbolicLink()) {
41
+ try {
42
+ const resolvedLink = realpathSync(targetPath);
43
+ const resolvedSource = realpathSync(sourcePath);
44
+ if (resolvedLink === resolvedSource)
45
+ continue;
46
+ }
47
+ catch {
48
+ // Resolution failed — treat as different, warn below
49
+ }
50
+ }
51
+ // Different file exists — warn but don't overwrite
52
+ process.stderr.write(`Warning: ${overlay.target} already exists, skipping.\n`);
53
+ continue;
54
+ }
55
+ catch (err) {
56
+ if (!(err instanceof Error && 'code' in err && err.code === 'ENOENT')) {
57
+ throw err;
58
+ }
59
+ }
60
+ symlinkSync(sourcePath, targetPath);
61
+ installed.push(overlay.target);
62
+ }
63
+ return installed;
64
+ }
65
+ function parseJsonFile(filePath, label) {
66
+ try {
67
+ return JSON.parse(readFileSync(filePath, 'utf-8'));
68
+ }
69
+ catch {
70
+ process.stderr.write(`Warning: could not parse ${label} at ${filePath} — treating as fresh install.\n`);
71
+ return {};
72
+ }
73
+ }
74
+ function installPlugins(claudeHome) {
75
+ mkdirSync(claudeHome, { recursive: true });
76
+ const settingsPath = join(claudeHome, 'settings.json');
77
+ const settings = existsSync(settingsPath)
78
+ ? parseJsonFile(settingsPath, 'settings.json')
79
+ : {};
80
+ if (!settings.enabledPlugins) {
81
+ settings.enabledPlugins = {};
82
+ }
83
+ const enabled = [];
84
+ for (const [plugin, value] of Object.entries(PLUGINS_TO_ENABLE)) {
85
+ if (settings.enabledPlugins[plugin] !== value) {
86
+ settings.enabledPlugins[plugin] = value;
87
+ enabled.push(plugin);
88
+ }
89
+ }
90
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
91
+ return enabled;
92
+ }
93
+ function installMcpServers(configPath) {
94
+ const config = existsSync(configPath)
95
+ ? parseJsonFile(configPath, '.claude.json')
96
+ : {};
97
+ if (!config.mcpServers) {
98
+ config.mcpServers = {};
99
+ }
100
+ const added = [];
101
+ for (const [name, entry] of Object.entries(MCP_SERVERS_TO_ADD)) {
102
+ if (!config.mcpServers[name]) {
103
+ config.mcpServers[name] = entry;
104
+ added.push(name);
105
+ }
106
+ }
107
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
108
+ return added;
109
+ }
110
+ // CLI entry point
111
+ const isMainModule = (() => {
112
+ try {
113
+ const thisFile = fileURLToPath(import.meta.url);
114
+ const mainFile = realpathSync(process.argv[1]);
115
+ return thisFile === mainFile;
116
+ }
117
+ catch {
118
+ return false;
119
+ }
120
+ })();
121
+ if (isMainModule) {
122
+ const result = installCompanion();
123
+ console.log('Exarchos Dev Tools installed:');
124
+ result.pluginsEnabled.forEach(p => console.log(` Plugin enabled: ${p}`));
125
+ result.mcpServersAdded.forEach(s => console.log(` MCP server added: ${s}`));
126
+ result.contentOverlays.forEach(o => console.log(` Content overlay: ${o}`));
127
+ }
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@lvlup-sw/exarchos-dev",
3
+ "version": "2.0.0",
4
+ "description": "Developer convenience plugins for Exarchos — installs GitHub, Serena, Context7, and Microsoft Learn MCP",
5
+ "type": "module",
6
+ "bin": {
7
+ "exarchos-dev": "./dist/install.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ ".claude-plugin",
12
+ ".mcp.json",
13
+ "settings.json"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "test:run": "npx vitest run"
18
+ },
19
+ "keywords": ["exarchos", "dev-tools", "claude-code"],
20
+ "author": "lvlup-sw",
21
+ "license": "MIT",
22
+ "engines": {
23
+ "node": ">=20.0.0"
24
+ }
25
+ }
package/settings.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "enabledPlugins": {
3
+ "github@claude-plugins-official": true,
4
+ "serena@claude-plugins-official": true,
5
+ "context7@claude-plugins-official": true
6
+ }
7
+ }