@cg3/equip 0.2.18 → 0.2.20

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/README.md CHANGED
@@ -4,6 +4,19 @@ Universal MCP server + behavioral rules installer for AI coding agents.
4
4
 
5
5
  Equip handles the hard part of distributing your MCP tool: detecting which AI coding platforms are installed, writing the correct config format for each one, and managing versioned behavioral rules — all with zero dependencies.
6
6
 
7
+ ## Run the Demo
8
+
9
+ ```bash
10
+ npx @cg3/equip demo
11
+ ```
12
+
13
+ A self-contained, inline-documented setup script that walks through every equip feature — platform detection, MCP config, behavioral rules, and uninstallation. Runs in dry-run mode by default (no files touched). See [`demo/setup.js`](./demo/setup.js) for the full source.
14
+
15
+ ```bash
16
+ npx @cg3/equip demo --live # actually write config files
17
+ npx @cg3/equip demo --uninstall # clean up demo files
18
+ ```
19
+
7
20
  ## Supported Platforms
8
21
 
9
22
  Equip supports **11 platforms** across two tiers, depending on whether the platform has a writable location for behavioral rules.
@@ -158,17 +171,21 @@ const { detectPlatforms, installMcpJson, installRules, createManualPlatform, pla
158
171
  - **Dry-run support** — Preview changes without writing files
159
172
  - **CLI helpers** — Colored output, prompts, clipboard utilities included
160
173
 
161
- ## Limitations Why Rules Matter (and Why They're Not Enough)
174
+ ## How the Layers Work Together
175
+
176
+ Equip distributes your MCP tool through three complementary layers, each stronger than the last:
162
177
 
163
- MCP tool descriptions alone don't reliably trigger agent behavior. [Research on 856 MCP tools](https://arxiv.org/abs/2602.14878) found that 97.1% of tool descriptions contain quality issues, and even fully optimized descriptions only improve task success by ~6 percentage points.
178
+ 1. **MCP config** Makes the tool available. The agent *can* call it.
179
+ 2. **Behavioral rules** — Teaches the agent *when* to call it. Rules live in the agent's system prompt or project context, close to where decisions happen.
180
+ 3. **Lifecycle hooks** — Structurally enforces behavior at key moments (e.g., after an error, on task completion). Hooks inject context into the agent's reasoning at exactly the right time, without relying on the agent remembering its rules.
164
181
 
165
- Behavioral rules (the `.md` files equip installs) are stronger — they live in the agent's system prompt or project context, closer to how agents make decisions. But they have limits too:
182
+ Each layer compensates for the limitations of the one before it:
166
183
 
167
- - **Context window compaction** can drop rules from the agent's working memory during long sessions
168
- - **No platform hooks exist** to enforce tool calls the agent always decides whether to act
169
- - **No open standard** for server-initiated actions (MCP sampling exists in spec but isn't widely implemented)
184
+ - **Tool descriptions alone** don't reliably trigger behavior. [Research on 856 MCP tools](https://arxiv.org/abs/2602.14878) found that even fully optimized descriptions only improve task success by ~6 percentage points.
185
+ - **Behavioral rules** are stronger, but can be dropped during context window compaction in long sessions, and the agent can still rationalize skipping them.
186
+ - **Lifecycle hooks** are the strongest available enforcement they fire automatically at the platform level, independent of the agent's memory or reasoning. Not all platforms support hooks yet, but equip installs them where available and silently skips where not.
170
187
 
171
- Equip gives you the best available distribution: MCP config for tool availability + behavioral rules for usage guidance + lifecycle hooks for structural enforcement on platforms that support them. Hooks bridge the gap between "the agent knows the rules" and "the agent actually follows them" by injecting reminders at the exact moment an error occurs.
188
+ No layer is a silver bullet. Together, they give you the best coverage available today across the broadest set of platforms.
172
189
 
173
190
  ## License
174
191
 
package/bin/equip.js CHANGED
@@ -16,6 +16,7 @@ const EQUIP_VERSION = JSON.parse(
16
16
 
17
17
  const TOOLS = {
18
18
  prior: { package: "@cg3/prior-node", command: "setup" },
19
+ demo: { builtin: true },
19
20
  };
20
21
 
21
22
  // ─── CLI ─────────────────────────────────────────────────────
@@ -28,7 +29,11 @@ if (!alias || alias === "--help" || alias === "-h") {
28
29
  console.log("");
29
30
  console.log("Available tools:");
30
31
  for (const [name, info] of Object.entries(TOOLS)) {
31
- console.log(` ${name} → ${info.package} ${info.command}`);
32
+ if (info.builtin) {
33
+ console.log(` ${name} → built-in (reference example)`);
34
+ } else {
35
+ console.log(` ${name} → ${info.package} ${info.command}`);
36
+ }
32
37
  }
33
38
  console.log("");
34
39
  console.log("Options are forwarded to the tool (e.g. --dry-run, --platform codex)");
@@ -37,6 +42,23 @@ if (!alias || alias === "--help" || alias === "-h") {
37
42
 
38
43
  const entry = TOOLS[alias];
39
44
 
45
+ // Built-in tools run from this package directly
46
+ if (entry && entry.builtin) {
47
+ if (alias === "demo") {
48
+ const demoPath = path.join(__dirname, "..", "demo", "setup.js");
49
+ const child = spawn(process.execPath, [demoPath, ...extraArgs], {
50
+ stdio: "inherit",
51
+ env: { ...process.env, EQUIP_VERSION },
52
+ });
53
+ child.on("close", (code) => process.exit(code || 0));
54
+ child.on("error", (err) => {
55
+ console.error(`Failed to run demo: ${err.message}`);
56
+ process.exit(1);
57
+ });
58
+ return;
59
+ }
60
+ }
61
+
40
62
  // No registry match — treat as a package name (e.g. "@scope/pkg setup")
41
63
  if (!entry) {
42
64
  const pkg = alias;
package/demo/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # @cg3/equip Demo
2
+
3
+ A minimal, working setup script that shows how to build your own MCP tool installer on top of `@cg3/equip`.
4
+
5
+ ## Run it
6
+
7
+ ```bash
8
+ npx @cg3/equip demo # dry-run (default — safe to explore)
9
+ npx @cg3/equip demo --live # actually write config files
10
+ npx @cg3/equip demo --uninstall # clean up demo files
11
+ npx @cg3/equip demo --platform claude-code # target a specific platform
12
+ ```
13
+
14
+ The demo runs in **dry-run mode by default** — it shows exactly what would happen without touching any files. Use `--live` to write real config, and `--uninstall` to clean up afterward.
15
+
16
+ ## What it does
17
+
18
+ The demo installs a fictional MCP tool called `my-tool` across all detected AI coding platforms. It walks through the core equip operations:
19
+
20
+ 1. **Detect** — scan for installed AI tools (Claude Code, Cursor, VS Code, etc.)
21
+ 2. **API key** — prompt for or configure authentication
22
+ 3. **MCP config** — write server config to each platform's config file
23
+ 4. **Behavioral rules** — inject versioned instructions into agent rule files
24
+ 5. **Uninstall** — cleanly remove everything the install wrote
25
+
26
+ Every step is documented inline in [`setup.js`](./setup.js).
27
+
28
+ ## Use as a template
29
+
30
+ Copy `setup.js` into your own project and replace:
31
+
32
+ - `TOOL_NAME` — your MCP server name
33
+ - `SERVER_URL` — your MCP endpoint
34
+ - `RULES_CONTENT` — behavioral instructions for agents
35
+ - API key prompt — real authentication flow
36
+ - Remove the dry-run default (real tools should install by default)
37
+
38
+ Then wire it up in your `package.json`:
39
+
40
+ ```json
41
+ {
42
+ "bin": { "setup": "./setup.js" }
43
+ }
44
+ ```
45
+
46
+ And register it in equip's tool registry (or run directly with `npx your-package setup`).
47
+
48
+ ## API surface
49
+
50
+ The demo uses these equip APIs:
51
+
52
+ | API | Purpose |
53
+ |-----|---------|
54
+ | `new Equip(config)` | Create installer instance |
55
+ | `equip.detect()` | Find installed platforms |
56
+ | `equip.installMcp(platform, apiKey)` | Write MCP config |
57
+ | `equip.installRules(platform)` | Install behavioral rules |
58
+ | `equip.uninstallMcp(platform)` | Remove MCP config |
59
+ | `equip.uninstallRules(platform)` | Remove behavioral rules |
60
+ | `createManualPlatform(id)` | Force a specific platform |
61
+ | `platformName(id)` | Human-readable platform name |
62
+ | `cli.*` | Output helpers (colors, prompts, clipboard) |
63
+
64
+ See the [main README](../README.md) for the full API reference.
package/demo/setup.js ADDED
@@ -0,0 +1,316 @@
1
+ #!/usr/bin/env node
2
+ // ─────────────────────────────────────────────────────────────
3
+ // @cg3/equip Demo — Minimal setup script for a fictional MCP tool.
4
+ //
5
+ // This file is a working reference for building your own setup
6
+ // script on top of @cg3/equip. Run it with:
7
+ //
8
+ // npx @cg3/equip demo # dry-run by default (safe)
9
+ // npx @cg3/equip demo --live # actually write files
10
+ // npx @cg3/equip demo --uninstall # remove demo config
11
+ // npx @cg3/equip demo --platform codex # target a specific platform
12
+ //
13
+ // It demonstrates:
14
+ // 1. Platform detection (which AI tools are installed?)
15
+ // 2. MCP server configuration (HTTP or stdio transport)
16
+ // 3. Behavioral rules installation (versioned, marker-based)
17
+ // 4. Lifecycle hooks (optional, platform-dependent)
18
+ // 5. Uninstallation (clean removal of everything it installed)
19
+ // 6. CLI output helpers (colors, prompts, clipboard)
20
+ //
21
+ // Everything is inline-documented. Copy this file as a starting
22
+ // point for your own tool's setup script.
23
+ // ─────────────────────────────────────────────────────────────
24
+
25
+ "use strict";
26
+
27
+ // ─── 1. Import equip ────────────────────────────────────────
28
+ //
29
+ // The Equip class is the high-level API. It wraps detection,
30
+ // config building, installation, and uninstallation into a
31
+ // single object. You can also import individual primitives
32
+ // (detectPlatforms, installMcp, etc.) for lower-level control.
33
+
34
+ const { Equip, createManualPlatform, platformName, cli } = require("@cg3/equip");
35
+
36
+ // ─── 2. Parse CLI flags ─────────────────────────────────────
37
+ //
38
+ // Keep it simple — equip doesn't ship an arg parser on purpose.
39
+ // Your setup script owns its own CLI interface.
40
+
41
+ const args = process.argv.slice(2);
42
+ const uninstall = args.includes("--uninstall");
43
+ const liveMode = args.includes("--live");
44
+ const dryRun = !liveMode && !uninstall; // Demo defaults to dry-run for safety
45
+ const platformOverride = args.includes("--platform")
46
+ ? args[args.indexOf("--platform") + 1]
47
+ : null;
48
+
49
+ // ─── 3. Define your tool ────────────────────────────────────
50
+ //
51
+ // This is the core configuration. Replace these values with
52
+ // your actual MCP server details.
53
+
54
+ const TOOL_NAME = "my-tool"; // Name in MCP config files
55
+ const SERVER_URL = "https://api.example.com/mcp"; // Your MCP endpoint
56
+ const RULES_VERSION = "0.1.0"; // Bump when rules content changes
57
+
58
+ // Behavioral rules use HTML comment markers for versioned,
59
+ // non-destructive updates. The marker lets equip find and
60
+ // replace your block without touching the rest of the file.
61
+ //
62
+ // Format:
63
+ // <!-- marker:vX.Y.Z -->
64
+ // ... your rules content ...
65
+ // <!-- /marker -->
66
+
67
+ const RULES_CONTENT = `<!-- ${TOOL_NAME}:v${RULES_VERSION} -->
68
+ ## My Tool — Agent Instructions
69
+
70
+ When you encounter an error you haven't seen before:
71
+ 1. Search my-tool for existing solutions before debugging from scratch
72
+ 2. If you find a match, try it and give feedback (useful/not_useful/irrelevant)
73
+ 3. If you solve something novel, contribute the solution
74
+
75
+ Keep searches focused on the error message, not the goal.
76
+ <!-- /${TOOL_NAME} -->`;
77
+
78
+ // ─── 4. Create the Equip instance ───────────────────────────
79
+ //
80
+ // The constructor validates config and stores it. No side
81
+ // effects — detection and installation happen in separate calls.
82
+
83
+ const equip = new Equip({
84
+ name: TOOL_NAME,
85
+ serverUrl: SERVER_URL,
86
+
87
+ // Rules are optional. Omit this block if your tool doesn't
88
+ // need behavioral instructions injected into agent configs.
89
+ rules: {
90
+ content: RULES_CONTENT,
91
+ version: RULES_VERSION,
92
+ marker: TOOL_NAME,
93
+ // fileName: "my-tool.md", // Use for platforms with rules directories
94
+ // clipboardPlatforms: ["cursor", "vscode"], // These get clipboard instead
95
+ },
96
+
97
+ // Stdio transport (alternative to HTTP). Uncomment to use:
98
+ // stdio: {
99
+ // command: "npx",
100
+ // args: ["-y", "@example/my-tool-mcp@latest"],
101
+ // envKey: "MY_TOOL_API_KEY", // Env var name for the API key
102
+ // },
103
+
104
+ // Hooks are optional. They run code at specific lifecycle
105
+ // events in supported platforms (currently Claude Code only).
106
+ // hooks: [
107
+ // {
108
+ // event: "PostToolUseFailure",
109
+ // matcher: "Bash",
110
+ // name: "search-on-error",
111
+ // script: `
112
+ // // This runs after a Bash tool call fails.
113
+ // // Hook scripts receive context via stdin (JSON).
114
+ // const input = require("fs").readFileSync("/dev/stdin", "utf-8");
115
+ // const { tool_input, tool_output } = JSON.parse(input);
116
+ // console.log("Consider searching my-tool for:", tool_output?.stderr);
117
+ // `,
118
+ // },
119
+ // ],
120
+ });
121
+
122
+ // ─── 5. Detect platforms (shared by install and uninstall) ───
123
+
124
+ function detectTargetPlatforms() {
125
+ if (platformOverride) {
126
+ const p = createManualPlatform(platformOverride);
127
+ cli.info(`Forced platform: ${platformName(platformOverride)}`);
128
+ return [p];
129
+ }
130
+
131
+ const platforms = equip.detect();
132
+ if (platforms.length === 0) {
133
+ cli.fail("No AI coding tools detected. Install one of:");
134
+ cli.log(" Claude Code, Cursor, VS Code, Windsurf, Codex, Gemini CLI");
135
+ cli.log(" Or use --platform <id> to specify manually.\n");
136
+ process.exit(1);
137
+ }
138
+ return platforms;
139
+ }
140
+
141
+ // ─── 6. Uninstall flow ──────────────────────────────────────
142
+ //
143
+ // equip provides uninstallMcp() and uninstallRules() that
144
+ // cleanly remove everything the install wrote:
145
+ // - MCP config: removes the server entry (restores .bak if available)
146
+ // - Rules: removes the marker block, preserving other content
147
+ // - Hooks: removes scripts and settings entries
148
+ //
149
+ // This is important for demos — and equally important for real
150
+ // tools that want a clean "uninstall" command.
151
+
152
+ async function runUninstall() {
153
+ cli.log(`\n${cli.BOLD}@cg3/equip demo — uninstall${cli.RESET}\n`);
154
+
155
+ cli.step(1, 3, "Detecting platforms");
156
+ const platforms = detectTargetPlatforms();
157
+
158
+ for (const p of platforms) {
159
+ cli.ok(platformName(p.platform));
160
+ }
161
+
162
+ // ── Remove MCP config ────────────────────────────────────
163
+ cli.step(2, 3, "Removing MCP config");
164
+
165
+ for (const p of platforms) {
166
+ const removed = equip.uninstallMcp(p);
167
+ if (removed) {
168
+ cli.ok(`${platformName(p.platform)} → removed`);
169
+ } else {
170
+ cli.info(`${platformName(p.platform)} → not configured (nothing to remove)`);
171
+ }
172
+ }
173
+
174
+ // ── Remove behavioral rules ──────────────────────────────
175
+ cli.step(3, 3, "Removing behavioral rules");
176
+
177
+ for (const p of platforms) {
178
+ const removed = equip.uninstallRules(p);
179
+ if (removed) {
180
+ cli.ok(`${platformName(p.platform)} → rules removed`);
181
+ } else {
182
+ cli.info(`${platformName(p.platform)} → no rules found`);
183
+ }
184
+ }
185
+
186
+ cli.log(`\n${cli.GREEN}${cli.BOLD}✓ Uninstall complete${cli.RESET}`);
187
+ cli.log(` Demo config for "${TOOL_NAME}" has been cleaned up.\n`);
188
+ }
189
+
190
+ // ─── 7. Install flow ────────────────────────────────────────
191
+
192
+ async function runInstall() {
193
+ cli.log(`\n${cli.BOLD}@cg3/equip demo — setup walkthrough${cli.RESET}\n`);
194
+
195
+ if (dryRun) {
196
+ cli.warn("Dry run mode (default for demo) — no files will be modified");
197
+ cli.info(`Use ${cli.BOLD}--live${cli.RESET} to actually write files\n`);
198
+ }
199
+
200
+ // ── Step 1: Detect platforms ──────────────────────────────
201
+ //
202
+ // detectPlatforms() scans the system for installed AI coding
203
+ // tools: Claude Code, Cursor, VS Code, Windsurf, Codex, etc.
204
+ //
205
+ // Each result includes:
206
+ // - platform: id string ("claude-code", "cursor", etc.)
207
+ // - configPath: where MCP config lives
208
+ // - rulesPath: where behavioral rules go (or null)
209
+ // - existingMcp: current config for this server name (or null)
210
+ // - rootKey: JSON key for MCP servers ("mcpServers", "servers", etc.)
211
+ // - configFormat: "json" or "toml"
212
+ //
213
+ // You can also force a specific platform with createManualPlatform().
214
+
215
+ cli.step(1, 4, "Detecting platforms");
216
+
217
+ const platforms = detectTargetPlatforms();
218
+
219
+ for (const p of platforms) {
220
+ const status = p.existingMcp ? `${cli.YELLOW}configured${cli.RESET}` : `${cli.DIM}not configured${cli.RESET}`;
221
+ cli.ok(`${platformName(p.platform)} [${status}]`);
222
+ }
223
+
224
+ // ── Step 2: Get API key ───────────────────────────────────
225
+ //
226
+ // In a real setup script, you'd prompt for or generate an
227
+ // API key here. For the demo, we use a placeholder.
228
+
229
+ cli.step(2, 4, "API key");
230
+
231
+ // Real example:
232
+ // const apiKey = await cli.prompt(" Enter your API key: ");
233
+ // if (!apiKey) { cli.fail("API key required"); process.exit(1); }
234
+
235
+ const apiKey = "demo_key_xxx"; // Placeholder for demo
236
+ cli.info(`Using demo API key (${apiKey.slice(0, 8)}...)`);
237
+
238
+ // ── Step 3: Install MCP config ────────────────────────────
239
+ //
240
+ // installMcp() handles all platform differences:
241
+ // - JSON vs TOML config formats
242
+ // - Different root keys (mcpServers vs servers vs mcp_servers)
243
+ // - CLI-first installation (claude mcp add, cursor --add-mcp)
244
+ // - Fallback to direct file write with backup
245
+ // - Windows path handling (cmd /c wrapper for stdio)
246
+
247
+ cli.step(3, 4, "Installing MCP config");
248
+
249
+ for (const p of platforms) {
250
+ const result = equip.installMcp(p, apiKey, { dryRun });
251
+ if (result.success) {
252
+ cli.ok(`${platformName(p.platform)} → ${result.method}`);
253
+ } else {
254
+ cli.fail(`${platformName(p.platform)}`);
255
+ }
256
+ }
257
+
258
+ // ── Step 4: Install behavioral rules ──────────────────────
259
+ //
260
+ // Rules are versioned markdown blocks injected into each
261
+ // platform's rules file (CLAUDE.md, GEMINI.md, etc.).
262
+ //
263
+ // The marker system means:
264
+ // - First install: appends the block
265
+ // - Version bump: replaces the old block in-place
266
+ // - Same version: skips (idempotent)
267
+ // - Uninstall: removes the block cleanly
268
+ //
269
+ // Platforms without a rules file (Cursor, VS Code) get the
270
+ // content copied to clipboard instead.
271
+
272
+ cli.step(4, 4, "Installing behavioral rules");
273
+
274
+ for (const p of platforms) {
275
+ const result = equip.installRules(p, { dryRun });
276
+ switch (result.action) {
277
+ case "created":
278
+ cli.ok(`${platformName(p.platform)} → rules installed`);
279
+ break;
280
+ case "updated":
281
+ cli.ok(`${platformName(p.platform)} → rules updated`);
282
+ break;
283
+ case "skipped":
284
+ cli.info(`${platformName(p.platform)} → already current`);
285
+ break;
286
+ case "clipboard":
287
+ cli.info(`${platformName(p.platform)} → copied to clipboard (paste into settings)`);
288
+ break;
289
+ }
290
+ }
291
+
292
+ // ── Done ──────────────────────────────────────────────────
293
+
294
+ cli.log(`\n${cli.GREEN}${cli.BOLD}✓ Setup complete${cli.RESET}`);
295
+ if (dryRun) {
296
+ cli.warn("(dry run — nothing was actually written)\n");
297
+ } else {
298
+ // When files were actually written, remind user how to clean up
299
+ cli.log(` MCP server "${TOOL_NAME}" is now configured on ${platforms.length} platform(s).`);
300
+ cli.log("");
301
+ cli.warn(`This was a demo — run ${cli.BOLD}npx @cg3/equip demo --uninstall${cli.RESET} to remove demo files\n`);
302
+ }
303
+ }
304
+
305
+ // ─── 8. Entry point ─────────────────────────────────────────
306
+ //
307
+ // Route to install or uninstall based on flags.
308
+ // Wrap in error handler for clean output.
309
+
310
+ const run = uninstall ? runUninstall : runInstall;
311
+
312
+ run().catch((err) => {
313
+ cli.fail(cli.sanitizeError(err.message));
314
+ if (process.env.DEBUG) console.error(err);
315
+ process.exit(1);
316
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cg3/equip",
3
- "version": "0.2.18",
3
+ "version": "0.2.20",
4
4
  "description": "Universal MCP + behavioral rules installer for AI coding agents",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -18,7 +18,8 @@
18
18
  "files": [
19
19
  "index.js",
20
20
  "bin/",
21
- "lib/"
21
+ "lib/",
22
+ "demo/"
22
23
  ],
23
24
  "keywords": [
24
25
  "mcp",