@cg3/equip 0.8.0 → 0.9.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/README.md +93 -157
- package/bin/equip.js +84 -0
- package/demo/setup.js +85 -12
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/commands/doctor.d.ts.map +1 -1
- package/dist/lib/commands/doctor.js +14 -1
- package/dist/lib/commands/doctor.js.map +1 -1
- package/dist/lib/detect.d.ts.map +1 -1
- package/dist/lib/detect.js +2 -0
- package/dist/lib/detect.js.map +1 -1
- package/dist/lib/platforms.d.ts +2 -0
- package/dist/lib/platforms.d.ts.map +1 -1
- package/dist/lib/platforms.js +12 -0
- package/dist/lib/platforms.js.map +1 -1
- package/dist/lib/reconcile.d.ts.map +1 -1
- package/dist/lib/reconcile.js +21 -0
- package/dist/lib/reconcile.js.map +1 -1
- package/dist/lib/skills.d.ts +36 -0
- package/dist/lib/skills.d.ts.map +1 -0
- package/dist/lib/skills.js +125 -0
- package/dist/lib/skills.js.map +1 -0
- package/dist/lib/state.d.ts +4 -0
- package/dist/lib/state.d.ts.map +1 -1
- package/dist/lib/state.js.map +1 -1
- package/package.json +2 -2
- package/registry.json +2 -1
package/README.md
CHANGED
|
@@ -1,99 +1,32 @@
|
|
|
1
1
|
# @cg3/equip
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Cross-platform installer for MCP tools, behavioral rules, agent skills, and lifecycle hooks.
|
|
4
4
|
|
|
5
|
-
[Join the Discord](https://discord.gg/bBcRHT4J)
|
|
5
|
+
[Join the Discord](https://discord.gg/bBcRHT4J) | [Tool Author Guide](./docs/tool-author.md)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## What It Does
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
You build an MCP tool. You want it to work on Claude Code, Cursor, VS Code, Windsurf, Cline, Roo Code, Codex, Gemini CLI, and more. Each platform has its own config format, file paths, root keys, URL fields, and quirks.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
npx @cg3/equip demo
|
|
13
|
-
```
|
|
11
|
+
Equip handles all of that. One setup script, 11 platforms.
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
## Install
|
|
16
14
|
|
|
17
15
|
```bash
|
|
18
|
-
|
|
19
|
-
npx @cg3/equip demo --uninstall # clean up demo files
|
|
16
|
+
npm install -g @cg3/equip
|
|
20
17
|
```
|
|
21
18
|
|
|
22
|
-
## Supported Platforms
|
|
23
|
-
|
|
24
|
-
Equip supports **11 platforms** across two tiers, depending on whether the platform has a writable location for behavioral rules.
|
|
25
|
-
|
|
26
|
-
### Full Support — MCP + Behavioral Rules
|
|
27
|
-
|
|
28
|
-
These platforms get both MCP server config *and* auto-installed behavioral rules. Rules teach agents *when* to use your tool (e.g., "search before debugging") and are versioned for idempotent updates.
|
|
29
|
-
|
|
30
|
-
| Platform | MCP Config | Rules |
|
|
31
|
-
|---|---|---|
|
|
32
|
-
| Claude Code | `~/.claude.json` (JSON, `mcpServers`) | `~/.claude/CLAUDE.md` (append) |
|
|
33
|
-
| Windsurf | `~/.codeium/windsurf/mcp_config.json` (JSON, `mcpServers`, `serverUrl`) | `~/.codeium/windsurf/memories/global_rules.md` (append) |
|
|
34
|
-
| Cline | `globalStorage/.../cline_mcp_settings.json` (JSON, `mcpServers`) | `~/Documents/Cline/Rules/` (standalone file) |
|
|
35
|
-
| Roo Code | `globalStorage/.../cline_mcp_settings.json` (JSON, `mcpServers`) | `~/.roo/rules/` (standalone file) |
|
|
36
|
-
| Codex | `~/.codex/config.toml` (TOML, `mcp_servers`) | `~/.codex/AGENTS.md` (append) |
|
|
37
|
-
| Gemini CLI | `~/.gemini/settings.json` (JSON, `mcpServers`, `httpUrl`) | `~/.gemini/GEMINI.md` (append) |
|
|
38
|
-
|
|
39
|
-
### MCP Only — No Writable Rules Path
|
|
40
|
-
|
|
41
|
-
These platforms get MCP server config but don't have a writable global rules file (`rulesPath: null`). The MCP tools work fine — but equip can't auto-install behavioral rules.
|
|
42
|
-
|
|
43
|
-
| Platform | MCP Config |
|
|
44
|
-
|---|---|
|
|
45
|
-
| Cursor | `~/.cursor/mcp.json` (JSON, `mcpServers`, `type: "streamable-http"`) |
|
|
46
|
-
| VS Code | `Code/User/mcp.json` (JSON, `servers`, `type: "http"`) |
|
|
47
|
-
| Junie (JetBrains) | `~/.junie/mcp/mcp.json` (JSON, `mcpServers`) |
|
|
48
|
-
| Copilot (JetBrains) | `~/.config/github-copilot/intellij/mcp.json` (JSON, `mcpServers`) |
|
|
49
|
-
| Copilot CLI | `~/.copilot/mcp-config.json` (JSON, `mcpServers`) |
|
|
50
|
-
|
|
51
|
-
For these platforms, `installRules()` returns `{ action: "clipboard" }` if the platform is in the configurable `clipboardPlatforms` list (default: `["cursor", "vscode"]`) and automatically copies the rules content to the system clipboard. For platforms with no rules path and not in `clipboardPlatforms`, it returns `{ action: "skipped" }`.
|
|
52
|
-
|
|
53
|
-
### Hooks — Structural Enforcement
|
|
54
|
-
|
|
55
|
-
Some platforms support **lifecycle hooks** — scripts that run automatically at key moments (e.g., after a tool fails, when the agent finishes responding). Hooks provide structural enforcement that behavioral rules alone cannot:
|
|
56
|
-
|
|
57
|
-
| Platform | Hooks Support | Events |
|
|
58
|
-
|---|---|---|
|
|
59
|
-
| Claude Code | ✅ | `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `Stop`, `SessionStart`, `SessionEnd`, `UserPromptSubmit`, `Notification`, `SubagentStart`, `SubagentStop`, `PreCompact`, `TaskCompleted` |
|
|
60
|
-
| All others | ❌ | — |
|
|
61
|
-
|
|
62
|
-
When hooks are supported, equip writes the consumer-provided scripts to a configurable directory (default: `~/.${name}/hooks/`) and registers them in the platform's settings. Hooks are a **silent enhancement** — if the platform doesn't support them, equip installs only MCP + rules without any error or warning.
|
|
63
|
-
|
|
64
|
-
Hook scripts and event bindings are defined by the consumer (your package), not by equip. Equip provides only the installation infrastructure — capabilities detection, file writing, settings registration, and cleanup. As more platforms add hook support, equip can enable them without consumer code changes.
|
|
65
|
-
|
|
66
19
|
## Quick Start
|
|
67
20
|
|
|
68
21
|
```bash
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
## CLI Usage
|
|
75
|
-
|
|
76
|
-
You can invoke any npm package that has an equip-based setup command:
|
|
77
|
-
|
|
78
|
-
```bash
|
|
79
|
-
# Full package name + command
|
|
80
|
-
npx @cg3/equip @cg3/prior-node setup
|
|
81
|
-
|
|
82
|
-
# Shorthand (if registered)
|
|
83
|
-
npx @cg3/equip prior
|
|
22
|
+
equip prior # Install a tool
|
|
23
|
+
equip status # See what's installed across all platforms
|
|
24
|
+
equip doctor # Validate config integrity
|
|
25
|
+
equip update # Update equip + migrate configs
|
|
26
|
+
unequip prior # Remove a tool
|
|
84
27
|
```
|
|
85
28
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
### Shorthand Registry
|
|
89
|
-
|
|
90
|
-
Registered shorthands save typing. Open a PR to [`registry.json`](./registry.json) to add yours:
|
|
91
|
-
|
|
92
|
-
| Shorthand | Expands to |
|
|
93
|
-
|---|---|
|
|
94
|
-
| `prior` | `@cg3/prior-node setup` |
|
|
95
|
-
|
|
96
|
-
## Programmatic Usage
|
|
29
|
+
## For Tool Authors
|
|
97
30
|
|
|
98
31
|
```js
|
|
99
32
|
const { Equip } = require("@cg3/equip");
|
|
@@ -105,103 +38,106 @@ const equip = new Equip({
|
|
|
105
38
|
content: `<!-- my-tool:v1.0.0 -->\n## My Tool\nAlways check My Tool first.\n<!-- /my-tool -->`,
|
|
106
39
|
version: "1.0.0",
|
|
107
40
|
marker: "my-tool",
|
|
108
|
-
|
|
41
|
+
},
|
|
42
|
+
skill: {
|
|
43
|
+
name: "lookup",
|
|
44
|
+
files: [{ path: "SKILL.md", content: "---\nname: lookup\ndescription: Look up docs\n---\n\n# Lookup\n" }],
|
|
109
45
|
},
|
|
110
46
|
});
|
|
111
47
|
|
|
112
|
-
// Detect installed platforms
|
|
113
48
|
const platforms = equip.detect();
|
|
114
|
-
|
|
115
|
-
// Install MCP + rules on all detected platforms
|
|
116
49
|
for (const p of platforms) {
|
|
117
50
|
equip.installMcp(p, "api_key_here");
|
|
118
51
|
equip.installRules(p);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// Uninstall
|
|
122
|
-
for (const p of platforms) {
|
|
123
|
-
equip.uninstallMcp(p);
|
|
124
|
-
equip.uninstallRules(p);
|
|
52
|
+
equip.installSkill(p);
|
|
125
53
|
}
|
|
126
54
|
```
|
|
127
55
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
### `new Equip(config)`
|
|
131
|
-
|
|
132
|
-
- `config.name` — Server name in MCP configs (required)
|
|
133
|
-
- `config.serverUrl` — Remote MCP server URL (required unless `stdio` provided)
|
|
134
|
-
- `config.rules` — Behavioral rules config (optional)
|
|
135
|
-
- `content` — Markdown content with version markers
|
|
136
|
-
- `version` — Version string for idempotency tracking
|
|
137
|
-
- `marker` — Marker name used in `<!-- marker:vX.X -->` comments
|
|
138
|
-
- `fileName` — Standalone filename for directory-based platforms
|
|
139
|
-
- `clipboardPlatforms` — Platform IDs that use clipboard (default: `["cursor", "vscode"]`)
|
|
140
|
-
- `config.stdio` — Stdio transport config (optional, alternative to HTTP)
|
|
141
|
-
- `command`, `args`, `envKey`
|
|
142
|
-
- `config.hooks` — Lifecycle hook definitions (optional, array)
|
|
143
|
-
- `event` — Hook event name (e.g., `"PostToolUseFailure"`)
|
|
144
|
-
- `matcher` — Regex matcher for event filtering (optional, e.g., `"Bash"`)
|
|
145
|
-
- `script` — Hook script content (Node.js)
|
|
146
|
-
- `name` — Script filename (without `.js` extension)
|
|
147
|
-
- `config.hookDir` — Directory for hook scripts (default: `~/.${name}/hooks/`)
|
|
148
|
-
|
|
149
|
-
### Instance Methods
|
|
150
|
-
|
|
151
|
-
- `equip.detect()` — Returns array of detected platform objects
|
|
152
|
-
- `equip.installMcp(platform, apiKey, options?)` — Install MCP config
|
|
153
|
-
- `equip.uninstallMcp(platform, dryRun?)` — Remove MCP config
|
|
154
|
-
- `equip.updateMcpKey(platform, apiKey, transport?)` — Update API key
|
|
155
|
-
- `equip.installRules(platform, options?)` — Install behavioral rules
|
|
156
|
-
- `equip.uninstallRules(platform, dryRun?)` — Remove behavioral rules
|
|
157
|
-
- `equip.readMcp(platform)` — Check if MCP is configured
|
|
158
|
-
- `equip.buildConfig(platformId, apiKey, transport?)` — Build MCP config object
|
|
159
|
-
- `equip.installHooks(platform, options?)` — Install lifecycle hooks (if supported)
|
|
160
|
-
- `equip.uninstallHooks(platform, options?)` — Remove hooks
|
|
161
|
-
- `equip.hasHooks(platform, options?)` — Check if hooks are installed
|
|
162
|
-
- `equip.supportsHooks(platform)` — Check if platform supports hooks
|
|
163
|
-
|
|
164
|
-
### Utilities
|
|
56
|
+
See the [Tool Author Guide](./docs/tool-author.md) for the complete walkthrough, or run `equip demo` for an interactive example.
|
|
165
57
|
|
|
166
|
-
|
|
167
|
-
const { createManualPlatform, platformName, resolvePlatformId, parseRulesVersion, markerPatterns, cli, KNOWN_PLATFORMS, PLATFORM_REGISTRY, getPlatform } = require("@cg3/equip");
|
|
168
|
-
```
|
|
58
|
+
## The Four Layers
|
|
169
59
|
|
|
170
|
-
|
|
171
|
-
- `platformName(id)` — Human-readable display name for a platform ID
|
|
172
|
-
- `resolvePlatformId(input)` — Resolve a friendly name or alias to a canonical platform ID (e.g., `"claude"` → `"claude-code"`, `"roo"` → `"roo-code"`)
|
|
173
|
-
- `parseRulesVersion(content, marker)` — Extract version from a marker block in content
|
|
174
|
-
- `markerPatterns(marker)` — Get regex patterns for a marker name
|
|
175
|
-
- `KNOWN_PLATFORMS` — Array of all supported platform IDs
|
|
176
|
-
- `PLATFORM_REGISTRY` — Map of platform definitions (for advanced use)
|
|
177
|
-
- `getPlatform(id)` — Get a platform definition by ID (throws if unknown)
|
|
178
|
-
- `cli` — Output helpers: `log`, `ok`, `fail`, `warn`, `info`, `step`, `prompt`, `copyToClipboard`, color constants
|
|
60
|
+
Equip distributes your tool through four complementary layers:
|
|
179
61
|
|
|
180
|
-
|
|
62
|
+
| Layer | What It Does | Reliability | Coverage |
|
|
63
|
+
|---|---|---|---|
|
|
64
|
+
| [MCP Config](./docs/mcp-servers.md) | Makes the tool *available* — agent can call it | Baseline | 11 platforms |
|
|
65
|
+
| [Behavioral Rules](./docs/rules.md) | Teaches the agent *when* to call it | Strong | 8 platforms + clipboard |
|
|
66
|
+
| [Agent Skills](./docs/skills.md) | Gives the agent *detailed knowledge* of how to use it | Strong (varies) | 8 platforms |
|
|
67
|
+
| [Lifecycle Hooks](./docs/hooks.md) | *Structurally enforces* behavior at key moments | Strongest | 1 platform (Claude Code) |
|
|
181
68
|
|
|
182
|
-
-
|
|
183
|
-
- **11 platforms** — Covers ~80% of active AI coding tool users
|
|
184
|
-
- **Platform-aware** — Handles each platform's config quirks (JSON vs TOML, root keys, URL fields, type requirements)
|
|
185
|
-
- **Non-destructive** — Merges into existing configs, creates backups, preserves other servers
|
|
186
|
-
- **Versioned rules** — Marker-based blocks enable idempotent updates without clobbering user content
|
|
187
|
-
- **Dry-run support** — Preview changes without writing files
|
|
188
|
-
- **CLI helpers** — Colored output, prompts, clipboard utilities included
|
|
69
|
+
Each layer compensates for the limitations of the one before it. Tool descriptions alone don't reliably trigger behavior. Rules are stronger but can be compacted. Skills add depth but may not auto-invoke on all platforms. Hooks fire automatically, independent of the agent's memory.
|
|
189
70
|
|
|
190
|
-
|
|
71
|
+
No layer is a silver bullet. Together, they give you the best coverage available.
|
|
191
72
|
|
|
192
|
-
|
|
73
|
+
## Supported Platforms
|
|
193
74
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
75
|
+
| Platform | MCP | Rules | Skills | Hooks |
|
|
76
|
+
|---|---|---|---|---|
|
|
77
|
+
| Claude Code | Yes | Yes | Yes | Yes |
|
|
78
|
+
| Cursor | Yes | clipboard | Yes | -- |
|
|
79
|
+
| VS Code / Copilot | Yes | clipboard | Yes | -- |
|
|
80
|
+
| Windsurf | Yes | Yes | Yes | -- |
|
|
81
|
+
| Cline | Yes | Yes | Yes | -- |
|
|
82
|
+
| Roo Code | Yes | Yes | Yes | -- |
|
|
83
|
+
| Codex | Yes | Yes | Yes | -- |
|
|
84
|
+
| Gemini CLI | Yes | Yes | Yes | -- |
|
|
85
|
+
| Junie | Yes | -- | -- | -- |
|
|
86
|
+
| Copilot (JetBrains) | Yes | -- | -- | -- |
|
|
87
|
+
| Copilot CLI | Yes | -- | -- | -- |
|
|
88
|
+
|
|
89
|
+
See [Platforms](./docs/platforms.md) for full details — config paths, detection, and per-platform quirks.
|
|
90
|
+
|
|
91
|
+
## CLI Commands
|
|
92
|
+
|
|
93
|
+
| Command | Description |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `equip <tool>` | Install an MCP tool |
|
|
96
|
+
| `equip status` | Cross-platform MCP server inventory |
|
|
97
|
+
| `equip doctor` | Validate config integrity, detect drift |
|
|
98
|
+
| `equip update` | Update equip and migrate configs |
|
|
99
|
+
| `equip list` | Show registered tools |
|
|
100
|
+
| `equip uninstall <tool>` | Remove a tool (alias: `unequip`) |
|
|
101
|
+
| `equip demo` | Run the interactive demo |
|
|
197
102
|
|
|
198
|
-
|
|
103
|
+
See [CLI Reference](./docs/cli.md) for details.
|
|
199
104
|
|
|
200
|
-
|
|
201
|
-
- **Behavioral rules** are stronger, but can be dropped during context window compaction in long sessions, and the agent can still rationalize skipping them.
|
|
202
|
-
- **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.
|
|
105
|
+
## Documentation
|
|
203
106
|
|
|
204
|
-
|
|
107
|
+
| Guide | Audience |
|
|
108
|
+
|---|---|
|
|
109
|
+
| [Tool Author Guide](./docs/tool-author.md) | Building a setup script with equip |
|
|
110
|
+
| [Platforms](./docs/platforms.md) | Supported platforms, capabilities, paths |
|
|
111
|
+
| [MCP Servers](./docs/mcp-servers.md) | Config format translation, API reference |
|
|
112
|
+
| [Behavioral Rules](./docs/rules.md) | Marker-based versioned instructions |
|
|
113
|
+
| [Agent Skills](./docs/skills.md) | SKILL.md format, cross-platform distribution |
|
|
114
|
+
| [Lifecycle Hooks](./docs/hooks.md) | Event-driven enforcement scripts |
|
|
115
|
+
| [CLI Reference](./docs/cli.md) | Commands, state tracking, tool registry |
|
|
116
|
+
|
|
117
|
+
## Key Design Decisions
|
|
118
|
+
|
|
119
|
+
- **Zero runtime dependencies** — installs fast, no supply chain risk
|
|
120
|
+
- **Platform registry as single source of truth** — one place for all platform knowledge
|
|
121
|
+
- **Atomic file writes** — crash-safe config modifications
|
|
122
|
+
- **State reconciliation from disk** — CLI scans what's actually installed, no stale cache
|
|
123
|
+
- **Corrupt config detection** — throws instead of silently overwriting
|
|
124
|
+
|
|
125
|
+
## Tool Registry
|
|
126
|
+
|
|
127
|
+
Register a shorthand for your tool so users can run `equip <name>`. Open a PR to [`registry.json`](./registry.json):
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"my-tool": {
|
|
132
|
+
"package": "@myorg/my-tool",
|
|
133
|
+
"command": "setup",
|
|
134
|
+
"description": "What my tool does",
|
|
135
|
+
"marker": "my-tool",
|
|
136
|
+
"hookDir": "~/.my-tool/hooks",
|
|
137
|
+
"skillName": "my-skill"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
205
141
|
|
|
206
142
|
## License
|
|
207
143
|
|
package/bin/equip.js
CHANGED
|
@@ -60,6 +60,8 @@ function cmdHelp() {
|
|
|
60
60
|
console.log("");
|
|
61
61
|
console.log("Commands:");
|
|
62
62
|
console.log(" <tool> Install an MCP tool (e.g. equip prior)");
|
|
63
|
+
console.log(" ./script.js Run a local setup script (for development)");
|
|
64
|
+
console.log(" . Run current directory's package bin entry");
|
|
63
65
|
console.log(" uninstall <tool> Remove an installed tool (alias: unequip)");
|
|
64
66
|
console.log(" status Show all MCP servers across all platforms");
|
|
65
67
|
console.log(" doctor Validate config integrity and detect drift");
|
|
@@ -137,7 +139,20 @@ function cmdUpdate() {
|
|
|
137
139
|
|
|
138
140
|
// ─── Tool Dispatch ──────────────────────────────────────────
|
|
139
141
|
|
|
142
|
+
function isLocalPath(arg) {
|
|
143
|
+
return arg.startsWith("./") || arg.startsWith("../") || arg.startsWith("/")
|
|
144
|
+
|| arg.startsWith(".\\") || arg.startsWith("..\\")
|
|
145
|
+
|| arg === "."
|
|
146
|
+
|| arg.endsWith(".js");
|
|
147
|
+
}
|
|
148
|
+
|
|
140
149
|
function dispatchTool(alias, extraArgs) {
|
|
150
|
+
// Local path: run directly with node
|
|
151
|
+
if (isLocalPath(alias)) {
|
|
152
|
+
runLocal(alias, extraArgs);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
141
156
|
const entry = TOOLS[alias];
|
|
142
157
|
|
|
143
158
|
if (!entry) {
|
|
@@ -157,6 +172,75 @@ function dispatchTool(alias, extraArgs) {
|
|
|
157
172
|
spawnTool(entry.package, entry.command, extraArgs, alias);
|
|
158
173
|
}
|
|
159
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Run a local script or package directory.
|
|
177
|
+
* - equip ./piratehat.js → node ./piratehat.js
|
|
178
|
+
* - equip . → reads package.json bin, runs it
|
|
179
|
+
* - equip ../my-tool/setup.js → node ../my-tool/setup.js
|
|
180
|
+
*/
|
|
181
|
+
function runLocal(localPath, extraArgs) {
|
|
182
|
+
const _path = require("path");
|
|
183
|
+
const _fs = require("fs");
|
|
184
|
+
let scriptPath;
|
|
185
|
+
let toolName = null;
|
|
186
|
+
|
|
187
|
+
if (localPath === "." || (_fs.existsSync(localPath) && _fs.statSync(localPath).isDirectory())) {
|
|
188
|
+
// Directory — look for package.json with bin field
|
|
189
|
+
const pkgPath = _path.join(localPath, "package.json");
|
|
190
|
+
if (!_fs.existsSync(pkgPath)) {
|
|
191
|
+
console.error(`No package.json found in ${localPath}`);
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
const pkg = JSON.parse(_fs.readFileSync(pkgPath, "utf-8"));
|
|
195
|
+
toolName = pkg.name?.replace(/^@[^/]+\//, "") || null;
|
|
196
|
+
const binEntries = pkg.bin;
|
|
197
|
+
if (!binEntries || typeof binEntries !== "object") {
|
|
198
|
+
console.error(`No bin field in ${pkgPath}`);
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
// Use the first bin entry
|
|
202
|
+
const binScript = Object.values(binEntries)[0];
|
|
203
|
+
scriptPath = _path.resolve(localPath, binScript);
|
|
204
|
+
} else {
|
|
205
|
+
// Direct script path
|
|
206
|
+
scriptPath = _path.resolve(localPath);
|
|
207
|
+
// Infer tool name from filename (piratehat.js → piratehat)
|
|
208
|
+
toolName = _path.basename(scriptPath, ".js");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!_fs.existsSync(scriptPath)) {
|
|
212
|
+
console.error(`Script not found: ${scriptPath}`);
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const child = spawn(process.execPath, [scriptPath, ...extraArgs], {
|
|
217
|
+
stdio: "inherit",
|
|
218
|
+
env: { ...process.env, EQUIP_VERSION },
|
|
219
|
+
});
|
|
220
|
+
child.on("close", (code) => {
|
|
221
|
+
if (toolName) {
|
|
222
|
+
try {
|
|
223
|
+
const { reconcileState } = require("../dist/lib/reconcile");
|
|
224
|
+
const changed = reconcileState({
|
|
225
|
+
toolName,
|
|
226
|
+
package: toolName,
|
|
227
|
+
marker: toolName,
|
|
228
|
+
});
|
|
229
|
+
if (changed > 0) {
|
|
230
|
+
process.stderr.write(`\n equip: tracked ${toolName} on ${changed} platform${changed === 1 ? "" : "s"}\n`);
|
|
231
|
+
}
|
|
232
|
+
} catch (e) {
|
|
233
|
+
process.stderr.write(`\n[equip] state reconciliation failed: ${e.message}\n`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
process.exit(code || 0);
|
|
237
|
+
});
|
|
238
|
+
child.on("error", (err) => {
|
|
239
|
+
console.error(`Failed to run ${scriptPath}: ${err.message}`);
|
|
240
|
+
process.exit(1);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
160
244
|
function spawnTool(pkg, command, extraArgs, toolName) {
|
|
161
245
|
const npxCmd = process.platform === "win32" ? "npx.cmd" : "npx";
|
|
162
246
|
const child = spawn(npxCmd, ["-y", `${pkg}@latest`, command, ...extraArgs], {
|
package/demo/setup.js
CHANGED
|
@@ -14,9 +14,10 @@
|
|
|
14
14
|
// 1. Platform detection (which AI tools are installed?)
|
|
15
15
|
// 2. MCP server configuration (HTTP or stdio transport)
|
|
16
16
|
// 3. Behavioral rules installation (versioned, marker-based)
|
|
17
|
-
// 4.
|
|
18
|
-
// 5.
|
|
19
|
-
// 6.
|
|
17
|
+
// 4. Skills installation (SKILL.md files for agent discovery)
|
|
18
|
+
// 5. Lifecycle hooks (optional, platform-dependent)
|
|
19
|
+
// 6. Uninstallation (clean removal of everything it installed)
|
|
20
|
+
// 7. CLI output helpers (colors, prompts, clipboard)
|
|
20
21
|
//
|
|
21
22
|
// Everything is inline-documented. Copy this file as a starting
|
|
22
23
|
// point for your own tool's setup script.
|
|
@@ -120,6 +121,40 @@ const equip = new Equip({
|
|
|
120
121
|
// `,
|
|
121
122
|
// },
|
|
122
123
|
// ],
|
|
124
|
+
|
|
125
|
+
// Skills are optional. A skill is a SKILL.md file (Agent Skills
|
|
126
|
+
// spec) that agents auto-discover. Unlike MCP config and rules,
|
|
127
|
+
// the skill format is universal — same file works on all platforms.
|
|
128
|
+
skill: {
|
|
129
|
+
name: "lookup",
|
|
130
|
+
files: [
|
|
131
|
+
{
|
|
132
|
+
path: "SKILL.md",
|
|
133
|
+
content: `---
|
|
134
|
+
name: lookup
|
|
135
|
+
description: Look up Acme API docs for the current project's dependency version.
|
|
136
|
+
metadata:
|
|
137
|
+
author: acme-docs-demo
|
|
138
|
+
version: "${RULES_VERSION}"
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
# Acme Docs Lookup
|
|
142
|
+
|
|
143
|
+
Use this skill when working with Acme APIs or libraries.
|
|
144
|
+
|
|
145
|
+
## When to Use
|
|
146
|
+
- Before writing code that calls an Acme API
|
|
147
|
+
- When you see a deprecation warning from Acme
|
|
148
|
+
- When the user asks about Acme API signatures
|
|
149
|
+
|
|
150
|
+
## How to Use
|
|
151
|
+
1. Call the acme-docs MCP tool with the function name
|
|
152
|
+
2. The tool returns versioned docs matching the project's dependency
|
|
153
|
+
3. Use the returned signatures, not training data
|
|
154
|
+
`,
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
},
|
|
123
158
|
});
|
|
124
159
|
|
|
125
160
|
// ─── 5. Detect platforms (shared by install and uninstall) ───
|
|
@@ -155,7 +190,7 @@ function detectTargetPlatforms() {
|
|
|
155
190
|
async function runUninstall() {
|
|
156
191
|
cli.log(`\n${cli.BOLD}@cg3/equip demo — uninstall${cli.RESET}\n`);
|
|
157
192
|
|
|
158
|
-
cli.step(1,
|
|
193
|
+
cli.step(1, 4, "Detecting platforms");
|
|
159
194
|
const platforms = detectTargetPlatforms();
|
|
160
195
|
|
|
161
196
|
for (const p of platforms) {
|
|
@@ -163,7 +198,7 @@ async function runUninstall() {
|
|
|
163
198
|
}
|
|
164
199
|
|
|
165
200
|
// ── Remove MCP config ────────────────────────────────────
|
|
166
|
-
cli.step(2,
|
|
201
|
+
cli.step(2, 4, "Removing MCP config");
|
|
167
202
|
|
|
168
203
|
for (const p of platforms) {
|
|
169
204
|
const removed = equip.uninstallMcp(p);
|
|
@@ -175,7 +210,7 @@ async function runUninstall() {
|
|
|
175
210
|
}
|
|
176
211
|
|
|
177
212
|
// ── Remove behavioral rules ──────────────────────────────
|
|
178
|
-
cli.step(3,
|
|
213
|
+
cli.step(3, 4, "Removing behavioral rules");
|
|
179
214
|
|
|
180
215
|
for (const p of platforms) {
|
|
181
216
|
const removed = equip.uninstallRules(p);
|
|
@@ -186,6 +221,18 @@ async function runUninstall() {
|
|
|
186
221
|
}
|
|
187
222
|
}
|
|
188
223
|
|
|
224
|
+
// ── Remove skills ──────────────────────────────────────
|
|
225
|
+
cli.step(4, 4, "Removing skills");
|
|
226
|
+
|
|
227
|
+
for (const p of platforms) {
|
|
228
|
+
const removed = equip.uninstallSkill(p);
|
|
229
|
+
if (removed) {
|
|
230
|
+
cli.ok(`${platformName(p.platform)} → skill removed`);
|
|
231
|
+
} else {
|
|
232
|
+
cli.info(`${platformName(p.platform)} → no skill found`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
189
236
|
cli.log(`\n${cli.GREEN}${cli.BOLD}✓ Uninstall complete${cli.RESET}`);
|
|
190
237
|
cli.log(` Demo config for "${TOOL_NAME}" has been cleaned up.\n`);
|
|
191
238
|
}
|
|
@@ -215,7 +262,7 @@ async function runInstall() {
|
|
|
215
262
|
//
|
|
216
263
|
// You can also force a specific platform with createManualPlatform().
|
|
217
264
|
|
|
218
|
-
cli.step(1,
|
|
265
|
+
cli.step(1, 5, "Detecting platforms");
|
|
219
266
|
|
|
220
267
|
const platforms = detectTargetPlatforms();
|
|
221
268
|
|
|
@@ -229,7 +276,7 @@ async function runInstall() {
|
|
|
229
276
|
// In a real setup script, you'd prompt for or generate an
|
|
230
277
|
// API key here. For the demo, we use a placeholder.
|
|
231
278
|
|
|
232
|
-
cli.step(2,
|
|
279
|
+
cli.step(2, 5, "API key");
|
|
233
280
|
|
|
234
281
|
// Real example:
|
|
235
282
|
// const apiKey = await cli.prompt(" Enter your API key: ");
|
|
@@ -243,11 +290,11 @@ async function runInstall() {
|
|
|
243
290
|
// installMcp() handles all platform differences:
|
|
244
291
|
// - JSON vs TOML config formats
|
|
245
292
|
// - Different root keys (mcpServers vs servers vs mcp_servers)
|
|
246
|
-
// -
|
|
247
|
-
// -
|
|
293
|
+
// - Different URL fields (url vs serverUrl vs httpUrl)
|
|
294
|
+
// - Atomic file writes with crash safety
|
|
248
295
|
// - Windows path handling (cmd /c wrapper for stdio)
|
|
249
296
|
|
|
250
|
-
cli.step(3,
|
|
297
|
+
cli.step(3, 5, "Installing MCP config");
|
|
251
298
|
|
|
252
299
|
for (const p of platforms) {
|
|
253
300
|
const result = equip.installMcp(p, apiKey, { dryRun });
|
|
@@ -272,7 +319,7 @@ async function runInstall() {
|
|
|
272
319
|
// Platforms without a rules file (Cursor, VS Code) get the
|
|
273
320
|
// content copied to clipboard instead.
|
|
274
321
|
|
|
275
|
-
cli.step(4,
|
|
322
|
+
cli.step(4, 5, "Installing behavioral rules");
|
|
276
323
|
|
|
277
324
|
for (const p of platforms) {
|
|
278
325
|
const result = equip.installRules(p, { dryRun });
|
|
@@ -300,6 +347,32 @@ async function runInstall() {
|
|
|
300
347
|
}
|
|
301
348
|
}
|
|
302
349
|
|
|
350
|
+
// ── Step 5: Install skills ──────────────────────────────
|
|
351
|
+
//
|
|
352
|
+
// Skills are SKILL.md files (Agent Skills spec) that agents
|
|
353
|
+
// auto-discover from standard directories. Unlike MCP config,
|
|
354
|
+
// the skill format is universal — same file works on all
|
|
355
|
+
// platforms. Equip installs to each platform's native skill
|
|
356
|
+
// directory, or ~/.agents/skills/ for platforms without one.
|
|
357
|
+
|
|
358
|
+
cli.step(5, 5, "Installing skills");
|
|
359
|
+
|
|
360
|
+
for (const p of platforms) {
|
|
361
|
+
const result = equip.installSkill(p, { dryRun });
|
|
362
|
+
switch (result.action) {
|
|
363
|
+
case "created":
|
|
364
|
+
cli.ok(`${platformName(p.platform)} → skill installed`);
|
|
365
|
+
break;
|
|
366
|
+
case "skipped":
|
|
367
|
+
if (p.skillsPath) {
|
|
368
|
+
cli.info(`${platformName(p.platform)} → skill already current`);
|
|
369
|
+
} else {
|
|
370
|
+
cli.info(`${platformName(p.platform)} → no skills support`);
|
|
371
|
+
}
|
|
372
|
+
break;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
303
376
|
// ── Done ──────────────────────────────────────────────────
|
|
304
377
|
|
|
305
378
|
cli.log(`\n${cli.GREEN}${cli.BOLD}✓ Setup complete${cli.RESET}`);
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { parseRulesVersion, markerPatterns } from "./lib/rules";
|
|
|
2
2
|
import { type HookDefinition } from "./lib/hooks";
|
|
3
3
|
import { createManualPlatform, platformName, resolvePlatformId, KNOWN_PLATFORMS, PLATFORM_REGISTRY, getPlatform, type DetectedPlatform, type PlatformDefinition, type PlatformHttpShape, type PlatformHookCapabilities } from "./lib/platforms";
|
|
4
4
|
import * as cli from "./lib/cli";
|
|
5
|
+
import { type SkillConfig, type SkillFile } from "./lib/skills";
|
|
5
6
|
export interface EquipConfig {
|
|
6
7
|
name: string;
|
|
7
8
|
serverUrl?: string;
|
|
@@ -19,6 +20,7 @@ export interface EquipConfig {
|
|
|
19
20
|
};
|
|
20
21
|
hooks?: HookDefinition[];
|
|
21
22
|
hookDir?: string;
|
|
23
|
+
skill?: SkillConfig;
|
|
22
24
|
}
|
|
23
25
|
/**
|
|
24
26
|
* Equip — configure AI coding tools with your MCP server and behavioral rules.
|
|
@@ -30,6 +32,7 @@ declare class Equip {
|
|
|
30
32
|
stdio: EquipConfig["stdio"] | null;
|
|
31
33
|
hookDefs: HookDefinition[] | null;
|
|
32
34
|
hookDir: string;
|
|
35
|
+
skill: SkillConfig | null;
|
|
33
36
|
constructor(config: EquipConfig);
|
|
34
37
|
detect(): DetectedPlatform[];
|
|
35
38
|
buildConfig(platformId: string, apiKey: string, transport?: string): Record<string, unknown>;
|
|
@@ -68,6 +71,13 @@ declare class Equip {
|
|
|
68
71
|
hookDir?: string;
|
|
69
72
|
}): boolean;
|
|
70
73
|
supportsHooks(platform: DetectedPlatform): boolean;
|
|
74
|
+
installSkill(platform: DetectedPlatform, options?: {
|
|
75
|
+
dryRun?: boolean;
|
|
76
|
+
}): {
|
|
77
|
+
action: string;
|
|
78
|
+
};
|
|
79
|
+
uninstallSkill(platform: DetectedPlatform, dryRun?: boolean): boolean;
|
|
80
|
+
hasSkill(platform: DetectedPlatform): boolean;
|
|
71
81
|
/**
|
|
72
82
|
* Verify that a tool is correctly installed on a platform.
|
|
73
83
|
* Returns a structured result with per-check status.
|
|
@@ -85,5 +95,5 @@ export interface VerifyResult {
|
|
|
85
95
|
checks: VerifyCheck[];
|
|
86
96
|
}
|
|
87
97
|
export { Equip, createManualPlatform, platformName, resolvePlatformId, KNOWN_PLATFORMS, PLATFORM_REGISTRY, getPlatform, parseRulesVersion, markerPatterns, cli, };
|
|
88
|
-
export type { DetectedPlatform, PlatformDefinition, PlatformHttpShape, PlatformHookCapabilities, HookDefinition };
|
|
98
|
+
export type { DetectedPlatform, PlatformDefinition, PlatformHttpShape, PlatformHookCapabilities, HookDefinition, SkillConfig, SkillFile };
|
|
89
99
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,iBAAiB,EAAgC,cAAc,EAAE,MAAM,aAAa,CAAC;AAE9F,OAAO,EAA+D,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC/G,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,iBAAiB,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAChP,OAAO,KAAK,GAAG,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|